diff options
Diffstat (limited to 'drivers')
876 files changed, 56799 insertions, 55787 deletions
diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c index 6b115f6c4313..6afceb3d4034 100644 --- a/drivers/acpi/acpi_pad.c +++ b/drivers/acpi/acpi_pad.c @@ -30,18 +30,13 @@ #include <linux/slab.h> #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h> +#include <asm/mwait.h> #define ACPI_PROCESSOR_AGGREGATOR_CLASS "acpi_pad" #define ACPI_PROCESSOR_AGGREGATOR_DEVICE_NAME "Processor Aggregator" #define ACPI_PROCESSOR_AGGREGATOR_NOTIFY 0x80 static DEFINE_MUTEX(isolated_cpus_lock); -#define MWAIT_SUBSTATE_MASK (0xf) -#define MWAIT_CSTATE_MASK (0xf) -#define MWAIT_SUBSTATE_SIZE (4) -#define CPUID_MWAIT_LEAF (5) -#define CPUID5_ECX_EXTENSIONS_SUPPORTED (0x1) -#define CPUID5_ECX_INTERRUPT_BREAK (0x2) static unsigned long power_saving_mwait_eax; static unsigned char tsc_detected_unstable; diff --git a/drivers/acpi/apei/erst-dbg.c b/drivers/acpi/apei/erst-dbg.c index da1228a9a544..de73caf3cebc 100644 --- a/drivers/acpi/apei/erst-dbg.c +++ b/drivers/acpi/apei/erst-dbg.c @@ -184,6 +184,7 @@ static const struct file_operations erst_dbg_ops = { .read = erst_dbg_read, .write = erst_dbg_write, .unlocked_ioctl = erst_dbg_ioctl, + .llseek = no_llseek, }; static struct miscdevice erst_dbg_dev = { diff --git a/drivers/acpi/debugfs.c b/drivers/acpi/debugfs.c index 7de27d49c4b9..6355b575ee5a 100644 --- a/drivers/acpi/debugfs.c +++ b/drivers/acpi/debugfs.c @@ -69,6 +69,7 @@ static ssize_t cm_write(struct file *file, const char __user * user_buf, static const struct file_operations cm_fops = { .write = cm_write, + .llseek = default_llseek, }; int __init acpi_debugfs_init(void) diff --git a/drivers/acpi/ec_sys.c b/drivers/acpi/ec_sys.c index 0e869b3f81ca..411620ef84c2 100644 --- a/drivers/acpi/ec_sys.c +++ b/drivers/acpi/ec_sys.c @@ -101,6 +101,7 @@ static struct file_operations acpi_ec_io_ops = { .open = acpi_ec_open_io, .read = acpi_ec_read_io, .write = acpi_ec_write_io, + .llseek = default_llseek, }; int acpi_ec_add_debugfs(struct acpi_ec *ec, unsigned int ec_device_count) diff --git a/drivers/acpi/event.c b/drivers/acpi/event.c index d439314a75d8..85d908993809 100644 --- a/drivers/acpi/event.c +++ b/drivers/acpi/event.c @@ -110,6 +110,7 @@ static const struct file_operations acpi_system_event_ops = { .read = acpi_system_read_event, .release = acpi_system_close_event, .poll = acpi_system_poll_event, + .llseek = default_llseek, }; #endif /* CONFIG_ACPI_PROC_EVENT */ diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c index d31590e7011b..2737b9752205 100644 --- a/drivers/amba/bus.c +++ b/drivers/amba/bus.c @@ -298,7 +298,7 @@ int amba_device_register(struct amba_device *dev, struct resource *parent) amba_put_disable_pclk(dev); - if (cid == 0xb105f00d) + if (cid == AMBA_CID) dev->periphid = pid; if (!dev->periphid) diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index d5df04a395ca..c501af5b12b9 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -99,7 +99,7 @@ obj-$(CONFIG_ATA_GENERIC) += ata_generic.o # Should be last libata driver obj-$(CONFIG_PATA_LEGACY) += pata_legacy.o -libata-objs := libata-core.o libata-scsi.o libata-eh.o +libata-y := libata-core.o libata-scsi.o libata-eh.o libata-transport.o libata-$(CONFIG_ATA_SFF) += libata-sff.o libata-$(CONFIG_SATA_PMP) += libata-pmp.o libata-$(CONFIG_ATA_ACPI) += libata-acpi.o diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 99d0e5a51148..328826381a2d 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1208,9 +1208,6 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) ata_port_pbar_desc(ap, AHCI_PCI_BAR, 0x100 + ap->port_no * 0x80, "port"); - /* set initial link pm policy */ - ap->pm_policy = NOT_AVAILABLE; - /* set enclosure management message type */ if (ap->flags & ATA_FLAG_EM) ap->em_message_type = hpriv->em_msg_type; diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h index e5fdeebf9ef0..329cbbb91284 100644 --- a/drivers/ata/ahci.h +++ b/drivers/ata/ahci.h @@ -72,6 +72,7 @@ enum { AHCI_CMD_RESET = (1 << 8), AHCI_CMD_CLR_BUSY = (1 << 10), + RX_FIS_PIO_SETUP = 0x20, /* offset of PIO Setup FIS data */ RX_FIS_D2H_REG = 0x40, /* offset of D2H Register FIS data */ RX_FIS_SDB = 0x58, /* offset of SDB FIS data */ RX_FIS_UNK = 0x60, /* offset of Unknown FIS data */ @@ -201,7 +202,6 @@ enum { AHCI_HFLAG_MV_PATA = (1 << 4), /* PATA port */ AHCI_HFLAG_NO_MSI = (1 << 5), /* no PCI MSI */ AHCI_HFLAG_NO_PMP = (1 << 6), /* no PMP */ - AHCI_HFLAG_NO_HOTPLUG = (1 << 7), /* ignore PxSERR.DIAG.N */ AHCI_HFLAG_SECT255 = (1 << 8), /* max 255 sectors */ AHCI_HFLAG_YES_NCQ = (1 << 9), /* force NCQ cap on */ AHCI_HFLAG_NO_SUSPEND = (1 << 10), /* don't suspend */ @@ -216,7 +216,7 @@ enum { AHCI_FLAG_COMMON = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | ATA_FLAG_ACPI_SATA | ATA_FLAG_AN | - ATA_FLAG_IPM, + ATA_FLAG_LPM, ICH_MAP = 0x90, /* ICH MAP register */ diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c index 84b643270e7a..6fef1fa75c54 100644 --- a/drivers/ata/ahci_platform.c +++ b/drivers/ata/ahci_platform.c @@ -129,9 +129,6 @@ static int __init ahci_probe(struct platform_device *pdev) ata_port_desc(ap, "mmio %pR", mem); ata_port_desc(ap, "port 0x%x", 0x100 + ap->port_no * 0x80); - /* set initial link pm policy */ - ap->pm_policy = NOT_AVAILABLE; - /* set enclosure management message type */ if (ap->flags & ATA_FLAG_EM) ap->em_message_type = hpriv->em_msg_type; diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c index cc5f7726bde7..6981f7680a00 100644 --- a/drivers/ata/ata_generic.c +++ b/drivers/ata/ata_generic.c @@ -35,6 +35,7 @@ enum { ATA_GEN_CLASS_MATCH = (1 << 0), ATA_GEN_FORCE_DMA = (1 << 1), + ATA_GEN_INTEL_IDER = (1 << 2), }; /** @@ -109,6 +110,49 @@ static struct ata_port_operations generic_port_ops = { static int all_generic_ide; /* Set to claim all devices */ /** + * is_intel_ider - identify intel IDE-R devices + * @dev: PCI device + * + * Distinguish Intel IDE-R controller devices from other Intel IDE + * devices. IDE-R devices have no timing registers and are in + * most respects virtual. They should be driven by the ata_generic + * driver. + * + * IDE-R devices have PCI offset 0xF8.L as zero, later Intel ATA has + * it non zero. All Intel ATA has 0x40 writable (timing), but it is + * not writable on IDE-R devices (this is guaranteed). + */ + +static int is_intel_ider(struct pci_dev *dev) +{ + /* For Intel IDE the value at 0xF8 is only zero on IDE-R + interfaces */ + u32 r; + u16 t; + + /* Check the manufacturing ID, it will be zero for IDE-R */ + pci_read_config_dword(dev, 0xF8, &r); + /* Not IDE-R: punt so that ata_(old)piix gets it */ + if (r != 0) + return 0; + /* 0xF8 will also be zero on some early Intel IDE devices + but they will have a sane timing register */ + pci_read_config_word(dev, 0x40, &t); + if (t != 0) + return 0; + /* Finally check if the timing register is writable so that + we eliminate any early devices hot-docked in a docking + station */ + pci_write_config_word(dev, 0x40, 1); + pci_read_config_word(dev, 0x40, &t); + if (t) { + pci_write_config_word(dev, 0x40, 0); + return 0; + } + return 1; +} + +/** * ata_generic_init - attach generic IDE * @dev: PCI device found * @id: match entry @@ -134,6 +178,10 @@ static int ata_generic_init_one(struct pci_dev *dev, const struct pci_device_id if ((id->driver_data & ATA_GEN_CLASS_MATCH) && all_generic_ide == 0) return -ENODEV; + if (id->driver_data & ATA_GEN_INTEL_IDER) + if (!is_intel_ider(dev)) + return -ENODEV; + /* Devices that need care */ if (dev->vendor == PCI_VENDOR_ID_UMC && dev->device == PCI_DEVICE_ID_UMC_UM8886A && @@ -186,7 +234,11 @@ static struct pci_device_id ata_generic[] = { { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_2), }, { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_3), }, { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_5), }, -#endif +#endif + /* Intel, IDE class device */ + { PCI_VENDOR_ID_INTEL, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_STORAGE_IDE << 8, 0xFFFFFF00UL, + .driver_data = ATA_GEN_INTEL_IDER }, /* Must come last. If you add entries adjust this table appropriately */ { PCI_DEVICE_CLASS(PCI_CLASS_STORAGE_IDE << 8, 0xFFFFFF00UL), .driver_data = ATA_GEN_CLASS_MATCH }, diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index d712675d0a96..6cb14ca8ee85 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -158,7 +158,6 @@ struct piix_map_db { struct piix_host_priv { const int *map; u32 saved_iocfg; - spinlock_t sidpr_lock; /* FIXME: remove once locking in EH is fixed */ void __iomem *sidpr; }; @@ -175,6 +174,8 @@ static int piix_sidpr_scr_read(struct ata_link *link, unsigned int reg, u32 *val); static int piix_sidpr_scr_write(struct ata_link *link, unsigned int reg, u32 val); +static int piix_sidpr_set_lpm(struct ata_link *link, enum ata_lpm_policy policy, + unsigned hints); static bool piix_irq_check(struct ata_port *ap); #ifdef CONFIG_PM static int piix_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg); @@ -209,6 +210,8 @@ static const struct pci_device_id piix_pci_tbl[] = { { 0x8086, 0x248A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, /* Intel ICH3 (E7500/1) UDMA 100 */ { 0x8086, 0x248B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, + /* Intel ICH4-L */ + { 0x8086, 0x24C1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, /* Intel ICH4 (i845GV, i845E, i852, i855) UDMA 100 */ { 0x8086, 0x24CA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, { 0x8086, 0x24CB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, @@ -348,11 +351,22 @@ static struct ata_port_operations ich_pata_ops = { .set_dmamode = ich_set_dmamode, }; +static struct device_attribute *piix_sidpr_shost_attrs[] = { + &dev_attr_link_power_management_policy, + NULL +}; + +static struct scsi_host_template piix_sidpr_sht = { + ATA_BMDMA_SHT(DRV_NAME), + .shost_attrs = piix_sidpr_shost_attrs, +}; + static struct ata_port_operations piix_sidpr_sata_ops = { .inherits = &piix_sata_ops, .hardreset = sata_std_hardreset, .scr_read = piix_sidpr_scr_read, .scr_write = piix_sidpr_scr_write, + .set_lpm = piix_sidpr_set_lpm, }; static const struct piix_map_db ich5_map_db = { @@ -956,15 +970,12 @@ static int piix_sidpr_scr_read(struct ata_link *link, unsigned int reg, u32 *val) { struct piix_host_priv *hpriv = link->ap->host->private_data; - unsigned long flags; if (reg >= ARRAY_SIZE(piix_sidx_map)) return -EINVAL; - spin_lock_irqsave(&hpriv->sidpr_lock, flags); piix_sidpr_sel(link, reg); *val = ioread32(hpriv->sidpr + PIIX_SIDPR_DATA); - spin_unlock_irqrestore(&hpriv->sidpr_lock, flags); return 0; } @@ -972,18 +983,21 @@ static int piix_sidpr_scr_write(struct ata_link *link, unsigned int reg, u32 val) { struct piix_host_priv *hpriv = link->ap->host->private_data; - unsigned long flags; if (reg >= ARRAY_SIZE(piix_sidx_map)) return -EINVAL; - spin_lock_irqsave(&hpriv->sidpr_lock, flags); piix_sidpr_sel(link, reg); iowrite32(val, hpriv->sidpr + PIIX_SIDPR_DATA); - spin_unlock_irqrestore(&hpriv->sidpr_lock, flags); return 0; } +static int piix_sidpr_set_lpm(struct ata_link *link, enum ata_lpm_policy policy, + unsigned hints) +{ + return sata_link_scr_lpm(link, policy, false); +} + static bool piix_irq_check(struct ata_port *ap) { if (unlikely(!ap->ioaddr.bmdma_addr)) @@ -1543,6 +1557,7 @@ static int __devinit piix_init_one(struct pci_dev *pdev, struct device *dev = &pdev->dev; struct ata_port_info port_info[2]; const struct ata_port_info *ppi[] = { &port_info[0], &port_info[1] }; + struct scsi_host_template *sht = &piix_sht; unsigned long port_flags; struct ata_host *host; struct piix_host_priv *hpriv; @@ -1577,7 +1592,6 @@ static int __devinit piix_init_one(struct pci_dev *pdev, hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL); if (!hpriv) return -ENOMEM; - spin_lock_init(&hpriv->sidpr_lock); /* Save IOCFG, this will be used for cable detection, quirk * detection and restoration on detach. This is necessary @@ -1612,6 +1626,8 @@ static int __devinit piix_init_one(struct pci_dev *pdev, rc = piix_init_sidpr(host); if (rc) return rc; + if (host->ports[0]->ops == &piix_sidpr_sata_ops) + sht = &piix_sidpr_sht; } /* apply IOCFG bit18 quirk */ @@ -1638,7 +1654,7 @@ static int __devinit piix_init_one(struct pci_dev *pdev, host->flags |= ATA_HOST_PARALLEL_SCAN; pci_set_master(pdev); - return ata_pci_sff_activate_host(host, ata_bmdma_interrupt, &piix_sht); + return ata_pci_sff_activate_host(host, ata_bmdma_interrupt, sht); } static void piix_remove_one(struct pci_dev *pdev) diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 8eea309ea212..ebc08d65b3dd 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -56,9 +56,8 @@ MODULE_PARM_DESC(skip_host_reset, "skip global host reset (0=don't skip, 1=skip) module_param_named(ignore_sss, ahci_ignore_sss, int, 0444); MODULE_PARM_DESC(ignore_sss, "Ignore staggered spinup flag (0=don't ignore, 1=ignore)"); -static int ahci_enable_alpm(struct ata_port *ap, - enum link_pm policy); -static void ahci_disable_alpm(struct ata_port *ap); +static int ahci_set_lpm(struct ata_link *link, enum ata_lpm_policy policy, + unsigned hints); static ssize_t ahci_led_show(struct ata_port *ap, char *buf); static ssize_t ahci_led_store(struct ata_port *ap, const char *buf, size_t size); @@ -164,8 +163,7 @@ struct ata_port_operations ahci_ops = { .pmp_attach = ahci_pmp_attach, .pmp_detach = ahci_pmp_detach, - .enable_pm = ahci_enable_alpm, - .disable_pm = ahci_disable_alpm, + .set_lpm = ahci_set_lpm, .em_show = ahci_led_show, .em_store = ahci_led_store, .sw_activity_show = ahci_activity_show, @@ -569,7 +567,7 @@ int ahci_stop_engine(struct ata_port *ap) writel(tmp, port_mmio + PORT_CMD); /* wait for engine to stop. This could be as long as 500 msec */ - tmp = ata_wait_register(port_mmio + PORT_CMD, + tmp = ata_wait_register(ap, port_mmio + PORT_CMD, PORT_CMD_LIST_ON, PORT_CMD_LIST_ON, 1, 500); if (tmp & PORT_CMD_LIST_ON) return -EIO; @@ -616,7 +614,7 @@ static int ahci_stop_fis_rx(struct ata_port *ap) writel(tmp, port_mmio + PORT_CMD); /* wait for completion, spec says 500ms, give it 1000 */ - tmp = ata_wait_register(port_mmio + PORT_CMD, PORT_CMD_FIS_ON, + tmp = ata_wait_register(ap, port_mmio + PORT_CMD, PORT_CMD_FIS_ON, PORT_CMD_FIS_ON, 10, 1000); if (tmp & PORT_CMD_FIS_ON) return -EBUSY; @@ -642,127 +640,56 @@ static void ahci_power_up(struct ata_port *ap) writel(cmd | PORT_CMD_ICC_ACTIVE, port_mmio + PORT_CMD); } -static void ahci_disable_alpm(struct ata_port *ap) +static int ahci_set_lpm(struct ata_link *link, enum ata_lpm_policy policy, + unsigned int hints) { + struct ata_port *ap = link->ap; struct ahci_host_priv *hpriv = ap->host->private_data; - void __iomem *port_mmio = ahci_port_base(ap); - u32 cmd; struct ahci_port_priv *pp = ap->private_data; - - /* IPM bits should be disabled by libata-core */ - /* get the existing command bits */ - cmd = readl(port_mmio + PORT_CMD); - - /* disable ALPM and ASP */ - cmd &= ~PORT_CMD_ASP; - cmd &= ~PORT_CMD_ALPE; - - /* force the interface back to active */ - cmd |= PORT_CMD_ICC_ACTIVE; - - /* write out new cmd value */ - writel(cmd, port_mmio + PORT_CMD); - cmd = readl(port_mmio + PORT_CMD); - - /* wait 10ms to be sure we've come out of any low power state */ - msleep(10); - - /* clear out any PhyRdy stuff from interrupt status */ - writel(PORT_IRQ_PHYRDY, port_mmio + PORT_IRQ_STAT); - - /* go ahead and clean out PhyRdy Change from Serror too */ - ahci_scr_write(&ap->link, SCR_ERROR, ((1 << 16) | (1 << 18))); - - /* - * Clear flag to indicate that we should ignore all PhyRdy - * state changes - */ - hpriv->flags &= ~AHCI_HFLAG_NO_HOTPLUG; - - /* - * Enable interrupts on Phy Ready. - */ - pp->intr_mask |= PORT_IRQ_PHYRDY; - writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); - - /* - * don't change the link pm policy - we can be called - * just to turn of link pm temporarily - */ -} - -static int ahci_enable_alpm(struct ata_port *ap, - enum link_pm policy) -{ - struct ahci_host_priv *hpriv = ap->host->private_data; void __iomem *port_mmio = ahci_port_base(ap); - u32 cmd; - struct ahci_port_priv *pp = ap->private_data; - u32 asp; - /* Make sure the host is capable of link power management */ - if (!(hpriv->cap & HOST_CAP_ALPM)) - return -EINVAL; - - switch (policy) { - case MAX_PERFORMANCE: - case NOT_AVAILABLE: + if (policy != ATA_LPM_MAX_POWER) { /* - * if we came here with NOT_AVAILABLE, - * it just means this is the first time we - * have tried to enable - default to max performance, - * and let the user go to lower power modes on request. + * Disable interrupts on Phy Ready. This keeps us from + * getting woken up due to spurious phy ready + * interrupts. */ - ahci_disable_alpm(ap); - return 0; - case MIN_POWER: - /* configure HBA to enter SLUMBER */ - asp = PORT_CMD_ASP; - break; - case MEDIUM_POWER: - /* configure HBA to enter PARTIAL */ - asp = 0; - break; - default: - return -EINVAL; + pp->intr_mask &= ~PORT_IRQ_PHYRDY; + writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); + + sata_link_scr_lpm(link, policy, false); } - /* - * Disable interrupts on Phy Ready. This keeps us from - * getting woken up due to spurious phy ready interrupts - * TBD - Hot plug should be done via polling now, is - * that even supported? - */ - pp->intr_mask &= ~PORT_IRQ_PHYRDY; - writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); + if (hpriv->cap & HOST_CAP_ALPM) { + u32 cmd = readl(port_mmio + PORT_CMD); - /* - * Set a flag to indicate that we should ignore all PhyRdy - * state changes since these can happen now whenever we - * change link state - */ - hpriv->flags |= AHCI_HFLAG_NO_HOTPLUG; + if (policy == ATA_LPM_MAX_POWER || !(hints & ATA_LPM_HIPM)) { + cmd &= ~(PORT_CMD_ASP | PORT_CMD_ALPE); + cmd |= PORT_CMD_ICC_ACTIVE; - /* get the existing command bits */ - cmd = readl(port_mmio + PORT_CMD); + writel(cmd, port_mmio + PORT_CMD); + readl(port_mmio + PORT_CMD); - /* - * Set ASP based on Policy - */ - cmd |= asp; + /* wait 10ms to be sure we've come out of LPM state */ + ata_msleep(ap, 10); + } else { + cmd |= PORT_CMD_ALPE; + if (policy == ATA_LPM_MIN_POWER) + cmd |= PORT_CMD_ASP; - /* - * Setting this bit will instruct the HBA to aggressively - * enter a lower power link state when it's appropriate and - * based on the value set above for ASP - */ - cmd |= PORT_CMD_ALPE; + /* write out new cmd value */ + writel(cmd, port_mmio + PORT_CMD); + } + } - /* write out new cmd value */ - writel(cmd, port_mmio + PORT_CMD); - cmd = readl(port_mmio + PORT_CMD); + if (policy == ATA_LPM_MAX_POWER) { + sata_link_scr_lpm(link, policy, false); + + /* turn PHYRDY IRQ back on */ + pp->intr_mask |= PORT_IRQ_PHYRDY; + writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); + } - /* IPM bits should be set by libata-core */ return 0; } @@ -813,7 +740,7 @@ static void ahci_start_port(struct ata_port *ap) emp->led_state, 4); if (rc == -EBUSY) - msleep(1); + ata_msleep(ap, 1); else break; } @@ -872,7 +799,7 @@ int ahci_reset_controller(struct ata_host *host) * reset must complete within 1 second, or * the hardware should be considered fried. */ - tmp = ata_wait_register(mmio + HOST_CTL, HOST_RESET, + tmp = ata_wait_register(NULL, mmio + HOST_CTL, HOST_RESET, HOST_RESET, 10, 1000); if (tmp & HOST_RESET) { @@ -1252,7 +1179,7 @@ int ahci_kick_engine(struct ata_port *ap) writel(tmp, port_mmio + PORT_CMD); rc = 0; - tmp = ata_wait_register(port_mmio + PORT_CMD, + tmp = ata_wait_register(ap, port_mmio + PORT_CMD, PORT_CMD_CLO, PORT_CMD_CLO, 1, 500); if (tmp & PORT_CMD_CLO) rc = -EIO; @@ -1282,8 +1209,8 @@ static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp, writel(1, port_mmio + PORT_CMD_ISSUE); if (timeout_msec) { - tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1, - 1, timeout_msec); + tmp = ata_wait_register(ap, port_mmio + PORT_CMD_ISSUE, + 0x1, 0x1, 1, timeout_msec); if (tmp & 0x1) { ahci_kick_engine(ap); return -EBUSY; @@ -1330,7 +1257,7 @@ int ahci_do_softreset(struct ata_link *link, unsigned int *class, } /* spec says at least 5us, but be generous and sleep for 1ms */ - msleep(1); + ata_msleep(ap, 1); /* issue the second D2H Register FIS */ tf.ctl &= ~ATA_SRST; @@ -1660,15 +1587,10 @@ static void ahci_port_intr(struct ata_port *ap) if (unlikely(resetting)) status &= ~PORT_IRQ_BAD_PMP; - /* If we are getting PhyRdy, this is - * just a power state change, we should - * clear out this, plus the PhyRdy/Comm - * Wake bits from Serror - */ - if ((hpriv->flags & AHCI_HFLAG_NO_HOTPLUG) && - (status & PORT_IRQ_PHYRDY)) { + /* if LPM is enabled, PHYRDY doesn't mean anything */ + if (ap->link.lpm_policy > ATA_LPM_MAX_POWER) { status &= ~PORT_IRQ_PHYRDY; - ahci_scr_write(&ap->link, SCR_ERROR, ((1 << 16) | (1 << 18))); + ahci_scr_write(&ap->link, SCR_ERROR, SERR_PHYRDY_CHG); } if (unlikely(status & PORT_IRQ_ERROR)) { @@ -1830,12 +1752,24 @@ static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc) static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc) { struct ahci_port_priv *pp = qc->ap->private_data; - u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; + u8 *rx_fis = pp->rx_fis; if (pp->fbs_enabled) - d2h_fis += qc->dev->link->pmp * AHCI_RX_FIS_SZ; + rx_fis += qc->dev->link->pmp * AHCI_RX_FIS_SZ; + + /* + * After a successful execution of an ATA PIO data-in command, + * the device doesn't send D2H Reg FIS to update the TF and + * the host should take TF and E_Status from the preceding PIO + * Setup FIS. + */ + if (qc->tf.protocol == ATA_PROT_PIO && qc->dma_dir == DMA_FROM_DEVICE && + !(qc->flags & ATA_QCFLAG_FAILED)) { + ata_tf_from_fis(rx_fis + RX_FIS_PIO_SETUP, &qc->result_tf); + qc->result_tf.command = (rx_fis + RX_FIS_PIO_SETUP)[15]; + } else + ata_tf_from_fis(rx_fis + RX_FIS_D2H_REG, &qc->result_tf); - ata_tf_from_fis(d2h_fis, &qc->result_tf); return true; } diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 932eaee50245..7f77c67d267c 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -68,7 +68,7 @@ #include <linux/ratelimit.h> #include "libata.h" - +#include "libata-transport.h" /* debounce timing parameters in msecs { interval, duration, timeout } */ const unsigned long sata_deb_timing_normal[] = { 5, 100, 2000 }; @@ -91,8 +91,6 @@ const struct ata_port_operations sata_port_ops = { static unsigned int ata_dev_init_params(struct ata_device *dev, u16 heads, u16 sectors); static unsigned int ata_dev_set_xfermode(struct ata_device *dev); -static unsigned int ata_dev_set_feature(struct ata_device *dev, - u8 enable, u8 feature); static void ata_dev_xfermask(struct ata_device *dev); static unsigned long ata_dev_blacklisted(const struct ata_device *dev); @@ -1017,7 +1015,7 @@ const char *ata_mode_string(unsigned long xfer_mask) return "<n/a>"; } -static const char *sata_spd_string(unsigned int spd) +const char *sata_spd_string(unsigned int spd) { static const char * const spd_str[] = { "1.5 Gbps", @@ -1030,182 +1028,6 @@ static const char *sata_spd_string(unsigned int spd) return spd_str[spd - 1]; } -static int ata_dev_set_dipm(struct ata_device *dev, enum link_pm policy) -{ - struct ata_link *link = dev->link; - struct ata_port *ap = link->ap; - u32 scontrol; - unsigned int err_mask; - int rc; - - /* - * disallow DIPM for drivers which haven't set - * ATA_FLAG_IPM. This is because when DIPM is enabled, - * phy ready will be set in the interrupt status on - * state changes, which will cause some drivers to - * think there are errors - additionally drivers will - * need to disable hot plug. - */ - if (!(ap->flags & ATA_FLAG_IPM) || !ata_dev_enabled(dev)) { - ap->pm_policy = NOT_AVAILABLE; - return -EINVAL; - } - - /* - * For DIPM, we will only enable it for the - * min_power setting. - * - * Why? Because Disks are too stupid to know that - * If the host rejects a request to go to SLUMBER - * they should retry at PARTIAL, and instead it - * just would give up. So, for medium_power to - * work at all, we need to only allow HIPM. - */ - rc = sata_scr_read(link, SCR_CONTROL, &scontrol); - if (rc) - return rc; - - switch (policy) { - case MIN_POWER: - /* no restrictions on IPM transitions */ - scontrol &= ~(0x3 << 8); - rc = sata_scr_write(link, SCR_CONTROL, scontrol); - if (rc) - return rc; - - /* enable DIPM */ - if (dev->flags & ATA_DFLAG_DIPM) - err_mask = ata_dev_set_feature(dev, - SETFEATURES_SATA_ENABLE, SATA_DIPM); - break; - case MEDIUM_POWER: - /* allow IPM to PARTIAL */ - scontrol &= ~(0x1 << 8); - scontrol |= (0x2 << 8); - rc = sata_scr_write(link, SCR_CONTROL, scontrol); - if (rc) - return rc; - - /* - * we don't have to disable DIPM since IPM flags - * disallow transitions to SLUMBER, which effectively - * disable DIPM if it does not support PARTIAL - */ - break; - case NOT_AVAILABLE: - case MAX_PERFORMANCE: - /* disable all IPM transitions */ - scontrol |= (0x3 << 8); - rc = sata_scr_write(link, SCR_CONTROL, scontrol); - if (rc) - return rc; - - /* - * we don't have to disable DIPM since IPM flags - * disallow all transitions which effectively - * disable DIPM anyway. - */ - break; - } - - /* FIXME: handle SET FEATURES failure */ - (void) err_mask; - - return 0; -} - -/** - * ata_dev_enable_pm - enable SATA interface power management - * @dev: device to enable power management - * @policy: the link power management policy - * - * Enable SATA Interface power management. This will enable - * Device Interface Power Management (DIPM) for min_power - * policy, and then call driver specific callbacks for - * enabling Host Initiated Power management. - * - * Locking: Caller. - * Returns: -EINVAL if IPM is not supported, 0 otherwise. - */ -void ata_dev_enable_pm(struct ata_device *dev, enum link_pm policy) -{ - int rc = 0; - struct ata_port *ap = dev->link->ap; - - /* set HIPM first, then DIPM */ - if (ap->ops->enable_pm) - rc = ap->ops->enable_pm(ap, policy); - if (rc) - goto enable_pm_out; - rc = ata_dev_set_dipm(dev, policy); - -enable_pm_out: - if (rc) - ap->pm_policy = MAX_PERFORMANCE; - else - ap->pm_policy = policy; - return /* rc */; /* hopefully we can use 'rc' eventually */ -} - -#ifdef CONFIG_PM -/** - * ata_dev_disable_pm - disable SATA interface power management - * @dev: device to disable power management - * - * Disable SATA Interface power management. This will disable - * Device Interface Power Management (DIPM) without changing - * policy, call driver specific callbacks for disabling Host - * Initiated Power management. - * - * Locking: Caller. - * Returns: void - */ -static void ata_dev_disable_pm(struct ata_device *dev) -{ - struct ata_port *ap = dev->link->ap; - - ata_dev_set_dipm(dev, MAX_PERFORMANCE); - if (ap->ops->disable_pm) - ap->ops->disable_pm(ap); -} -#endif /* CONFIG_PM */ - -void ata_lpm_schedule(struct ata_port *ap, enum link_pm policy) -{ - ap->pm_policy = policy; - ap->link.eh_info.action |= ATA_EH_LPM; - ap->link.eh_info.flags |= ATA_EHI_NO_AUTOPSY; - ata_port_schedule_eh(ap); -} - -#ifdef CONFIG_PM -static void ata_lpm_enable(struct ata_host *host) -{ - struct ata_link *link; - struct ata_port *ap; - struct ata_device *dev; - int i; - - for (i = 0; i < host->n_ports; i++) { - ap = host->ports[i]; - ata_for_each_link(link, ap, EDGE) { - ata_for_each_dev(dev, link, ALL) - ata_dev_disable_pm(dev); - } - } -} - -static void ata_lpm_disable(struct ata_host *host) -{ - int i; - - for (i = 0; i < host->n_ports; i++) { - struct ata_port *ap = host->ports[i]; - ata_lpm_schedule(ap, ap->pm_policy); - } -} -#endif /* CONFIG_PM */ - /** * ata_dev_classify - determine device type based on ATA-spec signature * @tf: ATA taskfile register set for device to be identified @@ -1806,8 +1628,14 @@ unsigned ata_exec_internal_sg(struct ata_device *dev, } } + if (ap->ops->error_handler) + ata_eh_release(ap); + rc = wait_for_completion_timeout(&wait, msecs_to_jiffies(timeout)); + if (ap->ops->error_handler) + ata_eh_acquire(ap); + ata_sff_flush_pio_task(ap); if (!rc) { @@ -2564,13 +2392,6 @@ int ata_dev_configure(struct ata_device *dev) if (dev->flags & ATA_DFLAG_LBA48) dev->max_sectors = ATA_MAX_SECTORS_LBA48; - if (!(dev->horkage & ATA_HORKAGE_IPM)) { - if (ata_id_has_hipm(dev->id)) - dev->flags |= ATA_DFLAG_HIPM; - if (ata_id_has_dipm(dev->id)) - dev->flags |= ATA_DFLAG_DIPM; - } - /* Limit PATA drive on SATA cable bridge transfers to udma5, 200 sectors */ if (ata_dev_knobble(dev)) { @@ -2591,13 +2412,6 @@ int ata_dev_configure(struct ata_device *dev) dev->max_sectors = min_t(unsigned int, ATA_MAX_SECTORS_128, dev->max_sectors); - if (ata_dev_blacklisted(dev) & ATA_HORKAGE_IPM) { - dev->horkage |= ATA_HORKAGE_IPM; - - /* reset link pm_policy for this port to no pm */ - ap->pm_policy = MAX_PERFORMANCE; - } - if (ap->ops->dev_config) ap->ops->dev_config(dev); @@ -3596,7 +3410,7 @@ int ata_wait_ready(struct ata_link *link, unsigned long deadline, warned = 1; } - msleep(50); + ata_msleep(link->ap, 50); } } @@ -3617,7 +3431,7 @@ int ata_wait_ready(struct ata_link *link, unsigned long deadline, int ata_wait_after_reset(struct ata_link *link, unsigned long deadline, int (*check_ready)(struct ata_link *link)) { - msleep(ATA_WAIT_AFTER_RESET); + ata_msleep(link->ap, ATA_WAIT_AFTER_RESET); return ata_wait_ready(link, deadline, check_ready); } @@ -3628,7 +3442,7 @@ int ata_wait_after_reset(struct ata_link *link, unsigned long deadline, * @params: timing parameters { interval, duratinon, timeout } in msec * @deadline: deadline jiffies for the operation * -* Make sure SStatus of @link reaches stable state, determined by + * Make sure SStatus of @link reaches stable state, determined by * holding the same value where DET is not 1 for @duration polled * every @interval, before @timeout. Timeout constraints the * beginning of the stable state. Because DET gets stuck at 1 on @@ -3665,7 +3479,7 @@ int sata_link_debounce(struct ata_link *link, const unsigned long *params, last_jiffies = jiffies; while (1) { - msleep(interval); + ata_msleep(link->ap, interval); if ((rc = sata_scr_read(link, SCR_STATUS, &cur))) return rc; cur &= 0xf; @@ -3730,7 +3544,7 @@ int sata_link_resume(struct ata_link *link, const unsigned long *params, * immediately after resuming. Delay 200ms before * debouncing. */ - msleep(200); + ata_msleep(link->ap, 200); /* is SControl restored correctly? */ if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol))) @@ -3760,6 +3574,72 @@ int sata_link_resume(struct ata_link *link, const unsigned long *params, } /** + * sata_link_scr_lpm - manipulate SControl IPM and SPM fields + * @link: ATA link to manipulate SControl for + * @policy: LPM policy to configure + * @spm_wakeup: initiate LPM transition to active state + * + * Manipulate the IPM field of the SControl register of @link + * according to @policy. If @policy is ATA_LPM_MAX_POWER and + * @spm_wakeup is %true, the SPM field is manipulated to wake up + * the link. This function also clears PHYRDY_CHG before + * returning. + * + * LOCKING: + * EH context. + * + * RETURNS: + * 0 on succes, -errno otherwise. + */ +int sata_link_scr_lpm(struct ata_link *link, enum ata_lpm_policy policy, + bool spm_wakeup) +{ + struct ata_eh_context *ehc = &link->eh_context; + bool woken_up = false; + u32 scontrol; + int rc; + + rc = sata_scr_read(link, SCR_CONTROL, &scontrol); + if (rc) + return rc; + + switch (policy) { + case ATA_LPM_MAX_POWER: + /* disable all LPM transitions */ + scontrol |= (0x3 << 8); + /* initiate transition to active state */ + if (spm_wakeup) { + scontrol |= (0x4 << 12); + woken_up = true; + } + break; + case ATA_LPM_MED_POWER: + /* allow LPM to PARTIAL */ + scontrol &= ~(0x1 << 8); + scontrol |= (0x2 << 8); + break; + case ATA_LPM_MIN_POWER: + /* no restrictions on LPM transitions */ + scontrol &= ~(0x3 << 8); + break; + default: + WARN_ON(1); + } + + rc = sata_scr_write(link, SCR_CONTROL, scontrol); + if (rc) + return rc; + + /* give the link time to transit out of LPM state */ + if (woken_up) + msleep(10); + + /* clear PHYRDY_CHG from SError */ + ehc->i.serror &= ~SERR_PHYRDY_CHG; + return sata_scr_write(link, SCR_ERROR, SERR_PHYRDY_CHG); +} + +/** * ata_std_prereset - prepare for reset * @link: ATA link to be reset * @deadline: deadline jiffies for the operation @@ -3868,7 +3748,7 @@ int sata_link_hardreset(struct ata_link *link, const unsigned long *timing, /* Couldn't find anything in SATA I/II specs, but AHCI-1.1 * 10.4.2 says at least 1 ms. */ - msleep(1); + ata_msleep(link->ap, 1); /* bring link back */ rc = sata_link_resume(link, timing, deadline); @@ -4551,6 +4431,7 @@ static unsigned int ata_dev_set_xfermode(struct ata_device *dev) DPRINTK("EXIT, err_mask=%x\n", err_mask); return err_mask; } + /** * ata_dev_set_feature - Issue SET FEATURES - SATA FEATURES * @dev: Device to which command will be sent @@ -4566,8 +4447,7 @@ static unsigned int ata_dev_set_xfermode(struct ata_device *dev) * RETURNS: * 0 on success, AC_ERR_* mask otherwise. */ -static unsigned int ata_dev_set_feature(struct ata_device *dev, u8 enable, - u8 feature) +unsigned int ata_dev_set_feature(struct ata_device *dev, u8 enable, u8 feature) { struct ata_taskfile tf; unsigned int err_mask; @@ -4943,8 +4823,13 @@ static void ata_verify_xfer(struct ata_queued_cmd *qc) * ata_qc_complete - Complete an active ATA command * @qc: Command to complete * - * Indicate to the mid and upper layers that an ATA - * command has completed, with either an ok or not-ok status. + * Indicate to the mid and upper layers that an ATA command has + * completed, with either an ok or not-ok status. + * + * Refrain from calling this function multiple times when + * successfully completing multiple NCQ commands. + * ata_qc_complete_multiple() should be used instead, which will + * properly update IRQ expect state. * * LOCKING: * spin_lock_irqsave(host lock) @@ -5037,6 +4922,10 @@ void ata_qc_complete(struct ata_queued_cmd *qc) * requests normally. ap->qc_active and @qc_active is compared * and commands are completed accordingly. * + * Always use this function when completing multiple NCQ commands + * from IRQ handlers instead of calling ata_qc_complete() + * multiple times to keep IRQ expect status properly in sync. + * * LOCKING: * spin_lock_irqsave(host lock) * @@ -5422,12 +5311,6 @@ int ata_host_suspend(struct ata_host *host, pm_message_t mesg) int rc; /* - * disable link pm on all ports before requesting - * any pm activity - */ - ata_lpm_enable(host); - - /* * On some hardware, device fails to respond after spun down * for suspend. As the device won't be used before being * resumed, we don't need to touch the device. Ask EH to skip @@ -5460,9 +5343,6 @@ void ata_host_resume(struct ata_host *host) ata_host_request_pm(host, PMSG_ON, ATA_EH_RESET, ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, 0); host->dev->power.power_state = PMSG_ON; - - /* reenable link pm */ - ata_lpm_disable(host); } #endif @@ -5517,7 +5397,8 @@ void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp) int i; /* clear everything except for devices */ - memset(link, 0, offsetof(struct ata_link, device[0])); + memset((void *)link + ATA_LINK_CLEAR_BEGIN, 0, + ATA_LINK_CLEAR_END - ATA_LINK_CLEAR_BEGIN); link->ap = ap; link->pmp = pmp; @@ -5591,7 +5472,7 @@ struct ata_port *ata_port_alloc(struct ata_host *host) ap = kzalloc(sizeof(*ap), GFP_KERNEL); if (!ap) return NULL; - + ap->pflags |= ATA_PFLAG_INITIALIZING; ap->lock = &host->lock; ap->print_id = -1; @@ -5695,6 +5576,7 @@ struct ata_host *ata_host_alloc(struct device *dev, int max_ports) dev_set_drvdata(dev, host); spin_lock_init(&host->lock); + mutex_init(&host->eh_mutex); host->dev = dev; host->n_ports = max_ports; @@ -5992,6 +5874,7 @@ void ata_host_init(struct ata_host *host, struct device *dev, unsigned long flags, struct ata_port_operations *ops) { spin_lock_init(&host->lock); + mutex_init(&host->eh_mutex); host->dev = dev; host->flags = flags; host->ops = ops; @@ -6022,7 +5905,7 @@ static void async_port_probe(void *data, async_cookie_t cookie) spin_lock_irqsave(ap->lock, flags); ehi->probe_mask |= ATA_ALL_DEVICES; - ehi->action |= ATA_EH_RESET | ATA_EH_LPM; + ehi->action |= ATA_EH_RESET; ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET; ap->pflags &= ~ATA_PFLAG_INITIALIZING; @@ -6093,9 +5976,18 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) for (i = 0; i < host->n_ports; i++) host->ports[i]->print_id = ata_print_id++; + + /* Create associated sysfs transport objects */ + for (i = 0; i < host->n_ports; i++) { + rc = ata_tport_add(host->dev,host->ports[i]); + if (rc) { + goto err_tadd; + } + } + rc = ata_scsi_add_hosts(host, sht); if (rc) - return rc; + goto err_tadd; /* associate with ACPI nodes */ ata_acpi_associate(host); @@ -6136,6 +6028,13 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) } return 0; + + err_tadd: + while (--i >= 0) { + ata_tport_delete(host->ports[i]); + } + return rc; + } /** @@ -6226,6 +6125,13 @@ static void ata_port_detach(struct ata_port *ap) cancel_rearming_delayed_work(&ap->hotplug_task); skip_eh: + if (ap->pmp_link) { + int i; + for (i = 0; i < SATA_PMP_MAX_PORTS; i++) + ata_tlink_delete(&ap->pmp_link[i]); + } + ata_tport_delete(ap); + /* remove the associated SCSI host */ scsi_remove_host(ap->scsi_host); } @@ -6542,7 +6448,7 @@ static void __init ata_parse_force_param(void) static int __init ata_init(void) { - int rc = -ENOMEM; + int rc; ata_parse_force_param(); @@ -6552,12 +6458,25 @@ static int __init ata_init(void) return rc; } + libata_transport_init(); + ata_scsi_transport_template = ata_attach_transport(); + if (!ata_scsi_transport_template) { + ata_sff_exit(); + rc = -ENOMEM; + goto err_out; + } + printk(KERN_DEBUG "libata version " DRV_VERSION " loaded.\n"); return 0; + +err_out: + return rc; } static void __exit ata_exit(void) { + ata_release_transport(ata_scsi_transport_template); + libata_transport_exit(); ata_sff_exit(); kfree(ata_force_tbl); } @@ -6573,7 +6492,35 @@ int ata_ratelimit(void) } /** + * ata_msleep - ATA EH owner aware msleep + * @ap: ATA port to attribute the sleep to + * @msecs: duration to sleep in milliseconds + * + * Sleeps @msecs. If the current task is owner of @ap's EH, the + * ownership is released before going to sleep and reacquired + * after the sleep is complete. IOW, other ports sharing the + * @ap->host will be allowed to own the EH while this task is + * sleeping. + * + * LOCKING: + * Might sleep. + */ +void ata_msleep(struct ata_port *ap, unsigned int msecs) +{ + bool owns_eh = ap && ap->host->eh_owner == current; + + if (owns_eh) + ata_eh_release(ap); + + msleep(msecs); + + if (owns_eh) + ata_eh_acquire(ap); +} + +/** * ata_wait_register - wait until register value changes + * @ap: ATA port to wait register for, can be NULL * @reg: IO-mapped register * @mask: Mask to apply to read register value * @val: Wait condition @@ -6595,7 +6542,7 @@ int ata_ratelimit(void) * RETURNS: * The final register value. */ -u32 ata_wait_register(void __iomem *reg, u32 mask, u32 val, +u32 ata_wait_register(struct ata_port *ap, void __iomem *reg, u32 mask, u32 val, unsigned long interval, unsigned long timeout) { unsigned long deadline; @@ -6610,7 +6557,7 @@ u32 ata_wait_register(void __iomem *reg, u32 mask, u32 val, deadline = ata_deadline(jiffies, timeout); while ((tmp & mask) == val && time_before(jiffies, deadline)) { - msleep(interval); + ata_msleep(ap, interval); tmp = ioread32(reg); } @@ -6686,6 +6633,7 @@ EXPORT_SYMBOL_GPL(sata_set_spd); EXPORT_SYMBOL_GPL(ata_wait_after_reset); EXPORT_SYMBOL_GPL(sata_link_debounce); EXPORT_SYMBOL_GPL(sata_link_resume); +EXPORT_SYMBOL_GPL(sata_link_scr_lpm); EXPORT_SYMBOL_GPL(ata_std_prereset); EXPORT_SYMBOL_GPL(sata_link_hardreset); EXPORT_SYMBOL_GPL(sata_std_hardreset); @@ -6693,6 +6641,7 @@ EXPORT_SYMBOL_GPL(ata_std_postreset); EXPORT_SYMBOL_GPL(ata_dev_classify); EXPORT_SYMBOL_GPL(ata_dev_pair); EXPORT_SYMBOL_GPL(ata_ratelimit); +EXPORT_SYMBOL_GPL(ata_msleep); EXPORT_SYMBOL_GPL(ata_wait_register); EXPORT_SYMBOL_GPL(ata_scsi_queuecmd); EXPORT_SYMBOL_GPL(ata_scsi_slave_config); diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index e48302eae55f..5e590504f3aa 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -57,6 +57,7 @@ enum { /* error flags */ ATA_EFLAG_IS_IO = (1 << 0), ATA_EFLAG_DUBIOUS_XFER = (1 << 1), + ATA_EFLAG_OLD_ER = (1 << 31), /* error categories */ ATA_ECAT_NONE = 0, @@ -396,14 +397,9 @@ static struct ata_ering_entry *ata_ering_top(struct ata_ering *ering) return NULL; } -static void ata_ering_clear(struct ata_ering *ering) -{ - memset(ering, 0, sizeof(*ering)); -} - -static int ata_ering_map(struct ata_ering *ering, - int (*map_fn)(struct ata_ering_entry *, void *), - void *arg) +int ata_ering_map(struct ata_ering *ering, + int (*map_fn)(struct ata_ering_entry *, void *), + void *arg) { int idx, rc = 0; struct ata_ering_entry *ent; @@ -422,6 +418,17 @@ static int ata_ering_map(struct ata_ering *ering, return rc; } +int ata_ering_clear_cb(struct ata_ering_entry *ent, void *void_arg) +{ + ent->eflags |= ATA_EFLAG_OLD_ER; + return 0; +} + +static void ata_ering_clear(struct ata_ering *ering) +{ + ata_ering_map(ering, ata_ering_clear_cb, NULL); +} + static unsigned int ata_eh_dev_action(struct ata_device *dev) { struct ata_eh_context *ehc = &dev->link->eh_context; @@ -456,6 +463,41 @@ static void ata_eh_clear_action(struct ata_link *link, struct ata_device *dev, } /** + * ata_eh_acquire - acquire EH ownership + * @ap: ATA port to acquire EH ownership for + * + * Acquire EH ownership for @ap. This is the basic exclusion + * mechanism for ports sharing a host. Only one port hanging off + * the same host can claim the ownership of EH. + * + * LOCKING: + * EH context. + */ +void ata_eh_acquire(struct ata_port *ap) +{ + mutex_lock(&ap->host->eh_mutex); + WARN_ON_ONCE(ap->host->eh_owner); + ap->host->eh_owner = current; +} + +/** + * ata_eh_release - release EH ownership + * @ap: ATA port to release EH ownership for + * + * Release EH ownership for @ap if the caller. The caller must + * have acquired EH ownership using ata_eh_acquire() previously. + * + * LOCKING: + * EH context. + */ +void ata_eh_release(struct ata_port *ap) +{ + WARN_ON_ONCE(ap->host->eh_owner != current); + ap->host->eh_owner = NULL; + mutex_unlock(&ap->host->eh_mutex); +} + +/** * ata_scsi_timed_out - SCSI layer time out callback * @cmd: timed out SCSI command * @@ -572,19 +614,19 @@ void ata_scsi_error(struct Scsi_Host *host) int nr_timedout = 0; spin_lock_irqsave(ap->lock, flags); - + /* This must occur under the ap->lock as we don't want a polled recovery to race the real interrupt handler - + The lost_interrupt handler checks for any completed but non-notified command and completes much like an IRQ handler. - + We then fall into the error recovery code which will treat this as if normal completion won the race */ if (ap->ops->lost_interrupt) ap->ops->lost_interrupt(ap); - + list_for_each_entry_safe(scmd, tmp, &host->eh_cmd_q, eh_entry) { struct ata_queued_cmd *qc; @@ -628,15 +670,17 @@ void ata_scsi_error(struct Scsi_Host *host) ap->eh_tries = ATA_EH_MAX_TRIES; } else spin_unlock_wait(ap->lock); - + /* If we timed raced normal completion and there is nothing to recover nr_timedout == 0 why exactly are we doing error recovery ? */ - repeat: /* invoke error handler */ if (ap->ops->error_handler) { struct ata_link *link; + /* acquire EH ownership */ + ata_eh_acquire(ap); + repeat: /* kill fast drain timer */ del_timer_sync(&ap->fastdrain_timer); @@ -711,6 +755,7 @@ void ata_scsi_error(struct Scsi_Host *host) host->host_eh_scheduled = 0; spin_unlock_irqrestore(ap->lock, flags); + ata_eh_release(ap); } else { WARN_ON(ata_qc_from_tag(ap, ap->link.active_tag) == NULL); ap->ops->eng_timeout(ap); @@ -772,7 +817,7 @@ void ata_port_wait_eh(struct ata_port *ap) /* make sure SCSI EH is complete */ if (scsi_host_in_recovery(ap->scsi_host)) { - msleep(10); + ata_msleep(ap, 10); goto retry; } } @@ -1573,9 +1618,9 @@ static void ata_eh_analyze_serror(struct ata_link *link) * host links. For disabled PMP links, only N bit is * considered as X bit is left at 1 for link plugging. */ - hotplug_mask = 0; - - if (!(link->flags & ATA_LFLAG_DISABLED) || ata_is_host_link(link)) + if (link->lpm_policy != ATA_LPM_MAX_POWER) + hotplug_mask = 0; /* hotplug doesn't work w/ LPM */ + else if (!(link->flags & ATA_LFLAG_DISABLED) || ata_is_host_link(link)) hotplug_mask = SERR_PHYRDY_CHG | SERR_DEV_XCHG; else hotplug_mask = SERR_PHYRDY_CHG; @@ -1755,7 +1800,7 @@ static int speed_down_verdict_cb(struct ata_ering_entry *ent, void *void_arg) struct speed_down_verdict_arg *arg = void_arg; int cat; - if (ent->timestamp < arg->since) + if ((ent->eflags & ATA_EFLAG_OLD_ER) || (ent->timestamp < arg->since)) return -1; cat = ata_eh_categorize_error(ent->eflags, ent->err_mask, @@ -2777,8 +2822,9 @@ int ata_eh_reset(struct ata_link *link, int classify, ata_eh_done(link, NULL, ATA_EH_RESET); if (slave) ata_eh_done(slave, NULL, ATA_EH_RESET); - ehc->last_reset = jiffies; /* update to completion time */ + ehc->last_reset = jiffies; /* update to completion time */ ehc->i.action |= ATA_EH_REVALIDATE; + link->lpm_policy = ATA_LPM_UNKNOWN; /* reset LPM state */ rc = 0; out: @@ -2810,8 +2856,10 @@ int ata_eh_reset(struct ata_link *link, int classify, "reset failed (errno=%d), retrying in %u secs\n", rc, DIV_ROUND_UP(jiffies_to_msecs(delta), 1000)); + ata_eh_release(ap); while (delta) delta = schedule_timeout_uninterruptible(delta); + ata_eh_acquire(ap); } if (try == max_tries - 1) { @@ -3204,6 +3252,124 @@ static int ata_eh_maybe_retry_flush(struct ata_device *dev) return rc; } +/** + * ata_eh_set_lpm - configure SATA interface power management + * @link: link to configure power management + * @policy: the link power management policy + * @r_failed_dev: out parameter for failed device + * + * Enable SATA Interface power management. This will enable + * Device Interface Power Management (DIPM) for min_power + * policy, and then call driver specific callbacks for + * enabling Host Initiated Power management. + * + * LOCKING: + * EH context. + * + * RETURNS: + * 0 on success, -errno on failure. + */ +static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy, + struct ata_device **r_failed_dev) +{ + struct ata_port *ap = ata_is_host_link(link) ? link->ap : NULL; + struct ata_eh_context *ehc = &link->eh_context; + struct ata_device *dev, *link_dev = NULL, *lpm_dev = NULL; + unsigned int hints = ATA_LPM_EMPTY | ATA_LPM_HIPM; + unsigned int err_mask; + int rc; + + /* if the link or host doesn't do LPM, noop */ + if ((link->flags & ATA_LFLAG_NO_LPM) || (ap && !ap->ops->set_lpm)) + return 0; + + /* + * DIPM is enabled only for MIN_POWER as some devices + * misbehave when the host NACKs transition to SLUMBER. Order + * device and link configurations such that the host always + * allows DIPM requests. + */ + ata_for_each_dev(dev, link, ENABLED) { + bool hipm = ata_id_has_hipm(dev->id); + bool dipm = ata_id_has_dipm(dev->id); + + /* find the first enabled and LPM enabled devices */ + if (!link_dev) + link_dev = dev; + + if (!lpm_dev && (hipm || dipm)) + lpm_dev = dev; + + hints &= ~ATA_LPM_EMPTY; + if (!hipm) + hints &= ~ATA_LPM_HIPM; + + /* disable DIPM before changing link config */ + if (policy != ATA_LPM_MIN_POWER && dipm) { + err_mask = ata_dev_set_feature(dev, + SETFEATURES_SATA_DISABLE, SATA_DIPM); + if (err_mask && err_mask != AC_ERR_DEV) { + ata_dev_printk(dev, KERN_WARNING, + "failed to disable DIPM, Emask 0x%x\n", + err_mask); + rc = -EIO; + goto fail; + } + } + } + + if (ap) { + rc = ap->ops->set_lpm(link, policy, hints); + if (!rc && ap->slave_link) + rc = ap->ops->set_lpm(ap->slave_link, policy, hints); + } else + rc = sata_pmp_set_lpm(link, policy, hints); + + /* + * Attribute link config failure to the first (LPM) enabled + * device on the link. + */ + if (rc) { + if (rc == -EOPNOTSUPP) { + link->flags |= ATA_LFLAG_NO_LPM; + return 0; + } + dev = lpm_dev ? lpm_dev : link_dev; + goto fail; + } + + /* host config updated, enable DIPM if transitioning to MIN_POWER */ + ata_for_each_dev(dev, link, ENABLED) { + if (policy == ATA_LPM_MIN_POWER && ata_id_has_dipm(dev->id)) { + err_mask = ata_dev_set_feature(dev, + SETFEATURES_SATA_ENABLE, SATA_DIPM); + if (err_mask && err_mask != AC_ERR_DEV) { + ata_dev_printk(dev, KERN_WARNING, + "failed to enable DIPM, Emask 0x%x\n", + err_mask); + rc = -EIO; + goto fail; + } + } + } + + link->lpm_policy = policy; + if (ap && ap->slave_link) + ap->slave_link->lpm_policy = policy; + return 0; + +fail: + /* if no device or only one more chance is left, disable LPM */ + if (!dev || ehc->tries[dev->devno] <= 2) { + ata_link_printk(link, KERN_WARNING, + "disabling LPM on the link\n"); + link->flags |= ATA_LFLAG_NO_LPM; + } + if (r_failed_dev) + *r_failed_dev = dev; + return rc; +} + static int ata_link_nr_enabled(struct ata_link *link) { struct ata_device *dev; @@ -3288,6 +3454,16 @@ static int ata_eh_schedule_probe(struct ata_device *dev) ehc->saved_xfer_mode[dev->devno] = 0; ehc->saved_ncq_enabled &= ~(1 << dev->devno); + /* the link maybe in a deep sleep, wake it up */ + if (link->lpm_policy > ATA_LPM_MAX_POWER) { + if (ata_is_host_link(link)) + link->ap->ops->set_lpm(link, ATA_LPM_MAX_POWER, + ATA_LPM_EMPTY); + else + sata_pmp_set_lpm(link, ATA_LPM_MAX_POWER, + ATA_LPM_EMPTY); + } + /* Record and count probe trials on the ering. The specific * error mask used is irrelevant. Because a successful device * detection clears the ering, this count accumulates only if @@ -3389,8 +3565,7 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, { struct ata_link *link; struct ata_device *dev; - int nr_failed_devs; - int rc; + int rc, nr_fails; unsigned long flags, deadline; DPRINTK("ENTER\n"); @@ -3431,7 +3606,6 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, retry: rc = 0; - nr_failed_devs = 0; /* if UNLOADING, finish immediately */ if (ap->pflags & ATA_PFLAG_UNLOADING) @@ -3501,8 +3675,10 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, if (time_before_eq(deadline, now)) break; + ata_eh_release(ap); deadline = wait_for_completion_timeout(&ap->park_req_pending, deadline - now); + ata_eh_acquire(ap); } while (deadline); ata_for_each_link(link, ap, EDGE) { ata_for_each_dev(dev, link, ALL) { @@ -3516,13 +3692,17 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, } /* the rest */ - ata_for_each_link(link, ap, EDGE) { + nr_fails = 0; + ata_for_each_link(link, ap, PMP_FIRST) { struct ata_eh_context *ehc = &link->eh_context; + if (sata_pmp_attached(ap) && ata_is_host_link(link)) + goto config_lpm; + /* revalidate existing devices and attach new ones */ rc = ata_eh_revalidate_and_attach(link, &dev); if (rc) - goto dev_fail; + goto rest_fail; /* if PMP got attached, return, pmp EH will take care of it */ if (link->device->class == ATA_DEV_PMP) { @@ -3534,7 +3714,7 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, if (ehc->i.flags & ATA_EHI_SETMODE) { rc = ata_set_mode(link, &dev); if (rc) - goto dev_fail; + goto rest_fail; ehc->i.flags &= ~ATA_EHI_SETMODE; } @@ -3547,7 +3727,7 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, continue; rc = atapi_eh_clear_ua(dev); if (rc) - goto dev_fail; + goto rest_fail; } } @@ -3557,21 +3737,25 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, continue; rc = ata_eh_maybe_retry_flush(dev); if (rc) - goto dev_fail; + goto rest_fail; } + config_lpm: /* configure link power saving */ - if (ehc->i.action & ATA_EH_LPM) - ata_for_each_dev(dev, link, ALL) - ata_dev_enable_pm(dev, ap->pm_policy); + if (link->lpm_policy != ap->target_lpm_policy) { + rc = ata_eh_set_lpm(link, ap->target_lpm_policy, &dev); + if (rc) + goto rest_fail; + } /* this link is okay now */ ehc->i.flags = 0; continue; -dev_fail: - nr_failed_devs++; - ata_eh_handle_dev_fail(dev, rc); + rest_fail: + nr_fails++; + if (dev) + ata_eh_handle_dev_fail(dev, rc); if (ap->pflags & ATA_PFLAG_FROZEN) { /* PMP reset requires working host port. @@ -3583,7 +3767,7 @@ dev_fail: } } - if (nr_failed_devs) + if (nr_fails) goto retry; out: diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c index 224faabd7b7e..3120596d4afc 100644 --- a/drivers/ata/libata-pmp.c +++ b/drivers/ata/libata-pmp.c @@ -11,6 +11,7 @@ #include <linux/libata.h> #include <linux/slab.h> #include "libata.h" +#include "libata-transport.h" const struct ata_port_operations sata_pmp_port_ops = { .inherits = &sata_port_ops, @@ -185,6 +186,27 @@ int sata_pmp_scr_write(struct ata_link *link, int reg, u32 val) } /** + * sata_pmp_set_lpm - configure LPM for a PMP link + * @link: PMP link to configure LPM for + * @policy: target LPM policy + * @hints: LPM hints + * + * Configure LPM for @link. This function will contain any PMP + * specific workarounds if necessary. + * + * LOCKING: + * EH context. + * + * RETURNS: + * 0 on success, -errno on failure. + */ +int sata_pmp_set_lpm(struct ata_link *link, enum ata_lpm_policy policy, + unsigned hints) +{ + return sata_link_scr_lpm(link, policy, true); +} + +/** * sata_pmp_read_gscr - read GSCR block of SATA PMP * @dev: PMP device * @gscr: buffer to read GSCR block into @@ -312,10 +334,10 @@ static int sata_pmp_configure(struct ata_device *dev, int print_info) return rc; } -static int sata_pmp_init_links(struct ata_port *ap, int nr_ports) +static int sata_pmp_init_links (struct ata_port *ap, int nr_ports) { struct ata_link *pmp_link = ap->pmp_link; - int i; + int i, err; if (!pmp_link) { pmp_link = kzalloc(sizeof(pmp_link[0]) * SATA_PMP_MAX_PORTS, @@ -327,6 +349,13 @@ static int sata_pmp_init_links(struct ata_port *ap, int nr_ports) ata_link_init(ap, &pmp_link[i], i); ap->pmp_link = pmp_link; + + for (i = 0; i < SATA_PMP_MAX_PORTS; i++) { + err = ata_tlink_add(&pmp_link[i]); + if (err) { + goto err_tlink; + } + } } for (i = 0; i < nr_ports; i++) { @@ -339,6 +368,12 @@ static int sata_pmp_init_links(struct ata_port *ap, int nr_ports) } return 0; + err_tlink: + while (--i >= 0) + ata_tlink_delete(&pmp_link[i]); + kfree(pmp_link); + ap->pmp_link = NULL; + return err; } static void sata_pmp_quirks(struct ata_port *ap) @@ -351,6 +386,9 @@ static void sata_pmp_quirks(struct ata_port *ap) if (vendor == 0x1095 && devid == 0x3726) { /* sil3726 quirks */ ata_for_each_link(link, ap, EDGE) { + /* link reports offline after LPM */ + link->flags |= ATA_LFLAG_NO_LPM; + /* Class code report is unreliable and SRST * times out under certain configurations. */ @@ -366,6 +404,9 @@ static void sata_pmp_quirks(struct ata_port *ap) } else if (vendor == 0x1095 && devid == 0x4723) { /* sil4723 quirks */ ata_for_each_link(link, ap, EDGE) { + /* link reports offline after LPM */ + link->flags |= ATA_LFLAG_NO_LPM; + /* class code report is unreliable */ if (link->pmp < 2) link->flags |= ATA_LFLAG_ASSUME_ATA; @@ -378,6 +419,9 @@ static void sata_pmp_quirks(struct ata_port *ap) } else if (vendor == 0x1095 && devid == 0x4726) { /* sil4726 quirks */ ata_for_each_link(link, ap, EDGE) { + /* link reports offline after LPM */ + link->flags |= ATA_LFLAG_NO_LPM; + /* Class code report is unreliable and SRST * times out under certain configurations. * Config device can be at port 0 or 5 and @@ -938,15 +982,25 @@ static int sata_pmp_eh_recover(struct ata_port *ap) if (rc) goto link_fail; - /* Connection status might have changed while resetting other - * links, check SATA_PMP_GSCR_ERROR before returning. - */ - /* clear SNotification */ rc = sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf); if (rc == 0) sata_scr_write(&ap->link, SCR_NOTIFICATION, sntf); + /* + * If LPM is active on any fan-out port, hotplug wouldn't + * work. Return w/ PHY event notification disabled. + */ + ata_for_each_link(link, ap, EDGE) + if (link->lpm_policy > ATA_LPM_MAX_POWER) + return 0; + + /* + * Connection status might have changed while resetting other + * links, enable notification and check SATA_PMP_GSCR_ERROR + * before returning. + */ + /* enable notification */ if (pmp_dev->flags & ATA_DFLAG_AN) { gscr[SATA_PMP_GSCR_FEAT_EN] |= SATA_PMP_FEAT_NOTIFY; diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index a89172c100f5..d050e073e570 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -51,8 +51,8 @@ #include <asm/unaligned.h> #include "libata.h" +#include "libata-transport.h" -#define SECTOR_SIZE 512 #define ATA_SCSI_RBUF_SIZE 4096 static DEFINE_SPINLOCK(ata_scsi_rbuf_lock); @@ -64,9 +64,6 @@ static struct ata_device *__ata_scsi_find_dev(struct ata_port *ap, const struct scsi_device *scsidev); static struct ata_device *ata_scsi_find_dev(struct ata_port *ap, const struct scsi_device *scsidev); -static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel, - unsigned int id, unsigned int lun); - #define RW_RECOVERY_MPAGE 0x1 #define RW_RECOVERY_MPAGE_LEN 12 @@ -106,83 +103,55 @@ static const u8 def_control_mpage[CONTROL_MPAGE_LEN] = { 0, 30 /* extended self test time, see 05-359r1 */ }; -/* - * libata transport template. libata doesn't do real transport stuff. - * It just needs the eh_timed_out hook. - */ -static struct scsi_transport_template ata_scsi_transport_template = { - .eh_strategy_handler = ata_scsi_error, - .eh_timed_out = ata_scsi_timed_out, - .user_scan = ata_scsi_user_scan, -}; - - -static const struct { - enum link_pm value; - const char *name; -} link_pm_policy[] = { - { NOT_AVAILABLE, "max_performance" }, - { MIN_POWER, "min_power" }, - { MAX_PERFORMANCE, "max_performance" }, - { MEDIUM_POWER, "medium_power" }, +static const char *ata_lpm_policy_names[] = { + [ATA_LPM_UNKNOWN] = "max_performance", + [ATA_LPM_MAX_POWER] = "max_performance", + [ATA_LPM_MED_POWER] = "medium_power", + [ATA_LPM_MIN_POWER] = "min_power", }; -static const char *ata_scsi_lpm_get(enum link_pm policy) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(link_pm_policy); i++) - if (link_pm_policy[i].value == policy) - return link_pm_policy[i].name; - - return NULL; -} - -static ssize_t ata_scsi_lpm_put(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t ata_scsi_lpm_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct Scsi_Host *shost = class_to_shost(dev); struct ata_port *ap = ata_shost_to_port(shost); - enum link_pm policy = 0; - int i; + enum ata_lpm_policy policy; + unsigned long flags; - /* - * we are skipping array location 0 on purpose - this - * is because a value of NOT_AVAILABLE is displayed - * to the user as max_performance, but when the user - * writes "max_performance", they actually want the - * value to match MAX_PERFORMANCE. - */ - for (i = 1; i < ARRAY_SIZE(link_pm_policy); i++) { - const int len = strlen(link_pm_policy[i].name); - if (strncmp(link_pm_policy[i].name, buf, len) == 0) { - policy = link_pm_policy[i].value; + /* UNKNOWN is internal state, iterate from MAX_POWER */ + for (policy = ATA_LPM_MAX_POWER; + policy < ARRAY_SIZE(ata_lpm_policy_names); policy++) { + const char *name = ata_lpm_policy_names[policy]; + + if (strncmp(name, buf, strlen(name)) == 0) break; - } } - if (!policy) + if (policy == ARRAY_SIZE(ata_lpm_policy_names)) return -EINVAL; - ata_lpm_schedule(ap, policy); + spin_lock_irqsave(ap->lock, flags); + ap->target_lpm_policy = policy; + ata_port_schedule_eh(ap); + spin_unlock_irqrestore(ap->lock, flags); + return count; } -static ssize_t -ata_scsi_lpm_show(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t ata_scsi_lpm_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(dev); struct ata_port *ap = ata_shost_to_port(shost); - const char *policy = - ata_scsi_lpm_get(ap->pm_policy); - if (!policy) + if (ap->target_lpm_policy >= ARRAY_SIZE(ata_lpm_policy_names)) return -EINVAL; - return snprintf(buf, 23, "%s\n", policy); + return snprintf(buf, PAGE_SIZE, "%s\n", + ata_lpm_policy_names[ap->target_lpm_policy]); } DEVICE_ATTR(link_power_management_policy, S_IRUGO | S_IWUSR, - ata_scsi_lpm_show, ata_scsi_lpm_put); + ata_scsi_lpm_show, ata_scsi_lpm_store); EXPORT_SYMBOL_GPL(dev_attr_link_power_management_policy); static ssize_t ata_scsi_park_show(struct device *device, @@ -516,7 +485,7 @@ int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg) memset(scsi_cmd, 0, sizeof(scsi_cmd)); if (args[3]) { - argsize = SECTOR_SIZE * args[3]; + argsize = ATA_SECT_SIZE * args[3]; argbuf = kmalloc(argsize, GFP_KERNEL); if (argbuf == NULL) { rc = -ENOMEM; @@ -1150,8 +1119,9 @@ static int ata_scsi_dev_config(struct scsi_device *sdev, blk_queue_dma_drain(q, atapi_drain_needed, buf, ATAPI_MAX_DRAIN); } else { /* ATA devices must be sector aligned */ + sdev->sector_size = ata_id_logical_sector_size(dev->id); blk_queue_update_dma_alignment(sdev->request_queue, - ATA_SECT_SIZE - 1); + sdev->sector_size - 1); sdev->manage_start_stop = 1; } @@ -1166,6 +1136,7 @@ static int ata_scsi_dev_config(struct scsi_device *sdev, scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, depth); } + dev->sdev = sdev; return 0; } @@ -1696,7 +1667,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc) goto nothing_to_do; qc->flags |= ATA_QCFLAG_IO; - qc->nbytes = n_block * ATA_SECT_SIZE; + qc->nbytes = n_block * scmd->device->sector_size; rc = ata_build_rw_tf(&qc->tf, qc->dev, block, n_block, tf_flags, qc->tag); @@ -2001,6 +1972,7 @@ static unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf) 0x89, /* page 0x89, ata info page */ 0xb0, /* page 0xb0, block limits page */ 0xb1, /* page 0xb1, block device characteristics page */ + 0xb2, /* page 0xb2, thin provisioning page */ }; rbuf[3] = sizeof(pages); /* number of supported VPD pages */ @@ -2123,7 +2095,7 @@ static unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf) static unsigned int ata_scsiop_inq_b0(struct ata_scsi_args *args, u8 *rbuf) { - u32 min_io_sectors; + u16 min_io_sectors; rbuf[1] = 0xb0; rbuf[3] = 0x3c; /* required VPD size with unmap support */ @@ -2135,10 +2107,7 @@ static unsigned int ata_scsiop_inq_b0(struct ata_scsi_args *args, u8 *rbuf) * logical than physical sector size we need to figure out what the * latter is. */ - if (ata_id_has_large_logical_sectors(args->id)) - min_io_sectors = ata_id_logical_per_physical_sectors(args->id); - else - min_io_sectors = 1; + min_io_sectors = 1 << ata_id_log2_per_physical_sector(args->id); put_unaligned_be16(min_io_sectors, &rbuf[6]); /* @@ -2172,6 +2141,16 @@ static unsigned int ata_scsiop_inq_b1(struct ata_scsi_args *args, u8 *rbuf) return 0; } +static unsigned int ata_scsiop_inq_b2(struct ata_scsi_args *args, u8 *rbuf) +{ + /* SCSI Thin Provisioning VPD page: SBC-3 rev 22 or later */ + rbuf[1] = 0xb2; + rbuf[3] = 0x4; + rbuf[5] = 1 << 6; /* TPWS */ + + return 0; +} + /** * ata_scsiop_noop - Command handler that simply returns success. * @args: device IDENTIFY data / SCSI command of interest. @@ -2397,21 +2376,13 @@ static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf) { struct ata_device *dev = args->dev; u64 last_lba = dev->n_sectors - 1; /* LBA of the last block */ - u8 log_per_phys = 0; - u16 lowest_aligned = 0; - u16 word_106 = dev->id[106]; - u16 word_209 = dev->id[209]; - - if ((word_106 & 0xc000) == 0x4000) { - /* Number and offset of logical sectors per physical sector */ - if (word_106 & (1 << 13)) - log_per_phys = word_106 & 0xf; - if ((word_209 & 0xc000) == 0x4000) { - u16 first = dev->id[209] & 0x3fff; - if (first > 0) - lowest_aligned = (1 << log_per_phys) - first; - } - } + u32 sector_size; /* physical sector size in bytes */ + u8 log2_per_phys; + u16 lowest_aligned; + + sector_size = ata_id_logical_sector_size(dev->id); + log2_per_phys = ata_id_log2_per_physical_sector(dev->id); + lowest_aligned = ata_id_logical_sector_offset(dev->id, log2_per_phys); VPRINTK("ENTER\n"); @@ -2426,8 +2397,10 @@ static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf) rbuf[3] = last_lba; /* sector size */ - rbuf[6] = ATA_SECT_SIZE >> 8; - rbuf[7] = ATA_SECT_SIZE & 0xff; + rbuf[4] = sector_size >> (8 * 3); + rbuf[5] = sector_size >> (8 * 2); + rbuf[6] = sector_size >> (8 * 1); + rbuf[7] = sector_size; } else { /* sector count, 64-bit */ rbuf[0] = last_lba >> (8 * 7); @@ -2440,11 +2413,13 @@ static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf) rbuf[7] = last_lba; /* sector size */ - rbuf[10] = ATA_SECT_SIZE >> 8; - rbuf[11] = ATA_SECT_SIZE & 0xff; + rbuf[ 8] = sector_size >> (8 * 3); + rbuf[ 9] = sector_size >> (8 * 2); + rbuf[10] = sector_size >> (8 * 1); + rbuf[11] = sector_size; rbuf[12] = 0; - rbuf[13] = log_per_phys; + rbuf[13] = log2_per_phys; rbuf[14] = (lowest_aligned >> 8) & 0x3f; rbuf[15] = lowest_aligned; @@ -2888,9 +2863,8 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc) tf->device = dev->devno ? tf->device | ATA_DEV1 : tf->device & ~ATA_DEV1; - /* READ/WRITE LONG use a non-standard sect_size */ - qc->sect_size = ATA_SECT_SIZE; switch (tf->command) { + /* READ/WRITE LONG use a non-standard sect_size */ case ATA_CMD_READ_LONG: case ATA_CMD_READ_LONG_ONCE: case ATA_CMD_WRITE_LONG: @@ -2898,6 +2872,45 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc) if (tf->protocol != ATA_PROT_PIO || tf->nsect != 1) goto invalid_fld; qc->sect_size = scsi_bufflen(scmd); + break; + + /* commands using reported Logical Block size (e.g. 512 or 4K) */ + case ATA_CMD_CFA_WRITE_NE: + case ATA_CMD_CFA_TRANS_SECT: + case ATA_CMD_CFA_WRITE_MULT_NE: + /* XXX: case ATA_CMD_CFA_WRITE_SECTORS_WITHOUT_ERASE: */ + case ATA_CMD_READ: + case ATA_CMD_READ_EXT: + case ATA_CMD_READ_QUEUED: + /* XXX: case ATA_CMD_READ_QUEUED_EXT: */ + case ATA_CMD_FPDMA_READ: + case ATA_CMD_READ_MULTI: + case ATA_CMD_READ_MULTI_EXT: + case ATA_CMD_PIO_READ: + case ATA_CMD_PIO_READ_EXT: + case ATA_CMD_READ_STREAM_DMA_EXT: + case ATA_CMD_READ_STREAM_EXT: + case ATA_CMD_VERIFY: + case ATA_CMD_VERIFY_EXT: + case ATA_CMD_WRITE: + case ATA_CMD_WRITE_EXT: + case ATA_CMD_WRITE_FUA_EXT: + case ATA_CMD_WRITE_QUEUED: + case ATA_CMD_WRITE_QUEUED_FUA_EXT: + case ATA_CMD_FPDMA_WRITE: + case ATA_CMD_WRITE_MULTI: + case ATA_CMD_WRITE_MULTI_EXT: + case ATA_CMD_WRITE_MULTI_FUA_EXT: + case ATA_CMD_PIO_WRITE: + case ATA_CMD_PIO_WRITE_EXT: + case ATA_CMD_WRITE_STREAM_DMA_EXT: + case ATA_CMD_WRITE_STREAM_EXT: + qc->sect_size = scmd->device->sector_size; + break; + + /* Everything else uses 512 byte "sectors" */ + default: + qc->sect_size = ATA_SECT_SIZE; } /* @@ -3250,6 +3263,9 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd, case 0xb1: ata_scsi_rbuf_fill(&args, ata_scsiop_inq_b1); break; + case 0xb2: + ata_scsi_rbuf_fill(&args, ata_scsiop_inq_b2); + break; default: ata_scsi_invalid_field(cmd, done); break; @@ -3334,7 +3350,7 @@ int ata_scsi_add_hosts(struct ata_host *host, struct scsi_host_template *sht) *(struct ata_port **)&shost->hostdata[0] = ap; ap->scsi_host = shost; - shost->transportt = &ata_scsi_transport_template; + shost->transportt = ata_scsi_transport_template; shost->unique_id = ap->print_id; shost->max_id = 16; shost->max_lun = 1; @@ -3393,6 +3409,8 @@ void ata_scsi_scan_host(struct ata_port *ap, int sync) if (!IS_ERR(sdev)) { dev->sdev = sdev; scsi_device_put(sdev); + } else { + dev->sdev = NULL; } } } @@ -3616,8 +3634,8 @@ void ata_scsi_hotplug(struct work_struct *work) * RETURNS: * Zero. */ -static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel, - unsigned int id, unsigned int lun) +int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel, + unsigned int id, unsigned int lun) { struct ata_port *ap = ata_shost_to_port(shost); unsigned long flags; diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index e30c537cce32..d05387d1e14b 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -222,7 +222,7 @@ int ata_sff_busy_sleep(struct ata_port *ap, timeout = ata_deadline(timer_start, tmout_pat); while (status != 0xff && (status & ATA_BUSY) && time_before(jiffies, timeout)) { - msleep(50); + ata_msleep(ap, 50); status = ata_sff_busy_wait(ap, ATA_BUSY, 3); } @@ -234,7 +234,7 @@ int ata_sff_busy_sleep(struct ata_port *ap, timeout = ata_deadline(timer_start, tmout); while (status != 0xff && (status & ATA_BUSY) && time_before(jiffies, timeout)) { - msleep(50); + ata_msleep(ap, 50); status = ap->ops->sff_check_status(ap); } @@ -360,7 +360,7 @@ static void ata_dev_select(struct ata_port *ap, unsigned int device, if (wait) { if (can_sleep && ap->link.device[device].class == ATA_DEV_ATAPI) - msleep(150); + ata_msleep(ap, 150); ata_wait_idle(ap); } } @@ -1356,7 +1356,7 @@ fsm_start: */ status = ata_sff_busy_wait(ap, ATA_BUSY, 5); if (status & ATA_BUSY) { - msleep(2); + ata_msleep(ap, 2); status = ata_sff_busy_wait(ap, ATA_BUSY, 10); if (status & ATA_BUSY) { ata_sff_queue_pio_task(link, ATA_SHORT_PAUSE); @@ -1937,7 +1937,7 @@ int ata_sff_wait_after_reset(struct ata_link *link, unsigned int devmask, unsigned int dev1 = devmask & (1 << 1); int rc, ret = 0; - msleep(ATA_WAIT_AFTER_RESET); + ata_msleep(ap, ATA_WAIT_AFTER_RESET); /* always check readiness of the master device */ rc = ata_sff_wait_ready(link, deadline); @@ -1966,7 +1966,7 @@ int ata_sff_wait_after_reset(struct ata_link *link, unsigned int devmask, lbal = ioread8(ioaddr->lbal_addr); if ((nsect == 1) && (lbal == 1)) break; - msleep(50); /* give drive a breather */ + ata_msleep(ap, 50); /* give drive a breather */ } rc = ata_sff_wait_ready(link, deadline); @@ -3335,14 +3335,14 @@ void ata_sff_port_init(struct ata_port *ap) int __init ata_sff_init(void) { - ata_sff_wq = alloc_workqueue("ata_sff", WQ_RESCUER, WQ_MAX_ACTIVE); + ata_sff_wq = alloc_workqueue("ata_sff", WQ_MEM_RECLAIM, WQ_MAX_ACTIVE); if (!ata_sff_wq) return -ENOMEM; return 0; } -void __exit ata_sff_exit(void) +void ata_sff_exit(void) { destroy_workqueue(ata_sff_wq); } diff --git a/drivers/ata/libata-transport.c b/drivers/ata/libata-transport.c new file mode 100644 index 000000000000..ce9dc6207f37 --- /dev/null +++ b/drivers/ata/libata-transport.c @@ -0,0 +1,774 @@ +/* + * Copyright 2008 ioogle, Inc. All rights reserved. + * Released under GPL v2. + * + * Libata transport class. + * + * The ATA transport class contains common code to deal with ATA HBAs, + * an approximated representation of ATA topologies in the driver model, + * and various sysfs attributes to expose these topologies and management + * interfaces to user-space. + * + * There are 3 objects defined in in this class: + * - ata_port + * - ata_link + * - ata_device + * Each port has a link object. Each link can have up to two devices for PATA + * and generally one for SATA. + * If there is SATA port multiplier [PMP], 15 additional ata_link object are + * created. + * + * These objects are created when the ata host is initialized and when a PMP is + * found. They are removed only when the HBA is removed, cleaned before the + * error handler runs. + */ + + +#include <linux/kernel.h> +#include <linux/blkdev.h> +#include <linux/spinlock.h> +#include <linux/slab.h> +#include <scsi/scsi_transport.h> +#include <linux/libata.h> +#include <linux/hdreg.h> +#include <linux/uaccess.h> + +#include "libata.h" +#include "libata-transport.h" + +#define ATA_PORT_ATTRS 2 +#define ATA_LINK_ATTRS 3 +#define ATA_DEV_ATTRS 9 + +struct scsi_transport_template; +struct scsi_transport_template *ata_scsi_transport_template; + +struct ata_internal { + struct scsi_transport_template t; + + struct device_attribute private_port_attrs[ATA_PORT_ATTRS]; + struct device_attribute private_link_attrs[ATA_LINK_ATTRS]; + struct device_attribute private_dev_attrs[ATA_DEV_ATTRS]; + + struct transport_container link_attr_cont; + struct transport_container dev_attr_cont; + + /* + * The array of null terminated pointers to attributes + * needed by scsi_sysfs.c + */ + struct device_attribute *link_attrs[ATA_LINK_ATTRS + 1]; + struct device_attribute *port_attrs[ATA_PORT_ATTRS + 1]; + struct device_attribute *dev_attrs[ATA_DEV_ATTRS + 1]; +}; +#define to_ata_internal(tmpl) container_of(tmpl, struct ata_internal, t) + + +#define tdev_to_device(d) \ + container_of((d), struct ata_device, tdev) +#define transport_class_to_dev(dev) \ + tdev_to_device((dev)->parent) + +#define tdev_to_link(d) \ + container_of((d), struct ata_link, tdev) +#define transport_class_to_link(dev) \ + tdev_to_link((dev)->parent) + +#define tdev_to_port(d) \ + container_of((d), struct ata_port, tdev) +#define transport_class_to_port(dev) \ + tdev_to_port((dev)->parent) + + +/* Device objects are always created whit link objects */ +static int ata_tdev_add(struct ata_device *dev); +static void ata_tdev_delete(struct ata_device *dev); + + +/* + * Hack to allow attributes of the same name in different objects. + */ +#define ATA_DEVICE_ATTR(_prefix,_name,_mode,_show,_store) \ + struct device_attribute device_attr_##_prefix##_##_name = \ + __ATTR(_name,_mode,_show,_store) + +#define ata_bitfield_name_match(title, table) \ +static ssize_t \ +get_ata_##title##_names(u32 table_key, char *buf) \ +{ \ + char *prefix = ""; \ + ssize_t len = 0; \ + int i; \ + \ + for (i = 0; i < ARRAY_SIZE(table); i++) { \ + if (table[i].value & table_key) { \ + len += sprintf(buf + len, "%s%s", \ + prefix, table[i].name); \ + prefix = ", "; \ + } \ + } \ + len += sprintf(buf + len, "\n"); \ + return len; \ +} + +#define ata_bitfield_name_search(title, table) \ +static ssize_t \ +get_ata_##title##_names(u32 table_key, char *buf) \ +{ \ + ssize_t len = 0; \ + int i; \ + \ + for (i = 0; i < ARRAY_SIZE(table); i++) { \ + if (table[i].value == table_key) { \ + len += sprintf(buf + len, "%s", \ + table[i].name); \ + break; \ + } \ + } \ + len += sprintf(buf + len, "\n"); \ + return len; \ +} + +static struct { + u32 value; + char *name; +} ata_class_names[] = { + { ATA_DEV_UNKNOWN, "unknown" }, + { ATA_DEV_ATA, "ata" }, + { ATA_DEV_ATA_UNSUP, "ata" }, + { ATA_DEV_ATAPI, "atapi" }, + { ATA_DEV_ATAPI_UNSUP, "atapi" }, + { ATA_DEV_PMP, "pmp" }, + { ATA_DEV_PMP_UNSUP, "pmp" }, + { ATA_DEV_SEMB, "semb" }, + { ATA_DEV_SEMB_UNSUP, "semb" }, + { ATA_DEV_NONE, "none" } +}; +ata_bitfield_name_search(class, ata_class_names) + + +static struct { + u32 value; + char *name; +} ata_err_names[] = { + { AC_ERR_DEV, "DeviceError" }, + { AC_ERR_HSM, "HostStateMachineError" }, + { AC_ERR_TIMEOUT, "Timeout" }, + { AC_ERR_MEDIA, "MediaError" }, + { AC_ERR_ATA_BUS, "BusError" }, + { AC_ERR_HOST_BUS, "HostBusError" }, + { AC_ERR_SYSTEM, "SystemError" }, + { AC_ERR_INVALID, "InvalidArg" }, + { AC_ERR_OTHER, "Unknown" }, + { AC_ERR_NODEV_HINT, "NoDeviceHint" }, + { AC_ERR_NCQ, "NCQError" } +}; +ata_bitfield_name_match(err, ata_err_names) + +static struct { + u32 value; + char *name; +} ata_xfer_names[] = { + { XFER_UDMA_7, "XFER_UDMA_7" }, + { XFER_UDMA_6, "XFER_UDMA_6" }, + { XFER_UDMA_5, "XFER_UDMA_5" }, + { XFER_UDMA_4, "XFER_UDMA_4" }, + { XFER_UDMA_3, "XFER_UDMA_3" }, + { XFER_UDMA_2, "XFER_UDMA_2" }, + { XFER_UDMA_1, "XFER_UDMA_1" }, + { XFER_UDMA_0, "XFER_UDMA_0" }, + { XFER_MW_DMA_4, "XFER_MW_DMA_4" }, + { XFER_MW_DMA_3, "XFER_MW_DMA_3" }, + { XFER_MW_DMA_2, "XFER_MW_DMA_2" }, + { XFER_MW_DMA_1, "XFER_MW_DMA_1" }, + { XFER_MW_DMA_0, "XFER_MW_DMA_0" }, + { XFER_SW_DMA_2, "XFER_SW_DMA_2" }, + { XFER_SW_DMA_1, "XFER_SW_DMA_1" }, + { XFER_SW_DMA_0, "XFER_SW_DMA_0" }, + { XFER_PIO_6, "XFER_PIO_6" }, + { XFER_PIO_5, "XFER_PIO_5" }, + { XFER_PIO_4, "XFER_PIO_4" }, + { XFER_PIO_3, "XFER_PIO_3" }, + { XFER_PIO_2, "XFER_PIO_2" }, + { XFER_PIO_1, "XFER_PIO_1" }, + { XFER_PIO_0, "XFER_PIO_0" }, + { XFER_PIO_SLOW, "XFER_PIO_SLOW" } +}; +ata_bitfield_name_match(xfer,ata_xfer_names) + +/* + * ATA Port attributes + */ +#define ata_port_show_simple(field, name, format_string, cast) \ +static ssize_t \ +show_ata_port_##name(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ \ + struct ata_port *ap = transport_class_to_port(dev); \ + \ + return snprintf(buf, 20, format_string, cast ap->field); \ +} + +#define ata_port_simple_attr(field, name, format_string, type) \ + ata_port_show_simple(field, name, format_string, (type)) \ +static DEVICE_ATTR(name, S_IRUGO, show_ata_port_##name, NULL) + +ata_port_simple_attr(nr_pmp_links, nr_pmp_links, "%d\n", int); +ata_port_simple_attr(stats.idle_irq, idle_irq, "%ld\n", unsigned long); + +static DECLARE_TRANSPORT_CLASS(ata_port_class, + "ata_port", NULL, NULL, NULL); + +static void ata_tport_release(struct device *dev) +{ + put_device(dev->parent); +} + +/** + * ata_is_port -- check if a struct device represents a ATA port + * @dev: device to check + * + * Returns: + * %1 if the device represents a ATA Port, %0 else + */ +int ata_is_port(const struct device *dev) +{ + return dev->release == ata_tport_release; +} + +static int ata_tport_match(struct attribute_container *cont, + struct device *dev) +{ + if (!ata_is_port(dev)) + return 0; + return &ata_scsi_transport_template->host_attrs.ac == cont; +} + +/** + * ata_tport_delete -- remove ATA PORT + * @port: ATA PORT to remove + * + * Removes the specified ATA PORT. Remove the associated link as well. + */ +void ata_tport_delete(struct ata_port *ap) +{ + struct device *dev = &ap->tdev; + + ata_tlink_delete(&ap->link); + + transport_remove_device(dev); + device_del(dev); + transport_destroy_device(dev); + put_device(dev); +} + +/** ata_tport_add - initialize a transport ATA port structure + * + * @parent: parent device + * @ap: existing ata_port structure + * + * Initialize a ATA port structure for sysfs. It will be added to the device + * tree below the device specified by @parent which could be a PCI device. + * + * Returns %0 on success + */ +int ata_tport_add(struct device *parent, + struct ata_port *ap) +{ + int error; + struct device *dev = &ap->tdev; + + device_initialize(dev); + + dev->parent = get_device(parent); + dev->release = ata_tport_release; + dev_set_name(dev, "ata%d", ap->print_id); + transport_setup_device(dev); + error = device_add(dev); + if (error) { + goto tport_err; + } + + transport_add_device(dev); + transport_configure_device(dev); + + error = ata_tlink_add(&ap->link); + if (error) { + goto tport_link_err; + } + return 0; + + tport_link_err: + transport_remove_device(dev); + device_del(dev); + + tport_err: + transport_destroy_device(dev); + put_device(dev); + return error; +} + + +/* + * ATA link attributes + */ + + +#define ata_link_show_linkspeed(field) \ +static ssize_t \ +show_ata_link_##field(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ \ + struct ata_link *link = transport_class_to_link(dev); \ + \ + return sprintf(buf,"%s\n", sata_spd_string(fls(link->field))); \ +} + +#define ata_link_linkspeed_attr(field) \ + ata_link_show_linkspeed(field) \ +static DEVICE_ATTR(field, S_IRUGO, show_ata_link_##field, NULL) + +ata_link_linkspeed_attr(hw_sata_spd_limit); +ata_link_linkspeed_attr(sata_spd_limit); +ata_link_linkspeed_attr(sata_spd); + + +static DECLARE_TRANSPORT_CLASS(ata_link_class, + "ata_link", NULL, NULL, NULL); + +static void ata_tlink_release(struct device *dev) +{ + put_device(dev->parent); +} + +/** + * ata_is_link -- check if a struct device represents a ATA link + * @dev: device to check + * + * Returns: + * %1 if the device represents a ATA link, %0 else + */ +int ata_is_link(const struct device *dev) +{ + return dev->release == ata_tlink_release; +} + +static int ata_tlink_match(struct attribute_container *cont, + struct device *dev) +{ + struct ata_internal* i = to_ata_internal(ata_scsi_transport_template); + if (!ata_is_link(dev)) + return 0; + return &i->link_attr_cont.ac == cont; +} + +/** + * ata_tlink_delete -- remove ATA LINK + * @port: ATA LINK to remove + * + * Removes the specified ATA LINK. remove associated ATA device(s) as well. + */ +void ata_tlink_delete(struct ata_link *link) +{ + struct device *dev = &link->tdev; + struct ata_device *ata_dev; + + ata_for_each_dev(ata_dev, link, ALL) { + ata_tdev_delete(ata_dev); + } + + transport_remove_device(dev); + device_del(dev); + transport_destroy_device(dev); + put_device(dev); +} + +/** + * ata_tlink_add -- initialize a transport ATA link structure + * @link: allocated ata_link structure. + * + * Initialize an ATA LINK structure for sysfs. It will be added in the + * device tree below the ATA PORT it belongs to. + * + * Returns %0 on success + */ +int ata_tlink_add(struct ata_link *link) +{ + struct device *dev = &link->tdev; + struct ata_port *ap = link->ap; + struct ata_device *ata_dev; + int error; + + device_initialize(dev); + dev->parent = get_device(&ap->tdev); + dev->release = ata_tlink_release; + if (ata_is_host_link(link)) + dev_set_name(dev, "link%d", ap->print_id); + else + dev_set_name(dev, "link%d.%d", ap->print_id, link->pmp); + + transport_setup_device(dev); + + error = device_add(dev); + if (error) { + goto tlink_err; + } + + transport_add_device(dev); + transport_configure_device(dev); + + ata_for_each_dev(ata_dev, link, ALL) { + error = ata_tdev_add(ata_dev); + if (error) { + goto tlink_dev_err; + } + } + return 0; + tlink_dev_err: + while (--ata_dev >= link->device) { + ata_tdev_delete(ata_dev); + } + transport_remove_device(dev); + device_del(dev); + tlink_err: + transport_destroy_device(dev); + put_device(dev); + return error; +} + +/* + * ATA device attributes + */ + +#define ata_dev_show_class(title, field) \ +static ssize_t \ +show_ata_dev_##field(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ \ + struct ata_device *ata_dev = transport_class_to_dev(dev); \ + \ + return get_ata_##title##_names(ata_dev->field, buf); \ +} + +#define ata_dev_attr(title, field) \ + ata_dev_show_class(title, field) \ +static DEVICE_ATTR(field, S_IRUGO, show_ata_dev_##field, NULL) + +ata_dev_attr(class, class); +ata_dev_attr(xfer, pio_mode); +ata_dev_attr(xfer, dma_mode); +ata_dev_attr(xfer, xfer_mode); + + +#define ata_dev_show_simple(field, format_string, cast) \ +static ssize_t \ +show_ata_dev_##field(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ \ + struct ata_device *ata_dev = transport_class_to_dev(dev); \ + \ + return snprintf(buf, 20, format_string, cast ata_dev->field); \ +} + +#define ata_dev_simple_attr(field, format_string, type) \ + ata_dev_show_simple(field, format_string, (type)) \ +static DEVICE_ATTR(field, S_IRUGO, \ + show_ata_dev_##field, NULL) + +ata_dev_simple_attr(spdn_cnt, "%d\n", int); + +struct ata_show_ering_arg { + char* buf; + int written; +}; + +static int ata_show_ering(struct ata_ering_entry *ent, void *void_arg) +{ + struct ata_show_ering_arg* arg = void_arg; + struct timespec time; + + jiffies_to_timespec(ent->timestamp,&time); + arg->written += sprintf(arg->buf + arg->written, + "[%5lu.%06lu]", + time.tv_sec, time.tv_nsec); + arg->written += get_ata_err_names(ent->err_mask, + arg->buf + arg->written); + return 0; +} + +static ssize_t +show_ata_dev_ering(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ata_device *ata_dev = transport_class_to_dev(dev); + struct ata_show_ering_arg arg = { buf, 0 }; + + ata_ering_map(&ata_dev->ering, ata_show_ering, &arg); + return arg.written; +} + + +static DEVICE_ATTR(ering, S_IRUGO, show_ata_dev_ering, NULL); + +static ssize_t +show_ata_dev_id(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ata_device *ata_dev = transport_class_to_dev(dev); + int written = 0, i = 0; + + if (ata_dev->class == ATA_DEV_PMP) + return 0; + for(i=0;i<ATA_ID_WORDS;i++) { + written += snprintf(buf+written, 20, "%04x%c", + ata_dev->id[i], + ((i+1) & 7) ? ' ' : '\n'); + } + return written; +} + +static DEVICE_ATTR(id, S_IRUGO, show_ata_dev_id, NULL); + +static ssize_t +show_ata_dev_gscr(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ata_device *ata_dev = transport_class_to_dev(dev); + int written = 0, i = 0; + + if (ata_dev->class != ATA_DEV_PMP) + return 0; + for(i=0;i<SATA_PMP_GSCR_DWORDS;i++) { + written += snprintf(buf+written, 20, "%08x%c", + ata_dev->gscr[i], + ((i+1) & 3) ? ' ' : '\n'); + } + if (SATA_PMP_GSCR_DWORDS & 3) + buf[written-1] = '\n'; + return written; +} + +static DEVICE_ATTR(gscr, S_IRUGO, show_ata_dev_gscr, NULL); + +static DECLARE_TRANSPORT_CLASS(ata_dev_class, + "ata_device", NULL, NULL, NULL); + +static void ata_tdev_release(struct device *dev) +{ + put_device(dev->parent); +} + +/** + * ata_is_ata_dev -- check if a struct device represents a ATA device + * @dev: device to check + * + * Returns: + * %1 if the device represents a ATA device, %0 else + */ +int ata_is_ata_dev(const struct device *dev) +{ + return dev->release == ata_tdev_release; +} + +static int ata_tdev_match(struct attribute_container *cont, + struct device *dev) +{ + struct ata_internal* i = to_ata_internal(ata_scsi_transport_template); + if (!ata_is_ata_dev(dev)) + return 0; + return &i->dev_attr_cont.ac == cont; +} + +/** + * ata_tdev_free -- free a ATA LINK + * @dev: ATA PHY to free + * + * Frees the specified ATA PHY. + * + * Note: + * This function must only be called on a PHY that has not + * successfully been added using ata_tdev_add(). + */ +static void ata_tdev_free(struct ata_device *dev) +{ + transport_destroy_device(&dev->tdev); + put_device(&dev->tdev); +} + +/** + * ata_tdev_delete -- remove ATA device + * @port: ATA PORT to remove + * + * Removes the specified ATA device. + */ +static void ata_tdev_delete(struct ata_device *ata_dev) +{ + struct device *dev = &ata_dev->tdev; + + transport_remove_device(dev); + device_del(dev); + ata_tdev_free(ata_dev); +} + + +/** + * ata_tdev_add -- initialize a transport ATA device structure. + * @ata_dev: ata_dev structure. + * + * Initialize an ATA device structure for sysfs. It will be added in the + * device tree below the ATA LINK device it belongs to. + * + * Returns %0 on success + */ +static int ata_tdev_add(struct ata_device *ata_dev) +{ + struct device *dev = &ata_dev->tdev; + struct ata_link *link = ata_dev->link; + struct ata_port *ap = link->ap; + int error; + + device_initialize(dev); + dev->parent = get_device(&link->tdev); + dev->release = ata_tdev_release; + if (ata_is_host_link(link)) + dev_set_name(dev, "dev%d.%d", ap->print_id,ata_dev->devno); + else + dev_set_name(dev, "dev%d.%d.0", ap->print_id, link->pmp); + + transport_setup_device(dev); + error = device_add(dev); + if (error) { + ata_tdev_free(ata_dev); + return error; + } + + transport_add_device(dev); + transport_configure_device(dev); + return 0; +} + + +/* + * Setup / Teardown code + */ + +#define SETUP_TEMPLATE(attrb, field, perm, test) \ + i->private_##attrb[count] = dev_attr_##field; \ + i->private_##attrb[count].attr.mode = perm; \ + i->attrb[count] = &i->private_##attrb[count]; \ + if (test) \ + count++ + +#define SETUP_LINK_ATTRIBUTE(field) \ + SETUP_TEMPLATE(link_attrs, field, S_IRUGO, 1) + +#define SETUP_PORT_ATTRIBUTE(field) \ + SETUP_TEMPLATE(port_attrs, field, S_IRUGO, 1) + +#define SETUP_DEV_ATTRIBUTE(field) \ + SETUP_TEMPLATE(dev_attrs, field, S_IRUGO, 1) + +/** + * ata_attach_transport -- instantiate ATA transport template + */ +struct scsi_transport_template *ata_attach_transport(void) +{ + struct ata_internal *i; + int count; + + i = kzalloc(sizeof(struct ata_internal), GFP_KERNEL); + if (!i) + return NULL; + + i->t.eh_strategy_handler = ata_scsi_error; + i->t.eh_timed_out = ata_scsi_timed_out; + i->t.user_scan = ata_scsi_user_scan; + + i->t.host_attrs.ac.attrs = &i->port_attrs[0]; + i->t.host_attrs.ac.class = &ata_port_class.class; + i->t.host_attrs.ac.match = ata_tport_match; + transport_container_register(&i->t.host_attrs); + + i->link_attr_cont.ac.class = &ata_link_class.class; + i->link_attr_cont.ac.attrs = &i->link_attrs[0]; + i->link_attr_cont.ac.match = ata_tlink_match; + transport_container_register(&i->link_attr_cont); + + i->dev_attr_cont.ac.class = &ata_dev_class.class; + i->dev_attr_cont.ac.attrs = &i->dev_attrs[0]; + i->dev_attr_cont.ac.match = ata_tdev_match; + transport_container_register(&i->dev_attr_cont); + + count = 0; + SETUP_PORT_ATTRIBUTE(nr_pmp_links); + SETUP_PORT_ATTRIBUTE(idle_irq); + BUG_ON(count > ATA_PORT_ATTRS); + i->port_attrs[count] = NULL; + + count = 0; + SETUP_LINK_ATTRIBUTE(hw_sata_spd_limit); + SETUP_LINK_ATTRIBUTE(sata_spd_limit); + SETUP_LINK_ATTRIBUTE(sata_spd); + BUG_ON(count > ATA_LINK_ATTRS); + i->link_attrs[count] = NULL; + + count = 0; + SETUP_DEV_ATTRIBUTE(class); + SETUP_DEV_ATTRIBUTE(pio_mode); + SETUP_DEV_ATTRIBUTE(dma_mode); + SETUP_DEV_ATTRIBUTE(xfer_mode); + SETUP_DEV_ATTRIBUTE(spdn_cnt); + SETUP_DEV_ATTRIBUTE(ering); + SETUP_DEV_ATTRIBUTE(id); + SETUP_DEV_ATTRIBUTE(gscr); + BUG_ON(count > ATA_DEV_ATTRS); + i->dev_attrs[count] = NULL; + + return &i->t; +} + +/** + * ata_release_transport -- release ATA transport template instance + * @t: transport template instance + */ +void ata_release_transport(struct scsi_transport_template *t) +{ + struct ata_internal *i = to_ata_internal(t); + + transport_container_unregister(&i->t.host_attrs); + transport_container_unregister(&i->link_attr_cont); + transport_container_unregister(&i->dev_attr_cont); + + kfree(i); +} + +__init int libata_transport_init(void) +{ + int error; + + error = transport_class_register(&ata_link_class); + if (error) + goto out_unregister_transport; + error = transport_class_register(&ata_port_class); + if (error) + goto out_unregister_link; + error = transport_class_register(&ata_dev_class); + if (error) + goto out_unregister_port; + return 0; + + out_unregister_port: + transport_class_unregister(&ata_port_class); + out_unregister_link: + transport_class_unregister(&ata_link_class); + out_unregister_transport: + return error; + +} + +void __exit libata_transport_exit(void) +{ + transport_class_unregister(&ata_link_class); + transport_class_unregister(&ata_port_class); + transport_class_unregister(&ata_dev_class); +} diff --git a/drivers/ata/libata-transport.h b/drivers/ata/libata-transport.h new file mode 100644 index 000000000000..2820cf864f11 --- /dev/null +++ b/drivers/ata/libata-transport.h @@ -0,0 +1,18 @@ +#ifndef _LIBATA_TRANSPORT_H +#define _LIBATA_TRANSPORT_H + + +extern struct scsi_transport_template *ata_scsi_transport_template; + +int ata_tlink_add(struct ata_link *link); +void ata_tlink_delete(struct ata_link *link); + +int ata_tport_add(struct device *parent, struct ata_port *ap); +void ata_tport_delete(struct ata_port *ap); + +struct scsi_transport_template *ata_attach_transport(void); +void ata_release_transport(struct scsi_transport_template *t); + +__init int libata_transport_init(void); +void __exit libata_transport_exit(void); +#endif diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 9ce1ecc63e39..a9be110dbf51 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -86,6 +86,8 @@ extern int ata_dev_revalidate(struct ata_device *dev, unsigned int new_class, extern int ata_dev_configure(struct ata_device *dev); extern int sata_down_spd_limit(struct ata_link *link, u32 spd_limit); extern int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel); +extern unsigned int ata_dev_set_feature(struct ata_device *dev, + u8 enable, u8 feature); extern void ata_sg_clean(struct ata_queued_cmd *qc); extern void ata_qc_free(struct ata_queued_cmd *qc); extern void ata_qc_issue(struct ata_queued_cmd *qc); @@ -100,8 +102,7 @@ extern int sata_link_init_spd(struct ata_link *link); extern int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg); extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg); extern struct ata_port *ata_port_alloc(struct ata_host *host); -extern void ata_dev_enable_pm(struct ata_device *dev, enum link_pm policy); -extern void ata_lpm_schedule(struct ata_port *ap, enum link_pm); +extern const char *sata_spd_string(unsigned int spd); /* libata-acpi.c */ #ifdef CONFIG_ATA_ACPI @@ -137,10 +138,15 @@ extern void ata_scsi_hotplug(struct work_struct *work); extern void ata_schedule_scsi_eh(struct Scsi_Host *shost); extern void ata_scsi_dev_rescan(struct work_struct *work); extern int ata_bus_probe(struct ata_port *ap); +extern int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel, + unsigned int id, unsigned int lun); + /* libata-eh.c */ extern unsigned long ata_internal_cmd_timeout(struct ata_device *dev, u8 cmd); extern void ata_internal_cmd_timed_out(struct ata_device *dev, u8 cmd); +extern void ata_eh_acquire(struct ata_port *ap); +extern void ata_eh_release(struct ata_port *ap); extern enum blk_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd); extern void ata_scsi_error(struct Scsi_Host *host); extern void ata_port_wait_eh(struct ata_port *ap); @@ -164,11 +170,16 @@ extern int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, ata_postreset_fn_t postreset, struct ata_link **r_failed_disk); extern void ata_eh_finish(struct ata_port *ap); +extern int ata_ering_map(struct ata_ering *ering, + int (*map_fn)(struct ata_ering_entry *, void *), + void *arg); /* libata-pmp.c */ #ifdef CONFIG_SATA_PMP extern int sata_pmp_scr_read(struct ata_link *link, int reg, u32 *val); extern int sata_pmp_scr_write(struct ata_link *link, int reg, u32 val); +extern int sata_pmp_set_lpm(struct ata_link *link, enum ata_lpm_policy policy, + unsigned hints); extern int sata_pmp_attach(struct ata_device *dev); #else /* CONFIG_SATA_PMP */ static inline int sata_pmp_scr_read(struct ata_link *link, int reg, u32 *val) @@ -181,6 +192,12 @@ static inline int sata_pmp_scr_write(struct ata_link *link, int reg, u32 val) return -EINVAL; } +static inline int sata_pmp_set_lpm(struct ata_link *link, + enum ata_lpm_policy policy, unsigned hints) +{ + return -EINVAL; +} + static inline int sata_pmp_attach(struct ata_device *dev) { return -EINVAL; diff --git a/drivers/ata/pata_bf54x.c b/drivers/ata/pata_bf54x.c index 9cae65de750e..ec2c777fcdb0 100644 --- a/drivers/ata/pata_bf54x.c +++ b/drivers/ata/pata_bf54x.c @@ -826,7 +826,7 @@ static void bfin_dev_select(struct ata_port *ap, unsigned int device) * @ctl: value to write */ -static u8 bfin_set_devctl(struct ata_port *ap, u8 ctl) +static void bfin_set_devctl(struct ata_port *ap, u8 ctl) { void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; write_atapi_register(base, ATA_REG_CTRL, ctl); @@ -1046,7 +1046,7 @@ static void bfin_bus_post_reset(struct ata_port *ap, unsigned int devmask) dev1 = 0; break; } - msleep(50); /* give drive a breather */ + ata_msleep(ap, 50); /* give drive a breather */ } if (dev1) ata_sff_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT); @@ -1087,7 +1087,7 @@ static unsigned int bfin_bus_softreset(struct ata_port *ap, * * Old drivers/ide uses the 2mS rule and then waits for ready */ - msleep(150); + ata_msleep(ap, 150); /* Before we perform post reset processing we want to see if * the bus shows 0xFF because the odd clown forgets the D7 diff --git a/drivers/ata/pata_cmd640.c b/drivers/ata/pata_cmd640.c index e5f289f59ca3..549d28dbf90d 100644 --- a/drivers/ata/pata_cmd640.c +++ b/drivers/ata/pata_cmd640.c @@ -161,6 +161,17 @@ static int cmd640_port_start(struct ata_port *ap) return 0; } +static bool cmd640_sff_irq_check(struct ata_port *ap) +{ + struct pci_dev *pdev = to_pci_dev(ap->host->dev); + int irq_reg = ap->port_no ? ARTIM23 : CFR; + u8 irq_stat, irq_mask = ap->port_no ? 0x10 : 0x04; + + pci_read_config_byte(pdev, irq_reg, &irq_stat); + + return irq_stat & irq_mask; +} + static struct scsi_host_template cmd640_sht = { ATA_PIO_SHT(DRV_NAME), }; @@ -169,6 +180,7 @@ static struct ata_port_operations cmd640_port_ops = { .inherits = &ata_sff_port_ops, /* In theory xfer_noirq is not needed once we kill the prefetcher */ .sff_data_xfer = ata_sff_data_xfer_noirq, + .sff_irq_check = cmd640_sff_irq_check, .qc_issue = cmd640_qc_issue, .cable_detect = ata_cable_40wire, .set_piomode = cmd640_set_piomode, diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c index e944aa0c5517..806292160b3f 100644 --- a/drivers/ata/pata_pcmcia.c +++ b/drivers/ata/pata_pcmcia.c @@ -34,7 +34,6 @@ #include <linux/ata.h> #include <linux/libata.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/ds.h> #include <pcmcia/cisreg.h> @@ -168,63 +167,26 @@ static struct ata_port_operations pcmcia_8bit_port_ops = { }; -struct pcmcia_config_check { - unsigned long ctl_base; - int skip_vcc; - int is_kme; -}; - -static int pcmcia_check_one_config(struct pcmcia_device *pdev, - cistpl_cftable_entry_t *cfg, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, - void *priv_data) +static int pcmcia_check_one_config(struct pcmcia_device *pdev, void *priv_data) { - struct pcmcia_config_check *stk = priv_data; - - /* Check for matching Vcc, unless we're desperate */ - if (!stk->skip_vcc) { - if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { - if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) - return -ENODEV; - } else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) { - if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000) - return -ENODEV; - } + int *is_kme = priv_data; + + if (!(pdev->resource[0]->flags & IO_DATA_PATH_WIDTH_8)) { + pdev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; + pdev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; } + pdev->resource[1]->flags &= ~IO_DATA_PATH_WIDTH; + pdev->resource[1]->flags |= IO_DATA_PATH_WIDTH_8; - if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) - pdev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; - else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM)) - pdev->conf.Vpp = dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000; - - if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) { - cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io; - pdev->io_lines = io->flags & CISTPL_IO_LINES_MASK; - pdev->resource[0]->start = io->win[0].base; - if (!(io->flags & CISTPL_IO_16BIT)) { - pdev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; - pdev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; - } - if (io->nwin == 2) { - pdev->resource[0]->end = 8; - pdev->resource[1]->start = io->win[1].base; - pdev->resource[1]->end = (stk->is_kme) ? 2 : 1; - if (pcmcia_request_io(pdev) != 0) - return -ENODEV; - stk->ctl_base = pdev->resource[1]->start; - } else if ((io->nwin == 1) && (io->win[0].len >= 16)) { - pdev->resource[0]->end = io->win[0].len; - pdev->resource[1]->end = 0; - if (pcmcia_request_io(pdev) != 0) - return -ENODEV; - stk->ctl_base = pdev->resource[0]->start + 0x0e; - } else + if (pdev->resource[1]->end) { + pdev->resource[0]->end = 8; + pdev->resource[1]->end = (*is_kme) ? 2 : 1; + } else { + if (pdev->resource[0]->end < 16) return -ENODEV; - /* If we've got this far, we're done */ - return 0; } - return -ENODEV; + + return pcmcia_request_io(pdev); } /** @@ -239,7 +201,6 @@ static int pcmcia_init_one(struct pcmcia_device *pdev) { struct ata_host *host; struct ata_port *ap; - struct pcmcia_config_check *stk = NULL; int is_kme = 0, ret = -ENOMEM, p; unsigned long io_base, ctl_base; void __iomem *io_addr, *ctl_addr; @@ -247,10 +208,8 @@ static int pcmcia_init_one(struct pcmcia_device *pdev) struct ata_port_operations *ops = &pcmcia_port_ops; /* Set up attributes in order to probe card and get resources */ - pdev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; - pdev->resource[1]->flags |= IO_DATA_PATH_WIDTH_8; - pdev->conf.Attributes = CONF_ENABLE_IRQ; - pdev->conf.IntType = INT_MEMORY_AND_IO; + pdev->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO | + CONF_AUTO_SET_VPP | CONF_AUTO_CHECK_VCC; /* See if we have a manufacturer identifier. Use it to set is_kme for vendor quirks */ @@ -258,25 +217,21 @@ static int pcmcia_init_one(struct pcmcia_device *pdev) ((pdev->card_id == PRODID_KME_KXLC005_A) || (pdev->card_id == PRODID_KME_KXLC005_B))); - /* Allocate resoure probing structures */ - - stk = kzalloc(sizeof(*stk), GFP_KERNEL); - if (!stk) - goto out1; - stk->is_kme = is_kme; - stk->skip_vcc = io_base = ctl_base = 0; - - if (pcmcia_loop_config(pdev, pcmcia_check_one_config, stk)) { - stk->skip_vcc = 1; - if (pcmcia_loop_config(pdev, pcmcia_check_one_config, stk)) + if (pcmcia_loop_config(pdev, pcmcia_check_one_config, &is_kme)) { + pdev->config_flags &= ~CONF_AUTO_CHECK_VCC; + if (pcmcia_loop_config(pdev, pcmcia_check_one_config, &is_kme)) goto failed; /* No suitable config found */ } io_base = pdev->resource[0]->start; - ctl_base = stk->ctl_base; + if (pdev->resource[1]->end) + ctl_base = pdev->resource[1]->start; + else + ctl_base = pdev->resource[0]->start + 0x0e; + if (!pdev->irq) goto failed; - ret = pcmcia_request_configuration(pdev, &pdev->conf); + ret = pcmcia_enable_device(pdev); if (ret) goto failed; @@ -329,13 +284,10 @@ static int pcmcia_init_one(struct pcmcia_device *pdev) goto failed; pdev->priv = host; - kfree(stk); return 0; failed: - kfree(stk); pcmcia_disable_device(pdev); -out1: return ret; } @@ -430,9 +382,7 @@ MODULE_DEVICE_TABLE(pcmcia, pcmcia_devices); static struct pcmcia_driver pcmcia_driver = { .owner = THIS_MODULE, - .drv = { - .name = DRV_NAME, - }, + .name = DRV_NAME, .id_table = pcmcia_devices, .probe = pcmcia_init_one, .remove = pcmcia_remove_one, diff --git a/drivers/ata/pata_pdc202xx_old.c b/drivers/ata/pata_pdc202xx_old.c index c39f213e1bbc..c2ed5868dda6 100644 --- a/drivers/ata/pata_pdc202xx_old.c +++ b/drivers/ata/pata_pdc202xx_old.c @@ -44,6 +44,27 @@ static void pdc202xx_exec_command(struct ata_port *ap, ndelay(400); } +static bool pdc202xx_irq_check(struct ata_port *ap) +{ + struct pci_dev *pdev = to_pci_dev(ap->host->dev); + unsigned long master = pci_resource_start(pdev, 4); + u8 sc1d = inb(master + 0x1d); + + if (ap->port_no) { + /* + * bit 7: error, bit 6: interrupting, + * bit 5: FIFO full, bit 4: FIFO empty + */ + return sc1d & 0x40; + } else { + /* + * bit 3: error, bit 2: interrupting, + * bit 1: FIFO full, bit 0: FIFO empty + */ + return sc1d & 0x04; + } +} + /** * pdc202xx_configure_piomode - set chip PIO timing * @ap: ATA interface @@ -282,6 +303,7 @@ static struct ata_port_operations pdc2024x_port_ops = { .set_dmamode = pdc202xx_set_dmamode, .sff_exec_command = pdc202xx_exec_command, + .sff_irq_check = pdc202xx_irq_check, }; static struct ata_port_operations pdc2026x_port_ops = { @@ -297,6 +319,7 @@ static struct ata_port_operations pdc2026x_port_ops = { .port_start = pdc2026x_port_start, .sff_exec_command = pdc202xx_exec_command, + .sff_irq_check = pdc202xx_irq_check, }; static int pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id) diff --git a/drivers/ata/pata_samsung_cf.c b/drivers/ata/pata_samsung_cf.c index 6f9cfb24b751..8a51d673e5b2 100644 --- a/drivers/ata/pata_samsung_cf.c +++ b/drivers/ata/pata_samsung_cf.c @@ -322,7 +322,7 @@ static int pata_s3c_wait_after_reset(struct ata_link *link, { int rc; - msleep(ATA_WAIT_AFTER_RESET); + ata_msleep(link->ap, ATA_WAIT_AFTER_RESET); /* always check readiness of the master device */ rc = ata_sff_wait_ready(link, deadline); diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c index fe36966f7e34..093715c3273a 100644 --- a/drivers/ata/pata_scc.c +++ b/drivers/ata/pata_scc.c @@ -530,7 +530,7 @@ static int scc_wait_after_reset(struct ata_link *link, unsigned int devmask, * * Old drivers/ide uses the 2mS rule and then waits for ready. */ - msleep(150); + ata_msleep(ap, 150); /* always check readiness of the master device */ rc = ata_sff_wait_ready(link, deadline); @@ -559,7 +559,7 @@ static int scc_wait_after_reset(struct ata_link *link, unsigned int devmask, lbal = in_be32(ioaddr->lbal_addr); if ((nsect == 1) && (lbal == 1)) break; - msleep(50); /* give drive a breather */ + ata_msleep(ap, 50); /* give drive a breather */ } rc = ata_sff_wait_ready(link, deadline); diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c index d3190d7ec304..00eefbd84b33 100644 --- a/drivers/ata/pata_sil680.c +++ b/drivers/ata/pata_sil680.c @@ -202,14 +202,25 @@ static void sil680_set_dmamode(struct ata_port *ap, struct ata_device *adev) * LOCKING: * spin_lock_irqsave(host lock) */ -void sil680_sff_exec_command(struct ata_port *ap, - const struct ata_taskfile *tf) +static void sil680_sff_exec_command(struct ata_port *ap, + const struct ata_taskfile *tf) { DPRINTK("ata%u: cmd 0x%X\n", ap->print_id, tf->command); iowrite8(tf->command, ap->ioaddr.command_addr); ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD); } +static bool sil680_sff_irq_check(struct ata_port *ap) +{ + struct pci_dev *pdev = to_pci_dev(ap->host->dev); + unsigned long addr = sil680_selreg(ap, 1); + u8 val; + + pci_read_config_byte(pdev, addr, &val); + + return val & 0x08; +} + static struct scsi_host_template sil680_sht = { ATA_BMDMA_SHT(DRV_NAME), }; @@ -218,6 +229,7 @@ static struct scsi_host_template sil680_sht = { static struct ata_port_operations sil680_port_ops = { .inherits = &ata_bmdma32_port_ops, .sff_exec_command = sil680_sff_exec_command, + .sff_irq_check = sil680_sff_irq_check, .cable_detect = sil680_cable_detect, .set_piomode = sil680_set_piomode, .set_dmamode = sil680_set_dmamode, diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c index 98548f640c8e..7f5d020ed56c 100644 --- a/drivers/ata/pata_sl82c105.c +++ b/drivers/ata/pata_sl82c105.c @@ -227,6 +227,16 @@ static int sl82c105_qc_defer(struct ata_queued_cmd *qc) return 0; } +static bool sl82c105_sff_irq_check(struct ata_port *ap) +{ + struct pci_dev *pdev = to_pci_dev(ap->host->dev); + u32 val, mask = ap->port_no ? CTRL_IDE_IRQB : CTRL_IDE_IRQA; + + pci_read_config_dword(pdev, 0x40, &val); + + return val & mask; +} + static struct scsi_host_template sl82c105_sht = { ATA_BMDMA_SHT(DRV_NAME), }; @@ -239,6 +249,7 @@ static struct ata_port_operations sl82c105_port_ops = { .cable_detect = ata_cable_40wire, .set_piomode = sl82c105_set_piomode, .prereset = sl82c105_pre_reset, + .sff_irq_check = sl82c105_sff_irq_check, }; /** diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c index 7325f77480dc..b0214d00d50b 100644 --- a/drivers/ata/sata_fsl.c +++ b/drivers/ata/sata_fsl.c @@ -678,7 +678,7 @@ static void sata_fsl_port_stop(struct ata_port *ap) iowrite32(temp, hcr_base + HCONTROL); /* Poll for controller to go offline - should happen immediately */ - ata_wait_register(hcr_base + HSTATUS, ONLINE, ONLINE, 1, 1); + ata_wait_register(ap, hcr_base + HSTATUS, ONLINE, ONLINE, 1, 1); ap->private_data = NULL; dma_free_coherent(dev, SATA_FSL_PORT_PRIV_DMA_SZ, @@ -729,7 +729,8 @@ try_offline_again: iowrite32(temp, hcr_base + HCONTROL); /* Poll for controller to go offline */ - temp = ata_wait_register(hcr_base + HSTATUS, ONLINE, ONLINE, 1, 500); + temp = ata_wait_register(ap, hcr_base + HSTATUS, ONLINE, ONLINE, + 1, 500); if (temp & ONLINE) { ata_port_printk(ap, KERN_ERR, @@ -752,7 +753,7 @@ try_offline_again: /* * PHY reset should remain asserted for atleast 1ms */ - msleep(1); + ata_msleep(ap, 1); /* * Now, bring the host controller online again, this can take time @@ -766,7 +767,7 @@ try_offline_again: temp |= HCONTROL_PMP_ATTACHED; iowrite32(temp, hcr_base + HCONTROL); - temp = ata_wait_register(hcr_base + HSTATUS, ONLINE, 0, 1, 500); + temp = ata_wait_register(ap, hcr_base + HSTATUS, ONLINE, 0, 1, 500); if (!(temp & ONLINE)) { ata_port_printk(ap, KERN_ERR, @@ -784,7 +785,7 @@ try_offline_again: * presence */ - temp = ata_wait_register(hcr_base + HSTATUS, 0xFF, 0, 1, 500); + temp = ata_wait_register(ap, hcr_base + HSTATUS, 0xFF, 0, 1, 500); if ((!(temp & 0x10)) || ata_link_offline(link)) { ata_port_printk(ap, KERN_WARNING, "No Device OR PHYRDY change,Hstatus = 0x%x\n", @@ -797,7 +798,7 @@ try_offline_again: * Wait for the first D2H from device,i.e,signature update notification */ start_jiffies = jiffies; - temp = ata_wait_register(hcr_base + HSTATUS, 0xFF, 0x10, + temp = ata_wait_register(ap, hcr_base + HSTATUS, 0xFF, 0x10, 500, jiffies_to_msecs(deadline - start_jiffies)); if ((temp & 0xFF) != 0x18) { @@ -880,7 +881,7 @@ static int sata_fsl_softreset(struct ata_link *link, unsigned int *class, iowrite32(pmp, CQPMP + hcr_base); iowrite32(1, CQ + hcr_base); - temp = ata_wait_register(CQ + hcr_base, 0x1, 0x1, 1, 5000); + temp = ata_wait_register(ap, CQ + hcr_base, 0x1, 0x1, 1, 5000); if (temp & 0x1) { ata_port_printk(ap, KERN_WARNING, "ATA_SRST issue failed\n"); @@ -896,7 +897,7 @@ static int sata_fsl_softreset(struct ata_link *link, unsigned int *class, goto err; } - msleep(1); + ata_msleep(ap, 1); /* * SATA device enters reset state after receving a Control register @@ -915,7 +916,7 @@ static int sata_fsl_softreset(struct ata_link *link, unsigned int *class, if (pmp != SATA_PMP_CTRL_PORT) iowrite32(pmp, CQPMP + hcr_base); iowrite32(1, CQ + hcr_base); - msleep(150); /* ?? */ + ata_msleep(ap, 150); /* ?? */ /* * The above command would have signalled an interrupt on command @@ -1137,17 +1138,13 @@ static void sata_fsl_host_intr(struct ata_port *ap) ioread32(hcr_base + CE)); for (i = 0; i < SATA_FSL_QUEUE_DEPTH; i++) { - if (done_mask & (1 << i)) { - qc = ata_qc_from_tag(ap, i); - if (qc) { - ata_qc_complete(qc); - } + if (done_mask & (1 << i)) DPRINTK ("completing ncq cmd,tag=%d,CC=0x%x,CA=0x%x\n", i, ioread32(hcr_base + CC), ioread32(hcr_base + CA)); - } } + ata_qc_complete_multiple(ap, ap->qc_active ^ done_mask); return; } else if ((ap->qc_active & (1 << ATA_TAG_INTERNAL))) { diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c index a36149ebf4a2..83a44471b189 100644 --- a/drivers/ata/sata_inic162x.c +++ b/drivers/ata/sata_inic162x.c @@ -614,7 +614,7 @@ static int inic_hardreset(struct ata_link *link, unsigned int *class, writew(IDMA_CTL_RST_ATA, idma_ctl); readw(idma_ctl); /* flush */ - msleep(1); + ata_msleep(ap, 1); writew(0, idma_ctl); rc = sata_link_resume(link, timing, deadline); diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index a9fd9709c262..bf74a36d3cc3 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -2743,18 +2743,11 @@ static void mv_err_intr(struct ata_port *ap) } } -static void mv_process_crpb_response(struct ata_port *ap, +static bool mv_process_crpb_response(struct ata_port *ap, struct mv_crpb *response, unsigned int tag, int ncq_enabled) { u8 ata_status; u16 edma_status = le16_to_cpu(response->flags); - struct ata_queued_cmd *qc = ata_qc_from_tag(ap, tag); - - if (unlikely(!qc)) { - ata_port_printk(ap, KERN_ERR, "%s: no qc for tag=%d\n", - __func__, tag); - return; - } /* * edma_status from a response queue entry: @@ -2768,13 +2761,14 @@ static void mv_process_crpb_response(struct ata_port *ap, * Error will be seen/handled by * mv_err_intr(). So do nothing at all here. */ - return; + return false; } } ata_status = edma_status >> CRPB_FLAG_STATUS_SHIFT; if (!ac_err_mask(ata_status)) - ata_qc_complete(qc); + return true; /* else: leave it for mv_err_intr() */ + return false; } static void mv_process_crpb_entries(struct ata_port *ap, struct mv_port_priv *pp) @@ -2783,6 +2777,7 @@ static void mv_process_crpb_entries(struct ata_port *ap, struct mv_port_priv *pp struct mv_host_priv *hpriv = ap->host->private_data; u32 in_index; bool work_done = false; + u32 done_mask = 0; int ncq_enabled = (pp->pp_flags & MV_PP_FLAG_NCQ_EN); /* Get the hardware queue position index */ @@ -2803,15 +2798,19 @@ static void mv_process_crpb_entries(struct ata_port *ap, struct mv_port_priv *pp /* Gen II/IIE: get command tag from CRPB entry */ tag = le16_to_cpu(response->id) & 0x1f; } - mv_process_crpb_response(ap, response, tag, ncq_enabled); + if (mv_process_crpb_response(ap, response, tag, ncq_enabled)) + done_mask |= 1 << tag; work_done = true; } - /* Update the software queue position index in hardware */ - if (work_done) + if (work_done) { + ata_qc_complete_multiple(ap, ap->qc_active ^ done_mask); + + /* Update the software queue position index in hardware */ writelfl((pp->crpb_dma & EDMA_RSP_Q_BASE_LO_MASK) | (pp->resp_idx << EDMA_RSP_Q_PTR_SHIFT), port_mmio + EDMA_RSP_Q_OUT_PTR); + } } static void mv_port_intr(struct ata_port *ap, u32 port_cause) diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index cb89ef8d99d9..7254e255fd78 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -873,29 +873,11 @@ static int nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err) ata_port_freeze(ap); else ata_port_abort(ap); - return 1; + return -1; } - if (likely(flags & NV_CPB_RESP_DONE)) { - struct ata_queued_cmd *qc = ata_qc_from_tag(ap, cpb_num); - VPRINTK("CPB flags done, flags=0x%x\n", flags); - if (likely(qc)) { - DPRINTK("Completing qc from tag %d\n", cpb_num); - ata_qc_complete(qc); - } else { - struct ata_eh_info *ehi = &ap->link.eh_info; - /* Notifier bits set without a command may indicate the drive - is misbehaving. Raise host state machine violation on this - condition. */ - ata_port_printk(ap, KERN_ERR, - "notifier for tag %d with no cmd?\n", - cpb_num); - ehi->err_mask |= AC_ERR_HSM; - ehi->action |= ATA_EH_RESET; - ata_port_freeze(ap); - return 1; - } - } + if (likely(flags & NV_CPB_RESP_DONE)) + return 1; return 0; } @@ -1018,6 +1000,7 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance) NV_ADMA_STAT_CPBERR | NV_ADMA_STAT_CMD_COMPLETE)) { u32 check_commands = notifier_clears[i]; + u32 done_mask = 0; int pos, rc; if (status & NV_ADMA_STAT_CPBERR) { @@ -1034,10 +1017,13 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance) pos--; rc = nv_adma_check_cpb(ap, pos, notifier_error & (1 << pos)); - if (unlikely(rc)) + if (rc > 0) + done_mask |= 1 << pos; + else if (unlikely(rc < 0)) check_commands = 0; check_commands &= ~(1 << pos); } + ata_qc_complete_multiple(ap, ap->qc_active ^ done_mask); } } @@ -2132,7 +2118,6 @@ static int nv_swncq_sdbfis(struct ata_port *ap) struct ata_eh_info *ehi = &ap->link.eh_info; u32 sactive; u32 done_mask; - int i; u8 host_stat; u8 lack_dhfis = 0; @@ -2152,27 +2137,11 @@ static int nv_swncq_sdbfis(struct ata_port *ap) sactive = readl(pp->sactive_block); done_mask = pp->qc_active ^ sactive; - if (unlikely(done_mask & sactive)) { - ata_ehi_clear_desc(ehi); - ata_ehi_push_desc(ehi, "illegal SWNCQ:qc_active transition" - "(%08x->%08x)", pp->qc_active, sactive); - ehi->err_mask |= AC_ERR_HSM; - ehi->action |= ATA_EH_RESET; - return -EINVAL; - } - for (i = 0; i < ATA_MAX_QUEUE; i++) { - if (!(done_mask & (1 << i))) - continue; - - qc = ata_qc_from_tag(ap, i); - if (qc) { - ata_qc_complete(qc); - pp->qc_active &= ~(1 << i); - pp->dhfis_bits &= ~(1 << i); - pp->dmafis_bits &= ~(1 << i); - pp->sdbfis_bits |= (1 << i); - } - } + pp->qc_active &= ~done_mask; + pp->dhfis_bits &= ~done_mask; + pp->dmafis_bits &= ~done_mask; + pp->sdbfis_bits |= done_mask; + ata_qc_complete_multiple(ap, ap->qc_active ^ done_mask); if (!ap->qc_active) { DPRINTK("over\n"); diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index be7726d7686d..af41c6fd1254 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -589,9 +589,9 @@ static int sil24_init_port(struct ata_port *ap) sil24_clear_pmp(ap); writel(PORT_CS_INIT, port + PORT_CTRL_STAT); - ata_wait_register(port + PORT_CTRL_STAT, + ata_wait_register(ap, port + PORT_CTRL_STAT, PORT_CS_INIT, PORT_CS_INIT, 10, 100); - tmp = ata_wait_register(port + PORT_CTRL_STAT, + tmp = ata_wait_register(ap, port + PORT_CTRL_STAT, PORT_CS_RDY, 0, 10, 100); if ((tmp & (PORT_CS_INIT | PORT_CS_RDY)) != PORT_CS_RDY) { @@ -631,7 +631,7 @@ static int sil24_exec_polled_cmd(struct ata_port *ap, int pmp, writel((u64)paddr >> 32, port + PORT_CMD_ACTIVATE + 4); irq_mask = (PORT_IRQ_COMPLETE | PORT_IRQ_ERROR) << PORT_IRQ_RAW_SHIFT; - irq_stat = ata_wait_register(port + PORT_IRQ_STAT, irq_mask, 0x0, + irq_stat = ata_wait_register(ap, port + PORT_IRQ_STAT, irq_mask, 0x0, 10, timeout_msec); writel(irq_mask, port + PORT_IRQ_STAT); /* clear IRQs */ @@ -719,9 +719,9 @@ static int sil24_hardreset(struct ata_link *link, unsigned int *class, "state, performing PORT_RST\n"); writel(PORT_CS_PORT_RST, port + PORT_CTRL_STAT); - msleep(10); + ata_msleep(ap, 10); writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR); - ata_wait_register(port + PORT_CTRL_STAT, PORT_CS_RDY, 0, + ata_wait_register(ap, port + PORT_CTRL_STAT, PORT_CS_RDY, 0, 10, 5000); /* restore port configuration */ @@ -740,7 +740,7 @@ static int sil24_hardreset(struct ata_link *link, unsigned int *class, tout_msec = 5000; writel(PORT_CS_DEV_RST, port + PORT_CTRL_STAT); - tmp = ata_wait_register(port + PORT_CTRL_STAT, + tmp = ata_wait_register(ap, port + PORT_CTRL_STAT, PORT_CS_DEV_RST, PORT_CS_DEV_RST, 10, tout_msec); @@ -1253,7 +1253,7 @@ static void sil24_init_controller(struct ata_host *host) tmp = readl(port + PORT_CTRL_STAT); if (tmp & PORT_CS_PORT_RST) { writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR); - tmp = ata_wait_register(port + PORT_CTRL_STAT, + tmp = ata_wait_register(NULL, port + PORT_CTRL_STAT, PORT_CS_PORT_RST, PORT_CS_PORT_RST, 10, 100); if (tmp & PORT_CS_PORT_RST) diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c index 4730c42a5ee5..c21589986c69 100644 --- a/drivers/ata/sata_via.c +++ b/drivers/ata/sata_via.c @@ -349,7 +349,7 @@ static int vt6420_prereset(struct ata_link *link, unsigned long deadline) /* wait for phy to become ready, if necessary */ do { - msleep(200); + ata_msleep(link->ap, 200); svia_scr_read(link, SCR_STATUS, &sstatus); if ((sstatus & 0xf) != 1) break; diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile index cbccf9a3cee4..abe46edfe5b4 100644 --- a/drivers/base/power/Makefile +++ b/drivers/base/power/Makefile @@ -3,6 +3,7 @@ obj-$(CONFIG_PM_SLEEP) += main.o wakeup.o obj-$(CONFIG_PM_RUNTIME) += runtime.o obj-$(CONFIG_PM_OPS) += generic_ops.o obj-$(CONFIG_PM_TRACE_RTC) += trace.o +obj-$(CONFIG_PM_OPP) += opp.o ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG ccflags-$(CONFIG_PM_VERBOSE) += -DDEBUG diff --git a/drivers/base/power/generic_ops.c b/drivers/base/power/generic_ops.c index 4b29d4981253..81f2c84697f4 100644 --- a/drivers/base/power/generic_ops.c +++ b/drivers/base/power/generic_ops.c @@ -46,7 +46,7 @@ int pm_generic_runtime_suspend(struct device *dev) const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; int ret; - ret = pm && pm->runtime_suspend ? pm->runtime_suspend(dev) : -EINVAL; + ret = pm && pm->runtime_suspend ? pm->runtime_suspend(dev) : 0; return ret; } @@ -65,7 +65,7 @@ int pm_generic_runtime_resume(struct device *dev) const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; int ret; - ret = pm && pm->runtime_resume ? pm->runtime_resume(dev) : -EINVAL; + ret = pm && pm->runtime_resume ? pm->runtime_resume(dev) : 0; return ret; } diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 276d5a701dc3..31b526661ec4 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -51,6 +51,8 @@ static pm_message_t pm_transition; */ static bool transition_started; +static int async_error; + /** * device_pm_init - Initialize the PM-related part of a device object. * @dev: Device object being initialized. @@ -60,7 +62,8 @@ void device_pm_init(struct device *dev) dev->power.status = DPM_ON; init_completion(&dev->power.completion); complete_all(&dev->power.completion); - dev->power.wakeup_count = 0; + dev->power.wakeup = NULL; + spin_lock_init(&dev->power.lock); pm_runtime_init(dev); } @@ -120,6 +123,7 @@ void device_pm_remove(struct device *dev) mutex_lock(&dpm_list_mtx); list_del_init(&dev->power.entry); mutex_unlock(&dpm_list_mtx); + device_wakeup_disable(dev); pm_runtime_remove(dev); } @@ -407,7 +411,7 @@ static void pm_dev_err(struct device *dev, pm_message_t state, char *info, static void dpm_show_time(ktime_t starttime, pm_message_t state, char *info) { ktime_t calltime; - s64 usecs64; + u64 usecs64; int usecs; calltime = ktime_get(); @@ -600,6 +604,7 @@ static void dpm_resume(pm_message_t state) INIT_LIST_HEAD(&list); mutex_lock(&dpm_list_mtx); pm_transition = state; + async_error = 0; list_for_each_entry(dev, &dpm_list, power.entry) { if (dev->power.status < DPM_OFF) @@ -829,8 +834,6 @@ static int legacy_suspend(struct device *dev, pm_message_t state, return error; } -static int async_error; - /** * device_suspend - Execute "suspend" callbacks for given device. * @dev: Device to handle. @@ -885,6 +888,9 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) device_unlock(dev); complete_all(&dev->power.completion); + if (error) + async_error = error; + return error; } @@ -894,10 +900,8 @@ static void async_suspend(void *data, async_cookie_t cookie) int error; error = __device_suspend(dev, pm_transition, true); - if (error) { + if (error) pm_dev_err(dev, pm_transition, " async", error); - async_error = error; - } put_device(dev); } @@ -1085,8 +1089,9 @@ EXPORT_SYMBOL_GPL(__suspend_report_result); * @dev: Device to wait for. * @subordinate: Device that needs to wait for @dev. */ -void device_pm_wait_for_dev(struct device *subordinate, struct device *dev) +int device_pm_wait_for_dev(struct device *subordinate, struct device *dev) { dpm_wait(dev, subordinate->power.async_suspend); + return async_error; } EXPORT_SYMBOL_GPL(device_pm_wait_for_dev); diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c new file mode 100644 index 000000000000..2bb9b4cf59d7 --- /dev/null +++ b/drivers/base/power/opp.c @@ -0,0 +1,628 @@ +/* + * Generic OPP Interface + * + * Copyright (C) 2009-2010 Texas Instruments Incorporated. + * Nishanth Menon + * Romit Dasgupta + * Kevin Hilman + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/cpufreq.h> +#include <linux/list.h> +#include <linux/rculist.h> +#include <linux/rcupdate.h> +#include <linux/opp.h> + +/* + * Internal data structure organization with the OPP layer library is as + * follows: + * dev_opp_list (root) + * |- device 1 (represents voltage domain 1) + * | |- opp 1 (availability, freq, voltage) + * | |- opp 2 .. + * ... ... + * | `- opp n .. + * |- device 2 (represents the next voltage domain) + * ... + * `- device m (represents mth voltage domain) + * device 1, 2.. are represented by dev_opp structure while each opp + * is represented by the opp structure. + */ + +/** + * struct opp - Generic OPP description structure + * @node: opp list node. The nodes are maintained throughout the lifetime + * of boot. It is expected only an optimal set of OPPs are + * added to the library by the SoC framework. + * RCU usage: opp list is traversed with RCU locks. node + * modification is possible realtime, hence the modifications + * are protected by the dev_opp_list_lock for integrity. + * IMPORTANT: the opp nodes should be maintained in increasing + * order. + * @available: true/false - marks if this OPP as available or not + * @rate: Frequency in hertz + * @u_volt: Nominal voltage in microvolts corresponding to this OPP + * @dev_opp: points back to the device_opp struct this opp belongs to + * + * This structure stores the OPP information for a given device. + */ +struct opp { + struct list_head node; + + bool available; + unsigned long rate; + unsigned long u_volt; + + struct device_opp *dev_opp; +}; + +/** + * struct device_opp - Device opp structure + * @node: list node - contains the devices with OPPs that + * have been registered. Nodes once added are not modified in this + * list. + * RCU usage: nodes are not modified in the list of device_opp, + * however addition is possible and is secured by dev_opp_list_lock + * @dev: device pointer + * @opp_list: list of opps + * + * This is an internal data structure maintaining the link to opps attached to + * a device. This structure is not meant to be shared to users as it is + * meant for book keeping and private to OPP library + */ +struct device_opp { + struct list_head node; + + struct device *dev; + struct list_head opp_list; +}; + +/* + * The root of the list of all devices. All device_opp structures branch off + * from here, with each device_opp containing the list of opp it supports in + * various states of availability. + */ +static LIST_HEAD(dev_opp_list); +/* Lock to allow exclusive modification to the device and opp lists */ +static DEFINE_MUTEX(dev_opp_list_lock); + +/** + * find_device_opp() - find device_opp struct using device pointer + * @dev: device pointer used to lookup device OPPs + * + * Search list of device OPPs for one containing matching device. Does a RCU + * reader operation to grab the pointer needed. + * + * Returns pointer to 'struct device_opp' if found, otherwise -ENODEV or + * -EINVAL based on type of error. + * + * Locking: This function must be called under rcu_read_lock(). device_opp + * is a RCU protected pointer. This means that device_opp is valid as long + * as we are under RCU lock. + */ +static struct device_opp *find_device_opp(struct device *dev) +{ + struct device_opp *tmp_dev_opp, *dev_opp = ERR_PTR(-ENODEV); + + if (unlikely(IS_ERR_OR_NULL(dev))) { + pr_err("%s: Invalid parameters\n", __func__); + return ERR_PTR(-EINVAL); + } + + list_for_each_entry_rcu(tmp_dev_opp, &dev_opp_list, node) { + if (tmp_dev_opp->dev == dev) { + dev_opp = tmp_dev_opp; + break; + } + } + + return dev_opp; +} + +/** + * opp_get_voltage() - Gets the voltage corresponding to an available opp + * @opp: opp for which voltage has to be returned for + * + * Return voltage in micro volt corresponding to the opp, else + * return 0 + * + * Locking: This function must be called under rcu_read_lock(). opp is a rcu + * protected pointer. This means that opp which could have been fetched by + * opp_find_freq_{exact,ceil,floor} functions is valid as long as we are + * under RCU lock. The pointer returned by the opp_find_freq family must be + * used in the same section as the usage of this function with the pointer + * prior to unlocking with rcu_read_unlock() to maintain the integrity of the + * pointer. + */ +unsigned long opp_get_voltage(struct opp *opp) +{ + struct opp *tmp_opp; + unsigned long v = 0; + + tmp_opp = rcu_dereference(opp); + if (unlikely(IS_ERR_OR_NULL(tmp_opp)) || !tmp_opp->available) + pr_err("%s: Invalid parameters\n", __func__); + else + v = tmp_opp->u_volt; + + return v; +} + +/** + * opp_get_freq() - Gets the frequency corresponding to an available opp + * @opp: opp for which frequency has to be returned for + * + * Return frequency in hertz corresponding to the opp, else + * return 0 + * + * Locking: This function must be called under rcu_read_lock(). opp is a rcu + * protected pointer. This means that opp which could have been fetched by + * opp_find_freq_{exact,ceil,floor} functions is valid as long as we are + * under RCU lock. The pointer returned by the opp_find_freq family must be + * used in the same section as the usage of this function with the pointer + * prior to unlocking with rcu_read_unlock() to maintain the integrity of the + * pointer. + */ +unsigned long opp_get_freq(struct opp *opp) +{ + struct opp *tmp_opp; + unsigned long f = 0; + + tmp_opp = rcu_dereference(opp); + if (unlikely(IS_ERR_OR_NULL(tmp_opp)) || !tmp_opp->available) + pr_err("%s: Invalid parameters\n", __func__); + else + f = tmp_opp->rate; + + return f; +} + +/** + * opp_get_opp_count() - Get number of opps available in the opp list + * @dev: device for which we do this operation + * + * This function returns the number of available opps if there are any, + * else returns 0 if none or the corresponding error value. + * + * Locking: This function must be called under rcu_read_lock(). This function + * internally references two RCU protected structures: device_opp and opp which + * are safe as long as we are under a common RCU locked section. + */ +int opp_get_opp_count(struct device *dev) +{ + struct device_opp *dev_opp; + struct opp *temp_opp; + int count = 0; + + dev_opp = find_device_opp(dev); + if (IS_ERR(dev_opp)) { + int r = PTR_ERR(dev_opp); + dev_err(dev, "%s: device OPP not found (%d)\n", __func__, r); + return r; + } + + list_for_each_entry_rcu(temp_opp, &dev_opp->opp_list, node) { + if (temp_opp->available) + count++; + } + + return count; +} + +/** + * opp_find_freq_exact() - search for an exact frequency + * @dev: device for which we do this operation + * @freq: frequency to search for + * @is_available: true/false - match for available opp + * + * Searches for exact match in the opp list and returns pointer to the matching + * opp if found, else returns ERR_PTR in case of error and should be handled + * using IS_ERR. + * + * Note: available is a modifier for the search. if available=true, then the + * match is for exact matching frequency and is available in the stored OPP + * table. if false, the match is for exact frequency which is not available. + * + * This provides a mechanism to enable an opp which is not available currently + * or the opposite as well. + * + * Locking: This function must be called under rcu_read_lock(). opp is a rcu + * protected pointer. The reason for the same is that the opp pointer which is + * returned will remain valid for use with opp_get_{voltage, freq} only while + * under the locked area. The pointer returned must be used prior to unlocking + * with rcu_read_unlock() to maintain the integrity of the pointer. + */ +struct opp *opp_find_freq_exact(struct device *dev, unsigned long freq, + bool available) +{ + struct device_opp *dev_opp; + struct opp *temp_opp, *opp = ERR_PTR(-ENODEV); + + dev_opp = find_device_opp(dev); + if (IS_ERR(dev_opp)) { + int r = PTR_ERR(dev_opp); + dev_err(dev, "%s: device OPP not found (%d)\n", __func__, r); + return ERR_PTR(r); + } + + list_for_each_entry_rcu(temp_opp, &dev_opp->opp_list, node) { + if (temp_opp->available == available && + temp_opp->rate == freq) { + opp = temp_opp; + break; + } + } + + return opp; +} + +/** + * opp_find_freq_ceil() - Search for an rounded ceil freq + * @dev: device for which we do this operation + * @freq: Start frequency + * + * Search for the matching ceil *available* OPP from a starting freq + * for a device. + * + * Returns matching *opp and refreshes *freq accordingly, else returns + * ERR_PTR in case of error and should be handled using IS_ERR. + * + * Locking: This function must be called under rcu_read_lock(). opp is a rcu + * protected pointer. The reason for the same is that the opp pointer which is + * returned will remain valid for use with opp_get_{voltage, freq} only while + * under the locked area. The pointer returned must be used prior to unlocking + * with rcu_read_unlock() to maintain the integrity of the pointer. + */ +struct opp *opp_find_freq_ceil(struct device *dev, unsigned long *freq) +{ + struct device_opp *dev_opp; + struct opp *temp_opp, *opp = ERR_PTR(-ENODEV); + + if (!dev || !freq) { + dev_err(dev, "%s: Invalid argument freq=%p\n", __func__, freq); + return ERR_PTR(-EINVAL); + } + + dev_opp = find_device_opp(dev); + if (IS_ERR(dev_opp)) + return opp; + + list_for_each_entry_rcu(temp_opp, &dev_opp->opp_list, node) { + if (temp_opp->available && temp_opp->rate >= *freq) { + opp = temp_opp; + *freq = opp->rate; + break; + } + } + + return opp; +} + +/** + * opp_find_freq_floor() - Search for a rounded floor freq + * @dev: device for which we do this operation + * @freq: Start frequency + * + * Search for the matching floor *available* OPP from a starting freq + * for a device. + * + * Returns matching *opp and refreshes *freq accordingly, else returns + * ERR_PTR in case of error and should be handled using IS_ERR. + * + * Locking: This function must be called under rcu_read_lock(). opp is a rcu + * protected pointer. The reason for the same is that the opp pointer which is + * returned will remain valid for use with opp_get_{voltage, freq} only while + * under the locked area. The pointer returned must be used prior to unlocking + * with rcu_read_unlock() to maintain the integrity of the pointer. + */ +struct opp *opp_find_freq_floor(struct device *dev, unsigned long *freq) +{ + struct device_opp *dev_opp; + struct opp *temp_opp, *opp = ERR_PTR(-ENODEV); + + if (!dev || !freq) { + dev_err(dev, "%s: Invalid argument freq=%p\n", __func__, freq); + return ERR_PTR(-EINVAL); + } + + dev_opp = find_device_opp(dev); + if (IS_ERR(dev_opp)) + return opp; + + list_for_each_entry_rcu(temp_opp, &dev_opp->opp_list, node) { + if (temp_opp->available) { + /* go to the next node, before choosing prev */ + if (temp_opp->rate > *freq) + break; + else + opp = temp_opp; + } + } + if (!IS_ERR(opp)) + *freq = opp->rate; + + return opp; +} + +/** + * opp_add() - Add an OPP table from a table definitions + * @dev: device for which we do this operation + * @freq: Frequency in Hz for this OPP + * @u_volt: Voltage in uVolts for this OPP + * + * This function adds an opp definition to the opp list and returns status. + * The opp is made available by default and it can be controlled using + * opp_enable/disable functions. + * + * Locking: The internal device_opp and opp structures are RCU protected. + * Hence this function internally uses RCU updater strategy with mutex locks + * to keep the integrity of the internal data structures. Callers should ensure + * that this function is *NOT* called under RCU protection or in contexts where + * mutex cannot be locked. + */ +int opp_add(struct device *dev, unsigned long freq, unsigned long u_volt) +{ + struct device_opp *dev_opp = NULL; + struct opp *opp, *new_opp; + struct list_head *head; + + /* allocate new OPP node */ + new_opp = kzalloc(sizeof(struct opp), GFP_KERNEL); + if (!new_opp) { + dev_warn(dev, "%s: Unable to create new OPP node\n", __func__); + return -ENOMEM; + } + + /* Hold our list modification lock here */ + mutex_lock(&dev_opp_list_lock); + + /* Check for existing list for 'dev' */ + dev_opp = find_device_opp(dev); + if (IS_ERR(dev_opp)) { + /* + * Allocate a new device OPP table. In the infrequent case + * where a new device is needed to be added, we pay this + * penalty. + */ + dev_opp = kzalloc(sizeof(struct device_opp), GFP_KERNEL); + if (!dev_opp) { + mutex_unlock(&dev_opp_list_lock); + kfree(new_opp); + dev_warn(dev, + "%s: Unable to create device OPP structure\n", + __func__); + return -ENOMEM; + } + + dev_opp->dev = dev; + INIT_LIST_HEAD(&dev_opp->opp_list); + + /* Secure the device list modification */ + list_add_rcu(&dev_opp->node, &dev_opp_list); + } + + /* populate the opp table */ + new_opp->dev_opp = dev_opp; + new_opp->rate = freq; + new_opp->u_volt = u_volt; + new_opp->available = true; + + /* Insert new OPP in order of increasing frequency */ + head = &dev_opp->opp_list; + list_for_each_entry_rcu(opp, &dev_opp->opp_list, node) { + if (new_opp->rate < opp->rate) + break; + else + head = &opp->node; + } + + list_add_rcu(&new_opp->node, head); + mutex_unlock(&dev_opp_list_lock); + + return 0; +} + +/** + * opp_set_availability() - helper to set the availability of an opp + * @dev: device for which we do this operation + * @freq: OPP frequency to modify availability + * @availability_req: availability status requested for this opp + * + * Set the availability of an OPP with an RCU operation, opp_{enable,disable} + * share a common logic which is isolated here. + * + * Returns -EINVAL for bad pointers, -ENOMEM if no memory available for the + * copy operation, returns 0 if no modifcation was done OR modification was + * successful. + * + * Locking: The internal device_opp and opp structures are RCU protected. + * Hence this function internally uses RCU updater strategy with mutex locks to + * keep the integrity of the internal data structures. Callers should ensure + * that this function is *NOT* called under RCU protection or in contexts where + * mutex locking or synchronize_rcu() blocking calls cannot be used. + */ +static int opp_set_availability(struct device *dev, unsigned long freq, + bool availability_req) +{ + struct device_opp *tmp_dev_opp, *dev_opp = NULL; + struct opp *new_opp, *tmp_opp, *opp = ERR_PTR(-ENODEV); + int r = 0; + + /* keep the node allocated */ + new_opp = kmalloc(sizeof(struct opp), GFP_KERNEL); + if (!new_opp) { + dev_warn(dev, "%s: Unable to create OPP\n", __func__); + return -ENOMEM; + } + + mutex_lock(&dev_opp_list_lock); + + /* Find the device_opp */ + list_for_each_entry(tmp_dev_opp, &dev_opp_list, node) { + if (dev == tmp_dev_opp->dev) { + dev_opp = tmp_dev_opp; + break; + } + } + if (IS_ERR(dev_opp)) { + r = PTR_ERR(dev_opp); + dev_warn(dev, "%s: Device OPP not found (%d)\n", __func__, r); + goto unlock; + } + + /* Do we have the frequency? */ + list_for_each_entry(tmp_opp, &dev_opp->opp_list, node) { + if (tmp_opp->rate == freq) { + opp = tmp_opp; + break; + } + } + if (IS_ERR(opp)) { + r = PTR_ERR(opp); + goto unlock; + } + + /* Is update really needed? */ + if (opp->available == availability_req) + goto unlock; + /* copy the old data over */ + *new_opp = *opp; + + /* plug in new node */ + new_opp->available = availability_req; + + list_replace_rcu(&opp->node, &new_opp->node); + mutex_unlock(&dev_opp_list_lock); + synchronize_rcu(); + + /* clean up old opp */ + new_opp = opp; + goto out; + +unlock: + mutex_unlock(&dev_opp_list_lock); +out: + kfree(new_opp); + return r; +} + +/** + * opp_enable() - Enable a specific OPP + * @dev: device for which we do this operation + * @freq: OPP frequency to enable + * + * Enables a provided opp. If the operation is valid, this returns 0, else the + * corresponding error value. It is meant to be used for users an OPP available + * after being temporarily made unavailable with opp_disable. + * + * Locking: The internal device_opp and opp structures are RCU protected. + * Hence this function indirectly uses RCU and mutex locks to keep the + * integrity of the internal data structures. Callers should ensure that + * this function is *NOT* called under RCU protection or in contexts where + * mutex locking or synchronize_rcu() blocking calls cannot be used. + */ +int opp_enable(struct device *dev, unsigned long freq) +{ + return opp_set_availability(dev, freq, true); +} + +/** + * opp_disable() - Disable a specific OPP + * @dev: device for which we do this operation + * @freq: OPP frequency to disable + * + * Disables a provided opp. If the operation is valid, this returns + * 0, else the corresponding error value. It is meant to be a temporary + * control by users to make this OPP not available until the circumstances are + * right to make it available again (with a call to opp_enable). + * + * Locking: The internal device_opp and opp structures are RCU protected. + * Hence this function indirectly uses RCU and mutex locks to keep the + * integrity of the internal data structures. Callers should ensure that + * this function is *NOT* called under RCU protection or in contexts where + * mutex locking or synchronize_rcu() blocking calls cannot be used. + */ +int opp_disable(struct device *dev, unsigned long freq) +{ + return opp_set_availability(dev, freq, false); +} + +#ifdef CONFIG_CPU_FREQ +/** + * opp_init_cpufreq_table() - create a cpufreq table for a device + * @dev: device for which we do this operation + * @table: Cpufreq table returned back to caller + * + * Generate a cpufreq table for a provided device- this assumes that the + * opp list is already initialized and ready for usage. + * + * This function allocates required memory for the cpufreq table. It is + * expected that the caller does the required maintenance such as freeing + * the table as required. + * + * Returns -EINVAL for bad pointers, -ENODEV if the device is not found, -ENOMEM + * if no memory available for the operation (table is not populated), returns 0 + * if successful and table is populated. + * + * WARNING: It is important for the callers to ensure refreshing their copy of + * the table if any of the mentioned functions have been invoked in the interim. + * + * Locking: The internal device_opp and opp structures are RCU protected. + * To simplify the logic, we pretend we are updater and hold relevant mutex here + * Callers should ensure that this function is *NOT* called under RCU protection + * or in contexts where mutex locking cannot be used. + */ +int opp_init_cpufreq_table(struct device *dev, + struct cpufreq_frequency_table **table) +{ + struct device_opp *dev_opp; + struct opp *opp; + struct cpufreq_frequency_table *freq_table; + int i = 0; + + /* Pretend as if I am an updater */ + mutex_lock(&dev_opp_list_lock); + + dev_opp = find_device_opp(dev); + if (IS_ERR(dev_opp)) { + int r = PTR_ERR(dev_opp); + mutex_unlock(&dev_opp_list_lock); + dev_err(dev, "%s: Device OPP not found (%d)\n", __func__, r); + return r; + } + + freq_table = kzalloc(sizeof(struct cpufreq_frequency_table) * + (opp_get_opp_count(dev) + 1), GFP_KERNEL); + if (!freq_table) { + mutex_unlock(&dev_opp_list_lock); + dev_warn(dev, "%s: Unable to allocate frequency table\n", + __func__); + return -ENOMEM; + } + + list_for_each_entry(opp, &dev_opp->opp_list, node) { + if (opp->available) { + freq_table[i].index = i; + freq_table[i].frequency = opp->rate / 1000; + i++; + } + } + mutex_unlock(&dev_opp_list_lock); + + freq_table[i].index = i; + freq_table[i].frequency = CPUFREQ_TABLE_END; + + *table = &freq_table[0]; + + return 0; +} +#endif /* CONFIG_CPU_FREQ */ diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h index c0bd03c83b9c..698dde742587 100644 --- a/drivers/base/power/power.h +++ b/drivers/base/power/power.h @@ -34,6 +34,7 @@ extern void device_pm_move_last(struct device *); static inline void device_pm_init(struct device *dev) { + spin_lock_init(&dev->power.lock); pm_runtime_init(dev); } @@ -59,6 +60,7 @@ static inline void device_pm_move_last(struct device *dev) {} extern int dpm_sysfs_add(struct device *); extern void dpm_sysfs_remove(struct device *); +extern void rpm_sysfs_remove(struct device *); #else /* CONFIG_PM */ diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index b78c401ffa73..1dd8676d7f55 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -2,17 +2,55 @@ * drivers/base/power/runtime.c - Helper functions for device run-time PM * * Copyright (c) 2009 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc. + * Copyright (C) 2010 Alan Stern <stern@rowland.harvard.edu> * * This file is released under the GPLv2. */ #include <linux/sched.h> #include <linux/pm_runtime.h> -#include <linux/jiffies.h> +#include "power.h" -static int __pm_runtime_resume(struct device *dev, bool from_wq); -static int __pm_request_idle(struct device *dev); -static int __pm_request_resume(struct device *dev); +static int rpm_resume(struct device *dev, int rpmflags); +static int rpm_suspend(struct device *dev, int rpmflags); + +/** + * update_pm_runtime_accounting - Update the time accounting of power states + * @dev: Device to update the accounting for + * + * In order to be able to have time accounting of the various power states + * (as used by programs such as PowerTOP to show the effectiveness of runtime + * PM), we need to track the time spent in each state. + * update_pm_runtime_accounting must be called each time before the + * runtime_status field is updated, to account the time in the old state + * correctly. + */ +void update_pm_runtime_accounting(struct device *dev) +{ + unsigned long now = jiffies; + int delta; + + delta = now - dev->power.accounting_timestamp; + + if (delta < 0) + delta = 0; + + dev->power.accounting_timestamp = now; + + if (dev->power.disable_depth > 0) + return; + + if (dev->power.runtime_status == RPM_SUSPENDED) + dev->power.suspended_jiffies += delta; + else + dev->power.active_jiffies += delta; +} + +static void __update_runtime_status(struct device *dev, enum rpm_status status) +{ + update_pm_runtime_accounting(dev); + dev->power.runtime_status = status; +} /** * pm_runtime_deactivate_timer - Deactivate given device's suspend timer. @@ -40,62 +78,154 @@ static void pm_runtime_cancel_pending(struct device *dev) dev->power.request = RPM_REQ_NONE; } -/** - * __pm_runtime_idle - Notify device bus type if the device can be suspended. - * @dev: Device to notify the bus type about. +/* + * pm_runtime_autosuspend_expiration - Get a device's autosuspend-delay expiration time. + * @dev: Device to handle. * - * This function must be called under dev->power.lock with interrupts disabled. + * Compute the autosuspend-delay expiration time based on the device's + * power.last_busy time. If the delay has already expired or is disabled + * (negative) or the power.use_autosuspend flag isn't set, return 0. + * Otherwise return the expiration time in jiffies (adjusted to be nonzero). + * + * This function may be called either with or without dev->power.lock held. + * Either way it can be racy, since power.last_busy may be updated at any time. */ -static int __pm_runtime_idle(struct device *dev) - __releases(&dev->power.lock) __acquires(&dev->power.lock) +unsigned long pm_runtime_autosuspend_expiration(struct device *dev) +{ + int autosuspend_delay; + long elapsed; + unsigned long last_busy; + unsigned long expires = 0; + + if (!dev->power.use_autosuspend) + goto out; + + autosuspend_delay = ACCESS_ONCE(dev->power.autosuspend_delay); + if (autosuspend_delay < 0) + goto out; + + last_busy = ACCESS_ONCE(dev->power.last_busy); + elapsed = jiffies - last_busy; + if (elapsed < 0) + goto out; /* jiffies has wrapped around. */ + + /* + * If the autosuspend_delay is >= 1 second, align the timer by rounding + * up to the nearest second. + */ + expires = last_busy + msecs_to_jiffies(autosuspend_delay); + if (autosuspend_delay >= 1000) + expires = round_jiffies(expires); + expires += !expires; + if (elapsed >= expires - last_busy) + expires = 0; /* Already expired. */ + + out: + return expires; +} +EXPORT_SYMBOL_GPL(pm_runtime_autosuspend_expiration); + +/** + * rpm_check_suspend_allowed - Test whether a device may be suspended. + * @dev: Device to test. + */ +static int rpm_check_suspend_allowed(struct device *dev) { int retval = 0; if (dev->power.runtime_error) retval = -EINVAL; - else if (dev->power.idle_notification) - retval = -EINPROGRESS; else if (atomic_read(&dev->power.usage_count) > 0 - || dev->power.disable_depth > 0 - || dev->power.runtime_status != RPM_ACTIVE) + || dev->power.disable_depth > 0) retval = -EAGAIN; else if (!pm_children_suspended(dev)) retval = -EBUSY; + + /* Pending resume requests take precedence over suspends. */ + else if ((dev->power.deferred_resume + && dev->power.status == RPM_SUSPENDING) + || (dev->power.request_pending + && dev->power.request == RPM_REQ_RESUME)) + retval = -EAGAIN; + else if (dev->power.runtime_status == RPM_SUSPENDED) + retval = 1; + + return retval; +} + +/** + * rpm_idle - Notify device bus type if the device can be suspended. + * @dev: Device to notify the bus type about. + * @rpmflags: Flag bits. + * + * Check if the device's run-time PM status allows it to be suspended. If + * another idle notification has been started earlier, return immediately. If + * the RPM_ASYNC flag is set then queue an idle-notification request; otherwise + * run the ->runtime_idle() callback directly. + * + * This function must be called under dev->power.lock with interrupts disabled. + */ +static int rpm_idle(struct device *dev, int rpmflags) +{ + int (*callback)(struct device *); + int retval; + + retval = rpm_check_suspend_allowed(dev); + if (retval < 0) + ; /* Conditions are wrong. */ + + /* Idle notifications are allowed only in the RPM_ACTIVE state. */ + else if (dev->power.runtime_status != RPM_ACTIVE) + retval = -EAGAIN; + + /* + * Any pending request other than an idle notification takes + * precedence over us, except that the timer may be running. + */ + else if (dev->power.request_pending && + dev->power.request > RPM_REQ_IDLE) + retval = -EAGAIN; + + /* Act as though RPM_NOWAIT is always set. */ + else if (dev->power.idle_notification) + retval = -EINPROGRESS; if (retval) goto out; - if (dev->power.request_pending) { - /* - * If an idle notification request is pending, cancel it. Any - * other pending request takes precedence over us. - */ - if (dev->power.request == RPM_REQ_IDLE) { - dev->power.request = RPM_REQ_NONE; - } else if (dev->power.request != RPM_REQ_NONE) { - retval = -EAGAIN; - goto out; + /* Pending requests need to be canceled. */ + dev->power.request = RPM_REQ_NONE; + + if (dev->power.no_callbacks) { + /* Assume ->runtime_idle() callback would have suspended. */ + retval = rpm_suspend(dev, rpmflags); + goto out; + } + + /* Carry out an asynchronous or a synchronous idle notification. */ + if (rpmflags & RPM_ASYNC) { + dev->power.request = RPM_REQ_IDLE; + if (!dev->power.request_pending) { + dev->power.request_pending = true; + queue_work(pm_wq, &dev->power.work); } + goto out; } dev->power.idle_notification = true; - if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_idle) { - spin_unlock_irq(&dev->power.lock); - - dev->bus->pm->runtime_idle(dev); - - spin_lock_irq(&dev->power.lock); - } else if (dev->type && dev->type->pm && dev->type->pm->runtime_idle) { - spin_unlock_irq(&dev->power.lock); - - dev->type->pm->runtime_idle(dev); + if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_idle) + callback = dev->bus->pm->runtime_idle; + else if (dev->type && dev->type->pm && dev->type->pm->runtime_idle) + callback = dev->type->pm->runtime_idle; + else if (dev->class && dev->class->pm) + callback = dev->class->pm->runtime_idle; + else + callback = NULL; - spin_lock_irq(&dev->power.lock); - } else if (dev->class && dev->class->pm - && dev->class->pm->runtime_idle) { + if (callback) { spin_unlock_irq(&dev->power.lock); - dev->class->pm->runtime_idle(dev); + callback(dev); spin_lock_irq(&dev->power.lock); } @@ -108,113 +238,99 @@ static int __pm_runtime_idle(struct device *dev) } /** - * pm_runtime_idle - Notify device bus type if the device can be suspended. - * @dev: Device to notify the bus type about. + * rpm_callback - Run a given runtime PM callback for a given device. + * @cb: Runtime PM callback to run. + * @dev: Device to run the callback for. */ -int pm_runtime_idle(struct device *dev) +static int rpm_callback(int (*cb)(struct device *), struct device *dev) + __releases(&dev->power.lock) __acquires(&dev->power.lock) { int retval; - spin_lock_irq(&dev->power.lock); - retval = __pm_runtime_idle(dev); - spin_unlock_irq(&dev->power.lock); + if (!cb) + return -ENOSYS; - return retval; -} -EXPORT_SYMBOL_GPL(pm_runtime_idle); - - -/** - * update_pm_runtime_accounting - Update the time accounting of power states - * @dev: Device to update the accounting for - * - * In order to be able to have time accounting of the various power states - * (as used by programs such as PowerTOP to show the effectiveness of runtime - * PM), we need to track the time spent in each state. - * update_pm_runtime_accounting must be called each time before the - * runtime_status field is updated, to account the time in the old state - * correctly. - */ -void update_pm_runtime_accounting(struct device *dev) -{ - unsigned long now = jiffies; - int delta; - - delta = now - dev->power.accounting_timestamp; - - if (delta < 0) - delta = 0; + spin_unlock_irq(&dev->power.lock); - dev->power.accounting_timestamp = now; + retval = cb(dev); - if (dev->power.disable_depth > 0) - return; - - if (dev->power.runtime_status == RPM_SUSPENDED) - dev->power.suspended_jiffies += delta; - else - dev->power.active_jiffies += delta; -} + spin_lock_irq(&dev->power.lock); + dev->power.runtime_error = retval; -static void __update_runtime_status(struct device *dev, enum rpm_status status) -{ - update_pm_runtime_accounting(dev); - dev->power.runtime_status = status; + return retval; } /** - * __pm_runtime_suspend - Carry out run-time suspend of given device. + * rpm_suspend - Carry out run-time suspend of given device. * @dev: Device to suspend. - * @from_wq: If set, the function has been called via pm_wq. + * @rpmflags: Flag bits. * - * Check if the device can be suspended and run the ->runtime_suspend() callback - * provided by its bus type. If another suspend has been started earlier, wait - * for it to finish. If an idle notification or suspend request is pending or - * scheduled, cancel it. + * Check if the device's run-time PM status allows it to be suspended. If + * another suspend has been started earlier, either return immediately or wait + * for it to finish, depending on the RPM_NOWAIT and RPM_ASYNC flags. Cancel a + * pending idle notification. If the RPM_ASYNC flag is set then queue a + * suspend request; otherwise run the ->runtime_suspend() callback directly. + * If a deferred resume was requested while the callback was running then carry + * it out; otherwise send an idle notification for the device (if the suspend + * failed) or for its parent (if the suspend succeeded). * * This function must be called under dev->power.lock with interrupts disabled. */ -int __pm_runtime_suspend(struct device *dev, bool from_wq) +static int rpm_suspend(struct device *dev, int rpmflags) __releases(&dev->power.lock) __acquires(&dev->power.lock) { + int (*callback)(struct device *); struct device *parent = NULL; - bool notify = false; - int retval = 0; + int retval; - dev_dbg(dev, "__pm_runtime_suspend()%s!\n", - from_wq ? " from workqueue" : ""); + dev_dbg(dev, "%s flags 0x%x\n", __func__, rpmflags); repeat: - if (dev->power.runtime_error) { - retval = -EINVAL; - goto out; - } + retval = rpm_check_suspend_allowed(dev); - /* Pending resume requests take precedence over us. */ - if (dev->power.request_pending - && dev->power.request == RPM_REQ_RESUME) { + if (retval < 0) + ; /* Conditions are wrong. */ + + /* Synchronous suspends are not allowed in the RPM_RESUMING state. */ + else if (dev->power.runtime_status == RPM_RESUMING && + !(rpmflags & RPM_ASYNC)) retval = -EAGAIN; + if (retval) goto out; + + /* If the autosuspend_delay time hasn't expired yet, reschedule. */ + if ((rpmflags & RPM_AUTO) + && dev->power.runtime_status != RPM_SUSPENDING) { + unsigned long expires = pm_runtime_autosuspend_expiration(dev); + + if (expires != 0) { + /* Pending requests need to be canceled. */ + dev->power.request = RPM_REQ_NONE; + + /* + * Optimization: If the timer is already running and is + * set to expire at or before the autosuspend delay, + * avoid the overhead of resetting it. Just let it + * expire; pm_suspend_timer_fn() will take care of the + * rest. + */ + if (!(dev->power.timer_expires && time_before_eq( + dev->power.timer_expires, expires))) { + dev->power.timer_expires = expires; + mod_timer(&dev->power.suspend_timer, expires); + } + dev->power.timer_autosuspends = 1; + goto out; + } } /* Other scheduled or pending requests need to be canceled. */ pm_runtime_cancel_pending(dev); - if (dev->power.runtime_status == RPM_SUSPENDED) - retval = 1; - else if (dev->power.runtime_status == RPM_RESUMING - || dev->power.disable_depth > 0 - || atomic_read(&dev->power.usage_count) > 0) - retval = -EAGAIN; - else if (!pm_children_suspended(dev)) - retval = -EBUSY; - if (retval) - goto out; - if (dev->power.runtime_status == RPM_SUSPENDING) { DEFINE_WAIT(wait); - if (from_wq) { + if (rpmflags & (RPM_ASYNC | RPM_NOWAIT)) { retval = -EINPROGRESS; goto out; } @@ -236,46 +352,42 @@ int __pm_runtime_suspend(struct device *dev, bool from_wq) goto repeat; } - __update_runtime_status(dev, RPM_SUSPENDING); dev->power.deferred_resume = false; + if (dev->power.no_callbacks) + goto no_callback; /* Assume success. */ + + /* Carry out an asynchronous or a synchronous suspend. */ + if (rpmflags & RPM_ASYNC) { + dev->power.request = (rpmflags & RPM_AUTO) ? + RPM_REQ_AUTOSUSPEND : RPM_REQ_SUSPEND; + if (!dev->power.request_pending) { + dev->power.request_pending = true; + queue_work(pm_wq, &dev->power.work); + } + goto out; + } - if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_suspend) { - spin_unlock_irq(&dev->power.lock); - - retval = dev->bus->pm->runtime_suspend(dev); - - spin_lock_irq(&dev->power.lock); - dev->power.runtime_error = retval; - } else if (dev->type && dev->type->pm - && dev->type->pm->runtime_suspend) { - spin_unlock_irq(&dev->power.lock); - - retval = dev->type->pm->runtime_suspend(dev); - - spin_lock_irq(&dev->power.lock); - dev->power.runtime_error = retval; - } else if (dev->class && dev->class->pm - && dev->class->pm->runtime_suspend) { - spin_unlock_irq(&dev->power.lock); - - retval = dev->class->pm->runtime_suspend(dev); + __update_runtime_status(dev, RPM_SUSPENDING); - spin_lock_irq(&dev->power.lock); - dev->power.runtime_error = retval; - } else { - retval = -ENOSYS; - } + if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_suspend) + callback = dev->bus->pm->runtime_suspend; + else if (dev->type && dev->type->pm && dev->type->pm->runtime_suspend) + callback = dev->type->pm->runtime_suspend; + else if (dev->class && dev->class->pm) + callback = dev->class->pm->runtime_suspend; + else + callback = NULL; + retval = rpm_callback(callback, dev); if (retval) { __update_runtime_status(dev, RPM_ACTIVE); - if (retval == -EAGAIN || retval == -EBUSY) { - if (dev->power.timer_expires == 0) - notify = true; + dev->power.deferred_resume = 0; + if (retval == -EAGAIN || retval == -EBUSY) dev->power.runtime_error = 0; - } else { + else pm_runtime_cancel_pending(dev); - } } else { + no_callback: __update_runtime_status(dev, RPM_SUSPENDED); pm_runtime_deactivate_timer(dev); @@ -287,14 +399,11 @@ int __pm_runtime_suspend(struct device *dev, bool from_wq) wake_up_all(&dev->power.wait_queue); if (dev->power.deferred_resume) { - __pm_runtime_resume(dev, false); + rpm_resume(dev, 0); retval = -EAGAIN; goto out; } - if (notify) - __pm_runtime_idle(dev); - if (parent && !parent->power.ignore_children) { spin_unlock_irq(&dev->power.lock); @@ -304,72 +413,69 @@ int __pm_runtime_suspend(struct device *dev, bool from_wq) } out: - dev_dbg(dev, "__pm_runtime_suspend() returns %d!\n", retval); - - return retval; -} - -/** - * pm_runtime_suspend - Carry out run-time suspend of given device. - * @dev: Device to suspend. - */ -int pm_runtime_suspend(struct device *dev) -{ - int retval; - - spin_lock_irq(&dev->power.lock); - retval = __pm_runtime_suspend(dev, false); - spin_unlock_irq(&dev->power.lock); + dev_dbg(dev, "%s returns %d\n", __func__, retval); return retval; } -EXPORT_SYMBOL_GPL(pm_runtime_suspend); /** - * __pm_runtime_resume - Carry out run-time resume of given device. + * rpm_resume - Carry out run-time resume of given device. * @dev: Device to resume. - * @from_wq: If set, the function has been called via pm_wq. + * @rpmflags: Flag bits. * - * Check if the device can be woken up and run the ->runtime_resume() callback - * provided by its bus type. If another resume has been started earlier, wait - * for it to finish. If there's a suspend running in parallel with this - * function, wait for it to finish and resume the device. Cancel any scheduled - * or pending requests. + * Check if the device's run-time PM status allows it to be resumed. Cancel + * any scheduled or pending requests. If another resume has been started + * earlier, either return imediately or wait for it to finish, depending on the + * RPM_NOWAIT and RPM_ASYNC flags. Similarly, if there's a suspend running in + * parallel with this function, either tell the other process to resume after + * suspending (deferred_resume) or wait for it to finish. If the RPM_ASYNC + * flag is set then queue a resume request; otherwise run the + * ->runtime_resume() callback directly. Queue an idle notification for the + * device if the resume succeeded. * * This function must be called under dev->power.lock with interrupts disabled. */ -int __pm_runtime_resume(struct device *dev, bool from_wq) +static int rpm_resume(struct device *dev, int rpmflags) __releases(&dev->power.lock) __acquires(&dev->power.lock) { + int (*callback)(struct device *); struct device *parent = NULL; int retval = 0; - dev_dbg(dev, "__pm_runtime_resume()%s!\n", - from_wq ? " from workqueue" : ""); + dev_dbg(dev, "%s flags 0x%x\n", __func__, rpmflags); repeat: - if (dev->power.runtime_error) { + if (dev->power.runtime_error) retval = -EINVAL; + else if (dev->power.disable_depth > 0) + retval = -EAGAIN; + if (retval) goto out; - } - pm_runtime_cancel_pending(dev); + /* + * Other scheduled or pending requests need to be canceled. Small + * optimization: If an autosuspend timer is running, leave it running + * rather than cancelling it now only to restart it again in the near + * future. + */ + dev->power.request = RPM_REQ_NONE; + if (!dev->power.timer_autosuspends) + pm_runtime_deactivate_timer(dev); - if (dev->power.runtime_status == RPM_ACTIVE) + if (dev->power.runtime_status == RPM_ACTIVE) { retval = 1; - else if (dev->power.disable_depth > 0) - retval = -EAGAIN; - if (retval) goto out; + } if (dev->power.runtime_status == RPM_RESUMING || dev->power.runtime_status == RPM_SUSPENDING) { DEFINE_WAIT(wait); - if (from_wq) { + if (rpmflags & (RPM_ASYNC | RPM_NOWAIT)) { if (dev->power.runtime_status == RPM_SUSPENDING) dev->power.deferred_resume = true; - retval = -EINPROGRESS; + else + retval = -EINPROGRESS; goto out; } @@ -391,6 +497,34 @@ int __pm_runtime_resume(struct device *dev, bool from_wq) goto repeat; } + /* + * See if we can skip waking up the parent. This is safe only if + * power.no_callbacks is set, because otherwise we don't know whether + * the resume will actually succeed. + */ + if (dev->power.no_callbacks && !parent && dev->parent) { + spin_lock(&dev->parent->power.lock); + if (dev->parent->power.disable_depth > 0 + || dev->parent->power.ignore_children + || dev->parent->power.runtime_status == RPM_ACTIVE) { + atomic_inc(&dev->parent->power.child_count); + spin_unlock(&dev->parent->power.lock); + goto no_callback; /* Assume success. */ + } + spin_unlock(&dev->parent->power.lock); + } + + /* Carry out an asynchronous or a synchronous resume. */ + if (rpmflags & RPM_ASYNC) { + dev->power.request = RPM_REQ_RESUME; + if (!dev->power.request_pending) { + dev->power.request_pending = true; + queue_work(pm_wq, &dev->power.work); + } + retval = 0; + goto out; + } + if (!parent && dev->parent) { /* * Increment the parent's resume counter and resume it if @@ -408,7 +542,7 @@ int __pm_runtime_resume(struct device *dev, bool from_wq) */ if (!parent->power.disable_depth && !parent->power.ignore_children) { - __pm_runtime_resume(parent, false); + rpm_resume(parent, 0); if (parent->power.runtime_status != RPM_ACTIVE) retval = -EBUSY; } @@ -420,39 +554,26 @@ int __pm_runtime_resume(struct device *dev, bool from_wq) goto repeat; } - __update_runtime_status(dev, RPM_RESUMING); - - if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_resume) { - spin_unlock_irq(&dev->power.lock); - - retval = dev->bus->pm->runtime_resume(dev); - - spin_lock_irq(&dev->power.lock); - dev->power.runtime_error = retval; - } else if (dev->type && dev->type->pm - && dev->type->pm->runtime_resume) { - spin_unlock_irq(&dev->power.lock); - - retval = dev->type->pm->runtime_resume(dev); + if (dev->power.no_callbacks) + goto no_callback; /* Assume success. */ - spin_lock_irq(&dev->power.lock); - dev->power.runtime_error = retval; - } else if (dev->class && dev->class->pm - && dev->class->pm->runtime_resume) { - spin_unlock_irq(&dev->power.lock); - - retval = dev->class->pm->runtime_resume(dev); + __update_runtime_status(dev, RPM_RESUMING); - spin_lock_irq(&dev->power.lock); - dev->power.runtime_error = retval; - } else { - retval = -ENOSYS; - } + if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_resume) + callback = dev->bus->pm->runtime_resume; + else if (dev->type && dev->type->pm && dev->type->pm->runtime_resume) + callback = dev->type->pm->runtime_resume; + else if (dev->class && dev->class->pm) + callback = dev->class->pm->runtime_resume; + else + callback = NULL; + retval = rpm_callback(callback, dev); if (retval) { __update_runtime_status(dev, RPM_SUSPENDED); pm_runtime_cancel_pending(dev); } else { + no_callback: __update_runtime_status(dev, RPM_ACTIVE); if (parent) atomic_inc(&parent->power.child_count); @@ -460,7 +581,7 @@ int __pm_runtime_resume(struct device *dev, bool from_wq) wake_up_all(&dev->power.wait_queue); if (!retval) - __pm_request_idle(dev); + rpm_idle(dev, RPM_ASYNC); out: if (parent) { @@ -471,28 +592,12 @@ int __pm_runtime_resume(struct device *dev, bool from_wq) spin_lock_irq(&dev->power.lock); } - dev_dbg(dev, "__pm_runtime_resume() returns %d!\n", retval); + dev_dbg(dev, "%s returns %d\n", __func__, retval); return retval; } /** - * pm_runtime_resume - Carry out run-time resume of given device. - * @dev: Device to suspend. - */ -int pm_runtime_resume(struct device *dev) -{ - int retval; - - spin_lock_irq(&dev->power.lock); - retval = __pm_runtime_resume(dev, false); - spin_unlock_irq(&dev->power.lock); - - return retval; -} -EXPORT_SYMBOL_GPL(pm_runtime_resume); - -/** * pm_runtime_work - Universal run-time PM work function. * @work: Work structure used for scheduling the execution of this function. * @@ -517,13 +622,16 @@ static void pm_runtime_work(struct work_struct *work) case RPM_REQ_NONE: break; case RPM_REQ_IDLE: - __pm_runtime_idle(dev); + rpm_idle(dev, RPM_NOWAIT); break; case RPM_REQ_SUSPEND: - __pm_runtime_suspend(dev, true); + rpm_suspend(dev, RPM_NOWAIT); + break; + case RPM_REQ_AUTOSUSPEND: + rpm_suspend(dev, RPM_NOWAIT | RPM_AUTO); break; case RPM_REQ_RESUME: - __pm_runtime_resume(dev, true); + rpm_resume(dev, RPM_NOWAIT); break; } @@ -532,117 +640,10 @@ static void pm_runtime_work(struct work_struct *work) } /** - * __pm_request_idle - Submit an idle notification request for given device. - * @dev: Device to handle. - * - * Check if the device's run-time PM status is correct for suspending the device - * and queue up a request to run __pm_runtime_idle() for it. - * - * This function must be called under dev->power.lock with interrupts disabled. - */ -static int __pm_request_idle(struct device *dev) -{ - int retval = 0; - - if (dev->power.runtime_error) - retval = -EINVAL; - else if (atomic_read(&dev->power.usage_count) > 0 - || dev->power.disable_depth > 0 - || dev->power.runtime_status == RPM_SUSPENDED - || dev->power.runtime_status == RPM_SUSPENDING) - retval = -EAGAIN; - else if (!pm_children_suspended(dev)) - retval = -EBUSY; - if (retval) - return retval; - - if (dev->power.request_pending) { - /* Any requests other then RPM_REQ_IDLE take precedence. */ - if (dev->power.request == RPM_REQ_NONE) - dev->power.request = RPM_REQ_IDLE; - else if (dev->power.request != RPM_REQ_IDLE) - retval = -EAGAIN; - return retval; - } - - dev->power.request = RPM_REQ_IDLE; - dev->power.request_pending = true; - queue_work(pm_wq, &dev->power.work); - - return retval; -} - -/** - * pm_request_idle - Submit an idle notification request for given device. - * @dev: Device to handle. - */ -int pm_request_idle(struct device *dev) -{ - unsigned long flags; - int retval; - - spin_lock_irqsave(&dev->power.lock, flags); - retval = __pm_request_idle(dev); - spin_unlock_irqrestore(&dev->power.lock, flags); - - return retval; -} -EXPORT_SYMBOL_GPL(pm_request_idle); - -/** - * __pm_request_suspend - Submit a suspend request for given device. - * @dev: Device to suspend. - * - * This function must be called under dev->power.lock with interrupts disabled. - */ -static int __pm_request_suspend(struct device *dev) -{ - int retval = 0; - - if (dev->power.runtime_error) - return -EINVAL; - - if (dev->power.runtime_status == RPM_SUSPENDED) - retval = 1; - else if (atomic_read(&dev->power.usage_count) > 0 - || dev->power.disable_depth > 0) - retval = -EAGAIN; - else if (dev->power.runtime_status == RPM_SUSPENDING) - retval = -EINPROGRESS; - else if (!pm_children_suspended(dev)) - retval = -EBUSY; - if (retval < 0) - return retval; - - pm_runtime_deactivate_timer(dev); - - if (dev->power.request_pending) { - /* - * Pending resume requests take precedence over us, but we can - * overtake any other pending request. - */ - if (dev->power.request == RPM_REQ_RESUME) - retval = -EAGAIN; - else if (dev->power.request != RPM_REQ_SUSPEND) - dev->power.request = retval ? - RPM_REQ_NONE : RPM_REQ_SUSPEND; - return retval; - } else if (retval) { - return retval; - } - - dev->power.request = RPM_REQ_SUSPEND; - dev->power.request_pending = true; - queue_work(pm_wq, &dev->power.work); - - return 0; -} - -/** * pm_suspend_timer_fn - Timer function for pm_schedule_suspend(). * @data: Device pointer passed by pm_schedule_suspend(). * - * Check if the time is right and execute __pm_request_suspend() in that case. + * Check if the time is right and queue a suspend request. */ static void pm_suspend_timer_fn(unsigned long data) { @@ -656,7 +657,8 @@ static void pm_suspend_timer_fn(unsigned long data) /* If 'expire' is after 'jiffies' we've been called too early. */ if (expires > 0 && !time_after(expires, jiffies)) { dev->power.timer_expires = 0; - __pm_request_suspend(dev); + rpm_suspend(dev, dev->power.timer_autosuspends ? + (RPM_ASYNC | RPM_AUTO) : RPM_ASYNC); } spin_unlock_irqrestore(&dev->power.lock, flags); @@ -670,47 +672,25 @@ static void pm_suspend_timer_fn(unsigned long data) int pm_schedule_suspend(struct device *dev, unsigned int delay) { unsigned long flags; - int retval = 0; + int retval; spin_lock_irqsave(&dev->power.lock, flags); - if (dev->power.runtime_error) { - retval = -EINVAL; - goto out; - } - if (!delay) { - retval = __pm_request_suspend(dev); + retval = rpm_suspend(dev, RPM_ASYNC); goto out; } - pm_runtime_deactivate_timer(dev); - - if (dev->power.request_pending) { - /* - * Pending resume requests take precedence over us, but any - * other pending requests have to be canceled. - */ - if (dev->power.request == RPM_REQ_RESUME) { - retval = -EAGAIN; - goto out; - } - dev->power.request = RPM_REQ_NONE; - } - - if (dev->power.runtime_status == RPM_SUSPENDED) - retval = 1; - else if (atomic_read(&dev->power.usage_count) > 0 - || dev->power.disable_depth > 0) - retval = -EAGAIN; - else if (!pm_children_suspended(dev)) - retval = -EBUSY; + retval = rpm_check_suspend_allowed(dev); if (retval) goto out; + /* Other scheduled or pending requests need to be canceled. */ + pm_runtime_cancel_pending(dev); + dev->power.timer_expires = jiffies + msecs_to_jiffies(delay); - if (!dev->power.timer_expires) - dev->power.timer_expires = 1; + dev->power.timer_expires += !dev->power.timer_expires; + dev->power.timer_autosuspends = 0; mod_timer(&dev->power.suspend_timer, dev->power.timer_expires); out: @@ -721,103 +701,88 @@ int pm_schedule_suspend(struct device *dev, unsigned int delay) EXPORT_SYMBOL_GPL(pm_schedule_suspend); /** - * pm_request_resume - Submit a resume request for given device. - * @dev: Device to resume. + * __pm_runtime_idle - Entry point for run-time idle operations. + * @dev: Device to send idle notification for. + * @rpmflags: Flag bits. * - * This function must be called under dev->power.lock with interrupts disabled. + * If the RPM_GET_PUT flag is set, decrement the device's usage count and + * return immediately if it is larger than zero. Then carry out an idle + * notification, either synchronous or asynchronous. + * + * This routine may be called in atomic context if the RPM_ASYNC flag is set. */ -static int __pm_request_resume(struct device *dev) +int __pm_runtime_idle(struct device *dev, int rpmflags) { - int retval = 0; - - if (dev->power.runtime_error) - return -EINVAL; - - if (dev->power.runtime_status == RPM_ACTIVE) - retval = 1; - else if (dev->power.runtime_status == RPM_RESUMING) - retval = -EINPROGRESS; - else if (dev->power.disable_depth > 0) - retval = -EAGAIN; - if (retval < 0) - return retval; - - pm_runtime_deactivate_timer(dev); + unsigned long flags; + int retval; - if (dev->power.runtime_status == RPM_SUSPENDING) { - dev->power.deferred_resume = true; - return retval; + if (rpmflags & RPM_GET_PUT) { + if (!atomic_dec_and_test(&dev->power.usage_count)) + return 0; } - if (dev->power.request_pending) { - /* If non-resume request is pending, we can overtake it. */ - dev->power.request = retval ? RPM_REQ_NONE : RPM_REQ_RESUME; - return retval; - } - if (retval) - return retval; - dev->power.request = RPM_REQ_RESUME; - dev->power.request_pending = true; - queue_work(pm_wq, &dev->power.work); + spin_lock_irqsave(&dev->power.lock, flags); + retval = rpm_idle(dev, rpmflags); + spin_unlock_irqrestore(&dev->power.lock, flags); return retval; } +EXPORT_SYMBOL_GPL(__pm_runtime_idle); /** - * pm_request_resume - Submit a resume request for given device. - * @dev: Device to resume. + * __pm_runtime_suspend - Entry point for run-time put/suspend operations. + * @dev: Device to suspend. + * @rpmflags: Flag bits. + * + * If the RPM_GET_PUT flag is set, decrement the device's usage count and + * return immediately if it is larger than zero. Then carry out a suspend, + * either synchronous or asynchronous. + * + * This routine may be called in atomic context if the RPM_ASYNC flag is set. */ -int pm_request_resume(struct device *dev) +int __pm_runtime_suspend(struct device *dev, int rpmflags) { unsigned long flags; int retval; + if (rpmflags & RPM_GET_PUT) { + if (!atomic_dec_and_test(&dev->power.usage_count)) + return 0; + } + spin_lock_irqsave(&dev->power.lock, flags); - retval = __pm_request_resume(dev); + retval = rpm_suspend(dev, rpmflags); spin_unlock_irqrestore(&dev->power.lock, flags); return retval; } -EXPORT_SYMBOL_GPL(pm_request_resume); +EXPORT_SYMBOL_GPL(__pm_runtime_suspend); /** - * __pm_runtime_get - Reference count a device and wake it up, if necessary. - * @dev: Device to handle. - * @sync: If set and the device is suspended, resume it synchronously. + * __pm_runtime_resume - Entry point for run-time resume operations. + * @dev: Device to resume. + * @rpmflags: Flag bits. + * + * If the RPM_GET_PUT flag is set, increment the device's usage count. Then + * carry out a resume, either synchronous or asynchronous. * - * Increment the usage count of the device and resume it or submit a resume - * request for it, depending on the value of @sync. + * This routine may be called in atomic context if the RPM_ASYNC flag is set. */ -int __pm_runtime_get(struct device *dev, bool sync) +int __pm_runtime_resume(struct device *dev, int rpmflags) { + unsigned long flags; int retval; - atomic_inc(&dev->power.usage_count); - retval = sync ? pm_runtime_resume(dev) : pm_request_resume(dev); + if (rpmflags & RPM_GET_PUT) + atomic_inc(&dev->power.usage_count); - return retval; -} -EXPORT_SYMBOL_GPL(__pm_runtime_get); - -/** - * __pm_runtime_put - Decrement the device's usage counter and notify its bus. - * @dev: Device to handle. - * @sync: If the device's bus type is to be notified, do that synchronously. - * - * Decrement the usage count of the device and if it reaches zero, carry out a - * synchronous idle notification or submit an idle notification request for it, - * depending on the value of @sync. - */ -int __pm_runtime_put(struct device *dev, bool sync) -{ - int retval = 0; - - if (atomic_dec_and_test(&dev->power.usage_count)) - retval = sync ? pm_runtime_idle(dev) : pm_request_idle(dev); + spin_lock_irqsave(&dev->power.lock, flags); + retval = rpm_resume(dev, rpmflags); + spin_unlock_irqrestore(&dev->power.lock, flags); return retval; } -EXPORT_SYMBOL_GPL(__pm_runtime_put); +EXPORT_SYMBOL_GPL(__pm_runtime_resume); /** * __pm_runtime_set_status - Set run-time PM status of a device. @@ -968,7 +933,7 @@ int pm_runtime_barrier(struct device *dev) if (dev->power.request_pending && dev->power.request == RPM_REQ_RESUME) { - __pm_runtime_resume(dev, false); + rpm_resume(dev, 0); retval = 1; } @@ -1017,7 +982,7 @@ void __pm_runtime_disable(struct device *dev, bool check_resume) */ pm_runtime_get_noresume(dev); - __pm_runtime_resume(dev, false); + rpm_resume(dev, 0); pm_runtime_put_noidle(dev); } @@ -1065,7 +1030,7 @@ void pm_runtime_forbid(struct device *dev) dev->power.runtime_auto = false; atomic_inc(&dev->power.usage_count); - __pm_runtime_resume(dev, false); + rpm_resume(dev, 0); out: spin_unlock_irq(&dev->power.lock); @@ -1086,7 +1051,7 @@ void pm_runtime_allow(struct device *dev) dev->power.runtime_auto = true; if (atomic_dec_and_test(&dev->power.usage_count)) - __pm_runtime_idle(dev); + rpm_idle(dev, RPM_AUTO); out: spin_unlock_irq(&dev->power.lock); @@ -1094,13 +1059,110 @@ void pm_runtime_allow(struct device *dev) EXPORT_SYMBOL_GPL(pm_runtime_allow); /** + * pm_runtime_no_callbacks - Ignore run-time PM callbacks for a device. + * @dev: Device to handle. + * + * Set the power.no_callbacks flag, which tells the PM core that this + * device is power-managed through its parent and has no run-time PM + * callbacks of its own. The run-time sysfs attributes will be removed. + * + */ +void pm_runtime_no_callbacks(struct device *dev) +{ + spin_lock_irq(&dev->power.lock); + dev->power.no_callbacks = 1; + spin_unlock_irq(&dev->power.lock); + if (device_is_registered(dev)) + rpm_sysfs_remove(dev); +} +EXPORT_SYMBOL_GPL(pm_runtime_no_callbacks); + +/** + * update_autosuspend - Handle a change to a device's autosuspend settings. + * @dev: Device to handle. + * @old_delay: The former autosuspend_delay value. + * @old_use: The former use_autosuspend value. + * + * Prevent runtime suspend if the new delay is negative and use_autosuspend is + * set; otherwise allow it. Send an idle notification if suspends are allowed. + * + * This function must be called under dev->power.lock with interrupts disabled. + */ +static void update_autosuspend(struct device *dev, int old_delay, int old_use) +{ + int delay = dev->power.autosuspend_delay; + + /* Should runtime suspend be prevented now? */ + if (dev->power.use_autosuspend && delay < 0) { + + /* If it used to be allowed then prevent it. */ + if (!old_use || old_delay >= 0) { + atomic_inc(&dev->power.usage_count); + rpm_resume(dev, 0); + } + } + + /* Runtime suspend should be allowed now. */ + else { + + /* If it used to be prevented then allow it. */ + if (old_use && old_delay < 0) + atomic_dec(&dev->power.usage_count); + + /* Maybe we can autosuspend now. */ + rpm_idle(dev, RPM_AUTO); + } +} + +/** + * pm_runtime_set_autosuspend_delay - Set a device's autosuspend_delay value. + * @dev: Device to handle. + * @delay: Value of the new delay in milliseconds. + * + * Set the device's power.autosuspend_delay value. If it changes to negative + * and the power.use_autosuspend flag is set, prevent run-time suspends. If it + * changes the other way, allow run-time suspends. + */ +void pm_runtime_set_autosuspend_delay(struct device *dev, int delay) +{ + int old_delay, old_use; + + spin_lock_irq(&dev->power.lock); + old_delay = dev->power.autosuspend_delay; + old_use = dev->power.use_autosuspend; + dev->power.autosuspend_delay = delay; + update_autosuspend(dev, old_delay, old_use); + spin_unlock_irq(&dev->power.lock); +} +EXPORT_SYMBOL_GPL(pm_runtime_set_autosuspend_delay); + +/** + * __pm_runtime_use_autosuspend - Set a device's use_autosuspend flag. + * @dev: Device to handle. + * @use: New value for use_autosuspend. + * + * Set the device's power.use_autosuspend flag, and allow or prevent run-time + * suspends as needed. + */ +void __pm_runtime_use_autosuspend(struct device *dev, bool use) +{ + int old_delay, old_use; + + spin_lock_irq(&dev->power.lock); + old_delay = dev->power.autosuspend_delay; + old_use = dev->power.use_autosuspend; + dev->power.use_autosuspend = use; + update_autosuspend(dev, old_delay, old_use); + spin_unlock_irq(&dev->power.lock); +} +EXPORT_SYMBOL_GPL(__pm_runtime_use_autosuspend); + +/** * pm_runtime_init - Initialize run-time PM fields in given device object. * @dev: Device object to initialize. */ void pm_runtime_init(struct device *dev) { - spin_lock_init(&dev->power.lock); - dev->power.runtime_status = RPM_SUSPENDED; dev->power.idle_notification = false; diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c index e56b4388fe61..0b1e46bf3e56 100644 --- a/drivers/base/power/sysfs.c +++ b/drivers/base/power/sysfs.c @@ -75,12 +75,27 @@ * attribute is set to "enabled" by bus type code or device drivers and in * that cases it should be safe to leave the default value. * + * autosuspend_delay_ms - Report/change a device's autosuspend_delay value + * + * Some drivers don't want to carry out a runtime suspend as soon as a + * device becomes idle; they want it always to remain idle for some period + * of time before suspending it. This period is the autosuspend_delay + * value (expressed in milliseconds) and it can be controlled by the user. + * If the value is negative then the device will never be runtime + * suspended. + * + * NOTE: The autosuspend_delay_ms attribute and the autosuspend_delay + * value are used only if the driver calls pm_runtime_use_autosuspend(). + * * wakeup_count - Report the number of wakeup events related to the device */ static const char enabled[] = "enabled"; static const char disabled[] = "disabled"; +const char power_group_name[] = "power"; +EXPORT_SYMBOL_GPL(power_group_name); + #ifdef CONFIG_PM_RUNTIME static const char ctrl_auto[] = "auto"; static const char ctrl_on[] = "on"; @@ -170,6 +185,33 @@ static ssize_t rtpm_status_show(struct device *dev, } static DEVICE_ATTR(runtime_status, 0444, rtpm_status_show, NULL); + +static ssize_t autosuspend_delay_ms_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + if (!dev->power.use_autosuspend) + return -EIO; + return sprintf(buf, "%d\n", dev->power.autosuspend_delay); +} + +static ssize_t autosuspend_delay_ms_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t n) +{ + long delay; + + if (!dev->power.use_autosuspend) + return -EIO; + + if (strict_strtol(buf, 10, &delay) != 0 || delay != (int) delay) + return -EINVAL; + + pm_runtime_set_autosuspend_delay(dev, delay); + return n; +} + +static DEVICE_ATTR(autosuspend_delay_ms, 0644, autosuspend_delay_ms_show, + autosuspend_delay_ms_store); + #endif static ssize_t @@ -210,11 +252,122 @@ static DEVICE_ATTR(wakeup, 0644, wake_show, wake_store); static ssize_t wakeup_count_show(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%lu\n", dev->power.wakeup_count); + unsigned long count = 0; + bool enabled = false; + + spin_lock_irq(&dev->power.lock); + if (dev->power.wakeup) { + count = dev->power.wakeup->event_count; + enabled = true; + } + spin_unlock_irq(&dev->power.lock); + return enabled ? sprintf(buf, "%lu\n", count) : sprintf(buf, "\n"); } static DEVICE_ATTR(wakeup_count, 0444, wakeup_count_show, NULL); -#endif + +static ssize_t wakeup_active_count_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned long count = 0; + bool enabled = false; + + spin_lock_irq(&dev->power.lock); + if (dev->power.wakeup) { + count = dev->power.wakeup->active_count; + enabled = true; + } + spin_unlock_irq(&dev->power.lock); + return enabled ? sprintf(buf, "%lu\n", count) : sprintf(buf, "\n"); +} + +static DEVICE_ATTR(wakeup_active_count, 0444, wakeup_active_count_show, NULL); + +static ssize_t wakeup_hit_count_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned long count = 0; + bool enabled = false; + + spin_lock_irq(&dev->power.lock); + if (dev->power.wakeup) { + count = dev->power.wakeup->hit_count; + enabled = true; + } + spin_unlock_irq(&dev->power.lock); + return enabled ? sprintf(buf, "%lu\n", count) : sprintf(buf, "\n"); +} + +static DEVICE_ATTR(wakeup_hit_count, 0444, wakeup_hit_count_show, NULL); + +static ssize_t wakeup_active_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned int active = 0; + bool enabled = false; + + spin_lock_irq(&dev->power.lock); + if (dev->power.wakeup) { + active = dev->power.wakeup->active; + enabled = true; + } + spin_unlock_irq(&dev->power.lock); + return enabled ? sprintf(buf, "%u\n", active) : sprintf(buf, "\n"); +} + +static DEVICE_ATTR(wakeup_active, 0444, wakeup_active_show, NULL); + +static ssize_t wakeup_total_time_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + s64 msec = 0; + bool enabled = false; + + spin_lock_irq(&dev->power.lock); + if (dev->power.wakeup) { + msec = ktime_to_ms(dev->power.wakeup->total_time); + enabled = true; + } + spin_unlock_irq(&dev->power.lock); + return enabled ? sprintf(buf, "%lld\n", msec) : sprintf(buf, "\n"); +} + +static DEVICE_ATTR(wakeup_total_time_ms, 0444, wakeup_total_time_show, NULL); + +static ssize_t wakeup_max_time_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + s64 msec = 0; + bool enabled = false; + + spin_lock_irq(&dev->power.lock); + if (dev->power.wakeup) { + msec = ktime_to_ms(dev->power.wakeup->max_time); + enabled = true; + } + spin_unlock_irq(&dev->power.lock); + return enabled ? sprintf(buf, "%lld\n", msec) : sprintf(buf, "\n"); +} + +static DEVICE_ATTR(wakeup_max_time_ms, 0444, wakeup_max_time_show, NULL); + +static ssize_t wakeup_last_time_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + s64 msec = 0; + bool enabled = false; + + spin_lock_irq(&dev->power.lock); + if (dev->power.wakeup) { + msec = ktime_to_ms(dev->power.wakeup->last_time); + enabled = true; + } + spin_unlock_irq(&dev->power.lock); + return enabled ? sprintf(buf, "%lld\n", msec) : sprintf(buf, "\n"); +} + +static DEVICE_ATTR(wakeup_last_time_ms, 0444, wakeup_last_time_show, NULL); +#endif /* CONFIG_PM_SLEEP */ #ifdef CONFIG_PM_ADVANCED_DEBUG #ifdef CONFIG_PM_RUNTIME @@ -279,19 +432,20 @@ static DEVICE_ATTR(async, 0644, async_show, async_store); #endif /* CONFIG_PM_ADVANCED_DEBUG */ static struct attribute * power_attrs[] = { -#ifdef CONFIG_PM_RUNTIME - &dev_attr_control.attr, - &dev_attr_runtime_status.attr, - &dev_attr_runtime_suspended_time.attr, - &dev_attr_runtime_active_time.attr, -#endif &dev_attr_wakeup.attr, #ifdef CONFIG_PM_SLEEP &dev_attr_wakeup_count.attr, + &dev_attr_wakeup_active_count.attr, + &dev_attr_wakeup_hit_count.attr, + &dev_attr_wakeup_active.attr, + &dev_attr_wakeup_total_time_ms.attr, + &dev_attr_wakeup_max_time_ms.attr, + &dev_attr_wakeup_last_time_ms.attr, #endif #ifdef CONFIG_PM_ADVANCED_DEBUG &dev_attr_async.attr, #ifdef CONFIG_PM_RUNTIME + &dev_attr_runtime_status.attr, &dev_attr_runtime_usage.attr, &dev_attr_runtime_active_kids.attr, &dev_attr_runtime_enabled.attr, @@ -300,10 +454,53 @@ static struct attribute * power_attrs[] = { NULL, }; static struct attribute_group pm_attr_group = { - .name = "power", + .name = power_group_name, .attrs = power_attrs, }; +#ifdef CONFIG_PM_RUNTIME + +static struct attribute *runtime_attrs[] = { +#ifndef CONFIG_PM_ADVANCED_DEBUG + &dev_attr_runtime_status.attr, +#endif + &dev_attr_control.attr, + &dev_attr_runtime_suspended_time.attr, + &dev_attr_runtime_active_time.attr, + &dev_attr_autosuspend_delay_ms.attr, + NULL, +}; +static struct attribute_group pm_runtime_attr_group = { + .name = power_group_name, + .attrs = runtime_attrs, +}; + +int dpm_sysfs_add(struct device *dev) +{ + int rc; + + rc = sysfs_create_group(&dev->kobj, &pm_attr_group); + if (rc == 0 && !dev->power.no_callbacks) { + rc = sysfs_merge_group(&dev->kobj, &pm_runtime_attr_group); + if (rc) + sysfs_remove_group(&dev->kobj, &pm_attr_group); + } + return rc; +} + +void rpm_sysfs_remove(struct device *dev) +{ + sysfs_unmerge_group(&dev->kobj, &pm_runtime_attr_group); +} + +void dpm_sysfs_remove(struct device *dev) +{ + rpm_sysfs_remove(dev); + sysfs_remove_group(&dev->kobj, &pm_attr_group); +} + +#else /* CONFIG_PM_RUNTIME */ + int dpm_sysfs_add(struct device * dev) { return sysfs_create_group(&dev->kobj, &pm_attr_group); @@ -313,3 +510,5 @@ void dpm_sysfs_remove(struct device * dev) { sysfs_remove_group(&dev->kobj, &pm_attr_group); } + +#endif diff --git a/drivers/base/power/trace.c b/drivers/base/power/trace.c index 0a1a2c4dbc6e..9f4258df4cfd 100644 --- a/drivers/base/power/trace.c +++ b/drivers/base/power/trace.c @@ -188,8 +188,10 @@ static int show_file_hash(unsigned int value) static int show_dev_hash(unsigned int value) { int match = 0; - struct list_head *entry = dpm_list.prev; + struct list_head *entry; + device_pm_lock(); + entry = dpm_list.prev; while (entry != &dpm_list) { struct device * dev = to_device(entry); unsigned int hash = hash_string(DEVSEED, dev_name(dev), DEVHASH); @@ -199,11 +201,43 @@ static int show_dev_hash(unsigned int value) } entry = entry->prev; } + device_pm_unlock(); return match; } static unsigned int hash_value_early_read; +int show_trace_dev_match(char *buf, size_t size) +{ + unsigned int value = hash_value_early_read / (USERHASH * FILEHASH); + int ret = 0; + struct list_head *entry; + + /* + * It's possible that multiple devices will match the hash and we can't + * tell which is the culprit, so it's best to output them all. + */ + device_pm_lock(); + entry = dpm_list.prev; + while (size && entry != &dpm_list) { + struct device *dev = to_device(entry); + unsigned int hash = hash_string(DEVSEED, dev_name(dev), + DEVHASH); + if (hash == value) { + int len = snprintf(buf, size, "%s\n", + dev_driver_string(dev)); + if (len > size) + len = size; + buf += len; + ret += len; + size -= len; + } + entry = entry->prev; + } + device_pm_unlock(); + return ret; +} + static int early_resume_init(void) { hash_value_early_read = read_magic_time(); diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index eb594facfc3f..71c5528e1c35 100644 --- a/drivers/base/power/wakeup.c +++ b/drivers/base/power/wakeup.c @@ -11,7 +11,12 @@ #include <linux/sched.h> #include <linux/capability.h> #include <linux/suspend.h> -#include <linux/pm.h> +#include <linux/seq_file.h> +#include <linux/debugfs.h> + +#include "power.h" + +#define TIMEOUT 100 /* * If set, the suspend/hibernate code will abort transitions to a sleep state @@ -20,18 +25,244 @@ bool events_check_enabled; /* The counter of registered wakeup events. */ -static unsigned long event_count; +static atomic_t event_count = ATOMIC_INIT(0); /* A preserved old value of event_count. */ -static unsigned long saved_event_count; +static unsigned int saved_count; /* The counter of wakeup events being processed. */ -static unsigned long events_in_progress; +static atomic_t events_in_progress = ATOMIC_INIT(0); static DEFINE_SPINLOCK(events_lock); static void pm_wakeup_timer_fn(unsigned long data); -static DEFINE_TIMER(events_timer, pm_wakeup_timer_fn, 0, 0); -static unsigned long events_timer_expires; +static LIST_HEAD(wakeup_sources); + +/** + * wakeup_source_create - Create a struct wakeup_source object. + * @name: Name of the new wakeup source. + */ +struct wakeup_source *wakeup_source_create(const char *name) +{ + struct wakeup_source *ws; + + ws = kzalloc(sizeof(*ws), GFP_KERNEL); + if (!ws) + return NULL; + + spin_lock_init(&ws->lock); + if (name) + ws->name = kstrdup(name, GFP_KERNEL); + + return ws; +} +EXPORT_SYMBOL_GPL(wakeup_source_create); + +/** + * wakeup_source_destroy - Destroy a struct wakeup_source object. + * @ws: Wakeup source to destroy. + */ +void wakeup_source_destroy(struct wakeup_source *ws) +{ + if (!ws) + return; + + spin_lock_irq(&ws->lock); + while (ws->active) { + spin_unlock_irq(&ws->lock); + + schedule_timeout_interruptible(msecs_to_jiffies(TIMEOUT)); + + spin_lock_irq(&ws->lock); + } + spin_unlock_irq(&ws->lock); + + kfree(ws->name); + kfree(ws); +} +EXPORT_SYMBOL_GPL(wakeup_source_destroy); + +/** + * wakeup_source_add - Add given object to the list of wakeup sources. + * @ws: Wakeup source object to add to the list. + */ +void wakeup_source_add(struct wakeup_source *ws) +{ + if (WARN_ON(!ws)) + return; + + setup_timer(&ws->timer, pm_wakeup_timer_fn, (unsigned long)ws); + ws->active = false; + + spin_lock_irq(&events_lock); + list_add_rcu(&ws->entry, &wakeup_sources); + spin_unlock_irq(&events_lock); + synchronize_rcu(); +} +EXPORT_SYMBOL_GPL(wakeup_source_add); + +/** + * wakeup_source_remove - Remove given object from the wakeup sources list. + * @ws: Wakeup source object to remove from the list. + */ +void wakeup_source_remove(struct wakeup_source *ws) +{ + if (WARN_ON(!ws)) + return; + + spin_lock_irq(&events_lock); + list_del_rcu(&ws->entry); + spin_unlock_irq(&events_lock); + synchronize_rcu(); +} +EXPORT_SYMBOL_GPL(wakeup_source_remove); + +/** + * wakeup_source_register - Create wakeup source and add it to the list. + * @name: Name of the wakeup source to register. + */ +struct wakeup_source *wakeup_source_register(const char *name) +{ + struct wakeup_source *ws; + + ws = wakeup_source_create(name); + if (ws) + wakeup_source_add(ws); + + return ws; +} +EXPORT_SYMBOL_GPL(wakeup_source_register); + +/** + * wakeup_source_unregister - Remove wakeup source from the list and remove it. + * @ws: Wakeup source object to unregister. + */ +void wakeup_source_unregister(struct wakeup_source *ws) +{ + wakeup_source_remove(ws); + wakeup_source_destroy(ws); +} +EXPORT_SYMBOL_GPL(wakeup_source_unregister); + +/** + * device_wakeup_attach - Attach a wakeup source object to a device object. + * @dev: Device to handle. + * @ws: Wakeup source object to attach to @dev. + * + * This causes @dev to be treated as a wakeup device. + */ +static int device_wakeup_attach(struct device *dev, struct wakeup_source *ws) +{ + spin_lock_irq(&dev->power.lock); + if (dev->power.wakeup) { + spin_unlock_irq(&dev->power.lock); + return -EEXIST; + } + dev->power.wakeup = ws; + spin_unlock_irq(&dev->power.lock); + return 0; +} + +/** + * device_wakeup_enable - Enable given device to be a wakeup source. + * @dev: Device to handle. + * + * Create a wakeup source object, register it and attach it to @dev. + */ +int device_wakeup_enable(struct device *dev) +{ + struct wakeup_source *ws; + int ret; + + if (!dev || !dev->power.can_wakeup) + return -EINVAL; + + ws = wakeup_source_register(dev_name(dev)); + if (!ws) + return -ENOMEM; + + ret = device_wakeup_attach(dev, ws); + if (ret) + wakeup_source_unregister(ws); + + return ret; +} +EXPORT_SYMBOL_GPL(device_wakeup_enable); + +/** + * device_wakeup_detach - Detach a device's wakeup source object from it. + * @dev: Device to detach the wakeup source object from. + * + * After it returns, @dev will not be treated as a wakeup device any more. + */ +static struct wakeup_source *device_wakeup_detach(struct device *dev) +{ + struct wakeup_source *ws; + + spin_lock_irq(&dev->power.lock); + ws = dev->power.wakeup; + dev->power.wakeup = NULL; + spin_unlock_irq(&dev->power.lock); + return ws; +} + +/** + * device_wakeup_disable - Do not regard a device as a wakeup source any more. + * @dev: Device to handle. + * + * Detach the @dev's wakeup source object from it, unregister this wakeup source + * object and destroy it. + */ +int device_wakeup_disable(struct device *dev) +{ + struct wakeup_source *ws; + + if (!dev || !dev->power.can_wakeup) + return -EINVAL; + + ws = device_wakeup_detach(dev); + if (ws) + wakeup_source_unregister(ws); + + return 0; +} +EXPORT_SYMBOL_GPL(device_wakeup_disable); + +/** + * device_init_wakeup - Device wakeup initialization. + * @dev: Device to handle. + * @enable: Whether or not to enable @dev as a wakeup device. + * + * By default, most devices should leave wakeup disabled. The exceptions are + * devices that everyone expects to be wakeup sources: keyboards, power buttons, + * possibly network interfaces, etc. + */ +int device_init_wakeup(struct device *dev, bool enable) +{ + int ret = 0; + + if (enable) { + device_set_wakeup_capable(dev, true); + ret = device_wakeup_enable(dev); + } else { + device_set_wakeup_capable(dev, false); + } + + return ret; +} +EXPORT_SYMBOL_GPL(device_init_wakeup); + +/** + * device_set_wakeup_enable - Enable or disable a device to wake up the system. + * @dev: Device to handle. + */ +int device_set_wakeup_enable(struct device *dev, bool enable) +{ + if (!dev || !dev->power.can_wakeup) + return -EINVAL; + + return enable ? device_wakeup_enable(dev) : device_wakeup_disable(dev); +} +EXPORT_SYMBOL_GPL(device_set_wakeup_enable); /* * The functions below use the observation that each wakeup event starts a @@ -55,118 +286,259 @@ static unsigned long events_timer_expires; * knowledge, however, may not be available to it, so it can simply specify time * to wait before the system can be suspended and pass it as the second * argument of pm_wakeup_event(). + * + * It is valid to call pm_relax() after pm_wakeup_event(), in which case the + * "no suspend" period will be ended either by the pm_relax(), or by the timer + * function executed when the timer expires, whichever comes first. */ /** + * wakup_source_activate - Mark given wakeup source as active. + * @ws: Wakeup source to handle. + * + * Update the @ws' statistics and, if @ws has just been activated, notify the PM + * core of the event by incrementing the counter of of wakeup events being + * processed. + */ +static void wakeup_source_activate(struct wakeup_source *ws) +{ + ws->active = true; + ws->active_count++; + ws->timer_expires = jiffies; + ws->last_time = ktime_get(); + + atomic_inc(&events_in_progress); +} + +/** + * __pm_stay_awake - Notify the PM core of a wakeup event. + * @ws: Wakeup source object associated with the source of the event. + * + * It is safe to call this function from interrupt context. + */ +void __pm_stay_awake(struct wakeup_source *ws) +{ + unsigned long flags; + + if (!ws) + return; + + spin_lock_irqsave(&ws->lock, flags); + ws->event_count++; + if (!ws->active) + wakeup_source_activate(ws); + spin_unlock_irqrestore(&ws->lock, flags); +} +EXPORT_SYMBOL_GPL(__pm_stay_awake); + +/** * pm_stay_awake - Notify the PM core that a wakeup event is being processed. * @dev: Device the wakeup event is related to. * - * Notify the PM core of a wakeup event (signaled by @dev) by incrementing the - * counter of wakeup events being processed. If @dev is not NULL, the counter - * of wakeup events related to @dev is incremented too. + * Notify the PM core of a wakeup event (signaled by @dev) by calling + * __pm_stay_awake for the @dev's wakeup source object. * * Call this function after detecting of a wakeup event if pm_relax() is going * to be called directly after processing the event (and possibly passing it to * user space for further processing). - * - * It is safe to call this function from interrupt context. */ void pm_stay_awake(struct device *dev) { unsigned long flags; - spin_lock_irqsave(&events_lock, flags); - if (dev) - dev->power.wakeup_count++; + if (!dev) + return; - events_in_progress++; - spin_unlock_irqrestore(&events_lock, flags); + spin_lock_irqsave(&dev->power.lock, flags); + __pm_stay_awake(dev->power.wakeup); + spin_unlock_irqrestore(&dev->power.lock, flags); } +EXPORT_SYMBOL_GPL(pm_stay_awake); /** - * pm_relax - Notify the PM core that processing of a wakeup event has ended. + * wakup_source_deactivate - Mark given wakeup source as inactive. + * @ws: Wakeup source to handle. * - * Notify the PM core that a wakeup event has been processed by decrementing - * the counter of wakeup events being processed and incrementing the counter - * of registered wakeup events. + * Update the @ws' statistics and notify the PM core that the wakeup source has + * become inactive by decrementing the counter of wakeup events being processed + * and incrementing the counter of registered wakeup events. + */ +static void wakeup_source_deactivate(struct wakeup_source *ws) +{ + ktime_t duration; + ktime_t now; + + ws->relax_count++; + /* + * __pm_relax() may be called directly or from a timer function. + * If it is called directly right after the timer function has been + * started, but before the timer function calls __pm_relax(), it is + * possible that __pm_stay_awake() will be called in the meantime and + * will set ws->active. Then, ws->active may be cleared immediately + * by the __pm_relax() called from the timer function, but in such a + * case ws->relax_count will be different from ws->active_count. + */ + if (ws->relax_count != ws->active_count) { + ws->relax_count--; + return; + } + + ws->active = false; + + now = ktime_get(); + duration = ktime_sub(now, ws->last_time); + ws->total_time = ktime_add(ws->total_time, duration); + if (ktime_to_ns(duration) > ktime_to_ns(ws->max_time)) + ws->max_time = duration; + + del_timer(&ws->timer); + + /* + * event_count has to be incremented before events_in_progress is + * modified, so that the callers of pm_check_wakeup_events() and + * pm_save_wakeup_count() don't see the old value of event_count and + * events_in_progress equal to zero at the same time. + */ + atomic_inc(&event_count); + smp_mb__before_atomic_dec(); + atomic_dec(&events_in_progress); +} + +/** + * __pm_relax - Notify the PM core that processing of a wakeup event has ended. + * @ws: Wakeup source object associated with the source of the event. * * Call this function for wakeup events whose processing started with calling - * pm_stay_awake(). + * __pm_stay_awake(). * * It is safe to call it from interrupt context. */ -void pm_relax(void) +void __pm_relax(struct wakeup_source *ws) { unsigned long flags; - spin_lock_irqsave(&events_lock, flags); - if (events_in_progress) { - events_in_progress--; - event_count++; - } - spin_unlock_irqrestore(&events_lock, flags); + if (!ws) + return; + + spin_lock_irqsave(&ws->lock, flags); + if (ws->active) + wakeup_source_deactivate(ws); + spin_unlock_irqrestore(&ws->lock, flags); +} +EXPORT_SYMBOL_GPL(__pm_relax); + +/** + * pm_relax - Notify the PM core that processing of a wakeup event has ended. + * @dev: Device that signaled the event. + * + * Execute __pm_relax() for the @dev's wakeup source object. + */ +void pm_relax(struct device *dev) +{ + unsigned long flags; + + if (!dev) + return; + + spin_lock_irqsave(&dev->power.lock, flags); + __pm_relax(dev->power.wakeup); + spin_unlock_irqrestore(&dev->power.lock, flags); } +EXPORT_SYMBOL_GPL(pm_relax); /** * pm_wakeup_timer_fn - Delayed finalization of a wakeup event. + * @data: Address of the wakeup source object associated with the event source. * - * Decrease the counter of wakeup events being processed after it was increased - * by pm_wakeup_event(). + * Call __pm_relax() for the wakeup source whose address is stored in @data. */ static void pm_wakeup_timer_fn(unsigned long data) { + __pm_relax((struct wakeup_source *)data); +} + +/** + * __pm_wakeup_event - Notify the PM core of a wakeup event. + * @ws: Wakeup source object associated with the event source. + * @msec: Anticipated event processing time (in milliseconds). + * + * Notify the PM core of a wakeup event whose source is @ws that will take + * approximately @msec milliseconds to be processed by the kernel. If @ws is + * not active, activate it. If @msec is nonzero, set up the @ws' timer to + * execute pm_wakeup_timer_fn() in future. + * + * It is safe to call this function from interrupt context. + */ +void __pm_wakeup_event(struct wakeup_source *ws, unsigned int msec) +{ unsigned long flags; + unsigned long expires; - spin_lock_irqsave(&events_lock, flags); - if (events_timer_expires - && time_before_eq(events_timer_expires, jiffies)) { - events_in_progress--; - events_timer_expires = 0; + if (!ws) + return; + + spin_lock_irqsave(&ws->lock, flags); + + ws->event_count++; + if (!ws->active) + wakeup_source_activate(ws); + + if (!msec) { + wakeup_source_deactivate(ws); + goto unlock; } - spin_unlock_irqrestore(&events_lock, flags); + + expires = jiffies + msecs_to_jiffies(msec); + if (!expires) + expires = 1; + + if (time_after(expires, ws->timer_expires)) { + mod_timer(&ws->timer, expires); + ws->timer_expires = expires; + } + + unlock: + spin_unlock_irqrestore(&ws->lock, flags); } +EXPORT_SYMBOL_GPL(__pm_wakeup_event); + /** * pm_wakeup_event - Notify the PM core of a wakeup event. * @dev: Device the wakeup event is related to. * @msec: Anticipated event processing time (in milliseconds). * - * Notify the PM core of a wakeup event (signaled by @dev) that will take - * approximately @msec milliseconds to be processed by the kernel. Increment - * the counter of registered wakeup events and (if @msec is nonzero) set up - * the wakeup events timer to execute pm_wakeup_timer_fn() in future (if the - * timer has not been set up already, increment the counter of wakeup events - * being processed). If @dev is not NULL, the counter of wakeup events related - * to @dev is incremented too. - * - * It is safe to call this function from interrupt context. + * Call __pm_wakeup_event() for the @dev's wakeup source object. */ void pm_wakeup_event(struct device *dev, unsigned int msec) { unsigned long flags; - spin_lock_irqsave(&events_lock, flags); - event_count++; - if (dev) - dev->power.wakeup_count++; - - if (msec) { - unsigned long expires; + if (!dev) + return; - expires = jiffies + msecs_to_jiffies(msec); - if (!expires) - expires = 1; + spin_lock_irqsave(&dev->power.lock, flags); + __pm_wakeup_event(dev->power.wakeup, msec); + spin_unlock_irqrestore(&dev->power.lock, flags); +} +EXPORT_SYMBOL_GPL(pm_wakeup_event); - if (!events_timer_expires - || time_after(expires, events_timer_expires)) { - if (!events_timer_expires) - events_in_progress++; +/** + * pm_wakeup_update_hit_counts - Update hit counts of all active wakeup sources. + */ +static void pm_wakeup_update_hit_counts(void) +{ + unsigned long flags; + struct wakeup_source *ws; - mod_timer(&events_timer, expires); - events_timer_expires = expires; - } + rcu_read_lock(); + list_for_each_entry_rcu(ws, &wakeup_sources, entry) { + spin_lock_irqsave(&ws->lock, flags); + if (ws->active) + ws->hit_count++; + spin_unlock_irqrestore(&ws->lock, flags); } - spin_unlock_irqrestore(&events_lock, flags); + rcu_read_unlock(); } /** @@ -184,10 +556,13 @@ bool pm_check_wakeup_events(void) spin_lock_irqsave(&events_lock, flags); if (events_check_enabled) { - ret = (event_count == saved_event_count) && !events_in_progress; + ret = ((unsigned int)atomic_read(&event_count) == saved_count) + && !atomic_read(&events_in_progress); events_check_enabled = ret; } spin_unlock_irqrestore(&events_lock, flags); + if (!ret) + pm_wakeup_update_hit_counts(); return ret; } @@ -202,24 +577,20 @@ bool pm_check_wakeup_events(void) * drop down to zero has been interrupted by a signal (and the current number * of wakeup events being processed is still nonzero). Otherwise return true. */ -bool pm_get_wakeup_count(unsigned long *count) +bool pm_get_wakeup_count(unsigned int *count) { bool ret; - spin_lock_irq(&events_lock); if (capable(CAP_SYS_ADMIN)) events_check_enabled = false; - while (events_in_progress && !signal_pending(current)) { - spin_unlock_irq(&events_lock); - - schedule_timeout_interruptible(msecs_to_jiffies(100)); - - spin_lock_irq(&events_lock); + while (atomic_read(&events_in_progress) && !signal_pending(current)) { + pm_wakeup_update_hit_counts(); + schedule_timeout_interruptible(msecs_to_jiffies(TIMEOUT)); } - *count = event_count; - ret = !events_in_progress; - spin_unlock_irq(&events_lock); + + ret = !atomic_read(&events_in_progress); + *count = atomic_read(&event_count); return ret; } @@ -232,16 +603,102 @@ bool pm_get_wakeup_count(unsigned long *count) * old number of registered wakeup events to be used by pm_check_wakeup_events() * and return true. Otherwise return false. */ -bool pm_save_wakeup_count(unsigned long count) +bool pm_save_wakeup_count(unsigned int count) { bool ret = false; spin_lock_irq(&events_lock); - if (count == event_count && !events_in_progress) { - saved_event_count = count; + if (count == (unsigned int)atomic_read(&event_count) + && !atomic_read(&events_in_progress)) { + saved_count = count; events_check_enabled = true; ret = true; } spin_unlock_irq(&events_lock); + if (!ret) + pm_wakeup_update_hit_counts(); + return ret; +} + +static struct dentry *wakeup_sources_stats_dentry; + +/** + * print_wakeup_source_stats - Print wakeup source statistics information. + * @m: seq_file to print the statistics into. + * @ws: Wakeup source object to print the statistics for. + */ +static int print_wakeup_source_stats(struct seq_file *m, + struct wakeup_source *ws) +{ + unsigned long flags; + ktime_t total_time; + ktime_t max_time; + unsigned long active_count; + ktime_t active_time; + int ret; + + spin_lock_irqsave(&ws->lock, flags); + + total_time = ws->total_time; + max_time = ws->max_time; + active_count = ws->active_count; + if (ws->active) { + active_time = ktime_sub(ktime_get(), ws->last_time); + total_time = ktime_add(total_time, active_time); + if (active_time.tv64 > max_time.tv64) + max_time = active_time; + } else { + active_time = ktime_set(0, 0); + } + + ret = seq_printf(m, "%-12s\t%lu\t\t%lu\t\t%lu\t\t" + "%lld\t\t%lld\t\t%lld\t\t%lld\n", + ws->name, active_count, ws->event_count, ws->hit_count, + ktime_to_ms(active_time), ktime_to_ms(total_time), + ktime_to_ms(max_time), ktime_to_ms(ws->last_time)); + + spin_unlock_irqrestore(&ws->lock, flags); + return ret; } + +/** + * wakeup_sources_stats_show - Print wakeup sources statistics information. + * @m: seq_file to print the statistics into. + */ +static int wakeup_sources_stats_show(struct seq_file *m, void *unused) +{ + struct wakeup_source *ws; + + seq_puts(m, "name\t\tactive_count\tevent_count\thit_count\t" + "active_since\ttotal_time\tmax_time\tlast_change\n"); + + rcu_read_lock(); + list_for_each_entry_rcu(ws, &wakeup_sources, entry) + print_wakeup_source_stats(m, ws); + rcu_read_unlock(); + + return 0; +} + +static int wakeup_sources_stats_open(struct inode *inode, struct file *file) +{ + return single_open(file, wakeup_sources_stats_show, NULL); +} + +static const struct file_operations wakeup_sources_stats_fops = { + .owner = THIS_MODULE, + .open = wakeup_sources_stats_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int __init wakeup_sources_debugfs_init(void) +{ + wakeup_sources_stats_dentry = debugfs_create_file("wakeup_sources", + S_IRUGO, NULL, NULL, &wakeup_sources_stats_fops); + return 0; +} + +postcore_initcall(wakeup_sources_debugfs_init); diff --git a/drivers/base/topology.c b/drivers/base/topology.c index 9fc630ce1ddb..f6f37a05a0c3 100644 --- a/drivers/base/topology.c +++ b/drivers/base/topology.c @@ -45,7 +45,8 @@ static ssize_t show_##name(struct sys_device *dev, \ return sprintf(buf, "%d\n", topology_##name(cpu)); \ } -#if defined(topology_thread_cpumask) || defined(topology_core_cpumask) +#if defined(topology_thread_cpumask) || defined(topology_core_cpumask) || \ + defined(topology_book_cpumask) static ssize_t show_cpumap(int type, const struct cpumask *mask, char *buf) { ptrdiff_t len = PTR_ALIGN(buf + PAGE_SIZE - 1, PAGE_SIZE) - buf; @@ -114,6 +115,14 @@ define_siblings_show_func(core_cpumask); define_one_ro_named(core_siblings, show_core_cpumask); define_one_ro_named(core_siblings_list, show_core_cpumask_list); +#ifdef CONFIG_SCHED_BOOK +define_id_show_func(book_id); +define_one_ro(book_id); +define_siblings_show_func(book_cpumask); +define_one_ro_named(book_siblings, show_book_cpumask); +define_one_ro_named(book_siblings_list, show_book_cpumask_list); +#endif + static struct attribute *default_attrs[] = { &attr_physical_package_id.attr, &attr_core_id.attr, @@ -121,6 +130,11 @@ static struct attribute *default_attrs[] = { &attr_thread_siblings_list.attr, &attr_core_siblings.attr, &attr_core_siblings_list.attr, +#ifdef CONFIG_SCHED_BOOK + &attr_book_id.attr, + &attr_book_siblings.attr, + &attr_book_siblings_list.attr, +#endif NULL }; diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c index 4e2c367fec11..1f286ab461d3 100644 --- a/drivers/block/DAC960.c +++ b/drivers/block/DAC960.c @@ -36,7 +36,7 @@ #include <linux/ioport.h> #include <linux/mm.h> #include <linux/slab.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/reboot.h> @@ -54,6 +54,7 @@ #define DAC960_GAM_MINOR 252 +static DEFINE_MUTEX(DAC960_mutex); static DAC960_Controller_T *DAC960_Controllers[DAC960_MaxControllers]; static int DAC960_ControllerCount; static struct proc_dir_entry *DAC960_ProcDirectoryEntry; @@ -81,7 +82,7 @@ static int DAC960_open(struct block_device *bdev, fmode_t mode) int drive_nr = (long)disk->private_data; int ret = -ENXIO; - lock_kernel(); + mutex_lock(&DAC960_mutex); if (p->FirmwareType == DAC960_V1_Controller) { if (p->V1.LogicalDriveInformation[drive_nr]. LogicalDriveState == DAC960_V1_LogicalDrive_Offline) @@ -99,7 +100,7 @@ static int DAC960_open(struct block_device *bdev, fmode_t mode) goto out; ret = 0; out: - unlock_kernel(); + mutex_unlock(&DAC960_mutex); return ret; } @@ -6625,7 +6626,7 @@ static long DAC960_gam_ioctl(struct file *file, unsigned int Request, long ErrorCode = 0; if (!capable(CAP_SYS_ADMIN)) return -EACCES; - lock_kernel(); + mutex_lock(&DAC960_mutex); switch (Request) { case DAC960_IOCTL_GET_CONTROLLER_COUNT: @@ -7056,13 +7057,14 @@ static long DAC960_gam_ioctl(struct file *file, unsigned int Request, default: ErrorCode = -ENOTTY; } - unlock_kernel(); + mutex_unlock(&DAC960_mutex); return ErrorCode; } static const struct file_operations DAC960_gam_fops = { .owner = THIS_MODULE, - .unlocked_ioctl = DAC960_gam_ioctl + .unlocked_ioctl = DAC960_gam_ioctl, + .llseek = noop_llseek, }; static struct miscdevice DAC960_gam_dev = { diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index de277689da61..4b9359a6f6ca 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -488,4 +488,21 @@ config BLK_DEV_HD If unsure, say N. +config BLK_DEV_RBD + tristate "Rados block device (RBD)" + depends on INET && EXPERIMENTAL && BLOCK + select CEPH_LIB + select LIBCRC32C + select CRYPTO_AES + select CRYPTO + default n + help + Say Y here if you want include the Rados block device, which stripes + a block device over objects stored in the Ceph distributed object + store. + + More information at http://ceph.newdream.net/. + + If unsure, say N. + endif # BLK_DEV diff --git a/drivers/block/Makefile b/drivers/block/Makefile index aff5ac925c34..d7f463d6312d 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -37,5 +37,6 @@ obj-$(CONFIG_BLK_DEV_HD) += hd.o obj-$(CONFIG_XEN_BLKDEV_FRONTEND) += xen-blkfront.o obj-$(CONFIG_BLK_DEV_DRBD) += drbd/ +obj-$(CONFIG_BLK_DEV_RBD) += rbd.o swim_mod-objs := swim.o swim_asm.o diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c index 76f114f0bba3..a1725e6488d3 100644 --- a/drivers/block/amiflop.c +++ b/drivers/block/amiflop.c @@ -60,7 +60,7 @@ #include <linux/hdreg.h> #include <linux/delay.h> #include <linux/init.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/amifdreg.h> #include <linux/amifd.h> #include <linux/buffer_head.h> @@ -109,13 +109,12 @@ #define FD_HD_3 0x55555555 /* high-density 3.5" (1760K) drive */ #define FD_DD_5 0xaaaaaaaa /* double-density 5.25" (440K) drive */ +static DEFINE_MUTEX(amiflop_mutex); static unsigned long int fd_def_df0 = FD_DD_3; /* default for df0 if it doesn't identify */ module_param(fd_def_df0, ulong, 0); MODULE_LICENSE("GPL"); -static struct request_queue *floppy_queue; - /* * Macros */ @@ -164,6 +163,7 @@ static volatile int selected = -1; /* currently selected drive */ static int writepending; static int writefromint; static char *raw_buf; +static int fdc_queue; static DEFINE_SPINLOCK(amiflop_lock); @@ -1334,6 +1334,42 @@ static int get_track(int drive, int track) return -1; } +/* + * Round-robin between our available drives, doing one request from each + */ +static struct request *set_next_request(void) +{ + struct request_queue *q; + int cnt = FD_MAX_UNITS; + struct request *rq; + + /* Find next queue we can dispatch from */ + fdc_queue = fdc_queue + 1; + if (fdc_queue == FD_MAX_UNITS) + fdc_queue = 0; + + for(cnt = FD_MAX_UNITS; cnt > 0; cnt--) { + + if (unit[fdc_queue].type->code == FD_NODRIVE) { + if (++fdc_queue == FD_MAX_UNITS) + fdc_queue = 0; + continue; + } + + q = unit[fdc_queue].gendisk->queue; + if (q) { + rq = blk_fetch_request(q); + if (rq) + break; + } + + if (++fdc_queue == FD_MAX_UNITS) + fdc_queue = 0; + } + + return rq; +} + static void redo_fd_request(void) { struct request *rq; @@ -1345,7 +1381,7 @@ static void redo_fd_request(void) int err; next_req: - rq = blk_fetch_request(floppy_queue); + rq = set_next_request(); if (!rq) { /* Nothing left to do */ return; @@ -1506,9 +1542,9 @@ static int fd_ioctl(struct block_device *bdev, fmode_t mode, { int ret; - lock_kernel(); + mutex_lock(&amiflop_mutex); ret = fd_locked_ioctl(bdev, mode, cmd, param); - unlock_kernel(); + mutex_unlock(&amiflop_mutex); return ret; } @@ -1555,11 +1591,11 @@ static int floppy_open(struct block_device *bdev, fmode_t mode) int old_dev; unsigned long flags; - lock_kernel(); + mutex_lock(&amiflop_mutex); old_dev = fd_device[drive]; if (fd_ref[drive] && old_dev != system) { - unlock_kernel(); + mutex_unlock(&amiflop_mutex); return -EBUSY; } @@ -1575,7 +1611,7 @@ static int floppy_open(struct block_device *bdev, fmode_t mode) rel_fdc(); if (wrprot) { - unlock_kernel(); + mutex_unlock(&amiflop_mutex); return -EROFS; } } @@ -1594,7 +1630,7 @@ static int floppy_open(struct block_device *bdev, fmode_t mode) printk(KERN_INFO "fd%d: accessing %s-disk with %s-layout\n",drive, unit[drive].type->name, data_types[system].name); - unlock_kernel(); + mutex_unlock(&amiflop_mutex); return 0; } @@ -1603,7 +1639,7 @@ static int floppy_release(struct gendisk *disk, fmode_t mode) struct amiga_floppy_struct *p = disk->private_data; int drive = p - unit; - lock_kernel(); + mutex_lock(&amiflop_mutex); if (unit[drive].dirty == 1) { del_timer (flush_track_timer + drive); non_int_flush_track (drive); @@ -1617,7 +1653,7 @@ static int floppy_release(struct gendisk *disk, fmode_t mode) /* the mod_use counter is handled this way */ floppy_off (drive | 0x40000000); #endif - unlock_kernel(); + mutex_unlock(&amiflop_mutex); return 0; } @@ -1682,6 +1718,13 @@ static int __init fd_probe_drives(void) continue; } unit[drive].gendisk = disk; + + disk->queue = blk_init_queue(do_fd_request, &amiflop_lock); + if (!disk->queue) { + unit[drive].type->code = FD_NODRIVE; + continue; + } + drives++; if ((unit[drive].trackbuf = kmalloc(FLOPPY_MAX_SECTORS * 512, GFP_KERNEL)) == NULL) { printk("no mem for "); @@ -1695,7 +1738,6 @@ static int __init fd_probe_drives(void) disk->fops = &floppy_fops; sprintf(disk->disk_name, "fd%d", drive); disk->private_data = &unit[drive]; - disk->queue = floppy_queue; set_capacity(disk, 880*2); add_disk(disk); } @@ -1743,11 +1785,6 @@ static int __init amiga_floppy_probe(struct platform_device *pdev) goto out_irq2; } - ret = -ENOMEM; - floppy_queue = blk_init_queue(do_fd_request, &amiflop_lock); - if (!floppy_queue) - goto out_queue; - ret = -ENODEV; if (fd_probe_drives() < 1) /* No usable drives */ goto out_probe; @@ -1791,8 +1828,6 @@ static int __init amiga_floppy_probe(struct platform_device *pdev) return 0; out_probe: - blk_cleanup_queue(floppy_queue); -out_queue: free_irq(IRQ_AMIGA_CIAA_TB, NULL); out_irq2: free_irq(IRQ_AMIGA_DSKBLK, NULL); @@ -1810,9 +1845,12 @@ static int __exit amiga_floppy_remove(struct platform_device *pdev) for( i = 0; i < FD_MAX_UNITS; i++) { if (unit[i].type->code != FD_NODRIVE) { + struct request_queue *q = unit[i].gendisk->queue; del_gendisk(unit[i].gendisk); put_disk(unit[i].gendisk); kfree(unit[i].trackbuf); + if (q) + blk_cleanup_queue(q); } } blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256); @@ -1820,7 +1858,6 @@ static int __exit amiga_floppy_remove(struct platform_device *pdev) free_irq(IRQ_AMIGA_DSKBLK, NULL); custom.dmacon = DMAF_DISK; /* disable DMA */ amiga_chip_free(raw_buf); - blk_cleanup_queue(floppy_queue); unregister_blkdev(FLOPPY_MAJOR, "fd"); } #endif diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c index a946929735a5..f21c237a9e5e 100644 --- a/drivers/block/aoe/aoeblk.c +++ b/drivers/block/aoe/aoeblk.c @@ -12,9 +12,10 @@ #include <linux/slab.h> #include <linux/genhd.h> #include <linux/netdevice.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include "aoe.h" +static DEFINE_MUTEX(aoeblk_mutex); static struct kmem_cache *buf_pool_cache; static ssize_t aoedisk_show_state(struct device *dev, @@ -125,16 +126,16 @@ aoeblk_open(struct block_device *bdev, fmode_t mode) struct aoedev *d = bdev->bd_disk->private_data; ulong flags; - lock_kernel(); + mutex_lock(&aoeblk_mutex); spin_lock_irqsave(&d->lock, flags); if (d->flags & DEVFL_UP) { d->nopen++; spin_unlock_irqrestore(&d->lock, flags); - unlock_kernel(); + mutex_unlock(&aoeblk_mutex); return 0; } spin_unlock_irqrestore(&d->lock, flags); - unlock_kernel(); + mutex_unlock(&aoeblk_mutex); return -ENODEV; } diff --git a/drivers/block/aoe/aoechr.c b/drivers/block/aoe/aoechr.c index 4a1b9e7464aa..146296ca4965 100644 --- a/drivers/block/aoe/aoechr.c +++ b/drivers/block/aoe/aoechr.c @@ -9,7 +9,7 @@ #include <linux/completion.h> #include <linux/delay.h> #include <linux/slab.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/skbuff.h> #include "aoe.h" @@ -37,6 +37,7 @@ struct ErrMsg { char *msg; }; +static DEFINE_MUTEX(aoechr_mutex); static struct ErrMsg emsgs[NMSG]; static int emsgs_head_idx, emsgs_tail_idx; static struct completion emsgs_comp; @@ -183,16 +184,16 @@ aoechr_open(struct inode *inode, struct file *filp) { int n, i; - lock_kernel(); + mutex_lock(&aoechr_mutex); n = iminor(inode); filp->private_data = (void *) (unsigned long) n; for (i = 0; i < ARRAY_SIZE(chardevs); ++i) if (chardevs[i].minor == n) { - unlock_kernel(); + mutex_unlock(&aoechr_mutex); return 0; } - unlock_kernel(); + mutex_unlock(&aoechr_mutex); return -EINVAL; } @@ -265,6 +266,7 @@ static const struct file_operations aoe_fops = { .open = aoechr_open, .release = aoechr_rel, .owner = THIS_MODULE, + .llseek = noop_llseek, }; static char *aoe_devnode(struct device *dev, mode_t *mode) diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c index aceb96476524..4e4cc6c828cb 100644 --- a/drivers/block/ataflop.c +++ b/drivers/block/ataflop.c @@ -67,7 +67,7 @@ #include <linux/delay.h> #include <linux/init.h> #include <linux/blkdev.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <asm/atafd.h> #include <asm/atafdreg.h> @@ -79,8 +79,9 @@ #undef DEBUG -static struct request_queue *floppy_queue; +static DEFINE_MUTEX(ataflop_mutex); static struct request *fd_request; +static int fdc_queue; /* Disk types: DD, HD, ED */ static struct atari_disk_type { @@ -1391,6 +1392,29 @@ static void setup_req_params( int drive ) ReqTrack, ReqSector, (unsigned long)ReqData )); } +/* + * Round-robin between our available drives, doing one request from each + */ +static struct request *set_next_request(void) +{ + struct request_queue *q; + int old_pos = fdc_queue; + struct request *rq; + + do { + q = unit[fdc_queue].disk->queue; + if (++fdc_queue == FD_MAX_UNITS) + fdc_queue = 0; + if (q) { + rq = blk_fetch_request(q); + if (rq) + break; + } + } while (fdc_queue != old_pos); + + return rq; +} + static void redo_fd_request(void) { @@ -1405,7 +1429,7 @@ static void redo_fd_request(void) repeat: if (!fd_request) { - fd_request = blk_fetch_request(floppy_queue); + fd_request = set_next_request(); if (!fd_request) goto the_end; } @@ -1671,9 +1695,9 @@ static int fd_ioctl(struct block_device *bdev, fmode_t mode, { int ret; - lock_kernel(); + mutex_lock(&ataflop_mutex); ret = fd_locked_ioctl(bdev, mode, cmd, arg); - unlock_kernel(); + mutex_unlock(&ataflop_mutex); return ret; } @@ -1854,9 +1878,9 @@ static int floppy_unlocked_open(struct block_device *bdev, fmode_t mode) { int ret; - lock_kernel(); + mutex_lock(&ataflop_mutex); ret = floppy_open(bdev, mode); - unlock_kernel(); + mutex_unlock(&ataflop_mutex); return ret; } @@ -1864,14 +1888,14 @@ static int floppy_unlocked_open(struct block_device *bdev, fmode_t mode) static int floppy_release(struct gendisk *disk, fmode_t mode) { struct atari_floppy_struct *p = disk->private_data; - lock_kernel(); + mutex_lock(&ataflop_mutex); if (p->ref < 0) p->ref = 0; else if (!p->ref--) { printk(KERN_ERR "floppy_release with fd_ref == 0"); p->ref = 0; } - unlock_kernel(); + mutex_unlock(&ataflop_mutex); return 0; } @@ -1932,10 +1956,6 @@ static int __init atari_floppy_init (void) PhysTrackBuffer = virt_to_phys(TrackBuffer); BufferDrive = BufferSide = BufferTrack = -1; - floppy_queue = blk_init_queue(do_fd_request, &ataflop_lock); - if (!floppy_queue) - goto Enomem; - for (i = 0; i < FD_MAX_UNITS; i++) { unit[i].track = -1; unit[i].flags = 0; @@ -1944,7 +1964,10 @@ static int __init atari_floppy_init (void) sprintf(unit[i].disk->disk_name, "fd%d", i); unit[i].disk->fops = &floppy_fops; unit[i].disk->private_data = &unit[i]; - unit[i].disk->queue = floppy_queue; + unit[i].disk->queue = blk_init_queue(do_fd_request, + &ataflop_lock); + if (!unit[i].disk->queue) + goto Enomem; set_capacity(unit[i].disk, MAX_DISK_SIZE * 2); add_disk(unit[i].disk); } @@ -1959,10 +1982,14 @@ static int __init atari_floppy_init (void) return 0; Enomem: - while (i--) + while (i--) { + struct request_queue *q = unit[i].disk->queue; + put_disk(unit[i].disk); - if (floppy_queue) - blk_cleanup_queue(floppy_queue); + if (q) + blk_cleanup_queue(q); + } + unregister_blkdev(FLOPPY_MAJOR, "fd"); return -ENOMEM; } @@ -2011,12 +2038,14 @@ static void __exit atari_floppy_exit(void) int i; blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256); for (i = 0; i < FD_MAX_UNITS; i++) { + struct request_queue *q = unit[i].disk->queue; + del_gendisk(unit[i].disk); put_disk(unit[i].disk); + blk_cleanup_queue(q); } unregister_blkdev(FLOPPY_MAJOR, "fd"); - blk_cleanup_queue(floppy_queue); del_timer_sync(&fd_timer); atari_stram_free( DMABuffer ); } diff --git a/drivers/block/brd.c b/drivers/block/brd.c index 1c7f63792ff8..b7f51e4594f8 100644 --- a/drivers/block/brd.c +++ b/drivers/block/brd.c @@ -15,7 +15,7 @@ #include <linux/blkdev.h> #include <linux/bio.h> #include <linux/highmem.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/radix-tree.h> #include <linux/buffer_head.h> /* invalidate_bh_lrus() */ #include <linux/slab.h> @@ -55,6 +55,7 @@ struct brd_device { /* * Look up and return a brd's page for a given sector. */ +static DEFINE_MUTEX(brd_mutex); static struct page *brd_lookup_page(struct brd_device *brd, sector_t sector) { pgoff_t idx; @@ -402,7 +403,7 @@ static int brd_ioctl(struct block_device *bdev, fmode_t mode, * ram device BLKFLSBUF has special semantics, we want to actually * release and destroy the ramdisk data. */ - lock_kernel(); + mutex_lock(&brd_mutex); mutex_lock(&bdev->bd_mutex); error = -EBUSY; if (bdev->bd_openers <= 1) { @@ -419,7 +420,7 @@ static int brd_ioctl(struct block_device *bdev, fmode_t mode, error = 0; } mutex_unlock(&bdev->bd_mutex); - unlock_kernel(); + mutex_unlock(&brd_mutex); return error; } @@ -482,7 +483,6 @@ static struct brd_device *brd_alloc(int i) if (!brd->brd_queue) goto out_free_dev; blk_queue_make_request(brd->brd_queue, brd_make_request); - blk_queue_ordered(brd->brd_queue, QUEUE_ORDERED_TAG); blk_queue_max_hw_sectors(brd->brd_queue, 1024); blk_queue_bounce_limit(brd->brd_queue, BLK_BOUNCE_ANY); diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 5e4fadcdece9..f09e6df15aa7 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -26,7 +26,6 @@ #include <linux/pci.h> #include <linux/kernel.h> #include <linux/slab.h> -#include <linux/smp_lock.h> #include <linux/delay.h> #include <linux/major.h> #include <linux/fs.h> @@ -66,6 +65,7 @@ MODULE_SUPPORTED_DEVICE("HP Smart Array Controllers"); MODULE_VERSION("3.6.26"); MODULE_LICENSE("GPL"); +static DEFINE_MUTEX(cciss_mutex); static int cciss_allow_hpsa; module_param(cciss_allow_hpsa, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(cciss_allow_hpsa, @@ -105,11 +105,12 @@ static const struct pci_device_id cciss_pci_device_id[] = { {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3249}, {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, 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}, + {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x3350}, + {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x3351}, + {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x3352}, + {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x3353}, + {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x3354}, + {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x3355}, {0,} }; @@ -149,11 +150,12 @@ static struct board_type products[] = { {0x3249103C, "Smart Array P812", &SA5_access}, {0x324A103C, "Smart Array P712m", &SA5_access}, {0x324B103C, "Smart Array P711m", &SA5_access}, - {0x3250103C, "Smart Array", &SA5_access}, - {0x3251103C, "Smart Array", &SA5_access}, - {0x3252103C, "Smart Array", &SA5_access}, - {0x3253103C, "Smart Array", &SA5_access}, - {0x3254103C, "Smart Array", &SA5_access}, + {0x3350103C, "Smart Array", &SA5_access}, + {0x3351103C, "Smart Array", &SA5_access}, + {0x3352103C, "Smart Array", &SA5_access}, + {0x3353103C, "Smart Array", &SA5_access}, + {0x3354103C, "Smart Array", &SA5_access}, + {0x3355103C, "Smart Array", &SA5_access}, }; /* How long to wait (in milliseconds) for board to go into simple mode */ @@ -1059,9 +1061,9 @@ static int cciss_unlocked_open(struct block_device *bdev, fmode_t mode) { int ret; - lock_kernel(); + mutex_lock(&cciss_mutex); ret = cciss_open(bdev, mode); - unlock_kernel(); + mutex_unlock(&cciss_mutex); return ret; } @@ -1074,13 +1076,13 @@ static int cciss_release(struct gendisk *disk, fmode_t mode) ctlr_info_t *h; drive_info_struct *drv; - lock_kernel(); + mutex_lock(&cciss_mutex); h = get_host(disk); drv = get_drv(disk); dev_dbg(&h->pdev->dev, "cciss_release %s\n", disk->disk_name); drv->usage_count--; h->usage_count--; - unlock_kernel(); + mutex_unlock(&cciss_mutex); return 0; } @@ -1088,9 +1090,9 @@ static int do_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd, unsigned long arg) { int ret; - lock_kernel(); + mutex_lock(&cciss_mutex); ret = cciss_ioctl(bdev, mode, cmd, arg); - unlock_kernel(); + mutex_unlock(&cciss_mutex); return ret; } @@ -1232,470 +1234,452 @@ static void check_ioctl_unit_attention(ctlr_info_t *h, CommandList_struct *c) c->err_info->ScsiStatus != SAM_STAT_CHECK_CONDITION) (void)check_for_unit_attention(h, c); } -/* - * ioctl - */ -static int cciss_ioctl(struct block_device *bdev, fmode_t mode, - unsigned int cmd, unsigned long arg) + +static int cciss_getpciinfo(ctlr_info_t *h, void __user *argp) { - struct gendisk *disk = bdev->bd_disk; - ctlr_info_t *h = get_host(disk); - drive_info_struct *drv = get_drv(disk); - void __user *argp = (void __user *)arg; + cciss_pci_info_struct pciinfo; - dev_dbg(&h->pdev->dev, "cciss_ioctl: Called with cmd=%x %lx\n", - cmd, arg); - switch (cmd) { - case CCISS_GETPCIINFO: - { - cciss_pci_info_struct pciinfo; - - if (!arg) - return -EINVAL; - pciinfo.domain = pci_domain_nr(h->pdev->bus); - pciinfo.bus = h->pdev->bus->number; - pciinfo.dev_fn = h->pdev->devfn; - pciinfo.board_id = h->board_id; - if (copy_to_user - (argp, &pciinfo, sizeof(cciss_pci_info_struct))) - return -EFAULT; - return 0; - } - case CCISS_GETINTINFO: - { - cciss_coalint_struct intinfo; - if (!arg) - return -EINVAL; - intinfo.delay = - readl(&h->cfgtable->HostWrite.CoalIntDelay); - intinfo.count = - readl(&h->cfgtable->HostWrite.CoalIntCount); - if (copy_to_user - (argp, &intinfo, sizeof(cciss_coalint_struct))) - return -EFAULT; - return 0; - } - case CCISS_SETINTINFO: - { - cciss_coalint_struct intinfo; - unsigned long flags; - int i; - - if (!arg) - return -EINVAL; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (copy_from_user - (&intinfo, argp, sizeof(cciss_coalint_struct))) - return -EFAULT; - if ((intinfo.delay == 0) && (intinfo.count == 0)) - return -EINVAL; - spin_lock_irqsave(&h->lock, flags); - /* Update the field, and then ring the doorbell */ - writel(intinfo.delay, - &(h->cfgtable->HostWrite.CoalIntDelay)); - writel(intinfo.count, - &(h->cfgtable->HostWrite.CoalIntCount)); - writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); - - for (i = 0; i < MAX_IOCTL_CONFIG_WAIT; i++) { - if (!(readl(h->vaddr + SA5_DOORBELL) - & CFGTBL_ChangeReq)) - break; - /* delay and try again */ - udelay(1000); - } - spin_unlock_irqrestore(&h->lock, flags); - if (i >= MAX_IOCTL_CONFIG_WAIT) - return -EAGAIN; - return 0; - } - case CCISS_GETNODENAME: - { - NodeName_type NodeName; - int i; - - if (!arg) - return -EINVAL; - for (i = 0; i < 16; i++) - NodeName[i] = - readb(&h->cfgtable->ServerName[i]); - if (copy_to_user(argp, NodeName, sizeof(NodeName_type))) - return -EFAULT; - return 0; - } - case CCISS_SETNODENAME: - { - NodeName_type NodeName; - unsigned long flags; - int i; + if (!argp) + return -EINVAL; + pciinfo.domain = pci_domain_nr(h->pdev->bus); + pciinfo.bus = h->pdev->bus->number; + pciinfo.dev_fn = h->pdev->devfn; + pciinfo.board_id = h->board_id; + if (copy_to_user(argp, &pciinfo, sizeof(cciss_pci_info_struct))) + return -EFAULT; + return 0; +} - if (!arg) - return -EINVAL; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; +static int cciss_getintinfo(ctlr_info_t *h, void __user *argp) +{ + cciss_coalint_struct intinfo; - if (copy_from_user - (NodeName, argp, sizeof(NodeName_type))) - return -EFAULT; + if (!argp) + return -EINVAL; + intinfo.delay = readl(&h->cfgtable->HostWrite.CoalIntDelay); + intinfo.count = readl(&h->cfgtable->HostWrite.CoalIntCount); + if (copy_to_user + (argp, &intinfo, sizeof(cciss_coalint_struct))) + return -EFAULT; + return 0; +} - spin_lock_irqsave(&h->lock, flags); +static int cciss_setintinfo(ctlr_info_t *h, void __user *argp) +{ + cciss_coalint_struct intinfo; + unsigned long flags; + int i; - /* Update the field, and then ring the doorbell */ - for (i = 0; i < 16; i++) - writeb(NodeName[i], - &h->cfgtable->ServerName[i]); + if (!argp) + return -EINVAL; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (copy_from_user(&intinfo, argp, sizeof(intinfo))) + return -EFAULT; + if ((intinfo.delay == 0) && (intinfo.count == 0)) + return -EINVAL; + spin_lock_irqsave(&h->lock, flags); + /* Update the field, and then ring the doorbell */ + writel(intinfo.delay, &(h->cfgtable->HostWrite.CoalIntDelay)); + writel(intinfo.count, &(h->cfgtable->HostWrite.CoalIntCount)); + writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); - writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); + for (i = 0; i < MAX_IOCTL_CONFIG_WAIT; i++) { + if (!(readl(h->vaddr + SA5_DOORBELL) & CFGTBL_ChangeReq)) + break; + udelay(1000); /* delay and try again */ + } + spin_unlock_irqrestore(&h->lock, flags); + if (i >= MAX_IOCTL_CONFIG_WAIT) + return -EAGAIN; + return 0; +} - for (i = 0; i < MAX_IOCTL_CONFIG_WAIT; i++) { - if (!(readl(h->vaddr + SA5_DOORBELL) - & CFGTBL_ChangeReq)) - break; - /* delay and try again */ - udelay(1000); - } - spin_unlock_irqrestore(&h->lock, flags); - if (i >= MAX_IOCTL_CONFIG_WAIT) - return -EAGAIN; - return 0; - } +static int cciss_getnodename(ctlr_info_t *h, void __user *argp) +{ + NodeName_type NodeName; + int i; - case CCISS_GETHEARTBEAT: - { - Heartbeat_type heartbeat; - - if (!arg) - return -EINVAL; - heartbeat = readl(&h->cfgtable->HeartBeat); - if (copy_to_user - (argp, &heartbeat, sizeof(Heartbeat_type))) - return -EFAULT; - return 0; - } - case CCISS_GETBUSTYPES: - { - BusTypes_type BusTypes; - - if (!arg) - return -EINVAL; - BusTypes = readl(&h->cfgtable->BusTypes); - if (copy_to_user - (argp, &BusTypes, sizeof(BusTypes_type))) - return -EFAULT; - return 0; - } - case CCISS_GETFIRMVER: - { - FirmwareVer_type firmware; + if (!argp) + return -EINVAL; + for (i = 0; i < 16; i++) + NodeName[i] = readb(&h->cfgtable->ServerName[i]); + if (copy_to_user(argp, NodeName, sizeof(NodeName_type))) + return -EFAULT; + return 0; +} - if (!arg) - return -EINVAL; - memcpy(firmware, h->firm_ver, 4); +static int cciss_setnodename(ctlr_info_t *h, void __user *argp) +{ + NodeName_type NodeName; + unsigned long flags; + int i; - if (copy_to_user - (argp, firmware, sizeof(FirmwareVer_type))) - return -EFAULT; - return 0; - } - case CCISS_GETDRIVVER: - { - DriverVer_type DriverVer = DRIVER_VERSION; + if (!argp) + return -EINVAL; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (copy_from_user(NodeName, argp, sizeof(NodeName_type))) + return -EFAULT; + spin_lock_irqsave(&h->lock, flags); + /* Update the field, and then ring the doorbell */ + for (i = 0; i < 16; i++) + writeb(NodeName[i], &h->cfgtable->ServerName[i]); + writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); + for (i = 0; i < MAX_IOCTL_CONFIG_WAIT; i++) { + if (!(readl(h->vaddr + SA5_DOORBELL) & CFGTBL_ChangeReq)) + break; + udelay(1000); /* delay and try again */ + } + spin_unlock_irqrestore(&h->lock, flags); + if (i >= MAX_IOCTL_CONFIG_WAIT) + return -EAGAIN; + return 0; +} - if (!arg) - return -EINVAL; +static int cciss_getheartbeat(ctlr_info_t *h, void __user *argp) +{ + Heartbeat_type heartbeat; - if (copy_to_user - (argp, &DriverVer, sizeof(DriverVer_type))) - return -EFAULT; - return 0; - } + if (!argp) + return -EINVAL; + heartbeat = readl(&h->cfgtable->HeartBeat); + if (copy_to_user(argp, &heartbeat, sizeof(Heartbeat_type))) + return -EFAULT; + return 0; +} - case CCISS_DEREGDISK: - case CCISS_REGNEWD: - case CCISS_REVALIDVOLS: - return rebuild_lun_table(h, 0, 1); +static int cciss_getbustypes(ctlr_info_t *h, void __user *argp) +{ + BusTypes_type BusTypes; + + if (!argp) + return -EINVAL; + BusTypes = readl(&h->cfgtable->BusTypes); + if (copy_to_user(argp, &BusTypes, sizeof(BusTypes_type))) + return -EFAULT; + return 0; +} - case CCISS_GETLUNINFO:{ - LogvolInfo_struct luninfo; +static int cciss_getfirmver(ctlr_info_t *h, void __user *argp) +{ + FirmwareVer_type firmware; - memcpy(&luninfo.LunID, drv->LunID, - sizeof(luninfo.LunID)); - luninfo.num_opens = drv->usage_count; - luninfo.num_parts = 0; - if (copy_to_user(argp, &luninfo, - sizeof(LogvolInfo_struct))) - return -EFAULT; - return 0; + if (!argp) + return -EINVAL; + memcpy(firmware, h->firm_ver, 4); + + if (copy_to_user + (argp, firmware, sizeof(FirmwareVer_type))) + return -EFAULT; + return 0; +} + +static int cciss_getdrivver(ctlr_info_t *h, void __user *argp) +{ + DriverVer_type DriverVer = DRIVER_VERSION; + + if (!argp) + return -EINVAL; + if (copy_to_user(argp, &DriverVer, sizeof(DriverVer_type))) + return -EFAULT; + return 0; +} + +static int cciss_getluninfo(ctlr_info_t *h, + struct gendisk *disk, void __user *argp) +{ + LogvolInfo_struct luninfo; + drive_info_struct *drv = get_drv(disk); + + if (!argp) + return -EINVAL; + memcpy(&luninfo.LunID, drv->LunID, sizeof(luninfo.LunID)); + luninfo.num_opens = drv->usage_count; + luninfo.num_parts = 0; + if (copy_to_user(argp, &luninfo, sizeof(LogvolInfo_struct))) + return -EFAULT; + return 0; +} + +static int cciss_passthru(ctlr_info_t *h, void __user *argp) +{ + IOCTL_Command_struct iocommand; + CommandList_struct *c; + char *buff = NULL; + u64bit temp64; + DECLARE_COMPLETION_ONSTACK(wait); + + if (!argp) + return -EINVAL; + + if (!capable(CAP_SYS_RAWIO)) + return -EPERM; + + if (copy_from_user + (&iocommand, argp, sizeof(IOCTL_Command_struct))) + return -EFAULT; + if ((iocommand.buf_size < 1) && + (iocommand.Request.Type.Direction != XFER_NONE)) { + return -EINVAL; + } + if (iocommand.buf_size > 0) { + buff = kmalloc(iocommand.buf_size, GFP_KERNEL); + if (buff == NULL) + return -EFAULT; + } + if (iocommand.Request.Type.Direction == XFER_WRITE) { + /* Copy the data into the buffer we created */ + if (copy_from_user(buff, iocommand.buf, iocommand.buf_size)) { + kfree(buff); + return -EFAULT; } - case CCISS_PASSTHRU: - { - IOCTL_Command_struct iocommand; - CommandList_struct *c; - char *buff = NULL; - u64bit temp64; - DECLARE_COMPLETION_ONSTACK(wait); - - if (!arg) - return -EINVAL; - - if (!capable(CAP_SYS_RAWIO)) - return -EPERM; - - if (copy_from_user - (&iocommand, argp, sizeof(IOCTL_Command_struct))) - return -EFAULT; - if ((iocommand.buf_size < 1) && - (iocommand.Request.Type.Direction != XFER_NONE)) { - return -EINVAL; - } -#if 0 /* 'buf_size' member is 16-bits, and always smaller than kmalloc limit */ - /* Check kmalloc limits */ - if (iocommand.buf_size > 128000) - return -EINVAL; -#endif - if (iocommand.buf_size > 0) { - buff = kmalloc(iocommand.buf_size, GFP_KERNEL); - if (buff == NULL) - return -EFAULT; - } - if (iocommand.Request.Type.Direction == XFER_WRITE) { - /* Copy the data into the buffer we created */ - if (copy_from_user - (buff, iocommand.buf, iocommand.buf_size)) { - kfree(buff); - return -EFAULT; - } - } else { - memset(buff, 0, iocommand.buf_size); - } - c = cmd_special_alloc(h); - if (!c) { - kfree(buff); - return -ENOMEM; - } - /* Fill in the command type */ - c->cmd_type = CMD_IOCTL_PEND; - /* Fill in Command Header */ - c->Header.ReplyQueue = 0; /* unused in simple mode */ - if (iocommand.buf_size > 0) /* buffer to fill */ - { - c->Header.SGList = 1; - c->Header.SGTotal = 1; - } else /* no buffers to fill */ - { - c->Header.SGList = 0; - c->Header.SGTotal = 0; - } - c->Header.LUN = iocommand.LUN_info; - /* use the kernel address the cmd block for tag */ - c->Header.Tag.lower = c->busaddr; - - /* Fill in Request block */ - c->Request = iocommand.Request; - - /* Fill in the scatter gather information */ - if (iocommand.buf_size > 0) { - temp64.val = pci_map_single(h->pdev, buff, - iocommand.buf_size, - PCI_DMA_BIDIRECTIONAL); - c->SG[0].Addr.lower = temp64.val32.lower; - c->SG[0].Addr.upper = temp64.val32.upper; - c->SG[0].Len = iocommand.buf_size; - c->SG[0].Ext = 0; /* we are not chaining */ - } - c->waiting = &wait; + } else { + memset(buff, 0, iocommand.buf_size); + } + c = cmd_special_alloc(h); + if (!c) { + kfree(buff); + return -ENOMEM; + } + /* Fill in the command type */ + c->cmd_type = CMD_IOCTL_PEND; + /* Fill in Command Header */ + c->Header.ReplyQueue = 0; /* unused in simple mode */ + if (iocommand.buf_size > 0) { /* buffer to fill */ + c->Header.SGList = 1; + c->Header.SGTotal = 1; + } else { /* no buffers to fill */ + c->Header.SGList = 0; + c->Header.SGTotal = 0; + } + c->Header.LUN = iocommand.LUN_info; + /* use the kernel address the cmd block for tag */ + c->Header.Tag.lower = c->busaddr; - enqueue_cmd_and_start_io(h, c); - wait_for_completion(&wait); + /* Fill in Request block */ + c->Request = iocommand.Request; - /* unlock the buffers from DMA */ - temp64.val32.lower = c->SG[0].Addr.lower; - temp64.val32.upper = c->SG[0].Addr.upper; - pci_unmap_single(h->pdev, (dma_addr_t) temp64.val, - iocommand.buf_size, - PCI_DMA_BIDIRECTIONAL); + /* Fill in the scatter gather information */ + if (iocommand.buf_size > 0) { + temp64.val = pci_map_single(h->pdev, buff, + iocommand.buf_size, PCI_DMA_BIDIRECTIONAL); + c->SG[0].Addr.lower = temp64.val32.lower; + c->SG[0].Addr.upper = temp64.val32.upper; + c->SG[0].Len = iocommand.buf_size; + c->SG[0].Ext = 0; /* we are not chaining */ + } + c->waiting = &wait; - check_ioctl_unit_attention(h, c); + enqueue_cmd_and_start_io(h, c); + wait_for_completion(&wait); - /* Copy the error information out */ - iocommand.error_info = *(c->err_info); - if (copy_to_user - (argp, &iocommand, sizeof(IOCTL_Command_struct))) { - kfree(buff); - cmd_special_free(h, c); - return -EFAULT; - } + /* unlock the buffers from DMA */ + temp64.val32.lower = c->SG[0].Addr.lower; + temp64.val32.upper = c->SG[0].Addr.upper; + pci_unmap_single(h->pdev, (dma_addr_t) temp64.val, iocommand.buf_size, + PCI_DMA_BIDIRECTIONAL); + check_ioctl_unit_attention(h, c); + + /* Copy the error information out */ + iocommand.error_info = *(c->err_info); + if (copy_to_user(argp, &iocommand, sizeof(IOCTL_Command_struct))) { + kfree(buff); + cmd_special_free(h, c); + return -EFAULT; + } - if (iocommand.Request.Type.Direction == XFER_READ) { - /* Copy the data out of the buffer we created */ - if (copy_to_user - (iocommand.buf, buff, iocommand.buf_size)) { - kfree(buff); - cmd_special_free(h, c); - return -EFAULT; - } - } + if (iocommand.Request.Type.Direction == XFER_READ) { + /* Copy the data out of the buffer we created */ + if (copy_to_user(iocommand.buf, buff, iocommand.buf_size)) { kfree(buff); cmd_special_free(h, c); - return 0; + return -EFAULT; } - case CCISS_BIG_PASSTHRU:{ - BIG_IOCTL_Command_struct *ioc; - CommandList_struct *c; - unsigned char **buff = NULL; - int *buff_size = NULL; - u64bit temp64; - BYTE sg_used = 0; - int status = 0; - int i; - DECLARE_COMPLETION_ONSTACK(wait); - __u32 left; - __u32 sz; - BYTE __user *data_ptr; - - if (!arg) - return -EINVAL; - if (!capable(CAP_SYS_RAWIO)) - return -EPERM; - ioc = (BIG_IOCTL_Command_struct *) - kmalloc(sizeof(*ioc), GFP_KERNEL); - if (!ioc) { - status = -ENOMEM; - goto cleanup1; - } - if (copy_from_user(ioc, argp, sizeof(*ioc))) { + } + kfree(buff); + cmd_special_free(h, c); + return 0; +} + +static int cciss_bigpassthru(ctlr_info_t *h, void __user *argp) +{ + BIG_IOCTL_Command_struct *ioc; + CommandList_struct *c; + unsigned char **buff = NULL; + int *buff_size = NULL; + u64bit temp64; + BYTE sg_used = 0; + int status = 0; + int i; + DECLARE_COMPLETION_ONSTACK(wait); + __u32 left; + __u32 sz; + BYTE __user *data_ptr; + + if (!argp) + return -EINVAL; + if (!capable(CAP_SYS_RAWIO)) + return -EPERM; + ioc = (BIG_IOCTL_Command_struct *) + kmalloc(sizeof(*ioc), GFP_KERNEL); + if (!ioc) { + status = -ENOMEM; + goto cleanup1; + } + if (copy_from_user(ioc, argp, sizeof(*ioc))) { + status = -EFAULT; + goto cleanup1; + } + if ((ioc->buf_size < 1) && + (ioc->Request.Type.Direction != XFER_NONE)) { + status = -EINVAL; + goto cleanup1; + } + /* Check kmalloc limits using all SGs */ + if (ioc->malloc_size > MAX_KMALLOC_SIZE) { + status = -EINVAL; + goto cleanup1; + } + if (ioc->buf_size > ioc->malloc_size * MAXSGENTRIES) { + status = -EINVAL; + goto cleanup1; + } + buff = kzalloc(MAXSGENTRIES * sizeof(char *), GFP_KERNEL); + if (!buff) { + status = -ENOMEM; + goto cleanup1; + } + buff_size = kmalloc(MAXSGENTRIES * sizeof(int), GFP_KERNEL); + if (!buff_size) { + status = -ENOMEM; + goto cleanup1; + } + left = ioc->buf_size; + data_ptr = ioc->buf; + while (left) { + sz = (left > ioc->malloc_size) ? ioc->malloc_size : left; + buff_size[sg_used] = sz; + buff[sg_used] = kmalloc(sz, GFP_KERNEL); + if (buff[sg_used] == NULL) { + status = -ENOMEM; + goto cleanup1; + } + if (ioc->Request.Type.Direction == XFER_WRITE) { + if (copy_from_user(buff[sg_used], data_ptr, sz)) { status = -EFAULT; goto cleanup1; } - if ((ioc->buf_size < 1) && - (ioc->Request.Type.Direction != XFER_NONE)) { - status = -EINVAL; - goto cleanup1; - } - /* Check kmalloc limits using all SGs */ - if (ioc->malloc_size > MAX_KMALLOC_SIZE) { - status = -EINVAL; - goto cleanup1; - } - if (ioc->buf_size > ioc->malloc_size * MAXSGENTRIES) { - status = -EINVAL; - goto cleanup1; - } - buff = - kzalloc(MAXSGENTRIES * sizeof(char *), GFP_KERNEL); - if (!buff) { - status = -ENOMEM; - goto cleanup1; - } - buff_size = kmalloc(MAXSGENTRIES * sizeof(int), - GFP_KERNEL); - if (!buff_size) { - status = -ENOMEM; - goto cleanup1; - } - left = ioc->buf_size; - data_ptr = ioc->buf; - while (left) { - sz = (left > - ioc->malloc_size) ? ioc-> - malloc_size : left; - buff_size[sg_used] = sz; - buff[sg_used] = kmalloc(sz, GFP_KERNEL); - if (buff[sg_used] == NULL) { - status = -ENOMEM; - goto cleanup1; - } - if (ioc->Request.Type.Direction == XFER_WRITE) { - if (copy_from_user - (buff[sg_used], data_ptr, sz)) { - status = -EFAULT; - goto cleanup1; - } - } else { - memset(buff[sg_used], 0, sz); - } - left -= sz; - data_ptr += sz; - sg_used++; - } - c = cmd_special_alloc(h); - if (!c) { - status = -ENOMEM; - goto cleanup1; - } - c->cmd_type = CMD_IOCTL_PEND; - c->Header.ReplyQueue = 0; + } else { + memset(buff[sg_used], 0, sz); + } + left -= sz; + data_ptr += sz; + sg_used++; + } + c = cmd_special_alloc(h); + if (!c) { + status = -ENOMEM; + goto cleanup1; + } + c->cmd_type = CMD_IOCTL_PEND; + c->Header.ReplyQueue = 0; + c->Header.SGList = sg_used; + c->Header.SGTotal = sg_used; + c->Header.LUN = ioc->LUN_info; + c->Header.Tag.lower = c->busaddr; - if (ioc->buf_size > 0) { - c->Header.SGList = sg_used; - c->Header.SGTotal = sg_used; - } else { - c->Header.SGList = 0; - c->Header.SGTotal = 0; - } - c->Header.LUN = ioc->LUN_info; - c->Header.Tag.lower = c->busaddr; - - c->Request = ioc->Request; - if (ioc->buf_size > 0) { - for (i = 0; i < sg_used; i++) { - temp64.val = - pci_map_single(h->pdev, buff[i], - buff_size[i], - PCI_DMA_BIDIRECTIONAL); - c->SG[i].Addr.lower = - temp64.val32.lower; - c->SG[i].Addr.upper = - temp64.val32.upper; - c->SG[i].Len = buff_size[i]; - c->SG[i].Ext = 0; /* we are not chaining */ - } - } - c->waiting = &wait; - enqueue_cmd_and_start_io(h, c); - wait_for_completion(&wait); - /* unlock the buffers from DMA */ - for (i = 0; i < sg_used; i++) { - temp64.val32.lower = c->SG[i].Addr.lower; - temp64.val32.upper = c->SG[i].Addr.upper; - pci_unmap_single(h->pdev, - (dma_addr_t) temp64.val, buff_size[i], - PCI_DMA_BIDIRECTIONAL); - } - check_ioctl_unit_attention(h, c); - /* Copy the error information out */ - ioc->error_info = *(c->err_info); - if (copy_to_user(argp, ioc, sizeof(*ioc))) { + c->Request = ioc->Request; + for (i = 0; i < sg_used; i++) { + temp64.val = pci_map_single(h->pdev, buff[i], buff_size[i], + PCI_DMA_BIDIRECTIONAL); + c->SG[i].Addr.lower = temp64.val32.lower; + c->SG[i].Addr.upper = temp64.val32.upper; + c->SG[i].Len = buff_size[i]; + c->SG[i].Ext = 0; /* we are not chaining */ + } + c->waiting = &wait; + enqueue_cmd_and_start_io(h, c); + wait_for_completion(&wait); + /* unlock the buffers from DMA */ + for (i = 0; i < sg_used; i++) { + temp64.val32.lower = c->SG[i].Addr.lower; + temp64.val32.upper = c->SG[i].Addr.upper; + pci_unmap_single(h->pdev, + (dma_addr_t) temp64.val, buff_size[i], + PCI_DMA_BIDIRECTIONAL); + } + check_ioctl_unit_attention(h, c); + /* Copy the error information out */ + ioc->error_info = *(c->err_info); + if (copy_to_user(argp, ioc, sizeof(*ioc))) { + cmd_special_free(h, c); + status = -EFAULT; + goto cleanup1; + } + if (ioc->Request.Type.Direction == XFER_READ) { + /* Copy the data out of the buffer we created */ + BYTE __user *ptr = ioc->buf; + for (i = 0; i < sg_used; i++) { + if (copy_to_user(ptr, buff[i], buff_size[i])) { cmd_special_free(h, c); status = -EFAULT; goto cleanup1; } - if (ioc->Request.Type.Direction == XFER_READ) { - /* Copy the data out of the buffer we created */ - BYTE __user *ptr = ioc->buf; - for (i = 0; i < sg_used; i++) { - if (copy_to_user - (ptr, buff[i], buff_size[i])) { - cmd_special_free(h, c); - status = -EFAULT; - goto cleanup1; - } - ptr += buff_size[i]; - } - } - cmd_special_free(h, c); - status = 0; - cleanup1: - if (buff) { - for (i = 0; i < sg_used; i++) - kfree(buff[i]); - kfree(buff); - } - kfree(buff_size); - kfree(ioc); - return status; + ptr += buff_size[i]; } + } + cmd_special_free(h, c); + status = 0; +cleanup1: + if (buff) { + for (i = 0; i < sg_used; i++) + kfree(buff[i]); + kfree(buff); + } + kfree(buff_size); + kfree(ioc); + return status; +} + +static int cciss_ioctl(struct block_device *bdev, fmode_t mode, + unsigned int cmd, unsigned long arg) +{ + struct gendisk *disk = bdev->bd_disk; + ctlr_info_t *h = get_host(disk); + void __user *argp = (void __user *)arg; + + dev_dbg(&h->pdev->dev, "cciss_ioctl: Called with cmd=%x %lx\n", + cmd, arg); + switch (cmd) { + case CCISS_GETPCIINFO: + return cciss_getpciinfo(h, argp); + case CCISS_GETINTINFO: + return cciss_getintinfo(h, argp); + case CCISS_SETINTINFO: + return cciss_setintinfo(h, argp); + case CCISS_GETNODENAME: + return cciss_getnodename(h, argp); + case CCISS_SETNODENAME: + return cciss_setnodename(h, argp); + case CCISS_GETHEARTBEAT: + return cciss_getheartbeat(h, argp); + case CCISS_GETBUSTYPES: + return cciss_getbustypes(h, argp); + case CCISS_GETFIRMVER: + return cciss_getfirmver(h, argp); + case CCISS_GETDRIVVER: + return cciss_getdrivver(h, argp); + case CCISS_DEREGDISK: + case CCISS_REGNEWD: + case CCISS_REVALIDVOLS: + return rebuild_lun_table(h, 0, 1); + case CCISS_GETLUNINFO: + return cciss_getluninfo(h, disk, argp); + case CCISS_PASSTHRU: + return cciss_passthru(h, argp); + case CCISS_BIG_PASSTHRU: + return cciss_bigpassthru(h, argp); /* scsi_cmd_ioctl handles these, below, though some are not */ /* very meaningful for cciss. SG_IO is the main one people want. */ diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c index d53b0291c44b..946dad4caef3 100644 --- a/drivers/block/cpqarray.c +++ b/drivers/block/cpqarray.c @@ -35,7 +35,7 @@ #include <linux/seq_file.h> #include <linux/init.h> #include <linux/hdreg.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/spinlock.h> #include <linux/blkdev.h> #include <linux/genhd.h> @@ -68,6 +68,7 @@ MODULE_LICENSE("GPL"); #define CPQARRAY_DMA_MASK 0xFFFFFFFF /* 32 bit DMA */ +static DEFINE_MUTEX(cpqarray_mutex); static int nr_ctlr; static ctlr_info_t *hba[MAX_CTLR]; @@ -845,9 +846,9 @@ static int ida_unlocked_open(struct block_device *bdev, fmode_t mode) { int ret; - lock_kernel(); + mutex_lock(&cpqarray_mutex); ret = ida_open(bdev, mode); - unlock_kernel(); + mutex_unlock(&cpqarray_mutex); return ret; } @@ -859,10 +860,10 @@ static int ida_release(struct gendisk *disk, fmode_t mode) { ctlr_info_t *host; - lock_kernel(); + mutex_lock(&cpqarray_mutex); host = get_host(disk); host->usage_count--; - unlock_kernel(); + mutex_unlock(&cpqarray_mutex); return 0; } @@ -1217,9 +1218,9 @@ static int ida_ioctl(struct block_device *bdev, fmode_t mode, { int ret; - lock_kernel(); + mutex_lock(&cpqarray_mutex); ret = ida_locked_ioctl(bdev, mode, cmd, param); - unlock_kernel(); + mutex_unlock(&cpqarray_mutex); return ret; } diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c index 9400845d602e..ac04ef97eac2 100644 --- a/drivers/block/drbd/drbd_actlog.c +++ b/drivers/block/drbd/drbd_actlog.c @@ -965,29 +965,30 @@ void __drbd_set_in_sync(struct drbd_conf *mdev, sector_t sector, int size, * ok, (capacity & 7) != 0 sometimes, but who cares... * we count rs_{total,left} in bits, not sectors. */ - spin_lock_irqsave(&mdev->al_lock, flags); count = drbd_bm_clear_bits(mdev, sbnr, ebnr); - if (count) { - /* we need the lock for drbd_try_clear_on_disk_bm */ - if (jiffies - mdev->rs_mark_time > HZ*10) { - /* should be rolling marks, - * but we estimate only anyways. */ - if (mdev->rs_mark_left != drbd_bm_total_weight(mdev) && + if (count && get_ldev(mdev)) { + unsigned long now = jiffies; + unsigned long last = mdev->rs_mark_time[mdev->rs_last_mark]; + int next = (mdev->rs_last_mark + 1) % DRBD_SYNC_MARKS; + if (time_after_eq(now, last + DRBD_SYNC_MARK_STEP)) { + unsigned long tw = drbd_bm_total_weight(mdev); + if (mdev->rs_mark_left[mdev->rs_last_mark] != tw && mdev->state.conn != C_PAUSED_SYNC_T && mdev->state.conn != C_PAUSED_SYNC_S) { - mdev->rs_mark_time = jiffies; - mdev->rs_mark_left = drbd_bm_total_weight(mdev); + mdev->rs_mark_time[next] = now; + mdev->rs_mark_left[next] = tw; + mdev->rs_last_mark = next; } } - if (get_ldev(mdev)) { - drbd_try_clear_on_disk_bm(mdev, sector, count, TRUE); - put_ldev(mdev); - } + spin_lock_irqsave(&mdev->al_lock, flags); + drbd_try_clear_on_disk_bm(mdev, sector, count, TRUE); + spin_unlock_irqrestore(&mdev->al_lock, flags); + /* just wake_up unconditional now, various lc_chaged(), * lc_put() in drbd_try_clear_on_disk_bm(). */ wake_up = 1; + put_ldev(mdev); } - spin_unlock_irqrestore(&mdev->al_lock, flags); if (wake_up) wake_up(&mdev->al_wait); } @@ -1118,7 +1119,7 @@ static int _is_in_al(struct drbd_conf *mdev, unsigned int enr) * @mdev: DRBD device. * @sector: The sector number. * - * This functions sleeps on al_wait. Returns 1 on success, 0 if interrupted. + * This functions sleeps on al_wait. Returns 0 on success, -EINTR if interrupted. */ int drbd_rs_begin_io(struct drbd_conf *mdev, sector_t sector) { @@ -1129,10 +1130,10 @@ int drbd_rs_begin_io(struct drbd_conf *mdev, sector_t sector) sig = wait_event_interruptible(mdev->al_wait, (bm_ext = _bme_get(mdev, enr))); if (sig) - return 0; + return -EINTR; if (test_bit(BME_LOCKED, &bm_ext->flags)) - return 1; + return 0; for (i = 0; i < AL_EXT_PER_BM_SECT; i++) { sig = wait_event_interruptible(mdev->al_wait, @@ -1145,13 +1146,11 @@ int drbd_rs_begin_io(struct drbd_conf *mdev, sector_t sector) wake_up(&mdev->al_wait); } spin_unlock_irq(&mdev->al_lock); - return 0; + return -EINTR; } } - set_bit(BME_LOCKED, &bm_ext->flags); - - return 1; + return 0; } /** diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c index e3f88d6e1412..fd42832f785b 100644 --- a/drivers/block/drbd/drbd_bitmap.c +++ b/drivers/block/drbd/drbd_bitmap.c @@ -569,7 +569,7 @@ int drbd_bm_resize(struct drbd_conf *mdev, sector_t capacity, int set_new_bits) * * maybe bm_set should be atomic_t ? */ -static unsigned long _drbd_bm_total_weight(struct drbd_conf *mdev) +unsigned long _drbd_bm_total_weight(struct drbd_conf *mdev) { struct drbd_bitmap *b = mdev->bitmap; unsigned long s; diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 352441b0f92f..9bdcf4393c0a 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -337,13 +337,25 @@ static inline void bm_xfer_ctx_bit_to_word_offset(struct bm_xfer_ctx *c) * NOTE that the payload starts at a long aligned offset, * regardless of 32 or 64 bit arch! */ -struct p_header { +struct p_header80 { u32 magic; u16 command; u16 length; /* bytes of data after this header */ u8 payload[0]; } __packed; -/* 8 bytes. packet FIXED for the next century! */ + +/* Header for big packets, Used for data packets exceeding 64kB */ +struct p_header95 { + u16 magic; /* use DRBD_MAGIC_BIG here */ + u16 command; + u32 length; /* Use only 24 bits of that. Ignore the highest 8 bit. */ + u8 payload[0]; +} __packed; + +union p_header { + struct p_header80 h80; + struct p_header95 h95; +}; /* * short commands, packets without payload, plain p_header: @@ -362,12 +374,16 @@ struct p_header { */ /* these defines must not be changed without changing the protocol version */ -#define DP_HARDBARRIER 1 -#define DP_RW_SYNC 2 +#define DP_HARDBARRIER 1 /* depricated */ +#define DP_RW_SYNC 2 /* equals REQ_SYNC */ #define DP_MAY_SET_IN_SYNC 4 +#define DP_UNPLUG 8 /* equals REQ_UNPLUG */ +#define DP_FUA 16 /* equals REQ_FUA */ +#define DP_FLUSH 32 /* equals REQ_FLUSH */ +#define DP_DISCARD 64 /* equals REQ_DISCARD */ struct p_data { - struct p_header head; + union p_header head; u64 sector; /* 64 bits sector number */ u64 block_id; /* to identify the request in protocol B&C */ u32 seq_num; @@ -383,7 +399,7 @@ struct p_data { * P_DATA_REQUEST, P_RS_DATA_REQUEST */ struct p_block_ack { - struct p_header head; + struct p_header80 head; u64 sector; u64 block_id; u32 blksize; @@ -392,7 +408,7 @@ struct p_block_ack { struct p_block_req { - struct p_header head; + struct p_header80 head; u64 sector; u64 block_id; u32 blksize; @@ -409,7 +425,7 @@ struct p_block_req { */ struct p_handshake { - struct p_header head; /* 8 bytes */ + struct p_header80 head; /* 8 bytes */ u32 protocol_min; u32 feature_flags; u32 protocol_max; @@ -424,19 +440,19 @@ struct p_handshake { /* 80 bytes, FIXED for the next century */ struct p_barrier { - struct p_header head; + struct p_header80 head; u32 barrier; /* barrier number _handle_ only */ u32 pad; /* to multiple of 8 Byte */ } __packed; struct p_barrier_ack { - struct p_header head; + struct p_header80 head; u32 barrier; u32 set_size; } __packed; struct p_rs_param { - struct p_header head; + struct p_header80 head; u32 rate; /* Since protocol version 88 and higher. */ @@ -444,20 +460,31 @@ struct p_rs_param { } __packed; struct p_rs_param_89 { - struct p_header head; + struct p_header80 head; u32 rate; /* protocol version 89: */ char verify_alg[SHARED_SECRET_MAX]; char csums_alg[SHARED_SECRET_MAX]; } __packed; +struct p_rs_param_95 { + struct p_header80 head; + u32 rate; + char verify_alg[SHARED_SECRET_MAX]; + char csums_alg[SHARED_SECRET_MAX]; + u32 c_plan_ahead; + u32 c_delay_target; + u32 c_fill_target; + u32 c_max_rate; +} __packed; + enum drbd_conn_flags { CF_WANT_LOSE = 1, CF_DRY_RUN = 2, }; struct p_protocol { - struct p_header head; + struct p_header80 head; u32 protocol; u32 after_sb_0p; u32 after_sb_1p; @@ -471,17 +498,17 @@ struct p_protocol { } __packed; struct p_uuids { - struct p_header head; + struct p_header80 head; u64 uuid[UI_EXTENDED_SIZE]; } __packed; struct p_rs_uuid { - struct p_header head; + struct p_header80 head; u64 uuid; } __packed; struct p_sizes { - struct p_header head; + struct p_header80 head; u64 d_size; /* size of disk */ u64 u_size; /* user requested size */ u64 c_size; /* current exported size */ @@ -491,18 +518,18 @@ struct p_sizes { } __packed; struct p_state { - struct p_header head; + struct p_header80 head; u32 state; } __packed; struct p_req_state { - struct p_header head; + struct p_header80 head; u32 mask; u32 val; } __packed; struct p_req_state_reply { - struct p_header head; + struct p_header80 head; u32 retcode; } __packed; @@ -517,7 +544,7 @@ struct p_drbd06_param { } __packed; struct p_discard { - struct p_header head; + struct p_header80 head; u64 block_id; u32 seq_num; u32 pad; @@ -533,7 +560,7 @@ enum drbd_bitmap_code { }; struct p_compressed_bm { - struct p_header head; + struct p_header80 head; /* (encoding & 0x0f): actual encoding, see enum drbd_bitmap_code * (encoding & 0x80): polarity (set/unset) of first runlength * ((encoding >> 4) & 0x07): pad_bits, number of trailing zero bits @@ -544,10 +571,10 @@ struct p_compressed_bm { u8 code[0]; } __packed; -struct p_delay_probe { - struct p_header head; - u32 seq_num; /* sequence number to match the two probe packets */ - u32 offset; /* usecs the probe got sent after the reference time point */ +struct p_delay_probe93 { + struct p_header80 head; + u32 seq_num; /* sequence number to match the two probe packets */ + u32 offset; /* usecs the probe got sent after the reference time point */ } __packed; /* DCBP: Drbd Compressed Bitmap Packet ... */ @@ -594,7 +621,7 @@ DCBP_set_pad_bits(struct p_compressed_bm *p, int n) * so we need to use the fixed size 4KiB page size * most architechtures have used for a long time. */ -#define BM_PACKET_PAYLOAD_BYTES (4096 - sizeof(struct p_header)) +#define BM_PACKET_PAYLOAD_BYTES (4096 - sizeof(struct p_header80)) #define BM_PACKET_WORDS (BM_PACKET_PAYLOAD_BYTES/sizeof(long)) #define BM_PACKET_VLI_BYTES_MAX (4096 - sizeof(struct p_compressed_bm)) #if (PAGE_SIZE < 4096) @@ -603,13 +630,14 @@ DCBP_set_pad_bits(struct p_compressed_bm *p, int n) #endif union p_polymorph { - struct p_header header; + union p_header header; struct p_handshake handshake; struct p_data data; struct p_block_ack block_ack; struct p_barrier barrier; struct p_barrier_ack barrier_ack; struct p_rs_param_89 rs_param_89; + struct p_rs_param_95 rs_param_95; struct p_protocol protocol; struct p_sizes sizes; struct p_uuids uuids; @@ -617,6 +645,8 @@ union p_polymorph { struct p_req_state req_state; struct p_req_state_reply req_state_reply; struct p_block_req block_req; + struct p_delay_probe93 delay_probe93; + struct p_rs_uuid rs_uuid; } __packed; /**********************************************************************/ @@ -697,7 +727,7 @@ struct drbd_tl_epoch { struct list_head requests; /* requests before */ struct drbd_tl_epoch *next; /* pointer to the next barrier */ unsigned int br_number; /* the barriers identifier. */ - int n_req; /* number of requests attached before this barrier */ + int n_writes; /* number of requests attached before this barrier */ }; struct drbd_request; @@ -747,7 +777,7 @@ struct digest_info { struct drbd_epoch_entry { struct drbd_work w; struct hlist_node colision; - struct drbd_epoch *epoch; + struct drbd_epoch *epoch; /* for writes */ struct drbd_conf *mdev; struct page *pages; atomic_t pending_bios; @@ -755,7 +785,10 @@ struct drbd_epoch_entry { /* see comments on ee flag bits below */ unsigned long flags; sector_t sector; - u64 block_id; + union { + u64 block_id; + struct digest_info *digest; + }; }; /* ee flag bits. @@ -781,12 +814,16 @@ enum { * if any of those fail, we set this flag atomically * from the endio callback */ __EE_WAS_ERROR, + + /* This ee has a pointer to a digest instead of a block id */ + __EE_HAS_DIGEST, }; #define EE_CALL_AL_COMPLETE_IO (1<<__EE_CALL_AL_COMPLETE_IO) #define EE_MAY_SET_IN_SYNC (1<<__EE_MAY_SET_IN_SYNC) #define EE_IS_BARRIER (1<<__EE_IS_BARRIER) #define EE_RESUBMITTED (1<<__EE_RESUBMITTED) #define EE_WAS_ERROR (1<<__EE_WAS_ERROR) +#define EE_HAS_DIGEST (1<<__EE_HAS_DIGEST) /* global flag bits */ enum { @@ -794,7 +831,6 @@ enum { SIGNAL_ASENDER, /* whether asender wants to be interrupted */ SEND_PING, /* whether asender should send a ping asap */ - STOP_SYNC_TIMER, /* tell timer to cancel itself */ UNPLUG_QUEUED, /* only relevant with kernel 2.4 */ UNPLUG_REMOTE, /* sending a "UnplugRemote" could help */ MD_DIRTY, /* current uuids and flags not yet on disk */ @@ -816,6 +852,7 @@ enum { BITMAP_IO, /* suspend application io; once no more io in flight, start bitmap io */ BITMAP_IO_QUEUED, /* Started bitmap IO */ + GO_DISKLESS, /* Disk failed, local_cnt reached zero, we are going diskless */ RESYNC_AFTER_NEG, /* Resync after online grow after the attach&negotiate finished. */ NET_CONGESTED, /* The data socket is congested */ @@ -829,6 +866,8 @@ enum { * the peer, if it changed there as well. */ CONN_DRY_RUN, /* Expect disconnect after resync handshake. */ GOT_PING_ACK, /* set when we receive a ping_ack packet, misc wait gets woken */ + NEW_CUR_UUID, /* Create new current UUID when thawing IO */ + AL_SUSPENDED, /* Activity logging is currently suspended. */ }; struct drbd_bitmap; /* opaque for drbd_conf */ @@ -838,10 +877,6 @@ struct drbd_bitmap; /* opaque for drbd_conf */ /* THINK maybe we actually want to use the default "event/%s" worker threads * or similar in linux 2.6, which uses per cpu data and threads. - * - * To be general, this might need a spin_lock member. - * For now, please use the mdev->req_lock to protect list_head, - * see drbd_queue_work below. */ struct drbd_work_queue { struct list_head q; @@ -915,6 +950,12 @@ enum write_ordering_e { WO_bio_barrier }; +struct fifo_buffer { + int *values; + unsigned int head_index; + unsigned int size; +}; + struct drbd_conf { /* things that are stored as / read from meta data on disk */ unsigned long flags; @@ -936,9 +977,16 @@ struct drbd_conf { unsigned int ko_count; struct drbd_work resync_work, unplug_work, + go_diskless, md_sync_work; struct timer_list resync_timer; struct timer_list md_sync_timer; +#ifdef DRBD_DEBUG_MD_SYNC + struct { + unsigned int line; + const char* func; + } last_md_mark_dirty; +#endif /* Used after attach while negotiating new disk state. */ union drbd_state new_state_tmp; @@ -946,6 +994,7 @@ struct drbd_conf { union drbd_state state; wait_queue_head_t misc_wait; wait_queue_head_t state_wait; /* upon each state change. */ + wait_queue_head_t net_cnt_wait; unsigned int send_cnt; unsigned int recv_cnt; unsigned int read_cnt; @@ -974,12 +1023,16 @@ struct drbd_conf { unsigned long rs_start; /* cumulated time in PausedSyncX state [unit jiffies] */ unsigned long rs_paused; + /* skipped because csum was equal [unit BM_BLOCK_SIZE] */ + unsigned long rs_same_csum; +#define DRBD_SYNC_MARKS 8 +#define DRBD_SYNC_MARK_STEP (3*HZ) /* block not up-to-date at mark [unit BM_BLOCK_SIZE] */ - unsigned long rs_mark_left; + unsigned long rs_mark_left[DRBD_SYNC_MARKS]; /* marks's time [unit jiffies] */ - unsigned long rs_mark_time; - /* skipped because csum was equeal [unit BM_BLOCK_SIZE] */ - unsigned long rs_same_csum; + unsigned long rs_mark_time[DRBD_SYNC_MARKS]; + /* current index into rs_mark_{left,time} */ + int rs_last_mark; /* where does the admin want us to start? (sector) */ sector_t ov_start_sector; @@ -1012,10 +1065,10 @@ struct drbd_conf { spinlock_t epoch_lock; unsigned int epochs; enum write_ordering_e write_ordering; - struct list_head active_ee; /* IO in progress */ - struct list_head sync_ee; /* IO in progress */ + struct list_head active_ee; /* IO in progress (P_DATA gets written to disk) */ + struct list_head sync_ee; /* IO in progress (P_RS_DATA_REPLY gets written to disk) */ struct list_head done_ee; /* send ack */ - struct list_head read_ee; /* IO in progress */ + struct list_head read_ee; /* IO in progress (any read) */ struct list_head net_ee; /* zero-copy network send in progress */ struct hlist_head *ee_hash; /* is proteced by req_lock! */ unsigned int ee_hash_s; @@ -1026,7 +1079,8 @@ struct drbd_conf { int next_barrier_nr; struct hlist_head *app_reads_hash; /* is proteced by req_lock */ struct list_head resync_reads; - atomic_t pp_in_use; + atomic_t pp_in_use; /* allocated from page pool */ + atomic_t pp_in_use_by_net; /* sendpage()d, still referenced by tcp */ wait_queue_head_t ee_wait; struct page *md_io_page; /* one page buffer for md_io */ struct page *md_io_tmpp; /* for logical_block_size != 512 */ @@ -1054,6 +1108,15 @@ struct drbd_conf { u64 ed_uuid; /* UUID of the exposed data */ struct mutex state_mutex; char congestion_reason; /* Why we where congested... */ + atomic_t rs_sect_in; /* for incoming resync data rate, SyncTarget */ + atomic_t rs_sect_ev; /* for submitted resync data rate, both */ + int rs_last_sect_ev; /* counter to compare with */ + int rs_last_events; /* counter of read or write "events" (unit sectors) + * on the lower level device when we last looked. */ + int c_sync_rate; /* current resync rate after syncer throttle magic */ + struct fifo_buffer rs_plan_s; /* correction values of resync planer */ + int rs_in_flight; /* resync sectors in flight (to proxy, in proxy and from proxy) */ + int rs_planed; /* resync sectors already planed */ }; static inline struct drbd_conf *minor_to_mdev(unsigned int minor) @@ -1138,6 +1201,8 @@ extern void drbd_free_resources(struct drbd_conf *mdev); extern void tl_release(struct drbd_conf *mdev, unsigned int barrier_nr, unsigned int set_size); extern void tl_clear(struct drbd_conf *mdev); +enum drbd_req_event; +extern void tl_restart(struct drbd_conf *mdev, enum drbd_req_event what); extern void _tl_add_barrier(struct drbd_conf *, struct drbd_tl_epoch *); extern void drbd_free_sock(struct drbd_conf *mdev); extern int drbd_send(struct drbd_conf *mdev, struct socket *sock, @@ -1150,12 +1215,12 @@ extern int drbd_send_sizes(struct drbd_conf *mdev, int trigger_reply, enum dds_f extern int _drbd_send_state(struct drbd_conf *mdev); extern int drbd_send_state(struct drbd_conf *mdev); extern int _drbd_send_cmd(struct drbd_conf *mdev, struct socket *sock, - enum drbd_packets cmd, struct p_header *h, + enum drbd_packets cmd, struct p_header80 *h, size_t size, unsigned msg_flags); #define USE_DATA_SOCKET 1 #define USE_META_SOCKET 0 extern int drbd_send_cmd(struct drbd_conf *mdev, int use_data_socket, - enum drbd_packets cmd, struct p_header *h, + enum drbd_packets cmd, struct p_header80 *h, size_t size); extern int drbd_send_cmd2(struct drbd_conf *mdev, enum drbd_packets cmd, char *data, size_t size); @@ -1167,7 +1232,7 @@ extern int drbd_send_ack(struct drbd_conf *mdev, enum drbd_packets cmd, extern int drbd_send_ack_rp(struct drbd_conf *mdev, enum drbd_packets cmd, struct p_block_req *rp); extern int drbd_send_ack_dp(struct drbd_conf *mdev, enum drbd_packets cmd, - struct p_data *dp); + struct p_data *dp, int data_size); extern int drbd_send_ack_ex(struct drbd_conf *mdev, enum drbd_packets cmd, sector_t sector, int blksize, u64 block_id); extern int drbd_send_block(struct drbd_conf *mdev, enum drbd_packets cmd, @@ -1201,7 +1266,13 @@ extern void drbd_uuid_set_bm(struct drbd_conf *mdev, u64 val) __must_hold(local) extern void drbd_md_set_flag(struct drbd_conf *mdev, int flags) __must_hold(local); extern void drbd_md_clear_flag(struct drbd_conf *mdev, int flags)__must_hold(local); extern int drbd_md_test_flag(struct drbd_backing_dev *, int); +#ifndef DRBD_DEBUG_MD_SYNC extern void drbd_md_mark_dirty(struct drbd_conf *mdev); +#else +#define drbd_md_mark_dirty(m) drbd_md_mark_dirty_(m, __LINE__ , __func__ ) +extern void drbd_md_mark_dirty_(struct drbd_conf *mdev, + unsigned int line, const char *func); +#endif extern void drbd_queue_bitmap_io(struct drbd_conf *mdev, int (*io_fn)(struct drbd_conf *), void (*done)(struct drbd_conf *, int), @@ -1209,6 +1280,7 @@ extern void drbd_queue_bitmap_io(struct drbd_conf *mdev, extern int drbd_bmio_set_n_write(struct drbd_conf *mdev); extern int drbd_bmio_clear_n_write(struct drbd_conf *mdev); extern int drbd_bitmap_io(struct drbd_conf *mdev, int (*io_fn)(struct drbd_conf *), char *why); +extern void drbd_go_diskless(struct drbd_conf *mdev); /* Meta data layout @@ -1264,6 +1336,8 @@ struct bm_extent { * Bit 1 ==> local node thinks this block needs to be synced. */ +#define SLEEP_TIME (HZ/10) + #define BM_BLOCK_SHIFT 12 /* 4k per bit */ #define BM_BLOCK_SIZE (1<<BM_BLOCK_SHIFT) /* (9+3) : 512 bytes @ 8 bits; representing 16M storage @@ -1335,11 +1409,13 @@ struct bm_extent { #endif /* Sector shift value for the "hash" functions of tl_hash and ee_hash tables. - * With a value of 6 all IO in one 32K block make it to the same slot of the + * With a value of 8 all IO in one 128K block make it to the same slot of the * hash table. */ -#define HT_SHIFT 6 +#define HT_SHIFT 8 #define DRBD_MAX_SEGMENT_SIZE (1U<<(9+HT_SHIFT)) +#define DRBD_MAX_SIZE_H80_PACKET (1 << 15) /* The old header only allows packets up to 32Kib data */ + /* Number of elements in the app_reads_hash */ #define APP_R_HSIZE 15 @@ -1369,6 +1445,7 @@ extern unsigned long drbd_bm_find_next(struct drbd_conf *mdev, unsigned long bm_ /* bm_find_next variants for use while you hold drbd_bm_lock() */ extern unsigned long _drbd_bm_find_next(struct drbd_conf *mdev, unsigned long bm_fo); extern unsigned long _drbd_bm_find_next_zero(struct drbd_conf *mdev, unsigned long bm_fo); +extern unsigned long _drbd_bm_total_weight(struct drbd_conf *mdev); extern unsigned long drbd_bm_total_weight(struct drbd_conf *mdev); extern int drbd_bm_rs_done(struct drbd_conf *mdev); /* for receive_bitmap */ @@ -1421,7 +1498,8 @@ extern void resync_after_online_grow(struct drbd_conf *); extern void drbd_setup_queue_param(struct drbd_conf *mdev, unsigned int) __must_hold(local); extern int drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force); -enum drbd_disk_state drbd_try_outdate_peer(struct drbd_conf *mdev); +extern enum drbd_disk_state drbd_try_outdate_peer(struct drbd_conf *mdev); +extern void drbd_try_outdate_peer_async(struct drbd_conf *mdev); extern int drbd_khelper(struct drbd_conf *mdev, char *cmd); /* drbd_worker.c */ @@ -1467,10 +1545,12 @@ extern int w_send_barrier(struct drbd_conf *, struct drbd_work *, int); extern int w_send_read_req(struct drbd_conf *, struct drbd_work *, int); extern int w_prev_work_done(struct drbd_conf *, struct drbd_work *, int); extern int w_e_reissue(struct drbd_conf *, struct drbd_work *, int); +extern int w_restart_disk_io(struct drbd_conf *, struct drbd_work *, int); extern void resync_timer_fn(unsigned long data); /* drbd_receiver.c */ +extern int drbd_rs_should_slow_down(struct drbd_conf *mdev); extern int drbd_submit_ee(struct drbd_conf *mdev, struct drbd_epoch_entry *e, const unsigned rw, const int fault_type); extern int drbd_release_ee(struct drbd_conf *mdev, struct list_head *list); @@ -1479,7 +1559,10 @@ extern struct drbd_epoch_entry *drbd_alloc_ee(struct drbd_conf *mdev, sector_t sector, unsigned int data_size, gfp_t gfp_mask) __must_hold(local); -extern void drbd_free_ee(struct drbd_conf *mdev, struct drbd_epoch_entry *e); +extern void drbd_free_some_ee(struct drbd_conf *mdev, struct drbd_epoch_entry *e, + int is_net); +#define drbd_free_ee(m,e) drbd_free_some_ee(m, e, 0) +#define drbd_free_net_ee(m,e) drbd_free_some_ee(m, e, 1) extern void drbd_wait_ee_list_empty(struct drbd_conf *mdev, struct list_head *head); extern void _drbd_wait_ee_list_empty(struct drbd_conf *mdev, @@ -1487,6 +1570,7 @@ extern void _drbd_wait_ee_list_empty(struct drbd_conf *mdev, extern void drbd_set_recv_tcq(struct drbd_conf *mdev, int tcq_enabled); extern void _drbd_clear_done_ee(struct drbd_conf *mdev, struct list_head *to_be_freed); extern void drbd_flush_workqueue(struct drbd_conf *mdev); +extern void drbd_free_tl_hash(struct drbd_conf *mdev); /* yes, there is kernel_setsockopt, but only since 2.6.18. we don't need to * mess with get_fs/set_fs, we know we are KERNEL_DS always. */ @@ -1600,6 +1684,8 @@ void drbd_bcast_ee(struct drbd_conf *mdev, #define susp_MASK 1 #define user_isp_MASK 1 #define aftr_isp_MASK 1 +#define susp_nod_MASK 1 +#define susp_fen_MASK 1 #define NS(T, S) \ ({ union drbd_state mask; mask.i = 0; mask.T = T##_MASK; mask; }), \ @@ -1856,13 +1942,6 @@ static inline sector_t drbd_md_ss__(struct drbd_conf *mdev, } static inline void -_drbd_queue_work(struct drbd_work_queue *q, struct drbd_work *w) -{ - list_add_tail(&w->list, &q->q); - up(&q->s); -} - -static inline void drbd_queue_work_front(struct drbd_work_queue *q, struct drbd_work *w) { unsigned long flags; @@ -1899,19 +1978,19 @@ static inline void request_ping(struct drbd_conf *mdev) static inline int drbd_send_short_cmd(struct drbd_conf *mdev, enum drbd_packets cmd) { - struct p_header h; + struct p_header80 h; return drbd_send_cmd(mdev, USE_DATA_SOCKET, cmd, &h, sizeof(h)); } static inline int drbd_send_ping(struct drbd_conf *mdev) { - struct p_header h; + struct p_header80 h; return drbd_send_cmd(mdev, USE_META_SOCKET, P_PING, &h, sizeof(h)); } static inline int drbd_send_ping_ack(struct drbd_conf *mdev) { - struct p_header h; + struct p_header80 h; return drbd_send_cmd(mdev, USE_META_SOCKET, P_PING_ACK, &h, sizeof(h)); } @@ -2013,7 +2092,7 @@ static inline void inc_unacked(struct drbd_conf *mdev) static inline void put_net_conf(struct drbd_conf *mdev) { if (atomic_dec_and_test(&mdev->net_cnt)) - wake_up(&mdev->misc_wait); + wake_up(&mdev->net_cnt_wait); } /** @@ -2044,10 +2123,14 @@ static inline int get_net_conf(struct drbd_conf *mdev) static inline void put_ldev(struct drbd_conf *mdev) { + int i = atomic_dec_return(&mdev->local_cnt); __release(local); - if (atomic_dec_and_test(&mdev->local_cnt)) + D_ASSERT(i >= 0); + if (i == 0) { + if (mdev->state.disk == D_FAILED) + drbd_go_diskless(mdev); wake_up(&mdev->misc_wait); - D_ASSERT(atomic_read(&mdev->local_cnt) >= 0); + } } #ifndef __CHECKER__ @@ -2179,11 +2262,16 @@ static inline int drbd_state_is_stable(union drbd_state s) return 1; } +static inline int is_susp(union drbd_state s) +{ + return s.susp || s.susp_nod || s.susp_fen; +} + static inline int __inc_ap_bio_cond(struct drbd_conf *mdev) { int mxb = drbd_get_max_buffers(mdev); - if (mdev->state.susp) + if (is_susp(mdev->state)) return 0; if (test_bit(SUSPEND_IO, &mdev->flags)) return 0; @@ -2321,8 +2409,7 @@ static inline void drbd_md_flush(struct drbd_conf *mdev) if (test_bit(MD_NO_BARRIER, &mdev->flags)) return; - r = blkdev_issue_flush(mdev->ldev->md_bdev, GFP_KERNEL, NULL, - BLKDEV_IFL_WAIT); + r = blkdev_issue_flush(mdev->ldev->md_bdev, GFP_KERNEL, NULL); if (r) { set_bit(MD_NO_BARRIER, &mdev->flags); dev_err(DEV, "meta data flush failed with status %d, disabling md-flushes\n", r); diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index fa650dd85b90..c5dfe6486cf3 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -32,7 +32,7 @@ #include <asm/types.h> #include <net/sock.h> #include <linux/ctype.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/fs.h> #include <linux/file.h> #include <linux/proc_fs.h> @@ -64,6 +64,7 @@ struct after_state_chg_work { struct completion *done; }; +static DEFINE_MUTEX(drbd_main_mutex); int drbdd_init(struct drbd_thread *); int drbd_worker(struct drbd_thread *); int drbd_asender(struct drbd_thread *); @@ -77,6 +78,7 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, static int w_md_sync(struct drbd_conf *mdev, struct drbd_work *w, int unused); static void md_sync_timer_fn(unsigned long data); static int w_bitmap_io(struct drbd_conf *mdev, struct drbd_work *w, int unused); +static int w_go_diskless(struct drbd_conf *mdev, struct drbd_work *w, int unused); MODULE_AUTHOR("Philipp Reisner <phil@linbit.com>, " "Lars Ellenberg <lars@linbit.com>"); @@ -199,7 +201,7 @@ static int tl_init(struct drbd_conf *mdev) INIT_LIST_HEAD(&b->w.list); b->next = NULL; b->br_number = 4711; - b->n_req = 0; + b->n_writes = 0; b->w.cb = NULL; /* if this is != NULL, we need to dec_ap_pending in tl_clear */ mdev->oldest_tle = b; @@ -240,7 +242,7 @@ void _tl_add_barrier(struct drbd_conf *mdev, struct drbd_tl_epoch *new) INIT_LIST_HEAD(&new->w.list); new->w.cb = NULL; /* if this is != NULL, we need to dec_ap_pending in tl_clear */ new->next = NULL; - new->n_req = 0; + new->n_writes = 0; newest_before = mdev->newest_tle; /* never send a barrier number == 0, because that is special-cased @@ -284,9 +286,9 @@ void tl_release(struct drbd_conf *mdev, unsigned int barrier_nr, barrier_nr, b->br_number); goto bail; } - if (b->n_req != set_size) { - dev_err(DEV, "BAD! BarrierAck #%u received with n_req=%u, expected n_req=%u!\n", - barrier_nr, set_size, b->n_req); + if (b->n_writes != set_size) { + dev_err(DEV, "BAD! BarrierAck #%u received with n_writes=%u, expected n_writes=%u!\n", + barrier_nr, set_size, b->n_writes); goto bail; } @@ -333,6 +335,82 @@ bail: drbd_force_state(mdev, NS(conn, C_PROTOCOL_ERROR)); } +/** + * _tl_restart() - Walks the transfer log, and applies an action to all requests + * @mdev: DRBD device. + * @what: The action/event to perform with all request objects + * + * @what might be one of connection_lost_while_pending, resend, fail_frozen_disk_io, + * restart_frozen_disk_io. + */ +static void _tl_restart(struct drbd_conf *mdev, enum drbd_req_event what) +{ + struct drbd_tl_epoch *b, *tmp, **pn; + struct list_head *le, *tle, carry_reads; + struct drbd_request *req; + int rv, n_writes, n_reads; + + b = mdev->oldest_tle; + pn = &mdev->oldest_tle; + while (b) { + n_writes = 0; + n_reads = 0; + INIT_LIST_HEAD(&carry_reads); + list_for_each_safe(le, tle, &b->requests) { + req = list_entry(le, struct drbd_request, tl_requests); + rv = _req_mod(req, what); + + n_writes += (rv & MR_WRITE) >> MR_WRITE_SHIFT; + n_reads += (rv & MR_READ) >> MR_READ_SHIFT; + } + tmp = b->next; + + if (n_writes) { + if (what == resend) { + b->n_writes = n_writes; + if (b->w.cb == NULL) { + b->w.cb = w_send_barrier; + inc_ap_pending(mdev); + set_bit(CREATE_BARRIER, &mdev->flags); + } + + drbd_queue_work(&mdev->data.work, &b->w); + } + pn = &b->next; + } else { + if (n_reads) + list_add(&carry_reads, &b->requests); + /* there could still be requests on that ring list, + * in case local io is still pending */ + list_del(&b->requests); + + /* dec_ap_pending corresponding to queue_barrier. + * the newest barrier may not have been queued yet, + * in which case w.cb is still NULL. */ + if (b->w.cb != NULL) + dec_ap_pending(mdev); + + if (b == mdev->newest_tle) { + /* recycle, but reinit! */ + D_ASSERT(tmp == NULL); + INIT_LIST_HEAD(&b->requests); + list_splice(&carry_reads, &b->requests); + INIT_LIST_HEAD(&b->w.list); + b->w.cb = NULL; + b->br_number = net_random(); + b->n_writes = 0; + + *pn = b; + break; + } + *pn = tmp; + kfree(b); + } + b = tmp; + list_splice(&carry_reads, &b->requests); + } +} + /** * tl_clear() - Clears all requests and &struct drbd_tl_epoch objects out of the TL @@ -344,48 +422,12 @@ bail: */ void tl_clear(struct drbd_conf *mdev) { - struct drbd_tl_epoch *b, *tmp; struct list_head *le, *tle; struct drbd_request *r; - int new_initial_bnr = net_random(); spin_lock_irq(&mdev->req_lock); - b = mdev->oldest_tle; - while (b) { - list_for_each_safe(le, tle, &b->requests) { - r = list_entry(le, struct drbd_request, tl_requests); - /* It would be nice to complete outside of spinlock. - * But this is easier for now. */ - _req_mod(r, connection_lost_while_pending); - } - tmp = b->next; - - /* there could still be requests on that ring list, - * in case local io is still pending */ - list_del(&b->requests); - - /* dec_ap_pending corresponding to queue_barrier. - * the newest barrier may not have been queued yet, - * in which case w.cb is still NULL. */ - if (b->w.cb != NULL) - dec_ap_pending(mdev); - - if (b == mdev->newest_tle) { - /* recycle, but reinit! */ - D_ASSERT(tmp == NULL); - INIT_LIST_HEAD(&b->requests); - INIT_LIST_HEAD(&b->w.list); - b->w.cb = NULL; - b->br_number = new_initial_bnr; - b->n_req = 0; - - mdev->oldest_tle = b; - break; - } - kfree(b); - b = tmp; - } + _tl_restart(mdev, connection_lost_while_pending); /* we expect this list to be empty. */ D_ASSERT(list_empty(&mdev->out_of_sequence_requests)); @@ -401,6 +443,15 @@ void tl_clear(struct drbd_conf *mdev) /* ensure bit indicating barrier is required is clear */ clear_bit(CREATE_BARRIER, &mdev->flags); + memset(mdev->app_reads_hash, 0, APP_R_HSIZE*sizeof(void *)); + + spin_unlock_irq(&mdev->req_lock); +} + +void tl_restart(struct drbd_conf *mdev, enum drbd_req_event what) +{ + spin_lock_irq(&mdev->req_lock); + _tl_restart(mdev, what); spin_unlock_irq(&mdev->req_lock); } @@ -455,7 +506,7 @@ static int is_valid_state(struct drbd_conf *mdev, union drbd_state ns); static int is_valid_state_transition(struct drbd_conf *, union drbd_state, union drbd_state); static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state os, - union drbd_state ns, int *warn_sync_abort); + union drbd_state ns, const char **warn_sync_abort); int drbd_send_state_req(struct drbd_conf *, union drbd_state, union drbd_state); @@ -605,7 +656,7 @@ static void print_st(struct drbd_conf *mdev, char *name, union drbd_state ns) drbd_role_str(ns.peer), drbd_disk_str(ns.disk), drbd_disk_str(ns.pdsk), - ns.susp ? 's' : 'r', + is_susp(ns) ? 's' : 'r', ns.aftr_isp ? 'a' : '-', ns.peer_isp ? 'p' : '-', ns.user_isp ? 'u' : '-' @@ -763,7 +814,7 @@ static int is_valid_state_transition(struct drbd_conf *mdev, * to D_UNKNOWN. This rule and many more along those lines are in this function. */ static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state os, - union drbd_state ns, int *warn_sync_abort) + union drbd_state ns, const char **warn_sync_abort) { enum drbd_fencing_p fp; @@ -778,9 +829,10 @@ static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state os.conn <= C_DISCONNECTING) ns.conn = os.conn; - /* After a network error (+C_TEAR_DOWN) only C_UNCONNECTED or C_DISCONNECTING can follow */ + /* After a network error (+C_TEAR_DOWN) only C_UNCONNECTED or C_DISCONNECTING can follow. + * If you try to go into some Sync* state, that shall fail (elsewhere). */ if (os.conn >= C_TIMEOUT && os.conn <= C_TEAR_DOWN && - ns.conn != C_UNCONNECTED && ns.conn != C_DISCONNECTING) + ns.conn != C_UNCONNECTED && ns.conn != C_DISCONNECTING && ns.conn <= C_TEAR_DOWN) ns.conn = os.conn; /* After C_DISCONNECTING only C_STANDALONE may follow */ @@ -798,14 +850,13 @@ static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state if (ns.conn == C_STANDALONE && ns.disk == D_DISKLESS && ns.role == R_SECONDARY) ns.aftr_isp = 0; - if (ns.conn <= C_DISCONNECTING && ns.disk == D_DISKLESS) - ns.pdsk = D_UNKNOWN; - /* Abort resync if a disk fails/detaches */ if (os.conn > C_CONNECTED && ns.conn > C_CONNECTED && (ns.disk <= D_FAILED || ns.pdsk <= D_FAILED)) { if (warn_sync_abort) - *warn_sync_abort = 1; + *warn_sync_abort = + os.conn == C_VERIFY_S || os.conn == C_VERIFY_T ? + "Online-verify" : "Resync"; ns.conn = C_CONNECTED; } @@ -876,7 +927,12 @@ static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state if (fp == FP_STONITH && (ns.role == R_PRIMARY && ns.conn < C_CONNECTED && ns.pdsk > D_OUTDATED) && !(os.role == R_PRIMARY && os.conn < C_CONNECTED && os.pdsk > D_OUTDATED)) - ns.susp = 1; + ns.susp_fen = 1; /* Suspend IO while fence-peer handler runs (peer lost) */ + + if (mdev->sync_conf.on_no_data == OND_SUSPEND_IO && + (ns.role == R_PRIMARY && ns.disk < D_UP_TO_DATE && ns.pdsk < D_UP_TO_DATE) && + !(os.role == R_PRIMARY && os.disk < D_UP_TO_DATE && os.pdsk < D_UP_TO_DATE)) + ns.susp_nod = 1; /* Suspend IO while no data available (no accessible data available) */ if (ns.aftr_isp || ns.peer_isp || ns.user_isp) { if (ns.conn == C_SYNC_SOURCE) @@ -912,6 +968,12 @@ static void set_ov_position(struct drbd_conf *mdev, enum drbd_conns cs) } } +static void drbd_resume_al(struct drbd_conf *mdev) +{ + if (test_and_clear_bit(AL_SUSPENDED, &mdev->flags)) + dev_info(DEV, "Resumed AL updates\n"); +} + /** * __drbd_set_state() - Set a new DRBD state * @mdev: DRBD device. @@ -927,7 +989,7 @@ int __drbd_set_state(struct drbd_conf *mdev, { union drbd_state os; int rv = SS_SUCCESS; - int warn_sync_abort = 0; + const char *warn_sync_abort = NULL; struct after_state_chg_work *ascw; os = mdev->state; @@ -946,14 +1008,8 @@ int __drbd_set_state(struct drbd_conf *mdev, /* If the old state was illegal as well, then let this happen...*/ - if (is_valid_state(mdev, os) == rv) { - dev_err(DEV, "Considering state change from bad state. " - "Error would be: '%s'\n", - drbd_set_st_err_str(rv)); - print_st(mdev, "old", os); - print_st(mdev, "new", ns); + if (is_valid_state(mdev, os) == rv) rv = is_valid_state_transition(mdev, ns, os); - } } else rv = is_valid_state_transition(mdev, ns, os); } @@ -965,7 +1021,7 @@ int __drbd_set_state(struct drbd_conf *mdev, } if (warn_sync_abort) - dev_warn(DEV, "Resync aborted.\n"); + dev_warn(DEV, "%s aborted.\n", warn_sync_abort); { char *pbp, pb[300]; @@ -976,7 +1032,10 @@ int __drbd_set_state(struct drbd_conf *mdev, PSC(conn); PSC(disk); PSC(pdsk); - PSC(susp); + if (is_susp(ns) != is_susp(os)) + pbp += sprintf(pbp, "susp( %s -> %s ) ", + drbd_susp_str(is_susp(os)), + drbd_susp_str(is_susp(ns))); PSC(aftr_isp); PSC(peer_isp); PSC(user_isp); @@ -1001,12 +1060,6 @@ int __drbd_set_state(struct drbd_conf *mdev, wake_up(&mdev->misc_wait); wake_up(&mdev->state_wait); - /* post-state-change actions */ - if (os.conn >= C_SYNC_SOURCE && ns.conn <= C_CONNECTED) { - set_bit(STOP_SYNC_TIMER, &mdev->flags); - mod_timer(&mdev->resync_timer, jiffies); - } - /* aborted verify run. log the last position */ if ((os.conn == C_VERIFY_S || os.conn == C_VERIFY_T) && ns.conn < C_CONNECTED) { @@ -1019,41 +1072,42 @@ int __drbd_set_state(struct drbd_conf *mdev, if ((os.conn == C_PAUSED_SYNC_T || os.conn == C_PAUSED_SYNC_S) && (ns.conn == C_SYNC_TARGET || ns.conn == C_SYNC_SOURCE)) { dev_info(DEV, "Syncer continues.\n"); - mdev->rs_paused += (long)jiffies-(long)mdev->rs_mark_time; - if (ns.conn == C_SYNC_TARGET) { - if (!test_and_clear_bit(STOP_SYNC_TIMER, &mdev->flags)) - mod_timer(&mdev->resync_timer, jiffies); - /* This if (!test_bit) is only needed for the case - that a device that has ceased to used its timer, - i.e. it is already in drbd_resync_finished() gets - paused and resumed. */ - } + mdev->rs_paused += (long)jiffies + -(long)mdev->rs_mark_time[mdev->rs_last_mark]; + if (ns.conn == C_SYNC_TARGET) + mod_timer(&mdev->resync_timer, jiffies); } if ((os.conn == C_SYNC_TARGET || os.conn == C_SYNC_SOURCE) && (ns.conn == C_PAUSED_SYNC_T || ns.conn == C_PAUSED_SYNC_S)) { dev_info(DEV, "Resync suspended\n"); - mdev->rs_mark_time = jiffies; - if (ns.conn == C_PAUSED_SYNC_T) - set_bit(STOP_SYNC_TIMER, &mdev->flags); + mdev->rs_mark_time[mdev->rs_last_mark] = jiffies; } if (os.conn == C_CONNECTED && (ns.conn == C_VERIFY_S || ns.conn == C_VERIFY_T)) { + unsigned long now = jiffies; + int i; + mdev->ov_position = 0; - mdev->rs_total = - mdev->rs_mark_left = drbd_bm_bits(mdev); + mdev->rs_total = drbd_bm_bits(mdev); if (mdev->agreed_pro_version >= 90) set_ov_position(mdev, ns.conn); else mdev->ov_start_sector = 0; mdev->ov_left = mdev->rs_total - BM_SECT_TO_BIT(mdev->ov_position); - mdev->rs_start = - mdev->rs_mark_time = jiffies; + mdev->rs_start = now; + mdev->rs_last_events = 0; + mdev->rs_last_sect_ev = 0; mdev->ov_last_oos_size = 0; mdev->ov_last_oos_start = 0; + for (i = 0; i < DRBD_SYNC_MARKS; i++) { + mdev->rs_mark_left[i] = mdev->rs_total; + mdev->rs_mark_time[i] = now; + } + if (ns.conn == C_VERIFY_S) { dev_info(DEV, "Starting Online Verify from sector %llu\n", (unsigned long long)mdev->ov_position); @@ -1106,6 +1160,10 @@ int __drbd_set_state(struct drbd_conf *mdev, ns.conn <= C_TEAR_DOWN && ns.conn >= C_TIMEOUT) drbd_thread_restart_nowait(&mdev->receiver); + /* Resume AL writing if we get a connection */ + if (os.conn < C_CONNECTED && ns.conn >= C_CONNECTED) + drbd_resume_al(mdev); + ascw = kmalloc(sizeof(*ascw), GFP_ATOMIC); if (ascw) { ascw->os = os; @@ -1164,6 +1222,8 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, union drbd_state ns, enum chg_state_flags flags) { enum drbd_fencing_p fp; + enum drbd_req_event what = nothing; + union drbd_state nsm = (union drbd_state){ .i = -1 }; if (os.conn != C_CONNECTED && ns.conn == C_CONNECTED) { clear_bit(CRASHED_PRIMARY, &mdev->flags); @@ -1187,17 +1247,49 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, /* Here we have the actions that are performed after a state change. This function might sleep */ - if (fp == FP_STONITH && ns.susp) { - /* case1: The outdate peer handler is successful: - * case2: The connection was established again: */ - if ((os.pdsk > D_OUTDATED && ns.pdsk <= D_OUTDATED) || - (os.conn < C_CONNECTED && ns.conn >= C_CONNECTED)) { + nsm.i = -1; + if (ns.susp_nod) { + if (os.conn < C_CONNECTED && ns.conn >= C_CONNECTED) { + if (ns.conn == C_CONNECTED) + what = resend, nsm.susp_nod = 0; + else /* ns.conn > C_CONNECTED */ + dev_err(DEV, "Unexpected Resynd going on!\n"); + } + + if (os.disk == D_ATTACHING && ns.disk > D_ATTACHING) + what = restart_frozen_disk_io, nsm.susp_nod = 0; + + } + + if (ns.susp_fen) { + /* case1: The outdate peer handler is successful: */ + if (os.pdsk > D_OUTDATED && ns.pdsk <= D_OUTDATED) { tl_clear(mdev); + if (test_bit(NEW_CUR_UUID, &mdev->flags)) { + drbd_uuid_new_current(mdev); + clear_bit(NEW_CUR_UUID, &mdev->flags); + drbd_md_sync(mdev); + } spin_lock_irq(&mdev->req_lock); - _drbd_set_state(_NS(mdev, susp, 0), CS_VERBOSE, NULL); + _drbd_set_state(_NS(mdev, susp_fen, 0), CS_VERBOSE, NULL); spin_unlock_irq(&mdev->req_lock); } + /* case2: The connection was established again: */ + if (os.conn < C_CONNECTED && ns.conn >= C_CONNECTED) { + clear_bit(NEW_CUR_UUID, &mdev->flags); + what = resend; + nsm.susp_fen = 0; + } + } + + if (what != nothing) { + spin_lock_irq(&mdev->req_lock); + _tl_restart(mdev, what); + nsm.i &= mdev->state.i; + _drbd_set_state(mdev, nsm, CS_VERBOSE, NULL); + spin_unlock_irq(&mdev->req_lock); } + /* Do not change the order of the if above and the two below... */ if (os.pdsk == D_DISKLESS && ns.pdsk > D_DISKLESS) { /* attach on the peer */ drbd_send_uuids(mdev); @@ -1216,16 +1308,22 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, if (get_ldev(mdev)) { if ((ns.role == R_PRIMARY || ns.peer == R_PRIMARY) && mdev->ldev->md.uuid[UI_BITMAP] == 0 && ns.disk >= D_UP_TO_DATE) { - drbd_uuid_new_current(mdev); - drbd_send_uuids(mdev); + if (is_susp(mdev->state)) { + set_bit(NEW_CUR_UUID, &mdev->flags); + } else { + drbd_uuid_new_current(mdev); + drbd_send_uuids(mdev); + } } put_ldev(mdev); } } if (ns.pdsk < D_INCONSISTENT && get_ldev(mdev)) { - if (ns.peer == R_PRIMARY && mdev->ldev->md.uuid[UI_BITMAP] == 0) + if (ns.peer == R_PRIMARY && mdev->ldev->md.uuid[UI_BITMAP] == 0) { drbd_uuid_new_current(mdev); + drbd_send_uuids(mdev); + } /* D_DISKLESS Peer becomes secondary */ if (os.peer == R_PRIMARY && ns.peer == R_SECONDARY) @@ -1267,42 +1365,51 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, os.disk > D_INCONSISTENT && ns.disk == D_INCONSISTENT) drbd_queue_bitmap_io(mdev, &drbd_bmio_set_n_write, NULL, "set_n_write from invalidate"); + /* first half of local IO error */ if (os.disk > D_FAILED && ns.disk == D_FAILED) { - enum drbd_io_error_p eh; + enum drbd_io_error_p eh = EP_PASS_ON; + + if (drbd_send_state(mdev)) + dev_warn(DEV, "Notified peer that my disk is broken.\n"); + else + dev_err(DEV, "Sending state for drbd_io_error() failed\n"); + + drbd_rs_cancel_all(mdev); - eh = EP_PASS_ON; if (get_ldev_if_state(mdev, D_FAILED)) { eh = mdev->ldev->dc.on_io_error; put_ldev(mdev); } + if (eh == EP_CALL_HELPER) + drbd_khelper(mdev, "local-io-error"); + } - drbd_rs_cancel_all(mdev); - /* since get_ldev() only works as long as disk>=D_INCONSISTENT, - and it is D_DISKLESS here, local_cnt can only go down, it can - not increase... It will reach zero */ - wait_event(mdev->misc_wait, !atomic_read(&mdev->local_cnt)); + + /* second half of local IO error handling, + * after local_cnt references have reached zero: */ + if (os.disk == D_FAILED && ns.disk == D_DISKLESS) { mdev->rs_total = 0; mdev->rs_failed = 0; atomic_set(&mdev->rs_pending_cnt, 0); - - spin_lock_irq(&mdev->req_lock); - _drbd_set_state(_NS(mdev, disk, D_DISKLESS), CS_HARD, NULL); - spin_unlock_irq(&mdev->req_lock); - - if (eh == EP_CALL_HELPER) - drbd_khelper(mdev, "local-io-error"); } if (os.disk > D_DISKLESS && ns.disk == D_DISKLESS) { + /* We must still be diskless, + * re-attach has to be serialized with this! */ + if (mdev->state.disk != D_DISKLESS) + dev_err(DEV, + "ASSERT FAILED: disk is %s while going diskless\n", + drbd_disk_str(mdev->state.disk)); + + /* we cannot assert local_cnt == 0 here, as get_ldev_if_state + * will inc/dec it frequently. Since we became D_DISKLESS, no + * one has touched the protected members anymore, though, so we + * are safe to free them here. */ + if (drbd_send_state(mdev)) + dev_warn(DEV, "Notified peer that I detached my disk.\n"); + else + dev_err(DEV, "Sending state for detach failed\n"); - if (os.disk == D_FAILED) /* && ns.disk == D_DISKLESS*/ { - if (drbd_send_state(mdev)) - dev_warn(DEV, "Notified peer that my disk is broken.\n"); - else - dev_err(DEV, "Sending state in drbd_io_error() failed\n"); - } - - wait_event(mdev->misc_wait, !atomic_read(&mdev->local_cnt)); lc_destroy(mdev->resync); mdev->resync = NULL; lc_destroy(mdev->act_log); @@ -1311,8 +1418,10 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, drbd_free_bc(mdev->ldev); mdev->ldev = NULL;); - if (mdev->md_io_tmpp) + if (mdev->md_io_tmpp) { __free_page(mdev->md_io_tmpp); + mdev->md_io_tmpp = NULL; + } } /* Disks got bigger while they were detached */ @@ -1328,6 +1437,15 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, (os.user_isp && !ns.user_isp)) resume_next_sg(mdev); + /* sync target done with resync. Explicitly notify peer, even though + * it should (at least for non-empty resyncs) already know itself. */ + if (os.disk < D_UP_TO_DATE && os.conn >= C_SYNC_SOURCE && ns.conn == C_CONNECTED) + drbd_send_state(mdev); + + /* free tl_hash if we Got thawed and are C_STANDALONE */ + if (ns.conn == C_STANDALONE && !is_susp(ns) && mdev->tl_hash) + drbd_free_tl_hash(mdev); + /* Upon network connection, we need to start the receiver */ if (os.conn == C_STANDALONE && ns.conn == C_UNCONNECTED) drbd_thread_start(&mdev->receiver); @@ -1554,7 +1672,7 @@ void drbd_thread_current_set_cpu(struct drbd_conf *mdev) /* the appropriate socket mutex must be held already */ int _drbd_send_cmd(struct drbd_conf *mdev, struct socket *sock, - enum drbd_packets cmd, struct p_header *h, + enum drbd_packets cmd, struct p_header80 *h, size_t size, unsigned msg_flags) { int sent, ok; @@ -1564,7 +1682,7 @@ int _drbd_send_cmd(struct drbd_conf *mdev, struct socket *sock, h->magic = BE_DRBD_MAGIC; h->command = cpu_to_be16(cmd); - h->length = cpu_to_be16(size-sizeof(struct p_header)); + h->length = cpu_to_be16(size-sizeof(struct p_header80)); sent = drbd_send(mdev, sock, h, size, msg_flags); @@ -1579,7 +1697,7 @@ int _drbd_send_cmd(struct drbd_conf *mdev, struct socket *sock, * when we hold the appropriate socket mutex. */ int drbd_send_cmd(struct drbd_conf *mdev, int use_data_socket, - enum drbd_packets cmd, struct p_header *h, size_t size) + enum drbd_packets cmd, struct p_header80 *h, size_t size) { int ok = 0; struct socket *sock; @@ -1607,7 +1725,7 @@ int drbd_send_cmd(struct drbd_conf *mdev, int use_data_socket, int drbd_send_cmd2(struct drbd_conf *mdev, enum drbd_packets cmd, char *data, size_t size) { - struct p_header h; + struct p_header80 h; int ok; h.magic = BE_DRBD_MAGIC; @@ -1629,7 +1747,7 @@ int drbd_send_cmd2(struct drbd_conf *mdev, enum drbd_packets cmd, char *data, int drbd_send_sync_param(struct drbd_conf *mdev, struct syncer_conf *sc) { - struct p_rs_param_89 *p; + struct p_rs_param_95 *p; struct socket *sock; int size, rv; const int apv = mdev->agreed_pro_version; @@ -1637,7 +1755,8 @@ int drbd_send_sync_param(struct drbd_conf *mdev, struct syncer_conf *sc) size = apv <= 87 ? sizeof(struct p_rs_param) : apv == 88 ? sizeof(struct p_rs_param) + strlen(mdev->sync_conf.verify_alg) + 1 - : /* 89 */ sizeof(struct p_rs_param_89); + : apv <= 94 ? sizeof(struct p_rs_param_89) + : /* apv >= 95 */ sizeof(struct p_rs_param_95); /* used from admin command context and receiver/worker context. * to avoid kmalloc, grab the socket right here, @@ -1648,12 +1767,16 @@ int drbd_send_sync_param(struct drbd_conf *mdev, struct syncer_conf *sc) if (likely(sock != NULL)) { enum drbd_packets cmd = apv >= 89 ? P_SYNC_PARAM89 : P_SYNC_PARAM; - p = &mdev->data.sbuf.rs_param_89; + p = &mdev->data.sbuf.rs_param_95; /* initialize verify_alg and csums_alg */ memset(p->verify_alg, 0, 2 * SHARED_SECRET_MAX); p->rate = cpu_to_be32(sc->rate); + p->c_plan_ahead = cpu_to_be32(sc->c_plan_ahead); + p->c_delay_target = cpu_to_be32(sc->c_delay_target); + p->c_fill_target = cpu_to_be32(sc->c_fill_target); + p->c_max_rate = cpu_to_be32(sc->c_max_rate); if (apv >= 88) strcpy(p->verify_alg, mdev->sync_conf.verify_alg); @@ -1709,7 +1832,7 @@ int drbd_send_protocol(struct drbd_conf *mdev) strcpy(p->integrity_alg, mdev->net_conf->integrity_alg); rv = drbd_send_cmd(mdev, USE_DATA_SOCKET, P_PROTOCOL, - (struct p_header *)p, size); + (struct p_header80 *)p, size); kfree(p); return rv; } @@ -1735,7 +1858,7 @@ int _drbd_send_uuids(struct drbd_conf *mdev, u64 uuid_flags) put_ldev(mdev); return drbd_send_cmd(mdev, USE_DATA_SOCKET, P_UUIDS, - (struct p_header *)&p, sizeof(p)); + (struct p_header80 *)&p, sizeof(p)); } int drbd_send_uuids(struct drbd_conf *mdev) @@ -1756,7 +1879,7 @@ int drbd_send_sync_uuid(struct drbd_conf *mdev, u64 val) p.uuid = cpu_to_be64(val); return drbd_send_cmd(mdev, USE_DATA_SOCKET, P_SYNC_UUID, - (struct p_header *)&p, sizeof(p)); + (struct p_header80 *)&p, sizeof(p)); } int drbd_send_sizes(struct drbd_conf *mdev, int trigger_reply, enum dds_flags flags) @@ -1786,7 +1909,7 @@ int drbd_send_sizes(struct drbd_conf *mdev, int trigger_reply, enum dds_flags fl p.dds_flags = cpu_to_be16(flags); ok = drbd_send_cmd(mdev, USE_DATA_SOCKET, P_SIZES, - (struct p_header *)&p, sizeof(p)); + (struct p_header80 *)&p, sizeof(p)); return ok; } @@ -1811,7 +1934,7 @@ int drbd_send_state(struct drbd_conf *mdev) if (likely(sock != NULL)) { ok = _drbd_send_cmd(mdev, sock, P_STATE, - (struct p_header *)&p, sizeof(p), 0); + (struct p_header80 *)&p, sizeof(p), 0); } mutex_unlock(&mdev->data.mutex); @@ -1829,7 +1952,7 @@ int drbd_send_state_req(struct drbd_conf *mdev, p.val = cpu_to_be32(val.i); return drbd_send_cmd(mdev, USE_DATA_SOCKET, P_STATE_CHG_REQ, - (struct p_header *)&p, sizeof(p)); + (struct p_header80 *)&p, sizeof(p)); } int drbd_send_sr_reply(struct drbd_conf *mdev, int retcode) @@ -1839,7 +1962,7 @@ int drbd_send_sr_reply(struct drbd_conf *mdev, int retcode) p.retcode = cpu_to_be32(retcode); return drbd_send_cmd(mdev, USE_META_SOCKET, P_STATE_CHG_REPLY, - (struct p_header *)&p, sizeof(p)); + (struct p_header80 *)&p, sizeof(p)); } int fill_bitmap_rle_bits(struct drbd_conf *mdev, @@ -1938,7 +2061,7 @@ int fill_bitmap_rle_bits(struct drbd_conf *mdev, enum { OK, FAILED, DONE } send_bitmap_rle_or_plain(struct drbd_conf *mdev, - struct p_header *h, struct bm_xfer_ctx *c) + struct p_header80 *h, struct bm_xfer_ctx *c) { struct p_compressed_bm *p = (void*)h; unsigned long num_words; @@ -1968,12 +2091,12 @@ send_bitmap_rle_or_plain(struct drbd_conf *mdev, if (len) drbd_bm_get_lel(mdev, c->word_offset, num_words, (unsigned long*)h->payload); ok = _drbd_send_cmd(mdev, mdev->data.socket, P_BITMAP, - h, sizeof(struct p_header) + len, 0); + h, sizeof(struct p_header80) + len, 0); c->word_offset += num_words; c->bit_offset = c->word_offset * BITS_PER_LONG; c->packets[1]++; - c->bytes[1] += sizeof(struct p_header) + len; + c->bytes[1] += sizeof(struct p_header80) + len; if (c->bit_offset > c->bm_bits) c->bit_offset = c->bm_bits; @@ -1989,14 +2112,14 @@ send_bitmap_rle_or_plain(struct drbd_conf *mdev, int _drbd_send_bitmap(struct drbd_conf *mdev) { struct bm_xfer_ctx c; - struct p_header *p; + struct p_header80 *p; int ret; ERR_IF(!mdev->bitmap) return FALSE; /* maybe we should use some per thread scratch page, * and allocate that during initial device creation? */ - p = (struct p_header *) __get_free_page(GFP_NOIO); + p = (struct p_header80 *) __get_free_page(GFP_NOIO); if (!p) { dev_err(DEV, "failed to allocate one page buffer in %s\n", __func__); return FALSE; @@ -2054,7 +2177,7 @@ int drbd_send_b_ack(struct drbd_conf *mdev, u32 barrier_nr, u32 set_size) if (mdev->state.conn < C_CONNECTED) return FALSE; ok = drbd_send_cmd(mdev, USE_META_SOCKET, P_BARRIER_ACK, - (struct p_header *)&p, sizeof(p)); + (struct p_header80 *)&p, sizeof(p)); return ok; } @@ -2082,17 +2205,18 @@ static int _drbd_send_ack(struct drbd_conf *mdev, enum drbd_packets cmd, if (!mdev->meta.socket || mdev->state.conn < C_CONNECTED) return FALSE; ok = drbd_send_cmd(mdev, USE_META_SOCKET, cmd, - (struct p_header *)&p, sizeof(p)); + (struct p_header80 *)&p, sizeof(p)); return ok; } +/* dp->sector and dp->block_id already/still in network byte order, + * data_size is payload size according to dp->head, + * and may need to be corrected for digest size. */ int drbd_send_ack_dp(struct drbd_conf *mdev, enum drbd_packets cmd, - struct p_data *dp) + struct p_data *dp, int data_size) { - const int header_size = sizeof(struct p_data) - - sizeof(struct p_header); - int data_size = ((struct p_header *)dp)->length - header_size; - + data_size -= (mdev->agreed_pro_version >= 87 && mdev->integrity_r_tfm) ? + crypto_hash_digestsize(mdev->integrity_r_tfm) : 0; return _drbd_send_ack(mdev, cmd, dp->sector, cpu_to_be32(data_size), dp->block_id); } @@ -2140,7 +2264,7 @@ int drbd_send_drequest(struct drbd_conf *mdev, int cmd, p.blksize = cpu_to_be32(size); ok = drbd_send_cmd(mdev, USE_DATA_SOCKET, cmd, - (struct p_header *)&p, sizeof(p)); + (struct p_header80 *)&p, sizeof(p)); return ok; } @@ -2158,7 +2282,7 @@ int drbd_send_drequest_csum(struct drbd_conf *mdev, p.head.magic = BE_DRBD_MAGIC; p.head.command = cpu_to_be16(cmd); - p.head.length = cpu_to_be16(sizeof(p) - sizeof(struct p_header) + digest_size); + p.head.length = cpu_to_be16(sizeof(p) - sizeof(struct p_header80) + digest_size); mutex_lock(&mdev->data.mutex); @@ -2180,7 +2304,7 @@ int drbd_send_ov_request(struct drbd_conf *mdev, sector_t sector, int size) p.blksize = cpu_to_be32(size); ok = drbd_send_cmd(mdev, USE_DATA_SOCKET, P_OV_REQUEST, - (struct p_header *)&p, sizeof(p)); + (struct p_header80 *)&p, sizeof(p)); return ok; } @@ -2332,6 +2456,18 @@ static int _drbd_send_zc_ee(struct drbd_conf *mdev, struct drbd_epoch_entry *e) return 1; } +static u32 bio_flags_to_wire(struct drbd_conf *mdev, unsigned long bi_rw) +{ + if (mdev->agreed_pro_version >= 95) + return (bi_rw & REQ_SYNC ? DP_RW_SYNC : 0) | + (bi_rw & REQ_UNPLUG ? DP_UNPLUG : 0) | + (bi_rw & REQ_FUA ? DP_FUA : 0) | + (bi_rw & REQ_FLUSH ? DP_FLUSH : 0) | + (bi_rw & REQ_DISCARD ? DP_DISCARD : 0); + else + return bi_rw & (REQ_SYNC | REQ_UNPLUG) ? DP_RW_SYNC : 0; +} + /* Used to send write requests * R_PRIMARY -> Peer (P_DATA) */ @@ -2349,30 +2485,25 @@ int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req) dgs = (mdev->agreed_pro_version >= 87 && mdev->integrity_w_tfm) ? crypto_hash_digestsize(mdev->integrity_w_tfm) : 0; - p.head.magic = BE_DRBD_MAGIC; - p.head.command = cpu_to_be16(P_DATA); - p.head.length = - cpu_to_be16(sizeof(p) - sizeof(struct p_header) + dgs + req->size); + if (req->size <= DRBD_MAX_SIZE_H80_PACKET) { + p.head.h80.magic = BE_DRBD_MAGIC; + p.head.h80.command = cpu_to_be16(P_DATA); + p.head.h80.length = + cpu_to_be16(sizeof(p) - sizeof(union p_header) + dgs + req->size); + } else { + p.head.h95.magic = BE_DRBD_MAGIC_BIG; + p.head.h95.command = cpu_to_be16(P_DATA); + p.head.h95.length = + cpu_to_be32(sizeof(p) - sizeof(union p_header) + dgs + req->size); + } p.sector = cpu_to_be64(req->sector); p.block_id = (unsigned long)req; p.seq_num = cpu_to_be32(req->seq_num = atomic_add_return(1, &mdev->packet_seq)); - dp_flags = 0; - /* NOTE: no need to check if barriers supported here as we would - * not pass the test in make_request_common in that case - */ - if (req->master_bio->bi_rw & REQ_HARDBARRIER) { - dev_err(DEV, "ASSERT FAILED would have set DP_HARDBARRIER\n"); - /* dp_flags |= DP_HARDBARRIER; */ - } - if (req->master_bio->bi_rw & REQ_SYNC) - dp_flags |= DP_RW_SYNC; - /* for now handle SYNCIO and UNPLUG - * as if they still were one and the same flag */ - if (req->master_bio->bi_rw & REQ_UNPLUG) - dp_flags |= DP_RW_SYNC; + dp_flags = bio_flags_to_wire(mdev, req->master_bio->bi_rw); + if (mdev->state.conn >= C_SYNC_SOURCE && mdev->state.conn <= C_PAUSED_SYNC_T) dp_flags |= DP_MAY_SET_IN_SYNC; @@ -2413,10 +2544,17 @@ int drbd_send_block(struct drbd_conf *mdev, enum drbd_packets cmd, dgs = (mdev->agreed_pro_version >= 87 && mdev->integrity_w_tfm) ? crypto_hash_digestsize(mdev->integrity_w_tfm) : 0; - p.head.magic = BE_DRBD_MAGIC; - p.head.command = cpu_to_be16(cmd); - p.head.length = - cpu_to_be16(sizeof(p) - sizeof(struct p_header) + dgs + e->size); + if (e->size <= DRBD_MAX_SIZE_H80_PACKET) { + p.head.h80.magic = BE_DRBD_MAGIC; + p.head.h80.command = cpu_to_be16(cmd); + p.head.h80.length = + cpu_to_be16(sizeof(p) - sizeof(struct p_header80) + dgs + e->size); + } else { + p.head.h95.magic = BE_DRBD_MAGIC_BIG; + p.head.h95.command = cpu_to_be16(cmd); + p.head.h95.length = + cpu_to_be32(sizeof(p) - sizeof(struct p_header80) + dgs + e->size); + } p.sector = cpu_to_be64(e->sector); p.block_id = e->block_id; @@ -2429,8 +2567,7 @@ int drbd_send_block(struct drbd_conf *mdev, enum drbd_packets cmd, if (!drbd_get_data_sock(mdev)) return 0; - ok = sizeof(p) == drbd_send(mdev, mdev->data.socket, &p, - sizeof(p), dgs ? MSG_MORE : 0); + ok = sizeof(p) == drbd_send(mdev, mdev->data.socket, &p, sizeof(p), dgs ? MSG_MORE : 0); if (ok && dgs) { dgb = mdev->int_dig_out; drbd_csum_ee(mdev, mdev->integrity_w_tfm, e, dgb); @@ -2536,7 +2673,7 @@ static int drbd_open(struct block_device *bdev, fmode_t mode) unsigned long flags; int rv = 0; - lock_kernel(); + mutex_lock(&drbd_main_mutex); spin_lock_irqsave(&mdev->req_lock, flags); /* to have a stable mdev->state.role * and no race with updating open_cnt */ @@ -2551,7 +2688,7 @@ static int drbd_open(struct block_device *bdev, fmode_t mode) if (!rv) mdev->open_cnt++; spin_unlock_irqrestore(&mdev->req_lock, flags); - unlock_kernel(); + mutex_unlock(&drbd_main_mutex); return rv; } @@ -2559,9 +2696,9 @@ static int drbd_open(struct block_device *bdev, fmode_t mode) static int drbd_release(struct gendisk *gd, fmode_t mode) { struct drbd_conf *mdev = gd->private_data; - lock_kernel(); + mutex_lock(&drbd_main_mutex); mdev->open_cnt--; - unlock_kernel(); + mutex_unlock(&drbd_main_mutex); return 0; } @@ -2605,7 +2742,13 @@ static void drbd_set_defaults(struct drbd_conf *mdev) /* .verify_alg = */ {}, 0, /* .cpu_mask = */ {}, 0, /* .csums_alg = */ {}, 0, - /* .use_rle = */ 0 + /* .use_rle = */ 0, + /* .on_no_data = */ DRBD_ON_NO_DATA_DEF, + /* .c_plan_ahead = */ DRBD_C_PLAN_AHEAD_DEF, + /* .c_delay_target = */ DRBD_C_DELAY_TARGET_DEF, + /* .c_fill_target = */ DRBD_C_FILL_TARGET_DEF, + /* .c_max_rate = */ DRBD_C_MAX_RATE_DEF, + /* .c_min_rate = */ DRBD_C_MIN_RATE_DEF }; /* Have to use that way, because the layout differs between @@ -2616,7 +2759,9 @@ static void drbd_set_defaults(struct drbd_conf *mdev) .conn = C_STANDALONE, .disk = D_DISKLESS, .pdsk = D_UNKNOWN, - .susp = 0 + .susp = 0, + .susp_nod = 0, + .susp_fen = 0 } }; } @@ -2640,6 +2785,9 @@ void drbd_init_set_defaults(struct drbd_conf *mdev) atomic_set(&mdev->net_cnt, 0); atomic_set(&mdev->packet_seq, 0); atomic_set(&mdev->pp_in_use, 0); + atomic_set(&mdev->pp_in_use_by_net, 0); + atomic_set(&mdev->rs_sect_in, 0); + atomic_set(&mdev->rs_sect_ev, 0); mutex_init(&mdev->md_io_mutex); mutex_init(&mdev->data.mutex); @@ -2666,11 +2814,13 @@ void drbd_init_set_defaults(struct drbd_conf *mdev) INIT_LIST_HEAD(&mdev->meta.work.q); INIT_LIST_HEAD(&mdev->resync_work.list); INIT_LIST_HEAD(&mdev->unplug_work.list); + INIT_LIST_HEAD(&mdev->go_diskless.list); INIT_LIST_HEAD(&mdev->md_sync_work.list); INIT_LIST_HEAD(&mdev->bm_io_work.w.list); mdev->resync_work.cb = w_resync_inactive; mdev->unplug_work.cb = w_send_write_hint; + mdev->go_diskless.cb = w_go_diskless; mdev->md_sync_work.cb = w_md_sync; mdev->bm_io_work.w.cb = w_bitmap_io; init_timer(&mdev->resync_timer); @@ -2682,6 +2832,7 @@ void drbd_init_set_defaults(struct drbd_conf *mdev) init_waitqueue_head(&mdev->misc_wait); init_waitqueue_head(&mdev->state_wait); + init_waitqueue_head(&mdev->net_cnt_wait); init_waitqueue_head(&mdev->ee_wait); init_waitqueue_head(&mdev->al_wait); init_waitqueue_head(&mdev->seq_wait); @@ -2697,6 +2848,7 @@ void drbd_init_set_defaults(struct drbd_conf *mdev) void drbd_mdev_cleanup(struct drbd_conf *mdev) { + int i; if (mdev->receiver.t_state != None) dev_err(DEV, "ASSERT FAILED: receiver t_state == %d expected 0.\n", mdev->receiver.t_state); @@ -2713,9 +2865,13 @@ void drbd_mdev_cleanup(struct drbd_conf *mdev) mdev->p_size = mdev->rs_start = mdev->rs_total = - mdev->rs_failed = - mdev->rs_mark_left = - mdev->rs_mark_time = 0; + mdev->rs_failed = 0; + mdev->rs_last_events = 0; + mdev->rs_last_sect_ev = 0; + for (i = 0; i < DRBD_SYNC_MARKS; i++) { + mdev->rs_mark_left[i] = 0; + mdev->rs_mark_time[i] = 0; + } D_ASSERT(mdev->net_conf == NULL); drbd_set_my_capacity(mdev, 0); @@ -2726,6 +2882,7 @@ void drbd_mdev_cleanup(struct drbd_conf *mdev) } drbd_free_resources(mdev); + clear_bit(AL_SUSPENDED, &mdev->flags); /* * currently we drbd_init_ee only on module load, so @@ -2741,6 +2898,7 @@ void drbd_mdev_cleanup(struct drbd_conf *mdev) D_ASSERT(list_empty(&mdev->meta.work.q)); D_ASSERT(list_empty(&mdev->resync_work.list)); D_ASSERT(list_empty(&mdev->unplug_work.list)); + D_ASSERT(list_empty(&mdev->go_diskless.list)); } @@ -3280,9 +3438,10 @@ void drbd_md_sync(struct drbd_conf *mdev) sector_t sector; int i; + del_timer(&mdev->md_sync_timer); + /* timer may be rearmed by drbd_md_mark_dirty() now. */ if (!test_and_clear_bit(MD_DIRTY, &mdev->flags)) return; - del_timer(&mdev->md_sync_timer); /* We use here D_FAILED and not D_ATTACHING because we try to write * metadata even if we detach due to a disk failure! */ @@ -3310,12 +3469,9 @@ void drbd_md_sync(struct drbd_conf *mdev) D_ASSERT(drbd_md_ss__(mdev, mdev->ldev) == mdev->ldev->md.md_offset); sector = mdev->ldev->md.md_offset; - if (drbd_md_sync_page_io(mdev, mdev->ldev, sector, WRITE)) { - clear_bit(MD_DIRTY, &mdev->flags); - } else { + if (!drbd_md_sync_page_io(mdev, mdev->ldev, sector, WRITE)) { /* this was a try anyways ... */ dev_err(DEV, "meta data update failed!\n"); - drbd_chk_io_error(mdev, 1, TRUE); } @@ -3402,6 +3558,28 @@ int drbd_md_read(struct drbd_conf *mdev, struct drbd_backing_dev *bdev) return rv; } +static void debug_drbd_uuid(struct drbd_conf *mdev, enum drbd_uuid_index index) +{ + static char *uuid_str[UI_EXTENDED_SIZE] = { + [UI_CURRENT] = "CURRENT", + [UI_BITMAP] = "BITMAP", + [UI_HISTORY_START] = "HISTORY_START", + [UI_HISTORY_END] = "HISTORY_END", + [UI_SIZE] = "SIZE", + [UI_FLAGS] = "FLAGS", + }; + + if (index >= UI_EXTENDED_SIZE) { + dev_warn(DEV, " uuid_index >= EXTENDED_SIZE\n"); + return; + } + + dynamic_dev_dbg(DEV, " uuid[%s] now %016llX\n", + uuid_str[index], + (unsigned long long)mdev->ldev->md.uuid[index]); +} + + /** * drbd_md_mark_dirty() - Mark meta data super block as dirty * @mdev: DRBD device. @@ -3410,19 +3588,31 @@ int drbd_md_read(struct drbd_conf *mdev, struct drbd_backing_dev *bdev) * the meta-data super block. This function sets MD_DIRTY, and starts a * timer that ensures that within five seconds you have to call drbd_md_sync(). */ +#ifdef DEBUG +void drbd_md_mark_dirty_(struct drbd_conf *mdev, unsigned int line, const char *func) +{ + if (!test_and_set_bit(MD_DIRTY, &mdev->flags)) { + mod_timer(&mdev->md_sync_timer, jiffies + HZ); + mdev->last_md_mark_dirty.line = line; + mdev->last_md_mark_dirty.func = func; + } +} +#else void drbd_md_mark_dirty(struct drbd_conf *mdev) { - set_bit(MD_DIRTY, &mdev->flags); - mod_timer(&mdev->md_sync_timer, jiffies + 5*HZ); + if (!test_and_set_bit(MD_DIRTY, &mdev->flags)) + mod_timer(&mdev->md_sync_timer, jiffies + 5*HZ); } - +#endif static void drbd_uuid_move_history(struct drbd_conf *mdev) __must_hold(local) { int i; - for (i = UI_HISTORY_START; i < UI_HISTORY_END; i++) + for (i = UI_HISTORY_START; i < UI_HISTORY_END; i++) { mdev->ldev->md.uuid[i+1] = mdev->ldev->md.uuid[i]; + debug_drbd_uuid(mdev, i+1); + } } void _drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local) @@ -3437,6 +3627,7 @@ void _drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local) } mdev->ldev->md.uuid[idx] = val; + debug_drbd_uuid(mdev, idx); drbd_md_mark_dirty(mdev); } @@ -3446,6 +3637,7 @@ void drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local) if (mdev->ldev->md.uuid[idx]) { drbd_uuid_move_history(mdev); mdev->ldev->md.uuid[UI_HISTORY_START] = mdev->ldev->md.uuid[idx]; + debug_drbd_uuid(mdev, UI_HISTORY_START); } _drbd_uuid_set(mdev, idx, val); } @@ -3464,6 +3656,7 @@ void drbd_uuid_new_current(struct drbd_conf *mdev) __must_hold(local) dev_info(DEV, "Creating new current UUID\n"); D_ASSERT(mdev->ldev->md.uuid[UI_BITMAP] == 0); mdev->ldev->md.uuid[UI_BITMAP] = mdev->ldev->md.uuid[UI_CURRENT]; + debug_drbd_uuid(mdev, UI_BITMAP); get_random_bytes(&val, sizeof(u64)); _drbd_uuid_set(mdev, UI_CURRENT, val); @@ -3478,6 +3671,8 @@ void drbd_uuid_set_bm(struct drbd_conf *mdev, u64 val) __must_hold(local) drbd_uuid_move_history(mdev); mdev->ldev->md.uuid[UI_HISTORY_START] = mdev->ldev->md.uuid[UI_BITMAP]; mdev->ldev->md.uuid[UI_BITMAP] = 0; + debug_drbd_uuid(mdev, UI_HISTORY_START); + debug_drbd_uuid(mdev, UI_BITMAP); } else { if (mdev->ldev->md.uuid[UI_BITMAP]) dev_warn(DEV, "bm UUID already set"); @@ -3485,6 +3680,7 @@ void drbd_uuid_set_bm(struct drbd_conf *mdev, u64 val) __must_hold(local) mdev->ldev->md.uuid[UI_BITMAP] = val; mdev->ldev->md.uuid[UI_BITMAP] &= ~((u64)1); + debug_drbd_uuid(mdev, UI_BITMAP); } drbd_md_mark_dirty(mdev); } @@ -3527,6 +3723,7 @@ int drbd_bmio_clear_n_write(struct drbd_conf *mdev) { int rv = -EIO; + drbd_resume_al(mdev); if (get_ldev_if_state(mdev, D_ATTACHING)) { drbd_bm_clear_all(mdev); rv = drbd_bm_write(mdev); @@ -3559,6 +3756,32 @@ static int w_bitmap_io(struct drbd_conf *mdev, struct drbd_work *w, int unused) return 1; } +static int w_go_diskless(struct drbd_conf *mdev, struct drbd_work *w, int unused) +{ + D_ASSERT(mdev->state.disk == D_FAILED); + /* we cannot assert local_cnt == 0 here, as get_ldev_if_state will + * inc/dec it frequently. Once we are D_DISKLESS, no one will touch + * the protected members anymore, though, so in the after_state_ch work + * it will be safe to free them. */ + drbd_force_state(mdev, NS(disk, D_DISKLESS)); + /* We need to wait for return of references checked out while we still + * have been D_FAILED, though (drbd_md_sync, bitmap io). */ + wait_event(mdev->misc_wait, !atomic_read(&mdev->local_cnt)); + + clear_bit(GO_DISKLESS, &mdev->flags); + return 1; +} + +void drbd_go_diskless(struct drbd_conf *mdev) +{ + D_ASSERT(mdev->state.disk == D_FAILED); + if (!test_and_set_bit(GO_DISKLESS, &mdev->flags)) + drbd_queue_work(&mdev->data.work, &mdev->go_diskless); + /* don't drbd_queue_work_front, + * we need to serialize with the after_state_ch work + * of the -> D_FAILED transition. */ +} + /** * drbd_queue_bitmap_io() - Queues an IO operation on the whole bitmap * @mdev: DRBD device. @@ -3655,8 +3878,11 @@ static void md_sync_timer_fn(unsigned long data) static int w_md_sync(struct drbd_conf *mdev, struct drbd_work *w, int unused) { dev_warn(DEV, "md_sync_timer expired! Worker calls drbd_md_sync().\n"); +#ifdef DEBUG + dev_warn(DEV, "last md_mark_dirty: %s:%u\n", + mdev->last_md_mark_dirty.func, mdev->last_md_mark_dirty.line); +#endif drbd_md_sync(mdev); - return 1; } diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index 73131c5ae339..87925e97e613 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -33,10 +33,13 @@ #include <linux/blkpg.h> #include <linux/cpumask.h> #include "drbd_int.h" +#include "drbd_req.h" #include "drbd_wrappers.h" #include <asm/unaligned.h> #include <linux/drbd_tag_magic.h> #include <linux/drbd_limits.h> +#include <linux/compiler.h> +#include <linux/kthread.h> static unsigned short *tl_add_blob(unsigned short *, enum drbd_tags, const void *, int); static unsigned short *tl_add_str(unsigned short *, enum drbd_tags, const char *); @@ -169,6 +172,10 @@ int drbd_khelper(struct drbd_conf *mdev, char *cmd) put_net_conf(mdev); } + /* The helper may take some time. + * write out any unsynced meta data changes now */ + drbd_md_sync(mdev); + dev_info(DEV, "helper command: %s %s %s\n", usermode_helper, cmd, mb); drbd_bcast_ev_helper(mdev, cmd); @@ -202,12 +209,10 @@ enum drbd_disk_state drbd_try_outdate_peer(struct drbd_conf *mdev) put_ldev(mdev); } else { dev_warn(DEV, "Not fencing peer, I'm not even Consistent myself.\n"); - return mdev->state.pdsk; + nps = mdev->state.pdsk; + goto out; } - if (fp == FP_STONITH) - _drbd_request_state(mdev, NS(susp, 1), CS_WAIT_COMPLETE); - r = drbd_khelper(mdev, "fence-peer"); switch ((r>>8) & 0xff) { @@ -252,9 +257,36 @@ enum drbd_disk_state drbd_try_outdate_peer(struct drbd_conf *mdev) dev_info(DEV, "fence-peer helper returned %d (%s)\n", (r>>8) & 0xff, ex_to_string); + +out: + if (mdev->state.susp_fen && nps >= D_UNKNOWN) { + /* The handler was not successful... unfreeze here, the + state engine can not unfreeze... */ + _drbd_request_state(mdev, NS(susp_fen, 0), CS_VERBOSE); + } + return nps; } +static int _try_outdate_peer_async(void *data) +{ + struct drbd_conf *mdev = (struct drbd_conf *)data; + enum drbd_disk_state nps; + + nps = drbd_try_outdate_peer(mdev); + drbd_request_state(mdev, NS(pdsk, nps)); + + return 0; +} + +void drbd_try_outdate_peer_async(struct drbd_conf *mdev) +{ + struct task_struct *opa; + + opa = kthread_run(_try_outdate_peer_async, mdev, "drbd%d_a_helper", mdev_to_minor(mdev)); + if (IS_ERR(opa)) + dev_err(DEV, "out of mem, failed to invoke fence-peer helper\n"); +} int drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force) { @@ -394,6 +426,39 @@ int drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force) return r; } +static struct drbd_conf *ensure_mdev(int minor, int create) +{ + struct drbd_conf *mdev; + + if (minor >= minor_count) + return NULL; + + mdev = minor_to_mdev(minor); + + if (!mdev && create) { + struct gendisk *disk = NULL; + mdev = drbd_new_device(minor); + + spin_lock_irq(&drbd_pp_lock); + if (minor_table[minor] == NULL) { + minor_table[minor] = mdev; + disk = mdev->vdisk; + mdev = NULL; + } /* else: we lost the race */ + spin_unlock_irq(&drbd_pp_lock); + + if (disk) /* we won the race above */ + /* in case we ever add a drbd_delete_device(), + * don't forget the del_gendisk! */ + add_disk(disk); + else /* we lost the race above */ + drbd_free_mdev(mdev); + + mdev = minor_to_mdev(minor); + } + + return mdev; +} static int drbd_nl_primary(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, struct drbd_nl_cfg_reply *reply) @@ -494,6 +559,8 @@ char *ppsize(char *buf, unsigned long long size) void drbd_suspend_io(struct drbd_conf *mdev) { set_bit(SUSPEND_IO, &mdev->flags); + if (is_susp(mdev->state)) + return; wait_event(mdev->misc_wait, !atomic_read(&mdev->ap_bio_cnt)); } @@ -713,9 +780,6 @@ void drbd_setup_queue_param(struct drbd_conf *mdev, unsigned int max_seg_s) __mu blk_queue_segment_boundary(q, PAGE_SIZE-1); blk_stack_limits(&q->limits, &b->limits, 0); - if (b->merge_bvec_fn) - dev_warn(DEV, "Backing device's merge_bvec_fn() = %p\n", - b->merge_bvec_fn); dev_info(DEV, "max_segment_size ( = BIO size ) = %u\n", queue_max_segment_size(q)); if (q->backing_dev_info.ra_pages != b->backing_dev_info.ra_pages) { @@ -729,14 +793,16 @@ void drbd_setup_queue_param(struct drbd_conf *mdev, unsigned int max_seg_s) __mu /* serialize deconfig (worker exiting, doing cleanup) * and reconfig (drbdsetup disk, drbdsetup net) * - * wait for a potentially exiting worker, then restart it, - * or start a new one. + * Wait for a potentially exiting worker, then restart it, + * or start a new one. Flush any pending work, there may still be an + * after_state_change queued. */ static void drbd_reconfig_start(struct drbd_conf *mdev) { wait_event(mdev->state_wait, !test_and_set_bit(CONFIG_PENDING, &mdev->flags)); wait_event(mdev->state_wait, !test_bit(DEVICE_DYING, &mdev->flags)); drbd_thread_start(&mdev->worker); + drbd_flush_workqueue(mdev); } /* if still unconfigured, stops worker again. @@ -756,6 +822,29 @@ static void drbd_reconfig_done(struct drbd_conf *mdev) wake_up(&mdev->state_wait); } +/* Make sure IO is suspended before calling this function(). */ +static void drbd_suspend_al(struct drbd_conf *mdev) +{ + int s = 0; + + if (lc_try_lock(mdev->act_log)) { + drbd_al_shrink(mdev); + lc_unlock(mdev->act_log); + } else { + dev_warn(DEV, "Failed to lock al in drbd_suspend_al()\n"); + return; + } + + spin_lock_irq(&mdev->req_lock); + if (mdev->state.conn < C_CONNECTED) + s = !test_and_set_bit(AL_SUSPENDED, &mdev->flags); + + spin_unlock_irq(&mdev->req_lock); + + if (s) + dev_info(DEV, "Suspended AL updates\n"); +} + /* does always return 0; * interesting return code is in reply->ret_code */ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, @@ -769,6 +858,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp struct inode *inode, *inode2; struct lru_cache *resync_lru = NULL; union drbd_state ns, os; + unsigned int max_seg_s; int rv; int cp_discovered = 0; int logical_block_size; @@ -803,6 +893,15 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp goto fail; } + if (get_net_conf(mdev)) { + int prot = mdev->net_conf->wire_protocol; + put_net_conf(mdev); + if (nbc->dc.fencing == FP_STONITH && prot == DRBD_PROT_A) { + retcode = ERR_STONITH_AND_PROT_A; + goto fail; + } + } + nbc->lo_file = filp_open(nbc->dc.backing_dev, O_RDWR, 0); if (IS_ERR(nbc->lo_file)) { dev_err(DEV, "open(\"%s\") failed with %ld\n", nbc->dc.backing_dev, @@ -924,7 +1023,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp drbd_suspend_io(mdev); /* also wait for the last barrier ack. */ - wait_event(mdev->misc_wait, !atomic_read(&mdev->ap_pending_cnt)); + wait_event(mdev->misc_wait, !atomic_read(&mdev->ap_pending_cnt) || is_susp(mdev->state)); /* and for any other previously queued work */ drbd_flush_workqueue(mdev); @@ -1021,7 +1120,8 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp else clear_bit(CRASHED_PRIMARY, &mdev->flags); - if (drbd_md_test_flag(mdev->ldev, MDF_PRIMARY_IND)) { + if (drbd_md_test_flag(mdev->ldev, MDF_PRIMARY_IND) && + !(mdev->state.role == R_PRIMARY && mdev->state.susp_nod)) { set_bit(CRASHED_PRIMARY, &mdev->flags); cp_discovered = 1; } @@ -1031,7 +1131,20 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp mdev->read_cnt = 0; mdev->writ_cnt = 0; - drbd_setup_queue_param(mdev, DRBD_MAX_SEGMENT_SIZE); + max_seg_s = DRBD_MAX_SEGMENT_SIZE; + if (mdev->state.conn == C_CONNECTED) { + /* We are Primary, Connected, and now attach a new local + * backing store. We must not increase the user visible maximum + * bio size on this device to something the peer may not be + * able to handle. */ + if (mdev->agreed_pro_version < 94) + max_seg_s = queue_max_segment_size(mdev->rq_queue); + else if (mdev->agreed_pro_version == 94) + max_seg_s = DRBD_MAX_SIZE_H80_PACKET; + /* else: drbd 8.3.9 and later, stay with default */ + } + + drbd_setup_queue_param(mdev, max_seg_s); /* If I am currently not R_PRIMARY, * but meta data primary indicator is set, @@ -1079,6 +1192,9 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp drbd_al_to_on_disk_bm(mdev); } + if (_drbd_bm_total_weight(mdev) == drbd_bm_bits(mdev)) + drbd_suspend_al(mdev); /* IO is still suspended here... */ + spin_lock_irq(&mdev->req_lock); os = mdev->state; ns.i = os.i; @@ -1235,7 +1351,16 @@ static int drbd_nl_net_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, && (new_conf->wire_protocol != DRBD_PROT_C)) { retcode = ERR_NOT_PROTO_C; goto fail; - }; + } + + if (get_ldev(mdev)) { + enum drbd_fencing_p fp = mdev->ldev->dc.fencing; + put_ldev(mdev); + if (new_conf->wire_protocol == DRBD_PROT_A && fp == FP_STONITH) { + retcode = ERR_STONITH_AND_PROT_A; + goto fail; + } + } if (mdev->state.role == R_PRIMARY && new_conf->want_lose) { retcode = ERR_DISCARD; @@ -1350,6 +1475,7 @@ static int drbd_nl_net_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, } } + drbd_flush_workqueue(mdev); spin_lock_irq(&mdev->req_lock); if (mdev->net_conf != NULL) { retcode = ERR_NET_CONFIGURED; @@ -1388,10 +1514,9 @@ static int drbd_nl_net_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, mdev->int_dig_out=int_dig_out; mdev->int_dig_in=int_dig_in; mdev->int_dig_vv=int_dig_vv; + retcode = _drbd_set_state(_NS(mdev, conn, C_UNCONNECTED), CS_VERBOSE, NULL); spin_unlock_irq(&mdev->req_lock); - retcode = _drbd_request_state(mdev, NS(conn, C_UNCONNECTED), CS_VERBOSE); - kobject_uevent(&disk_to_dev(mdev->vdisk)->kobj, KOBJ_CHANGE); reply->ret_code = retcode; drbd_reconfig_done(mdev); @@ -1546,6 +1671,8 @@ static int drbd_nl_syncer_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *n struct crypto_hash *csums_tfm = NULL; struct syncer_conf sc; cpumask_var_t new_cpu_mask; + int *rs_plan_s = NULL; + int fifo_size; if (!zalloc_cpumask_var(&new_cpu_mask, GFP_KERNEL)) { retcode = ERR_NOMEM; @@ -1557,6 +1684,12 @@ static int drbd_nl_syncer_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *n sc.rate = DRBD_RATE_DEF; sc.after = DRBD_AFTER_DEF; sc.al_extents = DRBD_AL_EXTENTS_DEF; + sc.on_no_data = DRBD_ON_NO_DATA_DEF; + sc.c_plan_ahead = DRBD_C_PLAN_AHEAD_DEF; + sc.c_delay_target = DRBD_C_DELAY_TARGET_DEF; + sc.c_fill_target = DRBD_C_FILL_TARGET_DEF; + sc.c_max_rate = DRBD_C_MAX_RATE_DEF; + sc.c_min_rate = DRBD_C_MIN_RATE_DEF; } else memcpy(&sc, &mdev->sync_conf, sizeof(struct syncer_conf)); @@ -1634,6 +1767,12 @@ static int drbd_nl_syncer_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *n } #undef AL_MAX + /* to avoid spurious errors when configuring minors before configuring + * the minors they depend on: if necessary, first create the minor we + * depend on */ + if (sc.after >= 0) + ensure_mdev(sc.after, 1); + /* most sanity checks done, try to assign the new sync-after * dependency. need to hold the global lock in there, * to avoid a race in the dependency loop check. */ @@ -1641,6 +1780,16 @@ static int drbd_nl_syncer_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *n if (retcode != NO_ERROR) goto fail; + fifo_size = (sc.c_plan_ahead * 10 * SLEEP_TIME) / HZ; + if (fifo_size != mdev->rs_plan_s.size && fifo_size > 0) { + rs_plan_s = kzalloc(sizeof(int) * fifo_size, GFP_KERNEL); + if (!rs_plan_s) { + dev_err(DEV, "kmalloc of fifo_buffer failed"); + retcode = ERR_NOMEM; + goto fail; + } + } + /* ok, assign the rest of it as well. * lock against receive_SyncParam() */ spin_lock(&mdev->peer_seq_lock); @@ -1657,6 +1806,15 @@ static int drbd_nl_syncer_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *n mdev->verify_tfm = verify_tfm; verify_tfm = NULL; } + + if (fifo_size != mdev->rs_plan_s.size) { + kfree(mdev->rs_plan_s.values); + mdev->rs_plan_s.values = rs_plan_s; + mdev->rs_plan_s.size = fifo_size; + mdev->rs_planed = 0; + rs_plan_s = NULL; + } + spin_unlock(&mdev->peer_seq_lock); if (get_ldev(mdev)) { @@ -1688,6 +1846,7 @@ static int drbd_nl_syncer_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *n kobject_uevent(&disk_to_dev(mdev->vdisk)->kobj, KOBJ_CHANGE); fail: + kfree(rs_plan_s); free_cpumask_var(new_cpu_mask); crypto_free_hash(csums_tfm); crypto_free_hash(verify_tfm); @@ -1721,12 +1880,38 @@ static int drbd_nl_invalidate(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nl return 0; } +static int drbd_bmio_set_susp_al(struct drbd_conf *mdev) +{ + int rv; + + rv = drbd_bmio_set_n_write(mdev); + drbd_suspend_al(mdev); + return rv; +} + static int drbd_nl_invalidate_peer(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, struct drbd_nl_cfg_reply *reply) { + int retcode; - reply->ret_code = drbd_request_state(mdev, NS(conn, C_STARTING_SYNC_S)); + retcode = _drbd_request_state(mdev, NS(conn, C_STARTING_SYNC_S), CS_ORDERED); + + if (retcode < SS_SUCCESS) { + if (retcode == SS_NEED_CONNECTION && mdev->state.role == R_PRIMARY) { + /* The peer will get a resync upon connect anyways. Just make that + into a full resync. */ + retcode = drbd_request_state(mdev, NS(pdsk, D_INCONSISTENT)); + if (retcode >= SS_SUCCESS) { + /* open coded drbd_bitmap_io() */ + if (drbd_bitmap_io(mdev, &drbd_bmio_set_susp_al, + "set_n_write from invalidate_peer")) + retcode = ERR_IO_MD_DISK; + } + } else + retcode = drbd_request_state(mdev, NS(conn, C_STARTING_SYNC_S)); + } + reply->ret_code = retcode; return 0; } @@ -1765,7 +1950,21 @@ static int drbd_nl_suspend_io(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nl static int drbd_nl_resume_io(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, struct drbd_nl_cfg_reply *reply) { - reply->ret_code = drbd_request_state(mdev, NS(susp, 0)); + if (test_bit(NEW_CUR_UUID, &mdev->flags)) { + drbd_uuid_new_current(mdev); + clear_bit(NEW_CUR_UUID, &mdev->flags); + drbd_md_sync(mdev); + } + drbd_suspend_io(mdev); + reply->ret_code = drbd_request_state(mdev, NS3(susp, 0, susp_nod, 0, susp_fen, 0)); + if (reply->ret_code == SS_SUCCESS) { + if (mdev->state.conn < C_CONNECTED) + tl_clear(mdev); + if (mdev->state.disk == D_DISKLESS || mdev->state.disk == D_FAILED) + tl_restart(mdev, fail_frozen_disk_io); + } + drbd_resume_io(mdev); + return 0; } @@ -1941,40 +2140,6 @@ out: return 0; } -static struct drbd_conf *ensure_mdev(struct drbd_nl_cfg_req *nlp) -{ - struct drbd_conf *mdev; - - if (nlp->drbd_minor >= minor_count) - return NULL; - - mdev = minor_to_mdev(nlp->drbd_minor); - - if (!mdev && (nlp->flags & DRBD_NL_CREATE_DEVICE)) { - struct gendisk *disk = NULL; - mdev = drbd_new_device(nlp->drbd_minor); - - spin_lock_irq(&drbd_pp_lock); - if (minor_table[nlp->drbd_minor] == NULL) { - minor_table[nlp->drbd_minor] = mdev; - disk = mdev->vdisk; - mdev = NULL; - } /* else: we lost the race */ - spin_unlock_irq(&drbd_pp_lock); - - if (disk) /* we won the race above */ - /* in case we ever add a drbd_delete_device(), - * don't forget the del_gendisk! */ - add_disk(disk); - else /* we lost the race above */ - drbd_free_mdev(mdev); - - mdev = minor_to_mdev(nlp->drbd_minor); - } - - return mdev; -} - struct cn_handler_struct { int (*function)(struct drbd_conf *, struct drbd_nl_cfg_req *, @@ -2035,7 +2200,8 @@ static void drbd_connector_callback(struct cn_msg *req, struct netlink_skb_parms goto fail; } - mdev = ensure_mdev(nlp); + mdev = ensure_mdev(nlp->drbd_minor, + (nlp->flags & DRBD_NL_CREATE_DEVICE)); if (!mdev) { retcode = ERR_MINOR_INVALID; goto fail; diff --git a/drivers/block/drbd/drbd_proc.c b/drivers/block/drbd/drbd_proc.c index be3374b68460..ad325c5d0ce1 100644 --- a/drivers/block/drbd/drbd_proc.c +++ b/drivers/block/drbd/drbd_proc.c @@ -57,6 +57,7 @@ static void drbd_syncer_progress(struct drbd_conf *mdev, struct seq_file *seq) unsigned long db, dt, dbdt, rt, rs_left; unsigned int res; int i, x, y; + int stalled = 0; drbd_get_syncer_progress(mdev, &rs_left, &res); @@ -90,18 +91,17 @@ static void drbd_syncer_progress(struct drbd_conf *mdev, struct seq_file *seq) * db: blocks written from mark until now * rt: remaining time */ - dt = (jiffies - mdev->rs_mark_time) / HZ; - - if (dt > 20) { - /* if we made no update to rs_mark_time for too long, - * we are stalled. show that. */ - seq_printf(seq, "stalled\n"); - return; - } + /* Rolling marks. last_mark+1 may just now be modified. last_mark+2 is + * at least (DRBD_SYNC_MARKS-2)*DRBD_SYNC_MARK_STEP old, and has at + * least DRBD_SYNC_MARK_STEP time before it will be modified. */ + i = (mdev->rs_last_mark + 2) % DRBD_SYNC_MARKS; + dt = (jiffies - mdev->rs_mark_time[i]) / HZ; + if (dt > (DRBD_SYNC_MARK_STEP * DRBD_SYNC_MARKS)) + stalled = 1; if (!dt) dt++; - db = mdev->rs_mark_left - rs_left; + db = mdev->rs_mark_left[i] - rs_left; rt = (dt * (rs_left / (db/100+1)))/100; /* seconds */ seq_printf(seq, "finish: %lu:%02lu:%02lu", @@ -118,7 +118,7 @@ static void drbd_syncer_progress(struct drbd_conf *mdev, struct seq_file *seq) /* mean speed since syncer started * we do account for PausedSync periods */ dt = (jiffies - mdev->rs_start - mdev->rs_paused) / HZ; - if (dt <= 0) + if (dt == 0) dt = 1; db = mdev->rs_total - rs_left; dbdt = Bit2KB(db/dt); @@ -128,7 +128,14 @@ static void drbd_syncer_progress(struct drbd_conf *mdev, struct seq_file *seq) else seq_printf(seq, " (%ld)", dbdt); - seq_printf(seq, " K/sec\n"); + if (mdev->state.conn == C_SYNC_TARGET) { + if (mdev->c_sync_rate > 1000) + seq_printf(seq, " want: %d,%03d", + mdev->c_sync_rate / 1000, mdev->c_sync_rate % 1000); + else + seq_printf(seq, " want: %d", mdev->c_sync_rate); + } + seq_printf(seq, " K/sec%s\n", stalled ? " (stalled)" : ""); } static void resync_dump_detail(struct seq_file *seq, struct lc_element *e) @@ -196,7 +203,7 @@ static int drbd_seq_show(struct seq_file *seq, void *v) seq_printf(seq, "%2d: cs:Unconfigured\n", i); } else { seq_printf(seq, - "%2d: cs:%s ro:%s/%s ds:%s/%s %c %c%c%c%c%c\n" + "%2d: cs:%s ro:%s/%s ds:%s/%s %c %c%c%c%c%c%c\n" " ns:%u nr:%u dw:%u dr:%u al:%u bm:%u " "lo:%d pe:%d ua:%d ap:%d ep:%d wo:%c", i, sn, @@ -206,11 +213,12 @@ static int drbd_seq_show(struct seq_file *seq, void *v) drbd_disk_str(mdev->state.pdsk), (mdev->net_conf == NULL ? ' ' : (mdev->net_conf->wire_protocol - DRBD_PROT_A+'A')), - mdev->state.susp ? 's' : 'r', + is_susp(mdev->state) ? 's' : 'r', mdev->state.aftr_isp ? 'a' : '-', mdev->state.peer_isp ? 'p' : '-', mdev->state.user_isp ? 'u' : '-', mdev->congestion_reason ?: '-', + test_bit(AL_SUSPENDED, &mdev->flags) ? 's' : '-', mdev->send_cnt/2, mdev->recv_cnt/2, mdev->writ_cnt/2, diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 081522d3c742..efd6169acf2f 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -241,7 +241,7 @@ static void drbd_kick_lo_and_reclaim_net(struct drbd_conf *mdev) spin_unlock_irq(&mdev->req_lock); list_for_each_entry_safe(e, t, &reclaimed, w.list) - drbd_free_ee(mdev, e); + drbd_free_net_ee(mdev, e); } /** @@ -298,9 +298,11 @@ static struct page *drbd_pp_alloc(struct drbd_conf *mdev, unsigned number, bool * Is also used from inside an other spin_lock_irq(&mdev->req_lock); * Either links the page chain back to the global pool, * or returns all pages to the system. */ -static void drbd_pp_free(struct drbd_conf *mdev, struct page *page) +static void drbd_pp_free(struct drbd_conf *mdev, struct page *page, int is_net) { + atomic_t *a = is_net ? &mdev->pp_in_use_by_net : &mdev->pp_in_use; int i; + if (drbd_pp_vacant > (DRBD_MAX_SEGMENT_SIZE/PAGE_SIZE)*minor_count) i = page_chain_free(page); else { @@ -311,10 +313,10 @@ static void drbd_pp_free(struct drbd_conf *mdev, struct page *page) drbd_pp_vacant += i; spin_unlock(&drbd_pp_lock); } - atomic_sub(i, &mdev->pp_in_use); - i = atomic_read(&mdev->pp_in_use); + i = atomic_sub_return(i, a); if (i < 0) - dev_warn(DEV, "ASSERTION FAILED: pp_in_use: %d < 0\n", i); + dev_warn(DEV, "ASSERTION FAILED: %s: %d < 0\n", + is_net ? "pp_in_use_by_net" : "pp_in_use", i); wake_up(&drbd_pp_wait); } @@ -365,7 +367,6 @@ struct drbd_epoch_entry *drbd_alloc_ee(struct drbd_conf *mdev, e->size = data_size; e->flags = 0; e->sector = sector; - e->sector = sector; e->block_id = id; return e; @@ -375,9 +376,11 @@ struct drbd_epoch_entry *drbd_alloc_ee(struct drbd_conf *mdev, return NULL; } -void drbd_free_ee(struct drbd_conf *mdev, struct drbd_epoch_entry *e) +void drbd_free_some_ee(struct drbd_conf *mdev, struct drbd_epoch_entry *e, int is_net) { - drbd_pp_free(mdev, e->pages); + if (e->flags & EE_HAS_DIGEST) + kfree(e->digest); + drbd_pp_free(mdev, e->pages, is_net); D_ASSERT(atomic_read(&e->pending_bios) == 0); D_ASSERT(hlist_unhashed(&e->colision)); mempool_free(e, drbd_ee_mempool); @@ -388,13 +391,14 @@ int drbd_release_ee(struct drbd_conf *mdev, struct list_head *list) LIST_HEAD(work_list); struct drbd_epoch_entry *e, *t; int count = 0; + int is_net = list == &mdev->net_ee; spin_lock_irq(&mdev->req_lock); list_splice_init(list, &work_list); spin_unlock_irq(&mdev->req_lock); list_for_each_entry_safe(e, t, &work_list, w.list) { - drbd_free_ee(mdev, e); + drbd_free_some_ee(mdev, e, is_net); count++; } return count; @@ -423,7 +427,7 @@ static int drbd_process_done_ee(struct drbd_conf *mdev) spin_unlock_irq(&mdev->req_lock); list_for_each_entry_safe(e, t, &reclaimed, w.list) - drbd_free_ee(mdev, e); + drbd_free_net_ee(mdev, e); /* possible callbacks here: * e_end_block, and e_end_resync_block, e_send_discard_ack. @@ -719,14 +723,14 @@ out: static int drbd_send_fp(struct drbd_conf *mdev, struct socket *sock, enum drbd_packets cmd) { - struct p_header *h = (struct p_header *) &mdev->data.sbuf.header; + struct p_header80 *h = &mdev->data.sbuf.header.h80; return _drbd_send_cmd(mdev, sock, cmd, h, sizeof(*h), 0); } static enum drbd_packets drbd_recv_fp(struct drbd_conf *mdev, struct socket *sock) { - struct p_header *h = (struct p_header *) &mdev->data.sbuf.header; + struct p_header80 *h = &mdev->data.rbuf.header.h80; int rr; rr = drbd_recv_short(mdev, sock, h, sizeof(*h), 0); @@ -776,9 +780,6 @@ static int drbd_connect(struct drbd_conf *mdev) D_ASSERT(!mdev->data.socket); - if (test_and_clear_bit(CREATE_BARRIER, &mdev->flags)) - dev_err(DEV, "CREATE_BARRIER flag was set in drbd_connect - now cleared!\n"); - if (drbd_request_state(mdev, NS(conn, C_WF_CONNECTION)) < SS_SUCCESS) return -2; @@ -927,6 +928,11 @@ retry: drbd_thread_start(&mdev->asender); + if (mdev->agreed_pro_version < 95 && get_ldev(mdev)) { + drbd_setup_queue_param(mdev, DRBD_MAX_SIZE_H80_PACKET); + put_ldev(mdev); + } + if (!drbd_send_protocol(mdev)) return -1; drbd_send_sync_param(mdev, &mdev->sync_conf); @@ -946,22 +952,28 @@ out_release_sockets: return -1; } -static int drbd_recv_header(struct drbd_conf *mdev, struct p_header *h) +static int drbd_recv_header(struct drbd_conf *mdev, enum drbd_packets *cmd, unsigned int *packet_size) { + union p_header *h = &mdev->data.rbuf.header; int r; r = drbd_recv(mdev, h, sizeof(*h)); - if (unlikely(r != sizeof(*h))) { dev_err(DEV, "short read expecting header on sock: r=%d\n", r); return FALSE; - }; - h->command = be16_to_cpu(h->command); - h->length = be16_to_cpu(h->length); - if (unlikely(h->magic != BE_DRBD_MAGIC)) { - dev_err(DEV, "magic?? on data m: 0x%lx c: %d l: %d\n", - (long)be32_to_cpu(h->magic), - h->command, h->length); + } + + if (likely(h->h80.magic == BE_DRBD_MAGIC)) { + *cmd = be16_to_cpu(h->h80.command); + *packet_size = be16_to_cpu(h->h80.length); + } else if (h->h95.magic == BE_DRBD_MAGIC_BIG) { + *cmd = be16_to_cpu(h->h95.command); + *packet_size = be32_to_cpu(h->h95.length); + } else { + dev_err(DEV, "magic?? on data m: 0x%08x c: %d l: %d\n", + be32_to_cpu(h->h80.magic), + be16_to_cpu(h->h80.command), + be16_to_cpu(h->h80.length)); return FALSE; } mdev->last_received = jiffies; @@ -975,7 +987,7 @@ static enum finish_epoch drbd_flush_after_epoch(struct drbd_conf *mdev, struct d if (mdev->write_ordering >= WO_bdev_flush && get_ldev(mdev)) { rv = blkdev_issue_flush(mdev->ldev->backing_bdev, GFP_KERNEL, - NULL, BLKDEV_IFL_WAIT); + NULL); if (rv) { dev_err(DEV, "local disk flush failed with status %d\n", rv); /* would rather check on EOPNOTSUPP, but that is not reliable. @@ -1268,17 +1280,12 @@ int w_e_reissue(struct drbd_conf *mdev, struct drbd_work *w, int cancel) __relea return 1; } -static int receive_Barrier(struct drbd_conf *mdev, struct p_header *h) +static int receive_Barrier(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) { int rv, issue_flush; - struct p_barrier *p = (struct p_barrier *)h; + struct p_barrier *p = &mdev->data.rbuf.barrier; struct drbd_epoch *epoch; - ERR_IF(h->length != (sizeof(*p)-sizeof(*h))) return FALSE; - - rv = drbd_recv(mdev, h->payload, h->length); - ERR_IF(rv != h->length) return FALSE; - inc_unacked(mdev); if (mdev->net_conf->wire_protocol != DRBD_PROT_C) @@ -1457,7 +1464,7 @@ static int drbd_drain_block(struct drbd_conf *mdev, int data_size) data_size -= rr; } kunmap(page); - drbd_pp_free(mdev, page); + drbd_pp_free(mdev, page, 0); return rv; } @@ -1562,30 +1569,29 @@ static int recv_resync_read(struct drbd_conf *mdev, sector_t sector, int data_si list_add(&e->w.list, &mdev->sync_ee); spin_unlock_irq(&mdev->req_lock); + atomic_add(data_size >> 9, &mdev->rs_sect_ev); if (drbd_submit_ee(mdev, e, WRITE, DRBD_FAULT_RS_WR) == 0) return TRUE; + /* drbd_submit_ee currently fails for one reason only: + * not being able to allocate enough bios. + * Is dropping the connection going to help? */ + spin_lock_irq(&mdev->req_lock); + list_del(&e->w.list); + spin_unlock_irq(&mdev->req_lock); + drbd_free_ee(mdev, e); fail: put_ldev(mdev); return FALSE; } -static int receive_DataReply(struct drbd_conf *mdev, struct p_header *h) +static int receive_DataReply(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) { struct drbd_request *req; sector_t sector; - unsigned int header_size, data_size; int ok; - struct p_data *p = (struct p_data *)h; - - header_size = sizeof(*p) - sizeof(*h); - data_size = h->length - header_size; - - ERR_IF(data_size == 0) return FALSE; - - if (drbd_recv(mdev, h->payload, header_size) != header_size) - return FALSE; + struct p_data *p = &mdev->data.rbuf.data; sector = be64_to_cpu(p->sector); @@ -1611,20 +1617,11 @@ static int receive_DataReply(struct drbd_conf *mdev, struct p_header *h) return ok; } -static int receive_RSDataReply(struct drbd_conf *mdev, struct p_header *h) +static int receive_RSDataReply(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) { sector_t sector; - unsigned int header_size, data_size; int ok; - struct p_data *p = (struct p_data *)h; - - header_size = sizeof(*p) - sizeof(*h); - data_size = h->length - header_size; - - ERR_IF(data_size == 0) return FALSE; - - if (drbd_recv(mdev, h->payload, header_size) != header_size) - return FALSE; + struct p_data *p = &mdev->data.rbuf.data; sector = be64_to_cpu(p->sector); D_ASSERT(p->block_id == ID_SYNCER); @@ -1640,9 +1637,11 @@ static int receive_RSDataReply(struct drbd_conf *mdev, struct p_header *h) ok = drbd_drain_block(mdev, data_size); - drbd_send_ack_dp(mdev, P_NEG_ACK, p); + drbd_send_ack_dp(mdev, P_NEG_ACK, p, data_size); } + atomic_add(data_size >> 9, &mdev->rs_sect_in); + return ok; } @@ -1765,24 +1764,27 @@ static int drbd_wait_peer_seq(struct drbd_conf *mdev, const u32 packet_seq) return ret; } +static unsigned long write_flags_to_bio(struct drbd_conf *mdev, u32 dpf) +{ + if (mdev->agreed_pro_version >= 95) + return (dpf & DP_RW_SYNC ? REQ_SYNC : 0) | + (dpf & DP_UNPLUG ? REQ_UNPLUG : 0) | + (dpf & DP_FUA ? REQ_FUA : 0) | + (dpf & DP_FLUSH ? REQ_FUA : 0) | + (dpf & DP_DISCARD ? REQ_DISCARD : 0); + else + return dpf & DP_RW_SYNC ? (REQ_SYNC | REQ_UNPLUG) : 0; +} + /* mirrored write */ -static int receive_Data(struct drbd_conf *mdev, struct p_header *h) +static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) { sector_t sector; struct drbd_epoch_entry *e; - struct p_data *p = (struct p_data *)h; - int header_size, data_size; + struct p_data *p = &mdev->data.rbuf.data; int rw = WRITE; u32 dp_flags; - header_size = sizeof(*p) - sizeof(*h); - data_size = h->length - header_size; - - ERR_IF(data_size == 0) return FALSE; - - if (drbd_recv(mdev, h->payload, header_size) != header_size) - return FALSE; - if (!get_ldev(mdev)) { if (__ratelimit(&drbd_ratelimit_state)) dev_err(DEV, "Can not write mirrored data block " @@ -1792,7 +1794,7 @@ static int receive_Data(struct drbd_conf *mdev, struct p_header *h) mdev->peer_seq++; spin_unlock(&mdev->peer_seq_lock); - drbd_send_ack_dp(mdev, P_NEG_ACK, p); + drbd_send_ack_dp(mdev, P_NEG_ACK, p, data_size); atomic_inc(&mdev->current_epoch->epoch_size); return drbd_drain_block(mdev, data_size); } @@ -1839,12 +1841,8 @@ static int receive_Data(struct drbd_conf *mdev, struct p_header *h) spin_unlock(&mdev->epoch_lock); dp_flags = be32_to_cpu(p->dp_flags); - if (dp_flags & DP_HARDBARRIER) { - dev_err(DEV, "ASSERT FAILED would have submitted barrier request\n"); - /* rw |= REQ_HARDBARRIER; */ - } - if (dp_flags & DP_RW_SYNC) - rw |= REQ_SYNC | REQ_UNPLUG; + rw |= write_flags_to_bio(mdev, dp_flags); + if (dp_flags & DP_MAY_SET_IN_SYNC) e->flags |= EE_MAY_SET_IN_SYNC; @@ -2007,6 +2005,16 @@ static int receive_Data(struct drbd_conf *mdev, struct p_header *h) if (drbd_submit_ee(mdev, e, rw, DRBD_FAULT_DT_WR) == 0) return TRUE; + /* drbd_submit_ee currently fails for one reason only: + * not being able to allocate enough bios. + * Is dropping the connection going to help? */ + spin_lock_irq(&mdev->req_lock); + list_del(&e->w.list); + hlist_del_init(&e->colision); + spin_unlock_irq(&mdev->req_lock); + if (e->flags & EE_CALL_AL_COMPLETE_IO) + drbd_al_complete_io(mdev, e->sector); + out_interrupted: /* yes, the epoch_size now is imbalanced. * but we drop the connection anyways, so we don't have a chance to @@ -2016,20 +2024,64 @@ out_interrupted: return FALSE; } -static int receive_DataRequest(struct drbd_conf *mdev, struct p_header *h) +/* We may throttle resync, if the lower device seems to be busy, + * and current sync rate is above c_min_rate. + * + * To decide whether or not the lower device is busy, we use a scheme similar + * to MD RAID is_mddev_idle(): if the partition stats reveal "significant" + * (more than 64 sectors) of activity we cannot account for with our own resync + * activity, it obviously is "busy". + * + * The current sync rate used here uses only the most recent two step marks, + * to have a short time average so we can react faster. + */ +int drbd_rs_should_slow_down(struct drbd_conf *mdev) +{ + struct gendisk *disk = mdev->ldev->backing_bdev->bd_contains->bd_disk; + unsigned long db, dt, dbdt; + int curr_events; + int throttle = 0; + + /* feature disabled? */ + if (mdev->sync_conf.c_min_rate == 0) + return 0; + + curr_events = (int)part_stat_read(&disk->part0, sectors[0]) + + (int)part_stat_read(&disk->part0, sectors[1]) - + atomic_read(&mdev->rs_sect_ev); + if (!mdev->rs_last_events || curr_events - mdev->rs_last_events > 64) { + unsigned long rs_left; + int i; + + mdev->rs_last_events = curr_events; + + /* sync speed average over the last 2*DRBD_SYNC_MARK_STEP, + * approx. */ + i = (mdev->rs_last_mark + DRBD_SYNC_MARKS-2) % DRBD_SYNC_MARKS; + rs_left = drbd_bm_total_weight(mdev) - mdev->rs_failed; + + dt = ((long)jiffies - (long)mdev->rs_mark_time[i]) / HZ; + if (!dt) + dt++; + db = mdev->rs_mark_left[i] - rs_left; + dbdt = Bit2KB(db/dt); + + if (dbdt > mdev->sync_conf.c_min_rate) + throttle = 1; + } + return throttle; +} + + +static int receive_DataRequest(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int digest_size) { sector_t sector; const sector_t capacity = drbd_get_capacity(mdev->this_bdev); struct drbd_epoch_entry *e; struct digest_info *di = NULL; - int size, digest_size; + int size, verb; unsigned int fault_type; - struct p_block_req *p = - (struct p_block_req *)h; - const int brps = sizeof(*p)-sizeof(*h); - - if (drbd_recv(mdev, h->payload, brps) != brps) - return FALSE; + struct p_block_req *p = &mdev->data.rbuf.block_req; sector = be64_to_cpu(p->sector); size = be32_to_cpu(p->blksize); @@ -2046,12 +2098,31 @@ static int receive_DataRequest(struct drbd_conf *mdev, struct p_header *h) } if (!get_ldev_if_state(mdev, D_UP_TO_DATE)) { - if (__ratelimit(&drbd_ratelimit_state)) + verb = 1; + switch (cmd) { + case P_DATA_REQUEST: + drbd_send_ack_rp(mdev, P_NEG_DREPLY, p); + break; + case P_RS_DATA_REQUEST: + case P_CSUM_RS_REQUEST: + case P_OV_REQUEST: + drbd_send_ack_rp(mdev, P_NEG_RS_DREPLY , p); + break; + case P_OV_REPLY: + verb = 0; + dec_rs_pending(mdev); + drbd_send_ack_ex(mdev, P_OV_RESULT, sector, size, ID_IN_SYNC); + break; + default: + dev_err(DEV, "unexpected command (%s) in receive_DataRequest\n", + cmdname(cmd)); + } + if (verb && __ratelimit(&drbd_ratelimit_state)) dev_err(DEV, "Can not satisfy peer's read request, " "no local data.\n"); - drbd_send_ack_rp(mdev, h->command == P_DATA_REQUEST ? P_NEG_DREPLY : - P_NEG_RS_DREPLY , p); - return drbd_drain_block(mdev, h->length - brps); + + /* drain possibly payload */ + return drbd_drain_block(mdev, digest_size); } /* GFP_NOIO, because we must not cause arbitrary write-out: in a DRBD @@ -2063,31 +2134,21 @@ static int receive_DataRequest(struct drbd_conf *mdev, struct p_header *h) return FALSE; } - switch (h->command) { + switch (cmd) { case P_DATA_REQUEST: e->w.cb = w_e_end_data_req; fault_type = DRBD_FAULT_DT_RD; - break; + /* application IO, don't drbd_rs_begin_io */ + goto submit; + case P_RS_DATA_REQUEST: e->w.cb = w_e_end_rsdata_req; fault_type = DRBD_FAULT_RS_RD; - /* Eventually this should become asynchronously. Currently it - * blocks the whole receiver just to delay the reading of a - * resync data block. - * the drbd_work_queue mechanism is made for this... - */ - if (!drbd_rs_begin_io(mdev, sector)) { - /* we have been interrupted, - * probably connection lost! */ - D_ASSERT(signal_pending(current)); - goto out_free_e; - } break; case P_OV_REPLY: case P_CSUM_RS_REQUEST: fault_type = DRBD_FAULT_RS_RD; - digest_size = h->length - brps ; di = kmalloc(sizeof(*di) + digest_size, GFP_NOIO); if (!di) goto out_free_e; @@ -2095,31 +2156,25 @@ static int receive_DataRequest(struct drbd_conf *mdev, struct p_header *h) di->digest_size = digest_size; di->digest = (((char *)di)+sizeof(struct digest_info)); + e->digest = di; + e->flags |= EE_HAS_DIGEST; + if (drbd_recv(mdev, di->digest, digest_size) != digest_size) goto out_free_e; - e->block_id = (u64)(unsigned long)di; - if (h->command == P_CSUM_RS_REQUEST) { + if (cmd == P_CSUM_RS_REQUEST) { D_ASSERT(mdev->agreed_pro_version >= 89); e->w.cb = w_e_end_csum_rs_req; - } else if (h->command == P_OV_REPLY) { + } else if (cmd == P_OV_REPLY) { e->w.cb = w_e_end_ov_reply; dec_rs_pending(mdev); - break; - } - - if (!drbd_rs_begin_io(mdev, sector)) { - /* we have been interrupted, probably connection lost! */ - D_ASSERT(signal_pending(current)); - goto out_free_e; + /* drbd_rs_begin_io done when we sent this request, + * but accounting still needs to be done. */ + goto submit_for_resync; } break; case P_OV_REQUEST: - if (mdev->state.conn >= C_CONNECTED && - mdev->state.conn != C_VERIFY_T) - dev_warn(DEV, "ASSERT FAILED: got P_OV_REQUEST while being %s\n", - drbd_conn_str(mdev->state.conn)); if (mdev->ov_start_sector == ~(sector_t)0 && mdev->agreed_pro_version >= 90) { mdev->ov_start_sector = sector; @@ -2130,37 +2185,63 @@ static int receive_DataRequest(struct drbd_conf *mdev, struct p_header *h) } e->w.cb = w_e_end_ov_req; fault_type = DRBD_FAULT_RS_RD; - /* Eventually this should become asynchronous. Currently it - * blocks the whole receiver just to delay the reading of a - * resync data block. - * the drbd_work_queue mechanism is made for this... - */ - if (!drbd_rs_begin_io(mdev, sector)) { - /* we have been interrupted, - * probably connection lost! */ - D_ASSERT(signal_pending(current)); - goto out_free_e; - } break; - default: dev_err(DEV, "unexpected command (%s) in receive_DataRequest\n", - cmdname(h->command)); + cmdname(cmd)); fault_type = DRBD_FAULT_MAX; + goto out_free_e; } - spin_lock_irq(&mdev->req_lock); - list_add(&e->w.list, &mdev->read_ee); - spin_unlock_irq(&mdev->req_lock); + /* Throttle, drbd_rs_begin_io and submit should become asynchronous + * wrt the receiver, but it is not as straightforward as it may seem. + * Various places in the resync start and stop logic assume resync + * requests are processed in order, requeuing this on the worker thread + * introduces a bunch of new code for synchronization between threads. + * + * Unlimited throttling before drbd_rs_begin_io may stall the resync + * "forever", throttling after drbd_rs_begin_io will lock that extent + * for application writes for the same time. For now, just throttle + * here, where the rest of the code expects the receiver to sleep for + * a while, anyways. + */ + + /* Throttle before drbd_rs_begin_io, as that locks out application IO; + * this defers syncer requests for some time, before letting at least + * on request through. The resync controller on the receiving side + * will adapt to the incoming rate accordingly. + * + * We cannot throttle here if remote is Primary/SyncTarget: + * we would also throttle its application reads. + * In that case, throttling is done on the SyncTarget only. + */ + if (mdev->state.peer != R_PRIMARY && drbd_rs_should_slow_down(mdev)) + msleep(100); + if (drbd_rs_begin_io(mdev, e->sector)) + goto out_free_e; +submit_for_resync: + atomic_add(size >> 9, &mdev->rs_sect_ev); + +submit: inc_unacked(mdev); + spin_lock_irq(&mdev->req_lock); + list_add_tail(&e->w.list, &mdev->read_ee); + spin_unlock_irq(&mdev->req_lock); if (drbd_submit_ee(mdev, e, READ, fault_type) == 0) return TRUE; + /* drbd_submit_ee currently fails for one reason only: + * not being able to allocate enough bios. + * Is dropping the connection going to help? */ + spin_lock_irq(&mdev->req_lock); + list_del(&e->w.list); + spin_unlock_irq(&mdev->req_lock); + /* no drbd_rs_complete_io(), we are dropping the connection anyways */ + out_free_e: - kfree(di); put_ldev(mdev); drbd_free_ee(mdev, e); return FALSE; @@ -2699,20 +2780,13 @@ static int cmp_after_sb(enum drbd_after_sb_p peer, enum drbd_after_sb_p self) return 1; } -static int receive_protocol(struct drbd_conf *mdev, struct p_header *h) +static int receive_protocol(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) { - struct p_protocol *p = (struct p_protocol *)h; - int header_size, data_size; + struct p_protocol *p = &mdev->data.rbuf.protocol; int p_proto, p_after_sb_0p, p_after_sb_1p, p_after_sb_2p; int p_want_lose, p_two_primaries, cf; char p_integrity_alg[SHARED_SECRET_MAX] = ""; - header_size = sizeof(*p) - sizeof(*h); - data_size = h->length - header_size; - - if (drbd_recv(mdev, h->payload, header_size) != header_size) - return FALSE; - p_proto = be32_to_cpu(p->protocol); p_after_sb_0p = be32_to_cpu(p->after_sb_0p); p_after_sb_1p = be32_to_cpu(p->after_sb_1p); @@ -2805,39 +2879,46 @@ struct crypto_hash *drbd_crypto_alloc_digest_safe(const struct drbd_conf *mdev, return tfm; } -static int receive_SyncParam(struct drbd_conf *mdev, struct p_header *h) +static int receive_SyncParam(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int packet_size) { int ok = TRUE; - struct p_rs_param_89 *p = (struct p_rs_param_89 *)h; + struct p_rs_param_95 *p = &mdev->data.rbuf.rs_param_95; unsigned int header_size, data_size, exp_max_sz; struct crypto_hash *verify_tfm = NULL; struct crypto_hash *csums_tfm = NULL; const int apv = mdev->agreed_pro_version; + int *rs_plan_s = NULL; + int fifo_size = 0; exp_max_sz = apv <= 87 ? sizeof(struct p_rs_param) : apv == 88 ? sizeof(struct p_rs_param) + SHARED_SECRET_MAX - : /* 89 */ sizeof(struct p_rs_param_89); + : apv <= 94 ? sizeof(struct p_rs_param_89) + : /* apv >= 95 */ sizeof(struct p_rs_param_95); - if (h->length > exp_max_sz) { + if (packet_size > exp_max_sz) { dev_err(DEV, "SyncParam packet too long: received %u, expected <= %u bytes\n", - h->length, exp_max_sz); + packet_size, exp_max_sz); return FALSE; } if (apv <= 88) { - header_size = sizeof(struct p_rs_param) - sizeof(*h); - data_size = h->length - header_size; - } else /* apv >= 89 */ { - header_size = sizeof(struct p_rs_param_89) - sizeof(*h); - data_size = h->length - header_size; + header_size = sizeof(struct p_rs_param) - sizeof(struct p_header80); + data_size = packet_size - header_size; + } else if (apv <= 94) { + header_size = sizeof(struct p_rs_param_89) - sizeof(struct p_header80); + data_size = packet_size - header_size; + D_ASSERT(data_size == 0); + } else { + header_size = sizeof(struct p_rs_param_95) - sizeof(struct p_header80); + data_size = packet_size - header_size; D_ASSERT(data_size == 0); } /* initialize verify_alg and csums_alg */ memset(p->verify_alg, 0, 2 * SHARED_SECRET_MAX); - if (drbd_recv(mdev, h->payload, header_size) != header_size) + if (drbd_recv(mdev, &p->head.payload, header_size) != header_size) return FALSE; mdev->sync_conf.rate = be32_to_cpu(p->rate); @@ -2896,6 +2977,22 @@ static int receive_SyncParam(struct drbd_conf *mdev, struct p_header *h) } } + if (apv > 94) { + mdev->sync_conf.rate = be32_to_cpu(p->rate); + mdev->sync_conf.c_plan_ahead = be32_to_cpu(p->c_plan_ahead); + mdev->sync_conf.c_delay_target = be32_to_cpu(p->c_delay_target); + mdev->sync_conf.c_fill_target = be32_to_cpu(p->c_fill_target); + mdev->sync_conf.c_max_rate = be32_to_cpu(p->c_max_rate); + + fifo_size = (mdev->sync_conf.c_plan_ahead * 10 * SLEEP_TIME) / HZ; + if (fifo_size != mdev->rs_plan_s.size && fifo_size > 0) { + rs_plan_s = kzalloc(sizeof(int) * fifo_size, GFP_KERNEL); + if (!rs_plan_s) { + dev_err(DEV, "kmalloc of fifo_buffer failed"); + goto disconnect; + } + } + } spin_lock(&mdev->peer_seq_lock); /* lock against drbd_nl_syncer_conf() */ @@ -2913,6 +3010,12 @@ static int receive_SyncParam(struct drbd_conf *mdev, struct p_header *h) mdev->csums_tfm = csums_tfm; dev_info(DEV, "using csums-alg: \"%s\"\n", p->csums_alg); } + if (fifo_size != mdev->rs_plan_s.size) { + kfree(mdev->rs_plan_s.values); + mdev->rs_plan_s.values = rs_plan_s; + mdev->rs_plan_s.size = fifo_size; + mdev->rs_planed = 0; + } spin_unlock(&mdev->peer_seq_lock); } @@ -2946,19 +3049,15 @@ static void warn_if_differ_considerably(struct drbd_conf *mdev, (unsigned long long)a, (unsigned long long)b); } -static int receive_sizes(struct drbd_conf *mdev, struct p_header *h) +static int receive_sizes(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) { - struct p_sizes *p = (struct p_sizes *)h; + struct p_sizes *p = &mdev->data.rbuf.sizes; enum determine_dev_size dd = unchanged; unsigned int max_seg_s; sector_t p_size, p_usize, my_usize; int ldsc = 0; /* local disk size changed */ enum dds_flags ddsf; - ERR_IF(h->length != (sizeof(*p)-sizeof(*h))) return FALSE; - if (drbd_recv(mdev, h->payload, h->length) != h->length) - return FALSE; - p_size = be64_to_cpu(p->d_size); p_usize = be64_to_cpu(p->u_size); @@ -2972,7 +3071,6 @@ static int receive_sizes(struct drbd_conf *mdev, struct p_header *h) * we still need to figure out whether we accept that. */ mdev->p_size = p_size; -#define min_not_zero(l, r) (l == 0) ? r : ((r == 0) ? l : min(l, r)) if (get_ldev(mdev)) { warn_if_differ_considerably(mdev, "lower level device sizes", p_size, drbd_get_max_capacity(mdev->ldev)); @@ -3029,6 +3127,8 @@ static int receive_sizes(struct drbd_conf *mdev, struct p_header *h) if (mdev->agreed_pro_version < 94) max_seg_s = be32_to_cpu(p->max_segment_size); + else if (mdev->agreed_pro_version == 94) + max_seg_s = DRBD_MAX_SIZE_H80_PACKET; else /* drbd 8.3.8 onwards */ max_seg_s = DRBD_MAX_SEGMENT_SIZE; @@ -3062,16 +3162,12 @@ static int receive_sizes(struct drbd_conf *mdev, struct p_header *h) return TRUE; } -static int receive_uuids(struct drbd_conf *mdev, struct p_header *h) +static int receive_uuids(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) { - struct p_uuids *p = (struct p_uuids *)h; + struct p_uuids *p = &mdev->data.rbuf.uuids; u64 *p_uuid; int i; - ERR_IF(h->length != (sizeof(*p)-sizeof(*h))) return FALSE; - if (drbd_recv(mdev, h->payload, h->length) != h->length) - return FALSE; - p_uuid = kmalloc(sizeof(u64)*UI_EXTENDED_SIZE, GFP_NOIO); for (i = UI_CURRENT; i < UI_EXTENDED_SIZE; i++) @@ -3107,6 +3203,11 @@ static int receive_uuids(struct drbd_conf *mdev, struct p_header *h) drbd_md_sync(mdev); } put_ldev(mdev); + } else if (mdev->state.disk < D_INCONSISTENT && + mdev->state.role == R_PRIMARY) { + /* I am a diskless primary, the peer just created a new current UUID + for me. */ + drbd_set_ed_uuid(mdev, p_uuid[UI_CURRENT]); } /* Before we test for the disk state, we should wait until an eventually @@ -3150,16 +3251,12 @@ static union drbd_state convert_state(union drbd_state ps) return ms; } -static int receive_req_state(struct drbd_conf *mdev, struct p_header *h) +static int receive_req_state(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) { - struct p_req_state *p = (struct p_req_state *)h; + struct p_req_state *p = &mdev->data.rbuf.req_state; union drbd_state mask, val; int rv; - ERR_IF(h->length != (sizeof(*p)-sizeof(*h))) return FALSE; - if (drbd_recv(mdev, h->payload, h->length) != h->length) - return FALSE; - mask.i = be32_to_cpu(p->mask); val.i = be32_to_cpu(p->val); @@ -3180,20 +3277,14 @@ static int receive_req_state(struct drbd_conf *mdev, struct p_header *h) return TRUE; } -static int receive_state(struct drbd_conf *mdev, struct p_header *h) +static int receive_state(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) { - struct p_state *p = (struct p_state *)h; - enum drbd_conns nconn, oconn; - union drbd_state ns, peer_state; + struct p_state *p = &mdev->data.rbuf.state; + union drbd_state os, ns, peer_state; enum drbd_disk_state real_peer_disk; + enum chg_state_flags cs_flags; int rv; - ERR_IF(h->length != (sizeof(*p)-sizeof(*h))) - return FALSE; - - if (drbd_recv(mdev, h->payload, h->length) != h->length) - return FALSE; - peer_state.i = be32_to_cpu(p->state); real_peer_disk = peer_state.disk; @@ -3204,38 +3295,72 @@ static int receive_state(struct drbd_conf *mdev, struct p_header *h) spin_lock_irq(&mdev->req_lock); retry: - oconn = nconn = mdev->state.conn; + os = ns = mdev->state; spin_unlock_irq(&mdev->req_lock); - if (nconn == C_WF_REPORT_PARAMS) - nconn = C_CONNECTED; + /* peer says his disk is uptodate, while we think it is inconsistent, + * and this happens while we think we have a sync going on. */ + if (os.pdsk == D_INCONSISTENT && real_peer_disk == D_UP_TO_DATE && + os.conn > C_CONNECTED && os.disk == D_UP_TO_DATE) { + /* If we are (becoming) SyncSource, but peer is still in sync + * preparation, ignore its uptodate-ness to avoid flapping, it + * will change to inconsistent once the peer reaches active + * syncing states. + * It may have changed syncer-paused flags, however, so we + * cannot ignore this completely. */ + if (peer_state.conn > C_CONNECTED && + peer_state.conn < C_SYNC_SOURCE) + real_peer_disk = D_INCONSISTENT; + + /* if peer_state changes to connected at the same time, + * it explicitly notifies us that it finished resync. + * Maybe we should finish it up, too? */ + else if (os.conn >= C_SYNC_SOURCE && + peer_state.conn == C_CONNECTED) { + if (drbd_bm_total_weight(mdev) <= mdev->rs_failed) + drbd_resync_finished(mdev); + return TRUE; + } + } + + /* peer says his disk is inconsistent, while we think it is uptodate, + * and this happens while the peer still thinks we have a sync going on, + * but we think we are already done with the sync. + * We ignore this to avoid flapping pdsk. + * This should not happen, if the peer is a recent version of drbd. */ + if (os.pdsk == D_UP_TO_DATE && real_peer_disk == D_INCONSISTENT && + os.conn == C_CONNECTED && peer_state.conn > C_SYNC_SOURCE) + real_peer_disk = D_UP_TO_DATE; + + if (ns.conn == C_WF_REPORT_PARAMS) + ns.conn = C_CONNECTED; if (mdev->p_uuid && peer_state.disk >= D_NEGOTIATING && get_ldev_if_state(mdev, D_NEGOTIATING)) { int cr; /* consider resync */ /* if we established a new connection */ - cr = (oconn < C_CONNECTED); + cr = (os.conn < C_CONNECTED); /* if we had an established connection * and one of the nodes newly attaches a disk */ - cr |= (oconn == C_CONNECTED && + cr |= (os.conn == C_CONNECTED && (peer_state.disk == D_NEGOTIATING || - mdev->state.disk == D_NEGOTIATING)); + os.disk == D_NEGOTIATING)); /* if we have both been inconsistent, and the peer has been * forced to be UpToDate with --overwrite-data */ cr |= test_bit(CONSIDER_RESYNC, &mdev->flags); /* if we had been plain connected, and the admin requested to * start a sync by "invalidate" or "invalidate-remote" */ - cr |= (oconn == C_CONNECTED && + cr |= (os.conn == C_CONNECTED && (peer_state.conn >= C_STARTING_SYNC_S && peer_state.conn <= C_WF_BITMAP_T)); if (cr) - nconn = drbd_sync_handshake(mdev, peer_state.role, real_peer_disk); + ns.conn = drbd_sync_handshake(mdev, peer_state.role, real_peer_disk); put_ldev(mdev); - if (nconn == C_MASK) { - nconn = C_CONNECTED; + if (ns.conn == C_MASK) { + ns.conn = C_CONNECTED; if (mdev->state.disk == D_NEGOTIATING) { drbd_force_state(mdev, NS(disk, D_DISKLESS)); } else if (peer_state.disk == D_NEGOTIATING) { @@ -3245,7 +3370,7 @@ static int receive_state(struct drbd_conf *mdev, struct p_header *h) } else { if (test_and_clear_bit(CONN_DRY_RUN, &mdev->flags)) return FALSE; - D_ASSERT(oconn == C_WF_REPORT_PARAMS); + D_ASSERT(os.conn == C_WF_REPORT_PARAMS); drbd_force_state(mdev, NS(conn, C_DISCONNECTING)); return FALSE; } @@ -3253,18 +3378,28 @@ static int receive_state(struct drbd_conf *mdev, struct p_header *h) } spin_lock_irq(&mdev->req_lock); - if (mdev->state.conn != oconn) + if (mdev->state.i != os.i) goto retry; clear_bit(CONSIDER_RESYNC, &mdev->flags); - ns.i = mdev->state.i; - ns.conn = nconn; ns.peer = peer_state.role; ns.pdsk = real_peer_disk; ns.peer_isp = (peer_state.aftr_isp | peer_state.user_isp); - if ((nconn == C_CONNECTED || nconn == C_WF_BITMAP_S) && ns.disk == D_NEGOTIATING) + if ((ns.conn == C_CONNECTED || ns.conn == C_WF_BITMAP_S) && ns.disk == D_NEGOTIATING) ns.disk = mdev->new_state_tmp.disk; - - rv = _drbd_set_state(mdev, ns, CS_VERBOSE | CS_HARD, NULL); + cs_flags = CS_VERBOSE + (os.conn < C_CONNECTED && ns.conn >= C_CONNECTED ? 0 : CS_HARD); + if (ns.pdsk == D_CONSISTENT && is_susp(ns) && ns.conn == C_CONNECTED && os.conn < C_CONNECTED && + test_bit(NEW_CUR_UUID, &mdev->flags)) { + /* Do not allow tl_restart(resend) for a rebooted peer. We can only allow this + for temporal network outages! */ + spin_unlock_irq(&mdev->req_lock); + dev_err(DEV, "Aborting Connect, can not thaw IO with an only Consistent peer\n"); + tl_clear(mdev); + drbd_uuid_new_current(mdev); + clear_bit(NEW_CUR_UUID, &mdev->flags); + drbd_force_state(mdev, NS2(conn, C_PROTOCOL_ERROR, susp, 0)); + return FALSE; + } + rv = _drbd_set_state(mdev, ns, cs_flags, NULL); ns = mdev->state; spin_unlock_irq(&mdev->req_lock); @@ -3273,8 +3408,8 @@ static int receive_state(struct drbd_conf *mdev, struct p_header *h) return FALSE; } - if (oconn > C_WF_REPORT_PARAMS) { - if (nconn > C_CONNECTED && peer_state.conn <= C_CONNECTED && + if (os.conn > C_WF_REPORT_PARAMS) { + if (ns.conn > C_CONNECTED && peer_state.conn <= C_CONNECTED && peer_state.disk != D_NEGOTIATING ) { /* we want resync, peer has not yet decided to sync... */ /* Nowadays only used when forcing a node into primary role and @@ -3291,9 +3426,9 @@ static int receive_state(struct drbd_conf *mdev, struct p_header *h) return TRUE; } -static int receive_sync_uuid(struct drbd_conf *mdev, struct p_header *h) +static int receive_sync_uuid(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) { - struct p_rs_uuid *p = (struct p_rs_uuid *)h; + struct p_rs_uuid *p = &mdev->data.rbuf.rs_uuid; wait_event(mdev->misc_wait, mdev->state.conn == C_WF_SYNC_UUID || @@ -3302,10 +3437,6 @@ static int receive_sync_uuid(struct drbd_conf *mdev, struct p_header *h) /* D_ASSERT( mdev->state.conn == C_WF_SYNC_UUID ); */ - ERR_IF(h->length != (sizeof(*p)-sizeof(*h))) return FALSE; - if (drbd_recv(mdev, h->payload, h->length) != h->length) - return FALSE; - /* Here the _drbd_uuid_ functions are right, current should _not_ be rotated into the history */ if (get_ldev_if_state(mdev, D_NEGOTIATING)) { @@ -3324,14 +3455,14 @@ static int receive_sync_uuid(struct drbd_conf *mdev, struct p_header *h) enum receive_bitmap_ret { OK, DONE, FAILED }; static enum receive_bitmap_ret -receive_bitmap_plain(struct drbd_conf *mdev, struct p_header *h, - unsigned long *buffer, struct bm_xfer_ctx *c) +receive_bitmap_plain(struct drbd_conf *mdev, unsigned int data_size, + unsigned long *buffer, struct bm_xfer_ctx *c) { unsigned num_words = min_t(size_t, BM_PACKET_WORDS, c->bm_words - c->word_offset); unsigned want = num_words * sizeof(long); - if (want != h->length) { - dev_err(DEV, "%s:want (%u) != h->length (%u)\n", __func__, want, h->length); + if (want != data_size) { + dev_err(DEV, "%s:want (%u) != data_size (%u)\n", __func__, want, data_size); return FAILED; } if (want == 0) @@ -3360,7 +3491,7 @@ recv_bm_rle_bits(struct drbd_conf *mdev, u64 tmp; unsigned long s = c->bit_offset; unsigned long e; - int len = p->head.length - (sizeof(*p) - sizeof(p->head)); + int len = be16_to_cpu(p->head.length) - (sizeof(*p) - sizeof(p->head)); int toggle = DCBP_get_start(p); int have; int bits; @@ -3429,7 +3560,7 @@ void INFO_bm_xfer_stats(struct drbd_conf *mdev, const char *direction, struct bm_xfer_ctx *c) { /* what would it take to transfer it "plaintext" */ - unsigned plain = sizeof(struct p_header) * + unsigned plain = sizeof(struct p_header80) * ((c->bm_words+BM_PACKET_WORDS-1)/BM_PACKET_WORDS+1) + c->bm_words * sizeof(long); unsigned total = c->bytes[0] + c->bytes[1]; @@ -3467,12 +3598,13 @@ void INFO_bm_xfer_stats(struct drbd_conf *mdev, in order to be agnostic to the 32 vs 64 bits issue. returns 0 on failure, 1 if we successfully received it. */ -static int receive_bitmap(struct drbd_conf *mdev, struct p_header *h) +static int receive_bitmap(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) { struct bm_xfer_ctx c; void *buffer; enum receive_bitmap_ret ret; int ok = FALSE; + struct p_header80 *h = &mdev->data.rbuf.header.h80; wait_event(mdev->misc_wait, !atomic_read(&mdev->ap_bio_cnt)); @@ -3492,39 +3624,39 @@ static int receive_bitmap(struct drbd_conf *mdev, struct p_header *h) }; do { - if (h->command == P_BITMAP) { - ret = receive_bitmap_plain(mdev, h, buffer, &c); - } else if (h->command == P_COMPRESSED_BITMAP) { + if (cmd == P_BITMAP) { + ret = receive_bitmap_plain(mdev, data_size, buffer, &c); + } else if (cmd == P_COMPRESSED_BITMAP) { /* MAYBE: sanity check that we speak proto >= 90, * and the feature is enabled! */ struct p_compressed_bm *p; - if (h->length > BM_PACKET_PAYLOAD_BYTES) { + if (data_size > BM_PACKET_PAYLOAD_BYTES) { dev_err(DEV, "ReportCBitmap packet too large\n"); goto out; } /* use the page buff */ p = buffer; memcpy(p, h, sizeof(*h)); - if (drbd_recv(mdev, p->head.payload, h->length) != h->length) + if (drbd_recv(mdev, p->head.payload, data_size) != data_size) goto out; - if (p->head.length <= (sizeof(*p) - sizeof(p->head))) { - dev_err(DEV, "ReportCBitmap packet too small (l:%u)\n", p->head.length); + if (data_size <= (sizeof(*p) - sizeof(p->head))) { + dev_err(DEV, "ReportCBitmap packet too small (l:%u)\n", data_size); return FAILED; } ret = decode_bitmap_c(mdev, p, &c); } else { - dev_warn(DEV, "receive_bitmap: h->command neither ReportBitMap nor ReportCBitMap (is 0x%x)", h->command); + dev_warn(DEV, "receive_bitmap: cmd neither ReportBitMap nor ReportCBitMap (is 0x%x)", cmd); goto out; } - c.packets[h->command == P_BITMAP]++; - c.bytes[h->command == P_BITMAP] += sizeof(struct p_header) + h->length; + c.packets[cmd == P_BITMAP]++; + c.bytes[cmd == P_BITMAP] += sizeof(struct p_header80) + data_size; if (ret != OK) break; - if (!drbd_recv_header(mdev, h)) + if (!drbd_recv_header(mdev, &cmd, &data_size)) goto out; } while (ret == OK); if (ret == FAILED) @@ -3555,17 +3687,16 @@ static int receive_bitmap(struct drbd_conf *mdev, struct p_header *h) return ok; } -static int receive_skip_(struct drbd_conf *mdev, struct p_header *h, int silent) +static int receive_skip(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) { /* TODO zero copy sink :) */ static char sink[128]; int size, want, r; - if (!silent) - dev_warn(DEV, "skipping unknown optional packet type %d, l: %d!\n", - h->command, h->length); + dev_warn(DEV, "skipping unknown optional packet type %d, l: %d!\n", + cmd, data_size); - size = h->length; + size = data_size; while (size > 0) { want = min_t(int, size, sizeof(sink)); r = drbd_recv(mdev, sink, want); @@ -3575,17 +3706,7 @@ static int receive_skip_(struct drbd_conf *mdev, struct p_header *h, int silent) return size == 0; } -static int receive_skip(struct drbd_conf *mdev, struct p_header *h) -{ - return receive_skip_(mdev, h, 0); -} - -static int receive_skip_silent(struct drbd_conf *mdev, struct p_header *h) -{ - return receive_skip_(mdev, h, 1); -} - -static int receive_UnplugRemote(struct drbd_conf *mdev, struct p_header *h) +static int receive_UnplugRemote(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) { if (mdev->state.disk >= D_INCONSISTENT) drbd_kick_lo(mdev); @@ -3597,108 +3718,94 @@ static int receive_UnplugRemote(struct drbd_conf *mdev, struct p_header *h) return TRUE; } -typedef int (*drbd_cmd_handler_f)(struct drbd_conf *, struct p_header *); - -static drbd_cmd_handler_f drbd_default_handler[] = { - [P_DATA] = receive_Data, - [P_DATA_REPLY] = receive_DataReply, - [P_RS_DATA_REPLY] = receive_RSDataReply, - [P_BARRIER] = receive_Barrier, - [P_BITMAP] = receive_bitmap, - [P_COMPRESSED_BITMAP] = receive_bitmap, - [P_UNPLUG_REMOTE] = receive_UnplugRemote, - [P_DATA_REQUEST] = receive_DataRequest, - [P_RS_DATA_REQUEST] = receive_DataRequest, - [P_SYNC_PARAM] = receive_SyncParam, - [P_SYNC_PARAM89] = receive_SyncParam, - [P_PROTOCOL] = receive_protocol, - [P_UUIDS] = receive_uuids, - [P_SIZES] = receive_sizes, - [P_STATE] = receive_state, - [P_STATE_CHG_REQ] = receive_req_state, - [P_SYNC_UUID] = receive_sync_uuid, - [P_OV_REQUEST] = receive_DataRequest, - [P_OV_REPLY] = receive_DataRequest, - [P_CSUM_RS_REQUEST] = receive_DataRequest, - [P_DELAY_PROBE] = receive_skip_silent, +typedef int (*drbd_cmd_handler_f)(struct drbd_conf *, enum drbd_packets cmd, unsigned int to_receive); + +struct data_cmd { + int expect_payload; + size_t pkt_size; + drbd_cmd_handler_f function; +}; + +static struct data_cmd drbd_cmd_handler[] = { + [P_DATA] = { 1, sizeof(struct p_data), receive_Data }, + [P_DATA_REPLY] = { 1, sizeof(struct p_data), receive_DataReply }, + [P_RS_DATA_REPLY] = { 1, sizeof(struct p_data), receive_RSDataReply } , + [P_BARRIER] = { 0, sizeof(struct p_barrier), receive_Barrier } , + [P_BITMAP] = { 1, sizeof(struct p_header80), receive_bitmap } , + [P_COMPRESSED_BITMAP] = { 1, sizeof(struct p_header80), receive_bitmap } , + [P_UNPLUG_REMOTE] = { 0, sizeof(struct p_header80), receive_UnplugRemote }, + [P_DATA_REQUEST] = { 0, sizeof(struct p_block_req), receive_DataRequest }, + [P_RS_DATA_REQUEST] = { 0, sizeof(struct p_block_req), receive_DataRequest }, + [P_SYNC_PARAM] = { 1, sizeof(struct p_header80), receive_SyncParam }, + [P_SYNC_PARAM89] = { 1, sizeof(struct p_header80), receive_SyncParam }, + [P_PROTOCOL] = { 1, sizeof(struct p_protocol), receive_protocol }, + [P_UUIDS] = { 0, sizeof(struct p_uuids), receive_uuids }, + [P_SIZES] = { 0, sizeof(struct p_sizes), receive_sizes }, + [P_STATE] = { 0, sizeof(struct p_state), receive_state }, + [P_STATE_CHG_REQ] = { 0, sizeof(struct p_req_state), receive_req_state }, + [P_SYNC_UUID] = { 0, sizeof(struct p_rs_uuid), receive_sync_uuid }, + [P_OV_REQUEST] = { 0, sizeof(struct p_block_req), receive_DataRequest }, + [P_OV_REPLY] = { 1, sizeof(struct p_block_req), receive_DataRequest }, + [P_CSUM_RS_REQUEST] = { 1, sizeof(struct p_block_req), receive_DataRequest }, + [P_DELAY_PROBE] = { 0, sizeof(struct p_delay_probe93), receive_skip }, /* anything missing from this table is in * the asender_tbl, see get_asender_cmd */ - [P_MAX_CMD] = NULL, + [P_MAX_CMD] = { 0, 0, NULL }, }; -static drbd_cmd_handler_f *drbd_cmd_handler = drbd_default_handler; -static drbd_cmd_handler_f *drbd_opt_cmd_handler; +/* All handler functions that expect a sub-header get that sub-heder in + mdev->data.rbuf.header.head.payload. + + Usually in mdev->data.rbuf.header.head the callback can find the usual + p_header, but they may not rely on that. Since there is also p_header95 ! + */ static void drbdd(struct drbd_conf *mdev) { - drbd_cmd_handler_f handler; - struct p_header *header = &mdev->data.rbuf.header; + union p_header *header = &mdev->data.rbuf.header; + unsigned int packet_size; + enum drbd_packets cmd; + size_t shs; /* sub header size */ + int rv; while (get_t_state(&mdev->receiver) == Running) { drbd_thread_current_set_cpu(mdev); - if (!drbd_recv_header(mdev, header)) { - drbd_force_state(mdev, NS(conn, C_PROTOCOL_ERROR)); - break; - } + if (!drbd_recv_header(mdev, &cmd, &packet_size)) + goto err_out; - if (header->command < P_MAX_CMD) - handler = drbd_cmd_handler[header->command]; - else if (P_MAY_IGNORE < header->command - && header->command < P_MAX_OPT_CMD) - handler = drbd_opt_cmd_handler[header->command-P_MAY_IGNORE]; - else if (header->command > P_MAX_OPT_CMD) - handler = receive_skip; - else - handler = NULL; + if (unlikely(cmd >= P_MAX_CMD || !drbd_cmd_handler[cmd].function)) { + dev_err(DEV, "unknown packet type %d, l: %d!\n", cmd, packet_size); + goto err_out; + } - if (unlikely(!handler)) { - dev_err(DEV, "unknown packet type %d, l: %d!\n", - header->command, header->length); - drbd_force_state(mdev, NS(conn, C_PROTOCOL_ERROR)); - break; + shs = drbd_cmd_handler[cmd].pkt_size - sizeof(union p_header); + rv = drbd_recv(mdev, &header->h80.payload, shs); + if (unlikely(rv != shs)) { + dev_err(DEV, "short read while reading sub header: rv=%d\n", rv); + goto err_out; } - if (unlikely(!handler(mdev, header))) { - dev_err(DEV, "error receiving %s, l: %d!\n", - cmdname(header->command), header->length); - drbd_force_state(mdev, NS(conn, C_PROTOCOL_ERROR)); - break; + + if (packet_size - shs > 0 && !drbd_cmd_handler[cmd].expect_payload) { + dev_err(DEV, "No payload expected %s l:%d\n", cmdname(cmd), packet_size); + goto err_out; } - } -} -static void drbd_fail_pending_reads(struct drbd_conf *mdev) -{ - struct hlist_head *slot; - struct hlist_node *pos; - struct hlist_node *tmp; - struct drbd_request *req; - int i; + rv = drbd_cmd_handler[cmd].function(mdev, cmd, packet_size - shs); - /* - * Application READ requests - */ - spin_lock_irq(&mdev->req_lock); - for (i = 0; i < APP_R_HSIZE; i++) { - slot = mdev->app_reads_hash+i; - hlist_for_each_entry_safe(req, pos, tmp, slot, colision) { - /* it may (but should not any longer!) - * be on the work queue; if that assert triggers, - * we need to also grab the - * spin_lock_irq(&mdev->data.work.q_lock); - * and list_del_init here. */ - D_ASSERT(list_empty(&req->w.list)); - /* It would be nice to complete outside of spinlock. - * But this is easier for now. */ - _req_mod(req, connection_lost_while_pending); + if (unlikely(!rv)) { + dev_err(DEV, "error receiving %s, l: %d!\n", + cmdname(cmd), packet_size); + goto err_out; } } - for (i = 0; i < APP_R_HSIZE; i++) - if (!hlist_empty(mdev->app_reads_hash+i)) - dev_warn(DEV, "ASSERT FAILED: app_reads_hash[%d].first: " - "%p, should be NULL\n", i, mdev->app_reads_hash[i].first); - memset(mdev->app_reads_hash, 0, APP_R_HSIZE*sizeof(void *)); - spin_unlock_irq(&mdev->req_lock); + if (0) { + err_out: + drbd_force_state(mdev, NS(conn, C_PROTOCOL_ERROR)); + } + /* If we leave here, we probably want to update at least the + * "Connected" indicator on stable storage. Do so explicitly here. */ + drbd_md_sync(mdev); } void drbd_flush_workqueue(struct drbd_conf *mdev) @@ -3711,6 +3818,36 @@ void drbd_flush_workqueue(struct drbd_conf *mdev) wait_for_completion(&barr.done); } +void drbd_free_tl_hash(struct drbd_conf *mdev) +{ + struct hlist_head *h; + + spin_lock_irq(&mdev->req_lock); + + if (!mdev->tl_hash || mdev->state.conn != C_STANDALONE) { + spin_unlock_irq(&mdev->req_lock); + return; + } + /* paranoia code */ + for (h = mdev->ee_hash; h < mdev->ee_hash + mdev->ee_hash_s; h++) + if (h->first) + dev_err(DEV, "ASSERT FAILED ee_hash[%u].first == %p, expected NULL\n", + (int)(h - mdev->ee_hash), h->first); + kfree(mdev->ee_hash); + mdev->ee_hash = NULL; + mdev->ee_hash_s = 0; + + /* paranoia code */ + for (h = mdev->tl_hash; h < mdev->tl_hash + mdev->tl_hash_s; h++) + if (h->first) + dev_err(DEV, "ASSERT FAILED tl_hash[%u] == %p, expected NULL\n", + (int)(h - mdev->tl_hash), h->first); + kfree(mdev->tl_hash); + mdev->tl_hash = NULL; + mdev->tl_hash_s = 0; + spin_unlock_irq(&mdev->req_lock); +} + static void drbd_disconnect(struct drbd_conf *mdev) { enum drbd_fencing_p fp; @@ -3728,6 +3865,7 @@ static void drbd_disconnect(struct drbd_conf *mdev) drbd_thread_stop(&mdev->asender); drbd_free_sock(mdev); + /* wait for current activity to cease. */ spin_lock_irq(&mdev->req_lock); _drbd_wait_ee_list_empty(mdev, &mdev->active_ee); _drbd_wait_ee_list_empty(mdev, &mdev->sync_ee); @@ -3752,7 +3890,6 @@ static void drbd_disconnect(struct drbd_conf *mdev) /* make sure syncer is stopped and w_resume_next_sg queued */ del_timer_sync(&mdev->resync_timer); - set_bit(STOP_SYNC_TIMER, &mdev->flags); resync_timer_fn((unsigned long)mdev); /* wait for all w_e_end_data_req, w_e_end_rsdata_req, w_send_barrier, @@ -3767,11 +3904,9 @@ static void drbd_disconnect(struct drbd_conf *mdev) kfree(mdev->p_uuid); mdev->p_uuid = NULL; - if (!mdev->state.susp) + if (!is_susp(mdev->state)) tl_clear(mdev); - drbd_fail_pending_reads(mdev); - dev_info(DEV, "Connection closed\n"); drbd_md_sync(mdev); @@ -3782,12 +3917,8 @@ static void drbd_disconnect(struct drbd_conf *mdev) put_ldev(mdev); } - if (mdev->state.role == R_PRIMARY) { - if (fp >= FP_RESOURCE && mdev->state.pdsk >= D_UNKNOWN) { - enum drbd_disk_state nps = drbd_try_outdate_peer(mdev); - drbd_request_state(mdev, NS(pdsk, nps)); - } - } + if (mdev->state.role == R_PRIMARY && fp >= FP_RESOURCE && mdev->state.pdsk >= D_UNKNOWN) + drbd_try_outdate_peer_async(mdev); spin_lock_irq(&mdev->req_lock); os = mdev->state; @@ -3800,32 +3931,14 @@ static void drbd_disconnect(struct drbd_conf *mdev) spin_unlock_irq(&mdev->req_lock); if (os.conn == C_DISCONNECTING) { - struct hlist_head *h; - wait_event(mdev->misc_wait, atomic_read(&mdev->net_cnt) == 0); + wait_event(mdev->net_cnt_wait, atomic_read(&mdev->net_cnt) == 0); - /* we must not free the tl_hash - * while application io is still on the fly */ - wait_event(mdev->misc_wait, atomic_read(&mdev->ap_bio_cnt) == 0); - - spin_lock_irq(&mdev->req_lock); - /* paranoia code */ - for (h = mdev->ee_hash; h < mdev->ee_hash + mdev->ee_hash_s; h++) - if (h->first) - dev_err(DEV, "ASSERT FAILED ee_hash[%u].first == %p, expected NULL\n", - (int)(h - mdev->ee_hash), h->first); - kfree(mdev->ee_hash); - mdev->ee_hash = NULL; - mdev->ee_hash_s = 0; - - /* paranoia code */ - for (h = mdev->tl_hash; h < mdev->tl_hash + mdev->tl_hash_s; h++) - if (h->first) - dev_err(DEV, "ASSERT FAILED tl_hash[%u] == %p, expected NULL\n", - (int)(h - mdev->tl_hash), h->first); - kfree(mdev->tl_hash); - mdev->tl_hash = NULL; - mdev->tl_hash_s = 0; - spin_unlock_irq(&mdev->req_lock); + if (!is_susp(mdev->state)) { + /* we must not free the tl_hash + * while application io is still on the fly */ + wait_event(mdev->misc_wait, !atomic_read(&mdev->ap_bio_cnt)); + drbd_free_tl_hash(mdev); + } crypto_free_hash(mdev->cram_hmac_tfm); mdev->cram_hmac_tfm = NULL; @@ -3845,6 +3958,9 @@ static void drbd_disconnect(struct drbd_conf *mdev) i = drbd_release_ee(mdev, &mdev->net_ee); if (i) dev_info(DEV, "net_ee not empty, killed %u entries\n", i); + i = atomic_read(&mdev->pp_in_use_by_net); + if (i) + dev_info(DEV, "pp_in_use_by_net = %d, expected 0\n", i); i = atomic_read(&mdev->pp_in_use); if (i) dev_info(DEV, "pp_in_use = %d, expected 0\n", i); @@ -3888,7 +4004,7 @@ static int drbd_send_handshake(struct drbd_conf *mdev) p->protocol_min = cpu_to_be32(PRO_VERSION_MIN); p->protocol_max = cpu_to_be32(PRO_VERSION_MAX); ok = _drbd_send_cmd( mdev, mdev->data.socket, P_HAND_SHAKE, - (struct p_header *)p, sizeof(*p), 0 ); + (struct p_header80 *)p, sizeof(*p), 0 ); mutex_unlock(&mdev->data.mutex); return ok; } @@ -3904,27 +4020,28 @@ static int drbd_do_handshake(struct drbd_conf *mdev) { /* ASSERT current == mdev->receiver ... */ struct p_handshake *p = &mdev->data.rbuf.handshake; - const int expect = sizeof(struct p_handshake) - -sizeof(struct p_header); + const int expect = sizeof(struct p_handshake) - sizeof(struct p_header80); + unsigned int length; + enum drbd_packets cmd; int rv; rv = drbd_send_handshake(mdev); if (!rv) return 0; - rv = drbd_recv_header(mdev, &p->head); + rv = drbd_recv_header(mdev, &cmd, &length); if (!rv) return 0; - if (p->head.command != P_HAND_SHAKE) { + if (cmd != P_HAND_SHAKE) { dev_err(DEV, "expected HandShake packet, received: %s (0x%04x)\n", - cmdname(p->head.command), p->head.command); + cmdname(cmd), cmd); return -1; } - if (p->head.length != expect) { + if (length != expect) { dev_err(DEV, "expected HandShake length: %u, received: %u\n", - expect, p->head.length); + expect, length); return -1; } @@ -3982,10 +4099,11 @@ static int drbd_do_auth(struct drbd_conf *mdev) char *response = NULL; char *right_response = NULL; char *peers_ch = NULL; - struct p_header p; unsigned int key_len = strlen(mdev->net_conf->shared_secret); unsigned int resp_size; struct hash_desc desc; + enum drbd_packets cmd; + unsigned int length; int rv; desc.tfm = mdev->cram_hmac_tfm; @@ -4005,33 +4123,33 @@ static int drbd_do_auth(struct drbd_conf *mdev) if (!rv) goto fail; - rv = drbd_recv_header(mdev, &p); + rv = drbd_recv_header(mdev, &cmd, &length); if (!rv) goto fail; - if (p.command != P_AUTH_CHALLENGE) { + if (cmd != P_AUTH_CHALLENGE) { dev_err(DEV, "expected AuthChallenge packet, received: %s (0x%04x)\n", - cmdname(p.command), p.command); + cmdname(cmd), cmd); rv = 0; goto fail; } - if (p.length > CHALLENGE_LEN*2) { + if (length > CHALLENGE_LEN * 2) { dev_err(DEV, "expected AuthChallenge payload too big.\n"); rv = -1; goto fail; } - peers_ch = kmalloc(p.length, GFP_NOIO); + peers_ch = kmalloc(length, GFP_NOIO); if (peers_ch == NULL) { dev_err(DEV, "kmalloc of peers_ch failed\n"); rv = -1; goto fail; } - rv = drbd_recv(mdev, peers_ch, p.length); + rv = drbd_recv(mdev, peers_ch, length); - if (rv != p.length) { + if (rv != length) { dev_err(DEV, "short read AuthChallenge: l=%u\n", rv); rv = 0; goto fail; @@ -4046,7 +4164,7 @@ static int drbd_do_auth(struct drbd_conf *mdev) } sg_init_table(&sg, 1); - sg_set_buf(&sg, peers_ch, p.length); + sg_set_buf(&sg, peers_ch, length); rv = crypto_hash_digest(&desc, &sg, sg.length, response); if (rv) { @@ -4059,18 +4177,18 @@ static int drbd_do_auth(struct drbd_conf *mdev) if (!rv) goto fail; - rv = drbd_recv_header(mdev, &p); + rv = drbd_recv_header(mdev, &cmd, &length); if (!rv) goto fail; - if (p.command != P_AUTH_RESPONSE) { + if (cmd != P_AUTH_RESPONSE) { dev_err(DEV, "expected AuthResponse packet, received: %s (0x%04x)\n", - cmdname(p.command), p.command); + cmdname(cmd), cmd); rv = 0; goto fail; } - if (p.length != resp_size) { + if (length != resp_size) { dev_err(DEV, "expected AuthResponse payload of wrong size\n"); rv = 0; goto fail; @@ -4155,7 +4273,7 @@ int drbdd_init(struct drbd_thread *thi) /* ********* acknowledge sender ******** */ -static int got_RqSReply(struct drbd_conf *mdev, struct p_header *h) +static int got_RqSReply(struct drbd_conf *mdev, struct p_header80 *h) { struct p_req_state_reply *p = (struct p_req_state_reply *)h; @@ -4173,13 +4291,13 @@ static int got_RqSReply(struct drbd_conf *mdev, struct p_header *h) return TRUE; } -static int got_Ping(struct drbd_conf *mdev, struct p_header *h) +static int got_Ping(struct drbd_conf *mdev, struct p_header80 *h) { return drbd_send_ping_ack(mdev); } -static int got_PingAck(struct drbd_conf *mdev, struct p_header *h) +static int got_PingAck(struct drbd_conf *mdev, struct p_header80 *h) { /* restore idle timeout */ mdev->meta.socket->sk->sk_rcvtimeo = mdev->net_conf->ping_int*HZ; @@ -4189,7 +4307,7 @@ static int got_PingAck(struct drbd_conf *mdev, struct p_header *h) return TRUE; } -static int got_IsInSync(struct drbd_conf *mdev, struct p_header *h) +static int got_IsInSync(struct drbd_conf *mdev, struct p_header80 *h) { struct p_block_ack *p = (struct p_block_ack *)h; sector_t sector = be64_to_cpu(p->sector); @@ -4199,11 +4317,15 @@ static int got_IsInSync(struct drbd_conf *mdev, struct p_header *h) update_peer_seq(mdev, be32_to_cpu(p->seq_num)); - drbd_rs_complete_io(mdev, sector); - drbd_set_in_sync(mdev, sector, blksize); - /* rs_same_csums is supposed to count in units of BM_BLOCK_SIZE */ - mdev->rs_same_csum += (blksize >> BM_BLOCK_SHIFT); + if (get_ldev(mdev)) { + drbd_rs_complete_io(mdev, sector); + drbd_set_in_sync(mdev, sector, blksize); + /* rs_same_csums is supposed to count in units of BM_BLOCK_SIZE */ + mdev->rs_same_csum += (blksize >> BM_BLOCK_SHIFT); + put_ldev(mdev); + } dec_rs_pending(mdev); + atomic_add(blksize >> 9, &mdev->rs_sect_in); return TRUE; } @@ -4259,7 +4381,7 @@ static int validate_req_change_req_state(struct drbd_conf *mdev, return TRUE; } -static int got_BlockAck(struct drbd_conf *mdev, struct p_header *h) +static int got_BlockAck(struct drbd_conf *mdev, struct p_header80 *h) { struct p_block_ack *p = (struct p_block_ack *)h; sector_t sector = be64_to_cpu(p->sector); @@ -4299,7 +4421,7 @@ static int got_BlockAck(struct drbd_conf *mdev, struct p_header *h) _ack_id_to_req, __func__ , what); } -static int got_NegAck(struct drbd_conf *mdev, struct p_header *h) +static int got_NegAck(struct drbd_conf *mdev, struct p_header80 *h) { struct p_block_ack *p = (struct p_block_ack *)h; sector_t sector = be64_to_cpu(p->sector); @@ -4319,7 +4441,7 @@ static int got_NegAck(struct drbd_conf *mdev, struct p_header *h) _ack_id_to_req, __func__ , neg_acked); } -static int got_NegDReply(struct drbd_conf *mdev, struct p_header *h) +static int got_NegDReply(struct drbd_conf *mdev, struct p_header80 *h) { struct p_block_ack *p = (struct p_block_ack *)h; sector_t sector = be64_to_cpu(p->sector); @@ -4332,7 +4454,7 @@ static int got_NegDReply(struct drbd_conf *mdev, struct p_header *h) _ar_id_to_req, __func__ , neg_acked); } -static int got_NegRSDReply(struct drbd_conf *mdev, struct p_header *h) +static int got_NegRSDReply(struct drbd_conf *mdev, struct p_header80 *h) { sector_t sector; int size; @@ -4354,7 +4476,7 @@ static int got_NegRSDReply(struct drbd_conf *mdev, struct p_header *h) return TRUE; } -static int got_BarrierAck(struct drbd_conf *mdev, struct p_header *h) +static int got_BarrierAck(struct drbd_conf *mdev, struct p_header80 *h) { struct p_barrier_ack *p = (struct p_barrier_ack *)h; @@ -4363,7 +4485,7 @@ static int got_BarrierAck(struct drbd_conf *mdev, struct p_header *h) return TRUE; } -static int got_OVResult(struct drbd_conf *mdev, struct p_header *h) +static int got_OVResult(struct drbd_conf *mdev, struct p_header80 *h) { struct p_block_ack *p = (struct p_block_ack *)h; struct drbd_work *w; @@ -4380,6 +4502,9 @@ static int got_OVResult(struct drbd_conf *mdev, struct p_header *h) else ov_oos_print(mdev); + if (!get_ldev(mdev)) + return TRUE; + drbd_rs_complete_io(mdev, sector); dec_rs_pending(mdev); @@ -4394,18 +4519,18 @@ static int got_OVResult(struct drbd_conf *mdev, struct p_header *h) drbd_resync_finished(mdev); } } + put_ldev(mdev); return TRUE; } -static int got_something_to_ignore_m(struct drbd_conf *mdev, struct p_header *h) +static int got_skip(struct drbd_conf *mdev, struct p_header80 *h) { - /* IGNORE */ return TRUE; } struct asender_cmd { size_t pkt_size; - int (*process)(struct drbd_conf *mdev, struct p_header *h); + int (*process)(struct drbd_conf *mdev, struct p_header80 *h); }; static struct asender_cmd *get_asender_cmd(int cmd) @@ -4414,8 +4539,8 @@ static struct asender_cmd *get_asender_cmd(int cmd) /* anything missing from this table is in * the drbd_cmd_handler (drbd_default_handler) table, * see the beginning of drbdd() */ - [P_PING] = { sizeof(struct p_header), got_Ping }, - [P_PING_ACK] = { sizeof(struct p_header), got_PingAck }, + [P_PING] = { sizeof(struct p_header80), got_Ping }, + [P_PING_ACK] = { sizeof(struct p_header80), got_PingAck }, [P_RECV_ACK] = { sizeof(struct p_block_ack), got_BlockAck }, [P_WRITE_ACK] = { sizeof(struct p_block_ack), got_BlockAck }, [P_RS_WRITE_ACK] = { sizeof(struct p_block_ack), got_BlockAck }, @@ -4427,7 +4552,7 @@ static struct asender_cmd *get_asender_cmd(int cmd) [P_BARRIER_ACK] = { sizeof(struct p_barrier_ack), got_BarrierAck }, [P_STATE_CHG_REPLY] = { sizeof(struct p_req_state_reply), got_RqSReply }, [P_RS_IS_IN_SYNC] = { sizeof(struct p_block_ack), got_IsInSync }, - [P_DELAY_PROBE] = { sizeof(struct p_delay_probe), got_something_to_ignore_m }, + [P_DELAY_PROBE] = { sizeof(struct p_delay_probe93), got_skip }, [P_MAX_CMD] = { 0, NULL }, }; if (cmd > P_MAX_CMD || asender_tbl[cmd].process == NULL) @@ -4438,13 +4563,13 @@ static struct asender_cmd *get_asender_cmd(int cmd) int drbd_asender(struct drbd_thread *thi) { struct drbd_conf *mdev = thi->mdev; - struct p_header *h = &mdev->meta.rbuf.header; + struct p_header80 *h = &mdev->meta.rbuf.header.h80; struct asender_cmd *cmd = NULL; int rv, len; void *buf = h; int received = 0; - int expect = sizeof(struct p_header); + int expect = sizeof(struct p_header80); int empty; sprintf(current->comm, "drbd%d_asender", mdev_to_minor(mdev)); @@ -4468,10 +4593,8 @@ int drbd_asender(struct drbd_thread *thi) while (1) { clear_bit(SIGNAL_ASENDER, &mdev->flags); flush_signals(current); - if (!drbd_process_done_ee(mdev)) { - dev_err(DEV, "process_done_ee() = NOT_OK\n"); + if (!drbd_process_done_ee(mdev)) goto reconnect; - } /* to avoid race with newly queued ACKs */ set_bit(SIGNAL_ASENDER, &mdev->flags); spin_lock_irq(&mdev->req_lock); @@ -4530,21 +4653,23 @@ int drbd_asender(struct drbd_thread *thi) if (received == expect && cmd == NULL) { if (unlikely(h->magic != BE_DRBD_MAGIC)) { - dev_err(DEV, "magic?? on meta m: 0x%lx c: %d l: %d\n", - (long)be32_to_cpu(h->magic), - h->command, h->length); + dev_err(DEV, "magic?? on meta m: 0x%08x c: %d l: %d\n", + be32_to_cpu(h->magic), + be16_to_cpu(h->command), + be16_to_cpu(h->length)); goto reconnect; } cmd = get_asender_cmd(be16_to_cpu(h->command)); len = be16_to_cpu(h->length); if (unlikely(cmd == NULL)) { - dev_err(DEV, "unknown command?? on meta m: 0x%lx c: %d l: %d\n", - (long)be32_to_cpu(h->magic), - h->command, h->length); + dev_err(DEV, "unknown command?? on meta m: 0x%08x c: %d l: %d\n", + be32_to_cpu(h->magic), + be16_to_cpu(h->command), + be16_to_cpu(h->length)); goto disconnect; } expect = cmd->pkt_size; - ERR_IF(len != expect-sizeof(struct p_header)) + ERR_IF(len != expect-sizeof(struct p_header80)) goto reconnect; } if (received == expect) { @@ -4554,7 +4679,7 @@ int drbd_asender(struct drbd_thread *thi) buf = h; received = 0; - expect = sizeof(struct p_header); + expect = sizeof(struct p_header80); cmd = NULL; } } @@ -4562,10 +4687,12 @@ int drbd_asender(struct drbd_thread *thi) if (0) { reconnect: drbd_force_state(mdev, NS(conn, C_NETWORK_FAILURE)); + drbd_md_sync(mdev); } if (0) { disconnect: drbd_force_state(mdev, NS(conn, C_DISCONNECTING)); + drbd_md_sync(mdev); } clear_bit(SIGNAL_ASENDER, &mdev->flags); diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index f761d98a4e90..9e91a2545fc8 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -59,17 +59,19 @@ static void _drbd_end_io_acct(struct drbd_conf *mdev, struct drbd_request *req) static void _req_is_done(struct drbd_conf *mdev, struct drbd_request *req, const int rw) { const unsigned long s = req->rq_state; + + /* remove it from the transfer log. + * well, only if it had been there in the first + * place... if it had not (local only or conflicting + * and never sent), it should still be "empty" as + * initialized in drbd_req_new(), so we can list_del() it + * here unconditionally */ + list_del(&req->tl_requests); + /* if it was a write, we may have to set the corresponding * bit(s) out-of-sync first. If it had a local part, we need to * release the reference to the activity log. */ if (rw == WRITE) { - /* remove it from the transfer log. - * well, only if it had been there in the first - * place... if it had not (local only or conflicting - * and never sent), it should still be "empty" as - * initialized in drbd_req_new(), so we can list_del() it - * here unconditionally */ - list_del(&req->tl_requests); /* Set out-of-sync unless both OK flags are set * (local only or remote failed). * Other places where we set out-of-sync: @@ -92,7 +94,8 @@ static void _req_is_done(struct drbd_conf *mdev, struct drbd_request *req, const */ if (s & RQ_LOCAL_MASK) { if (get_ldev_if_state(mdev, D_FAILED)) { - drbd_al_complete_io(mdev, req->sector); + if (s & RQ_IN_ACT_LOG) + drbd_al_complete_io(mdev, req->sector); put_ldev(mdev); } else if (__ratelimit(&drbd_ratelimit_state)) { dev_warn(DEV, "Should have called drbd_al_complete_io(, %llu), " @@ -280,6 +283,14 @@ void _req_may_be_done(struct drbd_request *req, struct bio_and_error *m) * protocol A or B, barrier ack still pending... */ } +static void _req_may_be_done_not_susp(struct drbd_request *req, struct bio_and_error *m) +{ + struct drbd_conf *mdev = req->mdev; + + if (!is_susp(mdev->state)) + _req_may_be_done(req, m); +} + /* * checks whether there was an overlapping request * or ee already registered. @@ -380,10 +391,11 @@ out_conflict: * and it enforces that we have to think in a very structured manner * about the "events" that may happen to a request during its life time ... */ -void __req_mod(struct drbd_request *req, enum drbd_req_event what, +int __req_mod(struct drbd_request *req, enum drbd_req_event what, struct bio_and_error *m) { struct drbd_conf *mdev = req->mdev; + int rv = 0; m->bio = NULL; switch (what) { @@ -420,7 +432,7 @@ void __req_mod(struct drbd_request *req, enum drbd_req_event what, req->rq_state |= (RQ_LOCAL_COMPLETED|RQ_LOCAL_OK); req->rq_state &= ~RQ_LOCAL_PENDING; - _req_may_be_done(req, m); + _req_may_be_done_not_susp(req, m); put_ldev(mdev); break; @@ -429,7 +441,7 @@ void __req_mod(struct drbd_request *req, enum drbd_req_event what, req->rq_state &= ~RQ_LOCAL_PENDING; __drbd_chk_io_error(mdev, FALSE); - _req_may_be_done(req, m); + _req_may_be_done_not_susp(req, m); put_ldev(mdev); break; @@ -437,7 +449,7 @@ void __req_mod(struct drbd_request *req, enum drbd_req_event what, /* it is legal to fail READA */ req->rq_state |= RQ_LOCAL_COMPLETED; req->rq_state &= ~RQ_LOCAL_PENDING; - _req_may_be_done(req, m); + _req_may_be_done_not_susp(req, m); put_ldev(mdev); break; @@ -455,7 +467,7 @@ void __req_mod(struct drbd_request *req, enum drbd_req_event what, /* no point in retrying if there is no good remote data, * or we have no connection. */ if (mdev->state.pdsk != D_UP_TO_DATE) { - _req_may_be_done(req, m); + _req_may_be_done_not_susp(req, m); break; } @@ -517,11 +529,9 @@ void __req_mod(struct drbd_request *req, enum drbd_req_event what, D_ASSERT(test_bit(CREATE_BARRIER, &mdev->flags) == 0); req->epoch = mdev->newest_tle->br_number; - list_add_tail(&req->tl_requests, - &mdev->newest_tle->requests); /* increment size of current epoch */ - mdev->newest_tle->n_req++; + mdev->newest_tle->n_writes++; /* queue work item to send data */ D_ASSERT(req->rq_state & RQ_NET_PENDING); @@ -530,7 +540,7 @@ void __req_mod(struct drbd_request *req, enum drbd_req_event what, drbd_queue_work(&mdev->data.work, &req->w); /* close the epoch, in case it outgrew the limit */ - if (mdev->newest_tle->n_req >= mdev->net_conf->max_epoch_size) + if (mdev->newest_tle->n_writes >= mdev->net_conf->max_epoch_size) queue_barrier(mdev); break; @@ -543,7 +553,7 @@ void __req_mod(struct drbd_request *req, enum drbd_req_event what, req->rq_state &= ~RQ_NET_QUEUED; /* if we did it right, tl_clear should be scheduled only after * this, so this should not be necessary! */ - _req_may_be_done(req, m); + _req_may_be_done_not_susp(req, m); break; case handed_over_to_network: @@ -568,7 +578,7 @@ void __req_mod(struct drbd_request *req, enum drbd_req_event what, * "completed_ok" events came in, once we return from * _drbd_send_zc_bio (drbd_send_dblock), we have to check * whether it is done already, and end it. */ - _req_may_be_done(req, m); + _req_may_be_done_not_susp(req, m); break; case read_retry_remote_canceled: @@ -584,7 +594,7 @@ void __req_mod(struct drbd_request *req, enum drbd_req_event what, /* if it is still queued, we may not complete it here. * it will be canceled soon. */ if (!(req->rq_state & RQ_NET_QUEUED)) - _req_may_be_done(req, m); + _req_may_be_done(req, m); /* Allowed while state.susp */ break; case write_acked_by_peer_and_sis: @@ -619,7 +629,7 @@ void __req_mod(struct drbd_request *req, enum drbd_req_event what, D_ASSERT(req->rq_state & RQ_NET_PENDING); dec_ap_pending(mdev); req->rq_state &= ~RQ_NET_PENDING; - _req_may_be_done(req, m); + _req_may_be_done_not_susp(req, m); break; case neg_acked: @@ -629,11 +639,50 @@ void __req_mod(struct drbd_request *req, enum drbd_req_event what, req->rq_state &= ~(RQ_NET_OK|RQ_NET_PENDING); req->rq_state |= RQ_NET_DONE; - _req_may_be_done(req, m); + _req_may_be_done_not_susp(req, m); /* else: done by handed_over_to_network */ break; + case fail_frozen_disk_io: + if (!(req->rq_state & RQ_LOCAL_COMPLETED)) + break; + + _req_may_be_done(req, m); /* Allowed while state.susp */ + break; + + case restart_frozen_disk_io: + if (!(req->rq_state & RQ_LOCAL_COMPLETED)) + break; + + req->rq_state &= ~RQ_LOCAL_COMPLETED; + + rv = MR_READ; + if (bio_data_dir(req->master_bio) == WRITE) + rv = MR_WRITE; + + get_ldev(mdev); + req->w.cb = w_restart_disk_io; + drbd_queue_work(&mdev->data.work, &req->w); + break; + + case resend: + /* If RQ_NET_OK is already set, we got a P_WRITE_ACK or P_RECV_ACK + before the connection loss (B&C only); only P_BARRIER_ACK was missing. + Trowing them out of the TL here by pretending we got a BARRIER_ACK + We ensure that the peer was not rebooted */ + if (!(req->rq_state & RQ_NET_OK)) { + if (req->w.cb) { + drbd_queue_work(&mdev->data.work, &req->w); + rv = req->rq_state & RQ_WRITE ? MR_WRITE : MR_READ; + } + break; + } + /* else, fall through to barrier_acked */ + case barrier_acked: + if (!(req->rq_state & RQ_WRITE)) + break; + if (req->rq_state & RQ_NET_PENDING) { /* barrier came in before all requests have been acked. * this is bad, because if the connection is lost now, @@ -643,7 +692,7 @@ void __req_mod(struct drbd_request *req, enum drbd_req_event what, } D_ASSERT(req->rq_state & RQ_NET_SENT); req->rq_state |= RQ_NET_DONE; - _req_may_be_done(req, m); + _req_may_be_done(req, m); /* Allowed while state.susp */ break; case data_received: @@ -651,9 +700,11 @@ void __req_mod(struct drbd_request *req, enum drbd_req_event what, dec_ap_pending(mdev); req->rq_state &= ~RQ_NET_PENDING; req->rq_state |= (RQ_NET_OK|RQ_NET_DONE); - _req_may_be_done(req, m); + _req_may_be_done_not_susp(req, m); break; }; + + return rv; } /* we may do a local read if: @@ -752,14 +803,16 @@ static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio) * resync extent to finish, and, if necessary, pulls in the target * extent into the activity log, which involves further disk io because * of transactional on-disk meta data updates. */ - if (rw == WRITE && local) + if (rw == WRITE && local && !test_bit(AL_SUSPENDED, &mdev->flags)) { + req->rq_state |= RQ_IN_ACT_LOG; drbd_al_begin_io(mdev, sector); + } remote = remote && (mdev->state.pdsk == D_UP_TO_DATE || (mdev->state.pdsk == D_INCONSISTENT && mdev->state.conn >= C_CONNECTED)); - if (!(local || remote) && !mdev->state.susp) { + if (!(local || remote) && !is_susp(mdev->state)) { dev_err(DEV, "IO ERROR: neither local nor remote disk\n"); goto fail_free_complete; } @@ -785,7 +838,7 @@ allocate_barrier: /* GOOD, everything prepared, grab the spin_lock */ spin_lock_irq(&mdev->req_lock); - if (mdev->state.susp) { + if (is_susp(mdev->state)) { /* If we got suspended, use the retry mechanism of generic_make_request() to restart processing of this bio. In the next call to drbd_make_request_26 @@ -867,30 +920,10 @@ allocate_barrier: /* check this request on the collision detection hash tables. * if we have a conflict, just complete it here. * THINK do we want to check reads, too? (I don't think so...) */ - if (rw == WRITE && _req_conflicts(req)) { - /* this is a conflicting request. - * even though it may have been only _partially_ - * overlapping with one of the currently pending requests, - * without even submitting or sending it, we will - * pretend that it was successfully served right now. - */ - if (local) { - bio_put(req->private_bio); - req->private_bio = NULL; - drbd_al_complete_io(mdev, req->sector); - put_ldev(mdev); - local = 0; - } - if (remote) - dec_ap_pending(mdev); - _drbd_end_io_acct(mdev, req); - /* THINK: do we want to fail it (-EIO), or pretend success? */ - bio_endio(req->master_bio, 0); - req->master_bio = NULL; - dec_ap_bio(mdev); - drbd_req_free(req); - remote = 0; - } + if (rw == WRITE && _req_conflicts(req)) + goto fail_conflicting; + + list_add_tail(&req->tl_requests, &mdev->newest_tle->requests); /* NOTE remote first: to get the concurrent write detection right, * we must register the request before start of local IO. */ @@ -923,6 +956,21 @@ allocate_barrier: return 0; +fail_conflicting: + /* this is a conflicting request. + * even though it may have been only _partially_ + * overlapping with one of the currently pending requests, + * without even submitting or sending it, we will + * pretend that it was successfully served right now. + */ + _drbd_end_io_acct(mdev, req); + spin_unlock_irq(&mdev->req_lock); + if (remote) + dec_ap_pending(mdev); + /* THINK: do we want to fail it (-EIO), or pretend success? + * this pretends success. */ + err = 0; + fail_free_complete: if (rw == WRITE && local) drbd_al_complete_io(mdev, sector); @@ -961,21 +1009,6 @@ static int drbd_fail_request_early(struct drbd_conf *mdev, int is_write) return 1; } - /* - * Paranoia: we might have been primary, but sync target, or - * even diskless, then lost the connection. - * This should have been handled (panic? suspend?) somewhere - * else. But maybe it was not, so check again here. - * Caution: as long as we do not have a read/write lock on mdev, - * to serialize state changes, this is racy, since we may lose - * the connection *after* we test for the cstate. - */ - if (mdev->state.disk < D_UP_TO_DATE && mdev->state.pdsk < D_UP_TO_DATE) { - if (__ratelimit(&drbd_ratelimit_state)) - dev_err(DEV, "Sorry, I have no access to good data anymore.\n"); - return 1; - } - return 0; } diff --git a/drivers/block/drbd/drbd_req.h b/drivers/block/drbd/drbd_req.h index 02d575d24518..181ea0364822 100644 --- a/drivers/block/drbd/drbd_req.h +++ b/drivers/block/drbd/drbd_req.h @@ -104,6 +104,9 @@ enum drbd_req_event { read_ahead_completed_with_error, write_completed_with_error, completed_ok, + resend, + fail_frozen_disk_io, + restart_frozen_disk_io, nothing, /* for tracing only */ }; @@ -183,6 +186,12 @@ enum drbd_req_state_bits { /* keep this last, its for the RQ_NET_MASK */ __RQ_NET_MAX, + + /* Set when this is a write, clear for a read */ + __RQ_WRITE, + + /* Should call drbd_al_complete_io() for this request... */ + __RQ_IN_ACT_LOG, }; #define RQ_LOCAL_PENDING (1UL << __RQ_LOCAL_PENDING) @@ -201,6 +210,16 @@ enum drbd_req_state_bits { /* 0x1f8 */ #define RQ_NET_MASK (((1UL << __RQ_NET_MAX)-1) & ~RQ_LOCAL_MASK) +#define RQ_WRITE (1UL << __RQ_WRITE) +#define RQ_IN_ACT_LOG (1UL << __RQ_IN_ACT_LOG) + +/* For waking up the frozen transfer log mod_req() has to return if the request + should be counted in the epoch object*/ +#define MR_WRITE_SHIFT 0 +#define MR_WRITE (1 << MR_WRITE_SHIFT) +#define MR_READ_SHIFT 1 +#define MR_READ (1 << MR_READ_SHIFT) + /* epoch entries */ static inline struct hlist_head *ee_hash_slot(struct drbd_conf *mdev, sector_t sector) @@ -244,30 +263,36 @@ static inline struct drbd_request *_ar_id_to_req(struct drbd_conf *mdev, return NULL; } +static inline void drbd_req_make_private_bio(struct drbd_request *req, struct bio *bio_src) +{ + struct bio *bio; + bio = bio_clone(bio_src, GFP_NOIO); /* XXX cannot fail?? */ + + req->private_bio = bio; + + bio->bi_private = req; + bio->bi_end_io = drbd_endio_pri; + bio->bi_next = NULL; +} + static inline struct drbd_request *drbd_req_new(struct drbd_conf *mdev, struct bio *bio_src) { - struct bio *bio; struct drbd_request *req = mempool_alloc(drbd_request_mempool, GFP_NOIO); if (likely(req)) { - bio = bio_clone(bio_src, GFP_NOIO); /* XXX cannot fail?? */ + drbd_req_make_private_bio(req, bio_src); - req->rq_state = 0; + req->rq_state = bio_data_dir(bio_src) == WRITE ? RQ_WRITE : 0; req->mdev = mdev; req->master_bio = bio_src; - req->private_bio = bio; req->epoch = 0; - req->sector = bio->bi_sector; - req->size = bio->bi_size; + req->sector = bio_src->bi_sector; + req->size = bio_src->bi_size; req->start_time = jiffies; INIT_HLIST_NODE(&req->colision); INIT_LIST_HEAD(&req->tl_requests); INIT_LIST_HEAD(&req->w.list); - - bio->bi_private = req; - bio->bi_end_io = drbd_endio_pri; - bio->bi_next = NULL; } return req; } @@ -292,36 +317,43 @@ struct bio_and_error { extern void _req_may_be_done(struct drbd_request *req, struct bio_and_error *m); -extern void __req_mod(struct drbd_request *req, enum drbd_req_event what, +extern int __req_mod(struct drbd_request *req, enum drbd_req_event what, struct bio_and_error *m); extern void complete_master_bio(struct drbd_conf *mdev, struct bio_and_error *m); /* use this if you don't want to deal with calling complete_master_bio() * outside the spinlock, e.g. when walking some list on cleanup. */ -static inline void _req_mod(struct drbd_request *req, enum drbd_req_event what) +static inline int _req_mod(struct drbd_request *req, enum drbd_req_event what) { struct drbd_conf *mdev = req->mdev; struct bio_and_error m; + int rv; /* __req_mod possibly frees req, do not touch req after that! */ - __req_mod(req, what, &m); + rv = __req_mod(req, what, &m); if (m.bio) complete_master_bio(mdev, &m); + + return rv; } /* completion of master bio is outside of spinlock. * If you need it irqsave, do it your self! */ -static inline void req_mod(struct drbd_request *req, +static inline int req_mod(struct drbd_request *req, enum drbd_req_event what) { struct drbd_conf *mdev = req->mdev; struct bio_and_error m; + int rv; + spin_lock_irq(&mdev->req_lock); - __req_mod(req, what, &m); + rv = __req_mod(req, what, &m); spin_unlock_irq(&mdev->req_lock); if (m.bio) complete_master_bio(mdev, &m); + + return rv; } #endif diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index ca4a16cea2d8..108d58015cd1 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -39,8 +39,6 @@ #include "drbd_int.h" #include "drbd_req.h" -#define SLEEP_TIME (HZ/10) - static int w_make_ov_request(struct drbd_conf *mdev, struct drbd_work *w, int cancel); @@ -217,10 +215,8 @@ void drbd_endio_sec(struct bio *bio, int error) */ void drbd_endio_pri(struct bio *bio, int error) { - unsigned long flags; struct drbd_request *req = bio->bi_private; struct drbd_conf *mdev = req->mdev; - struct bio_and_error m; enum drbd_req_event what; int uptodate = bio_flagged(bio, BIO_UPTODATE); @@ -246,12 +242,7 @@ void drbd_endio_pri(struct bio *bio, int error) bio_put(req->private_bio); req->private_bio = ERR_PTR(error); - spin_lock_irqsave(&mdev->req_lock, flags); - __req_mod(req, what, &m); - spin_unlock_irqrestore(&mdev->req_lock, flags); - - if (m.bio) - complete_master_bio(mdev, &m); + req_mod(req, what); } int w_read_retry_remote(struct drbd_conf *mdev, struct drbd_work *w, int cancel) @@ -376,54 +367,145 @@ static int read_for_csum(struct drbd_conf *mdev, sector_t sector, int size) struct drbd_epoch_entry *e; if (!get_ldev(mdev)) - return 0; + return -EIO; + + if (drbd_rs_should_slow_down(mdev)) + goto defer; /* GFP_TRY, because if there is no memory available right now, this may * be rescheduled for later. It is "only" background resync, after all. */ e = drbd_alloc_ee(mdev, DRBD_MAGIC+0xbeef, sector, size, GFP_TRY); if (!e) - goto fail; + goto defer; + e->w.cb = w_e_send_csum; spin_lock_irq(&mdev->req_lock); list_add(&e->w.list, &mdev->read_ee); spin_unlock_irq(&mdev->req_lock); - e->w.cb = w_e_send_csum; + atomic_add(size >> 9, &mdev->rs_sect_ev); if (drbd_submit_ee(mdev, e, READ, DRBD_FAULT_RS_RD) == 0) - return 1; + return 0; + + /* drbd_submit_ee currently fails for one reason only: + * not being able to allocate enough bios. + * Is dropping the connection going to help? */ + spin_lock_irq(&mdev->req_lock); + list_del(&e->w.list); + spin_unlock_irq(&mdev->req_lock); drbd_free_ee(mdev, e); -fail: +defer: put_ldev(mdev); - return 2; + return -EAGAIN; } void resync_timer_fn(unsigned long data) { - unsigned long flags; struct drbd_conf *mdev = (struct drbd_conf *) data; int queue; - spin_lock_irqsave(&mdev->req_lock, flags); - - if (likely(!test_and_clear_bit(STOP_SYNC_TIMER, &mdev->flags))) { - queue = 1; - if (mdev->state.conn == C_VERIFY_S) - mdev->resync_work.cb = w_make_ov_request; - else - mdev->resync_work.cb = w_make_resync_request; - } else { + queue = 1; + switch (mdev->state.conn) { + case C_VERIFY_S: + mdev->resync_work.cb = w_make_ov_request; + break; + case C_SYNC_TARGET: + mdev->resync_work.cb = w_make_resync_request; + break; + default: queue = 0; mdev->resync_work.cb = w_resync_inactive; } - spin_unlock_irqrestore(&mdev->req_lock, flags); - /* harmless race: list_empty outside data.work.q_lock */ if (list_empty(&mdev->resync_work.list) && queue) drbd_queue_work(&mdev->data.work, &mdev->resync_work); } +static void fifo_set(struct fifo_buffer *fb, int value) +{ + int i; + + for (i = 0; i < fb->size; i++) + fb->values[i] = value; +} + +static int fifo_push(struct fifo_buffer *fb, int value) +{ + int ov; + + ov = fb->values[fb->head_index]; + fb->values[fb->head_index++] = value; + + if (fb->head_index >= fb->size) + fb->head_index = 0; + + return ov; +} + +static void fifo_add_val(struct fifo_buffer *fb, int value) +{ + int i; + + for (i = 0; i < fb->size; i++) + fb->values[i] += value; +} + +int drbd_rs_controller(struct drbd_conf *mdev) +{ + unsigned int sect_in; /* Number of sectors that came in since the last turn */ + unsigned int want; /* The number of sectors we want in the proxy */ + int req_sect; /* Number of sectors to request in this turn */ + int correction; /* Number of sectors more we need in the proxy*/ + int cps; /* correction per invocation of drbd_rs_controller() */ + int steps; /* Number of time steps to plan ahead */ + int curr_corr; + int max_sect; + + sect_in = atomic_xchg(&mdev->rs_sect_in, 0); /* Number of sectors that came in */ + mdev->rs_in_flight -= sect_in; + + spin_lock(&mdev->peer_seq_lock); /* get an atomic view on mdev->rs_plan_s */ + + steps = mdev->rs_plan_s.size; /* (mdev->sync_conf.c_plan_ahead * 10 * SLEEP_TIME) / HZ; */ + + if (mdev->rs_in_flight + sect_in == 0) { /* At start of resync */ + want = ((mdev->sync_conf.rate * 2 * SLEEP_TIME) / HZ) * steps; + } else { /* normal path */ + want = mdev->sync_conf.c_fill_target ? mdev->sync_conf.c_fill_target : + sect_in * mdev->sync_conf.c_delay_target * HZ / (SLEEP_TIME * 10); + } + + correction = want - mdev->rs_in_flight - mdev->rs_planed; + + /* Plan ahead */ + cps = correction / steps; + fifo_add_val(&mdev->rs_plan_s, cps); + mdev->rs_planed += cps * steps; + + /* What we do in this step */ + curr_corr = fifo_push(&mdev->rs_plan_s, 0); + spin_unlock(&mdev->peer_seq_lock); + mdev->rs_planed -= curr_corr; + + req_sect = sect_in + curr_corr; + if (req_sect < 0) + req_sect = 0; + + max_sect = (mdev->sync_conf.c_max_rate * 2 * SLEEP_TIME) / HZ; + if (req_sect > max_sect) + req_sect = max_sect; + + /* + dev_warn(DEV, "si=%u if=%d wa=%u co=%d st=%d cps=%d pl=%d cc=%d rs=%d\n", + sect_in, mdev->rs_in_flight, want, correction, + steps, cps, mdev->rs_planed, curr_corr, req_sect); + */ + + return req_sect; +} + int w_make_resync_request(struct drbd_conf *mdev, struct drbd_work *w, int cancel) { @@ -431,8 +513,9 @@ int w_make_resync_request(struct drbd_conf *mdev, sector_t sector; const sector_t capacity = drbd_get_capacity(mdev->this_bdev); int max_segment_size; - int number, i, size, pe, mx; + int number, rollback_i, size, pe, mx; int align, queued, sndbuf; + int i = 0; if (unlikely(cancel)) return 1; @@ -446,6 +529,12 @@ int w_make_resync_request(struct drbd_conf *mdev, dev_err(DEV, "%s in w_make_resync_request\n", drbd_conn_str(mdev->state.conn)); + if (mdev->rs_total == 0) { + /* empty resync? */ + drbd_resync_finished(mdev); + return 1; + } + if (!get_ldev(mdev)) { /* Since we only need to access mdev->rsync a get_ldev_if_state(mdev,D_FAILED) would be sufficient, but @@ -458,11 +547,25 @@ int w_make_resync_request(struct drbd_conf *mdev, /* starting with drbd 8.3.8, we can handle multi-bio EEs, * if it should be necessary */ - max_segment_size = mdev->agreed_pro_version < 94 ? - queue_max_segment_size(mdev->rq_queue) : DRBD_MAX_SEGMENT_SIZE; + max_segment_size = + mdev->agreed_pro_version < 94 ? queue_max_segment_size(mdev->rq_queue) : + mdev->agreed_pro_version < 95 ? DRBD_MAX_SIZE_H80_PACKET : DRBD_MAX_SEGMENT_SIZE; - number = SLEEP_TIME * mdev->sync_conf.rate / ((BM_BLOCK_SIZE / 1024) * HZ); - pe = atomic_read(&mdev->rs_pending_cnt); + if (mdev->rs_plan_s.size) { /* mdev->sync_conf.c_plan_ahead */ + number = drbd_rs_controller(mdev) >> (BM_BLOCK_SHIFT - 9); + mdev->c_sync_rate = number * HZ * (BM_BLOCK_SIZE / 1024) / SLEEP_TIME; + } else { + mdev->c_sync_rate = mdev->sync_conf.rate; + number = SLEEP_TIME * mdev->c_sync_rate / ((BM_BLOCK_SIZE / 1024) * HZ); + } + + /* Throttle resync on lower level disk activity, which may also be + * caused by application IO on Primary/SyncTarget. + * Keep this after the call to drbd_rs_controller, as that assumes + * to be called as precisely as possible every SLEEP_TIME, + * and would be confused otherwise. */ + if (drbd_rs_should_slow_down(mdev)) + goto requeue; mutex_lock(&mdev->data.mutex); if (mdev->data.socket) @@ -476,6 +579,7 @@ int w_make_resync_request(struct drbd_conf *mdev, mx = number; /* Limit the number of pending RS requests to no more than the peer's receive buffer */ + pe = atomic_read(&mdev->rs_pending_cnt); if ((pe + number) > mx) { number = mx - pe; } @@ -526,6 +630,7 @@ next_sector: * be prepared for all stripe sizes of software RAIDs. */ align = 1; + rollback_i = i; for (;;) { if (size + BM_BLOCK_SIZE > max_segment_size) break; @@ -561,14 +666,19 @@ next_sector: size = (capacity-sector)<<9; if (mdev->agreed_pro_version >= 89 && mdev->csums_tfm) { switch (read_for_csum(mdev, sector, size)) { - case 0: /* Disk failure*/ + case -EIO: /* Disk failure */ put_ldev(mdev); return 0; - case 2: /* Allocation failed */ + case -EAGAIN: /* allocation failed, or ldev busy */ drbd_rs_complete_io(mdev, sector); mdev->bm_resync_fo = BM_SECT_TO_BIT(sector); + i = rollback_i; goto requeue; - /* case 1: everything ok */ + case 0: + /* everything ok */ + break; + default: + BUG(); } } else { inc_rs_pending(mdev); @@ -595,6 +705,7 @@ next_sector: } requeue: + mdev->rs_in_flight += (i << (BM_BLOCK_SHIFT - 9)); mod_timer(&mdev->resync_timer, jiffies + SLEEP_TIME); put_ldev(mdev); return 1; @@ -670,6 +781,14 @@ static int w_resync_finished(struct drbd_conf *mdev, struct drbd_work *w, int ca return 1; } +static void ping_peer(struct drbd_conf *mdev) +{ + clear_bit(GOT_PING_ACK, &mdev->flags); + request_ping(mdev); + wait_event(mdev->misc_wait, + test_bit(GOT_PING_ACK, &mdev->flags) || mdev->state.conn < C_CONNECTED); +} + int drbd_resync_finished(struct drbd_conf *mdev) { unsigned long db, dt, dbdt; @@ -709,6 +828,8 @@ int drbd_resync_finished(struct drbd_conf *mdev) if (!get_ldev(mdev)) goto out; + ping_peer(mdev); + spin_lock_irq(&mdev->req_lock); os = mdev->state; @@ -801,6 +922,8 @@ out: mdev->rs_paused = 0; mdev->ov_start_sector = 0; + drbd_md_sync(mdev); + if (test_and_clear_bit(WRITE_BM_AFTER_RESYNC, &mdev->flags)) { dev_warn(DEV, "Writing the whole bitmap, due to failed kmalloc\n"); drbd_queue_bitmap_io(mdev, &drbd_bm_write, NULL, "write from resync_finished"); @@ -817,9 +940,13 @@ static void move_to_net_ee_or_free(struct drbd_conf *mdev, struct drbd_epoch_ent { if (drbd_ee_has_active_page(e)) { /* This might happen if sendpage() has not finished */ + int i = (e->size + PAGE_SIZE -1) >> PAGE_SHIFT; + atomic_add(i, &mdev->pp_in_use_by_net); + atomic_sub(i, &mdev->pp_in_use); spin_lock_irq(&mdev->req_lock); list_add_tail(&e->w.list, &mdev->net_ee); spin_unlock_irq(&mdev->req_lock); + wake_up(&drbd_pp_wait); } else drbd_free_ee(mdev, e); } @@ -926,9 +1053,12 @@ int w_e_end_csum_rs_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) return 1; } - drbd_rs_complete_io(mdev, e->sector); + if (get_ldev(mdev)) { + drbd_rs_complete_io(mdev, e->sector); + put_ldev(mdev); + } - di = (struct digest_info *)(unsigned long)e->block_id; + di = e->digest; if (likely((e->flags & EE_WAS_ERROR) == 0)) { /* quick hack to try to avoid a race against reconfiguration. @@ -952,7 +1082,9 @@ int w_e_end_csum_rs_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) ok = drbd_send_ack(mdev, P_RS_IS_IN_SYNC, e); } else { inc_rs_pending(mdev); - e->block_id = ID_SYNCER; + e->block_id = ID_SYNCER; /* By setting block_id, digest pointer becomes invalid! */ + e->flags &= ~EE_HAS_DIGEST; /* This e no longer has a digest pointer */ + kfree(di); ok = drbd_send_block(mdev, P_RS_DATA_REPLY, e); } } else { @@ -962,9 +1094,6 @@ int w_e_end_csum_rs_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) } dec_unacked(mdev); - - kfree(di); - move_to_net_ee_or_free(mdev, e); if (unlikely(!ok)) @@ -1034,9 +1163,12 @@ int w_e_end_ov_reply(struct drbd_conf *mdev, struct drbd_work *w, int cancel) /* after "cancel", because after drbd_disconnect/drbd_rs_cancel_all * the resync lru has been cleaned up already */ - drbd_rs_complete_io(mdev, e->sector); + if (get_ldev(mdev)) { + drbd_rs_complete_io(mdev, e->sector); + put_ldev(mdev); + } - di = (struct digest_info *)(unsigned long)e->block_id; + di = e->digest; if (likely((e->flags & EE_WAS_ERROR) == 0)) { digest_size = crypto_hash_digestsize(mdev->verify_tfm); @@ -1055,9 +1187,6 @@ int w_e_end_ov_reply(struct drbd_conf *mdev, struct drbd_work *w, int cancel) } dec_unacked(mdev); - - kfree(di); - if (!eq) drbd_ov_oos_found(mdev, e->sector, e->size); else @@ -1108,7 +1237,7 @@ int w_send_barrier(struct drbd_conf *mdev, struct drbd_work *w, int cancel) * dec_ap_pending will be done in got_BarrierAck * or (on connection loss) in w_clear_epoch. */ ok = _drbd_send_cmd(mdev, mdev->data.socket, P_BARRIER, - (struct p_header *)p, sizeof(*p), 0); + (struct p_header80 *)p, sizeof(*p), 0); drbd_put_data_sock(mdev); return ok; @@ -1173,6 +1302,24 @@ int w_send_read_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) return ok; } +int w_restart_disk_io(struct drbd_conf *mdev, struct drbd_work *w, int cancel) +{ + struct drbd_request *req = container_of(w, struct drbd_request, w); + + if (bio_data_dir(req->master_bio) == WRITE && req->rq_state & RQ_IN_ACT_LOG) + drbd_al_begin_io(mdev, req->sector); + /* Calling drbd_al_begin_io() out of the worker might deadlocks + theoretically. Practically it can not deadlock, since this is + only used when unfreezing IOs. All the extents of the requests + that made it into the TL are already active */ + + drbd_req_make_private_bio(req, req->master_bio); + req->private_bio->bi_bdev = mdev->ldev->backing_bdev; + generic_make_request(req->private_bio); + + return 1; +} + static int _drbd_may_sync_now(struct drbd_conf *mdev) { struct drbd_conf *odev = mdev; @@ -1298,14 +1445,6 @@ int drbd_alter_sa(struct drbd_conf *mdev, int na) return retcode; } -static void ping_peer(struct drbd_conf *mdev) -{ - clear_bit(GOT_PING_ACK, &mdev->flags); - request_ping(mdev); - wait_event(mdev->misc_wait, - test_bit(GOT_PING_ACK, &mdev->flags) || mdev->state.conn < C_CONNECTED); -} - /** * drbd_start_resync() - Start the resync process * @mdev: DRBD device. @@ -1379,13 +1518,21 @@ void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side) r = SS_UNKNOWN_ERROR; if (r == SS_SUCCESS) { - mdev->rs_total = - mdev->rs_mark_left = drbd_bm_total_weight(mdev); + unsigned long tw = drbd_bm_total_weight(mdev); + unsigned long now = jiffies; + int i; + mdev->rs_failed = 0; mdev->rs_paused = 0; - mdev->rs_start = - mdev->rs_mark_time = jiffies; mdev->rs_same_csum = 0; + mdev->rs_last_events = 0; + mdev->rs_last_sect_ev = 0; + mdev->rs_total = tw; + mdev->rs_start = now; + for (i = 0; i < DRBD_SYNC_MARKS; i++) { + mdev->rs_mark_left[i] = tw; + mdev->rs_mark_time[i] = now; + } _drbd_pause_after(mdev); } write_unlock_irq(&global_state_lock); @@ -1397,12 +1544,31 @@ void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side) (unsigned long) mdev->rs_total << (BM_BLOCK_SHIFT-10), (unsigned long) mdev->rs_total); - if (mdev->rs_total == 0) { - /* Peer still reachable? Beware of failing before-resync-target handlers! */ - ping_peer(mdev); + if (mdev->agreed_pro_version < 95 && mdev->rs_total == 0) { + /* This still has a race (about when exactly the peers + * detect connection loss) that can lead to a full sync + * on next handshake. In 8.3.9 we fixed this with explicit + * resync-finished notifications, but the fix + * introduces a protocol change. Sleeping for some + * time longer than the ping interval + timeout on the + * SyncSource, to give the SyncTarget the chance to + * detect connection loss, then waiting for a ping + * response (implicit in drbd_resync_finished) reduces + * the race considerably, but does not solve it. */ + if (side == C_SYNC_SOURCE) + schedule_timeout_interruptible( + mdev->net_conf->ping_int * HZ + + mdev->net_conf->ping_timeo*HZ/9); drbd_resync_finished(mdev); } + atomic_set(&mdev->rs_sect_in, 0); + atomic_set(&mdev->rs_sect_ev, 0); + mdev->rs_in_flight = 0; + mdev->rs_planed = 0; + spin_lock(&mdev->peer_seq_lock); + fifo_set(&mdev->rs_plan_s, 0); + spin_unlock(&mdev->peer_seq_lock); /* ns.conn may already be != mdev->state.conn, * we may have been paused in between, or become paused until * the timer triggers. diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index cf04c1b234ed..767107cce982 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -178,7 +178,6 @@ static int print_unex = 1; #include <linux/slab.h> #include <linux/mm.h> #include <linux/bio.h> -#include <linux/smp_lock.h> #include <linux/string.h> #include <linux/jiffies.h> #include <linux/fcntl.h> @@ -199,6 +198,7 @@ static int print_unex = 1; * It's been recommended that take about 1/4 of the default speed * in some more extreme cases. */ +static DEFINE_MUTEX(floppy_mutex); static int slow_floppy; #include <asm/dma.h> @@ -258,8 +258,8 @@ static int irqdma_allocated; #include <linux/completion.h> static struct request *current_req; -static struct request_queue *floppy_queue; static void do_fd_request(struct request_queue *q); +static int set_next_request(void); #ifndef fd_get_dma_residue #define fd_get_dma_residue() get_dma_residue(FLOPPY_DMA) @@ -413,6 +413,7 @@ static struct gendisk *disks[N_DRIVE]; static struct block_device *opened_bdev[N_DRIVE]; static DEFINE_MUTEX(open_lock); static struct floppy_raw_cmd *raw_cmd, default_raw_cmd; +static int fdc_queue; /* * This struct defines the different floppy types. @@ -890,8 +891,8 @@ static void unlock_fdc(void) del_timer(&fd_timeout); cont = NULL; clear_bit(0, &fdc_busy); - if (current_req || blk_peek_request(floppy_queue)) - do_fd_request(floppy_queue); + if (current_req || set_next_request()) + do_fd_request(current_req->q); spin_unlock_irqrestore(&floppy_lock, flags); wake_up(&fdc_wait); } @@ -2243,8 +2244,8 @@ static void floppy_end_request(struct request *req, int error) * logical buffer */ static void request_done(int uptodate) { - struct request_queue *q = floppy_queue; struct request *req = current_req; + struct request_queue *q; unsigned long flags; int block; char msg[sizeof("request done ") + sizeof(int) * 3]; @@ -2258,6 +2259,8 @@ static void request_done(int uptodate) return; } + q = req->q; + if (uptodate) { /* maintain values for invalidation on geometry * change */ @@ -2811,6 +2814,28 @@ static int make_raw_rw_request(void) return 2; } +/* + * Round-robin between our available drives, doing one request from each + */ +static int set_next_request(void) +{ + struct request_queue *q; + int old_pos = fdc_queue; + + do { + q = disks[fdc_queue]->queue; + if (++fdc_queue == N_DRIVE) + fdc_queue = 0; + if (q) { + current_req = blk_fetch_request(q); + if (current_req) + break; + } + } while (fdc_queue != old_pos); + + return current_req != NULL; +} + static void redo_fd_request(void) { int drive; @@ -2822,17 +2847,17 @@ static void redo_fd_request(void) do_request: if (!current_req) { - struct request *req; + int pending; + + spin_lock_irq(&floppy_lock); + pending = set_next_request(); + spin_unlock_irq(&floppy_lock); - spin_lock_irq(floppy_queue->queue_lock); - req = blk_fetch_request(floppy_queue); - spin_unlock_irq(floppy_queue->queue_lock); - if (!req) { + if (!pending) { do_floppy = NULL; unlock_fdc(); return; } - current_req = req; } drive = (long)current_req->rq_disk->private_data; set_fdc(drive); @@ -3553,9 +3578,9 @@ static int fd_ioctl(struct block_device *bdev, fmode_t mode, { int ret; - lock_kernel(); + mutex_lock(&floppy_mutex); ret = fd_locked_ioctl(bdev, mode, cmd, param); - unlock_kernel(); + mutex_unlock(&floppy_mutex); return ret; } @@ -3616,7 +3641,7 @@ static int floppy_release(struct gendisk *disk, fmode_t mode) { int drive = (long)disk->private_data; - lock_kernel(); + mutex_lock(&floppy_mutex); mutex_lock(&open_lock); if (UDRS->fd_ref < 0) UDRS->fd_ref = 0; @@ -3627,7 +3652,7 @@ static int floppy_release(struct gendisk *disk, fmode_t mode) if (!UDRS->fd_ref) opened_bdev[drive] = NULL; mutex_unlock(&open_lock); - unlock_kernel(); + mutex_unlock(&floppy_mutex); return 0; } @@ -3645,7 +3670,7 @@ static int floppy_open(struct block_device *bdev, fmode_t mode) int res = -EBUSY; char *tmp; - lock_kernel(); + mutex_lock(&floppy_mutex); mutex_lock(&open_lock); old_dev = UDRS->fd_device; if (opened_bdev[drive] && opened_bdev[drive] != bdev) @@ -3722,7 +3747,7 @@ static int floppy_open(struct block_device *bdev, fmode_t mode) goto out; } mutex_unlock(&open_lock); - unlock_kernel(); + mutex_unlock(&floppy_mutex); return 0; out: if (UDRS->fd_ref < 0) @@ -3733,7 +3758,7 @@ out: opened_bdev[drive] = NULL; out2: mutex_unlock(&open_lock); - unlock_kernel(); + mutex_unlock(&floppy_mutex); return res; } @@ -4165,6 +4190,13 @@ static int __init floppy_init(void) goto out_put_disk; } + disks[dr]->queue = blk_init_queue(do_fd_request, &floppy_lock); + if (!disks[dr]->queue) { + err = -ENOMEM; + goto out_put_disk; + } + + blk_queue_max_hw_sectors(disks[dr]->queue, 64); disks[dr]->major = FLOPPY_MAJOR; disks[dr]->first_minor = TOMINOR(dr); disks[dr]->fops = &floppy_fops; @@ -4183,13 +4215,6 @@ static int __init floppy_init(void) if (err) goto out_unreg_blkdev; - floppy_queue = blk_init_queue(do_fd_request, &floppy_lock); - if (!floppy_queue) { - err = -ENOMEM; - goto out_unreg_driver; - } - blk_queue_max_hw_sectors(floppy_queue, 64); - blk_register_region(MKDEV(FLOPPY_MAJOR, 0), 256, THIS_MODULE, floppy_find, NULL, NULL); @@ -4317,7 +4342,6 @@ static int __init floppy_init(void) /* to be cleaned up... */ disks[drive]->private_data = (void *)(long)drive; - disks[drive]->queue = floppy_queue; disks[drive]->flags |= GENHD_FL_REMOVABLE; disks[drive]->driverfs_dev = &floppy_device[drive].dev; add_disk(disks[drive]); @@ -4333,8 +4357,6 @@ out_flush_work: floppy_release_irq_and_dma(); out_unreg_region: blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256); - blk_cleanup_queue(floppy_queue); -out_unreg_driver: platform_driver_unregister(&floppy_driver); out_unreg_blkdev: unregister_blkdev(FLOPPY_MAJOR, "fd"); @@ -4342,6 +4364,8 @@ out_put_disk: while (dr--) { del_timer(&motor_off_timer[dr]); put_disk(disks[dr]); + if (disks[dr]->queue) + blk_cleanup_queue(disks[dr]->queue); } return err; } @@ -4550,11 +4574,11 @@ static void __exit floppy_module_exit(void) platform_device_unregister(&floppy_device[drive]); } put_disk(disks[drive]); + blk_cleanup_queue(disks[drive]->queue); } del_timer_sync(&fd_timeout); del_timer_sync(&fd_timer); - blk_cleanup_queue(floppy_queue); if (atomic_read(&usage_count)) floppy_release_irq_and_dma(); diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 91797bbbe702..6c48b3545f84 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -67,16 +67,18 @@ #include <linux/compat.h> #include <linux/suspend.h> #include <linux/freezer.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/writeback.h> #include <linux/buffer_head.h> /* for invalidate_bdev() */ #include <linux/completion.h> #include <linux/highmem.h> #include <linux/kthread.h> #include <linux/splice.h> +#include <linux/sysfs.h> #include <asm/uaccess.h> +static DEFINE_MUTEX(loop_mutex); static LIST_HEAD(loop_devices); static DEFINE_MUTEX(loop_devices_mutex); @@ -477,17 +479,17 @@ static int do_bio_filebacked(struct loop_device *lo, struct bio *bio) pos = ((loff_t) bio->bi_sector << 9) + lo->lo_offset; if (bio_rw(bio) == WRITE) { - bool barrier = !!(bio->bi_rw & REQ_HARDBARRIER); struct file *file = lo->lo_backing_file; - if (barrier) { - if (unlikely(!file->f_op->fsync)) { - ret = -EOPNOTSUPP; - goto out; - } + /* REQ_HARDBARRIER is deprecated */ + if (bio->bi_rw & REQ_HARDBARRIER) { + ret = -EOPNOTSUPP; + goto out; + } + if (bio->bi_rw & REQ_FLUSH) { ret = vfs_fsync(file, 0); - if (unlikely(ret)) { + if (unlikely(ret && ret != -EINVAL)) { ret = -EIO; goto out; } @@ -495,9 +497,9 @@ static int do_bio_filebacked(struct loop_device *lo, struct bio *bio) ret = lo_send(lo, bio, pos); - if (barrier && !ret) { + if ((bio->bi_rw & REQ_FUA) && !ret) { ret = vfs_fsync(file, 0); - if (unlikely(ret)) + if (unlikely(ret && ret != -EINVAL)) ret = -EIO; } } else @@ -737,6 +739,103 @@ static inline int is_loop_device(struct file *file) return i && S_ISBLK(i->i_mode) && MAJOR(i->i_rdev) == LOOP_MAJOR; } +/* loop sysfs attributes */ + +static ssize_t loop_attr_show(struct device *dev, char *page, + ssize_t (*callback)(struct loop_device *, char *)) +{ + struct loop_device *l, *lo = NULL; + + mutex_lock(&loop_devices_mutex); + list_for_each_entry(l, &loop_devices, lo_list) + if (disk_to_dev(l->lo_disk) == dev) { + lo = l; + break; + } + mutex_unlock(&loop_devices_mutex); + + return lo ? callback(lo, page) : -EIO; +} + +#define LOOP_ATTR_RO(_name) \ +static ssize_t loop_attr_##_name##_show(struct loop_device *, char *); \ +static ssize_t loop_attr_do_show_##_name(struct device *d, \ + struct device_attribute *attr, char *b) \ +{ \ + return loop_attr_show(d, b, loop_attr_##_name##_show); \ +} \ +static struct device_attribute loop_attr_##_name = \ + __ATTR(_name, S_IRUGO, loop_attr_do_show_##_name, NULL); + +static ssize_t loop_attr_backing_file_show(struct loop_device *lo, char *buf) +{ + ssize_t ret; + char *p = NULL; + + mutex_lock(&lo->lo_ctl_mutex); + if (lo->lo_backing_file) + p = d_path(&lo->lo_backing_file->f_path, buf, PAGE_SIZE - 1); + mutex_unlock(&lo->lo_ctl_mutex); + + if (IS_ERR_OR_NULL(p)) + ret = PTR_ERR(p); + else { + ret = strlen(p); + memmove(buf, p, ret); + buf[ret++] = '\n'; + buf[ret] = 0; + } + + return ret; +} + +static ssize_t loop_attr_offset_show(struct loop_device *lo, char *buf) +{ + return sprintf(buf, "%llu\n", (unsigned long long)lo->lo_offset); +} + +static ssize_t loop_attr_sizelimit_show(struct loop_device *lo, char *buf) +{ + return sprintf(buf, "%llu\n", (unsigned long long)lo->lo_sizelimit); +} + +static ssize_t loop_attr_autoclear_show(struct loop_device *lo, char *buf) +{ + int autoclear = (lo->lo_flags & LO_FLAGS_AUTOCLEAR); + + return sprintf(buf, "%s\n", autoclear ? "1" : "0"); +} + +LOOP_ATTR_RO(backing_file); +LOOP_ATTR_RO(offset); +LOOP_ATTR_RO(sizelimit); +LOOP_ATTR_RO(autoclear); + +static struct attribute *loop_attrs[] = { + &loop_attr_backing_file.attr, + &loop_attr_offset.attr, + &loop_attr_sizelimit.attr, + &loop_attr_autoclear.attr, + NULL, +}; + +static struct attribute_group loop_attribute_group = { + .name = "loop", + .attrs= loop_attrs, +}; + +static int loop_sysfs_init(struct loop_device *lo) +{ + return sysfs_create_group(&disk_to_dev(lo->lo_disk)->kobj, + &loop_attribute_group); +} + +static void loop_sysfs_exit(struct loop_device *lo) +{ + sysfs_remove_group(&disk_to_dev(lo->lo_disk)->kobj, + &loop_attribute_group); +} + static int loop_set_fd(struct loop_device *lo, fmode_t mode, struct block_device *bdev, unsigned int arg) { @@ -832,10 +931,11 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode, lo->lo_queue->unplug_fn = loop_unplug; if (!(lo_flags & LO_FLAGS_READ_ONLY) && file->f_op->fsync) - blk_queue_ordered(lo->lo_queue, QUEUE_ORDERED_DRAIN); + blk_queue_flush(lo->lo_queue, REQ_FLUSH); set_capacity(lo->lo_disk, size); bd_set_size(bdev, size << 9); + loop_sysfs_init(lo); /* let user-space know about the new size */ kobject_uevent(&disk_to_dev(bdev->bd_disk)->kobj, KOBJ_CHANGE); @@ -854,6 +954,7 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode, return 0; out_clr: + loop_sysfs_exit(lo); lo->lo_thread = NULL; lo->lo_device = NULL; lo->lo_backing_file = NULL; @@ -950,6 +1051,7 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev) set_capacity(lo->lo_disk, 0); if (bdev) { bd_set_size(bdev, 0); + loop_sysfs_exit(lo); /* let user-space know about this change */ kobject_uevent(&disk_to_dev(bdev->bd_disk)->kobj, KOBJ_CHANGE); } @@ -1409,11 +1511,11 @@ static int lo_open(struct block_device *bdev, fmode_t mode) { struct loop_device *lo = bdev->bd_disk->private_data; - lock_kernel(); + mutex_lock(&loop_mutex); mutex_lock(&lo->lo_ctl_mutex); lo->lo_refcnt++; mutex_unlock(&lo->lo_ctl_mutex); - unlock_kernel(); + mutex_unlock(&loop_mutex); return 0; } @@ -1423,7 +1525,7 @@ static int lo_release(struct gendisk *disk, fmode_t mode) struct loop_device *lo = disk->private_data; int err; - lock_kernel(); + mutex_lock(&loop_mutex); mutex_lock(&lo->lo_ctl_mutex); if (--lo->lo_refcnt) @@ -1448,7 +1550,7 @@ static int lo_release(struct gendisk *disk, fmode_t mode) out: mutex_unlock(&lo->lo_ctl_mutex); out_unlocked: - lock_kernel(); + mutex_unlock(&loop_mutex); return 0; } diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 0daa422aa281..a32fb41246f8 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -24,7 +24,7 @@ #include <linux/errno.h> #include <linux/file.h> #include <linux/ioctl.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/compiler.h> #include <linux/err.h> #include <linux/kernel.h> @@ -53,6 +53,7 @@ #define DBG_BLKDEV 0x0100 #define DBG_RX 0x0200 #define DBG_TX 0x0400 +static DEFINE_MUTEX(nbd_mutex); static unsigned int debugflags; #endif /* NDEBUG */ @@ -717,11 +718,11 @@ static int nbd_ioctl(struct block_device *bdev, fmode_t mode, dprintk(DBG_IOCTL, "%s: nbd_ioctl cmd=%s(0x%x) arg=%lu\n", lo->disk->disk_name, ioctl_cmd_to_ascii(cmd), cmd, arg); - lock_kernel(); + mutex_lock(&nbd_mutex); mutex_lock(&lo->tx_lock); error = __nbd_ioctl(bdev, lo, cmd, arg); mutex_unlock(&lo->tx_lock); - unlock_kernel(); + mutex_unlock(&nbd_mutex); return error; } diff --git a/drivers/block/osdblk.c b/drivers/block/osdblk.c index 2284b4f05c62..87311ebac0db 100644 --- a/drivers/block/osdblk.c +++ b/drivers/block/osdblk.c @@ -310,8 +310,7 @@ static void osdblk_rq_fn(struct request_queue *q) break; /* filter out block requests we don't understand */ - if (rq->cmd_type != REQ_TYPE_FS && - !(rq->cmd_flags & REQ_HARDBARRIER)) { + if (rq->cmd_type != REQ_TYPE_FS) { blk_end_request_all(rq, 0); continue; } @@ -439,7 +438,7 @@ static int osdblk_init_disk(struct osdblk_device *osdev) blk_queue_stack_limits(q, osd_request_queue(osdev->osd)); blk_queue_prep_rq(q, blk_queue_start_tag); - blk_queue_ordered(q, QUEUE_ORDERED_DRAIN_FLUSH); + blk_queue_flush(q, REQ_FLUSH); disk->queue = q; diff --git a/drivers/block/paride/pcd.c b/drivers/block/paride/pcd.c index 76f8565e1e8d..62cec6afd7ad 100644 --- a/drivers/block/paride/pcd.c +++ b/drivers/block/paride/pcd.c @@ -138,9 +138,10 @@ enum {D_PRT, D_PRO, D_UNI, D_MOD, D_SLV, D_DLY}; #include <linux/cdrom.h> #include <linux/spinlock.h> #include <linux/blkdev.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <asm/uaccess.h> +static DEFINE_MUTEX(pcd_mutex); static DEFINE_SPINLOCK(pcd_lock); module_param(verbose, bool, 0644); @@ -227,9 +228,9 @@ static int pcd_block_open(struct block_device *bdev, fmode_t mode) struct pcd_unit *cd = bdev->bd_disk->private_data; int ret; - lock_kernel(); + mutex_lock(&pcd_mutex); ret = cdrom_open(&cd->info, bdev, mode); - unlock_kernel(); + mutex_unlock(&pcd_mutex); return ret; } @@ -237,9 +238,9 @@ static int pcd_block_open(struct block_device *bdev, fmode_t mode) static int pcd_block_release(struct gendisk *disk, fmode_t mode) { struct pcd_unit *cd = disk->private_data; - lock_kernel(); + mutex_lock(&pcd_mutex); cdrom_release(&cd->info, mode); - unlock_kernel(); + mutex_unlock(&pcd_mutex); return 0; } @@ -249,9 +250,9 @@ static int pcd_block_ioctl(struct block_device *bdev, fmode_t mode, struct pcd_unit *cd = bdev->bd_disk->private_data; int ret; - lock_kernel(); + mutex_lock(&pcd_mutex); ret = cdrom_ioctl(&cd->info, bdev, mode, cmd, arg); - unlock_kernel(); + mutex_unlock(&pcd_mutex); return ret; } diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c index 985f0d4f1d1e..c0ee1558b9bb 100644 --- a/drivers/block/paride/pd.c +++ b/drivers/block/paride/pd.c @@ -153,10 +153,11 @@ enum {D_PRT, D_PRO, D_UNI, D_MOD, D_GEO, D_SBY, D_DLY, D_SLV}; #include <linux/blkdev.h> #include <linux/blkpg.h> #include <linux/kernel.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <asm/uaccess.h> #include <linux/workqueue.h> +static DEFINE_MUTEX(pd_mutex); static DEFINE_SPINLOCK(pd_lock); module_param(verbose, bool, 0); @@ -736,14 +737,14 @@ static int pd_open(struct block_device *bdev, fmode_t mode) { struct pd_unit *disk = bdev->bd_disk->private_data; - lock_kernel(); + mutex_lock(&pd_mutex); disk->access++; if (disk->removable) { pd_special_command(disk, pd_media_check); pd_special_command(disk, pd_door_lock); } - unlock_kernel(); + mutex_unlock(&pd_mutex); return 0; } @@ -771,10 +772,10 @@ static int pd_ioctl(struct block_device *bdev, fmode_t mode, switch (cmd) { case CDROMEJECT: - lock_kernel(); + mutex_lock(&pd_mutex); if (disk->access == 1) pd_special_command(disk, pd_eject); - unlock_kernel(); + mutex_unlock(&pd_mutex); return 0; default: return -EINVAL; @@ -785,10 +786,10 @@ static int pd_release(struct gendisk *p, fmode_t mode) { struct pd_unit *disk = p->private_data; - lock_kernel(); + mutex_lock(&pd_mutex); if (!--disk->access && disk->removable) pd_special_command(disk, pd_door_unlock); - unlock_kernel(); + mutex_unlock(&pd_mutex); return 0; } diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c index 4457b494882a..635f25dd9e10 100644 --- a/drivers/block/paride/pf.c +++ b/drivers/block/paride/pf.c @@ -152,9 +152,10 @@ enum {D_PRT, D_PRO, D_UNI, D_MOD, D_SLV, D_LUN, D_DLY}; #include <linux/spinlock.h> #include <linux/blkdev.h> #include <linux/blkpg.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <asm/uaccess.h> +static DEFINE_MUTEX(pf_mutex); static DEFINE_SPINLOCK(pf_spin_lock); module_param(verbose, bool, 0644); @@ -302,7 +303,7 @@ static int pf_open(struct block_device *bdev, fmode_t mode) struct pf_unit *pf = bdev->bd_disk->private_data; int ret; - lock_kernel(); + mutex_lock(&pf_mutex); pf_identify(pf); ret = -ENODEV; @@ -318,7 +319,7 @@ static int pf_open(struct block_device *bdev, fmode_t mode) if (pf->removable) pf_lock(pf, 1); out: - unlock_kernel(); + mutex_unlock(&pf_mutex); return ret; } @@ -349,9 +350,9 @@ static int pf_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, u if (pf->access != 1) return -EBUSY; - lock_kernel(); + mutex_lock(&pf_mutex); pf_eject(pf); - unlock_kernel(); + mutex_unlock(&pf_mutex); return 0; } @@ -360,9 +361,9 @@ static int pf_release(struct gendisk *disk, fmode_t mode) { struct pf_unit *pf = disk->private_data; - lock_kernel(); + mutex_lock(&pf_mutex); if (pf->access <= 0) { - unlock_kernel(); + mutex_unlock(&pf_mutex); return -EINVAL; } @@ -371,7 +372,7 @@ static int pf_release(struct gendisk *disk, fmode_t mode) if (!pf->access && pf->removable) pf_lock(pf, 0); - unlock_kernel(); + mutex_unlock(&pf_mutex); return 0; } diff --git a/drivers/block/paride/pg.c b/drivers/block/paride/pg.c index c397b3ddba9b..6b9a2000d56a 100644 --- a/drivers/block/paride/pg.c +++ b/drivers/block/paride/pg.c @@ -162,7 +162,7 @@ enum {D_PRT, D_PRO, D_UNI, D_MOD, D_SLV, D_DLY}; #include <linux/pg.h> #include <linux/device.h> #include <linux/sched.h> /* current, TASK_* */ -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/jiffies.h> #include <asm/uaccess.h> @@ -193,6 +193,7 @@ module_param_array(drive3, int, NULL, 0); #define ATAPI_IDENTIFY 0x12 +static DEFINE_MUTEX(pg_mutex); static int pg_open(struct inode *inode, struct file *file); static int pg_release(struct inode *inode, struct file *file); static ssize_t pg_read(struct file *filp, char __user *buf, @@ -234,6 +235,7 @@ static const struct file_operations pg_fops = { .write = pg_write, .open = pg_open, .release = pg_release, + .llseek = noop_llseek, }; static void pg_init_units(void) @@ -518,7 +520,7 @@ static int pg_open(struct inode *inode, struct file *file) struct pg *dev = &devices[unit]; int ret = 0; - lock_kernel(); + mutex_lock(&pg_mutex); if ((unit >= PG_UNITS) || (!dev->present)) { ret = -ENODEV; goto out; @@ -547,7 +549,7 @@ static int pg_open(struct inode *inode, struct file *file) file->private_data = dev; out: - unlock_kernel(); + mutex_unlock(&pg_mutex); return ret; } diff --git a/drivers/block/paride/pt.c b/drivers/block/paride/pt.c index bc5825fdeaab..7179f79d7468 100644 --- a/drivers/block/paride/pt.c +++ b/drivers/block/paride/pt.c @@ -146,7 +146,7 @@ static int (*drives[4])[6] = {&drive0, &drive1, &drive2, &drive3}; #include <linux/mtio.h> #include <linux/device.h> #include <linux/sched.h> /* current, TASK_*, schedule_timeout() */ -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <asm/uaccess.h> @@ -189,6 +189,7 @@ module_param_array(drive3, int, NULL, 0); #define ATAPI_MODE_SENSE 0x1a #define ATAPI_LOG_SENSE 0x4d +static DEFINE_MUTEX(pt_mutex); static int pt_open(struct inode *inode, struct file *file); static long pt_ioctl(struct file *file, unsigned int cmd, unsigned long arg); static int pt_release(struct inode *inode, struct file *file); @@ -239,6 +240,7 @@ static const struct file_operations pt_fops = { .unlocked_ioctl = pt_ioctl, .open = pt_open, .release = pt_release, + .llseek = noop_llseek, }; /* sysfs class support */ @@ -650,9 +652,9 @@ static int pt_open(struct inode *inode, struct file *file) struct pt_unit *tape = pt + unit; int err; - lock_kernel(); + mutex_lock(&pt_mutex); if (unit >= PT_UNITS || (!tape->present)) { - unlock_kernel(); + mutex_unlock(&pt_mutex); return -ENODEV; } @@ -681,12 +683,12 @@ static int pt_open(struct inode *inode, struct file *file) } file->private_data = tape; - unlock_kernel(); + mutex_unlock(&pt_mutex); return 0; out: atomic_inc(&tape->available); - unlock_kernel(); + mutex_unlock(&pt_mutex); return err; } @@ -704,15 +706,15 @@ static long pt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) switch (mtop.mt_op) { case MTREW: - lock_kernel(); + mutex_lock(&pt_mutex); pt_rewind(tape); - unlock_kernel(); + mutex_unlock(&pt_mutex); return 0; case MTWEOF: - lock_kernel(); + mutex_lock(&pt_mutex); pt_write_fm(tape); - unlock_kernel(); + mutex_unlock(&pt_mutex); return 0; default: diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 37a2bb595076..19b3568e9326 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -57,7 +57,6 @@ #include <linux/seq_file.h> #include <linux/miscdevice.h> #include <linux/freezer.h> -#include <linux/smp_lock.h> #include <linux/mutex.h> #include <linux/slab.h> #include <scsi/scsi_cmnd.h> @@ -86,6 +85,7 @@ #define ZONE(sector, pd) (((sector) + (pd)->offset) & ~((pd)->settings.size - 1)) +static DEFINE_MUTEX(pktcdvd_mutex); static struct pktcdvd_device *pkt_devs[MAX_WRITERS]; static struct proc_dir_entry *pkt_proc; static int pktdev_major; @@ -753,7 +753,6 @@ static int pkt_generic_packet(struct pktcdvd_device *pd, struct packet_command * rq->timeout = 60*HZ; rq->cmd_type = REQ_TYPE_BLOCK_PC; - rq->cmd_flags |= REQ_HARDBARRIER; if (cgc->quiet) rq->cmd_flags |= REQ_QUIET; @@ -2383,7 +2382,7 @@ static int pkt_open(struct block_device *bdev, fmode_t mode) VPRINTK(DRIVER_NAME": entering open\n"); - lock_kernel(); + mutex_lock(&pktcdvd_mutex); mutex_lock(&ctl_mutex); pd = pkt_find_dev_from_minor(MINOR(bdev->bd_dev)); if (!pd) { @@ -2411,7 +2410,7 @@ static int pkt_open(struct block_device *bdev, fmode_t mode) } mutex_unlock(&ctl_mutex); - unlock_kernel(); + mutex_unlock(&pktcdvd_mutex); return 0; out_dec: @@ -2419,7 +2418,7 @@ out_dec: out: VPRINTK(DRIVER_NAME": failed open (%d)\n", ret); mutex_unlock(&ctl_mutex); - unlock_kernel(); + mutex_unlock(&pktcdvd_mutex); return ret; } @@ -2428,7 +2427,7 @@ static int pkt_close(struct gendisk *disk, fmode_t mode) struct pktcdvd_device *pd = disk->private_data; int ret = 0; - lock_kernel(); + mutex_lock(&pktcdvd_mutex); mutex_lock(&ctl_mutex); pd->refcnt--; BUG_ON(pd->refcnt < 0); @@ -2437,7 +2436,7 @@ static int pkt_close(struct gendisk *disk, fmode_t mode) pkt_release_dev(pd, flush); } mutex_unlock(&ctl_mutex); - unlock_kernel(); + mutex_unlock(&pktcdvd_mutex); return ret; } @@ -2773,7 +2772,7 @@ static int pkt_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, VPRINTK("pkt_ioctl: cmd %x, dev %d:%d\n", cmd, MAJOR(bdev->bd_dev), MINOR(bdev->bd_dev)); - lock_kernel(); + mutex_lock(&pktcdvd_mutex); switch (cmd) { case CDROMEJECT: /* @@ -2798,7 +2797,7 @@ static int pkt_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, VPRINTK(DRIVER_NAME": Unknown ioctl for %s (%x)\n", pd->name, cmd); ret = -ENOTTY; } - unlock_kernel(); + mutex_unlock(&pktcdvd_mutex); return ret; } @@ -3046,6 +3045,7 @@ static const struct file_operations pkt_ctl_fops = { .compat_ioctl = pkt_ctl_compat_ioctl, #endif .owner = THIS_MODULE, + .llseek = no_llseek, }; static struct miscdevice pkt_misc = { diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c index 03688c2da319..8e1ce2e2916a 100644 --- a/drivers/block/ps3disk.c +++ b/drivers/block/ps3disk.c @@ -468,7 +468,7 @@ static int __devinit ps3disk_probe(struct ps3_system_bus_device *_dev) blk_queue_dma_alignment(queue, dev->blk_size-1); blk_queue_logical_block_size(queue, dev->blk_size); - blk_queue_ordered(queue, QUEUE_ORDERED_DRAIN_FLUSH); + blk_queue_flush(queue, REQ_FLUSH); blk_queue_max_segments(queue, -1); blk_queue_max_segment_size(queue, dev->bounce_size); diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c new file mode 100644 index 000000000000..6ec9d53806c5 --- /dev/null +++ b/drivers/block/rbd.c @@ -0,0 +1,1841 @@ +/* + rbd.c -- Export ceph rados objects as a Linux block device + + + based on drivers/block/osdblk.c: + + Copyright 2009 Red Hat, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + 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. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + + + + Instructions for use + -------------------- + + 1) Map a Linux block device to an existing rbd image. + + Usage: <mon ip addr> <options> <pool name> <rbd image name> [snap name] + + $ echo "192.168.0.1 name=admin rbd foo" > /sys/class/rbd/add + + The snapshot name can be "-" or omitted to map the image read/write. + + 2) List all active blkdev<->object mappings. + + In this example, we have performed step #1 twice, creating two blkdevs, + mapped to two separate rados objects in the rados rbd pool + + $ cat /sys/class/rbd/list + #id major client_name pool name snap KB + 0 254 client4143 rbd foo - 1024000 + + The columns, in order, are: + - blkdev unique id + - blkdev assigned major + - rados client id + - rados pool name + - rados block device name + - mapped snapshot ("-" if none) + - device size in KB + + + 3) Create a snapshot. + + Usage: <blkdev id> <snapname> + + $ echo "0 mysnap" > /sys/class/rbd/snap_create + + + 4) Listing a snapshot. + + $ cat /sys/class/rbd/snaps_list + #id snap KB + 0 - 1024000 (*) + 0 foo 1024000 + + The columns, in order, are: + - blkdev unique id + - snapshot name, '-' means none (active read/write version) + - size of device at time of snapshot + - the (*) indicates this is the active version + + 5) Rollback to snapshot. + + Usage: <blkdev id> <snapname> + + $ echo "0 mysnap" > /sys/class/rbd/snap_rollback + + + 6) Mapping an image using snapshot. + + A snapshot mapping is read-only. This is being done by passing + snap=<snapname> to the options when adding a device. + + $ echo "192.168.0.1 name=admin,snap=mysnap rbd foo" > /sys/class/rbd/add + + + 7) Remove an active blkdev<->rbd image mapping. + + In this example, we remove the mapping with blkdev unique id 1. + + $ echo 1 > /sys/class/rbd/remove + + + NOTE: The actual creation and deletion of rados objects is outside the scope + of this driver. + + */ + +#include <linux/ceph/libceph.h> +#include <linux/ceph/osd_client.h> +#include <linux/ceph/mon_client.h> +#include <linux/ceph/decode.h> + +#include <linux/kernel.h> +#include <linux/device.h> +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/blkdev.h> + +#include "rbd_types.h" + +#define DRV_NAME "rbd" +#define DRV_NAME_LONG "rbd (rados block device)" + +#define RBD_MINORS_PER_MAJOR 256 /* max minors per blkdev */ + +#define RBD_MAX_MD_NAME_LEN (96 + sizeof(RBD_SUFFIX)) +#define RBD_MAX_POOL_NAME_LEN 64 +#define RBD_MAX_SNAP_NAME_LEN 32 +#define RBD_MAX_OPT_LEN 1024 + +#define RBD_SNAP_HEAD_NAME "-" + +#define DEV_NAME_LEN 32 + +/* + * block device image metadata (in-memory version) + */ +struct rbd_image_header { + u64 image_size; + char block_name[32]; + __u8 obj_order; + __u8 crypt_type; + __u8 comp_type; + struct rw_semaphore snap_rwsem; + struct ceph_snap_context *snapc; + size_t snap_names_len; + u64 snap_seq; + u32 total_snaps; + + char *snap_names; + u64 *snap_sizes; +}; + +/* + * an instance of the client. multiple devices may share a client. + */ +struct rbd_client { + struct ceph_client *client; + struct kref kref; + struct list_head node; +}; + +/* + * a single io request + */ +struct rbd_request { + struct request *rq; /* blk layer request */ + struct bio *bio; /* cloned bio */ + struct page **pages; /* list of used pages */ + u64 len; +}; + +/* + * a single device + */ +struct rbd_device { + int id; /* blkdev unique id */ + + int major; /* blkdev assigned major */ + struct gendisk *disk; /* blkdev's gendisk and rq */ + struct request_queue *q; + + struct ceph_client *client; + struct rbd_client *rbd_client; + + char name[DEV_NAME_LEN]; /* blkdev name, e.g. rbd3 */ + + spinlock_t lock; /* queue lock */ + + struct rbd_image_header header; + char obj[RBD_MAX_OBJ_NAME_LEN]; /* rbd image name */ + int obj_len; + char obj_md_name[RBD_MAX_MD_NAME_LEN]; /* hdr nm. */ + char pool_name[RBD_MAX_POOL_NAME_LEN]; + int poolid; + + char snap_name[RBD_MAX_SNAP_NAME_LEN]; + u32 cur_snap; /* index+1 of current snapshot within snap context + 0 - for the head */ + int read_only; + + struct list_head node; +}; + +static spinlock_t node_lock; /* protects client get/put */ + +static struct class *class_rbd; /* /sys/class/rbd */ +static DEFINE_MUTEX(ctl_mutex); /* Serialize open/close/setup/teardown */ +static LIST_HEAD(rbd_dev_list); /* devices */ +static LIST_HEAD(rbd_client_list); /* clients */ + + +static int rbd_open(struct block_device *bdev, fmode_t mode) +{ + struct gendisk *disk = bdev->bd_disk; + struct rbd_device *rbd_dev = disk->private_data; + + set_device_ro(bdev, rbd_dev->read_only); + + if ((mode & FMODE_WRITE) && rbd_dev->read_only) + return -EROFS; + + return 0; +} + +static const struct block_device_operations rbd_bd_ops = { + .owner = THIS_MODULE, + .open = rbd_open, +}; + +/* + * Initialize an rbd client instance. + * We own *opt. + */ +static struct rbd_client *rbd_client_create(struct ceph_options *opt) +{ + struct rbd_client *rbdc; + int ret = -ENOMEM; + + dout("rbd_client_create\n"); + rbdc = kmalloc(sizeof(struct rbd_client), GFP_KERNEL); + if (!rbdc) + goto out_opt; + + kref_init(&rbdc->kref); + INIT_LIST_HEAD(&rbdc->node); + + rbdc->client = ceph_create_client(opt, rbdc); + if (IS_ERR(rbdc->client)) + goto out_rbdc; + opt = NULL; /* Now rbdc->client is responsible for opt */ + + ret = ceph_open_session(rbdc->client); + if (ret < 0) + goto out_err; + + spin_lock(&node_lock); + list_add_tail(&rbdc->node, &rbd_client_list); + spin_unlock(&node_lock); + + dout("rbd_client_create created %p\n", rbdc); + return rbdc; + +out_err: + ceph_destroy_client(rbdc->client); +out_rbdc: + kfree(rbdc); +out_opt: + if (opt) + ceph_destroy_options(opt); + return ERR_PTR(ret); +} + +/* + * Find a ceph client with specific addr and configuration. + */ +static struct rbd_client *__rbd_client_find(struct ceph_options *opt) +{ + struct rbd_client *client_node; + + if (opt->flags & CEPH_OPT_NOSHARE) + return NULL; + + list_for_each_entry(client_node, &rbd_client_list, node) + if (ceph_compare_options(opt, client_node->client) == 0) + return client_node; + return NULL; +} + +/* + * Get a ceph client with specific addr and configuration, if one does + * not exist create it. + */ +static int rbd_get_client(struct rbd_device *rbd_dev, const char *mon_addr, + char *options) +{ + struct rbd_client *rbdc; + struct ceph_options *opt; + int ret; + + ret = ceph_parse_options(&opt, options, mon_addr, + mon_addr + strlen(mon_addr), NULL, NULL); + if (ret < 0) + return ret; + + spin_lock(&node_lock); + rbdc = __rbd_client_find(opt); + if (rbdc) { + ceph_destroy_options(opt); + + /* using an existing client */ + kref_get(&rbdc->kref); + rbd_dev->rbd_client = rbdc; + rbd_dev->client = rbdc->client; + spin_unlock(&node_lock); + return 0; + } + spin_unlock(&node_lock); + + rbdc = rbd_client_create(opt); + if (IS_ERR(rbdc)) + return PTR_ERR(rbdc); + + rbd_dev->rbd_client = rbdc; + rbd_dev->client = rbdc->client; + return 0; +} + +/* + * Destroy ceph client + */ +static void rbd_client_release(struct kref *kref) +{ + struct rbd_client *rbdc = container_of(kref, struct rbd_client, kref); + + dout("rbd_release_client %p\n", rbdc); + spin_lock(&node_lock); + list_del(&rbdc->node); + spin_unlock(&node_lock); + + ceph_destroy_client(rbdc->client); + kfree(rbdc); +} + +/* + * Drop reference to ceph client node. If it's not referenced anymore, release + * it. + */ +static void rbd_put_client(struct rbd_device *rbd_dev) +{ + kref_put(&rbd_dev->rbd_client->kref, rbd_client_release); + rbd_dev->rbd_client = NULL; + rbd_dev->client = NULL; +} + + +/* + * Create a new header structure, translate header format from the on-disk + * header. + */ +static int rbd_header_from_disk(struct rbd_image_header *header, + struct rbd_image_header_ondisk *ondisk, + int allocated_snaps, + gfp_t gfp_flags) +{ + int i; + u32 snap_count = le32_to_cpu(ondisk->snap_count); + int ret = -ENOMEM; + + init_rwsem(&header->snap_rwsem); + + header->snap_names_len = le64_to_cpu(ondisk->snap_names_len); + header->snapc = kmalloc(sizeof(struct ceph_snap_context) + + snap_count * + sizeof(struct rbd_image_snap_ondisk), + gfp_flags); + if (!header->snapc) + return -ENOMEM; + if (snap_count) { + header->snap_names = kmalloc(header->snap_names_len, + GFP_KERNEL); + if (!header->snap_names) + goto err_snapc; + header->snap_sizes = kmalloc(snap_count * sizeof(u64), + GFP_KERNEL); + if (!header->snap_sizes) + goto err_names; + } else { + header->snap_names = NULL; + header->snap_sizes = NULL; + } + memcpy(header->block_name, ondisk->block_name, + sizeof(ondisk->block_name)); + + header->image_size = le64_to_cpu(ondisk->image_size); + header->obj_order = ondisk->options.order; + header->crypt_type = ondisk->options.crypt_type; + header->comp_type = ondisk->options.comp_type; + + atomic_set(&header->snapc->nref, 1); + header->snap_seq = le64_to_cpu(ondisk->snap_seq); + header->snapc->num_snaps = snap_count; + header->total_snaps = snap_count; + + if (snap_count && + allocated_snaps == snap_count) { + for (i = 0; i < snap_count; i++) { + header->snapc->snaps[i] = + le64_to_cpu(ondisk->snaps[i].id); + header->snap_sizes[i] = + le64_to_cpu(ondisk->snaps[i].image_size); + } + + /* copy snapshot names */ + memcpy(header->snap_names, &ondisk->snaps[i], + header->snap_names_len); + } + + return 0; + +err_names: + kfree(header->snap_names); +err_snapc: + kfree(header->snapc); + return ret; +} + +static int snap_index(struct rbd_image_header *header, int snap_num) +{ + return header->total_snaps - snap_num; +} + +static u64 cur_snap_id(struct rbd_device *rbd_dev) +{ + struct rbd_image_header *header = &rbd_dev->header; + + if (!rbd_dev->cur_snap) + return 0; + + return header->snapc->snaps[snap_index(header, rbd_dev->cur_snap)]; +} + +static int snap_by_name(struct rbd_image_header *header, const char *snap_name, + u64 *seq, u64 *size) +{ + int i; + char *p = header->snap_names; + + for (i = 0; i < header->total_snaps; i++, p += strlen(p) + 1) { + if (strcmp(snap_name, p) == 0) + break; + } + if (i == header->total_snaps) + return -ENOENT; + if (seq) + *seq = header->snapc->snaps[i]; + + if (size) + *size = header->snap_sizes[i]; + + return i; +} + +static int rbd_header_set_snap(struct rbd_device *dev, + const char *snap_name, + u64 *size) +{ + struct rbd_image_header *header = &dev->header; + struct ceph_snap_context *snapc = header->snapc; + int ret = -ENOENT; + + down_write(&header->snap_rwsem); + + if (!snap_name || + !*snap_name || + strcmp(snap_name, "-") == 0 || + strcmp(snap_name, RBD_SNAP_HEAD_NAME) == 0) { + if (header->total_snaps) + snapc->seq = header->snap_seq; + else + snapc->seq = 0; + dev->cur_snap = 0; + dev->read_only = 0; + if (size) + *size = header->image_size; + } else { + ret = snap_by_name(header, snap_name, &snapc->seq, size); + if (ret < 0) + goto done; + + dev->cur_snap = header->total_snaps - ret; + dev->read_only = 1; + } + + ret = 0; +done: + up_write(&header->snap_rwsem); + return ret; +} + +static void rbd_header_free(struct rbd_image_header *header) +{ + kfree(header->snapc); + kfree(header->snap_names); + kfree(header->snap_sizes); +} + +/* + * get the actual striped segment name, offset and length + */ +static u64 rbd_get_segment(struct rbd_image_header *header, + const char *block_name, + u64 ofs, u64 len, + char *seg_name, u64 *segofs) +{ + u64 seg = ofs >> header->obj_order; + + if (seg_name) + snprintf(seg_name, RBD_MAX_SEG_NAME_LEN, + "%s.%012llx", block_name, seg); + + ofs = ofs & ((1 << header->obj_order) - 1); + len = min_t(u64, len, (1 << header->obj_order) - ofs); + + if (segofs) + *segofs = ofs; + + return len; +} + +/* + * bio helpers + */ + +static void bio_chain_put(struct bio *chain) +{ + struct bio *tmp; + + while (chain) { + tmp = chain; + chain = chain->bi_next; + bio_put(tmp); + } +} + +/* + * zeros a bio chain, starting at specific offset + */ +static void zero_bio_chain(struct bio *chain, int start_ofs) +{ + struct bio_vec *bv; + unsigned long flags; + void *buf; + int i; + int pos = 0; + + while (chain) { + bio_for_each_segment(bv, chain, i) { + if (pos + bv->bv_len > start_ofs) { + int remainder = max(start_ofs - pos, 0); + buf = bvec_kmap_irq(bv, &flags); + memset(buf + remainder, 0, + bv->bv_len - remainder); + bvec_kunmap_irq(buf, &flags); + } + pos += bv->bv_len; + } + + chain = chain->bi_next; + } +} + +/* + * bio_chain_clone - clone a chain of bios up to a certain length. + * might return a bio_pair that will need to be released. + */ +static struct bio *bio_chain_clone(struct bio **old, struct bio **next, + struct bio_pair **bp, + int len, gfp_t gfpmask) +{ + struct bio *tmp, *old_chain = *old, *new_chain = NULL, *tail = NULL; + int total = 0; + + if (*bp) { + bio_pair_release(*bp); + *bp = NULL; + } + + while (old_chain && (total < len)) { + tmp = bio_kmalloc(gfpmask, old_chain->bi_max_vecs); + if (!tmp) + goto err_out; + + if (total + old_chain->bi_size > len) { + struct bio_pair *bp; + + /* + * this split can only happen with a single paged bio, + * split_bio will BUG_ON if this is not the case + */ + dout("bio_chain_clone split! total=%d remaining=%d" + "bi_size=%d\n", + (int)total, (int)len-total, + (int)old_chain->bi_size); + + /* split the bio. We'll release it either in the next + call, or it will have to be released outside */ + bp = bio_split(old_chain, (len - total) / 512ULL); + if (!bp) + goto err_out; + + __bio_clone(tmp, &bp->bio1); + + *next = &bp->bio2; + } else { + __bio_clone(tmp, old_chain); + *next = old_chain->bi_next; + } + + tmp->bi_bdev = NULL; + gfpmask &= ~__GFP_WAIT; + tmp->bi_next = NULL; + + if (!new_chain) { + new_chain = tail = tmp; + } else { + tail->bi_next = tmp; + tail = tmp; + } + old_chain = old_chain->bi_next; + + total += tmp->bi_size; + } + + BUG_ON(total < len); + + if (tail) + tail->bi_next = NULL; + + *old = old_chain; + + return new_chain; + +err_out: + dout("bio_chain_clone with err\n"); + bio_chain_put(new_chain); + return NULL; +} + +/* + * helpers for osd request op vectors. + */ +static int rbd_create_rw_ops(struct ceph_osd_req_op **ops, + int num_ops, + int opcode, + u32 payload_len) +{ + *ops = kzalloc(sizeof(struct ceph_osd_req_op) * (num_ops + 1), + GFP_NOIO); + if (!*ops) + return -ENOMEM; + (*ops)[0].op = opcode; + /* + * op extent offset and length will be set later on + * in calc_raw_layout() + */ + (*ops)[0].payload_len = payload_len; + return 0; +} + +static void rbd_destroy_ops(struct ceph_osd_req_op *ops) +{ + kfree(ops); +} + +/* + * Send ceph osd request + */ +static int rbd_do_request(struct request *rq, + struct rbd_device *dev, + struct ceph_snap_context *snapc, + u64 snapid, + const char *obj, u64 ofs, u64 len, + struct bio *bio, + struct page **pages, + int num_pages, + int flags, + struct ceph_osd_req_op *ops, + int num_reply, + void (*rbd_cb)(struct ceph_osd_request *req, + struct ceph_msg *msg)) +{ + struct ceph_osd_request *req; + struct ceph_file_layout *layout; + int ret; + u64 bno; + struct timespec mtime = CURRENT_TIME; + struct rbd_request *req_data; + struct ceph_osd_request_head *reqhead; + struct rbd_image_header *header = &dev->header; + + ret = -ENOMEM; + req_data = kzalloc(sizeof(*req_data), GFP_NOIO); + if (!req_data) + goto done; + + dout("rbd_do_request len=%lld ofs=%lld\n", len, ofs); + + down_read(&header->snap_rwsem); + + req = ceph_osdc_alloc_request(&dev->client->osdc, flags, + snapc, + ops, + false, + GFP_NOIO, pages, bio); + if (IS_ERR(req)) { + up_read(&header->snap_rwsem); + ret = PTR_ERR(req); + goto done_pages; + } + + req->r_callback = rbd_cb; + + req_data->rq = rq; + req_data->bio = bio; + req_data->pages = pages; + req_data->len = len; + + req->r_priv = req_data; + + reqhead = req->r_request->front.iov_base; + reqhead->snapid = cpu_to_le64(CEPH_NOSNAP); + + strncpy(req->r_oid, obj, sizeof(req->r_oid)); + req->r_oid_len = strlen(req->r_oid); + + layout = &req->r_file_layout; + memset(layout, 0, sizeof(*layout)); + layout->fl_stripe_unit = cpu_to_le32(1 << RBD_MAX_OBJ_ORDER); + layout->fl_stripe_count = cpu_to_le32(1); + layout->fl_object_size = cpu_to_le32(1 << RBD_MAX_OBJ_ORDER); + layout->fl_pg_preferred = cpu_to_le32(-1); + layout->fl_pg_pool = cpu_to_le32(dev->poolid); + ceph_calc_raw_layout(&dev->client->osdc, layout, snapid, + ofs, &len, &bno, req, ops); + + ceph_osdc_build_request(req, ofs, &len, + ops, + snapc, + &mtime, + req->r_oid, req->r_oid_len); + up_read(&header->snap_rwsem); + + ret = ceph_osdc_start_request(&dev->client->osdc, req, false); + if (ret < 0) + goto done_err; + + if (!rbd_cb) { + ret = ceph_osdc_wait_request(&dev->client->osdc, req); + ceph_osdc_put_request(req); + } + return ret; + +done_err: + bio_chain_put(req_data->bio); + ceph_osdc_put_request(req); +done_pages: + kfree(req_data); +done: + if (rq) + blk_end_request(rq, ret, len); + return ret; +} + +/* + * Ceph osd op callback + */ +static void rbd_req_cb(struct ceph_osd_request *req, struct ceph_msg *msg) +{ + struct rbd_request *req_data = req->r_priv; + struct ceph_osd_reply_head *replyhead; + struct ceph_osd_op *op; + __s32 rc; + u64 bytes; + int read_op; + + /* parse reply */ + replyhead = msg->front.iov_base; + WARN_ON(le32_to_cpu(replyhead->num_ops) == 0); + op = (void *)(replyhead + 1); + rc = le32_to_cpu(replyhead->result); + bytes = le64_to_cpu(op->extent.length); + read_op = (le32_to_cpu(op->op) == CEPH_OSD_OP_READ); + + dout("rbd_req_cb bytes=%lld readop=%d rc=%d\n", bytes, read_op, rc); + + if (rc == -ENOENT && read_op) { + zero_bio_chain(req_data->bio, 0); + rc = 0; + } else if (rc == 0 && read_op && bytes < req_data->len) { + zero_bio_chain(req_data->bio, bytes); + bytes = req_data->len; + } + + blk_end_request(req_data->rq, rc, bytes); + + if (req_data->bio) + bio_chain_put(req_data->bio); + + ceph_osdc_put_request(req); + kfree(req_data); +} + +/* + * Do a synchronous ceph osd operation + */ +static int rbd_req_sync_op(struct rbd_device *dev, + struct ceph_snap_context *snapc, + u64 snapid, + int opcode, + int flags, + struct ceph_osd_req_op *orig_ops, + int num_reply, + const char *obj, + u64 ofs, u64 len, + char *buf) +{ + int ret; + struct page **pages; + int num_pages; + struct ceph_osd_req_op *ops = orig_ops; + u32 payload_len; + + num_pages = calc_pages_for(ofs , len); + pages = ceph_alloc_page_vector(num_pages, GFP_KERNEL); + if (IS_ERR(pages)) + return PTR_ERR(pages); + + if (!orig_ops) { + payload_len = (flags & CEPH_OSD_FLAG_WRITE ? len : 0); + ret = rbd_create_rw_ops(&ops, 1, opcode, payload_len); + if (ret < 0) + goto done; + + if ((flags & CEPH_OSD_FLAG_WRITE) && buf) { + ret = ceph_copy_to_page_vector(pages, buf, ofs, len); + if (ret < 0) + goto done_ops; + } + } + + ret = rbd_do_request(NULL, dev, snapc, snapid, + obj, ofs, len, NULL, + pages, num_pages, + flags, + ops, + 2, + NULL); + if (ret < 0) + goto done_ops; + + if ((flags & CEPH_OSD_FLAG_READ) && buf) + ret = ceph_copy_from_page_vector(pages, buf, ofs, ret); + +done_ops: + if (!orig_ops) + rbd_destroy_ops(ops); +done: + ceph_release_page_vector(pages, num_pages); + return ret; +} + +/* + * Do an asynchronous ceph osd operation + */ +static int rbd_do_op(struct request *rq, + struct rbd_device *rbd_dev , + struct ceph_snap_context *snapc, + u64 snapid, + int opcode, int flags, int num_reply, + u64 ofs, u64 len, + struct bio *bio) +{ + char *seg_name; + u64 seg_ofs; + u64 seg_len; + int ret; + struct ceph_osd_req_op *ops; + u32 payload_len; + + seg_name = kmalloc(RBD_MAX_SEG_NAME_LEN + 1, GFP_NOIO); + if (!seg_name) + return -ENOMEM; + + seg_len = rbd_get_segment(&rbd_dev->header, + rbd_dev->header.block_name, + ofs, len, + seg_name, &seg_ofs); + + payload_len = (flags & CEPH_OSD_FLAG_WRITE ? seg_len : 0); + + ret = rbd_create_rw_ops(&ops, 1, opcode, payload_len); + if (ret < 0) + goto done; + + /* we've taken care of segment sizes earlier when we + cloned the bios. We should never have a segment + truncated at this point */ + BUG_ON(seg_len < len); + + ret = rbd_do_request(rq, rbd_dev, snapc, snapid, + seg_name, seg_ofs, seg_len, + bio, + NULL, 0, + flags, + ops, + num_reply, + rbd_req_cb); +done: + kfree(seg_name); + return ret; +} + +/* + * Request async osd write + */ +static int rbd_req_write(struct request *rq, + struct rbd_device *rbd_dev, + struct ceph_snap_context *snapc, + u64 ofs, u64 len, + struct bio *bio) +{ + return rbd_do_op(rq, rbd_dev, snapc, CEPH_NOSNAP, + CEPH_OSD_OP_WRITE, + CEPH_OSD_FLAG_WRITE | CEPH_OSD_FLAG_ONDISK, + 2, + ofs, len, bio); +} + +/* + * Request async osd read + */ +static int rbd_req_read(struct request *rq, + struct rbd_device *rbd_dev, + u64 snapid, + u64 ofs, u64 len, + struct bio *bio) +{ + return rbd_do_op(rq, rbd_dev, NULL, + (snapid ? snapid : CEPH_NOSNAP), + CEPH_OSD_OP_READ, + CEPH_OSD_FLAG_READ, + 2, + ofs, len, bio); +} + +/* + * Request sync osd read + */ +static int rbd_req_sync_read(struct rbd_device *dev, + struct ceph_snap_context *snapc, + u64 snapid, + const char *obj, + u64 ofs, u64 len, + char *buf) +{ + return rbd_req_sync_op(dev, NULL, + (snapid ? snapid : CEPH_NOSNAP), + CEPH_OSD_OP_READ, + CEPH_OSD_FLAG_READ, + NULL, + 1, obj, ofs, len, buf); +} + +/* + * Request sync osd read + */ +static int rbd_req_sync_rollback_obj(struct rbd_device *dev, + u64 snapid, + const char *obj) +{ + struct ceph_osd_req_op *ops; + int ret = rbd_create_rw_ops(&ops, 1, CEPH_OSD_OP_ROLLBACK, 0); + if (ret < 0) + return ret; + + ops[0].snap.snapid = snapid; + + ret = rbd_req_sync_op(dev, NULL, + CEPH_NOSNAP, + 0, + CEPH_OSD_FLAG_WRITE | CEPH_OSD_FLAG_ONDISK, + ops, + 1, obj, 0, 0, NULL); + + rbd_destroy_ops(ops); + + if (ret < 0) + return ret; + + return ret; +} + +/* + * Request sync osd read + */ +static int rbd_req_sync_exec(struct rbd_device *dev, + const char *obj, + const char *cls, + const char *method, + const char *data, + int len) +{ + struct ceph_osd_req_op *ops; + int cls_len = strlen(cls); + int method_len = strlen(method); + int ret = rbd_create_rw_ops(&ops, 1, CEPH_OSD_OP_CALL, + cls_len + method_len + len); + if (ret < 0) + return ret; + + ops[0].cls.class_name = cls; + ops[0].cls.class_len = (__u8)cls_len; + ops[0].cls.method_name = method; + ops[0].cls.method_len = (__u8)method_len; + ops[0].cls.argc = 0; + ops[0].cls.indata = data; + ops[0].cls.indata_len = len; + + ret = rbd_req_sync_op(dev, NULL, + CEPH_NOSNAP, + 0, + CEPH_OSD_FLAG_WRITE | CEPH_OSD_FLAG_ONDISK, + ops, + 1, obj, 0, 0, NULL); + + rbd_destroy_ops(ops); + + dout("cls_exec returned %d\n", ret); + return ret; +} + +/* + * block device queue callback + */ +static void rbd_rq_fn(struct request_queue *q) +{ + struct rbd_device *rbd_dev = q->queuedata; + struct request *rq; + struct bio_pair *bp = NULL; + + rq = blk_fetch_request(q); + + while (1) { + struct bio *bio; + struct bio *rq_bio, *next_bio = NULL; + bool do_write; + int size, op_size = 0; + u64 ofs; + + /* peek at request from block layer */ + if (!rq) + break; + + dout("fetched request\n"); + + /* filter out block requests we don't understand */ + if ((rq->cmd_type != REQ_TYPE_FS)) { + __blk_end_request_all(rq, 0); + goto next; + } + + /* deduce our operation (read, write) */ + do_write = (rq_data_dir(rq) == WRITE); + + size = blk_rq_bytes(rq); + ofs = blk_rq_pos(rq) * 512ULL; + rq_bio = rq->bio; + if (do_write && rbd_dev->read_only) { + __blk_end_request_all(rq, -EROFS); + goto next; + } + + spin_unlock_irq(q->queue_lock); + + dout("%s 0x%x bytes at 0x%llx\n", + do_write ? "write" : "read", + size, blk_rq_pos(rq) * 512ULL); + + do { + /* a bio clone to be passed down to OSD req */ + dout("rq->bio->bi_vcnt=%d\n", rq->bio->bi_vcnt); + op_size = rbd_get_segment(&rbd_dev->header, + rbd_dev->header.block_name, + ofs, size, + NULL, NULL); + bio = bio_chain_clone(&rq_bio, &next_bio, &bp, + op_size, GFP_ATOMIC); + if (!bio) { + spin_lock_irq(q->queue_lock); + __blk_end_request_all(rq, -ENOMEM); + goto next; + } + + /* init OSD command: write or read */ + if (do_write) + rbd_req_write(rq, rbd_dev, + rbd_dev->header.snapc, + ofs, + op_size, bio); + else + rbd_req_read(rq, rbd_dev, + cur_snap_id(rbd_dev), + ofs, + op_size, bio); + + size -= op_size; + ofs += op_size; + + rq_bio = next_bio; + } while (size > 0); + + if (bp) + bio_pair_release(bp); + + spin_lock_irq(q->queue_lock); +next: + rq = blk_fetch_request(q); + } +} + +/* + * a queue callback. Makes sure that we don't create a bio that spans across + * multiple osd objects. One exception would be with a single page bios, + * which we handle later at bio_chain_clone + */ +static int rbd_merge_bvec(struct request_queue *q, struct bvec_merge_data *bmd, + struct bio_vec *bvec) +{ + struct rbd_device *rbd_dev = q->queuedata; + unsigned int chunk_sectors = 1 << (rbd_dev->header.obj_order - 9); + sector_t sector = bmd->bi_sector + get_start_sect(bmd->bi_bdev); + unsigned int bio_sectors = bmd->bi_size >> 9; + int max; + + max = (chunk_sectors - ((sector & (chunk_sectors - 1)) + + bio_sectors)) << 9; + if (max < 0) + max = 0; /* bio_add cannot handle a negative return */ + if (max <= bvec->bv_len && bio_sectors == 0) + return bvec->bv_len; + return max; +} + +static void rbd_free_disk(struct rbd_device *rbd_dev) +{ + struct gendisk *disk = rbd_dev->disk; + + if (!disk) + return; + + rbd_header_free(&rbd_dev->header); + + if (disk->flags & GENHD_FL_UP) + del_gendisk(disk); + if (disk->queue) + blk_cleanup_queue(disk->queue); + put_disk(disk); +} + +/* + * reload the ondisk the header + */ +static int rbd_read_header(struct rbd_device *rbd_dev, + struct rbd_image_header *header) +{ + ssize_t rc; + struct rbd_image_header_ondisk *dh; + int snap_count = 0; + u64 snap_names_len = 0; + + while (1) { + int len = sizeof(*dh) + + snap_count * sizeof(struct rbd_image_snap_ondisk) + + snap_names_len; + + rc = -ENOMEM; + dh = kmalloc(len, GFP_KERNEL); + if (!dh) + return -ENOMEM; + + rc = rbd_req_sync_read(rbd_dev, + NULL, CEPH_NOSNAP, + rbd_dev->obj_md_name, + 0, len, + (char *)dh); + if (rc < 0) + goto out_dh; + + rc = rbd_header_from_disk(header, dh, snap_count, GFP_KERNEL); + if (rc < 0) + goto out_dh; + + if (snap_count != header->total_snaps) { + snap_count = header->total_snaps; + snap_names_len = header->snap_names_len; + rbd_header_free(header); + kfree(dh); + continue; + } + break; + } + +out_dh: + kfree(dh); + return rc; +} + +/* + * create a snapshot + */ +static int rbd_header_add_snap(struct rbd_device *dev, + const char *snap_name, + gfp_t gfp_flags) +{ + int name_len = strlen(snap_name); + u64 new_snapid; + int ret; + void *data, *data_start, *data_end; + + /* we should create a snapshot only if we're pointing at the head */ + if (dev->cur_snap) + return -EINVAL; + + ret = ceph_monc_create_snapid(&dev->client->monc, dev->poolid, + &new_snapid); + dout("created snapid=%lld\n", new_snapid); + if (ret < 0) + return ret; + + data = kmalloc(name_len + 16, gfp_flags); + if (!data) + return -ENOMEM; + + data_start = data; + data_end = data + name_len + 16; + + ceph_encode_string_safe(&data, data_end, snap_name, name_len, bad); + ceph_encode_64_safe(&data, data_end, new_snapid, bad); + + ret = rbd_req_sync_exec(dev, dev->obj_md_name, "rbd", "snap_add", + data_start, data - data_start); + + kfree(data_start); + + if (ret < 0) + return ret; + + dev->header.snapc->seq = new_snapid; + + return 0; +bad: + return -ERANGE; +} + +/* + * only read the first part of the ondisk header, without the snaps info + */ +static int rbd_update_snaps(struct rbd_device *rbd_dev) +{ + int ret; + struct rbd_image_header h; + u64 snap_seq; + + ret = rbd_read_header(rbd_dev, &h); + if (ret < 0) + return ret; + + down_write(&rbd_dev->header.snap_rwsem); + + snap_seq = rbd_dev->header.snapc->seq; + + kfree(rbd_dev->header.snapc); + kfree(rbd_dev->header.snap_names); + kfree(rbd_dev->header.snap_sizes); + + rbd_dev->header.total_snaps = h.total_snaps; + rbd_dev->header.snapc = h.snapc; + rbd_dev->header.snap_names = h.snap_names; + rbd_dev->header.snap_sizes = h.snap_sizes; + rbd_dev->header.snapc->seq = snap_seq; + + up_write(&rbd_dev->header.snap_rwsem); + + return 0; +} + +static int rbd_init_disk(struct rbd_device *rbd_dev) +{ + struct gendisk *disk; + struct request_queue *q; + int rc; + u64 total_size = 0; + + /* contact OSD, request size info about the object being mapped */ + rc = rbd_read_header(rbd_dev, &rbd_dev->header); + if (rc) + return rc; + + rc = rbd_header_set_snap(rbd_dev, rbd_dev->snap_name, &total_size); + if (rc) + return rc; + + /* create gendisk info */ + rc = -ENOMEM; + disk = alloc_disk(RBD_MINORS_PER_MAJOR); + if (!disk) + goto out; + + sprintf(disk->disk_name, DRV_NAME "%d", rbd_dev->id); + disk->major = rbd_dev->major; + disk->first_minor = 0; + disk->fops = &rbd_bd_ops; + disk->private_data = rbd_dev; + + /* init rq */ + rc = -ENOMEM; + q = blk_init_queue(rbd_rq_fn, &rbd_dev->lock); + if (!q) + goto out_disk; + blk_queue_merge_bvec(q, rbd_merge_bvec); + disk->queue = q; + + q->queuedata = rbd_dev; + + rbd_dev->disk = disk; + rbd_dev->q = q; + + /* finally, announce the disk to the world */ + set_capacity(disk, total_size / 512ULL); + add_disk(disk); + + pr_info("%s: added with size 0x%llx\n", + disk->disk_name, (unsigned long long)total_size); + return 0; + +out_disk: + put_disk(disk); +out: + return rc; +} + +/******************************************************************** + * /sys/class/rbd/ + * add map rados objects to blkdev + * remove unmap rados objects + * list show mappings + *******************************************************************/ + +static void class_rbd_release(struct class *cls) +{ + kfree(cls); +} + +static ssize_t class_rbd_list(struct class *c, + struct class_attribute *attr, + char *data) +{ + int n = 0; + struct list_head *tmp; + int max = PAGE_SIZE; + + mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); + + n += snprintf(data, max, + "#id\tmajor\tclient_name\tpool\tname\tsnap\tKB\n"); + + list_for_each(tmp, &rbd_dev_list) { + struct rbd_device *rbd_dev; + + rbd_dev = list_entry(tmp, struct rbd_device, node); + n += snprintf(data+n, max-n, + "%d\t%d\tclient%lld\t%s\t%s\t%s\t%lld\n", + rbd_dev->id, + rbd_dev->major, + ceph_client_id(rbd_dev->client), + rbd_dev->pool_name, + rbd_dev->obj, rbd_dev->snap_name, + rbd_dev->header.image_size >> 10); + if (n == max) + break; + } + + mutex_unlock(&ctl_mutex); + return n; +} + +static ssize_t class_rbd_add(struct class *c, + struct class_attribute *attr, + const char *buf, size_t count) +{ + struct ceph_osd_client *osdc; + struct rbd_device *rbd_dev; + ssize_t rc = -ENOMEM; + int irc, new_id = 0; + struct list_head *tmp; + char *mon_dev_name; + char *options; + + if (!try_module_get(THIS_MODULE)) + return -ENODEV; + + mon_dev_name = kmalloc(RBD_MAX_OPT_LEN, GFP_KERNEL); + if (!mon_dev_name) + goto err_out_mod; + + options = kmalloc(RBD_MAX_OPT_LEN, GFP_KERNEL); + if (!options) + goto err_mon_dev; + + /* new rbd_device object */ + rbd_dev = kzalloc(sizeof(*rbd_dev), GFP_KERNEL); + if (!rbd_dev) + goto err_out_opt; + + /* static rbd_device initialization */ + spin_lock_init(&rbd_dev->lock); + INIT_LIST_HEAD(&rbd_dev->node); + + /* generate unique id: find highest unique id, add one */ + mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); + + list_for_each(tmp, &rbd_dev_list) { + struct rbd_device *rbd_dev; + + rbd_dev = list_entry(tmp, struct rbd_device, node); + if (rbd_dev->id >= new_id) + new_id = rbd_dev->id + 1; + } + + rbd_dev->id = new_id; + + /* add to global list */ + list_add_tail(&rbd_dev->node, &rbd_dev_list); + + /* parse add command */ + if (sscanf(buf, "%" __stringify(RBD_MAX_OPT_LEN) "s " + "%" __stringify(RBD_MAX_OPT_LEN) "s " + "%" __stringify(RBD_MAX_POOL_NAME_LEN) "s " + "%" __stringify(RBD_MAX_OBJ_NAME_LEN) "s" + "%" __stringify(RBD_MAX_SNAP_NAME_LEN) "s", + mon_dev_name, options, rbd_dev->pool_name, + rbd_dev->obj, rbd_dev->snap_name) < 4) { + rc = -EINVAL; + goto err_out_slot; + } + + if (rbd_dev->snap_name[0] == 0) + rbd_dev->snap_name[0] = '-'; + + rbd_dev->obj_len = strlen(rbd_dev->obj); + snprintf(rbd_dev->obj_md_name, sizeof(rbd_dev->obj_md_name), "%s%s", + rbd_dev->obj, RBD_SUFFIX); + + /* initialize rest of new object */ + snprintf(rbd_dev->name, DEV_NAME_LEN, DRV_NAME "%d", rbd_dev->id); + rc = rbd_get_client(rbd_dev, mon_dev_name, options); + if (rc < 0) + goto err_out_slot; + + mutex_unlock(&ctl_mutex); + + /* pick the pool */ + osdc = &rbd_dev->client->osdc; + rc = ceph_pg_poolid_by_name(osdc->osdmap, rbd_dev->pool_name); + if (rc < 0) + goto err_out_client; + rbd_dev->poolid = rc; + + /* register our block device */ + irc = register_blkdev(0, rbd_dev->name); + if (irc < 0) { + rc = irc; + goto err_out_client; + } + rbd_dev->major = irc; + + /* set up and announce blkdev mapping */ + rc = rbd_init_disk(rbd_dev); + if (rc) + goto err_out_blkdev; + + return count; + +err_out_blkdev: + unregister_blkdev(rbd_dev->major, rbd_dev->name); +err_out_client: + rbd_put_client(rbd_dev); + mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); +err_out_slot: + list_del_init(&rbd_dev->node); + mutex_unlock(&ctl_mutex); + + kfree(rbd_dev); +err_out_opt: + kfree(options); +err_mon_dev: + kfree(mon_dev_name); +err_out_mod: + dout("Error adding device %s\n", buf); + module_put(THIS_MODULE); + return rc; +} + +static struct rbd_device *__rbd_get_dev(unsigned long id) +{ + struct list_head *tmp; + struct rbd_device *rbd_dev; + + list_for_each(tmp, &rbd_dev_list) { + rbd_dev = list_entry(tmp, struct rbd_device, node); + if (rbd_dev->id == id) + return rbd_dev; + } + return NULL; +} + +static ssize_t class_rbd_remove(struct class *c, + struct class_attribute *attr, + const char *buf, + size_t count) +{ + struct rbd_device *rbd_dev = NULL; + int target_id, rc; + unsigned long ul; + + rc = strict_strtoul(buf, 10, &ul); + if (rc) + return rc; + + /* convert to int; abort if we lost anything in the conversion */ + target_id = (int) ul; + if (target_id != ul) + return -EINVAL; + + /* remove object from list immediately */ + mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); + + rbd_dev = __rbd_get_dev(target_id); + if (rbd_dev) + list_del_init(&rbd_dev->node); + + mutex_unlock(&ctl_mutex); + + if (!rbd_dev) + return -ENOENT; + + rbd_put_client(rbd_dev); + + /* clean up and free blkdev */ + rbd_free_disk(rbd_dev); + unregister_blkdev(rbd_dev->major, rbd_dev->name); + kfree(rbd_dev); + + /* release module ref */ + module_put(THIS_MODULE); + + return count; +} + +static ssize_t class_rbd_snaps_list(struct class *c, + struct class_attribute *attr, + char *data) +{ + struct rbd_device *rbd_dev = NULL; + struct list_head *tmp; + struct rbd_image_header *header; + int i, n = 0, max = PAGE_SIZE; + int ret; + + mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); + + n += snprintf(data, max, "#id\tsnap\tKB\n"); + + list_for_each(tmp, &rbd_dev_list) { + char *names, *p; + struct ceph_snap_context *snapc; + + rbd_dev = list_entry(tmp, struct rbd_device, node); + header = &rbd_dev->header; + + down_read(&header->snap_rwsem); + + names = header->snap_names; + snapc = header->snapc; + + n += snprintf(data + n, max - n, "%d\t%s\t%lld%s\n", + rbd_dev->id, RBD_SNAP_HEAD_NAME, + header->image_size >> 10, + (!rbd_dev->cur_snap ? " (*)" : "")); + if (n == max) + break; + + p = names; + for (i = 0; i < header->total_snaps; i++, p += strlen(p) + 1) { + n += snprintf(data + n, max - n, "%d\t%s\t%lld%s\n", + rbd_dev->id, p, header->snap_sizes[i] >> 10, + (rbd_dev->cur_snap && + (snap_index(header, i) == rbd_dev->cur_snap) ? + " (*)" : "")); + if (n == max) + break; + } + + up_read(&header->snap_rwsem); + } + + + ret = n; + mutex_unlock(&ctl_mutex); + return ret; +} + +static ssize_t class_rbd_snaps_refresh(struct class *c, + struct class_attribute *attr, + const char *buf, + size_t count) +{ + struct rbd_device *rbd_dev = NULL; + int target_id, rc; + unsigned long ul; + int ret = count; + + rc = strict_strtoul(buf, 10, &ul); + if (rc) + return rc; + + /* convert to int; abort if we lost anything in the conversion */ + target_id = (int) ul; + if (target_id != ul) + return -EINVAL; + + mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); + + rbd_dev = __rbd_get_dev(target_id); + if (!rbd_dev) { + ret = -ENOENT; + goto done; + } + + rc = rbd_update_snaps(rbd_dev); + if (rc < 0) + ret = rc; + +done: + mutex_unlock(&ctl_mutex); + return ret; +} + +static ssize_t class_rbd_snap_create(struct class *c, + struct class_attribute *attr, + const char *buf, + size_t count) +{ + struct rbd_device *rbd_dev = NULL; + int target_id, ret; + char *name; + + name = kmalloc(RBD_MAX_SNAP_NAME_LEN + 1, GFP_KERNEL); + if (!name) + return -ENOMEM; + + /* parse snaps add command */ + if (sscanf(buf, "%d " + "%" __stringify(RBD_MAX_SNAP_NAME_LEN) "s", + &target_id, + name) != 2) { + ret = -EINVAL; + goto done; + } + + mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); + + rbd_dev = __rbd_get_dev(target_id); + if (!rbd_dev) { + ret = -ENOENT; + goto done_unlock; + } + + ret = rbd_header_add_snap(rbd_dev, + name, GFP_KERNEL); + if (ret < 0) + goto done_unlock; + + ret = rbd_update_snaps(rbd_dev); + if (ret < 0) + goto done_unlock; + + ret = count; +done_unlock: + mutex_unlock(&ctl_mutex); +done: + kfree(name); + return ret; +} + +static ssize_t class_rbd_rollback(struct class *c, + struct class_attribute *attr, + const char *buf, + size_t count) +{ + struct rbd_device *rbd_dev = NULL; + int target_id, ret; + u64 snapid; + char snap_name[RBD_MAX_SNAP_NAME_LEN]; + u64 cur_ofs; + char *seg_name; + + /* parse snaps add command */ + if (sscanf(buf, "%d " + "%" __stringify(RBD_MAX_SNAP_NAME_LEN) "s", + &target_id, + snap_name) != 2) { + return -EINVAL; + } + + ret = -ENOMEM; + seg_name = kmalloc(RBD_MAX_SEG_NAME_LEN + 1, GFP_NOIO); + if (!seg_name) + return ret; + + mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); + + rbd_dev = __rbd_get_dev(target_id); + if (!rbd_dev) { + ret = -ENOENT; + goto done_unlock; + } + + ret = snap_by_name(&rbd_dev->header, snap_name, &snapid, NULL); + if (ret < 0) + goto done_unlock; + + dout("snapid=%lld\n", snapid); + + cur_ofs = 0; + while (cur_ofs < rbd_dev->header.image_size) { + cur_ofs += rbd_get_segment(&rbd_dev->header, + rbd_dev->obj, + cur_ofs, (u64)-1, + seg_name, NULL); + dout("seg_name=%s\n", seg_name); + + ret = rbd_req_sync_rollback_obj(rbd_dev, snapid, seg_name); + if (ret < 0) + pr_warning("could not roll back obj %s err=%d\n", + seg_name, ret); + } + + ret = rbd_update_snaps(rbd_dev); + if (ret < 0) + goto done_unlock; + + ret = count; + +done_unlock: + mutex_unlock(&ctl_mutex); + kfree(seg_name); + + return ret; +} + +static struct class_attribute class_rbd_attrs[] = { + __ATTR(add, 0200, NULL, class_rbd_add), + __ATTR(remove, 0200, NULL, class_rbd_remove), + __ATTR(list, 0444, class_rbd_list, NULL), + __ATTR(snaps_refresh, 0200, NULL, class_rbd_snaps_refresh), + __ATTR(snap_create, 0200, NULL, class_rbd_snap_create), + __ATTR(snaps_list, 0444, class_rbd_snaps_list, NULL), + __ATTR(snap_rollback, 0200, NULL, class_rbd_rollback), + __ATTR_NULL +}; + +/* + * create control files in sysfs + * /sys/class/rbd/... + */ +static int rbd_sysfs_init(void) +{ + int ret = -ENOMEM; + + class_rbd = kzalloc(sizeof(*class_rbd), GFP_KERNEL); + if (!class_rbd) + goto out; + + class_rbd->name = DRV_NAME; + class_rbd->owner = THIS_MODULE; + class_rbd->class_release = class_rbd_release; + class_rbd->class_attrs = class_rbd_attrs; + + ret = class_register(class_rbd); + if (ret) + goto out_class; + return 0; + +out_class: + kfree(class_rbd); + class_rbd = NULL; + pr_err(DRV_NAME ": failed to create class rbd\n"); +out: + return ret; +} + +static void rbd_sysfs_cleanup(void) +{ + if (class_rbd) + class_destroy(class_rbd); + class_rbd = NULL; +} + +int __init rbd_init(void) +{ + int rc; + + rc = rbd_sysfs_init(); + if (rc) + return rc; + spin_lock_init(&node_lock); + pr_info("loaded " DRV_NAME_LONG "\n"); + return 0; +} + +void __exit rbd_exit(void) +{ + rbd_sysfs_cleanup(); +} + +module_init(rbd_init); +module_exit(rbd_exit); + +MODULE_AUTHOR("Sage Weil <sage@newdream.net>"); +MODULE_AUTHOR("Yehuda Sadeh <yehuda@hq.newdream.net>"); +MODULE_DESCRIPTION("rados block device"); + +/* following authorship retained from original osdblk.c */ +MODULE_AUTHOR("Jeff Garzik <jeff@garzik.org>"); + +MODULE_LICENSE("GPL"); diff --git a/drivers/block/rbd_types.h b/drivers/block/rbd_types.h new file mode 100644 index 000000000000..fc6c678aa2cb --- /dev/null +++ b/drivers/block/rbd_types.h @@ -0,0 +1,73 @@ +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2004-2010 Sage Weil <sage@newdream.net> + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#ifndef CEPH_RBD_TYPES_H +#define CEPH_RBD_TYPES_H + +#include <linux/types.h> + +/* + * rbd image 'foo' consists of objects + * foo.rbd - image metadata + * foo.00000000 + * foo.00000001 + * ... - data + */ + +#define RBD_SUFFIX ".rbd" +#define RBD_DIRECTORY "rbd_directory" +#define RBD_INFO "rbd_info" + +#define RBD_DEFAULT_OBJ_ORDER 22 /* 4MB */ +#define RBD_MIN_OBJ_ORDER 16 +#define RBD_MAX_OBJ_ORDER 30 + +#define RBD_MAX_OBJ_NAME_LEN 96 +#define RBD_MAX_SEG_NAME_LEN 128 + +#define RBD_COMP_NONE 0 +#define RBD_CRYPT_NONE 0 + +#define RBD_HEADER_TEXT "<<< Rados Block Device Image >>>\n" +#define RBD_HEADER_SIGNATURE "RBD" +#define RBD_HEADER_VERSION "001.005" + +struct rbd_info { + __le64 max_id; +} __attribute__ ((packed)); + +struct rbd_image_snap_ondisk { + __le64 id; + __le64 image_size; +} __attribute__((packed)); + +struct rbd_image_header_ondisk { + char text[40]; + char block_name[24]; + char signature[4]; + char version[8]; + struct { + __u8 order; + __u8 crypt_type; + __u8 comp_type; + __u8 unused; + } __attribute__((packed)) options; + __le64 image_size; + __le64 snap_seq; + __le32 snap_count; + __le32 reserved; + __le64 snap_names_len; + struct rbd_image_snap_ondisk snaps[0]; +} __attribute__((packed)); + + +#endif diff --git a/drivers/block/swim.c b/drivers/block/swim.c index 2e46815876df..75333d0a3327 100644 --- a/drivers/block/swim.c +++ b/drivers/block/swim.c @@ -20,7 +20,7 @@ #include <linux/fd.h> #include <linux/slab.h> #include <linux/blkdev.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/hdreg.h> #include <linux/kernel.h> #include <linux/delay.h> @@ -222,6 +222,7 @@ extern int swim_read_sector_header(struct swim __iomem *base, extern int swim_read_sector_data(struct swim __iomem *base, unsigned char *data); +static DEFINE_MUTEX(swim_mutex); static inline void set_swim_mode(struct swim __iomem *base, int enable) { struct iwm __iomem *iwm_base; @@ -666,9 +667,9 @@ static int floppy_unlocked_open(struct block_device *bdev, fmode_t mode) { int ret; - lock_kernel(); + mutex_lock(&swim_mutex); ret = floppy_open(bdev, mode); - unlock_kernel(); + mutex_unlock(&swim_mutex); return ret; } @@ -678,7 +679,7 @@ static int floppy_release(struct gendisk *disk, fmode_t mode) struct floppy_state *fs = disk->private_data; struct swim __iomem *base = fs->swd->base; - lock_kernel(); + mutex_lock(&swim_mutex); if (fs->ref_count < 0) fs->ref_count = 0; else if (fs->ref_count > 0) @@ -686,7 +687,7 @@ static int floppy_release(struct gendisk *disk, fmode_t mode) if (fs->ref_count == 0) swim_motor(base, OFF); - unlock_kernel(); + mutex_unlock(&swim_mutex); return 0; } @@ -704,9 +705,9 @@ static int floppy_ioctl(struct block_device *bdev, fmode_t mode, case FDEJECT: if (fs->ref_count != 1) return -EBUSY; - lock_kernel(); + mutex_lock(&swim_mutex); err = floppy_eject(fs); - unlock_kernel(); + mutex_unlock(&swim_mutex); return err; case FDGETPRM: diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c index cc6a3864822c..bf3a5b859299 100644 --- a/drivers/block/swim3.c +++ b/drivers/block/swim3.c @@ -25,7 +25,7 @@ #include <linux/ioctl.h> #include <linux/blkdev.h> #include <linux/interrupt.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/module.h> #include <linux/spinlock.h> #include <asm/io.h> @@ -36,6 +36,7 @@ #include <asm/machdep.h> #include <asm/pmac_feature.h> +static DEFINE_MUTEX(swim3_mutex); static struct request_queue *swim3_queue; static struct gendisk *disks[2]; static struct request *fd_req; @@ -873,9 +874,9 @@ static int floppy_ioctl(struct block_device *bdev, fmode_t mode, { int ret; - lock_kernel(); + mutex_lock(&swim3_mutex); ret = floppy_locked_ioctl(bdev, mode, cmd, param); - unlock_kernel(); + mutex_unlock(&swim3_mutex); return ret; } @@ -953,9 +954,9 @@ static int floppy_unlocked_open(struct block_device *bdev, fmode_t mode) { int ret; - lock_kernel(); + mutex_lock(&swim3_mutex); ret = floppy_open(bdev, mode); - unlock_kernel(); + mutex_unlock(&swim3_mutex); return ret; } @@ -964,13 +965,13 @@ static int floppy_release(struct gendisk *disk, fmode_t mode) { struct floppy_state *fs = disk->private_data; struct swim3 __iomem *sw = fs->swim3; - lock_kernel(); + mutex_lock(&swim3_mutex); if (fs->ref_count > 0 && --fs->ref_count == 0) { swim3_action(fs, MOTOR_OFF); out_8(&sw->control_bic, 0xff); swim3_select(fs, RELAX); } - unlock_kernel(); + mutex_unlock(&swim3_mutex); return 0; } diff --git a/drivers/block/ub.c b/drivers/block/ub.c index c48e14878582..b5690a045a01 100644 --- a/drivers/block/ub.c +++ b/drivers/block/ub.c @@ -28,7 +28,7 @@ #include <linux/timer.h> #include <linux/scatterlist.h> #include <linux/slab.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <scsi/scsi.h> #define DRV_NAME "ub" @@ -248,6 +248,7 @@ struct ub_completion { spinlock_t lock; }; +static DEFINE_MUTEX(ub_mutex); static inline void ub_init_completion(struct ub_completion *x) { x->done = 0; @@ -1715,9 +1716,9 @@ static int ub_bd_unlocked_open(struct block_device *bdev, fmode_t mode) { int ret; - lock_kernel(); + mutex_lock(&ub_mutex); ret = ub_bd_open(bdev, mode); - unlock_kernel(); + mutex_unlock(&ub_mutex); return ret; } @@ -1730,9 +1731,9 @@ static int ub_bd_release(struct gendisk *disk, fmode_t mode) struct ub_lun *lun = disk->private_data; struct ub_dev *sc = lun->udev; - lock_kernel(); + mutex_lock(&ub_mutex); ub_put(sc); - unlock_kernel(); + mutex_unlock(&ub_mutex); return 0; } @@ -1747,9 +1748,9 @@ static int ub_bd_ioctl(struct block_device *bdev, fmode_t mode, void __user *usermem = (void __user *) arg; int ret; - lock_kernel(); + mutex_lock(&ub_mutex); ret = scsi_cmd_ioctl(disk->queue, disk, mode, cmd, usermem); - unlock_kernel(); + mutex_unlock(&ub_mutex); return ret; } diff --git a/drivers/block/viodasd.c b/drivers/block/viodasd.c index f651e51a3319..e2ff697697c2 100644 --- a/drivers/block/viodasd.c +++ b/drivers/block/viodasd.c @@ -41,7 +41,7 @@ #include <linux/errno.h> #include <linux/init.h> #include <linux/string.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/dma-mapping.h> #include <linux/completion.h> #include <linux/device.h> @@ -73,6 +73,7 @@ enum { MAX_DISK_NAME = FIELD_SIZEOF(struct gendisk, disk_name) }; +static DEFINE_MUTEX(viodasd_mutex); static DEFINE_SPINLOCK(viodasd_spinlock); #define VIOMAXREQ 16 @@ -180,9 +181,9 @@ static int viodasd_unlocked_open(struct block_device *bdev, fmode_t mode) { int ret; - lock_kernel(); + mutex_lock(&viodasd_mutex); ret = viodasd_open(bdev, mode); - unlock_kernel(); + mutex_unlock(&viodasd_mutex); return ret; } @@ -196,7 +197,7 @@ static int viodasd_release(struct gendisk *disk, fmode_t mode) struct viodasd_device *d = disk->private_data; HvLpEvent_Rc hvrc; - lock_kernel(); + mutex_lock(&viodasd_mutex); /* Send the event to OS/400. We DON'T expect a response */ hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, HvLpEvent_Type_VirtualIo, @@ -210,7 +211,7 @@ static int viodasd_release(struct gendisk *disk, fmode_t mode) if (hvrc != 0) pr_warning("HV close call failed %d\n", (int)hvrc); - unlock_kernel(); + mutex_unlock(&viodasd_mutex); return 0; } diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index 1101e251a629..6ecf89cdf006 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -2,7 +2,6 @@ #include <linux/spinlock.h> #include <linux/slab.h> #include <linux/blkdev.h> -#include <linux/smp_lock.h> #include <linux/hdreg.h> #include <linux/virtio.h> #include <linux/virtio_blk.h> @@ -128,9 +127,6 @@ static bool do_req(struct request_queue *q, struct virtio_blk *vblk, } } - if (vbr->req->cmd_flags & REQ_HARDBARRIER) - vbr->out_hdr.type |= VIRTIO_BLK_T_BARRIER; - sg_set_buf(&vblk->sg[out++], &vbr->out_hdr, sizeof(vbr->out_hdr)); /* @@ -222,8 +218,8 @@ static int virtblk_get_id(struct gendisk *disk, char *id_str) return err; } -static int virtblk_locked_ioctl(struct block_device *bdev, fmode_t mode, - unsigned cmd, unsigned long data) +static int virtblk_ioctl(struct block_device *bdev, fmode_t mode, + unsigned int cmd, unsigned long data) { struct gendisk *disk = bdev->bd_disk; struct virtio_blk *vblk = disk->private_data; @@ -238,18 +234,6 @@ static int virtblk_locked_ioctl(struct block_device *bdev, fmode_t mode, (void __user *)data); } -static int virtblk_ioctl(struct block_device *bdev, fmode_t mode, - unsigned int cmd, unsigned long param) -{ - int ret; - - lock_kernel(); - ret = virtblk_locked_ioctl(bdev, mode, cmd, param); - unlock_kernel(); - - return ret; -} - /* We provide getgeo only to please some old bootloader/partitioning tools */ static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo) { @@ -392,31 +376,9 @@ static int __devinit virtblk_probe(struct virtio_device *vdev) vblk->disk->driverfs_dev = &vdev->dev; index++; - if (virtio_has_feature(vdev, VIRTIO_BLK_F_FLUSH)) { - /* - * If the FLUSH feature is supported we do have support for - * flushing a volatile write cache on the host. Use that - * to implement write barrier support. - */ - blk_queue_ordered(q, QUEUE_ORDERED_DRAIN_FLUSH); - } else if (virtio_has_feature(vdev, VIRTIO_BLK_F_BARRIER)) { - /* - * If the BARRIER feature is supported the host expects us - * to order request by tags. This implies there is not - * volatile write cache on the host, and that the host - * never re-orders outstanding I/O. This feature is not - * useful for real life scenarious and deprecated. - */ - blk_queue_ordered(q, QUEUE_ORDERED_TAG); - } else { - /* - * If the FLUSH feature is not supported we must assume that - * the host does not perform any kind of volatile write - * caching. We still need to drain the queue to provider - * proper barrier semantics. - */ - blk_queue_ordered(q, QUEUE_ORDERED_DRAIN); - } + /* configure queue flush support */ + if (virtio_has_feature(vdev, VIRTIO_BLK_F_FLUSH)) + blk_queue_flush(q, REQ_FLUSH); /* If disk is read-only in the host, the guest should obey */ if (virtio_has_feature(vdev, VIRTIO_BLK_F_RO)) @@ -535,9 +497,9 @@ static const struct virtio_device_id id_table[] = { }; static unsigned int features[] = { - VIRTIO_BLK_F_BARRIER, VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX, - VIRTIO_BLK_F_GEOMETRY, VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE, - VIRTIO_BLK_F_SCSI, VIRTIO_BLK_F_FLUSH, VIRTIO_BLK_F_TOPOLOGY + VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX, VIRTIO_BLK_F_GEOMETRY, + VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE, VIRTIO_BLK_F_SCSI, + VIRTIO_BLK_F_FLUSH, VIRTIO_BLK_F_TOPOLOGY }; /* diff --git a/drivers/block/xd.c b/drivers/block/xd.c index d5a3cd750561..4abd2bcd20fb 100644 --- a/drivers/block/xd.c +++ b/drivers/block/xd.c @@ -46,7 +46,7 @@ #include <linux/init.h> #include <linux/wait.h> #include <linux/blkdev.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/blkpg.h> #include <linux/delay.h> #include <linux/io.h> @@ -58,6 +58,7 @@ #include "xd.h" +static DEFINE_MUTEX(xd_mutex); static void __init do_xd_setup (int *integers); #ifdef MODULE static int xd[5] = { -1,-1,-1,-1, }; @@ -381,9 +382,9 @@ static int xd_ioctl(struct block_device *bdev, fmode_t mode, { int ret; - lock_kernel(); + mutex_lock(&xd_mutex); ret = xd_locked_ioctl(bdev, mode, cmd, param); - unlock_kernel(); + mutex_unlock(&xd_mutex); return ret; } diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index ab735a605cf3..4b33a18c32e0 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -41,7 +41,7 @@ #include <linux/cdrom.h> #include <linux/module.h> #include <linux/slab.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/scatterlist.h> #include <xen/xen.h> @@ -69,6 +69,7 @@ struct blk_shadow { unsigned long frame[BLKIF_MAX_SEGMENTS_PER_REQUEST]; }; +static DEFINE_MUTEX(blkfront_mutex); static const struct block_device_operations xlvbd_block_fops; #define BLK_RING_SIZE __RING_SIZE((struct blkif_sring *)0, PAGE_SIZE) @@ -95,7 +96,7 @@ struct blkfront_info struct gnttab_free_callback callback; struct blk_shadow shadow[BLK_RING_SIZE]; unsigned long shadow_free; - int feature_barrier; + unsigned int feature_flush; int is_ready; }; @@ -418,26 +419,12 @@ static int xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size) } -static int xlvbd_barrier(struct blkfront_info *info) +static void xlvbd_flush(struct blkfront_info *info) { - int err; - const char *barrier; - - switch (info->feature_barrier) { - case QUEUE_ORDERED_DRAIN: barrier = "enabled (drain)"; break; - case QUEUE_ORDERED_TAG: barrier = "enabled (tag)"; break; - case QUEUE_ORDERED_NONE: barrier = "disabled"; break; - default: return -EINVAL; - } - - err = blk_queue_ordered(info->rq, info->feature_barrier); - - if (err) - return err; - + blk_queue_flush(info->rq, info->feature_flush); printk(KERN_INFO "blkfront: %s: barriers %s\n", - info->gd->disk_name, barrier); - return 0; + info->gd->disk_name, + info->feature_flush ? "enabled" : "disabled"); } @@ -516,7 +503,7 @@ static int xlvbd_alloc_gendisk(blkif_sector_t capacity, info->rq = gd->queue; info->gd = gd; - xlvbd_barrier(info); + xlvbd_flush(info); if (vdisk_info & VDISK_READONLY) set_disk_ro(gd, 1); @@ -662,8 +649,8 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id) printk(KERN_WARNING "blkfront: %s: write barrier op failed\n", info->gd->disk_name); error = -EOPNOTSUPP; - info->feature_barrier = QUEUE_ORDERED_NONE; - xlvbd_barrier(info); + info->feature_flush = 0; + xlvbd_flush(info); } /* fall through */ case BLKIF_OP_READ: @@ -1076,20 +1063,20 @@ static void blkfront_connect(struct blkfront_info *info) /* * If there's no "feature-barrier" defined, then it means * we're dealing with a very old backend which writes - * synchronously; draining will do what needs to get done. + * synchronously; nothing to do. * - * If there are barriers, then we can do full queued writes - * with tagged barriers. - * - * If barriers are not supported, then there's no much we can - * do, so just set ordering to NONE. + * If there are barriers, then we use flush. */ - if (err) - info->feature_barrier = QUEUE_ORDERED_DRAIN; - else if (barrier) - info->feature_barrier = QUEUE_ORDERED_TAG; - else - info->feature_barrier = QUEUE_ORDERED_NONE; + info->feature_flush = 0; + + /* + * The driver doesn't properly handled empty flushes, so + * lets disable barrier support for now. + */ +#if 0 + if (!err && barrier) + info->feature_flush = REQ_FLUSH; +#endif err = xlvbd_alloc_gendisk(sectors, info, binfo, sector_size); if (err) { @@ -1201,7 +1188,7 @@ static int blkif_open(struct block_device *bdev, fmode_t mode) struct blkfront_info *info; int err = 0; - lock_kernel(); + mutex_lock(&blkfront_mutex); info = disk->private_data; if (!info) { @@ -1219,7 +1206,7 @@ static int blkif_open(struct block_device *bdev, fmode_t mode) mutex_unlock(&info->mutex); out: - unlock_kernel(); + mutex_unlock(&blkfront_mutex); return err; } @@ -1229,7 +1216,7 @@ static int blkif_release(struct gendisk *disk, fmode_t mode) struct block_device *bdev; struct xenbus_device *xbdev; - lock_kernel(); + mutex_lock(&blkfront_mutex); bdev = bdget_disk(disk, 0); bdput(bdev); @@ -1263,7 +1250,7 @@ static int blkif_release(struct gendisk *disk, fmode_t mode) } out: - unlock_kernel(); + mutex_unlock(&blkfront_mutex); return 0; } diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c index 057413bb16e2..6e968cd4893c 100644 --- a/drivers/block/xsysace.c +++ b/drivers/block/xsysace.c @@ -89,7 +89,7 @@ #include <linux/delay.h> #include <linux/slab.h> #include <linux/blkdev.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/ata.h> #include <linux/hdreg.h> #include <linux/platform_device.h> @@ -214,6 +214,7 @@ struct ace_device { u16 cf_id[ATA_ID_WORDS]; }; +static DEFINE_MUTEX(xsysace_mutex); static int ace_major; /* --------------------------------------------------------------------- @@ -903,13 +904,13 @@ static int ace_open(struct block_device *bdev, fmode_t mode) dev_dbg(ace->dev, "ace_open() users=%i\n", ace->users + 1); - lock_kernel(); + mutex_lock(&xsysace_mutex); spin_lock_irqsave(&ace->lock, flags); ace->users++; spin_unlock_irqrestore(&ace->lock, flags); check_disk_change(bdev); - unlock_kernel(); + mutex_unlock(&xsysace_mutex); return 0; } @@ -922,7 +923,7 @@ static int ace_release(struct gendisk *disk, fmode_t mode) dev_dbg(ace->dev, "ace_release() users=%i\n", ace->users - 1); - lock_kernel(); + mutex_lock(&xsysace_mutex); spin_lock_irqsave(&ace->lock, flags); ace->users--; if (ace->users == 0) { @@ -930,7 +931,7 @@ static int ace_release(struct gendisk *disk, fmode_t mode) ace_out(ace, ACE_CTRL, val & ~ACE_CTRL_LOCKREQ); } spin_unlock_irqrestore(&ace->lock, flags); - unlock_kernel(); + mutex_unlock(&xsysace_mutex); return 0; } diff --git a/drivers/block/z2ram.c b/drivers/block/z2ram.c index d75b2bb601ad..dcd4cfcf4126 100644 --- a/drivers/block/z2ram.c +++ b/drivers/block/z2ram.c @@ -33,7 +33,7 @@ #include <linux/module.h> #include <linux/blkdev.h> #include <linux/bitops.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/slab.h> #include <asm/setup.h> @@ -57,6 +57,7 @@ extern struct mem_info m68k_memory[NUM_MEMINFO]; #define Z2RAM_CHUNK1024 ( Z2RAM_CHUNKSIZE >> 10 ) +static DEFINE_MUTEX(z2ram_mutex); static u_long *z2ram_map = NULL; static u_long z2ram_size = 0; static int z2_count = 0; @@ -154,7 +155,7 @@ static int z2_open(struct block_device *bdev, fmode_t mode) device = MINOR(bdev->bd_dev); - lock_kernel(); + mutex_lock(&z2ram_mutex); if ( current_device != -1 && current_device != device ) { rc = -EBUSY; @@ -296,25 +297,25 @@ static int z2_open(struct block_device *bdev, fmode_t mode) set_capacity(z2ram_gendisk, z2ram_size >> 9); } - unlock_kernel(); + mutex_unlock(&z2ram_mutex); return 0; err_out_kfree: kfree(z2ram_map); err_out: - unlock_kernel(); + mutex_unlock(&z2ram_mutex); return rc; } static int z2_release(struct gendisk *disk, fmode_t mode) { - lock_kernel(); + mutex_lock(&z2ram_mutex); if ( current_device == -1 ) { - unlock_kernel(); + mutex_unlock(&z2ram_mutex); return 0; } - unlock_kernel(); + mutex_unlock(&z2ram_mutex); /* * FIXME: unmap memory */ diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c index d52e90a5a617..4104b7feae67 100644 --- a/drivers/bluetooth/bluecard_cs.c +++ b/drivers/bluetooth/bluecard_cs.c @@ -39,7 +39,6 @@ #include <linux/skbuff.h> #include <linux/io.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/ciscode.h> #include <pcmcia/ds.h> @@ -865,8 +864,7 @@ static int bluecard_probe(struct pcmcia_device *link) info->p_dev = link; link->priv = info; - link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.IntType = INT_MEMORY_AND_IO; + link->config_flags |= CONF_ENABLE_IRQ; return bluecard_config(link); } @@ -886,7 +884,7 @@ static int bluecard_config(struct pcmcia_device *link) bluecard_info_t *info = link->priv; int i, n; - link->conf.ConfigIndex = 0x20; + link->config_index = 0x20; link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; link->resource[0]->end = 64; @@ -906,7 +904,7 @@ static int bluecard_config(struct pcmcia_device *link) if (i != 0) goto failed; - i = pcmcia_request_configuration(link, &link->conf); + i = pcmcia_enable_device(link); if (i != 0) goto failed; @@ -942,9 +940,7 @@ MODULE_DEVICE_TABLE(pcmcia, bluecard_ids); static struct pcmcia_driver bluecard_driver = { .owner = THIS_MODULE, - .drv = { - .name = "bluecard_cs", - }, + .name = "bluecard_cs", .probe = bluecard_probe, .remove = bluecard_detach, .id_table = bluecard_ids, diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c index 7ab8f29d5e0d..0c8a65587491 100644 --- a/drivers/bluetooth/bt3c_cs.c +++ b/drivers/bluetooth/bt3c_cs.c @@ -45,7 +45,6 @@ #include <linux/device.h> #include <linux/firmware.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/ciscode.h> #include <pcmcia/ds.h> @@ -657,11 +656,8 @@ static int bt3c_probe(struct pcmcia_device *link) info->p_dev = link; link->priv = info; - link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; - link->resource[0]->end = 8; - - link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.IntType = INT_MEMORY_AND_IO; + link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_VPP | + CONF_AUTO_SET_IO; return bt3c_config(link); } @@ -675,43 +671,41 @@ static void bt3c_detach(struct pcmcia_device *link) kfree(info); } -static int bt3c_check_config(struct pcmcia_device *p_dev, - cistpl_cftable_entry_t *cf, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, - void *priv_data) +static int bt3c_check_config(struct pcmcia_device *p_dev, void *priv_data) { - unsigned long try = (unsigned long) priv_data; + int *try = priv_data; - p_dev->io_lines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK; + if (try == 0) + p_dev->io_lines = 16; - if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM)) - p_dev->conf.Vpp = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000; - if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) && - (cf->io.win[0].base != 0)) { - p_dev->resource[0]->start = cf->io.win[0].base; - if (!pcmcia_request_io(p_dev)) - return 0; - } - return -ENODEV; + if ((p_dev->resource[0]->end != 8) || (p_dev->resource[0]->start == 0)) + return -EINVAL; + + p_dev->resource[0]->end = 8; + p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; + p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; + + return pcmcia_request_io(p_dev); } static int bt3c_check_config_notpicky(struct pcmcia_device *p_dev, - cistpl_cftable_entry_t *cf, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, void *priv_data) { static unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 }; int j; - if ((cf->io.nwin > 0) && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) { - for (j = 0; j < 5; j++) { - p_dev->resource[0]->start = base[j]; - p_dev->io_lines = base[j] ? 16 : 3; - if (!pcmcia_request_io(p_dev)) - return 0; - } + if (p_dev->io_lines > 3) + return -ENODEV; + + p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; + p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; + p_dev->resource[0]->end = 8; + + for (j = 0; j < 5; j++) { + p_dev->resource[0]->start = base[j]; + p_dev->io_lines = base[j] ? 16 : 3; + if (!pcmcia_request_io(p_dev)) + return 0; } return -ENODEV; } @@ -742,7 +736,7 @@ found_port: if (i != 0) goto failed; - i = pcmcia_request_configuration(link, &link->conf); + i = pcmcia_enable_device(link); if (i != 0) goto failed; @@ -775,9 +769,7 @@ MODULE_DEVICE_TABLE(pcmcia, bt3c_ids); static struct pcmcia_driver bt3c_driver = { .owner = THIS_MODULE, - .drv = { - .name = "bt3c_cs", - }, + .name = "bt3c_cs", .probe = bt3c_probe, .remove = bt3c_detach, .id_table = bt3c_ids, diff --git a/drivers/bluetooth/btmrvl_debugfs.c b/drivers/bluetooth/btmrvl_debugfs.c index 54739b08c308..fd6305bf953e 100644 --- a/drivers/bluetooth/btmrvl_debugfs.c +++ b/drivers/bluetooth/btmrvl_debugfs.c @@ -92,6 +92,7 @@ static const struct file_operations btmrvl_hscfgcmd_fops = { .read = btmrvl_hscfgcmd_read, .write = btmrvl_hscfgcmd_write, .open = btmrvl_open_generic, + .llseek = default_llseek, }; static ssize_t btmrvl_psmode_write(struct file *file, const char __user *ubuf, @@ -130,6 +131,7 @@ static const struct file_operations btmrvl_psmode_fops = { .read = btmrvl_psmode_read, .write = btmrvl_psmode_write, .open = btmrvl_open_generic, + .llseek = default_llseek, }; static ssize_t btmrvl_pscmd_write(struct file *file, const char __user *ubuf, @@ -173,6 +175,7 @@ static const struct file_operations btmrvl_pscmd_fops = { .read = btmrvl_pscmd_read, .write = btmrvl_pscmd_write, .open = btmrvl_open_generic, + .llseek = default_llseek, }; static ssize_t btmrvl_gpiogap_write(struct file *file, const char __user *ubuf, @@ -211,6 +214,7 @@ static const struct file_operations btmrvl_gpiogap_fops = { .read = btmrvl_gpiogap_read, .write = btmrvl_gpiogap_write, .open = btmrvl_open_generic, + .llseek = default_llseek, }; static ssize_t btmrvl_hscmd_write(struct file *file, const char __user *ubuf, @@ -252,6 +256,7 @@ static const struct file_operations btmrvl_hscmd_fops = { .read = btmrvl_hscmd_read, .write = btmrvl_hscmd_write, .open = btmrvl_open_generic, + .llseek = default_llseek, }; static ssize_t btmrvl_hsmode_write(struct file *file, const char __user *ubuf, @@ -289,6 +294,7 @@ static const struct file_operations btmrvl_hsmode_fops = { .read = btmrvl_hsmode_read, .write = btmrvl_hsmode_write, .open = btmrvl_open_generic, + .llseek = default_llseek, }; static ssize_t btmrvl_curpsmode_read(struct file *file, char __user *userbuf, @@ -306,6 +312,7 @@ static ssize_t btmrvl_curpsmode_read(struct file *file, char __user *userbuf, static const struct file_operations btmrvl_curpsmode_fops = { .read = btmrvl_curpsmode_read, .open = btmrvl_open_generic, + .llseek = default_llseek, }; static ssize_t btmrvl_psstate_read(struct file *file, char __user * userbuf, @@ -323,6 +330,7 @@ static ssize_t btmrvl_psstate_read(struct file *file, char __user * userbuf, static const struct file_operations btmrvl_psstate_fops = { .read = btmrvl_psstate_read, .open = btmrvl_open_generic, + .llseek = default_llseek, }; static ssize_t btmrvl_hsstate_read(struct file *file, char __user *userbuf, @@ -340,6 +348,7 @@ static ssize_t btmrvl_hsstate_read(struct file *file, char __user *userbuf, static const struct file_operations btmrvl_hsstate_fops = { .read = btmrvl_hsstate_read, .open = btmrvl_open_generic, + .llseek = default_llseek, }; static ssize_t btmrvl_txdnldready_read(struct file *file, char __user *userbuf, @@ -358,6 +367,7 @@ static ssize_t btmrvl_txdnldready_read(struct file *file, char __user *userbuf, static const struct file_operations btmrvl_txdnldready_fops = { .read = btmrvl_txdnldready_read, .open = btmrvl_open_generic, + .llseek = default_llseek, }; void btmrvl_debugfs_init(struct hci_dev *hdev) diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c index 1c4f5e863b03..f8a0708e2311 100644 --- a/drivers/bluetooth/btuart_cs.c +++ b/drivers/bluetooth/btuart_cs.c @@ -41,7 +41,6 @@ #include <asm/system.h> #include <asm/io.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/ciscode.h> #include <pcmcia/ds.h> @@ -586,11 +585,8 @@ static int btuart_probe(struct pcmcia_device *link) info->p_dev = link; link->priv = info; - link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; - link->resource[0]->end = 8; - - link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.IntType = INT_MEMORY_AND_IO; + link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_VPP | + CONF_AUTO_SET_IO; return btuart_config(link); } @@ -604,43 +600,41 @@ static void btuart_detach(struct pcmcia_device *link) kfree(info); } -static int btuart_check_config(struct pcmcia_device *p_dev, - cistpl_cftable_entry_t *cf, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, - void *priv_data) +static int btuart_check_config(struct pcmcia_device *p_dev, void *priv_data) { int *try = priv_data; - p_dev->io_lines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK; + if (try == 0) + p_dev->io_lines = 16; - if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM)) - p_dev->conf.Vpp = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000; - if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) && - (cf->io.win[0].base != 0)) { - p_dev->resource[0]->start = cf->io.win[0].base; - if (!pcmcia_request_io(p_dev)) - return 0; - } - return -ENODEV; + if ((p_dev->resource[0]->end != 8) || (p_dev->resource[0]->start == 0)) + return -EINVAL; + + p_dev->resource[0]->end = 8; + p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; + p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; + + return pcmcia_request_io(p_dev); } static int btuart_check_config_notpicky(struct pcmcia_device *p_dev, - cistpl_cftable_entry_t *cf, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, void *priv_data) { static unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 }; int j; - if ((cf->io.nwin > 0) && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) { - for (j = 0; j < 5; j++) { - p_dev->resource[0]->start = base[j]; - p_dev->io_lines = base[j] ? 16 : 3; - if (!pcmcia_request_io(p_dev)) - return 0; - } + if (p_dev->io_lines > 3) + return -ENODEV; + + p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; + p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; + p_dev->resource[0]->end = 8; + + for (j = 0; j < 5; j++) { + p_dev->resource[0]->start = base[j]; + p_dev->io_lines = base[j] ? 16 : 3; + if (!pcmcia_request_io(p_dev)) + return 0; } return -ENODEV; } @@ -671,7 +665,7 @@ found_port: if (i != 0) goto failed; - i = pcmcia_request_configuration(link, &link->conf); + i = pcmcia_enable_device(link); if (i != 0) goto failed; @@ -703,9 +697,7 @@ MODULE_DEVICE_TABLE(pcmcia, btuart_ids); static struct pcmcia_driver btuart_driver = { .owner = THIS_MODULE, - .drv = { - .name = "btuart_cs", - }, + .name = "btuart_cs", .probe = btuart_probe, .remove = btuart_detach, .id_table = btuart_ids, diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c index db7c8db695fc..26ee0cf88d20 100644 --- a/drivers/bluetooth/dtl1_cs.c +++ b/drivers/bluetooth/dtl1_cs.c @@ -41,7 +41,6 @@ #include <asm/system.h> #include <asm/io.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/ciscode.h> #include <pcmcia/ds.h> @@ -572,11 +571,7 @@ static int dtl1_probe(struct pcmcia_device *link) info->p_dev = link; link->priv = info; - link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; - link->resource[0]->end = 8; - - link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.IntType = INT_MEMORY_AND_IO; + link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; return dtl1_config(link); } @@ -591,18 +586,14 @@ static void dtl1_detach(struct pcmcia_device *link) kfree(info); } -static int dtl1_confcheck(struct pcmcia_device *p_dev, - cistpl_cftable_entry_t *cf, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, - void *priv_data) +static int dtl1_confcheck(struct pcmcia_device *p_dev, void *priv_data) { - if ((cf->io.nwin != 1) || (cf->io.win[0].len <= 8)) + if ((p_dev->resource[1]->end) || (p_dev->resource[1]->end < 8)) return -ENODEV; - p_dev->resource[0]->start = cf->io.win[0].base; - p_dev->resource[0]->end = cf->io.win[0].len; /*yo */ - p_dev->io_lines = cf->io.flags & CISTPL_IO_LINES_MASK; + p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; + p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; + return pcmcia_request_io(p_dev); } @@ -620,7 +611,7 @@ static int dtl1_config(struct pcmcia_device *link) if (i != 0) goto failed; - i = pcmcia_request_configuration(link, &link->conf); + i = pcmcia_enable_device(link); if (i != 0) goto failed; @@ -656,9 +647,7 @@ MODULE_DEVICE_TABLE(pcmcia, dtl1_ids); static struct pcmcia_driver dtl1_driver = { .owner = THIS_MODULE, - .drv = { - .name = "dtl1_cs", - }, + .name = "dtl1_cs", .probe = dtl1_probe, .remove = dtl1_detach, .id_table = dtl1_ids, diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 998833d93c13..17361bad46dd 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -256,9 +256,16 @@ static int hci_uart_tty_open(struct tty_struct *tty) BT_DBG("tty %p", tty); + /* FIXME: This btw is bogus, nothing requires the old ldisc to clear + the pointer */ if (hu) return -EEXIST; + /* Error if the tty has no write op instead of leaving an exploitable + hole */ + if (tty->ops->write == NULL) + return -EOPNOTSUPP; + if (!(hu = kzalloc(sizeof(struct hci_uart), GFP_KERNEL))) { BT_ERR("Can't allocate control structure"); return -ENFILE; diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c index 3aa7b2a54b6f..67c180c2c1e0 100644 --- a/drivers/bluetooth/hci_vhci.c +++ b/drivers/bluetooth/hci_vhci.c @@ -282,6 +282,7 @@ static const struct file_operations vhci_fops = { .poll = vhci_poll, .open = vhci_open, .release = vhci_release, + .llseek = no_llseek, }; static struct miscdevice vhci_miscdev= { diff --git a/drivers/cdrom/gdrom.c b/drivers/cdrom/gdrom.c index 261107d1457c..3af6516919b7 100644 --- a/drivers/cdrom/gdrom.c +++ b/drivers/cdrom/gdrom.c @@ -34,7 +34,7 @@ #include <linux/blkdev.h> #include <linux/interrupt.h> #include <linux/device.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/wait.h> #include <linux/workqueue.h> #include <linux/platform_device.h> @@ -81,6 +81,7 @@ #define GDROM_DEFAULT_TIMEOUT (HZ * 7) +static DEFINE_MUTEX(gdrom_mutex); static const struct { int sense_key; const char * const text; @@ -494,17 +495,17 @@ static struct cdrom_device_ops gdrom_ops = { static int gdrom_bdops_open(struct block_device *bdev, fmode_t mode) { int ret; - lock_kernel(); + mutex_lock(&gdrom_mutex); ret = cdrom_open(gd.cd_info, bdev, mode); - unlock_kernel(); + mutex_unlock(&gdrom_mutex); return ret; } static int gdrom_bdops_release(struct gendisk *disk, fmode_t mode) { - lock_kernel(); + mutex_lock(&gdrom_mutex); cdrom_release(gd.cd_info, mode); - unlock_kernel(); + mutex_unlock(&gdrom_mutex); return 0; } @@ -518,9 +519,9 @@ static int gdrom_bdops_ioctl(struct block_device *bdev, fmode_t mode, { int ret; - lock_kernel(); + mutex_lock(&gdrom_mutex); ret = cdrom_ioctl(gd.cd_info, bdev, mode, cmd, arg); - unlock_kernel(); + mutex_unlock(&gdrom_mutex); return ret; } diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c index 56bf9f44700c..be73a9b493a6 100644 --- a/drivers/cdrom/viocd.c +++ b/drivers/cdrom/viocd.c @@ -42,7 +42,7 @@ #include <linux/module.h> #include <linux/completion.h> #include <linux/proc_fs.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/seq_file.h> #include <linux/scatterlist.h> @@ -61,6 +61,7 @@ */ #define VIOCD_MAX_CD HVMAXARCHITECTEDVIRTUALCDROMS +static DEFINE_MUTEX(viocd_mutex); static const struct vio_error_entry viocd_err_table[] = { {0x0201, EINVAL, "Invalid Range"}, {0x0202, EINVAL, "Invalid Token"}, @@ -156,9 +157,9 @@ static int viocd_blk_open(struct block_device *bdev, fmode_t mode) struct disk_info *di = bdev->bd_disk->private_data; int ret; - lock_kernel(); + mutex_lock(&viocd_mutex); ret = cdrom_open(&di->viocd_info, bdev, mode); - unlock_kernel(); + mutex_unlock(&viocd_mutex); return ret; } @@ -166,9 +167,9 @@ static int viocd_blk_open(struct block_device *bdev, fmode_t mode) static int viocd_blk_release(struct gendisk *disk, fmode_t mode) { struct disk_info *di = disk->private_data; - lock_kernel(); + mutex_lock(&viocd_mutex); cdrom_release(&di->viocd_info, mode); - unlock_kernel(); + mutex_unlock(&viocd_mutex); return 0; } @@ -178,9 +179,9 @@ static int viocd_blk_ioctl(struct block_device *bdev, fmode_t mode, struct disk_info *di = bdev->bd_disk->private_data; int ret; - lock_kernel(); + mutex_lock(&viocd_mutex); ret = cdrom_ioctl(&di->viocd_info, bdev, mode, cmd, arg); - unlock_kernel(); + mutex_unlock(&viocd_mutex); return ret; } diff --git a/drivers/char/agp/Kconfig b/drivers/char/agp/Kconfig index 4b66c69eaf57..5ddf67e76f8b 100644 --- a/drivers/char/agp/Kconfig +++ b/drivers/char/agp/Kconfig @@ -57,7 +57,7 @@ config AGP_AMD config AGP_AMD64 tristate "AMD Opteron/Athlon64 on-CPU GART support" - depends on AGP && X86 && K8_NB + depends on AGP && X86 && AMD_NB help This option gives you AGP support for the GLX component of X using the on-CPU northbridge of the AMD Athlon64/Opteron CPUs. diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c index 70312da4c968..42396df55556 100644 --- a/drivers/char/agp/amd64-agp.c +++ b/drivers/char/agp/amd64-agp.c @@ -15,7 +15,7 @@ #include <linux/mmzone.h> #include <asm/page.h> /* PAGE_SIZE */ #include <asm/e820.h> -#include <asm/k8.h> +#include <asm/amd_nb.h> #include <asm/gart.h> #include "agp.h" @@ -124,7 +124,7 @@ static int amd64_fetch_size(void) u32 temp; struct aper_size_info_32 *values; - dev = k8_northbridges[0]; + dev = k8_northbridges.nb_misc[0]; if (dev==NULL) return 0; @@ -181,10 +181,14 @@ static int amd_8151_configure(void) unsigned long gatt_bus = virt_to_phys(agp_bridge->gatt_table_real); int i; + if (!k8_northbridges.gart_supported) + return 0; + /* Configure AGP regs in each x86-64 host bridge. */ - for (i = 0; i < num_k8_northbridges; i++) { + for (i = 0; i < k8_northbridges.num; i++) { agp_bridge->gart_bus_addr = - amd64_configure(k8_northbridges[i], gatt_bus); + amd64_configure(k8_northbridges.nb_misc[i], + gatt_bus); } k8_flush_garts(); return 0; @@ -195,11 +199,15 @@ static void amd64_cleanup(void) { u32 tmp; int i; - for (i = 0; i < num_k8_northbridges; i++) { - struct pci_dev *dev = k8_northbridges[i]; + + if (!k8_northbridges.gart_supported) + return; + + for (i = 0; i < k8_northbridges.num; i++) { + struct pci_dev *dev = k8_northbridges.nb_misc[i]; /* disable gart translation */ pci_read_config_dword(dev, AMD64_GARTAPERTURECTL, &tmp); - tmp &= ~AMD64_GARTEN; + tmp &= ~GARTEN; pci_write_config_dword(dev, AMD64_GARTAPERTURECTL, tmp); } } @@ -313,22 +321,25 @@ static __devinit int fix_northbridge(struct pci_dev *nb, struct pci_dev *agp, if (order < 0 || !agp_aperture_valid(aper, (32*1024*1024)<<order)) return -1; - pci_write_config_dword(nb, AMD64_GARTAPERTURECTL, order << 1); + gart_set_size_and_enable(nb, order); pci_write_config_dword(nb, AMD64_GARTAPERTUREBASE, aper >> 25); return 0; } -static __devinit int cache_nbs (struct pci_dev *pdev, u32 cap_ptr) +static __devinit int cache_nbs(struct pci_dev *pdev, u32 cap_ptr) { int i; if (cache_k8_northbridges() < 0) return -ENODEV; + if (!k8_northbridges.gart_supported) + return -ENODEV; + i = 0; - for (i = 0; i < num_k8_northbridges; i++) { - struct pci_dev *dev = k8_northbridges[i]; + for (i = 0; i < k8_northbridges.num; i++) { + struct pci_dev *dev = k8_northbridges.nb_misc[i]; if (fix_northbridge(dev, pdev, cap_ptr) < 0) { dev_err(&dev->dev, "no usable aperture found\n"); #ifdef __x86_64__ @@ -405,7 +416,8 @@ static int __devinit uli_agp_init(struct pci_dev *pdev) } /* shadow x86-64 registers into ULi registers */ - pci_read_config_dword (k8_northbridges[0], AMD64_GARTAPERTUREBASE, &httfea); + pci_read_config_dword (k8_northbridges.nb_misc[0], AMD64_GARTAPERTUREBASE, + &httfea); /* if x86-64 aperture base is beyond 4G, exit here */ if ((httfea & 0x7fff) >> (32 - 25)) { @@ -472,7 +484,8 @@ static int nforce3_agp_init(struct pci_dev *pdev) pci_write_config_dword(dev1, NVIDIA_X86_64_1_APSIZE, tmp); /* shadow x86-64 registers into NVIDIA registers */ - pci_read_config_dword (k8_northbridges[0], AMD64_GARTAPERTUREBASE, &apbase); + pci_read_config_dword (k8_northbridges.nb_misc[0], AMD64_GARTAPERTUREBASE, + &apbase); /* if x86-64 aperture base is beyond 4G, exit here */ if ( (apbase & 0x7fff) >> (32 - 25) ) { diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c index d2abf5143983..64255cef8a7d 100644 --- a/drivers/char/agp/generic.c +++ b/drivers/char/agp/generic.c @@ -984,7 +984,9 @@ int agp_generic_create_gatt_table(struct agp_bridge_data *bridge) bridge->driver->cache_flush(); #ifdef CONFIG_X86 - set_memory_uc((unsigned long)table, 1 << page_order); + if (set_memory_uc((unsigned long)table, 1 << page_order)) + printk(KERN_WARNING "Could not set GATT table memory to UC!"); + bridge->gatt_table = (void *)table; #else bridge->gatt_table = ioremap_nocache(virt_to_phys(table), diff --git a/drivers/char/apm-emulation.c b/drivers/char/apm-emulation.c index 033e1505fca9..3022801669b1 100644 --- a/drivers/char/apm-emulation.c +++ b/drivers/char/apm-emulation.c @@ -13,7 +13,7 @@ #include <linux/module.h> #include <linux/poll.h> #include <linux/slab.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/miscdevice.h> @@ -126,6 +126,7 @@ struct apm_user { /* * Local variables */ +static DEFINE_MUTEX(apm_mutex); static atomic_t suspend_acks_pending = ATOMIC_INIT(0); static atomic_t userspace_notification_inhibit = ATOMIC_INIT(0); static int apm_disabled; @@ -274,7 +275,7 @@ apm_ioctl(struct file *filp, u_int cmd, u_long arg) if (!as->suser || !as->writer) return -EPERM; - lock_kernel(); + mutex_lock(&apm_mutex); switch (cmd) { case APM_IOC_SUSPEND: mutex_lock(&state_lock); @@ -335,7 +336,7 @@ apm_ioctl(struct file *filp, u_int cmd, u_long arg) mutex_unlock(&state_lock); break; } - unlock_kernel(); + mutex_unlock(&apm_mutex); return err; } @@ -370,7 +371,7 @@ static int apm_open(struct inode * inode, struct file * filp) { struct apm_user *as; - lock_kernel(); + mutex_lock(&apm_mutex); as = kzalloc(sizeof(*as), GFP_KERNEL); if (as) { /* @@ -390,7 +391,7 @@ static int apm_open(struct inode * inode, struct file * filp) filp->private_data = as; } - unlock_kernel(); + mutex_unlock(&apm_mutex); return as ? 0 : -ENOMEM; } @@ -402,6 +403,7 @@ static const struct file_operations apm_bios_fops = { .unlocked_ioctl = apm_ioctl, .open = apm_open, .release = apm_release, + .llseek = noop_llseek, }; static struct miscdevice apm_device = { diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c index f4ae0e0fb631..e7ba774beda6 100644 --- a/drivers/char/applicom.c +++ b/drivers/char/applicom.c @@ -26,7 +26,7 @@ #include <linux/sched.h> #include <linux/slab.h> #include <linux/errno.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/miscdevice.h> #include <linux/pci.h> #include <linux/wait.h> @@ -60,6 +60,7 @@ #define PCI_DEVICE_ID_APPLICOM_PCI2000PFB 0x0003 #endif +static DEFINE_MUTEX(ac_mutex); static char *applicom_pci_devnames[] = { "PCI board", "PCI2000IBS / PCI2000CAN", @@ -707,7 +708,7 @@ static long ac_ioctl(struct file *file, unsigned int cmd, unsigned long arg) if (IS_ERR(adgl)) return PTR_ERR(adgl); - lock_kernel(); + mutex_lock(&ac_mutex); IndexCard = adgl->num_card-1; if(cmd != 6 && ((IndexCard >= MAX_BOARD) || !apbs[IndexCard].RamIO)) { @@ -717,7 +718,7 @@ static long ac_ioctl(struct file *file, unsigned int cmd, unsigned long arg) warncount--; } kfree(adgl); - unlock_kernel(); + mutex_unlock(&ac_mutex); return -EINVAL; } @@ -835,7 +836,7 @@ static long ac_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } Dummy = readb(apbs[IndexCard].RamIO + VERS); kfree(adgl); - unlock_kernel(); + mutex_unlock(&ac_mutex); return 0; } diff --git a/drivers/char/bfin-otp.c b/drivers/char/bfin-otp.c index 836d4f0a876f..44660f1c4849 100644 --- a/drivers/char/bfin-otp.c +++ b/drivers/char/bfin-otp.c @@ -222,6 +222,7 @@ static const struct file_operations bfin_otp_fops = { .unlocked_ioctl = bfin_otp_ioctl, .read = bfin_otp_read, .write = bfin_otp_write, + .llseek = default_llseek, }; static struct miscdevice bfin_otp_misc_device = { diff --git a/drivers/char/briq_panel.c b/drivers/char/briq_panel.c index d5fa113afe37..f6718f05dad4 100644 --- a/drivers/char/briq_panel.c +++ b/drivers/char/briq_panel.c @@ -186,6 +186,7 @@ static const struct file_operations briq_panel_fops = { .write = briq_panel_write, .open = briq_panel_open, .release = briq_panel_release, + .llseek = noop_llseek, }; static struct miscdevice briq_panel_miscdev = { diff --git a/drivers/char/bsr.c b/drivers/char/bsr.c index 91917133ae0a..a4a6c2f044b5 100644 --- a/drivers/char/bsr.c +++ b/drivers/char/bsr.c @@ -155,6 +155,7 @@ static const struct file_operations bsr_fops = { .owner = THIS_MODULE, .mmap = bsr_mmap, .open = bsr_open, + .llseek = noop_llseek, }; static void bsr_cleanup_devs(void) diff --git a/drivers/char/cs5535_gpio.c b/drivers/char/cs5535_gpio.c index 4d830dc482ef..0cf1e5fad9ab 100644 --- a/drivers/char/cs5535_gpio.c +++ b/drivers/char/cs5535_gpio.c @@ -169,7 +169,8 @@ static const struct file_operations cs5535_gpio_fops = { .owner = THIS_MODULE, .write = cs5535_gpio_write, .read = cs5535_gpio_read, - .open = cs5535_gpio_open + .open = cs5535_gpio_open, + .llseek = no_llseek, }; static int __init cs5535_gpio_init(void) diff --git a/drivers/char/ds1302.c b/drivers/char/ds1302.c index 170693c93c73..ed8303f9890c 100644 --- a/drivers/char/ds1302.c +++ b/drivers/char/ds1302.c @@ -20,7 +20,7 @@ #include <linux/miscdevice.h> #include <linux/delay.h> #include <linux/bcd.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/uaccess.h> #include <linux/io.h> @@ -32,6 +32,7 @@ #define RTC_MAJOR_NR 121 /* local major, change later */ +static DEFINE_MUTEX(rtc_mutex); static const char ds1302_name[] = "ds1302"; /* Send 8 bits. */ @@ -164,9 +165,9 @@ static long rtc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) struct rtc_time rtc_tm; memset(&rtc_tm, 0, sizeof (struct rtc_time)); - lock_kernel(); + mutex_lock(&rtc_mutex); get_rtc_time(&rtc_tm); - unlock_kernel(); + mutex_unlock(&rtc_mutex); if (copy_to_user((struct rtc_time*)arg, &rtc_tm, sizeof(struct rtc_time))) return -EFAULT; return 0; @@ -218,7 +219,7 @@ static long rtc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) mon = bin2bcd(mon); yrs = bin2bcd(yrs); - lock_kernel(); + mutex_lock(&rtc_mutex); local_irq_save(flags); CMOS_WRITE(yrs, RTC_YEAR); CMOS_WRITE(mon, RTC_MONTH); @@ -227,7 +228,7 @@ static long rtc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) CMOS_WRITE(min, RTC_MINUTES); CMOS_WRITE(sec, RTC_SECONDS); local_irq_restore(flags); - unlock_kernel(); + mutex_unlock(&rtc_mutex); /* Notice that at this point, the RTC is updated but * the kernel is still running with the old time. @@ -247,10 +248,10 @@ static long rtc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) if(copy_from_user(&tcs_val, (int*)arg, sizeof(int))) return -EFAULT; - lock_kernel(); + mutex_lock(&rtc_mutex); tcs_val = RTC_TCR_PATTERN | (tcs_val & 0x0F); ds1302_writereg(RTC_TRICKLECHARGER, tcs_val); - unlock_kernel(); + mutex_unlock(&rtc_mutex); return 0; } default: @@ -288,6 +289,7 @@ get_rtc_status(char *buf) static const struct file_operations rtc_fops = { .owner = THIS_MODULE, .unlocked_ioctl = rtc_ioctl, + .llseek = noop_llseek, }; /* Probe for the chip by writing something to its RAM and try reading it back. */ diff --git a/drivers/char/ds1620.c b/drivers/char/ds1620.c index dbee8688f75c..aab9605f0b43 100644 --- a/drivers/char/ds1620.c +++ b/drivers/char/ds1620.c @@ -8,7 +8,7 @@ #include <linux/proc_fs.h> #include <linux/capability.h> #include <linux/init.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <mach/hardware.h> #include <asm/mach-types.h> @@ -34,6 +34,7 @@ #define CFG_CPU 2 #define CFG_1SHOT 1 +static DEFINE_MUTEX(ds1620_mutex); static const char *fan_state[] = { "off", "on", "on (hardwired)" }; /* @@ -210,7 +211,6 @@ static void ds1620_read_state(struct therm *therm) static int ds1620_open(struct inode *inode, struct file *file) { - cycle_kernel_lock(); return nonseekable_open(inode, file); } @@ -321,9 +321,9 @@ ds1620_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int ret; - lock_kernel(); + mutex_lock(&ds1620_mutex); ret = ds1620_ioctl(file, cmd, arg); - unlock_kernel(); + mutex_unlock(&ds1620_mutex); return ret; } @@ -357,6 +357,7 @@ static const struct file_operations ds1620_fops = { .open = ds1620_open, .read = ds1620_read, .unlocked_ioctl = ds1620_unlocked_ioctl, + .llseek = no_llseek, }; static struct miscdevice ds1620_miscdev = { diff --git a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c index 8a1b28a10ef0..052797b32bd3 100644 --- a/drivers/char/dsp56k.c +++ b/drivers/char/dsp56k.c @@ -32,7 +32,7 @@ #include <linux/mm.h> #include <linux/init.h> #include <linux/device.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/firmware.h> #include <linux/platform_device.h> #include <linux/uaccess.h> /* For put_user and get_user */ @@ -94,6 +94,7 @@ } \ } +static DEFINE_MUTEX(dsp56k_mutex); static struct dsp56k_device { unsigned long in_use; long maxio, timeout; @@ -330,9 +331,9 @@ static long dsp56k_ioctl(struct file *file, unsigned int cmd, if (len > DSP56K_MAX_BINARY_LENGTH) { return -EINVAL; } - lock_kernel(); + mutex_lock(&dsp56k_mutex); r = dsp56k_upload(bin, len); - unlock_kernel(); + mutex_unlock(&dsp56k_mutex); if (r < 0) { return r; } @@ -342,16 +343,16 @@ static long dsp56k_ioctl(struct file *file, unsigned int cmd, case DSP56K_SET_TX_WSIZE: if (arg > 4 || arg < 1) return -EINVAL; - lock_kernel(); + mutex_lock(&dsp56k_mutex); dsp56k.tx_wsize = (int) arg; - unlock_kernel(); + mutex_unlock(&dsp56k_mutex); break; case DSP56K_SET_RX_WSIZE: if (arg > 4 || arg < 1) return -EINVAL; - lock_kernel(); + mutex_lock(&dsp56k_mutex); dsp56k.rx_wsize = (int) arg; - unlock_kernel(); + mutex_unlock(&dsp56k_mutex); break; case DSP56K_HOST_FLAGS: { @@ -363,7 +364,7 @@ static long dsp56k_ioctl(struct file *file, unsigned int cmd, if(get_user(out, &hf->out) < 0) return -EFAULT; - lock_kernel(); + mutex_lock(&dsp56k_mutex); if ((dir & 0x1) && (out & 0x1)) dsp56k_host_interface.icr |= DSP56K_ICR_HF0; else if (dir & 0x1) @@ -378,16 +379,16 @@ static long dsp56k_ioctl(struct file *file, unsigned int cmd, if (dsp56k_host_interface.icr & DSP56K_ICR_HF1) status |= 0x2; if (dsp56k_host_interface.isr & DSP56K_ISR_HF2) status |= 0x4; if (dsp56k_host_interface.isr & DSP56K_ISR_HF3) status |= 0x8; - unlock_kernel(); + mutex_unlock(&dsp56k_mutex); return put_user(status, &hf->status); } case DSP56K_HOST_CMD: if (arg > 31 || arg < 0) return -EINVAL; - lock_kernel(); + mutex_lock(&dsp56k_mutex); dsp56k_host_interface.cvr = (u_char)((arg & DSP56K_CVR_HV_MASK) | DSP56K_CVR_HC); - unlock_kernel(); + mutex_unlock(&dsp56k_mutex); break; default: return -EINVAL; @@ -427,7 +428,7 @@ static int dsp56k_open(struct inode *inode, struct file *file) int dev = iminor(inode) & 0x0f; int ret = 0; - lock_kernel(); + mutex_lock(&dsp56k_mutex); switch(dev) { case DSP56K_DEV_56001: @@ -454,7 +455,7 @@ static int dsp56k_open(struct inode *inode, struct file *file) ret = -ENODEV; } out: - unlock_kernel(); + mutex_unlock(&dsp56k_mutex); return ret; } @@ -482,6 +483,7 @@ static const struct file_operations dsp56k_fops = { .unlocked_ioctl = dsp56k_ioctl, .open = dsp56k_open, .release = dsp56k_release, + .llseek = noop_llseek, }; diff --git a/drivers/char/dtlk.c b/drivers/char/dtlk.c index e3859d4eaead..85156dd0caee 100644 --- a/drivers/char/dtlk.c +++ b/drivers/char/dtlk.c @@ -57,7 +57,7 @@ #include <linux/ioport.h> /* for request_region */ #include <linux/delay.h> /* for loops_per_jiffy */ #include <linux/sched.h> -#include <linux/smp_lock.h> /* cycle_kernel_lock() */ +#include <linux/mutex.h> #include <asm/io.h> /* for inb_p, outb_p, inb, outb, etc. */ #include <asm/uaccess.h> /* for get_user, etc. */ #include <linux/wait.h> /* for wait_queue */ @@ -73,6 +73,7 @@ #define TRACE_RET ((void) 0) #endif /* TRACING */ +static DEFINE_MUTEX(dtlk_mutex); static void dtlk_timer_tick(unsigned long data); static int dtlk_major; @@ -105,6 +106,7 @@ static const struct file_operations dtlk_fops = .unlocked_ioctl = dtlk_ioctl, .open = dtlk_open, .release = dtlk_release, + .llseek = no_llseek, }; /* local prototypes */ @@ -275,9 +277,9 @@ static long dtlk_ioctl(struct file *file, switch (cmd) { case DTLK_INTERROGATE: - lock_kernel(); + mutex_lock(&dtlk_mutex); sp = dtlk_interrogate(); - unlock_kernel(); + mutex_unlock(&dtlk_mutex); if (copy_to_user(argp, sp, sizeof(struct dtlk_settings))) return -EINVAL; return 0; @@ -296,7 +298,6 @@ static int dtlk_open(struct inode *inode, struct file *file) { TRACE_TEXT("(dtlk_open"); - cycle_kernel_lock(); nonseekable_open(inode, file); switch (iminor(inode)) { case DTLK_MINOR: diff --git a/drivers/char/generic_nvram.c b/drivers/char/generic_nvram.c index 82b5a88a82d7..0e941b57482e 100644 --- a/drivers/char/generic_nvram.c +++ b/drivers/char/generic_nvram.c @@ -19,7 +19,7 @@ #include <linux/miscdevice.h> #include <linux/fcntl.h> #include <linux/init.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <asm/uaccess.h> #include <asm/nvram.h> #ifdef CONFIG_PPC_PMAC @@ -28,6 +28,7 @@ #define NVRAM_SIZE 8192 +static DEFINE_MUTEX(nvram_mutex); static ssize_t nvram_len; static loff_t nvram_llseek(struct file *file, loff_t offset, int origin) @@ -120,9 +121,9 @@ static long nvram_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned l { int ret; - lock_kernel(); + mutex_lock(&nvram_mutex); ret = nvram_ioctl(file, cmd, arg); - unlock_kernel(); + mutex_unlock(&nvram_mutex); return ret; } diff --git a/drivers/char/genrtc.c b/drivers/char/genrtc.c index b6c2cc167c11..f773a9dd14f3 100644 --- a/drivers/char/genrtc.c +++ b/drivers/char/genrtc.c @@ -52,7 +52,7 @@ #include <linux/init.h> #include <linux/poll.h> #include <linux/proc_fs.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/workqueue.h> #include <asm/uaccess.h> @@ -66,6 +66,7 @@ * ioctls. */ +static DEFINE_MUTEX(gen_rtc_mutex); static DECLARE_WAIT_QUEUE_HEAD(gen_rtc_wait); /* @@ -337,9 +338,9 @@ static long gen_rtc_unlocked_ioctl(struct file *file, unsigned int cmd, { int ret; - lock_kernel(); + mutex_lock(&gen_rtc_mutex); ret = gen_rtc_ioctl(file, cmd, arg); - unlock_kernel(); + mutex_unlock(&gen_rtc_mutex); return ret; } @@ -352,16 +353,16 @@ static long gen_rtc_unlocked_ioctl(struct file *file, unsigned int cmd, static int gen_rtc_open(struct inode *inode, struct file *file) { - lock_kernel(); + mutex_lock(&gen_rtc_mutex); if (gen_rtc_status & RTC_IS_OPEN) { - unlock_kernel(); + mutex_unlock(&gen_rtc_mutex); return -EBUSY; } gen_rtc_status |= RTC_IS_OPEN; gen_rtc_irq_data = 0; irq_active = 0; - unlock_kernel(); + mutex_unlock(&gen_rtc_mutex); return 0; } @@ -497,6 +498,7 @@ static const struct file_operations gen_rtc_fops = { .unlocked_ioctl = gen_rtc_unlocked_ioctl, .open = gen_rtc_open, .release = gen_rtc_release, + .llseek = noop_llseek, }; static struct miscdevice rtc_gen_dev = diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index a0a1829d3198..a4eee324eb1e 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c @@ -30,6 +30,7 @@ #include <linux/bcd.h> #include <linux/seq_file.h> #include <linux/bitops.h> +#include <linux/compat.h> #include <linux/clocksource.h> #include <linux/slab.h> @@ -67,6 +68,7 @@ #define read_counter(MC) readl(MC) #endif +static DEFINE_MUTEX(hpet_mutex); /* replaces BKL */ static u32 hpet_nhpet, hpet_max_freq = HPET_USER_FREQ; /* This clocksource driver currently only works on ia64 */ @@ -250,7 +252,7 @@ static int hpet_open(struct inode *inode, struct file *file) if (file->f_mode & FMODE_WRITE) return -EINVAL; - lock_kernel(); + mutex_lock(&hpet_mutex); spin_lock_irq(&hpet_lock); for (devp = NULL, hpetp = hpets; hpetp && !devp; hpetp = hpetp->hp_next) @@ -264,7 +266,7 @@ static int hpet_open(struct inode *inode, struct file *file) if (!devp) { spin_unlock_irq(&hpet_lock); - unlock_kernel(); + mutex_unlock(&hpet_mutex); return -EBUSY; } @@ -272,7 +274,7 @@ static int hpet_open(struct inode *inode, struct file *file) devp->hd_irqdata = 0; devp->hd_flags |= HPET_OPEN; spin_unlock_irq(&hpet_lock); - unlock_kernel(); + mutex_unlock(&hpet_mutex); hpet_timer_set_irq(devp); @@ -429,22 +431,6 @@ static int hpet_release(struct inode *inode, struct file *file) return 0; } -static int hpet_ioctl_common(struct hpet_dev *, int, unsigned long, int); - -static long hpet_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - struct hpet_dev *devp; - int ret; - - devp = file->private_data; - lock_kernel(); - ret = hpet_ioctl_common(devp, cmd, arg, 0); - unlock_kernel(); - - return ret; -} - static int hpet_ioctl_ieon(struct hpet_dev *devp) { struct hpet_timer __iomem *timer; @@ -553,7 +539,8 @@ static inline unsigned long hpet_time_div(struct hpets *hpets, } static int -hpet_ioctl_common(struct hpet_dev *devp, int cmd, unsigned long arg, int kernel) +hpet_ioctl_common(struct hpet_dev *devp, int cmd, unsigned long arg, + struct hpet_info *info) { struct hpet_timer __iomem *timer; struct hpet __iomem *hpet; @@ -594,23 +581,15 @@ hpet_ioctl_common(struct hpet_dev *devp, int cmd, unsigned long arg, int kernel) break; case HPET_INFO: { - struct hpet_info info; - if (devp->hd_ireqfreq) - info.hi_ireqfreq = + info->hi_ireqfreq = hpet_time_div(hpetp, devp->hd_ireqfreq); else - info.hi_ireqfreq = 0; - info.hi_flags = + info->hi_ireqfreq = 0; + info->hi_flags = readq(&timer->hpet_config) & Tn_PER_INT_CAP_MASK; - info.hi_hpet = hpetp->hp_which; - info.hi_timer = devp - hpetp->hp_dev; - if (kernel) - memcpy((void *)arg, &info, sizeof(info)); - else - if (copy_to_user((void __user *)arg, &info, - sizeof(info))) - err = -EFAULT; + info->hi_hpet = hpetp->hp_which; + info->hi_timer = devp - hpetp->hp_dev; break; } case HPET_EPI: @@ -636,7 +615,7 @@ hpet_ioctl_common(struct hpet_dev *devp, int cmd, unsigned long arg, int kernel) devp->hd_flags &= ~HPET_PERIODIC; break; case HPET_IRQFREQ: - if (!kernel && (arg > hpet_max_freq) && + if ((arg > hpet_max_freq) && !capable(CAP_SYS_RESOURCE)) { err = -EACCES; break; @@ -653,12 +632,63 @@ hpet_ioctl_common(struct hpet_dev *devp, int cmd, unsigned long arg, int kernel) return err; } +static long +hpet_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct hpet_info info; + int err; + + mutex_lock(&hpet_mutex); + err = hpet_ioctl_common(file->private_data, cmd, arg, &info); + mutex_unlock(&hpet_mutex); + + if ((cmd == HPET_INFO) && !err && + (copy_to_user((void __user *)arg, &info, sizeof(info)))) + err = -EFAULT; + + return err; +} + +#ifdef CONFIG_COMPAT +struct compat_hpet_info { + compat_ulong_t hi_ireqfreq; /* Hz */ + compat_ulong_t hi_flags; /* information */ + unsigned short hi_hpet; + unsigned short hi_timer; +}; + +static long +hpet_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct hpet_info info; + int err; + + mutex_lock(&hpet_mutex); + err = hpet_ioctl_common(file->private_data, cmd, arg, &info); + mutex_unlock(&hpet_mutex); + + if ((cmd == HPET_INFO) && !err) { + struct compat_hpet_info __user *u = compat_ptr(arg); + if (put_user(info.hi_ireqfreq, &u->hi_ireqfreq) || + put_user(info.hi_flags, &u->hi_flags) || + put_user(info.hi_hpet, &u->hi_hpet) || + put_user(info.hi_timer, &u->hi_timer)) + err = -EFAULT; + } + + return err; +} +#endif + static const struct file_operations hpet_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .read = hpet_read, .poll = hpet_poll, .unlocked_ioctl = hpet_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = hpet_compat_ioctl, +#endif .open = hpet_open, .release = hpet_release, .fasync = hpet_fasync, diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c index 3d9c61e5acbf..788da05190cc 100644 --- a/drivers/char/hw_random/core.c +++ b/drivers/char/hw_random/core.c @@ -170,6 +170,7 @@ static const struct file_operations rng_chrdev_ops = { .owner = THIS_MODULE, .open = rng_dev_open, .read = rng_dev_read, + .llseek = noop_llseek, }; static struct miscdevice rng_miscdev = { diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c index 4cd8b227c11f..3bc0eef88717 100644 --- a/drivers/char/i8k.c +++ b/drivers/char/i8k.c @@ -23,7 +23,7 @@ #include <linux/seq_file.h> #include <linux/dmi.h> #include <linux/capability.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <asm/uaccess.h> #include <asm/io.h> @@ -56,6 +56,7 @@ #define I8K_TEMPERATURE_BUG 1 +static DEFINE_MUTEX(i8k_mutex); static char bios_version[4]; MODULE_AUTHOR("Massimo Dal Zotto (dz@debian.org)"); @@ -399,9 +400,9 @@ static long i8k_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) { long ret; - lock_kernel(); + mutex_lock(&i8k_mutex); ret = i8k_ioctl_unlocked(fp, cmd, arg); - unlock_kernel(); + mutex_unlock(&i8k_mutex); return ret; } diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c index d4b71e8d0d23..64a439ce2f89 100644 --- a/drivers/char/ip2/ip2main.c +++ b/drivers/char/ip2/ip2main.c @@ -98,7 +98,7 @@ #include <linux/major.h> #include <linux/wait.h> #include <linux/device.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/firmware.h> #include <linux/platform_device.h> @@ -138,6 +138,7 @@ #include <linux/proc_fs.h> #include <linux/seq_file.h> +static DEFINE_MUTEX(ip2_mutex); static const struct file_operations ip2mem_proc_fops; static const struct file_operations ip2_proc_fops; @@ -236,6 +237,7 @@ static const struct file_operations ip2_ipl = { .write = ip2_ipl_write, .unlocked_ioctl = ip2_ipl_ioctl, .open = ip2_ipl_open, + .llseek = noop_llseek, }; static unsigned long irq_counter; @@ -2897,7 +2899,7 @@ ip2_ipl_ioctl (struct file *pFile, UINT cmd, ULONG arg ) printk (KERN_DEBUG "IP2IPL: ioctl cmd %d, arg %ld\n", cmd, arg ); #endif - lock_kernel(); + mutex_lock(&ip2_mutex); switch ( iplminor ) { case 0: // IPL device @@ -2961,7 +2963,7 @@ ip2_ipl_ioctl (struct file *pFile, UINT cmd, ULONG arg ) rc = -ENODEV; break; } - unlock_kernel(); + mutex_unlock(&ip2_mutex); return rc; } @@ -2982,7 +2984,6 @@ ip2_ipl_open( struct inode *pInode, struct file *pFile ) #ifdef IP2DEBUG_IPL printk (KERN_DEBUG "IP2IPL: open\n" ); #endif - cycle_kernel_lock(); return 0; } diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c index d8ec92a38980..1fc8876af1f5 100644 --- a/drivers/char/ipmi/ipmi_devintf.c +++ b/drivers/char/ipmi/ipmi_devintf.c @@ -44,7 +44,6 @@ #include <linux/init.h> #include <linux/device.h> #include <linux/compat.h> -#include <linux/smp_lock.h> struct ipmi_file_private { @@ -59,6 +58,7 @@ struct ipmi_file_private unsigned int default_retry_time_ms; }; +static DEFINE_MUTEX(ipmi_mutex); static void file_receive_handler(struct ipmi_recv_msg *msg, void *handler_data) { @@ -102,9 +102,9 @@ static int ipmi_fasync(int fd, struct file *file, int on) struct ipmi_file_private *priv = file->private_data; int result; - lock_kernel(); /* could race against open() otherwise */ + mutex_lock(&ipmi_mutex); /* could race against open() otherwise */ result = fasync_helper(fd, file, on, &priv->fasync_queue); - unlock_kernel(); + mutex_unlock(&ipmi_mutex); return (result); } @@ -125,7 +125,7 @@ static int ipmi_open(struct inode *inode, struct file *file) if (!priv) return -ENOMEM; - lock_kernel(); + mutex_lock(&ipmi_mutex); priv->file = file; rv = ipmi_create_user(if_num, @@ -150,7 +150,7 @@ static int ipmi_open(struct inode *inode, struct file *file) priv->default_retry_time_ms = 0; out: - unlock_kernel(); + mutex_unlock(&ipmi_mutex); return rv; } @@ -639,9 +639,9 @@ static long ipmi_unlocked_ioctl(struct file *file, { int ret; - lock_kernel(); + mutex_lock(&ipmi_mutex); ret = ipmi_ioctl(file, cmd, data); - unlock_kernel(); + mutex_unlock(&ipmi_mutex); return ret; } @@ -850,6 +850,7 @@ static const struct file_operations ipmi_fops = { .release = ipmi_release, .fasync = ipmi_fasync, .poll = ipmi_poll, + .llseek = noop_llseek, }; #define DEVICE_NAME "ipmidev" diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c index 654d566ca57c..f4d334f2536e 100644 --- a/drivers/char/ipmi/ipmi_watchdog.c +++ b/drivers/char/ipmi/ipmi_watchdog.c @@ -35,7 +35,7 @@ #include <linux/moduleparam.h> #include <linux/ipmi.h> #include <linux/ipmi_smi.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/watchdog.h> #include <linux/miscdevice.h> #include <linux/init.h> @@ -149,6 +149,7 @@ #define WDIOC_GET_PRETIMEOUT _IOW(WATCHDOG_IOCTL_BASE, 22, int) #endif +static DEFINE_MUTEX(ipmi_watchdog_mutex); static int nowayout = WATCHDOG_NOWAYOUT; static ipmi_user_t watchdog_user; @@ -748,9 +749,9 @@ static long ipmi_unlocked_ioctl(struct file *file, { int ret; - lock_kernel(); + mutex_lock(&ipmi_watchdog_mutex); ret = ipmi_ioctl(file, cmd, arg); - unlock_kernel(); + mutex_unlock(&ipmi_watchdog_mutex); return ret; } @@ -844,7 +845,6 @@ static int ipmi_open(struct inode *ino, struct file *filep) if (test_and_set_bit(0, &ipmi_wdog_open)) return -EBUSY; - cycle_kernel_lock(); /* * Don't start the timer now, let it start on the @@ -909,6 +909,7 @@ static const struct file_operations ipmi_wdog_fops = { .open = ipmi_open, .release = ipmi_close, .fasync = ipmi_fasync, + .llseek = no_llseek, }; static struct miscdevice ipmi_wdog_miscdev = { diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c index be28391adb79..667abd23ad6a 100644 --- a/drivers/char/istallion.c +++ b/drivers/char/istallion.c @@ -704,6 +704,7 @@ static const struct file_operations stli_fsiomem = { .read = stli_memread, .write = stli_memwrite, .unlocked_ioctl = stli_memioctl, + .llseek = default_llseek, }; /*****************************************************************************/ diff --git a/drivers/char/lp.c b/drivers/char/lp.c index 938a3a273886..97c3edb95ae7 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -126,7 +126,7 @@ #include <linux/device.h> #include <linux/wait.h> #include <linux/jiffies.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/compat.h> #include <linux/parport.h> @@ -140,6 +140,7 @@ /* if you have more than 8 printers, remember to increase LP_NO */ #define LP_NO 8 +static DEFINE_MUTEX(lp_mutex); static struct lp_struct lp_table[LP_NO]; static unsigned int lp_count = 0; @@ -493,7 +494,7 @@ static int lp_open(struct inode * inode, struct file * file) unsigned int minor = iminor(inode); int ret = 0; - lock_kernel(); + mutex_lock(&lp_mutex); if (minor >= LP_NO) { ret = -ENXIO; goto out; @@ -554,7 +555,7 @@ static int lp_open(struct inode * inode, struct file * file) lp_release_parport (&lp_table[minor]); lp_table[minor].current_mode = IEEE1284_MODE_COMPAT; out: - unlock_kernel(); + mutex_unlock(&lp_mutex); return ret; } @@ -680,7 +681,7 @@ static long lp_ioctl(struct file *file, unsigned int cmd, int ret; minor = iminor(file->f_path.dentry->d_inode); - lock_kernel(); + mutex_lock(&lp_mutex); switch (cmd) { case LPSETTIMEOUT: if (copy_from_user(&par_timeout, (void __user *)arg, @@ -694,7 +695,7 @@ static long lp_ioctl(struct file *file, unsigned int cmd, ret = lp_do_ioctl(minor, cmd, arg, (void __user *)arg); break; } - unlock_kernel(); + mutex_unlock(&lp_mutex); return ret; } @@ -709,7 +710,7 @@ static long lp_compat_ioctl(struct file *file, unsigned int cmd, int ret; minor = iminor(file->f_path.dentry->d_inode); - lock_kernel(); + mutex_lock(&lp_mutex); switch (cmd) { case LPSETTIMEOUT: tc = compat_ptr(arg); @@ -730,7 +731,7 @@ static long lp_compat_ioctl(struct file *file, unsigned int cmd, ret = lp_do_ioctl(minor, cmd, arg, compat_ptr(arg)); break; } - unlock_kernel(); + mutex_unlock(&lp_mutex); return ret; } @@ -748,6 +749,7 @@ static const struct file_operations lp_fops = { #ifdef CONFIG_PARPORT_1284 .read = lp_read, #endif + .llseek = noop_llseek, }; /* --- support for console on the line printer ----------------- */ diff --git a/drivers/char/mbcs.c b/drivers/char/mbcs.c index 83bef4efe376..1aeaaba680d2 100644 --- a/drivers/char/mbcs.c +++ b/drivers/char/mbcs.c @@ -25,7 +25,6 @@ #include <linux/mm.h> #include <linux/uio.h> #include <linux/mutex.h> -#include <linux/smp_lock.h> #include <linux/slab.h> #include <asm/io.h> #include <asm/uaccess.h> @@ -42,6 +41,7 @@ #else #define DBG(fmt...) #endif +static DEFINE_MUTEX(mbcs_mutex); static int mbcs_major; static LIST_HEAD(soft_list); @@ -385,19 +385,19 @@ static int mbcs_open(struct inode *ip, struct file *fp) struct mbcs_soft *soft; int minor; - lock_kernel(); + mutex_lock(&mbcs_mutex); minor = iminor(ip); /* Nothing protects access to this list... */ list_for_each_entry(soft, &soft_list, list) { if (soft->nasid == minor) { fp->private_data = soft->cxdev; - unlock_kernel(); + mutex_unlock(&mbcs_mutex); return 0; } } - unlock_kernel(); + mutex_unlock(&mbcs_mutex); return -ENODEV; } diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 1f528fad3516..e985b1c2730e 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -805,6 +805,7 @@ static const struct file_operations full_fops = { static const struct file_operations oldmem_fops = { .read = read_oldmem, .open = open_oldmem, + .llseek = default_llseek, }; #endif @@ -831,6 +832,7 @@ static ssize_t kmsg_write(struct file *file, const char __user *buf, static const struct file_operations kmsg_fops = { .write = kmsg_write, + .llseek = noop_llseek, }; static const struct memdev { @@ -882,6 +884,7 @@ static int memory_open(struct inode *inode, struct file *filp) static const struct file_operations memory_fops = { .open = memory_open, + .llseek = noop_llseek, }; static char *mem_devnode(struct device *dev, mode_t *mode) diff --git a/drivers/char/misc.c b/drivers/char/misc.c index abdafd488980..778273c93242 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -162,6 +162,7 @@ static struct class *misc_class; static const struct file_operations misc_fops = { .owner = THIS_MODULE, .open = misc_open, + .llseek = noop_llseek, }; /** diff --git a/drivers/char/mmtimer.c b/drivers/char/mmtimer.c index ea7c99fa978f..c070b53984e4 100644 --- a/drivers/char/mmtimer.c +++ b/drivers/char/mmtimer.c @@ -32,7 +32,7 @@ #include <linux/interrupt.h> #include <linux/time.h> #include <linux/math64.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/slab.h> #include <asm/uaccess.h> @@ -59,6 +59,7 @@ extern unsigned long sn_rtc_cycles_per_second; #define rtc_time() (*RTC_COUNTER_ADDR) +static DEFINE_MUTEX(mmtimer_mutex); static long mmtimer_ioctl(struct file *file, unsigned int cmd, unsigned long arg); static int mmtimer_mmap(struct file *file, struct vm_area_struct *vma); @@ -72,6 +73,7 @@ static const struct file_operations mmtimer_fops = { .owner = THIS_MODULE, .mmap = mmtimer_mmap, .unlocked_ioctl = mmtimer_ioctl, + .llseek = noop_llseek, }; /* @@ -371,7 +373,7 @@ static long mmtimer_ioctl(struct file *file, unsigned int cmd, { int ret = 0; - lock_kernel(); + mutex_lock(&mmtimer_mutex); switch (cmd) { case MMTIMER_GETOFFSET: /* offset of the counter */ @@ -414,7 +416,7 @@ static long mmtimer_ioctl(struct file *file, unsigned int cmd, ret = -ENOTTY; break; } - unlock_kernel(); + mutex_unlock(&mmtimer_mutex); return ret; } diff --git a/drivers/char/mspec.c b/drivers/char/mspec.c index ecb89d798e35..966a95bc974b 100644 --- a/drivers/char/mspec.c +++ b/drivers/char/mspec.c @@ -316,7 +316,8 @@ uncached_mmap(struct file *file, struct vm_area_struct *vma) static const struct file_operations fetchop_fops = { .owner = THIS_MODULE, - .mmap = fetchop_mmap + .mmap = fetchop_mmap, + .llseek = noop_llseek, }; static struct miscdevice fetchop_miscdev = { @@ -327,7 +328,8 @@ static struct miscdevice fetchop_miscdev = { static const struct file_operations cached_fops = { .owner = THIS_MODULE, - .mmap = cached_mmap + .mmap = cached_mmap, + .llseek = noop_llseek, }; static struct miscdevice cached_miscdev = { @@ -338,7 +340,8 @@ static struct miscdevice cached_miscdev = { static const struct file_operations uncached_fops = { .owner = THIS_MODULE, - .mmap = uncached_mmap + .mmap = uncached_mmap, + .llseek = noop_llseek, }; static struct miscdevice uncached_miscdev = { diff --git a/drivers/char/mwave/mwavedd.c b/drivers/char/mwave/mwavedd.c index a4ec50c95072..1d82d5838f0c 100644 --- a/drivers/char/mwave/mwavedd.c +++ b/drivers/char/mwave/mwavedd.c @@ -56,7 +56,7 @@ #include <linux/serial.h> #include <linux/sched.h> #include <linux/spinlock.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/delay.h> #include <linux/serial_8250.h> #include "smapi.h" @@ -73,6 +73,7 @@ MODULE_LICENSE("GPL"); * checks are made against other devices (ie. superio) for conflicts. * We'll depend on users using the tpctl utility to do that for now */ +static DEFINE_MUTEX(mwave_mutex); int mwave_debug = 0; int mwave_3780i_irq = 0; int mwave_3780i_io = 0; @@ -101,7 +102,6 @@ static int mwave_open(struct inode *inode, struct file *file) PRINTK_2(TRACE_MWAVE, "mwavedd::mwave_open, exit return retval %x\n", retval); - cycle_kernel_lock(); return retval; } @@ -136,9 +136,9 @@ static long mwave_ioctl(struct file *file, unsigned int iocmd, PRINTK_1(TRACE_MWAVE, "mwavedd::mwave_ioctl, IOCTL_MW_RESET" " calling tp3780I_ResetDSP\n"); - lock_kernel(); + mutex_lock(&mwave_mutex); retval = tp3780I_ResetDSP(&pDrvData->rBDData); - unlock_kernel(); + mutex_unlock(&mwave_mutex); PRINTK_2(TRACE_MWAVE, "mwavedd::mwave_ioctl, IOCTL_MW_RESET" " retval %x from tp3780I_ResetDSP\n", @@ -149,9 +149,9 @@ static long mwave_ioctl(struct file *file, unsigned int iocmd, PRINTK_1(TRACE_MWAVE, "mwavedd::mwave_ioctl, IOCTL_MW_RUN" " calling tp3780I_StartDSP\n"); - lock_kernel(); + mutex_lock(&mwave_mutex); retval = tp3780I_StartDSP(&pDrvData->rBDData); - unlock_kernel(); + mutex_unlock(&mwave_mutex); PRINTK_2(TRACE_MWAVE, "mwavedd::mwave_ioctl, IOCTL_MW_RUN" " retval %x from tp3780I_StartDSP\n", @@ -165,10 +165,10 @@ static long mwave_ioctl(struct file *file, unsigned int iocmd, "mwavedd::mwave_ioctl," " IOCTL_MW_DSP_ABILITIES calling" " tp3780I_QueryAbilities\n"); - lock_kernel(); + mutex_lock(&mwave_mutex); retval = tp3780I_QueryAbilities(&pDrvData->rBDData, &rAbilities); - unlock_kernel(); + mutex_unlock(&mwave_mutex); PRINTK_2(TRACE_MWAVE, "mwavedd::mwave_ioctl, IOCTL_MW_DSP_ABILITIES" " retval %x from tp3780I_QueryAbilities\n", @@ -199,13 +199,13 @@ static long mwave_ioctl(struct file *file, unsigned int iocmd, "mwavedd::mwave_ioctl IOCTL_MW_READ_DATA," " size %lx, ioarg %lx pusBuffer %p\n", rReadData.ulDataLength, ioarg, pusBuffer); - lock_kernel(); + mutex_lock(&mwave_mutex); retval = tp3780I_ReadWriteDspDStore(&pDrvData->rBDData, iocmd, pusBuffer, rReadData.ulDataLength, rReadData.usDspAddress); - unlock_kernel(); + mutex_unlock(&mwave_mutex); } break; @@ -223,12 +223,12 @@ static long mwave_ioctl(struct file *file, unsigned int iocmd, " size %lx, ioarg %lx pusBuffer %p\n", rReadData.ulDataLength / 2, ioarg, pusBuffer); - lock_kernel(); + mutex_lock(&mwave_mutex); retval = tp3780I_ReadWriteDspDStore(&pDrvData->rBDData, iocmd, pusBuffer, rReadData.ulDataLength / 2, rReadData.usDspAddress); - unlock_kernel(); + mutex_unlock(&mwave_mutex); } break; @@ -246,12 +246,12 @@ static long mwave_ioctl(struct file *file, unsigned int iocmd, " size %lx, ioarg %lx pusBuffer %p\n", rWriteData.ulDataLength, ioarg, pusBuffer); - lock_kernel(); + mutex_lock(&mwave_mutex); retval = tp3780I_ReadWriteDspDStore(&pDrvData->rBDData, iocmd, pusBuffer, rWriteData.ulDataLength, rWriteData.usDspAddress); - unlock_kernel(); + mutex_unlock(&mwave_mutex); } break; @@ -269,12 +269,12 @@ static long mwave_ioctl(struct file *file, unsigned int iocmd, " size %lx, ioarg %lx pusBuffer %p\n", rWriteData.ulDataLength, ioarg, pusBuffer); - lock_kernel(); + mutex_lock(&mwave_mutex); retval = tp3780I_ReadWriteDspIStore(&pDrvData->rBDData, iocmd, pusBuffer, rWriteData.ulDataLength, rWriteData.usDspAddress); - unlock_kernel(); + mutex_unlock(&mwave_mutex); } break; @@ -295,10 +295,10 @@ static long mwave_ioctl(struct file *file, unsigned int iocmd, ipcnum, pDrvData->IPCs[ipcnum].usIntCount); - lock_kernel(); + mutex_lock(&mwave_mutex); pDrvData->IPCs[ipcnum].bIsHere = FALSE; pDrvData->IPCs[ipcnum].bIsEnabled = TRUE; - unlock_kernel(); + mutex_unlock(&mwave_mutex); PRINTK_2(TRACE_MWAVE, "mwavedd::mwave_ioctl IOCTL_MW_REGISTER_IPC" @@ -323,7 +323,7 @@ static long mwave_ioctl(struct file *file, unsigned int iocmd, ipcnum, pDrvData->IPCs[ipcnum].usIntCount); - lock_kernel(); + mutex_lock(&mwave_mutex); if (pDrvData->IPCs[ipcnum].bIsEnabled == TRUE) { DECLARE_WAITQUEUE(wait, current); @@ -364,7 +364,7 @@ static long mwave_ioctl(struct file *file, unsigned int iocmd, " processing\n", ipcnum); } - unlock_kernel(); + mutex_unlock(&mwave_mutex); } break; @@ -383,14 +383,14 @@ static long mwave_ioctl(struct file *file, unsigned int iocmd, ipcnum); return -EINVAL; } - lock_kernel(); + mutex_lock(&mwave_mutex); if (pDrvData->IPCs[ipcnum].bIsEnabled == TRUE) { pDrvData->IPCs[ipcnum].bIsEnabled = FALSE; if (pDrvData->IPCs[ipcnum].bIsHere == TRUE) { wake_up_interruptible(&pDrvData->IPCs[ipcnum].ipc_wait_queue); } } - unlock_kernel(); + mutex_unlock(&mwave_mutex); } break; @@ -479,7 +479,8 @@ static const struct file_operations mwave_fops = { .write = mwave_write, .unlocked_ioctl = mwave_ioctl, .open = mwave_open, - .release = mwave_close + .release = mwave_close, + .llseek = default_llseek, }; diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c index 66d2917b003f..166f1e7aaa7e 100644 --- a/drivers/char/nvram.c +++ b/drivers/char/nvram.c @@ -109,10 +109,11 @@ #include <linux/spinlock.h> #include <linux/io.h> #include <linux/uaccess.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <asm/system.h> +static DEFINE_MUTEX(nvram_mutex); static DEFINE_SPINLOCK(nvram_state_lock); static int nvram_open_cnt; /* #times opened */ static int nvram_open_mode; /* special open modes */ @@ -308,7 +309,7 @@ static long nvram_ioctl(struct file *file, unsigned int cmd, if (!capable(CAP_SYS_ADMIN)) return -EACCES; - lock_kernel(); + mutex_lock(&nvram_mutex); spin_lock_irq(&rtc_lock); for (i = 0; i < NVRAM_BYTES; ++i) @@ -316,7 +317,7 @@ static long nvram_ioctl(struct file *file, unsigned int cmd, __nvram_set_checksum(); spin_unlock_irq(&rtc_lock); - unlock_kernel(); + mutex_unlock(&nvram_mutex); return 0; case NVRAM_SETCKS: @@ -325,11 +326,11 @@ static long nvram_ioctl(struct file *file, unsigned int cmd, if (!capable(CAP_SYS_ADMIN)) return -EACCES; - lock_kernel(); + mutex_lock(&nvram_mutex); spin_lock_irq(&rtc_lock); __nvram_set_checksum(); spin_unlock_irq(&rtc_lock); - unlock_kernel(); + mutex_unlock(&nvram_mutex); return 0; default: diff --git a/drivers/char/nwbutton.c b/drivers/char/nwbutton.c index 2604246501e4..8994ce32e6c7 100644 --- a/drivers/char/nwbutton.c +++ b/drivers/char/nwbutton.c @@ -182,6 +182,7 @@ static int button_read (struct file *filp, char __user *buffer, static const struct file_operations button_fops = { .owner = THIS_MODULE, .read = button_read, + .llseek = noop_llseek, }; /* diff --git a/drivers/char/nwflash.c b/drivers/char/nwflash.c index 043a1c7b86be..a12f52400dbc 100644 --- a/drivers/char/nwflash.c +++ b/drivers/char/nwflash.c @@ -25,7 +25,6 @@ #include <linux/spinlock.h> #include <linux/rwsem.h> #include <linux/init.h> -#include <linux/smp_lock.h> #include <linux/mutex.h> #include <linux/jiffies.h> @@ -41,6 +40,7 @@ #define NWFLASH_VERSION "6.4" +static DEFINE_MUTEX(flash_mutex); static void kick_open(void); static int get_flash_id(void); static int erase_block(int nBlock); @@ -96,7 +96,7 @@ static int get_flash_id(void) static long flash_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) { - lock_kernel(); + mutex_lock(&flash_mutex); switch (cmd) { case CMD_WRITE_DISABLE: gbWriteBase64Enable = 0; @@ -114,10 +114,10 @@ static long flash_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) default: gbWriteBase64Enable = 0; gbWriteEnable = 0; - unlock_kernel(); + mutex_unlock(&flash_mutex); return -EINVAL; } - unlock_kernel(); + mutex_unlock(&flash_mutex); return 0; } @@ -282,7 +282,7 @@ static loff_t flash_llseek(struct file *file, loff_t offset, int orig) { loff_t ret; - lock_kernel(); + mutex_lock(&flash_mutex); if (flashdebug) printk(KERN_DEBUG "flash_llseek: offset=0x%X, orig=0x%X.\n", (unsigned int) offset, orig); @@ -317,7 +317,7 @@ static loff_t flash_llseek(struct file *file, loff_t offset, int orig) default: ret = -EINVAL; } - unlock_kernel(); + mutex_unlock(&flash_mutex); return ret; } diff --git a/drivers/char/pc8736x_gpio.c b/drivers/char/pc8736x_gpio.c index 8ecbcc174c15..b304ec052501 100644 --- a/drivers/char/pc8736x_gpio.c +++ b/drivers/char/pc8736x_gpio.c @@ -234,6 +234,7 @@ static const struct file_operations pc8736x_gpio_fileops = { .open = pc8736x_gpio_open, .write = nsc_gpio_write, .read = nsc_gpio_read, + .llseek = no_llseek, }; static void __init pc8736x_init_shadow(void) diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c index ec73d9f6d9ed..6835c23e9a51 100644 --- a/drivers/char/pcmcia/cm4000_cs.c +++ b/drivers/char/pcmcia/cm4000_cs.c @@ -30,11 +30,10 @@ #include <linux/fs.h> #include <linux/delay.h> #include <linux/bitrev.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/uaccess.h> #include <linux/io.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/cisreg.h> #include <pcmcia/ciscode.h> @@ -55,7 +54,7 @@ __func__ , ## args); \ } while (0) -static char *version = "cm4000_cs.c v2.4.0gm6 - All bugs added by Harald Welte"; +static DEFINE_MUTEX(cmm_mutex); #define T_1SEC (HZ) #define T_10MSEC msecs_to_jiffies(10) @@ -1418,7 +1417,7 @@ static long cmm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) iminor(inode), ioctl_names[_IOC_NR(cmd)]); #endif - lock_kernel(); + mutex_lock(&cmm_mutex); rc = -ENODEV; link = dev_table[iminor(inode)]; if (!pcmcia_dev_present(link)) { @@ -1626,7 +1625,7 @@ static long cmm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) rc = -ENOTTY; } out: - unlock_kernel(); + mutex_unlock(&cmm_mutex); return rc; } @@ -1640,7 +1639,7 @@ static int cmm_open(struct inode *inode, struct file *filp) if (minor >= CM4000_MAX_DEV) return -ENODEV; - lock_kernel(); + mutex_lock(&cmm_mutex); link = dev_table[minor]; if (link == NULL || !pcmcia_dev_present(link)) { ret = -ENODEV; @@ -1685,7 +1684,7 @@ static int cmm_open(struct inode *inode, struct file *filp) DEBUGP(2, dev, "<- cmm_open\n"); ret = nonseekable_open(inode, filp); out: - unlock_kernel(); + mutex_unlock(&cmm_mutex); return ret; } @@ -1742,20 +1741,8 @@ static void cmm_cm4000_release(struct pcmcia_device * link) /*==== Interface to PCMCIA Layer =======================================*/ -static int cm4000_config_check(struct pcmcia_device *p_dev, - cistpl_cftable_entry_t *cfg, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, - void *priv_data) +static int cm4000_config_check(struct pcmcia_device *p_dev, void *priv_data) { - if (!cfg->io.nwin) - return -ENODEV; - - p_dev->resource[0]->start = cfg->io.win[0].base; - p_dev->resource[0]->end = cfg->io.win[0].len; - p_dev->resource[0]->flags |= pcmcia_io_cfg_data_width(cfg->io.flags); - p_dev->io_lines = cfg->io.flags & CISTPL_IO_LINES_MASK; - return pcmcia_request_io(p_dev); } @@ -1763,13 +1750,13 @@ static int cm4000_config(struct pcmcia_device * link, int devno) { struct cm4000_dev *dev; + link->config_flags |= CONF_AUTO_SET_IO; + /* read the config-tuples */ if (pcmcia_loop_config(link, cm4000_config_check, NULL)) goto cs_release; - link->conf.IntType = 00000002; - - if (pcmcia_request_configuration(link, &link->conf)) + if (pcmcia_enable_device(link)) goto cs_release; dev = link->priv; @@ -1829,7 +1816,6 @@ static int cm4000_probe(struct pcmcia_device *link) dev->p_dev = link; link->priv = dev; - link->conf.IntType = INT_MEMORY_AND_IO; dev_table[i] = link; init_waitqueue_head(&dev->devq); @@ -1880,6 +1866,7 @@ static const struct file_operations cm4000_fops = { .unlocked_ioctl = cmm_ioctl, .open = cmm_open, .release= cmm_close, + .llseek = no_llseek, }; static struct pcmcia_device_id cm4000_ids[] = { @@ -1891,9 +1878,7 @@ MODULE_DEVICE_TABLE(pcmcia, cm4000_ids); static struct pcmcia_driver cm4000_driver = { .owner = THIS_MODULE, - .drv = { - .name = "cm4000_cs", - }, + .name = "cm4000_cs", .probe = cm4000_probe, .remove = cm4000_detach, .suspend = cm4000_suspend, @@ -1905,8 +1890,6 @@ static int __init cmm_init(void) { int rc; - printk(KERN_INFO "%s\n", version); - cmm_class = class_create(THIS_MODULE, "cardman_4000"); if (IS_ERR(cmm_class)) return PTR_ERR(cmm_class); @@ -1931,7 +1914,6 @@ static int __init cmm_init(void) static void __exit cmm_exit(void) { - printk(KERN_INFO MODULE_NAME ": unloading\n"); pcmcia_unregister_driver(&cm4000_driver); unregister_chrdev(major, DEVICE_NAME); class_destroy(cmm_class); diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c index 815cde1d0570..5d8d59e865f4 100644 --- a/drivers/char/pcmcia/cm4040_cs.c +++ b/drivers/char/pcmcia/cm4040_cs.c @@ -24,12 +24,11 @@ #include <linux/fs.h> #include <linux/delay.h> #include <linux/poll.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/wait.h> #include <asm/uaccess.h> #include <asm/io.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/cisreg.h> #include <pcmcia/ciscode.h> @@ -49,8 +48,7 @@ __func__ , ## args); \ } while (0) -static char *version = -"OMNIKEY CardMan 4040 v1.1.0gm5 - All bugs added by Harald Welte"; +static DEFINE_MUTEX(cm4040_mutex); #define CCID_DRIVER_BULK_DEFAULT_TIMEOUT (150*HZ) #define CCID_DRIVER_ASYNC_POWERUP_TIMEOUT (35*HZ) @@ -444,7 +442,7 @@ static int cm4040_open(struct inode *inode, struct file *filp) if (minor >= CM_MAX_DEV) return -ENODEV; - lock_kernel(); + mutex_lock(&cm4040_mutex); link = dev_table[minor]; if (link == NULL || !pcmcia_dev_present(link)) { ret = -ENODEV; @@ -473,7 +471,7 @@ static int cm4040_open(struct inode *inode, struct file *filp) DEBUGP(2, dev, "<- cm4040_open (successfully)\n"); ret = nonseekable_open(inode, filp); out: - unlock_kernel(); + mutex_unlock(&cm4040_mutex); return ret; } @@ -516,26 +514,9 @@ static void cm4040_reader_release(struct pcmcia_device *link) return; } -static int cm4040_config_check(struct pcmcia_device *p_dev, - cistpl_cftable_entry_t *cfg, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, - void *priv_data) +static int cm4040_config_check(struct pcmcia_device *p_dev, void *priv_data) { - int rc; - if (!cfg->io.nwin) - return -ENODEV; - - /* Get the IOaddr */ - p_dev->resource[0]->start = cfg->io.win[0].base; - p_dev->resource[0]->end = cfg->io.win[0].len; - p_dev->resource[0]->flags |= pcmcia_io_cfg_data_width(cfg->io.flags); - p_dev->io_lines = cfg->io.flags & CISTPL_IO_LINES_MASK; - rc = pcmcia_request_io(p_dev); - - dev_printk(KERN_INFO, &p_dev->dev, - "pcmcia_request_io returned 0x%x\n", rc); - return rc; + return pcmcia_request_io(p_dev); } @@ -544,15 +525,15 @@ static int reader_config(struct pcmcia_device *link, int devno) struct reader_dev *dev; int fail_rc; + link->config_flags |= CONF_AUTO_SET_IO; + if (pcmcia_loop_config(link, cm4040_config_check, NULL)) goto cs_release; - link->conf.IntType = 00000002; - - fail_rc = pcmcia_request_configuration(link, &link->conf); + fail_rc = pcmcia_enable_device(link); if (fail_rc != 0) { dev_printk(KERN_INFO, &link->dev, - "pcmcia_request_configuration failed 0x%x\n", + "pcmcia_enable_device failed 0x%x\n", fail_rc); goto cs_release; } @@ -599,7 +580,6 @@ static int reader_probe(struct pcmcia_device *link) link->priv = dev; dev->p_dev = link; - link->conf.IntType = INT_MEMORY_AND_IO; dev_table[i] = link; init_waitqueue_head(&dev->devq); @@ -650,6 +630,7 @@ static const struct file_operations reader_fops = { .open = cm4040_open, .release = cm4040_close, .poll = cm4040_poll, + .llseek = no_llseek, }; static struct pcmcia_device_id cm4040_ids[] = { @@ -662,9 +643,7 @@ MODULE_DEVICE_TABLE(pcmcia, cm4040_ids); static struct pcmcia_driver reader_driver = { .owner = THIS_MODULE, - .drv = { - .name = "cm4040_cs", - }, + .name = "cm4040_cs", .probe = reader_probe, .remove = reader_detach, .id_table = cm4040_ids, @@ -674,7 +653,6 @@ static int __init cm4040_init(void) { int rc; - printk(KERN_INFO "%s\n", version); cmx_class = class_create(THIS_MODULE, "cardman_4040"); if (IS_ERR(cmx_class)) return PTR_ERR(cmx_class); @@ -699,7 +677,6 @@ static int __init cm4040_init(void) static void __exit cm4040_exit(void) { - printk(KERN_INFO MODULE_NAME ": unloading\n"); pcmcia_unregister_driver(&reader_driver); unregister_chrdev(major, DEVICE_NAME); class_destroy(cmx_class); diff --git a/drivers/char/pcmcia/ipwireless/main.c b/drivers/char/pcmcia/ipwireless/main.c index 67bdb05798b1..94b8eb4d691d 100644 --- a/drivers/char/pcmcia/ipwireless/main.c +++ b/drivers/char/pcmcia/ipwireless/main.c @@ -32,7 +32,6 @@ #include <pcmcia/device_id.h> #include <pcmcia/ss.h> #include <pcmcia/ds.h> -#include <pcmcia/cs.h> static struct pcmcia_device_id ipw_ids[] = { PCMCIA_DEVICE_MANF_CARD(0x02f2, 0x0100), @@ -76,23 +75,18 @@ static void signalled_reboot_callback(void *callback_data) schedule_work(&ipw->work_reboot); } -static int ipwireless_probe(struct pcmcia_device *p_dev, - cistpl_cftable_entry_t *cfg, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, - void *priv_data) +static int ipwireless_probe(struct pcmcia_device *p_dev, void *priv_data) { struct ipw_dev *ipw = priv_data; struct resource *io_resource; int ret; + p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; - p_dev->resource[0]->start = cfg->io.win[0].base; - p_dev->resource[0]->end = cfg->io.win[0].len; /* 0x40 causes it to generate level mode interrupts. */ /* 0x04 enables IREQ pin. */ - p_dev->conf.ConfigIndex = cfg->index | 0x44; + p_dev->config_index |= 0x44; p_dev->io_lines = 16; ret = pcmcia_request_io(p_dev); if (ret) @@ -102,65 +96,49 @@ static int ipwireless_probe(struct pcmcia_device *p_dev, resource_size(p_dev->resource[0]), IPWIRELESS_PCCARD_NAME); - if (cfg->mem.nwin == 0) - return 0; - - ipw->request_common_memory.Attributes = + p_dev->resource[2]->flags |= WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_CM | WIN_ENABLE; - ipw->request_common_memory.Base = cfg->mem.win[0].host_addr; - ipw->request_common_memory.Size = cfg->mem.win[0].len; - if (ipw->request_common_memory.Size < 0x1000) - ipw->request_common_memory.Size = 0x1000; - ipw->request_common_memory.AccessSpeed = 0; - - ret = pcmcia_request_window(p_dev, &ipw->request_common_memory, - &ipw->handle_common_memory); + ret = pcmcia_request_window(p_dev, p_dev->resource[2], 0); if (ret != 0) goto exit1; - ret = pcmcia_map_mem_page(p_dev, ipw->handle_common_memory, - cfg->mem.win[0].card_addr); - + ret = pcmcia_map_mem_page(p_dev, p_dev->resource[2], p_dev->card_addr); if (ret != 0) goto exit2; - ipw->is_v2_card = cfg->mem.win[0].len == 0x100; + ipw->is_v2_card = resource_size(p_dev->resource[2]) == 0x100; - ipw->common_memory = ioremap(ipw->request_common_memory.Base, - ipw->request_common_memory.Size); - request_mem_region(ipw->request_common_memory.Base, - ipw->request_common_memory.Size, + ipw->attr_memory = ioremap(p_dev->resource[2]->start, + resource_size(p_dev->resource[2])); + request_mem_region(p_dev->resource[2]->start, + resource_size(p_dev->resource[2]), IPWIRELESS_PCCARD_NAME); - ipw->request_attr_memory.Attributes = - WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_AM | WIN_ENABLE; - ipw->request_attr_memory.Base = 0; - ipw->request_attr_memory.Size = 0; /* this used to be 0x1000 */ - ipw->request_attr_memory.AccessSpeed = 0; - - ret = pcmcia_request_window(p_dev, &ipw->request_attr_memory, - &ipw->handle_attr_memory); - + p_dev->resource[3]->flags |= WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_AM | + WIN_ENABLE; + p_dev->resource[3]->end = 0; /* this used to be 0x1000 */ + ret = pcmcia_request_window(p_dev, p_dev->resource[3], 0); if (ret != 0) goto exit2; - ret = pcmcia_map_mem_page(p_dev, ipw->handle_attr_memory, 0); + ret = pcmcia_map_mem_page(p_dev, p_dev->resource[3], 0); if (ret != 0) goto exit3; - ipw->attr_memory = ioremap(ipw->request_attr_memory.Base, - ipw->request_attr_memory.Size); - request_mem_region(ipw->request_attr_memory.Base, - ipw->request_attr_memory.Size, IPWIRELESS_PCCARD_NAME); + ipw->attr_memory = ioremap(p_dev->resource[3]->start, + resource_size(p_dev->resource[3])); + request_mem_region(p_dev->resource[3]->start, + resource_size(p_dev->resource[3]), + IPWIRELESS_PCCARD_NAME); return 0; exit3: exit2: if (ipw->common_memory) { - release_mem_region(ipw->request_common_memory.Base, - ipw->request_common_memory.Size); + release_mem_region(p_dev->resource[2]->start, + resource_size(p_dev->resource[2])); iounmap(ipw->common_memory); } exit1: @@ -175,14 +153,13 @@ static int config_ipwireless(struct ipw_dev *ipw) int ret = 0; ipw->is_v2_card = 0; + link->config_flags |= CONF_AUTO_SET_IO | CONF_AUTO_SET_IOMEM | + CONF_ENABLE_IRQ; ret = pcmcia_loop_config(link, ipwireless_probe, ipw); if (ret != 0) return ret; - link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.IntType = INT_MEMORY_AND_IO; - INIT_WORK(&ipw->work_reboot, signalled_reboot_work); ipwireless_init_hardware_v1(ipw->hardware, link->resource[0]->start, @@ -201,13 +178,9 @@ static int config_ipwireless(struct ipw_dev *ipw) (unsigned int) link->irq); if (ipw->attr_memory && ipw->common_memory) printk(KERN_INFO IPWIRELESS_PCCARD_NAME - ": attr memory 0x%08lx-0x%08lx, common memory 0x%08lx-0x%08lx\n", - ipw->request_attr_memory.Base, - ipw->request_attr_memory.Base - + ipw->request_attr_memory.Size - 1, - ipw->request_common_memory.Base, - ipw->request_common_memory.Base - + ipw->request_common_memory.Size - 1); + ": attr memory %pR, common memory %pR\n", + link->resource[3], + link->resource[2]); ipw->network = ipwireless_network_create(ipw->hardware); if (!ipw->network) @@ -223,25 +196,23 @@ static int config_ipwireless(struct ipw_dev *ipw) * Do the RequestConfiguration last, because it enables interrupts. * Then we don't get any interrupts before we're ready for them. */ - ret = pcmcia_request_configuration(link, &link->conf); - + ret = pcmcia_enable_device(link); if (ret != 0) goto exit; return 0; exit: - if (ipw->attr_memory) { - release_mem_region(ipw->request_attr_memory.Base, - ipw->request_attr_memory.Size); - iounmap(ipw->attr_memory); - - } if (ipw->common_memory) { - release_mem_region(ipw->request_common_memory.Base, - ipw->request_common_memory.Size); + release_mem_region(link->resource[2]->start, + resource_size(link->resource[2])); iounmap(ipw->common_memory); } + if (ipw->attr_memory) { + release_mem_region(link->resource[3]->start, + resource_size(link->resource[3])); + iounmap(ipw->attr_memory); + } pcmcia_disable_device(link); return -1; } @@ -249,13 +220,13 @@ exit: static void release_ipwireless(struct ipw_dev *ipw) { if (ipw->common_memory) { - release_mem_region(ipw->request_common_memory.Base, - ipw->request_common_memory.Size); + release_mem_region(ipw->link->resource[2]->start, + resource_size(ipw->link->resource[2])); iounmap(ipw->common_memory); } if (ipw->attr_memory) { - release_mem_region(ipw->request_attr_memory.Base, - ipw->request_attr_memory.Size); + release_mem_region(ipw->link->resource[3]->start, + resource_size(ipw->link->resource[3])); iounmap(ipw->attr_memory); } pcmcia_disable_device(ipw->link); @@ -324,7 +295,7 @@ static struct pcmcia_driver me = { .owner = THIS_MODULE, .probe = ipwireless_attach, .remove = ipwireless_detach, - .drv = { .name = IPWIRELESS_PCCARD_NAME }, + .name = IPWIRELESS_PCCARD_NAME, .id_table = ipw_ids }; @@ -336,9 +307,6 @@ static int __init init_ipwireless(void) { int ret; - printk(KERN_INFO IPWIRELESS_PCCARD_NAME " " - IPWIRELESS_PCMCIA_VERSION " by " IPWIRELESS_PCMCIA_AUTHOR "\n"); - ret = ipwireless_tty_init(); if (ret != 0) return ret; @@ -355,9 +323,6 @@ static int __init init_ipwireless(void) */ static void __exit exit_ipwireless(void) { - printk(KERN_INFO IPWIRELESS_PCCARD_NAME " " - IPWIRELESS_PCMCIA_VERSION " removed\n"); - pcmcia_unregister_driver(&me); ipwireless_tty_release(); } diff --git a/drivers/char/pcmcia/ipwireless/main.h b/drivers/char/pcmcia/ipwireless/main.h index c207be87b597..f2cbb116bccb 100644 --- a/drivers/char/pcmcia/ipwireless/main.h +++ b/drivers/char/pcmcia/ipwireless/main.h @@ -21,7 +21,6 @@ #include <linux/sched.h> #include <linux/types.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/ds.h> @@ -45,13 +44,9 @@ struct ipw_dev { struct pcmcia_device *link; int is_v2_card; - window_handle_t handle_attr_memory; void __iomem *attr_memory; - win_req_t request_attr_memory; - window_handle_t handle_common_memory; void __iomem *common_memory; - win_req_t request_common_memory; /* Reference to attribute memory, containing CIS data */ void *attribute_memory; diff --git a/drivers/char/pcmcia/ipwireless/tty.h b/drivers/char/pcmcia/ipwireless/tty.h index 3e163d4cab15..747b2d637860 100644 --- a/drivers/char/pcmcia/ipwireless/tty.h +++ b/drivers/char/pcmcia/ipwireless/tty.h @@ -21,7 +21,6 @@ #include <linux/types.h> #include <linux/sched.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/ds.h> diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 9ecd6bef5d3b..be1810057607 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -70,7 +70,6 @@ #include <linux/workqueue.h> #include <linux/hdlc.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/cisreg.h> #include <pcmcia/ds.h> @@ -550,9 +549,6 @@ static int mgslpc_probe(struct pcmcia_device *link) /* Initialize the struct pcmcia_device structure */ - link->conf.Attributes = 0; - link->conf.IntType = INT_MEMORY_AND_IO; - ret = mgslpc_config(link); if (ret) return ret; @@ -565,20 +561,8 @@ static int mgslpc_probe(struct pcmcia_device *link) /* Card has been inserted. */ -static int mgslpc_ioprobe(struct pcmcia_device *p_dev, - cistpl_cftable_entry_t *cfg, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, - void *priv_data) +static int mgslpc_ioprobe(struct pcmcia_device *p_dev, void *priv_data) { - if (!cfg->io.nwin) - return -ENODEV; - - p_dev->resource[0]->start = cfg->io.win[0].base; - p_dev->resource[0]->end = cfg->io.win[0].len; - p_dev->resource[0]->flags |= pcmcia_io_cfg_data_width(cfg->io.flags); - p_dev->io_lines = cfg->io.flags & CISTPL_IO_LINES_MASK; - return pcmcia_request_io(p_dev); } @@ -590,32 +574,24 @@ static int mgslpc_config(struct pcmcia_device *link) if (debug_level >= DEBUG_LEVEL_INFO) printk("mgslpc_config(0x%p)\n", link); + link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; + ret = pcmcia_loop_config(link, mgslpc_ioprobe, NULL); if (ret != 0) goto failed; - link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.IntType = INT_MEMORY_AND_IO; - link->conf.ConfigIndex = 8; - link->conf.Present = PRESENT_OPTION; + link->config_index = 8; + link->config_regs = PRESENT_OPTION; ret = pcmcia_request_irq(link, mgslpc_isr); if (ret) goto failed; - ret = pcmcia_request_configuration(link, &link->conf); + ret = pcmcia_enable_device(link); if (ret) goto failed; info->io_base = link->resource[0]->start; info->irq_level = link->irq; - - dev_info(&link->dev, "index 0x%02x:", - link->conf.ConfigIndex); - if (link->conf.Attributes & CONF_ENABLE_IRQ) - printk(", irq %d", link->irq); - if (link->resource[0]) - printk(", io %pR", link->resource[0]); - printk("\n"); return 0; failed: @@ -2797,9 +2773,7 @@ MODULE_DEVICE_TABLE(pcmcia, mgslpc_ids); static struct pcmcia_driver mgslpc_driver = { .owner = THIS_MODULE, - .drv = { - .name = "synclink_cs", - }, + .name = "synclink_cs", .probe = mgslpc_probe, .remove = mgslpc_detach, .id_table = mgslpc_ids, @@ -2835,8 +2809,6 @@ static void synclink_cs_cleanup(void) { int rc; - printk("Unloading %s: version %s\n", driver_name, driver_version); - while(mgslpc_device_list) mgslpc_remove_device(mgslpc_device_list); @@ -2859,8 +2831,6 @@ static int __init synclink_cs_init(void) BREAKPOINT(); } - printk("%s %s\n", driver_name, driver_version); - if ((rc = pcmcia_register_driver(&mgslpc_driver)) < 0) return rc; @@ -4127,6 +4097,8 @@ static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) if (cmd != SIOCWANDEV) return hdlc_ioctl(dev, ifr, cmd); + memset(&new_line, 0, size); + switch(ifr->ifr_settings.type) { case IF_GET_IFACE: /* return current sync_serial_settings */ diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c index 02abfddce45a..723152d978a9 100644 --- a/drivers/char/ppdev.c +++ b/drivers/char/ppdev.c @@ -67,7 +67,7 @@ #include <linux/slab.h> #include <linux/major.h> #include <linux/ppdev.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/uaccess.h> #define PP_VERSION "ppdev: user-space parallel port driver" @@ -97,6 +97,7 @@ struct pp_struct { /* ROUND_UP macro from fs/select.c */ #define ROUND_UP(x,y) (((x)+(y)-1)/(y)) +static DEFINE_MUTEX(pp_do_mutex); static inline void pp_enable_irq (struct pp_struct *pp) { struct parport *port = pp->pdev->port; @@ -630,9 +631,9 @@ static int pp_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg) static long pp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { long ret; - lock_kernel(); + mutex_lock(&pp_do_mutex); ret = pp_do_ioctl(file, cmd, arg); - unlock_kernel(); + mutex_unlock(&pp_do_mutex); return ret; } @@ -641,7 +642,6 @@ static int pp_open (struct inode * inode, struct file * file) unsigned int minor = iminor(inode); struct pp_struct *pp; - cycle_kernel_lock(); if (minor >= PARPORT_MAX) return -ENXIO; diff --git a/drivers/char/random.c b/drivers/char/random.c index caef35a46890..5a1aa64f4e76 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -1165,6 +1165,7 @@ const struct file_operations random_fops = { .poll = random_poll, .unlocked_ioctl = random_ioctl, .fasync = random_fasync, + .llseek = noop_llseek, }; const struct file_operations urandom_fops = { @@ -1172,6 +1173,7 @@ const struct file_operations urandom_fops = { .write = random_write, .unlocked_ioctl = random_ioctl, .fasync = random_fasync, + .llseek = noop_llseek, }; /*************************************************************** diff --git a/drivers/char/raw.c b/drivers/char/raw.c index b38942f6bf31..bfe25ea9766b 100644 --- a/drivers/char/raw.c +++ b/drivers/char/raw.c @@ -19,8 +19,8 @@ #include <linux/cdev.h> #include <linux/device.h> #include <linux/mutex.h> -#include <linux/smp_lock.h> #include <linux/gfp.h> +#include <linux/compat.h> #include <asm/uaccess.h> @@ -55,7 +55,6 @@ static int raw_open(struct inode *inode, struct file *filp) return 0; } - lock_kernel(); mutex_lock(&raw_mutex); /* @@ -82,7 +81,6 @@ static int raw_open(struct inode *inode, struct file *filp) bdev->bd_inode->i_mapping; filp->private_data = bdev; mutex_unlock(&raw_mutex); - unlock_kernel(); return 0; out2: @@ -91,7 +89,6 @@ out1: blkdev_put(bdev, filp->f_mode); out: mutex_unlock(&raw_mutex); - unlock_kernel(); return err; } @@ -125,20 +122,84 @@ static long raw_ioctl(struct file *filp, unsigned int command, unsigned long arg) { struct block_device *bdev = filp->private_data; - int ret; + return blkdev_ioctl(bdev, 0, command, arg); +} + +static int bind_set(int number, u64 major, u64 minor) +{ + dev_t dev = MKDEV(major, minor); + struct raw_device_data *rawdev; + int err = 0; - lock_kernel(); - ret = blkdev_ioctl(bdev, 0, command, arg); - unlock_kernel(); + if (number <= 0 || number >= MAX_RAW_MINORS) + return -EINVAL; - return ret; + if (MAJOR(dev) != major || MINOR(dev) != minor) + return -EINVAL; + + rawdev = &raw_devices[number]; + + /* + * This is like making block devices, so demand the + * same capability + */ + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + /* + * For now, we don't need to check that the underlying + * block device is present or not: we can do that when + * the raw device is opened. Just check that the + * major/minor numbers make sense. + */ + + if (MAJOR(dev) == 0 && dev != 0) + return -EINVAL; + + mutex_lock(&raw_mutex); + if (rawdev->inuse) { + mutex_unlock(&raw_mutex); + return -EBUSY; + } + if (rawdev->binding) { + bdput(rawdev->binding); + module_put(THIS_MODULE); + } + if (!dev) { + /* unbind */ + rawdev->binding = NULL; + device_destroy(raw_class, MKDEV(RAW_MAJOR, number)); + } else { + rawdev->binding = bdget(dev); + if (rawdev->binding == NULL) { + err = -ENOMEM; + } else { + dev_t raw = MKDEV(RAW_MAJOR, number); + __module_get(THIS_MODULE); + device_destroy(raw_class, raw); + device_create(raw_class, NULL, raw, NULL, + "raw%d", number); + } + } + mutex_unlock(&raw_mutex); + return err; } -static void bind_device(struct raw_config_request *rq) +static int bind_get(int number, dev_t *dev) { - device_destroy(raw_class, MKDEV(RAW_MAJOR, rq->raw_minor)); - device_create(raw_class, NULL, MKDEV(RAW_MAJOR, rq->raw_minor), NULL, - "raw%d", rq->raw_minor); + struct raw_device_data *rawdev; + struct block_device *bdev; + + if (number <= 0 || number >= MAX_RAW_MINORS) + return -EINVAL; + + rawdev = &raw_devices[number]; + + mutex_lock(&raw_mutex); + bdev = rawdev->binding; + *dev = bdev ? bdev->bd_dev : 0; + mutex_unlock(&raw_mutex); + return 0; } /* @@ -149,105 +210,78 @@ static long raw_ctl_ioctl(struct file *filp, unsigned int command, unsigned long arg) { struct raw_config_request rq; - struct raw_device_data *rawdev; - int err = 0; + dev_t dev; + int err; - lock_kernel(); switch (command) { case RAW_SETBIND: + if (copy_from_user(&rq, (void __user *) arg, sizeof(rq))) + return -EFAULT; + + return bind_set(rq.raw_minor, rq.block_major, rq.block_minor); + case RAW_GETBIND: + if (copy_from_user(&rq, (void __user *) arg, sizeof(rq))) + return -EFAULT; - /* First, find out which raw minor we want */ + err = bind_get(rq.raw_minor, &dev); + if (err) + return err; - if (copy_from_user(&rq, (void __user *) arg, sizeof(rq))) { - err = -EFAULT; - goto out; - } + rq.block_major = MAJOR(dev); + rq.block_minor = MINOR(dev); - if (rq.raw_minor <= 0 || rq.raw_minor >= MAX_RAW_MINORS) { - err = -EINVAL; - goto out; - } - rawdev = &raw_devices[rq.raw_minor]; - - if (command == RAW_SETBIND) { - dev_t dev; - - /* - * This is like making block devices, so demand the - * same capability - */ - if (!capable(CAP_SYS_ADMIN)) { - err = -EPERM; - goto out; - } - - /* - * For now, we don't need to check that the underlying - * block device is present or not: we can do that when - * the raw device is opened. Just check that the - * major/minor numbers make sense. - */ - - dev = MKDEV(rq.block_major, rq.block_minor); - if ((rq.block_major == 0 && rq.block_minor != 0) || - MAJOR(dev) != rq.block_major || - MINOR(dev) != rq.block_minor) { - err = -EINVAL; - goto out; - } - - mutex_lock(&raw_mutex); - if (rawdev->inuse) { - mutex_unlock(&raw_mutex); - err = -EBUSY; - goto out; - } - if (rawdev->binding) { - bdput(rawdev->binding); - module_put(THIS_MODULE); - } - if (rq.block_major == 0 && rq.block_minor == 0) { - /* unbind */ - rawdev->binding = NULL; - device_destroy(raw_class, - MKDEV(RAW_MAJOR, rq.raw_minor)); - } else { - rawdev->binding = bdget(dev); - if (rawdev->binding == NULL) - err = -ENOMEM; - else { - __module_get(THIS_MODULE); - bind_device(&rq); - } - } - mutex_unlock(&raw_mutex); - } else { - struct block_device *bdev; - - mutex_lock(&raw_mutex); - bdev = rawdev->binding; - if (bdev) { - rq.block_major = MAJOR(bdev->bd_dev); - rq.block_minor = MINOR(bdev->bd_dev); - } else { - rq.block_major = rq.block_minor = 0; - } - mutex_unlock(&raw_mutex); - if (copy_to_user((void __user *)arg, &rq, sizeof(rq))) { - err = -EFAULT; - goto out; - } - } - break; - default: - err = -EINVAL; - break; + if (copy_to_user((void __user *)arg, &rq, sizeof(rq))) + return -EFAULT; + + return 0; } -out: - unlock_kernel(); - return err; + + return -EINVAL; +} + +#ifdef CONFIG_COMPAT +struct raw32_config_request { + compat_int_t raw_minor; + compat_u64 block_major; + compat_u64 block_minor; +}; + +static long raw_ctl_compat_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct raw32_config_request __user *user_req = compat_ptr(arg); + struct raw32_config_request rq; + dev_t dev; + int err = 0; + + switch (cmd) { + case RAW_SETBIND: + if (copy_from_user(&rq, user_req, sizeof(rq))) + return -EFAULT; + + return bind_set(rq.raw_minor, rq.block_major, rq.block_minor); + + case RAW_GETBIND: + if (copy_from_user(&rq, user_req, sizeof(rq))) + return -EFAULT; + + err = bind_get(rq.raw_minor, &dev); + if (err) + return err; + + rq.block_major = MAJOR(dev); + rq.block_minor = MINOR(dev); + + if (copy_to_user(user_req, &rq, sizeof(rq))) + return -EFAULT; + + return 0; + } + + return -EINVAL; } +#endif static const struct file_operations raw_fops = { .read = do_sync_read, @@ -258,13 +292,18 @@ static const struct file_operations raw_fops = { .open = raw_open, .release = raw_release, .unlocked_ioctl = raw_ioctl, + .llseek = default_llseek, .owner = THIS_MODULE, }; static const struct file_operations raw_ctl_fops = { .unlocked_ioctl = raw_ctl_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = raw_ctl_compat_ioctl, +#endif .open = raw_open, .owner = THIS_MODULE, + .llseek = noop_llseek, }; static struct cdev raw_cdev; diff --git a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c index d58c2eb07f07..5e33293d24e3 100644 --- a/drivers/char/rio/rio_linux.c +++ b/drivers/char/rio/rio_linux.c @@ -44,7 +44,7 @@ #include <linux/delay.h> #include <linux/pci.h> #include <linux/slab.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/miscdevice.h> #include <linux/init.h> @@ -122,6 +122,7 @@ more than 512 ports.... */ /* These constants are derived from SCO Source */ +static DEFINE_MUTEX(rio_fw_mutex); static struct Conf RIOConf = { /* locator */ "RIO Config here", @@ -241,6 +242,7 @@ static struct real_driver rio_real_driver = { static const struct file_operations rio_fw_fops = { .owner = THIS_MODULE, .unlocked_ioctl = rio_fw_ioctl, + .llseek = noop_llseek, }; static struct miscdevice rio_fw_device = { @@ -566,9 +568,9 @@ static long rio_fw_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) func_enter(); /* The "dev" argument isn't used. */ - lock_kernel(); + mutex_lock(&rio_fw_mutex); rc = riocontrol(p, 0, cmd, arg, capable(CAP_SYS_ADMIN)); - unlock_kernel(); + mutex_unlock(&rio_fw_mutex); func_exit(); return rc; diff --git a/drivers/char/scx200_gpio.c b/drivers/char/scx200_gpio.c index 99e5272e3c53..0bc135b9b16f 100644 --- a/drivers/char/scx200_gpio.c +++ b/drivers/char/scx200_gpio.c @@ -67,6 +67,7 @@ static const struct file_operations scx200_gpio_fileops = { .read = nsc_gpio_read, .open = scx200_gpio_open, .release = scx200_gpio_release, + .llseek = no_llseek, }; static struct cdev scx200_gpio_cdev; /* use 1 cdev for all pins */ diff --git a/drivers/char/snsc.c b/drivers/char/snsc.c index 32b74de18f5f..5816b39ff5a9 100644 --- a/drivers/char/snsc.c +++ b/drivers/char/snsc.c @@ -21,7 +21,7 @@ #include <linux/poll.h> #include <linux/module.h> #include <linux/slab.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <asm/sn/io.h> #include <asm/sn/sn_sal.h> #include <asm/sn/module.h> @@ -34,6 +34,7 @@ #define SCDRV_BUFSZ 2048 #define SCDRV_TIMEOUT 1000 +static DEFINE_MUTEX(scdrv_mutex); static irqreturn_t scdrv_interrupt(int irq, void *subch_data) { @@ -105,7 +106,7 @@ scdrv_open(struct inode *inode, struct file *file) file->private_data = sd; /* hook this subchannel up to the system controller interrupt */ - lock_kernel(); + mutex_lock(&scdrv_mutex); rv = request_irq(SGI_UART_VECTOR, scdrv_interrupt, IRQF_SHARED | IRQF_DISABLED, SYSCTL_BASENAME, sd); @@ -113,10 +114,10 @@ scdrv_open(struct inode *inode, struct file *file) ia64_sn_irtr_close(sd->sd_nasid, sd->sd_subch); kfree(sd); printk("%s: irq request failed (%d)\n", __func__, rv); - unlock_kernel(); + mutex_unlock(&scdrv_mutex); return -EBUSY; } - unlock_kernel(); + mutex_unlock(&scdrv_mutex); return 0; } @@ -357,6 +358,7 @@ static const struct file_operations scdrv_fops = { .poll = scdrv_poll, .open = scdrv_open, .release = scdrv_release, + .llseek = noop_llseek, }; static struct class *snsc_class; diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c index f2167f8e5aab..8ef16490810c 100644 --- a/drivers/char/stallion.c +++ b/drivers/char/stallion.c @@ -608,6 +608,7 @@ static unsigned int sc26198_baudtable[] = { static const struct file_operations stl_fsiomem = { .owner = THIS_MODULE, .unlocked_ioctl = stl_memioctl, + .llseek = noop_llseek, }; static struct class *stallion_class; diff --git a/drivers/char/sx.c b/drivers/char/sx.c index 5b24db4ff7f1..e53f16865397 100644 --- a/drivers/char/sx.c +++ b/drivers/char/sx.c @@ -397,6 +397,7 @@ static struct real_driver sx_real_driver = { static const struct file_operations sx_fw_fops = { .owner = THIS_MODULE, .unlocked_ioctl = sx_fw_ioctl, + .llseek = noop_llseek, }; static struct miscdevice sx_fw_device = { diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c index ef31bb81e843..f3019f53e875 100644 --- a/drivers/char/sysrq.c +++ b/drivers/char/sysrq.c @@ -772,6 +772,7 @@ static ssize_t write_sysrq_trigger(struct file *file, const char __user *buf, static const struct file_operations proc_sysrq_trigger_operations = { .write = write_sysrq_trigger, + .llseek = noop_llseek, }; static void sysrq_init_procfs(void) diff --git a/drivers/char/tb0219.c b/drivers/char/tb0219.c index cad4eb65f13d..ad264185eb10 100644 --- a/drivers/char/tb0219.c +++ b/drivers/char/tb0219.c @@ -261,6 +261,7 @@ static const struct file_operations tb0219_fops = { .write = tanbac_tb0219_write, .open = tanbac_tb0219_open, .release = tanbac_tb0219_release, + .llseek = no_llseek, }; static void tb0219_restart(char *command) diff --git a/drivers/char/tlclk.c b/drivers/char/tlclk.c index 80ea6bcfffdc..0c964cdcc223 100644 --- a/drivers/char/tlclk.c +++ b/drivers/char/tlclk.c @@ -37,7 +37,7 @@ #include <linux/ioport.h> #include <linux/interrupt.h> #include <linux/spinlock.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/timer.h> #include <linux/sysfs.h> #include <linux/device.h> @@ -206,7 +206,7 @@ static int tlclk_open(struct inode *inode, struct file *filp) { int result; - lock_kernel(); + mutex_lock(&tlclk_mutex); if (test_and_set_bit(0, &useflags)) { result = -EBUSY; /* this legacy device is always one per system and it doesn't @@ -229,7 +229,7 @@ static int tlclk_open(struct inode *inode, struct file *filp) inb(TLCLK_REG6); /* Clear interrupt events */ out: - unlock_kernel(); + mutex_unlock(&tlclk_mutex); return result; } @@ -267,6 +267,7 @@ static const struct file_operations tlclk_fops = { .read = tlclk_read, .open = tlclk_open, .release = tlclk_release, + .llseek = noop_llseek, }; diff --git a/drivers/char/toshiba.c b/drivers/char/toshiba.c index f8bc79f6de34..014c9d90d297 100644 --- a/drivers/char/toshiba.c +++ b/drivers/char/toshiba.c @@ -68,7 +68,7 @@ #include <linux/stat.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/toshiba.h> #define TOSH_MINOR_DEV 181 @@ -78,6 +78,7 @@ MODULE_AUTHOR("Jonathan Buzzard <jonathan@buzzard.org.uk>"); MODULE_DESCRIPTION("Toshiba laptop SMM driver"); MODULE_SUPPORTED_DEVICE("toshiba"); +static DEFINE_MUTEX(tosh_mutex); static int tosh_fn; module_param_named(fn, tosh_fn, int, 0); MODULE_PARM_DESC(fn, "User specified Fn key detection port"); @@ -95,6 +96,7 @@ static long tosh_ioctl(struct file *, unsigned int, static const struct file_operations tosh_fops = { .owner = THIS_MODULE, .unlocked_ioctl = tosh_ioctl, + .llseek = noop_llseek, }; static struct miscdevice tosh_device = { @@ -274,16 +276,16 @@ static long tosh_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) return -EINVAL; /* do we need to emulate the fan ? */ - lock_kernel(); + mutex_lock(&tosh_mutex); if (tosh_fan==1) { if (((ax==0xf300) || (ax==0xf400)) && (bx==0x0004)) { err = tosh_emulate_fan(®s); - unlock_kernel(); + mutex_unlock(&tosh_mutex); break; } } err = tosh_smm(®s); - unlock_kernel(); + mutex_unlock(&tosh_mutex); break; default: return -EINVAL; diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 05ad4a17a28f..7c4133582dba 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -47,6 +47,16 @@ enum tpm_duration { #define TPM_MAX_PROTECTED_ORDINAL 12 #define TPM_PROTECTED_ORDINAL_MASK 0xFF +/* + * Bug workaround - some TPM's don't flush the most + * recently changed pcr on suspend, so force the flush + * with an extend to the selected _unused_ non-volatile pcr. + */ +static int tpm_suspend_pcr; +module_param_named(suspend_pcr, tpm_suspend_pcr, uint, 0644); +MODULE_PARM_DESC(suspend_pcr, + "PCR to use for dummy writes to faciltate flush on suspend."); + static LIST_HEAD(tpm_chip_list); static DEFINE_SPINLOCK(driver_lock); static DECLARE_BITMAP(dev_mask, TPM_NUM_DEVICES); @@ -1077,18 +1087,6 @@ static struct tpm_input_header savestate_header = { .ordinal = TPM_ORD_SAVESTATE }; -/* Bug workaround - some TPM's don't flush the most - * recently changed pcr on suspend, so force the flush - * with an extend to the selected _unused_ non-volatile pcr. - */ -static int tpm_suspend_pcr; -static int __init tpm_suspend_setup(char *str) -{ - get_option(&str, &tpm_suspend_pcr); - return 1; -} -__setup("tpm_suspend_pcr=", tpm_suspend_setup); - /* * We are about to suspend. Save the TPM state * so that it can be restored. diff --git a/drivers/char/uv_mmtimer.c b/drivers/char/uv_mmtimer.c index c7072ba14f48..493b47a0d511 100644 --- a/drivers/char/uv_mmtimer.c +++ b/drivers/char/uv_mmtimer.c @@ -52,6 +52,7 @@ static const struct file_operations uv_mmtimer_fops = { .owner = THIS_MODULE, .mmap = uv_mmtimer_mmap, .unlocked_ioctl = uv_mmtimer_ioctl, + .llseek = noop_llseek, }; /** diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c index 42f7fa442ff8..ad6e64a2912d 100644 --- a/drivers/char/viotape.c +++ b/drivers/char/viotape.c @@ -46,7 +46,7 @@ #include <linux/completion.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/slab.h> #include <asm/uaccess.h> @@ -64,6 +64,7 @@ #define VIOTAPE_KERN_WARN KERN_WARNING "viotape: " #define VIOTAPE_KERN_INFO KERN_INFO "viotape: " +static DEFINE_MUTEX(proc_viotape_mutex); static int viotape_numdev; /* @@ -684,9 +685,9 @@ static long viotap_unlocked_ioctl(struct file *file, { long rc; - lock_kernel(); + mutex_lock(&proc_viotape_mutex); rc = viotap_ioctl(file->f_path.dentry->d_inode, file, cmd, arg); - unlock_kernel(); + mutex_unlock(&proc_viotape_mutex); return rc; } @@ -700,7 +701,7 @@ static int viotap_open(struct inode *inode, struct file *file) if (op == NULL) return -ENOMEM; - lock_kernel(); + mutex_lock(&proc_viotape_mutex); get_dev_info(file->f_path.dentry->d_inode, &devi); /* Note: We currently only support one mode! */ @@ -731,7 +732,7 @@ static int viotap_open(struct inode *inode, struct file *file) free_op: free_op_struct(op); - unlock_kernel(); + mutex_unlock(&proc_viotape_mutex); return ret; } @@ -804,6 +805,7 @@ const struct file_operations viotap_fops = { .unlocked_ioctl = viotap_unlocked_ioctl, .open = viotap_open, .release = viotap_release, + .llseek = noop_llseek, }; /* Handle interrupt events for tape */ diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 0f69c5ec0ecd..6c1b676643a9 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -48,6 +48,9 @@ struct ports_driver_data { /* Used for exporting per-port information to debugfs */ struct dentry *debugfs_dir; + /* List of all the devices we're handling */ + struct list_head portdevs; + /* Number of devices this driver is handling */ unsigned int index; @@ -108,6 +111,9 @@ struct port_buffer { * ports for that device (vdev->priv). */ struct ports_device { + /* Next portdev in the list, head is in the pdrvdata struct */ + struct list_head list; + /* * Workqueue handlers where we process deferred work after * notification @@ -178,15 +184,21 @@ struct port { struct console cons; /* Each port associates with a separate char device */ - struct cdev cdev; + struct cdev *cdev; struct device *dev; + /* Reference-counting to handle port hot-unplugs and file operations */ + struct kref kref; + /* A waitqueue for poll() or blocking read operations */ wait_queue_head_t waitqueue; /* The 'name' of the port that we expose via sysfs properties */ char *name; + /* We can notify apps of host connect / disconnect events via SIGIO */ + struct fasync_struct *async_queue; + /* The 'id' to identify the port with the Host */ u32 id; @@ -221,6 +233,41 @@ out: return port; } +static struct port *find_port_by_devt_in_portdev(struct ports_device *portdev, + dev_t dev) +{ + struct port *port; + unsigned long flags; + + spin_lock_irqsave(&portdev->ports_lock, flags); + list_for_each_entry(port, &portdev->ports, list) + if (port->cdev->dev == dev) + goto out; + port = NULL; +out: + spin_unlock_irqrestore(&portdev->ports_lock, flags); + + return port; +} + +static struct port *find_port_by_devt(dev_t dev) +{ + struct ports_device *portdev; + struct port *port; + unsigned long flags; + + spin_lock_irqsave(&pdrvdata_lock, flags); + list_for_each_entry(portdev, &pdrvdata.portdevs, list) { + port = find_port_by_devt_in_portdev(portdev, dev); + if (port) + goto out; + } + port = NULL; +out: + spin_unlock_irqrestore(&pdrvdata_lock, flags); + return port; +} + static struct port *find_port_by_id(struct ports_device *portdev, u32 id) { struct port *port; @@ -410,7 +457,10 @@ static ssize_t __send_control_msg(struct ports_device *portdev, u32 port_id, static ssize_t send_control_msg(struct port *port, unsigned int event, unsigned int value) { - return __send_control_msg(port->portdev, port->id, event, value); + /* Did the port get unplugged before userspace closed it? */ + if (port->portdev) + return __send_control_msg(port->portdev, port->id, event, value); + return 0; } /* Callers must take the port->outvq_lock */ @@ -525,6 +575,10 @@ static ssize_t fill_readbuf(struct port *port, char *out_buf, size_t out_count, /* The condition that must be true for polling to end */ static bool will_read_block(struct port *port) { + if (!port->guest_connected) { + /* Port got hot-unplugged. Let's exit. */ + return false; + } return !port_has_data(port) && port->host_connected; } @@ -575,6 +629,9 @@ static ssize_t port_fops_read(struct file *filp, char __user *ubuf, if (ret < 0) return ret; } + /* Port got hot-unplugged. */ + if (!port->guest_connected) + return -ENODEV; /* * We could've received a disconnection message while we were * waiting for more data. @@ -616,6 +673,9 @@ static ssize_t port_fops_write(struct file *filp, const char __user *ubuf, if (ret < 0) return ret; } + /* Port got hot-unplugged. */ + if (!port->guest_connected) + return -ENODEV; count = min((size_t)(32 * 1024), count); @@ -656,6 +716,10 @@ static unsigned int port_fops_poll(struct file *filp, poll_table *wait) port = filp->private_data; poll_wait(filp, &port->waitqueue, wait); + if (!port->guest_connected) { + /* Port got unplugged */ + return POLLHUP; + } ret = 0; if (!will_read_block(port)) ret |= POLLIN | POLLRDNORM; @@ -667,6 +731,8 @@ static unsigned int port_fops_poll(struct file *filp, poll_table *wait) return ret; } +static void remove_port(struct kref *kref); + static int port_fops_release(struct inode *inode, struct file *filp) { struct port *port; @@ -687,6 +753,16 @@ static int port_fops_release(struct inode *inode, struct file *filp) reclaim_consumed_buffers(port); spin_unlock_irq(&port->outvq_lock); + /* + * Locks aren't necessary here as a port can't be opened after + * unplug, and if a port isn't unplugged, a kref would already + * exist for the port. Plus, taking ports_lock here would + * create a dependency on other locks taken by functions + * inside remove_port if we're the last holder of the port, + * creating many problems. + */ + kref_put(&port->kref, remove_port); + return 0; } @@ -694,22 +770,31 @@ static int port_fops_open(struct inode *inode, struct file *filp) { struct cdev *cdev = inode->i_cdev; struct port *port; + int ret; - port = container_of(cdev, struct port, cdev); + port = find_port_by_devt(cdev->dev); filp->private_data = port; + /* Prevent against a port getting hot-unplugged at the same time */ + spin_lock_irq(&port->portdev->ports_lock); + kref_get(&port->kref); + spin_unlock_irq(&port->portdev->ports_lock); + /* * Don't allow opening of console port devices -- that's done * via /dev/hvc */ - if (is_console_port(port)) - return -ENXIO; + if (is_console_port(port)) { + ret = -ENXIO; + goto out; + } /* Allow only one process to open a particular port at a time */ spin_lock_irq(&port->inbuf_lock); if (port->guest_connected) { spin_unlock_irq(&port->inbuf_lock); - return -EMFILE; + ret = -EMFILE; + goto out; } port->guest_connected = true; @@ -724,10 +809,23 @@ static int port_fops_open(struct inode *inode, struct file *filp) reclaim_consumed_buffers(port); spin_unlock_irq(&port->outvq_lock); + nonseekable_open(inode, filp); + /* Notify host of port being opened */ send_control_msg(filp->private_data, VIRTIO_CONSOLE_PORT_OPEN, 1); return 0; +out: + kref_put(&port->kref, remove_port); + return ret; +} + +static int port_fops_fasync(int fd, struct file *filp, int mode) +{ + struct port *port; + + port = filp->private_data; + return fasync_helper(fd, filp, mode, &port->async_queue); } /* @@ -743,6 +841,8 @@ static const struct file_operations port_fops = { .write = port_fops_write, .poll = port_fops_poll, .release = port_fops_release, + .fasync = port_fops_fasync, + .llseek = no_llseek, }; /* @@ -1001,6 +1101,12 @@ static unsigned int fill_queue(struct virtqueue *vq, spinlock_t *lock) return nr_added_bufs; } +static void send_sigio_to_port(struct port *port) +{ + if (port->async_queue && port->guest_connected) + kill_fasync(&port->async_queue, SIGIO, POLL_OUT); +} + static int add_port(struct ports_device *portdev, u32 id) { char debugfs_name[16]; @@ -1015,6 +1121,7 @@ static int add_port(struct ports_device *portdev, u32 id) err = -ENOMEM; goto fail; } + kref_init(&port->kref); port->portdev = portdev; port->id = id; @@ -1022,6 +1129,7 @@ static int add_port(struct ports_device *portdev, u32 id) port->name = NULL; port->inbuf = NULL; port->cons.hvc = NULL; + port->async_queue = NULL; port->cons.ws.ws_row = port->cons.ws.ws_col = 0; @@ -1032,14 +1140,20 @@ static int add_port(struct ports_device *portdev, u32 id) port->in_vq = portdev->in_vqs[port->id]; port->out_vq = portdev->out_vqs[port->id]; - cdev_init(&port->cdev, &port_fops); + port->cdev = cdev_alloc(); + if (!port->cdev) { + dev_err(&port->portdev->vdev->dev, "Error allocating cdev\n"); + err = -ENOMEM; + goto free_port; + } + port->cdev->ops = &port_fops; devt = MKDEV(portdev->chr_major, id); - err = cdev_add(&port->cdev, devt, 1); + err = cdev_add(port->cdev, devt, 1); if (err < 0) { dev_err(&port->portdev->vdev->dev, "Error %d adding cdev for port %u\n", err, id); - goto free_port; + goto free_cdev; } port->dev = device_create(pdrvdata.class, &port->portdev->vdev->dev, devt, port, "vport%up%u", @@ -1104,7 +1218,7 @@ free_inbufs: free_device: device_destroy(pdrvdata.class, port->dev->devt); free_cdev: - cdev_del(&port->cdev); + cdev_del(port->cdev); free_port: kfree(port); fail: @@ -1113,21 +1227,45 @@ fail: return err; } -/* Remove all port-specific data. */ -static int remove_port(struct port *port) +/* No users remain, remove all port-specific data. */ +static void remove_port(struct kref *kref) +{ + struct port *port; + + port = container_of(kref, struct port, kref); + + sysfs_remove_group(&port->dev->kobj, &port_attribute_group); + device_destroy(pdrvdata.class, port->dev->devt); + cdev_del(port->cdev); + + kfree(port->name); + + debugfs_remove(port->debugfs_file); + + kfree(port); +} + +/* + * Port got unplugged. Remove port from portdev's list and drop the + * kref reference. If no userspace has this port opened, it will + * result in immediate removal the port. + */ +static void unplug_port(struct port *port) { struct port_buffer *buf; + spin_lock_irq(&port->portdev->ports_lock); + list_del(&port->list); + spin_unlock_irq(&port->portdev->ports_lock); + if (port->guest_connected) { port->guest_connected = false; port->host_connected = false; wake_up_interruptible(&port->waitqueue); - send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 0); - } - spin_lock_irq(&port->portdev->ports_lock); - list_del(&port->list); - spin_unlock_irq(&port->portdev->ports_lock); + /* Let the app know the port is going down. */ + send_sigio_to_port(port); + } if (is_console_port(port)) { spin_lock_irq(&pdrvdata_lock); @@ -1146,9 +1284,6 @@ static int remove_port(struct port *port) hvc_remove(port->cons.hvc); #endif } - sysfs_remove_group(&port->dev->kobj, &port_attribute_group); - device_destroy(pdrvdata.class, port->dev->devt); - cdev_del(&port->cdev); /* Remove unused data this port might have received. */ discard_port_data(port); @@ -1159,12 +1294,19 @@ static int remove_port(struct port *port) while ((buf = virtqueue_detach_unused_buf(port->in_vq))) free_buf(buf); - kfree(port->name); - - debugfs_remove(port->debugfs_file); + /* + * We should just assume the device itself has gone off -- + * else a close on an open port later will try to send out a + * control message. + */ + port->portdev = NULL; - kfree(port); - return 0; + /* + * Locks around here are not necessary - a port can't be + * opened after we removed the port struct from ports_list + * above. + */ + kref_put(&port->kref, remove_port); } /* Any private messages that the Host and Guest want to share */ @@ -1203,7 +1345,7 @@ static void handle_control_message(struct ports_device *portdev, add_port(portdev, cpkt->id); break; case VIRTIO_CONSOLE_PORT_REMOVE: - remove_port(port); + unplug_port(port); break; case VIRTIO_CONSOLE_CONSOLE_PORT: if (!cpkt->value) @@ -1245,6 +1387,12 @@ static void handle_control_message(struct ports_device *portdev, spin_lock_irq(&port->outvq_lock); reclaim_consumed_buffers(port); spin_unlock_irq(&port->outvq_lock); + + /* + * If the guest is connected, it'll be interested in + * knowing the host connection state changed. + */ + send_sigio_to_port(port); break; case VIRTIO_CONSOLE_PORT_NAME: /* @@ -1341,6 +1489,9 @@ static void in_intr(struct virtqueue *vq) wake_up_interruptible(&port->waitqueue); + /* Send a SIGIO indicating new data in case the process asked for it */ + send_sigio_to_port(port); + if (is_console_port(port) && hvc_poll(port->cons.hvc)) hvc_kick(); } @@ -1577,6 +1728,10 @@ static int __devinit virtcons_probe(struct virtio_device *vdev) add_port(portdev, 0); } + spin_lock_irq(&pdrvdata_lock); + list_add_tail(&portdev->list, &pdrvdata.portdevs); + spin_unlock_irq(&pdrvdata_lock); + __send_control_msg(portdev, VIRTIO_CONSOLE_BAD_ID, VIRTIO_CONSOLE_DEVICE_READY, 1); return 0; @@ -1600,23 +1755,41 @@ static void virtcons_remove(struct virtio_device *vdev) { struct ports_device *portdev; struct port *port, *port2; - struct port_buffer *buf; - unsigned int len; portdev = vdev->priv; + spin_lock_irq(&pdrvdata_lock); + list_del(&portdev->list); + spin_unlock_irq(&pdrvdata_lock); + + /* Disable interrupts for vqs */ + vdev->config->reset(vdev); + /* Finish up work that's lined up */ cancel_work_sync(&portdev->control_work); list_for_each_entry_safe(port, port2, &portdev->ports, list) - remove_port(port); + unplug_port(port); unregister_chrdev(portdev->chr_major, "virtio-portsdev"); - while ((buf = virtqueue_get_buf(portdev->c_ivq, &len))) - free_buf(buf); + /* + * When yanking out a device, we immediately lose the + * (device-side) queues. So there's no point in keeping the + * guest side around till we drop our final reference. This + * also means that any ports which are in an open state will + * have to just stop using the port, as the vqs are going + * away. + */ + if (use_multiport(portdev)) { + struct port_buffer *buf; + unsigned int len; - while ((buf = virtqueue_detach_unused_buf(portdev->c_ivq))) - free_buf(buf); + while ((buf = virtqueue_get_buf(portdev->c_ivq, &len))) + free_buf(buf); + + while ((buf = virtqueue_detach_unused_buf(portdev->c_ivq))) + free_buf(buf); + } vdev->config->del_vqs(vdev); kfree(portdev->in_vqs); @@ -1663,6 +1836,7 @@ static int __init init(void) PTR_ERR(pdrvdata.debugfs_dir)); } INIT_LIST_HEAD(&pdrvdata.consoles); + INIT_LIST_HEAD(&pdrvdata.portdevs); return register_virtio_driver(&virtio_console); } diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c b/drivers/char/xilinx_hwicap/xilinx_hwicap.c index b663d573aad9..9f2272e6de1c 100644 --- a/drivers/char/xilinx_hwicap/xilinx_hwicap.c +++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.c @@ -81,7 +81,6 @@ #include <linux/poll.h> #include <linux/proc_fs.h> #include <linux/mutex.h> -#include <linux/smp_lock.h> #include <linux/sysctl.h> #include <linux/fs.h> #include <linux/cdev.h> @@ -112,6 +111,7 @@ #define HWICAP_DEVICES 1 /* An array, which is set to true when the device is registered. */ +static DEFINE_MUTEX(hwicap_mutex); static bool probed_devices[HWICAP_DEVICES]; static struct mutex icap_sem; @@ -502,7 +502,7 @@ static int hwicap_open(struct inode *inode, struct file *file) struct hwicap_drvdata *drvdata; int status; - lock_kernel(); + mutex_lock(&hwicap_mutex); drvdata = container_of(inode->i_cdev, struct hwicap_drvdata, cdev); status = mutex_lock_interruptible(&drvdata->sem); @@ -528,7 +528,7 @@ static int hwicap_open(struct inode *inode, struct file *file) error: mutex_unlock(&drvdata->sem); out: - unlock_kernel(); + mutex_unlock(&hwicap_mutex); return status; } @@ -567,6 +567,7 @@ static const struct file_operations hwicap_fops = { .read = hwicap_read, .open = hwicap_open, .release = hwicap_release, + .llseek = noop_llseek, }; static int __devinit hwicap_setup(struct device *dev, int id, diff --git a/drivers/dma/coh901318.c b/drivers/dma/coh901318.c index 557e2272e5b3..ae2b8714d190 100644 --- a/drivers/dma/coh901318.c +++ b/drivers/dma/coh901318.c @@ -157,6 +157,7 @@ static const struct file_operations coh901318_debugfs_status_operations = { .owner = THIS_MODULE, .open = coh901318_debugfs_open, .read = coh901318_debugfs_read, + .llseek = default_llseek, }; diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index 70bb350de996..9dbb28b9559f 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -39,7 +39,7 @@ config EDAC_DEBUG there're four debug levels (x=0,1,2,3 from low to high). Usually you should select 'N'. - config EDAC_DECODE_MCE +config EDAC_DECODE_MCE tristate "Decode MCEs in human-readable form (only on AMD for now)" depends on CPU_SUP_AMD && X86_MCE default y @@ -51,6 +51,16 @@ config EDAC_DEBUG which occur really early upon boot, before the module infrastructure has been initialized. +config EDAC_MCE_INJ + tristate "Simple MCE injection interface over /sysfs" + depends on EDAC_DECODE_MCE + default n + help + This is a simple interface to inject MCEs over /sysfs and test + the MCE decoding code in EDAC. + + This is currently AMD-only. + config EDAC_MM_EDAC tristate "Main Memory EDAC (Error Detection And Correction) reporting" help @@ -66,13 +76,13 @@ config EDAC_MCE config EDAC_AMD64 tristate "AMD64 (Opteron, Athlon64) K8, F10h, F11h" - depends on EDAC_MM_EDAC && K8_NB && X86_64 && PCI && EDAC_DECODE_MCE + depends on EDAC_MM_EDAC && AMD_NB && X86_64 && PCI && EDAC_DECODE_MCE help Support for error detection and correction on the AMD 64 Families of Memory Controllers (K8, F10h and F11h) config EDAC_AMD64_ERROR_INJECTION - bool "Sysfs Error Injection facilities" + bool "Sysfs HW Error injection facilities" depends on EDAC_AMD64 help Recent Opterons (Family 10h and later) provide for Memory Error diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile index ca6b1bb24ccc..32c7bc93c525 100644 --- a/drivers/edac/Makefile +++ b/drivers/edac/Makefile @@ -17,6 +17,9 @@ ifdef CONFIG_PCI edac_core-objs += edac_pci.o edac_pci_sysfs.o endif +obj-$(CONFIG_EDAC_MCE_INJ) += mce_amd_inj.o + +edac_mce_amd-objs := mce_amd.o obj-$(CONFIG_EDAC_DECODE_MCE) += edac_mce_amd.o obj-$(CONFIG_EDAC_AMD76X) += amd76x_edac.o diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index e7d5d6b5dcf6..8521401bbd75 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -1,5 +1,5 @@ #include "amd64_edac.h" -#include <asm/k8.h> +#include <asm/amd_nb.h> static struct edac_pci_ctl_info *amd64_ctl_pci; @@ -2073,11 +2073,18 @@ static inline void __amd64_decode_bus_error(struct mem_ctl_info *mci, amd64_handle_ue(mci, info); } -void amd64_decode_bus_error(int node_id, struct err_regs *regs) +void amd64_decode_bus_error(int node_id, struct mce *m, u32 nbcfg) { struct mem_ctl_info *mci = mci_lookup[node_id]; + struct err_regs regs; - __amd64_decode_bus_error(mci, regs); + regs.nbsl = (u32) m->status; + regs.nbsh = (u32)(m->status >> 32); + regs.nbeal = (u32) m->addr; + regs.nbeah = (u32)(m->addr >> 32); + regs.nbcfg = nbcfg; + + __amd64_decode_bus_error(mci, ®s); /* * Check the UE bit of the NB status high register, if set generate some @@ -2086,7 +2093,7 @@ void amd64_decode_bus_error(int node_id, struct err_regs *regs) * * FIXME: this should go somewhere else, if at all. */ - if (regs->nbsh & K8_NBSH_UC_ERR && !report_gart_errors) + if (regs.nbsh & K8_NBSH_UC_ERR && !report_gart_errors) edac_mc_handle_ue_no_info(mci, "UE bit is set"); } @@ -2927,7 +2934,7 @@ static int __init amd64_edac_init(void) * to finish initialization of the MC instances. */ err = -ENODEV; - for (nb = 0; nb < num_k8_northbridges; nb++) { + for (nb = 0; nb < k8_northbridges.num; nb++) { if (!pvt_lookup[nb]) continue; diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h index 613b9381e71a..044aee4f944d 100644 --- a/drivers/edac/amd64_edac.h +++ b/drivers/edac/amd64_edac.h @@ -72,7 +72,7 @@ #include <linux/edac.h> #include <asm/msr.h> #include "edac_core.h" -#include "edac_mce_amd.h" +#include "mce_amd.h" #define amd64_printk(level, fmt, arg...) \ edac_printk(level, "amd64", fmt, ##arg) @@ -482,11 +482,10 @@ extern const char *rrrr_msgs[16]; extern const char *to_msgs[2]; extern const char *pp_msgs[4]; extern const char *ii_msgs[4]; -extern const char *ext_msgs[32]; extern const char *htlink_msgs[8]; #ifdef CONFIG_EDAC_DEBUG -#define NUM_DBG_ATTRS 9 +#define NUM_DBG_ATTRS 5 #else #define NUM_DBG_ATTRS 0 #endif diff --git a/drivers/edac/amd64_edac_dbg.c b/drivers/edac/amd64_edac_dbg.c index 59cf2cf6e11e..e3562288f4ce 100644 --- a/drivers/edac/amd64_edac_dbg.c +++ b/drivers/edac/amd64_edac_dbg.c @@ -1,167 +1,16 @@ #include "amd64_edac.h" -/* - * accept a hex value and store it into the virtual error register file, field: - * nbeal and nbeah. Assume virtual error values have already been set for: NBSL, - * NBSH and NBCFG. Then proceed to map the error values to a MC, CSROW and - * CHANNEL - */ -static ssize_t amd64_nbea_store(struct mem_ctl_info *mci, const char *data, - size_t count) -{ - struct amd64_pvt *pvt = mci->pvt_info; - unsigned long long value; - int ret = 0; - - ret = strict_strtoull(data, 16, &value); - if (ret != -EINVAL) { - debugf0("received NBEA= 0x%llx\n", value); - - /* place the value into the virtual error packet */ - pvt->ctl_error_info.nbeal = (u32) value; - value >>= 32; - pvt->ctl_error_info.nbeah = (u32) value; - - /* Process the Mapping request */ - /* TODO: Add race prevention */ - amd_decode_nb_mce(pvt->mc_node_id, &pvt->ctl_error_info, 1); - - return count; - } - return ret; -} - -/* display back what the last NBEA (MCA NB Address (MC4_ADDR)) was written */ -static ssize_t amd64_nbea_show(struct mem_ctl_info *mci, char *data) -{ - struct amd64_pvt *pvt = mci->pvt_info; - u64 value; - - value = pvt->ctl_error_info.nbeah; - value <<= 32; - value |= pvt->ctl_error_info.nbeal; - - return sprintf(data, "%llx\n", value); -} - -/* store the NBSL (MCA NB Status Low (MC4_STATUS)) value user desires */ -static ssize_t amd64_nbsl_store(struct mem_ctl_info *mci, const char *data, - size_t count) -{ - struct amd64_pvt *pvt = mci->pvt_info; - unsigned long value; - int ret = 0; - - ret = strict_strtoul(data, 16, &value); - if (ret != -EINVAL) { - debugf0("received NBSL= 0x%lx\n", value); - - pvt->ctl_error_info.nbsl = (u32) value; - - return count; - } - return ret; -} - -/* display back what the last NBSL value written */ -static ssize_t amd64_nbsl_show(struct mem_ctl_info *mci, char *data) -{ - struct amd64_pvt *pvt = mci->pvt_info; - u32 value; - - value = pvt->ctl_error_info.nbsl; - - return sprintf(data, "%x\n", value); -} - -/* store the NBSH (MCA NB Status High) value user desires */ -static ssize_t amd64_nbsh_store(struct mem_ctl_info *mci, const char *data, - size_t count) -{ - struct amd64_pvt *pvt = mci->pvt_info; - unsigned long value; - int ret = 0; - - ret = strict_strtoul(data, 16, &value); - if (ret != -EINVAL) { - debugf0("received NBSH= 0x%lx\n", value); - - pvt->ctl_error_info.nbsh = (u32) value; - - return count; - } - return ret; -} - -/* display back what the last NBSH value written */ -static ssize_t amd64_nbsh_show(struct mem_ctl_info *mci, char *data) -{ - struct amd64_pvt *pvt = mci->pvt_info; - u32 value; - - value = pvt->ctl_error_info.nbsh; - - return sprintf(data, "%x\n", value); +#define EDAC_DCT_ATTR_SHOW(reg) \ +static ssize_t amd64_##reg##_show(struct mem_ctl_info *mci, char *data) \ +{ \ + struct amd64_pvt *pvt = mci->pvt_info; \ + return sprintf(data, "0x%016llx\n", (u64)pvt->reg); \ } -/* accept and store the NBCFG (MCA NB Configuration) value user desires */ -static ssize_t amd64_nbcfg_store(struct mem_ctl_info *mci, - const char *data, size_t count) -{ - struct amd64_pvt *pvt = mci->pvt_info; - unsigned long value; - int ret = 0; - - ret = strict_strtoul(data, 16, &value); - if (ret != -EINVAL) { - debugf0("received NBCFG= 0x%lx\n", value); - - pvt->ctl_error_info.nbcfg = (u32) value; - - return count; - } - return ret; -} - -/* various show routines for the controls of a MCI */ -static ssize_t amd64_nbcfg_show(struct mem_ctl_info *mci, char *data) -{ - struct amd64_pvt *pvt = mci->pvt_info; - - return sprintf(data, "%x\n", pvt->ctl_error_info.nbcfg); -} - - -static ssize_t amd64_dhar_show(struct mem_ctl_info *mci, char *data) -{ - struct amd64_pvt *pvt = mci->pvt_info; - - return sprintf(data, "%x\n", pvt->dhar); -} - - -static ssize_t amd64_dbam_show(struct mem_ctl_info *mci, char *data) -{ - struct amd64_pvt *pvt = mci->pvt_info; - - return sprintf(data, "%x\n", pvt->dbam0); -} - - -static ssize_t amd64_topmem_show(struct mem_ctl_info *mci, char *data) -{ - struct amd64_pvt *pvt = mci->pvt_info; - - return sprintf(data, "%llx\n", pvt->top_mem); -} - - -static ssize_t amd64_topmem2_show(struct mem_ctl_info *mci, char *data) -{ - struct amd64_pvt *pvt = mci->pvt_info; - - return sprintf(data, "%llx\n", pvt->top_mem2); -} +EDAC_DCT_ATTR_SHOW(dhar); +EDAC_DCT_ATTR_SHOW(dbam0); +EDAC_DCT_ATTR_SHOW(top_mem); +EDAC_DCT_ATTR_SHOW(top_mem2); static ssize_t amd64_hole_show(struct mem_ctl_info *mci, char *data) { @@ -182,38 +31,6 @@ struct mcidev_sysfs_attribute amd64_dbg_attrs[] = { { .attr = { - .name = "nbea_ctl", - .mode = (S_IRUGO | S_IWUSR) - }, - .show = amd64_nbea_show, - .store = amd64_nbea_store, - }, - { - .attr = { - .name = "nbsl_ctl", - .mode = (S_IRUGO | S_IWUSR) - }, - .show = amd64_nbsl_show, - .store = amd64_nbsl_store, - }, - { - .attr = { - .name = "nbsh_ctl", - .mode = (S_IRUGO | S_IWUSR) - }, - .show = amd64_nbsh_show, - .store = amd64_nbsh_store, - }, - { - .attr = { - .name = "nbcfg_ctl", - .mode = (S_IRUGO | S_IWUSR) - }, - .show = amd64_nbcfg_show, - .store = amd64_nbcfg_store, - }, - { - .attr = { .name = "dhar", .mode = (S_IRUGO) }, @@ -225,7 +42,7 @@ struct mcidev_sysfs_attribute amd64_dbg_attrs[] = { .name = "dbam", .mode = (S_IRUGO) }, - .show = amd64_dbam_show, + .show = amd64_dbam0_show, .store = NULL, }, { @@ -233,7 +50,7 @@ struct mcidev_sysfs_attribute amd64_dbg_attrs[] = { .name = "topmem", .mode = (S_IRUGO) }, - .show = amd64_topmem_show, + .show = amd64_top_mem_show, .store = NULL, }, { @@ -241,7 +58,7 @@ struct mcidev_sysfs_attribute amd64_dbg_attrs[] = { .name = "topmem2", .mode = (S_IRUGO) }, - .show = amd64_topmem2_show, + .show = amd64_top_mem2_show, .store = NULL, }, { diff --git a/drivers/edac/edac_device_sysfs.c b/drivers/edac/edac_device_sysfs.c index 070968178a24..2941dca91aae 100644 --- a/drivers/edac/edac_device_sysfs.c +++ b/drivers/edac/edac_device_sysfs.c @@ -13,6 +13,7 @@ #include <linux/ctype.h> #include <linux/module.h> #include <linux/slab.h> +#include <linux/edac.h> #include "edac_core.h" #include "edac_module.h" @@ -235,7 +236,7 @@ int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev) debugf1("%s()\n", __func__); /* get the /sys/devices/system/edac reference */ - edac_class = edac_get_edac_class(); + edac_class = edac_get_sysfs_class(); if (edac_class == NULL) { debugf1("%s() no edac_class error\n", __func__); err = -ENODEV; @@ -255,7 +256,7 @@ int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev) if (!try_module_get(edac_dev->owner)) { err = -ENODEV; - goto err_out; + goto err_mod_get; } /* register */ @@ -282,6 +283,9 @@ int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev) err_kobj_reg: module_put(edac_dev->owner); +err_mod_get: + edac_put_sysfs_class(); + err_out: return err; } @@ -290,12 +294,11 @@ err_out: * edac_device_unregister_sysfs_main_kobj: * the '..../edac/<name>' kobject */ -void edac_device_unregister_sysfs_main_kobj( - struct edac_device_ctl_info *edac_dev) +void edac_device_unregister_sysfs_main_kobj(struct edac_device_ctl_info *dev) { debugf0("%s()\n", __func__); debugf4("%s() name of kobject is: %s\n", - __func__, kobject_name(&edac_dev->kobj)); + __func__, kobject_name(&dev->kobj)); /* * Unregister the edac device's kobject and @@ -304,7 +307,8 @@ void edac_device_unregister_sysfs_main_kobj( * a) module_put() this module * b) 'kfree' the memory */ - kobject_put(&edac_dev->kobj); + kobject_put(&dev->kobj); + edac_put_sysfs_class(); } /* edac_dev -> instance information */ diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index 8aad94d10c0c..a4135860149b 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c @@ -11,6 +11,7 @@ #include <linux/ctype.h> #include <linux/slab.h> +#include <linux/edac.h> #include <linux/bug.h> #include "edac_core.h" @@ -1011,13 +1012,13 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci) */ int edac_sysfs_setup_mc_kset(void) { - int err = 0; + int err = -EINVAL; struct sysdev_class *edac_class; debugf1("%s()\n", __func__); /* get the /sys/devices/system/edac class reference */ - edac_class = edac_get_edac_class(); + edac_class = edac_get_sysfs_class(); if (edac_class == NULL) { debugf1("%s() no edac_class error=%d\n", __func__, err); goto fail_out; @@ -1028,15 +1029,16 @@ int edac_sysfs_setup_mc_kset(void) if (!mc_kset) { err = -ENOMEM; debugf1("%s() Failed to register '.../edac/mc'\n", __func__); - goto fail_out; + goto fail_kset; } debugf1("%s() Registered '.../edac/mc' kobject\n", __func__); return 0; +fail_kset: + edac_put_sysfs_class(); - /* error unwind stack */ fail_out: return err; } @@ -1049,5 +1051,6 @@ fail_out: void edac_sysfs_teardown_mc_kset(void) { kset_unregister(mc_kset); + edac_put_sysfs_class(); } diff --git a/drivers/edac/edac_mce_amd.c b/drivers/edac/edac_mce_amd.c deleted file mode 100644 index 9014df6f605d..000000000000 --- a/drivers/edac/edac_mce_amd.c +++ /dev/null @@ -1,452 +0,0 @@ -#include <linux/module.h> -#include "edac_mce_amd.h" - -static bool report_gart_errors; -static void (*nb_bus_decoder)(int node_id, struct err_regs *regs); - -void amd_report_gart_errors(bool v) -{ - report_gart_errors = v; -} -EXPORT_SYMBOL_GPL(amd_report_gart_errors); - -void amd_register_ecc_decoder(void (*f)(int, struct err_regs *)) -{ - nb_bus_decoder = f; -} -EXPORT_SYMBOL_GPL(amd_register_ecc_decoder); - -void amd_unregister_ecc_decoder(void (*f)(int, struct err_regs *)) -{ - if (nb_bus_decoder) { - WARN_ON(nb_bus_decoder != f); - - nb_bus_decoder = NULL; - } -} -EXPORT_SYMBOL_GPL(amd_unregister_ecc_decoder); - -/* - * string representation for the different MCA reported error types, see F3x48 - * or MSR0000_0411. - */ -const char *tt_msgs[] = { /* transaction type */ - "instruction", - "data", - "generic", - "reserved" -}; -EXPORT_SYMBOL_GPL(tt_msgs); - -const char *ll_msgs[] = { /* cache level */ - "L0", - "L1", - "L2", - "L3/generic" -}; -EXPORT_SYMBOL_GPL(ll_msgs); - -const char *rrrr_msgs[] = { - "generic", - "generic read", - "generic write", - "data read", - "data write", - "inst fetch", - "prefetch", - "evict", - "snoop", - "reserved RRRR= 9", - "reserved RRRR= 10", - "reserved RRRR= 11", - "reserved RRRR= 12", - "reserved RRRR= 13", - "reserved RRRR= 14", - "reserved RRRR= 15" -}; -EXPORT_SYMBOL_GPL(rrrr_msgs); - -const char *pp_msgs[] = { /* participating processor */ - "local node originated (SRC)", - "local node responded to request (RES)", - "local node observed as 3rd party (OBS)", - "generic" -}; -EXPORT_SYMBOL_GPL(pp_msgs); - -const char *to_msgs[] = { - "no timeout", - "timed out" -}; -EXPORT_SYMBOL_GPL(to_msgs); - -const char *ii_msgs[] = { /* memory or i/o */ - "mem access", - "reserved", - "i/o access", - "generic" -}; -EXPORT_SYMBOL_GPL(ii_msgs); - -/* - * Map the 4 or 5 (family-specific) bits of Extended Error code to the - * string table. - */ -const char *ext_msgs[] = { - "K8 ECC error", /* 0_0000b */ - "CRC error on link", /* 0_0001b */ - "Sync error packets on link", /* 0_0010b */ - "Master Abort during link operation", /* 0_0011b */ - "Target Abort during link operation", /* 0_0100b */ - "Invalid GART PTE entry during table walk", /* 0_0101b */ - "Unsupported atomic RMW command received", /* 0_0110b */ - "WDT error: NB transaction timeout", /* 0_0111b */ - "ECC/ChipKill ECC error", /* 0_1000b */ - "SVM DEV Error", /* 0_1001b */ - "Link Data error", /* 0_1010b */ - "Link/L3/Probe Filter Protocol error", /* 0_1011b */ - "NB Internal Arrays Parity error", /* 0_1100b */ - "DRAM Address/Control Parity error", /* 0_1101b */ - "Link Transmission error", /* 0_1110b */ - "GART/DEV Table Walk Data error" /* 0_1111b */ - "Res 0x100 error", /* 1_0000b */ - "Res 0x101 error", /* 1_0001b */ - "Res 0x102 error", /* 1_0010b */ - "Res 0x103 error", /* 1_0011b */ - "Res 0x104 error", /* 1_0100b */ - "Res 0x105 error", /* 1_0101b */ - "Res 0x106 error", /* 1_0110b */ - "Res 0x107 error", /* 1_0111b */ - "Res 0x108 error", /* 1_1000b */ - "Res 0x109 error", /* 1_1001b */ - "Res 0x10A error", /* 1_1010b */ - "Res 0x10B error", /* 1_1011b */ - "ECC error in L3 Cache Data", /* 1_1100b */ - "L3 Cache Tag error", /* 1_1101b */ - "L3 Cache LRU Parity error", /* 1_1110b */ - "Probe Filter error" /* 1_1111b */ -}; -EXPORT_SYMBOL_GPL(ext_msgs); - -static void amd_decode_dc_mce(u64 mc0_status) -{ - u32 ec = mc0_status & 0xffff; - u32 xec = (mc0_status >> 16) & 0xf; - - pr_emerg("Data Cache Error"); - - if (xec == 1 && TLB_ERROR(ec)) - pr_cont(": %s TLB multimatch.\n", LL_MSG(ec)); - else if (xec == 0) { - if (mc0_status & (1ULL << 40)) - pr_cont(" during Data Scrub.\n"); - else if (TLB_ERROR(ec)) - pr_cont(": %s TLB parity error.\n", LL_MSG(ec)); - else if (MEM_ERROR(ec)) { - u8 ll = ec & 0x3; - u8 tt = (ec >> 2) & 0x3; - u8 rrrr = (ec >> 4) & 0xf; - - /* see F10h BKDG (31116), Table 92. */ - if (ll == 0x1) { - if (tt != 0x1) - goto wrong_dc_mce; - - pr_cont(": Data/Tag %s error.\n", RRRR_MSG(ec)); - - } else if (ll == 0x2 && rrrr == 0x3) - pr_cont(" during L1 linefill from L2.\n"); - else - goto wrong_dc_mce; - } else if (BUS_ERROR(ec) && boot_cpu_data.x86 == 0xf) - pr_cont(" during system linefill.\n"); - else - goto wrong_dc_mce; - } else - goto wrong_dc_mce; - - return; - -wrong_dc_mce: - pr_warning("Corrupted DC MCE info?\n"); -} - -static void amd_decode_ic_mce(u64 mc1_status) -{ - u32 ec = mc1_status & 0xffff; - u32 xec = (mc1_status >> 16) & 0xf; - - pr_emerg("Instruction Cache Error"); - - if (xec == 1 && TLB_ERROR(ec)) - pr_cont(": %s TLB multimatch.\n", LL_MSG(ec)); - else if (xec == 0) { - if (TLB_ERROR(ec)) - pr_cont(": %s TLB Parity error.\n", LL_MSG(ec)); - else if (BUS_ERROR(ec)) { - if (boot_cpu_data.x86 == 0xf && - (mc1_status & (1ULL << 58))) - pr_cont(" during system linefill.\n"); - else - pr_cont(" during attempted NB data read.\n"); - } else if (MEM_ERROR(ec)) { - u8 ll = ec & 0x3; - u8 rrrr = (ec >> 4) & 0xf; - - if (ll == 0x2) - pr_cont(" during a linefill from L2.\n"); - else if (ll == 0x1) { - - switch (rrrr) { - case 0x5: - pr_cont(": Parity error during " - "data load.\n"); - break; - - case 0x7: - pr_cont(": Copyback Parity/Victim" - " error.\n"); - break; - - case 0x8: - pr_cont(": Tag Snoop error.\n"); - break; - - default: - goto wrong_ic_mce; - break; - } - } - } else - goto wrong_ic_mce; - } else - goto wrong_ic_mce; - - return; - -wrong_ic_mce: - pr_warning("Corrupted IC MCE info?\n"); -} - -static void amd_decode_bu_mce(u64 mc2_status) -{ - u32 ec = mc2_status & 0xffff; - u32 xec = (mc2_status >> 16) & 0xf; - - pr_emerg("Bus Unit Error"); - - if (xec == 0x1) - pr_cont(" in the write data buffers.\n"); - else if (xec == 0x3) - pr_cont(" in the victim data buffers.\n"); - else if (xec == 0x2 && MEM_ERROR(ec)) - pr_cont(": %s error in the L2 cache tags.\n", RRRR_MSG(ec)); - else if (xec == 0x0) { - if (TLB_ERROR(ec)) - pr_cont(": %s error in a Page Descriptor Cache or " - "Guest TLB.\n", TT_MSG(ec)); - else if (BUS_ERROR(ec)) - pr_cont(": %s/ECC error in data read from NB: %s.\n", - RRRR_MSG(ec), PP_MSG(ec)); - else if (MEM_ERROR(ec)) { - u8 rrrr = (ec >> 4) & 0xf; - - if (rrrr >= 0x7) - pr_cont(": %s error during data copyback.\n", - RRRR_MSG(ec)); - else if (rrrr <= 0x1) - pr_cont(": %s parity/ECC error during data " - "access from L2.\n", RRRR_MSG(ec)); - else - goto wrong_bu_mce; - } else - goto wrong_bu_mce; - } else - goto wrong_bu_mce; - - return; - -wrong_bu_mce: - pr_warning("Corrupted BU MCE info?\n"); -} - -static void amd_decode_ls_mce(u64 mc3_status) -{ - u32 ec = mc3_status & 0xffff; - u32 xec = (mc3_status >> 16) & 0xf; - - pr_emerg("Load Store Error"); - - if (xec == 0x0) { - u8 rrrr = (ec >> 4) & 0xf; - - if (!BUS_ERROR(ec) || (rrrr != 0x3 && rrrr != 0x4)) - goto wrong_ls_mce; - - pr_cont(" during %s.\n", RRRR_MSG(ec)); - } - return; - -wrong_ls_mce: - pr_warning("Corrupted LS MCE info?\n"); -} - -void amd_decode_nb_mce(int node_id, struct err_regs *regs, int handle_errors) -{ - u32 ec = ERROR_CODE(regs->nbsl); - - if (!handle_errors) - return; - - /* - * GART TLB error reporting is disabled by default. Bail out early. - */ - if (TLB_ERROR(ec) && !report_gart_errors) - return; - - pr_emerg("Northbridge Error, node %d", node_id); - - /* - * F10h, revD can disable ErrCpu[3:0] so check that first and also the - * value encoding has changed so interpret those differently - */ - if ((boot_cpu_data.x86 == 0x10) && - (boot_cpu_data.x86_model > 7)) { - if (regs->nbsh & K8_NBSH_ERR_CPU_VAL) - pr_cont(", core: %u\n", (u8)(regs->nbsh & 0xf)); - } else { - u8 assoc_cpus = regs->nbsh & 0xf; - - if (assoc_cpus > 0) - pr_cont(", core: %d", fls(assoc_cpus) - 1); - - pr_cont("\n"); - } - - pr_emerg("%s.\n", EXT_ERR_MSG(regs->nbsl)); - - if (BUS_ERROR(ec) && nb_bus_decoder) - nb_bus_decoder(node_id, regs); -} -EXPORT_SYMBOL_GPL(amd_decode_nb_mce); - -static void amd_decode_fr_mce(u64 mc5_status) -{ - /* we have only one error signature so match all fields at once. */ - if ((mc5_status & 0xffff) == 0x0f0f) - pr_emerg(" FR Error: CPU Watchdog timer expire.\n"); - else - pr_warning("Corrupted FR MCE info?\n"); -} - -static inline void amd_decode_err_code(unsigned int ec) -{ - if (TLB_ERROR(ec)) { - pr_emerg("Transaction: %s, Cache Level %s\n", - TT_MSG(ec), LL_MSG(ec)); - } else if (MEM_ERROR(ec)) { - pr_emerg("Transaction: %s, Type: %s, Cache Level: %s", - RRRR_MSG(ec), TT_MSG(ec), LL_MSG(ec)); - } else if (BUS_ERROR(ec)) { - pr_emerg("Transaction type: %s(%s), %s, Cache Level: %s, " - "Participating Processor: %s\n", - RRRR_MSG(ec), II_MSG(ec), TO_MSG(ec), LL_MSG(ec), - PP_MSG(ec)); - } else - pr_warning("Huh? Unknown MCE error 0x%x\n", ec); -} - -static int amd_decode_mce(struct notifier_block *nb, unsigned long val, - void *data) -{ - struct mce *m = (struct mce *)data; - struct err_regs regs; - int node, ecc; - - pr_emerg("MC%d_STATUS: ", m->bank); - - pr_cont("%sorrected error, other errors lost: %s, " - "CPU context corrupt: %s", - ((m->status & MCI_STATUS_UC) ? "Unc" : "C"), - ((m->status & MCI_STATUS_OVER) ? "yes" : "no"), - ((m->status & MCI_STATUS_PCC) ? "yes" : "no")); - - /* do the two bits[14:13] together */ - ecc = (m->status >> 45) & 0x3; - if (ecc) - pr_cont(", %sECC Error", ((ecc == 2) ? "C" : "U")); - - pr_cont("\n"); - - switch (m->bank) { - case 0: - amd_decode_dc_mce(m->status); - break; - - case 1: - amd_decode_ic_mce(m->status); - break; - - case 2: - amd_decode_bu_mce(m->status); - break; - - case 3: - amd_decode_ls_mce(m->status); - break; - - case 4: - regs.nbsl = (u32) m->status; - regs.nbsh = (u32)(m->status >> 32); - regs.nbeal = (u32) m->addr; - regs.nbeah = (u32)(m->addr >> 32); - node = amd_get_nb_id(m->extcpu); - - amd_decode_nb_mce(node, ®s, 1); - break; - - case 5: - amd_decode_fr_mce(m->status); - break; - - default: - break; - } - - amd_decode_err_code(m->status & 0xffff); - - return NOTIFY_STOP; -} - -static struct notifier_block amd_mce_dec_nb = { - .notifier_call = amd_decode_mce, -}; - -static int __init mce_amd_init(void) -{ - /* - * We can decode MCEs for K8, F10h and F11h CPUs: - */ - if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) - return 0; - - if (boot_cpu_data.x86 < 0xf || boot_cpu_data.x86 > 0x11) - return 0; - - atomic_notifier_chain_register(&x86_mce_decoder_chain, &amd_mce_dec_nb); - - return 0; -} -early_initcall(mce_amd_init); - -#ifdef MODULE -static void __exit mce_amd_exit(void) -{ - atomic_notifier_chain_unregister(&x86_mce_decoder_chain, &amd_mce_dec_nb); -} - -MODULE_DESCRIPTION("AMD MCE decoder"); -MODULE_ALIAS("edac-mce-amd"); -MODULE_LICENSE("GPL"); -module_exit(mce_amd_exit); -#endif diff --git a/drivers/edac/edac_module.c b/drivers/edac/edac_module.c index 7e1374afd967..be4b075c3098 100644 --- a/drivers/edac/edac_module.c +++ b/drivers/edac/edac_module.c @@ -27,15 +27,6 @@ EXPORT_SYMBOL_GPL(edac_debug_level); struct workqueue_struct *edac_workqueue; /* - * sysfs object: /sys/devices/system/edac - * need to export to other files in this modules - */ -static struct sysdev_class edac_class = { - .name = "edac", -}; -static int edac_class_valid; - -/* * edac_op_state_to_string() */ char *edac_op_state_to_string(int opstate) @@ -55,60 +46,6 @@ char *edac_op_state_to_string(int opstate) } /* - * edac_get_edac_class() - * - * return pointer to the edac class of 'edac' - */ -struct sysdev_class *edac_get_edac_class(void) -{ - struct sysdev_class *classptr = NULL; - - if (edac_class_valid) - classptr = &edac_class; - - return classptr; -} - -/* - * edac_register_sysfs_edac_name() - * - * register the 'edac' into /sys/devices/system - * - * return: - * 0 success - * !0 error - */ -static int edac_register_sysfs_edac_name(void) -{ - int err; - - /* create the /sys/devices/system/edac directory */ - err = sysdev_class_register(&edac_class); - - if (err) { - debugf1("%s() error=%d\n", __func__, err); - return err; - } - - edac_class_valid = 1; - return 0; -} - -/* - * sysdev_class_unregister() - * - * unregister the 'edac' from /sys/devices/system - */ -static void edac_unregister_sysfs_edac_name(void) -{ - /* only if currently registered, then unregister it */ - if (edac_class_valid) - sysdev_class_unregister(&edac_class); - - edac_class_valid = 0; -} - -/* * edac_workqueue_setup * initialize the edac work queue for polling operations */ @@ -154,21 +91,11 @@ static int __init edac_init(void) edac_pci_clear_parity_errors(); /* - * perform the registration of the /sys/devices/system/edac class object - */ - if (edac_register_sysfs_edac_name()) { - edac_printk(KERN_ERR, EDAC_MC, - "Error initializing 'edac' kobject\n"); - err = -ENODEV; - goto error; - } - - /* * now set up the mc_kset under the edac class object */ err = edac_sysfs_setup_mc_kset(); if (err) - goto sysfs_setup_fail; + goto error; /* Setup/Initialize the workq for this core */ err = edac_workqueue_setup(); @@ -183,9 +110,6 @@ static int __init edac_init(void) workq_fail: edac_sysfs_teardown_mc_kset(); -sysfs_setup_fail: - edac_unregister_sysfs_edac_name(); - error: return err; } @@ -201,7 +125,6 @@ static void __exit edac_exit(void) /* tear down the various subsystems */ edac_workqueue_teardown(); edac_sysfs_teardown_mc_kset(); - edac_unregister_sysfs_edac_name(); } /* diff --git a/drivers/edac/edac_module.h b/drivers/edac/edac_module.h index 233d4798c3aa..17aabb7b90ec 100644 --- a/drivers/edac/edac_module.h +++ b/drivers/edac/edac_module.h @@ -42,7 +42,6 @@ extern void edac_device_unregister_sysfs_main_kobj( struct edac_device_ctl_info *edac_dev); extern int edac_device_create_sysfs(struct edac_device_ctl_info *edac_dev); extern void edac_device_remove_sysfs(struct edac_device_ctl_info *edac_dev); -extern struct sysdev_class *edac_get_edac_class(void); /* edac core workqueue: single CPU mode */ extern struct workqueue_struct *edac_workqueue; diff --git a/drivers/edac/edac_pci_sysfs.c b/drivers/edac/edac_pci_sysfs.c index c39697df9cb4..023b01cb5175 100644 --- a/drivers/edac/edac_pci_sysfs.c +++ b/drivers/edac/edac_pci_sysfs.c @@ -7,7 +7,7 @@ * */ #include <linux/module.h> -#include <linux/sysdev.h> +#include <linux/edac.h> #include <linux/slab.h> #include <linux/ctype.h> @@ -354,7 +354,7 @@ static int edac_pci_main_kobj_setup(void) /* First time, so create the main kobject and its * controls and atributes */ - edac_class = edac_get_edac_class(); + edac_class = edac_get_sysfs_class(); if (edac_class == NULL) { debugf1("%s() no edac_class\n", __func__); err = -ENODEV; @@ -368,7 +368,7 @@ static int edac_pci_main_kobj_setup(void) if (!try_module_get(THIS_MODULE)) { debugf1("%s() try_module_get() failed\n", __func__); err = -ENODEV; - goto decrement_count_fail; + goto mod_get_fail; } edac_pci_top_main_kobj = kzalloc(sizeof(struct kobject), GFP_KERNEL); @@ -403,6 +403,9 @@ kobject_init_and_add_fail: kzalloc_fail: module_put(THIS_MODULE); +mod_get_fail: + edac_put_sysfs_class(); + decrement_count_fail: /* if are on this error exit, nothing to tear down */ atomic_dec(&edac_pci_sysfs_refcount); @@ -429,6 +432,7 @@ static void edac_pci_main_kobj_teardown(void) __func__); kobject_put(edac_pci_top_main_kobj); } + edac_put_sysfs_class(); } /* diff --git a/drivers/edac/edac_stub.c b/drivers/edac/edac_stub.c index 20b428aa155e..aab970760b75 100644 --- a/drivers/edac/edac_stub.c +++ b/drivers/edac/edac_stub.c @@ -3,10 +3,13 @@ * * Author: Dave Jiang <djiang@mvista.com> * - * 2007 (c) MontaVista Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. + * 2007 (c) MontaVista Software, Inc. + * 2010 (c) Advanced Micro Devices Inc. + * Borislav Petkov <borislav.petkov@amd.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. * */ #include <linux/module.h> @@ -23,6 +26,8 @@ EXPORT_SYMBOL_GPL(edac_handlers); int edac_err_assert = 0; EXPORT_SYMBOL_GPL(edac_err_assert); +static atomic_t edac_class_valid = ATOMIC_INIT(0); + /* * called to determine if there is an EDAC driver interested in * knowing an event (such as NMI) occurred @@ -44,3 +49,41 @@ void edac_atomic_assert_error(void) edac_err_assert++; } EXPORT_SYMBOL_GPL(edac_atomic_assert_error); + +/* + * sysfs object: /sys/devices/system/edac + * need to export to other files + */ +struct sysdev_class edac_class = { + .name = "edac", +}; +EXPORT_SYMBOL_GPL(edac_class); + +/* return pointer to the 'edac' node in sysfs */ +struct sysdev_class *edac_get_sysfs_class(void) +{ + int err = 0; + + if (atomic_read(&edac_class_valid)) + goto out; + + /* create the /sys/devices/system/edac directory */ + err = sysdev_class_register(&edac_class); + if (err) { + printk(KERN_ERR "Error registering toplevel EDAC sysfs dir\n"); + return NULL; + } + +out: + atomic_inc(&edac_class_valid); + return &edac_class; +} +EXPORT_SYMBOL_GPL(edac_get_sysfs_class); + +void edac_put_sysfs_class(void) +{ + /* last user unregisters it */ + if (atomic_dec_and_test(&edac_class_valid)) + sysdev_class_unregister(&edac_class); +} +EXPORT_SYMBOL_GPL(edac_put_sysfs_class); diff --git a/drivers/edac/mce_amd.c b/drivers/edac/mce_amd.c new file mode 100644 index 000000000000..c0181093b490 --- /dev/null +++ b/drivers/edac/mce_amd.c @@ -0,0 +1,680 @@ +#include <linux/module.h> +#include <linux/slab.h> + +#include "mce_amd.h" + +static struct amd_decoder_ops *fam_ops; + +static u8 nb_err_cpumask = 0xf; + +static bool report_gart_errors; +static void (*nb_bus_decoder)(int node_id, struct mce *m, u32 nbcfg); + +void amd_report_gart_errors(bool v) +{ + report_gart_errors = v; +} +EXPORT_SYMBOL_GPL(amd_report_gart_errors); + +void amd_register_ecc_decoder(void (*f)(int, struct mce *, u32)) +{ + nb_bus_decoder = f; +} +EXPORT_SYMBOL_GPL(amd_register_ecc_decoder); + +void amd_unregister_ecc_decoder(void (*f)(int, struct mce *, u32)) +{ + if (nb_bus_decoder) { + WARN_ON(nb_bus_decoder != f); + + nb_bus_decoder = NULL; + } +} +EXPORT_SYMBOL_GPL(amd_unregister_ecc_decoder); + +/* + * string representation for the different MCA reported error types, see F3x48 + * or MSR0000_0411. + */ + +/* transaction type */ +const char *tt_msgs[] = { "INSN", "DATA", "GEN", "RESV" }; +EXPORT_SYMBOL_GPL(tt_msgs); + +/* cache level */ +const char *ll_msgs[] = { "RESV", "L1", "L2", "L3/GEN" }; +EXPORT_SYMBOL_GPL(ll_msgs); + +/* memory transaction type */ +const char *rrrr_msgs[] = { + "GEN", "RD", "WR", "DRD", "DWR", "IRD", "PRF", "EV", "SNP" +}; +EXPORT_SYMBOL_GPL(rrrr_msgs); + +/* participating processor */ +const char *pp_msgs[] = { "SRC", "RES", "OBS", "GEN" }; +EXPORT_SYMBOL_GPL(pp_msgs); + +/* request timeout */ +const char *to_msgs[] = { "no timeout", "timed out" }; +EXPORT_SYMBOL_GPL(to_msgs); + +/* memory or i/o */ +const char *ii_msgs[] = { "MEM", "RESV", "IO", "GEN" }; +EXPORT_SYMBOL_GPL(ii_msgs); + +static const char *f10h_nb_mce_desc[] = { + "HT link data error", + "Protocol error (link, L3, probe filter, etc.)", + "Parity error in NB-internal arrays", + "Link Retry due to IO link transmission error", + "L3 ECC data cache error", + "ECC error in L3 cache tag", + "L3 LRU parity bits error", + "ECC Error in the Probe Filter directory" +}; + +static bool f12h_dc_mce(u16 ec) +{ + bool ret = false; + + if (MEM_ERROR(ec)) { + u8 ll = ec & 0x3; + ret = true; + + if (ll == LL_L2) + pr_cont("during L1 linefill from L2.\n"); + else if (ll == LL_L1) + pr_cont("Data/Tag %s error.\n", RRRR_MSG(ec)); + else + ret = false; + } + return ret; +} + +static bool f10h_dc_mce(u16 ec) +{ + u8 r4 = (ec >> 4) & 0xf; + u8 ll = ec & 0x3; + + if (r4 == R4_GEN && ll == LL_L1) { + pr_cont("during data scrub.\n"); + return true; + } + return f12h_dc_mce(ec); +} + +static bool k8_dc_mce(u16 ec) +{ + if (BUS_ERROR(ec)) { + pr_cont("during system linefill.\n"); + return true; + } + + return f10h_dc_mce(ec); +} + +static bool f14h_dc_mce(u16 ec) +{ + u8 r4 = (ec >> 4) & 0xf; + u8 ll = ec & 0x3; + u8 tt = (ec >> 2) & 0x3; + u8 ii = tt; + bool ret = true; + + if (MEM_ERROR(ec)) { + + if (tt != TT_DATA || ll != LL_L1) + return false; + + switch (r4) { + case R4_DRD: + case R4_DWR: + pr_cont("Data/Tag parity error due to %s.\n", + (r4 == R4_DRD ? "load/hw prf" : "store")); + break; + case R4_EVICT: + pr_cont("Copyback parity error on a tag miss.\n"); + break; + case R4_SNOOP: + pr_cont("Tag parity error during snoop.\n"); + break; + default: + ret = false; + } + } else if (BUS_ERROR(ec)) { + + if ((ii != II_MEM && ii != II_IO) || ll != LL_LG) + return false; + + pr_cont("System read data error on a "); + + switch (r4) { + case R4_RD: + pr_cont("TLB reload.\n"); + break; + case R4_DWR: + pr_cont("store.\n"); + break; + case R4_DRD: + pr_cont("load.\n"); + break; + default: + ret = false; + } + } else { + ret = false; + } + + return ret; +} + +static void amd_decode_dc_mce(struct mce *m) +{ + u16 ec = m->status & 0xffff; + u8 xec = (m->status >> 16) & 0xf; + + pr_emerg(HW_ERR "Data Cache Error: "); + + /* TLB error signatures are the same across families */ + if (TLB_ERROR(ec)) { + u8 tt = (ec >> 2) & 0x3; + + if (tt == TT_DATA) { + pr_cont("%s TLB %s.\n", LL_MSG(ec), + (xec ? "multimatch" : "parity error")); + return; + } + else + goto wrong_dc_mce; + } + + if (!fam_ops->dc_mce(ec)) + goto wrong_dc_mce; + + return; + +wrong_dc_mce: + pr_emerg(HW_ERR "Corrupted DC MCE info?\n"); +} + +static bool k8_ic_mce(u16 ec) +{ + u8 ll = ec & 0x3; + u8 r4 = (ec >> 4) & 0xf; + bool ret = true; + + if (!MEM_ERROR(ec)) + return false; + + if (ll == 0x2) + pr_cont("during a linefill from L2.\n"); + else if (ll == 0x1) { + switch (r4) { + case R4_IRD: + pr_cont("Parity error during data load.\n"); + break; + + case R4_EVICT: + pr_cont("Copyback Parity/Victim error.\n"); + break; + + case R4_SNOOP: + pr_cont("Tag Snoop error.\n"); + break; + + default: + ret = false; + break; + } + } else + ret = false; + + return ret; +} + +static bool f14h_ic_mce(u16 ec) +{ + u8 ll = ec & 0x3; + u8 tt = (ec >> 2) & 0x3; + u8 r4 = (ec >> 4) & 0xf; + bool ret = true; + + if (MEM_ERROR(ec)) { + if (tt != 0 || ll != 1) + ret = false; + + if (r4 == R4_IRD) + pr_cont("Data/tag array parity error for a tag hit.\n"); + else if (r4 == R4_SNOOP) + pr_cont("Tag error during snoop/victimization.\n"); + else + ret = false; + } + return ret; +} + +static void amd_decode_ic_mce(struct mce *m) +{ + u16 ec = m->status & 0xffff; + u8 xec = (m->status >> 16) & 0xf; + + pr_emerg(HW_ERR "Instruction Cache Error: "); + + if (TLB_ERROR(ec)) + pr_cont("%s TLB %s.\n", LL_MSG(ec), + (xec ? "multimatch" : "parity error")); + else if (BUS_ERROR(ec)) { + bool k8 = (boot_cpu_data.x86 == 0xf && (m->status & BIT_64(58))); + + pr_cont("during %s.\n", (k8 ? "system linefill" : "NB data read")); + } else if (fam_ops->ic_mce(ec)) + ; + else + pr_emerg(HW_ERR "Corrupted IC MCE info?\n"); +} + +static void amd_decode_bu_mce(struct mce *m) +{ + u32 ec = m->status & 0xffff; + u32 xec = (m->status >> 16) & 0xf; + + pr_emerg(HW_ERR "Bus Unit Error"); + + if (xec == 0x1) + pr_cont(" in the write data buffers.\n"); + else if (xec == 0x3) + pr_cont(" in the victim data buffers.\n"); + else if (xec == 0x2 && MEM_ERROR(ec)) + pr_cont(": %s error in the L2 cache tags.\n", RRRR_MSG(ec)); + else if (xec == 0x0) { + if (TLB_ERROR(ec)) + pr_cont(": %s error in a Page Descriptor Cache or " + "Guest TLB.\n", TT_MSG(ec)); + else if (BUS_ERROR(ec)) + pr_cont(": %s/ECC error in data read from NB: %s.\n", + RRRR_MSG(ec), PP_MSG(ec)); + else if (MEM_ERROR(ec)) { + u8 rrrr = (ec >> 4) & 0xf; + + if (rrrr >= 0x7) + pr_cont(": %s error during data copyback.\n", + RRRR_MSG(ec)); + else if (rrrr <= 0x1) + pr_cont(": %s parity/ECC error during data " + "access from L2.\n", RRRR_MSG(ec)); + else + goto wrong_bu_mce; + } else + goto wrong_bu_mce; + } else + goto wrong_bu_mce; + + return; + +wrong_bu_mce: + pr_emerg(HW_ERR "Corrupted BU MCE info?\n"); +} + +static void amd_decode_ls_mce(struct mce *m) +{ + u16 ec = m->status & 0xffff; + u8 xec = (m->status >> 16) & 0xf; + + if (boot_cpu_data.x86 == 0x14) { + pr_emerg("You shouldn't be seeing an LS MCE on this cpu family," + " please report on LKML.\n"); + return; + } + + pr_emerg(HW_ERR "Load Store Error"); + + if (xec == 0x0) { + u8 r4 = (ec >> 4) & 0xf; + + if (!BUS_ERROR(ec) || (r4 != R4_DRD && r4 != R4_DWR)) + goto wrong_ls_mce; + + pr_cont(" during %s.\n", RRRR_MSG(ec)); + } else + goto wrong_ls_mce; + + return; + +wrong_ls_mce: + pr_emerg(HW_ERR "Corrupted LS MCE info?\n"); +} + +static bool k8_nb_mce(u16 ec, u8 xec) +{ + bool ret = true; + + switch (xec) { + case 0x1: + pr_cont("CRC error detected on HT link.\n"); + break; + + case 0x5: + pr_cont("Invalid GART PTE entry during GART table walk.\n"); + break; + + case 0x6: + pr_cont("Unsupported atomic RMW received from an IO link.\n"); + break; + + case 0x0: + case 0x8: + if (boot_cpu_data.x86 == 0x11) + return false; + + pr_cont("DRAM ECC error detected on the NB.\n"); + break; + + case 0xd: + pr_cont("Parity error on the DRAM addr/ctl signals.\n"); + break; + + default: + ret = false; + break; + } + + return ret; +} + +static bool f10h_nb_mce(u16 ec, u8 xec) +{ + bool ret = true; + u8 offset = 0; + + if (k8_nb_mce(ec, xec)) + return true; + + switch(xec) { + case 0xa ... 0xc: + offset = 10; + break; + + case 0xe: + offset = 11; + break; + + case 0xf: + if (TLB_ERROR(ec)) + pr_cont("GART Table Walk data error.\n"); + else if (BUS_ERROR(ec)) + pr_cont("DMA Exclusion Vector Table Walk error.\n"); + else + ret = false; + + goto out; + break; + + case 0x1c ... 0x1f: + offset = 24; + break; + + default: + ret = false; + + goto out; + break; + } + + pr_cont("%s.\n", f10h_nb_mce_desc[xec - offset]); + +out: + return ret; +} + +static bool nb_noop_mce(u16 ec, u8 xec) +{ + return false; +} + +void amd_decode_nb_mce(int node_id, struct mce *m, u32 nbcfg) +{ + u8 xec = (m->status >> 16) & 0x1f; + u16 ec = m->status & 0xffff; + u32 nbsh = (u32)(m->status >> 32); + + pr_emerg(HW_ERR "Northbridge Error, node %d: ", node_id); + + /* + * F10h, revD can disable ErrCpu[3:0] so check that first and also the + * value encoding has changed so interpret those differently + */ + if ((boot_cpu_data.x86 == 0x10) && + (boot_cpu_data.x86_model > 7)) { + if (nbsh & K8_NBSH_ERR_CPU_VAL) + pr_cont(", core: %u", (u8)(nbsh & nb_err_cpumask)); + } else { + u8 assoc_cpus = nbsh & nb_err_cpumask; + + if (assoc_cpus > 0) + pr_cont(", core: %d", fls(assoc_cpus) - 1); + } + + switch (xec) { + case 0x2: + pr_cont("Sync error (sync packets on HT link detected).\n"); + return; + + case 0x3: + pr_cont("HT Master abort.\n"); + return; + + case 0x4: + pr_cont("HT Target abort.\n"); + return; + + case 0x7: + pr_cont("NB Watchdog timeout.\n"); + return; + + case 0x9: + pr_cont("SVM DMA Exclusion Vector error.\n"); + return; + + default: + break; + } + + if (!fam_ops->nb_mce(ec, xec)) + goto wrong_nb_mce; + + if (boot_cpu_data.x86 == 0xf || boot_cpu_data.x86 == 0x10) + if ((xec == 0x8 || xec == 0x0) && nb_bus_decoder) + nb_bus_decoder(node_id, m, nbcfg); + + return; + +wrong_nb_mce: + pr_emerg(HW_ERR "Corrupted NB MCE info?\n"); +} +EXPORT_SYMBOL_GPL(amd_decode_nb_mce); + +static void amd_decode_fr_mce(struct mce *m) +{ + if (boot_cpu_data.x86 == 0xf || + boot_cpu_data.x86 == 0x11) + goto wrong_fr_mce; + + /* we have only one error signature so match all fields at once. */ + if ((m->status & 0xffff) == 0x0f0f) { + pr_emerg(HW_ERR "FR Error: CPU Watchdog timer expire.\n"); + return; + } + +wrong_fr_mce: + pr_emerg(HW_ERR "Corrupted FR MCE info?\n"); +} + +static inline void amd_decode_err_code(u16 ec) +{ + if (TLB_ERROR(ec)) { + pr_emerg(HW_ERR "Transaction: %s, Cache Level: %s\n", + TT_MSG(ec), LL_MSG(ec)); + } else if (MEM_ERROR(ec)) { + pr_emerg(HW_ERR "Transaction: %s, Type: %s, Cache Level: %s\n", + RRRR_MSG(ec), TT_MSG(ec), LL_MSG(ec)); + } else if (BUS_ERROR(ec)) { + pr_emerg(HW_ERR "Transaction: %s (%s), %s, Cache Level: %s, " + "Participating Processor: %s\n", + RRRR_MSG(ec), II_MSG(ec), TO_MSG(ec), LL_MSG(ec), + PP_MSG(ec)); + } else + pr_emerg(HW_ERR "Huh? Unknown MCE error 0x%x\n", ec); +} + +/* + * Filter out unwanted MCE signatures here. + */ +static bool amd_filter_mce(struct mce *m) +{ + u8 xec = (m->status >> 16) & 0x1f; + + /* + * NB GART TLB error reporting is disabled by default. + */ + if (m->bank == 4 && xec == 0x5 && !report_gart_errors) + return true; + + return false; +} + +int amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data) +{ + struct mce *m = (struct mce *)data; + int node, ecc; + + if (amd_filter_mce(m)) + return NOTIFY_STOP; + + pr_emerg(HW_ERR "MC%d_STATUS: ", m->bank); + + pr_cont("%sorrected error, other errors lost: %s, " + "CPU context corrupt: %s", + ((m->status & MCI_STATUS_UC) ? "Unc" : "C"), + ((m->status & MCI_STATUS_OVER) ? "yes" : "no"), + ((m->status & MCI_STATUS_PCC) ? "yes" : "no")); + + /* do the two bits[14:13] together */ + ecc = (m->status >> 45) & 0x3; + if (ecc) + pr_cont(", %sECC Error", ((ecc == 2) ? "C" : "U")); + + pr_cont("\n"); + + switch (m->bank) { + case 0: + amd_decode_dc_mce(m); + break; + + case 1: + amd_decode_ic_mce(m); + break; + + case 2: + amd_decode_bu_mce(m); + break; + + case 3: + amd_decode_ls_mce(m); + break; + + case 4: + node = amd_get_nb_id(m->extcpu); + amd_decode_nb_mce(node, m, 0); + break; + + case 5: + amd_decode_fr_mce(m); + break; + + default: + break; + } + + amd_decode_err_code(m->status & 0xffff); + + return NOTIFY_STOP; +} +EXPORT_SYMBOL_GPL(amd_decode_mce); + +static struct notifier_block amd_mce_dec_nb = { + .notifier_call = amd_decode_mce, +}; + +static int __init mce_amd_init(void) +{ + if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) + return 0; + + if ((boot_cpu_data.x86 < 0xf || boot_cpu_data.x86 > 0x12) && + (boot_cpu_data.x86 != 0x14 || boot_cpu_data.x86_model > 0xf)) + return 0; + + fam_ops = kzalloc(sizeof(struct amd_decoder_ops), GFP_KERNEL); + if (!fam_ops) + return -ENOMEM; + + switch (boot_cpu_data.x86) { + case 0xf: + fam_ops->dc_mce = k8_dc_mce; + fam_ops->ic_mce = k8_ic_mce; + fam_ops->nb_mce = k8_nb_mce; + break; + + case 0x10: + fam_ops->dc_mce = f10h_dc_mce; + fam_ops->ic_mce = k8_ic_mce; + fam_ops->nb_mce = f10h_nb_mce; + break; + + case 0x11: + fam_ops->dc_mce = k8_dc_mce; + fam_ops->ic_mce = k8_ic_mce; + fam_ops->nb_mce = f10h_nb_mce; + break; + + case 0x12: + fam_ops->dc_mce = f12h_dc_mce; + fam_ops->ic_mce = k8_ic_mce; + fam_ops->nb_mce = nb_noop_mce; + break; + + case 0x14: + nb_err_cpumask = 0x3; + fam_ops->dc_mce = f14h_dc_mce; + fam_ops->ic_mce = f14h_ic_mce; + fam_ops->nb_mce = nb_noop_mce; + break; + + default: + printk(KERN_WARNING "Huh? What family is that: %d?!\n", + boot_cpu_data.x86); + kfree(fam_ops); + return -EINVAL; + } + + pr_info("MCE: In-kernel MCE decoding enabled.\n"); + + atomic_notifier_chain_register(&x86_mce_decoder_chain, &amd_mce_dec_nb); + + return 0; +} +early_initcall(mce_amd_init); + +#ifdef MODULE +static void __exit mce_amd_exit(void) +{ + atomic_notifier_chain_unregister(&x86_mce_decoder_chain, &amd_mce_dec_nb); + kfree(fam_ops); +} + +MODULE_DESCRIPTION("AMD MCE decoder"); +MODULE_ALIAS("edac-mce-amd"); +MODULE_LICENSE("GPL"); +module_exit(mce_amd_exit); +#endif diff --git a/drivers/edac/edac_mce_amd.h b/drivers/edac/mce_amd.h index df23ee065f79..35f6e0e3b297 100644 --- a/drivers/edac/edac_mce_amd.h +++ b/drivers/edac/mce_amd.h @@ -1,11 +1,14 @@ #ifndef _EDAC_MCE_AMD_H #define _EDAC_MCE_AMD_H +#include <linux/notifier.h> + #include <asm/mce.h> +#define BIT_64(n) (U64_C(1) << (n)) + #define ERROR_CODE(x) ((x) & 0xffff) #define EXT_ERROR_CODE(x) (((x) >> 16) & 0x1f) -#define EXT_ERR_MSG(x) ext_msgs[EXT_ERROR_CODE(x)] #define LOW_SYNDROME(x) (((x) >> 15) & 0xff) #define HIGH_SYNDROME(x) (((x) >> 24) & 0xff) @@ -20,13 +23,14 @@ #define II_MSG(x) ii_msgs[II(x)] #define LL(x) (((x) >> 0) & 0x3) #define LL_MSG(x) ll_msgs[LL(x)] -#define RRRR(x) (((x) >> 4) & 0xf) -#define RRRR_MSG(x) rrrr_msgs[RRRR(x)] #define TO(x) (((x) >> 8) & 0x1) #define TO_MSG(x) to_msgs[TO(x)] #define PP(x) (((x) >> 9) & 0x3) #define PP_MSG(x) pp_msgs[PP(x)] +#define RRRR(x) (((x) >> 4) & 0xf) +#define RRRR_MSG(x) ((RRRR(x) < 9) ? rrrr_msgs[RRRR(x)] : "Wrong R4!") + #define K8_NBSH 0x4C #define K8_NBSH_VALID_BIT BIT(31) @@ -41,13 +45,45 @@ #define K8_NBSH_UECC BIT(13) #define K8_NBSH_ERR_SCRUBER BIT(8) +enum tt_ids { + TT_INSTR = 0, + TT_DATA, + TT_GEN, + TT_RESV, +}; + +enum ll_ids { + LL_RESV = 0, + LL_L1, + LL_L2, + LL_LG, +}; + +enum ii_ids { + II_MEM = 0, + II_RESV, + II_IO, + II_GEN, +}; + +enum rrrr_ids { + R4_GEN = 0, + R4_RD, + R4_WR, + R4_DRD, + R4_DWR, + R4_IRD, + R4_PREF, + R4_EVICT, + R4_SNOOP, +}; + extern const char *tt_msgs[]; extern const char *ll_msgs[]; extern const char *rrrr_msgs[]; extern const char *pp_msgs[]; extern const char *to_msgs[]; extern const char *ii_msgs[]; -extern const char *ext_msgs[]; /* * relevant NB regs @@ -60,10 +96,19 @@ struct err_regs { u32 nbeal; }; +/* + * per-family decoder ops + */ +struct amd_decoder_ops { + bool (*dc_mce)(u16); + bool (*ic_mce)(u16); + bool (*nb_mce)(u16, u8); +}; void amd_report_gart_errors(bool); -void amd_register_ecc_decoder(void (*f)(int, struct err_regs *)); -void amd_unregister_ecc_decoder(void (*f)(int, struct err_regs *)); -void amd_decode_nb_mce(int, struct err_regs *, int); +void amd_register_ecc_decoder(void (*f)(int, struct mce *, u32)); +void amd_unregister_ecc_decoder(void (*f)(int, struct mce *, u32)); +void amd_decode_nb_mce(int, struct mce *, u32); +int amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data); #endif /* _EDAC_MCE_AMD_H */ diff --git a/drivers/edac/mce_amd_inj.c b/drivers/edac/mce_amd_inj.c new file mode 100644 index 000000000000..8d0688f36d4c --- /dev/null +++ b/drivers/edac/mce_amd_inj.c @@ -0,0 +1,171 @@ +/* + * A simple MCE injection facility for testing the MCE decoding code. This + * driver should be built as module so that it can be loaded on production + * kernels for testing purposes. + * + * This file may be distributed under the terms of the GNU General Public + * License version 2. + * + * Copyright (c) 2010: Borislav Petkov <borislav.petkov@amd.com> + * Advanced Micro Devices Inc. + */ + +#include <linux/kobject.h> +#include <linux/sysdev.h> +#include <linux/edac.h> +#include <asm/mce.h> + +#include "mce_amd.h" + +struct edac_mce_attr { + struct attribute attr; + ssize_t (*show) (struct kobject *kobj, struct edac_mce_attr *attr, char *buf); + ssize_t (*store)(struct kobject *kobj, struct edac_mce_attr *attr, + const char *buf, size_t count); +}; + +#define EDAC_MCE_ATTR(_name, _mode, _show, _store) \ +static struct edac_mce_attr mce_attr_##_name = __ATTR(_name, _mode, _show, _store) + +static struct kobject *mce_kobj; + +/* + * Collect all the MCi_XXX settings + */ +static struct mce i_mce; + +#define MCE_INJECT_STORE(reg) \ +static ssize_t edac_inject_##reg##_store(struct kobject *kobj, \ + struct edac_mce_attr *attr, \ + const char *data, size_t count)\ +{ \ + int ret = 0; \ + unsigned long value; \ + \ + ret = strict_strtoul(data, 16, &value); \ + if (ret < 0) \ + printk(KERN_ERR "Error writing MCE " #reg " field.\n"); \ + \ + i_mce.reg = value; \ + \ + return count; \ +} + +MCE_INJECT_STORE(status); +MCE_INJECT_STORE(misc); +MCE_INJECT_STORE(addr); + +#define MCE_INJECT_SHOW(reg) \ +static ssize_t edac_inject_##reg##_show(struct kobject *kobj, \ + struct edac_mce_attr *attr, \ + char *buf) \ +{ \ + return sprintf(buf, "0x%016llx\n", i_mce.reg); \ +} + +MCE_INJECT_SHOW(status); +MCE_INJECT_SHOW(misc); +MCE_INJECT_SHOW(addr); + +EDAC_MCE_ATTR(status, 0644, edac_inject_status_show, edac_inject_status_store); +EDAC_MCE_ATTR(misc, 0644, edac_inject_misc_show, edac_inject_misc_store); +EDAC_MCE_ATTR(addr, 0644, edac_inject_addr_show, edac_inject_addr_store); + +/* + * This denotes into which bank we're injecting and triggers + * the injection, at the same time. + */ +static ssize_t edac_inject_bank_store(struct kobject *kobj, + struct edac_mce_attr *attr, + const char *data, size_t count) +{ + int ret = 0; + unsigned long value; + + ret = strict_strtoul(data, 10, &value); + if (ret < 0) { + printk(KERN_ERR "Invalid bank value!\n"); + return -EINVAL; + } + + if (value > 5) { + printk(KERN_ERR "Non-existant MCE bank: %lu\n", value); + return -EINVAL; + } + + i_mce.bank = value; + + amd_decode_mce(NULL, 0, &i_mce); + + return count; +} + +static ssize_t edac_inject_bank_show(struct kobject *kobj, + struct edac_mce_attr *attr, char *buf) +{ + return sprintf(buf, "%d\n", i_mce.bank); +} + +EDAC_MCE_ATTR(bank, 0644, edac_inject_bank_show, edac_inject_bank_store); + +static struct edac_mce_attr *sysfs_attrs[] = { &mce_attr_status, &mce_attr_misc, + &mce_attr_addr, &mce_attr_bank +}; + +static int __init edac_init_mce_inject(void) +{ + struct sysdev_class *edac_class = NULL; + int i, err = 0; + + edac_class = edac_get_sysfs_class(); + if (!edac_class) + return -EINVAL; + + mce_kobj = kobject_create_and_add("mce", &edac_class->kset.kobj); + if (!mce_kobj) { + printk(KERN_ERR "Error creating a mce kset.\n"); + err = -ENOMEM; + goto err_mce_kobj; + } + + for (i = 0; i < ARRAY_SIZE(sysfs_attrs); i++) { + err = sysfs_create_file(mce_kobj, &sysfs_attrs[i]->attr); + if (err) { + printk(KERN_ERR "Error creating %s in sysfs.\n", + sysfs_attrs[i]->attr.name); + goto err_sysfs_create; + } + } + return 0; + +err_sysfs_create: + while (i-- >= 0) + sysfs_remove_file(mce_kobj, &sysfs_attrs[i]->attr); + + kobject_del(mce_kobj); + +err_mce_kobj: + edac_put_sysfs_class(); + + return err; +} + +static void __exit edac_exit_mce_inject(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(sysfs_attrs); i++) + sysfs_remove_file(mce_kobj, &sysfs_attrs[i]->attr); + + kobject_del(mce_kobj); + + edac_put_sysfs_class(); +} + +module_init(edac_init_mce_inject); +module_exit(edac_exit_mce_inject); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Borislav Petkov <borislav.petkov@amd.com>"); +MODULE_AUTHOR("AMD Inc."); +MODULE_DESCRIPTION("MCE injection facility for testing MCE decoding"); diff --git a/drivers/firewire/nosy.c b/drivers/firewire/nosy.c index 8528b10763ed..bf184fb59a5e 100644 --- a/drivers/firewire/nosy.c +++ b/drivers/firewire/nosy.c @@ -405,6 +405,7 @@ static const struct file_operations nosy_ops = { .poll = nosy_poll, .open = nosy_open, .release = nosy_release, + .llseek = noop_llseek, }; #define PHY_PACKET_SIZE 12 /* 1 payload, 1 inverse, 1 ack = 3 quadlets */ diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index 280c9b5ad9e3..88a3ae6cd023 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -125,7 +125,7 @@ config ISCSI_IBFT_FIND config ISCSI_IBFT tristate "iSCSI Boot Firmware Table Attributes module" select ISCSI_BOOT_SYSFS - depends on ISCSI_IBFT_FIND && SCSI + depends on ISCSI_IBFT_FIND && SCSI && SCSI_LOWLEVEL default n help This option enables support for detection and exposing of iSCSI diff --git a/drivers/gpio/tc35892-gpio.c b/drivers/gpio/tc35892-gpio.c index 1be6288780de..7e10c935a047 100644 --- a/drivers/gpio/tc35892-gpio.c +++ b/drivers/gpio/tc35892-gpio.c @@ -322,6 +322,9 @@ static int __devinit tc35892_gpio_probe(struct platform_device *pdev) goto out_freeirq; } + if (pdata->setup) + pdata->setup(tc35892, tc35892_gpio->chip.base); + platform_set_drvdata(pdev, tc35892_gpio); return 0; @@ -338,9 +341,14 @@ out_free: static int __devexit tc35892_gpio_remove(struct platform_device *pdev) { struct tc35892_gpio *tc35892_gpio = platform_get_drvdata(pdev); + struct tc35892 *tc35892 = tc35892_gpio->tc35892; + struct tc35892_gpio_platform_data *pdata = tc35892->pdata->gpio; int irq = platform_get_irq(pdev, 0); int ret; + if (pdata->remove) + pdata->remove(tc35892, tc35892_gpio->chip.base); + ret = gpiochip_remove(&tc35892_gpio->chip); if (ret < 0) { dev_err(tc35892_gpio->dev, diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 4cab0c6397e3..7af443672626 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -73,7 +73,8 @@ source "drivers/gpu/drm/radeon/Kconfig" config DRM_I810 tristate "Intel I810" - depends on DRM && AGP && AGP_INTEL + # BKL usage in order to avoid AB-BA deadlocks, may become BROKEN_ON_SMP + depends on DRM && AGP && AGP_INTEL && BKL help Choose this option if you have an Intel I810 graphics card. If M is selected, the module will be called i810. AGP support is required @@ -86,6 +87,8 @@ choice config DRM_I830 tristate "i830 driver" + # BKL usage in order to avoid AB-BA deadlocks, i830 may get removed + depends on BKL help Choose this option if you have a system that has Intel 830M, 845G, 852GM, 855GM or 865G integrated graphics. If M is selected, the diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 84da748555bc..ff6690f4fc87 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -284,7 +284,8 @@ EXPORT_SYMBOL(drm_exit); /** File operations structure */ static const struct file_operations drm_stub_fops = { .owner = THIS_MODULE, - .open = drm_stub_open + .open = drm_stub_open, + .llseek = noop_llseek, }; static int __init drm_core_init(void) diff --git a/drivers/gpu/drm/i810/i810_dma.c b/drivers/gpu/drm/i810/i810_dma.c index fb07e73581e8..ff33e53bbbf8 100644 --- a/drivers/gpu/drm/i810/i810_dma.c +++ b/drivers/gpu/drm/i810/i810_dma.c @@ -119,6 +119,7 @@ static const struct file_operations i810_buffer_fops = { .unlocked_ioctl = i810_ioctl, .mmap = i810_mmap_buffers, .fasync = drm_fasync, + .llseek = noop_llseek, }; static int i810_map_buffer(struct drm_buf *buf, struct drm_file *file_priv) diff --git a/drivers/gpu/drm/i810/i810_drv.c b/drivers/gpu/drm/i810/i810_drv.c index b4250b2cac1f..fe69914ce507 100644 --- a/drivers/gpu/drm/i810/i810_drv.c +++ b/drivers/gpu/drm/i810/i810_drv.c @@ -63,6 +63,7 @@ static struct drm_driver driver = { .mmap = drm_mmap, .poll = drm_poll, .fasync = drm_fasync, + .llseek = noop_llseek, }, .pci_driver = { diff --git a/drivers/gpu/drm/i830/i830_dma.c b/drivers/gpu/drm/i830/i830_dma.c index cc92c7e6236f..ca6f31ff0eec 100644 --- a/drivers/gpu/drm/i830/i830_dma.c +++ b/drivers/gpu/drm/i830/i830_dma.c @@ -121,6 +121,7 @@ static const struct file_operations i830_buffer_fops = { .unlocked_ioctl = i830_ioctl, .mmap = i830_mmap_buffers, .fasync = drm_fasync, + .llseek = noop_llseek, }; static int i830_map_buffer(struct drm_buf *buf, struct drm_file *file_priv) diff --git a/drivers/gpu/drm/i830/i830_drv.c b/drivers/gpu/drm/i830/i830_drv.c index a5c66aa82f0c..5b6298b24e24 100644 --- a/drivers/gpu/drm/i830/i830_drv.c +++ b/drivers/gpu/drm/i830/i830_drv.c @@ -74,6 +74,7 @@ static struct drm_driver driver = { .mmap = drm_mmap, .poll = drm_poll, .fasync = drm_fasync, + .llseek = noop_llseek, }, .pci_driver = { diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 5e43d7076789..048149748fdc 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -782,6 +782,7 @@ static const struct file_operations i915_wedged_fops = { .open = i915_wedged_open, .read = i915_wedged_read, .write = i915_wedged_write, + .llseek = default_llseek, }; /* As the drm_debugfs_init() routines are called before dev->dev_private is diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 6dbe14cc4f74..895ab896e336 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -548,6 +548,7 @@ static struct drm_driver driver = { #ifdef CONFIG_COMPAT .compat_ioctl = i915_compat_ioctl, #endif + .llseek = noop_llseek, }, .pci_driver = { diff --git a/drivers/gpu/drm/mga/mga_drv.c b/drivers/gpu/drm/mga/mga_drv.c index 26d0d8ced80d..ac64f0b0392e 100644 --- a/drivers/gpu/drm/mga/mga_drv.c +++ b/drivers/gpu/drm/mga/mga_drv.c @@ -75,6 +75,7 @@ static struct drm_driver driver = { #ifdef CONFIG_COMPAT .compat_ioctl = mga_compat_ioctl, #endif + .llseek = noop_llseek, }, .pci_driver = { .name = DRIVER_NAME, diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c index 1de5eb53e016..eb15345162a0 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.c +++ b/drivers/gpu/drm/nouveau/nouveau_drv.c @@ -393,6 +393,7 @@ static struct drm_driver driver = { #if defined(CONFIG_COMPAT) .compat_ioctl = nouveau_compat_ioctl, #endif + .llseek = noop_llseek, }, .pci_driver = { .name = DRIVER_NAME, diff --git a/drivers/gpu/drm/r128/r128_drv.c b/drivers/gpu/drm/r128/r128_drv.c index 1e2971f13aa1..d42c76c23714 100644 --- a/drivers/gpu/drm/r128/r128_drv.c +++ b/drivers/gpu/drm/r128/r128_drv.c @@ -71,6 +71,7 @@ static struct drm_driver driver = { #ifdef CONFIG_COMPAT .compat_ioctl = r128_compat_ioctl, #endif + .llseek = noop_llseek, }, .pci_driver = { .name = DRIVER_NAME, diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 795403b0e2cd..29c1237c2e7b 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -219,6 +219,7 @@ static struct drm_driver driver_old = { #ifdef CONFIG_COMPAT .compat_ioctl = radeon_compat_ioctl, #endif + .llseek = noop_llseek, }, .pci_driver = { diff --git a/drivers/gpu/drm/savage/savage_drv.c b/drivers/gpu/drm/savage/savage_drv.c index 021de44c15ab..2a2830f5a840 100644 --- a/drivers/gpu/drm/savage/savage_drv.c +++ b/drivers/gpu/drm/savage/savage_drv.c @@ -54,6 +54,7 @@ static struct drm_driver driver = { .mmap = drm_mmap, .poll = drm_poll, .fasync = drm_fasync, + .llseek = noop_llseek, }, .pci_driver = { diff --git a/drivers/gpu/drm/sis/sis_drv.c b/drivers/gpu/drm/sis/sis_drv.c index 776bf9e9ea1a..4bb10ef6676a 100644 --- a/drivers/gpu/drm/sis/sis_drv.c +++ b/drivers/gpu/drm/sis/sis_drv.c @@ -83,6 +83,7 @@ static struct drm_driver driver = { .mmap = drm_mmap, .poll = drm_poll, .fasync = drm_fasync, + .llseek = noop_llseek, }, .pci_driver = { .name = DRIVER_NAME, diff --git a/drivers/gpu/drm/tdfx/tdfx_drv.c b/drivers/gpu/drm/tdfx/tdfx_drv.c index ec5a43e65722..640567ef713d 100644 --- a/drivers/gpu/drm/tdfx/tdfx_drv.c +++ b/drivers/gpu/drm/tdfx/tdfx_drv.c @@ -52,6 +52,7 @@ static struct drm_driver driver = { .mmap = drm_mmap, .poll = drm_poll, .fasync = drm_fasync, + .llseek = noop_llseek, }, .pci_driver = { .name = DRIVER_NAME, diff --git a/drivers/gpu/drm/via/via_drv.c b/drivers/gpu/drm/via/via_drv.c index 7a1b210401e0..b8984a5ae521 100644 --- a/drivers/gpu/drm/via/via_drv.c +++ b/drivers/gpu/drm/via/via_drv.c @@ -62,6 +62,7 @@ static struct drm_driver driver = { .mmap = drm_mmap, .poll = drm_poll, .fasync = drm_fasync, + .llseek = noop_llseek, }, .pci_driver = { .name = DRIVER_NAME, diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index a96ed6d9d010..2ef93df9e8ae 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -820,6 +820,7 @@ static struct drm_driver driver = { #if defined(CONFIG_COMPAT) .compat_ioctl = drm_compat_ioctl, #endif + .llseek = noop_llseek, }, .pci_driver = { .name = VMWGFX_DRIVER_NAME, diff --git a/drivers/gpu/vga/vgaarb.c b/drivers/gpu/vga/vgaarb.c index f366f968155a..c380c65da417 100644 --- a/drivers/gpu/vga/vgaarb.c +++ b/drivers/gpu/vga/vgaarb.c @@ -1211,6 +1211,7 @@ static const struct file_operations vga_arb_device_fops = { .poll = vga_arb_fpoll, .open = vga_arb_open, .release = vga_arb_release, + .llseek = noop_llseek, }; static struct miscdevice vga_arb_device = { diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c index 850d02a7a925..61a3e572224a 100644 --- a/drivers/hid/hid-debug.c +++ b/drivers/hid/hid-debug.c @@ -1051,6 +1051,7 @@ static const struct file_operations hid_debug_events_fops = { .read = hid_debug_events_read, .poll = hid_debug_events_poll, .release = hid_debug_events_release, + .llseek = noop_llseek, }; diff --git a/drivers/hid/hid-roccat.c b/drivers/hid/hid-roccat.c index f6e80c7ca61e..5a6879e235ac 100644 --- a/drivers/hid/hid-roccat.c +++ b/drivers/hid/hid-roccat.c @@ -384,6 +384,7 @@ static const struct file_operations roccat_ops = { .poll = roccat_poll, .open = roccat_open, .release = roccat_release, + .llseek = noop_llseek, }; static int __init roccat_init(void) diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c index a3866b5c0c43..925992f549f0 100644 --- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c @@ -340,6 +340,7 @@ static const struct file_operations hidraw_ops = { .open = hidraw_open, .release = hidraw_release, .unlocked_ioctl = hidraw_ioctl, + .llseek = noop_llseek, }; void hidraw_report_event(struct hid_device *hid, u8 *data, int len) diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c index 681e620eb95b..dfcb27613ec5 100644 --- a/drivers/hid/usbhid/hiddev.c +++ b/drivers/hid/usbhid/hiddev.c @@ -847,6 +847,7 @@ static const struct file_operations hiddev_fops = { #ifdef CONFIG_COMPAT .compat_ioctl = hiddev_compat_ioctl, #endif + .llseek = noop_llseek, }; static char *hiddev_devnode(struct device *dev, mode_t *mode) diff --git a/drivers/hwmon/asus_atk0110.c b/drivers/hwmon/asus_atk0110.c index 653db1bda934..23b8555215d2 100644 --- a/drivers/hwmon/asus_atk0110.c +++ b/drivers/hwmon/asus_atk0110.c @@ -762,6 +762,7 @@ static const struct file_operations atk_debugfs_ggrp_fops = { .read = atk_debugfs_ggrp_read, .open = atk_debugfs_ggrp_open, .release = atk_debugfs_ggrp_release, + .llseek = no_llseek, }; static void atk_debugfs_init(struct atk_data *data) diff --git a/drivers/hwmon/fschmd.c b/drivers/hwmon/fschmd.c index b7ca2a9676cf..d4d4ca65d371 100644 --- a/drivers/hwmon/fschmd.c +++ b/drivers/hwmon/fschmd.c @@ -38,7 +38,6 @@ #include <linux/i2c.h> #include <linux/hwmon.h> #include <linux/hwmon-sysfs.h> -#include <linux/smp_lock.h> #include <linux/err.h> #include <linux/mutex.h> #include <linux/sysfs.h> @@ -50,6 +49,7 @@ #include <linux/kref.h> /* Addresses to scan */ +static DEFINE_MUTEX(watchdog_mutex); static const unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END }; /* Insmod parameters */ @@ -858,7 +858,7 @@ static long watchdog_ioctl(struct file *filp, unsigned int cmd, unsigned long ar int i, ret = 0; struct fschmd_data *data = filp->private_data; - lock_kernel(); + mutex_lock(&watchdog_mutex); switch (cmd) { case WDIOC_GETSUPPORT: ident.firmware_version = data->revision; @@ -915,7 +915,7 @@ static long watchdog_ioctl(struct file *filp, unsigned int cmd, unsigned long ar default: ret = -ENOTTY; } - unlock_kernel(); + mutex_unlock(&watchdog_mutex); return ret; } diff --git a/drivers/hwmon/w83793.c b/drivers/hwmon/w83793.c index 697202e27891..8e540ada47d2 100644 --- a/drivers/hwmon/w83793.c +++ b/drivers/hwmon/w83793.c @@ -35,7 +35,6 @@ #include <linux/slab.h> #include <linux/i2c.h> #include <linux/hwmon.h> -#include <linux/smp_lock.h> #include <linux/hwmon-vid.h> #include <linux/hwmon-sysfs.h> #include <linux/err.h> @@ -52,6 +51,7 @@ #define WATCHDOG_TIMEOUT 2 /* 2 minute default timeout */ /* Addresses to scan */ +static DEFINE_MUTEX(watchdog_mutex); static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END }; @@ -1333,7 +1333,7 @@ static long watchdog_ioctl(struct file *filp, unsigned int cmd, int val, ret = 0; struct w83793_data *data = filp->private_data; - lock_kernel(); + mutex_lock(&watchdog_mutex); switch (cmd) { case WDIOC_GETSUPPORT: if (!nowayout) @@ -1387,7 +1387,7 @@ static long watchdog_ioctl(struct file *filp, unsigned int cmd, default: ret = -ENOTTY; } - unlock_kernel(); + mutex_unlock(&watchdog_mutex); return ret; } diff --git a/drivers/i2c/busses/i2c-pasemi.c b/drivers/i2c/busses/i2c-pasemi.c index 4174101660c9..837b8c1aa02a 100644 --- a/drivers/i2c/busses/i2c-pasemi.c +++ b/drivers/i2c/busses/i2c-pasemi.c @@ -88,7 +88,7 @@ static void pasemi_smb_clear(struct pasemi_smbus *smbus) reg_write(smbus, REG_SMSTA, status); } -static unsigned int pasemi_smb_waitready(struct pasemi_smbus *smbus) +static int pasemi_smb_waitready(struct pasemi_smbus *smbus) { int timeout = 10; unsigned int status; diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index 31fc76960a8f..0c73fe39a236 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -31,7 +31,6 @@ #include <linux/delay.h> #include <linux/timer.h> #include <linux/seq_file.h> -#include <linux/smp_lock.h> #include <linux/slab.h> #include <linux/interrupt.h> #include <linux/errno.h> @@ -52,6 +51,7 @@ #include "ide-cd.h" +static DEFINE_MUTEX(ide_cd_mutex); static DEFINE_MUTEX(idecd_ref_mutex); static void ide_cd_release(struct device *); @@ -1602,7 +1602,7 @@ static int idecd_open(struct block_device *bdev, fmode_t mode) struct cdrom_info *info; int rc = -ENXIO; - lock_kernel(); + mutex_lock(&ide_cd_mutex); info = ide_cd_get(bdev->bd_disk); if (!info) goto out; @@ -1611,7 +1611,7 @@ static int idecd_open(struct block_device *bdev, fmode_t mode) if (rc < 0) ide_cd_put(info); out: - unlock_kernel(); + mutex_unlock(&ide_cd_mutex); return rc; } @@ -1619,11 +1619,11 @@ static int idecd_release(struct gendisk *disk, fmode_t mode) { struct cdrom_info *info = ide_drv_g(disk, cdrom_info); - lock_kernel(); + mutex_lock(&ide_cd_mutex); cdrom_release(&info->devinfo, mode); ide_cd_put(info); - unlock_kernel(); + mutex_unlock(&ide_cd_mutex); return 0; } @@ -1694,9 +1694,9 @@ static int idecd_ioctl(struct block_device *bdev, fmode_t mode, { int ret; - lock_kernel(); + mutex_lock(&ide_cd_mutex); ret = idecd_locked_ioctl(bdev, mode, cmd, arg); - unlock_kernel(); + mutex_unlock(&ide_cd_mutex); return ret; } diff --git a/drivers/ide/ide-cs.c b/drivers/ide/ide-cs.c index 2a4cb9c18f01..404843e8611b 100644 --- a/drivers/ide/ide-cs.c +++ b/drivers/ide/ide-cs.c @@ -43,7 +43,6 @@ #include <asm/io.h> #include <asm/system.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/ds.h> #include <pcmcia/cisreg.h> @@ -72,17 +71,6 @@ static int ide_config(struct pcmcia_device *); static void ide_detach(struct pcmcia_device *p_dev); - - - -/*====================================================================== - - ide_attach() creates an "instance" of the driver, allocating - local data structures for one device. The device is registered - with Card Services. - -======================================================================*/ - static int ide_probe(struct pcmcia_device *link) { ide_info_t *info; @@ -97,23 +85,12 @@ static int ide_probe(struct pcmcia_device *link) info->p_dev = link; link->priv = info; - link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; - link->resource[1]->flags |= IO_DATA_PATH_WIDTH_8; - link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.IntType = INT_MEMORY_AND_IO; + link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO | + CONF_AUTO_SET_VPP | CONF_AUTO_CHECK_VCC; return ide_config(link); } /* ide_attach */ -/*====================================================================== - - This deletes a driver "instance". The device is de-registered - with Card Services. If it has been released, all local data - structures are freed. Otherwise, the structures will be freed - when the device is released. - -======================================================================*/ - static void ide_detach(struct pcmcia_device *link) { ide_info_t *info = link->priv; @@ -187,79 +164,31 @@ out_release: return NULL; } -/*====================================================================== - - ide_config() is scheduled to run after a CARD_INSERTION event - is received, to configure the PCMCIA socket, and to make the - ide device available to the system. - -======================================================================*/ - -struct pcmcia_config_check { - unsigned long ctl_base; - int skip_vcc; - int is_kme; -}; - -static int pcmcia_check_one_config(struct pcmcia_device *pdev, - cistpl_cftable_entry_t *cfg, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, - void *priv_data) +static int pcmcia_check_one_config(struct pcmcia_device *pdev, void *priv_data) { - struct pcmcia_config_check *stk = priv_data; - - /* Check for matching Vcc, unless we're desperate */ - if (!stk->skip_vcc) { - if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { - if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) - return -ENODEV; - } else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) { - if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000) - return -ENODEV; - } - } + int *is_kme = priv_data; - if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) - pdev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; - else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM)) - pdev->conf.Vpp = dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000; - - if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) { - cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io; - pdev->io_lines = io->flags & CISTPL_IO_LINES_MASK; - - pdev->conf.ConfigIndex = cfg->index; - pdev->resource[0]->start = io->win[0].base; - if (!(io->flags & CISTPL_IO_16BIT)) { - pdev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; - pdev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; - } - if (io->nwin == 2) { - pdev->resource[0]->end = 8; - pdev->resource[1]->start = io->win[1].base; - pdev->resource[1]->end = (stk->is_kme) ? 2 : 1; - if (pcmcia_request_io(pdev) != 0) - return -ENODEV; - stk->ctl_base = pdev->resource[1]->start; - } else if ((io->nwin == 1) && (io->win[0].len >= 16)) { - pdev->resource[0]->end = io->win[0].len; - pdev->resource[1]->end = 0; - if (pcmcia_request_io(pdev) != 0) - return -ENODEV; - stk->ctl_base = pdev->resource[0]->start + 0x0e; - } else + if (!(pdev->resource[0]->flags & IO_DATA_PATH_WIDTH_8)) { + pdev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; + pdev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; + } + pdev->resource[1]->flags &= ~IO_DATA_PATH_WIDTH; + pdev->resource[1]->flags |= IO_DATA_PATH_WIDTH_8; + + if (pdev->resource[1]->end) { + pdev->resource[0]->end = 8; + pdev->resource[1]->end = (*is_kme) ? 2 : 1; + } else { + if (pdev->resource[0]->end < 16) return -ENODEV; - /* If we've got this far, we're done */ - return 0; } - return -ENODEV; + + return pcmcia_request_io(pdev); } static int ide_config(struct pcmcia_device *link) { ide_info_t *info = link->priv; - struct pcmcia_config_check *stk = NULL; int ret = 0, is_kme = 0; unsigned long io_base, ctl_base; struct ide_host *host; @@ -270,23 +199,21 @@ static int ide_config(struct pcmcia_device *link) ((link->card_id == PRODID_KME_KXLC005_A) || (link->card_id == PRODID_KME_KXLC005_B))); - stk = kzalloc(sizeof(*stk), GFP_KERNEL); - if (!stk) - goto err_mem; - stk->is_kme = is_kme; - stk->skip_vcc = io_base = ctl_base = 0; - - if (pcmcia_loop_config(link, pcmcia_check_one_config, stk)) { - stk->skip_vcc = 1; - if (pcmcia_loop_config(link, pcmcia_check_one_config, stk)) + if (pcmcia_loop_config(link, pcmcia_check_one_config, &is_kme)) { + link->config_flags &= ~CONF_AUTO_CHECK_VCC; + if (pcmcia_loop_config(link, pcmcia_check_one_config, &is_kme)) goto failed; /* No suitable config found */ } io_base = link->resource[0]->start; - ctl_base = stk->ctl_base; + if (link->resource[1]->end) + ctl_base = link->resource[1]->start; + else + ctl_base = link->resource[0]->start + 0x0e; if (!link->irq) goto failed; - ret = pcmcia_request_configuration(link, &link->conf); + + ret = pcmcia_enable_device(link); if (ret) goto failed; @@ -311,29 +238,15 @@ static int ide_config(struct pcmcia_device *link) info->host = host; dev_info(&link->dev, "ide-cs: hd%c: Vpp = %d.%d\n", 'a' + host->ports[0]->index * 2, - link->conf.Vpp / 10, link->conf.Vpp % 10); + link->vpp / 10, link->vpp % 10); - kfree(stk); return 0; -err_mem: - printk(KERN_NOTICE "ide-cs: ide_config failed memory allocation\n"); - goto failed; - failed: - kfree(stk); ide_release(link); return -ENODEV; } /* ide_config */ -/*====================================================================== - - After a card is removed, ide_release() will unregister the net - device, and release the PCMCIA configuration. If the device is - still open, this will be postponed until it is closed. - -======================================================================*/ - static void ide_release(struct pcmcia_device *link) { ide_info_t *info = link->priv; @@ -359,15 +272,6 @@ static void ide_release(struct pcmcia_device *link) } /* ide_release */ -/*====================================================================== - - The card status event handler. Mostly, this schedules other - stuff to run after an event is received. A CARD_REMOVAL event - also sets some flags to discourage the ide drivers from - talking to the ports. - -======================================================================*/ - static struct pcmcia_device_id ide_ids[] = { PCMCIA_DEVICE_FUNC_ID(4), PCMCIA_DEVICE_MANF_CARD(0x0000, 0x0000), /* Corsair */ @@ -440,9 +344,7 @@ MODULE_DEVICE_TABLE(pcmcia, ide_ids); static struct pcmcia_driver ide_cs_driver = { .owner = THIS_MODULE, - .drv = { - .name = "ide-cs", - }, + .name = "ide-cs", .probe = ide_probe, .remove = ide_detach, .id_table = ide_ids, diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index 7433e07de30e..7c5b01ce51d2 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -516,10 +516,10 @@ static int ide_do_setfeature(ide_drive_t *drive, u8 feature, u8 nsect) return ide_no_data_taskfile(drive, &cmd); } -static void update_ordered(ide_drive_t *drive) +static void update_flush(ide_drive_t *drive) { u16 *id = drive->id; - unsigned ordered = QUEUE_ORDERED_NONE; + unsigned flush = 0; if (drive->dev_flags & IDE_DFLAG_WCACHE) { unsigned long long capacity; @@ -543,13 +543,12 @@ static void update_ordered(ide_drive_t *drive) drive->name, barrier ? "" : "not "); if (barrier) { - ordered = QUEUE_ORDERED_DRAIN_FLUSH; + flush = REQ_FLUSH; blk_queue_prep_rq(drive->queue, idedisk_prep_fn); } - } else - ordered = QUEUE_ORDERED_DRAIN; + } - blk_queue_ordered(drive->queue, ordered); + blk_queue_flush(drive->queue, flush); } ide_devset_get_flag(wcache, IDE_DFLAG_WCACHE); @@ -572,7 +571,7 @@ static int set_wcache(ide_drive_t *drive, int arg) } } - update_ordered(drive); + update_flush(drive); return err; } diff --git a/drivers/ide/ide-disk_ioctl.c b/drivers/ide/ide-disk_ioctl.c index ec94c66918f6..da36f729ff32 100644 --- a/drivers/ide/ide-disk_ioctl.c +++ b/drivers/ide/ide-disk_ioctl.c @@ -1,10 +1,11 @@ #include <linux/kernel.h> #include <linux/ide.h> #include <linux/hdreg.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include "ide-disk.h" +static DEFINE_MUTEX(ide_disk_ioctl_mutex); static const struct ide_ioctl_devset ide_disk_ioctl_settings[] = { { HDIO_GET_ADDRESS, HDIO_SET_ADDRESS, &ide_devset_address }, { HDIO_GET_MULTCOUNT, HDIO_SET_MULTCOUNT, &ide_devset_multcount }, @@ -19,13 +20,13 @@ int ide_disk_ioctl(ide_drive_t *drive, struct block_device *bdev, fmode_t mode, { int err; - lock_kernel(); + mutex_lock(&ide_disk_ioctl_mutex); err = ide_setting_ioctl(drive, bdev, cmd, arg, ide_disk_ioctl_settings); if (err != -EOPNOTSUPP) goto out; err = generic_ide_ioctl(drive, bdev, cmd, arg); out: - unlock_kernel(); + mutex_unlock(&ide_disk_ioctl_mutex); return err; } diff --git a/drivers/ide/ide-floppy_ioctl.c b/drivers/ide/ide-floppy_ioctl.c index fd3d05ab3417..d267b7affad6 100644 --- a/drivers/ide/ide-floppy_ioctl.c +++ b/drivers/ide/ide-floppy_ioctl.c @@ -5,7 +5,7 @@ #include <linux/kernel.h> #include <linux/ide.h> #include <linux/cdrom.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <asm/unaligned.h> @@ -32,6 +32,7 @@ * On exit we set nformats to the number of records we've actually initialized. */ +static DEFINE_MUTEX(ide_floppy_ioctl_mutex); static int ide_floppy_get_format_capacities(ide_drive_t *drive, struct ide_atapi_pc *pc, int __user *arg) @@ -276,7 +277,7 @@ int ide_floppy_ioctl(ide_drive_t *drive, struct block_device *bdev, void __user *argp = (void __user *)arg; int err; - lock_kernel(); + mutex_lock(&ide_floppy_ioctl_mutex); if (cmd == CDROMEJECT || cmd == CDROM_LOCKDOOR) { err = ide_floppy_lockdoor(drive, &pc, arg, cmd); goto out; @@ -298,6 +299,6 @@ int ide_floppy_ioctl(ide_drive_t *drive, struct block_device *bdev, err = generic_ide_ioctl(drive, bdev, cmd, arg); out: - unlock_kernel(); + mutex_unlock(&ide_floppy_ioctl_mutex); return err; } diff --git a/drivers/ide/ide-gd.c b/drivers/ide/ide-gd.c index 70aeeb18833e..35c4b43585e3 100644 --- a/drivers/ide/ide-gd.c +++ b/drivers/ide/ide-gd.c @@ -1,4 +1,3 @@ -#include <linux/smp_lock.h> #include <linux/module.h> #include <linux/types.h> #include <linux/string.h> @@ -23,6 +22,7 @@ #define IDE_GD_VERSION "1.18" /* module parameters */ +static DEFINE_MUTEX(ide_gd_mutex); static unsigned long debug_mask; module_param(debug_mask, ulong, 0644); @@ -242,9 +242,9 @@ static int ide_gd_unlocked_open(struct block_device *bdev, fmode_t mode) { int ret; - lock_kernel(); + mutex_lock(&ide_gd_mutex); ret = ide_gd_open(bdev, mode); - unlock_kernel(); + mutex_unlock(&ide_gd_mutex); return ret; } @@ -257,7 +257,7 @@ static int ide_gd_release(struct gendisk *disk, fmode_t mode) ide_debug_log(IDE_DBG_FUNC, "enter"); - lock_kernel(); + mutex_lock(&ide_gd_mutex); if (idkp->openers == 1) drive->disk_ops->flush(drive); @@ -269,7 +269,7 @@ static int ide_gd_release(struct gendisk *disk, fmode_t mode) idkp->openers--; ide_disk_put(idkp); - unlock_kernel(); + mutex_unlock(&ide_gd_mutex); return 0; } diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index a381be814070..999dac054bcc 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -441,19 +441,6 @@ void do_ide_request(struct request_queue *q) struct request *rq = NULL; ide_startstop_t startstop; - /* - * drive is doing pre-flush, ordered write, post-flush sequence. even - * though that is 3 requests, it must be seen as a single transaction. - * we must not preempt this drive until that is complete - */ - if (blk_queue_flushing(q)) - /* - * small race where queue could get replugged during - * the 3-request flush cycle, just yank the plug since - * we want it to finish asap - */ - blk_remove_plug(q); - spin_unlock_irq(q->queue_lock); /* HLD do_request() callback might sleep, make sure it's okay */ diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index 6d622cb5ac81..7ecb1ade8874 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -32,11 +32,9 @@ #include <linux/errno.h> #include <linux/genhd.h> #include <linux/seq_file.h> -#include <linux/smp_lock.h> #include <linux/slab.h> #include <linux/pci.h> #include <linux/ide.h> -#include <linux/smp_lock.h> #include <linux/completion.h> #include <linux/bitops.h> #include <linux/mutex.h> @@ -220,6 +218,7 @@ typedef struct ide_tape_obj { char write_prot; } idetape_tape_t; +static DEFINE_MUTEX(ide_tape_mutex); static DEFINE_MUTEX(idetape_ref_mutex); static DEFINE_MUTEX(idetape_chrdev_mutex); @@ -1426,9 +1425,9 @@ static long idetape_chrdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { long ret; - lock_kernel(); + mutex_lock(&ide_tape_mutex); ret = do_idetape_chrdev_ioctl(file, cmd, arg); - unlock_kernel(); + mutex_unlock(&ide_tape_mutex); return ret; } @@ -1903,15 +1902,16 @@ static const struct file_operations idetape_fops = { .unlocked_ioctl = idetape_chrdev_ioctl, .open = idetape_chrdev_open, .release = idetape_chrdev_release, + .llseek = noop_llseek, }; static int idetape_open(struct block_device *bdev, fmode_t mode) { struct ide_tape_obj *tape; - lock_kernel(); + mutex_lock(&ide_tape_mutex); tape = ide_tape_get(bdev->bd_disk, false, 0); - unlock_kernel(); + mutex_unlock(&ide_tape_mutex); if (!tape) return -ENXIO; @@ -1923,9 +1923,9 @@ static int idetape_release(struct gendisk *disk, fmode_t mode) { struct ide_tape_obj *tape = ide_drv_g(disk, ide_tape_obj); - lock_kernel(); + mutex_lock(&ide_tape_mutex); ide_tape_put(tape); - unlock_kernel(); + mutex_unlock(&ide_tape_mutex); return 0; } @@ -1937,11 +1937,11 @@ static int idetape_ioctl(struct block_device *bdev, fmode_t mode, ide_drive_t *drive = tape->drive; int err; - lock_kernel(); + mutex_lock(&ide_tape_mutex); err = generic_ide_ioctl(drive, bdev, cmd, arg); if (err == -EINVAL) err = idetape_blkdev_ioctl(drive, cmd, arg); - unlock_kernel(); + mutex_unlock(&ide_tape_mutex); return err; } diff --git a/drivers/idle/i7300_idle.c b/drivers/idle/i7300_idle.c index 15341fc1c68b..c976285d313e 100644 --- a/drivers/idle/i7300_idle.c +++ b/drivers/idle/i7300_idle.c @@ -536,6 +536,7 @@ static ssize_t stats_read_ul(struct file *fp, char __user *ubuf, size_t count, static const struct file_operations idle_fops = { .open = stats_open_generic, .read = stats_read_ul, + .llseek = default_llseek, }; struct debugfs_file_info { diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index c37ef64d1465..cb3ccf3ed221 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -59,18 +59,11 @@ #include <linux/hrtimer.h> /* ktime_get_real() */ #include <trace/events/power.h> #include <linux/sched.h> +#include <asm/mwait.h> #define INTEL_IDLE_VERSION "0.4" #define PREFIX "intel_idle: " -#define MWAIT_SUBSTATE_MASK (0xf) -#define MWAIT_CSTATE_MASK (0xf) -#define MWAIT_SUBSTATE_SIZE (4) -#define MWAIT_MAX_NUM_CSTATES 8 -#define CPUID_MWAIT_LEAF (5) -#define CPUID5_ECX_EXTENSIONS_SUPPORTED (0x1) -#define CPUID5_ECX_INTERRUPT_BREAK (0x2) - static struct cpuidle_driver intel_idle_driver = { .name = "intel_idle", .owner = THIS_MODULE, diff --git a/drivers/infiniband/hw/ipath/ipath_diag.c b/drivers/infiniband/hw/ipath/ipath_diag.c index d4ce8b63e19e..daef61d5e5bb 100644 --- a/drivers/infiniband/hw/ipath/ipath_diag.c +++ b/drivers/infiniband/hw/ipath/ipath_diag.c @@ -65,7 +65,8 @@ static const struct file_operations diag_file_ops = { .write = ipath_diag_write, .read = ipath_diag_read, .open = ipath_diag_open, - .release = ipath_diag_release + .release = ipath_diag_release, + .llseek = default_llseek, }; static ssize_t ipath_diagpkt_write(struct file *fp, @@ -75,6 +76,7 @@ static ssize_t ipath_diagpkt_write(struct file *fp, static const struct file_operations diagpkt_file_ops = { .owner = THIS_MODULE, .write = ipath_diagpkt_write, + .llseek = noop_llseek, }; static atomic_t diagpkt_count = ATOMIC_INIT(0); diff --git a/drivers/infiniband/hw/ipath/ipath_file_ops.c b/drivers/infiniband/hw/ipath/ipath_file_ops.c index 65eb8929db22..6078992da3f0 100644 --- a/drivers/infiniband/hw/ipath/ipath_file_ops.c +++ b/drivers/infiniband/hw/ipath/ipath_file_ops.c @@ -63,7 +63,8 @@ static const struct file_operations ipath_file_ops = { .open = ipath_open, .release = ipath_close, .poll = ipath_poll, - .mmap = ipath_mmap + .mmap = ipath_mmap, + .llseek = noop_llseek, }; /* diff --git a/drivers/infiniband/hw/ipath/ipath_fs.c b/drivers/infiniband/hw/ipath/ipath_fs.c index 2fca70836dae..d13e72685dcf 100644 --- a/drivers/infiniband/hw/ipath/ipath_fs.c +++ b/drivers/infiniband/hw/ipath/ipath_fs.c @@ -103,6 +103,7 @@ static ssize_t atomic_stats_read(struct file *file, char __user *buf, static const struct file_operations atomic_stats_ops = { .read = atomic_stats_read, + .llseek = default_llseek, }; static ssize_t atomic_counters_read(struct file *file, char __user *buf, @@ -120,6 +121,7 @@ static ssize_t atomic_counters_read(struct file *file, char __user *buf, static const struct file_operations atomic_counters_ops = { .read = atomic_counters_read, + .llseek = default_llseek, }; static ssize_t flash_read(struct file *file, char __user *buf, @@ -224,6 +226,7 @@ bail: static const struct file_operations flash_ops = { .read = flash_read, .write = flash_write, + .llseek = default_llseek, }; static int create_device_files(struct super_block *sb, diff --git a/drivers/infiniband/hw/qib/qib_diag.c b/drivers/infiniband/hw/qib/qib_diag.c index 05dcf0d9a7d3..204c4dd9dce0 100644 --- a/drivers/infiniband/hw/qib/qib_diag.c +++ b/drivers/infiniband/hw/qib/qib_diag.c @@ -136,7 +136,8 @@ static const struct file_operations diag_file_ops = { .write = qib_diag_write, .read = qib_diag_read, .open = qib_diag_open, - .release = qib_diag_release + .release = qib_diag_release, + .llseek = default_llseek, }; static atomic_t diagpkt_count = ATOMIC_INIT(0); @@ -149,6 +150,7 @@ static ssize_t qib_diagpkt_write(struct file *fp, const char __user *data, static const struct file_operations diagpkt_file_ops = { .owner = THIS_MODULE, .write = qib_diagpkt_write, + .llseek = noop_llseek, }; int qib_diag_add(struct qib_devdata *dd) diff --git a/drivers/infiniband/hw/qib/qib_file_ops.c b/drivers/infiniband/hw/qib/qib_file_ops.c index 6b11645edf35..aa2be214270f 100644 --- a/drivers/infiniband/hw/qib/qib_file_ops.c +++ b/drivers/infiniband/hw/qib/qib_file_ops.c @@ -63,7 +63,8 @@ static const struct file_operations qib_file_ops = { .open = qib_open, .release = qib_close, .poll = qib_poll, - .mmap = qib_mmapf + .mmap = qib_mmapf, + .llseek = noop_llseek, }; /* diff --git a/drivers/infiniband/hw/qib/qib_fs.c b/drivers/infiniband/hw/qib/qib_fs.c index 9f989c0ba9d3..a0e6613e8be6 100644 --- a/drivers/infiniband/hw/qib/qib_fs.c +++ b/drivers/infiniband/hw/qib/qib_fs.c @@ -367,6 +367,7 @@ bail: static const struct file_operations flash_ops = { .read = flash_read, .write = flash_write, + .llseek = default_llseek, }; static int add_cntr_files(struct super_block *sb, struct qib_devdata *dd) diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 9ddafc30f432..535fea4fe67f 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -28,7 +28,7 @@ struct evdev { int minor; struct input_handle handle; wait_queue_head_t wait; - struct evdev_client *grab; + struct evdev_client __rcu *grab; struct list_head client_list; spinlock_t client_lock; /* protects client_list */ struct mutex mutex; @@ -767,7 +767,8 @@ static const struct file_operations evdev_fops = { .compat_ioctl = evdev_ioctl_compat, #endif .fasync = evdev_fasync, - .flush = evdev_flush + .flush = evdev_flush, + .llseek = no_llseek, }; static int evdev_install_chrdev(struct evdev *evdev) diff --git a/drivers/input/input.c b/drivers/input/input.c index ab6982056518..7919c2537225 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -2047,6 +2047,7 @@ out: static const struct file_operations input_fops = { .owner = THIS_MODULE, .open = input_open_file, + .llseek = noop_llseek, }; static int __init input_init(void) diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index 22239e988498..9d424cebfd2c 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c @@ -739,6 +739,7 @@ static const struct file_operations joydev_fops = { .compat_ioctl = joydev_compat_ioctl, #endif .fasync = joydev_fasync, + .llseek = no_llseek, }; static int joydev_install_chrdev(struct joydev *joydev) diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 9cc488d21490..aa037fec2f86 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -338,7 +338,7 @@ config KEYBOARD_OPENCORES config KEYBOARD_PXA27x tristate "PXA27x/PXA3xx keypad support" - depends on PXA27x || PXA3xx + depends on PXA27x || PXA3xx || ARCH_MMP help Enable support for PXA27x/PXA3xx keypad controller. diff --git a/drivers/input/keyboard/pxa27x_keypad.c b/drivers/input/keyboard/pxa27x_keypad.c index f32404f99189..4b0ec35259a1 100644 --- a/drivers/input/keyboard/pxa27x_keypad.c +++ b/drivers/input/keyboard/pxa27x_keypad.c @@ -32,7 +32,7 @@ #include <asm/mach/map.h> #include <mach/hardware.h> -#include <mach/pxa27x_keypad.h> +#include <plat/pxa27x_keypad.h> /* * Keypad Controller registers */ @@ -330,11 +330,21 @@ static void pxa27x_keypad_scan_direct(struct pxa27x_keypad *keypad) keypad->direct_key_state = new_state; } +static void clear_wakeup_event(struct pxa27x_keypad *keypad) +{ + struct pxa27x_keypad_platform_data *pdata = keypad->pdata; + + if (pdata->clear_wakeup_event) + (pdata->clear_wakeup_event)(); +} + static irqreturn_t pxa27x_keypad_irq_handler(int irq, void *dev_id) { struct pxa27x_keypad *keypad = dev_id; unsigned long kpc = keypad_readl(KPC); + clear_wakeup_event(keypad); + if (kpc & KPC_DI) pxa27x_keypad_scan_direct(keypad); diff --git a/drivers/input/misc/hp_sdc_rtc.c b/drivers/input/misc/hp_sdc_rtc.c index c19066479057..0b4f54265f62 100644 --- a/drivers/input/misc/hp_sdc_rtc.c +++ b/drivers/input/misc/hp_sdc_rtc.c @@ -43,7 +43,7 @@ #include <linux/proc_fs.h> #include <linux/poll.h> #include <linux/rtc.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/semaphore.h> MODULE_AUTHOR("Brian S. Julin <bri@calyx.com>"); @@ -52,6 +52,7 @@ MODULE_LICENSE("Dual BSD/GPL"); #define RTC_VERSION "1.10d" +static DEFINE_MUTEX(hp_sdc_rtc_mutex); static unsigned long epoch = 2000; static struct semaphore i8042tregs; @@ -104,7 +105,7 @@ static int hp_sdc_rtc_do_read_bbrtc (struct rtc_time *rtctm) t.endidx = 91; t.seq = tseq; t.act.semaphore = &tsem; - init_MUTEX_LOCKED(&tsem); + sema_init(&tsem, 0); if (hp_sdc_enqueue_transaction(&t)) return -1; @@ -665,9 +666,9 @@ static long hp_sdc_rtc_unlocked_ioctl(struct file *file, { int ret; - lock_kernel(); + mutex_lock(&hp_sdc_rtc_mutex); ret = hp_sdc_rtc_ioctl(file, cmd, arg); - unlock_kernel(); + mutex_unlock(&hp_sdc_rtc_mutex); return ret; } @@ -698,7 +699,7 @@ static int __init hp_sdc_rtc_init(void) return -ENODEV; #endif - init_MUTEX(&i8042tregs); + sema_init(&i8042tregs, 1); if ((ret = hp_sdc_request_timer_irq(&hp_sdc_rtc_isr))) return ret; diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index 360698553eb5..b9410784e6a1 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -811,6 +811,7 @@ static const struct file_operations uinput_fops = { #ifdef CONFIG_COMPAT .compat_ioctl = uinput_compat_ioctl, #endif + .llseek = no_llseek, }; static struct miscdevice uinput_misc = { diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index d528a2dba064..31ec7265aac6 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c @@ -792,6 +792,7 @@ static const struct file_operations mousedev_fops = { .open = mousedev_open, .release = mousedev_release, .fasync = mousedev_fasync, + .llseek = noop_llseek, }; static int mousedev_install_chrdev(struct mousedev *mousedev) diff --git a/drivers/input/serio/hil_mlc.c b/drivers/input/serio/hil_mlc.c index c92f4edfee7b..e5624d8f1709 100644 --- a/drivers/input/serio/hil_mlc.c +++ b/drivers/input/serio/hil_mlc.c @@ -915,15 +915,15 @@ int hil_mlc_register(hil_mlc *mlc) mlc->ostarted = 0; rwlock_init(&mlc->lock); - init_MUTEX(&mlc->osem); + sema_init(&mlc->osem, 1); - init_MUTEX(&mlc->isem); + sema_init(&mlc->isem, 1); mlc->icount = -1; mlc->imatch = 0; mlc->opercnt = 0; - init_MUTEX_LOCKED(&(mlc->csem)); + sema_init(&(mlc->csem), 0); hil_mlc_clear_di_scratch(mlc); hil_mlc_clear_di_map(mlc, 0); diff --git a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c index bcc2d30ec245..8c0b51c31424 100644 --- a/drivers/input/serio/hp_sdc.c +++ b/drivers/input/serio/hp_sdc.c @@ -905,7 +905,7 @@ static int __init hp_sdc_init(void) ts_sync[1] = 0x0f; ts_sync[2] = ts_sync[3] = ts_sync[4] = ts_sync[5] = 0; t_sync.act.semaphore = &s_sync; - init_MUTEX_LOCKED(&s_sync); + sema_init(&s_sync, 0); hp_sdc_enqueue_transaction(&t_sync); down(&s_sync); /* Wait for t_sync to complete */ @@ -1039,7 +1039,7 @@ static int __init hp_sdc_register(void) return hp_sdc.dev_err; } - init_MUTEX_LOCKED(&tq_init_sem); + sema_init(&tq_init_sem, 0); tq_init.actidx = 0; tq_init.idx = 1; diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c index 998664854440..cd82bb125915 100644 --- a/drivers/input/serio/serio_raw.c +++ b/drivers/input/serio/serio_raw.c @@ -243,6 +243,7 @@ static const struct file_operations serio_raw_fops = { .write = serio_raw_write, .poll = serio_raw_poll, .fasync = serio_raw_fasync, + .llseek = noop_llseek, }; diff --git a/drivers/isdn/act2000/act2000.h b/drivers/isdn/act2000/act2000.h index d4c50512a1ff..88c9423500d8 100644 --- a/drivers/isdn/act2000/act2000.h +++ b/drivers/isdn/act2000/act2000.h @@ -141,9 +141,9 @@ typedef struct irq_data_isa { __u8 rcvhdr[8]; } irq_data_isa; -typedef union irq_data { +typedef union act2000_irq_data { irq_data_isa isa; -} irq_data; +} act2000_irq_data; /* * Per card driver data @@ -176,7 +176,7 @@ typedef struct act2000_card { char *status_buf_read; char *status_buf_write; char *status_buf_end; - irq_data idat; /* Data used for IRQ handler */ + act2000_irq_data idat; /* Data used for IRQ handler */ isdn_if interface; /* Interface to upper layer */ char regname[35]; /* Name used for request_region */ } act2000_card; diff --git a/drivers/isdn/hardware/avm/avm_cs.c b/drivers/isdn/hardware/avm/avm_cs.c index 09b1795516f4..91f06a3ef002 100644 --- a/drivers/isdn/hardware/avm/avm_cs.c +++ b/drivers/isdn/hardware/avm/avm_cs.c @@ -20,7 +20,6 @@ #include <asm/io.h> #include <asm/system.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/ciscode.h> #include <pcmcia/ds.h> @@ -39,87 +38,32 @@ MODULE_LICENSE("GPL"); /*====================================================================*/ -/* - The event() function is this driver's Card Services event handler. - It will be called by Card Services when an appropriate card status - event is received. The config() and release() entry points are - used to configure or release a socket, in response to card insertion - and ejection events. They are invoked from the skeleton event - handler. -*/ - static int avmcs_config(struct pcmcia_device *link); static void avmcs_release(struct pcmcia_device *link); - -/* - The attach() and detach() entry points are used to create and destroy - "instances" of the driver, where each instance represents everything - needed to manage one actual PCMCIA card. -*/ - static void avmcs_detach(struct pcmcia_device *p_dev); -/*====================================================================== - - avmcs_attach() creates an "instance" of the driver, allocating - local data structures for one device. The device is registered - with Card Services. - - The dev_link structure is initialized, but we don't actually - configure the card at this point -- we wait until we receive a - card insertion event. - -======================================================================*/ - static int avmcs_probe(struct pcmcia_device *p_dev) { - - /* The io structure describes IO port mapping */ - p_dev->resource[0]->end = 16; - p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; - /* General socket configuration */ - p_dev->conf.Attributes = CONF_ENABLE_IRQ; - p_dev->conf.IntType = INT_MEMORY_AND_IO; - p_dev->conf.ConfigIndex = 1; - p_dev->conf.Present = PRESENT_OPTION; + p_dev->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; + p_dev->config_index = 1; + p_dev->config_regs = PRESENT_OPTION; return avmcs_config(p_dev); } /* avmcs_attach */ -/*====================================================================== - - This deletes a driver "instance". The device is de-registered - with Card Services. If it has been released, all local data - structures are freed. Otherwise, the structures will be freed - when the device is released. - -======================================================================*/ static void avmcs_detach(struct pcmcia_device *link) { avmcs_release(link); } /* avmcs_detach */ -/*====================================================================== - - avmcs_config() is scheduled to run after a CARD_INSERTION event - is received, to configure the PCMCIA socket, and to make the - ethernet device available to the system. - -======================================================================*/ - -static int avmcs_configcheck(struct pcmcia_device *p_dev, - cistpl_cftable_entry_t *cf, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, - void *priv_data) +static int avmcs_configcheck(struct pcmcia_device *p_dev, void *priv_data) { - if (cf->io.nwin <= 0) - return -ENODEV; + p_dev->resource[0]->end = 16; + p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; + p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; - p_dev->resource[0]->start = cf->io.win[0].base; - p_dev->resource[0]->end = cf->io.win[0].len; return pcmcia_request_io(p_dev); } @@ -150,7 +94,7 @@ static int avmcs_config(struct pcmcia_device *link) /* * configure the PCMCIA socket */ - i = pcmcia_request_configuration(link, &link->conf); + i = pcmcia_enable_device(link); if (i != 0) { pcmcia_disable_device(link); break; @@ -197,13 +141,6 @@ static int avmcs_config(struct pcmcia_device *link) } /* avmcs_config */ -/*====================================================================== - - After a card is removed, avmcs_release() will unregister the net - device, and release the PCMCIA configuration. If the device is - still open, this will be postponed until it is closed. - -======================================================================*/ static void avmcs_release(struct pcmcia_device *link) { @@ -222,9 +159,7 @@ MODULE_DEVICE_TABLE(pcmcia, avmcs_ids); static struct pcmcia_driver avmcs_driver = { .owner = THIS_MODULE, - .drv = { - .name = "avm_cs", - }, + .name = "avm_cs", .probe = avmcs_probe, .remove = avmcs_detach, .id_table = avmcs_ids, diff --git a/drivers/isdn/hardware/eicon/divasmain.c b/drivers/isdn/hardware/eicon/divasmain.c index ed9c55506797..f332b60eff6b 100644 --- a/drivers/isdn/hardware/eicon/divasmain.c +++ b/drivers/isdn/hardware/eicon/divasmain.c @@ -15,7 +15,6 @@ #include <asm/uaccess.h> #include <asm/io.h> #include <linux/ioport.h> -#include <linux/workqueue.h> #include <linux/pci.h> #include <linux/interrupt.h> #include <linux/list.h> @@ -546,7 +545,6 @@ void diva_os_remove_soft_isr(diva_os_soft_isr_t * psoft_isr) void *mem; tasklet_kill(&pdpc->divas_task); - flush_scheduled_work(); mem = psoft_isr->object; psoft_isr->object = NULL; diva_os_free(0, mem); diff --git a/drivers/isdn/hisax/avma1_cs.c b/drivers/isdn/hisax/avma1_cs.c index 94263c22b874..ac4dd7857cbd 100644 --- a/drivers/isdn/hisax/avma1_cs.c +++ b/drivers/isdn/hisax/avma1_cs.c @@ -20,7 +20,6 @@ #include <asm/io.h> #include <asm/system.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/ds.h> #include "hisax_cfg.h" @@ -40,67 +39,22 @@ module_param(isdnprot, int, 0); /*====================================================================*/ -/* - The event() function is this driver's Card Services event handler. - It will be called by Card Services when an appropriate card status - event is received. The config() and release() entry points are - used to configure or release a socket, in response to card insertion - and ejection events. They are invoked from the skeleton event - handler. -*/ - static int avma1cs_config(struct pcmcia_device *link) __devinit ; static void avma1cs_release(struct pcmcia_device *link); - -/* - The attach() and detach() entry points are used to create and destroy - "instances" of the driver, where each instance represents everything - needed to manage one actual PCMCIA card. -*/ - static void avma1cs_detach(struct pcmcia_device *p_dev) __devexit ; - -/*====================================================================== - - avma1cs_attach() creates an "instance" of the driver, allocating - local data structures for one device. The device is registered - with Card Services. - - The dev_link structure is initialized, but we don't actually - configure the card at this point -- we wait until we receive a - card insertion event. - -======================================================================*/ - static int __devinit avma1cs_probe(struct pcmcia_device *p_dev) { dev_dbg(&p_dev->dev, "avma1cs_attach()\n"); - /* The io structure describes IO port mapping */ - p_dev->resource[0]->end = 16; - p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; - p_dev->resource[1]->end = 16; - p_dev->resource[1]->flags |= IO_DATA_PATH_WIDTH_16; - /* General socket configuration */ - p_dev->conf.Attributes = CONF_ENABLE_IRQ; - p_dev->conf.IntType = INT_MEMORY_AND_IO; - p_dev->conf.ConfigIndex = 1; - p_dev->conf.Present = PRESENT_OPTION; + p_dev->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; + p_dev->config_index = 1; + p_dev->config_regs = PRESENT_OPTION; return avma1cs_config(p_dev); } /* avma1cs_attach */ -/*====================================================================== - - This deletes a driver "instance". The device is de-registered - with Card Services. If it has been released, all local data - structures are freed. Otherwise, the structures will be freed - when the device is released. - -======================================================================*/ - static void __devexit avma1cs_detach(struct pcmcia_device *link) { dev_dbg(&link->dev, "avma1cs_detach(0x%p)\n", link); @@ -108,26 +62,13 @@ static void __devexit avma1cs_detach(struct pcmcia_device *link) kfree(link->priv); } /* avma1cs_detach */ -/*====================================================================== - - avma1cs_config() is scheduled to run after a CARD_INSERTION event - is received, to configure the PCMCIA socket, and to make the - ethernet device available to the system. - -======================================================================*/ - -static int avma1cs_configcheck(struct pcmcia_device *p_dev, - cistpl_cftable_entry_t *cf, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, - void *priv_data) +static int avma1cs_configcheck(struct pcmcia_device *p_dev, void *priv_data) { - if (cf->io.nwin <= 0) - return -ENODEV; - - p_dev->resource[0]->start = cf->io.win[0].base; - p_dev->resource[0]->end = cf->io.win[0].len; + p_dev->resource[0]->end = 16; + p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; + p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; p_dev->io_lines = 5; + return pcmcia_request_io(p_dev); } @@ -161,7 +102,7 @@ static int __devinit avma1cs_config(struct pcmcia_device *link) /* * configure the PCMCIA socket */ - i = pcmcia_request_configuration(link, &link->conf); + i = pcmcia_enable_device(link); if (i != 0) { pcmcia_disable_device(link); break; @@ -175,9 +116,6 @@ static int __devinit avma1cs_config(struct pcmcia_device *link) return -ENODEV; } - printk(KERN_NOTICE "avma1_cs: checking at i/o %#x, irq %d\n", - (unsigned int) link->resource[0]->start, link->irq); - icard.para[0] = link->irq; icard.para[1] = link->resource[0]->start; icard.protocol = isdnprot; @@ -196,14 +134,6 @@ static int __devinit avma1cs_config(struct pcmcia_device *link) return 0; } /* avma1cs_config */ -/*====================================================================== - - After a card is removed, avma1cs_release() will unregister the net - device, and release the PCMCIA configuration. If the device is - still open, this will be postponed until it is closed. - -======================================================================*/ - static void avma1cs_release(struct pcmcia_device *link) { unsigned long minor = (unsigned long) link->priv; @@ -216,7 +146,6 @@ static void avma1cs_release(struct pcmcia_device *link) pcmcia_disable_device(link); } /* avma1cs_release */ - static struct pcmcia_device_id avma1cs_ids[] = { PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN A", 0x95d42008, 0xadc9d4bb), PCMCIA_DEVICE_PROD_ID12("ISDN", "CARD", 0x8d9761c8, 0x01c5aa7b), @@ -226,19 +155,15 @@ MODULE_DEVICE_TABLE(pcmcia, avma1cs_ids); static struct pcmcia_driver avma1cs_driver = { .owner = THIS_MODULE, - .drv = { - .name = "avma1_cs", - }, + .name = "avma1_cs", .probe = avma1cs_probe, .remove = __devexit_p(avma1cs_detach), .id_table = avma1cs_ids, }; -/*====================================================================*/ - static int __init init_avma1_cs(void) { - return(pcmcia_register_driver(&avma1cs_driver)); + return pcmcia_register_driver(&avma1cs_driver); } static void __exit exit_avma1_cs(void) diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c index 6f9afcd5ca4e..b133378d4dc9 100644 --- a/drivers/isdn/hisax/config.c +++ b/drivers/isdn/hisax/config.c @@ -801,6 +801,16 @@ static void closecard(int cardnr) ll_unload(csta); } +static irqreturn_t card_irq(int intno, void *dev_id) +{ + struct IsdnCardState *cs = dev_id; + irqreturn_t ret = cs->irq_func(intno, cs); + + if (ret == IRQ_HANDLED) + cs->irq_cnt++; + return ret; +} + static int init_card(struct IsdnCardState *cs) { int irq_cnt, cnt = 3, ret; @@ -809,10 +819,10 @@ static int init_card(struct IsdnCardState *cs) ret = cs->cardmsg(cs, CARD_INIT, NULL); return(ret); } - irq_cnt = kstat_irqs(cs->irq); + irq_cnt = cs->irq_cnt = 0; printk(KERN_INFO "%s: IRQ %d count %d\n", CardType[cs->typ], cs->irq, irq_cnt); - if (request_irq(cs->irq, cs->irq_func, cs->irq_flags, "HiSax", cs)) { + if (request_irq(cs->irq, card_irq, cs->irq_flags, "HiSax", cs)) { printk(KERN_WARNING "HiSax: couldn't get interrupt %d\n", cs->irq); return 1; @@ -822,8 +832,8 @@ static int init_card(struct IsdnCardState *cs) /* Timeout 10ms */ msleep(10); printk(KERN_INFO "%s: IRQ %d count %d\n", - CardType[cs->typ], cs->irq, kstat_irqs(cs->irq)); - if (kstat_irqs(cs->irq) == irq_cnt) { + CardType[cs->typ], cs->irq, cs->irq_cnt); + if (cs->irq_cnt == irq_cnt) { printk(KERN_WARNING "%s: IRQ(%d) getting no interrupts during init %d\n", CardType[cs->typ], cs->irq, 4 - cnt); diff --git a/drivers/isdn/hisax/elsa_cs.c b/drivers/isdn/hisax/elsa_cs.c index b3c08aaf41c4..496d477af0f8 100644 --- a/drivers/isdn/hisax/elsa_cs.c +++ b/drivers/isdn/hisax/elsa_cs.c @@ -46,7 +46,6 @@ #include <asm/io.h> #include <asm/system.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/cisreg.h> #include <pcmcia/ds.h> @@ -64,26 +63,8 @@ MODULE_LICENSE("Dual MPL/GPL"); static int protocol = 2; /* EURO-ISDN Default */ module_param(protocol, int, 0); -/*====================================================================*/ - -/* - The event() function is this driver's Card Services event handler. - It will be called by Card Services when an appropriate card status - event is received. The config() and release() entry points are - used to configure or release a socket, in response to card insertion - and ejection events. They are invoked from the elsa_cs event - handler. -*/ - static int elsa_cs_config(struct pcmcia_device *link) __devinit ; static void elsa_cs_release(struct pcmcia_device *link); - -/* - The attach() and detach() entry points are used to create and destroy - "instances" of the driver, where each instance represents everything - needed to manage one actual PCMCIA card. -*/ - static void elsa_cs_detach(struct pcmcia_device *p_dev) __devexit; typedef struct local_info_t { @@ -92,18 +73,6 @@ typedef struct local_info_t { int cardnr; } local_info_t; -/*====================================================================== - - elsa_cs_attach() creates an "instance" of the driver, allocatingx - local data structures for one device. The device is registered - with Card Services. - - The dev_link structure is initialized, but we don't actually - configure the card at this point -- we wait until we receive a - card insertion event. - -======================================================================*/ - static int __devinit elsa_cs_probe(struct pcmcia_device *link) { local_info_t *local; @@ -119,31 +88,9 @@ static int __devinit elsa_cs_probe(struct pcmcia_device *link) local->cardnr = -1; - /* - General socket configuration defaults can go here. In this - client, we assume very little, and rely on the CIS for almost - everything. In most clients, many details (i.e., number, sizes, - and attributes of IO windows) are fixed by the nature of the - device, and can be hard-wired here. - */ - link->resource[0]->end = 8; - link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; - - link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.IntType = INT_MEMORY_AND_IO; - return elsa_cs_config(link); } /* elsa_cs_attach */ -/*====================================================================== - - This deletes a driver "instance". The device is de-registered - with Card Services. If it has been released, all local data - structures are freed. Otherwise, the structures will be freed - when the device is released. - -======================================================================*/ - static void __devexit elsa_cs_detach(struct pcmcia_device *link) { local_info_t *info = link->priv; @@ -156,27 +103,17 @@ static void __devexit elsa_cs_detach(struct pcmcia_device *link) kfree(info); } /* elsa_cs_detach */ -/*====================================================================== - - elsa_cs_config() is scheduled to run after a CARD_INSERTION event - is received, to configure the PCMCIA socket, and to make the - device available to the system. - -======================================================================*/ - -static int elsa_cs_configcheck(struct pcmcia_device *p_dev, - cistpl_cftable_entry_t *cf, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, - void *priv_data) +static int elsa_cs_configcheck(struct pcmcia_device *p_dev, void *priv_data) { int j; p_dev->io_lines = 3; + p_dev->resource[0]->end = 8; + p_dev->resource[0]->flags &= IO_DATA_PATH_WIDTH; + p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; - if ((cf->io.nwin > 0) && cf->io.win[0].base) { + if ((p_dev->resource[0]->end) && p_dev->resource[0]->start) { printk(KERN_INFO "(elsa_cs: looks like the 96 model)\n"); - p_dev->resource[0]->start = cf->io.win[0].base; if (!pcmcia_request_io(p_dev)) return 0; } else { @@ -199,6 +136,8 @@ static int __devinit elsa_cs_config(struct pcmcia_device *link) dev_dbg(&link->dev, "elsa_config(0x%p)\n", link); dev = link->priv; + link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; + i = pcmcia_loop_config(link, elsa_cs_configcheck, NULL); if (i != 0) goto failed; @@ -206,21 +145,10 @@ static int __devinit elsa_cs_config(struct pcmcia_device *link) if (!link->irq) goto failed; - i = pcmcia_request_configuration(link, &link->conf); + i = pcmcia_enable_device(link); if (i != 0) goto failed; - /* Finally, report what we've done */ - dev_info(&link->dev, "index 0x%02x: ", - link->conf.ConfigIndex); - if (link->conf.Attributes & CONF_ENABLE_IRQ) - printk(", irq %d", link->irq); - if (link->resource[0]) - printk(" & %pR", link->resource[0]); - if (link->resource[1]) - printk(" & %pR", link->resource[1]); - printk("\n"); - icard.para[0] = link->irq; icard.para[1] = link->resource[0]->start; icard.protocol = protocol; @@ -240,14 +168,6 @@ failed: return -ENODEV; } /* elsa_cs_config */ -/*====================================================================== - - After a card is removed, elsa_cs_release() will unregister the net - device, and release the PCMCIA configuration. If the device is - still open, this will be postponed until it is closed. - -======================================================================*/ - static void elsa_cs_release(struct pcmcia_device *link) { local_info_t *local = link->priv; @@ -291,9 +211,7 @@ MODULE_DEVICE_TABLE(pcmcia, elsa_ids); static struct pcmcia_driver elsa_cs_driver = { .owner = THIS_MODULE, - .drv = { - .name = "elsa_cs", - }, + .name = "elsa_cs", .probe = elsa_cs_probe, .remove = __devexit_p(elsa_cs_detach), .id_table = elsa_ids, diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h index 832a87855ffb..32ab3924aa73 100644 --- a/drivers/isdn/hisax/hisax.h +++ b/drivers/isdn/hisax/hisax.h @@ -959,6 +959,7 @@ struct IsdnCardState { u_long event; struct work_struct tqueue; struct timer_list dbusytimer; + unsigned int irq_cnt; #ifdef ERROR_STATISTIC int err_crc; int err_tx; diff --git a/drivers/isdn/hisax/sedlbauer_cs.c b/drivers/isdn/hisax/sedlbauer_cs.c index a024192b672a..360204bc2777 100644 --- a/drivers/isdn/hisax/sedlbauer_cs.c +++ b/drivers/isdn/hisax/sedlbauer_cs.c @@ -46,7 +46,6 @@ #include <asm/io.h> #include <asm/system.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/cisreg.h> #include <pcmcia/ds.h> @@ -64,26 +63,9 @@ MODULE_LICENSE("Dual MPL/GPL"); static int protocol = 2; /* EURO-ISDN Default */ module_param(protocol, int, 0); -/*====================================================================*/ - -/* - The event() function is this driver's Card Services event handler. - It will be called by Card Services when an appropriate card status - event is received. The config() and release() entry points are - used to configure or release a socket, in response to card - insertion and ejection events. They are invoked from the sedlbauer - event handler. -*/ - static int sedlbauer_config(struct pcmcia_device *link) __devinit ; static void sedlbauer_release(struct pcmcia_device *link); -/* - The attach() and detach() entry points are used to create and destroy - "instances" of the driver, where each instance represents everything - needed to manage one actual PCMCIA card. -*/ - static void sedlbauer_detach(struct pcmcia_device *p_dev) __devexit; typedef struct local_info_t { @@ -92,18 +74,6 @@ typedef struct local_info_t { int cardnr; } local_info_t; -/*====================================================================== - - sedlbauer_attach() creates an "instance" of the driver, allocating - local data structures for one device. The device is registered - with Card Services. - - The dev_link structure is initialized, but we don't actually - configure the card at this point -- we wait until we receive a - card insertion event. - -======================================================================*/ - static int __devinit sedlbauer_probe(struct pcmcia_device *link) { local_info_t *local; @@ -118,35 +88,9 @@ static int __devinit sedlbauer_probe(struct pcmcia_device *link) local->p_dev = link; link->priv = local; - /* - General socket configuration defaults can go here. In this - client, we assume very little, and rely on the CIS for almost - everything. In most clients, many details (i.e., number, sizes, - and attributes of IO windows) are fixed by the nature of the - device, and can be hard-wired here. - */ - - /* from old sedl_cs - */ - /* The io structure describes IO port mapping */ - link->resource[0]->end = 8; - link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; - - link->conf.Attributes = 0; - link->conf.IntType = INT_MEMORY_AND_IO; - return sedlbauer_config(link); } /* sedlbauer_attach */ -/*====================================================================== - - This deletes a driver "instance". The device is de-registered - with Card Services. If it has been released, all local data - structures are freed. Otherwise, the structures will be freed - when the device is released. - -======================================================================*/ - static void __devexit sedlbauer_detach(struct pcmcia_device *link) { dev_dbg(&link->dev, "sedlbauer_detach(0x%p)\n", link); @@ -158,70 +102,15 @@ static void __devexit sedlbauer_detach(struct pcmcia_device *link) kfree(link->priv); } /* sedlbauer_detach */ -/*====================================================================== - - sedlbauer_config() is scheduled to run after a CARD_INSERTION event - is received, to configure the PCMCIA socket, and to make the - device available to the system. - -======================================================================*/ -static int sedlbauer_config_check(struct pcmcia_device *p_dev, - cistpl_cftable_entry_t *cfg, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, - void *priv_data) +static int sedlbauer_config_check(struct pcmcia_device *p_dev, void *priv_data) { - if (cfg->index == 0) - return -ENODEV; - - /* Does this card need audio output? */ - if (cfg->flags & CISTPL_CFTABLE_AUDIO) { - p_dev->conf.Attributes |= CONF_ENABLE_SPKR; - p_dev->conf.Status = CCSR_AUDIO_ENA; - } + if (p_dev->config_index == 0) + return -EINVAL; - /* Use power settings for Vcc and Vpp if present */ - /* Note that the CIS values need to be rescaled */ - if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) { - if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM]/10000) - return -ENODEV; - } else if (dflt->vcc.present & (1<<CISTPL_POWER_VNOM)) { - if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM]/10000) - return -ENODEV; - } - - if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM)) - p_dev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM]/10000; - else if (dflt->vpp1.present & (1<<CISTPL_POWER_VNOM)) - p_dev->conf.Vpp = dflt->vpp1.param[CISTPL_POWER_VNOM]/10000; - - p_dev->conf.Attributes |= CONF_ENABLE_IRQ; - - /* IO window settings */ - p_dev->resource[0]->end = p_dev->resource[1]->end = 0; - if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) { - cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io; - p_dev->resource[0]->start = io->win[0].base; - p_dev->resource[0]->end = io->win[0].len; - p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; - p_dev->resource[0]->flags |= - pcmcia_io_cfg_data_width(io->flags); - if (io->nwin > 1) { - p_dev->resource[1]->flags = p_dev->resource[0]->flags; - p_dev->resource[1]->start = io->win[1].base; - p_dev->resource[1]->end = io->win[1].len; - } - /* This reserves IO space but doesn't actually enable it */ - p_dev->io_lines = 3; - if (pcmcia_request_io(p_dev) != 0) - return -ENODEV; - } - - return 0; + p_dev->io_lines = 3; + return pcmcia_request_io(p_dev); } - - static int __devinit sedlbauer_config(struct pcmcia_device *link) { int ret; @@ -229,44 +118,17 @@ static int __devinit sedlbauer_config(struct pcmcia_device *link) dev_dbg(&link->dev, "sedlbauer_config(0x%p)\n", link); - /* - In this loop, we scan the CIS for configuration table entries, - each of which describes a valid card configuration, including - voltage, IO window, memory window, and interrupt settings. - - We make no assumptions about the card to be configured: we use - just the information available in the CIS. In an ideal world, - this would work for any PCMCIA card, but it requires a complete - and accurate CIS. In practice, a driver usually "knows" most of - these things without consulting the CIS, and most client drivers - will only use the CIS to fill in implementation-defined details. - */ + link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_CHECK_VCC | + CONF_AUTO_SET_VPP | CONF_AUTO_AUDIO | CONF_AUTO_SET_IO; + ret = pcmcia_loop_config(link, sedlbauer_config_check, NULL); if (ret) goto failed; - /* - This actually configures the PCMCIA socket -- setting up - the I/O windows and the interrupt mapping, and putting the - card and host interface into "Memory and IO" mode. - */ - ret = pcmcia_request_configuration(link, &link->conf); + ret = pcmcia_enable_device(link); if (ret) goto failed; - /* Finally, report what we've done */ - dev_info(&link->dev, "index 0x%02x:", - link->conf.ConfigIndex); - if (link->conf.Vpp) - printk(", Vpp %d.%d", link->conf.Vpp/10, link->conf.Vpp%10); - if (link->conf.Attributes & CONF_ENABLE_IRQ) - printk(", irq %d", link->irq); - if (link->resource[0]) - printk(" & %pR", link->resource[0]); - if (link->resource[1]) - printk(" & %pR", link->resource[1]); - printk("\n"); - icard.para[0] = link->irq; icard.para[1] = link->resource[0]->start; icard.protocol = protocol; @@ -290,14 +152,6 @@ failed: } /* sedlbauer_config */ -/*====================================================================== - - After a card is removed, sedlbauer_release() will unregister the - device, and release the PCMCIA configuration. If the device is - still open, this will be postponed until it is closed. - -======================================================================*/ - static void sedlbauer_release(struct pcmcia_device *link) { local_info_t *local = link->priv; @@ -346,9 +200,7 @@ MODULE_DEVICE_TABLE(pcmcia, sedlbauer_ids); static struct pcmcia_driver sedlbauer_driver = { .owner = THIS_MODULE, - .drv = { - .name = "sedlbauer_cs", - }, + .name = "sedlbauer_cs", .probe = sedlbauer_probe, .remove = __devexit_p(sedlbauer_detach), .id_table = sedlbauer_ids, diff --git a/drivers/isdn/hisax/teles_cs.c b/drivers/isdn/hisax/teles_cs.c index 7296102ca255..282a4467ef19 100644 --- a/drivers/isdn/hisax/teles_cs.c +++ b/drivers/isdn/hisax/teles_cs.c @@ -27,7 +27,6 @@ #include <asm/io.h> #include <asm/system.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/cisreg.h> #include <pcmcia/ds.h> @@ -45,26 +44,8 @@ MODULE_LICENSE("GPL"); static int protocol = 2; /* EURO-ISDN Default */ module_param(protocol, int, 0); -/*====================================================================*/ - -/* - The event() function is this driver's Card Services event handler. - It will be called by Card Services when an appropriate card status - event is received. The config() and release() entry points are - used to configure or release a socket, in response to card insertion - and ejection events. They are invoked from the teles_cs event - handler. -*/ - static int teles_cs_config(struct pcmcia_device *link) __devinit ; static void teles_cs_release(struct pcmcia_device *link); - -/* - The attach() and detach() entry points are used to create and destroy - "instances" of the driver, where each instance represents everything - needed to manage one actual PCMCIA card. -*/ - static void teles_detach(struct pcmcia_device *p_dev) __devexit ; typedef struct local_info_t { @@ -73,18 +54,6 @@ typedef struct local_info_t { int cardnr; } local_info_t; -/*====================================================================== - - teles_attach() creates an "instance" of the driver, allocatingx - local data structures for one device. The device is registered - with Card Services. - - The dev_link structure is initialized, but we don't actually - configure the card at this point -- we wait until we receive a - card insertion event. - -======================================================================*/ - static int __devinit teles_probe(struct pcmcia_device *link) { local_info_t *local; @@ -99,31 +68,11 @@ static int __devinit teles_probe(struct pcmcia_device *link) local->p_dev = link; link->priv = local; - /* - General socket configuration defaults can go here. In this - client, we assume very little, and rely on the CIS for almost - everything. In most clients, many details (i.e., number, sizes, - and attributes of IO windows) are fixed by the nature of the - device, and can be hard-wired here. - */ - link->resource[0]->end = 96; - link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; - - link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.IntType = INT_MEMORY_AND_IO; + link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; return teles_cs_config(link); } /* teles_attach */ -/*====================================================================== - - This deletes a driver "instance". The device is de-registered - with Card Services. If it has been released, all local data - structures are freed. Otherwise, the structures will be freed - when the device is released. - -======================================================================*/ - static void __devexit teles_detach(struct pcmcia_device *link) { local_info_t *info = link->priv; @@ -136,27 +85,17 @@ static void __devexit teles_detach(struct pcmcia_device *link) kfree(info); } /* teles_detach */ -/*====================================================================== - - teles_cs_config() is scheduled to run after a CARD_INSERTION event - is received, to configure the PCMCIA socket, and to make the - device available to the system. - -======================================================================*/ - -static int teles_cs_configcheck(struct pcmcia_device *p_dev, - cistpl_cftable_entry_t *cf, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, - void *priv_data) +static int teles_cs_configcheck(struct pcmcia_device *p_dev, void *priv_data) { int j; p_dev->io_lines = 5; + p_dev->resource[0]->end = 96; + p_dev->resource[0]->flags &= IO_DATA_PATH_WIDTH; + p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; - if ((cf->io.nwin > 0) && cf->io.win[0].base) { + if ((p_dev->resource[0]->end) && p_dev->resource[0]->start) { printk(KERN_INFO "(teles_cs: looks like the 96 model)\n"); - p_dev->resource[0]->start = cf->io.win[0].base; if (!pcmcia_request_io(p_dev)) return 0; } else { @@ -186,21 +125,10 @@ static int __devinit teles_cs_config(struct pcmcia_device *link) if (!link->irq) goto cs_failed; - i = pcmcia_request_configuration(link, &link->conf); + i = pcmcia_enable_device(link); if (i != 0) goto cs_failed; - /* Finally, report what we've done */ - dev_info(&link->dev, "index 0x%02x:", - link->conf.ConfigIndex); - if (link->conf.Attributes & CONF_ENABLE_IRQ) - printk(", irq %d", link->irq); - if (link->resource[0]) - printk(" & %pR", link->resource[0]); - if (link->resource[1]) - printk(" & %pR", link->resource[1]); - printk("\n"); - icard.para[0] = link->irq; icard.para[1] = link->resource[0]->start; icard.protocol = protocol; @@ -222,14 +150,6 @@ cs_failed: return -ENODEV; } /* teles_cs_config */ -/*====================================================================== - - After a card is removed, teles_cs_release() will unregister the net - device, and release the PCMCIA configuration. If the device is - still open, this will be postponed until it is closed. - -======================================================================*/ - static void teles_cs_release(struct pcmcia_device *link) { local_info_t *local = link->priv; @@ -273,9 +193,7 @@ MODULE_DEVICE_TABLE(pcmcia, teles_ids); static struct pcmcia_driver teles_cs_driver = { .owner = THIS_MODULE, - .drv = { - .name = "teles_cs", - }, + .name = "teles_cs", .probe = teles_probe, .remove = __devexit_p(teles_detach), .id_table = teles_ids, diff --git a/drivers/isdn/mISDN/timerdev.c b/drivers/isdn/mISDN/timerdev.c index de43c8c70ad0..859c81e9483b 100644 --- a/drivers/isdn/mISDN/timerdev.c +++ b/drivers/isdn/mISDN/timerdev.c @@ -267,6 +267,7 @@ static const struct file_operations mISDN_fops = { .unlocked_ioctl = mISDN_ioctl, .open = mISDN_open, .release = mISDN_close, + .llseek = no_llseek, }; static struct miscdevice mISDNtimer = { diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index e4112622e5a2..cc2a88d5192f 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -304,13 +304,22 @@ config LEDS_MC13783 config LEDS_NS2 tristate "LED support for Network Space v2 GPIO LEDs" - depends on MACH_NETSPACE_V2 || MACH_INETSPACE_V2 || MACH_NETSPACE_MAX_V2 + depends on MACH_NETSPACE_V2 || MACH_INETSPACE_V2 || MACH_NETSPACE_MAX_V2 || D2NET_V2 default y help This option enable support for the dual-GPIO LED found on the Network Space v2 board (and parents). This include Internet Space v2, Network Space (Max) v2 and d2 Network v2 boards. +config LEDS_NETXBIG + tristate "LED support for Big Network series LEDs" + depends on MACH_NET2BIG_V2 || MACH_NET5BIG_V2 + default y + help + This option enable support for LEDs found on the LaCie 2Big + and 5Big Network v2 boards. The LEDs are wired to a CPLD and are + controlled through a GPIO extension bus. + config LEDS_TRIGGERS bool "LED Trigger support" help diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index 7d6b95831f8e..9c96db40ef6d 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_LEDS_ADP5520) += leds-adp5520.o obj-$(CONFIG_LEDS_DELL_NETBOOKS) += dell-led.o obj-$(CONFIG_LEDS_MC13783) += leds-mc13783.o obj-$(CONFIG_LEDS_NS2) += leds-ns2.o +obj-$(CONFIG_LEDS_NETXBIG) += leds-netxbig.o # LED SPI Drivers obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o diff --git a/drivers/leds/leds-netxbig.c b/drivers/leds/leds-netxbig.c new file mode 100644 index 000000000000..f2e51c134399 --- /dev/null +++ b/drivers/leds/leds-netxbig.c @@ -0,0 +1,449 @@ +/* + * leds-netxbig.c - Driver for the 2Big and 5Big Network series LEDs + * + * Copyright (C) 2010 LaCie + * + * Author: Simon Guinot <sguinot@lacie.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/irq.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/platform_device.h> +#include <linux/gpio.h> +#include <linux/leds.h> +#include <mach/leds-netxbig.h> + +/* + * GPIO extension bus. + */ + +static DEFINE_SPINLOCK(gpio_ext_lock); + +static void gpio_ext_set_addr(struct netxbig_gpio_ext *gpio_ext, int addr) +{ + int pin; + + for (pin = 0; pin < gpio_ext->num_addr; pin++) + gpio_set_value(gpio_ext->addr[pin], (addr >> pin) & 1); +} + +static void gpio_ext_set_data(struct netxbig_gpio_ext *gpio_ext, int data) +{ + int pin; + + for (pin = 0; pin < gpio_ext->num_data; pin++) + gpio_set_value(gpio_ext->data[pin], (data >> pin) & 1); +} + +static void gpio_ext_enable_select(struct netxbig_gpio_ext *gpio_ext) +{ + /* Enable select is done on the raising edge. */ + gpio_set_value(gpio_ext->enable, 0); + gpio_set_value(gpio_ext->enable, 1); +} + +static void gpio_ext_set_value(struct netxbig_gpio_ext *gpio_ext, + int addr, int value) +{ + unsigned long flags; + + spin_lock_irqsave(&gpio_ext_lock, flags); + gpio_ext_set_addr(gpio_ext, addr); + gpio_ext_set_data(gpio_ext, value); + gpio_ext_enable_select(gpio_ext); + spin_unlock_irqrestore(&gpio_ext_lock, flags); +} + +static int __devinit gpio_ext_init(struct netxbig_gpio_ext *gpio_ext) +{ + int err; + int i; + + if (unlikely(!gpio_ext)) + return -EINVAL; + + /* Configure address GPIOs. */ + for (i = 0; i < gpio_ext->num_addr; i++) { + err = gpio_request(gpio_ext->addr[i], "GPIO extension addr"); + if (err) + goto err_free_addr; + err = gpio_direction_output(gpio_ext->addr[i], 0); + if (err) { + gpio_free(gpio_ext->addr[i]); + goto err_free_addr; + } + } + /* Configure data GPIOs. */ + for (i = 0; i < gpio_ext->num_data; i++) { + err = gpio_request(gpio_ext->data[i], "GPIO extension data"); + if (err) + goto err_free_data; + err = gpio_direction_output(gpio_ext->data[i], 0); + if (err) { + gpio_free(gpio_ext->data[i]); + goto err_free_data; + } + } + /* Configure "enable select" GPIO. */ + err = gpio_request(gpio_ext->enable, "GPIO extension enable"); + if (err) + goto err_free_data; + err = gpio_direction_output(gpio_ext->enable, 0); + if (err) { + gpio_free(gpio_ext->enable); + goto err_free_data; + } + + return 0; + +err_free_data: + for (i = i - 1; i >= 0; i--) + gpio_free(gpio_ext->data[i]); + i = gpio_ext->num_addr; +err_free_addr: + for (i = i - 1; i >= 0; i--) + gpio_free(gpio_ext->addr[i]); + + return err; +} + +static void __devexit gpio_ext_free(struct netxbig_gpio_ext *gpio_ext) +{ + int i; + + gpio_free(gpio_ext->enable); + for (i = gpio_ext->num_addr - 1; i >= 0; i--) + gpio_free(gpio_ext->addr[i]); + for (i = gpio_ext->num_data - 1; i >= 0; i--) + gpio_free(gpio_ext->data[i]); +} + +/* + * Class LED driver. + */ + +struct netxbig_led_data { + struct netxbig_gpio_ext *gpio_ext; + struct led_classdev cdev; + int mode_addr; + int *mode_val; + int bright_addr; + int bright_max; + struct netxbig_led_timer *timer; + int num_timer; + enum netxbig_led_mode mode; + int sata; + spinlock_t lock; +}; + +static int netxbig_led_get_timer_mode(enum netxbig_led_mode *mode, + unsigned long delay_on, + unsigned long delay_off, + struct netxbig_led_timer *timer, + int num_timer) +{ + int i; + + for (i = 0; i < num_timer; i++) { + if (timer[i].delay_on == delay_on && + timer[i].delay_off == delay_off) { + *mode = timer[i].mode; + return 0; + } + } + return -EINVAL; +} + +static int netxbig_led_blink_set(struct led_classdev *led_cdev, + unsigned long *delay_on, + unsigned long *delay_off) +{ + struct netxbig_led_data *led_dat = + container_of(led_cdev, struct netxbig_led_data, cdev); + enum netxbig_led_mode mode; + int mode_val; + int ret; + + /* Look for a LED mode with the requested timer frequency. */ + ret = netxbig_led_get_timer_mode(&mode, *delay_on, *delay_off, + led_dat->timer, led_dat->num_timer); + if (ret < 0) + return ret; + + mode_val = led_dat->mode_val[mode]; + if (mode_val == NETXBIG_LED_INVALID_MODE) + return -EINVAL; + + spin_lock_irq(&led_dat->lock); + + gpio_ext_set_value(led_dat->gpio_ext, led_dat->mode_addr, mode_val); + led_dat->mode = mode; + + spin_unlock_irq(&led_dat->lock); + + return 0; +} + +static void netxbig_led_set(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct netxbig_led_data *led_dat = + container_of(led_cdev, struct netxbig_led_data, cdev); + enum netxbig_led_mode mode; + int mode_val, bright_val; + int set_brightness = 1; + unsigned long flags; + + spin_lock_irqsave(&led_dat->lock, flags); + + if (value == LED_OFF) { + mode = NETXBIG_LED_OFF; + set_brightness = 0; + } else { + if (led_dat->sata) + mode = NETXBIG_LED_SATA; + else if (led_dat->mode == NETXBIG_LED_OFF) + mode = NETXBIG_LED_ON; + else /* Keep 'timer' mode. */ + mode = led_dat->mode; + } + mode_val = led_dat->mode_val[mode]; + + gpio_ext_set_value(led_dat->gpio_ext, led_dat->mode_addr, mode_val); + led_dat->mode = mode; + /* + * Note that the brightness register is shared between all the + * SATA LEDs. So, change the brightness setting for a single + * SATA LED will affect all the others. + */ + if (set_brightness) { + bright_val = DIV_ROUND_UP(value * led_dat->bright_max, + LED_FULL); + gpio_ext_set_value(led_dat->gpio_ext, + led_dat->bright_addr, bright_val); + } + + spin_unlock_irqrestore(&led_dat->lock, flags); +} + +static ssize_t netxbig_led_sata_store(struct device *dev, + struct device_attribute *attr, + const char *buff, size_t count) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct netxbig_led_data *led_dat = + container_of(led_cdev, struct netxbig_led_data, cdev); + unsigned long enable; + enum netxbig_led_mode mode; + int mode_val; + int ret; + + ret = strict_strtoul(buff, 10, &enable); + if (ret < 0) + return ret; + + enable = !!enable; + + spin_lock_irq(&led_dat->lock); + + if (led_dat->sata == enable) { + ret = count; + goto exit_unlock; + } + + if (led_dat->mode != NETXBIG_LED_ON && + led_dat->mode != NETXBIG_LED_SATA) + mode = led_dat->mode; /* Keep modes 'off' and 'timer'. */ + else if (enable) + mode = NETXBIG_LED_SATA; + else + mode = NETXBIG_LED_ON; + + mode_val = led_dat->mode_val[mode]; + if (mode_val == NETXBIG_LED_INVALID_MODE) { + ret = -EINVAL; + goto exit_unlock; + } + + gpio_ext_set_value(led_dat->gpio_ext, led_dat->mode_addr, mode_val); + led_dat->mode = mode; + led_dat->sata = enable; + + ret = count; + +exit_unlock: + spin_unlock_irq(&led_dat->lock); + + return ret; +} + +static ssize_t netxbig_led_sata_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct netxbig_led_data *led_dat = + container_of(led_cdev, struct netxbig_led_data, cdev); + + return sprintf(buf, "%d\n", led_dat->sata); +} + +static DEVICE_ATTR(sata, 0644, netxbig_led_sata_show, netxbig_led_sata_store); + +static void __devexit delete_netxbig_led(struct netxbig_led_data *led_dat) +{ + if (led_dat->mode_val[NETXBIG_LED_SATA] != NETXBIG_LED_INVALID_MODE) + device_remove_file(led_dat->cdev.dev, &dev_attr_sata); + led_classdev_unregister(&led_dat->cdev); +} + +static int __devinit +create_netxbig_led(struct platform_device *pdev, + struct netxbig_led_data *led_dat, + const struct netxbig_led *template) +{ + struct netxbig_led_platform_data *pdata = pdev->dev.platform_data; + int ret; + + spin_lock_init(&led_dat->lock); + led_dat->gpio_ext = pdata->gpio_ext; + led_dat->cdev.name = template->name; + led_dat->cdev.default_trigger = template->default_trigger; + led_dat->cdev.blink_set = netxbig_led_blink_set; + led_dat->cdev.brightness_set = netxbig_led_set; + /* + * Because the GPIO extension bus don't allow to read registers + * value, there is no way to probe the LED initial state. + * So, the initial sysfs LED value for the "brightness" and "sata" + * attributes are inconsistent. + * + * Note that the initial LED state can't be reconfigured. + * The reason is that the LED behaviour must stay uniform during + * the whole boot process (bootloader+linux). + */ + led_dat->sata = 0; + led_dat->cdev.brightness = LED_OFF; + led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME; + led_dat->mode_addr = template->mode_addr; + led_dat->mode_val = template->mode_val; + led_dat->bright_addr = template->bright_addr; + led_dat->bright_max = (1 << pdata->gpio_ext->num_data) - 1; + led_dat->timer = pdata->timer; + led_dat->num_timer = pdata->num_timer; + + ret = led_classdev_register(&pdev->dev, &led_dat->cdev); + if (ret < 0) + return ret; + + /* + * If available, expose the SATA activity blink capability through + * a "sata" sysfs attribute. + */ + if (led_dat->mode_val[NETXBIG_LED_SATA] != NETXBIG_LED_INVALID_MODE) { + ret = device_create_file(led_dat->cdev.dev, &dev_attr_sata); + if (ret) + led_classdev_unregister(&led_dat->cdev); + } + + return ret; +} + +static int __devinit netxbig_led_probe(struct platform_device *pdev) +{ + struct netxbig_led_platform_data *pdata = pdev->dev.platform_data; + struct netxbig_led_data *leds_data; + int i; + int ret; + + if (!pdata) + return -EINVAL; + + leds_data = kzalloc(sizeof(struct netxbig_led_data) * pdata->num_leds, + GFP_KERNEL); + if (!leds_data) + return -ENOMEM; + + ret = gpio_ext_init(pdata->gpio_ext); + if (ret < 0) + goto err_free_data; + + for (i = 0; i < pdata->num_leds; i++) { + ret = create_netxbig_led(pdev, &leds_data[i], &pdata->leds[i]); + if (ret < 0) + goto err_free_leds; + } + + platform_set_drvdata(pdev, leds_data); + + return 0; + +err_free_leds: + for (i = i - 1; i >= 0; i--) + delete_netxbig_led(&leds_data[i]); + + gpio_ext_free(pdata->gpio_ext); +err_free_data: + kfree(leds_data); + + return ret; +} + +static int __devexit netxbig_led_remove(struct platform_device *pdev) +{ + struct netxbig_led_platform_data *pdata = pdev->dev.platform_data; + struct netxbig_led_data *leds_data; + int i; + + leds_data = platform_get_drvdata(pdev); + + for (i = 0; i < pdata->num_leds; i++) + delete_netxbig_led(&leds_data[i]); + + gpio_ext_free(pdata->gpio_ext); + kfree(leds_data); + + return 0; +} + +static struct platform_driver netxbig_led_driver = { + .probe = netxbig_led_probe, + .remove = __devexit_p(netxbig_led_remove), + .driver = { + .name = "leds-netxbig", + .owner = THIS_MODULE, + }, +}; +MODULE_ALIAS("platform:leds-netxbig"); + +static int __init netxbig_led_init(void) +{ + return platform_driver_register(&netxbig_led_driver); +} + +static void __exit netxbig_led_exit(void) +{ + platform_driver_unregister(&netxbig_led_driver); +} + +module_init(netxbig_led_init); +module_exit(netxbig_led_exit); + +MODULE_AUTHOR("Simon Guinot <sguinot@lacie.com>"); +MODULE_DESCRIPTION("LED driver for LaCie xBig Network boards"); +MODULE_LICENSE("GPL"); diff --git a/drivers/leds/leds-ns2.c b/drivers/leds/leds-ns2.c index 350eb34f049c..f77d48d0b3e4 100644 --- a/drivers/leds/leds-ns2.c +++ b/drivers/leds/leds-ns2.c @@ -141,10 +141,12 @@ static ssize_t ns2_led_sata_store(struct device *dev, struct device_attribute *attr, const char *buff, size_t count) { + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct ns2_led_data *led_dat = + container_of(led_cdev, struct ns2_led_data, cdev); int ret; unsigned long enable; enum ns2_led_modes mode; - struct ns2_led_data *led_dat = dev_get_drvdata(dev); ret = strict_strtoul(buff, 10, &enable); if (ret < 0) @@ -172,7 +174,9 @@ static ssize_t ns2_led_sata_store(struct device *dev, static ssize_t ns2_led_sata_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct ns2_led_data *led_dat = dev_get_drvdata(dev); + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct ns2_led_data *led_dat = + container_of(led_cdev, struct ns2_led_data, cdev); return sprintf(buf, "%d\n", led_dat->sata); } @@ -234,7 +238,6 @@ create_ns2_led(struct platform_device *pdev, struct ns2_led_data *led_dat, if (ret < 0) goto err_free_slow; - dev_set_drvdata(led_dat->cdev.dev, led_dat); ret = device_create_file(led_dat->cdev.dev, &dev_attr_sata); if (ret < 0) goto err_free_cdev; diff --git a/drivers/lguest/lguest_user.c b/drivers/lguest/lguest_user.c index 85b714df8eae..3c781cdddda9 100644 --- a/drivers/lguest/lguest_user.c +++ b/drivers/lguest/lguest_user.c @@ -514,6 +514,7 @@ static const struct file_operations lguest_fops = { .release = close, .write = write, .read = read, + .llseek = default_llseek, }; /* diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c index 1c4ee6e77937..75049e765191 100644 --- a/drivers/macintosh/adb.c +++ b/drivers/macintosh/adb.c @@ -24,7 +24,6 @@ #include <linux/fs.h> #include <linux/mm.h> #include <linux/sched.h> -#include <linux/smp_lock.h> #include <linux/adb.h> #include <linux/cuda.h> #include <linux/pmu.h> @@ -55,6 +54,7 @@ extern struct adb_driver adb_iop_driver; extern struct adb_driver via_pmu_driver; extern struct adb_driver macio_adb_driver; +static DEFINE_MUTEX(adb_mutex); static struct adb_driver *adb_driver_list[] = { #ifdef CONFIG_ADB_MACII &via_macii_driver, @@ -83,7 +83,7 @@ static struct adb_driver *adb_controller; BLOCKING_NOTIFIER_HEAD(adb_client_list); static int adb_got_sleep; static int adb_inited; -static DECLARE_MUTEX(adb_probe_mutex); +static DEFINE_SEMAPHORE(adb_probe_mutex); static int sleepy_trackpad; static int autopoll_devs; int __adb_probe_sync; @@ -647,7 +647,7 @@ static int adb_open(struct inode *inode, struct file *file) struct adbdev_state *state; int ret = 0; - lock_kernel(); + mutex_lock(&adb_mutex); if (iminor(inode) > 0 || adb_controller == NULL) { ret = -ENXIO; goto out; @@ -665,7 +665,7 @@ static int adb_open(struct inode *inode, struct file *file) state->inuse = 1; out: - unlock_kernel(); + mutex_unlock(&adb_mutex); return ret; } @@ -674,7 +674,7 @@ static int adb_release(struct inode *inode, struct file *file) struct adbdev_state *state = file->private_data; unsigned long flags; - lock_kernel(); + mutex_lock(&adb_mutex); if (state) { file->private_data = NULL; spin_lock_irqsave(&state->lock, flags); @@ -687,7 +687,7 @@ static int adb_release(struct inode *inode, struct file *file) spin_unlock_irqrestore(&state->lock, flags); } } - unlock_kernel(); + mutex_unlock(&adb_mutex); return 0; } diff --git a/drivers/macintosh/ans-lcd.c b/drivers/macintosh/ans-lcd.c index a3d25da2f275..1a57e88a38f7 100644 --- a/drivers/macintosh/ans-lcd.c +++ b/drivers/macintosh/ans-lcd.c @@ -137,6 +137,7 @@ const struct file_operations anslcd_fops = { .write = anslcd_write, .unlocked_ioctl = anslcd_ioctl, .open = anslcd_open, + .llseek = default_llseek, }; static struct miscdevice anslcd_dev = { diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c index e58c3d33e035..290cb325a94c 100644 --- a/drivers/macintosh/smu.c +++ b/drivers/macintosh/smu.c @@ -19,7 +19,6 @@ * the userland interface */ -#include <linux/smp_lock.h> #include <linux/types.h> #include <linux/kernel.h> #include <linux/device.h> @@ -97,6 +96,7 @@ struct smu_device { * I don't think there will ever be more than one SMU, so * for now, just hard code that */ +static DEFINE_MUTEX(smu_mutex); static struct smu_device *smu; static DEFINE_MUTEX(smu_part_access); static int smu_irq_inited; @@ -1095,12 +1095,12 @@ static int smu_open(struct inode *inode, struct file *file) pp->mode = smu_file_commands; init_waitqueue_head(&pp->wait); - lock_kernel(); + mutex_lock(&smu_mutex); spin_lock_irqsave(&smu_clist_lock, flags); list_add(&pp->list, &smu_clist); spin_unlock_irqrestore(&smu_clist_lock, flags); file->private_data = pp; - unlock_kernel(); + mutex_unlock(&smu_mutex); return 0; } diff --git a/drivers/macintosh/via-pmu-led.c b/drivers/macintosh/via-pmu-led.c index d242976bcfe7..19c371809d77 100644 --- a/drivers/macintosh/via-pmu-led.c +++ b/drivers/macintosh/via-pmu-led.c @@ -92,8 +92,10 @@ static int __init via_pmu_led_init(void) if (dt == NULL) return -ENODEV; model = of_get_property(dt, "model", NULL); - if (model == NULL) + if (model == NULL) { + of_node_put(dt); return -ENODEV; + } if (strncmp(model, "PowerBook", strlen("PowerBook")) != 0 && strncmp(model, "iBook", strlen("iBook")) != 0 && strcmp(model, "PowerMac7,2") != 0 && diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index 2d17e76066bd..cd29c8248386 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -18,7 +18,7 @@ * */ #include <stdarg.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/types.h> #include <linux/errno.h> #include <linux/kernel.h> @@ -73,6 +73,7 @@ /* How many iterations between battery polls */ #define BATTERY_POLLING_COUNT 2 +static DEFINE_MUTEX(pmu_info_proc_mutex); static volatile unsigned char __iomem *via; /* VIA registers - spaced 0x200 bytes apart */ @@ -2078,7 +2079,7 @@ pmu_open(struct inode *inode, struct file *file) pp->rb_get = pp->rb_put = 0; spin_lock_init(&pp->lock); init_waitqueue_head(&pp->wait); - lock_kernel(); + mutex_lock(&pmu_info_proc_mutex); spin_lock_irqsave(&all_pvt_lock, flags); #if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) pp->backlight_locker = 0; @@ -2086,7 +2087,7 @@ pmu_open(struct inode *inode, struct file *file) list_add(&pp->list, &all_pmu_pvt); spin_unlock_irqrestore(&all_pvt_lock, flags); file->private_data = pp; - unlock_kernel(); + mutex_unlock(&pmu_info_proc_mutex); return 0; } @@ -2343,9 +2344,9 @@ static long pmu_unlocked_ioctl(struct file *filp, { int ret; - lock_kernel(); + mutex_lock(&pmu_info_proc_mutex); ret = pmu_ioctl(filp, cmd, arg); - unlock_kernel(); + mutex_unlock(&pmu_info_proc_mutex); return ret; } @@ -2398,6 +2399,7 @@ static const struct file_operations pmu_device_fops = { #endif .open = pmu_open, .release = pmu_release, + .llseek = noop_llseek, }; static struct miscdevice pmu_device = { diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 368e8e98f705..d5b0e4c0e702 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -1278,7 +1278,7 @@ static int crypt_map(struct dm_target *ti, struct bio *bio, struct dm_crypt_io *io; struct crypt_config *cc; - if (unlikely(bio_empty_barrier(bio))) { + if (bio->bi_rw & REQ_FLUSH) { cc = ti->private; bio->bi_bdev = cc->dev->bdev; return DM_MAPIO_REMAPPED; diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c index 0590c75b0ab6..136d4f71a116 100644 --- a/drivers/md/dm-io.c +++ b/drivers/md/dm-io.c @@ -31,7 +31,6 @@ struct dm_io_client { */ struct io { unsigned long error_bits; - unsigned long eopnotsupp_bits; atomic_t count; struct task_struct *sleeper; struct dm_io_client *client; @@ -130,11 +129,8 @@ static void retrieve_io_and_region_from_bio(struct bio *bio, struct io **io, *---------------------------------------------------------------*/ static void dec_count(struct io *io, unsigned int region, int error) { - if (error) { + if (error) set_bit(region, &io->error_bits); - if (error == -EOPNOTSUPP) - set_bit(region, &io->eopnotsupp_bits); - } if (atomic_dec_and_test(&io->count)) { if (io->sleeper) @@ -310,8 +306,8 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where, sector_t remaining = where->count; /* - * where->count may be zero if rw holds a write barrier and we - * need to send a zero-sized barrier. + * where->count may be zero if rw holds a flush and we need to + * send a zero-sized flush. */ do { /* @@ -364,7 +360,7 @@ static void dispatch_io(int rw, unsigned int num_regions, */ for (i = 0; i < num_regions; i++) { *dp = old_pages; - if (where[i].count || (rw & REQ_HARDBARRIER)) + if (where[i].count || (rw & REQ_FLUSH)) do_region(rw, i, where + i, dp, io); } @@ -393,9 +389,7 @@ static int sync_io(struct dm_io_client *client, unsigned int num_regions, return -EIO; } -retry: io->error_bits = 0; - io->eopnotsupp_bits = 0; atomic_set(&io->count, 1); /* see dispatch_io() */ io->sleeper = current; io->client = client; @@ -412,11 +406,6 @@ retry: } set_current_state(TASK_RUNNING); - if (io->eopnotsupp_bits && (rw & REQ_HARDBARRIER)) { - rw &= ~REQ_HARDBARRIER; - goto retry; - } - if (error_bits) *error_bits = io->error_bits; @@ -437,7 +426,6 @@ static int async_io(struct dm_io_client *client, unsigned int num_regions, io = mempool_alloc(client->pool, GFP_NOIO); io->error_bits = 0; - io->eopnotsupp_bits = 0; atomic_set(&io->count, 1); /* see dispatch_io() */ io->sleeper = NULL; io->client = client; diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c index 3e39193e5036..4b54618b4159 100644 --- a/drivers/md/dm-ioctl.c +++ b/drivers/md/dm-ioctl.c @@ -1596,6 +1596,7 @@ static const struct file_operations _ctl_fops = { .unlocked_ioctl = dm_ctl_ioctl, .compat_ioctl = dm_compat_ctl_ioctl, .owner = THIS_MODULE, + .llseek = noop_llseek, }; static struct miscdevice _dm_misc = { diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c index 5a08be0222db..33420e68d153 100644 --- a/drivers/md/dm-log.c +++ b/drivers/md/dm-log.c @@ -300,7 +300,7 @@ static int flush_header(struct log_c *lc) .count = 0, }; - lc->io_req.bi_rw = WRITE_BARRIER; + lc->io_req.bi_rw = WRITE_FLUSH; return dm_io(&lc->io_req, 1, &null_location, NULL); } diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index 7c081bcbc3cf..19a59b041c27 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c @@ -259,7 +259,7 @@ static int mirror_flush(struct dm_target *ti) struct dm_io_region io[ms->nr_mirrors]; struct mirror *m; struct dm_io_request io_req = { - .bi_rw = WRITE_BARRIER, + .bi_rw = WRITE_FLUSH, .mem.type = DM_IO_KMEM, .mem.ptr.bvec = NULL, .client = ms->io_client, @@ -629,7 +629,7 @@ static void do_write(struct mirror_set *ms, struct bio *bio) struct dm_io_region io[ms->nr_mirrors], *dest = io; struct mirror *m; struct dm_io_request io_req = { - .bi_rw = WRITE | (bio->bi_rw & WRITE_BARRIER), + .bi_rw = WRITE | (bio->bi_rw & WRITE_FLUSH_FUA), .mem.type = DM_IO_BVEC, .mem.ptr.bvec = bio->bi_io_vec + bio->bi_idx, .notify.fn = write_callback, @@ -670,7 +670,7 @@ static void do_writes(struct mirror_set *ms, struct bio_list *writes) bio_list_init(&requeue); while ((bio = bio_list_pop(writes))) { - if (unlikely(bio_empty_barrier(bio))) { + if (bio->bi_rw & REQ_FLUSH) { bio_list_add(&sync, bio); continue; } @@ -1203,7 +1203,7 @@ static int mirror_end_io(struct dm_target *ti, struct bio *bio, * We need to dec pending if this was a write. */ if (rw == WRITE) { - if (likely(!bio_empty_barrier(bio))) + if (!(bio->bi_rw & REQ_FLUSH)) dm_rh_dec(ms->rh, map_context->ll); return error; } diff --git a/drivers/md/dm-region-hash.c b/drivers/md/dm-region-hash.c index bd5c58b28868..dad011aed0c9 100644 --- a/drivers/md/dm-region-hash.c +++ b/drivers/md/dm-region-hash.c @@ -81,9 +81,9 @@ struct dm_region_hash { struct list_head failed_recovered_regions; /* - * If there was a barrier failure no regions can be marked clean. + * If there was a flush failure no regions can be marked clean. */ - int barrier_failure; + int flush_failure; void *context; sector_t target_begin; @@ -217,7 +217,7 @@ struct dm_region_hash *dm_region_hash_create( INIT_LIST_HEAD(&rh->quiesced_regions); INIT_LIST_HEAD(&rh->recovered_regions); INIT_LIST_HEAD(&rh->failed_recovered_regions); - rh->barrier_failure = 0; + rh->flush_failure = 0; rh->region_pool = mempool_create_kmalloc_pool(MIN_REGIONS, sizeof(struct dm_region)); @@ -399,8 +399,8 @@ void dm_rh_mark_nosync(struct dm_region_hash *rh, struct bio *bio) region_t region = dm_rh_bio_to_region(rh, bio); int recovering = 0; - if (bio_empty_barrier(bio)) { - rh->barrier_failure = 1; + if (bio->bi_rw & REQ_FLUSH) { + rh->flush_failure = 1; return; } @@ -524,7 +524,7 @@ void dm_rh_inc_pending(struct dm_region_hash *rh, struct bio_list *bios) struct bio *bio; for (bio = bios->head; bio; bio = bio->bi_next) { - if (bio_empty_barrier(bio)) + if (bio->bi_rw & REQ_FLUSH) continue; rh_inc(rh, dm_rh_bio_to_region(rh, bio)); } @@ -555,9 +555,9 @@ void dm_rh_dec(struct dm_region_hash *rh, region_t region) */ /* do nothing for DM_RH_NOSYNC */ - if (unlikely(rh->barrier_failure)) { + if (unlikely(rh->flush_failure)) { /* - * If a write barrier failed some time ago, we + * If a write flush failed some time ago, we * don't know whether or not this write made it * to the disk, so we must resync the device. */ diff --git a/drivers/md/dm-snap-persistent.c b/drivers/md/dm-snap-persistent.c index cc2bdb83f9ad..0b61792a2780 100644 --- a/drivers/md/dm-snap-persistent.c +++ b/drivers/md/dm-snap-persistent.c @@ -687,7 +687,7 @@ static void persistent_commit_exception(struct dm_exception_store *store, /* * Commit exceptions to disk. */ - if (ps->valid && area_io(ps, WRITE_BARRIER)) + if (ps->valid && area_io(ps, WRITE_FLUSH_FUA)) ps->valid = 0; /* diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index 5974d3094d97..53cf79d8bcbc 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c @@ -706,8 +706,6 @@ static int dm_add_exception(void *context, chunk_t old, chunk_t new) return 0; } -#define min_not_zero(l, r) (((l) == 0) ? (r) : (((r) == 0) ? (l) : min(l, r))) - /* * Return a minimum chunk size of all snapshots that have the specified origin. * Return zero if the origin has no snapshots. @@ -1587,7 +1585,7 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio, chunk_t chunk; struct dm_snap_pending_exception *pe = NULL; - if (unlikely(bio_empty_barrier(bio))) { + if (bio->bi_rw & REQ_FLUSH) { bio->bi_bdev = s->cow->bdev; return DM_MAPIO_REMAPPED; } @@ -1691,7 +1689,7 @@ static int snapshot_merge_map(struct dm_target *ti, struct bio *bio, int r = DM_MAPIO_REMAPPED; chunk_t chunk; - if (unlikely(bio_empty_barrier(bio))) { + if (bio->bi_rw & REQ_FLUSH) { if (!map_context->target_request_nr) bio->bi_bdev = s->origin->bdev; else @@ -2135,7 +2133,7 @@ static int origin_map(struct dm_target *ti, struct bio *bio, struct dm_dev *dev = ti->private; bio->bi_bdev = dev->bdev; - if (unlikely(bio_empty_barrier(bio))) + if (bio->bi_rw & REQ_FLUSH) return DM_MAPIO_REMAPPED; /* Only tell snapshots if this is a write */ diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c index c297f6da91ea..f0371b4c4fbf 100644 --- a/drivers/md/dm-stripe.c +++ b/drivers/md/dm-stripe.c @@ -271,7 +271,7 @@ static int stripe_map(struct dm_target *ti, struct bio *bio, uint32_t stripe; unsigned target_request_nr; - if (unlikely(bio_empty_barrier(bio))) { + if (bio->bi_rw & REQ_FLUSH) { target_request_nr = map_context->target_request_nr; BUG_ON(target_request_nr >= sc->stripes); bio->bi_bdev = sc->stripe[target_request_nr].dev->bdev; diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index f9fc07d7a4b9..90267f8d64ee 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -486,11 +486,6 @@ static int __table_get_device(struct dm_table *t, struct dm_target *ti, return 0; } -/* - * Returns the minimum that is _not_ zero, unless both are zero. - */ -#define min_not_zero(l, r) (l == 0) ? r : ((r == 0) ? l : min(l, r)) - int dm_set_device_limits(struct dm_target *ti, struct dm_dev *dev, sector_t start, sector_t len, void *data) { diff --git a/drivers/md/dm.c b/drivers/md/dm.c index ac384b2a6a33..7cb1352f7e7a 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -15,7 +15,6 @@ #include <linux/blkpg.h> #include <linux/bio.h> #include <linux/buffer_head.h> -#include <linux/smp_lock.h> #include <linux/mempool.h> #include <linux/slab.h> #include <linux/idr.h> @@ -33,6 +32,7 @@ #define DM_COOKIE_ENV_VAR_NAME "DM_COOKIE" #define DM_COOKIE_LENGTH 24 +static DEFINE_MUTEX(dm_mutex); static const char *_name = DM_NAME; static unsigned int major = 0; @@ -110,7 +110,6 @@ EXPORT_SYMBOL_GPL(dm_get_rq_mapinfo); #define DMF_FREEING 3 #define DMF_DELETING 4 #define DMF_NOFLUSH_SUSPENDING 5 -#define DMF_QUEUE_IO_TO_THREAD 6 /* * Work processed by per-device workqueue. @@ -144,24 +143,9 @@ struct mapped_device { spinlock_t deferred_lock; /* - * An error from the barrier request currently being processed. - */ - int barrier_error; - - /* - * Protect barrier_error from concurrent endio processing - * in request-based dm. - */ - spinlock_t barrier_error_lock; - - /* - * Processing queue (flush/barriers) + * Processing queue (flush) */ struct workqueue_struct *wq; - struct work_struct barrier_work; - - /* A pointer to the currently processing pre/post flush request */ - struct request *flush_request; /* * The current mapping. @@ -200,8 +184,8 @@ struct mapped_device { /* sysfs handle */ struct kobject kobj; - /* zero-length barrier that will be cloned and submitted to targets */ - struct bio barrier_bio; + /* zero-length flush that will be cloned and submitted to targets */ + struct bio flush_bio; }; /* @@ -344,7 +328,7 @@ static int dm_blk_open(struct block_device *bdev, fmode_t mode) { struct mapped_device *md; - lock_kernel(); + mutex_lock(&dm_mutex); spin_lock(&_minor_lock); md = bdev->bd_disk->private_data; @@ -362,7 +346,7 @@ static int dm_blk_open(struct block_device *bdev, fmode_t mode) out: spin_unlock(&_minor_lock); - unlock_kernel(); + mutex_unlock(&dm_mutex); return md ? 0 : -ENXIO; } @@ -371,10 +355,10 @@ static int dm_blk_close(struct gendisk *disk, fmode_t mode) { struct mapped_device *md = disk->private_data; - lock_kernel(); + mutex_lock(&dm_mutex); atomic_dec(&md->open_count); dm_put(md); - unlock_kernel(); + mutex_unlock(&dm_mutex); return 0; } @@ -512,7 +496,7 @@ static void end_io_acct(struct dm_io *io) /* * After this is decremented the bio must not be touched if it is - * a barrier. + * a flush. */ dm_disk(md)->part0.in_flight[rw] = pending = atomic_dec_return(&md->pending[rw]); @@ -528,16 +512,12 @@ static void end_io_acct(struct dm_io *io) */ static void queue_io(struct mapped_device *md, struct bio *bio) { - down_write(&md->io_lock); + unsigned long flags; - spin_lock_irq(&md->deferred_lock); + spin_lock_irqsave(&md->deferred_lock, flags); bio_list_add(&md->deferred, bio); - spin_unlock_irq(&md->deferred_lock); - - if (!test_and_set_bit(DMF_QUEUE_IO_TO_THREAD, &md->flags)) - queue_work(md->wq, &md->work); - - up_write(&md->io_lock); + spin_unlock_irqrestore(&md->deferred_lock, flags); + queue_work(md->wq, &md->work); } /* @@ -625,11 +605,9 @@ static void dec_pending(struct dm_io *io, int error) * Target requested pushing back the I/O. */ spin_lock_irqsave(&md->deferred_lock, flags); - if (__noflush_suspending(md)) { - if (!(io->bio->bi_rw & REQ_HARDBARRIER)) - bio_list_add_head(&md->deferred, - io->bio); - } else + if (__noflush_suspending(md)) + bio_list_add_head(&md->deferred, io->bio); + else /* noflush suspend was interrupted. */ io->error = -EIO; spin_unlock_irqrestore(&md->deferred_lock, flags); @@ -637,32 +615,23 @@ static void dec_pending(struct dm_io *io, int error) io_error = io->error; bio = io->bio; + end_io_acct(io); + free_io(md, io); + + if (io_error == DM_ENDIO_REQUEUE) + return; - if (bio->bi_rw & REQ_HARDBARRIER) { + if ((bio->bi_rw & REQ_FLUSH) && bio->bi_size) { /* - * There can be just one barrier request so we use - * a per-device variable for error reporting. - * Note that you can't touch the bio after end_io_acct - * - * We ignore -EOPNOTSUPP for empty flush reported by - * underlying devices. We assume that if the device - * doesn't support empty barriers, it doesn't need - * cache flushing commands. + * Preflush done for flush with data, reissue + * without REQ_FLUSH. */ - if (!md->barrier_error && - !(bio_empty_barrier(bio) && io_error == -EOPNOTSUPP)) - md->barrier_error = io_error; - end_io_acct(io); - free_io(md, io); + bio->bi_rw &= ~REQ_FLUSH; + queue_io(md, bio); } else { - end_io_acct(io); - free_io(md, io); - - if (io_error != DM_ENDIO_REQUEUE) { - trace_block_bio_complete(md->queue, bio); - - bio_endio(bio, io_error); - } + /* done with normal IO or empty flush */ + trace_block_bio_complete(md->queue, bio); + bio_endio(bio, io_error); } } } @@ -755,23 +724,6 @@ static void end_clone_bio(struct bio *clone, int error) blk_update_request(tio->orig, 0, nr_bytes); } -static void store_barrier_error(struct mapped_device *md, int error) -{ - unsigned long flags; - - spin_lock_irqsave(&md->barrier_error_lock, flags); - /* - * Basically, the first error is taken, but: - * -EOPNOTSUPP supersedes any I/O error. - * Requeue request supersedes any I/O error but -EOPNOTSUPP. - */ - if (!md->barrier_error || error == -EOPNOTSUPP || - (md->barrier_error != -EOPNOTSUPP && - error == DM_ENDIO_REQUEUE)) - md->barrier_error = error; - spin_unlock_irqrestore(&md->barrier_error_lock, flags); -} - /* * Don't touch any member of the md after calling this function because * the md may be freed in dm_put() at the end of this function. @@ -809,13 +761,11 @@ static void free_rq_clone(struct request *clone) static void dm_end_request(struct request *clone, int error) { int rw = rq_data_dir(clone); - int run_queue = 1; - bool is_barrier = clone->cmd_flags & REQ_HARDBARRIER; struct dm_rq_target_io *tio = clone->end_io_data; struct mapped_device *md = tio->md; struct request *rq = tio->orig; - if (rq->cmd_type == REQ_TYPE_BLOCK_PC && !is_barrier) { + if (rq->cmd_type == REQ_TYPE_BLOCK_PC) { rq->errors = clone->errors; rq->resid_len = clone->resid_len; @@ -829,15 +779,8 @@ static void dm_end_request(struct request *clone, int error) } free_rq_clone(clone); - - if (unlikely(is_barrier)) { - if (unlikely(error)) - store_barrier_error(md, error); - run_queue = 0; - } else - blk_end_request_all(rq, error); - - rq_completed(md, rw, run_queue); + blk_end_request_all(rq, error); + rq_completed(md, rw, true); } static void dm_unprep_request(struct request *rq) @@ -862,16 +805,6 @@ void dm_requeue_unmapped_request(struct request *clone) struct request_queue *q = rq->q; unsigned long flags; - if (unlikely(clone->cmd_flags & REQ_HARDBARRIER)) { - /* - * Barrier clones share an original request. - * Leave it to dm_end_request(), which handles this special - * case. - */ - dm_end_request(clone, DM_ENDIO_REQUEUE); - return; - } - dm_unprep_request(rq); spin_lock_irqsave(q->queue_lock, flags); @@ -961,19 +894,6 @@ static void dm_complete_request(struct request *clone, int error) struct dm_rq_target_io *tio = clone->end_io_data; struct request *rq = tio->orig; - if (unlikely(clone->cmd_flags & REQ_HARDBARRIER)) { - /* - * Barrier clones share an original request. So can't use - * softirq_done with the original. - * Pass the clone to dm_done() directly in this special case. - * It is safe (even if clone->q->queue_lock is held here) - * because there is no I/O dispatching during the completion - * of barrier clone. - */ - dm_done(clone, error, true); - return; - } - tio->error = error; rq->completion_data = clone; blk_complete_request(rq); @@ -990,17 +910,6 @@ void dm_kill_unmapped_request(struct request *clone, int error) struct dm_rq_target_io *tio = clone->end_io_data; struct request *rq = tio->orig; - if (unlikely(clone->cmd_flags & REQ_HARDBARRIER)) { - /* - * Barrier clones share an original request. - * Leave it to dm_end_request(), which handles this special - * case. - */ - BUG_ON(error > 0); - dm_end_request(clone, error); - return; - } - rq->cmd_flags |= REQ_FAILED; dm_complete_request(clone, error); } @@ -1119,7 +1028,7 @@ static void dm_bio_destructor(struct bio *bio) } /* - * Creates a little bio that is just does part of a bvec. + * Creates a little bio that just does part of a bvec. */ static struct bio *split_bvec(struct bio *bio, sector_t sector, unsigned short idx, unsigned int offset, @@ -1134,7 +1043,7 @@ static struct bio *split_bvec(struct bio *bio, sector_t sector, clone->bi_sector = sector; clone->bi_bdev = bio->bi_bdev; - clone->bi_rw = bio->bi_rw & ~REQ_HARDBARRIER; + clone->bi_rw = bio->bi_rw; clone->bi_vcnt = 1; clone->bi_size = to_bytes(len); clone->bi_io_vec->bv_offset = offset; @@ -1161,7 +1070,6 @@ static struct bio *clone_bio(struct bio *bio, sector_t sector, clone = bio_alloc_bioset(GFP_NOIO, bio->bi_max_vecs, bs); __bio_clone(clone, bio); - clone->bi_rw &= ~REQ_HARDBARRIER; clone->bi_destructor = dm_bio_destructor; clone->bi_sector = sector; clone->bi_idx = idx; @@ -1225,16 +1133,15 @@ static void __issue_target_requests(struct clone_info *ci, struct dm_target *ti, __issue_target_request(ci, ti, request_nr, len); } -static int __clone_and_map_empty_barrier(struct clone_info *ci) +static int __clone_and_map_empty_flush(struct clone_info *ci) { unsigned target_nr = 0; struct dm_target *ti; + BUG_ON(bio_has_data(ci->bio)); while ((ti = dm_table_get_target(ci->map, target_nr++))) __issue_target_requests(ci, ti, ti->num_flush_requests, 0); - ci->sector_count = 0; - return 0; } @@ -1289,9 +1196,6 @@ static int __clone_and_map(struct clone_info *ci) sector_t len = 0, max; struct dm_target_io *tio; - if (unlikely(bio_empty_barrier(bio))) - return __clone_and_map_empty_barrier(ci); - if (unlikely(bio->bi_rw & REQ_DISCARD)) return __clone_and_map_discard(ci); @@ -1383,16 +1287,11 @@ static void __split_and_process_bio(struct mapped_device *md, struct bio *bio) ci.map = dm_get_live_table(md); if (unlikely(!ci.map)) { - if (!(bio->bi_rw & REQ_HARDBARRIER)) - bio_io_error(bio); - else - if (!md->barrier_error) - md->barrier_error = -EIO; + bio_io_error(bio); return; } ci.md = md; - ci.bio = bio; ci.io = alloc_io(md); ci.io->error = 0; atomic_set(&ci.io->io_count, 1); @@ -1400,14 +1299,20 @@ static void __split_and_process_bio(struct mapped_device *md, struct bio *bio) ci.io->md = md; spin_lock_init(&ci.io->endio_lock); ci.sector = bio->bi_sector; - ci.sector_count = bio_sectors(bio); - if (unlikely(bio_empty_barrier(bio))) - ci.sector_count = 1; ci.idx = bio->bi_idx; start_io_acct(ci.io); - while (ci.sector_count && !error) - error = __clone_and_map(&ci); + if (bio->bi_rw & REQ_FLUSH) { + ci.bio = &ci.md->flush_bio; + ci.sector_count = 0; + error = __clone_and_map_empty_flush(&ci); + /* dec_pending submits any data associated with flush */ + } else { + ci.bio = bio; + ci.sector_count = bio_sectors(bio); + while (ci.sector_count && !error) + error = __clone_and_map(&ci); + } /* drop the extra reference count */ dec_pending(ci.io, error); @@ -1491,22 +1396,14 @@ static int _dm_request(struct request_queue *q, struct bio *bio) part_stat_add(cpu, &dm_disk(md)->part0, sectors[rw], bio_sectors(bio)); part_stat_unlock(); - /* - * If we're suspended or the thread is processing barriers - * we have to queue this io for later. - */ - if (unlikely(test_bit(DMF_QUEUE_IO_TO_THREAD, &md->flags)) || - unlikely(bio->bi_rw & REQ_HARDBARRIER)) { + /* if we're suspended, we have to queue this io for later */ + if (unlikely(test_bit(DMF_BLOCK_IO_FOR_SUSPEND, &md->flags))) { up_read(&md->io_lock); - if (unlikely(test_bit(DMF_BLOCK_IO_FOR_SUSPEND, &md->flags)) && - bio_rw(bio) == READA) { + if (bio_rw(bio) != READA) + queue_io(md, bio); + else bio_io_error(bio); - return 0; - } - - queue_io(md, bio); - return 0; } @@ -1537,14 +1434,6 @@ static int dm_request(struct request_queue *q, struct bio *bio) return _dm_request(q, bio); } -static bool dm_rq_is_flush_request(struct request *rq) -{ - if (rq->cmd_flags & REQ_FLUSH) - return true; - else - return false; -} - void dm_dispatch_request(struct request *rq) { int r; @@ -1592,22 +1481,15 @@ static int setup_clone(struct request *clone, struct request *rq, { int r; - if (dm_rq_is_flush_request(rq)) { - blk_rq_init(NULL, clone); - clone->cmd_type = REQ_TYPE_FS; - clone->cmd_flags |= (REQ_HARDBARRIER | WRITE); - } else { - r = blk_rq_prep_clone(clone, rq, tio->md->bs, GFP_ATOMIC, - dm_rq_bio_constructor, tio); - if (r) - return r; - - clone->cmd = rq->cmd; - clone->cmd_len = rq->cmd_len; - clone->sense = rq->sense; - clone->buffer = rq->buffer; - } + r = blk_rq_prep_clone(clone, rq, tio->md->bs, GFP_ATOMIC, + dm_rq_bio_constructor, tio); + if (r) + return r; + clone->cmd = rq->cmd; + clone->cmd_len = rq->cmd_len; + clone->sense = rq->sense; + clone->buffer = rq->buffer; clone->end_io = end_clone_request; clone->end_io_data = tio; @@ -1648,9 +1530,6 @@ static int dm_prep_fn(struct request_queue *q, struct request *rq) struct mapped_device *md = q->queuedata; struct request *clone; - if (unlikely(dm_rq_is_flush_request(rq))) - return BLKPREP_OK; - if (unlikely(rq->special)) { DMWARN("Already has something in rq->special."); return BLKPREP_KILL; @@ -1727,6 +1606,7 @@ static void dm_request_fn(struct request_queue *q) struct dm_table *map = dm_get_live_table(md); struct dm_target *ti; struct request *rq, *clone; + sector_t pos; /* * For suspend, check blk_queue_stopped() and increment @@ -1739,15 +1619,14 @@ static void dm_request_fn(struct request_queue *q) if (!rq) goto plug_and_out; - if (unlikely(dm_rq_is_flush_request(rq))) { - BUG_ON(md->flush_request); - md->flush_request = rq; - blk_start_request(rq); - queue_work(md->wq, &md->barrier_work); - goto out; - } + /* always use block 0 to find the target for flushes for now */ + pos = 0; + if (!(rq->cmd_flags & REQ_FLUSH)) + pos = blk_rq_pos(rq); + + ti = dm_table_find_target(map, pos); + BUG_ON(!dm_target_is_valid(ti)); - ti = dm_table_find_target(map, blk_rq_pos(rq)); if (ti->type->busy && ti->type->busy(ti)) goto plug_and_out; @@ -1918,7 +1797,6 @@ out: static const struct block_device_operations dm_blk_dops; static void dm_wq_work(struct work_struct *work); -static void dm_rq_barrier_work(struct work_struct *work); static void dm_init_md_queue(struct mapped_device *md) { @@ -1940,6 +1818,7 @@ static void dm_init_md_queue(struct mapped_device *md) blk_queue_bounce_limit(md->queue, BLK_BOUNCE_ANY); md->queue->unplug_fn = dm_unplug_all; blk_queue_merge_bvec(md->queue, dm_merge_bvec); + blk_queue_flush(md->queue, REQ_FLUSH | REQ_FUA); } /* @@ -1972,7 +1851,6 @@ static struct mapped_device *alloc_dev(int minor) mutex_init(&md->suspend_lock); mutex_init(&md->type_lock); spin_lock_init(&md->deferred_lock); - spin_lock_init(&md->barrier_error_lock); rwlock_init(&md->map_lock); atomic_set(&md->holders, 1); atomic_set(&md->open_count, 0); @@ -1995,7 +1873,6 @@ static struct mapped_device *alloc_dev(int minor) atomic_set(&md->pending[1], 0); init_waitqueue_head(&md->wait); INIT_WORK(&md->work, dm_wq_work); - INIT_WORK(&md->barrier_work, dm_rq_barrier_work); init_waitqueue_head(&md->eventq); md->disk->major = _major; @@ -2015,6 +1892,10 @@ static struct mapped_device *alloc_dev(int minor) if (!md->bdev) goto bad_bdev; + bio_init(&md->flush_bio); + md->flush_bio.bi_bdev = md->bdev; + md->flush_bio.bi_rw = WRITE_FLUSH; + /* Populate the mapping, nobody knows we exist yet */ spin_lock(&_minor_lock); old_md = idr_replace(&_minor_idr, md, minor); @@ -2245,7 +2126,6 @@ static int dm_init_request_based_queue(struct mapped_device *md) blk_queue_softirq_done(md->queue, dm_softirq_done); blk_queue_prep_rq(md->queue, dm_prep_fn); blk_queue_lld_busy(md->queue, dm_lld_busy); - blk_queue_ordered(md->queue, QUEUE_ORDERED_DRAIN_FLUSH); elv_register_queue(md->queue); @@ -2406,43 +2286,6 @@ static int dm_wait_for_completion(struct mapped_device *md, int interruptible) return r; } -static void dm_flush(struct mapped_device *md) -{ - dm_wait_for_completion(md, TASK_UNINTERRUPTIBLE); - - bio_init(&md->barrier_bio); - md->barrier_bio.bi_bdev = md->bdev; - md->barrier_bio.bi_rw = WRITE_BARRIER; - __split_and_process_bio(md, &md->barrier_bio); - - dm_wait_for_completion(md, TASK_UNINTERRUPTIBLE); -} - -static void process_barrier(struct mapped_device *md, struct bio *bio) -{ - md->barrier_error = 0; - - dm_flush(md); - - if (!bio_empty_barrier(bio)) { - __split_and_process_bio(md, bio); - /* - * If the request isn't supported, don't waste time with - * the second flush. - */ - if (md->barrier_error != -EOPNOTSUPP) - dm_flush(md); - } - - if (md->barrier_error != DM_ENDIO_REQUEUE) - bio_endio(bio, md->barrier_error); - else { - spin_lock_irq(&md->deferred_lock); - bio_list_add_head(&md->deferred, bio); - spin_unlock_irq(&md->deferred_lock); - } -} - /* * Process the deferred bios */ @@ -2452,33 +2295,27 @@ static void dm_wq_work(struct work_struct *work) work); struct bio *c; - down_write(&md->io_lock); + down_read(&md->io_lock); while (!test_bit(DMF_BLOCK_IO_FOR_SUSPEND, &md->flags)) { spin_lock_irq(&md->deferred_lock); c = bio_list_pop(&md->deferred); spin_unlock_irq(&md->deferred_lock); - if (!c) { - clear_bit(DMF_QUEUE_IO_TO_THREAD, &md->flags); + if (!c) break; - } - up_write(&md->io_lock); + up_read(&md->io_lock); if (dm_request_based(md)) generic_make_request(c); - else { - if (c->bi_rw & REQ_HARDBARRIER) - process_barrier(md, c); - else - __split_and_process_bio(md, c); - } + else + __split_and_process_bio(md, c); - down_write(&md->io_lock); + down_read(&md->io_lock); } - up_write(&md->io_lock); + up_read(&md->io_lock); } static void dm_queue_flush(struct mapped_device *md) @@ -2488,73 +2325,6 @@ static void dm_queue_flush(struct mapped_device *md) queue_work(md->wq, &md->work); } -static void dm_rq_set_target_request_nr(struct request *clone, unsigned request_nr) -{ - struct dm_rq_target_io *tio = clone->end_io_data; - - tio->info.target_request_nr = request_nr; -} - -/* Issue barrier requests to targets and wait for their completion. */ -static int dm_rq_barrier(struct mapped_device *md) -{ - int i, j; - struct dm_table *map = dm_get_live_table(md); - unsigned num_targets = dm_table_get_num_targets(map); - struct dm_target *ti; - struct request *clone; - - md->barrier_error = 0; - - for (i = 0; i < num_targets; i++) { - ti = dm_table_get_target(map, i); - for (j = 0; j < ti->num_flush_requests; j++) { - clone = clone_rq(md->flush_request, md, GFP_NOIO); - dm_rq_set_target_request_nr(clone, j); - atomic_inc(&md->pending[rq_data_dir(clone)]); - map_request(ti, clone, md); - } - } - - dm_wait_for_completion(md, TASK_UNINTERRUPTIBLE); - dm_table_put(map); - - return md->barrier_error; -} - -static void dm_rq_barrier_work(struct work_struct *work) -{ - int error; - struct mapped_device *md = container_of(work, struct mapped_device, - barrier_work); - struct request_queue *q = md->queue; - struct request *rq; - unsigned long flags; - - /* - * Hold the md reference here and leave it at the last part so that - * the md can't be deleted by device opener when the barrier request - * completes. - */ - dm_get(md); - - error = dm_rq_barrier(md); - - rq = md->flush_request; - md->flush_request = NULL; - - if (error == DM_ENDIO_REQUEUE) { - spin_lock_irqsave(q->queue_lock, flags); - blk_requeue_request(q, rq); - spin_unlock_irqrestore(q->queue_lock, flags); - } else - blk_end_request_all(rq, error); - - blk_run_queue(q); - - dm_put(md); -} - /* * Swap in a new table, returning the old one for the caller to destroy. */ @@ -2677,23 +2447,17 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags) * * To get all processes out of __split_and_process_bio in dm_request, * we take the write lock. To prevent any process from reentering - * __split_and_process_bio from dm_request, we set - * DMF_QUEUE_IO_TO_THREAD. - * - * To quiesce the thread (dm_wq_work), we set DMF_BLOCK_IO_FOR_SUSPEND - * and call flush_workqueue(md->wq). flush_workqueue will wait until - * dm_wq_work exits and DMF_BLOCK_IO_FOR_SUSPEND will prevent any - * further calls to __split_and_process_bio from dm_wq_work. + * __split_and_process_bio from dm_request and quiesce the thread + * (dm_wq_work), we set BMF_BLOCK_IO_FOR_SUSPEND and call + * flush_workqueue(md->wq). */ down_write(&md->io_lock); set_bit(DMF_BLOCK_IO_FOR_SUSPEND, &md->flags); - set_bit(DMF_QUEUE_IO_TO_THREAD, &md->flags); up_write(&md->io_lock); /* - * Request-based dm uses md->wq for barrier (dm_rq_barrier_work) which - * can be kicked until md->queue is stopped. So stop md->queue before - * flushing md->wq. + * Stop md->queue before flushing md->wq in case request-based + * dm defers requests to md->wq from md->queue. */ if (dm_request_based(md)) stop_queue(md->queue); diff --git a/drivers/md/linear.c b/drivers/md/linear.c index ba19060bcf3f..8a2f767f26d8 100644 --- a/drivers/md/linear.c +++ b/drivers/md/linear.c @@ -294,8 +294,8 @@ static int linear_make_request (mddev_t *mddev, struct bio *bio) dev_info_t *tmp_dev; sector_t start_sector; - if (unlikely(bio->bi_rw & REQ_HARDBARRIER)) { - md_barrier_request(mddev, bio); + if (unlikely(bio->bi_rw & REQ_FLUSH)) { + md_flush_request(mddev, bio); return 0; } diff --git a/drivers/md/md.c b/drivers/md/md.c index f20d13e717d5..225815197a3d 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -36,7 +36,7 @@ #include <linux/blkdev.h> #include <linux/sysctl.h> #include <linux/seq_file.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/buffer_head.h> /* for invalidate_bdev */ #include <linux/poll.h> #include <linux/ctype.h> @@ -57,6 +57,7 @@ #define DEBUG 0 #define dprintk(x...) ((void)(DEBUG && printk(x))) +static DEFINE_MUTEX(md_mutex); #ifndef MODULE static void autostart_arrays(int part); @@ -226,12 +227,12 @@ static int md_make_request(struct request_queue *q, struct bio *bio) return 0; } rcu_read_lock(); - if (mddev->suspended || mddev->barrier) { + if (mddev->suspended) { DEFINE_WAIT(__wait); for (;;) { prepare_to_wait(&mddev->sb_wait, &__wait, TASK_UNINTERRUPTIBLE); - if (!mddev->suspended && !mddev->barrier) + if (!mddev->suspended) break; rcu_read_unlock(); schedule(); @@ -282,40 +283,29 @@ EXPORT_SYMBOL_GPL(mddev_resume); int mddev_congested(mddev_t *mddev, int bits) { - if (mddev->barrier) - return 1; return mddev->suspended; } EXPORT_SYMBOL(mddev_congested); /* - * Generic barrier handling for md + * Generic flush handling for md */ -#define POST_REQUEST_BARRIER ((void*)1) - -static void md_end_barrier(struct bio *bio, int err) +static void md_end_flush(struct bio *bio, int err) { mdk_rdev_t *rdev = bio->bi_private; mddev_t *mddev = rdev->mddev; - if (err == -EOPNOTSUPP && mddev->barrier != POST_REQUEST_BARRIER) - set_bit(BIO_EOPNOTSUPP, &mddev->barrier->bi_flags); rdev_dec_pending(rdev, mddev); if (atomic_dec_and_test(&mddev->flush_pending)) { - if (mddev->barrier == POST_REQUEST_BARRIER) { - /* This was a post-request barrier */ - mddev->barrier = NULL; - wake_up(&mddev->sb_wait); - } else - /* The pre-request barrier has finished */ - schedule_work(&mddev->barrier_work); + /* The pre-request flush has finished */ + schedule_work(&mddev->flush_work); } bio_put(bio); } -static void submit_barriers(mddev_t *mddev) +static void submit_flushes(mddev_t *mddev) { mdk_rdev_t *rdev; @@ -332,60 +322,56 @@ static void submit_barriers(mddev_t *mddev) atomic_inc(&rdev->nr_pending); rcu_read_unlock(); bi = bio_alloc(GFP_KERNEL, 0); - bi->bi_end_io = md_end_barrier; + bi->bi_end_io = md_end_flush; bi->bi_private = rdev; bi->bi_bdev = rdev->bdev; atomic_inc(&mddev->flush_pending); - submit_bio(WRITE_BARRIER, bi); + submit_bio(WRITE_FLUSH, bi); rcu_read_lock(); rdev_dec_pending(rdev, mddev); } rcu_read_unlock(); } -static void md_submit_barrier(struct work_struct *ws) +static void md_submit_flush_data(struct work_struct *ws) { - mddev_t *mddev = container_of(ws, mddev_t, barrier_work); - struct bio *bio = mddev->barrier; + mddev_t *mddev = container_of(ws, mddev_t, flush_work); + struct bio *bio = mddev->flush_bio; atomic_set(&mddev->flush_pending, 1); - if (test_bit(BIO_EOPNOTSUPP, &bio->bi_flags)) - bio_endio(bio, -EOPNOTSUPP); - else if (bio->bi_size == 0) + if (bio->bi_size == 0) /* an empty barrier - all done */ bio_endio(bio, 0); else { - bio->bi_rw &= ~REQ_HARDBARRIER; + bio->bi_rw &= ~REQ_FLUSH; if (mddev->pers->make_request(mddev, bio)) generic_make_request(bio); - mddev->barrier = POST_REQUEST_BARRIER; - submit_barriers(mddev); } if (atomic_dec_and_test(&mddev->flush_pending)) { - mddev->barrier = NULL; + mddev->flush_bio = NULL; wake_up(&mddev->sb_wait); } } -void md_barrier_request(mddev_t *mddev, struct bio *bio) +void md_flush_request(mddev_t *mddev, struct bio *bio) { spin_lock_irq(&mddev->write_lock); wait_event_lock_irq(mddev->sb_wait, - !mddev->barrier, + !mddev->flush_bio, mddev->write_lock, /*nothing*/); - mddev->barrier = bio; + mddev->flush_bio = bio; spin_unlock_irq(&mddev->write_lock); atomic_set(&mddev->flush_pending, 1); - INIT_WORK(&mddev->barrier_work, md_submit_barrier); + INIT_WORK(&mddev->flush_work, md_submit_flush_data); - submit_barriers(mddev); + submit_flushes(mddev); if (atomic_dec_and_test(&mddev->flush_pending)) - schedule_work(&mddev->barrier_work); + schedule_work(&mddev->flush_work); } -EXPORT_SYMBOL(md_barrier_request); +EXPORT_SYMBOL(md_flush_request); /* Support for plugging. * This mirrors the plugging support in request_queue, but does not @@ -696,31 +682,6 @@ static void super_written(struct bio *bio, int error) bio_put(bio); } -static void super_written_barrier(struct bio *bio, int error) -{ - struct bio *bio2 = bio->bi_private; - mdk_rdev_t *rdev = bio2->bi_private; - mddev_t *mddev = rdev->mddev; - - if (!test_bit(BIO_UPTODATE, &bio->bi_flags) && - error == -EOPNOTSUPP) { - unsigned long flags; - /* barriers don't appear to be supported :-( */ - set_bit(BarriersNotsupp, &rdev->flags); - mddev->barriers_work = 0; - spin_lock_irqsave(&mddev->write_lock, flags); - bio2->bi_next = mddev->biolist; - mddev->biolist = bio2; - spin_unlock_irqrestore(&mddev->write_lock, flags); - wake_up(&mddev->sb_wait); - bio_put(bio); - } else { - bio_put(bio2); - bio->bi_private = rdev; - super_written(bio, error); - } -} - void md_super_write(mddev_t *mddev, mdk_rdev_t *rdev, sector_t sector, int size, struct page *page) { @@ -729,51 +690,28 @@ void md_super_write(mddev_t *mddev, mdk_rdev_t *rdev, * and decrement it on completion, waking up sb_wait * if zero is reached. * If an error occurred, call md_error - * - * As we might need to resubmit the request if REQ_HARDBARRIER - * causes ENOTSUPP, we allocate a spare bio... */ struct bio *bio = bio_alloc(GFP_NOIO, 1); - int rw = REQ_WRITE | REQ_SYNC | REQ_UNPLUG; bio->bi_bdev = rdev->bdev; bio->bi_sector = sector; bio_add_page(bio, page, size, 0); bio->bi_private = rdev; bio->bi_end_io = super_written; - bio->bi_rw = rw; atomic_inc(&mddev->pending_writes); - if (!test_bit(BarriersNotsupp, &rdev->flags)) { - struct bio *rbio; - rw |= REQ_HARDBARRIER; - rbio = bio_clone(bio, GFP_NOIO); - rbio->bi_private = bio; - rbio->bi_end_io = super_written_barrier; - submit_bio(rw, rbio); - } else - submit_bio(rw, bio); + submit_bio(REQ_WRITE | REQ_SYNC | REQ_UNPLUG | REQ_FLUSH | REQ_FUA, + bio); } void md_super_wait(mddev_t *mddev) { - /* wait for all superblock writes that were scheduled to complete. - * if any had to be retried (due to BARRIER problems), retry them - */ + /* wait for all superblock writes that were scheduled to complete */ DEFINE_WAIT(wq); for(;;) { prepare_to_wait(&mddev->sb_wait, &wq, TASK_UNINTERRUPTIBLE); if (atomic_read(&mddev->pending_writes)==0) break; - while (mddev->biolist) { - struct bio *bio; - spin_lock_irq(&mddev->write_lock); - bio = mddev->biolist; - mddev->biolist = bio->bi_next ; - bio->bi_next = NULL; - spin_unlock_irq(&mddev->write_lock); - submit_bio(bio->bi_rw, bio); - } schedule(); } finish_wait(&mddev->sb_wait, &wq); @@ -1070,7 +1008,6 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev) clear_bit(Faulty, &rdev->flags); clear_bit(In_sync, &rdev->flags); clear_bit(WriteMostly, &rdev->flags); - clear_bit(BarriersNotsupp, &rdev->flags); if (mddev->raid_disks == 0) { mddev->major_version = 0; @@ -1485,7 +1422,6 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev) clear_bit(Faulty, &rdev->flags); clear_bit(In_sync, &rdev->flags); clear_bit(WriteMostly, &rdev->flags); - clear_bit(BarriersNotsupp, &rdev->flags); if (mddev->raid_disks == 0) { mddev->major_version = 1; @@ -4504,7 +4440,6 @@ int md_run(mddev_t *mddev) /* may be over-ridden by personality */ mddev->resync_max_sectors = mddev->dev_sectors; - mddev->barriers_work = 1; mddev->ok_start_degraded = start_dirty_degraded; if (start_readonly && mddev->ro == 0) @@ -4683,7 +4618,6 @@ static void md_clean(mddev_t *mddev) mddev->recovery = 0; mddev->in_sync = 0; mddev->degraded = 0; - mddev->barriers_work = 0; mddev->safemode = 0; mddev->bitmap_info.offset = 0; mddev->bitmap_info.default_offset = 0; @@ -5951,7 +5885,7 @@ static int md_open(struct block_device *bdev, fmode_t mode) mddev_t *mddev = mddev_find(bdev->bd_dev); int err; - lock_kernel(); + mutex_lock(&md_mutex); if (mddev->gendisk != bdev->bd_disk) { /* we are racing with mddev_put which is discarding this * bd_disk. @@ -5960,7 +5894,7 @@ static int md_open(struct block_device *bdev, fmode_t mode) /* Wait until bdev->bd_disk is definitely gone */ flush_scheduled_work(); /* Then retry the open from the top */ - unlock_kernel(); + mutex_unlock(&md_mutex); return -ERESTARTSYS; } BUG_ON(mddev != bdev->bd_disk->private_data); @@ -5974,7 +5908,7 @@ static int md_open(struct block_device *bdev, fmode_t mode) check_disk_size_change(mddev->gendisk, bdev); out: - unlock_kernel(); + mutex_unlock(&md_mutex); return err; } @@ -5983,10 +5917,10 @@ static int md_release(struct gendisk *disk, fmode_t mode) mddev_t *mddev = disk->private_data; BUG_ON(!mddev); - lock_kernel(); + mutex_lock(&md_mutex); atomic_dec(&mddev->openers); mddev_put(mddev); - unlock_kernel(); + mutex_unlock(&md_mutex); return 0; } diff --git a/drivers/md/md.h b/drivers/md/md.h index 3931299788dc..112a2c32db0c 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h @@ -87,7 +87,6 @@ struct mdk_rdev_s #define Faulty 1 /* device is known to have a fault */ #define In_sync 2 /* device is in_sync with rest of array */ #define WriteMostly 4 /* Avoid reading if at all possible */ -#define BarriersNotsupp 5 /* REQ_HARDBARRIER is not supported */ #define AllReserved 6 /* If whole device is reserved for * one array */ #define AutoDetected 7 /* added by auto-detect */ @@ -273,13 +272,6 @@ struct mddev_s int degraded; /* whether md should consider * adding a spare */ - int barriers_work; /* initialised to true, cleared as soon - * as a barrier request to slave - * fails. Only supported - */ - struct bio *biolist; /* bios that need to be retried - * because REQ_HARDBARRIER is not supported - */ atomic_t recovery_active; /* blocks scheduled, but not written */ wait_queue_head_t recovery_wait; @@ -339,16 +331,13 @@ struct mddev_s struct attribute_group *to_remove; struct plug_handle *plug; /* if used by personality */ - /* Generic barrier handling. - * If there is a pending barrier request, all other - * writes are blocked while the devices are flushed. - * The last to finish a flush schedules a worker to - * submit the barrier request (without the barrier flag), - * then submit more flush requests. + /* Generic flush handling. + * The last to finish preflush schedules a worker to submit + * the rest of the request (without the REQ_FLUSH flag). */ - struct bio *barrier; + struct bio *flush_bio; atomic_t flush_pending; - struct work_struct barrier_work; + struct work_struct flush_work; struct work_struct event_work; /* used by dm to report failure event */ }; @@ -502,7 +491,7 @@ extern void md_done_sync(mddev_t *mddev, int blocks, int ok); extern void md_error(mddev_t *mddev, mdk_rdev_t *rdev); extern int mddev_congested(mddev_t *mddev, int bits); -extern void md_barrier_request(mddev_t *mddev, struct bio *bio); +extern void md_flush_request(mddev_t *mddev, struct bio *bio); extern void md_super_write(mddev_t *mddev, mdk_rdev_t *rdev, sector_t sector, int size, struct page *page); extern void md_super_wait(mddev_t *mddev); diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index 0307d217e7a4..6d7ddf32ef2e 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -142,8 +142,8 @@ static int multipath_make_request(mddev_t *mddev, struct bio * bio) struct multipath_bh * mp_bh; struct multipath_info *multipath; - if (unlikely(bio->bi_rw & REQ_HARDBARRIER)) { - md_barrier_request(mddev, bio); + if (unlikely(bio->bi_rw & REQ_FLUSH)) { + md_flush_request(mddev, bio); return 0; } diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index 6f7af46d623c..a39f4c355e55 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -483,8 +483,8 @@ static int raid0_make_request(mddev_t *mddev, struct bio *bio) struct strip_zone *zone; mdk_rdev_t *tmp_dev; - if (unlikely(bio->bi_rw & REQ_HARDBARRIER)) { - md_barrier_request(mddev, bio); + if (unlikely(bio->bi_rw & REQ_FLUSH)) { + md_flush_request(mddev, bio); return 0; } diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 0b830bbe1d8b..378a25894c57 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -319,83 +319,74 @@ static void raid1_end_write_request(struct bio *bio, int error) if (r1_bio->bios[mirror] == bio) break; - if (error == -EOPNOTSUPP && test_bit(R1BIO_Barrier, &r1_bio->state)) { - set_bit(BarriersNotsupp, &conf->mirrors[mirror].rdev->flags); - set_bit(R1BIO_BarrierRetry, &r1_bio->state); - r1_bio->mddev->barriers_work = 0; - /* Don't rdev_dec_pending in this branch - keep it for the retry */ - } else { + /* + * 'one mirror IO has finished' event handler: + */ + r1_bio->bios[mirror] = NULL; + to_put = bio; + if (!uptodate) { + md_error(r1_bio->mddev, conf->mirrors[mirror].rdev); + /* an I/O failed, we can't clear the bitmap */ + set_bit(R1BIO_Degraded, &r1_bio->state); + } else /* - * this branch is our 'one mirror IO has finished' event handler: + * Set R1BIO_Uptodate in our master bio, so that we + * will return a good error code for to the higher + * levels even if IO on some other mirrored buffer + * fails. + * + * The 'master' represents the composite IO operation + * to user-side. So if something waits for IO, then it + * will wait for the 'master' bio. */ - r1_bio->bios[mirror] = NULL; - to_put = bio; - if (!uptodate) { - md_error(r1_bio->mddev, conf->mirrors[mirror].rdev); - /* an I/O failed, we can't clear the bitmap */ - set_bit(R1BIO_Degraded, &r1_bio->state); - } else - /* - * Set R1BIO_Uptodate in our master bio, so that - * we will return a good error code for to the higher - * levels even if IO on some other mirrored buffer fails. - * - * The 'master' represents the composite IO operation to - * user-side. So if something waits for IO, then it will - * wait for the 'master' bio. - */ - set_bit(R1BIO_Uptodate, &r1_bio->state); - - update_head_pos(mirror, r1_bio); - - if (behind) { - if (test_bit(WriteMostly, &conf->mirrors[mirror].rdev->flags)) - atomic_dec(&r1_bio->behind_remaining); - - /* In behind mode, we ACK the master bio once the I/O has safely - * reached all non-writemostly disks. Setting the Returned bit - * ensures that this gets done only once -- we don't ever want to - * return -EIO here, instead we'll wait */ - - if (atomic_read(&r1_bio->behind_remaining) >= (atomic_read(&r1_bio->remaining)-1) && - test_bit(R1BIO_Uptodate, &r1_bio->state)) { - /* Maybe we can return now */ - if (!test_and_set_bit(R1BIO_Returned, &r1_bio->state)) { - struct bio *mbio = r1_bio->master_bio; - PRINTK(KERN_DEBUG "raid1: behind end write sectors %llu-%llu\n", - (unsigned long long) mbio->bi_sector, - (unsigned long long) mbio->bi_sector + - (mbio->bi_size >> 9) - 1); - bio_endio(mbio, 0); - } + set_bit(R1BIO_Uptodate, &r1_bio->state); + + update_head_pos(mirror, r1_bio); + + if (behind) { + if (test_bit(WriteMostly, &conf->mirrors[mirror].rdev->flags)) + atomic_dec(&r1_bio->behind_remaining); + + /* + * In behind mode, we ACK the master bio once the I/O + * has safely reached all non-writemostly + * disks. Setting the Returned bit ensures that this + * gets done only once -- we don't ever want to return + * -EIO here, instead we'll wait + */ + if (atomic_read(&r1_bio->behind_remaining) >= (atomic_read(&r1_bio->remaining)-1) && + test_bit(R1BIO_Uptodate, &r1_bio->state)) { + /* Maybe we can return now */ + if (!test_and_set_bit(R1BIO_Returned, &r1_bio->state)) { + struct bio *mbio = r1_bio->master_bio; + PRINTK(KERN_DEBUG "raid1: behind end write sectors %llu-%llu\n", + (unsigned long long) mbio->bi_sector, + (unsigned long long) mbio->bi_sector + + (mbio->bi_size >> 9) - 1); + bio_endio(mbio, 0); } } - rdev_dec_pending(conf->mirrors[mirror].rdev, conf->mddev); } + rdev_dec_pending(conf->mirrors[mirror].rdev, conf->mddev); + /* - * * Let's see if all mirrored write operations have finished * already. */ if (atomic_dec_and_test(&r1_bio->remaining)) { - if (test_bit(R1BIO_BarrierRetry, &r1_bio->state)) - reschedule_retry(r1_bio); - else { - /* it really is the end of this request */ - if (test_bit(R1BIO_BehindIO, &r1_bio->state)) { - /* free extra copy of the data pages */ - int i = bio->bi_vcnt; - while (i--) - safe_put_page(bio->bi_io_vec[i].bv_page); - } - /* clear the bitmap if all writes complete successfully */ - bitmap_endwrite(r1_bio->mddev->bitmap, r1_bio->sector, - r1_bio->sectors, - !test_bit(R1BIO_Degraded, &r1_bio->state), - behind); - md_write_end(r1_bio->mddev); - raid_end_bio_io(r1_bio); + if (test_bit(R1BIO_BehindIO, &r1_bio->state)) { + /* free extra copy of the data pages */ + int i = bio->bi_vcnt; + while (i--) + safe_put_page(bio->bi_io_vec[i].bv_page); } + /* clear the bitmap if all writes complete successfully */ + bitmap_endwrite(r1_bio->mddev->bitmap, r1_bio->sector, + r1_bio->sectors, + !test_bit(R1BIO_Degraded, &r1_bio->state), + behind); + md_write_end(r1_bio->mddev); + raid_end_bio_io(r1_bio); } if (to_put) @@ -788,16 +779,13 @@ static int make_request(mddev_t *mddev, struct bio * bio) struct page **behind_pages = NULL; const int rw = bio_data_dir(bio); const unsigned long do_sync = (bio->bi_rw & REQ_SYNC); - unsigned long do_barriers; + const unsigned long do_flush_fua = (bio->bi_rw & (REQ_FLUSH | REQ_FUA)); mdk_rdev_t *blocked_rdev; /* * Register the new request and wait if the reconstruction * thread has put up a bar for new requests. * Continue immediately if no resync is active currently. - * We test barriers_work *after* md_write_start as md_write_start - * may cause the first superblock write, and that will check out - * if barriers work. */ md_write_start(mddev, bio); /* wait on superblock update early */ @@ -821,13 +809,6 @@ static int make_request(mddev_t *mddev, struct bio * bio) } finish_wait(&conf->wait_barrier, &w); } - if (unlikely(!mddev->barriers_work && - (bio->bi_rw & REQ_HARDBARRIER))) { - if (rw == WRITE) - md_write_end(mddev); - bio_endio(bio, -EOPNOTSUPP); - return 0; - } wait_barrier(conf); @@ -959,10 +940,6 @@ static int make_request(mddev_t *mddev, struct bio * bio) atomic_set(&r1_bio->remaining, 0); atomic_set(&r1_bio->behind_remaining, 0); - do_barriers = bio->bi_rw & REQ_HARDBARRIER; - if (do_barriers) - set_bit(R1BIO_Barrier, &r1_bio->state); - bio_list_init(&bl); for (i = 0; i < disks; i++) { struct bio *mbio; @@ -975,7 +952,7 @@ static int make_request(mddev_t *mddev, struct bio * bio) mbio->bi_sector = r1_bio->sector + conf->mirrors[i].rdev->data_offset; mbio->bi_bdev = conf->mirrors[i].rdev->bdev; mbio->bi_end_io = raid1_end_write_request; - mbio->bi_rw = WRITE | do_barriers | do_sync; + mbio->bi_rw = WRITE | do_flush_fua | do_sync; mbio->bi_private = r1_bio; if (behind_pages) { @@ -1634,41 +1611,6 @@ static void raid1d(mddev_t *mddev) if (test_bit(R1BIO_IsSync, &r1_bio->state)) { sync_request_write(mddev, r1_bio); unplug = 1; - } else if (test_bit(R1BIO_BarrierRetry, &r1_bio->state)) { - /* some requests in the r1bio were REQ_HARDBARRIER - * requests which failed with -EOPNOTSUPP. Hohumm.. - * Better resubmit without the barrier. - * We know which devices to resubmit for, because - * all others have had their bios[] entry cleared. - * We already have a nr_pending reference on these rdevs. - */ - int i; - const unsigned long do_sync = (r1_bio->master_bio->bi_rw & REQ_SYNC); - clear_bit(R1BIO_BarrierRetry, &r1_bio->state); - clear_bit(R1BIO_Barrier, &r1_bio->state); - for (i=0; i < conf->raid_disks; i++) - if (r1_bio->bios[i]) - atomic_inc(&r1_bio->remaining); - for (i=0; i < conf->raid_disks; i++) - if (r1_bio->bios[i]) { - struct bio_vec *bvec; - int j; - - bio = bio_clone(r1_bio->master_bio, GFP_NOIO); - /* copy pages from the failed bio, as - * this might be a write-behind device */ - __bio_for_each_segment(bvec, bio, j, 0) - bvec->bv_page = bio_iovec_idx(r1_bio->bios[i], j)->bv_page; - bio_put(r1_bio->bios[i]); - bio->bi_sector = r1_bio->sector + - conf->mirrors[i].rdev->data_offset; - bio->bi_bdev = conf->mirrors[i].rdev->bdev; - bio->bi_end_io = raid1_end_write_request; - bio->bi_rw = WRITE | do_sync; - bio->bi_private = r1_bio; - r1_bio->bios[i] = bio; - generic_make_request(bio); - } } else { int disk; diff --git a/drivers/md/raid1.h b/drivers/md/raid1.h index 5f2d443ae28a..adf8cfd73313 100644 --- a/drivers/md/raid1.h +++ b/drivers/md/raid1.h @@ -117,8 +117,6 @@ struct r1bio_s { #define R1BIO_IsSync 1 #define R1BIO_Degraded 2 #define R1BIO_BehindIO 3 -#define R1BIO_Barrier 4 -#define R1BIO_BarrierRetry 5 /* For write-behind requests, we call bi_end_io when * the last non-write-behind device completes, providing * any write was successful. Otherwise we call when diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 84718383124d..f0d082f749be 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -800,12 +800,13 @@ static int make_request(mddev_t *mddev, struct bio * bio) int chunk_sects = conf->chunk_mask + 1; const int rw = bio_data_dir(bio); const unsigned long do_sync = (bio->bi_rw & REQ_SYNC); + const unsigned long do_fua = (bio->bi_rw & REQ_FUA); struct bio_list bl; unsigned long flags; mdk_rdev_t *blocked_rdev; - if (unlikely(bio->bi_rw & REQ_HARDBARRIER)) { - md_barrier_request(mddev, bio); + if (unlikely(bio->bi_rw & REQ_FLUSH)) { + md_flush_request(mddev, bio); return 0; } @@ -965,7 +966,7 @@ static int make_request(mddev_t *mddev, struct bio * bio) conf->mirrors[d].rdev->data_offset; mbio->bi_bdev = conf->mirrors[d].rdev->bdev; mbio->bi_end_io = raid10_end_write_request; - mbio->bi_rw = WRITE | do_sync; + mbio->bi_rw = WRITE | do_sync | do_fua; mbio->bi_private = r10_bio; atomic_inc(&r10_bio->remaining); diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 69b0a169e43d..31140d1259dc 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -506,9 +506,12 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s) int rw; struct bio *bi; mdk_rdev_t *rdev; - if (test_and_clear_bit(R5_Wantwrite, &sh->dev[i].flags)) - rw = WRITE; - else if (test_and_clear_bit(R5_Wantread, &sh->dev[i].flags)) + if (test_and_clear_bit(R5_Wantwrite, &sh->dev[i].flags)) { + if (test_and_clear_bit(R5_WantFUA, &sh->dev[i].flags)) + rw = WRITE_FUA; + else + rw = WRITE; + } else if (test_and_clear_bit(R5_Wantread, &sh->dev[i].flags)) rw = READ; else continue; @@ -1031,6 +1034,8 @@ ops_run_biodrain(struct stripe_head *sh, struct dma_async_tx_descriptor *tx) while (wbi && wbi->bi_sector < dev->sector + STRIPE_SECTORS) { + if (wbi->bi_rw & REQ_FUA) + set_bit(R5_WantFUA, &dev->flags); tx = async_copy_data(1, wbi, dev->page, dev->sector, tx); wbi = r5_next_bio(wbi, dev->sector); @@ -1048,15 +1053,22 @@ static void ops_complete_reconstruct(void *stripe_head_ref) int pd_idx = sh->pd_idx; int qd_idx = sh->qd_idx; int i; + bool fua = false; pr_debug("%s: stripe %llu\n", __func__, (unsigned long long)sh->sector); + for (i = disks; i--; ) + fua |= test_bit(R5_WantFUA, &sh->dev[i].flags); + for (i = disks; i--; ) { struct r5dev *dev = &sh->dev[i]; - if (dev->written || i == pd_idx || i == qd_idx) + if (dev->written || i == pd_idx || i == qd_idx) { set_bit(R5_UPTODATE, &dev->flags); + if (fua) + set_bit(R5_WantFUA, &dev->flags); + } } if (sh->reconstruct_state == reconstruct_state_drain_run) @@ -3281,7 +3293,7 @@ static void handle_stripe5(struct stripe_head *sh) if (dec_preread_active) { /* We delay this until after ops_run_io so that if make_request - * is waiting on a barrier, it won't continue until the writes + * is waiting on a flush, it won't continue until the writes * have actually been submitted. */ atomic_dec(&conf->preread_active_stripes); @@ -3583,7 +3595,7 @@ static void handle_stripe6(struct stripe_head *sh) if (dec_preread_active) { /* We delay this until after ops_run_io so that if make_request - * is waiting on a barrier, it won't continue until the writes + * is waiting on a flush, it won't continue until the writes * have actually been submitted. */ atomic_dec(&conf->preread_active_stripes); @@ -3978,14 +3990,8 @@ static int make_request(mddev_t *mddev, struct bio * bi) const int rw = bio_data_dir(bi); int remaining; - if (unlikely(bi->bi_rw & REQ_HARDBARRIER)) { - /* Drain all pending writes. We only really need - * to ensure they have been submitted, but this is - * easier. - */ - mddev->pers->quiesce(mddev, 1); - mddev->pers->quiesce(mddev, 0); - md_barrier_request(mddev, bi); + if (unlikely(bi->bi_rw & REQ_FLUSH)) { + md_flush_request(mddev, bi); return 0; } @@ -4103,7 +4109,7 @@ static int make_request(mddev_t *mddev, struct bio * bi) finish_wait(&conf->wait_for_overlap, &w); set_bit(STRIPE_HANDLE, &sh->state); clear_bit(STRIPE_DELAYED, &sh->state); - if (mddev->barrier && + if ((bi->bi_rw & REQ_SYNC) && !test_and_set_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) atomic_inc(&conf->preread_active_stripes); release_stripe(sh); @@ -4126,13 +4132,6 @@ static int make_request(mddev_t *mddev, struct bio * bi) bio_endio(bi, 0); } - if (mddev->barrier) { - /* We need to wait for the stripes to all be handled. - * So: wait for preread_active_stripes to drop to 0. - */ - wait_event(mddev->thread->wqueue, - atomic_read(&conf->preread_active_stripes) == 0); - } return 0; } diff --git a/drivers/md/raid5.h b/drivers/md/raid5.h index 36eaed5dfd6e..2ace0582b409 100644 --- a/drivers/md/raid5.h +++ b/drivers/md/raid5.h @@ -275,6 +275,7 @@ struct r6_state { * filling */ #define R5_Wantdrain 13 /* dev->towrite needs to be drained */ +#define R5_WantFUA 14 /* Write should be FUA */ /* * Write method */ diff --git a/drivers/media/IR/imon.c b/drivers/media/IR/imon.c index c185422ef28c..faed5a332c71 100644 --- a/drivers/media/IR/imon.c +++ b/drivers/media/IR/imon.c @@ -151,7 +151,8 @@ static const struct file_operations vfd_fops = { .owner = THIS_MODULE, .open = &display_open, .write = &vfd_write, - .release = &display_close + .release = &display_close, + .llseek = noop_llseek, }; /* lcd character device file operations */ @@ -159,7 +160,8 @@ static const struct file_operations lcd_fops = { .owner = THIS_MODULE, .open = &display_open, .write = &lcd_write, - .release = &display_close + .release = &display_close, + .llseek = noop_llseek, }; enum { diff --git a/drivers/media/IR/ir-lirc-codec.c b/drivers/media/IR/ir-lirc-codec.c index e63f757d5d72..1983cd3f3994 100644 --- a/drivers/media/IR/ir-lirc-codec.c +++ b/drivers/media/IR/ir-lirc-codec.c @@ -235,6 +235,7 @@ static struct file_operations lirc_fops = { .poll = lirc_dev_fop_poll, .open = lirc_dev_fop_open, .release = lirc_dev_fop_close, + .llseek = no_llseek, }; static int ir_lirc_register(struct input_dev *input_dev) diff --git a/drivers/media/IR/lirc_dev.c b/drivers/media/IR/lirc_dev.c index 899891bec352..0acf6396e068 100644 --- a/drivers/media/IR/lirc_dev.c +++ b/drivers/media/IR/lirc_dev.c @@ -163,6 +163,7 @@ static struct file_operations fops = { .unlocked_ioctl = lirc_dev_fop_ioctl, .open = lirc_dev_fop_open, .release = lirc_dev_fop_close, + .llseek = noop_llseek, }; static int lirc_cdev_add(struct irctl *ir) @@ -460,6 +461,8 @@ error: mutex_unlock(&lirc_dev_lock); + nonseekable_open(inode, file); + return retval; } EXPORT_SYMBOL(lirc_dev_fop_open); diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index a28541b2b1a2..bad2cedb8d96 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -19,6 +19,7 @@ comment "Multimedia core support" config VIDEO_DEV tristate "Video For Linux" + depends on BKL # used in many drivers for ioctl handling, need to kill ---help--- V4L core support for video capture and overlay devices, webcams and AM/FM radio cards. diff --git a/drivers/media/dvb/bt8xx/dst_ca.c b/drivers/media/dvb/bt8xx/dst_ca.c index cf8705162845..48e48e8af55a 100644 --- a/drivers/media/dvb/bt8xx/dst_ca.c +++ b/drivers/media/dvb/bt8xx/dst_ca.c @@ -22,7 +22,7 @@ #include <linux/module.h> #include <linux/slab.h> #include <linux/init.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/string.h> #include <linux/dvb/ca.h> #include "dvbdev.h" @@ -52,6 +52,7 @@ } while(0) +static DEFINE_MUTEX(dst_ca_mutex); static unsigned int verbose = 5; module_param(verbose, int, 0644); MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)"); @@ -564,7 +565,7 @@ static long dst_ca_ioctl(struct file *file, unsigned int cmd, unsigned long ioct void __user *arg = (void __user *)ioctl_arg; int result = 0; - lock_kernel(); + mutex_lock(&dst_ca_mutex); dvbdev = file->private_data; state = (struct dst_state *)dvbdev->priv; p_ca_message = kmalloc(sizeof (struct ca_msg), GFP_KERNEL); @@ -652,7 +653,7 @@ static long dst_ca_ioctl(struct file *file, unsigned int cmd, unsigned long ioct kfree (p_ca_slot_info); kfree (p_ca_caps); - unlock_kernel(); + mutex_unlock(&dst_ca_mutex); return result; } @@ -694,7 +695,8 @@ static const struct file_operations dst_ca_fops = { .open = dst_ca_open, .release = dst_ca_release, .read = dst_ca_read, - .write = dst_ca_write + .write = dst_ca_write, + .llseek = noop_llseek, }; static struct dvb_device dvbdev_ca = { diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c index 0042306ea11b..ad1f61d301e1 100644 --- a/drivers/media/dvb/dvb-core/dmxdev.c +++ b/drivers/media/dvb/dvb-core/dmxdev.c @@ -25,7 +25,6 @@ #include <linux/slab.h> #include <linux/vmalloc.h> #include <linux/module.h> -#include <linux/smp_lock.h> #include <linux/poll.h> #include <linux/ioctl.h> #include <linux/wait.h> @@ -1088,13 +1087,7 @@ static int dvb_demux_do_ioctl(struct file *file, static long dvb_demux_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - int ret; - - lock_kernel(); - ret = dvb_usercopy(file, cmd, arg, dvb_demux_do_ioctl); - unlock_kernel(); - - return ret; + return dvb_usercopy(file, cmd, arg, dvb_demux_do_ioctl); } static unsigned int dvb_demux_poll(struct file *file, poll_table *wait) @@ -1150,6 +1143,7 @@ static const struct file_operations dvb_demux_fops = { .open = dvb_demux_open, .release = dvb_demux_release, .poll = dvb_demux_poll, + .llseek = default_llseek, }; static struct dvb_device dvbdev_demux = { @@ -1186,13 +1180,7 @@ static int dvb_dvr_do_ioctl(struct file *file, static long dvb_dvr_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - int ret; - - lock_kernel(); - ret = dvb_usercopy(file, cmd, arg, dvb_dvr_do_ioctl); - unlock_kernel(); - - return ret; + return dvb_usercopy(file, cmd, arg, dvb_dvr_do_ioctl); } static unsigned int dvb_dvr_poll(struct file *file, poll_table *wait) @@ -1225,6 +1213,7 @@ static const struct file_operations dvb_dvr_fops = { .open = dvb_dvr_open, .release = dvb_dvr_release, .poll = dvb_dvr_poll, + .llseek = default_llseek, }; static struct dvb_device dvbdev_dvr = { diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c index cb97e6b85432..4d0646da6087 100644 --- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c +++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c @@ -1259,13 +1259,7 @@ static int dvb_ca_en50221_io_do_ioctl(struct file *file, static long dvb_ca_en50221_io_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - int ret; - - lock_kernel(); - ret = dvb_usercopy(file, cmd, arg, dvb_ca_en50221_io_do_ioctl); - unlock_kernel(); - - return ret; + return dvb_usercopy(file, cmd, arg, dvb_ca_en50221_io_do_ioctl); } @@ -1628,6 +1622,7 @@ static const struct file_operations dvb_ca_fops = { .open = dvb_ca_en50221_io_open, .release = dvb_ca_en50221_io_release, .poll = dvb_ca_en50221_io_poll, + .llseek = noop_llseek, }; static struct dvb_device dvbdev_ca = { diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 4d45b7d6b3fb..970c9b8882d4 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -2034,7 +2034,8 @@ static const struct file_operations dvb_frontend_fops = { .unlocked_ioctl = dvb_generic_ioctl, .poll = dvb_frontend_poll, .open = dvb_frontend_open, - .release = dvb_frontend_release + .release = dvb_frontend_release, + .llseek = noop_llseek, }; int dvb_register_frontend(struct dvb_adapter* dvb, diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c index 6c3a8a06ccab..4df42aaae7f7 100644 --- a/drivers/media/dvb/dvb-core/dvb_net.c +++ b/drivers/media/dvb/dvb-core/dvb_net.c @@ -59,7 +59,6 @@ #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/dvb/net.h> -#include <linux/smp_lock.h> #include <linux/uio.h> #include <asm/uaccess.h> #include <linux/crc32.h> @@ -1445,13 +1444,7 @@ static int dvb_net_do_ioctl(struct file *file, static long dvb_net_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - int ret; - - lock_kernel(); - ret = dvb_usercopy(file, cmd, arg, dvb_net_do_ioctl); - unlock_kernel(); - - return ret; + return dvb_usercopy(file, cmd, arg, dvb_net_do_ioctl); } static int dvb_net_close(struct inode *inode, struct file *file) @@ -1475,6 +1468,7 @@ static const struct file_operations dvb_net_fops = { .unlocked_ioctl = dvb_net_ioctl, .open = dvb_generic_open, .release = dvb_net_close, + .llseek = noop_llseek, }; static struct dvb_device dvbdev_net = { diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c index b915c39d782f..f73287775953 100644 --- a/drivers/media/dvb/dvb-core/dvbdev.c +++ b/drivers/media/dvb/dvb-core/dvbdev.c @@ -32,9 +32,9 @@ #include <linux/fs.h> #include <linux/cdev.h> #include <linux/mutex.h> -#include <linux/smp_lock.h> #include "dvbdev.h" +static DEFINE_MUTEX(dvbdev_mutex); static int dvbdev_debug; module_param(dvbdev_debug, int, 0644); @@ -68,7 +68,7 @@ static int dvb_device_open(struct inode *inode, struct file *file) { struct dvb_device *dvbdev; - lock_kernel(); + mutex_lock(&dvbdev_mutex); down_read(&minor_rwsem); dvbdev = dvb_minors[iminor(inode)]; @@ -91,12 +91,12 @@ static int dvb_device_open(struct inode *inode, struct file *file) } fops_put(old_fops); up_read(&minor_rwsem); - unlock_kernel(); + mutex_unlock(&dvbdev_mutex); return err; } fail: up_read(&minor_rwsem); - unlock_kernel(); + mutex_unlock(&dvbdev_mutex); return -ENODEV; } @@ -105,6 +105,7 @@ static const struct file_operations dvb_device_fops = { .owner = THIS_MODULE, .open = dvb_device_open, + .llseek = noop_llseek, }; static struct cdev dvb_device_cdev; @@ -158,7 +159,6 @@ long dvb_generic_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct dvb_device *dvbdev = file->private_data; - int ret; if (!dvbdev) return -ENODEV; @@ -166,11 +166,7 @@ long dvb_generic_ioctl(struct file *file, if (!dvbdev->kernel_ioctl) return -EINVAL; - lock_kernel(); - ret = dvb_usercopy(file, cmd, arg, dvbdev->kernel_ioctl); - unlock_kernel(); - - return ret; + return dvb_usercopy(file, cmd, arg, dvbdev->kernel_ioctl); } EXPORT_SYMBOL(dvb_generic_ioctl); @@ -421,8 +417,10 @@ int dvb_usercopy(struct file *file, } /* call driver */ + mutex_lock(&dvbdev_mutex); if ((err = func(file, cmd, parg)) == -ENOIOCTLCMD) err = -EINVAL; + mutex_unlock(&dvbdev_mutex); if (err < 0) goto out; diff --git a/drivers/media/dvb/firewire/firedtv-ci.c b/drivers/media/dvb/firewire/firedtv-ci.c index d3c2cf60de76..8ffb565f0704 100644 --- a/drivers/media/dvb/firewire/firedtv-ci.c +++ b/drivers/media/dvb/firewire/firedtv-ci.c @@ -220,6 +220,7 @@ static const struct file_operations fdtv_ca_fops = { .open = dvb_generic_open, .release = dvb_generic_release, .poll = fdtv_ca_io_poll, + .llseek = noop_llseek, }; static struct dvb_device fdtv_ca = { diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index a6be529eec5c..893fbc57c72f 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c @@ -730,6 +730,7 @@ static const struct file_operations dvb_osd_fops = { .unlocked_ioctl = dvb_generic_ioctl, .open = dvb_generic_open, .release = dvb_generic_release, + .llseek = noop_llseek, }; static struct dvb_device dvbdev_osd = { diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c index 13efba942dac..6ef3996565ad 100644 --- a/drivers/media/dvb/ttpci/av7110_av.c +++ b/drivers/media/dvb/ttpci/av7110_av.c @@ -1521,6 +1521,7 @@ static const struct file_operations dvb_video_fops = { .open = dvb_video_open, .release = dvb_video_release, .poll = dvb_video_poll, + .llseek = noop_llseek, }; static struct dvb_device dvbdev_video = { @@ -1539,6 +1540,7 @@ static const struct file_operations dvb_audio_fops = { .open = dvb_audio_open, .release = dvb_audio_release, .poll = dvb_audio_poll, + .llseek = noop_llseek, }; static struct dvb_device dvbdev_audio = { diff --git a/drivers/media/dvb/ttpci/av7110_ca.c b/drivers/media/dvb/ttpci/av7110_ca.c index 4eba35a018e3..43f61f2eca98 100644 --- a/drivers/media/dvb/ttpci/av7110_ca.c +++ b/drivers/media/dvb/ttpci/av7110_ca.c @@ -353,6 +353,7 @@ static const struct file_operations dvb_ca_fops = { .open = dvb_ca_open, .release = dvb_generic_release, .poll = dvb_ca_poll, + .llseek = default_llseek, }; static struct dvb_device dvbdev_ca = { diff --git a/drivers/media/dvb/ttpci/av7110_ir.c b/drivers/media/dvb/ttpci/av7110_ir.c index b070e88d8c6b..908f272fe26c 100644 --- a/drivers/media/dvb/ttpci/av7110_ir.c +++ b/drivers/media/dvb/ttpci/av7110_ir.c @@ -312,6 +312,7 @@ static ssize_t av7110_ir_proc_write(struct file *file, const char __user *buffer static const struct file_operations av7110_ir_proc_fops = { .owner = THIS_MODULE, .write = av7110_ir_proc_write, + .llseek = noop_llseek, }; /* interrupt handler */ diff --git a/drivers/media/video/dabusb.c b/drivers/media/video/dabusb.c index 5b176bd7afdb..f3e25e91366d 100644 --- a/drivers/media/video/dabusb.c +++ b/drivers/media/video/dabusb.c @@ -32,7 +32,6 @@ #include <linux/list.h> #include <linux/vmalloc.h> #include <linux/slab.h> -#include <linux/smp_lock.h> #include <linux/init.h> #include <asm/uaccess.h> #include <asm/atomic.h> @@ -621,7 +620,6 @@ static int dabusb_open (struct inode *inode, struct file *file) if (devnum < DABUSB_MINOR || devnum >= (DABUSB_MINOR + NRDABUSB)) return -EIO; - lock_kernel(); s = &dabusb[devnum - DABUSB_MINOR]; dbg("dabusb_open"); @@ -630,21 +628,17 @@ static int dabusb_open (struct inode *inode, struct file *file) while (!s->usbdev || s->opened) { mutex_unlock(&s->mutex); - if (file->f_flags & O_NONBLOCK) { + if (file->f_flags & O_NONBLOCK) return -EBUSY; - } msleep_interruptible(500); - if (signal_pending (current)) { - unlock_kernel(); + if (signal_pending (current)) return -EAGAIN; - } mutex_lock(&s->mutex); } if (usb_set_interface (s->usbdev, _DABUSB_IF, 1) < 0) { mutex_unlock(&s->mutex); dev_err(&s->usbdev->dev, "set_interface failed\n"); - unlock_kernel(); return -EINVAL; } s->opened = 1; @@ -654,7 +648,6 @@ static int dabusb_open (struct inode *inode, struct file *file) file->private_data = s; r = nonseekable_open(inode, file); - unlock_kernel(); return r; } @@ -689,17 +682,13 @@ static long dabusb_ioctl (struct file *file, unsigned int cmd, unsigned long arg dbg("dabusb_ioctl"); - lock_kernel(); - if (s->remove_pending) { - unlock_kernel(); + if (s->remove_pending) return -EIO; - } mutex_lock(&s->mutex); if (!s->usbdev) { mutex_unlock(&s->mutex); - unlock_kernel(); return -EIO; } @@ -735,7 +724,6 @@ static long dabusb_ioctl (struct file *file, unsigned int cmd, unsigned long arg break; } mutex_unlock(&s->mutex); - unlock_kernel(); return ret; } diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c index d3f1a087eced..02362eccc588 100644 --- a/drivers/memstick/core/mspro_block.c +++ b/drivers/memstick/core/mspro_block.c @@ -18,11 +18,12 @@ #include <linux/kthread.h> #include <linux/delay.h> #include <linux/slab.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/memstick.h> #define DRIVER_NAME "mspro_block" +static DEFINE_MUTEX(mspro_block_mutex); static int major; module_param(major, int, 0644); @@ -180,7 +181,7 @@ static int mspro_block_bd_open(struct block_device *bdev, fmode_t mode) struct mspro_block_data *msb = disk->private_data; int rc = -ENXIO; - lock_kernel(); + mutex_lock(&mspro_block_mutex); mutex_lock(&mspro_block_disk_lock); if (msb && msb->card) { @@ -192,7 +193,7 @@ static int mspro_block_bd_open(struct block_device *bdev, fmode_t mode) } mutex_unlock(&mspro_block_disk_lock); - unlock_kernel(); + mutex_unlock(&mspro_block_mutex); return rc; } @@ -225,9 +226,9 @@ static int mspro_block_disk_release(struct gendisk *disk) static int mspro_block_bd_release(struct gendisk *disk, fmode_t mode) { int ret; - lock_kernel(); + mutex_lock(&mspro_block_mutex); ret = mspro_block_disk_release(disk); - unlock_kernel(); + mutex_unlock(&mspro_block_mutex); return ret; } diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index 6837a8ef9371..3e57b61ca446 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -5945,8 +5945,10 @@ mpt_findImVolumes(MPT_ADAPTER *ioc) goto out; mem = kmalloc(iocpage2sz, GFP_KERNEL); - if (!mem) + if (!mem) { + rc = -ENOMEM; goto out; + } memcpy(mem, (u8 *)pIoc2, iocpage2sz); ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem; diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c index d8ddfdf8be14..a3856ed90aef 100644 --- a/drivers/message/fusion/mptctl.c +++ b/drivers/message/fusion/mptctl.c @@ -54,7 +54,7 @@ #include <linux/pci.h> #include <linux/delay.h> /* for mdelay */ #include <linux/miscdevice.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/compat.h> #include <asm/io.h> @@ -83,6 +83,7 @@ MODULE_VERSION(my_VERSION); /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static DEFINE_MUTEX(mpctl_mutex); static u8 mptctl_id = MPT_MAX_PROTOCOL_DRIVERS; static u8 mptctl_taskmgmt_id = MPT_MAX_PROTOCOL_DRIVERS; @@ -601,12 +602,12 @@ mptctl_fasync(int fd, struct file *filep, int mode) MPT_ADAPTER *ioc; int ret; - lock_kernel(); + mutex_lock(&mpctl_mutex); list_for_each_entry(ioc, &ioc_list, list) ioc->aen_event_read_flag=0; ret = fasync_helper(fd, filep, mode, &async_queue); - unlock_kernel(); + mutex_unlock(&mpctl_mutex); return ret; } @@ -698,9 +699,9 @@ static long mptctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { long ret; - lock_kernel(); + mutex_lock(&mpctl_mutex); ret = __mptctl_ioctl(file, cmd, arg); - unlock_kernel(); + mutex_unlock(&mpctl_mutex); return ret; } @@ -2926,7 +2927,7 @@ compat_mpt_command(struct file *filp, unsigned int cmd, static long compat_mpctl_ioctl(struct file *f, unsigned int cmd, unsigned long arg) { long ret; - lock_kernel(); + mutex_lock(&mpctl_mutex); switch (cmd) { case MPTIOCINFO: case MPTIOCINFO1: @@ -2951,7 +2952,7 @@ static long compat_mpctl_ioctl(struct file *f, unsigned int cmd, unsigned long a ret = -ENOIOCTLCMD; break; } - unlock_kernel(); + mutex_unlock(&mpctl_mutex); return ret; } diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c index f0f1e667000f..f87a9d405a5e 100644 --- a/drivers/message/i2o/i2o_block.c +++ b/drivers/message/i2o/i2o_block.c @@ -53,7 +53,7 @@ #include <linux/module.h> #include <linux/slab.h> #include <linux/i2o.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/mempool.h> @@ -69,6 +69,7 @@ #define OSM_VERSION "1.325" #define OSM_DESCRIPTION "I2O Block Device OSM" +static DEFINE_MUTEX(i2o_block_mutex); static struct i2o_driver i2o_block_driver; /* global Block OSM request mempool */ @@ -578,7 +579,7 @@ static int i2o_block_open(struct block_device *bdev, fmode_t mode) if (!dev->i2o_dev) return -ENODEV; - lock_kernel(); + mutex_lock(&i2o_block_mutex); if (dev->power > 0x1f) i2o_block_device_power(dev, 0x02); @@ -587,7 +588,7 @@ static int i2o_block_open(struct block_device *bdev, fmode_t mode) i2o_block_device_lock(dev->i2o_dev, -1); osm_debug("Ready.\n"); - unlock_kernel(); + mutex_unlock(&i2o_block_mutex); return 0; }; @@ -618,7 +619,7 @@ static int i2o_block_release(struct gendisk *disk, fmode_t mode) if (!dev->i2o_dev) return 0; - lock_kernel(); + mutex_lock(&i2o_block_mutex); i2o_block_device_flush(dev->i2o_dev); i2o_block_device_unlock(dev->i2o_dev, -1); @@ -629,7 +630,7 @@ static int i2o_block_release(struct gendisk *disk, fmode_t mode) operation = 0x24; i2o_block_device_power(dev, operation); - unlock_kernel(); + mutex_unlock(&i2o_block_mutex); return 0; } @@ -664,7 +665,7 @@ static int i2o_block_ioctl(struct block_device *bdev, fmode_t mode, if (!capable(CAP_SYS_ADMIN)) return -EPERM; - lock_kernel(); + mutex_lock(&i2o_block_mutex); switch (cmd) { case BLKI2OGRSTRAT: ret = put_user(dev->rcache, (int __user *)arg); @@ -688,7 +689,7 @@ static int i2o_block_ioctl(struct block_device *bdev, fmode_t mode, ret = 0; break; } - unlock_kernel(); + mutex_unlock(&i2o_block_mutex); return ret; }; diff --git a/drivers/message/i2o/i2o_config.c b/drivers/message/i2o/i2o_config.c index 068ba0785bb4..7d3cc575c361 100644 --- a/drivers/message/i2o/i2o_config.c +++ b/drivers/message/i2o/i2o_config.c @@ -31,7 +31,7 @@ */ #include <linux/miscdevice.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/compat.h> #include <linux/slab.h> @@ -41,6 +41,7 @@ #define SG_TABLESIZE 30 +static DEFINE_MUTEX(i2o_cfg_mutex); static long i2o_cfg_ioctl(struct file *, unsigned int, unsigned long); static spinlock_t i2o_config_lock; @@ -741,7 +742,7 @@ static long i2o_cfg_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg) { int ret; - lock_kernel(); + mutex_lock(&i2o_cfg_mutex); switch (cmd) { case I2OGETIOPS: ret = i2o_cfg_ioctl(file, cmd, arg); @@ -753,7 +754,7 @@ static long i2o_cfg_compat_ioctl(struct file *file, unsigned cmd, ret = -ENOIOCTLCMD; break; } - unlock_kernel(); + mutex_unlock(&i2o_cfg_mutex); return ret; } @@ -981,7 +982,7 @@ static long i2o_cfg_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) { int ret; - lock_kernel(); + mutex_lock(&i2o_cfg_mutex); switch (cmd) { case I2OGETIOPS: ret = i2o_cfg_getiops(arg); @@ -1037,7 +1038,7 @@ static long i2o_cfg_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) osm_debug("unknown ioctl called!\n"); ret = -EINVAL; } - unlock_kernel(); + mutex_unlock(&i2o_cfg_mutex); return ret; } @@ -1051,7 +1052,7 @@ static int cfg_open(struct inode *inode, struct file *file) if (!tmp) return -ENOMEM; - lock_kernel(); + mutex_lock(&i2o_cfg_mutex); file->private_data = (void *)(i2o_cfg_info_id++); tmp->fp = file; tmp->fasync = NULL; @@ -1065,7 +1066,7 @@ static int cfg_open(struct inode *inode, struct file *file) spin_lock_irqsave(&i2o_config_lock, flags); open_files = tmp; spin_unlock_irqrestore(&i2o_config_lock, flags); - unlock_kernel(); + mutex_unlock(&i2o_cfg_mutex); return 0; } @@ -1076,14 +1077,14 @@ static int cfg_fasync(int fd, struct file *fp, int on) struct i2o_cfg_info *p; int ret = -EBADF; - lock_kernel(); + mutex_lock(&i2o_cfg_mutex); for (p = open_files; p; p = p->next) if (p->q_id == id) break; if (p) ret = fasync_helper(fd, fp, on, &p->fasync); - unlock_kernel(); + mutex_unlock(&i2o_cfg_mutex); return ret; } @@ -1093,7 +1094,7 @@ static int cfg_release(struct inode *inode, struct file *file) struct i2o_cfg_info *p, **q; unsigned long flags; - lock_kernel(); + mutex_lock(&i2o_cfg_mutex); spin_lock_irqsave(&i2o_config_lock, flags); for (q = &open_files; (p = *q) != NULL; q = &p->next) { if (p->q_id == id) { @@ -1103,7 +1104,7 @@ static int cfg_release(struct inode *inode, struct file *file) } } spin_unlock_irqrestore(&i2o_config_lock, flags); - unlock_kernel(); + mutex_unlock(&i2o_cfg_mutex); return 0; } diff --git a/drivers/mfd/ab3100-core.c b/drivers/mfd/ab3100-core.c index 66379b413906..b048ecc56db9 100644 --- a/drivers/mfd/ab3100-core.c +++ b/drivers/mfd/ab3100-core.c @@ -583,6 +583,7 @@ static ssize_t ab3100_get_set_reg(struct file *file, static const struct file_operations ab3100_get_set_reg_fops = { .open = ab3100_get_set_reg_open_file, .write = ab3100_get_set_reg, + .llseek = noop_llseek, }; static struct dentry *ab3100_dir; diff --git a/drivers/mfd/ab8500-spi.c b/drivers/mfd/ab8500-spi.c index e1c8b62b086d..01b6d584442c 100644 --- a/drivers/mfd/ab8500-spi.c +++ b/drivers/mfd/ab8500-spi.c @@ -83,6 +83,11 @@ static int __devinit ab8500_spi_probe(struct spi_device *spi) struct ab8500 *ab8500; int ret; + spi->bits_per_word = 24; + ret = spi_setup(spi); + if (ret < 0) + return ret; + ab8500 = kzalloc(sizeof *ab8500, GFP_KERNEL); if (!ab8500) return -ENOMEM; diff --git a/drivers/mfd/twl4030-irq.c b/drivers/mfd/twl4030-irq.c index 097f24d8bceb..b9fda7018cef 100644 --- a/drivers/mfd/twl4030-irq.c +++ b/drivers/mfd/twl4030-irq.c @@ -78,7 +78,7 @@ struct sih { u8 irq_lines; /* number of supported irq lines */ /* SIR ignored -- set interrupt, for testing only */ - struct irq_data { + struct sih_irq_data { u8 isr_offset; u8 imr_offset; } mask[2]; @@ -810,7 +810,7 @@ int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end) twl4030_irq_chip = dummy_irq_chip; twl4030_irq_chip.name = "twl4030"; - twl4030_sih_irq_chip.ack = dummy_irq_chip.ack; + twl4030_sih_irq_chip.irq_ack = dummy_irq_chip.irq_ack; for (i = irq_base; i < irq_end; i++) { set_irq_chip_and_handler(i, &twl4030_irq_chip, diff --git a/drivers/misc/hpilo.c b/drivers/misc/hpilo.c index d4158ec8c860..fffc227181b0 100644 --- a/drivers/misc/hpilo.c +++ b/drivers/misc/hpilo.c @@ -640,6 +640,7 @@ static const struct file_operations ilo_fops = { .poll = ilo_poll, .open = ilo_open, .release = ilo_close, + .llseek = noop_llseek, }; static irqreturn_t ilo_isr(int irq, void *data) diff --git a/drivers/misc/ibmasm/ibmasmfs.c b/drivers/misc/ibmasm/ibmasmfs.c index 8844a3f45381..af2497ae5fe3 100644 --- a/drivers/misc/ibmasm/ibmasmfs.c +++ b/drivers/misc/ibmasm/ibmasmfs.c @@ -584,6 +584,7 @@ static const struct file_operations command_fops = { .release = command_file_close, .read = command_file_read, .write = command_file_write, + .llseek = generic_file_llseek, }; static const struct file_operations event_fops = { @@ -591,6 +592,7 @@ static const struct file_operations event_fops = { .release = event_file_close, .read = event_file_read, .write = event_file_write, + .llseek = generic_file_llseek, }; static const struct file_operations r_heartbeat_fops = { @@ -598,6 +600,7 @@ static const struct file_operations r_heartbeat_fops = { .release = r_heartbeat_file_close, .read = r_heartbeat_file_read, .write = r_heartbeat_file_write, + .llseek = generic_file_llseek, }; static const struct file_operations remote_settings_fops = { @@ -605,6 +608,7 @@ static const struct file_operations remote_settings_fops = { .release = remote_settings_file_close, .read = remote_settings_file_read, .write = remote_settings_file_write, + .llseek = generic_file_llseek, }; diff --git a/drivers/misc/iwmc3200top/debugfs.c b/drivers/misc/iwmc3200top/debugfs.c index e9eda471f6e0..62fbaec48207 100644 --- a/drivers/misc/iwmc3200top/debugfs.c +++ b/drivers/misc/iwmc3200top/debugfs.c @@ -71,6 +71,7 @@ ssize_t iwmct_dbgfs_##name##_write(struct file *file, \ static const struct file_operations iwmct_dbgfs_##name##_ops = { \ .read = iwmct_dbgfs_##name##_read, \ .open = iwmct_dbgfs_open_file_generic, \ + .llseek = generic_file_llseek, \ }; #define DEBUGFS_WRITE_FILE_OPS(name) \ @@ -78,6 +79,7 @@ ssize_t iwmct_dbgfs_##name##_write(struct file *file, \ static const struct file_operations iwmct_dbgfs_##name##_ops = { \ .write = iwmct_dbgfs_##name##_write, \ .open = iwmct_dbgfs_open_file_generic, \ + .llseek = generic_file_llseek, \ }; #define DEBUGFS_READ_WRITE_FILE_OPS(name) \ @@ -87,6 +89,7 @@ ssize_t iwmct_dbgfs_##name##_write(struct file *file, \ .write = iwmct_dbgfs_##name##_write, \ .read = iwmct_dbgfs_##name##_read, \ .open = iwmct_dbgfs_open_file_generic, \ + .llseek = generic_file_llseek, \ }; diff --git a/drivers/misc/lkdtm.c b/drivers/misc/lkdtm.c index ef34de7a8026..343b5d8ea697 100644 --- a/drivers/misc/lkdtm.c +++ b/drivers/misc/lkdtm.c @@ -575,30 +575,39 @@ struct crash_entry { static const struct crash_entry crash_entries[] = { {"DIRECT", {.read = lkdtm_debugfs_read, + .llseek = generic_file_llseek, .open = lkdtm_debugfs_open, .write = direct_entry} }, {"INT_HARDWARE_ENTRY", {.read = lkdtm_debugfs_read, + .llseek = generic_file_llseek, .open = lkdtm_debugfs_open, .write = int_hardware_entry} }, {"INT_HW_IRQ_EN", {.read = lkdtm_debugfs_read, + .llseek = generic_file_llseek, .open = lkdtm_debugfs_open, .write = int_hw_irq_en} }, {"INT_TASKLET_ENTRY", {.read = lkdtm_debugfs_read, + .llseek = generic_file_llseek, .open = lkdtm_debugfs_open, .write = int_tasklet_entry} }, {"FS_DEVRW", {.read = lkdtm_debugfs_read, + .llseek = generic_file_llseek, .open = lkdtm_debugfs_open, .write = fs_devrw_entry} }, {"MEM_SWAPOUT", {.read = lkdtm_debugfs_read, + .llseek = generic_file_llseek, .open = lkdtm_debugfs_open, .write = mem_swapout_entry} }, {"TIMERADD", {.read = lkdtm_debugfs_read, + .llseek = generic_file_llseek, .open = lkdtm_debugfs_open, .write = timeradd_entry} }, {"SCSI_DISPATCH_CMD", {.read = lkdtm_debugfs_read, + .llseek = generic_file_llseek, .open = lkdtm_debugfs_open, .write = scsi_dispatch_cmd_entry} }, {"IDE_CORE_CP", {.read = lkdtm_debugfs_read, + .llseek = generic_file_llseek, .open = lkdtm_debugfs_open, .write = ide_core_cp_entry} }, }; diff --git a/drivers/misc/phantom.c b/drivers/misc/phantom.c index 75ee0d3f6f45..4197a3cb26ba 100644 --- a/drivers/misc/phantom.c +++ b/drivers/misc/phantom.c @@ -24,7 +24,7 @@ #include <linux/slab.h> #include <linux/phantom.h> #include <linux/sched.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <asm/atomic.h> #include <asm/io.h> @@ -38,6 +38,7 @@ #define PHB_RUNNING 1 #define PHB_NOT_OH 2 +static DEFINE_MUTEX(phantom_mutex); static struct class *phantom_class; static int phantom_major; @@ -215,17 +216,17 @@ static int phantom_open(struct inode *inode, struct file *file) struct phantom_device *dev = container_of(inode->i_cdev, struct phantom_device, cdev); - lock_kernel(); + mutex_lock(&phantom_mutex); nonseekable_open(inode, file); if (mutex_lock_interruptible(&dev->open_lock)) { - unlock_kernel(); + mutex_unlock(&phantom_mutex); return -ERESTARTSYS; } if (dev->opened) { mutex_unlock(&dev->open_lock); - unlock_kernel(); + mutex_unlock(&phantom_mutex); return -EINVAL; } @@ -236,7 +237,7 @@ static int phantom_open(struct inode *inode, struct file *file) atomic_set(&dev->counter, 0); dev->opened++; mutex_unlock(&dev->open_lock); - unlock_kernel(); + mutex_unlock(&phantom_mutex); return 0; } @@ -279,6 +280,7 @@ static const struct file_operations phantom_file_ops = { .unlocked_ioctl = phantom_ioctl, .compat_ioctl = phantom_compat_ioctl, .poll = phantom_poll, + .llseek = no_llseek, }; static irqreturn_t phantom_isr(int irq, void *data) diff --git a/drivers/misc/sgi-gru/grufile.c b/drivers/misc/sgi-gru/grufile.c index cb3b4d228475..28852dfa310d 100644 --- a/drivers/misc/sgi-gru/grufile.c +++ b/drivers/misc/sgi-gru/grufile.c @@ -587,6 +587,7 @@ static const struct file_operations gru_fops = { .owner = THIS_MODULE, .unlocked_ioctl = gru_file_unlocked_ioctl, .mmap = gru_file_mmap, + .llseek = noop_llseek, }; static struct miscdevice gru_miscdev = { diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index d545f79f6000..00073b7c0368 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -29,7 +29,6 @@ #include <linux/kdev_t.h> #include <linux/blkdev.h> #include <linux/mutex.h> -#include <linux/smp_lock.h> #include <linux/scatterlist.h> #include <linux/string_helpers.h> @@ -51,6 +50,7 @@ MODULE_ALIAS("mmc:block"); #define MMC_SHIFT 3 #define MMC_NUM_MINORS (256 >> MMC_SHIFT) +static DEFINE_MUTEX(block_mutex); static DECLARE_BITMAP(dev_use, MMC_NUM_MINORS); /* @@ -108,7 +108,7 @@ static int mmc_blk_open(struct block_device *bdev, fmode_t mode) struct mmc_blk_data *md = mmc_blk_get(bdev->bd_disk); int ret = -ENXIO; - lock_kernel(); + mutex_lock(&block_mutex); if (md) { if (md->usage == 2) check_disk_change(bdev); @@ -119,7 +119,7 @@ static int mmc_blk_open(struct block_device *bdev, fmode_t mode) ret = -EROFS; } } - unlock_kernel(); + mutex_unlock(&block_mutex); return ret; } @@ -128,9 +128,9 @@ static int mmc_blk_release(struct gendisk *disk, fmode_t mode) { struct mmc_blk_data *md = disk->private_data; - lock_kernel(); + mutex_lock(&block_mutex); mmc_blk_put(md); - unlock_kernel(); + mutex_unlock(&block_mutex); return 0; } diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c index e876678176be..9c0b42bfe089 100644 --- a/drivers/mmc/card/queue.c +++ b/drivers/mmc/card/queue.c @@ -128,7 +128,6 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock mq->req = NULL; blk_queue_prep_rq(mq->queue, mmc_prep_request); - blk_queue_ordered(mq->queue, QUEUE_ORDERED_DRAIN); queue_flag_set_unlocked(QUEUE_FLAG_NONROT, mq->queue); if (mmc_can_erase(card)) { queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, mq->queue); diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c index 53cb380c0987..46bc6d7551a3 100644 --- a/drivers/mmc/core/debugfs.c +++ b/drivers/mmc/core/debugfs.c @@ -245,6 +245,7 @@ static const struct file_operations mmc_dbg_ext_csd_fops = { .open = mmc_ext_csd_open, .read = mmc_ext_csd_read, .release = mmc_ext_csd_release, + .llseek = default_llseek, }; void mmc_add_card_debugfs(struct mmc_card *card) diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 840b301b5671..f2e02d7d9f3d 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -41,23 +41,35 @@ static unsigned int fmax = 515633; * @clkreg: default value for MCICLOCK register * @clkreg_enable: enable value for MMCICLOCK register * @datalength_bits: number of bits in the MMCIDATALENGTH register + * @fifosize: number of bytes that can be written when MMCI_TXFIFOEMPTY + * is asserted (likewise for RX) + * @fifohalfsize: number of bytes that can be written when MCI_TXFIFOHALFEMPTY + * is asserted (likewise for RX) */ struct variant_data { unsigned int clkreg; unsigned int clkreg_enable; unsigned int datalength_bits; + unsigned int fifosize; + unsigned int fifohalfsize; }; static struct variant_data variant_arm = { + .fifosize = 16 * 4, + .fifohalfsize = 8 * 4, .datalength_bits = 16, }; static struct variant_data variant_u300 = { + .fifosize = 16 * 4, + .fifohalfsize = 8 * 4, .clkreg_enable = 1 << 13, /* HWFCEN */ .datalength_bits = 16, }; static struct variant_data variant_ux500 = { + .fifosize = 30 * 4, + .fifohalfsize = 8 * 4, .clkreg = MCI_CLK_ENABLE, .clkreg_enable = 1 << 14, /* HWFCEN */ .datalength_bits = 24, @@ -138,6 +150,7 @@ static void mmci_init_sg(struct mmci_host *host, struct mmc_data *data) static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) { + struct variant_data *variant = host->variant; unsigned int datactrl, timeout, irqmask; unsigned long long clks; void __iomem *base; @@ -173,7 +186,7 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) * If we have less than a FIFOSIZE of bytes to transfer, * trigger a PIO interrupt as soon as any data is available. */ - if (host->size < MCI_FIFOSIZE) + if (host->size < variant->fifosize) irqmask |= MCI_RXDATAAVLBLMASK; } else { /* @@ -332,13 +345,15 @@ static int mmci_pio_read(struct mmci_host *host, char *buffer, unsigned int rema static int mmci_pio_write(struct mmci_host *host, char *buffer, unsigned int remain, u32 status) { + struct variant_data *variant = host->variant; void __iomem *base = host->base; char *ptr = buffer; do { unsigned int count, maxcnt; - maxcnt = status & MCI_TXFIFOEMPTY ? MCI_FIFOSIZE : MCI_FIFOHALFSIZE; + maxcnt = status & MCI_TXFIFOEMPTY ? + variant->fifosize : variant->fifohalfsize; count = min(remain, maxcnt); writesl(base + MMCIFIFO, ptr, count >> 2); @@ -362,6 +377,7 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id) { struct mmci_host *host = dev_id; struct sg_mapping_iter *sg_miter = &host->sg_miter; + struct variant_data *variant = host->variant; void __iomem *base = host->base; unsigned long flags; u32 status; @@ -420,7 +436,7 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id) * If we're nearing the end of the read, switch to * "any data available" mode. */ - if (status & MCI_RXACTIVE && host->size < MCI_FIFOSIZE) + if (status & MCI_RXACTIVE && host->size < variant->fifosize) writel(MCI_RXDATAAVLBLMASK, base + MMCIMASK1); /* @@ -564,18 +580,23 @@ static int mmci_get_ro(struct mmc_host *mmc) if (host->gpio_wp == -ENOSYS) return -ENOSYS; - return gpio_get_value(host->gpio_wp); + return gpio_get_value_cansleep(host->gpio_wp); } static int mmci_get_cd(struct mmc_host *mmc) { struct mmci_host *host = mmc_priv(mmc); + struct mmci_platform_data *plat = host->plat; unsigned int status; - if (host->gpio_cd == -ENOSYS) - status = host->plat->status(mmc_dev(host->mmc)); - else - status = !gpio_get_value(host->gpio_cd); + if (host->gpio_cd == -ENOSYS) { + if (!plat->status) + return 1; /* Assume always present */ + + status = plat->status(mmc_dev(host->mmc)); + } else + status = !!gpio_get_value_cansleep(host->gpio_cd) + ^ plat->cd_invert; /* * Use positive logic throughout - status is zero for no card, @@ -584,6 +605,15 @@ static int mmci_get_cd(struct mmc_host *mmc) return status; } +static irqreturn_t mmci_cd_irq(int irq, void *dev_id) +{ + struct mmci_host *host = dev_id; + + mmc_detect_change(host->mmc, msecs_to_jiffies(500)); + + return IRQ_HANDLED; +} + static const struct mmc_host_ops mmci_ops = { .request = mmci_request, .set_ios = mmci_set_ios, @@ -620,6 +650,7 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) host->gpio_wp = -ENOSYS; host->gpio_cd = -ENOSYS; + host->gpio_cd_irq = -1; host->hw_designer = amba_manf(dev); host->hw_revision = amba_rev(dev); @@ -699,7 +730,6 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) if (host->vcc == NULL) mmc->ocr_avail = plat->ocr_mask; mmc->caps = plat->capabilities; - mmc->caps |= MMC_CAP_NEEDS_POLL; /* * We can do SGIO @@ -744,6 +774,12 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) host->gpio_cd = plat->gpio_cd; else if (ret != -ENOSYS) goto err_gpio_cd; + + ret = request_any_context_irq(gpio_to_irq(plat->gpio_cd), + mmci_cd_irq, 0, + DRIVER_NAME " (cd)", host); + if (ret >= 0) + host->gpio_cd_irq = gpio_to_irq(plat->gpio_cd); } if (gpio_is_valid(plat->gpio_wp)) { ret = gpio_request(plat->gpio_wp, DRIVER_NAME " (wp)"); @@ -755,6 +791,10 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) goto err_gpio_wp; } + if ((host->plat->status || host->gpio_cd != -ENOSYS) + && host->gpio_cd_irq < 0) + mmc->caps |= MMC_CAP_NEEDS_POLL; + ret = request_irq(dev->irq[0], mmci_irq, IRQF_SHARED, DRIVER_NAME " (cmd)", host); if (ret) goto unmap; @@ -781,6 +821,8 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) if (host->gpio_wp != -ENOSYS) gpio_free(host->gpio_wp); err_gpio_wp: + if (host->gpio_cd_irq >= 0) + free_irq(host->gpio_cd_irq, host); if (host->gpio_cd != -ENOSYS) gpio_free(host->gpio_cd); err_gpio_cd: @@ -819,6 +861,8 @@ static int __devexit mmci_remove(struct amba_device *dev) if (host->gpio_wp != -ENOSYS) gpio_free(host->gpio_wp); + if (host->gpio_cd_irq >= 0) + free_irq(host->gpio_cd_irq, host); if (host->gpio_cd != -ENOSYS) gpio_free(host->gpio_cd); diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index 68970cfb81e1..4ae887fc0189 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h @@ -54,10 +54,16 @@ #define MCI_DPSM_MODE (1 << 2) #define MCI_DPSM_DMAENABLE (1 << 3) #define MCI_DPSM_BLOCKSIZE (1 << 4) -#define MCI_DPSM_RWSTART (1 << 8) -#define MCI_DPSM_RWSTOP (1 << 9) -#define MCI_DPSM_RWMOD (1 << 10) -#define MCI_DPSM_SDIOEN (1 << 11) +/* Control register extensions in the ST Micro U300 and Ux500 versions */ +#define MCI_ST_DPSM_RWSTART (1 << 8) +#define MCI_ST_DPSM_RWSTOP (1 << 9) +#define MCI_ST_DPSM_RWMOD (1 << 10) +#define MCI_ST_DPSM_SDIOEN (1 << 11) +/* Control register extensions in the ST Micro Ux500 versions */ +#define MCI_ST_DPSM_DMAREQCTL (1 << 12) +#define MCI_ST_DPSM_DBOOTMODEEN (1 << 13) +#define MCI_ST_DPSM_BUSYMODE (1 << 14) +#define MCI_ST_DPSM_DDRMODE (1 << 15) #define MMCIDATACNT 0x030 #define MMCISTATUS 0x034 @@ -133,13 +139,6 @@ MCI_DATATIMEOUTMASK|MCI_TXUNDERRUNMASK|MCI_RXOVERRUNMASK| \ MCI_CMDRESPENDMASK|MCI_CMDSENTMASK|MCI_DATABLOCKENDMASK) -/* - * The size of the FIFO in bytes. - */ -#define MCI_FIFOSIZE (16*4) - -#define MCI_FIFOHALFSIZE (MCI_FIFOSIZE / 2) - #define NR_SG 16 struct clk; @@ -154,6 +153,7 @@ struct mmci_host { struct clk *clk; int gpio_cd; int gpio_wp; + int gpio_cd_irq; unsigned int data_xfered; diff --git a/drivers/mmc/host/sdricoh_cs.c b/drivers/mmc/host/sdricoh_cs.c index 7aa65bb2af4a..f472c2714eb8 100644 --- a/drivers/mmc/host/sdricoh_cs.c +++ b/drivers/mmc/host/sdricoh_cs.c @@ -30,7 +30,6 @@ #include <linux/ioport.h> #include <linux/scatterlist.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/ds.h> #include <linux/io.h> @@ -536,9 +535,7 @@ static int sdricoh_pcmcia_resume(struct pcmcia_device *link) #endif static struct pcmcia_driver sdricoh_driver = { - .drv = { - .name = DRIVER_NAME, - }, + .name = DRIVER_NAME, .probe = sdricoh_pcmcia_probe, .remove = sdricoh_pcmcia_detach, .id_table = pcmcia_ids, diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c index e9ca5ba7d9d2..57a1acfe22c4 100644 --- a/drivers/mtd/maps/pcmciamtd.c +++ b/drivers/mtd/maps/pcmciamtd.c @@ -16,7 +16,6 @@ #include <asm/io.h> #include <asm/system.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/ds.h> @@ -101,7 +100,7 @@ MODULE_PARM_DESC(mem_type, "Set Memory type (0=Flash, 1=RAM, 2=ROM, default=0)") static caddr_t remap_window(struct map_info *map, unsigned long to) { struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1; - window_handle_t win = (window_handle_t)map->map_priv_2; + struct resource *win = (struct resource *) map->map_priv_2; unsigned int offset; int ret; @@ -316,30 +315,19 @@ static void pcmciamtd_set_vpp(struct map_info *map, int on) { struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1; struct pcmcia_device *link = dev->p_dev; - modconf_t mod; - int ret; - - mod.Attributes = CONF_VPP1_CHANGE_VALID | CONF_VPP2_CHANGE_VALID; - mod.Vcc = 0; - mod.Vpp1 = mod.Vpp2 = on ? dev->vpp : 0; DEBUG(2, "dev = %p on = %d vpp = %d\n", dev, on, dev->vpp); - ret = pcmcia_modify_configuration(link, &mod); + pcmcia_fixup_vpp(link, on ? dev->vpp : 0); } -/* After a card is removed, pcmciamtd_release() will unregister the - * device, and release the PCMCIA configuration. If the device is - * still open, this will be postponed until it is closed. - */ - static void pcmciamtd_release(struct pcmcia_device *link) { struct pcmciamtd_dev *dev = link->priv; DEBUG(3, "link = 0x%p", link); - if (link->win) { + if (link->resource[2]->end) { if(dev->win_base) { iounmap(dev->win_base); dev->win_base = NULL; @@ -482,18 +470,12 @@ static void card_settings(struct pcmciamtd_dev *dev, struct pcmcia_device *p_dev } -/* pcmciamtd_config() is scheduled to run after a CARD_INSERTION event - * is received, to configure the PCMCIA socket, and to make the - * MTD device available to the system. - */ - static int pcmciamtd_config(struct pcmcia_device *link) { struct pcmciamtd_dev *dev = link->priv; struct mtd_info *mtd = NULL; - win_req_t req; int ret; - int i; + int i, j = 0; static char *probes[] = { "jedec_probe", "cfi_probe" }; int new_name = 0; @@ -520,28 +502,34 @@ static int pcmciamtd_config(struct pcmcia_device *link) * smaller windows until we succeed */ - req.Attributes = WIN_MEMORY_TYPE_CM | WIN_ENABLE; - req.Attributes |= (dev->pcmcia_map.bankwidth == 1) ? WIN_DATA_WIDTH_8 : WIN_DATA_WIDTH_16; - req.Base = 0; - req.AccessSpeed = mem_speed; - link->win = (window_handle_t)link; - req.Size = (force_size) ? force_size << 20 : MAX_PCMCIA_ADDR; + link->resource[2]->flags |= WIN_MEMORY_TYPE_CM | WIN_ENABLE; + link->resource[2]->flags |= (dev->pcmcia_map.bankwidth == 1) ? + WIN_DATA_WIDTH_8 : WIN_DATA_WIDTH_16; + link->resource[2]->start = 0; + link->resource[2]->end = (force_size) ? force_size << 20 : + MAX_PCMCIA_ADDR; dev->win_size = 0; do { int ret; - DEBUG(2, "requesting window with size = %dKiB memspeed = %d", - req.Size >> 10, req.AccessSpeed); - ret = pcmcia_request_window(link, &req, &link->win); + DEBUG(2, "requesting window with size = %luKiB memspeed = %d", + (unsigned long) resource_size(link->resource[2]) >> 10, + mem_speed); + ret = pcmcia_request_window(link, link->resource[2], mem_speed); DEBUG(2, "ret = %d dev->win_size = %d", ret, dev->win_size); if(ret) { - req.Size >>= 1; + j++; + link->resource[2]->start = 0; + link->resource[2]->end = (force_size) ? + force_size << 20 : MAX_PCMCIA_ADDR; + link->resource[2]->end >>= j; } else { - DEBUG(2, "Got window of size %dKiB", req.Size >> 10); - dev->win_size = req.Size; + DEBUG(2, "Got window of size %luKiB", (unsigned long) + resource_size(link->resource[2]) >> 10); + dev->win_size = resource_size(link->resource[2]); break; } - } while(req.Size >= 0x1000); + } while (link->resource[2]->end >= 0x1000); DEBUG(2, "dev->win_size = %d", dev->win_size); @@ -553,33 +541,31 @@ static int pcmciamtd_config(struct pcmcia_device *link) DEBUG(1, "Allocated a window of %dKiB", dev->win_size >> 10); /* Get write protect status */ - DEBUG(2, "window handle = 0x%8.8lx", (unsigned long)link->win); - dev->win_base = ioremap(req.Base, req.Size); + dev->win_base = ioremap(link->resource[2]->start, + resource_size(link->resource[2])); if(!dev->win_base) { - dev_err(&dev->p_dev->dev, "ioremap(%lu, %u) failed\n", - req.Base, req.Size); + dev_err(&dev->p_dev->dev, "ioremap(%pR) failed\n", + link->resource[2]); pcmciamtd_release(link); return -ENODEV; } - DEBUG(1, "mapped window dev = %p req.base = 0x%lx base = %p size = 0x%x", - dev, req.Base, dev->win_base, req.Size); + DEBUG(1, "mapped window dev = %p @ %pR, base = %p", + dev, link->resource[2], dev->win_base); dev->offset = 0; dev->pcmcia_map.map_priv_1 = (unsigned long)dev; - dev->pcmcia_map.map_priv_2 = (unsigned long)link->win; + dev->pcmcia_map.map_priv_2 = (unsigned long)link->resource[2]; dev->vpp = (vpp) ? vpp : link->socket->socket.Vpp; - link->conf.Attributes = 0; if(setvpp == 2) { - link->conf.Vpp = dev->vpp; + link->vpp = dev->vpp; } else { - link->conf.Vpp = 0; + link->vpp = 0; } - link->conf.IntType = INT_MEMORY; - link->conf.ConfigIndex = 0; + link->config_index = 0; DEBUG(2, "Setting Configuration"); - ret = pcmcia_request_configuration(link, &link->conf); + ret = pcmcia_enable_device(link); if (ret != 0) { if (dev->win_base) { iounmap(dev->win_base); @@ -680,12 +666,6 @@ static int pcmciamtd_resume(struct pcmcia_device *dev) } -/* This deletes a driver "instance". The device is de-registered - * with Card Services. If it has been released, all local data - * structures are freed. Otherwise, the structures will be freed - * when the device is released. - */ - static void pcmciamtd_detach(struct pcmcia_device *link) { struct pcmciamtd_dev *dev = link->priv; @@ -703,11 +683,6 @@ static void pcmciamtd_detach(struct pcmcia_device *link) } -/* pcmciamtd_attach() creates an "instance" of the driver, allocating - * local data structures for one device. The device is registered - * with Card Services. - */ - static int pcmciamtd_probe(struct pcmcia_device *link) { struct pcmciamtd_dev *dev; @@ -720,9 +695,6 @@ static int pcmciamtd_probe(struct pcmcia_device *link) dev->p_dev = link; link->priv = dev; - link->conf.Attributes = 0; - link->conf.IntType = INT_MEMORY; - return pcmciamtd_config(link); } @@ -757,9 +729,7 @@ static struct pcmcia_device_id pcmciamtd_ids[] = { MODULE_DEVICE_TABLE(pcmcia, pcmciamtd_ids); static struct pcmcia_driver pcmciamtd_driver = { - .drv = { - .name = "pcmciamtd" - }, + .name = "pcmciamtd", .probe = pcmciamtd_probe, .remove = pcmciamtd_detach, .owner = THIS_MODULE, @@ -771,8 +741,6 @@ static struct pcmcia_driver pcmciamtd_driver = { static int __init init_pcmciamtd(void) { - info(DRIVER_DESC); - if(bankwidth && bankwidth != 1 && bankwidth != 2) { info("bad bankwidth (%d), using default", bankwidth); bankwidth = 2; diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index 62e68707b07f..50ab431b24eb 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c @@ -29,7 +29,6 @@ #include <linux/blkdev.h> #include <linux/blkpg.h> #include <linux/spinlock.h> -#include <linux/smp_lock.h> #include <linux/hdreg.h> #include <linux/init.h> #include <linux/mutex.h> @@ -38,6 +37,7 @@ #include "mtdcore.h" +static DEFINE_MUTEX(mtd_blkdevs_mutex); static LIST_HEAD(blktrans_majors); static DEFINE_MUTEX(blktrans_ref_mutex); @@ -181,7 +181,7 @@ static int blktrans_open(struct block_device *bdev, fmode_t mode) if (!dev) return -ERESTARTSYS; /* FIXME: busy loop! -arnd*/ - lock_kernel(); + mutex_lock(&mtd_blkdevs_mutex); mutex_lock(&dev->lock); if (!dev->mtd) { @@ -198,7 +198,7 @@ static int blktrans_open(struct block_device *bdev, fmode_t mode) unlock: mutex_unlock(&dev->lock); blktrans_dev_put(dev); - unlock_kernel(); + mutex_unlock(&mtd_blkdevs_mutex); return ret; } @@ -210,7 +210,7 @@ static int blktrans_release(struct gendisk *disk, fmode_t mode) if (!dev) return ret; - lock_kernel(); + mutex_lock(&mtd_blkdevs_mutex); mutex_lock(&dev->lock); /* Release one reference, we sure its not the last one here*/ @@ -223,7 +223,7 @@ static int blktrans_release(struct gendisk *disk, fmode_t mode) unlock: mutex_unlock(&dev->lock); blktrans_dev_put(dev); - unlock_kernel(); + mutex_unlock(&mtd_blkdevs_mutex); return ret; } @@ -256,7 +256,7 @@ static int blktrans_ioctl(struct block_device *bdev, fmode_t mode, if (!dev) return ret; - lock_kernel(); + mutex_lock(&mtd_blkdevs_mutex); mutex_lock(&dev->lock); if (!dev->mtd) @@ -271,7 +271,7 @@ static int blktrans_ioctl(struct block_device *bdev, fmode_t mode, } unlock: mutex_unlock(&dev->lock); - unlock_kernel(); + mutex_unlock(&mtd_blkdevs_mutex); blktrans_dev_put(dev); return ret; } diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index a825002123c8..5ef45487b65f 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -26,7 +26,7 @@ #include <linux/module.h> #include <linux/slab.h> #include <linux/sched.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/backing-dev.h> #include <linux/compat.h> #include <linux/mount.h> @@ -37,6 +37,7 @@ #include <asm/uaccess.h> #define MTD_INODE_FS_MAGIC 0x11307854 +static DEFINE_MUTEX(mtd_mutex); static struct vfsmount *mtd_inode_mnt __read_mostly; /* @@ -90,7 +91,7 @@ static int mtd_open(struct inode *inode, struct file *file) if ((file->f_mode & FMODE_WRITE) && (minor & 1)) return -EACCES; - lock_kernel(); + mutex_lock(&mtd_mutex); mtd = get_mtd_device(NULL, devnum); if (IS_ERR(mtd)) { @@ -138,7 +139,7 @@ static int mtd_open(struct inode *inode, struct file *file) file->private_data = mfi; out: - unlock_kernel(); + mutex_unlock(&mtd_mutex); return ret; } /* mtd_open */ @@ -866,9 +867,9 @@ static long mtd_unlocked_ioctl(struct file *file, u_int cmd, u_long arg) { int ret; - lock_kernel(); + mutex_lock(&mtd_mutex); ret = mtd_ioctl(file, cmd, arg); - unlock_kernel(); + mutex_unlock(&mtd_mutex); return ret; } @@ -892,7 +893,7 @@ static long mtd_compat_ioctl(struct file *file, unsigned int cmd, void __user *argp = compat_ptr(arg); int ret = 0; - lock_kernel(); + mutex_lock(&mtd_mutex); switch (cmd) { case MEMWRITEOOB32: @@ -927,7 +928,7 @@ static long mtd_compat_ioctl(struct file *file, unsigned int cmd, ret = mtd_ioctl(file, cmd, (unsigned long)argp); } - unlock_kernel(); + mutex_unlock(&mtd_mutex); return ret; } diff --git a/drivers/mtd/ubi/Kconfig b/drivers/mtd/ubi/Kconfig index f702a163d8df..3cf193fb5e00 100644 --- a/drivers/mtd/ubi/Kconfig +++ b/drivers/mtd/ubi/Kconfig @@ -1,9 +1,5 @@ -menu "UBI - Unsorted block images" - depends on MTD - -config MTD_UBI - tristate "Enable UBI" - depends on MTD +menuconfig MTD_UBI + tristate "Enable UBI - Unsorted block images" select CRC32 help UBI is a software layer above MTD layer which admits of LVM-like @@ -12,11 +8,12 @@ config MTD_UBI capabilities. Please, consult the MTD web site for more details (www.linux-mtd.infradead.org). +if MTD_UBI + config MTD_UBI_WL_THRESHOLD int "UBI wear-leveling threshold" default 4096 range 2 65536 - depends on MTD_UBI help This parameter defines the maximum difference between the highest erase counter value and the lowest erase counter value of eraseblocks @@ -34,7 +31,6 @@ config MTD_UBI_BEB_RESERVE int "Percentage of reserved eraseblocks for bad eraseblocks handling" default 1 range 0 25 - depends on MTD_UBI help If the MTD device admits of bad eraseblocks (e.g. NAND flash), UBI reserves some amount of physical eraseblocks to handle new bad @@ -48,8 +44,6 @@ config MTD_UBI_BEB_RESERVE config MTD_UBI_GLUEBI tristate "MTD devices emulation driver (gluebi)" - default n - depends on MTD_UBI help This option enables gluebi - an additional driver which emulates MTD devices on top of UBI volumes: for each UBI volumes an MTD device is @@ -59,4 +53,5 @@ config MTD_UBI_GLUEBI software. source "drivers/mtd/ubi/Kconfig.debug" -endmenu + +endif # MTD_UBI diff --git a/drivers/mtd/ubi/Kconfig.debug b/drivers/mtd/ubi/Kconfig.debug index 61f6e5e40458..fad4adc0fe2c 100644 --- a/drivers/mtd/ubi/Kconfig.debug +++ b/drivers/mtd/ubi/Kconfig.debug @@ -1,94 +1,73 @@ comment "UBI debugging options" - depends on MTD_UBI config MTD_UBI_DEBUG bool "UBI debugging" depends on SYSFS - depends on MTD_UBI select DEBUG_FS select KALLSYMS_ALL if KALLSYMS && DEBUG_KERNEL help This option enables UBI debugging. +if MTD_UBI_DEBUG + config MTD_UBI_DEBUG_MSG bool "UBI debugging messages" - depends on MTD_UBI_DEBUG - default n help This option enables UBI debugging messages. config MTD_UBI_DEBUG_PARANOID bool "Extra self-checks" - default n - depends on MTD_UBI_DEBUG help This option enables extra checks in UBI code. Note this slows UBI down significantly. config MTD_UBI_DEBUG_DISABLE_BGT bool "Do not enable the UBI background thread" - depends on MTD_UBI_DEBUG - default n help This option switches the background thread off by default. The thread may be also be enabled/disabled via UBI sysfs. config MTD_UBI_DEBUG_EMULATE_BITFLIPS bool "Emulate flash bit-flips" - depends on MTD_UBI_DEBUG - default n help This option emulates bit-flips with probability 1/50, which in turn causes scrubbing. Useful for debugging and stressing UBI. config MTD_UBI_DEBUG_EMULATE_WRITE_FAILURES bool "Emulate flash write failures" - depends on MTD_UBI_DEBUG - default n help This option emulates write failures with probability 1/100. Useful for debugging and testing how UBI handlines errors. config MTD_UBI_DEBUG_EMULATE_ERASE_FAILURES bool "Emulate flash erase failures" - depends on MTD_UBI_DEBUG - default n help This option emulates erase failures with probability 1/100. Useful for debugging and testing how UBI handlines errors. -menu "Additional UBI debugging messages" - depends on MTD_UBI_DEBUG +comment "Additional UBI debugging messages" config MTD_UBI_DEBUG_MSG_BLD bool "Additional UBI initialization and build messages" - default n - depends on MTD_UBI_DEBUG help This option enables detailed UBI initialization and device build debugging messages. config MTD_UBI_DEBUG_MSG_EBA bool "Eraseblock association unit messages" - default n - depends on MTD_UBI_DEBUG help This option enables debugging messages from the UBI eraseblock association unit. config MTD_UBI_DEBUG_MSG_WL bool "Wear-leveling unit messages" - default n - depends on MTD_UBI_DEBUG help This option enables debugging messages from the UBI wear-leveling unit. config MTD_UBI_DEBUG_MSG_IO bool "Input/output unit messages" - default n - depends on MTD_UBI_DEBUG help This option enables debugging messages from the UBI input/output unit. -endmenu # UBI debugging messages +endif # MTD_UBI_DEBUG diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 78ae89488a4f..5ebe280225d6 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -95,8 +95,8 @@ DEFINE_MUTEX(ubi_devices_mutex); static DEFINE_SPINLOCK(ubi_devices_lock); /* "Show" method for files in '/<sysfs>/class/ubi/' */ -static ssize_t ubi_version_show(struct class *class, struct class_attribute *attr, - char *buf) +static ssize_t ubi_version_show(struct class *class, + struct class_attribute *attr, char *buf) { return sprintf(buf, "%d\n", UBI_VERSION); } @@ -591,6 +591,7 @@ static int attach_by_scanning(struct ubi_device *ubi) ubi->bad_peb_count = si->bad_peb_count; ubi->good_peb_count = ubi->peb_count - ubi->bad_peb_count; + ubi->corr_peb_count = si->corr_peb_count; ubi->max_ec = si->max_ec; ubi->mean_ec = si->mean_ec; ubi_msg("max. sequence number: %llu", si->max_sqnum); @@ -972,6 +973,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset) ubi_msg("MTD device size: %llu MiB", ubi->flash_size >> 20); ubi_msg("number of good PEBs: %d", ubi->good_peb_count); ubi_msg("number of bad PEBs: %d", ubi->bad_peb_count); + ubi_msg("number of corrupted PEBs: %d", ubi->corr_peb_count); ubi_msg("max. allowed volumes: %d", ubi->vtbl_slots); ubi_msg("wear-leveling threshold: %d", CONFIG_MTD_UBI_WL_THRESHOLD); ubi_msg("number of internal volumes: %d", UBI_INT_VOL_COUNT); diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c index 3d2d1a69e9a0..af9fb0ff8210 100644 --- a/drivers/mtd/ubi/cdev.c +++ b/drivers/mtd/ubi/cdev.c @@ -1100,4 +1100,5 @@ const struct file_operations ubi_ctrl_cdev_operations = { .owner = THIS_MODULE, .unlocked_ioctl = ctrl_cdev_ioctl, .compat_ioctl = ctrl_cdev_compat_ioctl, + .llseek = noop_llseek, }; diff --git a/drivers/mtd/ubi/debug.h b/drivers/mtd/ubi/debug.h index 17a107129726..9eca95074bc2 100644 --- a/drivers/mtd/ubi/debug.h +++ b/drivers/mtd/ubi/debug.h @@ -57,6 +57,9 @@ void ubi_dbg_dump_seb(const struct ubi_scan_leb *seb, int type); void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req); void ubi_dbg_dump_flash(struct ubi_device *ubi, int pnum, int offset, int len); +#define ubi_dbg_print_hex_dump(l, ps, pt, r, g, b, len, a) \ + print_hex_dump(l, ps, pt, r, g, b, len, a) + #ifdef CONFIG_MTD_UBI_DEBUG_MSG /* General debugging messages */ #define dbg_gen(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__) @@ -172,6 +175,7 @@ static inline int ubi_dbg_is_erase_failure(void) #define ubi_dbg_dump_seb(seb, type) ({}) #define ubi_dbg_dump_mkvol_req(req) ({}) #define ubi_dbg_dump_flash(ubi, pnum, offset, len) ({}) +#define ubi_dbg_print_hex_dump(l, ps, pt, r, g, b, len, a) ({}) #define UBI_IO_DEBUG 0 #define DBG_DISABLE_BGT 0 diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index fe74749e0dae..4be671815014 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c @@ -418,7 +418,7 @@ retry: * may try to recover data. FIXME: but this is * not implemented. */ - if (err == UBI_IO_BAD_HDR_READ || + if (err == UBI_IO_BAD_HDR_EBADMSG || err == UBI_IO_BAD_HDR) { ubi_warn("corrupted VID header at PEB " "%d, LEB %d:%d", pnum, vol_id, @@ -963,7 +963,7 @@ write_error: static int is_error_sane(int err) { if (err == -EIO || err == -ENOMEM || err == UBI_IO_BAD_HDR || - err == UBI_IO_BAD_HDR_READ || err == -ETIMEDOUT) + err == UBI_IO_BAD_HDR_EBADMSG || err == -ETIMEDOUT) return 0; return 1; } @@ -1201,6 +1201,9 @@ static void print_rsvd_warning(struct ubi_device *ubi, ubi_warn("cannot reserve enough PEBs for bad PEB handling, reserved %d," " need %d", ubi->beb_rsvd_pebs, ubi->beb_rsvd_level); + if (ubi->corr_peb_count) + ubi_warn("%d PEBs are corrupted and not used", + ubi->corr_peb_count); } /** @@ -1263,6 +1266,9 @@ int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si) if (ubi->avail_pebs < EBA_RESERVED_PEBS) { ubi_err("no enough physical eraseblocks (%d, need %d)", ubi->avail_pebs, EBA_RESERVED_PEBS); + if (ubi->corr_peb_count) + ubi_err("%d PEBs are corrupted and not used", + ubi->corr_peb_count); err = -ENOSPC; goto out_free; } diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c index 332f992f13d9..c2960ac9f39c 100644 --- a/drivers/mtd/ubi/io.c +++ b/drivers/mtd/ubi/io.c @@ -376,25 +376,6 @@ retry: return 0; } -/** - * check_pattern - check if buffer contains only a certain byte pattern. - * @buf: buffer to check - * @patt: the pattern to check - * @size: buffer size in bytes - * - * This function returns %1 in there are only @patt bytes in @buf, and %0 if - * something else was also found. - */ -static int check_pattern(const void *buf, uint8_t patt, int size) -{ - int i; - - for (i = 0; i < size; i++) - if (((const uint8_t *)buf)[i] != patt) - return 0; - return 1; -} - /* Patterns to write to a physical eraseblock when torturing it */ static uint8_t patterns[] = {0xa5, 0x5a, 0x0}; @@ -426,7 +407,7 @@ static int torture_peb(struct ubi_device *ubi, int pnum) if (err) goto out; - err = check_pattern(ubi->peb_buf1, 0xFF, ubi->peb_size); + err = ubi_check_pattern(ubi->peb_buf1, 0xFF, ubi->peb_size); if (err == 0) { ubi_err("erased PEB %d, but a non-0xFF byte found", pnum); @@ -445,7 +426,8 @@ static int torture_peb(struct ubi_device *ubi, int pnum) if (err) goto out; - err = check_pattern(ubi->peb_buf1, patterns[i], ubi->peb_size); + err = ubi_check_pattern(ubi->peb_buf1, patterns[i], + ubi->peb_size); if (err == 0) { ubi_err("pattern %x checking failed for PEB %d", patterns[i], pnum); @@ -517,7 +499,7 @@ static int nor_erase_prepare(struct ubi_device *ubi, int pnum) * In this case we probably anyway have garbage in this PEB. */ err1 = ubi_io_read_vid_hdr(ubi, pnum, &vid_hdr, 0); - if (err1 == UBI_IO_BAD_HDR_READ || err1 == UBI_IO_BAD_HDR) + if (err1 == UBI_IO_BAD_HDR_EBADMSG || err1 == UBI_IO_BAD_HDR) /* * The VID header is corrupted, so we can safely erase this * PEB and not afraid that it will be treated as a valid PEB in @@ -712,47 +694,47 @@ bad: * and corrected by the flash driver; this is harmless but may indicate that * this eraseblock may become bad soon (but may be not); * o %UBI_IO_BAD_HDR if the erase counter header is corrupted (a CRC error); - * o %UBI_IO_PEB_EMPTY if the physical eraseblock is empty; + * o %UBI_IO_BAD_HDR_EBADMSG is the same as %UBI_IO_BAD_HDR, but there also was + * a data integrity error (uncorrectable ECC error in case of NAND); + * o %UBI_IO_FF if only 0xFF bytes were read (the PEB is supposedly empty) * o a negative error code in case of failure. */ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum, struct ubi_ec_hdr *ec_hdr, int verbose) { - int err, read_err = 0; + int err, read_err; uint32_t crc, magic, hdr_crc; dbg_io("read EC header from PEB %d", pnum); ubi_assert(pnum >= 0 && pnum < ubi->peb_count); - err = ubi_io_read(ubi, ec_hdr, pnum, 0, UBI_EC_HDR_SIZE); - if (err) { - if (err != UBI_IO_BITFLIPS && err != -EBADMSG) - return err; + read_err = ubi_io_read(ubi, ec_hdr, pnum, 0, UBI_EC_HDR_SIZE); + if (read_err) { + if (read_err != UBI_IO_BITFLIPS && read_err != -EBADMSG) + return read_err; /* * We read all the data, but either a correctable bit-flip - * occurred, or MTD reported about some data integrity error, - * like an ECC error in case of NAND. The former is harmless, - * the later may mean that the read data is corrupted. But we - * have a CRC check-sum and we will detect this. If the EC - * header is still OK, we just report this as there was a - * bit-flip. + * occurred, or MTD reported a data integrity error + * (uncorrectable ECC error in case of NAND). The former is + * harmless, the later may mean that the read data is + * corrupted. But we have a CRC check-sum and we will detect + * this. If the EC header is still OK, we just report this as + * there was a bit-flip, to force scrubbing. */ - if (err == -EBADMSG) - read_err = UBI_IO_BAD_HDR_READ; } magic = be32_to_cpu(ec_hdr->magic); if (magic != UBI_EC_HDR_MAGIC) { - if (read_err) - return read_err; + if (read_err == -EBADMSG) + return UBI_IO_BAD_HDR_EBADMSG; /* * The magic field is wrong. Let's check if we have read all * 0xFF. If yes, this physical eraseblock is assumed to be * empty. */ - if (check_pattern(ec_hdr, 0xFF, UBI_EC_HDR_SIZE)) { + if (ubi_check_pattern(ec_hdr, 0xFF, UBI_EC_HDR_SIZE)) { /* The physical eraseblock is supposedly empty */ if (verbose) ubi_warn("no EC header found at PEB %d, " @@ -760,7 +742,10 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum, else if (UBI_IO_DEBUG) dbg_msg("no EC header found at PEB %d, " "only 0xFF bytes", pnum); - return UBI_IO_PEB_EMPTY; + if (!read_err) + return UBI_IO_FF; + else + return UBI_IO_FF_BITFLIPS; } /* @@ -788,7 +773,11 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum, } else if (UBI_IO_DEBUG) dbg_msg("bad EC header CRC at PEB %d, calculated " "%#08x, read %#08x", pnum, crc, hdr_crc); - return read_err ?: UBI_IO_BAD_HDR; + + if (!read_err) + return UBI_IO_BAD_HDR; + else + return UBI_IO_BAD_HDR_EBADMSG; } /* And of course validate what has just been read from the media */ @@ -975,22 +964,16 @@ bad: * * This function reads the volume identifier header from physical eraseblock * @pnum and stores it in @vid_hdr. It also checks CRC checksum of the read - * volume identifier header. The following codes may be returned: + * volume identifier header. The error codes are the same as in + * 'ubi_io_read_ec_hdr()'. * - * o %0 if the CRC checksum is correct and the header was successfully read; - * o %UBI_IO_BITFLIPS if the CRC is correct, but bit-flips were detected - * and corrected by the flash driver; this is harmless but may indicate that - * this eraseblock may become bad soon; - * o %UBI_IO_BAD_HDR if the volume identifier header is corrupted (a CRC - * error detected); - * o %UBI_IO_PEB_FREE if the physical eraseblock is free (i.e., there is no VID - * header there); - * o a negative error code in case of failure. + * Note, the implementation of this function is also very similar to + * 'ubi_io_read_ec_hdr()', so refer commentaries in 'ubi_io_read_ec_hdr()'. */ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum, struct ubi_vid_hdr *vid_hdr, int verbose) { - int err, read_err = 0; + int err, read_err; uint32_t crc, magic, hdr_crc; void *p; @@ -998,48 +981,29 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum, ubi_assert(pnum >= 0 && pnum < ubi->peb_count); p = (char *)vid_hdr - ubi->vid_hdr_shift; - err = ubi_io_read(ubi, p, pnum, ubi->vid_hdr_aloffset, + read_err = ubi_io_read(ubi, p, pnum, ubi->vid_hdr_aloffset, ubi->vid_hdr_alsize); - if (err) { - if (err != UBI_IO_BITFLIPS && err != -EBADMSG) - return err; - - /* - * We read all the data, but either a correctable bit-flip - * occurred, or MTD reported about some data integrity error, - * like an ECC error in case of NAND. The former is harmless, - * the later may mean the read data is corrupted. But we have a - * CRC check-sum and we will identify this. If the VID header is - * still OK, we just report this as there was a bit-flip. - */ - if (err == -EBADMSG) - read_err = UBI_IO_BAD_HDR_READ; - } + if (read_err && read_err != UBI_IO_BITFLIPS && read_err != -EBADMSG) + return read_err; magic = be32_to_cpu(vid_hdr->magic); if (magic != UBI_VID_HDR_MAGIC) { - if (read_err) - return read_err; + if (read_err == -EBADMSG) + return UBI_IO_BAD_HDR_EBADMSG; - /* - * If we have read all 0xFF bytes, the VID header probably does - * not exist and the physical eraseblock is assumed to be free. - */ - if (check_pattern(vid_hdr, 0xFF, UBI_VID_HDR_SIZE)) { - /* The physical eraseblock is supposedly free */ + if (ubi_check_pattern(vid_hdr, 0xFF, UBI_VID_HDR_SIZE)) { if (verbose) ubi_warn("no VID header found at PEB %d, " "only 0xFF bytes", pnum); else if (UBI_IO_DEBUG) dbg_msg("no VID header found at PEB %d, " "only 0xFF bytes", pnum); - return UBI_IO_PEB_FREE; + if (!read_err) + return UBI_IO_FF; + else + return UBI_IO_FF_BITFLIPS; } - /* - * This is not a valid VID header, and these are not 0xFF - * bytes. Report that the header is corrupted. - */ if (verbose) { ubi_warn("bad magic number at PEB %d: %08x instead of " "%08x", pnum, magic, UBI_VID_HDR_MAGIC); @@ -1061,20 +1025,18 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum, } else if (UBI_IO_DEBUG) dbg_msg("bad CRC at PEB %d, calculated %#08x, " "read %#08x", pnum, crc, hdr_crc); - return read_err ?: UBI_IO_BAD_HDR; + if (!read_err) + return UBI_IO_BAD_HDR; + else + return UBI_IO_BAD_HDR_EBADMSG; } - /* Validate the VID header that we have just read */ err = validate_vid_hdr(ubi, vid_hdr); if (err) { ubi_err("validation failed for PEB %d", pnum); return -EINVAL; } - /* - * If there was a read error (%-EBADMSG), but the header CRC is still - * OK, report about a bit-flip to force scrubbing on this PEB. - */ return read_err ? UBI_IO_BITFLIPS : 0; } @@ -1383,7 +1345,7 @@ int ubi_dbg_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len) goto error; } - err = check_pattern(ubi->dbg_peb_buf, 0xFF, len); + err = ubi_check_pattern(ubi->dbg_peb_buf, 0xFF, len); if (err == 0) { ubi_err("flash region at PEB %d:%d, length %d does not " "contain all 0xFF bytes", pnum, offset, len); diff --git a/drivers/mtd/ubi/misc.c b/drivers/mtd/ubi/misc.c index 22ad31402945..ff2a65c37f69 100644 --- a/drivers/mtd/ubi/misc.c +++ b/drivers/mtd/ubi/misc.c @@ -103,3 +103,22 @@ void ubi_calculate_reserved(struct ubi_device *ubi) if (ubi->beb_rsvd_level < MIN_RESEVED_PEBS) ubi->beb_rsvd_level = MIN_RESEVED_PEBS; } + +/** + * ubi_check_pattern - check if buffer contains only a certain byte pattern. + * @buf: buffer to check + * @patt: the pattern to check + * @size: buffer size in bytes + * + * This function returns %1 in there are only @patt bytes in @buf, and %0 if + * something else was also found. + */ +int ubi_check_pattern(const void *buf, uint8_t patt, int size) +{ + int i; + + for (i = 0; i < size; i++) + if (((const uint8_t *)buf)[i] != patt) + return 0; + return 1; +} diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c index 69b52e9c9489..3c631863bf40 100644 --- a/drivers/mtd/ubi/scan.c +++ b/drivers/mtd/ubi/scan.c @@ -29,7 +29,7 @@ * objects which are kept in volume RB-tree with root at the @volumes field. * The RB-tree is indexed by the volume ID. * - * Found logical eraseblocks are represented by &struct ubi_scan_leb objects. + * Scanned logical eraseblocks are represented by &struct ubi_scan_leb objects. * These objects are kept in per-volume RB-trees with the root at the * corresponding &struct ubi_scan_volume object. To put it differently, we keep * an RB-tree of per-volume objects and each of these objects is the root of @@ -38,6 +38,33 @@ * Corrupted physical eraseblocks are put to the @corr list, free physical * eraseblocks are put to the @free list and the physical eraseblock to be * erased are put to the @erase list. + * + * UBI tries to distinguish between 2 types of corruptions. + * 1. Corruptions caused by power cuts. These are harmless and expected + * corruptions and UBI tries to handle them gracefully, without printing too + * many warnings and error messages. The idea is that we do not lose + * important data in these case - we may lose only the data which was being + * written to the media just before the power cut happened, and the upper + * layers (e.g., UBIFS) are supposed to handle these situations. UBI puts + * these PEBs to the head of the @erase list and they are scheduled for + * erasure. + * + * 2. Unexpected corruptions which are not caused by power cuts. During + * scanning, such PEBs are put to the @corr list and UBI preserves them. + * Obviously, this lessens the amount of available PEBs, and if at some + * point UBI runs out of free PEBs, it switches to R/O mode. UBI also loudly + * informs about such PEBs every time the MTD device is attached. + * + * However, it is difficult to reliably distinguish between these types of + * corruptions and UBI's strategy is as follows. UBI assumes (2.) if the VID + * header is corrupted and the data area does not contain all 0xFFs, and there + * were not bit-flips or integrity errors while reading the data area. Otherwise + * UBI assumes (1.). The assumptions are: + * o if the data area contains only 0xFFs, there is no data, and it is safe + * to just erase this PEB. + * o if the data area has bit-flips and data integrity errors (ECC errors on + * NAND), it is probably a PEB which was being erased when power cut + * happened. */ #include <linux/err.h> @@ -62,26 +89,26 @@ static struct ubi_vid_hdr *vidh; * @si: scanning information * @pnum: physical eraseblock number to add * @ec: erase counter of the physical eraseblock + * @to_head: if not zero, add to the head of the list * @list: the list to add to * - * This function adds physical eraseblock @pnum to free, erase, corrupted or - * alien lists. Returns zero in case of success and a negative error code in - * case of failure. + * This function adds physical eraseblock @pnum to free, erase, or alien lists. + * If @to_head is not zero, PEB will be added to the head of the list, which + * basically means it will be processed first later. E.g., we add corrupted + * PEBs (corrupted due to power cuts) to the head of the erase list to make + * sure we erase them first and get rid of corruptions ASAP. This function + * returns zero in case of success and a negative error code in case of + * failure. */ -static int add_to_list(struct ubi_scan_info *si, int pnum, int ec, +static int add_to_list(struct ubi_scan_info *si, int pnum, int ec, int to_head, struct list_head *list) { struct ubi_scan_leb *seb; if (list == &si->free) { dbg_bld("add to free: PEB %d, EC %d", pnum, ec); - si->free_peb_count += 1; } else if (list == &si->erase) { dbg_bld("add to erase: PEB %d, EC %d", pnum, ec); - si->erase_peb_count += 1; - } else if (list == &si->corr) { - dbg_bld("add to corrupted: PEB %d, EC %d", pnum, ec); - si->corr_peb_count += 1; } else if (list == &si->alien) { dbg_bld("add to alien: PEB %d, EC %d", pnum, ec); si->alien_peb_count += 1; @@ -94,7 +121,37 @@ static int add_to_list(struct ubi_scan_info *si, int pnum, int ec, seb->pnum = pnum; seb->ec = ec; - list_add_tail(&seb->u.list, list); + if (to_head) + list_add(&seb->u.list, list); + else + list_add_tail(&seb->u.list, list); + return 0; +} + +/** + * add_corrupted - add a corrupted physical eraseblock. + * @si: scanning information + * @pnum: physical eraseblock number to add + * @ec: erase counter of the physical eraseblock + * + * This function adds corrupted physical eraseblock @pnum to the 'corr' list. + * The corruption was presumably not caused by a power cut. Returns zero in + * case of success and a negative error code in case of failure. + */ +static int add_corrupted(struct ubi_scan_info *si, int pnum, int ec) +{ + struct ubi_scan_leb *seb; + + dbg_bld("add to corrupted: PEB %d, EC %d", pnum, ec); + + seb = kmalloc(sizeof(struct ubi_scan_leb), GFP_KERNEL); + if (!seb) + return -ENOMEM; + + si->corr_peb_count += 1; + seb->pnum = pnum; + seb->ec = ec; + list_add(&seb->u.list, &si->corr); return 0; } @@ -258,8 +315,8 @@ static int compare_lebs(struct ubi_device *ubi, const struct ubi_scan_leb *seb, * created before sequence numbers support has been added. At * that times we used 32-bit LEB versions stored in logical * eraseblocks. That was before UBI got into mainline. We do not - * support these images anymore. Well, those images will work - * still work, but only if no unclean reboots happened. + * support these images anymore. Well, those images still work, + * but only if no unclean reboots happened. */ ubi_err("unsupported on-flash UBI format\n"); return -EINVAL; @@ -285,19 +342,25 @@ static int compare_lebs(struct ubi_device *ubi, const struct ubi_scan_leb *seb, return 1; } } else { - pnum = seb->pnum; + if (!seb->copy_flag) { + /* It is not a copy, so it is newer */ + dbg_bld("first PEB %d is newer, copy_flag is unset", + pnum); + return bitflips << 1; + } vh = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL); if (!vh) return -ENOMEM; + pnum = seb->pnum; err = ubi_io_read_vid_hdr(ubi, pnum, vh, 0); if (err) { if (err == UBI_IO_BITFLIPS) bitflips = 1; else { dbg_err("VID of PEB %d header is bad, but it " - "was OK earlier", pnum); + "was OK earlier, err %d", pnum, err); if (err > 0) err = -EIO; @@ -305,14 +368,6 @@ static int compare_lebs(struct ubi_device *ubi, const struct ubi_scan_leb *seb, } } - if (!vh->copy_flag) { - /* It is not a copy, so it is newer */ - dbg_bld("first PEB %d is newer, copy_flag is unset", - pnum); - err = bitflips << 1; - goto out_free_vidh; - } - vid_hdr = vh; } @@ -463,18 +518,15 @@ int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si, if (err) return err; - if (cmp_res & 4) - err = add_to_list(si, seb->pnum, seb->ec, - &si->corr); - else - err = add_to_list(si, seb->pnum, seb->ec, - &si->erase); + err = add_to_list(si, seb->pnum, seb->ec, cmp_res & 4, + &si->erase); if (err) return err; seb->ec = ec; seb->pnum = pnum; seb->scrub = ((cmp_res & 2) || bitflips); + seb->copy_flag = vid_hdr->copy_flag; seb->sqnum = sqnum; if (sv->highest_lnum == lnum) @@ -487,10 +539,8 @@ int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si, * This logical eraseblock is older than the one found * previously. */ - if (cmp_res & 4) - return add_to_list(si, pnum, ec, &si->corr); - else - return add_to_list(si, pnum, ec, &si->erase); + return add_to_list(si, pnum, ec, cmp_res & 4, + &si->erase); } } @@ -510,8 +560,9 @@ int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si, seb->ec = ec; seb->pnum = pnum; seb->lnum = lnum; - seb->sqnum = sqnum; seb->scrub = bitflips; + seb->copy_flag = vid_hdr->copy_flag; + seb->sqnum = sqnum; if (sv->highest_lnum <= lnum) { sv->highest_lnum = lnum; @@ -521,7 +572,6 @@ int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si, sv->leb_count += 1; rb_link_node(&seb->u.rb, parent, p); rb_insert_color(&seb->u.rb, &sv->root); - si->used_peb_count += 1; return 0; } @@ -668,8 +718,8 @@ out_free: struct ubi_scan_leb *ubi_scan_get_free_peb(struct ubi_device *ubi, struct ubi_scan_info *si) { - int err = 0, i; - struct ubi_scan_leb *seb; + int err = 0; + struct ubi_scan_leb *seb, *tmp_seb; if (!list_empty(&si->free)) { seb = list_entry(si->free.next, struct ubi_scan_leb, u.list); @@ -678,38 +728,86 @@ struct ubi_scan_leb *ubi_scan_get_free_peb(struct ubi_device *ubi, return seb; } - for (i = 0; i < 2; i++) { - struct list_head *head; - struct ubi_scan_leb *tmp_seb; + /* + * We try to erase the first physical eraseblock from the erase list + * and pick it if we succeed, or try to erase the next one if not. And + * so forth. We don't want to take care about bad eraseblocks here - + * they'll be handled later. + */ + list_for_each_entry_safe(seb, tmp_seb, &si->erase, u.list) { + if (seb->ec == UBI_SCAN_UNKNOWN_EC) + seb->ec = si->mean_ec; - if (i == 0) - head = &si->erase; - else - head = &si->corr; + err = ubi_scan_erase_peb(ubi, si, seb->pnum, seb->ec+1); + if (err) + continue; + seb->ec += 1; + list_del(&seb->u.list); + dbg_bld("return PEB %d, EC %d", seb->pnum, seb->ec); + return seb; + } + + ubi_err("no free eraseblocks"); + return ERR_PTR(-ENOSPC); +} + +/** + * check_corruption - check the data area of PEB. + * @ubi: UBI device description object + * @vid_hrd: the (corrupted) VID header of this PEB + * @pnum: the physical eraseblock number to check + * + * This is a helper function which is used to distinguish between VID header + * corruptions caused by power cuts and other reasons. If the PEB contains only + * 0xFF bytes in the data area, the VID header is most probably corrupted + * because of a power cut (%0 is returned in this case). Otherwise, it was + * probably corrupted for some other reasons (%1 is returned in this case). A + * negative error code is returned if a read error occurred. + * + * If the corruption reason was a power cut, UBI can safely erase this PEB. + * Otherwise, it should preserve it to avoid possibly destroying important + * information. + */ +static int check_corruption(struct ubi_device *ubi, struct ubi_vid_hdr *vid_hdr, + int pnum) +{ + int err; + + mutex_lock(&ubi->buf_mutex); + memset(ubi->peb_buf1, 0x00, ubi->leb_size); + + err = ubi_io_read(ubi, ubi->peb_buf1, pnum, ubi->leb_start, + ubi->leb_size); + if (err == UBI_IO_BITFLIPS || err == -EBADMSG) { /* - * We try to erase the first physical eraseblock from the @head - * list and pick it if we succeed, or try to erase the - * next one if not. And so forth. We don't want to take care - * about bad eraseblocks here - they'll be handled later. + * Bit-flips or integrity errors while reading the data area. + * It is difficult to say for sure what type of corruption is + * this, but presumably a power cut happened while this PEB was + * erased, so it became unstable and corrupted, and should be + * erased. */ - list_for_each_entry_safe(seb, tmp_seb, head, u.list) { - if (seb->ec == UBI_SCAN_UNKNOWN_EC) - seb->ec = si->mean_ec; + return 0; + } - err = ubi_scan_erase_peb(ubi, si, seb->pnum, seb->ec+1); - if (err) - continue; + if (err) + return err; - seb->ec += 1; - list_del(&seb->u.list); - dbg_bld("return PEB %d, EC %d", seb->pnum, seb->ec); - return seb; - } + if (ubi_check_pattern(ubi->peb_buf1, 0xFF, ubi->leb_size)) { + mutex_unlock(&ubi->buf_mutex); + return 0; } - ubi_err("no eraseblocks found"); - return ERR_PTR(-ENOSPC); + ubi_err("PEB %d contains corrupted VID header, and the data does not " + "contain all 0xFF, this may be a non-UBI PEB or a severe VID " + "header corruption which requires manual inspection", pnum); + ubi_dbg_dump_vid_hdr(vid_hdr); + dbg_msg("hexdump of PEB %d offset %d, length %d", + pnum, ubi->leb_start, ubi->leb_size); + ubi_dbg_print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, + ubi->peb_buf1, ubi->leb_size, 1); + mutex_unlock(&ubi->buf_mutex); + return 1; } /** @@ -725,7 +823,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum) { long long uninitialized_var(ec); - int err, bitflips = 0, vol_id, ec_corr = 0; + int err, bitflips = 0, vol_id, ec_err = 0; dbg_bld("scan PEB %d", pnum); @@ -746,22 +844,37 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, err = ubi_io_read_ec_hdr(ubi, pnum, ech, 0); if (err < 0) return err; - else if (err == UBI_IO_BITFLIPS) + switch (err) { + case 0: + break; + case UBI_IO_BITFLIPS: bitflips = 1; - else if (err == UBI_IO_PEB_EMPTY) - return add_to_list(si, pnum, UBI_SCAN_UNKNOWN_EC, &si->erase); - else if (err == UBI_IO_BAD_HDR_READ || err == UBI_IO_BAD_HDR) { + break; + case UBI_IO_FF: + si->empty_peb_count += 1; + return add_to_list(si, pnum, UBI_SCAN_UNKNOWN_EC, 0, + &si->erase); + case UBI_IO_FF_BITFLIPS: + si->empty_peb_count += 1; + return add_to_list(si, pnum, UBI_SCAN_UNKNOWN_EC, 1, + &si->erase); + case UBI_IO_BAD_HDR_EBADMSG: + case UBI_IO_BAD_HDR: /* * We have to also look at the VID header, possibly it is not * corrupted. Set %bitflips flag in order to make this PEB be * moved and EC be re-created. */ - ec_corr = err; + ec_err = err; ec = UBI_SCAN_UNKNOWN_EC; bitflips = 1; + break; + default: + ubi_err("'ubi_io_read_ec_hdr()' returned unknown code %d", err); + return -EINVAL; } - if (!ec_corr) { + if (!ec_err) { int image_seq; /* Make sure UBI version is OK */ @@ -814,24 +927,67 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, err = ubi_io_read_vid_hdr(ubi, pnum, vidh, 0); if (err < 0) return err; - else if (err == UBI_IO_BITFLIPS) + switch (err) { + case 0: + break; + case UBI_IO_BITFLIPS: bitflips = 1; - else if (err == UBI_IO_BAD_HDR_READ || err == UBI_IO_BAD_HDR || - (err == UBI_IO_PEB_FREE && ec_corr)) { - /* VID header is corrupted */ - if (err == UBI_IO_BAD_HDR_READ || - ec_corr == UBI_IO_BAD_HDR_READ) - si->read_err_count += 1; - err = add_to_list(si, pnum, ec, &si->corr); + break; + case UBI_IO_BAD_HDR_EBADMSG: + if (ec_err == UBI_IO_BAD_HDR_EBADMSG) + /* + * Both EC and VID headers are corrupted and were read + * with data integrity error, probably this is a bad + * PEB, bit it is not marked as bad yet. This may also + * be a result of power cut during erasure. + */ + si->maybe_bad_peb_count += 1; + case UBI_IO_BAD_HDR: + if (ec_err) + /* + * Both headers are corrupted. There is a possibility + * that this a valid UBI PEB which has corresponding + * LEB, but the headers are corrupted. However, it is + * impossible to distinguish it from a PEB which just + * contains garbage because of a power cut during erase + * operation. So we just schedule this PEB for erasure. + */ + err = 0; + else + /* + * The EC was OK, but the VID header is corrupted. We + * have to check what is in the data area. + */ + err = check_corruption(ubi, vidh, pnum); + + if (err < 0) + return err; + else if (!err) + /* This corruption is caused by a power cut */ + err = add_to_list(si, pnum, ec, 1, &si->erase); + else + /* This is an unexpected corruption */ + err = add_corrupted(si, pnum, ec); if (err) return err; goto adjust_mean_ec; - } else if (err == UBI_IO_PEB_FREE) { - /* No VID header - the physical eraseblock is free */ - err = add_to_list(si, pnum, ec, &si->free); + case UBI_IO_FF_BITFLIPS: + err = add_to_list(si, pnum, ec, 1, &si->erase); if (err) return err; goto adjust_mean_ec; + case UBI_IO_FF: + if (ec_err) + err = add_to_list(si, pnum, ec, 1, &si->erase); + else + err = add_to_list(si, pnum, ec, 0, &si->free); + if (err) + return err; + goto adjust_mean_ec; + default: + ubi_err("'ubi_io_read_vid_hdr()' returned unknown code %d", + err); + return -EINVAL; } vol_id = be32_to_cpu(vidh->vol_id); @@ -843,7 +999,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, case UBI_COMPAT_DELETE: ubi_msg("\"delete\" compatible internal volume %d:%d" " found, will remove it", vol_id, lnum); - err = add_to_list(si, pnum, ec, &si->erase); + err = add_to_list(si, pnum, ec, 1, &si->erase); if (err) return err; return 0; @@ -858,7 +1014,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, case UBI_COMPAT_PRESERVE: ubi_msg("\"preserve\" compatible internal volume %d:%d" " found", vol_id, lnum); - err = add_to_list(si, pnum, ec, &si->alien); + err = add_to_list(si, pnum, ec, 0, &si->alien); if (err) return err; return 0; @@ -870,7 +1026,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, } } - if (ec_corr) + if (ec_err) ubi_warn("valid VID header but corrupted EC header at PEB %d", pnum); err = ubi_scan_add_used(ubi, si, pnum, ec, vidh, bitflips); @@ -878,7 +1034,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, return err; adjust_mean_ec: - if (!ec_corr) { + if (!ec_err) { si->ec_sum += ec; si->ec_count += 1; if (ec > si->max_ec) @@ -904,19 +1060,20 @@ adjust_mean_ec: static int check_what_we_have(struct ubi_device *ubi, struct ubi_scan_info *si) { struct ubi_scan_leb *seb; - int max_corr; + int max_corr, peb_count; - max_corr = ubi->peb_count - si->bad_peb_count - si->alien_peb_count; - max_corr = max_corr / 20 ?: 8; + peb_count = ubi->peb_count - si->bad_peb_count - si->alien_peb_count; + max_corr = peb_count / 20 ?: 8; /* - * Few corrupted PEBs are not a problem and may be just a result of + * Few corrupted PEBs is not a problem and may be just a result of * unclean reboots. However, many of them may indicate some problems * with the flash HW or driver. */ - if (si->corr_peb_count >= 8) { - ubi_warn("%d PEBs are corrupted", si->corr_peb_count); - printk(KERN_WARNING "corrupted PEBs are:"); + if (si->corr_peb_count) { + ubi_err("%d PEBs are corrupted and preserved", + si->corr_peb_count); + printk(KERN_ERR "Corrupted PEBs are:"); list_for_each_entry(seb, &si->corr, u.list) printk(KERN_CONT " %d", seb->pnum); printk(KERN_CONT "\n"); @@ -931,41 +1088,35 @@ static int check_what_we_have(struct ubi_device *ubi, struct ubi_scan_info *si) } } - if (si->free_peb_count + si->used_peb_count + - si->alien_peb_count == 0) { - /* No UBI-formatted eraseblocks were found */ - if (si->corr_peb_count == si->read_err_count && - si->corr_peb_count < 8) { - /* No or just few corrupted PEBs, and all of them had a - * read error. We assume that those are bad PEBs, which - * were just not marked as bad so far. - * - * This piece of code basically tries to distinguish - * between the following 2 situations: - * - * 1. Flash is empty, but there are few bad PEBs, which - * are not marked as bad so far, and which were read - * with error. We want to go ahead and format this - * flash. While formating, the faulty PEBs will - * probably be marked as bad. - * - * 2. Flash probably contains non-UBI data and we do - * not want to format it and destroy possibly needed - * data (e.g., consider the case when the bootloader - * MTD partition was accidentally fed to UBI). - */ + if (si->empty_peb_count + si->maybe_bad_peb_count == peb_count) { + /* + * All PEBs are empty, or almost all - a couple PEBs look like + * they may be bad PEBs which were not marked as bad yet. + * + * This piece of code basically tries to distinguish between + * the following situations: + * + * 1. Flash is empty, but there are few bad PEBs, which are not + * marked as bad so far, and which were read with error. We + * want to go ahead and format this flash. While formatting, + * the faulty PEBs will probably be marked as bad. + * + * 2. Flash contains non-UBI data and we do not want to format + * it and destroy possibly important information. + */ + if (si->maybe_bad_peb_count <= 2) { si->is_empty = 1; ubi_msg("empty MTD device detected"); - get_random_bytes(&ubi->image_seq, sizeof(ubi->image_seq)); + get_random_bytes(&ubi->image_seq, + sizeof(ubi->image_seq)); } else { - ubi_err("MTD device possibly contains non-UBI data, " - "refusing it"); + ubi_err("MTD device is not UBI-formatted and possibly " + "contains non-UBI data - refusing it"); return -EINVAL; } + } - if (si->corr_peb_count > 0) - ubi_msg("corrupted PEBs will be formatted"); return 0; } diff --git a/drivers/mtd/ubi/scan.h b/drivers/mtd/ubi/scan.h index 2576a8d1532b..a3264f0bef2b 100644 --- a/drivers/mtd/ubi/scan.h +++ b/drivers/mtd/ubi/scan.h @@ -30,6 +30,7 @@ * @pnum: physical eraseblock number * @lnum: logical eraseblock number * @scrub: if this physical eraseblock needs scrubbing + * @copy_flag: this LEB is a copy (@copy_flag is set in VID header of this LEB) * @sqnum: sequence number * @u: unions RB-tree or @list links * @u.rb: link in the per-volume RB-tree of &struct ubi_scan_leb objects @@ -42,7 +43,8 @@ struct ubi_scan_leb { int ec; int pnum; int lnum; - int scrub; + unsigned int scrub:1; + unsigned int copy_flag:1; unsigned long long sqnum; union { struct rb_node rb; @@ -91,14 +93,13 @@ struct ubi_scan_volume { * @erase: list of physical eraseblocks which have to be erased * @alien: list of physical eraseblocks which should not be used by UBI (e.g., * those belonging to "preserve"-compatible internal volumes) - * @used_peb_count: count of used PEBs * @corr_peb_count: count of PEBs in the @corr list - * @read_err_count: count of PEBs read with error (%UBI_IO_BAD_HDR_READ was - * returned) - * @free_peb_count: count of PEBs in the @free list - * @erase_peb_count: count of PEBs in the @erase list + * @empty_peb_count: count of PEBs which are presumably empty (contain only + * 0xFF bytes) * @alien_peb_count: count of PEBs in the @alien list * @bad_peb_count: count of bad physical eraseblocks + * @maybe_bad_peb_count: count of bad physical eraseblocks which are not marked + * as bad yet, but which look like bad * @vols_found: number of volumes found during scanning * @highest_vol_id: highest volume ID * @is_empty: flag indicating whether the MTD device is empty or not @@ -119,13 +120,11 @@ struct ubi_scan_info { struct list_head free; struct list_head erase; struct list_head alien; - int used_peb_count; int corr_peb_count; - int read_err_count; - int free_peb_count; - int erase_peb_count; + int empty_peb_count; int alien_peb_count; int bad_peb_count; + int maybe_bad_peb_count; int vols_found; int highest_vol_id; int is_empty; diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h index 0359e0cce482..0b0149c41fe3 100644 --- a/drivers/mtd/ubi/ubi.h +++ b/drivers/mtd/ubi/ubi.h @@ -85,21 +85,26 @@ /* * Error codes returned by the I/O sub-system. * - * UBI_IO_PEB_EMPTY: the physical eraseblock is empty, i.e. it contains only - * %0xFF bytes - * UBI_IO_PEB_FREE: the physical eraseblock is free, i.e. it contains only a - * valid erase counter header, and the rest are %0xFF bytes + * UBI_IO_FF: the read region of flash contains only 0xFFs + * UBI_IO_FF_BITFLIPS: the same as %UBI_IO_FF, but also also there was a data + * integrity error reported by the MTD driver + * (uncorrectable ECC error in case of NAND) * UBI_IO_BAD_HDR: the EC or VID header is corrupted (bad magic or CRC) - * UBI_IO_BAD_HDR_READ: the same as %UBI_IO_BAD_HDR, but also there was a read - * error reported by the flash driver + * UBI_IO_BAD_HDR_EBADMSG: the same as %UBI_IO_BAD_HDR, but also there was a + * data integrity error reported by the MTD driver + * (uncorrectable ECC error in case of NAND) * UBI_IO_BITFLIPS: bit-flips were detected and corrected + * + * Note, it is probably better to have bit-flip and ebadmsg as flags which can + * be or'ed with other error code. But this is a big change because there are + * may callers, so it does not worth the risk of introducing a bug */ enum { - UBI_IO_PEB_EMPTY = 1, - UBI_IO_PEB_FREE, + UBI_IO_FF = 1, + UBI_IO_FF_BITFLIPS, UBI_IO_BAD_HDR, - UBI_IO_BAD_HDR_READ, - UBI_IO_BITFLIPS + UBI_IO_BAD_HDR_EBADMSG, + UBI_IO_BITFLIPS, }; /* @@ -356,6 +361,8 @@ struct ubi_wl_entry; * @peb_size: physical eraseblock size * @bad_peb_count: count of bad physical eraseblocks * @good_peb_count: count of good physical eraseblocks + * @corr_peb_count: count of corrupted physical eraseblocks (preserved and not + * used by UBI) * @erroneous_peb_count: count of erroneous physical eraseblocks in @erroneous * @max_erroneous: maximum allowed amount of erroneous physical eraseblocks * @min_io_size: minimal input/output unit size of the underlying MTD device @@ -442,6 +449,7 @@ struct ubi_device { int peb_size; int bad_peb_count; int good_peb_count; + int corr_peb_count; int erroneous_peb_count; int max_erroneous; int min_io_size; @@ -506,6 +514,7 @@ int ubi_calc_data_len(const struct ubi_device *ubi, const void *buf, int length); int ubi_check_volume(struct ubi_device *ubi, int vol_id); void ubi_calculate_reserved(struct ubi_device *ubi); +int ubi_check_pattern(const void *buf, uint8_t patt, int size); /* eba.c */ int ubi_eba_unmap_leb(struct ubi_device *ubi, struct ubi_volume *vol, diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c index e42afab9a9fe..c47620dfc722 100644 --- a/drivers/mtd/ubi/vmt.c +++ b/drivers/mtd/ubi/vmt.c @@ -261,6 +261,9 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) /* Reserve physical eraseblocks */ if (vol->reserved_pebs > ubi->avail_pebs) { dbg_err("not enough PEBs, only %d available", ubi->avail_pebs); + if (ubi->corr_peb_count) + dbg_err("%d PEBs are corrupted and not used", + ubi->corr_peb_count); err = -ENOSPC; goto out_unlock; } @@ -527,6 +530,9 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs) if (pebs > ubi->avail_pebs) { dbg_err("not enough PEBs: requested %d, available %d", pebs, ubi->avail_pebs); + if (ubi->corr_peb_count) + dbg_err("%d PEBs are corrupted and not used", + ubi->corr_peb_count); spin_unlock(&ubi->volumes_lock); err = -ENOSPC; goto out_free; diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c index 14c10bed94ee..fcdb7f65fe0b 100644 --- a/drivers/mtd/ubi/vtbl.c +++ b/drivers/mtd/ubi/vtbl.c @@ -366,7 +366,7 @@ write_error: * Probably this physical eraseblock went bad, try to pick * another one. */ - list_add_tail(&new_seb->u.list, &si->corr); + list_add(&new_seb->u.list, &si->erase); goto retry; } kfree(new_seb); @@ -662,9 +662,13 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si, ubi->vol_count += 1; vol->ubi = ubi; - if (reserved_pebs > ubi->avail_pebs) + if (reserved_pebs > ubi->avail_pebs) { ubi_err("not enough PEBs, required %d, available %d", reserved_pebs, ubi->avail_pebs); + if (ubi->corr_peb_count) + ubi_err("%d PEBs are corrupted and not used", + ubi->corr_peb_count); + } ubi->rsvd_pebs += reserved_pebs; ubi->avail_pebs -= reserved_pebs; @@ -837,7 +841,7 @@ int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si) return PTR_ERR(ubi->vtbl); } - ubi->avail_pebs = ubi->good_peb_count; + ubi->avail_pebs = ubi->good_peb_count - ubi->corr_peb_count; /* * The layout volume is OK, initialize the corresponding in-RAM data diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index 97a435672eaf..655bbbe415d9 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -745,7 +745,7 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, err = ubi_io_read_vid_hdr(ubi, e1->pnum, vid_hdr, 0); if (err && err != UBI_IO_BITFLIPS) { - if (err == UBI_IO_PEB_FREE) { + if (err == UBI_IO_FF) { /* * We are trying to move PEB without a VID header. UBI * always write VID headers shortly after the PEB was @@ -759,6 +759,16 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, dbg_wl("PEB %d has no VID header", e1->pnum); protect = 1; goto out_not_moved; + } else if (err == UBI_IO_FF_BITFLIPS) { + /* + * The same situation as %UBI_IO_FF, but bit-flips were + * detected. It is better to schedule this PEB for + * scrubbing. + */ + dbg_wl("PEB %d has no VID header but has bit-flips", + e1->pnum); + scrubbing = 1; + goto out_not_moved; } ubi_err("error %d while reading VID header from PEB %d", @@ -1468,22 +1478,6 @@ int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si) ubi->lookuptbl[e->pnum] = e; } - list_for_each_entry(seb, &si->corr, u.list) { - cond_resched(); - - e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL); - if (!e) - goto out_free; - - e->pnum = seb->pnum; - e->ec = seb->ec; - ubi->lookuptbl[e->pnum] = e; - if (schedule_erase(ubi, e, 0)) { - kmem_cache_free(ubi_wl_entry_slab, e); - goto out_free; - } - } - ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) { ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb) { cond_resched(); @@ -1510,6 +1504,9 @@ int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si) if (ubi->avail_pebs < WL_RESERVED_PEBS) { ubi_err("no enough physical eraseblocks (%d, need %d)", ubi->avail_pebs, WL_RESERVED_PEBS); + if (ubi->corr_peb_count) + ubi_err("%d PEBs are corrupted and not used", + ubi->corr_peb_count); goto out_free; } ubi->avail_pebs -= WL_RESERVED_PEBS; diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c index 70705d1306b9..eca55c52bdfd 100644 --- a/drivers/net/3c527.c +++ b/drivers/net/3c527.c @@ -522,7 +522,7 @@ static int __init mc32_probe1(struct net_device *dev, int slot) lp->tx_len = lp->exec_box->data[9]; /* Transmit list count */ lp->rx_len = lp->exec_box->data[11]; /* Receive list count */ - init_MUTEX_LOCKED(&lp->cmd_mutex); + sema_init(&lp->cmd_mutex, 0); init_completion(&lp->execution_cmd); init_completion(&lp->xceiver_cmd); diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 5db667c0b371..77efe462b921 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2,6 +2,9 @@ # Network device configuration # +config HAVE_NET_MACB + bool + menuconfig NETDEVICES default y if UML depends on NET @@ -221,7 +224,7 @@ config MII config MACB tristate "Atmel MACB support" - depends on AVR32 || ARCH_AT91SAM9260 || ARCH_AT91SAM9263 || ARCH_AT91SAM9G20 || ARCH_AT91SAM9G45 || ARCH_AT91CAP9 + depends on HAVE_NET_MACB select PHYLIB help The Atmel MACB ethernet interface is found on many AT32 and AT91 diff --git a/drivers/net/appletalk/Kconfig b/drivers/net/appletalk/Kconfig index 0a0e0cd81a23..20f97e7017ce 100644 --- a/drivers/net/appletalk/Kconfig +++ b/drivers/net/appletalk/Kconfig @@ -3,6 +3,7 @@ # config ATALK tristate "Appletalk protocol support" + depends on BKL # waiting to be removed from net/appletalk/ddp.c select LLC ---help--- AppleTalk is the protocol that Apple computers can use to communicate diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c index 012613fde3f4..03d063554b7f 100644 --- a/drivers/net/bfin_mac.c +++ b/drivers/net/bfin_mac.c @@ -38,6 +38,7 @@ #include <asm/blackfin.h> #include <asm/cacheflush.h> #include <asm/portmux.h> +#include <mach/pll.h> #include "bfin_mac.h" diff --git a/drivers/net/caif/caif_spi.c b/drivers/net/caif/caif_spi.c index f5058ff2b210..8427533fe313 100644 --- a/drivers/net/caif/caif_spi.c +++ b/drivers/net/caif/caif_spi.c @@ -240,13 +240,15 @@ static ssize_t dbgfs_frame(struct file *file, char __user *user_buf, static const struct file_operations dbgfs_state_fops = { .open = dbgfs_open, .read = dbgfs_state, - .owner = THIS_MODULE + .owner = THIS_MODULE, + .llseek = default_llseek, }; static const struct file_operations dbgfs_frame_fops = { .open = dbgfs_open, .read = dbgfs_frame, - .owner = THIS_MODULE + .owner = THIS_MODULE, + .llseek = default_llseek, }; static inline void dev_debugfs_add(struct cfspi *cfspi) diff --git a/drivers/net/cxgb4/cxgb4_main.c b/drivers/net/cxgb4/cxgb4_main.c index c327527fbbc8..e2bf10d90add 100644 --- a/drivers/net/cxgb4/cxgb4_main.c +++ b/drivers/net/cxgb4/cxgb4_main.c @@ -2026,6 +2026,7 @@ static const struct file_operations mem_debugfs_fops = { .owner = THIS_MODULE, .open = mem_open, .read = mem_read, + .llseek = default_llseek, }; static void __devinit add_debugfs_mem(struct adapter *adap, const char *name, diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c index 4b52c767ad05..3e5d0b6b6516 100644 --- a/drivers/net/hamradio/6pack.c +++ b/drivers/net/hamradio/6pack.c @@ -608,7 +608,7 @@ static int sixpack_open(struct tty_struct *tty) spin_lock_init(&sp->lock); atomic_set(&sp->refcnt, 1); - init_MUTEX_LOCKED(&sp->dead_sem); + sema_init(&sp->dead_sem, 0); /* !!! length of the buffers. MTU is IP MTU, not PACLEN! */ diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index 66e88bd59caa..4c628393c8b1 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -747,7 +747,7 @@ static int mkiss_open(struct tty_struct *tty) spin_lock_init(&ax->buflock); atomic_set(&ax->refcnt, 1); - init_MUTEX_LOCKED(&ax->dead_sem); + sema_init(&ax->dead_sem, 0); ax->tty = tty; tty->disc_data = ax; diff --git a/drivers/net/irda/sir_dev.c b/drivers/net/irda/sir_dev.c index 1b051dab7b29..51d74447f8f8 100644 --- a/drivers/net/irda/sir_dev.c +++ b/drivers/net/irda/sir_dev.c @@ -909,7 +909,7 @@ struct sir_dev * sirdev_get_instance(const struct sir_driver *drv, const char *n dev->tx_skb = NULL; spin_lock_init(&dev->tx_lock); - init_MUTEX(&dev->fsm.sem); + sema_init(&dev->fsm.sem, 1); dev->drv = drv; dev->netdev = ndev; diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c index c683f77c6f42..ff824e11f0b6 100644 --- a/drivers/net/pcmcia/3c574_cs.c +++ b/drivers/net/pcmcia/3c574_cs.c @@ -87,7 +87,6 @@ earlier 3Com products. #include <linux/bitops.h> #include <linux/mii.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/cisreg.h> #include <pcmcia/ciscode.h> @@ -280,25 +279,15 @@ static int tc574_probe(struct pcmcia_device *link) spin_lock_init(&lp->window_lock); link->resource[0]->end = 32; link->resource[0]->flags |= IO_DATA_PATH_WIDTH_16; - link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.IntType = INT_MEMORY_AND_IO; - link->conf.ConfigIndex = 1; + link->config_flags |= CONF_ENABLE_IRQ; + link->config_index = 1; dev->netdev_ops = &el3_netdev_ops; SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops); dev->watchdog_timeo = TX_TIMEOUT; return tc574_config(link); -} /* tc574_attach */ - -/* - - This deletes a driver "instance". The device is de-registered - with Card Services. If it has been released, all local data - structures are freed. Otherwise, the structures will be freed - when the device is released. - -*/ +} static void tc574_detach(struct pcmcia_device *link) { @@ -313,12 +302,6 @@ static void tc574_detach(struct pcmcia_device *link) free_netdev(dev); } /* tc574_detach */ -/* - tc574_config() is scheduled to run after a CARD_INSERTION event - is received, to configure the PCMCIA socket, and to make the - ethernet device available to the system. -*/ - static const char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"}; static int tc574_config(struct pcmcia_device *link) @@ -352,7 +335,7 @@ static int tc574_config(struct pcmcia_device *link) if (ret) goto failed; - ret = pcmcia_request_configuration(link, &link->conf); + ret = pcmcia_enable_device(link); if (ret) goto failed; @@ -465,12 +448,6 @@ failed: } /* tc574_config */ -/* - After a card is removed, tc574_release() will unregister the net - device, and release the PCMCIA configuration. If the device is - still open, this will be postponed until it is closed. -*/ - static void tc574_release(struct pcmcia_device *link) { pcmcia_disable_device(link); @@ -1198,9 +1175,7 @@ MODULE_DEVICE_TABLE(pcmcia, tc574_ids); static struct pcmcia_driver tc574_driver = { .owner = THIS_MODULE, - .drv = { - .name = "3c574_cs", - }, + .name = "3c574_cs", .probe = tc574_probe, .remove = tc574_detach, .id_table = tc574_ids, diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c index 61f9cf2100ff..a07e22295330 100644 --- a/drivers/net/pcmcia/3c589_cs.c +++ b/drivers/net/pcmcia/3c589_cs.c @@ -41,7 +41,6 @@ #include <linux/bitops.h> #include <linux/jiffies.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/cisreg.h> #include <pcmcia/ciscode.h> @@ -176,14 +175,6 @@ static const struct ethtool_ops netdev_ethtool_ops; static void tc589_detach(struct pcmcia_device *p_dev); -/*====================================================================== - - tc589_attach() creates an "instance" of the driver, allocating - local data structures for one device. The device is registered - with Card Services. - -======================================================================*/ - static const struct net_device_ops el3_netdev_ops = { .ndo_open = el3_open, .ndo_stop = el3_close, @@ -216,9 +207,8 @@ static int tc589_probe(struct pcmcia_device *link) link->resource[0]->end = 16; link->resource[0]->flags |= IO_DATA_PATH_WIDTH_16; - link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.IntType = INT_MEMORY_AND_IO; - link->conf.ConfigIndex = 1; + link->config_flags |= CONF_ENABLE_IRQ; + link->config_index = 1; dev->netdev_ops = &el3_netdev_ops; dev->watchdog_timeo = TX_TIMEOUT; @@ -226,16 +216,7 @@ static int tc589_probe(struct pcmcia_device *link) SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops); return tc589_config(link); -} /* tc589_attach */ - -/*====================================================================== - - This deletes a driver "instance". The device is de-registered - with Card Services. If it has been released, all local data - structures are freed. Otherwise, the structures will be freed - when the device is released. - -======================================================================*/ +} static void tc589_detach(struct pcmcia_device *link) { @@ -250,14 +231,6 @@ static void tc589_detach(struct pcmcia_device *link) free_netdev(dev); } /* tc589_detach */ -/*====================================================================== - - tc589_config() is scheduled to run after a CARD_INSERTION event - is received, to configure the PCMCIA socket, and to make the - ethernet device available to the system. - -======================================================================*/ - static int tc589_config(struct pcmcia_device *link) { struct net_device *dev = link->priv; @@ -294,7 +267,7 @@ static int tc589_config(struct pcmcia_device *link) if (ret) goto failed; - ret = pcmcia_request_configuration(link, &link->conf); + ret = pcmcia_enable_device(link); if (ret) goto failed; @@ -352,14 +325,6 @@ failed: return -ENODEV; } /* tc589_config */ -/*====================================================================== - - After a card is removed, tc589_release() will unregister the net - device, and release the PCMCIA configuration. If the device is - still open, this will be postponed until it is closed. - -======================================================================*/ - static void tc589_release(struct pcmcia_device *link) { pcmcia_disable_device(link); @@ -955,9 +920,7 @@ MODULE_DEVICE_TABLE(pcmcia, tc589_ids); static struct pcmcia_driver tc589_driver = { .owner = THIS_MODULE, - .drv = { - .name = "3c589_cs", - }, + .name = "3c589_cs", .probe = tc589_probe, .remove = tc589_detach, .id_table = tc589_ids, diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index 5f05ffb240cc..9e8b28b271ae 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -39,7 +39,6 @@ #include <linux/mii.h> #include "../8390.h" -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/ciscode.h> #include <pcmcia/ds.h> @@ -140,14 +139,6 @@ static const struct net_device_ops axnet_netdev_ops = { .ndo_validate_addr = eth_validate_addr, }; -/*====================================================================== - - axnet_attach() creates an "instance" of the driver, allocating - local data structures for one device. The device is registered - with Card Services. - -======================================================================*/ - static int axnet_probe(struct pcmcia_device *link) { axnet_dev_t *info; @@ -166,8 +157,7 @@ static int axnet_probe(struct pcmcia_device *link) info = PRIV(dev); info->p_dev = link; link->priv = dev; - link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.IntType = INT_MEMORY_AND_IO; + link->config_flags |= CONF_ENABLE_IRQ; dev->netdev_ops = &axnet_netdev_ops; @@ -177,15 +167,6 @@ static int axnet_probe(struct pcmcia_device *link) return axnet_config(link); } /* axnet_attach */ -/*====================================================================== - - This deletes a driver "instance". The device is de-registered - with Card Services. If it has been released, all local data - structures are freed. Otherwise, the structures will be freed - when the device is released. - -======================================================================*/ - static void axnet_detach(struct pcmcia_device *link) { struct net_device *dev = link->priv; @@ -231,7 +212,7 @@ static int get_prom(struct pcmcia_device *link) }; /* Not much of a test, but the alternatives are messy */ - if (link->conf.ConfigBase != 0x03c0) + if (link->config_base != 0x03c0) return 0; axnet_reset_8390(dev); @@ -248,14 +229,6 @@ static int get_prom(struct pcmcia_device *link) return 1; } /* get_prom */ -/*====================================================================== - - axnet_config() is scheduled to run after a CARD_INSERTION event - is received, to configure the PCMCIA socket, and to make the - ethernet device available to the system. - -======================================================================*/ - static int try_io_port(struct pcmcia_device *link) { int j, ret; @@ -286,35 +259,16 @@ static int try_io_port(struct pcmcia_device *link) } } -static int axnet_configcheck(struct pcmcia_device *p_dev, - cistpl_cftable_entry_t *cfg, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, - void *priv_data) +static int axnet_configcheck(struct pcmcia_device *p_dev, void *priv_data) { - int i; - cistpl_io_t *io = &cfg->io; + if (p_dev->config_index == 0) + return -EINVAL; - if (cfg->index == 0 || cfg->io.nwin == 0) + p_dev->config_index = 0x05; + if (p_dev->resource[0]->end + p_dev->resource[1]->end < 32) return -ENODEV; - p_dev->conf.ConfigIndex = 0x05; - /* For multifunction cards, by convention, we configure the - network function with window 0, and serial with window 1 */ - if (io->nwin > 1) { - i = (io->win[1].len > io->win[0].len); - p_dev->resource[1]->start = io->win[1-i].base; - p_dev->resource[1]->end = io->win[1-i].len; - } else { - i = p_dev->resource[1]->end = 0; - } - p_dev->resource[0]->start = io->win[i].base; - p_dev->resource[0]->end = io->win[i].len; - p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK; - if (p_dev->resource[0]->end + p_dev->resource[1]->end >= 32) - return try_io_port(p_dev); - - return -ENODEV; + return try_io_port(p_dev); } static int axnet_config(struct pcmcia_device *link) @@ -326,20 +280,19 @@ static int axnet_config(struct pcmcia_device *link) dev_dbg(&link->dev, "axnet_config(0x%p)\n", link); /* don't trust the CIS on this; Linksys got it wrong */ - link->conf.Present = 0x63; + link->config_regs = 0x63; + link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; ret = pcmcia_loop_config(link, axnet_configcheck, NULL); if (ret != 0) goto failed; if (!link->irq) goto failed; + + if (resource_size(link->resource[1]) == 8) + link->config_flags |= CONF_ENABLE_SPKR; - if (resource_size(link->resource[1]) == 8) { - link->conf.Attributes |= CONF_ENABLE_SPKR; - link->conf.Status = CCSR_AUDIO_ENA; - } - - ret = pcmcia_request_configuration(link, &link->conf); + ret = pcmcia_enable_device(link); if (ret) goto failed; @@ -414,14 +367,6 @@ failed: return -ENODEV; } /* axnet_config */ -/*====================================================================== - - After a card is removed, axnet_release() will unregister the net - device, and release the PCMCIA configuration. If the device is - still open, this will be postponed until it is closed. - -======================================================================*/ - static void axnet_release(struct pcmcia_device *link) { pcmcia_disable_device(link); @@ -783,9 +728,7 @@ MODULE_DEVICE_TABLE(pcmcia, axnet_ids); static struct pcmcia_driver axnet_cs_driver = { .owner = THIS_MODULE, - .drv = { - .name = "axnet_cs", - }, + .name = "axnet_cs", .probe = axnet_probe, .remove = axnet_detach, .id_table = axnet_ids, diff --git a/drivers/net/pcmcia/com20020_cs.c b/drivers/net/pcmcia/com20020_cs.c index 3c400cfa82ae..b706a7249477 100644 --- a/drivers/net/pcmcia/com20020_cs.c +++ b/drivers/net/pcmcia/com20020_cs.c @@ -43,7 +43,6 @@ #include <linux/arcdevice.h> #include <linux/com20020.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/ds.h> @@ -123,14 +122,6 @@ typedef struct com20020_dev_t { struct net_device *dev; } com20020_dev_t; -/*====================================================================== - - com20020_attach() creates an "instance" of the driver, allocating - local data structures for one device. The device is registered - with Card Services. - -======================================================================*/ - static int com20020_probe(struct pcmcia_device *p_dev) { com20020_dev_t *info; @@ -160,8 +151,7 @@ static int com20020_probe(struct pcmcia_device *p_dev) p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; p_dev->resource[0]->end = 16; - p_dev->conf.Attributes = CONF_ENABLE_IRQ; - p_dev->conf.IntType = INT_MEMORY_AND_IO; + p_dev->config_flags |= CONF_ENABLE_IRQ; info->dev = dev; p_dev->priv = info; @@ -174,15 +164,6 @@ fail_alloc_info: return -ENOMEM; } /* com20020_attach */ -/*====================================================================== - - This deletes a driver "instance". The device is de-registered - with Card Services. If it has been released, all local data - structures are freed. Otherwise, the structures will be freed - when the device is released. - -======================================================================*/ - static void com20020_detach(struct pcmcia_device *link) { struct com20020_dev_t *info = link->priv; @@ -221,14 +202,6 @@ static void com20020_detach(struct pcmcia_device *link) } /* com20020_detach */ -/*====================================================================== - - com20020_config() is scheduled to run after a CARD_INSERTION event - is received, to configure the PCMCIA socket, and to make the - device available to the system. - -======================================================================*/ - static int com20020_config(struct pcmcia_device *link) { struct arcnet_local *lp; @@ -282,7 +255,7 @@ static int com20020_config(struct pcmcia_device *link) dev->irq = link->irq; - ret = pcmcia_request_configuration(link, &link->conf); + ret = pcmcia_enable_device(link); if (ret) goto failed; @@ -316,14 +289,6 @@ failed: return -ENODEV; } /* com20020_config */ -/*====================================================================== - - After a card is removed, com20020_release() will unregister the net - device, and release the PCMCIA configuration. If the device is - still open, this will be postponed until it is closed. - -======================================================================*/ - static void com20020_release(struct pcmcia_device *link) { dev_dbg(&link->dev, "com20020_release\n"); @@ -366,9 +331,7 @@ MODULE_DEVICE_TABLE(pcmcia, com20020_ids); static struct pcmcia_driver com20020_cs_driver = { .owner = THIS_MODULE, - .drv = { - .name = "com20020_cs", - }, + .name = "com20020_cs", .probe = com20020_probe, .remove = com20020_detach, .id_table = com20020_ids, diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c index 98fffb03ecd7..1c327598bbe8 100644 --- a/drivers/net/pcmcia/fmvj18x_cs.c +++ b/drivers/net/pcmcia/fmvj18x_cs.c @@ -49,7 +49,6 @@ #include <linux/ioport.h> #include <linux/crc32.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/ciscode.h> #include <pcmcia/ds.h> @@ -252,8 +251,7 @@ static int fmvj18x_probe(struct pcmcia_device *link) link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; /* General socket configuration */ - link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.IntType = INT_MEMORY_AND_IO; + link->config_flags |= CONF_ENABLE_IRQ; dev->netdev_ops = &fjn_netdev_ops; dev->watchdog_timeo = TX_TIMEOUT; @@ -313,7 +311,7 @@ static int ungermann_try_io_port(struct pcmcia_device *link) ret = pcmcia_request_io(link); if (ret == 0) { /* calculate ConfigIndex value */ - link->conf.ConfigIndex = + link->config_index = ((link->resource[0]->start & 0x0f0) >> 3) | 0x22; return ret; } @@ -321,11 +319,7 @@ static int ungermann_try_io_port(struct pcmcia_device *link) return ret; /* RequestIO failed */ } -static int fmvj18x_ioprobe(struct pcmcia_device *p_dev, - cistpl_cftable_entry_t *cfg, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, - void *priv_data) +static int fmvj18x_ioprobe(struct pcmcia_device *p_dev, void *priv_data) { return 0; /* strange, but that's what the code did already before... */ } @@ -362,28 +356,28 @@ static int fmvj18x_config(struct pcmcia_device *link) link->card_id == PRODID_TDK_NP9610 || link->card_id == PRODID_TDK_MN3200) { /* MultiFunction Card */ - link->conf.ConfigBase = 0x800; - link->conf.ConfigIndex = 0x47; + link->config_base = 0x800; + link->config_index = 0x47; link->resource[1]->end = 8; } break; case MANFID_NEC: cardtype = NEC; /* MultiFunction Card */ - link->conf.ConfigBase = 0x800; - link->conf.ConfigIndex = 0x47; + link->config_base = 0x800; + link->config_index = 0x47; link->resource[1]->end = 8; break; case MANFID_KME: cardtype = KME; /* MultiFunction Card */ - link->conf.ConfigBase = 0x800; - link->conf.ConfigIndex = 0x47; + link->config_base = 0x800; + link->config_index = 0x47; link->resource[1]->end = 8; break; case MANFID_CONTEC: cardtype = CONTEC; break; case MANFID_FUJITSU: - if (link->conf.ConfigBase == 0x0fe0) + if (link->config_base == 0x0fe0) cardtype = MBH10302; else if (link->card_id == PRODID_FUJITSU_MBH10302) /* RATOC REX-5588/9822/4886's PRODID are 0004(=MBH10302), @@ -403,10 +397,10 @@ static int fmvj18x_config(struct pcmcia_device *link) case MANFID_FUJITSU: if (link->card_id == PRODID_FUJITSU_MBH10304) { cardtype = XXX10304; /* MBH10304 with buggy CIS */ - link->conf.ConfigIndex = 0x20; + link->config_index = 0x20; } else { cardtype = MBH10302; /* NextCom NC5310, etc. */ - link->conf.ConfigIndex = 1; + link->config_index = 1; } break; case MANFID_UNGERMANN: @@ -414,7 +408,7 @@ static int fmvj18x_config(struct pcmcia_device *link) break; default: cardtype = MBH10302; - link->conf.ConfigIndex = 1; + link->config_index = 1; } } @@ -432,7 +426,7 @@ static int fmvj18x_config(struct pcmcia_device *link) ret = pcmcia_request_irq(link, fjn_interrupt); if (ret) goto failed; - ret = pcmcia_request_configuration(link, &link->conf); + ret = pcmcia_enable_device(link); if (ret) goto failed; @@ -544,20 +538,18 @@ failed: static int fmvj18x_get_hwinfo(struct pcmcia_device *link, u_char *node_id) { - win_req_t req; u_char __iomem *base; int i, j; /* Allocate a small memory window */ - req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; - req.Base = 0; req.Size = 0; - req.AccessSpeed = 0; - i = pcmcia_request_window(link, &req, &link->win); + link->resource[2]->flags |= WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; + link->resource[2]->start = 0; link->resource[2]->end = 0; + i = pcmcia_request_window(link, link->resource[2], 0); if (i != 0) return -1; - base = ioremap(req.Base, req.Size); - pcmcia_map_mem_page(link, link->win, 0); + base = ioremap(link->resource[2]->start, resource_size(link->resource[2])); + pcmcia_map_mem_page(link, link->resource[2], 0); /* * MBH10304 CISTPL_FUNCE_LAN_NODE_ID format @@ -582,7 +574,7 @@ static int fmvj18x_get_hwinfo(struct pcmcia_device *link, u_char *node_id) } iounmap(base); - j = pcmcia_release_window(link, link->win); + j = pcmcia_release_window(link, link->resource[2]); return (i != 0x200) ? 0 : -1; } /* fmvj18x_get_hwinfo */ @@ -590,27 +582,26 @@ static int fmvj18x_get_hwinfo(struct pcmcia_device *link, u_char *node_id) static int fmvj18x_setup_mfc(struct pcmcia_device *link) { - win_req_t req; int i; struct net_device *dev = link->priv; unsigned int ioaddr; local_info_t *lp = netdev_priv(dev); /* Allocate a small memory window */ - req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; - req.Base = 0; req.Size = 0; - req.AccessSpeed = 0; - i = pcmcia_request_window(link, &req, &link->win); + link->resource[3]->flags = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; + link->resource[3]->start = link->resource[3]->end = 0; + i = pcmcia_request_window(link, link->resource[3], 0); if (i != 0) return -1; - lp->base = ioremap(req.Base, req.Size); + lp->base = ioremap(link->resource[3]->start, + resource_size(link->resource[3])); if (lp->base == NULL) { printk(KERN_NOTICE "fmvj18x_cs: ioremap failed\n"); return -1; } - i = pcmcia_map_mem_page(link, link->win, 0); + i = pcmcia_map_mem_page(link, link->resource[3], 0); if (i != 0) { iounmap(lp->base); lp->base = NULL; @@ -638,7 +629,6 @@ static void fmvj18x_release(struct pcmcia_device *link) struct net_device *dev = link->priv; local_info_t *lp = netdev_priv(dev); u_char __iomem *tmp; - int j; dev_dbg(&link->dev, "fmvj18x_release\n"); @@ -646,7 +636,6 @@ static void fmvj18x_release(struct pcmcia_device *link) tmp = lp->base; lp->base = NULL; /* set NULL before iounmap */ iounmap(tmp); - j = pcmcia_release_window(link, link->win); } pcmcia_disable_device(link); @@ -708,9 +697,7 @@ MODULE_DEVICE_TABLE(pcmcia, fmvj18x_ids); static struct pcmcia_driver fmvj18x_cs_driver = { .owner = THIS_MODULE, - .drv = { - .name = "fmvj18x_cs", - }, + .name = "fmvj18x_cs", .probe = fmvj18x_probe, .remove = fmvj18x_detach, .id_table = fmvj18x_ids, diff --git a/drivers/net/pcmcia/ibmtr_cs.c b/drivers/net/pcmcia/ibmtr_cs.c index b0d06a3d962f..bf7dff96d881 100644 --- a/drivers/net/pcmcia/ibmtr_cs.c +++ b/drivers/net/pcmcia/ibmtr_cs.c @@ -57,7 +57,6 @@ #include <linux/trdevice.h> #include <linux/ibmtr.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/ds.h> @@ -102,9 +101,8 @@ static void ibmtr_detach(struct pcmcia_device *p_dev); typedef struct ibmtr_dev_t { struct pcmcia_device *p_dev; - struct net_device *dev; - window_handle_t sram_win_handle; - struct tok_info *ti; + struct net_device *dev; + struct tok_info *ti; } ibmtr_dev_t; static void netdev_get_drvinfo(struct net_device *dev, @@ -123,14 +121,6 @@ static irqreturn_t ibmtr_interrupt(int irq, void *dev_id) { return tok_interrupt(irq, dev); }; -/*====================================================================== - - ibmtr_attach() creates an "instance" of the driver, allocating - local data structures for one device. The device is registered - with Card Services. - -======================================================================*/ - static int __devinit ibmtr_attach(struct pcmcia_device *link) { ibmtr_dev_t *info; @@ -153,9 +143,8 @@ static int __devinit ibmtr_attach(struct pcmcia_device *link) link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; link->resource[0]->end = 4; - link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.IntType = INT_MEMORY_AND_IO; - link->conf.Present = PRESENT_OPTION; + link->config_flags |= CONF_ENABLE_IRQ; + link->config_regs = PRESENT_OPTION; info->dev = dev; @@ -164,15 +153,6 @@ static int __devinit ibmtr_attach(struct pcmcia_device *link) return ibmtr_config(link); } /* ibmtr_attach */ -/*====================================================================== - - This deletes a driver "instance". The device is de-registered - with Card Services. If it has been released, all local data - structures are freed. Otherwise, the structures will be freed - when the device is released. - -======================================================================*/ - static void ibmtr_detach(struct pcmcia_device *link) { struct ibmtr_dev_t *info = link->priv; @@ -197,26 +177,17 @@ static void ibmtr_detach(struct pcmcia_device *link) kfree(info); } /* ibmtr_detach */ -/*====================================================================== - - ibmtr_config() is scheduled to run after a CARD_INSERTION event - is received, to configure the PCMCIA socket, and to make the - token-ring device available to the system. - -======================================================================*/ - static int __devinit ibmtr_config(struct pcmcia_device *link) { ibmtr_dev_t *info = link->priv; struct net_device *dev = info->dev; struct tok_info *ti = netdev_priv(dev); - win_req_t req; int i, ret; dev_dbg(&link->dev, "ibmtr_config\n"); - link->conf.ConfigIndex = 0x61; link->io_lines = 16; + link->config_index = 0x61; /* Determine if this is PRIMARY or ALTERNATE. */ @@ -240,39 +211,39 @@ static int __devinit ibmtr_config(struct pcmcia_device *link) ti->global_int_enable=GLOBAL_INT_ENABLE+((dev->irq==9) ? 2 : dev->irq); /* Allocate the MMIO memory window */ - req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE; - req.Attributes |= WIN_USE_WAIT; - req.Base = 0; - req.Size = 0x2000; - req.AccessSpeed = 250; - ret = pcmcia_request_window(link, &req, &link->win); + link->resource[2]->flags |= WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE; + link->resource[2]->flags |= WIN_USE_WAIT; + link->resource[2]->start = 0; + link->resource[2]->end = 0x2000; + ret = pcmcia_request_window(link, link->resource[2], 250); if (ret) goto failed; - ret = pcmcia_map_mem_page(link, link->win, mmiobase); + ret = pcmcia_map_mem_page(link, link->resource[2], mmiobase); if (ret) goto failed; - ti->mmio = ioremap(req.Base, req.Size); + ti->mmio = ioremap(link->resource[2]->start, + resource_size(link->resource[2])); /* Allocate the SRAM memory window */ - req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE; - req.Attributes |= WIN_USE_WAIT; - req.Base = 0; - req.Size = sramsize * 1024; - req.AccessSpeed = 250; - ret = pcmcia_request_window(link, &req, &info->sram_win_handle); + link->resource[3]->flags = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE; + link->resource[3]->flags |= WIN_USE_WAIT; + link->resource[3]->start = 0; + link->resource[3]->end = sramsize * 1024; + ret = pcmcia_request_window(link, link->resource[3], 250); if (ret) goto failed; - ret = pcmcia_map_mem_page(link, info->sram_win_handle, srambase); + ret = pcmcia_map_mem_page(link, link->resource[3], srambase); if (ret) goto failed; ti->sram_base = srambase >> 12; - ti->sram_virt = ioremap(req.Base, req.Size); - ti->sram_phys = req.Base; + ti->sram_virt = ioremap(link->resource[3]->start, + resource_size(link->resource[3])); + ti->sram_phys = link->resource[3]->start; - ret = pcmcia_request_configuration(link, &link->conf); + ret = pcmcia_enable_device(link); if (ret) goto failed; @@ -301,14 +272,6 @@ failed: return -ENODEV; } /* ibmtr_config */ -/*====================================================================== - - After a card is removed, ibmtr_release() will unregister the net - device, and release the PCMCIA configuration. If the device is - still open, this will be postponed until it is closed. - -======================================================================*/ - static void ibmtr_release(struct pcmcia_device *link) { ibmtr_dev_t *info = link->priv; @@ -316,7 +279,7 @@ static void ibmtr_release(struct pcmcia_device *link) dev_dbg(&link->dev, "ibmtr_release\n"); - if (link->win) { + if (link->resource[2]->end) { struct tok_info *ti = netdev_priv(dev); iounmap(ti->mmio); } @@ -398,9 +361,7 @@ MODULE_DEVICE_TABLE(pcmcia, ibmtr_ids); static struct pcmcia_driver ibmtr_cs_driver = { .owner = THIS_MODULE, - .drv = { - .name = "ibmtr_cs", - }, + .name = "ibmtr_cs", .probe = ibmtr_attach, .remove = ibmtr_detach, .id_table = ibmtr_ids, diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c index 68f2deeb3ade..1eca4f5a6e78 100644 --- a/drivers/net/pcmcia/nmclan_cs.c +++ b/drivers/net/pcmcia/nmclan_cs.c @@ -146,7 +146,6 @@ Include Files #include <linux/ioport.h> #include <linux/bitops.h> -#include <pcmcia/cs.h> #include <pcmcia/cisreg.h> #include <pcmcia/cistpl.h> #include <pcmcia/ds.h> @@ -435,13 +434,6 @@ static const struct net_device_ops mace_netdev_ops = { .ndo_validate_addr = eth_validate_addr, }; -/* ---------------------------------------------------------------------------- -nmclan_attach - Creates an "instance" of the driver, allocating local data - structures for one device. The device is registered with Card - Services. ----------------------------------------------------------------------------- */ - static int nmclan_probe(struct pcmcia_device *link) { mace_private *lp; @@ -460,10 +452,9 @@ static int nmclan_probe(struct pcmcia_device *link) spin_lock_init(&lp->bank_lock); link->resource[0]->end = 32; link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; - link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.IntType = INT_MEMORY_AND_IO; - link->conf.ConfigIndex = 1; - link->conf.Present = PRESENT_OPTION; + link->config_flags |= CONF_ENABLE_IRQ; + link->config_index = 1; + link->config_regs = PRESENT_OPTION; lp->tx_free_frames=AM2150_MAX_TX_FRAMES; @@ -474,14 +465,6 @@ static int nmclan_probe(struct pcmcia_device *link) return nmclan_config(link); } /* nmclan_attach */ -/* ---------------------------------------------------------------------------- -nmclan_detach - This deletes a driver "instance". The device is de-registered - with Card Services. If it has been released, all local data - structures are freed. Otherwise, the structures will be freed - when the device is released. ----------------------------------------------------------------------------- */ - static void nmclan_detach(struct pcmcia_device *link) { struct net_device *dev = link->priv; @@ -625,13 +608,6 @@ static int mace_init(mace_private *lp, unsigned int ioaddr, char *enet_addr) return 0; } /* mace_init */ -/* ---------------------------------------------------------------------------- -nmclan_config - This routine is scheduled to run after a CARD_INSERTION event - is received, to configure the PCMCIA socket, and to make the - ethernet device available to the system. ----------------------------------------------------------------------------- */ - static int nmclan_config(struct pcmcia_device *link) { struct net_device *dev = link->priv; @@ -650,7 +626,7 @@ static int nmclan_config(struct pcmcia_device *link) ret = pcmcia_request_exclusive_irq(link, mace_interrupt); if (ret) goto failed; - ret = pcmcia_request_configuration(link, &link->conf); + ret = pcmcia_enable_device(link); if (ret) goto failed; @@ -712,12 +688,6 @@ failed: return -ENODEV; } /* nmclan_config */ -/* ---------------------------------------------------------------------------- -nmclan_release - After a card is removed, nmclan_release() will unregister the - net device, and release the PCMCIA configuration. If the device - is still open, this will be postponed until it is closed. ----------------------------------------------------------------------------- */ static void nmclan_release(struct pcmcia_device *link) { dev_dbg(&link->dev, "nmclan_release\n"); @@ -1535,9 +1505,7 @@ MODULE_DEVICE_TABLE(pcmcia, nmclan_ids); static struct pcmcia_driver nmclan_cs_driver = { .owner = THIS_MODULE, - .drv = { - .name = "nmclan_cs", - }, + .name = "nmclan_cs", .probe = nmclan_probe, .remove = nmclan_detach, .id_table = nmclan_ids, diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index f9b509a6b09a..5d7d1d3088ae 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -42,7 +42,6 @@ #include <linux/mii.h> #include "../8390.h" -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/ciscode.h> #include <pcmcia/ds.h> @@ -238,14 +237,6 @@ static const struct net_device_ops pcnet_netdev_ops = { #endif }; -/*====================================================================== - - pcnet_attach() creates an "instance" of the driver, allocating - local data structures for one device. The device is registered - with Card Services. - -======================================================================*/ - static int pcnet_probe(struct pcmcia_device *link) { pcnet_dev_t *info; @@ -260,23 +251,13 @@ static int pcnet_probe(struct pcmcia_device *link) info->p_dev = link; link->priv = dev; - link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.IntType = INT_MEMORY_AND_IO; + link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; dev->netdev_ops = &pcnet_netdev_ops; return pcnet_config(link); } /* pcnet_attach */ -/*====================================================================== - - This deletes a driver "instance". The device is de-registered - with Card Services. If it has been released, all local data - structures are freed. Otherwise, the structures will be freed - when the device is released. - -======================================================================*/ - static void pcnet_detach(struct pcmcia_device *link) { struct net_device *dev = link->priv; @@ -300,22 +281,22 @@ static void pcnet_detach(struct pcmcia_device *link) static hw_info_t *get_hwinfo(struct pcmcia_device *link) { struct net_device *dev = link->priv; - win_req_t req; u_char __iomem *base, *virt; int i, j; /* Allocate a small memory window */ - req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; - req.Base = 0; req.Size = 0; - req.AccessSpeed = 0; - i = pcmcia_request_window(link, &req, &link->win); + link->resource[2]->flags |= WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; + link->resource[2]->start = 0; link->resource[2]->end = 0; + i = pcmcia_request_window(link, link->resource[2], 0); if (i != 0) return NULL; - virt = ioremap(req.Base, req.Size); + virt = ioremap(link->resource[2]->start, + resource_size(link->resource[2])); for (i = 0; i < NR_INFO; i++) { - pcmcia_map_mem_page(link, link->win, hw_info[i].offset & ~(req.Size-1)); - base = &virt[hw_info[i].offset & (req.Size-1)]; + pcmcia_map_mem_page(link, link->resource[2], + hw_info[i].offset & ~(resource_size(link->resource[2])-1)); + base = &virt[hw_info[i].offset & (resource_size(link->resource[2])-1)]; if ((readb(base+0) == hw_info[i].a0) && (readb(base+2) == hw_info[i].a1) && (readb(base+4) == hw_info[i].a2)) { @@ -326,7 +307,7 @@ static hw_info_t *get_hwinfo(struct pcmcia_device *link) } iounmap(virt); - j = pcmcia_release_window(link, link->win); + j = pcmcia_release_window(link, link->resource[2]); return (i < NR_INFO) ? hw_info+i : NULL; } /* get_hwinfo */ @@ -421,7 +402,7 @@ static hw_info_t *get_ax88190(struct pcmcia_device *link) int i, j; /* Not much of a test, but the alternatives are messy */ - if (link->conf.ConfigBase != 0x03c0) + if (link->config_base != 0x03c0) return NULL; outb_p(0x01, ioaddr + EN0_DCFG); /* Set word-wide access. */ @@ -463,14 +444,6 @@ static hw_info_t *get_hwired(struct pcmcia_device *link) return &default_info; } /* get_hwired */ -/*====================================================================== - - pcnet_config() is scheduled to run after a CARD_INSERTION event - is received, to configure the PCMCIA socket, and to make the - ethernet device available to the system. - -======================================================================*/ - static int try_io_port(struct pcmcia_device *link) { int j, ret; @@ -502,43 +475,22 @@ static int try_io_port(struct pcmcia_device *link) } } -static int pcnet_confcheck(struct pcmcia_device *p_dev, - cistpl_cftable_entry_t *cfg, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, - void *priv_data) +static int pcnet_confcheck(struct pcmcia_device *p_dev, void *priv_data) { int *priv = priv_data; int try = (*priv & 0x1); - int i; - cistpl_io_t *io = &cfg->io; - if (cfg->index == 0 || cfg->io.nwin == 0) - return -EINVAL; + *priv &= (p_dev->resource[2]->end >= 0x4000) ? 0x10 : ~0x10; - /* For multifunction cards, by convention, we configure the - network function with window 0, and serial with window 1 */ - if (io->nwin > 1) { - i = (io->win[1].len > io->win[0].len); - p_dev->resource[1]->start = io->win[1-i].base; - p_dev->resource[1]->end = io->win[1-i].len; - } else { - i = p_dev->resource[1]->end = 0; - } + if (p_dev->config_index == 0) + return -EINVAL; - *priv &= ((cfg->mem.nwin == 1) && - (cfg->mem.win[0].len >= 0x4000)) ? 0x10 : ~0x10; + if (p_dev->resource[0]->end + p_dev->resource[1]->end < 32) + return -EINVAL; - p_dev->resource[0]->start = io->win[i].base; - p_dev->resource[0]->end = io->win[i].len; - if (!try) - p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK; - else + if (try) p_dev->io_lines = 16; - if (p_dev->resource[0]->end + p_dev->resource[1]->end >= 32) - return try_io_port(p_dev); - - return -EINVAL; + return try_io_port(p_dev); } static hw_info_t *pcnet_try_config(struct pcmcia_device *link, @@ -560,15 +512,14 @@ static hw_info_t *pcnet_try_config(struct pcmcia_device *link, if (!link->irq) return NULL; - if (resource_size(link->resource[1]) == 8) { - link->conf.Attributes |= CONF_ENABLE_SPKR; - link->conf.Status = CCSR_AUDIO_ENA; - } + if (resource_size(link->resource[1]) == 8) + link->config_flags |= CONF_ENABLE_SPKR; + if ((link->manf_id == MANFID_IBM) && (link->card_id == PRODID_IBM_HOME_AND_AWAY)) - link->conf.ConfigIndex |= 0x10; + link->config_index |= 0x10; - ret = pcmcia_request_configuration(link, &link->conf); + ret = pcmcia_enable_device(link); if (ret) return NULL; @@ -583,7 +534,7 @@ static hw_info_t *pcnet_try_config(struct pcmcia_device *link, } else dev->if_port = 0; - if ((link->conf.ConfigBase == 0x03c0) && + if ((link->config_base == 0x03c0) && (link->manf_id == 0x149) && (link->card_id == 0xc1ab)) { dev_info(&link->dev, "this is an AX88190 card - use axnet_cs instead.\n"); @@ -689,14 +640,6 @@ failed: return -ENODEV; } /* pcnet_config */ -/*====================================================================== - - After a card is removed, pcnet_release() will unregister the net - device, and release the PCMCIA configuration. If the device is - still open, this will be postponed until it is closed. - -======================================================================*/ - static void pcnet_release(struct pcmcia_device *link) { pcnet_dev_t *info = PRIV(link->priv); @@ -709,15 +652,6 @@ static void pcnet_release(struct pcmcia_device *link) pcmcia_disable_device(link); } -/*====================================================================== - - The card status event handler. Mostly, this schedules other - stuff to run after an event is received. A CARD_REMOVAL event - also sets some flags to discourage the net drivers from trying - to talk to the card any more. - -======================================================================*/ - static int pcnet_suspend(struct pcmcia_device *link) { struct net_device *dev = link->priv; @@ -1486,7 +1420,6 @@ static int setup_shmem_window(struct pcmcia_device *link, int start_pg, { struct net_device *dev = link->priv; pcnet_dev_t *info = PRIV(dev); - win_req_t req; int i, window_size, offset, ret; window_size = (stop_pg - start_pg) << 8; @@ -1497,22 +1430,22 @@ static int setup_shmem_window(struct pcmcia_device *link, int start_pg, window_size = roundup_pow_of_two(window_size); /* Allocate a memory window */ - req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE; - req.Attributes |= WIN_USE_WAIT; - req.Base = 0; req.Size = window_size; - req.AccessSpeed = mem_speed; - ret = pcmcia_request_window(link, &req, &link->win); + link->resource[3]->flags |= WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE; + link->resource[3]->flags |= WIN_USE_WAIT; + link->resource[3]->start = 0; link->resource[3]->end = window_size; + ret = pcmcia_request_window(link, link->resource[3], mem_speed); if (ret) goto failed; offset = (start_pg << 8) + cm_offset; offset -= offset % window_size; - ret = pcmcia_map_mem_page(link, link->win, offset); + ret = pcmcia_map_mem_page(link, link->resource[3], offset); if (ret) goto failed; /* Try scribbling on the buffer */ - info->base = ioremap(req.Base, window_size); + info->base = ioremap(link->resource[3]->start, + resource_size(link->resource[3])); for (i = 0; i < (TX_PAGES<<8); i += 2) __raw_writew((i>>1), info->base+offset+i); udelay(100); @@ -1521,19 +1454,20 @@ static int setup_shmem_window(struct pcmcia_device *link, int start_pg, pcnet_reset_8390(dev); if (i != (TX_PAGES<<8)) { iounmap(info->base); - pcmcia_release_window(link, link->win); - info->base = NULL; link->win = 0; + pcmcia_release_window(link, link->resource[3]); + info->base = NULL; goto failed; } ei_status.mem = info->base + offset; - ei_status.priv = req.Size; + ei_status.priv = resource_size(link->resource[3]); dev->mem_start = (u_long)ei_status.mem; - dev->mem_end = dev->mem_start + req.Size; + dev->mem_end = dev->mem_start + resource_size(link->resource[3]); ei_status.tx_start_page = start_pg; ei_status.rx_start_page = start_pg + TX_PAGES; - ei_status.stop_page = start_pg + ((req.Size - offset) >> 8); + ei_status.stop_page = start_pg + ( + (resource_size(link->resource[3]) - offset) >> 8); /* set up block i/o functions */ ei_status.get_8390_hdr = &shmem_get_8390_hdr; @@ -1772,9 +1706,7 @@ MODULE_FIRMWARE("cis/PE-200.cis"); MODULE_FIRMWARE("cis/tamarack.cis"); static struct pcmcia_driver pcnet_driver = { - .drv = { - .name = "pcnet_cs", - }, + .name = "pcnet_cs", .probe = pcnet_probe, .remove = pcnet_detach, .owner = THIS_MODULE, diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index 377367d03b41..0af2fc8ec164 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -44,7 +44,6 @@ #include <linux/jiffies.h> #include <linux/firmware.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/cisreg.h> #include <pcmcia/ciscode.h> @@ -300,14 +299,6 @@ static const struct net_device_ops smc_netdev_ops = { .ndo_validate_addr = eth_validate_addr, }; -/*====================================================================== - - smc91c92_attach() creates an "instance" of the driver, allocating - local data structures for one device. The device is registered - with Card Services. - -======================================================================*/ - static int smc91c92_probe(struct pcmcia_device *link) { struct smc_private *smc; @@ -324,10 +315,6 @@ static int smc91c92_probe(struct pcmcia_device *link) link->priv = dev; spin_lock_init(&smc->lock); - link->resource[0]->end = 16; - link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; - link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.IntType = INT_MEMORY_AND_IO; /* The SMC91c92-specific entries in the device structure. */ dev->netdev_ops = &smc_netdev_ops; @@ -343,15 +330,6 @@ static int smc91c92_probe(struct pcmcia_device *link) return smc91c92_config(link); } /* smc91c92_attach */ -/*====================================================================== - - This deletes a driver "instance". The device is de-registered - with Card Services. If it has been released, all local data - structures are freed. Otherwise, the structures will be freed - when the device is released. - -======================================================================*/ - static void smc91c92_detach(struct pcmcia_device *link) { struct net_device *dev = link->priv; @@ -412,26 +390,28 @@ static int mhz_3288_power(struct pcmcia_device *link) mdelay(200); /* Now read and write the COR... */ - tmp = readb(smc->base + link->conf.ConfigBase + CISREG_COR); + tmp = readb(smc->base + link->config_base + CISREG_COR); udelay(5); - writeb(tmp, smc->base + link->conf.ConfigBase + CISREG_COR); + writeb(tmp, smc->base + link->config_base + CISREG_COR); return 0; } -static int mhz_mfc_config_check(struct pcmcia_device *p_dev, - cistpl_cftable_entry_t *cf, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, - void *priv_data) +static int mhz_mfc_config_check(struct pcmcia_device *p_dev, void *priv_data) { int k; - p_dev->resource[1]->start = cf->io.win[0].base; + p_dev->io_lines = 16; + p_dev->resource[1]->start = p_dev->resource[0]->start; + p_dev->resource[1]->end = 8; + p_dev->resource[1]->flags &= ~IO_DATA_PATH_WIDTH; + p_dev->resource[1]->flags |= IO_DATA_PATH_WIDTH_8; + p_dev->resource[0]->end = 16; + p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; + p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; for (k = 0; k < 0x400; k += 0x10) { if (k & 0x80) continue; p_dev->resource[0]->start = k ^ 0x300; - p_dev->io_lines = 16; if (!pcmcia_request_io(p_dev)) return 0; } @@ -442,14 +422,11 @@ static int mhz_mfc_config(struct pcmcia_device *link) { struct net_device *dev = link->priv; struct smc_private *smc = netdev_priv(dev); - win_req_t req; unsigned int offset; int i; - link->conf.Attributes |= CONF_ENABLE_SPKR; - link->conf.Status = CCSR_AUDIO_ENA; - link->resource[1]->flags |= IO_DATA_PATH_WIDTH_8; - link->resource[1]->end = 8; + link->config_flags |= CONF_ENABLE_SPKR | CONF_ENABLE_IRQ | + CONF_AUTO_SET_IO; /* The Megahertz combo cards have modem-like CIS entries, so we have to explicitly try a bunch of port combinations. */ @@ -459,16 +436,16 @@ static int mhz_mfc_config(struct pcmcia_device *link) dev->base_addr = link->resource[0]->start; /* Allocate a memory window, for accessing the ISR */ - req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; - req.Base = req.Size = 0; - req.AccessSpeed = 0; - i = pcmcia_request_window(link, &req, &link->win); + link->resource[2]->flags = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; + link->resource[2]->start = link->resource[2]->end = 0; + i = pcmcia_request_window(link, link->resource[2], 0); if (i != 0) return -ENODEV; - smc->base = ioremap(req.Base, req.Size); - offset = (smc->manfid == MANFID_MOTOROLA) ? link->conf.ConfigBase : 0; - i = pcmcia_map_mem_page(link, link->win, offset); + smc->base = ioremap(link->resource[2]->start, + resource_size(link->resource[2])); + offset = (smc->manfid == MANFID_MOTOROLA) ? link->config_base : 0; + i = pcmcia_map_mem_page(link, link->resource[2], offset); if ((i == 0) && (smc->manfid == MANFID_MEGAHERTZ) && (smc->cardid == PRODID_MEGAHERTZ_EM3288)) @@ -591,14 +568,12 @@ static int mot_setup(struct pcmcia_device *link) /*====================================================================*/ -static int smc_configcheck(struct pcmcia_device *p_dev, - cistpl_cftable_entry_t *cf, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, - void *priv_data) +static int smc_configcheck(struct pcmcia_device *p_dev, void *priv_data) { - p_dev->resource[0]->start = cf->io.win[0].base; - p_dev->io_lines = cf->io.flags & CISTPL_IO_LINES_MASK; + p_dev->resource[0]->end = 16; + p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; + p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; + return pcmcia_request_io(p_dev); } @@ -607,7 +582,8 @@ static int smc_config(struct pcmcia_device *link) struct net_device *dev = link->priv; int i; - link->resource[0]->end = 16; + link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; + i = pcmcia_loop_config(link, smc_configcheck, NULL); if (!i) dev->base_addr = link->resource[0]->start; @@ -640,15 +616,14 @@ static int osi_config(struct pcmcia_device *link) static const unsigned int com[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 }; int i, j; - link->conf.Attributes |= CONF_ENABLE_SPKR; - link->conf.Status = CCSR_AUDIO_ENA; + link->config_flags |= CONF_ENABLE_SPKR | CONF_ENABLE_IRQ; link->resource[0]->end = 64; link->resource[1]->flags |= IO_DATA_PATH_WIDTH_8; link->resource[1]->end = 8; /* Enable Hard Decode, LAN, Modem */ - link->conf.ConfigIndex = 0x23; link->io_lines = 16; + link->config_index = 0x23; for (i = j = 0; j < 4; j++) { link->resource[1]->start = com[j]; @@ -658,7 +633,7 @@ static int osi_config(struct pcmcia_device *link) } if (i != 0) { /* Fallback: turn off hard decode */ - link->conf.ConfigIndex = 0x03; + link->config_index = 0x03; link->resource[1]->end = 0; i = pcmcia_request_io(link); } @@ -817,27 +792,16 @@ static int check_sig(struct pcmcia_device *link) } if (width) { - modconf_t mod = { - .Attributes = CONF_IO_CHANGE_WIDTH, - }; printk(KERN_INFO "smc91c92_cs: using 8-bit IO window.\n"); smc91c92_suspend(link); - pcmcia_modify_configuration(link, &mod); + pcmcia_fixup_iowidth(link); smc91c92_resume(link); return check_sig(link); } return -ENODEV; } -/*====================================================================== - - smc91c92_config() is scheduled to run after a CARD_INSERTION event - is received, to configure the PCMCIA socket, and to make the - ethernet device available to the system. - -======================================================================*/ - static int smc91c92_config(struct pcmcia_device *link) { struct net_device *dev = link->priv; @@ -869,7 +833,7 @@ static int smc91c92_config(struct pcmcia_device *link) i = pcmcia_request_irq(link, smc_interrupt); if (i) goto config_failed; - i = pcmcia_request_configuration(link, &link->conf); + i = pcmcia_enable_device(link); if (i) goto config_failed; @@ -988,18 +952,10 @@ config_failed: return -ENODEV; } /* smc91c92_config */ -/*====================================================================== - - After a card is removed, smc91c92_release() will unregister the net - device, and release the PCMCIA configuration. If the device is - still open, this will be postponed until it is closed. - -======================================================================*/ - static void smc91c92_release(struct pcmcia_device *link) { dev_dbg(&link->dev, "smc91c92_release\n"); - if (link->win) { + if (link->resource[2]->end) { struct net_device *dev = link->priv; struct smc_private *smc = netdev_priv(dev); iounmap(smc->base); @@ -2101,9 +2057,7 @@ MODULE_DEVICE_TABLE(pcmcia, smc91c92_ids); static struct pcmcia_driver smc91c92_cs_driver = { .owner = THIS_MODULE, - .drv = { - .name = "smc91c92_cs", - }, + .name = "smc91c92_cs", .probe = smc91c92_probe, .remove = smc91c92_detach, .id_table = smc91c92_ids, diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index f5819526b5ee..1fece617c069 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c @@ -82,7 +82,6 @@ #include <linux/bitops.h> #include <linux/mii.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/cisreg.h> #include <pcmcia/ciscode.h> @@ -267,33 +266,11 @@ static unsigned mii_rd(unsigned int ioaddr, u_char phyaddr, u_char phyreg); static void mii_wr(unsigned int ioaddr, u_char phyaddr, u_char phyreg, unsigned data, int len); -/* - * The event() function is this driver's Card Services event handler. - * It will be called by Card Services when an appropriate card status - * event is received. The config() and release() entry points are - * used to configure or release a socket, in response to card insertion - * and ejection events. They are invoked from the event handler. - */ - static int has_ce2_string(struct pcmcia_device * link); static int xirc2ps_config(struct pcmcia_device * link); static void xirc2ps_release(struct pcmcia_device * link); - -/**************** - * The attach() and detach() entry points are used to create and destroy - * "instances" of the driver, where each instance represents everything - * needed to manage one actual PCMCIA card. - */ - static void xirc2ps_detach(struct pcmcia_device *p_dev); -/**************** - * You'll also need to prototype all the functions that will actually - * be used to talk to your device. See 'pcmem_cs' for a good example - * of a fully self-sufficient driver; the other drivers rely more or - * less on other parts of the kernel. - */ - static irqreturn_t xirc2ps_interrupt(int irq, void *dev_id); typedef struct local_info_t { @@ -501,16 +478,6 @@ static const struct net_device_ops netdev_ops = { .ndo_validate_addr = eth_validate_addr, }; -/**************** - * xirc2ps_attach() creates an "instance" of the driver, allocating - * local data structures for one device. The device is registered - * with Card Services. - * - * The dev_link structure is initialized, but we don't actually - * configure the card at this point -- we wait until we receive a - * card insertion event. - */ - static int xirc2ps_probe(struct pcmcia_device *link) { @@ -529,9 +496,7 @@ xirc2ps_probe(struct pcmcia_device *link) link->priv = dev; /* General socket configuration */ - link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.IntType = INT_MEMORY_AND_IO; - link->conf.ConfigIndex = 1; + link->config_index = 1; /* Fill in card specific entries */ dev->netdev_ops = &netdev_ops; @@ -542,13 +507,6 @@ xirc2ps_probe(struct pcmcia_device *link) return xirc2ps_config(link); } /* xirc2ps_attach */ -/**************** - * This deletes a driver "instance". The device is de-registered - * with Card Services. If it has been released, all local data - * structures are freed. Otherwise, the structures will be freed - * when the device is released. - */ - static void xirc2ps_detach(struct pcmcia_device *link) { @@ -667,44 +625,53 @@ has_ce2_string(struct pcmcia_device * p_dev) } static int -xirc2ps_config_modem(struct pcmcia_device *p_dev, - cistpl_cftable_entry_t *cf, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, - void *priv_data) +xirc2ps_config_modem(struct pcmcia_device *p_dev, void *priv_data) { unsigned int ioaddr; - if (cf->io.nwin > 0 && (cf->io.win[0].base & 0xf) == 8) { - for (ioaddr = 0x300; ioaddr < 0x400; ioaddr += 0x10) { - p_dev->resource[1]->start = cf->io.win[0].base; - p_dev->resource[0]->start = ioaddr; - if (!pcmcia_request_io(p_dev)) - return 0; - } + if ((p_dev->resource[0]->start & 0xf) == 8) + return -ENODEV; + + p_dev->resource[0]->end = 16; + p_dev->resource[1]->end = 8; + p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; + p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_16; + p_dev->resource[1]->flags &= ~IO_DATA_PATH_WIDTH; + p_dev->resource[1]->flags |= IO_DATA_PATH_WIDTH_8; + p_dev->io_lines = 10; + + p_dev->resource[1]->start = p_dev->resource[0]->start; + for (ioaddr = 0x300; ioaddr < 0x400; ioaddr += 0x10) { + p_dev->resource[0]->start = ioaddr; + if (!pcmcia_request_io(p_dev)) + return 0; } return -ENODEV; } static int -xirc2ps_config_check(struct pcmcia_device *p_dev, - cistpl_cftable_entry_t *cf, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, - void *priv_data) +xirc2ps_config_check(struct pcmcia_device *p_dev, void *priv_data) { int *pass = priv_data; + resource_size_t tmp = p_dev->resource[1]->start; - if (cf->io.nwin > 0 && (cf->io.win[0].base & 0xf) == 8) { - p_dev->resource[1]->start = cf->io.win[0].base; - p_dev->resource[0]->start = p_dev->resource[1]->start - + (*pass ? (cf->index & 0x20 ? -24:8) - : (cf->index & 0x20 ? 8:-24)); - if (!pcmcia_request_io(p_dev)) - return 0; - } - return -ENODEV; + tmp += (*pass ? (p_dev->config_index & 0x20 ? -24 : 8) + : (p_dev->config_index & 0x20 ? 8 : -24)); + + if ((p_dev->resource[0]->start & 0xf) == 8) + return -ENODEV; + + p_dev->resource[0]->end = 18; + p_dev->resource[1]->end = 8; + p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; + p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_16; + p_dev->resource[1]->flags &= ~IO_DATA_PATH_WIDTH; + p_dev->resource[1]->flags |= IO_DATA_PATH_WIDTH_8; + p_dev->io_lines = 10; + p_dev->resource[1]->start = p_dev->resource[0]->start; + p_dev->resource[0]->start = tmp; + return pcmcia_request_io(p_dev); } @@ -727,11 +694,6 @@ static int pcmcia_get_mac_ce(struct pcmcia_device *p_dev, }; -/**************** - * xirc2ps_config() is scheduled to run after a CARD_INSERTION event - * is received, to configure the PCMCIA socket, and to make the - * ethernet device available to the system. - */ static int xirc2ps_config(struct pcmcia_device * link) { @@ -807,32 +769,24 @@ xirc2ps_config(struct pcmcia_device * link) goto failure; } - link->resource[0]->flags |= IO_DATA_PATH_WIDTH_16; - link->io_lines = 10; if (local->modem) { int pass; + link->config_flags |= CONF_AUTO_SET_IO; - if (do_sound) { - link->conf.Attributes |= CONF_ENABLE_SPKR; - link->conf.Status |= CCSR_AUDIO_ENA; - } - link->resource[1]->end = 8; - link->resource[1]->flags |= IO_DATA_PATH_WIDTH_8; if (local->dingo) { /* Take the Modem IO port from the CIS and scan for a free * Ethernet port */ - link->resource[0]->end = 16; /* no Mako stuff anymore */ if (!pcmcia_loop_config(link, xirc2ps_config_modem, NULL)) goto port_found; } else { - link->resource[0]->end = 18; /* We do 2 passes here: The first one uses the regular mapping and * the second tries again, thereby considering that the 32 ports are * mirrored every 32 bytes. Actually we use a mirrored port for * the Mako if (on the first pass) the COR bit 5 is set. */ for (pass=0; pass < 2; pass++) - if (!pcmcia_loop_config(link, xirc2ps_config_check, &pass)) + if (!pcmcia_loop_config(link, xirc2ps_config_check, + &pass)) goto port_found; /* if special option: * try to configure as Ethernet only. @@ -840,7 +794,9 @@ xirc2ps_config(struct pcmcia_device * link) } printk(KNOT_XIRC "no ports available\n"); } else { + link->io_lines = 10; link->resource[0]->end = 16; + link->resource[0]->flags |= IO_DATA_PATH_WIDTH_16; for (ioaddr = 0x300; ioaddr < 0x400; ioaddr += 0x10) { link->resource[0]->start = ioaddr; if (!(err = pcmcia_request_io(link))) @@ -861,16 +817,14 @@ xirc2ps_config(struct pcmcia_device * link) if ((err=pcmcia_request_irq(link, xirc2ps_interrupt))) goto config_error; - /**************** - * This actually configures the PCMCIA socket -- setting up - * the I/O windows and the interrupt mapping. - */ - if ((err=pcmcia_request_configuration(link, &link->conf))) + link->config_flags |= CONF_ENABLE_IRQ; + if (do_sound) + link->config_flags |= CONF_ENABLE_SPKR; + + if ((err = pcmcia_enable_device(link))) goto config_error; if (local->dingo) { - win_req_t req; - /* Reset the modem's BAR to the correct value * This is necessary because in the RequestConfiguration call, * the base address of the ethernet port (BasePort1) is written @@ -890,14 +844,14 @@ xirc2ps_config(struct pcmcia_device * link) * is at 0x0800. So we allocate a window into the attribute * memory and write direct to the CIS registers */ - req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; - req.Base = req.Size = 0; - req.AccessSpeed = 0; - if ((err = pcmcia_request_window(link, &req, &link->win))) + link->resource[2]->flags = WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_AM | + WIN_ENABLE; + link->resource[2]->start = link->resource[2]->end = 0; + if ((err = pcmcia_request_window(link, link->resource[2], 0))) goto config_error; - local->dingo_ccr = ioremap(req.Base,0x1000) + 0x0800; - if ((err = pcmcia_map_mem_page(link, link->win, 0))) + local->dingo_ccr = ioremap(link->resource[2]->start, 0x1000) + 0x0800; + if ((err = pcmcia_map_mem_page(link, link->resource[2], 0))) goto config_error; /* Setup the CCRs; there are no infos in the CIS about the Ethernet @@ -978,17 +932,12 @@ xirc2ps_config(struct pcmcia_device * link) return -ENODEV; } /* xirc2ps_config */ -/**************** - * After a card is removed, xirc2ps_release() will unregister the net - * device, and release the PCMCIA configuration. If the device is - * still open, this will be postponed until it is closed. - */ static void xirc2ps_release(struct pcmcia_device *link) { dev_dbg(&link->dev, "release\n"); - if (link->win) { + if (link->resource[2]->end) { struct net_device *dev = link->priv; local_info_t *local = netdev_priv(dev); if (local->dingo) @@ -1830,9 +1779,7 @@ MODULE_DEVICE_TABLE(pcmcia, xirc2ps_ids); static struct pcmcia_driver xirc2ps_cs_driver = { .owner = THIS_MODULE, - .drv = { - .name = "xirc2ps_cs", - }, + .name = "xirc2ps_cs", .probe = xirc2ps_probe, .remove = xirc2ps_detach, .id_table = xirc2ps_ids, diff --git a/drivers/net/ppp_async.c b/drivers/net/ppp_async.c index af50a530daee..78d70a6481bf 100644 --- a/drivers/net/ppp_async.c +++ b/drivers/net/ppp_async.c @@ -184,7 +184,7 @@ ppp_asynctty_open(struct tty_struct *tty) tasklet_init(&ap->tsk, ppp_async_process, (unsigned long) ap); atomic_set(&ap->refcnt, 1); - init_MUTEX_LOCKED(&ap->dead_sem); + sema_init(&ap->dead_sem, 0); ap->chan.private = ap; ap->chan.ops = &async_ops; diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index 736b91703b3e..4bddb2afdd15 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -856,7 +856,8 @@ static const struct file_operations ppp_device_fops = { .poll = ppp_poll, .unlocked_ioctl = ppp_ioctl, .open = ppp_open, - .release = ppp_release + .release = ppp_release, + .llseek = noop_llseek, }; static __net_init int ppp_init_net(struct net *net) diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index 10cf0cbc2185..726df611ee17 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c @@ -72,6 +72,7 @@ static const char version[] = #include <linux/sched.h> #include <linux/delay.h> #include <linux/interrupt.h> +#include <linux/irq.h> #include <linux/errno.h> #include <linux/ioport.h> #include <linux/crc32.h> diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c index 04c6cd4333f1..10bafd59f9c3 100644 --- a/drivers/net/wan/cosa.c +++ b/drivers/net/wan/cosa.c @@ -575,7 +575,7 @@ static int cosa_probe(int base, int irq, int dma) /* Initialize the chardev data structures */ mutex_init(&chan->rlock); - init_MUTEX(&chan->wsem); + sema_init(&chan->wsem, 1); /* Register the network interface */ if (!(chan->netdev = alloc_hdlcdev(chan))) { diff --git a/drivers/net/wimax/i2400m/debugfs.c b/drivers/net/wimax/i2400m/debugfs.c index b1aec3e1892f..9c70b5fa3f51 100644 --- a/drivers/net/wimax/i2400m/debugfs.c +++ b/drivers/net/wimax/i2400m/debugfs.c @@ -119,6 +119,7 @@ const struct file_operations i2400m_rx_stats_fops = { .open = i2400m_stats_open, .read = i2400m_rx_stats_read, .write = i2400m_rx_stats_write, + .llseek = default_llseek, }; @@ -171,6 +172,7 @@ const struct file_operations i2400m_tx_stats_fops = { .open = i2400m_stats_open, .read = i2400m_tx_stats_read, .write = i2400m_tx_stats_write, + .llseek = default_llseek, }; diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 1d05445d4ba3..ce77575e88b3 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -4430,21 +4430,24 @@ static const struct file_operations proc_statsdelta_ops = { .owner = THIS_MODULE, .read = proc_read, .open = proc_statsdelta_open, - .release = proc_close + .release = proc_close, + .llseek = default_llseek, }; static const struct file_operations proc_stats_ops = { .owner = THIS_MODULE, .read = proc_read, .open = proc_stats_open, - .release = proc_close + .release = proc_close, + .llseek = default_llseek, }; static const struct file_operations proc_status_ops = { .owner = THIS_MODULE, .read = proc_read, .open = proc_status_open, - .release = proc_close + .release = proc_close, + .llseek = default_llseek, }; static const struct file_operations proc_SSID_ops = { @@ -4452,7 +4455,8 @@ static const struct file_operations proc_SSID_ops = { .read = proc_read, .write = proc_write, .open = proc_SSID_open, - .release = proc_close + .release = proc_close, + .llseek = default_llseek, }; static const struct file_operations proc_BSSList_ops = { @@ -4460,7 +4464,8 @@ static const struct file_operations proc_BSSList_ops = { .read = proc_read, .write = proc_write, .open = proc_BSSList_open, - .release = proc_close + .release = proc_close, + .llseek = default_llseek, }; static const struct file_operations proc_APList_ops = { @@ -4468,7 +4473,8 @@ static const struct file_operations proc_APList_ops = { .read = proc_read, .write = proc_write, .open = proc_APList_open, - .release = proc_close + .release = proc_close, + .llseek = default_llseek, }; static const struct file_operations proc_config_ops = { @@ -4476,7 +4482,8 @@ static const struct file_operations proc_config_ops = { .read = proc_read, .write = proc_write, .open = proc_config_open, - .release = proc_close + .release = proc_close, + .llseek = default_llseek, }; static const struct file_operations proc_wepkey_ops = { @@ -4484,7 +4491,8 @@ static const struct file_operations proc_wepkey_ops = { .read = proc_read, .write = proc_write, .open = proc_wepkey_open, - .release = proc_close + .release = proc_close, + .llseek = default_llseek, }; static struct proc_dir_entry *airo_entry; diff --git a/drivers/net/wireless/airo_cs.c b/drivers/net/wireless/airo_cs.c index 9a121a5b787c..df2484d45474 100644 --- a/drivers/net/wireless/airo_cs.c +++ b/drivers/net/wireless/airo_cs.c @@ -32,7 +32,6 @@ #include <linux/timer.h> #include <linux/netdevice.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/cisreg.h> #include <pcmcia/ds.h> @@ -54,58 +53,21 @@ MODULE_SUPPORTED_DEVICE("Aironet 4500, 4800 and Cisco 340 PCMCIA cards"); /*====================================================================*/ -/* - The event() function is this driver's Card Services event handler. - It will be called by Card Services when an appropriate card status - event is received. The config() and release() entry points are - used to configure or release a socket, in response to card - insertion and ejection events. They are invoked from the airo_cs - event handler. -*/ - static int airo_config(struct pcmcia_device *link); static void airo_release(struct pcmcia_device *link); -/* - The attach() and detach() entry points are used to create and destroy - "instances" of the driver, where each instance represents everything - needed to manage one actual PCMCIA card. -*/ - static void airo_detach(struct pcmcia_device *p_dev); typedef struct local_info_t { struct net_device *eth_dev; } local_info_t; -/*====================================================================== - - airo_attach() creates an "instance" of the driver, allocating - local data structures for one device. The device is registered - with Card Services. - - The dev_link structure is initialized, but we don't actually - configure the card at this point -- we wait until we receive a - card insertion event. - - ======================================================================*/ - static int airo_probe(struct pcmcia_device *p_dev) { local_info_t *local; dev_dbg(&p_dev->dev, "airo_attach()\n"); - /* - General socket configuration defaults can go here. In this - client, we assume very little, and rely on the CIS for almost - everything. In most clients, many details (i.e., number, sizes, - and attributes of IO windows) are fixed by the nature of the - device, and can be hard-wired here. - */ - p_dev->conf.Attributes = 0; - p_dev->conf.IntType = INT_MEMORY_AND_IO; - /* Allocate space for private device-specific data */ local = kzalloc(sizeof(local_info_t), GFP_KERNEL); if (!local) { @@ -117,15 +79,6 @@ static int airo_probe(struct pcmcia_device *p_dev) return airo_config(p_dev); } /* airo_attach */ -/*====================================================================== - - This deletes a driver "instance". The device is de-registered - with Card Services. If it has been released, all local data - structures are freed. Otherwise, the structures will be freed - when the device is released. - - ======================================================================*/ - static void airo_detach(struct pcmcia_device *link) { dev_dbg(&link->dev, "airo_detach\n"); @@ -140,60 +93,12 @@ static void airo_detach(struct pcmcia_device *link) kfree(link->priv); } /* airo_detach */ -/*====================================================================== - - airo_config() is scheduled to run after a CARD_INSERTION event - is received, to configure the PCMCIA socket, and to make the - device available to the system. - - ======================================================================*/ - -static int airo_cs_config_check(struct pcmcia_device *p_dev, - cistpl_cftable_entry_t *cfg, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, - void *priv_data) +static int airo_cs_config_check(struct pcmcia_device *p_dev, void *priv_data) { - if (cfg->index == 0) - return -ENODEV; - - /* Does this card need audio output? */ - if (cfg->flags & CISTPL_CFTABLE_AUDIO) { - p_dev->conf.Attributes |= CONF_ENABLE_SPKR; - p_dev->conf.Status = CCSR_AUDIO_ENA; - } - - /* Use power settings for Vcc and Vpp if present */ - /* Note that the CIS values need to be rescaled */ - if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM)) - p_dev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM]/10000; - else if (dflt->vpp1.present & (1<<CISTPL_POWER_VNOM)) - p_dev->conf.Vpp = dflt->vpp1.param[CISTPL_POWER_VNOM]/10000; - - p_dev->conf.Attributes |= CONF_ENABLE_IRQ; - - /* IO window settings */ - p_dev->resource[0]->end = p_dev->resource[1]->end = 0; - if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) { - cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io; - p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; - p_dev->resource[0]->flags |= - pcmcia_io_cfg_data_width(io->flags); - p_dev->resource[0]->start = io->win[0].base; - p_dev->resource[0]->end = io->win[0].len; - if (io->nwin > 1) { - p_dev->resource[1]->flags = p_dev->resource[0]->flags; - p_dev->resource[1]->start = io->win[1].base; - p_dev->resource[1]->end = io->win[1].len; - } - } + if (p_dev->config_index == 0) + return -EINVAL; - /* This reserves IO space but doesn't actually enable it */ - if (pcmcia_request_io(p_dev) != 0) - return -ENODEV; - - /* If we got this far, we're cool! */ - return 0; + return pcmcia_request_io(p_dev); } @@ -206,20 +111,9 @@ static int airo_config(struct pcmcia_device *link) dev_dbg(&link->dev, "airo_config\n"); - /* - * In this loop, we scan the CIS for configuration table - * entries, each of which describes a valid card - * configuration, including voltage, IO window, memory window, - * and interrupt settings. - * - * We make no assumptions about the card to be configured: we - * use just the information available in the CIS. In an ideal - * world, this would work for any PCMCIA card, but it requires - * a complete and accurate CIS. In practice, a driver usually - * "knows" most of these things without consulting the CIS, - * and most client drivers will only use the CIS to fill in - * implementation-defined details. - */ + link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_VPP | + CONF_AUTO_AUDIO | CONF_AUTO_SET_IO; + ret = pcmcia_loop_config(link, airo_cs_config_check, NULL); if (ret) goto failed; @@ -227,12 +121,7 @@ static int airo_config(struct pcmcia_device *link) if (!link->irq) goto failed; - /* - This actually configures the PCMCIA socket -- setting up - the I/O windows and the interrupt mapping, and putting the - card and host interface into "Memory and IO" mode. - */ - ret = pcmcia_request_configuration(link, &link->conf); + ret = pcmcia_enable_device(link); if (ret) goto failed; ((local_info_t *)link->priv)->eth_dev = @@ -241,17 +130,6 @@ static int airo_config(struct pcmcia_device *link) if (!((local_info_t *)link->priv)->eth_dev) goto failed; - /* Finally, report what we've done */ - dev_info(&link->dev, "index 0x%02x: ", - link->conf.ConfigIndex); - if (link->conf.Vpp) - printk(", Vpp %d.%d", link->conf.Vpp/10, link->conf.Vpp%10); - printk(", irq %d", link->irq); - if (link->resource[0]) - printk(" & %pR", link->resource[0]); - if (link->resource[1]) - printk(" & %pR", link->resource[1]); - printk("\n"); return 0; failed: @@ -259,14 +137,6 @@ static int airo_config(struct pcmcia_device *link) return -ENODEV; } /* airo_config */ -/*====================================================================== - - After a card is removed, airo_release() will unregister the - device, and release the PCMCIA configuration. If the device is - still open, this will be postponed until it is closed. - - ======================================================================*/ - static void airo_release(struct pcmcia_device *link) { dev_dbg(&link->dev, "airo_release\n"); @@ -305,9 +175,7 @@ MODULE_DEVICE_TABLE(pcmcia, airo_ids); static struct pcmcia_driver airo_driver = { .owner = THIS_MODULE, - .drv = { - .name = "airo_cs", - }, + .name = "airo_cs", .probe = airo_probe, .remove = airo_detach, .id_table = airo_ids, @@ -315,12 +183,12 @@ static struct pcmcia_driver airo_driver = { .resume = airo_resume, }; -static int airo_cs_init(void) +static int __init airo_cs_init(void) { return pcmcia_register_driver(&airo_driver); } -static void airo_cs_cleanup(void) +static void __exit airo_cs_cleanup(void) { pcmcia_unregister_driver(&airo_driver); } diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c index 4cccc29964f6..fb339c3852ee 100644 --- a/drivers/net/wireless/ath/ath5k/debug.c +++ b/drivers/net/wireless/ath/ath5k/debug.c @@ -271,6 +271,7 @@ static const struct file_operations fops_beacon = { .write = write_file_beacon, .open = ath5k_debugfs_open, .owner = THIS_MODULE, + .llseek = default_llseek, }; @@ -290,6 +291,7 @@ static const struct file_operations fops_reset = { .write = write_file_reset, .open = ath5k_debugfs_open, .owner = THIS_MODULE, + .llseek = noop_llseek, }; @@ -369,6 +371,7 @@ static const struct file_operations fops_debug = { .write = write_file_debug, .open = ath5k_debugfs_open, .owner = THIS_MODULE, + .llseek = default_llseek, }; @@ -480,6 +483,7 @@ static const struct file_operations fops_antenna = { .write = write_file_antenna, .open = ath5k_debugfs_open, .owner = THIS_MODULE, + .llseek = default_llseek, }; @@ -591,6 +595,7 @@ static const struct file_operations fops_frameerrors = { .write = write_file_frameerrors, .open = ath5k_debugfs_open, .owner = THIS_MODULE, + .llseek = default_llseek, }; @@ -748,6 +753,7 @@ static const struct file_operations fops_ani = { .write = write_file_ani, .open = ath5k_debugfs_open, .owner = THIS_MODULE, + .llseek = default_llseek, }; @@ -811,6 +817,7 @@ static const struct file_operations fops_queue = { .write = write_file_queue, .open = ath5k_debugfs_open, .owner = THIS_MODULE, + .llseek = default_llseek, }; diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 54aae931424e..cf500bf25ad5 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -71,7 +71,8 @@ static const struct file_operations fops_debug = { .read = read_file_debug, .write = write_file_debug, .open = ath9k_debugfs_open, - .owner = THIS_MODULE + .owner = THIS_MODULE, + .llseek = default_llseek, }; #endif @@ -116,7 +117,8 @@ static const struct file_operations fops_tx_chainmask = { .read = read_file_tx_chainmask, .write = write_file_tx_chainmask, .open = ath9k_debugfs_open, - .owner = THIS_MODULE + .owner = THIS_MODULE, + .llseek = default_llseek, }; @@ -158,7 +160,8 @@ static const struct file_operations fops_rx_chainmask = { .read = read_file_rx_chainmask, .write = write_file_rx_chainmask, .open = ath9k_debugfs_open, - .owner = THIS_MODULE + .owner = THIS_MODULE, + .llseek = default_llseek, }; @@ -259,7 +262,8 @@ static ssize_t read_file_dma(struct file *file, char __user *user_buf, static const struct file_operations fops_dma = { .read = read_file_dma, .open = ath9k_debugfs_open, - .owner = THIS_MODULE + .owner = THIS_MODULE, + .llseek = default_llseek, }; @@ -375,7 +379,8 @@ static ssize_t read_file_interrupt(struct file *file, char __user *user_buf, static const struct file_operations fops_interrupt = { .read = read_file_interrupt, .open = ath9k_debugfs_open, - .owner = THIS_MODULE + .owner = THIS_MODULE, + .llseek = default_llseek, }; void ath_debug_stat_rc(struct ath_softc *sc, int final_rate) @@ -464,7 +469,8 @@ static ssize_t read_file_rcstat(struct file *file, char __user *user_buf, static const struct file_operations fops_rcstat = { .read = read_file_rcstat, .open = ath9k_debugfs_open, - .owner = THIS_MODULE + .owner = THIS_MODULE, + .llseek = default_llseek, }; static const char * ath_wiphy_state_str(enum ath_wiphy_state state) @@ -623,7 +629,8 @@ static const struct file_operations fops_wiphy = { .read = read_file_wiphy, .write = write_file_wiphy, .open = ath9k_debugfs_open, - .owner = THIS_MODULE + .owner = THIS_MODULE, + .llseek = default_llseek, }; #define PR(str, elem) \ @@ -702,7 +709,8 @@ void ath_debug_stat_tx(struct ath_softc *sc, struct ath_txq *txq, static const struct file_operations fops_xmit = { .read = read_file_xmit, .open = ath9k_debugfs_open, - .owner = THIS_MODULE + .owner = THIS_MODULE, + .llseek = default_llseek, }; static ssize_t read_file_recv(struct file *file, char __user *user_buf, @@ -814,7 +822,8 @@ void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs) static const struct file_operations fops_recv = { .read = read_file_recv, .open = ath9k_debugfs_open, - .owner = THIS_MODULE + .owner = THIS_MODULE, + .llseek = default_llseek, }; static ssize_t read_file_regidx(struct file *file, char __user *user_buf, @@ -852,7 +861,8 @@ static const struct file_operations fops_regidx = { .read = read_file_regidx, .write = write_file_regidx, .open = ath9k_debugfs_open, - .owner = THIS_MODULE + .owner = THIS_MODULE, + .llseek = default_llseek, }; static ssize_t read_file_regval(struct file *file, char __user *user_buf, @@ -894,7 +904,8 @@ static const struct file_operations fops_regval = { .read = read_file_regval, .write = write_file_regval, .open = ath9k_debugfs_open, - .owner = THIS_MODULE + .owner = THIS_MODULE, + .llseek = default_llseek, }; int ath9k_init_debug(struct ath_hw *ah) diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 7d09b4b17bbd..bc2ca7d898e9 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -536,7 +536,8 @@ static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf, static const struct file_operations fops_tgt_stats = { .read = read_file_tgt_stats, .open = ath9k_debugfs_open, - .owner = THIS_MODULE + .owner = THIS_MODULE, + .llseek = default_llseek, }; static ssize_t read_file_xmit(struct file *file, char __user *user_buf, @@ -584,7 +585,8 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf, static const struct file_operations fops_xmit = { .read = read_file_xmit, .open = ath9k_debugfs_open, - .owner = THIS_MODULE + .owner = THIS_MODULE, + .llseek = default_llseek, }; static ssize_t read_file_recv(struct file *file, char __user *user_buf, @@ -613,7 +615,8 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf, static const struct file_operations fops_recv = { .read = read_file_recv, .open = ath9k_debugfs_open, - .owner = THIS_MODULE + .owner = THIS_MODULE, + .llseek = default_llseek, }; int ath9k_htc_init_debug(struct ath_hw *ah) diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c index 3b632161c106..c96e19da2949 100644 --- a/drivers/net/wireless/atmel_cs.c +++ b/drivers/net/wireless/atmel_cs.c @@ -42,7 +42,6 @@ #include <linux/moduleparam.h> #include <linux/device.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/cisreg.h> #include <pcmcia/ds.h> @@ -64,58 +63,21 @@ MODULE_SUPPORTED_DEVICE("Atmel at76c50x PCMCIA cards"); /*====================================================================*/ -/* - The event() function is this driver's Card Services event handler. - It will be called by Card Services when an appropriate card status - event is received. The config() and release() entry points are - used to configure or release a socket, in response to card - insertion and ejection events. They are invoked from the atmel_cs - event handler. -*/ - static int atmel_config(struct pcmcia_device *link); static void atmel_release(struct pcmcia_device *link); -/* - The attach() and detach() entry points are used to create and destroy - "instances" of the driver, where each instance represents everything - needed to manage one actual PCMCIA card. -*/ - static void atmel_detach(struct pcmcia_device *p_dev); typedef struct local_info_t { struct net_device *eth_dev; } local_info_t; -/*====================================================================== - - atmel_attach() creates an "instance" of the driver, allocating - local data structures for one device. The device is registered - with Card Services. - - The dev_link structure is initialized, but we don't actually - configure the card at this point -- we wait until we receive a - card insertion event. - - ======================================================================*/ - static int atmel_probe(struct pcmcia_device *p_dev) { local_info_t *local; dev_dbg(&p_dev->dev, "atmel_attach()\n"); - /* - General socket configuration defaults can go here. In this - client, we assume very little, and rely on the CIS for almost - everything. In most clients, many details (i.e., number, sizes, - and attributes of IO windows) are fixed by the nature of the - device, and can be hard-wired here. - */ - p_dev->conf.Attributes = 0; - p_dev->conf.IntType = INT_MEMORY_AND_IO; - /* Allocate space for private device-specific data */ local = kzalloc(sizeof(local_info_t), GFP_KERNEL); if (!local) { @@ -127,15 +89,6 @@ static int atmel_probe(struct pcmcia_device *p_dev) return atmel_config(p_dev); } /* atmel_attach */ -/*====================================================================== - - This deletes a driver "instance". The device is de-registered - with Card Services. If it has been released, all local data - structures are freed. Otherwise, the structures will be freed - when the device is released. - - ======================================================================*/ - static void atmel_detach(struct pcmcia_device *link) { dev_dbg(&link->dev, "atmel_detach\n"); @@ -145,14 +98,6 @@ static void atmel_detach(struct pcmcia_device *link) kfree(link->priv); } -/*====================================================================== - - atmel_config() is scheduled to run after a CARD_INSERTION event - is received, to configure the PCMCIA socket, and to make the - device available to the system. - - ======================================================================*/ - /* Call-back function to interrogate PCMCIA-specific information about the current existance of the card */ static int card_present(void *arg) @@ -165,47 +110,11 @@ static int card_present(void *arg) return 0; } -static int atmel_config_check(struct pcmcia_device *p_dev, - cistpl_cftable_entry_t *cfg, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, - void *priv_data) +static int atmel_config_check(struct pcmcia_device *p_dev, void *priv_data) { - if (cfg->index == 0) - return -ENODEV; - - /* Does this card need audio output? */ - if (cfg->flags & CISTPL_CFTABLE_AUDIO) { - p_dev->conf.Attributes |= CONF_ENABLE_SPKR; - p_dev->conf.Status = CCSR_AUDIO_ENA; - } + if (p_dev->config_index == 0) + return -EINVAL; - /* Use power settings for Vcc and Vpp if present */ - /* Note that the CIS values need to be rescaled */ - if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM)) - p_dev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM]/10000; - else if (dflt->vpp1.present & (1<<CISTPL_POWER_VNOM)) - p_dev->conf.Vpp = dflt->vpp1.param[CISTPL_POWER_VNOM]/10000; - - p_dev->conf.Attributes |= CONF_ENABLE_IRQ; - - /* IO window settings */ - p_dev->resource[0]->end = p_dev->resource[1]->end = 0; - if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) { - cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io; - p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; - p_dev->resource[0]->flags |= - pcmcia_io_cfg_data_width(io->flags); - p_dev->resource[0]->start = io->win[0].base; - p_dev->resource[0]->end = io->win[0].len; - if (io->nwin > 1) { - p_dev->resource[1]->flags = p_dev->resource[0]->flags; - p_dev->resource[1]->start = io->win[1].base; - p_dev->resource[1]->end = io->win[1].len; - } - } - - /* This reserves IO space but doesn't actually enable it */ return pcmcia_request_io(p_dev); } @@ -220,18 +129,9 @@ static int atmel_config(struct pcmcia_device *link) dev_dbg(&link->dev, "atmel_config\n"); - /* - In this loop, we scan the CIS for configuration table entries, - each of which describes a valid card configuration, including - voltage, IO window, memory window, and interrupt settings. - - We make no assumptions about the card to be configured: we use - just the information available in the CIS. In an ideal world, - this would work for any PCMCIA card, but it requires a complete - and accurate CIS. In practice, a driver usually "knows" most of - these things without consulting the CIS, and most client drivers - will only use the CIS to fill in implementation-defined details. - */ + link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_VPP | + CONF_AUTO_AUDIO | CONF_AUTO_SET_IO; + if (pcmcia_loop_config(link, atmel_config_check, NULL)) goto failed; @@ -240,12 +140,7 @@ static int atmel_config(struct pcmcia_device *link) goto failed; } - /* - This actually configures the PCMCIA socket -- setting up - the I/O windows and the interrupt mapping, and putting the - card and host interface into "Memory and IO" mode. - */ - ret = pcmcia_request_configuration(link, &link->conf); + ret = pcmcia_enable_device(link); if (ret) goto failed; @@ -267,14 +162,6 @@ static int atmel_config(struct pcmcia_device *link) return -ENODEV; } -/*====================================================================== - - After a card is removed, atmel_release() will unregister the - device, and release the PCMCIA configuration. If the device is - still open, this will be postponed until it is closed. - - ======================================================================*/ - static void atmel_release(struct pcmcia_device *link) { struct net_device *dev = ((local_info_t*)link->priv)->eth_dev; @@ -353,9 +240,7 @@ MODULE_DEVICE_TABLE(pcmcia, atmel_ids); static struct pcmcia_driver atmel_driver = { .owner = THIS_MODULE, - .drv = { - .name = "atmel_cs", - }, + .name = "atmel_cs", .probe = atmel_probe, .remove = atmel_detach, .id_table = atmel_ids, @@ -363,12 +248,12 @@ static struct pcmcia_driver atmel_driver = { .resume = atmel_resume, }; -static int atmel_cs_init(void) +static int __init atmel_cs_init(void) { return pcmcia_register_driver(&atmel_driver); } -static void atmel_cs_cleanup(void) +static void __exit atmel_cs_cleanup(void) { pcmcia_unregister_driver(&atmel_driver); } diff --git a/drivers/net/wireless/b43/debugfs.c b/drivers/net/wireless/b43/debugfs.c index 80b19a44a407..59f59fa40334 100644 --- a/drivers/net/wireless/b43/debugfs.c +++ b/drivers/net/wireless/b43/debugfs.c @@ -627,6 +627,7 @@ out_unlock: .open = b43_debugfs_open, \ .read = b43_debugfs_read, \ .write = b43_debugfs_write, \ + .llseek = generic_file_llseek, \ }, \ .file_struct_offset = offsetof(struct b43_dfsentry, \ file_##name), \ diff --git a/drivers/net/wireless/b43/pcmcia.c b/drivers/net/wireless/b43/pcmcia.c index dfbc41d431ff..7dcba5fafdc7 100644 --- a/drivers/net/wireless/b43/pcmcia.c +++ b/drivers/net/wireless/b43/pcmcia.c @@ -26,7 +26,6 @@ #include <linux/ssb/ssb.h> #include <linux/slab.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/ciscode.h> #include <pcmcia/ds.h> @@ -63,7 +62,6 @@ static int b43_pcmcia_resume(struct pcmcia_device *dev) static int __devinit b43_pcmcia_probe(struct pcmcia_device *dev) { struct ssb_bus *ssb; - win_req_t win; int err = -ENOMEM; int res = 0; @@ -73,30 +71,28 @@ static int __devinit b43_pcmcia_probe(struct pcmcia_device *dev) err = -ENODEV; - dev->conf.Attributes = CONF_ENABLE_IRQ; - dev->conf.IntType = INT_MEMORY_AND_IO; + dev->config_flags |= CONF_ENABLE_IRQ; - win.Attributes = WIN_ENABLE | WIN_DATA_WIDTH_16 | + dev->resource[2]->flags |= WIN_ENABLE | WIN_DATA_WIDTH_16 | WIN_USE_WAIT; - win.Base = 0; - win.Size = SSB_CORE_SIZE; - win.AccessSpeed = 250; - res = pcmcia_request_window(dev, &win, &dev->win); + dev->resource[2]->start = 0; + dev->resource[2]->end = SSB_CORE_SIZE; + res = pcmcia_request_window(dev, dev->resource[2], 250); if (res != 0) goto err_kfree_ssb; - res = pcmcia_map_mem_page(dev, dev->win, 0); + res = pcmcia_map_mem_page(dev, dev->resource[2], 0); if (res != 0) goto err_disable; if (!dev->irq) goto err_disable; - res = pcmcia_request_configuration(dev, &dev->conf); + res = pcmcia_enable_device(dev); if (res != 0) goto err_disable; - err = ssb_bus_pcmciabus_register(ssb, dev, win.Base); + err = ssb_bus_pcmciabus_register(ssb, dev, dev->resource[2]->start); if (err) goto err_disable; dev->priv = ssb; @@ -125,9 +121,7 @@ static void __devexit b43_pcmcia_remove(struct pcmcia_device *dev) static struct pcmcia_driver b43_pcmcia_driver = { .owner = THIS_MODULE, - .drv = { - .name = "b43-pcmcia", - }, + .name = "b43-pcmcia", .id_table = b43_pcmcia_tbl, .probe = b43_pcmcia_probe, .remove = __devexit_p(b43_pcmcia_remove), diff --git a/drivers/net/wireless/b43legacy/debugfs.c b/drivers/net/wireless/b43legacy/debugfs.c index 1f85ac569fec..f232618f2cd1 100644 --- a/drivers/net/wireless/b43legacy/debugfs.c +++ b/drivers/net/wireless/b43legacy/debugfs.c @@ -334,6 +334,7 @@ out_unlock: .open = b43legacy_debugfs_open, \ .read = b43legacy_debugfs_read, \ .write = b43legacy_debugfs_write, \ + .llseek = generic_file_llseek, \ }, \ .file_struct_offset = offsetof(struct b43legacy_dfsentry, \ file_##name), \ diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c index ba54d1b04d22..bd8a4134edeb 100644 --- a/drivers/net/wireless/hostap/hostap_cs.c +++ b/drivers/net/wireless/hostap/hostap_cs.c @@ -12,7 +12,6 @@ #include <linux/wireless.h> #include <net/iw_handler.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/cisreg.h> #include <pcmcia/ds.h> @@ -437,7 +436,6 @@ static int hostap_cs_probe(struct pcmcia_device *p_dev) int ret; PDEBUG(DEBUG_HW, "%s: setting Vcc=33 (constant)\n", dev_info); - p_dev->conf.IntType = INT_MEMORY_AND_IO; ret = prism2_config(p_dev); if (ret) { @@ -468,74 +466,11 @@ static void prism2_detach(struct pcmcia_device *link) } -/* run after a CARD_INSERTION event is received to configure the PCMCIA - * socket and make the device available to the system */ - -static int prism2_config_check(struct pcmcia_device *p_dev, - cistpl_cftable_entry_t *cfg, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, - void *priv_data) +static int prism2_config_check(struct pcmcia_device *p_dev, void *priv_data) { - if (cfg->index == 0) - return -ENODEV; - - PDEBUG(DEBUG_EXTRA, "Checking CFTABLE_ENTRY 0x%02X " - "(default 0x%02X)\n", cfg->index, dflt->index); - - /* Does this card need audio output? */ - if (cfg->flags & CISTPL_CFTABLE_AUDIO) { - p_dev->conf.Attributes |= CONF_ENABLE_SPKR; - p_dev->conf.Status = CCSR_AUDIO_ENA; - } - - /* Use power settings for Vcc and Vpp if present */ - /* Note that the CIS values need to be rescaled */ - if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { - if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / - 10000 && !ignore_cis_vcc) { - PDEBUG(DEBUG_EXTRA, " Vcc mismatch - skipping" - " this entry\n"); - return -ENODEV; - } - } else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) { - if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / - 10000 && !ignore_cis_vcc) { - PDEBUG(DEBUG_EXTRA, " Vcc (default) mismatch " - "- skipping this entry\n"); - return -ENODEV; - } - } + if (p_dev->config_index == 0) + return -EINVAL; - if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) - p_dev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; - else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM)) - p_dev->conf.Vpp = dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000; - - /* Do we need to allocate an interrupt? */ - p_dev->conf.Attributes |= CONF_ENABLE_IRQ; - - /* IO window settings */ - PDEBUG(DEBUG_EXTRA, "IO window settings: cfg->io.nwin=%d " - "dflt->io.nwin=%d\n", - cfg->io.nwin, dflt->io.nwin); - p_dev->resource[0]->end = p_dev->resource[1]->end = 0; - if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) { - cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io; - p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; - p_dev->resource[0]->flags |= - pcmcia_io_cfg_data_width(io->flags); - p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK; - p_dev->resource[0]->start = io->win[0].base; - p_dev->resource[0]->end = io->win[0].len; - if (io->nwin > 1) { - p_dev->resource[1]->flags = p_dev->resource[0]->flags; - p_dev->resource[1]->start = io->win[1].base; - p_dev->resource[1]->end = io->win[1].len; - } - } - - /* This reserves IO space but doesn't actually enable it */ return pcmcia_request_io(p_dev); } @@ -557,6 +492,10 @@ static int prism2_config(struct pcmcia_device *link) } /* Look for an appropriate configuration table entry in the CIS */ + link->config_flags |= CONF_AUTO_SET_VPP | CONF_AUTO_AUDIO | + CONF_AUTO_CHECK_VCC | CONF_AUTO_SET_IO | CONF_ENABLE_IRQ; + if (ignore_cis_vcc) + link->config_flags &= ~CONF_AUTO_CHECK_VCC; ret = pcmcia_loop_config(link, prism2_config_check, NULL); if (ret) { if (!ignore_cis_vcc) @@ -588,12 +527,7 @@ static int prism2_config(struct pcmcia_device *link) if (ret) goto failed_unlock; - /* - * This actually configures the PCMCIA socket -- setting up - * the I/O windows and the interrupt mapping, and putting the - * card and host interface into "Memory and IO" mode. - */ - ret = pcmcia_request_configuration(link, &link->conf); + ret = pcmcia_enable_device(link); if (ret) goto failed_unlock; @@ -602,20 +536,6 @@ static int prism2_config(struct pcmcia_device *link) spin_unlock_irqrestore(&local->irq_init_lock, flags); - /* Finally, report what we've done */ - printk(KERN_INFO "%s: index 0x%02x: ", - dev_info, link->conf.ConfigIndex); - if (link->conf.Vpp) - printk(", Vpp %d.%d", link->conf.Vpp / 10, - link->conf.Vpp % 10); - if (link->conf.Attributes & CONF_ENABLE_IRQ) - printk(", irq %d", link->irq); - if (link->resource[0]) - printk(" & %pR", link->resource[0]); - if (link->resource[1]) - printk(" & %pR", link->resource[1]); - printk("\n"); - local->shutdown = 0; sandisk_enable_wireless(dev); @@ -627,7 +547,7 @@ static int prism2_config(struct pcmcia_device *link) return ret; failed_unlock: - spin_unlock_irqrestore(&local->irq_init_lock, flags); + spin_unlock_irqrestore(&local->irq_init_lock, flags); failed: kfree(hw_priv); prism2_release((u_long)link); @@ -779,9 +699,7 @@ MODULE_DEVICE_TABLE(pcmcia, hostap_cs_ids); static struct pcmcia_driver hostap_driver = { - .drv = { - .name = "hostap_cs", - }, + .name = "hostap_cs", .probe = hostap_cs_probe, .remove = prism2_detach, .owner = THIS_MODULE, diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index 8e84a08ff951..293e1dbc166c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -873,6 +873,7 @@ static ssize_t iwl3945_sta_dbgfs_stats_table_read(struct file *file, static const struct file_operations rs_sta_dbgfs_stats_table_ops = { .read = iwl3945_sta_dbgfs_stats_table_read, .open = iwl3945_open_file_generic, + .llseek = default_llseek, }; static void iwl3945_add_debugfs(void *priv, void *priv_sta, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 23e5c42e7d7e..a4378ba31ef6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -2873,6 +2873,7 @@ static const struct file_operations rs_sta_dbgfs_scale_table_ops = { .write = rs_sta_dbgfs_scale_table_write, .read = rs_sta_dbgfs_scale_table_read, .open = open_file_generic, + .llseek = default_llseek, }; static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -2915,6 +2916,7 @@ static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file, static const struct file_operations rs_sta_dbgfs_stats_table_ops = { .read = rs_sta_dbgfs_stats_table_read, .open = open_file_generic, + .llseek = default_llseek, }; static ssize_t rs_sta_dbgfs_rate_scale_data_read(struct file *file, @@ -2946,6 +2948,7 @@ static ssize_t rs_sta_dbgfs_rate_scale_data_read(struct file *file, static const struct file_operations rs_sta_dbgfs_rate_scale_data_ops = { .read = rs_sta_dbgfs_rate_scale_data_read, .open = open_file_generic, + .llseek = default_llseek, }; static void rs_add_debugfs(void *priv, void *priv_sta, diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index e96a1bb12783..a32d5d337649 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -87,6 +87,7 @@ static int iwl_dbgfs_open_file_generic(struct inode *inode, struct file *file) static const struct file_operations iwl_dbgfs_##name##_ops = { \ .read = iwl_dbgfs_##name##_read, \ .open = iwl_dbgfs_open_file_generic, \ + .llseek = generic_file_llseek, \ }; #define DEBUGFS_WRITE_FILE_OPS(name) \ @@ -94,6 +95,7 @@ static const struct file_operations iwl_dbgfs_##name##_ops = { \ static const struct file_operations iwl_dbgfs_##name##_ops = { \ .write = iwl_dbgfs_##name##_write, \ .open = iwl_dbgfs_open_file_generic, \ + .llseek = generic_file_llseek, \ }; @@ -104,6 +106,7 @@ static const struct file_operations iwl_dbgfs_##name##_ops = { \ .write = iwl_dbgfs_##name##_write, \ .read = iwl_dbgfs_##name##_read, \ .open = iwl_dbgfs_open_file_generic, \ + .llseek = generic_file_llseek, \ }; static ssize_t iwl_dbgfs_tx_statistics_read(struct file *file, diff --git a/drivers/net/wireless/iwmc3200wifi/debugfs.c b/drivers/net/wireless/iwmc3200wifi/debugfs.c index 53b0b7711f02..0a0cc9667cd6 100644 --- a/drivers/net/wireless/iwmc3200wifi/debugfs.c +++ b/drivers/net/wireless/iwmc3200wifi/debugfs.c @@ -402,24 +402,28 @@ static const struct file_operations iwm_debugfs_txq_fops = { .owner = THIS_MODULE, .open = iwm_generic_open, .read = iwm_debugfs_txq_read, + .llseek = default_llseek, }; static const struct file_operations iwm_debugfs_tx_credit_fops = { .owner = THIS_MODULE, .open = iwm_generic_open, .read = iwm_debugfs_tx_credit_read, + .llseek = default_llseek, }; static const struct file_operations iwm_debugfs_rx_ticket_fops = { .owner = THIS_MODULE, .open = iwm_generic_open, .read = iwm_debugfs_rx_ticket_read, + .llseek = default_llseek, }; static const struct file_operations iwm_debugfs_fw_err_fops = { .owner = THIS_MODULE, .open = iwm_generic_open, .read = iwm_debugfs_fw_err_read, + .llseek = default_llseek, }; void iwm_debugfs_init(struct iwm_priv *iwm) diff --git a/drivers/net/wireless/iwmc3200wifi/sdio.c b/drivers/net/wireless/iwmc3200wifi/sdio.c index edcb52330cf5..56383e7be835 100644 --- a/drivers/net/wireless/iwmc3200wifi/sdio.c +++ b/drivers/net/wireless/iwmc3200wifi/sdio.c @@ -364,6 +364,7 @@ static const struct file_operations iwm_debugfs_sdio_fops = { .owner = THIS_MODULE, .open = iwm_debugfs_sdio_open, .read = iwm_debugfs_sdio_read, + .llseek = default_llseek, }; static void if_sdio_debugfs_init(struct iwm_priv *iwm, struct dentry *parent_dir) diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c index 651a79c8de8a..fbf3b0332bb7 100644 --- a/drivers/net/wireless/libertas/debugfs.c +++ b/drivers/net/wireless/libertas/debugfs.c @@ -696,6 +696,7 @@ out_unlock: .open = open_file_generic, \ .read = (fread), \ .write = (fwrite), \ + .llseek = generic_file_llseek, \ } struct lbs_debugfs_files { @@ -961,6 +962,7 @@ static const struct file_operations lbs_debug_fops = { .open = open_file_generic, .write = lbs_debugfs_write, .read = lbs_debugfs_read, + .llseek = default_llseek, }; /** diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c index 9c298396be50..ff1280f41336 100644 --- a/drivers/net/wireless/libertas/if_cs.c +++ b/drivers/net/wireless/libertas/if_cs.c @@ -28,7 +28,6 @@ #include <linux/firmware.h> #include <linux/netdevice.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/ds.h> @@ -761,15 +760,6 @@ static int if_cs_host_to_card(struct lbs_private *priv, } -/********************************************************************/ -/* Card Services */ -/********************************************************************/ - -/* - * After a card is removed, if_cs_release() will unregister the - * device, and release the PCMCIA configuration. If the device is - * still open, this will be postponed until it is closed. - */ static void if_cs_release(struct pcmcia_device *p_dev) { struct if_cs_card *card = p_dev->priv; @@ -785,31 +775,12 @@ static void if_cs_release(struct pcmcia_device *p_dev) } -/* - * This creates an "instance" of the driver, allocating local data - * structures for one device. The device is registered with Card - * Services. - * - * The dev_link structure is initialized, but we don't actually - * configure the card at this point -- we wait until we receive a card - * insertion event. - */ - -static int if_cs_ioprobe(struct pcmcia_device *p_dev, - cistpl_cftable_entry_t *cfg, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, - void *priv_data) +static int if_cs_ioprobe(struct pcmcia_device *p_dev, void *priv_data) { + p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; - p_dev->resource[0]->start = cfg->io.win[0].base; - p_dev->resource[0]->end = cfg->io.win[0].len; - - /* Do we need to allocate an interrupt? */ - p_dev->conf.Attributes |= CONF_ENABLE_IRQ; - /* IO window settings */ - if (cfg->io.nwin != 1) { + if (p_dev->resource[1]->end) { lbs_pr_err("wrong CIS (check number of IO windows)\n"); return -ENODEV; } @@ -835,15 +806,13 @@ static int if_cs_probe(struct pcmcia_device *p_dev) card->p_dev = p_dev; p_dev->priv = card; - p_dev->conf.Attributes = 0; - p_dev->conf.IntType = INT_MEMORY_AND_IO; + p_dev->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; if (pcmcia_loop_config(p_dev, if_cs_ioprobe, NULL)) { lbs_pr_err("error in pcmcia_loop_config\n"); goto out1; } - /* * Allocate an interrupt line. Note that this does not assign * a handler to the interrupt, unless the 'Handler' member of @@ -861,14 +830,9 @@ static int if_cs_probe(struct pcmcia_device *p_dev) goto out1; } - /* - * This actually configures the PCMCIA socket -- setting up - * the I/O windows and the interrupt mapping, and putting the - * card and host interface into "Memory and IO" mode. - */ - ret = pcmcia_request_configuration(p_dev, &p_dev->conf); + ret = pcmcia_enable_device(p_dev); if (ret) { - lbs_pr_err("error in pcmcia_request_configuration\n"); + lbs_pr_err("error in pcmcia_enable_device\n"); goto out2; } @@ -962,12 +926,6 @@ out: } -/* - * This deletes a driver "instance". The device is de-registered with - * Card Services. If it has been released, all local data structures - * are freed. Otherwise, the structures will be freed when the device - * is released. - */ static void if_cs_detach(struct pcmcia_device *p_dev) { struct if_cs_card *card = p_dev->priv; @@ -1000,9 +958,7 @@ MODULE_DEVICE_TABLE(pcmcia, if_cs_ids); static struct pcmcia_driver lbs_driver = { .owner = THIS_MODULE, - .drv = { - .name = DRV_NAME, - }, + .name = DRV_NAME, .probe = if_cs_probe, .remove = if_cs_detach, .id_table = if_cs_ids, diff --git a/drivers/net/wireless/orinoco/orinoco_cs.c b/drivers/net/wireless/orinoco/orinoco_cs.c index ef46a2d88539..71b3d68b9403 100644 --- a/drivers/net/wireless/orinoco/orinoco_cs.c +++ b/drivers/net/wireless/orinoco/orinoco_cs.c @@ -17,7 +17,6 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/delay.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/cisreg.h> #include <pcmcia/ds.h> @@ -93,14 +92,6 @@ orinoco_cs_hard_reset(struct orinoco_private *priv) /* PCMCIA stuff */ /********************************************************************/ -/* - * This creates an "instance" of the driver, allocating local data - * structures for one device. The device is registered with Card - * Services. - * - * The dev_link structure is initialized, but we don't actually - * configure the card at this point -- we wait until we receive a card - * insertion event. */ static int orinoco_cs_probe(struct pcmcia_device *link) { @@ -117,23 +108,9 @@ orinoco_cs_probe(struct pcmcia_device *link) card->p_dev = link; link->priv = priv; - /* General socket configuration defaults can go here. In this - * client, we assume very little, and rely on the CIS for - * almost everything. In most clients, many details (i.e., - * number, sizes, and attributes of IO windows) are fixed by - * the nature of the device, and can be hard-wired here. */ - link->conf.Attributes = 0; - link->conf.IntType = INT_MEMORY_AND_IO; - return orinoco_cs_config(link); } /* orinoco_cs_attach */ -/* - * This deletes a driver "instance". The device is de-registered with - * Card Services. If it has been released, all local data structures - * are freed. Otherwise, the structures will be freed when the device - * is released. - */ static void orinoco_cs_detach(struct pcmcia_device *link) { struct orinoco_private *priv = link->priv; @@ -145,76 +122,12 @@ static void orinoco_cs_detach(struct pcmcia_device *link) free_orinocodev(priv); } /* orinoco_cs_detach */ -/* - * orinoco_cs_config() is scheduled to run after a CARD_INSERTION - * event is received, to configure the PCMCIA socket, and to make the - * device available to the system. - */ - -static int orinoco_cs_config_check(struct pcmcia_device *p_dev, - cistpl_cftable_entry_t *cfg, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, - void *priv_data) +static int orinoco_cs_config_check(struct pcmcia_device *p_dev, void *priv_data) { - if (cfg->index == 0) - goto next_entry; - - /* Use power settings for Vcc and Vpp if present */ - /* Note that the CIS values need to be rescaled */ - if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { - if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) { - DEBUG(2, "%s: Vcc mismatch (vcc = %d, CIS = %d)\n", - __func__, vcc, - cfg->vcc.param[CISTPL_POWER_VNOM] / 10000); - if (!ignore_cis_vcc) - goto next_entry; - } - } else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) { - if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000) { - DEBUG(2, "%s: Vcc mismatch (vcc = %d, CIS = %d)\n", - __func__, vcc, - dflt->vcc.param[CISTPL_POWER_VNOM] / 10000); - if (!ignore_cis_vcc) - goto next_entry; - } - } + if (p_dev->config_index == 0) + return -EINVAL; - if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) - p_dev->conf.Vpp = - cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; - else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM)) - p_dev->conf.Vpp = - dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000; - - /* Do we need to allocate an interrupt? */ - p_dev->conf.Attributes |= CONF_ENABLE_IRQ; - - /* IO window settings */ - p_dev->resource[0]->end = p_dev->resource[1]->end = 0; - if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) { - cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io; - p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK; - p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; - p_dev->resource[0]->flags |= - pcmcia_io_cfg_data_width(io->flags); - p_dev->resource[0]->start = io->win[0].base; - p_dev->resource[0]->end = io->win[0].len; - if (io->nwin > 1) { - p_dev->resource[1]->flags = p_dev->resource[0]->flags; - p_dev->resource[1]->start = io->win[1].base; - p_dev->resource[1]->end = io->win[1].len; - } - - /* This reserves IO space but doesn't actually enable it */ - if (pcmcia_request_io(p_dev) != 0) - goto next_entry; - } - return 0; - -next_entry: - pcmcia_disable_device(p_dev); - return -ENODEV; + return pcmcia_request_io(p_dev); }; static int @@ -225,20 +138,10 @@ orinoco_cs_config(struct pcmcia_device *link) int ret; void __iomem *mem; - /* - * In this loop, we scan the CIS for configuration table - * entries, each of which describes a valid card - * configuration, including voltage, IO window, memory window, - * and interrupt settings. - * - * We make no assumptions about the card to be configured: we - * use just the information available in the CIS. In an ideal - * world, this would work for any PCMCIA card, but it requires - * a complete and accurate CIS. In practice, a driver usually - * "knows" most of these things without consulting the CIS, - * and most client drivers will only use the CIS to fill in - * implementation-defined details. - */ + link->config_flags |= CONF_AUTO_SET_VPP | CONF_AUTO_CHECK_VCC | + CONF_AUTO_SET_IO | CONF_ENABLE_IRQ; + if (ignore_cis_vcc) + link->config_flags &= ~CONF_AUTO_CHECK_VCC; ret = pcmcia_loop_config(link, orinoco_cs_config_check, NULL); if (ret) { if (!ignore_cis_vcc) @@ -262,12 +165,7 @@ orinoco_cs_config(struct pcmcia_device *link) hermes_struct_init(hw, mem, HERMES_16BIT_REGSPACING); - /* - * This actually configures the PCMCIA socket -- setting up - * the I/O windows and the interrupt mapping, and putting the - * card and host interface into "Memory and IO" mode. - */ - ret = pcmcia_request_configuration(link, &link->conf); + ret = pcmcia_enable_device(link); if (ret) goto failed; @@ -291,11 +189,6 @@ orinoco_cs_config(struct pcmcia_device *link) return -ENODEV; } /* orinoco_cs_config */ -/* - * After a card is removed, orinoco_cs_release() will unregister the - * device, and release the PCMCIA configuration. If the device is - * still open, this will be postponed until it is closed. - */ static void orinoco_cs_release(struct pcmcia_device *link) { @@ -344,12 +237,6 @@ static int orinoco_cs_resume(struct pcmcia_device *link) /* Module initialization */ /********************************************************************/ -/* Can't be declared "const" or the whole __initdata section will - * become const */ -static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION - " (David Gibson <hermes@gibson.dropbear.id.au>, " - "Pavel Roskin <proski@gnu.org>, et al)"; - static struct pcmcia_device_id orinoco_cs_ids[] = { PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0777), /* 3Com AirConnect PCI 777A */ PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0002), /* Lucent Orinoco and old Intersil */ @@ -441,9 +328,7 @@ MODULE_DEVICE_TABLE(pcmcia, orinoco_cs_ids); static struct pcmcia_driver orinoco_driver = { .owner = THIS_MODULE, - .drv = { - .name = DRIVER_NAME, - }, + .name = DRIVER_NAME, .probe = orinoco_cs_probe, .remove = orinoco_cs_detach, .id_table = orinoco_cs_ids, @@ -454,8 +339,6 @@ static struct pcmcia_driver orinoco_driver = { static int __init init_orinoco_cs(void) { - printk(KERN_DEBUG "%s\n", version); - return pcmcia_register_driver(&orinoco_driver); } diff --git a/drivers/net/wireless/orinoco/spectrum_cs.c b/drivers/net/wireless/orinoco/spectrum_cs.c index 873877e17e1b..fb859a5ad2eb 100644 --- a/drivers/net/wireless/orinoco/spectrum_cs.c +++ b/drivers/net/wireless/orinoco/spectrum_cs.c @@ -25,7 +25,6 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/delay.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/cisreg.h> #include <pcmcia/ds.h> @@ -154,14 +153,6 @@ spectrum_cs_stop_firmware(struct orinoco_private *priv, int idle) /* PCMCIA stuff */ /********************************************************************/ -/* - * This creates an "instance" of the driver, allocating local data - * structures for one device. The device is registered with Card - * Services. - * - * The dev_link structure is initialized, but we don't actually - * configure the card at this point -- we wait until we receive a card - * insertion event. */ static int spectrum_cs_probe(struct pcmcia_device *link) { @@ -179,23 +170,9 @@ spectrum_cs_probe(struct pcmcia_device *link) card->p_dev = link; link->priv = priv; - /* General socket configuration defaults can go here. In this - * client, we assume very little, and rely on the CIS for - * almost everything. In most clients, many details (i.e., - * number, sizes, and attributes of IO windows) are fixed by - * the nature of the device, and can be hard-wired here. */ - link->conf.Attributes = 0; - link->conf.IntType = INT_MEMORY_AND_IO; - return spectrum_cs_config(link); } /* spectrum_cs_attach */ -/* - * This deletes a driver "instance". The device is de-registered with - * Card Services. If it has been released, all local data structures - * are freed. Otherwise, the structures will be freed when the device - * is released. - */ static void spectrum_cs_detach(struct pcmcia_device *link) { struct orinoco_private *priv = link->priv; @@ -207,76 +184,13 @@ static void spectrum_cs_detach(struct pcmcia_device *link) free_orinocodev(priv); } /* spectrum_cs_detach */ -/* - * spectrum_cs_config() is scheduled to run after a CARD_INSERTION - * event is received, to configure the PCMCIA socket, and to make the - * device available to the system. - */ - static int spectrum_cs_config_check(struct pcmcia_device *p_dev, - cistpl_cftable_entry_t *cfg, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, void *priv_data) { - if (cfg->index == 0) - goto next_entry; - - /* Use power settings for Vcc and Vpp if present */ - /* Note that the CIS values need to be rescaled */ - if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { - if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) { - DEBUG(2, "%s: Vcc mismatch (vcc = %d, CIS = %d)\n", - __func__, vcc, - cfg->vcc.param[CISTPL_POWER_VNOM] / 10000); - if (!ignore_cis_vcc) - goto next_entry; - } - } else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) { - if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000) { - DEBUG(2, "%s: Vcc mismatch (vcc = %d, CIS = %d)\n", - __func__, vcc, - dflt->vcc.param[CISTPL_POWER_VNOM] / 10000); - if (!ignore_cis_vcc) - goto next_entry; - } - } + if (p_dev->config_index == 0) + return -EINVAL; - if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) - p_dev->conf.Vpp = - cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; - else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM)) - p_dev->conf.Vpp = - dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000; - - /* Do we need to allocate an interrupt? */ - p_dev->conf.Attributes |= CONF_ENABLE_IRQ; - - /* IO window settings */ - p_dev->resource[0]->end = p_dev->resource[1]->end = 0; - if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) { - cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io; - p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK; - p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; - p_dev->resource[0]->flags |= - pcmcia_io_cfg_data_width(io->flags); - p_dev->resource[0]->start = io->win[0].base; - p_dev->resource[0]->end = io->win[0].len; - if (io->nwin > 1) { - p_dev->resource[1]->flags = p_dev->resource[0]->flags; - p_dev->resource[1]->start = io->win[1].base; - p_dev->resource[1]->end = io->win[1].len; - } - - /* This reserves IO space but doesn't actually enable it */ - if (pcmcia_request_io(p_dev) != 0) - goto next_entry; - } - return 0; - -next_entry: - pcmcia_disable_device(p_dev); - return -ENODEV; + return pcmcia_request_io(p_dev); }; static int @@ -287,20 +201,10 @@ spectrum_cs_config(struct pcmcia_device *link) int ret; void __iomem *mem; - /* - * In this loop, we scan the CIS for configuration table - * entries, each of which describes a valid card - * configuration, including voltage, IO window, memory window, - * and interrupt settings. - * - * We make no assumptions about the card to be configured: we - * use just the information available in the CIS. In an ideal - * world, this would work for any PCMCIA card, but it requires - * a complete and accurate CIS. In practice, a driver usually - * "knows" most of these things without consulting the CIS, - * and most client drivers will only use the CIS to fill in - * implementation-defined details. - */ + link->config_flags |= CONF_AUTO_SET_VPP | CONF_AUTO_CHECK_VCC | + CONF_AUTO_SET_IO | CONF_ENABLE_IRQ; + if (ignore_cis_vcc) + link->config_flags &= ~CONF_AUTO_CHECK_VCC; ret = pcmcia_loop_config(link, spectrum_cs_config_check, NULL); if (ret) { if (!ignore_cis_vcc) @@ -325,12 +229,7 @@ spectrum_cs_config(struct pcmcia_device *link) hermes_struct_init(hw, mem, HERMES_16BIT_REGSPACING); hw->eeprom_pda = true; - /* - * This actually configures the PCMCIA socket -- setting up - * the I/O windows and the interrupt mapping, and putting the - * card and host interface into "Memory and IO" mode. - */ - ret = pcmcia_request_configuration(link, &link->conf); + ret = pcmcia_enable_device(link); if (ret) goto failed; @@ -358,11 +257,6 @@ spectrum_cs_config(struct pcmcia_device *link) return -ENODEV; } /* spectrum_cs_config */ -/* - * After a card is removed, spectrum_cs_release() will unregister the - * device, and release the PCMCIA configuration. If the device is - * still open, this will be postponed until it is closed. - */ static void spectrum_cs_release(struct pcmcia_device *link) { @@ -407,12 +301,6 @@ spectrum_cs_resume(struct pcmcia_device *link) /* Module initialization */ /********************************************************************/ -/* Can't be declared "const" or the whole __initdata section will - * become const */ -static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION - " (Pavel Roskin <proski@gnu.org>," - " David Gibson <hermes@gibson.dropbear.id.au>, et al)"; - static struct pcmcia_device_id spectrum_cs_ids[] = { PCMCIA_DEVICE_MANF_CARD(0x026c, 0x0001), /* Symbol Spectrum24 LA4137 */ PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0001), /* Socket Communications CF */ @@ -423,9 +311,7 @@ MODULE_DEVICE_TABLE(pcmcia, spectrum_cs_ids); static struct pcmcia_driver orinoco_driver = { .owner = THIS_MODULE, - .drv = { - .name = DRIVER_NAME, - }, + .name = DRIVER_NAME, .probe = spectrum_cs_probe, .remove = spectrum_cs_detach, .suspend = spectrum_cs_suspend, @@ -436,8 +322,6 @@ static struct pcmcia_driver orinoco_driver = { static int __init init_spectrum_cs(void) { - printk(KERN_DEBUG "%s\n", version); - return pcmcia_register_driver(&orinoco_driver); } diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 88560d0ae50a..46da03753fd5 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -46,7 +46,6 @@ #include <linux/ethtool.h> #include <linux/ieee80211.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/cisreg.h> #include <pcmcia/ds.h> @@ -169,13 +168,6 @@ static int bc; */ static char *phy_addr = NULL; - -/* A struct pcmcia_device structure has fields for most things that are needed - to keep track of a socket, but there will usually be some device - specific information that also needs to be kept track of. The - 'priv' pointer in a struct pcmcia_device structure can be used to point to - a device-specific private data structure, like this. -*/ static unsigned int ray_mem_speed = 500; /* WARNING: THIS DRIVER IS NOT CAPABLE OF HANDLING MULTIPLE DEVICES! */ @@ -290,14 +282,6 @@ static const struct net_device_ops ray_netdev_ops = { .ndo_validate_addr = eth_validate_addr, }; -/*============================================================================= - ray_attach() creates an "instance" of the driver, allocating - local data structures for one device. The device is registered - with Card Services. - The dev_link structure is initialized, but we don't actually - configure the card at this point -- we wait until we receive a - card insertion event. -=============================================================================*/ static int ray_probe(struct pcmcia_device *p_dev) { ray_dev_t *local; @@ -318,9 +302,8 @@ static int ray_probe(struct pcmcia_device *p_dev) p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; /* General socket configuration */ - p_dev->conf.Attributes = CONF_ENABLE_IRQ; - p_dev->conf.IntType = INT_MEMORY_AND_IO; - p_dev->conf.ConfigIndex = 1; + p_dev->config_flags |= CONF_ENABLE_IRQ; + p_dev->config_index = 1; p_dev->priv = dev; @@ -353,12 +336,6 @@ fail_alloc_dev: return -ENOMEM; } /* ray_attach */ -/*============================================================================= - This deletes a driver "instance". The device is de-registered - with Card Services. If it has been released, all local data - structures are freed. Otherwise, the structures will be freed - when the device is released. -=============================================================================*/ static void ray_detach(struct pcmcia_device *link) { struct net_device *dev; @@ -381,17 +358,11 @@ static void ray_detach(struct pcmcia_device *link) dev_dbg(&link->dev, "ray_cs ray_detach ending\n"); } /* ray_detach */ -/*============================================================================= - ray_config() is run after a CARD_INSERTION event - is received, to configure the PCMCIA socket, and to make the - ethernet device available to the system. -=============================================================================*/ #define MAX_TUPLE_SIZE 128 static int ray_config(struct pcmcia_device *link) { int ret = 0; int i; - win_req_t req; struct net_device *dev = (struct net_device *)link->priv; ray_dev_t *local = netdev_priv(dev); @@ -412,54 +383,50 @@ static int ray_config(struct pcmcia_device *link) goto failed; dev->irq = link->irq; - /* This actually configures the PCMCIA socket -- setting up - the I/O windows and the interrupt mapping. - */ - ret = pcmcia_request_configuration(link, &link->conf); + ret = pcmcia_enable_device(link); if (ret) goto failed; /*** Set up 32k window for shared memory (transmit and control) ************/ - req.Attributes = - WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT; - req.Base = 0; - req.Size = 0x8000; - req.AccessSpeed = ray_mem_speed; - ret = pcmcia_request_window(link, &req, &link->win); + link->resource[2]->flags |= WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT; + link->resource[2]->start = 0; + link->resource[2]->end = 0x8000; + ret = pcmcia_request_window(link, link->resource[2], ray_mem_speed); if (ret) goto failed; - ret = pcmcia_map_mem_page(link, link->win, 0); + ret = pcmcia_map_mem_page(link, link->resource[2], 0); if (ret) goto failed; - local->sram = ioremap(req.Base, req.Size); + local->sram = ioremap(link->resource[2]->start, + resource_size(link->resource[2])); /*** Set up 16k window for shared memory (receive buffer) ***************/ - req.Attributes = + link->resource[3]->flags |= WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT; - req.Base = 0; - req.Size = 0x4000; - req.AccessSpeed = ray_mem_speed; - ret = pcmcia_request_window(link, &req, &local->rmem_handle); + link->resource[3]->start = 0; + link->resource[3]->end = 0x4000; + ret = pcmcia_request_window(link, link->resource[3], ray_mem_speed); if (ret) goto failed; - ret = pcmcia_map_mem_page(link, local->rmem_handle, 0x8000); + ret = pcmcia_map_mem_page(link, link->resource[3], 0x8000); if (ret) goto failed; - local->rmem = ioremap(req.Base, req.Size); + local->rmem = ioremap(link->resource[3]->start, + resource_size(link->resource[3])); /*** Set up window for attribute memory ***********************************/ - req.Attributes = + link->resource[4]->flags |= WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_AM | WIN_ENABLE | WIN_USE_WAIT; - req.Base = 0; - req.Size = 0x1000; - req.AccessSpeed = ray_mem_speed; - ret = pcmcia_request_window(link, &req, &local->amem_handle); + link->resource[4]->start = 0; + link->resource[4]->end = 0x1000; + ret = pcmcia_request_window(link, link->resource[4], ray_mem_speed); if (ret) goto failed; - ret = pcmcia_map_mem_page(link, local->amem_handle, 0); + ret = pcmcia_map_mem_page(link, link->resource[4], 0); if (ret) goto failed; - local->amem = ioremap(req.Base, req.Size); + local->amem = ioremap(link->resource[4]->start, + resource_size(link->resource[4])); dev_dbg(&link->dev, "ray_config sram=%p\n", local->sram); dev_dbg(&link->dev, "ray_config rmem=%p\n", local->rmem); @@ -775,11 +742,7 @@ static void join_net(u_long data) local->card_status = CARD_DOING_ACQ; } -/*============================================================================ - After a card is removed, ray_release() will unregister the net - device, and release the PCMCIA configuration. If the device is - still open, this will be postponed until it is closed. -=============================================================================*/ + static void ray_release(struct pcmcia_device *link) { struct net_device *dev = link->priv; @@ -2802,6 +2765,7 @@ static ssize_t ray_cs_essid_proc_write(struct file *file, static const struct file_operations ray_cs_essid_proc_fops = { .owner = THIS_MODULE, .write = ray_cs_essid_proc_write, + .llseek = noop_llseek, }; static ssize_t int_proc_write(struct file *file, const char __user *buffer, @@ -2835,6 +2799,7 @@ static ssize_t int_proc_write(struct file *file, const char __user *buffer, static const struct file_operations int_proc_fops = { .owner = THIS_MODULE, .write = int_proc_write, + .llseek = noop_llseek, }; #endif @@ -2847,9 +2812,7 @@ MODULE_DEVICE_TABLE(pcmcia, ray_ids); static struct pcmcia_driver ray_driver = { .owner = THIS_MODULE, - .drv = { - .name = "ray_cs", - }, + .name = "ray_cs", .probe = ray_probe, .remove = ray_detach, .id_table = ray_ids, diff --git a/drivers/net/wireless/ray_cs.h b/drivers/net/wireless/ray_cs.h index 9f01ddb19748..e79848fbcca1 100644 --- a/drivers/net/wireless/ray_cs.h +++ b/drivers/net/wireless/ray_cs.h @@ -25,8 +25,6 @@ struct beacon_rx { typedef struct ray_dev_t { int card_status; int authentication_state; - window_handle_t amem_handle; /* handle to window for attribute memory */ - window_handle_t rmem_handle; /* handle to window for rx buffer on card */ void __iomem *sram; /* pointer to beginning of shared RAM */ void __iomem *amem; /* pointer to attribute mem window */ void __iomem *rmem; /* pointer to receive buffer window */ diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c index b0498e7e7aae..cea81e4c5c82 100644 --- a/drivers/net/wireless/rt2x00/rt2x00debug.c +++ b/drivers/net/wireless/rt2x00/rt2x00debug.c @@ -315,6 +315,7 @@ static const struct file_operations rt2x00debug_fop_queue_dump = { .poll = rt2x00debug_poll_queue_dump, .open = rt2x00debug_open_queue_dump, .release = rt2x00debug_release_queue_dump, + .llseek = default_llseek, }; static ssize_t rt2x00debug_read_queue_stats(struct file *file, @@ -371,6 +372,7 @@ static const struct file_operations rt2x00debug_fop_queue_stats = { .read = rt2x00debug_read_queue_stats, .open = rt2x00debug_file_open, .release = rt2x00debug_file_release, + .llseek = default_llseek, }; #ifdef CONFIG_RT2X00_LIB_CRYPTO @@ -423,6 +425,7 @@ static const struct file_operations rt2x00debug_fop_crypto_stats = { .read = rt2x00debug_read_crypto_stats, .open = rt2x00debug_file_open, .release = rt2x00debug_file_release, + .llseek = default_llseek, }; #endif @@ -509,6 +512,7 @@ static const struct file_operations rt2x00debug_fop_##__name = {\ .write = rt2x00debug_write_##__name, \ .open = rt2x00debug_file_open, \ .release = rt2x00debug_file_release, \ + .llseek = generic_file_llseek, \ }; RT2X00DEBUGFS_OPS(csr, "0x%.8x\n", u32); @@ -542,6 +546,7 @@ static const struct file_operations rt2x00debug_fop_dev_flags = { .read = rt2x00debug_read_dev_flags, .open = rt2x00debug_file_open, .release = rt2x00debug_file_release, + .llseek = default_llseek, }; static struct dentry *rt2x00debug_create_file_driver(const char *name, diff --git a/drivers/net/wireless/wl12xx/wl1251_debugfs.c b/drivers/net/wireless/wl12xx/wl1251_debugfs.c index 5e4465ac08fa..fa620a5e5303 100644 --- a/drivers/net/wireless/wl12xx/wl1251_debugfs.c +++ b/drivers/net/wireless/wl12xx/wl1251_debugfs.c @@ -50,6 +50,7 @@ static ssize_t name## _read(struct file *file, char __user *userbuf, \ static const struct file_operations name## _ops = { \ .read = name## _read, \ .open = wl1251_open_file_generic, \ + .llseek = generic_file_llseek, \ }; #define DEBUGFS_ADD(name, parent) \ @@ -86,6 +87,7 @@ static ssize_t sub## _ ##name## _read(struct file *file, \ static const struct file_operations sub## _ ##name## _ops = { \ .read = sub## _ ##name## _read, \ .open = wl1251_open_file_generic, \ + .llseek = generic_file_llseek, \ }; #define DEBUGFS_FWSTATS_ADD(sub, name) \ @@ -236,6 +238,7 @@ static ssize_t tx_queue_len_read(struct file *file, char __user *userbuf, static const struct file_operations tx_queue_len_ops = { .read = tx_queue_len_read, .open = wl1251_open_file_generic, + .llseek = generic_file_llseek, }; static ssize_t tx_queue_status_read(struct file *file, char __user *userbuf, @@ -257,6 +260,7 @@ static ssize_t tx_queue_status_read(struct file *file, char __user *userbuf, static const struct file_operations tx_queue_status_ops = { .read = tx_queue_status_read, .open = wl1251_open_file_generic, + .llseek = generic_file_llseek, }; static void wl1251_debugfs_delete_files(struct wl1251 *wl) diff --git a/drivers/net/wireless/wl12xx/wl1271_debugfs.c b/drivers/net/wireless/wl12xx/wl1271_debugfs.c index c239ef4d0b8d..66c2b90ddfd4 100644 --- a/drivers/net/wireless/wl12xx/wl1271_debugfs.c +++ b/drivers/net/wireless/wl12xx/wl1271_debugfs.c @@ -51,6 +51,7 @@ static ssize_t name## _read(struct file *file, char __user *userbuf, \ static const struct file_operations name## _ops = { \ .read = name## _read, \ .open = wl1271_open_file_generic, \ + .llseek = generic_file_llseek, \ }; #define DEBUGFS_ADD(name, parent) \ @@ -87,6 +88,7 @@ static ssize_t sub## _ ##name## _read(struct file *file, \ static const struct file_operations sub## _ ##name## _ops = { \ .read = sub## _ ##name## _read, \ .open = wl1271_open_file_generic, \ + .llseek = generic_file_llseek, \ }; #define DEBUGFS_FWSTATS_ADD(sub, name) \ @@ -237,6 +239,7 @@ static ssize_t tx_queue_len_read(struct file *file, char __user *userbuf, static const struct file_operations tx_queue_len_ops = { .read = tx_queue_len_read, .open = wl1271_open_file_generic, + .llseek = default_llseek, }; static ssize_t gpio_power_read(struct file *file, char __user *user_buf, @@ -291,7 +294,8 @@ out: static const struct file_operations gpio_power_ops = { .read = gpio_power_read, .write = gpio_power_write, - .open = wl1271_open_file_generic + .open = wl1271_open_file_generic, + .llseek = default_llseek, }; static void wl1271_debugfs_delete_files(struct wl1271 *wl) diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index a1cc2d498a1c..ca3f8961fa27 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -48,7 +48,6 @@ #include <net/iw_handler.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/cisreg.h> #include <pcmcia/ds.h> @@ -78,13 +77,6 @@ #define WL3501_RESUME 0 #define WL3501_SUSPEND 1 -/* - * The event() function is this driver's Card Services event handler. It will - * be called by Card Services when an appropriate card status event is - * received. The config() and release() entry points are used to configure or - * release a socket, in response to card insertion and ejection events. They - * are invoked from the wl24 event handler. - */ static int wl3501_config(struct pcmcia_device *link); static void wl3501_release(struct pcmcia_device *link); @@ -1869,15 +1861,6 @@ static const struct net_device_ops wl3501_netdev_ops = { .ndo_validate_addr = eth_validate_addr, }; -/** - * wl3501_attach - creates an "instance" of the driver - * - * Creates an "instance" of the driver, allocating local data structures for - * one device. The device is registered with Card Services. - * - * The dev_link structure is initialized, but we don't actually configure the - * card at this point -- we wait until we receive a card insertion event. - */ static int wl3501_probe(struct pcmcia_device *p_dev) { struct net_device *dev; @@ -1888,9 +1871,8 @@ static int wl3501_probe(struct pcmcia_device *p_dev) p_dev->resource[0]->flags = IO_DATA_PATH_WIDTH_8; /* General socket configuration */ - p_dev->conf.Attributes = CONF_ENABLE_IRQ; - p_dev->conf.IntType = INT_MEMORY_AND_IO; - p_dev->conf.ConfigIndex = 1; + p_dev->config_flags = CONF_ENABLE_IRQ; + p_dev->config_index = 1; dev = alloc_etherdev(sizeof(struct wl3501_card)); if (!dev) @@ -1914,14 +1896,6 @@ out_link: return -ENOMEM; } -/** - * wl3501_config - configure the PCMCIA socket and make eth device available - * @link - FILL_IN - * - * wl3501_config() is scheduled to run after a CARD_INSERTION event is - * received, to configure the PCMCIA socket, and to make the ethernet device - * available to the system. - */ static int wl3501_config(struct pcmcia_device *link) { struct net_device *dev = link->priv; @@ -1952,10 +1926,7 @@ static int wl3501_config(struct pcmcia_device *link) if (ret) goto failed; - /* This actually configures the PCMCIA socket -- setting up the I/O - * windows and the interrupt mapping. */ - - ret = pcmcia_request_configuration(link, &link->conf); + ret = pcmcia_enable_device(link); if (ret) goto failed; @@ -2010,14 +1981,6 @@ failed: return -ENODEV; } -/** - * wl3501_release - unregister the net, release PCMCIA configuration - * @arg - link - * - * After a card is removed, wl3501_release() will unregister the net device, - * and release the PCMCIA configuration. If the device is still open, this - * will be postponed until it is closed. - */ static void wl3501_release(struct pcmcia_device *link) { pcmcia_disable_device(link); @@ -2056,9 +2019,7 @@ MODULE_DEVICE_TABLE(pcmcia, wl3501_ids); static struct pcmcia_driver wl3501_driver = { .owner = THIS_MODULE, - .drv = { - .name = "wl3501_cs", - }, + .name = "wl3501_cs", .probe = wl3501_probe, .remove = wl3501_detach, .id_table = wl3501_ids, diff --git a/drivers/oprofile/oprof.c b/drivers/oprofile/oprof.c index b336cd9ee7a1..f9bda64fcd1b 100644 --- a/drivers/oprofile/oprof.c +++ b/drivers/oprofile/oprof.c @@ -225,26 +225,17 @@ post_sync: mutex_unlock(&start_mutex); } -int oprofile_set_backtrace(unsigned long val) +int oprofile_set_ulong(unsigned long *addr, unsigned long val) { - int err = 0; + int err = -EBUSY; mutex_lock(&start_mutex); - - if (oprofile_started) { - err = -EBUSY; - goto out; - } - - if (!oprofile_ops.backtrace) { - err = -EINVAL; - goto out; + if (!oprofile_started) { + *addr = val; + err = 0; } - - oprofile_backtrace_depth = val; - -out: mutex_unlock(&start_mutex); + return err; } @@ -257,16 +248,9 @@ static int __init oprofile_init(void) printk(KERN_INFO "oprofile: using timer interrupt.\n"); err = oprofile_timer_init(&oprofile_ops); if (err) - goto out_arch; + return err; } - err = oprofilefs_register(); - if (err) - goto out_arch; - return 0; - -out_arch: - oprofile_arch_exit(); - return err; + return oprofilefs_register(); } diff --git a/drivers/oprofile/oprof.h b/drivers/oprofile/oprof.h index 47e12cb4ee8b..177b73de5e5f 100644 --- a/drivers/oprofile/oprof.h +++ b/drivers/oprofile/oprof.h @@ -37,7 +37,7 @@ void oprofile_create_files(struct super_block *sb, struct dentry *root); int oprofile_timer_init(struct oprofile_operations *ops); void oprofile_timer_exit(void); -int oprofile_set_backtrace(unsigned long depth); +int oprofile_set_ulong(unsigned long *addr, unsigned long val); int oprofile_set_timeout(unsigned long time); #endif /* OPROF_H */ diff --git a/drivers/oprofile/oprofile_files.c b/drivers/oprofile/oprofile_files.c index bbd7516e0869..89f63456646f 100644 --- a/drivers/oprofile/oprofile_files.c +++ b/drivers/oprofile/oprofile_files.c @@ -59,6 +59,7 @@ static ssize_t timeout_write(struct file *file, char const __user *buf, static const struct file_operations timeout_fops = { .read = timeout_read, .write = timeout_write, + .llseek = default_llseek, }; #endif @@ -79,21 +80,25 @@ static ssize_t depth_write(struct file *file, char const __user *buf, size_t cou if (*offset) return -EINVAL; + if (!oprofile_ops.backtrace) + return -EINVAL; + retval = oprofilefs_ulong_from_user(&val, buf, count); if (retval) return retval; - retval = oprofile_set_backtrace(val); - + retval = oprofile_set_ulong(&oprofile_backtrace_depth, val); if (retval) return retval; + return count; } static const struct file_operations depth_fops = { .read = depth_read, - .write = depth_write + .write = depth_write, + .llseek = default_llseek, }; @@ -105,6 +110,7 @@ static ssize_t pointer_size_read(struct file *file, char __user *buf, size_t cou static const struct file_operations pointer_size_fops = { .read = pointer_size_read, + .llseek = default_llseek, }; @@ -116,6 +122,7 @@ static ssize_t cpu_type_read(struct file *file, char __user *buf, size_t count, static const struct file_operations cpu_type_fops = { .read = cpu_type_read, + .llseek = default_llseek, }; @@ -151,6 +158,7 @@ static ssize_t enable_write(struct file *file, char const __user *buf, size_t co static const struct file_operations enable_fops = { .read = enable_read, .write = enable_write, + .llseek = default_llseek, }; @@ -163,6 +171,7 @@ static ssize_t dump_write(struct file *file, char const __user *buf, size_t coun static const struct file_operations dump_fops = { .write = dump_write, + .llseek = noop_llseek, }; void oprofile_create_files(struct super_block *sb, struct dentry *root) diff --git a/drivers/oprofile/oprofile_perf.c b/drivers/oprofile/oprofile_perf.c new file mode 100644 index 000000000000..9046f7b2ed79 --- /dev/null +++ b/drivers/oprofile/oprofile_perf.c @@ -0,0 +1,328 @@ +/* + * Copyright 2010 ARM Ltd. + * + * Perf-events backend for OProfile. + */ +#include <linux/perf_event.h> +#include <linux/platform_device.h> +#include <linux/oprofile.h> +#include <linux/slab.h> + +/* + * Per performance monitor configuration as set via oprofilefs. + */ +struct op_counter_config { + unsigned long count; + unsigned long enabled; + unsigned long event; + unsigned long unit_mask; + unsigned long kernel; + unsigned long user; + struct perf_event_attr attr; +}; + +static int oprofile_perf_enabled; +static DEFINE_MUTEX(oprofile_perf_mutex); + +static struct op_counter_config *counter_config; +static struct perf_event **perf_events[nr_cpumask_bits]; +static int num_counters; + +/* + * Overflow callback for oprofile. + */ +static void op_overflow_handler(struct perf_event *event, int unused, + struct perf_sample_data *data, struct pt_regs *regs) +{ + int id; + u32 cpu = smp_processor_id(); + + for (id = 0; id < num_counters; ++id) + if (perf_events[cpu][id] == event) + break; + + if (id != num_counters) + oprofile_add_sample(regs, id); + else + pr_warning("oprofile: ignoring spurious overflow " + "on cpu %u\n", cpu); +} + +/* + * Called by oprofile_perf_setup to create perf attributes to mirror the oprofile + * settings in counter_config. Attributes are created as `pinned' events and + * so are permanently scheduled on the PMU. + */ +static void op_perf_setup(void) +{ + int i; + u32 size = sizeof(struct perf_event_attr); + struct perf_event_attr *attr; + + for (i = 0; i < num_counters; ++i) { + attr = &counter_config[i].attr; + memset(attr, 0, size); + attr->type = PERF_TYPE_RAW; + attr->size = size; + attr->config = counter_config[i].event; + attr->sample_period = counter_config[i].count; + attr->pinned = 1; + } +} + +static int op_create_counter(int cpu, int event) +{ + struct perf_event *pevent; + + if (!counter_config[event].enabled || perf_events[cpu][event]) + return 0; + + pevent = perf_event_create_kernel_counter(&counter_config[event].attr, + cpu, NULL, + op_overflow_handler); + + if (IS_ERR(pevent)) + return PTR_ERR(pevent); + + if (pevent->state != PERF_EVENT_STATE_ACTIVE) { + perf_event_release_kernel(pevent); + pr_warning("oprofile: failed to enable event %d " + "on CPU %d\n", event, cpu); + return -EBUSY; + } + + perf_events[cpu][event] = pevent; + + return 0; +} + +static void op_destroy_counter(int cpu, int event) +{ + struct perf_event *pevent = perf_events[cpu][event]; + + if (pevent) { + perf_event_release_kernel(pevent); + perf_events[cpu][event] = NULL; + } +} + +/* + * Called by oprofile_perf_start to create active perf events based on the + * perviously configured attributes. + */ +static int op_perf_start(void) +{ + int cpu, event, ret = 0; + + for_each_online_cpu(cpu) { + for (event = 0; event < num_counters; ++event) { + ret = op_create_counter(cpu, event); + if (ret) + return ret; + } + } + + return ret; +} + +/* + * Called by oprofile_perf_stop at the end of a profiling run. + */ +static void op_perf_stop(void) +{ + int cpu, event; + + for_each_online_cpu(cpu) + for (event = 0; event < num_counters; ++event) + op_destroy_counter(cpu, event); +} + +static int oprofile_perf_create_files(struct super_block *sb, struct dentry *root) +{ + unsigned int i; + + for (i = 0; i < num_counters; i++) { + struct dentry *dir; + char buf[4]; + + snprintf(buf, sizeof buf, "%d", i); + dir = oprofilefs_mkdir(sb, root, buf); + oprofilefs_create_ulong(sb, dir, "enabled", &counter_config[i].enabled); + oprofilefs_create_ulong(sb, dir, "event", &counter_config[i].event); + oprofilefs_create_ulong(sb, dir, "count", &counter_config[i].count); + oprofilefs_create_ulong(sb, dir, "unit_mask", &counter_config[i].unit_mask); + oprofilefs_create_ulong(sb, dir, "kernel", &counter_config[i].kernel); + oprofilefs_create_ulong(sb, dir, "user", &counter_config[i].user); + } + + return 0; +} + +static int oprofile_perf_setup(void) +{ + spin_lock(&oprofilefs_lock); + op_perf_setup(); + spin_unlock(&oprofilefs_lock); + return 0; +} + +static int oprofile_perf_start(void) +{ + int ret = -EBUSY; + + mutex_lock(&oprofile_perf_mutex); + if (!oprofile_perf_enabled) { + ret = 0; + op_perf_start(); + oprofile_perf_enabled = 1; + } + mutex_unlock(&oprofile_perf_mutex); + return ret; +} + +static void oprofile_perf_stop(void) +{ + mutex_lock(&oprofile_perf_mutex); + if (oprofile_perf_enabled) + op_perf_stop(); + oprofile_perf_enabled = 0; + mutex_unlock(&oprofile_perf_mutex); +} + +#ifdef CONFIG_PM + +static int oprofile_perf_suspend(struct platform_device *dev, pm_message_t state) +{ + mutex_lock(&oprofile_perf_mutex); + if (oprofile_perf_enabled) + op_perf_stop(); + mutex_unlock(&oprofile_perf_mutex); + return 0; +} + +static int oprofile_perf_resume(struct platform_device *dev) +{ + mutex_lock(&oprofile_perf_mutex); + if (oprofile_perf_enabled && op_perf_start()) + oprofile_perf_enabled = 0; + mutex_unlock(&oprofile_perf_mutex); + return 0; +} + +static struct platform_driver oprofile_driver = { + .driver = { + .name = "oprofile-perf", + }, + .resume = oprofile_perf_resume, + .suspend = oprofile_perf_suspend, +}; + +static struct platform_device *oprofile_pdev; + +static int __init init_driverfs(void) +{ + int ret; + + ret = platform_driver_register(&oprofile_driver); + if (ret) + return ret; + + oprofile_pdev = platform_device_register_simple( + oprofile_driver.driver.name, 0, NULL, 0); + if (IS_ERR(oprofile_pdev)) { + ret = PTR_ERR(oprofile_pdev); + platform_driver_unregister(&oprofile_driver); + } + + return ret; +} + +static void exit_driverfs(void) +{ + platform_device_unregister(oprofile_pdev); + platform_driver_unregister(&oprofile_driver); +} + +#else + +static inline int init_driverfs(void) { return 0; } +static inline void exit_driverfs(void) { } + +#endif /* CONFIG_PM */ + +void oprofile_perf_exit(void) +{ + int cpu, id; + struct perf_event *event; + + for_each_possible_cpu(cpu) { + for (id = 0; id < num_counters; ++id) { + event = perf_events[cpu][id]; + if (event) + perf_event_release_kernel(event); + } + + kfree(perf_events[cpu]); + } + + kfree(counter_config); + exit_driverfs(); +} + +int __init oprofile_perf_init(struct oprofile_operations *ops) +{ + int cpu, ret = 0; + + ret = init_driverfs(); + if (ret) + return ret; + + memset(&perf_events, 0, sizeof(perf_events)); + + num_counters = perf_num_counters(); + if (num_counters <= 0) { + pr_info("oprofile: no performance counters\n"); + ret = -ENODEV; + goto out; + } + + counter_config = kcalloc(num_counters, + sizeof(struct op_counter_config), GFP_KERNEL); + + if (!counter_config) { + pr_info("oprofile: failed to allocate %d " + "counters\n", num_counters); + ret = -ENOMEM; + num_counters = 0; + goto out; + } + + for_each_possible_cpu(cpu) { + perf_events[cpu] = kcalloc(num_counters, + sizeof(struct perf_event *), GFP_KERNEL); + if (!perf_events[cpu]) { + pr_info("oprofile: failed to allocate %d perf events " + "for cpu %d\n", num_counters, cpu); + ret = -ENOMEM; + goto out; + } + } + + ops->create_files = oprofile_perf_create_files; + ops->setup = oprofile_perf_setup; + ops->start = oprofile_perf_start; + ops->stop = oprofile_perf_stop; + ops->shutdown = oprofile_perf_stop; + ops->cpu_type = op_name_from_perf_id(); + + if (!ops->cpu_type) + ret = -ENODEV; + else + pr_info("oprofile: using %s\n", ops->cpu_type); + +out: + if (ret) + oprofile_perf_exit(); + + return ret; +} diff --git a/drivers/oprofile/oprofilefs.c b/drivers/oprofile/oprofilefs.c index 2766a6d3c2e9..95f711b251ad 100644 --- a/drivers/oprofile/oprofilefs.c +++ b/drivers/oprofile/oprofilefs.c @@ -91,16 +91,20 @@ static ssize_t ulong_read_file(struct file *file, char __user *buf, size_t count static ssize_t ulong_write_file(struct file *file, char const __user *buf, size_t count, loff_t *offset) { - unsigned long *value = file->private_data; + unsigned long value; int retval; if (*offset) return -EINVAL; - retval = oprofilefs_ulong_from_user(value, buf, count); + retval = oprofilefs_ulong_from_user(&value, buf, count); + if (retval) + return retval; + retval = oprofile_set_ulong(file->private_data, value); if (retval) return retval; + return count; } @@ -117,59 +121,52 @@ static const struct file_operations ulong_fops = { .read = ulong_read_file, .write = ulong_write_file, .open = default_open, + .llseek = default_llseek, }; static const struct file_operations ulong_ro_fops = { .read = ulong_read_file, .open = default_open, + .llseek = default_llseek, }; -static struct dentry *__oprofilefs_create_file(struct super_block *sb, +static int __oprofilefs_create_file(struct super_block *sb, struct dentry *root, char const *name, const struct file_operations *fops, - int perm) + int perm, void *priv) { struct dentry *dentry; struct inode *inode; dentry = d_alloc_name(root, name); if (!dentry) - return NULL; + return -ENOMEM; inode = oprofilefs_get_inode(sb, S_IFREG | perm); if (!inode) { dput(dentry); - return NULL; + return -ENOMEM; } inode->i_fop = fops; d_add(dentry, inode); - return dentry; + dentry->d_inode->i_private = priv; + return 0; } int oprofilefs_create_ulong(struct super_block *sb, struct dentry *root, char const *name, unsigned long *val) { - struct dentry *d = __oprofilefs_create_file(sb, root, name, - &ulong_fops, 0644); - if (!d) - return -EFAULT; - - d->d_inode->i_private = val; - return 0; + return __oprofilefs_create_file(sb, root, name, + &ulong_fops, 0644, val); } int oprofilefs_create_ro_ulong(struct super_block *sb, struct dentry *root, char const *name, unsigned long *val) { - struct dentry *d = __oprofilefs_create_file(sb, root, name, - &ulong_ro_fops, 0444); - if (!d) - return -EFAULT; - - d->d_inode->i_private = val; - return 0; + return __oprofilefs_create_file(sb, root, name, + &ulong_ro_fops, 0444, val); } @@ -183,37 +180,29 @@ static ssize_t atomic_read_file(struct file *file, char __user *buf, size_t coun static const struct file_operations atomic_ro_fops = { .read = atomic_read_file, .open = default_open, + .llseek = default_llseek, }; int oprofilefs_create_ro_atomic(struct super_block *sb, struct dentry *root, char const *name, atomic_t *val) { - struct dentry *d = __oprofilefs_create_file(sb, root, name, - &atomic_ro_fops, 0444); - if (!d) - return -EFAULT; - - d->d_inode->i_private = val; - return 0; + return __oprofilefs_create_file(sb, root, name, + &atomic_ro_fops, 0444, val); } int oprofilefs_create_file(struct super_block *sb, struct dentry *root, char const *name, const struct file_operations *fops) { - if (!__oprofilefs_create_file(sb, root, name, fops, 0644)) - return -EFAULT; - return 0; + return __oprofilefs_create_file(sb, root, name, fops, 0644, NULL); } int oprofilefs_create_file_perm(struct super_block *sb, struct dentry *root, char const *name, const struct file_operations *fops, int perm) { - if (!__oprofilefs_create_file(sb, root, name, fops, perm)) - return -EFAULT; - return 0; + return __oprofilefs_create_file(sb, root, name, fops, perm, NULL); } diff --git a/drivers/parport/parport_cs.c b/drivers/parport/parport_cs.c index 23e50f4a27c5..787ebdeae310 100644 --- a/drivers/parport/parport_cs.c +++ b/drivers/parport/parport_cs.c @@ -48,7 +48,6 @@ #include <linux/parport.h> #include <linux/parport_pc.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/ds.h> #include <pcmcia/cisreg.h> @@ -81,14 +80,6 @@ static void parport_detach(struct pcmcia_device *p_dev); static int parport_config(struct pcmcia_device *link); static void parport_cs_release(struct pcmcia_device *); -/*====================================================================== - - parport_attach() creates an "instance" of the driver, allocating - local data structures for one device. The device is registered - with Card Services. - -======================================================================*/ - static int parport_probe(struct pcmcia_device *link) { parport_info_t *info; @@ -101,23 +92,11 @@ static int parport_probe(struct pcmcia_device *link) link->priv = info; info->p_dev = link; - link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; - link->resource[1]->flags |= IO_DATA_PATH_WIDTH_8; - link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.IntType = INT_MEMORY_AND_IO; + link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; return parport_config(link); } /* parport_attach */ -/*====================================================================== - - This deletes a driver "instance". The device is de-registered - with Card Services. If it has been released, all local data - structures are freed. Otherwise, the structures will be freed - when the device is released. - -======================================================================*/ - static void parport_detach(struct pcmcia_device *link) { dev_dbg(&link->dev, "parport_detach\n"); @@ -127,36 +106,14 @@ static void parport_detach(struct pcmcia_device *link) kfree(link->priv); } /* parport_detach */ -/*====================================================================== - - parport_config() is scheduled to run after a CARD_INSERTION event - is received, to configure the PCMCIA socket, and to make the - parport device available to the system. - -======================================================================*/ - -static int parport_config_check(struct pcmcia_device *p_dev, - cistpl_cftable_entry_t *cfg, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, - void *priv_data) +static int parport_config_check(struct pcmcia_device *p_dev, void *priv_data) { - if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) { - cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io; - p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK; - if (epp_mode) - p_dev->conf.ConfigIndex |= FORCE_EPP_MODE; - p_dev->resource[0]->start = io->win[0].base; - p_dev->resource[0]->end = io->win[0].len; - if (io->nwin == 2) { - p_dev->resource[1]->start = io->win[1].base; - p_dev->resource[1]->end = io->win[1].len; - } - if (pcmcia_request_io(p_dev) != 0) - return -ENODEV; - return 0; - } - return -ENODEV; + p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; + p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; + p_dev->resource[1]->flags &= ~IO_DATA_PATH_WIDTH; + p_dev->resource[1]->flags |= IO_DATA_PATH_WIDTH_8; + + return pcmcia_request_io(p_dev); } static int parport_config(struct pcmcia_device *link) @@ -167,13 +124,16 @@ static int parport_config(struct pcmcia_device *link) dev_dbg(&link->dev, "parport_config\n"); + if (epp_mode) + link->config_index |= FORCE_EPP_MODE; + ret = pcmcia_loop_config(link, parport_config_check, NULL); if (ret) goto failed; if (!link->irq) goto failed; - ret = pcmcia_request_configuration(link, &link->conf); + ret = pcmcia_enable_device(link); if (ret) goto failed; @@ -202,14 +162,6 @@ failed: return -ENODEV; } /* parport_config */ -/*====================================================================== - - After a card is removed, parport_cs_release() will unregister the - device, and release the PCMCIA configuration. If the device is - still open, this will be postponed until it is closed. - -======================================================================*/ - static void parport_cs_release(struct pcmcia_device *link) { parport_info_t *info = link->priv; @@ -236,9 +188,7 @@ MODULE_DEVICE_TABLE(pcmcia, parport_ids); static struct pcmcia_driver parport_cs_driver = { .owner = THIS_MODULE, - .drv = { - .name = "parport_cs", - }, + .name = "parport_cs", .probe = parport_probe, .remove = parport_detach, .id_table = parport_ids, diff --git a/drivers/parport/share.c b/drivers/parport/share.c index dffa5d4fb298..a2d9d1e59260 100644 --- a/drivers/parport/share.c +++ b/drivers/parport/share.c @@ -306,7 +306,7 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma, spin_lock_init(&tmp->pardevice_lock); tmp->ieee1284.mode = IEEE1284_MODE_COMPAT; tmp->ieee1284.phase = IEEE1284_PH_FWD_IDLE; - init_MUTEX_LOCKED (&tmp->ieee1284.irq); /* actually a semaphore at 0 */ + sema_init(&tmp->ieee1284.irq, 0); tmp->spintime = parport_default_spintime; atomic_set (&tmp->ref_count, 1); INIT_LIST_HEAD(&tmp->full_list); diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c index 0a19708074c2..0157708d474d 100644 --- a/drivers/pci/dmar.c +++ b/drivers/pci/dmar.c @@ -36,6 +36,7 @@ #include <linux/tboot.h> #include <linux/dmi.h> #include <linux/slab.h> +#include <asm/iommu_table.h> #define PREFIX "DMAR: " @@ -687,7 +688,7 @@ failed: return 0; } -void __init detect_intel_iommu(void) +int __init detect_intel_iommu(void) { int ret; @@ -723,6 +724,8 @@ void __init detect_intel_iommu(void) } early_acpi_os_unmap_memory(dmar_tbl, dmar_tbl_size); dmar_tbl = NULL; + + return ret ? 1 : -ENODEV; } @@ -1221,9 +1224,9 @@ const char *dmar_get_fault_reason(u8 fault_reason, int *fault_type) } } -void dmar_msi_unmask(unsigned int irq) +void dmar_msi_unmask(struct irq_data *data) { - struct intel_iommu *iommu = get_irq_data(irq); + struct intel_iommu *iommu = irq_data_get_irq_data(data); unsigned long flag; /* unmask it */ @@ -1234,10 +1237,10 @@ void dmar_msi_unmask(unsigned int irq) spin_unlock_irqrestore(&iommu->register_lock, flag); } -void dmar_msi_mask(unsigned int irq) +void dmar_msi_mask(struct irq_data *data) { unsigned long flag; - struct intel_iommu *iommu = get_irq_data(irq); + struct intel_iommu *iommu = irq_data_get_irq_data(data); /* mask it */ spin_lock_irqsave(&iommu->register_lock, flag); @@ -1455,3 +1458,4 @@ int __init dmar_ir_support(void) return 0; return dmar->flags & 0x1; } +IOMMU_INIT_POST(detect_intel_iommu); diff --git a/drivers/pci/hotplug/cpqphp_sysfs.c b/drivers/pci/hotplug/cpqphp_sysfs.c index 56215322930a..4cb30447a486 100644 --- a/drivers/pci/hotplug/cpqphp_sysfs.c +++ b/drivers/pci/hotplug/cpqphp_sysfs.c @@ -34,10 +34,11 @@ #include <linux/workqueue.h> #include <linux/pci.h> #include <linux/pci_hotplug.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/debugfs.h> #include "cpqphp.h" +static DEFINE_MUTEX(cpqphp_mutex); static int show_ctrl (struct controller *ctrl, char *buf) { char *out = buf; @@ -147,7 +148,7 @@ static int open(struct inode *inode, struct file *file) struct ctrl_dbg *dbg; int retval = -ENOMEM; - lock_kernel(); + mutex_lock(&cpqphp_mutex); dbg = kmalloc(sizeof(*dbg), GFP_KERNEL); if (!dbg) goto exit; @@ -160,7 +161,7 @@ static int open(struct inode *inode, struct file *file) file->private_data = dbg; retval = 0; exit: - unlock_kernel(); + mutex_unlock(&cpqphp_mutex); return retval; } @@ -169,7 +170,7 @@ static loff_t lseek(struct file *file, loff_t off, int whence) struct ctrl_dbg *dbg; loff_t new = -1; - lock_kernel(); + mutex_lock(&cpqphp_mutex); dbg = file->private_data; switch (whence) { @@ -181,10 +182,10 @@ static loff_t lseek(struct file *file, loff_t off, int whence) break; } if (new < 0 || new > dbg->size) { - unlock_kernel(); + mutex_unlock(&cpqphp_mutex); return -EINVAL; } - unlock_kernel(); + mutex_unlock(&cpqphp_mutex); return (file->f_pos = new); } diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 73d513989263..838f571027b7 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -36,6 +36,7 @@ #include <linux/sched.h> /* signal_pending() */ #include <linux/pcieport_if.h> #include <linux/mutex.h> +#include <linux/workqueue.h> #define MY_NAME "pciehp" @@ -44,6 +45,7 @@ extern int pciehp_poll_time; extern int pciehp_debug; extern int pciehp_force; extern struct workqueue_struct *pciehp_wq; +extern struct workqueue_struct *pciehp_ordered_wq; #define dbg(format, arg...) \ do { \ diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index aa5f3ff629ff..7ac8358df8fd 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -43,6 +43,7 @@ int pciehp_poll_mode; int pciehp_poll_time; int pciehp_force; struct workqueue_struct *pciehp_wq; +struct workqueue_struct *pciehp_ordered_wq; #define DRIVER_VERSION "0.4" #define DRIVER_AUTHOR "Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>, Dely Sy <dely.l.sy@intel.com>" @@ -340,18 +341,33 @@ static int __init pcied_init(void) { int retval = 0; + pciehp_wq = alloc_workqueue("pciehp", 0, 0); + if (!pciehp_wq) + return -ENOMEM; + + pciehp_ordered_wq = alloc_ordered_workqueue("pciehp_ordered", 0); + if (!pciehp_ordered_wq) { + destroy_workqueue(pciehp_wq); + return -ENOMEM; + } + pciehp_firmware_init(); retval = pcie_port_service_register(&hpdriver_portdrv); dbg("pcie_port_service_register = %d\n", retval); info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); - if (retval) + if (retval) { + destroy_workqueue(pciehp_ordered_wq); + destroy_workqueue(pciehp_wq); dbg("Failure to register service\n"); + } return retval; } static void __exit pcied_cleanup(void) { dbg("unload_pciehpd()\n"); + destroy_workqueue(pciehp_ordered_wq); + destroy_workqueue(pciehp_wq); pcie_port_service_unregister(&hpdriver_portdrv); info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n"); } diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index 8f58148be044..085dbb5fc168 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c @@ -32,7 +32,6 @@ #include <linux/types.h> #include <linux/slab.h> #include <linux/pci.h> -#include <linux/workqueue.h> #include "../pci.h" #include "pciehp.h" @@ -50,7 +49,7 @@ static int queue_interrupt_event(struct slot *p_slot, u32 event_type) info->p_slot = p_slot; INIT_WORK(&info->work, interrupt_event_handler); - schedule_work(&info->work); + queue_work(pciehp_wq, &info->work); return 0; } @@ -345,7 +344,7 @@ void pciehp_queue_pushbutton_work(struct work_struct *work) kfree(info); goto out; } - queue_work(pciehp_wq, &info->work); + queue_work(pciehp_ordered_wq, &info->work); out: mutex_unlock(&p_slot->lock); } @@ -378,7 +377,7 @@ static void handle_button_press_event(struct slot *p_slot) if (ATTN_LED(ctrl)) pciehp_set_attention_status(p_slot, 0); - schedule_delayed_work(&p_slot->work, 5*HZ); + queue_delayed_work(pciehp_wq, &p_slot->work, 5*HZ); break; case BLINKINGOFF_STATE: case BLINKINGON_STATE: @@ -440,7 +439,7 @@ static void handle_surprise_event(struct slot *p_slot) else p_slot->state = POWERON_STATE; - queue_work(pciehp_wq, &info->work); + queue_work(pciehp_ordered_wq, &info->work); } static void interrupt_event_handler(struct work_struct *work) diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 0cd42047d89b..50a23da5d24d 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -41,8 +41,6 @@ #include "../pci.h" #include "pciehp.h" -static atomic_t pciehp_num_controllers = ATOMIC_INIT(0); - static inline int pciehp_readw(struct controller *ctrl, int reg, u16 *value) { struct pci_dev *dev = ctrl->pcie->port; @@ -805,8 +803,8 @@ static void pcie_cleanup_slot(struct controller *ctrl) { struct slot *slot = ctrl->slot; cancel_delayed_work(&slot->work); - flush_scheduled_work(); flush_workqueue(pciehp_wq); + flush_workqueue(pciehp_ordered_wq); kfree(slot); } @@ -912,16 +910,6 @@ struct controller *pcie_init(struct pcie_device *dev) /* Disable sotfware notification */ pcie_disable_notification(ctrl); - /* - * If this is the first controller to be initialized, - * initialize the pciehp work queue - */ - if (atomic_add_return(1, &pciehp_num_controllers) == 1) { - pciehp_wq = create_singlethread_workqueue("pciehpd"); - if (!pciehp_wq) - goto abort_ctrl; - } - ctrl_info(ctrl, "HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, pdev->subsystem_vendor, pdev->subsystem_device); @@ -941,11 +929,5 @@ void pciehp_release_ctrl(struct controller *ctrl) { pcie_shutdown_notification(ctrl); pcie_cleanup_slot(ctrl); - /* - * If this is the last controller to be released, destroy the - * pciehp work queue - */ - if (atomic_dec_and_test(&pciehp_num_controllers)) - destroy_workqueue(pciehp_wq); kfree(ctrl); } diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h index d2627e1c3ac1..e0c90e643b5f 100644 --- a/drivers/pci/hotplug/shpchp.h +++ b/drivers/pci/hotplug/shpchp.h @@ -35,6 +35,7 @@ #include <linux/delay.h> #include <linux/sched.h> /* signal_pending(), struct timer_list */ #include <linux/mutex.h> +#include <linux/workqueue.h> #if !defined(MODULE) #define MY_NAME "shpchp" @@ -46,6 +47,7 @@ extern int shpchp_poll_mode; extern int shpchp_poll_time; extern int shpchp_debug; extern struct workqueue_struct *shpchp_wq; +extern struct workqueue_struct *shpchp_ordered_wq; #define dbg(format, arg...) \ do { \ diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c index a7bd5048396e..aca972bbfb4c 100644 --- a/drivers/pci/hotplug/shpchp_core.c +++ b/drivers/pci/hotplug/shpchp_core.c @@ -33,7 +33,6 @@ #include <linux/types.h> #include <linux/slab.h> #include <linux/pci.h> -#include <linux/workqueue.h> #include "shpchp.h" /* Global variables */ @@ -41,6 +40,7 @@ int shpchp_debug; int shpchp_poll_mode; int shpchp_poll_time; struct workqueue_struct *shpchp_wq; +struct workqueue_struct *shpchp_ordered_wq; #define DRIVER_VERSION "0.4" #define DRIVER_AUTHOR "Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>, Dely Sy <dely.l.sy@intel.com>" @@ -174,8 +174,8 @@ void cleanup_slots(struct controller *ctrl) slot = list_entry(tmp, struct slot, slot_list); list_del(&slot->slot_list); cancel_delayed_work(&slot->work); - flush_scheduled_work(); flush_workqueue(shpchp_wq); + flush_workqueue(shpchp_ordered_wq); pci_hp_deregister(slot->hotplug_slot); } } @@ -360,9 +360,23 @@ static int __init shpcd_init(void) { int retval = 0; + shpchp_wq = alloc_ordered_workqueue("shpchp", 0); + if (!shpchp_wq) + return -ENOMEM; + + shpchp_ordered_wq = alloc_ordered_workqueue("shpchp_ordered", 0); + if (!shpchp_ordered_wq) { + destroy_workqueue(shpchp_wq); + return -ENOMEM; + } + retval = pci_register_driver(&shpc_driver); dbg("%s: pci_register_driver = %d\n", __func__, retval); info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); + if (retval) { + destroy_workqueue(shpchp_ordered_wq); + destroy_workqueue(shpchp_wq); + } return retval; } @@ -370,6 +384,8 @@ static void __exit shpcd_cleanup(void) { dbg("unload_shpchpd()\n"); pci_unregister_driver(&shpc_driver); + destroy_workqueue(shpchp_ordered_wq); + destroy_workqueue(shpchp_wq); info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n"); } diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c index 3387fbfb0c54..b00b09bdd38a 100644 --- a/drivers/pci/hotplug/shpchp_ctrl.c +++ b/drivers/pci/hotplug/shpchp_ctrl.c @@ -32,7 +32,6 @@ #include <linux/types.h> #include <linux/slab.h> #include <linux/pci.h> -#include <linux/workqueue.h> #include "../pci.h" #include "shpchp.h" @@ -52,7 +51,7 @@ static int queue_interrupt_event(struct slot *p_slot, u32 event_type) info->p_slot = p_slot; INIT_WORK(&info->work, interrupt_event_handler); - schedule_work(&info->work); + queue_work(shpchp_wq, &info->work); return 0; } @@ -457,7 +456,7 @@ void shpchp_queue_pushbutton_work(struct work_struct *work) kfree(info); goto out; } - queue_work(shpchp_wq, &info->work); + queue_work(shpchp_ordered_wq, &info->work); out: mutex_unlock(&p_slot->lock); } @@ -505,7 +504,7 @@ static void handle_button_press_event(struct slot *p_slot) p_slot->hpc_ops->green_led_blink(p_slot); p_slot->hpc_ops->set_attention_status(p_slot, 0); - schedule_delayed_work(&p_slot->work, 5*HZ); + queue_delayed_work(shpchp_wq, &p_slot->work, 5*HZ); break; case BLINKINGOFF_STATE: case BLINKINGON_STATE: diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c index d3985e7deab7..36547f0ce305 100644 --- a/drivers/pci/hotplug/shpchp_hpc.c +++ b/drivers/pci/hotplug/shpchp_hpc.c @@ -179,8 +179,6 @@ #define SLOT_EVENT_LATCH 0x2 #define SLOT_SERR_INT_MASK 0x3 -static atomic_t shpchp_num_controllers = ATOMIC_INIT(0); - static irqreturn_t shpc_isr(int irq, void *dev_id); static void start_int_poll_timer(struct controller *ctrl, int sec); static int hpc_check_cmd_status(struct controller *ctrl); @@ -614,13 +612,6 @@ static void hpc_release_ctlr(struct controller *ctrl) iounmap(ctrl->creg); release_mem_region(ctrl->mmio_base, ctrl->mmio_size); - - /* - * If this is the last controller to be released, destroy the - * shpchpd work queue - */ - if (atomic_dec_and_test(&shpchp_num_controllers)) - destroy_workqueue(shpchp_wq); } static int hpc_power_on_slot(struct slot * slot) @@ -1077,9 +1068,8 @@ int shpc_init(struct controller *ctrl, struct pci_dev *pdev) rc = request_irq(ctrl->pci_dev->irq, shpc_isr, IRQF_SHARED, MY_NAME, (void *)ctrl); - ctrl_dbg(ctrl, "request_irq %d for hpc%d (returns %d)\n", - ctrl->pci_dev->irq, - atomic_read(&shpchp_num_controllers), rc); + ctrl_dbg(ctrl, "request_irq %d (returns %d)\n", + ctrl->pci_dev->irq, rc); if (rc) { ctrl_err(ctrl, "Can't get irq %d for the hotplug " "controller\n", ctrl->pci_dev->irq); @@ -1092,18 +1082,6 @@ int shpc_init(struct controller *ctrl, struct pci_dev *pdev) shpc_get_cur_bus_speed(ctrl); /* - * If this is the first controller to be initialized, - * initialize the shpchpd work queue - */ - if (atomic_add_return(1, &shpchp_num_controllers) == 1) { - shpchp_wq = create_singlethread_workqueue("shpchpd"); - if (!shpchp_wq) { - rc = -ENOMEM; - goto abort_iounmap; - } - } - - /* * Unmask all event interrupts of all slots */ for (hp_slot = 0; hp_slot < ctrl->num_slots; hp_slot++) { diff --git a/drivers/pci/htirq.c b/drivers/pci/htirq.c index 98abf8b91294..834842aa5bbf 100644 --- a/drivers/pci/htirq.c +++ b/drivers/pci/htirq.c @@ -57,28 +57,22 @@ void fetch_ht_irq_msg(unsigned int irq, struct ht_irq_msg *msg) *msg = cfg->msg; } -void mask_ht_irq(unsigned int irq) +void mask_ht_irq(struct irq_data *data) { - struct ht_irq_cfg *cfg; - struct ht_irq_msg msg; - - cfg = get_irq_data(irq); + struct ht_irq_cfg *cfg = irq_data_get_irq_data(data); + struct ht_irq_msg msg = cfg->msg; - msg = cfg->msg; msg.address_lo |= 1; - write_ht_irq_msg(irq, &msg); + write_ht_irq_msg(data->irq, &msg); } -void unmask_ht_irq(unsigned int irq) +void unmask_ht_irq(struct irq_data *data) { - struct ht_irq_cfg *cfg; - struct ht_irq_msg msg; - - cfg = get_irq_data(irq); + struct ht_irq_cfg *cfg = irq_data_get_irq_data(data); + struct ht_irq_msg msg = cfg->msg; - msg = cfg->msg; msg.address_lo &= ~1; - write_ht_irq_msg(irq, &msg); + write_ht_irq_msg(data->irq, &msg); } /** diff --git a/drivers/pci/intr_remapping.c b/drivers/pci/intr_remapping.c index fd1d2867cdcc..ec87cd66f3eb 100644 --- a/drivers/pci/intr_remapping.c +++ b/drivers/pci/intr_remapping.c @@ -46,109 +46,24 @@ static __init int setup_intremap(char *str) } early_param("intremap", setup_intremap); -struct irq_2_iommu { - struct intel_iommu *iommu; - u16 irte_index; - u16 sub_handle; - u8 irte_mask; -}; - -#ifdef CONFIG_GENERIC_HARDIRQS -static struct irq_2_iommu *get_one_free_irq_2_iommu(int node) -{ - struct irq_2_iommu *iommu; - - iommu = kzalloc_node(sizeof(*iommu), GFP_ATOMIC, node); - printk(KERN_DEBUG "alloc irq_2_iommu on node %d\n", node); - - return iommu; -} - -static struct irq_2_iommu *irq_2_iommu(unsigned int irq) -{ - struct irq_desc *desc; - - desc = irq_to_desc(irq); - - if (WARN_ON_ONCE(!desc)) - return NULL; - - return desc->irq_2_iommu; -} - -static struct irq_2_iommu *irq_2_iommu_alloc(unsigned int irq) -{ - struct irq_desc *desc; - struct irq_2_iommu *irq_iommu; - - desc = irq_to_desc(irq); - if (!desc) { - printk(KERN_INFO "can not get irq_desc for %d\n", irq); - return NULL; - } - - irq_iommu = desc->irq_2_iommu; - - if (!irq_iommu) - desc->irq_2_iommu = get_one_free_irq_2_iommu(irq_node(irq)); - - return desc->irq_2_iommu; -} - -#else /* !CONFIG_SPARSE_IRQ */ - -static struct irq_2_iommu irq_2_iommuX[NR_IRQS]; - -static struct irq_2_iommu *irq_2_iommu(unsigned int irq) -{ - if (irq < nr_irqs) - return &irq_2_iommuX[irq]; - - return NULL; -} -static struct irq_2_iommu *irq_2_iommu_alloc(unsigned int irq) -{ - return irq_2_iommu(irq); -} -#endif - static DEFINE_SPINLOCK(irq_2_ir_lock); -static struct irq_2_iommu *valid_irq_2_iommu(unsigned int irq) -{ - struct irq_2_iommu *irq_iommu; - - irq_iommu = irq_2_iommu(irq); - - if (!irq_iommu) - return NULL; - - if (!irq_iommu->iommu) - return NULL; - - return irq_iommu; -} - -int irq_remapped(int irq) +static struct irq_2_iommu *irq_2_iommu(unsigned int irq) { - return valid_irq_2_iommu(irq) != NULL; + struct irq_cfg *cfg = get_irq_chip_data(irq); + return cfg ? &cfg->irq_2_iommu : NULL; } int get_irte(int irq, struct irte *entry) { - int index; - struct irq_2_iommu *irq_iommu; + struct irq_2_iommu *irq_iommu = irq_2_iommu(irq); unsigned long flags; + int index; - if (!entry) + if (!entry || !irq_iommu) return -1; spin_lock_irqsave(&irq_2_ir_lock, flags); - irq_iommu = valid_irq_2_iommu(irq); - if (!irq_iommu) { - spin_unlock_irqrestore(&irq_2_ir_lock, flags); - return -1; - } index = irq_iommu->irte_index + irq_iommu->sub_handle; *entry = *(irq_iommu->iommu->ir_table->base + index); @@ -160,20 +75,14 @@ int get_irte(int irq, struct irte *entry) int alloc_irte(struct intel_iommu *iommu, int irq, u16 count) { struct ir_table *table = iommu->ir_table; - struct irq_2_iommu *irq_iommu; + struct irq_2_iommu *irq_iommu = irq_2_iommu(irq); u16 index, start_index; unsigned int mask = 0; unsigned long flags; int i; - if (!count) - return -1; - -#ifndef CONFIG_SPARSE_IRQ - /* protect irq_2_iommu_alloc later */ - if (irq >= nr_irqs) + if (!count || !irq_iommu) return -1; -#endif /* * start the IRTE search from index 0. @@ -214,13 +123,6 @@ int alloc_irte(struct intel_iommu *iommu, int irq, u16 count) for (i = index; i < index + count; i++) table->base[i].present = 1; - irq_iommu = irq_2_iommu_alloc(irq); - if (!irq_iommu) { - spin_unlock_irqrestore(&irq_2_ir_lock, flags); - printk(KERN_ERR "can't allocate irq_2_iommu\n"); - return -1; - } - irq_iommu->iommu = iommu; irq_iommu->irte_index = index; irq_iommu->sub_handle = 0; @@ -244,17 +146,14 @@ static int qi_flush_iec(struct intel_iommu *iommu, int index, int mask) int map_irq_to_irte_handle(int irq, u16 *sub_handle) { - int index; - struct irq_2_iommu *irq_iommu; + struct irq_2_iommu *irq_iommu = irq_2_iommu(irq); unsigned long flags; + int index; - spin_lock_irqsave(&irq_2_ir_lock, flags); - irq_iommu = valid_irq_2_iommu(irq); - if (!irq_iommu) { - spin_unlock_irqrestore(&irq_2_ir_lock, flags); + if (!irq_iommu) return -1; - } + spin_lock_irqsave(&irq_2_ir_lock, flags); *sub_handle = irq_iommu->sub_handle; index = irq_iommu->irte_index; spin_unlock_irqrestore(&irq_2_ir_lock, flags); @@ -263,18 +162,13 @@ int map_irq_to_irte_handle(int irq, u16 *sub_handle) int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subhandle) { - struct irq_2_iommu *irq_iommu; + struct irq_2_iommu *irq_iommu = irq_2_iommu(irq); unsigned long flags; - spin_lock_irqsave(&irq_2_ir_lock, flags); - - irq_iommu = irq_2_iommu_alloc(irq); - - if (!irq_iommu) { - spin_unlock_irqrestore(&irq_2_ir_lock, flags); - printk(KERN_ERR "can't allocate irq_2_iommu\n"); + if (!irq_iommu) return -1; - } + + spin_lock_irqsave(&irq_2_ir_lock, flags); irq_iommu->iommu = iommu; irq_iommu->irte_index = index; @@ -286,43 +180,18 @@ int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subhandle) return 0; } -int clear_irte_irq(int irq, struct intel_iommu *iommu, u16 index) -{ - struct irq_2_iommu *irq_iommu; - unsigned long flags; - - spin_lock_irqsave(&irq_2_ir_lock, flags); - irq_iommu = valid_irq_2_iommu(irq); - if (!irq_iommu) { - spin_unlock_irqrestore(&irq_2_ir_lock, flags); - return -1; - } - - irq_iommu->iommu = NULL; - irq_iommu->irte_index = 0; - irq_iommu->sub_handle = 0; - irq_2_iommu(irq)->irte_mask = 0; - - spin_unlock_irqrestore(&irq_2_ir_lock, flags); - - return 0; -} - int modify_irte(int irq, struct irte *irte_modified) { - int rc; - int index; - struct irte *irte; + struct irq_2_iommu *irq_iommu = irq_2_iommu(irq); struct intel_iommu *iommu; - struct irq_2_iommu *irq_iommu; unsigned long flags; + struct irte *irte; + int rc, index; - spin_lock_irqsave(&irq_2_ir_lock, flags); - irq_iommu = valid_irq_2_iommu(irq); - if (!irq_iommu) { - spin_unlock_irqrestore(&irq_2_ir_lock, flags); + if (!irq_iommu) return -1; - } + + spin_lock_irqsave(&irq_2_ir_lock, flags); iommu = irq_iommu->iommu; @@ -339,31 +208,6 @@ int modify_irte(int irq, struct irte *irte_modified) return rc; } -int flush_irte(int irq) -{ - int rc; - int index; - struct intel_iommu *iommu; - struct irq_2_iommu *irq_iommu; - unsigned long flags; - - spin_lock_irqsave(&irq_2_ir_lock, flags); - irq_iommu = valid_irq_2_iommu(irq); - if (!irq_iommu) { - spin_unlock_irqrestore(&irq_2_ir_lock, flags); - return -1; - } - - iommu = irq_iommu->iommu; - - index = irq_iommu->irte_index + irq_iommu->sub_handle; - - rc = qi_flush_iec(iommu, index, irq_iommu->irte_mask); - spin_unlock_irqrestore(&irq_2_ir_lock, flags); - - return rc; -} - struct intel_iommu *map_hpet_to_ir(u8 hpet_id) { int i; @@ -420,16 +264,14 @@ static int clear_entries(struct irq_2_iommu *irq_iommu) int free_irte(int irq) { - int rc = 0; - struct irq_2_iommu *irq_iommu; + struct irq_2_iommu *irq_iommu = irq_2_iommu(irq); unsigned long flags; + int rc; - spin_lock_irqsave(&irq_2_ir_lock, flags); - irq_iommu = valid_irq_2_iommu(irq); - if (!irq_iommu) { - spin_unlock_irqrestore(&irq_2_ir_lock, flags); + if (!irq_iommu) return -1; - } + + spin_lock_irqsave(&irq_2_ir_lock, flags); rc = clear_entries(irq_iommu); diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 69b7be33b3a2..5fcf5aec680f 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -170,33 +170,31 @@ static void msix_mask_irq(struct msi_desc *desc, u32 flag) desc->masked = __msix_mask_irq(desc, flag); } -static void msi_set_mask_bit(unsigned irq, u32 flag) +static void msi_set_mask_bit(struct irq_data *data, u32 flag) { - struct msi_desc *desc = get_irq_msi(irq); + struct msi_desc *desc = irq_data_get_msi(data); if (desc->msi_attrib.is_msix) { msix_mask_irq(desc, flag); readl(desc->mask_base); /* Flush write to device */ } else { - unsigned offset = irq - desc->dev->irq; + unsigned offset = data->irq - desc->dev->irq; msi_mask_irq(desc, 1 << offset, flag << offset); } } -void mask_msi_irq(unsigned int irq) +void mask_msi_irq(struct irq_data *data) { - msi_set_mask_bit(irq, 1); + msi_set_mask_bit(data, 1); } -void unmask_msi_irq(unsigned int irq) +void unmask_msi_irq(struct irq_data *data) { - msi_set_mask_bit(irq, 0); + msi_set_mask_bit(data, 0); } -void read_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg) +void __read_msi_msg(struct msi_desc *entry, struct msi_msg *msg) { - struct msi_desc *entry = get_irq_desc_msi(desc); - BUG_ON(entry->dev->current_state != PCI_D0); if (entry->msi_attrib.is_msix) { @@ -227,15 +225,13 @@ void read_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg) void read_msi_msg(unsigned int irq, struct msi_msg *msg) { - struct irq_desc *desc = irq_to_desc(irq); + struct msi_desc *entry = get_irq_msi(irq); - read_msi_msg_desc(desc, msg); + __read_msi_msg(entry, msg); } -void get_cached_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg) +void __get_cached_msi_msg(struct msi_desc *entry, struct msi_msg *msg) { - struct msi_desc *entry = get_irq_desc_msi(desc); - /* Assert that the cache is valid, assuming that * valid messages are not all-zeroes. */ BUG_ON(!(entry->msg.address_hi | entry->msg.address_lo | @@ -246,15 +242,13 @@ void get_cached_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg) void get_cached_msi_msg(unsigned int irq, struct msi_msg *msg) { - struct irq_desc *desc = irq_to_desc(irq); + struct msi_desc *entry = get_irq_msi(irq); - get_cached_msi_msg_desc(desc, msg); + __get_cached_msi_msg(entry, msg); } -void write_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg) +void __write_msi_msg(struct msi_desc *entry, struct msi_msg *msg) { - struct msi_desc *entry = get_irq_desc_msi(desc); - if (entry->dev->current_state != PCI_D0) { /* Don't touch the hardware now */ } else if (entry->msi_attrib.is_msix) { @@ -292,9 +286,9 @@ void write_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg) void write_msi_msg(unsigned int irq, struct msi_msg *msg) { - struct irq_desc *desc = irq_to_desc(irq); + struct msi_desc *entry = get_irq_msi(irq); - write_msi_msg_desc(desc, msg); + __write_msi_msg(entry, msg); } static void free_msi_irqs(struct pci_dev *dev) diff --git a/drivers/pci/pcie/aer/aer_inject.c b/drivers/pci/pcie/aer/aer_inject.c index 909924692b8a..b3cf6223f63a 100644 --- a/drivers/pci/pcie/aer/aer_inject.c +++ b/drivers/pci/pcie/aer/aer_inject.c @@ -472,6 +472,7 @@ static ssize_t aer_inject_write(struct file *filp, const char __user *ubuf, static const struct file_operations aer_inject_fops = { .write = aer_inject_write, .owner = THIS_MODULE, + .llseek = noop_llseek, }; static struct miscdevice aer_inject_device = { diff --git a/drivers/pcmcia/au1000_generic.c b/drivers/pcmcia/au1000_generic.c index 88c4c4098789..95dd7c62741f 100644 --- a/drivers/pcmcia/au1000_generic.c +++ b/drivers/pcmcia/au1000_generic.c @@ -441,14 +441,12 @@ int au1x00_pcmcia_socket_probe(struct device *dev, struct pcmcia_low_level *ops, out_err: - flush_scheduled_work(); ops->hw_shutdown(skt); while (i-- > 0) { skt = PCMCIA_SOCKET(i); del_timer_sync(&skt->poll_timer); pcmcia_unregister_socket(&skt->socket); - flush_scheduled_work(); if (i == 0) { iounmap(skt->virt_io + (u32)mips_io_port_base); skt->virt_io = NULL; @@ -480,7 +478,6 @@ int au1x00_drv_pcmcia_remove(struct platform_device *dev) del_timer_sync(&skt->poll_timer); pcmcia_unregister_socket(&skt->socket); - flush_scheduled_work(); skt->ops->hw_shutdown(skt); au1x00_pcmcia_config_skt(skt, &dead_socket); iounmap(skt->virt_io + (u32)mips_io_port_base); diff --git a/drivers/pcmcia/au1000_generic.h b/drivers/pcmcia/au1000_generic.h index 67530cefcf3c..5c36bda2963b 100644 --- a/drivers/pcmcia/au1000_generic.h +++ b/drivers/pcmcia/au1000_generic.h @@ -23,7 +23,6 @@ /* include the world */ -#include <pcmcia/cs.h> #include <pcmcia/ss.h> #include <pcmcia/cistpl.h> #include "cs_internal.h" diff --git a/drivers/pcmcia/au1000_pb1x00.c b/drivers/pcmcia/au1000_pb1x00.c index 807f2d75dad3..b2396647a165 100644 --- a/drivers/pcmcia/au1000_pb1x00.c +++ b/drivers/pcmcia/au1000_pb1x00.c @@ -31,7 +31,6 @@ #include <linux/proc_fs.h> #include <linux/types.h> -#include <pcmcia/cs.h> #include <pcmcia/ss.h> #include <pcmcia/cistpl.h> diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c index 91414a0ddc44..884a984216fe 100644 --- a/drivers/pcmcia/cistpl.c +++ b/drivers/pcmcia/cistpl.c @@ -28,7 +28,6 @@ #include <asm/unaligned.h> #include <pcmcia/ss.h> -#include <pcmcia/cs.h> #include <pcmcia/cisreg.h> #include <pcmcia/cistpl.h> #include "cs_internal.h" diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index 2ec8ac97445c..d9ea192c4001 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -33,7 +33,6 @@ #include <asm/irq.h> #include <pcmcia/ss.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/cisreg.h> #include <pcmcia/ds.h> @@ -845,7 +844,7 @@ static int pcmcia_socket_dev_resume_noirq(struct device *dev) return __pcmcia_pm_op(dev, socket_early_resume); } -static int pcmcia_socket_dev_resume(struct device *dev) +static int __used pcmcia_socket_dev_resume(struct device *dev) { return __pcmcia_pm_op(dev, socket_late_resume); } diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h index da055dc14d98..7f1953f78b12 100644 --- a/drivers/pcmcia/cs_internal.h +++ b/drivers/pcmcia/cs_internal.h @@ -33,18 +33,9 @@ typedef struct config_t { struct kref ref; unsigned int state; - unsigned int Attributes; - unsigned int IntType; - unsigned int ConfigBase; - unsigned char Status, Pin, Copy, Option, ExtStatus; - unsigned int CardValues; struct resource io[MAX_IO_WIN]; /* io ports */ struct resource mem[MAX_WIN]; /* mem areas */ - - struct { - u_int Attributes; - } irq; } config_t; diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 55570d9e1e4c..100c4412457d 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -26,7 +26,6 @@ #include <linux/dma-mapping.h> #include <linux/slab.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/ds.h> #include <pcmcia/ss.h> @@ -52,7 +51,7 @@ static void pcmcia_check_driver(struct pcmcia_driver *p_drv) if (!p_drv->probe || !p_drv->remove) printk(KERN_DEBUG "pcmcia: %s lacks a requisite callback " - "function\n", p_drv->drv.name); + "function\n", p_drv->name); while (did && did->match_flags) { for (i = 0; i < 4; i++) { @@ -65,7 +64,7 @@ static void pcmcia_check_driver(struct pcmcia_driver *p_drv) printk(KERN_DEBUG "pcmcia: %s: invalid hash for " "product string \"%s\": is 0x%x, should " - "be 0x%x\n", p_drv->drv.name, did->prod_id[i], + "be 0x%x\n", p_drv->name, did->prod_id[i], did->prod_id_hash[i], hash); printk(KERN_DEBUG "pcmcia: see " "Documentation/pcmcia/devicetable.txt for " @@ -180,10 +179,11 @@ int pcmcia_register_driver(struct pcmcia_driver *driver) /* initialize common fields */ driver->drv.bus = &pcmcia_bus_type; driver->drv.owner = driver->owner; + driver->drv.name = driver->name; mutex_init(&driver->dynids.lock); INIT_LIST_HEAD(&driver->dynids.list); - pr_debug("registering driver %s\n", driver->drv.name); + pr_debug("registering driver %s\n", driver->name); error = driver_register(&driver->drv); if (error < 0) @@ -203,7 +203,7 @@ EXPORT_SYMBOL(pcmcia_register_driver); */ void pcmcia_unregister_driver(struct pcmcia_driver *driver) { - pr_debug("unregistering driver %s\n", driver->drv.name); + pr_debug("unregistering driver %s\n", driver->name); driver_unregister(&driver->drv); pcmcia_free_dynids(driver); } @@ -264,7 +264,7 @@ static int pcmcia_device_probe(struct device *dev) p_drv = to_pcmcia_drv(dev->driver); s = p_dev->socket; - dev_dbg(dev, "trying to bind to %s\n", p_drv->drv.name); + dev_dbg(dev, "trying to bind to %s\n", p_drv->name); if ((!p_drv->probe) || (!p_dev->function_config) || (!try_module_get(p_drv->owner))) { @@ -276,21 +276,28 @@ static int pcmcia_device_probe(struct device *dev) ret = pccard_read_tuple(p_dev->socket, p_dev->func, CISTPL_CONFIG, &cis_config); if (!ret) { - p_dev->conf.ConfigBase = cis_config.base; - p_dev->conf.Present = cis_config.rmask[0]; + p_dev->config_base = cis_config.base; + p_dev->config_regs = cis_config.rmask[0]; + dev_dbg(dev, "base %x, regs %x", p_dev->config_base, + p_dev->config_regs); } else { dev_printk(KERN_INFO, dev, "pcmcia: could not parse base and rmask0 of CIS\n"); - p_dev->conf.ConfigBase = 0; - p_dev->conf.Present = 0; + p_dev->config_base = 0; + p_dev->config_regs = 0; } ret = p_drv->probe(p_dev); if (ret) { dev_dbg(dev, "binding to %s failed with %d\n", - p_drv->drv.name, ret); + p_drv->name, ret); goto put_module; } + dev_dbg(dev, "%s bound: Vpp %d.%d, idx %x, IRQ %d", p_drv->name, + p_dev->vpp/10, p_dev->vpp%10, p_dev->config_index, p_dev->irq); + dev_dbg(dev, "resources: ioport %pR %pR iomem %pR %pR %pR", + p_dev->resource[0], p_dev->resource[1], p_dev->resource[2], + p_dev->resource[3], p_dev->resource[4]); mutex_lock(&s->ops_mutex); if ((s->pcmcia_pfc) && @@ -374,13 +381,13 @@ static int pcmcia_device_remove(struct device *dev) if (p_dev->_irq || p_dev->_io || p_dev->_locked) dev_printk(KERN_INFO, dev, "pcmcia: driver %s did not release config properly\n", - p_drv->drv.name); + p_drv->name); for (i = 0; i < MAX_WIN; i++) if (p_dev->_win & CLIENT_WIN_REQ(i)) dev_printk(KERN_INFO, dev, "pcmcia: driver %s did not release window properly\n", - p_drv->drv.name); + p_drv->name); /* references from pcmcia_probe_device */ pcmcia_put_dev(p_dev); @@ -1136,7 +1143,7 @@ static int pcmcia_dev_suspend(struct device *dev, pm_message_t state) dev_printk(KERN_ERR, dev, "pcmcia: device %s (driver %s) did " "not want to go to sleep (%d)\n", - p_dev->devname, p_drv->drv.name, ret); + p_dev->devname, p_drv->name, ret); mutex_lock(&p_dev->socket->ops_mutex); p_dev->suspended = 0; mutex_unlock(&p_dev->socket->ops_mutex); @@ -1178,7 +1185,7 @@ static int pcmcia_dev_resume(struct device *dev) if (p_dev->device_no == p_dev->func) { dev_dbg(dev, "requesting configuration\n"); - ret = pcmcia_request_configuration(p_dev, &p_dev->conf); + ret = pcmcia_enable_device(p_dev); if (ret) goto out; } diff --git a/drivers/pcmcia/i82092.c b/drivers/pcmcia/i82092.c index 05d0879ce935..fc7906eaf228 100644 --- a/drivers/pcmcia/i82092.c +++ b/drivers/pcmcia/i82092.c @@ -16,7 +16,6 @@ #include <linux/device.h> #include <pcmcia/ss.h> -#include <pcmcia/cs.h> #include <asm/system.h> #include <asm/io.h> diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c index 61746bd598b3..72a033a2acdb 100644 --- a/drivers/pcmcia/i82365.c +++ b/drivers/pcmcia/i82365.c @@ -51,7 +51,6 @@ #include <asm/system.h> #include <pcmcia/ss.h> -#include <pcmcia/cs.h> #include <linux/isapnp.h> diff --git a/drivers/pcmcia/m32r_cfc.c b/drivers/pcmcia/m32r_cfc.c index 24de49925863..2adb0106a039 100644 --- a/drivers/pcmcia/m32r_cfc.c +++ b/drivers/pcmcia/m32r_cfc.c @@ -27,7 +27,6 @@ #include <asm/system.h> #include <pcmcia/ss.h> -#include <pcmcia/cs.h> #undef MAX_IO_WIN /* FIXME */ #define MAX_IO_WIN 1 diff --git a/drivers/pcmcia/m32r_pcc.c b/drivers/pcmcia/m32r_pcc.c index 8e4723844ad3..1511ff71c87b 100644 --- a/drivers/pcmcia/m32r_pcc.c +++ b/drivers/pcmcia/m32r_pcc.c @@ -28,7 +28,6 @@ #include <asm/addrspace.h> #include <pcmcia/ss.h> -#include <pcmcia/cs.h> /* XXX: should be moved into asm/irq.h */ #define PCC0_IRQ 24 diff --git a/drivers/pcmcia/m8xx_pcmcia.c b/drivers/pcmcia/m8xx_pcmcia.c index f0ecad99ce81..99d4f23cb435 100644 --- a/drivers/pcmcia/m8xx_pcmcia.c +++ b/drivers/pcmcia/m8xx_pcmcia.c @@ -59,7 +59,6 @@ #include <asm/irq.h> #include <asm/fs_pd.h> -#include <pcmcia/cs.h> #include <pcmcia/ss.h> #define pcmcia_info(args...) printk(KERN_INFO "m8xx_pcmcia: "args) diff --git a/drivers/pcmcia/o2micro.h b/drivers/pcmcia/o2micro.h index e74bebac2695..5096e92c7a4c 100644 --- a/drivers/pcmcia/o2micro.h +++ b/drivers/pcmcia/o2micro.h @@ -153,14 +153,14 @@ static int o2micro_override(struct yenta_socket *socket) if (use_speedup) { dev_info(&socket->dev->dev, - "O2: enabling read prefetch/write burst\n"); + "O2: enabling read prefetch/write burst. If you experience problems or performance issues, use the yenta_socket parameter 'o2_speedup=off'\n"); config_writeb(socket, O2_RESERVED1, a | O2_RES_READ_PREFETCH | O2_RES_WRITE_BURST); config_writeb(socket, O2_RESERVED2, b | O2_RES_READ_PREFETCH | O2_RES_WRITE_BURST); } else { dev_info(&socket->dev->dev, - "O2: disabling read prefetch/write burst\n"); + "O2: disabling read prefetch/write burst. If you experience problems or performance issues, use the yenta_socket parameter 'o2_speedup=on'\n"); config_writeb(socket, O2_RESERVED1, a & ~(O2_RES_READ_PREFETCH | O2_RES_WRITE_BURST)); config_writeb(socket, O2_RESERVED2, diff --git a/drivers/pcmcia/pcmcia_cis.c b/drivers/pcmcia/pcmcia_cis.c index 0ac54da15885..e2c92415b892 100644 --- a/drivers/pcmcia/pcmcia_cis.c +++ b/drivers/pcmcia/pcmcia_cis.c @@ -6,7 +6,7 @@ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. * * Copyright (C) 1999 David A. Hinds - * Copyright (C) 2004-2009 Dominik Brodowski + * Copyright (C) 2004-2010 Dominik Brodowski * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -22,7 +22,6 @@ #include <pcmcia/cisreg.h> #include <pcmcia/cistpl.h> #include <pcmcia/ss.h> -#include <pcmcia/cs.h> #include <pcmcia/ds.h> #include "cs_internal.h" @@ -126,14 +125,24 @@ next_entry: return ret; } + +/** + * pcmcia_io_cfg_data_width() - convert cfgtable to data path width parameter + */ +static int pcmcia_io_cfg_data_width(unsigned int flags) +{ + if (!(flags & CISTPL_IO_8BIT)) + return IO_DATA_PATH_WIDTH_16; + if (!(flags & CISTPL_IO_16BIT)) + return IO_DATA_PATH_WIDTH_8; + return IO_DATA_PATH_WIDTH_AUTO; +} + + struct pcmcia_cfg_mem { struct pcmcia_device *p_dev; + int (*conf_check) (struct pcmcia_device *p_dev, void *priv_data); void *priv_data; - int (*conf_check) (struct pcmcia_device *p_dev, - cistpl_cftable_entry_t *cfg, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, - void *priv_data); cisparse_t parse; cistpl_cftable_entry_t dflt; }; @@ -147,25 +156,102 @@ struct pcmcia_cfg_mem { */ static int pcmcia_do_loop_config(tuple_t *tuple, cisparse_t *parse, void *priv) { - cistpl_cftable_entry_t *cfg = &parse->cftable_entry; struct pcmcia_cfg_mem *cfg_mem = priv; + struct pcmcia_device *p_dev = cfg_mem->p_dev; + cistpl_cftable_entry_t *cfg = &parse->cftable_entry; + cistpl_cftable_entry_t *dflt = &cfg_mem->dflt; + unsigned int flags = p_dev->config_flags; + unsigned int vcc = p_dev->socket->socket.Vcc; + + dev_dbg(&p_dev->dev, "testing configuration %x, autoconf %x\n", + cfg->index, flags); /* default values */ - cfg_mem->p_dev->conf.ConfigIndex = cfg->index; + cfg_mem->p_dev->config_index = cfg->index; if (cfg->flags & CISTPL_CFTABLE_DEFAULT) cfg_mem->dflt = *cfg; - return cfg_mem->conf_check(cfg_mem->p_dev, cfg, &cfg_mem->dflt, - cfg_mem->p_dev->socket->socket.Vcc, - cfg_mem->priv_data); + /* check for matching Vcc? */ + if (flags & CONF_AUTO_CHECK_VCC) { + if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { + if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) + return -ENODEV; + } else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) { + if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000) + return -ENODEV; + } + } + + /* set Vpp? */ + if (flags & CONF_AUTO_SET_VPP) { + if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) + p_dev->vpp = cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; + else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM)) + p_dev->vpp = + dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000; + } + + /* enable audio? */ + if ((flags & CONF_AUTO_AUDIO) && (cfg->flags & CISTPL_CFTABLE_AUDIO)) + p_dev->config_flags |= CONF_ENABLE_SPKR; + + + /* IO window settings? */ + if (flags & CONF_AUTO_SET_IO) { + cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io; + int i = 0; + + p_dev->resource[0]->start = p_dev->resource[0]->end = 0; + p_dev->resource[1]->start = p_dev->resource[1]->end = 0; + if (io->nwin == 0) + return -ENODEV; + + p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; + p_dev->resource[0]->flags |= + pcmcia_io_cfg_data_width(io->flags); + if (io->nwin > 1) { + /* For multifunction cards, by convention, we + * configure the network function with window 0, + * and serial with window 1 */ + i = (io->win[1].len > io->win[0].len); + p_dev->resource[1]->flags = p_dev->resource[0]->flags; + p_dev->resource[1]->start = io->win[1-i].base; + p_dev->resource[1]->end = io->win[1-i].len; + } + p_dev->resource[0]->start = io->win[i].base; + p_dev->resource[0]->end = io->win[i].len; + p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK; + } + + /* MEM window settings? */ + if (flags & CONF_AUTO_SET_IOMEM) { + /* so far, we only set one memory window */ + cistpl_mem_t *mem = (cfg->mem.nwin) ? &cfg->mem : &dflt->mem; + + p_dev->resource[2]->start = p_dev->resource[2]->end = 0; + if (mem->nwin == 0) + return -ENODEV; + + p_dev->resource[2]->start = mem->win[0].host_addr; + p_dev->resource[2]->end = mem->win[0].len; + if (p_dev->resource[2]->end < 0x1000) + p_dev->resource[2]->end = 0x1000; + p_dev->card_addr = mem->win[0].card_addr; + } + + dev_dbg(&p_dev->dev, + "checking configuration %x: %pr %pr %pr (%d lines)\n", + p_dev->config_index, p_dev->resource[0], p_dev->resource[1], + p_dev->resource[2], p_dev->io_lines); + + return cfg_mem->conf_check(p_dev, cfg_mem->priv_data); } /** * pcmcia_loop_config() - loop over configuration options * @p_dev: the struct pcmcia_device which we need to loop for. * @conf_check: function to call for each configuration option. - * It gets passed the struct pcmcia_device, the CIS data - * describing the configuration option, and private data + * It gets passed the struct pcmcia_device and private data * being passed to pcmcia_loop_config() * @priv_data: private data to be passed to the conf_check function. * @@ -175,9 +261,6 @@ static int pcmcia_do_loop_config(tuple_t *tuple, cisparse_t *parse, void *priv) */ int pcmcia_loop_config(struct pcmcia_device *p_dev, int (*conf_check) (struct pcmcia_device *p_dev, - cistpl_cftable_entry_t *cfg, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, void *priv_data), void *priv_data) { diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index 9ba4dade69a4..0bdda5b3ed55 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c @@ -6,7 +6,7 @@ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. * * Copyright (C) 1999 David A. Hinds - * Copyright (C) 2004-2005 Dominik Brodowski + * Copyright (C) 2004-2010 Dominik Brodowski * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -26,7 +26,6 @@ #include <asm/irq.h> #include <pcmcia/ss.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/cisreg.h> #include <pcmcia/ds.h> @@ -56,6 +55,12 @@ struct resource *pcmcia_find_mem_region(u_long base, u_long num, u_long align, } +/** + * release_io_space() - release IO ports allocated with alloc_io_space() + * @s: pcmcia socket + * @res: resource to release + * + */ static void release_io_space(struct pcmcia_socket *s, struct resource *res) { resource_size_t num = resource_size(res); @@ -81,9 +86,14 @@ static void release_io_space(struct pcmcia_socket *s, struct resource *res) } } } -} /* release_io_space */ +} + -/** alloc_io_space +/** + * alloc_io_space() - allocate IO ports for use by a PCMCIA device + * @s: pcmcia socket + * @res: resource to allocate (begin: begin, end: size) + * @lines: number of IO lines decoded by the PCMCIA card * * Special stuff for managing IO windows, because they are scarce */ @@ -135,7 +145,7 @@ static int alloc_io_space(struct pcmcia_socket *s, struct resource *res, } dev_dbg(&s->dev, "alloc_io_space request result %d: %pR\n", ret, res); return ret; -} /* alloc_io_space */ +} /** @@ -168,14 +178,14 @@ static int pcmcia_access_config(struct pcmcia_device *p_dev, return -EACCES; } - addr = (c->ConfigBase + where) >> 1; + addr = (p_dev->config_base + where) >> 1; ret = accessf(s, 1, addr, 1, val); mutex_unlock(&s->ops_mutex); return ret; -} /* pcmcia_access_config */ +} /** @@ -204,11 +214,20 @@ int pcmcia_write_config_byte(struct pcmcia_device *p_dev, off_t where, u8 val) EXPORT_SYMBOL(pcmcia_write_config_byte); -int pcmcia_map_mem_page(struct pcmcia_device *p_dev, window_handle_t wh, +/** + * pcmcia_map_mem_page() - modify iomem window to point to a different offset + * @p_dev: pcmcia device + * @res: iomem resource already enabled by pcmcia_request_window() + * @offset: card_offset to map + * + * pcmcia_map_mem_page() modifies what can be read and written by accessing + * an iomem range previously enabled by pcmcia_request_window(), by setting + * the card_offset value to @offset. + */ +int pcmcia_map_mem_page(struct pcmcia_device *p_dev, struct resource *res, unsigned int offset) { struct pcmcia_socket *s = p_dev->socket; - struct resource *res = wh; unsigned int w; int ret; @@ -223,98 +242,111 @@ int pcmcia_map_mem_page(struct pcmcia_device *p_dev, window_handle_t wh, dev_warn(&p_dev->dev, "failed to set_mem_map\n"); mutex_unlock(&s->ops_mutex); return ret; -} /* pcmcia_map_mem_page */ +} EXPORT_SYMBOL(pcmcia_map_mem_page); -/** pcmcia_modify_configuration +/** + * pcmcia_fixup_iowidth() - reduce io width to 8bit + * @p_dev: pcmcia device * - * Modify a locked socket configuration + * pcmcia_fixup_iowidth() allows a PCMCIA device driver to reduce the + * IO width to 8bit after having called pcmcia_enable_device() + * previously. */ -int pcmcia_modify_configuration(struct pcmcia_device *p_dev, - modconf_t *mod) +int pcmcia_fixup_iowidth(struct pcmcia_device *p_dev) { - struct pcmcia_socket *s; - config_t *c; - int ret; - - s = p_dev->socket; + struct pcmcia_socket *s = p_dev->socket; + pccard_io_map io_off = { 0, 0, 0, 0, 1 }; + pccard_io_map io_on; + int i, ret = 0; mutex_lock(&s->ops_mutex); - c = p_dev->function_config; - if (!(s->state & SOCKET_PRESENT)) { - dev_dbg(&p_dev->dev, "No card present\n"); - ret = -ENODEV; - goto unlock; - } - if (!(c->state & CONFIG_LOCKED)) { - dev_dbg(&p_dev->dev, "Configuration isnt't locked\n"); + dev_dbg(&p_dev->dev, "fixup iowidth to 8bit\n"); + + if (!(s->state & SOCKET_PRESENT) || + !(p_dev->function_config->state & CONFIG_LOCKED)) { + dev_dbg(&p_dev->dev, "No card? Config not locked?\n"); ret = -EACCES; goto unlock; } - if (mod->Attributes & (CONF_IRQ_CHANGE_VALID | CONF_VCC_CHANGE_VALID)) { - dev_dbg(&p_dev->dev, - "changing Vcc or IRQ is not allowed at this time\n"); - ret = -EINVAL; - goto unlock; - } + io_on.speed = io_speed; + for (i = 0; i < MAX_IO_WIN; i++) { + if (!s->io[i].res) + continue; + io_off.map = i; + io_on.map = i; - /* We only allow changing Vpp1 and Vpp2 to the same value */ - if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) && - (mod->Attributes & CONF_VPP2_CHANGE_VALID)) { - if (mod->Vpp1 != mod->Vpp2) { - dev_dbg(&p_dev->dev, - "Vpp1 and Vpp2 must be the same\n"); - ret = -EINVAL; - goto unlock; - } - s->socket.Vpp = mod->Vpp1; - if (s->ops->set_socket(s, &s->socket)) { - dev_printk(KERN_WARNING, &p_dev->dev, - "Unable to set VPP\n"); - ret = -EIO; - goto unlock; - } - } else if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) || - (mod->Attributes & CONF_VPP2_CHANGE_VALID)) { - dev_dbg(&p_dev->dev, - "changing Vcc is not allowed at this time\n"); - ret = -EINVAL; - goto unlock; + io_on.flags = MAP_ACTIVE | IO_DATA_PATH_WIDTH_8; + io_on.start = s->io[i].res->start; + io_on.stop = s->io[i].res->end; + + s->ops->set_io_map(s, &io_off); + mdelay(40); + s->ops->set_io_map(s, &io_on); } +unlock: + mutex_unlock(&s->ops_mutex); + + return ret; +} +EXPORT_SYMBOL(pcmcia_fixup_iowidth); + + +/** + * pcmcia_fixup_vpp() - set Vpp to a new voltage level + * @p_dev: pcmcia device + * @new_vpp: new Vpp voltage + * + * pcmcia_fixup_vpp() allows a PCMCIA device driver to set Vpp to + * a new voltage level between calls to pcmcia_enable_device() + * and pcmcia_disable_device(). + */ +int pcmcia_fixup_vpp(struct pcmcia_device *p_dev, unsigned char new_vpp) +{ + struct pcmcia_socket *s = p_dev->socket; + int ret = 0; - if (mod->Attributes & CONF_IO_CHANGE_WIDTH) { - pccard_io_map io_off = { 0, 0, 0, 0, 1 }; - pccard_io_map io_on; - int i; + mutex_lock(&s->ops_mutex); - io_on.speed = io_speed; - for (i = 0; i < MAX_IO_WIN; i++) { - if (!s->io[i].res) - continue; - io_off.map = i; - io_on.map = i; + dev_dbg(&p_dev->dev, "fixup Vpp to %d\n", new_vpp); - io_on.flags = MAP_ACTIVE | IO_DATA_PATH_WIDTH_8; - io_on.start = s->io[i].res->start; - io_on.stop = s->io[i].res->end; + if (!(s->state & SOCKET_PRESENT) || + !(p_dev->function_config->state & CONFIG_LOCKED)) { + dev_dbg(&p_dev->dev, "No card? Config not locked?\n"); + ret = -EACCES; + goto unlock; + } - s->ops->set_io_map(s, &io_off); - mdelay(40); - s->ops->set_io_map(s, &io_on); - } + s->socket.Vpp = new_vpp; + if (s->ops->set_socket(s, &s->socket)) { + dev_warn(&p_dev->dev, "Unable to set VPP\n"); + ret = -EIO; + goto unlock; } - ret = 0; + p_dev->vpp = new_vpp; + unlock: mutex_unlock(&s->ops_mutex); return ret; -} /* modify_configuration */ -EXPORT_SYMBOL(pcmcia_modify_configuration); +} +EXPORT_SYMBOL(pcmcia_fixup_vpp); +/** + * pcmcia_release_configuration() - physically disable a PCMCIA device + * @p_dev: pcmcia device + * + * pcmcia_release_configuration() is the 1:1 counterpart to + * pcmcia_enable_device(): If a PCMCIA device is no longer used by any + * driver, the Vpp voltage is set to 0, IRQs will no longer be generated, + * and I/O ranges will be disabled. As pcmcia_release_io() and + * pcmcia_release_window() still need to be called, device drivers are + * expected to call pcmcia_disable_device() instead. + */ int pcmcia_release_configuration(struct pcmcia_device *p_dev) { pccard_io_map io = { 0, 0, 0, 0, 1 }; @@ -327,7 +359,7 @@ int pcmcia_release_configuration(struct pcmcia_device *p_dev) if (p_dev->_locked) { p_dev->_locked = 0; if (--(s->lock_count) == 0) { - s->socket.flags = SS_OUTPUT_ENA; /* Is this correct? */ + s->socket.flags = SS_OUTPUT_ENA; /* Is this correct? */ s->socket.Vpp = 0; s->socket.io_irq = 0; s->ops->set_socket(s, &s->socket); @@ -349,16 +381,18 @@ int pcmcia_release_configuration(struct pcmcia_device *p_dev) mutex_unlock(&s->ops_mutex); return 0; -} /* pcmcia_release_configuration */ +} -/** pcmcia_release_io +/** + * pcmcia_release_io() - release I/O allocated by a PCMCIA device + * @p_dev: pcmcia device * - * Release_io() releases the I/O ranges allocated by a client. This - * may be invoked some time after a card ejection has already dumped - * the actual socket configuration, so if the client is "stale", we - * don't bother checking the port ranges against the current socket - * values. + * pcmcia_release_io() releases the I/O ranges allocated by a PCMCIA + * device. This may be invoked some time after a card ejection has + * already dumped the actual socket configuration, so if the client is + * "stale", we don't bother checking the port ranges against the + * current socket values. */ static int pcmcia_release_io(struct pcmcia_device *p_dev) { @@ -387,6 +421,14 @@ out: } /* pcmcia_release_io */ +/** + * pcmcia_release_window() - release reserved iomem for PCMCIA devices + * @p_dev: pcmcia device + * @res: iomem resource to release + * + * pcmcia_release_window() releases &struct resource *res which was + * previously reserved by calling pcmcia_request_window(). + */ int pcmcia_release_window(struct pcmcia_device *p_dev, struct resource *res) { struct pcmcia_socket *s = p_dev->socket; @@ -420,6 +462,8 @@ int pcmcia_release_window(struct pcmcia_device *p_dev, struct resource *res) kfree(win->res); win->res = NULL; } + res->start = res->end = 0; + res->flags = IORESOURCE_MEM; p_dev->_win &= ~CLIENT_WIN_REQ(w); mutex_unlock(&s->ops_mutex); @@ -428,23 +472,30 @@ int pcmcia_release_window(struct pcmcia_device *p_dev, struct resource *res) EXPORT_SYMBOL(pcmcia_release_window); -int pcmcia_request_configuration(struct pcmcia_device *p_dev, - config_req_t *req) +/** + * pcmcia_enable_device() - set up and activate a PCMCIA device + * @p_dev: the associated PCMCIA device + * + * pcmcia_enable_device() physically enables a PCMCIA device. It parses + * the flags passed to in @flags and stored in @p_dev->flags and sets up + * the Vpp voltage, enables the speaker line, I/O ports and store proper + * values to configuration registers. + */ +int pcmcia_enable_device(struct pcmcia_device *p_dev) { int i; - u_int base; + unsigned int base; struct pcmcia_socket *s = p_dev->socket; config_t *c; pccard_io_map iomap; + unsigned char status = 0; + unsigned char ext_status = 0; + unsigned char option = 0; + unsigned int flags = p_dev->config_flags; if (!(s->state & SOCKET_PRESENT)) return -ENODEV; - if (req->IntType & INT_CARDBUS) { - dev_dbg(&p_dev->dev, "IntType may not be INT_CARDBUS\n"); - return -EINVAL; - } - mutex_lock(&s->ops_mutex); c = p_dev->function_config; if (c->state & CONFIG_LOCKED) { @@ -454,7 +505,7 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev, } /* Do power control. We don't allow changes in Vcc. */ - s->socket.Vpp = req->Vpp; + s->socket.Vpp = p_dev->vpp; if (s->ops->set_socket(s, &s->socket)) { mutex_unlock(&s->ops_mutex); dev_printk(KERN_WARNING, &p_dev->dev, @@ -463,64 +514,74 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev, } /* Pick memory or I/O card, DMA mode, interrupt */ - c->IntType = req->IntType; - c->Attributes = req->Attributes; - if (req->IntType & INT_MEMORY_AND_IO) + if (p_dev->_io || flags & CONF_ENABLE_IRQ) + flags |= CONF_ENABLE_IOCARD; + if (flags & CONF_ENABLE_IOCARD) s->socket.flags |= SS_IOCARD; - if (req->IntType & INT_ZOOMED_VIDEO) - s->socket.flags |= SS_ZVCARD | SS_IOCARD; - if (req->Attributes & CONF_ENABLE_DMA) - s->socket.flags |= SS_DMA_MODE; - if (req->Attributes & CONF_ENABLE_SPKR) + if (flags & CONF_ENABLE_SPKR) { s->socket.flags |= SS_SPKR_ENA; - if (req->Attributes & CONF_ENABLE_IRQ) + status = CCSR_AUDIO_ENA; + if (!(p_dev->config_regs & PRESENT_STATUS)) + dev_warn(&p_dev->dev, "speaker requested, but " + "PRESENT_STATUS not set!\n"); + } + if (flags & CONF_ENABLE_IRQ) s->socket.io_irq = s->pcmcia_irq; else s->socket.io_irq = 0; + if (flags & CONF_ENABLE_ESR) { + p_dev->config_regs |= PRESENT_EXT_STATUS; + ext_status = ESR_REQ_ATTN_ENA; + } s->ops->set_socket(s, &s->socket); s->lock_count++; + dev_dbg(&p_dev->dev, + "enable_device: V %d, flags %x, base %x, regs %x, idx %x\n", + p_dev->vpp, flags, p_dev->config_base, p_dev->config_regs, + p_dev->config_index); + /* Set up CIS configuration registers */ - base = c->ConfigBase = req->ConfigBase; - c->CardValues = req->Present; - if (req->Present & PRESENT_COPY) { - c->Copy = req->Copy; - pcmcia_write_cis_mem(s, 1, (base + CISREG_SCR)>>1, 1, &c->Copy); - } - if (req->Present & PRESENT_OPTION) { + base = p_dev->config_base; + if (p_dev->config_regs & PRESENT_COPY) { + u16 tmp = 0; + dev_dbg(&p_dev->dev, "clearing CISREG_SCR\n"); + pcmcia_write_cis_mem(s, 1, (base + CISREG_SCR)>>1, 1, &tmp); + } + if (p_dev->config_regs & PRESENT_PIN_REPLACE) { + u16 tmp = 0; + dev_dbg(&p_dev->dev, "clearing CISREG_PRR\n"); + pcmcia_write_cis_mem(s, 1, (base + CISREG_PRR)>>1, 1, &tmp); + } + if (p_dev->config_regs & PRESENT_OPTION) { if (s->functions == 1) { - c->Option = req->ConfigIndex & COR_CONFIG_MASK; + option = p_dev->config_index & COR_CONFIG_MASK; } else { - c->Option = req->ConfigIndex & COR_MFC_CONFIG_MASK; - c->Option |= COR_FUNC_ENA|COR_IREQ_ENA; - if (req->Present & PRESENT_IOBASE_0) - c->Option |= COR_ADDR_DECODE; + option = p_dev->config_index & COR_MFC_CONFIG_MASK; + option |= COR_FUNC_ENA|COR_IREQ_ENA; + if (p_dev->config_regs & PRESENT_IOBASE_0) + option |= COR_ADDR_DECODE; } - if ((req->Attributes & CONF_ENABLE_IRQ) && - !(req->Attributes & CONF_ENABLE_PULSE_IRQ)) - c->Option |= COR_LEVEL_REQ; - pcmcia_write_cis_mem(s, 1, (base + CISREG_COR)>>1, 1, &c->Option); + if ((flags & CONF_ENABLE_IRQ) && + !(flags & CONF_ENABLE_PULSE_IRQ)) + option |= COR_LEVEL_REQ; + pcmcia_write_cis_mem(s, 1, (base + CISREG_COR)>>1, 1, &option); mdelay(40); } - if (req->Present & PRESENT_STATUS) { - c->Status = req->Status; - pcmcia_write_cis_mem(s, 1, (base + CISREG_CCSR)>>1, 1, &c->Status); - } - if (req->Present & PRESENT_PIN_REPLACE) { - c->Pin = req->Pin; - pcmcia_write_cis_mem(s, 1, (base + CISREG_PRR)>>1, 1, &c->Pin); - } - if (req->Present & PRESENT_EXT_STATUS) { - c->ExtStatus = req->ExtStatus; - pcmcia_write_cis_mem(s, 1, (base + CISREG_ESR)>>1, 1, &c->ExtStatus); - } - if (req->Present & PRESENT_IOBASE_0) { + if (p_dev->config_regs & PRESENT_STATUS) + pcmcia_write_cis_mem(s, 1, (base + CISREG_CCSR)>>1, 1, &status); + + if (p_dev->config_regs & PRESENT_EXT_STATUS) + pcmcia_write_cis_mem(s, 1, (base + CISREG_ESR)>>1, 1, + &ext_status); + + if (p_dev->config_regs & PRESENT_IOBASE_0) { u8 b = c->io[0].start & 0xff; pcmcia_write_cis_mem(s, 1, (base + CISREG_IOBASE_0)>>1, 1, &b); b = (c->io[0].start >> 8) & 0xff; pcmcia_write_cis_mem(s, 1, (base + CISREG_IOBASE_1)>>1, 1, &b); } - if (req->Present & PRESENT_IOSIZE) { + if (p_dev->config_regs & PRESENT_IOSIZE) { u8 b = resource_size(&c->io[0]) + resource_size(&c->io[1]) - 1; pcmcia_write_cis_mem(s, 1, (base + CISREG_IOSIZE)>>1, 1, &b); } @@ -551,14 +612,15 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev, p_dev->_locked = 1; mutex_unlock(&s->ops_mutex); return 0; -} /* pcmcia_request_configuration */ -EXPORT_SYMBOL(pcmcia_request_configuration); +} /* pcmcia_enable_device */ +EXPORT_SYMBOL(pcmcia_enable_device); /** * pcmcia_request_io() - attempt to reserve port ranges for PCMCIA devices + * @p_dev: the associated PCMCIA device * - * pcmcia_request_io() attepts to reserve the IO port ranges specified in + * pcmcia_request_io() attempts to reserve the IO port ranges specified in * &struct pcmcia_device @p_dev->resource[0] and @p_dev->resource[1]. The * "start" value is the requested start of the IO port resource; "end" * reflects the number of ports requested. The number of IO lines requested @@ -622,11 +684,13 @@ EXPORT_SYMBOL(pcmcia_request_io); /** * pcmcia_request_irq() - attempt to request a IRQ for a PCMCIA device + * @p_dev: the associated PCMCIA device + * @handler: IRQ handler to register * - * pcmcia_request_irq() is a wrapper around request_irq which will allow + * pcmcia_request_irq() is a wrapper around request_irq() which allows * the PCMCIA core to clean up the registration in pcmcia_disable_device(). * Drivers are free to use request_irq() directly, but then they need to - * call free_irq themselfves, too. Also, only IRQF_SHARED capable IRQ + * call free_irq() themselfves, too. Also, only %IRQF_SHARED capable IRQ * handlers are allowed. */ int __must_check pcmcia_request_irq(struct pcmcia_device *p_dev, @@ -649,12 +713,14 @@ EXPORT_SYMBOL(pcmcia_request_irq); /** * pcmcia_request_exclusive_irq() - attempt to request an exclusive IRQ first + * @p_dev: the associated PCMCIA device + * @handler: IRQ handler to register * - * pcmcia_request_exclusive_irq() is a wrapper around request_irq which + * pcmcia_request_exclusive_irq() is a wrapper around request_irq() which * attempts first to request an exclusive IRQ. If it fails, it also accepts * a shared IRQ, but prints out a warning. PCMCIA drivers should allow for * IRQ sharing and either use request_irq directly (then they need to call - * free_irq themselves, too), or the pcmcia_request_irq() function. + * free_irq() themselves, too), or the pcmcia_request_irq() function. */ int __must_check __pcmcia_request_exclusive_irq(struct pcmcia_device *p_dev, @@ -795,38 +861,47 @@ int pcmcia_setup_irq(struct pcmcia_device *p_dev) } -/** pcmcia_request_window +/** + * pcmcia_request_window() - attempt to reserve iomem for PCMCIA devices + * @p_dev: the associated PCMCIA device + * @res: &struct resource pointing to p_dev->resource[2..5] + * @speed: access speed * - * Request_window() establishes a mapping between card memory space - * and system memory space. + * pcmcia_request_window() attepts to reserve an iomem ranges specified in + * &struct resource @res pointing to one of the entries in + * &struct pcmcia_device @p_dev->resource[2..5]. The "start" value is the + * requested start of the IO mem resource; "end" reflects the size + * requested. */ -int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_handle_t *wh) +int pcmcia_request_window(struct pcmcia_device *p_dev, struct resource *res, + unsigned int speed) { struct pcmcia_socket *s = p_dev->socket; pccard_mem_map *win; u_long align; - struct resource *res; int w; + dev_dbg(&p_dev->dev, "request_window %pR %d\n", res, speed); + if (!(s->state & SOCKET_PRESENT)) { dev_dbg(&p_dev->dev, "No card present\n"); return -ENODEV; } /* Window size defaults to smallest available */ - if (req->Size == 0) - req->Size = s->map_size; - align = (s->features & SS_CAP_MEM_ALIGN) ? req->Size : s->map_size; - if (req->Size & (s->map_size-1)) { + if (res->end == 0) + res->end = s->map_size; + align = (s->features & SS_CAP_MEM_ALIGN) ? res->end : s->map_size; + if (res->end & (s->map_size-1)) { dev_dbg(&p_dev->dev, "invalid map size\n"); return -EINVAL; } - if ((req->Base && (s->features & SS_CAP_STATIC_MAP)) || - (req->Base & (align-1))) { + if ((res->start && (s->features & SS_CAP_STATIC_MAP)) || + (res->start & (align-1))) { dev_dbg(&p_dev->dev, "invalid base address\n"); return -EINVAL; } - if (req->Base) + if (res->start) align = 0; /* Allocate system memory window */ @@ -843,7 +918,7 @@ int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_ha win = &s->win[w]; if (!(s->features & SS_CAP_STATIC_MAP)) { - win->res = pcmcia_find_mem_region(req->Base, req->Size, align, + win->res = pcmcia_find_mem_region(res->start, res->end, align, 0, s); if (!win->res) { dev_dbg(&p_dev->dev, "allocating mem region failed\n"); @@ -855,8 +930,8 @@ int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_ha /* Configure the socket controller */ win->map = w+1; - win->flags = req->Attributes; - win->speed = req->AccessSpeed; + win->flags = res->flags & WIN_FLAGS_MAP; + win->speed = speed; win->card_start = 0; if (s->ops->set_mem_map(s, win) != 0) { @@ -868,17 +943,14 @@ int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_ha /* Return window handle */ if (s->features & SS_CAP_STATIC_MAP) - req->Base = win->static_start; + res->start = win->static_start; else - req->Base = win->res->start; + res->start = win->res->start; /* convert to new-style resources */ - res = p_dev->resource[w + MAX_IO_WIN]; - res->start = req->Base; - res->end = req->Base + req->Size - 1; - res->flags &= ~IORESOURCE_BITS; - res->flags |= (req->Attributes & WIN_FLAGS_MAP) | (win->map << 2); - res->flags |= IORESOURCE_MEM; + res->end += res->start - 1; + res->flags &= ~WIN_FLAGS_REQ; + res->flags |= (win->map << 2) | IORESOURCE_MEM; res->parent = win->res; if (win->res) request_resource(&iomem_resource, res); @@ -886,15 +958,30 @@ int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_ha dev_dbg(&p_dev->dev, "request_window results in %pR\n", res); mutex_unlock(&s->ops_mutex); - *wh = res; return 0; } /* pcmcia_request_window */ EXPORT_SYMBOL(pcmcia_request_window); + +/** + * pcmcia_disable_device() - disable and clean up a PCMCIA device + * @p_dev: the associated PCMCIA device + * + * pcmcia_disable_device() is the driver-callable counterpart to + * pcmcia_enable_device(): If a PCMCIA device is no longer used, + * drivers are expected to clean up and disable the device by calling + * this function. Any I/O ranges (iomem and ioports) will be released, + * the Vpp voltage will be set to 0, and IRQs will no longer be + * generated -- at least if there is no other card function (of + * multifunction devices) being used. + */ void pcmcia_disable_device(struct pcmcia_device *p_dev) { int i; + + dev_dbg(&p_dev->dev, "disabling device\n"); + for (i = 0; i < MAX_WIN; i++) { struct resource *res = p_dev->resource[MAX_IO_WIN + i]; if (res->flags & WIN_FLAGS_REQ) diff --git a/drivers/pcmcia/pd6729.c b/drivers/pcmcia/pd6729.c index deef6656ab7b..8cbfa067171f 100644 --- a/drivers/pcmcia/pd6729.c +++ b/drivers/pcmcia/pd6729.c @@ -18,7 +18,6 @@ #include <linux/io.h> #include <pcmcia/ss.h> -#include <pcmcia/cs.h> #include <asm/system.h> diff --git a/drivers/pcmcia/rsrc_iodyn.c b/drivers/pcmcia/rsrc_iodyn.c index 8510c35d2952..523eb691c30b 100644 --- a/drivers/pcmcia/rsrc_iodyn.c +++ b/drivers/pcmcia/rsrc_iodyn.c @@ -17,7 +17,6 @@ #include <linux/kernel.h> #include <pcmcia/ss.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include "cs_internal.h" diff --git a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c index 4e80421fd908..aa628ed0e9f4 100644 --- a/drivers/pcmcia/rsrc_mgr.c +++ b/drivers/pcmcia/rsrc_mgr.c @@ -17,7 +17,6 @@ #include <linux/kernel.h> #include <pcmcia/ss.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include "cs_internal.h" diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c index 96f348b35fde..b187555d4388 100644 --- a/drivers/pcmcia/rsrc_nonstatic.c +++ b/drivers/pcmcia/rsrc_nonstatic.c @@ -29,7 +29,6 @@ #include <asm/irq.h> #include <pcmcia/ss.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include "cs_internal.h" diff --git a/drivers/pcmcia/sa1100_generic.c b/drivers/pcmcia/sa1100_generic.c index e09851480295..945857f8c284 100644 --- a/drivers/pcmcia/sa1100_generic.c +++ b/drivers/pcmcia/sa1100_generic.c @@ -35,7 +35,6 @@ #include <linux/slab.h> #include <linux/platform_device.h> -#include <pcmcia/cs.h> #include <pcmcia/ss.h> #include <asm/hardware/scoop.h> diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index 6f1a86b43c60..689e3c02edb8 100644 --- a/drivers/pcmcia/soc_common.c +++ b/drivers/pcmcia/soc_common.c @@ -627,8 +627,6 @@ void soc_pcmcia_remove_one(struct soc_pcmcia_socket *skt) pcmcia_unregister_socket(&skt->socket); - flush_scheduled_work(); - skt->ops->hw_shutdown(skt); soc_common_pcmcia_config_skt(skt, &dead_socket); @@ -720,8 +718,6 @@ int soc_pcmcia_add_one(struct soc_pcmcia_socket *skt) pcmcia_unregister_socket(&skt->socket); out_err_7: - flush_scheduled_work(); - skt->ops->hw_shutdown(skt); out_err_6: list_del(&skt->node); diff --git a/drivers/pcmcia/soc_common.h b/drivers/pcmcia/soc_common.h index 3fba3a679128..bbcd5385a221 100644 --- a/drivers/pcmcia/soc_common.h +++ b/drivers/pcmcia/soc_common.h @@ -11,7 +11,6 @@ /* include the world */ #include <linux/cpufreq.h> -#include <pcmcia/cs.h> #include <pcmcia/ss.h> #include <pcmcia/cistpl.h> diff --git a/drivers/pcmcia/socket_sysfs.c b/drivers/pcmcia/socket_sysfs.c index cb0d3ace18bd..71aeed93037c 100644 --- a/drivers/pcmcia/socket_sysfs.c +++ b/drivers/pcmcia/socket_sysfs.c @@ -27,7 +27,6 @@ #include <asm/irq.h> #include <pcmcia/ss.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/cisreg.h> #include <pcmcia/ds.h> diff --git a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c index be0d841c7ebd..310160bffe38 100644 --- a/drivers/pcmcia/tcic.c +++ b/drivers/pcmcia/tcic.c @@ -49,7 +49,6 @@ #include <asm/io.h> #include <asm/system.h> -#include <pcmcia/cs.h> #include <pcmcia/ss.h> #include "tcic.h" diff --git a/drivers/pcmcia/vrc4173_cardu.c b/drivers/pcmcia/vrc4173_cardu.c index 9b3c15827e5c..c6d36b3a6ce8 100644 --- a/drivers/pcmcia/vrc4173_cardu.c +++ b/drivers/pcmcia/vrc4173_cardu.c @@ -461,7 +461,7 @@ static int __devinit vrc4173_cardu_probe(struct pci_dev *dev, { vrc4173_socket_t *socket; unsigned long start, len, flags; - int slot, err; + int slot, err, ret; slot = vrc4173_cardu_slots++; socket = &cardu_sockets[slot]; @@ -474,43 +474,63 @@ static int __devinit vrc4173_cardu_probe(struct pci_dev *dev, return err; start = pci_resource_start(dev, 0); - if (start == 0) - return -ENODEV; + if (start == 0) { + ret = -ENODEV; + goto disable; + } len = pci_resource_len(dev, 0); - if (len == 0) - return -ENODEV; + if (len == 0) { + ret = -ENODEV; + goto disable; + } - if (((flags = pci_resource_flags(dev, 0)) & IORESOURCE_MEM) == 0) - return -EBUSY; + flags = pci_resource_flags(dev, 0); + if ((flags & IORESOURCE_MEM) == 0) { + ret = -EBUSY; + goto disable; + } - if ((err = pci_request_regions(dev, socket->name)) < 0) - return err; + err = pci_request_regions(dev, socket->name); + if (err < 0) { + ret = err; + goto disable; + } socket->base = ioremap(start, len); - if (socket->base == NULL) - return -ENODEV; + if (socket->base == NULL) { + ret = -ENODEV; + goto release; + } socket->dev = dev; socket->pcmcia_socket = pcmcia_register_socket(slot, &cardu_operations, 1); if (socket->pcmcia_socket == NULL) { - iounmap(socket->base); - socket->base = NULL; - return -ENOMEM; + ret = -ENOMEM; + goto unmap; } if (request_irq(dev->irq, cardu_interrupt, IRQF_SHARED, socket->name, socket) < 0) { - pcmcia_unregister_socket(socket->pcmcia_socket); - socket->pcmcia_socket = NULL; - iounmap(socket->base); - socket->base = NULL; - return -EBUSY; + ret = -EBUSY; + goto unregister; } printk(KERN_INFO "%s at %#08lx, IRQ %d\n", socket->name, start, dev->irq); return 0; + +unregister: + pcmcia_unregister_socket(socket->pcmcia_socket); + socket->pcmcia_socket = NULL; +unmap: + iounmap(socket->base); + socket->base = NULL; +release: + pci_release_regions(dev); +disable: + pci_disable_device(dev); + return ret; } static int __devinit vrc4173_cardu_setup(char *options) diff --git a/drivers/pcmcia/xxs1500_ss.c b/drivers/pcmcia/xxs1500_ss.c index fa88c360c37a..3b67a1b6a197 100644 --- a/drivers/pcmcia/xxs1500_ss.c +++ b/drivers/pcmcia/xxs1500_ss.c @@ -17,7 +17,6 @@ #include <linux/slab.h> #include <linux/spinlock.h> -#include <pcmcia/cs.h> #include <pcmcia/ss.h> #include <pcmcia/cistpl.h> diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index 414d9a6f9a32..408dbaa080a1 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c @@ -20,7 +20,6 @@ #include <linux/slab.h> #include <pcmcia/ss.h> -#include <pcmcia/cs.h> #include "yenta_socket.h" #include "i82365.h" diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index e3154ff7a39f..f200677851b8 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -2360,6 +2360,7 @@ static const struct file_operations sonypi_misc_fops = { .release = sonypi_misc_release, .fasync = sonypi_misc_fasync, .unlocked_ioctl = sonypi_misc_ioctl, + .llseek = noop_llseek, }; static struct miscdevice sonypi_misc_device = { diff --git a/drivers/pnp/isapnp/proc.c b/drivers/pnp/isapnp/proc.c index 3f94edab25fa..e73ebefdf3e0 100644 --- a/drivers/pnp/isapnp/proc.c +++ b/drivers/pnp/isapnp/proc.c @@ -31,8 +31,9 @@ static struct proc_dir_entry *isapnp_proc_bus_dir = NULL; static loff_t isapnp_proc_bus_lseek(struct file *file, loff_t off, int whence) { loff_t new = -1; + struct inode *inode = file->f_path.dentry->d_inode; - lock_kernel(); + mutex_lock(&inode->i_mutex); switch (whence) { case 0: new = off; @@ -44,12 +45,12 @@ static loff_t isapnp_proc_bus_lseek(struct file *file, loff_t off, int whence) new = 256 + off; break; } - if (new < 0 || new > 256) { - unlock_kernel(); - return -EINVAL; - } - unlock_kernel(); - return (file->f_pos = new); + if (new < 0 || new > 256) + new = -EINVAL; + else + file->f_pos = new; + mutex_unlock(&inode->i_mutex); + return new; } static ssize_t isapnp_proc_bus_read(struct file *file, char __user * buf, diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c index d60557cae8ef..5a8daa358066 100644 --- a/drivers/rtc/rtc-m41t80.c +++ b/drivers/rtc/rtc-m41t80.c @@ -20,7 +20,7 @@ #include <linux/module.h> #include <linux/rtc.h> #include <linux/slab.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/string.h> #ifdef CONFIG_RTC_DRV_M41T80_WDT #include <linux/fs.h> @@ -68,6 +68,7 @@ #define DRV_VERSION "0.05" +static DEFINE_MUTEX(m41t80_rtc_mutex); static const struct i2c_device_id m41t80_id[] = { { "m41t62", M41T80_FEATURE_SQ | M41T80_FEATURE_SQ_ALT }, { "m41t65", M41T80_FEATURE_HT | M41T80_FEATURE_WD }, @@ -677,9 +678,9 @@ static long wdt_unlocked_ioctl(struct file *file, unsigned int cmd, { int ret; - lock_kernel(); + mutex_lock(&m41t80_rtc_mutex); ret = wdt_ioctl(file, cmd, arg); - unlock_kernel(); + mutex_unlock(&m41t80_rtc_mutex); return ret; } @@ -693,16 +694,16 @@ static long wdt_unlocked_ioctl(struct file *file, unsigned int cmd, static int wdt_open(struct inode *inode, struct file *file) { if (MINOR(inode->i_rdev) == WATCHDOG_MINOR) { - lock_kernel(); + mutex_lock(&m41t80_rtc_mutex); if (test_and_set_bit(0, &wdt_is_open)) { - unlock_kernel(); + mutex_unlock(&m41t80_rtc_mutex); return -EBUSY; } /* * Activate */ wdt_is_open = 1; - unlock_kernel(); + mutex_unlock(&m41t80_rtc_mutex); return nonseekable_open(inode, file); } return -ENODEV; @@ -748,6 +749,7 @@ static const struct file_operations wdt_fops = { .write = wdt_write, .open = wdt_open, .release = wdt_release, + .llseek = no_llseek, }; static struct miscdevice wdt_dev = { diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 8373ca0de8e0..aa95f1001761 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -21,7 +21,6 @@ #include <linux/hdreg.h> #include <linux/async.h> #include <linux/mutex.h> -#include <linux/smp_lock.h> #include <asm/ccwdev.h> #include <asm/ebcdic.h> @@ -2197,7 +2196,6 @@ static void dasd_setup_queue(struct dasd_block *block) */ blk_queue_max_segment_size(block->request_queue, PAGE_SIZE); blk_queue_segment_boundary(block->request_queue, PAGE_SIZE - 1); - blk_queue_ordered(block->request_queue, QUEUE_ORDERED_DRAIN); } /* @@ -2236,7 +2234,6 @@ static int dasd_open(struct block_device *bdev, fmode_t mode) if (!block) return -ENODEV; - lock_kernel(); base = block->base; atomic_inc(&block->open_count); if (test_bit(DASD_FLAG_OFFLINE, &base->flags)) { @@ -2271,14 +2268,12 @@ static int dasd_open(struct block_device *bdev, fmode_t mode) goto out; } - unlock_kernel(); return 0; out: module_put(base->discipline->owner); unlock: atomic_dec(&block->open_count); - unlock_kernel(); return rc; } @@ -2286,10 +2281,8 @@ static int dasd_release(struct gendisk *disk, fmode_t mode) { struct dasd_block *block = disk->private_data; - lock_kernel(); atomic_dec(&block->open_count); module_put(block->base->discipline->owner); - unlock_kernel(); return 0; } diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c index 7158f9528ecc..c71d89dba302 100644 --- a/drivers/s390/block/dasd_eer.c +++ b/drivers/s390/block/dasd_eer.c @@ -670,6 +670,7 @@ static const struct file_operations dasd_eer_fops = { .read = &dasd_eer_read, .poll = &dasd_eer_poll, .owner = THIS_MODULE, + .llseek = noop_llseek, }; static struct miscdevice *dasd_eer_dev = NULL; diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c index 1557214944f7..26075e95b1ba 100644 --- a/drivers/s390/block/dasd_ioctl.c +++ b/drivers/s390/block/dasd_ioctl.c @@ -16,7 +16,6 @@ #include <linux/major.h> #include <linux/fs.h> #include <linux/blkpg.h> -#include <linux/smp_lock.h> #include <linux/slab.h> #include <asm/compat.h> #include <asm/ccwdev.h> @@ -370,9 +369,8 @@ static int dasd_ioctl_readall_cmb(struct dasd_block *block, unsigned int cmd, return ret; } -static int -dasd_do_ioctl(struct block_device *bdev, fmode_t mode, - unsigned int cmd, unsigned long arg) +int dasd_ioctl(struct block_device *bdev, fmode_t mode, + unsigned int cmd, unsigned long arg) { struct dasd_block *block = bdev->bd_disk->private_data; void __user *argp; @@ -430,14 +428,3 @@ dasd_do_ioctl(struct block_device *bdev, fmode_t mode, return -EINVAL; } } - -int dasd_ioctl(struct block_device *bdev, fmode_t mode, - unsigned int cmd, unsigned long arg) -{ - int rc; - - lock_kernel(); - rc = dasd_do_ioctl(bdev, mode, cmd, arg); - unlock_kernel(); - return rc; -} diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index 2bd72aa34c59..9b43ae94beba 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c @@ -14,7 +14,6 @@ #include <linux/init.h> #include <linux/slab.h> #include <linux/blkdev.h> -#include <linux/smp_lock.h> #include <linux/completion.h> #include <linux/interrupt.h> #include <linux/platform_device.h> @@ -776,7 +775,6 @@ dcssblk_open(struct block_device *bdev, fmode_t mode) struct dcssblk_dev_info *dev_info; int rc; - lock_kernel(); dev_info = bdev->bd_disk->private_data; if (NULL == dev_info) { rc = -ENODEV; @@ -786,7 +784,6 @@ dcssblk_open(struct block_device *bdev, fmode_t mode) bdev->bd_block_size = 4096; rc = 0; out: - unlock_kernel(); return rc; } @@ -797,7 +794,6 @@ dcssblk_release(struct gendisk *disk, fmode_t mode) struct segment_info *entry; int rc; - lock_kernel(); if (!dev_info) { rc = -ENODEV; goto out; @@ -815,7 +811,6 @@ dcssblk_release(struct gendisk *disk, fmode_t mode) up_write(&dcssblk_devices_sem); rc = 0; out: - unlock_kernel(); return rc; } diff --git a/drivers/s390/char/fs3270.c b/drivers/s390/char/fs3270.c index 857dfcb7b359..eb28fb01a38a 100644 --- a/drivers/s390/char/fs3270.c +++ b/drivers/s390/char/fs3270.c @@ -520,6 +520,7 @@ static const struct file_operations fs3270_fops = { .compat_ioctl = fs3270_ioctl, /* ioctl */ .open = fs3270_open, /* open */ .release = fs3270_close, /* release */ + .llseek = no_llseek, }; /* diff --git a/drivers/s390/char/monreader.c b/drivers/s390/char/monreader.c index e021ec663ef9..5b8b8592d311 100644 --- a/drivers/s390/char/monreader.c +++ b/drivers/s390/char/monreader.c @@ -447,6 +447,7 @@ static const struct file_operations mon_fops = { .release = &mon_close, .read = &mon_read, .poll = &mon_poll, + .llseek = noop_llseek, }; static struct miscdevice mon_dev = { diff --git a/drivers/s390/char/monwriter.c b/drivers/s390/char/monwriter.c index 572a1e7fd099..e0702d3ea33b 100644 --- a/drivers/s390/char/monwriter.c +++ b/drivers/s390/char/monwriter.c @@ -274,6 +274,7 @@ static const struct file_operations monwrite_fops = { .open = &monwrite_open, .release = &monwrite_close, .write = &monwrite_write, + .llseek = noop_llseek, }; static struct miscdevice mon_dev = { diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index f6d72e1f2a38..5707a80b96b6 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c @@ -468,7 +468,7 @@ sclp_sync_wait(void) cr0_sync &= 0xffff00a0; cr0_sync |= 0x00000200; __ctl_load(cr0_sync, 0, 0); - __raw_local_irq_stosm(0x01); + __arch_local_irq_stosm(0x01); /* Loop until driver state indicates finished request */ while (sclp_running_state != sclp_running_state_idle) { /* Check for expired request timer */ diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c index 85cf607fc78f..f0fa9ca5cb2c 100644 --- a/drivers/s390/char/tape_block.c +++ b/drivers/s390/char/tape_block.c @@ -16,7 +16,7 @@ #include <linux/fs.h> #include <linux/module.h> #include <linux/blkdev.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/interrupt.h> #include <linux/buffer_head.h> #include <linux/kernel.h> @@ -45,6 +45,7 @@ /* * file operation structure for tape block frontend */ +static DEFINE_MUTEX(tape_block_mutex); static int tapeblock_open(struct block_device *, fmode_t); static int tapeblock_release(struct gendisk *, fmode_t); static int tapeblock_medium_changed(struct gendisk *); @@ -361,7 +362,7 @@ tapeblock_open(struct block_device *bdev, fmode_t mode) struct tape_device * device; int rc; - lock_kernel(); + mutex_lock(&tape_block_mutex); device = tape_get_device(disk->private_data); if (device->required_tapemarks) { @@ -385,14 +386,14 @@ tapeblock_open(struct block_device *bdev, fmode_t mode) * is called. */ tape_state_set(device, TS_BLKUSE); - unlock_kernel(); + mutex_unlock(&tape_block_mutex); return 0; release: tape_release(device); put_device: tape_put_device(device); - unlock_kernel(); + mutex_unlock(&tape_block_mutex); return rc; } @@ -407,11 +408,11 @@ tapeblock_release(struct gendisk *disk, fmode_t mode) { struct tape_device *device = disk->private_data; - lock_kernel(); + mutex_lock(&tape_block_mutex); tape_state_set(device, TS_IN_USE); tape_release(device); tape_put_device(device); - unlock_kernel(); + mutex_unlock(&tape_block_mutex); return 0; } diff --git a/drivers/s390/char/tape_char.c b/drivers/s390/char/tape_char.c index 539045acaad4..883e2db02bd3 100644 --- a/drivers/s390/char/tape_char.c +++ b/drivers/s390/char/tape_char.c @@ -53,6 +53,7 @@ static const struct file_operations tape_fops = #endif .open = tapechar_open, .release = tapechar_release, + .llseek = no_llseek, }; static int tapechar_major = TAPECHAR_MAJOR; diff --git a/drivers/s390/char/vmcp.c b/drivers/s390/char/vmcp.c index 04e532eec032..0e7cb1a84151 100644 --- a/drivers/s390/char/vmcp.c +++ b/drivers/s390/char/vmcp.c @@ -177,6 +177,7 @@ static const struct file_operations vmcp_fops = { .write = vmcp_write, .unlocked_ioctl = vmcp_ioctl, .compat_ioctl = vmcp_ioctl, + .llseek = no_llseek, }; static struct miscdevice vmcp_dev = { diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c index e40a1b892866..0d6dc4b92cc2 100644 --- a/drivers/s390/char/vmlogrdr.c +++ b/drivers/s390/char/vmlogrdr.c @@ -97,6 +97,7 @@ static const struct file_operations vmlogrdr_fops = { .open = vmlogrdr_open, .release = vmlogrdr_release, .read = vmlogrdr_read, + .llseek = no_llseek, }; diff --git a/drivers/s390/char/vmwatchdog.c b/drivers/s390/char/vmwatchdog.c index e13508c98b1a..12ef9121d4f0 100644 --- a/drivers/s390/char/vmwatchdog.c +++ b/drivers/s390/char/vmwatchdog.c @@ -297,6 +297,7 @@ static const struct file_operations vmwdt_fops = { .unlocked_ioctl = &vmwdt_ioctl, .write = &vmwdt_write, .owner = THIS_MODULE, + .llseek = noop_llseek, }; static struct miscdevice vmwdt_dev = { diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c index f5ea3384a4b9..3b94044027c2 100644 --- a/drivers/s390/char/zcore.c +++ b/drivers/s390/char/zcore.c @@ -459,6 +459,7 @@ static const struct file_operations zcore_memmap_fops = { .read = zcore_memmap_read, .open = zcore_memmap_open, .release = zcore_memmap_release, + .llseek = no_llseek, }; static ssize_t zcore_reipl_write(struct file *filp, const char __user *buf, @@ -486,6 +487,7 @@ static const struct file_operations zcore_reipl_fops = { .write = zcore_reipl_write, .open = zcore_reipl_open, .release = zcore_reipl_release, + .llseek = no_llseek, }; #ifdef CONFIG_32BIT diff --git a/drivers/s390/cio/chsc_sch.c b/drivers/s390/cio/chsc_sch.c index a83877c664a6..f2b77e7bfc6f 100644 --- a/drivers/s390/cio/chsc_sch.c +++ b/drivers/s390/cio/chsc_sch.c @@ -806,6 +806,7 @@ static const struct file_operations chsc_fops = { .open = nonseekable_open, .unlocked_ioctl = chsc_ioctl, .compat_ioctl = chsc_ioctl, + .llseek = no_llseek, }; static struct miscdevice chsc_misc_device = { diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index ac94ac751459..ca8e1c240c3c 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -1067,6 +1067,7 @@ static ssize_t cio_settle_write(struct file *file, const char __user *buf, static const struct file_operations cio_settle_proc_fops = { .open = nonseekable_open, .write = cio_settle_write, + .llseek = no_llseek, }; static int __init cio_settle_init(void) diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index 41e0aaefafd5..f5221749d180 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -897,7 +897,8 @@ static const struct file_operations zcrypt_fops = { .compat_ioctl = zcrypt_compat_ioctl, #endif .open = zcrypt_open, - .release = zcrypt_release + .release = zcrypt_release, + .llseek = no_llseek, }; /* diff --git a/drivers/s390/scsi/Makefile b/drivers/s390/scsi/Makefile index cb301cc6178c..c454ffebb63e 100644 --- a/drivers/s390/scsi/Makefile +++ b/drivers/s390/scsi/Makefile @@ -2,7 +2,8 @@ # Makefile for the S/390 specific device drivers # -zfcp-objs := zfcp_aux.o zfcp_ccw.o zfcp_scsi.o zfcp_erp.o zfcp_qdio.o \ - zfcp_fsf.o zfcp_dbf.o zfcp_sysfs.o zfcp_fc.o zfcp_cfdc.o +zfcp-objs := zfcp_aux.o zfcp_ccw.o zfcp_cfdc.o zfcp_dbf.o zfcp_erp.o \ + zfcp_fc.o zfcp_fsf.o zfcp_qdio.o zfcp_scsi.o zfcp_sysfs.o \ + zfcp_unit.o obj-$(CONFIG_ZFCP) += zfcp.o diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 96fa1f536394..044fb22718d2 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -56,7 +56,6 @@ static void __init zfcp_init_device_configure(char *busid, u64 wwpn, u64 lun) struct ccw_device *cdev; struct zfcp_adapter *adapter; struct zfcp_port *port; - struct zfcp_unit *unit; cdev = get_ccwdev_by_busid(&zfcp_ccw_driver, busid); if (!cdev) @@ -72,17 +71,11 @@ static void __init zfcp_init_device_configure(char *busid, u64 wwpn, u64 lun) port = zfcp_get_port_by_wwpn(adapter, wwpn); if (!port) goto out_port; + flush_work(&port->rport_work); - unit = zfcp_unit_enqueue(port, lun); - if (IS_ERR(unit)) - goto out_unit; - - zfcp_erp_unit_reopen(unit, 0, "auidc_1", NULL); - zfcp_erp_wait(adapter); - flush_work(&unit->scsi_work); - -out_unit: + zfcp_unit_add(port, lun); put_device(&port->dev); + out_port: zfcp_ccw_adapter_put(adapter); out_ccw_device: @@ -158,6 +151,9 @@ static int __init zfcp_module_init(void) fc_attach_transport(&zfcp_transport_functions); if (!zfcp_data.scsi_transport_template) goto out_transport; + scsi_transport_reserve_device(zfcp_data.scsi_transport_template, + sizeof(struct zfcp_scsi_dev)); + retval = misc_register(&zfcp_cfdc_misc); if (retval) { @@ -211,30 +207,6 @@ static void __exit zfcp_module_exit(void) module_exit(zfcp_module_exit); /** - * zfcp_get_unit_by_lun - find unit in unit list of port by FCP LUN - * @port: pointer to port to search for unit - * @fcp_lun: FCP LUN to search for - * - * Returns: pointer to zfcp_unit or NULL - */ -struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *port, u64 fcp_lun) -{ - unsigned long flags; - struct zfcp_unit *unit; - - read_lock_irqsave(&port->unit_list_lock, flags); - list_for_each_entry(unit, &port->unit_list, list) - if (unit->fcp_lun == fcp_lun) { - if (!get_device(&unit->dev)) - unit = NULL; - read_unlock_irqrestore(&port->unit_list_lock, flags); - return unit; - } - read_unlock_irqrestore(&port->unit_list_lock, flags); - return NULL; -} - -/** * zfcp_get_port_by_wwpn - find port in port list of adapter by wwpn * @adapter: pointer to adapter to search for port * @wwpn: wwpn to search for @@ -259,92 +231,6 @@ struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *adapter, return NULL; } -/** - * zfcp_unit_release - dequeue unit - * @dev: pointer to device - * - * waits until all work is done on unit and removes it then from the unit->list - * of the associated port. - */ -static void zfcp_unit_release(struct device *dev) -{ - struct zfcp_unit *unit = container_of(dev, struct zfcp_unit, dev); - - put_device(&unit->port->dev); - kfree(unit); -} - -/** - * zfcp_unit_enqueue - enqueue unit to unit list of a port. - * @port: pointer to port where unit is added - * @fcp_lun: FCP LUN of unit to be enqueued - * Returns: pointer to enqueued unit on success, ERR_PTR on error - * - * Sets up some unit internal structures and creates sysfs entry. - */ -struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun) -{ - struct zfcp_unit *unit; - int retval = -ENOMEM; - - get_device(&port->dev); - - unit = zfcp_get_unit_by_lun(port, fcp_lun); - if (unit) { - put_device(&unit->dev); - retval = -EEXIST; - goto err_out; - } - - unit = kzalloc(sizeof(struct zfcp_unit), GFP_KERNEL); - if (!unit) - goto err_out; - - unit->port = port; - unit->fcp_lun = fcp_lun; - unit->dev.parent = &port->dev; - unit->dev.release = zfcp_unit_release; - - if (dev_set_name(&unit->dev, "0x%016llx", - (unsigned long long) fcp_lun)) { - kfree(unit); - goto err_out; - } - retval = -EINVAL; - - INIT_WORK(&unit->scsi_work, zfcp_scsi_scan_work); - - spin_lock_init(&unit->latencies.lock); - unit->latencies.write.channel.min = 0xFFFFFFFF; - unit->latencies.write.fabric.min = 0xFFFFFFFF; - unit->latencies.read.channel.min = 0xFFFFFFFF; - unit->latencies.read.fabric.min = 0xFFFFFFFF; - unit->latencies.cmd.channel.min = 0xFFFFFFFF; - unit->latencies.cmd.fabric.min = 0xFFFFFFFF; - - if (device_register(&unit->dev)) { - put_device(&unit->dev); - goto err_out; - } - - if (sysfs_create_group(&unit->dev.kobj, &zfcp_sysfs_unit_attrs)) - goto err_out_put; - - write_lock_irq(&port->unit_list_lock); - list_add_tail(&unit->list, &port->unit_list); - write_unlock_irq(&port->unit_list_lock); - - atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &unit->status); - - return unit; - -err_out_put: - device_unregister(&unit->dev); -err_out: - put_device(&port->dev); - return ERR_PTR(retval); -} - static int zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter) { adapter->pool.erp_req = diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c index ce1cc7a11fb4..0833c2b51e39 100644 --- a/drivers/s390/scsi/zfcp_ccw.c +++ b/drivers/s390/scsi/zfcp_ccw.c @@ -46,8 +46,7 @@ static int zfcp_ccw_activate(struct ccw_device *cdev) if (!adapter) return 0; - zfcp_erp_modify_adapter_status(adapter, "ccresu1", NULL, - ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET); + zfcp_erp_set_adapter_status(adapter, ZFCP_STATUS_COMMON_RUNNING); zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, "ccresu2", NULL); zfcp_erp_wait(adapter); @@ -164,14 +163,7 @@ static int zfcp_ccw_set_online(struct ccw_device *cdev) BUG_ON(!zfcp_reqlist_isempty(adapter->req_list)); adapter->req_no = 0; - zfcp_erp_modify_adapter_status(adapter, "ccsonl1", NULL, - ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET); - zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, - "ccsonl2", NULL); - zfcp_erp_wait(adapter); - - flush_work(&adapter->scan_work); - + zfcp_ccw_activate(cdev); zfcp_ccw_adapter_put(adapter); return 0; } @@ -224,9 +216,8 @@ static int zfcp_ccw_notify(struct ccw_device *cdev, int event) break; case CIO_OPER: dev_info(&cdev->dev, "The FCP device is operational again\n"); - zfcp_erp_modify_adapter_status(adapter, "ccnoti3", NULL, - ZFCP_STATUS_COMMON_RUNNING, - ZFCP_SET); + zfcp_erp_set_adapter_status(adapter, + ZFCP_STATUS_COMMON_RUNNING); zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, "ccnoti4", NULL); break; diff --git a/drivers/s390/scsi/zfcp_cfdc.c b/drivers/s390/scsi/zfcp_cfdc.c index fcbd2b756da4..d692e229ecba 100644 --- a/drivers/s390/scsi/zfcp_cfdc.c +++ b/drivers/s390/scsi/zfcp_cfdc.c @@ -2,9 +2,10 @@ * zfcp device driver * * Userspace interface for accessing the - * Access Control Lists / Control File Data Channel + * Access Control Lists / Control File Data Channel; + * handling of response code and states for ports and LUNs. * - * Copyright IBM Corporation 2008, 2009 + * Copyright IBM Corporation 2008, 2010 */ #define KMSG_COMPONENT "zfcp" @@ -251,8 +252,9 @@ static const struct file_operations zfcp_cfdc_fops = { .open = nonseekable_open, .unlocked_ioctl = zfcp_cfdc_dev_ioctl, #ifdef CONFIG_COMPAT - .compat_ioctl = zfcp_cfdc_dev_ioctl + .compat_ioctl = zfcp_cfdc_dev_ioctl, #endif + .llseek = no_llseek, }; struct miscdevice zfcp_cfdc_misc = { @@ -260,3 +262,184 @@ struct miscdevice zfcp_cfdc_misc = { .name = "zfcp_cfdc", .fops = &zfcp_cfdc_fops, }; + +/** + * zfcp_cfdc_adapter_access_changed - Process change in adapter ACT + * @adapter: Adapter where the Access Control Table (ACT) changed + * + * After a change in the adapter ACT, check if access to any + * previously denied resources is now possible. + */ +void zfcp_cfdc_adapter_access_changed(struct zfcp_adapter *adapter) +{ + unsigned long flags; + struct zfcp_port *port; + struct scsi_device *sdev; + struct zfcp_scsi_dev *zfcp_sdev; + int status; + + if (adapter->connection_features & FSF_FEATURE_NPIV_MODE) + return; + + read_lock_irqsave(&adapter->port_list_lock, flags); + list_for_each_entry(port, &adapter->port_list, list) { + status = atomic_read(&port->status); + if ((status & ZFCP_STATUS_COMMON_ACCESS_DENIED) || + (status & ZFCP_STATUS_COMMON_ACCESS_BOXED)) + zfcp_erp_port_reopen(port, + ZFCP_STATUS_COMMON_ERP_FAILED, + "cfaac_1", NULL); + } + read_unlock_irqrestore(&adapter->port_list_lock, flags); + + shost_for_each_device(sdev, port->adapter->scsi_host) { + zfcp_sdev = sdev_to_zfcp(sdev); + status = atomic_read(&zfcp_sdev->status); + if ((status & ZFCP_STATUS_COMMON_ACCESS_DENIED) || + (status & ZFCP_STATUS_COMMON_ACCESS_BOXED)) + zfcp_erp_lun_reopen(sdev, + ZFCP_STATUS_COMMON_ERP_FAILED, + "cfaac_2", NULL); + } +} + +static void zfcp_act_eval_err(struct zfcp_adapter *adapter, u32 table) +{ + u16 subtable = table >> 16; + u16 rule = table & 0xffff; + const char *act_type[] = { "unknown", "OS", "WWPN", "DID", "LUN" }; + + if (subtable && subtable < ARRAY_SIZE(act_type)) + dev_warn(&adapter->ccw_device->dev, + "Access denied according to ACT rule type %s, " + "rule %d\n", act_type[subtable], rule); +} + +/** + * zfcp_cfdc_port_denied - Process "access denied" for port + * @port: The port where the acces has been denied + * @qual: The FSF status qualifier for the access denied FSF status + */ +void zfcp_cfdc_port_denied(struct zfcp_port *port, + union fsf_status_qual *qual) +{ + dev_warn(&port->adapter->ccw_device->dev, + "Access denied to port 0x%016Lx\n", + (unsigned long long)port->wwpn); + + zfcp_act_eval_err(port->adapter, qual->halfword[0]); + zfcp_act_eval_err(port->adapter, qual->halfword[1]); + zfcp_erp_set_port_status(port, + ZFCP_STATUS_COMMON_ERP_FAILED | + ZFCP_STATUS_COMMON_ACCESS_DENIED); +} + +/** + * zfcp_cfdc_lun_denied - Process "access denied" for LUN + * @sdev: The SCSI device / LUN where the access has been denied + * @qual: The FSF status qualifier for the access denied FSF status + */ +void zfcp_cfdc_lun_denied(struct scsi_device *sdev, + union fsf_status_qual *qual) +{ + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); + + dev_warn(&zfcp_sdev->port->adapter->ccw_device->dev, + "Access denied to LUN 0x%016Lx on port 0x%016Lx\n", + zfcp_scsi_dev_lun(sdev), + (unsigned long long)zfcp_sdev->port->wwpn); + zfcp_act_eval_err(zfcp_sdev->port->adapter, qual->halfword[0]); + zfcp_act_eval_err(zfcp_sdev->port->adapter, qual->halfword[1]); + zfcp_erp_set_lun_status(sdev, + ZFCP_STATUS_COMMON_ERP_FAILED | + ZFCP_STATUS_COMMON_ACCESS_DENIED); + + atomic_clear_mask(ZFCP_STATUS_LUN_SHARED, &zfcp_sdev->status); + atomic_clear_mask(ZFCP_STATUS_LUN_READONLY, &zfcp_sdev->status); +} + +/** + * zfcp_cfdc_lun_shrng_vltn - Evaluate LUN sharing violation status + * @sdev: The LUN / SCSI device where sharing violation occurred + * @qual: The FSF status qualifier from the LUN sharing violation + */ +void zfcp_cfdc_lun_shrng_vltn(struct scsi_device *sdev, + union fsf_status_qual *qual) +{ + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); + + if (qual->word[0]) + dev_warn(&zfcp_sdev->port->adapter->ccw_device->dev, + "LUN 0x%Lx on port 0x%Lx is already in " + "use by CSS%d, MIF Image ID %x\n", + zfcp_scsi_dev_lun(sdev), + (unsigned long long)zfcp_sdev->port->wwpn, + qual->fsf_queue_designator.cssid, + qual->fsf_queue_designator.hla); + else + zfcp_act_eval_err(zfcp_sdev->port->adapter, qual->word[2]); + + zfcp_erp_set_lun_status(sdev, + ZFCP_STATUS_COMMON_ERP_FAILED | + ZFCP_STATUS_COMMON_ACCESS_DENIED); + atomic_clear_mask(ZFCP_STATUS_LUN_SHARED, &zfcp_sdev->status); + atomic_clear_mask(ZFCP_STATUS_LUN_READONLY, &zfcp_sdev->status); +} + +/** + * zfcp_cfdc_open_lun_eval - Eval access ctrl. status for successful "open lun" + * @sdev: The SCSI device / LUN where to evaluate the status + * @bottom: The qtcb bottom with the status from the "open lun" + * + * Returns: 0 if LUN is usable, -EACCES if the access control table + * reports an unsupported configuration. + */ +int zfcp_cfdc_open_lun_eval(struct scsi_device *sdev, + struct fsf_qtcb_bottom_support *bottom) +{ + int shared, rw; + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); + struct zfcp_adapter *adapter = zfcp_sdev->port->adapter; + + if ((adapter->connection_features & FSF_FEATURE_NPIV_MODE) || + !(adapter->adapter_features & FSF_FEATURE_LUN_SHARING) || + zfcp_ccw_priv_sch(adapter)) + return 0; + + shared = !(bottom->lun_access_info & FSF_UNIT_ACCESS_EXCLUSIVE); + rw = (bottom->lun_access_info & FSF_UNIT_ACCESS_OUTBOUND_TRANSFER); + + if (shared) + atomic_set_mask(ZFCP_STATUS_LUN_SHARED, &zfcp_sdev->status); + + if (!rw) { + atomic_set_mask(ZFCP_STATUS_LUN_READONLY, &zfcp_sdev->status); + dev_info(&adapter->ccw_device->dev, "SCSI device at LUN " + "0x%016Lx on port 0x%016Lx opened read-only\n", + zfcp_scsi_dev_lun(sdev), + (unsigned long long)zfcp_sdev->port->wwpn); + } + + if (!shared && !rw) { + dev_err(&adapter->ccw_device->dev, "Exclusive read-only access " + "not supported (LUN 0x%016Lx, port 0x%016Lx)\n", + zfcp_scsi_dev_lun(sdev), + (unsigned long long)zfcp_sdev->port->wwpn); + zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_ERP_FAILED); + zfcp_erp_lun_shutdown(sdev, 0, "fsouh_6", NULL); + return -EACCES; + } + + if (shared && rw) { + dev_err(&adapter->ccw_device->dev, + "Shared read-write access not supported " + "(LUN 0x%016Lx, port 0x%016Lx)\n", + zfcp_scsi_dev_lun(sdev), + (unsigned long long)zfcp_sdev->port->wwpn); + zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_ERP_FAILED); + zfcp_erp_lun_shutdown(sdev, 0, "fsosh_8", NULL); + return -EACCES; + } + + return 0; +} diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index a86117b0d6e1..2cdd6b28ff7f 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -154,7 +154,6 @@ void _zfcp_dbf_hba_fsf_response(const char *tag2, int level, scsi_cmnd = (struct scsi_cmnd *)fsf_req->data; 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; } @@ -330,7 +329,6 @@ static void zfcp_dbf_hba_view_response(char **p, 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"); break; @@ -482,7 +480,7 @@ static int zfcp_dbf_rec_view_format(debug_info_t *id, struct debug_view *view, zfcp_dbf_out(&p, "fcp_lun", "0x%016Lx", r->u.trigger.fcp_lun); zfcp_dbf_out(&p, "adapter_status", "0x%08x", r->u.trigger.as); zfcp_dbf_out(&p, "port_status", "0x%08x", r->u.trigger.ps); - zfcp_dbf_out(&p, "unit_status", "0x%08x", r->u.trigger.us); + zfcp_dbf_out(&p, "lun_status", "0x%08x", r->u.trigger.ls); break; case ZFCP_REC_DBF_ID_ACTION: zfcp_dbf_out(&p, "erp_action", "0x%016Lx", r->u.action.action); @@ -600,19 +598,20 @@ void zfcp_dbf_rec_port(char *id, void *ref, struct zfcp_port *port) } /** - * zfcp_dbf_rec_unit - trace event for unit state change + * zfcp_dbf_rec_lun - trace event for LUN state change * @id: identifier for trigger of state change * @ref: additional reference (e.g. request) - * @unit: unit + * @sdev: SCSI device */ -void zfcp_dbf_rec_unit(char *id, void *ref, struct zfcp_unit *unit) +void zfcp_dbf_rec_lun(char *id, void *ref, struct scsi_device *sdev) { - struct zfcp_port *port = unit->port; + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); + struct zfcp_port *port = zfcp_sdev->port; struct zfcp_dbf *dbf = port->adapter->dbf; - zfcp_dbf_rec_target(id, ref, dbf, &unit->status, - &unit->erp_counter, port->wwpn, port->d_id, - unit->fcp_lun); + zfcp_dbf_rec_target(id, ref, dbf, &zfcp_sdev->status, + &zfcp_sdev->erp_counter, port->wwpn, port->d_id, + zfcp_scsi_dev_lun(sdev)); } /** @@ -624,11 +623,11 @@ void zfcp_dbf_rec_unit(char *id, void *ref, struct zfcp_unit *unit) * @action: address of error recovery action struct * @adapter: adapter * @port: port - * @unit: unit + * @sdev: SCSI device */ void zfcp_dbf_rec_trigger(char *id2, void *ref, u8 want, u8 need, void *action, struct zfcp_adapter *adapter, struct zfcp_port *port, - struct zfcp_unit *unit) + struct scsi_device *sdev) { struct zfcp_dbf *dbf = adapter->dbf; struct zfcp_dbf_rec_record *r = &dbf->rec_buf; @@ -647,9 +646,10 @@ void zfcp_dbf_rec_trigger(char *id2, void *ref, u8 want, u8 need, void *action, r->u.trigger.ps = atomic_read(&port->status); r->u.trigger.wwpn = port->wwpn; } - if (unit) - r->u.trigger.us = atomic_read(&unit->status); - r->u.trigger.fcp_lun = unit ? unit->fcp_lun : ZFCP_DBF_INVALID_LUN; + if (sdev) + r->u.trigger.ls = atomic_read(&sdev_to_zfcp(sdev)->status); + r->u.trigger.fcp_lun = sdev ? zfcp_scsi_dev_lun(sdev) : + ZFCP_DBF_INVALID_LUN; debug_event(dbf->rec, action ? 1 : 4, r, sizeof(*r)); spin_unlock_irqrestore(&dbf->rec_lock, flags); } @@ -879,7 +879,6 @@ void _zfcp_dbf_scsi(const char *tag, const char *tag2, int level, } rec->scsi_result = scsi_cmnd->result; rec->scsi_cmnd = (unsigned long)scsi_cmnd; - rec->scsi_serial = scsi_cmnd->serial_number; memcpy(rec->scsi_opcode, scsi_cmnd->cmnd, min((int)scsi_cmnd->cmd_len, ZFCP_DBF_SCSI_OPCODE)); @@ -948,7 +947,6 @@ static int zfcp_dbf_scsi_view_format(debug_info_t *id, struct debug_view *view, zfcp_dbf_out(&p, "scsi_lun", "0x%08x", r->scsi_lun); zfcp_dbf_out(&p, "scsi_result", "0x%08x", r->scsi_result); zfcp_dbf_out(&p, "scsi_cmnd", "0x%0Lx", r->scsi_cmnd); - zfcp_dbf_out(&p, "scsi_serial", "0x%016Lx", r->scsi_serial); zfcp_dbf_outd(&p, "scsi_opcode", r->scsi_opcode, ZFCP_DBF_SCSI_OPCODE, 0, ZFCP_DBF_SCSI_OPCODE); zfcp_dbf_out(&p, "scsi_retries", "0x%02x", r->scsi_retries); diff --git a/drivers/s390/scsi/zfcp_dbf.h b/drivers/s390/scsi/zfcp_dbf.h index 2bcc3403126a..04081b1b62b4 100644 --- a/drivers/s390/scsi/zfcp_dbf.h +++ b/drivers/s390/scsi/zfcp_dbf.h @@ -60,7 +60,7 @@ struct zfcp_dbf_rec_record_trigger { u8 need; u32 as; u32 ps; - u32 us; + u32 ls; u64 ref; u64 action; u64 wwpn; @@ -110,7 +110,6 @@ struct zfcp_dbf_hba_record_response { union { struct { u64 cmnd; - u64 serial; u32 data_dir; } fcp; struct { @@ -206,7 +205,6 @@ struct zfcp_dbf_scsi_record { u32 scsi_lun; u32 scsi_result; u64 scsi_cmnd; - u64 scsi_serial; #define ZFCP_DBF_SCSI_OPCODE 16 u8 scsi_opcode[ZFCP_DBF_SCSI_OPCODE]; u8 scsi_retries; @@ -350,16 +348,16 @@ void zfcp_dbf_scsi_abort(const char *tag, struct zfcp_dbf *dbf, /** * zfcp_dbf_scsi_devreset - trace event for Logical Unit or Target Reset * @tag: tag indicating success or failure of reset operation + * @scmnd: SCSI command which caused this error recovery * @flag: indicates type of reset (Target Reset, Logical Unit Reset) - * @unit: unit that needs reset - * @scsi_cmnd: SCSI command which caused this error recovery */ static inline -void zfcp_dbf_scsi_devreset(const char *tag, u8 flag, struct zfcp_unit *unit, - struct scsi_cmnd *scsi_cmnd) +void zfcp_dbf_scsi_devreset(const char *tag, struct scsi_cmnd *scmnd, u8 flag) { + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scmnd->device); + zfcp_dbf_scsi(flag == FCP_TMF_TGT_RESET ? "trst" : "lrst", tag, 1, - unit->port->adapter->dbf, scsi_cmnd, NULL, 0); + zfcp_sdev->port->adapter->dbf, scmnd, NULL, 0); } #endif /* ZFCP_DBF_H */ diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index e1c6b6e05a75..9ae1d0a6f627 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -85,8 +85,8 @@ struct zfcp_reqlist; #define ZFCP_STATUS_PORT_LINK_TEST 0x00000002 /* logical unit status */ -#define ZFCP_STATUS_UNIT_SHARED 0x00000004 -#define ZFCP_STATUS_UNIT_READONLY 0x00000008 +#define ZFCP_STATUS_LUN_SHARED 0x00000004 +#define ZFCP_STATUS_LUN_READONLY 0x00000008 /* FSF request status (this does not have a common part) */ #define ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT 0x00000002 @@ -118,7 +118,7 @@ struct zfcp_erp_action { int action; /* requested action code */ struct zfcp_adapter *adapter; /* device which should be recovered */ struct zfcp_port *port; - struct zfcp_unit *unit; + struct scsi_device *sdev; u32 status; /* recovery status */ u32 step; /* active step of this erp action */ unsigned long fsf_req_id; @@ -219,21 +219,66 @@ struct zfcp_port { unsigned int starget_id; }; +/** + * struct zfcp_unit - LUN configured via zfcp sysfs + * @dev: struct device for sysfs representation and reference counting + * @list: entry in LUN/unit list per zfcp_port + * @port: reference to zfcp_port where this LUN is configured + * @fcp_lun: 64 bit LUN value + * @scsi_work: for running scsi_scan_target + * + * This is the representation of a LUN that has been configured for + * usage. The main data here is the 64 bit LUN value, data for + * running I/O and recovery is in struct zfcp_scsi_dev. + */ struct zfcp_unit { - struct device dev; - struct list_head list; /* list of logical units */ - struct zfcp_port *port; /* remote port of unit */ - atomic_t status; /* status of this logical unit */ - u64 fcp_lun; /* own FCP_LUN */ - u32 handle; /* handle assigned by FSF */ - struct scsi_device *device; /* scsi device struct pointer */ - struct zfcp_erp_action erp_action; /* pending error recovery */ - atomic_t erp_counter; - struct zfcp_latencies latencies; + struct device dev; + struct list_head list; + struct zfcp_port *port; + u64 fcp_lun; struct work_struct scsi_work; }; /** + * struct zfcp_scsi_dev - zfcp data per SCSI device + * @status: zfcp internal status flags + * @lun_handle: handle from "open lun" for issuing FSF requests + * @erp_action: zfcp erp data for opening and recovering this LUN + * @erp_counter: zfcp erp counter for this LUN + * @latencies: FSF channel and fabric latencies + * @port: zfcp_port where this LUN belongs to + */ +struct zfcp_scsi_dev { + atomic_t status; + u32 lun_handle; + struct zfcp_erp_action erp_action; + atomic_t erp_counter; + struct zfcp_latencies latencies; + struct zfcp_port *port; +}; + +/** + * sdev_to_zfcp - Access zfcp LUN data for SCSI device + * @sdev: scsi_device where to get the zfcp_scsi_dev pointer + */ +static inline struct zfcp_scsi_dev *sdev_to_zfcp(struct scsi_device *sdev) +{ + return scsi_transport_device_data(sdev); +} + +/** + * zfcp_scsi_dev_lun - Return SCSI device LUN as 64 bit FCP LUN + * @sdev: SCSI device where to get the LUN from + */ +static inline u64 zfcp_scsi_dev_lun(struct scsi_device *sdev) +{ + u64 fcp_lun; + + int_to_scsilun(sdev->lun, (struct scsi_lun *)&fcp_lun); + return fcp_lun; +} + +/** * struct zfcp_fsf_req - basic FSF request structure * @list: list of FSF requests * @req_id: unique request ID @@ -249,7 +294,6 @@ struct zfcp_unit { * @erp_action: reference to erp action if request issued on behalf of ERP * @pool: reference to memory pool if used for this request * @issued: time when request was send (STCK) - * @unit: reference to unit if this request is a SCSI request * @handler: handler which should be called to process response */ struct zfcp_fsf_req { @@ -267,7 +311,6 @@ struct zfcp_fsf_req { struct zfcp_erp_action *erp_action; mempool_t *pool; unsigned long long issued; - struct zfcp_unit *unit; void (*handler)(struct zfcp_fsf_req *); }; @@ -282,9 +325,4 @@ struct zfcp_data { struct kmem_cache *adisc_cache; }; -/********************** ZFCP SPECIFIC DEFINES ********************************/ - -#define ZFCP_SET 0x00000100 -#define ZFCP_CLEAR 0x00000200 - #endif /* ZFCP_DEF_H */ diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 160b432c907f..d37c7331f244 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -21,6 +21,7 @@ enum zfcp_erp_act_flags { ZFCP_STATUS_ERP_DISMISSING = 0x00100000, ZFCP_STATUS_ERP_DISMISSED = 0x00200000, ZFCP_STATUS_ERP_LOWMEM = 0x00400000, + ZFCP_STATUS_ERP_NO_REF = 0x00800000, }; enum zfcp_erp_steps { @@ -29,12 +30,12 @@ enum zfcp_erp_steps { ZFCP_ERP_STEP_PHYS_PORT_CLOSING = 0x0010, ZFCP_ERP_STEP_PORT_CLOSING = 0x0100, ZFCP_ERP_STEP_PORT_OPENING = 0x0800, - ZFCP_ERP_STEP_UNIT_CLOSING = 0x1000, - ZFCP_ERP_STEP_UNIT_OPENING = 0x2000, + ZFCP_ERP_STEP_LUN_CLOSING = 0x1000, + ZFCP_ERP_STEP_LUN_OPENING = 0x2000, }; enum zfcp_erp_act_type { - ZFCP_ERP_ACTION_REOPEN_UNIT = 1, + ZFCP_ERP_ACTION_REOPEN_LUN = 1, ZFCP_ERP_ACTION_REOPEN_PORT = 2, ZFCP_ERP_ACTION_REOPEN_PORT_FORCED = 3, ZFCP_ERP_ACTION_REOPEN_ADAPTER = 4, @@ -56,9 +57,8 @@ enum zfcp_erp_act_result { static void zfcp_erp_adapter_block(struct zfcp_adapter *adapter, int mask) { - zfcp_erp_modify_adapter_status(adapter, "erablk1", NULL, - ZFCP_STATUS_COMMON_UNBLOCKED | mask, - ZFCP_CLEAR); + zfcp_erp_clear_adapter_status(adapter, + ZFCP_STATUS_COMMON_UNBLOCKED | mask); } static int zfcp_erp_action_exists(struct zfcp_erp_action *act) @@ -88,24 +88,24 @@ static void zfcp_erp_action_dismiss(struct zfcp_erp_action *act) zfcp_erp_action_ready(act); } -static void zfcp_erp_action_dismiss_unit(struct zfcp_unit *unit) +static void zfcp_erp_action_dismiss_lun(struct scsi_device *sdev) { - if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_ERP_INUSE) - zfcp_erp_action_dismiss(&unit->erp_action); + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); + + if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_ERP_INUSE) + zfcp_erp_action_dismiss(&zfcp_sdev->erp_action); } static void zfcp_erp_action_dismiss_port(struct zfcp_port *port) { - struct zfcp_unit *unit; + struct scsi_device *sdev; if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_INUSE) zfcp_erp_action_dismiss(&port->erp_action); - else { - read_lock(&port->unit_list_lock); - list_for_each_entry(unit, &port->unit_list, list) - zfcp_erp_action_dismiss_unit(unit); - read_unlock(&port->unit_list_lock); - } + else + shost_for_each_device(sdev, port->adapter->scsi_host) + if (sdev_to_zfcp(sdev)->port == port) + zfcp_erp_action_dismiss_lun(sdev); } static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter) @@ -124,15 +124,17 @@ static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter) static int zfcp_erp_required_act(int want, struct zfcp_adapter *adapter, struct zfcp_port *port, - struct zfcp_unit *unit) + struct scsi_device *sdev) { int need = want; - int u_status, p_status, a_status; + int l_status, p_status, a_status; + struct zfcp_scsi_dev *zfcp_sdev; switch (want) { - case ZFCP_ERP_ACTION_REOPEN_UNIT: - u_status = atomic_read(&unit->status); - if (u_status & ZFCP_STATUS_COMMON_ERP_INUSE) + case ZFCP_ERP_ACTION_REOPEN_LUN: + zfcp_sdev = sdev_to_zfcp(sdev); + l_status = atomic_read(&zfcp_sdev->status); + if (l_status & ZFCP_STATUS_COMMON_ERP_INUSE) return 0; p_status = atomic_read(&port->status); if (!(p_status & ZFCP_STATUS_COMMON_RUNNING) || @@ -169,22 +171,26 @@ static int zfcp_erp_required_act(int want, struct zfcp_adapter *adapter, return need; } -static struct zfcp_erp_action *zfcp_erp_setup_act(int need, +static struct zfcp_erp_action *zfcp_erp_setup_act(int need, u32 act_status, struct zfcp_adapter *adapter, struct zfcp_port *port, - struct zfcp_unit *unit) + struct scsi_device *sdev) { struct zfcp_erp_action *erp_action; - u32 status = 0; + struct zfcp_scsi_dev *zfcp_sdev; switch (need) { - case ZFCP_ERP_ACTION_REOPEN_UNIT: - if (!get_device(&unit->dev)) - return NULL; - atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &unit->status); - erp_action = &unit->erp_action; - if (!(atomic_read(&unit->status) & ZFCP_STATUS_COMMON_RUNNING)) - status = ZFCP_STATUS_ERP_CLOSE_ONLY; + case ZFCP_ERP_ACTION_REOPEN_LUN: + zfcp_sdev = sdev_to_zfcp(sdev); + if (!(act_status & ZFCP_STATUS_ERP_NO_REF)) + if (scsi_device_get(sdev)) + return NULL; + atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, + &zfcp_sdev->status); + erp_action = &zfcp_sdev->erp_action; + if (!(atomic_read(&zfcp_sdev->status) & + ZFCP_STATUS_COMMON_RUNNING)) + act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY; break; case ZFCP_ERP_ACTION_REOPEN_PORT: @@ -195,7 +201,7 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status); erp_action = &port->erp_action; if (!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_RUNNING)) - status = ZFCP_STATUS_ERP_CLOSE_ONLY; + act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY; break; case ZFCP_ERP_ACTION_REOPEN_ADAPTER: @@ -205,7 +211,7 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, erp_action = &adapter->erp_action; if (!(atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_RUNNING)) - status = ZFCP_STATUS_ERP_CLOSE_ONLY; + act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY; break; default: @@ -215,16 +221,17 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, memset(erp_action, 0, sizeof(struct zfcp_erp_action)); erp_action->adapter = adapter; erp_action->port = port; - erp_action->unit = unit; + erp_action->sdev = sdev; erp_action->action = need; - erp_action->status = status; + erp_action->status = act_status; return erp_action; } static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter, struct zfcp_port *port, - struct zfcp_unit *unit, char *id, void *ref) + struct scsi_device *sdev, + char *id, void *ref, u32 act_status) { int retval = 1, need; struct zfcp_erp_action *act = NULL; @@ -232,21 +239,21 @@ static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter, if (!adapter->erp_thread) return -EIO; - need = zfcp_erp_required_act(want, adapter, port, unit); + need = zfcp_erp_required_act(want, adapter, port, sdev); if (!need) goto out; - atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, &adapter->status); - act = zfcp_erp_setup_act(need, adapter, port, unit); + act = zfcp_erp_setup_act(need, act_status, adapter, port, sdev); if (!act) goto out; + atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, &adapter->status); ++adapter->erp_total_count; list_add_tail(&act->list, &adapter->erp_ready_head); wake_up(&adapter->erp_ready_wq); zfcp_dbf_rec_thread("eracte1", adapter->dbf); retval = 0; out: - zfcp_dbf_rec_trigger(id, ref, want, need, act, adapter, port, unit); + zfcp_dbf_rec_trigger(id, ref, want, need, act, adapter, port, sdev); return retval; } @@ -258,11 +265,12 @@ static int _zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, /* ensure propagation of failed status to new devices */ if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { - zfcp_erp_adapter_failed(adapter, "erareo1", NULL); + zfcp_erp_set_adapter_status(adapter, + ZFCP_STATUS_COMMON_ERP_FAILED); return -EIO; } return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, - adapter, NULL, NULL, id, ref); + adapter, NULL, NULL, id, ref, 0); } /** @@ -282,10 +290,11 @@ void zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear, write_lock_irqsave(&adapter->erp_lock, flags); if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) - zfcp_erp_adapter_failed(adapter, "erareo1", NULL); + zfcp_erp_set_adapter_status(adapter, + ZFCP_STATUS_COMMON_ERP_FAILED); else zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, adapter, - NULL, NULL, id, ref); + NULL, NULL, id, ref, 0); write_unlock_irqrestore(&adapter->erp_lock, flags); } @@ -317,25 +326,10 @@ void zfcp_erp_port_shutdown(struct zfcp_port *port, int clear, char *id, zfcp_erp_port_reopen(port, clear | flags, id, ref); } -/** - * zfcp_erp_unit_shutdown - Shutdown unit - * @unit: Unit to shut down. - * @clear: Status flags to clear. - * @id: Id for debug trace event. - * @ref: Reference for debug trace event. - */ -void zfcp_erp_unit_shutdown(struct zfcp_unit *unit, int clear, char *id, - void *ref) -{ - int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED; - zfcp_erp_unit_reopen(unit, clear | flags, id, ref); -} - static void zfcp_erp_port_block(struct zfcp_port *port, int clear) { - zfcp_erp_modify_port_status(port, "erpblk1", NULL, - ZFCP_STATUS_COMMON_UNBLOCKED | clear, - ZFCP_CLEAR); + zfcp_erp_clear_port_status(port, + ZFCP_STATUS_COMMON_UNBLOCKED | clear); } static void _zfcp_erp_port_forced_reopen(struct zfcp_port *port, @@ -348,7 +342,7 @@ static void _zfcp_erp_port_forced_reopen(struct zfcp_port *port, return; zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT_FORCED, - port->adapter, port, NULL, id, ref); + port->adapter, port, NULL, id, ref, 0); } /** @@ -376,12 +370,12 @@ static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id, if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { /* ensure propagation of failed status to new devices */ - zfcp_erp_port_failed(port, "erpreo1", NULL); + zfcp_erp_set_port_status(port, ZFCP_STATUS_COMMON_ERP_FAILED); return -EIO; } return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT, - port->adapter, port, NULL, id, ref); + port->adapter, port, NULL, id, ref, 0); } /** @@ -404,53 +398,88 @@ int zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id, void *ref) return retval; } -static void zfcp_erp_unit_block(struct zfcp_unit *unit, int clear_mask) +static void zfcp_erp_lun_block(struct scsi_device *sdev, int clear_mask) { - zfcp_erp_modify_unit_status(unit, "erublk1", NULL, - ZFCP_STATUS_COMMON_UNBLOCKED | clear_mask, - ZFCP_CLEAR); + zfcp_erp_clear_lun_status(sdev, + ZFCP_STATUS_COMMON_UNBLOCKED | clear_mask); } -static void _zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear, char *id, - void *ref) +static void _zfcp_erp_lun_reopen(struct scsi_device *sdev, int clear, char *id, + void *ref, u32 act_status) { - struct zfcp_adapter *adapter = unit->port->adapter; + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); + struct zfcp_adapter *adapter = zfcp_sdev->port->adapter; - zfcp_erp_unit_block(unit, clear); + zfcp_erp_lun_block(sdev, clear); - if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_ERP_FAILED) + if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_ERP_FAILED) return; - zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_UNIT, - adapter, unit->port, unit, id, ref); + zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_LUN, adapter, + zfcp_sdev->port, sdev, id, ref, act_status); } /** - * zfcp_erp_unit_reopen - initiate reopen of a unit - * @unit: unit to be reopened - * @clear_mask: specifies flags in unit status to be cleared + * zfcp_erp_lun_reopen - initiate reopen of a LUN + * @sdev: SCSI device / LUN to be reopened + * @clear_mask: specifies flags in LUN status to be cleared * Return: 0 on success, < 0 on error */ -void zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear, char *id, - void *ref) +void zfcp_erp_lun_reopen(struct scsi_device *sdev, int clear, char *id, + void *ref) { unsigned long flags; - struct zfcp_port *port = unit->port; + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); + struct zfcp_port *port = zfcp_sdev->port; struct zfcp_adapter *adapter = port->adapter; write_lock_irqsave(&adapter->erp_lock, flags); - _zfcp_erp_unit_reopen(unit, clear, id, ref); + _zfcp_erp_lun_reopen(sdev, clear, id, ref, 0); write_unlock_irqrestore(&adapter->erp_lock, flags); } -static int status_change_set(unsigned long mask, atomic_t *status) +/** + * zfcp_erp_lun_shutdown - Shutdown LUN + * @sdev: SCSI device / LUN to shut down. + * @clear: Status flags to clear. + * @id: Id for debug trace event. + * @ref: Reference for debug trace event. + */ +void zfcp_erp_lun_shutdown(struct scsi_device *sdev, int clear, char *id, + void *ref) { - return (atomic_read(status) ^ mask) & mask; + int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED; + zfcp_erp_lun_reopen(sdev, clear | flags, id, ref); } -static int status_change_clear(unsigned long mask, atomic_t *status) +/** + * zfcp_erp_lun_shutdown_wait - Shutdown LUN and wait for erp completion + * @sdev: SCSI device / LUN to shut down. + * @id: Id for debug trace event. + * + * Do not acquire a reference for the LUN when creating the ERP + * action. It is safe, because this function waits for the ERP to + * complete first. This allows to shutdown the LUN, even when the SCSI + * device is in the state SDEV_DEL when scsi_device_get will fail. + */ +void zfcp_erp_lun_shutdown_wait(struct scsi_device *sdev, char *id) { - return atomic_read(status) & mask; + unsigned long flags; + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); + struct zfcp_port *port = zfcp_sdev->port; + struct zfcp_adapter *adapter = port->adapter; + int clear = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED; + + write_lock_irqsave(&adapter->erp_lock, flags); + _zfcp_erp_lun_reopen(sdev, clear, id, NULL, ZFCP_STATUS_ERP_NO_REF); + write_unlock_irqrestore(&adapter->erp_lock, flags); + + zfcp_erp_wait(adapter); +} + +static int status_change_set(unsigned long mask, atomic_t *status) +{ + return (atomic_read(status) ^ mask) & mask; } static void zfcp_erp_adapter_unblock(struct zfcp_adapter *adapter) @@ -467,11 +496,13 @@ static void zfcp_erp_port_unblock(struct zfcp_port *port) atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status); } -static void zfcp_erp_unit_unblock(struct zfcp_unit *unit) +static void zfcp_erp_lun_unblock(struct scsi_device *sdev) { - if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status)) - zfcp_dbf_rec_unit("eruubl1", NULL, unit); - atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status); + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); + + if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &zfcp_sdev->status)) + zfcp_dbf_rec_lun("erlubl1", NULL, sdev); + atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &zfcp_sdev->status); } static void zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action) @@ -559,15 +590,14 @@ static void _zfcp_erp_port_reopen_all(struct zfcp_adapter *adapter, read_unlock(&adapter->port_list_lock); } -static void _zfcp_erp_unit_reopen_all(struct zfcp_port *port, int clear, - char *id, void *ref) +static void _zfcp_erp_lun_reopen_all(struct zfcp_port *port, int clear, + char *id, void *ref) { - struct zfcp_unit *unit; + struct scsi_device *sdev; - read_lock(&port->unit_list_lock); - list_for_each_entry(unit, &port->unit_list, list) - _zfcp_erp_unit_reopen(unit, clear, id, ref); - read_unlock(&port->unit_list_lock); + shost_for_each_device(sdev, port->adapter->scsi_host) + if (sdev_to_zfcp(sdev)->port == port) + _zfcp_erp_lun_reopen(sdev, clear, id, ref, 0); } static void zfcp_erp_strategy_followup_failed(struct zfcp_erp_action *act) @@ -582,8 +612,8 @@ static void zfcp_erp_strategy_followup_failed(struct zfcp_erp_action *act) case ZFCP_ERP_ACTION_REOPEN_PORT: _zfcp_erp_port_reopen(act->port, 0, "ersff_3", NULL); break; - case ZFCP_ERP_ACTION_REOPEN_UNIT: - _zfcp_erp_unit_reopen(act->unit, 0, "ersff_4", NULL); + case ZFCP_ERP_ACTION_REOPEN_LUN: + _zfcp_erp_lun_reopen(act->sdev, 0, "ersff_4", NULL, 0); break; } } @@ -598,7 +628,7 @@ static void zfcp_erp_strategy_followup_success(struct zfcp_erp_action *act) _zfcp_erp_port_reopen(act->port, 0, "ersfs_2", NULL); break; case ZFCP_ERP_ACTION_REOPEN_PORT: - _zfcp_erp_unit_reopen_all(act->port, 0, "ersfs_3", NULL); + _zfcp_erp_lun_reopen_all(act->port, 0, "ersfs_3", NULL); break; } } @@ -742,9 +772,8 @@ static void zfcp_erp_adapter_strategy_close(struct zfcp_erp_action *act) zfcp_fsf_req_dismiss_all(adapter); adapter->fsf_req_seq_no = 0; zfcp_fc_wka_ports_force_offline(adapter->gs); - /* all ports and units are closed */ - zfcp_erp_modify_adapter_status(adapter, "erascl1", NULL, - ZFCP_STATUS_COMMON_OPEN, ZFCP_CLEAR); + /* all ports and LUNs are closed */ + zfcp_erp_clear_adapter_status(adapter, ZFCP_STATUS_COMMON_OPEN); atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK | ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status); @@ -861,7 +890,7 @@ static int zfcp_erp_open_ptp_port(struct zfcp_erp_action *act) struct zfcp_port *port = act->port; if (port->wwpn != adapter->peer_wwpn) { - zfcp_erp_port_failed(port, "eroptp1", NULL); + zfcp_erp_set_port_status(port, ZFCP_STATUS_COMMON_ERP_FAILED); return ZFCP_ERP_FAILED; } port->d_id = adapter->peer_d_id; @@ -933,82 +962,87 @@ close_init_done: return zfcp_erp_port_strategy_open_common(erp_action); } -static void zfcp_erp_unit_strategy_clearstati(struct zfcp_unit *unit) +static void zfcp_erp_lun_strategy_clearstati(struct scsi_device *sdev) { + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); + atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED | - ZFCP_STATUS_UNIT_SHARED | - ZFCP_STATUS_UNIT_READONLY, - &unit->status); + ZFCP_STATUS_LUN_SHARED | ZFCP_STATUS_LUN_READONLY, + &zfcp_sdev->status); } -static int zfcp_erp_unit_strategy_close(struct zfcp_erp_action *erp_action) +static int zfcp_erp_lun_strategy_close(struct zfcp_erp_action *erp_action) { - int retval = zfcp_fsf_close_unit(erp_action); + int retval = zfcp_fsf_close_lun(erp_action); if (retval == -ENOMEM) return ZFCP_ERP_NOMEM; - erp_action->step = ZFCP_ERP_STEP_UNIT_CLOSING; + erp_action->step = ZFCP_ERP_STEP_LUN_CLOSING; if (retval) return ZFCP_ERP_FAILED; return ZFCP_ERP_CONTINUES; } -static int zfcp_erp_unit_strategy_open(struct zfcp_erp_action *erp_action) +static int zfcp_erp_lun_strategy_open(struct zfcp_erp_action *erp_action) { - int retval = zfcp_fsf_open_unit(erp_action); + int retval = zfcp_fsf_open_lun(erp_action); if (retval == -ENOMEM) return ZFCP_ERP_NOMEM; - erp_action->step = ZFCP_ERP_STEP_UNIT_OPENING; + erp_action->step = ZFCP_ERP_STEP_LUN_OPENING; if (retval) return ZFCP_ERP_FAILED; return ZFCP_ERP_CONTINUES; } -static int zfcp_erp_unit_strategy(struct zfcp_erp_action *erp_action) +static int zfcp_erp_lun_strategy(struct zfcp_erp_action *erp_action) { - struct zfcp_unit *unit = erp_action->unit; + struct scsi_device *sdev = erp_action->sdev; + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); switch (erp_action->step) { case ZFCP_ERP_STEP_UNINITIALIZED: - zfcp_erp_unit_strategy_clearstati(unit); - if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN) - return zfcp_erp_unit_strategy_close(erp_action); + zfcp_erp_lun_strategy_clearstati(sdev); + if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_OPEN) + return zfcp_erp_lun_strategy_close(erp_action); /* already closed, fall through */ - case ZFCP_ERP_STEP_UNIT_CLOSING: - if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN) + case ZFCP_ERP_STEP_LUN_CLOSING: + if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_OPEN) return ZFCP_ERP_FAILED; if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY) return ZFCP_ERP_EXIT; - return zfcp_erp_unit_strategy_open(erp_action); + return zfcp_erp_lun_strategy_open(erp_action); - case ZFCP_ERP_STEP_UNIT_OPENING: - if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN) + case ZFCP_ERP_STEP_LUN_OPENING: + if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_OPEN) return ZFCP_ERP_SUCCEEDED; } return ZFCP_ERP_FAILED; } -static int zfcp_erp_strategy_check_unit(struct zfcp_unit *unit, int result) +static int zfcp_erp_strategy_check_lun(struct scsi_device *sdev, int result) { + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); + switch (result) { case ZFCP_ERP_SUCCEEDED : - atomic_set(&unit->erp_counter, 0); - zfcp_erp_unit_unblock(unit); + atomic_set(&zfcp_sdev->erp_counter, 0); + zfcp_erp_lun_unblock(sdev); break; case ZFCP_ERP_FAILED : - atomic_inc(&unit->erp_counter); - if (atomic_read(&unit->erp_counter) > ZFCP_MAX_ERPS) { - dev_err(&unit->port->adapter->ccw_device->dev, - "ERP failed for unit 0x%016Lx on " + atomic_inc(&zfcp_sdev->erp_counter); + if (atomic_read(&zfcp_sdev->erp_counter) > ZFCP_MAX_ERPS) { + dev_err(&zfcp_sdev->port->adapter->ccw_device->dev, + "ERP failed for LUN 0x%016Lx on " "port 0x%016Lx\n", - (unsigned long long)unit->fcp_lun, - (unsigned long long)unit->port->wwpn); - zfcp_erp_unit_failed(unit, "erusck1", NULL); + (unsigned long long)zfcp_scsi_dev_lun(sdev), + (unsigned long long)zfcp_sdev->port->wwpn); + zfcp_erp_set_lun_status(sdev, + ZFCP_STATUS_COMMON_ERP_FAILED); } break; } - if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { - zfcp_erp_unit_block(unit, 0); + if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { + zfcp_erp_lun_block(sdev, 0); result = ZFCP_ERP_EXIT; } return result; @@ -1032,7 +1066,8 @@ static int zfcp_erp_strategy_check_port(struct zfcp_port *port, int result) dev_err(&port->adapter->ccw_device->dev, "ERP failed for remote port 0x%016Lx\n", (unsigned long long)port->wwpn); - zfcp_erp_port_failed(port, "erpsck1", NULL); + zfcp_erp_set_port_status(port, + ZFCP_STATUS_COMMON_ERP_FAILED); } break; } @@ -1059,7 +1094,8 @@ static int zfcp_erp_strategy_check_adapter(struct zfcp_adapter *adapter, dev_err(&adapter->ccw_device->dev, "ERP cannot recover an error " "on the FCP device\n"); - zfcp_erp_adapter_failed(adapter, "erasck1", NULL); + zfcp_erp_set_adapter_status(adapter, + ZFCP_STATUS_COMMON_ERP_FAILED); } break; } @@ -1076,12 +1112,12 @@ static int zfcp_erp_strategy_check_target(struct zfcp_erp_action *erp_action, { struct zfcp_adapter *adapter = erp_action->adapter; struct zfcp_port *port = erp_action->port; - struct zfcp_unit *unit = erp_action->unit; + struct scsi_device *sdev = erp_action->sdev; switch (erp_action->action) { - case ZFCP_ERP_ACTION_REOPEN_UNIT: - result = zfcp_erp_strategy_check_unit(unit, result); + case ZFCP_ERP_ACTION_REOPEN_LUN: + result = zfcp_erp_strategy_check_lun(sdev, result); break; case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: @@ -1116,7 +1152,8 @@ static int zfcp_erp_strategy_statechange(struct zfcp_erp_action *act, int ret) int action = act->action; struct zfcp_adapter *adapter = act->adapter; struct zfcp_port *port = act->port; - struct zfcp_unit *unit = act->unit; + struct scsi_device *sdev = act->sdev; + struct zfcp_scsi_dev *zfcp_sdev; u32 erp_status = act->status; switch (action) { @@ -1139,11 +1176,12 @@ static int zfcp_erp_strategy_statechange(struct zfcp_erp_action *act, int ret) } break; - case ZFCP_ERP_ACTION_REOPEN_UNIT: - if (zfcp_erp_strat_change_det(&unit->status, erp_status)) { - _zfcp_erp_unit_reopen(unit, - ZFCP_STATUS_COMMON_ERP_FAILED, - "ersscg3", NULL); + case ZFCP_ERP_ACTION_REOPEN_LUN: + zfcp_sdev = sdev_to_zfcp(sdev); + if (zfcp_erp_strat_change_det(&zfcp_sdev->status, erp_status)) { + _zfcp_erp_lun_reopen(sdev, + ZFCP_STATUS_COMMON_ERP_FAILED, + "ersscg3", NULL, 0); return ZFCP_ERP_EXIT; } break; @@ -1154,6 +1192,7 @@ static int zfcp_erp_strategy_statechange(struct zfcp_erp_action *act, int ret) static void zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action) { struct zfcp_adapter *adapter = erp_action->adapter; + struct zfcp_scsi_dev *zfcp_sdev; adapter->erp_total_count--; if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) { @@ -1165,9 +1204,10 @@ static void zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action) zfcp_dbf_rec_action("eractd1", erp_action); switch (erp_action->action) { - case ZFCP_ERP_ACTION_REOPEN_UNIT: + case ZFCP_ERP_ACTION_REOPEN_LUN: + zfcp_sdev = sdev_to_zfcp(erp_action->sdev); atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE, - &erp_action->unit->status); + &zfcp_sdev->status); break; case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: @@ -1187,11 +1227,12 @@ static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result) { struct zfcp_adapter *adapter = act->adapter; struct zfcp_port *port = act->port; - struct zfcp_unit *unit = act->unit; + struct scsi_device *sdev = act->sdev; switch (act->action) { - case ZFCP_ERP_ACTION_REOPEN_UNIT: - put_device(&unit->dev); + case ZFCP_ERP_ACTION_REOPEN_LUN: + if (!(act->status & ZFCP_STATUS_ERP_NO_REF)) + scsi_device_put(sdev); break; case ZFCP_ERP_ACTION_REOPEN_PORT: @@ -1222,8 +1263,8 @@ static int zfcp_erp_strategy_do_action(struct zfcp_erp_action *erp_action) return zfcp_erp_port_forced_strategy(erp_action); case ZFCP_ERP_ACTION_REOPEN_PORT: return zfcp_erp_port_strategy(erp_action); - case ZFCP_ERP_ACTION_REOPEN_UNIT: - return zfcp_erp_unit_strategy(erp_action); + case ZFCP_ERP_ACTION_REOPEN_LUN: + return zfcp_erp_lun_strategy(erp_action); } return ZFCP_ERP_FAILED; } @@ -1376,42 +1417,6 @@ void zfcp_erp_thread_kill(struct zfcp_adapter *adapter) } /** - * zfcp_erp_adapter_failed - Set adapter status to failed. - * @adapter: Failed adapter. - * @id: Event id for debug trace. - * @ref: Reference for debug trace. - */ -void zfcp_erp_adapter_failed(struct zfcp_adapter *adapter, char *id, void *ref) -{ - zfcp_erp_modify_adapter_status(adapter, id, ref, - ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET); -} - -/** - * zfcp_erp_port_failed - Set port status to failed. - * @port: Failed port. - * @id: Event id for debug trace. - * @ref: Reference for debug trace. - */ -void zfcp_erp_port_failed(struct zfcp_port *port, char *id, void *ref) -{ - zfcp_erp_modify_port_status(port, id, ref, - ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET); -} - -/** - * zfcp_erp_unit_failed - Set unit status to failed. - * @unit: Failed unit. - * @id: Event id for debug trace. - * @ref: Reference for debug trace. - */ -void zfcp_erp_unit_failed(struct zfcp_unit *unit, char *id, void *ref) -{ - zfcp_erp_modify_unit_status(unit, id, ref, - ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET); -} - -/** * zfcp_erp_wait - wait for completion of error recovery on an adapter * @adapter: adapter for which to wait for completion of its error recovery */ @@ -1423,210 +1428,148 @@ void zfcp_erp_wait(struct zfcp_adapter *adapter) } /** - * zfcp_erp_modify_adapter_status - change adapter status bits + * zfcp_erp_set_adapter_status - set adapter status bits * @adapter: adapter to change the status - * @id: id for the debug trace - * @ref: reference for the debug trace * @mask: status bits to change - * @set_or_clear: ZFCP_SET or ZFCP_CLEAR * - * Changes in common status bits are propagated to attached ports and units. + * Changes in common status bits are propagated to attached ports and LUNs. */ -void zfcp_erp_modify_adapter_status(struct zfcp_adapter *adapter, char *id, - void *ref, u32 mask, int set_or_clear) +void zfcp_erp_set_adapter_status(struct zfcp_adapter *adapter, u32 mask) { struct zfcp_port *port; + struct scsi_device *sdev; unsigned long flags; u32 common_mask = mask & ZFCP_COMMON_FLAGS; - if (set_or_clear == ZFCP_SET) { - if (status_change_set(mask, &adapter->status)) - zfcp_dbf_rec_adapter(id, ref, adapter->dbf); - atomic_set_mask(mask, &adapter->status); - } else { - if (status_change_clear(mask, &adapter->status)) - zfcp_dbf_rec_adapter(id, ref, adapter->dbf); - atomic_clear_mask(mask, &adapter->status); - if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) - atomic_set(&adapter->erp_counter, 0); - } + atomic_set_mask(mask, &adapter->status); - if (common_mask) { - read_lock_irqsave(&adapter->port_list_lock, flags); - list_for_each_entry(port, &adapter->port_list, list) - zfcp_erp_modify_port_status(port, id, ref, common_mask, - set_or_clear); - read_unlock_irqrestore(&adapter->port_list_lock, flags); - } + if (!common_mask) + return; + + read_lock_irqsave(&adapter->port_list_lock, flags); + list_for_each_entry(port, &adapter->port_list, list) + atomic_set_mask(common_mask, &port->status); + read_unlock_irqrestore(&adapter->port_list_lock, flags); + + shost_for_each_device(sdev, adapter->scsi_host) + atomic_set_mask(common_mask, &sdev_to_zfcp(sdev)->status); } /** - * zfcp_erp_modify_port_status - change port status bits - * @port: port to change the status bits - * @id: id for the debug trace - * @ref: reference for the debug trace + * zfcp_erp_clear_adapter_status - clear adapter status bits + * @adapter: adapter to change the status * @mask: status bits to change - * @set_or_clear: ZFCP_SET or ZFCP_CLEAR * - * Changes in common status bits are propagated to attached units. + * Changes in common status bits are propagated to attached ports and LUNs. */ -void zfcp_erp_modify_port_status(struct zfcp_port *port, char *id, void *ref, - u32 mask, int set_or_clear) +void zfcp_erp_clear_adapter_status(struct zfcp_adapter *adapter, u32 mask) { - struct zfcp_unit *unit; + struct zfcp_port *port; + struct scsi_device *sdev; unsigned long flags; u32 common_mask = mask & ZFCP_COMMON_FLAGS; + u32 clear_counter = mask & ZFCP_STATUS_COMMON_ERP_FAILED; + + atomic_clear_mask(mask, &adapter->status); + + if (!common_mask) + return; + + if (clear_counter) + atomic_set(&adapter->erp_counter, 0); - if (set_or_clear == ZFCP_SET) { - if (status_change_set(mask, &port->status)) - zfcp_dbf_rec_port(id, ref, port); - atomic_set_mask(mask, &port->status); - } else { - if (status_change_clear(mask, &port->status)) - zfcp_dbf_rec_port(id, ref, port); - atomic_clear_mask(mask, &port->status); - if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) + read_lock_irqsave(&adapter->port_list_lock, flags); + list_for_each_entry(port, &adapter->port_list, list) { + atomic_clear_mask(common_mask, &port->status); + if (clear_counter) atomic_set(&port->erp_counter, 0); } + read_unlock_irqrestore(&adapter->port_list_lock, flags); - if (common_mask) { - read_lock_irqsave(&port->unit_list_lock, flags); - list_for_each_entry(unit, &port->unit_list, list) - zfcp_erp_modify_unit_status(unit, id, ref, common_mask, - set_or_clear); - read_unlock_irqrestore(&port->unit_list_lock, flags); + shost_for_each_device(sdev, adapter->scsi_host) { + atomic_clear_mask(common_mask, &sdev_to_zfcp(sdev)->status); + if (clear_counter) + atomic_set(&sdev_to_zfcp(sdev)->erp_counter, 0); } } /** - * zfcp_erp_modify_unit_status - change unit status bits - * @unit: unit to change the status bits - * @id: id for the debug trace - * @ref: reference for the debug trace + * zfcp_erp_set_port_status - set port status bits + * @port: port to change the status * @mask: status bits to change - * @set_or_clear: ZFCP_SET or ZFCP_CLEAR - */ -void zfcp_erp_modify_unit_status(struct zfcp_unit *unit, char *id, void *ref, - u32 mask, int set_or_clear) -{ - if (set_or_clear == ZFCP_SET) { - if (status_change_set(mask, &unit->status)) - zfcp_dbf_rec_unit(id, ref, unit); - atomic_set_mask(mask, &unit->status); - } else { - if (status_change_clear(mask, &unit->status)) - zfcp_dbf_rec_unit(id, ref, unit); - atomic_clear_mask(mask, &unit->status); - if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) { - atomic_set(&unit->erp_counter, 0); - } - } -} - -/** - * zfcp_erp_port_boxed - Mark port as "boxed" and start ERP - * @port: The "boxed" port. - * @id: The debug trace id. - * @id: Reference for the debug trace. + * + * Changes in common status bits are propagated to attached LUNs. */ -void zfcp_erp_port_boxed(struct zfcp_port *port, char *id, void *ref) +void zfcp_erp_set_port_status(struct zfcp_port *port, u32 mask) { - zfcp_erp_modify_port_status(port, id, ref, - ZFCP_STATUS_COMMON_ACCESS_BOXED, ZFCP_SET); - zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref); -} + struct scsi_device *sdev; + u32 common_mask = mask & ZFCP_COMMON_FLAGS; -/** - * zfcp_erp_unit_boxed - Mark unit as "boxed" and start ERP - * @port: The "boxed" unit. - * @id: The debug trace id. - * @id: Reference for the debug trace. - */ -void zfcp_erp_unit_boxed(struct zfcp_unit *unit, char *id, void *ref) -{ - zfcp_erp_modify_unit_status(unit, id, ref, - ZFCP_STATUS_COMMON_ACCESS_BOXED, ZFCP_SET); - zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref); -} + atomic_set_mask(mask, &port->status); -/** - * zfcp_erp_port_access_denied - Adapter denied access to port. - * @port: port where access has been denied - * @id: id for debug trace - * @ref: reference for debug trace - * - * Since the adapter has denied access, stop using the port and the - * attached units. - */ -void zfcp_erp_port_access_denied(struct zfcp_port *port, char *id, void *ref) -{ - zfcp_erp_modify_port_status(port, id, ref, - ZFCP_STATUS_COMMON_ERP_FAILED | - ZFCP_STATUS_COMMON_ACCESS_DENIED, ZFCP_SET); + if (!common_mask) + return; + + shost_for_each_device(sdev, port->adapter->scsi_host) + if (sdev_to_zfcp(sdev)->port == port) + atomic_set_mask(common_mask, + &sdev_to_zfcp(sdev)->status); } /** - * zfcp_erp_unit_access_denied - Adapter denied access to unit. - * @unit: unit where access has been denied - * @id: id for debug trace - * @ref: reference for debug trace + * zfcp_erp_clear_port_status - clear port status bits + * @port: adapter to change the status + * @mask: status bits to change * - * Since the adapter has denied access, stop using the unit. + * Changes in common status bits are propagated to attached LUNs. */ -void zfcp_erp_unit_access_denied(struct zfcp_unit *unit, char *id, void *ref) +void zfcp_erp_clear_port_status(struct zfcp_port *port, u32 mask) { - zfcp_erp_modify_unit_status(unit, id, ref, - ZFCP_STATUS_COMMON_ERP_FAILED | - ZFCP_STATUS_COMMON_ACCESS_DENIED, ZFCP_SET); -} + struct scsi_device *sdev; + u32 common_mask = mask & ZFCP_COMMON_FLAGS; + u32 clear_counter = mask & ZFCP_STATUS_COMMON_ERP_FAILED; -static void zfcp_erp_unit_access_changed(struct zfcp_unit *unit, char *id, - void *ref) -{ - int status = atomic_read(&unit->status); - if (!(status & (ZFCP_STATUS_COMMON_ACCESS_DENIED | - ZFCP_STATUS_COMMON_ACCESS_BOXED))) + atomic_clear_mask(mask, &port->status); + + if (!common_mask) return; - zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref); + if (clear_counter) + atomic_set(&port->erp_counter, 0); + + shost_for_each_device(sdev, port->adapter->scsi_host) + if (sdev_to_zfcp(sdev)->port == port) { + atomic_clear_mask(common_mask, + &sdev_to_zfcp(sdev)->status); + if (clear_counter) + atomic_set(&sdev_to_zfcp(sdev)->erp_counter, 0); + } } -static void zfcp_erp_port_access_changed(struct zfcp_port *port, char *id, - void *ref) +/** + * zfcp_erp_set_lun_status - set lun status bits + * @sdev: SCSI device / lun to set the status bits + * @mask: status bits to change + */ +void zfcp_erp_set_lun_status(struct scsi_device *sdev, u32 mask) { - struct zfcp_unit *unit; - unsigned long flags; - int status = atomic_read(&port->status); + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); - if (!(status & (ZFCP_STATUS_COMMON_ACCESS_DENIED | - ZFCP_STATUS_COMMON_ACCESS_BOXED))) { - read_lock_irqsave(&port->unit_list_lock, flags); - list_for_each_entry(unit, &port->unit_list, list) - zfcp_erp_unit_access_changed(unit, id, ref); - read_unlock_irqrestore(&port->unit_list_lock, flags); - return; - } - - zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref); + atomic_set_mask(mask, &zfcp_sdev->status); } /** - * zfcp_erp_adapter_access_changed - Process change in adapter ACT - * @adapter: Adapter where the Access Control Table (ACT) changed - * @id: Id for debug trace - * @ref: Reference for debug trace + * zfcp_erp_clear_lun_status - clear lun status bits + * @sdev: SCSi device / lun to clear the status bits + * @mask: status bits to change */ -void zfcp_erp_adapter_access_changed(struct zfcp_adapter *adapter, char *id, - void *ref) +void zfcp_erp_clear_lun_status(struct scsi_device *sdev, u32 mask) { - unsigned long flags; - struct zfcp_port *port; + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); - if (adapter->connection_features & FSF_FEATURE_NPIV_MODE) - return; + atomic_clear_mask(mask, &zfcp_sdev->status); - read_lock_irqsave(&adapter->port_list_lock, flags); - list_for_each_entry(port, &adapter->port_list, list) - zfcp_erp_port_access_changed(port, id, ref); - read_unlock_irqrestore(&adapter->port_list_lock, flags); + if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) + atomic_set(&zfcp_sdev->erp_counter, 0); } + diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 3b93239c6f69..bf8f3e514839 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -15,12 +15,10 @@ #include "zfcp_fc.h" /* zfcp_aux.c */ -extern struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *, u64); extern struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *, u64); extern struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *); extern struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *, u64, u32, u32); -extern struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *, u64); extern void zfcp_sg_free_table(struct scatterlist *, int); extern int zfcp_sg_setup_table(struct scatterlist *, int); extern void zfcp_device_unregister(struct device *, @@ -36,6 +34,14 @@ extern void zfcp_ccw_adapter_put(struct zfcp_adapter *); /* zfcp_cfdc.c */ extern struct miscdevice zfcp_cfdc_misc; +extern void zfcp_cfdc_port_denied(struct zfcp_port *, union fsf_status_qual *); +extern void zfcp_cfdc_lun_denied(struct scsi_device *, union fsf_status_qual *); +extern void zfcp_cfdc_lun_shrng_vltn(struct scsi_device *, + union fsf_status_qual *); +extern int zfcp_cfdc_open_lun_eval(struct scsi_device *, + struct fsf_qtcb_bottom_support *); +extern void zfcp_cfdc_adapter_access_changed(struct zfcp_adapter *); + /* zfcp_dbf.c */ extern int zfcp_dbf_adapter_register(struct zfcp_adapter *); @@ -44,10 +50,10 @@ extern void zfcp_dbf_rec_thread(char *, struct zfcp_dbf *); extern void zfcp_dbf_rec_thread_lock(char *, struct zfcp_dbf *); extern void zfcp_dbf_rec_adapter(char *, void *, struct zfcp_dbf *); extern void zfcp_dbf_rec_port(char *, void *, struct zfcp_port *); -extern void zfcp_dbf_rec_unit(char *, void *, struct zfcp_unit *); +extern void zfcp_dbf_rec_lun(char *, void *, struct scsi_device *); extern void zfcp_dbf_rec_trigger(char *, void *, u8, u8, void *, struct zfcp_adapter *, struct zfcp_port *, - struct zfcp_unit *); + struct scsi_device *); extern void zfcp_dbf_rec_action(char *, struct zfcp_erp_action *); extern void _zfcp_dbf_hba_fsf_response(const char *, int, struct zfcp_fsf_req *, struct zfcp_dbf *); @@ -65,34 +71,26 @@ extern void _zfcp_dbf_scsi(const char *, const char *, int, struct zfcp_dbf *, unsigned long); /* zfcp_erp.c */ -extern void zfcp_erp_modify_adapter_status(struct zfcp_adapter *, char *, - void *, u32, int); +extern void zfcp_erp_set_adapter_status(struct zfcp_adapter *, u32); +extern void zfcp_erp_clear_adapter_status(struct zfcp_adapter *, u32); extern void zfcp_erp_adapter_reopen(struct zfcp_adapter *, int, char *, void *); extern void zfcp_erp_adapter_shutdown(struct zfcp_adapter *, int, char *, void *); -extern void zfcp_erp_adapter_failed(struct zfcp_adapter *, char *, void *); -extern void zfcp_erp_modify_port_status(struct zfcp_port *, char *, void *, u32, - int); +extern void zfcp_erp_set_port_status(struct zfcp_port *, u32); +extern void zfcp_erp_clear_port_status(struct zfcp_port *, u32); extern int zfcp_erp_port_reopen(struct zfcp_port *, int, char *, void *); extern void zfcp_erp_port_shutdown(struct zfcp_port *, int, char *, void *); extern void zfcp_erp_port_forced_reopen(struct zfcp_port *, int, char *, void *); -extern void zfcp_erp_port_failed(struct zfcp_port *, char *, void *); -extern void zfcp_erp_modify_unit_status(struct zfcp_unit *, char *, void *, u32, - int); -extern void zfcp_erp_unit_reopen(struct zfcp_unit *, int, char *, void *); -extern void zfcp_erp_unit_shutdown(struct zfcp_unit *, int, char *, void *); -extern void zfcp_erp_unit_failed(struct zfcp_unit *, char *, void *); +extern void zfcp_erp_set_lun_status(struct scsi_device *, u32); +extern void zfcp_erp_clear_lun_status(struct scsi_device *, u32); +extern void zfcp_erp_lun_reopen(struct scsi_device *, int, char *, void *); +extern void zfcp_erp_lun_shutdown(struct scsi_device *, int, char *, void *); +extern void zfcp_erp_lun_shutdown_wait(struct scsi_device *, char *); extern int zfcp_erp_thread_setup(struct zfcp_adapter *); extern void zfcp_erp_thread_kill(struct zfcp_adapter *); extern void zfcp_erp_wait(struct zfcp_adapter *); extern void zfcp_erp_notify(struct zfcp_erp_action *, unsigned long); -extern void zfcp_erp_port_boxed(struct zfcp_port *, char *, void *); -extern void zfcp_erp_unit_boxed(struct zfcp_unit *, char *, void *); -extern void zfcp_erp_port_access_denied(struct zfcp_port *, char *, void *); -extern void zfcp_erp_unit_access_denied(struct zfcp_unit *, char *, void *); -extern void zfcp_erp_adapter_access_changed(struct zfcp_adapter *, char *, - void *); extern void zfcp_erp_timeout_handler(unsigned long); /* zfcp_fc.c */ @@ -118,8 +116,8 @@ extern int zfcp_fsf_open_wka_port(struct zfcp_fc_wka_port *); extern int zfcp_fsf_close_wka_port(struct zfcp_fc_wka_port *); extern int zfcp_fsf_close_port(struct zfcp_erp_action *); extern int zfcp_fsf_close_physical_port(struct zfcp_erp_action *); -extern int zfcp_fsf_open_unit(struct zfcp_erp_action *); -extern int zfcp_fsf_close_unit(struct zfcp_erp_action *); +extern int zfcp_fsf_open_lun(struct zfcp_erp_action *); +extern int zfcp_fsf_close_lun(struct zfcp_erp_action *); extern int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *); extern int zfcp_fsf_exchange_config_data_sync(struct zfcp_qdio *, struct fsf_qtcb_bottom_config *); @@ -135,12 +133,10 @@ extern int zfcp_fsf_send_ct(struct zfcp_fc_wka_port *, struct zfcp_fsf_ct_els *, mempool_t *, unsigned int); extern int zfcp_fsf_send_els(struct zfcp_adapter *, u32, struct zfcp_fsf_ct_els *, unsigned int); -extern int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *, - struct scsi_cmnd *); +extern int zfcp_fsf_fcp_cmnd(struct scsi_cmnd *); extern void zfcp_fsf_req_free(struct zfcp_fsf_req *); -extern struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *, u8); -extern struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long, - struct zfcp_unit *); +extern struct zfcp_fsf_req *zfcp_fsf_fcp_task_mgmt(struct scsi_cmnd *, u8); +extern struct zfcp_fsf_req *zfcp_fsf_abort_fcp_cmnd(struct scsi_cmnd *); extern void zfcp_fsf_reqid_check(struct zfcp_qdio *, int); /* zfcp_qdio.c */ @@ -163,8 +159,6 @@ 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 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); @@ -175,4 +169,13 @@ extern struct attribute_group zfcp_sysfs_port_attrs; extern struct device_attribute *zfcp_sysfs_sdev_attrs[]; extern struct device_attribute *zfcp_sysfs_shost_attrs[]; +/* zfcp_unit.c */ +extern int zfcp_unit_add(struct zfcp_port *, u64); +extern int zfcp_unit_remove(struct zfcp_port *, u64); +extern struct zfcp_unit *zfcp_unit_find(struct zfcp_port *, u64); +extern struct scsi_device *zfcp_unit_sdev(struct zfcp_unit *unit); +extern void zfcp_unit_scsi_scan(struct zfcp_unit *); +extern void zfcp_unit_queue_scsi_scan(struct zfcp_port *); +extern unsigned int zfcp_unit_sdev_status(struct zfcp_unit *); + #endif /* ZFCP_EXT_H */ diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index 6f3ed2b9a349..86fd905df48b 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -365,7 +365,7 @@ void zfcp_fc_port_did_lookup(struct work_struct *work) } if (!port->d_id) { - zfcp_erp_port_failed(port, "fcgpn_2", NULL); + zfcp_erp_set_port_status(port, ZFCP_STATUS_COMMON_ERP_FAILED); goto out; } diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 9d1d7d1842ce..beaf0916ceab 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -61,45 +61,6 @@ static u32 fsf_qtcb_type[] = { [FSF_QTCB_UPLOAD_CONTROL_FILE] = FSF_SUPPORT_COMMAND }; -static void zfcp_act_eval_err(struct zfcp_adapter *adapter, u32 table) -{ - u16 subtable = table >> 16; - u16 rule = table & 0xffff; - const char *act_type[] = { "unknown", "OS", "WWPN", "DID", "LUN" }; - - if (subtable && subtable < ARRAY_SIZE(act_type)) - dev_warn(&adapter->ccw_device->dev, - "Access denied according to ACT rule type %s, " - "rule %d\n", act_type[subtable], rule); -} - -static void zfcp_fsf_access_denied_port(struct zfcp_fsf_req *req, - struct zfcp_port *port) -{ - struct fsf_qtcb_header *header = &req->qtcb->header; - dev_warn(&req->adapter->ccw_device->dev, - "Access denied to port 0x%016Lx\n", - (unsigned long long)port->wwpn); - zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[0]); - zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[1]); - zfcp_erp_port_access_denied(port, "fspad_1", req); - req->status |= ZFCP_STATUS_FSFREQ_ERROR; -} - -static void zfcp_fsf_access_denied_unit(struct zfcp_fsf_req *req, - struct zfcp_unit *unit) -{ - struct fsf_qtcb_header *header = &req->qtcb->header; - dev_warn(&req->adapter->ccw_device->dev, - "Access denied to unit 0x%016Lx on port 0x%016Lx\n", - (unsigned long long)unit->fcp_lun, - (unsigned long long)unit->port->wwpn); - zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[0]); - zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[1]); - zfcp_erp_unit_access_denied(unit, "fsuad_1", req); - req->status |= ZFCP_STATUS_FSFREQ_ERROR; -} - static void zfcp_fsf_class_not_supp(struct zfcp_fsf_req *req) { dev_err(&req->adapter->ccw_device->dev, "FCP device not " @@ -143,7 +104,7 @@ static void zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *req) read_unlock_irqrestore(&adapter->port_list_lock, flags); } -static void zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *req, char *id, +static void zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *req, struct fsf_link_down_info *link_down) { struct zfcp_adapter *adapter = req->adapter; @@ -223,7 +184,7 @@ static void zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *req, char *id, "the FC fabric is down\n"); } out: - zfcp_erp_adapter_failed(adapter, id, req); + zfcp_erp_set_adapter_status(adapter, ZFCP_STATUS_COMMON_ERP_FAILED); } static void zfcp_fsf_status_read_link_down(struct zfcp_fsf_req *req) @@ -234,13 +195,13 @@ static void zfcp_fsf_status_read_link_down(struct zfcp_fsf_req *req) switch (sr_buf->status_subtype) { case FSF_STATUS_READ_SUB_NO_PHYSICAL_LINK: - zfcp_fsf_link_down_info_eval(req, "fssrld1", ldi); + zfcp_fsf_link_down_info_eval(req, ldi); break; case FSF_STATUS_READ_SUB_FDISC_FAILED: - zfcp_fsf_link_down_info_eval(req, "fssrld2", ldi); + zfcp_fsf_link_down_info_eval(req, ldi); break; case FSF_STATUS_READ_SUB_FIRMWARE_UPDATE: - zfcp_fsf_link_down_info_eval(req, "fssrld3", NULL); + zfcp_fsf_link_down_info_eval(req, NULL); }; } @@ -281,9 +242,8 @@ static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req) dev_info(&adapter->ccw_device->dev, "The local link has been restored\n"); /* All ports should be marked as ready to run again */ - zfcp_erp_modify_adapter_status(adapter, "fssrh_1", NULL, - ZFCP_STATUS_COMMON_RUNNING, - ZFCP_SET); + zfcp_erp_set_adapter_status(adapter, + ZFCP_STATUS_COMMON_RUNNING); zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | ZFCP_STATUS_COMMON_ERP_FAILED, @@ -293,13 +253,12 @@ static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req) break; case FSF_STATUS_READ_NOTIFICATION_LOST: if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_ACT_UPDATED) - zfcp_erp_adapter_access_changed(adapter, "fssrh_3", - req); + zfcp_cfdc_adapter_access_changed(adapter); if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_INCOMING_ELS) queue_work(adapter->work_queue, &adapter->scan_work); break; case FSF_STATUS_READ_CFDC_UPDATED: - zfcp_erp_adapter_access_changed(adapter, "fssrh_4", req); + zfcp_cfdc_adapter_access_changed(adapter); break; case FSF_STATUS_READ_FEATURE_UPDATE_ALERT: adapter->adapter_features = sr_buf->payload.word[0]; @@ -399,16 +358,14 @@ static void zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *req) zfcp_erp_adapter_shutdown(adapter, 0, "fspse_4", req); break; case FSF_PROT_LINK_DOWN: - zfcp_fsf_link_down_info_eval(req, "fspse_5", - &psq->link_down_info); + zfcp_fsf_link_down_info_eval(req, &psq->link_down_info); /* go through reopen to flush pending requests */ zfcp_erp_adapter_reopen(adapter, 0, "fspse_6", req); break; case FSF_PROT_REEST_QUEUE: /* All ports should be marked as ready to run again */ - zfcp_erp_modify_adapter_status(adapter, "fspse_7", NULL, - ZFCP_STATUS_COMMON_RUNNING, - ZFCP_SET); + zfcp_erp_set_adapter_status(adapter, + ZFCP_STATUS_COMMON_RUNNING); zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | ZFCP_STATUS_COMMON_ERP_FAILED, @@ -578,7 +535,7 @@ static void zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *req) atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, &adapter->status); - zfcp_fsf_link_down_info_eval(req, "fsecdh2", + zfcp_fsf_link_down_info_eval(req, &qtcb->header.fsf_status_qual.link_down_info); break; default: @@ -644,7 +601,7 @@ static void zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *req) break; case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE: zfcp_fsf_exchange_port_evaluate(req); - zfcp_fsf_link_down_info_eval(req, "fsepdh1", + zfcp_fsf_link_down_info_eval(req, &qtcb->header.fsf_status_qual.link_down_info); break; } @@ -771,7 +728,7 @@ int zfcp_fsf_status_read(struct zfcp_qdio *qdio) struct fsf_status_read_buffer *sr_buf; int retval = -EIO; - spin_lock_bh(&qdio->req_q_lock); + spin_lock_irq(&qdio->req_q_lock); if (zfcp_qdio_sbal_get(qdio)) goto out; @@ -805,13 +762,14 @@ failed_buf: zfcp_fsf_req_free(req); zfcp_dbf_hba_fsf_unsol("fail", adapter->dbf, NULL); out: - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); return retval; } static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req) { - struct zfcp_unit *unit = req->data; + struct scsi_device *sdev = req->data; + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); union fsf_status_qual *fsq = &req->qtcb->header.fsf_status_qual; if (req->status & ZFCP_STATUS_FSFREQ_ERROR) @@ -820,14 +778,15 @@ static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req) switch (req->qtcb->header.fsf_status) { case FSF_PORT_HANDLE_NOT_VALID: if (fsq->word[0] == fsq->word[1]) { - zfcp_erp_adapter_reopen(unit->port->adapter, 0, + zfcp_erp_adapter_reopen(zfcp_sdev->port->adapter, 0, "fsafch1", req); req->status |= ZFCP_STATUS_FSFREQ_ERROR; } break; case FSF_LUN_HANDLE_NOT_VALID: if (fsq->word[0] == fsq->word[1]) { - zfcp_erp_port_reopen(unit->port, 0, "fsafch2", req); + zfcp_erp_port_reopen(zfcp_sdev->port, 0, "fsafch2", + req); req->status |= ZFCP_STATUS_FSFREQ_ERROR; } break; @@ -835,17 +794,23 @@ static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req) req->status |= ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED; break; case FSF_PORT_BOXED: - zfcp_erp_port_boxed(unit->port, "fsafch3", req); + zfcp_erp_set_port_status(zfcp_sdev->port, + ZFCP_STATUS_COMMON_ACCESS_BOXED); + zfcp_erp_port_reopen(zfcp_sdev->port, + ZFCP_STATUS_COMMON_ERP_FAILED, "fsafch3", + req); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_LUN_BOXED: - zfcp_erp_unit_boxed(unit, "fsafch4", req); + zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_ACCESS_BOXED); + zfcp_erp_lun_reopen(sdev, ZFCP_STATUS_COMMON_ERP_FAILED, + "fsafch4", req); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_ADAPTER_STATUS_AVAILABLE: switch (fsq->word[0]) { case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: - zfcp_fc_test_link(unit->port); + zfcp_fc_test_link(zfcp_sdev->port); /* fall through */ case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: req->status |= ZFCP_STATUS_FSFREQ_ERROR; @@ -859,19 +824,20 @@ static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req) } /** - * zfcp_fsf_abort_fcp_command - abort running SCSI command - * @old_req_id: unsigned long - * @unit: pointer to struct zfcp_unit + * zfcp_fsf_abort_fcp_cmnd - abort running SCSI command + * @scmnd: The SCSI command to abort * Returns: pointer to struct zfcp_fsf_req */ -struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long old_req_id, - struct zfcp_unit *unit) +struct zfcp_fsf_req *zfcp_fsf_abort_fcp_cmnd(struct scsi_cmnd *scmnd) { struct zfcp_fsf_req *req = NULL; - struct zfcp_qdio *qdio = unit->port->adapter->qdio; + struct scsi_device *sdev = scmnd->device; + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); + struct zfcp_qdio *qdio = zfcp_sdev->port->adapter->qdio; + unsigned long old_req_id = (unsigned long) scmnd->host_scribble; - spin_lock_bh(&qdio->req_q_lock); + spin_lock_irq(&qdio->req_q_lock); if (zfcp_qdio_sbal_get(qdio)) goto out; req = zfcp_fsf_req_create(qdio, FSF_QTCB_ABORT_FCP_CMND, @@ -882,16 +848,16 @@ struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long old_req_id, goto out; } - if (unlikely(!(atomic_read(&unit->status) & + if (unlikely(!(atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_UNBLOCKED))) goto out_error_free; zfcp_qdio_set_sbale_last(qdio, &req->qdio_req); - req->data = unit; + req->data = zfcp_sdev; req->handler = zfcp_fsf_abort_fcp_command_handler; - req->qtcb->header.lun_handle = unit->handle; - req->qtcb->header.port_handle = unit->port->handle; + req->qtcb->header.lun_handle = zfcp_sdev->lun_handle; + req->qtcb->header.port_handle = zfcp_sdev->port->handle; req->qtcb->bottom.support.req_handle = (u64) old_req_id; zfcp_fsf_start_timer(req, ZFCP_SCSI_ER_TIMEOUT); @@ -902,7 +868,7 @@ out_error_free: zfcp_fsf_req_free(req); req = NULL; out: - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); return req; } @@ -1041,7 +1007,7 @@ int zfcp_fsf_send_ct(struct zfcp_fc_wka_port *wka_port, struct zfcp_fsf_req *req; int ret = -EIO; - spin_lock_bh(&qdio->req_q_lock); + spin_lock_irq(&qdio->req_q_lock); if (zfcp_qdio_sbal_get(qdio)) goto out; @@ -1073,7 +1039,7 @@ int zfcp_fsf_send_ct(struct zfcp_fc_wka_port *wka_port, failed_send: zfcp_fsf_req_free(req); out: - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); return ret; } @@ -1111,8 +1077,10 @@ static void zfcp_fsf_send_els_handler(struct zfcp_fsf_req *req) case FSF_RESPONSE_SIZE_TOO_LARGE: break; case FSF_ACCESS_DENIED: - if (port) - zfcp_fsf_access_denied_port(req, port); + if (port) { + zfcp_cfdc_port_denied(port, &header->fsf_status_qual); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; + } break; case FSF_SBAL_MISMATCH: /* should never occure, avoided in zfcp_fsf_send_els */ @@ -1137,7 +1105,7 @@ int zfcp_fsf_send_els(struct zfcp_adapter *adapter, u32 d_id, struct zfcp_qdio *qdio = adapter->qdio; int ret = -EIO; - spin_lock_bh(&qdio->req_q_lock); + spin_lock_irq(&qdio->req_q_lock); if (zfcp_qdio_sbal_get(qdio)) goto out; @@ -1173,7 +1141,7 @@ int zfcp_fsf_send_els(struct zfcp_adapter *adapter, u32 d_id, failed_send: zfcp_fsf_req_free(req); out: - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); return ret; } @@ -1183,7 +1151,7 @@ int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action) struct zfcp_qdio *qdio = erp_action->adapter->qdio; int retval = -EIO; - spin_lock_bh(&qdio->req_q_lock); + spin_lock_irq(&qdio->req_q_lock); if (zfcp_qdio_sbal_get(qdio)) goto out; @@ -1215,7 +1183,7 @@ int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action) erp_action->fsf_req_id = 0; } out: - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); return retval; } @@ -1225,7 +1193,7 @@ int zfcp_fsf_exchange_config_data_sync(struct zfcp_qdio *qdio, struct zfcp_fsf_req *req = NULL; int retval = -EIO; - spin_lock_bh(&qdio->req_q_lock); + spin_lock_irq(&qdio->req_q_lock); if (zfcp_qdio_sbal_get(qdio)) goto out_unlock; @@ -1251,7 +1219,7 @@ int zfcp_fsf_exchange_config_data_sync(struct zfcp_qdio *qdio, zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); retval = zfcp_fsf_req_send(req); - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); if (!retval) wait_for_completion(&req->completion); @@ -1259,7 +1227,7 @@ int zfcp_fsf_exchange_config_data_sync(struct zfcp_qdio *qdio, return retval; out_unlock: - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); return retval; } @@ -1277,7 +1245,7 @@ int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action) if (!(qdio->adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT)) return -EOPNOTSUPP; - spin_lock_bh(&qdio->req_q_lock); + spin_lock_irq(&qdio->req_q_lock); if (zfcp_qdio_sbal_get(qdio)) goto out; @@ -1304,7 +1272,7 @@ int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action) erp_action->fsf_req_id = 0; } out: - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); return retval; } @@ -1323,7 +1291,7 @@ int zfcp_fsf_exchange_port_data_sync(struct zfcp_qdio *qdio, if (!(qdio->adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT)) return -EOPNOTSUPP; - spin_lock_bh(&qdio->req_q_lock); + spin_lock_irq(&qdio->req_q_lock); if (zfcp_qdio_sbal_get(qdio)) goto out_unlock; @@ -1343,7 +1311,7 @@ int zfcp_fsf_exchange_port_data_sync(struct zfcp_qdio *qdio, req->handler = zfcp_fsf_exchange_port_data_handler; zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); retval = zfcp_fsf_req_send(req); - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); if (!retval) wait_for_completion(&req->completion); @@ -1353,7 +1321,7 @@ int zfcp_fsf_exchange_port_data_sync(struct zfcp_qdio *qdio, return retval; out_unlock: - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); return retval; } @@ -1370,14 +1338,16 @@ static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req) case FSF_PORT_ALREADY_OPEN: break; case FSF_ACCESS_DENIED: - zfcp_fsf_access_denied_port(req, port); + zfcp_cfdc_port_denied(port, &header->fsf_status_qual); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_MAXIMUM_NUMBER_OF_PORTS_EXCEEDED: dev_warn(&req->adapter->ccw_device->dev, "Not enough FCP adapter resources to open " "remote port 0x%016Lx\n", (unsigned long long)port->wwpn); - zfcp_erp_port_failed(port, "fsoph_1", req); + zfcp_erp_set_port_status(port, + ZFCP_STATUS_COMMON_ERP_FAILED); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_ADAPTER_STATUS_AVAILABLE: @@ -1437,7 +1407,7 @@ int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action) struct zfcp_fsf_req *req; int retval = -EIO; - spin_lock_bh(&qdio->req_q_lock); + spin_lock_irq(&qdio->req_q_lock); if (zfcp_qdio_sbal_get(qdio)) goto out; @@ -1468,7 +1438,7 @@ int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action) put_device(&port->dev); } out: - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); return retval; } @@ -1487,9 +1457,7 @@ static void zfcp_fsf_close_port_handler(struct zfcp_fsf_req *req) case FSF_ADAPTER_STATUS_AVAILABLE: break; case FSF_GOOD: - zfcp_erp_modify_port_status(port, "fscph_2", req, - ZFCP_STATUS_COMMON_OPEN, - ZFCP_CLEAR); + zfcp_erp_clear_port_status(port, ZFCP_STATUS_COMMON_OPEN); break; } } @@ -1505,7 +1473,7 @@ int zfcp_fsf_close_port(struct zfcp_erp_action *erp_action) struct zfcp_fsf_req *req; int retval = -EIO; - spin_lock_bh(&qdio->req_q_lock); + spin_lock_irq(&qdio->req_q_lock); if (zfcp_qdio_sbal_get(qdio)) goto out; @@ -1534,7 +1502,7 @@ int zfcp_fsf_close_port(struct zfcp_erp_action *erp_action) erp_action->fsf_req_id = 0; } out: - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); return retval; } @@ -1580,7 +1548,7 @@ int zfcp_fsf_open_wka_port(struct zfcp_fc_wka_port *wka_port) struct zfcp_fsf_req *req; int retval = -EIO; - spin_lock_bh(&qdio->req_q_lock); + spin_lock_irq(&qdio->req_q_lock); if (zfcp_qdio_sbal_get(qdio)) goto out; @@ -1605,7 +1573,7 @@ int zfcp_fsf_open_wka_port(struct zfcp_fc_wka_port *wka_port) if (retval) zfcp_fsf_req_free(req); out: - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); return retval; } @@ -1633,7 +1601,7 @@ int zfcp_fsf_close_wka_port(struct zfcp_fc_wka_port *wka_port) struct zfcp_fsf_req *req; int retval = -EIO; - spin_lock_bh(&qdio->req_q_lock); + spin_lock_irq(&qdio->req_q_lock); if (zfcp_qdio_sbal_get(qdio)) goto out; @@ -1658,7 +1626,7 @@ int zfcp_fsf_close_wka_port(struct zfcp_fc_wka_port *wka_port) if (retval) zfcp_fsf_req_free(req); out: - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); return retval; } @@ -1666,7 +1634,7 @@ static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req) { struct zfcp_port *port = req->data; struct fsf_qtcb_header *header = &req->qtcb->header; - struct zfcp_unit *unit; + struct scsi_device *sdev; if (req->status & ZFCP_STATUS_FSFREQ_ERROR) return; @@ -1677,18 +1645,19 @@ static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req) req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_ACCESS_DENIED: - zfcp_fsf_access_denied_port(req, port); + zfcp_cfdc_port_denied(port, &header->fsf_status_qual); break; case FSF_PORT_BOXED: /* can't use generic zfcp_erp_modify_port_status because * ZFCP_STATUS_COMMON_OPEN must not be reset for the port */ atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status); - read_lock(&port->unit_list_lock); - list_for_each_entry(unit, &port->unit_list, list) - atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, - &unit->status); - read_unlock(&port->unit_list_lock); - zfcp_erp_port_boxed(port, "fscpph2", req); + shost_for_each_device(sdev, port->adapter->scsi_host) + if (sdev_to_zfcp(sdev)->port == port) + atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, + &sdev_to_zfcp(sdev)->status); + zfcp_erp_set_port_status(port, ZFCP_STATUS_COMMON_ACCESS_BOXED); + zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, + "fscpph2", req); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_ADAPTER_STATUS_AVAILABLE: @@ -1705,11 +1674,10 @@ static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req) * ZFCP_STATUS_COMMON_OPEN must not be reset for the port */ atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status); - read_lock(&port->unit_list_lock); - list_for_each_entry(unit, &port->unit_list, list) - atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, - &unit->status); - read_unlock(&port->unit_list_lock); + shost_for_each_device(sdev, port->adapter->scsi_host) + if (sdev_to_zfcp(sdev)->port == port) + atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, + &sdev_to_zfcp(sdev)->status); break; } } @@ -1725,7 +1693,7 @@ int zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action) struct zfcp_fsf_req *req; int retval = -EIO; - spin_lock_bh(&qdio->req_q_lock); + spin_lock_irq(&qdio->req_q_lock); if (zfcp_qdio_sbal_get(qdio)) goto out; @@ -1754,69 +1722,57 @@ int zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action) erp_action->fsf_req_id = 0; } out: - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); return retval; } -static void zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *req) +static void zfcp_fsf_open_lun_handler(struct zfcp_fsf_req *req) { struct zfcp_adapter *adapter = req->adapter; - struct zfcp_unit *unit = req->data; + struct scsi_device *sdev = req->data; + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); struct fsf_qtcb_header *header = &req->qtcb->header; struct fsf_qtcb_bottom_support *bottom = &req->qtcb->bottom.support; - struct fsf_queue_designator *queue_designator = - &header->fsf_status_qual.fsf_queue_designator; - int exclusive, readwrite; if (req->status & ZFCP_STATUS_FSFREQ_ERROR) return; atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED | ZFCP_STATUS_COMMON_ACCESS_BOXED | - ZFCP_STATUS_UNIT_SHARED | - ZFCP_STATUS_UNIT_READONLY, - &unit->status); + ZFCP_STATUS_LUN_SHARED | + ZFCP_STATUS_LUN_READONLY, + &zfcp_sdev->status); switch (header->fsf_status) { case FSF_PORT_HANDLE_NOT_VALID: - zfcp_erp_adapter_reopen(unit->port->adapter, 0, "fsouh_1", req); + zfcp_erp_adapter_reopen(adapter, 0, "fsouh_1", req); /* fall through */ case FSF_LUN_ALREADY_OPEN: break; case FSF_ACCESS_DENIED: - zfcp_fsf_access_denied_unit(req, unit); - atomic_clear_mask(ZFCP_STATUS_UNIT_SHARED, &unit->status); - atomic_clear_mask(ZFCP_STATUS_UNIT_READONLY, &unit->status); + zfcp_cfdc_lun_denied(sdev, &header->fsf_status_qual); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_PORT_BOXED: - zfcp_erp_port_boxed(unit->port, "fsouh_2", req); + zfcp_erp_set_port_status(zfcp_sdev->port, + ZFCP_STATUS_COMMON_ACCESS_BOXED); + zfcp_erp_port_reopen(zfcp_sdev->port, + ZFCP_STATUS_COMMON_ERP_FAILED, "fsouh_2", + req); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_LUN_SHARING_VIOLATION: - if (header->fsf_status_qual.word[0]) - dev_warn(&adapter->ccw_device->dev, - "LUN 0x%Lx on port 0x%Lx is already in " - "use by CSS%d, MIF Image ID %x\n", - (unsigned long long)unit->fcp_lun, - (unsigned long long)unit->port->wwpn, - queue_designator->cssid, - queue_designator->hla); - else - zfcp_act_eval_err(adapter, - header->fsf_status_qual.word[2]); - zfcp_erp_unit_access_denied(unit, "fsouh_3", req); - atomic_clear_mask(ZFCP_STATUS_UNIT_SHARED, &unit->status); - atomic_clear_mask(ZFCP_STATUS_UNIT_READONLY, &unit->status); + zfcp_cfdc_lun_shrng_vltn(sdev, &header->fsf_status_qual); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_MAXIMUM_NUMBER_OF_LUNS_EXCEEDED: dev_warn(&adapter->ccw_device->dev, "No handle is available for LUN " "0x%016Lx on port 0x%016Lx\n", - (unsigned long long)unit->fcp_lun, - (unsigned long long)unit->port->wwpn); - zfcp_erp_unit_failed(unit, "fsouh_4", req); + (unsigned long long)zfcp_scsi_dev_lun(sdev), + (unsigned long long)zfcp_sdev->port->wwpn); + zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_ERP_FAILED); /* fall through */ case FSF_INVALID_COMMAND_OPTION: req->status |= ZFCP_STATUS_FSFREQ_ERROR; @@ -1824,7 +1780,7 @@ static void zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *req) case FSF_ADAPTER_STATUS_AVAILABLE: switch (header->fsf_status_qual.word[0]) { case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: - zfcp_fc_test_link(unit->port); + zfcp_fc_test_link(zfcp_sdev->port); /* fall through */ case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: req->status |= ZFCP_STATUS_FSFREQ_ERROR; @@ -1833,70 +1789,26 @@ static void zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *req) break; case FSF_GOOD: - unit->handle = header->lun_handle; - atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status); - - if (!(adapter->connection_features & FSF_FEATURE_NPIV_MODE) && - (adapter->adapter_features & FSF_FEATURE_LUN_SHARING) && - !zfcp_ccw_priv_sch(adapter)) { - exclusive = (bottom->lun_access_info & - FSF_UNIT_ACCESS_EXCLUSIVE); - readwrite = (bottom->lun_access_info & - FSF_UNIT_ACCESS_OUTBOUND_TRANSFER); - - if (!exclusive) - atomic_set_mask(ZFCP_STATUS_UNIT_SHARED, - &unit->status); - - if (!readwrite) { - atomic_set_mask(ZFCP_STATUS_UNIT_READONLY, - &unit->status); - dev_info(&adapter->ccw_device->dev, - "SCSI device at LUN 0x%016Lx on port " - "0x%016Lx opened read-only\n", - (unsigned long long)unit->fcp_lun, - (unsigned long long)unit->port->wwpn); - } - - if (exclusive && !readwrite) { - dev_err(&adapter->ccw_device->dev, - "Exclusive read-only access not " - "supported (unit 0x%016Lx, " - "port 0x%016Lx)\n", - (unsigned long long)unit->fcp_lun, - (unsigned long long)unit->port->wwpn); - zfcp_erp_unit_failed(unit, "fsouh_5", req); - req->status |= ZFCP_STATUS_FSFREQ_ERROR; - zfcp_erp_unit_shutdown(unit, 0, "fsouh_6", req); - } else if (!exclusive && readwrite) { - dev_err(&adapter->ccw_device->dev, - "Shared read-write access not " - "supported (unit 0x%016Lx, port " - "0x%016Lx)\n", - (unsigned long long)unit->fcp_lun, - (unsigned long long)unit->port->wwpn); - zfcp_erp_unit_failed(unit, "fsouh_7", req); - req->status |= ZFCP_STATUS_FSFREQ_ERROR; - zfcp_erp_unit_shutdown(unit, 0, "fsouh_8", req); - } - } + zfcp_sdev->lun_handle = header->lun_handle; + atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &zfcp_sdev->status); + zfcp_cfdc_open_lun_eval(sdev, bottom); break; } } /** - * zfcp_fsf_open_unit - open unit + * zfcp_fsf_open_lun - open LUN * @erp_action: pointer to struct zfcp_erp_action * Returns: 0 on success, error otherwise */ -int zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action) +int zfcp_fsf_open_lun(struct zfcp_erp_action *erp_action) { struct zfcp_adapter *adapter = erp_action->adapter; struct zfcp_qdio *qdio = adapter->qdio; struct zfcp_fsf_req *req; int retval = -EIO; - spin_lock_bh(&qdio->req_q_lock); + spin_lock_irq(&qdio->req_q_lock); if (zfcp_qdio_sbal_get(qdio)) goto out; @@ -1913,9 +1825,9 @@ int zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action) zfcp_qdio_set_sbale_last(qdio, &req->qdio_req); req->qtcb->header.port_handle = erp_action->port->handle; - req->qtcb->bottom.support.fcp_lun = erp_action->unit->fcp_lun; - req->handler = zfcp_fsf_open_unit_handler; - req->data = erp_action->unit; + req->qtcb->bottom.support.fcp_lun = zfcp_scsi_dev_lun(erp_action->sdev); + req->handler = zfcp_fsf_open_lun_handler; + req->data = erp_action->sdev; req->erp_action = erp_action; erp_action->fsf_req_id = req->req_id; @@ -1929,34 +1841,40 @@ int zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action) erp_action->fsf_req_id = 0; } out: - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); return retval; } -static void zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *req) +static void zfcp_fsf_close_lun_handler(struct zfcp_fsf_req *req) { - struct zfcp_unit *unit = req->data; + struct scsi_device *sdev = req->data; + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); if (req->status & ZFCP_STATUS_FSFREQ_ERROR) return; switch (req->qtcb->header.fsf_status) { case FSF_PORT_HANDLE_NOT_VALID: - zfcp_erp_adapter_reopen(unit->port->adapter, 0, "fscuh_1", req); + zfcp_erp_adapter_reopen(zfcp_sdev->port->adapter, 0, "fscuh_1", + req); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_LUN_HANDLE_NOT_VALID: - zfcp_erp_port_reopen(unit->port, 0, "fscuh_2", req); + zfcp_erp_port_reopen(zfcp_sdev->port, 0, "fscuh_2", req); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_PORT_BOXED: - zfcp_erp_port_boxed(unit->port, "fscuh_3", req); + zfcp_erp_set_port_status(zfcp_sdev->port, + ZFCP_STATUS_COMMON_ACCESS_BOXED); + zfcp_erp_port_reopen(zfcp_sdev->port, + ZFCP_STATUS_COMMON_ERP_FAILED, "fscuh_3", + req); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_ADAPTER_STATUS_AVAILABLE: switch (req->qtcb->header.fsf_status_qual.word[0]) { case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: - zfcp_fc_test_link(unit->port); + zfcp_fc_test_link(zfcp_sdev->port); /* fall through */ case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: req->status |= ZFCP_STATUS_FSFREQ_ERROR; @@ -1964,23 +1882,24 @@ static void zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *req) } break; case FSF_GOOD: - atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status); + atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, &zfcp_sdev->status); break; } } /** - * zfcp_fsf_close_unit - close zfcp unit - * @erp_action: pointer to struct zfcp_unit + * zfcp_fsf_close_LUN - close LUN + * @erp_action: pointer to erp_action triggering the "close LUN" * Returns: 0 on success, error otherwise */ -int zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action) +int zfcp_fsf_close_lun(struct zfcp_erp_action *erp_action) { struct zfcp_qdio *qdio = erp_action->adapter->qdio; + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(erp_action->sdev); struct zfcp_fsf_req *req; int retval = -EIO; - spin_lock_bh(&qdio->req_q_lock); + spin_lock_irq(&qdio->req_q_lock); if (zfcp_qdio_sbal_get(qdio)) goto out; @@ -1997,9 +1916,9 @@ int zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action) zfcp_qdio_set_sbale_last(qdio, &req->qdio_req); req->qtcb->header.port_handle = erp_action->port->handle; - req->qtcb->header.lun_handle = erp_action->unit->handle; - req->handler = zfcp_fsf_close_unit_handler; - req->data = erp_action->unit; + req->qtcb->header.lun_handle = zfcp_sdev->lun_handle; + req->handler = zfcp_fsf_close_lun_handler; + req->data = erp_action->sdev; req->erp_action = erp_action; erp_action->fsf_req_id = req->req_id; @@ -2010,7 +1929,7 @@ int zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action) erp_action->fsf_req_id = 0; } out: - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); return retval; } @@ -2025,7 +1944,7 @@ static void zfcp_fsf_req_trace(struct zfcp_fsf_req *req, struct scsi_cmnd *scsi) { struct fsf_qual_latency_info *lat_in; struct latency_cont *lat = NULL; - struct zfcp_unit *unit = req->unit; + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scsi->device); struct zfcp_blk_drv_data blktrc; int ticks = req->adapter->timer_ticks; @@ -2048,24 +1967,24 @@ static void zfcp_fsf_req_trace(struct zfcp_fsf_req *req, struct scsi_cmnd *scsi) case FSF_DATADIR_DIF_READ_STRIP: case FSF_DATADIR_DIF_READ_CONVERT: case FSF_DATADIR_READ: - lat = &unit->latencies.read; + lat = &zfcp_sdev->latencies.read; break; case FSF_DATADIR_DIF_WRITE_INSERT: case FSF_DATADIR_DIF_WRITE_CONVERT: case FSF_DATADIR_WRITE: - lat = &unit->latencies.write; + lat = &zfcp_sdev->latencies.write; break; case FSF_DATADIR_CMND: - lat = &unit->latencies.cmd; + lat = &zfcp_sdev->latencies.cmd; break; } if (lat) { - spin_lock(&unit->latencies.lock); + spin_lock(&zfcp_sdev->latencies.lock); zfcp_fsf_update_lat(&lat->channel, lat_in->channel_lat); zfcp_fsf_update_lat(&lat->fabric, lat_in->fabric_lat); lat->counter++; - spin_unlock(&unit->latencies.lock); + spin_unlock(&zfcp_sdev->latencies.lock); } } @@ -2073,12 +1992,88 @@ static void zfcp_fsf_req_trace(struct zfcp_fsf_req *req, struct scsi_cmnd *scsi) sizeof(blktrc)); } -static void zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *req) +static void zfcp_fsf_fcp_handler_common(struct zfcp_fsf_req *req) +{ + struct scsi_cmnd *scmnd = req->data; + struct scsi_device *sdev = scmnd->device; + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); + struct fsf_qtcb_header *header = &req->qtcb->header; + + if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR)) + return; + + switch (header->fsf_status) { + case FSF_HANDLE_MISMATCH: + case FSF_PORT_HANDLE_NOT_VALID: + zfcp_erp_adapter_reopen(zfcp_sdev->port->adapter, 0, "fssfch1", + req); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; + break; + case FSF_FCPLUN_NOT_VALID: + case FSF_LUN_HANDLE_NOT_VALID: + zfcp_erp_port_reopen(zfcp_sdev->port, 0, "fssfch2", req); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; + break; + case FSF_SERVICE_CLASS_NOT_SUPPORTED: + zfcp_fsf_class_not_supp(req); + break; + case FSF_ACCESS_DENIED: + zfcp_cfdc_lun_denied(sdev, &header->fsf_status_qual); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; + break; + case FSF_DIRECTION_INDICATOR_NOT_VALID: + dev_err(&req->adapter->ccw_device->dev, + "Incorrect direction %d, LUN 0x%016Lx on port " + "0x%016Lx closed\n", + req->qtcb->bottom.io.data_direction, + (unsigned long long)zfcp_scsi_dev_lun(sdev), + (unsigned long long)zfcp_sdev->port->wwpn); + zfcp_erp_adapter_shutdown(zfcp_sdev->port->adapter, 0, + "fssfch3", req); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; + break; + case FSF_CMND_LENGTH_NOT_VALID: + dev_err(&req->adapter->ccw_device->dev, + "Incorrect CDB length %d, LUN 0x%016Lx on " + "port 0x%016Lx closed\n", + req->qtcb->bottom.io.fcp_cmnd_length, + (unsigned long long)zfcp_scsi_dev_lun(sdev), + (unsigned long long)zfcp_sdev->port->wwpn); + zfcp_erp_adapter_shutdown(zfcp_sdev->port->adapter, 0, + "fssfch4", req); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; + break; + case FSF_PORT_BOXED: + zfcp_erp_set_port_status(zfcp_sdev->port, + ZFCP_STATUS_COMMON_ACCESS_BOXED); + zfcp_erp_port_reopen(zfcp_sdev->port, + ZFCP_STATUS_COMMON_ERP_FAILED, "fssfch5", + req); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; + break; + case FSF_LUN_BOXED: + zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_ACCESS_BOXED); + zfcp_erp_lun_reopen(sdev, ZFCP_STATUS_COMMON_ERP_FAILED, + "fssfch6", req); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; + break; + case FSF_ADAPTER_STATUS_AVAILABLE: + if (header->fsf_status_qual.word[0] == + FSF_SQ_INVOKE_LINK_TEST_PROCEDURE) + zfcp_fc_test_link(zfcp_sdev->port); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; + break; + } +} + +static void zfcp_fsf_fcp_cmnd_handler(struct zfcp_fsf_req *req) { struct scsi_cmnd *scpnt; struct fcp_resp_with_ext *fcp_rsp; unsigned long flags; + zfcp_fsf_fcp_handler_common(req); + read_lock_irqsave(&req->adapter->abort_lock, flags); scpnt = req->data; @@ -2125,97 +2120,6 @@ skip_fsfstatus: read_unlock_irqrestore(&req->adapter->abort_lock, flags); } -static void zfcp_fsf_send_fcp_ctm_handler(struct zfcp_fsf_req *req) -{ - struct fcp_resp_with_ext *fcp_rsp; - struct fcp_resp_rsp_info *rsp_info; - - fcp_rsp = (struct fcp_resp_with_ext *) &req->qtcb->bottom.io.fcp_rsp; - rsp_info = (struct fcp_resp_rsp_info *) &fcp_rsp[1]; - - if ((rsp_info->rsp_code != FCP_TMF_CMPL) || - (req->status & ZFCP_STATUS_FSFREQ_ERROR)) - req->status |= ZFCP_STATUS_FSFREQ_TMFUNCFAILED; -} - - -static void zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *req) -{ - struct zfcp_unit *unit; - struct fsf_qtcb_header *header = &req->qtcb->header; - - if (unlikely(req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT)) - unit = req->data; - else - unit = req->unit; - - if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR)) - goto skip_fsfstatus; - - switch (header->fsf_status) { - case FSF_HANDLE_MISMATCH: - case FSF_PORT_HANDLE_NOT_VALID: - zfcp_erp_adapter_reopen(unit->port->adapter, 0, "fssfch1", req); - req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; - case FSF_FCPLUN_NOT_VALID: - case FSF_LUN_HANDLE_NOT_VALID: - zfcp_erp_port_reopen(unit->port, 0, "fssfch2", req); - req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; - case FSF_SERVICE_CLASS_NOT_SUPPORTED: - zfcp_fsf_class_not_supp(req); - break; - case FSF_ACCESS_DENIED: - zfcp_fsf_access_denied_unit(req, unit); - break; - case FSF_DIRECTION_INDICATOR_NOT_VALID: - dev_err(&req->adapter->ccw_device->dev, - "Incorrect direction %d, unit 0x%016Lx on port " - "0x%016Lx closed\n", - req->qtcb->bottom.io.data_direction, - (unsigned long long)unit->fcp_lun, - (unsigned long long)unit->port->wwpn); - zfcp_erp_adapter_shutdown(unit->port->adapter, 0, "fssfch3", - req); - req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; - case FSF_CMND_LENGTH_NOT_VALID: - dev_err(&req->adapter->ccw_device->dev, - "Incorrect CDB length %d, unit 0x%016Lx on " - "port 0x%016Lx closed\n", - req->qtcb->bottom.io.fcp_cmnd_length, - (unsigned long long)unit->fcp_lun, - (unsigned long long)unit->port->wwpn); - zfcp_erp_adapter_shutdown(unit->port->adapter, 0, "fssfch4", - req); - req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; - case FSF_PORT_BOXED: - zfcp_erp_port_boxed(unit->port, "fssfch5", req); - req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; - case FSF_LUN_BOXED: - zfcp_erp_unit_boxed(unit, "fssfch6", req); - req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; - case FSF_ADAPTER_STATUS_AVAILABLE: - if (header->fsf_status_qual.word[0] == - FSF_SQ_INVOKE_LINK_TEST_PROCEDURE) - zfcp_fc_test_link(unit->port); - req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; - } -skip_fsfstatus: - if (req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT) - zfcp_fsf_send_fcp_ctm_handler(req); - else { - zfcp_fsf_send_fcp_command_task_handler(req); - req->unit = NULL; - put_device(&unit->dev); - } -} - static int zfcp_fsf_set_data_dir(struct scsi_cmnd *scsi_cmnd, u32 *data_dir) { switch (scsi_get_prot_op(scsi_cmnd)) { @@ -2255,22 +2159,22 @@ static int zfcp_fsf_set_data_dir(struct scsi_cmnd *scsi_cmnd, u32 *data_dir) } /** - * zfcp_fsf_send_fcp_command_task - initiate an FCP command (for a SCSI command) - * @unit: unit where command is sent to + * zfcp_fsf_fcp_cmnd - initiate an FCP command (for a SCSI command) * @scsi_cmnd: scsi command to be sent */ -int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit, - struct scsi_cmnd *scsi_cmnd) +int zfcp_fsf_fcp_cmnd(struct scsi_cmnd *scsi_cmnd) { struct zfcp_fsf_req *req; struct fcp_cmnd *fcp_cmnd; unsigned int sbtype = SBAL_FLAGS0_TYPE_READ; int real_bytes, retval = -EIO, dix_bytes = 0; - struct zfcp_adapter *adapter = unit->port->adapter; + struct scsi_device *sdev = scsi_cmnd->device; + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); + struct zfcp_adapter *adapter = zfcp_sdev->port->adapter; struct zfcp_qdio *qdio = adapter->qdio; struct fsf_qtcb_bottom_io *io; - if (unlikely(!(atomic_read(&unit->status) & + if (unlikely(!(atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_UNBLOCKED))) return -EBUSY; @@ -2295,11 +2199,10 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit, 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->handler = zfcp_fsf_fcp_cmnd_handler; + req->qtcb->header.lun_handle = zfcp_sdev->lun_handle; + req->qtcb->header.port_handle = zfcp_sdev->port->handle; io->service_class = FSF_CLASS_3; io->fcp_cmnd_length = FCP_CMND_LEN; @@ -2310,8 +2213,6 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit, 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); @@ -2338,7 +2239,6 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit, goto out; failed_scsi_cmnd: - put_device(&unit->dev); zfcp_fsf_req_free(req); scsi_cmnd->host_scribble = NULL; out: @@ -2346,23 +2246,40 @@ out: return retval; } +static void zfcp_fsf_fcp_task_mgmt_handler(struct zfcp_fsf_req *req) +{ + struct fcp_resp_with_ext *fcp_rsp; + struct fcp_resp_rsp_info *rsp_info; + + zfcp_fsf_fcp_handler_common(req); + + fcp_rsp = (struct fcp_resp_with_ext *) &req->qtcb->bottom.io.fcp_rsp; + rsp_info = (struct fcp_resp_rsp_info *) &fcp_rsp[1]; + + if ((rsp_info->rsp_code != FCP_TMF_CMPL) || + (req->status & ZFCP_STATUS_FSFREQ_ERROR)) + req->status |= ZFCP_STATUS_FSFREQ_TMFUNCFAILED; +} + /** - * zfcp_fsf_send_fcp_ctm - send SCSI task management command - * @unit: pointer to struct zfcp_unit + * zfcp_fsf_fcp_task_mgmt - send SCSI task management command + * @scmnd: SCSI command to send the task management command for * @tm_flags: unsigned byte for task management flags * Returns: on success pointer to struct fsf_req, NULL otherwise */ -struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *unit, u8 tm_flags) +struct zfcp_fsf_req *zfcp_fsf_fcp_task_mgmt(struct scsi_cmnd *scmnd, + u8 tm_flags) { struct zfcp_fsf_req *req = NULL; struct fcp_cmnd *fcp_cmnd; - struct zfcp_qdio *qdio = unit->port->adapter->qdio; + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scmnd->device); + struct zfcp_qdio *qdio = zfcp_sdev->port->adapter->qdio; - if (unlikely(!(atomic_read(&unit->status) & + if (unlikely(!(atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_UNBLOCKED))) return NULL; - spin_lock_bh(&qdio->req_q_lock); + spin_lock_irq(&qdio->req_q_lock); if (zfcp_qdio_sbal_get(qdio)) goto out; @@ -2376,10 +2293,10 @@ struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *unit, u8 tm_flags) } req->status |= ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT; - req->data = unit; - req->handler = zfcp_fsf_send_fcp_command_handler; - req->qtcb->header.lun_handle = unit->handle; - req->qtcb->header.port_handle = unit->port->handle; + req->data = scmnd; + req->handler = zfcp_fsf_fcp_task_mgmt_handler; + req->qtcb->header.lun_handle = zfcp_sdev->lun_handle; + req->qtcb->header.port_handle = zfcp_sdev->port->handle; req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND; req->qtcb->bottom.io.service_class = FSF_CLASS_3; req->qtcb->bottom.io.fcp_cmnd_length = FCP_CMND_LEN; @@ -2387,7 +2304,7 @@ struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *unit, u8 tm_flags) zfcp_qdio_set_sbale_last(qdio, &req->qdio_req); fcp_cmnd = (struct fcp_cmnd *) &req->qtcb->bottom.io.fcp_cmnd; - zfcp_fc_fcp_tm(fcp_cmnd, unit->device, tm_flags); + zfcp_fc_fcp_tm(fcp_cmnd, scmnd->device, tm_flags); zfcp_fsf_start_timer(req, ZFCP_SCSI_ER_TIMEOUT); if (!zfcp_fsf_req_send(req)) @@ -2396,7 +2313,7 @@ struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *unit, u8 tm_flags) zfcp_fsf_req_free(req); req = NULL; out: - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); return req; } @@ -2432,7 +2349,7 @@ struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter, return ERR_PTR(-EINVAL); } - spin_lock_bh(&qdio->req_q_lock); + spin_lock_irq(&qdio->req_q_lock); if (zfcp_qdio_sbal_get(qdio)) goto out; @@ -2459,7 +2376,7 @@ struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter, zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); retval = zfcp_fsf_req_send(req); out: - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); if (!retval) { wait_for_completion(&req->completion); diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index b2635759721c..60e6e5714eb9 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -60,13 +60,11 @@ static inline void zfcp_qdio_account(struct zfcp_qdio *qdio) unsigned long long now, span; int used; - spin_lock(&qdio->stat_lock); now = get_clock_monotonic(); span = (now - qdio->req_q_time) >> 12; 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, @@ -84,7 +82,9 @@ static void zfcp_qdio_int_req(struct ccw_device *cdev, unsigned int qdio_err, /* cleanup all SBALs being program-owned now */ zfcp_qdio_zero_sbals(qdio->req_q, idx, count); + spin_lock_irq(&qdio->stat_lock); zfcp_qdio_account(qdio); + spin_unlock_irq(&qdio->stat_lock); atomic_add(count, &qdio->req_q_free); wake_up(&qdio->req_q_wq); } @@ -201,11 +201,11 @@ 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) { - spin_lock_bh(&qdio->req_q_lock); + spin_lock_irq(&qdio->req_q_lock); 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); + spin_unlock_irq(&qdio->req_q_lock); return 0; } @@ -223,7 +223,7 @@ int zfcp_qdio_sbal_get(struct zfcp_qdio *qdio) { long ret; - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); ret = wait_event_interruptible_timeout(qdio->req_q_wq, zfcp_qdio_sbal_check(qdio), 5 * HZ); @@ -239,7 +239,7 @@ int zfcp_qdio_sbal_get(struct zfcp_qdio *qdio) zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdsbg_1", NULL); } - spin_lock_bh(&qdio->req_q_lock); + spin_lock_irq(&qdio->req_q_lock); return -EIO; } @@ -254,7 +254,9 @@ int zfcp_qdio_send(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req) int retval; u8 sbal_number = q_req->sbal_number; + spin_lock(&qdio->stat_lock); zfcp_qdio_account(qdio); + spin_unlock(&qdio->stat_lock); retval = do_QDIO(qdio->adapter->ccw_device, QDIO_FLAG_SYNC_OUTPUT, 0, q_req->sbal_first, sbal_number); @@ -328,9 +330,9 @@ void zfcp_qdio_close(struct zfcp_qdio *qdio) return; /* clear QDIOUP flag, thus do_QDIO is not called during qdio_shutdown */ - spin_lock_bh(&qdio->req_q_lock); + spin_lock_irq(&qdio->req_q_lock); atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status); - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); wake_up(&qdio->req_q_wq); diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index cb000c9833bb..50286d8707f3 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -49,11 +49,12 @@ static int zfcp_scsi_change_queue_depth(struct scsi_device *sdev, int depth, return sdev->queue_depth; } -static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt) +static void zfcp_scsi_slave_destroy(struct scsi_device *sdev) { - struct zfcp_unit *unit = (struct zfcp_unit *) sdpnt->hostdata; - unit->device = NULL; - put_device(&unit->dev); + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); + + zfcp_erp_lun_shutdown_wait(sdev, "scssd_1"); + put_device(&zfcp_sdev->port->dev); } static int zfcp_scsi_slave_configure(struct scsi_device *sdp) @@ -78,23 +79,16 @@ static void zfcp_scsi_command_fail(struct scsi_cmnd *scpnt, int result) static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt, void (*done) (struct scsi_cmnd *)) { - struct zfcp_unit *unit; - struct zfcp_adapter *adapter; - int status, scsi_result, ret; + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scpnt->device); + struct zfcp_adapter *adapter = zfcp_sdev->port->adapter; struct fc_rport *rport = starget_to_rport(scsi_target(scpnt->device)); + int status, scsi_result, ret; /* reset the status for this request */ scpnt->result = 0; scpnt->host_scribble = NULL; scpnt->scsi_done = done; - /* - * figure out adapter and target device - * (stored there by zfcp_scsi_slave_alloc) - */ - adapter = (struct zfcp_adapter *) scpnt->device->host->hostdata[0]; - unit = scpnt->device->hostdata; - scsi_result = fc_remote_port_chkready(rport); if (unlikely(scsi_result)) { scpnt->result = scsi_result; @@ -103,11 +97,11 @@ static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt, return 0; } - status = atomic_read(&unit->status); + status = atomic_read(&zfcp_sdev->status); if (unlikely(status & ZFCP_STATUS_COMMON_ERP_FAILED) && - !(atomic_read(&unit->port->status) & + !(atomic_read(&zfcp_sdev->port->status) & ZFCP_STATUS_COMMON_ERP_FAILED)) { - /* only unit access denied, but port is good + /* only LUN access denied, but port is good * not covered by FC transport, have to fail here */ zfcp_scsi_command_fail(scpnt, DID_ERROR); return 0; @@ -115,8 +109,8 @@ static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt, if (unlikely(!(status & ZFCP_STATUS_COMMON_UNBLOCKED))) { /* This could be either - * open unit pending: this is temporary, will result in - * open unit or ERP_FAILED, so retry command + * open LUN pending: this is temporary, will result in + * open LUN or ERP_FAILED, so retry command * call to rport_delete pending: mimic retry from * fc_remote_port_chkready until rport is BLOCKED */ @@ -124,7 +118,7 @@ static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt, return 0; } - ret = zfcp_fsf_send_fcp_command_task(unit, scpnt); + ret = zfcp_fsf_fcp_cmnd(scpnt); if (unlikely(ret == -EBUSY)) return SCSI_MLQUEUE_DEVICE_BUSY; else if (unlikely(ret < 0)) @@ -133,45 +127,42 @@ static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt, return ret; } -static struct zfcp_unit *zfcp_unit_lookup(struct zfcp_adapter *adapter, - unsigned int id, u64 lun) +static int zfcp_scsi_slave_alloc(struct scsi_device *sdev) { - unsigned long flags; + struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); + struct zfcp_adapter *adapter = + (struct zfcp_adapter *) sdev->host->hostdata[0]; + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); struct zfcp_port *port; - struct zfcp_unit *unit = NULL; + struct zfcp_unit *unit; - read_lock_irqsave(&adapter->port_list_lock, flags); - list_for_each_entry(port, &adapter->port_list, list) { - if (!port->rport || (id != port->rport->scsi_target_id)) - continue; - unit = zfcp_get_unit_by_lun(port, lun); - if (unit) - break; - } - read_unlock_irqrestore(&adapter->port_list_lock, flags); + port = zfcp_get_port_by_wwpn(adapter, rport->port_name); + if (!port) + return -ENXIO; - return unit; -} + unit = zfcp_unit_find(port, zfcp_scsi_dev_lun(sdev)); + if (unit) + put_device(&unit->dev); -static int zfcp_scsi_slave_alloc(struct scsi_device *sdp) -{ - struct zfcp_adapter *adapter; - struct zfcp_unit *unit; - u64 lun; + if (!unit && !(adapter->connection_features & FSF_FEATURE_NPIV_MODE)) { + put_device(&port->dev); + return -ENXIO; + } - adapter = (struct zfcp_adapter *) sdp->host->hostdata[0]; - if (!adapter) - goto out; + zfcp_sdev->port = port; + zfcp_sdev->latencies.write.channel.min = 0xFFFFFFFF; + zfcp_sdev->latencies.write.fabric.min = 0xFFFFFFFF; + zfcp_sdev->latencies.read.channel.min = 0xFFFFFFFF; + zfcp_sdev->latencies.read.fabric.min = 0xFFFFFFFF; + zfcp_sdev->latencies.cmd.channel.min = 0xFFFFFFFF; + zfcp_sdev->latencies.cmd.fabric.min = 0xFFFFFFFF; + spin_lock_init(&zfcp_sdev->latencies.lock); - int_to_scsilun(sdp->lun, (struct scsi_lun *)&lun); - unit = zfcp_unit_lookup(adapter, sdp->id, lun); - if (unit) { - sdp->hostdata = unit; - unit->device = sdp; - return 0; - } -out: - return -ENXIO; + zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_RUNNING); + zfcp_erp_lun_reopen(sdev, 0, "scsla_1", NULL); + zfcp_erp_wait(port->adapter); + + return 0; } static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) @@ -179,7 +170,6 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) struct Scsi_Host *scsi_host = scpnt->device->host; struct zfcp_adapter *adapter = (struct zfcp_adapter *) scsi_host->hostdata[0]; - struct zfcp_unit *unit = scpnt->device->hostdata; struct zfcp_fsf_req *old_req, *abrt_req; unsigned long flags; unsigned long old_reqid = (unsigned long) scpnt->host_scribble; @@ -203,7 +193,7 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) write_unlock_irqrestore(&adapter->abort_lock, flags); while (retry--) { - abrt_req = zfcp_fsf_abort_fcp_command(old_reqid, unit); + abrt_req = zfcp_fsf_abort_fcp_cmnd(scpnt); if (abrt_req) break; @@ -238,14 +228,14 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags) { - struct zfcp_unit *unit = scpnt->device->hostdata; - struct zfcp_adapter *adapter = unit->port->adapter; + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scpnt->device); + struct zfcp_adapter *adapter = zfcp_sdev->port->adapter; struct zfcp_fsf_req *fsf_req = NULL; int retval = SUCCESS, ret; int retry = 3; while (retry--) { - fsf_req = zfcp_fsf_send_fcp_ctm(unit, tm_flags); + fsf_req = zfcp_fsf_fcp_task_mgmt(scpnt, tm_flags); if (fsf_req) break; @@ -256,7 +246,7 @@ static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags) if (!(atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_RUNNING)) { - zfcp_dbf_scsi_devreset("nres", tm_flags, unit, scpnt); + zfcp_dbf_scsi_devreset("nres", scpnt, tm_flags); return SUCCESS; } } @@ -266,10 +256,10 @@ static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags) wait_for_completion(&fsf_req->completion); if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCFAILED) { - zfcp_dbf_scsi_devreset("fail", tm_flags, unit, scpnt); + zfcp_dbf_scsi_devreset("fail", scpnt, tm_flags); retval = FAILED; } else - zfcp_dbf_scsi_devreset("okay", tm_flags, unit, scpnt); + zfcp_dbf_scsi_devreset("okay", scpnt, tm_flags); zfcp_fsf_req_free(fsf_req); return retval; @@ -287,8 +277,8 @@ static int zfcp_scsi_eh_target_reset_handler(struct scsi_cmnd *scpnt) static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt) { - struct zfcp_unit *unit = scpnt->device->hostdata; - struct zfcp_adapter *adapter = unit->port->adapter; + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scpnt->device); + struct zfcp_adapter *adapter = zfcp_sdev->port->adapter; int ret; zfcp_erp_adapter_reopen(adapter, 0, "schrh_1", scpnt); @@ -319,8 +309,8 @@ int zfcp_adapter_scsi_register(struct zfcp_adapter *adapter) } /* tell the SCSI stack some characteristics of this adapter */ - adapter->scsi_host->max_id = 1; - adapter->scsi_host->max_lun = 1; + adapter->scsi_host->max_id = 511; + adapter->scsi_host->max_lun = 0xFFFFFFFF; adapter->scsi_host->max_channel = 0; adapter->scsi_host->unique_id = dev_id.devno; adapter->scsi_host->max_cmd_len = 16; /* in struct fcp_cmnd */ @@ -534,20 +524,6 @@ 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; @@ -574,7 +550,7 @@ static void zfcp_scsi_rport_register(struct zfcp_port *port) port->rport = rport; port->starget_id = rport->scsi_target_id; - zfcp_scsi_queue_unit_register(port); + zfcp_unit_queue_scsi_scan(port); } static void zfcp_scsi_rport_block(struct zfcp_port *port) @@ -638,29 +614,6 @@ void zfcp_scsi_rport_work(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 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); -} - -/** * zfcp_scsi_set_prot - Configure DIF/DIX support in scsi_host * @adapter: The adapter where to configure DIF/DIX for the SCSI host */ @@ -681,6 +634,7 @@ void zfcp_scsi_set_prot(struct zfcp_adapter *adapter) adapter->adapter_features & FSF_FEATURE_DIX_PROT_TCPIP) { mask |= SHOST_DIX_TYPE1_PROTECTION; scsi_host_set_guard(shost, SHOST_DIX_GUARD_IP); + shost->sg_prot_tablesize = ZFCP_QDIO_MAX_SBALES_PER_REQ / 2; shost->sg_tablesize = ZFCP_QDIO_MAX_SBALES_PER_REQ / 2; shost->max_sectors = ZFCP_QDIO_MAX_SBALES_PER_REQ * 8 / 2; } @@ -734,7 +688,6 @@ struct fc_function_template zfcp_transport_functions = { .show_host_port_type = 1, .show_host_speed = 1, .show_host_port_id = 1, - .disable_target_scan = 1, .dd_bsg_size = sizeof(struct zfcp_fsf_ct_els), }; diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c index b4561c86e230..2f2c54f4718f 100644 --- a/drivers/s390/scsi/zfcp_sysfs.c +++ b/drivers/s390/scsi/zfcp_sysfs.c @@ -68,63 +68,96 @@ ZFCP_DEFINE_ATTR(zfcp_port, port, access_denied, "%d\n", ZFCP_STATUS_COMMON_ACCESS_DENIED) != 0); ZFCP_DEFINE_ATTR(zfcp_unit, unit, status, "0x%08x\n", - atomic_read(&unit->status)); + zfcp_unit_sdev_status(unit)); ZFCP_DEFINE_ATTR(zfcp_unit, unit, in_recovery, "%d\n", - (atomic_read(&unit->status) & + (zfcp_unit_sdev_status(unit) & ZFCP_STATUS_COMMON_ERP_INUSE) != 0); ZFCP_DEFINE_ATTR(zfcp_unit, unit, access_denied, "%d\n", - (atomic_read(&unit->status) & + (zfcp_unit_sdev_status(unit) & ZFCP_STATUS_COMMON_ACCESS_DENIED) != 0); ZFCP_DEFINE_ATTR(zfcp_unit, unit, access_shared, "%d\n", - (atomic_read(&unit->status) & - ZFCP_STATUS_UNIT_SHARED) != 0); + (zfcp_unit_sdev_status(unit) & + ZFCP_STATUS_LUN_SHARED) != 0); ZFCP_DEFINE_ATTR(zfcp_unit, unit, access_readonly, "%d\n", - (atomic_read(&unit->status) & - ZFCP_STATUS_UNIT_READONLY) != 0); + (zfcp_unit_sdev_status(unit) & + ZFCP_STATUS_LUN_READONLY) != 0); -#define ZFCP_SYSFS_FAILED(_feat_def, _feat, _adapter, _mod_id, _reopen_id) \ -static ssize_t zfcp_sysfs_##_feat##_failed_show(struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ - struct _feat_def *_feat = container_of(dev, struct _feat_def, dev); \ - \ - if (atomic_read(&_feat->status) & ZFCP_STATUS_COMMON_ERP_FAILED) \ - return sprintf(buf, "1\n"); \ - else \ - return sprintf(buf, "0\n"); \ -} \ -static ssize_t zfcp_sysfs_##_feat##_failed_store(struct device *dev, \ - struct device_attribute *attr,\ - const char *buf, size_t count)\ -{ \ - struct _feat_def *_feat = container_of(dev, struct _feat_def, dev); \ - unsigned long val; \ - int retval = 0; \ - \ - if (!(_feat && get_device(&_feat->dev))) \ - return -EBUSY; \ - \ - if (strict_strtoul(buf, 0, &val) || val != 0) { \ - retval = -EINVAL; \ - goto out; \ - } \ - \ - zfcp_erp_modify_##_feat##_status(_feat, _mod_id, NULL, \ - ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET);\ - zfcp_erp_##_feat##_reopen(_feat, ZFCP_STATUS_COMMON_ERP_FAILED, \ - _reopen_id, NULL); \ - zfcp_erp_wait(_adapter); \ -out: \ - put_device(&_feat->dev); \ - return retval ? retval : (ssize_t) count; \ -} \ -static ZFCP_DEV_ATTR(_feat, failed, S_IWUSR | S_IRUGO, \ - zfcp_sysfs_##_feat##_failed_show, \ - zfcp_sysfs_##_feat##_failed_store); +static ssize_t zfcp_sysfs_port_failed_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct zfcp_port *port = container_of(dev, struct zfcp_port, dev); + + if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) + return sprintf(buf, "1\n"); + + return sprintf(buf, "0\n"); +} + +static ssize_t zfcp_sysfs_port_failed_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct zfcp_port *port = container_of(dev, struct zfcp_port, dev); + unsigned long val; + + if (strict_strtoul(buf, 0, &val) || val != 0) + return -EINVAL; + + zfcp_erp_set_port_status(port, ZFCP_STATUS_COMMON_RUNNING); + zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, "sypfai2", + NULL); + zfcp_erp_wait(port->adapter); -ZFCP_SYSFS_FAILED(zfcp_port, port, port->adapter, "sypfai1", "sypfai2"); -ZFCP_SYSFS_FAILED(zfcp_unit, unit, unit->port->adapter, "syufai1", "syufai2"); + return count; +} +static ZFCP_DEV_ATTR(port, failed, S_IWUSR | S_IRUGO, + zfcp_sysfs_port_failed_show, + zfcp_sysfs_port_failed_store); + +static ssize_t zfcp_sysfs_unit_failed_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct zfcp_unit *unit = container_of(dev, struct zfcp_unit, dev); + struct scsi_device *sdev; + unsigned int status, failed = 1; + + sdev = zfcp_unit_sdev(unit); + if (sdev) { + status = atomic_read(&sdev_to_zfcp(sdev)->status); + failed = status & ZFCP_STATUS_COMMON_ERP_FAILED ? 1 : 0; + scsi_device_put(sdev); + } + + return sprintf(buf, "%d\n", failed); +} + +static ssize_t zfcp_sysfs_unit_failed_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct zfcp_unit *unit = container_of(dev, struct zfcp_unit, dev); + unsigned long val; + struct scsi_device *sdev; + + if (strict_strtoul(buf, 0, &val) || val != 0) + return -EINVAL; + + sdev = zfcp_unit_sdev(unit); + if (sdev) { + zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_RUNNING); + zfcp_erp_lun_reopen(sdev, ZFCP_STATUS_COMMON_ERP_FAILED, + "syufai2", NULL); + zfcp_erp_wait(unit->port->adapter); + } else + zfcp_unit_scsi_scan(unit); + + return count; +} +static ZFCP_DEV_ATTR(unit, failed, S_IWUSR | S_IRUGO, + zfcp_sysfs_unit_failed_show, + zfcp_sysfs_unit_failed_store); static ssize_t zfcp_sysfs_adapter_failed_show(struct device *dev, struct device_attribute *attr, @@ -163,8 +196,7 @@ static ssize_t zfcp_sysfs_adapter_failed_store(struct device *dev, goto out; } - zfcp_erp_modify_adapter_status(adapter, "syafai1", NULL, - ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET); + zfcp_erp_set_adapter_status(adapter, ZFCP_STATUS_COMMON_RUNNING); zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, "syafai2", NULL); zfcp_erp_wait(adapter); @@ -257,28 +289,15 @@ static ssize_t zfcp_sysfs_unit_add_store(struct device *dev, const char *buf, size_t count) { struct zfcp_port *port = container_of(dev, struct zfcp_port, dev); - struct zfcp_unit *unit; u64 fcp_lun; - int retval = -EINVAL; - - if (!(port && get_device(&port->dev))) - return -EBUSY; if (strict_strtoull(buf, 0, (unsigned long long *) &fcp_lun)) - goto out; + return -EINVAL; - unit = zfcp_unit_enqueue(port, fcp_lun); - if (IS_ERR(unit)) - goto out; - else - retval = 0; + if (zfcp_unit_add(port, fcp_lun)) + return -EINVAL; - zfcp_erp_unit_reopen(unit, 0, "syuas_1", NULL); - zfcp_erp_wait(unit->port->adapter); - zfcp_scsi_scan(unit); -out: - put_device(&port->dev); - return retval ? retval : (ssize_t) count; + return count; } static DEVICE_ATTR(unit_add, S_IWUSR, NULL, zfcp_sysfs_unit_add_store); @@ -287,42 +306,15 @@ static ssize_t zfcp_sysfs_unit_remove_store(struct device *dev, const char *buf, size_t count) { struct zfcp_port *port = container_of(dev, struct zfcp_port, dev); - struct zfcp_unit *unit; u64 fcp_lun; - int retval = -EINVAL; - struct scsi_device *sdev; - - if (!(port && get_device(&port->dev))) - return -EBUSY; if (strict_strtoull(buf, 0, (unsigned long long *) &fcp_lun)) - goto out; + return -EINVAL; - unit = zfcp_get_unit_by_lun(port, fcp_lun); - if (!unit) - goto out; - else - retval = 0; - - 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); - write_unlock_irq(&port->unit_list_lock); - - put_device(&unit->dev); + if (zfcp_unit_remove(port, fcp_lun)) + return -EINVAL; - zfcp_erp_unit_shutdown(unit, 0, "syurs_1", NULL); - zfcp_device_unregister(&unit->dev, &zfcp_sysfs_unit_attrs); -out: - put_device(&port->dev); - return retval ? retval : (ssize_t) count; + return count; } static DEVICE_ATTR(unit_remove, S_IWUSR, NULL, zfcp_sysfs_unit_remove_store); @@ -363,9 +355,9 @@ zfcp_sysfs_unit_##_name##_latency_show(struct device *dev, \ struct device_attribute *attr, \ char *buf) { \ struct scsi_device *sdev = to_scsi_device(dev); \ - struct zfcp_unit *unit = sdev->hostdata; \ - struct zfcp_latencies *lat = &unit->latencies; \ - struct zfcp_adapter *adapter = unit->port->adapter; \ + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); \ + struct zfcp_latencies *lat = &zfcp_sdev->latencies; \ + struct zfcp_adapter *adapter = zfcp_sdev->port->adapter; \ unsigned long long fsum, fmin, fmax, csum, cmin, cmax, cc; \ \ spin_lock_bh(&lat->lock); \ @@ -394,8 +386,8 @@ zfcp_sysfs_unit_##_name##_latency_store(struct device *dev, \ const char *buf, size_t count) \ { \ struct scsi_device *sdev = to_scsi_device(dev); \ - struct zfcp_unit *unit = sdev->hostdata; \ - struct zfcp_latencies *lat = &unit->latencies; \ + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); \ + struct zfcp_latencies *lat = &zfcp_sdev->latencies; \ unsigned long flags; \ \ spin_lock_irqsave(&lat->lock, flags); \ @@ -423,19 +415,28 @@ static ssize_t zfcp_sysfs_scsi_##_name##_show(struct device *dev, \ struct device_attribute *attr,\ char *buf) \ { \ - struct scsi_device *sdev = to_scsi_device(dev); \ - struct zfcp_unit *unit = sdev->hostdata; \ + struct scsi_device *sdev = to_scsi_device(dev); \ + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); \ + struct zfcp_port *port = zfcp_sdev->port; \ \ return sprintf(buf, _format, _value); \ } \ static DEVICE_ATTR(_name, S_IRUGO, zfcp_sysfs_scsi_##_name##_show, NULL); ZFCP_DEFINE_SCSI_ATTR(hba_id, "%s\n", - dev_name(&unit->port->adapter->ccw_device->dev)); + dev_name(&port->adapter->ccw_device->dev)); ZFCP_DEFINE_SCSI_ATTR(wwpn, "0x%016llx\n", - (unsigned long long) unit->port->wwpn); -ZFCP_DEFINE_SCSI_ATTR(fcp_lun, "0x%016llx\n", - (unsigned long long) unit->fcp_lun); + (unsigned long long) port->wwpn); + +static ssize_t zfcp_sysfs_scsi_fcp_lun_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct scsi_device *sdev = to_scsi_device(dev); + + return sprintf(buf, "0x%016llx\n", zfcp_scsi_dev_lun(sdev)); +} +static DEVICE_ATTR(fcp_lun, S_IRUGO, zfcp_sysfs_scsi_fcp_lun_show, NULL); struct device_attribute *zfcp_sysfs_sdev_attrs[] = { &dev_attr_fcp_lun, diff --git a/drivers/s390/scsi/zfcp_unit.c b/drivers/s390/scsi/zfcp_unit.c new file mode 100644 index 000000000000..1119c535a667 --- /dev/null +++ b/drivers/s390/scsi/zfcp_unit.c @@ -0,0 +1,244 @@ +/* + * zfcp device driver + * + * Tracking of manually configured LUNs and helper functions to + * register the LUNs with the SCSI midlayer. + * + * Copyright IBM Corporation 2010 + */ + +#include "zfcp_def.h" +#include "zfcp_ext.h" + +/** + * zfcp_unit_scsi_scan - Register LUN with SCSI midlayer + * @unit: The zfcp LUN/unit to register + * + * When the SCSI midlayer is not allowed to automatically scan and + * attach SCSI devices, zfcp has to register the single devices with + * the SCSI midlayer. + */ +void zfcp_unit_scsi_scan(struct zfcp_unit *unit) +{ + struct fc_rport *rport = unit->port->rport; + unsigned int lun; + + lun = scsilun_to_int((struct scsi_lun *) &unit->fcp_lun); + + if (rport && rport->port_state == FC_PORTSTATE_ONLINE) + scsi_scan_target(&rport->dev, 0, rport->scsi_target_id, lun, 1); +} + +static void zfcp_unit_scsi_scan_work(struct work_struct *work) +{ + struct zfcp_unit *unit = container_of(work, struct zfcp_unit, + scsi_work); + + zfcp_unit_scsi_scan(unit); + put_device(&unit->dev); +} + +/** + * zfcp_unit_queue_scsi_scan - Register configured units on port + * @port: The zfcp_port where to register units + * + * After opening a port, all units configured on this port have to be + * registered with the SCSI midlayer. This function should be called + * after calling fc_remote_port_add, so that the fc_rport is already + * ONLINE and the call to scsi_scan_target runs the same way as the + * call in the FC transport class. + */ +void zfcp_unit_queue_scsi_scan(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 struct zfcp_unit *_zfcp_unit_find(struct zfcp_port *port, u64 fcp_lun) +{ + struct zfcp_unit *unit; + + list_for_each_entry(unit, &port->unit_list, list) + if (unit->fcp_lun == fcp_lun) { + get_device(&unit->dev); + return unit; + } + + return NULL; +} + +/** + * zfcp_unit_find - Find and return zfcp_unit with specified FCP LUN + * @port: zfcp_port where to look for the unit + * @fcp_lun: 64 Bit FCP LUN used to identify the zfcp_unit + * + * If zfcp_unit is found, a reference is acquired that has to be + * released later. + * + * Returns: Pointer to the zfcp_unit, or NULL if there is no zfcp_unit + * with the specified FCP LUN. + */ +struct zfcp_unit *zfcp_unit_find(struct zfcp_port *port, u64 fcp_lun) +{ + struct zfcp_unit *unit; + + read_lock_irq(&port->unit_list_lock); + unit = _zfcp_unit_find(port, fcp_lun); + read_unlock_irq(&port->unit_list_lock); + return unit; +} + +/** + * zfcp_unit_release - Drop reference to zfcp_port and free memory of zfcp_unit. + * @dev: pointer to device in zfcp_unit + */ +static void zfcp_unit_release(struct device *dev) +{ + struct zfcp_unit *unit = container_of(dev, struct zfcp_unit, dev); + + put_device(&unit->port->dev); + kfree(unit); +} + +/** + * zfcp_unit_enqueue - enqueue unit to unit list of a port. + * @port: pointer to port where unit is added + * @fcp_lun: FCP LUN of unit to be enqueued + * Returns: 0 success + * + * Sets up some unit internal structures and creates sysfs entry. + */ +int zfcp_unit_add(struct zfcp_port *port, u64 fcp_lun) +{ + struct zfcp_unit *unit; + + unit = zfcp_unit_find(port, fcp_lun); + if (unit) { + put_device(&unit->dev); + return -EEXIST; + } + + unit = kzalloc(sizeof(struct zfcp_unit), GFP_KERNEL); + if (!unit) + return -ENOMEM; + + unit->port = port; + unit->fcp_lun = fcp_lun; + unit->dev.parent = &port->dev; + unit->dev.release = zfcp_unit_release; + INIT_WORK(&unit->scsi_work, zfcp_unit_scsi_scan_work); + + if (dev_set_name(&unit->dev, "0x%016llx", + (unsigned long long) fcp_lun)) { + kfree(unit); + return -ENOMEM; + } + + if (device_register(&unit->dev)) { + put_device(&unit->dev); + return -ENOMEM; + } + + if (sysfs_create_group(&unit->dev.kobj, &zfcp_sysfs_unit_attrs)) { + device_unregister(&unit->dev); + return -EINVAL; + } + + get_device(&port->dev); + + write_lock_irq(&port->unit_list_lock); + list_add_tail(&unit->list, &port->unit_list); + write_unlock_irq(&port->unit_list_lock); + + zfcp_unit_scsi_scan(unit); + + return 0; +} + +/** + * zfcp_unit_sdev - Return SCSI device for zfcp_unit + * @unit: The zfcp_unit where to get the SCSI device for + * + * Returns: scsi_device pointer on success, NULL if there is no SCSI + * device for this zfcp_unit + * + * On success, the caller also holds a reference to the SCSI device + * that must be released with scsi_device_put. + */ +struct scsi_device *zfcp_unit_sdev(struct zfcp_unit *unit) +{ + struct Scsi_Host *shost; + struct zfcp_port *port; + unsigned int lun; + + lun = scsilun_to_int((struct scsi_lun *) &unit->fcp_lun); + port = unit->port; + shost = port->adapter->scsi_host; + return scsi_device_lookup(shost, 0, port->starget_id, lun); +} + +/** + * zfcp_unit_sdev_status - Return zfcp LUN status for SCSI device + * @unit: The unit to lookup the SCSI device for + * + * Returns the zfcp LUN status field of the SCSI device if the SCSI device + * for the zfcp_unit exists, 0 otherwise. + */ +unsigned int zfcp_unit_sdev_status(struct zfcp_unit *unit) +{ + unsigned int status = 0; + struct scsi_device *sdev; + struct zfcp_scsi_dev *zfcp_sdev; + + sdev = zfcp_unit_sdev(unit); + if (sdev) { + zfcp_sdev = sdev_to_zfcp(sdev); + status = atomic_read(&zfcp_sdev->status); + scsi_device_put(sdev); + } + + return status; +} + +/** + * zfcp_unit_remove - Remove entry from list of configured units + * @port: The port where to remove the unit from the configuration + * @fcp_lun: The 64 bit LUN of the unit to remove + * + * Returns: -EINVAL if a unit with the specified LUN does not exist, + * 0 on success. + */ +int zfcp_unit_remove(struct zfcp_port *port, u64 fcp_lun) +{ + struct zfcp_unit *unit; + struct scsi_device *sdev; + + write_lock_irq(&port->unit_list_lock); + unit = _zfcp_unit_find(port, fcp_lun); + if (unit) + list_del(&unit->list); + write_unlock_irq(&port->unit_list_lock); + + if (!unit) + return -EINVAL; + + sdev = zfcp_unit_sdev(unit); + if (sdev) { + scsi_remove_device(sdev); + scsi_device_put(sdev); + } + + put_device(&unit->dev); + + zfcp_device_unregister(&unit->dev, &zfcp_sysfs_unit_attrs); + + return 0; +} diff --git a/drivers/sbus/char/display7seg.c b/drivers/sbus/char/display7seg.c index 1690e53fb84a..55f71ea9c418 100644 --- a/drivers/sbus/char/display7seg.c +++ b/drivers/sbus/char/display7seg.c @@ -162,6 +162,7 @@ static const struct file_operations d7s_fops = { .compat_ioctl = d7s_ioctl, .open = d7s_open, .release = d7s_release, + .llseek = noop_llseek, }; static struct miscdevice d7s_miscdev = { diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c index 078e5f4520ef..8ce414e39489 100644 --- a/drivers/sbus/char/envctrl.c +++ b/drivers/sbus/char/envctrl.c @@ -720,6 +720,7 @@ static const struct file_operations envctrl_fops = { #endif .open = envctrl_open, .release = envctrl_release, + .llseek = noop_llseek, }; static struct miscdevice envctrl_dev = { diff --git a/drivers/sbus/char/jsflash.c b/drivers/sbus/char/jsflash.c index 4942050dc5b6..13f48e28a1e1 100644 --- a/drivers/sbus/char/jsflash.c +++ b/drivers/sbus/char/jsflash.c @@ -27,7 +27,7 @@ */ #include <linux/module.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/types.h> #include <linux/errno.h> #include <linux/miscdevice.h> @@ -68,6 +68,8 @@ #define JSF_PART_BITS 2 /* 2 bits of minors to cover JSF_NPART */ #define JSF_PART_MASK 0x3 /* 2 bits mask */ +static DEFINE_MUTEX(jsf_mutex); + /* * Access functions. * We could ioremap(), but it's easier this way. @@ -225,7 +227,7 @@ static loff_t jsf_lseek(struct file * file, loff_t offset, int orig) { loff_t ret; - lock_kernel(); + mutex_lock(&jsf_mutex); switch (orig) { case 0: file->f_pos = offset; @@ -238,7 +240,7 @@ static loff_t jsf_lseek(struct file * file, loff_t offset, int orig) default: ret = -EINVAL; } - unlock_kernel(); + mutex_unlock(&jsf_mutex); return ret; } @@ -384,18 +386,18 @@ static int jsf_ioctl_program(void __user *arg) static long jsf_ioctl(struct file *f, unsigned int cmd, unsigned long arg) { - lock_kernel(); + mutex_lock(&jsf_mutex); int error = -ENOTTY; void __user *argp = (void __user *)arg; if (!capable(CAP_SYS_ADMIN)) { - unlock_kernel(); + mutex_unlock(&jsf_mutex); return -EPERM; } switch (cmd) { case JSFLASH_IDENT: if (copy_to_user(argp, &jsf0.id, JSFIDSZ)) { - unlock_kernel(); + mutex_unlock(&jsf_mutex); return -EFAULT; } break; @@ -407,7 +409,7 @@ static long jsf_ioctl(struct file *f, unsigned int cmd, unsigned long arg) break; } - unlock_kernel(); + mutex_unlock(&jsf_mutex); return error; } @@ -418,17 +420,17 @@ static int jsf_mmap(struct file * file, struct vm_area_struct * vma) static int jsf_open(struct inode * inode, struct file * filp) { - lock_kernel(); + mutex_lock(&jsf_mutex); if (jsf0.base == 0) { - unlock_kernel(); + mutex_unlock(&jsf_mutex); return -ENXIO; } if (test_and_set_bit(0, (void *)&jsf0.busy) != 0) { - unlock_kernel(); + mutex_unlock(&jsf_mutex); return -EBUSY; } - unlock_kernel(); + mutex_unlock(&jsf_mutex); return 0; /* XXX What security? */ } diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c index e20b7bdd4c78..fcf08b3f52c1 100644 --- a/drivers/scsi/3w-9xxx.c +++ b/drivers/scsi/3w-9xxx.c @@ -92,7 +92,6 @@ #include <linux/pci.h> #include <linux/time.h> #include <linux/mutex.h> -#include <linux/smp_lock.h> #include <linux/slab.h> #include <asm/io.h> #include <asm/irq.h> @@ -105,6 +104,7 @@ /* Globals */ #define TW_DRIVER_VERSION "2.26.02.014" +static DEFINE_MUTEX(twa_chrdev_mutex); static TW_Device_Extension *twa_device_extension_list[TW_MAX_SLOT]; static unsigned int twa_device_extension_count; static int twa_major = -1; @@ -222,7 +222,8 @@ static const struct file_operations twa_fops = { .owner = THIS_MODULE, .unlocked_ioctl = twa_chrdev_ioctl, .open = twa_chrdev_open, - .release = NULL + .release = NULL, + .llseek = noop_llseek, }; /* This function will complete an aen request from the isr */ @@ -658,7 +659,7 @@ static long twa_chrdev_ioctl(struct file *file, unsigned int cmd, unsigned long int retval = TW_IOCTL_ERROR_OS_EFAULT; void __user *argp = (void __user *)arg; - lock_kernel(); + mutex_lock(&twa_chrdev_mutex); /* Only let one of these through at a time */ if (mutex_lock_interruptible(&tw_dev->ioctl_lock)) { @@ -879,7 +880,7 @@ out3: out2: mutex_unlock(&tw_dev->ioctl_lock); out: - unlock_kernel(); + mutex_unlock(&twa_chrdev_mutex); return retval; } /* End twa_chrdev_ioctl() */ @@ -890,7 +891,6 @@ static int twa_chrdev_open(struct inode *inode, struct file *file) unsigned int minor_number; int retval = TW_IOCTL_ERROR_OS_ENODEV; - cycle_kernel_lock(); minor_number = iminor(inode); if (minor_number >= twa_device_extension_count) goto out; diff --git a/drivers/scsi/3w-sas.c b/drivers/scsi/3w-sas.c index f481e734aad4..6a95d111d207 100644 --- a/drivers/scsi/3w-sas.c +++ b/drivers/scsi/3w-sas.c @@ -64,7 +64,6 @@ #include <linux/pci.h> #include <linux/time.h> #include <linux/mutex.h> -#include <linux/smp_lock.h> #include <linux/slab.h> #include <asm/io.h> #include <asm/irq.h> @@ -77,6 +76,7 @@ /* Globals */ #define TW_DRIVER_VERSION "3.26.02.000" +static DEFINE_MUTEX(twl_chrdev_mutex); static TW_Device_Extension *twl_device_extension_list[TW_MAX_SLOT]; static unsigned int twl_device_extension_count; static int twl_major = -1; @@ -764,7 +764,7 @@ static long twl_chrdev_ioctl(struct file *file, unsigned int cmd, unsigned long int retval = -EFAULT; void __user *argp = (void __user *)arg; - lock_kernel(); + mutex_lock(&twl_chrdev_mutex); /* Only let one of these through at a time */ if (mutex_lock_interruptible(&tw_dev->ioctl_lock)) { @@ -861,7 +861,7 @@ out3: out2: mutex_unlock(&tw_dev->ioctl_lock); out: - unlock_kernel(); + mutex_unlock(&twl_chrdev_mutex); return retval; } /* End twl_chrdev_ioctl() */ @@ -876,7 +876,6 @@ static int twl_chrdev_open(struct inode *inode, struct file *file) goto out; } - cycle_kernel_lock(); minor_number = iminor(inode); if (minor_number >= twl_device_extension_count) goto out; @@ -890,7 +889,8 @@ static const struct file_operations twl_fops = { .owner = THIS_MODULE, .unlocked_ioctl = twl_chrdev_ioctl, .open = twl_chrdev_open, - .release = NULL + .release = NULL, + .llseek = noop_llseek, }; /* This function passes sense data from firmware to scsi layer */ diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c index 30d735ad35b5..b1125341f4c8 100644 --- a/drivers/scsi/3w-xxxx.c +++ b/drivers/scsi/3w-xxxx.c @@ -199,7 +199,6 @@ #include <linux/module.h> #include <linux/reboot.h> -#include <linux/smp_lock.h> #include <linux/spinlock.h> #include <linux/interrupt.h> #include <linux/moduleparam.h> @@ -221,6 +220,7 @@ /* Globals */ #define TW_DRIVER_VERSION "1.26.02.003" +static DEFINE_MUTEX(tw_mutex); static TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT]; static int tw_device_extension_count = 0; static int twe_major = -1; @@ -900,10 +900,10 @@ static long tw_chrdev_ioctl(struct file *file, unsigned int cmd, unsigned long a dprintk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl()\n"); - lock_kernel(); + mutex_lock(&tw_mutex); /* Only let one of these through at a time */ if (mutex_lock_interruptible(&tw_dev->ioctl_lock)) { - unlock_kernel(); + mutex_unlock(&tw_mutex); return -EINTR; } @@ -1034,7 +1034,7 @@ out2: dma_free_coherent(&tw_dev->tw_pci_dev->dev, data_buffer_length_adjusted+sizeof(TW_New_Ioctl) - 1, cpu_addr, dma_handle); out: mutex_unlock(&tw_dev->ioctl_lock); - unlock_kernel(); + mutex_unlock(&tw_mutex); return retval; } /* End tw_chrdev_ioctl() */ @@ -1044,7 +1044,6 @@ static int tw_chrdev_open(struct inode *inode, struct file *file) { unsigned int minor_number; - cycle_kernel_lock(); dprintk(KERN_WARNING "3w-xxxx: tw_ioctl_open()\n"); minor_number = iminor(inode); @@ -1059,7 +1058,8 @@ static const struct file_operations tw_fops = { .owner = THIS_MODULE, .unlocked_ioctl = tw_chrdev_ioctl, .open = tw_chrdev_open, - .release = NULL + .release = NULL, + .llseek = noop_llseek, }; /* This function will free up device extension resources */ diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index bbf91aec64f5..2e9632e2c98b 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -316,7 +316,8 @@ config SCSI_ISCSI_ATTRS config SCSI_SAS_ATTRS tristate "SAS Transport Attributes" - depends on SCSI && BLK_DEV_BSG + depends on SCSI + select BLK_DEV_BSG help If you wish to export transport-specific information about each attached SAS device to sysfs, say Y. @@ -378,7 +379,7 @@ config ISCSI_BOOT_SYSFS via sysfs to userspace. If you wish to export this information, say Y. Otherwise, say N. -source "drivers/scsi/cxgb3i/Kconfig" +source "drivers/scsi/cxgbi/Kconfig" source "drivers/scsi/bnx2i/Kconfig" source "drivers/scsi/be2iscsi/Kconfig" diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 2703c6ec5e36..2e9a87e8e7d8 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -133,7 +133,8 @@ obj-$(CONFIG_SCSI_HPTIOP) += hptiop.o obj-$(CONFIG_SCSI_STEX) += stex.o obj-$(CONFIG_SCSI_MVSAS) += mvsas/ obj-$(CONFIG_PS3_ROM) += ps3rom.o -obj-$(CONFIG_SCSI_CXGB3_ISCSI) += libiscsi.o libiscsi_tcp.o cxgb3i/ +obj-$(CONFIG_SCSI_CXGB3_ISCSI) += libiscsi.o libiscsi_tcp.o cxgbi/ +obj-$(CONFIG_SCSI_CXGB4_ISCSI) += libiscsi.o libiscsi_tcp.o cxgbi/ obj-$(CONFIG_SCSI_BNX2_ISCSI) += libiscsi.o bnx2i/ obj-$(CONFIG_BE2ISCSI) += libiscsi.o be2iscsi/ obj-$(CONFIG_SCSI_PMCRAID) += pmcraid.o diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c index 1a5bf5724750..645ddd9d9b9e 100644 --- a/drivers/scsi/aacraid/commctrl.c +++ b/drivers/scsi/aacraid/commctrl.c @@ -190,7 +190,7 @@ static int open_getadapter_fib(struct aac_dev * dev, void __user *arg) /* * Initialize the mutex used to wait for the next AIF. */ - init_MUTEX_LOCKED(&fibctx->wait_sem); + sema_init(&fibctx->wait_sem, 0); fibctx->wait = 0; /* * Initialize the fibs and set the count of fibs on diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c index 70079146e203..afc9aeba5edb 100644 --- a/drivers/scsi/aacraid/commsup.c +++ b/drivers/scsi/aacraid/commsup.c @@ -124,7 +124,7 @@ int aac_fib_setup(struct aac_dev * dev) fibptr->hw_fib_va = hw_fib; fibptr->data = (void *) fibptr->hw_fib_va->data; fibptr->next = fibptr+1; /* Forward chain the fibs */ - init_MUTEX_LOCKED(&fibptr->event_wait); + sema_init(&fibptr->event_wait, 0); spin_lock_init(&fibptr->event_lock); hw_fib->header.XferState = cpu_to_le32(0xffffffff); hw_fib->header.SenderSize = cpu_to_le16(dev->max_fib_size); diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index cad6f9abaeb9..dae46d779c7b 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -38,7 +38,7 @@ #include <linux/moduleparam.h> #include <linux/pci.h> #include <linux/slab.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/spinlock.h> #include <linux/syscalls.h> #include <linux/delay.h> @@ -76,6 +76,7 @@ MODULE_DESCRIPTION("Dell PERC2, 2/Si, 3/Si, 3/Di, " MODULE_LICENSE("GPL"); MODULE_VERSION(AAC_DRIVER_FULL_VERSION); +static DEFINE_MUTEX(aac_mutex); static LIST_HEAD(aac_devices); static int aac_cfg_major = -1; char aac_driver_version[] = AAC_DRIVER_FULL_VERSION; @@ -678,7 +679,7 @@ static int aac_cfg_open(struct inode *inode, struct file *file) unsigned minor_number = iminor(inode); int err = -ENODEV; - lock_kernel(); /* BKL pushdown: nothing else protects this list */ + mutex_lock(&aac_mutex); /* BKL pushdown: nothing else protects this list */ list_for_each_entry(aac, &aac_devices, entry) { if (aac->id == minor_number) { file->private_data = aac; @@ -686,7 +687,7 @@ static int aac_cfg_open(struct inode *inode, struct file *file) break; } } - unlock_kernel(); + mutex_unlock(&aac_mutex); return err; } @@ -711,9 +712,9 @@ static long aac_cfg_ioctl(struct file *file, int ret; if (!capable(CAP_SYS_RAWIO)) return -EPERM; - lock_kernel(); + mutex_lock(&aac_mutex); ret = aac_do_ioctl(file->private_data, cmd, (void __user *)arg); - unlock_kernel(); + mutex_unlock(&aac_mutex); return ret; } @@ -722,7 +723,7 @@ static long aac_cfg_ioctl(struct file *file, static long aac_compat_do_ioctl(struct aac_dev *dev, unsigned cmd, unsigned long arg) { long ret; - lock_kernel(); + mutex_lock(&aac_mutex); switch (cmd) { case FSACTL_MINIPORT_REV_CHECK: case FSACTL_SENDFIB: @@ -756,7 +757,7 @@ static long aac_compat_do_ioctl(struct aac_dev *dev, unsigned cmd, unsigned long ret = -ENOIOCTLCMD; break; } - unlock_kernel(); + mutex_unlock(&aac_mutex); return ret; } @@ -1039,6 +1040,7 @@ static const struct file_operations aac_cfg_fops = { .compat_ioctl = aac_compat_cfg_ioctl, #endif .open = aac_cfg_open, + .llseek = noop_llseek, }; static struct scsi_host_template aac_driver_template = { diff --git a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c index 93984c9dfe14..aee73fafccc8 100644 --- a/drivers/scsi/aic7xxx_old.c +++ b/drivers/scsi/aic7xxx_old.c @@ -2850,12 +2850,6 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb) aic_dev->r_total++; ptr = aic_dev->r_bins; } - if(cmd->device->simple_tags && cmd->request->cmd_flags & REQ_HARDBARRIER) - { - aic_dev->barrier_total++; - if(scb->tag_action == MSG_ORDERED_Q_TAG) - aic_dev->ordered_total++; - } x = scb->sg_length; x >>= 10; for(i=0; i<6; i++) @@ -10125,7 +10119,6 @@ static void aic7xxx_buildscb(struct aic7xxx_host *p, struct scsi_cmnd *cmd, struct aic_dev_data *aic_dev = cmd->device->hostdata; struct scsi_device *sdptr = cmd->device; unsigned char tindex = TARGET_INDEX(cmd); - struct request *req = cmd->request; int use_sg; mask = (0x01 << tindex); @@ -10144,19 +10137,8 @@ static void aic7xxx_buildscb(struct aic7xxx_host *p, struct scsi_cmnd *cmd, /* We always force TEST_UNIT_READY to untagged */ if (cmd->cmnd[0] != TEST_UNIT_READY && sdptr->simple_tags) { - if (req->cmd_flags & REQ_HARDBARRIER) - { - if(sdptr->ordered_tags) - { - hscb->control |= MSG_ORDERED_Q_TAG; - scb->tag_action = MSG_ORDERED_Q_TAG; - } - } - else - { - hscb->control |= MSG_SIMPLE_Q_TAG; - scb->tag_action = MSG_SIMPLE_Q_TAG; - } + hscb->control |= MSG_SIMPLE_Q_TAG; + scb->tag_action = MSG_SIMPLE_Q_TAG; } } if ( !(aic_dev->dtr_pending) && diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index c8dc392edd57..05a78e515a24 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -878,8 +878,8 @@ static void arcmsr_report_ccb_state(struct AdapterControlBlock *acb, 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); + ccb->pcmd->result = DID_OK << 16; + arcmsr_ccb_complete(ccb); }else{ switch (ccb->arcmsr_cdb.DeviceStatus) { case ARCMSR_DEV_SELECT_TIMEOUT: { diff --git a/drivers/scsi/be2iscsi/be_cmds.c b/drivers/scsi/be2iscsi/be_cmds.c index 7c7537335c88..ad246369d373 100644 --- a/drivers/scsi/be2iscsi/be_cmds.c +++ b/drivers/scsi/be2iscsi/be_cmds.c @@ -335,7 +335,7 @@ static int be_mbox_db_ready_wait(struct be_ctrl_info *ctrl) if (ready) break; - if (cnt > 6000000) { + if (cnt > 12000000) { dev_err(&ctrl->pdev->dev, "mbox_db poll timed out\n"); return -EBUSY; } diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c index 7f11f3e48e12..eaaa8813067d 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.c +++ b/drivers/scsi/be2iscsi/be_iscsi.c @@ -522,7 +522,6 @@ 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; } @@ -559,7 +558,6 @@ 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); @@ -574,7 +572,6 @@ 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; diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 8220bde6c04c..75a85aa9e882 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -2040,7 +2040,7 @@ hwi_write_sgl(struct iscsi_wrb *pwrb, struct scatterlist *sg, unsigned int num_sg, struct beiscsi_io_task *io_task) { struct iscsi_sge *psgl; - unsigned short sg_len, index; + unsigned int sg_len, index; unsigned int sge_len = 0; unsigned long long addr; struct scatterlist *l_sg; diff --git a/drivers/scsi/bfa/Makefile b/drivers/scsi/bfa/Makefile index ac3fdf02d5f6..d2eefd3e3bd5 100644 --- a/drivers/scsi/bfa/Makefile +++ b/drivers/scsi/bfa/Makefile @@ -1,15 +1,8 @@ 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 -bfa-y += bfa_itnim.o bfa_fcpim.o bfa_tskim.o bfa_log.o bfa_log_module.o -bfa-y += bfa_csdebug.o bfa_sm.o plog.o +bfa-y := bfad.o bfad_im.o bfad_attr.o bfad_debugfs.o +bfa-y += bfa_ioc.o bfa_ioc_cb.o bfa_ioc_ct.o bfa_hw_cb.o bfa_hw_ct.o +bfa-y += bfa_fcs.o bfa_fcs_lport.o bfa_fcs_rport.o bfa_fcs_fcpim.o bfa_fcbuild.o +bfa-y += bfa_port.o bfa_fcpim.o bfa_core.o bfa_drv.o bfa_svc.o -bfa-y += fcbuild.o fabric.o fcpim.o vfapi.o fcptm.o bfa_fcs.o bfa_fcs_port.o -bfa-y += bfa_fcs_uf.o bfa_fcs_lport.o fab.o fdmi.o ms.o ns.o scn.o loop.o -bfa-y += lport_api.o n2n.o rport.o rport_api.o rport_ftrs.o vport.o - -ccflags-y := -I$(obj) -I$(obj)/include -I$(obj)/include/cna -DBFA_PERF_BUILD +ccflags-y := -DBFA_PERF_BUILD diff --git a/drivers/scsi/bfa/bfa.h b/drivers/scsi/bfa/bfa.h new file mode 100644 index 000000000000..ceaac65a91ff --- /dev/null +++ b/drivers/scsi/bfa/bfa.h @@ -0,0 +1,438 @@ +/* + * 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 __BFA_H__ +#define __BFA_H__ + +#include "bfa_os_inc.h" +#include "bfa_cs.h" +#include "bfa_plog.h" +#include "bfa_defs_svc.h" +#include "bfi.h" +#include "bfa_ioc.h" + +struct bfa_s; + +typedef void (*bfa_isr_func_t) (struct bfa_s *bfa, struct bfi_msg_s *m); +typedef void (*bfa_cb_cbfn_t) (void *cbarg, bfa_boolean_t complete); + +/** + * Interrupt message handlers + */ +void bfa_isr_unhandled(struct bfa_s *bfa, struct bfi_msg_s *m); +void bfa_isr_bind(enum bfi_mclass mc, bfa_isr_func_t isr_func); + +/** + * Request and response queue related defines + */ +#define BFA_REQQ_NELEMS_MIN (4) +#define BFA_RSPQ_NELEMS_MIN (4) + +#define bfa_reqq_pi(__bfa, __reqq) ((__bfa)->iocfc.req_cq_pi[__reqq]) +#define bfa_reqq_ci(__bfa, __reqq) \ + (*(u32 *)((__bfa)->iocfc.req_cq_shadow_ci[__reqq].kva)) + +#define bfa_reqq_full(__bfa, __reqq) \ + (((bfa_reqq_pi(__bfa, __reqq) + 1) & \ + ((__bfa)->iocfc.cfg.drvcfg.num_reqq_elems - 1)) == \ + bfa_reqq_ci(__bfa, __reqq)) + +#define bfa_reqq_next(__bfa, __reqq) \ + (bfa_reqq_full(__bfa, __reqq) ? NULL : \ + ((void *)((struct bfi_msg_s *)((__bfa)->iocfc.req_cq_ba[__reqq].kva) \ + + bfa_reqq_pi((__bfa), (__reqq))))) + +#define bfa_reqq_produce(__bfa, __reqq) do { \ + (__bfa)->iocfc.req_cq_pi[__reqq]++; \ + (__bfa)->iocfc.req_cq_pi[__reqq] &= \ + ((__bfa)->iocfc.cfg.drvcfg.num_reqq_elems - 1); \ + bfa_reg_write((__bfa)->iocfc.bfa_regs.cpe_q_pi[__reqq], \ + (__bfa)->iocfc.req_cq_pi[__reqq]); \ + mmiowb(); \ + } while (0) + +#define bfa_rspq_pi(__bfa, __rspq) \ + (*(u32 *)((__bfa)->iocfc.rsp_cq_shadow_pi[__rspq].kva)) + +#define bfa_rspq_ci(__bfa, __rspq) ((__bfa)->iocfc.rsp_cq_ci[__rspq]) +#define bfa_rspq_elem(__bfa, __rspq, __ci) \ + (&((struct bfi_msg_s *)((__bfa)->iocfc.rsp_cq_ba[__rspq].kva))[__ci]) + +#define CQ_INCR(__index, __size) do { \ + (__index)++; \ + (__index) &= ((__size) - 1); \ +} while (0) + +/** + * Queue element to wait for room in request queue. FIFO order is + * maintained when fullfilling requests. + */ +struct bfa_reqq_wait_s { + struct list_head qe; + void (*qresume) (void *cbarg); + void *cbarg; +}; + +/** + * Circular queue usage assignments + */ +enum { + BFA_REQQ_IOC = 0, /* all low-priority IOC msgs */ + BFA_REQQ_FCXP = 0, /* all FCXP messages */ + BFA_REQQ_LPS = 0, /* all lport service msgs */ + BFA_REQQ_PORT = 0, /* all port messages */ + BFA_REQQ_FLASH = 0, /* for flash module */ + BFA_REQQ_DIAG = 0, /* for diag module */ + BFA_REQQ_RPORT = 0, /* all port messages */ + BFA_REQQ_SBOOT = 0, /* all san boot messages */ + BFA_REQQ_QOS_LO = 1, /* all low priority IO */ + BFA_REQQ_QOS_MD = 2, /* all medium priority IO */ + BFA_REQQ_QOS_HI = 3, /* all high priority IO */ +}; + +static inline void +bfa_reqq_winit(struct bfa_reqq_wait_s *wqe, void (*qresume) (void *cbarg), + void *cbarg) +{ + wqe->qresume = qresume; + wqe->cbarg = cbarg; +} + +#define bfa_reqq(__bfa, __reqq) (&(__bfa)->reqq_waitq[__reqq]) + +/** + * static inline void + * bfa_reqq_wait(struct bfa_s *bfa, int reqq, struct bfa_reqq_wait_s *wqe) + */ +#define bfa_reqq_wait(__bfa, __reqq, __wqe) do { \ + \ + struct list_head *waitq = bfa_reqq(__bfa, __reqq); \ + \ + bfa_assert(((__reqq) < BFI_IOC_MAX_CQS)); \ + bfa_assert((__wqe)->qresume && (__wqe)->cbarg); \ + \ + list_add_tail(&(__wqe)->qe, waitq); \ + } while (0) + +#define bfa_reqq_wcancel(__wqe) list_del(&(__wqe)->qe) + + +/** + * Generic BFA callback element. + */ +struct bfa_cb_qe_s { + struct list_head qe; + bfa_cb_cbfn_t cbfn; + bfa_boolean_t once; + u32 rsvd; + void *cbarg; +}; + +#define bfa_cb_queue(__bfa, __hcb_qe, __cbfn, __cbarg) do { \ + (__hcb_qe)->cbfn = (__cbfn); \ + (__hcb_qe)->cbarg = (__cbarg); \ + list_add_tail(&(__hcb_qe)->qe, &(__bfa)->comp_q); \ + } while (0) + +#define bfa_cb_dequeue(__hcb_qe) list_del(&(__hcb_qe)->qe) + +#define bfa_cb_queue_once(__bfa, __hcb_qe, __cbfn, __cbarg) do { \ + (__hcb_qe)->cbfn = (__cbfn); \ + (__hcb_qe)->cbarg = (__cbarg); \ + if (!(__hcb_qe)->once) { \ + list_add_tail(&(__hcb_qe)->qe, &(__bfa)->comp_q); \ + (__hcb_qe)->once = BFA_TRUE; \ + } \ + } while (0) + +#define bfa_cb_queue_done(__hcb_qe) do { \ + (__hcb_qe)->once = BFA_FALSE; \ + } while (0) + + +/** + * PCI devices supported by the current BFA + */ +struct bfa_pciid_s { + u16 device_id; + u16 vendor_id; +}; + +extern char bfa_version[]; + +/** + * BFA memory resources + */ +enum bfa_mem_type { + BFA_MEM_TYPE_KVA = 1, /* Kernel Virtual Memory *(non-dma-able) */ + BFA_MEM_TYPE_DMA = 2, /* DMA-able memory */ + BFA_MEM_TYPE_MAX = BFA_MEM_TYPE_DMA, +}; + +struct bfa_mem_elem_s { + enum bfa_mem_type mem_type; /* see enum bfa_mem_type */ + u32 mem_len; /* Total Length in Bytes */ + u8 *kva; /* kernel virtual address */ + u64 dma; /* dma address if DMA memory */ + u8 *kva_curp; /* kva allocation cursor */ + u64 dma_curp; /* dma allocation cursor */ +}; + +struct bfa_meminfo_s { + struct bfa_mem_elem_s meminfo[BFA_MEM_TYPE_MAX]; +}; +#define bfa_meminfo_kva(_m) \ + ((_m)->meminfo[BFA_MEM_TYPE_KVA - 1].kva_curp) +#define bfa_meminfo_dma_virt(_m) \ + ((_m)->meminfo[BFA_MEM_TYPE_DMA - 1].kva_curp) +#define bfa_meminfo_dma_phys(_m) \ + ((_m)->meminfo[BFA_MEM_TYPE_DMA - 1].dma_curp) + +struct bfa_iocfc_regs_s { + bfa_os_addr_t intr_status; + bfa_os_addr_t intr_mask; + bfa_os_addr_t cpe_q_pi[BFI_IOC_MAX_CQS]; + bfa_os_addr_t cpe_q_ci[BFI_IOC_MAX_CQS]; + bfa_os_addr_t cpe_q_depth[BFI_IOC_MAX_CQS]; + bfa_os_addr_t cpe_q_ctrl[BFI_IOC_MAX_CQS]; + bfa_os_addr_t rme_q_ci[BFI_IOC_MAX_CQS]; + bfa_os_addr_t rme_q_pi[BFI_IOC_MAX_CQS]; + bfa_os_addr_t rme_q_depth[BFI_IOC_MAX_CQS]; + bfa_os_addr_t rme_q_ctrl[BFI_IOC_MAX_CQS]; +}; + +/** + * MSIX vector handlers + */ +#define BFA_MSIX_MAX_VECTORS 22 +typedef void (*bfa_msix_handler_t)(struct bfa_s *bfa, int vec); +struct bfa_msix_s { + int nvecs; + bfa_msix_handler_t handler[BFA_MSIX_MAX_VECTORS]; +}; + +/** + * Chip specific interfaces + */ +struct bfa_hwif_s { + void (*hw_reginit)(struct bfa_s *bfa); + void (*hw_reqq_ack)(struct bfa_s *bfa, int reqq); + void (*hw_rspq_ack)(struct bfa_s *bfa, int rspq); + void (*hw_msix_init)(struct bfa_s *bfa, int nvecs); + void (*hw_msix_install)(struct bfa_s *bfa); + void (*hw_msix_uninstall)(struct bfa_s *bfa); + void (*hw_isr_mode_set)(struct bfa_s *bfa, bfa_boolean_t msix); + void (*hw_msix_getvecs)(struct bfa_s *bfa, u32 *vecmap, + u32 *nvecs, u32 *maxvec); + 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); + +struct bfa_iocfc_s { + struct bfa_s *bfa; + struct bfa_iocfc_cfg_s cfg; + int action; + u32 req_cq_pi[BFI_IOC_MAX_CQS]; + u32 rsp_cq_ci[BFI_IOC_MAX_CQS]; + struct bfa_cb_qe_s init_hcb_qe; + struct bfa_cb_qe_s stop_hcb_qe; + struct bfa_cb_qe_s dis_hcb_qe; + struct bfa_cb_qe_s stats_hcb_qe; + bfa_boolean_t cfgdone; + + struct bfa_dma_s cfg_info; + struct bfi_iocfc_cfg_s *cfginfo; + struct bfa_dma_s cfgrsp_dma; + struct bfi_iocfc_cfgrsp_s *cfgrsp; + struct bfi_iocfc_cfg_reply_s *cfg_reply; + struct bfa_dma_s req_cq_ba[BFI_IOC_MAX_CQS]; + struct bfa_dma_s req_cq_shadow_ci[BFI_IOC_MAX_CQS]; + struct bfa_dma_s rsp_cq_ba[BFI_IOC_MAX_CQS]; + struct bfa_dma_s rsp_cq_shadow_pi[BFI_IOC_MAX_CQS]; + struct bfa_iocfc_regs_s bfa_regs; /* BFA device registers */ + struct bfa_hwif_s hwif; + bfa_cb_iocfc_t updateq_cbfn; /* bios callback function */ + void *updateq_cbarg; /* bios callback arg */ + u32 intr_mask; +}; + +#define bfa_lpuid(__bfa) \ + bfa_ioc_portid(&(__bfa)->ioc) +#define bfa_msix_init(__bfa, __nvecs) \ + ((__bfa)->iocfc.hwif.hw_msix_init(__bfa, __nvecs)) +#define bfa_msix_install(__bfa) \ + ((__bfa)->iocfc.hwif.hw_msix_install(__bfa)) +#define bfa_msix_uninstall(__bfa) \ + ((__bfa)->iocfc.hwif.hw_msix_uninstall(__bfa)) +#define bfa_isr_mode_set(__bfa, __msix) \ + ((__bfa)->iocfc.hwif.hw_isr_mode_set(__bfa, __msix)) +#define bfa_msix_getvecs(__bfa, __vecmap, __nvecs, __maxvec) \ + ((__bfa)->iocfc.hwif.hw_msix_getvecs(__bfa, __vecmap, \ + __nvecs, __maxvec)) +#define bfa_msix_get_rme_range(__bfa, __start, __end) \ + ((__bfa)->iocfc.hwif.hw_msix_get_rme_range(__bfa, __start, __end)) +#define bfa_msix(__bfa, __vec) \ + ((__bfa)->msix.handler[__vec](__bfa, __vec)) + +/* + * FC specific IOC functions. + */ +void bfa_iocfc_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len, + u32 *dm_len); +void bfa_iocfc_attach(struct bfa_s *bfa, void *bfad, + struct bfa_iocfc_cfg_s *cfg, + struct bfa_meminfo_s *meminfo, + struct bfa_pcidev_s *pcidev); +void bfa_iocfc_detach(struct bfa_s *bfa); +void bfa_iocfc_init(struct bfa_s *bfa); +void bfa_iocfc_start(struct bfa_s *bfa); +void bfa_iocfc_stop(struct bfa_s *bfa); +void bfa_iocfc_isr(void *bfa, struct bfi_mbmsg_s *msg); +void bfa_iocfc_set_snsbase(struct bfa_s *bfa, u64 snsbase_pa); +bfa_boolean_t bfa_iocfc_is_operational(struct bfa_s *bfa); +void bfa_iocfc_reset_queues(struct bfa_s *bfa); + +void bfa_msix_all(struct bfa_s *bfa, int vec); +void bfa_msix_reqq(struct bfa_s *bfa, int vec); +void bfa_msix_rspq(struct bfa_s *bfa, int vec); +void bfa_msix_lpu_err(struct bfa_s *bfa, int vec); + +void bfa_hwcb_reginit(struct bfa_s *bfa); +void bfa_hwcb_reqq_ack(struct bfa_s *bfa, int rspq); +void bfa_hwcb_rspq_ack(struct bfa_s *bfa, int rspq); +void bfa_hwcb_msix_init(struct bfa_s *bfa, int nvecs); +void bfa_hwcb_msix_install(struct bfa_s *bfa); +void bfa_hwcb_msix_uninstall(struct bfa_s *bfa); +void bfa_hwcb_isr_mode_set(struct bfa_s *bfa, bfa_boolean_t msix); +void bfa_hwcb_msix_getvecs(struct bfa_s *bfa, u32 *vecmap, u32 *nvecs, + u32 *maxvec); +void bfa_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); +void bfa_hwct_msix_init(struct bfa_s *bfa, int nvecs); +void bfa_hwct_msix_install(struct bfa_s *bfa); +void bfa_hwct_msix_uninstall(struct bfa_s *bfa); +void bfa_hwct_isr_mode_set(struct bfa_s *bfa, bfa_boolean_t msix); +void bfa_hwct_msix_getvecs(struct bfa_s *bfa, u32 *vecmap, u32 *nvecs, + u32 *maxvec); +void bfa_hwct_msix_get_rme_range(struct bfa_s *bfa, u32 *start, + u32 *end); +void bfa_com_port_attach(struct bfa_s *bfa, struct bfa_meminfo_s *mi); +void bfa_iocfc_get_bootwwns(struct bfa_s *bfa, u8 *nwwns, wwn_t *wwns); +wwn_t bfa_iocfc_get_pwwn(struct bfa_s *bfa); +wwn_t bfa_iocfc_get_nwwn(struct bfa_s *bfa); +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); + + +/** + *---------------------------------------------------------------------- + * BFA public interfaces + *---------------------------------------------------------------------- + */ +#define bfa_stats(_mod, _stats) ((_mod)->stats._stats++) +#define bfa_ioc_get_stats(__bfa, __ioc_stats) \ + bfa_ioc_fetch_stats(&(__bfa)->ioc, __ioc_stats) +#define bfa_ioc_clear_stats(__bfa) \ + bfa_ioc_clr_stats(&(__bfa)->ioc) +#define bfa_get_nports(__bfa) \ + bfa_ioc_get_nports(&(__bfa)->ioc) +#define bfa_get_adapter_manufacturer(__bfa, __manufacturer) \ + bfa_ioc_get_adapter_manufacturer(&(__bfa)->ioc, __manufacturer) +#define bfa_get_adapter_model(__bfa, __model) \ + bfa_ioc_get_adapter_model(&(__bfa)->ioc, __model) +#define bfa_get_adapter_serial_num(__bfa, __serial_num) \ + bfa_ioc_get_adapter_serial_num(&(__bfa)->ioc, __serial_num) +#define bfa_get_adapter_fw_ver(__bfa, __fw_ver) \ + bfa_ioc_get_adapter_fw_ver(&(__bfa)->ioc, __fw_ver) +#define bfa_get_adapter_optrom_ver(__bfa, __optrom_ver) \ + bfa_ioc_get_adapter_optrom_ver(&(__bfa)->ioc, __optrom_ver) +#define bfa_get_pci_chip_rev(__bfa, __chip_rev) \ + bfa_ioc_get_pci_chip_rev(&(__bfa)->ioc, __chip_rev) +#define bfa_get_ioc_state(__bfa) \ + bfa_ioc_get_state(&(__bfa)->ioc) +#define bfa_get_type(__bfa) \ + 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) + +void bfa_get_pciids(struct bfa_pciid_s **pciids, int *npciids); +void bfa_cfg_get_default(struct bfa_iocfc_cfg_s *cfg); +void bfa_cfg_get_min(struct bfa_iocfc_cfg_s *cfg); +void bfa_cfg_get_meminfo(struct bfa_iocfc_cfg_s *cfg, + struct bfa_meminfo_s *meminfo); +void bfa_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, + struct bfa_meminfo_s *meminfo, + struct bfa_pcidev_s *pcidev); +void bfa_init_trc(struct bfa_s *bfa, struct bfa_trc_mod_s *trcmod); +void bfa_init_plog(struct bfa_s *bfa, struct bfa_plog_s *plog); +void bfa_detach(struct bfa_s *bfa); +void bfa_init(struct bfa_s *bfa); +void bfa_start(struct bfa_s *bfa); +void bfa_stop(struct bfa_s *bfa); +void bfa_attach_fcs(struct bfa_s *bfa); +void bfa_cb_init(void *bfad, bfa_status_t status); +void bfa_cb_updateq(void *bfad, bfa_status_t status); + +bfa_boolean_t bfa_intx(struct bfa_s *bfa); +void bfa_intx_disable(struct bfa_s *bfa); +void bfa_intx_enable(struct bfa_s *bfa); +void bfa_isr_enable(struct bfa_s *bfa); +void bfa_isr_disable(struct bfa_s *bfa); + +void bfa_comp_deq(struct bfa_s *bfa, struct list_head *comp_q); +void bfa_comp_process(struct bfa_s *bfa, struct list_head *comp_q); +void bfa_comp_free(struct bfa_s *bfa, struct list_head *comp_q); + +typedef void (*bfa_cb_ioc_t) (void *cbarg, enum bfa_status status); +void bfa_iocfc_get_attr(struct bfa_s *bfa, struct bfa_iocfc_attr_s *attr); +void bfa_get_attr(struct bfa_s *bfa, struct bfa_ioc_attr_s *ioc_attr); + +void bfa_adapter_get_attr(struct bfa_s *bfa, + struct bfa_adapter_attr_s *ad_attr); +u64 bfa_adapter_get_id(struct bfa_s *bfa); + +bfa_status_t bfa_iocfc_israttr_set(struct bfa_s *bfa, + struct bfa_iocfc_intr_attr_s *attr); + +void bfa_iocfc_enable(struct bfa_s *bfa); +void bfa_iocfc_disable(struct bfa_s *bfa); +void bfa_chip_reset(struct bfa_s *bfa); +void bfa_timer_tick(struct bfa_s *bfa); +#define bfa_timer_start(_bfa, _timer, _timercb, _arg, _timeout) \ + bfa_timer_begin(&(_bfa)->timer_mod, _timer, _timercb, _arg, _timeout) + +/* + * BFA debug API functions + */ +bfa_status_t bfa_debug_fwtrc(struct bfa_s *bfa, void *trcdata, int *trclen); +bfa_status_t bfa_debug_fwsave(struct bfa_s *bfa, void *trcdata, int *trclen); +bfa_status_t bfa_debug_fwcore(struct bfa_s *bfa, void *buf, + u32 *offset, int *buflen); +void bfa_debug_fwsave_clear(struct bfa_s *bfa); +bfa_status_t bfa_fw_stats_get(struct bfa_s *bfa, void *data); +bfa_status_t bfa_fw_stats_clear(struct bfa_s *bfa); + +#endif /* __BFA_H__ */ diff --git a/drivers/scsi/bfa/bfa_callback_priv.h b/drivers/scsi/bfa/bfa_callback_priv.h deleted file mode 100644 index 1e3265c9f7d4..000000000000 --- a/drivers/scsi/bfa/bfa_callback_priv.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFA_CALLBACK_PRIV_H__ -#define __BFA_CALLBACK_PRIV_H__ - -#include <cs/bfa_q.h> - -typedef void (*bfa_cb_cbfn_t) (void *cbarg, bfa_boolean_t complete); - -/** - * Generic BFA callback element. - */ -struct bfa_cb_qe_s { - struct list_head qe; - bfa_cb_cbfn_t cbfn; - bfa_boolean_t once; - u32 rsvd; - void *cbarg; -}; - -#define bfa_cb_queue(__bfa, __hcb_qe, __cbfn, __cbarg) do { \ - (__hcb_qe)->cbfn = (__cbfn); \ - (__hcb_qe)->cbarg = (__cbarg); \ - list_add_tail(&(__hcb_qe)->qe, &(__bfa)->comp_q); \ -} while (0) - -#define bfa_cb_dequeue(__hcb_qe) list_del(&(__hcb_qe)->qe) - -#define bfa_cb_queue_once(__bfa, __hcb_qe, __cbfn, __cbarg) do { \ - (__hcb_qe)->cbfn = (__cbfn); \ - (__hcb_qe)->cbarg = (__cbarg); \ - if (!(__hcb_qe)->once) { \ - list_add_tail((__hcb_qe), &(__bfa)->comp_q); \ - (__hcb_qe)->once = BFA_TRUE; \ - } \ -} while (0) - -#define bfa_cb_queue_done(__hcb_qe) do { \ - (__hcb_qe)->once = BFA_FALSE; \ -} while (0) - -#endif /* __BFA_CALLBACK_PRIV_H__ */ diff --git a/drivers/scsi/bfa/bfa_cb_ioim_macros.h b/drivers/scsi/bfa/bfa_cb_ioim.h index 3906ed926966..a989a94c38da 100644 --- a/drivers/scsi/bfa/bfa_cb_ioim_macros.h +++ b/drivers/scsi/bfa/bfa_cb_ioim.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. * All rights reserved * www.brocade.com * @@ -15,37 +15,25 @@ * General Public License for more details. */ -/** - * bfa_cb_ioim_macros.h BFA IOIM driver interface macros. - */ - -#ifndef __BFA_HCB_IOIM_MACROS_H__ -#define __BFA_HCB_IOIM_MACROS_H__ - -#include <bfa_os_inc.h> -/* - * #include <linux/dma-mapping.h> - * - * #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> #include - * <scsi/scsi_device.h> #include <scsi/scsi_host.h> - */ -#include "bfad_im_compat.h" +#ifndef __BFA_HCB_IOIM_H__ +#define __BFA_HCB_IOIM_H__ +#include "bfa_os_inc.h" /* * task attribute values in FCP-2 FCP_CMND IU */ #define SIMPLE_Q 0 #define HEAD_OF_Q 1 #define ORDERED_Q 2 -#define ACA_Q 4 +#define ACA_Q 4 #define UNTAGGED 5 static inline lun_t bfad_int_to_lun(u32 luno) { union { - u16 scsi_lun[4]; - lun_t bfa_lun; + u16 scsi_lun[4]; + lun_t bfa_lun; } lun; lun.bfa_lun = 0; @@ -141,7 +129,7 @@ static inline u8 bfa_cb_ioim_get_taskattr(struct bfad_ioim_s *dio) { struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio; - u8 task_attr = UNTAGGED; + u8 task_attr = UNTAGGED; if (cmnd->device->tagged_supported) { switch (cmnd->tag) { @@ -178,4 +166,4 @@ bfa_cb_ioim_get_cdblen(struct bfad_ioim_s *dio) */ #define bfa_cb_ioim_get_reqq(__dio) BFA_FALSE -#endif /* __BFA_HCB_IOIM_MACROS_H__ */ +#endif /* __BFA_HCB_IOIM_H__ */ diff --git a/drivers/scsi/bfa/bfa_cee.c b/drivers/scsi/bfa/bfa_cee.c deleted file mode 100644 index 2b917792c6bc..000000000000 --- a/drivers/scsi/bfa/bfa_cee.c +++ /dev/null @@ -1,492 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#include <defs/bfa_defs_cee.h> -#include <cs/bfa_trc.h> -#include <cs/bfa_log.h> -#include <cs/bfa_debug.h> -#include <cee/bfa_cee.h> -#include <bfi/bfi_cee.h> -#include <bfi/bfi.h> -#include <bfa_ioc.h> -#include <cna/bfa_cna_trcmod.h> - -BFA_TRC_FILE(CNA, CEE); - -#define bfa_ioc_portid(__ioc) ((__ioc)->port_id) -#define bfa_lpuid(__arg) bfa_ioc_portid(&(__arg)->ioc) - -static void bfa_cee_format_lldp_cfg(struct bfa_cee_lldp_cfg_s *lldp_cfg); -static void bfa_cee_format_dcbcx_stats(struct bfa_cee_dcbx_stats_s - *dcbcx_stats); -static void bfa_cee_format_lldp_stats(struct bfa_cee_lldp_stats_s - *lldp_stats); -static void bfa_cee_format_cfg_stats(struct bfa_cee_cfg_stats_s *cfg_stats); -static void bfa_cee_format_cee_cfg(void *buffer); -static void bfa_cee_format_cee_stats(void *buffer); - -static void -bfa_cee_format_cee_stats(void *buffer) -{ - struct bfa_cee_stats_s *cee_stats = buffer; - bfa_cee_format_dcbcx_stats(&cee_stats->dcbx_stats); - bfa_cee_format_lldp_stats(&cee_stats->lldp_stats); - bfa_cee_format_cfg_stats(&cee_stats->cfg_stats); -} - -static void -bfa_cee_format_cee_cfg(void *buffer) -{ - struct bfa_cee_attr_s *cee_cfg = buffer; - bfa_cee_format_lldp_cfg(&cee_cfg->lldp_remote); -} - -static void -bfa_cee_format_dcbcx_stats(struct bfa_cee_dcbx_stats_s *dcbcx_stats) -{ - dcbcx_stats->subtlvs_unrecognized = - bfa_os_ntohl(dcbcx_stats->subtlvs_unrecognized); - dcbcx_stats->negotiation_failed = - bfa_os_ntohl(dcbcx_stats->negotiation_failed); - dcbcx_stats->remote_cfg_changed = - bfa_os_ntohl(dcbcx_stats->remote_cfg_changed); - dcbcx_stats->tlvs_received = bfa_os_ntohl(dcbcx_stats->tlvs_received); - dcbcx_stats->tlvs_invalid = bfa_os_ntohl(dcbcx_stats->tlvs_invalid); - dcbcx_stats->seqno = bfa_os_ntohl(dcbcx_stats->seqno); - dcbcx_stats->ackno = bfa_os_ntohl(dcbcx_stats->ackno); - dcbcx_stats->recvd_seqno = bfa_os_ntohl(dcbcx_stats->recvd_seqno); - dcbcx_stats->recvd_ackno = bfa_os_ntohl(dcbcx_stats->recvd_ackno); -} - -static void -bfa_cee_format_lldp_stats(struct bfa_cee_lldp_stats_s *lldp_stats) -{ - lldp_stats->frames_transmitted = - bfa_os_ntohl(lldp_stats->frames_transmitted); - lldp_stats->frames_aged_out = bfa_os_ntohl(lldp_stats->frames_aged_out); - lldp_stats->frames_discarded = - bfa_os_ntohl(lldp_stats->frames_discarded); - lldp_stats->frames_in_error = bfa_os_ntohl(lldp_stats->frames_in_error); - lldp_stats->frames_rcvd = bfa_os_ntohl(lldp_stats->frames_rcvd); - lldp_stats->tlvs_discarded = bfa_os_ntohl(lldp_stats->tlvs_discarded); - lldp_stats->tlvs_unrecognized = - bfa_os_ntohl(lldp_stats->tlvs_unrecognized); -} - -static void -bfa_cee_format_cfg_stats(struct bfa_cee_cfg_stats_s *cfg_stats) -{ - cfg_stats->cee_status_down = bfa_os_ntohl(cfg_stats->cee_status_down); - cfg_stats->cee_status_up = bfa_os_ntohl(cfg_stats->cee_status_up); - cfg_stats->cee_hw_cfg_changed = - bfa_os_ntohl(cfg_stats->cee_hw_cfg_changed); - cfg_stats->recvd_invalid_cfg = - bfa_os_ntohl(cfg_stats->recvd_invalid_cfg); -} - -static void -bfa_cee_format_lldp_cfg(struct bfa_cee_lldp_cfg_s *lldp_cfg) -{ - lldp_cfg->time_to_interval = bfa_os_ntohs(lldp_cfg->time_to_interval); - lldp_cfg->enabled_system_cap = - bfa_os_ntohs(lldp_cfg->enabled_system_cap); -} - -/** - * bfa_cee_attr_meminfo() - * - * - * @param[in] void - * - * @return Size of DMA region - */ -static u32 -bfa_cee_attr_meminfo(void) -{ - return BFA_ROUNDUP(sizeof(struct bfa_cee_attr_s), BFA_DMA_ALIGN_SZ); -} - -/** - * bfa_cee_stats_meminfo() - * - * - * @param[in] void - * - * @return Size of DMA region - */ -static u32 -bfa_cee_stats_meminfo(void) -{ - return BFA_ROUNDUP(sizeof(struct bfa_cee_stats_s), BFA_DMA_ALIGN_SZ); -} - -/** - * bfa_cee_get_attr_isr() - * - * - * @param[in] cee - Pointer to the CEE module - * status - Return status from the f/w - * - * @return void - */ -static void -bfa_cee_get_attr_isr(struct bfa_cee_s *cee, bfa_status_t status) -{ - cee->get_attr_status = status; - bfa_trc(cee, 0); - if (status == BFA_STATUS_OK) { - bfa_trc(cee, 0); - /* - * The requested data has been copied to the DMA area, *process - * it. - */ - memcpy(cee->attr, cee->attr_dma.kva, - sizeof(struct bfa_cee_attr_s)); - bfa_cee_format_cee_cfg(cee->attr); - } - cee->get_attr_pending = BFA_FALSE; - if (cee->cbfn.get_attr_cbfn) { - bfa_trc(cee, 0); - cee->cbfn.get_attr_cbfn(cee->cbfn.get_attr_cbarg, status); - } - bfa_trc(cee, 0); -} - -/** - * bfa_cee_get_attr_isr() - * - * - * @param[in] cee - Pointer to the CEE module - * status - Return status from the f/w - * - * @return void - */ -static void -bfa_cee_get_stats_isr(struct bfa_cee_s *cee, bfa_status_t status) -{ - cee->get_stats_status = status; - bfa_trc(cee, 0); - if (status == BFA_STATUS_OK) { - bfa_trc(cee, 0); - /* - * The requested data has been copied to the DMA area, process - * it. - */ - memcpy(cee->stats, cee->stats_dma.kva, - sizeof(struct bfa_cee_stats_s)); - bfa_cee_format_cee_stats(cee->stats); - } - cee->get_stats_pending = BFA_FALSE; - bfa_trc(cee, 0); - if (cee->cbfn.get_stats_cbfn) { - bfa_trc(cee, 0); - cee->cbfn.get_stats_cbfn(cee->cbfn.get_stats_cbarg, status); - } - bfa_trc(cee, 0); -} - -/** - * bfa_cee_get_attr_isr() - * - * - * @param[in] cee - Pointer to the CEE module - * status - Return status from the f/w - * - * @return void - */ -static void -bfa_cee_reset_stats_isr(struct bfa_cee_s *cee, bfa_status_t status) -{ - cee->reset_stats_status = status; - cee->reset_stats_pending = BFA_FALSE; - if (cee->cbfn.reset_stats_cbfn) - cee->cbfn.reset_stats_cbfn(cee->cbfn.reset_stats_cbarg, status); -} - -/** - * bfa_cee_meminfo() - * - * - * @param[in] void - * - * @return Size of DMA region - */ -u32 -bfa_cee_meminfo(void) -{ - return bfa_cee_attr_meminfo() + bfa_cee_stats_meminfo(); -} - -/** - * bfa_cee_mem_claim() - * - * - * @param[in] cee CEE module pointer - * dma_kva Kernel Virtual Address of CEE DMA Memory - * dma_pa Physical Address of CEE DMA Memory - * - * @return void - */ -void -bfa_cee_mem_claim(struct bfa_cee_s *cee, u8 *dma_kva, u64 dma_pa) -{ - cee->attr_dma.kva = dma_kva; - cee->attr_dma.pa = dma_pa; - cee->stats_dma.kva = dma_kva + bfa_cee_attr_meminfo(); - cee->stats_dma.pa = dma_pa + bfa_cee_attr_meminfo(); - cee->attr = (struct bfa_cee_attr_s *)dma_kva; - cee->stats = - (struct bfa_cee_stats_s *)(dma_kva + bfa_cee_attr_meminfo()); -} - -/** - * bfa_cee_get_attr() - * - * Send the request to the f/w to fetch CEE attributes. - * - * @param[in] Pointer to the CEE module data structure. - * - * @return Status - */ - -bfa_status_t -bfa_cee_get_attr(struct bfa_cee_s *cee, struct bfa_cee_attr_s *attr, - bfa_cee_get_attr_cbfn_t cbfn, void *cbarg) -{ - struct bfi_cee_get_req_s *cmd; - - bfa_assert((cee != NULL) && (cee->ioc != NULL)); - bfa_trc(cee, 0); - if (!bfa_ioc_is_operational(cee->ioc)) { - bfa_trc(cee, 0); - return BFA_STATUS_IOC_FAILURE; - } - if (cee->get_attr_pending == BFA_TRUE) { - bfa_trc(cee, 0); - return BFA_STATUS_DEVBUSY; - } - cee->get_attr_pending = BFA_TRUE; - cmd = (struct bfi_cee_get_req_s *)cee->get_cfg_mb.msg; - cee->attr = attr; - cee->cbfn.get_attr_cbfn = cbfn; - cee->cbfn.get_attr_cbarg = cbarg; - bfi_h2i_set(cmd->mh, BFI_MC_CEE, BFI_CEE_H2I_GET_CFG_REQ, - bfa_ioc_portid(cee->ioc)); - bfa_dma_be_addr_set(cmd->dma_addr, cee->attr_dma.pa); - bfa_ioc_mbox_queue(cee->ioc, &cee->get_cfg_mb); - bfa_trc(cee, 0); - - return BFA_STATUS_OK; -} - -/** - * bfa_cee_get_stats() - * - * Send the request to the f/w to fetch CEE statistics. - * - * @param[in] Pointer to the CEE module data structure. - * - * @return Status - */ - -bfa_status_t -bfa_cee_get_stats(struct bfa_cee_s *cee, struct bfa_cee_stats_s *stats, - bfa_cee_get_stats_cbfn_t cbfn, void *cbarg) -{ - struct bfi_cee_get_req_s *cmd; - - bfa_assert((cee != NULL) && (cee->ioc != NULL)); - - if (!bfa_ioc_is_operational(cee->ioc)) { - bfa_trc(cee, 0); - return BFA_STATUS_IOC_FAILURE; - } - if (cee->get_stats_pending == BFA_TRUE) { - bfa_trc(cee, 0); - return BFA_STATUS_DEVBUSY; - } - cee->get_stats_pending = BFA_TRUE; - cmd = (struct bfi_cee_get_req_s *)cee->get_stats_mb.msg; - cee->stats = stats; - cee->cbfn.get_stats_cbfn = cbfn; - cee->cbfn.get_stats_cbarg = cbarg; - bfi_h2i_set(cmd->mh, BFI_MC_CEE, BFI_CEE_H2I_GET_STATS_REQ, - bfa_ioc_portid(cee->ioc)); - bfa_dma_be_addr_set(cmd->dma_addr, cee->stats_dma.pa); - bfa_ioc_mbox_queue(cee->ioc, &cee->get_stats_mb); - bfa_trc(cee, 0); - - return BFA_STATUS_OK; -} - -/** - * bfa_cee_reset_stats() - * - * - * @param[in] Pointer to the CEE module data structure. - * - * @return Status - */ - -bfa_status_t -bfa_cee_reset_stats(struct bfa_cee_s *cee, bfa_cee_reset_stats_cbfn_t cbfn, - void *cbarg) -{ - struct bfi_cee_reset_stats_s *cmd; - - bfa_assert((cee != NULL) && (cee->ioc != NULL)); - if (!bfa_ioc_is_operational(cee->ioc)) { - bfa_trc(cee, 0); - return BFA_STATUS_IOC_FAILURE; - } - if (cee->reset_stats_pending == BFA_TRUE) { - bfa_trc(cee, 0); - return BFA_STATUS_DEVBUSY; - } - cee->reset_stats_pending = BFA_TRUE; - cmd = (struct bfi_cee_reset_stats_s *)cee->reset_stats_mb.msg; - cee->cbfn.reset_stats_cbfn = cbfn; - cee->cbfn.reset_stats_cbarg = cbarg; - bfi_h2i_set(cmd->mh, BFI_MC_CEE, BFI_CEE_H2I_RESET_STATS, - bfa_ioc_portid(cee->ioc)); - bfa_ioc_mbox_queue(cee->ioc, &cee->reset_stats_mb); - bfa_trc(cee, 0); - return BFA_STATUS_OK; -} - -/** - * bfa_cee_isrs() - * - * - * @param[in] Pointer to the CEE module data structure. - * - * @return void - */ - -void -bfa_cee_isr(void *cbarg, struct bfi_mbmsg_s *m) -{ - union bfi_cee_i2h_msg_u *msg; - struct bfi_cee_get_rsp_s *get_rsp; - struct bfa_cee_s *cee = (struct bfa_cee_s *)cbarg; - msg = (union bfi_cee_i2h_msg_u *)m; - get_rsp = (struct bfi_cee_get_rsp_s *)m; - bfa_trc(cee, msg->mh.msg_id); - switch (msg->mh.msg_id) { - case BFI_CEE_I2H_GET_CFG_RSP: - bfa_trc(cee, get_rsp->cmd_status); - bfa_cee_get_attr_isr(cee, get_rsp->cmd_status); - break; - case BFI_CEE_I2H_GET_STATS_RSP: - bfa_cee_get_stats_isr(cee, get_rsp->cmd_status); - break; - case BFI_CEE_I2H_RESET_STATS_RSP: - bfa_cee_reset_stats_isr(cee, get_rsp->cmd_status); - break; - default: - bfa_assert(0); - } -} - -/** - * bfa_cee_hbfail() - * - * - * @param[in] Pointer to the CEE module data structure. - * - * @return void - */ - -void -bfa_cee_hbfail(void *arg) -{ - struct bfa_cee_s *cee; - cee = (struct bfa_cee_s *)arg; - - if (cee->get_attr_pending == BFA_TRUE) { - cee->get_attr_status = BFA_STATUS_FAILED; - cee->get_attr_pending = BFA_FALSE; - if (cee->cbfn.get_attr_cbfn) { - cee->cbfn.get_attr_cbfn(cee->cbfn.get_attr_cbarg, - BFA_STATUS_FAILED); - } - } - if (cee->get_stats_pending == BFA_TRUE) { - cee->get_stats_status = BFA_STATUS_FAILED; - cee->get_stats_pending = BFA_FALSE; - if (cee->cbfn.get_stats_cbfn) { - cee->cbfn.get_stats_cbfn(cee->cbfn.get_stats_cbarg, - BFA_STATUS_FAILED); - } - } - if (cee->reset_stats_pending == BFA_TRUE) { - cee->reset_stats_status = BFA_STATUS_FAILED; - cee->reset_stats_pending = BFA_FALSE; - if (cee->cbfn.reset_stats_cbfn) { - cee->cbfn.reset_stats_cbfn(cee->cbfn.reset_stats_cbarg, - BFA_STATUS_FAILED); - } - } -} - -/** - * bfa_cee_attach() - * - * - * @param[in] cee - Pointer to the CEE module data structure - * ioc - Pointer to the ioc module data structure - * dev - Pointer to the device driver module data structure - * The device driver specific mbox ISR functions have - * this pointer as one of the parameters. - * trcmod - - * logmod - - * - * @return void - */ -void -bfa_cee_attach(struct bfa_cee_s *cee, struct bfa_ioc_s *ioc, void *dev, - struct bfa_trc_mod_s *trcmod, struct bfa_log_mod_s *logmod) -{ - bfa_assert(cee != NULL); - cee->dev = dev; - cee->trcmod = trcmod; - cee->logmod = logmod; - cee->ioc = ioc; - - bfa_ioc_mbox_regisr(cee->ioc, BFI_MC_CEE, bfa_cee_isr, cee); - bfa_ioc_hbfail_init(&cee->hbfail, bfa_cee_hbfail, cee); - bfa_ioc_hbfail_register(cee->ioc, &cee->hbfail); - bfa_trc(cee, 0); -} - -/** - * bfa_cee_detach() - * - * - * @param[in] cee - Pointer to the CEE module data structure - * - * @return void - */ -void -bfa_cee_detach(struct bfa_cee_s *cee) -{ - /* - * For now, just check if there is some ioctl pending and mark that as - * failed? - */ - /* bfa_cee_hbfail(cee); */ -} diff --git a/drivers/scsi/bfa/bfa_core.c b/drivers/scsi/bfa/bfa_core.c index 76fa5c5b40dd..c2fa07f2485d 100644 --- a/drivers/scsi/bfa/bfa_core.c +++ b/drivers/scsi/bfa/bfa_core.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. * All rights reserved * www.brocade.com * @@ -15,27 +15,992 @@ * General Public License for more details. */ -#include <bfa.h> -#include <defs/bfa_defs_pci.h> -#include <cs/bfa_debug.h> -#include <bfa_iocfc.h> +#include "bfa_modules.h" +#include "bfi_ctreg.h" +#include "bfad_drv.h" -#define DEF_CFG_NUM_FABRICS 1 -#define DEF_CFG_NUM_LPORTS 256 -#define DEF_CFG_NUM_CQS 4 -#define DEF_CFG_NUM_IOIM_REQS (BFA_IOIM_MAX) -#define DEF_CFG_NUM_TSKIM_REQS 128 -#define DEF_CFG_NUM_FCXP_REQS 64 -#define DEF_CFG_NUM_UF_BUFS 64 -#define DEF_CFG_NUM_RPORTS 1024 -#define DEF_CFG_NUM_ITNIMS (DEF_CFG_NUM_RPORTS) -#define DEF_CFG_NUM_TINS 256 +BFA_TRC_FILE(HAL, CORE); -#define DEF_CFG_NUM_SGPGS 2048 -#define DEF_CFG_NUM_REQQ_ELEMS 256 -#define DEF_CFG_NUM_RSPQ_ELEMS 64 -#define DEF_CFG_NUM_SBOOT_TGTS 16 -#define DEF_CFG_NUM_SBOOT_LUNS 16 +/** + * BFA IOC FC related definitions + */ + +/** + * IOC local definitions + */ +#define BFA_IOCFC_TOV 5000 /* msecs */ + +enum { + BFA_IOCFC_ACT_NONE = 0, + BFA_IOCFC_ACT_INIT = 1, + BFA_IOCFC_ACT_STOP = 2, + BFA_IOCFC_ACT_DISABLE = 3, +}; + +#define DEF_CFG_NUM_FABRICS 1 +#define DEF_CFG_NUM_LPORTS 256 +#define DEF_CFG_NUM_CQS 4 +#define DEF_CFG_NUM_IOIM_REQS (BFA_IOIM_MAX) +#define DEF_CFG_NUM_TSKIM_REQS 128 +#define DEF_CFG_NUM_FCXP_REQS 64 +#define DEF_CFG_NUM_UF_BUFS 64 +#define DEF_CFG_NUM_RPORTS 1024 +#define DEF_CFG_NUM_ITNIMS (DEF_CFG_NUM_RPORTS) +#define DEF_CFG_NUM_TINS 256 + +#define DEF_CFG_NUM_SGPGS 2048 +#define DEF_CFG_NUM_REQQ_ELEMS 256 +#define DEF_CFG_NUM_RSPQ_ELEMS 64 +#define DEF_CFG_NUM_SBOOT_TGTS 16 +#define DEF_CFG_NUM_SBOOT_LUNS 16 + +/** + * forward declaration for IOC FC functions + */ +static void bfa_iocfc_enable_cbfn(void *bfa_arg, enum bfa_status status); +static void bfa_iocfc_disable_cbfn(void *bfa_arg); +static void bfa_iocfc_hbfail_cbfn(void *bfa_arg); +static void bfa_iocfc_reset_cbfn(void *bfa_arg); +static struct bfa_ioc_cbfn_s bfa_iocfc_cbfn; + +/** + * BFA Interrupt handling functions + */ +static void +bfa_msix_errint(struct bfa_s *bfa, u32 intr) +{ + bfa_ioc_error_isr(&bfa->ioc); +} + +static void +bfa_msix_lpu(struct bfa_s *bfa) +{ + bfa_ioc_mbox_isr(&bfa->ioc); +} + +static void +bfa_reqq_resume(struct bfa_s *bfa, int qid) +{ + struct list_head *waitq, *qe, *qen; + struct bfa_reqq_wait_s *wqe; + + waitq = bfa_reqq(bfa, qid); + list_for_each_safe(qe, qen, waitq) { + /** + * Callback only as long as there is room in request queue + */ + if (bfa_reqq_full(bfa, qid)) + break; + + list_del(qe); + wqe = (struct bfa_reqq_wait_s *) qe; + wqe->qresume(wqe->cbarg); + } +} + +void +bfa_msix_all(struct bfa_s *bfa, int vec) +{ + bfa_intx(bfa); +} + +/** + * hal_intr_api + */ +bfa_boolean_t +bfa_intx(struct bfa_s *bfa) +{ + u32 intr, qintr; + int queue; + + intr = bfa_reg_read(bfa->iocfc.bfa_regs.intr_status); + if (!intr) + return BFA_FALSE; + + /** + * RME completion queue interrupt + */ + qintr = intr & __HFN_INT_RME_MASK; + bfa_reg_write(bfa->iocfc.bfa_regs.intr_status, qintr); + + for (queue = 0; queue < BFI_IOC_MAX_CQS_ASIC; queue++) { + if (intr & (__HFN_INT_RME_Q0 << queue)) + bfa_msix_rspq(bfa, queue & (BFI_IOC_MAX_CQS - 1)); + } + intr &= ~qintr; + if (!intr) + return BFA_TRUE; + + /** + * CPE completion queue interrupt + */ + qintr = intr & __HFN_INT_CPE_MASK; + bfa_reg_write(bfa->iocfc.bfa_regs.intr_status, qintr); + + for (queue = 0; queue < BFI_IOC_MAX_CQS_ASIC; queue++) { + if (intr & (__HFN_INT_CPE_Q0 << queue)) + bfa_msix_reqq(bfa, queue & (BFI_IOC_MAX_CQS - 1)); + } + intr &= ~qintr; + if (!intr) + return BFA_TRUE; + + bfa_msix_lpu_err(bfa, intr); + + return BFA_TRUE; +} + +void +bfa_intx_enable(struct bfa_s *bfa) +{ + bfa_reg_write(bfa->iocfc.bfa_regs.intr_mask, bfa->iocfc.intr_mask); +} + +void +bfa_intx_disable(struct bfa_s *bfa) +{ + bfa_reg_write(bfa->iocfc.bfa_regs.intr_mask, -1L); +} + +void +bfa_isr_enable(struct bfa_s *bfa) +{ + u32 intr_unmask; + int pci_func = bfa_ioc_pcifn(&bfa->ioc); + + bfa_trc(bfa, pci_func); + + bfa_msix_install(bfa); + intr_unmask = (__HFN_INT_ERR_EMC | __HFN_INT_ERR_LPU0 | + __HFN_INT_ERR_LPU1 | __HFN_INT_ERR_PSS | + __HFN_INT_LL_HALT); + + if (pci_func == 0) + intr_unmask |= (__HFN_INT_CPE_Q0 | __HFN_INT_CPE_Q1 | + __HFN_INT_CPE_Q2 | __HFN_INT_CPE_Q3 | + __HFN_INT_RME_Q0 | __HFN_INT_RME_Q1 | + __HFN_INT_RME_Q2 | __HFN_INT_RME_Q3 | + __HFN_INT_MBOX_LPU0); + else + intr_unmask |= (__HFN_INT_CPE_Q4 | __HFN_INT_CPE_Q5 | + __HFN_INT_CPE_Q6 | __HFN_INT_CPE_Q7 | + __HFN_INT_RME_Q4 | __HFN_INT_RME_Q5 | + __HFN_INT_RME_Q6 | __HFN_INT_RME_Q7 | + __HFN_INT_MBOX_LPU1); + + bfa_reg_write(bfa->iocfc.bfa_regs.intr_status, intr_unmask); + bfa_reg_write(bfa->iocfc.bfa_regs.intr_mask, ~intr_unmask); + bfa->iocfc.intr_mask = ~intr_unmask; + bfa_isr_mode_set(bfa, bfa->msix.nvecs != 0); +} + +void +bfa_isr_disable(struct bfa_s *bfa) +{ + bfa_isr_mode_set(bfa, BFA_FALSE); + bfa_reg_write(bfa->iocfc.bfa_regs.intr_mask, -1L); + bfa_msix_uninstall(bfa); +} + +void +bfa_msix_reqq(struct bfa_s *bfa, int qid) +{ + struct list_head *waitq; + + qid &= (BFI_IOC_MAX_CQS - 1); + + bfa->iocfc.hwif.hw_reqq_ack(bfa, qid); + + /** + * Resume any pending requests in the corresponding reqq. + */ + waitq = bfa_reqq(bfa, qid); + if (!list_empty(waitq)) + bfa_reqq_resume(bfa, qid); +} + +void +bfa_isr_unhandled(struct bfa_s *bfa, struct bfi_msg_s *m) +{ + bfa_trc(bfa, m->mhdr.msg_class); + bfa_trc(bfa, m->mhdr.msg_id); + bfa_trc(bfa, m->mhdr.mtag.i2htok); + bfa_assert(0); + bfa_trc_stop(bfa->trcmod); +} + +void +bfa_msix_rspq(struct bfa_s *bfa, int qid) +{ + struct bfi_msg_s *m; + u32 pi, ci; + struct list_head *waitq; + + bfa_trc_fp(bfa, qid); + + qid &= (BFI_IOC_MAX_CQS - 1); + + bfa->iocfc.hwif.hw_rspq_ack(bfa, qid); + + ci = bfa_rspq_ci(bfa, qid); + pi = bfa_rspq_pi(bfa, qid); + + bfa_trc_fp(bfa, ci); + bfa_trc_fp(bfa, pi); + + if (bfa->rme_process) { + while (ci != pi) { + m = bfa_rspq_elem(bfa, qid, ci); + bfa_assert_fp(m->mhdr.msg_class < BFI_MC_MAX); + + bfa_isrs[m->mhdr.msg_class] (bfa, m); + + CQ_INCR(ci, bfa->iocfc.cfg.drvcfg.num_rspq_elems); + } + } + + /** + * update CI + */ + bfa_rspq_ci(bfa, qid) = pi; + bfa_reg_write(bfa->iocfc.bfa_regs.rme_q_ci[qid], pi); + mmiowb(); + + /** + * Resume any pending requests in the corresponding reqq. + */ + waitq = bfa_reqq(bfa, qid); + if (!list_empty(waitq)) + bfa_reqq_resume(bfa, qid); +} + +void +bfa_msix_lpu_err(struct bfa_s *bfa, int vec) +{ + u32 intr, curr_value; + + intr = bfa_reg_read(bfa->iocfc.bfa_regs.intr_status); + + if (intr & (__HFN_INT_MBOX_LPU0 | __HFN_INT_MBOX_LPU1)) + bfa_msix_lpu(bfa); + + intr &= (__HFN_INT_ERR_EMC | __HFN_INT_ERR_LPU0 | + __HFN_INT_ERR_LPU1 | __HFN_INT_ERR_PSS | __HFN_INT_LL_HALT); + + if (intr) { + if (intr & __HFN_INT_LL_HALT) { + /** + * If LL_HALT bit is set then FW Init Halt LL Port + * Register needs to be cleared as well so Interrupt + * Status Register will be cleared. + */ + curr_value = bfa_reg_read(bfa->ioc.ioc_regs.ll_halt); + curr_value &= ~__FW_INIT_HALT_P; + bfa_reg_write(bfa->ioc.ioc_regs.ll_halt, curr_value); + } + + if (intr & __HFN_INT_ERR_PSS) { + /** + * ERR_PSS bit needs to be cleared as well in case + * interrups are shared so driver's interrupt handler is + * still called eventhough it is already masked out. + */ + curr_value = bfa_reg_read( + bfa->ioc.ioc_regs.pss_err_status_reg); + curr_value &= __PSS_ERR_STATUS_SET; + bfa_reg_write(bfa->ioc.ioc_regs.pss_err_status_reg, + curr_value); + } + + bfa_reg_write(bfa->iocfc.bfa_regs.intr_status, intr); + bfa_msix_errint(bfa, intr); + } +} + +void +bfa_isr_bind(enum bfi_mclass mc, bfa_isr_func_t isr_func) +{ + bfa_isrs[mc] = isr_func; +} + +/** + * BFA IOC FC related functions + */ + +/** + * hal_ioc_pvt BFA IOC private functions + */ + +static void +bfa_iocfc_cqs_sz(struct bfa_iocfc_cfg_s *cfg, u32 *dm_len) +{ + int i, per_reqq_sz, per_rspq_sz; + + per_reqq_sz = BFA_ROUNDUP((cfg->drvcfg.num_reqq_elems * BFI_LMSG_SZ), + BFA_DMA_ALIGN_SZ); + per_rspq_sz = BFA_ROUNDUP((cfg->drvcfg.num_rspq_elems * BFI_LMSG_SZ), + BFA_DMA_ALIGN_SZ); + + /* + * Calculate CQ size + */ + for (i = 0; i < cfg->fwcfg.num_cqs; i++) { + *dm_len = *dm_len + per_reqq_sz; + *dm_len = *dm_len + per_rspq_sz; + } + + /* + * Calculate Shadow CI/PI size + */ + for (i = 0; i < cfg->fwcfg.num_cqs; i++) + *dm_len += (2 * BFA_CACHELINE_SZ); +} + +static void +bfa_iocfc_fw_cfg_sz(struct bfa_iocfc_cfg_s *cfg, u32 *dm_len) +{ + *dm_len += + BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfg_s), BFA_CACHELINE_SZ); + *dm_len += + BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfgrsp_s), + BFA_CACHELINE_SZ); +} + +/** + * Use the Mailbox interface to send BFI_IOCFC_H2I_CFG_REQ + */ +static void +bfa_iocfc_send_cfg(void *bfa_arg) +{ + struct bfa_s *bfa = bfa_arg; + struct bfa_iocfc_s *iocfc = &bfa->iocfc; + struct bfi_iocfc_cfg_req_s cfg_req; + struct bfi_iocfc_cfg_s *cfg_info = iocfc->cfginfo; + struct bfa_iocfc_cfg_s *cfg = &iocfc->cfg; + int i; + + bfa_assert(cfg->fwcfg.num_cqs <= BFI_IOC_MAX_CQS); + bfa_trc(bfa, cfg->fwcfg.num_cqs); + + bfa_iocfc_reset_queues(bfa); + + /** + * initialize IOC configuration info + */ + cfg_info->endian_sig = BFI_IOC_ENDIAN_SIG; + cfg_info->num_cqs = cfg->fwcfg.num_cqs; + + bfa_dma_be_addr_set(cfg_info->cfgrsp_addr, iocfc->cfgrsp_dma.pa); + /** + * dma map REQ and RSP circular queues and shadow pointers + */ + for (i = 0; i < cfg->fwcfg.num_cqs; i++) { + bfa_dma_be_addr_set(cfg_info->req_cq_ba[i], + iocfc->req_cq_ba[i].pa); + bfa_dma_be_addr_set(cfg_info->req_shadow_ci[i], + iocfc->req_cq_shadow_ci[i].pa); + cfg_info->req_cq_elems[i] = + bfa_os_htons(cfg->drvcfg.num_reqq_elems); + + bfa_dma_be_addr_set(cfg_info->rsp_cq_ba[i], + iocfc->rsp_cq_ba[i].pa); + bfa_dma_be_addr_set(cfg_info->rsp_shadow_pi[i], + iocfc->rsp_cq_shadow_pi[i].pa); + cfg_info->rsp_cq_elems[i] = + bfa_os_htons(cfg->drvcfg.num_rspq_elems); + } + + /** + * 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 + */ + bfi_h2i_set(cfg_req.mh, BFI_MC_IOCFC, BFI_IOCFC_H2I_CFG_REQ, + bfa_lpuid(bfa)); + bfa_dma_be_addr_set(cfg_req.ioc_cfg_dma_addr, iocfc->cfg_info.pa); + + bfa_ioc_mbox_send(&bfa->ioc, &cfg_req, + sizeof(struct bfi_iocfc_cfg_req_s)); +} + +static void +bfa_iocfc_init_mem(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, + struct bfa_pcidev_s *pcidev) +{ + struct bfa_iocfc_s *iocfc = &bfa->iocfc; + + bfa->bfad = bfad; + iocfc->bfa = bfa; + iocfc->action = BFA_IOCFC_ACT_NONE; + + bfa_os_assign(iocfc->cfg, *cfg); + + /** + * Initialize chip specific handlers. + */ + if (bfa_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; + iocfc->hwif.hw_msix_init = bfa_hwct_msix_init; + iocfc->hwif.hw_msix_install = bfa_hwct_msix_install; + iocfc->hwif.hw_msix_uninstall = bfa_hwct_msix_uninstall; + iocfc->hwif.hw_isr_mode_set = bfa_hwct_isr_mode_set; + iocfc->hwif.hw_msix_getvecs = bfa_hwct_msix_getvecs; + 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; + iocfc->hwif.hw_rspq_ack = bfa_hwcb_rspq_ack; + iocfc->hwif.hw_msix_init = bfa_hwcb_msix_init; + iocfc->hwif.hw_msix_install = bfa_hwcb_msix_install; + iocfc->hwif.hw_msix_uninstall = bfa_hwcb_msix_uninstall; + iocfc->hwif.hw_isr_mode_set = bfa_hwcb_isr_mode_set; + iocfc->hwif.hw_msix_getvecs = bfa_hwcb_msix_getvecs; + iocfc->hwif.hw_msix_get_rme_range = bfa_hwcb_msix_get_rme_range; + } + + iocfc->hwif.hw_reginit(bfa); + bfa->msix.nvecs = 0; +} + +static void +bfa_iocfc_mem_claim(struct bfa_s *bfa, struct bfa_iocfc_cfg_s *cfg, + struct bfa_meminfo_s *meminfo) +{ + u8 *dm_kva; + u64 dm_pa; + int i, per_reqq_sz, per_rspq_sz; + struct bfa_iocfc_s *iocfc = &bfa->iocfc; + int dbgsz; + + dm_kva = bfa_meminfo_dma_virt(meminfo); + dm_pa = bfa_meminfo_dma_phys(meminfo); + + /* + * First allocate dma memory for IOC. + */ + bfa_ioc_mem_claim(&bfa->ioc, dm_kva, dm_pa); + dm_kva += bfa_ioc_meminfo(); + dm_pa += bfa_ioc_meminfo(); + + /* + * Claim DMA-able memory for the request/response queues and for shadow + * ci/pi registers + */ + per_reqq_sz = BFA_ROUNDUP((cfg->drvcfg.num_reqq_elems * BFI_LMSG_SZ), + BFA_DMA_ALIGN_SZ); + per_rspq_sz = BFA_ROUNDUP((cfg->drvcfg.num_rspq_elems * BFI_LMSG_SZ), + BFA_DMA_ALIGN_SZ); + + for (i = 0; i < cfg->fwcfg.num_cqs; i++) { + iocfc->req_cq_ba[i].kva = dm_kva; + iocfc->req_cq_ba[i].pa = dm_pa; + bfa_os_memset(dm_kva, 0, per_reqq_sz); + dm_kva += per_reqq_sz; + dm_pa += per_reqq_sz; + + iocfc->rsp_cq_ba[i].kva = dm_kva; + iocfc->rsp_cq_ba[i].pa = dm_pa; + bfa_os_memset(dm_kva, 0, per_rspq_sz); + dm_kva += per_rspq_sz; + dm_pa += per_rspq_sz; + } + + for (i = 0; i < cfg->fwcfg.num_cqs; i++) { + iocfc->req_cq_shadow_ci[i].kva = dm_kva; + iocfc->req_cq_shadow_ci[i].pa = dm_pa; + dm_kva += BFA_CACHELINE_SZ; + dm_pa += BFA_CACHELINE_SZ; + + iocfc->rsp_cq_shadow_pi[i].kva = dm_kva; + iocfc->rsp_cq_shadow_pi[i].pa = dm_pa; + dm_kva += BFA_CACHELINE_SZ; + dm_pa += BFA_CACHELINE_SZ; + } + + /* + * Claim DMA-able memory for the config info page + */ + bfa->iocfc.cfg_info.kva = dm_kva; + bfa->iocfc.cfg_info.pa = dm_pa; + bfa->iocfc.cfginfo = (struct bfi_iocfc_cfg_s *) dm_kva; + dm_kva += BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfg_s), BFA_CACHELINE_SZ); + dm_pa += BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfg_s), BFA_CACHELINE_SZ); + + /* + * Claim DMA-able memory for the config response + */ + bfa->iocfc.cfgrsp_dma.kva = dm_kva; + bfa->iocfc.cfgrsp_dma.pa = dm_pa; + bfa->iocfc.cfgrsp = (struct bfi_iocfc_cfgrsp_s *) dm_kva; + + dm_kva += + BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfgrsp_s), + BFA_CACHELINE_SZ); + dm_pa += BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfgrsp_s), + BFA_CACHELINE_SZ); + + + bfa_meminfo_dma_virt(meminfo) = dm_kva; + bfa_meminfo_dma_phys(meminfo) = dm_pa; + + dbgsz = bfa_ioc_debug_trcsz(bfa_auto_recover); + if (dbgsz > 0) { + bfa_ioc_debug_memclaim(&bfa->ioc, bfa_meminfo_kva(meminfo)); + bfa_meminfo_kva(meminfo) += dbgsz; + } +} + +/** + * Start BFA submodules. + */ +static void +bfa_iocfc_start_submod(struct bfa_s *bfa) +{ + int i; + + bfa->rme_process = BFA_TRUE; + + for (i = 0; hal_mods[i]; i++) + hal_mods[i]->start(bfa); +} + +/** + * Disable BFA submodules. + */ +static void +bfa_iocfc_disable_submod(struct bfa_s *bfa) +{ + int i; + + for (i = 0; hal_mods[i]; i++) + hal_mods[i]->iocdisable(bfa); +} + +static void +bfa_iocfc_init_cb(void *bfa_arg, bfa_boolean_t complete) +{ + struct bfa_s *bfa = bfa_arg; + + if (complete) { + if (bfa->iocfc.cfgdone) + bfa_cb_init(bfa->bfad, BFA_STATUS_OK); + else + bfa_cb_init(bfa->bfad, BFA_STATUS_FAILED); + } else { + if (bfa->iocfc.cfgdone) + bfa->iocfc.action = BFA_IOCFC_ACT_NONE; + } +} + +static void +bfa_iocfc_stop_cb(void *bfa_arg, bfa_boolean_t compl) +{ + struct bfa_s *bfa = bfa_arg; + struct bfad_s *bfad = bfa->bfad; + + if (compl) + complete(&bfad->comp); + else + bfa->iocfc.action = BFA_IOCFC_ACT_NONE; +} + +static void +bfa_iocfc_disable_cb(void *bfa_arg, bfa_boolean_t compl) +{ + struct bfa_s *bfa = bfa_arg; + struct bfad_s *bfad = bfa->bfad; + + if (compl) + complete(&bfad->disable_comp); +} + +/** + * Update BFA configuration from firmware configuration. + */ +static void +bfa_iocfc_cfgrsp(struct bfa_s *bfa) +{ + struct bfa_iocfc_s *iocfc = &bfa->iocfc; + struct bfi_iocfc_cfgrsp_s *cfgrsp = iocfc->cfgrsp; + struct bfa_iocfc_fwcfg_s *fwcfg = &cfgrsp->fwcfg; + + fwcfg->num_cqs = fwcfg->num_cqs; + fwcfg->num_ioim_reqs = bfa_os_ntohs(fwcfg->num_ioim_reqs); + fwcfg->num_tskim_reqs = bfa_os_ntohs(fwcfg->num_tskim_reqs); + fwcfg->num_fcxp_reqs = bfa_os_ntohs(fwcfg->num_fcxp_reqs); + fwcfg->num_uf_bufs = bfa_os_ntohs(fwcfg->num_uf_bufs); + fwcfg->num_rports = bfa_os_ntohs(fwcfg->num_rports); + + iocfc->cfgdone = BFA_TRUE; + + /** + * 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 + bfa_iocfc_start_submod(bfa); +} +void +bfa_iocfc_reset_queues(struct bfa_s *bfa) +{ + int q; + + for (q = 0; q < BFI_IOC_MAX_CQS; q++) { + bfa_reqq_ci(bfa, q) = 0; + bfa_reqq_pi(bfa, q) = 0; + bfa_rspq_ci(bfa, q) = 0; + bfa_rspq_pi(bfa, q) = 0; + } +} + +/** + * IOC enable request is complete + */ +static void +bfa_iocfc_enable_cbfn(void *bfa_arg, enum bfa_status status) +{ + struct bfa_s *bfa = bfa_arg; + + if (status != BFA_STATUS_OK) { + bfa_isr_disable(bfa); + if (bfa->iocfc.action == BFA_IOCFC_ACT_INIT) + bfa_cb_queue(bfa, &bfa->iocfc.init_hcb_qe, + bfa_iocfc_init_cb, bfa); + return; + } + + bfa_iocfc_send_cfg(bfa); +} + +/** + * IOC disable request is complete + */ +static void +bfa_iocfc_disable_cbfn(void *bfa_arg) +{ + struct bfa_s *bfa = bfa_arg; + + bfa_isr_disable(bfa); + bfa_iocfc_disable_submod(bfa); + + if (bfa->iocfc.action == BFA_IOCFC_ACT_STOP) + bfa_cb_queue(bfa, &bfa->iocfc.stop_hcb_qe, bfa_iocfc_stop_cb, + bfa); + else { + bfa_assert(bfa->iocfc.action == BFA_IOCFC_ACT_DISABLE); + bfa_cb_queue(bfa, &bfa->iocfc.dis_hcb_qe, bfa_iocfc_disable_cb, + bfa); + } +} + +/** + * Notify sub-modules of hardware failure. + */ +static void +bfa_iocfc_hbfail_cbfn(void *bfa_arg) +{ + struct bfa_s *bfa = bfa_arg; + + bfa->rme_process = BFA_FALSE; + + bfa_isr_disable(bfa); + bfa_iocfc_disable_submod(bfa); + + if (bfa->iocfc.action == BFA_IOCFC_ACT_INIT) + bfa_cb_queue(bfa, &bfa->iocfc.init_hcb_qe, bfa_iocfc_init_cb, + bfa); +} + +/** + * Actions on chip-reset completion. + */ +static void +bfa_iocfc_reset_cbfn(void *bfa_arg) +{ + struct bfa_s *bfa = bfa_arg; + + bfa_iocfc_reset_queues(bfa); + bfa_isr_enable(bfa); +} + +/** + * hal_ioc_public + */ + +/** + * Query IOC memory requirement information. + */ +void +bfa_iocfc_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len, + u32 *dm_len) +{ + /* dma memory for IOC */ + *dm_len += bfa_ioc_meminfo(); + + bfa_iocfc_fw_cfg_sz(cfg, dm_len); + bfa_iocfc_cqs_sz(cfg, dm_len); + *km_len += bfa_ioc_debug_trcsz(bfa_auto_recover); +} + +/** + * Query IOC memory requirement information. + */ +void +bfa_iocfc_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, + struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev) +{ + int i; + struct bfa_ioc_s *ioc = &bfa->ioc; + + bfa_iocfc_cbfn.enable_cbfn = bfa_iocfc_enable_cbfn; + bfa_iocfc_cbfn.disable_cbfn = bfa_iocfc_disable_cbfn; + bfa_iocfc_cbfn.hbfail_cbfn = bfa_iocfc_hbfail_cbfn; + bfa_iocfc_cbfn.reset_cbfn = bfa_iocfc_reset_cbfn; + + ioc->trcmod = bfa->trcmod; + bfa_ioc_attach(&bfa->ioc, bfa, &bfa_iocfc_cbfn, &bfa->timer_mod); + + /** + * Set FC mode for BFA_PCI_DEVICE_ID_CT_FC. + */ + 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); + bfa_ioc_mbox_register(&bfa->ioc, bfa_mbox_isrs); + + bfa_iocfc_init_mem(bfa, bfad, cfg, pcidev); + bfa_iocfc_mem_claim(bfa, cfg, meminfo); + bfa_timer_init(&bfa->timer_mod); + + INIT_LIST_HEAD(&bfa->comp_q); + for (i = 0; i < BFI_IOC_MAX_CQS; i++) + INIT_LIST_HEAD(&bfa->reqq_waitq[i]); +} + +/** + * Query IOC memory requirement information. + */ +void +bfa_iocfc_detach(struct bfa_s *bfa) +{ + bfa_ioc_detach(&bfa->ioc); +} + +/** + * Query IOC memory requirement information. + */ +void +bfa_iocfc_init(struct bfa_s *bfa) +{ + bfa->iocfc.action = BFA_IOCFC_ACT_INIT; + bfa_ioc_enable(&bfa->ioc); +} + +/** + * IOC start called from bfa_start(). Called to start IOC operations + * at driver instantiation for this instance. + */ +void +bfa_iocfc_start(struct bfa_s *bfa) +{ + if (bfa->iocfc.cfgdone) + bfa_iocfc_start_submod(bfa); +} + +/** + * IOC stop called from bfa_stop(). Called only when driver is unloaded + * for this instance. + */ +void +bfa_iocfc_stop(struct bfa_s *bfa) +{ + bfa->iocfc.action = BFA_IOCFC_ACT_STOP; + + bfa->rme_process = BFA_FALSE; + bfa_ioc_disable(&bfa->ioc); +} + +void +bfa_iocfc_isr(void *bfaarg, struct bfi_mbmsg_s *m) +{ + struct bfa_s *bfa = bfaarg; + struct bfa_iocfc_s *iocfc = &bfa->iocfc; + union bfi_iocfc_i2h_msg_u *msg; + + msg = (union bfi_iocfc_i2h_msg_u *) m; + bfa_trc(bfa, msg->mh.msg_id); + + switch (msg->mh.msg_id) { + case BFI_IOCFC_I2H_CFG_REPLY: + iocfc->cfg_reply = &msg->cfg_reply; + bfa_iocfc_cfgrsp(bfa); + break; + case BFI_IOCFC_I2H_UPDATEQ_RSP: + iocfc->updateq_cbfn(iocfc->updateq_cbarg, BFA_STATUS_OK); + break; + default: + bfa_assert(0); + } +} + +void +bfa_adapter_get_attr(struct bfa_s *bfa, struct bfa_adapter_attr_s *ad_attr) +{ + bfa_ioc_get_adapter_attr(&bfa->ioc, ad_attr); +} + +u64 +bfa_adapter_get_id(struct bfa_s *bfa) +{ + return bfa_ioc_get_adid(&bfa->ioc); +} + +void +bfa_iocfc_get_attr(struct bfa_s *bfa, struct bfa_iocfc_attr_s *attr) +{ + struct bfa_iocfc_s *iocfc = &bfa->iocfc; + + attr->intr_attr.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; +} + +bfa_status_t +bfa_iocfc_israttr_set(struct bfa_s *bfa, struct bfa_iocfc_intr_attr_s *attr) +{ + struct bfa_iocfc_s *iocfc = &bfa->iocfc; + struct bfi_iocfc_set_intr_req_s *m; + + iocfc->cfginfo->intr_attr.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; + + m = bfa_reqq_next(bfa, BFA_REQQ_IOC); + if (!m) + return BFA_STATUS_DEVBUSY; + + bfi_h2i_set(m->mh, BFI_MC_IOCFC, BFI_IOCFC_H2I_SET_INTR_REQ, + bfa_lpuid(bfa)); + m->coalesce = 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); + + bfa_reqq_produce(bfa, BFA_REQQ_IOC); + return BFA_STATUS_OK; +} + +void +bfa_iocfc_set_snsbase(struct bfa_s *bfa, u64 snsbase_pa) +{ + struct bfa_iocfc_s *iocfc = &bfa->iocfc; + + iocfc->cfginfo->sense_buf_len = (BFI_IOIM_SNSLEN - 1); + bfa_dma_be_addr_set(iocfc->cfginfo->ioim_snsbase, snsbase_pa); +} +/** + * Enable IOC after it is disabled. + */ +void +bfa_iocfc_enable(struct bfa_s *bfa) +{ + bfa_plog_str(bfa->plog, BFA_PL_MID_HAL, BFA_PL_EID_MISC, 0, + "IOC Enable"); + bfa_ioc_enable(&bfa->ioc); +} + +void +bfa_iocfc_disable(struct bfa_s *bfa) +{ + bfa_plog_str(bfa->plog, BFA_PL_MID_HAL, BFA_PL_EID_MISC, 0, + "IOC Disable"); + bfa->iocfc.action = BFA_IOCFC_ACT_DISABLE; + + bfa->rme_process = BFA_FALSE; + bfa_ioc_disable(&bfa->ioc); +} + + +bfa_boolean_t +bfa_iocfc_is_operational(struct bfa_s *bfa) +{ + return bfa_ioc_is_operational(&bfa->ioc) && bfa->iocfc.cfgdone; +} + +/** + * Return boot target port wwns -- read from boot information in flash. + */ +void +bfa_iocfc_get_bootwwns(struct bfa_s *bfa, u8 *nwwns, wwn_t *wwns) +{ + struct bfa_iocfc_s *iocfc = &bfa->iocfc; + struct bfi_iocfc_cfgrsp_s *cfgrsp = iocfc->cfgrsp; + 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; + memcpy(wwns, cfgrsp->bootwwns.wwn, sizeof(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)); +} + +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; +} + +/** + * hal_api + */ /** * Use this function query the memory requirement of the BFA library. @@ -45,16 +1010,16 @@ * This call will fail, if the cap is out of range compared to pre-defined * values within the BFA library * - * @param[in] cfg - pointer to bfa_ioc_cfg_t. Driver layer should indicate - * its configuration in this structure. + * @param[in] cfg - pointer to bfa_ioc_cfg_t. Driver layer should indicate + * its configuration in this structure. * The default values for struct bfa_iocfc_cfg_s can be * fetched using bfa_cfg_get_default() API. * - * If cap's boundary check fails, the library will use + * If cap's boundary check fails, the library will use * the default bfa_cap_t values (and log a warning msg). * * @param[out] meminfo - pointer to bfa_meminfo_t. This content - * indicates the memory type (see bfa_mem_type_t) and + * indicates the memory type (see bfa_mem_type_t) and * amount of memory required. * * Driver should allocate the memory, populate the @@ -68,8 +1033,8 @@ void bfa_cfg_get_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo) { - int i; - u32 km_len = 0, dm_len = 0; + int i; + u32 km_len = 0, dm_len = 0; bfa_assert((cfg != NULL) && (meminfo != NULL)); @@ -90,26 +1055,6 @@ bfa_cfg_get_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo) meminfo->meminfo[BFA_MEM_TYPE_DMA - 1].mem_len = dm_len; } -static void -bfa_com_port_attach(struct bfa_s *bfa, struct bfa_meminfo_s *mi) -{ - struct bfa_port_s *port = &bfa->modules.port; - uint32_t dm_len; - uint8_t *dm_kva; - uint64_t dm_pa; - - dm_len = bfa_port_meminfo(); - dm_kva = bfa_meminfo_dma_virt(mi); - dm_pa = bfa_meminfo_dma_phys(mi); - - memset(port, 0, sizeof(struct bfa_port_s)); - bfa_port_attach(port, &bfa->ioc, bfa, bfa->trcmod, bfa->logm); - bfa_port_mem_claim(port, dm_kva, dm_pa); - - bfa_meminfo_dma_virt(mi) = dm_kva + dm_len; - bfa_meminfo_dma_phys(mi) = dm_pa + dm_len; -} - /** * Use this function to do attach the driver instance with the BFA * library. This function will not trigger any HW initialization @@ -119,14 +1064,14 @@ bfa_com_port_attach(struct bfa_s *bfa, struct bfa_meminfo_s *mi) * pre-defined values within the BFA library * * @param[out] bfa Pointer to bfa_t. - * @param[in] bfad Opaque handle back to the driver's IOC structure + * @param[in] bfad Opaque handle back to the driver's IOC structure * @param[in] cfg Pointer to bfa_ioc_cfg_t. Should be same structure - * that was used in bfa_cfg_get_meminfo(). - * @param[in] meminfo Pointer to bfa_meminfo_t. The driver should - * use the bfa_cfg_get_meminfo() call to - * find the memory blocks required, allocate the - * required memory and provide the starting addresses. - * @param[in] pcidev pointer to struct bfa_pcidev_s + * that was used in bfa_cfg_get_meminfo(). + * @param[in] meminfo Pointer to bfa_meminfo_t. The driver should + * use the bfa_cfg_get_meminfo() call to + * find the memory blocks required, allocate the + * required memory and provide the starting addresses. + * @param[in] pcidev pointer to struct bfa_pcidev_s * * @return * void @@ -140,8 +1085,8 @@ void bfa_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev) { - int i; - struct bfa_mem_elem_s *melem; + int i; + struct bfa_mem_elem_s *melem; bfa->fcs = BFA_FALSE; @@ -195,20 +1140,6 @@ bfa_init_trc(struct bfa_s *bfa, struct bfa_trc_mod_s *trcmod) bfa->trcmod = trcmod; } - -void -bfa_init_log(struct bfa_s *bfa, struct bfa_log_mod_s *logmod) -{ - bfa->logm = logmod; -} - - -void -bfa_init_aen(struct bfa_s *bfa, struct bfa_aen_s *aen) -{ - bfa->aen = aen; -} - void bfa_init_plog(struct bfa_s *bfa, struct bfa_plog_s *plog) { @@ -254,14 +1185,14 @@ bfa_start(struct bfa_s *bfa) /** * Use this function quiese the IOC. This function will return immediately, - * when the IOC is actually stopped, the bfa_cb_stop() will be called. + * when the IOC is actually stopped, the bfad->comp will be set. * - * @param[in] bfa - pointer to bfa_t. + * @param[in]bfa - pointer to bfa_t. * * @return None * * Special Considerations: - * bfa_cb_stop() could be called before or after bfa_stop() returns. + * bfad->comp can be set before or after bfa_stop() returns. * * @note * In case of any failure, we could handle it automatically by doing a @@ -283,9 +1214,9 @@ bfa_comp_deq(struct bfa_s *bfa, struct list_head *comp_q) void bfa_comp_process(struct bfa_s *bfa, struct list_head *comp_q) { - struct list_head *qe; - struct list_head *qen; - struct bfa_cb_qe_s *hcb_qe; + struct list_head *qe; + struct list_head *qen; + struct bfa_cb_qe_s *hcb_qe; list_for_each_safe(qe, qen, comp_q) { hcb_qe = (struct bfa_cb_qe_s *) qe; @@ -296,8 +1227,8 @@ bfa_comp_process(struct bfa_s *bfa, struct list_head *comp_q) void bfa_comp_free(struct bfa_s *bfa, struct list_head *comp_q) { - struct list_head *qe; - struct bfa_cb_qe_s *hcb_qe; + struct list_head *qe; + struct bfa_cb_qe_s *hcb_qe; while (!list_empty(comp_q)) { bfa_q_deq(comp_q, &qe); @@ -321,7 +1252,6 @@ bfa_timer_tick(struct bfa_s *bfa) bfa_timer_beat(&bfa->timer_mod); } -#ifndef BFA_BIOS_BUILD /** * Return the list of PCI vendor/device id lists supported by this * BFA instance. @@ -336,7 +1266,7 @@ bfa_get_pciids(struct bfa_pciid_s **pciids, int *npciids) {BFA_PCI_VENDOR_ID_BROCADE, BFA_PCI_DEVICE_ID_CT_FC}, }; - *npciids = ARRAY_SIZE(__pciids); + *npciids = sizeof(__pciids) / sizeof(__pciids[0]); *pciids = __pciids; } @@ -351,7 +1281,7 @@ bfa_get_pciids(struct bfa_pciid_s **pciids, int *npciids) * void * * Special Considerations: - * note + * note */ void bfa_cfg_get_default(struct bfa_iocfc_cfg_s *cfg) @@ -389,7 +1319,7 @@ bfa_cfg_get_min(struct bfa_iocfc_cfg_s *cfg) cfg->drvcfg.num_sgpgs = BFA_SGPG_MIN; cfg->drvcfg.num_reqq_elems = BFA_REQQ_NELEMS_MIN; cfg->drvcfg.num_rspq_elems = BFA_RSPQ_NELEMS_MIN; - cfg->drvcfg.min_cfg = BFA_TRUE; + cfg->drvcfg.min_cfg = BFA_TRUE; } void @@ -417,7 +1347,7 @@ bfa_debug_fwsave_clear(struct bfa_s *bfa) } /** - * Fetch firmware trace data. + * Fetch firmware trace data. * * @param[in] bfa BFA instance * @param[out] trcdata Firmware trace buffer @@ -433,6 +1363,22 @@ bfa_debug_fwtrc(struct bfa_s *bfa, void *trcdata, int *trclen) } /** + * Dump firmware memory. + * + * @param[in] bfa BFA instance + * @param[out] buf buffer for dump + * @param[in,out] offset smem offset to start read + * @param[in,out] buflen length of buffer + * + * @retval BFA_STATUS_OK Firmware memory is dumped. + * @retval BFA_STATUS_INPROGRESS Firmware memory dump is in progress. + */ +bfa_status_t +bfa_debug_fwcore(struct bfa_s *bfa, void *buf, u32 *offset, int *buflen) +{ + return bfa_ioc_debug_fwcore(&bfa->ioc, buf, offset, buflen); +} +/** * Reset hw semaphore & usage cnt regs and initialize. */ void @@ -441,4 +1387,23 @@ bfa_chip_reset(struct bfa_s *bfa) bfa_ioc_ownership_reset(&bfa->ioc); bfa_ioc_pll_init(&bfa->ioc); } -#endif + +/** + * Fetch firmware statistics data. + * + * @param[in] bfa BFA instance + * @param[out] data Firmware stats buffer + * + * @retval BFA_STATUS_OK Firmware trace is fetched. + */ +bfa_status_t +bfa_fw_stats_get(struct bfa_s *bfa, void *data) +{ + return bfa_ioc_fw_stats_get(&bfa->ioc, data); +} + +bfa_status_t +bfa_fw_stats_clear(struct bfa_s *bfa) +{ + return bfa_ioc_fw_stats_clear(&bfa->ioc); +} diff --git a/drivers/scsi/bfa/bfa_cs.h b/drivers/scsi/bfa/bfa_cs.h new file mode 100644 index 000000000000..7260c74620f8 --- /dev/null +++ b/drivers/scsi/bfa/bfa_cs.h @@ -0,0 +1,364 @@ +/* + * 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. + */ + +/** + * bfa_cs.h BFA common services + */ + +#ifndef __BFA_CS_H__ +#define __BFA_CS_H__ + +#include "bfa_os_inc.h" + +/** + * BFA TRC + */ + +#ifndef BFA_TRC_MAX +#define BFA_TRC_MAX (4 * 1024) +#endif + +#ifndef BFA_TRC_TS +#define BFA_TRC_TS(_trcm) ((_trcm)->ticks++) +#endif + +struct bfa_trc_s { +#ifdef __BIGENDIAN + u16 fileno; + u16 line; +#else + u16 line; + u16 fileno; +#endif + u32 timestamp; + union { + struct { + u32 rsvd; + u32 u32; + } u32; + u64 u64; + } data; +}; + +struct bfa_trc_mod_s { + u32 head; + u32 tail; + u32 ntrc; + u32 stopped; + u32 ticks; + u32 rsvd[3]; + struct bfa_trc_s trc[BFA_TRC_MAX]; +}; + +enum { + BFA_TRC_HAL = 1, /* BFA modules */ + BFA_TRC_FCS = 2, /* BFA FCS modules */ + BFA_TRC_LDRV = 3, /* Linux driver modules */ + BFA_TRC_CNA = 4, /* Common modules */ +}; +#define BFA_TRC_MOD_SH 10 +#define BFA_TRC_MOD(__mod) ((BFA_TRC_ ## __mod) << BFA_TRC_MOD_SH) + +/** + * Define a new tracing file (module). Module should match one defined above. + */ +#define BFA_TRC_FILE(__mod, __submod) \ + static int __trc_fileno = ((BFA_TRC_ ## __mod ## _ ## __submod) | \ + BFA_TRC_MOD(__mod)) + + +#define bfa_trc32(_trcp, _data) \ + __bfa_trc((_trcp)->trcmod, __trc_fileno, __LINE__, (u32)_data) +#define bfa_trc(_trcp, _data) \ + __bfa_trc((_trcp)->trcmod, __trc_fileno, __LINE__, (u64)_data) + +static inline void +bfa_trc_init(struct bfa_trc_mod_s *trcm) +{ + trcm->head = trcm->tail = trcm->stopped = 0; + trcm->ntrc = BFA_TRC_MAX; +} + +static inline void +bfa_trc_stop(struct bfa_trc_mod_s *trcm) +{ + trcm->stopped = 1; +} + +#ifdef FWTRC +extern void dc_flush(void *data); +#else +#define dc_flush(data) +#endif + + +static inline void +__bfa_trc(struct bfa_trc_mod_s *trcm, int fileno, int line, u64 data) +{ + int tail = trcm->tail; + struct bfa_trc_s *trc = &trcm->trc[tail]; + + if (trcm->stopped) + return; + + trc->fileno = (u16) fileno; + trc->line = (u16) line; + trc->data.u64 = data; + trc->timestamp = BFA_TRC_TS(trcm); + dc_flush(trc); + + trcm->tail = (trcm->tail + 1) & (BFA_TRC_MAX - 1); + if (trcm->tail == trcm->head) + trcm->head = (trcm->head + 1) & (BFA_TRC_MAX - 1); + dc_flush(trcm); +} + + +static inline void +__bfa_trc32(struct bfa_trc_mod_s *trcm, int fileno, int line, u32 data) +{ + int tail = trcm->tail; + struct bfa_trc_s *trc = &trcm->trc[tail]; + + if (trcm->stopped) + return; + + trc->fileno = (u16) fileno; + trc->line = (u16) line; + trc->data.u32.u32 = data; + trc->timestamp = BFA_TRC_TS(trcm); + dc_flush(trc); + + trcm->tail = (trcm->tail + 1) & (BFA_TRC_MAX - 1); + if (trcm->tail == trcm->head) + trcm->head = (trcm->head + 1) & (BFA_TRC_MAX - 1); + dc_flush(trcm); +} + +#ifndef BFA_PERF_BUILD +#define bfa_trc_fp(_trcp, _data) bfa_trc(_trcp, _data) +#else +#define bfa_trc_fp(_trcp, _data) +#endif + +/** + * @ BFA LOG interfaces + */ +#define bfa_assert(__cond) do { \ + if (!(__cond)) { \ + printk(KERN_ERR "assert(%s) failed at %s:%d\\n", \ + #__cond, __FILE__, __LINE__); \ + } \ +} while (0) + +#define bfa_sm_fault(__mod, __event) do { \ + bfa_trc(__mod, (((u32)0xDEAD << 16) | __event)); \ + printk(KERN_ERR "Assertion failure: %s:%d: %d", \ + __FILE__, __LINE__, (__event)); \ +} while (0) + +#ifndef BFA_PERF_BUILD +#define bfa_assert_fp(__cond) bfa_assert(__cond) +#else +#define bfa_assert_fp(__cond) +#endif + +/* BFA queue definitions */ +#define bfa_q_first(_q) ((void *)(((struct list_head *) (_q))->next)) +#define bfa_q_next(_qe) (((struct list_head *) (_qe))->next) +#define bfa_q_prev(_qe) (((struct list_head *) (_qe))->prev) + +/* + * bfa_q_qe_init - to initialize a queue element + */ +#define bfa_q_qe_init(_qe) { \ + bfa_q_next(_qe) = (struct list_head *) NULL; \ + bfa_q_prev(_qe) = (struct list_head *) NULL; \ +} + +/* + * bfa_q_deq - dequeue an element from head of the queue + */ +#define bfa_q_deq(_q, _qe) { \ + if (!list_empty(_q)) { \ + (*((struct list_head **) (_qe))) = bfa_q_next(_q); \ + bfa_q_prev(bfa_q_next(*((struct list_head **) _qe))) = \ + (struct list_head *) (_q); \ + bfa_q_next(_q) = bfa_q_next(*((struct list_head **) _qe));\ + BFA_Q_DBG_INIT(*((struct list_head **) _qe)); \ + } else { \ + *((struct list_head **) (_qe)) = (struct list_head *) NULL;\ + } \ +} + +/* + * bfa_q_deq_tail - dequeue an element from tail of the queue + */ +#define bfa_q_deq_tail(_q, _qe) { \ + if (!list_empty(_q)) { \ + *((struct list_head **) (_qe)) = bfa_q_prev(_q); \ + bfa_q_next(bfa_q_prev(*((struct list_head **) _qe))) = \ + (struct list_head *) (_q); \ + bfa_q_prev(_q) = bfa_q_prev(*(struct list_head **) _qe);\ + BFA_Q_DBG_INIT(*((struct list_head **) _qe)); \ + } else { \ + *((struct list_head **) (_qe)) = (struct list_head *) NULL;\ + } \ +} + +static inline int +bfa_q_is_on_q_func(struct list_head *q, struct list_head *qe) +{ + struct list_head *tqe; + + tqe = bfa_q_next(q); + while (tqe != q) { + if (tqe == qe) + return 1; + tqe = bfa_q_next(tqe); + if (tqe == NULL) + break; + } + return 0; +} + +/* + * #ifdef BFA_DEBUG (Using bfa_assert to check for debug_build is not + * consistent across modules) + */ +#ifndef BFA_PERF_BUILD +#define BFA_Q_DBG_INIT(_qe) bfa_q_qe_init(_qe) +#else +#define BFA_Q_DBG_INIT(_qe) +#endif + +#define bfa_q_is_on_q(_q, _qe) \ + bfa_q_is_on_q_func(_q, (struct list_head *)(_qe)) + +/** + * @ BFA state machine interfaces + */ + +typedef void (*bfa_sm_t)(void *sm, int event); + +/** + * oc - object class eg. bfa_ioc + * st - state, eg. reset + * otype - object type, eg. struct bfa_ioc_s + * etype - object type, eg. enum ioc_event + */ +#define bfa_sm_state_decl(oc, st, otype, etype) \ + static void oc ## _sm_ ## st(otype * fsm, etype event) + +#define bfa_sm_set_state(_sm, _state) ((_sm)->sm = (bfa_sm_t)(_state)) +#define bfa_sm_send_event(_sm, _event) ((_sm)->sm((_sm), (_event))) +#define bfa_sm_get_state(_sm) ((_sm)->sm) +#define bfa_sm_cmp_state(_sm, _state) ((_sm)->sm == (bfa_sm_t)(_state)) + +/** + * For converting from state machine function to state encoding. + */ +struct bfa_sm_table_s { + bfa_sm_t sm; /* state machine function */ + int state; /* state machine encoding */ + char *name; /* state name for display */ +}; +#define BFA_SM(_sm) ((bfa_sm_t)(_sm)) + +/** + * State machine with entry actions. + */ +typedef void (*bfa_fsm_t)(void *fsm, int event); + +/** + * oc - object class eg. bfa_ioc + * st - state, eg. reset + * otype - object type, eg. struct bfa_ioc_s + * etype - object type, eg. enum ioc_event + */ +#define bfa_fsm_state_decl(oc, st, otype, etype) \ + static void oc ## _sm_ ## st(otype * fsm, etype event); \ + static void oc ## _sm_ ## st ## _entry(otype * fsm) + +#define bfa_fsm_set_state(_fsm, _state) do { \ + (_fsm)->fsm = (bfa_fsm_t)(_state); \ + _state ## _entry(_fsm); \ +} while (0) + +#define bfa_fsm_send_event(_fsm, _event) ((_fsm)->fsm((_fsm), (_event))) +#define bfa_fsm_get_state(_fsm) ((_fsm)->fsm) +#define bfa_fsm_cmp_state(_fsm, _state) \ + ((_fsm)->fsm == (bfa_fsm_t)(_state)) + +static inline int +bfa_sm_to_state(struct bfa_sm_table_s *smt, bfa_sm_t sm) +{ + int i = 0; + + while (smt[i].sm && smt[i].sm != sm) + i++; + return smt[i].state; +} + +/** + * @ Generic wait counter. + */ + +typedef void (*bfa_wc_resume_t) (void *cbarg); + +struct bfa_wc_s { + bfa_wc_resume_t wc_resume; + void *wc_cbarg; + int wc_count; +}; + +static inline void +bfa_wc_up(struct bfa_wc_s *wc) +{ + wc->wc_count++; +} + +static inline void +bfa_wc_down(struct bfa_wc_s *wc) +{ + wc->wc_count--; + if (wc->wc_count == 0) + wc->wc_resume(wc->wc_cbarg); +} + +/** + * Initialize a waiting counter. + */ +static inline void +bfa_wc_init(struct bfa_wc_s *wc, bfa_wc_resume_t wc_resume, void *wc_cbarg) +{ + wc->wc_resume = wc_resume; + wc->wc_cbarg = wc_cbarg; + wc->wc_count = 0; + bfa_wc_up(wc); +} + +/** + * Wait for counter to reach zero + */ +static inline void +bfa_wc_wait(struct bfa_wc_s *wc) +{ + bfa_wc_down(wc); +} + +#endif /* __BFA_CS_H__ */ diff --git a/drivers/scsi/bfa/bfa_csdebug.c b/drivers/scsi/bfa/bfa_csdebug.c deleted file mode 100644 index caeb1143a4e6..000000000000 --- a/drivers/scsi/bfa/bfa_csdebug.c +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#include <cs/bfa_debug.h> -#include <bfa_os_inc.h> -#include <cs/bfa_q.h> -#include <log/bfa_log_hal.h> - -/** - * cs_debug_api - */ - - -void -bfa_panic(int line, char *file, char *panicstr) -{ - bfa_log(NULL, BFA_LOG_HAL_ASSERT, file, line, panicstr); - bfa_os_panic(); -} - -void -bfa_sm_panic(struct bfa_log_mod_s *logm, int line, char *file, int event) -{ - bfa_log(logm, BFA_LOG_HAL_SM_ASSERT, file, line, event); - bfa_os_panic(); -} - -int -bfa_q_is_on_q_func(struct list_head *q, struct list_head *qe) -{ - struct list_head *tqe; - - tqe = bfa_q_next(q); - while (tqe != q) { - if (tqe == qe) - return 1; - tqe = bfa_q_next(tqe); - if (tqe == NULL) - break; - } - return 0; -} - - diff --git a/drivers/scsi/bfa/bfa_defs.h b/drivers/scsi/bfa/bfa_defs.h new file mode 100644 index 000000000000..d49877ff5140 --- /dev/null +++ b/drivers/scsi/bfa/bfa_defs.h @@ -0,0 +1,466 @@ +/* + * 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 __BFA_DEFS_H__ +#define __BFA_DEFS_H__ + +#include "bfa_fc.h" +#include "bfa_os_inc.h" + +#define BFA_MFG_SERIALNUM_SIZE 11 +#define STRSZ(_n) (((_n) + 4) & ~3) + +/** + * Manufacturing card type + */ +enum { + BFA_MFG_TYPE_CB_MAX = 825, /* Crossbow card type max */ + BFA_MFG_TYPE_FC8P2 = 825, /* 8G 2port FC card */ + BFA_MFG_TYPE_FC8P1 = 815, /* 8G 1port FC card */ + BFA_MFG_TYPE_FC4P2 = 425, /* 4G 2port FC card */ + 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_ASTRA = 807, /* Astra mezz card */ + BFA_MFG_TYPE_LIGHTNING_P0 = 902, /* Lightning mezz card - old */ + BFA_MFG_TYPE_LIGHTNING = 1741, /* Lightning mezz card */ + BFA_MFG_TYPE_INVALID = 0, /* Invalid card type */ +}; + +#pragma pack(1) + +/** + * Check if Mezz card + */ +#define bfa_mfg_is_mezz(type) (( \ + (type) == BFA_MFG_TYPE_JAYHAWK || \ + (type) == BFA_MFG_TYPE_WANCHESE || \ + (type) == BFA_MFG_TYPE_ASTRA || \ + (type) == BFA_MFG_TYPE_LIGHTNING_P0 || \ + (type) == BFA_MFG_TYPE_LIGHTNING)) + +/** + * Check if the card having old wwn/mac handling + */ +#define bfa_mfg_is_old_wwn_mac_model(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 || \ + (type) == BFA_MFG_TYPE_JAYHAWK || \ + (type) == BFA_MFG_TYPE_WANCHESE)) + +#define bfa_mfg_increment_wwn_mac(m, i) \ +do { \ + u32 t = ((u32)(m)[0] << 16) | ((u32)(m)[1] << 8) | \ + (u32)(m)[2]; \ + t += (i); \ + (m)[0] = (t >> 16) & 0xFF; \ + (m)[1] = (t >> 8) & 0xFF; \ + (m)[2] = t & 0xFF; \ +} while (0) + +/** + * VPD data length + */ +#define BFA_MFG_VPD_LEN 512 + +/** + * VPD vendor tag + */ +enum { + BFA_MFG_VPD_UNKNOWN = 0, /* vendor unknown */ + BFA_MFG_VPD_IBM = 1, /* vendor IBM */ + BFA_MFG_VPD_HP = 2, /* vendor HP */ + BFA_MFG_VPD_DELL = 3, /* vendor DELL */ + BFA_MFG_VPD_PCI_IBM = 0x08, /* PCI VPD IBM */ + BFA_MFG_VPD_PCI_HP = 0x10, /* PCI VPD HP */ + BFA_MFG_VPD_PCI_DELL = 0x20, /* PCI VPD DELL */ + BFA_MFG_VPD_PCI_BRCD = 0xf8, /* PCI VPD Brocade */ +}; + +/** + * All numerical fields are in big-endian format. + */ +struct bfa_mfg_vpd_s { + u8 version; /* vpd data version */ + u8 vpd_sig[3]; /* characters 'V', 'P', 'D' */ + u8 chksum; /* u8 checksum */ + u8 vendor; /* vendor */ + u8 len; /* vpd data length excluding header */ + u8 rsv; + u8 data[BFA_MFG_VPD_LEN]; /* vpd data */ +}; + +#pragma pack() + +/** + * Status return values + */ +enum bfa_status { + BFA_STATUS_OK = 0, /* Success */ + BFA_STATUS_FAILED = 1, /* Operation failed */ + BFA_STATUS_EINVAL = 2, /* Invalid params Check input + * parameters */ + BFA_STATUS_ENOMEM = 3, /* Out of resources */ + BFA_STATUS_ETIMER = 5, /* Timer expired - Retry, if persists, + * contact support */ + BFA_STATUS_EPROTOCOL = 6, /* Protocol error */ + BFA_STATUS_DEVBUSY = 13, /* Device busy - Retry operation */ + BFA_STATUS_UNKNOWN_LWWN = 18, /* LPORT PWWN not found */ + BFA_STATUS_UNKNOWN_RWWN = 19, /* RPORT PWWN not found */ + BFA_STATUS_VPORT_EXISTS = 21, /* VPORT already exists */ + BFA_STATUS_VPORT_MAX = 22, /* Reached max VPORT supported limit */ + BFA_STATUS_UNSUPP_SPEED = 23, /* Invalid Speed Check speed setting */ + BFA_STATUS_INVLD_DFSZ = 24, /* Invalid Max data field size */ + BFA_STATUS_FABRIC_RJT = 29, /* Reject from attached fabric */ + BFA_STATUS_VPORT_WWN_BP = 46, /* WWN is same as base port's WWN */ + BFA_STATUS_NO_FCPIM_NEXUS = 52, /* No FCP Nexus exists with the rport */ + BFA_STATUS_IOC_FAILURE = 56, /* IOC failure - Retry, if persists + * contact support */ + BFA_STATUS_INVALID_WWN = 57, /* Invalid WWN */ + BFA_STATUS_DIAG_BUSY = 71, /* diag busy */ + BFA_STATUS_ENOFSAVE = 78, /* No saved firmware trace */ + BFA_STATUS_IOC_DISABLED = 82, /* IOC is already disabled */ + BFA_STATUS_INVALID_MAC = 134, /* Invalid MAC address */ + BFA_STATUS_PBC = 154, /* Operation not allowed for pre-boot + * configuration */ + BFA_STATUS_TRUNK_ENABLED = 164, /* Trunk is already enabled on + * this adapter */ + BFA_STATUS_TRUNK_DISABLED = 165, /* Trunking is disabled on + * the adapter */ + BFA_STATUS_IOPROFILE_OFF = 175, /* IO profile OFF */ + BFA_STATUS_MAX_VAL /* Unknown error code */ +}; +#define bfa_status_t enum bfa_status + +enum bfa_eproto_status { + BFA_EPROTO_BAD_ACCEPT = 0, + BFA_EPROTO_UNKNOWN_RSP = 1 +}; +#define bfa_eproto_status_t enum bfa_eproto_status + +enum bfa_boolean { + BFA_FALSE = 0, + BFA_TRUE = 1 +}; +#define bfa_boolean_t enum bfa_boolean + +#define BFA_STRING_32 32 +#define BFA_VERSION_LEN 64 + +/** + * ---------------------- adapter definitions ------------ + */ + +/** + * BFA adapter level attributes. + */ +enum { + BFA_ADAPTER_SERIAL_NUM_LEN = STRSZ(BFA_MFG_SERIALNUM_SIZE), + /* + *!< adapter serial num length + */ + BFA_ADAPTER_MODEL_NAME_LEN = 16, /* model name length */ + BFA_ADAPTER_MODEL_DESCR_LEN = 128, /* model description length */ + BFA_ADAPTER_MFG_NAME_LEN = 8, /* manufacturer name length */ + BFA_ADAPTER_SYM_NAME_LEN = 64, /* adapter symbolic name length */ + BFA_ADAPTER_OS_TYPE_LEN = 64, /* adapter os type length */ +}; + +struct bfa_adapter_attr_s { + char manufacturer[BFA_ADAPTER_MFG_NAME_LEN]; + char serial_num[BFA_ADAPTER_SERIAL_NUM_LEN]; + u32 card_type; + char model[BFA_ADAPTER_MODEL_NAME_LEN]; + char model_descr[BFA_ADAPTER_MODEL_DESCR_LEN]; + wwn_t pwwn; + char node_symname[FC_SYMNAME_MAX]; + char hw_ver[BFA_VERSION_LEN]; + char fw_ver[BFA_VERSION_LEN]; + char optrom_ver[BFA_VERSION_LEN]; + char os_type[BFA_ADAPTER_OS_TYPE_LEN]; + struct bfa_mfg_vpd_s vpd; + struct mac_s mac; + + u8 nports; + u8 max_speed; + u8 prototype; + char asic_rev; + + u8 pcie_gen; + u8 pcie_lanes_orig; + u8 pcie_lanes; + u8 cna_capable; + + u8 is_mezz; + u8 trunk_capable; +}; + +/** + * ---------------------- IOC definitions ------------ + */ + +enum { + BFA_IOC_DRIVER_LEN = 16, + BFA_IOC_CHIP_REV_LEN = 8, +}; + +/** + * Driver and firmware versions. + */ +struct bfa_ioc_driver_attr_s { + char driver[BFA_IOC_DRIVER_LEN]; /* driver name */ + char driver_ver[BFA_VERSION_LEN]; /* driver version */ + char fw_ver[BFA_VERSION_LEN]; /* firmware version */ + char bios_ver[BFA_VERSION_LEN]; /* bios version */ + char efi_ver[BFA_VERSION_LEN]; /* EFI version */ + char ob_ver[BFA_VERSION_LEN]; /* openboot version */ +}; + +/** + * IOC PCI device attributes + */ +struct bfa_ioc_pci_attr_s { + u16 vendor_id; /* PCI vendor ID */ + u16 device_id; /* PCI device ID */ + u16 ssid; /* subsystem ID */ + u16 ssvid; /* subsystem vendor ID */ + u32 pcifn; /* PCI device function */ + u32 rsvd; /* padding */ + char chip_rev[BFA_IOC_CHIP_REV_LEN]; /* chip revision */ +}; + +/** + * IOC states + */ +enum bfa_ioc_state { + BFA_IOC_UNINIT = 1, /* IOC is in uninit state */ + BFA_IOC_RESET = 2, /* IOC is in reset state */ + BFA_IOC_SEMWAIT = 3, /* Waiting for IOC h/w semaphore */ + BFA_IOC_HWINIT = 4, /* IOC h/w is being initialized */ + BFA_IOC_GETATTR = 5, /* IOC is being configured */ + BFA_IOC_OPERATIONAL = 6, /* IOC is operational */ + BFA_IOC_INITFAIL = 7, /* IOC hardware failure */ + BFA_IOC_FAIL = 8, /* IOC heart-beat failure */ + BFA_IOC_DISABLING = 9, /* IOC is being disabled */ + BFA_IOC_DISABLED = 10, /* IOC is disabled */ + BFA_IOC_FWMISMATCH = 11, /* IOC f/w different from drivers */ + BFA_IOC_ENABLING = 12, /* IOC is being enabled */ +}; + +/** + * IOC firmware stats + */ +struct bfa_fw_ioc_stats_s { + u32 enable_reqs; + u32 disable_reqs; + u32 get_attr_reqs; + u32 dbg_sync; + u32 dbg_dump; + u32 unknown_reqs; +}; + +/** + * IOC driver stats + */ +struct bfa_ioc_drv_stats_s { + u32 ioc_isrs; + u32 ioc_enables; + u32 ioc_disables; + u32 ioc_hbfails; + u32 ioc_boots; + u32 stats_tmos; + u32 hb_count; + u32 disable_reqs; + u32 enable_reqs; + u32 disable_replies; + u32 enable_replies; +}; + +/** + * IOC statistics + */ +struct bfa_ioc_stats_s { + struct bfa_ioc_drv_stats_s drv_stats; /* driver IOC stats */ + struct bfa_fw_ioc_stats_s fw_stats; /* firmware IOC stats */ +}; + +enum bfa_ioc_type_e { + BFA_IOC_TYPE_FC = 1, + BFA_IOC_TYPE_FCoE = 2, + BFA_IOC_TYPE_LL = 3, +}; + +/** + * IOC attributes returned in queries + */ +struct bfa_ioc_attr_s { + enum bfa_ioc_type_e ioc_type; + enum bfa_ioc_state state; /* IOC state */ + struct bfa_adapter_attr_s adapter_attr; /* HBA attributes */ + struct bfa_ioc_driver_attr_s driver_attr; /* driver attr */ + struct bfa_ioc_pci_attr_s pci_attr; + u8 port_id; /* port number */ + u8 rsvd[7]; /* 64bit align */ +}; + +/** + * ---------------------- mfg definitions ------------ + */ + +/** + * Checksum size + */ +#define BFA_MFG_CHKSUM_SIZE 16 + +#define BFA_MFG_PARTNUM_SIZE 14 +#define BFA_MFG_SUPPLIER_ID_SIZE 10 +#define BFA_MFG_SUPPLIER_PARTNUM_SIZE 20 +#define BFA_MFG_SUPPLIER_SERIALNUM_SIZE 20 +#define BFA_MFG_SUPPLIER_REVISION_SIZE 4 + +#pragma pack(1) + +/** + * All numerical fields are in big-endian format. + */ +struct bfa_mfg_block_s { + u8 version; /* manufacturing block version */ + u8 mfg_sig[3]; /* characters 'M', 'F', 'G' */ + u16 mfgsize; /* mfg block size */ + u16 u16_chksum; /* old u16 checksum */ + char brcd_serialnum[STRSZ(BFA_MFG_SERIALNUM_SIZE)]; + char brcd_partnum[STRSZ(BFA_MFG_PARTNUM_SIZE)]; + u8 mfg_day; /* manufacturing day */ + u8 mfg_month; /* manufacturing month */ + u16 mfg_year; /* manufacturing year */ + wwn_t mfg_wwn; /* wwn base for this adapter */ + u8 num_wwn; /* number of wwns assigned */ + u8 mfg_speeds; /* speeds allowed for this adapter */ + u8 rsv[2]; + char supplier_id[STRSZ(BFA_MFG_SUPPLIER_ID_SIZE)]; + char supplier_partnum[STRSZ(BFA_MFG_SUPPLIER_PARTNUM_SIZE)]; + char + supplier_serialnum[STRSZ(BFA_MFG_SUPPLIER_SERIALNUM_SIZE)]; + char + supplier_revision[STRSZ(BFA_MFG_SUPPLIER_REVISION_SIZE)]; + mac_t mfg_mac; /* mac address */ + u8 num_mac; /* number of mac addresses */ + u8 rsv2; + u32 mfg_type; /* card type */ + u8 rsv3[108]; + u8 md5_chksum[BFA_MFG_CHKSUM_SIZE]; /* md5 checksum */ +}; + +#pragma pack() + +/** + * ---------------------- pci definitions ------------ + */ + +/** + * PCI device and vendor ID information + */ +enum { + BFA_PCI_VENDOR_ID_BROCADE = 0x1657, + BFA_PCI_DEVICE_ID_FC_8G2P = 0x13, + BFA_PCI_DEVICE_ID_FC_8G1P = 0x17, + BFA_PCI_DEVICE_ID_CT = 0x14, + 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 + */ +enum { + BFA_PCI_FCOE_SSDEVICE_ID = 0x14, +}; + +/** + * Maximum number of device address ranges mapped through different BAR(s) + */ +#define BFA_PCI_ACCESS_RANGES 1 + +/* + * Port speed settings. Each specific speed is a bit field. Use multiple + * bits to specify speeds to be selected for auto-negotiation. + */ +enum bfa_port_speed { + BFA_PORT_SPEED_UNKNOWN = 0, + BFA_PORT_SPEED_1GBPS = 1, + BFA_PORT_SPEED_2GBPS = 2, + BFA_PORT_SPEED_4GBPS = 4, + BFA_PORT_SPEED_8GBPS = 8, + BFA_PORT_SPEED_10GBPS = 10, + BFA_PORT_SPEED_16GBPS = 16, + BFA_PORT_SPEED_AUTO = + (BFA_PORT_SPEED_1GBPS | BFA_PORT_SPEED_2GBPS | + BFA_PORT_SPEED_4GBPS | BFA_PORT_SPEED_8GBPS), +}; +#define bfa_port_speed_t enum bfa_port_speed + +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 +#define BOOT_CFG_VLAN 1 + +/** + * Boot options setting. Boot options setting determines from where + * to get the boot lun information + */ +enum bfa_boot_bootopt { + BFA_BOOT_AUTO_DISCOVER = 0, /* Boot from blun provided by fabric */ + BFA_BOOT_STORED_BLUN = 1, /* Boot from bluns stored in flash */ + BFA_BOOT_FIRST_LUN = 2, /* Boot from first discovered blun */ + BFA_BOOT_PBC = 3, /* Boot from pbc configured blun */ +}; + +#pragma pack(1) +/** + * Boot lun information. + */ +struct bfa_boot_bootlun_s { + wwn_t pwwn; /* port wwn of target */ + lun_t lun; /* 64-bit lun */ +}; +#pragma pack() + +/** + * BOOT boot configuraton + */ +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_H__ */ diff --git a/drivers/scsi/bfa/bfa_defs_fcs.h b/drivers/scsi/bfa/bfa_defs_fcs.h new file mode 100644 index 000000000000..96905d301828 --- /dev/null +++ b/drivers/scsi/bfa/bfa_defs_fcs.h @@ -0,0 +1,457 @@ +/* + * 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 __BFA_DEFS_FCS_H__ +#define __BFA_DEFS_FCS_H__ + +#include "bfa_fc.h" +#include "bfa_defs_svc.h" + +/** + * VF states + */ +enum bfa_vf_state { + BFA_VF_UNINIT = 0, /* fabric is not yet initialized */ + BFA_VF_LINK_DOWN = 1, /* link is down */ + BFA_VF_FLOGI = 2, /* flogi is in progress */ + BFA_VF_AUTH = 3, /* authentication in progress */ + BFA_VF_NOFABRIC = 4, /* fabric is not present */ + BFA_VF_ONLINE = 5, /* login to fabric is complete */ + BFA_VF_EVFP = 6, /* EVFP is in progress */ + BFA_VF_ISOLATED = 7, /* port isolated due to vf_id mismatch */ +}; + +/** + * VF statistics + */ +struct bfa_vf_stats_s { + u32 flogi_sent; /* Num FLOGIs sent */ + u32 flogi_rsp_err; /* FLOGI response errors */ + u32 flogi_acc_err; /* FLOGI accept errors */ + u32 flogi_accepts; /* FLOGI accepts received */ + u32 flogi_rejects; /* FLOGI rejects received */ + u32 flogi_unknown_rsp; /* Unknown responses for FLOGI */ + u32 flogi_alloc_wait; /* Allocation waits prior to sending FLOGI */ + u32 flogi_rcvd; /* FLOGIs received */ + u32 flogi_rejected; /* Incoming FLOGIs rejected */ + u32 fabric_onlines; /* Internal fabric online notification sent + * to other modules */ + u32 fabric_offlines; /* Internal fabric offline notification sent + * to other modules */ + u32 resvd; /* padding for 64 bit alignment */ +}; + +/** + * VF attributes returned in queries + */ +struct bfa_vf_attr_s { + enum bfa_vf_state state; /* VF state */ + u32 rsvd; + wwn_t fabric_name; /* fabric name */ +}; + +#define BFA_FCS_MAX_LPORTS 256 +#define BFA_FCS_FABRIC_IPADDR_SZ 16 + +/** + * symbolic names for base port/virtual port + */ +#define BFA_SYMNAME_MAXLEN 128 /* 128 bytes */ +struct bfa_lport_symname_s { + char symname[BFA_SYMNAME_MAXLEN]; +}; + +/** +* Roles of FCS port: + * - FCP IM and FCP TM roles cannot be enabled together for a FCS port + * - Create multiple ports if both IM and TM functions required. + * - Atleast one role must be specified. + */ +enum bfa_lport_role { + BFA_LPORT_ROLE_FCP_IM = 0x01, /* FCP initiator role */ + BFA_LPORT_ROLE_FCP_MAX = BFA_LPORT_ROLE_FCP_IM, +}; + +/** + * FCS port configuration. + */ +struct bfa_lport_cfg_s { + wwn_t pwwn; /* port wwn */ + wwn_t nwwn; /* node wwn */ + struct bfa_lport_symname_s sym_name; /* vm port symbolic name */ + bfa_boolean_t preboot_vp; /* vport created from PBC */ + enum bfa_lport_role roles; /* FCS port roles */ + u8 tag[16]; /* opaque tag from application */ +}; + +/** + * FCS port states + */ +enum bfa_lport_state { + BFA_LPORT_UNINIT = 0, /* PORT is not yet initialized */ + BFA_LPORT_FDISC = 1, /* FDISC is in progress */ + BFA_LPORT_ONLINE = 2, /* login to fabric is complete */ + BFA_LPORT_OFFLINE = 3, /* No login to fabric */ +}; + +/** + * FCS port type. + */ +enum bfa_lport_type { + BFA_LPORT_TYPE_PHYSICAL = 0, + BFA_LPORT_TYPE_VIRTUAL, +}; + +/** + * FCS port offline reason. + */ +enum bfa_lport_offline_reason { + BFA_LPORT_OFFLINE_UNKNOWN = 0, + BFA_LPORT_OFFLINE_LINKDOWN, + BFA_LPORT_OFFLINE_FAB_UNSUPPORTED, /* NPIV not supported by the + * fabric */ + BFA_LPORT_OFFLINE_FAB_NORESOURCES, + BFA_LPORT_OFFLINE_FAB_LOGOUT, +}; + +/** + * FCS lport info. + */ +struct bfa_lport_info_s { + u8 port_type; /* bfa_lport_type_t : physical or + * virtual */ + u8 port_state; /* one of bfa_lport_state values */ + u8 offline_reason; /* one of bfa_lport_offline_reason_t + * values */ + wwn_t port_wwn; + wwn_t node_wwn; + + /* + * following 4 feilds are valid for Physical Ports only + */ + u32 max_vports_supp; /* Max supported vports */ + u32 num_vports_inuse; /* Num of in use vports */ + u32 max_rports_supp; /* Max supported rports */ + u32 num_rports_inuse; /* Num of doscovered rports */ + +}; + +/** + * FCS port statistics + */ +struct bfa_lport_stats_s { + u32 ns_plogi_sent; + u32 ns_plogi_rsp_err; + u32 ns_plogi_acc_err; + u32 ns_plogi_accepts; + u32 ns_rejects; /* NS command rejects */ + u32 ns_plogi_unknown_rsp; + u32 ns_plogi_alloc_wait; + + u32 ns_retries; /* NS command retries */ + u32 ns_timeouts; /* NS command timeouts */ + + u32 ns_rspnid_sent; + u32 ns_rspnid_accepts; + u32 ns_rspnid_rsp_err; + u32 ns_rspnid_rejects; + u32 ns_rspnid_alloc_wait; + + u32 ns_rftid_sent; + u32 ns_rftid_accepts; + u32 ns_rftid_rsp_err; + u32 ns_rftid_rejects; + u32 ns_rftid_alloc_wait; + + u32 ns_rffid_sent; + u32 ns_rffid_accepts; + u32 ns_rffid_rsp_err; + u32 ns_rffid_rejects; + u32 ns_rffid_alloc_wait; + + u32 ns_gidft_sent; + u32 ns_gidft_accepts; + u32 ns_gidft_rsp_err; + u32 ns_gidft_rejects; + u32 ns_gidft_unknown_rsp; + u32 ns_gidft_alloc_wait; + + /* + * Mgmt Server stats + */ + u32 ms_retries; /* MS command retries */ + u32 ms_timeouts; /* MS command timeouts */ + u32 ms_plogi_sent; + u32 ms_plogi_rsp_err; + u32 ms_plogi_acc_err; + u32 ms_plogi_accepts; + u32 ms_rejects; /* MS command rejects */ + u32 ms_plogi_unknown_rsp; + u32 ms_plogi_alloc_wait; + + u32 num_rscn; /* Num of RSCN received */ + u32 num_portid_rscn;/* Num portid format RSCN + * received */ + + u32 uf_recvs; /* Unsolicited recv frames */ + u32 uf_recv_drops; /* Dropped received frames */ + + u32 plogi_rcvd; /* Received plogi */ + u32 prli_rcvd; /* Received prli */ + u32 adisc_rcvd; /* Received adisc */ + u32 prlo_rcvd; /* Received prlo */ + u32 logo_rcvd; /* Received logo */ + u32 rpsc_rcvd; /* Received rpsc */ + u32 un_handled_els_rcvd; /* Received unhandled ELS */ + u32 rport_plogi_timeouts; /* Rport plogi retry timeout count */ + u32 rport_del_max_plogi_retry; /* Deleted rport + * (max retry of plogi) */ +}; + +/** + * BFA port attribute returned in queries + */ +struct bfa_lport_attr_s { + enum bfa_lport_state state; /* port state */ + u32 pid; /* port ID */ + struct bfa_lport_cfg_s port_cfg; /* port configuration */ + enum bfa_port_type port_type; /* current topology */ + u32 loopback; /* cable is externally looped back */ + wwn_t fabric_name; /* attached switch's nwwn */ + u8 fabric_ip_addr[BFA_FCS_FABRIC_IPADDR_SZ]; /* attached + * fabric's ip addr */ + mac_t fpma_mac; /* Lport's FPMA Mac address */ + u16 authfail; /* auth failed state */ +}; + + +/** + * VPORT states + */ +enum bfa_vport_state { + BFA_FCS_VPORT_UNINIT = 0, + BFA_FCS_VPORT_CREATED = 1, + BFA_FCS_VPORT_OFFLINE = 1, + BFA_FCS_VPORT_FDISC_SEND = 2, + BFA_FCS_VPORT_FDISC = 3, + BFA_FCS_VPORT_FDISC_RETRY = 4, + BFA_FCS_VPORT_ONLINE = 5, + BFA_FCS_VPORT_DELETING = 6, + BFA_FCS_VPORT_CLEANUP = 6, + BFA_FCS_VPORT_LOGO_SEND = 7, + BFA_FCS_VPORT_LOGO = 8, + BFA_FCS_VPORT_ERROR = 9, + BFA_FCS_VPORT_MAX_STATE, +}; + +/** + * vport statistics + */ +struct bfa_vport_stats_s { + struct bfa_lport_stats_s port_stats; /* base class (port) stats */ + /* + * TODO - remove + */ + + u32 fdisc_sent; /* num fdisc sent */ + u32 fdisc_accepts; /* fdisc accepts */ + u32 fdisc_retries; /* fdisc retries */ + u32 fdisc_timeouts; /* fdisc timeouts */ + u32 fdisc_rsp_err; /* fdisc response error */ + u32 fdisc_acc_bad; /* bad fdisc accepts */ + u32 fdisc_rejects; /* fdisc rejects */ + u32 fdisc_unknown_rsp; + /* + *!< fdisc rsp unknown error + */ + u32 fdisc_alloc_wait;/* fdisc req (fcxp)alloc wait */ + + u32 logo_alloc_wait;/* logo req (fcxp) alloc wait */ + u32 logo_sent; /* logo sent */ + u32 logo_accepts; /* logo accepts */ + u32 logo_rejects; /* logo rejects */ + u32 logo_rsp_err; /* logo rsp errors */ + u32 logo_unknown_rsp; + /* logo rsp unknown errors */ + + u32 fab_no_npiv; /* fabric does not support npiv */ + + u32 fab_offline; /* offline events from fab SM */ + u32 fab_online; /* online events from fab SM */ + u32 fab_cleanup; /* cleanup request from fab SM */ + u32 rsvd; +}; + +/** + * BFA vport attribute returned in queries + */ +struct bfa_vport_attr_s { + struct bfa_lport_attr_s port_attr; /* base class (port) attributes */ + enum bfa_vport_state vport_state; /* vport state */ + u32 rsvd; +}; + +/** + * FCS remote port states + */ +enum bfa_rport_state { + BFA_RPORT_UNINIT = 0, /* PORT is not yet initialized */ + BFA_RPORT_OFFLINE = 1, /* rport is offline */ + BFA_RPORT_PLOGI = 2, /* PLOGI to rport is in progress */ + BFA_RPORT_ONLINE = 3, /* login to rport is complete */ + BFA_RPORT_PLOGI_RETRY = 4, /* retrying login to rport */ + BFA_RPORT_NSQUERY = 5, /* nameserver query */ + BFA_RPORT_ADISC = 6, /* ADISC authentication */ + BFA_RPORT_LOGO = 7, /* logging out with rport */ + BFA_RPORT_LOGORCV = 8, /* handling LOGO from rport */ + BFA_RPORT_NSDISC = 9, /* re-discover rport */ +}; + +/** + * Rport Scsi Function : Initiator/Target. + */ +enum bfa_rport_function { + BFA_RPORT_INITIATOR = 0x01, /* SCSI Initiator */ + BFA_RPORT_TARGET = 0x02, /* SCSI Target */ +}; + +/** + * port/node symbolic names for rport + */ +#define BFA_RPORT_SYMNAME_MAXLEN 255 +struct bfa_rport_symname_s { + char symname[BFA_RPORT_SYMNAME_MAXLEN]; +}; + +/** + * FCS remote port statistics + */ +struct bfa_rport_stats_s { + u32 offlines; /* remote port offline count */ + u32 onlines; /* remote port online count */ + u32 rscns; /* RSCN affecting rport */ + u32 plogis; /* plogis sent */ + u32 plogi_accs; /* plogi accepts */ + u32 plogi_timeouts; /* plogi timeouts */ + u32 plogi_rejects; /* rcvd plogi rejects */ + u32 plogi_failed; /* local failure */ + u32 plogi_rcvd; /* plogis rcvd */ + u32 prli_rcvd; /* inbound PRLIs */ + u32 adisc_rcvd; /* ADISCs received */ + u32 adisc_rejects; /* recvd ADISC rejects */ + u32 adisc_sent; /* ADISC requests sent */ + u32 adisc_accs; /* ADISC accepted by rport */ + u32 adisc_failed; /* ADISC failed (no response) */ + u32 adisc_rejected; /* ADISC rejected by us */ + u32 logos; /* logos sent */ + u32 logo_accs; /* LOGO accepts from rport */ + u32 logo_failed; /* LOGO failures */ + u32 logo_rejected; /* LOGO rejects from rport */ + u32 logo_rcvd; /* LOGO from remote port */ + + u32 rpsc_rcvd; /* RPSC received */ + u32 rpsc_rejects; /* recvd RPSC rejects */ + u32 rpsc_sent; /* RPSC requests sent */ + u32 rpsc_accs; /* RPSC accepted by rport */ + u32 rpsc_failed; /* RPSC failed (no response) */ + u32 rpsc_rejected; /* RPSC rejected by us */ + + u32 rjt_insuff_res; /* LS RJT with insuff resources */ + struct bfa_rport_hal_stats_s hal_stats; /* BFA rport stats */ +}; + +/** + * FCS remote port attributes returned in queries + */ +struct bfa_rport_attr_s { + wwn_t nwwn; /* node wwn */ + wwn_t pwwn; /* port wwn */ + enum fc_cos cos_supported; /* supported class of services */ + u32 pid; /* port ID */ + u32 df_sz; /* Max payload size */ + enum bfa_rport_state state; /* Rport State machine state */ + enum fc_cos fc_cos; /* FC classes of services */ + bfa_boolean_t cisc; /* CISC capable device */ + struct bfa_rport_symname_s symname; /* Symbolic Name */ + enum bfa_rport_function scsi_function; /* Initiator/Target */ + struct bfa_rport_qos_attr_s qos_attr; /* qos attributes */ + enum bfa_port_speed curr_speed; /* operating speed got from + * RPSC ELS. UNKNOWN, if RPSC + * is not supported */ + bfa_boolean_t trl_enforced; /* TRL enforced ? TRUE/FALSE */ + enum bfa_port_speed assigned_speed; /* Speed assigned by the user. + * will be used if RPSC is not + * supported by the rport */ +}; + +struct bfa_rport_remote_link_stats_s { + u32 lfc; /* Link Failure Count */ + u32 lsyc; /* Loss of Synchronization Count */ + u32 lsic; /* Loss of Signal Count */ + u32 pspec; /* Primitive Sequence Protocol Error Count */ + u32 itwc; /* Invalid Transmission Word Count */ + u32 icc; /* Invalid CRC Count */ +}; + + +#define BFA_MAX_IO_INDEX 7 +#define BFA_NO_IO_INDEX 9 + +/** + * FCS itnim states + */ +enum bfa_itnim_state { + BFA_ITNIM_OFFLINE = 0, /* offline */ + BFA_ITNIM_PRLI_SEND = 1, /* prli send */ + BFA_ITNIM_PRLI_SENT = 2, /* prli sent */ + BFA_ITNIM_PRLI_RETRY = 3, /* prli retry */ + BFA_ITNIM_HCB_ONLINE = 4, /* online callback */ + BFA_ITNIM_ONLINE = 5, /* online */ + BFA_ITNIM_HCB_OFFLINE = 6, /* offline callback */ + BFA_ITNIM_INITIATIOR = 7, /* initiator */ +}; + +/** + * FCS remote port statistics + */ +struct bfa_itnim_stats_s { + u32 onlines; /* num rport online */ + u32 offlines; /* num rport offline */ + u32 prli_sent; /* num prli sent out */ + u32 fcxp_alloc_wait;/* num fcxp alloc waits */ + u32 prli_rsp_err; /* num prli rsp errors */ + u32 prli_rsp_acc; /* num prli rsp accepts */ + u32 initiator; /* rport is an initiator */ + u32 prli_rsp_parse_err; /* prli rsp parsing errors */ + u32 prli_rsp_rjt; /* num prli rsp rejects */ + u32 timeout; /* num timeouts detected */ + u32 sler; /* num sler notification from BFA */ + u32 rsvd; /* padding for 64 bit alignment */ +}; + +/** + * FCS itnim attributes returned in queries + */ +struct bfa_itnim_attr_s { + enum bfa_itnim_state state; /* FCS itnim state */ + u8 retry; /* data retransmision support */ + u8 task_retry_id; /* task retry ident support */ + u8 rec_support; /* REC supported */ + u8 conf_comp; /* confirmed completion supp */ +}; + +#endif /* __BFA_DEFS_FCS_H__ */ diff --git a/drivers/scsi/bfa/bfa_defs_svc.h b/drivers/scsi/bfa/bfa_defs_svc.h new file mode 100644 index 000000000000..56226fcf9470 --- /dev/null +++ b/drivers/scsi/bfa/bfa_defs_svc.h @@ -0,0 +1,1081 @@ +/* + * 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 __BFA_DEFS_SVC_H__ +#define __BFA_DEFS_SVC_H__ + +#include "bfa_defs.h" +#include "bfa_fc.h" +#include "bfi.h" + +#define BFA_IOCFC_INTR_DELAY 1125 +#define BFA_IOCFC_INTR_LATENCY 225 +#define BFA_IOCFCOE_INTR_DELAY 25 +#define BFA_IOCFCOE_INTR_LATENCY 5 + +/** + * Interrupt coalescing configuration. + */ +#pragma pack(1) +struct bfa_iocfc_intr_attr_s { + u8 coalesce; /* enable/disable coalescing */ + u8 rsvd[3]; + u16 latency; /* latency in microseconds */ + u16 delay; /* delay in microseconds */ +}; + +/** + * IOC firmware configuraton + */ +struct bfa_iocfc_fwcfg_s { + u16 num_fabrics; /* number of fabrics */ + u16 num_lports; /* number of local lports */ + u16 num_rports; /* number of remote ports */ + u16 num_ioim_reqs; /* number of IO reqs */ + u16 num_tskim_reqs; /* task management requests */ + u16 num_iotm_reqs; /* number of TM IO reqs */ + u16 num_tsktm_reqs; /* TM task management requests*/ + u16 num_fcxp_reqs; /* unassisted FC exchanges */ + u16 num_uf_bufs; /* unsolicited recv buffers */ + u8 num_cqs; + u8 fw_tick_res; /* FW clock resolution in ms */ + u8 rsvd[4]; +}; +#pragma pack() + +struct bfa_iocfc_drvcfg_s { + u16 num_reqq_elems; /* number of req queue elements */ + u16 num_rspq_elems; /* number of rsp queue elements */ + u16 num_sgpgs; /* number of total SG pages */ + u16 num_sboot_tgts; /* number of SAN boot targets */ + u16 num_sboot_luns; /* number of SAN boot luns */ + u16 ioc_recover; /* IOC recovery mode */ + u16 min_cfg; /* minimum configuration */ + u16 path_tov; /* device path timeout */ + bfa_boolean_t delay_comp; /* delay completion of + failed inflight IOs */ + u32 rsvd; +}; + +/** + * IOC configuration + */ +struct bfa_iocfc_cfg_s { + struct bfa_iocfc_fwcfg_s fwcfg; /* firmware side config */ + struct bfa_iocfc_drvcfg_s drvcfg; /* driver side config */ +}; + +/** + * IOC firmware IO stats + */ +struct bfa_fw_io_stats_s { + u32 host_abort; /* IO aborted by host driver*/ + u32 host_cleanup; /* IO clean up by host driver */ + + u32 fw_io_timeout; /* IOs timedout */ + u32 fw_frm_parse; /* frame parsed by f/w */ + u32 fw_frm_data; /* fcp_data frame parsed by f/w */ + u32 fw_frm_rsp; /* fcp_rsp frame parsed by f/w */ + u32 fw_frm_xfer_rdy; /* xfer_rdy frame parsed by f/w */ + u32 fw_frm_bls_acc; /* BLS ACC frame parsed by f/w */ + u32 fw_frm_tgt_abort; /* target ABTS parsed by f/w */ + u32 fw_frm_unknown; /* unknown parsed by f/w */ + u32 fw_data_dma; /* f/w DMA'ed the data frame */ + u32 fw_frm_drop; /* f/w drop the frame */ + + u32 rec_timeout; /* FW rec timed out */ + u32 error_rec; /* FW sending rec on + * an error condition*/ + u32 wait_for_si; /* FW wait for SI */ + u32 rec_rsp_inval; /* REC rsp invalid */ + u32 seqr_io_abort; /* target does not know cmd so abort */ + u32 seqr_io_retry; /* SEQR failed so retry IO */ + + u32 itn_cisc_upd_rsp; /* ITN cisc updated on fcp_rsp */ + u32 itn_cisc_upd_data; /* ITN cisc updated on fcp_data */ + u32 itn_cisc_upd_xfer_rdy; /* ITN cisc updated on fcp_data */ + + u32 fcp_data_lost; /* fcp data lost */ + + u32 ro_set_in_xfer_rdy; /* Target set RO in Xfer_rdy frame */ + u32 xfer_rdy_ooo_err; /* Out of order Xfer_rdy received */ + u32 xfer_rdy_unknown_err; /* unknown error in xfer_rdy frame */ + + u32 io_abort_timeout; /* ABTS timedout */ + u32 sler_initiated; /* SLER initiated */ + + u32 unexp_fcp_rsp; /* fcp response in wrong state */ + + u32 fcp_rsp_under_run; /* fcp rsp IO underrun */ + u32 fcp_rsp_under_run_wr; /* fcp rsp IO underrun for write */ + u32 fcp_rsp_under_run_err; /* fcp rsp IO underrun error */ + u32 fcp_rsp_resid_inval; /* invalid residue */ + u32 fcp_rsp_over_run; /* fcp rsp IO overrun */ + u32 fcp_rsp_over_run_err; /* fcp rsp IO overrun error */ + u32 fcp_rsp_proto_err; /* protocol error in fcp rsp */ + u32 fcp_rsp_sense_err; /* error in sense info in fcp rsp */ + u32 fcp_conf_req; /* FCP conf requested */ + + u32 tgt_aborted_io; /* target initiated abort */ + + u32 ioh_edtov_timeout_event;/* IOH edtov timer popped */ + u32 ioh_fcp_rsp_excp_event; /* IOH FCP_RSP exception */ + u32 ioh_fcp_conf_event; /* IOH FCP_CONF */ + u32 ioh_mult_frm_rsp_event; /* IOH multi_frame FCP_RSP */ + u32 ioh_hit_class2_event; /* IOH hit class2 */ + u32 ioh_miss_other_event; /* IOH miss other */ + u32 ioh_seq_cnt_err_event; /* IOH seq cnt error */ + u32 ioh_len_err_event; /* IOH len error - fcp_dl != + * bytes xfered */ + u32 ioh_seq_len_err_event; /* IOH seq len error */ + u32 ioh_data_oor_event; /* Data out of range */ + u32 ioh_ro_ooo_event; /* Relative offset out of range */ + u32 ioh_cpu_owned_event; /* IOH hit -iost owned by f/w */ + u32 ioh_unexp_frame_event; /* unexpected frame recieved + * count */ + u32 ioh_err_int; /* IOH error int during data-phase + * for scsi write + */ +}; + +/** + * IOC port firmware stats + */ + +struct bfa_fw_port_fpg_stats_s { + u32 intr_evt; + u32 intr; + u32 intr_excess; + u32 intr_cause0; + u32 intr_other; + u32 intr_other_ign; + u32 sig_lost; + u32 sig_regained; + u32 sync_lost; + u32 sync_to; + u32 sync_regained; + u32 div2_overflow; + u32 div2_underflow; + u32 efifo_overflow; + u32 efifo_underflow; + u32 idle_rx; + u32 lrr_rx; + u32 lr_rx; + u32 ols_rx; + u32 nos_rx; + u32 lip_rx; + u32 arbf0_rx; + u32 arb_rx; + u32 mrk_rx; + u32 const_mrk_rx; + u32 prim_unknown; +}; + + +struct bfa_fw_port_lksm_stats_s { + u32 hwsm_success; /* hwsm state machine success */ + u32 hwsm_fails; /* hwsm fails */ + u32 hwsm_wdtov; /* hwsm timed out */ + u32 swsm_success; /* swsm success */ + u32 swsm_fails; /* swsm fails */ + u32 swsm_wdtov; /* swsm timed out */ + u32 busybufs; /* link init failed due to busybuf */ + u32 buf_waits; /* bufwait state entries */ + u32 link_fails; /* link failures */ + u32 psp_errors; /* primitive sequence protocol errors */ + u32 lr_unexp; /* No. of times LR rx-ed unexpectedly */ + u32 lrr_unexp; /* No. of times LRR rx-ed unexpectedly */ + u32 lr_tx; /* No. of times LR tx started */ + u32 lrr_tx; /* No. of times LRR tx started */ + u32 ols_tx; /* No. of times OLS tx started */ + u32 nos_tx; /* No. of times NOS tx started */ + u32 hwsm_lrr_rx; /* No. of times LRR rx-ed by HWSM */ + u32 hwsm_lr_rx; /* No. of times LR rx-ed by HWSM */ +}; + +struct bfa_fw_port_snsm_stats_s { + u32 hwsm_success; /* Successful hwsm terminations */ + u32 hwsm_fails; /* hwsm fail count */ + u32 hwsm_wdtov; /* hwsm timed out */ + u32 swsm_success; /* swsm success */ + u32 swsm_wdtov; /* swsm timed out */ + u32 error_resets; /* error resets initiated by upsm */ + u32 sync_lost; /* Sync loss count */ + u32 sig_lost; /* Signal loss count */ +}; + +struct bfa_fw_port_physm_stats_s { + u32 module_inserts; /* Module insert count */ + u32 module_xtracts; /* Module extracts count */ + u32 module_invalids; /* Invalid module inserted count */ + u32 module_read_ign; /* Module validation status ignored */ + u32 laser_faults; /* Laser fault count */ + u32 rsvd; +}; + +struct bfa_fw_fip_stats_s { + u32 vlan_req; /* vlan discovery requests */ + u32 vlan_notify; /* vlan notifications */ + u32 vlan_err; /* vlan response error */ + u32 vlan_timeouts; /* vlan disvoery timeouts */ + u32 vlan_invalids; /* invalid vlan in discovery advert. */ + u32 disc_req; /* Discovery solicit requests */ + u32 disc_rsp; /* Discovery solicit response */ + u32 disc_err; /* Discovery advt. parse errors */ + u32 disc_unsol; /* Discovery unsolicited */ + u32 disc_timeouts; /* Discovery timeouts */ + u32 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; /* FIP logos received */ + u32 clrvlink_req; /* Clear virtual link req */ + u32 op_unsupp; /* Unsupported FIP operation */ + u32 untagged; /* Untagged frames (ignored) */ + u32 invalid_version; /* Invalid FIP version */ +}; + +struct bfa_fw_lps_stats_s { + u32 mac_invalids; /* Invalid mac assigned */ + u32 rsvd; +}; + +struct bfa_fw_fcoe_stats_s { + u32 cee_linkups; /* CEE link up count */ + u32 cee_linkdns; /* CEE link down count */ + u32 fip_linkups; /* FIP link up count */ + u32 fip_linkdns; /* FIP link up count */ + u32 fip_fails; /* FIP fail count */ + u32 mac_invalids; /* Invalid mac assigned */ +}; + +/** + * IOC firmware FCoE port stats + */ +struct bfa_fw_fcoe_port_stats_s { + struct bfa_fw_fcoe_stats_s fcoe_stats; + struct bfa_fw_fip_stats_s fip_stats; +}; + +/** + * IOC firmware FC uport stats + */ +struct bfa_fw_fc_uport_stats_s { + struct bfa_fw_port_snsm_stats_s snsm_stats; + struct bfa_fw_port_lksm_stats_s lksm_stats; +}; + +/** + * IOC firmware FC port stats + */ +union bfa_fw_fc_port_stats_s { + struct bfa_fw_fc_uport_stats_s fc_stats; + struct bfa_fw_fcoe_port_stats_s fcoe_stats; +}; + +/** + * IOC firmware port stats + */ +struct bfa_fw_port_stats_s { + struct bfa_fw_port_fpg_stats_s fpg_stats; + struct bfa_fw_port_physm_stats_s physm_stats; + union bfa_fw_fc_port_stats_s fc_port; +}; + +/** + * fcxchg module statistics + */ +struct bfa_fw_fcxchg_stats_s { + u32 ua_tag_inv; + u32 ua_state_inv; +}; + +struct bfa_fw_lpsm_stats_s { + u32 cls_rx; + u32 cls_tx; +}; + +/** + * Trunk statistics + */ +struct bfa_fw_trunk_stats_s { + u32 emt_recvd; /* Trunk EMT received */ + u32 emt_accepted; /* Trunk EMT Accepted */ + u32 emt_rejected; /* Trunk EMT rejected */ + u32 etp_recvd; /* Trunk ETP received */ + u32 etp_accepted; /* Trunk ETP Accepted */ + u32 etp_rejected; /* Trunk ETP rejected */ + u32 lr_recvd; /* Trunk LR received */ + u32 rsvd; /* padding for 64 bit alignment */ +}; + +struct bfa_fw_advsm_stats_s { + u32 flogi_sent; /* Flogi sent */ + u32 flogi_acc_recvd; /* Flogi Acc received */ + u32 flogi_rjt_recvd; /* Flogi rejects received */ + u32 flogi_retries; /* Flogi retries */ + + u32 elp_recvd; /* ELP received */ + u32 elp_accepted; /* ELP Accepted */ + u32 elp_rejected; /* ELP rejected */ + u32 elp_dropped; /* ELP dropped */ +}; + +/** + * IOCFC firmware stats + */ +struct bfa_fw_iocfc_stats_s { + u32 cfg_reqs; /* cfg request */ + u32 updq_reqs; /* update queue request */ + u32 ic_reqs; /* interrupt coalesce reqs */ + u32 unknown_reqs; + u32 set_intr_reqs; /* set interrupt reqs */ +}; + +/** + * IOC attributes returned in queries + */ +struct bfa_iocfc_attr_s { + struct bfa_iocfc_cfg_s config; /* IOCFC config */ + struct bfa_iocfc_intr_attr_s intr_attr; /* interrupt attr */ +}; + +/** + * Eth_sndrcv mod stats + */ +struct bfa_fw_eth_sndrcv_stats_s { + u32 crc_err; + u32 rsvd; /* 64bit align */ +}; + +/** + * CT MAC mod stats + */ +struct bfa_fw_mac_mod_stats_s { + u32 mac_on; /* MAC got turned-on */ + u32 link_up; /* link-up */ + u32 signal_off; /* lost signal */ + u32 dfe_on; /* DFE on */ + u32 mac_reset; /* # of MAC reset to bring lnk up */ + u32 pcs_reset; /* # of PCS reset to bring lnk up */ + u32 loopback; /* MAC got into serdes loopback */ + u32 lb_mac_reset; + /* # of MAC reset to bring link up in loopback */ + u32 lb_pcs_reset; + /* # of PCS reset to bring link up in loopback */ + u32 rsvd; /* 64bit align */ +}; + +/** + * CT MOD stats + */ +struct bfa_fw_ct_mod_stats_s { + u32 rxa_rds_undrun; /* RxA RDS underrun */ + u32 rad_bpc_ovfl; /* RAD BPC overflow */ + u32 rad_rlb_bpc_ovfl; /* RAD RLB BPC overflow */ + u32 bpc_fcs_err; /* BPC FCS_ERR */ + u32 txa_tso_hdr; /* TxA TSO header too long */ + u32 rsvd; /* 64bit align */ +}; + +/** + * IOC firmware stats + */ +struct bfa_fw_stats_s { + struct bfa_fw_ioc_stats_s ioc_stats; + struct bfa_fw_iocfc_stats_s iocfc_stats; + struct bfa_fw_io_stats_s io_stats; + struct bfa_fw_port_stats_s port_stats; + struct bfa_fw_fcxchg_stats_s fcxchg_stats; + struct bfa_fw_lpsm_stats_s lpsm_stats; + struct bfa_fw_lps_stats_s lps_stats; + struct bfa_fw_trunk_stats_s trunk_stats; + struct bfa_fw_advsm_stats_s advsm_stats; + struct bfa_fw_mac_mod_stats_s macmod_stats; + struct bfa_fw_ct_mod_stats_s ctmod_stats; + struct bfa_fw_eth_sndrcv_stats_s ethsndrcv_stats; +}; + +#define BFA_IOCFC_PATHTOV_MAX 60 +#define BFA_IOCFC_QDEPTH_MAX 2000 + +/** + * QoS states + */ +enum bfa_qos_state { + BFA_QOS_ONLINE = 1, /* QoS is online */ + BFA_QOS_OFFLINE = 2, /* QoS is offline */ +}; + +/** + * QoS Priority levels. + */ +enum bfa_qos_priority { + BFA_QOS_UNKNOWN = 0, + BFA_QOS_HIGH = 1, /* QoS Priority Level High */ + BFA_QOS_MED = 2, /* QoS Priority Level Medium */ + BFA_QOS_LOW = 3, /* QoS Priority Level Low */ +}; + +/** + * QoS bandwidth allocation for each priority level + */ +enum bfa_qos_bw_alloc { + BFA_QOS_BW_HIGH = 60, /* bandwidth allocation for High */ + BFA_QOS_BW_MED = 30, /* bandwidth allocation for Medium */ + BFA_QOS_BW_LOW = 10, /* bandwidth allocation for Low */ +}; +#pragma pack(1) +/** + * QoS attribute returned in QoS Query + */ +struct bfa_qos_attr_s { + u8 state; /* QoS current state */ + u8 rsvd[3]; + u32 total_bb_cr; /* Total BB Credits */ +}; + +/** + * These fields should be displayed only from the CLI. + * There will be a separate BFAL API (get_qos_vc_attr ?) + * to retrieve this. + * + */ +#define BFA_QOS_MAX_VC 16 + +struct bfa_qos_vc_info_s { + u8 vc_credit; + u8 borrow_credit; + u8 priority; + u8 resvd; +}; + +struct bfa_qos_vc_attr_s { + u16 total_vc_count; /* Total VC Count */ + u16 shared_credit; + u32 elp_opmode_flags; + struct bfa_qos_vc_info_s vc_info[BFA_QOS_MAX_VC]; /* as many as + * total_vc_count */ +}; + +/** + * QoS statistics + */ +struct bfa_qos_stats_s { + u32 flogi_sent; /* QoS Flogi sent */ + u32 flogi_acc_recvd; /* QoS Flogi Acc received */ + u32 flogi_rjt_recvd; /* QoS Flogi rejects received */ + u32 flogi_retries; /* QoS Flogi retries */ + + u32 elp_recvd; /* QoS ELP received */ + u32 elp_accepted; /* QoS ELP Accepted */ + u32 elp_rejected; /* QoS ELP rejected */ + u32 elp_dropped; /* QoS ELP dropped */ + + u32 qos_rscn_recvd; /* QoS RSCN received */ + u32 rsvd; /* padding for 64 bit alignment */ +}; + +/** + * FCoE statistics + */ +struct bfa_fcoe_stats_s { + u64 secs_reset; /* Seconds since stats reset */ + u64 cee_linkups; /* CEE link up */ + u64 cee_linkdns; /* CEE link down */ + u64 fip_linkups; /* FIP link up */ + u64 fip_linkdns; /* FIP link down */ + u64 fip_fails; /* FIP failures */ + u64 mac_invalids; /* Invalid mac assignments */ + u64 vlan_req; /* Vlan requests */ + u64 vlan_notify; /* Vlan notifications */ + u64 vlan_err; /* Vlan notification errors */ + u64 vlan_timeouts; /* Vlan request timeouts */ + u64 vlan_invalids; /* Vlan invalids */ + u64 disc_req; /* Discovery requests */ + u64 disc_rsp; /* Discovery responses */ + u64 disc_err; /* Discovery error frames */ + u64 disc_unsol; /* Discovery unsolicited */ + u64 disc_timeouts; /* Discovery timeouts */ + 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 logos received */ + u64 clrvlink_req; /* Clear virtual link requests */ + u64 op_unsupp; /* FIP operation unsupp. */ + u64 untagged; /* FIP untagged frames */ + u64 txf_ucast; /* Tx FCoE unicast frames */ + u64 txf_ucast_vlan; /* Tx FCoE unicast vlan frames */ + u64 txf_ucast_octets; /* Tx FCoE unicast octets */ + u64 txf_mcast; /* Tx FCoE multicast frames */ + u64 txf_mcast_vlan; /* Tx FCoE multicast vlan frames */ + u64 txf_mcast_octets; /* Tx FCoE multicast octets */ + u64 txf_bcast; /* Tx FCoE broadcast frames */ + u64 txf_bcast_vlan; /* Tx FCoE broadcast vlan frames */ + u64 txf_bcast_octets; /* Tx FCoE broadcast octets */ + u64 txf_timeout; /* Tx timeouts */ + u64 txf_parity_errors; /* Transmit parity err */ + u64 txf_fid_parity_errors; /* Transmit FID parity err */ + 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 */ +}; + +/** + * QoS or FCoE stats (fcport stats excluding physical FC port stats) + */ +union bfa_fcport_stats_u { + struct bfa_qos_stats_s fcqos; + struct bfa_fcoe_stats_s fcoe; +}; +#pragma pack() + +struct bfa_fcpim_del_itn_stats_s { + u32 del_itn_iocomp_aborted; /* Aborted IO requests */ + u32 del_itn_iocomp_timedout; /* IO timeouts */ + u32 del_itn_iocom_sqer_needed; /* IO retry for SQ error recovery */ + u32 del_itn_iocom_res_free; /* Delayed freeing of IO resources */ + u32 del_itn_iocom_hostabrts; /* Host IO abort requests */ + u32 del_itn_total_ios; /* Total IO count */ + u32 del_io_iocdowns; /* IO cleaned-up due to IOC down */ + u32 del_tm_iocdowns; /* TM cleaned-up due to IOC down */ +}; + +struct bfa_itnim_iostats_s { + + u32 total_ios; /* Total IO Requests */ + u32 input_reqs; /* Data in-bound requests */ + u32 output_reqs; /* Data out-bound requests */ + u32 io_comps; /* Total IO Completions */ + u32 wr_throughput; /* Write data transfered in bytes */ + u32 rd_throughput; /* Read data transfered in bytes */ + + u32 iocomp_ok; /* Slowpath IO completions */ + u32 iocomp_underrun; /* IO underrun */ + u32 iocomp_overrun; /* IO overrun */ + u32 qwait; /* IO Request-Q wait */ + u32 qresumes; /* IO Request-Q wait done */ + u32 no_iotags; /* No free IO tag */ + u32 iocomp_timedout; /* IO timeouts */ + u32 iocom_nexus_abort; /* IO failure due to target offline */ + u32 iocom_proto_err; /* IO protocol errors */ + u32 iocom_dif_err; /* IO SBC-3 protection errors */ + + u32 iocom_sqer_needed; /* fcp-2 error recovery failed */ + u32 iocom_res_free; /* Delayed freeing of IO tag */ + + + u32 io_aborts; /* Host IO abort requests */ + u32 iocom_hostabrts; /* Host IO abort completions */ + u32 io_cleanups; /* IO clean-up requests */ + u32 path_tov_expired; /* IO path tov expired */ + u32 iocomp_aborted; /* IO abort completions */ + u32 io_iocdowns; /* IO cleaned-up due to IOC down */ + u32 iocom_utags; /* IO comp with unknown tags */ + + u32 io_tmaborts; /* Abort request due to TM command */ + u32 tm_io_comps; /* Abort completion due to TM command */ + + u32 creates; /* IT Nexus create requests */ + u32 fw_create; /* IT Nexus FW create requests */ + u32 create_comps; /* IT Nexus FW create completions */ + u32 onlines; /* IT Nexus onlines */ + u32 offlines; /* IT Nexus offlines */ + u32 fw_delete; /* IT Nexus FW delete requests */ + u32 delete_comps; /* IT Nexus FW delete completions */ + u32 deletes; /* IT Nexus delete requests */ + u32 sler_events; /* SLER events */ + u32 ioc_disabled; /* Num IOC disables */ + u32 cleanup_comps; /* IT Nexus cleanup completions */ + + u32 tm_cmnds; /* TM Requests */ + u32 tm_fw_rsps; /* TM Completions */ + u32 tm_success; /* TM initiated IO cleanup success */ + u32 tm_failures; /* TM initiated IO cleanup failure */ + u32 no_tskims; /* No free TM tag */ + u32 tm_qwait; /* TM Request-Q wait */ + u32 tm_qresumes; /* TM Request-Q wait done */ + + u32 tm_iocdowns; /* TM cleaned-up due to IOC down */ + u32 tm_cleanups; /* TM cleanup requests */ + u32 tm_cleanup_comps; /* TM cleanup completions */ +}; + +/* Modify char* port_stt[] in bfal_port.c if a new state was added */ +enum bfa_port_states { + BFA_PORT_ST_UNINIT = 1, + BFA_PORT_ST_ENABLING_QWAIT = 2, + BFA_PORT_ST_ENABLING = 3, + BFA_PORT_ST_LINKDOWN = 4, + BFA_PORT_ST_LINKUP = 5, + BFA_PORT_ST_DISABLING_QWAIT = 6, + BFA_PORT_ST_DISABLING = 7, + BFA_PORT_ST_DISABLED = 8, + BFA_PORT_ST_STOPPED = 9, + BFA_PORT_ST_IOCDOWN = 10, + BFA_PORT_ST_IOCDIS = 11, + BFA_PORT_ST_FWMISMATCH = 12, + BFA_PORT_ST_PREBOOT_DISABLED = 13, + BFA_PORT_ST_TOGGLING_QWAIT = 14, + BFA_PORT_ST_MAX_STATE, +}; + +/** + * Port operational type (in sync with SNIA port type). + */ +enum bfa_port_type { + BFA_PORT_TYPE_UNKNOWN = 1, /* port type is unknown */ + BFA_PORT_TYPE_NPORT = 5, /* P2P with switched fabric */ + BFA_PORT_TYPE_NLPORT = 6, /* public loop */ + BFA_PORT_TYPE_LPORT = 20, /* private loop */ + BFA_PORT_TYPE_P2P = 21, /* P2P with no switched fabric */ + BFA_PORT_TYPE_VPORT = 22, /* NPIV - virtual port */ +}; + +/** + * Port topology setting. A port's topology and fabric login status + * determine its operational type. + */ +enum bfa_port_topology { + BFA_PORT_TOPOLOGY_NONE = 0, /* No valid topology */ + BFA_PORT_TOPOLOGY_P2P = 1, /* P2P only */ + BFA_PORT_TOPOLOGY_LOOP = 2, /* LOOP topology */ + BFA_PORT_TOPOLOGY_AUTO = 3, /* auto topology selection */ +}; + +/** + * Physical port loopback types. + */ +enum bfa_port_opmode { + BFA_PORT_OPMODE_NORMAL = 0x00, /* normal non-loopback mode */ + BFA_PORT_OPMODE_LB_INT = 0x01, /* internal loop back */ + BFA_PORT_OPMODE_LB_SLW = 0x02, /* serial link wrapback (serdes) */ + BFA_PORT_OPMODE_LB_EXT = 0x04, /* external loop back (serdes) */ + BFA_PORT_OPMODE_LB_CBL = 0x08, /* cabled loop back */ + BFA_PORT_OPMODE_LB_NLINT = 0x20, /* NL_Port internal loopback */ +}; + +#define BFA_PORT_OPMODE_LB_HARD(_mode) \ + ((_mode == BFA_PORT_OPMODE_LB_INT) || \ + (_mode == BFA_PORT_OPMODE_LB_SLW) || \ + (_mode == BFA_PORT_OPMODE_LB_EXT)) + +/** + * Port link state + */ +enum bfa_port_linkstate { + BFA_PORT_LINKUP = 1, /* Physical port/Trunk link up */ + BFA_PORT_LINKDOWN = 2, /* Physical port/Trunk link down */ +}; + +/** + * Port link state reason code + */ +enum bfa_port_linkstate_rsn { + BFA_PORT_LINKSTATE_RSN_NONE = 0, + BFA_PORT_LINKSTATE_RSN_DISABLED = 1, + BFA_PORT_LINKSTATE_RSN_RX_NOS = 2, + BFA_PORT_LINKSTATE_RSN_RX_OLS = 3, + BFA_PORT_LINKSTATE_RSN_RX_LIP = 4, + BFA_PORT_LINKSTATE_RSN_RX_LIPF7 = 5, + BFA_PORT_LINKSTATE_RSN_SFP_REMOVED = 6, + BFA_PORT_LINKSTATE_RSN_PORT_FAULT = 7, + BFA_PORT_LINKSTATE_RSN_RX_LOS = 8, + BFA_PORT_LINKSTATE_RSN_LOCAL_FAULT = 9, + BFA_PORT_LINKSTATE_RSN_REMOTE_FAULT = 10, + BFA_PORT_LINKSTATE_RSN_TIMEOUT = 11, + + + + /* CEE related reason codes/errors */ + CEE_LLDP_INFO_AGED_OUT = 20, + CEE_LLDP_SHUTDOWN_TLV_RCVD = 21, + CEE_PEER_NOT_ADVERTISE_DCBX = 22, + CEE_PEER_NOT_ADVERTISE_PG = 23, + CEE_PEER_NOT_ADVERTISE_PFC = 24, + CEE_PEER_NOT_ADVERTISE_FCOE = 25, + CEE_PG_NOT_COMPATIBLE = 26, + CEE_PFC_NOT_COMPATIBLE = 27, + CEE_FCOE_NOT_COMPATIBLE = 28, + CEE_BAD_PG_RCVD = 29, + CEE_BAD_BW_RCVD = 30, + CEE_BAD_PFC_RCVD = 31, + CEE_BAD_APP_PRI_RCVD = 32, + CEE_FCOE_PRI_PFC_OFF = 33, + CEE_DUP_CONTROL_TLV_RCVD = 34, + CEE_DUP_FEAT_TLV_RCVD = 35, + CEE_APPLY_NEW_CFG = 36, /* reason, not error */ + CEE_PROTOCOL_INIT = 37, /* reason, not error */ + CEE_PHY_LINK_DOWN = 38, + CEE_LLS_FCOE_ABSENT = 39, + CEE_LLS_FCOE_DOWN = 40, + CEE_ISCSI_NOT_COMPATIBLE = 41, + CEE_ISCSI_PRI_PFC_OFF = 42, + CEE_ISCSI_PRI_OVERLAP_FCOE_PRI = 43 +}; +#pragma pack(1) +/** + * Physical port configuration + */ +struct bfa_port_cfg_s { + u8 topology; /* bfa_port_topology */ + u8 speed; /* enum bfa_port_speed */ + u8 trunked; /* trunked or not */ + u8 qos_enabled; /* qos enabled or not */ + u8 cfg_hardalpa; /* is hard alpa configured */ + u8 hardalpa; /* configured hard alpa */ + u16 maxfrsize; /* maximum frame size */ + u8 rx_bbcredit; /* receive buffer credits */ + u8 tx_bbcredit; /* transmit buffer credits */ + u8 ratelimit; /* ratelimit enabled or not */ + u8 trl_def_speed; /* ratelimit default speed */ + u16 path_tov; /* device path timeout */ + u16 q_depth; /* SCSI Queue depth */ +}; +#pragma pack() + +/** + * Port attribute values. + */ +struct bfa_port_attr_s { + /* + * Static fields + */ + 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 */ + enum bfa_port_speed speed_supported; /* supported speeds */ + bfa_boolean_t pbind_enabled; + + /* + * Configured values + */ + struct bfa_port_cfg_s pport_cfg; /* pport cfg */ + + /* + * Dynamic field - info from BFA + */ + enum bfa_port_states port_state; /* current port state */ + enum bfa_port_speed speed; /* current speed */ + enum bfa_port_topology topology; /* current topology */ + bfa_boolean_t beacon; /* current beacon status */ + bfa_boolean_t link_e2e_beacon; /* link beacon is on */ + bfa_boolean_t plog_enabled; /* portlog is enabled */ + + /* + * Dynamic field - info from FCS + */ + u32 pid; /* port ID */ + enum bfa_port_type port_type; /* current topology */ + u32 loopback; /* external loopback */ + u32 authfail; /* auth fail state */ + bfa_boolean_t io_profile; /* get it from fcpim mod */ + u8 pad[4]; /* for 64-bit alignement */ + + /* FCoE specific */ + u16 fcoe_vlan; + u8 rsvd1[6]; +}; + +/** + * Port FCP mappings. + */ +struct bfa_port_fcpmap_s { + char osdevname[256]; + u32 bus; + u32 target; + u32 oslun; + u32 fcid; + wwn_t nwwn; + wwn_t pwwn; + u64 fcplun; + char luid[256]; +}; + +/** + * Port RNID info. + */ +struct bfa_port_rnid_s { + wwn_t wwn; + u32 unittype; + u32 portid; + u32 attached_nodes_num; + u16 ip_version; + u16 udp_port; + u8 ipaddr[16]; + u16 rsvd; + u16 topologydiscoveryflags; +}; + +#pragma pack(1) +struct bfa_fcport_fcf_s { + wwn_t name; /* FCF name */ + wwn_t fabric_name; /* Fabric Name */ + u8 fipenabled; /* FIP enabled or not */ + u8 fipfailed; /* FIP failed or not */ + u8 resv[2]; + u8 pri; /* FCF priority */ + u8 version; /* FIP version used */ + u8 available; /* Available for login */ + u8 fka_disabled; /* FKA is disabled */ + u8 maxsz_verified; /* FCoE max size verified */ + u8 fc_map[3]; /* FC map */ + u16 vlan; /* FCoE vlan tag/priority */ + u32 fka_adv_per; /* FIP ka advert. period */ + mac_t mac; /* FCF mac */ +}; + +/** + * Trunk states for BCU/BFAL + */ +enum bfa_trunk_state { + BFA_TRUNK_DISABLED = 0, /* Trunk is not configured */ + BFA_TRUNK_ONLINE = 1, /* Trunk is online */ + BFA_TRUNK_OFFLINE = 2, /* Trunk is offline */ +}; + +/** + * VC attributes for trunked link + */ +struct bfa_trunk_vc_attr_s { + u32 bb_credit; + u32 elp_opmode_flags; + u32 req_credit; + u16 vc_credits[8]; +}; + +/** + * Link state information + */ +struct bfa_port_link_s { + u8 linkstate; /* Link state bfa_port_linkstate */ + u8 linkstate_rsn; /* bfa_port_linkstate_rsn_t */ + u8 topology; /* P2P/LOOP bfa_port_topology */ + u8 speed; /* Link speed (1/2/4/8 G) */ + u32 linkstate_opt; /* Linkstate optional data (debug) */ + u8 trunked; /* Trunked or not (1 or 0) */ + u8 resvd[3]; + struct bfa_qos_attr_s qos_attr; /* QoS Attributes */ + union { + struct bfa_qos_vc_attr_s qos_vc_attr; /* VC info from ELP */ + struct bfa_trunk_vc_attr_s trunk_vc_attr; + struct bfa_fcport_fcf_s fcf; /* FCF information (for FCoE) */ + } vc_fcf; +}; +#pragma pack() + +enum bfa_trunk_link_fctl { + BFA_TRUNK_LINK_FCTL_NORMAL, + BFA_TRUNK_LINK_FCTL_VC, + BFA_TRUNK_LINK_FCTL_VC_QOS, +}; + +enum bfa_trunk_link_state { + BFA_TRUNK_LINK_STATE_UP = 1, /* link part of trunk */ + BFA_TRUNK_LINK_STATE_DN_LINKDN = 2, /* physical link down */ + BFA_TRUNK_LINK_STATE_DN_GRP_MIS = 3, /* trunk group different */ + BFA_TRUNK_LINK_STATE_DN_SPD_MIS = 4, /* speed mismatch */ + BFA_TRUNK_LINK_STATE_DN_MODE_MIS = 5, /* remote port not trunked */ +}; + +#define BFA_TRUNK_MAX_PORTS 2 +struct bfa_trunk_link_attr_s { + wwn_t trunk_wwn; + enum bfa_trunk_link_fctl fctl; + enum bfa_trunk_link_state link_state; + enum bfa_port_speed speed; + u32 deskew; +}; + +struct bfa_trunk_attr_s { + enum bfa_trunk_state state; + enum bfa_port_speed speed; + u32 port_id; + u32 rsvd; + struct bfa_trunk_link_attr_s link_attr[BFA_TRUNK_MAX_PORTS]; +}; + +struct bfa_rport_hal_stats_s { + u32 sm_un_cr; /* uninit: create events */ + u32 sm_un_unexp; /* uninit: exception events */ + u32 sm_cr_on; /* created: online events */ + u32 sm_cr_del; /* created: delete events */ + u32 sm_cr_hwf; /* created: IOC down */ + u32 sm_cr_unexp; /* created: exception events */ + u32 sm_fwc_rsp; /* fw create: f/w responses */ + u32 sm_fwc_del; /* fw create: delete events */ + u32 sm_fwc_off; /* fw create: offline events */ + u32 sm_fwc_hwf; /* fw create: IOC down */ + u32 sm_fwc_unexp; /* fw create: exception events*/ + u32 sm_on_off; /* online: offline events */ + u32 sm_on_del; /* online: delete events */ + u32 sm_on_hwf; /* online: IOC down events */ + u32 sm_on_unexp; /* online: exception events */ + u32 sm_fwd_rsp; /* fw delete: fw responses */ + u32 sm_fwd_del; /* fw delete: delete events */ + u32 sm_fwd_hwf; /* fw delete: IOC down events */ + u32 sm_fwd_unexp; /* fw delete: exception events*/ + u32 sm_off_del; /* offline: delete events */ + u32 sm_off_on; /* offline: online events */ + u32 sm_off_hwf; /* offline: IOC down events */ + u32 sm_off_unexp; /* offline: exception events */ + u32 sm_del_fwrsp; /* delete: fw responses */ + u32 sm_del_hwf; /* delete: IOC down events */ + u32 sm_del_unexp; /* delete: exception events */ + u32 sm_delp_fwrsp; /* delete pend: fw responses */ + u32 sm_delp_hwf; /* delete pend: IOC downs */ + u32 sm_delp_unexp; /* delete pend: exceptions */ + u32 sm_offp_fwrsp; /* off-pending: fw responses */ + u32 sm_offp_del; /* off-pending: deletes */ + u32 sm_offp_hwf; /* off-pending: IOC downs */ + u32 sm_offp_unexp; /* off-pending: exceptions */ + u32 sm_iocd_off; /* IOC down: offline events */ + u32 sm_iocd_del; /* IOC down: delete events */ + u32 sm_iocd_on; /* IOC down: online events */ + u32 sm_iocd_unexp; /* IOC down: exceptions */ + u32 rsvd; +}; +#pragma pack(1) +/** + * Rport's QoS attributes + */ +struct bfa_rport_qos_attr_s { + u8 qos_priority; /* rport's QoS priority */ + u8 rsvd[3]; + u32 qos_flow_id; /* QoS flow Id */ +}; +#pragma pack() + +#define BFA_IOBUCKET_MAX 14 + +struct bfa_itnim_latency_s { + u32 min[BFA_IOBUCKET_MAX]; + u32 max[BFA_IOBUCKET_MAX]; + u32 count[BFA_IOBUCKET_MAX]; + u32 avg[BFA_IOBUCKET_MAX]; +}; + +struct bfa_itnim_ioprofile_s { + u32 clock_res_mul; + u32 clock_res_div; + u32 index; + u32 io_profile_start_time; /* IO profile start time */ + u32 iocomps[BFA_IOBUCKET_MAX]; /* IO completed */ + struct bfa_itnim_latency_s io_latency; +}; + +/** + * FC physical port statistics. + */ +struct bfa_port_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_nos; /* Tx NOS */ + u64 tx_ols; /* Tx OLS */ + u64 tx_lr; /* Tx LR */ + u64 tx_lrr; /* Tx LRR */ + u64 rx_frames; /* Rx frames */ + u64 rx_words; /* Rx words */ + u64 lip_count; /* Rx LIP */ + u64 nos_count; /* Rx NOS */ + u64 ols_count; /* Rx OLS */ + u64 lr_count; /* Rx LR */ + u64 lrr_count; /* Rx LRR */ + u64 invalid_crcs; /* Rx CRC err frames */ + u64 invalid_crc_gd_eof; /* Rx CRC err good EOF frames */ + u64 undersized_frm; /* Rx undersized frames */ + u64 oversized_frm; /* Rx oversized frames */ + u64 bad_eof_frm; /* Rx frames with bad EOF */ + u64 error_frames; /* Errored frames */ + u64 dropped_frames; /* Dropped frames */ + u64 link_failures; /* Link Failure (LF) count */ + u64 loss_of_syncs; /* Loss of sync count */ + u64 loss_of_signals; /* Loss of signal count */ + u64 primseq_errs; /* Primitive sequence protocol err. */ + u64 bad_os_count; /* Invalid ordered sets */ + u64 err_enc_out; /* Encoding err nonframe_8b10b */ + u64 err_enc; /* Encoding err frame_8b10b */ +}; + +/** + * Eth Physical Port statistics. + */ +struct bfa_port_eth_stats_s { + u64 secs_reset; /* Seconds since stats is reset */ + u64 frame_64; /* Frames 64 bytes */ + u64 frame_65_127; /* Frames 65-127 bytes */ + u64 frame_128_255; /* Frames 128-255 bytes */ + u64 frame_256_511; /* Frames 256-511 bytes */ + u64 frame_512_1023; /* Frames 512-1023 bytes */ + u64 frame_1024_1518; /* Frames 1024-1518 bytes */ + u64 frame_1519_1522; /* Frames 1519-1522 bytes */ + u64 tx_bytes; /* Tx bytes */ + u64 tx_packets; /* Tx packets */ + u64 tx_mcast_packets; /* Tx multicast packets */ + u64 tx_bcast_packets; /* Tx broadcast packets */ + u64 tx_control_frame; /* Tx control frame */ + u64 tx_drop; /* Tx drops */ + u64 tx_jabber; /* Tx jabber */ + u64 tx_fcs_error; /* Tx FCS errors */ + u64 tx_fragments; /* Tx fragments */ + u64 rx_bytes; /* Rx bytes */ + u64 rx_packets; /* Rx packets */ + u64 rx_mcast_packets; /* Rx multicast packets */ + u64 rx_bcast_packets; /* Rx broadcast packets */ + u64 rx_control_frames; /* Rx control frames */ + u64 rx_unknown_opcode; /* Rx unknown opcode */ + u64 rx_drop; /* Rx drops */ + u64 rx_jabber; /* Rx jabber */ + u64 rx_fcs_error; /* Rx FCS errors */ + u64 rx_alignment_error; /* Rx alignment errors */ + u64 rx_frame_length_error; /* Rx frame len errors */ + u64 rx_code_error; /* Rx code errors */ + u64 rx_fragments; /* Rx fragments */ + u64 rx_pause; /* Rx pause */ + 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_zero_pause; /* Rx FCoE zero pause */ + u64 tx_fcoe_pause; /* Tx FCoE pause */ + u64 tx_fcoe_zero_pause; /* Tx FCoE zero pause */ + u64 rx_iscsi_pause; /* Rx iSCSI pause */ + u64 rx_iscsi_zero_pause; /* Rx iSCSI zero pause */ + u64 tx_iscsi_pause; /* Tx iSCSI pause */ + u64 tx_iscsi_zero_pause; /* Tx iSCSI zero pause */ +}; + +/** + * Port statistics. + */ +union bfa_port_stats_u { + struct bfa_port_fc_stats_s fc; + struct bfa_port_eth_stats_s eth; +}; + +#endif /* __BFA_DEFS_SVC_H__ */ diff --git a/drivers/scsi/bfa/bfa_module.c b/drivers/scsi/bfa/bfa_drv.c index a7fcc80c177e..14127646dc54 100644 --- a/drivers/scsi/bfa/bfa_module.c +++ b/drivers/scsi/bfa/bfa_drv.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. * All rights reserved * www.brocade.com * @@ -14,10 +14,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. */ -#include <bfa.h> -#include <defs/bfa_defs_pci.h> -#include <cs/bfa_debug.h> -#include <bfa_iocfc.h> + +#include "bfa_modules.h" /** * BFA module list terminated by NULL @@ -30,9 +28,6 @@ struct bfa_module_s *hal_mods[] = { &hal_mod_uf, &hal_mod_rport, &hal_mod_fcpim, -#ifdef BFA_CFG_PBIND - &hal_mod_pbind, -#endif NULL }; @@ -74,17 +69,39 @@ bfa_isr_func_t bfa_isrs[BFI_MC_MAX] = { bfa_isr_unhandled, /* --------- */ }; + /** * Message handlers for mailbox command classes */ bfa_ioc_mbox_mcfunc_t bfa_mbox_isrs[BFI_MC_MAX] = { NULL, - NULL, /* BFI_MC_IOC */ - NULL, /* BFI_MC_DIAG */ + NULL, /* BFI_MC_IOC */ + NULL, /* BFI_MC_DIAG */ NULL, /* BFI_MC_FLASH */ - NULL, /* BFI_MC_CEE */ - NULL, /* BFI_MC_PORT */ + NULL, /* BFI_MC_CEE */ + NULL, /* BFI_MC_PORT */ bfa_iocfc_isr, /* BFI_MC_IOCFC */ NULL, }; + + +void +bfa_com_port_attach(struct bfa_s *bfa, struct bfa_meminfo_s *mi) +{ + struct bfa_port_s *port = &bfa->modules.port; + u32 dm_len; + u8 *dm_kva; + u64 dm_pa; + + dm_len = bfa_port_meminfo(); + dm_kva = bfa_meminfo_dma_virt(mi); + dm_pa = bfa_meminfo_dma_phys(mi); + + memset(port, 0, sizeof(struct bfa_port_s)); + bfa_port_attach(port, &bfa->ioc, bfa, bfa->trcmod); + bfa_port_mem_claim(port, dm_kva, dm_pa); + + bfa_meminfo_dma_virt(mi) = dm_kva + dm_len; + bfa_meminfo_dma_phys(mi) = dm_pa + dm_len; +} diff --git a/drivers/scsi/bfa/include/protocol/fc.h b/drivers/scsi/bfa/bfa_fc.h index 436dd7c5643a..6eff705564eb 100644 --- a/drivers/scsi/bfa/include/protocol/fc.h +++ b/drivers/scsi/bfa/bfa_fc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. * All rights reserved * www.brocade.com * @@ -15,13 +15,50 @@ * General Public License for more details. */ -#ifndef __FC_H__ -#define __FC_H__ +#ifndef __BFA_FC_H__ +#define __BFA_FC_H__ -#include <protocol/types.h> +#include "bfa_os_inc.h" + +typedef u64 wwn_t; +typedef u64 lun_t; + +#define WWN_NULL (0) +#define FC_SYMNAME_MAX 256 /* max name server symbolic name size */ +#define FC_ALPA_MAX 128 #pragma pack(1) +#define MAC_ADDRLEN (6) +struct mac_s { u8 mac[MAC_ADDRLEN]; }; +#define mac_t struct mac_s + +/* + * generic SCSI cdb definition + */ +#define SCSI_MAX_CDBLEN 16 +struct scsi_cdb_s { + u8 scsi_cdb[SCSI_MAX_CDBLEN]; +}; +#define scsi_cdb_t struct scsi_cdb_s + +/* ------------------------------------------------------------ + * SCSI status byte values + * ------------------------------------------------------------ + */ +#define SCSI_STATUS_GOOD 0x00 +#define SCSI_STATUS_CHECK_CONDITION 0x02 +#define SCSI_STATUS_CONDITION_MET 0x04 +#define SCSI_STATUS_BUSY 0x08 +#define SCSI_STATUS_INTERMEDIATE 0x10 +#define SCSI_STATUS_ICM 0x14 /* intermediate condition met */ +#define SCSI_STATUS_RESERVATION_CONFLICT 0x18 +#define SCSI_STATUS_COMMAND_TERMINATED 0x22 +#define SCSI_STATUS_QUEUE_FULL 0x28 +#define SCSI_STATUS_ACA_ACTIVE 0x30 + +#define SCSI_MAX_ALLOC_LEN 0xFF /* maximum allocarion length */ + /* * Fibre Channel Header Structure (FCHS) definition */ @@ -51,9 +88,9 @@ struct fchs_s { u32 ro; /* relative offset */ }; -#define FC_SOF_LEN 4 -#define FC_EOF_LEN 4 -#define FC_CRC_LEN 4 +#define FC_SOF_LEN 4 +#define FC_EOF_LEN 4 +#define FC_CRC_LEN 4 /* * Fibre Channel BB_E Header Structure @@ -140,10 +177,12 @@ enum { FC_TYPE_FC_FSS = 0x22, /* Fabric Switch Services */ FC_TYPE_FC_AL = 0x23, /* FC-AL */ FC_TYPE_FC_SNMP = 0x24, /* FC-SNMP */ + FC_TYPE_FC_SPINFAB = 0xEE, /* SPINFAB */ + FC_TYPE_FC_DIAG = 0xEF, /* DIAG */ FC_TYPE_MAX = 256, /* 256 FC-4 types */ }; -struct fc_fc4types_s{ +struct fc_fc4types_s { u8 bits[FC_TYPE_MAX / 8]; }; @@ -168,7 +207,7 @@ enum { */ enum { FC_MIN_WELL_KNOWN_ADDR = 0xFFFFF0, - FC_DOMAIN_CONTROLLER_MASK = 0xFFFC00, + FC_DOMAIN_CONTROLLER_MASK = 0xFFFC00, FC_ALIAS_SERVER = 0xFFFFF8, FC_MGMT_SERVER = 0xFFFFFA, FC_TIME_SERVER = 0xFFFFFB, @@ -201,7 +240,7 @@ enum { /* * generic ELS command */ -struct fc_els_cmd_s{ +struct fc_els_cmd_s { u32 els_code:8; /* ELS Command Code */ u32 reserved:24; }; @@ -233,6 +272,8 @@ enum { FC_ELS_PDISC = 0x50, /* Discover N_Port Parameters. */ FC_ELS_FDISC = 0x51, /* Discover F_Port Parameters. */ FC_ELS_ADISC = 0x52, /* Discover Address. */ + FC_ELS_FARP_REQ = 0x54, /* FARP Request. */ + FC_ELS_FARP_REP = 0x55, /* FARP Reply. */ FC_ELS_FAN = 0x60, /* Fabric Address Notification */ FC_ELS_RSCN = 0x61, /* Reg State Change Notification */ FC_ELS_SCR = 0x62, /* State Change Registration. */ @@ -272,7 +313,7 @@ enum { * N_Port PLOGI Common Service Parameters. * FC-PH-x. Figure-76. pg. 308. */ -struct fc_plogi_csp_s{ +struct fc_plogi_csp_s { u8 verhi; /* FC-PH high version */ u8 verlo; /* FC-PH low version */ u16 bbcred; /* BB_Credit */ @@ -326,7 +367,7 @@ struct fc_plogi_csp_s{ * N_Port PLOGI Class Specific Parameters. * FC-PH-x. Figure 78. pg. 318. */ -struct fc_plogi_clp_s{ +struct fc_plogi_clp_s { #ifdef __BIGENDIAN u32 class_valid:1; u32 intermix:1; /* class intermix supported if set =1. @@ -361,29 +402,29 @@ struct fc_plogi_clp_s{ u32 reserved8:16; }; -#define FLOGI_VVL_BRCD 0x42524344 /* ASCII value for each character in - * string "BRCD" */ +/* ASCII value for each character in string "BRCD" */ +#define FLOGI_VVL_BRCD 0x42524344 /* * PLOGI els command and reply payload */ -struct fc_logi_s{ +struct fc_logi_s { struct fc_els_cmd_s els_cmd; /* ELS command code */ - struct fc_plogi_csp_s csp; /* common service params */ + struct fc_plogi_csp_s csp; /* common service params */ wwn_t port_name; wwn_t node_name; - struct fc_plogi_clp_s class1; /* class 1 service parameters */ - struct fc_plogi_clp_s class2; /* class 2 service parameters */ - struct fc_plogi_clp_s class3; /* class 3 service parameters */ - struct fc_plogi_clp_s class4; /* class 4 service parameters */ + struct fc_plogi_clp_s class1; /* class 1 service parameters */ + struct fc_plogi_clp_s class2; /* class 2 service parameters */ + struct fc_plogi_clp_s class3; /* class 3 service parameters */ + struct fc_plogi_clp_s class4; /* class 4 service parameters */ u8 vvl[16]; /* vendor version level */ }; /* * LOGO els command payload */ -struct fc_logo_s{ - struct fc_els_cmd_s els_cmd; /* ELS command code */ +struct fc_logo_s { + struct fc_els_cmd_s els_cmd; /* ELS command code */ u32 res1:8; u32 nport_id:24; /* N_Port identifier of source */ wwn_t orig_port_name; /* Port name of the LOGO originator */ @@ -393,7 +434,7 @@ struct fc_logo_s{ * ADISC els command payload */ struct fc_adisc_s { - struct fc_els_cmd_s els_cmd; /* ELS command code */ + struct fc_els_cmd_s els_cmd; /* ELS command code */ u32 res1:8; u32 orig_HA:24; /* originator hard address */ wwn_t orig_port_name; /* originator port name */ @@ -405,7 +446,7 @@ struct fc_adisc_s { /* * Exchange status block */ -struct fc_exch_status_blk_s{ +struct fc_exch_status_blk_s { u32 oxid:16; u32 rxid:16; u32 res1:8; @@ -423,7 +464,7 @@ struct fc_exch_status_blk_s{ * RES els command payload */ struct fc_res_s { - struct fc_els_cmd_s els_cmd; /* ELS command code */ + struct fc_els_cmd_s els_cmd; /* ELS command code */ u32 res1:8; u32 nport_id:24; /* N_Port identifier of source */ u32 oxid:16; @@ -434,16 +475,16 @@ struct fc_res_s { /* * RES els accept payload */ -struct fc_res_acc_s{ - struct fc_els_cmd_s els_cmd; /* ELS command code */ - struct fc_exch_status_blk_s fc_exch_blk; /* Exchange status block */ +struct fc_res_acc_s { + struct fc_els_cmd_s els_cmd; /* ELS command code */ + struct fc_exch_status_blk_s fc_exch_blk; /* Exchange status block */ }; /* * REC els command payload */ struct fc_rec_s { - struct fc_els_cmd_s els_cmd; /* ELS command code */ + struct fc_els_cmd_s els_cmd; /* ELS command code */ u32 res1:8; u32 nport_id:24; /* N_Port identifier of source */ u32 oxid:16; @@ -451,9 +492,9 @@ struct fc_rec_s { }; #define FC_REC_ESB_OWN_RSP 0x80000000 /* responder owns */ -#define FC_REC_ESB_SI 0x40000000 /* SI is owned */ +#define FC_REC_ESB_SI 0x40000000 /* SI is owned */ #define FC_REC_ESB_COMP 0x20000000 /* exchange is complete */ -#define FC_REC_ESB_ENDCOND_ABN 0x10000000 /* abnormal ending */ +#define FC_REC_ESB_ENDCOND_ABN 0x10000000 /* abnormal ending */ #define FC_REC_ESB_RQACT 0x04000000 /* recovery qual active */ #define FC_REC_ESB_ERRP_MSK 0x03000000 #define FC_REC_ESB_OXID_INV 0x00800000 /* invalid OXID */ @@ -464,7 +505,7 @@ struct fc_rec_s { * REC els accept payload */ struct fc_rec_acc_s { - struct fc_els_cmd_s els_cmd; /* ELS command code */ + struct fc_els_cmd_s els_cmd; /* ELS command code */ u32 oxid:16; u32 rxid:16; u32 res1:8; @@ -479,7 +520,7 @@ struct fc_rec_acc_s { * RSI els payload */ struct fc_rsi_s { - struct fc_els_cmd_s els_cmd; + struct fc_els_cmd_s els_cmd; u32 res1:8; u32 orig_sid:24; u32 oxid:16; @@ -490,7 +531,7 @@ struct fc_rsi_s { * structure for PRLI paramater pages, both request & response * see FC-PH-X table 113 & 115 for explanation also FCP table 8 */ -struct fc_prli_params_s{ +struct fc_prli_params_s { u32 reserved:16; #ifdef __BIGENDIAN u32 reserved1:5; @@ -531,7 +572,7 @@ enum { FC_PRLI_ACC_PREDEF_IMG = 0x5, /* predefined image - no prli needed */ }; -struct fc_prli_params_page_s{ +struct fc_prli_params_page_s { u32 type:8; u32 codext:8; #ifdef __BIGENDIAN @@ -551,13 +592,13 @@ struct fc_prli_params_page_s{ u32 origprocas; u32 rspprocas; - struct fc_prli_params_s servparams; + struct fc_prli_params_s servparams; }; /* * PRLI request and accept payload, FC-PH-X tables 112 & 114 */ -struct fc_prli_s{ +struct fc_prli_s { u32 command:8; u32 pglen:8; u32 pagebytes:16; @@ -567,7 +608,7 @@ struct fc_prli_s{ /* * PRLO logout params page */ -struct fc_prlo_params_page_s{ +struct fc_prlo_params_page_s { u32 type:8; u32 type_ext:8; #ifdef __BIGENDIAN @@ -592,17 +633,17 @@ struct fc_prlo_params_page_s{ /* * PRLO els command payload */ -struct fc_prlo_s{ - u32 command:8; - u32 page_len:8; - u32 payload_len:16; - struct fc_prlo_params_page_s prlo_params[1]; +struct fc_prlo_s { + u32 command:8; + u32 page_len:8; + u32 payload_len:16; + struct fc_prlo_params_page_s prlo_params[1]; }; /* * PRLO Logout response parameter page */ -struct fc_prlo_acc_params_page_s{ +struct fc_prlo_acc_params_page_s { u32 type:8; u32 type_ext:8; @@ -628,7 +669,7 @@ struct fc_prlo_acc_params_page_s{ /* * PRLO els command ACC payload */ -struct fc_prlo_acc_s{ +struct fc_prlo_acc_s { u32 command:8; u32 page_len:8; u32 payload_len:16; @@ -650,7 +691,7 @@ enum { FC_VU_SCR_REG_FUNC_FABRIC_NAME_CHANGE = 0x01 }; -struct fc_scr_s{ +struct fc_scr_s { u32 command:8; u32 res:24; u32 vu_reg_func:8; /* Vendor Unique Registrations */ @@ -674,7 +715,7 @@ enum { * LS_RJT els reply payload */ struct fc_ls_rjt_s { - struct fc_els_cmd_s els_cmd; /* ELS command code */ + struct fc_els_cmd_s els_cmd; /* ELS command code */ u32 res1:8; u32 reason_code:8; /* Reason code for reject */ u32 reason_code_expl:8; /* Reason code explanation */ @@ -722,8 +763,8 @@ enum { /* * RRQ els command payload */ -struct fc_rrq_s{ - struct fc_els_cmd_s els_cmd; /* ELS command code */ +struct fc_rrq_s { + struct fc_els_cmd_s els_cmd; /* ELS command code */ u32 res1:8; u32 s_id:24; /* exchange originator S_ID */ @@ -736,7 +777,7 @@ struct fc_rrq_s{ /* * ABTS BA_ACC reply payload */ -struct fc_ba_acc_s{ +struct fc_ba_acc_s { u32 seq_id_valid:8; /* set to 0x00 for Abort Exchange */ u32 seq_id:8; /* invalid for Abort Exchange */ u32 res2:16; @@ -749,7 +790,7 @@ struct fc_ba_acc_s{ /* * ABTS BA_RJT reject payload */ -struct fc_ba_rjt_s{ +struct fc_ba_rjt_s { u32 res1:8; /* Reserved */ u32 reason_code:8; /* reason code for reject */ u32 reason_expl:8; /* reason code explanation */ @@ -759,9 +800,9 @@ struct fc_ba_rjt_s{ /* * TPRLO logout parameter page */ -struct fc_tprlo_params_page_s{ - u32 type:8; - u32 type_ext:8; +struct fc_tprlo_params_page_s { +u32 type:8; +u32 type_ext:8; #ifdef __BIGENDIAN u32 opa_valid:1; @@ -787,7 +828,7 @@ struct fc_tprlo_params_page_s{ /* * TPRLO ELS command payload */ -struct fc_tprlo_s{ +struct fc_tprlo_s { u32 command:8; u32 page_len:8; u32 payload_len:16; @@ -795,7 +836,7 @@ struct fc_tprlo_s{ struct fc_tprlo_params_page_s tprlo_params[1]; }; -enum fc_tprlo_type{ +enum fc_tprlo_type { FC_GLOBAL_LOGO = 1, FC_TPR_LOGO }; @@ -803,7 +844,7 @@ enum fc_tprlo_type{ /* * TPRLO els command ACC payload */ -struct fc_tprlo_acc_s{ +struct fc_tprlo_acc_s { u32 command:8; u32 page_len:8; u32 payload_len:16; @@ -815,21 +856,21 @@ struct fc_tprlo_acc_s{ */ #define FC_RSCN_PGLEN 0x4 -enum fc_rscn_format{ +enum fc_rscn_format { FC_RSCN_FORMAT_PORTID = 0x0, FC_RSCN_FORMAT_AREA = 0x1, FC_RSCN_FORMAT_DOMAIN = 0x2, FC_RSCN_FORMAT_FABRIC = 0x3, }; -struct fc_rscn_event_s{ +struct fc_rscn_event_s { u32 format:2; u32 qualifier:4; u32 resvd:2; u32 portid:24; }; -struct fc_rscn_pl_s{ +struct fc_rscn_pl_s { u8 command; u8 pagelen; u16 payldlen; @@ -840,18 +881,18 @@ struct fc_rscn_pl_s{ * ECHO els command req payload */ struct fc_echo_s { - struct fc_els_cmd_s els_cmd; + struct fc_els_cmd_s els_cmd; }; /* * RNID els command */ -#define RNID_NODEID_DATA_FORMAT_COMMON 0x00 -#define RNID_NODEID_DATA_FORMAT_FCP3 0x08 -#define RNID_NODEID_DATA_FORMAT_DISCOVERY 0xDF +#define RNID_NODEID_DATA_FORMAT_COMMON 0x00 +#define RNID_NODEID_DATA_FORMAT_FCP3 0x08 +#define RNID_NODEID_DATA_FORMAT_DISCOVERY 0xDF -#define RNID_ASSOCIATED_TYPE_UNKNOWN 0x00000001 +#define RNID_ASSOCIATED_TYPE_UNKNOWN 0x00000001 #define RNID_ASSOCIATED_TYPE_OTHER 0x00000002 #define RNID_ASSOCIATED_TYPE_HUB 0x00000003 #define RNID_ASSOCIATED_TYPE_SWITCH 0x00000004 @@ -868,8 +909,8 @@ struct fc_echo_s { /* * RNID els command payload */ -struct fc_rnid_cmd_s{ - struct fc_els_cmd_s els_cmd; +struct fc_rnid_cmd_s { + struct fc_els_cmd_s els_cmd; u32 node_id_data_format:8; u32 reserved:24; }; @@ -878,12 +919,12 @@ struct fc_rnid_cmd_s{ * RNID els response payload */ -struct fc_rnid_common_id_data_s{ +struct fc_rnid_common_id_data_s { wwn_t port_name; wwn_t node_name; }; -struct fc_rnid_general_topology_data_s{ +struct fc_rnid_general_topology_data_s { u32 vendor_unique[4]; u32 asso_type; u32 phy_port_num; @@ -896,8 +937,8 @@ struct fc_rnid_general_topology_data_s{ u32 vendor_specific:16; }; -struct fc_rnid_acc_s{ - struct fc_els_cmd_s els_cmd; +struct fc_rnid_acc_s { + struct fc_els_cmd_s els_cmd; u32 node_id_data_format:8; u32 common_id_data_length:8; u32 reserved:8; @@ -920,7 +961,7 @@ struct fc_rnid_acc_s{ #define RNID_ASSOCIATED_TYPE_VIRTUALIZATION_DEVICE 0x00000003 #define RNID_ASSOCIATED_TYPE_MULTI_FUNCTION_DEVICE 0x000000FF -enum fc_rpsc_speed_cap{ +enum fc_rpsc_speed_cap { RPSC_SPEED_CAP_1G = 0x8000, RPSC_SPEED_CAP_2G = 0x4000, RPSC_SPEED_CAP_4G = 0x2000, @@ -931,7 +972,7 @@ enum fc_rpsc_speed_cap{ RPSC_SPEED_CAP_UNKNOWN = 0x0001, }; -enum fc_rpsc_op_speed_s{ +enum fc_rpsc_op_speed { RPSC_OP_SPEED_1G = 0x8000, RPSC_OP_SPEED_2G = 0x4000, RPSC_OP_SPEED_4G = 0x2000, @@ -942,24 +983,24 @@ enum fc_rpsc_op_speed_s{ RPSC_OP_SPEED_NOT_EST = 0x0001, /*! speed not established */ }; -struct fc_rpsc_speed_info_s{ - u16 port_speed_cap; /*! see fc_rpsc_speed_cap_t */ - u16 port_op_speed; /*! see fc_rpsc_op_speed_t */ +struct fc_rpsc_speed_info_s { + u16 port_speed_cap; /*! see enum fc_rpsc_speed_cap */ + u16 port_op_speed; /*! see enum fc_rpsc_op_speed */ }; -enum link_e2e_beacon_subcmd{ +enum link_e2e_beacon_subcmd { LINK_E2E_BEACON_ON = 1, LINK_E2E_BEACON_OFF = 2 }; -enum beacon_type{ +enum beacon_type { BEACON_TYPE_NORMAL = 1, /*! Normal Beaconing. Green */ BEACON_TYPE_WARN = 2, /*! Warning Beaconing. Yellow/Amber */ BEACON_TYPE_CRITICAL = 3 /*! Critical Beaconing. Red */ }; struct link_e2e_beacon_param_s { - u8 beacon_type; /* Beacon Type. See beacon_type_t */ + u8 beacon_type; /* Beacon Type. See enum beacon_type */ u8 beacon_frequency; /* Beacon frequency. Number of blinks * per 10 seconds @@ -978,12 +1019,13 @@ struct link_e2e_beacon_param_s { }; /* - * Link E2E beacon request/good response format. For LS_RJTs use fc_ls_rjt_t + * Link E2E beacon request/good response format. + * For LS_RJTs use struct fc_ls_rjt_s */ -struct link_e2e_beacon_req_s{ +struct link_e2e_beacon_req_s { u32 ls_code; /*! FC_ELS_E2E_LBEACON in requests * *or FC_ELS_ACC in good replies */ - u32 ls_sub_cmd; /*! See link_e2e_beacon_subcmd_t */ + u32 ls_sub_cmd; /*! See enum link_e2e_beacon_subcmd */ struct link_e2e_beacon_param_s beacon_parm; }; @@ -992,14 +1034,14 @@ struct link_e2e_beacon_req_s{ * all the ports within that domain (TODO - I don't think FOS implements * this...). */ -struct fc_rpsc_cmd_s{ - struct fc_els_cmd_s els_cmd; +struct fc_rpsc_cmd_s { + struct fc_els_cmd_s els_cmd; }; /* * RPSC Acc */ -struct fc_rpsc_acc_s{ +struct fc_rpsc_acc_s { u32 command:8; u32 rsvd:8; u32 num_entries:16; @@ -1012,51 +1054,50 @@ struct fc_rpsc_acc_s{ */ #define FC_BRCD_TOKEN 0x42524344 -struct fc_rpsc2_cmd_s{ - struct fc_els_cmd_s els_cmd; - u32 token; - u16 resvd; - u16 num_pids; /* Number of pids in the request */ +struct fc_rpsc2_cmd_s { + struct fc_els_cmd_s els_cmd; + u32 token; + u16 resvd; + u16 num_pids; /* Number of pids in the request */ struct { u32 rsvd1:8; - u32 pid:24; /* port identifier */ + u32 pid:24; /* port identifier */ } pid_list[1]; }; -enum fc_rpsc2_port_type{ +enum fc_rpsc2_port_type { RPSC2_PORT_TYPE_UNKNOWN = 0, RPSC2_PORT_TYPE_NPORT = 1, RPSC2_PORT_TYPE_NLPORT = 2, RPSC2_PORT_TYPE_NPIV_PORT = 0x5f, RPSC2_PORT_TYPE_NPORT_TRUNK = 0x6f, }; - /* * RPSC2 portInfo entry structure */ -struct fc_rpsc2_port_info_s{ +struct fc_rpsc2_port_info_s { u32 pid; /* PID */ u16 resvd1; u16 index; /* port number / index */ u8 resvd2; - u8 type; /* port type N/NL/... */ + u8 type; /* port type N/NL/... */ u16 speed; /* port Operating Speed */ }; /* * RPSC2 Accept payload */ -struct fc_rpsc2_acc_s{ +struct fc_rpsc2_acc_s { u8 els_cmd; u8 resvd; - u16 num_pids; /* Number of pids in the request */ - struct fc_rpsc2_port_info_s port_info[1]; /* port information */ + u16 num_pids; /* Number of pids in the request */ + struct fc_rpsc2_port_info_s port_info[1]; /* port information */ }; /** * bit fields so that multiple classes can be specified */ -enum fc_cos{ +enum fc_cos { FC_CLASS_2 = 0x04, FC_CLASS_3 = 0x08, FC_CLASS_2_3 = 0x0C, @@ -1065,11 +1106,11 @@ enum fc_cos{ /* * symbolic name */ -struct fc_symname_s{ +struct fc_symname_s { u8 symname[FC_SYMNAME_MAX]; }; -struct fc_alpabm_s{ +struct fc_alpabm_s { u8 alpa_bm[FC_ALPA_MAX / 8]; }; @@ -1094,7 +1135,7 @@ struct fc_alpabm_s{ * Virtual Fabric Tagging header format * @caution This is defined only in BIG ENDIAN format. */ -struct fc_vft_s{ +struct fc_vft_s { u32 r_ctl:8; u32 ver:2; u32 type:4; @@ -1106,6 +1147,770 @@ struct fc_vft_s{ u32 res_c:24; }; -#pragma pack() +/* + * FCP + */ +enum { + FCP_RJT = 0x01000000, /* SRR reject */ + FCP_SRR_ACCEPT = 0x02000000, /* SRR accept */ + FCP_SRR = 0x14000000, /* Sequence Retransmission Request */ +}; + +/* + * SRR FC-4 LS payload + */ +struct fc_srr_s { + u32 ls_cmd; + u32 ox_id:16; /* ox-id */ + u32 rx_id:16; /* rx-id */ + u32 ro; /* relative offset */ + u32 r_ctl:8; /* R_CTL for I.U. */ + u32 res:24; +}; + + +/* + * FCP_CMND definitions + */ +#define FCP_CMND_CDB_LEN 16 +#define FCP_CMND_LUN_LEN 8 + +struct fcp_cmnd_s { + lun_t lun; /* 64-bit LU number */ + u8 crn; /* command reference number */ +#ifdef __BIGENDIAN + u8 resvd:1, + priority:4, /* FCP-3: SAM-3 priority */ + taskattr:3; /* scsi task attribute */ +#else + u8 taskattr:3, /* scsi task attribute */ + priority:4, /* FCP-3: SAM-3 priority */ + resvd:1; +#endif + u8 tm_flags; /* task management flags */ +#ifdef __BIGENDIAN + u8 addl_cdb_len:6, /* additional CDB length words */ + iodir:2; /* read/write FCP_DATA IUs */ +#else + u8 iodir:2, /* read/write FCP_DATA IUs */ + addl_cdb_len:6; /* additional CDB length */ +#endif + scsi_cdb_t cdb; + + /* + * !!! additional cdb bytes follows here!!! + */ + u32 fcp_dl; /* bytes to be transferred */ +}; + +#define fcp_cmnd_cdb_len(_cmnd) ((_cmnd)->addl_cdb_len * 4 + FCP_CMND_CDB_LEN) +#define fcp_cmnd_fcpdl(_cmnd) ((&(_cmnd)->fcp_dl)[(_cmnd)->addl_cdb_len]) +/* + * struct fcp_cmnd_s .iodir field values + */ +enum fcp_iodir { + FCP_IODIR_NONE = 0, + FCP_IODIR_WRITE = 1, + FCP_IODIR_READ = 2, + FCP_IODIR_RW = 3, +}; + +/* + * Task attribute field + */ +enum { + FCP_TASK_ATTR_SIMPLE = 0, + FCP_TASK_ATTR_HOQ = 1, + FCP_TASK_ATTR_ORDERED = 2, + FCP_TASK_ATTR_ACA = 4, + FCP_TASK_ATTR_UNTAGGED = 5, /* obsolete in FCP-3 */ +}; + +/* + * Task management flags field - only one bit shall be set + */ +enum fcp_tm_cmnd { + FCP_TM_ABORT_TASK_SET = BIT(1), + FCP_TM_CLEAR_TASK_SET = BIT(2), + FCP_TM_LUN_RESET = BIT(4), + FCP_TM_TARGET_RESET = BIT(5), /* obsolete in FCP-3 */ + FCP_TM_CLEAR_ACA = BIT(6), +}; + +/* + * FCP_XFER_RDY IU defines + */ +struct fcp_xfer_rdy_s { + u32 data_ro; + u32 burst_len; + u32 reserved; +}; + +/* + * FCP_RSP residue flags + */ +enum fcp_residue { + FCP_NO_RESIDUE = 0, /* no residue */ + FCP_RESID_OVER = 1, /* more data left that was not sent */ + FCP_RESID_UNDER = 2, /* less data than requested */ +}; + +enum { + FCP_RSPINFO_GOOD = 0, + FCP_RSPINFO_DATALEN_MISMATCH = 1, + FCP_RSPINFO_CMND_INVALID = 2, + FCP_RSPINFO_ROLEN_MISMATCH = 3, + FCP_RSPINFO_TM_NOT_SUPP = 4, + FCP_RSPINFO_TM_FAILED = 5, +}; + +struct fcp_rspinfo_s { + u32 res0:24; + u32 rsp_code:8; /* response code (as above) */ + u32 res1; +}; + +struct fcp_resp_s { + u32 reserved[2]; /* 2 words reserved */ + u16 reserved2; +#ifdef __BIGENDIAN + u8 reserved3:3; + u8 fcp_conf_req:1; /* FCP_CONF is requested */ + u8 resid_flags:2; /* underflow/overflow */ + u8 sns_len_valid:1;/* sense len is valid */ + u8 rsp_len_valid:1;/* response len is valid */ +#else + u8 rsp_len_valid:1;/* response len is valid */ + u8 sns_len_valid:1;/* sense len is valid */ + u8 resid_flags:2; /* underflow/overflow */ + u8 fcp_conf_req:1; /* FCP_CONF is requested */ + u8 reserved3:3; #endif + u8 scsi_status; /* one byte SCSI status */ + u32 residue; /* residual data bytes */ + u32 sns_len; /* length od sense info */ + u32 rsp_len; /* length of response info */ +}; + +#define fcp_snslen(__fcprsp) ((__fcprsp)->sns_len_valid ? \ + (__fcprsp)->sns_len : 0) +#define fcp_rsplen(__fcprsp) ((__fcprsp)->rsp_len_valid ? \ + (__fcprsp)->rsp_len : 0) +#define fcp_rspinfo(__fcprsp) ((struct fcp_rspinfo_s *)((__fcprsp) + 1)) +#define fcp_snsinfo(__fcprsp) (((u8 *)fcp_rspinfo(__fcprsp)) + \ + fcp_rsplen(__fcprsp)) + +struct fcp_cmnd_fr_s { + struct fchs_s fchs; + struct fcp_cmnd_s fcp; +}; + +/* + * CT + */ +struct ct_hdr_s { + u32 rev_id:8; /* Revision of the CT */ + u32 in_id:24; /* Initiator Id */ + u32 gs_type:8; /* Generic service Type */ + u32 gs_sub_type:8; /* Generic service sub type */ + u32 options:8; /* options */ + u32 rsvrd:8; /* reserved */ + u32 cmd_rsp_code:16;/* ct command/response code */ + u32 max_res_size:16;/* maximum/residual size */ + u32 frag_id:8; /* fragment ID */ + u32 reason_code:8; /* reason code */ + u32 exp_code:8; /* explanation code */ + u32 vendor_unq:8; /* vendor unique */ +}; + +/* + * defines for the Revision + */ +enum { + CT_GS3_REVISION = 0x01, +}; + +/* + * defines for gs_type + */ +enum { + CT_GSTYPE_KEYSERVICE = 0xF7, + CT_GSTYPE_ALIASSERVICE = 0xF8, + CT_GSTYPE_MGMTSERVICE = 0xFA, + CT_GSTYPE_TIMESERVICE = 0xFB, + CT_GSTYPE_DIRSERVICE = 0xFC, +}; + +/* + * defines for gs_sub_type for gs type directory service + */ +enum { + CT_GSSUBTYPE_NAMESERVER = 0x02, +}; + +/* + * defines for gs_sub_type for gs type management service + */ +enum { + CT_GSSUBTYPE_CFGSERVER = 0x01, + CT_GSSUBTYPE_UNZONED_NS = 0x02, + CT_GSSUBTYPE_ZONESERVER = 0x03, + CT_GSSUBTYPE_LOCKSERVER = 0x04, + CT_GSSUBTYPE_HBA_MGMTSERVER = 0x10, /* for FDMI */ +}; + +/* + * defines for CT response code field + */ +enum { + CT_RSP_REJECT = 0x8001, + CT_RSP_ACCEPT = 0x8002, +}; + +/* + * defintions for CT reason code + */ +enum { + CT_RSN_INV_CMD = 0x01, + CT_RSN_INV_VER = 0x02, + CT_RSN_LOGIC_ERR = 0x03, + CT_RSN_INV_SIZE = 0x04, + CT_RSN_LOGICAL_BUSY = 0x05, + CT_RSN_PROTO_ERR = 0x07, + CT_RSN_UNABLE_TO_PERF = 0x09, + CT_RSN_NOT_SUPP = 0x0B, + CT_RSN_SERVER_NOT_AVBL = 0x0D, + CT_RSN_SESSION_COULD_NOT_BE_ESTBD = 0x0E, + CT_RSN_VENDOR_SPECIFIC = 0xFF, + +}; + +/* + * definitions for explanations code for Name server + */ +enum { + CT_NS_EXP_NOADDITIONAL = 0x00, + CT_NS_EXP_ID_NOT_REG = 0x01, + CT_NS_EXP_PN_NOT_REG = 0x02, + CT_NS_EXP_NN_NOT_REG = 0x03, + CT_NS_EXP_CS_NOT_REG = 0x04, + CT_NS_EXP_IPN_NOT_REG = 0x05, + CT_NS_EXP_IPA_NOT_REG = 0x06, + CT_NS_EXP_FT_NOT_REG = 0x07, + CT_NS_EXP_SPN_NOT_REG = 0x08, + CT_NS_EXP_SNN_NOT_REG = 0x09, + CT_NS_EXP_PT_NOT_REG = 0x0A, + CT_NS_EXP_IPP_NOT_REG = 0x0B, + CT_NS_EXP_FPN_NOT_REG = 0x0C, + CT_NS_EXP_HA_NOT_REG = 0x0D, + CT_NS_EXP_FD_NOT_REG = 0x0E, + CT_NS_EXP_FF_NOT_REG = 0x0F, + CT_NS_EXP_ACCESSDENIED = 0x10, + CT_NS_EXP_UNACCEPTABLE_ID = 0x11, + CT_NS_EXP_DATABASEEMPTY = 0x12, + CT_NS_EXP_NOT_REG_IN_SCOPE = 0x13, + CT_NS_EXP_DOM_ID_NOT_PRESENT = 0x14, + CT_NS_EXP_PORT_NUM_NOT_PRESENT = 0x15, + CT_NS_EXP_NO_DEVICE_ATTACHED = 0x16 +}; + +/* + * defintions for the explanation code for all servers + */ +enum { + CT_EXP_AUTH_EXCEPTION = 0xF1, + CT_EXP_DB_FULL = 0xF2, + CT_EXP_DB_EMPTY = 0xF3, + CT_EXP_PROCESSING_REQ = 0xF4, + CT_EXP_UNABLE_TO_VERIFY_CONN = 0xF5, + CT_EXP_DEVICES_NOT_IN_CMN_ZONE = 0xF6 +}; + +/* + * Command codes for Name server + */ +enum { + GS_GID_PN = 0x0121, /* Get Id on port name */ + GS_GPN_ID = 0x0112, /* Get port name on ID */ + GS_GNN_ID = 0x0113, /* Get node name on ID */ + GS_GID_FT = 0x0171, /* Get Id on FC4 type */ + GS_GSPN_ID = 0x0118, /* Get symbolic PN on ID */ + GS_RFT_ID = 0x0217, /* Register fc4type on ID */ + GS_RSPN_ID = 0x0218, /* Register symbolic PN on ID */ + GS_RPN_ID = 0x0212, /* Register port name */ + GS_RNN_ID = 0x0213, /* Register node name */ + GS_RCS_ID = 0x0214, /* Register class of service */ + GS_RPT_ID = 0x021A, /* Register port type */ + GS_GA_NXT = 0x0100, /* Get all next */ + GS_RFF_ID = 0x021F, /* Register FC4 Feature */ +}; + +struct fcgs_id_req_s{ + u32 rsvd:8; + u32 dap:24; /* port identifier */ +}; +#define fcgs_gpnid_req_t struct fcgs_id_req_s +#define fcgs_gnnid_req_t struct fcgs_id_req_s +#define fcgs_gspnid_req_t struct fcgs_id_req_s + +struct fcgs_gidpn_req_s { + wwn_t port_name; /* port wwn */ +}; + +struct fcgs_gidpn_resp_s { + u32 rsvd:8; + u32 dap:24; /* port identifier */ +}; + +/** + * RFT_ID + */ +struct fcgs_rftid_req_s { + u32 rsvd:8; + u32 dap:24; /* port identifier */ + u32 fc4_type[8]; /* fc4 types */ +}; + +/** + * RFF_ID : Register FC4 features. + */ + +#define FC_GS_FCP_FC4_FEATURE_INITIATOR 0x02 +#define FC_GS_FCP_FC4_FEATURE_TARGET 0x01 + +struct fcgs_rffid_req_s { + u32 rsvd:8; + u32 dap:24; /* port identifier */ + u32 rsvd1:16; + u32 fc4ftr_bits:8; /* fc4 feature bits */ + u32 fc4_type:8; /* corresponding FC4 Type */ +}; + +/** + * GID_FT Request + */ +struct fcgs_gidft_req_s { + u8 reserved; + u8 domain_id; /* domain, 0 - all fabric */ + u8 area_id; /* area, 0 - whole domain */ + u8 fc4_type; /* FC_TYPE_FCP for SCSI devices */ +}; /* GID_FT Request */ + +/** + * GID_FT Response + */ +struct fcgs_gidft_resp_s { + u8 last:1; /* last port identifier flag */ + u8 reserved:7; + u32 pid:24; /* port identifier */ +}; /* GID_FT Response */ + +/** + * RSPN_ID + */ +struct fcgs_rspnid_req_s { + u32 rsvd:8; + u32 dap:24; /* port identifier */ + u8 spn_len; /* symbolic port name length */ + u8 spn[256]; /* symbolic port name */ +}; + +/** + * RPN_ID + */ +struct fcgs_rpnid_req_s { + u32 rsvd:8; + u32 port_id:24; + wwn_t port_name; +}; + +/** + * RNN_ID + */ +struct fcgs_rnnid_req_s { + u32 rsvd:8; + u32 port_id:24; + wwn_t node_name; +}; + +/** + * RCS_ID + */ +struct fcgs_rcsid_req_s { + u32 rsvd:8; + u32 port_id:24; + u32 cos; +}; + +/** + * RPT_ID + */ +struct fcgs_rptid_req_s { + u32 rsvd:8; + u32 port_id:24; + u32 port_type:8; + u32 rsvd1:24; +}; + +/** + * GA_NXT Request + */ +struct fcgs_ganxt_req_s { + u32 rsvd:8; + u32 port_id:24; +}; + +/** + * GA_NXT Response + */ +struct fcgs_ganxt_rsp_s { + u32 port_type:8; /* Port Type */ + u32 port_id:24; /* Port Identifier */ + wwn_t port_name; /* Port Name */ + u8 spn_len; /* Length of Symbolic Port Name */ + char spn[255]; /* Symbolic Port Name */ + wwn_t node_name; /* Node Name */ + u8 snn_len; /* Length of Symbolic Node Name */ + char snn[255]; /* Symbolic Node Name */ + u8 ipa[8]; /* Initial Process Associator */ + u8 ip[16]; /* IP Address */ + u32 cos; /* Class of Service */ + u32 fc4types[8]; /* FC-4 TYPEs */ + wwn_t fabric_port_name; + /* Fabric Port Name */ + u32 rsvd:8; /* Reserved */ + u32 hard_addr:24; /* Hard Address */ +}; + +/* + * Fabric Config Server + */ + +/* + * Command codes for Fabric Configuration Server + */ +enum { + GS_FC_GFN_CMD = 0x0114, /* GS FC Get Fabric Name */ + GS_FC_GMAL_CMD = 0x0116, /* GS FC GMAL */ + GS_FC_TRACE_CMD = 0x0400, /* GS FC Trace Route */ + GS_FC_PING_CMD = 0x0401, /* GS FC Ping */ +}; + +/* + * Source or Destination Port Tags. + */ +enum { + GS_FTRACE_TAG_NPORT_ID = 1, + GS_FTRACE_TAG_NPORT_NAME = 2, +}; + +/* +* Port Value : Could be a Port id or wwn + */ +union fcgs_port_val_u { + u32 nport_id; + wwn_t nport_wwn; +}; + +#define GS_FTRACE_MAX_HOP_COUNT 20 +#define GS_FTRACE_REVISION 1 + +/* + * Ftrace Related Structures. + */ + +/* + * STR (Switch Trace) Reject Reason Codes. From FC-SW. + */ +enum { + GS_FTRACE_STR_CMD_COMPLETED_SUCC = 0, + GS_FTRACE_STR_CMD_NOT_SUPP_IN_NEXT_SWITCH, + GS_FTRACE_STR_NO_RESP_FROM_NEXT_SWITCH, + GS_FTRACE_STR_MAX_HOP_CNT_REACHED, + GS_FTRACE_STR_SRC_PORT_NOT_FOUND, + GS_FTRACE_STR_DST_PORT_NOT_FOUND, + GS_FTRACE_STR_DEVICES_NOT_IN_COMMON_ZONE, + GS_FTRACE_STR_NO_ROUTE_BW_PORTS, + GS_FTRACE_STR_NO_ADDL_EXPLN, + GS_FTRACE_STR_FABRIC_BUSY, + GS_FTRACE_STR_FABRIC_BUILD_IN_PROGRESS, + GS_FTRACE_STR_VENDOR_SPECIFIC_ERR_START = 0xf0, + GS_FTRACE_STR_VENDOR_SPECIFIC_ERR_END = 0xff, +}; + +/* + * Ftrace Request + */ +struct fcgs_ftrace_req_s { + u32 revision; + u16 src_port_tag; /* Source Port tag */ + u16 src_port_len; /* Source Port len */ + union fcgs_port_val_u src_port_val; /* Source Port value */ + u16 dst_port_tag; /* Destination Port tag */ + u16 dst_port_len; /* Destination Port len */ + union fcgs_port_val_u dst_port_val; /* Destination Port value */ + u32 token; + u8 vendor_id[8]; /* T10 Vendor Identifier */ + u8 vendor_info[8]; /* Vendor specific Info */ + u32 max_hop_cnt; /* Max Hop Count */ +}; + +/* + * Path info structure + */ +struct fcgs_ftrace_path_info_s { + wwn_t switch_name; /* Switch WWN */ + u32 domain_id; + wwn_t ingress_port_name; /* Ingress ports wwn */ + u32 ingress_phys_port_num; /* Ingress ports physical port + * number + */ + wwn_t egress_port_name; /* Ingress ports wwn */ + u32 egress_phys_port_num; /* Ingress ports physical port + * number + */ +}; + +/* + * Ftrace Acc Response + */ +struct fcgs_ftrace_resp_s { + u32 revision; + u32 token; + u8 vendor_id[8]; /* T10 Vendor Identifier */ + u8 vendor_info[8]; /* Vendor specific Info */ + u32 str_rej_reason_code; /* STR Reject Reason Code */ + u32 num_path_info_entries; /* No. of path info entries */ + /* + * path info entry/entries. + */ + struct fcgs_ftrace_path_info_s path_info[1]; + +}; + +/* +* Fabric Config Server : FCPing + */ + +/* + * FC Ping Request + */ +struct fcgs_fcping_req_s { + u32 revision; + u16 port_tag; + u16 port_len; /* Port len */ + union fcgs_port_val_u port_val; /* Port value */ + u32 token; +}; + +/* + * FC Ping Response + */ +struct fcgs_fcping_resp_s { + u32 token; +}; + +/* + * Command codes for zone server query. + */ +enum { + ZS_GZME = 0x0124, /* Get zone member extended */ +}; + +/* + * ZS GZME request + */ +#define ZS_GZME_ZNAMELEN 32 +struct zs_gzme_req_s { + u8 znamelen; + u8 rsvd[3]; + u8 zname[ZS_GZME_ZNAMELEN]; +}; + +enum zs_mbr_type { + ZS_MBR_TYPE_PWWN = 1, + ZS_MBR_TYPE_DOMPORT = 2, + ZS_MBR_TYPE_PORTID = 3, + ZS_MBR_TYPE_NWWN = 4, +}; + +struct zs_mbr_wwn_s { + u8 mbr_type; + u8 rsvd[3]; + wwn_t wwn; +}; + +struct zs_query_resp_s { + u32 nmbrs; /* number of zone members */ + struct zs_mbr_wwn_s mbr[1]; +}; + +/* + * GMAL Command ( Get ( interconnect Element) Management Address List) + * To retrieve the IP Address of a Switch. + */ + +#define CT_GMAL_RESP_PREFIX_TELNET "telnet://" +#define CT_GMAL_RESP_PREFIX_HTTP "http://" + +/* GMAL/GFN request */ +struct fcgs_req_s { + wwn_t wwn; /* PWWN/NWWN */ +}; + +#define fcgs_gmal_req_t struct fcgs_req_s +#define fcgs_gfn_req_t struct fcgs_req_s + +/* Accept Response to GMAL */ +struct fcgs_gmal_resp_s { + u32 ms_len; /* Num of entries */ + u8 ms_ma[256]; +}; + +struct fcgs_gmal_entry_s { + u8 len; + u8 prefix[7]; /* like "http://" */ + u8 ip_addr[248]; +}; + +/* + * FDMI + */ +/* + * FDMI Command Codes + */ +#define FDMI_GRHL 0x0100 +#define FDMI_GHAT 0x0101 +#define FDMI_GRPL 0x0102 +#define FDMI_GPAT 0x0110 +#define FDMI_RHBA 0x0200 +#define FDMI_RHAT 0x0201 +#define FDMI_RPRT 0x0210 +#define FDMI_RPA 0x0211 +#define FDMI_DHBA 0x0300 +#define FDMI_DPRT 0x0310 + +/* + * FDMI reason codes + */ +#define FDMI_NO_ADDITIONAL_EXP 0x00 +#define FDMI_HBA_ALREADY_REG 0x10 +#define FDMI_HBA_ATTRIB_NOT_REG 0x11 +#define FDMI_HBA_ATTRIB_MULTIPLE 0x12 +#define FDMI_HBA_ATTRIB_LENGTH_INVALID 0x13 +#define FDMI_HBA_ATTRIB_NOT_PRESENT 0x14 +#define FDMI_PORT_ORIG_NOT_IN_LIST 0x15 +#define FDMI_PORT_HBA_NOT_IN_LIST 0x16 +#define FDMI_PORT_ATTRIB_NOT_REG 0x20 +#define FDMI_PORT_NOT_REG 0x21 +#define FDMI_PORT_ATTRIB_MULTIPLE 0x22 +#define FDMI_PORT_ATTRIB_LENGTH_INVALID 0x23 +#define FDMI_PORT_ALREADY_REGISTEREED 0x24 + +/* + * FDMI Transmission Speed Mask values + */ +#define FDMI_TRANS_SPEED_1G 0x00000001 +#define FDMI_TRANS_SPEED_2G 0x00000002 +#define FDMI_TRANS_SPEED_10G 0x00000004 +#define FDMI_TRANS_SPEED_4G 0x00000008 +#define FDMI_TRANS_SPEED_8G 0x00000010 +#define FDMI_TRANS_SPEED_16G 0x00000020 +#define FDMI_TRANS_SPEED_UNKNOWN 0x00008000 + +/* + * FDMI HBA attribute types + */ +enum fdmi_hba_attribute_type { + FDMI_HBA_ATTRIB_NODENAME = 1, /* 0x0001 */ + FDMI_HBA_ATTRIB_MANUFACTURER, /* 0x0002 */ + FDMI_HBA_ATTRIB_SERIALNUM, /* 0x0003 */ + FDMI_HBA_ATTRIB_MODEL, /* 0x0004 */ + FDMI_HBA_ATTRIB_MODEL_DESC, /* 0x0005 */ + FDMI_HBA_ATTRIB_HW_VERSION, /* 0x0006 */ + FDMI_HBA_ATTRIB_DRIVER_VERSION, /* 0x0007 */ + FDMI_HBA_ATTRIB_ROM_VERSION, /* 0x0008 */ + FDMI_HBA_ATTRIB_FW_VERSION, /* 0x0009 */ + FDMI_HBA_ATTRIB_OS_NAME, /* 0x000A */ + FDMI_HBA_ATTRIB_MAX_CT, /* 0x000B */ + + FDMI_HBA_ATTRIB_MAX_TYPE +}; + +/* + * FDMI Port attribute types + */ +enum fdmi_port_attribute_type { + FDMI_PORT_ATTRIB_FC4_TYPES = 1, /* 0x0001 */ + FDMI_PORT_ATTRIB_SUPP_SPEED, /* 0x0002 */ + FDMI_PORT_ATTRIB_PORT_SPEED, /* 0x0003 */ + FDMI_PORT_ATTRIB_FRAME_SIZE, /* 0x0004 */ + FDMI_PORT_ATTRIB_DEV_NAME, /* 0x0005 */ + FDMI_PORT_ATTRIB_HOST_NAME, /* 0x0006 */ + + FDMI_PORT_ATTR_MAX_TYPE +}; + +/* + * FDMI attribute + */ +struct fdmi_attr_s { + u16 type; + u16 len; + u8 value[1]; +}; + +/* + * HBA Attribute Block + */ +struct fdmi_hba_attr_s { + u32 attr_count; /* # of attributes */ + struct fdmi_attr_s hba_attr; /* n attributes */ +}; + +/* + * Registered Port List + */ +struct fdmi_port_list_s { + u32 num_ports; /* number Of Port Entries */ + wwn_t port_entry; /* one or more */ +}; + +/* + * Port Attribute Block + */ +struct fdmi_port_attr_s { + u32 attr_count; /* # of attributes */ + struct fdmi_attr_s port_attr; /* n attributes */ +}; + +/* + * FDMI Register HBA Attributes + */ +struct fdmi_rhba_s { + wwn_t hba_id; /* HBA Identifier */ + struct fdmi_port_list_s port_list; /* Registered Port List */ + struct fdmi_hba_attr_s hba_attr_blk; /* HBA attribute block */ +}; + +/* + * FDMI Register Port + */ +struct fdmi_rprt_s { + wwn_t hba_id; /* HBA Identifier */ + wwn_t port_name; /* Port wwn */ + struct fdmi_port_attr_s port_attr_blk; /* Port Attr Block */ +}; + +/* + * FDMI Register Port Attributes + */ +struct fdmi_rpa_s { + wwn_t port_name; /* port wwn */ + struct fdmi_port_attr_s port_attr_blk; /* Port Attr Block */ +}; + +#pragma pack() + +#endif /* __BFA_FC_H__ */ diff --git a/drivers/scsi/bfa/fcbuild.c b/drivers/scsi/bfa/bfa_fcbuild.c index fee5456451cb..b7d2657ca82a 100644 --- a/drivers/scsi/bfa/fcbuild.c +++ b/drivers/scsi/bfa/bfa_fcbuild.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. * All rights reserved * www.brocade.com * @@ -18,25 +18,25 @@ * fcbuild.c - FC link service frame building and parsing routines */ -#include <bfa_os_inc.h> -#include "fcbuild.h" +#include "bfa_os_inc.h" +#include "bfa_fcbuild.h" /* * static build functions */ -static void fc_els_rsp_build(struct fchs_s *fchs, u32 d_id, u32 s_id, - u16 ox_id); -static void fc_bls_rsp_build(struct fchs_s *fchs, u32 d_id, u32 s_id, - u16 ox_id); -static struct fchs_s fc_els_req_tmpl; -static struct fchs_s fc_els_rsp_tmpl; -static struct fchs_s fc_bls_req_tmpl; -static struct fchs_s fc_bls_rsp_tmpl; +static void fc_els_rsp_build(struct fchs_s *fchs, u32 d_id, u32 s_id, + u16 ox_id); +static void fc_bls_rsp_build(struct fchs_s *fchs, u32 d_id, u32 s_id, + u16 ox_id); +static struct fchs_s fc_els_req_tmpl; +static struct fchs_s fc_els_rsp_tmpl; +static struct fchs_s fc_bls_req_tmpl; +static struct fchs_s fc_bls_rsp_tmpl; static struct fc_ba_acc_s ba_acc_tmpl; static struct fc_logi_s plogi_tmpl; static struct fc_prli_s prli_tmpl; static struct fc_rrq_s rrq_tmpl; -static struct fchs_s fcp_fchs_tmpl; +static struct fchs_s fcp_fchs_tmpl; void fcbuild_init(void) @@ -123,7 +123,7 @@ fcbuild_init(void) rrq_tmpl.els_cmd.els_code = FC_ELS_RRQ; /* - * fcp_fchs_tmpl + * fcp_struct fchs_s mpl */ fcp_fchs_tmpl.routing = FC_RTG_FC4_DEV_DATA; fcp_fchs_tmpl.cat_info = FC_CAT_UNSOLICIT_CMD; @@ -135,8 +135,7 @@ fcbuild_init(void) } static void -fc_gs_fchdr_build(struct fchs_s *fchs, u32 d_id, u32 s_id, - u32 ox_id) +fc_gs_fchdr_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u32 ox_id) { bfa_os_memset(fchs, 0, sizeof(struct fchs_s)); @@ -158,8 +157,7 @@ fc_gs_fchdr_build(struct fchs_s *fchs, u32 d_id, u32 s_id, } void -fc_els_req_build(struct fchs_s *fchs, u32 d_id, u32 s_id, - u16 ox_id) +fc_els_req_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id) { bfa_os_memcpy(fchs, &fc_els_req_tmpl, sizeof(struct fchs_s)); fchs->d_id = (d_id); @@ -168,8 +166,7 @@ fc_els_req_build(struct fchs_s *fchs, u32 d_id, u32 s_id, } static void -fc_els_rsp_build(struct fchs_s *fchs, u32 d_id, u32 s_id, - u16 ox_id) +fc_els_rsp_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id) { bfa_os_memcpy(fchs, &fc_els_rsp_tmpl, sizeof(struct fchs_s)); fchs->d_id = d_id; @@ -180,8 +177,8 @@ fc_els_rsp_build(struct fchs_s *fchs, u32 d_id, u32 s_id, enum fc_parse_status fc_els_rsp_parse(struct fchs_s *fchs, int len) { - struct fc_els_cmd_s *els_cmd = (struct fc_els_cmd_s *) (fchs + 1); - struct fc_ls_rjt_s *ls_rjt = (struct fc_ls_rjt_s *) els_cmd; + struct fc_els_cmd_s *els_cmd = (struct fc_els_cmd_s *) (fchs + 1); + struct fc_ls_rjt_s *ls_rjt = (struct fc_ls_rjt_s *) els_cmd; len = len; @@ -199,8 +196,7 @@ fc_els_rsp_parse(struct fchs_s *fchs, int len) } static void -fc_bls_rsp_build(struct fchs_s *fchs, u32 d_id, u32 s_id, - u16 ox_id) +fc_bls_rsp_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id) { bfa_os_memcpy(fchs, &fc_bls_rsp_tmpl, sizeof(struct fchs_s)); fchs->d_id = d_id; @@ -213,7 +209,7 @@ fc_plogi_x_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id, u16 ox_id, wwn_t port_name, wwn_t node_name, u16 pdu_size, u8 els_code) { - struct fc_logi_s *plogi = (struct fc_logi_s *) (pld); + struct fc_logi_s *plogi = (struct fc_logi_s *) (pld); bfa_os_memcpy(plogi, &plogi_tmpl, sizeof(struct fc_logi_s)); @@ -233,12 +229,11 @@ fc_plogi_x_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id, u16 fc_flogi_build(struct fchs_s *fchs, struct fc_logi_s *flogi, u32 s_id, - u16 ox_id, wwn_t port_name, wwn_t node_name, - u16 pdu_size, u8 set_npiv, u8 set_auth, - u16 local_bb_credits) + u16 ox_id, wwn_t port_name, wwn_t node_name, u16 pdu_size, + u8 set_npiv, u8 set_auth, u16 local_bb_credits) { u32 d_id = bfa_os_hton3b(FC_FABRIC_PORT); - u32 *vvl_info; + u32 *vvl_info; bfa_os_memcpy(flogi, &plogi_tmpl, sizeof(struct fc_logi_s)); @@ -292,8 +287,7 @@ fc_flogi_acc_build(struct fchs_s *fchs, struct fc_logi_s *flogi, u32 s_id, u16 fc_fdisc_build(struct fchs_s *fchs, struct fc_logi_s *flogi, u32 s_id, - u16 ox_id, wwn_t port_name, wwn_t node_name, - u16 pdu_size) + u16 ox_id, wwn_t port_name, wwn_t node_name, u16 pdu_size) { u32 d_id = bfa_os_hton3b(FC_FABRIC_PORT); @@ -330,9 +324,9 @@ fc_plogi_acc_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id, enum fc_parse_status fc_plogi_rsp_parse(struct fchs_s *fchs, int len, wwn_t port_name) { - struct fc_els_cmd_s *els_cmd = (struct fc_els_cmd_s *) (fchs + 1); - struct fc_logi_s *plogi; - struct fc_ls_rjt_s *ls_rjt; + struct fc_els_cmd_s *els_cmd = (struct fc_els_cmd_s *) (fchs + 1); + struct fc_logi_s *plogi; + struct fc_ls_rjt_s *ls_rjt; switch (els_cmd->els_code) { case FC_ELS_LS_RJT: @@ -364,7 +358,7 @@ fc_plogi_rsp_parse(struct fchs_s *fchs, int len, wwn_t port_name) enum fc_parse_status fc_plogi_parse(struct fchs_s *fchs) { - struct fc_logi_s *plogi = (struct fc_logi_s *) (fchs + 1); + struct fc_logi_s *plogi = (struct fc_logi_s *) (fchs + 1); if (plogi->class3.class_valid != 1) return FC_PARSE_FAILURE; @@ -381,7 +375,7 @@ u16 fc_prli_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id, u16 ox_id) { - struct fc_prli_s *prli = (struct fc_prli_s *) (pld); + struct fc_prli_s *prli = (struct fc_prli_s *) (pld); fc_els_req_build(fchs, d_id, s_id, ox_id); bfa_os_memcpy(prli, &prli_tmpl, sizeof(struct fc_prli_s)); @@ -398,19 +392,16 @@ fc_prli_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id, u16 fc_prli_acc_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id, - u16 ox_id, enum bfa_port_role role) + u16 ox_id, enum bfa_lport_role role) { - struct fc_prli_s *prli = (struct fc_prli_s *) (pld); + struct fc_prli_s *prli = (struct fc_prli_s *) (pld); fc_els_rsp_build(fchs, d_id, s_id, ox_id); bfa_os_memcpy(prli, &prli_tmpl, sizeof(struct fc_prli_s)); prli->command = FC_ELS_ACC; - if ((role & BFA_PORT_ROLE_FCP_TM) == BFA_PORT_ROLE_FCP_TM) - prli->parampage.servparams.target = 1; - else - prli->parampage.servparams.initiator = 1; + prli->parampage.servparams.initiator = 1; prli->parampage.rspcode = FC_PRLI_ACC_XQTD; @@ -452,12 +443,12 @@ fc_prli_parse(struct fc_prli_s *prli) } u16 -fc_logo_build(struct fchs_s *fchs, struct fc_logo_s *logo, u32 d_id, - u32 s_id, u16 ox_id, wwn_t port_name) +fc_logo_build(struct fchs_s *fchs, struct fc_logo_s *logo, u32 d_id, u32 s_id, + u16 ox_id, wwn_t port_name) { fc_els_req_build(fchs, d_id, s_id, ox_id); - memset(logo, '\0', sizeof(struct fc_logo_s)); + bfa_os_memset(logo, '\0', sizeof(struct fc_logo_s)); logo->els_cmd.els_code = FC_ELS_LOGO; logo->nport_id = (s_id); logo->orig_port_name = port_name; @@ -470,7 +461,7 @@ fc_adisc_x_build(struct fchs_s *fchs, struct fc_adisc_s *adisc, u32 d_id, u32 s_id, u16 ox_id, wwn_t port_name, wwn_t node_name, u8 els_code) { - memset(adisc, '\0', sizeof(struct fc_adisc_s)); + bfa_os_memset(adisc, '\0', sizeof(struct fc_adisc_s)); adisc->els_cmd.els_code = els_code; @@ -489,8 +480,7 @@ fc_adisc_x_build(struct fchs_s *fchs, struct fc_adisc_s *adisc, u32 d_id, u16 fc_adisc_build(struct fchs_s *fchs, struct fc_adisc_s *adisc, u32 d_id, - u32 s_id, u16 ox_id, wwn_t port_name, - wwn_t node_name) + u32 s_id, u16 ox_id, wwn_t port_name, wwn_t node_name) { return fc_adisc_x_build(fchs, adisc, d_id, s_id, ox_id, port_name, node_name, FC_ELS_ADISC); @@ -523,10 +513,10 @@ fc_adisc_rsp_parse(struct fc_adisc_s *adisc, int len, wwn_t port_name, } enum fc_parse_status -fc_adisc_parse(struct fchs_s *fchs, void *pld, u32 host_dap, - wwn_t node_name, wwn_t port_name) +fc_adisc_parse(struct fchs_s *fchs, void *pld, u32 host_dap, wwn_t node_name, + wwn_t port_name) { - struct fc_adisc_s *adisc = (struct fc_adisc_s *) pld; + struct fc_adisc_s *adisc = (struct fc_adisc_s *) pld; if (adisc->els_cmd.els_code != FC_ELS_ACC) return FC_PARSE_FAILURE; @@ -542,13 +532,13 @@ fc_adisc_parse(struct fchs_s *fchs, void *pld, u32 host_dap, enum fc_parse_status fc_pdisc_parse(struct fchs_s *fchs, wwn_t node_name, wwn_t port_name) { - struct fc_logi_s *pdisc = (struct fc_logi_s *) (fchs + 1); + struct fc_logi_s *pdisc = (struct fc_logi_s *) (fchs + 1); if (pdisc->class3.class_valid != 1) return FC_PARSE_FAILURE; if ((bfa_os_ntohs(pdisc->class3.rxsz) < - (FC_MIN_PDUSZ - sizeof(struct fchs_s))) + (FC_MIN_PDUSZ - sizeof(struct fchs_s))) || (pdisc->class3.rxsz == 0)) return FC_PARSE_FAILURE; @@ -584,8 +574,8 @@ fc_abts_rsp_parse(struct fchs_s *fchs, int len) } u16 -fc_rrq_build(struct fchs_s *fchs, struct fc_rrq_s *rrq, u32 d_id, - u32 s_id, u16 ox_id, u16 rrq_oxid) +fc_rrq_build(struct fchs_s *fchs, struct fc_rrq_s *rrq, u32 d_id, u32 s_id, + u16 ox_id, u16 rrq_oxid) { fc_els_req_build(fchs, d_id, s_id, ox_id); @@ -604,11 +594,11 @@ u16 fc_logo_acc_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id, u16 ox_id) { - struct fc_els_cmd_s *acc = pld; + struct fc_els_cmd_s *acc = pld; fc_els_rsp_build(fchs, d_id, s_id, ox_id); - memset(acc, 0, sizeof(struct fc_els_cmd_s)); + bfa_os_memset(acc, 0, sizeof(struct fc_els_cmd_s)); acc->els_code = FC_ELS_ACC; return sizeof(struct fc_els_cmd_s); @@ -620,7 +610,7 @@ fc_ls_rjt_build(struct fchs_s *fchs, struct fc_ls_rjt_s *ls_rjt, u32 d_id, u8 reason_code_expl) { fc_els_rsp_build(fchs, d_id, s_id, ox_id); - memset(ls_rjt, 0, sizeof(struct fc_ls_rjt_s)); + bfa_os_memset(ls_rjt, 0, sizeof(struct fc_ls_rjt_s)); ls_rjt->els_cmd.els_code = FC_ELS_LS_RJT; ls_rjt->reason_code = reason_code; @@ -647,11 +637,11 @@ fc_ba_acc_build(struct fchs_s *fchs, struct fc_ba_acc_s *ba_acc, u32 d_id, } u16 -fc_ls_acc_build(struct fchs_s *fchs, struct fc_els_cmd_s *els_cmd, - u32 d_id, u32 s_id, u16 ox_id) +fc_ls_acc_build(struct fchs_s *fchs, struct fc_els_cmd_s *els_cmd, u32 d_id, + u32 s_id, u16 ox_id) { fc_els_rsp_build(fchs, d_id, s_id, ox_id); - memset(els_cmd, 0, sizeof(struct fc_els_cmd_s)); + bfa_os_memset(els_cmd, 0, sizeof(struct fc_els_cmd_s)); els_cmd->els_code = FC_ELS_ACC; return sizeof(struct fc_els_cmd_s); @@ -661,8 +651,8 @@ int fc_logout_params_pages(struct fchs_s *fc_frame, u8 els_code) { int num_pages = 0; - struct fc_prlo_s *prlo; - struct fc_tprlo_s *tprlo; + struct fc_prlo_s *prlo; + struct fc_tprlo_s *tprlo; if (els_code == FC_ELS_PRLO) { prlo = (struct fc_prlo_s *) (fc_frame + 1); @@ -676,14 +666,13 @@ fc_logout_params_pages(struct fchs_s *fc_frame, u8 els_code) u16 fc_tprlo_acc_build(struct fchs_s *fchs, struct fc_tprlo_acc_s *tprlo_acc, - u32 d_id, u32 s_id, u16 ox_id, - int num_pages) + u32 d_id, u32 s_id, u16 ox_id, int num_pages) { int page; fc_els_rsp_build(fchs, d_id, s_id, ox_id); - memset(tprlo_acc, 0, (num_pages * 16) + 4); + bfa_os_memset(tprlo_acc, 0, (num_pages * 16) + 4); tprlo_acc->command = FC_ELS_ACC; tprlo_acc->page_len = 0x10; @@ -700,15 +689,14 @@ fc_tprlo_acc_build(struct fchs_s *fchs, struct fc_tprlo_acc_s *tprlo_acc, } u16 -fc_prlo_acc_build(struct fchs_s *fchs, struct fc_prlo_acc_s *prlo_acc, - u32 d_id, u32 s_id, u16 ox_id, - int num_pages) +fc_prlo_acc_build(struct fchs_s *fchs, struct fc_prlo_acc_s *prlo_acc, u32 d_id, + u32 s_id, u16 ox_id, int num_pages) { int page; fc_els_rsp_build(fchs, d_id, s_id, ox_id); - memset(prlo_acc, 0, (num_pages * 16) + 4); + bfa_os_memset(prlo_acc, 0, (num_pages * 16) + 4); prlo_acc->command = FC_ELS_ACC; prlo_acc->page_len = 0x10; prlo_acc->payload_len = bfa_os_htons((num_pages * 16) + 4); @@ -726,11 +714,11 @@ fc_prlo_acc_build(struct fchs_s *fchs, struct fc_prlo_acc_s *prlo_acc, u16 fc_rnid_build(struct fchs_s *fchs, struct fc_rnid_cmd_s *rnid, u32 d_id, - u32 s_id, u16 ox_id, u32 data_format) + u32 s_id, u16 ox_id, u32 data_format) { fc_els_req_build(fchs, d_id, s_id, ox_id); - memset(rnid, 0, sizeof(struct fc_rnid_cmd_s)); + bfa_os_memset(rnid, 0, sizeof(struct fc_rnid_cmd_s)); rnid->els_cmd.els_code = FC_ELS_RNID; rnid->node_id_data_format = data_format; @@ -739,13 +727,12 @@ fc_rnid_build(struct fchs_s *fchs, struct fc_rnid_cmd_s *rnid, u32 d_id, } u16 -fc_rnid_acc_build(struct fchs_s *fchs, struct fc_rnid_acc_s *rnid_acc, - u32 d_id, u32 s_id, u16 ox_id, - u32 data_format, - struct fc_rnid_common_id_data_s *common_id_data, - struct fc_rnid_general_topology_data_s *gen_topo_data) +fc_rnid_acc_build(struct fchs_s *fchs, struct fc_rnid_acc_s *rnid_acc, u32 d_id, + u32 s_id, u16 ox_id, u32 data_format, + struct fc_rnid_common_id_data_s *common_id_data, + struct fc_rnid_general_topology_data_s *gen_topo_data) { - memset(rnid_acc, 0, sizeof(struct fc_rnid_acc_s)); + bfa_os_memset(rnid_acc, 0, sizeof(struct fc_rnid_acc_s)); fc_els_rsp_build(fchs, d_id, s_id, ox_id); @@ -769,27 +756,26 @@ fc_rnid_acc_build(struct fchs_s *fchs, struct fc_rnid_acc_s *rnid_acc, u16 fc_rpsc_build(struct fchs_s *fchs, struct fc_rpsc_cmd_s *rpsc, u32 d_id, - u32 s_id, u16 ox_id) + u32 s_id, u16 ox_id) { fc_els_req_build(fchs, d_id, s_id, ox_id); - memset(rpsc, 0, sizeof(struct fc_rpsc_cmd_s)); + bfa_os_memset(rpsc, 0, sizeof(struct fc_rpsc_cmd_s)); rpsc->els_cmd.els_code = FC_ELS_RPSC; return sizeof(struct fc_rpsc_cmd_s); } u16 -fc_rpsc2_build(struct fchs_s *fchs, struct fc_rpsc2_cmd_s *rpsc2, - u32 d_id, u32 s_id, u32 *pid_list, - u16 npids) +fc_rpsc2_build(struct fchs_s *fchs, struct fc_rpsc2_cmd_s *rpsc2, u32 d_id, + u32 s_id, u32 *pid_list, u16 npids) { u32 dctlr_id = FC_DOMAIN_CTRLR(bfa_os_hton3b(d_id)); int i = 0; fc_els_req_build(fchs, bfa_os_hton3b(dctlr_id), s_id, 0); - memset(rpsc2, 0, sizeof(struct fc_rpsc2_cmd_s)); + bfa_os_memset(rpsc2, 0, sizeof(struct fc_rpsc2_cmd_s)); rpsc2->els_cmd.els_code = FC_ELS_RPSC; rpsc2->token = bfa_os_htonl(FC_BRCD_TOKEN); @@ -797,16 +783,15 @@ fc_rpsc2_build(struct fchs_s *fchs, struct fc_rpsc2_cmd_s *rpsc2, for (i = 0; i < npids; i++) rpsc2->pid_list[i].pid = pid_list[i]; - return sizeof(struct fc_rpsc2_cmd_s) + ((npids - 1) * - (sizeof(u32))); + return sizeof(struct fc_rpsc2_cmd_s) + ((npids - 1) * (sizeof(u32))); } u16 fc_rpsc_acc_build(struct fchs_s *fchs, struct fc_rpsc_acc_s *rpsc_acc, - u32 d_id, u32 s_id, u16 ox_id, - struct fc_rpsc_speed_info_s *oper_speed) + u32 d_id, u32 s_id, u16 ox_id, + struct fc_rpsc_speed_info_s *oper_speed) { - memset(rpsc_acc, 0, sizeof(struct fc_rpsc_acc_s)); + bfa_os_memset(rpsc_acc, 0, sizeof(struct fc_rpsc_acc_s)); fc_els_rsp_build(fchs, d_id, s_id, ox_id); @@ -820,7 +805,6 @@ fc_rpsc_acc_build(struct fchs_s *fchs, struct fc_rpsc_acc_s *rpsc_acc, bfa_os_htons(oper_speed->port_op_speed); return sizeof(struct fc_rpsc_acc_s); - } /* @@ -831,7 +815,7 @@ fc_rpsc_acc_build(struct fchs_s *fchs, struct fc_rpsc_acc_s *rpsc_acc, u16 fc_logo_rsp_parse(struct fchs_s *fchs, int len) { - struct fc_els_cmd_s *els_cmd = (struct fc_els_cmd_s *) (fchs + 1); + struct fc_els_cmd_s *els_cmd = (struct fc_els_cmd_s *) (fchs + 1); len = len; if (els_cmd->els_code != FC_ELS_ACC) @@ -841,11 +825,10 @@ fc_logo_rsp_parse(struct fchs_s *fchs, int len) } u16 -fc_pdisc_build(struct fchs_s *fchs, u32 d_id, u32 s_id, - u16 ox_id, wwn_t port_name, wwn_t node_name, - u16 pdu_size) +fc_pdisc_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id, + wwn_t port_name, wwn_t node_name, u16 pdu_size) { - struct fc_logi_s *pdisc = (struct fc_logi_s *) (fchs + 1); + struct fc_logi_s *pdisc = (struct fc_logi_s *) (fchs + 1); bfa_os_memcpy(pdisc, &plogi_tmpl, sizeof(struct fc_logi_s)); @@ -862,7 +845,7 @@ fc_pdisc_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 fc_pdisc_rsp_parse(struct fchs_s *fchs, int len, wwn_t port_name) { - struct fc_logi_s *pdisc = (struct fc_logi_s *) (fchs + 1); + struct fc_logi_s *pdisc = (struct fc_logi_s *) (fchs + 1); if (len < sizeof(struct fc_logi_s)) return FC_PARSE_LEN_INVAL; @@ -886,11 +869,11 @@ u16 fc_prlo_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id, int num_pages) { - struct fc_prlo_s *prlo = (struct fc_prlo_s *) (fchs + 1); + struct fc_prlo_s *prlo = (struct fc_prlo_s *) (fchs + 1); int page; fc_els_req_build(fchs, d_id, s_id, ox_id); - memset(prlo, 0, (num_pages * 16) + 4); + bfa_os_memset(prlo, 0, (num_pages * 16) + 4); prlo->command = FC_ELS_PRLO; prlo->page_len = 0x10; prlo->payload_len = bfa_os_htons((num_pages * 16) + 4); @@ -909,7 +892,7 @@ fc_prlo_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id, u16 fc_prlo_rsp_parse(struct fchs_s *fchs, int len) { - struct fc_prlo_acc_s *prlo = (struct fc_prlo_acc_s *) (fchs + 1); + struct fc_prlo_acc_s *prlo = (struct fc_prlo_acc_s *) (fchs + 1); int num_pages = 0; int page = 0; @@ -941,15 +924,14 @@ fc_prlo_rsp_parse(struct fchs_s *fchs, int len) } u16 -fc_tprlo_build(struct fchs_s *fchs, u32 d_id, u32 s_id, - u16 ox_id, int num_pages, - enum fc_tprlo_type tprlo_type, u32 tpr_id) +fc_tprlo_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id, + int num_pages, enum fc_tprlo_type tprlo_type, u32 tpr_id) { - struct fc_tprlo_s *tprlo = (struct fc_tprlo_s *) (fchs + 1); + struct fc_tprlo_s *tprlo = (struct fc_tprlo_s *) (fchs + 1); int page; fc_els_req_build(fchs, d_id, s_id, ox_id); - memset(tprlo, 0, (num_pages * 16) + 4); + bfa_os_memset(tprlo, 0, (num_pages * 16) + 4); tprlo->command = FC_ELS_TPRLO; tprlo->page_len = 0x10; tprlo->payload_len = bfa_os_htons((num_pages * 16) + 4); @@ -1003,7 +985,7 @@ fc_tprlo_rsp_parse(struct fchs_s *fchs, int len) enum fc_parse_status fc_rrq_rsp_parse(struct fchs_s *fchs, int len) { - struct fc_els_cmd_s *els_cmd = (struct fc_els_cmd_s *) (fchs + 1); + struct fc_els_cmd_s *els_cmd = (struct fc_els_cmd_s *) (fchs + 1); len = len; if (els_cmd->els_code != FC_ELS_ACC) @@ -1013,11 +995,10 @@ fc_rrq_rsp_parse(struct fchs_s *fchs, int len) } u16 -fc_ba_rjt_build(struct fchs_s *fchs, u32 d_id, u32 s_id, - u16 ox_id, u32 reason_code, - u32 reason_expl) +fc_ba_rjt_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id, + u32 reason_code, u32 reason_expl) { - struct fc_ba_rjt_s *ba_rjt = (struct fc_ba_rjt_s *) (fchs + 1); + struct fc_ba_rjt_s *ba_rjt = (struct fc_ba_rjt_s *) (fchs + 1); fc_bls_rsp_build(fchs, d_id, s_id, ox_id); @@ -1062,10 +1043,8 @@ u16 fc_gidpn_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id, wwn_t port_name) { - - struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; - struct fcgs_gidpn_req_s *gidpn = - (struct fcgs_gidpn_req_s *) (cthdr + 1); + struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; + struct fcgs_gidpn_req_s *gidpn = (struct fcgs_gidpn_req_s *)(cthdr + 1); u32 d_id = bfa_os_hton3b(FC_NAME_SERVER); fc_gs_fchdr_build(fchs, d_id, s_id, ox_id); @@ -1080,8 +1059,7 @@ u16 fc_gpnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id, u32 port_id) { - - struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; + struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; fcgs_gpnid_req_t *gpnid = (fcgs_gpnid_req_t *) (cthdr + 1); u32 d_id = bfa_os_hton3b(FC_NAME_SERVER); @@ -1097,8 +1075,7 @@ u16 fc_gnnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id, u32 port_id) { - - struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; + struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; fcgs_gnnid_req_t *gnnid = (fcgs_gnnid_req_t *) (cthdr + 1); u32 d_id = bfa_os_hton3b(FC_NAME_SERVER); @@ -1124,8 +1101,8 @@ fc_ct_rsp_parse(struct ct_hdr_s *cthdr) } u16 -fc_scr_build(struct fchs_s *fchs, struct fc_scr_s *scr, u8 set_br_reg, - u32 s_id, u16 ox_id) +fc_scr_build(struct fchs_s *fchs, struct fc_scr_s *scr, + u8 set_br_reg, u32 s_id, u16 ox_id) { u32 d_id = bfa_os_hton3b(FC_FABRIC_CONTROLLER); @@ -1141,8 +1118,8 @@ fc_scr_build(struct fchs_s *fchs, struct fc_scr_s *scr, u8 set_br_reg, } u16 -fc_rscn_build(struct fchs_s *fchs, struct fc_rscn_pl_s *rscn, u32 s_id, - u16 ox_id) +fc_rscn_build(struct fchs_s *fchs, struct fc_rscn_pl_s *rscn, + u32 s_id, u16 ox_id) { u32 d_id = bfa_os_hton3b(FC_FABRIC_CONTROLLER); u16 payldlen; @@ -1162,11 +1139,10 @@ fc_rscn_build(struct fchs_s *fchs, struct fc_rscn_pl_s *rscn, u32 s_id, u16 fc_rftid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id, - enum bfa_port_role roles) + enum bfa_lport_role roles) { - struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; - struct fcgs_rftid_req_s *rftid = - (struct fcgs_rftid_req_s *) (cthdr + 1); + struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; + struct fcgs_rftid_req_s *rftid = (struct fcgs_rftid_req_s *)(cthdr + 1); u32 type_value, d_id = bfa_os_hton3b(FC_NAME_SERVER); u8 index; @@ -1182,23 +1158,15 @@ fc_rftid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id, type_value = 1 << (FC_TYPE_FCP % 32); rftid->fc4_type[index] = bfa_os_htonl(type_value); - if (roles & BFA_PORT_ROLE_FCP_IPFC) { - index = FC_TYPE_IP >> 5; - type_value = 1 << (FC_TYPE_IP % 32); - rftid->fc4_type[index] |= bfa_os_htonl(type_value); - } - return sizeof(struct fcgs_rftid_req_s) + sizeof(struct ct_hdr_s); } u16 -fc_rftid_build_sol(struct fchs_s *fchs, void *pyld, u32 s_id, - u16 ox_id, u8 *fc4_bitmap, - u32 bitmap_size) +fc_rftid_build_sol(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id, + u8 *fc4_bitmap, u32 bitmap_size) { - struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; - struct fcgs_rftid_req_s *rftid = - (struct fcgs_rftid_req_s *) (cthdr + 1); + struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; + struct fcgs_rftid_req_s *rftid = (struct fcgs_rftid_req_s *)(cthdr + 1); u32 d_id = bfa_os_hton3b(FC_NAME_SERVER); fc_gs_fchdr_build(fchs, d_id, s_id, ox_id); @@ -1208,7 +1176,7 @@ fc_rftid_build_sol(struct fchs_s *fchs, void *pyld, u32 s_id, rftid->dap = s_id; bfa_os_memcpy((void *)rftid->fc4_type, (void *)fc4_bitmap, - (bitmap_size < 32 ? bitmap_size : 32)); + (bitmap_size < 32 ? bitmap_size : 32)); return sizeof(struct fcgs_rftid_req_s) + sizeof(struct ct_hdr_s); } @@ -1217,9 +1185,8 @@ u16 fc_rffid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id, u8 fc4_type, u8 fc4_ftrs) { - struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; - struct fcgs_rffid_req_s *rffid = - (struct fcgs_rffid_req_s *) (cthdr + 1); + struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; + struct fcgs_rffid_req_s *rffid = (struct fcgs_rffid_req_s *)(cthdr + 1); u32 d_id = bfa_os_hton3b(FC_NAME_SERVER); fc_gs_fchdr_build(fchs, d_id, s_id, ox_id); @@ -1227,9 +1194,9 @@ fc_rffid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id, bfa_os_memset(rffid, 0, sizeof(struct fcgs_rffid_req_s)); - rffid->dap = s_id; + rffid->dap = s_id; rffid->fc4ftr_bits = fc4_ftrs; - rffid->fc4_type = fc4_type; + rffid->fc4_type = fc4_type; return sizeof(struct fcgs_rffid_req_s) + sizeof(struct ct_hdr_s); } @@ -1239,9 +1206,9 @@ fc_rspnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id, u8 *name) { - struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; + struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; struct fcgs_rspnid_req_s *rspnid = - (struct fcgs_rspnid_req_s *) (cthdr + 1); + (struct fcgs_rspnid_req_s *)(cthdr + 1); u32 d_id = bfa_os_hton3b(FC_NAME_SERVER); fc_gs_fchdr_build(fchs, d_id, s_id, ox_id); @@ -1257,13 +1224,11 @@ fc_rspnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id, } u16 -fc_gid_ft_build(struct fchs_s *fchs, void *pyld, u32 s_id, - u8 fc4_type) +fc_gid_ft_build(struct fchs_s *fchs, void *pyld, u32 s_id, u8 fc4_type) { - struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; - struct fcgs_gidft_req_s *gidft = - (struct fcgs_gidft_req_s *) (cthdr + 1); + struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; + struct fcgs_gidft_req_s *gidft = (struct fcgs_gidft_req_s *)(cthdr + 1); u32 d_id = bfa_os_hton3b(FC_NAME_SERVER); fc_gs_fchdr_build(fchs, d_id, s_id, 0); @@ -1282,9 +1247,8 @@ u16 fc_rpnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id, wwn_t port_name) { - struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; - struct fcgs_rpnid_req_s *rpnid = - (struct fcgs_rpnid_req_s *) (cthdr + 1); + struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; + struct fcgs_rpnid_req_s *rpnid = (struct fcgs_rpnid_req_s *)(cthdr + 1); u32 d_id = bfa_os_hton3b(FC_NAME_SERVER); fc_gs_fchdr_build(fchs, d_id, s_id, 0); @@ -1301,9 +1265,8 @@ u16 fc_rnnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id, wwn_t node_name) { - struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; - struct fcgs_rnnid_req_s *rnnid = - (struct fcgs_rnnid_req_s *) (cthdr + 1); + struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; + struct fcgs_rnnid_req_s *rnnid = (struct fcgs_rnnid_req_s *)(cthdr + 1); u32 d_id = bfa_os_hton3b(FC_NAME_SERVER); fc_gs_fchdr_build(fchs, d_id, s_id, 0); @@ -1320,7 +1283,7 @@ u16 fc_rcsid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id, u32 cos) { - struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; + struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; struct fcgs_rcsid_req_s *rcsid = (struct fcgs_rcsid_req_s *) (cthdr + 1); u32 d_id = bfa_os_hton3b(FC_NAME_SERVER); @@ -1339,9 +1302,8 @@ u16 fc_rptid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id, u8 port_type) { - struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; - struct fcgs_rptid_req_s *rptid = - (struct fcgs_rptid_req_s *) (cthdr + 1); + struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; + struct fcgs_rptid_req_s *rptid = (struct fcgs_rptid_req_s *)(cthdr + 1); u32 d_id = bfa_os_hton3b(FC_NAME_SERVER); fc_gs_fchdr_build(fchs, d_id, s_id, 0); @@ -1357,9 +1319,8 @@ fc_rptid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id, u16 fc_ganxt_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id) { - struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; - struct fcgs_ganxt_req_s *ganxt = - (struct fcgs_ganxt_req_s *) (cthdr + 1); + struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; + struct fcgs_ganxt_req_s *ganxt = (struct fcgs_ganxt_req_s *)(cthdr + 1); u32 d_id = bfa_os_hton3b(FC_NAME_SERVER); fc_gs_fchdr_build(fchs, d_id, s_id, 0); @@ -1379,7 +1340,7 @@ fc_fdmi_reqhdr_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 cmd_code) { - struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; + struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; u32 d_id = bfa_os_hton3b(FC_MGMT_SERVER); fc_gs_fchdr_build(fchs, d_id, s_id, 0); @@ -1409,12 +1370,12 @@ fc_get_fc4type_bitmask(u8 fc4_type, u8 *bit_mask) } /* - * GMAL Request + * GMAL Request */ u16 fc_gmal_req_build(struct fchs_s *fchs, void *pyld, u32 s_id, wwn_t wwn) { - struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; + struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; fcgs_gmal_req_t *gmal = (fcgs_gmal_req_t *) (cthdr + 1); u32 d_id = bfa_os_hton3b(FC_MGMT_SERVER); @@ -1434,7 +1395,7 @@ fc_gmal_req_build(struct fchs_s *fchs, void *pyld, u32 s_id, wwn_t wwn) u16 fc_gfn_req_build(struct fchs_s *fchs, void *pyld, u32 s_id, wwn_t wwn) { - struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; + struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; fcgs_gfn_req_t *gfn = (fcgs_gfn_req_t *) (cthdr + 1); u32 d_id = bfa_os_hton3b(FC_MGMT_SERVER); diff --git a/drivers/scsi/bfa/bfa_fcbuild.h b/drivers/scsi/bfa/bfa_fcbuild.h new file mode 100644 index 000000000000..73abd02e53cc --- /dev/null +++ b/drivers/scsi/bfa/bfa_fcbuild.h @@ -0,0 +1,316 @@ +/* + * 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. + */ +/* + * fcbuild.h - FC link service frame building and parsing routines + */ + +#ifndef __FCBUILD_H__ +#define __FCBUILD_H__ + +#include "bfa_os_inc.h" +#include "bfa_fc.h" +#include "bfa_defs_fcs.h" + +/* + * Utility Macros/functions + */ + +#define wwn_is_equal(_wwn1, _wwn2) \ + (memcmp(&(_wwn1), &(_wwn2), sizeof(wwn_t)) == 0) + +#define fc_roundup(_l, _s) (((_l) + ((_s) - 1)) & ~((_s) - 1)) + +/* + * Given the fc response length, this routine will return + * the length of the actual payload bytes following the CT header. + * + * Assumes the input response length does not include the crc, eof, etc. + */ +static inline u32 +fc_get_ctresp_pyld_len(u32 resp_len) +{ + return resp_len - sizeof(struct ct_hdr_s); +} + +/* + * Convert bfa speed to rpsc speed value. + */ +static inline enum bfa_port_speed +fc_rpsc_operspeed_to_bfa_speed(enum fc_rpsc_op_speed speed) +{ + switch (speed) { + + case RPSC_OP_SPEED_1G: + return BFA_PORT_SPEED_1GBPS; + + case RPSC_OP_SPEED_2G: + return BFA_PORT_SPEED_2GBPS; + + case RPSC_OP_SPEED_4G: + return BFA_PORT_SPEED_4GBPS; + + case RPSC_OP_SPEED_8G: + return BFA_PORT_SPEED_8GBPS; + + case RPSC_OP_SPEED_10G: + return BFA_PORT_SPEED_10GBPS; + + default: + return BFA_PORT_SPEED_UNKNOWN; + } +} + +/* + * Convert RPSC speed to bfa speed value. + */ +static inline enum fc_rpsc_op_speed +fc_bfa_speed_to_rpsc_operspeed(enum bfa_port_speed op_speed) +{ + switch (op_speed) { + + case BFA_PORT_SPEED_1GBPS: + return RPSC_OP_SPEED_1G; + + case BFA_PORT_SPEED_2GBPS: + return RPSC_OP_SPEED_2G; + + case BFA_PORT_SPEED_4GBPS: + return RPSC_OP_SPEED_4G; + + case BFA_PORT_SPEED_8GBPS: + return RPSC_OP_SPEED_8G; + + case BFA_PORT_SPEED_10GBPS: + return RPSC_OP_SPEED_10G; + + default: + return RPSC_OP_SPEED_NOT_EST; + } +} + +enum fc_parse_status { + FC_PARSE_OK = 0, + FC_PARSE_FAILURE = 1, + FC_PARSE_BUSY = 2, + FC_PARSE_LEN_INVAL, + FC_PARSE_ACC_INVAL, + FC_PARSE_PWWN_NOT_EQUAL, + FC_PARSE_NWWN_NOT_EQUAL, + FC_PARSE_RXSZ_INVAL, + FC_PARSE_NOT_FCP, + FC_PARSE_OPAFLAG_INVAL, + FC_PARSE_RPAFLAG_INVAL, + FC_PARSE_OPA_INVAL, + FC_PARSE_RPA_INVAL, + +}; + +struct fc_templates_s { + struct fchs_s fc_els_req; + struct fchs_s fc_bls_req; + struct fc_logi_s plogi; + struct fc_rrq_s rrq; +}; + +void fcbuild_init(void); + +u16 fc_flogi_build(struct fchs_s *fchs, struct fc_logi_s *flogi, + u32 s_id, u16 ox_id, wwn_t port_name, wwn_t node_name, + u16 pdu_size, u8 set_npiv, u8 set_auth, + u16 local_bb_credits); + +u16 fc_fdisc_build(struct fchs_s *buf, struct fc_logi_s *flogi, u32 s_id, + u16 ox_id, wwn_t port_name, wwn_t node_name, + u16 pdu_size); + +u16 fc_flogi_acc_build(struct fchs_s *fchs, struct fc_logi_s *flogi, + u32 s_id, u16 ox_id, + wwn_t port_name, wwn_t node_name, + u16 pdu_size, + u16 local_bb_credits); + +u16 fc_plogi_build(struct fchs_s *fchs, void *pld, u32 d_id, + u32 s_id, u16 ox_id, wwn_t port_name, + wwn_t node_name, u16 pdu_size); + +enum fc_parse_status fc_plogi_parse(struct fchs_s *fchs); + +u16 fc_abts_build(struct fchs_s *buf, u32 d_id, u32 s_id, + u16 ox_id); + +enum fc_parse_status fc_abts_rsp_parse(struct fchs_s *buf, int len); + +u16 fc_rrq_build(struct fchs_s *buf, struct fc_rrq_s *rrq, u32 d_id, + u32 s_id, u16 ox_id, u16 rrq_oxid); +enum fc_parse_status fc_rrq_rsp_parse(struct fchs_s *buf, int len); + +u16 fc_rspnid_build(struct fchs_s *fchs, void *pld, u32 s_id, + u16 ox_id, u8 *name); + +u16 fc_rftid_build(struct fchs_s *fchs, void *pld, u32 s_id, + u16 ox_id, enum bfa_lport_role role); + +u16 fc_rftid_build_sol(struct fchs_s *fchs, void *pyld, u32 s_id, + u16 ox_id, u8 *fc4_bitmap, + u32 bitmap_size); + +u16 fc_rffid_build(struct fchs_s *fchs, void *pyld, u32 s_id, + u16 ox_id, u8 fc4_type, u8 fc4_ftrs); + +u16 fc_gidpn_build(struct fchs_s *fchs, void *pyld, u32 s_id, + u16 ox_id, wwn_t port_name); + +u16 fc_gpnid_build(struct fchs_s *fchs, void *pld, u32 s_id, + u16 ox_id, u32 port_id); + +u16 fc_scr_build(struct fchs_s *fchs, struct fc_scr_s *scr, + u8 set_br_reg, u32 s_id, u16 ox_id); + +u16 fc_plogi_acc_build(struct fchs_s *fchs, void *pld, u32 d_id, + u32 s_id, u16 ox_id, + wwn_t port_name, wwn_t node_name, + u16 pdu_size); + +u16 fc_adisc_build(struct fchs_s *fchs, struct fc_adisc_s *adisc, + u32 d_id, u32 s_id, u16 ox_id, wwn_t port_name, + wwn_t node_name); + +enum fc_parse_status fc_adisc_parse(struct fchs_s *fchs, void *pld, + u32 host_dap, wwn_t node_name, wwn_t port_name); + +enum fc_parse_status fc_adisc_rsp_parse(struct fc_adisc_s *adisc, int len, + wwn_t port_name, wwn_t node_name); + +u16 fc_adisc_acc_build(struct fchs_s *fchs, struct fc_adisc_s *adisc, + u32 d_id, u32 s_id, u16 ox_id, + wwn_t port_name, wwn_t node_name); +u16 fc_ls_rjt_build(struct fchs_s *fchs, struct fc_ls_rjt_s *ls_rjt, + u32 d_id, u32 s_id, u16 ox_id, + u8 reason_code, u8 reason_code_expl); +u16 fc_ls_acc_build(struct fchs_s *fchs, struct fc_els_cmd_s *els_cmd, + u32 d_id, u32 s_id, u16 ox_id); +u16 fc_prli_build(struct fchs_s *fchs, void *pld, u32 d_id, + u32 s_id, u16 ox_id); + +enum fc_parse_status fc_prli_rsp_parse(struct fc_prli_s *prli, int len); + +u16 fc_prli_acc_build(struct fchs_s *fchs, void *pld, u32 d_id, + u32 s_id, u16 ox_id, + enum bfa_lport_role role); + +u16 fc_rnid_build(struct fchs_s *fchs, struct fc_rnid_cmd_s *rnid, + u32 d_id, u32 s_id, u16 ox_id, + u32 data_format); + +u16 fc_rnid_acc_build(struct fchs_s *fchs, + struct fc_rnid_acc_s *rnid_acc, u32 d_id, u32 s_id, + u16 ox_id, u32 data_format, + struct fc_rnid_common_id_data_s *common_id_data, + struct fc_rnid_general_topology_data_s *gen_topo_data); + +u16 fc_rpsc2_build(struct fchs_s *fchs, struct fc_rpsc2_cmd_s *rps2c, + u32 d_id, u32 s_id, u32 *pid_list, u16 npids); +u16 fc_rpsc_build(struct fchs_s *fchs, struct fc_rpsc_cmd_s *rpsc, + u32 d_id, u32 s_id, u16 ox_id); +u16 fc_rpsc_acc_build(struct fchs_s *fchs, + struct fc_rpsc_acc_s *rpsc_acc, u32 d_id, u32 s_id, + u16 ox_id, struct fc_rpsc_speed_info_s *oper_speed); +u16 fc_gid_ft_build(struct fchs_s *fchs, void *pld, u32 s_id, + u8 fc4_type); + +u16 fc_rpnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, + u32 port_id, wwn_t port_name); + +u16 fc_rnnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, + u32 port_id, wwn_t node_name); + +u16 fc_rcsid_build(struct fchs_s *fchs, void *pyld, u32 s_id, + u32 port_id, u32 cos); + +u16 fc_rptid_build(struct fchs_s *fchs, void *pyld, u32 s_id, + u32 port_id, u8 port_type); + +u16 fc_ganxt_build(struct fchs_s *fchs, void *pyld, u32 s_id, + u32 port_id); + +u16 fc_logo_build(struct fchs_s *fchs, struct fc_logo_s *logo, u32 d_id, + u32 s_id, u16 ox_id, wwn_t port_name); + +u16 fc_logo_acc_build(struct fchs_s *fchs, void *pld, u32 d_id, + u32 s_id, u16 ox_id); + +u16 fc_fdmi_reqhdr_build(struct fchs_s *fchs, void *pyld, u32 s_id, + u16 cmd_code); +u16 fc_gmal_req_build(struct fchs_s *fchs, void *pyld, u32 s_id, wwn_t wwn); +u16 fc_gfn_req_build(struct fchs_s *fchs, void *pyld, u32 s_id, wwn_t wwn); + +void fc_get_fc4type_bitmask(u8 fc4_type, u8 *bit_mask); + +void fc_els_req_build(struct fchs_s *fchs, u32 d_id, u32 s_id, + u16 ox_id); + +enum fc_parse_status fc_els_rsp_parse(struct fchs_s *fchs, int len); + +enum fc_parse_status fc_plogi_rsp_parse(struct fchs_s *fchs, int len, + wwn_t port_name); + +enum fc_parse_status fc_prli_parse(struct fc_prli_s *prli); + +enum fc_parse_status fc_pdisc_parse(struct fchs_s *fchs, wwn_t node_name, + wwn_t port_name); + +u16 fc_ba_acc_build(struct fchs_s *fchs, struct fc_ba_acc_s *ba_acc, u32 d_id, + u32 s_id, u16 ox_id, u16 rx_id); + +int fc_logout_params_pages(struct fchs_s *fc_frame, u8 els_code); + +u16 fc_tprlo_acc_build(struct fchs_s *fchs, struct fc_tprlo_acc_s *tprlo_acc, + u32 d_id, u32 s_id, u16 ox_id, int num_pages); + +u16 fc_prlo_acc_build(struct fchs_s *fchs, struct fc_prlo_acc_s *prlo_acc, + u32 d_id, u32 s_id, u16 ox_id, int num_pages); + +u16 fc_logo_rsp_parse(struct fchs_s *fchs, int len); + +u16 fc_pdisc_build(struct fchs_s *fchs, u32 d_id, u32 s_id, + u16 ox_id, wwn_t port_name, wwn_t node_name, + u16 pdu_size); + +u16 fc_pdisc_rsp_parse(struct fchs_s *fchs, int len, wwn_t port_name); + +u16 fc_prlo_build(struct fchs_s *fchs, u32 d_id, u32 s_id, + u16 ox_id, int num_pages); + +u16 fc_prlo_rsp_parse(struct fchs_s *fchs, int len); + +u16 fc_tprlo_build(struct fchs_s *fchs, u32 d_id, u32 s_id, + u16 ox_id, int num_pages, enum fc_tprlo_type tprlo_type, + u32 tpr_id); + +u16 fc_tprlo_rsp_parse(struct fchs_s *fchs, int len); + +u16 fc_ba_rjt_build(struct fchs_s *fchs, u32 d_id, u32 s_id, + u16 ox_id, u32 reason_code, u32 reason_expl); + +u16 fc_gnnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id, + u32 port_id); + +u16 fc_ct_rsp_parse(struct ct_hdr_s *cthdr); + +u16 fc_rscn_build(struct fchs_s *fchs, struct fc_rscn_pl_s *rscn, u32 s_id, + u16 ox_id); +#endif diff --git a/drivers/scsi/bfa/bfa_fcpim.c b/drivers/scsi/bfa/bfa_fcpim.c index 8c703d8dc94b..33c8dd51f474 100644 --- a/drivers/scsi/bfa/bfa_fcpim.c +++ b/drivers/scsi/bfa/bfa_fcpim.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. * All rights reserved * www.brocade.com * @@ -15,18 +15,291 @@ * General Public License for more details. */ -#include <bfa.h> -#include <log/bfa_log_hal.h> +#include "bfa_modules.h" +#include "bfa_cb_ioim.h" BFA_TRC_FILE(HAL, FCPIM); BFA_MODULE(fcpim); + +#define bfa_fcpim_add_iostats(__l, __r, __stats) \ + (__l->__stats += __r->__stats) + + +/** + * BFA ITNIM Related definitions + */ +static void bfa_itnim_update_del_itn_stats(struct bfa_itnim_s *itnim); + +#define BFA_ITNIM_FROM_TAG(_fcpim, _tag) \ + (((_fcpim)->itnim_arr + ((_tag) & ((_fcpim)->num_itnims - 1)))) + +#define bfa_fcpim_additn(__itnim) \ + list_add_tail(&(__itnim)->qe, &(__itnim)->fcpim->itnim_q) +#define bfa_fcpim_delitn(__itnim) do { \ + bfa_assert(bfa_q_is_on_q(&(__itnim)->fcpim->itnim_q, __itnim)); \ + bfa_itnim_update_del_itn_stats(__itnim); \ + list_del(&(__itnim)->qe); \ + bfa_assert(list_empty(&(__itnim)->io_q)); \ + bfa_assert(list_empty(&(__itnim)->io_cleanup_q)); \ + bfa_assert(list_empty(&(__itnim)->pending_q)); \ +} while (0) + +#define bfa_itnim_online_cb(__itnim) do { \ + if ((__itnim)->bfa->fcs) \ + bfa_cb_itnim_online((__itnim)->ditn); \ + else { \ + bfa_cb_queue((__itnim)->bfa, &(__itnim)->hcb_qe, \ + __bfa_cb_itnim_online, (__itnim)); \ + } \ +} while (0) + +#define bfa_itnim_offline_cb(__itnim) do { \ + if ((__itnim)->bfa->fcs) \ + bfa_cb_itnim_offline((__itnim)->ditn); \ + else { \ + bfa_cb_queue((__itnim)->bfa, &(__itnim)->hcb_qe, \ + __bfa_cb_itnim_offline, (__itnim)); \ + } \ +} while (0) + +#define bfa_itnim_sler_cb(__itnim) do { \ + if ((__itnim)->bfa->fcs) \ + bfa_cb_itnim_sler((__itnim)->ditn); \ + else { \ + bfa_cb_queue((__itnim)->bfa, &(__itnim)->hcb_qe, \ + __bfa_cb_itnim_sler, (__itnim)); \ + } \ +} while (0) + +/** + * bfa_itnim_sm BFA itnim state machine + */ + + +enum bfa_itnim_event { + BFA_ITNIM_SM_CREATE = 1, /* itnim is created */ + BFA_ITNIM_SM_ONLINE = 2, /* itnim is online */ + BFA_ITNIM_SM_OFFLINE = 3, /* itnim is offline */ + BFA_ITNIM_SM_FWRSP = 4, /* firmware response */ + BFA_ITNIM_SM_DELETE = 5, /* deleting an existing itnim */ + BFA_ITNIM_SM_CLEANUP = 6, /* IO cleanup completion */ + BFA_ITNIM_SM_SLER = 7, /* second level error recovery */ + BFA_ITNIM_SM_HWFAIL = 8, /* IOC h/w failure event */ + BFA_ITNIM_SM_QRESUME = 9, /* queue space available */ +}; + +/** + * BFA IOIM related definitions + */ +#define bfa_ioim_move_to_comp_q(__ioim) do { \ + list_del(&(__ioim)->qe); \ + list_add_tail(&(__ioim)->qe, &(__ioim)->fcpim->ioim_comp_q); \ +} while (0) + + +#define bfa_ioim_cb_profile_comp(__fcpim, __ioim) do { \ + if ((__fcpim)->profile_comp) \ + (__fcpim)->profile_comp(__ioim); \ +} while (0) + +#define bfa_ioim_cb_profile_start(__fcpim, __ioim) do { \ + if ((__fcpim)->profile_start) \ + (__fcpim)->profile_start(__ioim); \ +} while (0) +/** + * hal_ioim_sm + */ + +/** + * IO state machine events + */ +enum bfa_ioim_event { + BFA_IOIM_SM_START = 1, /* io start request from host */ + BFA_IOIM_SM_COMP_GOOD = 2, /* io good comp, resource free */ + BFA_IOIM_SM_COMP = 3, /* io comp, resource is free */ + BFA_IOIM_SM_COMP_UTAG = 4, /* io comp, resource is free */ + BFA_IOIM_SM_DONE = 5, /* io comp, resource not free */ + BFA_IOIM_SM_FREE = 6, /* io resource is freed */ + BFA_IOIM_SM_ABORT = 7, /* abort request from scsi stack */ + BFA_IOIM_SM_ABORT_COMP = 8, /* abort from f/w */ + BFA_IOIM_SM_ABORT_DONE = 9, /* abort completion from f/w */ + BFA_IOIM_SM_QRESUME = 10, /* CQ space available to queue IO */ + BFA_IOIM_SM_SGALLOCED = 11, /* SG page allocation successful */ + BFA_IOIM_SM_SQRETRY = 12, /* sequence recovery retry */ + BFA_IOIM_SM_HCB = 13, /* bfa callback complete */ + BFA_IOIM_SM_CLEANUP = 14, /* IO cleanup from itnim */ + BFA_IOIM_SM_TMSTART = 15, /* IO cleanup from tskim */ + BFA_IOIM_SM_TMDONE = 16, /* IO cleanup from tskim */ + BFA_IOIM_SM_HWFAIL = 17, /* IOC h/w failure event */ + BFA_IOIM_SM_IOTOV = 18, /* ITN offline TOV */ +}; + + +/** + * BFA TSKIM related definitions + */ + +/** + * task management completion handling + */ +#define bfa_tskim_qcomp(__tskim, __cbfn) do { \ + bfa_cb_queue((__tskim)->bfa, &(__tskim)->hcb_qe, __cbfn, (__tskim));\ + bfa_tskim_notify_comp(__tskim); \ +} while (0) + +#define bfa_tskim_notify_comp(__tskim) do { \ + if ((__tskim)->notify) \ + bfa_itnim_tskdone((__tskim)->itnim); \ +} while (0) + + +enum bfa_tskim_event { + BFA_TSKIM_SM_START = 1, /* TM command start */ + BFA_TSKIM_SM_DONE = 2, /* TM completion */ + BFA_TSKIM_SM_QRESUME = 3, /* resume after qfull */ + BFA_TSKIM_SM_HWFAIL = 5, /* IOC h/w failure event */ + BFA_TSKIM_SM_HCB = 6, /* BFA callback completion */ + BFA_TSKIM_SM_IOS_DONE = 7, /* IO and sub TM completions */ + BFA_TSKIM_SM_CLEANUP = 8, /* TM cleanup on ITN offline */ + BFA_TSKIM_SM_CLEANUP_DONE = 9, /* TM abort completion */ +}; + +/** + * forward declaration for BFA ITNIM functions + */ +static void bfa_itnim_iocdisable_cleanup(struct bfa_itnim_s *itnim); +static bfa_boolean_t bfa_itnim_send_fwcreate(struct bfa_itnim_s *itnim); +static bfa_boolean_t bfa_itnim_send_fwdelete(struct bfa_itnim_s *itnim); +static void bfa_itnim_cleanp_comp(void *itnim_cbarg); +static void bfa_itnim_cleanup(struct bfa_itnim_s *itnim); +static void __bfa_cb_itnim_online(void *cbarg, bfa_boolean_t complete); +static void __bfa_cb_itnim_offline(void *cbarg, bfa_boolean_t complete); +static void __bfa_cb_itnim_sler(void *cbarg, bfa_boolean_t complete); +static void bfa_itnim_iotov_online(struct bfa_itnim_s *itnim); +static void bfa_itnim_iotov_cleanup(struct bfa_itnim_s *itnim); +static void bfa_itnim_iotov(void *itnim_arg); +static void bfa_itnim_iotov_start(struct bfa_itnim_s *itnim); +static void bfa_itnim_iotov_stop(struct bfa_itnim_s *itnim); +static void bfa_itnim_iotov_delete(struct bfa_itnim_s *itnim); + +/** + * forward declaration of ITNIM state machine + */ +static void bfa_itnim_sm_uninit(struct bfa_itnim_s *itnim, + enum bfa_itnim_event event); +static void bfa_itnim_sm_created(struct bfa_itnim_s *itnim, + enum bfa_itnim_event event); +static void bfa_itnim_sm_fwcreate(struct bfa_itnim_s *itnim, + enum bfa_itnim_event event); +static void bfa_itnim_sm_delete_pending(struct bfa_itnim_s *itnim, + enum bfa_itnim_event event); +static void bfa_itnim_sm_online(struct bfa_itnim_s *itnim, + enum bfa_itnim_event event); +static void bfa_itnim_sm_sler(struct bfa_itnim_s *itnim, + enum bfa_itnim_event event); +static void bfa_itnim_sm_cleanup_offline(struct bfa_itnim_s *itnim, + enum bfa_itnim_event event); +static void bfa_itnim_sm_cleanup_delete(struct bfa_itnim_s *itnim, + enum bfa_itnim_event event); +static void bfa_itnim_sm_fwdelete(struct bfa_itnim_s *itnim, + enum bfa_itnim_event event); +static void bfa_itnim_sm_offline(struct bfa_itnim_s *itnim, + enum bfa_itnim_event event); +static void bfa_itnim_sm_iocdisable(struct bfa_itnim_s *itnim, + enum bfa_itnim_event event); +static void bfa_itnim_sm_deleting(struct bfa_itnim_s *itnim, + enum bfa_itnim_event event); +static void bfa_itnim_sm_fwcreate_qfull(struct bfa_itnim_s *itnim, + enum bfa_itnim_event event); +static void bfa_itnim_sm_fwdelete_qfull(struct bfa_itnim_s *itnim, + enum bfa_itnim_event event); +static void bfa_itnim_sm_deleting_qfull(struct bfa_itnim_s *itnim, + enum bfa_itnim_event event); + +/** + * forward declaration for BFA IOIM functions + */ +static bfa_boolean_t bfa_ioim_send_ioreq(struct bfa_ioim_s *ioim); +static bfa_boolean_t bfa_ioim_sge_setup(struct bfa_ioim_s *ioim); +static void bfa_ioim_sgpg_setup(struct bfa_ioim_s *ioim); +static bfa_boolean_t bfa_ioim_send_abort(struct bfa_ioim_s *ioim); +static void bfa_ioim_notify_cleanup(struct bfa_ioim_s *ioim); +static void __bfa_cb_ioim_good_comp(void *cbarg, bfa_boolean_t complete); +static void __bfa_cb_ioim_comp(void *cbarg, bfa_boolean_t complete); +static void __bfa_cb_ioim_abort(void *cbarg, bfa_boolean_t complete); +static void __bfa_cb_ioim_failed(void *cbarg, bfa_boolean_t complete); +static void __bfa_cb_ioim_pathtov(void *cbarg, bfa_boolean_t complete); +static bfa_boolean_t bfa_ioim_is_abortable(struct bfa_ioim_s *ioim); + + +/** + * forward declaration of BFA IO state machine + */ +static void bfa_ioim_sm_uninit(struct bfa_ioim_s *ioim, + enum bfa_ioim_event event); +static void bfa_ioim_sm_sgalloc(struct bfa_ioim_s *ioim, + enum bfa_ioim_event event); +static void bfa_ioim_sm_active(struct bfa_ioim_s *ioim, + enum bfa_ioim_event event); +static void bfa_ioim_sm_abort(struct bfa_ioim_s *ioim, + enum bfa_ioim_event event); +static void bfa_ioim_sm_cleanup(struct bfa_ioim_s *ioim, + enum bfa_ioim_event event); +static void bfa_ioim_sm_qfull(struct bfa_ioim_s *ioim, + enum bfa_ioim_event event); +static void bfa_ioim_sm_abort_qfull(struct bfa_ioim_s *ioim, + enum bfa_ioim_event event); +static void bfa_ioim_sm_cleanup_qfull(struct bfa_ioim_s *ioim, + enum bfa_ioim_event event); +static void bfa_ioim_sm_hcb(struct bfa_ioim_s *ioim, + enum bfa_ioim_event event); +static void bfa_ioim_sm_hcb_free(struct bfa_ioim_s *ioim, + enum bfa_ioim_event event); +static void bfa_ioim_sm_resfree(struct bfa_ioim_s *ioim, + enum bfa_ioim_event event); +static void bfa_ioim_sm_cmnd_retry(struct bfa_ioim_s *ioim, + enum bfa_ioim_event event); + +/** + * forward declaration for BFA TSKIM functions + */ +static void __bfa_cb_tskim_done(void *cbarg, bfa_boolean_t complete); +static void __bfa_cb_tskim_failed(void *cbarg, bfa_boolean_t complete); +static bfa_boolean_t bfa_tskim_match_scope(struct bfa_tskim_s *tskim, + lun_t lun); +static void bfa_tskim_gather_ios(struct bfa_tskim_s *tskim); +static void bfa_tskim_cleanp_comp(void *tskim_cbarg); +static void bfa_tskim_cleanup_ios(struct bfa_tskim_s *tskim); +static bfa_boolean_t bfa_tskim_send(struct bfa_tskim_s *tskim); +static bfa_boolean_t bfa_tskim_send_abort(struct bfa_tskim_s *tskim); +static void bfa_tskim_iocdisable_ios(struct bfa_tskim_s *tskim); + + +/** + * forward declaration of BFA TSKIM state machine + */ +static void bfa_tskim_sm_uninit(struct bfa_tskim_s *tskim, + enum bfa_tskim_event event); +static void bfa_tskim_sm_active(struct bfa_tskim_s *tskim, + enum bfa_tskim_event event); +static void bfa_tskim_sm_cleanup(struct bfa_tskim_s *tskim, + enum bfa_tskim_event event); +static void bfa_tskim_sm_iocleanup(struct bfa_tskim_s *tskim, + enum bfa_tskim_event event); +static void bfa_tskim_sm_qfull(struct bfa_tskim_s *tskim, + enum bfa_tskim_event event); +static void bfa_tskim_sm_cleanup_qfull(struct bfa_tskim_s *tskim, + enum bfa_tskim_event event); +static void bfa_tskim_sm_hcb(struct bfa_tskim_s *tskim, + enum bfa_tskim_event event); + /** * hal_fcpim_mod BFA FCP Initiator Mode module */ /** - * Compute and return memory needed by FCP(im) module. + * Compute and return memory needed by FCP(im) module. */ static void bfa_fcpim_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len, @@ -58,7 +331,7 @@ bfa_fcpim_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len, static void bfa_fcpim_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, - struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev) + struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev) { struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); @@ -67,12 +340,14 @@ bfa_fcpim_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, bfa_trc(bfa, cfg->fwcfg.num_ioim_reqs); bfa_trc(bfa, cfg->fwcfg.num_tskim_reqs); - fcpim->bfa = bfa; - fcpim->num_itnims = cfg->fwcfg.num_rports; + fcpim->bfa = bfa; + fcpim->num_itnims = cfg->fwcfg.num_rports; fcpim->num_ioim_reqs = cfg->fwcfg.num_ioim_reqs; fcpim->num_tskim_reqs = cfg->fwcfg.num_tskim_reqs; - fcpim->path_tov = cfg->drvcfg.path_tov; - fcpim->delay_comp = cfg->drvcfg.delay_comp; + fcpim->path_tov = cfg->drvcfg.path_tov; + fcpim->delay_comp = cfg->drvcfg.delay_comp; + fcpim->profile_comp = NULL; + fcpim->profile_start = NULL; bfa_itnim_attach(fcpim, meminfo); bfa_tskim_attach(fcpim, meminfo); @@ -103,7 +378,7 @@ bfa_fcpim_iocdisable(struct bfa_s *bfa) { struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); struct bfa_itnim_s *itnim; - struct list_head *qe, *qen; + struct list_head *qe, *qen; list_for_each_safe(qe, qen, &fcpim->itnim_q) { itnim = (struct bfa_itnim_s *) qe; @@ -112,6 +387,56 @@ bfa_fcpim_iocdisable(struct bfa_s *bfa) } void +bfa_fcpim_add_stats(struct bfa_itnim_iostats_s *lstats, + struct bfa_itnim_iostats_s *rstats) +{ + bfa_fcpim_add_iostats(lstats, rstats, total_ios); + bfa_fcpim_add_iostats(lstats, rstats, qresumes); + bfa_fcpim_add_iostats(lstats, rstats, no_iotags); + bfa_fcpim_add_iostats(lstats, rstats, io_aborts); + bfa_fcpim_add_iostats(lstats, rstats, no_tskims); + bfa_fcpim_add_iostats(lstats, rstats, iocomp_ok); + bfa_fcpim_add_iostats(lstats, rstats, iocomp_underrun); + bfa_fcpim_add_iostats(lstats, rstats, iocomp_overrun); + bfa_fcpim_add_iostats(lstats, rstats, iocomp_aborted); + bfa_fcpim_add_iostats(lstats, rstats, iocomp_timedout); + bfa_fcpim_add_iostats(lstats, rstats, iocom_nexus_abort); + bfa_fcpim_add_iostats(lstats, rstats, iocom_proto_err); + bfa_fcpim_add_iostats(lstats, rstats, iocom_dif_err); + bfa_fcpim_add_iostats(lstats, rstats, iocom_sqer_needed); + bfa_fcpim_add_iostats(lstats, rstats, iocom_res_free); + bfa_fcpim_add_iostats(lstats, rstats, iocom_hostabrts); + bfa_fcpim_add_iostats(lstats, rstats, iocom_utags); + bfa_fcpim_add_iostats(lstats, rstats, io_cleanups); + bfa_fcpim_add_iostats(lstats, rstats, io_tmaborts); + bfa_fcpim_add_iostats(lstats, rstats, onlines); + bfa_fcpim_add_iostats(lstats, rstats, offlines); + bfa_fcpim_add_iostats(lstats, rstats, creates); + bfa_fcpim_add_iostats(lstats, rstats, deletes); + bfa_fcpim_add_iostats(lstats, rstats, create_comps); + bfa_fcpim_add_iostats(lstats, rstats, delete_comps); + bfa_fcpim_add_iostats(lstats, rstats, sler_events); + bfa_fcpim_add_iostats(lstats, rstats, fw_create); + bfa_fcpim_add_iostats(lstats, rstats, fw_delete); + bfa_fcpim_add_iostats(lstats, rstats, ioc_disabled); + bfa_fcpim_add_iostats(lstats, rstats, cleanup_comps); + bfa_fcpim_add_iostats(lstats, rstats, tm_cmnds); + bfa_fcpim_add_iostats(lstats, rstats, tm_fw_rsps); + bfa_fcpim_add_iostats(lstats, rstats, tm_success); + bfa_fcpim_add_iostats(lstats, rstats, tm_failures); + bfa_fcpim_add_iostats(lstats, rstats, tm_io_comps); + bfa_fcpim_add_iostats(lstats, rstats, tm_qresumes); + bfa_fcpim_add_iostats(lstats, rstats, tm_iocdowns); + bfa_fcpim_add_iostats(lstats, rstats, tm_cleanups); + bfa_fcpim_add_iostats(lstats, rstats, tm_cleanup_comps); + bfa_fcpim_add_iostats(lstats, rstats, io_comps); + bfa_fcpim_add_iostats(lstats, rstats, input_reqs); + bfa_fcpim_add_iostats(lstats, rstats, output_reqs); + bfa_fcpim_add_iostats(lstats, rstats, rd_throughput); + bfa_fcpim_add_iostats(lstats, rstats, wr_throughput); +} + +void bfa_fcpim_path_tov_set(struct bfa_s *bfa, u16 path_tov) { struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); @@ -130,21 +455,113 @@ bfa_fcpim_path_tov_get(struct bfa_s *bfa) } bfa_status_t -bfa_fcpim_get_modstats(struct bfa_s *bfa, struct bfa_fcpim_stats_s *modstats) +bfa_fcpim_port_iostats(struct bfa_s *bfa, struct bfa_itnim_iostats_s *stats, + u8 lp_tag) +{ + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); + struct list_head *qe, *qen; + struct bfa_itnim_s *itnim; + + /* accumulate IO stats from itnim */ + bfa_os_memset(stats, 0, sizeof(struct bfa_itnim_iostats_s)); + list_for_each_safe(qe, qen, &fcpim->itnim_q) { + itnim = (struct bfa_itnim_s *) qe; + if (itnim->rport->rport_info.lp_tag != lp_tag) + continue; + bfa_fcpim_add_stats(stats, &(itnim->stats)); + } + return BFA_STATUS_OK; +} +bfa_status_t +bfa_fcpim_get_modstats(struct bfa_s *bfa, struct bfa_itnim_iostats_s *modstats) +{ + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); + struct list_head *qe, *qen; + struct bfa_itnim_s *itnim; + + /* accumulate IO stats from itnim */ + bfa_os_memset(modstats, 0, sizeof(struct bfa_itnim_iostats_s)); + list_for_each_safe(qe, qen, &fcpim->itnim_q) { + itnim = (struct bfa_itnim_s *) qe; + bfa_fcpim_add_stats(modstats, &(itnim->stats)); + } + return BFA_STATUS_OK; +} + +bfa_status_t +bfa_fcpim_get_del_itn_stats(struct bfa_s *bfa, + struct bfa_fcpim_del_itn_stats_s *modstats) { struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); - *modstats = fcpim->stats; + *modstats = fcpim->del_itn_stats; return BFA_STATUS_OK; } + +bfa_status_t +bfa_fcpim_profile_on(struct bfa_s *bfa, u32 time) +{ + struct bfa_itnim_s *itnim; + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); + struct list_head *qe, *qen; + + /* accumulate IO stats from itnim */ + list_for_each_safe(qe, qen, &fcpim->itnim_q) { + itnim = (struct bfa_itnim_s *) qe; + bfa_itnim_clear_stats(itnim); + } + fcpim->io_profile = BFA_TRUE; + fcpim->io_profile_start_time = time; + fcpim->profile_comp = bfa_ioim_profile_comp; + fcpim->profile_start = bfa_ioim_profile_start; + + return BFA_STATUS_OK; +} +bfa_status_t +bfa_fcpim_profile_off(struct bfa_s *bfa) +{ + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); + fcpim->io_profile = BFA_FALSE; + fcpim->io_profile_start_time = 0; + fcpim->profile_comp = NULL; + fcpim->profile_start = NULL; + return BFA_STATUS_OK; +} + +bfa_status_t +bfa_fcpim_port_clear_iostats(struct bfa_s *bfa, u8 lp_tag) +{ + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); + struct list_head *qe, *qen; + struct bfa_itnim_s *itnim; + + /* clear IO stats from all active itnims */ + list_for_each_safe(qe, qen, &fcpim->itnim_q) { + itnim = (struct bfa_itnim_s *) qe; + if (itnim->rport->rport_info.lp_tag != lp_tag) + continue; + bfa_itnim_clear_stats(itnim); + } + return BFA_STATUS_OK; + +} + bfa_status_t bfa_fcpim_clr_modstats(struct bfa_s *bfa) { struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); + struct list_head *qe, *qen; + struct bfa_itnim_s *itnim; - memset(&fcpim->stats, 0, sizeof(struct bfa_fcpim_stats_s)); + /* clear IO stats from all active itnims */ + list_for_each_safe(qe, qen, &fcpim->itnim_q) { + itnim = (struct bfa_itnim_s *) qe; + bfa_itnim_clear_stats(itnim); + } + bfa_os_memset(&fcpim->del_itn_stats, 0, + sizeof(struct bfa_fcpim_del_itn_stats_s)); return BFA_STATUS_OK; } @@ -176,14 +593,6 @@ bfa_fcpim_update_ioredirect(struct bfa_s *bfa) * 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 @@ -192,3 +601,3012 @@ 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; } + + + +/** + * BFA ITNIM module state machine functions + */ + +/** + * Beginning/unallocated state - no events expected. + */ +static void +bfa_itnim_sm_uninit(struct bfa_itnim_s *itnim, enum bfa_itnim_event event) +{ + bfa_trc(itnim->bfa, itnim->rport->rport_tag); + bfa_trc(itnim->bfa, event); + + switch (event) { + case BFA_ITNIM_SM_CREATE: + bfa_sm_set_state(itnim, bfa_itnim_sm_created); + itnim->is_online = BFA_FALSE; + bfa_fcpim_additn(itnim); + break; + + default: + bfa_sm_fault(itnim->bfa, event); + } +} + +/** + * Beginning state, only online event expected. + */ +static void +bfa_itnim_sm_created(struct bfa_itnim_s *itnim, enum bfa_itnim_event event) +{ + bfa_trc(itnim->bfa, itnim->rport->rport_tag); + bfa_trc(itnim->bfa, event); + + switch (event) { + case BFA_ITNIM_SM_ONLINE: + if (bfa_itnim_send_fwcreate(itnim)) + bfa_sm_set_state(itnim, bfa_itnim_sm_fwcreate); + else + bfa_sm_set_state(itnim, bfa_itnim_sm_fwcreate_qfull); + break; + + case BFA_ITNIM_SM_DELETE: + bfa_sm_set_state(itnim, bfa_itnim_sm_uninit); + bfa_fcpim_delitn(itnim); + break; + + case BFA_ITNIM_SM_HWFAIL: + bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable); + break; + + default: + bfa_sm_fault(itnim->bfa, event); + } +} + +/** + * Waiting for itnim create response from firmware. + */ +static void +bfa_itnim_sm_fwcreate(struct bfa_itnim_s *itnim, enum bfa_itnim_event event) +{ + bfa_trc(itnim->bfa, itnim->rport->rport_tag); + bfa_trc(itnim->bfa, event); + + switch (event) { + case BFA_ITNIM_SM_FWRSP: + bfa_sm_set_state(itnim, bfa_itnim_sm_online); + itnim->is_online = BFA_TRUE; + bfa_itnim_iotov_online(itnim); + bfa_itnim_online_cb(itnim); + break; + + case BFA_ITNIM_SM_DELETE: + bfa_sm_set_state(itnim, bfa_itnim_sm_delete_pending); + break; + + case BFA_ITNIM_SM_OFFLINE: + if (bfa_itnim_send_fwdelete(itnim)) + bfa_sm_set_state(itnim, bfa_itnim_sm_fwdelete); + else + bfa_sm_set_state(itnim, bfa_itnim_sm_fwdelete_qfull); + break; + + case BFA_ITNIM_SM_HWFAIL: + bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable); + break; + + default: + bfa_sm_fault(itnim->bfa, event); + } +} + +static void +bfa_itnim_sm_fwcreate_qfull(struct bfa_itnim_s *itnim, + enum bfa_itnim_event event) +{ + bfa_trc(itnim->bfa, itnim->rport->rport_tag); + bfa_trc(itnim->bfa, event); + + switch (event) { + case BFA_ITNIM_SM_QRESUME: + bfa_sm_set_state(itnim, bfa_itnim_sm_fwcreate); + bfa_itnim_send_fwcreate(itnim); + break; + + case BFA_ITNIM_SM_DELETE: + bfa_sm_set_state(itnim, bfa_itnim_sm_uninit); + bfa_reqq_wcancel(&itnim->reqq_wait); + bfa_fcpim_delitn(itnim); + break; + + case BFA_ITNIM_SM_OFFLINE: + bfa_sm_set_state(itnim, bfa_itnim_sm_offline); + bfa_reqq_wcancel(&itnim->reqq_wait); + bfa_itnim_offline_cb(itnim); + break; + + case BFA_ITNIM_SM_HWFAIL: + bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable); + bfa_reqq_wcancel(&itnim->reqq_wait); + break; + + default: + bfa_sm_fault(itnim->bfa, event); + } +} + +/** + * Waiting for itnim create response from firmware, a delete is pending. + */ +static void +bfa_itnim_sm_delete_pending(struct bfa_itnim_s *itnim, + enum bfa_itnim_event event) +{ + bfa_trc(itnim->bfa, itnim->rport->rport_tag); + bfa_trc(itnim->bfa, event); + + switch (event) { + case BFA_ITNIM_SM_FWRSP: + if (bfa_itnim_send_fwdelete(itnim)) + bfa_sm_set_state(itnim, bfa_itnim_sm_deleting); + else + bfa_sm_set_state(itnim, bfa_itnim_sm_deleting_qfull); + break; + + case BFA_ITNIM_SM_HWFAIL: + bfa_sm_set_state(itnim, bfa_itnim_sm_uninit); + bfa_fcpim_delitn(itnim); + break; + + default: + bfa_sm_fault(itnim->bfa, event); + } +} + +/** + * Online state - normal parking state. + */ +static void +bfa_itnim_sm_online(struct bfa_itnim_s *itnim, enum bfa_itnim_event event) +{ + bfa_trc(itnim->bfa, itnim->rport->rport_tag); + bfa_trc(itnim->bfa, event); + + switch (event) { + case BFA_ITNIM_SM_OFFLINE: + bfa_sm_set_state(itnim, bfa_itnim_sm_cleanup_offline); + itnim->is_online = BFA_FALSE; + bfa_itnim_iotov_start(itnim); + bfa_itnim_cleanup(itnim); + break; + + case BFA_ITNIM_SM_DELETE: + bfa_sm_set_state(itnim, bfa_itnim_sm_cleanup_delete); + itnim->is_online = BFA_FALSE; + bfa_itnim_cleanup(itnim); + break; + + case BFA_ITNIM_SM_SLER: + bfa_sm_set_state(itnim, bfa_itnim_sm_sler); + itnim->is_online = BFA_FALSE; + bfa_itnim_iotov_start(itnim); + bfa_itnim_sler_cb(itnim); + break; + + case BFA_ITNIM_SM_HWFAIL: + bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable); + itnim->is_online = BFA_FALSE; + bfa_itnim_iotov_start(itnim); + bfa_itnim_iocdisable_cleanup(itnim); + break; + + default: + bfa_sm_fault(itnim->bfa, event); + } +} + +/** + * Second level error recovery need. + */ +static void +bfa_itnim_sm_sler(struct bfa_itnim_s *itnim, enum bfa_itnim_event event) +{ + bfa_trc(itnim->bfa, itnim->rport->rport_tag); + bfa_trc(itnim->bfa, event); + + switch (event) { + case BFA_ITNIM_SM_OFFLINE: + bfa_sm_set_state(itnim, bfa_itnim_sm_cleanup_offline); + bfa_itnim_cleanup(itnim); + break; + + case BFA_ITNIM_SM_DELETE: + bfa_sm_set_state(itnim, bfa_itnim_sm_cleanup_delete); + bfa_itnim_cleanup(itnim); + bfa_itnim_iotov_delete(itnim); + break; + + case BFA_ITNIM_SM_HWFAIL: + bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable); + bfa_itnim_iocdisable_cleanup(itnim); + break; + + default: + bfa_sm_fault(itnim->bfa, event); + } +} + +/** + * Going offline. Waiting for active IO cleanup. + */ +static void +bfa_itnim_sm_cleanup_offline(struct bfa_itnim_s *itnim, + enum bfa_itnim_event event) +{ + bfa_trc(itnim->bfa, itnim->rport->rport_tag); + bfa_trc(itnim->bfa, event); + + switch (event) { + case BFA_ITNIM_SM_CLEANUP: + if (bfa_itnim_send_fwdelete(itnim)) + bfa_sm_set_state(itnim, bfa_itnim_sm_fwdelete); + else + bfa_sm_set_state(itnim, bfa_itnim_sm_fwdelete_qfull); + break; + + case BFA_ITNIM_SM_DELETE: + bfa_sm_set_state(itnim, bfa_itnim_sm_cleanup_delete); + bfa_itnim_iotov_delete(itnim); + break; + + case BFA_ITNIM_SM_HWFAIL: + bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable); + bfa_itnim_iocdisable_cleanup(itnim); + bfa_itnim_offline_cb(itnim); + break; + + case BFA_ITNIM_SM_SLER: + break; + + default: + bfa_sm_fault(itnim->bfa, event); + } +} + +/** + * Deleting itnim. Waiting for active IO cleanup. + */ +static void +bfa_itnim_sm_cleanup_delete(struct bfa_itnim_s *itnim, + enum bfa_itnim_event event) +{ + bfa_trc(itnim->bfa, itnim->rport->rport_tag); + bfa_trc(itnim->bfa, event); + + switch (event) { + case BFA_ITNIM_SM_CLEANUP: + if (bfa_itnim_send_fwdelete(itnim)) + bfa_sm_set_state(itnim, bfa_itnim_sm_deleting); + else + bfa_sm_set_state(itnim, bfa_itnim_sm_deleting_qfull); + break; + + case BFA_ITNIM_SM_HWFAIL: + bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable); + bfa_itnim_iocdisable_cleanup(itnim); + break; + + default: + bfa_sm_fault(itnim->bfa, event); + } +} + +/** + * Rport offline. Fimrware itnim is being deleted - awaiting f/w response. + */ +static void +bfa_itnim_sm_fwdelete(struct bfa_itnim_s *itnim, enum bfa_itnim_event event) +{ + bfa_trc(itnim->bfa, itnim->rport->rport_tag); + bfa_trc(itnim->bfa, event); + + switch (event) { + case BFA_ITNIM_SM_FWRSP: + bfa_sm_set_state(itnim, bfa_itnim_sm_offline); + bfa_itnim_offline_cb(itnim); + break; + + case BFA_ITNIM_SM_DELETE: + bfa_sm_set_state(itnim, bfa_itnim_sm_deleting); + break; + + case BFA_ITNIM_SM_HWFAIL: + bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable); + bfa_itnim_offline_cb(itnim); + break; + + default: + bfa_sm_fault(itnim->bfa, event); + } +} + +static void +bfa_itnim_sm_fwdelete_qfull(struct bfa_itnim_s *itnim, + enum bfa_itnim_event event) +{ + bfa_trc(itnim->bfa, itnim->rport->rport_tag); + bfa_trc(itnim->bfa, event); + + switch (event) { + case BFA_ITNIM_SM_QRESUME: + bfa_sm_set_state(itnim, bfa_itnim_sm_fwdelete); + bfa_itnim_send_fwdelete(itnim); + break; + + case BFA_ITNIM_SM_DELETE: + bfa_sm_set_state(itnim, bfa_itnim_sm_deleting_qfull); + break; + + case BFA_ITNIM_SM_HWFAIL: + bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable); + bfa_reqq_wcancel(&itnim->reqq_wait); + bfa_itnim_offline_cb(itnim); + break; + + default: + bfa_sm_fault(itnim->bfa, event); + } +} + +/** + * Offline state. + */ +static void +bfa_itnim_sm_offline(struct bfa_itnim_s *itnim, enum bfa_itnim_event event) +{ + bfa_trc(itnim->bfa, itnim->rport->rport_tag); + bfa_trc(itnim->bfa, event); + + switch (event) { + case BFA_ITNIM_SM_DELETE: + bfa_sm_set_state(itnim, bfa_itnim_sm_uninit); + bfa_itnim_iotov_delete(itnim); + bfa_fcpim_delitn(itnim); + break; + + case BFA_ITNIM_SM_ONLINE: + if (bfa_itnim_send_fwcreate(itnim)) + bfa_sm_set_state(itnim, bfa_itnim_sm_fwcreate); + else + bfa_sm_set_state(itnim, bfa_itnim_sm_fwcreate_qfull); + break; + + case BFA_ITNIM_SM_HWFAIL: + bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable); + break; + + default: + bfa_sm_fault(itnim->bfa, event); + } +} + +/** + * IOC h/w failed state. + */ +static void +bfa_itnim_sm_iocdisable(struct bfa_itnim_s *itnim, + enum bfa_itnim_event event) +{ + bfa_trc(itnim->bfa, itnim->rport->rport_tag); + bfa_trc(itnim->bfa, event); + + switch (event) { + case BFA_ITNIM_SM_DELETE: + bfa_sm_set_state(itnim, bfa_itnim_sm_uninit); + bfa_itnim_iotov_delete(itnim); + bfa_fcpim_delitn(itnim); + break; + + case BFA_ITNIM_SM_OFFLINE: + bfa_itnim_offline_cb(itnim); + break; + + case BFA_ITNIM_SM_ONLINE: + if (bfa_itnim_send_fwcreate(itnim)) + bfa_sm_set_state(itnim, bfa_itnim_sm_fwcreate); + else + bfa_sm_set_state(itnim, bfa_itnim_sm_fwcreate_qfull); + break; + + case BFA_ITNIM_SM_HWFAIL: + break; + + default: + bfa_sm_fault(itnim->bfa, event); + } +} + +/** + * Itnim is deleted, waiting for firmware response to delete. + */ +static void +bfa_itnim_sm_deleting(struct bfa_itnim_s *itnim, enum bfa_itnim_event event) +{ + bfa_trc(itnim->bfa, itnim->rport->rport_tag); + bfa_trc(itnim->bfa, event); + + switch (event) { + case BFA_ITNIM_SM_FWRSP: + case BFA_ITNIM_SM_HWFAIL: + bfa_sm_set_state(itnim, bfa_itnim_sm_uninit); + bfa_fcpim_delitn(itnim); + break; + + default: + bfa_sm_fault(itnim->bfa, event); + } +} + +static void +bfa_itnim_sm_deleting_qfull(struct bfa_itnim_s *itnim, + enum bfa_itnim_event event) +{ + bfa_trc(itnim->bfa, itnim->rport->rport_tag); + bfa_trc(itnim->bfa, event); + + switch (event) { + case BFA_ITNIM_SM_QRESUME: + bfa_sm_set_state(itnim, bfa_itnim_sm_deleting); + bfa_itnim_send_fwdelete(itnim); + break; + + case BFA_ITNIM_SM_HWFAIL: + bfa_sm_set_state(itnim, bfa_itnim_sm_uninit); + bfa_reqq_wcancel(&itnim->reqq_wait); + bfa_fcpim_delitn(itnim); + break; + + default: + bfa_sm_fault(itnim->bfa, event); + } +} + +/** + * Initiate cleanup of all IOs on an IOC failure. + */ +static void +bfa_itnim_iocdisable_cleanup(struct bfa_itnim_s *itnim) +{ + struct bfa_tskim_s *tskim; + struct bfa_ioim_s *ioim; + struct list_head *qe, *qen; + + list_for_each_safe(qe, qen, &itnim->tsk_q) { + tskim = (struct bfa_tskim_s *) qe; + bfa_tskim_iocdisable(tskim); + } + + list_for_each_safe(qe, qen, &itnim->io_q) { + ioim = (struct bfa_ioim_s *) qe; + bfa_ioim_iocdisable(ioim); + } + + /** + * For IO request in pending queue, we pretend an early timeout. + */ + list_for_each_safe(qe, qen, &itnim->pending_q) { + ioim = (struct bfa_ioim_s *) qe; + bfa_ioim_tov(ioim); + } + + list_for_each_safe(qe, qen, &itnim->io_cleanup_q) { + ioim = (struct bfa_ioim_s *) qe; + bfa_ioim_iocdisable(ioim); + } +} + +/** + * IO cleanup completion + */ +static void +bfa_itnim_cleanp_comp(void *itnim_cbarg) +{ + struct bfa_itnim_s *itnim = itnim_cbarg; + + bfa_stats(itnim, cleanup_comps); + bfa_sm_send_event(itnim, BFA_ITNIM_SM_CLEANUP); +} + +/** + * Initiate cleanup of all IOs. + */ +static void +bfa_itnim_cleanup(struct bfa_itnim_s *itnim) +{ + struct bfa_ioim_s *ioim; + struct bfa_tskim_s *tskim; + struct list_head *qe, *qen; + + bfa_wc_init(&itnim->wc, bfa_itnim_cleanp_comp, itnim); + + list_for_each_safe(qe, qen, &itnim->io_q) { + ioim = (struct bfa_ioim_s *) qe; + + /** + * Move IO to a cleanup queue from active queue so that a later + * TM will not pickup this IO. + */ + list_del(&ioim->qe); + list_add_tail(&ioim->qe, &itnim->io_cleanup_q); + + bfa_wc_up(&itnim->wc); + bfa_ioim_cleanup(ioim); + } + + list_for_each_safe(qe, qen, &itnim->tsk_q) { + tskim = (struct bfa_tskim_s *) qe; + bfa_wc_up(&itnim->wc); + bfa_tskim_cleanup(tskim); + } + + bfa_wc_wait(&itnim->wc); +} + +static void +__bfa_cb_itnim_online(void *cbarg, bfa_boolean_t complete) +{ + struct bfa_itnim_s *itnim = cbarg; + + if (complete) + bfa_cb_itnim_online(itnim->ditn); +} + +static void +__bfa_cb_itnim_offline(void *cbarg, bfa_boolean_t complete) +{ + struct bfa_itnim_s *itnim = cbarg; + + if (complete) + bfa_cb_itnim_offline(itnim->ditn); +} + +static void +__bfa_cb_itnim_sler(void *cbarg, bfa_boolean_t complete) +{ + struct bfa_itnim_s *itnim = cbarg; + + if (complete) + bfa_cb_itnim_sler(itnim->ditn); +} + +/** + * Call to resume any I/O requests waiting for room in request queue. + */ +static void +bfa_itnim_qresume(void *cbarg) +{ + struct bfa_itnim_s *itnim = cbarg; + + bfa_sm_send_event(itnim, BFA_ITNIM_SM_QRESUME); +} + + + + +/** + * bfa_itnim_public + */ + +void +bfa_itnim_iodone(struct bfa_itnim_s *itnim) +{ + bfa_wc_down(&itnim->wc); +} + +void +bfa_itnim_tskdone(struct bfa_itnim_s *itnim) +{ + bfa_wc_down(&itnim->wc); +} + +void +bfa_itnim_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len, + u32 *dm_len) +{ + /** + * ITN memory + */ + *km_len += cfg->fwcfg.num_rports * sizeof(struct bfa_itnim_s); +} + +void +bfa_itnim_attach(struct bfa_fcpim_mod_s *fcpim, struct bfa_meminfo_s *minfo) +{ + struct bfa_s *bfa = fcpim->bfa; + struct bfa_itnim_s *itnim; + int i, j; + + INIT_LIST_HEAD(&fcpim->itnim_q); + + itnim = (struct bfa_itnim_s *) bfa_meminfo_kva(minfo); + fcpim->itnim_arr = itnim; + + for (i = 0; i < fcpim->num_itnims; i++, itnim++) { + bfa_os_memset(itnim, 0, sizeof(struct bfa_itnim_s)); + itnim->bfa = bfa; + itnim->fcpim = fcpim; + itnim->reqq = BFA_REQQ_QOS_LO; + itnim->rport = BFA_RPORT_FROM_TAG(bfa, i); + itnim->iotov_active = BFA_FALSE; + bfa_reqq_winit(&itnim->reqq_wait, bfa_itnim_qresume, itnim); + + INIT_LIST_HEAD(&itnim->io_q); + INIT_LIST_HEAD(&itnim->io_cleanup_q); + INIT_LIST_HEAD(&itnim->pending_q); + INIT_LIST_HEAD(&itnim->tsk_q); + INIT_LIST_HEAD(&itnim->delay_comp_q); + for (j = 0; j < BFA_IOBUCKET_MAX; j++) + itnim->ioprofile.io_latency.min[j] = ~0; + bfa_sm_set_state(itnim, bfa_itnim_sm_uninit); + } + + bfa_meminfo_kva(minfo) = (u8 *) itnim; +} + +void +bfa_itnim_iocdisable(struct bfa_itnim_s *itnim) +{ + bfa_stats(itnim, ioc_disabled); + bfa_sm_send_event(itnim, BFA_ITNIM_SM_HWFAIL); +} + +static bfa_boolean_t +bfa_itnim_send_fwcreate(struct bfa_itnim_s *itnim) +{ + struct bfi_itnim_create_req_s *m; + + itnim->msg_no++; + + /** + * check for room in queue to send request now + */ + m = bfa_reqq_next(itnim->bfa, itnim->reqq); + if (!m) { + bfa_reqq_wait(itnim->bfa, itnim->reqq, &itnim->reqq_wait); + return BFA_FALSE; + } + + bfi_h2i_set(m->mh, BFI_MC_ITNIM, BFI_ITNIM_H2I_CREATE_REQ, + bfa_lpuid(itnim->bfa)); + m->fw_handle = itnim->rport->fw_handle; + m->class = FC_CLASS_3; + m->seq_rec = itnim->seq_rec; + m->msg_no = itnim->msg_no; + bfa_stats(itnim, fw_create); + + /** + * queue I/O message to firmware + */ + bfa_reqq_produce(itnim->bfa, itnim->reqq); + return BFA_TRUE; +} + +static bfa_boolean_t +bfa_itnim_send_fwdelete(struct bfa_itnim_s *itnim) +{ + struct bfi_itnim_delete_req_s *m; + + /** + * check for room in queue to send request now + */ + m = bfa_reqq_next(itnim->bfa, itnim->reqq); + if (!m) { + bfa_reqq_wait(itnim->bfa, itnim->reqq, &itnim->reqq_wait); + return BFA_FALSE; + } + + bfi_h2i_set(m->mh, BFI_MC_ITNIM, BFI_ITNIM_H2I_DELETE_REQ, + bfa_lpuid(itnim->bfa)); + m->fw_handle = itnim->rport->fw_handle; + bfa_stats(itnim, fw_delete); + + /** + * queue I/O message to firmware + */ + bfa_reqq_produce(itnim->bfa, itnim->reqq); + return BFA_TRUE; +} + +/** + * Cleanup all pending failed inflight requests. + */ +static void +bfa_itnim_delayed_comp(struct bfa_itnim_s *itnim, bfa_boolean_t iotov) +{ + struct bfa_ioim_s *ioim; + struct list_head *qe, *qen; + + list_for_each_safe(qe, qen, &itnim->delay_comp_q) { + ioim = (struct bfa_ioim_s *)qe; + bfa_ioim_delayed_comp(ioim, iotov); + } +} + +/** + * Start all pending IO requests. + */ +static void +bfa_itnim_iotov_online(struct bfa_itnim_s *itnim) +{ + struct bfa_ioim_s *ioim; + + bfa_itnim_iotov_stop(itnim); + + /** + * Abort all inflight IO requests in the queue + */ + bfa_itnim_delayed_comp(itnim, BFA_FALSE); + + /** + * Start all pending IO requests. + */ + while (!list_empty(&itnim->pending_q)) { + bfa_q_deq(&itnim->pending_q, &ioim); + list_add_tail(&ioim->qe, &itnim->io_q); + bfa_ioim_start(ioim); + } +} + +/** + * Fail all pending IO requests + */ +static void +bfa_itnim_iotov_cleanup(struct bfa_itnim_s *itnim) +{ + struct bfa_ioim_s *ioim; + + /** + * Fail all inflight IO requests in the queue + */ + bfa_itnim_delayed_comp(itnim, BFA_TRUE); + + /** + * Fail any pending IO requests. + */ + while (!list_empty(&itnim->pending_q)) { + bfa_q_deq(&itnim->pending_q, &ioim); + list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q); + bfa_ioim_tov(ioim); + } +} + +/** + * IO TOV timer callback. Fail any pending IO requests. + */ +static void +bfa_itnim_iotov(void *itnim_arg) +{ + struct bfa_itnim_s *itnim = itnim_arg; + + itnim->iotov_active = BFA_FALSE; + + bfa_cb_itnim_tov_begin(itnim->ditn); + bfa_itnim_iotov_cleanup(itnim); + bfa_cb_itnim_tov(itnim->ditn); +} + +/** + * Start IO TOV timer for failing back pending IO requests in offline state. + */ +static void +bfa_itnim_iotov_start(struct bfa_itnim_s *itnim) +{ + if (itnim->fcpim->path_tov > 0) { + + itnim->iotov_active = BFA_TRUE; + bfa_assert(bfa_itnim_hold_io(itnim)); + bfa_timer_start(itnim->bfa, &itnim->timer, + bfa_itnim_iotov, itnim, itnim->fcpim->path_tov); + } +} + +/** + * Stop IO TOV timer. + */ +static void +bfa_itnim_iotov_stop(struct bfa_itnim_s *itnim) +{ + if (itnim->iotov_active) { + itnim->iotov_active = BFA_FALSE; + bfa_timer_stop(&itnim->timer); + } +} + +/** + * Stop IO TOV timer. + */ +static void +bfa_itnim_iotov_delete(struct bfa_itnim_s *itnim) +{ + bfa_boolean_t pathtov_active = BFA_FALSE; + + if (itnim->iotov_active) + pathtov_active = BFA_TRUE; + + bfa_itnim_iotov_stop(itnim); + if (pathtov_active) + bfa_cb_itnim_tov_begin(itnim->ditn); + bfa_itnim_iotov_cleanup(itnim); + if (pathtov_active) + bfa_cb_itnim_tov(itnim->ditn); +} + +static void +bfa_itnim_update_del_itn_stats(struct bfa_itnim_s *itnim) +{ + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(itnim->bfa); + fcpim->del_itn_stats.del_itn_iocomp_aborted += + itnim->stats.iocomp_aborted; + fcpim->del_itn_stats.del_itn_iocomp_timedout += + itnim->stats.iocomp_timedout; + fcpim->del_itn_stats.del_itn_iocom_sqer_needed += + itnim->stats.iocom_sqer_needed; + fcpim->del_itn_stats.del_itn_iocom_res_free += + itnim->stats.iocom_res_free; + fcpim->del_itn_stats.del_itn_iocom_hostabrts += + itnim->stats.iocom_hostabrts; + fcpim->del_itn_stats.del_itn_total_ios += itnim->stats.total_ios; + fcpim->del_itn_stats.del_io_iocdowns += itnim->stats.io_iocdowns; + fcpim->del_itn_stats.del_tm_iocdowns += itnim->stats.tm_iocdowns; +} + + + +/** + * bfa_itnim_public + */ + +/** + * Itnim interrupt processing. + */ +void +bfa_itnim_isr(struct bfa_s *bfa, struct bfi_msg_s *m) +{ + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); + union bfi_itnim_i2h_msg_u msg; + struct bfa_itnim_s *itnim; + + bfa_trc(bfa, m->mhdr.msg_id); + + msg.msg = m; + + switch (m->mhdr.msg_id) { + case BFI_ITNIM_I2H_CREATE_RSP: + itnim = BFA_ITNIM_FROM_TAG(fcpim, + msg.create_rsp->bfa_handle); + bfa_assert(msg.create_rsp->status == BFA_STATUS_OK); + bfa_stats(itnim, create_comps); + bfa_sm_send_event(itnim, BFA_ITNIM_SM_FWRSP); + break; + + case BFI_ITNIM_I2H_DELETE_RSP: + itnim = BFA_ITNIM_FROM_TAG(fcpim, + msg.delete_rsp->bfa_handle); + bfa_assert(msg.delete_rsp->status == BFA_STATUS_OK); + bfa_stats(itnim, delete_comps); + bfa_sm_send_event(itnim, BFA_ITNIM_SM_FWRSP); + break; + + case BFI_ITNIM_I2H_SLER_EVENT: + itnim = BFA_ITNIM_FROM_TAG(fcpim, + msg.sler_event->bfa_handle); + bfa_stats(itnim, sler_events); + bfa_sm_send_event(itnim, BFA_ITNIM_SM_SLER); + break; + + default: + bfa_trc(bfa, m->mhdr.msg_id); + bfa_assert(0); + } +} + + + +/** + * bfa_itnim_api + */ + +struct bfa_itnim_s * +bfa_itnim_create(struct bfa_s *bfa, struct bfa_rport_s *rport, void *ditn) +{ + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); + struct bfa_itnim_s *itnim; + + itnim = BFA_ITNIM_FROM_TAG(fcpim, rport->rport_tag); + bfa_assert(itnim->rport == rport); + + itnim->ditn = ditn; + + bfa_stats(itnim, creates); + bfa_sm_send_event(itnim, BFA_ITNIM_SM_CREATE); + + return itnim; +} + +void +bfa_itnim_delete(struct bfa_itnim_s *itnim) +{ + bfa_stats(itnim, deletes); + bfa_sm_send_event(itnim, BFA_ITNIM_SM_DELETE); +} + +void +bfa_itnim_online(struct bfa_itnim_s *itnim, bfa_boolean_t seq_rec) +{ + itnim->seq_rec = seq_rec; + bfa_stats(itnim, onlines); + bfa_sm_send_event(itnim, BFA_ITNIM_SM_ONLINE); +} + +void +bfa_itnim_offline(struct bfa_itnim_s *itnim) +{ + bfa_stats(itnim, offlines); + bfa_sm_send_event(itnim, BFA_ITNIM_SM_OFFLINE); +} + +/** + * Return true if itnim is considered offline for holding off IO request. + * IO is not held if itnim is being deleted. + */ +bfa_boolean_t +bfa_itnim_hold_io(struct bfa_itnim_s *itnim) +{ + return itnim->fcpim->path_tov && itnim->iotov_active && + (bfa_sm_cmp_state(itnim, bfa_itnim_sm_fwcreate) || + bfa_sm_cmp_state(itnim, bfa_itnim_sm_sler) || + bfa_sm_cmp_state(itnim, bfa_itnim_sm_cleanup_offline) || + bfa_sm_cmp_state(itnim, bfa_itnim_sm_fwdelete) || + bfa_sm_cmp_state(itnim, bfa_itnim_sm_offline) || + bfa_sm_cmp_state(itnim, bfa_itnim_sm_iocdisable)); +} + +bfa_status_t +bfa_itnim_get_ioprofile(struct bfa_itnim_s *itnim, + struct bfa_itnim_ioprofile_s *ioprofile) +{ + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(itnim->bfa); + if (!fcpim->io_profile) + return BFA_STATUS_IOPROFILE_OFF; + + itnim->ioprofile.index = BFA_IOBUCKET_MAX; + itnim->ioprofile.io_profile_start_time = + bfa_io_profile_start_time(itnim->bfa); + itnim->ioprofile.clock_res_mul = bfa_io_lat_clock_res_mul; + itnim->ioprofile.clock_res_div = bfa_io_lat_clock_res_div; + *ioprofile = itnim->ioprofile; + + return BFA_STATUS_OK; +} + +void +bfa_itnim_get_stats(struct bfa_itnim_s *itnim, + struct bfa_itnim_iostats_s *stats) +{ + *stats = itnim->stats; +} + +void +bfa_itnim_clear_stats(struct bfa_itnim_s *itnim) +{ + int j; + bfa_os_memset(&itnim->stats, 0, sizeof(itnim->stats)); + bfa_os_memset(&itnim->ioprofile, 0, sizeof(itnim->ioprofile)); + for (j = 0; j < BFA_IOBUCKET_MAX; j++) + itnim->ioprofile.io_latency.min[j] = ~0; +} + +/** + * BFA IO module state machine functions + */ + +/** + * IO is not started (unallocated). + */ +static void +bfa_ioim_sm_uninit(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) +{ + bfa_trc_fp(ioim->bfa, ioim->iotag); + bfa_trc_fp(ioim->bfa, event); + + switch (event) { + case BFA_IOIM_SM_START: + if (!bfa_itnim_is_online(ioim->itnim)) { + if (!bfa_itnim_hold_io(ioim->itnim)) { + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); + list_del(&ioim->qe); + list_add_tail(&ioim->qe, + &ioim->fcpim->ioim_comp_q); + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, + __bfa_cb_ioim_pathtov, ioim); + } else { + list_del(&ioim->qe); + list_add_tail(&ioim->qe, + &ioim->itnim->pending_q); + } + break; + } + + if (ioim->nsges > BFI_SGE_INLINE) { + if (!bfa_ioim_sge_setup(ioim)) { + bfa_sm_set_state(ioim, bfa_ioim_sm_sgalloc); + return; + } + } + + if (!bfa_ioim_send_ioreq(ioim)) { + bfa_sm_set_state(ioim, bfa_ioim_sm_qfull); + break; + } + + bfa_sm_set_state(ioim, bfa_ioim_sm_active); + break; + + case BFA_IOIM_SM_IOTOV: + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); + bfa_ioim_move_to_comp_q(ioim); + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, + __bfa_cb_ioim_pathtov, ioim); + break; + + case BFA_IOIM_SM_ABORT: + /** + * IO in pending queue can get abort requests. Complete abort + * requests immediately. + */ + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); + bfa_assert(bfa_q_is_on_q(&ioim->itnim->pending_q, ioim)); + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, + __bfa_cb_ioim_abort, ioim); + break; + + default: + bfa_sm_fault(ioim->bfa, event); + } +} + +/** + * IO is waiting for SG pages. + */ +static void +bfa_ioim_sm_sgalloc(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) +{ + bfa_trc(ioim->bfa, ioim->iotag); + bfa_trc(ioim->bfa, event); + + switch (event) { + case BFA_IOIM_SM_SGALLOCED: + if (!bfa_ioim_send_ioreq(ioim)) { + bfa_sm_set_state(ioim, bfa_ioim_sm_qfull); + break; + } + bfa_sm_set_state(ioim, bfa_ioim_sm_active); + break; + + case BFA_IOIM_SM_CLEANUP: + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); + bfa_sgpg_wcancel(ioim->bfa, &ioim->iosp->sgpg_wqe); + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed, + ioim); + bfa_ioim_notify_cleanup(ioim); + break; + + case BFA_IOIM_SM_ABORT: + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); + bfa_sgpg_wcancel(ioim->bfa, &ioim->iosp->sgpg_wqe); + bfa_ioim_move_to_comp_q(ioim); + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort, + ioim); + break; + + case BFA_IOIM_SM_HWFAIL: + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); + bfa_sgpg_wcancel(ioim->bfa, &ioim->iosp->sgpg_wqe); + bfa_ioim_move_to_comp_q(ioim); + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed, + ioim); + break; + + default: + bfa_sm_fault(ioim->bfa, event); + } +} + +/** + * IO is active. + */ +static void +bfa_ioim_sm_active(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) +{ + bfa_trc_fp(ioim->bfa, ioim->iotag); + bfa_trc_fp(ioim->bfa, event); + + switch (event) { + case BFA_IOIM_SM_COMP_GOOD: + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); + bfa_ioim_move_to_comp_q(ioim); + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, + __bfa_cb_ioim_good_comp, ioim); + break; + + case BFA_IOIM_SM_COMP: + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); + bfa_ioim_move_to_comp_q(ioim); + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_comp, + ioim); + break; + + case BFA_IOIM_SM_DONE: + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb_free); + bfa_ioim_move_to_comp_q(ioim); + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_comp, + ioim); + break; + + case BFA_IOIM_SM_ABORT: + ioim->iosp->abort_explicit = BFA_TRUE; + ioim->io_cbfn = __bfa_cb_ioim_abort; + + if (bfa_ioim_send_abort(ioim)) + bfa_sm_set_state(ioim, bfa_ioim_sm_abort); + else { + bfa_sm_set_state(ioim, bfa_ioim_sm_abort_qfull); + bfa_stats(ioim->itnim, qwait); + bfa_reqq_wait(ioim->bfa, ioim->reqq, + &ioim->iosp->reqq_wait); + } + break; + + case BFA_IOIM_SM_CLEANUP: + ioim->iosp->abort_explicit = BFA_FALSE; + ioim->io_cbfn = __bfa_cb_ioim_failed; + + if (bfa_ioim_send_abort(ioim)) + bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup); + else { + bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup_qfull); + bfa_stats(ioim->itnim, qwait); + bfa_reqq_wait(ioim->bfa, ioim->reqq, + &ioim->iosp->reqq_wait); + } + break; + + case BFA_IOIM_SM_HWFAIL: + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); + bfa_ioim_move_to_comp_q(ioim); + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed, + ioim); + break; + + case BFA_IOIM_SM_SQRETRY: + if (bfa_ioim_get_iotag(ioim) != BFA_TRUE) { + /* max retry completed free IO */ + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb_free); + bfa_ioim_move_to_comp_q(ioim); + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, + __bfa_cb_ioim_failed, ioim); + break; + } + /* waiting for IO tag resource free */ + bfa_sm_set_state(ioim, bfa_ioim_sm_cmnd_retry); + break; + + default: + bfa_sm_fault(ioim->bfa, event); + } +} + +/** +* IO is retried with new tag. +*/ +static void +bfa_ioim_sm_cmnd_retry(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) +{ + bfa_trc_fp(ioim->bfa, ioim->iotag); + bfa_trc_fp(ioim->bfa, event); + + switch (event) { + case BFA_IOIM_SM_FREE: + /* abts and rrq done. Now retry the IO with new tag */ + if (!bfa_ioim_send_ioreq(ioim)) { + bfa_sm_set_state(ioim, bfa_ioim_sm_qfull); + break; + } + bfa_sm_set_state(ioim, bfa_ioim_sm_active); + break; + + case BFA_IOIM_SM_CLEANUP: + ioim->iosp->abort_explicit = BFA_FALSE; + ioim->io_cbfn = __bfa_cb_ioim_failed; + + if (bfa_ioim_send_abort(ioim)) + bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup); + else { + bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup_qfull); + bfa_stats(ioim->itnim, qwait); + bfa_reqq_wait(ioim->bfa, ioim->reqq, + &ioim->iosp->reqq_wait); + } + break; + + case BFA_IOIM_SM_HWFAIL: + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); + bfa_ioim_move_to_comp_q(ioim); + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, + __bfa_cb_ioim_failed, ioim); + break; + + case BFA_IOIM_SM_ABORT: + /** in this state IO abort is done. + * Waiting for IO tag resource free. + */ + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb_free); + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort, + ioim); + break; + + default: + bfa_sm_fault(ioim->bfa, event); + } +} + +/** + * IO is being aborted, waiting for completion from firmware. + */ +static void +bfa_ioim_sm_abort(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) +{ + bfa_trc(ioim->bfa, ioim->iotag); + bfa_trc(ioim->bfa, event); + + switch (event) { + case BFA_IOIM_SM_COMP_GOOD: + case BFA_IOIM_SM_COMP: + case BFA_IOIM_SM_DONE: + case BFA_IOIM_SM_FREE: + break; + + case BFA_IOIM_SM_ABORT_DONE: + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb_free); + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort, + ioim); + break; + + case BFA_IOIM_SM_ABORT_COMP: + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); + bfa_ioim_move_to_comp_q(ioim); + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort, + ioim); + break; + + case BFA_IOIM_SM_COMP_UTAG: + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); + bfa_ioim_move_to_comp_q(ioim); + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort, + ioim); + break; + + case BFA_IOIM_SM_CLEANUP: + bfa_assert(ioim->iosp->abort_explicit == BFA_TRUE); + ioim->iosp->abort_explicit = BFA_FALSE; + + if (bfa_ioim_send_abort(ioim)) + bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup); + else { + bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup_qfull); + bfa_stats(ioim->itnim, qwait); + bfa_reqq_wait(ioim->bfa, ioim->reqq, + &ioim->iosp->reqq_wait); + } + break; + + case BFA_IOIM_SM_HWFAIL: + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); + bfa_ioim_move_to_comp_q(ioim); + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed, + ioim); + break; + + default: + bfa_sm_fault(ioim->bfa, event); + } +} + +/** + * IO is being cleaned up (implicit abort), waiting for completion from + * firmware. + */ +static void +bfa_ioim_sm_cleanup(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) +{ + bfa_trc(ioim->bfa, ioim->iotag); + bfa_trc(ioim->bfa, event); + + switch (event) { + case BFA_IOIM_SM_COMP_GOOD: + case BFA_IOIM_SM_COMP: + case BFA_IOIM_SM_DONE: + case BFA_IOIM_SM_FREE: + break; + + case BFA_IOIM_SM_ABORT: + /** + * IO is already being aborted implicitly + */ + ioim->io_cbfn = __bfa_cb_ioim_abort; + break; + + case BFA_IOIM_SM_ABORT_DONE: + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb_free); + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, ioim->io_cbfn, ioim); + bfa_ioim_notify_cleanup(ioim); + break; + + case BFA_IOIM_SM_ABORT_COMP: + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, ioim->io_cbfn, ioim); + bfa_ioim_notify_cleanup(ioim); + break; + + case BFA_IOIM_SM_COMP_UTAG: + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, ioim->io_cbfn, ioim); + bfa_ioim_notify_cleanup(ioim); + break; + + case BFA_IOIM_SM_HWFAIL: + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); + bfa_ioim_move_to_comp_q(ioim); + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed, + ioim); + break; + + case BFA_IOIM_SM_CLEANUP: + /** + * IO can be in cleanup state already due to TM command. + * 2nd cleanup request comes from ITN offline event. + */ + break; + + default: + bfa_sm_fault(ioim->bfa, event); + } +} + +/** + * IO is waiting for room in request CQ + */ +static void +bfa_ioim_sm_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) +{ + bfa_trc(ioim->bfa, ioim->iotag); + bfa_trc(ioim->bfa, event); + + switch (event) { + case BFA_IOIM_SM_QRESUME: + bfa_sm_set_state(ioim, bfa_ioim_sm_active); + bfa_ioim_send_ioreq(ioim); + break; + + case BFA_IOIM_SM_ABORT: + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); + bfa_reqq_wcancel(&ioim->iosp->reqq_wait); + bfa_ioim_move_to_comp_q(ioim); + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort, + ioim); + break; + + case BFA_IOIM_SM_CLEANUP: + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); + bfa_reqq_wcancel(&ioim->iosp->reqq_wait); + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed, + ioim); + bfa_ioim_notify_cleanup(ioim); + break; + + case BFA_IOIM_SM_HWFAIL: + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); + bfa_reqq_wcancel(&ioim->iosp->reqq_wait); + bfa_ioim_move_to_comp_q(ioim); + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed, + ioim); + break; + + default: + bfa_sm_fault(ioim->bfa, event); + } +} + +/** + * Active IO is being aborted, waiting for room in request CQ. + */ +static void +bfa_ioim_sm_abort_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) +{ + bfa_trc(ioim->bfa, ioim->iotag); + bfa_trc(ioim->bfa, event); + + switch (event) { + case BFA_IOIM_SM_QRESUME: + bfa_sm_set_state(ioim, bfa_ioim_sm_abort); + bfa_ioim_send_abort(ioim); + break; + + case BFA_IOIM_SM_CLEANUP: + bfa_assert(ioim->iosp->abort_explicit == BFA_TRUE); + ioim->iosp->abort_explicit = BFA_FALSE; + bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup_qfull); + break; + + case BFA_IOIM_SM_COMP_GOOD: + case BFA_IOIM_SM_COMP: + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); + bfa_reqq_wcancel(&ioim->iosp->reqq_wait); + bfa_ioim_move_to_comp_q(ioim); + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort, + ioim); + break; + + case BFA_IOIM_SM_DONE: + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb_free); + bfa_reqq_wcancel(&ioim->iosp->reqq_wait); + bfa_ioim_move_to_comp_q(ioim); + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort, + ioim); + break; + + case BFA_IOIM_SM_HWFAIL: + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); + bfa_reqq_wcancel(&ioim->iosp->reqq_wait); + bfa_ioim_move_to_comp_q(ioim); + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed, + ioim); + break; + + default: + bfa_sm_fault(ioim->bfa, event); + } +} + +/** + * Active IO is being cleaned up, waiting for room in request CQ. + */ +static void +bfa_ioim_sm_cleanup_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) +{ + bfa_trc(ioim->bfa, ioim->iotag); + bfa_trc(ioim->bfa, event); + + switch (event) { + case BFA_IOIM_SM_QRESUME: + bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup); + bfa_ioim_send_abort(ioim); + break; + + case BFA_IOIM_SM_ABORT: + /** + * IO is alraedy being cleaned up implicitly + */ + ioim->io_cbfn = __bfa_cb_ioim_abort; + break; + + case BFA_IOIM_SM_COMP_GOOD: + case BFA_IOIM_SM_COMP: + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); + bfa_reqq_wcancel(&ioim->iosp->reqq_wait); + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, ioim->io_cbfn, ioim); + bfa_ioim_notify_cleanup(ioim); + break; + + case BFA_IOIM_SM_DONE: + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb_free); + bfa_reqq_wcancel(&ioim->iosp->reqq_wait); + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, ioim->io_cbfn, ioim); + bfa_ioim_notify_cleanup(ioim); + break; + + case BFA_IOIM_SM_HWFAIL: + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); + bfa_reqq_wcancel(&ioim->iosp->reqq_wait); + bfa_ioim_move_to_comp_q(ioim); + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed, + ioim); + break; + + default: + bfa_sm_fault(ioim->bfa, event); + } +} + +/** + * IO bfa callback is pending. + */ +static void +bfa_ioim_sm_hcb(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) +{ + bfa_trc_fp(ioim->bfa, ioim->iotag); + bfa_trc_fp(ioim->bfa, event); + + switch (event) { + case BFA_IOIM_SM_HCB: + bfa_sm_set_state(ioim, bfa_ioim_sm_uninit); + bfa_ioim_free(ioim); + break; + + case BFA_IOIM_SM_CLEANUP: + bfa_ioim_notify_cleanup(ioim); + break; + + case BFA_IOIM_SM_HWFAIL: + break; + + default: + bfa_sm_fault(ioim->bfa, event); + } +} + +/** + * IO bfa callback is pending. IO resource cannot be freed. + */ +static void +bfa_ioim_sm_hcb_free(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) +{ + bfa_trc(ioim->bfa, ioim->iotag); + bfa_trc(ioim->bfa, event); + + switch (event) { + case BFA_IOIM_SM_HCB: + bfa_sm_set_state(ioim, bfa_ioim_sm_resfree); + list_del(&ioim->qe); + list_add_tail(&ioim->qe, &ioim->fcpim->ioim_resfree_q); + break; + + case BFA_IOIM_SM_FREE: + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); + break; + + case BFA_IOIM_SM_CLEANUP: + bfa_ioim_notify_cleanup(ioim); + break; + + case BFA_IOIM_SM_HWFAIL: + bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); + break; + + default: + bfa_sm_fault(ioim->bfa, event); + } +} + +/** + * IO is completed, waiting resource free from firmware. + */ +static void +bfa_ioim_sm_resfree(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) +{ + bfa_trc(ioim->bfa, ioim->iotag); + bfa_trc(ioim->bfa, event); + + switch (event) { + case BFA_IOIM_SM_FREE: + bfa_sm_set_state(ioim, bfa_ioim_sm_uninit); + bfa_ioim_free(ioim); + break; + + case BFA_IOIM_SM_CLEANUP: + bfa_ioim_notify_cleanup(ioim); + break; + + case BFA_IOIM_SM_HWFAIL: + break; + + default: + bfa_sm_fault(ioim->bfa, event); + } +} + + + +/** + * hal_ioim_private + */ + +static void +__bfa_cb_ioim_good_comp(void *cbarg, bfa_boolean_t complete) +{ + struct bfa_ioim_s *ioim = cbarg; + + if (!complete) { + bfa_sm_send_event(ioim, BFA_IOIM_SM_HCB); + return; + } + + bfa_cb_ioim_good_comp(ioim->bfa->bfad, ioim->dio); +} + +static void +__bfa_cb_ioim_comp(void *cbarg, bfa_boolean_t complete) +{ + struct bfa_ioim_s *ioim = cbarg; + struct bfi_ioim_rsp_s *m; + u8 *snsinfo = NULL; + u8 sns_len = 0; + s32 residue = 0; + + if (!complete) { + bfa_sm_send_event(ioim, BFA_IOIM_SM_HCB); + return; + } + + m = (struct bfi_ioim_rsp_s *) &ioim->iosp->comp_rspmsg; + if (m->io_status == BFI_IOIM_STS_OK) { + /** + * setup sense information, if present + */ + if ((m->scsi_status == SCSI_STATUS_CHECK_CONDITION) && + m->sns_len) { + sns_len = m->sns_len; + snsinfo = ioim->iosp->snsinfo; + } + + /** + * setup residue value correctly for normal completions + */ + if (m->resid_flags == FCP_RESID_UNDER) { + residue = bfa_os_ntohl(m->residue); + bfa_stats(ioim->itnim, iocomp_underrun); + } + if (m->resid_flags == FCP_RESID_OVER) { + residue = bfa_os_ntohl(m->residue); + residue = -residue; + bfa_stats(ioim->itnim, iocomp_overrun); + } + } + + bfa_cb_ioim_done(ioim->bfa->bfad, ioim->dio, m->io_status, + m->scsi_status, sns_len, snsinfo, residue); +} + +static void +__bfa_cb_ioim_failed(void *cbarg, bfa_boolean_t complete) +{ + struct bfa_ioim_s *ioim = cbarg; + + if (!complete) { + bfa_sm_send_event(ioim, BFA_IOIM_SM_HCB); + return; + } + + bfa_cb_ioim_done(ioim->bfa->bfad, ioim->dio, BFI_IOIM_STS_ABORTED, + 0, 0, NULL, 0); +} + +static void +__bfa_cb_ioim_pathtov(void *cbarg, bfa_boolean_t complete) +{ + struct bfa_ioim_s *ioim = cbarg; + + bfa_stats(ioim->itnim, path_tov_expired); + if (!complete) { + bfa_sm_send_event(ioim, BFA_IOIM_SM_HCB); + return; + } + + bfa_cb_ioim_done(ioim->bfa->bfad, ioim->dio, BFI_IOIM_STS_PATHTOV, + 0, 0, NULL, 0); +} + +static void +__bfa_cb_ioim_abort(void *cbarg, bfa_boolean_t complete) +{ + struct bfa_ioim_s *ioim = cbarg; + + if (!complete) { + bfa_sm_send_event(ioim, BFA_IOIM_SM_HCB); + return; + } + + bfa_cb_ioim_abort(ioim->bfa->bfad, ioim->dio); +} + +static void +bfa_ioim_sgpg_alloced(void *cbarg) +{ + struct bfa_ioim_s *ioim = cbarg; + + ioim->nsgpgs = BFA_SGPG_NPAGE(ioim->nsges); + list_splice_tail_init(&ioim->iosp->sgpg_wqe.sgpg_q, &ioim->sgpg_q); + bfa_ioim_sgpg_setup(ioim); + bfa_sm_send_event(ioim, BFA_IOIM_SM_SGALLOCED); +} + +/** + * Send I/O request to firmware. + */ +static bfa_boolean_t +bfa_ioim_send_ioreq(struct bfa_ioim_s *ioim) +{ + struct bfa_itnim_s *itnim = ioim->itnim; + struct bfi_ioim_req_s *m; + static struct fcp_cmnd_s cmnd_z0 = { 0 }; + struct bfi_sge_s *sge; + u32 pgdlen = 0; + u32 fcp_dl; + u64 addr; + struct scatterlist *sg; + struct scsi_cmnd *cmnd = (struct scsi_cmnd *) ioim->dio; + + /** + * check for room in queue to send request now + */ + m = bfa_reqq_next(ioim->bfa, ioim->reqq); + if (!m) { + bfa_stats(ioim->itnim, qwait); + bfa_reqq_wait(ioim->bfa, ioim->reqq, + &ioim->iosp->reqq_wait); + return BFA_FALSE; + } + + /** + * build i/o request message next + */ + m->io_tag = bfa_os_htons(ioim->iotag); + m->rport_hdl = ioim->itnim->rport->fw_handle; + m->io_timeout = bfa_cb_ioim_get_timeout(ioim->dio); + + /** + * build inline IO SG element here + */ + sge = &m->sges[0]; + if (ioim->nsges) { + sg = (struct scatterlist *)scsi_sglist(cmnd); + addr = bfa_os_sgaddr(sg_dma_address(sg)); + sge->sga = *(union bfi_addr_u *) &addr; + pgdlen = sg_dma_len(sg); + sge->sg_len = pgdlen; + sge->flags = (ioim->nsges > BFI_SGE_INLINE) ? + BFI_SGE_DATA_CPL : BFI_SGE_DATA_LAST; + bfa_sge_to_be(sge); + sge++; + } + + if (ioim->nsges > BFI_SGE_INLINE) { + sge->sga = ioim->sgpg->sgpg_pa; + } else { + sge->sga.a32.addr_lo = 0; + sge->sga.a32.addr_hi = 0; + } + sge->sg_len = pgdlen; + sge->flags = BFI_SGE_PGDLEN; + bfa_sge_to_be(sge); + + /** + * set up I/O command parameters + */ + bfa_os_assign(m->cmnd, cmnd_z0); + m->cmnd.lun = bfa_cb_ioim_get_lun(ioim->dio); + m->cmnd.iodir = bfa_cb_ioim_get_iodir(ioim->dio); + bfa_os_assign(m->cmnd.cdb, + *(scsi_cdb_t *)bfa_cb_ioim_get_cdb(ioim->dio)); + fcp_dl = bfa_cb_ioim_get_size(ioim->dio); + m->cmnd.fcp_dl = bfa_os_htonl(fcp_dl); + + /** + * set up I/O message header + */ + switch (m->cmnd.iodir) { + case FCP_IODIR_READ: + bfi_h2i_set(m->mh, BFI_MC_IOIM_READ, 0, bfa_lpuid(ioim->bfa)); + bfa_stats(itnim, input_reqs); + ioim->itnim->stats.rd_throughput += fcp_dl; + break; + case FCP_IODIR_WRITE: + bfi_h2i_set(m->mh, BFI_MC_IOIM_WRITE, 0, bfa_lpuid(ioim->bfa)); + bfa_stats(itnim, output_reqs); + ioim->itnim->stats.wr_throughput += fcp_dl; + break; + case FCP_IODIR_RW: + bfa_stats(itnim, input_reqs); + bfa_stats(itnim, output_reqs); + default: + bfi_h2i_set(m->mh, BFI_MC_IOIM_IO, 0, bfa_lpuid(ioim->bfa)); + } + if (itnim->seq_rec || + (bfa_cb_ioim_get_size(ioim->dio) & (sizeof(u32) - 1))) + bfi_h2i_set(m->mh, BFI_MC_IOIM_IO, 0, bfa_lpuid(ioim->bfa)); + +#ifdef IOIM_ADVANCED + m->cmnd.crn = bfa_cb_ioim_get_crn(ioim->dio); + m->cmnd.priority = bfa_cb_ioim_get_priority(ioim->dio); + m->cmnd.taskattr = bfa_cb_ioim_get_taskattr(ioim->dio); + + /** + * Handle large CDB (>16 bytes). + */ + m->cmnd.addl_cdb_len = (bfa_cb_ioim_get_cdblen(ioim->dio) - + FCP_CMND_CDB_LEN) / sizeof(u32); + if (m->cmnd.addl_cdb_len) { + bfa_os_memcpy(&m->cmnd.cdb + 1, (scsi_cdb_t *) + bfa_cb_ioim_get_cdb(ioim->dio) + 1, + m->cmnd.addl_cdb_len * sizeof(u32)); + fcp_cmnd_fcpdl(&m->cmnd) = + bfa_os_htonl(bfa_cb_ioim_get_size(ioim->dio)); + } +#endif + + /** + * queue I/O message to firmware + */ + bfa_reqq_produce(ioim->bfa, ioim->reqq); + return BFA_TRUE; +} + +/** + * Setup any additional SG pages needed.Inline SG element is setup + * at queuing time. + */ +static bfa_boolean_t +bfa_ioim_sge_setup(struct bfa_ioim_s *ioim) +{ + u16 nsgpgs; + + bfa_assert(ioim->nsges > BFI_SGE_INLINE); + + /** + * allocate SG pages needed + */ + nsgpgs = BFA_SGPG_NPAGE(ioim->nsges); + if (!nsgpgs) + return BFA_TRUE; + + if (bfa_sgpg_malloc(ioim->bfa, &ioim->sgpg_q, nsgpgs) + != BFA_STATUS_OK) { + bfa_sgpg_wait(ioim->bfa, &ioim->iosp->sgpg_wqe, nsgpgs); + return BFA_FALSE; + } + + ioim->nsgpgs = nsgpgs; + bfa_ioim_sgpg_setup(ioim); + + return BFA_TRUE; +} + +static void +bfa_ioim_sgpg_setup(struct bfa_ioim_s *ioim) +{ + int sgeid, nsges, i; + struct bfi_sge_s *sge; + struct bfa_sgpg_s *sgpg; + u32 pgcumsz; + u64 addr; + struct scatterlist *sg; + struct scsi_cmnd *cmnd = (struct scsi_cmnd *) ioim->dio; + + sgeid = BFI_SGE_INLINE; + ioim->sgpg = sgpg = bfa_q_first(&ioim->sgpg_q); + + sg = scsi_sglist(cmnd); + sg = sg_next(sg); + + do { + sge = sgpg->sgpg->sges; + nsges = ioim->nsges - sgeid; + if (nsges > BFI_SGPG_DATA_SGES) + nsges = BFI_SGPG_DATA_SGES; + + pgcumsz = 0; + for (i = 0; i < nsges; i++, sge++, sgeid++, sg = sg_next(sg)) { + addr = bfa_os_sgaddr(sg_dma_address(sg)); + sge->sga = *(union bfi_addr_u *) &addr; + sge->sg_len = sg_dma_len(sg); + pgcumsz += sge->sg_len; + + /** + * set flags + */ + if (i < (nsges - 1)) + sge->flags = BFI_SGE_DATA; + else if (sgeid < (ioim->nsges - 1)) + sge->flags = BFI_SGE_DATA_CPL; + else + sge->flags = BFI_SGE_DATA_LAST; + + bfa_sge_to_le(sge); + } + + sgpg = (struct bfa_sgpg_s *) bfa_q_next(sgpg); + + /** + * set the link element of each page + */ + if (sgeid == ioim->nsges) { + sge->flags = BFI_SGE_PGDLEN; + sge->sga.a32.addr_lo = 0; + sge->sga.a32.addr_hi = 0; + } else { + sge->flags = BFI_SGE_LINK; + sge->sga = sgpg->sgpg_pa; + } + sge->sg_len = pgcumsz; + + bfa_sge_to_le(sge); + } while (sgeid < ioim->nsges); +} + +/** + * Send I/O abort request to firmware. + */ +static bfa_boolean_t +bfa_ioim_send_abort(struct bfa_ioim_s *ioim) +{ + struct 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, ioim->reqq); + if (!m) + return BFA_FALSE; + + /** + * build i/o request message next + */ + if (ioim->iosp->abort_explicit) + msgop = BFI_IOIM_H2I_IOABORT_REQ; + else + msgop = BFI_IOIM_H2I_IOCLEANUP_REQ; + + bfi_h2i_set(m->mh, BFI_MC_IOIM, msgop, bfa_lpuid(ioim->bfa)); + m->io_tag = bfa_os_htons(ioim->iotag); + m->abort_tag = ++ioim->abort_tag; + + /** + * queue I/O message to firmware + */ + bfa_reqq_produce(ioim->bfa, ioim->reqq); + return BFA_TRUE; +} + +/** + * Call to resume any I/O requests waiting for room in request queue. + */ +static void +bfa_ioim_qresume(void *cbarg) +{ + struct bfa_ioim_s *ioim = cbarg; + + bfa_stats(ioim->itnim, qresumes); + bfa_sm_send_event(ioim, BFA_IOIM_SM_QRESUME); +} + + +static void +bfa_ioim_notify_cleanup(struct bfa_ioim_s *ioim) +{ + /** + * Move IO from itnim queue to fcpim global queue since itnim will be + * freed. + */ + list_del(&ioim->qe); + list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q); + + if (!ioim->iosp->tskim) { + if (ioim->fcpim->delay_comp && ioim->itnim->iotov_active) { + bfa_cb_dequeue(&ioim->hcb_qe); + list_del(&ioim->qe); + list_add_tail(&ioim->qe, &ioim->itnim->delay_comp_q); + } + bfa_itnim_iodone(ioim->itnim); + } else + bfa_tskim_iodone(ioim->iosp->tskim); +} + +static bfa_boolean_t +bfa_ioim_is_abortable(struct bfa_ioim_s *ioim) +{ + if ((bfa_sm_cmp_state(ioim, bfa_ioim_sm_uninit) && + (!bfa_q_is_on_q(&ioim->itnim->pending_q, ioim))) || + (bfa_sm_cmp_state(ioim, bfa_ioim_sm_abort)) || + (bfa_sm_cmp_state(ioim, bfa_ioim_sm_abort_qfull)) || + (bfa_sm_cmp_state(ioim, bfa_ioim_sm_hcb)) || + (bfa_sm_cmp_state(ioim, bfa_ioim_sm_hcb_free)) || + (bfa_sm_cmp_state(ioim, bfa_ioim_sm_resfree))) + return BFA_FALSE; + + return BFA_TRUE; +} + +/** + * or after the link comes back. + */ +void +bfa_ioim_delayed_comp(struct bfa_ioim_s *ioim, bfa_boolean_t iotov) +{ + /** + * If path tov timer expired, failback with PATHTOV status - these + * IO requests are not normally retried by IO stack. + * + * Otherwise device cameback online and fail it with normal failed + * status so that IO stack retries these failed IO requests. + */ + if (iotov) + ioim->io_cbfn = __bfa_cb_ioim_pathtov; + else { + ioim->io_cbfn = __bfa_cb_ioim_failed; + bfa_stats(ioim->itnim, iocom_nexus_abort); + } + bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, ioim->io_cbfn, ioim); + + /** + * Move IO to fcpim global queue since itnim will be + * freed. + */ + list_del(&ioim->qe); + list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q); +} + + + +/** + * hal_ioim_friend + */ + +/** + * Memory allocation and initialization. + */ +void +bfa_ioim_attach(struct bfa_fcpim_mod_s *fcpim, struct bfa_meminfo_s *minfo) +{ + struct bfa_ioim_s *ioim; + struct bfa_ioim_sp_s *iosp; + u16 i; + u8 *snsinfo; + u32 snsbufsz; + + /** + * claim memory first + */ + ioim = (struct bfa_ioim_s *) bfa_meminfo_kva(minfo); + fcpim->ioim_arr = ioim; + bfa_meminfo_kva(minfo) = (u8 *) (ioim + fcpim->num_ioim_reqs); + + iosp = (struct bfa_ioim_sp_s *) bfa_meminfo_kva(minfo); + fcpim->ioim_sp_arr = iosp; + bfa_meminfo_kva(minfo) = (u8 *) (iosp + fcpim->num_ioim_reqs); + + /** + * Claim DMA memory for per IO sense data. + */ + snsbufsz = fcpim->num_ioim_reqs * BFI_IOIM_SNSLEN; + fcpim->snsbase.pa = bfa_meminfo_dma_phys(minfo); + bfa_meminfo_dma_phys(minfo) += snsbufsz; + + fcpim->snsbase.kva = bfa_meminfo_dma_virt(minfo); + bfa_meminfo_dma_virt(minfo) += snsbufsz; + snsinfo = fcpim->snsbase.kva; + bfa_iocfc_set_snsbase(fcpim->bfa, fcpim->snsbase.pa); + + /** + * Initialize ioim free queues + */ + INIT_LIST_HEAD(&fcpim->ioim_free_q); + INIT_LIST_HEAD(&fcpim->ioim_resfree_q); + INIT_LIST_HEAD(&fcpim->ioim_comp_q); + + for (i = 0; i < fcpim->num_ioim_reqs; + i++, ioim++, iosp++, snsinfo += BFI_IOIM_SNSLEN) { + /* + * initialize IOIM + */ + bfa_os_memset(ioim, 0, sizeof(struct bfa_ioim_s)); + ioim->iotag = i; + ioim->bfa = fcpim->bfa; + ioim->fcpim = fcpim; + ioim->iosp = iosp; + iosp->snsinfo = snsinfo; + INIT_LIST_HEAD(&ioim->sgpg_q); + bfa_reqq_winit(&ioim->iosp->reqq_wait, + bfa_ioim_qresume, ioim); + bfa_sgpg_winit(&ioim->iosp->sgpg_wqe, + bfa_ioim_sgpg_alloced, ioim); + bfa_sm_set_state(ioim, bfa_ioim_sm_uninit); + + list_add_tail(&ioim->qe, &fcpim->ioim_free_q); + } +} + +/** + * Driver detach time call. + */ +void +bfa_ioim_detach(struct bfa_fcpim_mod_s *fcpim) +{ +} + +void +bfa_ioim_isr(struct bfa_s *bfa, struct bfi_msg_s *m) +{ + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); + struct bfi_ioim_rsp_s *rsp = (struct bfi_ioim_rsp_s *) m; + struct bfa_ioim_s *ioim; + u16 iotag; + enum bfa_ioim_event evt = BFA_IOIM_SM_COMP; + + iotag = bfa_os_ntohs(rsp->io_tag); + + ioim = BFA_IOIM_FROM_TAG(fcpim, iotag); + bfa_assert(ioim->iotag == iotag); + + bfa_trc(ioim->bfa, ioim->iotag); + bfa_trc(ioim->bfa, rsp->io_status); + bfa_trc(ioim->bfa, rsp->reuse_io_tag); + + if (bfa_sm_cmp_state(ioim, bfa_ioim_sm_active)) + bfa_os_assign(ioim->iosp->comp_rspmsg, *m); + + switch (rsp->io_status) { + case BFI_IOIM_STS_OK: + bfa_stats(ioim->itnim, iocomp_ok); + if (rsp->reuse_io_tag == 0) + evt = BFA_IOIM_SM_DONE; + else + evt = BFA_IOIM_SM_COMP; + break; + + case BFI_IOIM_STS_TIMEDOUT: + bfa_stats(ioim->itnim, iocomp_timedout); + case BFI_IOIM_STS_ABORTED: + rsp->io_status = BFI_IOIM_STS_ABORTED; + bfa_stats(ioim->itnim, iocomp_aborted); + if (rsp->reuse_io_tag == 0) + evt = BFA_IOIM_SM_DONE; + else + evt = BFA_IOIM_SM_COMP; + break; + + case BFI_IOIM_STS_PROTO_ERR: + bfa_stats(ioim->itnim, iocom_proto_err); + bfa_assert(rsp->reuse_io_tag); + evt = BFA_IOIM_SM_COMP; + break; + + case BFI_IOIM_STS_SQER_NEEDED: + bfa_stats(ioim->itnim, iocom_sqer_needed); + bfa_assert(rsp->reuse_io_tag == 0); + evt = BFA_IOIM_SM_SQRETRY; + break; + + case BFI_IOIM_STS_RES_FREE: + bfa_stats(ioim->itnim, iocom_res_free); + evt = BFA_IOIM_SM_FREE; + break; + + case BFI_IOIM_STS_HOST_ABORTED: + bfa_stats(ioim->itnim, iocom_hostabrts); + if (rsp->abort_tag != ioim->abort_tag) { + bfa_trc(ioim->bfa, rsp->abort_tag); + bfa_trc(ioim->bfa, ioim->abort_tag); + return; + } + + if (rsp->reuse_io_tag) + evt = BFA_IOIM_SM_ABORT_COMP; + else + evt = BFA_IOIM_SM_ABORT_DONE; + break; + + case BFI_IOIM_STS_UTAG: + bfa_stats(ioim->itnim, iocom_utags); + evt = BFA_IOIM_SM_COMP_UTAG; + break; + + default: + bfa_assert(0); + } + + bfa_sm_send_event(ioim, evt); +} + +void +bfa_ioim_good_comp_isr(struct bfa_s *bfa, struct bfi_msg_s *m) +{ + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); + struct bfi_ioim_rsp_s *rsp = (struct bfi_ioim_rsp_s *) m; + struct bfa_ioim_s *ioim; + u16 iotag; + + iotag = bfa_os_ntohs(rsp->io_tag); + + ioim = BFA_IOIM_FROM_TAG(fcpim, iotag); + bfa_assert(ioim->iotag == iotag); + + bfa_trc_fp(ioim->bfa, ioim->iotag); + bfa_ioim_cb_profile_comp(fcpim, ioim); + + bfa_sm_send_event(ioim, BFA_IOIM_SM_COMP_GOOD); +} + +void +bfa_ioim_profile_start(struct bfa_ioim_s *ioim) +{ + ioim->start_time = bfa_os_get_clock(); +} + +void +bfa_ioim_profile_comp(struct bfa_ioim_s *ioim) +{ + u32 fcp_dl = bfa_cb_ioim_get_size(ioim->dio); + u32 index = bfa_ioim_get_index(fcp_dl); + u64 end_time = bfa_os_get_clock(); + struct bfa_itnim_latency_s *io_lat = + &(ioim->itnim->ioprofile.io_latency); + u32 val = (u32)(end_time - ioim->start_time); + + bfa_itnim_ioprofile_update(ioim->itnim, index); + + io_lat->count[index]++; + io_lat->min[index] = (io_lat->min[index] < val) ? + io_lat->min[index] : val; + io_lat->max[index] = (io_lat->max[index] > val) ? + io_lat->max[index] : val; + io_lat->avg[index] += val; +} +/** + * Called by itnim to clean up IO while going offline. + */ +void +bfa_ioim_cleanup(struct bfa_ioim_s *ioim) +{ + bfa_trc(ioim->bfa, ioim->iotag); + bfa_stats(ioim->itnim, io_cleanups); + + ioim->iosp->tskim = NULL; + bfa_sm_send_event(ioim, BFA_IOIM_SM_CLEANUP); +} + +void +bfa_ioim_cleanup_tm(struct bfa_ioim_s *ioim, struct bfa_tskim_s *tskim) +{ + bfa_trc(ioim->bfa, ioim->iotag); + bfa_stats(ioim->itnim, io_tmaborts); + + ioim->iosp->tskim = tskim; + bfa_sm_send_event(ioim, BFA_IOIM_SM_CLEANUP); +} + +/** + * IOC failure handling. + */ +void +bfa_ioim_iocdisable(struct bfa_ioim_s *ioim) +{ + bfa_trc(ioim->bfa, ioim->iotag); + bfa_stats(ioim->itnim, io_iocdowns); + bfa_sm_send_event(ioim, BFA_IOIM_SM_HWFAIL); +} + +/** + * IO offline TOV popped. Fail the pending IO. + */ +void +bfa_ioim_tov(struct bfa_ioim_s *ioim) +{ + bfa_trc(ioim->bfa, ioim->iotag); + bfa_sm_send_event(ioim, BFA_IOIM_SM_IOTOV); +} + + + +/** + * hal_ioim_api + */ + +/** + * Allocate IOIM resource for initiator mode I/O request. + */ +struct bfa_ioim_s * +bfa_ioim_alloc(struct bfa_s *bfa, struct bfad_ioim_s *dio, + struct bfa_itnim_s *itnim, u16 nsges) +{ + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); + struct bfa_ioim_s *ioim; + + /** + * alocate IOIM resource + */ + bfa_q_deq(&fcpim->ioim_free_q, &ioim); + if (!ioim) { + bfa_stats(itnim, no_iotags); + return NULL; + } + + ioim->dio = dio; + ioim->itnim = itnim; + ioim->nsges = nsges; + ioim->nsgpgs = 0; + + bfa_stats(itnim, total_ios); + fcpim->ios_active++; + + list_add_tail(&ioim->qe, &itnim->io_q); + bfa_trc_fp(ioim->bfa, ioim->iotag); + + return ioim; +} + +void +bfa_ioim_free(struct bfa_ioim_s *ioim) +{ + struct bfa_fcpim_mod_s *fcpim = ioim->fcpim; + + bfa_trc_fp(ioim->bfa, ioim->iotag); + bfa_assert_fp(bfa_sm_cmp_state(ioim, bfa_ioim_sm_uninit)); + + bfa_assert_fp(list_empty(&ioim->sgpg_q) || + (ioim->nsges > BFI_SGE_INLINE)); + + if (ioim->nsgpgs > 0) + bfa_sgpg_mfree(ioim->bfa, &ioim->sgpg_q, ioim->nsgpgs); + + bfa_stats(ioim->itnim, io_comps); + fcpim->ios_active--; + + list_del(&ioim->qe); + list_add_tail(&ioim->qe, &fcpim->ioim_free_q); +} + +void +bfa_ioim_start(struct bfa_ioim_s *ioim) +{ + bfa_trc_fp(ioim->bfa, ioim->iotag); + + bfa_ioim_cb_profile_start(ioim->fcpim, ioim); + + /** + * 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); +} + +/** + * Driver I/O abort request. + */ +bfa_status_t +bfa_ioim_abort(struct bfa_ioim_s *ioim) +{ + + bfa_trc(ioim->bfa, ioim->iotag); + + if (!bfa_ioim_is_abortable(ioim)) + return BFA_STATUS_FAILED; + + bfa_stats(ioim->itnim, io_aborts); + bfa_sm_send_event(ioim, BFA_IOIM_SM_ABORT); + + return BFA_STATUS_OK; +} + + +/** + * BFA TSKIM state machine functions + */ + +/** + * Task management command beginning state. + */ +static void +bfa_tskim_sm_uninit(struct bfa_tskim_s *tskim, enum bfa_tskim_event event) +{ + bfa_trc(tskim->bfa, event); + + switch (event) { + case BFA_TSKIM_SM_START: + bfa_sm_set_state(tskim, bfa_tskim_sm_active); + bfa_tskim_gather_ios(tskim); + + /** + * If device is offline, do not send TM on wire. Just cleanup + * any pending IO requests and complete TM request. + */ + if (!bfa_itnim_is_online(tskim->itnim)) { + bfa_sm_set_state(tskim, bfa_tskim_sm_iocleanup); + tskim->tsk_status = BFI_TSKIM_STS_OK; + bfa_tskim_cleanup_ios(tskim); + return; + } + + if (!bfa_tskim_send(tskim)) { + bfa_sm_set_state(tskim, bfa_tskim_sm_qfull); + bfa_stats(tskim->itnim, tm_qwait); + bfa_reqq_wait(tskim->bfa, tskim->itnim->reqq, + &tskim->reqq_wait); + } + break; + + default: + bfa_sm_fault(tskim->bfa, event); + } +} + +/** + * brief + * TM command is active, awaiting completion from firmware to + * cleanup IO requests in TM scope. + */ +static void +bfa_tskim_sm_active(struct bfa_tskim_s *tskim, enum bfa_tskim_event event) +{ + bfa_trc(tskim->bfa, event); + + switch (event) { + case BFA_TSKIM_SM_DONE: + bfa_sm_set_state(tskim, bfa_tskim_sm_iocleanup); + bfa_tskim_cleanup_ios(tskim); + break; + + case BFA_TSKIM_SM_CLEANUP: + bfa_sm_set_state(tskim, bfa_tskim_sm_cleanup); + if (!bfa_tskim_send_abort(tskim)) { + bfa_sm_set_state(tskim, bfa_tskim_sm_cleanup_qfull); + bfa_stats(tskim->itnim, tm_qwait); + bfa_reqq_wait(tskim->bfa, tskim->itnim->reqq, + &tskim->reqq_wait); + } + break; + + case BFA_TSKIM_SM_HWFAIL: + bfa_sm_set_state(tskim, bfa_tskim_sm_hcb); + bfa_tskim_iocdisable_ios(tskim); + bfa_tskim_qcomp(tskim, __bfa_cb_tskim_failed); + break; + + default: + bfa_sm_fault(tskim->bfa, event); + } +} + +/** + * An active TM is being cleaned up since ITN is offline. Awaiting cleanup + * completion event from firmware. + */ +static void +bfa_tskim_sm_cleanup(struct bfa_tskim_s *tskim, enum bfa_tskim_event event) +{ + bfa_trc(tskim->bfa, event); + + switch (event) { + case BFA_TSKIM_SM_DONE: + /** + * Ignore and wait for ABORT completion from firmware. + */ + break; + + case BFA_TSKIM_SM_CLEANUP_DONE: + bfa_sm_set_state(tskim, bfa_tskim_sm_iocleanup); + bfa_tskim_cleanup_ios(tskim); + break; + + case BFA_TSKIM_SM_HWFAIL: + bfa_sm_set_state(tskim, bfa_tskim_sm_hcb); + bfa_tskim_iocdisable_ios(tskim); + bfa_tskim_qcomp(tskim, __bfa_cb_tskim_failed); + break; + + default: + bfa_sm_fault(tskim->bfa, event); + } +} + +static void +bfa_tskim_sm_iocleanup(struct bfa_tskim_s *tskim, enum bfa_tskim_event event) +{ + bfa_trc(tskim->bfa, event); + + switch (event) { + case BFA_TSKIM_SM_IOS_DONE: + bfa_sm_set_state(tskim, bfa_tskim_sm_hcb); + bfa_tskim_qcomp(tskim, __bfa_cb_tskim_done); + break; + + case BFA_TSKIM_SM_CLEANUP: + /** + * Ignore, TM command completed on wire. + * Notify TM conmpletion on IO cleanup completion. + */ + break; + + case BFA_TSKIM_SM_HWFAIL: + bfa_sm_set_state(tskim, bfa_tskim_sm_hcb); + bfa_tskim_iocdisable_ios(tskim); + bfa_tskim_qcomp(tskim, __bfa_cb_tskim_failed); + break; + + default: + bfa_sm_fault(tskim->bfa, event); + } +} + +/** + * Task management command is waiting for room in request CQ + */ +static void +bfa_tskim_sm_qfull(struct bfa_tskim_s *tskim, enum bfa_tskim_event event) +{ + bfa_trc(tskim->bfa, event); + + switch (event) { + case BFA_TSKIM_SM_QRESUME: + bfa_sm_set_state(tskim, bfa_tskim_sm_active); + bfa_tskim_send(tskim); + break; + + case BFA_TSKIM_SM_CLEANUP: + /** + * No need to send TM on wire since ITN is offline. + */ + bfa_sm_set_state(tskim, bfa_tskim_sm_iocleanup); + bfa_reqq_wcancel(&tskim->reqq_wait); + bfa_tskim_cleanup_ios(tskim); + break; + + case BFA_TSKIM_SM_HWFAIL: + bfa_sm_set_state(tskim, bfa_tskim_sm_hcb); + bfa_reqq_wcancel(&tskim->reqq_wait); + bfa_tskim_iocdisable_ios(tskim); + bfa_tskim_qcomp(tskim, __bfa_cb_tskim_failed); + break; + + default: + bfa_sm_fault(tskim->bfa, event); + } +} + +/** + * Task management command is active, awaiting for room in request CQ + * to send clean up request. + */ +static void +bfa_tskim_sm_cleanup_qfull(struct bfa_tskim_s *tskim, + enum bfa_tskim_event event) +{ + bfa_trc(tskim->bfa, event); + + switch (event) { + case BFA_TSKIM_SM_DONE: + bfa_reqq_wcancel(&tskim->reqq_wait); + /** + * + * Fall through !!! + */ + + case BFA_TSKIM_SM_QRESUME: + bfa_sm_set_state(tskim, bfa_tskim_sm_cleanup); + bfa_tskim_send_abort(tskim); + break; + + case BFA_TSKIM_SM_HWFAIL: + bfa_sm_set_state(tskim, bfa_tskim_sm_hcb); + bfa_reqq_wcancel(&tskim->reqq_wait); + bfa_tskim_iocdisable_ios(tskim); + bfa_tskim_qcomp(tskim, __bfa_cb_tskim_failed); + break; + + default: + bfa_sm_fault(tskim->bfa, event); + } +} + +/** + * BFA callback is pending + */ +static void +bfa_tskim_sm_hcb(struct bfa_tskim_s *tskim, enum bfa_tskim_event event) +{ + bfa_trc(tskim->bfa, event); + + switch (event) { + case BFA_TSKIM_SM_HCB: + bfa_sm_set_state(tskim, bfa_tskim_sm_uninit); + bfa_tskim_free(tskim); + break; + + case BFA_TSKIM_SM_CLEANUP: + bfa_tskim_notify_comp(tskim); + break; + + case BFA_TSKIM_SM_HWFAIL: + break; + + default: + bfa_sm_fault(tskim->bfa, event); + } +} + + + +/** + * hal_tskim_private + */ + +static void +__bfa_cb_tskim_done(void *cbarg, bfa_boolean_t complete) +{ + struct bfa_tskim_s *tskim = cbarg; + + if (!complete) { + bfa_sm_send_event(tskim, BFA_TSKIM_SM_HCB); + return; + } + + bfa_stats(tskim->itnim, tm_success); + bfa_cb_tskim_done(tskim->bfa->bfad, tskim->dtsk, tskim->tsk_status); +} + +static void +__bfa_cb_tskim_failed(void *cbarg, bfa_boolean_t complete) +{ + struct bfa_tskim_s *tskim = cbarg; + + if (!complete) { + bfa_sm_send_event(tskim, BFA_TSKIM_SM_HCB); + return; + } + + bfa_stats(tskim->itnim, tm_failures); + bfa_cb_tskim_done(tskim->bfa->bfad, tskim->dtsk, + BFI_TSKIM_STS_FAILED); +} + +static bfa_boolean_t +bfa_tskim_match_scope(struct bfa_tskim_s *tskim, lun_t lun) +{ + switch (tskim->tm_cmnd) { + case FCP_TM_TARGET_RESET: + return BFA_TRUE; + + case FCP_TM_ABORT_TASK_SET: + case FCP_TM_CLEAR_TASK_SET: + case FCP_TM_LUN_RESET: + case FCP_TM_CLEAR_ACA: + return (tskim->lun == lun); + + default: + bfa_assert(0); + } + + return BFA_FALSE; +} + +/** + * Gather affected IO requests and task management commands. + */ +static void +bfa_tskim_gather_ios(struct bfa_tskim_s *tskim) +{ + struct bfa_itnim_s *itnim = tskim->itnim; + struct bfa_ioim_s *ioim; + struct list_head *qe, *qen; + + INIT_LIST_HEAD(&tskim->io_q); + + /** + * Gather any active IO requests first. + */ + list_for_each_safe(qe, qen, &itnim->io_q) { + ioim = (struct bfa_ioim_s *) qe; + if (bfa_tskim_match_scope + (tskim, bfa_cb_ioim_get_lun(ioim->dio))) { + list_del(&ioim->qe); + list_add_tail(&ioim->qe, &tskim->io_q); + } + } + + /** + * Failback any pending IO requests immediately. + */ + list_for_each_safe(qe, qen, &itnim->pending_q) { + ioim = (struct bfa_ioim_s *) qe; + if (bfa_tskim_match_scope + (tskim, bfa_cb_ioim_get_lun(ioim->dio))) { + list_del(&ioim->qe); + list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q); + bfa_ioim_tov(ioim); + } + } +} + +/** + * IO cleanup completion + */ +static void +bfa_tskim_cleanp_comp(void *tskim_cbarg) +{ + struct bfa_tskim_s *tskim = tskim_cbarg; + + bfa_stats(tskim->itnim, tm_io_comps); + bfa_sm_send_event(tskim, BFA_TSKIM_SM_IOS_DONE); +} + +/** + * Gather affected IO requests and task management commands. + */ +static void +bfa_tskim_cleanup_ios(struct bfa_tskim_s *tskim) +{ + struct bfa_ioim_s *ioim; + struct list_head *qe, *qen; + + bfa_wc_init(&tskim->wc, bfa_tskim_cleanp_comp, tskim); + + list_for_each_safe(qe, qen, &tskim->io_q) { + ioim = (struct bfa_ioim_s *) qe; + bfa_wc_up(&tskim->wc); + bfa_ioim_cleanup_tm(ioim, tskim); + } + + bfa_wc_wait(&tskim->wc); +} + +/** + * Send task management request to firmware. + */ +static bfa_boolean_t +bfa_tskim_send(struct bfa_tskim_s *tskim) +{ + struct bfa_itnim_s *itnim = tskim->itnim; + struct bfi_tskim_req_s *m; + + /** + * check for room in queue to send request now + */ + m = bfa_reqq_next(tskim->bfa, itnim->reqq); + if (!m) + return BFA_FALSE; + + /** + * build i/o request message next + */ + bfi_h2i_set(m->mh, BFI_MC_TSKIM, BFI_TSKIM_H2I_TM_REQ, + bfa_lpuid(tskim->bfa)); + + m->tsk_tag = bfa_os_htons(tskim->tsk_tag); + m->itn_fhdl = tskim->itnim->rport->fw_handle; + m->t_secs = tskim->tsecs; + m->lun = tskim->lun; + m->tm_flags = tskim->tm_cmnd; + + /** + * queue I/O message to firmware + */ + bfa_reqq_produce(tskim->bfa, itnim->reqq); + return BFA_TRUE; +} + +/** + * Send abort request to cleanup an active TM to firmware. + */ +static bfa_boolean_t +bfa_tskim_send_abort(struct bfa_tskim_s *tskim) +{ + struct bfa_itnim_s *itnim = tskim->itnim; + struct bfi_tskim_abortreq_s *m; + + /** + * check for room in queue to send request now + */ + m = bfa_reqq_next(tskim->bfa, itnim->reqq); + if (!m) + return BFA_FALSE; + + /** + * build i/o request message next + */ + bfi_h2i_set(m->mh, BFI_MC_TSKIM, BFI_TSKIM_H2I_ABORT_REQ, + bfa_lpuid(tskim->bfa)); + + m->tsk_tag = bfa_os_htons(tskim->tsk_tag); + + /** + * queue I/O message to firmware + */ + bfa_reqq_produce(tskim->bfa, itnim->reqq); + return BFA_TRUE; +} + +/** + * Call to resume task management cmnd waiting for room in request queue. + */ +static void +bfa_tskim_qresume(void *cbarg) +{ + struct bfa_tskim_s *tskim = cbarg; + + bfa_stats(tskim->itnim, tm_qresumes); + bfa_sm_send_event(tskim, BFA_TSKIM_SM_QRESUME); +} + +/** + * Cleanup IOs associated with a task mangement command on IOC failures. + */ +static void +bfa_tskim_iocdisable_ios(struct bfa_tskim_s *tskim) +{ + struct bfa_ioim_s *ioim; + struct list_head *qe, *qen; + + list_for_each_safe(qe, qen, &tskim->io_q) { + ioim = (struct bfa_ioim_s *) qe; + bfa_ioim_iocdisable(ioim); + } +} + + + +/** + * hal_tskim_friend + */ + +/** + * Notification on completions from related ioim. + */ +void +bfa_tskim_iodone(struct bfa_tskim_s *tskim) +{ + bfa_wc_down(&tskim->wc); +} + +/** + * Handle IOC h/w failure notification from itnim. + */ +void +bfa_tskim_iocdisable(struct bfa_tskim_s *tskim) +{ + tskim->notify = BFA_FALSE; + bfa_stats(tskim->itnim, tm_iocdowns); + bfa_sm_send_event(tskim, BFA_TSKIM_SM_HWFAIL); +} + +/** + * Cleanup TM command and associated IOs as part of ITNIM offline. + */ +void +bfa_tskim_cleanup(struct bfa_tskim_s *tskim) +{ + tskim->notify = BFA_TRUE; + bfa_stats(tskim->itnim, tm_cleanups); + bfa_sm_send_event(tskim, BFA_TSKIM_SM_CLEANUP); +} + +/** + * Memory allocation and initialization. + */ +void +bfa_tskim_attach(struct bfa_fcpim_mod_s *fcpim, struct bfa_meminfo_s *minfo) +{ + struct bfa_tskim_s *tskim; + u16 i; + + INIT_LIST_HEAD(&fcpim->tskim_free_q); + + tskim = (struct bfa_tskim_s *) bfa_meminfo_kva(minfo); + fcpim->tskim_arr = tskim; + + for (i = 0; i < fcpim->num_tskim_reqs; i++, tskim++) { + /* + * initialize TSKIM + */ + bfa_os_memset(tskim, 0, sizeof(struct bfa_tskim_s)); + tskim->tsk_tag = i; + tskim->bfa = fcpim->bfa; + tskim->fcpim = fcpim; + tskim->notify = BFA_FALSE; + bfa_reqq_winit(&tskim->reqq_wait, bfa_tskim_qresume, + tskim); + bfa_sm_set_state(tskim, bfa_tskim_sm_uninit); + + list_add_tail(&tskim->qe, &fcpim->tskim_free_q); + } + + bfa_meminfo_kva(minfo) = (u8 *) tskim; +} + +void +bfa_tskim_detach(struct bfa_fcpim_mod_s *fcpim) +{ + /** + * @todo + */ +} + +void +bfa_tskim_isr(struct bfa_s *bfa, struct bfi_msg_s *m) +{ + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); + struct bfi_tskim_rsp_s *rsp = (struct bfi_tskim_rsp_s *) m; + struct bfa_tskim_s *tskim; + u16 tsk_tag = bfa_os_ntohs(rsp->tsk_tag); + + tskim = BFA_TSKIM_FROM_TAG(fcpim, tsk_tag); + bfa_assert(tskim->tsk_tag == tsk_tag); + + tskim->tsk_status = rsp->tsk_status; + + /** + * Firmware sends BFI_TSKIM_STS_ABORTED status for abort + * requests. All other statuses are for normal completions. + */ + if (rsp->tsk_status == BFI_TSKIM_STS_ABORTED) { + bfa_stats(tskim->itnim, tm_cleanup_comps); + bfa_sm_send_event(tskim, BFA_TSKIM_SM_CLEANUP_DONE); + } else { + bfa_stats(tskim->itnim, tm_fw_rsps); + bfa_sm_send_event(tskim, BFA_TSKIM_SM_DONE); + } +} + + + +/** + * hal_tskim_api + */ + + +struct bfa_tskim_s * +bfa_tskim_alloc(struct bfa_s *bfa, struct bfad_tskim_s *dtsk) +{ + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); + struct bfa_tskim_s *tskim; + + bfa_q_deq(&fcpim->tskim_free_q, &tskim); + + if (tskim) + tskim->dtsk = dtsk; + + return tskim; +} + +void +bfa_tskim_free(struct bfa_tskim_s *tskim) +{ + bfa_assert(bfa_q_is_on_q_func(&tskim->itnim->tsk_q, &tskim->qe)); + list_del(&tskim->qe); + list_add_tail(&tskim->qe, &tskim->fcpim->tskim_free_q); +} + +/** + * Start a task management command. + * + * @param[in] tskim BFA task management command instance + * @param[in] itnim i-t nexus for the task management command + * @param[in] lun lun, if applicable + * @param[in] tm_cmnd Task management command code. + * @param[in] t_secs Timeout in seconds + * + * @return None. + */ +void +bfa_tskim_start(struct bfa_tskim_s *tskim, struct bfa_itnim_s *itnim, lun_t lun, + enum fcp_tm_cmnd tm_cmnd, u8 tsecs) +{ + tskim->itnim = itnim; + tskim->lun = lun; + tskim->tm_cmnd = tm_cmnd; + tskim->tsecs = tsecs; + tskim->notify = BFA_FALSE; + bfa_stats(itnim, tm_cmnds); + + list_add_tail(&tskim->qe, &itnim->tsk_q); + bfa_sm_send_event(tskim, BFA_TSKIM_SM_START); +} diff --git a/drivers/scsi/bfa/bfa_fcpim.h b/drivers/scsi/bfa/bfa_fcpim.h new file mode 100644 index 000000000000..3bf343160aac --- /dev/null +++ b/drivers/scsi/bfa/bfa_fcpim.h @@ -0,0 +1,401 @@ +/* + * 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 __BFA_FCPIM_H__ +#define __BFA_FCPIM_H__ + +#include "bfa.h" +#include "bfa_svc.h" +#include "bfi_ms.h" +#include "bfa_defs_svc.h" +#include "bfa_cs.h" + + +#define BFA_ITNIM_MIN 32 +#define BFA_ITNIM_MAX 1024 + +#define BFA_IOIM_MIN 8 +#define BFA_IOIM_MAX 2000 + +#define BFA_TSKIM_MIN 4 +#define BFA_TSKIM_MAX 512 +#define BFA_FCPIM_PATHTOV_DEF (30 * 1000) /* in millisecs */ +#define BFA_FCPIM_PATHTOV_MAX (90 * 1000) /* in millisecs */ + + +#define bfa_itnim_ioprofile_update(__itnim, __index) \ + (__itnim->ioprofile.iocomps[__index]++) + +#define BFA_IOIM_RETRY_TAG_OFFSET 11 +#define BFA_IOIM_RETRY_TAG_MASK 0x07ff /* 2K IOs */ +#define BFA_IOIM_RETRY_MAX 7 + +/* Buckets are are 512 bytes to 2MB */ +static inline u32 +bfa_ioim_get_index(u32 n) { + int pos = 0; + if (n >= (1UL)<<22) + return BFA_IOBUCKET_MAX - 1; + n >>= 8; + if (n >= (1UL)<<16) + n >>= 16; pos += 16; + if (n >= 1 << 8) + n >>= 8; pos += 8; + if (n >= 1 << 4) + n >>= 4; pos += 4; + if (n >= 1 << 2) + n >>= 2; pos += 2; + if (n >= 1 << 1) + pos += 1; + + return (n == 0) ? (0) : pos; +} + +/* + * forward declarations + */ +struct bfa_ioim_s; +struct bfa_tskim_s; +struct bfad_ioim_s; +struct bfad_tskim_s; + +typedef void (*bfa_fcpim_profile_t) (struct bfa_ioim_s *ioim); + +struct bfa_fcpim_mod_s { + struct bfa_s *bfa; + struct bfa_itnim_s *itnim_arr; + struct bfa_ioim_s *ioim_arr; + struct bfa_ioim_sp_s *ioim_sp_arr; + struct bfa_tskim_s *tskim_arr; + struct bfa_dma_s snsbase; + int num_itnims; + int num_ioim_reqs; + int num_tskim_reqs; + u32 path_tov; + u16 q_depth; + 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 */ + struct list_head ioim_comp_q; /* IO global comp Q */ + struct list_head tskim_free_q; + u32 ios_active; /* current active IOs */ + u32 delay_comp; + struct bfa_fcpim_del_itn_stats_s del_itn_stats; + bfa_boolean_t ioredirect; + bfa_boolean_t io_profile; + u32 io_profile_start_time; + bfa_fcpim_profile_t profile_comp; + bfa_fcpim_profile_t profile_start; +}; + +/** + * BFA IO (initiator mode) + */ +struct bfa_ioim_s { + struct list_head qe; /* queue elememt */ + bfa_sm_t sm; /* BFA ioim state machine */ + struct bfa_s *bfa; /* BFA module */ + struct bfa_fcpim_mod_s *fcpim; /* parent fcpim module */ + struct bfa_itnim_s *itnim; /* i-t-n nexus for this IO */ + struct bfad_ioim_s *dio; /* driver IO handle */ + u16 iotag; /* FWI IO tag */ + u16 abort_tag; /* unqiue abort request tag */ + u16 nsges; /* number of SG elements */ + u16 nsgpgs; /* number of SG pages */ + struct bfa_sgpg_s *sgpg; /* first SG page */ + struct list_head sgpg_q; /* allocated SG pages */ + struct bfa_cb_qe_s hcb_qe; /* bfa callback qelem */ + bfa_cb_cbfn_t io_cbfn; /* IO completion handler */ + struct bfa_ioim_sp_s *iosp; /* slow-path IO handling */ + u8 reqq; /* Request queue for I/O */ + u64 start_time; /* IO's Profile start val */ +}; + + +struct bfa_ioim_sp_s { + struct bfi_msg_s comp_rspmsg; /* IO comp f/w response */ + u8 *snsinfo; /* sense info for this IO */ + struct bfa_sgpg_wqe_s sgpg_wqe; /* waitq elem for sgpg */ + struct bfa_reqq_wait_s reqq_wait; /* to wait for room in reqq */ + bfa_boolean_t abort_explicit; /* aborted by OS */ + struct bfa_tskim_s *tskim; /* Relevant TM cmd */ +}; + +/** + * BFA Task management command (initiator mode) + */ +struct bfa_tskim_s { + struct list_head qe; + bfa_sm_t sm; + struct bfa_s *bfa; /* BFA module */ + struct bfa_fcpim_mod_s *fcpim; /* parent fcpim module */ + struct bfa_itnim_s *itnim; /* i-t-n nexus for this IO */ + struct bfad_tskim_s *dtsk; /* driver task mgmt cmnd */ + bfa_boolean_t notify; /* notify itnim on TM comp */ + lun_t lun; /* lun if applicable */ + enum fcp_tm_cmnd tm_cmnd; /* task management command */ + u16 tsk_tag; /* FWI IO tag */ + u8 tsecs; /* timeout in seconds */ + struct bfa_reqq_wait_s reqq_wait; /* to wait for room in reqq */ + struct list_head io_q; /* queue of affected IOs */ + struct bfa_wc_s wc; /* waiting counter */ + struct bfa_cb_qe_s hcb_qe; /* bfa callback qelem */ + enum bfi_tskim_status tsk_status; /* TM status */ +}; + + +/** + * BFA i-t-n (initiator mode) + */ +struct bfa_itnim_s { + struct list_head qe; /* queue element */ + bfa_sm_t sm; /* i-t-n im BFA state machine */ + struct bfa_s *bfa; /* bfa instance */ + struct bfa_rport_s *rport; /* bfa rport */ + void *ditn; /* driver i-t-n structure */ + struct bfi_mhdr_s mhdr; /* pre-built mhdr */ + u8 msg_no; /* itnim/rport firmware handle */ + u8 reqq; /* CQ for requests */ + struct bfa_cb_qe_s hcb_qe; /* bfa callback qelem */ + struct list_head pending_q; /* queue of pending IO requests */ + struct list_head io_q; /* queue of active IO requests */ + struct list_head io_cleanup_q; /* IO being cleaned up */ + struct list_head tsk_q; /* queue of active TM commands */ + struct list_head delay_comp_q; /* queue of failed inflight cmds */ + bfa_boolean_t seq_rec; /* SQER supported */ + bfa_boolean_t is_online; /* itnim is ONLINE for IO */ + bfa_boolean_t iotov_active; /* IO TOV timer is active */ + struct bfa_wc_s wc; /* waiting counter */ + struct bfa_timer_s timer; /* pending IO TOV */ + struct bfa_reqq_wait_s reqq_wait; /* to wait for room in reqq */ + struct bfa_fcpim_mod_s *fcpim; /* fcpim module */ + struct bfa_itnim_iostats_s stats; + struct bfa_itnim_ioprofile_s ioprofile; +}; + + +#define bfa_itnim_is_online(_itnim) ((_itnim)->is_online) +#define BFA_FCPIM_MOD(_hal) (&(_hal)->modules.fcpim_mod) +#define BFA_IOIM_FROM_TAG(_fcpim, _iotag) \ + (&fcpim->ioim_arr[(_iotag & BFA_IOIM_RETRY_TAG_MASK)]) +#define BFA_TSKIM_FROM_TAG(_fcpim, _tmtag) \ + (&fcpim->tskim_arr[_tmtag & (fcpim->num_tskim_reqs - 1)]) + +#define bfa_io_profile_start_time(_bfa) \ + (_bfa->modules.fcpim_mod.io_profile_start_time) +#define bfa_fcpim_get_io_profile(_bfa) \ + (_bfa->modules.fcpim_mod.io_profile) + +static inline bfa_boolean_t +bfa_ioim_get_iotag(struct bfa_ioim_s *ioim) +{ + u16 k = ioim->iotag; + + k >>= BFA_IOIM_RETRY_TAG_OFFSET; k++; + + if (k > BFA_IOIM_RETRY_MAX) + return BFA_FALSE; + ioim->iotag &= BFA_IOIM_RETRY_TAG_MASK; + ioim->iotag |= k<<BFA_IOIM_RETRY_TAG_OFFSET; + return BFA_TRUE; +} +/* + * function prototypes + */ +void bfa_ioim_attach(struct bfa_fcpim_mod_s *fcpim, + struct bfa_meminfo_s *minfo); +void bfa_ioim_detach(struct bfa_fcpim_mod_s *fcpim); +void bfa_ioim_isr(struct bfa_s *bfa, struct bfi_msg_s *msg); +void bfa_ioim_good_comp_isr(struct bfa_s *bfa, + struct bfi_msg_s *msg); +void bfa_ioim_cleanup(struct bfa_ioim_s *ioim); +void bfa_ioim_cleanup_tm(struct bfa_ioim_s *ioim, + struct bfa_tskim_s *tskim); +void bfa_ioim_iocdisable(struct bfa_ioim_s *ioim); +void bfa_ioim_tov(struct bfa_ioim_s *ioim); + +void bfa_tskim_attach(struct bfa_fcpim_mod_s *fcpim, + struct bfa_meminfo_s *minfo); +void bfa_tskim_detach(struct bfa_fcpim_mod_s *fcpim); +void bfa_tskim_isr(struct bfa_s *bfa, struct bfi_msg_s *msg); +void bfa_tskim_iodone(struct bfa_tskim_s *tskim); +void bfa_tskim_iocdisable(struct bfa_tskim_s *tskim); +void bfa_tskim_cleanup(struct bfa_tskim_s *tskim); + +void bfa_itnim_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len, + u32 *dm_len); +void bfa_itnim_attach(struct bfa_fcpim_mod_s *fcpim, + struct bfa_meminfo_s *minfo); +void bfa_itnim_detach(struct bfa_fcpim_mod_s *fcpim); +void bfa_itnim_iocdisable(struct bfa_itnim_s *itnim); +void bfa_itnim_isr(struct bfa_s *bfa, struct bfi_msg_s *msg); +void bfa_itnim_iodone(struct bfa_itnim_s *itnim); +void bfa_itnim_tskdone(struct bfa_itnim_s *itnim); +bfa_boolean_t bfa_itnim_hold_io(struct bfa_itnim_s *itnim); +void bfa_ioim_profile_comp(struct bfa_ioim_s *ioim); +void bfa_ioim_profile_start(struct bfa_ioim_s *ioim); + + +/* + * bfa fcpim module API functions + */ +void bfa_fcpim_path_tov_set(struct bfa_s *bfa, u16 path_tov); +u16 bfa_fcpim_path_tov_get(struct bfa_s *bfa); +void bfa_fcpim_qdepth_set(struct bfa_s *bfa, u16 q_depth); +u16 bfa_fcpim_qdepth_get(struct bfa_s *bfa); +bfa_status_t bfa_fcpim_get_modstats(struct bfa_s *bfa, + struct bfa_itnim_iostats_s *modstats); +bfa_status_t bfa_fcpim_port_iostats(struct bfa_s *bfa, + struct bfa_itnim_iostats_s *stats, u8 lp_tag); +bfa_status_t bfa_fcpim_get_del_itn_stats(struct bfa_s *bfa, + struct bfa_fcpim_del_itn_stats_s *modstats); +bfa_status_t bfa_fcpim_port_clear_iostats(struct bfa_s *bfa, u8 lp_tag); +void bfa_fcpim_add_stats(struct bfa_itnim_iostats_s *fcpim_stats, + struct bfa_itnim_iostats_s *itnim_stats); +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); +bfa_status_t bfa_fcpim_profile_on(struct bfa_s *bfa, u32 time); +bfa_status_t bfa_fcpim_profile_off(struct bfa_s *bfa); +#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 + */ +struct bfa_itnim_s *bfa_itnim_create(struct bfa_s *bfa, + struct bfa_rport_s *rport, void *itnim); +void bfa_itnim_delete(struct bfa_itnim_s *itnim); +void bfa_itnim_online(struct bfa_itnim_s *itnim, + bfa_boolean_t seq_rec); +void bfa_itnim_offline(struct bfa_itnim_s *itnim); +void bfa_itnim_get_stats(struct bfa_itnim_s *itnim, + struct bfa_itnim_iostats_s *stats); +void bfa_itnim_clear_stats(struct bfa_itnim_s *itnim); +bfa_status_t bfa_itnim_get_ioprofile(struct bfa_itnim_s *itnim, + struct bfa_itnim_ioprofile_s *ioprofile); +#define bfa_itnim_get_reqq(__ioim) (((struct bfa_ioim_s *)__ioim)->itnim->reqq) + +/** + * BFA completion callback for bfa_itnim_online(). + * + * @param[in] itnim FCS or driver itnim instance + * + * return None + */ +void bfa_cb_itnim_online(void *itnim); + +/** + * BFA completion callback for bfa_itnim_offline(). + * + * @param[in] itnim FCS or driver itnim instance + * + * return None + */ +void bfa_cb_itnim_offline(void *itnim); +void bfa_cb_itnim_tov_begin(void *itnim); +void bfa_cb_itnim_tov(void *itnim); + +/** + * BFA notification to FCS/driver for second level error recovery. + * + * Atleast one I/O request has timedout and target is unresponsive to + * repeated abort requests. Second level error recovery should be initiated + * by starting implicit logout and recovery procedures. + * + * @param[in] itnim FCS or driver itnim instance + * + * return None + */ +void bfa_cb_itnim_sler(void *itnim); + +/* + * bfa ioim API functions + */ +struct bfa_ioim_s *bfa_ioim_alloc(struct bfa_s *bfa, + struct bfad_ioim_s *dio, + struct bfa_itnim_s *itnim, + u16 nsgles); + +void bfa_ioim_free(struct bfa_ioim_s *ioim); +void bfa_ioim_start(struct bfa_ioim_s *ioim); +bfa_status_t bfa_ioim_abort(struct bfa_ioim_s *ioim); +void bfa_ioim_delayed_comp(struct bfa_ioim_s *ioim, + bfa_boolean_t iotov); + + +/** + * I/O completion notification. + * + * @param[in] dio driver IO structure + * @param[in] io_status IO completion status + * @param[in] scsi_status SCSI status returned by target + * @param[in] sns_len SCSI sense length, 0 if none + * @param[in] sns_info SCSI sense data, if any + * @param[in] residue Residual length + * + * @return None + */ +void bfa_cb_ioim_done(void *bfad, struct bfad_ioim_s *dio, + enum bfi_ioim_status io_status, + u8 scsi_status, int sns_len, + u8 *sns_info, s32 residue); + +/** + * I/O good completion notification. + * + * @param[in] dio driver IO structure + * + * @return None + */ +void bfa_cb_ioim_good_comp(void *bfad, struct bfad_ioim_s *dio); + +/** + * I/O abort completion notification + * + * @param[in] dio driver IO that was aborted + * + * @return None + */ +void bfa_cb_ioim_abort(void *bfad, struct bfad_ioim_s *dio); + +/* + * bfa tskim API functions + */ +struct bfa_tskim_s *bfa_tskim_alloc(struct bfa_s *bfa, + struct bfad_tskim_s *dtsk); +void bfa_tskim_free(struct bfa_tskim_s *tskim); +void bfa_tskim_start(struct bfa_tskim_s *tskim, + struct bfa_itnim_s *itnim, lun_t lun, + enum fcp_tm_cmnd tm, u8 t_secs); +void bfa_cb_tskim_done(void *bfad, struct bfad_tskim_s *dtsk, + enum bfi_tskim_status tsk_status); + +#endif /* __BFA_FCPIM_H__ */ diff --git a/drivers/scsi/bfa/bfa_fcpim_priv.h b/drivers/scsi/bfa/bfa_fcpim_priv.h deleted file mode 100644 index 762516cb5cb2..000000000000 --- a/drivers/scsi/bfa/bfa_fcpim_priv.h +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFA_FCPIM_PRIV_H__ -#define __BFA_FCPIM_PRIV_H__ - -#include <bfa_fcpim.h> -#include <defs/bfa_defs_fcpim.h> -#include <cs/bfa_wc.h> -#include "bfa_sgpg_priv.h" - -#define BFA_ITNIM_MIN 32 -#define BFA_ITNIM_MAX 1024 - -#define BFA_IOIM_MIN 8 -#define BFA_IOIM_MAX 2000 - -#define BFA_TSKIM_MIN 4 -#define BFA_TSKIM_MAX 512 -#define BFA_FCPIM_PATHTOV_DEF (30 * 1000) /* in millisecs */ -#define BFA_FCPIM_PATHTOV_MAX (90 * 1000) /* in millisecs */ - -#define bfa_fcpim_stats(__fcpim, __stats) \ - ((__fcpim)->stats.__stats++) - -struct bfa_fcpim_mod_s { - struct bfa_s *bfa; - struct bfa_itnim_s *itnim_arr; - struct bfa_ioim_s *ioim_arr; - struct bfa_ioim_sp_s *ioim_sp_arr; - struct bfa_tskim_s *tskim_arr; - struct bfa_dma_s snsbase; - int num_itnims; - int num_ioim_reqs; - int num_tskim_reqs; - u32 path_tov; - u16 q_depth; - 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 */ - struct list_head ioim_comp_q; /* IO global comp Q */ - struct list_head tskim_free_q; - u32 ios_active; /* current active IOs */ - u32 delay_comp; - struct bfa_fcpim_stats_s stats; - bfa_boolean_t ioredirect; -}; - -struct bfa_ioim_s; -struct bfa_tskim_s; - -/** - * BFA IO (initiator mode) - */ -struct bfa_ioim_s { - struct list_head qe; /* queue elememt */ - bfa_sm_t sm; /* BFA ioim state machine */ - struct bfa_s *bfa; /* BFA module */ - struct bfa_fcpim_mod_s *fcpim; /* parent fcpim module */ - struct bfa_itnim_s *itnim; /* i-t-n nexus for this IO */ - struct bfad_ioim_s *dio; /* driver IO handle */ - u16 iotag; /* FWI IO tag */ - u16 abort_tag; /* unqiue abort request tag */ - u16 nsges; /* number of SG elements */ - u16 nsgpgs; /* number of SG pages */ - struct bfa_sgpg_s *sgpg; /* first SG page */ - struct list_head sgpg_q; /* allocated SG pages */ - struct bfa_cb_qe_s hcb_qe; /* bfa callback qelem */ - bfa_cb_cbfn_t io_cbfn; /* IO completion handler */ - struct bfa_ioim_sp_s *iosp; /* slow-path IO handling */ - u8 reqq; /* Request queue for I/O */ -}; - -struct bfa_ioim_sp_s { - struct bfi_msg_s comp_rspmsg; /* IO comp f/w response */ - u8 *snsinfo; /* sense info for this IO */ - struct bfa_sgpg_wqe_s sgpg_wqe; /* waitq elem for sgpg */ - struct bfa_reqq_wait_s reqq_wait; /* to wait for room in reqq */ - bfa_boolean_t abort_explicit; /* aborted by OS */ - struct bfa_tskim_s *tskim; /* Relevant TM cmd */ -}; - -/** - * BFA Task management command (initiator mode) - */ -struct bfa_tskim_s { - struct list_head qe; - bfa_sm_t sm; - struct bfa_s *bfa; /* BFA module */ - struct bfa_fcpim_mod_s *fcpim; /* parent fcpim module */ - struct bfa_itnim_s *itnim; /* i-t-n nexus for this IO */ - struct bfad_tskim_s *dtsk; /* driver task mgmt cmnd */ - bfa_boolean_t notify; /* notify itnim on TM comp */ - lun_t lun; /* lun if applicable */ - enum fcp_tm_cmnd tm_cmnd; /* task management command */ - u16 tsk_tag; /* FWI IO tag */ - u8 tsecs; /* timeout in seconds */ - struct bfa_reqq_wait_s reqq_wait; /* to wait for room in reqq */ - struct list_head io_q; /* queue of affected IOs */ - struct bfa_wc_s wc; /* waiting counter */ - struct bfa_cb_qe_s hcb_qe; /* bfa callback qelem */ - enum bfi_tskim_status tsk_status; /* TM status */ -}; - -/** - * BFA i-t-n (initiator mode) - */ -struct bfa_itnim_s { - struct list_head qe; /* queue element */ - bfa_sm_t sm; /* i-t-n im BFA state machine */ - struct bfa_s *bfa; /* bfa instance */ - struct bfa_rport_s *rport; /* bfa rport */ - void *ditn; /* driver i-t-n structure */ - struct bfi_mhdr_s mhdr; /* pre-built mhdr */ - u8 msg_no; /* itnim/rport firmware handle */ - u8 reqq; /* CQ for requests */ - struct bfa_cb_qe_s hcb_qe; /* bfa callback qelem */ - struct list_head pending_q; /* queue of pending IO requests*/ - struct list_head io_q; /* queue of active IO requests */ - struct list_head io_cleanup_q; /* IO being cleaned up */ - struct list_head tsk_q; /* queue of active TM commands */ - struct list_head delay_comp_q;/* queue of failed inflight cmds */ - bfa_boolean_t seq_rec; /* SQER supported */ - bfa_boolean_t is_online; /* itnim is ONLINE for IO */ - bfa_boolean_t iotov_active; /* IO TOV timer is active */ - struct bfa_wc_s wc; /* waiting counter */ - struct bfa_timer_s timer; /* pending IO TOV */ - struct bfa_reqq_wait_s reqq_wait; /* to wait for room in reqq */ - struct bfa_fcpim_mod_s *fcpim; /* fcpim module */ - struct bfa_itnim_hal_stats_s stats; - struct bfa_itnim_latency_s io_latency; -}; - -#define bfa_itnim_is_online(_itnim) ((_itnim)->is_online) -#define BFA_FCPIM_MOD(_hal) (&(_hal)->modules.fcpim_mod) -#define BFA_IOIM_FROM_TAG(_fcpim, _iotag) \ - (&fcpim->ioim_arr[_iotag]) -#define BFA_TSKIM_FROM_TAG(_fcpim, _tmtag) \ - (&fcpim->tskim_arr[_tmtag & (fcpim->num_tskim_reqs - 1)]) - -/* - * function prototypes - */ -void bfa_ioim_attach(struct bfa_fcpim_mod_s *fcpim, - struct bfa_meminfo_s *minfo); -void bfa_ioim_detach(struct bfa_fcpim_mod_s *fcpim); -void bfa_ioim_isr(struct bfa_s *bfa, struct bfi_msg_s *msg); -void bfa_ioim_good_comp_isr(struct bfa_s *bfa, - struct bfi_msg_s *msg); -void bfa_ioim_cleanup(struct bfa_ioim_s *ioim); -void bfa_ioim_cleanup_tm(struct bfa_ioim_s *ioim, - struct bfa_tskim_s *tskim); -void bfa_ioim_iocdisable(struct bfa_ioim_s *ioim); -void bfa_ioim_tov(struct bfa_ioim_s *ioim); - -void bfa_tskim_attach(struct bfa_fcpim_mod_s *fcpim, - struct bfa_meminfo_s *minfo); -void bfa_tskim_detach(struct bfa_fcpim_mod_s *fcpim); -void bfa_tskim_isr(struct bfa_s *bfa, struct bfi_msg_s *msg); -void bfa_tskim_iodone(struct bfa_tskim_s *tskim); -void bfa_tskim_iocdisable(struct bfa_tskim_s *tskim); -void bfa_tskim_cleanup(struct bfa_tskim_s *tskim); - -void bfa_itnim_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len, - u32 *dm_len); -void bfa_itnim_attach(struct bfa_fcpim_mod_s *fcpim, - struct bfa_meminfo_s *minfo); -void bfa_itnim_detach(struct bfa_fcpim_mod_s *fcpim); -void bfa_itnim_iocdisable(struct bfa_itnim_s *itnim); -void bfa_itnim_isr(struct bfa_s *bfa, struct bfi_msg_s *msg); -void bfa_itnim_iodone(struct bfa_itnim_s *itnim); -void bfa_itnim_tskdone(struct bfa_itnim_s *itnim); -bfa_boolean_t bfa_itnim_hold_io(struct bfa_itnim_s *itnim); - -#endif /* __BFA_FCPIM_PRIV_H__ */ - diff --git a/drivers/scsi/bfa/bfa_fcport.c b/drivers/scsi/bfa/bfa_fcport.c deleted file mode 100644 index 76867b5577fa..000000000000 --- a/drivers/scsi/bfa/bfa_fcport.c +++ /dev/null @@ -1,1962 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#include <bfa.h> -#include <bfa_svc.h> -#include <bfi/bfi_pport.h> -#include <bfi/bfi_pbc.h> -#include <cs/bfa_debug.h> -#include <aen/bfa_aen.h> -#include <cs/bfa_plog.h> -#include <aen/bfa_aen_port.h> - -BFA_TRC_FILE(HAL, FCPORT); -BFA_MODULE(fcport); - -/* - * The port is considered disabled if corresponding physical port or IOC are - * disabled explicitly - */ -#define BFA_PORT_IS_DISABLED(bfa) \ - ((bfa_fcport_is_disabled(bfa) == BFA_TRUE) || \ - (bfa_ioc_is_disabled(&bfa->ioc) == BFA_TRUE)) - -/* - * forward declarations - */ -static bfa_boolean_t bfa_fcport_send_enable(struct bfa_fcport_s *fcport); -static bfa_boolean_t bfa_fcport_send_disable(struct bfa_fcport_s *fcport); -static void bfa_fcport_update_linkinfo(struct bfa_fcport_s *fcport); -static void bfa_fcport_reset_linkinfo(struct bfa_fcport_s *fcport); -static void bfa_fcport_set_wwns(struct bfa_fcport_s *fcport); -static void __bfa_cb_fcport_event(void *cbarg, bfa_boolean_t complete); -static void bfa_fcport_callback(struct bfa_fcport_s *fcport, - enum bfa_pport_linkstate event); -static void bfa_fcport_queue_cb(struct bfa_fcport_ln_s *ln, - enum bfa_pport_linkstate event); -static void __bfa_cb_fcport_stats_clr(void *cbarg, bfa_boolean_t complete); -static void bfa_fcport_stats_get_timeout(void *cbarg); -static void bfa_fcport_stats_clr_timeout(void *cbarg); - -/** - * bfa_pport_private - */ - -/** - * BFA port state machine events - */ -enum bfa_fcport_sm_event { - BFA_FCPORT_SM_START = 1, /* start port state machine */ - BFA_FCPORT_SM_STOP = 2, /* stop port state machine */ - BFA_FCPORT_SM_ENABLE = 3, /* enable port */ - BFA_FCPORT_SM_DISABLE = 4, /* disable port state machine */ - BFA_FCPORT_SM_FWRSP = 5, /* firmware enable/disable rsp */ - BFA_FCPORT_SM_LINKUP = 6, /* firmware linkup event */ - BFA_FCPORT_SM_LINKDOWN = 7, /* firmware linkup down */ - BFA_FCPORT_SM_QRESUME = 8, /* CQ space available */ - BFA_FCPORT_SM_HWFAIL = 9, /* IOC h/w failure */ -}; - -/** - * BFA port link notification state machine events - */ - -enum bfa_fcport_ln_sm_event { - BFA_FCPORT_LN_SM_LINKUP = 1, /* linkup event */ - BFA_FCPORT_LN_SM_LINKDOWN = 2, /* linkdown event */ - BFA_FCPORT_LN_SM_NOTIFICATION = 3 /* done notification */ -}; - -static void bfa_fcport_sm_uninit(struct bfa_fcport_s *fcport, - enum bfa_fcport_sm_event event); -static void bfa_fcport_sm_enabling_qwait(struct bfa_fcport_s *fcport, - enum bfa_fcport_sm_event event); -static void bfa_fcport_sm_enabling(struct bfa_fcport_s *fcport, - enum bfa_fcport_sm_event event); -static void bfa_fcport_sm_linkdown(struct bfa_fcport_s *fcport, - enum bfa_fcport_sm_event event); -static void bfa_fcport_sm_linkup(struct bfa_fcport_s *fcport, - enum bfa_fcport_sm_event event); -static void bfa_fcport_sm_disabling(struct bfa_fcport_s *fcport, - enum bfa_fcport_sm_event event); -static void bfa_fcport_sm_disabling_qwait(struct bfa_fcport_s *fcport, - enum bfa_fcport_sm_event event); -static void bfa_fcport_sm_disabled(struct bfa_fcport_s *fcport, - enum bfa_fcport_sm_event event); -static void bfa_fcport_sm_stopped(struct bfa_fcport_s *fcport, - enum bfa_fcport_sm_event event); -static void bfa_fcport_sm_iocdown(struct bfa_fcport_s *fcport, - enum bfa_fcport_sm_event event); -static void bfa_fcport_sm_iocfail(struct bfa_fcport_s *fcport, - enum bfa_fcport_sm_event event); - -static void bfa_fcport_ln_sm_dn(struct bfa_fcport_ln_s *ln, - enum bfa_fcport_ln_sm_event event); -static void bfa_fcport_ln_sm_dn_nf(struct bfa_fcport_ln_s *ln, - enum bfa_fcport_ln_sm_event event); -static void bfa_fcport_ln_sm_dn_up_nf(struct bfa_fcport_ln_s *ln, - enum bfa_fcport_ln_sm_event event); -static void bfa_fcport_ln_sm_up(struct bfa_fcport_ln_s *ln, - enum bfa_fcport_ln_sm_event event); -static void bfa_fcport_ln_sm_up_nf(struct bfa_fcport_ln_s *ln, - enum bfa_fcport_ln_sm_event event); -static void bfa_fcport_ln_sm_up_dn_nf(struct bfa_fcport_ln_s *ln, - enum bfa_fcport_ln_sm_event event); -static void bfa_fcport_ln_sm_up_dn_up_nf(struct bfa_fcport_ln_s *ln, - enum bfa_fcport_ln_sm_event event); - -static struct bfa_sm_table_s hal_pport_sm_table[] = { - {BFA_SM(bfa_fcport_sm_uninit), BFA_PPORT_ST_UNINIT}, - {BFA_SM(bfa_fcport_sm_enabling_qwait), BFA_PPORT_ST_ENABLING_QWAIT}, - {BFA_SM(bfa_fcport_sm_enabling), BFA_PPORT_ST_ENABLING}, - {BFA_SM(bfa_fcport_sm_linkdown), BFA_PPORT_ST_LINKDOWN}, - {BFA_SM(bfa_fcport_sm_linkup), BFA_PPORT_ST_LINKUP}, - {BFA_SM(bfa_fcport_sm_disabling_qwait), BFA_PPORT_ST_DISABLING_QWAIT}, - {BFA_SM(bfa_fcport_sm_disabling), BFA_PPORT_ST_DISABLING}, - {BFA_SM(bfa_fcport_sm_disabled), BFA_PPORT_ST_DISABLED}, - {BFA_SM(bfa_fcport_sm_stopped), BFA_PPORT_ST_STOPPED}, - {BFA_SM(bfa_fcport_sm_iocdown), BFA_PPORT_ST_IOCDOWN}, - {BFA_SM(bfa_fcport_sm_iocfail), BFA_PPORT_ST_IOCDOWN}, -}; - -static void -bfa_fcport_aen_post(struct bfa_fcport_s *fcport, enum bfa_port_aen_event event) -{ - union bfa_aen_data_u aen_data; - struct bfa_log_mod_s *logmod = fcport->bfa->logm; - wwn_t pwwn = fcport->pwwn; - char pwwn_ptr[BFA_STRING_32]; - - memset(&aen_data, 0, sizeof(aen_data)); - wwn2str(pwwn_ptr, pwwn); - bfa_log(logmod, BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, event), pwwn_ptr); - - aen_data.port.ioc_type = bfa_get_type(fcport->bfa); - aen_data.port.pwwn = pwwn; -} - -static void -bfa_fcport_sm_uninit(struct bfa_fcport_s *fcport, - enum bfa_fcport_sm_event event) -{ - bfa_trc(fcport->bfa, event); - - switch (event) { - case BFA_FCPORT_SM_START: - /** - * Start event after IOC is configured and BFA is started. - */ - if (bfa_fcport_send_enable(fcport)) - bfa_sm_set_state(fcport, bfa_fcport_sm_enabling); - else - bfa_sm_set_state(fcport, bfa_fcport_sm_enabling_qwait); - break; - - case BFA_FCPORT_SM_ENABLE: - /** - * Port is persistently configured to be in enabled state. Do - * not change state. Port enabling is done when START event is - * received. - */ - break; - - case BFA_FCPORT_SM_DISABLE: - /** - * If a port is persistently configured to be disabled, the - * first event will a port disable request. - */ - bfa_sm_set_state(fcport, bfa_fcport_sm_disabled); - break; - - case BFA_FCPORT_SM_HWFAIL: - bfa_sm_set_state(fcport, bfa_fcport_sm_iocdown); - break; - - default: - bfa_sm_fault(fcport->bfa, event); - } -} - -static void -bfa_fcport_sm_enabling_qwait(struct bfa_fcport_s *fcport, - enum bfa_fcport_sm_event event) -{ - bfa_trc(fcport->bfa, event); - - switch (event) { - case BFA_FCPORT_SM_QRESUME: - bfa_sm_set_state(fcport, bfa_fcport_sm_enabling); - bfa_fcport_send_enable(fcport); - break; - - case BFA_FCPORT_SM_STOP: - bfa_reqq_wcancel(&fcport->reqq_wait); - bfa_sm_set_state(fcport, bfa_fcport_sm_stopped); - break; - - case BFA_FCPORT_SM_ENABLE: - /** - * Already enable is in progress. - */ - break; - - case BFA_FCPORT_SM_DISABLE: - /** - * Just send disable request to firmware when room becomes - * available in request queue. - */ - bfa_sm_set_state(fcport, bfa_fcport_sm_disabled); - bfa_reqq_wcancel(&fcport->reqq_wait); - bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL, - BFA_PL_EID_PORT_DISABLE, 0, "Port Disable"); - bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISABLE); - break; - - case BFA_FCPORT_SM_LINKUP: - case BFA_FCPORT_SM_LINKDOWN: - /** - * Possible to get link events when doing back-to-back - * enable/disables. - */ - break; - - case BFA_FCPORT_SM_HWFAIL: - bfa_reqq_wcancel(&fcport->reqq_wait); - bfa_sm_set_state(fcport, bfa_fcport_sm_iocdown); - break; - - default: - bfa_sm_fault(fcport->bfa, event); - } -} - -static void -bfa_fcport_sm_enabling(struct bfa_fcport_s *fcport, - enum bfa_fcport_sm_event event) -{ - bfa_trc(fcport->bfa, event); - - switch (event) { - case BFA_FCPORT_SM_FWRSP: - case BFA_FCPORT_SM_LINKDOWN: - bfa_sm_set_state(fcport, bfa_fcport_sm_linkdown); - break; - - case BFA_FCPORT_SM_LINKUP: - bfa_fcport_update_linkinfo(fcport); - bfa_sm_set_state(fcport, bfa_fcport_sm_linkup); - - bfa_assert(fcport->event_cbfn); - bfa_fcport_callback(fcport, BFA_PPORT_LINKUP); - break; - - case BFA_FCPORT_SM_ENABLE: - /** - * Already being enabled. - */ - break; - - case BFA_FCPORT_SM_DISABLE: - if (bfa_fcport_send_disable(fcport)) - bfa_sm_set_state(fcport, bfa_fcport_sm_disabling); - else - bfa_sm_set_state(fcport, bfa_fcport_sm_disabling_qwait); - - bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL, - BFA_PL_EID_PORT_DISABLE, 0, "Port Disable"); - bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISABLE); - break; - - case BFA_FCPORT_SM_STOP: - bfa_sm_set_state(fcport, bfa_fcport_sm_stopped); - break; - - case BFA_FCPORT_SM_HWFAIL: - bfa_sm_set_state(fcport, bfa_fcport_sm_iocdown); - break; - - default: - bfa_sm_fault(fcport->bfa, event); - } -} - -static void -bfa_fcport_sm_linkdown(struct bfa_fcport_s *fcport, - enum bfa_fcport_sm_event event) -{ - struct bfi_fcport_event_s *pevent = fcport->event_arg.i2hmsg.event; - bfa_trc(fcport->bfa, event); - - switch (event) { - case BFA_FCPORT_SM_LINKUP: - bfa_fcport_update_linkinfo(fcport); - bfa_sm_set_state(fcport, bfa_fcport_sm_linkup); - bfa_assert(fcport->event_cbfn); - bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL, - BFA_PL_EID_PORT_ST_CHANGE, 0, "Port Linkup"); - - if (!bfa_ioc_get_fcmode(&fcport->bfa->ioc)) { - - 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.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"); - else - bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL, - BFA_PL_EID_FIP_FCF_DISC, 0, - "FIP FCF Discovered"); - } - - bfa_fcport_callback(fcport, BFA_PPORT_LINKUP); - bfa_fcport_aen_post(fcport, BFA_PORT_AEN_ONLINE); - /** - * If QoS is enabled and it is not online, - * Send a separate event. - */ - if ((fcport->cfg.qos_enabled) - && (bfa_os_ntohl(fcport->qos_attr.state) != BFA_QOS_ONLINE)) - bfa_fcport_aen_post(fcport, BFA_PORT_AEN_QOS_NEG); - - break; - - case BFA_FCPORT_SM_LINKDOWN: - /** - * Possible to get link down event. - */ - break; - - case BFA_FCPORT_SM_ENABLE: - /** - * Already enabled. - */ - break; - - case BFA_FCPORT_SM_DISABLE: - if (bfa_fcport_send_disable(fcport)) - bfa_sm_set_state(fcport, bfa_fcport_sm_disabling); - else - bfa_sm_set_state(fcport, bfa_fcport_sm_disabling_qwait); - - bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL, - BFA_PL_EID_PORT_DISABLE, 0, "Port Disable"); - bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISABLE); - break; - - case BFA_FCPORT_SM_STOP: - bfa_sm_set_state(fcport, bfa_fcport_sm_stopped); - break; - - case BFA_FCPORT_SM_HWFAIL: - bfa_sm_set_state(fcport, bfa_fcport_sm_iocdown); - break; - - default: - bfa_sm_fault(fcport->bfa, event); - } -} - -static void -bfa_fcport_sm_linkup(struct bfa_fcport_s *fcport, - enum bfa_fcport_sm_event event) -{ - bfa_trc(fcport->bfa, event); - - switch (event) { - case BFA_FCPORT_SM_ENABLE: - /** - * Already enabled. - */ - break; - - case BFA_FCPORT_SM_DISABLE: - if (bfa_fcport_send_disable(fcport)) - bfa_sm_set_state(fcport, bfa_fcport_sm_disabling); - else - bfa_sm_set_state(fcport, bfa_fcport_sm_disabling_qwait); - - bfa_fcport_reset_linkinfo(fcport); - bfa_fcport_callback(fcport, BFA_PPORT_LINKDOWN); - bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL, - BFA_PL_EID_PORT_DISABLE, 0, "Port Disable"); - bfa_fcport_aen_post(fcport, BFA_PORT_AEN_OFFLINE); - bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISABLE); - break; - - case BFA_FCPORT_SM_LINKDOWN: - bfa_sm_set_state(fcport, bfa_fcport_sm_linkdown); - bfa_fcport_reset_linkinfo(fcport); - bfa_fcport_callback(fcport, BFA_PPORT_LINKDOWN); - bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL, - BFA_PL_EID_PORT_ST_CHANGE, 0, "Port Linkdown"); - if (BFA_PORT_IS_DISABLED(fcport->bfa)) - bfa_fcport_aen_post(fcport, BFA_PORT_AEN_OFFLINE); - else - bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISCONNECT); - break; - - case BFA_FCPORT_SM_STOP: - bfa_sm_set_state(fcport, bfa_fcport_sm_stopped); - bfa_fcport_reset_linkinfo(fcport); - if (BFA_PORT_IS_DISABLED(fcport->bfa)) - bfa_fcport_aen_post(fcport, BFA_PORT_AEN_OFFLINE); - else - bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISCONNECT); - break; - - case BFA_FCPORT_SM_HWFAIL: - bfa_sm_set_state(fcport, bfa_fcport_sm_iocdown); - bfa_fcport_reset_linkinfo(fcport); - bfa_fcport_callback(fcport, BFA_PPORT_LINKDOWN); - if (BFA_PORT_IS_DISABLED(fcport->bfa)) - bfa_fcport_aen_post(fcport, BFA_PORT_AEN_OFFLINE); - else - bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISCONNECT); - break; - - default: - bfa_sm_fault(fcport->bfa, event); - } -} - -static void -bfa_fcport_sm_disabling_qwait(struct bfa_fcport_s *fcport, - enum bfa_fcport_sm_event event) -{ - bfa_trc(fcport->bfa, event); - - switch (event) { - case BFA_FCPORT_SM_QRESUME: - bfa_sm_set_state(fcport, bfa_fcport_sm_disabling); - bfa_fcport_send_disable(fcport); - break; - - case BFA_FCPORT_SM_STOP: - bfa_sm_set_state(fcport, bfa_fcport_sm_stopped); - bfa_reqq_wcancel(&fcport->reqq_wait); - break; - - case BFA_FCPORT_SM_DISABLE: - /** - * Already being disabled. - */ - break; - - case BFA_FCPORT_SM_LINKUP: - case BFA_FCPORT_SM_LINKDOWN: - /** - * Possible to get link events when doing back-to-back - * enable/disables. - */ - break; - - case BFA_FCPORT_SM_HWFAIL: - bfa_sm_set_state(fcport, bfa_fcport_sm_iocfail); - bfa_reqq_wcancel(&fcport->reqq_wait); - break; - - default: - bfa_sm_fault(fcport->bfa, event); - } -} - -static void -bfa_fcport_sm_disabling(struct bfa_fcport_s *fcport, - enum bfa_fcport_sm_event event) -{ - bfa_trc(fcport->bfa, event); - - switch (event) { - case BFA_FCPORT_SM_FWRSP: - bfa_sm_set_state(fcport, bfa_fcport_sm_disabled); - break; - - case BFA_FCPORT_SM_DISABLE: - /** - * Already being disabled. - */ - break; - - case BFA_FCPORT_SM_ENABLE: - if (bfa_fcport_send_enable(fcport)) - bfa_sm_set_state(fcport, bfa_fcport_sm_enabling); - else - bfa_sm_set_state(fcport, bfa_fcport_sm_enabling_qwait); - - bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL, - BFA_PL_EID_PORT_ENABLE, 0, "Port Enable"); - bfa_fcport_aen_post(fcport, BFA_PORT_AEN_ENABLE); - break; - - case BFA_FCPORT_SM_STOP: - bfa_sm_set_state(fcport, bfa_fcport_sm_stopped); - break; - - case BFA_FCPORT_SM_LINKUP: - case BFA_FCPORT_SM_LINKDOWN: - /** - * Possible to get link events when doing back-to-back - * enable/disables. - */ - break; - - case BFA_FCPORT_SM_HWFAIL: - bfa_sm_set_state(fcport, bfa_fcport_sm_iocfail); - break; - - default: - bfa_sm_fault(fcport->bfa, event); - } -} - -static void -bfa_fcport_sm_disabled(struct bfa_fcport_s *fcport, - enum bfa_fcport_sm_event event) -{ - bfa_trc(fcport->bfa, event); - - switch (event) { - case BFA_FCPORT_SM_START: - /** - * Ignore start event for a port that is disabled. - */ - break; - - case BFA_FCPORT_SM_STOP: - bfa_sm_set_state(fcport, bfa_fcport_sm_stopped); - break; - - case BFA_FCPORT_SM_ENABLE: - if (bfa_fcport_send_enable(fcport)) - bfa_sm_set_state(fcport, bfa_fcport_sm_enabling); - else - bfa_sm_set_state(fcport, bfa_fcport_sm_enabling_qwait); - - bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL, - BFA_PL_EID_PORT_ENABLE, 0, "Port Enable"); - bfa_fcport_aen_post(fcport, BFA_PORT_AEN_ENABLE); - break; - - case BFA_FCPORT_SM_DISABLE: - /** - * Already disabled. - */ - break; - - case BFA_FCPORT_SM_HWFAIL: - bfa_sm_set_state(fcport, bfa_fcport_sm_iocfail); - break; - - default: - bfa_sm_fault(fcport->bfa, event); - } -} - -static void -bfa_fcport_sm_stopped(struct bfa_fcport_s *fcport, - enum bfa_fcport_sm_event event) -{ - bfa_trc(fcport->bfa, event); - - switch (event) { - case BFA_FCPORT_SM_START: - if (bfa_fcport_send_enable(fcport)) - bfa_sm_set_state(fcport, bfa_fcport_sm_enabling); - else - bfa_sm_set_state(fcport, bfa_fcport_sm_enabling_qwait); - break; - - default: - /** - * Ignore all other events. - */ - ; - } -} - -/** - * Port is enabled. IOC is down/failed. - */ -static void -bfa_fcport_sm_iocdown(struct bfa_fcport_s *fcport, - enum bfa_fcport_sm_event event) -{ - bfa_trc(fcport->bfa, event); - - switch (event) { - case BFA_FCPORT_SM_START: - if (bfa_fcport_send_enable(fcport)) - bfa_sm_set_state(fcport, bfa_fcport_sm_enabling); - else - bfa_sm_set_state(fcport, bfa_fcport_sm_enabling_qwait); - break; - - default: - /** - * Ignore all events. - */ - ; - } -} - -/** - * Port is disabled. IOC is down/failed. - */ -static void -bfa_fcport_sm_iocfail(struct bfa_fcport_s *fcport, - enum bfa_fcport_sm_event event) -{ - bfa_trc(fcport->bfa, event); - - switch (event) { - case BFA_FCPORT_SM_START: - bfa_sm_set_state(fcport, bfa_fcport_sm_disabled); - break; - - case BFA_FCPORT_SM_ENABLE: - bfa_sm_set_state(fcport, bfa_fcport_sm_iocdown); - break; - - default: - /** - * Ignore all events. - */ - ; - } -} - -/** - * Link state is down - */ -static void -bfa_fcport_ln_sm_dn(struct bfa_fcport_ln_s *ln, - enum bfa_fcport_ln_sm_event event) -{ - bfa_trc(ln->fcport->bfa, event); - - switch (event) { - case BFA_FCPORT_LN_SM_LINKUP: - bfa_sm_set_state(ln, bfa_fcport_ln_sm_up_nf); - bfa_fcport_queue_cb(ln, BFA_PPORT_LINKUP); - break; - - default: - bfa_sm_fault(ln->fcport->bfa, event); - } -} - -/** - * Link state is waiting for down notification - */ -static void -bfa_fcport_ln_sm_dn_nf(struct bfa_fcport_ln_s *ln, - enum bfa_fcport_ln_sm_event event) -{ - bfa_trc(ln->fcport->bfa, event); - - switch (event) { - case BFA_FCPORT_LN_SM_LINKUP: - bfa_sm_set_state(ln, bfa_fcport_ln_sm_dn_up_nf); - break; - - case BFA_FCPORT_LN_SM_NOTIFICATION: - bfa_sm_set_state(ln, bfa_fcport_ln_sm_dn); - break; - - default: - bfa_sm_fault(ln->fcport->bfa, event); - } -} - -/** - * Link state is waiting for down notification and there is a pending up - */ -static void -bfa_fcport_ln_sm_dn_up_nf(struct bfa_fcport_ln_s *ln, - enum bfa_fcport_ln_sm_event event) -{ - bfa_trc(ln->fcport->bfa, event); - - switch (event) { - case BFA_FCPORT_LN_SM_LINKDOWN: - bfa_sm_set_state(ln, bfa_fcport_ln_sm_dn_nf); - break; - - case BFA_FCPORT_LN_SM_NOTIFICATION: - bfa_sm_set_state(ln, bfa_fcport_ln_sm_up_nf); - bfa_fcport_queue_cb(ln, BFA_PPORT_LINKUP); - break; - - default: - bfa_sm_fault(ln->fcport->bfa, event); - } -} - -/** - * Link state is up - */ -static void -bfa_fcport_ln_sm_up(struct bfa_fcport_ln_s *ln, - enum bfa_fcport_ln_sm_event event) -{ - bfa_trc(ln->fcport->bfa, event); - - switch (event) { - case BFA_FCPORT_LN_SM_LINKDOWN: - bfa_sm_set_state(ln, bfa_fcport_ln_sm_dn_nf); - bfa_fcport_queue_cb(ln, BFA_PPORT_LINKDOWN); - break; - - default: - bfa_sm_fault(ln->fcport->bfa, event); - } -} - -/** - * Link state is waiting for up notification - */ -static void -bfa_fcport_ln_sm_up_nf(struct bfa_fcport_ln_s *ln, - enum bfa_fcport_ln_sm_event event) -{ - bfa_trc(ln->fcport->bfa, event); - - switch (event) { - case BFA_FCPORT_LN_SM_LINKDOWN: - bfa_sm_set_state(ln, bfa_fcport_ln_sm_up_dn_nf); - break; - - case BFA_FCPORT_LN_SM_NOTIFICATION: - bfa_sm_set_state(ln, bfa_fcport_ln_sm_up); - break; - - default: - bfa_sm_fault(ln->fcport->bfa, event); - } -} - -/** - * Link state is waiting for up notification and there is a pending down - */ -static void -bfa_fcport_ln_sm_up_dn_nf(struct bfa_fcport_ln_s *ln, - enum bfa_fcport_ln_sm_event event) -{ - bfa_trc(ln->fcport->bfa, event); - - switch (event) { - case BFA_FCPORT_LN_SM_LINKUP: - bfa_sm_set_state(ln, bfa_fcport_ln_sm_up_dn_up_nf); - break; - - case BFA_FCPORT_LN_SM_NOTIFICATION: - bfa_sm_set_state(ln, bfa_fcport_ln_sm_dn_nf); - bfa_fcport_queue_cb(ln, BFA_PPORT_LINKDOWN); - break; - - default: - bfa_sm_fault(ln->fcport->bfa, event); - } -} - -/** - * Link state is waiting for up notification and there are pending down and up - */ -static void -bfa_fcport_ln_sm_up_dn_up_nf(struct bfa_fcport_ln_s *ln, - enum bfa_fcport_ln_sm_event event) -{ - bfa_trc(ln->fcport->bfa, event); - - switch (event) { - case BFA_FCPORT_LN_SM_LINKDOWN: - bfa_sm_set_state(ln, bfa_fcport_ln_sm_up_dn_nf); - break; - - case BFA_FCPORT_LN_SM_NOTIFICATION: - bfa_sm_set_state(ln, bfa_fcport_ln_sm_dn_up_nf); - bfa_fcport_queue_cb(ln, BFA_PPORT_LINKDOWN); - break; - - default: - bfa_sm_fault(ln->fcport->bfa, event); - } -} - -/** - * bfa_pport_private - */ - -static void -__bfa_cb_fcport_event(void *cbarg, bfa_boolean_t complete) -{ - struct bfa_fcport_ln_s *ln = cbarg; - - if (complete) - ln->fcport->event_cbfn(ln->fcport->event_cbarg, ln->ln_event); - else - bfa_sm_send_event(ln, BFA_FCPORT_LN_SM_NOTIFICATION); -} - -static void -bfa_fcport_callback(struct bfa_fcport_s *fcport, enum bfa_pport_linkstate event) -{ - if (fcport->bfa->fcs) { - fcport->event_cbfn(fcport->event_cbarg, event); - return; - } - - switch (event) { - case BFA_PPORT_LINKUP: - bfa_sm_send_event(&fcport->ln, BFA_FCPORT_LN_SM_LINKUP); - break; - case BFA_PPORT_LINKDOWN: - bfa_sm_send_event(&fcport->ln, BFA_FCPORT_LN_SM_LINKDOWN); - break; - default: - bfa_assert(0); - } -} - -static void -bfa_fcport_queue_cb(struct bfa_fcport_ln_s *ln, enum bfa_pport_linkstate event) -{ - ln->ln_event = event; - bfa_cb_queue(ln->fcport->bfa, &ln->ln_qe, __bfa_cb_fcport_event, ln); -} - -#define FCPORT_STATS_DMA_SZ (BFA_ROUNDUP(sizeof(union bfa_fcport_stats_u), \ - BFA_CACHELINE_SZ)) - -static void -bfa_fcport_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len, - u32 *dm_len) -{ - *dm_len += FCPORT_STATS_DMA_SZ; -} - -static void -bfa_fcport_qresume(void *cbarg) -{ - struct bfa_fcport_s *fcport = cbarg; - - bfa_sm_send_event(fcport, BFA_FCPORT_SM_QRESUME); -} - -static void -bfa_fcport_mem_claim(struct bfa_fcport_s *fcport, struct bfa_meminfo_s *meminfo) -{ - u8 *dm_kva; - u64 dm_pa; - - dm_kva = bfa_meminfo_dma_virt(meminfo); - dm_pa = bfa_meminfo_dma_phys(meminfo); - - fcport->stats_kva = dm_kva; - fcport->stats_pa = dm_pa; - fcport->stats = (union bfa_fcport_stats_u *)dm_kva; - - dm_kva += FCPORT_STATS_DMA_SZ; - dm_pa += FCPORT_STATS_DMA_SZ; - - bfa_meminfo_dma_virt(meminfo) = dm_kva; - bfa_meminfo_dma_phys(meminfo) = dm_pa; -} - -/** - * Memory initialization. - */ -static void -bfa_fcport_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, - struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev) -{ - struct bfa_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; - ln->fcport = fcport; - - bfa_fcport_mem_claim(fcport, meminfo); - - 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 - */ - port_cfg->topology = BFA_PPORT_TOPOLOGY_P2P; - port_cfg->speed = BFA_PPORT_SPEED_AUTO; - port_cfg->trunked = BFA_FALSE; - port_cfg->maxfrsize = 0; - - port_cfg->trl_def_speed = BFA_PPORT_SPEED_1GBPS; - - bfa_reqq_winit(&fcport->reqq_wait, bfa_fcport_qresume, fcport); -} - -static void -bfa_fcport_detach(struct bfa_s *bfa) -{ -} - -/** - * Called when IOC is ready. - */ -static void -bfa_fcport_start(struct bfa_s *bfa) -{ - bfa_sm_send_event(BFA_FCPORT_MOD(bfa), BFA_FCPORT_SM_START); -} - -/** - * Called before IOC is stopped. - */ -static void -bfa_fcport_stop(struct bfa_s *bfa) -{ - bfa_sm_send_event(BFA_FCPORT_MOD(bfa), BFA_FCPORT_SM_STOP); -} - -/** - * Called when IOC failure is detected. - */ -static void -bfa_fcport_iocdisable(struct bfa_s *bfa) -{ - bfa_sm_send_event(BFA_FCPORT_MOD(bfa), BFA_FCPORT_SM_HWFAIL); -} - -static void -bfa_fcport_update_linkinfo(struct bfa_fcport_s *fcport) -{ - struct bfi_fcport_event_s *pevent = fcport->event_arg.i2hmsg.event; - - fcport->speed = pevent->link_state.speed; - fcport->topology = pevent->link_state.topology; - - if (fcport->topology == BFA_PPORT_TOPOLOGY_LOOP) - 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.vc_fcf.qos_vc_attr); - - - bfa_trc(fcport->bfa, fcport->speed); - bfa_trc(fcport->bfa, fcport->topology); -} - -static void -bfa_fcport_reset_linkinfo(struct bfa_fcport_s *fcport) -{ - fcport->speed = BFA_PPORT_SPEED_UNKNOWN; - fcport->topology = BFA_PPORT_TOPOLOGY_NONE; -} - -/** - * Send port enable message to firmware. - */ -static bfa_boolean_t -bfa_fcport_send_enable(struct bfa_fcport_s *fcport) -{ - struct bfi_fcport_enable_req_s *m; - - /** - * Increment message tag before queue check, so that responses to old - * requests are discarded. - */ - fcport->msgtag++; - - /** - * check for room in queue to send request now - */ - m = bfa_reqq_next(fcport->bfa, BFA_REQQ_PORT); - if (!m) { - bfa_reqq_wait(fcport->bfa, BFA_REQQ_PORT, - &fcport->reqq_wait); - return BFA_FALSE; - } - - bfi_h2i_set(m->mh, BFI_MC_FCPORT, BFI_FCPORT_H2I_ENABLE_REQ, - bfa_lpuid(fcport->bfa)); - m->nwwn = fcport->nwwn; - m->pwwn = fcport->pwwn; - m->port_cfg = fcport->cfg; - m->msgtag = fcport->msgtag; - m->port_cfg.maxfrsize = bfa_os_htons(fcport->cfg.maxfrsize); - bfa_dma_be_addr_set(m->stats_dma_addr, fcport->stats_pa); - bfa_trc(fcport->bfa, m->stats_dma_addr.a32.addr_lo); - bfa_trc(fcport->bfa, m->stats_dma_addr.a32.addr_hi); - - /** - * queue I/O message to firmware - */ - bfa_reqq_produce(fcport->bfa, BFA_REQQ_PORT); - return BFA_TRUE; -} - -/** - * Send port disable message to firmware. - */ -static bfa_boolean_t -bfa_fcport_send_disable(struct bfa_fcport_s *fcport) -{ - struct bfi_fcport_req_s *m; - - /** - * Increment message tag before queue check, so that responses to old - * requests are discarded. - */ - fcport->msgtag++; - - /** - * check for room in queue to send request now - */ - m = bfa_reqq_next(fcport->bfa, BFA_REQQ_PORT); - if (!m) { - bfa_reqq_wait(fcport->bfa, BFA_REQQ_PORT, - &fcport->reqq_wait); - return BFA_FALSE; - } - - bfi_h2i_set(m->mh, BFI_MC_FCPORT, BFI_FCPORT_H2I_DISABLE_REQ, - bfa_lpuid(fcport->bfa)); - m->msgtag = fcport->msgtag; - - /** - * queue I/O message to firmware - */ - bfa_reqq_produce(fcport->bfa, BFA_REQQ_PORT); - - return BFA_TRUE; -} - -static void -bfa_fcport_set_wwns(struct bfa_fcport_s *fcport) -{ - fcport->pwwn = bfa_ioc_get_pwwn(&fcport->bfa->ioc); - fcport->nwwn = bfa_ioc_get_nwwn(&fcport->bfa->ioc); - - bfa_trc(fcport->bfa, fcport->pwwn); - bfa_trc(fcport->bfa, fcport->nwwn); -} - -static void -bfa_fcport_send_txcredit(void *port_cbarg) -{ - - struct bfa_fcport_s *fcport = port_cbarg; - struct bfi_fcport_set_svc_params_req_s *m; - - /** - * check for room in queue to send request now - */ - m = bfa_reqq_next(fcport->bfa, BFA_REQQ_PORT); - if (!m) { - bfa_trc(fcport->bfa, fcport->cfg.tx_bbcredit); - return; - } - - bfi_h2i_set(m->mh, BFI_MC_FCPORT, BFI_FCPORT_H2I_SET_SVC_PARAMS_REQ, - bfa_lpuid(fcport->bfa)); - m->tx_bbcredit = bfa_os_htons((u16) fcport->cfg.tx_bbcredit); - - /** - * queue I/O message to firmware - */ - bfa_reqq_produce(fcport->bfa, BFA_REQQ_PORT); -} - -static void -bfa_fcport_qos_stats_swap(struct bfa_qos_stats_s *d, - struct bfa_qos_stats_s *s) -{ - u32 *dip = (u32 *) d; - u32 *sip = (u32 *) s; - int i; - - /* Now swap the 32 bit fields */ - for (i = 0; i < (sizeof(struct bfa_qos_stats_s)/sizeof(u32)); ++i) - dip[i] = bfa_os_ntohl(sip[i]); -} - -static void -bfa_fcport_fcoe_stats_swap(struct bfa_fcoe_stats_s *d, - struct bfa_fcoe_stats_s *s) -{ - u32 *dip = (u32 *) d; - u32 *sip = (u32 *) s; - int i; - - for (i = 0; i < ((sizeof(struct bfa_fcoe_stats_s))/sizeof(u32)); - i = i + 2) { -#ifdef __BIGENDIAN - dip[i] = bfa_os_ntohl(sip[i]); - dip[i + 1] = bfa_os_ntohl(sip[i + 1]); -#else - dip[i] = bfa_os_ntohl(sip[i + 1]); - dip[i + 1] = bfa_os_ntohl(sip[i]); -#endif - } -} - -static void -__bfa_cb_fcport_stats_get(void *cbarg, bfa_boolean_t complete) -{ - struct bfa_fcport_s *fcport = cbarg; - - 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)) { - bfa_fcport_qos_stats_swap( - &fcport->stats_ret->fcqos, - &fcport->stats->fcqos); - } 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 { - fcport->stats_busy = BFA_FALSE; - fcport->stats_status = BFA_STATUS_OK; - } -} - -static void -bfa_fcport_stats_get_timeout(void *cbarg) -{ - struct bfa_fcport_s *fcport = (struct bfa_fcport_s *) cbarg; - - bfa_trc(fcport->bfa, fcport->stats_qfull); - - if (fcport->stats_qfull) { - bfa_reqq_wcancel(&fcport->stats_reqq_wait); - fcport->stats_qfull = BFA_FALSE; - } - - fcport->stats_status = BFA_STATUS_ETIMER; - bfa_cb_queue(fcport->bfa, &fcport->hcb_qe, __bfa_cb_fcport_stats_get, - fcport); -} - -static void -bfa_fcport_send_stats_get(void *cbarg) -{ - struct bfa_fcport_s *fcport = (struct bfa_fcport_s *) cbarg; - struct bfi_fcport_req_s *msg; - - msg = bfa_reqq_next(fcport->bfa, BFA_REQQ_PORT); - - if (!msg) { - fcport->stats_qfull = BFA_TRUE; - bfa_reqq_winit(&fcport->stats_reqq_wait, - bfa_fcport_send_stats_get, fcport); - bfa_reqq_wait(fcport->bfa, BFA_REQQ_PORT, - &fcport->stats_reqq_wait); - return; - } - fcport->stats_qfull = BFA_FALSE; - - bfa_os_memset(msg, 0, sizeof(struct bfi_fcport_req_s)); - bfi_h2i_set(msg->mh, BFI_MC_FCPORT, BFI_FCPORT_H2I_STATS_GET_REQ, - bfa_lpuid(fcport->bfa)); - bfa_reqq_produce(fcport->bfa, BFA_REQQ_PORT); -} - -static void -__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; - fcport->stats_status = BFA_STATUS_OK; - } -} - -static void -bfa_fcport_stats_clr_timeout(void *cbarg) -{ - struct bfa_fcport_s *fcport = (struct bfa_fcport_s *) cbarg; - - bfa_trc(fcport->bfa, fcport->stats_qfull); - - if (fcport->stats_qfull) { - bfa_reqq_wcancel(&fcport->stats_reqq_wait); - fcport->stats_qfull = BFA_FALSE; - } - - fcport->stats_status = BFA_STATUS_ETIMER; - bfa_cb_queue(fcport->bfa, &fcport->hcb_qe, - __bfa_cb_fcport_stats_clr, fcport); -} - -static void -bfa_fcport_send_stats_clear(void *cbarg) -{ - struct bfa_fcport_s *fcport = (struct bfa_fcport_s *) cbarg; - struct bfi_fcport_req_s *msg; - - msg = bfa_reqq_next(fcport->bfa, BFA_REQQ_PORT); - - if (!msg) { - fcport->stats_qfull = BFA_TRUE; - bfa_reqq_winit(&fcport->stats_reqq_wait, - bfa_fcport_send_stats_clear, fcport); - bfa_reqq_wait(fcport->bfa, BFA_REQQ_PORT, - &fcport->stats_reqq_wait); - return; - } - fcport->stats_qfull = BFA_FALSE; - - bfa_os_memset(msg, 0, sizeof(struct bfi_fcport_req_s)); - bfi_h2i_set(msg->mh, BFI_MC_FCPORT, BFI_FCPORT_H2I_STATS_CLEAR_REQ, - bfa_lpuid(fcport->bfa)); - bfa_reqq_produce(fcport->bfa, BFA_REQQ_PORT); -} - -/** - * 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. - */ -void -bfa_fcport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - union bfi_fcport_i2h_msg_u i2hmsg; - - i2hmsg.msg = msg; - fcport->event_arg.i2hmsg = i2hmsg; - - switch (msg->mhdr.msg_id) { - case BFI_FCPORT_I2H_ENABLE_RSP: - if (fcport->msgtag == i2hmsg.penable_rsp->msgtag) - bfa_sm_send_event(fcport, BFA_FCPORT_SM_FWRSP); - break; - - case BFI_FCPORT_I2H_DISABLE_RSP: - if (fcport->msgtag == i2hmsg.pdisable_rsp->msgtag) - bfa_sm_send_event(fcport, BFA_FCPORT_SM_FWRSP); - break; - - case BFI_FCPORT_I2H_EVENT: - switch (i2hmsg.event->link_state.linkstate) { - case BFA_PPORT_LINKUP: - bfa_sm_send_event(fcport, BFA_FCPORT_SM_LINKUP); - break; - case BFA_PPORT_LINKDOWN: - bfa_sm_send_event(fcport, BFA_FCPORT_SM_LINKDOWN); - break; - case BFA_PPORT_TRUNK_LINKDOWN: - /** todo: event notification */ - break; - } - break; - - case BFI_FCPORT_I2H_STATS_GET_RSP: - /* - * check for timer pop before processing the rsp - */ - if (fcport->stats_busy == BFA_FALSE || - fcport->stats_status == BFA_STATUS_ETIMER) - break; - - bfa_timer_stop(&fcport->timer); - fcport->stats_status = i2hmsg.pstatsget_rsp->status; - bfa_cb_queue(fcport->bfa, &fcport->hcb_qe, - __bfa_cb_fcport_stats_get, fcport); - break; - - case BFI_FCPORT_I2H_STATS_CLEAR_RSP: - /* - * check for timer pop before processing the rsp - */ - if (fcport->stats_busy == BFA_FALSE || - fcport->stats_status == BFA_STATUS_ETIMER) - break; - - bfa_timer_stop(&fcport->timer); - fcport->stats_status = BFA_STATUS_OK; - bfa_cb_queue(fcport->bfa, &fcport->hcb_qe, - __bfa_cb_fcport_stats_clr, fcport); - break; - - default: - bfa_assert(0); - break; - } -} - -/** - * bfa_pport_api - */ - -/** - * Registered callback for port events. - */ -void -bfa_fcport_event_register(struct bfa_s *bfa, - void (*cbfn) (void *cbarg, bfa_pport_event_t event), - void *cbarg) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - fcport->event_cbfn = cbfn; - fcport->event_cbarg = cbarg; -} - -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 (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 - (BFA_FCPORT_MOD(bfa), bfa_fcport_sm_disabling_qwait)) - return BFA_STATUS_DEVBUSY; - - bfa_sm_send_event(BFA_FCPORT_MOD(bfa), BFA_FCPORT_SM_ENABLE); - return BFA_STATUS_OK; -} - -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; -} - -/** - * Configure port speed. - */ -bfa_status_t -bfa_fcport_cfg_speed(struct bfa_s *bfa, enum bfa_pport_speed speed) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - bfa_trc(bfa, speed); - - if ((speed != BFA_PPORT_SPEED_AUTO) && (speed > fcport->speed_sup)) { - bfa_trc(bfa, fcport->speed_sup); - return BFA_STATUS_UNSUPP_SPEED; - } - - fcport->cfg.speed = speed; - - return BFA_STATUS_OK; -} - -/** - * Get current speed. - */ -enum bfa_pport_speed -bfa_fcport_get_speed(struct bfa_s *bfa) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - return fcport->speed; -} - -/** - * Configure port topology. - */ -bfa_status_t -bfa_fcport_cfg_topology(struct bfa_s *bfa, enum bfa_pport_topology topology) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - bfa_trc(bfa, topology); - bfa_trc(bfa, fcport->cfg.topology); - - switch (topology) { - case BFA_PPORT_TOPOLOGY_P2P: - case BFA_PPORT_TOPOLOGY_LOOP: - case BFA_PPORT_TOPOLOGY_AUTO: - break; - - default: - return BFA_STATUS_EINVAL; - } - - fcport->cfg.topology = topology; - return BFA_STATUS_OK; -} - -/** - * Get current topology. - */ -enum bfa_pport_topology -bfa_fcport_get_topology(struct bfa_s *bfa) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - return fcport->topology; -} - -bfa_status_t -bfa_fcport_cfg_hardalpa(struct bfa_s *bfa, u8 alpa) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - bfa_trc(bfa, alpa); - bfa_trc(bfa, fcport->cfg.cfg_hardalpa); - bfa_trc(bfa, fcport->cfg.hardalpa); - - fcport->cfg.cfg_hardalpa = BFA_TRUE; - fcport->cfg.hardalpa = alpa; - - return BFA_STATUS_OK; -} - -bfa_status_t -bfa_fcport_clr_hardalpa(struct bfa_s *bfa) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - bfa_trc(bfa, fcport->cfg.cfg_hardalpa); - bfa_trc(bfa, fcport->cfg.hardalpa); - - fcport->cfg.cfg_hardalpa = BFA_FALSE; - return BFA_STATUS_OK; -} - -bfa_boolean_t -bfa_fcport_get_hardalpa(struct bfa_s *bfa, u8 *alpa) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - *alpa = fcport->cfg.hardalpa; - return fcport->cfg.cfg_hardalpa; -} - -u8 -bfa_fcport_get_myalpa(struct bfa_s *bfa) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - return fcport->myalpa; -} - -bfa_status_t -bfa_fcport_cfg_maxfrsize(struct bfa_s *bfa, u16 maxfrsize) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - bfa_trc(bfa, maxfrsize); - bfa_trc(bfa, fcport->cfg.maxfrsize); - - /* - * with in range - */ - if ((maxfrsize > FC_MAX_PDUSZ) || (maxfrsize < FC_MIN_PDUSZ)) - return BFA_STATUS_INVLD_DFSZ; - - /* - * power of 2, if not the max frame size of 2112 - */ - if ((maxfrsize != FC_MAX_PDUSZ) && (maxfrsize & (maxfrsize - 1))) - return BFA_STATUS_INVLD_DFSZ; - - fcport->cfg.maxfrsize = maxfrsize; - return BFA_STATUS_OK; -} - -u16 -bfa_fcport_get_maxfrsize(struct bfa_s *bfa) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - return fcport->cfg.maxfrsize; -} - -u32 -bfa_fcport_mypid(struct bfa_s *bfa) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - return fcport->mypid; -} - -u8 -bfa_fcport_get_rx_bbcredit(struct bfa_s *bfa) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - return fcport->cfg.rx_bbcredit; -} - -void -bfa_fcport_set_tx_bbcredit(struct bfa_s *bfa, u16 tx_bbcredit) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - fcport->cfg.tx_bbcredit = (u8) tx_bbcredit; - bfa_fcport_send_txcredit(fcport); -} - -/** - * Get port attributes. - */ - -wwn_t -bfa_fcport_get_wwn(struct bfa_s *bfa, bfa_boolean_t node) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - if (node) - return fcport->nwwn; - else - return fcport->pwwn; -} - -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)); - - 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)); - /* - * speed attributes - */ - attr->pport_cfg.speed = fcport->cfg.speed; - attr->speed_supported = fcport->speed_sup; - attr->speed = fcport->speed; - attr->cos_supported = FC_CLASS_3; - - /* - * topology attributes - */ - attr->pport_cfg.topology = fcport->cfg.topology; - attr->topology = fcport->topology; - - /* - * beacon attributes - */ - attr->beacon = fcport->beacon; - attr->link_e2e_beacon = fcport->link_e2e_beacon; - attr->plog_enabled = bfa_plog_get_setting(fcport->bfa->plog); - - attr->pport_cfg.path_tov = bfa_fcpim_path_tov_get(bfa); - attr->pport_cfg.q_depth = bfa_fcpim_qdepth_get(bfa); - - /* 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 - -/** - * Fetch port attributes (FCQoS or FCoE). - */ -bfa_status_t -bfa_fcport_get_stats(struct bfa_s *bfa, union bfa_fcport_stats_u *stats, - bfa_cb_pport_t cbfn, void *cbarg) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - if (fcport->stats_busy) { - bfa_trc(bfa, fcport->stats_busy); - return BFA_STATUS_DEVBUSY; - } - - fcport->stats_busy = BFA_TRUE; - fcport->stats_ret = stats; - fcport->stats_cbfn = cbfn; - fcport->stats_cbarg = cbarg; - - bfa_fcport_send_stats_get(fcport); - - bfa_timer_start(bfa, &fcport->timer, bfa_fcport_stats_get_timeout, - fcport, BFA_FCPORT_STATS_TOV); - return BFA_STATUS_OK; -} - -/** - * Reset port statistics (FCQoS or FCoE). - */ -bfa_status_t -bfa_fcport_clear_stats(struct bfa_s *bfa, bfa_cb_pport_t cbfn, void *cbarg) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - if (fcport->stats_busy) { - bfa_trc(bfa, fcport->stats_busy); - return BFA_STATUS_DEVBUSY; - } - - fcport->stats_busy = BFA_TRUE; - fcport->stats_cbfn = cbfn; - fcport->stats_cbarg = cbarg; - - bfa_fcport_send_stats_clear(fcport); - - bfa_timer_start(bfa, &fcport->timer, bfa_fcport_stats_clr_timeout, - fcport, BFA_FCPORT_STATS_TOV); - return BFA_STATUS_OK; -} - -/** - * Fetch FCQoS port statistics - */ -bfa_status_t -bfa_fcport_get_qos_stats(struct bfa_s *bfa, union bfa_fcport_stats_u *stats, - bfa_cb_pport_t cbfn, void *cbarg) -{ - /* Meaningful only for FC mode */ - bfa_assert(bfa_ioc_get_fcmode(&bfa->ioc)); - - return bfa_fcport_get_stats(bfa, stats, cbfn, cbarg); -} - -/** - * Reset FCoE port statistics - */ -bfa_status_t -bfa_fcport_clear_qos_stats(struct bfa_s *bfa, bfa_cb_pport_t cbfn, void *cbarg) -{ - /* Meaningful only for FC mode */ - bfa_assert(bfa_ioc_get_fcmode(&bfa->ioc)); - - return bfa_fcport_clear_stats(bfa, cbfn, cbarg); -} - -/** - * Fetch FCQoS port statistics - */ -bfa_status_t -bfa_fcport_get_fcoe_stats(struct bfa_s *bfa, union bfa_fcport_stats_u *stats, - bfa_cb_pport_t cbfn, void *cbarg) -{ - /* Meaningful only for FCoE mode */ - bfa_assert(!bfa_ioc_get_fcmode(&bfa->ioc)); - - return bfa_fcport_get_stats(bfa, stats, cbfn, cbarg); -} - -/** - * Reset FCoE port statistics - */ -bfa_status_t -bfa_fcport_clear_fcoe_stats(struct bfa_s *bfa, bfa_cb_pport_t cbfn, void *cbarg) -{ - /* Meaningful only for FCoE mode */ - bfa_assert(!bfa_ioc_get_fcmode(&bfa->ioc)); - - return bfa_fcport_clear_stats(bfa, cbfn, cbarg); -} - -bfa_status_t -bfa_fcport_trunk_enable(struct bfa_s *bfa, u8 bitmap) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - bfa_trc(bfa, bitmap); - bfa_trc(bfa, fcport->cfg.trunked); - bfa_trc(bfa, fcport->cfg.trunk_ports); - - if (!bitmap || (bitmap & (bitmap - 1))) - return BFA_STATUS_EINVAL; - - fcport->cfg.trunked = BFA_TRUE; - fcport->cfg.trunk_ports = bitmap; - - return BFA_STATUS_OK; -} - -void -bfa_fcport_qos_get_attr(struct bfa_s *bfa, struct bfa_qos_attr_s *qos_attr) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - qos_attr->state = bfa_os_ntohl(fcport->qos_attr.state); - qos_attr->total_bb_cr = bfa_os_ntohl(fcport->qos_attr.total_bb_cr); -} - -void -bfa_fcport_qos_get_vc_attr(struct bfa_s *bfa, - struct bfa_qos_vc_attr_s *qos_vc_attr) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - struct bfa_qos_vc_attr_s *bfa_vc_attr = &fcport->qos_vc_attr; - u32 i = 0; - - qos_vc_attr->total_vc_count = bfa_os_ntohs(bfa_vc_attr->total_vc_count); - qos_vc_attr->shared_credit = bfa_os_ntohs(bfa_vc_attr->shared_credit); - qos_vc_attr->elp_opmode_flags = - bfa_os_ntohl(bfa_vc_attr->elp_opmode_flags); - - /* - * Individual VC info - */ - while (i < qos_vc_attr->total_vc_count) { - qos_vc_attr->vc_info[i].vc_credit = - bfa_vc_attr->vc_info[i].vc_credit; - qos_vc_attr->vc_info[i].borrow_credit = - bfa_vc_attr->vc_info[i].borrow_credit; - qos_vc_attr->vc_info[i].priority = - bfa_vc_attr->vc_info[i].priority; - ++i; - } -} - -/** - * Fetch port attributes. - */ -bfa_status_t -bfa_fcport_trunk_disable(struct bfa_s *bfa) -{ - return BFA_STATUS_OK; -} - -bfa_boolean_t -bfa_fcport_trunk_query(struct bfa_s *bfa, u32 *bitmap) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - *bitmap = fcport->cfg.trunk_ports; - return fcport->cfg.trunked; -} - -bfa_boolean_t -bfa_fcport_is_disabled(struct bfa_s *bfa) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - return bfa_sm_to_state(hal_pport_sm_table, fcport->sm) == - BFA_PPORT_ST_DISABLED; - -} - -bfa_boolean_t -bfa_fcport_is_ratelim(struct bfa_s *bfa) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - return fcport->cfg.ratelimit ? BFA_TRUE : BFA_FALSE; - -} - -void -bfa_fcport_cfg_qos(struct bfa_s *bfa, bfa_boolean_t on_off) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - enum bfa_ioc_type_e ioc_type = bfa_get_type(bfa); - - bfa_trc(bfa, on_off); - bfa_trc(bfa, fcport->cfg.qos_enabled); - - bfa_trc(bfa, ioc_type); - - 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 -bfa_fcport_cfg_ratelim(struct bfa_s *bfa, bfa_boolean_t on_off) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - bfa_trc(bfa, on_off); - bfa_trc(bfa, fcport->cfg.ratelimit); - - fcport->cfg.ratelimit = on_off; - if (fcport->cfg.trl_def_speed == BFA_PPORT_SPEED_UNKNOWN) - fcport->cfg.trl_def_speed = BFA_PPORT_SPEED_1GBPS; -} - -/** - * Configure default minimum ratelim speed - */ -bfa_status_t -bfa_fcport_cfg_ratelim_speed(struct bfa_s *bfa, enum bfa_pport_speed speed) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - bfa_trc(bfa, speed); - - /* - * Auto and speeds greater than the supported speed, are invalid - */ - if ((speed == BFA_PPORT_SPEED_AUTO) || (speed > fcport->speed_sup)) { - bfa_trc(bfa, fcport->speed_sup); - return BFA_STATUS_UNSUPP_SPEED; - } - - fcport->cfg.trl_def_speed = speed; - - return BFA_STATUS_OK; -} - -/** - * Get default minimum ratelim speed - */ -enum bfa_pport_speed -bfa_fcport_get_ratelim_speed(struct bfa_s *bfa) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - bfa_trc(bfa, fcport->cfg.trl_def_speed); - return fcport->cfg.trl_def_speed; - -} - -void -bfa_fcport_busy(struct bfa_s *bfa, bfa_boolean_t status) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - bfa_trc(bfa, status); - bfa_trc(bfa, fcport->diag_busy); - - fcport->diag_busy = status; -} - -void -bfa_fcport_beacon(struct bfa_s *bfa, bfa_boolean_t beacon, - bfa_boolean_t link_e2e_beacon) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - bfa_trc(bfa, beacon); - bfa_trc(bfa, link_e2e_beacon); - bfa_trc(bfa, fcport->beacon); - bfa_trc(bfa, fcport->link_e2e_beacon); - - fcport->beacon = beacon; - fcport->link_e2e_beacon = link_e2e_beacon; -} - -bfa_boolean_t -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_fcs.c b/drivers/scsi/bfa/bfa_fcs.c index d1a99209bf5f..9cebbe30a678 100644 --- a/drivers/scsi/bfa/bfa_fcs.c +++ b/drivers/scsi/bfa/bfa_fcs.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. * All rights reserved * www.brocade.com * @@ -19,35 +19,28 @@ * bfa_fcs.c BFA FCS main */ -#include <fcs/bfa_fcs.h> -#include "fcs_port.h" -#include "fcs_uf.h" -#include "fcs_vport.h" -#include "fcs_rport.h" -#include "fcs_fabric.h" -#include "fcs_fcpim.h" -#include "fcs_fcptm.h" -#include "fcbuild.h" -#include "fcs.h" +#include "bfa_fcs.h" +#include "bfa_fcbuild.h" #include "bfad_drv.h" -#include <fcb/bfa_fcb.h> + +BFA_TRC_FILE(FCS, FCS); /** * FCS sub-modules */ struct bfa_fcs_mod_s { void (*attach) (struct bfa_fcs_s *fcs); - void (*modinit) (struct bfa_fcs_s *fcs); - void (*modexit) (struct bfa_fcs_s *fcs); + void (*modinit) (struct bfa_fcs_s *fcs); + void (*modexit) (struct bfa_fcs_s *fcs); }; #define BFA_FCS_MODULE(_mod) { _mod ## _modinit, _mod ## _modexit } static struct bfa_fcs_mod_s fcs_modules[] = { - { bfa_fcs_pport_attach, NULL, NULL }, + { bfa_fcs_port_attach, NULL, NULL }, { bfa_fcs_uf_attach, NULL, NULL }, { bfa_fcs_fabric_attach, bfa_fcs_fabric_modinit, - bfa_fcs_fabric_modexit }, + bfa_fcs_fabric_modexit }, }; /** @@ -57,8 +50,8 @@ static struct bfa_fcs_mod_s fcs_modules[] = { static void bfa_fcs_exit_comp(void *fcs_cbarg) { - struct bfa_fcs_s *fcs = fcs_cbarg; - struct bfad_s *bfad = fcs->bfad; + struct bfa_fcs_s *fcs = fcs_cbarg; + struct bfad_s *bfad = fcs->bfad; complete(&bfad->comp); } @@ -74,9 +67,9 @@ bfa_fcs_exit_comp(void *fcs_cbarg) */ void bfa_fcs_attach(struct bfa_fcs_s *fcs, struct bfa_s *bfa, struct bfad_s *bfad, - bfa_boolean_t min_cfg) + bfa_boolean_t min_cfg) { - int i; + int i; struct bfa_fcs_mod_s *mod; fcs->bfa = bfa; @@ -86,7 +79,7 @@ bfa_fcs_attach(struct bfa_fcs_s *fcs, struct bfa_s *bfa, struct bfad_s *bfad, bfa_attach_fcs(bfa); fcbuild_init(); - for (i = 0; i < ARRAY_SIZE(fcs_modules); i++) { + for (i = 0; i < sizeof(fcs_modules) / sizeof(fcs_modules[0]); i++) { mod = &fcs_modules[i]; if (mod->attach) mod->attach(fcs); @@ -99,11 +92,11 @@ 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, npbc_vports; + 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 < ARRAY_SIZE(fcs_modules); i++) { + for (i = 0; i < sizeof(fcs_modules) / sizeof(fcs_modules[0]); i++) { mod = &fcs_modules[i]; if (mod->modinit) mod->modinit(fcs); @@ -111,7 +104,7 @@ bfa_fcs_init(struct bfa_fcs_s *fcs) /* Initialize pbc vports */ if (!fcs->min_cfg) { npbc_vports = - bfa_iocfc_get_pbc_vports(fcs->bfa, pbc_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]); } @@ -127,12 +120,13 @@ bfa_fcs_start(struct bfa_fcs_s *fcs) } /** - * FCS driver details initialization. + * brief + * FCS driver details initialization. * - * param[in] fcs FCS instance - * param[in] driver_info Driver Details + * param[in] fcs FCS instance + * param[in] driver_info Driver Details * - * return None + * return None */ void bfa_fcs_driver_info_init(struct bfa_fcs_s *fcs, @@ -145,13 +139,13 @@ bfa_fcs_driver_info_init(struct bfa_fcs_s *fcs, } /** - * @brief - * FCS FDMI Driver Parameter Initialization + * brief + * FCS FDMI Driver Parameter Initialization * - * @param[in] fcs FCS instance - * @param[in] fdmi_enable TRUE/FALSE + * param[in] fcs FCS instance + * param[in] fdmi_enable TRUE/FALSE * - * @return None + * return None */ void bfa_fcs_set_fdmi_param(struct bfa_fcs_s *fcs, bfa_boolean_t fdmi_enable) @@ -160,22 +154,24 @@ bfa_fcs_set_fdmi_param(struct bfa_fcs_s *fcs, bfa_boolean_t fdmi_enable) fcs->fdmi_enabled = fdmi_enable; } - /** - * FCS instance cleanup and exit. + * brief + * FCS instance cleanup and exit. * - * param[in] fcs FCS instance - * return None + * param[in] fcs FCS instance + * return None */ void bfa_fcs_exit(struct bfa_fcs_s *fcs) { struct bfa_fcs_mod_s *mod; - int i; + int nmods, i; bfa_wc_init(&fcs->wc, bfa_fcs_exit_comp, fcs); - for (i = 0; i < ARRAY_SIZE(fcs_modules); i++) { + nmods = sizeof(fcs_modules) / sizeof(fcs_modules[0]); + + for (i = 0; i < nmods; i++) { mod = &fcs_modules[i]; if (mod->modexit) { @@ -194,24 +190,1547 @@ bfa_fcs_trc_init(struct bfa_fcs_s *fcs, struct bfa_trc_mod_s *trcmod) fcs->trcmod = trcmod; } +void +bfa_fcs_modexit_comp(struct bfa_fcs_s *fcs) +{ + bfa_wc_down(&fcs->wc); +} + +/** + * Fabric module implementation. + */ + +#define BFA_FCS_FABRIC_RETRY_DELAY (2000) /* Milliseconds */ +#define BFA_FCS_FABRIC_CLEANUP_DELAY (10000) /* Milliseconds */ + +#define bfa_fcs_fabric_set_opertype(__fabric) do { \ + if (bfa_fcport_get_topology((__fabric)->fcs->bfa) \ + == BFA_PORT_TOPOLOGY_P2P) \ + (__fabric)->oper_type = BFA_PORT_TYPE_NPORT; \ + else \ + (__fabric)->oper_type = BFA_PORT_TYPE_NLPORT; \ +} while (0) + +/* + * forward declarations + */ +static void bfa_fcs_fabric_init(struct bfa_fcs_fabric_s *fabric); +static void bfa_fcs_fabric_login(struct bfa_fcs_fabric_s *fabric); +static void bfa_fcs_fabric_notify_online(struct bfa_fcs_fabric_s *fabric); +static void bfa_fcs_fabric_notify_offline(struct bfa_fcs_fabric_s *fabric); +static void bfa_fcs_fabric_delay(void *cbarg); +static void bfa_fcs_fabric_delete(struct bfa_fcs_fabric_s *fabric); +static void bfa_fcs_fabric_delete_comp(void *cbarg); +static void bfa_fcs_fabric_process_uf(struct bfa_fcs_fabric_s *fabric, + struct fchs_s *fchs, u16 len); +static void bfa_fcs_fabric_process_flogi(struct bfa_fcs_fabric_s *fabric, + struct fchs_s *fchs, u16 len); +static void bfa_fcs_fabric_send_flogi_acc(struct bfa_fcs_fabric_s *fabric); +static void bfa_fcs_fabric_flogiacc_comp(void *fcsarg, + struct bfa_fcxp_s *fcxp, void *cbarg, + bfa_status_t status, + u32 rsp_len, + u32 resid_len, + struct fchs_s *rspfchs); +/** + * fcs_fabric_sm fabric state machine functions + */ + +/** + * Fabric state machine events + */ +enum bfa_fcs_fabric_event { + BFA_FCS_FABRIC_SM_CREATE = 1, /* create from driver */ + BFA_FCS_FABRIC_SM_DELETE = 2, /* delete from driver */ + BFA_FCS_FABRIC_SM_LINK_DOWN = 3, /* link down from port */ + BFA_FCS_FABRIC_SM_LINK_UP = 4, /* link up from port */ + BFA_FCS_FABRIC_SM_CONT_OP = 5, /* flogi/auth continue op */ + BFA_FCS_FABRIC_SM_RETRY_OP = 6, /* flogi/auth retry op */ + BFA_FCS_FABRIC_SM_NO_FABRIC = 7, /* from flogi/auth */ + BFA_FCS_FABRIC_SM_PERF_EVFP = 8, /* from flogi/auth */ + BFA_FCS_FABRIC_SM_ISOLATE = 9, /* from EVFP processing */ + BFA_FCS_FABRIC_SM_NO_TAGGING = 10, /* no VFT tagging from EVFP */ + BFA_FCS_FABRIC_SM_DELAYED = 11, /* timeout delay event */ + BFA_FCS_FABRIC_SM_AUTH_FAILED = 12, /* auth failed */ + BFA_FCS_FABRIC_SM_AUTH_SUCCESS = 13, /* auth successful */ + BFA_FCS_FABRIC_SM_DELCOMP = 14, /* all vports deleted event */ + BFA_FCS_FABRIC_SM_LOOPBACK = 15, /* Received our own FLOGI */ + BFA_FCS_FABRIC_SM_START = 16, /* from driver */ +}; + +static void bfa_fcs_fabric_sm_uninit(struct bfa_fcs_fabric_s *fabric, + enum bfa_fcs_fabric_event event); +static void bfa_fcs_fabric_sm_created(struct bfa_fcs_fabric_s *fabric, + enum bfa_fcs_fabric_event event); +static void bfa_fcs_fabric_sm_linkdown(struct bfa_fcs_fabric_s *fabric, + enum bfa_fcs_fabric_event event); +static void bfa_fcs_fabric_sm_flogi(struct bfa_fcs_fabric_s *fabric, + enum bfa_fcs_fabric_event event); +static void bfa_fcs_fabric_sm_flogi_retry(struct bfa_fcs_fabric_s *fabric, + enum bfa_fcs_fabric_event event); +static void bfa_fcs_fabric_sm_auth(struct bfa_fcs_fabric_s *fabric, + enum bfa_fcs_fabric_event event); +static void bfa_fcs_fabric_sm_auth_failed(struct bfa_fcs_fabric_s *fabric, + enum bfa_fcs_fabric_event event); +static void bfa_fcs_fabric_sm_loopback(struct bfa_fcs_fabric_s *fabric, + enum bfa_fcs_fabric_event event); +static void bfa_fcs_fabric_sm_nofabric(struct bfa_fcs_fabric_s *fabric, + enum bfa_fcs_fabric_event event); +static void bfa_fcs_fabric_sm_online(struct bfa_fcs_fabric_s *fabric, + enum bfa_fcs_fabric_event event); +static void bfa_fcs_fabric_sm_evfp(struct bfa_fcs_fabric_s *fabric, + enum bfa_fcs_fabric_event event); +static void bfa_fcs_fabric_sm_evfp_done(struct bfa_fcs_fabric_s *fabric, + enum bfa_fcs_fabric_event event); +static void bfa_fcs_fabric_sm_isolated(struct bfa_fcs_fabric_s *fabric, + enum bfa_fcs_fabric_event event); +static void bfa_fcs_fabric_sm_deleting(struct bfa_fcs_fabric_s *fabric, + enum bfa_fcs_fabric_event event); +/** + * Beginning state before fabric creation. + */ +static void +bfa_fcs_fabric_sm_uninit(struct bfa_fcs_fabric_s *fabric, + enum bfa_fcs_fabric_event event) +{ + bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); + bfa_trc(fabric->fcs, event); + + switch (event) { + case BFA_FCS_FABRIC_SM_CREATE: + bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_created); + bfa_fcs_fabric_init(fabric); + bfa_fcs_lport_init(&fabric->bport, &fabric->bport.port_cfg); + break; + + case BFA_FCS_FABRIC_SM_LINK_UP: + case BFA_FCS_FABRIC_SM_LINK_DOWN: + break; + + default: + bfa_sm_fault(fabric->fcs, event); + } +} + +/** + * Beginning state before fabric creation. + */ +static void +bfa_fcs_fabric_sm_created(struct bfa_fcs_fabric_s *fabric, + enum bfa_fcs_fabric_event event) +{ + bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); + bfa_trc(fabric->fcs, event); + + switch (event) { + case BFA_FCS_FABRIC_SM_START: + if (bfa_fcport_is_linkup(fabric->fcs->bfa)) { + bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_flogi); + bfa_fcs_fabric_login(fabric); + } else + bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown); + break; + + case BFA_FCS_FABRIC_SM_LINK_UP: + case BFA_FCS_FABRIC_SM_LINK_DOWN: + break; + + case BFA_FCS_FABRIC_SM_DELETE: + bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_uninit); + bfa_fcs_modexit_comp(fabric->fcs); + break; + + default: + bfa_sm_fault(fabric->fcs, event); + } +} + +/** + * Link is down, awaiting LINK UP event from port. This is also the + * first state at fabric creation. + */ +static void +bfa_fcs_fabric_sm_linkdown(struct bfa_fcs_fabric_s *fabric, + enum bfa_fcs_fabric_event event) +{ + bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); + bfa_trc(fabric->fcs, event); + + switch (event) { + case BFA_FCS_FABRIC_SM_LINK_UP: + bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_flogi); + bfa_fcs_fabric_login(fabric); + break; + + case BFA_FCS_FABRIC_SM_RETRY_OP: + break; + + case BFA_FCS_FABRIC_SM_DELETE: + bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting); + bfa_fcs_fabric_delete(fabric); + break; + + default: + bfa_sm_fault(fabric->fcs, event); + } +} + +/** + * FLOGI is in progress, awaiting FLOGI reply. + */ +static void +bfa_fcs_fabric_sm_flogi(struct bfa_fcs_fabric_s *fabric, + enum bfa_fcs_fabric_event event) +{ + bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); + bfa_trc(fabric->fcs, event); + + switch (event) { + case BFA_FCS_FABRIC_SM_CONT_OP: + + bfa_fcport_set_tx_bbcredit(fabric->fcs->bfa, + fabric->bb_credit); + fabric->fab_type = BFA_FCS_FABRIC_SWITCHED; + + if (fabric->auth_reqd && fabric->is_auth) { + bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_auth); + bfa_trc(fabric->fcs, event); + } else { + bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_online); + bfa_fcs_fabric_notify_online(fabric); + } + break; + + case BFA_FCS_FABRIC_SM_RETRY_OP: + bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_flogi_retry); + bfa_timer_start(fabric->fcs->bfa, &fabric->delay_timer, + bfa_fcs_fabric_delay, fabric, + BFA_FCS_FABRIC_RETRY_DELAY); + break; + + case BFA_FCS_FABRIC_SM_LOOPBACK: + bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_loopback); + bfa_lps_discard(fabric->lps); + bfa_fcs_fabric_set_opertype(fabric); + break; + + case BFA_FCS_FABRIC_SM_NO_FABRIC: + fabric->fab_type = BFA_FCS_FABRIC_N2N; + bfa_fcport_set_tx_bbcredit(fabric->fcs->bfa, + fabric->bb_credit); + bfa_fcs_fabric_notify_online(fabric); + bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_nofabric); + break; + + case BFA_FCS_FABRIC_SM_LINK_DOWN: + bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown); + bfa_lps_discard(fabric->lps); + break; + + case BFA_FCS_FABRIC_SM_DELETE: + bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting); + bfa_lps_discard(fabric->lps); + bfa_fcs_fabric_delete(fabric); + break; + + default: + bfa_sm_fault(fabric->fcs, event); + } +} + + +static void +bfa_fcs_fabric_sm_flogi_retry(struct bfa_fcs_fabric_s *fabric, + enum bfa_fcs_fabric_event event) +{ + bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); + bfa_trc(fabric->fcs, event); + + switch (event) { + case BFA_FCS_FABRIC_SM_DELAYED: + bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_flogi); + bfa_fcs_fabric_login(fabric); + break; + + case BFA_FCS_FABRIC_SM_LINK_DOWN: + bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown); + bfa_timer_stop(&fabric->delay_timer); + break; + + case BFA_FCS_FABRIC_SM_DELETE: + bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting); + bfa_timer_stop(&fabric->delay_timer); + bfa_fcs_fabric_delete(fabric); + break; + + default: + bfa_sm_fault(fabric->fcs, event); + } +} + +/** + * Authentication is in progress, awaiting authentication results. + */ +static void +bfa_fcs_fabric_sm_auth(struct bfa_fcs_fabric_s *fabric, + enum bfa_fcs_fabric_event event) +{ + bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); + bfa_trc(fabric->fcs, event); + + switch (event) { + case BFA_FCS_FABRIC_SM_AUTH_FAILED: + bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_auth_failed); + bfa_lps_discard(fabric->lps); + break; + + case BFA_FCS_FABRIC_SM_AUTH_SUCCESS: + bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_online); + bfa_fcs_fabric_notify_online(fabric); + break; + + case BFA_FCS_FABRIC_SM_PERF_EVFP: + bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_evfp); + break; + + case BFA_FCS_FABRIC_SM_LINK_DOWN: + bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown); + bfa_lps_discard(fabric->lps); + break; + + case BFA_FCS_FABRIC_SM_DELETE: + bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting); + bfa_fcs_fabric_delete(fabric); + break; + + default: + bfa_sm_fault(fabric->fcs, event); + } +} + +/** + * Authentication failed + */ +static void +bfa_fcs_fabric_sm_auth_failed(struct bfa_fcs_fabric_s *fabric, + enum bfa_fcs_fabric_event event) +{ + bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); + bfa_trc(fabric->fcs, event); + + switch (event) { + case BFA_FCS_FABRIC_SM_LINK_DOWN: + bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown); + bfa_fcs_fabric_notify_offline(fabric); + break; + + case BFA_FCS_FABRIC_SM_DELETE: + bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting); + bfa_fcs_fabric_delete(fabric); + break; + + default: + bfa_sm_fault(fabric->fcs, event); + } +} + +/** + * Port is in loopback mode. + */ +static void +bfa_fcs_fabric_sm_loopback(struct bfa_fcs_fabric_s *fabric, + enum bfa_fcs_fabric_event event) +{ + bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); + bfa_trc(fabric->fcs, event); + + switch (event) { + case BFA_FCS_FABRIC_SM_LINK_DOWN: + bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown); + bfa_fcs_fabric_notify_offline(fabric); + break; + + case BFA_FCS_FABRIC_SM_DELETE: + bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting); + bfa_fcs_fabric_delete(fabric); + break; + + default: + bfa_sm_fault(fabric->fcs, event); + } +} + +/** + * There is no attached fabric - private loop or NPort-to-NPort topology. + */ +static void +bfa_fcs_fabric_sm_nofabric(struct bfa_fcs_fabric_s *fabric, + enum bfa_fcs_fabric_event event) +{ + bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); + bfa_trc(fabric->fcs, event); + + switch (event) { + case BFA_FCS_FABRIC_SM_LINK_DOWN: + bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown); + bfa_lps_discard(fabric->lps); + bfa_fcs_fabric_notify_offline(fabric); + break; + + case BFA_FCS_FABRIC_SM_DELETE: + bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting); + bfa_fcs_fabric_delete(fabric); + break; + + case BFA_FCS_FABRIC_SM_NO_FABRIC: + bfa_trc(fabric->fcs, fabric->bb_credit); + bfa_fcport_set_tx_bbcredit(fabric->fcs->bfa, + fabric->bb_credit); + break; + + default: + bfa_sm_fault(fabric->fcs, event); + } +} + +/** + * Fabric is online - normal operating state. + */ +static void +bfa_fcs_fabric_sm_online(struct bfa_fcs_fabric_s *fabric, + enum bfa_fcs_fabric_event event) +{ + bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); + bfa_trc(fabric->fcs, event); + + switch (event) { + case BFA_FCS_FABRIC_SM_LINK_DOWN: + bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown); + bfa_lps_discard(fabric->lps); + bfa_fcs_fabric_notify_offline(fabric); + break; + + case BFA_FCS_FABRIC_SM_DELETE: + bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting); + bfa_fcs_fabric_delete(fabric); + break; + + case BFA_FCS_FABRIC_SM_AUTH_FAILED: + bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_auth_failed); + bfa_lps_discard(fabric->lps); + break; + + case BFA_FCS_FABRIC_SM_AUTH_SUCCESS: + break; + + default: + bfa_sm_fault(fabric->fcs, event); + } +} + +/** + * Exchanging virtual fabric parameters. + */ +static void +bfa_fcs_fabric_sm_evfp(struct bfa_fcs_fabric_s *fabric, + enum bfa_fcs_fabric_event event) +{ + bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); + bfa_trc(fabric->fcs, event); + + switch (event) { + case BFA_FCS_FABRIC_SM_CONT_OP: + bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_evfp_done); + break; + case BFA_FCS_FABRIC_SM_ISOLATE: + bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_isolated); + break; + + default: + bfa_sm_fault(fabric->fcs, event); + } +} + +/** + * EVFP exchange complete and VFT tagging is enabled. + */ +static void +bfa_fcs_fabric_sm_evfp_done(struct bfa_fcs_fabric_s *fabric, + enum bfa_fcs_fabric_event event) +{ + bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); + bfa_trc(fabric->fcs, event); +} + +/** + * Port is isolated after EVFP exchange due to VF_ID mismatch (N and F). + */ +static void +bfa_fcs_fabric_sm_isolated(struct bfa_fcs_fabric_s *fabric, + enum bfa_fcs_fabric_event event) +{ + struct bfad_s *bfad = (struct bfad_s *)fabric->fcs->bfad; + char pwwn_ptr[BFA_STRING_32]; + + bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); + bfa_trc(fabric->fcs, event); + wwn2str(pwwn_ptr, fabric->bport.port_cfg.pwwn); + + BFA_LOG(KERN_INFO, bfad, log_level, + "Port is isolated due to VF_ID mismatch. " + "PWWN: %s Port VF_ID: %04x switch port VF_ID: %04x.", + pwwn_ptr, fabric->fcs->port_vfid, + fabric->event_arg.swp_vfid); +} + +/** + * Fabric is being deleted, awaiting vport delete completions. + */ +static void +bfa_fcs_fabric_sm_deleting(struct bfa_fcs_fabric_s *fabric, + enum bfa_fcs_fabric_event event) +{ + bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); + bfa_trc(fabric->fcs, event); + + switch (event) { + case BFA_FCS_FABRIC_SM_DELCOMP: + bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_uninit); + bfa_fcs_modexit_comp(fabric->fcs); + break; + + case BFA_FCS_FABRIC_SM_LINK_UP: + break; + + case BFA_FCS_FABRIC_SM_LINK_DOWN: + bfa_fcs_fabric_notify_offline(fabric); + break; + + default: + bfa_sm_fault(fabric->fcs, event); + } +} + + + +/** + * fcs_fabric_private fabric private functions + */ + +static void +bfa_fcs_fabric_init(struct bfa_fcs_fabric_s *fabric) +{ + struct bfa_lport_cfg_s *port_cfg = &fabric->bport.port_cfg; + + port_cfg->roles = BFA_LPORT_ROLE_FCP_IM; + port_cfg->nwwn = bfa_ioc_get_nwwn(&fabric->fcs->bfa->ioc); + port_cfg->pwwn = bfa_ioc_get_pwwn(&fabric->fcs->bfa->ioc); +} + +/** + * Port Symbolic Name Creation for base port. + */ void -bfa_fcs_log_init(struct bfa_fcs_s *fcs, struct bfa_log_mod_s *logmod) +bfa_fcs_fabric_psymb_init(struct bfa_fcs_fabric_s *fabric) +{ + struct bfa_lport_cfg_s *port_cfg = &fabric->bport.port_cfg; + char model[BFA_ADAPTER_MODEL_NAME_LEN] = {0}; + struct bfa_fcs_driver_info_s *driver_info = &fabric->fcs->driver_info; + + bfa_ioc_get_adapter_model(&fabric->fcs->bfa->ioc, model); + + /* Model name/number */ + strncpy((char *)&port_cfg->sym_name, model, + BFA_FCS_PORT_SYMBNAME_MODEL_SZ); + strncat((char *)&port_cfg->sym_name, BFA_FCS_PORT_SYMBNAME_SEPARATOR, + sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR)); + + /* Driver Version */ + strncat((char *)&port_cfg->sym_name, (char *)driver_info->version, + BFA_FCS_PORT_SYMBNAME_VERSION_SZ); + strncat((char *)&port_cfg->sym_name, BFA_FCS_PORT_SYMBNAME_SEPARATOR, + sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR)); + + /* Host machine name */ + strncat((char *)&port_cfg->sym_name, + (char *)driver_info->host_machine_name, + BFA_FCS_PORT_SYMBNAME_MACHINENAME_SZ); + strncat((char *)&port_cfg->sym_name, BFA_FCS_PORT_SYMBNAME_SEPARATOR, + sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR)); + + /* + * Host OS Info : + * If OS Patch Info is not there, do not truncate any bytes from the + * OS name string and instead copy the entire OS info string (64 bytes). + */ + if (driver_info->host_os_patch[0] == '\0') { + strncat((char *)&port_cfg->sym_name, + (char *)driver_info->host_os_name, + BFA_FCS_OS_STR_LEN); + strncat((char *)&port_cfg->sym_name, + BFA_FCS_PORT_SYMBNAME_SEPARATOR, + sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR)); + } else { + strncat((char *)&port_cfg->sym_name, + (char *)driver_info->host_os_name, + BFA_FCS_PORT_SYMBNAME_OSINFO_SZ); + strncat((char *)&port_cfg->sym_name, + BFA_FCS_PORT_SYMBNAME_SEPARATOR, + sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR)); + + /* Append host OS Patch Info */ + strncat((char *)&port_cfg->sym_name, + (char *)driver_info->host_os_patch, + BFA_FCS_PORT_SYMBNAME_OSPATCH_SZ); + } + + /* null terminate */ + port_cfg->sym_name.symname[BFA_SYMNAME_MAXLEN - 1] = 0; +} + +/** + * bfa lps login completion callback + */ +void +bfa_cb_lps_flogi_comp(void *bfad, void *uarg, bfa_status_t status) +{ + struct bfa_fcs_fabric_s *fabric = uarg; + + bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); + bfa_trc(fabric->fcs, status); + + switch (status) { + case BFA_STATUS_OK: + fabric->stats.flogi_accepts++; + break; + + case BFA_STATUS_INVALID_MAC: + /* Only for CNA */ + fabric->stats.flogi_acc_err++; + bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_RETRY_OP); + + return; + + case BFA_STATUS_EPROTOCOL: + switch (bfa_lps_get_extstatus(fabric->lps)) { + case BFA_EPROTO_BAD_ACCEPT: + fabric->stats.flogi_acc_err++; + break; + + case BFA_EPROTO_UNKNOWN_RSP: + fabric->stats.flogi_unknown_rsp++; + break; + + default: + break; + } + bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_RETRY_OP); + + return; + + case BFA_STATUS_FABRIC_RJT: + fabric->stats.flogi_rejects++; + bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_RETRY_OP); + return; + + default: + fabric->stats.flogi_rsp_err++; + bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_RETRY_OP); + return; + } + + fabric->bb_credit = bfa_lps_get_peer_bbcredit(fabric->lps); + bfa_trc(fabric->fcs, fabric->bb_credit); + + if (!bfa_lps_is_brcd_fabric(fabric->lps)) + fabric->fabric_name = bfa_lps_get_peer_nwwn(fabric->lps); + + /* + * Check port type. It should be 1 = F-port. + */ + if (bfa_lps_is_fport(fabric->lps)) { + fabric->bport.pid = bfa_lps_get_pid(fabric->lps); + fabric->is_npiv = bfa_lps_is_npiv_en(fabric->lps); + fabric->is_auth = bfa_lps_is_authreq(fabric->lps); + bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_CONT_OP); + } else { + /* + * Nport-2-Nport direct attached + */ + fabric->bport.port_topo.pn2n.rem_port_wwn = + bfa_lps_get_peer_pwwn(fabric->lps); + bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_NO_FABRIC); + } + + bfa_trc(fabric->fcs, fabric->bport.pid); + bfa_trc(fabric->fcs, fabric->is_npiv); + bfa_trc(fabric->fcs, fabric->is_auth); +} +/** + * Allocate and send FLOGI. + */ +static void +bfa_fcs_fabric_login(struct bfa_fcs_fabric_s *fabric) +{ + struct bfa_s *bfa = fabric->fcs->bfa; + struct bfa_lport_cfg_s *pcfg = &fabric->bport.port_cfg; + u8 alpa = 0; + + if (bfa_fcport_get_topology(bfa) == BFA_PORT_TOPOLOGY_LOOP) + alpa = bfa_fcport_get_myalpa(bfa); + + bfa_lps_flogi(fabric->lps, fabric, alpa, bfa_fcport_get_maxfrsize(bfa), + pcfg->pwwn, pcfg->nwwn, fabric->auth_reqd); + + fabric->stats.flogi_sent++; +} + +static void +bfa_fcs_fabric_notify_online(struct bfa_fcs_fabric_s *fabric) +{ + struct bfa_fcs_vport_s *vport; + struct list_head *qe, *qen; + + bfa_trc(fabric->fcs, fabric->fabric_name); + + bfa_fcs_fabric_set_opertype(fabric); + fabric->stats.fabric_onlines++; + + /** + * notify online event to base and then virtual ports + */ + bfa_fcs_lport_online(&fabric->bport); + + list_for_each_safe(qe, qen, &fabric->vport_q) { + vport = (struct bfa_fcs_vport_s *) qe; + bfa_fcs_vport_online(vport); + } +} + +static void +bfa_fcs_fabric_notify_offline(struct bfa_fcs_fabric_s *fabric) +{ + struct bfa_fcs_vport_s *vport; + struct list_head *qe, *qen; + + bfa_trc(fabric->fcs, fabric->fabric_name); + fabric->stats.fabric_offlines++; + + /** + * notify offline event first to vports and then base port. + */ + list_for_each_safe(qe, qen, &fabric->vport_q) { + vport = (struct bfa_fcs_vport_s *) qe; + bfa_fcs_vport_offline(vport); + } + + bfa_fcs_lport_offline(&fabric->bport); + + fabric->fabric_name = 0; + fabric->fabric_ip_addr[0] = 0; +} + +static void +bfa_fcs_fabric_delay(void *cbarg) { - fcs->logm = logmod; + struct bfa_fcs_fabric_s *fabric = cbarg; + + bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_DELAYED); } +/** + * Delete all vports and wait for vport delete completions. + */ +static void +bfa_fcs_fabric_delete(struct bfa_fcs_fabric_s *fabric) +{ + struct bfa_fcs_vport_s *vport; + struct list_head *qe, *qen; + list_for_each_safe(qe, qen, &fabric->vport_q) { + vport = (struct bfa_fcs_vport_s *) qe; + bfa_fcs_vport_fcs_delete(vport); + } + + bfa_fcs_lport_delete(&fabric->bport); + bfa_wc_wait(&fabric->wc); +} + +static void +bfa_fcs_fabric_delete_comp(void *cbarg) +{ + struct bfa_fcs_fabric_s *fabric = cbarg; + + bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_DELCOMP); +} + +/** + * fcs_fabric_public fabric public functions + */ + +/** + * Attach time initialization. + */ void -bfa_fcs_aen_init(struct bfa_fcs_s *fcs, struct bfa_aen_s *aen) +bfa_fcs_fabric_attach(struct bfa_fcs_s *fcs) { - fcs->aen = aen; + struct bfa_fcs_fabric_s *fabric; + + fabric = &fcs->fabric; + bfa_os_memset(fabric, 0, sizeof(struct bfa_fcs_fabric_s)); + + /** + * Initialize base fabric. + */ + fabric->fcs = fcs; + INIT_LIST_HEAD(&fabric->vport_q); + INIT_LIST_HEAD(&fabric->vf_q); + fabric->lps = bfa_lps_alloc(fcs->bfa); + bfa_assert(fabric->lps); + + /** + * Initialize fabric delete completion handler. Fabric deletion is + * complete when the last vport delete is complete. + */ + bfa_wc_init(&fabric->wc, bfa_fcs_fabric_delete_comp, fabric); + bfa_wc_up(&fabric->wc); /* For the base port */ + + bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_uninit); + bfa_fcs_lport_attach(&fabric->bport, fabric->fcs, FC_VF_ID_NULL, NULL); } void -bfa_fcs_modexit_comp(struct bfa_fcs_s *fcs) +bfa_fcs_fabric_modinit(struct bfa_fcs_s *fcs) { - bfa_wc_down(&fcs->wc); + bfa_sm_send_event(&fcs->fabric, BFA_FCS_FABRIC_SM_CREATE); + bfa_trc(fcs, 0); } +/** + * Module cleanup + */ +void +bfa_fcs_fabric_modexit(struct bfa_fcs_s *fcs) +{ + struct bfa_fcs_fabric_s *fabric; + + bfa_trc(fcs, 0); + + /** + * Cleanup base fabric. + */ + fabric = &fcs->fabric; + bfa_lps_delete(fabric->lps); + bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_DELETE); +} +/** + * Fabric module start -- kick starts FCS actions + */ +void +bfa_fcs_fabric_modstart(struct bfa_fcs_s *fcs) +{ + struct bfa_fcs_fabric_s *fabric; + + bfa_trc(fcs, 0); + fabric = &fcs->fabric; + bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_START); +} + +/** + * Suspend fabric activity as part of driver suspend. + */ +void +bfa_fcs_fabric_modsusp(struct bfa_fcs_s *fcs) +{ +} + +bfa_boolean_t +bfa_fcs_fabric_is_loopback(struct bfa_fcs_fabric_s *fabric) +{ + return bfa_sm_cmp_state(fabric, bfa_fcs_fabric_sm_loopback); +} + +bfa_boolean_t +bfa_fcs_fabric_is_auth_failed(struct bfa_fcs_fabric_s *fabric) +{ + return bfa_sm_cmp_state(fabric, bfa_fcs_fabric_sm_auth_failed); +} + +enum bfa_port_type +bfa_fcs_fabric_port_type(struct bfa_fcs_fabric_s *fabric) +{ + return fabric->oper_type; +} + +/** + * Link up notification from BFA physical port module. + */ +void +bfa_fcs_fabric_link_up(struct bfa_fcs_fabric_s *fabric) +{ + bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); + bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_LINK_UP); +} + +/** + * Link down notification from BFA physical port module. + */ +void +bfa_fcs_fabric_link_down(struct bfa_fcs_fabric_s *fabric) +{ + bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); + bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_LINK_DOWN); +} + +/** + * A child vport is being created in the fabric. + * + * Call from vport module at vport creation. A list of base port and vports + * belonging to a fabric is maintained to propagate link events. + * + * param[in] fabric - Fabric instance. This can be a base fabric or vf. + * param[in] vport - Vport being created. + * + * @return None (always succeeds) + */ +void +bfa_fcs_fabric_addvport(struct bfa_fcs_fabric_s *fabric, + struct bfa_fcs_vport_s *vport) +{ + /** + * - add vport to fabric's vport_q + */ + bfa_trc(fabric->fcs, fabric->vf_id); + + list_add_tail(&vport->qe, &fabric->vport_q); + fabric->num_vports++; + bfa_wc_up(&fabric->wc); +} + +/** + * A child vport is being deleted from fabric. + * + * Vport is being deleted. + */ +void +bfa_fcs_fabric_delvport(struct bfa_fcs_fabric_s *fabric, + struct bfa_fcs_vport_s *vport) +{ + list_del(&vport->qe); + fabric->num_vports--; + bfa_wc_down(&fabric->wc); +} + +/** + * Base port is deleted. + */ +void +bfa_fcs_fabric_port_delete_comp(struct bfa_fcs_fabric_s *fabric) +{ + bfa_wc_down(&fabric->wc); +} + + +/** + * Check if fabric is online. + * + * param[in] fabric - Fabric instance. This can be a base fabric or vf. + * + * @return TRUE/FALSE + */ +int +bfa_fcs_fabric_is_online(struct bfa_fcs_fabric_s *fabric) +{ + return bfa_sm_cmp_state(fabric, bfa_fcs_fabric_sm_online); +} + +/** + * brief + * + */ +bfa_status_t +bfa_fcs_fabric_addvf(struct bfa_fcs_fabric_s *vf, struct bfa_fcs_s *fcs, + struct bfa_lport_cfg_s *port_cfg, struct bfad_vf_s *vf_drv) +{ + bfa_sm_set_state(vf, bfa_fcs_fabric_sm_uninit); + return BFA_STATUS_OK; +} + +/** + * Lookup for a vport withing a fabric given its pwwn + */ +struct bfa_fcs_vport_s * +bfa_fcs_fabric_vport_lookup(struct bfa_fcs_fabric_s *fabric, wwn_t pwwn) +{ + struct bfa_fcs_vport_s *vport; + struct list_head *qe; + + list_for_each(qe, &fabric->vport_q) { + vport = (struct bfa_fcs_vport_s *) qe; + if (bfa_fcs_lport_get_pwwn(&vport->lport) == pwwn) + return vport; + } + + return NULL; +} + +/** + * In a given fabric, return the number of lports. + * + * param[in] fabric - Fabric instance. This can be a base fabric or vf. + * + * @return : 1 or more. + */ +u16 +bfa_fcs_fabric_vport_count(struct bfa_fcs_fabric_s *fabric) +{ + return fabric->num_vports; +} + +/* + * 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 = (u8 *)&fab_nwwn; + oui = (tmp[3] << 8) | tmp[4]; + + return oui; +} +/** + * Unsolicited frame receive handling. + */ +void +bfa_fcs_fabric_uf_recv(struct bfa_fcs_fabric_s *fabric, struct fchs_s *fchs, + u16 len) +{ + u32 pid = fchs->d_id; + struct bfa_fcs_vport_s *vport; + struct list_head *qe; + struct fc_els_cmd_s *els_cmd = (struct fc_els_cmd_s *) (fchs + 1); + struct fc_logi_s *flogi = (struct fc_logi_s *) els_cmd; + + bfa_trc(fabric->fcs, len); + bfa_trc(fabric->fcs, pid); + + /** + * Look for our own FLOGI frames being looped back. This means an + * external loopback cable is in place. Our own FLOGI frames are + * sometimes looped back when switch port gets temporarily bypassed. + */ + if ((pid == bfa_os_ntoh3b(FC_FABRIC_PORT)) && + (els_cmd->els_code == FC_ELS_FLOGI) && + (flogi->port_name == bfa_fcs_lport_get_pwwn(&fabric->bport))) { + bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_LOOPBACK); + return; + } + + /** + * FLOGI/EVFP exchanges should be consumed by base fabric. + */ + if (fchs->d_id == bfa_os_hton3b(FC_FABRIC_PORT)) { + bfa_trc(fabric->fcs, pid); + bfa_fcs_fabric_process_uf(fabric, fchs, len); + return; + } + + if (fabric->bport.pid == pid) { + /** + * All authentication frames should be routed to auth + */ + bfa_trc(fabric->fcs, els_cmd->els_code); + if (els_cmd->els_code == FC_ELS_AUTH) { + bfa_trc(fabric->fcs, els_cmd->els_code); + return; + } + + bfa_trc(fabric->fcs, *(u8 *) ((u8 *) fchs)); + bfa_fcs_lport_uf_recv(&fabric->bport, fchs, len); + return; + } + + /** + * look for a matching local port ID + */ + list_for_each(qe, &fabric->vport_q) { + vport = (struct bfa_fcs_vport_s *) qe; + if (vport->lport.pid == pid) { + bfa_fcs_lport_uf_recv(&vport->lport, fchs, len); + return; + } + } + bfa_trc(fabric->fcs, els_cmd->els_code); + bfa_fcs_lport_uf_recv(&fabric->bport, fchs, len); +} + +/** + * Unsolicited frames to be processed by fabric. + */ +static void +bfa_fcs_fabric_process_uf(struct bfa_fcs_fabric_s *fabric, struct fchs_s *fchs, + u16 len) +{ + struct fc_els_cmd_s *els_cmd = (struct fc_els_cmd_s *) (fchs + 1); + + bfa_trc(fabric->fcs, els_cmd->els_code); + + switch (els_cmd->els_code) { + case FC_ELS_FLOGI: + bfa_fcs_fabric_process_flogi(fabric, fchs, len); + break; + + default: + /* + * need to generate a LS_RJT + */ + break; + } +} + +/** + * Process incoming FLOGI + */ +static void +bfa_fcs_fabric_process_flogi(struct bfa_fcs_fabric_s *fabric, + struct fchs_s *fchs, u16 len) +{ + struct fc_logi_s *flogi = (struct fc_logi_s *) (fchs + 1); + struct bfa_fcs_lport_s *bport = &fabric->bport; + + bfa_trc(fabric->fcs, fchs->s_id); + + fabric->stats.flogi_rcvd++; + /* + * Check port type. It should be 0 = n-port. + */ + if (flogi->csp.port_type) { + /* + * @todo: may need to send a LS_RJT + */ + bfa_trc(fabric->fcs, flogi->port_name); + fabric->stats.flogi_rejected++; + return; + } + + fabric->bb_credit = bfa_os_ntohs(flogi->csp.bbcred); + bport->port_topo.pn2n.rem_port_wwn = flogi->port_name; + bport->port_topo.pn2n.reply_oxid = fchs->ox_id; + + /* + * Send a Flogi Acc + */ + bfa_fcs_fabric_send_flogi_acc(fabric); + bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_NO_FABRIC); +} + +static void +bfa_fcs_fabric_send_flogi_acc(struct bfa_fcs_fabric_s *fabric) +{ + struct bfa_lport_cfg_s *pcfg = &fabric->bport.port_cfg; + struct bfa_fcs_lport_n2n_s *n2n_port = &fabric->bport.port_topo.pn2n; + struct bfa_s *bfa = fabric->fcs->bfa; + struct bfa_fcxp_s *fcxp; + u16 reqlen; + struct fchs_s fchs; + + fcxp = bfa_fcs_fcxp_alloc(fabric->fcs); + /** + * Do not expect this failure -- expect remote node to retry + */ + if (!fcxp) + return; + + reqlen = fc_flogi_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), + bfa_os_hton3b(FC_FABRIC_PORT), + n2n_port->reply_oxid, pcfg->pwwn, + pcfg->nwwn, + bfa_fcport_get_maxfrsize(bfa), + bfa_fcport_get_rx_bbcredit(bfa)); + + bfa_fcxp_send(fcxp, NULL, fabric->vf_id, bfa_lps_get_tag(fabric->lps), + BFA_FALSE, FC_CLASS_3, + reqlen, &fchs, bfa_fcs_fabric_flogiacc_comp, fabric, + FC_MAX_PDUSZ, 0); +} + +/** + * Flogi Acc completion callback. + */ +static void +bfa_fcs_fabric_flogiacc_comp(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg, + bfa_status_t status, u32 rsp_len, + u32 resid_len, struct fchs_s *rspfchs) +{ + struct bfa_fcs_fabric_s *fabric = cbarg; + + bfa_trc(fabric->fcs, status); +} + +/* + * + * @param[in] fabric - fabric + * @param[in] wwn_t - new fabric name + * + * @return - none + */ +void +bfa_fcs_fabric_set_fabric_name(struct bfa_fcs_fabric_s *fabric, + wwn_t fabric_name) +{ + struct bfad_s *bfad = (struct bfad_s *)fabric->fcs->bfad; + char pwwn_ptr[BFA_STRING_32]; + char fwwn_ptr[BFA_STRING_32]; + + bfa_trc(fabric->fcs, fabric_name); + + if (fabric->fabric_name == 0) { + /* + * With BRCD switches, we don't get Fabric Name in FLOGI. + * Don't generate a fabric name change event in this case. + */ + fabric->fabric_name = fabric_name; + } else { + fabric->fabric_name = fabric_name; + wwn2str(pwwn_ptr, bfa_fcs_lport_get_pwwn(&fabric->bport)); + wwn2str(fwwn_ptr, + bfa_fcs_lport_get_fabric_name(&fabric->bport)); + BFA_LOG(KERN_WARNING, bfad, log_level, + "Base port WWN = %s Fabric WWN = %s\n", + pwwn_ptr, fwwn_ptr); + } +} + +/** + * fcs_vf_api virtual fabrics API + */ + +/** + * Enable VF mode. + * + * @param[in] fcs fcs module instance + * @param[in] vf_id default vf_id of port, FC_VF_ID_NULL + * to use standard default vf_id of 1. + * + * @retval BFA_STATUS_OK vf mode is enabled + * @retval BFA_STATUS_BUSY Port is active. Port must be disabled + * before VF mode can be enabled. + */ +bfa_status_t +bfa_fcs_vf_mode_enable(struct bfa_fcs_s *fcs, u16 vf_id) +{ + return BFA_STATUS_OK; +} + +/** + * Disable VF mode. + * + * @param[in] fcs fcs module instance + * + * @retval BFA_STATUS_OK vf mode is disabled + * @retval BFA_STATUS_BUSY VFs are present and being used. All + * VFs must be deleted before disabling + * VF mode. + */ +bfa_status_t +bfa_fcs_vf_mode_disable(struct bfa_fcs_s *fcs) +{ + return BFA_STATUS_OK; +} + +/** + * Create a new VF instance. + * + * A new VF is created using the given VF configuration. A VF is identified + * by VF id. No duplicate VF creation is allowed with the same VF id. Once + * a VF is created, VF is automatically started after link initialization + * and EVFP exchange is completed. + * + * param[in] vf - FCS vf data structure. Memory is + * allocated by caller (driver) + * param[in] fcs - FCS module + * param[in] vf_cfg - VF configuration + * param[in] vf_drv - Opaque handle back to the driver's + * virtual vf structure + * + * retval BFA_STATUS_OK VF creation is successful + * retval BFA_STATUS_FAILED VF creation failed + * retval BFA_STATUS_EEXIST A VF exists with the given vf_id + */ +bfa_status_t +bfa_fcs_vf_create(bfa_fcs_vf_t *vf, struct bfa_fcs_s *fcs, u16 vf_id, + struct bfa_lport_cfg_s *port_cfg, struct bfad_vf_s *vf_drv) +{ + bfa_trc(fcs, vf_id); + return BFA_STATUS_OK; +} + +/** + * Use this function to delete a BFA VF object. VF object should + * be stopped before this function call. + * + * param[in] vf - pointer to bfa_vf_t. + * + * retval BFA_STATUS_OK On vf deletion success + * retval BFA_STATUS_BUSY VF is not in a stopped state + * retval BFA_STATUS_INPROGRESS VF deletion in in progress + */ +bfa_status_t +bfa_fcs_vf_delete(bfa_fcs_vf_t *vf) +{ + bfa_trc(vf->fcs, vf->vf_id); + return BFA_STATUS_OK; +} + + +/** + * Returns attributes of the given VF. + * + * param[in] vf pointer to bfa_vf_t. + * param[out] vf_attr vf attributes returned + * + * return None + */ +void +bfa_fcs_vf_get_attr(bfa_fcs_vf_t *vf, struct bfa_vf_attr_s *vf_attr) +{ + bfa_trc(vf->fcs, vf->vf_id); +} + +/** + * Return statistics associated with the given vf. + * + * param[in] vf pointer to bfa_vf_t. + * param[out] vf_stats vf statistics returned + * + * @return None + */ +void +bfa_fcs_vf_get_stats(bfa_fcs_vf_t *vf, struct bfa_vf_stats_s *vf_stats) +{ + bfa_os_memcpy(vf_stats, &vf->stats, sizeof(struct bfa_vf_stats_s)); +} + +/** + * clear statistics associated with the given vf. + * + * param[in] vf pointer to bfa_vf_t. + * + * @return None + */ +void +bfa_fcs_vf_clear_stats(bfa_fcs_vf_t *vf) +{ + bfa_os_memset(&vf->stats, 0, sizeof(struct bfa_vf_stats_s)); +} + +/** + * Returns FCS vf structure for a given vf_id. + * + * param[in] vf_id - VF_ID + * + * return + * If lookup succeeds, retuns fcs vf object, otherwise returns NULL + */ +bfa_fcs_vf_t * +bfa_fcs_vf_lookup(struct bfa_fcs_s *fcs, u16 vf_id) +{ + bfa_trc(fcs, vf_id); + if (vf_id == FC_VF_ID_NULL) + return &fcs->fabric; + + return NULL; +} + +/** + * Return the list of VFs configured. + * + * param[in] fcs fcs module instance + * param[out] vf_ids returned list of vf_ids + * param[in,out] nvfs in:size of vf_ids array, + * out:total elements present, + * actual elements returned is limited by the size + * + * return Driver VF structure + */ +void +bfa_fcs_vf_list(struct bfa_fcs_s *fcs, u16 *vf_ids, int *nvfs) +{ + bfa_trc(fcs, *nvfs); +} + +/** + * Return the list of all VFs visible from fabric. + * + * param[in] fcs fcs module instance + * param[out] vf_ids returned list of vf_ids + * param[in,out] nvfs in:size of vf_ids array, + * out:total elements present, + * actual elements returned is limited by the size + * + * return Driver VF structure + */ +void +bfa_fcs_vf_list_all(struct bfa_fcs_s *fcs, u16 *vf_ids, int *nvfs) +{ + bfa_trc(fcs, *nvfs); +} + +/** + * Return the list of local logical ports present in the given VF. + * + * param[in] vf vf for which logical ports are returned + * param[out] lpwwn returned logical port wwn list + * param[in,out] nlports in:size of lpwwn list; + * out:total elements present, + * actual elements returned is limited by the size + */ +void +bfa_fcs_vf_get_ports(bfa_fcs_vf_t *vf, wwn_t lpwwn[], int *nlports) +{ + struct list_head *qe; + struct bfa_fcs_vport_s *vport; + int i; + struct bfa_fcs_s *fcs; + + if (vf == NULL || lpwwn == NULL || *nlports == 0) + return; + + fcs = vf->fcs; + + bfa_trc(fcs, vf->vf_id); + bfa_trc(fcs, (u32) *nlports); + + i = 0; + lpwwn[i++] = vf->bport.port_cfg.pwwn; + + list_for_each(qe, &vf->vport_q) { + if (i >= *nlports) + break; + + vport = (struct bfa_fcs_vport_s *) qe; + lpwwn[i++] = vport->lport.port_cfg.pwwn; + } + + bfa_trc(fcs, i); + *nlports = i; +} + +/** + * BFA FCS PPORT ( physical port) + */ +static void +bfa_fcs_port_event_handler(void *cbarg, enum bfa_port_linkstate event) +{ + struct bfa_fcs_s *fcs = cbarg; + + bfa_trc(fcs, event); + + switch (event) { + case BFA_PORT_LINKUP: + bfa_fcs_fabric_link_up(&fcs->fabric); + break; + + case BFA_PORT_LINKDOWN: + bfa_fcs_fabric_link_down(&fcs->fabric); + break; + + default: + bfa_assert(0); + } +} + +void +bfa_fcs_port_attach(struct bfa_fcs_s *fcs) +{ + bfa_fcport_event_register(fcs->bfa, bfa_fcs_port_event_handler, fcs); +} + +/** + * BFA FCS UF ( Unsolicited Frames) + */ + +/** + * BFA callback for unsolicited frame receive handler. + * + * @param[in] cbarg callback arg for receive handler + * @param[in] uf unsolicited frame descriptor + * + * @return None + */ +static void +bfa_fcs_uf_recv(void *cbarg, struct bfa_uf_s *uf) +{ + struct bfa_fcs_s *fcs = (struct bfa_fcs_s *) cbarg; + struct fchs_s *fchs = bfa_uf_get_frmbuf(uf); + u16 len = bfa_uf_get_frmlen(uf); + struct fc_vft_s *vft; + struct bfa_fcs_fabric_s *fabric; + + /** + * check for VFT header + */ + if (fchs->routing == FC_RTG_EXT_HDR && + fchs->cat_info == FC_CAT_VFT_HDR) { + bfa_stats(fcs, uf.tagged); + vft = bfa_uf_get_frmbuf(uf); + if (fcs->port_vfid == vft->vf_id) + fabric = &fcs->fabric; + else + fabric = bfa_fcs_vf_lookup(fcs, (u16) vft->vf_id); + + /** + * drop frame if vfid is unknown + */ + if (!fabric) { + bfa_assert(0); + bfa_stats(fcs, uf.vfid_unknown); + bfa_uf_free(uf); + return; + } + + /** + * skip vft header + */ + fchs = (struct fchs_s *) (vft + 1); + len -= sizeof(struct fc_vft_s); + + bfa_trc(fcs, vft->vf_id); + } else { + bfa_stats(fcs, uf.untagged); + fabric = &fcs->fabric; + } + + bfa_trc(fcs, ((u32 *) fchs)[0]); + bfa_trc(fcs, ((u32 *) fchs)[1]); + bfa_trc(fcs, ((u32 *) fchs)[2]); + bfa_trc(fcs, ((u32 *) fchs)[3]); + bfa_trc(fcs, ((u32 *) fchs)[4]); + bfa_trc(fcs, ((u32 *) fchs)[5]); + bfa_trc(fcs, len); + + bfa_fcs_fabric_uf_recv(fabric, fchs, len); + bfa_uf_free(uf); +} + +void +bfa_fcs_uf_attach(struct bfa_fcs_s *fcs) +{ + bfa_uf_recv_register(fcs->bfa, bfa_fcs_uf_recv, fcs); +} diff --git a/drivers/scsi/bfa/bfa_fcs.h b/drivers/scsi/bfa/bfa_fcs.h new file mode 100644 index 000000000000..d75045df1e7e --- /dev/null +++ b/drivers/scsi/bfa/bfa_fcs.h @@ -0,0 +1,779 @@ +/* + * 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 __BFA_FCS_H__ +#define __BFA_FCS_H__ + +#include "bfa_cs.h" +#include "bfa_defs.h" +#include "bfa_defs_fcs.h" +#include "bfa_modules.h" +#include "bfa_fc.h" + +#define BFA_FCS_OS_STR_LEN 64 + +/* + * !!! Only append to the enums defined here to avoid any versioning + * !!! needed between trace utility and driver version + */ +enum { + BFA_TRC_FCS_FCS = 1, + BFA_TRC_FCS_PORT = 2, + BFA_TRC_FCS_RPORT = 3, + BFA_TRC_FCS_FCPIM = 4, +}; + + +struct bfa_fcs_s; + +#define __fcs_min_cfg(__fcs) ((__fcs)->min_cfg) +void bfa_fcs_modexit_comp(struct bfa_fcs_s *fcs); + +#define BFA_FCS_BRCD_SWITCH_OUI 0x051e +#define N2N_LOCAL_PID 0x010000 +#define N2N_REMOTE_PID 0x020000 +#define BFA_FCS_RETRY_TIMEOUT 2000 +#define BFA_FCS_PID_IS_WKA(pid) ((bfa_os_ntoh3b(pid) > 0xFFF000) ? 1 : 0) + + + +struct bfa_fcs_lport_ns_s { + bfa_sm_t sm; /* state machine */ + struct bfa_timer_s timer; + struct bfa_fcs_lport_s *port; /* parent port */ + struct bfa_fcxp_s *fcxp; + struct bfa_fcxp_wqe_s fcxp_wqe; +}; + + +struct bfa_fcs_lport_scn_s { + bfa_sm_t sm; /* state machine */ + struct bfa_timer_s timer; + struct bfa_fcs_lport_s *port; /* parent port */ + struct bfa_fcxp_s *fcxp; + struct bfa_fcxp_wqe_s fcxp_wqe; +}; + + +struct bfa_fcs_lport_fdmi_s { + bfa_sm_t sm; /* state machine */ + struct bfa_timer_s timer; + struct bfa_fcs_lport_ms_s *ms; /* parent ms */ + struct bfa_fcxp_s *fcxp; + struct bfa_fcxp_wqe_s fcxp_wqe; + u8 retry_cnt; /* retry count */ + u8 rsvd[3]; +}; + + +struct bfa_fcs_lport_ms_s { + bfa_sm_t sm; /* state machine */ + struct bfa_timer_s timer; + struct bfa_fcs_lport_s *port; /* parent port */ + struct bfa_fcxp_s *fcxp; + struct bfa_fcxp_wqe_s fcxp_wqe; + struct bfa_fcs_lport_fdmi_s fdmi; /* FDMI component of MS */ + u8 retry_cnt; /* retry count */ + u8 rsvd[3]; +}; + + +struct bfa_fcs_lport_fab_s { + struct bfa_fcs_lport_ns_s ns; /* NS component of port */ + struct bfa_fcs_lport_scn_s scn; /* scn component of port */ + struct bfa_fcs_lport_ms_s ms; /* MS component of port */ +}; + +#define MAX_ALPA_COUNT 127 + +struct bfa_fcs_lport_loop_s { + u8 num_alpa; /* Num of ALPA entries in the map */ + u8 alpa_pos_map[MAX_ALPA_COUNT]; /* ALPA Positional + *Map */ + struct bfa_fcs_lport_s *port; /* parent port */ +}; + +struct bfa_fcs_lport_n2n_s { + u32 rsvd; + u16 reply_oxid; /* ox_id from the req flogi to be + *used in flogi acc */ + wwn_t rem_port_wwn; /* Attached port's wwn */ +}; + + +union bfa_fcs_lport_topo_u { + struct bfa_fcs_lport_fab_s pfab; + struct bfa_fcs_lport_loop_s ploop; + struct bfa_fcs_lport_n2n_s pn2n; +}; + + +struct bfa_fcs_lport_s { + struct list_head qe; /* used by port/vport */ + bfa_sm_t sm; /* state machine */ + struct bfa_fcs_fabric_s *fabric; /* parent fabric */ + struct bfa_lport_cfg_s port_cfg; /* port configuration */ + struct bfa_timer_s link_timer; /* timer for link offline */ + u32 pid:24; /* FC address */ + u8 lp_tag; /* lport tag */ + u16 num_rports; /* Num of r-ports */ + struct list_head rport_q; /* queue of discovered r-ports */ + struct bfa_fcs_s *fcs; /* FCS instance */ + union bfa_fcs_lport_topo_u port_topo; /* fabric/loop/n2n details */ + struct bfad_port_s *bfad_port; /* driver peer instance */ + struct bfa_fcs_vport_s *vport; /* NULL for base ports */ + struct bfa_fcxp_s *fcxp; + struct bfa_fcxp_wqe_s fcxp_wqe; + struct bfa_lport_stats_s stats; + struct bfa_wc_s wc; /* waiting counter for events */ +}; +#define BFA_FCS_GET_HAL_FROM_PORT(port) (port->fcs->bfa) +#define BFA_FCS_GET_NS_FROM_PORT(port) (&port->port_topo.pfab.ns) +#define BFA_FCS_GET_SCN_FROM_PORT(port) (&port->port_topo.pfab.scn) +#define BFA_FCS_GET_MS_FROM_PORT(port) (&port->port_topo.pfab.ms) +#define BFA_FCS_GET_FDMI_FROM_PORT(port) (&port->port_topo.pfab.ms.fdmi) +#define BFA_FCS_VPORT_IS_INITIATOR_MODE(port) \ + (port->port_cfg.roles & BFA_LPORT_ROLE_FCP_IM) + +/* + * forward declaration + */ +struct bfad_vf_s; + +enum bfa_fcs_fabric_type { + BFA_FCS_FABRIC_UNKNOWN = 0, + BFA_FCS_FABRIC_SWITCHED = 1, + BFA_FCS_FABRIC_N2N = 2, +}; + + +struct bfa_fcs_fabric_s { + struct list_head qe; /* queue element */ + bfa_sm_t sm; /* state machine */ + struct bfa_fcs_s *fcs; /* FCS instance */ + struct bfa_fcs_lport_s bport; /* base logical port */ + enum bfa_fcs_fabric_type fab_type; /* fabric type */ + enum bfa_port_type oper_type; /* current link topology */ + u8 is_vf; /* is virtual fabric? */ + u8 is_npiv; /* is NPIV supported ? */ + u8 is_auth; /* is Security/Auth supported ? */ + u16 bb_credit; /* BB credit from fabric */ + u16 vf_id; /* virtual fabric ID */ + u16 num_vports; /* num vports */ + u16 rsvd; + struct list_head vport_q; /* queue of virtual ports */ + struct list_head vf_q; /* queue of virtual fabrics */ + struct bfad_vf_s *vf_drv; /* driver vf structure */ + struct bfa_timer_s link_timer; /* Link Failure timer. Vport */ + wwn_t fabric_name; /* attached fabric name */ + bfa_boolean_t auth_reqd; /* authentication required */ + struct bfa_timer_s delay_timer; /* delay timer */ + union { + u16 swp_vfid;/* switch port VF id */ + } event_arg; + struct bfa_wc_s wc; /* wait counter for delete */ + struct bfa_vf_stats_s stats; /* fabric/vf stats */ + struct bfa_lps_s *lps; /* lport login services */ + u8 fabric_ip_addr[BFA_FCS_FABRIC_IPADDR_SZ]; + /* attached fabric's ip addr */ +}; + +#define bfa_fcs_fabric_npiv_capable(__f) ((__f)->is_npiv) +#define bfa_fcs_fabric_is_switched(__f) \ + ((__f)->fab_type == BFA_FCS_FABRIC_SWITCHED) + +/** + * The design calls for a single implementation of base fabric and vf. + */ +#define bfa_fcs_vf_t struct bfa_fcs_fabric_s + +struct bfa_vf_event_s { + u32 undefined; +}; + +struct bfa_fcs_s; +struct bfa_fcs_fabric_s; + +/* + * @todo : need to move to a global config file. + * Maximum Rports supported per port (physical/logical). + */ +#define BFA_FCS_MAX_RPORTS_SUPP 256 /* @todo : tentative value */ + +#define bfa_fcs_lport_t struct bfa_fcs_lport_s + +/** + * Symbolic Name related defines + * Total bytes 255. + * Physical Port's symbolic name 128 bytes. + * For Vports, Vport's symbolic name is appended to the Physical port's + * Symbolic Name. + * + * Physical Port's symbolic name Format : (Total 128 bytes) + * Adapter Model number/name : 12 bytes + * Driver Version : 10 bytes + * Host Machine Name : 30 bytes + * Host OS Info : 48 bytes + * Host OS PATCH Info : 16 bytes + * ( remaining 12 bytes reserved to be used for separator) + */ +#define BFA_FCS_PORT_SYMBNAME_SEPARATOR " | " + +#define BFA_FCS_PORT_SYMBNAME_MODEL_SZ 12 +#define BFA_FCS_PORT_SYMBNAME_VERSION_SZ 10 +#define BFA_FCS_PORT_SYMBNAME_MACHINENAME_SZ 30 +#define BFA_FCS_PORT_SYMBNAME_OSINFO_SZ 48 +#define BFA_FCS_PORT_SYMBNAME_OSPATCH_SZ 16 + +/** + * Get FC port ID for a logical port. + */ +#define bfa_fcs_lport_get_fcid(_lport) ((_lport)->pid) +#define bfa_fcs_lport_get_pwwn(_lport) ((_lport)->port_cfg.pwwn) +#define bfa_fcs_lport_get_nwwn(_lport) ((_lport)->port_cfg.nwwn) +#define bfa_fcs_lport_get_psym_name(_lport) ((_lport)->port_cfg.sym_name) +#define bfa_fcs_lport_is_initiator(_lport) \ + ((_lport)->port_cfg.roles & BFA_LPORT_ROLE_FCP_IM) +#define bfa_fcs_lport_get_nrports(_lport) \ + ((_lport) ? (_lport)->num_rports : 0) + +static inline struct bfad_port_s * +bfa_fcs_lport_get_drvport(struct bfa_fcs_lport_s *port) +{ + return port->bfad_port; +} + +#define bfa_fcs_lport_get_opertype(_lport) ((_lport)->fabric->oper_type) +#define bfa_fcs_lport_get_fabric_name(_lport) ((_lport)->fabric->fabric_name) +#define bfa_fcs_lport_get_fabric_ipaddr(_lport) \ + ((_lport)->fabric->fabric_ip_addr) + +/** + * bfa fcs port public functions + */ + +bfa_boolean_t bfa_fcs_lport_is_online(struct bfa_fcs_lport_s *port); +struct bfa_fcs_lport_s *bfa_fcs_get_base_port(struct bfa_fcs_s *fcs); +void bfa_fcs_lport_get_rports(struct bfa_fcs_lport_s *port, + wwn_t rport_wwns[], int *nrports); + +wwn_t bfa_fcs_lport_get_rport(struct bfa_fcs_lport_s *port, wwn_t wwn, + int index, int nrports, bfa_boolean_t bwwn); + +struct bfa_fcs_lport_s *bfa_fcs_lookup_port(struct bfa_fcs_s *fcs, + u16 vf_id, wwn_t lpwwn); + +void bfa_fcs_lport_get_info(struct bfa_fcs_lport_s *port, + struct bfa_lport_info_s *port_info); +void bfa_fcs_lport_get_attr(struct bfa_fcs_lport_s *port, + struct bfa_lport_attr_s *port_attr); +void bfa_fcs_lport_get_stats(struct bfa_fcs_lport_s *fcs_port, + struct bfa_lport_stats_s *port_stats); +void bfa_fcs_lport_clear_stats(struct bfa_fcs_lport_s *fcs_port); +enum bfa_port_speed bfa_fcs_lport_get_rport_max_speed( + struct bfa_fcs_lport_s *port); + +/* MS FCS routines */ +void bfa_fcs_lport_ms_init(struct bfa_fcs_lport_s *port); +void bfa_fcs_lport_ms_offline(struct bfa_fcs_lport_s *port); +void bfa_fcs_lport_ms_online(struct bfa_fcs_lport_s *port); +void bfa_fcs_lport_ms_fabric_rscn(struct bfa_fcs_lport_s *port); + +/* FDMI FCS routines */ +void bfa_fcs_lport_fdmi_init(struct bfa_fcs_lport_ms_s *ms); +void bfa_fcs_lport_fdmi_offline(struct bfa_fcs_lport_ms_s *ms); +void bfa_fcs_lport_fdmi_online(struct bfa_fcs_lport_ms_s *ms); +void bfa_fcs_lport_uf_recv(struct bfa_fcs_lport_s *lport, struct fchs_s *fchs, + u16 len); +void bfa_fcs_lport_attach(struct bfa_fcs_lport_s *lport, struct bfa_fcs_s *fcs, + u16 vf_id, struct bfa_fcs_vport_s *vport); +void bfa_fcs_lport_init(struct bfa_fcs_lport_s *lport, + struct bfa_lport_cfg_s *port_cfg); +void bfa_fcs_lport_online(struct bfa_fcs_lport_s *port); +void bfa_fcs_lport_offline(struct bfa_fcs_lport_s *port); +void bfa_fcs_lport_delete(struct bfa_fcs_lport_s *port); +struct bfa_fcs_rport_s *bfa_fcs_lport_get_rport_by_pid( + struct bfa_fcs_lport_s *port, u32 pid); +struct bfa_fcs_rport_s *bfa_fcs_lport_get_rport_by_pwwn( + struct bfa_fcs_lport_s *port, wwn_t pwwn); +struct bfa_fcs_rport_s *bfa_fcs_lport_get_rport_by_nwwn( + struct bfa_fcs_lport_s *port, wwn_t nwwn); +void bfa_fcs_lport_add_rport(struct bfa_fcs_lport_s *port, + struct bfa_fcs_rport_s *rport); +void bfa_fcs_lport_del_rport(struct bfa_fcs_lport_s *port, + struct bfa_fcs_rport_s *rport); +void bfa_fcs_lport_modinit(struct bfa_fcs_s *fcs); +void bfa_fcs_lport_modexit(struct bfa_fcs_s *fcs); +void bfa_fcs_lport_ns_init(struct bfa_fcs_lport_s *vport); +void bfa_fcs_lport_ns_offline(struct bfa_fcs_lport_s *vport); +void bfa_fcs_lport_ns_online(struct bfa_fcs_lport_s *vport); +void bfa_fcs_lport_ns_query(struct bfa_fcs_lport_s *port); +void bfa_fcs_lport_scn_init(struct bfa_fcs_lport_s *vport); +void bfa_fcs_lport_scn_offline(struct bfa_fcs_lport_s *vport); +void bfa_fcs_lport_scn_online(struct bfa_fcs_lport_s *vport); +void bfa_fcs_lport_scn_process_rscn(struct bfa_fcs_lport_s *port, + struct fchs_s *rx_frame, u32 len); + +struct bfa_fcs_vport_s { + struct list_head qe; /* queue elem */ + bfa_sm_t sm; /* state machine */ + bfa_fcs_lport_t lport; /* logical port */ + struct bfa_timer_s timer; + struct bfad_vport_s *vport_drv; /* Driver private */ + struct bfa_vport_stats_s vport_stats; /* vport statistics */ + struct bfa_lps_s *lps; /* Lport login service*/ + int fdisc_retries; +}; + +#define bfa_fcs_vport_get_port(vport) \ + ((struct bfa_fcs_lport_s *)(&vport->port)) + +/** + * bfa fcs vport public functions + */ +bfa_status_t bfa_fcs_vport_create(struct bfa_fcs_vport_s *vport, + struct bfa_fcs_s *fcs, u16 vf_id, + struct bfa_lport_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, u16 vf_id, + struct bfa_lport_cfg_s *port_cfg, + struct bfad_vport_s *vport_drv); +bfa_boolean_t bfa_fcs_is_pbc_vport(struct bfa_fcs_vport_s *vport); +bfa_status_t bfa_fcs_vport_delete(struct bfa_fcs_vport_s *vport); +bfa_status_t bfa_fcs_vport_start(struct bfa_fcs_vport_s *vport); +bfa_status_t bfa_fcs_vport_stop(struct bfa_fcs_vport_s *vport); +void bfa_fcs_vport_get_attr(struct bfa_fcs_vport_s *vport, + struct bfa_vport_attr_s *vport_attr); +void bfa_fcs_vport_get_stats(struct bfa_fcs_vport_s *vport, + struct bfa_vport_stats_s *vport_stats); +void bfa_fcs_vport_clr_stats(struct bfa_fcs_vport_s *vport); +struct bfa_fcs_vport_s *bfa_fcs_vport_lookup(struct bfa_fcs_s *fcs, + u16 vf_id, wwn_t vpwwn); +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); + +#define BFA_FCS_RPORT_DEF_DEL_TIMEOUT 90 /* in secs */ +#define BFA_FCS_RPORT_MAX_RETRIES (5) + +/* + * forward declarations + */ +struct bfad_rport_s; + +struct bfa_fcs_itnim_s; +struct bfa_fcs_tin_s; +struct bfa_fcs_iprp_s; + +/* Rport Features (RPF) */ +struct bfa_fcs_rpf_s { + bfa_sm_t sm; /* state machine */ + struct bfa_fcs_rport_s *rport; /* parent rport */ + struct bfa_timer_s timer; /* general purpose timer */ + struct bfa_fcxp_s *fcxp; /* FCXP needed for discarding */ + struct bfa_fcxp_wqe_s fcxp_wqe; /* fcxp wait queue element */ + int rpsc_retries; /* max RPSC retry attempts */ + enum bfa_port_speed rpsc_speed; + /* Current Speed from RPSC. O if RPSC fails */ + enum bfa_port_speed assigned_speed; + /** + * Speed assigned by the user. will be used if RPSC is + * not supported by the rport. + */ +}; + +struct bfa_fcs_rport_s { + struct list_head qe; /* used by port/vport */ + struct bfa_fcs_lport_s *port; /* parent FCS port */ + struct bfa_fcs_s *fcs; /* fcs instance */ + struct bfad_rport_s *rp_drv; /* driver peer instance */ + u32 pid; /* port ID of rport */ + u16 maxfrsize; /* maximum frame size */ + u16 reply_oxid; /* OX_ID of inbound requests */ + enum fc_cos fc_cos; /* FC classes of service supp */ + bfa_boolean_t cisc; /* CISC capable device */ + 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 */ + bfa_sm_t sm; /* state machine */ + struct bfa_timer_s timer; /* general purpose timer */ + struct bfa_fcs_itnim_s *itnim; /* ITN initiator mode role */ + struct bfa_fcs_tin_s *tin; /* ITN initiator mode role */ + struct bfa_fcs_iprp_s *iprp; /* IP/FC role */ + struct bfa_rport_s *bfa_rport; /* BFA Rport */ + struct bfa_fcxp_s *fcxp; /* FCXP needed for discarding */ + int plogi_retries; /* max plogi retry attempts */ + int ns_retries; /* max NS query retry attempts */ + struct bfa_fcxp_wqe_s fcxp_wqe; /* fcxp wait queue element */ + struct bfa_rport_stats_s stats; /* rport stats */ + enum bfa_rport_function scsi_function; /* Initiator/Target */ + struct bfa_fcs_rpf_s rpf; /* Rport features module */ +}; + +static inline struct bfa_rport_s * +bfa_fcs_rport_get_halrport(struct bfa_fcs_rport_s *rport) +{ + return rport->bfa_rport; +} + +/** + * bfa fcs rport API functions + */ +bfa_status_t bfa_fcs_rport_add(struct bfa_fcs_lport_s *port, wwn_t *pwwn, + struct bfa_fcs_rport_s *rport, + struct bfad_rport_s *rport_drv); +bfa_status_t bfa_fcs_rport_remove(struct bfa_fcs_rport_s *rport); +void bfa_fcs_rport_get_attr(struct bfa_fcs_rport_s *rport, + struct bfa_rport_attr_s *attr); +void bfa_fcs_rport_get_stats(struct bfa_fcs_rport_s *rport, + struct bfa_rport_stats_s *stats); +void bfa_fcs_rport_clear_stats(struct bfa_fcs_rport_s *rport); +struct bfa_fcs_rport_s *bfa_fcs_rport_lookup(struct bfa_fcs_lport_s *port, + wwn_t rpwwn); +struct bfa_fcs_rport_s *bfa_fcs_rport_lookup_by_nwwn( + struct bfa_fcs_lport_s *port, wwn_t rnwwn); +void bfa_fcs_rport_set_del_timeout(u8 rport_tmo); + +void bfa_fcs_rport_set_speed(struct bfa_fcs_rport_s *rport, + enum bfa_port_speed speed); +void bfa_fcs_rport_uf_recv(struct bfa_fcs_rport_s *rport, + struct fchs_s *fchs, u16 len); +void bfa_fcs_rport_scn(struct bfa_fcs_rport_s *rport); + +struct bfa_fcs_rport_s *bfa_fcs_rport_create(struct bfa_fcs_lport_s *port, + u32 pid); +void bfa_fcs_rport_delete(struct bfa_fcs_rport_s *rport); +void bfa_fcs_rport_online(struct bfa_fcs_rport_s *rport); +void bfa_fcs_rport_offline(struct bfa_fcs_rport_s *rport); +void bfa_fcs_rport_start(struct bfa_fcs_lport_s *port, struct fchs_s *rx_fchs, + struct fc_logi_s *plogi_rsp); +void bfa_fcs_rport_plogi_create(struct bfa_fcs_lport_s *port, + struct fchs_s *rx_fchs, + struct fc_logi_s *plogi); +void bfa_fcs_rport_plogi(struct bfa_fcs_rport_s *rport, struct fchs_s *fchs, + struct fc_logi_s *plogi); +void bfa_fcs_rport_logo_imp(struct bfa_fcs_rport_s *rport); +void bfa_fcs_rport_prlo(struct bfa_fcs_rport_s *rport, u16 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_fcptm_offline_done(struct bfa_fcs_rport_s *rport); +int bfa_fcs_rport_get_state(struct bfa_fcs_rport_s *rport); +struct bfa_fcs_rport_s *bfa_fcs_rport_create_by_wwn( + struct bfa_fcs_lport_s *port, wwn_t wwn); +void bfa_fcs_rpf_init(struct bfa_fcs_rport_s *rport); +void bfa_fcs_rpf_rport_online(struct bfa_fcs_rport_s *rport); +void bfa_fcs_rpf_rport_offline(struct bfa_fcs_rport_s *rport); + +/* + * forward declarations + */ +struct bfad_itnim_s; + +struct bfa_fcs_itnim_s { + bfa_sm_t sm; /* state machine */ + struct bfa_fcs_rport_s *rport; /* parent remote rport */ + struct bfad_itnim_s *itnim_drv; /* driver peer instance */ + struct bfa_fcs_s *fcs; /* fcs instance */ + struct bfa_timer_s timer; /* timer functions */ + struct bfa_itnim_s *bfa_itnim; /* BFA itnim struct */ + 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 */ + bfa_boolean_t task_retry_id; /* task retry id supp */ + struct bfa_fcxp_wqe_s fcxp_wqe; /* wait qelem for fcxp */ + struct bfa_fcxp_s *fcxp; /* FCXP in use */ + struct bfa_itnim_stats_s stats; /* itn statistics */ +}; +#define bfa_fcs_fcxp_alloc(__fcs) \ + bfa_fcxp_alloc(NULL, (__fcs)->bfa, 0, 0, NULL, NULL, NULL, NULL) + +#define bfa_fcs_fcxp_alloc_wait(__bfa, __wqe, __alloc_cbfn, __alloc_cbarg) \ + bfa_fcxp_alloc_wait(__bfa, __wqe, __alloc_cbfn, __alloc_cbarg, \ + NULL, 0, 0, NULL, NULL, NULL, NULL) + +static inline struct bfad_port_s * +bfa_fcs_itnim_get_drvport(struct bfa_fcs_itnim_s *itnim) +{ + return itnim->rport->port->bfad_port; +} + + +static inline struct bfa_fcs_lport_s * +bfa_fcs_itnim_get_port(struct bfa_fcs_itnim_s *itnim) +{ + return itnim->rport->port; +} + + +static inline wwn_t +bfa_fcs_itnim_get_nwwn(struct bfa_fcs_itnim_s *itnim) +{ + return itnim->rport->nwwn; +} + + +static inline wwn_t +bfa_fcs_itnim_get_pwwn(struct bfa_fcs_itnim_s *itnim) +{ + return itnim->rport->pwwn; +} + + +static inline u32 +bfa_fcs_itnim_get_fcid(struct bfa_fcs_itnim_s *itnim) +{ + return itnim->rport->pid; +} + + +static inline u32 +bfa_fcs_itnim_get_maxfrsize(struct bfa_fcs_itnim_s *itnim) +{ + return itnim->rport->maxfrsize; +} + + +static inline enum fc_cos +bfa_fcs_itnim_get_cos(struct bfa_fcs_itnim_s *itnim) +{ + return itnim->rport->fc_cos; +} + + +static inline struct bfad_itnim_s * +bfa_fcs_itnim_get_drvitn(struct bfa_fcs_itnim_s *itnim) +{ + return itnim->itnim_drv; +} + + +static inline struct bfa_itnim_s * +bfa_fcs_itnim_get_halitn(struct bfa_fcs_itnim_s *itnim) +{ + return itnim->bfa_itnim; +} + +/** + * bfa fcs FCP Initiator mode API functions + */ +void bfa_fcs_itnim_get_attr(struct bfa_fcs_itnim_s *itnim, + struct bfa_itnim_attr_s *attr); +void bfa_fcs_itnim_get_stats(struct bfa_fcs_itnim_s *itnim, + struct bfa_itnim_stats_s *stats); +struct bfa_fcs_itnim_s *bfa_fcs_itnim_lookup(struct bfa_fcs_lport_s *port, + wwn_t rpwwn); +bfa_status_t bfa_fcs_itnim_attr_get(struct bfa_fcs_lport_s *port, wwn_t rpwwn, + struct bfa_itnim_attr_s *attr); +bfa_status_t bfa_fcs_itnim_stats_get(struct bfa_fcs_lport_s *port, wwn_t rpwwn, + struct bfa_itnim_stats_s *stats); +bfa_status_t bfa_fcs_itnim_stats_clear(struct bfa_fcs_lport_s *port, + wwn_t rpwwn); +struct bfa_fcs_itnim_s *bfa_fcs_itnim_create(struct bfa_fcs_rport_s *rport); +void bfa_fcs_itnim_delete(struct bfa_fcs_itnim_s *itnim); +void bfa_fcs_itnim_rport_offline(struct bfa_fcs_itnim_s *itnim); +void bfa_fcs_itnim_rport_online(struct bfa_fcs_itnim_s *itnim); +bfa_status_t bfa_fcs_itnim_get_online_state(struct bfa_fcs_itnim_s *itnim); +void bfa_fcs_itnim_is_initiator(struct bfa_fcs_itnim_s *itnim); +void bfa_fcs_fcpim_uf_recv(struct bfa_fcs_itnim_s *itnim, + struct fchs_s *fchs, u16 len); + +#define BFA_FCS_FDMI_SUPORTED_SPEEDS (FDMI_TRANS_SPEED_1G | \ + FDMI_TRANS_SPEED_2G | \ + FDMI_TRANS_SPEED_4G | \ + FDMI_TRANS_SPEED_8G) + +/* + * HBA Attribute Block : BFA internal representation. Note : Some variable + * sizes have been trimmed to suit BFA For Ex : Model will be "Brocade". Based + * on this the size has been reduced to 16 bytes from the standard's 64 bytes. + */ +struct bfa_fcs_fdmi_hba_attr_s { + wwn_t node_name; + u8 manufacturer[64]; + u8 serial_num[64]; + u8 model[16]; + u8 model_desc[256]; + u8 hw_version[8]; + u8 driver_version[8]; + u8 option_rom_ver[BFA_VERSION_LEN]; + u8 fw_version[8]; + u8 os_name[256]; + u32 max_ct_pyld; +}; + +/* + * Port Attribute Block + */ +struct bfa_fcs_fdmi_port_attr_s { + u8 supp_fc4_types[32]; /* supported FC4 types */ + u32 supp_speed; /* supported speed */ + u32 curr_speed; /* current Speed */ + u32 max_frm_size; /* max frame size */ + u8 os_device_name[256]; /* OS device Name */ + u8 host_name[256]; /* host name */ +}; + +struct bfa_fcs_stats_s { + struct { + u32 untagged; /* untagged receive frames */ + u32 tagged; /* tagged receive frames */ + u32 vfid_unknown; /* VF id is unknown */ + } uf; +}; + +struct bfa_fcs_driver_info_s { + u8 version[BFA_VERSION_LEN]; /* Driver Version */ + u8 host_machine_name[BFA_FCS_OS_STR_LEN]; + u8 host_os_name[BFA_FCS_OS_STR_LEN]; /* OS name and version */ + u8 host_os_patch[BFA_FCS_OS_STR_LEN]; /* patch or service pack */ + u8 os_device_name[BFA_FCS_OS_STR_LEN]; /* Driver Device Name */ +}; + +struct bfa_fcs_s { + struct bfa_s *bfa; /* corresponding BFA bfa instance */ + struct bfad_s *bfad; /* corresponding BDA driver instance */ + struct bfa_trc_mod_s *trcmod; /* tracing module */ + bfa_boolean_t vf_enabled; /* VF mode is enabled */ + bfa_boolean_t fdmi_enabled; /* FDMI is enabled */ + bfa_boolean_t min_cfg; /* min cfg enabled/disabled */ + u16 port_vfid; /* port default VF ID */ + struct bfa_fcs_driver_info_s driver_info; + struct bfa_fcs_fabric_s fabric; /* base fabric state machine */ + struct bfa_fcs_stats_s stats; /* FCS statistics */ + struct bfa_wc_s wc; /* waiting counter */ +}; + +/* + * bfa fcs API functions + */ +void bfa_fcs_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); +void bfa_fcs_set_fdmi_param(struct bfa_fcs_s *fcs, bfa_boolean_t fdmi_enable); +void bfa_fcs_exit(struct bfa_fcs_s *fcs); +void bfa_fcs_trc_init(struct bfa_fcs_s *fcs, struct bfa_trc_mod_s *trcmod); +void bfa_fcs_start(struct bfa_fcs_s *fcs); + +/** + * bfa fcs vf public functions + */ +bfa_status_t bfa_fcs_vf_mode_enable(struct bfa_fcs_s *fcs, u16 vf_id); +bfa_status_t bfa_fcs_vf_mode_disable(struct bfa_fcs_s *fcs); +bfa_status_t bfa_fcs_vf_create(bfa_fcs_vf_t *vf, struct bfa_fcs_s *fcs, + u16 vf_id, struct bfa_lport_cfg_s *port_cfg, + struct bfad_vf_s *vf_drv); +bfa_status_t bfa_fcs_vf_delete(bfa_fcs_vf_t *vf); +void bfa_fcs_vf_list(struct bfa_fcs_s *fcs, u16 *vf_ids, int *nvfs); +void bfa_fcs_vf_list_all(struct bfa_fcs_s *fcs, u16 *vf_ids, int *nvfs); +void bfa_fcs_vf_get_attr(bfa_fcs_vf_t *vf, struct bfa_vf_attr_s *vf_attr); +void bfa_fcs_vf_get_stats(bfa_fcs_vf_t *vf, + struct bfa_vf_stats_s *vf_stats); +void bfa_fcs_vf_clear_stats(bfa_fcs_vf_t *vf); +void bfa_fcs_vf_get_ports(bfa_fcs_vf_t *vf, wwn_t vpwwn[], int *nports); +bfa_fcs_vf_t *bfa_fcs_vf_lookup(struct bfa_fcs_s *fcs, u16 vf_id); +u16 bfa_fcs_fabric_vport_count(struct bfa_fcs_fabric_s *fabric); + +/* + * fabric protected interface functions + */ +void bfa_fcs_fabric_attach(struct bfa_fcs_s *fcs); +void bfa_fcs_fabric_modinit(struct bfa_fcs_s *fcs); +void bfa_fcs_fabric_modexit(struct bfa_fcs_s *fcs); +void bfa_fcs_fabric_modsusp(struct bfa_fcs_s *fcs); +void bfa_fcs_fabric_link_up(struct bfa_fcs_fabric_s *fabric); +void bfa_fcs_fabric_link_down(struct bfa_fcs_fabric_s *fabric); +void bfa_fcs_fabric_addvport(struct bfa_fcs_fabric_s *fabric, + struct bfa_fcs_vport_s *vport); +void bfa_fcs_fabric_delvport(struct bfa_fcs_fabric_s *fabric, + struct bfa_fcs_vport_s *vport); +int bfa_fcs_fabric_is_online(struct bfa_fcs_fabric_s *fabric); +struct bfa_fcs_vport_s *bfa_fcs_fabric_vport_lookup( + struct bfa_fcs_fabric_s *fabric, wwn_t pwwn); +void bfa_fcs_fabric_modstart(struct bfa_fcs_s *fcs); +void bfa_fcs_fabric_uf_recv(struct bfa_fcs_fabric_s *fabric, + struct fchs_s *fchs, u16 len); +bfa_boolean_t bfa_fcs_fabric_is_loopback(struct bfa_fcs_fabric_s *fabric); +bfa_boolean_t bfa_fcs_fabric_is_auth_failed(struct bfa_fcs_fabric_s *fabric); +enum bfa_port_type bfa_fcs_fabric_port_type(struct bfa_fcs_fabric_s *fabric); +void bfa_fcs_fabric_psymb_init(struct bfa_fcs_fabric_s *fabric); +void bfa_fcs_fabric_port_delete_comp(struct bfa_fcs_fabric_s *fabric); +bfa_status_t bfa_fcs_fabric_addvf(struct bfa_fcs_fabric_s *vf, + struct bfa_fcs_s *fcs, struct bfa_lport_cfg_s *port_cfg, + struct bfad_vf_s *vf_drv); +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_uf_attach(struct bfa_fcs_s *fcs); +void bfa_fcs_port_attach(struct bfa_fcs_s *fcs); + +/** + * BFA FCS callback interfaces + */ + +/** + * fcb Main fcs callbacks + */ + +struct bfad_port_s; +struct bfad_vf_s; +struct bfad_vport_s; +struct bfad_rport_s; + +/** + * lport callbacks + */ +struct bfad_port_s *bfa_fcb_lport_new(struct bfad_s *bfad, + struct bfa_fcs_lport_s *port, + enum bfa_lport_role roles, + struct bfad_vf_s *vf_drv, + struct bfad_vport_s *vp_drv); +void bfa_fcb_lport_delete(struct bfad_s *bfad, enum bfa_lport_role roles, + struct bfad_vf_s *vf_drv, + struct bfad_vport_s *vp_drv); + +/** + * vport callbacks + */ +void bfa_fcb_pbc_vport_create(struct bfad_s *bfad, struct bfi_pbc_vport_s); + +/** + * rport callbacks + */ +bfa_status_t bfa_fcb_rport_alloc(struct bfad_s *bfad, + struct bfa_fcs_rport_s **rport, + struct bfad_rport_s **rport_drv); + +/** + * itnim callbacks + */ +void bfa_fcb_itnim_alloc(struct bfad_s *bfad, struct bfa_fcs_itnim_s **itnim, + struct bfad_itnim_s **itnim_drv); +void bfa_fcb_itnim_free(struct bfad_s *bfad, + struct bfad_itnim_s *itnim_drv); +void bfa_fcb_itnim_online(struct bfad_itnim_s *itnim_drv); +void bfa_fcb_itnim_offline(struct bfad_itnim_s *itnim_drv); + +#endif /* __BFA_FCS_H__ */ diff --git a/drivers/scsi/bfa/fcpim.c b/drivers/scsi/bfa/bfa_fcs_fcpim.c index 6b8976ad22fa..569dfefab70d 100644 --- a/drivers/scsi/bfa/fcpim.c +++ b/drivers/scsi/bfa/bfa_fcs_fcpim.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. * All rights reserved * www.brocade.com * @@ -19,36 +19,24 @@ * fcpim.c - FCP initiator mode i-t nexus state machine */ -#include <bfa.h> -#include <bfa_svc.h> -#include "fcs_fcpim.h" -#include "fcs_rport.h" -#include "fcs_lport.h" -#include "fcs_trcmod.h" -#include "fcs_fcxp.h" -#include "fcs.h" -#include <fcs/bfa_fcs_fcpim.h> -#include <fcb/bfa_fcb_fcpim.h> -#include <aen/bfa_aen_itnim.h> +#include "bfa_fcs.h" +#include "bfa_fcbuild.h" +#include "bfad_drv.h" +#include "bfad_im.h" BFA_TRC_FILE(FCS, FCPIM); /* * forward declarations */ -static void bfa_fcs_itnim_timeout(void *arg); -static void bfa_fcs_itnim_free(struct bfa_fcs_itnim_s *itnim); -static void bfa_fcs_itnim_send_prli(void *itnim_cbarg, +static void bfa_fcs_itnim_timeout(void *arg); +static void bfa_fcs_itnim_free(struct bfa_fcs_itnim_s *itnim); +static void bfa_fcs_itnim_send_prli(void *itnim_cbarg, struct bfa_fcxp_s *fcxp_alloced); -static void bfa_fcs_itnim_prli_response(void *fcsarg, - struct bfa_fcxp_s *fcxp, - void *cbarg, - bfa_status_t req_status, - u32 rsp_len, - u32 resid_len, - struct fchs_s *rsp_fchs); -static void bfa_fcs_itnim_aen_post(struct bfa_fcs_itnim_s *itnim, - enum bfa_itnim_aen_event event); +static void bfa_fcs_itnim_prli_response(void *fcsarg, + struct bfa_fcxp_s *fcxp, void *cbarg, + bfa_status_t req_status, u32 rsp_len, + u32 resid_len, struct fchs_s *rsp_fchs); /** * fcs_itnim_sm FCS itnim state machine events @@ -61,28 +49,28 @@ enum bfa_fcs_itnim_event { BFA_FCS_ITNIM_SM_RSP_OK = 4, /* good response */ BFA_FCS_ITNIM_SM_RSP_ERROR = 5, /* error response */ BFA_FCS_ITNIM_SM_TIMEOUT = 6, /* delay timeout */ - BFA_FCS_ITNIM_SM_HCB_OFFLINE = 7, /* BFA online callback */ - BFA_FCS_ITNIM_SM_HCB_ONLINE = 8, /* BFA offline callback */ + BFA_FCS_ITNIM_SM_HCB_OFFLINE = 7, /* BFA online callback */ + BFA_FCS_ITNIM_SM_HCB_ONLINE = 8, /* BFA offline callback */ BFA_FCS_ITNIM_SM_INITIATOR = 9, /* rport is initiator */ BFA_FCS_ITNIM_SM_DELETE = 10, /* delete event from rport */ BFA_FCS_ITNIM_SM_PRLO = 11, /* delete event from rport */ }; -static void bfa_fcs_itnim_sm_offline(struct bfa_fcs_itnim_s *itnim, +static void bfa_fcs_itnim_sm_offline(struct bfa_fcs_itnim_s *itnim, enum bfa_fcs_itnim_event event); -static void bfa_fcs_itnim_sm_prli_send(struct bfa_fcs_itnim_s *itnim, +static void bfa_fcs_itnim_sm_prli_send(struct bfa_fcs_itnim_s *itnim, enum bfa_fcs_itnim_event event); -static void bfa_fcs_itnim_sm_prli(struct bfa_fcs_itnim_s *itnim, +static void bfa_fcs_itnim_sm_prli(struct bfa_fcs_itnim_s *itnim, enum bfa_fcs_itnim_event event); -static void bfa_fcs_itnim_sm_prli_retry(struct bfa_fcs_itnim_s *itnim, +static void bfa_fcs_itnim_sm_prli_retry(struct bfa_fcs_itnim_s *itnim, enum bfa_fcs_itnim_event event); -static void bfa_fcs_itnim_sm_hcb_online(struct bfa_fcs_itnim_s *itnim, +static void bfa_fcs_itnim_sm_hcb_online(struct bfa_fcs_itnim_s *itnim, enum bfa_fcs_itnim_event event); -static void bfa_fcs_itnim_sm_online(struct bfa_fcs_itnim_s *itnim, +static void bfa_fcs_itnim_sm_online(struct bfa_fcs_itnim_s *itnim, enum bfa_fcs_itnim_event event); -static void bfa_fcs_itnim_sm_hcb_offline(struct bfa_fcs_itnim_s *itnim, +static void bfa_fcs_itnim_sm_hcb_offline(struct bfa_fcs_itnim_s *itnim, enum bfa_fcs_itnim_event event); -static void bfa_fcs_itnim_sm_initiator(struct bfa_fcs_itnim_s *itnim, +static void bfa_fcs_itnim_sm_initiator(struct bfa_fcs_itnim_s *itnim, enum bfa_fcs_itnim_event event); static struct bfa_sm_table_s itnim_sm_table[] = { @@ -102,7 +90,7 @@ static struct bfa_sm_table_s itnim_sm_table[] = { static void bfa_fcs_itnim_sm_offline(struct bfa_fcs_itnim_s *itnim, - enum bfa_fcs_itnim_event event) + enum bfa_fcs_itnim_event event) { bfa_trc(itnim->fcs, itnim->rport->pwwn); bfa_trc(itnim->fcs, event); @@ -134,7 +122,7 @@ bfa_fcs_itnim_sm_offline(struct bfa_fcs_itnim_s *itnim, static void bfa_fcs_itnim_sm_prli_send(struct bfa_fcs_itnim_s *itnim, - enum bfa_fcs_itnim_event event) + enum bfa_fcs_itnim_event event) { bfa_trc(itnim->fcs, itnim->rport->pwwn); bfa_trc(itnim->fcs, event); @@ -168,7 +156,7 @@ bfa_fcs_itnim_sm_prli_send(struct bfa_fcs_itnim_s *itnim, static void bfa_fcs_itnim_sm_prli(struct bfa_fcs_itnim_s *itnim, - enum bfa_fcs_itnim_event event) + enum bfa_fcs_itnim_event event) { bfa_trc(itnim->fcs, itnim->rport->pwwn); bfa_trc(itnim->fcs, event); @@ -233,6 +221,7 @@ bfa_fcs_itnim_sm_prli_retry(struct bfa_fcs_itnim_s *itnim, } break; + case BFA_FCS_ITNIM_SM_OFFLINE: bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline); bfa_timer_stop(&itnim->timer); @@ -259,6 +248,10 @@ static void bfa_fcs_itnim_sm_hcb_online(struct bfa_fcs_itnim_s *itnim, enum bfa_fcs_itnim_event event) { + struct bfad_s *bfad = (struct bfad_s *)itnim->fcs->bfad; + char lpwwn_buf[BFA_STRING_32]; + char rpwwn_buf[BFA_STRING_32]; + bfa_trc(itnim->fcs, itnim->rport->pwwn); bfa_trc(itnim->fcs, event); @@ -266,7 +259,11 @@ bfa_fcs_itnim_sm_hcb_online(struct bfa_fcs_itnim_s *itnim, case BFA_FCS_ITNIM_SM_HCB_ONLINE: bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_online); bfa_fcb_itnim_online(itnim->itnim_drv); - bfa_fcs_itnim_aen_post(itnim, BFA_ITNIM_AEN_ONLINE); + wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(itnim->rport->port)); + wwn2str(rpwwn_buf, itnim->rport->pwwn); + BFA_LOG(KERN_INFO, bfad, log_level, + "Target (WWN = %s) is online for initiator (WWN = %s)\n", + rpwwn_buf, lpwwn_buf); break; case BFA_FCS_ITNIM_SM_OFFLINE: @@ -287,8 +284,12 @@ bfa_fcs_itnim_sm_hcb_online(struct bfa_fcs_itnim_s *itnim, static void bfa_fcs_itnim_sm_online(struct bfa_fcs_itnim_s *itnim, - enum bfa_fcs_itnim_event event) + enum bfa_fcs_itnim_event event) { + struct bfad_s *bfad = (struct bfad_s *)itnim->fcs->bfad; + char lpwwn_buf[BFA_STRING_32]; + char rpwwn_buf[BFA_STRING_32]; + bfa_trc(itnim->fcs, itnim->rport->pwwn); bfa_trc(itnim->fcs, event); @@ -297,10 +298,16 @@ bfa_fcs_itnim_sm_online(struct bfa_fcs_itnim_s *itnim, bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_hcb_offline); bfa_fcb_itnim_offline(itnim->itnim_drv); bfa_itnim_offline(itnim->bfa_itnim); - if (bfa_fcs_port_is_online(itnim->rport->port) == BFA_TRUE) - bfa_fcs_itnim_aen_post(itnim, BFA_ITNIM_AEN_DISCONNECT); + wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(itnim->rport->port)); + wwn2str(rpwwn_buf, itnim->rport->pwwn); + if (bfa_fcs_lport_is_online(itnim->rport->port) == BFA_TRUE) + BFA_LOG(KERN_ERR, bfad, log_level, + "Target (WWN = %s) connectivity lost for " + "initiator (WWN = %s)\n", rpwwn_buf, lpwwn_buf); else - bfa_fcs_itnim_aen_post(itnim, BFA_ITNIM_AEN_OFFLINE); + BFA_LOG(KERN_INFO, bfad, log_level, + "Target (WWN = %s) offlined by initiator (WWN = %s)\n", + rpwwn_buf, lpwwn_buf); break; case BFA_FCS_ITNIM_SM_DELETE: @@ -343,7 +350,7 @@ bfa_fcs_itnim_sm_hcb_offline(struct bfa_fcs_itnim_s *itnim, */ static void bfa_fcs_itnim_sm_initiator(struct bfa_fcs_itnim_s *itnim, - enum bfa_fcs_itnim_event event) + enum bfa_fcs_itnim_event event) { bfa_trc(itnim->fcs, itnim->rport->pwwn); bfa_trc(itnim->fcs, event); @@ -369,71 +376,34 @@ bfa_fcs_itnim_sm_initiator(struct bfa_fcs_itnim_s *itnim, } } - - -/** - * itnim_private FCS ITNIM private interfaces - */ - -static void -bfa_fcs_itnim_aen_post(struct bfa_fcs_itnim_s *itnim, - enum bfa_itnim_aen_event event) -{ - struct bfa_fcs_rport_s *rport = itnim->rport; - union bfa_aen_data_u aen_data; - struct bfa_log_mod_s *logmod = rport->fcs->logm; - wwn_t lpwwn = bfa_fcs_port_get_pwwn(rport->port); - wwn_t rpwwn = rport->pwwn; - char lpwwn_ptr[BFA_STRING_32]; - char rpwwn_ptr[BFA_STRING_32]; - - /* - * Don't post events for well known addresses - */ - if (BFA_FCS_PID_IS_WKA(rport->pid)) - return; - - wwn2str(lpwwn_ptr, lpwwn); - wwn2str(rpwwn_ptr, rpwwn); - - bfa_log(logmod, BFA_LOG_CREATE_ID(BFA_AEN_CAT_ITNIM, event), - rpwwn_ptr, lpwwn_ptr); - - aen_data.itnim.vf_id = rport->port->fabric->vf_id; - aen_data.itnim.ppwwn = - bfa_fcs_port_get_pwwn(bfa_fcs_get_base_port(itnim->fcs)); - aen_data.itnim.lpwwn = lpwwn; - aen_data.itnim.rpwwn = rpwwn; -} - static void bfa_fcs_itnim_send_prli(void *itnim_cbarg, struct bfa_fcxp_s *fcxp_alloced) { struct bfa_fcs_itnim_s *itnim = itnim_cbarg; struct bfa_fcs_rport_s *rport = itnim->rport; - struct bfa_fcs_port_s *port = rport->port; - struct fchs_s fchs; + struct bfa_fcs_lport_s *port = rport->port; + struct fchs_s fchs; struct bfa_fcxp_s *fcxp; - int len; + int len; bfa_trc(itnim->fcs, itnim->rport->pwwn); fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); if (!fcxp) { itnim->stats.fcxp_alloc_wait++; - bfa_fcxp_alloc_wait(port->fcs->bfa, &itnim->fcxp_wqe, + bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &itnim->fcxp_wqe, bfa_fcs_itnim_send_prli, itnim); return; } itnim->fcxp = fcxp; - len = fc_prli_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), itnim->rport->pid, - bfa_fcs_port_get_fcid(port), 0); + len = fc_prli_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), + itnim->rport->pid, bfa_fcs_lport_get_fcid(port), 0); bfa_fcxp_send(fcxp, rport->bfa_rport, port->fabric->vf_id, port->lp_tag, BFA_FALSE, FC_CLASS_3, len, &fchs, - bfa_fcs_itnim_prli_response, (void *)itnim, FC_MAX_PDUSZ, - FC_ELS_TOV); + bfa_fcs_itnim_prli_response, (void *)itnim, + FC_MAX_PDUSZ, FC_ELS_TOV); itnim->stats.prli_sent++; bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_FRMSENT); @@ -444,10 +414,10 @@ bfa_fcs_itnim_prli_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg, bfa_status_t req_status, u32 rsp_len, u32 resid_len, struct fchs_s *rsp_fchs) { - struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *)cbarg; - struct fc_els_cmd_s *els_cmd; - struct fc_prli_s *prli_resp; - struct fc_ls_rjt_s *ls_rjt; + struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cbarg; + struct fc_els_cmd_s *els_cmd; + struct fc_prli_s *prli_resp; + struct fc_ls_rjt_s *ls_rjt; struct fc_prli_params_s *sparams; bfa_trc(itnim->fcs, req_status); @@ -475,7 +445,7 @@ bfa_fcs_itnim_prli_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg, if (prli_resp->parampage.servparams.initiator) { bfa_trc(itnim->fcs, prli_resp->parampage.type); itnim->rport->scsi_function = - BFA_RPORT_INITIATOR; + BFA_RPORT_INITIATOR; itnim->stats.prli_rsp_acc++; bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_RSP_OK); @@ -488,10 +458,10 @@ bfa_fcs_itnim_prli_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg, itnim->rport->scsi_function = BFA_RPORT_TARGET; sparams = &prli_resp->parampage.servparams; - itnim->seq_rec = sparams->retry; - itnim->rec_support = sparams->rec_support; + itnim->seq_rec = sparams->retry; + itnim->rec_support = sparams->rec_support; itnim->task_retry_id = sparams->task_retry_id; - itnim->conf_comp = sparams->confirm; + itnim->conf_comp = sparams->confirm; itnim->stats.prli_rsp_acc++; bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_RSP_OK); @@ -509,7 +479,7 @@ bfa_fcs_itnim_prli_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg, static void bfa_fcs_itnim_timeout(void *arg) { - struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *)arg; + struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) arg; itnim->stats.timeout++; bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_TIMEOUT); @@ -529,16 +499,16 @@ bfa_fcs_itnim_free(struct bfa_fcs_itnim_s *itnim) */ /** - * Called by rport when a new rport is created. + * Called by rport when a new rport is created. * * @param[in] rport - remote port. */ struct bfa_fcs_itnim_s * bfa_fcs_itnim_create(struct bfa_fcs_rport_s *rport) { - struct bfa_fcs_port_s *port = rport->port; + struct bfa_fcs_lport_s *port = rport->port; struct bfa_fcs_itnim_s *itnim; - struct bfad_itnim_s *itnim_drv; + struct bfad_itnim_s *itnim_drv; struct bfa_itnim_s *bfa_itnim; /* @@ -560,7 +530,8 @@ bfa_fcs_itnim_create(struct bfa_fcs_rport_s *rport) /* * call BFA to create the itnim */ - bfa_itnim = bfa_itnim_create(port->fcs->bfa, rport->bfa_rport, itnim); + bfa_itnim = + bfa_itnim_create(port->fcs->bfa, rport->bfa_rport, itnim); if (bfa_itnim == NULL) { bfa_trc(port->fcs, rport->pwwn); @@ -569,10 +540,10 @@ bfa_fcs_itnim_create(struct bfa_fcs_rport_s *rport) return NULL; } - itnim->bfa_itnim = bfa_itnim; - itnim->seq_rec = BFA_FALSE; - itnim->rec_support = BFA_FALSE; - itnim->conf_comp = BFA_FALSE; + itnim->bfa_itnim = bfa_itnim; + itnim->seq_rec = BFA_FALSE; + itnim->rec_support = BFA_FALSE; + itnim->conf_comp = BFA_FALSE; itnim->task_retry_id = BFA_FALSE; /* @@ -584,7 +555,7 @@ bfa_fcs_itnim_create(struct bfa_fcs_rport_s *rport) } /** - * Called by rport to delete the instance of FCPIM. + * Called by rport to delete the instance of FCPIM. * * @param[in] rport - remote port. */ @@ -607,8 +578,8 @@ bfa_fcs_itnim_rport_online(struct bfa_fcs_itnim_s *itnim) bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_ONLINE); } else { /* - * For well known addresses, we set the itnim to initiator - * state + * For well known addresses, we set the itnim to initiator + * state */ itnim->stats.initiator++; bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_INITIATOR); @@ -651,7 +622,6 @@ bfa_fcs_itnim_get_online_state(struct bfa_fcs_itnim_s *itnim) default: return BFA_STATUS_NO_FCPIM_NEXUS; - } } @@ -661,7 +631,7 @@ bfa_fcs_itnim_get_online_state(struct bfa_fcs_itnim_s *itnim) void bfa_cb_itnim_online(void *cbarg) { - struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *)cbarg; + struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cbarg; bfa_trc(itnim->fcs, itnim->rport->pwwn); bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_HCB_ONLINE); @@ -673,7 +643,7 @@ bfa_cb_itnim_online(void *cbarg) void bfa_cb_itnim_offline(void *cb_arg) { - struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *)cb_arg; + struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cb_arg; bfa_trc(itnim->fcs, itnim->rport->pwwn); bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_HCB_OFFLINE); @@ -686,7 +656,7 @@ bfa_cb_itnim_offline(void *cb_arg) void bfa_cb_itnim_tov_begin(void *cb_arg) { - struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *)cb_arg; + struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cb_arg; bfa_trc(itnim->fcs, itnim->rport->pwwn); } @@ -697,14 +667,15 @@ bfa_cb_itnim_tov_begin(void *cb_arg) void bfa_cb_itnim_tov(void *cb_arg) { - struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *)cb_arg; + struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cb_arg; + struct bfad_itnim_s *itnim_drv = itnim->itnim_drv; bfa_trc(itnim->fcs, itnim->rport->pwwn); - bfa_fcb_itnim_tov(itnim->itnim_drv); + itnim_drv->state = ITNIM_STATE_TIMEOUT; } /** - * BFA notification to FCS/driver for second level error recovery. + * BFA notification to FCS/driver for second level error recovery. * * Atleast one I/O request has timedout and target is unresponsive to * repeated abort requests. Second level error recovery should be initiated @@ -713,7 +684,7 @@ bfa_cb_itnim_tov(void *cb_arg) void bfa_cb_itnim_sler(void *cb_arg) { - struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *)cb_arg; + struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cb_arg; itnim->stats.sler++; bfa_trc(itnim->fcs, itnim->rport->pwwn); @@ -721,7 +692,7 @@ bfa_cb_itnim_sler(void *cb_arg) } struct bfa_fcs_itnim_s * -bfa_fcs_itnim_lookup(struct bfa_fcs_port_s *port, wwn_t rpwwn) +bfa_fcs_itnim_lookup(struct bfa_fcs_lport_s *port, wwn_t rpwwn) { struct bfa_fcs_rport_s *rport; rport = bfa_fcs_rport_lookup(port, rpwwn); @@ -734,7 +705,7 @@ bfa_fcs_itnim_lookup(struct bfa_fcs_port_s *port, wwn_t rpwwn) } bfa_status_t -bfa_fcs_itnim_attr_get(struct bfa_fcs_port_s *port, wwn_t rpwwn, +bfa_fcs_itnim_attr_get(struct bfa_fcs_lport_s *port, wwn_t rpwwn, struct bfa_itnim_attr_s *attr) { struct bfa_fcs_itnim_s *itnim = NULL; @@ -744,18 +715,16 @@ bfa_fcs_itnim_attr_get(struct bfa_fcs_port_s *port, wwn_t rpwwn, if (itnim == NULL) return BFA_STATUS_NO_FCPIM_NEXUS; - attr->state = bfa_sm_to_state(itnim_sm_table, itnim->sm); - attr->retry = itnim->seq_rec; - attr->rec_support = itnim->rec_support; - attr->conf_comp = itnim->conf_comp; + attr->state = bfa_sm_to_state(itnim_sm_table, itnim->sm); + attr->retry = itnim->seq_rec; + attr->rec_support = itnim->rec_support; + attr->conf_comp = itnim->conf_comp; attr->task_retry_id = itnim->task_retry_id; - bfa_os_memset(&attr->io_latency, 0, sizeof(struct bfa_itnim_latency_s)); - return BFA_STATUS_OK; } bfa_status_t -bfa_fcs_itnim_stats_get(struct bfa_fcs_port_s *port, wwn_t rpwwn, +bfa_fcs_itnim_stats_get(struct bfa_fcs_lport_s *port, wwn_t rpwwn, struct bfa_itnim_stats_s *stats) { struct bfa_fcs_itnim_s *itnim = NULL; @@ -773,7 +742,7 @@ bfa_fcs_itnim_stats_get(struct bfa_fcs_port_s *port, wwn_t rpwwn, } bfa_status_t -bfa_fcs_itnim_stats_clear(struct bfa_fcs_port_s *port, wwn_t rpwwn) +bfa_fcs_itnim_stats_clear(struct bfa_fcs_lport_s *port, wwn_t rpwwn) { struct bfa_fcs_itnim_s *itnim = NULL; @@ -789,10 +758,10 @@ bfa_fcs_itnim_stats_clear(struct bfa_fcs_port_s *port, wwn_t rpwwn) } void -bfa_fcs_fcpim_uf_recv(struct bfa_fcs_itnim_s *itnim, struct fchs_s *fchs, - u16 len) +bfa_fcs_fcpim_uf_recv(struct bfa_fcs_itnim_s *itnim, + struct fchs_s *fchs, u16 len) { - struct fc_els_cmd_s *els_cmd; + struct fc_els_cmd_s *els_cmd; bfa_trc(itnim->fcs, fchs->type); @@ -812,13 +781,3 @@ bfa_fcs_fcpim_uf_recv(struct bfa_fcs_itnim_s *itnim, struct fchs_s *fchs, bfa_assert(0); } } - -void -bfa_fcs_itnim_pause(struct bfa_fcs_itnim_s *itnim) -{ -} - -void -bfa_fcs_itnim_resume(struct bfa_fcs_itnim_s *itnim) -{ -} diff --git a/drivers/scsi/bfa/bfa_fcs_lport.c b/drivers/scsi/bfa/bfa_fcs_lport.c index 35df20e68a52..b522bf30247a 100644 --- a/drivers/scsi/bfa/bfa_fcs_lport.c +++ b/drivers/scsi/bfa/bfa_fcs_lport.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. * All rights reserved * www.brocade.com * @@ -16,23 +16,13 @@ */ /** - * bfa_fcs_port.c BFA FCS port + * bfa_fcs_lport.c BFA FCS port */ -#include <fcs/bfa_fcs.h> -#include <fcs/bfa_fcs_lport.h> -#include <fcs/bfa_fcs_rport.h> -#include <fcb/bfa_fcb_port.h> -#include <bfa_svc.h> -#include <log/bfa_log_fcs.h> -#include "fcs.h" -#include "fcs_lport.h" -#include "fcs_vport.h" -#include "fcs_rport.h" -#include "fcs_fcxp.h" -#include "fcs_trcmod.h" -#include "lport_priv.h" -#include <aen/bfa_aen_lport.h> +#include "bfa_fcs.h" +#include "bfa_fcbuild.h" +#include "bfa_fc.h" +#include "bfad_drv.h" BFA_TRC_FILE(FCS, PORT); @@ -40,49 +30,53 @@ BFA_TRC_FILE(FCS, PORT); * Forward declarations */ -static void bfa_fcs_port_aen_post(struct bfa_fcs_port_s *port, - enum bfa_lport_aen_event event); -static void bfa_fcs_port_send_ls_rjt(struct bfa_fcs_port_s *port, - struct fchs_s *rx_fchs, u8 reason_code, - u8 reason_code_expl); -static void bfa_fcs_port_plogi(struct bfa_fcs_port_s *port, - struct fchs_s *rx_fchs, - struct fc_logi_s *plogi); -static void bfa_fcs_port_online_actions(struct bfa_fcs_port_s *port); -static void bfa_fcs_port_offline_actions(struct bfa_fcs_port_s *port); -static void bfa_fcs_port_unknown_init(struct bfa_fcs_port_s *port); -static void bfa_fcs_port_unknown_online(struct bfa_fcs_port_s *port); -static void bfa_fcs_port_unknown_offline(struct bfa_fcs_port_s *port); -static void bfa_fcs_port_deleted(struct bfa_fcs_port_s *port); -static void bfa_fcs_port_echo(struct bfa_fcs_port_s *port, +static void bfa_fcs_lport_send_ls_rjt(struct bfa_fcs_lport_s *port, + struct fchs_s *rx_fchs, u8 reason_code, + u8 reason_code_expl); +static void bfa_fcs_lport_plogi(struct bfa_fcs_lport_s *port, + struct fchs_s *rx_fchs, struct fc_logi_s *plogi); +static void bfa_fcs_lport_online_actions(struct bfa_fcs_lport_s *port); +static void bfa_fcs_lport_offline_actions(struct bfa_fcs_lport_s *port); +static void bfa_fcs_lport_unknown_init(struct bfa_fcs_lport_s *port); +static void bfa_fcs_lport_unknown_online(struct bfa_fcs_lport_s *port); +static void bfa_fcs_lport_unknown_offline(struct bfa_fcs_lport_s *port); +static void bfa_fcs_lport_deleted(struct bfa_fcs_lport_s *port); +static void bfa_fcs_lport_echo(struct bfa_fcs_lport_s *port, struct fchs_s *rx_fchs, struct fc_echo_s *echo, u16 len); -static void bfa_fcs_port_rnid(struct bfa_fcs_port_s *port, +static void bfa_fcs_lport_rnid(struct bfa_fcs_lport_s *port, struct fchs_s *rx_fchs, struct fc_rnid_cmd_s *rnid, u16 len); -static void bfa_fs_port_get_gen_topo_data(struct bfa_fcs_port_s *port, +static void bfa_fs_port_get_gen_topo_data(struct bfa_fcs_lport_s *port, struct fc_rnid_general_topology_data_s *gen_topo_data); +static void bfa_fcs_lport_fab_init(struct bfa_fcs_lport_s *port); +static void bfa_fcs_lport_fab_online(struct bfa_fcs_lport_s *port); +static void bfa_fcs_lport_fab_offline(struct bfa_fcs_lport_s *port); + +static void bfa_fcs_lport_n2n_init(struct bfa_fcs_lport_s *port); +static void bfa_fcs_lport_n2n_online(struct bfa_fcs_lport_s *port); +static void bfa_fcs_lport_n2n_offline(struct bfa_fcs_lport_s *port); + static struct { - void (*init) (struct bfa_fcs_port_s *port); - void (*online) (struct bfa_fcs_port_s *port); - void (*offline) (struct bfa_fcs_port_s *port); + void (*init) (struct bfa_fcs_lport_s *port); + void (*online) (struct bfa_fcs_lport_s *port); + void (*offline) (struct bfa_fcs_lport_s *port); } __port_action[] = { { - bfa_fcs_port_unknown_init, bfa_fcs_port_unknown_online, - bfa_fcs_port_unknown_offline}, { - bfa_fcs_port_fab_init, bfa_fcs_port_fab_online, - bfa_fcs_port_fab_offline}, { - bfa_fcs_port_loop_init, bfa_fcs_port_loop_online, - bfa_fcs_port_loop_offline}, { -bfa_fcs_port_n2n_init, bfa_fcs_port_n2n_online, - bfa_fcs_port_n2n_offline},}; + bfa_fcs_lport_unknown_init, bfa_fcs_lport_unknown_online, + bfa_fcs_lport_unknown_offline}, { + bfa_fcs_lport_fab_init, bfa_fcs_lport_fab_online, + bfa_fcs_lport_fab_offline}, { + bfa_fcs_lport_n2n_init, bfa_fcs_lport_n2n_online, + bfa_fcs_lport_n2n_offline}, + }; /** * fcs_port_sm FCS logical port state machine */ -enum bfa_fcs_port_event { +enum bfa_fcs_lport_event { BFA_FCS_PORT_SM_CREATE = 1, BFA_FCS_PORT_SM_ONLINE = 2, BFA_FCS_PORT_SM_OFFLINE = 3, @@ -90,27 +84,28 @@ enum bfa_fcs_port_event { BFA_FCS_PORT_SM_DELRPORT = 5, }; -static void bfa_fcs_port_sm_uninit(struct bfa_fcs_port_s *port, - enum bfa_fcs_port_event event); -static void bfa_fcs_port_sm_init(struct bfa_fcs_port_s *port, - enum bfa_fcs_port_event event); -static void bfa_fcs_port_sm_online(struct bfa_fcs_port_s *port, - enum bfa_fcs_port_event event); -static void bfa_fcs_port_sm_offline(struct bfa_fcs_port_s *port, - enum bfa_fcs_port_event event); -static void bfa_fcs_port_sm_deleting(struct bfa_fcs_port_s *port, - enum bfa_fcs_port_event event); +static void bfa_fcs_lport_sm_uninit(struct bfa_fcs_lport_s *port, + enum bfa_fcs_lport_event event); +static void bfa_fcs_lport_sm_init(struct bfa_fcs_lport_s *port, + enum bfa_fcs_lport_event event); +static void bfa_fcs_lport_sm_online(struct bfa_fcs_lport_s *port, + enum bfa_fcs_lport_event event); +static void bfa_fcs_lport_sm_offline(struct bfa_fcs_lport_s *port, + enum bfa_fcs_lport_event event); +static void bfa_fcs_lport_sm_deleting(struct bfa_fcs_lport_s *port, + enum bfa_fcs_lport_event event); static void -bfa_fcs_port_sm_uninit(struct bfa_fcs_port_s *port, - enum bfa_fcs_port_event event) +bfa_fcs_lport_sm_uninit( + struct bfa_fcs_lport_s *port, + enum bfa_fcs_lport_event event) { bfa_trc(port->fcs, port->port_cfg.pwwn); bfa_trc(port->fcs, event); switch (event) { case BFA_FCS_PORT_SM_CREATE: - bfa_sm_set_state(port, bfa_fcs_port_sm_init); + bfa_sm_set_state(port, bfa_fcs_lport_sm_init); break; default: @@ -119,20 +114,21 @@ bfa_fcs_port_sm_uninit(struct bfa_fcs_port_s *port, } static void -bfa_fcs_port_sm_init(struct bfa_fcs_port_s *port, enum bfa_fcs_port_event event) +bfa_fcs_lport_sm_init(struct bfa_fcs_lport_s *port, + enum bfa_fcs_lport_event event) { bfa_trc(port->fcs, port->port_cfg.pwwn); bfa_trc(port->fcs, event); switch (event) { case BFA_FCS_PORT_SM_ONLINE: - bfa_sm_set_state(port, bfa_fcs_port_sm_online); - bfa_fcs_port_online_actions(port); + bfa_sm_set_state(port, bfa_fcs_lport_sm_online); + bfa_fcs_lport_online_actions(port); break; case BFA_FCS_PORT_SM_DELETE: - bfa_sm_set_state(port, bfa_fcs_port_sm_uninit); - bfa_fcs_port_deleted(port); + bfa_sm_set_state(port, bfa_fcs_lport_sm_uninit); + bfa_fcs_lport_deleted(port); break; case BFA_FCS_PORT_SM_OFFLINE: @@ -144,19 +140,20 @@ bfa_fcs_port_sm_init(struct bfa_fcs_port_s *port, enum bfa_fcs_port_event event) } static void -bfa_fcs_port_sm_online(struct bfa_fcs_port_s *port, - enum bfa_fcs_port_event event) +bfa_fcs_lport_sm_online( + struct bfa_fcs_lport_s *port, + enum bfa_fcs_lport_event event) { struct bfa_fcs_rport_s *rport; - struct list_head *qe, *qen; + struct list_head *qe, *qen; bfa_trc(port->fcs, port->port_cfg.pwwn); bfa_trc(port->fcs, event); switch (event) { case BFA_FCS_PORT_SM_OFFLINE: - bfa_sm_set_state(port, bfa_fcs_port_sm_offline); - bfa_fcs_port_offline_actions(port); + bfa_sm_set_state(port, bfa_fcs_lport_sm_offline); + bfa_fcs_lport_offline_actions(port); break; case BFA_FCS_PORT_SM_DELETE: @@ -164,12 +161,12 @@ bfa_fcs_port_sm_online(struct bfa_fcs_port_s *port, __port_action[port->fabric->fab_type].offline(port); if (port->num_rports == 0) { - bfa_sm_set_state(port, bfa_fcs_port_sm_uninit); - bfa_fcs_port_deleted(port); + bfa_sm_set_state(port, bfa_fcs_lport_sm_uninit); + bfa_fcs_lport_deleted(port); } else { - bfa_sm_set_state(port, bfa_fcs_port_sm_deleting); + bfa_sm_set_state(port, bfa_fcs_lport_sm_deleting); list_for_each_safe(qe, qen, &port->rport_q) { - rport = (struct bfa_fcs_rport_s *)qe; + rport = (struct bfa_fcs_rport_s *) qe; bfa_fcs_rport_delete(rport); } } @@ -184,29 +181,30 @@ bfa_fcs_port_sm_online(struct bfa_fcs_port_s *port, } static void -bfa_fcs_port_sm_offline(struct bfa_fcs_port_s *port, - enum bfa_fcs_port_event event) +bfa_fcs_lport_sm_offline( + struct bfa_fcs_lport_s *port, + enum bfa_fcs_lport_event event) { struct bfa_fcs_rport_s *rport; - struct list_head *qe, *qen; + struct list_head *qe, *qen; bfa_trc(port->fcs, port->port_cfg.pwwn); bfa_trc(port->fcs, event); switch (event) { case BFA_FCS_PORT_SM_ONLINE: - bfa_sm_set_state(port, bfa_fcs_port_sm_online); - bfa_fcs_port_online_actions(port); + bfa_sm_set_state(port, bfa_fcs_lport_sm_online); + bfa_fcs_lport_online_actions(port); break; case BFA_FCS_PORT_SM_DELETE: if (port->num_rports == 0) { - bfa_sm_set_state(port, bfa_fcs_port_sm_uninit); - bfa_fcs_port_deleted(port); + bfa_sm_set_state(port, bfa_fcs_lport_sm_uninit); + bfa_fcs_lport_deleted(port); } else { - bfa_sm_set_state(port, bfa_fcs_port_sm_deleting); + bfa_sm_set_state(port, bfa_fcs_lport_sm_deleting); list_for_each_safe(qe, qen, &port->rport_q) { - rport = (struct bfa_fcs_rport_s *)qe; + rport = (struct bfa_fcs_rport_s *) qe; bfa_fcs_rport_delete(rport); } } @@ -222,8 +220,9 @@ bfa_fcs_port_sm_offline(struct bfa_fcs_port_s *port, } static void -bfa_fcs_port_sm_deleting(struct bfa_fcs_port_s *port, - enum bfa_fcs_port_event event) +bfa_fcs_lport_sm_deleting( + struct bfa_fcs_lport_s *port, + enum bfa_fcs_lport_event event) { bfa_trc(port->fcs, port->port_cfg.pwwn); bfa_trc(port->fcs, event); @@ -231,8 +230,8 @@ bfa_fcs_port_sm_deleting(struct bfa_fcs_port_s *port, switch (event) { case BFA_FCS_PORT_SM_DELRPORT: if (port->num_rports == 0) { - bfa_sm_set_state(port, bfa_fcs_port_sm_uninit); - bfa_fcs_port_deleted(port); + bfa_sm_set_state(port, bfa_fcs_lport_sm_uninit); + bfa_fcs_lport_deleted(port); } break; @@ -241,74 +240,44 @@ bfa_fcs_port_sm_deleting(struct bfa_fcs_port_s *port, } } - - /** * fcs_port_pvt */ -/** - * Send AEN notification - */ -static void -bfa_fcs_port_aen_post(struct bfa_fcs_port_s *port, - enum bfa_lport_aen_event event) -{ - union bfa_aen_data_u aen_data; - struct bfa_log_mod_s *logmod = port->fcs->logm; - enum bfa_port_role role = port->port_cfg.roles; - wwn_t lpwwn = bfa_fcs_port_get_pwwn(port); - char lpwwn_ptr[BFA_STRING_32]; - char *role_str[BFA_PORT_ROLE_FCP_MAX / 2 + 1] = - { "Initiator", "Target", "IPFC" }; - - wwn2str(lpwwn_ptr, lpwwn); - - bfa_assert(role <= BFA_PORT_ROLE_FCP_MAX); - - bfa_log(logmod, BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, event), lpwwn_ptr, - role_str[role/2]); - - aen_data.lport.vf_id = port->fabric->vf_id; - aen_data.lport.roles = role; - aen_data.lport.ppwwn = - bfa_fcs_port_get_pwwn(bfa_fcs_get_base_port(port->fcs)); - aen_data.lport.lpwwn = lpwwn; -} - /* * Send a LS reject */ static void -bfa_fcs_port_send_ls_rjt(struct bfa_fcs_port_s *port, struct fchs_s *rx_fchs, +bfa_fcs_lport_send_ls_rjt(struct bfa_fcs_lport_s *port, struct fchs_s *rx_fchs, u8 reason_code, u8 reason_code_expl) { - struct fchs_s fchs; + struct fchs_s fchs; struct bfa_fcxp_s *fcxp; struct bfa_rport_s *bfa_rport = NULL; - int len; + int len; + bfa_trc(port->fcs, rx_fchs->d_id); bfa_trc(port->fcs, rx_fchs->s_id); fcxp = bfa_fcs_fcxp_alloc(port->fcs); if (!fcxp) return; - len = fc_ls_rjt_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rx_fchs->s_id, - bfa_fcs_port_get_fcid(port), rx_fchs->ox_id, - reason_code, reason_code_expl); + len = fc_ls_rjt_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), + rx_fchs->s_id, bfa_fcs_lport_get_fcid(port), + rx_fchs->ox_id, reason_code, reason_code_expl); bfa_fcxp_send(fcxp, bfa_rport, port->fabric->vf_id, port->lp_tag, - BFA_FALSE, FC_CLASS_3, len, &fchs, NULL, NULL, - FC_MAX_PDUSZ, 0); + BFA_FALSE, FC_CLASS_3, len, &fchs, NULL, NULL, + FC_MAX_PDUSZ, 0); } /** * Process incoming plogi from a remote port. */ static void -bfa_fcs_port_plogi(struct bfa_fcs_port_s *port, struct fchs_s *rx_fchs, - struct fc_logi_s *plogi) +bfa_fcs_lport_plogi(struct bfa_fcs_lport_s *port, + struct fchs_s *rx_fchs, struct fc_logi_s *plogi) { struct bfa_fcs_rport_s *rport; @@ -328,46 +297,40 @@ bfa_fcs_port_plogi(struct bfa_fcs_port_s *port, struct fchs_s *rx_fchs, /* * send a LS reject */ - bfa_fcs_port_send_ls_rjt(port, rx_fchs, - FC_LS_RJT_RSN_PROTOCOL_ERROR, - FC_LS_RJT_EXP_SPARMS_ERR_OPTIONS); + bfa_fcs_lport_send_ls_rjt(port, rx_fchs, + FC_LS_RJT_RSN_PROTOCOL_ERROR, + FC_LS_RJT_EXP_SPARMS_ERR_OPTIONS); return; } /** -* Direct Attach P2P mode : verify address assigned by the r-port. + * Direct Attach P2P mode : verify address assigned by the r-port. */ - if ((!bfa_fcs_fabric_is_switched(port->fabric)) - && - (memcmp - ((void *)&bfa_fcs_port_get_pwwn(port), (void *)&plogi->port_name, - sizeof(wwn_t)) < 0)) { + if ((!bfa_fcs_fabric_is_switched(port->fabric)) && + (memcmp((void *)&bfa_fcs_lport_get_pwwn(port), + (void *)&plogi->port_name, sizeof(wwn_t)) < 0)) { if (BFA_FCS_PID_IS_WKA(rx_fchs->d_id)) { - /* - * Address assigned to us cannot be a WKA - */ - bfa_fcs_port_send_ls_rjt(port, rx_fchs, + /* Address assigned to us cannot be a WKA */ + bfa_fcs_lport_send_ls_rjt(port, rx_fchs, FC_LS_RJT_RSN_PROTOCOL_ERROR, FC_LS_RJT_EXP_INVALID_NPORT_ID); return; } - port->pid = rx_fchs->d_id; + port->pid = rx_fchs->d_id; } /** * First, check if we know the device by pwwn. */ - rport = bfa_fcs_port_get_rport_by_pwwn(port, plogi->port_name); + rport = bfa_fcs_lport_get_rport_by_pwwn(port, plogi->port_name); if (rport) { /** - * Direct Attach P2P mode: handle address assigned by the rport. - */ - if ((!bfa_fcs_fabric_is_switched(port->fabric)) - && - (memcmp - ((void *)&bfa_fcs_port_get_pwwn(port), - (void *)&plogi->port_name, sizeof(wwn_t)) < 0)) { - port->pid = rx_fchs->d_id; + * Direct Attach P2P mode : handle address assigned by r-port. + */ + if ((!bfa_fcs_fabric_is_switched(port->fabric)) && + (memcmp((void *)&bfa_fcs_lport_get_pwwn(port), + (void *)&plogi->port_name, sizeof(wwn_t)) < 0)) { + port->pid = rx_fchs->d_id; rport->pid = rx_fchs->s_id; } bfa_fcs_rport_plogi(rport, rx_fchs, plogi); @@ -377,7 +340,7 @@ bfa_fcs_port_plogi(struct bfa_fcs_port_s *port, struct fchs_s *rx_fchs, /** * Next, lookup rport by PID. */ - rport = bfa_fcs_port_get_rport_by_pid(port, rx_fchs->s_id); + rport = bfa_fcs_lport_get_rport_by_pid(port, rx_fchs->s_id); if (!rport) { /** * Inbound PLOGI from a new device. @@ -416,39 +379,40 @@ bfa_fcs_port_plogi(struct bfa_fcs_port_s *port, struct fchs_s *rx_fchs, * Since it does not require a login, it is processed here. */ static void -bfa_fcs_port_echo(struct bfa_fcs_port_s *port, struct fchs_s *rx_fchs, - struct fc_echo_s *echo, u16 rx_len) +bfa_fcs_lport_echo(struct bfa_fcs_lport_s *port, struct fchs_s *rx_fchs, + struct fc_echo_s *echo, u16 rx_len) { - struct fchs_s fchs; - struct bfa_fcxp_s *fcxp; - struct bfa_rport_s *bfa_rport = NULL; - int len, pyld_len; + struct fchs_s fchs; + struct bfa_fcxp_s *fcxp; + struct bfa_rport_s *bfa_rport = NULL; + int len, pyld_len; bfa_trc(port->fcs, rx_fchs->s_id); bfa_trc(port->fcs, rx_fchs->d_id); - bfa_trc(port->fcs, rx_len); fcxp = bfa_fcs_fcxp_alloc(port->fcs); if (!fcxp) return; - len = fc_ls_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rx_fchs->s_id, - bfa_fcs_port_get_fcid(port), rx_fchs->ox_id); + len = fc_ls_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), + rx_fchs->s_id, bfa_fcs_lport_get_fcid(port), + rx_fchs->ox_id); /* * Copy the payload (if any) from the echo frame */ pyld_len = rx_len - sizeof(struct fchs_s); + bfa_trc(port->fcs, rx_len); bfa_trc(port->fcs, pyld_len); if (pyld_len > len) memcpy(((u8 *) bfa_fcxp_get_reqbuf(fcxp)) + - sizeof(struct fc_echo_s), (echo + 1), - (pyld_len - sizeof(struct fc_echo_s))); + sizeof(struct fc_echo_s), (echo + 1), + (pyld_len - sizeof(struct fc_echo_s))); bfa_fcxp_send(fcxp, bfa_rport, port->fabric->vf_id, port->lp_tag, - BFA_FALSE, FC_CLASS_3, pyld_len, &fchs, NULL, NULL, - FC_MAX_PDUSZ, 0); + BFA_FALSE, FC_CLASS_3, pyld_len, &fchs, NULL, NULL, + FC_MAX_PDUSZ, 0); } /* @@ -456,16 +420,16 @@ bfa_fcs_port_echo(struct bfa_fcs_port_s *port, struct fchs_s *rx_fchs, * Since it does not require a login, it is processed here. */ static void -bfa_fcs_port_rnid(struct bfa_fcs_port_s *port, struct fchs_s *rx_fchs, - struct fc_rnid_cmd_s *rnid, u16 rx_len) +bfa_fcs_lport_rnid(struct bfa_fcs_lport_s *port, struct fchs_s *rx_fchs, + struct fc_rnid_cmd_s *rnid, u16 rx_len) { struct fc_rnid_common_id_data_s common_id_data; struct fc_rnid_general_topology_data_s gen_topo_data; - struct fchs_s fchs; + struct fchs_s fchs; struct bfa_fcxp_s *fcxp; struct bfa_rport_s *bfa_rport = NULL; - u16 len; - u32 data_format; + u16 len; + u32 data_format; bfa_trc(port->fcs, rx_fchs->s_id); bfa_trc(port->fcs, rx_fchs->d_id); @@ -495,28 +459,26 @@ bfa_fcs_port_rnid(struct bfa_fcs_port_s *port, struct fchs_s *rx_fchs, /* * Copy the Node Id Info */ - common_id_data.port_name = bfa_fcs_port_get_pwwn(port); - common_id_data.node_name = bfa_fcs_port_get_nwwn(port); + common_id_data.port_name = bfa_fcs_lport_get_pwwn(port); + common_id_data.node_name = bfa_fcs_lport_get_nwwn(port); - len = fc_rnid_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rx_fchs->s_id, - bfa_fcs_port_get_fcid(port), rx_fchs->ox_id, - data_format, &common_id_data, &gen_topo_data); + len = fc_rnid_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), + rx_fchs->s_id, bfa_fcs_lport_get_fcid(port), + rx_fchs->ox_id, data_format, &common_id_data, + &gen_topo_data); bfa_fcxp_send(fcxp, bfa_rport, port->fabric->vf_id, port->lp_tag, - BFA_FALSE, FC_CLASS_3, len, &fchs, NULL, NULL, - FC_MAX_PDUSZ, 0); - - return; + BFA_FALSE, FC_CLASS_3, len, &fchs, NULL, NULL, + FC_MAX_PDUSZ, 0); } /* * Fill out General Topolpgy Discovery Data for RNID ELS. */ static void -bfa_fs_port_get_gen_topo_data(struct bfa_fcs_port_s *port, +bfa_fs_port_get_gen_topo_data(struct bfa_fcs_lport_s *port, struct fc_rnid_general_topology_data_s *gen_topo_data) { - bfa_os_memset(gen_topo_data, 0, sizeof(struct fc_rnid_general_topology_data_s)); @@ -526,76 +488,111 @@ bfa_fs_port_get_gen_topo_data(struct bfa_fcs_port_s *port, } static void -bfa_fcs_port_online_actions(struct bfa_fcs_port_s *port) +bfa_fcs_lport_online_actions(struct bfa_fcs_lport_s *port) { + struct bfad_s *bfad = (struct bfad_s *)port->fcs->bfad; + char lpwwn_buf[BFA_STRING_32]; + bfa_trc(port->fcs, port->fabric->oper_type); __port_action[port->fabric->fab_type].init(port); __port_action[port->fabric->fab_type].online(port); - bfa_fcs_port_aen_post(port, BFA_LPORT_AEN_ONLINE); - bfa_fcb_port_online(port->fcs->bfad, port->port_cfg.roles, - port->fabric->vf_drv, (port->vport == NULL) ? - NULL : port->vport->vport_drv); + wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(port)); + BFA_LOG(KERN_INFO, bfad, log_level, + "Logical port online: WWN = %s Role = %s\n", + lpwwn_buf, "Initiator"); + + bfad->bfad_flags |= BFAD_PORT_ONLINE; } static void -bfa_fcs_port_offline_actions(struct bfa_fcs_port_s *port) +bfa_fcs_lport_offline_actions(struct bfa_fcs_lport_s *port) { - struct list_head *qe, *qen; + struct list_head *qe, *qen; struct bfa_fcs_rport_s *rport; + struct bfad_s *bfad = (struct bfad_s *)port->fcs->bfad; + char lpwwn_buf[BFA_STRING_32]; bfa_trc(port->fcs, port->fabric->oper_type); __port_action[port->fabric->fab_type].offline(port); + wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(port)); if (bfa_fcs_fabric_is_online(port->fabric) == BFA_TRUE) - bfa_fcs_port_aen_post(port, BFA_LPORT_AEN_DISCONNECT); + BFA_LOG(KERN_ERR, bfad, log_level, + "Logical port lost fabric connectivity: WWN = %s Role = %s\n", + lpwwn_buf, "Initiator"); else - bfa_fcs_port_aen_post(port, BFA_LPORT_AEN_OFFLINE); - bfa_fcb_port_offline(port->fcs->bfad, port->port_cfg.roles, - port->fabric->vf_drv, - (port->vport == NULL) ? NULL : port->vport->vport_drv); + BFA_LOG(KERN_INFO, bfad, log_level, + "Logical port taken offline: WWN = %s Role = %s\n", + lpwwn_buf, "Initiator"); list_for_each_safe(qe, qen, &port->rport_q) { - rport = (struct bfa_fcs_rport_s *)qe; + rport = (struct bfa_fcs_rport_s *) qe; bfa_fcs_rport_offline(rport); } } static void -bfa_fcs_port_unknown_init(struct bfa_fcs_port_s *port) +bfa_fcs_lport_unknown_init(struct bfa_fcs_lport_s *port) { bfa_assert(0); } static void -bfa_fcs_port_unknown_online(struct bfa_fcs_port_s *port) +bfa_fcs_lport_unknown_online(struct bfa_fcs_lport_s *port) { bfa_assert(0); } static void -bfa_fcs_port_unknown_offline(struct bfa_fcs_port_s *port) +bfa_fcs_lport_unknown_offline(struct bfa_fcs_lport_s *port) { bfa_assert(0); } static void -bfa_fcs_port_deleted(struct bfa_fcs_port_s *port) +bfa_fcs_lport_abts_acc(struct bfa_fcs_lport_s *port, struct fchs_s *rx_fchs) { - bfa_fcs_port_aen_post(port, BFA_LPORT_AEN_DELETE); + struct fchs_s fchs; + struct bfa_fcxp_s *fcxp; + int len; - /* - * Base port will be deleted by the OS driver - */ + bfa_trc(port->fcs, rx_fchs->d_id); + bfa_trc(port->fcs, rx_fchs->s_id); + + fcxp = bfa_fcs_fcxp_alloc(port->fcs); + if (!fcxp) + return; + + len = fc_ba_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), + rx_fchs->s_id, bfa_fcs_lport_get_fcid(port), + rx_fchs->ox_id, 0); + + bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, + BFA_FALSE, FC_CLASS_3, len, &fchs, NULL, NULL, + FC_MAX_PDUSZ, 0); +} +static void +bfa_fcs_lport_deleted(struct bfa_fcs_lport_s *port) +{ + struct bfad_s *bfad = (struct bfad_s *)port->fcs->bfad; + char lpwwn_buf[BFA_STRING_32]; + + wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(port)); + BFA_LOG(KERN_INFO, bfad, log_level, + "Logical port deleted: WWN = %s Role = %s\n", + lpwwn_buf, "Initiator"); + + /* Base port will be deleted by the OS driver */ if (port->vport) { - bfa_fcb_port_delete(port->fcs->bfad, port->port_cfg.roles, - port->fabric->vf_drv, - port->vport ? port->vport->vport_drv : NULL); + bfa_fcb_lport_delete(port->fcs->bfad, port->port_cfg.roles, + port->fabric->vf_drv, + port->vport ? port->vport->vport_drv : NULL); bfa_fcs_vport_delete_comp(port->vport); } else { - bfa_fcs_fabric_port_delete_comp(port->fabric); + bfa_fcs_fabric_port_delete_comp(port->fabric); } } @@ -608,7 +605,7 @@ bfa_fcs_port_deleted(struct bfa_fcs_port_s *port) * Module initialization */ void -bfa_fcs_port_modinit(struct bfa_fcs_s *fcs) +bfa_fcs_lport_modinit(struct bfa_fcs_s *fcs) { } @@ -617,25 +614,25 @@ bfa_fcs_port_modinit(struct bfa_fcs_s *fcs) * Module cleanup */ void -bfa_fcs_port_modexit(struct bfa_fcs_s *fcs) +bfa_fcs_lport_modexit(struct bfa_fcs_s *fcs) { bfa_fcs_modexit_comp(fcs); } /** - * Unsolicited frame receive handling. + * Unsolicited frame receive handling. */ void -bfa_fcs_port_uf_recv(struct bfa_fcs_port_s *lport, struct fchs_s *fchs, - u16 len) +bfa_fcs_lport_uf_recv(struct bfa_fcs_lport_s *lport, + struct fchs_s *fchs, u16 len) { - u32 pid = fchs->s_id; + u32 pid = fchs->s_id; struct bfa_fcs_rport_s *rport = NULL; - struct fc_els_cmd_s *els_cmd = (struct fc_els_cmd_s *) (fchs + 1); + struct fc_els_cmd_s *els_cmd = (struct fc_els_cmd_s *) (fchs + 1); bfa_stats(lport, uf_recvs); - if (!bfa_fcs_port_is_online(lport)) { + if (!bfa_fcs_lport_is_online(lport)) { bfa_stats(lport, uf_recv_drops); return; } @@ -648,7 +645,7 @@ bfa_fcs_port_uf_recv(struct bfa_fcs_port_s *lport, struct fchs_s *fchs, */ if ((fchs->type == FC_TYPE_ELS) && (els_cmd->els_code == FC_ELS_PLOGI)) { - bfa_fcs_port_plogi(lport, fchs, (struct fc_logi_s *) els_cmd); + bfa_fcs_lport_plogi(lport, fchs, (struct fc_logi_s *) els_cmd); return; } @@ -656,8 +653,8 @@ bfa_fcs_port_uf_recv(struct bfa_fcs_port_s *lport, struct fchs_s *fchs, * Handle ECHO separately. */ if ((fchs->type == FC_TYPE_ELS) && (els_cmd->els_code == FC_ELS_ECHO)) { - bfa_fcs_port_echo(lport, fchs, - (struct fc_echo_s *) els_cmd, len); + bfa_fcs_lport_echo(lport, fchs, + (struct fc_echo_s *)els_cmd, len); return; } @@ -665,15 +662,21 @@ bfa_fcs_port_uf_recv(struct bfa_fcs_port_s *lport, struct fchs_s *fchs, * Handle RNID separately. */ if ((fchs->type == FC_TYPE_ELS) && (els_cmd->els_code == FC_ELS_RNID)) { - bfa_fcs_port_rnid(lport, fchs, + bfa_fcs_lport_rnid(lport, fchs, (struct fc_rnid_cmd_s *) els_cmd, len); return; } + if (fchs->type == FC_TYPE_BLS) { + if ((fchs->routing == FC_RTG_BASIC_LINK) && + (fchs->cat_info == FC_CAT_ABTS)) + bfa_fcs_lport_abts_acc(lport, fchs); + return; + } /** * look for a matching remote port ID */ - rport = bfa_fcs_port_get_rport_by_pid(lport, pid); + rport = bfa_fcs_lport_get_rport_by_pid(lport, pid); if (rport) { bfa_trc(rport->fcs, fchs->s_id); bfa_trc(rport->fcs, fchs->d_id); @@ -694,7 +697,7 @@ bfa_fcs_port_uf_recv(struct bfa_fcs_port_s *lport, struct fchs_s *fchs, bfa_trc(lport->fcs, els_cmd->els_code); if (els_cmd->els_code == FC_ELS_RSCN) { - bfa_fcs_port_scn_process_rscn(lport, fchs, len); + bfa_fcs_lport_scn_process_rscn(lport, fchs, len); return; } @@ -702,7 +705,6 @@ bfa_fcs_port_uf_recv(struct bfa_fcs_port_s *lport, struct fchs_s *fchs, /** * @todo Handle LOGO frames received. */ - bfa_trc(lport->fcs, els_cmd->els_code); return; } @@ -710,14 +712,13 @@ bfa_fcs_port_uf_recv(struct bfa_fcs_port_s *lport, struct fchs_s *fchs, /** * @todo Handle PRLI frames received. */ - bfa_trc(lport->fcs, els_cmd->els_code); return; } /** * Unhandled ELS frames. Send a LS_RJT. */ - bfa_fcs_port_send_ls_rjt(lport, fchs, FC_LS_RJT_RSN_CMD_NOT_SUPP, + bfa_fcs_lport_send_ls_rjt(lport, fchs, FC_LS_RJT_RSN_CMD_NOT_SUPP, FC_LS_RJT_EXP_NO_ADDL_INFO); } @@ -726,13 +727,13 @@ bfa_fcs_port_uf_recv(struct bfa_fcs_port_s *lport, struct fchs_s *fchs, * PID based Lookup for a R-Port in the Port R-Port Queue */ struct bfa_fcs_rport_s * -bfa_fcs_port_get_rport_by_pid(struct bfa_fcs_port_s *port, u32 pid) +bfa_fcs_lport_get_rport_by_pid(struct bfa_fcs_lport_s *port, u32 pid) { struct bfa_fcs_rport_s *rport; - struct list_head *qe; + struct list_head *qe; list_for_each(qe, &port->rport_q) { - rport = (struct bfa_fcs_rport_s *)qe; + rport = (struct bfa_fcs_rport_s *) qe; if (rport->pid == pid) return rport; } @@ -745,13 +746,13 @@ bfa_fcs_port_get_rport_by_pid(struct bfa_fcs_port_s *port, u32 pid) * PWWN based Lookup for a R-Port in the Port R-Port Queue */ struct bfa_fcs_rport_s * -bfa_fcs_port_get_rport_by_pwwn(struct bfa_fcs_port_s *port, wwn_t pwwn) +bfa_fcs_lport_get_rport_by_pwwn(struct bfa_fcs_lport_s *port, wwn_t pwwn) { struct bfa_fcs_rport_s *rport; - struct list_head *qe; + struct list_head *qe; list_for_each(qe, &port->rport_q) { - rport = (struct bfa_fcs_rport_s *)qe; + rport = (struct bfa_fcs_rport_s *) qe; if (wwn_is_equal(rport->pwwn, pwwn)) return rport; } @@ -764,13 +765,13 @@ bfa_fcs_port_get_rport_by_pwwn(struct bfa_fcs_port_s *port, wwn_t pwwn) * NWWN based Lookup for a R-Port in the Port R-Port Queue */ struct bfa_fcs_rport_s * -bfa_fcs_port_get_rport_by_nwwn(struct bfa_fcs_port_s *port, wwn_t nwwn) +bfa_fcs_lport_get_rport_by_nwwn(struct bfa_fcs_lport_s *port, wwn_t nwwn) { struct bfa_fcs_rport_s *rport; - struct list_head *qe; + struct list_head *qe; list_for_each(qe, &port->rport_q) { - rport = (struct bfa_fcs_rport_s *)qe; + rport = (struct bfa_fcs_rport_s *) qe; if (wwn_is_equal(rport->nwwn, nwwn)) return rport; } @@ -783,8 +784,9 @@ bfa_fcs_port_get_rport_by_nwwn(struct bfa_fcs_port_s *port, wwn_t nwwn) * Called by rport module when new rports are discovered. */ void -bfa_fcs_port_add_rport(struct bfa_fcs_port_s *port, - struct bfa_fcs_rport_s *rport) +bfa_fcs_lport_add_rport( + struct bfa_fcs_lport_s *port, + struct bfa_fcs_rport_s *rport) { list_add_tail(&rport->qe, &port->rport_q); port->num_rports++; @@ -794,8 +796,9 @@ bfa_fcs_port_add_rport(struct bfa_fcs_port_s *port, * Called by rport module to when rports are deleted. */ void -bfa_fcs_port_del_rport(struct bfa_fcs_port_s *port, - struct bfa_fcs_rport_s *rport) +bfa_fcs_lport_del_rport( + struct bfa_fcs_lport_s *port, + struct bfa_fcs_rport_s *rport) { bfa_assert(bfa_q_is_on_q(&port->rport_q, rport)); list_del(&rport->qe); @@ -809,7 +812,7 @@ bfa_fcs_port_del_rport(struct bfa_fcs_port_s *port, * Called by vport for virtual ports when FDISC is complete. */ void -bfa_fcs_port_online(struct bfa_fcs_port_s *port) +bfa_fcs_lport_online(struct bfa_fcs_lport_s *port) { bfa_sm_send_event(port, BFA_FCS_PORT_SM_ONLINE); } @@ -819,7 +822,7 @@ bfa_fcs_port_online(struct bfa_fcs_port_s *port) * Called by vport for virtual ports when virtual port becomes offline. */ void -bfa_fcs_port_offline(struct bfa_fcs_port_s *port) +bfa_fcs_lport_offline(struct bfa_fcs_lport_s *port) { bfa_sm_send_event(port, BFA_FCS_PORT_SM_OFFLINE); } @@ -831,40 +834,32 @@ bfa_fcs_port_offline(struct bfa_fcs_port_s *port) * bfa_fcs_vport_delete_comp() for vports on completion. */ void -bfa_fcs_port_delete(struct bfa_fcs_port_s *port) +bfa_fcs_lport_delete(struct bfa_fcs_lport_s *port) { bfa_sm_send_event(port, BFA_FCS_PORT_SM_DELETE); } /** - * Called by fabric in private loop topology to process LIP event. - */ -void -bfa_fcs_port_lip(struct bfa_fcs_port_s *port) -{ -} - -/** * Return TRUE if port is online, else return FALSE */ bfa_boolean_t -bfa_fcs_port_is_online(struct bfa_fcs_port_s *port) +bfa_fcs_lport_is_online(struct bfa_fcs_lport_s *port) { - return bfa_sm_cmp_state(port, bfa_fcs_port_sm_online); + return bfa_sm_cmp_state(port, bfa_fcs_lport_sm_online); } /** - * Attach time initialization of logical ports. + * Attach time initialization of logical ports. */ void -bfa_fcs_lport_attach(struct bfa_fcs_port_s *lport, struct bfa_fcs_s *fcs, - uint16_t vf_id, struct bfa_fcs_vport_s *vport) +bfa_fcs_lport_attach(struct bfa_fcs_lport_s *lport, struct bfa_fcs_s *fcs, + u16 vf_id, struct bfa_fcs_vport_s *vport) { lport->fcs = fcs; lport->fabric = bfa_fcs_vf_lookup(fcs, vf_id); lport->vport = vport; lport->lp_tag = (vport) ? bfa_lps_get_tag(vport->lps) : - bfa_lps_get_tag(lport->fabric->lps); + bfa_lps_get_tag(lport->fabric->lps); INIT_LIST_HEAD(&lport->rport_q); lport->num_rports = 0; @@ -876,21 +871,26 @@ bfa_fcs_lport_attach(struct bfa_fcs_port_s *lport, struct bfa_fcs_s *fcs, */ void -bfa_fcs_lport_init(struct bfa_fcs_port_s *lport, - struct bfa_port_cfg_s *port_cfg) +bfa_fcs_lport_init(struct bfa_fcs_lport_s *lport, + struct bfa_lport_cfg_s *port_cfg) { struct bfa_fcs_vport_s *vport = lport->vport; + struct bfad_s *bfad = (struct bfad_s *)lport->fcs->bfad; + char lpwwn_buf[BFA_STRING_32]; bfa_os_assign(lport->port_cfg, *port_cfg); - lport->bfad_port = bfa_fcb_port_new(lport->fcs->bfad, lport, - lport->port_cfg.roles, - lport->fabric->vf_drv, - vport ? vport->vport_drv : NULL); + lport->bfad_port = bfa_fcb_lport_new(lport->fcs->bfad, lport, + lport->port_cfg.roles, + lport->fabric->vf_drv, + vport ? vport->vport_drv : NULL); - bfa_fcs_port_aen_post(lport, BFA_LPORT_AEN_NEW); + wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(lport)); + BFA_LOG(KERN_INFO, bfad, log_level, + "New logical port created: WWN = %s Role = %s\n", + lpwwn_buf, "Initiator"); - bfa_sm_set_state(lport, bfa_fcs_port_sm_uninit); + bfa_sm_set_state(lport, bfa_fcs_lport_sm_uninit); bfa_sm_send_event(lport, BFA_FCS_PORT_SM_CREATE); } @@ -899,10 +899,11 @@ bfa_fcs_lport_init(struct bfa_fcs_port_s *lport, */ void -bfa_fcs_port_get_attr(struct bfa_fcs_port_s *port, - struct bfa_port_attr_s *port_attr) +bfa_fcs_lport_get_attr( + struct bfa_fcs_lport_s *port, + struct bfa_lport_attr_s *port_attr) { - if (bfa_sm_cmp_state(port, bfa_fcs_port_sm_online)) + if (bfa_sm_cmp_state(port, bfa_fcs_lport_sm_online)) port_attr->pid = port->pid; else port_attr->pid = 0; @@ -913,25 +914,4895 @@ bfa_fcs_port_get_attr(struct bfa_fcs_port_s *port, port_attr->port_type = bfa_fcs_fabric_port_type(port->fabric); port_attr->loopback = bfa_fcs_fabric_is_loopback(port->fabric); port_attr->authfail = - bfa_fcs_fabric_is_auth_failed(port->fabric); - port_attr->fabric_name = bfa_fcs_port_get_fabric_name(port); + bfa_fcs_fabric_is_auth_failed(port->fabric); + port_attr->fabric_name = bfa_fcs_lport_get_fabric_name(port); memcpy(port_attr->fabric_ip_addr, - bfa_fcs_port_get_fabric_ipaddr(port), - BFA_FCS_FABRIC_IPADDR_SZ); + bfa_fcs_lport_get_fabric_ipaddr(port), + BFA_FCS_FABRIC_IPADDR_SZ); if (port->vport != NULL) { - port_attr->port_type = BFA_PPORT_TYPE_VPORT; + port_attr->port_type = BFA_PORT_TYPE_VPORT; port_attr->fpma_mac = bfa_lps_get_lp_mac(port->vport->lps); - } else + } else { port_attr->fpma_mac = bfa_lps_get_lp_mac(port->fabric->lps); + } + } else { + port_attr->port_type = BFA_PORT_TYPE_UNKNOWN; + port_attr->state = BFA_LPORT_UNINIT; + } +} + +/** + * bfa_fcs_lport_fab port fab functions + */ + +/** + * Called by port to initialize fabric services of the base port. + */ +static void +bfa_fcs_lport_fab_init(struct bfa_fcs_lport_s *port) +{ + bfa_fcs_lport_ns_init(port); + bfa_fcs_lport_scn_init(port); + bfa_fcs_lport_ms_init(port); +} + +/** + * Called by port to notify transition to online state. + */ +static void +bfa_fcs_lport_fab_online(struct bfa_fcs_lport_s *port) +{ + bfa_fcs_lport_ns_online(port); + bfa_fcs_lport_scn_online(port); +} + +/** + * Called by port to notify transition to offline state. + */ +static void +bfa_fcs_lport_fab_offline(struct bfa_fcs_lport_s *port) +{ + bfa_fcs_lport_ns_offline(port); + bfa_fcs_lport_scn_offline(port); + bfa_fcs_lport_ms_offline(port); +} + +/** + * bfa_fcs_lport_n2n functions + */ + +/** + * Called by fcs/port to initialize N2N topology. + */ +static void +bfa_fcs_lport_n2n_init(struct bfa_fcs_lport_s *port) +{ +} + +/** + * Called by fcs/port to notify transition to online state. + */ +static void +bfa_fcs_lport_n2n_online(struct bfa_fcs_lport_s *port) +{ + struct bfa_fcs_lport_n2n_s *n2n_port = &port->port_topo.pn2n; + struct bfa_lport_cfg_s *pcfg = &port->port_cfg; + struct bfa_fcs_rport_s *rport; + + bfa_trc(port->fcs, pcfg->pwwn); + + /* + * If our PWWN is > than that of the r-port, we have to initiate PLOGI + * and assign an Address. if not, we need to wait for its PLOGI. + * + * If our PWWN is < than that of the remote port, it will send a PLOGI + * with the PIDs assigned. The rport state machine take care of this + * incoming PLOGI. + */ + if (memcmp + ((void *)&pcfg->pwwn, (void *)&n2n_port->rem_port_wwn, + sizeof(wwn_t)) > 0) { + port->pid = N2N_LOCAL_PID; + /** + * First, check if we know the device by pwwn. + */ + rport = bfa_fcs_lport_get_rport_by_pwwn(port, + n2n_port->rem_port_wwn); + if (rport) { + bfa_trc(port->fcs, rport->pid); + bfa_trc(port->fcs, rport->pwwn); + rport->pid = N2N_REMOTE_PID; + bfa_fcs_rport_online(rport); + return; + } + + /* + * In n2n there can be only one rport. Delete the old one + * whose pid should be zero, because it is offline. + */ + if (port->num_rports > 0) { + rport = bfa_fcs_lport_get_rport_by_pid(port, 0); + bfa_assert(rport != NULL); + if (rport) { + bfa_trc(port->fcs, rport->pwwn); + bfa_fcs_rport_delete(rport); + } + } + bfa_fcs_rport_create(port, N2N_REMOTE_PID); + } +} + +/** + * Called by fcs/port to notify transition to offline state. + */ +static void +bfa_fcs_lport_n2n_offline(struct bfa_fcs_lport_s *port) +{ + struct bfa_fcs_lport_n2n_s *n2n_port = &port->port_topo.pn2n; + + bfa_trc(port->fcs, port->pid); + port->pid = 0; + n2n_port->rem_port_wwn = 0; + n2n_port->reply_oxid = 0; +} + +#define BFA_FCS_FDMI_CMD_MAX_RETRIES 2 + +/* + * forward declarations + */ +static void bfa_fcs_lport_fdmi_send_rhba(void *fdmi_cbarg, + struct bfa_fcxp_s *fcxp_alloced); +static void bfa_fcs_lport_fdmi_send_rprt(void *fdmi_cbarg, + struct bfa_fcxp_s *fcxp_alloced); +static void bfa_fcs_lport_fdmi_send_rpa(void *fdmi_cbarg, + struct bfa_fcxp_s *fcxp_alloced); +static void bfa_fcs_lport_fdmi_rhba_response(void *fcsarg, + struct bfa_fcxp_s *fcxp, + void *cbarg, + bfa_status_t req_status, + u32 rsp_len, + u32 resid_len, + struct fchs_s *rsp_fchs); +static void bfa_fcs_lport_fdmi_rprt_response(void *fcsarg, + struct bfa_fcxp_s *fcxp, + void *cbarg, + bfa_status_t req_status, + u32 rsp_len, + u32 resid_len, + struct fchs_s *rsp_fchs); +static void bfa_fcs_lport_fdmi_rpa_response(void *fcsarg, + struct bfa_fcxp_s *fcxp, + void *cbarg, + bfa_status_t req_status, + u32 rsp_len, + u32 resid_len, + struct fchs_s *rsp_fchs); +static void bfa_fcs_lport_fdmi_timeout(void *arg); +static u16 bfa_fcs_lport_fdmi_build_rhba_pyld(struct bfa_fcs_lport_fdmi_s *fdmi, + u8 *pyld); +static u16 bfa_fcs_lport_fdmi_build_rprt_pyld(struct bfa_fcs_lport_fdmi_s *fdmi, + u8 *pyld); +static u16 bfa_fcs_lport_fdmi_build_rpa_pyld(struct bfa_fcs_lport_fdmi_s *fdmi, + u8 *pyld); +static u16 bfa_fcs_lport_fdmi_build_portattr_block(struct bfa_fcs_lport_fdmi_s * + fdmi, u8 *pyld); +static void bfa_fcs_fdmi_get_hbaattr(struct bfa_fcs_lport_fdmi_s *fdmi, + struct bfa_fcs_fdmi_hba_attr_s *hba_attr); +static void bfa_fcs_fdmi_get_portattr(struct bfa_fcs_lport_fdmi_s *fdmi, + struct bfa_fcs_fdmi_port_attr_s *port_attr); +/** + * fcs_fdmi_sm FCS FDMI state machine + */ + +/** + * FDMI State Machine events + */ +enum port_fdmi_event { + FDMISM_EVENT_PORT_ONLINE = 1, + FDMISM_EVENT_PORT_OFFLINE = 2, + FDMISM_EVENT_RSP_OK = 4, + FDMISM_EVENT_RSP_ERROR = 5, + FDMISM_EVENT_TIMEOUT = 6, + FDMISM_EVENT_RHBA_SENT = 7, + FDMISM_EVENT_RPRT_SENT = 8, + FDMISM_EVENT_RPA_SENT = 9, +}; + +static void bfa_fcs_lport_fdmi_sm_offline(struct bfa_fcs_lport_fdmi_s *fdmi, + enum port_fdmi_event event); +static void bfa_fcs_lport_fdmi_sm_sending_rhba( + struct bfa_fcs_lport_fdmi_s *fdmi, + enum port_fdmi_event event); +static void bfa_fcs_lport_fdmi_sm_rhba(struct bfa_fcs_lport_fdmi_s *fdmi, + enum port_fdmi_event event); +static void bfa_fcs_lport_fdmi_sm_rhba_retry( + struct bfa_fcs_lport_fdmi_s *fdmi, + enum port_fdmi_event event); +static void bfa_fcs_lport_fdmi_sm_sending_rprt( + struct bfa_fcs_lport_fdmi_s *fdmi, + enum port_fdmi_event event); +static void bfa_fcs_lport_fdmi_sm_rprt(struct bfa_fcs_lport_fdmi_s *fdmi, + enum port_fdmi_event event); +static void bfa_fcs_lport_fdmi_sm_rprt_retry( + struct bfa_fcs_lport_fdmi_s *fdmi, + enum port_fdmi_event event); +static void bfa_fcs_lport_fdmi_sm_sending_rpa( + struct bfa_fcs_lport_fdmi_s *fdmi, + enum port_fdmi_event event); +static void bfa_fcs_lport_fdmi_sm_rpa(struct bfa_fcs_lport_fdmi_s *fdmi, + enum port_fdmi_event event); +static void bfa_fcs_lport_fdmi_sm_rpa_retry( + struct bfa_fcs_lport_fdmi_s *fdmi, + enum port_fdmi_event event); +static void bfa_fcs_lport_fdmi_sm_online(struct bfa_fcs_lport_fdmi_s *fdmi, + enum port_fdmi_event event); +static void bfa_fcs_lport_fdmi_sm_disabled( + struct bfa_fcs_lport_fdmi_s *fdmi, + enum port_fdmi_event event); +/** + * Start in offline state - awaiting MS to send start. + */ +static void +bfa_fcs_lport_fdmi_sm_offline(struct bfa_fcs_lport_fdmi_s *fdmi, + enum port_fdmi_event event) +{ + struct bfa_fcs_lport_s *port = fdmi->ms->port; + + bfa_trc(port->fcs, port->port_cfg.pwwn); + bfa_trc(port->fcs, event); + + fdmi->retry_cnt = 0; + + switch (event) { + case FDMISM_EVENT_PORT_ONLINE: + if (port->vport) { + /* + * For Vports, register a new port. + */ + bfa_sm_set_state(fdmi, + bfa_fcs_lport_fdmi_sm_sending_rprt); + bfa_fcs_lport_fdmi_send_rprt(fdmi, NULL); + } else { + /* + * For a base port, we should first register the HBA + * atribute. The HBA attribute also contains the base + * port registration. + */ + bfa_sm_set_state(fdmi, + bfa_fcs_lport_fdmi_sm_sending_rhba); + bfa_fcs_lport_fdmi_send_rhba(fdmi, NULL); + } + break; + + case FDMISM_EVENT_PORT_OFFLINE: + break; + + default: + bfa_sm_fault(port->fcs, event); + } +} + +static void +bfa_fcs_lport_fdmi_sm_sending_rhba(struct bfa_fcs_lport_fdmi_s *fdmi, + enum port_fdmi_event event) +{ + struct bfa_fcs_lport_s *port = fdmi->ms->port; + + bfa_trc(port->fcs, port->port_cfg.pwwn); + bfa_trc(port->fcs, event); + + switch (event) { + case FDMISM_EVENT_RHBA_SENT: + bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_rhba); + break; + + case FDMISM_EVENT_PORT_OFFLINE: + bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline); + bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(port), + &fdmi->fcxp_wqe); + break; + + default: + bfa_sm_fault(port->fcs, event); + } +} + +static void +bfa_fcs_lport_fdmi_sm_rhba(struct bfa_fcs_lport_fdmi_s *fdmi, + enum port_fdmi_event event) +{ + struct bfa_fcs_lport_s *port = fdmi->ms->port; + + bfa_trc(port->fcs, port->port_cfg.pwwn); + bfa_trc(port->fcs, event); + + switch (event) { + case FDMISM_EVENT_RSP_ERROR: + /* + * if max retries have not been reached, start timer for a + * delayed retry + */ + if (fdmi->retry_cnt++ < BFA_FCS_FDMI_CMD_MAX_RETRIES) { + bfa_sm_set_state(fdmi, + bfa_fcs_lport_fdmi_sm_rhba_retry); + bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(port), + &fdmi->timer, + bfa_fcs_lport_fdmi_timeout, fdmi, + BFA_FCS_RETRY_TIMEOUT); + } else { + /* + * set state to offline + */ + bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline); + } + break; + + case FDMISM_EVENT_RSP_OK: + /* + * Initiate Register Port Attributes + */ + bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_sending_rpa); + fdmi->retry_cnt = 0; + bfa_fcs_lport_fdmi_send_rpa(fdmi, NULL); + break; + + case FDMISM_EVENT_PORT_OFFLINE: + bfa_fcxp_discard(fdmi->fcxp); + bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline); + break; + + default: + bfa_sm_fault(port->fcs, event); + } +} + +static void +bfa_fcs_lport_fdmi_sm_rhba_retry(struct bfa_fcs_lport_fdmi_s *fdmi, + enum port_fdmi_event event) +{ + struct bfa_fcs_lport_s *port = fdmi->ms->port; + + bfa_trc(port->fcs, port->port_cfg.pwwn); + bfa_trc(port->fcs, event); + + switch (event) { + case FDMISM_EVENT_TIMEOUT: + /* + * Retry Timer Expired. Re-send + */ + bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_sending_rhba); + bfa_fcs_lport_fdmi_send_rhba(fdmi, NULL); + break; + + case FDMISM_EVENT_PORT_OFFLINE: + bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline); + bfa_timer_stop(&fdmi->timer); + break; + + default: + bfa_sm_fault(port->fcs, event); + } +} + +/* +* RPRT : Register Port + */ +static void +bfa_fcs_lport_fdmi_sm_sending_rprt(struct bfa_fcs_lport_fdmi_s *fdmi, + enum port_fdmi_event event) +{ + struct bfa_fcs_lport_s *port = fdmi->ms->port; + + bfa_trc(port->fcs, port->port_cfg.pwwn); + bfa_trc(port->fcs, event); + + switch (event) { + case FDMISM_EVENT_RPRT_SENT: + bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_rprt); + break; + + case FDMISM_EVENT_PORT_OFFLINE: + bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline); + bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(port), + &fdmi->fcxp_wqe); + break; + + default: + bfa_sm_fault(port->fcs, event); + } +} + +static void +bfa_fcs_lport_fdmi_sm_rprt(struct bfa_fcs_lport_fdmi_s *fdmi, + enum port_fdmi_event event) +{ + struct bfa_fcs_lport_s *port = fdmi->ms->port; + + bfa_trc(port->fcs, port->port_cfg.pwwn); + bfa_trc(port->fcs, event); + + switch (event) { + case FDMISM_EVENT_RSP_ERROR: + /* + * if max retries have not been reached, start timer for a + * delayed retry + */ + if (fdmi->retry_cnt++ < BFA_FCS_FDMI_CMD_MAX_RETRIES) { + bfa_sm_set_state(fdmi, + bfa_fcs_lport_fdmi_sm_rprt_retry); + bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(port), + &fdmi->timer, + bfa_fcs_lport_fdmi_timeout, fdmi, + BFA_FCS_RETRY_TIMEOUT); + + } else { + /* + * set state to offline + */ + bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline); + fdmi->retry_cnt = 0; + } + break; + + case FDMISM_EVENT_RSP_OK: + fdmi->retry_cnt = 0; + bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_online); + break; + + case FDMISM_EVENT_PORT_OFFLINE: + bfa_fcxp_discard(fdmi->fcxp); + bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline); + break; + + default: + bfa_sm_fault(port->fcs, event); + } +} + +static void +bfa_fcs_lport_fdmi_sm_rprt_retry(struct bfa_fcs_lport_fdmi_s *fdmi, + enum port_fdmi_event event) +{ + struct bfa_fcs_lport_s *port = fdmi->ms->port; + + bfa_trc(port->fcs, port->port_cfg.pwwn); + bfa_trc(port->fcs, event); + + switch (event) { + case FDMISM_EVENT_TIMEOUT: + /* + * Retry Timer Expired. Re-send + */ + bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_sending_rprt); + bfa_fcs_lport_fdmi_send_rprt(fdmi, NULL); + break; + + case FDMISM_EVENT_PORT_OFFLINE: + bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline); + bfa_timer_stop(&fdmi->timer); + break; + + default: + bfa_sm_fault(port->fcs, event); + } +} + +/* + * Register Port Attributes + */ +static void +bfa_fcs_lport_fdmi_sm_sending_rpa(struct bfa_fcs_lport_fdmi_s *fdmi, + enum port_fdmi_event event) +{ + struct bfa_fcs_lport_s *port = fdmi->ms->port; + + bfa_trc(port->fcs, port->port_cfg.pwwn); + bfa_trc(port->fcs, event); + + switch (event) { + case FDMISM_EVENT_RPA_SENT: + bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_rpa); + break; + + case FDMISM_EVENT_PORT_OFFLINE: + bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline); + bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(port), + &fdmi->fcxp_wqe); + break; + + default: + bfa_sm_fault(port->fcs, event); + } +} + +static void +bfa_fcs_lport_fdmi_sm_rpa(struct bfa_fcs_lport_fdmi_s *fdmi, + enum port_fdmi_event event) +{ + struct bfa_fcs_lport_s *port = fdmi->ms->port; + + bfa_trc(port->fcs, port->port_cfg.pwwn); + bfa_trc(port->fcs, event); + + switch (event) { + case FDMISM_EVENT_RSP_ERROR: + /* + * if max retries have not been reached, start timer for a + * delayed retry + */ + if (fdmi->retry_cnt++ < BFA_FCS_FDMI_CMD_MAX_RETRIES) { + bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_rpa_retry); + bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(port), + &fdmi->timer, + bfa_fcs_lport_fdmi_timeout, fdmi, + BFA_FCS_RETRY_TIMEOUT); + } else { + /* + * set state to offline + */ + bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline); + fdmi->retry_cnt = 0; + } + break; + + case FDMISM_EVENT_RSP_OK: + bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_online); + fdmi->retry_cnt = 0; + break; + + case FDMISM_EVENT_PORT_OFFLINE: + bfa_fcxp_discard(fdmi->fcxp); + bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline); + break; + + default: + bfa_sm_fault(port->fcs, event); + } +} + +static void +bfa_fcs_lport_fdmi_sm_rpa_retry(struct bfa_fcs_lport_fdmi_s *fdmi, + enum port_fdmi_event event) +{ + struct bfa_fcs_lport_s *port = fdmi->ms->port; + + bfa_trc(port->fcs, port->port_cfg.pwwn); + bfa_trc(port->fcs, event); + + switch (event) { + case FDMISM_EVENT_TIMEOUT: + /* + * Retry Timer Expired. Re-send + */ + bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_sending_rpa); + bfa_fcs_lport_fdmi_send_rpa(fdmi, NULL); + break; + + case FDMISM_EVENT_PORT_OFFLINE: + bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline); + bfa_timer_stop(&fdmi->timer); + break; + + default: + bfa_sm_fault(port->fcs, event); + } +} + +static void +bfa_fcs_lport_fdmi_sm_online(struct bfa_fcs_lport_fdmi_s *fdmi, + enum port_fdmi_event event) +{ + struct bfa_fcs_lport_s *port = fdmi->ms->port; + + bfa_trc(port->fcs, port->port_cfg.pwwn); + bfa_trc(port->fcs, event); + + switch (event) { + case FDMISM_EVENT_PORT_OFFLINE: + bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline); + break; + + default: + bfa_sm_fault(port->fcs, event); + } +} +/** + * FDMI is disabled state. + */ +static void +bfa_fcs_lport_fdmi_sm_disabled(struct bfa_fcs_lport_fdmi_s *fdmi, + enum port_fdmi_event event) +{ + struct bfa_fcs_lport_s *port = fdmi->ms->port; + + bfa_trc(port->fcs, port->port_cfg.pwwn); + bfa_trc(port->fcs, event); + + /* No op State. It can only be enabled at Driver Init. */ +} + +/** +* RHBA : Register HBA Attributes. + */ +static void +bfa_fcs_lport_fdmi_send_rhba(void *fdmi_cbarg, struct bfa_fcxp_s *fcxp_alloced) +{ + struct bfa_fcs_lport_fdmi_s *fdmi = fdmi_cbarg; + struct bfa_fcs_lport_s *port = fdmi->ms->port; + struct fchs_s fchs; + int len, attr_len; + struct bfa_fcxp_s *fcxp; + u8 *pyld; + + bfa_trc(port->fcs, port->port_cfg.pwwn); + + fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); + if (!fcxp) { + bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &fdmi->fcxp_wqe, + bfa_fcs_lport_fdmi_send_rhba, fdmi); + return; + } + fdmi->fcxp = fcxp; + + pyld = bfa_fcxp_get_reqbuf(fcxp); + bfa_os_memset(pyld, 0, FC_MAX_PDUSZ); + + len = fc_fdmi_reqhdr_build(&fchs, pyld, bfa_fcs_lport_get_fcid(port), + FDMI_RHBA); + + attr_len = + bfa_fcs_lport_fdmi_build_rhba_pyld(fdmi, + (u8 *) ((struct ct_hdr_s *) pyld + + 1)); + + bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, + FC_CLASS_3, (len + attr_len), &fchs, + bfa_fcs_lport_fdmi_rhba_response, (void *)fdmi, + FC_MAX_PDUSZ, FC_FCCT_TOV); + + bfa_sm_send_event(fdmi, FDMISM_EVENT_RHBA_SENT); +} + +static u16 +bfa_fcs_lport_fdmi_build_rhba_pyld(struct bfa_fcs_lport_fdmi_s *fdmi, u8 *pyld) +{ + struct bfa_fcs_lport_s *port = fdmi->ms->port; + struct bfa_fcs_fdmi_hba_attr_s hba_attr; + struct bfa_fcs_fdmi_hba_attr_s *fcs_hba_attr = &hba_attr; + struct fdmi_rhba_s *rhba = (struct fdmi_rhba_s *) pyld; + struct fdmi_attr_s *attr; + u8 *curr_ptr; + u16 len, count; + + /* + * get hba attributes + */ + bfa_fcs_fdmi_get_hbaattr(fdmi, fcs_hba_attr); + + rhba->hba_id = bfa_fcs_lport_get_pwwn(port); + rhba->port_list.num_ports = bfa_os_htonl(1); + rhba->port_list.port_entry = bfa_fcs_lport_get_pwwn(port); + + len = sizeof(rhba->hba_id) + sizeof(rhba->port_list); + + count = 0; + len += sizeof(rhba->hba_attr_blk.attr_count); + + /* + * fill out the invididual entries of the HBA attrib Block + */ + curr_ptr = (u8 *) &rhba->hba_attr_blk.hba_attr; + + /* + * Node Name + */ + attr = (struct fdmi_attr_s *) curr_ptr; + attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_NODENAME); + attr->len = sizeof(wwn_t); + memcpy(attr->value, &bfa_fcs_lport_get_nwwn(port), attr->len); + curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len; + len += attr->len; + count++; + attr->len = + bfa_os_htons(attr->len + sizeof(attr->type) + + sizeof(attr->len)); + + /* + * Manufacturer + */ + attr = (struct fdmi_attr_s *) curr_ptr; + attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_MANUFACTURER); + attr->len = (u16) strlen(fcs_hba_attr->manufacturer); + memcpy(attr->value, fcs_hba_attr->manufacturer, attr->len); + attr->len = fc_roundup(attr->len, sizeof(u32)); /* variable + *fields need + *to be 4 byte + *aligned */ + curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len; + len += attr->len; + count++; + attr->len = + bfa_os_htons(attr->len + sizeof(attr->type) + + sizeof(attr->len)); + + /* + * Serial Number + */ + attr = (struct fdmi_attr_s *) curr_ptr; + attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_SERIALNUM); + attr->len = (u16) strlen(fcs_hba_attr->serial_num); + memcpy(attr->value, fcs_hba_attr->serial_num, attr->len); + attr->len = fc_roundup(attr->len, sizeof(u32)); /* variable + *fields need + *to be 4 byte + *aligned */ + curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len; + len += attr->len; + count++; + attr->len = + bfa_os_htons(attr->len + sizeof(attr->type) + + sizeof(attr->len)); + + /* + * Model + */ + attr = (struct fdmi_attr_s *) curr_ptr; + attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_MODEL); + attr->len = (u16) strlen(fcs_hba_attr->model); + memcpy(attr->value, fcs_hba_attr->model, attr->len); + attr->len = fc_roundup(attr->len, sizeof(u32)); /* variable + *fields need + *to be 4 byte + *aligned */ + curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len; + len += attr->len; + count++; + attr->len = + bfa_os_htons(attr->len + sizeof(attr->type) + + sizeof(attr->len)); + + /* + * Model Desc + */ + attr = (struct fdmi_attr_s *) curr_ptr; + attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_MODEL_DESC); + attr->len = (u16) strlen(fcs_hba_attr->model_desc); + memcpy(attr->value, fcs_hba_attr->model_desc, attr->len); + attr->len = fc_roundup(attr->len, sizeof(u32)); /* variable + *fields need + *to be 4 byte + *aligned */ + curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len; + len += attr->len; + count++; + attr->len = + bfa_os_htons(attr->len + sizeof(attr->type) + + sizeof(attr->len)); + + /* + * H/W Version + */ + if (fcs_hba_attr->hw_version[0] != '\0') { + attr = (struct fdmi_attr_s *) curr_ptr; + attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_HW_VERSION); + attr->len = (u16) strlen(fcs_hba_attr->hw_version); + memcpy(attr->value, fcs_hba_attr->hw_version, attr->len); + attr->len = fc_roundup(attr->len, sizeof(u32)); /* variable + *fields need + *to be 4 byte + *aligned */ + curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len; + len += attr->len; + count++; + attr->len = + bfa_os_htons(attr->len + sizeof(attr->type) + + sizeof(attr->len)); + } + + /* + * Driver Version + */ + attr = (struct fdmi_attr_s *) curr_ptr; + attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_DRIVER_VERSION); + attr->len = (u16) strlen(fcs_hba_attr->driver_version); + memcpy(attr->value, fcs_hba_attr->driver_version, attr->len); + attr->len = fc_roundup(attr->len, sizeof(u32)); /* variable + *fields need + *to be 4 byte + *aligned */ + curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len; + len += attr->len;; + count++; + attr->len = + bfa_os_htons(attr->len + sizeof(attr->type) + + sizeof(attr->len)); + + /* + * Option Rom Version + */ + if (fcs_hba_attr->option_rom_ver[0] != '\0') { + attr = (struct fdmi_attr_s *) curr_ptr; + attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_ROM_VERSION); + attr->len = (u16) strlen(fcs_hba_attr->option_rom_ver); + memcpy(attr->value, fcs_hba_attr->option_rom_ver, attr->len); + attr->len = fc_roundup(attr->len, sizeof(u32)); /* variable + *fields need + *to be 4 byte + *aligned */ + curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len; + len += attr->len; + count++; + attr->len = + bfa_os_htons(attr->len + sizeof(attr->type) + + sizeof(attr->len)); + } + + /* + * f/w Version = driver version + */ + attr = (struct fdmi_attr_s *) curr_ptr; + attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_FW_VERSION); + attr->len = (u16) strlen(fcs_hba_attr->driver_version); + memcpy(attr->value, fcs_hba_attr->driver_version, attr->len); + attr->len = fc_roundup(attr->len, sizeof(u32)); /* variable + *fields need + *to be 4 byte + *aligned */ + curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len; + len += attr->len; + count++; + attr->len = + bfa_os_htons(attr->len + sizeof(attr->type) + + sizeof(attr->len)); + + /* + * OS Name + */ + if (fcs_hba_attr->os_name[0] != '\0') { + attr = (struct fdmi_attr_s *) curr_ptr; + attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_OS_NAME); + attr->len = (u16) strlen(fcs_hba_attr->os_name); + memcpy(attr->value, fcs_hba_attr->os_name, attr->len); + attr->len = fc_roundup(attr->len, sizeof(u32)); /* variable + *fields need + *to be 4 byte + *aligned */ + curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len; + len += attr->len; + count++; + attr->len = + bfa_os_htons(attr->len + sizeof(attr->type) + + sizeof(attr->len)); + } + + /* + * MAX_CT_PAYLOAD + */ + attr = (struct fdmi_attr_s *) curr_ptr; + attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_MAX_CT); + attr->len = sizeof(fcs_hba_attr->max_ct_pyld); + memcpy(attr->value, &fcs_hba_attr->max_ct_pyld, attr->len); + len += attr->len; + count++; + attr->len = + bfa_os_htons(attr->len + sizeof(attr->type) + + sizeof(attr->len)); + + /* + * Update size of payload + */ + len += ((sizeof(attr->type) + + sizeof(attr->len)) * count); + + rhba->hba_attr_blk.attr_count = bfa_os_htonl(count); + return len; +} + +static void +bfa_fcs_lport_fdmi_rhba_response(void *fcsarg, struct bfa_fcxp_s *fcxp, + void *cbarg, bfa_status_t req_status, + u32 rsp_len, u32 resid_len, + struct fchs_s *rsp_fchs) +{ + struct bfa_fcs_lport_fdmi_s *fdmi = + (struct bfa_fcs_lport_fdmi_s *) cbarg; + struct bfa_fcs_lport_s *port = fdmi->ms->port; + struct ct_hdr_s *cthdr = NULL; + + bfa_trc(port->fcs, port->port_cfg.pwwn); + + /* + * Sanity Checks + */ + if (req_status != BFA_STATUS_OK) { + bfa_trc(port->fcs, req_status); + bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_ERROR); + return; + } + + cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp); + cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code); + + if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) { + bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_OK); + return; + } + + bfa_trc(port->fcs, cthdr->reason_code); + bfa_trc(port->fcs, cthdr->exp_code); + bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_ERROR); +} + +/** +* RPRT : Register Port + */ +static void +bfa_fcs_lport_fdmi_send_rprt(void *fdmi_cbarg, struct bfa_fcxp_s *fcxp_alloced) +{ + struct bfa_fcs_lport_fdmi_s *fdmi = fdmi_cbarg; + struct bfa_fcs_lport_s *port = fdmi->ms->port; + struct fchs_s fchs; + u16 len, attr_len; + struct bfa_fcxp_s *fcxp; + u8 *pyld; + + bfa_trc(port->fcs, port->port_cfg.pwwn); + + fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); + if (!fcxp) { + bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &fdmi->fcxp_wqe, + bfa_fcs_lport_fdmi_send_rprt, fdmi); + return; + } + fdmi->fcxp = fcxp; + + pyld = bfa_fcxp_get_reqbuf(fcxp); + bfa_os_memset(pyld, 0, FC_MAX_PDUSZ); + + len = fc_fdmi_reqhdr_build(&fchs, pyld, bfa_fcs_lport_get_fcid(port), + FDMI_RPRT); + + attr_len = + bfa_fcs_lport_fdmi_build_rprt_pyld(fdmi, + (u8 *) ((struct ct_hdr_s *) pyld + + 1)); + + bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, + FC_CLASS_3, len + attr_len, &fchs, + bfa_fcs_lport_fdmi_rprt_response, (void *)fdmi, + FC_MAX_PDUSZ, FC_FCCT_TOV); + + bfa_sm_send_event(fdmi, FDMISM_EVENT_RPRT_SENT); +} + +/** + * This routine builds Port Attribute Block that used in RPA, RPRT commands. + */ +static u16 +bfa_fcs_lport_fdmi_build_portattr_block(struct bfa_fcs_lport_fdmi_s *fdmi, + u8 *pyld) +{ + struct bfa_fcs_fdmi_port_attr_s fcs_port_attr; + struct fdmi_port_attr_s *port_attrib = (struct fdmi_port_attr_s *) pyld; + struct fdmi_attr_s *attr; + u8 *curr_ptr; + u16 len; + u8 count = 0; + + /* + * get port attributes + */ + bfa_fcs_fdmi_get_portattr(fdmi, &fcs_port_attr); + + len = sizeof(port_attrib->attr_count); + + /* + * fill out the invididual entries + */ + curr_ptr = (u8 *) &port_attrib->port_attr; + + /* + * FC4 Types + */ + attr = (struct fdmi_attr_s *) curr_ptr; + attr->type = bfa_os_htons(FDMI_PORT_ATTRIB_FC4_TYPES); + attr->len = sizeof(fcs_port_attr.supp_fc4_types); + memcpy(attr->value, fcs_port_attr.supp_fc4_types, attr->len); + curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len; + len += attr->len; + ++count; + attr->len = + bfa_os_htons(attr->len + sizeof(attr->type) + + sizeof(attr->len)); + + /* + * Supported Speed + */ + attr = (struct fdmi_attr_s *) curr_ptr; + attr->type = bfa_os_htons(FDMI_PORT_ATTRIB_SUPP_SPEED); + attr->len = sizeof(fcs_port_attr.supp_speed); + memcpy(attr->value, &fcs_port_attr.supp_speed, attr->len); + curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len; + len += attr->len; + ++count; + attr->len = + bfa_os_htons(attr->len + sizeof(attr->type) + + sizeof(attr->len)); + + /* + * current Port Speed + */ + attr = (struct fdmi_attr_s *) curr_ptr; + attr->type = bfa_os_htons(FDMI_PORT_ATTRIB_PORT_SPEED); + attr->len = sizeof(fcs_port_attr.curr_speed); + memcpy(attr->value, &fcs_port_attr.curr_speed, attr->len); + curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len; + len += attr->len; + ++count; + attr->len = + bfa_os_htons(attr->len + sizeof(attr->type) + + sizeof(attr->len)); + + /* + * max frame size + */ + attr = (struct fdmi_attr_s *) curr_ptr; + attr->type = bfa_os_htons(FDMI_PORT_ATTRIB_FRAME_SIZE); + attr->len = sizeof(fcs_port_attr.max_frm_size); + memcpy(attr->value, &fcs_port_attr.max_frm_size, attr->len); + curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len; + len += attr->len; + ++count; + attr->len = + bfa_os_htons(attr->len + sizeof(attr->type) + + sizeof(attr->len)); + + /* + * OS Device Name + */ + if (fcs_port_attr.os_device_name[0] != '\0') { + attr = (struct fdmi_attr_s *) curr_ptr; + attr->type = bfa_os_htons(FDMI_PORT_ATTRIB_DEV_NAME); + attr->len = (u16) strlen(fcs_port_attr.os_device_name); + memcpy(attr->value, fcs_port_attr.os_device_name, attr->len); + attr->len = fc_roundup(attr->len, sizeof(u32)); /* variable + *fields need + *to be 4 byte + *aligned */ + curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len; + len += attr->len; + ++count; + attr->len = + bfa_os_htons(attr->len + sizeof(attr->type) + + sizeof(attr->len)); + } + /* + * Host Name + */ + if (fcs_port_attr.host_name[0] != '\0') { + attr = (struct fdmi_attr_s *) curr_ptr; + attr->type = bfa_os_htons(FDMI_PORT_ATTRIB_HOST_NAME); + attr->len = (u16) strlen(fcs_port_attr.host_name); + memcpy(attr->value, fcs_port_attr.host_name, attr->len); + attr->len = fc_roundup(attr->len, sizeof(u32)); /* variable + *fields need + *to be 4 byte + *aligned */ + curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len; + len += attr->len; + ++count; + attr->len = + bfa_os_htons(attr->len + sizeof(attr->type) + + sizeof(attr->len)); + } + + /* + * Update size of payload + */ + port_attrib->attr_count = bfa_os_htonl(count); + len += ((sizeof(attr->type) + + sizeof(attr->len)) * count); + return len; +} + +static u16 +bfa_fcs_lport_fdmi_build_rprt_pyld(struct bfa_fcs_lport_fdmi_s *fdmi, u8 *pyld) +{ + struct bfa_fcs_lport_s *port = fdmi->ms->port; + struct fdmi_rprt_s *rprt = (struct fdmi_rprt_s *) pyld; + u16 len; + + rprt->hba_id = bfa_fcs_lport_get_pwwn(bfa_fcs_get_base_port(port->fcs)); + rprt->port_name = bfa_fcs_lport_get_pwwn(port); + + len = bfa_fcs_lport_fdmi_build_portattr_block(fdmi, + (u8 *) &rprt->port_attr_blk); + + len += sizeof(rprt->hba_id) + sizeof(rprt->port_name); + + return len; +} + +static void +bfa_fcs_lport_fdmi_rprt_response(void *fcsarg, struct bfa_fcxp_s *fcxp, + void *cbarg, bfa_status_t req_status, + u32 rsp_len, u32 resid_len, + struct fchs_s *rsp_fchs) +{ + struct bfa_fcs_lport_fdmi_s *fdmi = + (struct bfa_fcs_lport_fdmi_s *) cbarg; + struct bfa_fcs_lport_s *port = fdmi->ms->port; + struct ct_hdr_s *cthdr = NULL; + + bfa_trc(port->fcs, port->port_cfg.pwwn); + + /* + * Sanity Checks + */ + if (req_status != BFA_STATUS_OK) { + bfa_trc(port->fcs, req_status); + bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_ERROR); + return; + } + + cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp); + cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code); + + if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) { + bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_OK); + return; + } + + bfa_trc(port->fcs, cthdr->reason_code); + bfa_trc(port->fcs, cthdr->exp_code); + bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_ERROR); +} + +/** +* RPA : Register Port Attributes. + */ +static void +bfa_fcs_lport_fdmi_send_rpa(void *fdmi_cbarg, struct bfa_fcxp_s *fcxp_alloced) +{ + struct bfa_fcs_lport_fdmi_s *fdmi = fdmi_cbarg; + struct bfa_fcs_lport_s *port = fdmi->ms->port; + struct fchs_s fchs; + u16 len, attr_len; + struct bfa_fcxp_s *fcxp; + u8 *pyld; + + bfa_trc(port->fcs, port->port_cfg.pwwn); + + fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); + if (!fcxp) { + bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &fdmi->fcxp_wqe, + bfa_fcs_lport_fdmi_send_rpa, fdmi); + return; + } + fdmi->fcxp = fcxp; + + pyld = bfa_fcxp_get_reqbuf(fcxp); + bfa_os_memset(pyld, 0, FC_MAX_PDUSZ); + + len = fc_fdmi_reqhdr_build(&fchs, pyld, bfa_fcs_lport_get_fcid(port), + FDMI_RPA); + + attr_len = + bfa_fcs_lport_fdmi_build_rpa_pyld(fdmi, + (u8 *) ((struct ct_hdr_s *) pyld + + 1)); + + bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, + FC_CLASS_3, len + attr_len, &fchs, + bfa_fcs_lport_fdmi_rpa_response, (void *)fdmi, + FC_MAX_PDUSZ, FC_FCCT_TOV); + + bfa_sm_send_event(fdmi, FDMISM_EVENT_RPA_SENT); +} + +static u16 +bfa_fcs_lport_fdmi_build_rpa_pyld(struct bfa_fcs_lport_fdmi_s *fdmi, u8 *pyld) +{ + struct bfa_fcs_lport_s *port = fdmi->ms->port; + struct fdmi_rpa_s *rpa = (struct fdmi_rpa_s *) pyld; + u16 len; + + rpa->port_name = bfa_fcs_lport_get_pwwn(port); + + len = bfa_fcs_lport_fdmi_build_portattr_block(fdmi, + (u8 *) &rpa->port_attr_blk); + + len += sizeof(rpa->port_name); + + return len; +} + +static void +bfa_fcs_lport_fdmi_rpa_response(void *fcsarg, struct bfa_fcxp_s *fcxp, + void *cbarg, bfa_status_t req_status, u32 rsp_len, + u32 resid_len, struct fchs_s *rsp_fchs) +{ + struct bfa_fcs_lport_fdmi_s *fdmi = + (struct bfa_fcs_lport_fdmi_s *) cbarg; + struct bfa_fcs_lport_s *port = fdmi->ms->port; + struct ct_hdr_s *cthdr = NULL; + + bfa_trc(port->fcs, port->port_cfg.pwwn); + + /* + * Sanity Checks + */ + if (req_status != BFA_STATUS_OK) { + bfa_trc(port->fcs, req_status); + bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_ERROR); + return; + } + + cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp); + cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code); + + if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) { + bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_OK); + return; + } + + bfa_trc(port->fcs, cthdr->reason_code); + bfa_trc(port->fcs, cthdr->exp_code); + bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_ERROR); +} + +static void +bfa_fcs_lport_fdmi_timeout(void *arg) +{ + struct bfa_fcs_lport_fdmi_s *fdmi = (struct bfa_fcs_lport_fdmi_s *) arg; + + bfa_sm_send_event(fdmi, FDMISM_EVENT_TIMEOUT); +} + +void +bfa_fcs_fdmi_get_hbaattr(struct bfa_fcs_lport_fdmi_s *fdmi, + struct bfa_fcs_fdmi_hba_attr_s *hba_attr) +{ + struct bfa_fcs_lport_s *port = fdmi->ms->port; + struct bfa_fcs_driver_info_s *driver_info = &port->fcs->driver_info; + + bfa_os_memset(hba_attr, 0, sizeof(struct bfa_fcs_fdmi_hba_attr_s)); + + bfa_ioc_get_adapter_manufacturer(&port->fcs->bfa->ioc, + hba_attr->manufacturer); + bfa_ioc_get_adapter_serial_num(&port->fcs->bfa->ioc, + hba_attr->serial_num); + bfa_ioc_get_adapter_model(&port->fcs->bfa->ioc, + hba_attr->model); + bfa_ioc_get_adapter_model(&port->fcs->bfa->ioc, + hba_attr->model_desc); + bfa_ioc_get_pci_chip_rev(&port->fcs->bfa->ioc, + hba_attr->hw_version); + bfa_ioc_get_adapter_optrom_ver(&port->fcs->bfa->ioc, + hba_attr->option_rom_ver); + bfa_ioc_get_adapter_fw_ver(&port->fcs->bfa->ioc, + hba_attr->fw_version); + + strncpy(hba_attr->driver_version, (char *)driver_info->version, + sizeof(hba_attr->driver_version)); + + strncpy(hba_attr->os_name, driver_info->host_os_name, + sizeof(hba_attr->os_name)); + + /* + * If there is a patch level, append it + * to the os name along with a separator + */ + if (driver_info->host_os_patch[0] != '\0') { + strncat(hba_attr->os_name, BFA_FCS_PORT_SYMBNAME_SEPARATOR, + sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR)); + strncat(hba_attr->os_name, driver_info->host_os_patch, + sizeof(driver_info->host_os_patch)); + } + + hba_attr->max_ct_pyld = bfa_os_htonl(FC_MAX_PDUSZ); +} + +void +bfa_fcs_fdmi_get_portattr(struct bfa_fcs_lport_fdmi_s *fdmi, + struct bfa_fcs_fdmi_port_attr_s *port_attr) +{ + struct bfa_fcs_lport_s *port = fdmi->ms->port; + struct bfa_fcs_driver_info_s *driver_info = &port->fcs->driver_info; + struct bfa_port_attr_s pport_attr; + + bfa_os_memset(port_attr, 0, sizeof(struct bfa_fcs_fdmi_port_attr_s)); + + /* + * get pport attributes from hal + */ + bfa_fcport_get_attr(port->fcs->bfa, &pport_attr); + + /* + * get FC4 type Bitmask + */ + fc_get_fc4type_bitmask(FC_TYPE_FCP, port_attr->supp_fc4_types); + + /* + * Supported Speeds + */ + port_attr->supp_speed = bfa_os_htonl(BFA_FCS_FDMI_SUPORTED_SPEEDS); + + /* + * Current Speed + */ + port_attr->curr_speed = bfa_os_htonl(pport_attr.speed); + + /* + * Max PDU Size. + */ + port_attr->max_frm_size = bfa_os_htonl(FC_MAX_PDUSZ); + + /* + * OS device Name + */ + strncpy(port_attr->os_device_name, (char *)driver_info->os_device_name, + sizeof(port_attr->os_device_name)); + + /* + * Host name + */ + strncpy(port_attr->host_name, (char *)driver_info->host_machine_name, + sizeof(port_attr->host_name)); + +} + + +void +bfa_fcs_lport_fdmi_init(struct bfa_fcs_lport_ms_s *ms) +{ + struct bfa_fcs_lport_fdmi_s *fdmi = &ms->fdmi; + + fdmi->ms = ms; + if (ms->port->fcs->fdmi_enabled) + bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline); + else + bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_disabled); +} + +void +bfa_fcs_lport_fdmi_offline(struct bfa_fcs_lport_ms_s *ms) +{ + struct bfa_fcs_lport_fdmi_s *fdmi = &ms->fdmi; + + fdmi->ms = ms; + bfa_sm_send_event(fdmi, FDMISM_EVENT_PORT_OFFLINE); +} + +void +bfa_fcs_lport_fdmi_online(struct bfa_fcs_lport_ms_s *ms) +{ + struct bfa_fcs_lport_fdmi_s *fdmi = &ms->fdmi; + + fdmi->ms = ms; + bfa_sm_send_event(fdmi, FDMISM_EVENT_PORT_ONLINE); +} + +#define BFA_FCS_MS_CMD_MAX_RETRIES 2 + +/* + * forward declarations + */ +static void bfa_fcs_lport_ms_send_plogi(void *ms_cbarg, + struct bfa_fcxp_s *fcxp_alloced); +static void bfa_fcs_lport_ms_timeout(void *arg); +static void bfa_fcs_lport_ms_plogi_response(void *fcsarg, + struct bfa_fcxp_s *fcxp, + void *cbarg, + bfa_status_t req_status, + u32 rsp_len, + u32 resid_len, + struct fchs_s *rsp_fchs); + +static void bfa_fcs_lport_ms_send_gmal(void *ms_cbarg, + struct bfa_fcxp_s *fcxp_alloced); +static void bfa_fcs_lport_ms_gmal_response(void *fcsarg, + struct bfa_fcxp_s *fcxp, + void *cbarg, + bfa_status_t req_status, + u32 rsp_len, + u32 resid_len, + struct fchs_s *rsp_fchs); +static void bfa_fcs_lport_ms_send_gfn(void *ms_cbarg, + struct bfa_fcxp_s *fcxp_alloced); +static void bfa_fcs_lport_ms_gfn_response(void *fcsarg, + struct bfa_fcxp_s *fcxp, + void *cbarg, + bfa_status_t req_status, + u32 rsp_len, + u32 resid_len, + struct fchs_s *rsp_fchs); +/** + * fcs_ms_sm FCS MS state machine + */ + +/** + * MS State Machine events + */ +enum port_ms_event { + MSSM_EVENT_PORT_ONLINE = 1, + MSSM_EVENT_PORT_OFFLINE = 2, + MSSM_EVENT_RSP_OK = 3, + MSSM_EVENT_RSP_ERROR = 4, + MSSM_EVENT_TIMEOUT = 5, + MSSM_EVENT_FCXP_SENT = 6, + MSSM_EVENT_PORT_FABRIC_RSCN = 7 +}; + +static void bfa_fcs_lport_ms_sm_offline(struct bfa_fcs_lport_ms_s *ms, + enum port_ms_event event); +static void bfa_fcs_lport_ms_sm_plogi_sending(struct bfa_fcs_lport_ms_s *ms, + enum port_ms_event event); +static void bfa_fcs_lport_ms_sm_plogi(struct bfa_fcs_lport_ms_s *ms, + enum port_ms_event event); +static void bfa_fcs_lport_ms_sm_plogi_retry(struct bfa_fcs_lport_ms_s *ms, + enum port_ms_event event); +static void bfa_fcs_lport_ms_sm_gmal_sending(struct bfa_fcs_lport_ms_s *ms, + enum port_ms_event event); +static void bfa_fcs_lport_ms_sm_gmal(struct bfa_fcs_lport_ms_s *ms, + enum port_ms_event event); +static void bfa_fcs_lport_ms_sm_gmal_retry(struct bfa_fcs_lport_ms_s *ms, + enum port_ms_event event); +static void bfa_fcs_lport_ms_sm_gfn_sending(struct bfa_fcs_lport_ms_s *ms, + enum port_ms_event event); +static void bfa_fcs_lport_ms_sm_gfn(struct bfa_fcs_lport_ms_s *ms, + enum port_ms_event event); +static void bfa_fcs_lport_ms_sm_gfn_retry(struct bfa_fcs_lport_ms_s *ms, + enum port_ms_event event); +static void bfa_fcs_lport_ms_sm_online(struct bfa_fcs_lport_ms_s *ms, + enum port_ms_event event); +/** + * Start in offline state - awaiting NS to send start. + */ +static void +bfa_fcs_lport_ms_sm_offline(struct bfa_fcs_lport_ms_s *ms, + enum port_ms_event event) +{ + bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn); + bfa_trc(ms->port->fcs, event); + + switch (event) { + case MSSM_EVENT_PORT_ONLINE: + bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_plogi_sending); + bfa_fcs_lport_ms_send_plogi(ms, NULL); + break; + + case MSSM_EVENT_PORT_OFFLINE: + break; + + default: + bfa_sm_fault(ms->port->fcs, event); + } +} + +static void +bfa_fcs_lport_ms_sm_plogi_sending(struct bfa_fcs_lport_ms_s *ms, + enum port_ms_event event) +{ + bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn); + bfa_trc(ms->port->fcs, event); + + switch (event) { + case MSSM_EVENT_FCXP_SENT: + bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_plogi); + break; + + case MSSM_EVENT_PORT_OFFLINE: + bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_offline); + bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ms->port), + &ms->fcxp_wqe); + break; + + default: + bfa_sm_fault(ms->port->fcs, event); + } +} + +static void +bfa_fcs_lport_ms_sm_plogi(struct bfa_fcs_lport_ms_s *ms, + enum port_ms_event event) +{ + bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn); + bfa_trc(ms->port->fcs, event); + + switch (event) { + case MSSM_EVENT_RSP_ERROR: + /* + * Start timer for a delayed retry + */ + bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_plogi_retry); + ms->port->stats.ms_retries++; + bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ms->port), + &ms->timer, bfa_fcs_lport_ms_timeout, ms, + BFA_FCS_RETRY_TIMEOUT); + break; + + case MSSM_EVENT_RSP_OK: + /* + * since plogi is done, now invoke MS related sub-modules + */ + bfa_fcs_lport_fdmi_online(ms); + + /** + * if this is a Vport, go to online state. + */ + if (ms->port->vport) { + bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_online); + break; + } + + /* + * For a base port we need to get the + * switch's IP address. + */ + bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_gmal_sending); + bfa_fcs_lport_ms_send_gmal(ms, NULL); + break; + + case MSSM_EVENT_PORT_OFFLINE: + bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_offline); + bfa_fcxp_discard(ms->fcxp); + break; + + default: + bfa_sm_fault(ms->port->fcs, event); + } +} + +static void +bfa_fcs_lport_ms_sm_plogi_retry(struct bfa_fcs_lport_ms_s *ms, + enum port_ms_event event) +{ + bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn); + bfa_trc(ms->port->fcs, event); + + switch (event) { + case MSSM_EVENT_TIMEOUT: + /* + * Retry Timer Expired. Re-send + */ + bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_plogi_sending); + bfa_fcs_lport_ms_send_plogi(ms, NULL); + break; + + case MSSM_EVENT_PORT_OFFLINE: + bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_offline); + bfa_timer_stop(&ms->timer); + break; + + default: + bfa_sm_fault(ms->port->fcs, event); + } +} + +static void +bfa_fcs_lport_ms_sm_online(struct bfa_fcs_lport_ms_s *ms, + enum port_ms_event event) +{ + bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn); + bfa_trc(ms->port->fcs, event); + + switch (event) { + case MSSM_EVENT_PORT_OFFLINE: + bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_offline); + break; + + case MSSM_EVENT_PORT_FABRIC_RSCN: + bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_gfn_sending); + ms->retry_cnt = 0; + bfa_fcs_lport_ms_send_gfn(ms, NULL); + break; + + default: + bfa_sm_fault(ms->port->fcs, event); + } +} + +static void +bfa_fcs_lport_ms_sm_gmal_sending(struct bfa_fcs_lport_ms_s *ms, + enum port_ms_event event) +{ + bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn); + bfa_trc(ms->port->fcs, event); + + switch (event) { + case MSSM_EVENT_FCXP_SENT: + bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_gmal); + break; + + case MSSM_EVENT_PORT_OFFLINE: + bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_offline); + bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ms->port), + &ms->fcxp_wqe); + break; + + default: + bfa_sm_fault(ms->port->fcs, event); + } +} + +static void +bfa_fcs_lport_ms_sm_gmal(struct bfa_fcs_lport_ms_s *ms, + enum port_ms_event event) +{ + bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn); + bfa_trc(ms->port->fcs, event); + + switch (event) { + case MSSM_EVENT_RSP_ERROR: + /* + * Start timer for a delayed retry + */ + if (ms->retry_cnt++ < BFA_FCS_MS_CMD_MAX_RETRIES) { + bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_gmal_retry); + ms->port->stats.ms_retries++; + bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ms->port), + &ms->timer, bfa_fcs_lport_ms_timeout, ms, + BFA_FCS_RETRY_TIMEOUT); + } else { + bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_gfn_sending); + bfa_fcs_lport_ms_send_gfn(ms, NULL); + ms->retry_cnt = 0; + } + break; + + case MSSM_EVENT_RSP_OK: + bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_gfn_sending); + bfa_fcs_lport_ms_send_gfn(ms, NULL); + break; + + case MSSM_EVENT_PORT_OFFLINE: + bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_offline); + bfa_fcxp_discard(ms->fcxp); + break; + + default: + bfa_sm_fault(ms->port->fcs, event); + } +} + +static void +bfa_fcs_lport_ms_sm_gmal_retry(struct bfa_fcs_lport_ms_s *ms, + enum port_ms_event event) +{ + bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn); + bfa_trc(ms->port->fcs, event); + + switch (event) { + case MSSM_EVENT_TIMEOUT: + /* + * Retry Timer Expired. Re-send + */ + bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_gmal_sending); + bfa_fcs_lport_ms_send_gmal(ms, NULL); + break; + + case MSSM_EVENT_PORT_OFFLINE: + bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_offline); + bfa_timer_stop(&ms->timer); + break; + + default: + bfa_sm_fault(ms->port->fcs, event); + } +} +/** + * ms_pvt MS local functions + */ + +static void +bfa_fcs_lport_ms_send_gmal(void *ms_cbarg, struct bfa_fcxp_s *fcxp_alloced) +{ + struct bfa_fcs_lport_ms_s *ms = ms_cbarg; + bfa_fcs_lport_t *port = ms->port; + struct fchs_s fchs; + int len; + struct bfa_fcxp_s *fcxp; + + bfa_trc(port->fcs, port->pid); + + fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); + if (!fcxp) { + bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &ms->fcxp_wqe, + bfa_fcs_lport_ms_send_gmal, ms); + return; + } + ms->fcxp = fcxp; + + len = fc_gmal_req_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), + bfa_fcs_lport_get_fcid(port), + bfa_lps_get_peer_nwwn(port->fabric->lps)); + + bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, + FC_CLASS_3, len, &fchs, + bfa_fcs_lport_ms_gmal_response, (void *)ms, + FC_MAX_PDUSZ, FC_FCCT_TOV); + + bfa_sm_send_event(ms, MSSM_EVENT_FCXP_SENT); +} + +static void +bfa_fcs_lport_ms_gmal_response(void *fcsarg, struct bfa_fcxp_s *fcxp, + void *cbarg, bfa_status_t req_status, + u32 rsp_len, u32 resid_len, + struct fchs_s *rsp_fchs) +{ + struct bfa_fcs_lport_ms_s *ms = (struct bfa_fcs_lport_ms_s *) cbarg; + bfa_fcs_lport_t *port = ms->port; + struct ct_hdr_s *cthdr = NULL; + struct fcgs_gmal_resp_s *gmal_resp; + struct fcgs_gmal_entry_s *gmal_entry; + u32 num_entries; + u8 *rsp_str; + + bfa_trc(port->fcs, req_status); + bfa_trc(port->fcs, port->port_cfg.pwwn); + + /* + * Sanity Checks + */ + if (req_status != BFA_STATUS_OK) { + bfa_trc(port->fcs, req_status); + bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR); + return; + } + + cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp); + cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code); + + if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) { + gmal_resp = (struct fcgs_gmal_resp_s *)(cthdr + 1); + + num_entries = bfa_os_ntohl(gmal_resp->ms_len); + if (num_entries == 0) { + bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR); + return; + } + /* + * The response could contain multiple Entries. + * Entries for SNMP interface, etc. + * We look for the entry with a telnet prefix. + * First "http://" entry refers to IP addr + */ + + gmal_entry = (struct fcgs_gmal_entry_s *)gmal_resp->ms_ma; + while (num_entries > 0) { + if (strncmp(gmal_entry->prefix, + CT_GMAL_RESP_PREFIX_HTTP, + sizeof(gmal_entry->prefix)) == 0) { + + /* + * if the IP address is terminating with a '/', + * remove it. + * Byte 0 consists of the length of the string. + */ + rsp_str = &(gmal_entry->prefix[0]); + if (rsp_str[gmal_entry->len-1] == '/') + rsp_str[gmal_entry->len-1] = 0; + + /* copy IP Address to fabric */ + strncpy(bfa_fcs_lport_get_fabric_ipaddr(port), + gmal_entry->ip_addr, + BFA_FCS_FABRIC_IPADDR_SZ); + break; + } else { + --num_entries; + ++gmal_entry; + } + } + + bfa_sm_send_event(ms, MSSM_EVENT_RSP_OK); + return; + } + + bfa_trc(port->fcs, cthdr->reason_code); + bfa_trc(port->fcs, cthdr->exp_code); + bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR); +} + +static void +bfa_fcs_lport_ms_sm_gfn_sending(struct bfa_fcs_lport_ms_s *ms, + enum port_ms_event event) +{ + bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn); + bfa_trc(ms->port->fcs, event); + + switch (event) { + case MSSM_EVENT_FCXP_SENT: + bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_gfn); + break; + + case MSSM_EVENT_PORT_OFFLINE: + bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_offline); + bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ms->port), + &ms->fcxp_wqe); + break; + + default: + bfa_sm_fault(ms->port->fcs, event); + } +} + +static void +bfa_fcs_lport_ms_sm_gfn(struct bfa_fcs_lport_ms_s *ms, + enum port_ms_event event) +{ + bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn); + bfa_trc(ms->port->fcs, event); + + switch (event) { + case MSSM_EVENT_RSP_ERROR: + /* + * Start timer for a delayed retry + */ + if (ms->retry_cnt++ < BFA_FCS_MS_CMD_MAX_RETRIES) { + bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_gfn_retry); + ms->port->stats.ms_retries++; + bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ms->port), + &ms->timer, bfa_fcs_lport_ms_timeout, ms, + BFA_FCS_RETRY_TIMEOUT); + } else { + bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_online); + ms->retry_cnt = 0; + } + break; + + case MSSM_EVENT_RSP_OK: + bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_online); + break; + + case MSSM_EVENT_PORT_OFFLINE: + bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_offline); + bfa_fcxp_discard(ms->fcxp); + break; + + default: + bfa_sm_fault(ms->port->fcs, event); + } +} + +static void +bfa_fcs_lport_ms_sm_gfn_retry(struct bfa_fcs_lport_ms_s *ms, + enum port_ms_event event) +{ + bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn); + bfa_trc(ms->port->fcs, event); + + switch (event) { + case MSSM_EVENT_TIMEOUT: + /* + * Retry Timer Expired. Re-send + */ + bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_gfn_sending); + bfa_fcs_lport_ms_send_gfn(ms, NULL); + break; + + case MSSM_EVENT_PORT_OFFLINE: + bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_offline); + bfa_timer_stop(&ms->timer); + break; + + default: + bfa_sm_fault(ms->port->fcs, event); + } +} +/** + * ms_pvt MS local functions + */ + +static void +bfa_fcs_lport_ms_send_gfn(void *ms_cbarg, struct bfa_fcxp_s *fcxp_alloced) +{ + struct bfa_fcs_lport_ms_s *ms = ms_cbarg; + bfa_fcs_lport_t *port = ms->port; + struct fchs_s fchs; + int len; + struct bfa_fcxp_s *fcxp; + + bfa_trc(port->fcs, port->pid); + + fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); + if (!fcxp) { + bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &ms->fcxp_wqe, + bfa_fcs_lport_ms_send_gfn, ms); + return; + } + ms->fcxp = fcxp; + + len = fc_gfn_req_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), + bfa_fcs_lport_get_fcid(port), + bfa_lps_get_peer_nwwn(port->fabric->lps)); + + bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, + FC_CLASS_3, len, &fchs, + bfa_fcs_lport_ms_gfn_response, (void *)ms, + FC_MAX_PDUSZ, FC_FCCT_TOV); + + bfa_sm_send_event(ms, MSSM_EVENT_FCXP_SENT); +} + +static void +bfa_fcs_lport_ms_gfn_response(void *fcsarg, struct bfa_fcxp_s *fcxp, + void *cbarg, bfa_status_t req_status, u32 rsp_len, + u32 resid_len, struct fchs_s *rsp_fchs) +{ + struct bfa_fcs_lport_ms_s *ms = (struct bfa_fcs_lport_ms_s *) cbarg; + bfa_fcs_lport_t *port = ms->port; + struct ct_hdr_s *cthdr = NULL; + wwn_t *gfn_resp; + + bfa_trc(port->fcs, req_status); + bfa_trc(port->fcs, port->port_cfg.pwwn); + + /* + * Sanity Checks + */ + if (req_status != BFA_STATUS_OK) { + bfa_trc(port->fcs, req_status); + bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR); + return; + } + + cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp); + cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code); + + if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) { + gfn_resp = (wwn_t *)(cthdr + 1); + /* check if it has actually changed */ + if ((memcmp((void *)&bfa_fcs_lport_get_fabric_name(port), + gfn_resp, sizeof(wwn_t)) != 0)) { + bfa_fcs_fabric_set_fabric_name(port->fabric, *gfn_resp); + } + bfa_sm_send_event(ms, MSSM_EVENT_RSP_OK); + return; + } + + bfa_trc(port->fcs, cthdr->reason_code); + bfa_trc(port->fcs, cthdr->exp_code); + bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR); +} + +/** + * ms_pvt MS local functions + */ + +static void +bfa_fcs_lport_ms_send_plogi(void *ms_cbarg, struct bfa_fcxp_s *fcxp_alloced) +{ + struct bfa_fcs_lport_ms_s *ms = ms_cbarg; + struct bfa_fcs_lport_s *port = ms->port; + struct fchs_s fchs; + int len; + struct bfa_fcxp_s *fcxp; + + bfa_trc(port->fcs, port->pid); + + fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); + if (!fcxp) { + port->stats.ms_plogi_alloc_wait++; + bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &ms->fcxp_wqe, + bfa_fcs_lport_ms_send_plogi, ms); + return; + } + ms->fcxp = fcxp; + + len = fc_plogi_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), + bfa_os_hton3b(FC_MGMT_SERVER), + bfa_fcs_lport_get_fcid(port), 0, + port->port_cfg.pwwn, port->port_cfg.nwwn, + bfa_fcport_get_maxfrsize(port->fcs->bfa)); + + bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, + FC_CLASS_3, len, &fchs, + bfa_fcs_lport_ms_plogi_response, (void *)ms, + FC_MAX_PDUSZ, FC_ELS_TOV); + + port->stats.ms_plogi_sent++; + bfa_sm_send_event(ms, MSSM_EVENT_FCXP_SENT); +} + +static void +bfa_fcs_lport_ms_plogi_response(void *fcsarg, struct bfa_fcxp_s *fcxp, + void *cbarg, bfa_status_t req_status, + u32 rsp_len, u32 resid_len, struct fchs_s *rsp_fchs) +{ + struct bfa_fcs_lport_ms_s *ms = (struct bfa_fcs_lport_ms_s *) cbarg; + struct bfa_fcs_lport_s *port = ms->port; + struct fc_els_cmd_s *els_cmd; + struct fc_ls_rjt_s *ls_rjt; + + bfa_trc(port->fcs, req_status); + bfa_trc(port->fcs, port->port_cfg.pwwn); + + /* + * Sanity Checks + */ + if (req_status != BFA_STATUS_OK) { + port->stats.ms_plogi_rsp_err++; + bfa_trc(port->fcs, req_status); + bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR); + return; + } + + els_cmd = (struct fc_els_cmd_s *) BFA_FCXP_RSP_PLD(fcxp); + + switch (els_cmd->els_code) { + + case FC_ELS_ACC: + if (rsp_len < sizeof(struct fc_logi_s)) { + bfa_trc(port->fcs, rsp_len); + port->stats.ms_plogi_acc_err++; + bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR); + break; + } + port->stats.ms_plogi_accepts++; + bfa_sm_send_event(ms, MSSM_EVENT_RSP_OK); + break; + + case FC_ELS_LS_RJT: + ls_rjt = (struct fc_ls_rjt_s *) BFA_FCXP_RSP_PLD(fcxp); + + bfa_trc(port->fcs, ls_rjt->reason_code); + bfa_trc(port->fcs, ls_rjt->reason_code_expl); + + port->stats.ms_rejects++; + bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR); + break; + + default: + port->stats.ms_plogi_unknown_rsp++; + bfa_trc(port->fcs, els_cmd->els_code); + bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR); + } +} + +static void +bfa_fcs_lport_ms_timeout(void *arg) +{ + struct bfa_fcs_lport_ms_s *ms = (struct bfa_fcs_lport_ms_s *) arg; + + ms->port->stats.ms_timeouts++; + bfa_sm_send_event(ms, MSSM_EVENT_TIMEOUT); +} + + +void +bfa_fcs_lport_ms_init(struct bfa_fcs_lport_s *port) +{ + struct bfa_fcs_lport_ms_s *ms = BFA_FCS_GET_MS_FROM_PORT(port); + + ms->port = port; + bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_offline); + + /* + * Invoke init routines of sub modules. + */ + bfa_fcs_lport_fdmi_init(ms); +} + +void +bfa_fcs_lport_ms_offline(struct bfa_fcs_lport_s *port) +{ + struct bfa_fcs_lport_ms_s *ms = BFA_FCS_GET_MS_FROM_PORT(port); + + ms->port = port; + bfa_sm_send_event(ms, MSSM_EVENT_PORT_OFFLINE); + bfa_fcs_lport_fdmi_offline(ms); +} + +void +bfa_fcs_lport_ms_online(struct bfa_fcs_lport_s *port) +{ + struct bfa_fcs_lport_ms_s *ms = BFA_FCS_GET_MS_FROM_PORT(port); + + ms->port = port; + bfa_sm_send_event(ms, MSSM_EVENT_PORT_ONLINE); +} +void +bfa_fcs_lport_ms_fabric_rscn(struct bfa_fcs_lport_s *port) +{ + struct bfa_fcs_lport_ms_s *ms = BFA_FCS_GET_MS_FROM_PORT(port); + + /* todo. Handle this only when in Online state */ + if (bfa_sm_cmp_state(ms, bfa_fcs_lport_ms_sm_online)) + bfa_sm_send_event(ms, MSSM_EVENT_PORT_FABRIC_RSCN); +} + +/** + * @page ns_sm_info VPORT NS State Machine + * + * @section ns_sm_interactions VPORT NS State Machine Interactions + * + * @section ns_sm VPORT NS State Machine + * img ns_sm.jpg + */ + +/* + * forward declarations + */ +static void bfa_fcs_lport_ns_send_plogi(void *ns_cbarg, + struct bfa_fcxp_s *fcxp_alloced); +static void bfa_fcs_lport_ns_send_rspn_id(void *ns_cbarg, + struct bfa_fcxp_s *fcxp_alloced); +static void bfa_fcs_lport_ns_send_rft_id(void *ns_cbarg, + struct bfa_fcxp_s *fcxp_alloced); +static void bfa_fcs_lport_ns_send_rff_id(void *ns_cbarg, + struct bfa_fcxp_s *fcxp_alloced); +static void bfa_fcs_lport_ns_send_gid_ft(void *ns_cbarg, + struct bfa_fcxp_s *fcxp_alloced); +static void bfa_fcs_lport_ns_timeout(void *arg); +static void bfa_fcs_lport_ns_plogi_response(void *fcsarg, + struct bfa_fcxp_s *fcxp, + void *cbarg, + bfa_status_t req_status, + u32 rsp_len, + u32 resid_len, + struct fchs_s *rsp_fchs); +static void bfa_fcs_lport_ns_rspn_id_response(void *fcsarg, + struct bfa_fcxp_s *fcxp, + void *cbarg, + bfa_status_t req_status, + u32 rsp_len, + u32 resid_len, + struct fchs_s *rsp_fchs); +static void bfa_fcs_lport_ns_rft_id_response(void *fcsarg, + struct bfa_fcxp_s *fcxp, + void *cbarg, + bfa_status_t req_status, + u32 rsp_len, + u32 resid_len, + struct fchs_s *rsp_fchs); +static void bfa_fcs_lport_ns_rff_id_response(void *fcsarg, + struct bfa_fcxp_s *fcxp, + void *cbarg, + bfa_status_t req_status, + u32 rsp_len, + u32 resid_len, + struct fchs_s *rsp_fchs); +static void bfa_fcs_lport_ns_gid_ft_response(void *fcsarg, + struct bfa_fcxp_s *fcxp, + void *cbarg, + bfa_status_t req_status, + u32 rsp_len, + u32 resid_len, + struct fchs_s *rsp_fchs); +static void bfa_fcs_lport_ns_process_gidft_pids( + struct bfa_fcs_lport_s *port, + u32 *pid_buf, u32 n_pids); + +static void bfa_fcs_lport_ns_boot_target_disc(bfa_fcs_lport_t *port); +/** + * fcs_ns_sm FCS nameserver interface state machine + */ + +/** + * VPort NS State Machine events + */ +enum vport_ns_event { + NSSM_EVENT_PORT_ONLINE = 1, + NSSM_EVENT_PORT_OFFLINE = 2, + NSSM_EVENT_PLOGI_SENT = 3, + NSSM_EVENT_RSP_OK = 4, + NSSM_EVENT_RSP_ERROR = 5, + NSSM_EVENT_TIMEOUT = 6, + NSSM_EVENT_NS_QUERY = 7, + NSSM_EVENT_RSPNID_SENT = 8, + NSSM_EVENT_RFTID_SENT = 9, + NSSM_EVENT_RFFID_SENT = 10, + NSSM_EVENT_GIDFT_SENT = 11, +}; + +static void bfa_fcs_lport_ns_sm_offline(struct bfa_fcs_lport_ns_s *ns, + enum vport_ns_event event); +static void bfa_fcs_lport_ns_sm_plogi_sending(struct bfa_fcs_lport_ns_s *ns, + enum vport_ns_event event); +static void bfa_fcs_lport_ns_sm_plogi(struct bfa_fcs_lport_ns_s *ns, + enum vport_ns_event event); +static void bfa_fcs_lport_ns_sm_plogi_retry(struct bfa_fcs_lport_ns_s *ns, + enum vport_ns_event event); +static void bfa_fcs_lport_ns_sm_sending_rspn_id( + struct bfa_fcs_lport_ns_s *ns, + enum vport_ns_event event); +static void bfa_fcs_lport_ns_sm_rspn_id(struct bfa_fcs_lport_ns_s *ns, + enum vport_ns_event event); +static void bfa_fcs_lport_ns_sm_rspn_id_retry(struct bfa_fcs_lport_ns_s *ns, + enum vport_ns_event event); +static void bfa_fcs_lport_ns_sm_sending_rft_id( + struct bfa_fcs_lport_ns_s *ns, + enum vport_ns_event event); +static void bfa_fcs_lport_ns_sm_rft_id_retry(struct bfa_fcs_lport_ns_s *ns, + enum vport_ns_event event); +static void bfa_fcs_lport_ns_sm_rft_id(struct bfa_fcs_lport_ns_s *ns, + enum vport_ns_event event); +static void bfa_fcs_lport_ns_sm_sending_rff_id( + struct bfa_fcs_lport_ns_s *ns, + enum vport_ns_event event); +static void bfa_fcs_lport_ns_sm_rff_id_retry(struct bfa_fcs_lport_ns_s *ns, + enum vport_ns_event event); +static void bfa_fcs_lport_ns_sm_rff_id(struct bfa_fcs_lport_ns_s *ns, + enum vport_ns_event event); +static void bfa_fcs_lport_ns_sm_sending_gid_ft( + struct bfa_fcs_lport_ns_s *ns, + enum vport_ns_event event); +static void bfa_fcs_lport_ns_sm_gid_ft(struct bfa_fcs_lport_ns_s *ns, + enum vport_ns_event event); +static void bfa_fcs_lport_ns_sm_gid_ft_retry(struct bfa_fcs_lport_ns_s *ns, + enum vport_ns_event event); +static void bfa_fcs_lport_ns_sm_online(struct bfa_fcs_lport_ns_s *ns, + enum vport_ns_event event); +/** + * Start in offline state - awaiting linkup + */ +static void +bfa_fcs_lport_ns_sm_offline(struct bfa_fcs_lport_ns_s *ns, + enum vport_ns_event event) +{ + bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); + bfa_trc(ns->port->fcs, event); + + switch (event) { + case NSSM_EVENT_PORT_ONLINE: + bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_plogi_sending); + bfa_fcs_lport_ns_send_plogi(ns, NULL); + break; + + case NSSM_EVENT_PORT_OFFLINE: + break; + + default: + bfa_sm_fault(ns->port->fcs, event); + } +} + +static void +bfa_fcs_lport_ns_sm_plogi_sending(struct bfa_fcs_lport_ns_s *ns, + enum vport_ns_event event) +{ + bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); + bfa_trc(ns->port->fcs, event); + + switch (event) { + case NSSM_EVENT_PLOGI_SENT: + bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_plogi); + break; + + case NSSM_EVENT_PORT_OFFLINE: + bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_offline); + bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ns->port), + &ns->fcxp_wqe); + break; + + default: + bfa_sm_fault(ns->port->fcs, event); + } +} + +static void +bfa_fcs_lport_ns_sm_plogi(struct bfa_fcs_lport_ns_s *ns, + enum vport_ns_event event) +{ + bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); + bfa_trc(ns->port->fcs, event); + + switch (event) { + case NSSM_EVENT_RSP_ERROR: + /* + * Start timer for a delayed retry + */ + bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_plogi_retry); + ns->port->stats.ns_retries++; + bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ns->port), + &ns->timer, bfa_fcs_lport_ns_timeout, ns, + BFA_FCS_RETRY_TIMEOUT); + break; + + case NSSM_EVENT_RSP_OK: + bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_sending_rspn_id); + bfa_fcs_lport_ns_send_rspn_id(ns, NULL); + break; + + case NSSM_EVENT_PORT_OFFLINE: + bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_offline); + bfa_fcxp_discard(ns->fcxp); + break; + + default: + bfa_sm_fault(ns->port->fcs, event); + } +} + +static void +bfa_fcs_lport_ns_sm_plogi_retry(struct bfa_fcs_lport_ns_s *ns, + enum vport_ns_event event) +{ + bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); + bfa_trc(ns->port->fcs, event); + + switch (event) { + case NSSM_EVENT_TIMEOUT: + /* + * Retry Timer Expired. Re-send + */ + bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_plogi_sending); + bfa_fcs_lport_ns_send_plogi(ns, NULL); + break; + + case NSSM_EVENT_PORT_OFFLINE: + bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_offline); + bfa_timer_stop(&ns->timer); + break; + + default: + bfa_sm_fault(ns->port->fcs, event); + } +} + +static void +bfa_fcs_lport_ns_sm_sending_rspn_id(struct bfa_fcs_lport_ns_s *ns, + enum vport_ns_event event) +{ + bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); + bfa_trc(ns->port->fcs, event); + + switch (event) { + case NSSM_EVENT_RSPNID_SENT: + bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_rspn_id); + break; + + case NSSM_EVENT_PORT_OFFLINE: + bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_offline); + bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ns->port), + &ns->fcxp_wqe); + break; + + default: + bfa_sm_fault(ns->port->fcs, event); + } +} + +static void +bfa_fcs_lport_ns_sm_rspn_id(struct bfa_fcs_lport_ns_s *ns, + enum vport_ns_event event) +{ + bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); + bfa_trc(ns->port->fcs, event); + + switch (event) { + case NSSM_EVENT_RSP_ERROR: + /* + * Start timer for a delayed retry + */ + bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_rspn_id_retry); + ns->port->stats.ns_retries++; + bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ns->port), + &ns->timer, bfa_fcs_lport_ns_timeout, ns, + BFA_FCS_RETRY_TIMEOUT); + break; + + case NSSM_EVENT_RSP_OK: + bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_sending_rft_id); + bfa_fcs_lport_ns_send_rft_id(ns, NULL); + break; + + case NSSM_EVENT_PORT_OFFLINE: + bfa_fcxp_discard(ns->fcxp); + bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_offline); + break; + + default: + bfa_sm_fault(ns->port->fcs, event); + } +} + +static void +bfa_fcs_lport_ns_sm_rspn_id_retry(struct bfa_fcs_lport_ns_s *ns, + enum vport_ns_event event) +{ + bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); + bfa_trc(ns->port->fcs, event); + + switch (event) { + case NSSM_EVENT_TIMEOUT: + /* + * Retry Timer Expired. Re-send + */ + bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_sending_rspn_id); + bfa_fcs_lport_ns_send_rspn_id(ns, NULL); + break; + + case NSSM_EVENT_PORT_OFFLINE: + bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_offline); + bfa_timer_stop(&ns->timer); + break; + + default: + bfa_sm_fault(ns->port->fcs, event); + } +} + +static void +bfa_fcs_lport_ns_sm_sending_rft_id(struct bfa_fcs_lport_ns_s *ns, + enum vport_ns_event event) +{ + bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); + bfa_trc(ns->port->fcs, event); + + switch (event) { + case NSSM_EVENT_RFTID_SENT: + bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_rft_id); + break; + + case NSSM_EVENT_PORT_OFFLINE: + bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_offline); + bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ns->port), + &ns->fcxp_wqe); + break; + + default: + bfa_sm_fault(ns->port->fcs, event); + } +} + +static void +bfa_fcs_lport_ns_sm_rft_id(struct bfa_fcs_lport_ns_s *ns, + enum vport_ns_event event) +{ + bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); + bfa_trc(ns->port->fcs, event); + + switch (event) { + case NSSM_EVENT_RSP_OK: + /* Now move to register FC4 Features */ + bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_sending_rff_id); + bfa_fcs_lport_ns_send_rff_id(ns, NULL); + break; + + case NSSM_EVENT_RSP_ERROR: + /* + * Start timer for a delayed retry + */ + bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_rft_id_retry); + ns->port->stats.ns_retries++; + bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ns->port), + &ns->timer, bfa_fcs_lport_ns_timeout, ns, + BFA_FCS_RETRY_TIMEOUT); + break; + + case NSSM_EVENT_PORT_OFFLINE: + bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_offline); + bfa_fcxp_discard(ns->fcxp); + break; + + default: + bfa_sm_fault(ns->port->fcs, event); + } +} + +static void +bfa_fcs_lport_ns_sm_rft_id_retry(struct bfa_fcs_lport_ns_s *ns, + enum vport_ns_event event) +{ + bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); + bfa_trc(ns->port->fcs, event); + + switch (event) { + case NSSM_EVENT_TIMEOUT: + bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_sending_rft_id); + bfa_fcs_lport_ns_send_rft_id(ns, NULL); + break; + + case NSSM_EVENT_PORT_OFFLINE: + bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_offline); + bfa_timer_stop(&ns->timer); + break; + + default: + bfa_sm_fault(ns->port->fcs, event); + } +} + +static void +bfa_fcs_lport_ns_sm_sending_rff_id(struct bfa_fcs_lport_ns_s *ns, + enum vport_ns_event event) +{ + bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); + bfa_trc(ns->port->fcs, event); + + switch (event) { + case NSSM_EVENT_RFFID_SENT: + bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_rff_id); + break; + + case NSSM_EVENT_PORT_OFFLINE: + bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_offline); + bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ns->port), + &ns->fcxp_wqe); + break; + + default: + bfa_sm_fault(ns->port->fcs, event); + } +} + +static void +bfa_fcs_lport_ns_sm_rff_id(struct bfa_fcs_lport_ns_s *ns, + enum vport_ns_event event) +{ + bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); + bfa_trc(ns->port->fcs, event); + + switch (event) { + case NSSM_EVENT_RSP_OK: + + /* + * If min cfg mode is enabled, we donot initiate rport + * discovery with the fabric. Instead, we will retrieve the + * boot targets from HAL/FW. + */ + if (__fcs_min_cfg(ns->port->fcs)) { + bfa_fcs_lport_ns_boot_target_disc(ns->port); + bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_online); + return; + } + + /* + * If the port role is Initiator Mode issue NS query. + * If it is Target Mode, skip this and go to online. + */ + if (BFA_FCS_VPORT_IS_INITIATOR_MODE(ns->port)) { + bfa_sm_set_state(ns, + bfa_fcs_lport_ns_sm_sending_gid_ft); + bfa_fcs_lport_ns_send_gid_ft(ns, NULL); + } + /* + * kick off mgmt srvr state machine + */ + bfa_fcs_lport_ms_online(ns->port); + break; + + case NSSM_EVENT_RSP_ERROR: + /* + * Start timer for a delayed retry + */ + bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_rff_id_retry); + ns->port->stats.ns_retries++; + bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ns->port), + &ns->timer, bfa_fcs_lport_ns_timeout, ns, + BFA_FCS_RETRY_TIMEOUT); + break; + + case NSSM_EVENT_PORT_OFFLINE: + bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_offline); + bfa_fcxp_discard(ns->fcxp); + break; + + default: + bfa_sm_fault(ns->port->fcs, event); + } +} + +static void +bfa_fcs_lport_ns_sm_rff_id_retry(struct bfa_fcs_lport_ns_s *ns, + enum vport_ns_event event) +{ + bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); + bfa_trc(ns->port->fcs, event); + + switch (event) { + case NSSM_EVENT_TIMEOUT: + bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_sending_rff_id); + bfa_fcs_lport_ns_send_rff_id(ns, NULL); + break; + + case NSSM_EVENT_PORT_OFFLINE: + bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_offline); + bfa_timer_stop(&ns->timer); + break; + + default: + bfa_sm_fault(ns->port->fcs, event); + } +} +static void +bfa_fcs_lport_ns_sm_sending_gid_ft(struct bfa_fcs_lport_ns_s *ns, + enum vport_ns_event event) +{ + bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); + bfa_trc(ns->port->fcs, event); + + switch (event) { + case NSSM_EVENT_GIDFT_SENT: + bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_gid_ft); + break; + + case NSSM_EVENT_PORT_OFFLINE: + bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_offline); + bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ns->port), + &ns->fcxp_wqe); + break; + + default: + bfa_sm_fault(ns->port->fcs, event); + } +} + +static void +bfa_fcs_lport_ns_sm_gid_ft(struct bfa_fcs_lport_ns_s *ns, + enum vport_ns_event event) +{ + bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); + bfa_trc(ns->port->fcs, event); + + switch (event) { + case NSSM_EVENT_RSP_OK: + bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_online); + break; + + case NSSM_EVENT_RSP_ERROR: + /* + * TBD: for certain reject codes, we don't need to retry + */ + /* + * Start timer for a delayed retry + */ + bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_gid_ft_retry); + ns->port->stats.ns_retries++; + bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ns->port), + &ns->timer, bfa_fcs_lport_ns_timeout, ns, + BFA_FCS_RETRY_TIMEOUT); + break; + + case NSSM_EVENT_PORT_OFFLINE: + bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_offline); + bfa_fcxp_discard(ns->fcxp); + break; + + case NSSM_EVENT_NS_QUERY: + break; + + default: + bfa_sm_fault(ns->port->fcs, event); + } +} + +static void +bfa_fcs_lport_ns_sm_gid_ft_retry(struct bfa_fcs_lport_ns_s *ns, + enum vport_ns_event event) +{ + bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); + bfa_trc(ns->port->fcs, event); + + switch (event) { + case NSSM_EVENT_TIMEOUT: + bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_sending_gid_ft); + bfa_fcs_lport_ns_send_gid_ft(ns, NULL); + break; + + case NSSM_EVENT_PORT_OFFLINE: + bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_offline); + bfa_timer_stop(&ns->timer); + break; + + default: + bfa_sm_fault(ns->port->fcs, event); + } +} + +static void +bfa_fcs_lport_ns_sm_online(struct bfa_fcs_lport_ns_s *ns, + enum vport_ns_event event) +{ + bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); + bfa_trc(ns->port->fcs, event); + + switch (event) { + case NSSM_EVENT_PORT_OFFLINE: + bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_offline); + break; + + case NSSM_EVENT_NS_QUERY: + /* + * If the port role is Initiator Mode issue NS query. + * If it is Target Mode, skip this and go to online. + */ + if (BFA_FCS_VPORT_IS_INITIATOR_MODE(ns->port)) { + bfa_sm_set_state(ns, + bfa_fcs_lport_ns_sm_sending_gid_ft); + bfa_fcs_lport_ns_send_gid_ft(ns, NULL); + }; + break; + + default: + bfa_sm_fault(ns->port->fcs, event); + } +} + + + +/** + * ns_pvt Nameserver local functions + */ + +static void +bfa_fcs_lport_ns_send_plogi(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced) +{ + struct bfa_fcs_lport_ns_s *ns = ns_cbarg; + struct bfa_fcs_lport_s *port = ns->port; + struct fchs_s fchs; + int len; + struct bfa_fcxp_s *fcxp; + + bfa_trc(port->fcs, port->pid); + +fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); + if (!fcxp) { + port->stats.ns_plogi_alloc_wait++; + bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &ns->fcxp_wqe, + bfa_fcs_lport_ns_send_plogi, ns); + return; + } + ns->fcxp = fcxp; + + len = fc_plogi_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), + bfa_os_hton3b(FC_NAME_SERVER), + bfa_fcs_lport_get_fcid(port), 0, + port->port_cfg.pwwn, port->port_cfg.nwwn, + bfa_fcport_get_maxfrsize(port->fcs->bfa)); + + bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, + FC_CLASS_3, len, &fchs, + bfa_fcs_lport_ns_plogi_response, (void *)ns, + FC_MAX_PDUSZ, FC_ELS_TOV); + port->stats.ns_plogi_sent++; + + bfa_sm_send_event(ns, NSSM_EVENT_PLOGI_SENT); +} + +static void +bfa_fcs_lport_ns_plogi_response(void *fcsarg, struct bfa_fcxp_s *fcxp, + void *cbarg, bfa_status_t req_status, u32 rsp_len, + u32 resid_len, struct fchs_s *rsp_fchs) +{ + struct bfa_fcs_lport_ns_s *ns = (struct bfa_fcs_lport_ns_s *) cbarg; + struct bfa_fcs_lport_s *port = ns->port; + /* struct fc_logi_s *plogi_resp; */ + struct fc_els_cmd_s *els_cmd; + struct fc_ls_rjt_s *ls_rjt; + + bfa_trc(port->fcs, req_status); + bfa_trc(port->fcs, port->port_cfg.pwwn); + + /* + * Sanity Checks + */ + if (req_status != BFA_STATUS_OK) { + bfa_trc(port->fcs, req_status); + port->stats.ns_plogi_rsp_err++; + bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); + return; + } + + els_cmd = (struct fc_els_cmd_s *) BFA_FCXP_RSP_PLD(fcxp); + + switch (els_cmd->els_code) { + + case FC_ELS_ACC: + if (rsp_len < sizeof(struct fc_logi_s)) { + bfa_trc(port->fcs, rsp_len); + port->stats.ns_plogi_acc_err++; + bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); + break; + } + port->stats.ns_plogi_accepts++; + bfa_sm_send_event(ns, NSSM_EVENT_RSP_OK); + break; + + case FC_ELS_LS_RJT: + ls_rjt = (struct fc_ls_rjt_s *) BFA_FCXP_RSP_PLD(fcxp); + + bfa_trc(port->fcs, ls_rjt->reason_code); + bfa_trc(port->fcs, ls_rjt->reason_code_expl); + + port->stats.ns_rejects++; + + bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); + break; + + default: + port->stats.ns_plogi_unknown_rsp++; + bfa_trc(port->fcs, els_cmd->els_code); + bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); + } +} + +/** + * Register the symbolic port name. + */ +static void +bfa_fcs_lport_ns_send_rspn_id(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced) +{ + struct bfa_fcs_lport_ns_s *ns = ns_cbarg; + struct bfa_fcs_lport_s *port = ns->port; + struct fchs_s fchs; + int len; + struct bfa_fcxp_s *fcxp; + u8 symbl[256]; + u8 *psymbl = &symbl[0]; + + bfa_os_memset(symbl, 0, sizeof(symbl)); + + bfa_trc(port->fcs, port->port_cfg.pwwn); + + fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); + if (!fcxp) { + port->stats.ns_rspnid_alloc_wait++; + bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &ns->fcxp_wqe, + bfa_fcs_lport_ns_send_rspn_id, ns); + return; + } + ns->fcxp = fcxp; + + /* + * for V-Port, form a Port Symbolic Name + */ + if (port->vport) { + /** + * For Vports, we append the vport's port symbolic name + * to that of the base port. + */ + + strncpy((char *)psymbl, + (char *) & + (bfa_fcs_lport_get_psym_name + (bfa_fcs_get_base_port(port->fcs))), + strlen((char *) & + bfa_fcs_lport_get_psym_name(bfa_fcs_get_base_port + (port->fcs)))); + + /* Ensure we have a null terminating string. */ + ((char *)psymbl)[strlen((char *) & + bfa_fcs_lport_get_psym_name(bfa_fcs_get_base_port + (port->fcs)))] = 0; + strncat((char *)psymbl, + (char *) &(bfa_fcs_lport_get_psym_name(port)), + strlen((char *) &bfa_fcs_lport_get_psym_name(port))); + } else { + psymbl = (u8 *) &(bfa_fcs_lport_get_psym_name(port)); + } + + len = fc_rspnid_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), + bfa_fcs_lport_get_fcid(port), 0, psymbl); + + bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, + FC_CLASS_3, len, &fchs, + bfa_fcs_lport_ns_rspn_id_response, (void *)ns, + FC_MAX_PDUSZ, FC_FCCT_TOV); + + port->stats.ns_rspnid_sent++; + + bfa_sm_send_event(ns, NSSM_EVENT_RSPNID_SENT); +} + +static void +bfa_fcs_lport_ns_rspn_id_response(void *fcsarg, struct bfa_fcxp_s *fcxp, + void *cbarg, bfa_status_t req_status, + u32 rsp_len, u32 resid_len, + struct fchs_s *rsp_fchs) +{ + struct bfa_fcs_lport_ns_s *ns = (struct bfa_fcs_lport_ns_s *) cbarg; + struct bfa_fcs_lport_s *port = ns->port; + struct ct_hdr_s *cthdr = NULL; + + bfa_trc(port->fcs, port->port_cfg.pwwn); + + /* + * Sanity Checks + */ + if (req_status != BFA_STATUS_OK) { + bfa_trc(port->fcs, req_status); + port->stats.ns_rspnid_rsp_err++; + bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); + return; + } + + cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp); + cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code); + + if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) { + port->stats.ns_rspnid_accepts++; + bfa_sm_send_event(ns, NSSM_EVENT_RSP_OK); + return; + } + + port->stats.ns_rspnid_rejects++; + bfa_trc(port->fcs, cthdr->reason_code); + bfa_trc(port->fcs, cthdr->exp_code); + bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); +} + +/** + * Register FC4-Types + */ +static void +bfa_fcs_lport_ns_send_rft_id(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced) +{ + struct bfa_fcs_lport_ns_s *ns = ns_cbarg; + struct bfa_fcs_lport_s *port = ns->port; + struct fchs_s fchs; + int len; + struct bfa_fcxp_s *fcxp; + + bfa_trc(port->fcs, port->port_cfg.pwwn); + + fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); + if (!fcxp) { + port->stats.ns_rftid_alloc_wait++; + bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &ns->fcxp_wqe, + bfa_fcs_lport_ns_send_rft_id, ns); + return; + } + ns->fcxp = fcxp; + + len = fc_rftid_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), + bfa_fcs_lport_get_fcid(port), 0, port->port_cfg.roles); + + bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, + FC_CLASS_3, len, &fchs, + bfa_fcs_lport_ns_rft_id_response, (void *)ns, + FC_MAX_PDUSZ, FC_FCCT_TOV); + + port->stats.ns_rftid_sent++; + bfa_sm_send_event(ns, NSSM_EVENT_RFTID_SENT); +} + +static void +bfa_fcs_lport_ns_rft_id_response(void *fcsarg, struct bfa_fcxp_s *fcxp, + void *cbarg, bfa_status_t req_status, + u32 rsp_len, u32 resid_len, + struct fchs_s *rsp_fchs) +{ + struct bfa_fcs_lport_ns_s *ns = (struct bfa_fcs_lport_ns_s *) cbarg; + struct bfa_fcs_lport_s *port = ns->port; + struct ct_hdr_s *cthdr = NULL; + + bfa_trc(port->fcs, port->port_cfg.pwwn); + + /* + * Sanity Checks + */ + if (req_status != BFA_STATUS_OK) { + bfa_trc(port->fcs, req_status); + port->stats.ns_rftid_rsp_err++; + bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); + return; + } + + cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp); + cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code); + + if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) { + port->stats.ns_rftid_accepts++; + bfa_sm_send_event(ns, NSSM_EVENT_RSP_OK); + return; + } + + port->stats.ns_rftid_rejects++; + bfa_trc(port->fcs, cthdr->reason_code); + bfa_trc(port->fcs, cthdr->exp_code); + bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); +} + +/** + * Register FC4-Features : Should be done after RFT_ID + */ +static void +bfa_fcs_lport_ns_send_rff_id(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced) +{ + struct bfa_fcs_lport_ns_s *ns = ns_cbarg; + struct bfa_fcs_lport_s *port = ns->port; + struct fchs_s fchs; + int len; + struct bfa_fcxp_s *fcxp; + u8 fc4_ftrs = 0; + + bfa_trc(port->fcs, port->port_cfg.pwwn); + + fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); + if (!fcxp) { + port->stats.ns_rffid_alloc_wait++; + bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &ns->fcxp_wqe, + bfa_fcs_lport_ns_send_rff_id, ns); + return; + } + ns->fcxp = fcxp; + + if (BFA_FCS_VPORT_IS_INITIATOR_MODE(ns->port)) + fc4_ftrs = FC_GS_FCP_FC4_FEATURE_INITIATOR; + + len = fc_rffid_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), + bfa_fcs_lport_get_fcid(port), 0, + FC_TYPE_FCP, fc4_ftrs); + + bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, + FC_CLASS_3, len, &fchs, + bfa_fcs_lport_ns_rff_id_response, (void *)ns, + FC_MAX_PDUSZ, FC_FCCT_TOV); + + port->stats.ns_rffid_sent++; + bfa_sm_send_event(ns, NSSM_EVENT_RFFID_SENT); +} + +static void +bfa_fcs_lport_ns_rff_id_response(void *fcsarg, struct bfa_fcxp_s *fcxp, + void *cbarg, bfa_status_t req_status, + u32 rsp_len, u32 resid_len, + struct fchs_s *rsp_fchs) +{ + struct bfa_fcs_lport_ns_s *ns = (struct bfa_fcs_lport_ns_s *) cbarg; + struct bfa_fcs_lport_s *port = ns->port; + struct ct_hdr_s *cthdr = NULL; + + bfa_trc(port->fcs, port->port_cfg.pwwn); + + /* + * Sanity Checks + */ + if (req_status != BFA_STATUS_OK) { + bfa_trc(port->fcs, req_status); + port->stats.ns_rffid_rsp_err++; + bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); + return; + } + + cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp); + cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code); + + if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) { + port->stats.ns_rffid_accepts++; + bfa_sm_send_event(ns, NSSM_EVENT_RSP_OK); + return; + } + + port->stats.ns_rffid_rejects++; + bfa_trc(port->fcs, cthdr->reason_code); + bfa_trc(port->fcs, cthdr->exp_code); + + if (cthdr->reason_code == CT_RSN_NOT_SUPP) { + /* if this command is not supported, we don't retry */ + bfa_sm_send_event(ns, NSSM_EVENT_RSP_OK); + } else + bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); +} +/** + * Query Fabric for FC4-Types Devices. + * +* TBD : Need to use a local (FCS private) response buffer, since the response + * can be larger than 2K. + */ +static void +bfa_fcs_lport_ns_send_gid_ft(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced) +{ + struct bfa_fcs_lport_ns_s *ns = ns_cbarg; + struct bfa_fcs_lport_s *port = ns->port; + struct fchs_s fchs; + int len; + struct bfa_fcxp_s *fcxp; + + bfa_trc(port->fcs, port->pid); + + fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); + if (!fcxp) { + port->stats.ns_gidft_alloc_wait++; + bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &ns->fcxp_wqe, + bfa_fcs_lport_ns_send_gid_ft, ns); + return; + } + ns->fcxp = fcxp; + + /* + * This query is only initiated for FCP initiator mode. + */ + len = fc_gid_ft_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), + ns->port->pid, FC_TYPE_FCP); + + bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, + FC_CLASS_3, len, &fchs, + bfa_fcs_lport_ns_gid_ft_response, (void *)ns, + bfa_fcxp_get_maxrsp(port->fcs->bfa), FC_FCCT_TOV); + + port->stats.ns_gidft_sent++; + + bfa_sm_send_event(ns, NSSM_EVENT_GIDFT_SENT); +} + +static void +bfa_fcs_lport_ns_gid_ft_response(void *fcsarg, struct bfa_fcxp_s *fcxp, + void *cbarg, bfa_status_t req_status, + u32 rsp_len, u32 resid_len, + struct fchs_s *rsp_fchs) +{ + struct bfa_fcs_lport_ns_s *ns = (struct bfa_fcs_lport_ns_s *) cbarg; + struct bfa_fcs_lport_s *port = ns->port; + struct ct_hdr_s *cthdr = NULL; + u32 n_pids; + + bfa_trc(port->fcs, port->port_cfg.pwwn); + + /* + * Sanity Checks + */ + if (req_status != BFA_STATUS_OK) { + bfa_trc(port->fcs, req_status); + port->stats.ns_gidft_rsp_err++; + bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); + return; + } + + if (resid_len != 0) { + /* + * TBD : we will need to allocate a larger buffer & retry the + * command + */ + bfa_trc(port->fcs, rsp_len); + bfa_trc(port->fcs, resid_len); + return; + } + + cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp); + cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code); + + switch (cthdr->cmd_rsp_code) { + + case CT_RSP_ACCEPT: + + port->stats.ns_gidft_accepts++; + n_pids = (fc_get_ctresp_pyld_len(rsp_len) / sizeof(u32)); + bfa_trc(port->fcs, n_pids); + bfa_fcs_lport_ns_process_gidft_pids(port, + (u32 *) (cthdr + 1), + n_pids); + bfa_sm_send_event(ns, NSSM_EVENT_RSP_OK); + break; + + case CT_RSP_REJECT: + + /* + * Check the reason code & explanation. + * There may not have been any FC4 devices in the fabric + */ + port->stats.ns_gidft_rejects++; + bfa_trc(port->fcs, cthdr->reason_code); + bfa_trc(port->fcs, cthdr->exp_code); + + if ((cthdr->reason_code == CT_RSN_UNABLE_TO_PERF) + && (cthdr->exp_code == CT_NS_EXP_FT_NOT_REG)) { + + bfa_sm_send_event(ns, NSSM_EVENT_RSP_OK); + } else { + /* + * for all other errors, retry + */ + bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); + } + break; + + default: + port->stats.ns_gidft_unknown_rsp++; + bfa_trc(port->fcs, cthdr->cmd_rsp_code); + bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); + } +} + +/** + * This routine will be called by bfa_timer on timer timeouts. + * + * param[in] port - pointer to bfa_fcs_lport_t. + * + * return + * void + * + * Special Considerations: + * + * note + */ +static void +bfa_fcs_lport_ns_timeout(void *arg) +{ + struct bfa_fcs_lport_ns_s *ns = (struct bfa_fcs_lport_ns_s *) arg; + + ns->port->stats.ns_timeouts++; + bfa_sm_send_event(ns, NSSM_EVENT_TIMEOUT); +} + +/* + * Process the PID list in GID_FT response + */ +static void +bfa_fcs_lport_ns_process_gidft_pids(struct bfa_fcs_lport_s *port, u32 *pid_buf, + u32 n_pids) +{ + struct fcgs_gidft_resp_s *gidft_entry; + struct bfa_fcs_rport_s *rport; + u32 ii; + + for (ii = 0; ii < n_pids; ii++) { + gidft_entry = (struct fcgs_gidft_resp_s *) &pid_buf[ii]; + + if (gidft_entry->pid == port->pid) + continue; + + /* + * Check if this rport already exists + */ + rport = bfa_fcs_lport_get_rport_by_pid(port, gidft_entry->pid); + if (rport == NULL) { + /* + * this is a new device. create rport + */ + rport = bfa_fcs_rport_create(port, gidft_entry->pid); + } else { + /* + * this rport already exists + */ + bfa_fcs_rport_scn(rport); + } + + bfa_trc(port->fcs, gidft_entry->pid); + + /* + * if the last entry bit is set, bail out. + */ + if (gidft_entry->last) + return; + } +} + +/** + * fcs_ns_public FCS nameserver public interfaces + */ + +/* + * Functions called by port/fab. + * These will send relevant Events to the ns state machine. + */ +void +bfa_fcs_lport_ns_init(struct bfa_fcs_lport_s *port) +{ + struct bfa_fcs_lport_ns_s *ns = BFA_FCS_GET_NS_FROM_PORT(port); + + ns->port = port; + bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_offline); +} + +void +bfa_fcs_lport_ns_offline(struct bfa_fcs_lport_s *port) +{ + struct bfa_fcs_lport_ns_s *ns = BFA_FCS_GET_NS_FROM_PORT(port); + + ns->port = port; + bfa_sm_send_event(ns, NSSM_EVENT_PORT_OFFLINE); +} + +void +bfa_fcs_lport_ns_online(struct bfa_fcs_lport_s *port) +{ + struct bfa_fcs_lport_ns_s *ns = BFA_FCS_GET_NS_FROM_PORT(port); + + ns->port = port; + bfa_sm_send_event(ns, NSSM_EVENT_PORT_ONLINE); +} + +void +bfa_fcs_lport_ns_query(struct bfa_fcs_lport_s *port) +{ + struct bfa_fcs_lport_ns_s *ns = BFA_FCS_GET_NS_FROM_PORT(port); + + bfa_trc(port->fcs, port->pid); + bfa_sm_send_event(ns, NSSM_EVENT_NS_QUERY); +} + +void +bfa_fcs_lport_ns_boot_target_disc(bfa_fcs_lport_t *port) +{ + + struct bfa_fcs_rport_s *rport; + u8 nwwns; + wwn_t wwns[BFA_PREBOOT_BOOTLUN_MAX]; + int ii; + + bfa_iocfc_get_bootwwns(port->fcs->bfa, &nwwns, wwns); + + for (ii = 0 ; ii < nwwns; ++ii) { + rport = bfa_fcs_rport_create_by_wwn(port, wwns[ii]); + bfa_assert(rport); + } +} + +/** + * FCS SCN + */ + +#define FC_QOS_RSCN_EVENT 0x0c +#define FC_FABRIC_NAME_RSCN_EVENT 0x0d + +/* + * forward declarations + */ +static void bfa_fcs_lport_scn_send_scr(void *scn_cbarg, + struct bfa_fcxp_s *fcxp_alloced); +static void bfa_fcs_lport_scn_scr_response(void *fcsarg, + struct bfa_fcxp_s *fcxp, + void *cbarg, + bfa_status_t req_status, + u32 rsp_len, + u32 resid_len, + struct fchs_s *rsp_fchs); +static void bfa_fcs_lport_scn_send_ls_acc(struct bfa_fcs_lport_s *port, + struct fchs_s *rx_fchs); +static void bfa_fcs_lport_scn_timeout(void *arg); + +/** + * fcs_scm_sm FCS SCN state machine + */ + +/** + * VPort SCN State Machine events + */ +enum port_scn_event { + SCNSM_EVENT_PORT_ONLINE = 1, + SCNSM_EVENT_PORT_OFFLINE = 2, + SCNSM_EVENT_RSP_OK = 3, + SCNSM_EVENT_RSP_ERROR = 4, + SCNSM_EVENT_TIMEOUT = 5, + SCNSM_EVENT_SCR_SENT = 6, +}; + +static void bfa_fcs_lport_scn_sm_offline(struct bfa_fcs_lport_scn_s *scn, + enum port_scn_event event); +static void bfa_fcs_lport_scn_sm_sending_scr( + struct bfa_fcs_lport_scn_s *scn, + enum port_scn_event event); +static void bfa_fcs_lport_scn_sm_scr(struct bfa_fcs_lport_scn_s *scn, + enum port_scn_event event); +static void bfa_fcs_lport_scn_sm_scr_retry(struct bfa_fcs_lport_scn_s *scn, + enum port_scn_event event); +static void bfa_fcs_lport_scn_sm_online(struct bfa_fcs_lport_scn_s *scn, + enum port_scn_event event); + +/** + * Starting state - awaiting link up. + */ +static void +bfa_fcs_lport_scn_sm_offline(struct bfa_fcs_lport_scn_s *scn, + enum port_scn_event event) +{ + switch (event) { + case SCNSM_EVENT_PORT_ONLINE: + bfa_sm_set_state(scn, bfa_fcs_lport_scn_sm_sending_scr); + bfa_fcs_lport_scn_send_scr(scn, NULL); + break; + + case SCNSM_EVENT_PORT_OFFLINE: + break; + + default: + bfa_sm_fault(scn->port->fcs, event); + } +} + +static void +bfa_fcs_lport_scn_sm_sending_scr(struct bfa_fcs_lport_scn_s *scn, + enum port_scn_event event) +{ + switch (event) { + case SCNSM_EVENT_SCR_SENT: + bfa_sm_set_state(scn, bfa_fcs_lport_scn_sm_scr); + break; + + case SCNSM_EVENT_PORT_OFFLINE: + bfa_sm_set_state(scn, bfa_fcs_lport_scn_sm_offline); + bfa_fcxp_walloc_cancel(scn->port->fcs->bfa, &scn->fcxp_wqe); + break; + + default: + bfa_sm_fault(scn->port->fcs, event); + } +} + +static void +bfa_fcs_lport_scn_sm_scr(struct bfa_fcs_lport_scn_s *scn, + enum port_scn_event event) +{ + struct bfa_fcs_lport_s *port = scn->port; + + switch (event) { + case SCNSM_EVENT_RSP_OK: + bfa_sm_set_state(scn, bfa_fcs_lport_scn_sm_online); + break; + + case SCNSM_EVENT_RSP_ERROR: + bfa_sm_set_state(scn, bfa_fcs_lport_scn_sm_scr_retry); + bfa_timer_start(port->fcs->bfa, &scn->timer, + bfa_fcs_lport_scn_timeout, scn, + BFA_FCS_RETRY_TIMEOUT); + break; + + case SCNSM_EVENT_PORT_OFFLINE: + bfa_sm_set_state(scn, bfa_fcs_lport_scn_sm_offline); + bfa_fcxp_discard(scn->fcxp); + break; + + default: + bfa_sm_fault(port->fcs, event); + } +} + +static void +bfa_fcs_lport_scn_sm_scr_retry(struct bfa_fcs_lport_scn_s *scn, + enum port_scn_event event) +{ + switch (event) { + case SCNSM_EVENT_TIMEOUT: + bfa_sm_set_state(scn, bfa_fcs_lport_scn_sm_sending_scr); + bfa_fcs_lport_scn_send_scr(scn, NULL); + break; + + case SCNSM_EVENT_PORT_OFFLINE: + bfa_sm_set_state(scn, bfa_fcs_lport_scn_sm_offline); + bfa_timer_stop(&scn->timer); + break; + + default: + bfa_sm_fault(scn->port->fcs, event); + } +} + +static void +bfa_fcs_lport_scn_sm_online(struct bfa_fcs_lport_scn_s *scn, + enum port_scn_event event) +{ + switch (event) { + case SCNSM_EVENT_PORT_OFFLINE: + bfa_sm_set_state(scn, bfa_fcs_lport_scn_sm_offline); + break; + + default: + bfa_sm_fault(scn->port->fcs, event); + } +} + + + +/** + * fcs_scn_private FCS SCN private functions + */ + +/** + * This routine will be called to send a SCR command. + */ +static void +bfa_fcs_lport_scn_send_scr(void *scn_cbarg, struct bfa_fcxp_s *fcxp_alloced) +{ + struct bfa_fcs_lport_scn_s *scn = scn_cbarg; + struct bfa_fcs_lport_s *port = scn->port; + struct fchs_s fchs; + int len; + struct bfa_fcxp_s *fcxp; + + bfa_trc(port->fcs, port->pid); + bfa_trc(port->fcs, port->port_cfg.pwwn); + + fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); + if (!fcxp) { + bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &scn->fcxp_wqe, + bfa_fcs_lport_scn_send_scr, scn); + return; + } + scn->fcxp = fcxp; + + /* Handle VU registrations for Base port only */ + if ((!port->vport) && bfa_ioc_get_fcmode(&port->fcs->bfa->ioc)) { + len = fc_scr_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), + bfa_lps_is_brcd_fabric(port->fabric->lps), + port->pid, 0); + } else { + len = fc_scr_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), + BFA_FALSE, + port->pid, 0); + } + + bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, + FC_CLASS_3, len, &fchs, + bfa_fcs_lport_scn_scr_response, + (void *)scn, FC_MAX_PDUSZ, FC_ELS_TOV); + + bfa_sm_send_event(scn, SCNSM_EVENT_SCR_SENT); +} + +static void +bfa_fcs_lport_scn_scr_response(void *fcsarg, struct bfa_fcxp_s *fcxp, + void *cbarg, bfa_status_t req_status, u32 rsp_len, + u32 resid_len, struct fchs_s *rsp_fchs) +{ + struct bfa_fcs_lport_scn_s *scn = (struct bfa_fcs_lport_scn_s *) cbarg; + struct bfa_fcs_lport_s *port = scn->port; + struct fc_els_cmd_s *els_cmd; + struct fc_ls_rjt_s *ls_rjt; + + bfa_trc(port->fcs, port->port_cfg.pwwn); + + /* + * Sanity Checks + */ + if (req_status != BFA_STATUS_OK) { + bfa_trc(port->fcs, req_status); + bfa_sm_send_event(scn, SCNSM_EVENT_RSP_ERROR); + return; + } + + els_cmd = (struct fc_els_cmd_s *) BFA_FCXP_RSP_PLD(fcxp); + + switch (els_cmd->els_code) { + + case FC_ELS_ACC: + bfa_sm_send_event(scn, SCNSM_EVENT_RSP_OK); + break; + + case FC_ELS_LS_RJT: + + ls_rjt = (struct fc_ls_rjt_s *) BFA_FCXP_RSP_PLD(fcxp); + + bfa_trc(port->fcs, ls_rjt->reason_code); + bfa_trc(port->fcs, ls_rjt->reason_code_expl); + + bfa_sm_send_event(scn, SCNSM_EVENT_RSP_ERROR); + break; + + default: + bfa_sm_send_event(scn, SCNSM_EVENT_RSP_ERROR); + } +} + +/* + * Send a LS Accept + */ +static void +bfa_fcs_lport_scn_send_ls_acc(struct bfa_fcs_lport_s *port, + struct fchs_s *rx_fchs) +{ + struct fchs_s fchs; + struct bfa_fcxp_s *fcxp; + struct bfa_rport_s *bfa_rport = NULL; + int len; + + bfa_trc(port->fcs, rx_fchs->s_id); + + fcxp = bfa_fcs_fcxp_alloc(port->fcs); + if (!fcxp) + return; + + len = fc_ls_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), + rx_fchs->s_id, bfa_fcs_lport_get_fcid(port), + rx_fchs->ox_id); + + bfa_fcxp_send(fcxp, bfa_rport, port->fabric->vf_id, port->lp_tag, + BFA_FALSE, FC_CLASS_3, len, &fchs, NULL, NULL, + FC_MAX_PDUSZ, 0); +} + +/** + * This routine will be called by bfa_timer on timer timeouts. + * + * param[in] vport - pointer to bfa_fcs_lport_t. + * param[out] vport_status - pointer to return vport status in + * + * return + * void + * + * Special Considerations: + * + * note + */ +static void +bfa_fcs_lport_scn_timeout(void *arg) +{ + struct bfa_fcs_lport_scn_s *scn = (struct bfa_fcs_lport_scn_s *) arg; + + bfa_sm_send_event(scn, SCNSM_EVENT_TIMEOUT); +} + + + +/** + * fcs_scn_public FCS state change notification public interfaces + */ + +/* + * Functions called by port/fab + */ +void +bfa_fcs_lport_scn_init(struct bfa_fcs_lport_s *port) +{ + struct bfa_fcs_lport_scn_s *scn = BFA_FCS_GET_SCN_FROM_PORT(port); + + scn->port = port; + bfa_sm_set_state(scn, bfa_fcs_lport_scn_sm_offline); +} + +void +bfa_fcs_lport_scn_offline(struct bfa_fcs_lport_s *port) +{ + struct bfa_fcs_lport_scn_s *scn = BFA_FCS_GET_SCN_FROM_PORT(port); + + scn->port = port; + bfa_sm_send_event(scn, SCNSM_EVENT_PORT_OFFLINE); +} + +void +bfa_fcs_lport_scn_online(struct bfa_fcs_lport_s *port) +{ + struct bfa_fcs_lport_scn_s *scn = BFA_FCS_GET_SCN_FROM_PORT(port); + + scn->port = port; + bfa_sm_send_event(scn, SCNSM_EVENT_PORT_ONLINE); +} + +static void +bfa_fcs_lport_scn_portid_rscn(struct bfa_fcs_lport_s *port, u32 rpid) +{ + struct bfa_fcs_rport_s *rport; + + bfa_trc(port->fcs, rpid); + + /** + * If this is an unknown device, then it just came online. + * Otherwise let rport handle the RSCN event. + */ + rport = bfa_fcs_lport_get_rport_by_pid(port, rpid); + if (rport == NULL) { + /* + * If min cfg mode is enabled, we donot need to + * discover any new rports. + */ + if (!__fcs_min_cfg(port->fcs)) + rport = bfa_fcs_rport_create(port, rpid); + } else + bfa_fcs_rport_scn(rport); +} + +/** + * rscn format based PID comparison + */ +#define __fc_pid_match(__c0, __c1, __fmt) \ + (((__fmt) == FC_RSCN_FORMAT_FABRIC) || \ + (((__fmt) == FC_RSCN_FORMAT_DOMAIN) && \ + ((__c0)[0] == (__c1)[0])) || \ + (((__fmt) == FC_RSCN_FORMAT_AREA) && \ + ((__c0)[0] == (__c1)[0]) && \ + ((__c0)[1] == (__c1)[1]))) + +static void +bfa_fcs_lport_scn_multiport_rscn(struct bfa_fcs_lport_s *port, + enum fc_rscn_format format, + u32 rscn_pid) +{ + struct bfa_fcs_rport_s *rport; + struct list_head *qe, *qe_next; + u8 *c0, *c1; + + bfa_trc(port->fcs, format); + bfa_trc(port->fcs, rscn_pid); + + c0 = (u8 *) &rscn_pid; + + list_for_each_safe(qe, qe_next, &port->rport_q) { + rport = (struct bfa_fcs_rport_s *) qe; + c1 = (u8 *) &rport->pid; + if (__fc_pid_match(c0, c1, format)) + bfa_fcs_rport_scn(rport); + } +} + + +void +bfa_fcs_lport_scn_process_rscn(struct bfa_fcs_lport_s *port, + struct fchs_s *fchs, u32 len) +{ + struct fc_rscn_pl_s *rscn = (struct fc_rscn_pl_s *) (fchs + 1); + int num_entries; + u32 rscn_pid; + bfa_boolean_t nsquery = BFA_FALSE, found; + int i = 0, j; + + num_entries = + (bfa_os_ntohs(rscn->payldlen) - + sizeof(u32)) / sizeof(rscn->event[0]); + + bfa_trc(port->fcs, num_entries); + + port->stats.num_rscn++; + + bfa_fcs_lport_scn_send_ls_acc(port, fchs); + + for (i = 0; i < num_entries; i++) { + rscn_pid = rscn->event[i].portid; + + bfa_trc(port->fcs, rscn->event[i].format); + bfa_trc(port->fcs, rscn_pid); + + /* check for duplicate entries in the list */ + found = BFA_FALSE; + for (j = 0; j < i; j++) { + if (rscn->event[j].portid == rscn_pid) { + found = BFA_TRUE; + break; + } + } + + /* if found in down the list, pid has been already processed */ + if (found) { + bfa_trc(port->fcs, rscn_pid); + continue; + } + + switch (rscn->event[i].format) { + case FC_RSCN_FORMAT_PORTID: + if (rscn->event[i].qualifier == FC_QOS_RSCN_EVENT) { + /* + * Ignore this event. + * f/w would have processed it + */ + bfa_trc(port->fcs, rscn_pid); + } else { + port->stats.num_portid_rscn++; + bfa_fcs_lport_scn_portid_rscn(port, rscn_pid); + } + break; + + case FC_RSCN_FORMAT_FABRIC: + if (rscn->event[i].qualifier == + FC_FABRIC_NAME_RSCN_EVENT) { + bfa_fcs_lport_ms_fabric_rscn(port); + break; + } + /* !!!!!!!!! Fall Through !!!!!!!!!!!!! */ + + case FC_RSCN_FORMAT_AREA: + case FC_RSCN_FORMAT_DOMAIN: + nsquery = BFA_TRUE; + bfa_fcs_lport_scn_multiport_rscn(port, + rscn->event[i].format, + rscn_pid); + break; + + + default: + bfa_assert(0); + nsquery = BFA_TRUE; + } + } + + /** + * If any of area, domain or fabric RSCN is received, do a fresh discovery + * to find new devices. + */ + if (nsquery) + bfa_fcs_lport_ns_query(port); +} + +/** + * BFA FCS port + */ +/** + * fcs_port_api BFA FCS port API + */ +struct bfa_fcs_lport_s * +bfa_fcs_get_base_port(struct bfa_fcs_s *fcs) +{ + return &fcs->fabric.bport; +} + +wwn_t +bfa_fcs_lport_get_rport(struct bfa_fcs_lport_s *port, wwn_t wwn, int index, + int nrports, bfa_boolean_t bwwn) +{ + struct list_head *qh, *qe; + struct bfa_fcs_rport_s *rport = NULL; + int i; + struct bfa_fcs_s *fcs; + + if (port == NULL || nrports == 0) + return (wwn_t) 0; + + fcs = port->fcs; + bfa_trc(fcs, (u32) nrports); + + i = 0; + qh = &port->rport_q; + qe = bfa_q_first(qh); + + while ((qe != qh) && (i < nrports)) { + rport = (struct bfa_fcs_rport_s *) qe; + if (bfa_os_ntoh3b(rport->pid) > 0xFFF000) { + qe = bfa_q_next(qe); + bfa_trc(fcs, (u32) rport->pwwn); + bfa_trc(fcs, rport->pid); + bfa_trc(fcs, i); + continue; + } + + if (bwwn) { + if (!memcmp(&wwn, &rport->pwwn, 8)) + break; + } else { + if (i == index) + break; + } + + i++; + qe = bfa_q_next(qe); + } + + bfa_trc(fcs, i); + if (rport) + return rport->pwwn; + else + return (wwn_t) 0; +} + +void +bfa_fcs_lport_get_rports(struct bfa_fcs_lport_s *port, + wwn_t rport_wwns[], int *nrports) +{ + struct list_head *qh, *qe; + struct bfa_fcs_rport_s *rport = NULL; + int i; + struct bfa_fcs_s *fcs; + + if (port == NULL || rport_wwns == NULL || *nrports == 0) + return; + + fcs = port->fcs; + bfa_trc(fcs, (u32) *nrports); + + i = 0; + qh = &port->rport_q; + qe = bfa_q_first(qh); + + while ((qe != qh) && (i < *nrports)) { + rport = (struct bfa_fcs_rport_s *) qe; + if (bfa_os_ntoh3b(rport->pid) > 0xFFF000) { + qe = bfa_q_next(qe); + bfa_trc(fcs, (u32) rport->pwwn); + bfa_trc(fcs, rport->pid); + bfa_trc(fcs, i); + continue; + } + + rport_wwns[i] = rport->pwwn; + + i++; + qe = bfa_q_next(qe); + } + + bfa_trc(fcs, i); + *nrports = i; +} + +/* + * Iterate's through all the rport's in the given port to + * determine the maximum operating speed. + * + * !!!! To be used in TRL Functionality only !!!! + */ +bfa_port_speed_t +bfa_fcs_lport_get_rport_max_speed(bfa_fcs_lport_t *port) +{ + struct list_head *qh, *qe; + struct bfa_fcs_rport_s *rport = NULL; + struct bfa_fcs_s *fcs; + bfa_port_speed_t max_speed = 0; + struct bfa_port_attr_s port_attr; + bfa_port_speed_t port_speed, rport_speed; + bfa_boolean_t trl_enabled = bfa_fcport_is_ratelim(port->fcs->bfa); + + + if (port == NULL) + return 0; + + fcs = port->fcs; + + /* Get Physical port's current speed */ + bfa_fcport_get_attr(port->fcs->bfa, &port_attr); + port_speed = port_attr.speed; + bfa_trc(fcs, port_speed); + + qh = &port->rport_q; + qe = bfa_q_first(qh); + + while (qe != qh) { + rport = (struct bfa_fcs_rport_s *) qe; + if ((bfa_os_ntoh3b(rport->pid) > 0xFFF000) || + (bfa_fcs_rport_get_state(rport) == + BFA_RPORT_OFFLINE)) { + qe = bfa_q_next(qe); + continue; + } + + rport_speed = rport->rpf.rpsc_speed; + if ((trl_enabled) && (rport_speed == + BFA_PORT_SPEED_UNKNOWN)) { + /* Use default ratelim speed setting */ + rport_speed = + bfa_fcport_get_ratelim_speed(port->fcs->bfa); + } + if ((rport_speed == BFA_PORT_SPEED_8GBPS) || + (rport_speed > port_speed)) { + max_speed = rport_speed; + break; + } else if (rport_speed > max_speed) { + max_speed = rport_speed; + } + + qe = bfa_q_next(qe); + } + + bfa_trc(fcs, max_speed); + return max_speed; +} + +struct bfa_fcs_lport_s * +bfa_fcs_lookup_port(struct bfa_fcs_s *fcs, u16 vf_id, wwn_t lpwwn) +{ + struct bfa_fcs_vport_s *vport; + bfa_fcs_vf_t *vf; + + bfa_assert(fcs != NULL); + + vf = bfa_fcs_vf_lookup(fcs, vf_id); + if (vf == NULL) { + bfa_trc(fcs, vf_id); + return NULL; + } + + if (!lpwwn || (vf->bport.port_cfg.pwwn == lpwwn)) + return &vf->bport; + + vport = bfa_fcs_fabric_vport_lookup(vf, lpwwn); + if (vport) + return &vport->lport; + + return NULL; +} + +/* + * API corresponding to NPIV_VPORT_GETINFO. + */ +void +bfa_fcs_lport_get_info(struct bfa_fcs_lport_s *port, + struct bfa_lport_info_s *port_info) +{ + + bfa_trc(port->fcs, port->fabric->fabric_name); + + if (port->vport == NULL) { + /* + * This is a Physical port + */ + port_info->port_type = BFA_LPORT_TYPE_PHYSICAL; + + /* + * @todo : need to fix the state & reason + */ + port_info->port_state = 0; + port_info->offline_reason = 0; + + port_info->port_wwn = bfa_fcs_lport_get_pwwn(port); + port_info->node_wwn = bfa_fcs_lport_get_nwwn(port); + + port_info->max_vports_supp = + bfa_lps_get_max_vport(port->fcs->bfa); + port_info->num_vports_inuse = + bfa_fcs_fabric_vport_count(port->fabric); + port_info->max_rports_supp = BFA_FCS_MAX_RPORTS_SUPP; + port_info->num_rports_inuse = port->num_rports; } else { - port_attr->port_type = BFA_PPORT_TYPE_UNKNOWN; - port_attr->state = BFA_PORT_UNINIT; + /* + * This is a virtual port + */ + port_info->port_type = BFA_LPORT_TYPE_VIRTUAL; + + /* + * @todo : need to fix the state & reason + */ + port_info->port_state = 0; + port_info->offline_reason = 0; + + port_info->port_wwn = bfa_fcs_lport_get_pwwn(port); + port_info->node_wwn = bfa_fcs_lport_get_nwwn(port); + } +} + +void +bfa_fcs_lport_get_stats(struct bfa_fcs_lport_s *fcs_port, + struct bfa_lport_stats_s *port_stats) +{ + *port_stats = fcs_port->stats; +} + +void +bfa_fcs_lport_clear_stats(struct bfa_fcs_lport_s *fcs_port) +{ + bfa_os_memset(&fcs_port->stats, 0, sizeof(struct bfa_lport_stats_s)); +} + +/** + * FCS virtual port state machine + */ + +#define __vport_fcs(__vp) ((__vp)->lport.fcs) +#define __vport_pwwn(__vp) ((__vp)->lport.port_cfg.pwwn) +#define __vport_nwwn(__vp) ((__vp)->lport.port_cfg.nwwn) +#define __vport_bfa(__vp) ((__vp)->lport.fcs->bfa) +#define __vport_fcid(__vp) ((__vp)->lport.pid) +#define __vport_fabric(__vp) ((__vp)->lport.fabric) +#define __vport_vfid(__vp) ((__vp)->lport.fabric->vf_id) + +#define BFA_FCS_VPORT_MAX_RETRIES 5 +/* + * Forward declarations + */ +static void bfa_fcs_vport_do_fdisc(struct bfa_fcs_vport_s *vport); +static void bfa_fcs_vport_timeout(void *vport_arg); +static void bfa_fcs_vport_do_logo(struct bfa_fcs_vport_s *vport); +static void bfa_fcs_vport_free(struct bfa_fcs_vport_s *vport); + +/** + * fcs_vport_sm FCS virtual port state machine + */ + +/** + * VPort State Machine events + */ +enum bfa_fcs_vport_event { + BFA_FCS_VPORT_SM_CREATE = 1, /* vport create event */ + BFA_FCS_VPORT_SM_DELETE = 2, /* vport delete event */ + BFA_FCS_VPORT_SM_START = 3, /* vport start request */ + BFA_FCS_VPORT_SM_STOP = 4, /* stop: unsupported */ + BFA_FCS_VPORT_SM_ONLINE = 5, /* fabric online */ + BFA_FCS_VPORT_SM_OFFLINE = 6, /* fabric offline event */ + BFA_FCS_VPORT_SM_FRMSENT = 7, /* fdisc/logo sent events */ + BFA_FCS_VPORT_SM_RSP_OK = 8, /* good response */ + BFA_FCS_VPORT_SM_RSP_ERROR = 9, /* error/bad response */ + BFA_FCS_VPORT_SM_TIMEOUT = 10, /* delay timer event */ + BFA_FCS_VPORT_SM_DELCOMP = 11, /* lport delete completion */ + BFA_FCS_VPORT_SM_RSP_DUP_WWN = 12, /* Dup wnn error*/ + BFA_FCS_VPORT_SM_RSP_FAILED = 13, /* non-retryable failure */ +}; + +static void bfa_fcs_vport_sm_uninit(struct bfa_fcs_vport_s *vport, + enum bfa_fcs_vport_event event); +static void bfa_fcs_vport_sm_created(struct bfa_fcs_vport_s *vport, + enum bfa_fcs_vport_event event); +static void bfa_fcs_vport_sm_offline(struct bfa_fcs_vport_s *vport, + enum bfa_fcs_vport_event event); +static void bfa_fcs_vport_sm_fdisc(struct bfa_fcs_vport_s *vport, + enum bfa_fcs_vport_event event); +static void bfa_fcs_vport_sm_fdisc_retry(struct bfa_fcs_vport_s *vport, + enum bfa_fcs_vport_event event); +static void bfa_fcs_vport_sm_online(struct bfa_fcs_vport_s *vport, + enum bfa_fcs_vport_event event); +static void bfa_fcs_vport_sm_deleting(struct bfa_fcs_vport_s *vport, + enum bfa_fcs_vport_event event); +static void bfa_fcs_vport_sm_cleanup(struct bfa_fcs_vport_s *vport, + enum bfa_fcs_vport_event event); +static void bfa_fcs_vport_sm_logo(struct bfa_fcs_vport_s *vport, + enum bfa_fcs_vport_event event); +static void bfa_fcs_vport_sm_error(struct bfa_fcs_vport_s *vport, + enum bfa_fcs_vport_event event); + +static struct bfa_sm_table_s vport_sm_table[] = { + {BFA_SM(bfa_fcs_vport_sm_uninit), BFA_FCS_VPORT_UNINIT}, + {BFA_SM(bfa_fcs_vport_sm_created), BFA_FCS_VPORT_CREATED}, + {BFA_SM(bfa_fcs_vport_sm_offline), BFA_FCS_VPORT_OFFLINE}, + {BFA_SM(bfa_fcs_vport_sm_fdisc), BFA_FCS_VPORT_FDISC}, + {BFA_SM(bfa_fcs_vport_sm_fdisc_retry), BFA_FCS_VPORT_FDISC_RETRY}, + {BFA_SM(bfa_fcs_vport_sm_online), BFA_FCS_VPORT_ONLINE}, + {BFA_SM(bfa_fcs_vport_sm_deleting), BFA_FCS_VPORT_DELETING}, + {BFA_SM(bfa_fcs_vport_sm_cleanup), BFA_FCS_VPORT_CLEANUP}, + {BFA_SM(bfa_fcs_vport_sm_logo), BFA_FCS_VPORT_LOGO}, + {BFA_SM(bfa_fcs_vport_sm_error), BFA_FCS_VPORT_ERROR} +}; + +/** + * Beginning state. + */ +static void +bfa_fcs_vport_sm_uninit(struct bfa_fcs_vport_s *vport, + enum bfa_fcs_vport_event event) +{ + bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); + bfa_trc(__vport_fcs(vport), event); + + switch (event) { + case BFA_FCS_VPORT_SM_CREATE: + bfa_sm_set_state(vport, bfa_fcs_vport_sm_created); + bfa_fcs_fabric_addvport(__vport_fabric(vport), vport); + break; + + default: + bfa_sm_fault(__vport_fcs(vport), event); + } +} + +/** + * Created state - a start event is required to start up the state machine. + */ +static void +bfa_fcs_vport_sm_created(struct bfa_fcs_vport_s *vport, + enum bfa_fcs_vport_event event) +{ + bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); + bfa_trc(__vport_fcs(vport), event); + + switch (event) { + case BFA_FCS_VPORT_SM_START: + if (bfa_fcs_fabric_is_online(__vport_fabric(vport)) + && bfa_fcs_fabric_npiv_capable(__vport_fabric(vport))) { + bfa_sm_set_state(vport, bfa_fcs_vport_sm_fdisc); + bfa_fcs_vport_do_fdisc(vport); + } else { + /** + * Fabric is offline or not NPIV capable, stay in + * offline state. + */ + vport->vport_stats.fab_no_npiv++; + bfa_sm_set_state(vport, bfa_fcs_vport_sm_offline); + } + break; + + case BFA_FCS_VPORT_SM_DELETE: + bfa_sm_set_state(vport, bfa_fcs_vport_sm_cleanup); + bfa_fcs_lport_delete(&vport->lport); + break; + + case BFA_FCS_VPORT_SM_ONLINE: + case BFA_FCS_VPORT_SM_OFFLINE: + /** + * Ignore ONLINE/OFFLINE events from fabric + * till vport is started. + */ + break; + + default: + bfa_sm_fault(__vport_fcs(vport), event); + } +} + +/** + * Offline state - awaiting ONLINE event from fabric SM. + */ +static void +bfa_fcs_vport_sm_offline(struct bfa_fcs_vport_s *vport, + enum bfa_fcs_vport_event event) +{ + bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); + bfa_trc(__vport_fcs(vport), event); + + switch (event) { + case BFA_FCS_VPORT_SM_DELETE: + bfa_sm_set_state(vport, bfa_fcs_vport_sm_cleanup); + bfa_fcs_lport_delete(&vport->lport); + break; + + case BFA_FCS_VPORT_SM_ONLINE: + bfa_sm_set_state(vport, bfa_fcs_vport_sm_fdisc); + vport->fdisc_retries = 0; + bfa_fcs_vport_do_fdisc(vport); + break; + + case BFA_FCS_VPORT_SM_OFFLINE: + /* + * This can happen if the vport couldn't be initialzied + * due the fact that the npiv was not enabled on the switch. + * In that case we will put the vport in offline state. + * However, the link can go down and cause the this event to + * be sent when we are already offline. Ignore it. + */ + break; + + default: + bfa_sm_fault(__vport_fcs(vport), event); + } +} + + +/** + * FDISC is sent and awaiting reply from fabric. + */ +static void +bfa_fcs_vport_sm_fdisc(struct bfa_fcs_vport_s *vport, + enum bfa_fcs_vport_event event) +{ + bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); + bfa_trc(__vport_fcs(vport), event); + + switch (event) { + case BFA_FCS_VPORT_SM_DELETE: + bfa_sm_set_state(vport, bfa_fcs_vport_sm_cleanup); + bfa_lps_discard(vport->lps); + bfa_fcs_lport_delete(&vport->lport); + break; + + case BFA_FCS_VPORT_SM_OFFLINE: + bfa_sm_set_state(vport, bfa_fcs_vport_sm_offline); + bfa_lps_discard(vport->lps); + break; + + case BFA_FCS_VPORT_SM_RSP_OK: + bfa_sm_set_state(vport, bfa_fcs_vport_sm_online); + bfa_fcs_lport_online(&vport->lport); + break; + + case BFA_FCS_VPORT_SM_RSP_ERROR: + bfa_sm_set_state(vport, bfa_fcs_vport_sm_fdisc_retry); + bfa_timer_start(__vport_bfa(vport), &vport->timer, + bfa_fcs_vport_timeout, vport, + BFA_FCS_RETRY_TIMEOUT); + break; + + case BFA_FCS_VPORT_SM_RSP_FAILED: + bfa_sm_set_state(vport, bfa_fcs_vport_sm_offline); + break; + + case BFA_FCS_VPORT_SM_RSP_DUP_WWN: + bfa_sm_set_state(vport, bfa_fcs_vport_sm_error); + break; + + default: + bfa_sm_fault(__vport_fcs(vport), event); + } +} + +/** + * FDISC attempt failed - a timer is active to retry FDISC. + */ +static void +bfa_fcs_vport_sm_fdisc_retry(struct bfa_fcs_vport_s *vport, + enum bfa_fcs_vport_event event) +{ + bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); + bfa_trc(__vport_fcs(vport), event); + + switch (event) { + case BFA_FCS_VPORT_SM_DELETE: + bfa_sm_set_state(vport, bfa_fcs_vport_sm_cleanup); + bfa_timer_stop(&vport->timer); + bfa_fcs_lport_delete(&vport->lport); + break; + + case BFA_FCS_VPORT_SM_OFFLINE: + bfa_sm_set_state(vport, bfa_fcs_vport_sm_offline); + bfa_timer_stop(&vport->timer); + break; + + case BFA_FCS_VPORT_SM_TIMEOUT: + bfa_sm_set_state(vport, bfa_fcs_vport_sm_fdisc); + vport->vport_stats.fdisc_retries++; + vport->fdisc_retries++; + bfa_fcs_vport_do_fdisc(vport); + break; + + default: + bfa_sm_fault(__vport_fcs(vport), event); + } +} + +/** + * Vport is online (FDISC is complete). + */ +static void +bfa_fcs_vport_sm_online(struct bfa_fcs_vport_s *vport, + enum bfa_fcs_vport_event event) +{ + bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); + bfa_trc(__vport_fcs(vport), event); + + switch (event) { + case BFA_FCS_VPORT_SM_DELETE: + bfa_sm_set_state(vport, bfa_fcs_vport_sm_deleting); + bfa_fcs_lport_delete(&vport->lport); + break; + + case BFA_FCS_VPORT_SM_OFFLINE: + bfa_sm_set_state(vport, bfa_fcs_vport_sm_offline); + bfa_lps_discard(vport->lps); + bfa_fcs_lport_offline(&vport->lport); + break; + + default: + bfa_sm_fault(__vport_fcs(vport), event); + } +} + +/** + * Vport is being deleted - awaiting lport delete completion to send + * LOGO to fabric. + */ +static void +bfa_fcs_vport_sm_deleting(struct bfa_fcs_vport_s *vport, + enum bfa_fcs_vport_event event) +{ + bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); + bfa_trc(__vport_fcs(vport), event); + + switch (event) { + case BFA_FCS_VPORT_SM_DELETE: + break; + + case BFA_FCS_VPORT_SM_DELCOMP: + bfa_sm_set_state(vport, bfa_fcs_vport_sm_logo); + bfa_fcs_vport_do_logo(vport); + break; + + case BFA_FCS_VPORT_SM_OFFLINE: + bfa_sm_set_state(vport, bfa_fcs_vport_sm_cleanup); + break; + + default: + bfa_sm_fault(__vport_fcs(vport), event); + } +} + +/** + * Error State. + * This state will be set when the Vport Creation fails due + * to errors like Dup WWN. In this state only operation allowed + * is a Vport Delete. + */ +static void +bfa_fcs_vport_sm_error(struct bfa_fcs_vport_s *vport, + enum bfa_fcs_vport_event event) +{ + bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); + bfa_trc(__vport_fcs(vport), event); + + switch (event) { + case BFA_FCS_VPORT_SM_DELETE: + bfa_sm_set_state(vport, bfa_fcs_vport_sm_cleanup); + bfa_fcs_lport_delete(&vport->lport); + break; + + default: + bfa_trc(__vport_fcs(vport), event); + } +} + +/** + * Lport cleanup is in progress since vport is being deleted. Fabric is + * offline, so no LOGO is needed to complete vport deletion. + */ +static void +bfa_fcs_vport_sm_cleanup(struct bfa_fcs_vport_s *vport, + enum bfa_fcs_vport_event event) +{ + bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); + bfa_trc(__vport_fcs(vport), event); + + switch (event) { + case BFA_FCS_VPORT_SM_DELCOMP: + bfa_sm_set_state(vport, bfa_fcs_vport_sm_uninit); + bfa_fcs_vport_free(vport); + break; + + case BFA_FCS_VPORT_SM_DELETE: + break; + + default: + bfa_sm_fault(__vport_fcs(vport), event); + } +} + +/** + * LOGO is sent to fabric. Vport delete is in progress. Lport delete cleanup + * is done. + */ +static void +bfa_fcs_vport_sm_logo(struct bfa_fcs_vport_s *vport, + enum bfa_fcs_vport_event event) +{ + bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); + bfa_trc(__vport_fcs(vport), event); + + switch (event) { + case BFA_FCS_VPORT_SM_OFFLINE: + bfa_lps_discard(vport->lps); + /* + * !!! fall through !!! + */ + + case BFA_FCS_VPORT_SM_RSP_OK: + case BFA_FCS_VPORT_SM_RSP_ERROR: + bfa_sm_set_state(vport, bfa_fcs_vport_sm_uninit); + bfa_fcs_vport_free(vport); + break; + + case BFA_FCS_VPORT_SM_DELETE: + break; + + default: + bfa_sm_fault(__vport_fcs(vport), event); + } +} + + + +/** + * fcs_vport_private FCS virtual port private functions + */ +/** + * This routine will be called to send a FDISC command. + */ +static void +bfa_fcs_vport_do_fdisc(struct bfa_fcs_vport_s *vport) +{ + bfa_lps_fdisc(vport->lps, vport, + bfa_fcport_get_maxfrsize(__vport_bfa(vport)), + __vport_pwwn(vport), __vport_nwwn(vport)); + vport->vport_stats.fdisc_sent++; +} + +static void +bfa_fcs_vport_fdisc_rejected(struct bfa_fcs_vport_s *vport) +{ + u8 lsrjt_rsn = bfa_lps_get_lsrjt_rsn(vport->lps); + u8 lsrjt_expl = bfa_lps_get_lsrjt_expl(vport->lps); + + bfa_trc(__vport_fcs(vport), lsrjt_rsn); + bfa_trc(__vport_fcs(vport), lsrjt_expl); + + /* For certain reason codes, we don't want to retry. */ + switch (bfa_lps_get_lsrjt_expl(vport->lps)) { + case FC_LS_RJT_EXP_INV_PORT_NAME: /* by brocade */ + case FC_LS_RJT_EXP_INVALID_NPORT_ID: /* by Cisco */ + if (vport->fdisc_retries < BFA_FCS_VPORT_MAX_RETRIES) + bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_ERROR); + else + bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_DUP_WWN); + break; + + case FC_LS_RJT_EXP_INSUFF_RES: + /* + * This means max logins per port/switch setting on the + * switch was exceeded. + */ + if (vport->fdisc_retries < BFA_FCS_VPORT_MAX_RETRIES) + bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_ERROR); + else + bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_FAILED); + break; + + default: + bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_ERROR); } +} + +/** + * Called to send a logout to the fabric. Used when a V-Port is + * deleted/stopped. + */ +static void +bfa_fcs_vport_do_logo(struct bfa_fcs_vport_s *vport) +{ + bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); + + vport->vport_stats.logo_sent++; + bfa_lps_fdisclogo(vport->lps); +} + + +/** + * This routine will be called by bfa_timer on timer timeouts. + * + * param[in] vport - pointer to bfa_fcs_vport_t. + * param[out] vport_status - pointer to return vport status in + * + * return + * void + * + * Special Considerations: + * + * note + */ +static void +bfa_fcs_vport_timeout(void *vport_arg) +{ + struct bfa_fcs_vport_s *vport = (struct bfa_fcs_vport_s *) vport_arg; + + vport->vport_stats.fdisc_timeouts++; + bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_TIMEOUT); +} + +static void +bfa_fcs_vport_free(struct bfa_fcs_vport_s *vport) +{ + struct bfad_vport_s *vport_drv = + (struct bfad_vport_s *)vport->vport_drv; + + bfa_fcs_fabric_delvport(__vport_fabric(vport), vport); + + if (vport_drv->comp_del) + complete(vport_drv->comp_del); + + bfa_lps_delete(vport->lps); +} + + +/** + * fcs_vport_public FCS virtual port public interfaces + */ + +/** + * Online notification from fabric SM. + */ +void +bfa_fcs_vport_online(struct bfa_fcs_vport_s *vport) +{ + vport->vport_stats.fab_online++; + bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_ONLINE); +} + +/** + * Offline notification from fabric SM. + */ +void +bfa_fcs_vport_offline(struct bfa_fcs_vport_s *vport) +{ + vport->vport_stats.fab_offline++; + bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_OFFLINE); +} + +/** + * Cleanup notification from fabric SM on link timer expiry. + */ +void +bfa_fcs_vport_cleanup(struct bfa_fcs_vport_s *vport) +{ + vport->vport_stats.fab_cleanup++; +} +/** + * delete 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 + */ +void +bfa_fcs_vport_delete_comp(struct bfa_fcs_vport_s *vport) +{ + bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_DELCOMP); +} + + +/** + * fcs_vport_api Virtual port API + */ + +/** + * Use this function to instantiate a new FCS vport object. This + * function will not trigger any HW initialization process (which will be + * done in vport_start() call) + * + * param[in] vport - pointer to bfa_fcs_vport_t. This space + * needs to be allocated by the driver. + * param[in] fcs - FCS instance + * param[in] vport_cfg - vport configuration + * param[in] vf_id - VF_ID if vport is created within a VF. + * FC_VF_ID_NULL to specify base fabric. + * param[in] vport_drv - Opaque handle back to the driver's vport + * structure + * + * retval BFA_STATUS_OK - on success. + * retval BFA_STATUS_FAILED - on failure. + */ +bfa_status_t +bfa_fcs_vport_create(struct bfa_fcs_vport_s *vport, struct bfa_fcs_s *fcs, + u16 vf_id, struct bfa_lport_cfg_s *vport_cfg, + struct bfad_vport_s *vport_drv) +{ + if (vport_cfg->pwwn == 0) + return BFA_STATUS_INVALID_WWN; + + if (bfa_fcs_lport_get_pwwn(&fcs->fabric.bport) == vport_cfg->pwwn) + return BFA_STATUS_VPORT_WWN_BP; + + if (bfa_fcs_vport_lookup(fcs, vf_id, vport_cfg->pwwn) != NULL) + return BFA_STATUS_VPORT_EXISTS; + + if (bfa_fcs_fabric_vport_count(&fcs->fabric) == + bfa_lps_get_max_vport(fcs->bfa)) + return BFA_STATUS_VPORT_MAX; + + vport->lps = bfa_lps_alloc(fcs->bfa); + if (!vport->lps) + return BFA_STATUS_VPORT_MAX; + + vport->vport_drv = vport_drv; + 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); + bfa_fcs_lport_init(&vport->lport, vport_cfg); + bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_CREATE); + + 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, + u16 vf_id, struct bfa_lport_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 to findout if this is a pbc vport or not. + * + * @param[in] vport - pointer to bfa_fcs_vport_t. + * + * @returns None + */ +bfa_boolean_t +bfa_fcs_is_pbc_vport(struct bfa_fcs_vport_s *vport) +{ + + if (vport && (vport->lport.port_cfg.preboot_vp == BFA_TRUE)) + return BFA_TRUE; + else + return BFA_FALSE; + +} + +/** + * Use this function initialize the vport. + * + * @param[in] vport - pointer to bfa_fcs_vport_t. + * + * @returns None + */ +bfa_status_t +bfa_fcs_vport_start(struct bfa_fcs_vport_s *vport) +{ + bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_START); + + return BFA_STATUS_OK; +} + +/** + * Use this function quiese the vport object. This function will return + * immediately, when the vport is actually stopped, the + * bfa_drv_vport_stop_cb() will be called. + * + * param[in] vport - pointer to bfa_fcs_vport_t. + * + * return None + */ +bfa_status_t +bfa_fcs_vport_stop(struct bfa_fcs_vport_s *vport) +{ + bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_STOP); + + return BFA_STATUS_OK; +} + +/** + * Use this function to delete a vport object. Fabric object should + * be stopped before this function call. + * + * !!!!!!! Donot invoke this from within FCS !!!!!!! + * + * param[in] vport - pointer to bfa_fcs_vport_t. + * + * return None + */ +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; +} + +/** + * Use this function to get vport's current status info. + * + * param[in] vport pointer to bfa_fcs_vport_t. + * param[out] attr pointer to return vport attributes + * + * return None + */ +void +bfa_fcs_vport_get_attr(struct bfa_fcs_vport_s *vport, + struct bfa_vport_attr_s *attr) +{ + if (vport == NULL || attr == NULL) + return; + + bfa_os_memset(attr, 0, sizeof(struct bfa_vport_attr_s)); + + bfa_fcs_lport_get_attr(&vport->lport, &attr->port_attr); + attr->vport_state = bfa_sm_to_state(vport_sm_table, vport->sm); +} + +/** + * Use this function to get vport's statistics. + * + * param[in] vport pointer to bfa_fcs_vport_t. + * param[out] stats pointer to return vport statistics in + * + * return None + */ +void +bfa_fcs_vport_get_stats(struct bfa_fcs_vport_s *vport, + struct bfa_vport_stats_s *stats) +{ + *stats = vport->vport_stats; +} + +/** + * Use this function to clear vport's statistics. + * + * param[in] vport pointer to bfa_fcs_vport_t. + * + * return None + */ +void +bfa_fcs_vport_clr_stats(struct bfa_fcs_vport_s *vport) +{ + bfa_os_memset(&vport->vport_stats, 0, sizeof(struct bfa_vport_stats_s)); +} + +/** + * Lookup a virtual port. Excludes base port from lookup. + */ +struct bfa_fcs_vport_s * +bfa_fcs_vport_lookup(struct bfa_fcs_s *fcs, u16 vf_id, wwn_t vpwwn) +{ + struct bfa_fcs_vport_s *vport; + struct bfa_fcs_fabric_s *fabric; + + bfa_trc(fcs, vf_id); + bfa_trc(fcs, vpwwn); + + fabric = bfa_fcs_vf_lookup(fcs, vf_id); + if (!fabric) { + bfa_trc(fcs, vf_id); + return NULL; + } + + vport = bfa_fcs_fabric_vport_lookup(fabric, vpwwn); + return vport; +} + +/** + * FDISC Response + */ +void +bfa_cb_lps_fdisc_comp(void *bfad, void *uarg, bfa_status_t status) +{ + struct bfa_fcs_vport_s *vport = uarg; + + bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); + bfa_trc(__vport_fcs(vport), status); + + switch (status) { + case BFA_STATUS_OK: + /* + * Initialiaze the V-Port fields + */ + __vport_fcid(vport) = bfa_lps_get_pid(vport->lps); + vport->vport_stats.fdisc_accepts++; + bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_OK); + break; + + case BFA_STATUS_INVALID_MAC: + /* Only for CNA */ + vport->vport_stats.fdisc_acc_bad++; + bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_ERROR); + + break; + + case BFA_STATUS_EPROTOCOL: + switch (bfa_lps_get_extstatus(vport->lps)) { + case BFA_EPROTO_BAD_ACCEPT: + vport->vport_stats.fdisc_acc_bad++; + break; + + case BFA_EPROTO_UNKNOWN_RSP: + vport->vport_stats.fdisc_unknown_rsp++; + break; + + default: + break; + } + + bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_ERROR); + break; + + case BFA_STATUS_FABRIC_RJT: + vport->vport_stats.fdisc_rejects++; + bfa_fcs_vport_fdisc_rejected(vport); + break; + + default: + vport->vport_stats.fdisc_rsp_err++; + bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_ERROR); + } +} + +/** + * LOGO response + */ +void +bfa_cb_lps_fdisclogo_comp(void *bfad, void *uarg) +{ + struct bfa_fcs_vport_s *vport = uarg; + bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_OK); +} + +/** + * Received clear virtual link + */ +void +bfa_cb_lps_cvl_event(void *bfad, void *uarg) +{ + struct bfa_fcs_vport_s *vport = uarg; + + /* Send an Offline followed by an ONLINE */ + bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_OFFLINE); + bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_ONLINE); +} diff --git a/drivers/scsi/bfa/bfa_fcs_port.c b/drivers/scsi/bfa/bfa_fcs_port.c deleted file mode 100644 index 3c27788cd527..000000000000 --- a/drivers/scsi/bfa/bfa_fcs_port.c +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/** - * bfa_fcs_pport.c BFA FCS PPORT ( physical port) - */ - -#include <fcs/bfa_fcs.h> -#include <bfa_svc.h> -#include <fcs/bfa_fcs_fabric.h> -#include "fcs_trcmod.h" -#include "fcs.h" -#include "fcs_fabric.h" -#include "fcs_port.h" - -BFA_TRC_FILE(FCS, PPORT); - -static void -bfa_fcs_pport_event_handler(void *cbarg, bfa_pport_event_t event) -{ - struct bfa_fcs_s *fcs = cbarg; - - bfa_trc(fcs, event); - - switch (event) { - case BFA_PPORT_LINKUP: - bfa_fcs_fabric_link_up(&fcs->fabric); - break; - - case BFA_PPORT_LINKDOWN: - bfa_fcs_fabric_link_down(&fcs->fabric); - break; - - case BFA_PPORT_TRUNK_LINKDOWN: - bfa_assert(0); - break; - - default: - bfa_assert(0); - } -} - -void -bfa_fcs_pport_attach(struct bfa_fcs_s *fcs) -{ - bfa_fcport_event_register(fcs->bfa, bfa_fcs_pport_event_handler, fcs); -} diff --git a/drivers/scsi/bfa/rport.c b/drivers/scsi/bfa/bfa_fcs_rport.c index 9b4c2c9a644b..635f0cd88714 100644 --- a/drivers/scsi/bfa/rport.c +++ b/drivers/scsi/bfa/bfa_fcs_rport.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. * All rights reserved * www.brocade.com * @@ -19,151 +19,133 @@ * rport.c Remote port implementation. */ -#include <linux/slab.h> -#include <bfa.h> -#include <bfa_svc.h> -#include "fcbuild.h" -#include "fcs_vport.h" -#include "fcs_lport.h" -#include "fcs_rport.h" -#include "fcs_fcpim.h" -#include "fcs_fcptm.h" -#include "fcs_trcmod.h" -#include "fcs_fcxp.h" -#include "fcs.h" -#include <fcb/bfa_fcb_rport.h> -#include <aen/bfa_aen_rport.h> +#include "bfa_fcs.h" +#include "bfa_fcbuild.h" +#include "bfad_drv.h" BFA_TRC_FILE(FCS, RPORT); -/* In millisecs */ -static u32 bfa_fcs_rport_del_timeout = - BFA_FCS_RPORT_DEF_DEL_TIMEOUT * 1000; - +static u32 +bfa_fcs_rport_del_timeout = BFA_FCS_RPORT_DEF_DEL_TIMEOUT * 1000; + /* In millisecs */ /* * forward declarations */ -static struct bfa_fcs_rport_s *bfa_fcs_rport_alloc(struct bfa_fcs_port_s *port, - wwn_t pwwn, u32 rpid); -static void bfa_fcs_rport_free(struct bfa_fcs_rport_s *rport); -static void bfa_fcs_rport_hal_online(struct bfa_fcs_rport_s *rport); -static void bfa_fcs_rport_online_action(struct bfa_fcs_rport_s *rport); -static void bfa_fcs_rport_offline_action(struct bfa_fcs_rport_s *rport); -static void bfa_fcs_rport_update(struct bfa_fcs_rport_s *rport, - struct fc_logi_s *plogi); -static void bfa_fcs_rport_fc4_pause(struct bfa_fcs_rport_s *rport); -static void bfa_fcs_rport_fc4_resume(struct bfa_fcs_rport_s *rport); -static void bfa_fcs_rport_timeout(void *arg); -static void bfa_fcs_rport_send_plogi(void *rport_cbarg, +static struct bfa_fcs_rport_s *bfa_fcs_rport_alloc( + struct bfa_fcs_lport_s *port, wwn_t pwwn, u32 rpid); +static void bfa_fcs_rport_free(struct bfa_fcs_rport_s *rport); +static void bfa_fcs_rport_hal_online(struct bfa_fcs_rport_s *rport); +static void bfa_fcs_rport_online_action(struct bfa_fcs_rport_s *rport); +static void bfa_fcs_rport_offline_action(struct bfa_fcs_rport_s *rport); +static void bfa_fcs_rport_update(struct bfa_fcs_rport_s *rport, + struct fc_logi_s *plogi); +static void bfa_fcs_rport_timeout(void *arg); +static void bfa_fcs_rport_send_plogi(void *rport_cbarg, struct bfa_fcxp_s *fcxp_alloced); -static void bfa_fcs_rport_send_plogiacc(void *rport_cbarg, - struct bfa_fcxp_s *fcxp_alloced); -static void bfa_fcs_rport_plogi_response(void *fcsarg, - struct bfa_fcxp_s *fcxp, - void *cbarg, - bfa_status_t req_status, - u32 rsp_len, - u32 resid_len, - struct fchs_s *rsp_fchs); -static void bfa_fcs_rport_send_adisc(void *rport_cbarg, +static void bfa_fcs_rport_send_plogiacc(void *rport_cbarg, + struct bfa_fcxp_s *fcxp_alloced); +static void bfa_fcs_rport_plogi_response(void *fcsarg, + struct bfa_fcxp_s *fcxp, void *cbarg, + bfa_status_t req_status, u32 rsp_len, + u32 resid_len, struct fchs_s *rsp_fchs); +static void bfa_fcs_rport_send_adisc(void *rport_cbarg, struct bfa_fcxp_s *fcxp_alloced); -static void bfa_fcs_rport_adisc_response(void *fcsarg, - struct bfa_fcxp_s *fcxp, - void *cbarg, - bfa_status_t req_status, - u32 rsp_len, - u32 resid_len, - struct fchs_s *rsp_fchs); -static void bfa_fcs_rport_send_gidpn(void *rport_cbarg, +static void bfa_fcs_rport_adisc_response(void *fcsarg, + struct bfa_fcxp_s *fcxp, void *cbarg, + bfa_status_t req_status, u32 rsp_len, + u32 resid_len, struct fchs_s *rsp_fchs); +static void bfa_fcs_rport_send_nsdisc(void *rport_cbarg, struct bfa_fcxp_s *fcxp_alloced); -static void bfa_fcs_rport_gidpn_response(void *fcsarg, - struct bfa_fcxp_s *fcxp, - void *cbarg, - bfa_status_t req_status, - u32 rsp_len, - u32 resid_len, - struct fchs_s *rsp_fchs); -static void bfa_fcs_rport_send_logo(void *rport_cbarg, +static void bfa_fcs_rport_gidpn_response(void *fcsarg, + struct bfa_fcxp_s *fcxp, void *cbarg, + bfa_status_t req_status, u32 rsp_len, + u32 resid_len, struct fchs_s *rsp_fchs); +static void bfa_fcs_rport_gpnid_response(void *fcsarg, + struct bfa_fcxp_s *fcxp, void *cbarg, + bfa_status_t req_status, u32 rsp_len, + u32 resid_len, struct fchs_s *rsp_fchs); +static void bfa_fcs_rport_send_logo(void *rport_cbarg, struct bfa_fcxp_s *fcxp_alloced); -static void bfa_fcs_rport_send_logo_acc(void *rport_cbarg); -static void bfa_fcs_rport_process_prli(struct bfa_fcs_rport_s *rport, - struct fchs_s *rx_fchs, u16 len); -static void bfa_fcs_rport_send_ls_rjt(struct bfa_fcs_rport_s *rport, - struct fchs_s *rx_fchs, u8 reason_code, - u8 reason_code_expl); -static void bfa_fcs_rport_process_adisc(struct bfa_fcs_rport_s *rport, - struct fchs_s *rx_fchs, u16 len); -static void bfa_fcs_rport_send_prlo_acc(struct bfa_fcs_rport_s *rport); +static void bfa_fcs_rport_send_logo_acc(void *rport_cbarg); +static void bfa_fcs_rport_process_prli(struct bfa_fcs_rport_s *rport, + struct fchs_s *rx_fchs, u16 len); +static void bfa_fcs_rport_send_ls_rjt(struct bfa_fcs_rport_s *rport, + struct fchs_s *rx_fchs, u8 reason_code, + u8 reason_code_expl); +static void bfa_fcs_rport_process_adisc(struct bfa_fcs_rport_s *rport, + struct fchs_s *rx_fchs, u16 len); +static void bfa_fcs_rport_send_prlo_acc(struct bfa_fcs_rport_s *rport); /** * fcs_rport_sm FCS rport state machine events */ enum rport_event { - RPSM_EVENT_PLOGI_SEND = 1, /* new rport; start with PLOGI */ - RPSM_EVENT_PLOGI_RCVD = 2, /* Inbound PLOGI from remote port */ - RPSM_EVENT_PLOGI_COMP = 3, /* PLOGI completed to rport */ - RPSM_EVENT_LOGO_RCVD = 4, /* LOGO from remote device */ - RPSM_EVENT_LOGO_IMP = 5, /* implicit logo for SLER */ - RPSM_EVENT_FCXP_SENT = 6, /* Frame from has been sent */ - RPSM_EVENT_DELETE = 7, /* RPORT delete request */ - RPSM_EVENT_SCN = 8, /* state change notification */ - RPSM_EVENT_ACCEPTED = 9,/* Good response from remote device */ - RPSM_EVENT_FAILED = 10, /* Request to rport failed. */ - RPSM_EVENT_TIMEOUT = 11, /* Rport SM timeout event */ - RPSM_EVENT_HCB_ONLINE = 12, /* BFA rport online callback */ - RPSM_EVENT_HCB_OFFLINE = 13, /* BFA rport offline callback */ - RPSM_EVENT_FC4_OFFLINE = 14, /* FC-4 offline complete */ - RPSM_EVENT_ADDRESS_CHANGE = 15, /* Rport's PID has changed */ + RPSM_EVENT_PLOGI_SEND = 1, /* new rport; start with PLOGI */ + RPSM_EVENT_PLOGI_RCVD = 2, /* Inbound PLOGI from remote port */ + RPSM_EVENT_PLOGI_COMP = 3, /* PLOGI completed to rport */ + RPSM_EVENT_LOGO_RCVD = 4, /* LOGO from remote device */ + RPSM_EVENT_LOGO_IMP = 5, /* implicit logo for SLER */ + RPSM_EVENT_FCXP_SENT = 6, /* Frame from has been sent */ + RPSM_EVENT_DELETE = 7, /* RPORT delete request */ + RPSM_EVENT_SCN = 8, /* state change notification */ + RPSM_EVENT_ACCEPTED = 9, /* Good response from remote device */ + RPSM_EVENT_FAILED = 10, /* Request to rport failed. */ + RPSM_EVENT_TIMEOUT = 11, /* Rport SM timeout event */ + RPSM_EVENT_HCB_ONLINE = 12, /* BFA rport online callback */ + RPSM_EVENT_HCB_OFFLINE = 13, /* BFA rport offline callback */ + RPSM_EVENT_FC4_OFFLINE = 14, /* FC-4 offline complete */ + RPSM_EVENT_ADDRESS_CHANGE = 15, /* Rport's PID has changed */ RPSM_EVENT_ADDRESS_DISC = 16, /* Need to Discover rport's PID */ - RPSM_EVENT_PRLO_RCVD = 17, /* PRLO from remote device */ + RPSM_EVENT_PRLO_RCVD = 17, /* PRLO from remote device */ + RPSM_EVENT_PLOGI_RETRY = 18, /* Retry PLOGI continously */ }; -static void bfa_fcs_rport_sm_uninit(struct bfa_fcs_rport_s *rport, +static void bfa_fcs_rport_sm_uninit(struct bfa_fcs_rport_s *rport, enum rport_event event); -static void bfa_fcs_rport_sm_plogi_sending(struct bfa_fcs_rport_s *rport, - enum rport_event event); -static void bfa_fcs_rport_sm_plogiacc_sending(struct bfa_fcs_rport_s *rport, +static void bfa_fcs_rport_sm_plogi_sending(struct bfa_fcs_rport_s *rport, + enum rport_event event); +static void bfa_fcs_rport_sm_plogiacc_sending(struct bfa_fcs_rport_s *rport, enum rport_event event); -static void bfa_fcs_rport_sm_plogi_retry(struct bfa_fcs_rport_s *rport, - enum rport_event event); -static void bfa_fcs_rport_sm_plogi(struct bfa_fcs_rport_s *rport, - enum rport_event event); -static void bfa_fcs_rport_sm_hal_online(struct bfa_fcs_rport_s *rport, - enum rport_event event); -static void bfa_fcs_rport_sm_online(struct bfa_fcs_rport_s *rport, +static void bfa_fcs_rport_sm_plogi_retry(struct bfa_fcs_rport_s *rport, + enum rport_event event); +static void bfa_fcs_rport_sm_plogi(struct bfa_fcs_rport_s *rport, enum rport_event event); -static void bfa_fcs_rport_sm_nsquery_sending(struct bfa_fcs_rport_s *rport, +static void bfa_fcs_rport_sm_hal_online(struct bfa_fcs_rport_s *rport, + enum rport_event event); +static void bfa_fcs_rport_sm_online(struct bfa_fcs_rport_s *rport, + enum rport_event event); +static void bfa_fcs_rport_sm_nsquery_sending(struct bfa_fcs_rport_s *rport, enum rport_event event); -static void bfa_fcs_rport_sm_nsquery(struct bfa_fcs_rport_s *rport, +static void bfa_fcs_rport_sm_nsquery(struct bfa_fcs_rport_s *rport, enum rport_event event); -static void bfa_fcs_rport_sm_adisc_sending(struct bfa_fcs_rport_s *rport, - enum rport_event event); -static void bfa_fcs_rport_sm_adisc(struct bfa_fcs_rport_s *rport, - enum rport_event event); -static void bfa_fcs_rport_sm_fc4_logorcv(struct bfa_fcs_rport_s *rport, - enum rport_event event); -static void bfa_fcs_rport_sm_fc4_logosend(struct bfa_fcs_rport_s *rport, - enum rport_event event); -static void bfa_fcs_rport_sm_fc4_offline(struct bfa_fcs_rport_s *rport, - enum rport_event event); -static void bfa_fcs_rport_sm_hcb_offline(struct bfa_fcs_rport_s *rport, - enum rport_event event); -static void bfa_fcs_rport_sm_hcb_logorcv(struct bfa_fcs_rport_s *rport, - enum rport_event event); -static void bfa_fcs_rport_sm_hcb_logosend(struct bfa_fcs_rport_s *rport, - enum rport_event event); -static void bfa_fcs_rport_sm_logo_sending(struct bfa_fcs_rport_s *rport, - enum rport_event event); -static void bfa_fcs_rport_sm_offline(struct bfa_fcs_rport_s *rport, +static void bfa_fcs_rport_sm_adisc_sending(struct bfa_fcs_rport_s *rport, + enum rport_event event); +static void bfa_fcs_rport_sm_adisc(struct bfa_fcs_rport_s *rport, + enum rport_event event); +static void bfa_fcs_rport_sm_fc4_logorcv(struct bfa_fcs_rport_s *rport, + enum rport_event event); +static void bfa_fcs_rport_sm_fc4_logosend(struct bfa_fcs_rport_s *rport, + enum rport_event event); +static void bfa_fcs_rport_sm_fc4_offline(struct bfa_fcs_rport_s *rport, + enum rport_event event); +static void bfa_fcs_rport_sm_hcb_offline(struct bfa_fcs_rport_s *rport, + enum rport_event event); +static void bfa_fcs_rport_sm_hcb_logorcv(struct bfa_fcs_rport_s *rport, + enum rport_event event); +static void bfa_fcs_rport_sm_hcb_logosend(struct bfa_fcs_rport_s *rport, + enum rport_event event); +static void bfa_fcs_rport_sm_logo_sending(struct bfa_fcs_rport_s *rport, + enum rport_event event); +static void bfa_fcs_rport_sm_offline(struct bfa_fcs_rport_s *rport, enum rport_event event); -static void bfa_fcs_rport_sm_nsdisc_sending(struct bfa_fcs_rport_s *rport, +static void bfa_fcs_rport_sm_nsdisc_sending(struct bfa_fcs_rport_s *rport, + enum rport_event event); +static void bfa_fcs_rport_sm_nsdisc_retry(struct bfa_fcs_rport_s *rport, + enum rport_event event); +static void bfa_fcs_rport_sm_nsdisc_sent(struct bfa_fcs_rport_s *rport, + enum rport_event event); +static void bfa_fcs_rport_sm_nsdisc_sent(struct bfa_fcs_rport_s *rport, enum rport_event event); -static void bfa_fcs_rport_sm_nsdisc_retry(struct bfa_fcs_rport_s *rport, - enum rport_event event); -static void bfa_fcs_rport_sm_nsdisc_sent(struct bfa_fcs_rport_s *rport, - enum rport_event event); -static void bfa_fcs_rport_sm_nsdisc_sent(struct bfa_fcs_rport_s *rport, - enum rport_event event); static struct bfa_sm_table_s rport_sm_table[] = { {BFA_SM(bfa_fcs_rport_sm_uninit), BFA_RPORT_UNINIT}, @@ -191,7 +173,7 @@ static struct bfa_sm_table_s rport_sm_table[] = { }; /** - * Beginning state. + * Beginning state. */ static void bfa_fcs_rport_sm_uninit(struct bfa_fcs_rport_s *rport, enum rport_event event) @@ -221,20 +203,19 @@ bfa_fcs_rport_sm_uninit(struct bfa_fcs_rport_s *rport, enum rport_event event) case RPSM_EVENT_ADDRESS_DISC: bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsdisc_sending); rport->ns_retries = 0; - bfa_fcs_rport_send_gidpn(rport, NULL); + bfa_fcs_rport_send_nsdisc(rport, NULL); break; - default: bfa_sm_fault(rport->fcs, event); } } /** - * PLOGI is being sent. + * PLOGI is being sent. */ static void bfa_fcs_rport_sm_plogi_sending(struct bfa_fcs_rport_s *rport, - enum rport_event event) + enum rport_event event) { bfa_trc(rport->fcs, rport->pwwn); bfa_trc(rport->fcs, rport->pid); @@ -258,10 +239,12 @@ bfa_fcs_rport_sm_plogi_sending(struct bfa_fcs_rport_s *rport, break; case RPSM_EVENT_ADDRESS_CHANGE: + case RPSM_EVENT_SCN: + /* query the NS */ bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe); bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsdisc_sending); rport->ns_retries = 0; - bfa_fcs_rport_send_gidpn(rport, NULL); + bfa_fcs_rport_send_nsdisc(rport, NULL); break; case RPSM_EVENT_LOGO_IMP: @@ -273,8 +256,6 @@ bfa_fcs_rport_sm_plogi_sending(struct bfa_fcs_rport_s *rport, bfa_fcs_rport_del_timeout); break; - case RPSM_EVENT_SCN: - break; default: bfa_sm_fault(rport->fcs, event); @@ -282,11 +263,11 @@ bfa_fcs_rport_sm_plogi_sending(struct bfa_fcs_rport_s *rport, } /** - * PLOGI is being sent. + * PLOGI is being sent. */ static void bfa_fcs_rport_sm_plogiacc_sending(struct bfa_fcs_rport_s *rport, - enum rport_event event) + enum rport_event event) { bfa_trc(rport->fcs, rport->pwwn); bfa_trc(rport->fcs, rport->pid); @@ -304,6 +285,7 @@ bfa_fcs_rport_sm_plogiacc_sending(struct bfa_fcs_rport_s *rport, bfa_fcs_rport_free(rport); break; + case RPSM_EVENT_PLOGI_RCVD: case RPSM_EVENT_SCN: /** * Ignore, SCN is possibly online notification. @@ -314,7 +296,7 @@ bfa_fcs_rport_sm_plogiacc_sending(struct bfa_fcs_rport_s *rport, bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe); bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsdisc_sending); rport->ns_retries = 0; - bfa_fcs_rport_send_gidpn(rport, NULL); + bfa_fcs_rport_send_nsdisc(rport, NULL); break; case RPSM_EVENT_LOGO_IMP: @@ -338,7 +320,7 @@ bfa_fcs_rport_sm_plogiacc_sending(struct bfa_fcs_rport_s *rport, } /** - * PLOGI is sent. + * PLOGI is sent. */ static void bfa_fcs_rport_sm_plogi_retry(struct bfa_fcs_rport_s *rport, @@ -349,24 +331,9 @@ bfa_fcs_rport_sm_plogi_retry(struct bfa_fcs_rport_s *rport, bfa_trc(rport->fcs, event); switch (event) { - case RPSM_EVENT_SCN: - bfa_timer_stop(&rport->timer); - /* - * !! fall through !! - */ - case RPSM_EVENT_TIMEOUT: - 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 { - rport->pid = 0; - bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline); - bfa_timer_start(rport->fcs->bfa, &rport->timer, - bfa_fcs_rport_timeout, rport, - bfa_fcs_rport_del_timeout); - } + bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogi_sending); + bfa_fcs_rport_send_plogi(rport, NULL); break; case RPSM_EVENT_DELETE: @@ -386,10 +353,11 @@ bfa_fcs_rport_sm_plogi_retry(struct bfa_fcs_rport_s *rport, break; case RPSM_EVENT_ADDRESS_CHANGE: + case RPSM_EVENT_SCN: bfa_timer_stop(&rport->timer); bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsdisc_sending); rport->ns_retries = 0; - bfa_fcs_rport_send_gidpn(rport, NULL); + bfa_fcs_rport_send_nsdisc(rport, NULL); break; case RPSM_EVENT_LOGO_IMP: @@ -413,7 +381,7 @@ bfa_fcs_rport_sm_plogi_retry(struct bfa_fcs_rport_s *rport, } /** - * PLOGI is sent. + * PLOGI is sent. */ static void bfa_fcs_rport_sm_plogi(struct bfa_fcs_rport_s *rport, enum rport_event event) @@ -443,10 +411,28 @@ bfa_fcs_rport_sm_plogi(struct bfa_fcs_rport_s *rport, enum rport_event event) * !! fall through !! */ case RPSM_EVENT_FAILED: + if (rport->plogi_retries < BFA_FCS_RPORT_MAX_RETRIES) { + rport->plogi_retries++; + bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogi_retry); + bfa_timer_start(rport->fcs->bfa, &rport->timer, + bfa_fcs_rport_timeout, rport, + BFA_FCS_RETRY_TIMEOUT); + } else { + bfa_stats(rport->port, rport_del_max_plogi_retry); + rport->pid = 0; + bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline); + bfa_timer_start(rport->fcs->bfa, &rport->timer, + bfa_fcs_rport_timeout, rport, + bfa_fcs_rport_del_timeout); + } + break; + + case RPSM_EVENT_PLOGI_RETRY: + rport->plogi_retries = 0; bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogi_retry); bfa_timer_start(rport->fcs->bfa, &rport->timer, bfa_fcs_rport_timeout, rport, - BFA_FCS_RETRY_TIMEOUT); + (FC_RA_TOV * 1000)); break; case RPSM_EVENT_LOGO_IMP: @@ -459,10 +445,11 @@ bfa_fcs_rport_sm_plogi(struct bfa_fcs_rport_s *rport, enum rport_event event) break; case RPSM_EVENT_ADDRESS_CHANGE: + case RPSM_EVENT_SCN: bfa_fcxp_discard(rport->fcxp); bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsdisc_sending); rport->ns_retries = 0; - bfa_fcs_rport_send_gidpn(rport, NULL); + bfa_fcs_rport_send_nsdisc(rport, NULL); break; case RPSM_EVENT_PLOGI_RCVD: @@ -471,12 +458,6 @@ bfa_fcs_rport_sm_plogi(struct bfa_fcs_rport_s *rport, enum rport_event event) bfa_fcs_rport_send_plogiacc(rport, NULL); break; - case RPSM_EVENT_SCN: - /** - * Ignore SCN - wait for PLOGI response. - */ - break; - case RPSM_EVENT_DELETE: bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit); bfa_fcxp_discard(rport->fcxp); @@ -495,8 +476,8 @@ bfa_fcs_rport_sm_plogi(struct bfa_fcs_rport_s *rport, enum rport_event event) } /** - * PLOGI is complete. Awaiting BFA rport online callback. FC-4s - * are offline. + * PLOGI is complete. Awaiting BFA rport online callback. FC-4s + * are offline. */ static void bfa_fcs_rport_sm_hal_online(struct bfa_fcs_rport_s *rport, @@ -551,7 +532,7 @@ bfa_fcs_rport_sm_hal_online(struct bfa_fcs_rport_s *rport, } /** - * Rport is ONLINE. FC-4s active. + * Rport is ONLINE. FC-4s active. */ static void bfa_fcs_rport_sm_online(struct bfa_fcs_rport_s *rport, enum rport_event event) @@ -562,18 +543,11 @@ bfa_fcs_rport_sm_online(struct bfa_fcs_rport_s *rport, enum rport_event event) switch (event) { case RPSM_EVENT_SCN: - /** - * Pause FC-4 activity till rport is authenticated. - * In switched fabrics, check presence of device in nameserver - * first. - */ - bfa_fcs_rport_fc4_pause(rport); - if (bfa_fcs_fabric_is_switched(rport->port->fabric)) { bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsquery_sending); rport->ns_retries = 0; - bfa_fcs_rport_send_gidpn(rport, NULL); + bfa_fcs_rport_send_nsdisc(rport, NULL); } else { bfa_sm_set_state(rport, bfa_fcs_rport_sm_adisc_sending); bfa_fcs_rport_send_adisc(rport, NULL); @@ -607,12 +581,12 @@ bfa_fcs_rport_sm_online(struct bfa_fcs_rport_s *rport, enum rport_event event) } /** - * An SCN event is received in ONLINE state. NS query is being sent - * prior to ADISC authentication with rport. FC-4s are paused. + * An SCN event is received in ONLINE state. NS query is being sent + * prior to ADISC authentication with rport. FC-4s are paused. */ static void bfa_fcs_rport_sm_nsquery_sending(struct bfa_fcs_rport_s *rport, - enum rport_event event) + enum rport_event event) { bfa_trc(rport->fcs, rport->pwwn); bfa_trc(rport->fcs, rport->pid); @@ -665,8 +639,8 @@ bfa_fcs_rport_sm_nsquery_sending(struct bfa_fcs_rport_s *rport, } /** - * An SCN event is received in ONLINE state. NS query is sent to rport. - * FC-4s are paused. + * An SCN event is received in ONLINE state. NS query is sent to rport. + * FC-4s are paused. */ static void bfa_fcs_rport_sm_nsquery(struct bfa_fcs_rport_s *rport, enum rport_event event) @@ -686,7 +660,7 @@ bfa_fcs_rport_sm_nsquery(struct bfa_fcs_rport_s *rport, enum rport_event event) if (rport->ns_retries < BFA_FCS_RPORT_MAX_RETRIES) { bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsquery_sending); - bfa_fcs_rport_send_gidpn(rport, NULL); + bfa_fcs_rport_send_nsdisc(rport, NULL); } else { bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_offline); bfa_fcs_rport_offline_action(rport); @@ -724,12 +698,12 @@ bfa_fcs_rport_sm_nsquery(struct bfa_fcs_rport_s *rport, enum rport_event event) } /** - * An SCN event is received in ONLINE state. ADISC is being sent for - * authenticating with rport. FC-4s are paused. + * An SCN event is received in ONLINE state. ADISC is being sent for + * authenticating with rport. FC-4s are paused. */ static void bfa_fcs_rport_sm_adisc_sending(struct bfa_fcs_rport_s *rport, - enum rport_event event) + enum rport_event event) { bfa_trc(rport->fcs, rport->pwwn); bfa_trc(rport->fcs, rport->pid); @@ -775,8 +749,8 @@ bfa_fcs_rport_sm_adisc_sending(struct bfa_fcs_rport_s *rport, } /** - * An SCN event is received in ONLINE state. ADISC is to rport. - * FC-4s are paused. + * An SCN event is received in ONLINE state. ADISC is to rport. + * FC-4s are paused. */ static void bfa_fcs_rport_sm_adisc(struct bfa_fcs_rport_s *rport, enum rport_event event) @@ -788,7 +762,6 @@ bfa_fcs_rport_sm_adisc(struct bfa_fcs_rport_s *rport, enum rport_event event) switch (event) { case RPSM_EVENT_ACCEPTED: bfa_sm_set_state(rport, bfa_fcs_rport_sm_online); - bfa_fcs_rport_fc4_resume(rport); break; case RPSM_EVENT_PLOGI_RCVD: @@ -838,7 +811,7 @@ bfa_fcs_rport_sm_adisc(struct bfa_fcs_rport_s *rport, enum rport_event event) } /** - * Rport has sent LOGO. Awaiting FC-4 offline completion callback. + * Rport has sent LOGO. Awaiting FC-4 offline completion callback. */ static void bfa_fcs_rport_sm_fc4_logorcv(struct bfa_fcs_rport_s *rport, @@ -869,12 +842,12 @@ bfa_fcs_rport_sm_fc4_logorcv(struct bfa_fcs_rport_s *rport, } /** - * LOGO needs to be sent to rport. Awaiting FC-4 offline completion - * callback. + * LOGO needs to be sent to rport. Awaiting FC-4 offline completion + * callback. */ static void bfa_fcs_rport_sm_fc4_logosend(struct bfa_fcs_rport_s *rport, - enum rport_event event) + enum rport_event event) { bfa_trc(rport->fcs, rport->pwwn); bfa_trc(rport->fcs, rport->pid); @@ -892,7 +865,7 @@ bfa_fcs_rport_sm_fc4_logosend(struct bfa_fcs_rport_s *rport, } /** - * Rport is going offline. Awaiting FC-4 offline completion callback. + * Rport is going offline. Awaiting FC-4 offline completion callback. */ static void bfa_fcs_rport_sm_fc4_offline(struct bfa_fcs_rport_s *rport, @@ -929,12 +902,12 @@ bfa_fcs_rport_sm_fc4_offline(struct bfa_fcs_rport_s *rport, } /** - * Rport is offline. FC-4s are offline. Awaiting BFA rport offline - * callback. + * Rport is offline. FC-4s are offline. Awaiting BFA rport offline + * callback. */ static void bfa_fcs_rport_sm_hcb_offline(struct bfa_fcs_rport_s *rport, - enum rport_event event) + enum rport_event event) { bfa_trc(rport->fcs, rport->pwwn); bfa_trc(rport->fcs, rport->pid); @@ -943,12 +916,12 @@ bfa_fcs_rport_sm_hcb_offline(struct bfa_fcs_rport_s *rport, switch (event) { case RPSM_EVENT_HCB_OFFLINE: case RPSM_EVENT_ADDRESS_CHANGE: - if (bfa_fcs_port_is_online(rport->port)) { + if (bfa_fcs_lport_is_online(rport->port)) { if (bfa_fcs_fabric_is_switched(rport->port->fabric)) { bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsdisc_sending); rport->ns_retries = 0; - bfa_fcs_rport_send_gidpn(rport, NULL); + bfa_fcs_rport_send_nsdisc(rport, NULL); } else { bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogi_sending); @@ -983,8 +956,8 @@ bfa_fcs_rport_sm_hcb_offline(struct bfa_fcs_rport_s *rport, } /** - * Rport is offline. FC-4s are offline. Awaiting BFA rport offline - * callback to send LOGO accept. + * Rport is offline. FC-4s are offline. Awaiting BFA rport offline + * callback to send LOGO accept. */ static void bfa_fcs_rport_sm_hcb_logorcv(struct bfa_fcs_rport_s *rport, @@ -1001,21 +974,21 @@ bfa_fcs_rport_sm_hcb_logorcv(struct bfa_fcs_rport_s *rport, 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. + * If the lport is online and if the rport is not a well + * known address port, + * we try to re-discover the r-port. */ - if (bfa_fcs_port_is_online(rport->port) - && (!BFA_FCS_PID_IS_WKA(rport->pid))) { + if (bfa_fcs_lport_is_online(rport->port) && + (!BFA_FCS_PID_IS_WKA(rport->pid))) { bfa_sm_set_state(rport, - bfa_fcs_rport_sm_nsdisc_sending); + bfa_fcs_rport_sm_nsdisc_sending); rport->ns_retries = 0; - bfa_fcs_rport_send_gidpn(rport, NULL); + bfa_fcs_rport_send_nsdisc(rport, NULL); } else { /* - * if it is not a well known address, reset the pid to - * + * if it is not a well known address, reset the + * pid to 0. */ if (!BFA_FCS_PID_IS_WKA(rport->pid)) rport->pid = 0; @@ -1047,12 +1020,13 @@ bfa_fcs_rport_sm_hcb_logorcv(struct bfa_fcs_rport_s *rport, } /** - * Rport is being deleted. FC-4s are offline. Awaiting BFA rport offline - * callback to send LOGO. + * Rport is being deleted. FC-4s are offline. + * Awaiting BFA rport offline + * callback to send LOGO. */ static void bfa_fcs_rport_sm_hcb_logosend(struct bfa_fcs_rport_s *rport, - enum rport_event event) + enum rport_event event) { bfa_trc(rport->fcs, rport->pwwn); bfa_trc(rport->fcs, rport->pid); @@ -1075,11 +1049,11 @@ bfa_fcs_rport_sm_hcb_logosend(struct bfa_fcs_rport_s *rport, } /** - * Rport is being deleted. FC-4s are offline. LOGO is being sent. + * Rport is being deleted. FC-4s are offline. LOGO is being sent. */ static void bfa_fcs_rport_sm_logo_sending(struct bfa_fcs_rport_s *rport, - enum rport_event event) + enum rport_event event) { bfa_trc(rport->fcs, rport->pwwn); bfa_trc(rport->fcs, rport->pid); @@ -1087,9 +1061,7 @@ bfa_fcs_rport_sm_logo_sending(struct bfa_fcs_rport_s *rport, switch (event) { case RPSM_EVENT_FCXP_SENT: - /* - * Once LOGO is sent, we donot wait for the response - */ + /* Once LOGO is sent, we donot wait for the response */ bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit); bfa_fcs_rport_free(rport); break; @@ -1111,8 +1083,8 @@ bfa_fcs_rport_sm_logo_sending(struct bfa_fcs_rport_s *rport, } /** - * Rport is offline. FC-4s are offline. BFA rport is offline. - * Timer active to delete stale rport. + * Rport is offline. FC-4s are offline. BFA rport is offline. + * Timer active to delete stale rport. */ static void bfa_fcs_rport_sm_offline(struct bfa_fcs_rport_s *rport, enum rport_event event) @@ -1132,7 +1104,7 @@ bfa_fcs_rport_sm_offline(struct bfa_fcs_rport_s *rport, enum rport_event event) bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsdisc_sending); bfa_timer_stop(&rport->timer); rport->ns_retries = 0; - bfa_fcs_rport_send_gidpn(rport, NULL); + bfa_fcs_rport_send_nsdisc(rport, NULL); break; case RPSM_EVENT_DELETE: @@ -1171,11 +1143,11 @@ bfa_fcs_rport_sm_offline(struct bfa_fcs_rport_s *rport, enum rport_event event) } /** - * Rport address has changed. Nameserver discovery request is being sent. + * Rport address has changed. Nameserver discovery request is being sent. */ static void bfa_fcs_rport_sm_nsdisc_sending(struct bfa_fcs_rport_s *rport, - enum rport_event event) + enum rport_event event) { bfa_trc(rport->fcs, rport->pwwn); bfa_trc(rport->fcs, rport->pid); @@ -1205,7 +1177,7 @@ bfa_fcs_rport_sm_nsdisc_sending(struct bfa_fcs_rport_s *rport, break; case RPSM_EVENT_ADDRESS_CHANGE: - rport->ns_retries = 0; /* reset the retry count */ + rport->ns_retries = 0; /* reset the retry count */ break; case RPSM_EVENT_LOGO_IMP: @@ -1228,11 +1200,11 @@ bfa_fcs_rport_sm_nsdisc_sending(struct bfa_fcs_rport_s *rport, } /** - * Nameserver discovery failed. Waiting for timeout to retry. + * Nameserver discovery failed. Waiting for timeout to retry. */ static void bfa_fcs_rport_sm_nsdisc_retry(struct bfa_fcs_rport_s *rport, - enum rport_event event) + enum rport_event event) { bfa_trc(rport->fcs, rport->pwwn); bfa_trc(rport->fcs, rport->pid); @@ -1241,7 +1213,7 @@ bfa_fcs_rport_sm_nsdisc_retry(struct bfa_fcs_rport_s *rport, switch (event) { case RPSM_EVENT_TIMEOUT: bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsdisc_sending); - bfa_fcs_rport_send_gidpn(rport, NULL); + bfa_fcs_rport_send_nsdisc(rport, NULL); break; case RPSM_EVENT_SCN: @@ -1249,7 +1221,7 @@ bfa_fcs_rport_sm_nsdisc_retry(struct bfa_fcs_rport_s *rport, bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsdisc_sending); bfa_timer_stop(&rport->timer); rport->ns_retries = 0; - bfa_fcs_rport_send_gidpn(rport, NULL); + bfa_fcs_rport_send_nsdisc(rport, NULL); break; case RPSM_EVENT_DELETE: @@ -1276,7 +1248,6 @@ bfa_fcs_rport_sm_nsdisc_retry(struct bfa_fcs_rport_s *rport, case RPSM_EVENT_LOGO_RCVD: bfa_fcs_rport_send_logo_acc(rport); break; - case RPSM_EVENT_PRLO_RCVD: bfa_fcs_rport_send_prlo_acc(rport); break; @@ -1293,7 +1264,7 @@ bfa_fcs_rport_sm_nsdisc_retry(struct bfa_fcs_rport_s *rport, } /** - * Rport address has changed. Nameserver discovery request is sent. + * Rport address has changed. Nameserver discovery request is sent. */ static void bfa_fcs_rport_sm_nsdisc_sent(struct bfa_fcs_rport_s *rport, @@ -1311,9 +1282,9 @@ bfa_fcs_rport_sm_nsdisc_sent(struct bfa_fcs_rport_s *rport, bfa_fcs_rport_send_plogi(rport, NULL); } else { bfa_sm_set_state(rport, - bfa_fcs_rport_sm_nsdisc_sending); + bfa_fcs_rport_sm_nsdisc_sending); rport->ns_retries = 0; - bfa_fcs_rport_send_gidpn(rport, NULL); + bfa_fcs_rport_send_nsdisc(rport, NULL); } break; @@ -1321,8 +1292,8 @@ bfa_fcs_rport_sm_nsdisc_sent(struct bfa_fcs_rport_s *rport, rport->ns_retries++; if (rport->ns_retries < BFA_FCS_RPORT_MAX_RETRIES) { bfa_sm_set_state(rport, - bfa_fcs_rport_sm_nsdisc_sending); - bfa_fcs_rport_send_gidpn(rport, NULL); + bfa_fcs_rport_sm_nsdisc_sending); + bfa_fcs_rport_send_nsdisc(rport, NULL); } else { rport->pid = 0; bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline); @@ -1353,10 +1324,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 @@ -1391,29 +1362,29 @@ static void bfa_fcs_rport_send_plogi(void *rport_cbarg, struct bfa_fcxp_s *fcxp_alloced) { struct bfa_fcs_rport_s *rport = rport_cbarg; - struct bfa_fcs_port_s *port = rport->port; - struct fchs_s fchs; - int len; + struct bfa_fcs_lport_s *port = rport->port; + struct fchs_s fchs; + int len; struct bfa_fcxp_s *fcxp; bfa_trc(rport->fcs, rport->pwwn); fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); if (!fcxp) { - bfa_fcxp_alloc_wait(port->fcs->bfa, &rport->fcxp_wqe, - bfa_fcs_rport_send_plogi, rport); + bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &rport->fcxp_wqe, + bfa_fcs_rport_send_plogi, rport); return; } rport->fcxp = fcxp; len = fc_plogi_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rport->pid, - bfa_fcs_port_get_fcid(port), 0, - port->port_cfg.pwwn, port->port_cfg.nwwn, - bfa_fcport_get_maxfrsize(port->fcs->bfa)); + bfa_fcs_lport_get_fcid(port), 0, + port->port_cfg.pwwn, port->port_cfg.nwwn, + bfa_fcport_get_maxfrsize(port->fcs->bfa)); bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, - FC_CLASS_3, len, &fchs, bfa_fcs_rport_plogi_response, - (void *)rport, FC_MAX_PDUSZ, FC_ELS_TOV); + FC_CLASS_3, len, &fchs, bfa_fcs_rport_plogi_response, + (void *)rport, FC_MAX_PDUSZ, FC_ELS_TOV); rport->stats.plogis++; bfa_sm_send_event(rport, RPSM_EVENT_FCXP_SENT); @@ -1421,14 +1392,14 @@ bfa_fcs_rport_send_plogi(void *rport_cbarg, struct bfa_fcxp_s *fcxp_alloced) static void bfa_fcs_rport_plogi_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg, - bfa_status_t req_status, u32 rsp_len, - u32 resid_len, struct fchs_s *rsp_fchs) + bfa_status_t req_status, u32 rsp_len, + u32 resid_len, struct fchs_s *rsp_fchs) { - struct bfa_fcs_rport_s *rport = (struct bfa_fcs_rport_s *)cbarg; + struct bfa_fcs_rport_s *rport = (struct bfa_fcs_rport_s *) cbarg; struct fc_logi_s *plogi_rsp; struct fc_ls_rjt_s *ls_rjt; struct bfa_fcs_rport_s *twin; - struct list_head *qe; + struct list_head *qe; bfa_trc(rport->fcs, rport->pwwn); @@ -1453,6 +1424,13 @@ bfa_fcs_rport_plogi_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg, bfa_trc(rport->fcs, ls_rjt->reason_code); bfa_trc(rport->fcs, ls_rjt->reason_code_expl); + if ((ls_rjt->reason_code == FC_LS_RJT_RSN_UNABLE_TO_PERF_CMD) && + (ls_rjt->reason_code_expl == FC_LS_RJT_EXP_INSUFF_RES)) { + rport->stats.rjt_insuff_res++; + bfa_sm_send_event(rport, RPSM_EVENT_PLOGI_RETRY); + return; + } + rport->stats.plogi_rejects++; bfa_sm_send_event(rport, RPSM_EVENT_FAILED); return; @@ -1463,22 +1441,22 @@ bfa_fcs_rport_plogi_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg, * device with a new FC port address. */ list_for_each(qe, &rport->port->rport_q) { - twin = (struct bfa_fcs_rport_s *)qe; + twin = (struct bfa_fcs_rport_s *) qe; if (twin == rport) continue; if (!rport->pwwn && (plogi_rsp->port_name == twin->pwwn)) { bfa_trc(rport->fcs, twin->pid); bfa_trc(rport->fcs, rport->pid); - /* - * Update plogi stats in twin - */ - twin->stats.plogis += rport->stats.plogis; - twin->stats.plogi_rejects += rport->stats.plogi_rejects; - twin->stats.plogi_timeouts += - rport->stats.plogi_timeouts; - twin->stats.plogi_failed += rport->stats.plogi_failed; - twin->stats.plogi_rcvd += rport->stats.plogi_rcvd; + /* Update plogi stats in twin */ + twin->stats.plogis += rport->stats.plogis; + twin->stats.plogi_rejects += + rport->stats.plogi_rejects; + twin->stats.plogi_timeouts += + rport->stats.plogi_timeouts; + twin->stats.plogi_failed += + rport->stats.plogi_failed; + twin->stats.plogi_rcvd += rport->stats.plogi_rcvd; twin->stats.plogi_accs++; bfa_fcs_rport_delete(rport); @@ -1502,9 +1480,9 @@ static void bfa_fcs_rport_send_plogiacc(void *rport_cbarg, struct bfa_fcxp_s *fcxp_alloced) { struct bfa_fcs_rport_s *rport = rport_cbarg; - struct bfa_fcs_port_s *port = rport->port; - struct fchs_s fchs; - int len; + struct bfa_fcs_lport_s *port = rport->port; + struct fchs_s fchs; + int len; struct bfa_fcxp_s *fcxp; bfa_trc(rport->fcs, rport->pwwn); @@ -1512,19 +1490,20 @@ bfa_fcs_rport_send_plogiacc(void *rport_cbarg, struct bfa_fcxp_s *fcxp_alloced) fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); if (!fcxp) { - bfa_fcxp_alloc_wait(port->fcs->bfa, &rport->fcxp_wqe, - bfa_fcs_rport_send_plogiacc, rport); + bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &rport->fcxp_wqe, + bfa_fcs_rport_send_plogiacc, rport); return; } rport->fcxp = fcxp; - len = fc_plogi_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rport->pid, - bfa_fcs_port_get_fcid(port), rport->reply_oxid, - port->port_cfg.pwwn, port->port_cfg.nwwn, + len = fc_plogi_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), + rport->pid, bfa_fcs_lport_get_fcid(port), + rport->reply_oxid, port->port_cfg.pwwn, + port->port_cfg.nwwn, bfa_fcport_get_maxfrsize(port->fcs->bfa)); bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, - FC_CLASS_3, len, &fchs, NULL, NULL, FC_MAX_PDUSZ, 0); + FC_CLASS_3, len, &fchs, NULL, NULL, FC_MAX_PDUSZ, 0); bfa_sm_send_event(rport, RPSM_EVENT_FCXP_SENT); } @@ -1533,28 +1512,28 @@ static void bfa_fcs_rport_send_adisc(void *rport_cbarg, struct bfa_fcxp_s *fcxp_alloced) { struct bfa_fcs_rport_s *rport = rport_cbarg; - struct bfa_fcs_port_s *port = rport->port; - struct fchs_s fchs; - int len; + struct bfa_fcs_lport_s *port = rport->port; + struct fchs_s fchs; + int len; struct bfa_fcxp_s *fcxp; bfa_trc(rport->fcs, rport->pwwn); fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); if (!fcxp) { - bfa_fcxp_alloc_wait(port->fcs->bfa, &rport->fcxp_wqe, - bfa_fcs_rport_send_adisc, rport); + bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &rport->fcxp_wqe, + bfa_fcs_rport_send_adisc, rport); return; } rport->fcxp = fcxp; len = fc_adisc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rport->pid, - bfa_fcs_port_get_fcid(port), 0, - port->port_cfg.pwwn, port->port_cfg.nwwn); + bfa_fcs_lport_get_fcid(port), 0, + port->port_cfg.pwwn, port->port_cfg.nwwn); bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, - FC_CLASS_3, len, &fchs, bfa_fcs_rport_adisc_response, - rport, FC_MAX_PDUSZ, FC_ELS_TOV); + FC_CLASS_3, len, &fchs, bfa_fcs_rport_adisc_response, + rport, FC_MAX_PDUSZ, FC_ELS_TOV); rport->stats.adisc_sent++; bfa_sm_send_event(rport, RPSM_EVENT_FCXP_SENT); @@ -1562,12 +1541,12 @@ bfa_fcs_rport_send_adisc(void *rport_cbarg, struct bfa_fcxp_s *fcxp_alloced) static void bfa_fcs_rport_adisc_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg, - bfa_status_t req_status, u32 rsp_len, - u32 resid_len, struct fchs_s *rsp_fchs) + bfa_status_t req_status, u32 rsp_len, + u32 resid_len, struct fchs_s *rsp_fchs) { - struct bfa_fcs_rport_s *rport = (struct bfa_fcs_rport_s *)cbarg; - void *pld = bfa_fcxp_get_rspbuf(fcxp); - struct fc_ls_rjt_s *ls_rjt; + struct bfa_fcs_rport_s *rport = (struct bfa_fcs_rport_s *) cbarg; + void *pld = bfa_fcxp_get_rspbuf(fcxp); + struct fc_ls_rjt_s *ls_rjt; if (req_status != BFA_STATUS_OK) { bfa_trc(rport->fcs, req_status); @@ -1577,7 +1556,7 @@ bfa_fcs_rport_adisc_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg, } if (fc_adisc_rsp_parse((struct fc_adisc_s *)pld, rsp_len, rport->pwwn, - rport->nwwn) == FC_PARSE_OK) { + rport->nwwn) == FC_PARSE_OK) { rport->stats.adisc_accs++; bfa_sm_send_event(rport, RPSM_EVENT_ACCEPTED); return; @@ -1592,44 +1571,52 @@ bfa_fcs_rport_adisc_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg, } static void -bfa_fcs_rport_send_gidpn(void *rport_cbarg, struct bfa_fcxp_s *fcxp_alloced) +bfa_fcs_rport_send_nsdisc(void *rport_cbarg, struct bfa_fcxp_s *fcxp_alloced) { struct bfa_fcs_rport_s *rport = rport_cbarg; - struct bfa_fcs_port_s *port = rport->port; - struct fchs_s fchs; + struct bfa_fcs_lport_s *port = rport->port; + struct fchs_s fchs; struct bfa_fcxp_s *fcxp; - int len; + int len; + bfa_cb_fcxp_send_t cbfn; bfa_trc(rport->fcs, rport->pid); fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); if (!fcxp) { - bfa_fcxp_alloc_wait(port->fcs->bfa, &rport->fcxp_wqe, - bfa_fcs_rport_send_gidpn, rport); + bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &rport->fcxp_wqe, + bfa_fcs_rport_send_nsdisc, rport); return; } rport->fcxp = fcxp; - len = fc_gidpn_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), - bfa_fcs_port_get_fcid(port), 0, rport->pwwn); + if (rport->pwwn) { + len = fc_gidpn_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), + bfa_fcs_lport_get_fcid(port), 0, rport->pwwn); + cbfn = bfa_fcs_rport_gidpn_response; + } else { + len = fc_gpnid_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), + bfa_fcs_lport_get_fcid(port), 0, rport->pid); + cbfn = bfa_fcs_rport_gpnid_response; + } 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_FCCT_TOV); + FC_CLASS_3, len, &fchs, cbfn, + (void *)rport, FC_MAX_PDUSZ, FC_FCCT_TOV); bfa_sm_send_event(rport, RPSM_EVENT_FCXP_SENT); } static void bfa_fcs_rport_gidpn_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg, - bfa_status_t req_status, u32 rsp_len, - u32 resid_len, struct fchs_s *rsp_fchs) + bfa_status_t req_status, u32 rsp_len, + u32 resid_len, struct fchs_s *rsp_fchs) { - struct bfa_fcs_rport_s *rport = (struct bfa_fcs_rport_s *)cbarg; - struct bfa_fcs_rport_s *twin; - struct list_head *qe; - struct ct_hdr_s *cthdr; + struct bfa_fcs_rport_s *rport = (struct bfa_fcs_rport_s *) cbarg; + struct ct_hdr_s *cthdr; struct fcgs_gidpn_resp_s *gidpn_rsp; + struct bfa_fcs_rport_s *twin; + struct list_head *qe; bfa_trc(rport->fcs, rport->pwwn); @@ -1637,25 +1624,21 @@ bfa_fcs_rport_gidpn_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg, cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code); if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) { - /* - * Check if the pid is the same as before. - */ + /* Check if the pid is the same as before. */ gidpn_rsp = (struct fcgs_gidpn_resp_s *) (cthdr + 1); if (gidpn_rsp->dap == rport->pid) { - /* - * Device is online - */ + /* Device is online */ bfa_sm_send_event(rport, RPSM_EVENT_ACCEPTED); } else { /* - * Device's PID has changed. We need to cleanup and - * re-login. If there is another device with the the - * newly discovered pid, send an scn notice so that its - * new pid can be discovered. + * Device's PID has changed. We need to cleanup + * and re-login. If there is another device with + * the the newly discovered pid, send an scn notice + * so that its new pid can be discovered. */ list_for_each(qe, &rport->port->rport_q) { - twin = (struct bfa_fcs_rport_s *)qe; + twin = (struct bfa_fcs_rport_s *) qe; if (twin == rport) continue; if (gidpn_rsp->dap == twin->pid) { @@ -1664,7 +1647,7 @@ bfa_fcs_rport_gidpn_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg, twin->pid = 0; bfa_sm_send_event(twin, - RPSM_EVENT_ADDRESS_CHANGE); + RPSM_EVENT_ADDRESS_CHANGE); } } rport->pid = gidpn_rsp->dap; @@ -1697,17 +1680,59 @@ bfa_fcs_rport_gidpn_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg, } } +static void +bfa_fcs_rport_gpnid_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg, + bfa_status_t req_status, u32 rsp_len, + u32 resid_len, struct fchs_s *rsp_fchs) +{ + struct bfa_fcs_rport_s *rport = (struct bfa_fcs_rport_s *) cbarg; + struct ct_hdr_s *cthdr; + + bfa_trc(rport->fcs, rport->pwwn); + + cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp); + cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code); + + if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) { + bfa_sm_send_event(rport, RPSM_EVENT_ACCEPTED); + return; + } + + /* + * Reject Response + */ + switch (cthdr->reason_code) { + case CT_RSN_LOGICAL_BUSY: + /* + * Need to retry + */ + bfa_sm_send_event(rport, RPSM_EVENT_TIMEOUT); + break; + + case CT_RSN_UNABLE_TO_PERF: + /* + * device doesn't exist : Start timer to cleanup this later. + */ + bfa_sm_send_event(rport, RPSM_EVENT_FAILED); + break; + + default: + bfa_sm_send_event(rport, RPSM_EVENT_FAILED); + break; + } +} + /** - * Called to send a logout to the rport. + * Called to send a logout to the rport. */ static void bfa_fcs_rport_send_logo(void *rport_cbarg, struct bfa_fcxp_s *fcxp_alloced) { struct bfa_fcs_rport_s *rport = rport_cbarg; - struct bfa_fcs_port_s *port; - struct fchs_s fchs; + struct bfa_fcs_lport_s *port; + struct fchs_s fchs; struct bfa_fcxp_s *fcxp; - u16 len; + u16 len; bfa_trc(rport->fcs, rport->pid); @@ -1715,19 +1740,19 @@ bfa_fcs_rport_send_logo(void *rport_cbarg, struct bfa_fcxp_s *fcxp_alloced) fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); if (!fcxp) { - bfa_fcxp_alloc_wait(port->fcs->bfa, &rport->fcxp_wqe, - bfa_fcs_rport_send_logo, rport); + bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &rport->fcxp_wqe, + bfa_fcs_rport_send_logo, rport); return; } rport->fcxp = fcxp; len = fc_logo_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rport->pid, - bfa_fcs_port_get_fcid(port), 0, - bfa_fcs_port_get_pwwn(port)); + bfa_fcs_lport_get_fcid(port), 0, + bfa_fcs_lport_get_pwwn(port)); bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, - FC_CLASS_3, len, &fchs, NULL, rport, FC_MAX_PDUSZ, - FC_ELS_TOV); + FC_CLASS_3, len, &fchs, NULL, + rport, FC_MAX_PDUSZ, FC_ELS_TOV); rport->stats.logos++; bfa_fcxp_discard(rport->fcxp); @@ -1735,16 +1760,16 @@ bfa_fcs_rport_send_logo(void *rport_cbarg, struct bfa_fcxp_s *fcxp_alloced) } /** - * Send ACC for a LOGO received. + * Send ACC for a LOGO received. */ static void bfa_fcs_rport_send_logo_acc(void *rport_cbarg) { struct bfa_fcs_rport_s *rport = rport_cbarg; - struct bfa_fcs_port_s *port; - struct fchs_s fchs; + struct bfa_fcs_lport_s *port; + struct fchs_s fchs; struct bfa_fcxp_s *fcxp; - u16 len; + u16 len; bfa_trc(rport->fcs, rport->pid); @@ -1755,32 +1780,35 @@ bfa_fcs_rport_send_logo_acc(void *rport_cbarg) return; rport->stats.logo_rcvd++; - len = fc_logo_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rport->pid, - bfa_fcs_port_get_fcid(port), rport->reply_oxid); + len = fc_logo_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), + rport->pid, bfa_fcs_lport_get_fcid(port), + rport->reply_oxid); bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, - FC_CLASS_3, len, &fchs, NULL, NULL, FC_MAX_PDUSZ, 0); + FC_CLASS_3, len, &fchs, NULL, NULL, FC_MAX_PDUSZ, 0); } /** - * This routine will be called by bfa_timer on timer timeouts. + * brief + * This routine will be called by bfa_timer on timer timeouts. * - * param[in] rport - pointer to bfa_fcs_port_ns_t. - * param[out] rport_status - pointer to return vport status in + * param[in] rport - pointer to bfa_fcs_lport_ns_t. + * param[out] rport_status - pointer to return vport status in * - * return - * void + * return + * void * -* Special Considerations: + * Special Considerations: * - * note + * note */ static void bfa_fcs_rport_timeout(void *arg) { - struct bfa_fcs_rport_s *rport = (struct bfa_fcs_rport_s *)arg; + struct bfa_fcs_rport_s *rport = (struct bfa_fcs_rport_s *) arg; rport->stats.plogi_timeouts++; + bfa_stats(rport->port, rport_plogi_timeouts); bfa_sm_send_event(rport, RPSM_EVENT_TIMEOUT); } @@ -1789,50 +1817,45 @@ bfa_fcs_rport_process_prli(struct bfa_fcs_rport_s *rport, struct fchs_s *rx_fchs, u16 len) { struct bfa_fcxp_s *fcxp; - struct fchs_s fchs; - struct bfa_fcs_port_s *port = rport->port; - struct fc_prli_s *prli; + struct fchs_s fchs; + struct bfa_fcs_lport_s *port = rport->port; + struct fc_prli_s *prli; bfa_trc(port->fcs, rx_fchs->s_id); bfa_trc(port->fcs, rx_fchs->d_id); rport->stats.prli_rcvd++; - if (BFA_FCS_VPORT_IS_TARGET_MODE(port)) { - /* - * Target Mode : Let the fcptm handle it - */ - bfa_fcs_tin_rx_prli(rport->tin, rx_fchs, len); - return; - } - /* - * We are either in Initiator or ipfc Mode + * We are in Initiator Mode */ prli = (struct fc_prli_s *) (rx_fchs + 1); - if (prli->parampage.servparams.initiator) { - bfa_trc(rport->fcs, prli->parampage.type); - rport->scsi_function = BFA_RPORT_INITIATOR; - bfa_fcs_itnim_is_initiator(rport->itnim); - } else { + if (prli->parampage.servparams.target) { /* - * @todo: PRLI from a target ? + * PRLI from a target ? + * Send the Acc. + * PRLI sent by us will be used to transition the IT nexus, + * once the response is received from the target. */ bfa_trc(port->fcs, rx_fchs->s_id); rport->scsi_function = BFA_RPORT_TARGET; + } else { + bfa_trc(rport->fcs, prli->parampage.type); + rport->scsi_function = BFA_RPORT_INITIATOR; + bfa_fcs_itnim_is_initiator(rport->itnim); } fcxp = bfa_fcs_fcxp_alloc(port->fcs); if (!fcxp) return; - len = fc_prli_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rx_fchs->s_id, - bfa_fcs_port_get_fcid(port), rx_fchs->ox_id, - port->port_cfg.roles); + len = fc_prli_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), + rx_fchs->s_id, bfa_fcs_lport_get_fcid(port), + rx_fchs->ox_id, port->port_cfg.roles); bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, - FC_CLASS_3, len, &fchs, NULL, NULL, FC_MAX_PDUSZ, 0); + FC_CLASS_3, len, &fchs, NULL, NULL, FC_MAX_PDUSZ, 0); } static void @@ -1840,10 +1863,10 @@ bfa_fcs_rport_process_rpsc(struct bfa_fcs_rport_s *rport, struct fchs_s *rx_fchs, u16 len) { struct bfa_fcxp_s *fcxp; - struct fchs_s fchs; - struct bfa_fcs_port_s *port = rport->port; + struct fchs_s fchs; + struct bfa_fcs_lport_s *port = rport->port; struct fc_rpsc_speed_info_s speeds; - struct bfa_pport_attr_s pport_attr; + struct bfa_port_attr_s pport_attr; bfa_trc(port->fcs, rx_fchs->s_id); bfa_trc(port->fcs, rx_fchs->d_id); @@ -1864,12 +1887,12 @@ bfa_fcs_rport_process_rpsc(struct bfa_fcs_rport_s *rport, if (!fcxp) return; - len = fc_rpsc_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rx_fchs->s_id, - bfa_fcs_port_get_fcid(port), rx_fchs->ox_id, - &speeds); + len = fc_rpsc_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), + rx_fchs->s_id, bfa_fcs_lport_get_fcid(port), + rx_fchs->ox_id, &speeds); bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, - FC_CLASS_3, len, &fchs, NULL, NULL, FC_MAX_PDUSZ, 0); + FC_CLASS_3, len, &fchs, NULL, NULL, FC_MAX_PDUSZ, 0); } static void @@ -1877,28 +1900,20 @@ bfa_fcs_rport_process_adisc(struct bfa_fcs_rport_s *rport, struct fchs_s *rx_fchs, u16 len) { struct bfa_fcxp_s *fcxp; - struct fchs_s fchs; - struct bfa_fcs_port_s *port = rport->port; - struct fc_adisc_s *adisc; + struct fchs_s fchs; + struct bfa_fcs_lport_s *port = rport->port; + struct fc_adisc_s *adisc; bfa_trc(port->fcs, rx_fchs->s_id); bfa_trc(port->fcs, rx_fchs->d_id); rport->stats.adisc_rcvd++; - if (BFA_FCS_VPORT_IS_TARGET_MODE(port)) { - /* - * @todo : Target Mode handling - */ - bfa_trc(port->fcs, rx_fchs->d_id); - bfa_assert(0); - return; - } - adisc = (struct fc_adisc_s *) (rx_fchs + 1); /* - * Accept if the itnim for this rport is online. Else reject the ADISC + * Accept if the itnim for this rport is online. + * Else reject the ADISC. */ if (bfa_fcs_itnim_get_online_state(rport->itnim) == BFA_STATUS_OK) { @@ -1907,27 +1922,25 @@ bfa_fcs_rport_process_adisc(struct bfa_fcs_rport_s *rport, return; len = fc_adisc_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), - rx_fchs->s_id, - bfa_fcs_port_get_fcid(port), - rx_fchs->ox_id, port->port_cfg.pwwn, - port->port_cfg.nwwn); + rx_fchs->s_id, bfa_fcs_lport_get_fcid(port), + rx_fchs->ox_id, port->port_cfg.pwwn, + port->port_cfg.nwwn); bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, - BFA_FALSE, FC_CLASS_3, len, &fchs, NULL, NULL, - FC_MAX_PDUSZ, 0); + BFA_FALSE, FC_CLASS_3, len, &fchs, NULL, NULL, + FC_MAX_PDUSZ, 0); } else { rport->stats.adisc_rejected++; bfa_fcs_rport_send_ls_rjt(rport, rx_fchs, FC_LS_RJT_RSN_UNABLE_TO_PERF_CMD, FC_LS_RJT_EXP_LOGIN_REQUIRED); } - } static void bfa_fcs_rport_hal_online(struct bfa_fcs_rport_s *rport) { - struct bfa_fcs_port_s *port = rport->port; + struct bfa_fcs_lport_s *port = rport->port; struct bfa_rport_info_s rport_info; rport_info.pid = rport->pid; @@ -1941,38 +1954,18 @@ bfa_fcs_rport_hal_online(struct bfa_fcs_rport_s *rport) bfa_rport_online(rport->bfa_rport, &rport_info); } -static void -bfa_fcs_rport_fc4_pause(struct bfa_fcs_rport_s *rport) -{ - if (bfa_fcs_port_is_initiator(rport->port)) - bfa_fcs_itnim_pause(rport->itnim); - - if (bfa_fcs_port_is_target(rport->port)) - bfa_fcs_tin_pause(rport->tin); -} - -static void -bfa_fcs_rport_fc4_resume(struct bfa_fcs_rport_s *rport) -{ - if (bfa_fcs_port_is_initiator(rport->port)) - bfa_fcs_itnim_resume(rport->itnim); - - if (bfa_fcs_port_is_target(rport->port)) - bfa_fcs_tin_resume(rport->tin); -} - static struct bfa_fcs_rport_s * -bfa_fcs_rport_alloc(struct bfa_fcs_port_s *port, wwn_t pwwn, u32 rpid) +bfa_fcs_rport_alloc(struct bfa_fcs_lport_s *port, wwn_t pwwn, u32 rpid) { - struct bfa_fcs_s *fcs = port->fcs; + struct bfa_fcs_s *fcs = port->fcs; struct bfa_fcs_rport_s *rport; - struct bfad_rport_s *rport_drv; + struct bfad_rport_s *rport_drv; /** * allocate rport */ if (bfa_fcb_rport_alloc(fcs->bfad, &rport, &rport_drv) - != BFA_STATUS_OK) { + != BFA_STATUS_OK) { bfa_trc(fcs, rpid); return NULL; } @@ -1999,10 +1992,9 @@ bfa_fcs_rport_alloc(struct bfa_fcs_port_s *port, wwn_t pwwn, u32 rpid) /** * allocate FC-4s */ - bfa_assert(bfa_fcs_port_is_initiator(port) ^ - bfa_fcs_port_is_target(port)); + bfa_assert(bfa_fcs_lport_is_initiator(port)); - if (bfa_fcs_port_is_initiator(port)) { + if (bfa_fcs_lport_is_initiator(port)) { rport->itnim = bfa_fcs_itnim_create(rport); if (!rport->itnim) { bfa_trc(fcs, rpid); @@ -2012,23 +2004,11 @@ bfa_fcs_rport_alloc(struct bfa_fcs_port_s *port, wwn_t pwwn, u32 rpid) } } - if (bfa_fcs_port_is_target(port)) { - rport->tin = bfa_fcs_tin_create(rport); - if (!rport->tin) { - bfa_trc(fcs, rpid); - bfa_rport_delete(rport->bfa_rport); - kfree(rport_drv); - return NULL; - } - } - - bfa_fcs_port_add_rport(port, rport); + bfa_fcs_lport_add_rport(port, rport); bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit); - /* - * Initialize the Rport Features(RPF) Sub Module - */ + /* Initialize the Rport Features(RPF) Sub Module */ if (!BFA_FCS_PID_IS_WKA(rport->pid)) bfa_fcs_rpf_init(rport); @@ -2039,121 +2019,78 @@ bfa_fcs_rport_alloc(struct bfa_fcs_port_s *port, wwn_t pwwn, u32 rpid) static void bfa_fcs_rport_free(struct bfa_fcs_rport_s *rport) { - struct bfa_fcs_port_s *port = rport->port; + struct bfa_fcs_lport_s *port = rport->port; /** * - delete FC-4s * - delete BFA rport * - remove from queue of rports */ - if (bfa_fcs_port_is_initiator(port)) + if (bfa_fcs_lport_is_initiator(port)) { bfa_fcs_itnim_delete(rport->itnim); - - if (bfa_fcs_port_is_target(port)) - bfa_fcs_tin_delete(rport->tin); + if (rport->pid != 0 && !BFA_FCS_PID_IS_WKA(rport->pid)) + bfa_fcs_rpf_rport_offline(rport); + } bfa_rport_delete(rport->bfa_rport); - bfa_fcs_port_del_rport(port, rport); + bfa_fcs_lport_del_rport(port, rport); kfree(rport->rp_drv); } static void -bfa_fcs_rport_aen_post(struct bfa_fcs_rport_s *rport, - enum bfa_rport_aen_event event, - struct bfa_rport_aen_data_s *data) -{ - union bfa_aen_data_u aen_data; - struct bfa_log_mod_s *logmod = rport->fcs->logm; - wwn_t lpwwn = bfa_fcs_port_get_pwwn(rport->port); - wwn_t rpwwn = rport->pwwn; - char lpwwn_ptr[BFA_STRING_32]; - char rpwwn_ptr[BFA_STRING_32]; - char *prio_str[] = { "unknown", "high", "medium", "low" }; - - wwn2str(lpwwn_ptr, lpwwn); - wwn2str(rpwwn_ptr, rpwwn); - - switch (event) { - case BFA_RPORT_AEN_ONLINE: - case BFA_RPORT_AEN_OFFLINE: - case BFA_RPORT_AEN_DISCONNECT: - bfa_log(logmod, BFA_LOG_CREATE_ID(BFA_AEN_CAT_RPORT, event), - rpwwn_ptr, lpwwn_ptr); - break; - case BFA_RPORT_AEN_QOS_PRIO: - aen_data.rport.priv.qos = data->priv.qos; - bfa_log(logmod, BFA_AEN_RPORT_QOS_PRIO, - prio_str[aen_data.rport.priv.qos.qos_priority], - rpwwn_ptr, lpwwn_ptr); - break; - case BFA_RPORT_AEN_QOS_FLOWID: - aen_data.rport.priv.qos = data->priv.qos; - bfa_log(logmod, BFA_AEN_RPORT_QOS_FLOWID, - aen_data.rport.priv.qos.qos_flow_id, rpwwn_ptr, - lpwwn_ptr); - break; - default: - break; - } - - aen_data.rport.vf_id = rport->port->fabric->vf_id; - aen_data.rport.ppwwn = - bfa_fcs_port_get_pwwn(bfa_fcs_get_base_port(rport->fcs)); - aen_data.rport.lpwwn = lpwwn; - aen_data.rport.rpwwn = rpwwn; -} - -static void bfa_fcs_rport_online_action(struct bfa_fcs_rport_s *rport) { - struct bfa_fcs_port_s *port = rport->port; + struct bfa_fcs_lport_s *port = rport->port; + struct bfad_s *bfad = (struct bfad_s *)port->fcs->bfad; + char lpwwn_buf[BFA_STRING_32]; + char rpwwn_buf[BFA_STRING_32]; rport->stats.onlines++; - if (bfa_fcs_port_is_initiator(port)) { + if (bfa_fcs_lport_is_initiator(port)) { bfa_fcs_itnim_rport_online(rport->itnim); if (!BFA_FCS_PID_IS_WKA(rport->pid)) bfa_fcs_rpf_rport_online(rport); }; - if (bfa_fcs_port_is_target(port)) - bfa_fcs_tin_rport_online(rport->tin); - - /* - * Don't post events for well known addresses - */ + wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(port)); + wwn2str(rpwwn_buf, rport->pwwn); if (!BFA_FCS_PID_IS_WKA(rport->pid)) - bfa_fcs_rport_aen_post(rport, BFA_RPORT_AEN_ONLINE, NULL); + BFA_LOG(KERN_INFO, bfad, log_level, + "Remote port (WWN = %s) online for logical port (WWN = %s)\n", + rpwwn_buf, lpwwn_buf); } static void bfa_fcs_rport_offline_action(struct bfa_fcs_rport_s *rport) { - struct bfa_fcs_port_s *port = rport->port; + struct bfa_fcs_lport_s *port = rport->port; + struct bfad_s *bfad = (struct bfad_s *)port->fcs->bfad; + char lpwwn_buf[BFA_STRING_32]; + char rpwwn_buf[BFA_STRING_32]; rport->stats.offlines++; - /* - * Don't post events for well known addresses - */ + wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(port)); + wwn2str(rpwwn_buf, rport->pwwn); if (!BFA_FCS_PID_IS_WKA(rport->pid)) { - if (bfa_fcs_port_is_online(rport->port) == BFA_TRUE) { - bfa_fcs_rport_aen_post(rport, BFA_RPORT_AEN_DISCONNECT, - NULL); - } else { - bfa_fcs_rport_aen_post(rport, BFA_RPORT_AEN_OFFLINE, - NULL); - } + if (bfa_fcs_lport_is_online(rport->port) == BFA_TRUE) + BFA_LOG(KERN_ERR, bfad, log_level, + "Remote port (WWN = %s) connectivity lost for " + "logical port (WWN = %s)\n", + rpwwn_buf, lpwwn_buf); + else + BFA_LOG(KERN_INFO, bfad, log_level, + "Remote port (WWN = %s) offlined by " + "logical port (WWN = %s)\n", + rpwwn_buf, lpwwn_buf); } - if (bfa_fcs_port_is_initiator(port)) { + if (bfa_fcs_lport_is_initiator(port)) { bfa_fcs_itnim_rport_offline(rport->itnim); if (!BFA_FCS_PID_IS_WKA(rport->pid)) bfa_fcs_rpf_rport_offline(rport); } - - if (bfa_fcs_port_is_target(port)) - bfa_fcs_tin_rport_offline(rport->tin); } /** @@ -2162,7 +2099,7 @@ bfa_fcs_rport_offline_action(struct bfa_fcs_rport_s *rport) static void bfa_fcs_rport_update(struct bfa_fcs_rport_s *rport, struct fc_logi_s *plogi) { - struct bfa_fcs_port_s *port = rport->port; + bfa_fcs_lport_t *port = rport->port; /** * - port name @@ -2193,12 +2130,13 @@ bfa_fcs_rport_update(struct bfa_fcs_rport_s *rport, struct fc_logi_s *plogi) /** * Direct Attach P2P mode : * This is to handle a bug (233476) in IBM targets in Direct Attach - * Mode. Basically, in FLOGI Accept the target would have erroneously - * set the BB Credit to the value used in the FLOGI sent by the HBA. - * It uses the correct value (its own BB credit) in PLOGI. + * Mode. Basically, in FLOGI Accept the target would have + * erroneously set the BB Credit to the value used in the FLOGI + * sent by the HBA. It uses the correct value (its own BB credit) + * in PLOGI. */ - if ((!bfa_fcs_fabric_is_switched(port->fabric)) - && (bfa_os_ntohs(plogi->csp.bbcred) < port->fabric->bb_credit)) { + if ((!bfa_fcs_fabric_is_switched(port->fabric)) && + (bfa_os_ntohs(plogi->csp.bbcred) < port->fabric->bb_credit)) { bfa_trc(port->fcs, bfa_os_ntohs(plogi->csp.bbcred)); bfa_trc(port->fcs, port->fabric->bb_credit); @@ -2211,7 +2149,7 @@ bfa_fcs_rport_update(struct bfa_fcs_rport_s *rport, struct fc_logi_s *plogi) } /** - * Called to handle LOGO received from an existing remote port. + * Called to handle LOGO received from an existing remote port. */ static void bfa_fcs_rport_process_logo(struct bfa_fcs_rport_s *rport, struct fchs_s *fchs) @@ -2231,8 +2169,8 @@ bfa_fcs_rport_process_logo(struct bfa_fcs_rport_s *rport, struct fchs_s *fchs) */ /** - * Called by bport/vport to create a remote port instance for a discovered - * remote device. + * Called by bport/vport to create a remote port instance for a discovered + * remote device. * * @param[in] port - base port or vport * @param[in] rpid - remote port ID @@ -2240,7 +2178,7 @@ bfa_fcs_rport_process_logo(struct bfa_fcs_rport_s *rport, struct fchs_s *fchs) * @return None */ struct bfa_fcs_rport_s * -bfa_fcs_rport_create(struct bfa_fcs_port_s *port, u32 rpid) +bfa_fcs_rport_create(struct bfa_fcs_lport_s *port, u32 rpid) { struct bfa_fcs_rport_s *rport; @@ -2262,10 +2200,9 @@ bfa_fcs_rport_create(struct bfa_fcs_port_s *port, u32 rpid) * @return None */ struct bfa_fcs_rport_s * -bfa_fcs_rport_create_by_wwn(struct bfa_fcs_port_s *port, wwn_t rpwwn) +bfa_fcs_rport_create_by_wwn(struct bfa_fcs_lport_s *port, wwn_t rpwwn) { struct bfa_fcs_rport_s *rport; - bfa_trc(port->fcs, rpwwn); rport = bfa_fcs_rport_alloc(port, rpwwn, 0); if (!rport) @@ -2274,7 +2211,6 @@ bfa_fcs_rport_create_by_wwn(struct bfa_fcs_port_s *port, wwn_t rpwwn) bfa_sm_send_event(rport, RPSM_EVENT_ADDRESS_DISC); return rport; } - /** * Called by bport in private loop topology to indicate that a * rport has been discovered and plogi has been completed. @@ -2283,8 +2219,8 @@ bfa_fcs_rport_create_by_wwn(struct bfa_fcs_port_s *port, wwn_t rpwwn) * @param[in] rpid - remote port ID */ void -bfa_fcs_rport_start(struct bfa_fcs_port_s *port, struct fchs_s *fchs, - struct fc_logi_s *plogi) +bfa_fcs_rport_start(struct bfa_fcs_lport_s *port, struct fchs_s *fchs, + struct fc_logi_s *plogi) { struct bfa_fcs_rport_s *rport; @@ -2298,12 +2234,12 @@ bfa_fcs_rport_start(struct bfa_fcs_port_s *port, struct fchs_s *fchs, } /** - * Called by bport/vport to handle PLOGI received from a new remote port. - * If an existing rport does a plogi, it will be handled separately. + * Called by bport/vport to handle PLOGI received from a new remote port. + * If an existing rport does a plogi, it will be handled separately. */ void -bfa_fcs_rport_plogi_create(struct bfa_fcs_port_s *port, struct fchs_s *fchs, - struct fc_logi_s *plogi) +bfa_fcs_rport_plogi_create(struct bfa_fcs_lport_s *port, struct fchs_s *fchs, + struct fc_logi_s *plogi) { struct bfa_fcs_rport_s *rport; @@ -2323,9 +2259,9 @@ bfa_fcs_rport_plogi_create(struct bfa_fcs_port_s *port, struct fchs_s *fchs, static int wwn_compare(wwn_t wwn1, wwn_t wwn2) { - u8 *b1 = (u8 *) &wwn1; - u8 *b2 = (u8 *) &wwn2; - int i; + u8 *b1 = (u8 *) &wwn1; + u8 *b2 = (u8 *) &wwn2; + int i; for (i = 0; i < sizeof(wwn_t); i++) { if (b1[i] < b2[i]) @@ -2337,12 +2273,12 @@ wwn_compare(wwn_t wwn1, wwn_t wwn2) } /** - * Called by bport/vport to handle PLOGI received from an existing - * remote port. + * Called by bport/vport to handle PLOGI received from an existing + * remote port. */ void bfa_fcs_rport_plogi(struct bfa_fcs_rport_s *rport, struct fchs_s *rx_fchs, - struct fc_logi_s *plogi) + struct fc_logi_s *plogi) { /** * @todo Handle P2P and initiator-initiator. @@ -2360,9 +2296,9 @@ bfa_fcs_rport_plogi(struct bfa_fcs_rport_s *rport, struct fchs_s *rx_fchs, * If the link topology is N2N, * this Plogi should be accepted. */ - if ((wwn_compare(rport->port->port_cfg.pwwn, rport->pwwn) == -1) - && (bfa_fcs_fabric_is_switched(rport->port->fabric)) - && (!BFA_FCS_PID_IS_WKA(rport->pid))) { + if ((wwn_compare(rport->port->port_cfg.pwwn, rport->pwwn) == -1) && + (bfa_fcs_fabric_is_switched(rport->port->fabric)) && + (!BFA_FCS_PID_IS_WKA(rport->pid))) { bfa_trc(rport->fcs, rport->pid); return; } @@ -2374,10 +2310,10 @@ bfa_fcs_rport_plogi(struct bfa_fcs_rport_s *rport, struct fchs_s *rx_fchs, /** * Called by bport/vport to delete a remote port instance. * -* Rport delete is called under the following conditions: - * - vport is deleted - * - vf is deleted - * - explicit request from OS to delete rport (vmware) + * Rport delete is called under the following conditions: + * - vport is deleted + * - vf is deleted + * - explicit request from OS to delete rport */ void bfa_fcs_rport_delete(struct bfa_fcs_rport_s *rport) @@ -2404,20 +2340,18 @@ bfa_fcs_rport_online(struct bfa_fcs_rport_s *rport) { bfa_sm_send_event(rport, RPSM_EVENT_PLOGI_SEND); } - /** - * Called by bport/vport to notify SCN for the remote port + * Called by bport/vport to notify SCN for the remote port */ void bfa_fcs_rport_scn(struct bfa_fcs_rport_s *rport) { - rport->stats.rscns++; bfa_sm_send_event(rport, RPSM_EVENT_SCN); } /** - * Called by fcpim to notify that the ITN cleanup is done. + * Called by fcpim to notify that the ITN cleanup is done. */ void bfa_fcs_rport_itnim_ack(struct bfa_fcs_rport_s *rport) @@ -2426,7 +2360,7 @@ bfa_fcs_rport_itnim_ack(struct bfa_fcs_rport_s *rport) } /** - * Called by fcptm to notify that the ITN cleanup is done. + * Called by fcptm to notify that the ITN cleanup is done. */ void bfa_fcs_rport_tin_ack(struct bfa_fcs_rport_s *rport) @@ -2435,99 +2369,100 @@ bfa_fcs_rport_tin_ack(struct bfa_fcs_rport_s *rport) } /** - * This routine BFA callback for bfa_rport_online() call. + * brief + * This routine BFA callback for bfa_rport_online() call. * - * param[in] cb_arg - rport struct. + * param[in] cb_arg - rport struct. * - * return - * void + * return + * void * -* Special Considerations: + * Special Considerations: * - * note + * note */ void bfa_cb_rport_online(void *cbarg) { - struct bfa_fcs_rport_s *rport = (struct bfa_fcs_rport_s *)cbarg; + struct bfa_fcs_rport_s *rport = (struct bfa_fcs_rport_s *) cbarg; bfa_trc(rport->fcs, rport->pwwn); bfa_sm_send_event(rport, RPSM_EVENT_HCB_ONLINE); } /** - * This routine BFA callback for bfa_rport_offline() call. + * brief + * This routine BFA callback for bfa_rport_offline() call. * - * param[in] rport - + * param[in] rport - * - * return - * void + * return + * void * - * Special Considerations: + * Special Considerations: * - * note + * note */ void bfa_cb_rport_offline(void *cbarg) { - struct bfa_fcs_rport_s *rport = (struct bfa_fcs_rport_s *)cbarg; + struct bfa_fcs_rport_s *rport = (struct bfa_fcs_rport_s *) cbarg; bfa_trc(rport->fcs, rport->pwwn); bfa_sm_send_event(rport, RPSM_EVENT_HCB_OFFLINE); } /** - * This routine is a static BFA callback when there is a QoS flow_id - * change notification + * brief + * This routine is a static BFA callback when there is a QoS flow_id + * change notification * - * @param[in] rport - + * param[in] rport - * - * @return void + * return + * void * - * Special Considerations: + * Special Considerations: * - * @note + * note */ void bfa_cb_rport_qos_scn_flowid(void *cbarg, - struct bfa_rport_qos_attr_s old_qos_attr, - struct bfa_rport_qos_attr_s new_qos_attr) + struct bfa_rport_qos_attr_s old_qos_attr, + struct bfa_rport_qos_attr_s new_qos_attr) { - struct bfa_fcs_rport_s *rport = (struct bfa_fcs_rport_s *)cbarg; - struct bfa_rport_aen_data_s aen_data; + struct bfa_fcs_rport_s *rport = (struct bfa_fcs_rport_s *) cbarg; bfa_trc(rport->fcs, rport->pwwn); - aen_data.priv.qos = new_qos_attr; - bfa_fcs_rport_aen_post(rport, BFA_RPORT_AEN_QOS_FLOWID, &aen_data); } /** - * This routine is a static BFA callback when there is a QoS priority - * change notification + * brief + * This routine is a static BFA callback when there is a QoS priority + * change notification * - * @param[in] rport - + * param[in] rport - * - * @return void + * return + * void * - * Special Considerations: + * Special Considerations: * - * @note + * note */ void -bfa_cb_rport_qos_scn_prio(void *cbarg, struct bfa_rport_qos_attr_s old_qos_attr, - struct bfa_rport_qos_attr_s new_qos_attr) +bfa_cb_rport_qos_scn_prio(void *cbarg, + struct bfa_rport_qos_attr_s old_qos_attr, + struct bfa_rport_qos_attr_s new_qos_attr) { - struct bfa_fcs_rport_s *rport = (struct bfa_fcs_rport_s *)cbarg; - struct bfa_rport_aen_data_s aen_data; + struct bfa_fcs_rport_s *rport = (struct bfa_fcs_rport_s *) cbarg; bfa_trc(rport->fcs, rport->pwwn); - aen_data.priv.qos = new_qos_attr; - bfa_fcs_rport_aen_post(rport, BFA_RPORT_AEN_QOS_PRIO, &aen_data); } /** - * Called to process any unsolicted frames from this remote port + * Called to process any unsolicted frames from this remote port */ void bfa_fcs_rport_logo_imp(struct bfa_fcs_rport_s *rport) @@ -2536,14 +2471,14 @@ bfa_fcs_rport_logo_imp(struct bfa_fcs_rport_s *rport) } /** - * Called to process any unsolicted frames from this remote port + * Called to process any unsolicted frames from this remote port */ void -bfa_fcs_rport_uf_recv(struct bfa_fcs_rport_s *rport, struct fchs_s *fchs, - u16 len) +bfa_fcs_rport_uf_recv(struct bfa_fcs_rport_s *rport, + struct fchs_s *fchs, u16 len) { - struct bfa_fcs_port_s *port = rport->port; - struct fc_els_cmd_s *els_cmd; + struct bfa_fcs_lport_s *port = rport->port; + struct fc_els_cmd_s *els_cmd; bfa_trc(rport->fcs, fchs->s_id); bfa_trc(rport->fcs, fchs->d_id); @@ -2558,30 +2493,33 @@ bfa_fcs_rport_uf_recv(struct bfa_fcs_rport_s *rport, struct fchs_s *fchs, switch (els_cmd->els_code) { case FC_ELS_LOGO: + bfa_stats(port, plogi_rcvd); bfa_fcs_rport_process_logo(rport, fchs); break; case FC_ELS_ADISC: + bfa_stats(port, adisc_rcvd); bfa_fcs_rport_process_adisc(rport, fchs, len); break; case FC_ELS_PRLO: - if (bfa_fcs_port_is_initiator(port)) + bfa_stats(port, prlo_rcvd); + if (bfa_fcs_lport_is_initiator(port)) bfa_fcs_fcpim_uf_recv(rport->itnim, fchs, len); - - if (bfa_fcs_port_is_target(port)) - bfa_fcs_fcptm_uf_recv(rport->tin, fchs, len); break; case FC_ELS_PRLI: + bfa_stats(port, prli_rcvd); bfa_fcs_rport_process_prli(rport, fchs, len); break; case FC_ELS_RPSC: + bfa_stats(port, rpsc_rcvd); bfa_fcs_rport_process_rpsc(rport, fchs, len); break; default: + bfa_stats(port, un_handled_els_rcvd); bfa_fcs_rport_send_ls_rjt(rport, fchs, FC_LS_RJT_RSN_CMD_NOT_SUPP, FC_LS_RJT_EXP_NO_ADDL_INFO); @@ -2589,28 +2527,27 @@ bfa_fcs_rport_uf_recv(struct bfa_fcs_rport_s *rport, struct fchs_s *fchs, } } -/* Send best case acc to prlo */ +/* 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_fcs_lport_s *port = rport->port; + struct fchs_s fchs; struct bfa_fcxp_s *fcxp; - int len; + 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->pid, bfa_fcs_lport_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); + port->lp_tag, BFA_FALSE, FC_CLASS_3, len, &fchs, + NULL, NULL, FC_MAX_PDUSZ, 0); } /* @@ -2620,10 +2557,10 @@ static void bfa_fcs_rport_send_ls_rjt(struct bfa_fcs_rport_s *rport, struct fchs_s *rx_fchs, u8 reason_code, u8 reason_code_expl) { - struct bfa_fcs_port_s *port = rport->port; - struct fchs_s fchs; + struct bfa_fcs_lport_s *port = rport->port; + struct fchs_s fchs; struct bfa_fcxp_s *fcxp; - int len; + int len; bfa_trc(rport->fcs, rx_fchs->s_id); @@ -2631,12 +2568,13 @@ bfa_fcs_rport_send_ls_rjt(struct bfa_fcs_rport_s *rport, struct fchs_s *rx_fchs, if (!fcxp) return; - len = fc_ls_rjt_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rx_fchs->s_id, - bfa_fcs_port_get_fcid(port), rx_fchs->ox_id, - reason_code, reason_code_expl); + len = fc_ls_rjt_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), + rx_fchs->s_id, bfa_fcs_lport_get_fcid(port), + rx_fchs->ox_id, reason_code, reason_code_expl); - bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, - FC_CLASS_3, len, &fchs, NULL, NULL, FC_MAX_PDUSZ, 0); + bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, + BFA_FALSE, FC_CLASS_3, len, &fchs, NULL, NULL, + FC_MAX_PDUSZ, 0); } /** @@ -2649,24 +2587,22 @@ bfa_fcs_rport_get_state(struct bfa_fcs_rport_s *rport) } /** - * Called by the Driver to set rport delete/ageout timeout + * brief + * Called by the Driver to set rport delete/ageout timeout * - * param[in] rport timeout value in seconds. + * param[in] rport timeout value in seconds. * - * return None + * return None */ void bfa_fcs_rport_set_del_timeout(u8 rport_tmo) { - /* - * convert to Millisecs - */ + /* convert to Millisecs */ 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_fcs_rport_prlo(struct bfa_fcs_rport_s *rport, u16 ox_id) { bfa_trc(rport->fcs, rport->pid); @@ -2674,3 +2610,517 @@ bfa_fcs_rport_prlo(struct bfa_fcs_rport_s *rport, uint16_t ox_id) rport->reply_oxid = ox_id; bfa_sm_send_event(rport, RPSM_EVENT_PRLO_RCVD); } + + + +/** + * Remote port implementation. + */ + +/** + * fcs_rport_api FCS rport API. + */ + +/** + * Direct API to add a target by port wwn. This interface is used, for + * example, by bios when target pwwn is known from boot lun configuration. + */ +bfa_status_t +bfa_fcs_rport_add(struct bfa_fcs_lport_s *port, wwn_t *pwwn, + struct bfa_fcs_rport_s *rport, struct bfad_rport_s *rport_drv) +{ + bfa_trc(port->fcs, *pwwn); + + return BFA_STATUS_OK; +} + +/** + * Direct API to remove a target and its associated resources. This + * interface is used, for example, by driver to remove target + * ports from the target list for a VM. + */ +bfa_status_t +bfa_fcs_rport_remove(struct bfa_fcs_rport_s *rport_in) +{ + + struct bfa_fcs_rport_s *rport; + + bfa_trc(rport_in->fcs, rport_in->pwwn); + + rport = bfa_fcs_lport_get_rport_by_pwwn(rport_in->port, rport_in->pwwn); + if (rport == NULL) { + /* + * TBD Error handling + */ + bfa_trc(rport_in->fcs, rport_in->pid); + return BFA_STATUS_UNKNOWN_RWWN; + } + + /* + * TBD if this remote port is online, send a logo + */ + return BFA_STATUS_OK; + +} + +/** + * Remote device status for display/debug. + */ +void +bfa_fcs_rport_get_attr(struct bfa_fcs_rport_s *rport, + struct bfa_rport_attr_s *rport_attr) +{ + struct bfa_rport_qos_attr_s qos_attr; + bfa_fcs_lport_t *port = rport->port; + bfa_port_speed_t rport_speed = rport->rpf.rpsc_speed; + + bfa_os_memset(rport_attr, 0, sizeof(struct bfa_rport_attr_s)); + + rport_attr->pid = rport->pid; + rport_attr->pwwn = rport->pwwn; + rport_attr->nwwn = rport->nwwn; + rport_attr->cos_supported = rport->fc_cos; + rport_attr->df_sz = rport->maxfrsize; + rport_attr->state = bfa_fcs_rport_get_state(rport); + rport_attr->fc_cos = rport->fc_cos; + rport_attr->cisc = rport->cisc; + rport_attr->scsi_function = rport->scsi_function; + rport_attr->curr_speed = rport->rpf.rpsc_speed; + rport_attr->assigned_speed = rport->rpf.assigned_speed; + + bfa_rport_get_qos_attr(rport->bfa_rport, &qos_attr); + rport_attr->qos_attr = qos_attr; + + rport_attr->trl_enforced = BFA_FALSE; + if (bfa_fcport_is_ratelim(port->fcs->bfa)) { + if (rport_speed == BFA_PORT_SPEED_UNKNOWN) { + /* Use default ratelim speed setting */ + rport_speed = + bfa_fcport_get_ratelim_speed(rport->fcs->bfa); + } + + if (rport_speed < bfa_fcs_lport_get_rport_max_speed(port)) + rport_attr->trl_enforced = BFA_TRUE; + } +} + +/** + * Per remote device statistics. + */ +void +bfa_fcs_rport_get_stats(struct bfa_fcs_rport_s *rport, + struct bfa_rport_stats_s *stats) +{ + *stats = rport->stats; +} + +void +bfa_fcs_rport_clear_stats(struct bfa_fcs_rport_s *rport) +{ + bfa_os_memset((char *)&rport->stats, 0, + sizeof(struct bfa_rport_stats_s)); +} + +struct bfa_fcs_rport_s * +bfa_fcs_rport_lookup(struct bfa_fcs_lport_s *port, wwn_t rpwwn) +{ + struct bfa_fcs_rport_s *rport; + + rport = bfa_fcs_lport_get_rport_by_pwwn(port, rpwwn); + if (rport == NULL) { + /* + * TBD Error handling + */ + } + + return rport; +} + +struct bfa_fcs_rport_s * +bfa_fcs_rport_lookup_by_nwwn(struct bfa_fcs_lport_s *port, wwn_t rnwwn) +{ + struct bfa_fcs_rport_s *rport; + + rport = bfa_fcs_lport_get_rport_by_nwwn(port, rnwwn); + if (rport == NULL) { + /* + * TBD Error handling + */ + } + + return rport; +} + +/* + * This API is to set the Rport's speed. Should be used when RPSC is not + * supported by the rport. + */ +void +bfa_fcs_rport_set_speed(struct bfa_fcs_rport_s *rport, bfa_port_speed_t speed) +{ + rport->rpf.assigned_speed = speed; + + /* Set this speed in f/w only if the RPSC speed is not available */ + if (rport->rpf.rpsc_speed == BFA_PORT_SPEED_UNKNOWN) + bfa_rport_speed(rport->bfa_rport, speed); +} + + + +/** + * Remote port features (RPF) implementation. + */ + +#define BFA_FCS_RPF_RETRIES (3) +#define BFA_FCS_RPF_RETRY_TIMEOUT (1000) /* 1 sec (In millisecs) */ + +static void bfa_fcs_rpf_send_rpsc2(void *rport_cbarg, + struct bfa_fcxp_s *fcxp_alloced); +static void bfa_fcs_rpf_rpsc2_response(void *fcsarg, + struct bfa_fcxp_s *fcxp, + void *cbarg, + bfa_status_t req_status, + u32 rsp_len, + u32 resid_len, + struct fchs_s *rsp_fchs); + +static void bfa_fcs_rpf_timeout(void *arg); + +/** + * fcs_rport_ftrs_sm FCS rport state machine events + */ + +enum rpf_event { + RPFSM_EVENT_RPORT_OFFLINE = 1, /* Rport offline */ + RPFSM_EVENT_RPORT_ONLINE = 2, /* Rport online */ + RPFSM_EVENT_FCXP_SENT = 3, /* Frame from has been sent */ + RPFSM_EVENT_TIMEOUT = 4, /* Rport SM timeout event */ + RPFSM_EVENT_RPSC_COMP = 5, + RPFSM_EVENT_RPSC_FAIL = 6, + RPFSM_EVENT_RPSC_ERROR = 7, +}; + +static void bfa_fcs_rpf_sm_uninit(struct bfa_fcs_rpf_s *rpf, + enum rpf_event event); +static void bfa_fcs_rpf_sm_rpsc_sending(struct bfa_fcs_rpf_s *rpf, + enum rpf_event event); +static void bfa_fcs_rpf_sm_rpsc(struct bfa_fcs_rpf_s *rpf, + enum rpf_event event); +static void bfa_fcs_rpf_sm_rpsc_retry(struct bfa_fcs_rpf_s *rpf, + enum rpf_event event); +static void bfa_fcs_rpf_sm_offline(struct bfa_fcs_rpf_s *rpf, + enum rpf_event event); +static void bfa_fcs_rpf_sm_online(struct bfa_fcs_rpf_s *rpf, + enum rpf_event event); + +static void +bfa_fcs_rpf_sm_uninit(struct bfa_fcs_rpf_s *rpf, enum rpf_event event) +{ + struct bfa_fcs_rport_s *rport = rpf->rport; + struct bfa_fcs_fabric_s *fabric = &rport->fcs->fabric; + + bfa_trc(rport->fcs, rport->pwwn); + bfa_trc(rport->fcs, rport->pid); + bfa_trc(rport->fcs, event); + + switch (event) { + case RPFSM_EVENT_RPORT_ONLINE: + /* 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; + + case RPFSM_EVENT_RPORT_OFFLINE: + break; + + default: + bfa_sm_fault(rport->fcs, event); + } +} + +static void +bfa_fcs_rpf_sm_rpsc_sending(struct bfa_fcs_rpf_s *rpf, enum rpf_event event) +{ + struct bfa_fcs_rport_s *rport = rpf->rport; + + bfa_trc(rport->fcs, event); + + switch (event) { + case RPFSM_EVENT_FCXP_SENT: + bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_rpsc); + break; + + case RPFSM_EVENT_RPORT_OFFLINE: + bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_offline); + bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rpf->fcxp_wqe); + rpf->rpsc_retries = 0; + break; + + default: + bfa_sm_fault(rport->fcs, event); + } +} + +static void +bfa_fcs_rpf_sm_rpsc(struct bfa_fcs_rpf_s *rpf, enum rpf_event event) +{ + struct bfa_fcs_rport_s *rport = rpf->rport; + + bfa_trc(rport->fcs, rport->pid); + bfa_trc(rport->fcs, event); + + switch (event) { + case RPFSM_EVENT_RPSC_COMP: + bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_online); + /* Update speed info in f/w via BFA */ + if (rpf->rpsc_speed != BFA_PORT_SPEED_UNKNOWN) + bfa_rport_speed(rport->bfa_rport, rpf->rpsc_speed); + else if (rpf->assigned_speed != BFA_PORT_SPEED_UNKNOWN) + bfa_rport_speed(rport->bfa_rport, rpf->assigned_speed); + break; + + case RPFSM_EVENT_RPSC_FAIL: + /* RPSC not supported by rport */ + bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_online); + break; + + case RPFSM_EVENT_RPSC_ERROR: + /* need to retry...delayed a bit. */ + if (rpf->rpsc_retries++ < BFA_FCS_RPF_RETRIES) { + bfa_timer_start(rport->fcs->bfa, &rpf->timer, + bfa_fcs_rpf_timeout, rpf, + BFA_FCS_RPF_RETRY_TIMEOUT); + bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_rpsc_retry); + } else { + bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_online); + } + break; + + case RPFSM_EVENT_RPORT_OFFLINE: + bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_offline); + bfa_fcxp_discard(rpf->fcxp); + rpf->rpsc_retries = 0; + break; + + default: + bfa_sm_fault(rport->fcs, event); + } +} + +static void +bfa_fcs_rpf_sm_rpsc_retry(struct bfa_fcs_rpf_s *rpf, enum rpf_event event) +{ + struct bfa_fcs_rport_s *rport = rpf->rport; + + bfa_trc(rport->fcs, rport->pid); + bfa_trc(rport->fcs, event); + + switch (event) { + case RPFSM_EVENT_TIMEOUT: + /* re-send the RPSC */ + bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_rpsc_sending); + bfa_fcs_rpf_send_rpsc2(rpf, NULL); + break; + + case RPFSM_EVENT_RPORT_OFFLINE: + bfa_timer_stop(&rpf->timer); + bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_offline); + rpf->rpsc_retries = 0; + break; + + default: + bfa_sm_fault(rport->fcs, event); + } +} + +static void +bfa_fcs_rpf_sm_online(struct bfa_fcs_rpf_s *rpf, enum rpf_event event) +{ + struct bfa_fcs_rport_s *rport = rpf->rport; + + bfa_trc(rport->fcs, rport->pwwn); + bfa_trc(rport->fcs, rport->pid); + bfa_trc(rport->fcs, event); + + switch (event) { + case RPFSM_EVENT_RPORT_OFFLINE: + bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_offline); + rpf->rpsc_retries = 0; + break; + + default: + bfa_sm_fault(rport->fcs, event); + } +} + +static void +bfa_fcs_rpf_sm_offline(struct bfa_fcs_rpf_s *rpf, enum rpf_event event) +{ + struct bfa_fcs_rport_s *rport = rpf->rport; + + bfa_trc(rport->fcs, rport->pwwn); + bfa_trc(rport->fcs, rport->pid); + bfa_trc(rport->fcs, event); + + switch (event) { + case RPFSM_EVENT_RPORT_ONLINE: + bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_rpsc_sending); + bfa_fcs_rpf_send_rpsc2(rpf, NULL); + break; + + case RPFSM_EVENT_RPORT_OFFLINE: + break; + + default: + bfa_sm_fault(rport->fcs, event); + } +} +/** + * Called when Rport is created. + */ +void +bfa_fcs_rpf_init(struct bfa_fcs_rport_s *rport) +{ + struct bfa_fcs_rpf_s *rpf = &rport->rpf; + + bfa_trc(rport->fcs, rport->pid); + rpf->rport = rport; + + bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_uninit); +} + +/** + * Called when Rport becomes online + */ +void +bfa_fcs_rpf_rport_online(struct bfa_fcs_rport_s *rport) +{ + bfa_trc(rport->fcs, rport->pid); + + if (__fcs_min_cfg(rport->port->fcs)) + return; + + if (bfa_fcs_fabric_is_switched(rport->port->fabric)) + bfa_sm_send_event(&rport->rpf, RPFSM_EVENT_RPORT_ONLINE); +} + +/** + * Called when Rport becomes offline + */ +void +bfa_fcs_rpf_rport_offline(struct bfa_fcs_rport_s *rport) +{ + bfa_trc(rport->fcs, rport->pid); + + if (__fcs_min_cfg(rport->port->fcs)) + return; + + rport->rpf.rpsc_speed = 0; + bfa_sm_send_event(&rport->rpf, RPFSM_EVENT_RPORT_OFFLINE); +} + +static void +bfa_fcs_rpf_timeout(void *arg) +{ + struct bfa_fcs_rpf_s *rpf = (struct bfa_fcs_rpf_s *) arg; + struct bfa_fcs_rport_s *rport = rpf->rport; + + bfa_trc(rport->fcs, rport->pid); + bfa_sm_send_event(rpf, RPFSM_EVENT_TIMEOUT); +} + +static void +bfa_fcs_rpf_send_rpsc2(void *rpf_cbarg, struct bfa_fcxp_s *fcxp_alloced) +{ + struct bfa_fcs_rpf_s *rpf = (struct bfa_fcs_rpf_s *)rpf_cbarg; + struct bfa_fcs_rport_s *rport = rpf->rport; + struct bfa_fcs_lport_s *port = rport->port; + struct fchs_s fchs; + int len; + struct bfa_fcxp_s *fcxp; + + bfa_trc(rport->fcs, rport->pwwn); + + fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); + if (!fcxp) { + bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &rpf->fcxp_wqe, + bfa_fcs_rpf_send_rpsc2, rpf); + return; + } + rpf->fcxp = fcxp; + + len = fc_rpsc2_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rport->pid, + bfa_fcs_lport_get_fcid(port), &rport->pid, 1); + + bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, + FC_CLASS_3, len, &fchs, bfa_fcs_rpf_rpsc2_response, + rpf, FC_MAX_PDUSZ, FC_ELS_TOV); + rport->stats.rpsc_sent++; + bfa_sm_send_event(rpf, RPFSM_EVENT_FCXP_SENT); + +} + +static void +bfa_fcs_rpf_rpsc2_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg, + bfa_status_t req_status, u32 rsp_len, + u32 resid_len, struct fchs_s *rsp_fchs) +{ + struct bfa_fcs_rpf_s *rpf = (struct bfa_fcs_rpf_s *) cbarg; + struct bfa_fcs_rport_s *rport = rpf->rport; + struct fc_ls_rjt_s *ls_rjt; + struct fc_rpsc2_acc_s *rpsc2_acc; + u16 num_ents; + + bfa_trc(rport->fcs, req_status); + + if (req_status != BFA_STATUS_OK) { + bfa_trc(rport->fcs, req_status); + if (req_status == BFA_STATUS_ETIMER) + rport->stats.rpsc_failed++; + bfa_sm_send_event(rpf, RPFSM_EVENT_RPSC_ERROR); + return; + } + + rpsc2_acc = (struct fc_rpsc2_acc_s *) BFA_FCXP_RSP_PLD(fcxp); + if (rpsc2_acc->els_cmd == FC_ELS_ACC) { + rport->stats.rpsc_accs++; + num_ents = bfa_os_ntohs(rpsc2_acc->num_pids); + bfa_trc(rport->fcs, num_ents); + if (num_ents > 0) { + bfa_assert(rpsc2_acc->port_info[0].pid != rport->pid); + bfa_trc(rport->fcs, + bfa_os_ntohs(rpsc2_acc->port_info[0].pid)); + bfa_trc(rport->fcs, + bfa_os_ntohs(rpsc2_acc->port_info[0].speed)); + bfa_trc(rport->fcs, + bfa_os_ntohs(rpsc2_acc->port_info[0].index)); + bfa_trc(rport->fcs, + rpsc2_acc->port_info[0].type); + + if (rpsc2_acc->port_info[0].speed == 0) { + bfa_sm_send_event(rpf, RPFSM_EVENT_RPSC_ERROR); + return; + } + + rpf->rpsc_speed = fc_rpsc_operspeed_to_bfa_speed( + bfa_os_ntohs(rpsc2_acc->port_info[0].speed)); + + bfa_sm_send_event(rpf, RPFSM_EVENT_RPSC_COMP); + } + } else { + ls_rjt = (struct fc_ls_rjt_s *) BFA_FCXP_RSP_PLD(fcxp); + bfa_trc(rport->fcs, ls_rjt->reason_code); + bfa_trc(rport->fcs, ls_rjt->reason_code_expl); + rport->stats.rpsc_rejects++; + if (ls_rjt->reason_code == FC_LS_RJT_RSN_CMD_NOT_SUPP) + bfa_sm_send_event(rpf, RPFSM_EVENT_RPSC_FAIL); + else + bfa_sm_send_event(rpf, RPFSM_EVENT_RPSC_ERROR); + } +} diff --git a/drivers/scsi/bfa/bfa_fcs_uf.c b/drivers/scsi/bfa/bfa_fcs_uf.c deleted file mode 100644 index 3d57d48bbae4..000000000000 --- a/drivers/scsi/bfa/bfa_fcs_uf.c +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/** - * bfa_fcs_uf.c BFA FCS UF ( Unsolicited Frames) - */ - -#include <fcs/bfa_fcs.h> -#include <bfa_svc.h> -#include <fcs/bfa_fcs_fabric.h> -#include "fcs.h" -#include "fcs_trcmod.h" -#include "fcs_fabric.h" -#include "fcs_uf.h" - -BFA_TRC_FILE(FCS, UF); - -/** - * BFA callback for unsolicited frame receive handler. - * - * @param[in] cbarg callback arg for receive handler - * @param[in] uf unsolicited frame descriptor - * - * @return None - */ -static void -bfa_fcs_uf_recv(void *cbarg, struct bfa_uf_s *uf) -{ - struct bfa_fcs_s *fcs = (struct bfa_fcs_s *) cbarg; - struct fchs_s *fchs = bfa_uf_get_frmbuf(uf); - u16 len = bfa_uf_get_frmlen(uf); - struct fc_vft_s *vft; - struct bfa_fcs_fabric_s *fabric; - - /** - * check for VFT header - */ - if (fchs->routing == FC_RTG_EXT_HDR && - fchs->cat_info == FC_CAT_VFT_HDR) { - bfa_stats(fcs, uf.tagged); - vft = bfa_uf_get_frmbuf(uf); - if (fcs->port_vfid == vft->vf_id) - fabric = &fcs->fabric; - else - fabric = bfa_fcs_vf_lookup(fcs, (u16) vft->vf_id); - - /** - * drop frame if vfid is unknown - */ - if (!fabric) { - bfa_assert(0); - bfa_stats(fcs, uf.vfid_unknown); - bfa_uf_free(uf); - return; - } - - /** - * skip vft header - */ - fchs = (struct fchs_s *) (vft + 1); - len -= sizeof(struct fc_vft_s); - - bfa_trc(fcs, vft->vf_id); - } else { - bfa_stats(fcs, uf.untagged); - fabric = &fcs->fabric; - } - - bfa_trc(fcs, ((u32 *) fchs)[0]); - bfa_trc(fcs, ((u32 *) fchs)[1]); - bfa_trc(fcs, ((u32 *) fchs)[2]); - bfa_trc(fcs, ((u32 *) fchs)[3]); - bfa_trc(fcs, ((u32 *) fchs)[4]); - bfa_trc(fcs, ((u32 *) fchs)[5]); - bfa_trc(fcs, len); - - bfa_fcs_fabric_uf_recv(fabric, fchs, len); - bfa_uf_free(uf); -} - -void -bfa_fcs_uf_attach(struct bfa_fcs_s *fcs) -{ - bfa_uf_recv_register(fcs->bfa, bfa_fcs_uf_recv, fcs); -} diff --git a/drivers/scsi/bfa/bfa_fcxp.c b/drivers/scsi/bfa/bfa_fcxp.c deleted file mode 100644 index 8258f88bfee6..000000000000 --- a/drivers/scsi/bfa/bfa_fcxp.c +++ /dev/null @@ -1,774 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#include <bfa.h> -#include <bfi/bfi_uf.h> -#include <cs/bfa_debug.h> - -BFA_TRC_FILE(HAL, FCXP); -BFA_MODULE(fcxp); - -/** - * forward declarations - */ -static void __bfa_fcxp_send_cbfn(void *cbarg, bfa_boolean_t complete); -static void hal_fcxp_rx_plog(struct bfa_s *bfa, struct bfa_fcxp_s *fcxp, - struct bfi_fcxp_send_rsp_s *fcxp_rsp); -static void hal_fcxp_tx_plog(struct bfa_s *bfa, u32 reqlen, - struct bfa_fcxp_s *fcxp, struct fchs_s *fchs); -static void bfa_fcxp_qresume(void *cbarg); -static void bfa_fcxp_queue(struct bfa_fcxp_s *fcxp, - struct bfi_fcxp_send_req_s *send_req); - -/** - * fcxp_pvt BFA FCXP private functions - */ - -static void -claim_fcxp_req_rsp_mem(struct bfa_fcxp_mod_s *mod, struct bfa_meminfo_s *mi) -{ - u8 *dm_kva = NULL; - u64 dm_pa; - u32 buf_pool_sz; - - dm_kva = bfa_meminfo_dma_virt(mi); - dm_pa = bfa_meminfo_dma_phys(mi); - - buf_pool_sz = mod->req_pld_sz * mod->num_fcxps; - - /* - * Initialize the fcxp req payload list - */ - mod->req_pld_list_kva = dm_kva; - mod->req_pld_list_pa = dm_pa; - dm_kva += buf_pool_sz; - dm_pa += buf_pool_sz; - bfa_os_memset(mod->req_pld_list_kva, 0, buf_pool_sz); - - /* - * Initialize the fcxp rsp payload list - */ - buf_pool_sz = mod->rsp_pld_sz * mod->num_fcxps; - mod->rsp_pld_list_kva = dm_kva; - mod->rsp_pld_list_pa = dm_pa; - dm_kva += buf_pool_sz; - dm_pa += buf_pool_sz; - bfa_os_memset(mod->rsp_pld_list_kva, 0, buf_pool_sz); - - bfa_meminfo_dma_virt(mi) = dm_kva; - bfa_meminfo_dma_phys(mi) = dm_pa; -} - -static void -claim_fcxps_mem(struct bfa_fcxp_mod_s *mod, struct bfa_meminfo_s *mi) -{ - u16 i; - struct bfa_fcxp_s *fcxp; - - fcxp = (struct bfa_fcxp_s *) bfa_meminfo_kva(mi); - bfa_os_memset(fcxp, 0, sizeof(struct bfa_fcxp_s) * mod->num_fcxps); - - INIT_LIST_HEAD(&mod->fcxp_free_q); - INIT_LIST_HEAD(&mod->fcxp_active_q); - - mod->fcxp_list = fcxp; - - for (i = 0; i < mod->num_fcxps; i++) { - fcxp->fcxp_mod = mod; - fcxp->fcxp_tag = i; - - list_add_tail(&fcxp->qe, &mod->fcxp_free_q); - bfa_reqq_winit(&fcxp->reqq_wqe, bfa_fcxp_qresume, fcxp); - fcxp->reqq_waiting = BFA_FALSE; - - fcxp = fcxp + 1; - } - - bfa_meminfo_kva(mi) = (void *)fcxp; -} - -static void -bfa_fcxp_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len, - u32 *dm_len) -{ - u16 num_fcxp_reqs = cfg->fwcfg.num_fcxp_reqs; - - if (num_fcxp_reqs == 0) - return; - - /* - * Account for req/rsp payload - */ - *dm_len += BFA_FCXP_MAX_IBUF_SZ * num_fcxp_reqs; - if (cfg->drvcfg.min_cfg) - *dm_len += BFA_FCXP_MAX_IBUF_SZ * num_fcxp_reqs; - else - *dm_len += BFA_FCXP_MAX_LBUF_SZ * num_fcxp_reqs; - - /* - * Account for fcxp structs - */ - *ndm_len += sizeof(struct bfa_fcxp_s) * num_fcxp_reqs; -} - -static void -bfa_fcxp_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, - struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev) -{ - struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa); - - bfa_os_memset(mod, 0, sizeof(struct bfa_fcxp_mod_s)); - mod->bfa = bfa; - mod->num_fcxps = cfg->fwcfg.num_fcxp_reqs; - - /** - * Initialize FCXP request and response payload sizes. - */ - mod->req_pld_sz = mod->rsp_pld_sz = BFA_FCXP_MAX_IBUF_SZ; - if (!cfg->drvcfg.min_cfg) - mod->rsp_pld_sz = BFA_FCXP_MAX_LBUF_SZ; - - INIT_LIST_HEAD(&mod->wait_q); - - claim_fcxp_req_rsp_mem(mod, meminfo); - claim_fcxps_mem(mod, meminfo); -} - -static void -bfa_fcxp_detach(struct bfa_s *bfa) -{ -} - -static void -bfa_fcxp_start(struct bfa_s *bfa) -{ -} - -static void -bfa_fcxp_stop(struct bfa_s *bfa) -{ -} - -static void -bfa_fcxp_iocdisable(struct bfa_s *bfa) -{ - struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa); - struct bfa_fcxp_s *fcxp; - struct list_head *qe, *qen; - - list_for_each_safe(qe, qen, &mod->fcxp_active_q) { - fcxp = (struct bfa_fcxp_s *) qe; - if (fcxp->caller == NULL) { - fcxp->send_cbfn(fcxp->caller, fcxp, fcxp->send_cbarg, - BFA_STATUS_IOC_FAILURE, 0, 0, NULL); - bfa_fcxp_free(fcxp); - } else { - fcxp->rsp_status = BFA_STATUS_IOC_FAILURE; - bfa_cb_queue(bfa, &fcxp->hcb_qe, - __bfa_fcxp_send_cbfn, fcxp); - } - } -} - -static struct bfa_fcxp_s * -bfa_fcxp_get(struct bfa_fcxp_mod_s *fm) -{ - struct bfa_fcxp_s *fcxp; - - bfa_q_deq(&fm->fcxp_free_q, &fcxp); - - if (fcxp) - list_add_tail(&fcxp->qe, &fm->fcxp_active_q); - - return fcxp; -} - -static void -bfa_fcxp_put(struct bfa_fcxp_s *fcxp) -{ - struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod; - struct bfa_fcxp_wqe_s *wqe; - - bfa_q_deq(&mod->wait_q, &wqe); - if (wqe) { - bfa_trc(mod->bfa, fcxp->fcxp_tag); - wqe->alloc_cbfn(wqe->alloc_cbarg, fcxp); - return; - } - - bfa_assert(bfa_q_is_on_q(&mod->fcxp_active_q, fcxp)); - list_del(&fcxp->qe); - list_add_tail(&fcxp->qe, &mod->fcxp_free_q); -} - -static void -bfa_fcxp_null_comp(void *bfad_fcxp, struct bfa_fcxp_s *fcxp, void *cbarg, - bfa_status_t req_status, u32 rsp_len, - u32 resid_len, struct fchs_s *rsp_fchs) -{ - /* discarded fcxp completion */ -} - -static void -__bfa_fcxp_send_cbfn(void *cbarg, bfa_boolean_t complete) -{ - struct bfa_fcxp_s *fcxp = cbarg; - - if (complete) { - fcxp->send_cbfn(fcxp->caller, fcxp, fcxp->send_cbarg, - fcxp->rsp_status, fcxp->rsp_len, - fcxp->residue_len, &fcxp->rsp_fchs); - } else { - bfa_fcxp_free(fcxp); - } -} - -static void -hal_fcxp_send_comp(struct bfa_s *bfa, struct bfi_fcxp_send_rsp_s *fcxp_rsp) -{ - struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa); - struct bfa_fcxp_s *fcxp; - u16 fcxp_tag = bfa_os_ntohs(fcxp_rsp->fcxp_tag); - - bfa_trc(bfa, fcxp_tag); - - fcxp_rsp->rsp_len = bfa_os_ntohl(fcxp_rsp->rsp_len); - - /** - * @todo f/w should not set residue to non-0 when everything - * is received. - */ - if (fcxp_rsp->req_status == BFA_STATUS_OK) - fcxp_rsp->residue_len = 0; - else - fcxp_rsp->residue_len = bfa_os_ntohl(fcxp_rsp->residue_len); - - fcxp = BFA_FCXP_FROM_TAG(mod, fcxp_tag); - - bfa_assert(fcxp->send_cbfn != NULL); - - hal_fcxp_rx_plog(mod->bfa, fcxp, fcxp_rsp); - - if (fcxp->send_cbfn != NULL) { - if (fcxp->caller == NULL) { - bfa_trc(mod->bfa, fcxp->fcxp_tag); - - fcxp->send_cbfn(fcxp->caller, fcxp, fcxp->send_cbarg, - fcxp_rsp->req_status, fcxp_rsp->rsp_len, - fcxp_rsp->residue_len, &fcxp_rsp->fchs); - /* - * fcxp automatically freed on return from the callback - */ - bfa_fcxp_free(fcxp); - } else { - bfa_trc(mod->bfa, fcxp->fcxp_tag); - fcxp->rsp_status = fcxp_rsp->req_status; - fcxp->rsp_len = fcxp_rsp->rsp_len; - fcxp->residue_len = fcxp_rsp->residue_len; - fcxp->rsp_fchs = fcxp_rsp->fchs; - - bfa_cb_queue(bfa, &fcxp->hcb_qe, - __bfa_fcxp_send_cbfn, fcxp); - } - } else { - bfa_trc(bfa, fcxp_tag); - } -} - -static void -hal_fcxp_set_local_sges(struct bfi_sge_s *sge, u32 reqlen, u64 req_pa) -{ - union bfi_addr_u sga_zero = { {0} }; - - sge->sg_len = reqlen; - sge->flags = BFI_SGE_DATA_LAST; - bfa_dma_addr_set(sge[0].sga, req_pa); - bfa_sge_to_be(sge); - sge++; - - sge->sga = sga_zero; - sge->sg_len = reqlen; - sge->flags = BFI_SGE_PGDLEN; - bfa_sge_to_be(sge); -} - -static void -hal_fcxp_tx_plog(struct bfa_s *bfa, u32 reqlen, struct bfa_fcxp_s *fcxp, - struct fchs_s *fchs) -{ - /* - * TODO: TX ox_id - */ - if (reqlen > 0) { - if (fcxp->use_ireqbuf) { - u32 pld_w0 = - *((u32 *) BFA_FCXP_REQ_PLD(fcxp)); - - bfa_plog_fchdr_and_pl(bfa->plog, BFA_PL_MID_HAL_FCXP, - BFA_PL_EID_TX, - reqlen + sizeof(struct fchs_s), fchs, pld_w0); - } else { - bfa_plog_fchdr(bfa->plog, BFA_PL_MID_HAL_FCXP, - BFA_PL_EID_TX, reqlen + sizeof(struct fchs_s), - fchs); - } - } else { - bfa_plog_fchdr(bfa->plog, BFA_PL_MID_HAL_FCXP, BFA_PL_EID_TX, - reqlen + sizeof(struct fchs_s), fchs); - } -} - -static void -hal_fcxp_rx_plog(struct bfa_s *bfa, struct bfa_fcxp_s *fcxp, - struct bfi_fcxp_send_rsp_s *fcxp_rsp) -{ - if (fcxp_rsp->rsp_len > 0) { - if (fcxp->use_irspbuf) { - u32 pld_w0 = - *((u32 *) BFA_FCXP_RSP_PLD(fcxp)); - - bfa_plog_fchdr_and_pl(bfa->plog, BFA_PL_MID_HAL_FCXP, - BFA_PL_EID_RX, - (u16) fcxp_rsp->rsp_len, - &fcxp_rsp->fchs, pld_w0); - } else { - bfa_plog_fchdr(bfa->plog, BFA_PL_MID_HAL_FCXP, - BFA_PL_EID_RX, - (u16) fcxp_rsp->rsp_len, - &fcxp_rsp->fchs); - } - } else { - bfa_plog_fchdr(bfa->plog, BFA_PL_MID_HAL_FCXP, BFA_PL_EID_RX, - (u16) fcxp_rsp->rsp_len, &fcxp_rsp->fchs); - } -} - -/** - * Handler to resume sending fcxp when space in available in cpe queue. - */ -static void -bfa_fcxp_qresume(void *cbarg) -{ - struct bfa_fcxp_s *fcxp = cbarg; - struct bfa_s *bfa = fcxp->fcxp_mod->bfa; - struct bfi_fcxp_send_req_s *send_req; - - fcxp->reqq_waiting = BFA_FALSE; - send_req = bfa_reqq_next(bfa, BFA_REQQ_FCXP); - bfa_fcxp_queue(fcxp, send_req); -} - -/** - * Queue fcxp send request to foimrware. - */ -static void -bfa_fcxp_queue(struct bfa_fcxp_s *fcxp, struct bfi_fcxp_send_req_s *send_req) -{ - struct bfa_s *bfa = fcxp->fcxp_mod->bfa; - struct bfa_fcxp_req_info_s *reqi = &fcxp->req_info; - struct bfa_fcxp_rsp_info_s *rspi = &fcxp->rsp_info; - struct bfa_rport_s *rport = reqi->bfa_rport; - - bfi_h2i_set(send_req->mh, BFI_MC_FCXP, BFI_FCXP_H2I_SEND_REQ, - bfa_lpuid(bfa)); - - send_req->fcxp_tag = bfa_os_htons(fcxp->fcxp_tag); - if (rport) { - send_req->rport_fw_hndl = rport->fw_handle; - send_req->max_frmsz = bfa_os_htons(rport->rport_info.max_frmsz); - if (send_req->max_frmsz == 0) - send_req->max_frmsz = bfa_os_htons(FC_MAX_PDUSZ); - } else { - send_req->rport_fw_hndl = 0; - send_req->max_frmsz = bfa_os_htons(FC_MAX_PDUSZ); - } - - send_req->vf_id = bfa_os_htons(reqi->vf_id); - send_req->lp_tag = reqi->lp_tag; - send_req->class = reqi->class; - send_req->rsp_timeout = rspi->rsp_timeout; - send_req->cts = reqi->cts; - send_req->fchs = reqi->fchs; - - send_req->req_len = bfa_os_htonl(reqi->req_tot_len); - send_req->rsp_maxlen = bfa_os_htonl(rspi->rsp_maxlen); - - /* - * setup req sgles - */ - if (fcxp->use_ireqbuf == 1) { - hal_fcxp_set_local_sges(send_req->req_sge, reqi->req_tot_len, - BFA_FCXP_REQ_PLD_PA(fcxp)); - } else { - if (fcxp->nreq_sgles > 0) { - bfa_assert(fcxp->nreq_sgles == 1); - hal_fcxp_set_local_sges(send_req->req_sge, - reqi->req_tot_len, - fcxp->req_sga_cbfn(fcxp->caller, - 0)); - } else { - bfa_assert(reqi->req_tot_len == 0); - hal_fcxp_set_local_sges(send_req->rsp_sge, 0, 0); - } - } - - /* - * setup rsp sgles - */ - if (fcxp->use_irspbuf == 1) { - bfa_assert(rspi->rsp_maxlen <= BFA_FCXP_MAX_LBUF_SZ); - - hal_fcxp_set_local_sges(send_req->rsp_sge, rspi->rsp_maxlen, - BFA_FCXP_RSP_PLD_PA(fcxp)); - - } else { - if (fcxp->nrsp_sgles > 0) { - bfa_assert(fcxp->nrsp_sgles == 1); - hal_fcxp_set_local_sges(send_req->rsp_sge, - rspi->rsp_maxlen, - fcxp->rsp_sga_cbfn(fcxp->caller, - 0)); - } else { - bfa_assert(rspi->rsp_maxlen == 0); - hal_fcxp_set_local_sges(send_req->rsp_sge, 0, 0); - } - } - - hal_fcxp_tx_plog(bfa, reqi->req_tot_len, fcxp, &reqi->fchs); - - bfa_reqq_produce(bfa, BFA_REQQ_FCXP); - - bfa_trc(bfa, bfa_reqq_pi(bfa, BFA_REQQ_FCXP)); - bfa_trc(bfa, bfa_reqq_ci(bfa, BFA_REQQ_FCXP)); -} - - -/** - * hal_fcxp_api BFA FCXP API - */ - -/** - * Allocate an FCXP instance to send a response or to send a request - * that has a response. Request/response buffers are allocated by caller. - * - * @param[in] bfa BFA bfa instance - * @param[in] nreq_sgles Number of SG elements required for request - * buffer. 0, if fcxp internal buffers are used. - * Use bfa_fcxp_get_reqbuf() to get the - * internal req buffer. - * @param[in] req_sgles SG elements describing request buffer. Will be - * copied in by BFA and hence can be freed on - * return from this function. - * @param[in] get_req_sga function ptr to be called to get a request SG - * Address (given the sge index). - * @param[in] get_req_sglen function ptr to be called to get a request SG - * len (given the sge index). - * @param[in] get_rsp_sga function ptr to be called to get a response SG - * Address (given the sge index). - * @param[in] get_rsp_sglen function ptr to be called to get a response SG - * len (given the sge index). - * - * @return FCXP instance. NULL on failure. - */ -struct bfa_fcxp_s * -bfa_fcxp_alloc(void *caller, struct bfa_s *bfa, int nreq_sgles, - int nrsp_sgles, bfa_fcxp_get_sgaddr_t req_sga_cbfn, - bfa_fcxp_get_sglen_t req_sglen_cbfn, - bfa_fcxp_get_sgaddr_t rsp_sga_cbfn, - bfa_fcxp_get_sglen_t rsp_sglen_cbfn) -{ - struct bfa_fcxp_s *fcxp = NULL; - u32 nreq_sgpg, nrsp_sgpg; - - bfa_assert(bfa != NULL); - - fcxp = bfa_fcxp_get(BFA_FCXP_MOD(bfa)); - if (fcxp == NULL) - return NULL; - - bfa_trc(bfa, fcxp->fcxp_tag); - - fcxp->caller = caller; - - if (nreq_sgles == 0) { - fcxp->use_ireqbuf = 1; - } else { - bfa_assert(req_sga_cbfn != NULL); - bfa_assert(req_sglen_cbfn != NULL); - - fcxp->use_ireqbuf = 0; - fcxp->req_sga_cbfn = req_sga_cbfn; - fcxp->req_sglen_cbfn = req_sglen_cbfn; - - fcxp->nreq_sgles = nreq_sgles; - - /* - * alloc required sgpgs - */ - if (nreq_sgles > BFI_SGE_INLINE) { - nreq_sgpg = BFA_SGPG_NPAGE(nreq_sgles); - - if (bfa_sgpg_malloc(bfa, &fcxp->req_sgpg_q, nreq_sgpg) - != BFA_STATUS_OK) { - /* - * TODO - */ - } - } - } - - if (nrsp_sgles == 0) { - fcxp->use_irspbuf = 1; - } else { - bfa_assert(rsp_sga_cbfn != NULL); - bfa_assert(rsp_sglen_cbfn != NULL); - - fcxp->use_irspbuf = 0; - fcxp->rsp_sga_cbfn = rsp_sga_cbfn; - fcxp->rsp_sglen_cbfn = rsp_sglen_cbfn; - - fcxp->nrsp_sgles = nrsp_sgles; - /* - * alloc required sgpgs - */ - if (nrsp_sgles > BFI_SGE_INLINE) { - nrsp_sgpg = BFA_SGPG_NPAGE(nreq_sgles); - - if (bfa_sgpg_malloc - (bfa, &fcxp->rsp_sgpg_q, nrsp_sgpg) - != BFA_STATUS_OK) { - /* bfa_sgpg_wait(bfa, &fcxp->rsp_sgpg_wqe, - nrsp_sgpg); */ - /* - * TODO - */ - } - } - } - - return fcxp; -} - -/** - * Get the internal request buffer pointer - * - * @param[in] fcxp BFA fcxp pointer - * - * @return pointer to the internal request buffer - */ -void * -bfa_fcxp_get_reqbuf(struct bfa_fcxp_s *fcxp) -{ - struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod; - void *reqbuf; - - bfa_assert(fcxp->use_ireqbuf == 1); - reqbuf = ((u8 *)mod->req_pld_list_kva) + - fcxp->fcxp_tag * mod->req_pld_sz; - return reqbuf; -} - -u32 -bfa_fcxp_get_reqbufsz(struct bfa_fcxp_s *fcxp) -{ - struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod; - - return mod->req_pld_sz; -} - -/** - * Get the internal response buffer pointer - * - * @param[in] fcxp BFA fcxp pointer - * - * @return pointer to the internal request buffer - */ -void * -bfa_fcxp_get_rspbuf(struct bfa_fcxp_s *fcxp) -{ - struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod; - void *rspbuf; - - bfa_assert(fcxp->use_irspbuf == 1); - - rspbuf = ((u8 *)mod->rsp_pld_list_kva) + - fcxp->fcxp_tag * mod->rsp_pld_sz; - return rspbuf; -} - -/** - * Free the BFA FCXP - * - * @param[in] fcxp BFA fcxp pointer - * - * @return void - */ -void -bfa_fcxp_free(struct bfa_fcxp_s *fcxp) -{ - struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod; - - bfa_assert(fcxp != NULL); - bfa_trc(mod->bfa, fcxp->fcxp_tag); - bfa_fcxp_put(fcxp); -} - -/** - * Send a FCXP request - * - * @param[in] fcxp BFA fcxp pointer - * @param[in] rport BFA rport pointer. Could be left NULL for WKA rports - * @param[in] vf_id virtual Fabric ID - * @param[in] lp_tag lport tag - * @param[in] cts use Continous sequence - * @param[in] cos fc Class of Service - * @param[in] reqlen request length, does not include FCHS length - * @param[in] fchs fc Header Pointer. The header content will be copied - * in by BFA. - * - * @param[in] cbfn call back function to be called on receiving - * the response - * @param[in] cbarg arg for cbfn - * @param[in] rsp_timeout - * response timeout - * - * @return bfa_status_t - */ -void -bfa_fcxp_send(struct bfa_fcxp_s *fcxp, struct bfa_rport_s *rport, - u16 vf_id, u8 lp_tag, bfa_boolean_t cts, enum fc_cos cos, - u32 reqlen, struct fchs_s *fchs, bfa_cb_fcxp_send_t cbfn, - void *cbarg, u32 rsp_maxlen, u8 rsp_timeout) -{ - struct bfa_s *bfa = fcxp->fcxp_mod->bfa; - struct bfa_fcxp_req_info_s *reqi = &fcxp->req_info; - struct bfa_fcxp_rsp_info_s *rspi = &fcxp->rsp_info; - struct bfi_fcxp_send_req_s *send_req; - - bfa_trc(bfa, fcxp->fcxp_tag); - - /** - * setup request/response info - */ - reqi->bfa_rport = rport; - reqi->vf_id = vf_id; - reqi->lp_tag = lp_tag; - reqi->class = cos; - rspi->rsp_timeout = rsp_timeout; - reqi->cts = cts; - reqi->fchs = *fchs; - reqi->req_tot_len = reqlen; - rspi->rsp_maxlen = rsp_maxlen; - fcxp->send_cbfn = cbfn ? cbfn : bfa_fcxp_null_comp; - fcxp->send_cbarg = cbarg; - - /** - * If no room in CPE queue, wait for space in request queue - */ - send_req = bfa_reqq_next(bfa, BFA_REQQ_FCXP); - if (!send_req) { - bfa_trc(bfa, fcxp->fcxp_tag); - fcxp->reqq_waiting = BFA_TRUE; - bfa_reqq_wait(bfa, BFA_REQQ_FCXP, &fcxp->reqq_wqe); - return; - } - - bfa_fcxp_queue(fcxp, send_req); -} - -/** - * Abort a BFA FCXP - * - * @param[in] fcxp BFA fcxp pointer - * - * @return void - */ -bfa_status_t -bfa_fcxp_abort(struct bfa_fcxp_s *fcxp) -{ - bfa_assert(0); - return BFA_STATUS_OK; -} - -void -bfa_fcxp_alloc_wait(struct bfa_s *bfa, struct bfa_fcxp_wqe_s *wqe, - bfa_fcxp_alloc_cbfn_t alloc_cbfn, void *alloc_cbarg) -{ - struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa); - - bfa_assert(list_empty(&mod->fcxp_free_q)); - - wqe->alloc_cbfn = alloc_cbfn; - wqe->alloc_cbarg = alloc_cbarg; - list_add_tail(&wqe->qe, &mod->wait_q); -} - -void -bfa_fcxp_walloc_cancel(struct bfa_s *bfa, struct bfa_fcxp_wqe_s *wqe) -{ - struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa); - - bfa_assert(bfa_q_is_on_q(&mod->wait_q, wqe)); - list_del(&wqe->qe); -} - -void -bfa_fcxp_discard(struct bfa_fcxp_s *fcxp) -{ - /** - * If waiting for room in request queue, cancel reqq wait - * and free fcxp. - */ - if (fcxp->reqq_waiting) { - fcxp->reqq_waiting = BFA_FALSE; - bfa_reqq_wcancel(&fcxp->reqq_wqe); - bfa_fcxp_free(fcxp); - return; - } - - fcxp->send_cbfn = bfa_fcxp_null_comp; -} - - - -/** - * hal_fcxp_public BFA FCXP public functions - */ - -void -bfa_fcxp_isr(struct bfa_s *bfa, struct bfi_msg_s *msg) -{ - switch (msg->mhdr.msg_id) { - case BFI_FCXP_I2H_SEND_RSP: - hal_fcxp_send_comp(bfa, (struct bfi_fcxp_send_rsp_s *) msg); - break; - - default: - bfa_trc(bfa, msg->mhdr.msg_id); - bfa_assert(0); - } -} - -u32 -bfa_fcxp_get_maxrsp(struct bfa_s *bfa) -{ - struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa); - - return mod->rsp_pld_sz; -} - - diff --git a/drivers/scsi/bfa/bfa_fcxp_priv.h b/drivers/scsi/bfa/bfa_fcxp_priv.h deleted file mode 100644 index 4cda49397da0..000000000000 --- a/drivers/scsi/bfa/bfa_fcxp_priv.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFA_FCXP_PRIV_H__ -#define __BFA_FCXP_PRIV_H__ - -#include <cs/bfa_sm.h> -#include <protocol/fc.h> -#include <bfa_svc.h> -#include <bfi/bfi_fcxp.h> - -#define BFA_FCXP_MIN (1) -#define BFA_FCXP_MAX_IBUF_SZ (2 * 1024 + 256) -#define BFA_FCXP_MAX_LBUF_SZ (4 * 1024 + 256) - -struct bfa_fcxp_mod_s { - struct bfa_s *bfa; /* backpointer to BFA */ - struct bfa_fcxp_s *fcxp_list; /* array of FCXPs */ - u16 num_fcxps; /* max num FCXP requests */ - struct list_head fcxp_free_q; /* free FCXPs */ - struct list_head fcxp_active_q; /* active FCXPs */ - void *req_pld_list_kva; /* list of FCXP req pld */ - u64 req_pld_list_pa; /* list of FCXP req pld */ - void *rsp_pld_list_kva; /* list of FCXP resp pld */ - u64 rsp_pld_list_pa; /* list of FCXP resp pld */ - struct list_head wait_q; /* wait queue for free fcxp */ - u32 req_pld_sz; - u32 rsp_pld_sz; -}; - -#define BFA_FCXP_MOD(__bfa) (&(__bfa)->modules.fcxp_mod) -#define BFA_FCXP_FROM_TAG(__mod, __tag) (&(__mod)->fcxp_list[__tag]) - -typedef void (*fcxp_send_cb_t) (struct bfa_s *ioc, struct bfa_fcxp_s *fcxp, - void *cb_arg, bfa_status_t req_status, - u32 rsp_len, u32 resid_len, - struct fchs_s *rsp_fchs); - -/** - * Information needed for a FCXP request - */ -struct bfa_fcxp_req_info_s { - struct bfa_rport_s *bfa_rport; /* Pointer to the bfa rport that was - *returned from bfa_rport_create(). - *This could be left NULL for WKA or for - *FCXP interactions before the rport - *nexus is established - */ - struct fchs_s fchs; /* request FC header structure */ - u8 cts; /* continous sequence */ - u8 class; /* FC class for the request/response */ - u16 max_frmsz; /* max send frame size */ - u16 vf_id; /* vsan tag if applicable */ - u8 lp_tag; /* lport tag */ - u32 req_tot_len; /* request payload total length */ -}; - -struct bfa_fcxp_rsp_info_s { - struct fchs_s rsp_fchs; /* Response frame's FC header will - * be *sent back in this field */ - u8 rsp_timeout; /* timeout in seconds, 0-no response - */ - u8 rsvd2[3]; - u32 rsp_maxlen; /* max response length expected */ -}; - -struct bfa_fcxp_s { - struct list_head qe; /* fcxp queue element */ - bfa_sm_t sm; /* state machine */ - void *caller; /* driver or fcs */ - struct bfa_fcxp_mod_s *fcxp_mod; - /* back pointer to fcxp mod */ - u16 fcxp_tag; /* internal tag */ - struct bfa_fcxp_req_info_s req_info; - /* request info */ - struct bfa_fcxp_rsp_info_s rsp_info; - /* response info */ - u8 use_ireqbuf; /* use internal req buf */ - u8 use_irspbuf; /* use internal rsp buf */ - u32 nreq_sgles; /* num request SGLEs */ - u32 nrsp_sgles; /* num response SGLEs */ - struct list_head req_sgpg_q; /* SG pages for request buf */ - struct list_head req_sgpg_wqe; /* wait queue for req SG page */ - struct list_head rsp_sgpg_q; /* SG pages for response buf */ - struct list_head rsp_sgpg_wqe; /* wait queue for rsp SG page */ - - bfa_fcxp_get_sgaddr_t req_sga_cbfn; - /* SG elem addr user function */ - bfa_fcxp_get_sglen_t req_sglen_cbfn; - /* SG elem len user function */ - bfa_fcxp_get_sgaddr_t rsp_sga_cbfn; - /* SG elem addr user function */ - bfa_fcxp_get_sglen_t rsp_sglen_cbfn; - /* SG elem len user function */ - bfa_cb_fcxp_send_t send_cbfn; /* send completion callback */ - void *send_cbarg; /* callback arg */ - struct bfa_sge_s req_sge[BFA_FCXP_MAX_SGES]; - /* req SG elems */ - struct bfa_sge_s rsp_sge[BFA_FCXP_MAX_SGES]; - /* rsp SG elems */ - u8 rsp_status; /* comp: rsp status */ - u32 rsp_len; /* comp: actual response len */ - u32 residue_len; /* comp: residual rsp length */ - struct fchs_s rsp_fchs; /* comp: response fchs */ - struct bfa_cb_qe_s hcb_qe; /* comp: callback qelem */ - struct bfa_reqq_wait_s reqq_wqe; - bfa_boolean_t reqq_waiting; -}; - -#define BFA_FCXP_REQ_PLD(_fcxp) (bfa_fcxp_get_reqbuf(_fcxp)) - -#define BFA_FCXP_RSP_FCHS(_fcxp) (&((_fcxp)->rsp_info.fchs)) -#define BFA_FCXP_RSP_PLD(_fcxp) (bfa_fcxp_get_rspbuf(_fcxp)) - -#define BFA_FCXP_REQ_PLD_PA(_fcxp) \ - ((_fcxp)->fcxp_mod->req_pld_list_pa + \ - ((_fcxp)->fcxp_mod->req_pld_sz * (_fcxp)->fcxp_tag)) - -#define BFA_FCXP_RSP_PLD_PA(_fcxp) \ - ((_fcxp)->fcxp_mod->rsp_pld_list_pa + \ - ((_fcxp)->fcxp_mod->rsp_pld_sz * (_fcxp)->fcxp_tag)) - -void bfa_fcxp_isr(struct bfa_s *bfa, struct bfi_msg_s *msg); -#endif /* __BFA_FCXP_PRIV_H__ */ diff --git a/drivers/scsi/bfa/bfa_fwimg_priv.h b/drivers/scsi/bfa/bfa_fwimg_priv.h deleted file mode 100644 index d33e19e54395..000000000000 --- a/drivers/scsi/bfa/bfa_fwimg_priv.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFA_FWIMG_PRIV_H__ -#define __BFA_FWIMG_PRIV_H__ - -#define BFI_FLASH_CHUNK_SZ 256 /* Flash chunk size */ -#define BFI_FLASH_CHUNK_SZ_WORDS (BFI_FLASH_CHUNK_SZ/sizeof(u32)) - -/** - * 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_hw_cb.c b/drivers/scsi/bfa/bfa_hw_cb.c index edfd729445cf..c787d3af0886 100644 --- a/drivers/scsi/bfa/bfa_hw_cb.c +++ b/drivers/scsi/bfa/bfa_hw_cb.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. * All rights reserved * www.brocade.com * @@ -15,15 +15,15 @@ * General Public License for more details. */ -#include <bfa_priv.h> -#include <bfi/bfi_cbreg.h> +#include "bfa_modules.h" +#include "bfi_cbreg.h" void bfa_hwcb_reginit(struct bfa_s *bfa) { struct bfa_iocfc_regs_s *bfa_regs = &bfa->iocfc.bfa_regs; bfa_os_addr_t kva = bfa_ioc_bar0(&bfa->ioc); - int i, q, fn = bfa_ioc_pcifn(&bfa->ioc); + int i, q, fn = bfa_ioc_pcifn(&bfa->ioc); if (fn == 0) { bfa_regs->intr_status = (kva + HOSTFN0_INT_STATUS); diff --git a/drivers/scsi/bfa/bfa_hw_ct.c b/drivers/scsi/bfa/bfa_hw_ct.c index a357fb3066fd..c97ebafec5ea 100644 --- a/drivers/scsi/bfa/bfa_hw_ct.c +++ b/drivers/scsi/bfa/bfa_hw_ct.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. * All rights reserved * www.brocade.com * @@ -15,9 +15,8 @@ * General Public License for more details. */ -#include <bfa_priv.h> -#include <bfi/bfi_ctreg.h> -#include <bfa_ioc.h> +#include "bfa_modules.h" +#include "bfi_ctreg.h" BFA_TRC_FILE(HAL, IOCFC_CT); @@ -53,7 +52,7 @@ bfa_hwct_reginit(struct bfa_s *bfa) { struct bfa_iocfc_regs_s *bfa_regs = &bfa->iocfc.bfa_regs; bfa_os_addr_t kva = bfa_ioc_bar0(&bfa->ioc); - int i, q, fn = bfa_ioc_pcifn(&bfa->ioc); + int i, q, fn = bfa_ioc_pcifn(&bfa->ioc); if (fn == 0) { bfa_regs->intr_status = (kva + HOSTFN0_INT_STATUS); @@ -87,7 +86,7 @@ bfa_hwct_reginit(struct bfa_s *bfa) void bfa_hwct_reqq_ack(struct bfa_s *bfa, int reqq) { - u32 r32; + u32 r32; r32 = bfa_reg_read(bfa->iocfc.bfa_regs.cpe_q_ctrl[reqq]); bfa_reg_write(bfa->iocfc.bfa_regs.cpe_q_ctrl[reqq], r32); diff --git a/drivers/scsi/bfa/bfa_intr.c b/drivers/scsi/bfa/bfa_intr.c deleted file mode 100644 index 493678889b24..000000000000 --- a/drivers/scsi/bfa/bfa_intr.c +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ -#include <bfa.h> -#include <bfi/bfi_ctreg.h> -#include <bfa_port_priv.h> -#include <bfa_intr_priv.h> -#include <cs/bfa_debug.h> - -BFA_TRC_FILE(HAL, INTR); - -static void -bfa_msix_errint(struct bfa_s *bfa, u32 intr) -{ - bfa_ioc_error_isr(&bfa->ioc); -} - -static void -bfa_msix_lpu(struct bfa_s *bfa) -{ - bfa_ioc_mbox_isr(&bfa->ioc); -} - -static void -bfa_reqq_resume(struct bfa_s *bfa, int qid) -{ - struct list_head *waitq, *qe, *qen; - struct bfa_reqq_wait_s *wqe; - - waitq = bfa_reqq(bfa, qid); - list_for_each_safe(qe, qen, waitq) { - /** - * Callback only as long as there is room in request queue - */ - if (bfa_reqq_full(bfa, qid)) - break; - - list_del(qe); - wqe = (struct bfa_reqq_wait_s *) qe; - wqe->qresume(wqe->cbarg); - } -} - -void -bfa_msix_all(struct bfa_s *bfa, int vec) -{ - bfa_intx(bfa); -} - -/** - * hal_intr_api - */ -bfa_boolean_t -bfa_intx(struct bfa_s *bfa) -{ - u32 intr, qintr; - int queue; - - intr = bfa_reg_read(bfa->iocfc.bfa_regs.intr_status); - if (!intr) - return BFA_FALSE; - - /** - * RME completion queue interrupt - */ - qintr = intr & __HFN_INT_RME_MASK; - bfa_reg_write(bfa->iocfc.bfa_regs.intr_status, qintr); - - for (queue = 0; queue < BFI_IOC_MAX_CQS_ASIC; queue++) { - if (intr & (__HFN_INT_RME_Q0 << queue)) - bfa_msix_rspq(bfa, queue & (BFI_IOC_MAX_CQS - 1)); - } - intr &= ~qintr; - if (!intr) - return BFA_TRUE; - - /** - * CPE completion queue interrupt - */ - qintr = intr & __HFN_INT_CPE_MASK; - bfa_reg_write(bfa->iocfc.bfa_regs.intr_status, qintr); - - for (queue = 0; queue < BFI_IOC_MAX_CQS_ASIC; queue++) { - if (intr & (__HFN_INT_CPE_Q0 << queue)) - bfa_msix_reqq(bfa, queue & (BFI_IOC_MAX_CQS - 1)); - } - intr &= ~qintr; - if (!intr) - return BFA_TRUE; - - bfa_msix_lpu_err(bfa, intr); - - return BFA_TRUE; -} - -void -bfa_isr_enable(struct bfa_s *bfa) -{ - u32 intr_unmask; - int pci_func = bfa_ioc_pcifn(&bfa->ioc); - - bfa_trc(bfa, pci_func); - - bfa_msix_install(bfa); - intr_unmask = (__HFN_INT_ERR_EMC | __HFN_INT_ERR_LPU0 | - __HFN_INT_ERR_LPU1 | __HFN_INT_ERR_PSS | - __HFN_INT_LL_HALT); - - if (pci_func == 0) - intr_unmask |= (__HFN_INT_CPE_Q0 | __HFN_INT_CPE_Q1 | - __HFN_INT_CPE_Q2 | __HFN_INT_CPE_Q3 | - __HFN_INT_RME_Q0 | __HFN_INT_RME_Q1 | - __HFN_INT_RME_Q2 | __HFN_INT_RME_Q3 | - __HFN_INT_MBOX_LPU0); - else - intr_unmask |= (__HFN_INT_CPE_Q4 | __HFN_INT_CPE_Q5 | - __HFN_INT_CPE_Q6 | __HFN_INT_CPE_Q7 | - __HFN_INT_RME_Q4 | __HFN_INT_RME_Q5 | - __HFN_INT_RME_Q6 | __HFN_INT_RME_Q7 | - __HFN_INT_MBOX_LPU1); - - bfa_reg_write(bfa->iocfc.bfa_regs.intr_status, intr_unmask); - bfa_reg_write(bfa->iocfc.bfa_regs.intr_mask, ~intr_unmask); - bfa->iocfc.intr_mask = ~intr_unmask; - bfa_isr_mode_set(bfa, bfa->msix.nvecs != 0); -} - -void -bfa_isr_disable(struct bfa_s *bfa) -{ - bfa_isr_mode_set(bfa, BFA_FALSE); - bfa_reg_write(bfa->iocfc.bfa_regs.intr_mask, -1L); - bfa_msix_uninstall(bfa); -} - -void -bfa_msix_reqq(struct bfa_s *bfa, int qid) -{ - struct list_head *waitq; - - qid &= (BFI_IOC_MAX_CQS - 1); - - bfa->iocfc.hwif.hw_reqq_ack(bfa, qid); - - /** - * Resume any pending requests in the corresponding reqq. - */ - waitq = bfa_reqq(bfa, qid); - if (!list_empty(waitq)) - bfa_reqq_resume(bfa, qid); -} - -void -bfa_isr_unhandled(struct bfa_s *bfa, struct bfi_msg_s *m) -{ - bfa_trc(bfa, m->mhdr.msg_class); - bfa_trc(bfa, m->mhdr.msg_id); - bfa_trc(bfa, m->mhdr.mtag.i2htok); - bfa_assert(0); - bfa_trc_stop(bfa->trcmod); -} - -void -bfa_msix_rspq(struct bfa_s *bfa, int qid) -{ - struct bfi_msg_s *m; - u32 pi, ci; - struct list_head *waitq; - - bfa_trc_fp(bfa, qid); - - qid &= (BFI_IOC_MAX_CQS - 1); - - bfa->iocfc.hwif.hw_rspq_ack(bfa, qid); - - ci = bfa_rspq_ci(bfa, qid); - pi = bfa_rspq_pi(bfa, qid); - - bfa_trc_fp(bfa, ci); - bfa_trc_fp(bfa, pi); - - if (bfa->rme_process) { - while (ci != pi) { - m = bfa_rspq_elem(bfa, qid, ci); - bfa_assert_fp(m->mhdr.msg_class < BFI_MC_MAX); - - bfa_isrs[m->mhdr.msg_class] (bfa, m); - - CQ_INCR(ci, bfa->iocfc.cfg.drvcfg.num_rspq_elems); - } - } - - /** - * update CI - */ - bfa_rspq_ci(bfa, qid) = pi; - bfa_reg_write(bfa->iocfc.bfa_regs.rme_q_ci[qid], pi); - bfa_os_mmiowb(); - - /** - * Resume any pending requests in the corresponding reqq. - */ - waitq = bfa_reqq(bfa, qid); - if (!list_empty(waitq)) - bfa_reqq_resume(bfa, qid); -} - -void -bfa_msix_lpu_err(struct bfa_s *bfa, int vec) -{ - u32 intr, curr_value; - - intr = bfa_reg_read(bfa->iocfc.bfa_regs.intr_status); - - if (intr & (__HFN_INT_MBOX_LPU0 | __HFN_INT_MBOX_LPU1)) - bfa_msix_lpu(bfa); - - intr &= (__HFN_INT_ERR_EMC | __HFN_INT_ERR_LPU0 | - __HFN_INT_ERR_LPU1 | __HFN_INT_ERR_PSS | __HFN_INT_LL_HALT); - - if (intr) { - if (intr & __HFN_INT_LL_HALT) { - /** - * If LL_HALT bit is set then FW Init Halt LL Port - * Register needs to be cleared as well so Interrupt - * Status Register will be cleared. - */ - curr_value = bfa_reg_read(bfa->ioc.ioc_regs.ll_halt); - curr_value &= ~__FW_INIT_HALT_P; - bfa_reg_write(bfa->ioc.ioc_regs.ll_halt, curr_value); - } - - if (intr & __HFN_INT_ERR_PSS) { - /** - * ERR_PSS bit needs to be cleared as well in case - * interrups are shared so driver's interrupt handler is - * still called eventhough it is already masked out. - */ - curr_value = bfa_reg_read( - bfa->ioc.ioc_regs.pss_err_status_reg); - curr_value &= __PSS_ERR_STATUS_SET; - bfa_reg_write(bfa->ioc.ioc_regs.pss_err_status_reg, - curr_value); - } - - bfa_reg_write(bfa->iocfc.bfa_regs.intr_status, intr); - bfa_msix_errint(bfa, intr); - } -} - -void -bfa_isr_bind(enum bfi_mclass mc, bfa_isr_func_t isr_func) -{ - bfa_isrs[mc] = isr_func; -} - - diff --git a/drivers/scsi/bfa/bfa_intr_priv.h b/drivers/scsi/bfa/bfa_intr_priv.h deleted file mode 100644 index 5fc301cf4d1b..000000000000 --- a/drivers/scsi/bfa/bfa_intr_priv.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFA_INTR_PRIV_H__ -#define __BFA_INTR_PRIV_H__ - -/** - * Message handler - */ -typedef void (*bfa_isr_func_t) (struct bfa_s *bfa, struct bfi_msg_s *m); -void bfa_isr_unhandled(struct bfa_s *bfa, struct bfi_msg_s *m); -void bfa_isr_bind(enum bfi_mclass mc, bfa_isr_func_t isr_func); - - -#define bfa_reqq_pi(__bfa, __reqq) ((__bfa)->iocfc.req_cq_pi[__reqq]) -#define bfa_reqq_ci(__bfa, __reqq) \ - (*(u32 *)((__bfa)->iocfc.req_cq_shadow_ci[__reqq].kva)) - -#define bfa_reqq_full(__bfa, __reqq) \ - (((bfa_reqq_pi(__bfa, __reqq) + 1) & \ - ((__bfa)->iocfc.cfg.drvcfg.num_reqq_elems - 1)) == \ - bfa_reqq_ci(__bfa, __reqq)) - -#define bfa_reqq_next(__bfa, __reqq) \ - (bfa_reqq_full(__bfa, __reqq) ? NULL : \ - ((void *)((struct bfi_msg_s *)((__bfa)->iocfc.req_cq_ba[__reqq].kva) \ - + bfa_reqq_pi((__bfa), (__reqq))))) - -#define bfa_reqq_produce(__bfa, __reqq) do { \ - (__bfa)->iocfc.req_cq_pi[__reqq]++; \ - (__bfa)->iocfc.req_cq_pi[__reqq] &= \ - ((__bfa)->iocfc.cfg.drvcfg.num_reqq_elems - 1); \ - bfa_reg_write((__bfa)->iocfc.bfa_regs.cpe_q_pi[__reqq], \ - (__bfa)->iocfc.req_cq_pi[__reqq]); \ - bfa_os_mmiowb(); \ -} while (0) - -#define bfa_rspq_pi(__bfa, __rspq) \ - (*(u32 *)((__bfa)->iocfc.rsp_cq_shadow_pi[__rspq].kva)) - -#define bfa_rspq_ci(__bfa, __rspq) ((__bfa)->iocfc.rsp_cq_ci[__rspq]) -#define bfa_rspq_elem(__bfa, __rspq, __ci) \ - (&((struct bfi_msg_s *)((__bfa)->iocfc.rsp_cq_ba[__rspq].kva))[__ci]) - -#define CQ_INCR(__index, __size) do { \ - (__index)++; \ - (__index) &= ((__size) - 1); \ -} while (0) - -/** - * Queue element to wait for room in request queue. FIFO order is - * maintained when fullfilling requests. - */ -struct bfa_reqq_wait_s { - struct list_head qe; - void (*qresume) (void *cbarg); - void *cbarg; -}; - -/** - * Circular queue usage assignments - */ -enum { - BFA_REQQ_IOC = 0, /* all low-priority IOC msgs */ - BFA_REQQ_FCXP = 0, /* all FCXP messages */ - BFA_REQQ_LPS = 0, /* all lport service msgs */ - BFA_REQQ_PORT = 0, /* all port messages */ - BFA_REQQ_FLASH = 0, /* for flash module */ - BFA_REQQ_DIAG = 0, /* for diag module */ - BFA_REQQ_RPORT = 0, /* all port messages */ - BFA_REQQ_SBOOT = 0, /* all san boot messages */ - BFA_REQQ_QOS_LO = 1, /* all low priority IO */ - BFA_REQQ_QOS_MD = 2, /* all medium priority IO */ - BFA_REQQ_QOS_HI = 3, /* all high priority IO */ -}; - -static inline void -bfa_reqq_winit(struct bfa_reqq_wait_s *wqe, void (*qresume) (void *cbarg), - void *cbarg) -{ - wqe->qresume = qresume; - wqe->cbarg = cbarg; -} - -#define bfa_reqq(__bfa, __reqq) (&(__bfa)->reqq_waitq[__reqq]) - -/** - * static inline void - * bfa_reqq_wait(struct bfa_s *bfa, int reqq, struct bfa_reqq_wait_s *wqe) - */ -#define bfa_reqq_wait(__bfa, __reqq, __wqe) do { \ - \ - struct list_head *waitq = bfa_reqq(__bfa, __reqq); \ - \ - bfa_assert(((__reqq) < BFI_IOC_MAX_CQS)); \ - bfa_assert((__wqe)->qresume && (__wqe)->cbarg); \ - \ - list_add_tail(&(__wqe)->qe, waitq); \ -} while (0) - -#define bfa_reqq_wcancel(__wqe) list_del(&(__wqe)->qe) - -#endif /* __BFA_INTR_PRIV_H__ */ diff --git a/drivers/scsi/bfa/bfa_ioc.c b/drivers/scsi/bfa/bfa_ioc.c index 8e78f20110a5..6795b247791a 100644 --- a/drivers/scsi/bfa/bfa_ioc.c +++ b/drivers/scsi/bfa/bfa_ioc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. * All rights reserved * www.brocade.com * @@ -15,35 +15,33 @@ * General Public License for more details. */ -#include <bfa.h> -#include <bfa_ioc.h> -#include <bfa_fwimg_priv.h> -#include <cna/bfa_cna_trcmod.h> -#include <cs/bfa_debug.h> -#include <bfi/bfi_ioc.h> -#include <bfi/bfi_ctreg.h> -#include <aen/bfa_aen_ioc.h> -#include <aen/bfa_aen.h> -#include <log/bfa_log_hal.h> -#include <defs/bfa_defs_pci.h> +#include "bfa_ioc.h" +#include "bfi_ctreg.h" +#include "bfa_defs.h" +#include "bfa_defs_svc.h" +#include "bfad_drv.h" BFA_TRC_FILE(CNA, IOC); /** * IOC local definitions */ -#define BFA_IOC_TOV 2000 /* msecs */ -#define BFA_IOC_HWSEM_TOV 500 /* msecs */ -#define BFA_IOC_HB_TOV 500 /* msecs */ -#define BFA_IOC_HWINIT_MAX 2 -#define BFA_IOC_FWIMG_MINSZ (16 * 1024) -#define BFA_IOC_TOV_RECOVER BFA_IOC_HB_TOV +#define BFA_IOC_TOV 3000 /* msecs */ +#define BFA_IOC_HWSEM_TOV 500 /* msecs */ +#define BFA_IOC_HB_TOV 500 /* msecs */ +#define BFA_IOC_HWINIT_MAX 2 +#define BFA_IOC_TOV_RECOVER BFA_IOC_HB_TOV #define bfa_ioc_timer_start(__ioc) \ bfa_timer_begin((__ioc)->timer_mod, &(__ioc)->ioc_timer, \ bfa_ioc_timeout, (__ioc), BFA_IOC_TOV) #define bfa_ioc_timer_stop(__ioc) bfa_timer_stop(&(__ioc)->ioc_timer) +#define bfa_hb_timer_start(__ioc) \ + bfa_timer_begin((__ioc)->timer_mod, &(__ioc)->hb_timer, \ + bfa_ioc_hb_check, (__ioc), BFA_IOC_HB_TOV) +#define bfa_hb_timer_stop(__ioc) bfa_timer_stop(&(__ioc)->hb_timer) + #define BFA_DBG_FWTRC_ENTS (BFI_IOC_TRC_ENTS) #define BFA_DBG_FWTRC_LEN \ (BFA_DBG_FWTRC_ENTS * sizeof(struct bfa_trc_s) + \ @@ -55,100 +53,226 @@ BFA_TRC_FILE(CNA, IOC); * Asic specific macros : see bfa_hw_cb.c and bfa_hw_ct.c for details. */ -#define bfa_ioc_firmware_lock(__ioc) \ +#define bfa_ioc_firmware_lock(__ioc) \ ((__ioc)->ioc_hwif->ioc_firmware_lock(__ioc)) -#define bfa_ioc_firmware_unlock(__ioc) \ +#define bfa_ioc_firmware_unlock(__ioc) \ ((__ioc)->ioc_hwif->ioc_firmware_unlock(__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) \ +#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; +#ifdef BFA_IOC_IS_UEFI +#define bfa_ioc_is_bios_optrom(__ioc) (0) +#define bfa_ioc_is_uefi(__ioc) BFA_IOC_IS_UEFI +#else +#define bfa_ioc_is_bios_optrom(__ioc) \ + (bfa_cb_image_get_size(BFA_IOC_FWIMG_TYPE(__ioc)) < BFA_IOC_FWIMG_MINSZ) +#define bfa_ioc_is_uefi(__ioc) (0) +#endif + +#define bfa_ioc_mbox_cmd_pending(__ioc) \ + (!list_empty(&((__ioc)->mbox_mod.cmd_q)) || \ + bfa_reg_read((__ioc)->ioc_regs.hfn_mbox_cmd)) + +bfa_boolean_t bfa_auto_recover = BFA_TRUE; /* * forward declarations */ -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); -static void bfa_ioc_timeout(void *ioc); -static void bfa_ioc_send_enable(struct bfa_ioc_s *ioc); -static void bfa_ioc_send_disable(struct bfa_ioc_s *ioc); -static void bfa_ioc_send_getattr(struct bfa_ioc_s *ioc); -static void bfa_ioc_hb_monitor(struct bfa_ioc_s *ioc); -static void bfa_ioc_hb_stop(struct bfa_ioc_s *ioc); -static void bfa_ioc_reset(struct bfa_ioc_s *ioc, bfa_boolean_t force); -static void bfa_ioc_mbox_poll(struct bfa_ioc_s *ioc); -static void bfa_ioc_mbox_hbfail(struct bfa_ioc_s *ioc); -static void bfa_ioc_recover(struct bfa_ioc_s *ioc); -static 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); +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); +static void bfa_ioc_timeout(void *ioc); +static void bfa_ioc_send_enable(struct bfa_ioc_s *ioc); +static void bfa_ioc_send_disable(struct bfa_ioc_s *ioc); +static void bfa_ioc_send_getattr(struct bfa_ioc_s *ioc); +static void bfa_ioc_hb_monitor(struct bfa_ioc_s *ioc); +static void bfa_ioc_hb_stop(struct bfa_ioc_s *ioc); +static void bfa_ioc_reset(struct bfa_ioc_s *ioc, bfa_boolean_t force); +static void bfa_ioc_mbox_poll(struct bfa_ioc_s *ioc); +static void bfa_ioc_mbox_hbfail(struct bfa_ioc_s *ioc); +static void bfa_ioc_recover(struct bfa_ioc_s *ioc); +static 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); +static void bfa_ioc_pf_enabled(struct bfa_ioc_s *ioc); +static void bfa_ioc_pf_disabled(struct bfa_ioc_s *ioc); +static void bfa_ioc_pf_failed(struct bfa_ioc_s *ioc); +static void bfa_ioc_pf_fwmismatch(struct bfa_ioc_s *ioc); /** - * bfa_ioc_sm + * hal_ioc_sm */ /** - * IOC state machine events + * IOC state machine definitions/declarations */ enum ioc_event { - IOC_E_ENABLE = 1, /* IOC enable request */ - IOC_E_DISABLE = 2, /* IOC disable request */ - IOC_E_TIMEOUT = 3, /* f/w response timeout */ - IOC_E_FWREADY = 4, /* f/w initialization done */ - IOC_E_FWRSP_GETATTR = 5, /* IOC get attribute response */ - IOC_E_FWRSP_ENABLE = 6, /* enable f/w response */ - IOC_E_FWRSP_DISABLE = 7, /* disable f/w response */ - IOC_E_HBFAIL = 8, /* heartbeat failure */ - IOC_E_HWERROR = 9, /* hardware error interrupt */ - IOC_E_SEMLOCKED = 10, /* h/w semaphore is locked */ - IOC_E_DETACH = 11, /* driver detach cleanup */ + IOC_E_RESET = 1, /* IOC reset request */ + IOC_E_ENABLE = 2, /* IOC enable request */ + IOC_E_DISABLE = 3, /* IOC disable request */ + IOC_E_DETACH = 4, /* driver detach cleanup */ + IOC_E_ENABLED = 5, /* f/w enabled */ + IOC_E_FWRSP_GETATTR = 6, /* IOC get attribute response */ + IOC_E_DISABLED = 7, /* f/w disabled */ + IOC_E_FAILED = 8, /* failure notice by iocpf sm */ + IOC_E_HBFAIL = 9, /* heartbeat failure */ + IOC_E_HWERROR = 10, /* hardware error interrupt */ + IOC_E_TIMEOUT = 11, /* timeout */ }; +bfa_fsm_state_decl(bfa_ioc, uninit, struct bfa_ioc_s, enum ioc_event); bfa_fsm_state_decl(bfa_ioc, reset, struct bfa_ioc_s, enum ioc_event); -bfa_fsm_state_decl(bfa_ioc, fwcheck, struct bfa_ioc_s, enum ioc_event); -bfa_fsm_state_decl(bfa_ioc, mismatch, struct bfa_ioc_s, enum ioc_event); -bfa_fsm_state_decl(bfa_ioc, semwait, struct bfa_ioc_s, enum ioc_event); -bfa_fsm_state_decl(bfa_ioc, hwinit, struct bfa_ioc_s, enum ioc_event); bfa_fsm_state_decl(bfa_ioc, enabling, struct bfa_ioc_s, enum ioc_event); bfa_fsm_state_decl(bfa_ioc, getattr, struct bfa_ioc_s, enum ioc_event); bfa_fsm_state_decl(bfa_ioc, op, struct bfa_ioc_s, enum ioc_event); bfa_fsm_state_decl(bfa_ioc, initfail, struct bfa_ioc_s, enum ioc_event); -bfa_fsm_state_decl(bfa_ioc, hbfail, struct bfa_ioc_s, enum ioc_event); +bfa_fsm_state_decl(bfa_ioc, fail, struct bfa_ioc_s, enum ioc_event); bfa_fsm_state_decl(bfa_ioc, disabling, struct bfa_ioc_s, enum ioc_event); bfa_fsm_state_decl(bfa_ioc, disabled, struct bfa_ioc_s, enum ioc_event); static struct bfa_sm_table_s ioc_sm_table[] = { + {BFA_SM(bfa_ioc_sm_uninit), BFA_IOC_UNINIT}, {BFA_SM(bfa_ioc_sm_reset), BFA_IOC_RESET}, - {BFA_SM(bfa_ioc_sm_fwcheck), BFA_IOC_FWMISMATCH}, - {BFA_SM(bfa_ioc_sm_mismatch), BFA_IOC_FWMISMATCH}, - {BFA_SM(bfa_ioc_sm_semwait), BFA_IOC_SEMWAIT}, - {BFA_SM(bfa_ioc_sm_hwinit), BFA_IOC_HWINIT}, - {BFA_SM(bfa_ioc_sm_enabling), BFA_IOC_HWINIT}, + {BFA_SM(bfa_ioc_sm_enabling), BFA_IOC_ENABLING}, {BFA_SM(bfa_ioc_sm_getattr), BFA_IOC_GETATTR}, {BFA_SM(bfa_ioc_sm_op), BFA_IOC_OPERATIONAL}, {BFA_SM(bfa_ioc_sm_initfail), BFA_IOC_INITFAIL}, - {BFA_SM(bfa_ioc_sm_hbfail), BFA_IOC_HBFAIL}, + {BFA_SM(bfa_ioc_sm_fail), BFA_IOC_FAIL}, {BFA_SM(bfa_ioc_sm_disabling), BFA_IOC_DISABLING}, {BFA_SM(bfa_ioc_sm_disabled), BFA_IOC_DISABLED}, }; /** + * IOCPF state machine definitions/declarations + */ + +#define bfa_iocpf_timer_start(__ioc) \ + bfa_timer_begin((__ioc)->timer_mod, &(__ioc)->ioc_timer, \ + bfa_iocpf_timeout, (__ioc), BFA_IOC_TOV) +#define bfa_iocpf_timer_stop(__ioc) bfa_timer_stop(&(__ioc)->ioc_timer) + +#define bfa_iocpf_recovery_timer_start(__ioc) \ + bfa_timer_begin((__ioc)->timer_mod, &(__ioc)->ioc_timer, \ + bfa_iocpf_timeout, (__ioc), BFA_IOC_TOV_RECOVER) + +#define bfa_sem_timer_start(__ioc) \ + bfa_timer_begin((__ioc)->timer_mod, &(__ioc)->sem_timer, \ + bfa_iocpf_sem_timeout, (__ioc), BFA_IOC_HWSEM_TOV) +#define bfa_sem_timer_stop(__ioc) bfa_timer_stop(&(__ioc)->sem_timer) + +/* + * Forward declareations for iocpf state machine + */ +static void bfa_iocpf_enable(struct bfa_ioc_s *ioc); +static void bfa_iocpf_disable(struct bfa_ioc_s *ioc); +static void bfa_iocpf_fail(struct bfa_ioc_s *ioc); +static void bfa_iocpf_initfail(struct bfa_ioc_s *ioc); +static void bfa_iocpf_getattrfail(struct bfa_ioc_s *ioc); +static void bfa_iocpf_stop(struct bfa_ioc_s *ioc); +static void bfa_iocpf_timeout(void *ioc_arg); +static void bfa_iocpf_sem_timeout(void *ioc_arg); + +/** + * IOCPF state machine events + */ +enum iocpf_event { + IOCPF_E_ENABLE = 1, /* IOCPF enable request */ + IOCPF_E_DISABLE = 2, /* IOCPF disable request */ + IOCPF_E_STOP = 3, /* stop on driver detach */ + IOCPF_E_FWREADY = 4, /* f/w initialization done */ + IOCPF_E_FWRSP_ENABLE = 5, /* enable f/w response */ + IOCPF_E_FWRSP_DISABLE = 6, /* disable f/w response */ + IOCPF_E_FAIL = 7, /* failure notice by ioc sm */ + IOCPF_E_INITFAIL = 8, /* init fail notice by ioc sm */ + IOCPF_E_GETATTRFAIL = 9, /* init fail notice by ioc sm */ + IOCPF_E_SEMLOCKED = 10, /* h/w semaphore is locked */ + IOCPF_E_TIMEOUT = 11, /* f/w response timeout */ +}; + +/** + * IOCPF states + */ +enum bfa_iocpf_state { + BFA_IOCPF_RESET = 1, /* IOC is in reset state */ + BFA_IOCPF_SEMWAIT = 2, /* Waiting for IOC h/w semaphore */ + BFA_IOCPF_HWINIT = 3, /* IOC h/w is being initialized */ + BFA_IOCPF_READY = 4, /* IOCPF is initialized */ + BFA_IOCPF_INITFAIL = 5, /* IOCPF failed */ + BFA_IOCPF_FAIL = 6, /* IOCPF failed */ + BFA_IOCPF_DISABLING = 7, /* IOCPF is being disabled */ + BFA_IOCPF_DISABLED = 8, /* IOCPF is disabled */ + BFA_IOCPF_FWMISMATCH = 9, /* IOC f/w different from drivers */ +}; + +bfa_fsm_state_decl(bfa_iocpf, reset, struct bfa_iocpf_s, enum iocpf_event); +bfa_fsm_state_decl(bfa_iocpf, fwcheck, struct bfa_iocpf_s, enum iocpf_event); +bfa_fsm_state_decl(bfa_iocpf, mismatch, struct bfa_iocpf_s, enum iocpf_event); +bfa_fsm_state_decl(bfa_iocpf, semwait, struct bfa_iocpf_s, enum iocpf_event); +bfa_fsm_state_decl(bfa_iocpf, hwinit, struct bfa_iocpf_s, enum iocpf_event); +bfa_fsm_state_decl(bfa_iocpf, enabling, struct bfa_iocpf_s, enum iocpf_event); +bfa_fsm_state_decl(bfa_iocpf, ready, struct bfa_iocpf_s, enum iocpf_event); +bfa_fsm_state_decl(bfa_iocpf, initfail, struct bfa_iocpf_s, enum iocpf_event); +bfa_fsm_state_decl(bfa_iocpf, fail, struct bfa_iocpf_s, enum iocpf_event); +bfa_fsm_state_decl(bfa_iocpf, disabling, struct bfa_iocpf_s, enum iocpf_event); +bfa_fsm_state_decl(bfa_iocpf, disabled, struct bfa_iocpf_s, enum iocpf_event); + +static struct bfa_sm_table_s iocpf_sm_table[] = { + {BFA_SM(bfa_iocpf_sm_reset), BFA_IOCPF_RESET}, + {BFA_SM(bfa_iocpf_sm_fwcheck), BFA_IOCPF_FWMISMATCH}, + {BFA_SM(bfa_iocpf_sm_mismatch), BFA_IOCPF_FWMISMATCH}, + {BFA_SM(bfa_iocpf_sm_semwait), BFA_IOCPF_SEMWAIT}, + {BFA_SM(bfa_iocpf_sm_hwinit), BFA_IOCPF_HWINIT}, + {BFA_SM(bfa_iocpf_sm_enabling), BFA_IOCPF_HWINIT}, + {BFA_SM(bfa_iocpf_sm_ready), BFA_IOCPF_READY}, + {BFA_SM(bfa_iocpf_sm_initfail), BFA_IOCPF_INITFAIL}, + {BFA_SM(bfa_iocpf_sm_fail), BFA_IOCPF_FAIL}, + {BFA_SM(bfa_iocpf_sm_disabling), BFA_IOCPF_DISABLING}, + {BFA_SM(bfa_iocpf_sm_disabled), BFA_IOCPF_DISABLED}, +}; + +/** + * IOC State Machine + */ + +/** + * Beginning state. IOC uninit state. + */ + +static void +bfa_ioc_sm_uninit_entry(struct bfa_ioc_s *ioc) +{ +} + +/** + * IOC is in uninit state. + */ +static void +bfa_ioc_sm_uninit(struct bfa_ioc_s *ioc, enum ioc_event event) +{ + bfa_trc(ioc, event); + + switch (event) { + case IOC_E_RESET: + bfa_fsm_set_state(ioc, bfa_ioc_sm_reset); + break; + + default: + bfa_sm_fault(ioc, event); + } +} +/** * Reset entry actions -- initialize state machine */ static void bfa_ioc_sm_reset_entry(struct bfa_ioc_s *ioc) { - ioc->retry_count = 0; - ioc->auto_recover = bfa_auto_recover; + bfa_fsm_set_state(&ioc->iocpf, bfa_iocpf_sm_reset); } /** - * Beginning state. IOC is in reset state. + * IOC is in reset state. */ static void bfa_ioc_sm_reset(struct bfa_ioc_s *ioc, enum ioc_event event) @@ -157,7 +281,7 @@ bfa_ioc_sm_reset(struct bfa_ioc_s *ioc, enum ioc_event event) switch (event) { case IOC_E_ENABLE: - bfa_fsm_set_state(ioc, bfa_ioc_sm_fwcheck); + bfa_fsm_set_state(ioc, bfa_ioc_sm_enabling); break; case IOC_E_DISABLE: @@ -165,6 +289,7 @@ bfa_ioc_sm_reset(struct bfa_ioc_s *ioc, enum ioc_event event) break; case IOC_E_DETACH: + bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit); break; default: @@ -172,46 +297,209 @@ bfa_ioc_sm_reset(struct bfa_ioc_s *ioc, enum ioc_event event) } } + +static void +bfa_ioc_sm_enabling_entry(struct bfa_ioc_s *ioc) +{ + bfa_iocpf_enable(ioc); +} + /** - * Semaphore should be acquired for version check. + * Host IOC function is being enabled, awaiting response from firmware. + * Semaphore is acquired. */ static void -bfa_ioc_sm_fwcheck_entry(struct bfa_ioc_s *ioc) +bfa_ioc_sm_enabling(struct bfa_ioc_s *ioc, enum ioc_event event) { - bfa_ioc_hw_sem_get(ioc); + bfa_trc(ioc, event); + + switch (event) { + case IOC_E_ENABLED: + bfa_fsm_set_state(ioc, bfa_ioc_sm_getattr); + break; + + case IOC_E_FAILED: + bfa_fsm_set_state(ioc, bfa_ioc_sm_initfail); + break; + + case IOC_E_HWERROR: + bfa_fsm_set_state(ioc, bfa_ioc_sm_initfail); + bfa_iocpf_initfail(ioc); + break; + + case IOC_E_DISABLE: + bfa_fsm_set_state(ioc, bfa_ioc_sm_disabling); + break; + + case IOC_E_DETACH: + bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit); + bfa_iocpf_stop(ioc); + break; + + case IOC_E_ENABLE: + break; + + default: + bfa_sm_fault(ioc, event); + } +} + + +static void +bfa_ioc_sm_getattr_entry(struct bfa_ioc_s *ioc) +{ + bfa_ioc_timer_start(ioc); + bfa_ioc_send_getattr(ioc); } /** - * Awaiting h/w semaphore to continue with version check. + * IOC configuration in progress. Timer is active. */ static void -bfa_ioc_sm_fwcheck(struct bfa_ioc_s *ioc, enum ioc_event event) +bfa_ioc_sm_getattr(struct bfa_ioc_s *ioc, enum ioc_event event) { bfa_trc(ioc, event); switch (event) { - case IOC_E_SEMLOCKED: - if (bfa_ioc_firmware_lock(ioc)) { - ioc->retry_count = 0; - bfa_fsm_set_state(ioc, bfa_ioc_sm_hwinit); - } else { - bfa_ioc_hw_sem_release(ioc); - bfa_fsm_set_state(ioc, bfa_ioc_sm_mismatch); - } + 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; + + case IOC_E_FAILED: + bfa_ioc_timer_stop(ioc); + bfa_fsm_set_state(ioc, bfa_ioc_sm_initfail); + break; + + case IOC_E_HWERROR: + bfa_ioc_timer_stop(ioc); + /* fall through */ + + case IOC_E_TIMEOUT: + bfa_fsm_set_state(ioc, bfa_ioc_sm_initfail); + bfa_iocpf_getattrfail(ioc); break; case IOC_E_DISABLE: - bfa_ioc_disable_comp(ioc); + bfa_ioc_timer_stop(ioc); + bfa_fsm_set_state(ioc, bfa_ioc_sm_disabling); + break; + + case IOC_E_ENABLE: + break; + + default: + bfa_sm_fault(ioc, event); + } +} + + +static void +bfa_ioc_sm_op_entry(struct bfa_ioc_s *ioc) +{ + struct bfad_s *bfad = (struct bfad_s *)ioc->bfa->bfad; + + ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_OK); + bfa_ioc_hb_monitor(ioc); + BFA_LOG(KERN_INFO, bfad, log_level, "IOC enabled\n"); +} + +static void +bfa_ioc_sm_op(struct bfa_ioc_s *ioc, enum ioc_event event) +{ + bfa_trc(ioc, event); + + switch (event) { + case IOC_E_ENABLE: + break; + + case IOC_E_DISABLE: + bfa_ioc_hb_stop(ioc); + bfa_fsm_set_state(ioc, bfa_ioc_sm_disabling); + break; + + case IOC_E_FAILED: + bfa_ioc_hb_stop(ioc); + bfa_fsm_set_state(ioc, bfa_ioc_sm_fail); + break; + + case IOC_E_HWERROR: + bfa_ioc_hb_stop(ioc); + /* !!! fall through !!! */ + + case IOC_E_HBFAIL: + bfa_fsm_set_state(ioc, bfa_ioc_sm_fail); + bfa_iocpf_fail(ioc); + break; + + default: + bfa_sm_fault(ioc, event); + } +} + + +static void +bfa_ioc_sm_disabling_entry(struct bfa_ioc_s *ioc) +{ + struct bfad_s *bfad = (struct bfad_s *)ioc->bfa->bfad; + bfa_iocpf_disable(ioc); + BFA_LOG(KERN_INFO, bfad, log_level, "IOC disabled\n"); +} + +/** + * IOC is being disabled + */ +static void +bfa_ioc_sm_disabling(struct bfa_ioc_s *ioc, enum ioc_event event) +{ + bfa_trc(ioc, event); + + switch (event) { + case IOC_E_DISABLED: + bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled); + break; + + case IOC_E_HWERROR: /* - * fall through + * No state change. Will move to disabled state + * after iocpf sm completes failure processing and + * moves to disabled state. */ + bfa_iocpf_fail(ioc); + break; - case IOC_E_DETACH: - bfa_ioc_hw_sem_get_cancel(ioc); - bfa_fsm_set_state(ioc, bfa_ioc_sm_reset); + default: + bfa_sm_fault(ioc, event); + } +} + +/** + * IOC disable completion entry. + */ +static void +bfa_ioc_sm_disabled_entry(struct bfa_ioc_s *ioc) +{ + bfa_ioc_disable_comp(ioc); +} + +static void +bfa_ioc_sm_disabled(struct bfa_ioc_s *ioc, enum ioc_event event) +{ + bfa_trc(ioc, event); + + switch (event) { + case IOC_E_ENABLE: + bfa_fsm_set_state(ioc, bfa_ioc_sm_enabling); + break; + + case IOC_E_DISABLE: + ioc->cbfn->disable_cbfn(ioc->bfa); break; - case IOC_E_FWREADY: + case IOC_E_DETACH: + bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit); + bfa_iocpf_stop(ioc); break; default: @@ -219,48 +507,138 @@ bfa_ioc_sm_fwcheck(struct bfa_ioc_s *ioc, enum ioc_event event) } } + +static void +bfa_ioc_sm_initfail_entry(struct bfa_ioc_s *ioc) +{ + ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE); +} + /** - * Notify enable completion callback and generate mismatch AEN. + * Hardware initialization failed. */ static void -bfa_ioc_sm_mismatch_entry(struct bfa_ioc_s *ioc) +bfa_ioc_sm_initfail(struct bfa_ioc_s *ioc, enum ioc_event event) +{ + bfa_trc(ioc, event); + + switch (event) { + case IOC_E_ENABLED: + bfa_fsm_set_state(ioc, bfa_ioc_sm_getattr); + break; + + case IOC_E_FAILED: + /** + * Initialization failure during iocpf init retry. + */ + ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE); + break; + + case IOC_E_DISABLE: + bfa_fsm_set_state(ioc, bfa_ioc_sm_disabling); + break; + + case IOC_E_DETACH: + bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit); + bfa_iocpf_stop(ioc); + break; + + default: + bfa_sm_fault(ioc, event); + } +} + + +static void +bfa_ioc_sm_fail_entry(struct bfa_ioc_s *ioc) { + struct list_head *qe; + struct bfa_ioc_hbfail_notify_s *notify; + struct bfad_s *bfad = (struct bfad_s *)ioc->bfa->bfad; + /** - * Provide enable completion callback and AEN notification only once. + * Notify driver and common modules registered for notification. */ - if (ioc->retry_count == 0) { - ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE); - bfa_ioc_aen_post(ioc, BFA_IOC_AEN_FWMISMATCH); + ioc->cbfn->hbfail_cbfn(ioc->bfa); + list_for_each(qe, &ioc->hb_notify_q) { + notify = (struct bfa_ioc_hbfail_notify_s *) qe; + notify->cbfn(notify->cbarg); } - ioc->retry_count++; - bfa_ioc_timer_start(ioc); + + BFA_LOG(KERN_CRIT, bfad, log_level, + "Heart Beat of IOC has failed\n"); } /** - * Awaiting firmware version match. + * IOC failure. */ static void -bfa_ioc_sm_mismatch(struct bfa_ioc_s *ioc, enum ioc_event event) +bfa_ioc_sm_fail(struct bfa_ioc_s *ioc, enum ioc_event event) { bfa_trc(ioc, event); switch (event) { - case IOC_E_TIMEOUT: - bfa_fsm_set_state(ioc, bfa_ioc_sm_fwcheck); + + case IOC_E_FAILED: + /** + * Initialization failure during iocpf recovery. + * !!! Fall through !!! + */ + case IOC_E_ENABLE: + ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE); + break; + + case IOC_E_ENABLED: + bfa_fsm_set_state(ioc, bfa_ioc_sm_getattr); break; case IOC_E_DISABLE: - bfa_ioc_disable_comp(ioc); + bfa_fsm_set_state(ioc, bfa_ioc_sm_disabling); + break; + + case IOC_E_HWERROR: /* - * fall through + * HB failure notification, ignore. */ + break; + default: + bfa_sm_fault(ioc, event); + } +} - case IOC_E_DETACH: - bfa_ioc_timer_stop(ioc); - bfa_fsm_set_state(ioc, bfa_ioc_sm_reset); + + +/** + * IOCPF State Machine + */ + + +/** + * Reset entry actions -- initialize state machine + */ +static void +bfa_iocpf_sm_reset_entry(struct bfa_iocpf_s *iocpf) +{ + iocpf->retry_count = 0; + iocpf->auto_recover = bfa_auto_recover; +} + +/** + * Beginning state. IOC is in reset state. + */ +static void +bfa_iocpf_sm_reset(struct bfa_iocpf_s *iocpf, enum iocpf_event event) +{ + struct bfa_ioc_s *ioc = iocpf->ioc; + + bfa_trc(ioc, event); + + switch (event) { + case IOCPF_E_ENABLE: + bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fwcheck); break; - case IOC_E_FWREADY: + case IOCPF_E_STOP: break; default: @@ -269,31 +647,44 @@ bfa_ioc_sm_mismatch(struct bfa_ioc_s *ioc, enum ioc_event event) } /** - * Request for semaphore. + * Semaphore should be acquired for version check. */ static void -bfa_ioc_sm_semwait_entry(struct bfa_ioc_s *ioc) +bfa_iocpf_sm_fwcheck_entry(struct bfa_iocpf_s *iocpf) { - bfa_ioc_hw_sem_get(ioc); + bfa_ioc_hw_sem_get(iocpf->ioc); } /** - * Awaiting semaphore for h/w initialzation. + * Awaiting h/w semaphore to continue with version check. */ static void -bfa_ioc_sm_semwait(struct bfa_ioc_s *ioc, enum ioc_event event) +bfa_iocpf_sm_fwcheck(struct bfa_iocpf_s *iocpf, enum iocpf_event event) { + struct bfa_ioc_s *ioc = iocpf->ioc; + bfa_trc(ioc, event); switch (event) { - case IOC_E_SEMLOCKED: - ioc->retry_count = 0; - bfa_fsm_set_state(ioc, bfa_ioc_sm_hwinit); + case IOCPF_E_SEMLOCKED: + if (bfa_ioc_firmware_lock(ioc)) { + iocpf->retry_count = 0; + bfa_fsm_set_state(iocpf, bfa_iocpf_sm_hwinit); + } else { + bfa_ioc_hw_sem_release(ioc); + bfa_fsm_set_state(iocpf, bfa_iocpf_sm_mismatch); + } break; - case IOC_E_DISABLE: + case IOCPF_E_DISABLE: bfa_ioc_hw_sem_get_cancel(ioc); - bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled); + bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset); + bfa_ioc_pf_disabled(ioc); + break; + + case IOCPF_E_STOP: + bfa_ioc_hw_sem_get_cancel(ioc); + bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset); break; default: @@ -301,51 +692,81 @@ bfa_ioc_sm_semwait(struct bfa_ioc_s *ioc, enum ioc_event event) } } - +/** + * Notify enable completion callback. + */ static void -bfa_ioc_sm_hwinit_entry(struct bfa_ioc_s *ioc) +bfa_iocpf_sm_mismatch_entry(struct bfa_iocpf_s *iocpf) { - bfa_ioc_timer_start(ioc); - bfa_ioc_reset(ioc, BFA_FALSE); + /* + * Call only the first time sm enters fwmismatch state. + */ + if (iocpf->retry_count == 0) + bfa_ioc_pf_fwmismatch(iocpf->ioc); + + iocpf->retry_count++; + bfa_iocpf_timer_start(iocpf->ioc); } /** - * Hardware is being initialized. Interrupts are enabled. - * Holding hardware semaphore lock. + * Awaiting firmware version match. */ static void -bfa_ioc_sm_hwinit(struct bfa_ioc_s *ioc, enum ioc_event event) +bfa_iocpf_sm_mismatch(struct bfa_iocpf_s *iocpf, enum iocpf_event event) { + struct bfa_ioc_s *ioc = iocpf->ioc; + bfa_trc(ioc, event); switch (event) { - case IOC_E_FWREADY: - bfa_ioc_timer_stop(ioc); - bfa_fsm_set_state(ioc, bfa_ioc_sm_enabling); + case IOCPF_E_TIMEOUT: + bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fwcheck); break; - case IOC_E_HWERROR: - bfa_ioc_timer_stop(ioc); - /* - * fall through - */ + case IOCPF_E_DISABLE: + bfa_iocpf_timer_stop(ioc); + bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset); + bfa_ioc_pf_disabled(ioc); + break; - case IOC_E_TIMEOUT: - ioc->retry_count++; - if (ioc->retry_count < BFA_IOC_HWINIT_MAX) { - bfa_ioc_timer_start(ioc); - bfa_ioc_reset(ioc, BFA_TRUE); - break; - } + case IOCPF_E_STOP: + bfa_iocpf_timer_stop(ioc); + bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset); + break; - bfa_ioc_hw_sem_release(ioc); - bfa_fsm_set_state(ioc, bfa_ioc_sm_initfail); + default: + bfa_sm_fault(ioc, event); + } +} + +/** + * Request for semaphore. + */ +static void +bfa_iocpf_sm_semwait_entry(struct bfa_iocpf_s *iocpf) +{ + bfa_ioc_hw_sem_get(iocpf->ioc); +} + +/** + * Awaiting semaphore for h/w initialzation. + */ +static void +bfa_iocpf_sm_semwait(struct bfa_iocpf_s *iocpf, enum iocpf_event event) +{ + struct bfa_ioc_s *ioc = iocpf->ioc; + + bfa_trc(ioc, event); + + switch (event) { + case IOCPF_E_SEMLOCKED: + iocpf->retry_count = 0; + bfa_fsm_set_state(iocpf, bfa_iocpf_sm_hwinit); break; - case IOC_E_DISABLE: - bfa_ioc_hw_sem_release(ioc); - bfa_ioc_timer_stop(ioc); - bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled); + case IOCPF_E_DISABLE: + bfa_ioc_hw_sem_get_cancel(ioc); + bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabled); break; default: @@ -355,55 +776,54 @@ bfa_ioc_sm_hwinit(struct bfa_ioc_s *ioc, enum ioc_event event) static void -bfa_ioc_sm_enabling_entry(struct bfa_ioc_s *ioc) +bfa_iocpf_sm_hwinit_entry(struct bfa_iocpf_s *iocpf) { - bfa_ioc_timer_start(ioc); - bfa_ioc_send_enable(ioc); + bfa_iocpf_timer_start(iocpf->ioc); + bfa_ioc_reset(iocpf->ioc, BFA_FALSE); } /** - * Host IOC function is being enabled, awaiting response from firmware. - * Semaphore is acquired. + * Hardware is being initialized. Interrupts are enabled. + * Holding hardware semaphore lock. */ static void -bfa_ioc_sm_enabling(struct bfa_ioc_s *ioc, enum ioc_event event) +bfa_iocpf_sm_hwinit(struct bfa_iocpf_s *iocpf, enum iocpf_event event) { + struct bfa_ioc_s *ioc = iocpf->ioc; + bfa_trc(ioc, event); switch (event) { - case IOC_E_FWRSP_ENABLE: - bfa_ioc_timer_stop(ioc); - bfa_ioc_hw_sem_release(ioc); - bfa_fsm_set_state(ioc, bfa_ioc_sm_getattr); + case IOCPF_E_FWREADY: + bfa_iocpf_timer_stop(ioc); + bfa_fsm_set_state(iocpf, bfa_iocpf_sm_enabling); break; - case IOC_E_HWERROR: - bfa_ioc_timer_stop(ioc); + case IOCPF_E_INITFAIL: + bfa_iocpf_timer_stop(ioc); /* - * fall through + * !!! fall through !!! */ - case IOC_E_TIMEOUT: - ioc->retry_count++; - if (ioc->retry_count < BFA_IOC_HWINIT_MAX) { - bfa_reg_write(ioc->ioc_regs.ioc_fwstate, - BFI_IOC_UNINIT); - bfa_fsm_set_state(ioc, bfa_ioc_sm_hwinit); + case IOCPF_E_TIMEOUT: + iocpf->retry_count++; + if (iocpf->retry_count < BFA_IOC_HWINIT_MAX) { + bfa_iocpf_timer_start(ioc); + bfa_ioc_reset(ioc, BFA_TRUE); break; } bfa_ioc_hw_sem_release(ioc); - bfa_fsm_set_state(ioc, bfa_ioc_sm_initfail); - break; + bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail); - case IOC_E_DISABLE: - bfa_ioc_timer_stop(ioc); - bfa_ioc_hw_sem_release(ioc); - bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled); + if (event == IOCPF_E_TIMEOUT) + bfa_ioc_pf_failed(ioc); break; - case IOC_E_FWREADY: - bfa_ioc_send_enable(ioc); + case IOCPF_E_DISABLE: + bfa_ioc_hw_sem_release(ioc); + bfa_iocpf_timer_stop(ioc); + bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabled); break; default: @@ -413,40 +833,60 @@ bfa_ioc_sm_enabling(struct bfa_ioc_s *ioc, enum ioc_event event) static void -bfa_ioc_sm_getattr_entry(struct bfa_ioc_s *ioc) +bfa_iocpf_sm_enabling_entry(struct bfa_iocpf_s *iocpf) { - bfa_ioc_timer_start(ioc); - bfa_ioc_send_getattr(ioc); + bfa_iocpf_timer_start(iocpf->ioc); + bfa_ioc_send_enable(iocpf->ioc); } /** - * IOC configuration in progress. Timer is active. + * Host IOC function is being enabled, awaiting response from firmware. + * Semaphore is acquired. */ static void -bfa_ioc_sm_getattr(struct bfa_ioc_s *ioc, enum ioc_event event) +bfa_iocpf_sm_enabling(struct bfa_iocpf_s *iocpf, enum iocpf_event event) { + struct bfa_ioc_s *ioc = iocpf->ioc; + bfa_trc(ioc, 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); + case IOCPF_E_FWRSP_ENABLE: + bfa_iocpf_timer_stop(ioc); + bfa_ioc_hw_sem_release(ioc); + bfa_fsm_set_state(iocpf, bfa_iocpf_sm_ready); break; - case IOC_E_HWERROR: - bfa_ioc_timer_stop(ioc); + case IOCPF_E_INITFAIL: + bfa_iocpf_timer_stop(ioc); /* - * fall through + * !!! fall through !!! */ - case IOC_E_TIMEOUT: - bfa_fsm_set_state(ioc, bfa_ioc_sm_initfail); + case IOCPF_E_TIMEOUT: + iocpf->retry_count++; + if (iocpf->retry_count < BFA_IOC_HWINIT_MAX) { + bfa_reg_write(ioc->ioc_regs.ioc_fwstate, + BFI_IOC_UNINIT); + bfa_fsm_set_state(iocpf, bfa_iocpf_sm_hwinit); + break; + } + + bfa_ioc_hw_sem_release(ioc); + bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail); + + if (event == IOCPF_E_TIMEOUT) + bfa_ioc_pf_failed(ioc); break; - case IOC_E_DISABLE: - bfa_ioc_timer_stop(ioc); - bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled); + case IOCPF_E_DISABLE: + bfa_iocpf_timer_stop(ioc); + bfa_ioc_hw_sem_release(ioc); + bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling); + break; + + case IOCPF_E_FWREADY: + bfa_ioc_send_enable(ioc); break; default: @@ -455,41 +895,40 @@ bfa_ioc_sm_getattr(struct bfa_ioc_s *ioc, enum ioc_event event) } + static void -bfa_ioc_sm_op_entry(struct bfa_ioc_s *ioc) +bfa_iocpf_sm_ready_entry(struct bfa_iocpf_s *iocpf) { - ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_OK); - bfa_ioc_hb_monitor(ioc); - bfa_ioc_aen_post(ioc, BFA_IOC_AEN_ENABLE); + bfa_ioc_pf_enabled(iocpf->ioc); } static void -bfa_ioc_sm_op(struct bfa_ioc_s *ioc, enum ioc_event event) +bfa_iocpf_sm_ready(struct bfa_iocpf_s *iocpf, enum iocpf_event event) { + struct bfa_ioc_s *ioc = iocpf->ioc; + bfa_trc(ioc, event); switch (event) { - case IOC_E_ENABLE: + case IOCPF_E_DISABLE: + bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling); break; - case IOC_E_DISABLE: - bfa_ioc_hb_stop(ioc); - bfa_fsm_set_state(ioc, bfa_ioc_sm_disabling); + case IOCPF_E_GETATTRFAIL: + bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail); break; - case IOC_E_HWERROR: - case IOC_E_FWREADY: - /** - * Hard error or IOC recovery by other function. - * Treat it same as heartbeat failure. - */ - bfa_ioc_hb_stop(ioc); - /* - * !!! fall through !!! - */ + case IOCPF_E_FAIL: + bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail); + break; - case IOC_E_HBFAIL: - bfa_fsm_set_state(ioc, bfa_ioc_sm_hbfail); + case IOCPF_E_FWREADY: + if (bfa_ioc_is_operational(ioc)) + bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail); + else + bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail); + + bfa_ioc_pf_failed(ioc); break; default: @@ -499,36 +938,41 @@ bfa_ioc_sm_op(struct bfa_ioc_s *ioc, enum ioc_event event) static void -bfa_ioc_sm_disabling_entry(struct bfa_ioc_s *ioc) +bfa_iocpf_sm_disabling_entry(struct bfa_iocpf_s *iocpf) { - bfa_ioc_aen_post(ioc, BFA_IOC_AEN_DISABLE); - bfa_ioc_timer_start(ioc); - bfa_ioc_send_disable(ioc); + bfa_iocpf_timer_start(iocpf->ioc); + bfa_ioc_send_disable(iocpf->ioc); } /** * IOC is being disabled */ static void -bfa_ioc_sm_disabling(struct bfa_ioc_s *ioc, enum ioc_event event) +bfa_iocpf_sm_disabling(struct bfa_iocpf_s *iocpf, enum iocpf_event event) { + struct bfa_ioc_s *ioc = iocpf->ioc; + bfa_trc(ioc, event); switch (event) { - case IOC_E_FWRSP_DISABLE: - bfa_ioc_timer_stop(ioc); - bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled); + case IOCPF_E_FWRSP_DISABLE: + case IOCPF_E_FWREADY: + bfa_iocpf_timer_stop(ioc); + bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabled); break; - case IOC_E_HWERROR: - bfa_ioc_timer_stop(ioc); + case IOCPF_E_FAIL: + bfa_iocpf_timer_stop(ioc); /* * !!! fall through !!! */ - case IOC_E_TIMEOUT: + case IOCPF_E_TIMEOUT: bfa_reg_write(ioc->ioc_regs.ioc_fwstate, BFI_IOC_FAIL); - bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled); + bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabled); + break; + + case IOCPF_E_FWRSP_ENABLE: break; default: @@ -540,31 +984,26 @@ bfa_ioc_sm_disabling(struct bfa_ioc_s *ioc, enum ioc_event event) * IOC disable completion entry. */ static void -bfa_ioc_sm_disabled_entry(struct bfa_ioc_s *ioc) +bfa_iocpf_sm_disabled_entry(struct bfa_iocpf_s *iocpf) { - bfa_ioc_disable_comp(ioc); + bfa_ioc_pf_disabled(iocpf->ioc); } static void -bfa_ioc_sm_disabled(struct bfa_ioc_s *ioc, enum ioc_event event) +bfa_iocpf_sm_disabled(struct bfa_iocpf_s *iocpf, enum iocpf_event event) { + struct bfa_ioc_s *ioc = iocpf->ioc; + bfa_trc(ioc, event); switch (event) { - case IOC_E_ENABLE: - bfa_fsm_set_state(ioc, bfa_ioc_sm_semwait); + case IOCPF_E_ENABLE: + bfa_fsm_set_state(iocpf, bfa_iocpf_sm_semwait); break; - case IOC_E_DISABLE: - ioc->cbfn->disable_cbfn(ioc->bfa); - break; - - case IOC_E_FWREADY: - break; - - case IOC_E_DETACH: + case IOCPF_E_STOP: bfa_ioc_firmware_unlock(ioc); - bfa_fsm_set_state(ioc, bfa_ioc_sm_reset); + bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset); break; default: @@ -574,34 +1013,35 @@ bfa_ioc_sm_disabled(struct bfa_ioc_s *ioc, enum ioc_event event) static void -bfa_ioc_sm_initfail_entry(struct bfa_ioc_s *ioc) +bfa_iocpf_sm_initfail_entry(struct bfa_iocpf_s *iocpf) { - ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE); - bfa_ioc_timer_start(ioc); + bfa_iocpf_timer_start(iocpf->ioc); } /** * Hardware initialization failed. */ static void -bfa_ioc_sm_initfail(struct bfa_ioc_s *ioc, enum ioc_event event) +bfa_iocpf_sm_initfail(struct bfa_iocpf_s *iocpf, enum iocpf_event event) { + struct bfa_ioc_s *ioc = iocpf->ioc; + bfa_trc(ioc, event); switch (event) { - case IOC_E_DISABLE: - bfa_ioc_timer_stop(ioc); - bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled); + case IOCPF_E_DISABLE: + bfa_iocpf_timer_stop(ioc); + bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabled); break; - case IOC_E_DETACH: - bfa_ioc_timer_stop(ioc); + case IOCPF_E_STOP: + bfa_iocpf_timer_stop(ioc); bfa_ioc_firmware_unlock(ioc); - bfa_fsm_set_state(ioc, bfa_ioc_sm_reset); + bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset); break; - case IOC_E_TIMEOUT: - bfa_fsm_set_state(ioc, bfa_ioc_sm_semwait); + case IOCPF_E_TIMEOUT: + bfa_fsm_set_state(iocpf, bfa_iocpf_sm_semwait); break; default: @@ -611,80 +1051,47 @@ bfa_ioc_sm_initfail(struct bfa_ioc_s *ioc, enum ioc_event event) static void -bfa_ioc_sm_hbfail_entry(struct bfa_ioc_s *ioc) +bfa_iocpf_sm_fail_entry(struct bfa_iocpf_s *iocpf) { - struct list_head *qe; - struct bfa_ioc_hbfail_notify_s *notify; - /** * Mark IOC as failed in hardware and stop firmware. */ - bfa_ioc_lpu_stop(ioc); - bfa_reg_write(ioc->ioc_regs.ioc_fwstate, BFI_IOC_FAIL); + bfa_ioc_lpu_stop(iocpf->ioc); + bfa_reg_write(iocpf->ioc->ioc_regs.ioc_fwstate, BFI_IOC_FAIL); /** * Notify other functions on HB failure. */ - bfa_ioc_notify_hbfail(ioc); - - /** - * Notify driver and common modules registered for notification. - */ - ioc->cbfn->hbfail_cbfn(ioc->bfa); - list_for_each(qe, &ioc->hb_notify_q) { - notify = (struct bfa_ioc_hbfail_notify_s *)qe; - notify->cbfn(notify->cbarg); - } + bfa_ioc_notify_hbfail(iocpf->ioc); /** * Flush any queued up mailbox requests. */ - bfa_ioc_mbox_hbfail(ioc); - bfa_ioc_aen_post(ioc, BFA_IOC_AEN_HBFAIL); + bfa_ioc_mbox_hbfail(iocpf->ioc); - /** - * Trigger auto-recovery after a delay. - */ - if (ioc->auto_recover) { - bfa_timer_begin(ioc->timer_mod, &ioc->ioc_timer, - bfa_ioc_timeout, ioc, BFA_IOC_TOV_RECOVER); - } + if (iocpf->auto_recover) + bfa_iocpf_recovery_timer_start(iocpf->ioc); } /** - * IOC heartbeat failure. + * IOC is in failed state. */ static void -bfa_ioc_sm_hbfail(struct bfa_ioc_s *ioc, enum ioc_event event) +bfa_iocpf_sm_fail(struct bfa_iocpf_s *iocpf, enum iocpf_event event) { + struct bfa_ioc_s *ioc = iocpf->ioc; + bfa_trc(ioc, event); switch (event) { - - case IOC_E_ENABLE: - ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE); - break; - - case IOC_E_DISABLE: - if (ioc->auto_recover) - bfa_ioc_timer_stop(ioc); - bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled); + case IOCPF_E_DISABLE: + if (iocpf->auto_recover) + bfa_iocpf_timer_stop(ioc); + bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabled); break; - case IOC_E_TIMEOUT: - bfa_fsm_set_state(ioc, bfa_ioc_sm_semwait); - break; - - case IOC_E_FWREADY: - /** - * Recovery is already initiated by other function. - */ - break; - - case IOC_E_HWERROR: - /* - * HB failure notification, ignore. - */ + case IOCPF_E_TIMEOUT: + bfa_fsm_set_state(iocpf, bfa_iocpf_sm_semwait); break; default: @@ -695,14 +1102,14 @@ bfa_ioc_sm_hbfail(struct bfa_ioc_s *ioc, enum ioc_event event) /** - * bfa_ioc_pvt BFA IOC private functions + * hal_ioc_pvt BFA IOC private functions */ static void bfa_ioc_disable_comp(struct bfa_ioc_s *ioc) { - struct list_head *qe; - struct bfa_ioc_hbfail_notify_s *notify; + struct list_head *qe; + struct bfa_ioc_hbfail_notify_s *notify; ioc->cbfn->disable_cbfn(ioc->bfa); @@ -710,25 +1117,17 @@ bfa_ioc_disable_comp(struct bfa_ioc_s *ioc) * Notify common modules registered for notification. */ list_for_each(qe, &ioc->hb_notify_q) { - notify = (struct bfa_ioc_hbfail_notify_s *)qe; + notify = (struct bfa_ioc_hbfail_notify_s *) qe; notify->cbfn(notify->cbarg); } } -void -bfa_ioc_sem_timeout(void *ioc_arg) -{ - struct bfa_ioc_s *ioc = (struct bfa_ioc_s *)ioc_arg; - - bfa_ioc_hw_sem_get(ioc); -} - bfa_boolean_t bfa_ioc_sem_get(bfa_os_addr_t sem_reg) { u32 r32; int cnt = 0; -#define BFA_SEM_SPINCNT 3000 +#define BFA_SEM_SPINCNT 3000 r32 = bfa_reg_read(sem_reg); @@ -754,7 +1153,7 @@ bfa_ioc_sem_release(bfa_os_addr_t sem_reg) static void bfa_ioc_hw_sem_get(struct bfa_ioc_s *ioc) { - u32 r32; + u32 r32; /** * First read to the semaphore register will return 0, subsequent reads @@ -762,12 +1161,11 @@ bfa_ioc_hw_sem_get(struct bfa_ioc_s *ioc) */ r32 = bfa_reg_read(ioc->ioc_regs.ioc_sem_reg); if (r32 == 0) { - bfa_fsm_send_event(ioc, IOC_E_SEMLOCKED); + bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_SEMLOCKED); return; } - bfa_timer_begin(ioc->timer_mod, &ioc->sem_timer, bfa_ioc_sem_timeout, - ioc, BFA_IOC_HWSEM_TOV); + bfa_sem_timer_start(ioc); } void @@ -779,7 +1177,7 @@ bfa_ioc_hw_sem_release(struct bfa_ioc_s *ioc) static void bfa_ioc_hw_sem_get_cancel(struct bfa_ioc_s *ioc) { - bfa_timer_stop(&ioc->sem_timer); + bfa_sem_timer_stop(ioc); } /** @@ -788,14 +1186,18 @@ bfa_ioc_hw_sem_get_cancel(struct bfa_ioc_s *ioc) static void bfa_ioc_lmem_init(struct bfa_ioc_s *ioc) { - u32 pss_ctl; - int i; + u32 pss_ctl; + int i; #define PSS_LMEM_INIT_TIME 10000 pss_ctl = bfa_reg_read(ioc->ioc_regs.pss_ctl_reg); pss_ctl &= ~__PSS_LMEM_RESET; pss_ctl |= __PSS_LMEM_INIT_EN; - pss_ctl |= __PSS_I2C_CLK_DIV(3UL); /* i2c workaround 12.5khz clock */ + + /* + * i2c workaround 12.5khz clock + */ + pss_ctl |= __PSS_I2C_CLK_DIV(3UL); bfa_reg_write(ioc->ioc_regs.pss_ctl_reg, pss_ctl); /** @@ -821,7 +1223,7 @@ bfa_ioc_lmem_init(struct bfa_ioc_s *ioc) static void bfa_ioc_lpu_start(struct bfa_ioc_s *ioc) { - u32 pss_ctl; + u32 pss_ctl; /** * Take processor out of reset. @@ -835,7 +1237,7 @@ bfa_ioc_lpu_start(struct bfa_ioc_s *ioc) static void bfa_ioc_lpu_stop(struct bfa_ioc_s *ioc) { - u32 pss_ctl; + u32 pss_ctl; /** * Put processors in reset. @@ -852,10 +1254,10 @@ bfa_ioc_lpu_stop(struct bfa_ioc_s *ioc) void bfa_ioc_fwver_get(struct bfa_ioc_s *ioc, struct bfi_ioc_image_hdr_s *fwhdr) { - u32 pgnum, pgoff; - u32 loff = 0; - int i; - u32 *fwsig = (u32 *) fwhdr; + u32 pgnum, pgoff; + u32 loff = 0; + int i; + u32 *fwsig = (u32 *) fwhdr; pgnum = bfa_ioc_smem_pgnum(ioc, loff); pgoff = bfa_ioc_smem_pgoff(ioc, loff); @@ -863,7 +1265,8 @@ bfa_ioc_fwver_get(struct bfa_ioc_s *ioc, struct bfi_ioc_image_hdr_s *fwhdr) for (i = 0; i < (sizeof(struct bfi_ioc_image_hdr_s) / sizeof(u32)); i++) { - fwsig[i] = bfa_mem_read(ioc->ioc_regs.smem_page_start, loff); + fwsig[i] = + bfa_mem_read(ioc->ioc_regs.smem_page_start, loff); loff += sizeof(u32); } } @@ -875,10 +1278,10 @@ bfa_boolean_t bfa_ioc_fwver_cmp(struct bfa_ioc_s *ioc, struct bfi_ioc_image_hdr_s *fwhdr) { struct bfi_ioc_image_hdr_s *drv_fwhdr; - int i; + int i; drv_fwhdr = (struct bfi_ioc_image_hdr_s *) - bfi_image_get_chunk(BFA_IOC_FWIMG_TYPE(ioc), 0); + bfa_cb_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]) { @@ -897,21 +1300,20 @@ bfa_ioc_fwver_cmp(struct bfa_ioc_s *ioc, struct bfi_ioc_image_hdr_s *fwhdr) * Return true if current running version is valid. Firmware signature and * execution context (driver/bios) must match. */ -static bfa_boolean_t -bfa_ioc_fwver_valid(struct bfa_ioc_s *ioc) +static bfa_boolean_t +bfa_ioc_fwver_valid(struct bfa_ioc_s *ioc, u32 boot_env) { struct bfi_ioc_image_hdr_s fwhdr, *drv_fwhdr; /** * If bios/efi boot (flash based) -- return true */ - if (bfa_ioc_is_optrom(ioc)) + if (bfa_ioc_is_bios_optrom(ioc)) return BFA_TRUE; bfa_ioc_fwver_get(ioc, &fwhdr); drv_fwhdr = (struct bfi_ioc_image_hdr_s *) - bfi_image_get_chunk(BFA_IOC_FWIMG_TYPE(ioc), 0); - + bfa_cb_image_get_chunk(BFA_IOC_FWIMG_TYPE(ioc), 0); if (fwhdr.signature != drv_fwhdr->signature) { bfa_trc(ioc, fwhdr.signature); @@ -919,9 +1321,9 @@ bfa_ioc_fwver_valid(struct bfa_ioc_s *ioc) return BFA_FALSE; } - if (fwhdr.exec != drv_fwhdr->exec) { - bfa_trc(ioc, fwhdr.exec); - bfa_trc(ioc, drv_fwhdr->exec); + if (bfa_os_swap32(fwhdr.param) != boot_env) { + bfa_trc(ioc, fwhdr.param); + bfa_trc(ioc, boot_env); return BFA_FALSE; } @@ -934,7 +1336,7 @@ bfa_ioc_fwver_valid(struct bfa_ioc_s *ioc) static void bfa_ioc_msgflush(struct bfa_ioc_s *ioc) { - u32 r32; + u32 r32; r32 = bfa_reg_read(ioc->ioc_regs.lpu_mbox_cmd); if (r32) @@ -946,7 +1348,9 @@ static void bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force) { enum bfi_ioc_state ioc_fwstate; - bfa_boolean_t fwvalid; + bfa_boolean_t fwvalid; + u32 boot_type; + u32 boot_env; ioc_fwstate = bfa_reg_read(ioc->ioc_regs.ioc_fwstate); @@ -955,14 +1359,33 @@ bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force) bfa_trc(ioc, ioc_fwstate); + boot_type = BFI_BOOT_TYPE_NORMAL; + boot_env = BFI_BOOT_LOADER_OS; + + /** + * Flash based firmware boot BIOS env. + */ + if (bfa_ioc_is_bios_optrom(ioc)) { + boot_type = BFI_BOOT_TYPE_FLASH; + boot_env = BFI_BOOT_LOADER_BIOS; + } + + /** + * Flash based firmware boot UEFI env. + */ + if (bfa_ioc_is_uefi(ioc)) { + boot_type = BFI_BOOT_TYPE_FLASH; + boot_env = BFI_BOOT_LOADER_UEFI; + } + /** * check if firmware is valid */ fwvalid = (ioc_fwstate == BFI_IOC_UNINIT) ? - BFA_FALSE : bfa_ioc_fwver_valid(ioc); + BFA_FALSE : bfa_ioc_fwver_valid(ioc, boot_env); if (!fwvalid) { - bfa_ioc_boot(ioc, BFI_BOOT_TYPE_NORMAL, ioc->pcidev.device_id); + bfa_ioc_boot(ioc, boot_type, boot_env); return; } @@ -971,7 +1394,6 @@ bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force) * just wait for an initialization completion interrupt. */ if (ioc_fwstate == BFI_IOC_INITING) { - bfa_trc(ioc, ioc_fwstate); ioc->cbfn->reset_cbfn(ioc->bfa); return; } @@ -985,8 +1407,7 @@ bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force) * is loaded. */ if (ioc_fwstate == BFI_IOC_DISABLED || - (!bfa_ioc_is_optrom(ioc) && ioc_fwstate == BFI_IOC_OP)) { - bfa_trc(ioc, ioc_fwstate); + (!bfa_ioc_is_bios_optrom(ioc) && ioc_fwstate == BFI_IOC_OP)) { /** * When using MSI-X any pending firmware ready event should @@ -994,20 +1415,20 @@ bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force) */ bfa_ioc_msgflush(ioc); ioc->cbfn->reset_cbfn(ioc->bfa); - bfa_fsm_send_event(ioc, IOC_E_FWREADY); + bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_FWREADY); return; } /** * Initialize the h/w for any other states. */ - bfa_ioc_boot(ioc, BFI_BOOT_TYPE_NORMAL, ioc->pcidev.device_id); + bfa_ioc_boot(ioc, boot_type, boot_env); } static void bfa_ioc_timeout(void *ioc_arg) { - struct bfa_ioc_s *ioc = (struct bfa_ioc_s *)ioc_arg; + struct bfa_ioc_s *ioc = (struct bfa_ioc_s *) ioc_arg; bfa_trc(ioc, 0); bfa_fsm_send_event(ioc, IOC_E_TIMEOUT); @@ -1016,8 +1437,8 @@ bfa_ioc_timeout(void *ioc_arg) void bfa_ioc_mbox_send(struct bfa_ioc_s *ioc, void *ioc_msg, int len) { - u32 *msgp = (u32 *) ioc_msg; - u32 i; + u32 *msgp = (u32 *) ioc_msg; + u32 i; bfa_trc(ioc, msgp[0]); bfa_trc(ioc, len); @@ -1038,17 +1459,20 @@ bfa_ioc_mbox_send(struct bfa_ioc_s *ioc, void *ioc_msg, int len) * write 1 to mailbox CMD to trigger LPU event */ bfa_reg_write(ioc->ioc_regs.hfn_mbox_cmd, 1); - (void)bfa_reg_read(ioc->ioc_regs.hfn_mbox_cmd); + (void) bfa_reg_read(ioc->ioc_regs.hfn_mbox_cmd); } static void bfa_ioc_send_enable(struct bfa_ioc_s *ioc) { struct bfi_ioc_ctrl_req_s enable_req; + struct bfa_timeval_s tv; bfi_h2i_set(enable_req.mh, BFI_MC_IOC, BFI_IOC_H2I_ENABLE_REQ, bfa_ioc_portid(ioc)); enable_req.ioc_class = ioc->ioc_mc; + bfa_os_gettimeofday(&tv); + enable_req.tv_sec = bfa_os_ntohl(tv.tv_sec); bfa_ioc_mbox_send(ioc, &enable_req, sizeof(struct bfi_ioc_ctrl_req_s)); } @@ -1065,7 +1489,7 @@ bfa_ioc_send_disable(struct bfa_ioc_s *ioc) static void bfa_ioc_send_getattr(struct bfa_ioc_s *ioc) { - struct bfi_ioc_getattr_req_s attr_req; + struct bfi_ioc_getattr_req_s attr_req; bfi_h2i_set(attr_req.mh, BFI_MC_IOC, BFI_IOC_H2I_GETATTR_REQ, bfa_ioc_portid(ioc)); @@ -1077,12 +1501,11 @@ static void bfa_ioc_hb_check(void *cbarg) { struct bfa_ioc_s *ioc = cbarg; - u32 hb_count; + u32 hb_count; hb_count = bfa_reg_read(ioc->ioc_regs.heartbeat); if (ioc->hb_count == hb_count) { - bfa_log(ioc->logm, BFA_LOG_HAL_HEARTBEAT_FAILURE, - hb_count); + printk(KERN_CRIT "Firmware heartbeat failure at %d", hb_count); bfa_ioc_recover(ioc); return; } else { @@ -1090,61 +1513,54 @@ bfa_ioc_hb_check(void *cbarg) } bfa_ioc_mbox_poll(ioc); - bfa_timer_begin(ioc->timer_mod, &ioc->ioc_timer, bfa_ioc_hb_check, - ioc, BFA_IOC_HB_TOV); + bfa_hb_timer_start(ioc); } static void bfa_ioc_hb_monitor(struct bfa_ioc_s *ioc) { ioc->hb_count = bfa_reg_read(ioc->ioc_regs.heartbeat); - bfa_timer_begin(ioc->timer_mod, &ioc->ioc_timer, bfa_ioc_hb_check, ioc, - BFA_IOC_HB_TOV); + bfa_hb_timer_start(ioc); } static void bfa_ioc_hb_stop(struct bfa_ioc_s *ioc) { - bfa_timer_stop(&ioc->ioc_timer); + bfa_hb_timer_stop(ioc); } + /** - * Initiate a full firmware download. + * Initiate a full firmware download. */ static void bfa_ioc_download_fw(struct bfa_ioc_s *ioc, u32 boot_type, - u32 boot_param) + u32 boot_env) { - u32 *fwimg; - u32 pgnum, pgoff; - u32 loff = 0; - u32 chunkno = 0; - u32 i; + u32 *fwimg; + u32 pgnum, pgoff; + u32 loff = 0; + u32 chunkno = 0; + u32 i; /** * Initialize LMEM first before code download */ bfa_ioc_lmem_init(ioc); - /** - * Flash based firmware boot - */ - bfa_trc(ioc, bfi_image_get_size(BFA_IOC_FWIMG_TYPE(ioc))); - if (bfa_ioc_is_optrom(ioc)) - boot_type = BFI_BOOT_TYPE_FLASH; - fwimg = bfi_image_get_chunk(BFA_IOC_FWIMG_TYPE(ioc), chunkno); - + bfa_trc(ioc, bfa_cb_image_get_size(BFA_IOC_FWIMG_TYPE(ioc))); + fwimg = bfa_cb_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 < bfi_image_get_size(BFA_IOC_FWIMG_TYPE(ioc)); i++) { + for (i = 0; i < bfa_cb_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 = bfi_image_get_chunk(BFA_IOC_FWIMG_TYPE(ioc), + fwimg = bfa_cb_image_get_chunk(BFA_IOC_FWIMG_TYPE(ioc), BFA_IOC_FLASH_CHUNK_ADDR(chunkno)); } @@ -1162,7 +1578,8 @@ bfa_ioc_download_fw(struct bfa_ioc_s *ioc, u32 boot_type, loff = PSS_SMEM_PGOFF(loff); if (loff == 0) { pgnum++; - bfa_reg_write(ioc->ioc_regs.host_page_num_fn, pgnum); + bfa_reg_write(ioc->ioc_regs.host_page_num_fn, + pgnum); } } @@ -1171,11 +1588,11 @@ bfa_ioc_download_fw(struct bfa_ioc_s *ioc, u32 boot_type, /* * Set boot type and boot param at the end. - */ + */ bfa_mem_write(ioc->ioc_regs.smem_page_start, BFI_BOOT_TYPE_OFF, bfa_os_swap32(boot_type)); - bfa_mem_write(ioc->ioc_regs.smem_page_start, BFI_BOOT_PARAM_OFF, - bfa_os_swap32(boot_param)); + bfa_mem_write(ioc->ioc_regs.smem_page_start, BFI_BOOT_LOADER_OFF, + bfa_os_swap32(boot_env)); } static void @@ -1190,11 +1607,11 @@ bfa_ioc_reset(struct bfa_ioc_s *ioc, bfa_boolean_t force) static void bfa_ioc_getattr_reply(struct bfa_ioc_s *ioc) { - struct bfi_ioc_attr_s *attr = ioc->attr; + struct bfi_ioc_attr_s *attr = ioc->attr; - attr->adapter_prop = bfa_os_ntohl(attr->adapter_prop); + 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); + attr->maxfrsize = bfa_os_ntohs(attr->maxfrsize); bfa_fsm_send_event(ioc, IOC_E_FWRSP_GETATTR); } @@ -1205,8 +1622,8 @@ bfa_ioc_getattr_reply(struct bfa_ioc_s *ioc) static void bfa_ioc_mbox_attach(struct bfa_ioc_s *ioc) { - struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod; - int mc; + struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod; + int mc; INIT_LIST_HEAD(&mod->cmd_q); for (mc = 0; mc < BFI_MC_MAX; mc++) { @@ -1221,9 +1638,9 @@ bfa_ioc_mbox_attach(struct bfa_ioc_s *ioc) static void bfa_ioc_mbox_poll(struct bfa_ioc_s *ioc) { - struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod; - struct bfa_mbox_cmd_s *cmd; - u32 stat; + struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod; + struct bfa_mbox_cmd_s *cmd; + u32 stat; /** * If no command pending, do nothing @@ -1251,25 +1668,194 @@ bfa_ioc_mbox_poll(struct bfa_ioc_s *ioc) static void bfa_ioc_mbox_hbfail(struct bfa_ioc_s *ioc) { - struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod; - struct bfa_mbox_cmd_s *cmd; + struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod; + struct bfa_mbox_cmd_s *cmd; while (!list_empty(&mod->cmd_q)) bfa_q_deq(&mod->cmd_q, &cmd); } /** - * bfa_ioc_public + * Read data from SMEM to host through PCI memmap + * + * @param[in] ioc memory for IOC + * @param[in] tbuf app memory to store data from smem + * @param[in] soff smem offset + * @param[in] sz size of smem in bytes + */ +static bfa_status_t +bfa_ioc_smem_read(struct bfa_ioc_s *ioc, void *tbuf, u32 soff, u32 sz) +{ + u32 pgnum, loff, r32; + int i, len; + u32 *buf = tbuf; + + pgnum = bfa_ioc_smem_pgnum(ioc, soff); + loff = bfa_ioc_smem_pgoff(ioc, soff); + bfa_trc(ioc, pgnum); + bfa_trc(ioc, loff); + bfa_trc(ioc, sz); + + /* + * Hold semaphore to serialize pll init and fwtrc. + */ + if (BFA_FALSE == bfa_ioc_sem_get(ioc->ioc_regs.ioc_init_sem_reg)) { + bfa_trc(ioc, 0); + return BFA_STATUS_FAILED; + } + + bfa_reg_write(ioc->ioc_regs.host_page_num_fn, pgnum); + + len = sz/sizeof(u32); + bfa_trc(ioc, len); + for (i = 0; i < len; i++) { + r32 = bfa_mem_read(ioc->ioc_regs.smem_page_start, loff); + buf[i] = bfa_os_ntohl(r32); + loff += sizeof(u32); + + /** + * handle page offset wrap around + */ + loff = PSS_SMEM_PGOFF(loff); + if (loff == 0) { + pgnum++; + bfa_reg_write(ioc->ioc_regs.host_page_num_fn, pgnum); + } + } + bfa_reg_write(ioc->ioc_regs.host_page_num_fn, + bfa_ioc_smem_pgnum(ioc, 0)); + /* + * release semaphore. + */ + bfa_ioc_sem_release(ioc->ioc_regs.ioc_init_sem_reg); + + bfa_trc(ioc, pgnum); + return BFA_STATUS_OK; +} + +/** + * Clear SMEM data from host through PCI memmap + * + * @param[in] ioc memory for IOC + * @param[in] soff smem offset + * @param[in] sz size of smem in bytes + */ +static bfa_status_t +bfa_ioc_smem_clr(struct bfa_ioc_s *ioc, u32 soff, u32 sz) +{ + int i, len; + u32 pgnum, loff; + + pgnum = bfa_ioc_smem_pgnum(ioc, soff); + loff = bfa_ioc_smem_pgoff(ioc, soff); + bfa_trc(ioc, pgnum); + bfa_trc(ioc, loff); + bfa_trc(ioc, sz); + + /* + * Hold semaphore to serialize pll init and fwtrc. + */ + if (BFA_FALSE == bfa_ioc_sem_get(ioc->ioc_regs.ioc_init_sem_reg)) { + bfa_trc(ioc, 0); + return BFA_STATUS_FAILED; + } + + bfa_reg_write(ioc->ioc_regs.host_page_num_fn, pgnum); + + len = sz/sizeof(u32); /* len in words */ + bfa_trc(ioc, len); + for (i = 0; i < len; i++) { + bfa_mem_write(ioc->ioc_regs.smem_page_start, loff, 0); + loff += sizeof(u32); + + /** + * handle page offset wrap around + */ + loff = PSS_SMEM_PGOFF(loff); + if (loff == 0) { + pgnum++; + bfa_reg_write(ioc->ioc_regs.host_page_num_fn, pgnum); + } + } + bfa_reg_write(ioc->ioc_regs.host_page_num_fn, + bfa_ioc_smem_pgnum(ioc, 0)); + + /* + * release semaphore. + */ + bfa_ioc_sem_release(ioc->ioc_regs.ioc_init_sem_reg); + bfa_trc(ioc, pgnum); + return BFA_STATUS_OK; +} + +/** + * hal iocpf to ioc interface + */ +static void +bfa_ioc_pf_enabled(struct bfa_ioc_s *ioc) +{ + bfa_fsm_send_event(ioc, IOC_E_ENABLED); +} + +static void +bfa_ioc_pf_disabled(struct bfa_ioc_s *ioc) +{ + bfa_fsm_send_event(ioc, IOC_E_DISABLED); +} + +static void +bfa_ioc_pf_failed(struct bfa_ioc_s *ioc) +{ + bfa_fsm_send_event(ioc, IOC_E_FAILED); +} + +static void +bfa_ioc_pf_fwmismatch(struct bfa_ioc_s *ioc) +{ + struct bfad_s *bfad = (struct bfad_s *)ioc->bfa->bfad; + /** + * Provide enable completion callback. + */ + ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE); + BFA_LOG(KERN_WARNING, bfad, log_level, + "Running firmware version is incompatible " + "with the driver version\n"); +} + + + +/** + * hal_ioc_public */ +bfa_status_t +bfa_ioc_pll_init(struct bfa_ioc_s *ioc) +{ + + /* + * Hold semaphore so that nobody can access the chip during init. + */ + bfa_ioc_sem_get(ioc->ioc_regs.ioc_init_sem_reg); + + bfa_ioc_pll_init_asic(ioc); + + ioc->pllinit = BFA_TRUE; + /* + * release semaphore. + */ + bfa_ioc_sem_release(ioc->ioc_regs.ioc_init_sem_reg); + + return BFA_STATUS_OK; +} + /** * Interface used by diag module to do firmware boot with memory test * as the entry vector. */ void -bfa_ioc_boot(struct bfa_ioc_s *ioc, u32 boot_type, u32 boot_param) +bfa_ioc_boot(struct bfa_ioc_s *ioc, u32 boot_type, u32 boot_env) { - bfa_os_addr_t rb; + bfa_os_addr_t rb; bfa_ioc_stats(ioc, ioc_boots); @@ -1280,7 +1866,7 @@ bfa_ioc_boot(struct bfa_ioc_s *ioc, u32 boot_type, u32 boot_param) * Initialize IOC state of all functions on a chip reset. */ rb = ioc->pcidev.pci_bar_kva; - if (boot_param == BFI_BOOT_TYPE_MEMTEST) { + if (boot_type == BFI_BOOT_TYPE_MEMTEST) { bfa_reg_write((rb + BFA_IOC0_STATE_REG), BFI_IOC_MEMTEST); bfa_reg_write((rb + BFA_IOC1_STATE_REG), BFI_IOC_MEMTEST); } else { @@ -1289,7 +1875,7 @@ bfa_ioc_boot(struct bfa_ioc_s *ioc, u32 boot_type, u32 boot_param) } bfa_ioc_msgflush(ioc); - bfa_ioc_download_fw(ioc, boot_type, boot_param); + bfa_ioc_download_fw(ioc, boot_type, boot_env); /** * Enable interrupts just before starting LPU @@ -1308,18 +1894,29 @@ bfa_ioc_auto_recover(bfa_boolean_t auto_recover) } + bfa_boolean_t bfa_ioc_is_operational(struct bfa_ioc_s *ioc) { return bfa_fsm_cmp_state(ioc, bfa_ioc_sm_op); } +bfa_boolean_t +bfa_ioc_is_initialized(struct bfa_ioc_s *ioc) +{ + u32 r32 = bfa_reg_read(ioc->ioc_regs.ioc_fwstate); + + return ((r32 != BFI_IOC_UNINIT) && + (r32 != BFI_IOC_INITING) && + (r32 != BFI_IOC_MEMTEST)); +} + void bfa_ioc_msgget(struct bfa_ioc_s *ioc, void *mbmsg) { - u32 *msgp = mbmsg; - u32 r32; - int i; + u32 *msgp = mbmsg; + u32 r32; + int i; /** * read the MBOX msg @@ -1341,9 +1938,10 @@ bfa_ioc_msgget(struct bfa_ioc_s *ioc, void *mbmsg) void bfa_ioc_isr(struct bfa_ioc_s *ioc, struct bfi_mbmsg_s *m) { - union bfi_ioc_i2h_msg_u *msg; + union bfi_ioc_i2h_msg_u *msg; + struct bfa_iocpf_s *iocpf = &ioc->iocpf; - msg = (union bfi_ioc_i2h_msg_u *)m; + msg = (union bfi_ioc_i2h_msg_u *) m; bfa_ioc_stats(ioc, ioc_isrs); @@ -1352,15 +1950,15 @@ bfa_ioc_isr(struct bfa_ioc_s *ioc, struct bfi_mbmsg_s *m) break; case BFI_IOC_I2H_READY_EVENT: - bfa_fsm_send_event(ioc, IOC_E_FWREADY); + bfa_fsm_send_event(iocpf, IOCPF_E_FWREADY); break; case BFI_IOC_I2H_ENABLE_REPLY: - bfa_fsm_send_event(ioc, IOC_E_FWRSP_ENABLE); + bfa_fsm_send_event(iocpf, IOCPF_E_FWRSP_ENABLE); break; case BFI_IOC_I2H_DISABLE_REPLY: - bfa_fsm_send_event(ioc, IOC_E_FWRSP_DISABLE); + bfa_fsm_send_event(iocpf, IOCPF_E_FWRSP_DISABLE); break; case BFI_IOC_I2H_GETATTR_REPLY: @@ -1378,29 +1976,24 @@ bfa_ioc_isr(struct bfa_ioc_s *ioc, struct bfi_mbmsg_s *m) * * @param[in] ioc memory for IOC * @param[in] bfa driver instance structure - * @param[in] trcmod kernel trace module - * @param[in] aen kernel aen event module - * @param[in] logm kernel logging module */ void bfa_ioc_attach(struct bfa_ioc_s *ioc, void *bfa, struct bfa_ioc_cbfn_s *cbfn, - struct bfa_timer_mod_s *timer_mod, struct bfa_trc_mod_s *trcmod, - struct bfa_aen_s *aen, struct bfa_log_mod_s *logm) -{ - ioc->bfa = bfa; - ioc->cbfn = cbfn; - ioc->timer_mod = timer_mod; - ioc->trcmod = trcmod; - ioc->aen = aen; - ioc->logm = logm; - ioc->fcmode = BFA_FALSE; - ioc->pllinit = BFA_FALSE; + struct bfa_timer_mod_s *timer_mod) +{ + ioc->bfa = bfa; + ioc->cbfn = cbfn; + ioc->timer_mod = timer_mod; + ioc->fcmode = BFA_FALSE; + ioc->pllinit = BFA_FALSE; ioc->dbg_fwsave_once = BFA_TRUE; + ioc->iocpf.ioc = ioc; bfa_ioc_mbox_attach(ioc); INIT_LIST_HEAD(&ioc->hb_notify_q); - bfa_fsm_set_state(ioc, bfa_ioc_sm_reset); + bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit); + bfa_fsm_send_event(ioc, IOC_E_RESET); } /** @@ -1421,10 +2014,10 @@ void bfa_ioc_pci_init(struct bfa_ioc_s *ioc, struct bfa_pcidev_s *pcidev, enum bfi_mclass mc) { - ioc->ioc_mc = mc; - ioc->pcidev = *pcidev; - ioc->ctdev = bfa_asic_id_ct(ioc->pcidev.device_id); - ioc->cna = ioc->ctdev && !ioc->fcmode; + ioc->ioc_mc = mc; + ioc->pcidev = *pcidev; + ioc->ctdev = bfa_asic_id_ct(ioc->pcidev.device_id); + ioc->cna = ioc->ctdev && !ioc->fcmode; /** * Set asic specific interfaces. See bfa_ioc_cb.c and bfa_ioc_ct.c @@ -1445,14 +2038,14 @@ bfa_ioc_pci_init(struct bfa_ioc_s *ioc, struct bfa_pcidev_s *pcidev, * @param[in] dm_pa physical address of IOC dma memory */ void -bfa_ioc_mem_claim(struct bfa_ioc_s *ioc, u8 *dm_kva, u64 dm_pa) +bfa_ioc_mem_claim(struct bfa_ioc_s *ioc, u8 *dm_kva, u64 dm_pa) { /** * dma memory for firmware attribute */ ioc->attr_dma.kva = dm_kva; ioc->attr_dma.pa = dm_pa; - ioc->attr = (struct bfi_ioc_attr_s *)dm_kva; + ioc->attr = (struct bfi_ioc_attr_s *) dm_kva; } /** @@ -1490,7 +2083,7 @@ bfa_ioc_disable(struct bfa_ioc_s *ioc) int bfa_ioc_debug_trcsz(bfa_boolean_t auto_recover) { -return (auto_recover) ? BFA_DBG_FWTRC_LEN : 0; + return (auto_recover) ? BFA_DBG_FWTRC_LEN : 0; } /** @@ -1500,8 +2093,8 @@ return (auto_recover) ? BFA_DBG_FWTRC_LEN : 0; void bfa_ioc_debug_memclaim(struct bfa_ioc_s *ioc, void *dbg_fwsave) { - ioc->dbg_fwsave = dbg_fwsave; - ioc->dbg_fwsave_len = bfa_ioc_debug_trcsz(ioc->auto_recover); + ioc->dbg_fwsave = dbg_fwsave; + ioc->dbg_fwsave_len = bfa_ioc_debug_trcsz(ioc->iocpf.auto_recover); } u32 @@ -1525,8 +2118,8 @@ bfa_ioc_smem_pgoff(struct bfa_ioc_s *ioc, u32 fmaddr) void bfa_ioc_mbox_register(struct bfa_ioc_s *ioc, bfa_ioc_mbox_mcfunc_t *mcfuncs) { - struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod; - int mc; + struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod; + int mc; for (mc = 0; mc < BFI_MC_MAX; mc++) mod->mbhdlr[mc].cbfn = mcfuncs[mc]; @@ -1539,10 +2132,10 @@ void bfa_ioc_mbox_regisr(struct bfa_ioc_s *ioc, enum bfi_mclass mc, bfa_ioc_mbox_mcfunc_t cbfn, void *cbarg) { - struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod; + struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod; - mod->mbhdlr[mc].cbfn = cbfn; - mod->mbhdlr[mc].cbarg = cbarg; + mod->mbhdlr[mc].cbfn = cbfn; + mod->mbhdlr[mc].cbarg = cbarg; } /** @@ -1555,8 +2148,8 @@ bfa_ioc_mbox_regisr(struct bfa_ioc_s *ioc, enum bfi_mclass mc, void bfa_ioc_mbox_queue(struct bfa_ioc_s *ioc, struct bfa_mbox_cmd_s *cmd) { - struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod; - u32 stat; + struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod; + u32 stat; /** * If a previous command is pending, queue new command @@ -1587,9 +2180,9 @@ bfa_ioc_mbox_queue(struct bfa_ioc_s *ioc, struct bfa_mbox_cmd_s *cmd) void bfa_ioc_mbox_isr(struct bfa_ioc_s *ioc) { - struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod; - struct bfi_mbmsg_s m; - int mc; + struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod; + struct bfi_mbmsg_s m; + int mc; bfa_ioc_msgget(ioc, &m); @@ -1621,16 +2214,14 @@ bfa_ioc_set_fcmode(struct bfa_ioc_s *ioc) ioc->port_id = bfa_ioc_pcifn(ioc); } -#ifndef BFA_BIOS_BUILD - /** * return true if IOC is disabled */ bfa_boolean_t bfa_ioc_is_disabled(struct bfa_ioc_s *ioc) { - return bfa_fsm_cmp_state(ioc, bfa_ioc_sm_disabling) - || bfa_fsm_cmp_state(ioc, bfa_ioc_sm_disabled); + return bfa_fsm_cmp_state(ioc, bfa_ioc_sm_disabling) || + bfa_fsm_cmp_state(ioc, bfa_ioc_sm_disabled); } /** @@ -1639,9 +2230,9 @@ bfa_ioc_is_disabled(struct bfa_ioc_s *ioc) bfa_boolean_t bfa_ioc_fw_mismatch(struct bfa_ioc_s *ioc) { - return bfa_fsm_cmp_state(ioc, bfa_ioc_sm_reset) - || bfa_fsm_cmp_state(ioc, bfa_ioc_sm_fwcheck) - || bfa_fsm_cmp_state(ioc, bfa_ioc_sm_mismatch); + return bfa_fsm_cmp_state(ioc, bfa_ioc_sm_reset) || + bfa_fsm_cmp_state(&ioc->iocpf, bfa_iocpf_sm_fwcheck) || + bfa_fsm_cmp_state(&ioc->iocpf, bfa_iocpf_sm_mismatch); } #define bfa_ioc_state_disabled(__sm) \ @@ -1659,8 +2250,8 @@ bfa_ioc_fw_mismatch(struct bfa_ioc_s *ioc) bfa_boolean_t bfa_ioc_adapter_is_disabled(struct bfa_ioc_s *ioc) { - u32 ioc_state; - bfa_os_addr_t rb = ioc->pcidev.pci_bar_kva; + u32 ioc_state; + bfa_os_addr_t rb = ioc->pcidev.pci_bar_kva; if (!bfa_fsm_cmp_state(ioc, bfa_ioc_sm_disabled)) return BFA_FALSE; @@ -1669,16 +2260,18 @@ bfa_ioc_adapter_is_disabled(struct bfa_ioc_s *ioc) if (!bfa_ioc_state_disabled(ioc_state)) return BFA_FALSE; - ioc_state = bfa_reg_read(rb + BFA_IOC1_STATE_REG); - if (!bfa_ioc_state_disabled(ioc_state)) - return BFA_FALSE; + if (ioc->pcidev.device_id != BFA_PCI_DEVICE_ID_FC_8G1P) { + ioc_state = bfa_reg_read(rb + BFA_IOC1_STATE_REG); + if (!bfa_ioc_state_disabled(ioc_state)) + return BFA_FALSE; + } return BFA_TRUE; } /** * Add to IOC heartbeat failure notification queue. To be used by common - * modules such as + * modules such as cee, port, diag. */ void bfa_ioc_hbfail_register(struct bfa_ioc_s *ioc, @@ -1692,7 +2285,7 @@ void bfa_ioc_get_adapter_attr(struct bfa_ioc_s *ioc, struct bfa_adapter_attr_s *ad_attr) { - struct bfi_ioc_attr_s *ioc_attr; + struct bfi_ioc_attr_s *ioc_attr; ioc_attr = ioc->attr; @@ -1719,7 +2312,7 @@ bfa_ioc_get_adapter_attr(struct bfa_ioc_s *ioc, ad_attr->prototype = 0; ad_attr->pwwn = bfa_ioc_get_pwwn(ioc); - ad_attr->mac = bfa_ioc_get_mac(ioc); + ad_attr->mac = bfa_ioc_get_mac(ioc); ad_attr->pcie_gen = ioc_attr->pcie_gen; ad_attr->pcie_lanes = ioc_attr->pcie_lanes; @@ -1729,6 +2322,7 @@ bfa_ioc_get_adapter_attr(struct bfa_ioc_s *ioc, bfa_ioc_get_pci_chip_rev(ioc, ad_attr->hw_ver); ad_attr->cna_capable = ioc->cna; + ad_attr->trunk_capable = (ad_attr->nports > 1) && !ioc->cna; } enum bfa_ioc_type_e @@ -1782,7 +2376,7 @@ bfa_ioc_get_adapter_optrom_ver(struct bfa_ioc_s *ioc, char *optrom_ver) { bfa_os_memset((void *)optrom_ver, 0, BFA_VERSION_LEN); bfa_os_memcpy(optrom_ver, ioc->attr->optrom_version, - BFA_VERSION_LEN); + BFA_VERSION_LEN); } void @@ -1795,7 +2389,7 @@ bfa_ioc_get_adapter_manufacturer(struct bfa_ioc_s *ioc, char *manufacturer) void bfa_ioc_get_adapter_model(struct bfa_ioc_s *ioc, char *model) { - struct bfi_ioc_attr_s *ioc_attr; + struct bfi_ioc_attr_s *ioc_attr; bfa_assert(model); bfa_os_memset((void *)model, 0, BFA_ADAPTER_MODEL_NAME_LEN); @@ -1805,14 +2399,48 @@ bfa_ioc_get_adapter_model(struct bfa_ioc_s *ioc, char *model) /** * model name */ - snprintf(model, BFA_ADAPTER_MODEL_NAME_LEN, "%s-%u", - BFA_MFG_NAME, ioc_attr->card_type); + bfa_os_snprintf(model, BFA_ADAPTER_MODEL_NAME_LEN, "%s-%u", + BFA_MFG_NAME, ioc_attr->card_type); } enum bfa_ioc_state bfa_ioc_get_state(struct bfa_ioc_s *ioc) { - return bfa_sm_to_state(ioc_sm_table, ioc->fsm); + enum bfa_iocpf_state iocpf_st; + enum bfa_ioc_state ioc_st = bfa_sm_to_state(ioc_sm_table, ioc->fsm); + + if (ioc_st == BFA_IOC_ENABLING || + ioc_st == BFA_IOC_FAIL || ioc_st == BFA_IOC_INITFAIL) { + + iocpf_st = bfa_sm_to_state(iocpf_sm_table, ioc->iocpf.fsm); + + switch (iocpf_st) { + case BFA_IOCPF_SEMWAIT: + ioc_st = BFA_IOC_SEMWAIT; + break; + + case BFA_IOCPF_HWINIT: + ioc_st = BFA_IOC_HWINIT; + break; + + case BFA_IOCPF_FWMISMATCH: + ioc_st = BFA_IOC_FWMISMATCH; + break; + + case BFA_IOCPF_FAIL: + ioc_st = BFA_IOC_FAIL; + break; + + case BFA_IOCPF_INITFAIL: + ioc_st = BFA_IOC_INITFAIL; + break; + + default: + break; + } + } + + return ioc_st; } void @@ -1833,7 +2461,7 @@ bfa_ioc_get_attr(struct bfa_ioc_s *ioc, struct bfa_ioc_attr_s *ioc_attr) } /** - * bfa_wwn_public + * hal_wwn_public */ wwn_t bfa_ioc_get_pwwn(struct bfa_ioc_s *ioc) @@ -1857,10 +2485,10 @@ mac_t bfa_ioc_get_mac(struct bfa_ioc_s *ioc) { /* - * Currently mfg mac is used as FCoE enode mac (not configured by PBC) + * Check the IOC type and return the appropriate MAC */ if (bfa_ioc_get_type(ioc) == BFA_IOC_TYPE_FCoE) - return bfa_ioc_get_mfg_mac(ioc); + return ioc->attr->fcoe_mac; else return ioc->attr->mac; } @@ -1880,12 +2508,16 @@ bfa_ioc_get_mfg_nwwn(struct bfa_ioc_s *ioc) mac_t bfa_ioc_get_mfg_mac(struct bfa_ioc_s *ioc) { - mac_t mac; + mac_t m; - mac = ioc->attr->mfg_mac; - mac.mac[MAC_ADDRLEN - 1] += bfa_ioc_pcifn(ioc); + m = ioc->attr->mfg_mac; + if (bfa_mfg_is_old_wwn_mac_model(ioc->attr->card_type)) + m.mac[MAC_ADDRLEN - 1] += bfa_ioc_pcifn(ioc); + else + bfa_mfg_increment_wwn_mac(&(m.mac[MAC_ADDRLEN-3]), + bfa_ioc_pcifn(ioc)); - return mac; + return m; } bfa_boolean_t @@ -1895,46 +2527,12 @@ bfa_ioc_get_fcmode(struct bfa_ioc_s *ioc) } /** - * Send AEN notification - */ -void -bfa_ioc_aen_post(struct bfa_ioc_s *ioc, enum bfa_ioc_aen_event event) -{ - union bfa_aen_data_u aen_data; - struct bfa_log_mod_s *logmod = ioc->logm; - s32 inst_num = 0; - enum bfa_ioc_type_e ioc_type; - - bfa_log(logmod, BFA_LOG_CREATE_ID(BFA_AEN_CAT_IOC, event), inst_num); - - memset(&aen_data.ioc.pwwn, 0, sizeof(aen_data.ioc.pwwn)); - memset(&aen_data.ioc.mac, 0, sizeof(aen_data.ioc.mac)); - ioc_type = bfa_ioc_get_type(ioc); - switch (ioc_type) { - case BFA_IOC_TYPE_FC: - aen_data.ioc.pwwn = bfa_ioc_get_pwwn(ioc); - break; - case BFA_IOC_TYPE_FCoE: - aen_data.ioc.pwwn = bfa_ioc_get_pwwn(ioc); - aen_data.ioc.mac = bfa_ioc_get_mac(ioc); - break; - case BFA_IOC_TYPE_LL: - aen_data.ioc.mac = bfa_ioc_get_mac(ioc); - break; - default: - bfa_assert(ioc_type == BFA_IOC_TYPE_FC); - break; - } - aen_data.ioc.ioc_type = ioc_type; -} - -/** * Retrieve saved firmware trace from a prior IOC failure. */ bfa_status_t bfa_ioc_debug_fwsave(struct bfa_ioc_s *ioc, void *trcdata, int *trclen) { - int tlen; + int tlen; if (ioc->dbg_fwsave_len == 0) return BFA_STATUS_ENOFSAVE; @@ -1963,57 +2561,145 @@ bfa_ioc_debug_fwsave_clear(struct bfa_ioc_s *ioc) bfa_status_t bfa_ioc_debug_fwtrc(struct bfa_ioc_s *ioc, void *trcdata, int *trclen) { - u32 pgnum; - u32 loff = BFA_DBG_FWTRC_OFF(bfa_ioc_portid(ioc)); - int i, tlen; - u32 *tbuf = trcdata, r32; + u32 loff = BFA_DBG_FWTRC_OFF(bfa_ioc_portid(ioc)); + int tlen; + bfa_status_t status; bfa_trc(ioc, *trclen); - pgnum = bfa_ioc_smem_pgnum(ioc, loff); - loff = bfa_ioc_smem_pgoff(ioc, loff); - - /* - * Hold semaphore to serialize pll init and fwtrc. - */ - if (BFA_FALSE == bfa_ioc_sem_get(ioc->ioc_regs.ioc_init_sem_reg)) - return BFA_STATUS_FAILED; - - bfa_reg_write(ioc->ioc_regs.host_page_num_fn, pgnum); - tlen = *trclen; if (tlen > BFA_DBG_FWTRC_LEN) tlen = BFA_DBG_FWTRC_LEN; - tlen /= sizeof(u32); - bfa_trc(ioc, tlen); + status = bfa_ioc_smem_read(ioc, trcdata, loff, tlen); + *trclen = tlen; + return status; +} - for (i = 0; i < tlen; i++) { - r32 = bfa_mem_read(ioc->ioc_regs.smem_page_start, loff); - tbuf[i] = bfa_os_ntohl(r32); - loff += sizeof(u32); +static void +bfa_ioc_send_fwsync(struct bfa_ioc_s *ioc) +{ + struct bfa_mbox_cmd_s cmd; + struct bfi_ioc_ctrl_req_s *req = (struct bfi_ioc_ctrl_req_s *) cmd.msg; - /** - * handle page offset wrap around - */ - loff = PSS_SMEM_PGOFF(loff); - if (loff == 0) { - pgnum++; - bfa_reg_write(ioc->ioc_regs.host_page_num_fn, pgnum); - } + bfi_h2i_set(req->mh, BFI_MC_IOC, BFI_IOC_H2I_DBG_SYNC, + bfa_ioc_portid(ioc)); + req->ioc_class = ioc->ioc_mc; + bfa_ioc_mbox_queue(ioc, &cmd); +} + +static void +bfa_ioc_fwsync(struct bfa_ioc_s *ioc) +{ + u32 fwsync_iter = 1000; + + bfa_ioc_send_fwsync(ioc); + + /** + * After sending a fw sync mbox command wait for it to + * take effect. We will not wait for a response because + * 1. fw_sync mbox cmd doesn't have a response. + * 2. Even if we implement that, interrupts might not + * be enabled when we call this function. + * So, just keep checking if any mbox cmd is pending, and + * after waiting for a reasonable amount of time, go ahead. + * It is possible that fw has crashed and the mbox command + * is never acknowledged. + */ + while (bfa_ioc_mbox_cmd_pending(ioc) && fwsync_iter > 0) + fwsync_iter--; +} + +/** + * Dump firmware smem + */ +bfa_status_t +bfa_ioc_debug_fwcore(struct bfa_ioc_s *ioc, void *buf, + u32 *offset, int *buflen) +{ + u32 loff; + int dlen; + bfa_status_t status; + u32 smem_len = BFA_IOC_FW_SMEM_SIZE(ioc); + + if (*offset >= smem_len) { + *offset = *buflen = 0; + return BFA_STATUS_EINVAL; } - bfa_reg_write(ioc->ioc_regs.host_page_num_fn, - bfa_ioc_smem_pgnum(ioc, 0)); - /* - * release semaphore. + loff = *offset; + dlen = *buflen; + + /** + * First smem read, sync smem before proceeding + * No need to sync before reading every chunk. */ - bfa_ioc_sem_release(ioc->ioc_regs.ioc_init_sem_reg); + if (loff == 0) + bfa_ioc_fwsync(ioc); - bfa_trc(ioc, pgnum); + if ((loff + dlen) >= smem_len) + dlen = smem_len - loff; - *trclen = tlen * sizeof(u32); - return BFA_STATUS_OK; + status = bfa_ioc_smem_read(ioc, buf, loff, dlen); + + if (status != BFA_STATUS_OK) { + *offset = *buflen = 0; + return status; + } + + *offset += dlen; + + if (*offset >= smem_len) + *offset = 0; + + *buflen = dlen; + + return status; +} + +/** + * Firmware statistics + */ +bfa_status_t +bfa_ioc_fw_stats_get(struct bfa_ioc_s *ioc, void *stats) +{ + u32 loff = BFI_IOC_FWSTATS_OFF + \ + BFI_IOC_FWSTATS_SZ * (bfa_ioc_portid(ioc)); + int tlen; + bfa_status_t status; + + if (ioc->stats_busy) { + bfa_trc(ioc, ioc->stats_busy); + return BFA_STATUS_DEVBUSY; + } + ioc->stats_busy = BFA_TRUE; + + tlen = sizeof(struct bfa_fw_stats_s); + status = bfa_ioc_smem_read(ioc, stats, loff, tlen); + + ioc->stats_busy = BFA_FALSE; + return status; +} + +bfa_status_t +bfa_ioc_fw_stats_clear(struct bfa_ioc_s *ioc) +{ + u32 loff = BFI_IOC_FWSTATS_OFF + \ + BFI_IOC_FWSTATS_SZ * (bfa_ioc_portid(ioc)); + int tlen; + bfa_status_t status; + + if (ioc->stats_busy) { + bfa_trc(ioc, ioc->stats_busy); + return BFA_STATUS_DEVBUSY; + } + ioc->stats_busy = BFA_TRUE; + + tlen = sizeof(struct bfa_fw_stats_s); + status = bfa_ioc_smem_clr(ioc, loff, tlen); + + ioc->stats_busy = BFA_FALSE; + return status; } /** @@ -2022,7 +2708,7 @@ bfa_ioc_debug_fwtrc(struct bfa_ioc_s *ioc, void *trcdata, int *trclen) static void bfa_ioc_debug_save(struct bfa_ioc_s *ioc) { - int tlen; + int tlen; if (ioc->dbg_fwsave_len) { tlen = ioc->dbg_fwsave_len; @@ -2050,11 +2736,135 @@ bfa_ioc_check_attr_wwns(struct bfa_ioc_s *ioc) { if (bfa_ioc_get_type(ioc) == BFA_IOC_TYPE_LL) return; +} + +/** + * hal_iocpf_pvt BFA IOC PF private functions + */ - 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); +static void +bfa_iocpf_enable(struct bfa_ioc_s *ioc) +{ + bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_ENABLE); } -#endif +static void +bfa_iocpf_disable(struct bfa_ioc_s *ioc) +{ + bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_DISABLE); +} + +static void +bfa_iocpf_fail(struct bfa_ioc_s *ioc) +{ + bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_FAIL); +} + +static void +bfa_iocpf_initfail(struct bfa_ioc_s *ioc) +{ + bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_INITFAIL); +} + +static void +bfa_iocpf_getattrfail(struct bfa_ioc_s *ioc) +{ + bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_GETATTRFAIL); +} + +static void +bfa_iocpf_stop(struct bfa_ioc_s *ioc) +{ + bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_STOP); +} + +static void +bfa_iocpf_timeout(void *ioc_arg) +{ + struct bfa_ioc_s *ioc = (struct bfa_ioc_s *) ioc_arg; + + bfa_trc(ioc, 0); + bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_TIMEOUT); +} + +static void +bfa_iocpf_sem_timeout(void *ioc_arg) +{ + struct bfa_ioc_s *ioc = (struct bfa_ioc_s *) ioc_arg; + + bfa_ioc_hw_sem_get(ioc); +} + +/** + * bfa timer function + */ +void +bfa_timer_init(struct bfa_timer_mod_s *mod) +{ + INIT_LIST_HEAD(&mod->timer_q); +} + +void +bfa_timer_beat(struct bfa_timer_mod_s *mod) +{ + struct list_head *qh = &mod->timer_q; + struct list_head *qe, *qe_next; + struct bfa_timer_s *elem; + struct list_head timedout_q; + + INIT_LIST_HEAD(&timedout_q); + + qe = bfa_q_next(qh); + + while (qe != qh) { + qe_next = bfa_q_next(qe); + + elem = (struct bfa_timer_s *) qe; + if (elem->timeout <= BFA_TIMER_FREQ) { + elem->timeout = 0; + list_del(&elem->qe); + list_add_tail(&elem->qe, &timedout_q); + } else { + elem->timeout -= BFA_TIMER_FREQ; + } + + qe = qe_next; /* go to next elem */ + } + + /* + * Pop all the timeout entries + */ + while (!list_empty(&timedout_q)) { + bfa_q_deq(&timedout_q, &elem); + elem->timercb(elem->arg); + } +} + +/** + * Should be called with lock protection + */ +void +bfa_timer_begin(struct bfa_timer_mod_s *mod, struct bfa_timer_s *timer, + void (*timercb) (void *), void *arg, unsigned int timeout) +{ + + bfa_assert(timercb != NULL); + bfa_assert(!bfa_q_is_on_q(&mod->timer_q, timer)); + + timer->timeout = timeout; + timer->timercb = timercb; + timer->arg = arg; + + list_add_tail(&timer->qe, &mod->timer_q); +} + +/** + * Should be called with lock protection + */ +void +bfa_timer_stop(struct bfa_timer_s *timer) +{ + bfa_assert(!list_empty(&timer->qe)); + + list_del(&timer->qe); +} diff --git a/drivers/scsi/bfa/bfa_ioc.h b/drivers/scsi/bfa/bfa_ioc.h index cae05b251c99..288c5801aace 100644 --- a/drivers/scsi/bfa/bfa_ioc.h +++ b/drivers/scsi/bfa/bfa_ioc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. * All rights reserved * www.brocade.com * @@ -18,18 +18,74 @@ #ifndef __BFA_IOC_H__ #define __BFA_IOC_H__ -#include <cs/bfa_sm.h> -#include <bfi/bfi.h> -#include <bfi/bfi_ioc.h> -#include <bfi/bfi_boot.h> -#include <bfa_timer.h> +#include "bfa_os_inc.h" +#include "bfa_cs.h" +#include "bfi.h" + +/** + * BFA timer declarations + */ +typedef void (*bfa_timer_cbfn_t)(void *); + +/** + * BFA timer data structure + */ +struct bfa_timer_s { + struct list_head qe; + bfa_timer_cbfn_t timercb; + void *arg; + int timeout; /**< in millisecs. */ +}; + +/** + * Timer module structure + */ +struct bfa_timer_mod_s { + struct list_head timer_q; +}; + +#define BFA_TIMER_FREQ 200 /**< specified in millisecs */ + +void bfa_timer_beat(struct bfa_timer_mod_s *mod); +void bfa_timer_init(struct bfa_timer_mod_s *mod); +void bfa_timer_begin(struct bfa_timer_mod_s *mod, struct bfa_timer_s *timer, + bfa_timer_cbfn_t timercb, void *arg, + unsigned int timeout); +void bfa_timer_stop(struct bfa_timer_s *timer); + +/** + * Generic Scatter Gather Element used by driver + */ +struct bfa_sge_s { + u32 sg_len; + void *sg_addr; +}; + +#define bfa_sge_word_swap(__sge) do { \ + ((u32 *)(__sge))[0] = bfa_os_swap32(((u32 *)(__sge))[0]); \ + ((u32 *)(__sge))[1] = bfa_os_swap32(((u32 *)(__sge))[1]); \ + ((u32 *)(__sge))[2] = bfa_os_swap32(((u32 *)(__sge))[2]); \ +} while (0) + +#define bfa_swap_words(_x) ( \ + ((_x) << 32) | ((_x) >> 32)) + +#ifdef __BIGENDIAN +#define bfa_sge_to_be(_x) +#define bfa_sge_to_le(_x) bfa_sge_word_swap(_x) +#define bfa_sgaddr_le(_x) bfa_swap_words(_x) +#else +#define bfa_sge_to_be(_x) bfa_sge_word_swap(_x) +#define bfa_sge_to_le(_x) +#define bfa_sgaddr_le(_x) (_x) +#endif /** * PCI device information required by IOC */ struct bfa_pcidev_s { - int pci_slot; - u8 pci_func; + int pci_slot; + u8 pci_func; u16 device_id; bfa_os_addr_t pci_bar_kva; }; @@ -39,13 +95,18 @@ struct bfa_pcidev_s { * Address */ struct bfa_dma_s { - void *kva; /*! Kernel virtual address */ - u64 pa; /*! Physical address */ + void *kva; /* ! Kernel virtual address */ + u64 pa; /* ! Physical address */ }; #define BFA_DMA_ALIGN_SZ 256 #define BFA_ROUNDUP(_l, _s) (((_l) + ((_s) - 1)) & ~((_s) - 1)) +/** + * smem size for Crossbow and Catapult + */ +#define BFI_SMEM_CB_SIZE 0x200000U /* ! 2MB for crossbow */ +#define BFI_SMEM_CT_SIZE 0x280000U /* ! 2.5MB for catapult */ #define bfa_dma_addr_set(dma_addr, pa) \ @@ -101,7 +162,7 @@ struct bfa_ioc_regs_s { * IOC Mailbox structures */ struct bfa_mbox_cmd_s { - struct list_head qe; + struct list_head qe; u32 msg[BFI_IOC_MSGSZ]; }; @@ -110,8 +171,8 @@ struct bfa_mbox_cmd_s { */ typedef void (*bfa_ioc_mbox_mcfunc_t)(void *cbarg, struct bfi_mbmsg_s *m); struct bfa_ioc_mbox_mod_s { - struct list_head cmd_q; /* pending mbox queue */ - int nmclass; /* number of handlers */ + struct list_head cmd_q; /* pending mbox queue */ + int nmclass; /* number of handlers */ struct { bfa_ioc_mbox_mcfunc_t cbfn; /* message handlers */ void *cbarg; @@ -149,49 +210,54 @@ struct bfa_ioc_hbfail_notify_s { (__notify)->cbarg = (__cbarg); \ } while (0) +struct bfa_iocpf_s { + bfa_fsm_t fsm; + struct bfa_ioc_s *ioc; + u32 retry_count; + bfa_boolean_t auto_recover; +}; + struct bfa_ioc_s { bfa_fsm_t fsm; struct bfa_s *bfa; struct bfa_pcidev_s pcidev; - struct bfa_timer_mod_s *timer_mod; - struct bfa_timer_s ioc_timer; - struct bfa_timer_s sem_timer; + struct bfa_timer_mod_s *timer_mod; + struct bfa_timer_s ioc_timer; + struct bfa_timer_s sem_timer; + struct bfa_timer_s hb_timer; u32 hb_count; - u32 retry_count; struct list_head hb_notify_q; void *dbg_fwsave; int dbg_fwsave_len; bfa_boolean_t dbg_fwsave_once; enum bfi_mclass ioc_mc; - struct bfa_ioc_regs_s ioc_regs; + struct bfa_ioc_regs_s ioc_regs; struct bfa_trc_mod_s *trcmod; - struct bfa_aen_s *aen; - struct bfa_log_mod_s *logm; struct bfa_ioc_drv_stats_s stats; - bfa_boolean_t auto_recover; bfa_boolean_t fcmode; bfa_boolean_t ctdev; bfa_boolean_t cna; bfa_boolean_t pllinit; + bfa_boolean_t stats_busy; /* outstanding stats */ u8 port_id; - struct bfa_dma_s attr_dma; struct bfi_ioc_attr_s *attr; struct bfa_ioc_cbfn_s *cbfn; struct bfa_ioc_mbox_mod_s mbox_mod; - struct bfa_ioc_hwif_s *ioc_hwif; + struct bfa_ioc_hwif_s *ioc_hwif; + struct bfa_iocpf_s iocpf; }; 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); - 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, - bfa_boolean_t msix); - void (*ioc_notify_hbfail) (struct bfa_ioc_s *ioc); - void (*ioc_ownership_reset) (struct bfa_ioc_s *ioc); + bfa_status_t (*ioc_pll_init) (bfa_os_addr_t rb, bfa_boolean_t fcmode); + bfa_boolean_t (*ioc_firmware_lock) (struct bfa_ioc_s *ioc); + void (*ioc_firmware_unlock) (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, + bfa_boolean_t msix); + void (*ioc_notify_hbfail) (struct bfa_ioc_s *ioc); + void (*ioc_ownership_reset) (struct bfa_ioc_s *ioc); }; #define bfa_ioc_pcifn(__ioc) ((__ioc)->pcidev.pci_func) @@ -206,18 +272,19 @@ struct bfa_ioc_hwif_s { #define bfa_ioc_rx_bbcredit(__ioc) ((__ioc)->attr->rx_bbcredit) #define bfa_ioc_speed_sup(__ioc) \ BFI_ADAPTER_GETP(SPEED, (__ioc)->attr->adapter_prop) -#define bfa_ioc_get_nports(__ioc) \ +#define bfa_ioc_get_nports(__ioc) \ BFI_ADAPTER_GETP(NPORTS, (__ioc)->attr->adapter_prop) -#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) : \ +#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) +#define BFA_IOC_FW_SMEM_SIZE(__ioc) \ + (((__ioc)->ctdev) ? BFI_SMEM_CT_SIZE : BFI_SMEM_CB_SIZE) +#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) #define BFA_IOC_FLASH_CHUNK_ADDR(chunkno) (chunkno * BFI_FLASH_CHUNK_SZ_WORDS) /** @@ -235,18 +302,28 @@ void bfa_ioc_mbox_regisr(struct bfa_ioc_s *ioc, enum bfi_mclass mc, /** * IOC interfaces */ -#define bfa_ioc_pll_init(__ioc) ((__ioc)->ioc_hwif->ioc_pll_init(__ioc)) -#define bfa_ioc_isr_mode_set(__ioc, __msix) \ + +#define bfa_ioc_pll_init_asic(__ioc) \ + ((__ioc)->ioc_hwif->ioc_pll_init((__ioc)->pcidev.pci_bar_kva, \ + (__ioc)->fcmode)) + +bfa_status_t bfa_ioc_pll_init(struct bfa_ioc_s *ioc); +bfa_status_t bfa_ioc_cb_pll_init(bfa_os_addr_t rb, bfa_boolean_t fcmode); +bfa_boolean_t bfa_ioc_ct_pll_init_complete(bfa_os_addr_t rb); +bfa_status_t bfa_ioc_ct_pll_init(bfa_os_addr_t rb, bfa_boolean_t fcmode); + +#define bfa_ioc_isr_mode_set(__ioc, __msix) \ ((__ioc)->ioc_hwif->ioc_isr_mode_set(__ioc, __msix)) -#define bfa_ioc_ownership_reset(__ioc) \ +#define bfa_ioc_ownership_reset(__ioc) \ ((__ioc)->ioc_hwif->ioc_ownership_reset(__ioc)) + void bfa_ioc_set_ct_hwif(struct bfa_ioc_s *ioc); void bfa_ioc_set_cb_hwif(struct bfa_ioc_s *ioc); + void bfa_ioc_attach(struct bfa_ioc_s *ioc, void *bfa, - struct bfa_ioc_cbfn_s *cbfn, struct bfa_timer_mod_s *timer_mod, - struct bfa_trc_mod_s *trcmod, - struct bfa_aen_s *aen, struct bfa_log_mod_s *logm); + struct bfa_ioc_cbfn_s *cbfn, struct bfa_timer_mod_s *timer_mod); +void bfa_ioc_auto_recover(bfa_boolean_t auto_recover); void bfa_ioc_detach(struct bfa_ioc_s *ioc); void bfa_ioc_pci_init(struct bfa_ioc_s *ioc, struct bfa_pcidev_s *pcidev, enum bfi_mclass mc); @@ -256,21 +333,22 @@ void bfa_ioc_enable(struct bfa_ioc_s *ioc); void bfa_ioc_disable(struct bfa_ioc_s *ioc); bfa_boolean_t bfa_ioc_intx_claim(struct bfa_ioc_s *ioc); -void bfa_ioc_boot(struct bfa_ioc_s *ioc, u32 boot_type, u32 boot_param); +void bfa_ioc_boot(struct bfa_ioc_s *ioc, u32 boot_type, + u32 boot_param); void bfa_ioc_isr(struct bfa_ioc_s *ioc, struct bfi_mbmsg_s *msg); void bfa_ioc_error_isr(struct bfa_ioc_s *ioc); bfa_boolean_t bfa_ioc_is_operational(struct bfa_ioc_s *ioc); +bfa_boolean_t bfa_ioc_is_initialized(struct bfa_ioc_s *ioc); bfa_boolean_t bfa_ioc_is_disabled(struct bfa_ioc_s *ioc); bfa_boolean_t bfa_ioc_fw_mismatch(struct bfa_ioc_s *ioc); bfa_boolean_t bfa_ioc_adapter_is_disabled(struct bfa_ioc_s *ioc); -void bfa_ioc_cfg_complete(struct bfa_ioc_s *ioc); enum bfa_ioc_type_e bfa_ioc_get_type(struct bfa_ioc_s *ioc); void bfa_ioc_get_adapter_serial_num(struct bfa_ioc_s *ioc, char *serial_num); void bfa_ioc_get_adapter_fw_ver(struct bfa_ioc_s *ioc, char *fw_ver); void bfa_ioc_get_adapter_optrom_ver(struct bfa_ioc_s *ioc, char *optrom_ver); void bfa_ioc_get_adapter_model(struct bfa_ioc_s *ioc, char *model); void bfa_ioc_get_adapter_manufacturer(struct bfa_ioc_s *ioc, - char *manufacturer); + char *manufacturer); void bfa_ioc_get_pci_chip_rev(struct bfa_ioc_s *ioc, char *chip_rev); enum bfa_ioc_state bfa_ioc_get_state(struct bfa_ioc_s *ioc); @@ -284,6 +362,8 @@ bfa_status_t bfa_ioc_debug_fwsave(struct bfa_ioc_s *ioc, void *trcdata, void bfa_ioc_debug_fwsave_clear(struct bfa_ioc_s *ioc); bfa_status_t bfa_ioc_debug_fwtrc(struct bfa_ioc_s *ioc, void *trcdata, int *trclen); +bfa_status_t bfa_ioc_debug_fwcore(struct bfa_ioc_s *ioc, void *buf, + u32 *offset, int *buflen); u32 bfa_ioc_smem_pgnum(struct bfa_ioc_s *ioc, u32 fmaddr); u32 bfa_ioc_smem_pgoff(struct bfa_ioc_s *ioc, u32 fmaddr); void bfa_ioc_set_fcmode(struct bfa_ioc_s *ioc); @@ -297,7 +377,8 @@ 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_status_t bfa_ioc_fw_stats_get(struct bfa_ioc_s *ioc, void *stats); +bfa_status_t bfa_ioc_fw_stats_clear(struct bfa_ioc_s *ioc); /* * bfa mfg wwn API functions @@ -310,5 +391,68 @@ 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__ */ +/* + * F/W Image Size & Chunk + */ +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; + +static inline u32 * +bfi_image_ct_fc_get_chunk(u32 off) +{ return (u32 *)(bfi_image_ct_fc + off); } + +static inline u32 * +bfi_image_ct_cna_get_chunk(u32 off) +{ return (u32 *)(bfi_image_ct_cna + off); } +static inline u32 * +bfi_image_cb_fc_get_chunk(u32 off) +{ return (u32 *)(bfi_image_cb_fc + off); } + +static inline u32* +bfa_cb_image_get_chunk(int type, u32 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; + } +} + +static inline u32 +bfa_cb_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; + } +} + +/** + * CNA TRCMOD declaration + */ +/* + * !!! Only append to the enums defined here to avoid any versioning + * !!! needed between trace utility and driver version + */ +enum { + BFA_TRC_CNA_PORT = 1, + BFA_TRC_CNA_IOC = 2, + BFA_TRC_CNA_IOC_CB = 3, + BFA_TRC_CNA_IOC_CT = 4, +}; + +#endif /* __BFA_IOC_H__ */ diff --git a/drivers/scsi/bfa/bfa_ioc_cb.c b/drivers/scsi/bfa/bfa_ioc_cb.c index 324bdde7ea2e..d7ac864d8539 100644 --- a/drivers/scsi/bfa/bfa_ioc_cb.c +++ b/drivers/scsi/bfa/bfa_ioc_cb.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. * All rights reserved * www.brocade.com * @@ -15,22 +15,15 @@ * General Public License for more details. */ -#include <bfa.h> -#include <bfa_ioc.h> -#include <bfa_fwimg_priv.h> -#include <cna/bfa_cna_trcmod.h> -#include <cs/bfa_debug.h> -#include <bfi/bfi_ioc.h> -#include <bfi/bfi_cbreg.h> -#include <log/bfa_log_hal.h> -#include <defs/bfa_defs_pci.h> +#include "bfa_ioc.h" +#include "bfi_cbreg.h" +#include "bfa_defs.h" BFA_TRC_FILE(CNA, IOC_CB); /* * forward declarations */ -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 void bfa_ioc_cb_reg_init(struct bfa_ioc_s *ioc); @@ -95,6 +88,7 @@ static struct { u32 hfn_mbox, lpu_mbox, hfn_pgn; } iocreg_fnreg[] = { * Host <-> LPU mailbox command/status registers */ static struct { u32 hfn, lpu; } iocreg_mbcmd[] = { + { HOSTFN0_LPU0_CMD_STAT, LPU0_HOSTFN0_CMD_STAT }, { HOSTFN1_LPU1_CMD_STAT, LPU1_HOSTFN1_CMD_STAT } }; @@ -154,6 +148,7 @@ bfa_ioc_cb_reg_init(struct bfa_ioc_s *ioc) /** * Initialize IOC to port mapping. */ + static void bfa_ioc_cb_map_port(struct bfa_ioc_s *ioc) { @@ -161,6 +156,7 @@ bfa_ioc_cb_map_port(struct bfa_ioc_s *ioc) * For crossbow, port id is same as pci function. */ ioc->port_id = bfa_ioc_pcifn(ioc); + bfa_trc(ioc, ioc->port_id); } @@ -172,87 +168,69 @@ bfa_ioc_cb_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix) { } -static bfa_status_t -bfa_ioc_cb_pll_init(struct bfa_ioc_s *ioc) +/** + * Cleanup hw semaphore and usecnt registers + */ +static void +bfa_ioc_cb_ownership_reset(struct bfa_ioc_s *ioc) { - bfa_os_addr_t rb = ioc->pcidev.pci_bar_kva; - u32 pll_sclk, pll_fclk; /* - * Hold semaphore so that nobody can access the chip during init. + * Read the hw sem reg to make sure that it is locked + * before we clear it. If it is not locked, writing 1 + * will lock it instead of clearing it. */ - bfa_ioc_sem_get(ioc->ioc_regs.ioc_init_sem_reg); + bfa_reg_read(ioc->ioc_regs.ioc_sem_reg); + bfa_ioc_hw_sem_release(ioc); +} + + + +bfa_status_t +bfa_ioc_cb_pll_init(bfa_os_addr_t rb, bfa_boolean_t fcmode) +{ + u32 pll_sclk, pll_fclk; pll_sclk = __APP_PLL_212_ENABLE | __APP_PLL_212_LRESETN | - __APP_PLL_212_P0_1(3U) | - __APP_PLL_212_JITLMT0_1(3U) | - __APP_PLL_212_CNTLMT0_1(3U); + __APP_PLL_212_P0_1(3U) | + __APP_PLL_212_JITLMT0_1(3U) | + __APP_PLL_212_CNTLMT0_1(3U); pll_fclk = __APP_PLL_400_ENABLE | __APP_PLL_400_LRESETN | - __APP_PLL_400_RSEL200500 | __APP_PLL_400_P0_1(3U) | - __APP_PLL_400_JITLMT0_1(3U) | - __APP_PLL_400_CNTLMT0_1(3U); - + __APP_PLL_400_RSEL200500 | __APP_PLL_400_P0_1(3U) | + __APP_PLL_400_JITLMT0_1(3U) | + __APP_PLL_400_CNTLMT0_1(3U); bfa_reg_write((rb + BFA_IOC0_STATE_REG), BFI_IOC_UNINIT); bfa_reg_write((rb + BFA_IOC1_STATE_REG), BFI_IOC_UNINIT); - bfa_reg_write((rb + HOSTFN0_INT_MSK), 0xffffffffU); bfa_reg_write((rb + HOSTFN1_INT_MSK), 0xffffffffU); bfa_reg_write((rb + HOSTFN0_INT_STATUS), 0xffffffffU); bfa_reg_write((rb + HOSTFN1_INT_STATUS), 0xffffffffU); bfa_reg_write((rb + HOSTFN0_INT_MSK), 0xffffffffU); bfa_reg_write((rb + HOSTFN1_INT_MSK), 0xffffffffU); - - bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg, - __APP_PLL_212_LOGIC_SOFT_RESET); - bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg, - __APP_PLL_212_BYPASS | - __APP_PLL_212_LOGIC_SOFT_RESET); - bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg, - __APP_PLL_400_LOGIC_SOFT_RESET); - bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg, - __APP_PLL_400_BYPASS | - __APP_PLL_400_LOGIC_SOFT_RESET); + bfa_reg_write(rb + APP_PLL_212_CTL_REG, + __APP_PLL_212_LOGIC_SOFT_RESET); + bfa_reg_write(rb + APP_PLL_212_CTL_REG, + __APP_PLL_212_BYPASS | + __APP_PLL_212_LOGIC_SOFT_RESET); + bfa_reg_write(rb + APP_PLL_400_CTL_REG, + __APP_PLL_400_LOGIC_SOFT_RESET); + bfa_reg_write(rb + APP_PLL_400_CTL_REG, + __APP_PLL_400_BYPASS | + __APP_PLL_400_LOGIC_SOFT_RESET); bfa_os_udelay(2); - bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg, - __APP_PLL_212_LOGIC_SOFT_RESET); - bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg, - __APP_PLL_400_LOGIC_SOFT_RESET); - - bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg, - pll_sclk | __APP_PLL_212_LOGIC_SOFT_RESET); - bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg, - pll_fclk | __APP_PLL_400_LOGIC_SOFT_RESET); - - /** - * Wait for PLLs to lock. - */ + bfa_reg_write(rb + APP_PLL_212_CTL_REG, + __APP_PLL_212_LOGIC_SOFT_RESET); + bfa_reg_write(rb + APP_PLL_400_CTL_REG, + __APP_PLL_400_LOGIC_SOFT_RESET); + bfa_reg_write(rb + APP_PLL_212_CTL_REG, + pll_sclk | __APP_PLL_212_LOGIC_SOFT_RESET); + bfa_reg_write(rb + APP_PLL_400_CTL_REG, + pll_fclk | __APP_PLL_400_LOGIC_SOFT_RESET); bfa_os_udelay(2000); bfa_reg_write((rb + HOSTFN0_INT_STATUS), 0xffffffffU); bfa_reg_write((rb + HOSTFN1_INT_STATUS), 0xffffffffU); - - bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg, pll_sclk); - bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg, pll_fclk); - - /* - * release semaphore. - */ - bfa_ioc_sem_release(ioc->ioc_regs.ioc_init_sem_reg); + bfa_reg_write((rb + APP_PLL_212_CTL_REG), pll_sclk); + bfa_reg_write((rb + APP_PLL_400_CTL_REG), pll_fclk); return BFA_STATUS_OK; } - -/** - * Cleanup hw semaphore and usecnt registers - */ -static void -bfa_ioc_cb_ownership_reset(struct bfa_ioc_s *ioc) -{ - - /* - * Read the hw sem reg to make sure that it is locked - * before we clear it. If it is not locked, writing 1 - * will lock it instead of clearing it. - */ - bfa_reg_read(ioc->ioc_regs.ioc_sem_reg); - bfa_ioc_hw_sem_release(ioc); -} diff --git a/drivers/scsi/bfa/bfa_ioc_ct.c b/drivers/scsi/bfa/bfa_ioc_ct.c index 68f027da001e..f21b82c5f64c 100644 --- a/drivers/scsi/bfa/bfa_ioc_ct.c +++ b/drivers/scsi/bfa/bfa_ioc_ct.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. * All rights reserved * www.brocade.com * @@ -15,22 +15,15 @@ * General Public License for more details. */ -#include <bfa.h> -#include <bfa_ioc.h> -#include <bfa_fwimg_priv.h> -#include <cna/bfa_cna_trcmod.h> -#include <cs/bfa_debug.h> -#include <bfi/bfi_ioc.h> -#include <bfi/bfi_ctreg.h> -#include <log/bfa_log_hal.h> -#include <defs/bfa_defs_pci.h> +#include "bfa_ioc.h" +#include "bfi_ctreg.h" +#include "bfa_defs.h" BFA_TRC_FILE(CNA, IOC_CT); /* * forward declarations */ -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 void bfa_ioc_ct_reg_init(struct bfa_ioc_s *ioc); @@ -78,7 +71,8 @@ bfa_ioc_ct_firmware_lock(struct bfa_ioc_s *ioc) /** * If bios boot (flash based) -- do not increment usage count */ - if (bfi_image_get_size(BFA_IOC_FWIMG_TYPE(ioc)) < BFA_IOC_FWIMG_MINSZ) + if (bfa_cb_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); @@ -136,7 +130,8 @@ bfa_ioc_ct_firmware_unlock(struct bfa_ioc_s *ioc) /** * If bios boot (flash based) -- do not decrement usage count */ - if (bfi_image_get_size(BFA_IOC_FWIMG_TYPE(ioc)) < BFA_IOC_FWIMG_MINSZ) + if (bfa_cb_image_get_size(BFA_IOC_FWIMG_TYPE(ioc)) < + BFA_IOC_FWIMG_MINSZ) return; /** @@ -308,16 +303,47 @@ bfa_ioc_ct_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix) bfa_reg_write(rb + FNC_PERS_REG, r32); } -static bfa_status_t -bfa_ioc_ct_pll_init(struct bfa_ioc_s *ioc) +/** + * Cleanup hw semaphore and usecnt registers + */ +static void +bfa_ioc_ct_ownership_reset(struct bfa_ioc_s *ioc) { - bfa_os_addr_t rb = ioc->pcidev.pci_bar_kva; - u32 pll_sclk, pll_fclk, r32; + + if (ioc->cna) { + bfa_ioc_sem_get(ioc->ioc_regs.ioc_usage_sem_reg); + bfa_reg_write(ioc->ioc_regs.ioc_usage_reg, 0); + bfa_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg); + } /* - * Hold semaphore so that nobody can access the chip during init. + * Read the hw sem reg to make sure that it is locked + * before we clear it. If it is not locked, writing 1 + * will lock it instead of clearing it. */ - bfa_ioc_sem_get(ioc->ioc_regs.ioc_init_sem_reg); + bfa_reg_read(ioc->ioc_regs.ioc_sem_reg); + bfa_ioc_hw_sem_release(ioc); +} + + + +/* + * Check the firmware state to know if pll_init has been completed already + */ +bfa_boolean_t +bfa_ioc_ct_pll_init_complete(bfa_os_addr_t rb) +{ + if ((bfa_reg_read(rb + BFA_IOC0_STATE_REG) == BFI_IOC_OP) || + (bfa_reg_read(rb + BFA_IOC1_STATE_REG) == BFI_IOC_OP)) + return BFA_TRUE; + + return BFA_FALSE; +} + +bfa_status_t +bfa_ioc_ct_pll_init(bfa_os_addr_t rb, bfa_boolean_t fcmode) +{ + u32 pll_sclk, pll_fclk, r32; pll_sclk = __APP_PLL_312_LRESETN | __APP_PLL_312_ENARST | __APP_PLL_312_RSEL200500 | __APP_PLL_312_P0_1(3U) | @@ -327,70 +353,50 @@ bfa_ioc_ct_pll_init(struct bfa_ioc_s *ioc) __APP_PLL_425_RSEL200500 | __APP_PLL_425_P0_1(3U) | __APP_PLL_425_JITLMT0_1(3U) | __APP_PLL_425_CNTLMT0_1(1U); - - /** - * For catapult, choose operational mode FC/FCoE - */ - if (ioc->fcmode) { + if (fcmode) { bfa_reg_write((rb + OP_MODE), 0); bfa_reg_write((rb + ETH_MAC_SER_REG), __APP_EMS_CMLCKSEL | __APP_EMS_REFCKBUFEN2 | __APP_EMS_CHANNEL_SEL); } else { - ioc->pllinit = BFA_TRUE; bfa_reg_write((rb + OP_MODE), __GLOBAL_FCOE_MODE); bfa_reg_write((rb + ETH_MAC_SER_REG), - __APP_EMS_REFCKBUFEN1); + __APP_EMS_REFCKBUFEN1); } - bfa_reg_write((rb + BFA_IOC0_STATE_REG), BFI_IOC_UNINIT); bfa_reg_write((rb + BFA_IOC1_STATE_REG), BFI_IOC_UNINIT); - bfa_reg_write((rb + HOSTFN0_INT_MSK), 0xffffffffU); bfa_reg_write((rb + HOSTFN1_INT_MSK), 0xffffffffU); bfa_reg_write((rb + HOSTFN0_INT_STATUS), 0xffffffffU); bfa_reg_write((rb + HOSTFN1_INT_STATUS), 0xffffffffU); bfa_reg_write((rb + HOSTFN0_INT_MSK), 0xffffffffU); bfa_reg_write((rb + HOSTFN1_INT_MSK), 0xffffffffU); - - bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg, pll_sclk | + bfa_reg_write(rb + APP_PLL_312_CTL_REG, pll_sclk | __APP_PLL_312_LOGIC_SOFT_RESET); - bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg, pll_fclk | + bfa_reg_write(rb + APP_PLL_425_CTL_REG, pll_fclk | __APP_PLL_425_LOGIC_SOFT_RESET); - bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg, pll_sclk | + bfa_reg_write(rb + APP_PLL_312_CTL_REG, pll_sclk | __APP_PLL_312_LOGIC_SOFT_RESET | __APP_PLL_312_ENABLE); - bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg, pll_fclk | + bfa_reg_write(rb + APP_PLL_425_CTL_REG, pll_fclk | __APP_PLL_425_LOGIC_SOFT_RESET | __APP_PLL_425_ENABLE); - - /** - * Wait for PLLs to lock. - */ bfa_reg_read(rb + HOSTFN0_INT_MSK); bfa_os_udelay(2000); bfa_reg_write((rb + HOSTFN0_INT_STATUS), 0xffffffffU); bfa_reg_write((rb + HOSTFN1_INT_STATUS), 0xffffffffU); - - bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg, pll_sclk | + bfa_reg_write(rb + APP_PLL_312_CTL_REG, pll_sclk | __APP_PLL_312_ENABLE); - bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg, pll_fclk | + bfa_reg_write(rb + APP_PLL_425_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) { + if (!fcmode) { 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) { + if (!fcmode) { bfa_reg_write((rb + PMM_1T_RESET_REG_P0), 0); bfa_reg_write((rb + PMM_1T_RESET_REG_P1), 0); } @@ -398,39 +404,6 @@ bfa_ioc_ct_pll_init(struct bfa_ioc_s *ioc) 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. - */ - bfa_ioc_sem_release(ioc->ioc_regs.ioc_init_sem_reg); - return BFA_STATUS_OK; } - -/** - * Cleanup hw semaphore and usecnt registers - */ -static void -bfa_ioc_ct_ownership_reset(struct bfa_ioc_s *ioc) -{ - - if (ioc->cna) { - bfa_ioc_sem_get(ioc->ioc_regs.ioc_usage_sem_reg); - bfa_reg_write(ioc->ioc_regs.ioc_usage_reg, 0); - bfa_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg); - } - - /* - * Read the hw sem reg to make sure that it is locked - * before we clear it. If it is not locked, writing 1 - * will lock it instead of clearing it. - */ - bfa_reg_read(ioc->ioc_regs.ioc_sem_reg); - bfa_ioc_hw_sem_release(ioc); -} diff --git a/drivers/scsi/bfa/bfa_iocfc.c b/drivers/scsi/bfa/bfa_iocfc.c deleted file mode 100644 index 90820be99864..000000000000 --- a/drivers/scsi/bfa/bfa_iocfc.c +++ /dev/null @@ -1,927 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#include <cs/bfa_debug.h> -#include <bfa_priv.h> -#include <log/bfa_log_hal.h> -#include <bfi/bfi_boot.h> -#include <bfi/bfi_cbreg.h> -#include <aen/bfa_aen_ioc.h> -#include <defs/bfa_defs_iocfc.h> -#include <defs/bfa_defs_pci.h> -#include "bfa_callback_priv.h" -#include "bfad_drv.h" - -BFA_TRC_FILE(HAL, IOCFC); - -/** - * IOC local definitions - */ -#define BFA_IOCFC_TOV 5000 /* msecs */ - -enum { - BFA_IOCFC_ACT_NONE = 0, - BFA_IOCFC_ACT_INIT = 1, - BFA_IOCFC_ACT_STOP = 2, - BFA_IOCFC_ACT_DISABLE = 3, -}; - -/* - * forward declarations - */ -static void bfa_iocfc_enable_cbfn(void *bfa_arg, enum bfa_status status); -static void bfa_iocfc_disable_cbfn(void *bfa_arg); -static void bfa_iocfc_hbfail_cbfn(void *bfa_arg); -static void bfa_iocfc_reset_cbfn(void *bfa_arg); -static void bfa_iocfc_stats_clear(void *bfa_arg); -static void bfa_iocfc_stats_swap(struct bfa_fw_stats_s *d, - struct bfa_fw_stats_s *s); -static void bfa_iocfc_stats_clr_cb(void *bfa_arg, bfa_boolean_t complete); -static void bfa_iocfc_stats_clr_timeout(void *bfa_arg); -static void bfa_iocfc_stats_cb(void *bfa_arg, bfa_boolean_t complete); -static void bfa_iocfc_stats_timeout(void *bfa_arg); - -static struct bfa_ioc_cbfn_s bfa_iocfc_cbfn; - -/** - * bfa_ioc_pvt BFA IOC private functions - */ - -static void -bfa_iocfc_cqs_sz(struct bfa_iocfc_cfg_s *cfg, u32 *dm_len) -{ - int i, per_reqq_sz, per_rspq_sz; - - per_reqq_sz = BFA_ROUNDUP((cfg->drvcfg.num_reqq_elems * BFI_LMSG_SZ), - BFA_DMA_ALIGN_SZ); - per_rspq_sz = BFA_ROUNDUP((cfg->drvcfg.num_rspq_elems * BFI_LMSG_SZ), - BFA_DMA_ALIGN_SZ); - - /* - * Calculate CQ size - */ - for (i = 0; i < cfg->fwcfg.num_cqs; i++) { - *dm_len = *dm_len + per_reqq_sz; - *dm_len = *dm_len + per_rspq_sz; - } - - /* - * Calculate Shadow CI/PI size - */ - for (i = 0; i < cfg->fwcfg.num_cqs; i++) - *dm_len += (2 * BFA_CACHELINE_SZ); -} - -static void -bfa_iocfc_fw_cfg_sz(struct bfa_iocfc_cfg_s *cfg, u32 *dm_len) -{ - *dm_len += - BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfg_s), BFA_CACHELINE_SZ); - *dm_len += - BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfgrsp_s), - BFA_CACHELINE_SZ); - *dm_len += BFA_ROUNDUP(sizeof(struct bfa_fw_stats_s), BFA_CACHELINE_SZ); -} - -/** - * Use the Mailbox interface to send BFI_IOCFC_H2I_CFG_REQ - */ -static void -bfa_iocfc_send_cfg(void *bfa_arg) -{ - struct bfa_s *bfa = bfa_arg; - struct bfa_iocfc_s *iocfc = &bfa->iocfc; - struct bfi_iocfc_cfg_req_s cfg_req; - struct bfi_iocfc_cfg_s *cfg_info = iocfc->cfginfo; - struct bfa_iocfc_cfg_s *cfg = &iocfc->cfg; - int i; - - bfa_assert(cfg->fwcfg.num_cqs <= BFI_IOC_MAX_CQS); - bfa_trc(bfa, cfg->fwcfg.num_cqs); - - bfa_iocfc_reset_queues(bfa); - - /** - * initialize IOC configuration info - */ - cfg_info->endian_sig = BFI_IOC_ENDIAN_SIG; - cfg_info->num_cqs = cfg->fwcfg.num_cqs; - - bfa_dma_be_addr_set(cfg_info->cfgrsp_addr, iocfc->cfgrsp_dma.pa); - bfa_dma_be_addr_set(cfg_info->stats_addr, iocfc->stats_pa); - - /** - * dma map REQ and RSP circular queues and shadow pointers - */ - for (i = 0; i < cfg->fwcfg.num_cqs; i++) { - bfa_dma_be_addr_set(cfg_info->req_cq_ba[i], - iocfc->req_cq_ba[i].pa); - bfa_dma_be_addr_set(cfg_info->req_shadow_ci[i], - iocfc->req_cq_shadow_ci[i].pa); - cfg_info->req_cq_elems[i] = - bfa_os_htons(cfg->drvcfg.num_reqq_elems); - - bfa_dma_be_addr_set(cfg_info->rsp_cq_ba[i], - iocfc->rsp_cq_ba[i].pa); - bfa_dma_be_addr_set(cfg_info->rsp_shadow_pi[i], - iocfc->rsp_cq_shadow_pi[i].pa); - cfg_info->rsp_cq_elems[i] = - bfa_os_htons(cfg->drvcfg.num_rspq_elems); - } - - /** - * 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 - */ - bfi_h2i_set(cfg_req.mh, BFI_MC_IOCFC, BFI_IOCFC_H2I_CFG_REQ, - bfa_lpuid(bfa)); - bfa_dma_be_addr_set(cfg_req.ioc_cfg_dma_addr, iocfc->cfg_info.pa); - - bfa_ioc_mbox_send(&bfa->ioc, &cfg_req, - sizeof(struct bfi_iocfc_cfg_req_s)); -} - -static void -bfa_iocfc_init_mem(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, - struct bfa_pcidev_s *pcidev) -{ - struct bfa_iocfc_s *iocfc = &bfa->iocfc; - - bfa->bfad = bfad; - iocfc->bfa = bfa; - iocfc->action = BFA_IOCFC_ACT_NONE; - - bfa_os_assign(iocfc->cfg, *cfg); - - /** - * Initialize chip specific handlers. - */ - if (bfa_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; - iocfc->hwif.hw_msix_init = bfa_hwct_msix_init; - iocfc->hwif.hw_msix_install = bfa_hwct_msix_install; - iocfc->hwif.hw_msix_uninstall = bfa_hwct_msix_uninstall; - iocfc->hwif.hw_isr_mode_set = bfa_hwct_isr_mode_set; - iocfc->hwif.hw_msix_getvecs = bfa_hwct_msix_getvecs; - 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; - iocfc->hwif.hw_rspq_ack = bfa_hwcb_rspq_ack; - iocfc->hwif.hw_msix_init = bfa_hwcb_msix_init; - iocfc->hwif.hw_msix_install = bfa_hwcb_msix_install; - iocfc->hwif.hw_msix_uninstall = bfa_hwcb_msix_uninstall; - iocfc->hwif.hw_isr_mode_set = bfa_hwcb_isr_mode_set; - iocfc->hwif.hw_msix_getvecs = bfa_hwcb_msix_getvecs; - iocfc->hwif.hw_msix_get_rme_range = bfa_hwcb_msix_get_rme_range; - } - - iocfc->hwif.hw_reginit(bfa); - bfa->msix.nvecs = 0; -} - -static void -bfa_iocfc_mem_claim(struct bfa_s *bfa, struct bfa_iocfc_cfg_s *cfg, - struct bfa_meminfo_s *meminfo) -{ - u8 *dm_kva; - u64 dm_pa; - int i, per_reqq_sz, per_rspq_sz; - struct bfa_iocfc_s *iocfc = &bfa->iocfc; - int dbgsz; - - dm_kva = bfa_meminfo_dma_virt(meminfo); - dm_pa = bfa_meminfo_dma_phys(meminfo); - - /* - * First allocate dma memory for IOC. - */ - bfa_ioc_mem_claim(&bfa->ioc, dm_kva, dm_pa); - dm_kva += bfa_ioc_meminfo(); - dm_pa += bfa_ioc_meminfo(); - - /* - * Claim DMA-able memory for the request/response queues and for shadow - * ci/pi registers - */ - per_reqq_sz = BFA_ROUNDUP((cfg->drvcfg.num_reqq_elems * BFI_LMSG_SZ), - BFA_DMA_ALIGN_SZ); - per_rspq_sz = BFA_ROUNDUP((cfg->drvcfg.num_rspq_elems * BFI_LMSG_SZ), - BFA_DMA_ALIGN_SZ); - - for (i = 0; i < cfg->fwcfg.num_cqs; i++) { - iocfc->req_cq_ba[i].kva = dm_kva; - iocfc->req_cq_ba[i].pa = dm_pa; - bfa_os_memset(dm_kva, 0, per_reqq_sz); - dm_kva += per_reqq_sz; - dm_pa += per_reqq_sz; - - iocfc->rsp_cq_ba[i].kva = dm_kva; - iocfc->rsp_cq_ba[i].pa = dm_pa; - bfa_os_memset(dm_kva, 0, per_rspq_sz); - dm_kva += per_rspq_sz; - dm_pa += per_rspq_sz; - } - - for (i = 0; i < cfg->fwcfg.num_cqs; i++) { - iocfc->req_cq_shadow_ci[i].kva = dm_kva; - iocfc->req_cq_shadow_ci[i].pa = dm_pa; - dm_kva += BFA_CACHELINE_SZ; - dm_pa += BFA_CACHELINE_SZ; - - iocfc->rsp_cq_shadow_pi[i].kva = dm_kva; - iocfc->rsp_cq_shadow_pi[i].pa = dm_pa; - dm_kva += BFA_CACHELINE_SZ; - dm_pa += BFA_CACHELINE_SZ; - } - - /* - * Claim DMA-able memory for the config info page - */ - bfa->iocfc.cfg_info.kva = dm_kva; - bfa->iocfc.cfg_info.pa = dm_pa; - bfa->iocfc.cfginfo = (struct bfi_iocfc_cfg_s *) dm_kva; - dm_kva += BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfg_s), BFA_CACHELINE_SZ); - dm_pa += BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfg_s), BFA_CACHELINE_SZ); - - /* - * Claim DMA-able memory for the config response - */ - bfa->iocfc.cfgrsp_dma.kva = dm_kva; - bfa->iocfc.cfgrsp_dma.pa = dm_pa; - bfa->iocfc.cfgrsp = (struct bfi_iocfc_cfgrsp_s *) dm_kva; - - dm_kva += - BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfgrsp_s), - BFA_CACHELINE_SZ); - dm_pa += BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfgrsp_s), - BFA_CACHELINE_SZ); - - /* - * Claim DMA-able memory for iocfc stats - */ - bfa->iocfc.stats_kva = dm_kva; - bfa->iocfc.stats_pa = dm_pa; - bfa->iocfc.fw_stats = (struct bfa_fw_stats_s *) dm_kva; - dm_kva += BFA_ROUNDUP(sizeof(struct bfa_fw_stats_s), BFA_CACHELINE_SZ); - dm_pa += BFA_ROUNDUP(sizeof(struct bfa_fw_stats_s), BFA_CACHELINE_SZ); - - bfa_meminfo_dma_virt(meminfo) = dm_kva; - bfa_meminfo_dma_phys(meminfo) = dm_pa; - - dbgsz = bfa_ioc_debug_trcsz(bfa_auto_recover); - if (dbgsz > 0) { - bfa_ioc_debug_memclaim(&bfa->ioc, bfa_meminfo_kva(meminfo)); - bfa_meminfo_kva(meminfo) += dbgsz; - } -} - -/** - * Start BFA submodules. - */ -static void -bfa_iocfc_start_submod(struct bfa_s *bfa) -{ - int i; - - bfa->rme_process = BFA_TRUE; - - for (i = 0; hal_mods[i]; i++) - hal_mods[i]->start(bfa); -} - -/** - * Disable BFA submodules. - */ -static void -bfa_iocfc_disable_submod(struct bfa_s *bfa) -{ - int i; - - for (i = 0; hal_mods[i]; i++) - hal_mods[i]->iocdisable(bfa); -} - -static void -bfa_iocfc_init_cb(void *bfa_arg, bfa_boolean_t complete) -{ - struct bfa_s *bfa = bfa_arg; - - if (complete) { - if (bfa->iocfc.cfgdone) - bfa_cb_init(bfa->bfad, BFA_STATUS_OK); - else - bfa_cb_init(bfa->bfad, BFA_STATUS_FAILED); - } else { - if (bfa->iocfc.cfgdone) - bfa->iocfc.action = BFA_IOCFC_ACT_NONE; - } -} - -static void -bfa_iocfc_stop_cb(void *bfa_arg, bfa_boolean_t compl) -{ - struct bfa_s *bfa = bfa_arg; - struct bfad_s *bfad = bfa->bfad; - - if (compl) - complete(&bfad->comp); - - else - bfa->iocfc.action = BFA_IOCFC_ACT_NONE; -} - -static void -bfa_iocfc_disable_cb(void *bfa_arg, bfa_boolean_t compl) -{ - struct bfa_s *bfa = bfa_arg; - struct bfad_s *bfad = bfa->bfad; - - if (compl) - complete(&bfad->disable_comp); -} - -/** - * Update BFA configuration from firmware configuration. - */ -static void -bfa_iocfc_cfgrsp(struct bfa_s *bfa) -{ - struct bfa_iocfc_s *iocfc = &bfa->iocfc; - struct bfi_iocfc_cfgrsp_s *cfgrsp = iocfc->cfgrsp; - struct bfa_iocfc_fwcfg_s *fwcfg = &cfgrsp->fwcfg; - - fwcfg->num_cqs = fwcfg->num_cqs; - fwcfg->num_ioim_reqs = bfa_os_ntohs(fwcfg->num_ioim_reqs); - fwcfg->num_tskim_reqs = bfa_os_ntohs(fwcfg->num_tskim_reqs); - fwcfg->num_fcxp_reqs = bfa_os_ntohs(fwcfg->num_fcxp_reqs); - fwcfg->num_uf_bufs = bfa_os_ntohs(fwcfg->num_uf_bufs); - fwcfg->num_rports = bfa_os_ntohs(fwcfg->num_rports); - - iocfc->cfgdone = BFA_TRUE; - - /** - * 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 - bfa_iocfc_start_submod(bfa); -} - -static void -bfa_iocfc_stats_clear(void *bfa_arg) -{ - struct bfa_s *bfa = bfa_arg; - struct bfa_iocfc_s *iocfc = &bfa->iocfc; - struct bfi_iocfc_stats_req_s stats_req; - - bfa_timer_start(bfa, &iocfc->stats_timer, - bfa_iocfc_stats_clr_timeout, bfa, - BFA_IOCFC_TOV); - - bfi_h2i_set(stats_req.mh, BFI_MC_IOCFC, BFI_IOCFC_H2I_CLEAR_STATS_REQ, - bfa_lpuid(bfa)); - bfa_ioc_mbox_send(&bfa->ioc, &stats_req, - sizeof(struct bfi_iocfc_stats_req_s)); -} - -static void -bfa_iocfc_stats_swap(struct bfa_fw_stats_s *d, struct bfa_fw_stats_s *s) -{ - u32 *dip = (u32 *) d; - u32 *sip = (u32 *) s; - int i; - - for (i = 0; i < (sizeof(struct bfa_fw_stats_s) / sizeof(u32)); i++) - dip[i] = bfa_os_ntohl(sip[i]); -} - -static void -bfa_iocfc_stats_clr_cb(void *bfa_arg, bfa_boolean_t complete) -{ - struct bfa_s *bfa = bfa_arg; - struct bfa_iocfc_s *iocfc = &bfa->iocfc; - - if (complete) { - bfa_ioc_clr_stats(&bfa->ioc); - iocfc->stats_cbfn(iocfc->stats_cbarg, iocfc->stats_status); - } else { - iocfc->stats_busy = BFA_FALSE; - iocfc->stats_status = BFA_STATUS_OK; - } -} - -static void -bfa_iocfc_stats_clr_timeout(void *bfa_arg) -{ - struct bfa_s *bfa = bfa_arg; - struct bfa_iocfc_s *iocfc = &bfa->iocfc; - - bfa_trc(bfa, 0); - - iocfc->stats_status = BFA_STATUS_ETIMER; - bfa_cb_queue(bfa, &iocfc->stats_hcb_qe, bfa_iocfc_stats_clr_cb, bfa); -} - -static void -bfa_iocfc_stats_cb(void *bfa_arg, bfa_boolean_t complete) -{ - struct bfa_s *bfa = bfa_arg; - struct bfa_iocfc_s *iocfc = &bfa->iocfc; - - if (complete) { - if (iocfc->stats_status == BFA_STATUS_OK) { - bfa_os_memset(iocfc->stats_ret, 0, - sizeof(*iocfc->stats_ret)); - bfa_iocfc_stats_swap(&iocfc->stats_ret->fw_stats, - iocfc->fw_stats); - } - iocfc->stats_cbfn(iocfc->stats_cbarg, iocfc->stats_status); - } else { - iocfc->stats_busy = BFA_FALSE; - iocfc->stats_status = BFA_STATUS_OK; - } -} - -static void -bfa_iocfc_stats_timeout(void *bfa_arg) -{ - struct bfa_s *bfa = bfa_arg; - struct bfa_iocfc_s *iocfc = &bfa->iocfc; - - bfa_trc(bfa, 0); - - iocfc->stats_status = BFA_STATUS_ETIMER; - bfa_cb_queue(bfa, &iocfc->stats_hcb_qe, bfa_iocfc_stats_cb, bfa); -} - -static void -bfa_iocfc_stats_query(struct bfa_s *bfa) -{ - struct bfa_iocfc_s *iocfc = &bfa->iocfc; - struct bfi_iocfc_stats_req_s stats_req; - - bfa_timer_start(bfa, &iocfc->stats_timer, - bfa_iocfc_stats_timeout, bfa, BFA_IOCFC_TOV); - - bfi_h2i_set(stats_req.mh, BFI_MC_IOCFC, BFI_IOCFC_H2I_GET_STATS_REQ, - bfa_lpuid(bfa)); - bfa_ioc_mbox_send(&bfa->ioc, &stats_req, - sizeof(struct bfi_iocfc_stats_req_s)); -} - -void -bfa_iocfc_reset_queues(struct bfa_s *bfa) -{ - int q; - - for (q = 0; q < BFI_IOC_MAX_CQS; q++) { - bfa_reqq_ci(bfa, q) = 0; - bfa_reqq_pi(bfa, q) = 0; - bfa_rspq_ci(bfa, q) = 0; - bfa_rspq_pi(bfa, q) = 0; - } -} - -/** - * IOC enable request is complete - */ -static void -bfa_iocfc_enable_cbfn(void *bfa_arg, enum bfa_status status) -{ - struct bfa_s *bfa = bfa_arg; - - if (status != BFA_STATUS_OK) { - bfa_isr_disable(bfa); - if (bfa->iocfc.action == BFA_IOCFC_ACT_INIT) - bfa_cb_queue(bfa, &bfa->iocfc.init_hcb_qe, - bfa_iocfc_init_cb, bfa); - return; - } - - bfa_iocfc_send_cfg(bfa); -} - -/** - * IOC disable request is complete - */ -static void -bfa_iocfc_disable_cbfn(void *bfa_arg) -{ - struct bfa_s *bfa = bfa_arg; - - bfa_isr_disable(bfa); - bfa_iocfc_disable_submod(bfa); - - if (bfa->iocfc.action == BFA_IOCFC_ACT_STOP) - bfa_cb_queue(bfa, &bfa->iocfc.stop_hcb_qe, bfa_iocfc_stop_cb, - bfa); - else { - bfa_assert(bfa->iocfc.action == BFA_IOCFC_ACT_DISABLE); - bfa_cb_queue(bfa, &bfa->iocfc.dis_hcb_qe, bfa_iocfc_disable_cb, - bfa); - } -} - -/** - * Notify sub-modules of hardware failure. - */ -static void -bfa_iocfc_hbfail_cbfn(void *bfa_arg) -{ - struct bfa_s *bfa = bfa_arg; - - bfa->rme_process = BFA_FALSE; - - bfa_isr_disable(bfa); - bfa_iocfc_disable_submod(bfa); - - if (bfa->iocfc.action == BFA_IOCFC_ACT_INIT) - bfa_cb_queue(bfa, &bfa->iocfc.init_hcb_qe, bfa_iocfc_init_cb, - bfa); -} - -/** - * Actions on chip-reset completion. - */ -static void -bfa_iocfc_reset_cbfn(void *bfa_arg) -{ - struct bfa_s *bfa = bfa_arg; - - bfa_iocfc_reset_queues(bfa); - bfa_isr_enable(bfa); -} - - - -/** - * bfa_ioc_public - */ - -/** - * Query IOC memory requirement information. - */ -void -bfa_iocfc_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len, - u32 *dm_len) -{ - /* dma memory for IOC */ - *dm_len += bfa_ioc_meminfo(); - - bfa_iocfc_fw_cfg_sz(cfg, dm_len); - bfa_iocfc_cqs_sz(cfg, dm_len); - *km_len += bfa_ioc_debug_trcsz(bfa_auto_recover); -} - -/** - * Query IOC memory requirement information. - */ -void -bfa_iocfc_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, - struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev) -{ - int i; - - bfa_iocfc_cbfn.enable_cbfn = bfa_iocfc_enable_cbfn; - bfa_iocfc_cbfn.disable_cbfn = bfa_iocfc_disable_cbfn; - bfa_iocfc_cbfn.hbfail_cbfn = bfa_iocfc_hbfail_cbfn; - bfa_iocfc_cbfn.reset_cbfn = bfa_iocfc_reset_cbfn; - - bfa_ioc_attach(&bfa->ioc, bfa, &bfa_iocfc_cbfn, &bfa->timer_mod, - bfa->trcmod, bfa->aen, bfa->logm); - - /** - * Set FC mode for BFA_PCI_DEVICE_ID_CT_FC. - */ - 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); - bfa_ioc_mbox_register(&bfa->ioc, bfa_mbox_isrs); - - bfa_iocfc_init_mem(bfa, bfad, cfg, pcidev); - bfa_iocfc_mem_claim(bfa, cfg, meminfo); - bfa_timer_init(&bfa->timer_mod); - - INIT_LIST_HEAD(&bfa->comp_q); - for (i = 0; i < BFI_IOC_MAX_CQS; i++) - INIT_LIST_HEAD(&bfa->reqq_waitq[i]); -} - -/** - * Query IOC memory requirement information. - */ -void -bfa_iocfc_detach(struct bfa_s *bfa) -{ - bfa_ioc_detach(&bfa->ioc); -} - -/** - * Query IOC memory requirement information. - */ -void -bfa_iocfc_init(struct bfa_s *bfa) -{ - bfa->iocfc.action = BFA_IOCFC_ACT_INIT; - bfa_ioc_enable(&bfa->ioc); -} - -/** - * IOC start called from bfa_start(). Called to start IOC operations - * at driver instantiation for this instance. - */ -void -bfa_iocfc_start(struct bfa_s *bfa) -{ - if (bfa->iocfc.cfgdone) - bfa_iocfc_start_submod(bfa); -} - -/** - * IOC stop called from bfa_stop(). Called only when driver is unloaded - * for this instance. - */ -void -bfa_iocfc_stop(struct bfa_s *bfa) -{ - bfa->iocfc.action = BFA_IOCFC_ACT_STOP; - - bfa->rme_process = BFA_FALSE; - bfa_ioc_disable(&bfa->ioc); -} - -void -bfa_iocfc_isr(void *bfaarg, struct bfi_mbmsg_s *m) -{ - struct bfa_s *bfa = bfaarg; - struct bfa_iocfc_s *iocfc = &bfa->iocfc; - union bfi_iocfc_i2h_msg_u *msg; - - msg = (union bfi_iocfc_i2h_msg_u *) m; - bfa_trc(bfa, msg->mh.msg_id); - - switch (msg->mh.msg_id) { - case BFI_IOCFC_I2H_CFG_REPLY: - iocfc->cfg_reply = &msg->cfg_reply; - bfa_iocfc_cfgrsp(bfa); - break; - - case BFI_IOCFC_I2H_GET_STATS_RSP: - if (iocfc->stats_busy == BFA_FALSE - || iocfc->stats_status == BFA_STATUS_ETIMER) - break; - - bfa_timer_stop(&iocfc->stats_timer); - iocfc->stats_status = BFA_STATUS_OK; - bfa_cb_queue(bfa, &iocfc->stats_hcb_qe, bfa_iocfc_stats_cb, - bfa); - break; - case BFI_IOCFC_I2H_CLEAR_STATS_RSP: - /* - * check for timer pop before processing the rsp - */ - if (iocfc->stats_busy == BFA_FALSE - || iocfc->stats_status == BFA_STATUS_ETIMER) - break; - - bfa_timer_stop(&iocfc->stats_timer); - iocfc->stats_status = BFA_STATUS_OK; - bfa_cb_queue(bfa, &iocfc->stats_hcb_qe, - bfa_iocfc_stats_clr_cb, bfa); - break; - case BFI_IOCFC_I2H_UPDATEQ_RSP: - iocfc->updateq_cbfn(iocfc->updateq_cbarg, BFA_STATUS_OK); - break; - default: - bfa_assert(0); - } -} - -#ifndef BFA_BIOS_BUILD -void -bfa_adapter_get_attr(struct bfa_s *bfa, struct bfa_adapter_attr_s *ad_attr) -{ - bfa_ioc_get_adapter_attr(&bfa->ioc, ad_attr); -} - -u64 -bfa_adapter_get_id(struct bfa_s *bfa) -{ - return bfa_ioc_get_adid(&bfa->ioc); -} - -void -bfa_iocfc_get_attr(struct bfa_s *bfa, struct bfa_iocfc_attr_s *attr) -{ - struct bfa_iocfc_s *iocfc = &bfa->iocfc; - - attr->intr_attr.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; - -} - -bfa_status_t -bfa_iocfc_israttr_set(struct bfa_s *bfa, struct bfa_iocfc_intr_attr_s *attr) -{ - struct bfa_iocfc_s *iocfc = &bfa->iocfc; - struct bfi_iocfc_set_intr_req_s *m; - - iocfc->cfginfo->intr_attr.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; - - m = bfa_reqq_next(bfa, BFA_REQQ_IOC); - if (!m) - return BFA_STATUS_DEVBUSY; - - bfi_h2i_set(m->mh, BFI_MC_IOCFC, BFI_IOCFC_H2I_SET_INTR_REQ, - bfa_lpuid(bfa)); - m->coalesce = 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); - - bfa_reqq_produce(bfa, BFA_REQQ_IOC); - return BFA_STATUS_OK; -} - -void -bfa_iocfc_set_snsbase(struct bfa_s *bfa, u64 snsbase_pa) -{ - struct bfa_iocfc_s *iocfc = &bfa->iocfc; - - iocfc->cfginfo->sense_buf_len = (BFI_IOIM_SNSLEN - 1); - bfa_dma_be_addr_set(iocfc->cfginfo->ioim_snsbase, snsbase_pa); -} - -bfa_status_t -bfa_iocfc_get_stats(struct bfa_s *bfa, struct bfa_iocfc_stats_s *stats, - bfa_cb_ioc_t cbfn, void *cbarg) -{ - struct bfa_iocfc_s *iocfc = &bfa->iocfc; - - if (iocfc->stats_busy) { - bfa_trc(bfa, iocfc->stats_busy); - return BFA_STATUS_DEVBUSY; - } - - if (!bfa_iocfc_is_operational(bfa)) { - bfa_trc(bfa, 0); - return BFA_STATUS_IOC_NON_OP; - } - - iocfc->stats_busy = BFA_TRUE; - iocfc->stats_ret = stats; - iocfc->stats_cbfn = cbfn; - iocfc->stats_cbarg = cbarg; - - bfa_iocfc_stats_query(bfa); - - return BFA_STATUS_OK; -} - -bfa_status_t -bfa_iocfc_clear_stats(struct bfa_s *bfa, bfa_cb_ioc_t cbfn, void *cbarg) -{ - struct bfa_iocfc_s *iocfc = &bfa->iocfc; - - if (iocfc->stats_busy) { - bfa_trc(bfa, iocfc->stats_busy); - return BFA_STATUS_DEVBUSY; - } - - if (!bfa_iocfc_is_operational(bfa)) { - bfa_trc(bfa, 0); - return BFA_STATUS_IOC_NON_OP; - } - - iocfc->stats_busy = BFA_TRUE; - iocfc->stats_cbfn = cbfn; - iocfc->stats_cbarg = cbarg; - - bfa_iocfc_stats_clear(bfa); - return BFA_STATUS_OK; -} - -/** - * Enable IOC after it is disabled. - */ -void -bfa_iocfc_enable(struct bfa_s *bfa) -{ - bfa_plog_str(bfa->plog, BFA_PL_MID_HAL, BFA_PL_EID_MISC, 0, - "IOC Enable"); - bfa_ioc_enable(&bfa->ioc); -} - -void -bfa_iocfc_disable(struct bfa_s *bfa) -{ - bfa_plog_str(bfa->plog, BFA_PL_MID_HAL, BFA_PL_EID_MISC, 0, - "IOC Disable"); - bfa->iocfc.action = BFA_IOCFC_ACT_DISABLE; - - bfa->rme_process = BFA_FALSE; - bfa_ioc_disable(&bfa->ioc); -} - - -bfa_boolean_t -bfa_iocfc_is_operational(struct bfa_s *bfa) -{ - return bfa_ioc_is_operational(&bfa->ioc) && bfa->iocfc.cfgdone; -} - -/** - * Return boot target port wwns -- read from boot information in flash. - */ -void -bfa_iocfc_get_bootwwns(struct bfa_s *bfa, u8 *nwwns, wwn_t *wwns) -{ - struct bfa_iocfc_s *iocfc = &bfa->iocfc; - struct bfi_iocfc_cfgrsp_s *cfgrsp = iocfc->cfgrsp; - 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; - memcpy(wwns, cfgrsp->bootwwns.wwn, sizeof(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)); -} - -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 deleted file mode 100644 index 74a6a048d1fd..000000000000 --- a/drivers/scsi/bfa/bfa_iocfc.h +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFA_IOCFC_H__ -#define __BFA_IOCFC_H__ - -#include <bfa_ioc.h> -#include <bfa.h> -#include <bfi/bfi_iocfc.h> -#include <bfi/bfi_pbc.h> -#include <bfa_callback_priv.h> - -#define BFA_REQQ_NELEMS_MIN (4) -#define BFA_RSPQ_NELEMS_MIN (4) - -struct bfa_iocfc_regs_s { - bfa_os_addr_t intr_status; - bfa_os_addr_t intr_mask; - bfa_os_addr_t cpe_q_pi[BFI_IOC_MAX_CQS]; - bfa_os_addr_t cpe_q_ci[BFI_IOC_MAX_CQS]; - bfa_os_addr_t cpe_q_depth[BFI_IOC_MAX_CQS]; - bfa_os_addr_t cpe_q_ctrl[BFI_IOC_MAX_CQS]; - bfa_os_addr_t rme_q_ci[BFI_IOC_MAX_CQS]; - bfa_os_addr_t rme_q_pi[BFI_IOC_MAX_CQS]; - bfa_os_addr_t rme_q_depth[BFI_IOC_MAX_CQS]; - bfa_os_addr_t rme_q_ctrl[BFI_IOC_MAX_CQS]; -}; - -/** - * MSIX vector handlers - */ -#define BFA_MSIX_MAX_VECTORS 22 -typedef void (*bfa_msix_handler_t)(struct bfa_s *bfa, int vec); -struct bfa_msix_s { - int nvecs; - bfa_msix_handler_t handler[BFA_MSIX_MAX_VECTORS]; -}; - -/** - * Chip specific interfaces - */ -struct bfa_hwif_s { - void (*hw_reginit)(struct bfa_s *bfa); - void (*hw_reqq_ack)(struct bfa_s *bfa, int reqq); - void (*hw_rspq_ack)(struct bfa_s *bfa, int rspq); - void (*hw_msix_init)(struct bfa_s *bfa, int nvecs); - void (*hw_msix_install)(struct bfa_s *bfa); - void (*hw_msix_uninstall)(struct bfa_s *bfa); - void (*hw_isr_mode_set)(struct bfa_s *bfa, bfa_boolean_t msix); - void (*hw_msix_getvecs)(struct bfa_s *bfa, u32 *vecmap, - u32 *nvecs, u32 *maxvec); - 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); - -struct bfa_iocfc_s { - struct bfa_s *bfa; - struct bfa_iocfc_cfg_s cfg; - int action; - - u32 req_cq_pi[BFI_IOC_MAX_CQS]; - u32 rsp_cq_ci[BFI_IOC_MAX_CQS]; - - struct bfa_cb_qe_s init_hcb_qe; - struct bfa_cb_qe_s stop_hcb_qe; - struct bfa_cb_qe_s dis_hcb_qe; - struct bfa_cb_qe_s stats_hcb_qe; - bfa_boolean_t cfgdone; - - struct bfa_dma_s cfg_info; - struct bfi_iocfc_cfg_s *cfginfo; - struct bfa_dma_s cfgrsp_dma; - struct bfi_iocfc_cfgrsp_s *cfgrsp; - struct bfi_iocfc_cfg_reply_s *cfg_reply; - - u8 *stats_kva; - u64 stats_pa; - struct bfa_fw_stats_s *fw_stats; - struct bfa_timer_s stats_timer; /* timer */ - struct bfa_iocfc_stats_s *stats_ret; /* driver stats location */ - bfa_status_t stats_status; /* stats/statsclr status */ - bfa_boolean_t stats_busy; /* outstanding stats */ - bfa_cb_ioc_t stats_cbfn; /* driver callback function */ - void *stats_cbarg; /* user callback arg */ - - struct bfa_dma_s req_cq_ba[BFI_IOC_MAX_CQS]; - struct bfa_dma_s req_cq_shadow_ci[BFI_IOC_MAX_CQS]; - struct bfa_dma_s rsp_cq_ba[BFI_IOC_MAX_CQS]; - struct bfa_dma_s rsp_cq_shadow_pi[BFI_IOC_MAX_CQS]; - struct bfa_iocfc_regs_s bfa_regs; /* BFA device registers */ - struct bfa_hwif_s hwif; - - bfa_cb_iocfc_t updateq_cbfn; /* bios callback function */ - void *updateq_cbarg; /* bios callback arg */ - u32 intr_mask; -}; - -#define bfa_lpuid(__bfa) bfa_ioc_portid(&(__bfa)->ioc) -#define bfa_msix_init(__bfa, __nvecs) \ - ((__bfa)->iocfc.hwif.hw_msix_init(__bfa, __nvecs)) -#define bfa_msix_install(__bfa) \ - ((__bfa)->iocfc.hwif.hw_msix_install(__bfa)) -#define bfa_msix_uninstall(__bfa) \ - ((__bfa)->iocfc.hwif.hw_msix_uninstall(__bfa)) -#define bfa_isr_mode_set(__bfa, __msix) \ - ((__bfa)->iocfc.hwif.hw_isr_mode_set(__bfa, __msix)) -#define bfa_msix_getvecs(__bfa, __vecmap, __nvecs, __maxvec) \ - ((__bfa)->iocfc.hwif.hw_msix_getvecs(__bfa, __vecmap, \ - __nvecs, __maxvec)) -#define bfa_msix_get_rme_range(__bfa, __start, __end) \ - ((__bfa)->iocfc.hwif.hw_msix_get_rme_range(__bfa, __start, __end)) - -/* - * FC specific IOC functions. - */ -void bfa_iocfc_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len, - u32 *dm_len); -void bfa_iocfc_attach(struct bfa_s *bfa, void *bfad, - struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo, - struct bfa_pcidev_s *pcidev); -void bfa_iocfc_detach(struct bfa_s *bfa); -void bfa_iocfc_init(struct bfa_s *bfa); -void bfa_iocfc_start(struct bfa_s *bfa); -void bfa_iocfc_stop(struct bfa_s *bfa); -void bfa_iocfc_isr(void *bfa, struct bfi_mbmsg_s *msg); -void bfa_iocfc_set_snsbase(struct bfa_s *bfa, u64 snsbase_pa); -bfa_boolean_t bfa_iocfc_is_operational(struct bfa_s *bfa); -void bfa_iocfc_reset_queues(struct bfa_s *bfa); -void bfa_iocfc_updateq(struct bfa_s *bfa, u32 reqq_ba, u32 rspq_ba, - u32 reqq_sci, u32 rspq_spi, - bfa_cb_iocfc_t cbfn, void *cbarg); - -void bfa_msix_all(struct bfa_s *bfa, int vec); -void bfa_msix_reqq(struct bfa_s *bfa, int vec); -void bfa_msix_rspq(struct bfa_s *bfa, int vec); -void bfa_msix_lpu_err(struct bfa_s *bfa, int vec); - -void bfa_hwcb_reginit(struct bfa_s *bfa); -void bfa_hwcb_reqq_ack(struct bfa_s *bfa, int rspq); -void bfa_hwcb_rspq_ack(struct bfa_s *bfa, int rspq); -void bfa_hwcb_msix_init(struct bfa_s *bfa, int nvecs); -void bfa_hwcb_msix_install(struct bfa_s *bfa); -void bfa_hwcb_msix_uninstall(struct bfa_s *bfa); -void bfa_hwcb_isr_mode_set(struct bfa_s *bfa, bfa_boolean_t msix); -void bfa_hwcb_msix_getvecs(struct bfa_s *bfa, u32 *vecmap, - u32 *nvecs, u32 *maxvec); -void bfa_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); -void bfa_hwct_msix_init(struct bfa_s *bfa, int nvecs); -void bfa_hwct_msix_install(struct bfa_s *bfa); -void bfa_hwct_msix_uninstall(struct bfa_s *bfa); -void bfa_hwct_isr_mode_set(struct bfa_s *bfa, bfa_boolean_t msix); -void bfa_hwct_msix_getvecs(struct bfa_s *bfa, u32 *vecmap, - u32 *nvecs, u32 *maxvec); -void bfa_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, - 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); -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/bfa_iocfc_q.c b/drivers/scsi/bfa/bfa_iocfc_q.c deleted file mode 100644 index 500a17df40b2..000000000000 --- a/drivers/scsi/bfa/bfa_iocfc_q.c +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#include <bfa.h> -#include "bfa_intr_priv.h" - -BFA_TRC_FILE(HAL, IOCFC_Q); - -void -bfa_iocfc_updateq(struct bfa_s *bfa, u32 reqq_ba, u32 rspq_ba, - u32 reqq_sci, u32 rspq_spi, bfa_cb_iocfc_t cbfn, - void *cbarg) -{ - struct bfa_iocfc_s *iocfc = &bfa->iocfc; - struct bfi_iocfc_updateq_req_s updateq_req; - - iocfc->updateq_cbfn = cbfn; - iocfc->updateq_cbarg = cbarg; - - bfi_h2i_set(updateq_req.mh, BFI_MC_IOCFC, BFI_IOCFC_H2I_UPDATEQ_REQ, - bfa_lpuid(bfa)); - - updateq_req.reqq_ba = bfa_os_htonl(reqq_ba); - updateq_req.rspq_ba = bfa_os_htonl(rspq_ba); - updateq_req.reqq_sci = bfa_os_htonl(reqq_sci); - updateq_req.rspq_spi = bfa_os_htonl(rspq_spi); - - bfa_ioc_mbox_send(&bfa->ioc, &updateq_req, - sizeof(struct bfi_iocfc_updateq_req_s)); -} diff --git a/drivers/scsi/bfa/bfa_ioim.c b/drivers/scsi/bfa/bfa_ioim.c deleted file mode 100644 index bdfdc19915f8..000000000000 --- a/drivers/scsi/bfa/bfa_ioim.c +++ /dev/null @@ -1,1364 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#include <bfa.h> -#include <cs/bfa_debug.h> -#include <bfa_cb_ioim_macros.h> - -BFA_TRC_FILE(HAL, IOIM); - -/* - * forward declarations. - */ -static bfa_boolean_t bfa_ioim_send_ioreq(struct bfa_ioim_s *ioim); -static bfa_boolean_t bfa_ioim_sge_setup(struct bfa_ioim_s *ioim); -static void bfa_ioim_sgpg_setup(struct bfa_ioim_s *ioim); -static bfa_boolean_t bfa_ioim_send_abort(struct bfa_ioim_s *ioim); -static void bfa_ioim_notify_cleanup(struct bfa_ioim_s *ioim); -static void __bfa_cb_ioim_good_comp(void *cbarg, bfa_boolean_t complete); -static void __bfa_cb_ioim_comp(void *cbarg, bfa_boolean_t complete); -static void __bfa_cb_ioim_abort(void *cbarg, bfa_boolean_t complete); -static void __bfa_cb_ioim_failed(void *cbarg, bfa_boolean_t complete); -static void __bfa_cb_ioim_pathtov(void *cbarg, bfa_boolean_t complete); - -/** - * bfa_ioim_sm - */ - -/** - * IO state machine events - */ -enum bfa_ioim_event { - BFA_IOIM_SM_START = 1, /* io start request from host */ - BFA_IOIM_SM_COMP_GOOD = 2, /* io good comp, resource free */ - BFA_IOIM_SM_COMP = 3, /* io comp, resource is free */ - BFA_IOIM_SM_COMP_UTAG = 4, /* io comp, resource is free */ - BFA_IOIM_SM_DONE = 5, /* io comp, resource not free */ - BFA_IOIM_SM_FREE = 6, /* io resource is freed */ - BFA_IOIM_SM_ABORT = 7, /* abort request from scsi stack */ - BFA_IOIM_SM_ABORT_COMP = 8, /* abort from f/w */ - BFA_IOIM_SM_ABORT_DONE = 9, /* abort completion from f/w */ - BFA_IOIM_SM_QRESUME = 10, /* CQ space available to queue IO */ - BFA_IOIM_SM_SGALLOCED = 11, /* SG page allocation successful */ - BFA_IOIM_SM_SQRETRY = 12, /* sequence recovery retry */ - BFA_IOIM_SM_HCB = 13, /* bfa callback complete */ - BFA_IOIM_SM_CLEANUP = 14, /* IO cleanup from itnim */ - BFA_IOIM_SM_TMSTART = 15, /* IO cleanup from tskim */ - BFA_IOIM_SM_TMDONE = 16, /* IO cleanup from tskim */ - BFA_IOIM_SM_HWFAIL = 17, /* IOC h/w failure event */ - BFA_IOIM_SM_IOTOV = 18, /* ITN offline TOV */ -}; - -/* - * forward declaration of IO state machine - */ -static void bfa_ioim_sm_uninit(struct bfa_ioim_s *ioim, - enum bfa_ioim_event event); -static void bfa_ioim_sm_sgalloc(struct bfa_ioim_s *ioim, - enum bfa_ioim_event event); -static void bfa_ioim_sm_active(struct bfa_ioim_s *ioim, - enum bfa_ioim_event event); -static void bfa_ioim_sm_abort(struct bfa_ioim_s *ioim, - enum bfa_ioim_event event); -static void bfa_ioim_sm_cleanup(struct bfa_ioim_s *ioim, - enum bfa_ioim_event event); -static void bfa_ioim_sm_qfull(struct bfa_ioim_s *ioim, - enum bfa_ioim_event event); -static void bfa_ioim_sm_abort_qfull(struct bfa_ioim_s *ioim, - enum bfa_ioim_event event); -static void bfa_ioim_sm_cleanup_qfull(struct bfa_ioim_s *ioim, - enum bfa_ioim_event event); -static void bfa_ioim_sm_hcb(struct bfa_ioim_s *ioim, - enum bfa_ioim_event event); -static void bfa_ioim_sm_hcb_free(struct bfa_ioim_s *ioim, - enum bfa_ioim_event event); -static void bfa_ioim_sm_resfree(struct bfa_ioim_s *ioim, - enum bfa_ioim_event event); - -/** - * IO is not started (unallocated). - */ -static void -bfa_ioim_sm_uninit(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) -{ - bfa_trc_fp(ioim->bfa, ioim->iotag); - bfa_trc_fp(ioim->bfa, event); - - switch (event) { - case BFA_IOIM_SM_START: - if (!bfa_itnim_is_online(ioim->itnim)) { - if (!bfa_itnim_hold_io(ioim->itnim)) { - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); - list_del(&ioim->qe); - list_add_tail(&ioim->qe, - &ioim->fcpim->ioim_comp_q); - bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, - __bfa_cb_ioim_pathtov, ioim); - } else { - list_del(&ioim->qe); - list_add_tail(&ioim->qe, - &ioim->itnim->pending_q); - } - break; - } - - if (ioim->nsges > BFI_SGE_INLINE) { - if (!bfa_ioim_sge_setup(ioim)) { - bfa_sm_set_state(ioim, bfa_ioim_sm_sgalloc); - return; - } - } - - if (!bfa_ioim_send_ioreq(ioim)) { - bfa_sm_set_state(ioim, bfa_ioim_sm_qfull); - break; - } - - bfa_sm_set_state(ioim, bfa_ioim_sm_active); - break; - - case BFA_IOIM_SM_IOTOV: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); - 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; - - case BFA_IOIM_SM_ABORT: - /** - * IO in pending queue can get abort requests. Complete abort - * requests immediately. - */ - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); - bfa_assert(bfa_q_is_on_q(&ioim->itnim->pending_q, ioim)); - bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort, - ioim); - break; - - default: - bfa_sm_fault(ioim->bfa, event); - } -} - -/** - * IO is waiting for SG pages. - */ -static void -bfa_ioim_sm_sgalloc(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) -{ - bfa_trc(ioim->bfa, ioim->iotag); - bfa_trc(ioim->bfa, event); - - switch (event) { - case BFA_IOIM_SM_SGALLOCED: - if (!bfa_ioim_send_ioreq(ioim)) { - bfa_sm_set_state(ioim, bfa_ioim_sm_qfull); - break; - } - bfa_sm_set_state(ioim, bfa_ioim_sm_active); - break; - - case BFA_IOIM_SM_CLEANUP: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); - bfa_sgpg_wcancel(ioim->bfa, &ioim->iosp->sgpg_wqe); - bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed, - ioim); - bfa_ioim_notify_cleanup(ioim); - break; - - case BFA_IOIM_SM_ABORT: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); - bfa_sgpg_wcancel(ioim->bfa, &ioim->iosp->sgpg_wqe); - 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_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; - - default: - bfa_sm_fault(ioim->bfa, event); - } -} - -/** - * IO is active. - */ -static void -bfa_ioim_sm_active(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) -{ - bfa_trc_fp(ioim->bfa, ioim->iotag); - bfa_trc_fp(ioim->bfa, event); - - switch (event) { - case BFA_IOIM_SM_COMP_GOOD: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); - 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; - - case BFA_IOIM_SM_ABORT: - ioim->iosp->abort_explicit = BFA_TRUE; - ioim->io_cbfn = __bfa_cb_ioim_abort; - - if (bfa_ioim_send_abort(ioim)) - bfa_sm_set_state(ioim, bfa_ioim_sm_abort); - else { - bfa_sm_set_state(ioim, bfa_ioim_sm_abort_qfull); - bfa_reqq_wait(ioim->bfa, ioim->reqq, - &ioim->iosp->reqq_wait); - } - break; - - case BFA_IOIM_SM_CLEANUP: - ioim->iosp->abort_explicit = BFA_FALSE; - ioim->io_cbfn = __bfa_cb_ioim_failed; - - if (bfa_ioim_send_abort(ioim)) - bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup); - else { - bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup_qfull); - bfa_reqq_wait(ioim->bfa, ioim->reqq, - &ioim->iosp->reqq_wait); - } - break; - - 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; - - default: - bfa_sm_fault(ioim->bfa, event); - } -} - -/** - * IO is being aborted, waiting for completion from firmware. - */ -static void -bfa_ioim_sm_abort(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) -{ - bfa_trc(ioim->bfa, ioim->iotag); - bfa_trc(ioim->bfa, event); - - switch (event) { - case BFA_IOIM_SM_COMP_GOOD: - case BFA_IOIM_SM_COMP: - case BFA_IOIM_SM_DONE: - case BFA_IOIM_SM_FREE: - break; - - case BFA_IOIM_SM_ABORT_DONE: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb_free); - bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort, - ioim); - break; - - case BFA_IOIM_SM_ABORT_COMP: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); - 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; - - case BFA_IOIM_SM_CLEANUP: - bfa_assert(ioim->iosp->abort_explicit == BFA_TRUE); - ioim->iosp->abort_explicit = BFA_FALSE; - - if (bfa_ioim_send_abort(ioim)) - bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup); - else { - bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup_qfull); - bfa_reqq_wait(ioim->bfa, ioim->reqq, - &ioim->iosp->reqq_wait); - } - break; - - 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; - - default: - bfa_sm_fault(ioim->bfa, event); - } -} - -/** - * IO is being cleaned up (implicit abort), waiting for completion from - * firmware. - */ -static void -bfa_ioim_sm_cleanup(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) -{ - bfa_trc(ioim->bfa, ioim->iotag); - bfa_trc(ioim->bfa, event); - - switch (event) { - case BFA_IOIM_SM_COMP_GOOD: - case BFA_IOIM_SM_COMP: - case BFA_IOIM_SM_DONE: - case BFA_IOIM_SM_FREE: - break; - - case BFA_IOIM_SM_ABORT: - /** - * IO is already being aborted implicitly - */ - ioim->io_cbfn = __bfa_cb_ioim_abort; - break; - - case BFA_IOIM_SM_ABORT_DONE: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb_free); - bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, ioim->io_cbfn, ioim); - bfa_ioim_notify_cleanup(ioim); - break; - - case BFA_IOIM_SM_ABORT_COMP: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); - bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, ioim->io_cbfn, ioim); - bfa_ioim_notify_cleanup(ioim); - break; - - case BFA_IOIM_SM_COMP_UTAG: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); - bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, ioim->io_cbfn, ioim); - bfa_ioim_notify_cleanup(ioim); - break; - - case BFA_IOIM_SM_HWFAIL: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); - 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; - - case BFA_IOIM_SM_CLEANUP: - /** - * IO can be in cleanup state already due to TM command. 2nd cleanup - * request comes from ITN offline event. - */ - break; - - default: - bfa_sm_fault(ioim->bfa, event); - } -} - -/** - * IO is waiting for room in request CQ - */ -static void -bfa_ioim_sm_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) -{ - bfa_trc(ioim->bfa, ioim->iotag); - bfa_trc(ioim->bfa, event); - - switch (event) { - case BFA_IOIM_SM_QRESUME: - bfa_sm_set_state(ioim, bfa_ioim_sm_active); - bfa_ioim_send_ioreq(ioim); - break; - - case BFA_IOIM_SM_ABORT: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); - bfa_reqq_wcancel(&ioim->iosp->reqq_wait); - 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_CLEANUP: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); - bfa_reqq_wcancel(&ioim->iosp->reqq_wait); - bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed, - ioim); - bfa_ioim_notify_cleanup(ioim); - break; - - case BFA_IOIM_SM_HWFAIL: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); - bfa_reqq_wcancel(&ioim->iosp->reqq_wait); - 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; - - default: - bfa_sm_fault(ioim->bfa, event); - } -} - -/** - * Active IO is being aborted, waiting for room in request CQ. - */ -static void -bfa_ioim_sm_abort_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) -{ - bfa_trc(ioim->bfa, ioim->iotag); - bfa_trc(ioim->bfa, event); - - switch (event) { - case BFA_IOIM_SM_QRESUME: - bfa_sm_set_state(ioim, bfa_ioim_sm_abort); - bfa_ioim_send_abort(ioim); - break; - - case BFA_IOIM_SM_CLEANUP: - bfa_assert(ioim->iosp->abort_explicit == BFA_TRUE); - ioim->iosp->abort_explicit = BFA_FALSE; - bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup_qfull); - break; - - case BFA_IOIM_SM_COMP_GOOD: - case BFA_IOIM_SM_COMP: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); - bfa_reqq_wcancel(&ioim->iosp->reqq_wait); - 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_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; - - 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; - - default: - bfa_sm_fault(ioim->bfa, event); - } -} - -/** - * Active IO is being cleaned up, waiting for room in request CQ. - */ -static void -bfa_ioim_sm_cleanup_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) -{ - bfa_trc(ioim->bfa, ioim->iotag); - bfa_trc(ioim->bfa, event); - - switch (event) { - case BFA_IOIM_SM_QRESUME: - bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup); - bfa_ioim_send_abort(ioim); - break; - - case BFA_IOIM_SM_ABORT: - /** - * IO is already being cleaned up implicitly - */ - ioim->io_cbfn = __bfa_cb_ioim_abort; - break; - - case BFA_IOIM_SM_COMP_GOOD: - case BFA_IOIM_SM_COMP: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); - bfa_reqq_wcancel(&ioim->iosp->reqq_wait); - bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, ioim->io_cbfn, ioim); - bfa_ioim_notify_cleanup(ioim); - break; - - case BFA_IOIM_SM_DONE: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb_free); - bfa_reqq_wcancel(&ioim->iosp->reqq_wait); - bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, ioim->io_cbfn, ioim); - bfa_ioim_notify_cleanup(ioim); - break; - - case BFA_IOIM_SM_HWFAIL: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); - bfa_reqq_wcancel(&ioim->iosp->reqq_wait); - 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; - - default: - bfa_sm_fault(ioim->bfa, event); - } -} - -/** - * IO bfa callback is pending. - */ -static void -bfa_ioim_sm_hcb(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) -{ - bfa_trc_fp(ioim->bfa, ioim->iotag); - bfa_trc_fp(ioim->bfa, event); - - switch (event) { - case BFA_IOIM_SM_HCB: - bfa_sm_set_state(ioim, bfa_ioim_sm_uninit); - bfa_ioim_free(ioim); - bfa_cb_ioim_resfree(ioim->bfa->bfad); - break; - - case BFA_IOIM_SM_CLEANUP: - bfa_ioim_notify_cleanup(ioim); - break; - - case BFA_IOIM_SM_HWFAIL: - break; - - default: - bfa_sm_fault(ioim->bfa, event); - } -} - -/** - * IO bfa callback is pending. IO resource cannot be freed. - */ -static void -bfa_ioim_sm_hcb_free(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) -{ - bfa_trc(ioim->bfa, ioim->iotag); - bfa_trc(ioim->bfa, event); - - switch (event) { - case BFA_IOIM_SM_HCB: - bfa_sm_set_state(ioim, bfa_ioim_sm_resfree); - list_del(&ioim->qe); - list_add_tail(&ioim->qe, &ioim->fcpim->ioim_resfree_q); - break; - - case BFA_IOIM_SM_FREE: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); - break; - - case BFA_IOIM_SM_CLEANUP: - bfa_ioim_notify_cleanup(ioim); - break; - - case BFA_IOIM_SM_HWFAIL: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); - break; - - default: - bfa_sm_fault(ioim->bfa, event); - } -} - -/** - * IO is completed, waiting resource free from firmware. - */ -static void -bfa_ioim_sm_resfree(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) -{ - bfa_trc(ioim->bfa, ioim->iotag); - bfa_trc(ioim->bfa, event); - - switch (event) { - case BFA_IOIM_SM_FREE: - bfa_sm_set_state(ioim, bfa_ioim_sm_uninit); - bfa_ioim_free(ioim); - bfa_cb_ioim_resfree(ioim->bfa->bfad); - break; - - case BFA_IOIM_SM_CLEANUP: - bfa_ioim_notify_cleanup(ioim); - break; - - case BFA_IOIM_SM_HWFAIL: - break; - - default: - bfa_sm_fault(ioim->bfa, event); - } -} - - - -/** - * bfa_ioim_private - */ - -static void -__bfa_cb_ioim_good_comp(void *cbarg, bfa_boolean_t complete) -{ - struct bfa_ioim_s *ioim = cbarg; - - if (!complete) { - bfa_sm_send_event(ioim, BFA_IOIM_SM_HCB); - return; - } - - bfa_cb_ioim_good_comp(ioim->bfa->bfad, ioim->dio); -} - -static void -__bfa_cb_ioim_comp(void *cbarg, bfa_boolean_t complete) -{ - struct bfa_ioim_s *ioim = cbarg; - struct bfi_ioim_rsp_s *m; - u8 *snsinfo = NULL; - u8 sns_len = 0; - s32 residue = 0; - - if (!complete) { - bfa_sm_send_event(ioim, BFA_IOIM_SM_HCB); - return; - } - - m = (struct bfi_ioim_rsp_s *) &ioim->iosp->comp_rspmsg; - if (m->io_status == BFI_IOIM_STS_OK) { - /** - * setup sense information, if present - */ - if (m->scsi_status == SCSI_STATUS_CHECK_CONDITION - && m->sns_len) { - sns_len = m->sns_len; - snsinfo = ioim->iosp->snsinfo; - } - - /** - * setup residue value correctly for normal completions - */ - if (m->resid_flags == FCP_RESID_UNDER) - residue = bfa_os_ntohl(m->residue); - if (m->resid_flags == FCP_RESID_OVER) { - residue = bfa_os_ntohl(m->residue); - residue = -residue; - } - } - - bfa_cb_ioim_done(ioim->bfa->bfad, ioim->dio, m->io_status, - m->scsi_status, sns_len, snsinfo, residue); -} - -static void -__bfa_cb_ioim_failed(void *cbarg, bfa_boolean_t complete) -{ - struct bfa_ioim_s *ioim = cbarg; - - if (!complete) { - bfa_sm_send_event(ioim, BFA_IOIM_SM_HCB); - return; - } - - bfa_cb_ioim_done(ioim->bfa->bfad, ioim->dio, BFI_IOIM_STS_ABORTED, - 0, 0, NULL, 0); -} - -static void -__bfa_cb_ioim_pathtov(void *cbarg, bfa_boolean_t complete) -{ - struct bfa_ioim_s *ioim = cbarg; - - if (!complete) { - bfa_sm_send_event(ioim, BFA_IOIM_SM_HCB); - return; - } - - bfa_cb_ioim_done(ioim->bfa->bfad, ioim->dio, BFI_IOIM_STS_PATHTOV, - 0, 0, NULL, 0); -} - -static void -__bfa_cb_ioim_abort(void *cbarg, bfa_boolean_t complete) -{ - struct bfa_ioim_s *ioim = cbarg; - - if (!complete) { - bfa_sm_send_event(ioim, BFA_IOIM_SM_HCB); - return; - } - - bfa_cb_ioim_abort(ioim->bfa->bfad, ioim->dio); -} - -static void -bfa_ioim_sgpg_alloced(void *cbarg) -{ - struct bfa_ioim_s *ioim = cbarg; - - ioim->nsgpgs = BFA_SGPG_NPAGE(ioim->nsges); - list_splice_tail_init(&ioim->iosp->sgpg_wqe.sgpg_q, &ioim->sgpg_q); - bfa_ioim_sgpg_setup(ioim); - bfa_sm_send_event(ioim, BFA_IOIM_SM_SGALLOCED); -} - -/** - * Send I/O request to firmware. - */ -static bfa_boolean_t -bfa_ioim_send_ioreq(struct bfa_ioim_s *ioim) -{ - struct bfa_itnim_s *itnim = ioim->itnim; - struct bfi_ioim_req_s *m; - static struct fcp_cmnd_s cmnd_z0 = { 0 }; - struct bfi_sge_s *sge; - u32 pgdlen = 0; - u64 addr; - struct scatterlist *sg; - struct scsi_cmnd *cmnd = (struct scsi_cmnd *) ioim->dio; - - /** - * check for room in queue to send request now - */ - m = bfa_reqq_next(ioim->bfa, ioim->reqq); - if (!m) { - bfa_reqq_wait(ioim->bfa, ioim->reqq, - &ioim->iosp->reqq_wait); - return BFA_FALSE; - } - - /** - * build i/o request message next - */ - m->io_tag = bfa_os_htons(ioim->iotag); - m->rport_hdl = ioim->itnim->rport->fw_handle; - m->io_timeout = bfa_cb_ioim_get_timeout(ioim->dio); - - /** - * build inline IO SG element here - */ - sge = &m->sges[0]; - if (ioim->nsges) { - sg = (struct scatterlist *)scsi_sglist(cmnd); - addr = bfa_os_sgaddr(sg_dma_address(sg)); - sge->sga = *(union bfi_addr_u *) &addr; - pgdlen = sg_dma_len(sg); - sge->sg_len = pgdlen; - sge->flags = (ioim->nsges > BFI_SGE_INLINE) ? - BFI_SGE_DATA_CPL : BFI_SGE_DATA_LAST; - bfa_sge_to_be(sge); - sge++; - } - - if (ioim->nsges > BFI_SGE_INLINE) { - sge->sga = ioim->sgpg->sgpg_pa; - } else { - sge->sga.a32.addr_lo = 0; - sge->sga.a32.addr_hi = 0; - } - sge->sg_len = pgdlen; - sge->flags = BFI_SGE_PGDLEN; - bfa_sge_to_be(sge); - - /** - * set up I/O command parameters - */ - bfa_os_assign(m->cmnd, cmnd_z0); - m->cmnd.lun = bfa_cb_ioim_get_lun(ioim->dio); - m->cmnd.iodir = bfa_cb_ioim_get_iodir(ioim->dio); - bfa_os_assign(m->cmnd.cdb, - *(struct scsi_cdb_s *)bfa_cb_ioim_get_cdb(ioim->dio)); - m->cmnd.fcp_dl = bfa_os_htonl(bfa_cb_ioim_get_size(ioim->dio)); - - /** - * set up I/O message header - */ - switch (m->cmnd.iodir) { - case FCP_IODIR_READ: - bfi_h2i_set(m->mh, BFI_MC_IOIM_READ, 0, bfa_lpuid(ioim->bfa)); - bfa_stats(itnim, input_reqs); - break; - case FCP_IODIR_WRITE: - bfi_h2i_set(m->mh, BFI_MC_IOIM_WRITE, 0, bfa_lpuid(ioim->bfa)); - bfa_stats(itnim, output_reqs); - break; - case FCP_IODIR_RW: - bfa_stats(itnim, input_reqs); - bfa_stats(itnim, output_reqs); - default: - bfi_h2i_set(m->mh, BFI_MC_IOIM_IO, 0, bfa_lpuid(ioim->bfa)); - } - if (itnim->seq_rec || - (bfa_cb_ioim_get_size(ioim->dio) & (sizeof(u32) - 1))) - bfi_h2i_set(m->mh, BFI_MC_IOIM_IO, 0, bfa_lpuid(ioim->bfa)); - -#ifdef IOIM_ADVANCED - m->cmnd.crn = bfa_cb_ioim_get_crn(ioim->dio); - m->cmnd.priority = bfa_cb_ioim_get_priority(ioim->dio); - m->cmnd.taskattr = bfa_cb_ioim_get_taskattr(ioim->dio); - - /** - * Handle large CDB (>16 bytes). - */ - m->cmnd.addl_cdb_len = (bfa_cb_ioim_get_cdblen(ioim->dio) - - FCP_CMND_CDB_LEN) / sizeof(u32); - if (m->cmnd.addl_cdb_len) { - bfa_os_memcpy(&m->cmnd.cdb + 1, (struct scsi_cdb_s *) - bfa_cb_ioim_get_cdb(ioim->dio) + 1, - m->cmnd.addl_cdb_len * sizeof(u32)); - fcp_cmnd_fcpdl(&m->cmnd) = - bfa_os_htonl(bfa_cb_ioim_get_size(ioim->dio)); - } -#endif - - /** - * queue I/O message to firmware - */ - bfa_reqq_produce(ioim->bfa, ioim->reqq); - return BFA_TRUE; -} - -/** - * Setup any additional SG pages needed.Inline SG element is setup - * at queuing time. - */ -static bfa_boolean_t -bfa_ioim_sge_setup(struct bfa_ioim_s *ioim) -{ - u16 nsgpgs; - - bfa_assert(ioim->nsges > BFI_SGE_INLINE); - - /** - * allocate SG pages needed - */ - nsgpgs = BFA_SGPG_NPAGE(ioim->nsges); - if (!nsgpgs) - return BFA_TRUE; - - if (bfa_sgpg_malloc(ioim->bfa, &ioim->sgpg_q, nsgpgs) - != BFA_STATUS_OK) { - bfa_sgpg_wait(ioim->bfa, &ioim->iosp->sgpg_wqe, nsgpgs); - return BFA_FALSE; - } - - ioim->nsgpgs = nsgpgs; - bfa_ioim_sgpg_setup(ioim); - - return BFA_TRUE; -} - -static void -bfa_ioim_sgpg_setup(struct bfa_ioim_s *ioim) -{ - int sgeid, nsges, i; - struct bfi_sge_s *sge; - struct bfa_sgpg_s *sgpg; - u32 pgcumsz; - u64 addr; - struct scatterlist *sg; - struct scsi_cmnd *cmnd = (struct scsi_cmnd *) ioim->dio; - - sgeid = BFI_SGE_INLINE; - ioim->sgpg = sgpg = bfa_q_first(&ioim->sgpg_q); - - sg = scsi_sglist(cmnd); - sg = sg_next(sg); - - do { - sge = sgpg->sgpg->sges; - nsges = ioim->nsges - sgeid; - if (nsges > BFI_SGPG_DATA_SGES) - nsges = BFI_SGPG_DATA_SGES; - - pgcumsz = 0; - for (i = 0; i < nsges; i++, sge++, sgeid++, sg = sg_next(sg)) { - addr = bfa_os_sgaddr(sg_dma_address(sg)); - sge->sga = *(union bfi_addr_u *) &addr; - sge->sg_len = sg_dma_len(sg); - pgcumsz += sge->sg_len; - - /** - * set flags - */ - if (i < (nsges - 1)) - sge->flags = BFI_SGE_DATA; - else if (sgeid < (ioim->nsges - 1)) - sge->flags = BFI_SGE_DATA_CPL; - else - sge->flags = BFI_SGE_DATA_LAST; - } - - sgpg = (struct bfa_sgpg_s *) bfa_q_next(sgpg); - - /** - * set the link element of each page - */ - if (sgeid == ioim->nsges) { - sge->flags = BFI_SGE_PGDLEN; - sge->sga.a32.addr_lo = 0; - sge->sga.a32.addr_hi = 0; - } else { - sge->flags = BFI_SGE_LINK; - sge->sga = sgpg->sgpg_pa; - } - sge->sg_len = pgcumsz; - } while (sgeid < ioim->nsges); -} - -/** - * Send I/O abort request to firmware. - */ -static bfa_boolean_t -bfa_ioim_send_abort(struct bfa_ioim_s *ioim) -{ - struct 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, ioim->reqq); - if (!m) - return BFA_FALSE; - - /** - * build i/o request message next - */ - if (ioim->iosp->abort_explicit) - msgop = BFI_IOIM_H2I_IOABORT_REQ; - else - msgop = BFI_IOIM_H2I_IOCLEANUP_REQ; - - bfi_h2i_set(m->mh, BFI_MC_IOIM, msgop, bfa_lpuid(ioim->bfa)); - m->io_tag = bfa_os_htons(ioim->iotag); - m->abort_tag = ++ioim->abort_tag; - - /** - * queue I/O message to firmware - */ - bfa_reqq_produce(ioim->bfa, ioim->reqq); - return BFA_TRUE; -} - -/** - * Call to resume any I/O requests waiting for room in request queue. - */ -static void -bfa_ioim_qresume(void *cbarg) -{ - struct bfa_ioim_s *ioim = cbarg; - - bfa_fcpim_stats(ioim->fcpim, qresumes); - bfa_sm_send_event(ioim, BFA_IOIM_SM_QRESUME); -} - - -static void -bfa_ioim_notify_cleanup(struct bfa_ioim_s *ioim) -{ - /** - * Move IO from itnim queue to fcpim global queue since itnim will be - * freed. - */ - list_del(&ioim->qe); - list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q); - - if (!ioim->iosp->tskim) { - if (ioim->fcpim->delay_comp && ioim->itnim->iotov_active) { - bfa_cb_dequeue(&ioim->hcb_qe); - list_del(&ioim->qe); - list_add_tail(&ioim->qe, &ioim->itnim->delay_comp_q); - } - bfa_itnim_iodone(ioim->itnim); - } else - bfa_tskim_iodone(ioim->iosp->tskim); -} - -/** - * or after the link comes back. - */ -void -bfa_ioim_delayed_comp(struct bfa_ioim_s *ioim, bfa_boolean_t iotov) -{ - /** - * If path tov timer expired, failback with PATHTOV status - these - * IO requests are not normally retried by IO stack. - * - * Otherwise device cameback online and fail it with normal failed - * status so that IO stack retries these failed IO requests. - */ - if (iotov) - ioim->io_cbfn = __bfa_cb_ioim_pathtov; - else - ioim->io_cbfn = __bfa_cb_ioim_failed; - - bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, ioim->io_cbfn, ioim); - - /** - * Move IO to fcpim global queue since itnim will be - * freed. - */ - list_del(&ioim->qe); - list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q); -} - - - -/** - * bfa_ioim_friend - */ - -/** - * Memory allocation and initialization. - */ -void -bfa_ioim_attach(struct bfa_fcpim_mod_s *fcpim, struct bfa_meminfo_s *minfo) -{ - struct bfa_ioim_s *ioim; - struct bfa_ioim_sp_s *iosp; - u16 i; - u8 *snsinfo; - u32 snsbufsz; - - /** - * claim memory first - */ - ioim = (struct bfa_ioim_s *) bfa_meminfo_kva(minfo); - fcpim->ioim_arr = ioim; - bfa_meminfo_kva(minfo) = (u8 *) (ioim + fcpim->num_ioim_reqs); - - iosp = (struct bfa_ioim_sp_s *) bfa_meminfo_kva(minfo); - fcpim->ioim_sp_arr = iosp; - bfa_meminfo_kva(minfo) = (u8 *) (iosp + fcpim->num_ioim_reqs); - - /** - * Claim DMA memory for per IO sense data. - */ - snsbufsz = fcpim->num_ioim_reqs * BFI_IOIM_SNSLEN; - fcpim->snsbase.pa = bfa_meminfo_dma_phys(minfo); - bfa_meminfo_dma_phys(minfo) += snsbufsz; - - fcpim->snsbase.kva = bfa_meminfo_dma_virt(minfo); - bfa_meminfo_dma_virt(minfo) += snsbufsz; - snsinfo = fcpim->snsbase.kva; - bfa_iocfc_set_snsbase(fcpim->bfa, fcpim->snsbase.pa); - - /** - * Initialize ioim free queues - */ - INIT_LIST_HEAD(&fcpim->ioim_free_q); - INIT_LIST_HEAD(&fcpim->ioim_resfree_q); - INIT_LIST_HEAD(&fcpim->ioim_comp_q); - - for (i = 0; i < fcpim->num_ioim_reqs; - i++, ioim++, iosp++, snsinfo += BFI_IOIM_SNSLEN) { - /* - * initialize IOIM - */ - bfa_os_memset(ioim, 0, sizeof(struct bfa_ioim_s)); - ioim->iotag = i; - ioim->bfa = fcpim->bfa; - ioim->fcpim = fcpim; - ioim->iosp = iosp; - iosp->snsinfo = snsinfo; - INIT_LIST_HEAD(&ioim->sgpg_q); - bfa_reqq_winit(&ioim->iosp->reqq_wait, - bfa_ioim_qresume, ioim); - bfa_sgpg_winit(&ioim->iosp->sgpg_wqe, - bfa_ioim_sgpg_alloced, ioim); - bfa_sm_set_state(ioim, bfa_ioim_sm_uninit); - - list_add_tail(&ioim->qe, &fcpim->ioim_free_q); - } -} - -/** - * Driver detach time call. - */ -void -bfa_ioim_detach(struct bfa_fcpim_mod_s *fcpim) -{ -} - -void -bfa_ioim_isr(struct bfa_s *bfa, struct bfi_msg_s *m) -{ - struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); - struct bfi_ioim_rsp_s *rsp = (struct bfi_ioim_rsp_s *) m; - struct bfa_ioim_s *ioim; - u16 iotag; - enum bfa_ioim_event evt = BFA_IOIM_SM_COMP; - - iotag = bfa_os_ntohs(rsp->io_tag); - - ioim = BFA_IOIM_FROM_TAG(fcpim, iotag); - bfa_assert(ioim->iotag == iotag); - - bfa_trc(ioim->bfa, ioim->iotag); - bfa_trc(ioim->bfa, rsp->io_status); - bfa_trc(ioim->bfa, rsp->reuse_io_tag); - - if (bfa_sm_cmp_state(ioim, bfa_ioim_sm_active)) - bfa_os_assign(ioim->iosp->comp_rspmsg, *m); - - switch (rsp->io_status) { - case BFI_IOIM_STS_OK: - bfa_fcpim_stats(fcpim, iocomp_ok); - if (rsp->reuse_io_tag == 0) - evt = BFA_IOIM_SM_DONE; - else - evt = BFA_IOIM_SM_COMP; - break; - - case BFI_IOIM_STS_TIMEDOUT: - case BFI_IOIM_STS_ABORTED: - rsp->io_status = BFI_IOIM_STS_ABORTED; - bfa_fcpim_stats(fcpim, iocomp_aborted); - if (rsp->reuse_io_tag == 0) - evt = BFA_IOIM_SM_DONE; - else - evt = BFA_IOIM_SM_COMP; - break; - - case BFI_IOIM_STS_PROTO_ERR: - bfa_fcpim_stats(fcpim, iocom_proto_err); - bfa_assert(rsp->reuse_io_tag); - evt = BFA_IOIM_SM_COMP; - break; - - case BFI_IOIM_STS_SQER_NEEDED: - bfa_fcpim_stats(fcpim, iocom_sqer_needed); - bfa_assert(rsp->reuse_io_tag == 0); - evt = BFA_IOIM_SM_SQRETRY; - break; - - case BFI_IOIM_STS_RES_FREE: - bfa_fcpim_stats(fcpim, iocom_res_free); - evt = BFA_IOIM_SM_FREE; - break; - - case BFI_IOIM_STS_HOST_ABORTED: - bfa_fcpim_stats(fcpim, iocom_hostabrts); - if (rsp->abort_tag != ioim->abort_tag) { - bfa_trc(ioim->bfa, rsp->abort_tag); - bfa_trc(ioim->bfa, ioim->abort_tag); - return; - } - - if (rsp->reuse_io_tag) - evt = BFA_IOIM_SM_ABORT_COMP; - else - evt = BFA_IOIM_SM_ABORT_DONE; - break; - - case BFI_IOIM_STS_UTAG: - bfa_fcpim_stats(fcpim, iocom_utags); - evt = BFA_IOIM_SM_COMP_UTAG; - break; - - default: - bfa_assert(0); - } - - bfa_sm_send_event(ioim, evt); -} - -void -bfa_ioim_good_comp_isr(struct bfa_s *bfa, struct bfi_msg_s *m) -{ - struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); - struct bfi_ioim_rsp_s *rsp = (struct bfi_ioim_rsp_s *) m; - struct bfa_ioim_s *ioim; - u16 iotag; - - iotag = bfa_os_ntohs(rsp->io_tag); - - ioim = BFA_IOIM_FROM_TAG(fcpim, iotag); - bfa_assert(ioim->iotag == iotag); - - bfa_trc_fp(ioim->bfa, ioim->iotag); - bfa_sm_send_event(ioim, BFA_IOIM_SM_COMP_GOOD); -} - -/** - * Called by itnim to clean up IO while going offline. - */ -void -bfa_ioim_cleanup(struct bfa_ioim_s *ioim) -{ - bfa_trc(ioim->bfa, ioim->iotag); - bfa_fcpim_stats(ioim->fcpim, io_cleanups); - - ioim->iosp->tskim = NULL; - bfa_sm_send_event(ioim, BFA_IOIM_SM_CLEANUP); -} - -void -bfa_ioim_cleanup_tm(struct bfa_ioim_s *ioim, struct bfa_tskim_s *tskim) -{ - bfa_trc(ioim->bfa, ioim->iotag); - bfa_fcpim_stats(ioim->fcpim, io_tmaborts); - - ioim->iosp->tskim = tskim; - bfa_sm_send_event(ioim, BFA_IOIM_SM_CLEANUP); -} - -/** - * IOC failure handling. - */ -void -bfa_ioim_iocdisable(struct bfa_ioim_s *ioim) -{ - bfa_sm_send_event(ioim, BFA_IOIM_SM_HWFAIL); -} - -/** - * IO offline TOV popped. Fail the pending IO. - */ -void -bfa_ioim_tov(struct bfa_ioim_s *ioim) -{ - bfa_sm_send_event(ioim, BFA_IOIM_SM_IOTOV); -} - - - -/** - * bfa_ioim_api - */ - -/** - * Allocate IOIM resource for initiator mode I/O request. - */ -struct bfa_ioim_s * -bfa_ioim_alloc(struct bfa_s *bfa, struct bfad_ioim_s *dio, - struct bfa_itnim_s *itnim, u16 nsges) -{ - struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); - struct bfa_ioim_s *ioim; - - /** - * alocate IOIM resource - */ - bfa_q_deq(&fcpim->ioim_free_q, &ioim); - if (!ioim) { - bfa_fcpim_stats(fcpim, no_iotags); - return NULL; - } - - ioim->dio = dio; - ioim->itnim = itnim; - ioim->nsges = nsges; - ioim->nsgpgs = 0; - - bfa_stats(fcpim, total_ios); - bfa_stats(itnim, ios); - fcpim->ios_active++; - - list_add_tail(&ioim->qe, &itnim->io_q); - bfa_trc_fp(ioim->bfa, ioim->iotag); - - return ioim; -} - -void -bfa_ioim_free(struct bfa_ioim_s *ioim) -{ - struct bfa_fcpim_mod_s *fcpim = ioim->fcpim; - - bfa_trc_fp(ioim->bfa, ioim->iotag); - bfa_assert_fp(bfa_sm_cmp_state(ioim, bfa_ioim_sm_uninit)); - - bfa_assert_fp(list_empty(&ioim->sgpg_q) - || (ioim->nsges > BFI_SGE_INLINE)); - - if (ioim->nsgpgs > 0) - bfa_sgpg_mfree(ioim->bfa, &ioim->sgpg_q, ioim->nsgpgs); - - bfa_stats(ioim->itnim, io_comps); - fcpim->ios_active--; - - list_del(&ioim->qe); - list_add_tail(&ioim->qe, &fcpim->ioim_free_q); -} - -void -bfa_ioim_start(struct bfa_ioim_s *ioim) -{ - bfa_trc_fp(ioim->bfa, ioim->iotag); - - /** - * 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); -} - -/** - * Driver I/O abort request. - */ -void -bfa_ioim_abort(struct bfa_ioim_s *ioim) -{ - bfa_trc(ioim->bfa, ioim->iotag); - bfa_fcpim_stats(ioim->fcpim, io_aborts); - bfa_sm_send_event(ioim, BFA_IOIM_SM_ABORT); -} - - diff --git a/drivers/scsi/bfa/bfa_itnim.c b/drivers/scsi/bfa/bfa_itnim.c deleted file mode 100644 index a914ff255135..000000000000 --- a/drivers/scsi/bfa/bfa_itnim.c +++ /dev/null @@ -1,1088 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#include <bfa.h> -#include <bfa_fcpim.h> -#include "bfa_fcpim_priv.h" - -BFA_TRC_FILE(HAL, ITNIM); - -#define BFA_ITNIM_FROM_TAG(_fcpim, _tag) \ - ((_fcpim)->itnim_arr + ((_tag) & ((_fcpim)->num_itnims - 1))) - -#define bfa_fcpim_additn(__itnim) \ - list_add_tail(&(__itnim)->qe, &(__itnim)->fcpim->itnim_q) -#define bfa_fcpim_delitn(__itnim) do { \ - bfa_assert(bfa_q_is_on_q(&(__itnim)->fcpim->itnim_q, __itnim)); \ - list_del(&(__itnim)->qe); \ - bfa_assert(list_empty(&(__itnim)->io_q)); \ - bfa_assert(list_empty(&(__itnim)->io_cleanup_q)); \ - bfa_assert(list_empty(&(__itnim)->pending_q)); \ -} while (0) - -#define bfa_itnim_online_cb(__itnim) do { \ - if ((__itnim)->bfa->fcs) \ - bfa_cb_itnim_online((__itnim)->ditn); \ - else { \ - bfa_cb_queue((__itnim)->bfa, &(__itnim)->hcb_qe, \ - __bfa_cb_itnim_online, (__itnim)); \ - } \ -} while (0) - -#define bfa_itnim_offline_cb(__itnim) do { \ - if ((__itnim)->bfa->fcs) \ - bfa_cb_itnim_offline((__itnim)->ditn); \ - else { \ - bfa_cb_queue((__itnim)->bfa, &(__itnim)->hcb_qe, \ - __bfa_cb_itnim_offline, (__itnim)); \ - } \ -} while (0) - -#define bfa_itnim_sler_cb(__itnim) do { \ - if ((__itnim)->bfa->fcs) \ - bfa_cb_itnim_sler((__itnim)->ditn); \ - else { \ - bfa_cb_queue((__itnim)->bfa, &(__itnim)->hcb_qe, \ - __bfa_cb_itnim_sler, (__itnim)); \ - } \ -} while (0) - -/* - * forward declarations - */ -static void bfa_itnim_iocdisable_cleanup(struct bfa_itnim_s *itnim); -static bfa_boolean_t bfa_itnim_send_fwcreate(struct bfa_itnim_s *itnim); -static bfa_boolean_t bfa_itnim_send_fwdelete(struct bfa_itnim_s *itnim); -static void bfa_itnim_cleanp_comp(void *itnim_cbarg); -static void bfa_itnim_cleanup(struct bfa_itnim_s *itnim); -static void __bfa_cb_itnim_online(void *cbarg, bfa_boolean_t complete); -static void __bfa_cb_itnim_offline(void *cbarg, bfa_boolean_t complete); -static void __bfa_cb_itnim_sler(void *cbarg, bfa_boolean_t complete); -static void bfa_itnim_iotov_online(struct bfa_itnim_s *itnim); -static void bfa_itnim_iotov_cleanup(struct bfa_itnim_s *itnim); -static void bfa_itnim_iotov(void *itnim_arg); -static void bfa_itnim_iotov_start(struct bfa_itnim_s *itnim); -static void bfa_itnim_iotov_stop(struct bfa_itnim_s *itnim); -static void bfa_itnim_iotov_delete(struct bfa_itnim_s *itnim); - -/** - * bfa_itnim_sm BFA itnim state machine - */ - - -enum bfa_itnim_event { - BFA_ITNIM_SM_CREATE = 1, /* itnim is created */ - BFA_ITNIM_SM_ONLINE = 2, /* itnim is online */ - BFA_ITNIM_SM_OFFLINE = 3, /* itnim is offline */ - BFA_ITNIM_SM_FWRSP = 4, /* firmware response */ - BFA_ITNIM_SM_DELETE = 5, /* deleting an existing itnim */ - BFA_ITNIM_SM_CLEANUP = 6, /* IO cleanup completion */ - BFA_ITNIM_SM_SLER = 7, /* second level error recovery */ - BFA_ITNIM_SM_HWFAIL = 8, /* IOC h/w failure event */ - BFA_ITNIM_SM_QRESUME = 9, /* queue space available */ -}; - -static void bfa_itnim_sm_uninit(struct bfa_itnim_s *itnim, - enum bfa_itnim_event event); -static void bfa_itnim_sm_created(struct bfa_itnim_s *itnim, - enum bfa_itnim_event event); -static void bfa_itnim_sm_fwcreate(struct bfa_itnim_s *itnim, - enum bfa_itnim_event event); -static void bfa_itnim_sm_delete_pending(struct bfa_itnim_s *itnim, - enum bfa_itnim_event event); -static void bfa_itnim_sm_online(struct bfa_itnim_s *itnim, - enum bfa_itnim_event event); -static void bfa_itnim_sm_sler(struct bfa_itnim_s *itnim, - enum bfa_itnim_event event); -static void bfa_itnim_sm_cleanup_offline(struct bfa_itnim_s *itnim, - enum bfa_itnim_event event); -static void bfa_itnim_sm_cleanup_delete(struct bfa_itnim_s *itnim, - enum bfa_itnim_event event); -static void bfa_itnim_sm_fwdelete(struct bfa_itnim_s *itnim, - enum bfa_itnim_event event); -static void bfa_itnim_sm_offline(struct bfa_itnim_s *itnim, - enum bfa_itnim_event event); -static void bfa_itnim_sm_iocdisable(struct bfa_itnim_s *itnim, - enum bfa_itnim_event event); -static void bfa_itnim_sm_deleting(struct bfa_itnim_s *itnim, - enum bfa_itnim_event event); -static void bfa_itnim_sm_fwcreate_qfull(struct bfa_itnim_s *itnim, - enum bfa_itnim_event event); -static void bfa_itnim_sm_fwdelete_qfull(struct bfa_itnim_s *itnim, - enum bfa_itnim_event event); -static void bfa_itnim_sm_deleting_qfull(struct bfa_itnim_s *itnim, - enum bfa_itnim_event event); - -/** - * Beginning/unallocated state - no events expected. - */ -static void -bfa_itnim_sm_uninit(struct bfa_itnim_s *itnim, enum bfa_itnim_event event) -{ - bfa_trc(itnim->bfa, itnim->rport->rport_tag); - bfa_trc(itnim->bfa, event); - - switch (event) { - case BFA_ITNIM_SM_CREATE: - bfa_sm_set_state(itnim, bfa_itnim_sm_created); - itnim->is_online = BFA_FALSE; - bfa_fcpim_additn(itnim); - break; - - default: - bfa_sm_fault(itnim->bfa, event); - } -} - -/** - * Beginning state, only online event expected. - */ -static void -bfa_itnim_sm_created(struct bfa_itnim_s *itnim, enum bfa_itnim_event event) -{ - bfa_trc(itnim->bfa, itnim->rport->rport_tag); - bfa_trc(itnim->bfa, event); - - switch (event) { - case BFA_ITNIM_SM_ONLINE: - if (bfa_itnim_send_fwcreate(itnim)) - bfa_sm_set_state(itnim, bfa_itnim_sm_fwcreate); - else - bfa_sm_set_state(itnim, bfa_itnim_sm_fwcreate_qfull); - break; - - case BFA_ITNIM_SM_DELETE: - bfa_sm_set_state(itnim, bfa_itnim_sm_uninit); - bfa_fcpim_delitn(itnim); - break; - - case BFA_ITNIM_SM_HWFAIL: - bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable); - break; - - default: - bfa_sm_fault(itnim->bfa, event); - } -} - -/** - * Waiting for itnim create response from firmware. - */ -static void -bfa_itnim_sm_fwcreate(struct bfa_itnim_s *itnim, enum bfa_itnim_event event) -{ - bfa_trc(itnim->bfa, itnim->rport->rport_tag); - bfa_trc(itnim->bfa, event); - - switch (event) { - case BFA_ITNIM_SM_FWRSP: - bfa_sm_set_state(itnim, bfa_itnim_sm_online); - itnim->is_online = BFA_TRUE; - bfa_itnim_iotov_online(itnim); - bfa_itnim_online_cb(itnim); - break; - - case BFA_ITNIM_SM_DELETE: - bfa_sm_set_state(itnim, bfa_itnim_sm_delete_pending); - break; - - case BFA_ITNIM_SM_OFFLINE: - if (bfa_itnim_send_fwdelete(itnim)) - bfa_sm_set_state(itnim, bfa_itnim_sm_fwdelete); - else - bfa_sm_set_state(itnim, bfa_itnim_sm_fwdelete_qfull); - break; - - case BFA_ITNIM_SM_HWFAIL: - bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable); - break; - - default: - bfa_sm_fault(itnim->bfa, event); - } -} - -static void -bfa_itnim_sm_fwcreate_qfull(struct bfa_itnim_s *itnim, - enum bfa_itnim_event event) -{ - bfa_trc(itnim->bfa, itnim->rport->rport_tag); - bfa_trc(itnim->bfa, event); - - switch (event) { - case BFA_ITNIM_SM_QRESUME: - bfa_sm_set_state(itnim, bfa_itnim_sm_fwcreate); - bfa_itnim_send_fwcreate(itnim); - break; - - case BFA_ITNIM_SM_DELETE: - bfa_sm_set_state(itnim, bfa_itnim_sm_uninit); - bfa_reqq_wcancel(&itnim->reqq_wait); - bfa_fcpim_delitn(itnim); - break; - - case BFA_ITNIM_SM_OFFLINE: - bfa_sm_set_state(itnim, bfa_itnim_sm_offline); - bfa_reqq_wcancel(&itnim->reqq_wait); - bfa_itnim_offline_cb(itnim); - break; - - case BFA_ITNIM_SM_HWFAIL: - bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable); - bfa_reqq_wcancel(&itnim->reqq_wait); - break; - - default: - bfa_sm_fault(itnim->bfa, event); - } -} - -/** - * Waiting for itnim create response from firmware, a delete is pending. - */ -static void -bfa_itnim_sm_delete_pending(struct bfa_itnim_s *itnim, - enum bfa_itnim_event event) -{ - bfa_trc(itnim->bfa, itnim->rport->rport_tag); - bfa_trc(itnim->bfa, event); - - switch (event) { - case BFA_ITNIM_SM_FWRSP: - if (bfa_itnim_send_fwdelete(itnim)) - bfa_sm_set_state(itnim, bfa_itnim_sm_deleting); - else - bfa_sm_set_state(itnim, bfa_itnim_sm_deleting_qfull); - break; - - case BFA_ITNIM_SM_HWFAIL: - bfa_sm_set_state(itnim, bfa_itnim_sm_uninit); - bfa_fcpim_delitn(itnim); - break; - - default: - bfa_sm_fault(itnim->bfa, event); - } -} - -/** - * Online state - normal parking state. - */ -static void -bfa_itnim_sm_online(struct bfa_itnim_s *itnim, enum bfa_itnim_event event) -{ - bfa_trc(itnim->bfa, itnim->rport->rport_tag); - bfa_trc(itnim->bfa, event); - - switch (event) { - case BFA_ITNIM_SM_OFFLINE: - bfa_sm_set_state(itnim, bfa_itnim_sm_cleanup_offline); - itnim->is_online = BFA_FALSE; - bfa_itnim_iotov_start(itnim); - bfa_itnim_cleanup(itnim); - break; - - case BFA_ITNIM_SM_DELETE: - bfa_sm_set_state(itnim, bfa_itnim_sm_cleanup_delete); - itnim->is_online = BFA_FALSE; - bfa_itnim_cleanup(itnim); - break; - - case BFA_ITNIM_SM_SLER: - bfa_sm_set_state(itnim, bfa_itnim_sm_sler); - itnim->is_online = BFA_FALSE; - bfa_itnim_iotov_start(itnim); - bfa_itnim_sler_cb(itnim); - break; - - case BFA_ITNIM_SM_HWFAIL: - bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable); - itnim->is_online = BFA_FALSE; - bfa_itnim_iotov_start(itnim); - bfa_itnim_iocdisable_cleanup(itnim); - break; - - default: - bfa_sm_fault(itnim->bfa, event); - } -} - -/** - * Second level error recovery need. - */ -static void -bfa_itnim_sm_sler(struct bfa_itnim_s *itnim, enum bfa_itnim_event event) -{ - bfa_trc(itnim->bfa, itnim->rport->rport_tag); - bfa_trc(itnim->bfa, event); - - switch (event) { - case BFA_ITNIM_SM_OFFLINE: - bfa_sm_set_state(itnim, bfa_itnim_sm_cleanup_offline); - bfa_itnim_cleanup(itnim); - break; - - case BFA_ITNIM_SM_DELETE: - bfa_sm_set_state(itnim, bfa_itnim_sm_cleanup_delete); - bfa_itnim_cleanup(itnim); - bfa_itnim_iotov_delete(itnim); - break; - - case BFA_ITNIM_SM_HWFAIL: - bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable); - bfa_itnim_iocdisable_cleanup(itnim); - break; - - default: - bfa_sm_fault(itnim->bfa, event); - } -} - -/** - * Going offline. Waiting for active IO cleanup. - */ -static void -bfa_itnim_sm_cleanup_offline(struct bfa_itnim_s *itnim, - enum bfa_itnim_event event) -{ - bfa_trc(itnim->bfa, itnim->rport->rport_tag); - bfa_trc(itnim->bfa, event); - - switch (event) { - case BFA_ITNIM_SM_CLEANUP: - if (bfa_itnim_send_fwdelete(itnim)) - bfa_sm_set_state(itnim, bfa_itnim_sm_fwdelete); - else - bfa_sm_set_state(itnim, bfa_itnim_sm_fwdelete_qfull); - break; - - case BFA_ITNIM_SM_DELETE: - bfa_sm_set_state(itnim, bfa_itnim_sm_cleanup_delete); - bfa_itnim_iotov_delete(itnim); - break; - - case BFA_ITNIM_SM_HWFAIL: - bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable); - bfa_itnim_iocdisable_cleanup(itnim); - bfa_itnim_offline_cb(itnim); - break; - - case BFA_ITNIM_SM_SLER: - break; - - default: - bfa_sm_fault(itnim->bfa, event); - } -} - -/** - * Deleting itnim. Waiting for active IO cleanup. - */ -static void -bfa_itnim_sm_cleanup_delete(struct bfa_itnim_s *itnim, - enum bfa_itnim_event event) -{ - bfa_trc(itnim->bfa, itnim->rport->rport_tag); - bfa_trc(itnim->bfa, event); - - switch (event) { - case BFA_ITNIM_SM_CLEANUP: - if (bfa_itnim_send_fwdelete(itnim)) - bfa_sm_set_state(itnim, bfa_itnim_sm_deleting); - else - bfa_sm_set_state(itnim, bfa_itnim_sm_deleting_qfull); - break; - - case BFA_ITNIM_SM_HWFAIL: - bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable); - bfa_itnim_iocdisable_cleanup(itnim); - break; - - default: - bfa_sm_fault(itnim->bfa, event); - } -} - -/** - * Rport offline. Fimrware itnim is being deleted - awaiting f/w response. - */ -static void -bfa_itnim_sm_fwdelete(struct bfa_itnim_s *itnim, enum bfa_itnim_event event) -{ - bfa_trc(itnim->bfa, itnim->rport->rport_tag); - bfa_trc(itnim->bfa, event); - - switch (event) { - case BFA_ITNIM_SM_FWRSP: - bfa_sm_set_state(itnim, bfa_itnim_sm_offline); - bfa_itnim_offline_cb(itnim); - break; - - case BFA_ITNIM_SM_DELETE: - bfa_sm_set_state(itnim, bfa_itnim_sm_deleting); - break; - - case BFA_ITNIM_SM_HWFAIL: - bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable); - bfa_itnim_offline_cb(itnim); - break; - - default: - bfa_sm_fault(itnim->bfa, event); - } -} - -static void -bfa_itnim_sm_fwdelete_qfull(struct bfa_itnim_s *itnim, - enum bfa_itnim_event event) -{ - bfa_trc(itnim->bfa, itnim->rport->rport_tag); - bfa_trc(itnim->bfa, event); - - switch (event) { - case BFA_ITNIM_SM_QRESUME: - bfa_sm_set_state(itnim, bfa_itnim_sm_fwdelete); - bfa_itnim_send_fwdelete(itnim); - break; - - case BFA_ITNIM_SM_DELETE: - bfa_sm_set_state(itnim, bfa_itnim_sm_deleting_qfull); - break; - - case BFA_ITNIM_SM_HWFAIL: - bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable); - bfa_reqq_wcancel(&itnim->reqq_wait); - bfa_itnim_offline_cb(itnim); - break; - - default: - bfa_sm_fault(itnim->bfa, event); - } -} - -/** - * Offline state. - */ -static void -bfa_itnim_sm_offline(struct bfa_itnim_s *itnim, enum bfa_itnim_event event) -{ - bfa_trc(itnim->bfa, itnim->rport->rport_tag); - bfa_trc(itnim->bfa, event); - - switch (event) { - case BFA_ITNIM_SM_DELETE: - bfa_sm_set_state(itnim, bfa_itnim_sm_uninit); - bfa_itnim_iotov_delete(itnim); - bfa_fcpim_delitn(itnim); - break; - - case BFA_ITNIM_SM_ONLINE: - if (bfa_itnim_send_fwcreate(itnim)) - bfa_sm_set_state(itnim, bfa_itnim_sm_fwcreate); - else - bfa_sm_set_state(itnim, bfa_itnim_sm_fwcreate_qfull); - break; - - case BFA_ITNIM_SM_HWFAIL: - bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable); - break; - - default: - bfa_sm_fault(itnim->bfa, event); - } -} - -/** - * IOC h/w failed state. - */ -static void -bfa_itnim_sm_iocdisable(struct bfa_itnim_s *itnim, - enum bfa_itnim_event event) -{ - bfa_trc(itnim->bfa, itnim->rport->rport_tag); - bfa_trc(itnim->bfa, event); - - switch (event) { - case BFA_ITNIM_SM_DELETE: - bfa_sm_set_state(itnim, bfa_itnim_sm_uninit); - bfa_itnim_iotov_delete(itnim); - bfa_fcpim_delitn(itnim); - break; - - case BFA_ITNIM_SM_OFFLINE: - bfa_itnim_offline_cb(itnim); - break; - - case BFA_ITNIM_SM_ONLINE: - if (bfa_itnim_send_fwcreate(itnim)) - bfa_sm_set_state(itnim, bfa_itnim_sm_fwcreate); - else - bfa_sm_set_state(itnim, bfa_itnim_sm_fwcreate_qfull); - break; - - case BFA_ITNIM_SM_HWFAIL: - break; - - default: - bfa_sm_fault(itnim->bfa, event); - } -} - -/** - * Itnim is deleted, waiting for firmware response to delete. - */ -static void -bfa_itnim_sm_deleting(struct bfa_itnim_s *itnim, enum bfa_itnim_event event) -{ - bfa_trc(itnim->bfa, itnim->rport->rport_tag); - bfa_trc(itnim->bfa, event); - - switch (event) { - case BFA_ITNIM_SM_FWRSP: - case BFA_ITNIM_SM_HWFAIL: - bfa_sm_set_state(itnim, bfa_itnim_sm_uninit); - bfa_fcpim_delitn(itnim); - break; - - default: - bfa_sm_fault(itnim->bfa, event); - } -} - -static void -bfa_itnim_sm_deleting_qfull(struct bfa_itnim_s *itnim, - enum bfa_itnim_event event) -{ - bfa_trc(itnim->bfa, itnim->rport->rport_tag); - bfa_trc(itnim->bfa, event); - - switch (event) { - case BFA_ITNIM_SM_QRESUME: - bfa_sm_set_state(itnim, bfa_itnim_sm_deleting); - bfa_itnim_send_fwdelete(itnim); - break; - - case BFA_ITNIM_SM_HWFAIL: - bfa_sm_set_state(itnim, bfa_itnim_sm_uninit); - bfa_reqq_wcancel(&itnim->reqq_wait); - bfa_fcpim_delitn(itnim); - break; - - default: - bfa_sm_fault(itnim->bfa, event); - } -} - - - -/** - * bfa_itnim_private - */ - -/** - * Initiate cleanup of all IOs on an IOC failure. - */ -static void -bfa_itnim_iocdisable_cleanup(struct bfa_itnim_s *itnim) -{ - struct bfa_tskim_s *tskim; - struct bfa_ioim_s *ioim; - struct list_head *qe, *qen; - - list_for_each_safe(qe, qen, &itnim->tsk_q) { - tskim = (struct bfa_tskim_s *) qe; - bfa_tskim_iocdisable(tskim); - } - - list_for_each_safe(qe, qen, &itnim->io_q) { - ioim = (struct bfa_ioim_s *) qe; - bfa_ioim_iocdisable(ioim); - } - - /** - * For IO request in pending queue, we pretend an early timeout. - */ - list_for_each_safe(qe, qen, &itnim->pending_q) { - ioim = (struct bfa_ioim_s *) qe; - bfa_ioim_tov(ioim); - } - - list_for_each_safe(qe, qen, &itnim->io_cleanup_q) { - ioim = (struct bfa_ioim_s *) qe; - bfa_ioim_iocdisable(ioim); - } -} - -/** - * IO cleanup completion - */ -static void -bfa_itnim_cleanp_comp(void *itnim_cbarg) -{ - struct bfa_itnim_s *itnim = itnim_cbarg; - - bfa_stats(itnim, cleanup_comps); - bfa_sm_send_event(itnim, BFA_ITNIM_SM_CLEANUP); -} - -/** - * Initiate cleanup of all IOs. - */ -static void -bfa_itnim_cleanup(struct bfa_itnim_s *itnim) -{ - struct bfa_ioim_s *ioim; - struct bfa_tskim_s *tskim; - struct list_head *qe, *qen; - - bfa_wc_init(&itnim->wc, bfa_itnim_cleanp_comp, itnim); - - list_for_each_safe(qe, qen, &itnim->io_q) { - ioim = (struct bfa_ioim_s *) qe; - - /** - * Move IO to a cleanup queue from active queue so that a later - * TM will not pickup this IO. - */ - list_del(&ioim->qe); - list_add_tail(&ioim->qe, &itnim->io_cleanup_q); - - bfa_wc_up(&itnim->wc); - bfa_ioim_cleanup(ioim); - } - - list_for_each_safe(qe, qen, &itnim->tsk_q) { - tskim = (struct bfa_tskim_s *) qe; - bfa_wc_up(&itnim->wc); - bfa_tskim_cleanup(tskim); - } - - bfa_wc_wait(&itnim->wc); -} - -static void -__bfa_cb_itnim_online(void *cbarg, bfa_boolean_t complete) -{ - struct bfa_itnim_s *itnim = cbarg; - - if (complete) - bfa_cb_itnim_online(itnim->ditn); -} - -static void -__bfa_cb_itnim_offline(void *cbarg, bfa_boolean_t complete) -{ - struct bfa_itnim_s *itnim = cbarg; - - if (complete) - bfa_cb_itnim_offline(itnim->ditn); -} - -static void -__bfa_cb_itnim_sler(void *cbarg, bfa_boolean_t complete) -{ - struct bfa_itnim_s *itnim = cbarg; - - if (complete) - bfa_cb_itnim_sler(itnim->ditn); -} - -/** - * Call to resume any I/O requests waiting for room in request queue. - */ -static void -bfa_itnim_qresume(void *cbarg) -{ - struct bfa_itnim_s *itnim = cbarg; - - bfa_sm_send_event(itnim, BFA_ITNIM_SM_QRESUME); -} - - - - -/** - * bfa_itnim_public - */ - -void -bfa_itnim_iodone(struct bfa_itnim_s *itnim) -{ - bfa_wc_down(&itnim->wc); -} - -void -bfa_itnim_tskdone(struct bfa_itnim_s *itnim) -{ - bfa_wc_down(&itnim->wc); -} - -void -bfa_itnim_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len, - u32 *dm_len) -{ - /** - * ITN memory - */ - *km_len += cfg->fwcfg.num_rports * sizeof(struct bfa_itnim_s); -} - -void -bfa_itnim_attach(struct bfa_fcpim_mod_s *fcpim, struct bfa_meminfo_s *minfo) -{ - struct bfa_s *bfa = fcpim->bfa; - struct bfa_itnim_s *itnim; - int i; - - INIT_LIST_HEAD(&fcpim->itnim_q); - - itnim = (struct bfa_itnim_s *) bfa_meminfo_kva(minfo); - fcpim->itnim_arr = itnim; - - for (i = 0; i < fcpim->num_itnims; i++, itnim++) { - bfa_os_memset(itnim, 0, sizeof(struct bfa_itnim_s)); - itnim->bfa = bfa; - itnim->fcpim = fcpim; - itnim->reqq = BFA_REQQ_QOS_LO; - itnim->rport = BFA_RPORT_FROM_TAG(bfa, i); - itnim->iotov_active = BFA_FALSE; - bfa_reqq_winit(&itnim->reqq_wait, bfa_itnim_qresume, itnim); - - INIT_LIST_HEAD(&itnim->io_q); - INIT_LIST_HEAD(&itnim->io_cleanup_q); - INIT_LIST_HEAD(&itnim->pending_q); - INIT_LIST_HEAD(&itnim->tsk_q); - INIT_LIST_HEAD(&itnim->delay_comp_q); - bfa_sm_set_state(itnim, bfa_itnim_sm_uninit); - } - - bfa_meminfo_kva(minfo) = (u8 *) itnim; -} - -void -bfa_itnim_iocdisable(struct bfa_itnim_s *itnim) -{ - bfa_stats(itnim, ioc_disabled); - bfa_sm_send_event(itnim, BFA_ITNIM_SM_HWFAIL); -} - -static bfa_boolean_t -bfa_itnim_send_fwcreate(struct bfa_itnim_s *itnim) -{ - struct bfi_itnim_create_req_s *m; - - itnim->msg_no++; - - /** - * check for room in queue to send request now - */ - m = bfa_reqq_next(itnim->bfa, itnim->reqq); - if (!m) { - bfa_reqq_wait(itnim->bfa, itnim->reqq, &itnim->reqq_wait); - return BFA_FALSE; - } - - bfi_h2i_set(m->mh, BFI_MC_ITNIM, BFI_ITNIM_H2I_CREATE_REQ, - bfa_lpuid(itnim->bfa)); - m->fw_handle = itnim->rport->fw_handle; - m->class = FC_CLASS_3; - m->seq_rec = itnim->seq_rec; - m->msg_no = itnim->msg_no; - - /** - * queue I/O message to firmware - */ - bfa_reqq_produce(itnim->bfa, itnim->reqq); - return BFA_TRUE; -} - -static bfa_boolean_t -bfa_itnim_send_fwdelete(struct bfa_itnim_s *itnim) -{ - struct bfi_itnim_delete_req_s *m; - - /** - * check for room in queue to send request now - */ - m = bfa_reqq_next(itnim->bfa, itnim->reqq); - if (!m) { - bfa_reqq_wait(itnim->bfa, itnim->reqq, &itnim->reqq_wait); - return BFA_FALSE; - } - - bfi_h2i_set(m->mh, BFI_MC_ITNIM, BFI_ITNIM_H2I_DELETE_REQ, - bfa_lpuid(itnim->bfa)); - m->fw_handle = itnim->rport->fw_handle; - - /** - * queue I/O message to firmware - */ - bfa_reqq_produce(itnim->bfa, itnim->reqq); - return BFA_TRUE; -} - -/** - * Cleanup all pending failed inflight requests. - */ -static void -bfa_itnim_delayed_comp(struct bfa_itnim_s *itnim, bfa_boolean_t iotov) -{ - struct bfa_ioim_s *ioim; - struct list_head *qe, *qen; - - list_for_each_safe(qe, qen, &itnim->delay_comp_q) { - ioim = (struct bfa_ioim_s *)qe; - bfa_ioim_delayed_comp(ioim, iotov); - } -} - -/** - * Start all pending IO requests. - */ -static void -bfa_itnim_iotov_online(struct bfa_itnim_s *itnim) -{ - struct bfa_ioim_s *ioim; - - bfa_itnim_iotov_stop(itnim); - - /** - * Abort all inflight IO requests in the queue - */ - bfa_itnim_delayed_comp(itnim, BFA_FALSE); - - /** - * Start all pending IO requests. - */ - while (!list_empty(&itnim->pending_q)) { - bfa_q_deq(&itnim->pending_q, &ioim); - list_add_tail(&ioim->qe, &itnim->io_q); - bfa_ioim_start(ioim); - } -} - -/** - * Fail all pending IO requests - */ -static void -bfa_itnim_iotov_cleanup(struct bfa_itnim_s *itnim) -{ - struct bfa_ioim_s *ioim; - - /** - * Fail all inflight IO requests in the queue - */ - bfa_itnim_delayed_comp(itnim, BFA_TRUE); - - /** - * Fail any pending IO requests. - */ - while (!list_empty(&itnim->pending_q)) { - bfa_q_deq(&itnim->pending_q, &ioim); - list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q); - bfa_ioim_tov(ioim); - } -} - -/** - * IO TOV timer callback. Fail any pending IO requests. - */ -static void -bfa_itnim_iotov(void *itnim_arg) -{ - struct bfa_itnim_s *itnim = itnim_arg; - - itnim->iotov_active = BFA_FALSE; - - bfa_cb_itnim_tov_begin(itnim->ditn); - bfa_itnim_iotov_cleanup(itnim); - bfa_cb_itnim_tov(itnim->ditn); -} - -/** - * Start IO TOV timer for failing back pending IO requests in offline state. - */ -static void -bfa_itnim_iotov_start(struct bfa_itnim_s *itnim) -{ - if (itnim->fcpim->path_tov > 0) { - - itnim->iotov_active = BFA_TRUE; - bfa_assert(bfa_itnim_hold_io(itnim)); - bfa_timer_start(itnim->bfa, &itnim->timer, - bfa_itnim_iotov, itnim, itnim->fcpim->path_tov); - } -} - -/** - * Stop IO TOV timer. - */ -static void -bfa_itnim_iotov_stop(struct bfa_itnim_s *itnim) -{ - if (itnim->iotov_active) { - itnim->iotov_active = BFA_FALSE; - bfa_timer_stop(&itnim->timer); - } -} - -/** - * Stop IO TOV timer. - */ -static void -bfa_itnim_iotov_delete(struct bfa_itnim_s *itnim) -{ - bfa_boolean_t pathtov_active = BFA_FALSE; - - if (itnim->iotov_active) - pathtov_active = BFA_TRUE; - - bfa_itnim_iotov_stop(itnim); - if (pathtov_active) - bfa_cb_itnim_tov_begin(itnim->ditn); - bfa_itnim_iotov_cleanup(itnim); - if (pathtov_active) - bfa_cb_itnim_tov(itnim->ditn); -} - - - -/** - * bfa_itnim_public - */ - -/** - * Itnim interrupt processing. - */ -void -bfa_itnim_isr(struct bfa_s *bfa, struct bfi_msg_s *m) -{ - struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); - union bfi_itnim_i2h_msg_u msg; - struct bfa_itnim_s *itnim; - - bfa_trc(bfa, m->mhdr.msg_id); - - msg.msg = m; - - switch (m->mhdr.msg_id) { - case BFI_ITNIM_I2H_CREATE_RSP: - itnim = BFA_ITNIM_FROM_TAG(fcpim, - msg.create_rsp->bfa_handle); - bfa_assert(msg.create_rsp->status == BFA_STATUS_OK); - bfa_stats(itnim, create_comps); - bfa_sm_send_event(itnim, BFA_ITNIM_SM_FWRSP); - break; - - case BFI_ITNIM_I2H_DELETE_RSP: - itnim = BFA_ITNIM_FROM_TAG(fcpim, - msg.delete_rsp->bfa_handle); - bfa_assert(msg.delete_rsp->status == BFA_STATUS_OK); - bfa_stats(itnim, delete_comps); - bfa_sm_send_event(itnim, BFA_ITNIM_SM_FWRSP); - break; - - case BFI_ITNIM_I2H_SLER_EVENT: - itnim = BFA_ITNIM_FROM_TAG(fcpim, - msg.sler_event->bfa_handle); - bfa_stats(itnim, sler_events); - bfa_sm_send_event(itnim, BFA_ITNIM_SM_SLER); - break; - - default: - bfa_trc(bfa, m->mhdr.msg_id); - bfa_assert(0); - } -} - - - -/** - * bfa_itnim_api - */ - -struct bfa_itnim_s * -bfa_itnim_create(struct bfa_s *bfa, struct bfa_rport_s *rport, void *ditn) -{ - struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); - struct bfa_itnim_s *itnim; - - itnim = BFA_ITNIM_FROM_TAG(fcpim, rport->rport_tag); - bfa_assert(itnim->rport == rport); - - itnim->ditn = ditn; - - bfa_stats(itnim, creates); - bfa_sm_send_event(itnim, BFA_ITNIM_SM_CREATE); - - return itnim; -} - -void -bfa_itnim_delete(struct bfa_itnim_s *itnim) -{ - bfa_stats(itnim, deletes); - bfa_sm_send_event(itnim, BFA_ITNIM_SM_DELETE); -} - -void -bfa_itnim_online(struct bfa_itnim_s *itnim, bfa_boolean_t seq_rec) -{ - itnim->seq_rec = seq_rec; - bfa_stats(itnim, onlines); - bfa_sm_send_event(itnim, BFA_ITNIM_SM_ONLINE); -} - -void -bfa_itnim_offline(struct bfa_itnim_s *itnim) -{ - bfa_stats(itnim, offlines); - bfa_sm_send_event(itnim, BFA_ITNIM_SM_OFFLINE); -} - -/** - * Return true if itnim is considered offline for holding off IO request. - * IO is not held if itnim is being deleted. - */ -bfa_boolean_t -bfa_itnim_hold_io(struct bfa_itnim_s *itnim) -{ - return - itnim->fcpim->path_tov && itnim->iotov_active && - (bfa_sm_cmp_state(itnim, bfa_itnim_sm_fwcreate) || - bfa_sm_cmp_state(itnim, bfa_itnim_sm_sler) || - bfa_sm_cmp_state(itnim, bfa_itnim_sm_cleanup_offline) || - bfa_sm_cmp_state(itnim, bfa_itnim_sm_fwdelete) || - bfa_sm_cmp_state(itnim, bfa_itnim_sm_offline) || - bfa_sm_cmp_state(itnim, bfa_itnim_sm_iocdisable)) - ; -} - -void -bfa_itnim_get_stats(struct bfa_itnim_s *itnim, - struct bfa_itnim_hal_stats_s *stats) -{ - *stats = itnim->stats; -} - -void -bfa_itnim_clear_stats(struct bfa_itnim_s *itnim) -{ - bfa_os_memset(&itnim->stats, 0, sizeof(itnim->stats)); -} - - diff --git a/drivers/scsi/bfa/bfa_log.c b/drivers/scsi/bfa/bfa_log.c deleted file mode 100644 index e7514016c9c6..000000000000 --- a/drivers/scsi/bfa/bfa_log.c +++ /dev/null @@ -1,346 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/** - * bfa_log.c BFA log library - */ - -#include <bfa_os_inc.h> -#include <cs/bfa_log.h> - -/* - * global log info structure - */ -struct bfa_log_info_s { - u32 start_idx; /* start index for a module */ - u32 total_count; /* total count for a module */ - enum bfa_log_severity level; /* global log level */ - bfa_log_cb_t cbfn; /* callback function */ -}; - -static struct bfa_log_info_s bfa_log_info[BFA_LOG_MODULE_ID_MAX + 1]; -static u32 bfa_log_msg_total_count; -static int bfa_log_initialized; - -static char *bfa_log_severity[] = - { "[none]", "[critical]", "[error]", "[warn]", "[info]", "" }; - -/** - * BFA log library initialization - * - * The log library initialization includes the following, - * - set log instance name and callback function - * - read the message array generated from xml files - * - calculate start index for each module - * - calculate message count for each module - * - perform error checking - * - * @param[in] log_mod - log module info - * @param[in] instance_name - instance name - * @param[in] cbfn - callback function - * - * It return 0 on success, or -1 on failure - */ -int -bfa_log_init(struct bfa_log_mod_s *log_mod, char *instance_name, - bfa_log_cb_t cbfn) -{ - struct bfa_log_msgdef_s *msg; - u32 pre_mod_id = 0; - u32 cur_mod_id = 0; - u32 i, pre_idx, idx, msg_id; - - /* - * set instance name - */ - if (log_mod) { - strncpy(log_mod->instance_info, instance_name, - sizeof(log_mod->instance_info)); - log_mod->cbfn = cbfn; - for (i = 0; i <= BFA_LOG_MODULE_ID_MAX; i++) - log_mod->log_level[i] = BFA_LOG_WARNING; - } - - if (bfa_log_initialized) - return 0; - - for (i = 0; i <= BFA_LOG_MODULE_ID_MAX; i++) { - bfa_log_info[i].start_idx = 0; - bfa_log_info[i].total_count = 0; - bfa_log_info[i].level = BFA_LOG_WARNING; - bfa_log_info[i].cbfn = cbfn; - } - - pre_idx = 0; - idx = 0; - msg = bfa_log_msg_array; - msg_id = BFA_LOG_GET_MSG_ID(msg); - pre_mod_id = BFA_LOG_GET_MOD_ID(msg_id); - while (msg_id != 0) { - cur_mod_id = BFA_LOG_GET_MOD_ID(msg_id); - - if (cur_mod_id > BFA_LOG_MODULE_ID_MAX) { - cbfn(log_mod, msg_id, - "%s%s log: module id %u out of range\n", - BFA_LOG_CAT_NAME, - bfa_log_severity[BFA_LOG_ERROR], - cur_mod_id); - return -1; - } - - if (pre_mod_id > BFA_LOG_MODULE_ID_MAX) { - cbfn(log_mod, msg_id, - "%s%s log: module id %u out of range\n", - BFA_LOG_CAT_NAME, - bfa_log_severity[BFA_LOG_ERROR], - pre_mod_id); - return -1; - } - - if (cur_mod_id != pre_mod_id) { - bfa_log_info[pre_mod_id].start_idx = pre_idx; - bfa_log_info[pre_mod_id].total_count = idx - pre_idx; - pre_mod_id = cur_mod_id; - pre_idx = idx; - } - - idx++; - msg++; - msg_id = BFA_LOG_GET_MSG_ID(msg); - } - - bfa_log_info[cur_mod_id].start_idx = pre_idx; - bfa_log_info[cur_mod_id].total_count = idx - pre_idx; - bfa_log_msg_total_count = idx; - - cbfn(log_mod, msg_id, "%s%s log: init OK, msg total count %u\n", - BFA_LOG_CAT_NAME, - bfa_log_severity[BFA_LOG_INFO], bfa_log_msg_total_count); - - bfa_log_initialized = 1; - - return 0; -} - -/** - * BFA log set log level for a module - * - * @param[in] log_mod - log module info - * @param[in] mod_id - module id - * @param[in] log_level - log severity level - * - * It return BFA_STATUS_OK on success, or > 0 on failure - */ -bfa_status_t -bfa_log_set_level(struct bfa_log_mod_s *log_mod, int mod_id, - enum bfa_log_severity log_level) -{ - if (mod_id <= BFA_LOG_UNUSED_ID || mod_id > BFA_LOG_MODULE_ID_MAX) - return BFA_STATUS_EINVAL; - - if (log_level <= BFA_LOG_INVALID || log_level > BFA_LOG_LEVEL_MAX) - return BFA_STATUS_EINVAL; - - if (log_mod) - log_mod->log_level[mod_id] = log_level; - else - bfa_log_info[mod_id].level = log_level; - - return BFA_STATUS_OK; -} - -/** - * BFA log set log level for all modules - * - * @param[in] log_mod - log module info - * @param[in] log_level - log severity level - * - * It return BFA_STATUS_OK on success, or > 0 on failure - */ -bfa_status_t -bfa_log_set_level_all(struct bfa_log_mod_s *log_mod, - enum bfa_log_severity log_level) -{ - int mod_id = BFA_LOG_UNUSED_ID + 1; - - if (log_level <= BFA_LOG_INVALID || log_level > BFA_LOG_LEVEL_MAX) - return BFA_STATUS_EINVAL; - - if (log_mod) { - for (; mod_id <= BFA_LOG_MODULE_ID_MAX; mod_id++) - log_mod->log_level[mod_id] = log_level; - } else { - for (; mod_id <= BFA_LOG_MODULE_ID_MAX; mod_id++) - bfa_log_info[mod_id].level = log_level; - } - - return BFA_STATUS_OK; -} - -/** - * BFA log set log level for all aen sub-modules - * - * @param[in] log_mod - log module info - * @param[in] log_level - log severity level - * - * It return BFA_STATUS_OK on success, or > 0 on failure - */ -bfa_status_t -bfa_log_set_level_aen(struct bfa_log_mod_s *log_mod, - enum bfa_log_severity log_level) -{ - int mod_id = BFA_LOG_AEN_MIN + 1; - - if (log_mod) { - for (; mod_id <= BFA_LOG_AEN_MAX; mod_id++) - log_mod->log_level[mod_id] = log_level; - } else { - for (; mod_id <= BFA_LOG_AEN_MAX; mod_id++) - bfa_log_info[mod_id].level = log_level; - } - - return BFA_STATUS_OK; -} - -/** - * BFA log get log level for a module - * - * @param[in] log_mod - log module info - * @param[in] mod_id - module id - * - * It returns log level or -1 on error - */ -enum bfa_log_severity -bfa_log_get_level(struct bfa_log_mod_s *log_mod, int mod_id) -{ - if (mod_id <= BFA_LOG_UNUSED_ID || mod_id > BFA_LOG_MODULE_ID_MAX) - return BFA_LOG_INVALID; - - if (log_mod) - return log_mod->log_level[mod_id]; - else - return bfa_log_info[mod_id].level; -} - -enum bfa_log_severity -bfa_log_get_msg_level(struct bfa_log_mod_s *log_mod, u32 msg_id) -{ - struct bfa_log_msgdef_s *msg; - u32 mod = BFA_LOG_GET_MOD_ID(msg_id); - u32 idx = BFA_LOG_GET_MSG_IDX(msg_id) - 1; - - if (!bfa_log_initialized) - return BFA_LOG_INVALID; - - if (mod > BFA_LOG_MODULE_ID_MAX) - return BFA_LOG_INVALID; - - if (idx >= bfa_log_info[mod].total_count) { - bfa_log_info[mod].cbfn(log_mod, msg_id, - "%s%s log: inconsistent idx %u vs. total count %u\n", - BFA_LOG_CAT_NAME, bfa_log_severity[BFA_LOG_ERROR], idx, - bfa_log_info[mod].total_count); - return BFA_LOG_INVALID; - } - - msg = bfa_log_msg_array + bfa_log_info[mod].start_idx + idx; - if (msg_id != BFA_LOG_GET_MSG_ID(msg)) { - bfa_log_info[mod].cbfn(log_mod, msg_id, - "%s%s log: inconsistent msg id %u array msg id %u\n", - BFA_LOG_CAT_NAME, bfa_log_severity[BFA_LOG_ERROR], - msg_id, BFA_LOG_GET_MSG_ID(msg)); - return BFA_LOG_INVALID; - } - - return BFA_LOG_GET_SEVERITY(msg); -} - -/** - * BFA log message handling - * - * BFA log message handling finds the message based on message id and prints - * out the message based on its format and arguments. It also does prefix - * the severity etc. - * - * @param[in] log_mod - log module info - * @param[in] msg_id - message id - * @param[in] ... - message arguments - * - * It return 0 on success, or -1 on errors - */ -int -bfa_log(struct bfa_log_mod_s *log_mod, u32 msg_id, ...) -{ - va_list ap; - char buf[256]; - struct bfa_log_msgdef_s *msg; - int log_level; - u32 mod = BFA_LOG_GET_MOD_ID(msg_id); - u32 idx = BFA_LOG_GET_MSG_IDX(msg_id) - 1; - - if (!bfa_log_initialized) - return -1; - - if (mod > BFA_LOG_MODULE_ID_MAX) - return -1; - - if (idx >= bfa_log_info[mod].total_count) { - bfa_log_info[mod]. - cbfn - (log_mod, msg_id, - "%s%s log: inconsistent idx %u vs. total count %u\n", - BFA_LOG_CAT_NAME, bfa_log_severity[BFA_LOG_ERROR], idx, - bfa_log_info[mod].total_count); - return -1; - } - - msg = bfa_log_msg_array + bfa_log_info[mod].start_idx + idx; - if (msg_id != BFA_LOG_GET_MSG_ID(msg)) { - bfa_log_info[mod]. - cbfn - (log_mod, msg_id, - "%s%s log: inconsistent msg id %u array msg id %u\n", - BFA_LOG_CAT_NAME, bfa_log_severity[BFA_LOG_ERROR], - msg_id, BFA_LOG_GET_MSG_ID(msg)); - return -1; - } - - log_level = log_mod ? log_mod->log_level[mod] : bfa_log_info[mod].level; - if ((BFA_LOG_GET_SEVERITY(msg) > log_level) && - (msg->attributes != BFA_LOG_ATTR_NONE)) - return 0; - - va_start(ap, msg_id); - bfa_os_vsprintf(buf, BFA_LOG_GET_MSG_FMT_STRING(msg), ap); - va_end(ap); - - if (log_mod) - log_mod->cbfn(log_mod, msg_id, "%s[%s]%s%s %s: %s\n", - BFA_LOG_CAT_NAME, log_mod->instance_info, - bfa_log_severity[BFA_LOG_GET_SEVERITY(msg)], - (msg->attributes & BFA_LOG_ATTR_AUDIT) - ? " (audit) " : "", msg->msg_value, buf); - else - bfa_log_info[mod].cbfn(log_mod, msg_id, "%s%s%s %s: %s\n", - BFA_LOG_CAT_NAME, - bfa_log_severity[BFA_LOG_GET_SEVERITY(msg)], - (msg->attributes & BFA_LOG_ATTR_AUDIT) ? - " (audit) " : "", msg->msg_value, buf); - - return 0; -} - diff --git a/drivers/scsi/bfa/bfa_log_module.c b/drivers/scsi/bfa/bfa_log_module.c deleted file mode 100644 index cf577ef7cb97..000000000000 --- a/drivers/scsi/bfa/bfa_log_module.c +++ /dev/null @@ -1,537 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#include <cs/bfa_log.h> -#include <aen/bfa_aen_adapter.h> -#include <aen/bfa_aen_audit.h> -#include <aen/bfa_aen_ethport.h> -#include <aen/bfa_aen_ioc.h> -#include <aen/bfa_aen_itnim.h> -#include <aen/bfa_aen_lport.h> -#include <aen/bfa_aen_port.h> -#include <aen/bfa_aen_rport.h> -#include <log/bfa_log_fcs.h> -#include <log/bfa_log_hal.h> -#include <log/bfa_log_linux.h> -#include <log/bfa_log_wdrv.h> - -struct bfa_log_msgdef_s bfa_log_msg_array[] = { - - -/* messages define for BFA_AEN_CAT_ADAPTER Module */ -{BFA_AEN_ADAPTER_ADD, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, - "BFA_AEN_ADAPTER_ADD", - "New adapter found: SN = %s, base port WWN = %s.", - ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2}, - -{BFA_AEN_ADAPTER_REMOVE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, - BFA_LOG_WARNING, "BFA_AEN_ADAPTER_REMOVE", - "Adapter removed: SN = %s.", - ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, - - - - -/* messages define for BFA_AEN_CAT_AUDIT Module */ -{BFA_AEN_AUDIT_AUTH_ENABLE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, - BFA_LOG_INFO, "BFA_AEN_AUDIT_AUTH_ENABLE", - "Authentication enabled for base port: WWN = %s.", - ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, - -{BFA_AEN_AUDIT_AUTH_DISABLE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, - BFA_LOG_INFO, "BFA_AEN_AUDIT_AUTH_DISABLE", - "Authentication disabled for base port: WWN = %s.", - ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, - - - - -/* messages define for BFA_AEN_CAT_ETHPORT Module */ -{BFA_AEN_ETHPORT_LINKUP, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, - "BFA_AEN_ETHPORT_LINKUP", - "Base port ethernet linkup: mac = %s.", - ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, - -{BFA_AEN_ETHPORT_LINKDOWN, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, - "BFA_AEN_ETHPORT_LINKDOWN", - "Base port ethernet linkdown: mac = %s.", - ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, - -{BFA_AEN_ETHPORT_ENABLE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, - "BFA_AEN_ETHPORT_ENABLE", - "Base port ethernet interface enabled: mac = %s.", - ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, - -{BFA_AEN_ETHPORT_DISABLE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, - "BFA_AEN_ETHPORT_DISABLE", - "Base port ethernet interface disabled: mac = %s.", - ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, - - - - -/* messages define for BFA_AEN_CAT_IOC Module */ -{BFA_AEN_IOC_HBGOOD, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, - "BFA_AEN_IOC_HBGOOD", - "Heart Beat of IOC %d is good.", - ((BFA_LOG_D << BFA_LOG_ARG0) | 0), 1}, - -{BFA_AEN_IOC_HBFAIL, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_CRITICAL, - "BFA_AEN_IOC_HBFAIL", - "Heart Beat of IOC %d has failed.", - ((BFA_LOG_D << BFA_LOG_ARG0) | 0), 1}, - -{BFA_AEN_IOC_ENABLE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, - "BFA_AEN_IOC_ENABLE", - "IOC %d is enabled.", - ((BFA_LOG_D << BFA_LOG_ARG0) | 0), 1}, - -{BFA_AEN_IOC_DISABLE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, - "BFA_AEN_IOC_DISABLE", - "IOC %d is disabled.", - ((BFA_LOG_D << BFA_LOG_ARG0) | 0), 1}, - -{BFA_AEN_IOC_FWMISMATCH, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, - BFA_LOG_CRITICAL, "BFA_AEN_IOC_FWMISMATCH", - "Running firmware version is incompatible with the driver version.", - (0), 0}, - -{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}, - - - - -/* messages define for BFA_AEN_CAT_ITNIM Module */ -{BFA_AEN_ITNIM_ONLINE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, - "BFA_AEN_ITNIM_ONLINE", - "Target (WWN = %s) is online for initiator (WWN = %s).", - ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2}, - -{BFA_AEN_ITNIM_OFFLINE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, - "BFA_AEN_ITNIM_OFFLINE", - "Target (WWN = %s) offlined by initiator (WWN = %s).", - ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2}, - -{BFA_AEN_ITNIM_DISCONNECT, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, - BFA_LOG_ERROR, "BFA_AEN_ITNIM_DISCONNECT", - "Target (WWN = %s) connectivity lost for initiator (WWN = %s).", - ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2}, - - - - -/* messages define for BFA_AEN_CAT_LPORT Module */ -{BFA_AEN_LPORT_NEW, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, - "BFA_AEN_LPORT_NEW", - "New logical port created: WWN = %s, Role = %s.", - ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2}, - -{BFA_AEN_LPORT_DELETE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, - "BFA_AEN_LPORT_DELETE", - "Logical port deleted: WWN = %s, Role = %s.", - ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2}, - -{BFA_AEN_LPORT_ONLINE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, - "BFA_AEN_LPORT_ONLINE", - "Logical port online: WWN = %s, Role = %s.", - ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2}, - -{BFA_AEN_LPORT_OFFLINE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, - "BFA_AEN_LPORT_OFFLINE", - "Logical port taken offline: WWN = %s, Role = %s.", - ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2}, - -{BFA_AEN_LPORT_DISCONNECT, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, - BFA_LOG_ERROR, "BFA_AEN_LPORT_DISCONNECT", - "Logical port lost fabric connectivity: WWN = %s, Role = %s.", - ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2}, - -{BFA_AEN_LPORT_NEW_PROP, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, - "BFA_AEN_LPORT_NEW_PROP", - "New virtual port created using proprietary interface: WWN = %s, Role = %s.", - ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2}, - -{BFA_AEN_LPORT_DELETE_PROP, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, - BFA_LOG_INFO, "BFA_AEN_LPORT_DELETE_PROP", - "Virtual port deleted using proprietary interface: WWN = %s, Role = %s.", - ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2}, - -{BFA_AEN_LPORT_NEW_STANDARD, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, - BFA_LOG_INFO, "BFA_AEN_LPORT_NEW_STANDARD", - "New virtual port created using standard interface: WWN = %s, Role = %s.", - ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2}, - -{BFA_AEN_LPORT_DELETE_STANDARD, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, - BFA_LOG_INFO, "BFA_AEN_LPORT_DELETE_STANDARD", - "Virtual port deleted using standard interface: WWN = %s, Role = %s.", - ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2}, - -{BFA_AEN_LPORT_NPIV_DUP_WWN, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, - BFA_LOG_WARNING, "BFA_AEN_LPORT_NPIV_DUP_WWN", - "Virtual port login failed. Duplicate WWN = %s reported by fabric.", - ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, - -{BFA_AEN_LPORT_NPIV_FABRIC_MAX, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, - BFA_LOG_WARNING, "BFA_AEN_LPORT_NPIV_FABRIC_MAX", - "Virtual port (WWN = %s) login failed. Max NPIV ports already exist in" - " fabric/fport.", - ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, - -{BFA_AEN_LPORT_NPIV_UNKNOWN, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, - BFA_LOG_WARNING, "BFA_AEN_LPORT_NPIV_UNKNOWN", - "Virtual port (WWN = %s) login failed.", - ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, - - - - -/* messages define for BFA_AEN_CAT_PORT Module */ -{BFA_AEN_PORT_ONLINE, BFA_LOG_ATTR_NONE, BFA_LOG_INFO, "BFA_AEN_PORT_ONLINE", - "Base port online: WWN = %s.", - ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, - -{BFA_AEN_PORT_OFFLINE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_WARNING, - "BFA_AEN_PORT_OFFLINE", - "Base port offline: WWN = %s.", - ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, - -{BFA_AEN_PORT_RLIR, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, - "BFA_AEN_PORT_RLIR", - "RLIR event not supported.", - (0), 0}, - -{BFA_AEN_PORT_SFP_INSERT, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, - "BFA_AEN_PORT_SFP_INSERT", - "New SFP found: WWN/MAC = %s.", - ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, - -{BFA_AEN_PORT_SFP_REMOVE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, - BFA_LOG_WARNING, "BFA_AEN_PORT_SFP_REMOVE", - "SFP removed: WWN/MAC = %s.", - ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, - -{BFA_AEN_PORT_SFP_POM, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_WARNING, - "BFA_AEN_PORT_SFP_POM", - "SFP POM level to %s: WWN/MAC = %s.", - ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2}, - -{BFA_AEN_PORT_ENABLE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, - "BFA_AEN_PORT_ENABLE", - "Base port enabled: WWN = %s.", - ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, - -{BFA_AEN_PORT_DISABLE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, - "BFA_AEN_PORT_DISABLE", - "Base port disabled: WWN = %s.", - ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, - -{BFA_AEN_PORT_AUTH_ON, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, - "BFA_AEN_PORT_AUTH_ON", - "Authentication successful for base port: WWN = %s.", - ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, - -{BFA_AEN_PORT_AUTH_OFF, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_ERROR, - "BFA_AEN_PORT_AUTH_OFF", - "Authentication unsuccessful for base port: WWN = %s.", - ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, - -{BFA_AEN_PORT_DISCONNECT, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_ERROR, - "BFA_AEN_PORT_DISCONNECT", - "Base port (WWN = %s) lost fabric connectivity.", - ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, - -{BFA_AEN_PORT_QOS_NEG, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_WARNING, - "BFA_AEN_PORT_QOS_NEG", - "QOS negotiation failed for base port: WWN = %s.", - ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, - -{BFA_AEN_PORT_FABRIC_NAME_CHANGE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, - BFA_LOG_WARNING, "BFA_AEN_PORT_FABRIC_NAME_CHANGE", - "Base port WWN = %s, Fabric WWN = %s.", - ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2}, - -{BFA_AEN_PORT_SFP_ACCESS_ERROR, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, - BFA_LOG_WARNING, "BFA_AEN_PORT_SFP_ACCESS_ERROR", - "SFP access error: WWN/MAC = %s.", - ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, - -{BFA_AEN_PORT_SFP_UNSUPPORT, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, - BFA_LOG_WARNING, "BFA_AEN_PORT_SFP_UNSUPPORT", - "Unsupported SFP found: WWN/MAC = %s.", - ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, - - - - -/* messages define for BFA_AEN_CAT_RPORT Module */ -{BFA_AEN_RPORT_ONLINE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, - "BFA_AEN_RPORT_ONLINE", - "Remote port (WWN = %s) online for logical port (WWN = %s).", - ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2}, - -{BFA_AEN_RPORT_OFFLINE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, - "BFA_AEN_RPORT_OFFLINE", - "Remote port (WWN = %s) offlined by logical port (WWN = %s).", - ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2}, - -{BFA_AEN_RPORT_DISCONNECT, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, - BFA_LOG_ERROR, "BFA_AEN_RPORT_DISCONNECT", - "Remote port (WWN = %s) connectivity lost for logical port (WWN = %s).", - ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2}, - -{BFA_AEN_RPORT_QOS_PRIO, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, - "BFA_AEN_RPORT_QOS_PRIO", - "QOS priority changed to %s: RPWWN = %s and LPWWN = %s.", - ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | - (BFA_LOG_S << BFA_LOG_ARG2) | 0), 3}, - -{BFA_AEN_RPORT_QOS_FLOWID, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, - "BFA_AEN_RPORT_QOS_FLOWID", - "QOS flow ID changed to %d: RPWWN = %s and LPWWN = %s.", - ((BFA_LOG_D << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | - (BFA_LOG_S << BFA_LOG_ARG2) | 0), 3}, - - - - -/* messages define for FCS Module */ -{BFA_LOG_FCS_FABRIC_NOSWITCH, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, - BFA_LOG_INFO, "FCS_FABRIC_NOSWITCH", - "No switched fabric presence is detected.", - (0), 0}, - -{BFA_LOG_FCS_FABRIC_ISOLATED, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, - BFA_LOG_INFO, "FCS_FABRIC_ISOLATED", - "Port is isolated due to VF_ID mismatch. PWWN: %s, Port VF_ID: %04x and" - " switch port VF_ID: %04x.", - ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_X << BFA_LOG_ARG1) | - (BFA_LOG_X << BFA_LOG_ARG2) | 0), 3}, - - - - -/* messages define for HAL Module */ -{BFA_LOG_HAL_ASSERT, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_ERROR, - "HAL_ASSERT", - "Assertion failure: %s:%d: %s", - ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_D << BFA_LOG_ARG1) | - (BFA_LOG_S << BFA_LOG_ARG2) | 0), 3}, - -{BFA_LOG_HAL_HEARTBEAT_FAILURE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, - BFA_LOG_CRITICAL, "HAL_HEARTBEAT_FAILURE", - "Firmware heartbeat failure at %d", - ((BFA_LOG_D << BFA_LOG_ARG0) | 0), 1}, - -{BFA_LOG_HAL_FCPIM_PARM_INVALID, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, - BFA_LOG_INFO, "HAL_FCPIM_PARM_INVALID", - "Driver configuration %s value %d is invalid. Value should be within" - " %d and %d.", - ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_D << BFA_LOG_ARG1) | - (BFA_LOG_D << BFA_LOG_ARG2) | (BFA_LOG_D << BFA_LOG_ARG3) | 0), 4}, - -{BFA_LOG_HAL_SM_ASSERT, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_ERROR, - "HAL_SM_ASSERT", - "SM Assertion failure: %s:%d: event = %d", - ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_D << BFA_LOG_ARG1) | - (BFA_LOG_D << BFA_LOG_ARG2) | 0), 3}, - -{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}, - - - - -/* messages define for LINUX Module */ -{BFA_LOG_LINUX_DEVICE_CLAIMED, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, - BFA_LOG_INFO, "LINUX_DEVICE_CLAIMED", - "bfa device at %s claimed.", - ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, - -{BFA_LOG_LINUX_HASH_INIT_FAILED, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, - BFA_LOG_INFO, "LINUX_HASH_INIT_FAILED", - "Hash table initialization failure for the port %s.", - ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, - -{BFA_LOG_LINUX_SYSFS_FAILED, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, - BFA_LOG_INFO, "LINUX_SYSFS_FAILED", - "sysfs file creation failure for the port %s.", - ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, - -{BFA_LOG_LINUX_MEM_ALLOC_FAILED, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, - BFA_LOG_INFO, "LINUX_MEM_ALLOC_FAILED", - "Memory allocation failed: %s. ", - ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, - -{BFA_LOG_LINUX_DRIVER_REGISTRATION_FAILED, - BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, - "LINUX_DRIVER_REGISTRATION_FAILED", - "%s. ", - ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, - -{BFA_LOG_LINUX_ITNIM_FREE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, - "LINUX_ITNIM_FREE", - "scsi%d: FCID: %s WWPN: %s", - ((BFA_LOG_D << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | - (BFA_LOG_S << BFA_LOG_ARG2) | 0), 3}, - -{BFA_LOG_LINUX_ITNIM_ONLINE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, - BFA_LOG_INFO, "LINUX_ITNIM_ONLINE", - "Target: %d:0:%d FCID: %s WWPN: %s", - ((BFA_LOG_D << BFA_LOG_ARG0) | (BFA_LOG_D << BFA_LOG_ARG1) | - (BFA_LOG_S << BFA_LOG_ARG2) | (BFA_LOG_S << BFA_LOG_ARG3) | 0), 4}, - -{BFA_LOG_LINUX_ITNIM_OFFLINE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, - BFA_LOG_INFO, "LINUX_ITNIM_OFFLINE", - "Target: %d:0:%d FCID: %s WWPN: %s", - ((BFA_LOG_D << BFA_LOG_ARG0) | (BFA_LOG_D << BFA_LOG_ARG1) | - (BFA_LOG_S << BFA_LOG_ARG2) | (BFA_LOG_S << BFA_LOG_ARG3) | 0), 4}, - -{BFA_LOG_LINUX_SCSI_HOST_FREE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, - BFA_LOG_INFO, "LINUX_SCSI_HOST_FREE", - "Free scsi%d", - ((BFA_LOG_D << BFA_LOG_ARG0) | 0), 1}, - -{BFA_LOG_LINUX_SCSI_ABORT, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, - "LINUX_SCSI_ABORT", - "scsi%d: abort cmnd %p, iotag %x", - ((BFA_LOG_D << BFA_LOG_ARG0) | (BFA_LOG_P << BFA_LOG_ARG1) | - (BFA_LOG_X << BFA_LOG_ARG2) | 0), 3}, - -{BFA_LOG_LINUX_SCSI_ABORT_COMP, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, - BFA_LOG_INFO, "LINUX_SCSI_ABORT_COMP", - "scsi%d: complete abort 0x%p, iotag 0x%x", - ((BFA_LOG_D << BFA_LOG_ARG0) | (BFA_LOG_P << BFA_LOG_ARG1) | - (BFA_LOG_X << BFA_LOG_ARG2) | 0), 3}, - -{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}, - - - - -/* messages define for WDRV Module */ -{BFA_LOG_WDRV_IOC_INIT_ERROR, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, - BFA_LOG_INFO, "WDRV_IOC_INIT_ERROR", - "IOC initialization has failed.", - (0), 0}, - -{BFA_LOG_WDRV_IOC_INTERNAL_ERROR, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, - BFA_LOG_INFO, "WDRV_IOC_INTERNAL_ERROR", - "IOC internal error. ", - (0), 0}, - -{BFA_LOG_WDRV_IOC_START_ERROR, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, - BFA_LOG_INFO, "WDRV_IOC_START_ERROR", - "IOC could not be started. ", - (0), 0}, - -{BFA_LOG_WDRV_IOC_STOP_ERROR, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, - BFA_LOG_INFO, "WDRV_IOC_STOP_ERROR", - "IOC could not be stopped. ", - (0), 0}, - -{BFA_LOG_WDRV_INSUFFICIENT_RESOURCES, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, - BFA_LOG_INFO, "WDRV_INSUFFICIENT_RESOURCES", - "Insufficient memory. ", - (0), 0}, - -{BFA_LOG_WDRV_BASE_ADDRESS_MAP_ERROR, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, - BFA_LOG_INFO, "WDRV_BASE_ADDRESS_MAP_ERROR", - "Unable to map the IOC onto the system address space. ", - (0), 0}, - - -{0, 0, 0, "", "", 0, 0}, -}; diff --git a/drivers/scsi/bfa/bfa_lps.c b/drivers/scsi/bfa/bfa_lps.c deleted file mode 100644 index acabb44f092f..000000000000 --- a/drivers/scsi/bfa/bfa_lps.c +++ /dev/null @@ -1,892 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#include <bfa.h> -#include <bfi/bfi_lps.h> -#include <cs/bfa_debug.h> -#include <defs/bfa_defs_pci.h> - -BFA_TRC_FILE(HAL, LPS); -BFA_MODULE(lps); - -#define BFA_LPS_MIN_LPORTS (1) -#define BFA_LPS_MAX_LPORTS (256) - -/* - * Maximum Vports supported per physical port or vf. - */ -#define BFA_LPS_MAX_VPORTS_SUPP_CB 255 -#define BFA_LPS_MAX_VPORTS_SUPP_CT 190 - -/** - * forward declarations - */ -static void bfa_lps_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len, - u32 *dm_len); -static void bfa_lps_attach(struct bfa_s *bfa, void *bfad, - struct bfa_iocfc_cfg_s *cfg, - struct bfa_meminfo_s *meminfo, - struct bfa_pcidev_s *pcidev); -static void bfa_lps_detach(struct bfa_s *bfa); -static void bfa_lps_start(struct bfa_s *bfa); -static void bfa_lps_stop(struct bfa_s *bfa); -static void bfa_lps_iocdisable(struct bfa_s *bfa); -static void bfa_lps_login_rsp(struct bfa_s *bfa, - struct bfi_lps_login_rsp_s *rsp); -static void bfa_lps_logout_rsp(struct bfa_s *bfa, - struct bfi_lps_logout_rsp_s *rsp); -static void bfa_lps_reqq_resume(void *lps_arg); -static void bfa_lps_free(struct bfa_lps_s *lps); -static void bfa_lps_send_login(struct bfa_lps_s *lps); -static void bfa_lps_send_logout(struct bfa_lps_s *lps); -static void bfa_lps_login_comp(struct bfa_lps_s *lps); -static void bfa_lps_logout_comp(struct bfa_lps_s *lps); -static void bfa_lps_cvl_event(struct bfa_lps_s *lps); - -/** - * lps_pvt BFA LPS private functions - */ - -enum bfa_lps_event { - BFA_LPS_SM_LOGIN = 1, /* login request from user */ - BFA_LPS_SM_LOGOUT = 2, /* logout request from user */ - BFA_LPS_SM_FWRSP = 3, /* f/w response to login/logout */ - BFA_LPS_SM_RESUME = 4, /* space present in reqq queue */ - BFA_LPS_SM_DELETE = 5, /* lps delete from user */ - BFA_LPS_SM_OFFLINE = 6, /* Link is offline */ - BFA_LPS_SM_RX_CVL = 7, /* Rx clear virtual link */ -}; - -static void bfa_lps_sm_init(struct bfa_lps_s *lps, enum bfa_lps_event event); -static void bfa_lps_sm_login(struct bfa_lps_s *lps, enum bfa_lps_event event); -static void bfa_lps_sm_loginwait(struct bfa_lps_s *lps, - enum bfa_lps_event event); -static void bfa_lps_sm_online(struct bfa_lps_s *lps, enum bfa_lps_event event); -static void bfa_lps_sm_logout(struct bfa_lps_s *lps, enum bfa_lps_event event); -static void bfa_lps_sm_logowait(struct bfa_lps_s *lps, - enum bfa_lps_event event); - -/** - * Init state -- no login - */ -static void -bfa_lps_sm_init(struct bfa_lps_s *lps, enum bfa_lps_event event) -{ - bfa_trc(lps->bfa, lps->lp_tag); - bfa_trc(lps->bfa, event); - - switch (event) { - case BFA_LPS_SM_LOGIN: - if (bfa_reqq_full(lps->bfa, lps->reqq)) { - bfa_sm_set_state(lps, bfa_lps_sm_loginwait); - bfa_reqq_wait(lps->bfa, lps->reqq, &lps->wqe); - } else { - bfa_sm_set_state(lps, bfa_lps_sm_login); - bfa_lps_send_login(lps); - } - if (lps->fdisc) - bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS, - BFA_PL_EID_LOGIN, 0, "FDISC Request"); - else - bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS, - BFA_PL_EID_LOGIN, 0, "FLOGI Request"); - break; - - case BFA_LPS_SM_LOGOUT: - bfa_lps_logout_comp(lps); - break; - - case BFA_LPS_SM_DELETE: - bfa_lps_free(lps); - break; - - case BFA_LPS_SM_RX_CVL: - case BFA_LPS_SM_OFFLINE: - break; - - case BFA_LPS_SM_FWRSP: - /* Could happen when fabric detects loopback and discards - * the lps request. Fw will eventually sent out the timeout - * Just ignore - */ - break; - - default: - bfa_sm_fault(lps->bfa, event); - } -} - -/** - * login is in progress -- awaiting response from firmware - */ -static void -bfa_lps_sm_login(struct bfa_lps_s *lps, enum bfa_lps_event event) -{ - bfa_trc(lps->bfa, lps->lp_tag); - bfa_trc(lps->bfa, event); - - switch (event) { - case BFA_LPS_SM_FWRSP: - if (lps->status == BFA_STATUS_OK) { - bfa_sm_set_state(lps, bfa_lps_sm_online); - if (lps->fdisc) - bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS, - BFA_PL_EID_LOGIN, 0, "FDISC Accept"); - else - bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS, - BFA_PL_EID_LOGIN, 0, "FLOGI Accept"); - } else { - bfa_sm_set_state(lps, bfa_lps_sm_init); - if (lps->fdisc) - bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS, - BFA_PL_EID_LOGIN, 0, - "FDISC Fail (RJT or timeout)"); - else - bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS, - BFA_PL_EID_LOGIN, 0, - "FLOGI Fail (RJT or timeout)"); - } - bfa_lps_login_comp(lps); - break; - - case BFA_LPS_SM_OFFLINE: - bfa_sm_set_state(lps, bfa_lps_sm_init); - break; - - default: - bfa_sm_fault(lps->bfa, event); - } -} - -/** - * login pending - awaiting space in request queue - */ -static void -bfa_lps_sm_loginwait(struct bfa_lps_s *lps, enum bfa_lps_event event) -{ - bfa_trc(lps->bfa, lps->lp_tag); - bfa_trc(lps->bfa, event); - - switch (event) { - case BFA_LPS_SM_RESUME: - bfa_sm_set_state(lps, bfa_lps_sm_login); - break; - - case BFA_LPS_SM_OFFLINE: - bfa_sm_set_state(lps, bfa_lps_sm_init); - bfa_reqq_wcancel(&lps->wqe); - break; - - case BFA_LPS_SM_RX_CVL: - /* - * Login was not even sent out; so when getting out - * of this state, it will appear like a login retry - * after Clear virtual link - */ - break; - - default: - bfa_sm_fault(lps->bfa, event); - } -} - -/** - * login complete - */ -static void -bfa_lps_sm_online(struct bfa_lps_s *lps, enum bfa_lps_event event) -{ - bfa_trc(lps->bfa, lps->lp_tag); - bfa_trc(lps->bfa, event); - - switch (event) { - case BFA_LPS_SM_LOGOUT: - if (bfa_reqq_full(lps->bfa, lps->reqq)) { - bfa_sm_set_state(lps, bfa_lps_sm_logowait); - bfa_reqq_wait(lps->bfa, lps->reqq, &lps->wqe); - } else { - bfa_sm_set_state(lps, bfa_lps_sm_logout); - bfa_lps_send_logout(lps); - } - bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS, - BFA_PL_EID_LOGO, 0, "Logout"); - break; - - case BFA_LPS_SM_RX_CVL: - bfa_sm_set_state(lps, bfa_lps_sm_init); - - /* Let the vport module know about this event */ - bfa_lps_cvl_event(lps); - bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS, - BFA_PL_EID_FIP_FCF_CVL, 0, "FCF Clear Virt. Link Rx"); - break; - - case BFA_LPS_SM_OFFLINE: - case BFA_LPS_SM_DELETE: - bfa_sm_set_state(lps, bfa_lps_sm_init); - break; - - default: - bfa_sm_fault(lps->bfa, event); - } -} - -/** - * logout in progress - awaiting firmware response - */ -static void -bfa_lps_sm_logout(struct bfa_lps_s *lps, enum bfa_lps_event event) -{ - bfa_trc(lps->bfa, lps->lp_tag); - bfa_trc(lps->bfa, event); - - switch (event) { - case BFA_LPS_SM_FWRSP: - bfa_sm_set_state(lps, bfa_lps_sm_init); - bfa_lps_logout_comp(lps); - break; - - case BFA_LPS_SM_OFFLINE: - bfa_sm_set_state(lps, bfa_lps_sm_init); - break; - - default: - bfa_sm_fault(lps->bfa, event); - } -} - -/** - * logout pending -- awaiting space in request queue - */ -static void -bfa_lps_sm_logowait(struct bfa_lps_s *lps, enum bfa_lps_event event) -{ - bfa_trc(lps->bfa, lps->lp_tag); - bfa_trc(lps->bfa, event); - - switch (event) { - case BFA_LPS_SM_RESUME: - bfa_sm_set_state(lps, bfa_lps_sm_logout); - bfa_lps_send_logout(lps); - break; - - case BFA_LPS_SM_OFFLINE: - bfa_sm_set_state(lps, bfa_lps_sm_init); - bfa_reqq_wcancel(&lps->wqe); - break; - - default: - bfa_sm_fault(lps->bfa, event); - } -} - - - -/** - * lps_pvt BFA LPS private functions - */ - -/** - * return memory requirement - */ -static void -bfa_lps_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len, u32 *dm_len) -{ - if (cfg->drvcfg.min_cfg) - *ndm_len += sizeof(struct bfa_lps_s) * BFA_LPS_MIN_LPORTS; - else - *ndm_len += sizeof(struct bfa_lps_s) * BFA_LPS_MAX_LPORTS; -} - -/** - * bfa module attach at initialization time - */ -static void -bfa_lps_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, - struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev) -{ - struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa); - struct bfa_lps_s *lps; - int i; - - bfa_os_memset(mod, 0, sizeof(struct bfa_lps_mod_s)); - mod->num_lps = BFA_LPS_MAX_LPORTS; - if (cfg->drvcfg.min_cfg) - mod->num_lps = BFA_LPS_MIN_LPORTS; - else - mod->num_lps = BFA_LPS_MAX_LPORTS; - mod->lps_arr = lps = (struct bfa_lps_s *) bfa_meminfo_kva(meminfo); - - bfa_meminfo_kva(meminfo) += mod->num_lps * sizeof(struct bfa_lps_s); - - INIT_LIST_HEAD(&mod->lps_free_q); - INIT_LIST_HEAD(&mod->lps_active_q); - - for (i = 0; i < mod->num_lps; i++, lps++) { - lps->bfa = bfa; - lps->lp_tag = (u8) i; - lps->reqq = BFA_REQQ_LPS; - bfa_reqq_winit(&lps->wqe, bfa_lps_reqq_resume, lps); - list_add_tail(&lps->qe, &mod->lps_free_q); - } -} - -static void -bfa_lps_detach(struct bfa_s *bfa) -{ -} - -static void -bfa_lps_start(struct bfa_s *bfa) -{ -} - -static void -bfa_lps_stop(struct bfa_s *bfa) -{ -} - -/** - * IOC in disabled state -- consider all lps offline - */ -static void -bfa_lps_iocdisable(struct bfa_s *bfa) -{ - struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa); - struct bfa_lps_s *lps; - struct list_head *qe, *qen; - - list_for_each_safe(qe, qen, &mod->lps_active_q) { - lps = (struct bfa_lps_s *) qe; - bfa_sm_send_event(lps, BFA_LPS_SM_OFFLINE); - } -} - -/** - * Firmware login response - */ -static void -bfa_lps_login_rsp(struct bfa_s *bfa, struct bfi_lps_login_rsp_s *rsp) -{ - struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa); - struct bfa_lps_s *lps; - - bfa_assert(rsp->lp_tag < mod->num_lps); - lps = BFA_LPS_FROM_TAG(mod, rsp->lp_tag); - - lps->status = rsp->status; - switch (rsp->status) { - case BFA_STATUS_OK: - lps->fport = rsp->f_port; - lps->npiv_en = rsp->npiv_en; - lps->lp_pid = rsp->lp_pid; - lps->pr_bbcred = bfa_os_ntohs(rsp->bb_credit); - lps->pr_pwwn = rsp->port_name; - lps->pr_nwwn = rsp->node_name; - lps->auth_req = rsp->auth_req; - lps->lp_mac = rsp->lp_mac; - lps->brcd_switch = rsp->brcd_switch; - lps->fcf_mac = rsp->fcf_mac; - - break; - - case BFA_STATUS_FABRIC_RJT: - lps->lsrjt_rsn = rsp->lsrjt_rsn; - lps->lsrjt_expl = rsp->lsrjt_expl; - - break; - - case BFA_STATUS_EPROTOCOL: - lps->ext_status = rsp->ext_status; - - break; - - default: - /* Nothing to do with other status */ - break; - } - - bfa_sm_send_event(lps, BFA_LPS_SM_FWRSP); -} - -/** - * Firmware logout response - */ -static void -bfa_lps_logout_rsp(struct bfa_s *bfa, struct bfi_lps_logout_rsp_s *rsp) -{ - struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa); - struct bfa_lps_s *lps; - - bfa_assert(rsp->lp_tag < mod->num_lps); - lps = BFA_LPS_FROM_TAG(mod, rsp->lp_tag); - - bfa_sm_send_event(lps, BFA_LPS_SM_FWRSP); -} - -/** - * Firmware received a Clear virtual link request (for FCoE) - */ -static void -bfa_lps_rx_cvl_event(struct bfa_s *bfa, struct bfi_lps_cvl_event_s *cvl) -{ - struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa); - struct bfa_lps_s *lps; - - lps = BFA_LPS_FROM_TAG(mod, cvl->lp_tag); - - bfa_sm_send_event(lps, BFA_LPS_SM_RX_CVL); -} - -/** - * Space is available in request queue, resume queueing request to firmware. - */ -static void -bfa_lps_reqq_resume(void *lps_arg) -{ - struct bfa_lps_s *lps = lps_arg; - - bfa_sm_send_event(lps, BFA_LPS_SM_RESUME); -} - -/** - * lps is freed -- triggered by vport delete - */ -static void -bfa_lps_free(struct bfa_lps_s *lps) -{ - struct bfa_lps_mod_s *mod = BFA_LPS_MOD(lps->bfa); - - list_del(&lps->qe); - list_add_tail(&lps->qe, &mod->lps_free_q); -} - -/** - * send login request to firmware - */ -static void -bfa_lps_send_login(struct bfa_lps_s *lps) -{ - struct bfi_lps_login_req_s *m; - - m = bfa_reqq_next(lps->bfa, lps->reqq); - bfa_assert(m); - - bfi_h2i_set(m->mh, BFI_MC_LPS, BFI_LPS_H2I_LOGIN_REQ, - bfa_lpuid(lps->bfa)); - - m->lp_tag = lps->lp_tag; - m->alpa = lps->alpa; - m->pdu_size = bfa_os_htons(lps->pdusz); - m->pwwn = lps->pwwn; - m->nwwn = lps->nwwn; - m->fdisc = lps->fdisc; - m->auth_en = lps->auth_en; - - bfa_reqq_produce(lps->bfa, lps->reqq); -} - -/** - * send logout request to firmware - */ -static void -bfa_lps_send_logout(struct bfa_lps_s *lps) -{ - struct bfi_lps_logout_req_s *m; - - m = bfa_reqq_next(lps->bfa, lps->reqq); - bfa_assert(m); - - bfi_h2i_set(m->mh, BFI_MC_LPS, BFI_LPS_H2I_LOGOUT_REQ, - bfa_lpuid(lps->bfa)); - - m->lp_tag = lps->lp_tag; - m->port_name = lps->pwwn; - bfa_reqq_produce(lps->bfa, lps->reqq); -} - -/** - * Indirect login completion handler for non-fcs - */ -static void -bfa_lps_login_comp_cb(void *arg, bfa_boolean_t complete) -{ - struct bfa_lps_s *lps = arg; - - if (!complete) - return; - - if (lps->fdisc) - bfa_cb_lps_fdisc_comp(lps->bfa->bfad, lps->uarg, lps->status); - else - bfa_cb_lps_flogi_comp(lps->bfa->bfad, lps->uarg, lps->status); -} - -/** - * Login completion handler -- direct call for fcs, queue for others - */ -static void -bfa_lps_login_comp(struct bfa_lps_s *lps) -{ - if (!lps->bfa->fcs) { - bfa_cb_queue(lps->bfa, &lps->hcb_qe, - bfa_lps_login_comp_cb, lps); - return; - } - - if (lps->fdisc) - bfa_cb_lps_fdisc_comp(lps->bfa->bfad, lps->uarg, lps->status); - else - bfa_cb_lps_flogi_comp(lps->bfa->bfad, lps->uarg, lps->status); -} - -/** - * Indirect logout completion handler for non-fcs - */ -static void -bfa_lps_logout_comp_cb(void *arg, bfa_boolean_t complete) -{ - struct bfa_lps_s *lps = arg; - - if (!complete) - return; - - if (lps->fdisc) - bfa_cb_lps_fdisclogo_comp(lps->bfa->bfad, lps->uarg); - else - bfa_cb_lps_flogo_comp(lps->bfa->bfad, lps->uarg); -} - -/** - * Logout completion handler -- direct call for fcs, queue for others - */ -static void -bfa_lps_logout_comp(struct bfa_lps_s *lps) -{ - if (!lps->bfa->fcs) { - bfa_cb_queue(lps->bfa, &lps->hcb_qe, - bfa_lps_logout_comp_cb, lps); - return; - } - if (lps->fdisc) - bfa_cb_lps_fdisclogo_comp(lps->bfa->bfad, lps->uarg); - else - bfa_cb_lps_flogo_comp(lps->bfa->bfad, lps->uarg); -} - -/** - * Clear virtual link completion handler for non-fcs - */ -static void -bfa_lps_cvl_event_cb(void *arg, bfa_boolean_t complete) -{ - struct bfa_lps_s *lps = arg; - - if (!complete) - return; - - /* Clear virtual link to base port will result in link down */ - if (lps->fdisc) - bfa_cb_lps_cvl_event(lps->bfa->bfad, lps->uarg); -} - -/** - * Received Clear virtual link event --direct call for fcs, - * queue for others - */ -static void -bfa_lps_cvl_event(struct bfa_lps_s *lps) -{ - if (!lps->bfa->fcs) { - bfa_cb_queue(lps->bfa, &lps->hcb_qe, bfa_lps_cvl_event_cb, - lps); - return; - } - - /* Clear virtual link to base port will result in link down */ - if (lps->fdisc) - bfa_cb_lps_cvl_event(lps->bfa->bfad, lps->uarg); -} - -u32 -bfa_lps_get_max_vport(struct bfa_s *bfa) -{ - if (bfa_ioc_devid(&bfa->ioc) == BFA_PCI_DEVICE_ID_CT) - return BFA_LPS_MAX_VPORTS_SUPP_CT; - else - return BFA_LPS_MAX_VPORTS_SUPP_CB; -} - -/** - * lps_public BFA LPS public functions - */ - -/** - * Allocate a lport srvice tag. - */ -struct bfa_lps_s * -bfa_lps_alloc(struct bfa_s *bfa) -{ - struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa); - struct bfa_lps_s *lps = NULL; - - bfa_q_deq(&mod->lps_free_q, &lps); - - if (lps == NULL) - return NULL; - - list_add_tail(&lps->qe, &mod->lps_active_q); - - bfa_sm_set_state(lps, bfa_lps_sm_init); - return lps; -} - -/** - * Free lport service tag. This can be called anytime after an alloc. - * No need to wait for any pending login/logout completions. - */ -void -bfa_lps_delete(struct bfa_lps_s *lps) -{ - bfa_sm_send_event(lps, BFA_LPS_SM_DELETE); -} - -/** - * Initiate a lport login. - */ -void -bfa_lps_flogi(struct bfa_lps_s *lps, void *uarg, u8 alpa, u16 pdusz, - wwn_t pwwn, wwn_t nwwn, bfa_boolean_t auth_en) -{ - lps->uarg = uarg; - lps->alpa = alpa; - lps->pdusz = pdusz; - lps->pwwn = pwwn; - lps->nwwn = nwwn; - lps->fdisc = BFA_FALSE; - lps->auth_en = auth_en; - bfa_sm_send_event(lps, BFA_LPS_SM_LOGIN); -} - -/** - * Initiate a lport fdisc login. - */ -void -bfa_lps_fdisc(struct bfa_lps_s *lps, void *uarg, u16 pdusz, wwn_t pwwn, - wwn_t nwwn) -{ - lps->uarg = uarg; - lps->alpa = 0; - lps->pdusz = pdusz; - lps->pwwn = pwwn; - lps->nwwn = nwwn; - lps->fdisc = BFA_TRUE; - lps->auth_en = BFA_FALSE; - bfa_sm_send_event(lps, BFA_LPS_SM_LOGIN); -} - -/** - * Initiate a lport logout (flogi). - */ -void -bfa_lps_flogo(struct bfa_lps_s *lps) -{ - bfa_sm_send_event(lps, BFA_LPS_SM_LOGOUT); -} - -/** - * Initiate a lport FDSIC logout. - */ -void -bfa_lps_fdisclogo(struct bfa_lps_s *lps) -{ - bfa_sm_send_event(lps, BFA_LPS_SM_LOGOUT); -} - -/** - * Discard a pending login request -- should be called only for - * link down handling. - */ -void -bfa_lps_discard(struct bfa_lps_s *lps) -{ - bfa_sm_send_event(lps, BFA_LPS_SM_OFFLINE); -} - -/** - * Return lport services tag - */ -u8 -bfa_lps_get_tag(struct bfa_lps_s *lps) -{ - return lps->lp_tag; -} - -/** - * Return lport services tag given the pid - */ -u8 -bfa_lps_get_tag_from_pid(struct bfa_s *bfa, u32 pid) -{ - struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa); - struct bfa_lps_s *lps; - int i; - - for (i = 0, lps = mod->lps_arr; i < mod->num_lps; i++, lps++) { - if (lps->lp_pid == pid) - return lps->lp_tag; - } - - /* Return base port tag anyway */ - return 0; -} - -/** - * return if fabric login indicates support for NPIV - */ -bfa_boolean_t -bfa_lps_is_npiv_en(struct bfa_lps_s *lps) -{ - return lps->npiv_en; -} - -/** - * Return TRUE if attached to F-Port, else return FALSE - */ -bfa_boolean_t -bfa_lps_is_fport(struct bfa_lps_s *lps) -{ - return lps->fport; -} - -/** - * Return TRUE if attached to a Brocade Fabric - */ -bfa_boolean_t -bfa_lps_is_brcd_fabric(struct bfa_lps_s *lps) -{ - return lps->brcd_switch; -} -/** - * return TRUE if authentication is required - */ -bfa_boolean_t -bfa_lps_is_authreq(struct bfa_lps_s *lps) -{ - return lps->auth_req; -} - -bfa_eproto_status_t -bfa_lps_get_extstatus(struct bfa_lps_s *lps) -{ - return lps->ext_status; -} - -/** - * return port id assigned to the lport - */ -u32 -bfa_lps_get_pid(struct bfa_lps_s *lps) -{ - return lps->lp_pid; -} - -/** - * Return bb_credit assigned in FLOGI response - */ -u16 -bfa_lps_get_peer_bbcredit(struct bfa_lps_s *lps) -{ - return lps->pr_bbcred; -} - -/** - * Return peer port name - */ -wwn_t -bfa_lps_get_peer_pwwn(struct bfa_lps_s *lps) -{ - return lps->pr_pwwn; -} - -/** - * Return peer node name - */ -wwn_t -bfa_lps_get_peer_nwwn(struct bfa_lps_s *lps) -{ - return lps->pr_nwwn; -} - -/** - * return reason code if login request is rejected - */ -u8 -bfa_lps_get_lsrjt_rsn(struct bfa_lps_s *lps) -{ - return lps->lsrjt_rsn; -} - -/** - * return explanation code if login request is rejected - */ -u8 -bfa_lps_get_lsrjt_expl(struct bfa_lps_s *lps) -{ - return lps->lsrjt_expl; -} - -/** - * Return fpma/spma MAC for lport - */ -struct mac_s -bfa_lps_get_lp_mac(struct bfa_lps_s *lps) -{ - return lps->lp_mac; -} - -/** - * LPS firmware message class handler. - */ -void -bfa_lps_isr(struct bfa_s *bfa, struct bfi_msg_s *m) -{ - union bfi_lps_i2h_msg_u msg; - - bfa_trc(bfa, m->mhdr.msg_id); - msg.msg = m; - - switch (m->mhdr.msg_id) { - case BFI_LPS_H2I_LOGIN_RSP: - bfa_lps_login_rsp(bfa, msg.login_rsp); - break; - - case BFI_LPS_H2I_LOGOUT_RSP: - bfa_lps_logout_rsp(bfa, msg.logout_rsp); - break; - - case BFI_LPS_H2I_CVL_EVENT: - bfa_lps_rx_cvl_event(bfa, msg.cvl_event); - break; - - default: - bfa_trc(bfa, m->mhdr.msg_id); - bfa_assert(0); - } -} - - diff --git a/drivers/scsi/bfa/bfa_lps_priv.h b/drivers/scsi/bfa/bfa_lps_priv.h deleted file mode 100644 index d16c6ce995df..000000000000 --- a/drivers/scsi/bfa/bfa_lps_priv.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFA_LPS_PRIV_H__ -#define __BFA_LPS_PRIV_H__ - -#include <bfa_svc.h> - -struct bfa_lps_mod_s { - struct list_head lps_free_q; - struct list_head lps_active_q; - struct bfa_lps_s *lps_arr; - int num_lps; -}; - -#define BFA_LPS_MOD(__bfa) (&(__bfa)->modules.lps_mod) -#define BFA_LPS_FROM_TAG(__mod, __tag) (&(__mod)->lps_arr[__tag]) - -/* - * external functions - */ -void bfa_lps_isr(struct bfa_s *bfa, struct bfi_msg_s *msg); - -#endif /* __BFA_LPS_PRIV_H__ */ diff --git a/drivers/scsi/bfa/bfa_priv.h b/drivers/scsi/bfa/bfa_modules.h index bf4939b1676c..2cd527338677 100644 --- a/drivers/scsi/bfa/bfa_priv.h +++ b/drivers/scsi/bfa/bfa_modules.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. * All rights reserved * www.brocade.com * @@ -15,26 +15,52 @@ * General Public License for more details. */ -#ifndef __BFA_PRIV_H__ -#define __BFA_PRIV_H__ +/** + * bfa_modules.h BFA modules + */ + +#ifndef __BFA_MODULES_H__ +#define __BFA_MODULES_H__ + +#include "bfa_cs.h" +#include "bfa.h" +#include "bfa_svc.h" +#include "bfa_fcpim.h" +#include "bfa_port.h" + +struct bfa_modules_s { + struct bfa_fcport_s fcport; /* fc port module */ + struct bfa_fcxp_mod_s fcxp_mod; /* fcxp module */ + struct bfa_lps_mod_s lps_mod; /* fcxp module */ + struct bfa_uf_mod_s uf_mod; /* unsolicited frame module */ + struct bfa_rport_mod_s rport_mod; /* remote port module */ + struct bfa_fcpim_mod_s fcpim_mod; /* FCP initiator module */ + struct bfa_sgpg_mod_s sgpg_mod; /* SG page module */ + struct bfa_port_s port; /* Physical port module */ +}; + +/* + * !!! Only append to the enums defined here to avoid any versioning + * !!! needed between trace utility and driver version + */ +enum { + BFA_TRC_HAL_CORE = 1, + BFA_TRC_HAL_FCXP = 2, + BFA_TRC_HAL_FCPIM = 3, + BFA_TRC_HAL_IOCFC_CT = 4, + BFA_TRC_HAL_IOCFC_CB = 5, +}; -#include "bfa_iocfc.h" -#include "bfa_intr_priv.h" -#include "bfa_trcmod_priv.h" -#include "bfa_modules_priv.h" -#include "bfa_fwimg_priv.h" -#include <cs/bfa_log.h> -#include <bfa_timer.h> /** * Macro to define a new BFA module */ -#define BFA_MODULE(__mod) \ +#define BFA_MODULE(__mod) \ static void bfa_ ## __mod ## _meminfo( \ struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len, \ u32 *dm_len); \ static void bfa_ ## __mod ## _attach(struct bfa_s *bfa, \ - void *bfad, struct bfa_iocfc_cfg_s *cfg, \ + void *bfad, struct bfa_iocfc_cfg_s *cfg, \ struct bfa_meminfo_s *meminfo, \ struct bfa_pcidev_s *pcidev); \ static void bfa_ ## __mod ## _detach(struct bfa_s *bfa); \ @@ -77,17 +103,15 @@ extern struct bfa_module_s *hal_mods[]; struct bfa_s { void *bfad; /* BFA driver instance */ - struct bfa_aen_s *aen; /* AEN module */ struct bfa_plog_s *plog; /* portlog buffer */ - struct bfa_log_mod_s *logm; /* driver logging modulen */ struct bfa_trc_mod_s *trcmod; /* driver tracing */ struct bfa_ioc_s ioc; /* IOC module */ struct bfa_iocfc_s iocfc; /* IOCFC module */ struct bfa_timer_mod_s timer_mod; /* timer module */ struct bfa_modules_s modules; /* BFA modules */ - struct list_head comp_q; /* pending completions */ - bfa_boolean_t rme_process; /* RME processing enabled */ - struct list_head reqq_waitq[BFI_IOC_MAX_CQS]; + struct list_head comp_q; /* pending completions */ + bfa_boolean_t rme_process; /* RME processing enabled */ + struct list_head reqq_waitq[BFI_IOC_MAX_CQS]; bfa_boolean_t fcs; /* FCS is attached to BFA */ struct bfa_msix_s msix; }; @@ -95,8 +119,6 @@ struct bfa_s { extern bfa_isr_func_t bfa_isrs[BFI_MC_MAX]; extern bfa_ioc_mbox_mcfunc_t bfa_mbox_isrs[]; extern bfa_boolean_t bfa_auto_recover; -extern struct bfa_module_s hal_mod_flash; -extern struct bfa_module_s hal_mod_fcdiag; extern struct bfa_module_s hal_mod_sgpg; extern struct bfa_module_s hal_mod_fcport; extern struct bfa_module_s hal_mod_fcxp; @@ -104,7 +126,5 @@ extern struct bfa_module_s hal_mod_lps; extern struct bfa_module_s hal_mod_uf; extern struct bfa_module_s hal_mod_rport; extern struct bfa_module_s hal_mod_fcpim; -extern struct bfa_module_s hal_mod_pbind; - -#endif /* __BFA_PRIV_H__ */ +#endif /* __BFA_MODULES_H__ */ diff --git a/drivers/scsi/bfa/bfa_modules_priv.h b/drivers/scsi/bfa/bfa_modules_priv.h deleted file mode 100644 index f554c2fad6a9..000000000000 --- a/drivers/scsi/bfa/bfa_modules_priv.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFA_MODULES_PRIV_H__ -#define __BFA_MODULES_PRIV_H__ - -#include "bfa_uf_priv.h" -#include "bfa_port_priv.h" -#include "bfa_rport_priv.h" -#include "bfa_fcxp_priv.h" -#include "bfa_lps_priv.h" -#include "bfa_fcpim_priv.h" -#include <cee/bfa_cee.h> -#include <port/bfa_port.h> - - -struct bfa_modules_s { - struct bfa_fcport_s fcport; /* fc port module */ - struct bfa_fcxp_mod_s fcxp_mod; /* fcxp module */ - struct bfa_lps_mod_s lps_mod; /* fcxp module */ - struct bfa_uf_mod_s uf_mod; /* unsolicited frame module */ - struct bfa_rport_mod_s rport_mod; /* remote port module */ - struct bfa_fcpim_mod_s fcpim_mod; /* FCP initiator module */ - struct bfa_sgpg_mod_s sgpg_mod; /* SG page module */ - struct bfa_cee_s cee; /* CEE Module */ - struct bfa_port_s port; /* Physical port module */ -}; - -#endif /* __BFA_MODULES_PRIV_H__ */ diff --git a/drivers/scsi/bfa/bfa_os_inc.h b/drivers/scsi/bfa/bfa_os_inc.h index bd1cd3ee3022..788a250ffb8a 100644 --- a/drivers/scsi/bfa/bfa_os_inc.h +++ b/drivers/scsi/bfa/bfa_os_inc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. * All rights reserved * www.brocade.com * @@ -22,30 +22,20 @@ #ifndef __BFA_OS_INC_H__ #define __BFA_OS_INC_H__ -#ifndef __KERNEL__ -#include <stdint.h> -#else #include <linux/types.h> - #include <linux/version.h> #include <linux/pci.h> - #include <linux/dma-mapping.h> -#define SET_MODULE_VERSION(VER) - #include <linux/idr.h> - #include <linux/interrupt.h> #include <linux/cdev.h> #include <linux/fs.h> #include <linux/delay.h> #include <linux/vmalloc.h> - #include <linux/workqueue.h> - +#include <linux/bitops.h> #include <scsi/scsi.h> #include <scsi/scsi_host.h> - #include <scsi/scsi_tcq.h> #include <scsi/scsi_transport_fc.h> #include <scsi/scsi_transport.h> @@ -54,97 +44,75 @@ #define __BIGENDIAN #endif -#define BFA_ERR KERN_ERR -#define BFA_WARNING KERN_WARNING -#define BFA_NOTICE KERN_NOTICE -#define BFA_INFO KERN_INFO -#define BFA_DEBUG KERN_DEBUG - -#define LOG_BFAD_INIT 0x00000001 -#define LOG_FCP_IO 0x00000002 - -#ifdef DEBUG -#define BFA_LOG_TRACE(bfad, level, mask, fmt, arg...) \ - BFA_LOG(bfad, level, mask, fmt, ## arg) -#define BFA_DEV_TRACE(bfad, level, fmt, arg...) \ - BFA_DEV_PRINTF(bfad, level, fmt, ## arg) -#define BFA_TRACE(level, fmt, arg...) \ - BFA_PRINTF(level, fmt, ## arg) -#else -#define BFA_LOG_TRACE(bfad, level, mask, fmt, arg...) -#define BFA_DEV_TRACE(bfad, level, fmt, arg...) -#define BFA_TRACE(level, fmt, arg...) -#endif +static inline u64 bfa_os_get_clock(void) +{ + return jiffies; +} + +static inline u64 bfa_os_get_log_time(void) +{ + u64 system_time = 0; + struct timeval tv; + do_gettimeofday(&tv); + + /* We are interested in seconds only. */ + system_time = tv.tv_sec; + return system_time; +} + +#define bfa_io_lat_clock_res_div HZ +#define bfa_io_lat_clock_res_mul 1000 #define BFA_ASSERT(p) do { \ if (!(p)) { \ printk(KERN_ERR "assert(%s) failed at %s:%d\n", \ #p, __FILE__, __LINE__); \ - BUG(); \ } \ } while (0) - -#define BFA_LOG(bfad, level, mask, fmt, arg...) \ -do { \ - if (((mask) & (((struct bfad_s *)(bfad))-> \ - cfg_data[cfg_log_mask])) || (level[1] <= '3')) \ - dev_printk(level, &(((struct bfad_s *) \ - (bfad))->pcidev->dev), fmt, ##arg); \ +#define BFA_LOG(level, bfad, mask, fmt, arg...) \ +do { \ + if (((mask) == 4) || (level[1] <= '4')) \ + dev_printk(level, &((bfad)->pcidev)->dev, fmt, ##arg); \ } while (0) -#ifndef BFA_DEV_PRINTF -#define BFA_DEV_PRINTF(bfad, level, fmt, arg...) \ - dev_printk(level, &(((struct bfad_s *) \ - (bfad))->pcidev->dev), fmt, ##arg); -#endif - -#define BFA_PRINTF(level, fmt, arg...) \ - printk(level fmt, ##arg); - -int bfa_os_MWB(void *); - -#define bfa_os_mmiowb() mmiowb() - #define bfa_swap_3b(_x) \ ((((_x) & 0xff) << 16) | \ ((_x) & 0x00ff00) | \ (((_x) & 0xff0000) >> 16)) -#define bfa_swap_8b(_x) \ - ((((_x) & 0xff00000000000000ull) >> 56) \ - | (((_x) & 0x00ff000000000000ull) >> 40) \ - | (((_x) & 0x0000ff0000000000ull) >> 24) \ - | (((_x) & 0x000000ff00000000ull) >> 8) \ - | (((_x) & 0x00000000ff000000ull) << 8) \ - | (((_x) & 0x0000000000ff0000ull) << 24) \ - | (((_x) & 0x000000000000ff00ull) << 40) \ - | (((_x) & 0x00000000000000ffull) << 56)) - -#define bfa_os_swap32(_x) \ - ((((_x) & 0xff) << 24) | \ +#define bfa_swap_8b(_x) \ + ((((_x) & 0xff00000000000000ull) >> 56) \ + | (((_x) & 0x00ff000000000000ull) >> 40) \ + | (((_x) & 0x0000ff0000000000ull) >> 24) \ + | (((_x) & 0x000000ff00000000ull) >> 8) \ + | (((_x) & 0x00000000ff000000ull) << 8) \ + | (((_x) & 0x0000000000ff0000ull) << 24) \ + | (((_x) & 0x000000000000ff00ull) << 40) \ + | (((_x) & 0x00000000000000ffull) << 56)) + +#define bfa_os_swap32(_x) \ + ((((_x) & 0xff) << 24) | \ (((_x) & 0x0000ff00) << 8) | \ (((_x) & 0x00ff0000) >> 8) | \ (((_x) & 0xff000000) >> 24)) -#define bfa_os_swap_sgaddr(_x) ((u64)( \ - (((u64)(_x) & (u64)0x00000000000000ffull) << 32) | \ - (((u64)(_x) & (u64)0x000000000000ff00ull) << 32) | \ - (((u64)(_x) & (u64)0x0000000000ff0000ull) << 32) | \ - (((u64)(_x) & (u64)0x00000000ff000000ull) << 32) | \ - (((u64)(_x) & (u64)0x000000ff00000000ull) >> 32) | \ - (((u64)(_x) & (u64)0x0000ff0000000000ull) >> 32) | \ - (((u64)(_x) & (u64)0x00ff000000000000ull) >> 32) | \ +#define bfa_os_swap_sgaddr(_x) ((u64)( \ + (((u64)(_x) & (u64)0x00000000000000ffull) << 32) | \ + (((u64)(_x) & (u64)0x000000000000ff00ull) << 32) | \ + (((u64)(_x) & (u64)0x0000000000ff0000ull) << 32) | \ + (((u64)(_x) & (u64)0x00000000ff000000ull) << 32) | \ + (((u64)(_x) & (u64)0x000000ff00000000ull) >> 32) | \ + (((u64)(_x) & (u64)0x0000ff0000000000ull) >> 32) | \ + (((u64)(_x) & (u64)0x00ff000000000000ull) >> 32) | \ (((u64)(_x) & (u64)0xff00000000000000ull) >> 32))) #ifndef __BIGENDIAN #define bfa_os_htons(_x) ((u16)((((_x) & 0xff00) >> 8) | \ (((_x) & 0x00ff) << 8))) - #define bfa_os_htonl(_x) bfa_os_swap32(_x) #define bfa_os_htonll(_x) bfa_swap_8b(_x) #define bfa_os_hton3b(_x) bfa_swap_3b(_x) - #define bfa_os_wtole(_x) (_x) #define bfa_os_sgaddr(_x) (_x) @@ -170,17 +138,16 @@ int bfa_os_MWB(void *); #define bfa_os_memcpy memcpy #define bfa_os_udelay udelay #define bfa_os_vsprintf vsprintf +#define bfa_os_snprintf snprintf #define bfa_os_assign(__t, __s) __t = __s - -#define bfa_os_addr_t char __iomem * -#define bfa_os_panic() +#define bfa_os_addr_t void __iomem * #define bfa_os_reg_read(_raddr) readl(_raddr) #define bfa_os_reg_write(_raddr, _val) writel((_val), (_raddr)) -#define bfa_os_mem_read(_raddr, _off) \ +#define bfa_os_mem_read(_raddr, _off) \ bfa_os_swap32(readl(((_raddr) + (_off)))) -#define bfa_os_mem_write(_raddr, _off, _val) \ +#define bfa_os_mem_write(_raddr, _off, _val) \ writel(bfa_os_swap32((_val)), ((_raddr) + (_off))) #define BFA_TRC_TS(_trcm) \ @@ -191,11 +158,6 @@ int bfa_os_MWB(void *); (tv.tv_sec*1000000+tv.tv_usec); \ }) -struct bfa_log_mod_s; -void bfa_os_printf(struct bfa_log_mod_s *log_mod, u32 msg_id, - const char *fmt, ...); -#endif - #define boolean_t int /** @@ -206,7 +168,15 @@ struct bfa_timeval_s { u32 tv_usec; /* microseconds */ }; -void bfa_os_gettimeofday(struct bfa_timeval_s *tv); +static inline void +bfa_os_gettimeofday(struct bfa_timeval_s *tv) +{ + struct timeval tmp_tv; + + do_gettimeofday(&tmp_tv); + tv->tv_sec = (u32) tmp_tv.tv_sec; + tv->tv_usec = (u32) tmp_tv.tv_usec; +} static inline void wwn2str(char *wwn_str, u64 wwn) diff --git a/drivers/scsi/bfa/include/cs/bfa_plog.h b/drivers/scsi/bfa/bfa_plog.h index f5bef63b5877..501f0ed35cf0 100644 --- a/drivers/scsi/bfa/include/cs/bfa_plog.h +++ b/drivers/scsi/bfa/bfa_plog.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. * All rights reserved * www.brocade.com * @@ -17,8 +17,8 @@ #ifndef __BFA_PORTLOG_H__ #define __BFA_PORTLOG_H__ -#include "protocol/fc.h" -#include <defs/bfa_defs_types.h> +#include "bfa_fc.h" +#include "bfa_defs.h" #define BFA_PL_NLOG_ENTS 256 #define BFA_PL_LOG_REC_INCR(_x) ((_x)++, (_x) %= BFA_PL_NLOG_ENTS) @@ -27,38 +27,30 @@ #define BFA_PL_INT_LOG_SZ 8 /* number of integers in the integer log */ enum bfa_plog_log_type { - BFA_PL_LOG_TYPE_INVALID = 0, - BFA_PL_LOG_TYPE_INT = 1, - BFA_PL_LOG_TYPE_STRING = 2, + BFA_PL_LOG_TYPE_INVALID = 0, + BFA_PL_LOG_TYPE_INT = 1, + BFA_PL_LOG_TYPE_STRING = 2, }; /* * the (fixed size) record format for each entry in the portlog */ struct bfa_plog_rec_s { - u32 tv; /* Filled by the portlog driver when the * - * entry is added to the circular log. */ - u8 port; /* Source port that logged this entry. CM - * entities will use 0xFF */ - u8 mid; /* Integer value to be used by all entities * - * while logging. The module id to string * - * conversion will be done by BFAL. See - * enum bfa_plog_mid */ - u8 eid; /* indicates Rx, Tx, IOCTL, etc. See - * enum bfa_plog_eid */ - u8 log_type; /* indicates string log or integer log. - * see bfa_plog_log_type_t */ - u8 log_num_ints; + u64 tv; /* timestamp */ + u8 port; /* Source port that logged this entry */ + u8 mid; /* module id */ + u8 eid; /* indicates Rx, Tx, IOCTL, etc. bfa_plog_eid */ + u8 log_type; /* string/integer log, bfa_plog_log_type_t */ + u8 log_num_ints; /* * interpreted only if log_type is INT_LOG. indicates number of * integers in the int_log[] (0-PL_INT_LOG_SZ). */ - u8 rsvd; - u16 misc; /* can be used to indicate fc frame length, - *etc.. */ + u8 rsvd; + u16 misc; /* can be used to indicate fc frame length */ union { - char string_log[BFA_PL_STRING_LOG_SZ]; - u32 int_log[BFA_PL_INT_LOG_SZ]; + char string_log[BFA_PL_STRING_LOG_SZ]; + u32 int_log[BFA_PL_INT_LOG_SZ]; } log_entry; }; @@ -73,20 +65,20 @@ struct bfa_plog_rec_s { * - Do not remove any entry or rearrange the order. */ enum bfa_plog_mid { - BFA_PL_MID_INVALID = 0, - BFA_PL_MID_DEBUG = 1, - BFA_PL_MID_DRVR = 2, - BFA_PL_MID_HAL = 3, - BFA_PL_MID_HAL_FCXP = 4, - BFA_PL_MID_HAL_UF = 5, - BFA_PL_MID_FCS = 6, + BFA_PL_MID_INVALID = 0, + BFA_PL_MID_DEBUG = 1, + BFA_PL_MID_DRVR = 2, + BFA_PL_MID_HAL = 3, + BFA_PL_MID_HAL_FCXP = 4, + BFA_PL_MID_HAL_UF = 5, + BFA_PL_MID_FCS = 6, BFA_PL_MID_LPS = 7, - BFA_PL_MID_MAX = 8 + BFA_PL_MID_MAX = 8 }; #define BFA_PL_MID_STRLEN 8 struct bfa_plog_mid_strings_s { - char m_str[BFA_PL_MID_STRLEN]; + char m_str[BFA_PL_MID_STRLEN]; }; /* @@ -99,36 +91,37 @@ struct bfa_plog_mid_strings_s { * - Do not remove any entry or rearrange the order. */ enum bfa_plog_eid { - BFA_PL_EID_INVALID = 0, - BFA_PL_EID_IOC_DISABLE = 1, - BFA_PL_EID_IOC_ENABLE = 2, - BFA_PL_EID_PORT_DISABLE = 3, - BFA_PL_EID_PORT_ENABLE = 4, - BFA_PL_EID_PORT_ST_CHANGE = 5, - BFA_PL_EID_TX = 6, - BFA_PL_EID_TX_ACK1 = 7, - BFA_PL_EID_TX_RJT = 8, - BFA_PL_EID_TX_BSY = 9, - BFA_PL_EID_RX = 10, - BFA_PL_EID_RX_ACK1 = 11, - BFA_PL_EID_RX_RJT = 12, - BFA_PL_EID_RX_BSY = 13, - BFA_PL_EID_CT_IN = 14, - BFA_PL_EID_CT_OUT = 15, - BFA_PL_EID_DRIVER_START = 16, - BFA_PL_EID_RSCN = 17, - BFA_PL_EID_DEBUG = 18, - BFA_PL_EID_MISC = 19, + BFA_PL_EID_INVALID = 0, + BFA_PL_EID_IOC_DISABLE = 1, + BFA_PL_EID_IOC_ENABLE = 2, + BFA_PL_EID_PORT_DISABLE = 3, + BFA_PL_EID_PORT_ENABLE = 4, + BFA_PL_EID_PORT_ST_CHANGE = 5, + BFA_PL_EID_TX = 6, + BFA_PL_EID_TX_ACK1 = 7, + BFA_PL_EID_TX_RJT = 8, + BFA_PL_EID_TX_BSY = 9, + BFA_PL_EID_RX = 10, + BFA_PL_EID_RX_ACK1 = 11, + BFA_PL_EID_RX_RJT = 12, + BFA_PL_EID_RX_BSY = 13, + BFA_PL_EID_CT_IN = 14, + BFA_PL_EID_CT_OUT = 15, + BFA_PL_EID_DRIVER_START = 16, + BFA_PL_EID_RSCN = 17, + BFA_PL_EID_DEBUG = 18, + BFA_PL_EID_MISC = 19, BFA_PL_EID_FIP_FCF_DISC = 20, BFA_PL_EID_FIP_FCF_CVL = 21, BFA_PL_EID_LOGIN = 22, BFA_PL_EID_LOGO = 23, - BFA_PL_EID_MAX = 24 + BFA_PL_EID_TRUNK_SCN = 24, + BFA_PL_EID_MAX }; -#define BFA_PL_ENAME_STRLEN 8 +#define BFA_PL_ENAME_STRLEN 8 struct bfa_plog_eid_strings_s { - char e_str[BFA_PL_ENAME_STRLEN]; + char e_str[BFA_PL_ENAME_STRLEN]; }; #define BFA_PL_SIG_LEN 8 @@ -138,12 +131,12 @@ struct bfa_plog_eid_strings_s { * per port circular log buffer */ struct bfa_plog_s { - char plog_sig[BFA_PL_SIG_LEN]; /* Start signature */ - u8 plog_enabled; - u8 rsvd[7]; - u32 ticks; - u16 head; - u16 tail; + char plog_sig[BFA_PL_SIG_LEN]; /* Start signature */ + u8 plog_enabled; + u8 rsvd[7]; + u32 ticks; + u16 head; + u16 tail; struct bfa_plog_rec_s plog_recs[BFA_PL_NLOG_ENTS]; }; @@ -154,8 +147,7 @@ void bfa_plog_intarr(struct bfa_plog_s *plog, enum bfa_plog_mid mid, enum bfa_plog_eid event, u16 misc, u32 *intarr, u32 num_ints); void bfa_plog_fchdr(struct bfa_plog_s *plog, enum bfa_plog_mid mid, - enum bfa_plog_eid event, u16 misc, - struct fchs_s *fchdr); + enum bfa_plog_eid event, u16 misc, struct fchs_s *fchdr); void bfa_plog_fchdr_and_pl(struct bfa_plog_s *plog, enum bfa_plog_mid mid, enum bfa_plog_eid event, u16 misc, struct fchs_s *fchdr, u32 pld_w0); diff --git a/drivers/scsi/bfa/bfa_port.c b/drivers/scsi/bfa/bfa_port.c index c7e69f1e56e3..b6d170a13bea 100644 --- a/drivers/scsi/bfa/bfa_port.c +++ b/drivers/scsi/bfa/bfa_port.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. * All rights reserved * www.brocade.com * @@ -15,30 +15,25 @@ * General Public License for more details. */ -#include <defs/bfa_defs_port.h> -#include <cs/bfa_trc.h> -#include <cs/bfa_log.h> -#include <cs/bfa_debug.h> -#include <port/bfa_port.h> -#include <bfi/bfi.h> -#include <bfi/bfi_port.h> -#include <bfa_ioc.h> -#include <cna/bfa_cna_trcmod.h> +#include "bfa_defs_svc.h" +#include "bfa_port.h" +#include "bfi.h" +#include "bfa_ioc.h" + BFA_TRC_FILE(CNA, PORT); #define bfa_ioc_portid(__ioc) ((__ioc)->port_id) -#define bfa_lpuid(__arg) bfa_ioc_portid(&(__arg)->ioc) static void -bfa_port_stats_swap(struct bfa_port_s *port, union bfa_pport_stats_u *stats) +bfa_port_stats_swap(struct bfa_port_s *port, union bfa_port_stats_u *stats) { - u32 *dip = (u32 *) stats; - u32 t0, t1; - int i; + u32 *dip = (u32 *) stats; + u32 t0, t1; + int i; - for (i = 0; i < sizeof(union bfa_pport_stats_u) / sizeof(u32); - i += 2) { + for (i = 0; i < sizeof(union bfa_port_stats_u)/sizeof(u32); + i += 2) { t0 = dip[i]; t1 = dip[i + 1]; #ifdef __BIGENDIAN @@ -49,11 +44,6 @@ bfa_port_stats_swap(struct bfa_port_s *port, union bfa_pport_stats_u *stats) dip[i + 1] = bfa_os_ntohl(t0); #endif } - - /** todo - * QoS stats r also swapped as 64bit; that structure also - * has to use 64 bit counters - */ } /** @@ -68,7 +58,9 @@ bfa_port_stats_swap(struct bfa_port_s *port, union bfa_pport_stats_u *stats) static void bfa_port_enable_isr(struct bfa_port_s *port, bfa_status_t status) { - bfa_assert(0); + bfa_trc(port, status); + port->endis_pending = BFA_FALSE; + port->endis_cbfn(port->endis_cbarg, status); } /** @@ -83,7 +75,9 @@ bfa_port_enable_isr(struct bfa_port_s *port, bfa_status_t status) static void bfa_port_disable_isr(struct bfa_port_s *port, bfa_status_t status) { - bfa_assert(0); + bfa_trc(port, status); + port->endis_pending = BFA_FALSE; + port->endis_cbfn(port->endis_cbarg, status); } /** @@ -105,7 +99,7 @@ bfa_port_get_stats_isr(struct bfa_port_s *port, bfa_status_t status) struct bfa_timeval_s tv; memcpy(port->stats, port->stats_dma.kva, - sizeof(union bfa_pport_stats_u)); + sizeof(union bfa_port_stats_u)); bfa_port_stats_swap(port, port->stats); bfa_os_gettimeofday(&tv); @@ -133,11 +127,11 @@ 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; + port->stats_busy = BFA_FALSE; /** - * re-initialize time stamp for stats reset - */ + * re-initialize time stamp for stats reset + */ bfa_os_gettimeofday(&tv); port->stats_reset_time = tv.tv_sec; @@ -158,10 +152,10 @@ bfa_port_clear_stats_isr(struct bfa_port_s *port, bfa_status_t status) static void bfa_port_isr(void *cbarg, struct bfi_mbmsg_s *m) { - struct bfa_port_s *port = (struct bfa_port_s *)cbarg; + struct bfa_port_s *port = (struct bfa_port_s *) cbarg; union bfi_port_i2h_msg_u *i2hmsg; - i2hmsg = (union bfi_port_i2h_msg_u *)m; + i2hmsg = (union bfi_port_i2h_msg_u *) m; bfa_trc(port, m->mh.msg_id); switch (m->mh.msg_id) { @@ -178,9 +172,7 @@ bfa_port_isr(void *cbarg, struct bfi_mbmsg_s *m) break; case BFI_PORT_I2H_GET_STATS_RSP: - /* - * Stats busy flag is still set? (may be cmd timed out) - */ + /* Stats busy flag is still set? (may be cmd timed out) */ if (port->stats_busy == BFA_FALSE) break; bfa_port_get_stats_isr(port, i2hmsg->getstats_rsp.status); @@ -208,7 +200,7 @@ bfa_port_isr(void *cbarg, struct bfi_mbmsg_s *m) u32 bfa_port_meminfo(void) { - return BFA_ROUNDUP(sizeof(union bfa_pport_stats_u), BFA_DMA_ALIGN_SZ); + return BFA_ROUNDUP(sizeof(union bfa_port_stats_u), BFA_DMA_ALIGN_SZ); } /** @@ -216,8 +208,8 @@ bfa_port_meminfo(void) * * * @param[in] port Port module pointer - * dma_kva Kernel Virtual Address of Port DMA Memory - * dma_pa Physical Address of Port DMA Memory + * dma_kva Kernel Virtual Address of Port DMA Memory + * dma_pa Physical Address of Port DMA Memory * * @return void */ @@ -225,7 +217,7 @@ void bfa_port_mem_claim(struct bfa_port_s *port, u8 *dma_kva, u64 dma_pa) { port->stats_dma.kva = dma_kva; - port->stats_dma.pa = dma_pa; + port->stats_dma.pa = dma_pa; } /** @@ -239,12 +231,14 @@ bfa_port_mem_claim(struct bfa_port_s *port, u8 *dma_kva, u64 dma_pa) */ bfa_status_t bfa_port_enable(struct bfa_port_s *port, bfa_port_endis_cbfn_t cbfn, - void *cbarg) + void *cbarg) { struct bfi_port_generic_req_s *m; - /** todo Not implemented */ - bfa_assert(0); + if (bfa_ioc_is_disabled(port->ioc)) { + bfa_trc(port, BFA_STATUS_IOC_DISABLED); + return BFA_STATUS_IOC_DISABLED; + } if (!bfa_ioc_is_operational(port->ioc)) { bfa_trc(port, BFA_STATUS_IOC_FAILURE); @@ -256,11 +250,11 @@ bfa_port_enable(struct bfa_port_s *port, bfa_port_endis_cbfn_t cbfn, return BFA_STATUS_DEVBUSY; } - m = (struct bfi_port_generic_req_s *)port->endis_mb.msg; + m = (struct bfi_port_generic_req_s *) port->endis_mb.msg; port->msgtag++; - port->endis_cbfn = cbfn; - port->endis_cbarg = cbarg; + port->endis_cbfn = cbfn; + port->endis_cbarg = cbarg; port->endis_pending = BFA_TRUE; bfi_h2i_set(m->mh, BFI_MC_PORT, BFI_PORT_H2I_ENABLE_REQ, @@ -281,12 +275,14 @@ bfa_port_enable(struct bfa_port_s *port, bfa_port_endis_cbfn_t cbfn, */ bfa_status_t bfa_port_disable(struct bfa_port_s *port, bfa_port_endis_cbfn_t cbfn, - void *cbarg) + void *cbarg) { struct bfi_port_generic_req_s *m; - /** todo Not implemented */ - bfa_assert(0); + if (bfa_ioc_is_disabled(port->ioc)) { + bfa_trc(port, BFA_STATUS_IOC_DISABLED); + return BFA_STATUS_IOC_DISABLED; + } if (!bfa_ioc_is_operational(port->ioc)) { bfa_trc(port, BFA_STATUS_IOC_FAILURE); @@ -298,11 +294,11 @@ bfa_port_disable(struct bfa_port_s *port, bfa_port_endis_cbfn_t cbfn, return BFA_STATUS_DEVBUSY; } - m = (struct bfi_port_generic_req_s *)port->endis_mb.msg; + m = (struct bfi_port_generic_req_s *) port->endis_mb.msg; port->msgtag++; - port->endis_cbfn = cbfn; - port->endis_cbarg = cbarg; + port->endis_cbfn = cbfn; + port->endis_cbarg = cbarg; port->endis_pending = BFA_TRUE; bfi_h2i_set(m->mh, BFI_MC_PORT, BFI_PORT_H2I_DISABLE_REQ, @@ -322,8 +318,8 @@ bfa_port_disable(struct bfa_port_s *port, bfa_port_endis_cbfn_t cbfn, * @return Status */ bfa_status_t -bfa_port_get_stats(struct bfa_port_s *port, union bfa_pport_stats_u *stats, - bfa_port_stats_cbfn_t cbfn, void *cbarg) +bfa_port_get_stats(struct bfa_port_s *port, union bfa_port_stats_u *stats, + bfa_port_stats_cbfn_t cbfn, void *cbarg) { struct bfi_port_get_stats_req_s *m; @@ -337,12 +333,12 @@ bfa_port_get_stats(struct bfa_port_s *port, union bfa_pport_stats_u *stats, return BFA_STATUS_DEVBUSY; } - m = (struct bfi_port_get_stats_req_s *)port->stats_mb.msg; + m = (struct bfi_port_get_stats_req_s *) port->stats_mb.msg; - port->stats = stats; - port->stats_cbfn = cbfn; + port->stats = stats; + port->stats_cbfn = cbfn; port->stats_cbarg = cbarg; - port->stats_busy = BFA_TRUE; + port->stats_busy = BFA_TRUE; bfa_dma_be_addr_set(m->dma_addr, port->stats_dma.pa); bfi_h2i_set(m->mh, BFI_MC_PORT, BFI_PORT_H2I_GET_STATS_REQ, @@ -362,7 +358,7 @@ bfa_port_get_stats(struct bfa_port_s *port, union bfa_pport_stats_u *stats, */ bfa_status_t bfa_port_clear_stats(struct bfa_port_s *port, bfa_port_stats_cbfn_t cbfn, - void *cbarg) + void *cbarg) { struct bfi_port_generic_req_s *m; @@ -376,11 +372,11 @@ bfa_port_clear_stats(struct bfa_port_s *port, bfa_port_stats_cbfn_t cbfn, return BFA_STATUS_DEVBUSY; } - m = (struct bfi_port_generic_req_s *)port->stats_mb.msg; + m = (struct bfi_port_generic_req_s *) port->stats_mb.msg; - port->stats_cbfn = cbfn; + port->stats_cbfn = cbfn; port->stats_cbarg = cbarg; - port->stats_busy = BFA_TRUE; + port->stats_busy = BFA_TRUE; bfi_h2i_set(m->mh, BFI_MC_PORT, BFI_PORT_H2I_CLEAR_STATS_REQ, bfa_ioc_portid(port->ioc)); @@ -400,11 +396,9 @@ bfa_port_clear_stats(struct bfa_port_s *port, bfa_port_stats_cbfn_t cbfn, void bfa_port_hbfail(void *arg) { - struct bfa_port_s *port = (struct bfa_port_s *)arg; + struct bfa_port_s *port = (struct bfa_port_s *) arg; - /* - * Fail any pending get_stats/clear_stats requests - */ + /* Fail any pending get_stats/clear_stats requests */ if (port->stats_busy) { if (port->stats_cbfn) port->stats_cbfn(port->stats_cbarg, BFA_STATUS_FAILED); @@ -412,9 +406,7 @@ bfa_port_hbfail(void *arg) port->stats_busy = BFA_FALSE; } - /* - * Clear any enable/disable is pending - */ + /* Clear any enable/disable is pending */ if (port->endis_pending) { if (port->endis_cbfn) port->endis_cbfn(port->endis_cbarg, BFA_STATUS_FAILED); @@ -433,22 +425,20 @@ bfa_port_hbfail(void *arg) * The device driver specific mbox ISR functions have * this pointer as one of the parameters. * trcmod - - * logmod - * * @return void */ void -bfa_port_attach(struct bfa_port_s *port, struct bfa_ioc_s *ioc, void *dev, - struct bfa_trc_mod_s *trcmod, struct bfa_log_mod_s *logmod) +bfa_port_attach(struct bfa_port_s *port, struct bfa_ioc_s *ioc, + void *dev, struct bfa_trc_mod_s *trcmod) { struct bfa_timeval_s tv; bfa_assert(port); - port->dev = dev; - port->ioc = ioc; + port->dev = dev; + port->ioc = ioc; port->trcmod = trcmod; - port->logmod = logmod; port->stats_busy = BFA_FALSE; port->endis_pending = BFA_FALSE; diff --git a/drivers/scsi/bfa/bfa_port.h b/drivers/scsi/bfa/bfa_port.h new file mode 100644 index 000000000000..dbce9dfd056b --- /dev/null +++ b/drivers/scsi/bfa/bfa_port.h @@ -0,0 +1,66 @@ +/* + * 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 __BFA_PORT_H__ +#define __BFA_PORT_H__ + +#include "bfa_defs_svc.h" +#include "bfa_ioc.h" +#include "bfa_cs.h" + +typedef void (*bfa_port_stats_cbfn_t) (void *dev, bfa_status_t status); +typedef void (*bfa_port_endis_cbfn_t) (void *dev, bfa_status_t status); + +struct bfa_port_s { + void *dev; + struct bfa_ioc_s *ioc; + struct bfa_trc_mod_s *trcmod; + u32 msgtag; + bfa_boolean_t stats_busy; + struct bfa_mbox_cmd_s stats_mb; + bfa_port_stats_cbfn_t stats_cbfn; + void *stats_cbarg; + bfa_status_t stats_status; + u32 stats_reset_time; + union bfa_port_stats_u *stats; + struct bfa_dma_s stats_dma; + bfa_boolean_t endis_pending; + struct bfa_mbox_cmd_s endis_mb; + bfa_port_endis_cbfn_t endis_cbfn; + void *endis_cbarg; + bfa_status_t endis_status; + struct bfa_ioc_hbfail_notify_s hbfail; +}; + +void bfa_port_attach(struct bfa_port_s *port, struct bfa_ioc_s *ioc, + void *dev, struct bfa_trc_mod_s *trcmod); +void bfa_port_detach(struct bfa_port_s *port); +void bfa_port_hbfail(void *arg); + +bfa_status_t bfa_port_get_stats(struct bfa_port_s *port, + union bfa_port_stats_u *stats, + bfa_port_stats_cbfn_t cbfn, void *cbarg); +bfa_status_t bfa_port_clear_stats(struct bfa_port_s *port, + bfa_port_stats_cbfn_t cbfn, void *cbarg); +bfa_status_t bfa_port_enable(struct bfa_port_s *port, + bfa_port_endis_cbfn_t cbfn, void *cbarg); +bfa_status_t bfa_port_disable(struct bfa_port_s *port, + bfa_port_endis_cbfn_t cbfn, void *cbarg); +u32 bfa_port_meminfo(void); +void bfa_port_mem_claim(struct bfa_port_s *port, + u8 *dma_kva, u64 dma_pa); +#endif /* __BFA_PORT_H__ */ diff --git a/drivers/scsi/bfa/bfa_port_priv.h b/drivers/scsi/bfa/bfa_port_priv.h deleted file mode 100644 index c9ebe0426fa6..000000000000 --- a/drivers/scsi/bfa/bfa_port_priv.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFA_PORT_PRIV_H__ -#define __BFA_PORT_PRIV_H__ - -#include <defs/bfa_defs_pport.h> -#include <bfi/bfi_pport.h> -#include "bfa_intr_priv.h" - -/** - * Link notification data structure - */ -struct bfa_fcport_ln_s { - struct bfa_fcport_s *fcport; - bfa_sm_t sm; - struct bfa_cb_qe_s ln_qe; /* BFA callback queue elem for ln */ - enum bfa_pport_linkstate ln_event; /* ln event for callback */ -}; - -/** - * BFA FC port data structure - */ -struct bfa_fcport_s { - struct bfa_s *bfa; /* parent BFA instance */ - bfa_sm_t sm; /* port state machine */ - wwn_t nwwn; /* node wwn of physical port */ - wwn_t pwwn; /* port wwn of physical oprt */ - enum bfa_pport_speed speed_sup; - /* supported speeds */ - enum bfa_pport_speed speed; /* current speed */ - enum bfa_pport_topology topology; /* current topology */ - u8 myalpa; /* my ALPA in LOOP topology */ - u8 rsvd[3]; - u32 mypid:24; - u32 rsvd_b:8; - struct bfa_pport_cfg_s cfg; /* current port configuration */ - struct bfa_qos_attr_s qos_attr; /* QoS Attributes */ - struct bfa_qos_vc_attr_s qos_vc_attr; /* VC info from ELP */ - struct bfa_reqq_wait_s reqq_wait; - /* to wait for room in reqq */ - struct bfa_reqq_wait_s svcreq_wait; - /* to wait for room in reqq */ - struct bfa_reqq_wait_s stats_reqq_wait; - /* to wait for room in reqq (stats) */ - void *event_cbarg; - void (*event_cbfn) (void *cbarg, - bfa_pport_event_t event); - union { - union bfi_fcport_i2h_msg_u i2hmsg; - } event_arg; - void *bfad; /* BFA driver handle */ - struct bfa_fcport_ln_s ln; /* Link Notification */ - struct bfa_cb_qe_s hcb_qe; /* BFA callback queue elem */ - struct bfa_timer_s timer; /* timer */ - u32 msgtag; /* fimrware msg tag for reply */ - u8 *stats_kva; - u64 stats_pa; - union bfa_fcport_stats_u *stats; - union bfa_fcport_stats_u *stats_ret; /* driver stats location */ - bfa_status_t stats_status; /* stats/statsclr status */ - bfa_boolean_t stats_busy; /* outstanding stats/statsclr */ - bfa_boolean_t stats_qfull; - u32 stats_reset_time; /* stats reset time stamp */ - bfa_cb_pport_t stats_cbfn; /* driver callback function */ - 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 */ -}; - -#define BFA_FCPORT_MOD(__bfa) (&(__bfa)->modules.fcport) - -/* - * public functions - */ -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_rport.c b/drivers/scsi/bfa/bfa_rport.c deleted file mode 100644 index ccd0680f6f16..000000000000 --- a/drivers/scsi/bfa/bfa_rport.c +++ /dev/null @@ -1,906 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#include <bfa.h> -#include <bfa_svc.h> -#include <cs/bfa_debug.h> -#include <bfi/bfi_rport.h> -#include "bfa_intr_priv.h" - -BFA_TRC_FILE(HAL, RPORT); -BFA_MODULE(rport); - -#define bfa_rport_offline_cb(__rp) do { \ - if ((__rp)->bfa->fcs) \ - bfa_cb_rport_offline((__rp)->rport_drv); \ - else { \ - bfa_cb_queue((__rp)->bfa, &(__rp)->hcb_qe, \ - __bfa_cb_rport_offline, (__rp)); \ - } \ -} while (0) - -#define bfa_rport_online_cb(__rp) do { \ - if ((__rp)->bfa->fcs) \ - bfa_cb_rport_online((__rp)->rport_drv); \ - else { \ - bfa_cb_queue((__rp)->bfa, &(__rp)->hcb_qe, \ - __bfa_cb_rport_online, (__rp)); \ - } \ -} while (0) - -/* - * forward declarations - */ -static struct bfa_rport_s *bfa_rport_alloc(struct bfa_rport_mod_s *rp_mod); -static void bfa_rport_free(struct bfa_rport_s *rport); -static bfa_boolean_t bfa_rport_send_fwcreate(struct bfa_rport_s *rp); -static bfa_boolean_t bfa_rport_send_fwdelete(struct bfa_rport_s *rp); -static bfa_boolean_t bfa_rport_send_fwspeed(struct bfa_rport_s *rp); -static void __bfa_cb_rport_online(void *cbarg, bfa_boolean_t complete); -static void __bfa_cb_rport_offline(void *cbarg, bfa_boolean_t complete); - -/** - * bfa_rport_sm BFA rport state machine - */ - - -enum bfa_rport_event { - BFA_RPORT_SM_CREATE = 1, /* rport create event */ - BFA_RPORT_SM_DELETE = 2, /* deleting an existing rport */ - BFA_RPORT_SM_ONLINE = 3, /* rport is online */ - BFA_RPORT_SM_OFFLINE = 4, /* rport is offline */ - BFA_RPORT_SM_FWRSP = 5, /* firmware response */ - BFA_RPORT_SM_HWFAIL = 6, /* IOC h/w failure */ - BFA_RPORT_SM_QOS_SCN = 7, /* QoS SCN from firmware */ - BFA_RPORT_SM_SET_SPEED = 8, /* Set Rport Speed */ - BFA_RPORT_SM_QRESUME = 9, /* space in requeue queue */ -}; - -static void bfa_rport_sm_uninit(struct bfa_rport_s *rp, - enum bfa_rport_event event); -static void bfa_rport_sm_created(struct bfa_rport_s *rp, - enum bfa_rport_event event); -static void bfa_rport_sm_fwcreate(struct bfa_rport_s *rp, - enum bfa_rport_event event); -static void bfa_rport_sm_online(struct bfa_rport_s *rp, - enum bfa_rport_event event); -static void bfa_rport_sm_fwdelete(struct bfa_rport_s *rp, - enum bfa_rport_event event); -static void bfa_rport_sm_offline(struct bfa_rport_s *rp, - enum bfa_rport_event event); -static void bfa_rport_sm_deleting(struct bfa_rport_s *rp, - enum bfa_rport_event event); -static void bfa_rport_sm_offline_pending(struct bfa_rport_s *rp, - enum bfa_rport_event event); -static void bfa_rport_sm_delete_pending(struct bfa_rport_s *rp, - enum bfa_rport_event event); -static void bfa_rport_sm_iocdisable(struct bfa_rport_s *rp, - enum bfa_rport_event event); -static void bfa_rport_sm_fwcreate_qfull(struct bfa_rport_s *rp, - enum bfa_rport_event event); -static void bfa_rport_sm_fwdelete_qfull(struct bfa_rport_s *rp, - enum bfa_rport_event event); -static void bfa_rport_sm_deleting_qfull(struct bfa_rport_s *rp, - enum bfa_rport_event event); - -/** - * Beginning state, only online event expected. - */ -static void -bfa_rport_sm_uninit(struct bfa_rport_s *rp, enum bfa_rport_event event) -{ - bfa_trc(rp->bfa, rp->rport_tag); - bfa_trc(rp->bfa, event); - - switch (event) { - case BFA_RPORT_SM_CREATE: - bfa_stats(rp, sm_un_cr); - bfa_sm_set_state(rp, bfa_rport_sm_created); - break; - - default: - bfa_stats(rp, sm_un_unexp); - bfa_sm_fault(rp->bfa, event); - } -} - -static void -bfa_rport_sm_created(struct bfa_rport_s *rp, enum bfa_rport_event event) -{ - bfa_trc(rp->bfa, rp->rport_tag); - bfa_trc(rp->bfa, event); - - switch (event) { - case BFA_RPORT_SM_ONLINE: - bfa_stats(rp, sm_cr_on); - if (bfa_rport_send_fwcreate(rp)) - bfa_sm_set_state(rp, bfa_rport_sm_fwcreate); - else - bfa_sm_set_state(rp, bfa_rport_sm_fwcreate_qfull); - break; - - case BFA_RPORT_SM_DELETE: - bfa_stats(rp, sm_cr_del); - bfa_sm_set_state(rp, bfa_rport_sm_uninit); - bfa_rport_free(rp); - break; - - case BFA_RPORT_SM_HWFAIL: - bfa_stats(rp, sm_cr_hwf); - bfa_sm_set_state(rp, bfa_rport_sm_iocdisable); - break; - - default: - bfa_stats(rp, sm_cr_unexp); - bfa_sm_fault(rp->bfa, event); - } -} - -/** - * Waiting for rport create response from firmware. - */ -static void -bfa_rport_sm_fwcreate(struct bfa_rport_s *rp, enum bfa_rport_event event) -{ - bfa_trc(rp->bfa, rp->rport_tag); - bfa_trc(rp->bfa, event); - - switch (event) { - case BFA_RPORT_SM_FWRSP: - bfa_stats(rp, sm_fwc_rsp); - bfa_sm_set_state(rp, bfa_rport_sm_online); - bfa_rport_online_cb(rp); - break; - - case BFA_RPORT_SM_DELETE: - bfa_stats(rp, sm_fwc_del); - bfa_sm_set_state(rp, bfa_rport_sm_delete_pending); - break; - - case BFA_RPORT_SM_OFFLINE: - bfa_stats(rp, sm_fwc_off); - bfa_sm_set_state(rp, bfa_rport_sm_offline_pending); - break; - - case BFA_RPORT_SM_HWFAIL: - bfa_stats(rp, sm_fwc_hwf); - bfa_sm_set_state(rp, bfa_rport_sm_iocdisable); - break; - - default: - bfa_stats(rp, sm_fwc_unexp); - bfa_sm_fault(rp->bfa, event); - } -} - -/** - * Request queue is full, awaiting queue resume to send create request. - */ -static void -bfa_rport_sm_fwcreate_qfull(struct bfa_rport_s *rp, enum bfa_rport_event event) -{ - bfa_trc(rp->bfa, rp->rport_tag); - bfa_trc(rp->bfa, event); - - switch (event) { - case BFA_RPORT_SM_QRESUME: - bfa_sm_set_state(rp, bfa_rport_sm_fwcreate); - bfa_rport_send_fwcreate(rp); - break; - - case BFA_RPORT_SM_DELETE: - bfa_stats(rp, sm_fwc_del); - bfa_sm_set_state(rp, bfa_rport_sm_uninit); - bfa_reqq_wcancel(&rp->reqq_wait); - bfa_rport_free(rp); - break; - - case BFA_RPORT_SM_OFFLINE: - bfa_stats(rp, sm_fwc_off); - bfa_sm_set_state(rp, bfa_rport_sm_offline); - bfa_reqq_wcancel(&rp->reqq_wait); - bfa_rport_offline_cb(rp); - break; - - case BFA_RPORT_SM_HWFAIL: - bfa_stats(rp, sm_fwc_hwf); - bfa_sm_set_state(rp, bfa_rport_sm_iocdisable); - bfa_reqq_wcancel(&rp->reqq_wait); - break; - - default: - bfa_stats(rp, sm_fwc_unexp); - bfa_sm_fault(rp->bfa, event); - } -} - -/** - * Online state - normal parking state. - */ -static void -bfa_rport_sm_online(struct bfa_rport_s *rp, enum bfa_rport_event event) -{ - struct bfi_rport_qos_scn_s *qos_scn; - - bfa_trc(rp->bfa, rp->rport_tag); - bfa_trc(rp->bfa, event); - - switch (event) { - case BFA_RPORT_SM_OFFLINE: - bfa_stats(rp, sm_on_off); - if (bfa_rport_send_fwdelete(rp)) - bfa_sm_set_state(rp, bfa_rport_sm_fwdelete); - else - bfa_sm_set_state(rp, bfa_rport_sm_fwdelete_qfull); - break; - - case BFA_RPORT_SM_DELETE: - bfa_stats(rp, sm_on_del); - if (bfa_rport_send_fwdelete(rp)) - bfa_sm_set_state(rp, bfa_rport_sm_deleting); - else - bfa_sm_set_state(rp, bfa_rport_sm_deleting_qfull); - break; - - case BFA_RPORT_SM_HWFAIL: - bfa_stats(rp, sm_on_hwf); - bfa_sm_set_state(rp, bfa_rport_sm_iocdisable); - break; - - case BFA_RPORT_SM_SET_SPEED: - bfa_rport_send_fwspeed(rp); - break; - - case BFA_RPORT_SM_QOS_SCN: - qos_scn = (struct bfi_rport_qos_scn_s *) rp->event_arg.fw_msg; - rp->qos_attr = qos_scn->new_qos_attr; - bfa_trc(rp->bfa, qos_scn->old_qos_attr.qos_flow_id); - bfa_trc(rp->bfa, qos_scn->new_qos_attr.qos_flow_id); - bfa_trc(rp->bfa, qos_scn->old_qos_attr.qos_priority); - bfa_trc(rp->bfa, qos_scn->new_qos_attr.qos_priority); - - qos_scn->old_qos_attr.qos_flow_id = - bfa_os_ntohl(qos_scn->old_qos_attr.qos_flow_id); - qos_scn->new_qos_attr.qos_flow_id = - bfa_os_ntohl(qos_scn->new_qos_attr.qos_flow_id); - qos_scn->old_qos_attr.qos_priority = - bfa_os_ntohl(qos_scn->old_qos_attr.qos_priority); - qos_scn->new_qos_attr.qos_priority = - bfa_os_ntohl(qos_scn->new_qos_attr.qos_priority); - - if (qos_scn->old_qos_attr.qos_flow_id != - qos_scn->new_qos_attr.qos_flow_id) - bfa_cb_rport_qos_scn_flowid(rp->rport_drv, - qos_scn->old_qos_attr, - qos_scn->new_qos_attr); - if (qos_scn->old_qos_attr.qos_priority != - qos_scn->new_qos_attr.qos_priority) - bfa_cb_rport_qos_scn_prio(rp->rport_drv, - qos_scn->old_qos_attr, - qos_scn->new_qos_attr); - break; - - default: - bfa_stats(rp, sm_on_unexp); - bfa_sm_fault(rp->bfa, event); - } -} - -/** - * Firmware rport is being deleted - awaiting f/w response. - */ -static void -bfa_rport_sm_fwdelete(struct bfa_rport_s *rp, enum bfa_rport_event event) -{ - bfa_trc(rp->bfa, rp->rport_tag); - bfa_trc(rp->bfa, event); - - switch (event) { - case BFA_RPORT_SM_FWRSP: - bfa_stats(rp, sm_fwd_rsp); - bfa_sm_set_state(rp, bfa_rport_sm_offline); - bfa_rport_offline_cb(rp); - break; - - case BFA_RPORT_SM_DELETE: - bfa_stats(rp, sm_fwd_del); - bfa_sm_set_state(rp, bfa_rport_sm_deleting); - break; - - case BFA_RPORT_SM_HWFAIL: - bfa_stats(rp, sm_fwd_hwf); - bfa_sm_set_state(rp, bfa_rport_sm_iocdisable); - bfa_rport_offline_cb(rp); - break; - - default: - bfa_stats(rp, sm_fwd_unexp); - bfa_sm_fault(rp->bfa, event); - } -} - -static void -bfa_rport_sm_fwdelete_qfull(struct bfa_rport_s *rp, enum bfa_rport_event event) -{ - bfa_trc(rp->bfa, rp->rport_tag); - bfa_trc(rp->bfa, event); - - switch (event) { - case BFA_RPORT_SM_QRESUME: - bfa_sm_set_state(rp, bfa_rport_sm_fwdelete); - bfa_rport_send_fwdelete(rp); - break; - - case BFA_RPORT_SM_DELETE: - bfa_stats(rp, sm_fwd_del); - bfa_sm_set_state(rp, bfa_rport_sm_deleting_qfull); - break; - - case BFA_RPORT_SM_HWFAIL: - bfa_stats(rp, sm_fwd_hwf); - bfa_sm_set_state(rp, bfa_rport_sm_iocdisable); - bfa_reqq_wcancel(&rp->reqq_wait); - bfa_rport_offline_cb(rp); - break; - - default: - bfa_stats(rp, sm_fwd_unexp); - bfa_sm_fault(rp->bfa, event); - } -} - -/** - * Offline state. - */ -static void -bfa_rport_sm_offline(struct bfa_rport_s *rp, enum bfa_rport_event event) -{ - bfa_trc(rp->bfa, rp->rport_tag); - bfa_trc(rp->bfa, event); - - switch (event) { - case BFA_RPORT_SM_DELETE: - bfa_stats(rp, sm_off_del); - bfa_sm_set_state(rp, bfa_rport_sm_uninit); - bfa_rport_free(rp); - break; - - case BFA_RPORT_SM_ONLINE: - bfa_stats(rp, sm_off_on); - if (bfa_rport_send_fwcreate(rp)) - bfa_sm_set_state(rp, bfa_rport_sm_fwcreate); - else - bfa_sm_set_state(rp, bfa_rport_sm_fwcreate_qfull); - break; - - case BFA_RPORT_SM_HWFAIL: - bfa_stats(rp, sm_off_hwf); - bfa_sm_set_state(rp, bfa_rport_sm_iocdisable); - break; - - default: - bfa_stats(rp, sm_off_unexp); - bfa_sm_fault(rp->bfa, event); - } -} - -/** - * Rport is deleted, waiting for firmware response to delete. - */ -static void -bfa_rport_sm_deleting(struct bfa_rport_s *rp, enum bfa_rport_event event) -{ - bfa_trc(rp->bfa, rp->rport_tag); - bfa_trc(rp->bfa, event); - - switch (event) { - case BFA_RPORT_SM_FWRSP: - bfa_stats(rp, sm_del_fwrsp); - bfa_sm_set_state(rp, bfa_rport_sm_uninit); - bfa_rport_free(rp); - break; - - case BFA_RPORT_SM_HWFAIL: - bfa_stats(rp, sm_del_hwf); - bfa_sm_set_state(rp, bfa_rport_sm_uninit); - bfa_rport_free(rp); - break; - - default: - bfa_sm_fault(rp->bfa, event); - } -} - -static void -bfa_rport_sm_deleting_qfull(struct bfa_rport_s *rp, enum bfa_rport_event event) -{ - bfa_trc(rp->bfa, rp->rport_tag); - bfa_trc(rp->bfa, event); - - switch (event) { - case BFA_RPORT_SM_QRESUME: - bfa_stats(rp, sm_del_fwrsp); - bfa_sm_set_state(rp, bfa_rport_sm_deleting); - bfa_rport_send_fwdelete(rp); - break; - - case BFA_RPORT_SM_HWFAIL: - bfa_stats(rp, sm_del_hwf); - bfa_sm_set_state(rp, bfa_rport_sm_uninit); - bfa_reqq_wcancel(&rp->reqq_wait); - bfa_rport_free(rp); - break; - - default: - bfa_sm_fault(rp->bfa, event); - } -} - -/** - * Waiting for rport create response from firmware. A delete is pending. - */ -static void -bfa_rport_sm_delete_pending(struct bfa_rport_s *rp, - enum bfa_rport_event event) -{ - bfa_trc(rp->bfa, rp->rport_tag); - bfa_trc(rp->bfa, event); - - switch (event) { - case BFA_RPORT_SM_FWRSP: - bfa_stats(rp, sm_delp_fwrsp); - if (bfa_rport_send_fwdelete(rp)) - bfa_sm_set_state(rp, bfa_rport_sm_deleting); - else - bfa_sm_set_state(rp, bfa_rport_sm_deleting_qfull); - break; - - case BFA_RPORT_SM_HWFAIL: - bfa_stats(rp, sm_delp_hwf); - bfa_sm_set_state(rp, bfa_rport_sm_uninit); - bfa_rport_free(rp); - break; - - default: - bfa_stats(rp, sm_delp_unexp); - bfa_sm_fault(rp->bfa, event); - } -} - -/** - * Waiting for rport create response from firmware. Rport offline is pending. - */ -static void -bfa_rport_sm_offline_pending(struct bfa_rport_s *rp, - enum bfa_rport_event event) -{ - bfa_trc(rp->bfa, rp->rport_tag); - bfa_trc(rp->bfa, event); - - switch (event) { - case BFA_RPORT_SM_FWRSP: - bfa_stats(rp, sm_offp_fwrsp); - if (bfa_rport_send_fwdelete(rp)) - bfa_sm_set_state(rp, bfa_rport_sm_fwdelete); - else - bfa_sm_set_state(rp, bfa_rport_sm_fwdelete_qfull); - break; - - case BFA_RPORT_SM_DELETE: - bfa_stats(rp, sm_offp_del); - bfa_sm_set_state(rp, bfa_rport_sm_delete_pending); - break; - - case BFA_RPORT_SM_HWFAIL: - bfa_stats(rp, sm_offp_hwf); - bfa_sm_set_state(rp, bfa_rport_sm_iocdisable); - break; - - default: - bfa_stats(rp, sm_offp_unexp); - bfa_sm_fault(rp->bfa, event); - } -} - -/** - * IOC h/w failed. - */ -static void -bfa_rport_sm_iocdisable(struct bfa_rport_s *rp, enum bfa_rport_event event) -{ - bfa_trc(rp->bfa, rp->rport_tag); - bfa_trc(rp->bfa, event); - - switch (event) { - case BFA_RPORT_SM_OFFLINE: - bfa_stats(rp, sm_iocd_off); - bfa_rport_offline_cb(rp); - break; - - case BFA_RPORT_SM_DELETE: - bfa_stats(rp, sm_iocd_del); - bfa_sm_set_state(rp, bfa_rport_sm_uninit); - bfa_rport_free(rp); - break; - - case BFA_RPORT_SM_ONLINE: - bfa_stats(rp, sm_iocd_on); - if (bfa_rport_send_fwcreate(rp)) - bfa_sm_set_state(rp, bfa_rport_sm_fwcreate); - else - bfa_sm_set_state(rp, bfa_rport_sm_fwcreate_qfull); - break; - - case BFA_RPORT_SM_HWFAIL: - break; - - default: - bfa_stats(rp, sm_iocd_unexp); - bfa_sm_fault(rp->bfa, event); - } -} - - - -/** - * bfa_rport_private BFA rport private functions - */ - -static void -__bfa_cb_rport_online(void *cbarg, bfa_boolean_t complete) -{ - struct bfa_rport_s *rp = cbarg; - - if (complete) - bfa_cb_rport_online(rp->rport_drv); -} - -static void -__bfa_cb_rport_offline(void *cbarg, bfa_boolean_t complete) -{ - struct bfa_rport_s *rp = cbarg; - - if (complete) - bfa_cb_rport_offline(rp->rport_drv); -} - -static void -bfa_rport_qresume(void *cbarg) -{ - struct bfa_rport_s *rp = cbarg; - - bfa_sm_send_event(rp, BFA_RPORT_SM_QRESUME); -} - -static void -bfa_rport_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len, - u32 *dm_len) -{ - if (cfg->fwcfg.num_rports < BFA_RPORT_MIN) - cfg->fwcfg.num_rports = BFA_RPORT_MIN; - - *km_len += cfg->fwcfg.num_rports * sizeof(struct bfa_rport_s); -} - -static void -bfa_rport_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, - struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev) -{ - struct bfa_rport_mod_s *mod = BFA_RPORT_MOD(bfa); - struct bfa_rport_s *rp; - u16 i; - - INIT_LIST_HEAD(&mod->rp_free_q); - INIT_LIST_HEAD(&mod->rp_active_q); - - rp = (struct bfa_rport_s *) bfa_meminfo_kva(meminfo); - mod->rps_list = rp; - mod->num_rports = cfg->fwcfg.num_rports; - - bfa_assert(mod->num_rports - && !(mod->num_rports & (mod->num_rports - 1))); - - for (i = 0; i < mod->num_rports; i++, rp++) { - bfa_os_memset(rp, 0, sizeof(struct bfa_rport_s)); - rp->bfa = bfa; - rp->rport_tag = i; - bfa_sm_set_state(rp, bfa_rport_sm_uninit); - - /** - * - is unused - */ - if (i) - list_add_tail(&rp->qe, &mod->rp_free_q); - - bfa_reqq_winit(&rp->reqq_wait, bfa_rport_qresume, rp); - } - - /** - * consume memory - */ - bfa_meminfo_kva(meminfo) = (u8 *) rp; -} - -static void -bfa_rport_detach(struct bfa_s *bfa) -{ -} - -static void -bfa_rport_start(struct bfa_s *bfa) -{ -} - -static void -bfa_rport_stop(struct bfa_s *bfa) -{ -} - -static void -bfa_rport_iocdisable(struct bfa_s *bfa) -{ - struct bfa_rport_mod_s *mod = BFA_RPORT_MOD(bfa); - struct bfa_rport_s *rport; - struct list_head *qe, *qen; - - list_for_each_safe(qe, qen, &mod->rp_active_q) { - rport = (struct bfa_rport_s *) qe; - bfa_sm_send_event(rport, BFA_RPORT_SM_HWFAIL); - } -} - -static struct bfa_rport_s * -bfa_rport_alloc(struct bfa_rport_mod_s *mod) -{ - struct bfa_rport_s *rport; - - bfa_q_deq(&mod->rp_free_q, &rport); - if (rport) - list_add_tail(&rport->qe, &mod->rp_active_q); - - return rport; -} - -static void -bfa_rport_free(struct bfa_rport_s *rport) -{ - struct bfa_rport_mod_s *mod = BFA_RPORT_MOD(rport->bfa); - - bfa_assert(bfa_q_is_on_q(&mod->rp_active_q, rport)); - list_del(&rport->qe); - list_add_tail(&rport->qe, &mod->rp_free_q); -} - -static bfa_boolean_t -bfa_rport_send_fwcreate(struct bfa_rport_s *rp) -{ - struct bfi_rport_create_req_s *m; - - /** - * check for room in queue to send request now - */ - m = bfa_reqq_next(rp->bfa, BFA_REQQ_RPORT); - if (!m) { - bfa_reqq_wait(rp->bfa, BFA_REQQ_RPORT, &rp->reqq_wait); - return BFA_FALSE; - } - - bfi_h2i_set(m->mh, BFI_MC_RPORT, BFI_RPORT_H2I_CREATE_REQ, - bfa_lpuid(rp->bfa)); - m->bfa_handle = rp->rport_tag; - m->max_frmsz = bfa_os_htons(rp->rport_info.max_frmsz); - m->pid = rp->rport_info.pid; - m->lp_tag = rp->rport_info.lp_tag; - m->local_pid = rp->rport_info.local_pid; - m->fc_class = rp->rport_info.fc_class; - m->vf_en = rp->rport_info.vf_en; - m->vf_id = rp->rport_info.vf_id; - m->cisc = rp->rport_info.cisc; - - /** - * queue I/O message to firmware - */ - bfa_reqq_produce(rp->bfa, BFA_REQQ_RPORT); - return BFA_TRUE; -} - -static bfa_boolean_t -bfa_rport_send_fwdelete(struct bfa_rport_s *rp) -{ - struct bfi_rport_delete_req_s *m; - - /** - * check for room in queue to send request now - */ - m = bfa_reqq_next(rp->bfa, BFA_REQQ_RPORT); - if (!m) { - bfa_reqq_wait(rp->bfa, BFA_REQQ_RPORT, &rp->reqq_wait); - return BFA_FALSE; - } - - bfi_h2i_set(m->mh, BFI_MC_RPORT, BFI_RPORT_H2I_DELETE_REQ, - bfa_lpuid(rp->bfa)); - m->fw_handle = rp->fw_handle; - - /** - * queue I/O message to firmware - */ - bfa_reqq_produce(rp->bfa, BFA_REQQ_RPORT); - return BFA_TRUE; -} - -static bfa_boolean_t -bfa_rport_send_fwspeed(struct bfa_rport_s *rp) -{ - struct bfa_rport_speed_req_s *m; - - /** - * check for room in queue to send request now - */ - m = bfa_reqq_next(rp->bfa, BFA_REQQ_RPORT); - if (!m) { - bfa_trc(rp->bfa, rp->rport_info.speed); - return BFA_FALSE; - } - - bfi_h2i_set(m->mh, BFI_MC_RPORT, BFI_RPORT_H2I_SET_SPEED_REQ, - bfa_lpuid(rp->bfa)); - m->fw_handle = rp->fw_handle; - m->speed = (u8)rp->rport_info.speed; - - /** - * queue I/O message to firmware - */ - bfa_reqq_produce(rp->bfa, BFA_REQQ_RPORT); - return BFA_TRUE; -} - - - -/** - * bfa_rport_public - */ - -/** - * Rport interrupt processing. - */ -void -bfa_rport_isr(struct bfa_s *bfa, struct bfi_msg_s *m) -{ - union bfi_rport_i2h_msg_u msg; - struct bfa_rport_s *rp; - - bfa_trc(bfa, m->mhdr.msg_id); - - msg.msg = m; - - switch (m->mhdr.msg_id) { - case BFI_RPORT_I2H_CREATE_RSP: - rp = BFA_RPORT_FROM_TAG(bfa, msg.create_rsp->bfa_handle); - rp->fw_handle = msg.create_rsp->fw_handle; - rp->qos_attr = msg.create_rsp->qos_attr; - bfa_assert(msg.create_rsp->status == BFA_STATUS_OK); - bfa_sm_send_event(rp, BFA_RPORT_SM_FWRSP); - break; - - case BFI_RPORT_I2H_DELETE_RSP: - rp = BFA_RPORT_FROM_TAG(bfa, msg.delete_rsp->bfa_handle); - bfa_assert(msg.delete_rsp->status == BFA_STATUS_OK); - bfa_sm_send_event(rp, BFA_RPORT_SM_FWRSP); - break; - - case BFI_RPORT_I2H_QOS_SCN: - rp = BFA_RPORT_FROM_TAG(bfa, msg.qos_scn_evt->bfa_handle); - rp->event_arg.fw_msg = msg.qos_scn_evt; - bfa_sm_send_event(rp, BFA_RPORT_SM_QOS_SCN); - break; - - default: - bfa_trc(bfa, m->mhdr.msg_id); - bfa_assert(0); - } -} - - - -/** - * bfa_rport_api - */ - -struct bfa_rport_s * -bfa_rport_create(struct bfa_s *bfa, void *rport_drv) -{ - struct bfa_rport_s *rp; - - rp = bfa_rport_alloc(BFA_RPORT_MOD(bfa)); - - if (rp == NULL) - return NULL; - - rp->bfa = bfa; - rp->rport_drv = rport_drv; - bfa_rport_clear_stats(rp); - - bfa_assert(bfa_sm_cmp_state(rp, bfa_rport_sm_uninit)); - bfa_sm_send_event(rp, BFA_RPORT_SM_CREATE); - - return rp; -} - -void -bfa_rport_delete(struct bfa_rport_s *rport) -{ - bfa_sm_send_event(rport, BFA_RPORT_SM_DELETE); -} - -void -bfa_rport_online(struct bfa_rport_s *rport, struct bfa_rport_info_s *rport_info) -{ - bfa_assert(rport_info->max_frmsz != 0); - - /** - * Some JBODs are seen to be not setting PDU size correctly in PLOGI - * responses. Default to minimum size. - */ - if (rport_info->max_frmsz == 0) { - bfa_trc(rport->bfa, rport->rport_tag); - rport_info->max_frmsz = FC_MIN_PDUSZ; - } - - bfa_os_assign(rport->rport_info, *rport_info); - bfa_sm_send_event(rport, BFA_RPORT_SM_ONLINE); -} - -void -bfa_rport_offline(struct bfa_rport_s *rport) -{ - bfa_sm_send_event(rport, BFA_RPORT_SM_OFFLINE); -} - -void -bfa_rport_speed(struct bfa_rport_s *rport, enum bfa_pport_speed speed) -{ - bfa_assert(speed != 0); - bfa_assert(speed != BFA_PPORT_SPEED_AUTO); - - rport->rport_info.speed = speed; - bfa_sm_send_event(rport, BFA_RPORT_SM_SET_SPEED); -} - -void -bfa_rport_get_stats(struct bfa_rport_s *rport, - struct bfa_rport_hal_stats_s *stats) -{ - *stats = rport->stats; -} - -void -bfa_rport_get_qos_attr(struct bfa_rport_s *rport, - struct bfa_rport_qos_attr_s *qos_attr) -{ - qos_attr->qos_priority = bfa_os_ntohl(rport->qos_attr.qos_priority); - qos_attr->qos_flow_id = bfa_os_ntohl(rport->qos_attr.qos_flow_id); - -} - -void -bfa_rport_clear_stats(struct bfa_rport_s *rport) -{ - bfa_os_memset(&rport->stats, 0, sizeof(rport->stats)); -} - - diff --git a/drivers/scsi/bfa/bfa_rport_priv.h b/drivers/scsi/bfa/bfa_rport_priv.h deleted file mode 100644 index 6490ce2e990d..000000000000 --- a/drivers/scsi/bfa/bfa_rport_priv.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFA_RPORT_PRIV_H__ -#define __BFA_RPORT_PRIV_H__ - -#include <bfa_svc.h> - -#define BFA_RPORT_MIN 4 - -struct bfa_rport_mod_s { - struct bfa_rport_s *rps_list; /* list of rports */ - struct list_head rp_free_q; /* free bfa_rports */ - struct list_head rp_active_q; /* free bfa_rports */ - u16 num_rports; /* number of rports */ -}; - -#define BFA_RPORT_MOD(__bfa) (&(__bfa)->modules.rport_mod) - -/** - * Convert rport tag to RPORT - */ -#define BFA_RPORT_FROM_TAG(__bfa, _tag) \ - (BFA_RPORT_MOD(__bfa)->rps_list + \ - ((_tag) & (BFA_RPORT_MOD(__bfa)->num_rports - 1))) - -/* - * external functions - */ -void bfa_rport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg); -#endif /* __BFA_RPORT_PRIV_H__ */ diff --git a/drivers/scsi/bfa/bfa_sgpg.c b/drivers/scsi/bfa/bfa_sgpg.c deleted file mode 100644 index ae452c42e40e..000000000000 --- a/drivers/scsi/bfa/bfa_sgpg.c +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#include <bfa.h> - -BFA_TRC_FILE(HAL, SGPG); -BFA_MODULE(sgpg); - -/** - * bfa_sgpg_mod BFA SGPG Mode module - */ - -/** - * Compute and return memory needed by FCP(im) module. - */ -static void -bfa_sgpg_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len, - u32 *dm_len) -{ - if (cfg->drvcfg.num_sgpgs < BFA_SGPG_MIN) - cfg->drvcfg.num_sgpgs = BFA_SGPG_MIN; - - *km_len += (cfg->drvcfg.num_sgpgs + 1) * sizeof(struct bfa_sgpg_s); - *dm_len += (cfg->drvcfg.num_sgpgs + 1) * sizeof(struct bfi_sgpg_s); -} - - -static void -bfa_sgpg_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, - struct bfa_meminfo_s *minfo, struct bfa_pcidev_s *pcidev) -{ - struct bfa_sgpg_mod_s *mod = BFA_SGPG_MOD(bfa); - int i; - struct bfa_sgpg_s *hsgpg; - struct bfi_sgpg_s *sgpg; - u64 align_len; - - union { - u64 pa; - union bfi_addr_u addr; - } sgpg_pa; - - INIT_LIST_HEAD(&mod->sgpg_q); - INIT_LIST_HEAD(&mod->sgpg_wait_q); - - bfa_trc(bfa, cfg->drvcfg.num_sgpgs); - - mod->num_sgpgs = cfg->drvcfg.num_sgpgs; - mod->sgpg_arr_pa = bfa_meminfo_dma_phys(minfo); - align_len = (BFA_SGPG_ROUNDUP(mod->sgpg_arr_pa) - mod->sgpg_arr_pa); - mod->sgpg_arr_pa += align_len; - mod->hsgpg_arr = (struct bfa_sgpg_s *) (bfa_meminfo_kva(minfo) + - align_len); - mod->sgpg_arr = (struct bfi_sgpg_s *) (bfa_meminfo_dma_virt(minfo) + - align_len); - - hsgpg = mod->hsgpg_arr; - sgpg = mod->sgpg_arr; - sgpg_pa.pa = mod->sgpg_arr_pa; - mod->free_sgpgs = mod->num_sgpgs; - - bfa_assert(!(sgpg_pa.pa & (sizeof(struct bfi_sgpg_s) - 1))); - - for (i = 0; i < mod->num_sgpgs; i++) { - bfa_os_memset(hsgpg, 0, sizeof(*hsgpg)); - bfa_os_memset(sgpg, 0, sizeof(*sgpg)); - - hsgpg->sgpg = sgpg; - hsgpg->sgpg_pa = sgpg_pa.addr; - list_add_tail(&hsgpg->qe, &mod->sgpg_q); - - hsgpg++; - sgpg++; - sgpg_pa.pa += sizeof(struct bfi_sgpg_s); - } - - bfa_meminfo_kva(minfo) = (u8 *) hsgpg; - bfa_meminfo_dma_virt(minfo) = (u8 *) sgpg; - bfa_meminfo_dma_phys(minfo) = sgpg_pa.pa; -} - -static void -bfa_sgpg_detach(struct bfa_s *bfa) -{ -} - -static void -bfa_sgpg_start(struct bfa_s *bfa) -{ -} - -static void -bfa_sgpg_stop(struct bfa_s *bfa) -{ -} - -static void -bfa_sgpg_iocdisable(struct bfa_s *bfa) -{ -} - - - -/** - * bfa_sgpg_public BFA SGPG public functions - */ - -bfa_status_t -bfa_sgpg_malloc(struct bfa_s *bfa, struct list_head *sgpg_q, int nsgpgs) -{ - struct bfa_sgpg_mod_s *mod = BFA_SGPG_MOD(bfa); - struct bfa_sgpg_s *hsgpg; - int i; - - bfa_trc_fp(bfa, nsgpgs); - - if (mod->free_sgpgs < nsgpgs) - return BFA_STATUS_ENOMEM; - - for (i = 0; i < nsgpgs; i++) { - bfa_q_deq(&mod->sgpg_q, &hsgpg); - bfa_assert(hsgpg); - list_add_tail(&hsgpg->qe, sgpg_q); - } - - mod->free_sgpgs -= nsgpgs; - return BFA_STATUS_OK; -} - -void -bfa_sgpg_mfree(struct bfa_s *bfa, struct list_head *sgpg_q, int nsgpg) -{ - struct bfa_sgpg_mod_s *mod = BFA_SGPG_MOD(bfa); - struct bfa_sgpg_wqe_s *wqe; - - bfa_trc_fp(bfa, nsgpg); - - mod->free_sgpgs += nsgpg; - bfa_assert(mod->free_sgpgs <= mod->num_sgpgs); - - list_splice_tail_init(sgpg_q, &mod->sgpg_q); - - if (list_empty(&mod->sgpg_wait_q)) - return; - - /** - * satisfy as many waiting requests as possible - */ - do { - wqe = bfa_q_first(&mod->sgpg_wait_q); - if (mod->free_sgpgs < wqe->nsgpg) - nsgpg = mod->free_sgpgs; - else - nsgpg = wqe->nsgpg; - bfa_sgpg_malloc(bfa, &wqe->sgpg_q, nsgpg); - wqe->nsgpg -= nsgpg; - if (wqe->nsgpg == 0) { - list_del(&wqe->qe); - wqe->cbfn(wqe->cbarg); - } - } while (mod->free_sgpgs && !list_empty(&mod->sgpg_wait_q)); -} - -void -bfa_sgpg_wait(struct bfa_s *bfa, struct bfa_sgpg_wqe_s *wqe, int nsgpg) -{ - struct bfa_sgpg_mod_s *mod = BFA_SGPG_MOD(bfa); - - bfa_assert(nsgpg > 0); - bfa_assert(nsgpg > mod->free_sgpgs); - - wqe->nsgpg_total = wqe->nsgpg = nsgpg; - - /** - * allocate any left to this one first - */ - if (mod->free_sgpgs) { - /** - * no one else is waiting for SGPG - */ - bfa_assert(list_empty(&mod->sgpg_wait_q)); - list_splice_tail_init(&mod->sgpg_q, &wqe->sgpg_q); - wqe->nsgpg -= mod->free_sgpgs; - mod->free_sgpgs = 0; - } - - list_add_tail(&wqe->qe, &mod->sgpg_wait_q); -} - -void -bfa_sgpg_wcancel(struct bfa_s *bfa, struct bfa_sgpg_wqe_s *wqe) -{ - struct bfa_sgpg_mod_s *mod = BFA_SGPG_MOD(bfa); - - bfa_assert(bfa_q_is_on_q(&mod->sgpg_wait_q, wqe)); - list_del(&wqe->qe); - - if (wqe->nsgpg_total != wqe->nsgpg) - bfa_sgpg_mfree(bfa, &wqe->sgpg_q, - wqe->nsgpg_total - wqe->nsgpg); -} - -void -bfa_sgpg_winit(struct bfa_sgpg_wqe_s *wqe, void (*cbfn) (void *cbarg), - void *cbarg) -{ - INIT_LIST_HEAD(&wqe->sgpg_q); - wqe->cbfn = cbfn; - wqe->cbarg = cbarg; -} - - diff --git a/drivers/scsi/bfa/bfa_sgpg_priv.h b/drivers/scsi/bfa/bfa_sgpg_priv.h deleted file mode 100644 index 9c2a8cbe7522..000000000000 --- a/drivers/scsi/bfa/bfa_sgpg_priv.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/** - * hal_sgpg.h BFA SG page module - */ - -#ifndef __BFA_SGPG_PRIV_H__ -#define __BFA_SGPG_PRIV_H__ - -#include <cs/bfa_q.h> - -#define BFA_SGPG_MIN (16) - -/** - * Alignment macro for SG page allocation - */ -#define BFA_SGPG_ROUNDUP(_l) (((_l) + (sizeof(struct bfi_sgpg_s) - 1)) \ - & ~(sizeof(struct bfi_sgpg_s) - 1)) - -struct bfa_sgpg_wqe_s { - struct list_head qe; /* queue sg page element */ - int nsgpg; /* pages to be allocated */ - int nsgpg_total; /* total pages required */ - void (*cbfn) (void *cbarg); - /* callback function */ - void *cbarg; /* callback arg */ - struct list_head sgpg_q; /* queue of alloced sgpgs */ -}; - -struct bfa_sgpg_s { - struct list_head qe; /* queue sg page element */ - struct bfi_sgpg_s *sgpg; /* va of SG page */ - union bfi_addr_u sgpg_pa;/* pa of SG page */ -}; - -/** - * Given number of SG elements, BFA_SGPG_NPAGE() returns the number of - * SG pages required. - */ -#define BFA_SGPG_NPAGE(_nsges) (((_nsges) / BFI_SGPG_DATA_SGES) + 1) - -struct bfa_sgpg_mod_s { - struct bfa_s *bfa; - int num_sgpgs; /* number of SG pages */ - int free_sgpgs; /* number of free SG pages */ - struct bfa_sgpg_s *hsgpg_arr; /* BFA SG page array */ - struct bfi_sgpg_s *sgpg_arr; /* actual SG page array */ - u64 sgpg_arr_pa; /* SG page array DMA addr */ - struct list_head sgpg_q; /* queue of free SG pages */ - struct list_head sgpg_wait_q; /* wait queue for SG pages */ -}; -#define BFA_SGPG_MOD(__bfa) (&(__bfa)->modules.sgpg_mod) - -bfa_status_t bfa_sgpg_malloc(struct bfa_s *bfa, struct list_head *sgpg_q, - int nsgpgs); -void bfa_sgpg_mfree(struct bfa_s *bfa, struct list_head *sgpg_q, - int nsgpgs); -void bfa_sgpg_winit(struct bfa_sgpg_wqe_s *wqe, - void (*cbfn) (void *cbarg), void *cbarg); -void bfa_sgpg_wait(struct bfa_s *bfa, struct bfa_sgpg_wqe_s *wqe, - int nsgpgs); -void bfa_sgpg_wcancel(struct bfa_s *bfa, struct bfa_sgpg_wqe_s *wqe); - -#endif /* __BFA_SGPG_PRIV_H__ */ diff --git a/drivers/scsi/bfa/bfa_sm.c b/drivers/scsi/bfa/bfa_sm.c deleted file mode 100644 index 5420f4f45e58..000000000000 --- a/drivers/scsi/bfa/bfa_sm.c +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/** - * bfasm.c BFA State machine utility functions - */ - -#include <cs/bfa_sm.h> - -/** - * cs_sm_api - */ - -int -bfa_sm_to_state(struct bfa_sm_table_s *smt, bfa_sm_t sm) -{ - int i = 0; - - while (smt[i].sm && smt[i].sm != sm) - i++; - return smt[i].state; -} - - diff --git a/drivers/scsi/bfa/bfa_svc.c b/drivers/scsi/bfa/bfa_svc.c new file mode 100644 index 000000000000..aa1dc749b281 --- /dev/null +++ b/drivers/scsi/bfa/bfa_svc.c @@ -0,0 +1,5423 @@ +/* + * 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 "bfa_os_inc.h" +#include "bfa_plog.h" +#include "bfa_cs.h" +#include "bfa_modules.h" +#include "bfad_drv.h" + +BFA_TRC_FILE(HAL, FCXP); +BFA_MODULE(fcxp); +BFA_MODULE(sgpg); +BFA_MODULE(lps); +BFA_MODULE(fcport); +BFA_MODULE(rport); +BFA_MODULE(uf); + +/** + * LPS related definitions + */ +#define BFA_LPS_MIN_LPORTS (1) +#define BFA_LPS_MAX_LPORTS (256) + +/* + * Maximum Vports supported per physical port or vf. + */ +#define BFA_LPS_MAX_VPORTS_SUPP_CB 255 +#define BFA_LPS_MAX_VPORTS_SUPP_CT 190 + +/** + * lps_pvt BFA LPS private functions + */ + +enum bfa_lps_event { + BFA_LPS_SM_LOGIN = 1, /* login request from user */ + BFA_LPS_SM_LOGOUT = 2, /* logout request from user */ + BFA_LPS_SM_FWRSP = 3, /* f/w response to login/logout */ + BFA_LPS_SM_RESUME = 4, /* space present in reqq queue */ + BFA_LPS_SM_DELETE = 5, /* lps delete from user */ + BFA_LPS_SM_OFFLINE = 6, /* Link is offline */ + BFA_LPS_SM_RX_CVL = 7, /* Rx clear virtual link */ +}; + +/** + * FC PORT related definitions + */ +/* + * The port is considered disabled if corresponding physical port or IOC are + * disabled explicitly + */ +#define BFA_PORT_IS_DISABLED(bfa) \ + ((bfa_fcport_is_disabled(bfa) == BFA_TRUE) || \ + (bfa_ioc_is_disabled(&bfa->ioc) == BFA_TRUE)) + + +/** + * BFA port state machine events + */ +enum bfa_fcport_sm_event { + BFA_FCPORT_SM_START = 1, /* start port state machine */ + BFA_FCPORT_SM_STOP = 2, /* stop port state machine */ + BFA_FCPORT_SM_ENABLE = 3, /* enable port */ + BFA_FCPORT_SM_DISABLE = 4, /* disable port state machine */ + BFA_FCPORT_SM_FWRSP = 5, /* firmware enable/disable rsp */ + BFA_FCPORT_SM_LINKUP = 6, /* firmware linkup event */ + BFA_FCPORT_SM_LINKDOWN = 7, /* firmware linkup down */ + BFA_FCPORT_SM_QRESUME = 8, /* CQ space available */ + BFA_FCPORT_SM_HWFAIL = 9, /* IOC h/w failure */ +}; + +/** + * BFA port link notification state machine events + */ + +enum bfa_fcport_ln_sm_event { + BFA_FCPORT_LN_SM_LINKUP = 1, /* linkup event */ + BFA_FCPORT_LN_SM_LINKDOWN = 2, /* linkdown event */ + BFA_FCPORT_LN_SM_NOTIFICATION = 3 /* done notification */ +}; + +/** + * RPORT related definitions + */ +#define bfa_rport_offline_cb(__rp) do { \ + if ((__rp)->bfa->fcs) \ + bfa_cb_rport_offline((__rp)->rport_drv); \ + else { \ + bfa_cb_queue((__rp)->bfa, &(__rp)->hcb_qe, \ + __bfa_cb_rport_offline, (__rp)); \ + } \ +} while (0) + +#define bfa_rport_online_cb(__rp) do { \ + if ((__rp)->bfa->fcs) \ + bfa_cb_rport_online((__rp)->rport_drv); \ + else { \ + bfa_cb_queue((__rp)->bfa, &(__rp)->hcb_qe, \ + __bfa_cb_rport_online, (__rp)); \ + } \ +} while (0) + + +enum bfa_rport_event { + BFA_RPORT_SM_CREATE = 1, /* rport create event */ + BFA_RPORT_SM_DELETE = 2, /* deleting an existing rport */ + BFA_RPORT_SM_ONLINE = 3, /* rport is online */ + BFA_RPORT_SM_OFFLINE = 4, /* rport is offline */ + BFA_RPORT_SM_FWRSP = 5, /* firmware response */ + BFA_RPORT_SM_HWFAIL = 6, /* IOC h/w failure */ + BFA_RPORT_SM_QOS_SCN = 7, /* QoS SCN from firmware */ + BFA_RPORT_SM_SET_SPEED = 8, /* Set Rport Speed */ + BFA_RPORT_SM_QRESUME = 9, /* space in requeue queue */ +}; + +/** + * forward declarations FCXP related functions + */ +static void __bfa_fcxp_send_cbfn(void *cbarg, bfa_boolean_t complete); +static void hal_fcxp_rx_plog(struct bfa_s *bfa, struct bfa_fcxp_s *fcxp, + struct bfi_fcxp_send_rsp_s *fcxp_rsp); +static void hal_fcxp_tx_plog(struct bfa_s *bfa, u32 reqlen, + struct bfa_fcxp_s *fcxp, struct fchs_s *fchs); +static void bfa_fcxp_qresume(void *cbarg); +static void bfa_fcxp_queue(struct bfa_fcxp_s *fcxp, + struct bfi_fcxp_send_req_s *send_req); + +/** + * forward declarations for LPS functions + */ +static void bfa_lps_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len, + u32 *dm_len); +static void bfa_lps_attach(struct bfa_s *bfa, void *bfad, + struct bfa_iocfc_cfg_s *cfg, + struct bfa_meminfo_s *meminfo, + struct bfa_pcidev_s *pcidev); +static void bfa_lps_detach(struct bfa_s *bfa); +static void bfa_lps_start(struct bfa_s *bfa); +static void bfa_lps_stop(struct bfa_s *bfa); +static void bfa_lps_iocdisable(struct bfa_s *bfa); +static void bfa_lps_login_rsp(struct bfa_s *bfa, + struct bfi_lps_login_rsp_s *rsp); +static void bfa_lps_logout_rsp(struct bfa_s *bfa, + struct bfi_lps_logout_rsp_s *rsp); +static void bfa_lps_reqq_resume(void *lps_arg); +static void bfa_lps_free(struct bfa_lps_s *lps); +static void bfa_lps_send_login(struct bfa_lps_s *lps); +static void bfa_lps_send_logout(struct bfa_lps_s *lps); +static void bfa_lps_login_comp(struct bfa_lps_s *lps); +static void bfa_lps_logout_comp(struct bfa_lps_s *lps); +static void bfa_lps_cvl_event(struct bfa_lps_s *lps); + +/** + * forward declaration for LPS state machine + */ +static void bfa_lps_sm_init(struct bfa_lps_s *lps, enum bfa_lps_event event); +static void bfa_lps_sm_login(struct bfa_lps_s *lps, enum bfa_lps_event event); +static void bfa_lps_sm_loginwait(struct bfa_lps_s *lps, enum bfa_lps_event + event); +static void bfa_lps_sm_online(struct bfa_lps_s *lps, enum bfa_lps_event event); +static void bfa_lps_sm_logout(struct bfa_lps_s *lps, enum bfa_lps_event event); +static void bfa_lps_sm_logowait(struct bfa_lps_s *lps, enum bfa_lps_event + event); + +/** + * forward declaration for FC Port functions + */ +static bfa_boolean_t bfa_fcport_send_enable(struct bfa_fcport_s *fcport); +static bfa_boolean_t bfa_fcport_send_disable(struct bfa_fcport_s *fcport); +static void bfa_fcport_update_linkinfo(struct bfa_fcport_s *fcport); +static void bfa_fcport_reset_linkinfo(struct bfa_fcport_s *fcport); +static void bfa_fcport_set_wwns(struct bfa_fcport_s *fcport); +static void __bfa_cb_fcport_event(void *cbarg, bfa_boolean_t complete); +static void bfa_fcport_scn(struct bfa_fcport_s *fcport, + enum bfa_port_linkstate event, bfa_boolean_t trunk); +static void bfa_fcport_queue_cb(struct bfa_fcport_ln_s *ln, + enum bfa_port_linkstate event); +static void __bfa_cb_fcport_stats_clr(void *cbarg, bfa_boolean_t complete); +static void bfa_fcport_stats_get_timeout(void *cbarg); +static void bfa_fcport_stats_clr_timeout(void *cbarg); +static void bfa_trunk_iocdisable(struct bfa_s *bfa); + +/** + * forward declaration for FC PORT state machine + */ +static void bfa_fcport_sm_uninit(struct bfa_fcport_s *fcport, + enum bfa_fcport_sm_event event); +static void bfa_fcport_sm_enabling_qwait(struct bfa_fcport_s *fcport, + enum bfa_fcport_sm_event event); +static void bfa_fcport_sm_enabling(struct bfa_fcport_s *fcport, + enum bfa_fcport_sm_event event); +static void bfa_fcport_sm_linkdown(struct bfa_fcport_s *fcport, + enum bfa_fcport_sm_event event); +static void bfa_fcport_sm_linkup(struct bfa_fcport_s *fcport, + enum bfa_fcport_sm_event event); +static void bfa_fcport_sm_disabling(struct bfa_fcport_s *fcport, + enum bfa_fcport_sm_event event); +static void bfa_fcport_sm_disabling_qwait(struct bfa_fcport_s *fcport, + enum bfa_fcport_sm_event event); +static void bfa_fcport_sm_toggling_qwait(struct bfa_fcport_s *fcport, + enum bfa_fcport_sm_event event); +static void bfa_fcport_sm_disabled(struct bfa_fcport_s *fcport, + enum bfa_fcport_sm_event event); +static void bfa_fcport_sm_stopped(struct bfa_fcport_s *fcport, + enum bfa_fcport_sm_event event); +static void bfa_fcport_sm_iocdown(struct bfa_fcport_s *fcport, + enum bfa_fcport_sm_event event); +static void bfa_fcport_sm_iocfail(struct bfa_fcport_s *fcport, + enum bfa_fcport_sm_event event); + +static void bfa_fcport_ln_sm_dn(struct bfa_fcport_ln_s *ln, + enum bfa_fcport_ln_sm_event event); +static void bfa_fcport_ln_sm_dn_nf(struct bfa_fcport_ln_s *ln, + enum bfa_fcport_ln_sm_event event); +static void bfa_fcport_ln_sm_dn_up_nf(struct bfa_fcport_ln_s *ln, + enum bfa_fcport_ln_sm_event event); +static void bfa_fcport_ln_sm_up(struct bfa_fcport_ln_s *ln, + enum bfa_fcport_ln_sm_event event); +static void bfa_fcport_ln_sm_up_nf(struct bfa_fcport_ln_s *ln, + enum bfa_fcport_ln_sm_event event); +static void bfa_fcport_ln_sm_up_dn_nf(struct bfa_fcport_ln_s *ln, + enum bfa_fcport_ln_sm_event event); +static void bfa_fcport_ln_sm_up_dn_up_nf(struct bfa_fcport_ln_s *ln, + enum bfa_fcport_ln_sm_event event); + +static struct bfa_sm_table_s hal_port_sm_table[] = { + {BFA_SM(bfa_fcport_sm_uninit), BFA_PORT_ST_UNINIT}, + {BFA_SM(bfa_fcport_sm_enabling_qwait), BFA_PORT_ST_ENABLING_QWAIT}, + {BFA_SM(bfa_fcport_sm_enabling), BFA_PORT_ST_ENABLING}, + {BFA_SM(bfa_fcport_sm_linkdown), BFA_PORT_ST_LINKDOWN}, + {BFA_SM(bfa_fcport_sm_linkup), BFA_PORT_ST_LINKUP}, + {BFA_SM(bfa_fcport_sm_disabling_qwait), BFA_PORT_ST_DISABLING_QWAIT}, + {BFA_SM(bfa_fcport_sm_toggling_qwait), BFA_PORT_ST_TOGGLING_QWAIT}, + {BFA_SM(bfa_fcport_sm_disabling), BFA_PORT_ST_DISABLING}, + {BFA_SM(bfa_fcport_sm_disabled), BFA_PORT_ST_DISABLED}, + {BFA_SM(bfa_fcport_sm_stopped), BFA_PORT_ST_STOPPED}, + {BFA_SM(bfa_fcport_sm_iocdown), BFA_PORT_ST_IOCDOWN}, + {BFA_SM(bfa_fcport_sm_iocfail), BFA_PORT_ST_IOCDOWN}, +}; + + +/** + * forward declaration for RPORT related functions + */ +static struct bfa_rport_s *bfa_rport_alloc(struct bfa_rport_mod_s *rp_mod); +static void bfa_rport_free(struct bfa_rport_s *rport); +static bfa_boolean_t bfa_rport_send_fwcreate(struct bfa_rport_s *rp); +static bfa_boolean_t bfa_rport_send_fwdelete(struct bfa_rport_s *rp); +static bfa_boolean_t bfa_rport_send_fwspeed(struct bfa_rport_s *rp); +static void __bfa_cb_rport_online(void *cbarg, + bfa_boolean_t complete); +static void __bfa_cb_rport_offline(void *cbarg, + bfa_boolean_t complete); + +/** + * forward declaration for RPORT state machine + */ +static void bfa_rport_sm_uninit(struct bfa_rport_s *rp, + enum bfa_rport_event event); +static void bfa_rport_sm_created(struct bfa_rport_s *rp, + enum bfa_rport_event event); +static void bfa_rport_sm_fwcreate(struct bfa_rport_s *rp, + enum bfa_rport_event event); +static void bfa_rport_sm_online(struct bfa_rport_s *rp, + enum bfa_rport_event event); +static void bfa_rport_sm_fwdelete(struct bfa_rport_s *rp, + enum bfa_rport_event event); +static void bfa_rport_sm_offline(struct bfa_rport_s *rp, + enum bfa_rport_event event); +static void bfa_rport_sm_deleting(struct bfa_rport_s *rp, + enum bfa_rport_event event); +static void bfa_rport_sm_offline_pending(struct bfa_rport_s *rp, + enum bfa_rport_event event); +static void bfa_rport_sm_delete_pending(struct bfa_rport_s *rp, + enum bfa_rport_event event); +static void bfa_rport_sm_iocdisable(struct bfa_rport_s *rp, + enum bfa_rport_event event); +static void bfa_rport_sm_fwcreate_qfull(struct bfa_rport_s *rp, + enum bfa_rport_event event); +static void bfa_rport_sm_fwdelete_qfull(struct bfa_rport_s *rp, + enum bfa_rport_event event); +static void bfa_rport_sm_deleting_qfull(struct bfa_rport_s *rp, + enum bfa_rport_event event); + +/** + * PLOG related definitions + */ +static int +plkd_validate_logrec(struct bfa_plog_rec_s *pl_rec) +{ + if ((pl_rec->log_type != BFA_PL_LOG_TYPE_INT) && + (pl_rec->log_type != BFA_PL_LOG_TYPE_STRING)) + return 1; + + if ((pl_rec->log_type != BFA_PL_LOG_TYPE_INT) && + (pl_rec->log_num_ints > BFA_PL_INT_LOG_SZ)) + return 1; + + return 0; +} + +static void +bfa_plog_add(struct bfa_plog_s *plog, struct bfa_plog_rec_s *pl_rec) +{ + u16 tail; + struct bfa_plog_rec_s *pl_recp; + + if (plog->plog_enabled == 0) + return; + + if (plkd_validate_logrec(pl_rec)) { + bfa_assert(0); + return; + } + + tail = plog->tail; + + pl_recp = &(plog->plog_recs[tail]); + + bfa_os_memcpy(pl_recp, pl_rec, sizeof(struct bfa_plog_rec_s)); + + pl_recp->tv = bfa_os_get_log_time(); + BFA_PL_LOG_REC_INCR(plog->tail); + + if (plog->head == plog->tail) + BFA_PL_LOG_REC_INCR(plog->head); +} + +void +bfa_plog_init(struct bfa_plog_s *plog) +{ + bfa_os_memset((char *)plog, 0, sizeof(struct bfa_plog_s)); + + bfa_os_memcpy(plog->plog_sig, BFA_PL_SIG_STR, BFA_PL_SIG_LEN); + plog->head = plog->tail = 0; + plog->plog_enabled = 1; +} + +void +bfa_plog_str(struct bfa_plog_s *plog, enum bfa_plog_mid mid, + enum bfa_plog_eid event, + u16 misc, char *log_str) +{ + struct bfa_plog_rec_s lp; + + if (plog->plog_enabled) { + bfa_os_memset(&lp, 0, sizeof(struct bfa_plog_rec_s)); + lp.mid = mid; + lp.eid = event; + lp.log_type = BFA_PL_LOG_TYPE_STRING; + lp.misc = misc; + strncpy(lp.log_entry.string_log, log_str, + BFA_PL_STRING_LOG_SZ - 1); + lp.log_entry.string_log[BFA_PL_STRING_LOG_SZ - 1] = '\0'; + bfa_plog_add(plog, &lp); + } +} + +void +bfa_plog_intarr(struct bfa_plog_s *plog, enum bfa_plog_mid mid, + enum bfa_plog_eid event, + u16 misc, u32 *intarr, u32 num_ints) +{ + struct bfa_plog_rec_s lp; + u32 i; + + if (num_ints > BFA_PL_INT_LOG_SZ) + num_ints = BFA_PL_INT_LOG_SZ; + + if (plog->plog_enabled) { + bfa_os_memset(&lp, 0, sizeof(struct bfa_plog_rec_s)); + lp.mid = mid; + lp.eid = event; + lp.log_type = BFA_PL_LOG_TYPE_INT; + lp.misc = misc; + + for (i = 0; i < num_ints; i++) + bfa_os_assign(lp.log_entry.int_log[i], + intarr[i]); + + lp.log_num_ints = (u8) num_ints; + + bfa_plog_add(plog, &lp); + } +} + +void +bfa_plog_fchdr(struct bfa_plog_s *plog, enum bfa_plog_mid mid, + enum bfa_plog_eid event, + u16 misc, struct fchs_s *fchdr) +{ + struct bfa_plog_rec_s lp; + u32 *tmp_int = (u32 *) fchdr; + u32 ints[BFA_PL_INT_LOG_SZ]; + + if (plog->plog_enabled) { + bfa_os_memset(&lp, 0, sizeof(struct bfa_plog_rec_s)); + + ints[0] = tmp_int[0]; + ints[1] = tmp_int[1]; + ints[2] = tmp_int[4]; + + bfa_plog_intarr(plog, mid, event, misc, ints, 3); + } +} + +void +bfa_plog_fchdr_and_pl(struct bfa_plog_s *plog, enum bfa_plog_mid mid, + enum bfa_plog_eid event, u16 misc, struct fchs_s *fchdr, + u32 pld_w0) +{ + struct bfa_plog_rec_s lp; + u32 *tmp_int = (u32 *) fchdr; + u32 ints[BFA_PL_INT_LOG_SZ]; + + if (plog->plog_enabled) { + bfa_os_memset(&lp, 0, sizeof(struct bfa_plog_rec_s)); + + ints[0] = tmp_int[0]; + ints[1] = tmp_int[1]; + ints[2] = tmp_int[4]; + ints[3] = pld_w0; + + bfa_plog_intarr(plog, mid, event, misc, ints, 4); + } +} + +void +bfa_plog_clear(struct bfa_plog_s *plog) +{ + plog->head = plog->tail = 0; +} + +void +bfa_plog_enable(struct bfa_plog_s *plog) +{ + plog->plog_enabled = 1; +} + +void +bfa_plog_disable(struct bfa_plog_s *plog) +{ + plog->plog_enabled = 0; +} + +bfa_boolean_t +bfa_plog_get_setting(struct bfa_plog_s *plog) +{ + return (bfa_boolean_t)plog->plog_enabled; +} + +/** + * fcxp_pvt BFA FCXP private functions + */ + +static void +claim_fcxp_req_rsp_mem(struct bfa_fcxp_mod_s *mod, struct bfa_meminfo_s *mi) +{ + u8 *dm_kva = NULL; + u64 dm_pa; + u32 buf_pool_sz; + + dm_kva = bfa_meminfo_dma_virt(mi); + dm_pa = bfa_meminfo_dma_phys(mi); + + buf_pool_sz = mod->req_pld_sz * mod->num_fcxps; + + /* + * Initialize the fcxp req payload list + */ + mod->req_pld_list_kva = dm_kva; + mod->req_pld_list_pa = dm_pa; + dm_kva += buf_pool_sz; + dm_pa += buf_pool_sz; + bfa_os_memset(mod->req_pld_list_kva, 0, buf_pool_sz); + + /* + * Initialize the fcxp rsp payload list + */ + buf_pool_sz = mod->rsp_pld_sz * mod->num_fcxps; + mod->rsp_pld_list_kva = dm_kva; + mod->rsp_pld_list_pa = dm_pa; + dm_kva += buf_pool_sz; + dm_pa += buf_pool_sz; + bfa_os_memset(mod->rsp_pld_list_kva, 0, buf_pool_sz); + + bfa_meminfo_dma_virt(mi) = dm_kva; + bfa_meminfo_dma_phys(mi) = dm_pa; +} + +static void +claim_fcxps_mem(struct bfa_fcxp_mod_s *mod, struct bfa_meminfo_s *mi) +{ + u16 i; + struct bfa_fcxp_s *fcxp; + + fcxp = (struct bfa_fcxp_s *) bfa_meminfo_kva(mi); + bfa_os_memset(fcxp, 0, sizeof(struct bfa_fcxp_s) * mod->num_fcxps); + + INIT_LIST_HEAD(&mod->fcxp_free_q); + INIT_LIST_HEAD(&mod->fcxp_active_q); + + mod->fcxp_list = fcxp; + + for (i = 0; i < mod->num_fcxps; i++) { + fcxp->fcxp_mod = mod; + fcxp->fcxp_tag = i; + + list_add_tail(&fcxp->qe, &mod->fcxp_free_q); + bfa_reqq_winit(&fcxp->reqq_wqe, bfa_fcxp_qresume, fcxp); + fcxp->reqq_waiting = BFA_FALSE; + + fcxp = fcxp + 1; + } + + bfa_meminfo_kva(mi) = (void *)fcxp; +} + +static void +bfa_fcxp_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len, + u32 *dm_len) +{ + u16 num_fcxp_reqs = cfg->fwcfg.num_fcxp_reqs; + + if (num_fcxp_reqs == 0) + return; + + /* + * Account for req/rsp payload + */ + *dm_len += BFA_FCXP_MAX_IBUF_SZ * num_fcxp_reqs; + if (cfg->drvcfg.min_cfg) + *dm_len += BFA_FCXP_MAX_IBUF_SZ * num_fcxp_reqs; + else + *dm_len += BFA_FCXP_MAX_LBUF_SZ * num_fcxp_reqs; + + /* + * Account for fcxp structs + */ + *ndm_len += sizeof(struct bfa_fcxp_s) * num_fcxp_reqs; +} + +static void +bfa_fcxp_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, + struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev) +{ + struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa); + + bfa_os_memset(mod, 0, sizeof(struct bfa_fcxp_mod_s)); + mod->bfa = bfa; + mod->num_fcxps = cfg->fwcfg.num_fcxp_reqs; + + /** + * Initialize FCXP request and response payload sizes. + */ + mod->req_pld_sz = mod->rsp_pld_sz = BFA_FCXP_MAX_IBUF_SZ; + if (!cfg->drvcfg.min_cfg) + mod->rsp_pld_sz = BFA_FCXP_MAX_LBUF_SZ; + + INIT_LIST_HEAD(&mod->wait_q); + + claim_fcxp_req_rsp_mem(mod, meminfo); + claim_fcxps_mem(mod, meminfo); +} + +static void +bfa_fcxp_detach(struct bfa_s *bfa) +{ +} + +static void +bfa_fcxp_start(struct bfa_s *bfa) +{ +} + +static void +bfa_fcxp_stop(struct bfa_s *bfa) +{ +} + +static void +bfa_fcxp_iocdisable(struct bfa_s *bfa) +{ + struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa); + struct bfa_fcxp_s *fcxp; + struct list_head *qe, *qen; + + list_for_each_safe(qe, qen, &mod->fcxp_active_q) { + fcxp = (struct bfa_fcxp_s *) qe; + if (fcxp->caller == NULL) { + fcxp->send_cbfn(fcxp->caller, fcxp, fcxp->send_cbarg, + BFA_STATUS_IOC_FAILURE, 0, 0, NULL); + bfa_fcxp_free(fcxp); + } else { + fcxp->rsp_status = BFA_STATUS_IOC_FAILURE; + bfa_cb_queue(bfa, &fcxp->hcb_qe, + __bfa_fcxp_send_cbfn, fcxp); + } + } +} + +static struct bfa_fcxp_s * +bfa_fcxp_get(struct bfa_fcxp_mod_s *fm) +{ + struct bfa_fcxp_s *fcxp; + + bfa_q_deq(&fm->fcxp_free_q, &fcxp); + + if (fcxp) + list_add_tail(&fcxp->qe, &fm->fcxp_active_q); + + return fcxp; +} + +static void +bfa_fcxp_init_reqrsp(struct bfa_fcxp_s *fcxp, + struct bfa_s *bfa, + u8 *use_ibuf, + u32 *nr_sgles, + bfa_fcxp_get_sgaddr_t *r_sga_cbfn, + bfa_fcxp_get_sglen_t *r_sglen_cbfn, + struct list_head *r_sgpg_q, + int n_sgles, + bfa_fcxp_get_sgaddr_t sga_cbfn, + bfa_fcxp_get_sglen_t sglen_cbfn) +{ + + bfa_assert(bfa != NULL); + + bfa_trc(bfa, fcxp->fcxp_tag); + + if (n_sgles == 0) { + *use_ibuf = 1; + } else { + bfa_assert(*sga_cbfn != NULL); + bfa_assert(*sglen_cbfn != NULL); + + *use_ibuf = 0; + *r_sga_cbfn = sga_cbfn; + *r_sglen_cbfn = sglen_cbfn; + + *nr_sgles = n_sgles; + + /* + * alloc required sgpgs + */ + if (n_sgles > BFI_SGE_INLINE) + bfa_assert(0); + } + +} + +static void +bfa_fcxp_init(struct bfa_fcxp_s *fcxp, + void *caller, struct bfa_s *bfa, int nreq_sgles, + int nrsp_sgles, bfa_fcxp_get_sgaddr_t req_sga_cbfn, + bfa_fcxp_get_sglen_t req_sglen_cbfn, + bfa_fcxp_get_sgaddr_t rsp_sga_cbfn, + bfa_fcxp_get_sglen_t rsp_sglen_cbfn) +{ + + bfa_assert(bfa != NULL); + + bfa_trc(bfa, fcxp->fcxp_tag); + + fcxp->caller = caller; + + bfa_fcxp_init_reqrsp(fcxp, bfa, + &fcxp->use_ireqbuf, &fcxp->nreq_sgles, &fcxp->req_sga_cbfn, + &fcxp->req_sglen_cbfn, &fcxp->req_sgpg_q, + nreq_sgles, req_sga_cbfn, req_sglen_cbfn); + + bfa_fcxp_init_reqrsp(fcxp, bfa, + &fcxp->use_irspbuf, &fcxp->nrsp_sgles, &fcxp->rsp_sga_cbfn, + &fcxp->rsp_sglen_cbfn, &fcxp->rsp_sgpg_q, + nrsp_sgles, rsp_sga_cbfn, rsp_sglen_cbfn); + +} + +static void +bfa_fcxp_put(struct bfa_fcxp_s *fcxp) +{ + struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod; + struct bfa_fcxp_wqe_s *wqe; + + bfa_q_deq(&mod->wait_q, &wqe); + if (wqe) { + bfa_trc(mod->bfa, fcxp->fcxp_tag); + + bfa_fcxp_init(fcxp, wqe->caller, wqe->bfa, wqe->nreq_sgles, + wqe->nrsp_sgles, wqe->req_sga_cbfn, + wqe->req_sglen_cbfn, wqe->rsp_sga_cbfn, + wqe->rsp_sglen_cbfn); + + wqe->alloc_cbfn(wqe->alloc_cbarg, fcxp); + return; + } + + bfa_assert(bfa_q_is_on_q(&mod->fcxp_active_q, fcxp)); + list_del(&fcxp->qe); + list_add_tail(&fcxp->qe, &mod->fcxp_free_q); +} + +static void +bfa_fcxp_null_comp(void *bfad_fcxp, struct bfa_fcxp_s *fcxp, void *cbarg, + bfa_status_t req_status, u32 rsp_len, + u32 resid_len, struct fchs_s *rsp_fchs) +{ + /* discarded fcxp completion */ +} + +static void +__bfa_fcxp_send_cbfn(void *cbarg, bfa_boolean_t complete) +{ + struct bfa_fcxp_s *fcxp = cbarg; + + if (complete) { + fcxp->send_cbfn(fcxp->caller, fcxp, fcxp->send_cbarg, + fcxp->rsp_status, fcxp->rsp_len, + fcxp->residue_len, &fcxp->rsp_fchs); + } else { + bfa_fcxp_free(fcxp); + } +} + +static void +hal_fcxp_send_comp(struct bfa_s *bfa, struct bfi_fcxp_send_rsp_s *fcxp_rsp) +{ + struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa); + struct bfa_fcxp_s *fcxp; + u16 fcxp_tag = bfa_os_ntohs(fcxp_rsp->fcxp_tag); + + bfa_trc(bfa, fcxp_tag); + + fcxp_rsp->rsp_len = bfa_os_ntohl(fcxp_rsp->rsp_len); + + /** + * @todo f/w should not set residue to non-0 when everything + * is received. + */ + if (fcxp_rsp->req_status == BFA_STATUS_OK) + fcxp_rsp->residue_len = 0; + else + fcxp_rsp->residue_len = bfa_os_ntohl(fcxp_rsp->residue_len); + + fcxp = BFA_FCXP_FROM_TAG(mod, fcxp_tag); + + bfa_assert(fcxp->send_cbfn != NULL); + + hal_fcxp_rx_plog(mod->bfa, fcxp, fcxp_rsp); + + if (fcxp->send_cbfn != NULL) { + bfa_trc(mod->bfa, (NULL == fcxp->caller)); + if (fcxp->caller == NULL) { + fcxp->send_cbfn(fcxp->caller, fcxp, fcxp->send_cbarg, + fcxp_rsp->req_status, fcxp_rsp->rsp_len, + fcxp_rsp->residue_len, &fcxp_rsp->fchs); + /* + * fcxp automatically freed on return from the callback + */ + bfa_fcxp_free(fcxp); + } else { + fcxp->rsp_status = fcxp_rsp->req_status; + fcxp->rsp_len = fcxp_rsp->rsp_len; + fcxp->residue_len = fcxp_rsp->residue_len; + fcxp->rsp_fchs = fcxp_rsp->fchs; + + bfa_cb_queue(bfa, &fcxp->hcb_qe, + __bfa_fcxp_send_cbfn, fcxp); + } + } else { + bfa_trc(bfa, (NULL == fcxp->send_cbfn)); + } +} + +static void +hal_fcxp_set_local_sges(struct bfi_sge_s *sge, u32 reqlen, u64 req_pa) +{ + union bfi_addr_u sga_zero = { {0} }; + + sge->sg_len = reqlen; + sge->flags = BFI_SGE_DATA_LAST; + bfa_dma_addr_set(sge[0].sga, req_pa); + bfa_sge_to_be(sge); + sge++; + + sge->sga = sga_zero; + sge->sg_len = reqlen; + sge->flags = BFI_SGE_PGDLEN; + bfa_sge_to_be(sge); +} + +static void +hal_fcxp_tx_plog(struct bfa_s *bfa, u32 reqlen, struct bfa_fcxp_s *fcxp, + struct fchs_s *fchs) +{ + /* + * TODO: TX ox_id + */ + if (reqlen > 0) { + if (fcxp->use_ireqbuf) { + u32 pld_w0 = + *((u32 *) BFA_FCXP_REQ_PLD(fcxp)); + + bfa_plog_fchdr_and_pl(bfa->plog, BFA_PL_MID_HAL_FCXP, + BFA_PL_EID_TX, + reqlen + sizeof(struct fchs_s), fchs, + pld_w0); + } else { + bfa_plog_fchdr(bfa->plog, BFA_PL_MID_HAL_FCXP, + BFA_PL_EID_TX, + reqlen + sizeof(struct fchs_s), + fchs); + } + } else { + bfa_plog_fchdr(bfa->plog, BFA_PL_MID_HAL_FCXP, BFA_PL_EID_TX, + reqlen + sizeof(struct fchs_s), fchs); + } +} + +static void +hal_fcxp_rx_plog(struct bfa_s *bfa, struct bfa_fcxp_s *fcxp, + struct bfi_fcxp_send_rsp_s *fcxp_rsp) +{ + if (fcxp_rsp->rsp_len > 0) { + if (fcxp->use_irspbuf) { + u32 pld_w0 = + *((u32 *) BFA_FCXP_RSP_PLD(fcxp)); + + bfa_plog_fchdr_and_pl(bfa->plog, BFA_PL_MID_HAL_FCXP, + BFA_PL_EID_RX, + (u16) fcxp_rsp->rsp_len, + &fcxp_rsp->fchs, pld_w0); + } else { + bfa_plog_fchdr(bfa->plog, BFA_PL_MID_HAL_FCXP, + BFA_PL_EID_RX, + (u16) fcxp_rsp->rsp_len, + &fcxp_rsp->fchs); + } + } else { + bfa_plog_fchdr(bfa->plog, BFA_PL_MID_HAL_FCXP, BFA_PL_EID_RX, + (u16) fcxp_rsp->rsp_len, &fcxp_rsp->fchs); + } +} + +/** + * Handler to resume sending fcxp when space in available in cpe queue. + */ +static void +bfa_fcxp_qresume(void *cbarg) +{ + struct bfa_fcxp_s *fcxp = cbarg; + struct bfa_s *bfa = fcxp->fcxp_mod->bfa; + struct bfi_fcxp_send_req_s *send_req; + + fcxp->reqq_waiting = BFA_FALSE; + send_req = bfa_reqq_next(bfa, BFA_REQQ_FCXP); + bfa_fcxp_queue(fcxp, send_req); +} + +/** + * Queue fcxp send request to foimrware. + */ +static void +bfa_fcxp_queue(struct bfa_fcxp_s *fcxp, struct bfi_fcxp_send_req_s *send_req) +{ + struct bfa_s *bfa = fcxp->fcxp_mod->bfa; + struct bfa_fcxp_req_info_s *reqi = &fcxp->req_info; + struct bfa_fcxp_rsp_info_s *rspi = &fcxp->rsp_info; + struct bfa_rport_s *rport = reqi->bfa_rport; + + bfi_h2i_set(send_req->mh, BFI_MC_FCXP, BFI_FCXP_H2I_SEND_REQ, + bfa_lpuid(bfa)); + + send_req->fcxp_tag = bfa_os_htons(fcxp->fcxp_tag); + if (rport) { + send_req->rport_fw_hndl = rport->fw_handle; + send_req->max_frmsz = bfa_os_htons(rport->rport_info.max_frmsz); + if (send_req->max_frmsz == 0) + send_req->max_frmsz = bfa_os_htons(FC_MAX_PDUSZ); + } else { + send_req->rport_fw_hndl = 0; + send_req->max_frmsz = bfa_os_htons(FC_MAX_PDUSZ); + } + + send_req->vf_id = bfa_os_htons(reqi->vf_id); + send_req->lp_tag = reqi->lp_tag; + send_req->class = reqi->class; + send_req->rsp_timeout = rspi->rsp_timeout; + send_req->cts = reqi->cts; + send_req->fchs = reqi->fchs; + + send_req->req_len = bfa_os_htonl(reqi->req_tot_len); + send_req->rsp_maxlen = bfa_os_htonl(rspi->rsp_maxlen); + + /* + * setup req sgles + */ + if (fcxp->use_ireqbuf == 1) { + hal_fcxp_set_local_sges(send_req->req_sge, reqi->req_tot_len, + BFA_FCXP_REQ_PLD_PA(fcxp)); + } else { + if (fcxp->nreq_sgles > 0) { + bfa_assert(fcxp->nreq_sgles == 1); + hal_fcxp_set_local_sges(send_req->req_sge, + reqi->req_tot_len, + fcxp->req_sga_cbfn(fcxp->caller, + 0)); + } else { + bfa_assert(reqi->req_tot_len == 0); + hal_fcxp_set_local_sges(send_req->rsp_sge, 0, 0); + } + } + + /* + * setup rsp sgles + */ + if (fcxp->use_irspbuf == 1) { + bfa_assert(rspi->rsp_maxlen <= BFA_FCXP_MAX_LBUF_SZ); + + hal_fcxp_set_local_sges(send_req->rsp_sge, rspi->rsp_maxlen, + BFA_FCXP_RSP_PLD_PA(fcxp)); + + } else { + if (fcxp->nrsp_sgles > 0) { + bfa_assert(fcxp->nrsp_sgles == 1); + hal_fcxp_set_local_sges(send_req->rsp_sge, + rspi->rsp_maxlen, + fcxp->rsp_sga_cbfn(fcxp->caller, + 0)); + } else { + bfa_assert(rspi->rsp_maxlen == 0); + hal_fcxp_set_local_sges(send_req->rsp_sge, 0, 0); + } + } + + hal_fcxp_tx_plog(bfa, reqi->req_tot_len, fcxp, &reqi->fchs); + + bfa_reqq_produce(bfa, BFA_REQQ_FCXP); + + bfa_trc(bfa, bfa_reqq_pi(bfa, BFA_REQQ_FCXP)); + bfa_trc(bfa, bfa_reqq_ci(bfa, BFA_REQQ_FCXP)); +} + +/** + * hal_fcxp_api BFA FCXP API + */ + +/** + * Allocate an FCXP instance to send a response or to send a request + * that has a response. Request/response buffers are allocated by caller. + * + * @param[in] bfa BFA bfa instance + * @param[in] nreq_sgles Number of SG elements required for request + * buffer. 0, if fcxp internal buffers are used. + * Use bfa_fcxp_get_reqbuf() to get the + * internal req buffer. + * @param[in] req_sgles SG elements describing request buffer. Will be + * copied in by BFA and hence can be freed on + * return from this function. + * @param[in] get_req_sga function ptr to be called to get a request SG + * Address (given the sge index). + * @param[in] get_req_sglen function ptr to be called to get a request SG + * len (given the sge index). + * @param[in] get_rsp_sga function ptr to be called to get a response SG + * Address (given the sge index). + * @param[in] get_rsp_sglen function ptr to be called to get a response SG + * len (given the sge index). + * + * @return FCXP instance. NULL on failure. + */ +struct bfa_fcxp_s * +bfa_fcxp_alloc(void *caller, struct bfa_s *bfa, int nreq_sgles, + int nrsp_sgles, bfa_fcxp_get_sgaddr_t req_sga_cbfn, + bfa_fcxp_get_sglen_t req_sglen_cbfn, + bfa_fcxp_get_sgaddr_t rsp_sga_cbfn, + bfa_fcxp_get_sglen_t rsp_sglen_cbfn) +{ + struct bfa_fcxp_s *fcxp = NULL; + + bfa_assert(bfa != NULL); + + fcxp = bfa_fcxp_get(BFA_FCXP_MOD(bfa)); + if (fcxp == NULL) + return NULL; + + bfa_trc(bfa, fcxp->fcxp_tag); + + bfa_fcxp_init(fcxp, caller, bfa, nreq_sgles, nrsp_sgles, req_sga_cbfn, + req_sglen_cbfn, rsp_sga_cbfn, rsp_sglen_cbfn); + + return fcxp; +} + +/** + * Get the internal request buffer pointer + * + * @param[in] fcxp BFA fcxp pointer + * + * @return pointer to the internal request buffer + */ +void * +bfa_fcxp_get_reqbuf(struct bfa_fcxp_s *fcxp) +{ + struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod; + void *reqbuf; + + bfa_assert(fcxp->use_ireqbuf == 1); + reqbuf = ((u8 *)mod->req_pld_list_kva) + + fcxp->fcxp_tag * mod->req_pld_sz; + return reqbuf; +} + +u32 +bfa_fcxp_get_reqbufsz(struct bfa_fcxp_s *fcxp) +{ + struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod; + + return mod->req_pld_sz; +} + +/** + * Get the internal response buffer pointer + * + * @param[in] fcxp BFA fcxp pointer + * + * @return pointer to the internal request buffer + */ +void * +bfa_fcxp_get_rspbuf(struct bfa_fcxp_s *fcxp) +{ + struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod; + void *rspbuf; + + bfa_assert(fcxp->use_irspbuf == 1); + + rspbuf = ((u8 *)mod->rsp_pld_list_kva) + + fcxp->fcxp_tag * mod->rsp_pld_sz; + return rspbuf; +} + +/** + * Free the BFA FCXP + * + * @param[in] fcxp BFA fcxp pointer + * + * @return void + */ +void +bfa_fcxp_free(struct bfa_fcxp_s *fcxp) +{ + struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod; + + bfa_assert(fcxp != NULL); + bfa_trc(mod->bfa, fcxp->fcxp_tag); + bfa_fcxp_put(fcxp); +} + +/** + * Send a FCXP request + * + * @param[in] fcxp BFA fcxp pointer + * @param[in] rport BFA rport pointer. Could be left NULL for WKA rports + * @param[in] vf_id virtual Fabric ID + * @param[in] lp_tag lport tag + * @param[in] cts use Continous sequence + * @param[in] cos fc Class of Service + * @param[in] reqlen request length, does not include FCHS length + * @param[in] fchs fc Header Pointer. The header content will be copied + * in by BFA. + * + * @param[in] cbfn call back function to be called on receiving + * the response + * @param[in] cbarg arg for cbfn + * @param[in] rsp_timeout + * response timeout + * + * @return bfa_status_t + */ +void +bfa_fcxp_send(struct bfa_fcxp_s *fcxp, struct bfa_rport_s *rport, + u16 vf_id, u8 lp_tag, bfa_boolean_t cts, enum fc_cos cos, + u32 reqlen, struct fchs_s *fchs, bfa_cb_fcxp_send_t cbfn, + void *cbarg, u32 rsp_maxlen, u8 rsp_timeout) +{ + struct bfa_s *bfa = fcxp->fcxp_mod->bfa; + struct bfa_fcxp_req_info_s *reqi = &fcxp->req_info; + struct bfa_fcxp_rsp_info_s *rspi = &fcxp->rsp_info; + struct bfi_fcxp_send_req_s *send_req; + + bfa_trc(bfa, fcxp->fcxp_tag); + + /** + * setup request/response info + */ + reqi->bfa_rport = rport; + reqi->vf_id = vf_id; + reqi->lp_tag = lp_tag; + reqi->class = cos; + rspi->rsp_timeout = rsp_timeout; + reqi->cts = cts; + reqi->fchs = *fchs; + reqi->req_tot_len = reqlen; + rspi->rsp_maxlen = rsp_maxlen; + fcxp->send_cbfn = cbfn ? cbfn : bfa_fcxp_null_comp; + fcxp->send_cbarg = cbarg; + + /** + * If no room in CPE queue, wait for space in request queue + */ + send_req = bfa_reqq_next(bfa, BFA_REQQ_FCXP); + if (!send_req) { + bfa_trc(bfa, fcxp->fcxp_tag); + fcxp->reqq_waiting = BFA_TRUE; + bfa_reqq_wait(bfa, BFA_REQQ_FCXP, &fcxp->reqq_wqe); + return; + } + + bfa_fcxp_queue(fcxp, send_req); +} + +/** + * Abort a BFA FCXP + * + * @param[in] fcxp BFA fcxp pointer + * + * @return void + */ +bfa_status_t +bfa_fcxp_abort(struct bfa_fcxp_s *fcxp) +{ + bfa_trc(fcxp->fcxp_mod->bfa, fcxp->fcxp_tag); + bfa_assert(0); + return BFA_STATUS_OK; +} + +void +bfa_fcxp_alloc_wait(struct bfa_s *bfa, struct bfa_fcxp_wqe_s *wqe, + bfa_fcxp_alloc_cbfn_t alloc_cbfn, void *alloc_cbarg, + void *caller, int nreq_sgles, + int nrsp_sgles, bfa_fcxp_get_sgaddr_t req_sga_cbfn, + bfa_fcxp_get_sglen_t req_sglen_cbfn, + bfa_fcxp_get_sgaddr_t rsp_sga_cbfn, + bfa_fcxp_get_sglen_t rsp_sglen_cbfn) +{ + struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa); + + bfa_assert(list_empty(&mod->fcxp_free_q)); + + wqe->alloc_cbfn = alloc_cbfn; + wqe->alloc_cbarg = alloc_cbarg; + wqe->caller = caller; + wqe->bfa = bfa; + wqe->nreq_sgles = nreq_sgles; + wqe->nrsp_sgles = nrsp_sgles; + wqe->req_sga_cbfn = req_sga_cbfn; + wqe->req_sglen_cbfn = req_sglen_cbfn; + wqe->rsp_sga_cbfn = rsp_sga_cbfn; + wqe->rsp_sglen_cbfn = rsp_sglen_cbfn; + + list_add_tail(&wqe->qe, &mod->wait_q); +} + +void +bfa_fcxp_walloc_cancel(struct bfa_s *bfa, struct bfa_fcxp_wqe_s *wqe) +{ + struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa); + + bfa_assert(bfa_q_is_on_q(&mod->wait_q, wqe)); + list_del(&wqe->qe); +} + +void +bfa_fcxp_discard(struct bfa_fcxp_s *fcxp) +{ + /** + * If waiting for room in request queue, cancel reqq wait + * and free fcxp. + */ + if (fcxp->reqq_waiting) { + fcxp->reqq_waiting = BFA_FALSE; + bfa_reqq_wcancel(&fcxp->reqq_wqe); + bfa_fcxp_free(fcxp); + return; + } + + fcxp->send_cbfn = bfa_fcxp_null_comp; +} + + + +/** + * hal_fcxp_public BFA FCXP public functions + */ + +void +bfa_fcxp_isr(struct bfa_s *bfa, struct bfi_msg_s *msg) +{ + switch (msg->mhdr.msg_id) { + case BFI_FCXP_I2H_SEND_RSP: + hal_fcxp_send_comp(bfa, (struct bfi_fcxp_send_rsp_s *) msg); + break; + + default: + bfa_trc(bfa, msg->mhdr.msg_id); + bfa_assert(0); + } +} + +u32 +bfa_fcxp_get_maxrsp(struct bfa_s *bfa) +{ + struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa); + + return mod->rsp_pld_sz; +} + + +/** + * BFA LPS state machine functions + */ + +/** + * Init state -- no login + */ +static void +bfa_lps_sm_init(struct bfa_lps_s *lps, enum bfa_lps_event event) +{ + bfa_trc(lps->bfa, lps->lp_tag); + bfa_trc(lps->bfa, event); + + switch (event) { + case BFA_LPS_SM_LOGIN: + if (bfa_reqq_full(lps->bfa, lps->reqq)) { + bfa_sm_set_state(lps, bfa_lps_sm_loginwait); + bfa_reqq_wait(lps->bfa, lps->reqq, &lps->wqe); + } else { + bfa_sm_set_state(lps, bfa_lps_sm_login); + bfa_lps_send_login(lps); + } + + if (lps->fdisc) + bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS, + BFA_PL_EID_LOGIN, 0, "FDISC Request"); + else + bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS, + BFA_PL_EID_LOGIN, 0, "FLOGI Request"); + break; + + case BFA_LPS_SM_LOGOUT: + bfa_lps_logout_comp(lps); + break; + + case BFA_LPS_SM_DELETE: + bfa_lps_free(lps); + break; + + case BFA_LPS_SM_RX_CVL: + case BFA_LPS_SM_OFFLINE: + break; + + case BFA_LPS_SM_FWRSP: + /* + * Could happen when fabric detects loopback and discards + * the lps request. Fw will eventually sent out the timeout + * Just ignore + */ + break; + + default: + bfa_sm_fault(lps->bfa, event); + } +} + +/** + * login is in progress -- awaiting response from firmware + */ +static void +bfa_lps_sm_login(struct bfa_lps_s *lps, enum bfa_lps_event event) +{ + bfa_trc(lps->bfa, lps->lp_tag); + bfa_trc(lps->bfa, event); + + switch (event) { + case BFA_LPS_SM_FWRSP: + if (lps->status == BFA_STATUS_OK) { + bfa_sm_set_state(lps, bfa_lps_sm_online); + if (lps->fdisc) + bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS, + BFA_PL_EID_LOGIN, 0, "FDISC Accept"); + else + bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS, + BFA_PL_EID_LOGIN, 0, "FLOGI Accept"); + } else { + bfa_sm_set_state(lps, bfa_lps_sm_init); + if (lps->fdisc) + bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS, + BFA_PL_EID_LOGIN, 0, + "FDISC Fail (RJT or timeout)"); + else + bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS, + BFA_PL_EID_LOGIN, 0, + "FLOGI Fail (RJT or timeout)"); + } + bfa_lps_login_comp(lps); + break; + + case BFA_LPS_SM_OFFLINE: + bfa_sm_set_state(lps, bfa_lps_sm_init); + break; + + default: + bfa_sm_fault(lps->bfa, event); + } +} + +/** + * login pending - awaiting space in request queue + */ +static void +bfa_lps_sm_loginwait(struct bfa_lps_s *lps, enum bfa_lps_event event) +{ + bfa_trc(lps->bfa, lps->lp_tag); + bfa_trc(lps->bfa, event); + + switch (event) { + case BFA_LPS_SM_RESUME: + bfa_sm_set_state(lps, bfa_lps_sm_login); + break; + + case BFA_LPS_SM_OFFLINE: + bfa_sm_set_state(lps, bfa_lps_sm_init); + bfa_reqq_wcancel(&lps->wqe); + break; + + case BFA_LPS_SM_RX_CVL: + /* + * Login was not even sent out; so when getting out + * of this state, it will appear like a login retry + * after Clear virtual link + */ + break; + + default: + bfa_sm_fault(lps->bfa, event); + } +} + +/** + * login complete + */ +static void +bfa_lps_sm_online(struct bfa_lps_s *lps, enum bfa_lps_event event) +{ + bfa_trc(lps->bfa, lps->lp_tag); + bfa_trc(lps->bfa, event); + + switch (event) { + case BFA_LPS_SM_LOGOUT: + if (bfa_reqq_full(lps->bfa, lps->reqq)) { + bfa_sm_set_state(lps, bfa_lps_sm_logowait); + bfa_reqq_wait(lps->bfa, lps->reqq, &lps->wqe); + } else { + bfa_sm_set_state(lps, bfa_lps_sm_logout); + bfa_lps_send_logout(lps); + } + bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS, + BFA_PL_EID_LOGO, 0, "Logout"); + break; + + case BFA_LPS_SM_RX_CVL: + bfa_sm_set_state(lps, bfa_lps_sm_init); + + /* Let the vport module know about this event */ + bfa_lps_cvl_event(lps); + bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS, + BFA_PL_EID_FIP_FCF_CVL, 0, "FCF Clear Virt. Link Rx"); + break; + + case BFA_LPS_SM_OFFLINE: + case BFA_LPS_SM_DELETE: + bfa_sm_set_state(lps, bfa_lps_sm_init); + break; + + default: + bfa_sm_fault(lps->bfa, event); + } +} + +/** + * logout in progress - awaiting firmware response + */ +static void +bfa_lps_sm_logout(struct bfa_lps_s *lps, enum bfa_lps_event event) +{ + bfa_trc(lps->bfa, lps->lp_tag); + bfa_trc(lps->bfa, event); + + switch (event) { + case BFA_LPS_SM_FWRSP: + bfa_sm_set_state(lps, bfa_lps_sm_init); + bfa_lps_logout_comp(lps); + break; + + case BFA_LPS_SM_OFFLINE: + bfa_sm_set_state(lps, bfa_lps_sm_init); + break; + + default: + bfa_sm_fault(lps->bfa, event); + } +} + +/** + * logout pending -- awaiting space in request queue + */ +static void +bfa_lps_sm_logowait(struct bfa_lps_s *lps, enum bfa_lps_event event) +{ + bfa_trc(lps->bfa, lps->lp_tag); + bfa_trc(lps->bfa, event); + + switch (event) { + case BFA_LPS_SM_RESUME: + bfa_sm_set_state(lps, bfa_lps_sm_logout); + bfa_lps_send_logout(lps); + break; + + case BFA_LPS_SM_OFFLINE: + bfa_sm_set_state(lps, bfa_lps_sm_init); + bfa_reqq_wcancel(&lps->wqe); + break; + + default: + bfa_sm_fault(lps->bfa, event); + } +} + + + +/** + * lps_pvt BFA LPS private functions + */ + +/** + * return memory requirement + */ +static void +bfa_lps_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len, + u32 *dm_len) +{ + if (cfg->drvcfg.min_cfg) + *ndm_len += sizeof(struct bfa_lps_s) * BFA_LPS_MIN_LPORTS; + else + *ndm_len += sizeof(struct bfa_lps_s) * BFA_LPS_MAX_LPORTS; +} + +/** + * bfa module attach at initialization time + */ +static void +bfa_lps_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, + struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev) +{ + struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa); + struct bfa_lps_s *lps; + int i; + + bfa_os_memset(mod, 0, sizeof(struct bfa_lps_mod_s)); + mod->num_lps = BFA_LPS_MAX_LPORTS; + if (cfg->drvcfg.min_cfg) + mod->num_lps = BFA_LPS_MIN_LPORTS; + else + mod->num_lps = BFA_LPS_MAX_LPORTS; + mod->lps_arr = lps = (struct bfa_lps_s *) bfa_meminfo_kva(meminfo); + + bfa_meminfo_kva(meminfo) += mod->num_lps * sizeof(struct bfa_lps_s); + + INIT_LIST_HEAD(&mod->lps_free_q); + INIT_LIST_HEAD(&mod->lps_active_q); + + for (i = 0; i < mod->num_lps; i++, lps++) { + lps->bfa = bfa; + lps->lp_tag = (u8) i; + lps->reqq = BFA_REQQ_LPS; + bfa_reqq_winit(&lps->wqe, bfa_lps_reqq_resume, lps); + list_add_tail(&lps->qe, &mod->lps_free_q); + } +} + +static void +bfa_lps_detach(struct bfa_s *bfa) +{ +} + +static void +bfa_lps_start(struct bfa_s *bfa) +{ +} + +static void +bfa_lps_stop(struct bfa_s *bfa) +{ +} + +/** + * IOC in disabled state -- consider all lps offline + */ +static void +bfa_lps_iocdisable(struct bfa_s *bfa) +{ + struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa); + struct bfa_lps_s *lps; + struct list_head *qe, *qen; + + list_for_each_safe(qe, qen, &mod->lps_active_q) { + lps = (struct bfa_lps_s *) qe; + bfa_sm_send_event(lps, BFA_LPS_SM_OFFLINE); + } +} + +/** + * Firmware login response + */ +static void +bfa_lps_login_rsp(struct bfa_s *bfa, struct bfi_lps_login_rsp_s *rsp) +{ + struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa); + struct bfa_lps_s *lps; + + bfa_assert(rsp->lp_tag < mod->num_lps); + lps = BFA_LPS_FROM_TAG(mod, rsp->lp_tag); + + lps->status = rsp->status; + switch (rsp->status) { + case BFA_STATUS_OK: + lps->fport = rsp->f_port; + lps->npiv_en = rsp->npiv_en; + lps->lp_pid = rsp->lp_pid; + lps->pr_bbcred = bfa_os_ntohs(rsp->bb_credit); + lps->pr_pwwn = rsp->port_name; + lps->pr_nwwn = rsp->node_name; + lps->auth_req = rsp->auth_req; + lps->lp_mac = rsp->lp_mac; + lps->brcd_switch = rsp->brcd_switch; + lps->fcf_mac = rsp->fcf_mac; + + break; + + case BFA_STATUS_FABRIC_RJT: + lps->lsrjt_rsn = rsp->lsrjt_rsn; + lps->lsrjt_expl = rsp->lsrjt_expl; + + break; + + case BFA_STATUS_EPROTOCOL: + lps->ext_status = rsp->ext_status; + + break; + + default: + /* Nothing to do with other status */ + break; + } + + bfa_sm_send_event(lps, BFA_LPS_SM_FWRSP); +} + +/** + * Firmware logout response + */ +static void +bfa_lps_logout_rsp(struct bfa_s *bfa, struct bfi_lps_logout_rsp_s *rsp) +{ + struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa); + struct bfa_lps_s *lps; + + bfa_assert(rsp->lp_tag < mod->num_lps); + lps = BFA_LPS_FROM_TAG(mod, rsp->lp_tag); + + bfa_sm_send_event(lps, BFA_LPS_SM_FWRSP); +} + +/** + * Firmware received a Clear virtual link request (for FCoE) + */ +static void +bfa_lps_rx_cvl_event(struct bfa_s *bfa, struct bfi_lps_cvl_event_s *cvl) +{ + struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa); + struct bfa_lps_s *lps; + + lps = BFA_LPS_FROM_TAG(mod, cvl->lp_tag); + + bfa_sm_send_event(lps, BFA_LPS_SM_RX_CVL); +} + +/** + * Space is available in request queue, resume queueing request to firmware. + */ +static void +bfa_lps_reqq_resume(void *lps_arg) +{ + struct bfa_lps_s *lps = lps_arg; + + bfa_sm_send_event(lps, BFA_LPS_SM_RESUME); +} + +/** + * lps is freed -- triggered by vport delete + */ +static void +bfa_lps_free(struct bfa_lps_s *lps) +{ + struct bfa_lps_mod_s *mod = BFA_LPS_MOD(lps->bfa); + + lps->lp_pid = 0; + list_del(&lps->qe); + list_add_tail(&lps->qe, &mod->lps_free_q); +} + +/** + * send login request to firmware + */ +static void +bfa_lps_send_login(struct bfa_lps_s *lps) +{ + struct bfi_lps_login_req_s *m; + + m = bfa_reqq_next(lps->bfa, lps->reqq); + bfa_assert(m); + + bfi_h2i_set(m->mh, BFI_MC_LPS, BFI_LPS_H2I_LOGIN_REQ, + bfa_lpuid(lps->bfa)); + + m->lp_tag = lps->lp_tag; + m->alpa = lps->alpa; + m->pdu_size = bfa_os_htons(lps->pdusz); + m->pwwn = lps->pwwn; + m->nwwn = lps->nwwn; + m->fdisc = lps->fdisc; + m->auth_en = lps->auth_en; + + bfa_reqq_produce(lps->bfa, lps->reqq); +} + +/** + * send logout request to firmware + */ +static void +bfa_lps_send_logout(struct bfa_lps_s *lps) +{ + struct bfi_lps_logout_req_s *m; + + m = bfa_reqq_next(lps->bfa, lps->reqq); + bfa_assert(m); + + bfi_h2i_set(m->mh, BFI_MC_LPS, BFI_LPS_H2I_LOGOUT_REQ, + bfa_lpuid(lps->bfa)); + + m->lp_tag = lps->lp_tag; + m->port_name = lps->pwwn; + bfa_reqq_produce(lps->bfa, lps->reqq); +} + +/** + * Indirect login completion handler for non-fcs + */ +static void +bfa_lps_login_comp_cb(void *arg, bfa_boolean_t complete) +{ + struct bfa_lps_s *lps = arg; + + if (!complete) + return; + + if (lps->fdisc) + bfa_cb_lps_fdisc_comp(lps->bfa->bfad, lps->uarg, lps->status); + else + bfa_cb_lps_flogi_comp(lps->bfa->bfad, lps->uarg, lps->status); +} + +/** + * Login completion handler -- direct call for fcs, queue for others + */ +static void +bfa_lps_login_comp(struct bfa_lps_s *lps) +{ + if (!lps->bfa->fcs) { + bfa_cb_queue(lps->bfa, &lps->hcb_qe, bfa_lps_login_comp_cb, + lps); + return; + } + + if (lps->fdisc) + bfa_cb_lps_fdisc_comp(lps->bfa->bfad, lps->uarg, lps->status); + else + bfa_cb_lps_flogi_comp(lps->bfa->bfad, lps->uarg, lps->status); +} + +/** + * Indirect logout completion handler for non-fcs + */ +static void +bfa_lps_logout_comp_cb(void *arg, bfa_boolean_t complete) +{ + struct bfa_lps_s *lps = arg; + + if (!complete) + return; + + if (lps->fdisc) + bfa_cb_lps_fdisclogo_comp(lps->bfa->bfad, lps->uarg); +} + +/** + * Logout completion handler -- direct call for fcs, queue for others + */ +static void +bfa_lps_logout_comp(struct bfa_lps_s *lps) +{ + if (!lps->bfa->fcs) { + bfa_cb_queue(lps->bfa, &lps->hcb_qe, bfa_lps_logout_comp_cb, + lps); + return; + } + if (lps->fdisc) + bfa_cb_lps_fdisclogo_comp(lps->bfa->bfad, lps->uarg); +} + +/** + * Clear virtual link completion handler for non-fcs + */ +static void +bfa_lps_cvl_event_cb(void *arg, bfa_boolean_t complete) +{ + struct bfa_lps_s *lps = arg; + + if (!complete) + return; + + /* Clear virtual link to base port will result in link down */ + if (lps->fdisc) + bfa_cb_lps_cvl_event(lps->bfa->bfad, lps->uarg); +} + +/** + * Received Clear virtual link event --direct call for fcs, + * queue for others + */ +static void +bfa_lps_cvl_event(struct bfa_lps_s *lps) +{ + if (!lps->bfa->fcs) { + bfa_cb_queue(lps->bfa, &lps->hcb_qe, bfa_lps_cvl_event_cb, + lps); + return; + } + + /* Clear virtual link to base port will result in link down */ + if (lps->fdisc) + bfa_cb_lps_cvl_event(lps->bfa->bfad, lps->uarg); +} + + + +/** + * lps_public BFA LPS public functions + */ + +u32 +bfa_lps_get_max_vport(struct bfa_s *bfa) +{ + if (bfa_ioc_devid(&bfa->ioc) == BFA_PCI_DEVICE_ID_CT) + return BFA_LPS_MAX_VPORTS_SUPP_CT; + else + return BFA_LPS_MAX_VPORTS_SUPP_CB; +} + +/** + * Allocate a lport srvice tag. + */ +struct bfa_lps_s * +bfa_lps_alloc(struct bfa_s *bfa) +{ + struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa); + struct bfa_lps_s *lps = NULL; + + bfa_q_deq(&mod->lps_free_q, &lps); + + if (lps == NULL) + return NULL; + + list_add_tail(&lps->qe, &mod->lps_active_q); + + bfa_sm_set_state(lps, bfa_lps_sm_init); + return lps; +} + +/** + * Free lport service tag. This can be called anytime after an alloc. + * No need to wait for any pending login/logout completions. + */ +void +bfa_lps_delete(struct bfa_lps_s *lps) +{ + bfa_sm_send_event(lps, BFA_LPS_SM_DELETE); +} + +/** + * Initiate a lport login. + */ +void +bfa_lps_flogi(struct bfa_lps_s *lps, void *uarg, u8 alpa, u16 pdusz, + wwn_t pwwn, wwn_t nwwn, bfa_boolean_t auth_en) +{ + lps->uarg = uarg; + lps->alpa = alpa; + lps->pdusz = pdusz; + lps->pwwn = pwwn; + lps->nwwn = nwwn; + lps->fdisc = BFA_FALSE; + lps->auth_en = auth_en; + bfa_sm_send_event(lps, BFA_LPS_SM_LOGIN); +} + +/** + * Initiate a lport fdisc login. + */ +void +bfa_lps_fdisc(struct bfa_lps_s *lps, void *uarg, u16 pdusz, wwn_t pwwn, + wwn_t nwwn) +{ + lps->uarg = uarg; + lps->alpa = 0; + lps->pdusz = pdusz; + lps->pwwn = pwwn; + lps->nwwn = nwwn; + lps->fdisc = BFA_TRUE; + lps->auth_en = BFA_FALSE; + bfa_sm_send_event(lps, BFA_LPS_SM_LOGIN); +} + +/** + * Initiate a lport logout (flogi). + */ +void +bfa_lps_flogo(struct bfa_lps_s *lps) +{ + bfa_sm_send_event(lps, BFA_LPS_SM_LOGOUT); +} + +/** + * Initiate a lport FDSIC logout. + */ +void +bfa_lps_fdisclogo(struct bfa_lps_s *lps) +{ + bfa_sm_send_event(lps, BFA_LPS_SM_LOGOUT); +} + +/** + * Discard a pending login request -- should be called only for + * link down handling. + */ +void +bfa_lps_discard(struct bfa_lps_s *lps) +{ + bfa_sm_send_event(lps, BFA_LPS_SM_OFFLINE); +} + +/** + * Return lport services tag + */ +u8 +bfa_lps_get_tag(struct bfa_lps_s *lps) +{ + return lps->lp_tag; +} + +/** + * Return lport services tag given the pid + */ +u8 +bfa_lps_get_tag_from_pid(struct bfa_s *bfa, u32 pid) +{ + struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa); + struct bfa_lps_s *lps; + int i; + + for (i = 0, lps = mod->lps_arr; i < mod->num_lps; i++, lps++) { + if (lps->lp_pid == pid) + return lps->lp_tag; + } + + /* Return base port tag anyway */ + return 0; +} + +/** + * return if fabric login indicates support for NPIV + */ +bfa_boolean_t +bfa_lps_is_npiv_en(struct bfa_lps_s *lps) +{ + return lps->npiv_en; +} + +/** + * Return TRUE if attached to F-Port, else return FALSE + */ +bfa_boolean_t +bfa_lps_is_fport(struct bfa_lps_s *lps) +{ + return lps->fport; +} + +/** + * Return TRUE if attached to a Brocade Fabric + */ +bfa_boolean_t +bfa_lps_is_brcd_fabric(struct bfa_lps_s *lps) +{ + return lps->brcd_switch; +} +/** + * return TRUE if authentication is required + */ +bfa_boolean_t +bfa_lps_is_authreq(struct bfa_lps_s *lps) +{ + return lps->auth_req; +} + +bfa_eproto_status_t +bfa_lps_get_extstatus(struct bfa_lps_s *lps) +{ + return lps->ext_status; +} + +/** + * return port id assigned to the lport + */ +u32 +bfa_lps_get_pid(struct bfa_lps_s *lps) +{ + return lps->lp_pid; +} + +/** + * return port id assigned to the base lport + */ +u32 +bfa_lps_get_base_pid(struct bfa_s *bfa) +{ + struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa); + + return BFA_LPS_FROM_TAG(mod, 0)->lp_pid; +} + +/** + * Return bb_credit assigned in FLOGI response + */ +u16 +bfa_lps_get_peer_bbcredit(struct bfa_lps_s *lps) +{ + return lps->pr_bbcred; +} + +/** + * Return peer port name + */ +wwn_t +bfa_lps_get_peer_pwwn(struct bfa_lps_s *lps) +{ + return lps->pr_pwwn; +} + +/** + * Return peer node name + */ +wwn_t +bfa_lps_get_peer_nwwn(struct bfa_lps_s *lps) +{ + return lps->pr_nwwn; +} + +/** + * return reason code if login request is rejected + */ +u8 +bfa_lps_get_lsrjt_rsn(struct bfa_lps_s *lps) +{ + return lps->lsrjt_rsn; +} + +/** + * return explanation code if login request is rejected + */ +u8 +bfa_lps_get_lsrjt_expl(struct bfa_lps_s *lps) +{ + return lps->lsrjt_expl; +} + +/** + * Return fpma/spma MAC for lport + */ +mac_t +bfa_lps_get_lp_mac(struct bfa_lps_s *lps) +{ + return lps->lp_mac; +} + +/** + * LPS firmware message class handler. + */ +void +bfa_lps_isr(struct bfa_s *bfa, struct bfi_msg_s *m) +{ + union bfi_lps_i2h_msg_u msg; + + bfa_trc(bfa, m->mhdr.msg_id); + msg.msg = m; + + switch (m->mhdr.msg_id) { + case BFI_LPS_H2I_LOGIN_RSP: + bfa_lps_login_rsp(bfa, msg.login_rsp); + break; + + case BFI_LPS_H2I_LOGOUT_RSP: + bfa_lps_logout_rsp(bfa, msg.logout_rsp); + break; + + case BFI_LPS_H2I_CVL_EVENT: + bfa_lps_rx_cvl_event(bfa, msg.cvl_event); + break; + + default: + bfa_trc(bfa, m->mhdr.msg_id); + bfa_assert(0); + } +} + +/** + * FC PORT state machine functions + */ +static void +bfa_fcport_sm_uninit(struct bfa_fcport_s *fcport, + enum bfa_fcport_sm_event event) +{ + bfa_trc(fcport->bfa, event); + + switch (event) { + case BFA_FCPORT_SM_START: + /** + * Start event after IOC is configured and BFA is started. + */ + if (bfa_fcport_send_enable(fcport)) { + bfa_trc(fcport->bfa, BFA_TRUE); + bfa_sm_set_state(fcport, bfa_fcport_sm_enabling); + } else { + bfa_trc(fcport->bfa, BFA_FALSE); + bfa_sm_set_state(fcport, + bfa_fcport_sm_enabling_qwait); + } + break; + + case BFA_FCPORT_SM_ENABLE: + /** + * Port is persistently configured to be in enabled state. Do + * not change state. Port enabling is done when START event is + * received. + */ + break; + + case BFA_FCPORT_SM_DISABLE: + /** + * If a port is persistently configured to be disabled, the + * first event will a port disable request. + */ + bfa_sm_set_state(fcport, bfa_fcport_sm_disabled); + break; + + case BFA_FCPORT_SM_HWFAIL: + bfa_sm_set_state(fcport, bfa_fcport_sm_iocdown); + break; + + default: + bfa_sm_fault(fcport->bfa, event); + } +} + +static void +bfa_fcport_sm_enabling_qwait(struct bfa_fcport_s *fcport, + enum bfa_fcport_sm_event event) +{ + char pwwn_buf[BFA_STRING_32]; + struct bfad_s *bfad = (struct bfad_s *)fcport->bfa->bfad; + bfa_trc(fcport->bfa, event); + + switch (event) { + case BFA_FCPORT_SM_QRESUME: + bfa_sm_set_state(fcport, bfa_fcport_sm_enabling); + bfa_fcport_send_enable(fcport); + break; + + case BFA_FCPORT_SM_STOP: + bfa_reqq_wcancel(&fcport->reqq_wait); + bfa_sm_set_state(fcport, bfa_fcport_sm_stopped); + break; + + case BFA_FCPORT_SM_ENABLE: + /** + * Already enable is in progress. + */ + break; + + case BFA_FCPORT_SM_DISABLE: + /** + * Just send disable request to firmware when room becomes + * available in request queue. + */ + bfa_sm_set_state(fcport, bfa_fcport_sm_disabled); + bfa_reqq_wcancel(&fcport->reqq_wait); + bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL, + BFA_PL_EID_PORT_DISABLE, 0, "Port Disable"); + wwn2str(pwwn_buf, fcport->pwwn); + BFA_LOG(KERN_INFO, bfad, log_level, + "Base port disabled: WWN = %s\n", pwwn_buf); + break; + + case BFA_FCPORT_SM_LINKUP: + case BFA_FCPORT_SM_LINKDOWN: + /** + * Possible to get link events when doing back-to-back + * enable/disables. + */ + break; + + case BFA_FCPORT_SM_HWFAIL: + bfa_reqq_wcancel(&fcport->reqq_wait); + bfa_sm_set_state(fcport, bfa_fcport_sm_iocdown); + break; + + default: + bfa_sm_fault(fcport->bfa, event); + } +} + +static void +bfa_fcport_sm_enabling(struct bfa_fcport_s *fcport, + enum bfa_fcport_sm_event event) +{ + char pwwn_buf[BFA_STRING_32]; + struct bfad_s *bfad = (struct bfad_s *)fcport->bfa->bfad; + bfa_trc(fcport->bfa, event); + + switch (event) { + case BFA_FCPORT_SM_FWRSP: + case BFA_FCPORT_SM_LINKDOWN: + bfa_sm_set_state(fcport, bfa_fcport_sm_linkdown); + break; + + case BFA_FCPORT_SM_LINKUP: + bfa_fcport_update_linkinfo(fcport); + bfa_sm_set_state(fcport, bfa_fcport_sm_linkup); + + bfa_assert(fcport->event_cbfn); + bfa_fcport_scn(fcport, BFA_PORT_LINKUP, BFA_FALSE); + break; + + case BFA_FCPORT_SM_ENABLE: + /** + * Already being enabled. + */ + break; + + case BFA_FCPORT_SM_DISABLE: + if (bfa_fcport_send_disable(fcport)) + bfa_sm_set_state(fcport, bfa_fcport_sm_disabling); + else + bfa_sm_set_state(fcport, + bfa_fcport_sm_disabling_qwait); + + bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL, + BFA_PL_EID_PORT_DISABLE, 0, "Port Disable"); + wwn2str(pwwn_buf, fcport->pwwn); + BFA_LOG(KERN_INFO, bfad, log_level, + "Base port disabled: WWN = %s\n", pwwn_buf); + break; + + case BFA_FCPORT_SM_STOP: + bfa_sm_set_state(fcport, bfa_fcport_sm_stopped); + break; + + case BFA_FCPORT_SM_HWFAIL: + bfa_sm_set_state(fcport, bfa_fcport_sm_iocdown); + break; + + default: + bfa_sm_fault(fcport->bfa, event); + } +} + +static void +bfa_fcport_sm_linkdown(struct bfa_fcport_s *fcport, + enum bfa_fcport_sm_event event) +{ + struct bfi_fcport_event_s *pevent = fcport->event_arg.i2hmsg.event; + char pwwn_buf[BFA_STRING_32]; + struct bfad_s *bfad = (struct bfad_s *)fcport->bfa->bfad; + + bfa_trc(fcport->bfa, event); + + switch (event) { + case BFA_FCPORT_SM_LINKUP: + bfa_fcport_update_linkinfo(fcport); + bfa_sm_set_state(fcport, bfa_fcport_sm_linkup); + bfa_assert(fcport->event_cbfn); + bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL, + BFA_PL_EID_PORT_ST_CHANGE, 0, "Port Linkup"); + if (!bfa_ioc_get_fcmode(&fcport->bfa->ioc)) { + + 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.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"); + else + bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL, + BFA_PL_EID_FIP_FCF_DISC, 0, + "FIP FCF Discovered"); + } + + bfa_fcport_scn(fcport, BFA_PORT_LINKUP, BFA_FALSE); + wwn2str(pwwn_buf, fcport->pwwn); + BFA_LOG(KERN_INFO, bfad, log_level, + "Base port online: WWN = %s\n", pwwn_buf); + break; + + case BFA_FCPORT_SM_LINKDOWN: + /** + * Possible to get link down event. + */ + break; + + case BFA_FCPORT_SM_ENABLE: + /** + * Already enabled. + */ + break; + + case BFA_FCPORT_SM_DISABLE: + if (bfa_fcport_send_disable(fcport)) + bfa_sm_set_state(fcport, bfa_fcport_sm_disabling); + else + bfa_sm_set_state(fcport, + bfa_fcport_sm_disabling_qwait); + + bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL, + BFA_PL_EID_PORT_DISABLE, 0, "Port Disable"); + wwn2str(pwwn_buf, fcport->pwwn); + BFA_LOG(KERN_INFO, bfad, log_level, + "Base port disabled: WWN = %s\n", pwwn_buf); + break; + + case BFA_FCPORT_SM_STOP: + bfa_sm_set_state(fcport, bfa_fcport_sm_stopped); + break; + + case BFA_FCPORT_SM_HWFAIL: + bfa_sm_set_state(fcport, bfa_fcport_sm_iocdown); + break; + + default: + bfa_sm_fault(fcport->bfa, event); + } +} + +static void +bfa_fcport_sm_linkup(struct bfa_fcport_s *fcport, + enum bfa_fcport_sm_event event) +{ + char pwwn_buf[BFA_STRING_32]; + struct bfad_s *bfad = (struct bfad_s *)fcport->bfa->bfad; + + bfa_trc(fcport->bfa, event); + + switch (event) { + case BFA_FCPORT_SM_ENABLE: + /** + * Already enabled. + */ + break; + + case BFA_FCPORT_SM_DISABLE: + if (bfa_fcport_send_disable(fcport)) + bfa_sm_set_state(fcport, bfa_fcport_sm_disabling); + else + bfa_sm_set_state(fcport, + bfa_fcport_sm_disabling_qwait); + + bfa_fcport_reset_linkinfo(fcport); + bfa_fcport_scn(fcport, BFA_PORT_LINKDOWN, BFA_FALSE); + bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL, + BFA_PL_EID_PORT_DISABLE, 0, "Port Disable"); + wwn2str(pwwn_buf, fcport->pwwn); + BFA_LOG(KERN_INFO, bfad, log_level, + "Base port offline: WWN = %s\n", pwwn_buf); + BFA_LOG(KERN_INFO, bfad, log_level, + "Base port disabled: WWN = %s\n", pwwn_buf); + break; + + case BFA_FCPORT_SM_LINKDOWN: + bfa_sm_set_state(fcport, bfa_fcport_sm_linkdown); + bfa_fcport_reset_linkinfo(fcport); + bfa_fcport_scn(fcport, BFA_PORT_LINKDOWN, BFA_FALSE); + bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL, + BFA_PL_EID_PORT_ST_CHANGE, 0, "Port Linkdown"); + wwn2str(pwwn_buf, fcport->pwwn); + if (BFA_PORT_IS_DISABLED(fcport->bfa)) + BFA_LOG(KERN_INFO, bfad, log_level, + "Base port offline: WWN = %s\n", pwwn_buf); + else + BFA_LOG(KERN_ERR, bfad, log_level, + "Base port (WWN = %s) " + "lost fabric connectivity\n", pwwn_buf); + break; + + case BFA_FCPORT_SM_STOP: + bfa_sm_set_state(fcport, bfa_fcport_sm_stopped); + bfa_fcport_reset_linkinfo(fcport); + wwn2str(pwwn_buf, fcport->pwwn); + if (BFA_PORT_IS_DISABLED(fcport->bfa)) + BFA_LOG(KERN_INFO, bfad, log_level, + "Base port offline: WWN = %s\n", pwwn_buf); + else + BFA_LOG(KERN_ERR, bfad, log_level, + "Base port (WWN = %s) " + "lost fabric connectivity\n", pwwn_buf); + break; + + case BFA_FCPORT_SM_HWFAIL: + bfa_sm_set_state(fcport, bfa_fcport_sm_iocdown); + bfa_fcport_reset_linkinfo(fcport); + bfa_fcport_scn(fcport, BFA_PORT_LINKDOWN, BFA_FALSE); + wwn2str(pwwn_buf, fcport->pwwn); + if (BFA_PORT_IS_DISABLED(fcport->bfa)) + BFA_LOG(KERN_INFO, bfad, log_level, + "Base port offline: WWN = %s\n", pwwn_buf); + else + BFA_LOG(KERN_ERR, bfad, log_level, + "Base port (WWN = %s) " + "lost fabric connectivity\n", pwwn_buf); + break; + + default: + bfa_sm_fault(fcport->bfa, event); + } +} + +static void +bfa_fcport_sm_disabling_qwait(struct bfa_fcport_s *fcport, + enum bfa_fcport_sm_event event) +{ + bfa_trc(fcport->bfa, event); + + switch (event) { + case BFA_FCPORT_SM_QRESUME: + bfa_sm_set_state(fcport, bfa_fcport_sm_disabling); + bfa_fcport_send_disable(fcport); + break; + + case BFA_FCPORT_SM_STOP: + bfa_sm_set_state(fcport, bfa_fcport_sm_stopped); + bfa_reqq_wcancel(&fcport->reqq_wait); + break; + + case BFA_FCPORT_SM_ENABLE: + bfa_sm_set_state(fcport, bfa_fcport_sm_toggling_qwait); + break; + + case BFA_FCPORT_SM_DISABLE: + /** + * Already being disabled. + */ + break; + + case BFA_FCPORT_SM_LINKUP: + case BFA_FCPORT_SM_LINKDOWN: + /** + * Possible to get link events when doing back-to-back + * enable/disables. + */ + break; + + case BFA_FCPORT_SM_HWFAIL: + bfa_sm_set_state(fcport, bfa_fcport_sm_iocfail); + bfa_reqq_wcancel(&fcport->reqq_wait); + break; + + default: + bfa_sm_fault(fcport->bfa, event); + } +} + +static void +bfa_fcport_sm_toggling_qwait(struct bfa_fcport_s *fcport, + enum bfa_fcport_sm_event event) +{ + bfa_trc(fcport->bfa, event); + + switch (event) { + case BFA_FCPORT_SM_QRESUME: + bfa_sm_set_state(fcport, bfa_fcport_sm_disabling); + bfa_fcport_send_disable(fcport); + if (bfa_fcport_send_enable(fcport)) + bfa_sm_set_state(fcport, bfa_fcport_sm_enabling); + else + bfa_sm_set_state(fcport, + bfa_fcport_sm_enabling_qwait); + break; + + case BFA_FCPORT_SM_STOP: + bfa_sm_set_state(fcport, bfa_fcport_sm_stopped); + bfa_reqq_wcancel(&fcport->reqq_wait); + break; + + case BFA_FCPORT_SM_ENABLE: + break; + + case BFA_FCPORT_SM_DISABLE: + bfa_sm_set_state(fcport, bfa_fcport_sm_disabling_qwait); + break; + + case BFA_FCPORT_SM_LINKUP: + case BFA_FCPORT_SM_LINKDOWN: + /** + * Possible to get link events when doing back-to-back + * enable/disables. + */ + break; + + case BFA_FCPORT_SM_HWFAIL: + bfa_sm_set_state(fcport, bfa_fcport_sm_iocfail); + bfa_reqq_wcancel(&fcport->reqq_wait); + break; + + default: + bfa_sm_fault(fcport->bfa, event); + } +} + +static void +bfa_fcport_sm_disabling(struct bfa_fcport_s *fcport, + enum bfa_fcport_sm_event event) +{ + char pwwn_buf[BFA_STRING_32]; + struct bfad_s *bfad = (struct bfad_s *)fcport->bfa->bfad; + bfa_trc(fcport->bfa, event); + + switch (event) { + case BFA_FCPORT_SM_FWRSP: + bfa_sm_set_state(fcport, bfa_fcport_sm_disabled); + break; + + case BFA_FCPORT_SM_DISABLE: + /** + * Already being disabled. + */ + break; + + case BFA_FCPORT_SM_ENABLE: + if (bfa_fcport_send_enable(fcport)) + bfa_sm_set_state(fcport, bfa_fcport_sm_enabling); + else + bfa_sm_set_state(fcport, + bfa_fcport_sm_enabling_qwait); + + bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL, + BFA_PL_EID_PORT_ENABLE, 0, "Port Enable"); + wwn2str(pwwn_buf, fcport->pwwn); + BFA_LOG(KERN_INFO, bfad, log_level, + "Base port enabled: WWN = %s\n", pwwn_buf); + break; + + case BFA_FCPORT_SM_STOP: + bfa_sm_set_state(fcport, bfa_fcport_sm_stopped); + break; + + case BFA_FCPORT_SM_LINKUP: + case BFA_FCPORT_SM_LINKDOWN: + /** + * Possible to get link events when doing back-to-back + * enable/disables. + */ + break; + + case BFA_FCPORT_SM_HWFAIL: + bfa_sm_set_state(fcport, bfa_fcport_sm_iocfail); + break; + + default: + bfa_sm_fault(fcport->bfa, event); + } +} + +static void +bfa_fcport_sm_disabled(struct bfa_fcport_s *fcport, + enum bfa_fcport_sm_event event) +{ + char pwwn_buf[BFA_STRING_32]; + struct bfad_s *bfad = (struct bfad_s *)fcport->bfa->bfad; + bfa_trc(fcport->bfa, event); + + switch (event) { + case BFA_FCPORT_SM_START: + /** + * Ignore start event for a port that is disabled. + */ + break; + + case BFA_FCPORT_SM_STOP: + bfa_sm_set_state(fcport, bfa_fcport_sm_stopped); + break; + + case BFA_FCPORT_SM_ENABLE: + if (bfa_fcport_send_enable(fcport)) + bfa_sm_set_state(fcport, bfa_fcport_sm_enabling); + else + bfa_sm_set_state(fcport, + bfa_fcport_sm_enabling_qwait); + + bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL, + BFA_PL_EID_PORT_ENABLE, 0, "Port Enable"); + wwn2str(pwwn_buf, fcport->pwwn); + BFA_LOG(KERN_INFO, bfad, log_level, + "Base port enabled: WWN = %s\n", pwwn_buf); + break; + + case BFA_FCPORT_SM_DISABLE: + /** + * Already disabled. + */ + break; + + case BFA_FCPORT_SM_HWFAIL: + bfa_sm_set_state(fcport, bfa_fcport_sm_iocfail); + break; + + default: + bfa_sm_fault(fcport->bfa, event); + } +} + +static void +bfa_fcport_sm_stopped(struct bfa_fcport_s *fcport, + enum bfa_fcport_sm_event event) +{ + bfa_trc(fcport->bfa, event); + + switch (event) { + case BFA_FCPORT_SM_START: + if (bfa_fcport_send_enable(fcport)) + bfa_sm_set_state(fcport, bfa_fcport_sm_enabling); + else + bfa_sm_set_state(fcport, + bfa_fcport_sm_enabling_qwait); + break; + + default: + /** + * Ignore all other events. + */ + ; + } +} + +/** + * Port is enabled. IOC is down/failed. + */ +static void +bfa_fcport_sm_iocdown(struct bfa_fcport_s *fcport, + enum bfa_fcport_sm_event event) +{ + bfa_trc(fcport->bfa, event); + + switch (event) { + case BFA_FCPORT_SM_START: + if (bfa_fcport_send_enable(fcport)) + bfa_sm_set_state(fcport, bfa_fcport_sm_enabling); + else + bfa_sm_set_state(fcport, + bfa_fcport_sm_enabling_qwait); + break; + + default: + /** + * Ignore all events. + */ + ; + } +} + +/** + * Port is disabled. IOC is down/failed. + */ +static void +bfa_fcport_sm_iocfail(struct bfa_fcport_s *fcport, + enum bfa_fcport_sm_event event) +{ + bfa_trc(fcport->bfa, event); + + switch (event) { + case BFA_FCPORT_SM_START: + bfa_sm_set_state(fcport, bfa_fcport_sm_disabled); + break; + + case BFA_FCPORT_SM_ENABLE: + bfa_sm_set_state(fcport, bfa_fcport_sm_iocdown); + break; + + default: + /** + * Ignore all events. + */ + ; + } +} + +/** + * Link state is down + */ +static void +bfa_fcport_ln_sm_dn(struct bfa_fcport_ln_s *ln, + enum bfa_fcport_ln_sm_event event) +{ + bfa_trc(ln->fcport->bfa, event); + + switch (event) { + case BFA_FCPORT_LN_SM_LINKUP: + bfa_sm_set_state(ln, bfa_fcport_ln_sm_up_nf); + bfa_fcport_queue_cb(ln, BFA_PORT_LINKUP); + break; + + default: + bfa_sm_fault(ln->fcport->bfa, event); + } +} + +/** + * Link state is waiting for down notification + */ +static void +bfa_fcport_ln_sm_dn_nf(struct bfa_fcport_ln_s *ln, + enum bfa_fcport_ln_sm_event event) +{ + bfa_trc(ln->fcport->bfa, event); + + switch (event) { + case BFA_FCPORT_LN_SM_LINKUP: + bfa_sm_set_state(ln, bfa_fcport_ln_sm_dn_up_nf); + break; + + case BFA_FCPORT_LN_SM_NOTIFICATION: + bfa_sm_set_state(ln, bfa_fcport_ln_sm_dn); + break; + + default: + bfa_sm_fault(ln->fcport->bfa, event); + } +} + +/** + * Link state is waiting for down notification and there is a pending up + */ +static void +bfa_fcport_ln_sm_dn_up_nf(struct bfa_fcport_ln_s *ln, + enum bfa_fcport_ln_sm_event event) +{ + bfa_trc(ln->fcport->bfa, event); + + switch (event) { + case BFA_FCPORT_LN_SM_LINKDOWN: + bfa_sm_set_state(ln, bfa_fcport_ln_sm_dn_nf); + break; + + case BFA_FCPORT_LN_SM_NOTIFICATION: + bfa_sm_set_state(ln, bfa_fcport_ln_sm_up_nf); + bfa_fcport_queue_cb(ln, BFA_PORT_LINKUP); + break; + + default: + bfa_sm_fault(ln->fcport->bfa, event); + } +} + +/** + * Link state is up + */ +static void +bfa_fcport_ln_sm_up(struct bfa_fcport_ln_s *ln, + enum bfa_fcport_ln_sm_event event) +{ + bfa_trc(ln->fcport->bfa, event); + + switch (event) { + case BFA_FCPORT_LN_SM_LINKDOWN: + bfa_sm_set_state(ln, bfa_fcport_ln_sm_dn_nf); + bfa_fcport_queue_cb(ln, BFA_PORT_LINKDOWN); + break; + + default: + bfa_sm_fault(ln->fcport->bfa, event); + } +} + +/** + * Link state is waiting for up notification + */ +static void +bfa_fcport_ln_sm_up_nf(struct bfa_fcport_ln_s *ln, + enum bfa_fcport_ln_sm_event event) +{ + bfa_trc(ln->fcport->bfa, event); + + switch (event) { + case BFA_FCPORT_LN_SM_LINKDOWN: + bfa_sm_set_state(ln, bfa_fcport_ln_sm_up_dn_nf); + break; + + case BFA_FCPORT_LN_SM_NOTIFICATION: + bfa_sm_set_state(ln, bfa_fcport_ln_sm_up); + break; + + default: + bfa_sm_fault(ln->fcport->bfa, event); + } +} + +/** + * Link state is waiting for up notification and there is a pending down + */ +static void +bfa_fcport_ln_sm_up_dn_nf(struct bfa_fcport_ln_s *ln, + enum bfa_fcport_ln_sm_event event) +{ + bfa_trc(ln->fcport->bfa, event); + + switch (event) { + case BFA_FCPORT_LN_SM_LINKUP: + bfa_sm_set_state(ln, bfa_fcport_ln_sm_up_dn_up_nf); + break; + + case BFA_FCPORT_LN_SM_NOTIFICATION: + bfa_sm_set_state(ln, bfa_fcport_ln_sm_dn_nf); + bfa_fcport_queue_cb(ln, BFA_PORT_LINKDOWN); + break; + + default: + bfa_sm_fault(ln->fcport->bfa, event); + } +} + +/** + * Link state is waiting for up notification and there are pending down and up + */ +static void +bfa_fcport_ln_sm_up_dn_up_nf(struct bfa_fcport_ln_s *ln, + enum bfa_fcport_ln_sm_event event) +{ + bfa_trc(ln->fcport->bfa, event); + + switch (event) { + case BFA_FCPORT_LN_SM_LINKDOWN: + bfa_sm_set_state(ln, bfa_fcport_ln_sm_up_dn_nf); + break; + + case BFA_FCPORT_LN_SM_NOTIFICATION: + bfa_sm_set_state(ln, bfa_fcport_ln_sm_dn_up_nf); + bfa_fcport_queue_cb(ln, BFA_PORT_LINKDOWN); + break; + + default: + bfa_sm_fault(ln->fcport->bfa, event); + } +} + + + +/** + * hal_port_private + */ + +static void +__bfa_cb_fcport_event(void *cbarg, bfa_boolean_t complete) +{ + struct bfa_fcport_ln_s *ln = cbarg; + + if (complete) + ln->fcport->event_cbfn(ln->fcport->event_cbarg, ln->ln_event); + else + bfa_sm_send_event(ln, BFA_FCPORT_LN_SM_NOTIFICATION); +} + +/** + * Send SCN notification to upper layers. + * trunk - false if caller is fcport to ignore fcport event in trunked mode + */ +static void +bfa_fcport_scn(struct bfa_fcport_s *fcport, enum bfa_port_linkstate event, + bfa_boolean_t trunk) +{ + if (fcport->cfg.trunked && !trunk) + return; + + switch (event) { + case BFA_PORT_LINKUP: + bfa_sm_send_event(&fcport->ln, BFA_FCPORT_LN_SM_LINKUP); + break; + case BFA_PORT_LINKDOWN: + bfa_sm_send_event(&fcport->ln, BFA_FCPORT_LN_SM_LINKDOWN); + break; + default: + bfa_assert(0); + } +} + +static void +bfa_fcport_queue_cb(struct bfa_fcport_ln_s *ln, enum bfa_port_linkstate event) +{ + struct bfa_fcport_s *fcport = ln->fcport; + + if (fcport->bfa->fcs) { + fcport->event_cbfn(fcport->event_cbarg, event); + bfa_sm_send_event(ln, BFA_FCPORT_LN_SM_NOTIFICATION); + } else { + ln->ln_event = event; + bfa_cb_queue(fcport->bfa, &ln->ln_qe, + __bfa_cb_fcport_event, ln); + } +} + +#define FCPORT_STATS_DMA_SZ (BFA_ROUNDUP(sizeof(union bfa_fcport_stats_u), \ + BFA_CACHELINE_SZ)) + +static void +bfa_fcport_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len, + u32 *dm_len) +{ + *dm_len += FCPORT_STATS_DMA_SZ; +} + +static void +bfa_fcport_qresume(void *cbarg) +{ + struct bfa_fcport_s *fcport = cbarg; + + bfa_sm_send_event(fcport, BFA_FCPORT_SM_QRESUME); +} + +static void +bfa_fcport_mem_claim(struct bfa_fcport_s *fcport, struct bfa_meminfo_s *meminfo) +{ + u8 *dm_kva; + u64 dm_pa; + + dm_kva = bfa_meminfo_dma_virt(meminfo); + dm_pa = bfa_meminfo_dma_phys(meminfo); + + fcport->stats_kva = dm_kva; + fcport->stats_pa = dm_pa; + fcport->stats = (union bfa_fcport_stats_u *) dm_kva; + + dm_kva += FCPORT_STATS_DMA_SZ; + dm_pa += FCPORT_STATS_DMA_SZ; + + bfa_meminfo_dma_virt(meminfo) = dm_kva; + bfa_meminfo_dma_phys(meminfo) = dm_pa; +} + +/** + * Memory initialization. + */ +static void +bfa_fcport_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, + struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev) +{ + struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); + struct bfa_port_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; + ln->fcport = fcport; + + bfa_fcport_mem_claim(fcport, meminfo); + + 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 + */ + port_cfg->topology = BFA_PORT_TOPOLOGY_P2P; + port_cfg->speed = BFA_PORT_SPEED_AUTO; + port_cfg->trunked = BFA_FALSE; + port_cfg->maxfrsize = 0; + + port_cfg->trl_def_speed = BFA_PORT_SPEED_1GBPS; + + bfa_reqq_winit(&fcport->reqq_wait, bfa_fcport_qresume, fcport); +} + +static void +bfa_fcport_detach(struct bfa_s *bfa) +{ +} + +/** + * Called when IOC is ready. + */ +static void +bfa_fcport_start(struct bfa_s *bfa) +{ + bfa_sm_send_event(BFA_FCPORT_MOD(bfa), BFA_FCPORT_SM_START); +} + +/** + * Called before IOC is stopped. + */ +static void +bfa_fcport_stop(struct bfa_s *bfa) +{ + bfa_sm_send_event(BFA_FCPORT_MOD(bfa), BFA_FCPORT_SM_STOP); + bfa_trunk_iocdisable(bfa); +} + +/** + * Called when IOC failure is detected. + */ +static void +bfa_fcport_iocdisable(struct bfa_s *bfa) +{ + struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); + + bfa_sm_send_event(fcport, BFA_FCPORT_SM_HWFAIL); + bfa_trunk_iocdisable(bfa); +} + +static void +bfa_fcport_update_linkinfo(struct bfa_fcport_s *fcport) +{ + struct bfi_fcport_event_s *pevent = fcport->event_arg.i2hmsg.event; + struct bfa_fcport_trunk_s *trunk = &fcport->trunk; + + fcport->speed = pevent->link_state.speed; + fcport->topology = pevent->link_state.topology; + + if (fcport->topology == BFA_PORT_TOPOLOGY_LOOP) + 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.vc_fcf.qos_vc_attr); + + /** + * update trunk state if applicable + */ + if (!fcport->cfg.trunked) + trunk->attr.state = BFA_TRUNK_DISABLED; + + /* update FCoE specific */ + fcport->fcoe_vlan = bfa_os_ntohs(pevent->link_state.vc_fcf.fcf.vlan); + + bfa_trc(fcport->bfa, fcport->speed); + bfa_trc(fcport->bfa, fcport->topology); +} + +static void +bfa_fcport_reset_linkinfo(struct bfa_fcport_s *fcport) +{ + fcport->speed = BFA_PORT_SPEED_UNKNOWN; + fcport->topology = BFA_PORT_TOPOLOGY_NONE; +} + +/** + * Send port enable message to firmware. + */ +static bfa_boolean_t +bfa_fcport_send_enable(struct bfa_fcport_s *fcport) +{ + struct bfi_fcport_enable_req_s *m; + + /** + * Increment message tag before queue check, so that responses to old + * requests are discarded. + */ + fcport->msgtag++; + + /** + * check for room in queue to send request now + */ + m = bfa_reqq_next(fcport->bfa, BFA_REQQ_PORT); + if (!m) { + bfa_reqq_wait(fcport->bfa, BFA_REQQ_PORT, + &fcport->reqq_wait); + return BFA_FALSE; + } + + bfi_h2i_set(m->mh, BFI_MC_FCPORT, BFI_FCPORT_H2I_ENABLE_REQ, + bfa_lpuid(fcport->bfa)); + m->nwwn = fcport->nwwn; + m->pwwn = fcport->pwwn; + m->port_cfg = fcport->cfg; + m->msgtag = fcport->msgtag; + m->port_cfg.maxfrsize = bfa_os_htons(fcport->cfg.maxfrsize); + bfa_dma_be_addr_set(m->stats_dma_addr, fcport->stats_pa); + bfa_trc(fcport->bfa, m->stats_dma_addr.a32.addr_lo); + bfa_trc(fcport->bfa, m->stats_dma_addr.a32.addr_hi); + + /** + * queue I/O message to firmware + */ + bfa_reqq_produce(fcport->bfa, BFA_REQQ_PORT); + return BFA_TRUE; +} + +/** + * Send port disable message to firmware. + */ +static bfa_boolean_t +bfa_fcport_send_disable(struct bfa_fcport_s *fcport) +{ + struct bfi_fcport_req_s *m; + + /** + * Increment message tag before queue check, so that responses to old + * requests are discarded. + */ + fcport->msgtag++; + + /** + * check for room in queue to send request now + */ + m = bfa_reqq_next(fcport->bfa, BFA_REQQ_PORT); + if (!m) { + bfa_reqq_wait(fcport->bfa, BFA_REQQ_PORT, + &fcport->reqq_wait); + return BFA_FALSE; + } + + bfi_h2i_set(m->mh, BFI_MC_FCPORT, BFI_FCPORT_H2I_DISABLE_REQ, + bfa_lpuid(fcport->bfa)); + m->msgtag = fcport->msgtag; + + /** + * queue I/O message to firmware + */ + bfa_reqq_produce(fcport->bfa, BFA_REQQ_PORT); + + return BFA_TRUE; +} + +static void +bfa_fcport_set_wwns(struct bfa_fcport_s *fcport) +{ + fcport->pwwn = bfa_ioc_get_pwwn(&fcport->bfa->ioc); + fcport->nwwn = bfa_ioc_get_nwwn(&fcport->bfa->ioc); + + bfa_trc(fcport->bfa, fcport->pwwn); + bfa_trc(fcport->bfa, fcport->nwwn); +} + +static void +bfa_fcport_send_txcredit(void *port_cbarg) +{ + + struct bfa_fcport_s *fcport = port_cbarg; + struct bfi_fcport_set_svc_params_req_s *m; + + /** + * check for room in queue to send request now + */ + m = bfa_reqq_next(fcport->bfa, BFA_REQQ_PORT); + if (!m) { + bfa_trc(fcport->bfa, fcport->cfg.tx_bbcredit); + return; + } + + bfi_h2i_set(m->mh, BFI_MC_FCPORT, BFI_FCPORT_H2I_SET_SVC_PARAMS_REQ, + bfa_lpuid(fcport->bfa)); + m->tx_bbcredit = bfa_os_htons((u16)fcport->cfg.tx_bbcredit); + + /** + * queue I/O message to firmware + */ + bfa_reqq_produce(fcport->bfa, BFA_REQQ_PORT); +} + +static void +bfa_fcport_qos_stats_swap(struct bfa_qos_stats_s *d, + struct bfa_qos_stats_s *s) +{ + u32 *dip = (u32 *) d; + u32 *sip = (u32 *) s; + int i; + + /* Now swap the 32 bit fields */ + for (i = 0; i < (sizeof(struct bfa_qos_stats_s)/sizeof(u32)); ++i) + dip[i] = bfa_os_ntohl(sip[i]); +} + +static void +bfa_fcport_fcoe_stats_swap(struct bfa_fcoe_stats_s *d, + struct bfa_fcoe_stats_s *s) +{ + u32 *dip = (u32 *) d; + u32 *sip = (u32 *) s; + int i; + + for (i = 0; i < ((sizeof(struct bfa_fcoe_stats_s))/sizeof(u32)); + i = i + 2) { +#ifdef __BIGENDIAN + dip[i] = bfa_os_ntohl(sip[i]); + dip[i + 1] = bfa_os_ntohl(sip[i + 1]); +#else + dip[i] = bfa_os_ntohl(sip[i + 1]); + dip[i + 1] = bfa_os_ntohl(sip[i]); +#endif + } +} + +static void +__bfa_cb_fcport_stats_get(void *cbarg, bfa_boolean_t complete) +{ + struct bfa_fcport_s *fcport = cbarg; + + 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)) { + bfa_fcport_qos_stats_swap( + &fcport->stats_ret->fcqos, + &fcport->stats->fcqos); + } 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 { + fcport->stats_busy = BFA_FALSE; + fcport->stats_status = BFA_STATUS_OK; + } +} + +static void +bfa_fcport_stats_get_timeout(void *cbarg) +{ + struct bfa_fcport_s *fcport = (struct bfa_fcport_s *) cbarg; + + bfa_trc(fcport->bfa, fcport->stats_qfull); + + if (fcport->stats_qfull) { + bfa_reqq_wcancel(&fcport->stats_reqq_wait); + fcport->stats_qfull = BFA_FALSE; + } + + fcport->stats_status = BFA_STATUS_ETIMER; + bfa_cb_queue(fcport->bfa, &fcport->hcb_qe, __bfa_cb_fcport_stats_get, + fcport); +} + +static void +bfa_fcport_send_stats_get(void *cbarg) +{ + struct bfa_fcport_s *fcport = (struct bfa_fcport_s *) cbarg; + struct bfi_fcport_req_s *msg; + + msg = bfa_reqq_next(fcport->bfa, BFA_REQQ_PORT); + + if (!msg) { + fcport->stats_qfull = BFA_TRUE; + bfa_reqq_winit(&fcport->stats_reqq_wait, + bfa_fcport_send_stats_get, fcport); + bfa_reqq_wait(fcport->bfa, BFA_REQQ_PORT, + &fcport->stats_reqq_wait); + return; + } + fcport->stats_qfull = BFA_FALSE; + + bfa_os_memset(msg, 0, sizeof(struct bfi_fcport_req_s)); + bfi_h2i_set(msg->mh, BFI_MC_FCPORT, BFI_FCPORT_H2I_STATS_GET_REQ, + bfa_lpuid(fcport->bfa)); + bfa_reqq_produce(fcport->bfa, BFA_REQQ_PORT); +} + +static void +__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; + fcport->stats_status = BFA_STATUS_OK; + } +} + +static void +bfa_fcport_stats_clr_timeout(void *cbarg) +{ + struct bfa_fcport_s *fcport = (struct bfa_fcport_s *) cbarg; + + bfa_trc(fcport->bfa, fcport->stats_qfull); + + if (fcport->stats_qfull) { + bfa_reqq_wcancel(&fcport->stats_reqq_wait); + fcport->stats_qfull = BFA_FALSE; + } + + fcport->stats_status = BFA_STATUS_ETIMER; + bfa_cb_queue(fcport->bfa, &fcport->hcb_qe, + __bfa_cb_fcport_stats_clr, fcport); +} + +static void +bfa_fcport_send_stats_clear(void *cbarg) +{ + struct bfa_fcport_s *fcport = (struct bfa_fcport_s *) cbarg; + struct bfi_fcport_req_s *msg; + + msg = bfa_reqq_next(fcport->bfa, BFA_REQQ_PORT); + + if (!msg) { + fcport->stats_qfull = BFA_TRUE; + bfa_reqq_winit(&fcport->stats_reqq_wait, + bfa_fcport_send_stats_clear, fcport); + bfa_reqq_wait(fcport->bfa, BFA_REQQ_PORT, + &fcport->stats_reqq_wait); + return; + } + fcport->stats_qfull = BFA_FALSE; + + bfa_os_memset(msg, 0, sizeof(struct bfi_fcport_req_s)); + bfi_h2i_set(msg->mh, BFI_MC_FCPORT, BFI_FCPORT_H2I_STATS_CLEAR_REQ, + bfa_lpuid(fcport->bfa)); + bfa_reqq_produce(fcport->bfa, BFA_REQQ_PORT); +} + +/** + * Handle trunk SCN event from firmware. + */ +static void +bfa_trunk_scn(struct bfa_fcport_s *fcport, struct bfi_fcport_trunk_scn_s *scn) +{ + struct bfa_fcport_trunk_s *trunk = &fcport->trunk; + struct bfi_fcport_trunk_link_s *tlink; + struct bfa_trunk_link_attr_s *lattr; + enum bfa_trunk_state state_prev; + int i; + int link_bm = 0; + + bfa_trc(fcport->bfa, fcport->cfg.trunked); + bfa_assert(scn->trunk_state == BFA_TRUNK_ONLINE || + scn->trunk_state == BFA_TRUNK_OFFLINE); + + bfa_trc(fcport->bfa, trunk->attr.state); + bfa_trc(fcport->bfa, scn->trunk_state); + bfa_trc(fcport->bfa, scn->trunk_speed); + + /** + * Save off new state for trunk attribute query + */ + state_prev = trunk->attr.state; + if (fcport->cfg.trunked && (trunk->attr.state != BFA_TRUNK_DISABLED)) + trunk->attr.state = scn->trunk_state; + trunk->attr.speed = scn->trunk_speed; + for (i = 0; i < BFA_TRUNK_MAX_PORTS; i++) { + lattr = &trunk->attr.link_attr[i]; + tlink = &scn->tlink[i]; + + lattr->link_state = tlink->state; + lattr->trunk_wwn = tlink->trunk_wwn; + lattr->fctl = tlink->fctl; + lattr->speed = tlink->speed; + lattr->deskew = bfa_os_ntohl(tlink->deskew); + + if (tlink->state == BFA_TRUNK_LINK_STATE_UP) { + fcport->speed = tlink->speed; + fcport->topology = BFA_PORT_TOPOLOGY_P2P; + link_bm |= 1 << i; + } + + bfa_trc(fcport->bfa, lattr->link_state); + bfa_trc(fcport->bfa, lattr->trunk_wwn); + bfa_trc(fcport->bfa, lattr->fctl); + bfa_trc(fcport->bfa, lattr->speed); + bfa_trc(fcport->bfa, lattr->deskew); + } + + switch (link_bm) { + case 3: + bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL, + BFA_PL_EID_TRUNK_SCN, 0, "Trunk up(0,1)"); + break; + case 2: + bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL, + BFA_PL_EID_TRUNK_SCN, 0, "Trunk up(-,1)"); + break; + case 1: + bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL, + BFA_PL_EID_TRUNK_SCN, 0, "Trunk up(0,-)"); + break; + default: + bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL, + BFA_PL_EID_TRUNK_SCN, 0, "Trunk down"); + } + + /** + * Notify upper layers if trunk state changed. + */ + if ((state_prev != trunk->attr.state) || + (scn->trunk_state == BFA_TRUNK_OFFLINE)) { + bfa_fcport_scn(fcport, (scn->trunk_state == BFA_TRUNK_ONLINE) ? + BFA_PORT_LINKUP : BFA_PORT_LINKDOWN, BFA_TRUE); + } +} + +static void +bfa_trunk_iocdisable(struct bfa_s *bfa) +{ + struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); + int i = 0; + + /** + * In trunked mode, notify upper layers that link is down + */ + if (fcport->cfg.trunked) { + if (fcport->trunk.attr.state == BFA_TRUNK_ONLINE) + bfa_fcport_scn(fcport, BFA_PORT_LINKDOWN, BFA_TRUE); + + fcport->trunk.attr.state = BFA_TRUNK_OFFLINE; + fcport->trunk.attr.speed = BFA_PORT_SPEED_UNKNOWN; + for (i = 0; i < BFA_TRUNK_MAX_PORTS; i++) { + fcport->trunk.attr.link_attr[i].trunk_wwn = 0; + fcport->trunk.attr.link_attr[i].fctl = + BFA_TRUNK_LINK_FCTL_NORMAL; + fcport->trunk.attr.link_attr[i].link_state = + BFA_TRUNK_LINK_STATE_DN_LINKDN; + fcport->trunk.attr.link_attr[i].speed = + BFA_PORT_SPEED_UNKNOWN; + fcport->trunk.attr.link_attr[i].deskew = 0; + } + } +} + + + +/** + * hal_port_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. + */ +void +bfa_fcport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg) +{ + struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); + union bfi_fcport_i2h_msg_u i2hmsg; + + i2hmsg.msg = msg; + fcport->event_arg.i2hmsg = i2hmsg; + + bfa_trc(bfa, msg->mhdr.msg_id); + bfa_trc(bfa, bfa_sm_to_state(hal_port_sm_table, fcport->sm)); + + switch (msg->mhdr.msg_id) { + case BFI_FCPORT_I2H_ENABLE_RSP: + if (fcport->msgtag == i2hmsg.penable_rsp->msgtag) + bfa_sm_send_event(fcport, BFA_FCPORT_SM_FWRSP); + break; + + case BFI_FCPORT_I2H_DISABLE_RSP: + if (fcport->msgtag == i2hmsg.penable_rsp->msgtag) + bfa_sm_send_event(fcport, BFA_FCPORT_SM_FWRSP); + break; + + case BFI_FCPORT_I2H_EVENT: + if (i2hmsg.event->link_state.linkstate == BFA_PORT_LINKUP) + bfa_sm_send_event(fcport, BFA_FCPORT_SM_LINKUP); + else + bfa_sm_send_event(fcport, BFA_FCPORT_SM_LINKDOWN); + break; + + case BFI_FCPORT_I2H_TRUNK_SCN: + bfa_trunk_scn(fcport, i2hmsg.trunk_scn); + break; + + case BFI_FCPORT_I2H_STATS_GET_RSP: + /* + * check for timer pop before processing the rsp + */ + if (fcport->stats_busy == BFA_FALSE || + fcport->stats_status == BFA_STATUS_ETIMER) + break; + + bfa_timer_stop(&fcport->timer); + fcport->stats_status = i2hmsg.pstatsget_rsp->status; + bfa_cb_queue(fcport->bfa, &fcport->hcb_qe, + __bfa_cb_fcport_stats_get, fcport); + break; + + case BFI_FCPORT_I2H_STATS_CLEAR_RSP: + /* + * check for timer pop before processing the rsp + */ + if (fcport->stats_busy == BFA_FALSE || + fcport->stats_status == BFA_STATUS_ETIMER) + break; + + bfa_timer_stop(&fcport->timer); + fcport->stats_status = BFA_STATUS_OK; + bfa_cb_queue(fcport->bfa, &fcport->hcb_qe, + __bfa_cb_fcport_stats_clr, fcport); + break; + + case BFI_FCPORT_I2H_ENABLE_AEN: + bfa_sm_send_event(fcport, BFA_FCPORT_SM_ENABLE); + break; + + case BFI_FCPORT_I2H_DISABLE_AEN: + bfa_sm_send_event(fcport, BFA_FCPORT_SM_DISABLE); + break; + + default: + bfa_assert(0); + break; + } +} + + + +/** + * hal_port_api + */ + +/** + * Registered callback for port events. + */ +void +bfa_fcport_event_register(struct bfa_s *bfa, + void (*cbfn) (void *cbarg, + enum bfa_port_linkstate event), + void *cbarg) +{ + struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); + + fcport->event_cbfn = cbfn; + fcport->event_cbarg = cbarg; +} + +bfa_status_t +bfa_fcport_enable(struct bfa_s *bfa) +{ + struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); + + if (bfa_ioc_is_disabled(&bfa->ioc)) + return BFA_STATUS_IOC_DISABLED; + + if (fcport->diag_busy) + return BFA_STATUS_DIAG_BUSY; + + bfa_sm_send_event(BFA_FCPORT_MOD(bfa), BFA_FCPORT_SM_ENABLE); + return BFA_STATUS_OK; +} + +bfa_status_t +bfa_fcport_disable(struct bfa_s *bfa) +{ + + if (bfa_ioc_is_disabled(&bfa->ioc)) + return BFA_STATUS_IOC_DISABLED; + + bfa_sm_send_event(BFA_FCPORT_MOD(bfa), BFA_FCPORT_SM_DISABLE); + return BFA_STATUS_OK; +} + +/** + * Configure port speed. + */ +bfa_status_t +bfa_fcport_cfg_speed(struct bfa_s *bfa, enum bfa_port_speed speed) +{ + struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); + + bfa_trc(bfa, speed); + + if (fcport->cfg.trunked == BFA_TRUE) + return BFA_STATUS_TRUNK_ENABLED; + if ((speed != BFA_PORT_SPEED_AUTO) && (speed > fcport->speed_sup)) { + bfa_trc(bfa, fcport->speed_sup); + return BFA_STATUS_UNSUPP_SPEED; + } + + fcport->cfg.speed = speed; + + return BFA_STATUS_OK; +} + +/** + * Get current speed. + */ +enum bfa_port_speed +bfa_fcport_get_speed(struct bfa_s *bfa) +{ + struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); + + return fcport->speed; +} + +/** + * Configure port topology. + */ +bfa_status_t +bfa_fcport_cfg_topology(struct bfa_s *bfa, enum bfa_port_topology topology) +{ + struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); + + bfa_trc(bfa, topology); + bfa_trc(bfa, fcport->cfg.topology); + + switch (topology) { + case BFA_PORT_TOPOLOGY_P2P: + case BFA_PORT_TOPOLOGY_LOOP: + case BFA_PORT_TOPOLOGY_AUTO: + break; + + default: + return BFA_STATUS_EINVAL; + } + + fcport->cfg.topology = topology; + return BFA_STATUS_OK; +} + +/** + * Get current topology. + */ +enum bfa_port_topology +bfa_fcport_get_topology(struct bfa_s *bfa) +{ + struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); + + return fcport->topology; +} + +bfa_status_t +bfa_fcport_cfg_hardalpa(struct bfa_s *bfa, u8 alpa) +{ + struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); + + bfa_trc(bfa, alpa); + bfa_trc(bfa, fcport->cfg.cfg_hardalpa); + bfa_trc(bfa, fcport->cfg.hardalpa); + + fcport->cfg.cfg_hardalpa = BFA_TRUE; + fcport->cfg.hardalpa = alpa; + + return BFA_STATUS_OK; +} + +bfa_status_t +bfa_fcport_clr_hardalpa(struct bfa_s *bfa) +{ + struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); + + bfa_trc(bfa, fcport->cfg.cfg_hardalpa); + bfa_trc(bfa, fcport->cfg.hardalpa); + + fcport->cfg.cfg_hardalpa = BFA_FALSE; + return BFA_STATUS_OK; +} + +bfa_boolean_t +bfa_fcport_get_hardalpa(struct bfa_s *bfa, u8 *alpa) +{ + struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); + + *alpa = fcport->cfg.hardalpa; + return fcport->cfg.cfg_hardalpa; +} + +u8 +bfa_fcport_get_myalpa(struct bfa_s *bfa) +{ + struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); + + return fcport->myalpa; +} + +bfa_status_t +bfa_fcport_cfg_maxfrsize(struct bfa_s *bfa, u16 maxfrsize) +{ + struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); + + bfa_trc(bfa, maxfrsize); + bfa_trc(bfa, fcport->cfg.maxfrsize); + + /* with in range */ + if ((maxfrsize > FC_MAX_PDUSZ) || (maxfrsize < FC_MIN_PDUSZ)) + return BFA_STATUS_INVLD_DFSZ; + + /* power of 2, if not the max frame size of 2112 */ + if ((maxfrsize != FC_MAX_PDUSZ) && (maxfrsize & (maxfrsize - 1))) + return BFA_STATUS_INVLD_DFSZ; + + fcport->cfg.maxfrsize = maxfrsize; + return BFA_STATUS_OK; +} + +u16 +bfa_fcport_get_maxfrsize(struct bfa_s *bfa) +{ + struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); + + return fcport->cfg.maxfrsize; +} + +u8 +bfa_fcport_get_rx_bbcredit(struct bfa_s *bfa) +{ + struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); + + return fcport->cfg.rx_bbcredit; +} + +void +bfa_fcport_set_tx_bbcredit(struct bfa_s *bfa, u16 tx_bbcredit) +{ + struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); + + fcport->cfg.tx_bbcredit = (u8)tx_bbcredit; + bfa_fcport_send_txcredit(fcport); +} + +/** + * Get port attributes. + */ + +wwn_t +bfa_fcport_get_wwn(struct bfa_s *bfa, bfa_boolean_t node) +{ + struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); + if (node) + return fcport->nwwn; + else + return fcport->pwwn; +} + +void +bfa_fcport_get_attr(struct bfa_s *bfa, struct bfa_port_attr_s *attr) +{ + struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); + + bfa_os_memset(attr, 0, sizeof(struct bfa_port_attr_s)); + + 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_port_cfg_s)); + /* speed attributes */ + attr->pport_cfg.speed = fcport->cfg.speed; + attr->speed_supported = fcport->speed_sup; + attr->speed = fcport->speed; + attr->cos_supported = FC_CLASS_3; + + /* topology attributes */ + attr->pport_cfg.topology = fcport->cfg.topology; + attr->topology = fcport->topology; + attr->pport_cfg.trunked = fcport->cfg.trunked; + + /* beacon attributes */ + attr->beacon = fcport->beacon; + attr->link_e2e_beacon = fcport->link_e2e_beacon; + attr->plog_enabled = bfa_plog_get_setting(fcport->bfa->plog); + attr->io_profile = bfa_fcpim_get_io_profile(fcport->bfa); + + 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_port_sm_table, fcport->sm); + if (bfa_ioc_is_disabled(&fcport->bfa->ioc)) + attr->port_state = BFA_PORT_ST_IOCDIS; + else if (bfa_ioc_fw_mismatch(&fcport->bfa->ioc)) + attr->port_state = BFA_PORT_ST_FWMISMATCH; + + /* FCoE vlan */ + attr->fcoe_vlan = fcport->fcoe_vlan; +} + +#define BFA_FCPORT_STATS_TOV 1000 + +/** + * Fetch port statistics (FCQoS or FCoE). + */ +bfa_status_t +bfa_fcport_get_stats(struct bfa_s *bfa, union bfa_fcport_stats_u *stats, + bfa_cb_port_t cbfn, void *cbarg) +{ + struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); + + if (fcport->stats_busy) { + bfa_trc(bfa, fcport->stats_busy); + return BFA_STATUS_DEVBUSY; + } + + fcport->stats_busy = BFA_TRUE; + fcport->stats_ret = stats; + fcport->stats_cbfn = cbfn; + fcport->stats_cbarg = cbarg; + + bfa_fcport_send_stats_get(fcport); + + bfa_timer_start(bfa, &fcport->timer, bfa_fcport_stats_get_timeout, + fcport, BFA_FCPORT_STATS_TOV); + return BFA_STATUS_OK; +} + +/** + * Reset port statistics (FCQoS or FCoE). + */ +bfa_status_t +bfa_fcport_clear_stats(struct bfa_s *bfa, bfa_cb_port_t cbfn, void *cbarg) +{ + struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); + + if (fcport->stats_busy) { + bfa_trc(bfa, fcport->stats_busy); + return BFA_STATUS_DEVBUSY; + } + + fcport->stats_busy = BFA_TRUE; + fcport->stats_cbfn = cbfn; + fcport->stats_cbarg = cbarg; + + bfa_fcport_send_stats_clear(fcport); + + bfa_timer_start(bfa, &fcport->timer, bfa_fcport_stats_clr_timeout, + fcport, BFA_FCPORT_STATS_TOV); + return BFA_STATUS_OK; +} + +/** + * Fetch FCQoS port statistics + */ +bfa_status_t +bfa_fcport_get_qos_stats(struct bfa_s *bfa, union bfa_fcport_stats_u *stats, + bfa_cb_port_t cbfn, void *cbarg) +{ + /* Meaningful only for FC mode */ + bfa_assert(bfa_ioc_get_fcmode(&bfa->ioc)); + + return bfa_fcport_get_stats(bfa, stats, cbfn, cbarg); +} + +/** + * Reset FCoE port statistics + */ +bfa_status_t +bfa_fcport_clear_qos_stats(struct bfa_s *bfa, bfa_cb_port_t cbfn, void *cbarg) +{ + /* Meaningful only for FC mode */ + bfa_assert(bfa_ioc_get_fcmode(&bfa->ioc)); + + return bfa_fcport_clear_stats(bfa, cbfn, cbarg); +} + +/** + * Fetch FCQoS port statistics + */ +bfa_status_t +bfa_fcport_get_fcoe_stats(struct bfa_s *bfa, union bfa_fcport_stats_u *stats, + bfa_cb_port_t cbfn, void *cbarg) +{ + /* Meaningful only for FCoE mode */ + bfa_assert(!bfa_ioc_get_fcmode(&bfa->ioc)); + + return bfa_fcport_get_stats(bfa, stats, cbfn, cbarg); +} + +/** + * Reset FCoE port statistics + */ +bfa_status_t +bfa_fcport_clear_fcoe_stats(struct bfa_s *bfa, bfa_cb_port_t cbfn, void *cbarg) +{ + /* Meaningful only for FCoE mode */ + bfa_assert(!bfa_ioc_get_fcmode(&bfa->ioc)); + + return bfa_fcport_clear_stats(bfa, cbfn, cbarg); +} + +void +bfa_fcport_qos_get_attr(struct bfa_s *bfa, struct bfa_qos_attr_s *qos_attr) +{ + struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); + + qos_attr->state = fcport->qos_attr.state; + qos_attr->total_bb_cr = bfa_os_ntohl(fcport->qos_attr.total_bb_cr); +} + +void +bfa_fcport_qos_get_vc_attr(struct bfa_s *bfa, + struct bfa_qos_vc_attr_s *qos_vc_attr) +{ + struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); + struct bfa_qos_vc_attr_s *bfa_vc_attr = &fcport->qos_vc_attr; + u32 i = 0; + + qos_vc_attr->total_vc_count = bfa_os_ntohs(bfa_vc_attr->total_vc_count); + qos_vc_attr->shared_credit = bfa_os_ntohs(bfa_vc_attr->shared_credit); + qos_vc_attr->elp_opmode_flags = + bfa_os_ntohl(bfa_vc_attr->elp_opmode_flags); + + /* Individual VC info */ + while (i < qos_vc_attr->total_vc_count) { + qos_vc_attr->vc_info[i].vc_credit = + bfa_vc_attr->vc_info[i].vc_credit; + qos_vc_attr->vc_info[i].borrow_credit = + bfa_vc_attr->vc_info[i].borrow_credit; + qos_vc_attr->vc_info[i].priority = + bfa_vc_attr->vc_info[i].priority; + ++i; + } +} + +/** + * Fetch port attributes. + */ +bfa_boolean_t +bfa_fcport_is_disabled(struct bfa_s *bfa) +{ + struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); + + return bfa_sm_to_state(hal_port_sm_table, fcport->sm) == + BFA_PORT_ST_DISABLED; + +} + +bfa_boolean_t +bfa_fcport_is_ratelim(struct bfa_s *bfa) +{ + struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); + + return fcport->cfg.ratelimit ? BFA_TRUE : BFA_FALSE; + +} + +void +bfa_fcport_cfg_qos(struct bfa_s *bfa, bfa_boolean_t on_off) +{ + struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); + enum bfa_ioc_type_e ioc_type = bfa_get_type(bfa); + + bfa_trc(bfa, on_off); + bfa_trc(bfa, fcport->cfg.qos_enabled); + + bfa_trc(bfa, ioc_type); + + 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 +bfa_fcport_cfg_ratelim(struct bfa_s *bfa, bfa_boolean_t on_off) +{ + struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); + + bfa_trc(bfa, on_off); + bfa_trc(bfa, fcport->cfg.ratelimit); + + fcport->cfg.ratelimit = on_off; + if (fcport->cfg.trl_def_speed == BFA_PORT_SPEED_UNKNOWN) + fcport->cfg.trl_def_speed = BFA_PORT_SPEED_1GBPS; +} + +/** + * Configure default minimum ratelim speed + */ +bfa_status_t +bfa_fcport_cfg_ratelim_speed(struct bfa_s *bfa, enum bfa_port_speed speed) +{ + struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); + + bfa_trc(bfa, speed); + + /* Auto and speeds greater than the supported speed, are invalid */ + if ((speed == BFA_PORT_SPEED_AUTO) || (speed > fcport->speed_sup)) { + bfa_trc(bfa, fcport->speed_sup); + return BFA_STATUS_UNSUPP_SPEED; + } + + fcport->cfg.trl_def_speed = speed; + + return BFA_STATUS_OK; +} + +/** + * Get default minimum ratelim speed + */ +enum bfa_port_speed +bfa_fcport_get_ratelim_speed(struct bfa_s *bfa) +{ + struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); + + bfa_trc(bfa, fcport->cfg.trl_def_speed); + return fcport->cfg.trl_def_speed; + +} +void +bfa_fcport_busy(struct bfa_s *bfa, bfa_boolean_t status) +{ + struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); + + bfa_trc(bfa, status); + bfa_trc(bfa, fcport->diag_busy); + + fcport->diag_busy = status; +} + +void +bfa_fcport_beacon(void *dev, bfa_boolean_t beacon, + bfa_boolean_t link_e2e_beacon) +{ + struct bfa_s *bfa = dev; + struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); + + bfa_trc(bfa, beacon); + bfa_trc(bfa, link_e2e_beacon); + bfa_trc(bfa, fcport->beacon); + bfa_trc(bfa, fcport->link_e2e_beacon); + + fcport->beacon = beacon; + fcport->link_e2e_beacon = link_e2e_beacon; +} + +bfa_boolean_t +bfa_fcport_is_linkup(struct bfa_s *bfa) +{ + struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); + + return (!fcport->cfg.trunked && + bfa_sm_cmp_state(fcport, bfa_fcport_sm_linkup)) || + (fcport->cfg.trunked && + fcport->trunk.attr.state == BFA_TRUNK_ONLINE); +} + +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; +} + +bfa_status_t +bfa_trunk_get_attr(struct bfa_s *bfa, struct bfa_trunk_attr_s *attr) + +{ + struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); + struct bfa_fcport_trunk_s *trunk = &fcport->trunk; + + bfa_trc(bfa, fcport->cfg.trunked); + bfa_trc(bfa, trunk->attr.state); + *attr = trunk->attr; + attr->port_id = bfa_lps_get_base_pid(bfa); + + return BFA_STATUS_OK; +} + +void +bfa_trunk_enable_cfg(struct bfa_s *bfa) +{ + struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); + struct bfa_fcport_trunk_s *trunk = &fcport->trunk; + + bfa_trc(bfa, 1); + trunk->attr.state = BFA_TRUNK_OFFLINE; + fcport->cfg.trunked = BFA_TRUE; +} + +bfa_status_t +bfa_trunk_enable(struct bfa_s *bfa) +{ + struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); + struct bfa_fcport_trunk_s *trunk = &fcport->trunk; + + bfa_trc(bfa, 1); + + trunk->attr.state = BFA_TRUNK_OFFLINE; + bfa_fcport_disable(bfa); + fcport->cfg.trunked = BFA_TRUE; + bfa_fcport_enable(bfa); + + return BFA_STATUS_OK; +} + +bfa_status_t +bfa_trunk_disable(struct bfa_s *bfa) +{ + struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); + struct bfa_fcport_trunk_s *trunk = &fcport->trunk; + + bfa_trc(bfa, 0); + trunk->attr.state = BFA_TRUNK_DISABLED; + bfa_fcport_disable(bfa); + fcport->cfg.trunked = BFA_FALSE; + bfa_fcport_enable(bfa); + return BFA_STATUS_OK; +} + + +/** + * Rport State machine functions + */ +/** + * Beginning state, only online event expected. + */ +static void +bfa_rport_sm_uninit(struct bfa_rport_s *rp, enum bfa_rport_event event) +{ + bfa_trc(rp->bfa, rp->rport_tag); + bfa_trc(rp->bfa, event); + + switch (event) { + case BFA_RPORT_SM_CREATE: + bfa_stats(rp, sm_un_cr); + bfa_sm_set_state(rp, bfa_rport_sm_created); + break; + + default: + bfa_stats(rp, sm_un_unexp); + bfa_sm_fault(rp->bfa, event); + } +} + +static void +bfa_rport_sm_created(struct bfa_rport_s *rp, enum bfa_rport_event event) +{ + bfa_trc(rp->bfa, rp->rport_tag); + bfa_trc(rp->bfa, event); + + switch (event) { + case BFA_RPORT_SM_ONLINE: + bfa_stats(rp, sm_cr_on); + if (bfa_rport_send_fwcreate(rp)) + bfa_sm_set_state(rp, bfa_rport_sm_fwcreate); + else + bfa_sm_set_state(rp, bfa_rport_sm_fwcreate_qfull); + break; + + case BFA_RPORT_SM_DELETE: + bfa_stats(rp, sm_cr_del); + bfa_sm_set_state(rp, bfa_rport_sm_uninit); + bfa_rport_free(rp); + break; + + case BFA_RPORT_SM_HWFAIL: + bfa_stats(rp, sm_cr_hwf); + bfa_sm_set_state(rp, bfa_rport_sm_iocdisable); + break; + + default: + bfa_stats(rp, sm_cr_unexp); + bfa_sm_fault(rp->bfa, event); + } +} + +/** + * Waiting for rport create response from firmware. + */ +static void +bfa_rport_sm_fwcreate(struct bfa_rport_s *rp, enum bfa_rport_event event) +{ + bfa_trc(rp->bfa, rp->rport_tag); + bfa_trc(rp->bfa, event); + + switch (event) { + case BFA_RPORT_SM_FWRSP: + bfa_stats(rp, sm_fwc_rsp); + bfa_sm_set_state(rp, bfa_rport_sm_online); + bfa_rport_online_cb(rp); + break; + + case BFA_RPORT_SM_DELETE: + bfa_stats(rp, sm_fwc_del); + bfa_sm_set_state(rp, bfa_rport_sm_delete_pending); + break; + + case BFA_RPORT_SM_OFFLINE: + bfa_stats(rp, sm_fwc_off); + bfa_sm_set_state(rp, bfa_rport_sm_offline_pending); + break; + + case BFA_RPORT_SM_HWFAIL: + bfa_stats(rp, sm_fwc_hwf); + bfa_sm_set_state(rp, bfa_rport_sm_iocdisable); + break; + + default: + bfa_stats(rp, sm_fwc_unexp); + bfa_sm_fault(rp->bfa, event); + } +} + +/** + * Request queue is full, awaiting queue resume to send create request. + */ +static void +bfa_rport_sm_fwcreate_qfull(struct bfa_rport_s *rp, enum bfa_rport_event event) +{ + bfa_trc(rp->bfa, rp->rport_tag); + bfa_trc(rp->bfa, event); + + switch (event) { + case BFA_RPORT_SM_QRESUME: + bfa_sm_set_state(rp, bfa_rport_sm_fwcreate); + bfa_rport_send_fwcreate(rp); + break; + + case BFA_RPORT_SM_DELETE: + bfa_stats(rp, sm_fwc_del); + bfa_sm_set_state(rp, bfa_rport_sm_uninit); + bfa_reqq_wcancel(&rp->reqq_wait); + bfa_rport_free(rp); + break; + + case BFA_RPORT_SM_OFFLINE: + bfa_stats(rp, sm_fwc_off); + bfa_sm_set_state(rp, bfa_rport_sm_offline); + bfa_reqq_wcancel(&rp->reqq_wait); + bfa_rport_offline_cb(rp); + break; + + case BFA_RPORT_SM_HWFAIL: + bfa_stats(rp, sm_fwc_hwf); + bfa_sm_set_state(rp, bfa_rport_sm_iocdisable); + bfa_reqq_wcancel(&rp->reqq_wait); + break; + + default: + bfa_stats(rp, sm_fwc_unexp); + bfa_sm_fault(rp->bfa, event); + } +} + +/** + * Online state - normal parking state. + */ +static void +bfa_rport_sm_online(struct bfa_rport_s *rp, enum bfa_rport_event event) +{ + struct bfi_rport_qos_scn_s *qos_scn; + + bfa_trc(rp->bfa, rp->rport_tag); + bfa_trc(rp->bfa, event); + + switch (event) { + case BFA_RPORT_SM_OFFLINE: + bfa_stats(rp, sm_on_off); + if (bfa_rport_send_fwdelete(rp)) + bfa_sm_set_state(rp, bfa_rport_sm_fwdelete); + else + bfa_sm_set_state(rp, bfa_rport_sm_fwdelete_qfull); + break; + + case BFA_RPORT_SM_DELETE: + bfa_stats(rp, sm_on_del); + if (bfa_rport_send_fwdelete(rp)) + bfa_sm_set_state(rp, bfa_rport_sm_deleting); + else + bfa_sm_set_state(rp, bfa_rport_sm_deleting_qfull); + break; + + case BFA_RPORT_SM_HWFAIL: + bfa_stats(rp, sm_on_hwf); + bfa_sm_set_state(rp, bfa_rport_sm_iocdisable); + break; + + case BFA_RPORT_SM_SET_SPEED: + bfa_rport_send_fwspeed(rp); + break; + + case BFA_RPORT_SM_QOS_SCN: + qos_scn = (struct bfi_rport_qos_scn_s *) rp->event_arg.fw_msg; + rp->qos_attr = qos_scn->new_qos_attr; + bfa_trc(rp->bfa, qos_scn->old_qos_attr.qos_flow_id); + bfa_trc(rp->bfa, qos_scn->new_qos_attr.qos_flow_id); + bfa_trc(rp->bfa, qos_scn->old_qos_attr.qos_priority); + bfa_trc(rp->bfa, qos_scn->new_qos_attr.qos_priority); + + qos_scn->old_qos_attr.qos_flow_id = + bfa_os_ntohl(qos_scn->old_qos_attr.qos_flow_id); + qos_scn->new_qos_attr.qos_flow_id = + bfa_os_ntohl(qos_scn->new_qos_attr.qos_flow_id); + + if (qos_scn->old_qos_attr.qos_flow_id != + qos_scn->new_qos_attr.qos_flow_id) + bfa_cb_rport_qos_scn_flowid(rp->rport_drv, + qos_scn->old_qos_attr, + qos_scn->new_qos_attr); + if (qos_scn->old_qos_attr.qos_priority != + qos_scn->new_qos_attr.qos_priority) + bfa_cb_rport_qos_scn_prio(rp->rport_drv, + qos_scn->old_qos_attr, + qos_scn->new_qos_attr); + break; + + default: + bfa_stats(rp, sm_on_unexp); + bfa_sm_fault(rp->bfa, event); + } +} + +/** + * Firmware rport is being deleted - awaiting f/w response. + */ +static void +bfa_rport_sm_fwdelete(struct bfa_rport_s *rp, enum bfa_rport_event event) +{ + bfa_trc(rp->bfa, rp->rport_tag); + bfa_trc(rp->bfa, event); + + switch (event) { + case BFA_RPORT_SM_FWRSP: + bfa_stats(rp, sm_fwd_rsp); + bfa_sm_set_state(rp, bfa_rport_sm_offline); + bfa_rport_offline_cb(rp); + break; + + case BFA_RPORT_SM_DELETE: + bfa_stats(rp, sm_fwd_del); + bfa_sm_set_state(rp, bfa_rport_sm_deleting); + break; + + case BFA_RPORT_SM_HWFAIL: + bfa_stats(rp, sm_fwd_hwf); + bfa_sm_set_state(rp, bfa_rport_sm_iocdisable); + bfa_rport_offline_cb(rp); + break; + + default: + bfa_stats(rp, sm_fwd_unexp); + bfa_sm_fault(rp->bfa, event); + } +} + +static void +bfa_rport_sm_fwdelete_qfull(struct bfa_rport_s *rp, enum bfa_rport_event event) +{ + bfa_trc(rp->bfa, rp->rport_tag); + bfa_trc(rp->bfa, event); + + switch (event) { + case BFA_RPORT_SM_QRESUME: + bfa_sm_set_state(rp, bfa_rport_sm_fwdelete); + bfa_rport_send_fwdelete(rp); + break; + + case BFA_RPORT_SM_DELETE: + bfa_stats(rp, sm_fwd_del); + bfa_sm_set_state(rp, bfa_rport_sm_deleting_qfull); + break; + + case BFA_RPORT_SM_HWFAIL: + bfa_stats(rp, sm_fwd_hwf); + bfa_sm_set_state(rp, bfa_rport_sm_iocdisable); + bfa_reqq_wcancel(&rp->reqq_wait); + bfa_rport_offline_cb(rp); + break; + + default: + bfa_stats(rp, sm_fwd_unexp); + bfa_sm_fault(rp->bfa, event); + } +} + +/** + * Offline state. + */ +static void +bfa_rport_sm_offline(struct bfa_rport_s *rp, enum bfa_rport_event event) +{ + bfa_trc(rp->bfa, rp->rport_tag); + bfa_trc(rp->bfa, event); + + switch (event) { + case BFA_RPORT_SM_DELETE: + bfa_stats(rp, sm_off_del); + bfa_sm_set_state(rp, bfa_rport_sm_uninit); + bfa_rport_free(rp); + break; + + case BFA_RPORT_SM_ONLINE: + bfa_stats(rp, sm_off_on); + if (bfa_rport_send_fwcreate(rp)) + bfa_sm_set_state(rp, bfa_rport_sm_fwcreate); + else + bfa_sm_set_state(rp, bfa_rport_sm_fwcreate_qfull); + break; + + case BFA_RPORT_SM_HWFAIL: + bfa_stats(rp, sm_off_hwf); + bfa_sm_set_state(rp, bfa_rport_sm_iocdisable); + break; + + default: + bfa_stats(rp, sm_off_unexp); + bfa_sm_fault(rp->bfa, event); + } +} + +/** + * Rport is deleted, waiting for firmware response to delete. + */ +static void +bfa_rport_sm_deleting(struct bfa_rport_s *rp, enum bfa_rport_event event) +{ + bfa_trc(rp->bfa, rp->rport_tag); + bfa_trc(rp->bfa, event); + + switch (event) { + case BFA_RPORT_SM_FWRSP: + bfa_stats(rp, sm_del_fwrsp); + bfa_sm_set_state(rp, bfa_rport_sm_uninit); + bfa_rport_free(rp); + break; + + case BFA_RPORT_SM_HWFAIL: + bfa_stats(rp, sm_del_hwf); + bfa_sm_set_state(rp, bfa_rport_sm_uninit); + bfa_rport_free(rp); + break; + + default: + bfa_sm_fault(rp->bfa, event); + } +} + +static void +bfa_rport_sm_deleting_qfull(struct bfa_rport_s *rp, enum bfa_rport_event event) +{ + bfa_trc(rp->bfa, rp->rport_tag); + bfa_trc(rp->bfa, event); + + switch (event) { + case BFA_RPORT_SM_QRESUME: + bfa_stats(rp, sm_del_fwrsp); + bfa_sm_set_state(rp, bfa_rport_sm_deleting); + bfa_rport_send_fwdelete(rp); + break; + + case BFA_RPORT_SM_HWFAIL: + bfa_stats(rp, sm_del_hwf); + bfa_sm_set_state(rp, bfa_rport_sm_uninit); + bfa_reqq_wcancel(&rp->reqq_wait); + bfa_rport_free(rp); + break; + + default: + bfa_sm_fault(rp->bfa, event); + } +} + +/** + * Waiting for rport create response from firmware. A delete is pending. + */ +static void +bfa_rport_sm_delete_pending(struct bfa_rport_s *rp, + enum bfa_rport_event event) +{ + bfa_trc(rp->bfa, rp->rport_tag); + bfa_trc(rp->bfa, event); + + switch (event) { + case BFA_RPORT_SM_FWRSP: + bfa_stats(rp, sm_delp_fwrsp); + if (bfa_rport_send_fwdelete(rp)) + bfa_sm_set_state(rp, bfa_rport_sm_deleting); + else + bfa_sm_set_state(rp, bfa_rport_sm_deleting_qfull); + break; + + case BFA_RPORT_SM_HWFAIL: + bfa_stats(rp, sm_delp_hwf); + bfa_sm_set_state(rp, bfa_rport_sm_uninit); + bfa_rport_free(rp); + break; + + default: + bfa_stats(rp, sm_delp_unexp); + bfa_sm_fault(rp->bfa, event); + } +} + +/** + * Waiting for rport create response from firmware. Rport offline is pending. + */ +static void +bfa_rport_sm_offline_pending(struct bfa_rport_s *rp, + enum bfa_rport_event event) +{ + bfa_trc(rp->bfa, rp->rport_tag); + bfa_trc(rp->bfa, event); + + switch (event) { + case BFA_RPORT_SM_FWRSP: + bfa_stats(rp, sm_offp_fwrsp); + if (bfa_rport_send_fwdelete(rp)) + bfa_sm_set_state(rp, bfa_rport_sm_fwdelete); + else + bfa_sm_set_state(rp, bfa_rport_sm_fwdelete_qfull); + break; + + case BFA_RPORT_SM_DELETE: + bfa_stats(rp, sm_offp_del); + bfa_sm_set_state(rp, bfa_rport_sm_delete_pending); + break; + + case BFA_RPORT_SM_HWFAIL: + bfa_stats(rp, sm_offp_hwf); + bfa_sm_set_state(rp, bfa_rport_sm_iocdisable); + break; + + default: + bfa_stats(rp, sm_offp_unexp); + bfa_sm_fault(rp->bfa, event); + } +} + +/** + * IOC h/w failed. + */ +static void +bfa_rport_sm_iocdisable(struct bfa_rport_s *rp, enum bfa_rport_event event) +{ + bfa_trc(rp->bfa, rp->rport_tag); + bfa_trc(rp->bfa, event); + + switch (event) { + case BFA_RPORT_SM_OFFLINE: + bfa_stats(rp, sm_iocd_off); + bfa_rport_offline_cb(rp); + break; + + case BFA_RPORT_SM_DELETE: + bfa_stats(rp, sm_iocd_del); + bfa_sm_set_state(rp, bfa_rport_sm_uninit); + bfa_rport_free(rp); + break; + + case BFA_RPORT_SM_ONLINE: + bfa_stats(rp, sm_iocd_on); + if (bfa_rport_send_fwcreate(rp)) + bfa_sm_set_state(rp, bfa_rport_sm_fwcreate); + else + bfa_sm_set_state(rp, bfa_rport_sm_fwcreate_qfull); + break; + + case BFA_RPORT_SM_HWFAIL: + break; + + default: + bfa_stats(rp, sm_iocd_unexp); + bfa_sm_fault(rp->bfa, event); + } +} + + + +/** + * bfa_rport_private BFA rport private functions + */ + +static void +__bfa_cb_rport_online(void *cbarg, bfa_boolean_t complete) +{ + struct bfa_rport_s *rp = cbarg; + + if (complete) + bfa_cb_rport_online(rp->rport_drv); +} + +static void +__bfa_cb_rport_offline(void *cbarg, bfa_boolean_t complete) +{ + struct bfa_rport_s *rp = cbarg; + + if (complete) + bfa_cb_rport_offline(rp->rport_drv); +} + +static void +bfa_rport_qresume(void *cbarg) +{ + struct bfa_rport_s *rp = cbarg; + + bfa_sm_send_event(rp, BFA_RPORT_SM_QRESUME); +} + +static void +bfa_rport_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len, + u32 *dm_len) +{ + if (cfg->fwcfg.num_rports < BFA_RPORT_MIN) + cfg->fwcfg.num_rports = BFA_RPORT_MIN; + + *km_len += cfg->fwcfg.num_rports * sizeof(struct bfa_rport_s); +} + +static void +bfa_rport_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, + struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev) +{ + struct bfa_rport_mod_s *mod = BFA_RPORT_MOD(bfa); + struct bfa_rport_s *rp; + u16 i; + + INIT_LIST_HEAD(&mod->rp_free_q); + INIT_LIST_HEAD(&mod->rp_active_q); + + rp = (struct bfa_rport_s *) bfa_meminfo_kva(meminfo); + mod->rps_list = rp; + mod->num_rports = cfg->fwcfg.num_rports; + + bfa_assert(mod->num_rports && + !(mod->num_rports & (mod->num_rports - 1))); + + for (i = 0; i < mod->num_rports; i++, rp++) { + bfa_os_memset(rp, 0, sizeof(struct bfa_rport_s)); + rp->bfa = bfa; + rp->rport_tag = i; + bfa_sm_set_state(rp, bfa_rport_sm_uninit); + + /** + * - is unused + */ + if (i) + list_add_tail(&rp->qe, &mod->rp_free_q); + + bfa_reqq_winit(&rp->reqq_wait, bfa_rport_qresume, rp); + } + + /** + * consume memory + */ + bfa_meminfo_kva(meminfo) = (u8 *) rp; +} + +static void +bfa_rport_detach(struct bfa_s *bfa) +{ +} + +static void +bfa_rport_start(struct bfa_s *bfa) +{ +} + +static void +bfa_rport_stop(struct bfa_s *bfa) +{ +} + +static void +bfa_rport_iocdisable(struct bfa_s *bfa) +{ + struct bfa_rport_mod_s *mod = BFA_RPORT_MOD(bfa); + struct bfa_rport_s *rport; + struct list_head *qe, *qen; + + list_for_each_safe(qe, qen, &mod->rp_active_q) { + rport = (struct bfa_rport_s *) qe; + bfa_sm_send_event(rport, BFA_RPORT_SM_HWFAIL); + } +} + +static struct bfa_rport_s * +bfa_rport_alloc(struct bfa_rport_mod_s *mod) +{ + struct bfa_rport_s *rport; + + bfa_q_deq(&mod->rp_free_q, &rport); + if (rport) + list_add_tail(&rport->qe, &mod->rp_active_q); + + return rport; +} + +static void +bfa_rport_free(struct bfa_rport_s *rport) +{ + struct bfa_rport_mod_s *mod = BFA_RPORT_MOD(rport->bfa); + + bfa_assert(bfa_q_is_on_q(&mod->rp_active_q, rport)); + list_del(&rport->qe); + list_add_tail(&rport->qe, &mod->rp_free_q); +} + +static bfa_boolean_t +bfa_rport_send_fwcreate(struct bfa_rport_s *rp) +{ + struct bfi_rport_create_req_s *m; + + /** + * check for room in queue to send request now + */ + m = bfa_reqq_next(rp->bfa, BFA_REQQ_RPORT); + if (!m) { + bfa_reqq_wait(rp->bfa, BFA_REQQ_RPORT, &rp->reqq_wait); + return BFA_FALSE; + } + + bfi_h2i_set(m->mh, BFI_MC_RPORT, BFI_RPORT_H2I_CREATE_REQ, + bfa_lpuid(rp->bfa)); + m->bfa_handle = rp->rport_tag; + m->max_frmsz = bfa_os_htons(rp->rport_info.max_frmsz); + m->pid = rp->rport_info.pid; + m->lp_tag = rp->rport_info.lp_tag; + m->local_pid = rp->rport_info.local_pid; + m->fc_class = rp->rport_info.fc_class; + m->vf_en = rp->rport_info.vf_en; + m->vf_id = rp->rport_info.vf_id; + m->cisc = rp->rport_info.cisc; + + /** + * queue I/O message to firmware + */ + bfa_reqq_produce(rp->bfa, BFA_REQQ_RPORT); + return BFA_TRUE; +} + +static bfa_boolean_t +bfa_rport_send_fwdelete(struct bfa_rport_s *rp) +{ + struct bfi_rport_delete_req_s *m; + + /** + * check for room in queue to send request now + */ + m = bfa_reqq_next(rp->bfa, BFA_REQQ_RPORT); + if (!m) { + bfa_reqq_wait(rp->bfa, BFA_REQQ_RPORT, &rp->reqq_wait); + return BFA_FALSE; + } + + bfi_h2i_set(m->mh, BFI_MC_RPORT, BFI_RPORT_H2I_DELETE_REQ, + bfa_lpuid(rp->bfa)); + m->fw_handle = rp->fw_handle; + + /** + * queue I/O message to firmware + */ + bfa_reqq_produce(rp->bfa, BFA_REQQ_RPORT); + return BFA_TRUE; +} + +static bfa_boolean_t +bfa_rport_send_fwspeed(struct bfa_rport_s *rp) +{ + struct bfa_rport_speed_req_s *m; + + /** + * check for room in queue to send request now + */ + m = bfa_reqq_next(rp->bfa, BFA_REQQ_RPORT); + if (!m) { + bfa_trc(rp->bfa, rp->rport_info.speed); + return BFA_FALSE; + } + + bfi_h2i_set(m->mh, BFI_MC_RPORT, BFI_RPORT_H2I_SET_SPEED_REQ, + bfa_lpuid(rp->bfa)); + m->fw_handle = rp->fw_handle; + m->speed = (u8)rp->rport_info.speed; + + /** + * queue I/O message to firmware + */ + bfa_reqq_produce(rp->bfa, BFA_REQQ_RPORT); + return BFA_TRUE; +} + + + +/** + * bfa_rport_public + */ + +/** + * Rport interrupt processing. + */ +void +bfa_rport_isr(struct bfa_s *bfa, struct bfi_msg_s *m) +{ + union bfi_rport_i2h_msg_u msg; + struct bfa_rport_s *rp; + + bfa_trc(bfa, m->mhdr.msg_id); + + msg.msg = m; + + switch (m->mhdr.msg_id) { + case BFI_RPORT_I2H_CREATE_RSP: + rp = BFA_RPORT_FROM_TAG(bfa, msg.create_rsp->bfa_handle); + rp->fw_handle = msg.create_rsp->fw_handle; + rp->qos_attr = msg.create_rsp->qos_attr; + bfa_assert(msg.create_rsp->status == BFA_STATUS_OK); + bfa_sm_send_event(rp, BFA_RPORT_SM_FWRSP); + break; + + case BFI_RPORT_I2H_DELETE_RSP: + rp = BFA_RPORT_FROM_TAG(bfa, msg.delete_rsp->bfa_handle); + bfa_assert(msg.delete_rsp->status == BFA_STATUS_OK); + bfa_sm_send_event(rp, BFA_RPORT_SM_FWRSP); + break; + + case BFI_RPORT_I2H_QOS_SCN: + rp = BFA_RPORT_FROM_TAG(bfa, msg.qos_scn_evt->bfa_handle); + rp->event_arg.fw_msg = msg.qos_scn_evt; + bfa_sm_send_event(rp, BFA_RPORT_SM_QOS_SCN); + break; + + default: + bfa_trc(bfa, m->mhdr.msg_id); + bfa_assert(0); + } +} + + + +/** + * bfa_rport_api + */ + +struct bfa_rport_s * +bfa_rport_create(struct bfa_s *bfa, void *rport_drv) +{ + struct bfa_rport_s *rp; + + rp = bfa_rport_alloc(BFA_RPORT_MOD(bfa)); + + if (rp == NULL) + return NULL; + + rp->bfa = bfa; + rp->rport_drv = rport_drv; + bfa_rport_clear_stats(rp); + + bfa_assert(bfa_sm_cmp_state(rp, bfa_rport_sm_uninit)); + bfa_sm_send_event(rp, BFA_RPORT_SM_CREATE); + + return rp; +} + +void +bfa_rport_delete(struct bfa_rport_s *rport) +{ + bfa_sm_send_event(rport, BFA_RPORT_SM_DELETE); +} + +void +bfa_rport_online(struct bfa_rport_s *rport, struct bfa_rport_info_s *rport_info) +{ + bfa_assert(rport_info->max_frmsz != 0); + + /** + * Some JBODs are seen to be not setting PDU size correctly in PLOGI + * responses. Default to minimum size. + */ + if (rport_info->max_frmsz == 0) { + bfa_trc(rport->bfa, rport->rport_tag); + rport_info->max_frmsz = FC_MIN_PDUSZ; + } + + bfa_os_assign(rport->rport_info, *rport_info); + bfa_sm_send_event(rport, BFA_RPORT_SM_ONLINE); +} + +void +bfa_rport_offline(struct bfa_rport_s *rport) +{ + bfa_sm_send_event(rport, BFA_RPORT_SM_OFFLINE); +} + +void +bfa_rport_speed(struct bfa_rport_s *rport, enum bfa_port_speed speed) +{ + bfa_assert(speed != 0); + bfa_assert(speed != BFA_PORT_SPEED_AUTO); + + rport->rport_info.speed = speed; + bfa_sm_send_event(rport, BFA_RPORT_SM_SET_SPEED); +} + +void +bfa_rport_get_stats(struct bfa_rport_s *rport, + struct bfa_rport_hal_stats_s *stats) +{ + *stats = rport->stats; +} + +void +bfa_rport_get_qos_attr(struct bfa_rport_s *rport, + struct bfa_rport_qos_attr_s *qos_attr) +{ + qos_attr->qos_priority = rport->qos_attr.qos_priority; + qos_attr->qos_flow_id = bfa_os_ntohl(rport->qos_attr.qos_flow_id); + +} + +void +bfa_rport_clear_stats(struct bfa_rport_s *rport) +{ + bfa_os_memset(&rport->stats, 0, sizeof(rport->stats)); +} + + +/** + * SGPG related functions + */ + +/** + * Compute and return memory needed by FCP(im) module. + */ +static void +bfa_sgpg_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len, + u32 *dm_len) +{ + if (cfg->drvcfg.num_sgpgs < BFA_SGPG_MIN) + cfg->drvcfg.num_sgpgs = BFA_SGPG_MIN; + + *km_len += (cfg->drvcfg.num_sgpgs + 1) * sizeof(struct bfa_sgpg_s); + *dm_len += (cfg->drvcfg.num_sgpgs + 1) * sizeof(struct bfi_sgpg_s); +} + + +static void +bfa_sgpg_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, + struct bfa_meminfo_s *minfo, struct bfa_pcidev_s *pcidev) +{ + struct bfa_sgpg_mod_s *mod = BFA_SGPG_MOD(bfa); + int i; + struct bfa_sgpg_s *hsgpg; + struct bfi_sgpg_s *sgpg; + u64 align_len; + + union { + u64 pa; + union bfi_addr_u addr; + } sgpg_pa, sgpg_pa_tmp; + + INIT_LIST_HEAD(&mod->sgpg_q); + INIT_LIST_HEAD(&mod->sgpg_wait_q); + + bfa_trc(bfa, cfg->drvcfg.num_sgpgs); + + mod->num_sgpgs = cfg->drvcfg.num_sgpgs; + mod->sgpg_arr_pa = bfa_meminfo_dma_phys(minfo); + align_len = (BFA_SGPG_ROUNDUP(mod->sgpg_arr_pa) - mod->sgpg_arr_pa); + mod->sgpg_arr_pa += align_len; + mod->hsgpg_arr = (struct bfa_sgpg_s *) (bfa_meminfo_kva(minfo) + + align_len); + mod->sgpg_arr = (struct bfi_sgpg_s *) (bfa_meminfo_dma_virt(minfo) + + align_len); + + hsgpg = mod->hsgpg_arr; + sgpg = mod->sgpg_arr; + sgpg_pa.pa = mod->sgpg_arr_pa; + mod->free_sgpgs = mod->num_sgpgs; + + bfa_assert(!(sgpg_pa.pa & (sizeof(struct bfi_sgpg_s) - 1))); + + for (i = 0; i < mod->num_sgpgs; i++) { + bfa_os_memset(hsgpg, 0, sizeof(*hsgpg)); + bfa_os_memset(sgpg, 0, sizeof(*sgpg)); + + hsgpg->sgpg = sgpg; + sgpg_pa_tmp.pa = bfa_sgaddr_le(sgpg_pa.pa); + hsgpg->sgpg_pa = sgpg_pa_tmp.addr; + list_add_tail(&hsgpg->qe, &mod->sgpg_q); + + hsgpg++; + sgpg++; + sgpg_pa.pa += sizeof(struct bfi_sgpg_s); + } + + bfa_meminfo_kva(minfo) = (u8 *) hsgpg; + bfa_meminfo_dma_virt(minfo) = (u8 *) sgpg; + bfa_meminfo_dma_phys(minfo) = sgpg_pa.pa; +} + +static void +bfa_sgpg_detach(struct bfa_s *bfa) +{ +} + +static void +bfa_sgpg_start(struct bfa_s *bfa) +{ +} + +static void +bfa_sgpg_stop(struct bfa_s *bfa) +{ +} + +static void +bfa_sgpg_iocdisable(struct bfa_s *bfa) +{ +} + + + +/** + * hal_sgpg_public BFA SGPG public functions + */ + +bfa_status_t +bfa_sgpg_malloc(struct bfa_s *bfa, struct list_head *sgpg_q, int nsgpgs) +{ + struct bfa_sgpg_mod_s *mod = BFA_SGPG_MOD(bfa); + struct bfa_sgpg_s *hsgpg; + int i; + + bfa_trc_fp(bfa, nsgpgs); + + if (mod->free_sgpgs < nsgpgs) + return BFA_STATUS_ENOMEM; + + for (i = 0; i < nsgpgs; i++) { + bfa_q_deq(&mod->sgpg_q, &hsgpg); + bfa_assert(hsgpg); + list_add_tail(&hsgpg->qe, sgpg_q); + } + + mod->free_sgpgs -= nsgpgs; + return BFA_STATUS_OK; +} + +void +bfa_sgpg_mfree(struct bfa_s *bfa, struct list_head *sgpg_q, int nsgpg) +{ + struct bfa_sgpg_mod_s *mod = BFA_SGPG_MOD(bfa); + struct bfa_sgpg_wqe_s *wqe; + + bfa_trc_fp(bfa, nsgpg); + + mod->free_sgpgs += nsgpg; + bfa_assert(mod->free_sgpgs <= mod->num_sgpgs); + + list_splice_tail_init(sgpg_q, &mod->sgpg_q); + + if (list_empty(&mod->sgpg_wait_q)) + return; + + /** + * satisfy as many waiting requests as possible + */ + do { + wqe = bfa_q_first(&mod->sgpg_wait_q); + if (mod->free_sgpgs < wqe->nsgpg) + nsgpg = mod->free_sgpgs; + else + nsgpg = wqe->nsgpg; + bfa_sgpg_malloc(bfa, &wqe->sgpg_q, nsgpg); + wqe->nsgpg -= nsgpg; + if (wqe->nsgpg == 0) { + list_del(&wqe->qe); + wqe->cbfn(wqe->cbarg); + } + } while (mod->free_sgpgs && !list_empty(&mod->sgpg_wait_q)); +} + +void +bfa_sgpg_wait(struct bfa_s *bfa, struct bfa_sgpg_wqe_s *wqe, int nsgpg) +{ + struct bfa_sgpg_mod_s *mod = BFA_SGPG_MOD(bfa); + + bfa_assert(nsgpg > 0); + bfa_assert(nsgpg > mod->free_sgpgs); + + wqe->nsgpg_total = wqe->nsgpg = nsgpg; + + /** + * allocate any left to this one first + */ + if (mod->free_sgpgs) { + /** + * no one else is waiting for SGPG + */ + bfa_assert(list_empty(&mod->sgpg_wait_q)); + list_splice_tail_init(&mod->sgpg_q, &wqe->sgpg_q); + wqe->nsgpg -= mod->free_sgpgs; + mod->free_sgpgs = 0; + } + + list_add_tail(&wqe->qe, &mod->sgpg_wait_q); +} + +void +bfa_sgpg_wcancel(struct bfa_s *bfa, struct bfa_sgpg_wqe_s *wqe) +{ + struct bfa_sgpg_mod_s *mod = BFA_SGPG_MOD(bfa); + + bfa_assert(bfa_q_is_on_q(&mod->sgpg_wait_q, wqe)); + list_del(&wqe->qe); + + if (wqe->nsgpg_total != wqe->nsgpg) + bfa_sgpg_mfree(bfa, &wqe->sgpg_q, + wqe->nsgpg_total - wqe->nsgpg); +} + +void +bfa_sgpg_winit(struct bfa_sgpg_wqe_s *wqe, void (*cbfn) (void *cbarg), + void *cbarg) +{ + INIT_LIST_HEAD(&wqe->sgpg_q); + wqe->cbfn = cbfn; + wqe->cbarg = cbarg; +} + +/** + * UF related functions + */ +/* + ***************************************************************************** + * Internal functions + ***************************************************************************** + */ +static void +__bfa_cb_uf_recv(void *cbarg, bfa_boolean_t complete) +{ + struct bfa_uf_s *uf = cbarg; + struct bfa_uf_mod_s *ufm = BFA_UF_MOD(uf->bfa); + + if (complete) + ufm->ufrecv(ufm->cbarg, uf); +} + +static void +claim_uf_pbs(struct bfa_uf_mod_s *ufm, struct bfa_meminfo_s *mi) +{ + u32 uf_pb_tot_sz; + + ufm->uf_pbs_kva = (struct bfa_uf_buf_s *) bfa_meminfo_dma_virt(mi); + ufm->uf_pbs_pa = bfa_meminfo_dma_phys(mi); + uf_pb_tot_sz = BFA_ROUNDUP((sizeof(struct bfa_uf_buf_s) * ufm->num_ufs), + BFA_DMA_ALIGN_SZ); + + bfa_meminfo_dma_virt(mi) += uf_pb_tot_sz; + bfa_meminfo_dma_phys(mi) += uf_pb_tot_sz; + + bfa_os_memset((void *)ufm->uf_pbs_kva, 0, uf_pb_tot_sz); +} + +static void +claim_uf_post_msgs(struct bfa_uf_mod_s *ufm, struct bfa_meminfo_s *mi) +{ + struct bfi_uf_buf_post_s *uf_bp_msg; + struct bfi_sge_s *sge; + union bfi_addr_u sga_zero = { {0} }; + u16 i; + u16 buf_len; + + ufm->uf_buf_posts = (struct bfi_uf_buf_post_s *) bfa_meminfo_kva(mi); + uf_bp_msg = ufm->uf_buf_posts; + + for (i = 0, uf_bp_msg = ufm->uf_buf_posts; i < ufm->num_ufs; + i++, uf_bp_msg++) { + bfa_os_memset(uf_bp_msg, 0, sizeof(struct bfi_uf_buf_post_s)); + + uf_bp_msg->buf_tag = i; + buf_len = sizeof(struct bfa_uf_buf_s); + uf_bp_msg->buf_len = bfa_os_htons(buf_len); + bfi_h2i_set(uf_bp_msg->mh, BFI_MC_UF, BFI_UF_H2I_BUF_POST, + bfa_lpuid(ufm->bfa)); + + sge = uf_bp_msg->sge; + sge[0].sg_len = buf_len; + sge[0].flags = BFI_SGE_DATA_LAST; + bfa_dma_addr_set(sge[0].sga, ufm_pbs_pa(ufm, i)); + bfa_sge_to_be(sge); + + sge[1].sg_len = buf_len; + sge[1].flags = BFI_SGE_PGDLEN; + sge[1].sga = sga_zero; + bfa_sge_to_be(&sge[1]); + } + + /** + * advance pointer beyond consumed memory + */ + bfa_meminfo_kva(mi) = (u8 *) uf_bp_msg; +} + +static void +claim_ufs(struct bfa_uf_mod_s *ufm, struct bfa_meminfo_s *mi) +{ + u16 i; + struct bfa_uf_s *uf; + + /* + * Claim block of memory for UF list + */ + ufm->uf_list = (struct bfa_uf_s *) bfa_meminfo_kva(mi); + + /* + * Initialize UFs and queue it in UF free queue + */ + for (i = 0, uf = ufm->uf_list; i < ufm->num_ufs; i++, uf++) { + bfa_os_memset(uf, 0, sizeof(struct bfa_uf_s)); + uf->bfa = ufm->bfa; + uf->uf_tag = i; + uf->pb_len = sizeof(struct bfa_uf_buf_s); + uf->buf_kva = (void *)&ufm->uf_pbs_kva[i]; + uf->buf_pa = ufm_pbs_pa(ufm, i); + list_add_tail(&uf->qe, &ufm->uf_free_q); + } + + /** + * advance memory pointer + */ + bfa_meminfo_kva(mi) = (u8 *) uf; +} + +static void +uf_mem_claim(struct bfa_uf_mod_s *ufm, struct bfa_meminfo_s *mi) +{ + claim_uf_pbs(ufm, mi); + claim_ufs(ufm, mi); + claim_uf_post_msgs(ufm, mi); +} + +static void +bfa_uf_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len, u32 *dm_len) +{ + u32 num_ufs = cfg->fwcfg.num_uf_bufs; + + /* + * dma-able memory for UF posted bufs + */ + *dm_len += BFA_ROUNDUP((sizeof(struct bfa_uf_buf_s) * num_ufs), + BFA_DMA_ALIGN_SZ); + + /* + * kernel Virtual memory for UFs and UF buf post msg copies + */ + *ndm_len += sizeof(struct bfa_uf_s) * num_ufs; + *ndm_len += sizeof(struct bfi_uf_buf_post_s) * num_ufs; +} + +static void +bfa_uf_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, + struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev) +{ + struct bfa_uf_mod_s *ufm = BFA_UF_MOD(bfa); + + bfa_os_memset(ufm, 0, sizeof(struct bfa_uf_mod_s)); + ufm->bfa = bfa; + ufm->num_ufs = cfg->fwcfg.num_uf_bufs; + INIT_LIST_HEAD(&ufm->uf_free_q); + INIT_LIST_HEAD(&ufm->uf_posted_q); + + uf_mem_claim(ufm, meminfo); +} + +static void +bfa_uf_detach(struct bfa_s *bfa) +{ +} + +static struct bfa_uf_s * +bfa_uf_get(struct bfa_uf_mod_s *uf_mod) +{ + struct bfa_uf_s *uf; + + bfa_q_deq(&uf_mod->uf_free_q, &uf); + return uf; +} + +static void +bfa_uf_put(struct bfa_uf_mod_s *uf_mod, struct bfa_uf_s *uf) +{ + list_add_tail(&uf->qe, &uf_mod->uf_free_q); +} + +static bfa_status_t +bfa_uf_post(struct bfa_uf_mod_s *ufm, struct bfa_uf_s *uf) +{ + struct bfi_uf_buf_post_s *uf_post_msg; + + uf_post_msg = bfa_reqq_next(ufm->bfa, BFA_REQQ_FCXP); + if (!uf_post_msg) + return BFA_STATUS_FAILED; + + bfa_os_memcpy(uf_post_msg, &ufm->uf_buf_posts[uf->uf_tag], + sizeof(struct bfi_uf_buf_post_s)); + bfa_reqq_produce(ufm->bfa, BFA_REQQ_FCXP); + + bfa_trc(ufm->bfa, uf->uf_tag); + + list_add_tail(&uf->qe, &ufm->uf_posted_q); + return BFA_STATUS_OK; +} + +static void +bfa_uf_post_all(struct bfa_uf_mod_s *uf_mod) +{ + struct bfa_uf_s *uf; + + while ((uf = bfa_uf_get(uf_mod)) != NULL) { + if (bfa_uf_post(uf_mod, uf) != BFA_STATUS_OK) + break; + } +} + +static void +uf_recv(struct bfa_s *bfa, struct bfi_uf_frm_rcvd_s *m) +{ + struct bfa_uf_mod_s *ufm = BFA_UF_MOD(bfa); + u16 uf_tag = m->buf_tag; + struct bfa_uf_buf_s *uf_buf = &ufm->uf_pbs_kva[uf_tag]; + struct bfa_uf_s *uf = &ufm->uf_list[uf_tag]; + u8 *buf = &uf_buf->d[0]; + struct fchs_s *fchs; + + m->frm_len = bfa_os_ntohs(m->frm_len); + m->xfr_len = bfa_os_ntohs(m->xfr_len); + + fchs = (struct fchs_s *)uf_buf; + + list_del(&uf->qe); /* dequeue from posted queue */ + + uf->data_ptr = buf; + uf->data_len = m->xfr_len; + + bfa_assert(uf->data_len >= sizeof(struct fchs_s)); + + if (uf->data_len == sizeof(struct fchs_s)) { + bfa_plog_fchdr(bfa->plog, BFA_PL_MID_HAL_UF, BFA_PL_EID_RX, + uf->data_len, (struct fchs_s *)buf); + } else { + u32 pld_w0 = *((u32 *) (buf + sizeof(struct fchs_s))); + bfa_plog_fchdr_and_pl(bfa->plog, BFA_PL_MID_HAL_UF, + BFA_PL_EID_RX, uf->data_len, + (struct fchs_s *)buf, pld_w0); + } + + 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 +bfa_uf_stop(struct bfa_s *bfa) +{ +} + +static void +bfa_uf_iocdisable(struct bfa_s *bfa) +{ + struct bfa_uf_mod_s *ufm = BFA_UF_MOD(bfa); + struct bfa_uf_s *uf; + struct list_head *qe, *qen; + + list_for_each_safe(qe, qen, &ufm->uf_posted_q) { + uf = (struct bfa_uf_s *) qe; + list_del(&uf->qe); + bfa_uf_put(ufm, uf); + } +} + +static void +bfa_uf_start(struct bfa_s *bfa) +{ + bfa_uf_post_all(BFA_UF_MOD(bfa)); +} + + + +/** + * hal_uf_api + */ + +/** + * Register handler for all unsolicted recieve frames. + * + * @param[in] bfa BFA instance + * @param[in] ufrecv receive handler function + * @param[in] cbarg receive handler arg + */ +void +bfa_uf_recv_register(struct bfa_s *bfa, bfa_cb_uf_recv_t ufrecv, void *cbarg) +{ + struct bfa_uf_mod_s *ufm = BFA_UF_MOD(bfa); + + ufm->ufrecv = ufrecv; + ufm->cbarg = cbarg; +} + +/** + * Free an unsolicited frame back to BFA. + * + * @param[in] uf unsolicited frame to be freed + * + * @return None + */ +void +bfa_uf_free(struct bfa_uf_s *uf) +{ + bfa_uf_put(BFA_UF_MOD(uf->bfa), uf); + bfa_uf_post_all(BFA_UF_MOD(uf->bfa)); +} + + + +/** + * uf_pub BFA uf module public functions + */ +void +bfa_uf_isr(struct bfa_s *bfa, struct bfi_msg_s *msg) +{ + bfa_trc(bfa, msg->mhdr.msg_id); + + switch (msg->mhdr.msg_id) { + case BFI_UF_I2H_FRM_RCVD: + uf_recv(bfa, (struct bfi_uf_frm_rcvd_s *) msg); + break; + + default: + bfa_trc(bfa, msg->mhdr.msg_id); + bfa_assert(0); + } +} + + diff --git a/drivers/scsi/bfa/bfa_svc.h b/drivers/scsi/bfa/bfa_svc.h new file mode 100644 index 000000000000..9921dad0d039 --- /dev/null +++ b/drivers/scsi/bfa/bfa_svc.h @@ -0,0 +1,657 @@ +/* + * 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 __BFA_SVC_H__ +#define __BFA_SVC_H__ + +#include "bfa_cs.h" +#include "bfi_ms.h" + + +/** + * Scatter-gather DMA related defines + */ +#define BFA_SGPG_MIN (16) + +/** + * Alignment macro for SG page allocation + */ +#define BFA_SGPG_ROUNDUP(_l) (((_l) + (sizeof(struct bfi_sgpg_s) - 1)) \ + & ~(sizeof(struct bfi_sgpg_s) - 1)) + +struct bfa_sgpg_wqe_s { + struct list_head qe; /* queue sg page element */ + int nsgpg; /* pages to be allocated */ + int nsgpg_total; /* total pages required */ + void (*cbfn) (void *cbarg); /* callback function */ + void *cbarg; /* callback arg */ + struct list_head sgpg_q; /* queue of alloced sgpgs */ +}; + +struct bfa_sgpg_s { + struct list_head qe; /* queue sg page element */ + struct bfi_sgpg_s *sgpg; /* va of SG page */ + union bfi_addr_u sgpg_pa; /* pa of SG page */ +}; + +/** + * Given number of SG elements, BFA_SGPG_NPAGE() returns the number of + * SG pages required. + */ +#define BFA_SGPG_NPAGE(_nsges) (((_nsges) / BFI_SGPG_DATA_SGES) + 1) + +struct bfa_sgpg_mod_s { + struct bfa_s *bfa; + int num_sgpgs; /* number of SG pages */ + int free_sgpgs; /* number of free SG pages */ + struct bfa_sgpg_s *hsgpg_arr; /* BFA SG page array */ + struct bfi_sgpg_s *sgpg_arr; /* actual SG page array */ + u64 sgpg_arr_pa; /* SG page array DMA addr */ + struct list_head sgpg_q; /* queue of free SG pages */ + struct list_head sgpg_wait_q; /* wait queue for SG pages */ +}; +#define BFA_SGPG_MOD(__bfa) (&(__bfa)->modules.sgpg_mod) + +bfa_status_t bfa_sgpg_malloc(struct bfa_s *bfa, struct list_head *sgpg_q, + int nsgpgs); +void bfa_sgpg_mfree(struct bfa_s *bfa, struct list_head *sgpg_q, int nsgpgs); +void bfa_sgpg_winit(struct bfa_sgpg_wqe_s *wqe, + void (*cbfn) (void *cbarg), void *cbarg); +void bfa_sgpg_wait(struct bfa_s *bfa, struct bfa_sgpg_wqe_s *wqe, int nsgpgs); +void bfa_sgpg_wcancel(struct bfa_s *bfa, struct bfa_sgpg_wqe_s *wqe); + + +/** + * FCXP related defines + */ +#define BFA_FCXP_MIN (1) +#define BFA_FCXP_MAX_IBUF_SZ (2 * 1024 + 256) +#define BFA_FCXP_MAX_LBUF_SZ (4 * 1024 + 256) + +struct bfa_fcxp_mod_s { + struct bfa_s *bfa; /* backpointer to BFA */ + struct bfa_fcxp_s *fcxp_list; /* array of FCXPs */ + u16 num_fcxps; /* max num FCXP requests */ + struct list_head fcxp_free_q; /* free FCXPs */ + struct list_head fcxp_active_q; /* active FCXPs */ + void *req_pld_list_kva; /* list of FCXP req pld */ + u64 req_pld_list_pa; /* list of FCXP req pld */ + void *rsp_pld_list_kva; /* list of FCXP resp pld */ + u64 rsp_pld_list_pa; /* list of FCXP resp pld */ + struct list_head wait_q; /* wait queue for free fcxp */ + u32 req_pld_sz; + u32 rsp_pld_sz; +}; + +#define BFA_FCXP_MOD(__bfa) (&(__bfa)->modules.fcxp_mod) +#define BFA_FCXP_FROM_TAG(__mod, __tag) (&(__mod)->fcxp_list[__tag]) + +typedef void (*fcxp_send_cb_t) (struct bfa_s *ioc, struct bfa_fcxp_s *fcxp, + void *cb_arg, bfa_status_t req_status, + u32 rsp_len, u32 resid_len, + struct fchs_s *rsp_fchs); + +typedef u64 (*bfa_fcxp_get_sgaddr_t) (void *bfad_fcxp, int sgeid); +typedef u32 (*bfa_fcxp_get_sglen_t) (void *bfad_fcxp, int sgeid); +typedef void (*bfa_cb_fcxp_send_t) (void *bfad_fcxp, struct bfa_fcxp_s *fcxp, + void *cbarg, enum bfa_status req_status, + u32 rsp_len, u32 resid_len, + struct fchs_s *rsp_fchs); +typedef void (*bfa_fcxp_alloc_cbfn_t) (void *cbarg, struct bfa_fcxp_s *fcxp); + + + +/** + * Information needed for a FCXP request + */ +struct bfa_fcxp_req_info_s { + struct bfa_rport_s *bfa_rport; + /** Pointer to the bfa rport that was + * returned from bfa_rport_create(). + * This could be left NULL for WKA or + * for FCXP interactions before the + * rport nexus is established + */ + struct fchs_s fchs; /* request FC header structure */ + u8 cts; /* continous sequence */ + u8 class; /* FC class for the request/response */ + u16 max_frmsz; /* max send frame size */ + u16 vf_id; /* vsan tag if applicable */ + u8 lp_tag; /* lport tag */ + u32 req_tot_len; /* request payload total length */ +}; + +struct bfa_fcxp_rsp_info_s { + struct fchs_s rsp_fchs; + /** !< Response frame's FC header will + * be sent back in this field */ + u8 rsp_timeout; + /** !< timeout in seconds, 0-no response + */ + u8 rsvd2[3]; + u32 rsp_maxlen; /* max response length expected */ +}; + +struct bfa_fcxp_s { + struct list_head qe; /* fcxp queue element */ + bfa_sm_t sm; /* state machine */ + void *caller; /* driver or fcs */ + struct bfa_fcxp_mod_s *fcxp_mod; + /* back pointer to fcxp mod */ + u16 fcxp_tag; /* internal tag */ + struct bfa_fcxp_req_info_s req_info; + /* request info */ + struct bfa_fcxp_rsp_info_s rsp_info; + /* response info */ + u8 use_ireqbuf; /* use internal req buf */ + u8 use_irspbuf; /* use internal rsp buf */ + u32 nreq_sgles; /* num request SGLEs */ + u32 nrsp_sgles; /* num response SGLEs */ + struct list_head req_sgpg_q; /* SG pages for request buf */ + struct list_head req_sgpg_wqe; /* wait queue for req SG page */ + struct list_head rsp_sgpg_q; /* SG pages for response buf */ + struct list_head rsp_sgpg_wqe; /* wait queue for rsp SG page */ + + bfa_fcxp_get_sgaddr_t req_sga_cbfn; + /* SG elem addr user function */ + bfa_fcxp_get_sglen_t req_sglen_cbfn; + /* SG elem len user function */ + bfa_fcxp_get_sgaddr_t rsp_sga_cbfn; + /* SG elem addr user function */ + bfa_fcxp_get_sglen_t rsp_sglen_cbfn; + /* SG elem len user function */ + bfa_cb_fcxp_send_t send_cbfn; /* send completion callback */ + void *send_cbarg; /* callback arg */ + struct bfa_sge_s req_sge[BFA_FCXP_MAX_SGES]; + /* req SG elems */ + struct bfa_sge_s rsp_sge[BFA_FCXP_MAX_SGES]; + /* rsp SG elems */ + u8 rsp_status; /* comp: rsp status */ + u32 rsp_len; /* comp: actual response len */ + u32 residue_len; /* comp: residual rsp length */ + struct fchs_s rsp_fchs; /* comp: response fchs */ + struct bfa_cb_qe_s hcb_qe; /* comp: callback qelem */ + struct bfa_reqq_wait_s reqq_wqe; + bfa_boolean_t reqq_waiting; +}; + +struct bfa_fcxp_wqe_s { + struct list_head qe; + bfa_fcxp_alloc_cbfn_t alloc_cbfn; + void *alloc_cbarg; + void *caller; + struct bfa_s *bfa; + int nreq_sgles; + int nrsp_sgles; + bfa_fcxp_get_sgaddr_t req_sga_cbfn; + bfa_fcxp_get_sglen_t req_sglen_cbfn; + bfa_fcxp_get_sgaddr_t rsp_sga_cbfn; + bfa_fcxp_get_sglen_t rsp_sglen_cbfn; +}; + +#define BFA_FCXP_REQ_PLD(_fcxp) (bfa_fcxp_get_reqbuf(_fcxp)) +#define BFA_FCXP_RSP_FCHS(_fcxp) (&((_fcxp)->rsp_info.fchs)) +#define BFA_FCXP_RSP_PLD(_fcxp) (bfa_fcxp_get_rspbuf(_fcxp)) + +#define BFA_FCXP_REQ_PLD_PA(_fcxp) \ + ((_fcxp)->fcxp_mod->req_pld_list_pa + \ + ((_fcxp)->fcxp_mod->req_pld_sz * (_fcxp)->fcxp_tag)) + +#define BFA_FCXP_RSP_PLD_PA(_fcxp) \ + ((_fcxp)->fcxp_mod->rsp_pld_list_pa + \ + ((_fcxp)->fcxp_mod->rsp_pld_sz * (_fcxp)->fcxp_tag)) + +void bfa_fcxp_isr(struct bfa_s *bfa, struct bfi_msg_s *msg); + + +/** + * RPORT related defines + */ +#define BFA_RPORT_MIN 4 + +struct bfa_rport_mod_s { + struct bfa_rport_s *rps_list; /* list of rports */ + struct list_head rp_free_q; /* free bfa_rports */ + struct list_head rp_active_q; /* free bfa_rports */ + u16 num_rports; /* number of rports */ +}; + +#define BFA_RPORT_MOD(__bfa) (&(__bfa)->modules.rport_mod) + +/** + * Convert rport tag to RPORT + */ +#define BFA_RPORT_FROM_TAG(__bfa, _tag) \ + (BFA_RPORT_MOD(__bfa)->rps_list + \ + ((_tag) & (BFA_RPORT_MOD(__bfa)->num_rports - 1))) + +/* + * protected functions + */ +void bfa_rport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg); + +/** + * BFA rport information. + */ +struct bfa_rport_info_s { + u16 max_frmsz; /* max rcv pdu size */ + u32 pid:24, /* remote port ID */ + lp_tag:8; /* tag */ + u32 local_pid:24, /* local port ID */ + cisc:8; /* CIRO supported */ + u8 fc_class; /* supported FC classes. enum fc_cos */ + u8 vf_en; /* virtual fabric enable */ + u16 vf_id; /* virtual fabric ID */ + enum bfa_port_speed speed; /* Rport's current speed */ +}; + +/** + * BFA rport data structure + */ +struct bfa_rport_s { + struct list_head qe; /* queue element */ + bfa_sm_t sm; /* state machine */ + struct bfa_s *bfa; /* backpointer to BFA */ + void *rport_drv; /* fcs/driver rport object */ + u16 fw_handle; /* firmware rport handle */ + u16 rport_tag; /* BFA rport tag */ + struct bfa_rport_info_s rport_info; /* rport info from fcs/driver */ + struct bfa_reqq_wait_s reqq_wait; /* to wait for room in reqq */ + struct bfa_cb_qe_s hcb_qe; /* BFA callback qelem */ + struct bfa_rport_hal_stats_s stats; /* BFA rport statistics */ + struct bfa_rport_qos_attr_s qos_attr; + union a { + bfa_status_t status; /* f/w status */ + void *fw_msg; /* QoS scn event */ + } event_arg; +}; +#define BFA_RPORT_FC_COS(_rport) ((_rport)->rport_info.fc_class) + + +/** + * UF - unsolicited receive related defines + */ + +#define BFA_UF_MIN (4) + + +struct bfa_uf_s { + struct list_head qe; /* queue element */ + struct bfa_s *bfa; /* bfa instance */ + u16 uf_tag; /* identifying tag fw msgs */ + u16 vf_id; + u16 src_rport_handle; + u16 rsvd; + u8 *data_ptr; + u16 data_len; /* actual receive length */ + u16 pb_len; /* posted buffer length */ + void *buf_kva; /* buffer virtual address */ + u64 buf_pa; /* buffer physical address */ + struct bfa_cb_qe_s hcb_qe; /* comp: BFA comp qelem */ + struct bfa_sge_s sges[BFI_SGE_INLINE_MAX]; +}; + +/** + * Callback prototype for unsolicited frame receive handler. + * + * @param[in] cbarg callback arg for receive handler + * @param[in] uf unsolicited frame descriptor + * + * @return None + */ +typedef void (*bfa_cb_uf_recv_t) (void *cbarg, struct bfa_uf_s *uf); + +struct bfa_uf_mod_s { + struct bfa_s *bfa; /* back pointer to BFA */ + struct bfa_uf_s *uf_list; /* array of UFs */ + u16 num_ufs; /* num unsolicited rx frames */ + struct list_head uf_free_q; /* free UFs */ + struct list_head uf_posted_q; /* UFs posted to IOC */ + struct bfa_uf_buf_s *uf_pbs_kva; /* list UF bufs request pld */ + u64 uf_pbs_pa; /* phy addr for UF bufs */ + struct bfi_uf_buf_post_s *uf_buf_posts; + /* pre-built UF post msgs */ + bfa_cb_uf_recv_t ufrecv; /* uf recv handler function */ + void *cbarg; /* uf receive handler arg */ +}; + +#define BFA_UF_MOD(__bfa) (&(__bfa)->modules.uf_mod) + +#define ufm_pbs_pa(_ufmod, _uftag) \ + ((_ufmod)->uf_pbs_pa + sizeof(struct bfa_uf_buf_s) * (_uftag)) + +void bfa_uf_isr(struct bfa_s *bfa, struct bfi_msg_s *msg); + +#define BFA_UF_BUFSZ (2 * 1024 + 256) + +/** + * @todo private + */ +struct bfa_uf_buf_s { + u8 d[BFA_UF_BUFSZ]; +}; + + +/** + * LPS - bfa lport login/logout service interface + */ +struct bfa_lps_s { + struct list_head qe; /* queue element */ + struct bfa_s *bfa; /* parent bfa instance */ + bfa_sm_t sm; /* finite state machine */ + u8 lp_tag; /* lport tag */ + u8 reqq; /* lport request queue */ + u8 alpa; /* ALPA for loop topologies */ + u32 lp_pid; /* lport port ID */ + bfa_boolean_t fdisc; /* snd FDISC instead of FLOGI */ + bfa_boolean_t auth_en; /* enable authentication */ + bfa_boolean_t auth_req; /* authentication required */ + bfa_boolean_t npiv_en; /* NPIV is allowed by peer */ + bfa_boolean_t fport; /* attached peer is F_PORT */ + bfa_boolean_t brcd_switch; /* attached peer is brcd sw */ + bfa_status_t status; /* login status */ + u16 pdusz; /* max receive PDU size */ + u16 pr_bbcred; /* BB_CREDIT from peer */ + u8 lsrjt_rsn; /* LSRJT reason */ + u8 lsrjt_expl; /* LSRJT explanation */ + wwn_t pwwn; /* port wwn of lport */ + wwn_t nwwn; /* node wwn of lport */ + wwn_t pr_pwwn; /* port wwn of lport peer */ + wwn_t pr_nwwn; /* node wwn of lport peer */ + mac_t lp_mac; /* fpma/spma MAC for lport */ + mac_t fcf_mac; /* FCF MAC of lport */ + struct bfa_reqq_wait_s wqe; /* request wait queue element */ + void *uarg; /* user callback arg */ + struct bfa_cb_qe_s hcb_qe; /* comp: callback qelem */ + struct bfi_lps_login_rsp_s *loginrsp; + bfa_eproto_status_t ext_status; +}; + +struct bfa_lps_mod_s { + struct list_head lps_free_q; + struct list_head lps_active_q; + struct bfa_lps_s *lps_arr; + int num_lps; +}; + +#define BFA_LPS_MOD(__bfa) (&(__bfa)->modules.lps_mod) +#define BFA_LPS_FROM_TAG(__mod, __tag) (&(__mod)->lps_arr[__tag]) + +/* + * external functions + */ +void bfa_lps_isr(struct bfa_s *bfa, struct bfi_msg_s *msg); + + +/** + * FCPORT related defines + */ + +#define BFA_FCPORT(_bfa) (&((_bfa)->modules.port)) +typedef void (*bfa_cb_port_t) (void *cbarg, enum bfa_status status); + +/** + * Link notification data structure + */ +struct bfa_fcport_ln_s { + struct bfa_fcport_s *fcport; + bfa_sm_t sm; + struct bfa_cb_qe_s ln_qe; /* BFA callback queue elem for ln */ + enum bfa_port_linkstate ln_event; /* ln event for callback */ +}; + +struct bfa_fcport_trunk_s { + struct bfa_trunk_attr_s attr; +}; + +/** + * BFA FC port data structure + */ +struct bfa_fcport_s { + struct bfa_s *bfa; /* parent BFA instance */ + bfa_sm_t sm; /* port state machine */ + wwn_t nwwn; /* node wwn of physical port */ + wwn_t pwwn; /* port wwn of physical oprt */ + enum bfa_port_speed speed_sup; + /* supported speeds */ + enum bfa_port_speed speed; /* current speed */ + enum bfa_port_topology topology; /* current topology */ + u8 myalpa; /* my ALPA in LOOP topology */ + u8 rsvd[3]; + struct bfa_port_cfg_s cfg; /* current port configuration */ + struct bfa_qos_attr_s qos_attr; /* QoS Attributes */ + struct bfa_qos_vc_attr_s qos_vc_attr; /* VC info from ELP */ + struct bfa_reqq_wait_s reqq_wait; + /* to wait for room in reqq */ + struct bfa_reqq_wait_s svcreq_wait; + /* to wait for room in reqq */ + struct bfa_reqq_wait_s stats_reqq_wait; + /* to wait for room in reqq (stats) */ + void *event_cbarg; + void (*event_cbfn) (void *cbarg, + enum bfa_port_linkstate event); + union { + union bfi_fcport_i2h_msg_u i2hmsg; + } event_arg; + void *bfad; /* BFA driver handle */ + struct bfa_fcport_ln_s ln; /* Link Notification */ + struct bfa_cb_qe_s hcb_qe; /* BFA callback queue elem */ + struct bfa_timer_s timer; /* timer */ + u32 msgtag; /* fimrware msg tag for reply */ + u8 *stats_kva; + u64 stats_pa; + union bfa_fcport_stats_u *stats; + union bfa_fcport_stats_u *stats_ret; /* driver stats location */ + bfa_status_t stats_status; /* stats/statsclr status */ + bfa_boolean_t stats_busy; /* outstanding stats/statsclr */ + bfa_boolean_t stats_qfull; + u32 stats_reset_time; /* stats reset time stamp */ + bfa_cb_port_t stats_cbfn; /* driver callback function */ + 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 */ + struct bfa_fcport_trunk_s trunk; + u16 fcoe_vlan; +}; + +#define BFA_FCPORT_MOD(__bfa) (&(__bfa)->modules.fcport) + +/* + * protected functions + */ +void bfa_fcport_init(struct bfa_s *bfa); +void bfa_fcport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg); + +/* + * bfa fcport API functions + */ +bfa_status_t bfa_fcport_enable(struct bfa_s *bfa); +bfa_status_t bfa_fcport_disable(struct bfa_s *bfa); +bfa_status_t bfa_fcport_cfg_speed(struct bfa_s *bfa, + enum bfa_port_speed speed); +enum bfa_port_speed bfa_fcport_get_speed(struct bfa_s *bfa); +bfa_status_t bfa_fcport_cfg_topology(struct bfa_s *bfa, + enum bfa_port_topology topo); +enum bfa_port_topology bfa_fcport_get_topology(struct bfa_s *bfa); +bfa_status_t bfa_fcport_cfg_hardalpa(struct bfa_s *bfa, u8 alpa); +bfa_boolean_t bfa_fcport_get_hardalpa(struct bfa_s *bfa, u8 *alpa); +u8 bfa_fcport_get_myalpa(struct bfa_s *bfa); +bfa_status_t bfa_fcport_clr_hardalpa(struct bfa_s *bfa); +bfa_status_t bfa_fcport_cfg_maxfrsize(struct bfa_s *bfa, u16 maxsize); +u16 bfa_fcport_get_maxfrsize(struct bfa_s *bfa); +u8 bfa_fcport_get_rx_bbcredit(struct bfa_s *bfa); +void bfa_fcport_get_attr(struct bfa_s *bfa, struct bfa_port_attr_s *attr); +wwn_t bfa_fcport_get_wwn(struct bfa_s *bfa, bfa_boolean_t node); +void bfa_fcport_event_register(struct bfa_s *bfa, + void (*event_cbfn) (void *cbarg, + enum bfa_port_linkstate event), void *event_cbarg); +bfa_boolean_t bfa_fcport_is_disabled(struct bfa_s *bfa); +void bfa_fcport_cfg_qos(struct bfa_s *bfa, bfa_boolean_t on_off); +void bfa_fcport_cfg_ratelim(struct bfa_s *bfa, bfa_boolean_t on_off); +bfa_status_t bfa_fcport_cfg_ratelim_speed(struct bfa_s *bfa, + enum bfa_port_speed speed); +enum bfa_port_speed bfa_fcport_get_ratelim_speed(struct bfa_s *bfa); + +void bfa_fcport_set_tx_bbcredit(struct bfa_s *bfa, u16 tx_bbcredit); +void bfa_fcport_busy(struct bfa_s *bfa, bfa_boolean_t status); +void bfa_fcport_beacon(void *dev, bfa_boolean_t beacon, + bfa_boolean_t link_e2e_beacon); +void bfa_fcport_qos_get_attr(struct bfa_s *bfa, + struct bfa_qos_attr_s *qos_attr); +void bfa_fcport_qos_get_vc_attr(struct bfa_s *bfa, + struct bfa_qos_vc_attr_s *qos_vc_attr); +bfa_status_t bfa_fcport_get_qos_stats(struct bfa_s *bfa, + union bfa_fcport_stats_u *stats, + bfa_cb_port_t cbfn, void *cbarg); +bfa_status_t bfa_fcport_clear_qos_stats(struct bfa_s *bfa, bfa_cb_port_t cbfn, + void *cbarg); +bfa_status_t bfa_fcport_get_fcoe_stats(struct bfa_s *bfa, + union bfa_fcport_stats_u *stats, + bfa_cb_port_t cbfn, void *cbarg); +bfa_status_t bfa_fcport_clear_fcoe_stats(struct bfa_s *bfa, bfa_cb_port_t cbfn, + void *cbarg); +bfa_boolean_t bfa_fcport_is_ratelim(struct bfa_s *bfa); +bfa_boolean_t bfa_fcport_is_linkup(struct bfa_s *bfa); +bfa_status_t bfa_fcport_get_stats(struct bfa_s *bfa, + union bfa_fcport_stats_u *stats, + bfa_cb_port_t cbfn, void *cbarg); +bfa_status_t bfa_fcport_clear_stats(struct bfa_s *bfa, bfa_cb_port_t cbfn, + void *cbarg); +bfa_boolean_t bfa_fcport_is_qos_enabled(struct bfa_s *bfa); + +/* + * bfa rport API functions + */ +struct bfa_rport_s *bfa_rport_create(struct bfa_s *bfa, void *rport_drv); +void bfa_rport_delete(struct bfa_rport_s *rport); +void bfa_rport_online(struct bfa_rport_s *rport, + struct bfa_rport_info_s *rport_info); +void bfa_rport_offline(struct bfa_rport_s *rport); +void bfa_rport_speed(struct bfa_rport_s *rport, enum bfa_port_speed speed); +void bfa_rport_get_stats(struct bfa_rport_s *rport, + struct bfa_rport_hal_stats_s *stats); +void bfa_rport_clear_stats(struct bfa_rport_s *rport); +void bfa_cb_rport_online(void *rport); +void bfa_cb_rport_offline(void *rport); +void bfa_cb_rport_qos_scn_flowid(void *rport, + struct bfa_rport_qos_attr_s old_qos_attr, + struct bfa_rport_qos_attr_s new_qos_attr); +void bfa_cb_rport_qos_scn_prio(void *rport, + struct bfa_rport_qos_attr_s old_qos_attr, + struct bfa_rport_qos_attr_s new_qos_attr); +void bfa_rport_get_qos_attr(struct bfa_rport_s *rport, + struct bfa_rport_qos_attr_s *qos_attr); + +/* + * bfa fcxp API functions + */ +struct bfa_fcxp_s *bfa_fcxp_alloc(void *bfad_fcxp, struct bfa_s *bfa, + int nreq_sgles, int nrsp_sgles, + bfa_fcxp_get_sgaddr_t get_req_sga, + bfa_fcxp_get_sglen_t get_req_sglen, + bfa_fcxp_get_sgaddr_t get_rsp_sga, + bfa_fcxp_get_sglen_t get_rsp_sglen); +void bfa_fcxp_alloc_wait(struct bfa_s *bfa, struct bfa_fcxp_wqe_s *wqe, + bfa_fcxp_alloc_cbfn_t alloc_cbfn, + void *cbarg, void *bfad_fcxp, + int nreq_sgles, int nrsp_sgles, + bfa_fcxp_get_sgaddr_t get_req_sga, + bfa_fcxp_get_sglen_t get_req_sglen, + bfa_fcxp_get_sgaddr_t get_rsp_sga, + bfa_fcxp_get_sglen_t get_rsp_sglen); +void bfa_fcxp_walloc_cancel(struct bfa_s *bfa, + struct bfa_fcxp_wqe_s *wqe); +void bfa_fcxp_discard(struct bfa_fcxp_s *fcxp); + +void *bfa_fcxp_get_reqbuf(struct bfa_fcxp_s *fcxp); +void *bfa_fcxp_get_rspbuf(struct bfa_fcxp_s *fcxp); + +void bfa_fcxp_free(struct bfa_fcxp_s *fcxp); + +void bfa_fcxp_send(struct bfa_fcxp_s *fcxp, struct bfa_rport_s *rport, + u16 vf_id, u8 lp_tag, + bfa_boolean_t cts, enum fc_cos cos, + u32 reqlen, struct fchs_s *fchs, + bfa_cb_fcxp_send_t cbfn, + void *cbarg, + u32 rsp_maxlen, u8 rsp_timeout); +bfa_status_t bfa_fcxp_abort(struct bfa_fcxp_s *fcxp); +u32 bfa_fcxp_get_reqbufsz(struct bfa_fcxp_s *fcxp); +u32 bfa_fcxp_get_maxrsp(struct bfa_s *bfa); + +static inline void * +bfa_uf_get_frmbuf(struct bfa_uf_s *uf) +{ + return uf->data_ptr; +} + +static inline u16 +bfa_uf_get_frmlen(struct bfa_uf_s *uf) +{ + return uf->data_len; +} + +/* + * bfa uf API functions + */ +void bfa_uf_recv_register(struct bfa_s *bfa, bfa_cb_uf_recv_t ufrecv, + void *cbarg); +void bfa_uf_free(struct bfa_uf_s *uf); + +/** + * bfa lport service api + */ + +u32 bfa_lps_get_max_vport(struct bfa_s *bfa); +struct bfa_lps_s *bfa_lps_alloc(struct bfa_s *bfa); +void bfa_lps_delete(struct bfa_lps_s *lps); +void bfa_lps_discard(struct bfa_lps_s *lps); +void bfa_lps_flogi(struct bfa_lps_s *lps, void *uarg, u8 alpa, + u16 pdusz, wwn_t pwwn, wwn_t nwwn, + bfa_boolean_t auth_en); +void bfa_lps_fdisc(struct bfa_lps_s *lps, void *uarg, u16 pdusz, + wwn_t pwwn, wwn_t nwwn); +void bfa_lps_flogo(struct bfa_lps_s *lps); +void bfa_lps_fdisclogo(struct bfa_lps_s *lps); +u8 bfa_lps_get_tag(struct bfa_lps_s *lps); +bfa_boolean_t bfa_lps_is_npiv_en(struct bfa_lps_s *lps); +bfa_boolean_t bfa_lps_is_fport(struct bfa_lps_s *lps); +bfa_boolean_t bfa_lps_is_brcd_fabric(struct bfa_lps_s *lps); +bfa_boolean_t bfa_lps_is_authreq(struct bfa_lps_s *lps); +bfa_eproto_status_t bfa_lps_get_extstatus(struct bfa_lps_s *lps); +u32 bfa_lps_get_pid(struct bfa_lps_s *lps); +u32 bfa_lps_get_base_pid(struct bfa_s *bfa); +u8 bfa_lps_get_tag_from_pid(struct bfa_s *bfa, u32 pid); +u16 bfa_lps_get_peer_bbcredit(struct bfa_lps_s *lps); +wwn_t bfa_lps_get_peer_pwwn(struct bfa_lps_s *lps); +wwn_t bfa_lps_get_peer_nwwn(struct bfa_lps_s *lps); +u8 bfa_lps_get_lsrjt_rsn(struct bfa_lps_s *lps); +u8 bfa_lps_get_lsrjt_expl(struct bfa_lps_s *lps); +mac_t bfa_lps_get_lp_mac(struct bfa_lps_s *lps); +void bfa_cb_lps_flogi_comp(void *bfad, void *uarg, bfa_status_t status); +void bfa_cb_lps_fdisc_comp(void *bfad, void *uarg, bfa_status_t status); +void bfa_cb_lps_fdisclogo_comp(void *bfad, void *uarg); +void bfa_cb_lps_cvl_event(void *bfad, void *uarg); + +void bfa_trunk_enable_cfg(struct bfa_s *bfa); +bfa_status_t bfa_trunk_enable(struct bfa_s *bfa); +bfa_status_t bfa_trunk_disable(struct bfa_s *bfa); +bfa_status_t bfa_trunk_get_attr(struct bfa_s *bfa, + struct bfa_trunk_attr_s *attr); + +#endif /* __BFA_SVC_H__ */ diff --git a/drivers/scsi/bfa/bfa_timer.c b/drivers/scsi/bfa/bfa_timer.c deleted file mode 100644 index cb76481f5cb1..000000000000 --- a/drivers/scsi/bfa/bfa_timer.c +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#include <bfa_timer.h> -#include <cs/bfa_debug.h> - -void -bfa_timer_init(struct bfa_timer_mod_s *mod) -{ - INIT_LIST_HEAD(&mod->timer_q); -} - -void -bfa_timer_beat(struct bfa_timer_mod_s *mod) -{ - struct list_head *qh = &mod->timer_q; - struct list_head *qe, *qe_next; - struct bfa_timer_s *elem; - struct list_head timedout_q; - - INIT_LIST_HEAD(&timedout_q); - - qe = bfa_q_next(qh); - - while (qe != qh) { - qe_next = bfa_q_next(qe); - - elem = (struct bfa_timer_s *) qe; - if (elem->timeout <= BFA_TIMER_FREQ) { - elem->timeout = 0; - list_del(&elem->qe); - list_add_tail(&elem->qe, &timedout_q); - } else { - elem->timeout -= BFA_TIMER_FREQ; - } - - qe = qe_next; /* go to next elem */ - } - - /* - * Pop all the timeout entries - */ - while (!list_empty(&timedout_q)) { - bfa_q_deq(&timedout_q, &elem); - elem->timercb(elem->arg); - } -} - -/** - * Should be called with lock protection - */ -void -bfa_timer_begin(struct bfa_timer_mod_s *mod, struct bfa_timer_s *timer, - void (*timercb) (void *), void *arg, unsigned int timeout) -{ - - bfa_assert(timercb != NULL); - bfa_assert(!bfa_q_is_on_q(&mod->timer_q, timer)); - - timer->timeout = timeout; - timer->timercb = timercb; - timer->arg = arg; - - list_add_tail(&timer->qe, &mod->timer_q); -} - -/** - * Should be called with lock protection - */ -void -bfa_timer_stop(struct bfa_timer_s *timer) -{ - bfa_assert(!list_empty(&timer->qe)); - - list_del(&timer->qe); -} diff --git a/drivers/scsi/bfa/bfa_trcmod_priv.h b/drivers/scsi/bfa/bfa_trcmod_priv.h deleted file mode 100644 index a7a82610db85..000000000000 --- a/drivers/scsi/bfa/bfa_trcmod_priv.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/** - * hal_trcmod.h BFA trace modules - */ - -#ifndef __BFA_TRCMOD_PRIV_H__ -#define __BFA_TRCMOD_PRIV_H__ - -#include <cs/bfa_trc.h> - -/* - * !!! Only append to the enums defined here to avoid any versioning - * !!! needed between trace utility and driver version - */ -enum { - BFA_TRC_HAL_INTR = 1, - BFA_TRC_HAL_FCXP = 2, - BFA_TRC_HAL_UF = 3, - BFA_TRC_HAL_RPORT = 4, - BFA_TRC_HAL_FCPIM = 5, - BFA_TRC_HAL_IOIM = 6, - BFA_TRC_HAL_TSKIM = 7, - BFA_TRC_HAL_ITNIM = 8, - BFA_TRC_HAL_FCPORT = 9, - BFA_TRC_HAL_SGPG = 10, - BFA_TRC_HAL_FLASH = 11, - BFA_TRC_HAL_DEBUG = 12, - BFA_TRC_HAL_WWN = 13, - BFA_TRC_HAL_FLASH_RAW = 14, - BFA_TRC_HAL_SBOOT = 15, - BFA_TRC_HAL_SBOOT_IO = 16, - BFA_TRC_HAL_SBOOT_INTR = 17, - BFA_TRC_HAL_SBTEST = 18, - BFA_TRC_HAL_IPFC = 19, - BFA_TRC_HAL_IOCFC = 20, - BFA_TRC_HAL_FCPTM = 21, - BFA_TRC_HAL_IOTM = 22, - BFA_TRC_HAL_TSKTM = 23, - BFA_TRC_HAL_TIN = 24, - BFA_TRC_HAL_LPS = 25, - BFA_TRC_HAL_FCDIAG = 26, - BFA_TRC_HAL_PBIND = 27, - BFA_TRC_HAL_IOCFC_CT = 28, - BFA_TRC_HAL_IOCFC_CB = 29, - BFA_TRC_HAL_IOCFC_Q = 30, -}; - -#endif /* __BFA_TRCMOD_PRIV_H__ */ diff --git a/drivers/scsi/bfa/bfa_tskim.c b/drivers/scsi/bfa/bfa_tskim.c deleted file mode 100644 index ad9aaaedd3f1..000000000000 --- a/drivers/scsi/bfa/bfa_tskim.c +++ /dev/null @@ -1,690 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#include <bfa.h> -#include <bfa_cb_ioim_macros.h> - -BFA_TRC_FILE(HAL, TSKIM); - -/** - * task management completion handling - */ -#define bfa_tskim_qcomp(__tskim, __cbfn) do { \ - bfa_cb_queue((__tskim)->bfa, &(__tskim)->hcb_qe, \ - __cbfn, (__tskim)); \ - bfa_tskim_notify_comp(__tskim); \ -} while (0) - -#define bfa_tskim_notify_comp(__tskim) do { \ - if ((__tskim)->notify) \ - bfa_itnim_tskdone((__tskim)->itnim); \ -} while (0) - -/* - * forward declarations - */ -static void __bfa_cb_tskim_done(void *cbarg, bfa_boolean_t complete); -static void __bfa_cb_tskim_failed(void *cbarg, bfa_boolean_t complete); -static bfa_boolean_t bfa_tskim_match_scope(struct bfa_tskim_s *tskim, - lun_t lun); -static void bfa_tskim_gather_ios(struct bfa_tskim_s *tskim); -static void bfa_tskim_cleanp_comp(void *tskim_cbarg); -static void bfa_tskim_cleanup_ios(struct bfa_tskim_s *tskim); -static bfa_boolean_t bfa_tskim_send(struct bfa_tskim_s *tskim); -static bfa_boolean_t bfa_tskim_send_abort(struct bfa_tskim_s *tskim); -static void bfa_tskim_iocdisable_ios(struct bfa_tskim_s *tskim); - -/** - * bfa_tskim_sm - */ - -enum bfa_tskim_event { - BFA_TSKIM_SM_START = 1, /* TM command start */ - BFA_TSKIM_SM_DONE = 2, /* TM completion */ - BFA_TSKIM_SM_QRESUME = 3, /* resume after qfull */ - BFA_TSKIM_SM_HWFAIL = 5, /* IOC h/w failure event */ - BFA_TSKIM_SM_HCB = 6, /* BFA callback completion */ - BFA_TSKIM_SM_IOS_DONE = 7, /* IO and sub TM completions */ - BFA_TSKIM_SM_CLEANUP = 8, /* TM cleanup on ITN offline */ - BFA_TSKIM_SM_CLEANUP_DONE = 9, /* TM abort completion */ -}; - -static void bfa_tskim_sm_uninit(struct bfa_tskim_s *tskim, - enum bfa_tskim_event event); -static void bfa_tskim_sm_active(struct bfa_tskim_s *tskim, - enum bfa_tskim_event event); -static void bfa_tskim_sm_cleanup(struct bfa_tskim_s *tskim, - enum bfa_tskim_event event); -static void bfa_tskim_sm_iocleanup(struct bfa_tskim_s *tskim, - enum bfa_tskim_event event); -static void bfa_tskim_sm_qfull(struct bfa_tskim_s *tskim, - enum bfa_tskim_event event); -static void bfa_tskim_sm_cleanup_qfull(struct bfa_tskim_s *tskim, - enum bfa_tskim_event event); -static void bfa_tskim_sm_hcb(struct bfa_tskim_s *tskim, - enum bfa_tskim_event event); - -/** - * Task management command beginning state. - */ -static void -bfa_tskim_sm_uninit(struct bfa_tskim_s *tskim, enum bfa_tskim_event event) -{ - bfa_trc(tskim->bfa, event); - - switch (event) { - case BFA_TSKIM_SM_START: - bfa_sm_set_state(tskim, bfa_tskim_sm_active); - bfa_tskim_gather_ios(tskim); - - /** - * If device is offline, do not send TM on wire. Just cleanup - * any pending IO requests and complete TM request. - */ - if (!bfa_itnim_is_online(tskim->itnim)) { - bfa_sm_set_state(tskim, bfa_tskim_sm_iocleanup); - tskim->tsk_status = BFI_TSKIM_STS_OK; - bfa_tskim_cleanup_ios(tskim); - return; - } - - if (!bfa_tskim_send(tskim)) { - bfa_sm_set_state(tskim, bfa_tskim_sm_qfull); - bfa_reqq_wait(tskim->bfa, tskim->itnim->reqq, - &tskim->reqq_wait); - } - break; - - default: - bfa_sm_fault(tskim->bfa, event); - } -} - -/** - * brief - * TM command is active, awaiting completion from firmware to - * cleanup IO requests in TM scope. - */ -static void -bfa_tskim_sm_active(struct bfa_tskim_s *tskim, enum bfa_tskim_event event) -{ - bfa_trc(tskim->bfa, event); - - switch (event) { - case BFA_TSKIM_SM_DONE: - bfa_sm_set_state(tskim, bfa_tskim_sm_iocleanup); - bfa_tskim_cleanup_ios(tskim); - break; - - case BFA_TSKIM_SM_CLEANUP: - bfa_sm_set_state(tskim, bfa_tskim_sm_cleanup); - if (!bfa_tskim_send_abort(tskim)) { - bfa_sm_set_state(tskim, bfa_tskim_sm_cleanup_qfull); - bfa_reqq_wait(tskim->bfa, tskim->itnim->reqq, - &tskim->reqq_wait); - } - break; - - case BFA_TSKIM_SM_HWFAIL: - bfa_sm_set_state(tskim, bfa_tskim_sm_hcb); - bfa_tskim_iocdisable_ios(tskim); - bfa_tskim_qcomp(tskim, __bfa_cb_tskim_failed); - break; - - default: - bfa_sm_fault(tskim->bfa, event); - } -} - -/** - * An active TM is being cleaned up since ITN is offline. Awaiting cleanup - * completion event from firmware. - */ -static void -bfa_tskim_sm_cleanup(struct bfa_tskim_s *tskim, enum bfa_tskim_event event) -{ - bfa_trc(tskim->bfa, event); - - switch (event) { - case BFA_TSKIM_SM_DONE: - /** - * Ignore and wait for ABORT completion from firmware. - */ - break; - - case BFA_TSKIM_SM_CLEANUP_DONE: - bfa_sm_set_state(tskim, bfa_tskim_sm_iocleanup); - bfa_tskim_cleanup_ios(tskim); - break; - - case BFA_TSKIM_SM_HWFAIL: - bfa_sm_set_state(tskim, bfa_tskim_sm_hcb); - bfa_tskim_iocdisable_ios(tskim); - bfa_tskim_qcomp(tskim, __bfa_cb_tskim_failed); - break; - - default: - bfa_sm_fault(tskim->bfa, event); - } -} - -static void -bfa_tskim_sm_iocleanup(struct bfa_tskim_s *tskim, enum bfa_tskim_event event) -{ - bfa_trc(tskim->bfa, event); - - switch (event) { - case BFA_TSKIM_SM_IOS_DONE: - bfa_sm_set_state(tskim, bfa_tskim_sm_hcb); - bfa_tskim_qcomp(tskim, __bfa_cb_tskim_done); - break; - - case BFA_TSKIM_SM_CLEANUP: - /** - * Ignore, TM command completed on wire. - * Notify TM conmpletion on IO cleanup completion. - */ - break; - - case BFA_TSKIM_SM_HWFAIL: - bfa_sm_set_state(tskim, bfa_tskim_sm_hcb); - bfa_tskim_iocdisable_ios(tskim); - bfa_tskim_qcomp(tskim, __bfa_cb_tskim_failed); - break; - - default: - bfa_sm_fault(tskim->bfa, event); - } -} - -/** - * Task management command is waiting for room in request CQ - */ -static void -bfa_tskim_sm_qfull(struct bfa_tskim_s *tskim, enum bfa_tskim_event event) -{ - bfa_trc(tskim->bfa, event); - - switch (event) { - case BFA_TSKIM_SM_QRESUME: - bfa_sm_set_state(tskim, bfa_tskim_sm_active); - bfa_tskim_send(tskim); - break; - - case BFA_TSKIM_SM_CLEANUP: - /** - * No need to send TM on wire since ITN is offline. - */ - bfa_sm_set_state(tskim, bfa_tskim_sm_iocleanup); - bfa_reqq_wcancel(&tskim->reqq_wait); - bfa_tskim_cleanup_ios(tskim); - break; - - case BFA_TSKIM_SM_HWFAIL: - bfa_sm_set_state(tskim, bfa_tskim_sm_hcb); - bfa_reqq_wcancel(&tskim->reqq_wait); - bfa_tskim_iocdisable_ios(tskim); - bfa_tskim_qcomp(tskim, __bfa_cb_tskim_failed); - break; - - default: - bfa_sm_fault(tskim->bfa, event); - } -} - -/** - * Task management command is active, awaiting for room in request CQ - * to send clean up request. - */ -static void -bfa_tskim_sm_cleanup_qfull(struct bfa_tskim_s *tskim, - enum bfa_tskim_event event) -{ - bfa_trc(tskim->bfa, event); - - switch (event) { - case BFA_TSKIM_SM_DONE: - bfa_reqq_wcancel(&tskim->reqq_wait); - /** - * - * Fall through !!! - */ - - case BFA_TSKIM_SM_QRESUME: - bfa_sm_set_state(tskim, bfa_tskim_sm_cleanup); - bfa_tskim_send_abort(tskim); - break; - - case BFA_TSKIM_SM_HWFAIL: - bfa_sm_set_state(tskim, bfa_tskim_sm_hcb); - bfa_reqq_wcancel(&tskim->reqq_wait); - bfa_tskim_iocdisable_ios(tskim); - bfa_tskim_qcomp(tskim, __bfa_cb_tskim_failed); - break; - - default: - bfa_sm_fault(tskim->bfa, event); - } -} - -/** - * BFA callback is pending - */ -static void -bfa_tskim_sm_hcb(struct bfa_tskim_s *tskim, enum bfa_tskim_event event) -{ - bfa_trc(tskim->bfa, event); - - switch (event) { - case BFA_TSKIM_SM_HCB: - bfa_sm_set_state(tskim, bfa_tskim_sm_uninit); - bfa_tskim_free(tskim); - break; - - case BFA_TSKIM_SM_CLEANUP: - bfa_tskim_notify_comp(tskim); - break; - - case BFA_TSKIM_SM_HWFAIL: - break; - - default: - bfa_sm_fault(tskim->bfa, event); - } -} - - - -/** - * bfa_tskim_private - */ - -static void -__bfa_cb_tskim_done(void *cbarg, bfa_boolean_t complete) -{ - struct bfa_tskim_s *tskim = cbarg; - - if (!complete) { - bfa_sm_send_event(tskim, BFA_TSKIM_SM_HCB); - return; - } - - bfa_stats(tskim->itnim, tm_success); - bfa_cb_tskim_done(tskim->bfa->bfad, tskim->dtsk, tskim->tsk_status); -} - -static void -__bfa_cb_tskim_failed(void *cbarg, bfa_boolean_t complete) -{ - struct bfa_tskim_s *tskim = cbarg; - - if (!complete) { - bfa_sm_send_event(tskim, BFA_TSKIM_SM_HCB); - return; - } - - bfa_stats(tskim->itnim, tm_failures); - bfa_cb_tskim_done(tskim->bfa->bfad, tskim->dtsk, - BFI_TSKIM_STS_FAILED); -} - -static bfa_boolean_t -bfa_tskim_match_scope(struct bfa_tskim_s *tskim, lun_t lun) -{ - switch (tskim->tm_cmnd) { - case FCP_TM_TARGET_RESET: - return BFA_TRUE; - - case FCP_TM_ABORT_TASK_SET: - case FCP_TM_CLEAR_TASK_SET: - case FCP_TM_LUN_RESET: - case FCP_TM_CLEAR_ACA: - return (tskim->lun == lun); - - default: - bfa_assert(0); - } - - return BFA_FALSE; -} - -/** - * Gather affected IO requests and task management commands. - */ -static void -bfa_tskim_gather_ios(struct bfa_tskim_s *tskim) -{ - struct bfa_itnim_s *itnim = tskim->itnim; - struct bfa_ioim_s *ioim; - struct list_head *qe, *qen; - - INIT_LIST_HEAD(&tskim->io_q); - - /** - * Gather any active IO requests first. - */ - list_for_each_safe(qe, qen, &itnim->io_q) { - ioim = (struct bfa_ioim_s *) qe; - if (bfa_tskim_match_scope - (tskim, bfa_cb_ioim_get_lun(ioim->dio))) { - list_del(&ioim->qe); - list_add_tail(&ioim->qe, &tskim->io_q); - } - } - - /** - * Failback any pending IO requests immediately. - */ - list_for_each_safe(qe, qen, &itnim->pending_q) { - ioim = (struct bfa_ioim_s *) qe; - if (bfa_tskim_match_scope - (tskim, bfa_cb_ioim_get_lun(ioim->dio))) { - list_del(&ioim->qe); - list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q); - bfa_ioim_tov(ioim); - } - } -} - -/** - * IO cleanup completion - */ -static void -bfa_tskim_cleanp_comp(void *tskim_cbarg) -{ - struct bfa_tskim_s *tskim = tskim_cbarg; - - bfa_stats(tskim->itnim, tm_io_comps); - bfa_sm_send_event(tskim, BFA_TSKIM_SM_IOS_DONE); -} - -/** - * Gather affected IO requests and task management commands. - */ -static void -bfa_tskim_cleanup_ios(struct bfa_tskim_s *tskim) -{ - struct bfa_ioim_s *ioim; - struct list_head *qe, *qen; - - bfa_wc_init(&tskim->wc, bfa_tskim_cleanp_comp, tskim); - - list_for_each_safe(qe, qen, &tskim->io_q) { - ioim = (struct bfa_ioim_s *) qe; - bfa_wc_up(&tskim->wc); - bfa_ioim_cleanup_tm(ioim, tskim); - } - - bfa_wc_wait(&tskim->wc); -} - -/** - * Send task management request to firmware. - */ -static bfa_boolean_t -bfa_tskim_send(struct bfa_tskim_s *tskim) -{ - struct bfa_itnim_s *itnim = tskim->itnim; - struct bfi_tskim_req_s *m; - - /** - * check for room in queue to send request now - */ - m = bfa_reqq_next(tskim->bfa, itnim->reqq); - if (!m) - return BFA_FALSE; - - /** - * build i/o request message next - */ - bfi_h2i_set(m->mh, BFI_MC_TSKIM, BFI_TSKIM_H2I_TM_REQ, - bfa_lpuid(tskim->bfa)); - - m->tsk_tag = bfa_os_htons(tskim->tsk_tag); - m->itn_fhdl = tskim->itnim->rport->fw_handle; - m->t_secs = tskim->tsecs; - m->lun = tskim->lun; - m->tm_flags = tskim->tm_cmnd; - - /** - * queue I/O message to firmware - */ - bfa_reqq_produce(tskim->bfa, itnim->reqq); - return BFA_TRUE; -} - -/** - * Send abort request to cleanup an active TM to firmware. - */ -static bfa_boolean_t -bfa_tskim_send_abort(struct bfa_tskim_s *tskim) -{ - struct bfa_itnim_s *itnim = tskim->itnim; - struct bfi_tskim_abortreq_s *m; - - /** - * check for room in queue to send request now - */ - m = bfa_reqq_next(tskim->bfa, itnim->reqq); - if (!m) - return BFA_FALSE; - - /** - * build i/o request message next - */ - bfi_h2i_set(m->mh, BFI_MC_TSKIM, BFI_TSKIM_H2I_ABORT_REQ, - bfa_lpuid(tskim->bfa)); - - m->tsk_tag = bfa_os_htons(tskim->tsk_tag); - - /** - * queue I/O message to firmware - */ - bfa_reqq_produce(tskim->bfa, itnim->reqq); - return BFA_TRUE; -} - -/** - * Call to resume task management cmnd waiting for room in request queue. - */ -static void -bfa_tskim_qresume(void *cbarg) -{ - struct bfa_tskim_s *tskim = cbarg; - - bfa_fcpim_stats(tskim->fcpim, qresumes); - bfa_stats(tskim->itnim, tm_qresumes); - bfa_sm_send_event(tskim, BFA_TSKIM_SM_QRESUME); -} - -/** - * Cleanup IOs associated with a task mangement command on IOC failures. - */ -static void -bfa_tskim_iocdisable_ios(struct bfa_tskim_s *tskim) -{ - struct bfa_ioim_s *ioim; - struct list_head *qe, *qen; - - list_for_each_safe(qe, qen, &tskim->io_q) { - ioim = (struct bfa_ioim_s *) qe; - bfa_ioim_iocdisable(ioim); - } -} - - - -/** - * bfa_tskim_friend - */ - -/** - * Notification on completions from related ioim. - */ -void -bfa_tskim_iodone(struct bfa_tskim_s *tskim) -{ - bfa_wc_down(&tskim->wc); -} - -/** - * Handle IOC h/w failure notification from itnim. - */ -void -bfa_tskim_iocdisable(struct bfa_tskim_s *tskim) -{ - tskim->notify = BFA_FALSE; - bfa_stats(tskim->itnim, tm_iocdowns); - bfa_sm_send_event(tskim, BFA_TSKIM_SM_HWFAIL); -} - -/** - * Cleanup TM command and associated IOs as part of ITNIM offline. - */ -void -bfa_tskim_cleanup(struct bfa_tskim_s *tskim) -{ - tskim->notify = BFA_TRUE; - bfa_stats(tskim->itnim, tm_cleanups); - bfa_sm_send_event(tskim, BFA_TSKIM_SM_CLEANUP); -} - -/** - * Memory allocation and initialization. - */ -void -bfa_tskim_attach(struct bfa_fcpim_mod_s *fcpim, struct bfa_meminfo_s *minfo) -{ - struct bfa_tskim_s *tskim; - u16 i; - - INIT_LIST_HEAD(&fcpim->tskim_free_q); - - tskim = (struct bfa_tskim_s *) bfa_meminfo_kva(minfo); - fcpim->tskim_arr = tskim; - - for (i = 0; i < fcpim->num_tskim_reqs; i++, tskim++) { - /* - * initialize TSKIM - */ - bfa_os_memset(tskim, 0, sizeof(struct bfa_tskim_s)); - tskim->tsk_tag = i; - tskim->bfa = fcpim->bfa; - tskim->fcpim = fcpim; - tskim->notify = BFA_FALSE; - bfa_reqq_winit(&tskim->reqq_wait, bfa_tskim_qresume, - tskim); - bfa_sm_set_state(tskim, bfa_tskim_sm_uninit); - - list_add_tail(&tskim->qe, &fcpim->tskim_free_q); - } - - bfa_meminfo_kva(minfo) = (u8 *) tskim; -} - -void -bfa_tskim_detach(struct bfa_fcpim_mod_s *fcpim) -{ - /** - * @todo - */ -} - -void -bfa_tskim_isr(struct bfa_s *bfa, struct bfi_msg_s *m) -{ - struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); - struct bfi_tskim_rsp_s *rsp = (struct bfi_tskim_rsp_s *) m; - struct bfa_tskim_s *tskim; - u16 tsk_tag = bfa_os_ntohs(rsp->tsk_tag); - - tskim = BFA_TSKIM_FROM_TAG(fcpim, tsk_tag); - bfa_assert(tskim->tsk_tag == tsk_tag); - - tskim->tsk_status = rsp->tsk_status; - - /** - * Firmware sends BFI_TSKIM_STS_ABORTED status for abort - * requests. All other statuses are for normal completions. - */ - if (rsp->tsk_status == BFI_TSKIM_STS_ABORTED) { - bfa_stats(tskim->itnim, tm_cleanup_comps); - bfa_sm_send_event(tskim, BFA_TSKIM_SM_CLEANUP_DONE); - } else { - bfa_stats(tskim->itnim, tm_fw_rsps); - bfa_sm_send_event(tskim, BFA_TSKIM_SM_DONE); - } -} - - - -/** - * bfa_tskim_api - */ - - -struct bfa_tskim_s * -bfa_tskim_alloc(struct bfa_s *bfa, struct bfad_tskim_s *dtsk) -{ - struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); - struct bfa_tskim_s *tskim; - - bfa_q_deq(&fcpim->tskim_free_q, &tskim); - - if (!tskim) - bfa_fcpim_stats(fcpim, no_tskims); - else - tskim->dtsk = dtsk; - - return tskim; -} - -void -bfa_tskim_free(struct bfa_tskim_s *tskim) -{ - bfa_assert(bfa_q_is_on_q_func(&tskim->itnim->tsk_q, &tskim->qe)); - list_del(&tskim->qe); - list_add_tail(&tskim->qe, &tskim->fcpim->tskim_free_q); -} - -/** - * Start a task management command. - * - * @param[in] tskim BFA task management command instance - * @param[in] itnim i-t nexus for the task management command - * @param[in] lun lun, if applicable - * @param[in] tm_cmnd Task management command code. - * @param[in] t_secs Timeout in seconds - * - * @return None. - */ -void -bfa_tskim_start(struct bfa_tskim_s *tskim, struct bfa_itnim_s *itnim, lun_t lun, - enum fcp_tm_cmnd tm_cmnd, u8 tsecs) -{ - tskim->itnim = itnim; - tskim->lun = lun; - tskim->tm_cmnd = tm_cmnd; - tskim->tsecs = tsecs; - tskim->notify = BFA_FALSE; - bfa_stats(itnim, tm_cmnds); - - list_add_tail(&tskim->qe, &itnim->tsk_q); - bfa_sm_send_event(tskim, BFA_TSKIM_SM_START); -} - - diff --git a/drivers/scsi/bfa/bfa_uf.c b/drivers/scsi/bfa/bfa_uf.c deleted file mode 100644 index b9a9a686ef6a..000000000000 --- a/drivers/scsi/bfa/bfa_uf.c +++ /dev/null @@ -1,343 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/** - * bfa_uf.c BFA unsolicited frame receive implementation - */ - -#include <bfa.h> -#include <bfa_svc.h> -#include <bfi/bfi_uf.h> -#include <cs/bfa_debug.h> - -BFA_TRC_FILE(HAL, UF); -BFA_MODULE(uf); - -/* - ***************************************************************************** - * Internal functions - ***************************************************************************** - */ -static void -__bfa_cb_uf_recv(void *cbarg, bfa_boolean_t complete) -{ - struct bfa_uf_s *uf = cbarg; - struct bfa_uf_mod_s *ufm = BFA_UF_MOD(uf->bfa); - - if (complete) - ufm->ufrecv(ufm->cbarg, uf); -} - -static void -claim_uf_pbs(struct bfa_uf_mod_s *ufm, struct bfa_meminfo_s *mi) -{ - u32 uf_pb_tot_sz; - - ufm->uf_pbs_kva = (struct bfa_uf_buf_s *) bfa_meminfo_dma_virt(mi); - ufm->uf_pbs_pa = bfa_meminfo_dma_phys(mi); - uf_pb_tot_sz = BFA_ROUNDUP((sizeof(struct bfa_uf_buf_s) * ufm->num_ufs), - BFA_DMA_ALIGN_SZ); - - bfa_meminfo_dma_virt(mi) += uf_pb_tot_sz; - bfa_meminfo_dma_phys(mi) += uf_pb_tot_sz; - - bfa_os_memset((void *)ufm->uf_pbs_kva, 0, uf_pb_tot_sz); -} - -static void -claim_uf_post_msgs(struct bfa_uf_mod_s *ufm, struct bfa_meminfo_s *mi) -{ - struct bfi_uf_buf_post_s *uf_bp_msg; - struct bfi_sge_s *sge; - union bfi_addr_u sga_zero = { {0} }; - u16 i; - u16 buf_len; - - ufm->uf_buf_posts = (struct bfi_uf_buf_post_s *) bfa_meminfo_kva(mi); - uf_bp_msg = ufm->uf_buf_posts; - - for (i = 0, uf_bp_msg = ufm->uf_buf_posts; i < ufm->num_ufs; - i++, uf_bp_msg++) { - bfa_os_memset(uf_bp_msg, 0, sizeof(struct bfi_uf_buf_post_s)); - - uf_bp_msg->buf_tag = i; - buf_len = sizeof(struct bfa_uf_buf_s); - uf_bp_msg->buf_len = bfa_os_htons(buf_len); - bfi_h2i_set(uf_bp_msg->mh, BFI_MC_UF, BFI_UF_H2I_BUF_POST, - bfa_lpuid(ufm->bfa)); - - sge = uf_bp_msg->sge; - sge[0].sg_len = buf_len; - sge[0].flags = BFI_SGE_DATA_LAST; - bfa_dma_addr_set(sge[0].sga, ufm_pbs_pa(ufm, i)); - bfa_sge_to_be(sge); - - sge[1].sg_len = buf_len; - sge[1].flags = BFI_SGE_PGDLEN; - sge[1].sga = sga_zero; - bfa_sge_to_be(&sge[1]); - } - - /** - * advance pointer beyond consumed memory - */ - bfa_meminfo_kva(mi) = (u8 *) uf_bp_msg; -} - -static void -claim_ufs(struct bfa_uf_mod_s *ufm, struct bfa_meminfo_s *mi) -{ - u16 i; - struct bfa_uf_s *uf; - - /* - * Claim block of memory for UF list - */ - ufm->uf_list = (struct bfa_uf_s *) bfa_meminfo_kva(mi); - - /* - * Initialize UFs and queue it in UF free queue - */ - for (i = 0, uf = ufm->uf_list; i < ufm->num_ufs; i++, uf++) { - bfa_os_memset(uf, 0, sizeof(struct bfa_uf_s)); - uf->bfa = ufm->bfa; - uf->uf_tag = i; - uf->pb_len = sizeof(struct bfa_uf_buf_s); - uf->buf_kva = (void *)&ufm->uf_pbs_kva[i]; - uf->buf_pa = ufm_pbs_pa(ufm, i); - list_add_tail(&uf->qe, &ufm->uf_free_q); - } - - /** - * advance memory pointer - */ - bfa_meminfo_kva(mi) = (u8 *) uf; -} - -static void -uf_mem_claim(struct bfa_uf_mod_s *ufm, struct bfa_meminfo_s *mi) -{ - claim_uf_pbs(ufm, mi); - claim_ufs(ufm, mi); - claim_uf_post_msgs(ufm, mi); -} - -static void -bfa_uf_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len, u32 *dm_len) -{ - u32 num_ufs = cfg->fwcfg.num_uf_bufs; - - /* - * dma-able memory for UF posted bufs - */ - *dm_len += BFA_ROUNDUP((sizeof(struct bfa_uf_buf_s) * num_ufs), - BFA_DMA_ALIGN_SZ); - - /* - * kernel Virtual memory for UFs and UF buf post msg copies - */ - *ndm_len += sizeof(struct bfa_uf_s) * num_ufs; - *ndm_len += sizeof(struct bfi_uf_buf_post_s) * num_ufs; -} - -static void -bfa_uf_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, - struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev) -{ - struct bfa_uf_mod_s *ufm = BFA_UF_MOD(bfa); - - bfa_os_memset(ufm, 0, sizeof(struct bfa_uf_mod_s)); - ufm->bfa = bfa; - ufm->num_ufs = cfg->fwcfg.num_uf_bufs; - INIT_LIST_HEAD(&ufm->uf_free_q); - INIT_LIST_HEAD(&ufm->uf_posted_q); - - uf_mem_claim(ufm, meminfo); -} - -static void -bfa_uf_detach(struct bfa_s *bfa) -{ -} - -static struct bfa_uf_s * -bfa_uf_get(struct bfa_uf_mod_s *uf_mod) -{ - struct bfa_uf_s *uf; - - bfa_q_deq(&uf_mod->uf_free_q, &uf); - return uf; -} - -static void -bfa_uf_put(struct bfa_uf_mod_s *uf_mod, struct bfa_uf_s *uf) -{ - list_add_tail(&uf->qe, &uf_mod->uf_free_q); -} - -static bfa_status_t -bfa_uf_post(struct bfa_uf_mod_s *ufm, struct bfa_uf_s *uf) -{ - struct bfi_uf_buf_post_s *uf_post_msg; - - uf_post_msg = bfa_reqq_next(ufm->bfa, BFA_REQQ_FCXP); - if (!uf_post_msg) - return BFA_STATUS_FAILED; - - bfa_os_memcpy(uf_post_msg, &ufm->uf_buf_posts[uf->uf_tag], - sizeof(struct bfi_uf_buf_post_s)); - bfa_reqq_produce(ufm->bfa, BFA_REQQ_FCXP); - - bfa_trc(ufm->bfa, uf->uf_tag); - - list_add_tail(&uf->qe, &ufm->uf_posted_q); - return BFA_STATUS_OK; -} - -static void -bfa_uf_post_all(struct bfa_uf_mod_s *uf_mod) -{ - struct bfa_uf_s *uf; - - while ((uf = bfa_uf_get(uf_mod)) != NULL) { - if (bfa_uf_post(uf_mod, uf) != BFA_STATUS_OK) - break; - } -} - -static void -uf_recv(struct bfa_s *bfa, struct bfi_uf_frm_rcvd_s *m) -{ - struct bfa_uf_mod_s *ufm = BFA_UF_MOD(bfa); - u16 uf_tag = m->buf_tag; - struct bfa_uf_buf_s *uf_buf = &ufm->uf_pbs_kva[uf_tag]; - struct bfa_uf_s *uf = &ufm->uf_list[uf_tag]; - u8 *buf = &uf_buf->d[0]; - struct fchs_s *fchs; - - m->frm_len = bfa_os_ntohs(m->frm_len); - m->xfr_len = bfa_os_ntohs(m->xfr_len); - - fchs = (struct fchs_s *) uf_buf; - - list_del(&uf->qe); /* dequeue from posted queue */ - - uf->data_ptr = buf; - uf->data_len = m->xfr_len; - - bfa_assert(uf->data_len >= sizeof(struct fchs_s)); - - if (uf->data_len == sizeof(struct fchs_s)) { - bfa_plog_fchdr(bfa->plog, BFA_PL_MID_HAL_UF, BFA_PL_EID_RX, - uf->data_len, (struct fchs_s *) buf); - } else { - u32 pld_w0 = *((u32 *) (buf + sizeof(struct fchs_s))); - bfa_plog_fchdr_and_pl(bfa->plog, BFA_PL_MID_HAL_UF, - BFA_PL_EID_RX, uf->data_len, - (struct fchs_s *) buf, pld_w0); - } - - 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 -bfa_uf_stop(struct bfa_s *bfa) -{ -} - -static void -bfa_uf_iocdisable(struct bfa_s *bfa) -{ - struct bfa_uf_mod_s *ufm = BFA_UF_MOD(bfa); - struct bfa_uf_s *uf; - struct list_head *qe, *qen; - - list_for_each_safe(qe, qen, &ufm->uf_posted_q) { - uf = (struct bfa_uf_s *) qe; - list_del(&uf->qe); - bfa_uf_put(ufm, uf); - } -} - -static void -bfa_uf_start(struct bfa_s *bfa) -{ - bfa_uf_post_all(BFA_UF_MOD(bfa)); -} - - - -/** - * bfa_uf_api - */ - -/** - * Register handler for all unsolicted recieve frames. - * - * @param[in] bfa BFA instance - * @param[in] ufrecv receive handler function - * @param[in] cbarg receive handler arg - */ -void -bfa_uf_recv_register(struct bfa_s *bfa, bfa_cb_uf_recv_t ufrecv, void *cbarg) -{ - struct bfa_uf_mod_s *ufm = BFA_UF_MOD(bfa); - - ufm->ufrecv = ufrecv; - ufm->cbarg = cbarg; -} - -/** - * Free an unsolicited frame back to BFA. - * - * @param[in] uf unsolicited frame to be freed - * - * @return None - */ -void -bfa_uf_free(struct bfa_uf_s *uf) -{ - bfa_uf_put(BFA_UF_MOD(uf->bfa), uf); - bfa_uf_post_all(BFA_UF_MOD(uf->bfa)); -} - - - -/** - * uf_pub BFA uf module public functions - */ - -void -bfa_uf_isr(struct bfa_s *bfa, struct bfi_msg_s *msg) -{ - bfa_trc(bfa, msg->mhdr.msg_id); - - switch (msg->mhdr.msg_id) { - case BFI_UF_I2H_FRM_RCVD: - uf_recv(bfa, (struct bfi_uf_frm_rcvd_s *) msg); - break; - - default: - bfa_trc(bfa, msg->mhdr.msg_id); - bfa_assert(0); - } -} - - diff --git a/drivers/scsi/bfa/bfa_uf_priv.h b/drivers/scsi/bfa/bfa_uf_priv.h deleted file mode 100644 index bcb490f834f3..000000000000 --- a/drivers/scsi/bfa/bfa_uf_priv.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ -#ifndef __BFA_UF_PRIV_H__ -#define __BFA_UF_PRIV_H__ - -#include <cs/bfa_sm.h> -#include <bfa_svc.h> -#include <bfi/bfi_uf.h> - -#define BFA_UF_MIN (4) - -struct bfa_uf_mod_s { - struct bfa_s *bfa; /* back pointer to BFA */ - struct bfa_uf_s *uf_list; /* array of UFs */ - u16 num_ufs; /* num unsolicited rx frames */ - struct list_head uf_free_q; /* free UFs */ - struct list_head uf_posted_q; /* UFs posted to IOC */ - struct bfa_uf_buf_s *uf_pbs_kva; /* list UF bufs request pld */ - u64 uf_pbs_pa; /* phy addr for UF bufs */ - struct bfi_uf_buf_post_s *uf_buf_posts; - /* pre-built UF post msgs */ - bfa_cb_uf_recv_t ufrecv; /* uf recv handler function */ - void *cbarg; /* uf receive handler arg */ -}; - -#define BFA_UF_MOD(__bfa) (&(__bfa)->modules.uf_mod) - -#define ufm_pbs_pa(_ufmod, _uftag) \ - ((_ufmod)->uf_pbs_pa + sizeof(struct bfa_uf_buf_s) * (_uftag)) - -void bfa_uf_isr(struct bfa_s *bfa, struct bfi_msg_s *msg); - -#endif /* __BFA_UF_PRIV_H__ */ diff --git a/drivers/scsi/bfa/bfad.c b/drivers/scsi/bfa/bfad.c index ca04cc9d332f..4d8784e06e14 100644 --- a/drivers/scsi/bfa/bfad.c +++ b/drivers/scsi/bfa/bfad.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. * All rights reserved * www.brocade.com * @@ -18,46 +18,62 @@ /** * bfad.c Linux driver PCI interface module. */ - -#include <linux/slab.h> #include <linux/module.h> #include <linux/kthread.h> +#include <linux/errno.h> +#include <linux/sched.h> +#include <linux/init.h> +#include <linux/fs.h> +#include <linux/pci.h> +#include <linux/firmware.h> +#include <asm/uaccess.h> +#include <asm/fcntl.h> + #include "bfad_drv.h" #include "bfad_im.h" -#include "bfad_tm.h" -#include "bfad_ipfc.h" -#include "bfad_trcmod.h" -#include <fcb/bfa_fcb_vf.h> -#include <fcb/bfa_fcb_rport.h> -#include <fcb/bfa_fcb_port.h> -#include <fcb/bfa_fcb.h> +#include "bfa_fcs.h" +#include "bfa_os_inc.h" +#include "bfa_defs.h" +#include "bfa.h" BFA_TRC_FILE(LDRV, BFAD); DEFINE_MUTEX(bfad_mutex); LIST_HEAD(bfad_list); -static int bfad_inst; -int bfad_supported_fc4s; - -static char *host_name; -static char *os_name; -static char *os_patch; -static int num_rports; -static int num_ios; -static int num_tms; -static int num_fcxps; -static int num_ufbufs; -static int reqq_size; -static int rspq_size; -static int num_sgpgs; -static int rport_del_timeout = BFA_FCS_RPORT_DEF_DEL_TIMEOUT; -static int bfa_io_max_sge = BFAD_IO_MAX_SGE; -static int log_level = BFA_LOG_WARNING; -static int ioc_auto_recover = BFA_TRUE; -static int ipfc_enable = BFA_FALSE; -static int fdmi_enable = BFA_TRUE; -int bfa_lun_queue_depth = BFAD_LUN_QUEUE_DEPTH; -int bfa_linkup_delay = -1; + +static int bfad_inst; +static int num_sgpgs_parm; +int supported_fc4s; +char *host_name, *os_name, *os_patch; +int num_rports, num_ios, num_tms; +int num_fcxps, num_ufbufs; +int reqq_size, rspq_size, num_sgpgs; +int rport_del_timeout = BFA_FCS_RPORT_DEF_DEL_TIMEOUT; +int bfa_lun_queue_depth = BFAD_LUN_QUEUE_DEPTH; +int bfa_io_max_sge = BFAD_IO_MAX_SGE; +int log_level = 3; /* WARNING log level */ +int ioc_auto_recover = BFA_TRUE; +int bfa_linkup_delay = -1; +int fdmi_enable = BFA_TRUE; +int pcie_max_read_reqsz; int bfa_debugfs_enable = 1; +int msix_disable_cb = 0, msix_disable_ct = 0; + +u32 bfi_image_ct_fc_size, bfi_image_ct_cna_size, bfi_image_cb_fc_size; +u32 *bfi_image_ct_fc, *bfi_image_ct_cna, *bfi_image_cb_fc; + +const char *msix_name_ct[] = { + "cpe0", "cpe1", "cpe2", "cpe3", + "rme0", "rme1", "rme2", "rme3", + "ctrl" }; + +const char *msix_name_cb[] = { + "cpe0", "cpe1", "cpe2", "cpe3", + "rme0", "rme1", "rme2", "rme3", + "eemc", "elpu0", "elpu1", "epss", "mlpu" }; + +MODULE_FIRMWARE(BFAD_FW_FILE_CT_FC); +MODULE_FIRMWARE(BFAD_FW_FILE_CT_CNA); +MODULE_FIRMWARE(BFAD_FW_FILE_CB_FC); module_param(os_name, charp, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(os_name, "OS name of the hba host machine"); @@ -66,8 +82,8 @@ 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_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); @@ -75,120 +91,277 @@ 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_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_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_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_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_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_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_PARM_DESC(ipfc_enable, "Enable IPoFC, default=0, Range[off:0|on:1]"); +MODULE_PARM_DESC(ioc_auto_recover, "IOC auto recovery, default=1, " + "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_PARM_DESC(bfa_linkup_delay, "Link up delay, default=30 secs for " + "boot port. Otherwise 10 secs in RHEL4 & 0 for " + "[RHEL5, SLES10, ESX40] Range[>0]"); +module_param(msix_disable_cb, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(msix_disable_cb, "Disable Message Signaled Interrupts " + "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 Message Signaled Interrupts " + "if possible for Brocade-1010/1020/804/1007/902/1741 " + "cards, default=0, Range[false:0|true:1]"); 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_PARM_DESC(fdmi_enable, "Enables fdmi registration, default=1, " + "Range[false:0|true:1]"); +module_param(pcie_max_read_reqsz, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(pcie_max_read_reqsz, "PCIe max read request size, default=0 " + "(use system setting), Range[128|256|512|1024|2048|4096]"); 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; - * used to reset for bfad next instance. +static void +bfad_sm_uninit(struct bfad_s *bfad, enum bfad_sm_event event); +static void +bfad_sm_created(struct bfad_s *bfad, enum bfad_sm_event event); +static void +bfad_sm_initializing(struct bfad_s *bfad, enum bfad_sm_event event); +static void +bfad_sm_operational(struct bfad_s *bfad, enum bfad_sm_event event); +static void +bfad_sm_stopping(struct bfad_s *bfad, enum bfad_sm_event event); +static void +bfad_sm_failed(struct bfad_s *bfad, enum bfad_sm_event event); +static void +bfad_sm_fcs_exit(struct bfad_s *bfad, enum bfad_sm_event event); + +/** + * Beginning state for the driver instance, awaiting the pci_probe event */ -static int num_sgpgs_parm; +static void +bfad_sm_uninit(struct bfad_s *bfad, enum bfad_sm_event event) +{ + bfa_trc(bfad, event); + + switch (event) { + case BFAD_E_CREATE: + bfa_sm_set_state(bfad, bfad_sm_created); + bfad->bfad_tsk = kthread_create(bfad_worker, (void *) bfad, + "%s", "bfad_worker"); + if (IS_ERR(bfad->bfad_tsk)) { + printk(KERN_INFO "bfad[%d]: Kernel thread " + "creation failed!\n", bfad->inst_no); + bfa_sm_send_event(bfad, BFAD_E_KTHREAD_CREATE_FAILED); + } + bfa_sm_send_event(bfad, BFAD_E_INIT); + break; + + case BFAD_E_STOP: + /* Ignore stop; already in uninit */ + break; + + default: + bfa_sm_fault(bfad, event); + } +} -static bfa_status_t -bfad_fc4_probe(struct bfad_s *bfad) +/** + * Driver Instance is created, awaiting event INIT to initialize the bfad + */ +static void +bfad_sm_created(struct bfad_s *bfad, enum bfad_sm_event event) { - int rc; + unsigned long flags; - rc = bfad_im_probe(bfad); - if (rc != BFA_STATUS_OK) - goto ext; + bfa_trc(bfad, event); - bfad_tm_probe(bfad); + switch (event) { + case BFAD_E_INIT: + bfa_sm_set_state(bfad, bfad_sm_initializing); - if (ipfc_enable) - bfad_ipfc_probe(bfad); + init_completion(&bfad->comp); - bfad->bfad_flags |= BFAD_FC4_PROBE_DONE; -ext: - return rc; + /* Enable Interrupt and wait bfa_init completion */ + if (bfad_setup_intr(bfad)) { + printk(KERN_WARNING "bfad%d: bfad_setup_intr failed\n", + bfad->inst_no); + bfa_sm_send_event(bfad, BFAD_E_INTR_INIT_FAILED); + break; + } + + spin_lock_irqsave(&bfad->bfad_lock, flags); + bfa_init(&bfad->bfa); + spin_unlock_irqrestore(&bfad->bfad_lock, flags); + + /* Set up interrupt handler for each vectors */ + if ((bfad->bfad_flags & BFAD_MSIX_ON) && + bfad_install_msix_handler(bfad)) { + printk(KERN_WARNING "%s: install_msix failed, bfad%d\n", + __func__, bfad->inst_no); + } + + bfad_init_timer(bfad); + + wait_for_completion(&bfad->comp); + + if ((bfad->bfad_flags & BFAD_HAL_INIT_DONE)) { + bfa_sm_send_event(bfad, BFAD_E_INIT_SUCCESS); + } else { + bfad->bfad_flags |= BFAD_HAL_INIT_FAIL; + bfa_sm_send_event(bfad, BFAD_E_INIT_FAILED); + } + + break; + + case BFAD_E_KTHREAD_CREATE_FAILED: + bfa_sm_set_state(bfad, bfad_sm_uninit); + break; + + default: + bfa_sm_fault(bfad, event); + } } static void -bfad_fc4_probe_undo(struct bfad_s *bfad) +bfad_sm_initializing(struct bfad_s *bfad, enum bfad_sm_event event) { - bfad_im_probe_undo(bfad); - bfad_tm_probe_undo(bfad); - if (ipfc_enable) - bfad_ipfc_probe_undo(bfad); - bfad->bfad_flags &= ~BFAD_FC4_PROBE_DONE; + int retval; + unsigned long flags; + + bfa_trc(bfad, event); + + switch (event) { + case BFAD_E_INIT_SUCCESS: + kthread_stop(bfad->bfad_tsk); + spin_lock_irqsave(&bfad->bfad_lock, flags); + bfad->bfad_tsk = NULL; + spin_unlock_irqrestore(&bfad->bfad_lock, flags); + + retval = bfad_start_ops(bfad); + if (retval != BFA_STATUS_OK) + break; + bfa_sm_set_state(bfad, bfad_sm_operational); + break; + + case BFAD_E_INTR_INIT_FAILED: + bfa_sm_set_state(bfad, bfad_sm_uninit); + kthread_stop(bfad->bfad_tsk); + spin_lock_irqsave(&bfad->bfad_lock, flags); + bfad->bfad_tsk = NULL; + spin_unlock_irqrestore(&bfad->bfad_lock, flags); + break; + + case BFAD_E_INIT_FAILED: + bfa_sm_set_state(bfad, bfad_sm_failed); + break; + default: + bfa_sm_fault(bfad, event); + } } static void -bfad_fc4_probe_post(struct bfad_s *bfad) +bfad_sm_failed(struct bfad_s *bfad, enum bfad_sm_event event) { - if (bfad->im) - bfad_im_probe_post(bfad->im); + int retval; - bfad_tm_probe_post(bfad); - if (ipfc_enable) - bfad_ipfc_probe_post(bfad); + bfa_trc(bfad, event); + + switch (event) { + case BFAD_E_INIT_SUCCESS: + retval = bfad_start_ops(bfad); + if (retval != BFA_STATUS_OK) + break; + bfa_sm_set_state(bfad, bfad_sm_operational); + break; + + case BFAD_E_STOP: + if (bfad->bfad_flags & BFAD_CFG_PPORT_DONE) + bfad_uncfg_pport(bfad); + if (bfad->bfad_flags & BFAD_FC4_PROBE_DONE) { + bfad_im_probe_undo(bfad); + bfad->bfad_flags &= ~BFAD_FC4_PROBE_DONE; + } + bfad_stop(bfad); + break; + + case BFAD_E_EXIT_COMP: + bfa_sm_set_state(bfad, bfad_sm_uninit); + bfad_remove_intr(bfad); + del_timer_sync(&bfad->hal_tmo); + break; + + default: + bfa_sm_fault(bfad, event); + } } -static bfa_status_t -bfad_fc4_port_new(struct bfad_s *bfad, struct bfad_port_s *port, int roles) +static void +bfad_sm_operational(struct bfad_s *bfad, enum bfad_sm_event event) { - int rc = BFA_STATUS_FAILED; + bfa_trc(bfad, event); - if (roles & BFA_PORT_ROLE_FCP_IM) - rc = bfad_im_port_new(bfad, port); - if (rc != BFA_STATUS_OK) - goto ext; + switch (event) { + case BFAD_E_STOP: + bfa_sm_set_state(bfad, bfad_sm_fcs_exit); + bfad_fcs_stop(bfad); + break; - if (roles & BFA_PORT_ROLE_FCP_TM) - rc = bfad_tm_port_new(bfad, port); - if (rc != BFA_STATUS_OK) - goto ext; + default: + bfa_sm_fault(bfad, event); + } +} - if ((roles & BFA_PORT_ROLE_FCP_IPFC) && ipfc_enable) - rc = bfad_ipfc_port_new(bfad, port, port->pvb_type); -ext: - return rc; +static void +bfad_sm_fcs_exit(struct bfad_s *bfad, enum bfad_sm_event event) +{ + bfa_trc(bfad, event); + + switch (event) { + case BFAD_E_FCS_EXIT_COMP: + bfa_sm_set_state(bfad, bfad_sm_stopping); + bfad_stop(bfad); + break; + + default: + bfa_sm_fault(bfad, event); + } } static void -bfad_fc4_port_delete(struct bfad_s *bfad, struct bfad_port_s *port, int roles) +bfad_sm_stopping(struct bfad_s *bfad, enum bfad_sm_event event) { - if (roles & BFA_PORT_ROLE_FCP_IM) - bfad_im_port_delete(bfad, port); + bfa_trc(bfad, event); - if (roles & BFA_PORT_ROLE_FCP_TM) - bfad_tm_port_delete(bfad, port); + switch (event) { + case BFAD_E_EXIT_COMP: + bfa_sm_set_state(bfad, bfad_sm_uninit); + bfad_remove_intr(bfad); + del_timer_sync(&bfad->hal_tmo); + bfad_im_probe_undo(bfad); + bfad->bfad_flags &= ~BFAD_FC4_PROBE_DONE; + bfad_uncfg_pport(bfad); + break; - if ((roles & BFA_PORT_ROLE_FCP_IPFC) && ipfc_enable) - bfad_ipfc_port_delete(bfad, port); + default: + bfa_sm_fault(bfad, event); + break; + } } /** @@ -209,12 +382,13 @@ bfad_hcb_comp(void *arg, bfa_status_t status) void bfa_cb_init(void *drv, bfa_status_t init_status) { - struct bfad_s *bfad = drv; + struct bfad_s *bfad = drv; if (init_status == BFA_STATUS_OK) { bfad->bfad_flags |= BFAD_HAL_INIT_DONE; - /* If BFAD_HAL_INIT_FAIL flag is set: + /* + * If BFAD_HAL_INIT_FAIL flag is set: * Wake up the kernel thread to start * the bfad operations after HAL init done */ @@ -227,26 +401,16 @@ bfa_cb_init(void *drv, bfa_status_t init_status) complete(&bfad->comp); } - - /** * BFA_FCS callbacks */ -static struct bfad_port_s * -bfad_get_drv_port(struct bfad_s *bfad, struct bfad_vf_s *vf_drv, - struct bfad_vport_s *vp_drv) -{ - return (vp_drv) ? (&(vp_drv)->drv_port) - : ((vf_drv) ? (&(vf_drv)->base_port) : (&(bfad)->pport)); -} - struct bfad_port_s * -bfa_fcb_port_new(struct bfad_s *bfad, struct bfa_fcs_port_s *port, - enum bfa_port_role roles, struct bfad_vf_s *vf_drv, +bfa_fcb_lport_new(struct bfad_s *bfad, struct bfa_fcs_lport_s *port, + enum bfa_lport_role roles, struct bfad_vf_s *vf_drv, struct bfad_vport_s *vp_drv) { - bfa_status_t rc; - struct bfad_port_s *port_drv; + bfa_status_t rc; + struct bfad_port_s *port_drv; if (!vp_drv && !vf_drv) { port_drv = &bfad->pport; @@ -264,71 +428,32 @@ bfa_fcb_port_new(struct bfad_s *bfad, struct bfa_fcs_port_s *port, port_drv->fcs_port = port; port_drv->roles = roles; - rc = bfad_fc4_port_new(bfad, port_drv, roles); - if (rc != BFA_STATUS_OK) { - bfad_fc4_port_delete(bfad, port_drv, roles); - port_drv = NULL; + + if (roles & BFA_LPORT_ROLE_FCP_IM) { + rc = bfad_im_port_new(bfad, port_drv); + if (rc != BFA_STATUS_OK) { + bfad_im_port_delete(bfad, port_drv); + port_drv = NULL; + } } return port_drv; } void -bfa_fcb_port_delete(struct bfad_s *bfad, enum bfa_port_role roles, +bfa_fcb_lport_delete(struct bfad_s *bfad, enum bfa_lport_role roles, struct bfad_vf_s *vf_drv, struct bfad_vport_s *vp_drv) { - struct bfad_port_s *port_drv; + struct bfad_port_s *port_drv; - /* - * this will be only called from rmmod context - */ + /* this will be only called from rmmod context */ if (vp_drv && !vp_drv->comp_del) { - port_drv = bfad_get_drv_port(bfad, vf_drv, vp_drv); + port_drv = (vp_drv) ? (&(vp_drv)->drv_port) : + ((vf_drv) ? (&(vf_drv)->base_port) : + (&(bfad)->pport)); bfa_trc(bfad, roles); - bfad_fc4_port_delete(bfad, port_drv, roles); - } -} - -void -bfa_fcb_port_online(struct bfad_s *bfad, enum bfa_port_role roles, - struct bfad_vf_s *vf_drv, struct bfad_vport_s *vp_drv) -{ - struct bfad_port_s *port_drv = bfad_get_drv_port(bfad, vf_drv, vp_drv); - - if (roles & BFA_PORT_ROLE_FCP_IM) - bfad_im_port_online(bfad, port_drv); - - if (roles & BFA_PORT_ROLE_FCP_TM) - bfad_tm_port_online(bfad, port_drv); - - if ((roles & BFA_PORT_ROLE_FCP_IPFC) && ipfc_enable) - bfad_ipfc_port_online(bfad, port_drv); - - bfad->bfad_flags |= BFAD_PORT_ONLINE; -} - -void -bfa_fcb_port_offline(struct bfad_s *bfad, enum bfa_port_role roles, - struct bfad_vf_s *vf_drv, struct bfad_vport_s *vp_drv) -{ - struct bfad_port_s *port_drv = bfad_get_drv_port(bfad, vf_drv, vp_drv); - - if (roles & BFA_PORT_ROLE_FCP_IM) - bfad_im_port_offline(bfad, port_drv); - - if (roles & BFA_PORT_ROLE_FCP_TM) - bfad_tm_port_offline(bfad, port_drv); - - if ((roles & BFA_PORT_ROLE_FCP_IPFC) && ipfc_enable) - bfad_ipfc_port_offline(bfad, port_drv); -} - -void -bfa_fcb_vport_delete(struct bfad_vport_s *vport_drv) -{ - if (vport_drv->comp_del) { - complete(vport_drv->comp_del); - return; + if (roles & BFA_LPORT_ROLE_FCP_IM) + bfad_im_port_delete(bfad, port_drv); } } @@ -339,7 +464,7 @@ bfa_status_t bfa_fcb_rport_alloc(struct bfad_s *bfad, struct bfa_fcs_rport_s **rport, struct bfad_rport_s **rport_drv) { - bfa_status_t rc = BFA_STATUS_OK; + bfa_status_t rc = BFA_STATUS_OK; *rport_drv = kzalloc(sizeof(struct bfad_rport_s), GFP_ATOMIC); if (*rport_drv == NULL) { @@ -354,35 +479,43 @@ ext: } /** - * @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; + struct bfa_lport_cfg_s port_cfg = {0}; + struct bfad_vport_s *vport; + int rc; - pcfg = kzalloc(sizeof(struct bfad_pcfg_s), GFP_ATOMIC); - if (!pcfg) { + vport = kzalloc(sizeof(struct bfad_vport_s), GFP_KERNEL); + if (!vport) { 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; + vport->drv_port.bfad = bfad; + port_cfg.roles = BFA_LPORT_ROLE_FCP_IM; + port_cfg.pwwn = pbc_vport.vp_pwwn; + port_cfg.nwwn = pbc_vport.vp_nwwn; + port_cfg.preboot_vp = BFA_TRUE; + + rc = bfa_fcs_pbc_vport_create(&vport->fcs_vport, &bfad->bfa_fcs, 0, + &port_cfg, vport); - list_add_tail(&pcfg->list_entry, &bfad->pbc_pcfg_list); + if (rc != BFA_STATUS_OK) { + bfa_trc(bfad, 0); + return; + } - return; + list_add_tail(&vport->list_entry, &bfad->pbc_vport_list); } void bfad_hal_mem_release(struct bfad_s *bfad) { - int i; + int i; struct bfa_meminfo_s *hal_meminfo = &bfad->meminfo; struct bfa_mem_elem_s *meminfo_elem; @@ -395,9 +528,9 @@ bfad_hal_mem_release(struct bfad_s *bfad) break; case BFA_MEM_TYPE_DMA: dma_free_coherent(&bfad->pcidev->dev, - meminfo_elem->mem_len, - meminfo_elem->kva, - (dma_addr_t) meminfo_elem->dma); + meminfo_elem->mem_len, + meminfo_elem->kva, + (dma_addr_t) meminfo_elem->dma); break; default: bfa_assert(0); @@ -434,27 +567,27 @@ bfad_update_hal_cfg(struct bfa_iocfc_cfg_s *bfa_cfg) * otherwise, the default values will be shown as 0 in sysfs */ num_rports = bfa_cfg->fwcfg.num_rports; - num_ios = bfa_cfg->fwcfg.num_ioim_reqs; - num_tms = bfa_cfg->fwcfg.num_tskim_reqs; - num_fcxps = bfa_cfg->fwcfg.num_fcxp_reqs; + num_ios = bfa_cfg->fwcfg.num_ioim_reqs; + num_tms = bfa_cfg->fwcfg.num_tskim_reqs; + num_fcxps = bfa_cfg->fwcfg.num_fcxp_reqs; num_ufbufs = bfa_cfg->fwcfg.num_uf_bufs; - reqq_size = bfa_cfg->drvcfg.num_reqq_elems; - rspq_size = bfa_cfg->drvcfg.num_rspq_elems; - num_sgpgs = bfa_cfg->drvcfg.num_sgpgs; + reqq_size = bfa_cfg->drvcfg.num_reqq_elems; + rspq_size = bfa_cfg->drvcfg.num_rspq_elems; + num_sgpgs = bfa_cfg->drvcfg.num_sgpgs; } bfa_status_t bfad_hal_mem_alloc(struct bfad_s *bfad) { + int i; struct bfa_meminfo_s *hal_meminfo = &bfad->meminfo; struct bfa_mem_elem_s *meminfo_elem; - bfa_status_t rc = BFA_STATUS_OK; - dma_addr_t phys_addr; - int retry_count = 0; - int reset_value = 1; - int min_num_sgpgs = 512; - void *kva; - int i; + dma_addr_t phys_addr; + void *kva; + bfa_status_t rc = BFA_STATUS_OK; + int retry_count = 0; + int reset_value = 1; + int min_num_sgpgs = 512; bfa_cfg_get_default(&bfad->ioc_cfg); @@ -478,8 +611,7 @@ retry: break; case BFA_MEM_TYPE_DMA: kva = dma_alloc_coherent(&bfad->pcidev->dev, - meminfo_elem->mem_len, - &phys_addr, GFP_KERNEL); + meminfo_elem->mem_len, &phys_addr, GFP_KERNEL); if (kva == NULL) { bfad_hal_mem_release(bfad); /* @@ -487,14 +619,14 @@ retry: * num_sgpages try with half the value. */ if (num_sgpgs > min_num_sgpgs) { - printk(KERN_INFO "bfad[%d]: memory" - " allocation failed with" - " num_sgpgs: %d\n", + printk(KERN_INFO + "bfad[%d]: memory allocation failed" + " with num_sgpgs: %d\n", bfad->inst_no, num_sgpgs); nextLowerInt(&num_sgpgs); - printk(KERN_INFO "bfad[%d]: trying to" - " allocate memory with" - " num_sgpgs: %d\n", + printk(KERN_INFO + "bfad[%d]: trying to allocate memory" + " with num_sgpgs: %d\n", bfad->inst_no, num_sgpgs); retry_count++; goto retry; @@ -536,11 +668,11 @@ 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_lport_cfg_s *port_cfg, struct device *dev) { - struct bfad_vport_s *vport; - int rc = BFA_STATUS_OK; - unsigned long flags; + struct bfad_vport_s *vport; + int rc = BFA_STATUS_OK; + unsigned long flags; struct completion fcomp; vport = kzalloc(sizeof(struct bfad_vport_s), GFP_KERNEL); @@ -551,18 +683,14 @@ bfad_vport_create(struct bfad_s *bfad, u16 vf_id, vport->drv_port.bfad = bfad; spin_lock_irqsave(&bfad->bfad_lock, flags); - 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); + rc = bfa_fcs_vport_create(&vport->fcs_vport, &bfad->bfa_fcs, vf_id, + port_cfg, vport); spin_unlock_irqrestore(&bfad->bfad_lock, flags); if (rc != BFA_STATUS_OK) goto ext_free_vport; - if (port_cfg->roles & BFA_PORT_ROLE_FCP_IM) { + if (port_cfg->roles & BFA_LPORT_ROLE_FCP_IM) { rc = bfad_im_scsi_host_alloc(bfad, vport->drv_port.im_port, dev); if (rc != BFA_STATUS_OK) @@ -593,10 +721,10 @@ ext: */ bfa_status_t bfad_vf_create(struct bfad_s *bfad, u16 vf_id, - struct bfa_port_cfg_s *port_cfg) + struct bfa_lport_cfg_s *port_cfg) { - struct bfad_vf_s *vf; - int rc = BFA_STATUS_OK; + struct bfad_vf_s *vf; + int rc = BFA_STATUS_OK; vf = kzalloc(sizeof(struct bfad_vf_s), GFP_KERNEL); if (!vf) { @@ -615,9 +743,9 @@ ext: void bfad_bfa_tmo(unsigned long data) { - struct bfad_s *bfad = (struct bfad_s *)data; - unsigned long flags; - struct list_head doneq; + struct bfad_s *bfad = (struct bfad_s *) data; + unsigned long flags; + struct list_head doneq; spin_lock_irqsave(&bfad->bfad_lock, flags); @@ -633,7 +761,8 @@ bfad_bfa_tmo(unsigned long data) spin_unlock_irqrestore(&bfad->bfad_lock, flags); } - mod_timer(&bfad->hal_tmo, jiffies + msecs_to_jiffies(BFA_TIMER_FREQ)); + mod_timer(&bfad->hal_tmo, + jiffies + msecs_to_jiffies(BFA_TIMER_FREQ)); } void @@ -643,16 +772,17 @@ bfad_init_timer(struct bfad_s *bfad) bfad->hal_tmo.function = bfad_bfa_tmo; bfad->hal_tmo.data = (unsigned long)bfad; - mod_timer(&bfad->hal_tmo, jiffies + msecs_to_jiffies(BFA_TIMER_FREQ)); + mod_timer(&bfad->hal_tmo, + jiffies + msecs_to_jiffies(BFA_TIMER_FREQ)); } int bfad_pci_init(struct pci_dev *pdev, struct bfad_s *bfad) { - int rc = -ENODEV; + int rc = -ENODEV; if (pci_enable_device(pdev)) { - BFA_PRINTF(BFA_ERR, "pci_enable_device fail %p\n", pdev); + printk(KERN_ERR "pci_enable_device fail %p\n", pdev); goto out; } @@ -664,14 +794,14 @@ bfad_pci_init(struct pci_dev *pdev, struct bfad_s *bfad) if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) != 0) if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) { - BFA_PRINTF(BFA_ERR, "pci_set_dma_mask fail %p\n", pdev); + printk(KERN_ERR "pci_set_dma_mask fail %p\n", pdev); goto out_release_region; } bfad->pci_bar0_kva = pci_iomap(pdev, 0, pci_resource_len(pdev, 0)); if (bfad->pci_bar0_kva == NULL) { - BFA_PRINTF(BFA_ERR, "Fail to map bar0\n"); + printk(KERN_ERR "Fail to map bar0\n"); goto out_release_region; } @@ -688,6 +818,54 @@ bfad_pci_init(struct pci_dev *pdev, struct bfad_s *bfad) bfad->pci_attr.pcifn = PCI_FUNC(pdev->devfn); bfad->pcidev = pdev; + + /* Adjust PCIe Maximum Read Request Size */ + if (pcie_max_read_reqsz > 0) { + int pcie_cap_reg; + u16 pcie_dev_ctl; + u16 mask = 0xffff; + + switch (pcie_max_read_reqsz) { + case 128: + mask = 0x0; + break; + case 256: + mask = 0x1000; + break; + case 512: + mask = 0x2000; + break; + case 1024: + mask = 0x3000; + break; + case 2048: + mask = 0x4000; + break; + case 4096: + mask = 0x5000; + break; + default: + break; + } + + pcie_cap_reg = pci_find_capability(pdev, PCI_CAP_ID_EXP); + if (mask != 0xffff && pcie_cap_reg) { + pcie_cap_reg += 0x08; + pci_read_config_word(pdev, pcie_cap_reg, &pcie_dev_ctl); + if ((pcie_dev_ctl & 0x7000) != mask) { + printk(KERN_WARNING "BFA[%s]: " + "pcie_max_read_request_size is %d, " + "reset to %d\n", bfad->pci_name, + (1 << ((pcie_dev_ctl & 0x7000) >> 12)) << 7, + pcie_max_read_reqsz); + + pcie_dev_ctl &= ~0x7000; + pci_write_config_word(pdev, pcie_cap_reg, + pcie_dev_ctl | mask); + } + } + } + return 0; out_release_region: @@ -710,25 +888,22 @@ bfad_pci_uninit(struct pci_dev *pdev, struct bfad_s *bfad) void bfad_fcs_port_cfg(struct bfad_s *bfad) { - struct bfa_port_cfg_s port_cfg; - struct bfa_pport_attr_s attr; - char symname[BFA_SYMNAME_MAXLEN]; + struct bfa_lport_cfg_s port_cfg; + struct bfa_port_attr_s attr; + char symname[BFA_SYMNAME_MAXLEN]; sprintf(symname, "%s-%d", BFAD_DRIVER_NAME, bfad->inst_no); memcpy(port_cfg.sym_name.symname, symname, strlen(symname)); bfa_fcport_get_attr(&bfad->bfa, &attr); port_cfg.nwwn = attr.nwwn; port_cfg.pwwn = attr.pwwn; - - bfa_fcs_cfg_base_port(&bfad->bfa_fcs, &port_cfg); } bfa_status_t bfad_drv_init(struct bfad_s *bfad) { - bfa_status_t rc; - unsigned long flags; - struct bfa_fcs_driver_info_s driver_info; + bfa_status_t rc; + unsigned long flags; bfad->cfg_data.rport_del_timeout = rport_del_timeout; bfad->cfg_data.lun_queue_depth = bfa_lun_queue_depth; @@ -740,15 +915,12 @@ bfad_drv_init(struct bfad_s *bfad) printk(KERN_WARNING "bfad%d bfad_hal_mem_alloc failure\n", bfad->inst_no); printk(KERN_WARNING - "Not enough memory to attach all Brocade HBA ports," - " System may need more memory.\n"); + "Not enough memory to attach all Brocade HBA ports, %s", + "System may need more memory.\n"); goto out_hal_mem_alloc_failure; } - bfa_init_log(&bfad->bfa, bfad->logmod); bfa_init_trc(&bfad->bfa, bfad->trcmod); - bfa_init_aen(&bfad->bfa, bfad->aen); - memset(bfad->file_map, 0, sizeof(bfad->file_map)); bfa_init_plog(&bfad->bfa, &bfad->plog_buf); bfa_plog_init(&bfad->plog_buf); bfa_plog_str(&bfad->plog_buf, BFA_PL_MID_DRVR, BFA_PL_EID_DRIVER_START, @@ -757,77 +929,17 @@ bfad_drv_init(struct bfad_s *bfad) bfa_attach(&bfad->bfa, bfad, &bfad->ioc_cfg, &bfad->meminfo, &bfad->hal_pcidev); - init_completion(&bfad->comp); - - /* - * Enable Interrupt and wait bfa_init completion - */ - if (bfad_setup_intr(bfad)) { - printk(KERN_WARNING "bfad%d: bfad_setup_intr failed\n", - bfad->inst_no); - goto out_setup_intr_failure; - } - + /* FCS INIT */ spin_lock_irqsave(&bfad->bfad_lock, flags); - bfa_init(&bfad->bfa); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - /* - * Set up interrupt handler for each vectors - */ - if ((bfad->bfad_flags & BFAD_MSIX_ON) - && bfad_install_msix_handler(bfad)) { - printk(KERN_WARNING "%s: install_msix failed, bfad%d\n", - __func__, bfad->inst_no); - } - - bfad_init_timer(bfad); - - wait_for_completion(&bfad->comp); - - memset(&driver_info, 0, sizeof(driver_info)); - strncpy(driver_info.version, BFAD_DRIVER_VERSION, - sizeof(driver_info.version) - 1); - __kernel_param_lock(); - if (host_name) - strncpy(driver_info.host_machine_name, host_name, - sizeof(driver_info.host_machine_name) - 1); - if (os_name) - strncpy(driver_info.host_os_name, os_name, - sizeof(driver_info.host_os_name) - 1); - if (os_patch) - strncpy(driver_info.host_os_patch, os_patch, - sizeof(driver_info.host_os_patch) - 1); - __kernel_param_unlock(); - - strncpy(driver_info.os_device_name, bfad->pci_name, - sizeof(driver_info.os_device_name - 1)); - - /* - * FCS INIT - */ - spin_lock_irqsave(&bfad->bfad_lock, flags); - bfa_fcs_log_init(&bfad->bfa_fcs, bfad->logmod); bfa_fcs_trc_init(&bfad->bfa_fcs, bfad->trcmod); - bfa_fcs_aen_init(&bfad->bfa_fcs, bfad->aen); bfa_fcs_attach(&bfad->bfa_fcs, &bfad->bfa, bfad, BFA_FALSE); - - /* Do FCS init only when HAL init is done */ - if ((bfad->bfad_flags & BFAD_HAL_INIT_DONE)) { - bfa_fcs_init(&bfad->bfa_fcs); - bfad->bfad_flags |= BFAD_FCS_INIT_DONE; - } - - bfa_fcs_driver_info_init(&bfad->bfa_fcs, &driver_info); bfa_fcs_set_fdmi_param(&bfad->bfa_fcs, fdmi_enable); spin_unlock_irqrestore(&bfad->bfad_lock, flags); bfad->bfad_flags |= BFAD_DRV_INIT_DONE; + return BFA_STATUS_OK; -out_setup_intr_failure: - bfa_detach(&bfad->bfa); - bfad_hal_mem_release(bfad); out_hal_mem_alloc_failure: return BFA_STATUS_FAILED; } @@ -855,7 +967,7 @@ bfad_drv_uninit(struct bfad_s *bfad) void bfad_drv_start(struct bfad_s *bfad) { - unsigned long flags; + unsigned long flags; spin_lock_irqsave(&bfad->bfad_lock, flags); bfa_start(&bfad->bfa); @@ -863,13 +975,14 @@ bfad_drv_start(struct bfad_s *bfad) bfad->bfad_flags |= BFAD_HAL_START_DONE; spin_unlock_irqrestore(&bfad->bfad_lock, flags); - bfad_fc4_probe_post(bfad); + if (bfad->im) + flush_workqueue(bfad->im->drv_workq); } void -bfad_drv_stop(struct bfad_s *bfad) +bfad_fcs_stop(struct bfad_s *bfad) { - unsigned long flags; + unsigned long flags; spin_lock_irqsave(&bfad->bfad_lock, flags); init_completion(&bfad->comp); @@ -878,24 +991,32 @@ bfad_drv_stop(struct bfad_s *bfad) spin_unlock_irqrestore(&bfad->bfad_lock, flags); wait_for_completion(&bfad->comp); + bfa_sm_send_event(bfad, BFAD_E_FCS_EXIT_COMP); +} + +void +bfad_stop(struct bfad_s *bfad) +{ + unsigned long flags; + spin_lock_irqsave(&bfad->bfad_lock, flags); init_completion(&bfad->comp); bfa_stop(&bfad->bfa); bfad->bfad_flags &= ~BFAD_HAL_START_DONE; spin_unlock_irqrestore(&bfad->bfad_lock, flags); wait_for_completion(&bfad->comp); + + bfa_sm_send_event(bfad, BFAD_E_EXIT_COMP); } bfa_status_t -bfad_cfg_pport(struct bfad_s *bfad, enum bfa_port_role role) +bfad_cfg_pport(struct bfad_s *bfad, enum bfa_lport_role role) { - int rc = BFA_STATUS_OK; + int rc = BFA_STATUS_OK; - /* - * Allocate scsi_host for the physical port - */ - if ((bfad_supported_fc4s & BFA_PORT_ROLE_FCP_IM) - && (role & BFA_PORT_ROLE_FCP_IM)) { + /* Allocate scsi_host for the physical port */ + if ((supported_fc4s & BFA_LPORT_ROLE_FCP_IM) && + (role & BFA_LPORT_ROLE_FCP_IM)) { if (bfad->pport.im_port == NULL) { rc = BFA_STATUS_FAILED; goto out; @@ -906,7 +1027,7 @@ bfad_cfg_pport(struct bfad_s *bfad, enum bfa_port_role role) if (rc != BFA_STATUS_OK) goto out; - bfad->pport.roles |= BFA_PORT_ROLE_FCP_IM; + bfad->pport.roles |= BFA_LPORT_ROLE_FCP_IM; } /* Setup the debugfs node for this scsi_host */ @@ -922,74 +1043,102 @@ out: void bfad_uncfg_pport(struct bfad_s *bfad) { - /* Remove the debugfs node for this scsi_host */ + /* 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; - } - - if ((bfad_supported_fc4s & BFA_PORT_ROLE_FCP_IM) - && (bfad->pport.roles & BFA_PORT_ROLE_FCP_IM)) { + if ((supported_fc4s & BFA_LPORT_ROLE_FCP_IM) && + (bfad->pport.roles & BFA_LPORT_ROLE_FCP_IM)) { bfad_im_scsi_host_free(bfad, bfad->pport.im_port); bfad_im_port_clean(bfad->pport.im_port); kfree(bfad->pport.im_port); - bfad->pport.roles &= ~BFA_PORT_ROLE_FCP_IM; + bfad->pport.roles &= ~BFA_LPORT_ROLE_FCP_IM; } bfad->bfad_flags &= ~BFAD_CFG_PPORT_DONE; } -void -bfad_drv_log_level_set(struct bfad_s *bfad) -{ - if (log_level > BFA_LOG_INVALID && log_level <= BFA_LOG_LEVEL_MAX) - bfa_log_set_level_all(&bfad->log_data, log_level); -} - bfa_status_t -bfad_start_ops(struct bfad_s *bfad) -{ - int retval; - struct bfad_pcfg_s *pcfg, *pcfg_new; +bfad_start_ops(struct bfad_s *bfad) { + + int retval; + unsigned long flags; + struct bfad_vport_s *vport, *vport_new; + struct bfa_fcs_driver_info_s driver_info; + + /* Fill the driver_info info to fcs*/ + memset(&driver_info, 0, sizeof(driver_info)); + strncpy(driver_info.version, BFAD_DRIVER_VERSION, + sizeof(driver_info.version) - 1); + if (host_name) + strncpy(driver_info.host_machine_name, host_name, + sizeof(driver_info.host_machine_name) - 1); + if (os_name) + strncpy(driver_info.host_os_name, os_name, + sizeof(driver_info.host_os_name) - 1); + if (os_patch) + strncpy(driver_info.host_os_patch, os_patch, + sizeof(driver_info.host_os_patch) - 1); + + strncpy(driver_info.os_device_name, bfad->pci_name, + sizeof(driver_info.os_device_name - 1)); + + /* FCS INIT */ + spin_lock_irqsave(&bfad->bfad_lock, flags); + bfa_fcs_driver_info_init(&bfad->bfa_fcs, &driver_info); + bfa_fcs_init(&bfad->bfa_fcs); + spin_unlock_irqrestore(&bfad->bfad_lock, flags); /* PPORT FCS config */ bfad_fcs_port_cfg(bfad); - retval = bfad_cfg_pport(bfad, BFA_PORT_ROLE_FCP_IM); - if (retval != BFA_STATUS_OK) - goto out_cfg_pport_failure; - - /* BFAD level FC4 (IM/TM/IPFC) specific resource allocation */ - retval = bfad_fc4_probe(bfad); + retval = bfad_cfg_pport(bfad, BFA_LPORT_ROLE_FCP_IM); if (retval != BFA_STATUS_OK) { - printk(KERN_WARNING "bfad_fc4_probe failed\n"); - goto out_fc4_probe_failure; + if (bfa_sm_cmp_state(bfad, bfad_sm_initializing)) + bfa_sm_set_state(bfad, bfad_sm_failed); + bfad_stop(bfad); + return BFA_STATUS_FAILED; } + /* BFAD level FC4 IM specific resource allocation */ + retval = bfad_im_probe(bfad); + if (retval != BFA_STATUS_OK) { + printk(KERN_WARNING "bfad_im_probe failed\n"); + if (bfa_sm_cmp_state(bfad, bfad_sm_initializing)) + bfa_sm_set_state(bfad, bfad_sm_failed); + bfad_im_probe_undo(bfad); + bfad->bfad_flags &= ~BFAD_FC4_PROBE_DONE; + bfad_uncfg_pport(bfad); + bfad_stop(bfad); + return BFA_STATUS_FAILED; + } else + bfad->bfad_flags |= BFAD_FC4_PROBE_DONE; + bfad_drv_start(bfad); - /* pbc vport creation */ - list_for_each_entry_safe(pcfg, pcfg_new, &bfad->pbc_pcfg_list, - list_entry) { + /* Complete pbc vport create */ + list_for_each_entry_safe(vport, vport_new, &bfad->pbc_vport_list, + list_entry) { struct fc_vport_identifiers vid; struct fc_vport *fc_vport; + char pwwn_buf[BFA_STRING_32]; 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); + vid.node_name = wwn_to_u64((u8 *) + (&((vport->fcs_vport).lport.port_cfg.nwwn))); + vid.port_name = wwn_to_u64((u8 *) + (&((vport->fcs_vport).lport.port_cfg.pwwn))); fc_vport = fc_vport_create(bfad->pport.im_port->shost, 0, &vid); - if (!fc_vport) + if (!fc_vport) { + wwn2str(pwwn_buf, vid.port_name); 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); - + " %s\n", bfad->inst_no, pwwn_buf); + } + list_del(&vport->list_entry); + kfree(vport); } /* @@ -998,24 +1147,15 @@ bfad_start_ops(struct bfad_s *bfad) * passed in module param value as the bfa_linkup_delay. */ if (bfa_linkup_delay < 0) { - bfa_linkup_delay = bfad_os_get_linkup_delay(bfad); bfad_os_rport_online_wait(bfad); bfa_linkup_delay = -1; - - } else { + } else bfad_os_rport_online_wait(bfad); - } - bfa_log(bfad->logmod, BFA_LOG_LINUX_DEVICE_CLAIMED, bfad->pci_name); + BFA_LOG(KERN_INFO, bfad, log_level, "bfa device claimed\n"); return BFA_STATUS_OK; - -out_fc4_probe_failure: - bfad_fc4_probe_undo(bfad); - bfad_uncfg_pport(bfad); -out_cfg_pport_failure: - return BFA_STATUS_FAILED; } int @@ -1028,18 +1168,8 @@ bfad_worker(void *ptr) while (!kthread_should_stop()) { - /* Check if the FCS init is done from bfad_drv_init; - * if not done do FCS init and set the flag. - */ - if (!(bfad->bfad_flags & BFAD_FCS_INIT_DONE)) { - spin_lock_irqsave(&bfad->bfad_lock, flags); - bfa_fcs_init(&bfad->bfa_fcs); - bfad->bfad_flags |= BFAD_FCS_INIT_DONE; - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - } - - /* Start the bfad operations after HAL init done */ - bfad_start_ops(bfad); + /* Send event BFAD_E_INIT_SUCCESS */ + bfa_sm_send_event(bfad, BFAD_E_INIT_SUCCESS); spin_lock_irqsave(&bfad->bfad_lock, flags); bfad->bfad_tsk = NULL; @@ -1051,9 +1181,198 @@ bfad_worker(void *ptr) return 0; } - /* - * PCI_entry PCI driver entries * { - */ +/** + * BFA driver interrupt functions + */ +irqreturn_t +bfad_intx(int irq, void *dev_id) +{ + struct bfad_s *bfad = dev_id; + struct list_head doneq; + unsigned long flags; + bfa_boolean_t rc; + + spin_lock_irqsave(&bfad->bfad_lock, flags); + rc = bfa_intx(&bfad->bfa); + if (!rc) { + spin_unlock_irqrestore(&bfad->bfad_lock, flags); + return IRQ_NONE; + } + + bfa_comp_deq(&bfad->bfa, &doneq); + spin_unlock_irqrestore(&bfad->bfad_lock, flags); + + if (!list_empty(&doneq)) { + bfa_comp_process(&bfad->bfa, &doneq); + + spin_lock_irqsave(&bfad->bfad_lock, flags); + bfa_comp_free(&bfad->bfa, &doneq); + spin_unlock_irqrestore(&bfad->bfad_lock, flags); + bfa_trc_fp(bfad, irq); + } + + return IRQ_HANDLED; + +} + +static irqreturn_t +bfad_msix(int irq, void *dev_id) +{ + struct bfad_msix_s *vec = dev_id; + struct bfad_s *bfad = vec->bfad; + struct list_head doneq; + unsigned long flags; + + spin_lock_irqsave(&bfad->bfad_lock, flags); + + bfa_msix(&bfad->bfa, vec->msix.entry); + bfa_comp_deq(&bfad->bfa, &doneq); + spin_unlock_irqrestore(&bfad->bfad_lock, flags); + + if (!list_empty(&doneq)) { + bfa_comp_process(&bfad->bfa, &doneq); + + spin_lock_irqsave(&bfad->bfad_lock, flags); + bfa_comp_free(&bfad->bfa, &doneq); + spin_unlock_irqrestore(&bfad->bfad_lock, flags); + } + + return IRQ_HANDLED; +} + +/** + * Initialize the MSIX entry table. + */ +static void +bfad_init_msix_entry(struct bfad_s *bfad, struct msix_entry *msix_entries, + int mask, int max_bit) +{ + int i; + int match = 0x00000001; + + for (i = 0, bfad->nvec = 0; i < MAX_MSIX_ENTRY; i++) { + if (mask & match) { + bfad->msix_tab[bfad->nvec].msix.entry = i; + bfad->msix_tab[bfad->nvec].bfad = bfad; + msix_entries[bfad->nvec].entry = i; + bfad->nvec++; + } + + match <<= 1; + } + +} + +int +bfad_install_msix_handler(struct bfad_s *bfad) +{ + int i, error = 0; + + for (i = 0; i < bfad->nvec; i++) { + sprintf(bfad->msix_tab[i].name, "bfa-%s-%s", + bfad->pci_name, + ((bfa_asic_id_ct(bfad->hal_pcidev.device_id)) ? + msix_name_ct[i] : msix_name_cb[i])); + + error = request_irq(bfad->msix_tab[i].msix.vector, + (irq_handler_t) bfad_msix, 0, + bfad->msix_tab[i].name, &bfad->msix_tab[i]); + bfa_trc(bfad, i); + bfa_trc(bfad, bfad->msix_tab[i].msix.vector); + if (error) { + int j; + + for (j = 0; j < i; j++) + free_irq(bfad->msix_tab[j].msix.vector, + &bfad->msix_tab[j]); + + return 1; + } + } + + return 0; +} + +/** + * Setup MSIX based interrupt. + */ +int +bfad_setup_intr(struct bfad_s *bfad) +{ + int error = 0; + u32 mask = 0, i, num_bit = 0, max_bit = 0; + struct msix_entry msix_entries[MAX_MSIX_ENTRY]; + struct pci_dev *pdev = bfad->pcidev; + + /* Call BFA to get the msix map for this PCI function. */ + bfa_msix_getvecs(&bfad->bfa, &mask, &num_bit, &max_bit); + + /* Set up the msix entry table */ + bfad_init_msix_entry(bfad, msix_entries, mask, max_bit); + + if ((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) { + /* + * Only error number of vector is available. + * We don't have a mechanism to map multiple + * interrupts into one vector, so even if we + * can try to request less vectors, we don't + * know how to associate interrupt events to + * vectors. Linux doesn't dupicate vectors + * in the MSIX table for this case. + */ + + printk(KERN_WARNING "bfad%d: " + "pci_enable_msix failed (%d)," + " use line based.\n", bfad->inst_no, error); + + goto line_based; + } + + /* Save the vectors */ + for (i = 0; i < bfad->nvec; i++) { + bfa_trc(bfad, msix_entries[i].vector); + bfad->msix_tab[i].msix.vector = msix_entries[i].vector; + } + + bfa_msix_init(&bfad->bfa, bfad->nvec); + + bfad->bfad_flags |= BFAD_MSIX_ON; + + return error; + } + +line_based: + error = 0; + if (request_irq + (bfad->pcidev->irq, (irq_handler_t) bfad_intx, BFAD_IRQ_FLAGS, + BFAD_DRIVER_NAME, bfad) != 0) { + /* Enable interrupt handler failed */ + return 1; + } + + return error; +} + +void +bfad_remove_intr(struct bfad_s *bfad) +{ + int i; + + if (bfad->bfad_flags & BFAD_MSIX_ON) { + for (i = 0; i < bfad->nvec; i++) + free_irq(bfad->msix_tab[i].msix.vector, + &bfad->msix_tab[i]); + + pci_disable_msix(bfad->pcidev); + bfad->bfad_flags &= ~BFAD_MSIX_ON; + } else { + free_irq(bfad->pcidev->irq, bfad); + } +} /** * PCI probe entry. @@ -1061,18 +1380,14 @@ bfad_worker(void *ptr) int bfad_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid) { - struct bfad_s *bfad; - int error = -ENODEV, retval; + struct bfad_s *bfad; + int error = -ENODEV, retval; - /* - * For single port cards - only claim function 0 - */ - if ((pdev->device == BFA_PCI_DEVICE_ID_FC_8G1P) - && (PCI_FUNC(pdev->devfn) != 0)) + /* For single port cards - only claim function 0 */ + if ((pdev->device == BFA_PCI_DEVICE_ID_FC_8G1P) && + (PCI_FUNC(pdev->devfn) != 0)) return -ENODEV; - BFA_TRACE(BFA_INFO, "bfad_pci_probe entry"); - bfad = kzalloc(sizeof(struct bfad_s), GFP_KERNEL); if (!bfad) { error = -ENOMEM; @@ -1086,21 +1401,11 @@ bfad_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid) goto out_alloc_trace_failure; } - /* - * LOG/TRACE INIT - */ + /* TRACE INIT */ bfa_trc_init(bfad->trcmod); bfa_trc(bfad, bfad_inst); - bfad->logmod = &bfad->log_data; - bfa_log_init(bfad->logmod, (char *)pci_name(pdev), bfa_os_printf); - - bfad_drv_log_level_set(bfad); - - bfad->aen = &bfad->aen_buf; - if (!(bfad_load_fwimg(pdev))) { - printk(KERN_WARNING "bfad_load_fwimg failure!\n"); kfree(bfad->trcmod); goto out_alloc_trace_failure; } @@ -1117,46 +1422,31 @@ bfad_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid) list_add_tail(&bfad->list_entry, &bfad_list); mutex_unlock(&bfad_mutex); + /* Initializing the state machine: State set to uninit */ + bfa_sm_set_state(bfad, bfad_sm_uninit); + spin_lock_init(&bfad->bfad_lock); pci_set_drvdata(pdev, bfad); 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"); - if (IS_ERR(bfad->bfad_tsk)) { - printk(KERN_INFO "bfad[%d]: Kernel thread" - " creation failed!\n", - bfad->inst_no); - goto out_kthread_create_failure; - } + INIT_LIST_HEAD(&bfad->pbc_vport_list); retval = bfad_drv_init(bfad); if (retval != BFA_STATUS_OK) goto out_drv_init_failure; - if (!(bfad->bfad_flags & BFAD_HAL_INIT_DONE)) { - bfad->bfad_flags |= BFAD_HAL_INIT_FAIL; - printk(KERN_WARNING "bfad%d: hal init failed\n", bfad->inst_no); - goto ok; - } - retval = bfad_start_ops(bfad); - if (retval != BFA_STATUS_OK) - goto out_start_ops_failure; + bfa_sm_send_event(bfad, BFAD_E_CREATE); - kthread_stop(bfad->bfad_tsk); - bfad->bfad_tsk = NULL; + if (bfa_sm_cmp_state(bfad, bfad_sm_uninit)) + goto out_bfad_sm_failure; -ok: return 0; -out_start_ops_failure: - bfad_drv_uninit(bfad); +out_bfad_sm_failure: + bfa_detach(&bfad->bfa); + bfad_hal_mem_release(bfad); out_drv_init_failure: - kthread_stop(bfad->bfad_tsk); -out_kthread_create_failure: mutex_lock(&bfad_mutex); bfad_inst--; list_del(&bfad->list_entry); @@ -1176,62 +1466,29 @@ out: void bfad_pci_remove(struct pci_dev *pdev) { - struct bfad_s *bfad = pci_get_drvdata(pdev); - unsigned long flags; + struct bfad_s *bfad = pci_get_drvdata(pdev); + unsigned long flags; bfa_trc(bfad, bfad->inst_no); spin_lock_irqsave(&bfad->bfad_lock, flags); - if (bfad->bfad_tsk != NULL) - kthread_stop(bfad->bfad_tsk); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - if ((bfad->bfad_flags & BFAD_DRV_INIT_DONE) - && !(bfad->bfad_flags & BFAD_HAL_INIT_DONE)) { - - spin_lock_irqsave(&bfad->bfad_lock, flags); - init_completion(&bfad->comp); - bfa_stop(&bfad->bfa); + if (bfad->bfad_tsk != NULL) { spin_unlock_irqrestore(&bfad->bfad_lock, flags); - wait_for_completion(&bfad->comp); - - bfad_remove_intr(bfad); - del_timer_sync(&bfad->hal_tmo); - goto hal_detach; - } else if (!(bfad->bfad_flags & BFAD_DRV_INIT_DONE)) { - goto remove_sysfs; - } - - if (bfad->bfad_flags & BFAD_HAL_START_DONE) { - bfad_drv_stop(bfad); - } else if (bfad->bfad_flags & BFAD_DRV_INIT_DONE) { - /* Invoking bfa_stop() before bfa_detach - * when HAL and DRV init are success - * but HAL start did not occur. - */ - spin_lock_irqsave(&bfad->bfad_lock, flags); - init_completion(&bfad->comp); - bfa_stop(&bfad->bfa); + kthread_stop(bfad->bfad_tsk); + } else { spin_unlock_irqrestore(&bfad->bfad_lock, flags); - wait_for_completion(&bfad->comp); } - bfad_remove_intr(bfad); - del_timer_sync(&bfad->hal_tmo); + /* Send Event BFAD_E_STOP */ + bfa_sm_send_event(bfad, BFAD_E_STOP); - if (bfad->bfad_flags & BFAD_FC4_PROBE_DONE) - bfad_fc4_probe_undo(bfad); - - if (bfad->bfad_flags & BFAD_CFG_PPORT_DONE) - bfad_uncfg_pport(bfad); - -hal_detach: + /* Driver detach and dealloc mem */ spin_lock_irqsave(&bfad->bfad_lock, flags); bfa_detach(&bfad->bfa); spin_unlock_irqrestore(&bfad->bfad_lock, flags); bfad_hal_mem_release(bfad); -remove_sysfs: + /* Cleaning the BFAD instance */ mutex_lock(&bfad_mutex); bfad_inst--; list_del(&bfad->list_entry); @@ -1242,35 +1499,34 @@ remove_sysfs: kfree(bfad); } - -static struct pci_device_id bfad_id_table[] = { +struct pci_device_id bfad_id_table[] = { { - .vendor = BFA_PCI_VENDOR_ID_BROCADE, - .device = BFA_PCI_DEVICE_ID_FC_8G2P, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, + .vendor = BFA_PCI_VENDOR_ID_BROCADE, + .device = BFA_PCI_DEVICE_ID_FC_8G2P, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, { - .vendor = BFA_PCI_VENDOR_ID_BROCADE, - .device = BFA_PCI_DEVICE_ID_FC_8G1P, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, + .vendor = BFA_PCI_VENDOR_ID_BROCADE, + .device = BFA_PCI_DEVICE_ID_FC_8G1P, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, { - .vendor = BFA_PCI_VENDOR_ID_BROCADE, - .device = BFA_PCI_DEVICE_ID_CT, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .class = (PCI_CLASS_SERIAL_FIBER << 8), - .class_mask = ~0, - }, + .vendor = BFA_PCI_VENDOR_ID_BROCADE, + .device = BFA_PCI_DEVICE_ID_CT, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .class = (PCI_CLASS_SERIAL_FIBER << 8), + .class_mask = ~0, + }, { - .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, + .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}, @@ -1286,89 +1542,104 @@ static struct pci_driver bfad_pci_driver = { }; /** - * Linux driver module functions - */ -bfa_status_t -bfad_fc4_module_init(void) -{ - int rc; - - rc = bfad_im_module_init(); - if (rc != BFA_STATUS_OK) - goto ext; - - bfad_tm_module_init(); - if (ipfc_enable) - bfad_ipfc_module_init(); -ext: - return rc; -} - -void -bfad_fc4_module_exit(void) -{ - if (ipfc_enable) - bfad_ipfc_module_exit(); - bfad_tm_module_exit(); - bfad_im_module_exit(); -} - -/** * Driver module init. */ -static int __init +static int __init bfad_init(void) { - int error = 0; + int error = 0; printk(KERN_INFO "Brocade BFA FC/FCOE SCSI driver - version: %s\n", - BFAD_DRIVER_VERSION); + BFAD_DRIVER_VERSION); if (num_sgpgs > 0) num_sgpgs_parm = num_sgpgs; - error = bfad_fc4_module_init(); + error = bfad_im_module_init(); if (error) { error = -ENOMEM; - printk(KERN_WARNING "bfad_fc4_module_init failure\n"); + printk(KERN_WARNING "bfad_im_module_init failure\n"); goto ext; } - if (!strcmp(FCPI_NAME, " fcpim")) - bfad_supported_fc4s |= BFA_PORT_ROLE_FCP_IM; - if (!strcmp(FCPT_NAME, " fcptm")) - bfad_supported_fc4s |= BFA_PORT_ROLE_FCP_TM; - if (!strcmp(IPFC_NAME, " ipfc")) - bfad_supported_fc4s |= BFA_PORT_ROLE_FCP_IPFC; + if (strcmp(FCPI_NAME, " fcpim") == 0) + supported_fc4s |= BFA_LPORT_ROLE_FCP_IM; bfa_ioc_auto_recover(ioc_auto_recover); bfa_fcs_rport_set_del_timeout(rport_del_timeout); - error = pci_register_driver(&bfad_pci_driver); + error = pci_register_driver(&bfad_pci_driver); if (error) { - printk(KERN_WARNING "bfad pci_register_driver failure\n"); + printk(KERN_WARNING "pci_register_driver failure\n"); goto ext; } return 0; ext: - bfad_fc4_module_exit(); + bfad_im_module_exit(); return error; } /** * Driver module exit. */ -static void __exit +static void __exit bfad_exit(void) { pci_unregister_driver(&bfad_pci_driver); - bfad_fc4_module_exit(); + bfad_im_module_exit(); bfad_free_fwimg(); } -#define BFAD_PROTO_NAME FCPI_NAME FCPT_NAME IPFC_NAME +/* Firmware handling */ +u32 * +bfad_read_firmware(struct pci_dev *pdev, u32 **bfi_image, + u32 *bfi_image_size, char *fw_name) +{ + const struct firmware *fw; + + if (request_firmware(&fw, fw_name, &pdev->dev)) { + printk(KERN_ALERT "Can't locate firmware %s\n", fw_name); + goto error; + } + + *bfi_image = vmalloc(fw->size); + if (NULL == *bfi_image) { + printk(KERN_ALERT "Fail to allocate buffer for fw image " + "size=%x!\n", (u32) fw->size); + goto error; + } + + memcpy(*bfi_image, fw->data, fw->size); + *bfi_image_size = fw->size/sizeof(u32); + + return *bfi_image; + +error: + return NULL; +} + +u32 * +bfad_get_firmware_buf(struct pci_dev *pdev) +{ + if (pdev->device == BFA_PCI_DEVICE_ID_CT_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_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; + } +} module_init(bfad_init); module_exit(bfad_exit); @@ -1376,5 +1647,3 @@ MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Brocade Fibre Channel HBA Driver" BFAD_PROTO_NAME); MODULE_AUTHOR("Brocade Communications Systems, Inc."); MODULE_VERSION(BFAD_DRIVER_VERSION); - - diff --git a/drivers/scsi/bfa/bfad_attr.c b/drivers/scsi/bfa/bfad_attr.c index 0818eb07ef88..d8843720eac1 100644 --- a/drivers/scsi/bfa/bfad_attr.c +++ b/drivers/scsi/bfa/bfad_attr.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. * All rights reserved * www.brocade.com * @@ -19,15 +19,8 @@ * bfa_attr.c Linux driver configuration interface module. */ -#include <linux/slab.h> #include "bfad_drv.h" #include "bfad_im.h" -#include "bfad_trcmod.h" -#include "bfad_attr.h" - -/** - * FC_transport_template FC transport template - */ /** * FC transport template entry, get SCSI target port ID. @@ -42,7 +35,7 @@ bfad_im_get_starget_port_id(struct scsi_target *starget) u32 fc_id = -1; unsigned long flags; - shost = bfad_os_starget_to_shost(starget); + shost = dev_to_shost(starget->dev.parent); im_port = (struct bfad_im_port_s *) shost->hostdata[0]; bfad = im_port->bfad; spin_lock_irqsave(&bfad->bfad_lock, flags); @@ -68,7 +61,7 @@ bfad_im_get_starget_node_name(struct scsi_target *starget) u64 node_name = 0; unsigned long flags; - shost = bfad_os_starget_to_shost(starget); + shost = dev_to_shost(starget->dev.parent); im_port = (struct bfad_im_port_s *) shost->hostdata[0]; bfad = im_port->bfad; spin_lock_irqsave(&bfad->bfad_lock, flags); @@ -94,7 +87,7 @@ bfad_im_get_starget_port_name(struct scsi_target *starget) u64 port_name = 0; unsigned long flags; - shost = bfad_os_starget_to_shost(starget); + shost = dev_to_shost(starget->dev.parent); im_port = (struct bfad_im_port_s *) shost->hostdata[0]; bfad = im_port->bfad; spin_lock_irqsave(&bfad->bfad_lock, flags); @@ -118,17 +111,7 @@ bfad_im_get_host_port_id(struct Scsi_Host *shost) struct bfad_port_s *port = im_port->port; fc_host_port_id(shost) = - bfa_os_hton3b(bfa_fcs_port_get_fcid(port->fcs_port)); -} - - - - - -struct Scsi_Host * -bfad_os_starget_to_shost(struct scsi_target *starget) -{ - return dev_to_shost(starget->dev.parent); + bfa_os_hton3b(bfa_fcs_lport_get_fcid(port->fcs_port)); } /** @@ -140,21 +123,21 @@ bfad_im_get_host_port_type(struct Scsi_Host *shost) struct bfad_im_port_s *im_port = (struct bfad_im_port_s *) shost->hostdata[0]; struct bfad_s *bfad = im_port->bfad; - struct bfa_pport_attr_s attr; + struct bfa_lport_attr_s port_attr; - bfa_fcport_get_attr(&bfad->bfa, &attr); + bfa_fcs_lport_get_attr(&bfad->bfa_fcs.fabric.bport, &port_attr); - switch (attr.port_type) { - case BFA_PPORT_TYPE_NPORT: + switch (port_attr.port_type) { + case BFA_PORT_TYPE_NPORT: fc_host_port_type(shost) = FC_PORTTYPE_NPORT; break; - case BFA_PPORT_TYPE_NLPORT: + case BFA_PORT_TYPE_NLPORT: fc_host_port_type(shost) = FC_PORTTYPE_NLPORT; break; - case BFA_PPORT_TYPE_P2P: + case BFA_PORT_TYPE_P2P: fc_host_port_type(shost) = FC_PORTTYPE_PTP; break; - case BFA_PPORT_TYPE_LPORT: + case BFA_PORT_TYPE_LPORT: fc_host_port_type(shost) = FC_PORTTYPE_LPORT; break; default: @@ -172,25 +155,28 @@ bfad_im_get_host_port_state(struct Scsi_Host *shost) struct bfad_im_port_s *im_port = (struct bfad_im_port_s *) shost->hostdata[0]; struct bfad_s *bfad = im_port->bfad; - struct bfa_pport_attr_s attr; + struct bfa_port_attr_s attr; bfa_fcport_get_attr(&bfad->bfa, &attr); switch (attr.port_state) { - case BFA_PPORT_ST_LINKDOWN: + case BFA_PORT_ST_LINKDOWN: fc_host_port_state(shost) = FC_PORTSTATE_LINKDOWN; break; - case BFA_PPORT_ST_LINKUP: + case BFA_PORT_ST_LINKUP: fc_host_port_state(shost) = FC_PORTSTATE_ONLINE; break; - case BFA_PPORT_ST_UNINIT: - case BFA_PPORT_ST_ENABLING_QWAIT: - case BFA_PPORT_ST_ENABLING: - case BFA_PPORT_ST_DISABLING_QWAIT: - case BFA_PPORT_ST_DISABLING: - case BFA_PPORT_ST_DISABLED: - case BFA_PPORT_ST_STOPPED: - case BFA_PPORT_ST_IOCDOWN: + case BFA_PORT_ST_DISABLED: + case BFA_PORT_ST_STOPPED: + case BFA_PORT_ST_IOCDOWN: + case BFA_PORT_ST_IOCDIS: + fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE; + break; + case BFA_PORT_ST_UNINIT: + case BFA_PORT_ST_ENABLING_QWAIT: + case BFA_PORT_ST_ENABLING: + case BFA_PORT_ST_DISABLING_QWAIT: + case BFA_PORT_ST_DISABLING: default: fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN; break; @@ -210,13 +196,9 @@ bfad_im_get_host_active_fc4s(struct Scsi_Host *shost) memset(fc_host_active_fc4s(shost), 0, sizeof(fc_host_active_fc4s(shost))); - if (port->supported_fc4s & - (BFA_PORT_ROLE_FCP_IM | BFA_PORT_ROLE_FCP_TM)) + if (port->supported_fc4s & BFA_LPORT_ROLE_FCP_IM) fc_host_active_fc4s(shost)[2] = 1; - if (port->supported_fc4s & BFA_PORT_ROLE_FCP_IPFC) - fc_host_active_fc4s(shost)[3] = 0x20; - fc_host_active_fc4s(shost)[7] = 1; } @@ -229,29 +211,29 @@ bfad_im_get_host_speed(struct Scsi_Host *shost) struct bfad_im_port_s *im_port = (struct bfad_im_port_s *) shost->hostdata[0]; struct bfad_s *bfad = im_port->bfad; - struct bfa_pport_attr_s attr; - unsigned long flags; + struct bfa_port_attr_s attr; - spin_lock_irqsave(shost->host_lock, flags); bfa_fcport_get_attr(&bfad->bfa, &attr); switch (attr.speed) { - case BFA_PPORT_SPEED_8GBPS: + case BFA_PORT_SPEED_10GBPS: + fc_host_speed(shost) = FC_PORTSPEED_10GBIT; + break; + case BFA_PORT_SPEED_8GBPS: fc_host_speed(shost) = FC_PORTSPEED_8GBIT; break; - case BFA_PPORT_SPEED_4GBPS: + case BFA_PORT_SPEED_4GBPS: fc_host_speed(shost) = FC_PORTSPEED_4GBIT; break; - case BFA_PPORT_SPEED_2GBPS: + case BFA_PORT_SPEED_2GBPS: fc_host_speed(shost) = FC_PORTSPEED_2GBIT; break; - case BFA_PPORT_SPEED_1GBPS: + case BFA_PORT_SPEED_1GBPS: fc_host_speed(shost) = FC_PORTSPEED_1GBIT; break; default: fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN; break; } - spin_unlock_irqrestore(shost->host_lock, flags); } /** @@ -265,7 +247,7 @@ bfad_im_get_host_fabric_name(struct Scsi_Host *shost) struct bfad_port_s *port = im_port->port; wwn_t fabric_nwwn = 0; - fabric_nwwn = bfa_fcs_port_get_fabric_name(port->fcs_port); + fabric_nwwn = bfa_fcs_lport_get_fabric_name(port->fcs_port); fc_host_fabric_name(shost) = bfa_os_htonll(fabric_nwwn); @@ -281,23 +263,44 @@ bfad_im_get_stats(struct Scsi_Host *shost) (struct bfad_im_port_s *) shost->hostdata[0]; struct bfad_s *bfad = im_port->bfad; struct bfad_hal_comp fcomp; + union bfa_port_stats_u *fcstats; struct fc_host_statistics *hstats; bfa_status_t rc; unsigned long flags; + fcstats = kzalloc(sizeof(union bfa_port_stats_u), GFP_KERNEL); + if (fcstats == NULL) + return NULL; + hstats = &bfad->link_stats; init_completion(&fcomp.comp); spin_lock_irqsave(&bfad->bfad_lock, flags); memset(hstats, 0, sizeof(struct fc_host_statistics)); - rc = bfa_port_get_stats(BFA_FCPORT(&bfad->bfa), - (union bfa_pport_stats_u *) hstats, - bfad_hcb_comp, &fcomp); + rc = bfa_port_get_stats(BFA_FCPORT(&bfad->bfa), + fcstats, bfad_hcb_comp, &fcomp); spin_unlock_irqrestore(&bfad->bfad_lock, flags); if (rc != BFA_STATUS_OK) return NULL; wait_for_completion(&fcomp.comp); + /* Fill the fc_host_statistics structure */ + hstats->seconds_since_last_reset = fcstats->fc.secs_reset; + hstats->tx_frames = fcstats->fc.tx_frames; + hstats->tx_words = fcstats->fc.tx_words; + hstats->rx_frames = fcstats->fc.rx_frames; + hstats->rx_words = fcstats->fc.rx_words; + hstats->lip_count = fcstats->fc.lip_count; + hstats->nos_count = fcstats->fc.nos_count; + hstats->error_frames = fcstats->fc.error_frames; + hstats->dumped_frames = fcstats->fc.dropped_frames; + hstats->link_failure_count = fcstats->fc.link_failures; + hstats->loss_of_sync_count = fcstats->fc.loss_of_syncs; + hstats->loss_of_signal_count = fcstats->fc.loss_of_signals; + hstats->prim_seq_protocol_err_count = fcstats->fc.primseq_errs; + hstats->invalid_crc_count = fcstats->fc.invalid_crcs; + + kfree(fcstats); return hstats; } @@ -317,7 +320,7 @@ bfad_im_reset_stats(struct Scsi_Host *shost) init_completion(&fcomp.comp); spin_lock_irqsave(&bfad->bfad_lock, flags); rc = bfa_port_clear_stats(BFA_FCPORT(&bfad->bfa), bfad_hcb_comp, - &fcomp); + &fcomp); spin_unlock_irqrestore(&bfad->bfad_lock, flags); if (rc != BFA_STATUS_OK) @@ -372,8 +375,8 @@ bfad_im_vport_create(struct fc_vport *fc_vport, bool disable) struct bfad_im_port_s *im_port = (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; + struct bfa_lport_cfg_s port_cfg; + struct bfad_vport_s *vp; int status = 0, rc; unsigned long flags; @@ -382,12 +385,14 @@ bfad_im_vport_create(struct fc_vport *fc_vport, bool disable) 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; + port_cfg.roles = BFA_LPORT_ROLE_FCP_IM; 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; + list_for_each_entry(vp, &bfad->pbc_vport_list, list_entry) { + if (port_cfg.pwwn == + vp->fcs_vport.lport.port_cfg.pwwn) { + port_cfg.preboot_vp = + vp->fcs_vport.lport.port_cfg.preboot_vp; break; } } @@ -638,7 +643,7 @@ bfad_im_serial_num_show(struct device *dev, struct device_attribute *attr, struct Scsi_Host *shost = class_to_shost(dev); struct bfad_im_port_s *im_port = (struct bfad_im_port_s *) shost->hostdata[0]; - struct bfad_s *bfad = im_port->bfad; + struct bfad_s *bfad = im_port->bfad; char serial_num[BFA_ADAPTER_SERIAL_NUM_LEN]; bfa_get_adapter_serial_num(&bfad->bfa, serial_num); @@ -652,7 +657,7 @@ bfad_im_model_show(struct device *dev, struct device_attribute *attr, struct Scsi_Host *shost = class_to_shost(dev); struct bfad_im_port_s *im_port = (struct bfad_im_port_s *) shost->hostdata[0]; - struct bfad_s *bfad = im_port->bfad; + struct bfad_s *bfad = im_port->bfad; char model[BFA_ADAPTER_MODEL_NAME_LEN]; bfa_get_adapter_model(&bfad->bfa, model); @@ -666,10 +671,54 @@ bfad_im_model_desc_show(struct device *dev, struct device_attribute *attr, struct Scsi_Host *shost = class_to_shost(dev); struct bfad_im_port_s *im_port = (struct bfad_im_port_s *) shost->hostdata[0]; - struct bfad_s *bfad = im_port->bfad; + struct bfad_s *bfad = im_port->bfad; + char model[BFA_ADAPTER_MODEL_NAME_LEN]; char model_descr[BFA_ADAPTER_MODEL_DESCR_LEN]; - bfa_get_adapter_model(&bfad->bfa, model_descr); + bfa_get_adapter_model(&bfad->bfa, model); + if (!strcmp(model, "Brocade-425")) + snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, + "Brocade 4Gbps PCIe dual port FC HBA"); + else if (!strcmp(model, "Brocade-825")) + snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, + "Brocade 8Gbps PCIe dual port FC HBA"); + else if (!strcmp(model, "Brocade-42B")) + snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, + "HP 4Gbps PCIe dual port FC HBA"); + else if (!strcmp(model, "Brocade-82B")) + snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, + "HP 8Gbps PCIe dual port FC HBA"); + else if (!strcmp(model, "Brocade-1010")) + snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, + "Brocade 10Gbps single port CNA"); + else if (!strcmp(model, "Brocade-1020")) + snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, + "Brocade 10Gbps dual port CNA"); + else if (!strcmp(model, "Brocade-1007")) + snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, + "Brocade 10Gbps CNA"); + else if (!strcmp(model, "Brocade-415")) + snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, + "Brocade 4Gbps PCIe single port FC HBA"); + else if (!strcmp(model, "Brocade-815")) + snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, + "Brocade 8Gbps PCIe single port FC HBA"); + else if (!strcmp(model, "Brocade-41B")) + snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, + "HP 4Gbps PCIe single port FC HBA"); + else if (!strcmp(model, "Brocade-81B")) + snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, + "HP 8Gbps PCIe single port FC HBA"); + else if (!strcmp(model, "Brocade-804")) + snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, + "HP Bladesystem C-class 8Gbps FC HBA"); + else if (!strcmp(model, "Brocade-902")) + snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, + "Brocade 10Gbps CNA"); + else + snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, + "Invalid Model"); + return snprintf(buf, PAGE_SIZE, "%s\n", model_descr); } @@ -683,7 +732,7 @@ bfad_im_node_name_show(struct device *dev, struct device_attribute *attr, struct bfad_port_s *port = im_port->port; u64 nwwn; - nwwn = bfa_fcs_port_get_nwwn(port->fcs_port); + nwwn = bfa_fcs_lport_get_nwwn(port->fcs_port); return snprintf(buf, PAGE_SIZE, "0x%llx\n", bfa_os_htonll(nwwn)); } @@ -694,14 +743,14 @@ bfad_im_symbolic_name_show(struct device *dev, struct device_attribute *attr, struct Scsi_Host *shost = class_to_shost(dev); struct bfad_im_port_s *im_port = (struct bfad_im_port_s *) shost->hostdata[0]; - struct bfad_s *bfad = im_port->bfad; - char model[BFA_ADAPTER_MODEL_NAME_LEN]; - char fw_ver[BFA_VERSION_LEN]; + struct bfad_s *bfad = im_port->bfad; + struct bfa_lport_attr_s port_attr; + char symname[BFA_SYMNAME_MAXLEN]; - bfa_get_adapter_model(&bfad->bfa, model); - bfa_get_adapter_fw_ver(&bfad->bfa, fw_ver); - return snprintf(buf, PAGE_SIZE, "Brocade %s FV%s DV%s\n", - model, fw_ver, BFAD_DRIVER_VERSION); + bfa_fcs_lport_get_attr(&bfad->bfa_fcs.fabric.bport, &port_attr); + strncpy(symname, port_attr.port_cfg.sym_name.symname, + BFA_SYMNAME_MAXLEN); + return snprintf(buf, PAGE_SIZE, "%s\n", symname); } static ssize_t @@ -711,7 +760,7 @@ bfad_im_hw_version_show(struct device *dev, struct device_attribute *attr, struct Scsi_Host *shost = class_to_shost(dev); struct bfad_im_port_s *im_port = (struct bfad_im_port_s *) shost->hostdata[0]; - struct bfad_s *bfad = im_port->bfad; + struct bfad_s *bfad = im_port->bfad; char hw_ver[BFA_VERSION_LEN]; bfa_get_pci_chip_rev(&bfad->bfa, hw_ver); @@ -732,7 +781,7 @@ bfad_im_optionrom_version_show(struct device *dev, struct Scsi_Host *shost = class_to_shost(dev); struct bfad_im_port_s *im_port = (struct bfad_im_port_s *) shost->hostdata[0]; - struct bfad_s *bfad = im_port->bfad; + struct bfad_s *bfad = im_port->bfad; char optrom_ver[BFA_VERSION_LEN]; bfa_get_adapter_optrom_ver(&bfad->bfa, optrom_ver); @@ -746,7 +795,7 @@ bfad_im_fw_version_show(struct device *dev, struct device_attribute *attr, struct Scsi_Host *shost = class_to_shost(dev); struct bfad_im_port_s *im_port = (struct bfad_im_port_s *) shost->hostdata[0]; - struct bfad_s *bfad = im_port->bfad; + struct bfad_s *bfad = im_port->bfad; char fw_ver[BFA_VERSION_LEN]; bfa_get_adapter_fw_ver(&bfad->bfa, fw_ver); @@ -760,10 +809,10 @@ bfad_im_num_of_ports_show(struct device *dev, struct device_attribute *attr, struct Scsi_Host *shost = class_to_shost(dev); struct bfad_im_port_s *im_port = (struct bfad_im_port_s *) shost->hostdata[0]; - struct bfad_s *bfad = im_port->bfad; + struct bfad_s *bfad = im_port->bfad; return snprintf(buf, PAGE_SIZE, "%d\n", - bfa_get_nports(&bfad->bfa)); + bfa_get_nports(&bfad->bfa)); } static ssize_t @@ -788,10 +837,10 @@ bfad_im_num_of_discovered_ports_show(struct device *dev, rports = kzalloc(sizeof(wwn_t) * nrports , GFP_ATOMIC); if (rports == NULL) - return -ENOMEM; + return snprintf(buf, PAGE_SIZE, "Failed\n"); spin_lock_irqsave(&bfad->bfad_lock, flags); - bfa_fcs_port_get_rports(port->fcs_port, rports, &nrports); + bfa_fcs_lport_get_rports(port->fcs_port, rports, &nrports); spin_unlock_irqrestore(&bfad->bfad_lock, flags); kfree(rports); @@ -837,19 +886,19 @@ struct device_attribute *bfad_im_host_attrs[] = { }; struct device_attribute *bfad_im_vport_attrs[] = { - &dev_attr_serial_number, - &dev_attr_model, - &dev_attr_model_description, - &dev_attr_node_name, - &dev_attr_symbolic_name, - &dev_attr_hardware_version, - &dev_attr_driver_version, - &dev_attr_option_rom_version, - &dev_attr_firmware_version, - &dev_attr_number_of_ports, - &dev_attr_driver_name, - &dev_attr_number_of_discovered_ports, - NULL, + &dev_attr_serial_number, + &dev_attr_model, + &dev_attr_model_description, + &dev_attr_node_name, + &dev_attr_symbolic_name, + &dev_attr_hardware_version, + &dev_attr_driver_version, + &dev_attr_option_rom_version, + &dev_attr_firmware_version, + &dev_attr_number_of_ports, + &dev_attr_driver_name, + &dev_attr_number_of_discovered_ports, + NULL, }; diff --git a/drivers/scsi/bfa/bfad_attr.h b/drivers/scsi/bfa/bfad_attr.h deleted file mode 100644 index bf0102076508..000000000000 --- a/drivers/scsi/bfa/bfad_attr.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFAD_ATTR_H__ -#define __BFAD_ATTR_H__ - -/** - * FC_transport_template FC transport template - */ - -struct Scsi_Host* -bfad_os_dev_to_shost(struct scsi_target *starget); - -/** - * FC transport template entry, get SCSI target port ID. - */ -void -bfad_im_get_starget_port_id(struct scsi_target *starget); - -/** - * FC transport template entry, get SCSI target nwwn. - */ -void -bfad_im_get_starget_node_name(struct scsi_target *starget); - -/** - * FC transport template entry, get SCSI target pwwn. - */ -void -bfad_im_get_starget_port_name(struct scsi_target *starget); - -/** - * FC transport template entry, get SCSI host port ID. - */ -void -bfad_im_get_host_port_id(struct Scsi_Host *shost); - -struct Scsi_Host* -bfad_os_starget_to_shost(struct scsi_target *starget); - - -#endif /* __BFAD_ATTR_H__ */ diff --git a/drivers/scsi/bfa/bfad_debugfs.c b/drivers/scsi/bfa/bfad_debugfs.c index 4b82f12aad62..69ed1c4a903e 100644 --- a/drivers/scsi/bfa/bfad_debugfs.c +++ b/drivers/scsi/bfa/bfad_debugfs.c @@ -17,8 +17,8 @@ #include <linux/debugfs.h> -#include <bfad_drv.h> -#include <bfad_im.h> +#include "bfad_drv.h" +#include "bfad_im.h" /* * BFA debufs interface @@ -28,7 +28,7 @@ * mount -t debugfs none /sys/kernel/debug * * BFA Hierarchy: - * - bfa/host# + * - bfa/host# * where the host number corresponds to the one under /sys/class/scsi_host/host# * * Debugging service available per host: @@ -217,7 +217,7 @@ bfad_debugfs_read(struct file *file, char __user *buf, #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)) +#define BFA_REG_ADDRMSK(__bfa) ((u32)(BFA_REG_ADDRSZ(__bfa) - 1)) static bfa_status_t bfad_reg_offset_check(struct bfa_s *bfa, u32 offset, u32 len) @@ -359,7 +359,7 @@ bfad_debugfs_write_regwr(struct file *file, const char __user *buf, return -EINVAL; } - reg_addr = (uint32_t *) ((uint8_t *) bfa_ioc_bar0(ioc) + addr); + reg_addr = (u32 *) ((u8 *) 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); diff --git a/drivers/scsi/bfa/bfad_drv.h b/drivers/scsi/bfa/bfad_drv.h index 465b8b86ec9c..98420bbb4f3f 100644 --- a/drivers/scsi/bfa/bfad_drv.h +++ b/drivers/scsi/bfa/bfad_drv.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. * All rights reserved * www.brocade.com * @@ -28,30 +28,27 @@ #include "bfa_os_inc.h" -#include <bfa.h> -#include <bfa_svc.h> -#include <fcs/bfa_fcs.h> -#include <defs/bfa_defs_pci.h> -#include <defs/bfa_defs_port.h> -#include <defs/bfa_defs_rport.h> -#include <fcs/bfa_fcs_rport.h> -#include <defs/bfa_defs_vport.h> -#include <fcs/bfa_fcs_vport.h> - -#include <cs/bfa_plog.h> -#include "aen/bfa_aen.h" -#include <log/bfa_log_linux.h> - -#define BFAD_DRIVER_NAME "bfa" +#include "bfa_modules.h" +#include "bfa_fcs.h" +#include "bfa_defs_fcs.h" + +#include "bfa_plog.h" +#include "bfa_cs.h" + +#define BFAD_DRIVER_NAME "bfa" #ifdef BFA_DRIVER_VERSION #define BFAD_DRIVER_VERSION BFA_DRIVER_VERSION #else -#define BFAD_DRIVER_VERSION "2.2.2.1" +#define BFAD_DRIVER_VERSION "2.3.2.0" #endif - +#define BFAD_PROTO_NAME FCPI_NAME #define BFAD_IRQ_FLAGS IRQF_SHARED +#ifndef FC_PORTSPEED_8GBIT +#define FC_PORTSPEED_8GBIT 0x10 +#endif + /* * BFAD flags */ @@ -62,9 +59,9 @@ #define BFAD_HAL_START_DONE 0x00000010 #define BFAD_PORT_ONLINE 0x00000020 #define BFAD_RPORT_ONLINE 0x00000040 -#define BFAD_FCS_INIT_DONE 0x00000080 -#define BFAD_HAL_INIT_FAIL 0x00000100 -#define BFAD_FC4_PROBE_DONE 0x00000200 +#define BFAD_FCS_INIT_DONE 0x00000080 +#define BFAD_HAL_INIT_FAIL 0x00000100 +#define BFAD_FC4_PROBE_DONE 0x00000200 #define BFAD_PORT_DELETE 0x00000001 /* @@ -77,8 +74,8 @@ /* * BFAD configuration parameter default values */ -#define BFAD_LUN_QUEUE_DEPTH 32 -#define BFAD_IO_MAX_SGE SG_ALL +#define BFAD_LUN_QUEUE_DEPTH 32 +#define BFAD_IO_MAX_SGE SG_ALL #define bfad_isr_t irq_handler_t @@ -87,6 +84,16 @@ struct bfad_msix_s { struct bfad_s *bfad; struct msix_entry msix; + char name[32]; +}; + +/* + * Only append to the enums defined here to avoid any versioning + * needed between trace utility and driver version + */ +enum { + BFA_TRC_LDRV_BFAD = 1, + BFA_TRC_LDRV_IM = 2, }; enum bfad_port_pvb_type { @@ -101,17 +108,13 @@ enum bfad_port_pvb_type { */ struct bfad_port_s { struct list_head list_entry; - struct bfad_s *bfad; - struct bfa_fcs_port_s *fcs_port; - u32 roles; - s32 flags; - u32 supported_fc4s; - u8 ipfc_flags; + struct bfad_s *bfad; + struct bfa_fcs_lport_s *fcs_port; + u32 roles; + s32 flags; + u32 supported_fc4s; enum bfad_port_pvb_type pvb_type; struct bfad_im_port_s *im_port; /* IM specific data */ - struct bfad_tm_port_s *tm_port; /* TM specific data */ - struct bfad_ipfc_port_s *ipfc_port; /* IPFC specific data */ - /* port debugfs specific data */ struct dentry *port_debugfs_root; }; @@ -124,7 +127,6 @@ struct bfad_vport_s { struct bfa_fcs_vport_s fcs_vport; struct completion *comp_del; struct list_head list_entry; - struct bfa_port_cfg_s port_cfg; }; /* @@ -137,20 +139,35 @@ struct bfad_vf_s { }; struct bfad_cfg_param_s { - u32 rport_del_timeout; - u32 ioc_queue_depth; - u32 lun_queue_depth; - u32 io_max_sge; - u32 binding_method; + u32 rport_del_timeout; + u32 ioc_queue_depth; + u32 lun_queue_depth; + u32 io_max_sge; + 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 */ + + wwn_t wwn[BFA_FCS_MAX_LPORTS]; }; /* * BFAD (PCI function) data structure */ struct bfad_s { + bfa_sm_t sm; /* state machine */ struct list_head list_entry; - struct bfa_s bfa; - struct bfa_fcs_s bfa_fcs; + struct bfa_s bfa; + struct bfa_fcs_s bfa_fcs; struct pci_dev *pcidev; const char *pci_name; struct bfa_pcidev_s hal_pcidev; @@ -163,41 +180,41 @@ struct bfad_s { struct bfad_port_s pport; /* physical port of the BFAD */ struct bfa_meminfo_s meminfo; struct bfa_iocfc_cfg_s ioc_cfg; - u32 inst_no; /* BFAD instance number */ - u32 bfad_flags; + u32 inst_no; /* BFAD instance number */ + u32 bfad_flags; spinlock_t bfad_lock; struct task_struct *bfad_tsk; struct bfad_cfg_param_s cfg_data; struct bfad_msix_s msix_tab[MAX_MSIX_ENTRY]; - int nvec; - char adapter_name[BFA_ADAPTER_SYM_NAME_LEN]; - char port_name[BFA_ADAPTER_SYM_NAME_LEN]; + int nvec; + char adapter_name[BFA_ADAPTER_SYM_NAME_LEN]; + char port_name[BFA_ADAPTER_SYM_NAME_LEN]; struct timer_list hal_tmo; unsigned long hs_start; struct bfad_im_s *im; /* IM specific data */ - struct bfad_tm_s *tm; /* TM specific data */ - struct bfad_ipfc_s *ipfc; /* IPFC specific data */ - struct bfa_log_mod_s log_data; struct bfa_trc_mod_s *trcmod; - struct bfa_log_mod_s *logmod; - struct bfa_aen_s *aen; - struct bfa_aen_s aen_buf; - void *file_map[BFA_AEN_MAX_APP]; struct bfa_plog_s plog_buf; - int ref_count; - bfa_boolean_t ipfc_enabled; + int ref_count; + union bfad_tmp_buf tmp_buf; struct fc_host_statistics link_stats; - struct list_head pbc_pcfg_list; - atomic_t wq_reqcnt; + struct list_head pbc_vport_list; /* debugfs specific data */ char *regdata; u32 reglen; struct dentry *bfad_dentry_files[5]; }; -struct bfad_pcfg_s { - struct list_head list_entry; - struct bfa_port_cfg_s port_cfg; +/* BFAD state machine events */ +enum bfad_sm_event { + BFAD_E_CREATE = 1, + BFAD_E_KTHREAD_CREATE_FAILED = 2, + BFAD_E_INIT = 3, + BFAD_E_INIT_SUCCESS = 4, + BFAD_E_INIT_FAILED = 5, + BFAD_E_INTR_INIT_FAILED = 6, + BFAD_E_FCS_EXIT_COMP = 7, + BFAD_E_EXIT_COMP = 8, + BFAD_E_STOP = 9 }; /* @@ -208,30 +225,30 @@ struct bfad_rport_s { }; struct bfad_buf_info { - void *virt; + void *virt; dma_addr_t phys; - u32 size; + u32 size; }; struct bfad_fcxp { struct bfad_port_s *port; struct bfa_rport_s *bfa_rport; bfa_status_t req_status; - u16 tag; - u16 rsp_len; - u16 rsp_maxlen; - u8 use_ireqbuf; - u8 use_irspbuf; - u32 num_req_sgles; - u32 num_rsp_sgles; - struct fchs_s fchs; - void *reqbuf_info; - void *rspbuf_info; + u16 tag; + u16 rsp_len; + u16 rsp_maxlen; + u8 use_ireqbuf; + u8 use_irspbuf; + u32 num_req_sgles; + u32 num_rsp_sgles; + struct fchs_s fchs; + void *reqbuf_info; + void *rspbuf_info; struct bfa_sge_s *req_sge; struct bfa_sge_s *rsp_sge; fcxp_send_cb_t send_cbfn; - void *send_cbarg; - void *bfa_fcxp; + void *send_cbarg; + void *bfa_fcxp; struct completion comp; }; @@ -244,34 +261,48 @@ struct bfad_hal_comp { * Macro to obtain the immediate lower power * of two for the integer. */ -#define nextLowerInt(x) \ -do { \ - int j; \ - (*x)--; \ - for (j = 1; j < (sizeof(int) * 8); j <<= 1) \ - (*x) = (*x) | (*x) >> j; \ - (*x)++; \ - (*x) = (*x) >> 1; \ +#define nextLowerInt(x) \ +do { \ + int i; \ + (*x)--; \ + for (i = 1; i < (sizeof(int)*8); i <<= 1) \ + (*x) = (*x) | (*x) >> i; \ + (*x)++; \ + (*x) = (*x) >> 1; \ } while (0) -bfa_status_t bfad_vport_create(struct bfad_s *bfad, u16 vf_id, - struct bfa_port_cfg_s *port_cfg, struct device *dev); -bfa_status_t bfad_vf_create(struct bfad_s *bfad, u16 vf_id, - struct bfa_port_cfg_s *port_cfg); -bfa_status_t bfad_cfg_pport(struct bfad_s *bfad, enum bfa_port_role role); -bfa_status_t bfad_drv_init(struct bfad_s *bfad); -bfa_status_t bfad_start_ops(struct bfad_s *bfad); -void bfad_drv_start(struct bfad_s *bfad); -void bfad_uncfg_pport(struct bfad_s *bfad); -void bfad_drv_stop(struct bfad_s *bfad); -void bfad_remove_intr(struct bfad_s *bfad); -void bfad_hal_mem_release(struct bfad_s *bfad); -void bfad_hcb_comp(void *arg, bfa_status_t status); - -int bfad_setup_intr(struct bfad_s *bfad); -void bfad_remove_intr(struct bfad_s *bfad); +#define list_remove_head(list, entry, type, member) \ +do { \ + entry = NULL; \ + if (!list_empty(list)) { \ + entry = list_entry((list)->next, type, member); \ + list_del_init(&entry->member); \ + } \ +} while (0) +#define list_get_first(list, type, member) \ +((list_empty(list)) ? NULL : \ + list_entry((list)->next, type, member)) + +bfa_status_t bfad_vport_create(struct bfad_s *bfad, u16 vf_id, + struct bfa_lport_cfg_s *port_cfg, + struct device *dev); +bfa_status_t bfad_vf_create(struct bfad_s *bfad, u16 vf_id, + struct bfa_lport_cfg_s *port_cfg); +bfa_status_t bfad_cfg_pport(struct bfad_s *bfad, enum bfa_lport_role role); +bfa_status_t bfad_drv_init(struct bfad_s *bfad); +bfa_status_t bfad_start_ops(struct bfad_s *bfad); +void bfad_drv_start(struct bfad_s *bfad); +void bfad_uncfg_pport(struct bfad_s *bfad); +void bfad_stop(struct bfad_s *bfad); +void bfad_fcs_stop(struct bfad_s *bfad); +void bfad_remove_intr(struct bfad_s *bfad); +void bfad_hal_mem_release(struct bfad_s *bfad); +void bfad_hcb_comp(void *arg, bfa_status_t status); + +int bfad_setup_intr(struct bfad_s *bfad); +void bfad_remove_intr(struct bfad_s *bfad); void bfad_update_hal_cfg(struct bfa_iocfc_cfg_s *bfa_cfg); bfa_status_t bfad_hal_mem_alloc(struct bfad_s *bfad); void bfad_bfa_tmo(unsigned long data); @@ -280,9 +311,6 @@ int bfad_pci_init(struct pci_dev *pdev, struct bfad_s *bfad); void bfad_pci_uninit(struct pci_dev *pdev, struct bfad_s *bfad); void bfad_fcs_port_cfg(struct bfad_s *bfad); void bfad_drv_uninit(struct bfad_s *bfad); -void bfad_drv_log_level_set(struct bfad_s *bfad); -bfa_status_t bfad_fc4_module_init(void); -void bfad_fc4_module_exit(void); int bfad_worker(void *ptr); void bfad_debugfs_init(struct bfad_port_s *port); void bfad_debugfs_exit(struct bfad_port_s *port); @@ -294,10 +322,30 @@ int bfad_os_get_linkup_delay(struct bfad_s *bfad); int bfad_install_msix_handler(struct bfad_s *bfad); extern struct idr bfad_im_port_index; +extern struct pci_device_id bfad_id_table[]; extern struct list_head bfad_list; -extern int bfa_lun_queue_depth; -extern int bfad_supported_fc4s; -extern int bfa_linkup_delay; +extern char *os_name; +extern char *os_patch; +extern char *host_name; +extern int num_rports; +extern int num_ios; +extern int num_tms; +extern int num_fcxps; +extern int num_ufbufs; +extern int reqq_size; +extern int rspq_size; +extern int num_sgpgs; +extern int rport_del_timeout; +extern int bfa_lun_queue_depth; +extern int bfa_io_max_sge; +extern int log_level; +extern int ioc_auto_recover; +extern int bfa_linkup_delay; +extern int msix_disable_cb; +extern int msix_disable_ct; +extern int fdmi_enable; +extern int supported_fc4s; +extern int pcie_max_read_reqsz; extern int bfa_debugfs_enable; extern struct mutex bfad_mutex; diff --git a/drivers/scsi/bfa/bfad_fwimg.c b/drivers/scsi/bfa/bfad_fwimg.c deleted file mode 100644 index 1baca1a12085..000000000000 --- a/drivers/scsi/bfa/bfad_fwimg.c +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/** - * bfad_fwimg.c Linux driver PCI interface module. - */ -#include <bfa_os_inc.h> -#include <bfad_drv.h> -#include <bfad_im_compat.h> -#include <defs/bfa_defs_version.h> -#include <linux/errno.h> -#include <linux/sched.h> -#include <linux/init.h> -#include <linux/fs.h> -#include <asm/uaccess.h> -#include <asm/fcntl.h> -#include <linux/pci.h> -#include <linux/firmware.h> -#include <bfa_fwimg_priv.h> -#include <bfa.h> - -u32 bfi_image_ct_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_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, - u32 *bfi_image_size, char *fw_name) -{ - const struct firmware *fw; - - if (request_firmware(&fw, fw_name, &pdev->dev)) { - printk(KERN_ALERT "Can't locate firmware %s\n", fw_name); - goto error; - } - - *bfi_image = vmalloc(fw->size); - if (NULL == *bfi_image) { - printk(KERN_ALERT "Fail to allocate buffer for fw image " - "size=%x!\n", (u32) fw->size); - goto error; - } - - memcpy(*bfi_image, fw->data, fw->size); - *bfi_image_size = fw->size/sizeof(u32); - - return *bfi_image; - -error: - return NULL; -} - -u32 * -bfad_get_firmware_buf(struct pci_dev *pdev) -{ - if (pdev->device == BFA_PCI_DEVICE_ID_CT_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_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_fc_get_chunk(u32 off) -{ return (u32 *)(bfi_image_ct_fc + off); } - -u32 * -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.c b/drivers/scsi/bfa/bfad_im.c index 6ef87f6fcdbb..d950ee44016e 100644 --- a/drivers/scsi/bfa/bfad_im.c +++ b/drivers/scsi/bfa/bfad_im.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. * All rights reserved * www.brocade.com * @@ -19,12 +19,10 @@ * bfad_im.c Linux driver IM module. */ -#include <linux/slab.h> #include "bfad_drv.h" #include "bfad_im.h" -#include "bfad_trcmod.h" -#include "bfa_cb_ioim_macros.h" -#include <fcb/bfa_fcb_fcpim.h> +#include "bfa_cb_ioim.h" +#include "bfa_fcs.h" BFA_TRC_FILE(LDRV, IM); @@ -33,8 +31,10 @@ struct scsi_transport_template *bfad_im_scsi_transport_template; struct scsi_transport_template *bfad_im_scsi_vport_transport_template; static void bfad_im_itnim_work_handler(struct work_struct *work); static int bfad_im_queuecommand(struct scsi_cmnd *cmnd, - void (*done)(struct scsi_cmnd *)); + void (*done)(struct scsi_cmnd *)); static int bfad_im_slave_alloc(struct scsi_device *sdev); +static void bfad_im_fc_rport_add(struct bfad_im_port_s *im_port, + struct bfad_itnim_s *itnim); void bfa_cb_ioim_done(void *drv, struct bfad_ioim_s *dio, @@ -58,6 +58,7 @@ bfa_cb_ioim_done(void *drv, struct bfad_ioim_s *dio, sns_len = SCSI_SENSE_BUFFERSIZE; memcpy(cmnd->sense_buffer, sns_info, sns_len); } + if (residue > 0) { bfa_trc(bfad, residue); scsi_set_resid(cmnd, residue); @@ -76,7 +77,8 @@ bfa_cb_ioim_done(void *drv, struct bfad_ioim_s *dio, case BFI_IOIM_STS_TIMEDOUT: case BFI_IOIM_STS_PATHTOV: default: - cmnd->result = ScsiResult(DID_ERROR, 0); + host_status = DID_ERROR; + cmnd->result = ScsiResult(host_status, 0); } /* Unmap DMA, if host is NULL, it means a scsi passthru cmd */ @@ -162,11 +164,6 @@ bfa_cb_tskim_done(void *bfad, struct bfad_tskim_s *dtsk, wake_up(wq); } -void -bfa_cb_ioim_resfree(void *drv) -{ -} - /** * Scsi_Host_template SCSI host template */ @@ -179,15 +176,23 @@ bfad_im_info(struct Scsi_Host *shost) static char bfa_buf[256]; struct bfad_im_port_s *im_port = (struct bfad_im_port_s *) shost->hostdata[0]; - struct bfad_s *bfad = im_port->bfad; + struct bfad_s *bfad = im_port->bfad; + struct bfa_s *bfa = &bfad->bfa; + struct bfa_ioc_s *ioc = &bfa->ioc; char model[BFA_ADAPTER_MODEL_NAME_LEN]; - bfa_get_adapter_model(&bfad->bfa, model); + bfa_get_adapter_model(bfa, model); memset(bfa_buf, 0, sizeof(bfa_buf)); - snprintf(bfa_buf, sizeof(bfa_buf), - "Brocade FC/FCOE Adapter, " "model: %s hwpath: %s driver: %s", + if (ioc->ctdev) + snprintf(bfa_buf, sizeof(bfa_buf), + "Brocade FCOE Adapter, " "model: %s hwpath: %s driver: %s", + model, bfad->pci_name, BFAD_DRIVER_VERSION); + else + snprintf(bfa_buf, sizeof(bfa_buf), + "Brocade FC Adapter, " "model: %s hwpath: %s driver: %s", model, bfad->pci_name, BFAD_DRIVER_VERSION); + return bfa_buf; } @@ -221,9 +226,9 @@ bfad_im_abort_handler(struct scsi_cmnd *cmnd) } bfa_trc(bfad, hal_io->iotag); - bfa_log(bfad->logmod, BFA_LOG_LINUX_SCSI_ABORT, + BFA_LOG(KERN_INFO, bfad, log_level, "scsi%d: abort cmnd %p iotag %x\n", im_port->shost->host_no, cmnd, hal_io->iotag); - bfa_ioim_abort(hal_io); + (void) bfa_ioim_abort(hal_io); spin_unlock_irqrestore(&bfad->bfad_lock, flags); /* Need to wait until the command get aborted */ @@ -237,7 +242,8 @@ bfad_im_abort_handler(struct scsi_cmnd *cmnd) cmnd->scsi_done(cmnd); bfa_trc(bfad, hal_io->iotag); - bfa_log(bfad->logmod, BFA_LOG_LINUX_SCSI_ABORT_COMP, + BFA_LOG(KERN_INFO, bfad, log_level, + "scsi%d: complete abort 0x%p iotag 0x%x\n", im_port->shost->host_no, cmnd, hal_io->iotag); return SUCCESS; out: @@ -255,8 +261,8 @@ bfad_im_target_reset_send(struct bfad_s *bfad, struct scsi_cmnd *cmnd, tskim = bfa_tskim_alloc(&bfad->bfa, (struct bfad_tskim_s *) cmnd); if (!tskim) { - BFA_DEV_PRINTF(bfad, BFA_ERR, - "target reset, fail to allocate tskim\n"); + BFA_LOG(KERN_ERR, bfad, log_level, + "target reset, fail to allocate tskim\n"); rc = BFA_STATUS_FAILED; goto out; } @@ -306,7 +312,7 @@ bfad_im_reset_lun_handler(struct scsi_cmnd *cmnd) tskim = bfa_tskim_alloc(&bfad->bfa, (struct bfad_tskim_s *) cmnd); if (!tskim) { - BFA_DEV_PRINTF(bfad, BFA_ERR, + BFA_LOG(KERN_ERR, bfad, log_level, "LUN reset, fail to allocate tskim"); spin_unlock_irqrestore(&bfad->bfad_lock, flags); rc = FAILED; @@ -331,8 +337,8 @@ bfad_im_reset_lun_handler(struct scsi_cmnd *cmnd) task_status = cmnd->SCp.Status >> 1; if (task_status != BFI_TSKIM_STS_OK) { - BFA_DEV_PRINTF(bfad, BFA_ERR, "LUN reset failure, status: %d\n", - task_status); + BFA_LOG(KERN_ERR, bfad, log_level, + "LUN reset failure, status: %d\n", task_status); rc = FAILED; } @@ -375,7 +381,7 @@ bfad_im_reset_bus_handler(struct scsi_cmnd *cmnd) task_status = cmnd->SCp.Status >> 1; if (task_status != BFI_TSKIM_STS_OK) { - BFA_DEV_PRINTF(bfad, BFA_ERR, + BFA_LOG(KERN_ERR, bfad, log_level, "target reset failure," " status: %d\n", task_status); err_cnt++; @@ -438,6 +444,7 @@ bfa_fcb_itnim_free(struct bfad_s *bfad, struct bfad_itnim_s *itnim_drv) wwn_t wwpn; u32 fcid; char wwpn_str[32], fcid_str[16]; + struct bfad_im_s *im = itnim_drv->im; /* online to free state transtion should not happen */ bfa_assert(itnim_drv->state != ITNIM_STATE_ONLINE); @@ -454,10 +461,14 @@ bfa_fcb_itnim_free(struct bfad_s *bfad, struct bfad_itnim_s *itnim_drv) fcid = bfa_fcs_itnim_get_fcid(&itnim_drv->fcs_itnim); wwn2str(wwpn_str, wwpn); fcid2str(fcid_str, fcid); - bfa_log(bfad->logmod, BFA_LOG_LINUX_ITNIM_FREE, + BFA_LOG(KERN_INFO, bfad, log_level, + "ITNIM FREE scsi%d: FCID: %s WWPN: %s\n", port->im_port->shost->host_no, fcid_str, wwpn_str); - bfad_os_itnim_process(itnim_drv); + + /* ITNIM processing */ + if (itnim_drv->queue_work) + queue_work(im->drv_workq, &itnim_drv->itnim_work); } /** @@ -468,13 +479,17 @@ void bfa_fcb_itnim_online(struct bfad_itnim_s *itnim_drv) { struct bfad_port_s *port; + struct bfad_im_s *im = itnim_drv->im; itnim_drv->bfa_itnim = bfa_fcs_itnim_get_halitn(&itnim_drv->fcs_itnim); port = bfa_fcs_itnim_get_drvport(&itnim_drv->fcs_itnim); itnim_drv->state = ITNIM_STATE_ONLINE; itnim_drv->queue_work = 1; itnim_drv->im_port = port->im_port; - bfad_os_itnim_process(itnim_drv); + + /* ITNIM processing */ + if (itnim_drv->queue_work) + queue_work(im->drv_workq, &itnim_drv->itnim_work); } /** @@ -486,6 +501,7 @@ bfa_fcb_itnim_offline(struct bfad_itnim_s *itnim_drv) { struct bfad_port_s *port; struct bfad_s *bfad; + struct bfad_im_s *im = itnim_drv->im; port = bfa_fcs_itnim_get_drvport(&itnim_drv->fcs_itnim); bfad = port->bfad; @@ -497,16 +513,10 @@ bfa_fcb_itnim_offline(struct bfad_itnim_s *itnim_drv) itnim_drv->im_port = port->im_port; itnim_drv->state = ITNIM_STATE_OFFLINE_PENDING; itnim_drv->queue_work = 1; - bfad_os_itnim_process(itnim_drv); -} -/** - * BFA FCS itnim timeout callback. - * Context: Interrupt. bfad_lock is held - */ -void bfa_fcb_itnim_tov(struct bfad_itnim_s *itnim) -{ - itnim->state = ITNIM_STATE_TIMEOUT; + /* ITNIM processing */ + if (itnim_drv->queue_work) + queue_work(im->drv_workq, &itnim_drv->itnim_work); } /** @@ -514,7 +524,7 @@ void bfa_fcb_itnim_tov(struct bfad_itnim_s *itnim) */ int bfad_im_scsi_host_alloc(struct bfad_s *bfad, struct bfad_im_port_s *im_port, - struct device *dev) + struct device *dev) { int error = 1; @@ -580,7 +590,7 @@ void bfad_im_scsi_host_free(struct bfad_s *bfad, struct bfad_im_port_s *im_port) { bfa_trc(bfad, bfad->inst_no); - bfa_log(bfad->logmod, BFA_LOG_LINUX_SCSI_HOST_FREE, + BFA_LOG(KERN_INFO, bfad, log_level, "Free scsi%d\n", im_port->shost->host_no); fc_remove_host(im_port->shost); @@ -598,14 +608,11 @@ 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); } - } bfa_status_t @@ -636,11 +643,8 @@ bfad_im_port_delete(struct bfad_s *bfad, struct bfad_port_s *port) { struct bfad_im_port_s *im_port = port->im_port; - if (im_port->port->pvb_type != BFAD_PORT_PHYS_BASE) { - atomic_inc(&bfad->wq_reqcnt); - queue_work(bfad->im->drv_workq, + queue_work(bfad->im->drv_workq, &im_port->port_delete_work); - } } void @@ -663,16 +667,6 @@ bfad_im_port_clean(struct bfad_im_port_s *im_port) spin_unlock_irqrestore(&bfad->bfad_lock, flags); } -void -bfad_im_port_online(struct bfad_s *bfad, struct bfad_port_s *port) -{ -} - -void -bfad_im_port_offline(struct bfad_s *bfad, struct bfad_port_s *port) -{ -} - bfa_status_t bfad_im_probe(struct bfad_s *bfad) { @@ -701,27 +695,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; } } -/** - * 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) { @@ -751,6 +730,7 @@ void bfad_os_destroy_workq(struct bfad_im_s *im) { if (im && im->drv_workq) { + flush_workqueue(im->drv_workq); destroy_workqueue(im->drv_workq); im->drv_workq = NULL; } @@ -762,7 +742,7 @@ bfad_os_thread_workq(struct bfad_s *bfad) struct bfad_im_s *im = bfad->im; bfa_trc(bfad, 0); - snprintf(im->drv_workq_name, BFAD_KOBJ_NAME_LEN, "bfad_wq_%d", + snprintf(im->drv_workq_name, KOBJ_NAME_LEN, "bfad_wq_%d", bfad->inst_no); im->drv_workq = create_singlethread_workqueue(im->drv_workq_name); if (!im->drv_workq) @@ -832,12 +812,6 @@ struct scsi_host_template bfad_im_vport_template = { .max_sectors = 0xFFFF, }; -void -bfad_im_probe_post(struct bfad_im_s *im) -{ - flush_workqueue(im->drv_workq); -} - bfa_status_t bfad_im_module_init(void) { @@ -861,20 +835,12 @@ bfad_im_module_exit(void) { if (bfad_im_scsi_transport_template) fc_release_transport(bfad_im_scsi_transport_template); + if (bfad_im_scsi_vport_transport_template) fc_release_transport(bfad_im_scsi_vport_transport_template); } void -bfad_os_itnim_process(struct bfad_itnim_s *itnim_drv) -{ - struct bfad_im_s *im = itnim_drv->im; - - if (itnim_drv->queue_work) - queue_work(im->drv_workq, &itnim_drv->itnim_work); -} - -void bfad_os_ramp_up_qdepth(struct bfad_itnim_s *itnim, struct scsi_device *sdev) { struct scsi_device *tmp_sdev; @@ -916,9 +882,6 @@ bfad_os_handle_qfull(struct bfad_itnim_s *itnim, struct scsi_device *sdev) } } - - - struct bfad_itnim_s * bfad_os_get_itnim(struct bfad_im_port_s *im_port, int id) { @@ -949,44 +912,64 @@ bfad_im_slave_alloc(struct scsi_device *sdev) return 0; } +static u32 +bfad_im_supported_speeds(struct bfa_s *bfa) +{ + struct bfa_ioc_attr_s ioc_attr; + u32 supported_speed = 0; + + bfa_get_attr(bfa, &ioc_attr); + if (ioc_attr.adapter_attr.max_speed == BFA_PORT_SPEED_8GBPS) { + if (ioc_attr.adapter_attr.is_mezz) { + supported_speed |= FC_PORTSPEED_8GBIT | + FC_PORTSPEED_4GBIT | + FC_PORTSPEED_2GBIT | FC_PORTSPEED_1GBIT; + } else { + supported_speed |= FC_PORTSPEED_8GBIT | + FC_PORTSPEED_4GBIT | + FC_PORTSPEED_2GBIT; + } + } else if (ioc_attr.adapter_attr.max_speed == BFA_PORT_SPEED_4GBPS) { + supported_speed |= FC_PORTSPEED_4GBIT | FC_PORTSPEED_2GBIT | + FC_PORTSPEED_1GBIT; + } else if (ioc_attr.adapter_attr.max_speed == BFA_PORT_SPEED_10GBPS) { + supported_speed |= FC_PORTSPEED_10GBIT; + } + return supported_speed; +} + void bfad_os_fc_host_init(struct bfad_im_port_s *im_port) { struct Scsi_Host *host = im_port->shost; struct bfad_s *bfad = im_port->bfad; struct bfad_port_s *port = im_port->port; - struct bfa_pport_attr_s pattr; - char model[BFA_ADAPTER_MODEL_NAME_LEN]; - char fw_ver[BFA_VERSION_LEN]; + struct bfa_port_attr_s pattr; + struct bfa_lport_attr_s port_attr; + char symname[BFA_SYMNAME_MAXLEN]; fc_host_node_name(host) = - bfa_os_htonll((bfa_fcs_port_get_nwwn(port->fcs_port))); + bfa_os_htonll((bfa_fcs_lport_get_nwwn(port->fcs_port))); fc_host_port_name(host) = - bfa_os_htonll((bfa_fcs_port_get_pwwn(port->fcs_port))); + bfa_os_htonll((bfa_fcs_lport_get_pwwn(port->fcs_port))); fc_host_max_npiv_vports(host) = bfa_lps_get_max_vport(&bfad->bfa); fc_host_supported_classes(host) = FC_COS_CLASS3; memset(fc_host_supported_fc4s(host), 0, sizeof(fc_host_supported_fc4s(host))); - if (bfad_supported_fc4s & (BFA_PORT_ROLE_FCP_IM | BFA_PORT_ROLE_FCP_TM)) + if (supported_fc4s & BFA_LPORT_ROLE_FCP_IM) /* For FCP type 0x08 */ fc_host_supported_fc4s(host)[2] = 1; - if (bfad_supported_fc4s & BFA_PORT_ROLE_FCP_IPFC) - /* For LLC/SNAP type 0x05 */ - fc_host_supported_fc4s(host)[3] = 0x20; /* For fibre channel services type 0x20 */ fc_host_supported_fc4s(host)[7] = 1; - bfa_get_adapter_model(&bfad->bfa, model); - bfa_get_adapter_fw_ver(&bfad->bfa, fw_ver); - sprintf(fc_host_symbolic_name(host), "Brocade %s FV%s DV%s", - model, fw_ver, BFAD_DRIVER_VERSION); + bfa_fcs_lport_get_attr(&bfad->bfa_fcs.fabric.bport, &port_attr); + strncpy(symname, port_attr.port_cfg.sym_name.symname, + BFA_SYMNAME_MAXLEN); + sprintf(fc_host_symbolic_name(host), "%s", symname); - fc_host_supported_speeds(host) = 0; - fc_host_supported_speeds(host) |= - FC_PORTSPEED_8GBIT | FC_PORTSPEED_4GBIT | FC_PORTSPEED_2GBIT | - FC_PORTSPEED_1GBIT; + fc_host_supported_speeds(host) = bfad_im_supported_speeds(&bfad->bfa); bfa_fcport_get_attr(&bfad->bfa, &pattr); fc_host_maxframe_size(host) = pattr.pport_cfg.maxfrsize; @@ -1065,7 +1048,9 @@ bfad_im_itnim_work_handler(struct work_struct *work) fcid2str(fcid_str, fcid); list_add_tail(&itnim->list_entry, &im_port->itnim_mapped_list); - bfa_log(bfad->logmod, BFA_LOG_LINUX_ITNIM_ONLINE, + BFA_LOG(KERN_INFO, bfad, log_level, + "ITNIM ONLINE Target: %d:0:%d " + "FCID: %s WWPN: %s\n", im_port->shost->host_no, itnim->scsi_tgt_id, fcid_str, wwpn_str); @@ -1096,7 +1081,9 @@ bfad_im_itnim_work_handler(struct work_struct *work) wwn2str(wwpn_str, wwpn); fcid2str(fcid_str, fcid); list_del(&itnim->list_entry); - bfa_log(bfad->logmod, BFA_LOG_LINUX_ITNIM_OFFLINE, + BFA_LOG(KERN_INFO, bfad, log_level, + "ITNIM OFFLINE Target: %d:0:%d " + "FCID: %s WWPN: %s\n", im_port->shost->host_no, itnim->scsi_tgt_id, fcid_str, wwpn_str); @@ -1142,7 +1129,7 @@ bfad_im_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) struct bfa_ioim_s *hal_io; unsigned long flags; int rc; - s16 sg_cnt = 0; + int sg_cnt = 0; struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device)); rc = fc_remote_port_chkready(rport); @@ -1153,7 +1140,6 @@ bfad_im_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) } sg_cnt = scsi_dma_map(cmnd); - if (sg_cnt < 0) return SCSI_MLQUEUE_HOST_BUSY; @@ -1168,6 +1154,7 @@ bfad_im_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) goto out_fail_cmd; } + itnim = itnim_data->itnim; if (!itnim) { cmnd->result = ScsiResult(DID_IMM_RETRY, 0); @@ -1206,47 +1193,49 @@ bfad_os_rport_online_wait(struct bfad_s *bfad) int rport_delay = 10; for (i = 0; !(bfad->bfad_flags & BFAD_PORT_ONLINE) - && i < bfa_linkup_delay; i++) - schedule_timeout_uninterruptible(HZ); + && i < bfa_linkup_delay; i++) { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ); + } if (bfad->bfad_flags & BFAD_PORT_ONLINE) { rport_delay = rport_delay < bfa_linkup_delay ? - rport_delay : bfa_linkup_delay; + rport_delay : bfa_linkup_delay; for (i = 0; !(bfad->bfad_flags & BFAD_RPORT_ONLINE) - && i < rport_delay; i++) - schedule_timeout_uninterruptible(HZ); + && i < rport_delay; i++) { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ); + } - if (rport_delay > 0 && (bfad->bfad_flags & BFAD_RPORT_ONLINE)) - schedule_timeout_uninterruptible(rport_delay * HZ); + if (rport_delay > 0 && (bfad->bfad_flags & BFAD_RPORT_ONLINE)) { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(rport_delay * HZ); + } } } int bfad_os_get_linkup_delay(struct bfad_s *bfad) { - - u8 nwwns = 0; - wwn_t wwns[BFA_PREBOOT_BOOTLUN_MAX]; - int ldelay; + u8 nwwns = 0; + wwn_t wwns[BFA_PREBOOT_BOOTLUN_MAX]; + int linkup_delay; /* * Querying for the boot target port wwns * -- read from boot information in flash. - * If nwwns > 0 => boot over SAN and set bfa_linkup_delay = 30 - * else => local boot machine set bfa_linkup_delay = 10 + * If nwwns > 0 => boot over SAN and set linkup_delay = 30 + * else => local boot machine set linkup_delay = 0 */ bfa_iocfc_get_bootwwns(&bfad->bfa, &nwwns, wwns); - if (nwwns > 0) { - /* If boot over SAN; linkup_delay = 30sec */ - ldelay = 30; - } else { - /* If local boot; linkup_delay = 10sec */ - ldelay = 0; - } + if (nwwns > 0) + /* If Boot over SAN set linkup_delay = 30sec */ + linkup_delay = 30; + else + /* If local boot; no linkup_delay */ + linkup_delay = 0; - return ldelay; + return linkup_delay; } - - diff --git a/drivers/scsi/bfa/bfad_im.h b/drivers/scsi/bfa/bfad_im.h index 973cab4d09c7..b038c0e08921 100644 --- a/drivers/scsi/bfa/bfad_im.h +++ b/drivers/scsi/bfa/bfad_im.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. * All rights reserved * www.brocade.com * @@ -18,20 +18,20 @@ #ifndef __BFAD_IM_H__ #define __BFAD_IM_H__ -#include "fcs/bfa_fcs_fcpim.h" -#include "bfad_im_compat.h" +#include "bfa_fcs.h" #define FCPI_NAME " fcpim" +#ifndef KOBJ_NAME_LEN +#define KOBJ_NAME_LEN 20 +#endif + bfa_status_t bfad_im_module_init(void); void bfad_im_module_exit(void); bfa_status_t bfad_im_probe(struct bfad_s *bfad); void bfad_im_probe_undo(struct bfad_s *bfad); -void bfad_im_probe_post(struct bfad_im_s *im); bfa_status_t bfad_im_port_new(struct bfad_s *bfad, struct bfad_port_s *port); void bfad_im_port_delete(struct bfad_s *bfad, struct bfad_port_s *port); -void bfad_im_port_online(struct bfad_s *bfad, struct bfad_port_s *port); -void bfad_im_port_offline(struct bfad_s *bfad, struct bfad_port_s *port); void bfad_im_port_clean(struct bfad_im_port_s *im_port); int bfad_im_scsi_host_alloc(struct bfad_s *bfad, struct bfad_im_port_s *im_port, struct device *dev); @@ -44,14 +44,10 @@ void bfad_im_scsi_host_free(struct bfad_s *bfad, #define BFAD_LUN_RESET_TMO 60 #define ScsiResult(host_code, scsi_code) (((host_code) << 16) | scsi_code) #define BFA_QUEUE_FULL_RAMP_UP_TIME 120 -#define BFAD_KOBJ_NAME_LEN 20 /* * itnim flags */ -#define ITNIM_MAPPED 0x00000001 - -#define SCSI_TASK_MGMT 0x00000001 #define IO_DONE_BIT 0 struct bfad_itnim_data_s { @@ -64,7 +60,7 @@ struct bfad_im_port_s { struct work_struct port_delete_work; int idr_id; u16 cur_scsi_id; - u16 flags; + u16 flags; struct list_head binding_list; struct Scsi_Host *shost; struct list_head itnim_mapped_list; @@ -118,14 +114,13 @@ struct bfad_fcp_binding { struct bfad_im_s { struct bfad_s *bfad; struct workqueue_struct *drv_workq; - char drv_workq_name[BFAD_KOBJ_NAME_LEN]; + char drv_workq_name[KOBJ_NAME_LEN]; }; struct Scsi_Host *bfad_os_scsi_host_alloc(struct bfad_im_port_s *im_port, struct bfad_s *); bfa_status_t bfad_os_thread_workq(struct bfad_s *bfad); void bfad_os_destroy_workq(struct bfad_im_s *im); -void bfad_os_itnim_process(struct bfad_itnim_s *itnim_drv); void bfad_os_fc_host_init(struct bfad_im_port_s *im_port); void bfad_os_scsi_host_free(struct bfad_s *bfad, struct bfad_im_port_s *im_port); @@ -133,11 +128,6 @@ void bfad_os_ramp_up_qdepth(struct bfad_itnim_s *itnim, struct scsi_device *sdev); void bfad_os_handle_qfull(struct bfad_itnim_s *itnim, struct scsi_device *sdev); struct bfad_itnim_s *bfad_os_get_itnim(struct bfad_im_port_s *im_port, int id); -int bfad_os_scsi_add_host(struct Scsi_Host *shost, - struct bfad_im_port_s *im_port, struct bfad_s *bfad); - -void bfad_im_itnim_unmap(struct bfad_im_port_s *im_port, - struct bfad_itnim_s *itnim); extern struct scsi_host_template bfad_im_scsi_host_template; extern struct scsi_host_template bfad_im_vport_template; @@ -146,4 +136,34 @@ extern struct fc_function_template bfad_im_vport_fc_function_template; extern struct scsi_transport_template *bfad_im_scsi_transport_template; extern struct scsi_transport_template *bfad_im_scsi_vport_transport_template; +extern struct device_attribute *bfad_im_host_attrs[]; +extern struct device_attribute *bfad_im_vport_attrs[]; + +irqreturn_t bfad_intx(int irq, void *dev_id); + +/* Firmware releated */ +#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" + +u32 *bfad_get_firmware_buf(struct pci_dev *pdev); +u32 *bfad_read_firmware(struct pci_dev *pdev, u32 **bfi_image, + u32 *bfi_image_size, char *fw_name); + +static inline u32 * +bfad_load_fwimg(struct pci_dev *pdev) +{ + return bfad_get_firmware_buf(pdev); +} + +static inline void +bfad_free_fwimg(void) +{ + if (bfi_image_ct_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_im_compat.h b/drivers/scsi/bfa/bfad_im_compat.h deleted file mode 100644 index 0a122abbbe89..000000000000 --- a/drivers/scsi/bfa/bfad_im_compat.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFAD_IM_COMPAT_H__ -#define __BFAD_IM_COMPAT_H__ - -extern struct device_attribute *bfad_im_host_attrs[]; -extern struct device_attribute *bfad_im_vport_attrs[]; - -u32 *bfad_get_firmware_buf(struct pci_dev *pdev); -u32 *bfad_read_firmware(struct pci_dev *pdev, u32 **bfi_image, - u32 *bfi_image_size, char *fw_name); - -static inline u32 * -bfad_load_fwimg(struct pci_dev *pdev) -{ - return bfad_get_firmware_buf(pdev); -} - -static inline void -bfad_free_fwimg(void) -{ - if (bfi_image_ct_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 deleted file mode 100644 index 56a351584f0c..000000000000 --- a/drivers/scsi/bfa/bfad_intr.c +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#include "bfad_drv.h" -#include "bfad_trcmod.h" - -BFA_TRC_FILE(LDRV, INTR); - -/** - * bfa_isr BFA driver interrupt functions - */ -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. - */ -static irqreturn_t -bfad_intx(int irq, void *dev_id) -{ - struct bfad_s *bfad = dev_id; - struct list_head doneq; - unsigned long flags; - bfa_boolean_t rc; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - rc = bfa_intx(&bfad->bfa); - if (!rc) { - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - return IRQ_NONE; - } - - bfa_comp_deq(&bfad->bfa, &doneq); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - if (!list_empty(&doneq)) { - bfa_comp_process(&bfad->bfa, &doneq); - - spin_lock_irqsave(&bfad->bfad_lock, flags); - bfa_comp_free(&bfad->bfa, &doneq); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - bfa_trc_fp(bfad, irq); - } - - return IRQ_HANDLED; - -} - -static irqreturn_t -bfad_msix(int irq, void *dev_id) -{ - struct bfad_msix_s *vec = dev_id; - struct bfad_s *bfad = vec->bfad; - struct list_head doneq; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - - bfa_msix(&bfad->bfa, vec->msix.entry); - bfa_comp_deq(&bfad->bfa, &doneq); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - if (!list_empty(&doneq)) { - bfa_comp_process(&bfad->bfa, &doneq); - - spin_lock_irqsave(&bfad->bfad_lock, flags); - bfa_comp_free(&bfad->bfa, &doneq); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - } - - return IRQ_HANDLED; -} - -/** - * Initialize the MSIX entry table. - */ -static void -bfad_init_msix_entry(struct bfad_s *bfad, struct msix_entry *msix_entries, - int mask, int max_bit) -{ - int i; - int match = 0x00000001; - - for (i = 0, bfad->nvec = 0; i < MAX_MSIX_ENTRY; i++) { - if (mask & match) { - bfad->msix_tab[bfad->nvec].msix.entry = i; - bfad->msix_tab[bfad->nvec].bfad = bfad; - msix_entries[bfad->nvec].entry = i; - bfad->nvec++; - } - - match <<= 1; - } - -} - -int -bfad_install_msix_handler(struct bfad_s *bfad) -{ - int i, error = 0; - - for (i = 0; i < bfad->nvec; i++) { - error = request_irq(bfad->msix_tab[i].msix.vector, - (irq_handler_t) bfad_msix, 0, - BFAD_DRIVER_NAME, &bfad->msix_tab[i]); - bfa_trc(bfad, i); - bfa_trc(bfad, bfad->msix_tab[i].msix.vector); - if (error) { - int j; - - for (j = 0; j < i; j++) - free_irq(bfad->msix_tab[j].msix.vector, - &bfad->msix_tab[j]); - - return 1; - } - } - - return 0; -} - -/** - * Setup MSIX based interrupt. - */ -int -bfad_setup_intr(struct bfad_s *bfad) -{ - int error = 0; - u32 mask = 0, i, num_bit = 0, max_bit = 0; - struct msix_entry msix_entries[MAX_MSIX_ENTRY]; - struct pci_dev *pdev = bfad->pcidev; - - /* Call BFA to get the msix map for this PCI function. */ - bfa_msix_getvecs(&bfad->bfa, &mask, &num_bit, &max_bit); - - /* Set up the msix entry table */ - bfad_init_msix_entry(bfad, msix_entries, mask, max_bit); - - if ((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) { - /* - * Only error number of vector is available. - * We don't have a mechanism to map multiple - * interrupts into one vector, so even if we - * can try to request less vectors, we don't - * know how to associate interrupt events to - * vectors. Linux doesn't dupicate vectors - * in the MSIX table for this case. - */ - - printk(KERN_WARNING "bfad%d: " - "pci_enable_msix failed (%d)," - " use line based.\n", bfad->inst_no, error); - - goto line_based; - } - - /* Save the vectors */ - for (i = 0; i < bfad->nvec; i++) { - bfa_trc(bfad, msix_entries[i].vector); - bfad->msix_tab[i].msix.vector = msix_entries[i].vector; - } - - bfa_msix_init(&bfad->bfa, bfad->nvec); - - bfad->bfad_flags |= BFAD_MSIX_ON; - - return error; - } - -line_based: - error = 0; - if (request_irq - (bfad->pcidev->irq, (irq_handler_t) bfad_intx, BFAD_IRQ_FLAGS, - BFAD_DRIVER_NAME, bfad) != 0) { - /* Enable interrupt handler failed */ - return 1; - } - - return error; -} - -void -bfad_remove_intr(struct bfad_s *bfad) -{ - int i; - - if (bfad->bfad_flags & BFAD_MSIX_ON) { - for (i = 0; i < bfad->nvec; i++) - free_irq(bfad->msix_tab[i].msix.vector, - &bfad->msix_tab[i]); - - pci_disable_msix(bfad->pcidev); - bfad->bfad_flags &= ~BFAD_MSIX_ON; - } else { - free_irq(bfad->pcidev->irq, bfad); - } -} - - diff --git a/drivers/scsi/bfa/bfad_ipfc.h b/drivers/scsi/bfa/bfad_ipfc.h deleted file mode 100644 index 718bc5227671..000000000000 --- a/drivers/scsi/bfa/bfad_ipfc.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ -#ifndef __BFA_DRV_IPFC_H__ -#define __BFA_DRV_IPFC_H__ - - -#define IPFC_NAME "" - -#define bfad_ipfc_module_init(x) do {} while (0) -#define bfad_ipfc_module_exit(x) do {} while (0) -#define bfad_ipfc_probe(x) do {} while (0) -#define bfad_ipfc_probe_undo(x) do {} while (0) -#define bfad_ipfc_port_config(x, y) BFA_STATUS_OK -#define bfad_ipfc_port_unconfig(x, y) do {} while (0) - -#define bfad_ipfc_probe_post(x) do {} while (0) -#define bfad_ipfc_port_new(x, y, z) BFA_STATUS_OK -#define bfad_ipfc_port_delete(x, y) do {} while (0) -#define bfad_ipfc_port_online(x, y) do {} while (0) -#define bfad_ipfc_port_offline(x, y) do {} while (0) - -#define bfad_ip_get_attr(x) BFA_STATUS_FAILED -#define bfad_ip_reset_drv_stats(x) BFA_STATUS_FAILED -#define bfad_ip_get_drv_stats(x, y) BFA_STATUS_FAILED -#define bfad_ip_enable_ipfc(x, y, z) BFA_STATUS_FAILED - - -#endif diff --git a/drivers/scsi/bfa/bfad_os.c b/drivers/scsi/bfa/bfad_os.c deleted file mode 100644 index faf47b4f1a38..000000000000 --- a/drivers/scsi/bfa/bfad_os.c +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/** - * bfad_os.c Linux driver OS specific calls. - */ - -#include "bfa_os_inc.h" -#include "bfad_drv.h" - -void -bfa_os_gettimeofday(struct bfa_timeval_s *tv) -{ - struct timeval tmp_tv; - - do_gettimeofday(&tmp_tv); - tv->tv_sec = (u32) tmp_tv.tv_sec; - tv->tv_usec = (u32) tmp_tv.tv_usec; -} - -void -bfa_os_printf(struct bfa_log_mod_s *log_mod, u32 msg_id, - const char *fmt, ...) -{ - va_list ap; - #define BFA_STRING_256 256 - char tmp[BFA_STRING_256]; - - va_start(ap, fmt); - vsprintf(tmp, fmt, ap); - va_end(ap); - - printk(tmp); -} - - diff --git a/drivers/scsi/bfa/bfad_tm.h b/drivers/scsi/bfa/bfad_tm.h deleted file mode 100644 index 4901b1b7df02..000000000000 --- a/drivers/scsi/bfa/bfad_tm.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/* - * Brocade Fibre Channel HBA Linux Target Mode Driver - */ - -/** - * tm/dummy/bfad_tm.h BFA callback dummy header file for BFA Linux target mode PCI interface module. - */ - -#ifndef __BFAD_TM_H__ -#define __BFAD_TM_H__ - -#include <defs/bfa_defs_status.h> - -#define FCPT_NAME "" - -/* - * Called from base Linux driver on (De)Init events - */ - -/* attach tgt template with scst */ -#define bfad_tm_module_init() do {} while (0) - -/* detach/release tgt template */ -#define bfad_tm_module_exit() do {} while (0) - -#define bfad_tm_probe(x) do {} while (0) -#define bfad_tm_probe_undo(x) do {} while (0) -#define bfad_tm_probe_post(x) do {} while (0) - -/* - * Called by base Linux driver but triggered by BFA FCS on config events - */ -#define bfad_tm_port_new(x, y) BFA_STATUS_OK -#define bfad_tm_port_delete(x, y) do {} while (0) - -/* - * Called by base Linux driver but triggered by BFA FCS on PLOGI/O events - */ -#define bfad_tm_port_online(x, y) do {} while (0) -#define bfad_tm_port_offline(x, y) do {} while (0) - -#endif diff --git a/drivers/scsi/bfa/bfad_trcmod.h b/drivers/scsi/bfa/bfad_trcmod.h deleted file mode 100644 index 2827b2acd041..000000000000 --- a/drivers/scsi/bfa/bfad_trcmod.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/** - * bfad_trcmod.h Linux driver trace modules - */ - - -#ifndef __BFAD_TRCMOD_H__ -#define __BFAD_TRCMOD_H__ - -#include <cs/bfa_trc.h> - -/* - * !!! Only append to the enums defined here to avoid any versioning - * !!! needed between trace utility and driver version - */ -enum { - /* 2.6 Driver */ - BFA_TRC_LDRV_BFAD = 1, - BFA_TRC_LDRV_BFAD_2_6 = 2, - BFA_TRC_LDRV_BFAD_2_6_9 = 3, - BFA_TRC_LDRV_BFAD_2_6_10 = 4, - BFA_TRC_LDRV_INTR = 5, - BFA_TRC_LDRV_IOCTL = 6, - BFA_TRC_LDRV_OS = 7, - BFA_TRC_LDRV_IM = 8, - BFA_TRC_LDRV_IM_2_6 = 9, - BFA_TRC_LDRV_IM_2_6_9 = 10, - BFA_TRC_LDRV_IM_2_6_10 = 11, - BFA_TRC_LDRV_TM = 12, - BFA_TRC_LDRV_IPFC = 13, - BFA_TRC_LDRV_IM_2_4 = 14, - BFA_TRC_LDRV_IM_VMW = 15, - BFA_TRC_LDRV_IM_LT_2_6_10 = 16, -}; - -#endif /* __BFAD_TRCMOD_H__ */ diff --git a/drivers/scsi/bfa/bfi.h b/drivers/scsi/bfa/bfi.h new file mode 100644 index 000000000000..85f2224a5733 --- /dev/null +++ b/drivers/scsi/bfa/bfi.h @@ -0,0 +1,579 @@ +/* + * 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_H__ +#define __BFI_H__ + +#include "bfa_defs.h" +#include "bfa_defs_svc.h" + +#pragma pack(1) + +/** + * BFI FW image type + */ +#define BFI_FLASH_CHUNK_SZ 256 /* Flash chunk size */ +#define BFI_FLASH_CHUNK_SZ_WORDS (BFI_FLASH_CHUNK_SZ/sizeof(u32)) +enum { + BFI_IMAGE_CB_FC, + BFI_IMAGE_CT_FC, + BFI_IMAGE_CT_CNA, + BFI_IMAGE_MAX, +}; + +/** + * Msg header common to all msgs + */ +struct bfi_mhdr_s { + u8 msg_class; /* @ref bfi_mclass_t */ + u8 msg_id; /* msg opcode with in the class */ + union { + struct { + u8 rsvd; + u8 lpu_id; /* msg destination */ + } h2i; + u16 i2htok; /* token in msgs to host */ + } mtag; +}; + +#define bfi_h2i_set(_mh, _mc, _op, _lpuid) do { \ + (_mh).msg_class = (_mc); \ + (_mh).msg_id = (_op); \ + (_mh).mtag.h2i.lpu_id = (_lpuid); \ +} while (0) + +#define bfi_i2h_set(_mh, _mc, _op, _i2htok) do { \ + (_mh).msg_class = (_mc); \ + (_mh).msg_id = (_op); \ + (_mh).mtag.i2htok = (_i2htok); \ +} while (0) + +/* + * Message opcodes: 0-127 to firmware, 128-255 to host + */ +#define BFI_I2H_OPCODE_BASE 128 +#define BFA_I2HM(_x) ((_x) + BFI_I2H_OPCODE_BASE) + +/** + **************************************************************************** + * + * Scatter Gather Element and Page definition + * + **************************************************************************** + */ + +#define BFI_SGE_INLINE 1 +#define BFI_SGE_INLINE_MAX (BFI_SGE_INLINE + 1) + +/** + * SG Flags + */ +enum { + BFI_SGE_DATA = 0, /* data address, not last */ + BFI_SGE_DATA_CPL = 1, /* data addr, last in current page */ + BFI_SGE_DATA_LAST = 3, /* data address, last */ + BFI_SGE_LINK = 2, /* link address */ + BFI_SGE_PGDLEN = 2, /* cumulative data length for page */ +}; + +/** + * DMA addresses + */ +union bfi_addr_u { + struct { + u32 addr_lo; + u32 addr_hi; + } a32; +}; + +/** + * Scatter Gather Element + */ +struct bfi_sge_s { +#ifdef __BIGENDIAN + u32 flags:2, + rsvd:2, + sg_len:28; +#else + u32 sg_len:28, + rsvd:2, + flags:2; +#endif + union bfi_addr_u sga; +}; + +/** + * Scatter Gather Page + */ +#define BFI_SGPG_DATA_SGES 7 +#define BFI_SGPG_SGES_MAX (BFI_SGPG_DATA_SGES + 1) +#define BFI_SGPG_RSVD_WD_LEN 8 +struct bfi_sgpg_s { + struct bfi_sge_s sges[BFI_SGPG_SGES_MAX]; + u32 rsvd[BFI_SGPG_RSVD_WD_LEN]; +}; + +/* + * Large Message structure - 128 Bytes size Msgs + */ +#define BFI_LMSG_SZ 128 +#define BFI_LMSG_PL_WSZ \ + ((BFI_LMSG_SZ - sizeof(struct bfi_mhdr_s)) / 4) + +struct bfi_msg_s { + struct bfi_mhdr_s mhdr; + u32 pl[BFI_LMSG_PL_WSZ]; +}; + +/** + * Mailbox message structure + */ +#define BFI_MBMSG_SZ 7 +struct bfi_mbmsg_s { + struct bfi_mhdr_s mh; + u32 pl[BFI_MBMSG_SZ]; +}; + +/** + * Message Classes + */ +enum bfi_mclass { + BFI_MC_IOC = 1, /* IO Controller (IOC) */ + BFI_MC_FCPORT = 5, /* FC port */ + BFI_MC_IOCFC = 6, /* FC - IO Controller (IOC) */ + BFI_MC_LL = 7, /* Link Layer */ + BFI_MC_UF = 8, /* Unsolicited frame receive */ + BFI_MC_FCXP = 9, /* FC Transport */ + BFI_MC_LPS = 10, /* lport fc login services */ + BFI_MC_RPORT = 11, /* Remote port */ + BFI_MC_ITNIM = 12, /* I-T nexus (Initiator mode) */ + BFI_MC_IOIM_READ = 13, /* read IO (Initiator mode) */ + BFI_MC_IOIM_WRITE = 14, /* write IO (Initiator mode) */ + BFI_MC_IOIM_IO = 15, /* IO (Initiator mode) */ + BFI_MC_IOIM = 16, /* IO (Initiator mode) */ + BFI_MC_IOIM_IOCOM = 17, /* good IO completion */ + BFI_MC_TSKIM = 18, /* Initiator Task management */ + BFI_MC_PORT = 21, /* Physical port */ + BFI_MC_MAX = 32 +}; + +#define BFI_IOC_MAX_CQS 4 +#define BFI_IOC_MAX_CQS_ASIC 8 +#define BFI_IOC_MSGLEN_MAX 32 /* 32 bytes */ + +#define BFI_BOOT_TYPE_OFF 8 +#define BFI_BOOT_LOADER_OFF 12 + +#define BFI_BOOT_TYPE_NORMAL 0 +#define BFI_BOOT_TYPE_FLASH 1 +#define BFI_BOOT_TYPE_MEMTEST 2 + +#define BFI_BOOT_LOADER_OS 0 +#define BFI_BOOT_LOADER_BIOS 1 +#define BFI_BOOT_LOADER_UEFI 2 + +/** + *---------------------------------------------------------------------- + * IOC + *---------------------------------------------------------------------- + */ + +enum bfi_ioc_h2i_msgs { + BFI_IOC_H2I_ENABLE_REQ = 1, + BFI_IOC_H2I_DISABLE_REQ = 2, + BFI_IOC_H2I_GETATTR_REQ = 3, + BFI_IOC_H2I_DBG_SYNC = 4, + BFI_IOC_H2I_DBG_DUMP = 5, +}; + +enum bfi_ioc_i2h_msgs { + BFI_IOC_I2H_ENABLE_REPLY = BFA_I2HM(1), + BFI_IOC_I2H_DISABLE_REPLY = BFA_I2HM(2), + BFI_IOC_I2H_GETATTR_REPLY = BFA_I2HM(3), + BFI_IOC_I2H_READY_EVENT = BFA_I2HM(4), + BFI_IOC_I2H_HBEAT = BFA_I2HM(5), +}; + +/** + * BFI_IOC_H2I_GETATTR_REQ message + */ +struct bfi_ioc_getattr_req_s { + struct bfi_mhdr_s mh; + union bfi_addr_u attr_addr; +}; + +struct bfi_ioc_attr_s { + wwn_t mfg_pwwn; /* Mfg port wwn */ + wwn_t mfg_nwwn; /* Mfg node wwn */ + mac_t mfg_mac; /* Mfg mac */ + u16 rsvd_a; + wwn_t pwwn; + wwn_t nwwn; + mac_t mac; /* PBC or Mfg mac */ + u16 rsvd_b; + mac_t fcoe_mac; + u16 rsvd_c; + char brcd_serialnum[STRSZ(BFA_MFG_SERIALNUM_SIZE)]; + u8 pcie_gen; + u8 pcie_lanes_orig; + u8 pcie_lanes; + u8 rx_bbcredit; /* receive buffer credits */ + u32 adapter_prop; /* adapter properties */ + u16 maxfrsize; /* max receive frame size */ + char asic_rev; + u8 rsvd_d; + char fw_version[BFA_VERSION_LEN]; + char optrom_version[BFA_VERSION_LEN]; + struct bfa_mfg_vpd_s vpd; + u32 card_type; /* card type */ +}; + +/** + * BFI_IOC_I2H_GETATTR_REPLY message + */ +struct bfi_ioc_getattr_reply_s { + struct bfi_mhdr_s mh; /* Common msg header */ + u8 status; /* cfg reply status */ + u8 rsvd[3]; +}; + +/** + * Firmware memory page offsets + */ +#define BFI_IOC_SMEM_PG0_CB (0x40) +#define BFI_IOC_SMEM_PG0_CT (0x180) + +/** + * Firmware statistic offset + */ +#define BFI_IOC_FWSTATS_OFF (0x6B40) +#define BFI_IOC_FWSTATS_SZ (4096) + +/** + * Firmware trace offset + */ +#define BFI_IOC_TRC_OFF (0x4b00) +#define BFI_IOC_TRC_ENTS 256 + +#define BFI_IOC_FW_SIGNATURE (0xbfadbfad) +#define BFI_IOC_MD5SUM_SZ 4 +struct bfi_ioc_image_hdr_s { + u32 signature; /* constant signature */ + u32 rsvd_a; + u32 exec; /* exec vector */ + u32 param; /* parameters */ + u32 rsvd_b[4]; + u32 md5sum[BFI_IOC_MD5SUM_SZ]; +}; + +/** + * BFI_IOC_I2H_READY_EVENT message + */ +struct bfi_ioc_rdy_event_s { + struct bfi_mhdr_s mh; /* common msg header */ + u8 init_status; /* init event status */ + u8 rsvd[3]; +}; + +struct bfi_ioc_hbeat_s { + struct bfi_mhdr_s mh; /* common msg header */ + u32 hb_count; /* current heart beat count */ +}; + +/** + * IOC hardware/firmware state + */ +enum bfi_ioc_state { + BFI_IOC_UNINIT = 0, /* not initialized */ + BFI_IOC_INITING = 1, /* h/w is being initialized */ + BFI_IOC_HWINIT = 2, /* h/w is initialized */ + BFI_IOC_CFG = 3, /* IOC configuration in progress */ + BFI_IOC_OP = 4, /* IOC is operational */ + BFI_IOC_DISABLING = 5, /* IOC is being disabled */ + BFI_IOC_DISABLED = 6, /* IOC is disabled */ + BFI_IOC_CFG_DISABLED = 7, /* IOC is being disabled;transient */ + BFI_IOC_FAIL = 8, /* IOC heart-beat failure */ + BFI_IOC_MEMTEST = 9, /* IOC is doing memtest */ +}; + +#define BFI_IOC_ENDIAN_SIG 0x12345678 + +enum { + BFI_ADAPTER_TYPE_FC = 0x01, /* FC adapters */ + BFI_ADAPTER_TYPE_MK = 0x0f0000, /* adapter type mask */ + BFI_ADAPTER_TYPE_SH = 16, /* adapter type shift */ + BFI_ADAPTER_NPORTS_MK = 0xff00, /* number of ports mask */ + BFI_ADAPTER_NPORTS_SH = 8, /* number of ports shift */ + BFI_ADAPTER_SPEED_MK = 0xff, /* adapter speed mask */ + BFI_ADAPTER_SPEED_SH = 0, /* adapter speed shift */ + BFI_ADAPTER_PROTO = 0x100000, /* prototype adapaters */ + BFI_ADAPTER_TTV = 0x200000, /* TTV debug capable */ + BFI_ADAPTER_UNSUPP = 0x400000, /* unknown adapter type */ +}; + +#define BFI_ADAPTER_GETP(__prop, __adap_prop) \ + (((__adap_prop) & BFI_ADAPTER_ ## __prop ## _MK) >> \ + BFI_ADAPTER_ ## __prop ## _SH) +#define BFI_ADAPTER_SETP(__prop, __val) \ + ((__val) << BFI_ADAPTER_ ## __prop ## _SH) +#define BFI_ADAPTER_IS_PROTO(__adap_type) \ + ((__adap_type) & BFI_ADAPTER_PROTO) +#define BFI_ADAPTER_IS_TTV(__adap_type) \ + ((__adap_type) & BFI_ADAPTER_TTV) +#define BFI_ADAPTER_IS_UNSUPP(__adap_type) \ + ((__adap_type) & BFI_ADAPTER_UNSUPP) +#define BFI_ADAPTER_IS_SPECIAL(__adap_type) \ + ((__adap_type) & (BFI_ADAPTER_TTV | BFI_ADAPTER_PROTO | \ + BFI_ADAPTER_UNSUPP)) + +/** + * BFI_IOC_H2I_ENABLE_REQ & BFI_IOC_H2I_DISABLE_REQ messages + */ +struct bfi_ioc_ctrl_req_s { + struct bfi_mhdr_s mh; + u8 ioc_class; + u8 rsvd[3]; + u32 tv_sec; +}; +#define bfi_ioc_enable_req_t struct bfi_ioc_ctrl_req_s; +#define bfi_ioc_disable_req_t struct bfi_ioc_ctrl_req_s; + +/** + * BFI_IOC_I2H_ENABLE_REPLY & BFI_IOC_I2H_DISABLE_REPLY messages + */ +struct bfi_ioc_ctrl_reply_s { + struct bfi_mhdr_s mh; /* Common msg header */ + u8 status; /* enable/disable status */ + u8 rsvd[3]; +}; +#define bfi_ioc_enable_reply_t struct bfi_ioc_ctrl_reply_s; +#define bfi_ioc_disable_reply_t struct bfi_ioc_ctrl_reply_s; + +#define BFI_IOC_MSGSZ 8 +/** + * H2I Messages + */ +union bfi_ioc_h2i_msg_u { + struct bfi_mhdr_s mh; + struct bfi_ioc_ctrl_req_s enable_req; + struct bfi_ioc_ctrl_req_s disable_req; + struct bfi_ioc_getattr_req_s getattr_req; + u32 mboxmsg[BFI_IOC_MSGSZ]; +}; + +/** + * I2H Messages + */ +union bfi_ioc_i2h_msg_u { + struct bfi_mhdr_s mh; + struct bfi_ioc_rdy_event_s rdy_event; + u32 mboxmsg[BFI_IOC_MSGSZ]; +}; + + +/** + *---------------------------------------------------------------------- + * PBC + *---------------------------------------------------------------------- + */ + +#define BFI_PBC_MAX_BLUNS 8 +#define BFI_PBC_MAX_VPORTS 16 + +/** + * 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]; +}; + +/** + *---------------------------------------------------------------------- + * MSGQ + *---------------------------------------------------------------------- + */ +#define BFI_MSGQ_FULL(_q) (((_q->pi + 1) % _q->q_depth) == _q->ci) +#define BFI_MSGQ_EMPTY(_q) (_q->pi == _q->ci) +#define BFI_MSGQ_UPDATE_CI(_q) (_q->ci = (_q->ci + 1) % _q->q_depth) +#define BFI_MSGQ_UPDATE_PI(_q) (_q->pi = (_q->pi + 1) % _q->q_depth) + +/* q_depth must be power of 2 */ +#define BFI_MSGQ_FREE_CNT(_q) ((_q->ci - _q->pi - 1) & (_q->q_depth - 1)) + +enum bfi_msgq_h2i_msgs_e { + BFI_MSGQ_H2I_INIT_REQ = 1, + BFI_MSGQ_H2I_DOORBELL = 2, + BFI_MSGQ_H2I_SHUTDOWN = 3, +}; + +enum bfi_msgq_i2h_msgs_e { + BFI_MSGQ_I2H_INIT_RSP = 1, + BFI_MSGQ_I2H_DOORBELL = 2, +}; + + +/* Messages(commands/responsed/AENS will have the following header */ +struct bfi_msgq_mhdr_s { + u8 msg_class; + u8 msg_id; + u16 msg_token; + u16 num_entries; + u8 enet_id; + u8 rsvd[1]; +}; + +#define bfi_msgq_mhdr_set(_mh, _mc, _mid, _tok, _enet_id) do { \ + (_mh).msg_class = (_mc); \ + (_mh).msg_id = (_mid); \ + (_mh).msg_token = (_tok); \ + (_mh).enet_id = (_enet_id); \ +} while (0) + +/* + * Mailbox for messaging interface + * +*/ +#define BFI_MSGQ_CMD_ENTRY_SIZE (64) /* TBD */ +#define BFI_MSGQ_RSP_ENTRY_SIZE (64) /* TBD */ +#define BFI_MSGQ_MSG_SIZE_MAX (2048) /* TBD */ + +struct bfi_msgq_s { + union bfi_addr_u addr; + u16 q_depth; /* Total num of entries in the queue */ + u8 rsvd[2]; +}; + +/* BFI_ENET_MSGQ_CFG_REQ TBD init or cfg? */ +struct bfi_msgq_cfg_req_s { + struct bfi_mhdr_s mh; + struct bfi_msgq_s cmdq; + struct bfi_msgq_s rspq; +}; + +/* BFI_ENET_MSGQ_CFG_RSP */ +struct bfi_msgq_cfg_rsp_s { + struct bfi_mhdr_s mh; + u8 cmd_status; + u8 rsvd[3]; +}; + + +/* BFI_MSGQ_H2I_DOORBELL */ +struct bfi_msgq_h2i_db_s { + struct bfi_mhdr_s mh; + u16 cmdq_pi; + u16 rspq_ci; +}; + +/* BFI_MSGQ_I2H_DOORBELL */ +struct bfi_msgq_i2h_db_s { + struct bfi_mhdr_s mh; + u16 rspq_pi; + u16 cmdq_ci; +}; + +#pragma pack() + +/* BFI port specific */ +#pragma pack(1) + +enum bfi_port_h2i { + BFI_PORT_H2I_ENABLE_REQ = (1), + BFI_PORT_H2I_DISABLE_REQ = (2), + BFI_PORT_H2I_GET_STATS_REQ = (3), + BFI_PORT_H2I_CLEAR_STATS_REQ = (4), +}; + +enum bfi_port_i2h { + BFI_PORT_I2H_ENABLE_RSP = BFA_I2HM(1), + BFI_PORT_I2H_DISABLE_RSP = BFA_I2HM(2), + BFI_PORT_I2H_GET_STATS_RSP = BFA_I2HM(3), + BFI_PORT_I2H_CLEAR_STATS_RSP = BFA_I2HM(4), +}; + +/** + * Generic REQ type + */ +struct bfi_port_generic_req_s { + struct bfi_mhdr_s mh; /* msg header */ + u32 msgtag; /* msgtag for reply */ + u32 rsvd; +}; + +/** + * Generic RSP type + */ +struct bfi_port_generic_rsp_s { + struct bfi_mhdr_s mh; /* common msg header */ + u8 status; /* port enable status */ + u8 rsvd[3]; + u32 msgtag; /* msgtag for reply */ +}; + +/** + * BFI_PORT_H2I_GET_STATS_REQ + */ +struct bfi_port_get_stats_req_s { + struct bfi_mhdr_s mh; /* common msg header */ + union bfi_addr_u dma_addr; +}; + +union bfi_port_h2i_msg_u { + struct bfi_mhdr_s mh; + struct bfi_port_generic_req_s enable_req; + struct bfi_port_generic_req_s disable_req; + struct bfi_port_get_stats_req_s getstats_req; + struct bfi_port_generic_req_s clearstats_req; +}; + +union bfi_port_i2h_msg_u { + struct bfi_mhdr_s mh; + struct bfi_port_generic_rsp_s enable_rsp; + struct bfi_port_generic_rsp_s disable_rsp; + struct bfi_port_generic_rsp_s getstats_rsp; + struct bfi_port_generic_rsp_s clearstats_rsp; +}; + +#pragma pack() + +#endif /* __BFI_H__ */ diff --git a/drivers/scsi/bfa/include/bfi/bfi_cbreg.h b/drivers/scsi/bfa/bfi_cbreg.h index a51ee61ddb19..6f03ed382c69 100644 --- a/drivers/scsi/bfa/include/bfi/bfi_cbreg.h +++ b/drivers/scsi/bfa/bfi_cbreg.h @@ -1,19 +1,3 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ /* * bfi_cbreg.h crossbow host block register definitions @@ -177,8 +161,8 @@ #define __PSS_LMEM_INIT_EN 0x00000100 #define __PSS_LPU1_RESET 0x00000002 #define __PSS_LPU0_RESET 0x00000001 -#define PSS_ERR_STATUS_REG 0x00018810 -#define __PSS_LMEM1_CORR_ERR 0x00000800 +#define PSS_ERR_STATUS_REG 0x00018810 +#define __PSS_LMEM1_CORR_ERR 0x00000800 #define __PSS_LMEM0_CORR_ERR 0x00000400 #define __PSS_LMEM1_UNCORR_ERR 0x00000200 #define __PSS_LMEM0_UNCORR_ERR 0x00000100 @@ -190,8 +174,9 @@ #define __PSS_SGM_IF_ERR 0x00000004 #define __PSS_LPU1_RAM_ERR 0x00000002 #define __PSS_LPU0_RAM_ERR 0x00000001 -#define ERR_SET_REG 0x00018818 -#define __PSS_ERR_STATUS_SET 0x00000fff +#define ERR_SET_REG 0x00018818 +#define __PSS_ERR_STATUS_SET 0x00000fff + /* * These definitions are either in error/missing in spec. Its auto-generated diff --git a/drivers/scsi/bfa/bfi_ctreg.h b/drivers/scsi/bfa/bfi_ctreg.h new file mode 100644 index 000000000000..62b86a4b0e4b --- /dev/null +++ b/drivers/scsi/bfa/bfi_ctreg.h @@ -0,0 +1,627 @@ + +/* + * bfi_ctreg.h catapult host block register definitions + * + * !!! Do not edit. Auto generated. !!! + */ + +#ifndef __BFI_CTREG_H__ +#define __BFI_CTREG_H__ + + +#define HOSTFN0_LPU_MBOX0_0 0x00019200 +#define HOSTFN1_LPU_MBOX0_8 0x00019260 +#define LPU_HOSTFN0_MBOX0_0 0x00019280 +#define LPU_HOSTFN1_MBOX0_8 0x000192e0 +#define HOSTFN2_LPU_MBOX0_0 0x00019400 +#define HOSTFN3_LPU_MBOX0_8 0x00019460 +#define LPU_HOSTFN2_MBOX0_0 0x00019480 +#define LPU_HOSTFN3_MBOX0_8 0x000194e0 +#define HOSTFN0_INT_STATUS 0x00014000 +#define __HOSTFN0_HALT_OCCURRED 0x01000000 +#define __HOSTFN0_INT_STATUS_LVL_MK 0x00f00000 +#define __HOSTFN0_INT_STATUS_LVL_SH 20 +#define __HOSTFN0_INT_STATUS_LVL(_v) ((_v) << __HOSTFN0_INT_STATUS_LVL_SH) +#define __HOSTFN0_INT_STATUS_P_MK 0x000f0000 +#define __HOSTFN0_INT_STATUS_P_SH 16 +#define __HOSTFN0_INT_STATUS_P(_v) ((_v) << __HOSTFN0_INT_STATUS_P_SH) +#define __HOSTFN0_INT_STATUS_F 0x0000ffff +#define HOSTFN0_INT_MSK 0x00014004 +#define HOST_PAGE_NUM_FN0 0x00014008 +#define __HOST_PAGE_NUM_FN 0x000001ff +#define HOST_MSIX_ERR_INDEX_FN0 0x0001400c +#define __MSIX_ERR_INDEX_FN 0x000001ff +#define HOSTFN1_INT_STATUS 0x00014100 +#define __HOSTFN1_HALT_OCCURRED 0x01000000 +#define __HOSTFN1_INT_STATUS_LVL_MK 0x00f00000 +#define __HOSTFN1_INT_STATUS_LVL_SH 20 +#define __HOSTFN1_INT_STATUS_LVL(_v) ((_v) << __HOSTFN1_INT_STATUS_LVL_SH) +#define __HOSTFN1_INT_STATUS_P_MK 0x000f0000 +#define __HOSTFN1_INT_STATUS_P_SH 16 +#define __HOSTFN1_INT_STATUS_P(_v) ((_v) << __HOSTFN1_INT_STATUS_P_SH) +#define __HOSTFN1_INT_STATUS_F 0x0000ffff +#define HOSTFN1_INT_MSK 0x00014104 +#define HOST_PAGE_NUM_FN1 0x00014108 +#define HOST_MSIX_ERR_INDEX_FN1 0x0001410c +#define APP_PLL_425_CTL_REG 0x00014204 +#define __P_425_PLL_LOCK 0x80000000 +#define __APP_PLL_425_SRAM_USE_100MHZ 0x00100000 +#define __APP_PLL_425_RESET_TIMER_MK 0x000e0000 +#define __APP_PLL_425_RESET_TIMER_SH 17 +#define __APP_PLL_425_RESET_TIMER(_v) ((_v) << __APP_PLL_425_RESET_TIMER_SH) +#define __APP_PLL_425_LOGIC_SOFT_RESET 0x00010000 +#define __APP_PLL_425_CNTLMT0_1_MK 0x0000c000 +#define __APP_PLL_425_CNTLMT0_1_SH 14 +#define __APP_PLL_425_CNTLMT0_1(_v) ((_v) << __APP_PLL_425_CNTLMT0_1_SH) +#define __APP_PLL_425_JITLMT0_1_MK 0x00003000 +#define __APP_PLL_425_JITLMT0_1_SH 12 +#define __APP_PLL_425_JITLMT0_1(_v) ((_v) << __APP_PLL_425_JITLMT0_1_SH) +#define __APP_PLL_425_HREF 0x00000800 +#define __APP_PLL_425_HDIV 0x00000400 +#define __APP_PLL_425_P0_1_MK 0x00000300 +#define __APP_PLL_425_P0_1_SH 8 +#define __APP_PLL_425_P0_1(_v) ((_v) << __APP_PLL_425_P0_1_SH) +#define __APP_PLL_425_Z0_2_MK 0x000000e0 +#define __APP_PLL_425_Z0_2_SH 5 +#define __APP_PLL_425_Z0_2(_v) ((_v) << __APP_PLL_425_Z0_2_SH) +#define __APP_PLL_425_RSEL200500 0x00000010 +#define __APP_PLL_425_ENARST 0x00000008 +#define __APP_PLL_425_BYPASS 0x00000004 +#define __APP_PLL_425_LRESETN 0x00000002 +#define __APP_PLL_425_ENABLE 0x00000001 +#define APP_PLL_312_CTL_REG 0x00014208 +#define __P_312_PLL_LOCK 0x80000000 +#define __ENABLE_MAC_AHB_1 0x00800000 +#define __ENABLE_MAC_AHB_0 0x00400000 +#define __ENABLE_MAC_1 0x00200000 +#define __ENABLE_MAC_0 0x00100000 +#define __APP_PLL_312_RESET_TIMER_MK 0x000e0000 +#define __APP_PLL_312_RESET_TIMER_SH 17 +#define __APP_PLL_312_RESET_TIMER(_v) ((_v) << __APP_PLL_312_RESET_TIMER_SH) +#define __APP_PLL_312_LOGIC_SOFT_RESET 0x00010000 +#define __APP_PLL_312_CNTLMT0_1_MK 0x0000c000 +#define __APP_PLL_312_CNTLMT0_1_SH 14 +#define __APP_PLL_312_CNTLMT0_1(_v) ((_v) << __APP_PLL_312_CNTLMT0_1_SH) +#define __APP_PLL_312_JITLMT0_1_MK 0x00003000 +#define __APP_PLL_312_JITLMT0_1_SH 12 +#define __APP_PLL_312_JITLMT0_1(_v) ((_v) << __APP_PLL_312_JITLMT0_1_SH) +#define __APP_PLL_312_HREF 0x00000800 +#define __APP_PLL_312_HDIV 0x00000400 +#define __APP_PLL_312_P0_1_MK 0x00000300 +#define __APP_PLL_312_P0_1_SH 8 +#define __APP_PLL_312_P0_1(_v) ((_v) << __APP_PLL_312_P0_1_SH) +#define __APP_PLL_312_Z0_2_MK 0x000000e0 +#define __APP_PLL_312_Z0_2_SH 5 +#define __APP_PLL_312_Z0_2(_v) ((_v) << __APP_PLL_312_Z0_2_SH) +#define __APP_PLL_312_RSEL200500 0x00000010 +#define __APP_PLL_312_ENARST 0x00000008 +#define __APP_PLL_312_BYPASS 0x00000004 +#define __APP_PLL_312_LRESETN 0x00000002 +#define __APP_PLL_312_ENABLE 0x00000001 +#define MBIST_CTL_REG 0x00014220 +#define __EDRAM_BISTR_START 0x00000004 +#define __MBIST_RESET 0x00000002 +#define __MBIST_START 0x00000001 +#define MBIST_STAT_REG 0x00014224 +#define __EDRAM_BISTR_STATUS 0x00000008 +#define __EDRAM_BISTR_DONE 0x00000004 +#define __MEM_BIT_STATUS 0x00000002 +#define __MBIST_DONE 0x00000001 +#define HOST_SEM0_REG 0x00014230 +#define __HOST_SEMAPHORE 0x00000001 +#define HOST_SEM1_REG 0x00014234 +#define HOST_SEM2_REG 0x00014238 +#define HOST_SEM3_REG 0x0001423c +#define HOST_SEM0_INFO_REG 0x00014240 +#define HOST_SEM1_INFO_REG 0x00014244 +#define HOST_SEM2_INFO_REG 0x00014248 +#define HOST_SEM3_INFO_REG 0x0001424c +#define ETH_MAC_SER_REG 0x00014288 +#define __APP_EMS_CKBUFAMPIN 0x00000020 +#define __APP_EMS_REFCLKSEL 0x00000010 +#define __APP_EMS_CMLCKSEL 0x00000008 +#define __APP_EMS_REFCKBUFEN2 0x00000004 +#define __APP_EMS_REFCKBUFEN1 0x00000002 +#define __APP_EMS_CHANNEL_SEL 0x00000001 +#define HOSTFN2_INT_STATUS 0x00014300 +#define __HOSTFN2_HALT_OCCURRED 0x01000000 +#define __HOSTFN2_INT_STATUS_LVL_MK 0x00f00000 +#define __HOSTFN2_INT_STATUS_LVL_SH 20 +#define __HOSTFN2_INT_STATUS_LVL(_v) ((_v) << __HOSTFN2_INT_STATUS_LVL_SH) +#define __HOSTFN2_INT_STATUS_P_MK 0x000f0000 +#define __HOSTFN2_INT_STATUS_P_SH 16 +#define __HOSTFN2_INT_STATUS_P(_v) ((_v) << __HOSTFN2_INT_STATUS_P_SH) +#define __HOSTFN2_INT_STATUS_F 0x0000ffff +#define HOSTFN2_INT_MSK 0x00014304 +#define HOST_PAGE_NUM_FN2 0x00014308 +#define HOST_MSIX_ERR_INDEX_FN2 0x0001430c +#define HOSTFN3_INT_STATUS 0x00014400 +#define __HALT_OCCURRED 0x01000000 +#define __HOSTFN3_INT_STATUS_LVL_MK 0x00f00000 +#define __HOSTFN3_INT_STATUS_LVL_SH 20 +#define __HOSTFN3_INT_STATUS_LVL(_v) ((_v) << __HOSTFN3_INT_STATUS_LVL_SH) +#define __HOSTFN3_INT_STATUS_P_MK 0x000f0000 +#define __HOSTFN3_INT_STATUS_P_SH 16 +#define __HOSTFN3_INT_STATUS_P(_v) ((_v) << __HOSTFN3_INT_STATUS_P_SH) +#define __HOSTFN3_INT_STATUS_F 0x0000ffff +#define HOSTFN3_INT_MSK 0x00014404 +#define HOST_PAGE_NUM_FN3 0x00014408 +#define HOST_MSIX_ERR_INDEX_FN3 0x0001440c +#define FNC_ID_REG 0x00014600 +#define __FUNCTION_NUMBER 0x00000007 +#define FNC_PERS_REG 0x00014604 +#define __F3_FUNCTION_ACTIVE 0x80000000 +#define __F3_FUNCTION_MODE 0x40000000 +#define __F3_PORT_MAP_MK 0x30000000 +#define __F3_PORT_MAP_SH 28 +#define __F3_PORT_MAP(_v) ((_v) << __F3_PORT_MAP_SH) +#define __F3_VM_MODE 0x08000000 +#define __F3_INTX_STATUS_MK 0x07000000 +#define __F3_INTX_STATUS_SH 24 +#define __F3_INTX_STATUS(_v) ((_v) << __F3_INTX_STATUS_SH) +#define __F2_FUNCTION_ACTIVE 0x00800000 +#define __F2_FUNCTION_MODE 0x00400000 +#define __F2_PORT_MAP_MK 0x00300000 +#define __F2_PORT_MAP_SH 20 +#define __F2_PORT_MAP(_v) ((_v) << __F2_PORT_MAP_SH) +#define __F2_VM_MODE 0x00080000 +#define __F2_INTX_STATUS_MK 0x00070000 +#define __F2_INTX_STATUS_SH 16 +#define __F2_INTX_STATUS(_v) ((_v) << __F2_INTX_STATUS_SH) +#define __F1_FUNCTION_ACTIVE 0x00008000 +#define __F1_FUNCTION_MODE 0x00004000 +#define __F1_PORT_MAP_MK 0x00003000 +#define __F1_PORT_MAP_SH 12 +#define __F1_PORT_MAP(_v) ((_v) << __F1_PORT_MAP_SH) +#define __F1_VM_MODE 0x00000800 +#define __F1_INTX_STATUS_MK 0x00000700 +#define __F1_INTX_STATUS_SH 8 +#define __F1_INTX_STATUS(_v) ((_v) << __F1_INTX_STATUS_SH) +#define __F0_FUNCTION_ACTIVE 0x00000080 +#define __F0_FUNCTION_MODE 0x00000040 +#define __F0_PORT_MAP_MK 0x00000030 +#define __F0_PORT_MAP_SH 4 +#define __F0_PORT_MAP(_v) ((_v) << __F0_PORT_MAP_SH) +#define __F0_VM_MODE 0x00000008 +#define __F0_INTX_STATUS 0x00000007 +enum { + __F0_INTX_STATUS_MSIX = 0x0, + __F0_INTX_STATUS_INTA = 0x1, + __F0_INTX_STATUS_INTB = 0x2, + __F0_INTX_STATUS_INTC = 0x3, + __F0_INTX_STATUS_INTD = 0x4, +}; +#define OP_MODE 0x0001460c +#define __APP_ETH_CLK_LOWSPEED 0x00000004 +#define __GLOBAL_CORECLK_HALFSPEED 0x00000002 +#define __GLOBAL_FCOE_MODE 0x00000001 +#define HOST_SEM4_REG 0x00014610 +#define HOST_SEM5_REG 0x00014614 +#define HOST_SEM6_REG 0x00014618 +#define HOST_SEM7_REG 0x0001461c +#define HOST_SEM4_INFO_REG 0x00014620 +#define HOST_SEM5_INFO_REG 0x00014624 +#define HOST_SEM6_INFO_REG 0x00014628 +#define HOST_SEM7_INFO_REG 0x0001462c +#define HOSTFN0_LPU0_MBOX0_CMD_STAT 0x00019000 +#define __HOSTFN0_LPU0_MBOX0_INFO_MK 0xfffffffe +#define __HOSTFN0_LPU0_MBOX0_INFO_SH 1 +#define __HOSTFN0_LPU0_MBOX0_INFO(_v) ((_v) << __HOSTFN0_LPU0_MBOX0_INFO_SH) +#define __HOSTFN0_LPU0_MBOX0_CMD_STATUS 0x00000001 +#define HOSTFN0_LPU1_MBOX0_CMD_STAT 0x00019004 +#define __HOSTFN0_LPU1_MBOX0_INFO_MK 0xfffffffe +#define __HOSTFN0_LPU1_MBOX0_INFO_SH 1 +#define __HOSTFN0_LPU1_MBOX0_INFO(_v) ((_v) << __HOSTFN0_LPU1_MBOX0_INFO_SH) +#define __HOSTFN0_LPU1_MBOX0_CMD_STATUS 0x00000001 +#define LPU0_HOSTFN0_MBOX0_CMD_STAT 0x00019008 +#define __LPU0_HOSTFN0_MBOX0_INFO_MK 0xfffffffe +#define __LPU0_HOSTFN0_MBOX0_INFO_SH 1 +#define __LPU0_HOSTFN0_MBOX0_INFO(_v) ((_v) << __LPU0_HOSTFN0_MBOX0_INFO_SH) +#define __LPU0_HOSTFN0_MBOX0_CMD_STATUS 0x00000001 +#define LPU1_HOSTFN0_MBOX0_CMD_STAT 0x0001900c +#define __LPU1_HOSTFN0_MBOX0_INFO_MK 0xfffffffe +#define __LPU1_HOSTFN0_MBOX0_INFO_SH 1 +#define __LPU1_HOSTFN0_MBOX0_INFO(_v) ((_v) << __LPU1_HOSTFN0_MBOX0_INFO_SH) +#define __LPU1_HOSTFN0_MBOX0_CMD_STATUS 0x00000001 +#define HOSTFN1_LPU0_MBOX0_CMD_STAT 0x00019010 +#define __HOSTFN1_LPU0_MBOX0_INFO_MK 0xfffffffe +#define __HOSTFN1_LPU0_MBOX0_INFO_SH 1 +#define __HOSTFN1_LPU0_MBOX0_INFO(_v) ((_v) << __HOSTFN1_LPU0_MBOX0_INFO_SH) +#define __HOSTFN1_LPU0_MBOX0_CMD_STATUS 0x00000001 +#define HOSTFN1_LPU1_MBOX0_CMD_STAT 0x00019014 +#define __HOSTFN1_LPU1_MBOX0_INFO_MK 0xfffffffe +#define __HOSTFN1_LPU1_MBOX0_INFO_SH 1 +#define __HOSTFN1_LPU1_MBOX0_INFO(_v) ((_v) << __HOSTFN1_LPU1_MBOX0_INFO_SH) +#define __HOSTFN1_LPU1_MBOX0_CMD_STATUS 0x00000001 +#define LPU0_HOSTFN1_MBOX0_CMD_STAT 0x00019018 +#define __LPU0_HOSTFN1_MBOX0_INFO_MK 0xfffffffe +#define __LPU0_HOSTFN1_MBOX0_INFO_SH 1 +#define __LPU0_HOSTFN1_MBOX0_INFO(_v) ((_v) << __LPU0_HOSTFN1_MBOX0_INFO_SH) +#define __LPU0_HOSTFN1_MBOX0_CMD_STATUS 0x00000001 +#define LPU1_HOSTFN1_MBOX0_CMD_STAT 0x0001901c +#define __LPU1_HOSTFN1_MBOX0_INFO_MK 0xfffffffe +#define __LPU1_HOSTFN1_MBOX0_INFO_SH 1 +#define __LPU1_HOSTFN1_MBOX0_INFO(_v) ((_v) << __LPU1_HOSTFN1_MBOX0_INFO_SH) +#define __LPU1_HOSTFN1_MBOX0_CMD_STATUS 0x00000001 +#define HOSTFN2_LPU0_MBOX0_CMD_STAT 0x00019150 +#define __HOSTFN2_LPU0_MBOX0_INFO_MK 0xfffffffe +#define __HOSTFN2_LPU0_MBOX0_INFO_SH 1 +#define __HOSTFN2_LPU0_MBOX0_INFO(_v) ((_v) << __HOSTFN2_LPU0_MBOX0_INFO_SH) +#define __HOSTFN2_LPU0_MBOX0_CMD_STATUS 0x00000001 +#define HOSTFN2_LPU1_MBOX0_CMD_STAT 0x00019154 +#define __HOSTFN2_LPU1_MBOX0_INFO_MK 0xfffffffe +#define __HOSTFN2_LPU1_MBOX0_INFO_SH 1 +#define __HOSTFN2_LPU1_MBOX0_INFO(_v) ((_v) << __HOSTFN2_LPU1_MBOX0_INFO_SH) +#define __HOSTFN2_LPU1_MBOX0BOX0_CMD_STATUS 0x00000001 +#define LPU0_HOSTFN2_MBOX0_CMD_STAT 0x00019158 +#define __LPU0_HOSTFN2_MBOX0_INFO_MK 0xfffffffe +#define __LPU0_HOSTFN2_MBOX0_INFO_SH 1 +#define __LPU0_HOSTFN2_MBOX0_INFO(_v) ((_v) << __LPU0_HOSTFN2_MBOX0_INFO_SH) +#define __LPU0_HOSTFN2_MBOX0_CMD_STATUS 0x00000001 +#define LPU1_HOSTFN2_MBOX0_CMD_STAT 0x0001915c +#define __LPU1_HOSTFN2_MBOX0_INFO_MK 0xfffffffe +#define __LPU1_HOSTFN2_MBOX0_INFO_SH 1 +#define __LPU1_HOSTFN2_MBOX0_INFO(_v) ((_v) << __LPU1_HOSTFN2_MBOX0_INFO_SH) +#define __LPU1_HOSTFN2_MBOX0_CMD_STATUS 0x00000001 +#define HOSTFN3_LPU0_MBOX0_CMD_STAT 0x00019160 +#define __HOSTFN3_LPU0_MBOX0_INFO_MK 0xfffffffe +#define __HOSTFN3_LPU0_MBOX0_INFO_SH 1 +#define __HOSTFN3_LPU0_MBOX0_INFO(_v) ((_v) << __HOSTFN3_LPU0_MBOX0_INFO_SH) +#define __HOSTFN3_LPU0_MBOX0_CMD_STATUS 0x00000001 +#define HOSTFN3_LPU1_MBOX0_CMD_STAT 0x00019164 +#define __HOSTFN3_LPU1_MBOX0_INFO_MK 0xfffffffe +#define __HOSTFN3_LPU1_MBOX0_INFO_SH 1 +#define __HOSTFN3_LPU1_MBOX0_INFO(_v) ((_v) << __HOSTFN3_LPU1_MBOX0_INFO_SH) +#define __HOSTFN3_LPU1_MBOX0_CMD_STATUS 0x00000001 +#define LPU0_HOSTFN3_MBOX0_CMD_STAT 0x00019168 +#define __LPU0_HOSTFN3_MBOX0_INFO_MK 0xfffffffe +#define __LPU0_HOSTFN3_MBOX0_INFO_SH 1 +#define __LPU0_HOSTFN3_MBOX0_INFO(_v) ((_v) << __LPU0_HOSTFN3_MBOX0_INFO_SH) +#define __LPU0_HOSTFN3_MBOX0_CMD_STATUS 0x00000001 +#define LPU1_HOSTFN3_MBOX0_CMD_STAT 0x0001916c +#define __LPU1_HOSTFN3_MBOX0_INFO_MK 0xfffffffe +#define __LPU1_HOSTFN3_MBOX0_INFO_SH 1 +#define __LPU1_HOSTFN3_MBOX0_INFO(_v) ((_v) << __LPU1_HOSTFN3_MBOX0_INFO_SH) +#define __LPU1_HOSTFN3_MBOX0_CMD_STATUS 0x00000001 +#define FW_INIT_HALT_P0 0x000191ac +#define __FW_INIT_HALT_P 0x00000001 +#define FW_INIT_HALT_P1 0x000191bc +#define CPE_PI_PTR_Q0 0x00038000 +#define __CPE_PI_UNUSED_MK 0xffff0000 +#define __CPE_PI_UNUSED_SH 16 +#define __CPE_PI_UNUSED(_v) ((_v) << __CPE_PI_UNUSED_SH) +#define __CPE_PI_PTR 0x0000ffff +#define CPE_PI_PTR_Q1 0x00038040 +#define CPE_CI_PTR_Q0 0x00038004 +#define __CPE_CI_UNUSED_MK 0xffff0000 +#define __CPE_CI_UNUSED_SH 16 +#define __CPE_CI_UNUSED(_v) ((_v) << __CPE_CI_UNUSED_SH) +#define __CPE_CI_PTR 0x0000ffff +#define CPE_CI_PTR_Q1 0x00038044 +#define CPE_DEPTH_Q0 0x00038008 +#define __CPE_DEPTH_UNUSED_MK 0xf8000000 +#define __CPE_DEPTH_UNUSED_SH 27 +#define __CPE_DEPTH_UNUSED(_v) ((_v) << __CPE_DEPTH_UNUSED_SH) +#define __CPE_MSIX_VEC_INDEX_MK 0x07ff0000 +#define __CPE_MSIX_VEC_INDEX_SH 16 +#define __CPE_MSIX_VEC_INDEX(_v) ((_v) << __CPE_MSIX_VEC_INDEX_SH) +#define __CPE_DEPTH 0x0000ffff +#define CPE_DEPTH_Q1 0x00038048 +#define CPE_QCTRL_Q0 0x0003800c +#define __CPE_CTRL_UNUSED30_MK 0xfc000000 +#define __CPE_CTRL_UNUSED30_SH 26 +#define __CPE_CTRL_UNUSED30(_v) ((_v) << __CPE_CTRL_UNUSED30_SH) +#define __CPE_FUNC_INT_CTRL_MK 0x03000000 +#define __CPE_FUNC_INT_CTRL_SH 24 +#define __CPE_FUNC_INT_CTRL(_v) ((_v) << __CPE_FUNC_INT_CTRL_SH) +enum { + __CPE_FUNC_INT_CTRL_DISABLE = 0x0, + __CPE_FUNC_INT_CTRL_F2NF = 0x1, + __CPE_FUNC_INT_CTRL_3QUART = 0x2, + __CPE_FUNC_INT_CTRL_HALF = 0x3, +}; +#define __CPE_CTRL_UNUSED20_MK 0x00f00000 +#define __CPE_CTRL_UNUSED20_SH 20 +#define __CPE_CTRL_UNUSED20(_v) ((_v) << __CPE_CTRL_UNUSED20_SH) +#define __CPE_SCI_TH_MK 0x000f0000 +#define __CPE_SCI_TH_SH 16 +#define __CPE_SCI_TH(_v) ((_v) << __CPE_SCI_TH_SH) +#define __CPE_CTRL_UNUSED10_MK 0x0000c000 +#define __CPE_CTRL_UNUSED10_SH 14 +#define __CPE_CTRL_UNUSED10(_v) ((_v) << __CPE_CTRL_UNUSED10_SH) +#define __CPE_ACK_PENDING 0x00002000 +#define __CPE_CTRL_UNUSED40_MK 0x00001c00 +#define __CPE_CTRL_UNUSED40_SH 10 +#define __CPE_CTRL_UNUSED40(_v) ((_v) << __CPE_CTRL_UNUSED40_SH) +#define __CPE_PCIEID_MK 0x00000300 +#define __CPE_PCIEID_SH 8 +#define __CPE_PCIEID(_v) ((_v) << __CPE_PCIEID_SH) +#define __CPE_CTRL_UNUSED00_MK 0x000000fe +#define __CPE_CTRL_UNUSED00_SH 1 +#define __CPE_CTRL_UNUSED00(_v) ((_v) << __CPE_CTRL_UNUSED00_SH) +#define __CPE_ESIZE 0x00000001 +#define CPE_QCTRL_Q1 0x0003804c +#define __CPE_CTRL_UNUSED31_MK 0xfc000000 +#define __CPE_CTRL_UNUSED31_SH 26 +#define __CPE_CTRL_UNUSED31(_v) ((_v) << __CPE_CTRL_UNUSED31_SH) +#define __CPE_CTRL_UNUSED21_MK 0x00f00000 +#define __CPE_CTRL_UNUSED21_SH 20 +#define __CPE_CTRL_UNUSED21(_v) ((_v) << __CPE_CTRL_UNUSED21_SH) +#define __CPE_CTRL_UNUSED11_MK 0x0000c000 +#define __CPE_CTRL_UNUSED11_SH 14 +#define __CPE_CTRL_UNUSED11(_v) ((_v) << __CPE_CTRL_UNUSED11_SH) +#define __CPE_CTRL_UNUSED41_MK 0x00001c00 +#define __CPE_CTRL_UNUSED41_SH 10 +#define __CPE_CTRL_UNUSED41(_v) ((_v) << __CPE_CTRL_UNUSED41_SH) +#define __CPE_CTRL_UNUSED01_MK 0x000000fe +#define __CPE_CTRL_UNUSED01_SH 1 +#define __CPE_CTRL_UNUSED01(_v) ((_v) << __CPE_CTRL_UNUSED01_SH) +#define RME_PI_PTR_Q0 0x00038020 +#define __LATENCY_TIME_STAMP_MK 0xffff0000 +#define __LATENCY_TIME_STAMP_SH 16 +#define __LATENCY_TIME_STAMP(_v) ((_v) << __LATENCY_TIME_STAMP_SH) +#define __RME_PI_PTR 0x0000ffff +#define RME_PI_PTR_Q1 0x00038060 +#define RME_CI_PTR_Q0 0x00038024 +#define __DELAY_TIME_STAMP_MK 0xffff0000 +#define __DELAY_TIME_STAMP_SH 16 +#define __DELAY_TIME_STAMP(_v) ((_v) << __DELAY_TIME_STAMP_SH) +#define __RME_CI_PTR 0x0000ffff +#define RME_CI_PTR_Q1 0x00038064 +#define RME_DEPTH_Q0 0x00038028 +#define __RME_DEPTH_UNUSED_MK 0xf8000000 +#define __RME_DEPTH_UNUSED_SH 27 +#define __RME_DEPTH_UNUSED(_v) ((_v) << __RME_DEPTH_UNUSED_SH) +#define __RME_MSIX_VEC_INDEX_MK 0x07ff0000 +#define __RME_MSIX_VEC_INDEX_SH 16 +#define __RME_MSIX_VEC_INDEX(_v) ((_v) << __RME_MSIX_VEC_INDEX_SH) +#define __RME_DEPTH 0x0000ffff +#define RME_DEPTH_Q1 0x00038068 +#define RME_QCTRL_Q0 0x0003802c +#define __RME_INT_LATENCY_TIMER_MK 0xff000000 +#define __RME_INT_LATENCY_TIMER_SH 24 +#define __RME_INT_LATENCY_TIMER(_v) ((_v) << __RME_INT_LATENCY_TIMER_SH) +#define __RME_INT_DELAY_TIMER_MK 0x00ff0000 +#define __RME_INT_DELAY_TIMER_SH 16 +#define __RME_INT_DELAY_TIMER(_v) ((_v) << __RME_INT_DELAY_TIMER_SH) +#define __RME_INT_DELAY_DISABLE 0x00008000 +#define __RME_DLY_DELAY_DISABLE 0x00004000 +#define __RME_ACK_PENDING 0x00002000 +#define __RME_FULL_INTERRUPT_DISABLE 0x00001000 +#define __RME_CTRL_UNUSED10_MK 0x00000c00 +#define __RME_CTRL_UNUSED10_SH 10 +#define __RME_CTRL_UNUSED10(_v) ((_v) << __RME_CTRL_UNUSED10_SH) +#define __RME_PCIEID_MK 0x00000300 +#define __RME_PCIEID_SH 8 +#define __RME_PCIEID(_v) ((_v) << __RME_PCIEID_SH) +#define __RME_CTRL_UNUSED00_MK 0x000000fe +#define __RME_CTRL_UNUSED00_SH 1 +#define __RME_CTRL_UNUSED00(_v) ((_v) << __RME_CTRL_UNUSED00_SH) +#define __RME_ESIZE 0x00000001 +#define RME_QCTRL_Q1 0x0003806c +#define __RME_CTRL_UNUSED11_MK 0x00000c00 +#define __RME_CTRL_UNUSED11_SH 10 +#define __RME_CTRL_UNUSED11(_v) ((_v) << __RME_CTRL_UNUSED11_SH) +#define __RME_CTRL_UNUSED01_MK 0x000000fe +#define __RME_CTRL_UNUSED01_SH 1 +#define __RME_CTRL_UNUSED01(_v) ((_v) << __RME_CTRL_UNUSED01_SH) +#define PSS_CTL_REG 0x00018800 +#define __PSS_I2C_CLK_DIV_MK 0x007f0000 +#define __PSS_I2C_CLK_DIV_SH 16 +#define __PSS_I2C_CLK_DIV(_v) ((_v) << __PSS_I2C_CLK_DIV_SH) +#define __PSS_LMEM_INIT_DONE 0x00001000 +#define __PSS_LMEM_RESET 0x00000200 +#define __PSS_LMEM_INIT_EN 0x00000100 +#define __PSS_LPU1_RESET 0x00000002 +#define __PSS_LPU0_RESET 0x00000001 +#define PSS_ERR_STATUS_REG 0x00018810 +#define __PSS_LPU1_TCM_READ_ERR 0x00200000 +#define __PSS_LPU0_TCM_READ_ERR 0x00100000 +#define __PSS_LMEM5_CORR_ERR 0x00080000 +#define __PSS_LMEM4_CORR_ERR 0x00040000 +#define __PSS_LMEM3_CORR_ERR 0x00020000 +#define __PSS_LMEM2_CORR_ERR 0x00010000 +#define __PSS_LMEM1_CORR_ERR 0x00008000 +#define __PSS_LMEM0_CORR_ERR 0x00004000 +#define __PSS_LMEM5_UNCORR_ERR 0x00002000 +#define __PSS_LMEM4_UNCORR_ERR 0x00001000 +#define __PSS_LMEM3_UNCORR_ERR 0x00000800 +#define __PSS_LMEM2_UNCORR_ERR 0x00000400 +#define __PSS_LMEM1_UNCORR_ERR 0x00000200 +#define __PSS_LMEM0_UNCORR_ERR 0x00000100 +#define __PSS_BAL_PERR 0x00000080 +#define __PSS_DIP_IF_ERR 0x00000040 +#define __PSS_IOH_IF_ERR 0x00000020 +#define __PSS_TDS_IF_ERR 0x00000010 +#define __PSS_RDS_IF_ERR 0x00000008 +#define __PSS_SGM_IF_ERR 0x00000004 +#define __PSS_LPU1_RAM_ERR 0x00000002 +#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 +#define __RXQ0_PRD_PTR_P 0x0000ffff +#define HQM_QSET1_RXQ_DRBL_P0 0x00038080 +#define __RXQ1_ADD_VECTORS_P 0x80000000 +#define __RXQ1_STOP_P 0x40000000 +#define __RXQ1_PRD_PTR_P 0x0000ffff +#define HQM_QSET0_RXQ_DRBL_P1 0x0003c000 +#define HQM_QSET1_RXQ_DRBL_P1 0x0003c080 +#define HQM_QSET0_TXQ_DRBL_P0 0x00038020 +#define __TXQ0_ADD_VECTORS_P 0x80000000 +#define __TXQ0_STOP_P 0x40000000 +#define __TXQ0_PRD_PTR_P 0x0000ffff +#define HQM_QSET1_TXQ_DRBL_P0 0x000380a0 +#define __TXQ1_ADD_VECTORS_P 0x80000000 +#define __TXQ1_STOP_P 0x40000000 +#define __TXQ1_PRD_PTR_P 0x0000ffff +#define HQM_QSET0_TXQ_DRBL_P1 0x0003c020 +#define HQM_QSET1_TXQ_DRBL_P1 0x0003c0a0 +#define HQM_QSET0_IB_DRBL_1_P0 0x00038040 +#define __IB1_0_ACK_P 0x80000000 +#define __IB1_0_DISABLE_P 0x40000000 +#define __IB1_0_COALESCING_CFG_P_MK 0x00ff0000 +#define __IB1_0_COALESCING_CFG_P_SH 16 +#define __IB1_0_COALESCING_CFG_P(_v) ((_v) << __IB1_0_COALESCING_CFG_P_SH) +#define __IB1_0_NUM_OF_ACKED_EVENTS_P 0x0000ffff +#define HQM_QSET1_IB_DRBL_1_P0 0x000380c0 +#define __IB1_1_ACK_P 0x80000000 +#define __IB1_1_DISABLE_P 0x40000000 +#define __IB1_1_COALESCING_CFG_P_MK 0x00ff0000 +#define __IB1_1_COALESCING_CFG_P_SH 16 +#define __IB1_1_COALESCING_CFG_P(_v) ((_v) << __IB1_1_COALESCING_CFG_P_SH) +#define __IB1_1_NUM_OF_ACKED_EVENTS_P 0x0000ffff +#define HQM_QSET0_IB_DRBL_1_P1 0x0003c040 +#define HQM_QSET1_IB_DRBL_1_P1 0x0003c0c0 +#define HQM_QSET0_IB_DRBL_2_P0 0x00038060 +#define __IB2_0_ACK_P 0x80000000 +#define __IB2_0_DISABLE_P 0x40000000 +#define __IB2_0_COALESCING_CFG_P_MK 0x00ff0000 +#define __IB2_0_COALESCING_CFG_P_SH 16 +#define __IB2_0_COALESCING_CFG_P(_v) ((_v) << __IB2_0_COALESCING_CFG_P_SH) +#define __IB2_0_NUM_OF_ACKED_EVENTS_P 0x0000ffff +#define HQM_QSET1_IB_DRBL_2_P0 0x000380e0 +#define __IB2_1_ACK_P 0x80000000 +#define __IB2_1_DISABLE_P 0x40000000 +#define __IB2_1_COALESCING_CFG_P_MK 0x00ff0000 +#define __IB2_1_COALESCING_CFG_P_SH 16 +#define __IB2_1_COALESCING_CFG_P(_v) ((_v) << __IB2_1_COALESCING_CFG_P_SH) +#define __IB2_1_NUM_OF_ACKED_EVENTS_P 0x0000ffff +#define HQM_QSET0_IB_DRBL_2_P1 0x0003c060 +#define HQM_QSET1_IB_DRBL_2_P1 0x0003c0e0 + + +/* + * These definitions are either in error/missing in spec. Its auto-generated + * from hard coded values in regparse.pl. + */ +#define __EMPHPOST_AT_4G_MK_FIX 0x0000001c +#define __EMPHPOST_AT_4G_SH_FIX 0x00000002 +#define __EMPHPRE_AT_4G_FIX 0x00000003 +#define __SFP_TXRATE_EN_FIX 0x00000100 +#define __SFP_RXRATE_EN_FIX 0x00000080 + + +/* + * These register definitions are auto-generated from hard coded values + * in regparse.pl. + */ + + +/* + * These register mapping definitions are auto-generated from mapping tables + * in regparse.pl. + */ +#define BFA_IOC0_HBEAT_REG HOST_SEM0_INFO_REG +#define BFA_IOC0_STATE_REG HOST_SEM1_INFO_REG +#define BFA_IOC1_HBEAT_REG HOST_SEM2_INFO_REG +#define BFA_IOC1_STATE_REG HOST_SEM3_INFO_REG +#define BFA_FW_USE_COUNT HOST_SEM4_INFO_REG + +#define CPE_DEPTH_Q(__n) \ + (CPE_DEPTH_Q0 + (__n) * (CPE_DEPTH_Q1 - CPE_DEPTH_Q0)) +#define CPE_QCTRL_Q(__n) \ + (CPE_QCTRL_Q0 + (__n) * (CPE_QCTRL_Q1 - CPE_QCTRL_Q0)) +#define CPE_PI_PTR_Q(__n) \ + (CPE_PI_PTR_Q0 + (__n) * (CPE_PI_PTR_Q1 - CPE_PI_PTR_Q0)) +#define CPE_CI_PTR_Q(__n) \ + (CPE_CI_PTR_Q0 + (__n) * (CPE_CI_PTR_Q1 - CPE_CI_PTR_Q0)) +#define RME_DEPTH_Q(__n) \ + (RME_DEPTH_Q0 + (__n) * (RME_DEPTH_Q1 - RME_DEPTH_Q0)) +#define RME_QCTRL_Q(__n) \ + (RME_QCTRL_Q0 + (__n) * (RME_QCTRL_Q1 - RME_QCTRL_Q0)) +#define RME_PI_PTR_Q(__n) \ + (RME_PI_PTR_Q0 + (__n) * (RME_PI_PTR_Q1 - RME_PI_PTR_Q0)) +#define RME_CI_PTR_Q(__n) \ + (RME_CI_PTR_Q0 + (__n) * (RME_CI_PTR_Q1 - RME_CI_PTR_Q0)) +#define HQM_QSET_RXQ_DRBL_P0(__n) (HQM_QSET0_RXQ_DRBL_P0 + (__n) \ + * (HQM_QSET1_RXQ_DRBL_P0 - HQM_QSET0_RXQ_DRBL_P0)) +#define HQM_QSET_TXQ_DRBL_P0(__n) (HQM_QSET0_TXQ_DRBL_P0 + (__n) \ + * (HQM_QSET1_TXQ_DRBL_P0 - HQM_QSET0_TXQ_DRBL_P0)) +#define HQM_QSET_IB_DRBL_1_P0(__n) (HQM_QSET0_IB_DRBL_1_P0 + (__n) \ + * (HQM_QSET1_IB_DRBL_1_P0 - HQM_QSET0_IB_DRBL_1_P0)) +#define HQM_QSET_IB_DRBL_2_P0(__n) (HQM_QSET0_IB_DRBL_2_P0 + (__n) \ + * (HQM_QSET1_IB_DRBL_2_P0 - HQM_QSET0_IB_DRBL_2_P0)) +#define HQM_QSET_RXQ_DRBL_P1(__n) (HQM_QSET0_RXQ_DRBL_P1 + (__n) \ + * (HQM_QSET1_RXQ_DRBL_P1 - HQM_QSET0_RXQ_DRBL_P1)) +#define HQM_QSET_TXQ_DRBL_P1(__n) (HQM_QSET0_TXQ_DRBL_P1 + (__n) \ + * (HQM_QSET1_TXQ_DRBL_P1 - HQM_QSET0_TXQ_DRBL_P1)) +#define HQM_QSET_IB_DRBL_1_P1(__n) (HQM_QSET0_IB_DRBL_1_P1 + (__n) \ + * (HQM_QSET1_IB_DRBL_1_P1 - HQM_QSET0_IB_DRBL_1_P1)) +#define HQM_QSET_IB_DRBL_2_P1(__n) (HQM_QSET0_IB_DRBL_2_P1 + (__n) \ + * (HQM_QSET1_IB_DRBL_2_P1 - HQM_QSET0_IB_DRBL_2_P1)) + +#define CPE_Q_NUM(__fn, __q) (((__fn) << 2) + (__q)) +#define RME_Q_NUM(__fn, __q) (((__fn) << 2) + (__q)) +#define CPE_Q_MASK(__q) ((__q) & 0x3) +#define RME_Q_MASK(__q) ((__q) & 0x3) + + +/* + * PCI MSI-X vector defines + */ +enum { + BFA_MSIX_CPE_Q0 = 0, + BFA_MSIX_CPE_Q1 = 1, + BFA_MSIX_CPE_Q2 = 2, + BFA_MSIX_CPE_Q3 = 3, + BFA_MSIX_RME_Q0 = 4, + BFA_MSIX_RME_Q1 = 5, + BFA_MSIX_RME_Q2 = 6, + BFA_MSIX_RME_Q3 = 7, + BFA_MSIX_LPU_ERR = 8, + BFA_MSIX_CT_MAX = 9, +}; + +/* + * And corresponding host interrupt status bit field defines + */ +#define __HFN_INT_CPE_Q0 0x00000001U +#define __HFN_INT_CPE_Q1 0x00000002U +#define __HFN_INT_CPE_Q2 0x00000004U +#define __HFN_INT_CPE_Q3 0x00000008U +#define __HFN_INT_CPE_Q4 0x00000010U +#define __HFN_INT_CPE_Q5 0x00000020U +#define __HFN_INT_CPE_Q6 0x00000040U +#define __HFN_INT_CPE_Q7 0x00000080U +#define __HFN_INT_RME_Q0 0x00000100U +#define __HFN_INT_RME_Q1 0x00000200U +#define __HFN_INT_RME_Q2 0x00000400U +#define __HFN_INT_RME_Q3 0x00000800U +#define __HFN_INT_RME_Q4 0x00001000U +#define __HFN_INT_RME_Q5 0x00002000U +#define __HFN_INT_RME_Q6 0x00004000U +#define __HFN_INT_RME_Q7 0x00008000U +#define __HFN_INT_ERR_EMC 0x00010000U +#define __HFN_INT_ERR_LPU0 0x00020000U +#define __HFN_INT_ERR_LPU1 0x00040000U +#define __HFN_INT_ERR_PSS 0x00080000U +#define __HFN_INT_MBOX_LPU0 0x00100000U +#define __HFN_INT_MBOX_LPU1 0x00200000U +#define __HFN_INT_MBOX1_LPU0 0x00400000U +#define __HFN_INT_MBOX1_LPU1 0x00800000U +#define __HFN_INT_LL_HALT 0x01000000U +#define __HFN_INT_CPE_MASK 0x000000ffU +#define __HFN_INT_RME_MASK 0x0000ff00U + + +/* + * catapult memory map. + */ +#define LL_PGN_HQM0 0x0096 +#define LL_PGN_HQM1 0x0097 +#define PSS_SMEM_PAGE_START 0x8000 +#define PSS_SMEM_PGNUM(_pg0, _ma) ((_pg0) + ((_ma) >> 15)) +#define PSS_SMEM_PGOFF(_ma) ((_ma) & 0x7fff) + +/* + * End of catapult memory map + */ + + +#endif /* __BFI_CTREG_H__ */ diff --git a/drivers/scsi/bfa/bfi_ms.h b/drivers/scsi/bfa/bfi_ms.h new file mode 100644 index 000000000000..69ac85f9e938 --- /dev/null +++ b/drivers/scsi/bfa/bfi_ms.h @@ -0,0 +1,765 @@ +/* + * 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_MS_H__ +#define __BFI_MS_H__ + +#include "bfi.h" +#include "bfa_fc.h" +#include "bfa_defs_svc.h" + +#pragma pack(1) + +enum bfi_iocfc_h2i_msgs { + BFI_IOCFC_H2I_CFG_REQ = 1, + BFI_IOCFC_H2I_SET_INTR_REQ = 2, + BFI_IOCFC_H2I_UPDATEQ_REQ = 3, +}; + +enum bfi_iocfc_i2h_msgs { + BFI_IOCFC_I2H_CFG_REPLY = BFA_I2HM(1), + BFI_IOCFC_I2H_UPDATEQ_RSP = BFA_I2HM(3), +}; + +struct bfi_iocfc_cfg_s { + u8 num_cqs; /* Number of CQs to be used */ + u8 sense_buf_len; /* SCSI sense length */ + u16 rsvd_1; + u32 endian_sig; /* endian signature of host */ + + /** + * Request and response circular queue base addresses, size and + * shadow index pointers. + */ + union bfi_addr_u req_cq_ba[BFI_IOC_MAX_CQS]; + union bfi_addr_u req_shadow_ci[BFI_IOC_MAX_CQS]; + u16 req_cq_elems[BFI_IOC_MAX_CQS]; + union bfi_addr_u rsp_cq_ba[BFI_IOC_MAX_CQS]; + union bfi_addr_u rsp_shadow_pi[BFI_IOC_MAX_CQS]; + u16 rsp_cq_elems[BFI_IOC_MAX_CQS]; + + union bfi_addr_u stats_addr; /* DMA-able address for stats */ + union bfi_addr_u cfgrsp_addr; /* config response dma address */ + union bfi_addr_u ioim_snsbase; /* IO sense buffer base address */ + struct bfa_iocfc_intr_attr_s intr_attr; /* IOC interrupt attributes */ +}; + +/** + * Boot target wwn information for this port. This contains either the stored + * or discovered boot target port wwns for the port. + */ +struct bfi_iocfc_bootwwns { + wwn_t wwn[BFA_BOOT_BOOTLUN_MAX]; + u8 nwwns; + u8 rsvd[7]; +}; + +struct bfi_iocfc_cfgrsp_s { + struct bfa_iocfc_fwcfg_s fwcfg; + struct bfa_iocfc_intr_attr_s intr_attr; + struct bfi_iocfc_bootwwns bootwwns; + struct bfi_pbc_s pbc_cfg; +}; + +/** + * BFI_IOCFC_H2I_CFG_REQ message + */ +struct bfi_iocfc_cfg_req_s { + struct bfi_mhdr_s mh; + union bfi_addr_u ioc_cfg_dma_addr; +}; + + +/** + * BFI_IOCFC_I2H_CFG_REPLY message + */ +struct bfi_iocfc_cfg_reply_s { + struct bfi_mhdr_s mh; /* Common msg header */ + u8 cfg_success; /* cfg reply status */ + u8 lpu_bm; /* LPUs assigned for this IOC */ + u8 rsvd[2]; +}; + + +/** + * BFI_IOCFC_H2I_SET_INTR_REQ message + */ +struct bfi_iocfc_set_intr_req_s { + struct bfi_mhdr_s mh; /* common msg header */ + u8 coalesce; /* enable intr coalescing */ + u8 rsvd[3]; + u16 delay; /* delay timer 0..1125us */ + u16 latency; /* latency timer 0..225us */ +}; + + +/** + * BFI_IOCFC_H2I_UPDATEQ_REQ message + */ +struct bfi_iocfc_updateq_req_s { + struct bfi_mhdr_s mh; /* common msg header */ + u32 reqq_ba; /* reqq base addr */ + u32 rspq_ba; /* rspq base addr */ + u32 reqq_sci; /* reqq shadow ci */ + u32 rspq_spi; /* rspq shadow pi */ +}; + + +/** + * BFI_IOCFC_I2H_UPDATEQ_RSP message + */ +struct bfi_iocfc_updateq_rsp_s { + struct bfi_mhdr_s mh; /* common msg header */ + u8 status; /* updateq status */ + u8 rsvd[3]; +}; + + +/** + * H2I Messages + */ +union bfi_iocfc_h2i_msg_u { + struct bfi_mhdr_s mh; + struct bfi_iocfc_cfg_req_s cfg_req; + struct bfi_iocfc_updateq_req_s updateq_req; + u32 mboxmsg[BFI_IOC_MSGSZ]; +}; + + +/** + * I2H Messages + */ +union bfi_iocfc_i2h_msg_u { + struct bfi_mhdr_s mh; + struct bfi_iocfc_cfg_reply_s cfg_reply; + struct bfi_iocfc_updateq_rsp_s updateq_rsp; + u32 mboxmsg[BFI_IOC_MSGSZ]; +}; + + +enum bfi_fcport_h2i { + BFI_FCPORT_H2I_ENABLE_REQ = (1), + BFI_FCPORT_H2I_DISABLE_REQ = (2), + BFI_FCPORT_H2I_SET_SVC_PARAMS_REQ = (3), + BFI_FCPORT_H2I_STATS_GET_REQ = (4), + BFI_FCPORT_H2I_STATS_CLEAR_REQ = (5), +}; + + +enum bfi_fcport_i2h { + BFI_FCPORT_I2H_ENABLE_RSP = BFA_I2HM(1), + BFI_FCPORT_I2H_DISABLE_RSP = BFA_I2HM(2), + BFI_FCPORT_I2H_SET_SVC_PARAMS_RSP = BFA_I2HM(3), + BFI_FCPORT_I2H_STATS_GET_RSP = BFA_I2HM(4), + BFI_FCPORT_I2H_STATS_CLEAR_RSP = BFA_I2HM(5), + BFI_FCPORT_I2H_EVENT = BFA_I2HM(6), + BFI_FCPORT_I2H_TRUNK_SCN = BFA_I2HM(7), + BFI_FCPORT_I2H_ENABLE_AEN = BFA_I2HM(8), + BFI_FCPORT_I2H_DISABLE_AEN = BFA_I2HM(9), +}; + + +/** + * Generic REQ type + */ +struct bfi_fcport_req_s { + struct bfi_mhdr_s mh; /* msg header */ + u32 msgtag; /* msgtag for reply */ +}; + +/** + * Generic RSP type + */ +struct bfi_fcport_rsp_s { + struct bfi_mhdr_s mh; /* common msg header */ + u8 status; /* port enable status */ + u8 rsvd[3]; + u32 msgtag; /* msgtag for reply */ +}; + +/** + * BFI_FCPORT_H2I_ENABLE_REQ + */ +struct bfi_fcport_enable_req_s { + struct bfi_mhdr_s mh; /* msg header */ + u32 rsvd1; + wwn_t nwwn; /* node wwn of physical port */ + wwn_t pwwn; /* port wwn of physical port */ + struct bfa_port_cfg_s port_cfg; /* port configuration */ + union bfi_addr_u stats_dma_addr; /* DMA address for stats */ + u32 msgtag; /* msgtag for reply */ + u32 rsvd2; +}; + +/** + * BFI_FCPORT_H2I_SET_SVC_PARAMS_REQ + */ +struct bfi_fcport_set_svc_params_req_s { + struct bfi_mhdr_s mh; /* msg header */ + u16 tx_bbcredit; /* Tx credits */ + u16 rsvd; +}; + +/** + * BFI_FCPORT_I2H_EVENT + */ +struct bfi_fcport_event_s { + struct bfi_mhdr_s mh; /* common msg header */ + struct bfa_port_link_s link_state; +}; + +/** + * BFI_FCPORT_I2H_TRUNK_SCN + */ +struct bfi_fcport_trunk_link_s { + wwn_t trunk_wwn; + u8 fctl; /* bfa_trunk_link_fctl_t */ + u8 state; /* bfa_trunk_link_state_t */ + u8 speed; /* bfa_port_speed_t */ + u8 rsvd; + u32 deskew; +}; + +#define BFI_FCPORT_MAX_LINKS 2 +struct bfi_fcport_trunk_scn_s { + struct bfi_mhdr_s mh; + u8 trunk_state; /* bfa_trunk_state_t */ + u8 trunk_speed; /* bfa_port_speed_t */ + u8 rsvd_a[2]; + struct bfi_fcport_trunk_link_s tlink[BFI_FCPORT_MAX_LINKS]; +}; + +/** + * fcport H2I message + */ +union bfi_fcport_h2i_msg_u { + struct bfi_mhdr_s *mhdr; + struct bfi_fcport_enable_req_s *penable; + struct bfi_fcport_req_s *pdisable; + struct bfi_fcport_set_svc_params_req_s *psetsvcparams; + struct bfi_fcport_req_s *pstatsget; + struct bfi_fcport_req_s *pstatsclear; +}; + +/** + * fcport I2H message + */ +union bfi_fcport_i2h_msg_u { + struct bfi_msg_s *msg; + struct bfi_fcport_rsp_s *penable_rsp; + struct bfi_fcport_rsp_s *pdisable_rsp; + struct bfi_fcport_rsp_s *psetsvcparams_rsp; + struct bfi_fcport_rsp_s *pstatsget_rsp; + struct bfi_fcport_rsp_s *pstatsclear_rsp; + struct bfi_fcport_event_s *event; + struct bfi_fcport_trunk_scn_s *trunk_scn; +}; + +enum bfi_fcxp_h2i { + BFI_FCXP_H2I_SEND_REQ = 1, +}; + +enum bfi_fcxp_i2h { + BFI_FCXP_I2H_SEND_RSP = BFA_I2HM(1), +}; + +#define BFA_FCXP_MAX_SGES 2 + +/** + * FCXP send request structure + */ +struct bfi_fcxp_send_req_s { + struct bfi_mhdr_s mh; /* Common msg header */ + u16 fcxp_tag; /* driver request tag */ + u16 max_frmsz; /* max send frame size */ + u16 vf_id; /* vsan tag if applicable */ + u16 rport_fw_hndl; /* FW Handle for the remote port */ + u8 class; /* FC class used for req/rsp */ + u8 rsp_timeout; /* timeout in secs, 0-no response */ + u8 cts; /* continue sequence */ + u8 lp_tag; /* lport tag */ + struct fchs_s fchs; /* request FC header structure */ + u32 req_len; /* request payload length */ + u32 rsp_maxlen; /* max response length expected */ + struct bfi_sge_s req_sge[BFA_FCXP_MAX_SGES]; /* request buf */ + struct bfi_sge_s rsp_sge[BFA_FCXP_MAX_SGES]; /* response buf */ +}; + +/** + * FCXP send response structure + */ +struct bfi_fcxp_send_rsp_s { + struct bfi_mhdr_s mh; /* Common msg header */ + u16 fcxp_tag; /* send request tag */ + u8 req_status; /* request status */ + u8 rsvd; + u32 rsp_len; /* actual response length */ + u32 residue_len; /* residual response length */ + struct fchs_s fchs; /* response FC header structure */ +}; + +enum bfi_uf_h2i { + BFI_UF_H2I_BUF_POST = 1, +}; + +enum bfi_uf_i2h { + BFI_UF_I2H_FRM_RCVD = BFA_I2HM(1), +}; + +#define BFA_UF_MAX_SGES 2 + +struct bfi_uf_buf_post_s { + struct bfi_mhdr_s mh; /* Common msg header */ + u16 buf_tag; /* buffer tag */ + u16 buf_len; /* total buffer length */ + struct bfi_sge_s sge[BFA_UF_MAX_SGES]; /* buffer DMA SGEs */ +}; + +struct bfi_uf_frm_rcvd_s { + struct bfi_mhdr_s mh; /* Common msg header */ + u16 buf_tag; /* buffer tag */ + u16 rsvd; + u16 frm_len; /* received frame length */ + u16 xfr_len; /* tranferred length */ +}; + +enum bfi_lps_h2i_msgs { + BFI_LPS_H2I_LOGIN_REQ = 1, + BFI_LPS_H2I_LOGOUT_REQ = 2, +}; + +enum bfi_lps_i2h_msgs { + BFI_LPS_H2I_LOGIN_RSP = BFA_I2HM(1), + BFI_LPS_H2I_LOGOUT_RSP = BFA_I2HM(2), + BFI_LPS_H2I_CVL_EVENT = BFA_I2HM(3), +}; + +struct bfi_lps_login_req_s { + struct bfi_mhdr_s mh; /* common msg header */ + u8 lp_tag; + u8 alpa; + u16 pdu_size; + wwn_t pwwn; + wwn_t nwwn; + u8 fdisc; + u8 auth_en; + u8 rsvd[2]; +}; + +struct bfi_lps_login_rsp_s { + struct bfi_mhdr_s mh; /* common msg header */ + u8 lp_tag; + u8 status; + u8 lsrjt_rsn; + u8 lsrjt_expl; + wwn_t port_name; + wwn_t node_name; + u16 bb_credit; + u8 f_port; + u8 npiv_en; + u32 lp_pid:24; + u32 auth_req:8; + mac_t lp_mac; + mac_t fcf_mac; + u8 ext_status; + u8 brcd_switch; /* attached peer is brcd switch */ +}; + +struct bfi_lps_logout_req_s { + struct bfi_mhdr_s mh; /* common msg header */ + u8 lp_tag; + u8 rsvd[3]; + wwn_t port_name; +}; + +struct bfi_lps_logout_rsp_s { + struct bfi_mhdr_s mh; /* common msg header */ + u8 lp_tag; + u8 status; + u8 rsvd[2]; +}; + +struct bfi_lps_cvl_event_s { + struct bfi_mhdr_s mh; /* common msg header */ + u8 lp_tag; + u8 rsvd[3]; +}; + +union bfi_lps_h2i_msg_u { + struct bfi_mhdr_s *msg; + struct bfi_lps_login_req_s *login_req; + struct bfi_lps_logout_req_s *logout_req; +}; + +union bfi_lps_i2h_msg_u { + struct bfi_msg_s *msg; + struct bfi_lps_login_rsp_s *login_rsp; + struct bfi_lps_logout_rsp_s *logout_rsp; + struct bfi_lps_cvl_event_s *cvl_event; +}; + +enum bfi_rport_h2i_msgs { + BFI_RPORT_H2I_CREATE_REQ = 1, + BFI_RPORT_H2I_DELETE_REQ = 2, + BFI_RPORT_H2I_SET_SPEED_REQ = 3, +}; + +enum bfi_rport_i2h_msgs { + BFI_RPORT_I2H_CREATE_RSP = BFA_I2HM(1), + BFI_RPORT_I2H_DELETE_RSP = BFA_I2HM(2), + BFI_RPORT_I2H_QOS_SCN = BFA_I2HM(3), +}; + +struct bfi_rport_create_req_s { + struct bfi_mhdr_s mh; /* common msg header */ + u16 bfa_handle; /* host rport handle */ + u16 max_frmsz; /* max rcv pdu size */ + u32 pid:24, /* remote port ID */ + lp_tag:8; /* local port tag */ + u32 local_pid:24, /* local port ID */ + cisc:8; + u8 fc_class; /* supported FC classes */ + u8 vf_en; /* virtual fabric enable */ + u16 vf_id; /* virtual fabric ID */ +}; + +struct bfi_rport_create_rsp_s { + struct bfi_mhdr_s mh; /* common msg header */ + u8 status; /* rport creation status */ + u8 rsvd[3]; + u16 bfa_handle; /* host rport handle */ + u16 fw_handle; /* firmware rport handle */ + struct bfa_rport_qos_attr_s qos_attr; /* QoS Attributes */ +}; + +struct bfa_rport_speed_req_s { + struct bfi_mhdr_s mh; /* common msg header */ + u16 fw_handle; /* firmware rport handle */ + u8 speed; /* rport's speed via RPSC */ + u8 rsvd; +}; + +struct bfi_rport_delete_req_s { + struct bfi_mhdr_s mh; /* common msg header */ + u16 fw_handle; /* firmware rport handle */ + u16 rsvd; +}; + +struct bfi_rport_delete_rsp_s { + struct bfi_mhdr_s mh; /* common msg header */ + u16 bfa_handle; /* host rport handle */ + u8 status; /* rport deletion status */ + u8 rsvd; +}; + +struct bfi_rport_qos_scn_s { + struct bfi_mhdr_s mh; /* common msg header */ + u16 bfa_handle; /* host rport handle */ + u16 rsvd; + struct bfa_rport_qos_attr_s old_qos_attr; /* Old QoS Attributes */ + struct bfa_rport_qos_attr_s new_qos_attr; /* New QoS Attributes */ +}; + +union bfi_rport_h2i_msg_u { + struct bfi_msg_s *msg; + struct bfi_rport_create_req_s *create_req; + struct bfi_rport_delete_req_s *delete_req; + struct bfi_rport_speed_req_s *speed_req; +}; + +union bfi_rport_i2h_msg_u { + struct bfi_msg_s *msg; + struct bfi_rport_create_rsp_s *create_rsp; + struct bfi_rport_delete_rsp_s *delete_rsp; + struct bfi_rport_qos_scn_s *qos_scn_evt; +}; + +/* + * Initiator mode I-T nexus interface defines. + */ + +enum bfi_itnim_h2i { + BFI_ITNIM_H2I_CREATE_REQ = 1, /* i-t nexus creation */ + BFI_ITNIM_H2I_DELETE_REQ = 2, /* i-t nexus deletion */ +}; + +enum bfi_itnim_i2h { + BFI_ITNIM_I2H_CREATE_RSP = BFA_I2HM(1), + BFI_ITNIM_I2H_DELETE_RSP = BFA_I2HM(2), + BFI_ITNIM_I2H_SLER_EVENT = BFA_I2HM(3), +}; + +struct bfi_itnim_create_req_s { + struct bfi_mhdr_s mh; /* common msg header */ + u16 fw_handle; /* f/w handle for itnim */ + u8 class; /* FC class for IO */ + u8 seq_rec; /* sequence recovery support */ + u8 msg_no; /* seq id of the msg */ +}; + +struct bfi_itnim_create_rsp_s { + struct bfi_mhdr_s mh; /* common msg header */ + u16 bfa_handle; /* bfa handle for itnim */ + u8 status; /* fcp request status */ + u8 seq_id; /* seq id of the msg */ +}; + +struct bfi_itnim_delete_req_s { + struct bfi_mhdr_s mh; /* common msg header */ + u16 fw_handle; /* f/w itnim handle */ + u8 seq_id; /* seq id of the msg */ + u8 rsvd; +}; + +struct bfi_itnim_delete_rsp_s { + struct bfi_mhdr_s mh; /* common msg header */ + u16 bfa_handle; /* bfa handle for itnim */ + u8 status; /* fcp request status */ + u8 seq_id; /* seq id of the msg */ +}; + +struct bfi_itnim_sler_event_s { + struct bfi_mhdr_s mh; /* common msg header */ + u16 bfa_handle; /* bfa handle for itnim */ + u16 rsvd; +}; + +union bfi_itnim_h2i_msg_u { + struct bfi_itnim_create_req_s *create_req; + struct bfi_itnim_delete_req_s *delete_req; + struct bfi_msg_s *msg; +}; + +union bfi_itnim_i2h_msg_u { + struct bfi_itnim_create_rsp_s *create_rsp; + struct bfi_itnim_delete_rsp_s *delete_rsp; + struct bfi_itnim_sler_event_s *sler_event; + struct bfi_msg_s *msg; +}; + +/* + * Initiator mode IO interface defines. + */ + +enum bfi_ioim_h2i { + BFI_IOIM_H2I_IOABORT_REQ = 1, /* IO abort request */ + BFI_IOIM_H2I_IOCLEANUP_REQ = 2, /* IO cleanup request */ +}; + +enum bfi_ioim_i2h { + BFI_IOIM_I2H_IO_RSP = BFA_I2HM(1), /* non-fp IO response */ + BFI_IOIM_I2H_IOABORT_RSP = BFA_I2HM(2), /* ABORT rsp */ +}; + +/** + * IO command DIF info + */ +struct bfi_ioim_dif_s { + u32 dif_info[4]; +}; + +/** + * FCP IO messages overview + * + * @note + * - Max CDB length supported is 64 bytes. + * - SCSI Linked commands and SCSI bi-directional Commands not + * supported. + * + */ +struct bfi_ioim_req_s { + struct bfi_mhdr_s mh; /* Common msg header */ + u16 io_tag; /* I/O tag */ + u16 rport_hdl; /* itnim/rport firmware handle */ + struct fcp_cmnd_s cmnd; /* IO request info */ + + /** + * SG elements array within the IO request must be double word + * aligned. This aligment is required to optimize SGM setup for the IO. + */ + struct bfi_sge_s sges[BFI_SGE_INLINE_MAX]; + u8 io_timeout; + u8 dif_en; + u8 rsvd_a[2]; + struct bfi_ioim_dif_s dif; +}; + +/** + * This table shows various IO status codes from firmware and their + * meaning. Host driver can use these status codes to further process + * IO completions. + * + * BFI_IOIM_STS_OK : IO completed with error free SCSI & + * transport status. + * io-tag can be reused. + * + * BFA_IOIM_STS_SCSI_ERR : IO completed with scsi error. + * - io-tag can be reused. + * + * BFI_IOIM_STS_HOST_ABORTED : IO was aborted successfully due to + * host request. + * - io-tag cannot be reused yet. + * + * BFI_IOIM_STS_ABORTED : IO was aborted successfully + * internally by f/w. + * - io-tag cannot be reused yet. + * + * BFI_IOIM_STS_TIMEDOUT : IO timedout and ABTS/RRQ is happening + * in the firmware and + * - io-tag cannot be reused yet. + * + * BFI_IOIM_STS_SQER_NEEDED : Firmware could not recover the IO + * with sequence level error + * logic and hence host needs to retry + * this IO with a different IO tag + * - io-tag cannot be used yet. + * + * BFI_IOIM_STS_NEXUS_ABORT : Second Level Error Recovery from host + * is required because 2 consecutive ABTS + * timedout and host needs logout and + * re-login with the target + * - io-tag cannot be used yet. + * + * BFI_IOIM_STS_UNDERRUN : IO completed with SCSI status good, + * but the data tranferred is less than + * the fcp data length in the command. + * ex. SCSI INQUIRY where transferred + * data length and residue count in FCP + * response accounts for total fcp-dl + * - io-tag can be reused. + * + * BFI_IOIM_STS_OVERRUN : IO completed with SCSI status good, + * but the data transerred is more than + * fcp data length in the command. ex. + * TAPE IOs where blocks can of unequal + * lengths. + * - io-tag can be reused. + * + * BFI_IOIM_STS_RES_FREE : Firmware has completed using io-tag + * during abort process + * - io-tag can be reused. + * + * BFI_IOIM_STS_PROTO_ERR : Firmware detected a protocol error. + * ex target sent more data than + * requested, or there was data frame + * loss and other reasons + * - io-tag cannot be used yet. + * + * BFI_IOIM_STS_DIF_ERR : Firwmare detected DIF error. ex: DIF + * CRC err or Ref Tag err or App tag err. + * - io-tag can be reused. + * + * BFA_IOIM_STS_TSK_MGT_ABORT : IO was aborted because of Task + * Management command from the host + * - io-tag can be reused. + * + * BFI_IOIM_STS_UTAG : Firmware does not know about this + * io_tag. + * - io-tag can be reused. + */ +enum bfi_ioim_status { + BFI_IOIM_STS_OK = 0, + BFI_IOIM_STS_HOST_ABORTED = 1, + BFI_IOIM_STS_ABORTED = 2, + BFI_IOIM_STS_TIMEDOUT = 3, + BFI_IOIM_STS_RES_FREE = 4, + BFI_IOIM_STS_SQER_NEEDED = 5, + BFI_IOIM_STS_PROTO_ERR = 6, + BFI_IOIM_STS_UTAG = 7, + BFI_IOIM_STS_PATHTOV = 8, +}; + +#define BFI_IOIM_SNSLEN (256) +/** + * I/O response message + */ +struct bfi_ioim_rsp_s { + struct bfi_mhdr_s mh; /* common msg header */ + u16 io_tag; /* completed IO tag */ + u16 bfa_rport_hndl; /* releated rport handle */ + u8 io_status; /* IO completion status */ + u8 reuse_io_tag; /* IO tag can be reused */ + u16 abort_tag; /* host abort request tag */ + u8 scsi_status; /* scsi status from target */ + u8 sns_len; /* scsi sense length */ + u8 resid_flags; /* IO residue flags */ + u8 rsvd_a; + u32 residue; /* IO residual length in bytes */ + u32 rsvd_b[3]; +}; + +struct bfi_ioim_abort_req_s { + struct bfi_mhdr_s mh; /* Common msg header */ + u16 io_tag; /* I/O tag */ + u16 abort_tag; /* unique request tag */ +}; + +/* + * Initiator mode task management command interface defines. + */ + +enum bfi_tskim_h2i { + BFI_TSKIM_H2I_TM_REQ = 1, /* task-mgmt command */ + BFI_TSKIM_H2I_ABORT_REQ = 2, /* task-mgmt command */ +}; + +enum bfi_tskim_i2h { + BFI_TSKIM_I2H_TM_RSP = BFA_I2HM(1), +}; + +struct bfi_tskim_req_s { + struct bfi_mhdr_s mh; /* Common msg header */ + u16 tsk_tag; /* task management tag */ + u16 itn_fhdl; /* itn firmware handle */ + lun_t lun; /* LU number */ + u8 tm_flags; /* see enum fcp_tm_cmnd */ + u8 t_secs; /* Timeout value in seconds */ + u8 rsvd[2]; +}; + +struct bfi_tskim_abortreq_s { + struct bfi_mhdr_s mh; /* Common msg header */ + u16 tsk_tag; /* task management tag */ + u16 rsvd; +}; + +enum bfi_tskim_status { + /* + * Following are FCP-4 spec defined status codes, + * **DO NOT CHANGE THEM ** + */ + BFI_TSKIM_STS_OK = 0, + BFI_TSKIM_STS_NOT_SUPP = 4, + BFI_TSKIM_STS_FAILED = 5, + + /** + * Defined by BFA + */ + BFI_TSKIM_STS_TIMEOUT = 10, /* TM request timedout */ + BFI_TSKIM_STS_ABORTED = 11, /* Aborted on host request */ +}; + +struct bfi_tskim_rsp_s { + struct bfi_mhdr_s mh; /* Common msg header */ + u16 tsk_tag; /* task mgmt cmnd tag */ + u8 tsk_status; /* @ref bfi_tskim_status */ + u8 rsvd; +}; + +#pragma pack() + +#endif /* __BFI_MS_H__ */ diff --git a/drivers/scsi/bfa/fab.c b/drivers/scsi/bfa/fab.c deleted file mode 100644 index 7e3a4d5d7bb4..000000000000 --- a/drivers/scsi/bfa/fab.c +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#include <bfa.h> -#include <bfa_svc.h> -#include "fcs_lport.h" -#include "fcs_rport.h" -#include "lport_priv.h" - -/** - * fab.c port fab implementation. - */ - -/** - * bfa_fcs_port_fab_public port fab public functions - */ - -/** - * Called by port to initialize fabric services of the base port. - */ -void -bfa_fcs_port_fab_init(struct bfa_fcs_port_s *port) -{ - bfa_fcs_port_ns_init(port); - bfa_fcs_port_scn_init(port); - bfa_fcs_port_ms_init(port); -} - -/** - * Called by port to notify transition to online state. - */ -void -bfa_fcs_port_fab_online(struct bfa_fcs_port_s *port) -{ - bfa_fcs_port_ns_online(port); - bfa_fcs_port_scn_online(port); -} - -/** - * Called by port to notify transition to offline state. - */ -void -bfa_fcs_port_fab_offline(struct bfa_fcs_port_s *port) -{ - bfa_fcs_port_ns_offline(port); - bfa_fcs_port_scn_offline(port); - bfa_fcs_port_ms_offline(port); -} diff --git a/drivers/scsi/bfa/fabric.c b/drivers/scsi/bfa/fabric.c deleted file mode 100644 index ddd4ba9317e6..000000000000 --- a/drivers/scsi/bfa/fabric.c +++ /dev/null @@ -1,1323 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/** - * fabric.c Fabric module implementation. - */ - -#include "fcs_fabric.h" -#include "fcs_lport.h" -#include "fcs_vport.h" -#include "fcs_trcmod.h" -#include "fcs_fcxp.h" -#include "fcs_auth.h" -#include "fcs.h" -#include "fcbuild.h" -#include <log/bfa_log_fcs.h> -#include <aen/bfa_aen_port.h> -#include <bfa_svc.h> - -BFA_TRC_FILE(FCS, FABRIC); - -#define BFA_FCS_FABRIC_RETRY_DELAY (2000) /* Milliseconds */ -#define BFA_FCS_FABRIC_CLEANUP_DELAY (10000) /* Milliseconds */ - -#define bfa_fcs_fabric_set_opertype(__fabric) do { \ - if (bfa_fcport_get_topology((__fabric)->fcs->bfa) \ - == BFA_PPORT_TOPOLOGY_P2P) \ - (__fabric)->oper_type = BFA_PPORT_TYPE_NPORT; \ - else \ - (__fabric)->oper_type = BFA_PPORT_TYPE_NLPORT; \ -} while (0) - -/* - * forward declarations - */ -static void bfa_fcs_fabric_init(struct bfa_fcs_fabric_s *fabric); -static void bfa_fcs_fabric_login(struct bfa_fcs_fabric_s *fabric); -static void bfa_fcs_fabric_notify_online(struct bfa_fcs_fabric_s *fabric); -static void bfa_fcs_fabric_notify_offline(struct bfa_fcs_fabric_s *fabric); -static void bfa_fcs_fabric_delay(void *cbarg); -static void bfa_fcs_fabric_delete(struct bfa_fcs_fabric_s *fabric); -static void bfa_fcs_fabric_delete_comp(void *cbarg); -static void bfa_fcs_fabric_process_uf(struct bfa_fcs_fabric_s *fabric, - struct fchs_s *fchs, u16 len); -static void bfa_fcs_fabric_process_flogi(struct bfa_fcs_fabric_s *fabric, - struct fchs_s *fchs, u16 len); -static void bfa_fcs_fabric_send_flogi_acc(struct bfa_fcs_fabric_s *fabric); -static void bfa_fcs_fabric_flogiacc_comp(void *fcsarg, - struct bfa_fcxp_s *fcxp, - void *cbarg, bfa_status_t status, - u32 rsp_len, - u32 resid_len, - struct fchs_s *rspfchs); -/** - * fcs_fabric_sm fabric state machine functions - */ - -/** - * Fabric state machine events - */ -enum bfa_fcs_fabric_event { - BFA_FCS_FABRIC_SM_CREATE = 1, /* fabric create from driver */ - BFA_FCS_FABRIC_SM_DELETE = 2, /* fabric delete from driver */ - BFA_FCS_FABRIC_SM_LINK_DOWN = 3, /* link down from port */ - BFA_FCS_FABRIC_SM_LINK_UP = 4, /* link up from port */ - BFA_FCS_FABRIC_SM_CONT_OP = 5, /* continue op from flogi/auth */ - BFA_FCS_FABRIC_SM_RETRY_OP = 6, /* continue op from flogi/auth */ - BFA_FCS_FABRIC_SM_NO_FABRIC = 7, /* no fabric from flogi/auth - */ - BFA_FCS_FABRIC_SM_PERF_EVFP = 8, /* perform EVFP from - *flogi/auth */ - BFA_FCS_FABRIC_SM_ISOLATE = 9, /* isolate from EVFP processing */ - BFA_FCS_FABRIC_SM_NO_TAGGING = 10,/* no VFT tagging from EVFP */ - BFA_FCS_FABRIC_SM_DELAYED = 11, /* timeout delay event */ - BFA_FCS_FABRIC_SM_AUTH_FAILED = 12, /* authentication failed */ - BFA_FCS_FABRIC_SM_AUTH_SUCCESS = 13, /* authentication successful - */ - BFA_FCS_FABRIC_SM_DELCOMP = 14, /* all vports deleted event */ - BFA_FCS_FABRIC_SM_LOOPBACK = 15, /* Received our own FLOGI */ - BFA_FCS_FABRIC_SM_START = 16, /* fabric delete from driver */ -}; - -static void bfa_fcs_fabric_sm_uninit(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event); -static void bfa_fcs_fabric_sm_created(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event); -static void bfa_fcs_fabric_sm_linkdown(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event); -static void bfa_fcs_fabric_sm_flogi(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event); -static void bfa_fcs_fabric_sm_flogi_retry(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event); -static void bfa_fcs_fabric_sm_auth(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event); -static void bfa_fcs_fabric_sm_auth_failed(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event); -static void bfa_fcs_fabric_sm_loopback(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event); -static void bfa_fcs_fabric_sm_nofabric(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event); -static void bfa_fcs_fabric_sm_online(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event); -static void bfa_fcs_fabric_sm_evfp(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event); -static void bfa_fcs_fabric_sm_evfp_done(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event); -static void bfa_fcs_fabric_sm_isolated(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event); -static void bfa_fcs_fabric_sm_deleting(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event); -/** - * Beginning state before fabric creation. - */ -static void -bfa_fcs_fabric_sm_uninit(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event) -{ - bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); - bfa_trc(fabric->fcs, event); - - switch (event) { - case BFA_FCS_FABRIC_SM_CREATE: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_created); - bfa_fcs_fabric_init(fabric); - bfa_fcs_lport_init(&fabric->bport, &fabric->bport.port_cfg); - break; - - case BFA_FCS_FABRIC_SM_LINK_UP: - case BFA_FCS_FABRIC_SM_LINK_DOWN: - break; - - default: - bfa_sm_fault(fabric->fcs, event); - } -} - -/** - * Beginning state before fabric creation. - */ -static void -bfa_fcs_fabric_sm_created(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event) -{ - bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); - bfa_trc(fabric->fcs, event); - - switch (event) { - case BFA_FCS_FABRIC_SM_START: - if (bfa_fcport_is_linkup(fabric->fcs->bfa)) { - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_flogi); - bfa_fcs_fabric_login(fabric); - } else - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown); - break; - - case BFA_FCS_FABRIC_SM_LINK_UP: - case BFA_FCS_FABRIC_SM_LINK_DOWN: - break; - - case BFA_FCS_FABRIC_SM_DELETE: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_uninit); - bfa_fcs_modexit_comp(fabric->fcs); - break; - - default: - bfa_sm_fault(fabric->fcs, event); - } -} - -/** - * Link is down, awaiting LINK UP event from port. This is also the - * first state at fabric creation. - */ -static void -bfa_fcs_fabric_sm_linkdown(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event) -{ - bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); - bfa_trc(fabric->fcs, event); - - switch (event) { - case BFA_FCS_FABRIC_SM_LINK_UP: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_flogi); - bfa_fcs_fabric_login(fabric); - break; - - case BFA_FCS_FABRIC_SM_RETRY_OP: - break; - - case BFA_FCS_FABRIC_SM_DELETE: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting); - bfa_fcs_fabric_delete(fabric); - break; - - default: - bfa_sm_fault(fabric->fcs, event); - } -} - -/** - * FLOGI is in progress, awaiting FLOGI reply. - */ -static void -bfa_fcs_fabric_sm_flogi(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event) -{ - bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); - bfa_trc(fabric->fcs, event); - - switch (event) { - case BFA_FCS_FABRIC_SM_CONT_OP: - - bfa_fcport_set_tx_bbcredit(fabric->fcs->bfa, fabric->bb_credit); - fabric->fab_type = BFA_FCS_FABRIC_SWITCHED; - - if (fabric->auth_reqd && fabric->is_auth) { - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_auth); - bfa_trc(fabric->fcs, event); - } else { - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_online); - bfa_fcs_fabric_notify_online(fabric); - } - break; - - case BFA_FCS_FABRIC_SM_RETRY_OP: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_flogi_retry); - bfa_timer_start(fabric->fcs->bfa, &fabric->delay_timer, - bfa_fcs_fabric_delay, fabric, - BFA_FCS_FABRIC_RETRY_DELAY); - break; - - case BFA_FCS_FABRIC_SM_LOOPBACK: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_loopback); - bfa_lps_discard(fabric->lps); - bfa_fcs_fabric_set_opertype(fabric); - break; - - case BFA_FCS_FABRIC_SM_NO_FABRIC: - fabric->fab_type = BFA_FCS_FABRIC_N2N; - bfa_fcport_set_tx_bbcredit(fabric->fcs->bfa, fabric->bb_credit); - bfa_fcs_fabric_notify_online(fabric); - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_nofabric); - break; - - case BFA_FCS_FABRIC_SM_LINK_DOWN: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown); - bfa_lps_discard(fabric->lps); - break; - - case BFA_FCS_FABRIC_SM_DELETE: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting); - bfa_lps_discard(fabric->lps); - bfa_fcs_fabric_delete(fabric); - break; - - default: - bfa_sm_fault(fabric->fcs, event); - } -} - - -static void -bfa_fcs_fabric_sm_flogi_retry(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event) -{ - bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); - bfa_trc(fabric->fcs, event); - - switch (event) { - case BFA_FCS_FABRIC_SM_DELAYED: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_flogi); - bfa_fcs_fabric_login(fabric); - break; - - case BFA_FCS_FABRIC_SM_LINK_DOWN: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown); - bfa_timer_stop(&fabric->delay_timer); - break; - - case BFA_FCS_FABRIC_SM_DELETE: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting); - bfa_timer_stop(&fabric->delay_timer); - bfa_fcs_fabric_delete(fabric); - break; - - default: - bfa_sm_fault(fabric->fcs, event); - } -} - -/** - * Authentication is in progress, awaiting authentication results. - */ -static void -bfa_fcs_fabric_sm_auth(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event) -{ - bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); - bfa_trc(fabric->fcs, event); - - switch (event) { - case BFA_FCS_FABRIC_SM_AUTH_FAILED: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_auth_failed); - bfa_lps_discard(fabric->lps); - break; - - case BFA_FCS_FABRIC_SM_AUTH_SUCCESS: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_online); - bfa_fcs_fabric_notify_online(fabric); - break; - - case BFA_FCS_FABRIC_SM_PERF_EVFP: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_evfp); - break; - - case BFA_FCS_FABRIC_SM_LINK_DOWN: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown); - bfa_lps_discard(fabric->lps); - break; - - case BFA_FCS_FABRIC_SM_DELETE: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting); - bfa_fcs_fabric_delete(fabric); - break; - - default: - bfa_sm_fault(fabric->fcs, event); - } -} - -/** - * Authentication failed - */ -static void -bfa_fcs_fabric_sm_auth_failed(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event) -{ - bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); - bfa_trc(fabric->fcs, event); - - switch (event) { - case BFA_FCS_FABRIC_SM_LINK_DOWN: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown); - bfa_fcs_fabric_notify_offline(fabric); - break; - - case BFA_FCS_FABRIC_SM_DELETE: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting); - bfa_fcs_fabric_delete(fabric); - break; - - default: - bfa_sm_fault(fabric->fcs, event); - } -} - -/** - * Port is in loopback mode. - */ -static void -bfa_fcs_fabric_sm_loopback(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event) -{ - bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); - bfa_trc(fabric->fcs, event); - - switch (event) { - case BFA_FCS_FABRIC_SM_LINK_DOWN: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown); - bfa_fcs_fabric_notify_offline(fabric); - break; - - case BFA_FCS_FABRIC_SM_DELETE: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting); - bfa_fcs_fabric_delete(fabric); - break; - - default: - bfa_sm_fault(fabric->fcs, event); - } -} - -/** - * There is no attached fabric - private loop or NPort-to-NPort topology. - */ -static void -bfa_fcs_fabric_sm_nofabric(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event) -{ - bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); - bfa_trc(fabric->fcs, event); - - switch (event) { - case BFA_FCS_FABRIC_SM_LINK_DOWN: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown); - bfa_lps_discard(fabric->lps); - bfa_fcs_fabric_notify_offline(fabric); - break; - - case BFA_FCS_FABRIC_SM_DELETE: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting); - bfa_fcs_fabric_delete(fabric); - break; - - case BFA_FCS_FABRIC_SM_NO_FABRIC: - bfa_trc(fabric->fcs, fabric->bb_credit); - bfa_fcport_set_tx_bbcredit(fabric->fcs->bfa, fabric->bb_credit); - break; - - default: - bfa_sm_fault(fabric->fcs, event); - } -} - -/** - * Fabric is online - normal operating state. - */ -static void -bfa_fcs_fabric_sm_online(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event) -{ - bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); - bfa_trc(fabric->fcs, event); - - switch (event) { - case BFA_FCS_FABRIC_SM_LINK_DOWN: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown); - bfa_lps_discard(fabric->lps); - bfa_fcs_fabric_notify_offline(fabric); - break; - - case BFA_FCS_FABRIC_SM_DELETE: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting); - bfa_fcs_fabric_delete(fabric); - break; - - case BFA_FCS_FABRIC_SM_AUTH_FAILED: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_auth_failed); - bfa_lps_discard(fabric->lps); - break; - - case BFA_FCS_FABRIC_SM_AUTH_SUCCESS: - break; - - default: - bfa_sm_fault(fabric->fcs, event); - } -} - -/** - * Exchanging virtual fabric parameters. - */ -static void -bfa_fcs_fabric_sm_evfp(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event) -{ - bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); - bfa_trc(fabric->fcs, event); - - switch (event) { - case BFA_FCS_FABRIC_SM_CONT_OP: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_evfp_done); - break; - - case BFA_FCS_FABRIC_SM_ISOLATE: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_isolated); - break; - - default: - bfa_sm_fault(fabric->fcs, event); - } -} - -/** - * EVFP exchange complete and VFT tagging is enabled. - */ -static void -bfa_fcs_fabric_sm_evfp_done(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event) -{ - bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); - bfa_trc(fabric->fcs, event); -} - -/** - * Port is isolated after EVFP exchange due to VF_ID mismatch (N and F). - */ -static void -bfa_fcs_fabric_sm_isolated(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event) -{ - bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); - bfa_trc(fabric->fcs, event); - - bfa_log(fabric->fcs->logm, BFA_LOG_FCS_FABRIC_ISOLATED, - fabric->bport.port_cfg.pwwn, fabric->fcs->port_vfid, - fabric->event_arg.swp_vfid); -} - -/** - * Fabric is being deleted, awaiting vport delete completions. - */ -static void -bfa_fcs_fabric_sm_deleting(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event) -{ - bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); - bfa_trc(fabric->fcs, event); - - switch (event) { - case BFA_FCS_FABRIC_SM_DELCOMP: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_uninit); - bfa_fcs_modexit_comp(fabric->fcs); - break; - - case BFA_FCS_FABRIC_SM_LINK_UP: - break; - - case BFA_FCS_FABRIC_SM_LINK_DOWN: - bfa_fcs_fabric_notify_offline(fabric); - break; - - default: - bfa_sm_fault(fabric->fcs, event); - } -} - - - -/** - * fcs_fabric_private fabric private functions - */ - -static void -bfa_fcs_fabric_init(struct bfa_fcs_fabric_s *fabric) -{ - struct bfa_port_cfg_s *port_cfg = &fabric->bport.port_cfg; - - port_cfg->roles = BFA_PORT_ROLE_FCP_IM; - port_cfg->nwwn = bfa_ioc_get_nwwn(&fabric->fcs->bfa->ioc); - port_cfg->pwwn = bfa_ioc_get_pwwn(&fabric->fcs->bfa->ioc); -} - -/** - * Port Symbolic Name Creation for base port. - */ -void -bfa_fcs_fabric_psymb_init(struct bfa_fcs_fabric_s *fabric) -{ - struct bfa_port_cfg_s *port_cfg = &fabric->bport.port_cfg; - char model[BFA_ADAPTER_MODEL_NAME_LEN] = {0}; - struct bfa_fcs_driver_info_s *driver_info = &fabric->fcs->driver_info; - - bfa_ioc_get_adapter_model(&fabric->fcs->bfa->ioc, model); - - /* - * Model name/number - */ - strncpy((char *)&port_cfg->sym_name, model, - BFA_FCS_PORT_SYMBNAME_MODEL_SZ); - strncat((char *)&port_cfg->sym_name, BFA_FCS_PORT_SYMBNAME_SEPARATOR, - sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR)); - - /* - * Driver Version - */ - strncat((char *)&port_cfg->sym_name, (char *)driver_info->version, - BFA_FCS_PORT_SYMBNAME_VERSION_SZ); - strncat((char *)&port_cfg->sym_name, BFA_FCS_PORT_SYMBNAME_SEPARATOR, - sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR)); - - /* - * Host machine name - */ - strncat((char *)&port_cfg->sym_name, - (char *)driver_info->host_machine_name, - BFA_FCS_PORT_SYMBNAME_MACHINENAME_SZ); - strncat((char *)&port_cfg->sym_name, BFA_FCS_PORT_SYMBNAME_SEPARATOR, - sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR)); - - /* - * Host OS Info : - * If OS Patch Info is not there, do not truncate any bytes from the - * OS name string and instead copy the entire OS info string (64 bytes). - */ - if (driver_info->host_os_patch[0] == '\0') { - strncat((char *)&port_cfg->sym_name, - (char *)driver_info->host_os_name, BFA_FCS_OS_STR_LEN); - strncat((char *)&port_cfg->sym_name, - BFA_FCS_PORT_SYMBNAME_SEPARATOR, - sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR)); - } else { - strncat((char *)&port_cfg->sym_name, - (char *)driver_info->host_os_name, - BFA_FCS_PORT_SYMBNAME_OSINFO_SZ); - strncat((char *)&port_cfg->sym_name, - BFA_FCS_PORT_SYMBNAME_SEPARATOR, - sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR)); - - /* - * Append host OS Patch Info - */ - strncat((char *)&port_cfg->sym_name, - (char *)driver_info->host_os_patch, - BFA_FCS_PORT_SYMBNAME_OSPATCH_SZ); - } - - /* - * null terminate - */ - port_cfg->sym_name.symname[BFA_SYMNAME_MAXLEN - 1] = 0; -} - -/** - * bfa lps login completion callback - */ -void -bfa_cb_lps_flogi_comp(void *bfad, void *uarg, bfa_status_t status) -{ - struct bfa_fcs_fabric_s *fabric = uarg; - - bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); - bfa_trc(fabric->fcs, status); - - switch (status) { - case BFA_STATUS_OK: - fabric->stats.flogi_accepts++; - break; - - case BFA_STATUS_INVALID_MAC: - /* - * Only for CNA - */ - fabric->stats.flogi_acc_err++; - bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_RETRY_OP); - - return; - - case BFA_STATUS_EPROTOCOL: - switch (bfa_lps_get_extstatus(fabric->lps)) { - case BFA_EPROTO_BAD_ACCEPT: - fabric->stats.flogi_acc_err++; - break; - - case BFA_EPROTO_UNKNOWN_RSP: - fabric->stats.flogi_unknown_rsp++; - break; - - default: - break; - } - bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_RETRY_OP); - - return; - - case BFA_STATUS_FABRIC_RJT: - fabric->stats.flogi_rejects++; - bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_RETRY_OP); - return; - - default: - fabric->stats.flogi_rsp_err++; - bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_RETRY_OP); - return; - } - - fabric->bb_credit = bfa_lps_get_peer_bbcredit(fabric->lps); - bfa_trc(fabric->fcs, fabric->bb_credit); - - if (!bfa_lps_is_brcd_fabric(fabric->lps)) - fabric->fabric_name = bfa_lps_get_peer_nwwn(fabric->lps); - - /* - * Check port type. It should be 1 = F-port. - */ - if (bfa_lps_is_fport(fabric->lps)) { - fabric->bport.pid = bfa_lps_get_pid(fabric->lps); - fabric->is_npiv = bfa_lps_is_npiv_en(fabric->lps); - fabric->is_auth = bfa_lps_is_authreq(fabric->lps); - bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_CONT_OP); - } else { - /* - * Nport-2-Nport direct attached - */ - fabric->bport.port_topo.pn2n.rem_port_wwn = - bfa_lps_get_peer_pwwn(fabric->lps); - bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_NO_FABRIC); - } - - bfa_trc(fabric->fcs, fabric->bport.pid); - bfa_trc(fabric->fcs, fabric->is_npiv); - bfa_trc(fabric->fcs, fabric->is_auth); -} - -/** - * Allocate and send FLOGI. - */ -static void -bfa_fcs_fabric_login(struct bfa_fcs_fabric_s *fabric) -{ - struct bfa_s *bfa = fabric->fcs->bfa; - struct bfa_port_cfg_s *pcfg = &fabric->bport.port_cfg; - u8 alpa = 0; - - if (bfa_fcport_get_topology(bfa) == BFA_PPORT_TOPOLOGY_LOOP) - alpa = bfa_fcport_get_myalpa(bfa); - - bfa_lps_flogi(fabric->lps, fabric, alpa, bfa_fcport_get_maxfrsize(bfa), - pcfg->pwwn, pcfg->nwwn, fabric->auth_reqd); - - fabric->stats.flogi_sent++; -} - -static void -bfa_fcs_fabric_notify_online(struct bfa_fcs_fabric_s *fabric) -{ - struct bfa_fcs_vport_s *vport; - struct list_head *qe, *qen; - - bfa_trc(fabric->fcs, fabric->fabric_name); - - bfa_fcs_fabric_set_opertype(fabric); - fabric->stats.fabric_onlines++; - - /** - * notify online event to base and then virtual ports - */ - bfa_fcs_port_online(&fabric->bport); - - list_for_each_safe(qe, qen, &fabric->vport_q) { - vport = (struct bfa_fcs_vport_s *)qe; - bfa_fcs_vport_online(vport); - } -} - -static void -bfa_fcs_fabric_notify_offline(struct bfa_fcs_fabric_s *fabric) -{ - struct bfa_fcs_vport_s *vport; - struct list_head *qe, *qen; - - bfa_trc(fabric->fcs, fabric->fabric_name); - fabric->stats.fabric_offlines++; - - /** - * notify offline event first to vports and then base port. - */ - list_for_each_safe(qe, qen, &fabric->vport_q) { - vport = (struct bfa_fcs_vport_s *)qe; - bfa_fcs_vport_offline(vport); - } - - bfa_fcs_port_offline(&fabric->bport); - - fabric->fabric_name = 0; - fabric->fabric_ip_addr[0] = 0; -} - -static void -bfa_fcs_fabric_delay(void *cbarg) -{ - struct bfa_fcs_fabric_s *fabric = cbarg; - - bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_DELAYED); -} - -/** - * Delete all vports and wait for vport delete completions. - */ -static void -bfa_fcs_fabric_delete(struct bfa_fcs_fabric_s *fabric) -{ - struct bfa_fcs_vport_s *vport; - struct list_head *qe, *qen; - - list_for_each_safe(qe, qen, &fabric->vport_q) { - vport = (struct bfa_fcs_vport_s *)qe; - bfa_fcs_vport_fcs_delete(vport); - } - - bfa_fcs_port_delete(&fabric->bport); - bfa_wc_wait(&fabric->wc); -} - -static void -bfa_fcs_fabric_delete_comp(void *cbarg) -{ - struct bfa_fcs_fabric_s *fabric = cbarg; - - bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_DELCOMP); -} - - - -/** - * fcs_fabric_public fabric public functions - */ - -/** - * Attach time initialization - */ -void -bfa_fcs_fabric_attach(struct bfa_fcs_s *fcs) -{ - struct bfa_fcs_fabric_s *fabric; - - fabric = &fcs->fabric; - bfa_os_memset(fabric, 0, sizeof(struct bfa_fcs_fabric_s)); - - /** - * Initialize base fabric. - */ - fabric->fcs = fcs; - INIT_LIST_HEAD(&fabric->vport_q); - INIT_LIST_HEAD(&fabric->vf_q); - fabric->lps = bfa_lps_alloc(fcs->bfa); - bfa_assert(fabric->lps); - - /** - * Initialize fabric delete completion handler. Fabric deletion is complete - * when the last vport delete is complete. - */ - bfa_wc_init(&fabric->wc, bfa_fcs_fabric_delete_comp, fabric); - bfa_wc_up(&fabric->wc); /* For the base port */ - - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_uninit); - bfa_fcs_lport_attach(&fabric->bport, fabric->fcs, FC_VF_ID_NULL, NULL); -} - -void -bfa_fcs_fabric_modinit(struct bfa_fcs_s *fcs) -{ - bfa_sm_send_event(&fcs->fabric, BFA_FCS_FABRIC_SM_CREATE); - bfa_trc(fcs, 0); -} - -/** - * Module cleanup - */ -void -bfa_fcs_fabric_modexit(struct bfa_fcs_s *fcs) -{ - struct bfa_fcs_fabric_s *fabric; - - bfa_trc(fcs, 0); - - /** - * Cleanup base fabric. - */ - fabric = &fcs->fabric; - bfa_lps_delete(fabric->lps); - bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_DELETE); -} - -/** - * Fabric module start -- kick starts FCS actions - */ -void -bfa_fcs_fabric_modstart(struct bfa_fcs_s *fcs) -{ - struct bfa_fcs_fabric_s *fabric; - - bfa_trc(fcs, 0); - fabric = &fcs->fabric; - bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_START); -} - -/** - * Suspend fabric activity as part of driver suspend. - */ -void -bfa_fcs_fabric_modsusp(struct bfa_fcs_s *fcs) -{ -} - -bfa_boolean_t -bfa_fcs_fabric_is_loopback(struct bfa_fcs_fabric_s *fabric) -{ - return bfa_sm_cmp_state(fabric, bfa_fcs_fabric_sm_loopback); -} - -bfa_boolean_t -bfa_fcs_fabric_is_auth_failed(struct bfa_fcs_fabric_s *fabric) -{ - return bfa_sm_cmp_state(fabric, bfa_fcs_fabric_sm_auth_failed); -} - -enum bfa_pport_type -bfa_fcs_fabric_port_type(struct bfa_fcs_fabric_s *fabric) -{ - return fabric->oper_type; -} - -/** - * Link up notification from BFA physical port module. - */ -void -bfa_fcs_fabric_link_up(struct bfa_fcs_fabric_s *fabric) -{ - bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); - bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_LINK_UP); -} - -/** - * Link down notification from BFA physical port module. - */ -void -bfa_fcs_fabric_link_down(struct bfa_fcs_fabric_s *fabric) -{ - bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); - bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_LINK_DOWN); -} - -/** - * A child vport is being created in the fabric. - * - * Call from vport module at vport creation. A list of base port and vports - * belonging to a fabric is maintained to propagate link events. - * - * param[in] fabric - Fabric instance. This can be a base fabric or vf. - * param[in] vport - Vport being created. - * - * @return None (always succeeds) - */ -void -bfa_fcs_fabric_addvport(struct bfa_fcs_fabric_s *fabric, - struct bfa_fcs_vport_s *vport) -{ - /** - * - add vport to fabric's vport_q - */ - bfa_trc(fabric->fcs, fabric->vf_id); - - list_add_tail(&vport->qe, &fabric->vport_q); - fabric->num_vports++; - bfa_wc_up(&fabric->wc); -} - -/** - * A child vport is being deleted from fabric. - * - * Vport is being deleted. - */ -void -bfa_fcs_fabric_delvport(struct bfa_fcs_fabric_s *fabric, - struct bfa_fcs_vport_s *vport) -{ - list_del(&vport->qe); - fabric->num_vports--; - bfa_wc_down(&fabric->wc); -} - -/** - * Base port is deleted. - */ -void -bfa_fcs_fabric_port_delete_comp(struct bfa_fcs_fabric_s *fabric) -{ - bfa_wc_down(&fabric->wc); -} - -/** - * Check if fabric is online. - * - * param[in] fabric - Fabric instance. This can be a base fabric or vf. - * - * @return TRUE/FALSE - */ -int -bfa_fcs_fabric_is_online(struct bfa_fcs_fabric_s *fabric) -{ - return bfa_sm_cmp_state(fabric, bfa_fcs_fabric_sm_online); -} - - -bfa_status_t -bfa_fcs_fabric_addvf(struct bfa_fcs_fabric_s *vf, struct bfa_fcs_s *fcs, - struct bfa_port_cfg_s *port_cfg, - struct bfad_vf_s *vf_drv) -{ - bfa_sm_set_state(vf, bfa_fcs_fabric_sm_uninit); - return BFA_STATUS_OK; -} - -/** - * Lookup for a vport withing a fabric given its pwwn - */ -struct bfa_fcs_vport_s * -bfa_fcs_fabric_vport_lookup(struct bfa_fcs_fabric_s *fabric, wwn_t pwwn) -{ - struct bfa_fcs_vport_s *vport; - struct list_head *qe; - - list_for_each(qe, &fabric->vport_q) { - vport = (struct bfa_fcs_vport_s *)qe; - if (bfa_fcs_port_get_pwwn(&vport->lport) == pwwn) - return vport; - } - - return NULL; -} - -/** - * In a given fabric, return the number of lports. - * - * param[in] fabric - Fabric instance. This can be a base fabric or vf. - * -* @return : 1 or more. - */ -u16 -bfa_fcs_fabric_vport_count(struct bfa_fcs_fabric_s *fabric) -{ - return fabric->num_vports; -} - -/* - * 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. - */ -void -bfa_fcs_fabric_uf_recv(struct bfa_fcs_fabric_s *fabric, struct fchs_s *fchs, - u16 len) -{ - u32 pid = fchs->d_id; - struct bfa_fcs_vport_s *vport; - struct list_head *qe; - struct fc_els_cmd_s *els_cmd = (struct fc_els_cmd_s *) (fchs + 1); - struct fc_logi_s *flogi = (struct fc_logi_s *) els_cmd; - - bfa_trc(fabric->fcs, len); - bfa_trc(fabric->fcs, pid); - - /** - * Look for our own FLOGI frames being looped back. This means an - * external loopback cable is in place. Our own FLOGI frames are - * sometimes looped back when switch port gets temporarily bypassed. - */ - if ((pid == bfa_os_ntoh3b(FC_FABRIC_PORT)) - && (els_cmd->els_code == FC_ELS_FLOGI) - && (flogi->port_name == bfa_fcs_port_get_pwwn(&fabric->bport))) { - bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_LOOPBACK); - return; - } - - /** - * FLOGI/EVFP exchanges should be consumed by base fabric. - */ - if (fchs->d_id == bfa_os_hton3b(FC_FABRIC_PORT)) { - bfa_trc(fabric->fcs, pid); - bfa_fcs_fabric_process_uf(fabric, fchs, len); - return; - } - - if (fabric->bport.pid == pid) { - /** - * All authentication frames should be routed to auth - */ - bfa_trc(fabric->fcs, els_cmd->els_code); - if (els_cmd->els_code == FC_ELS_AUTH) { - bfa_trc(fabric->fcs, els_cmd->els_code); - fabric->auth.response = (u8 *) els_cmd; - return; - } - - bfa_trc(fabric->fcs, *(u8 *) ((u8 *) fchs)); - bfa_fcs_port_uf_recv(&fabric->bport, fchs, len); - return; - } - - /** - * look for a matching local port ID - */ - list_for_each(qe, &fabric->vport_q) { - vport = (struct bfa_fcs_vport_s *)qe; - if (vport->lport.pid == pid) { - bfa_fcs_port_uf_recv(&vport->lport, fchs, len); - return; - } - } - bfa_trc(fabric->fcs, els_cmd->els_code); - bfa_fcs_port_uf_recv(&fabric->bport, fchs, len); -} - -/** - * Unsolicited frames to be processed by fabric. - */ -static void -bfa_fcs_fabric_process_uf(struct bfa_fcs_fabric_s *fabric, struct fchs_s *fchs, - u16 len) -{ - struct fc_els_cmd_s *els_cmd = (struct fc_els_cmd_s *) (fchs + 1); - - bfa_trc(fabric->fcs, els_cmd->els_code); - - switch (els_cmd->els_code) { - case FC_ELS_FLOGI: - bfa_fcs_fabric_process_flogi(fabric, fchs, len); - break; - - default: - /* - * need to generate a LS_RJT - */ - break; - } -} - -/** - * Process incoming FLOGI - */ -static void -bfa_fcs_fabric_process_flogi(struct bfa_fcs_fabric_s *fabric, - struct fchs_s *fchs, u16 len) -{ - struct fc_logi_s *flogi = (struct fc_logi_s *) (fchs + 1); - struct bfa_fcs_port_s *bport = &fabric->bport; - - bfa_trc(fabric->fcs, fchs->s_id); - - fabric->stats.flogi_rcvd++; - /* - * Check port type. It should be 0 = n-port. - */ - if (flogi->csp.port_type) { - /* - * @todo: may need to send a LS_RJT - */ - bfa_trc(fabric->fcs, flogi->port_name); - fabric->stats.flogi_rejected++; - return; - } - - fabric->bb_credit = bfa_os_ntohs(flogi->csp.bbcred); - bport->port_topo.pn2n.rem_port_wwn = flogi->port_name; - bport->port_topo.pn2n.reply_oxid = fchs->ox_id; - - /* - * Send a Flogi Acc - */ - bfa_fcs_fabric_send_flogi_acc(fabric); - bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_NO_FABRIC); -} - -static void -bfa_fcs_fabric_send_flogi_acc(struct bfa_fcs_fabric_s *fabric) -{ - struct bfa_port_cfg_s *pcfg = &fabric->bport.port_cfg; - struct bfa_fcs_port_n2n_s *n2n_port = &fabric->bport.port_topo.pn2n; - struct bfa_s *bfa = fabric->fcs->bfa; - struct bfa_fcxp_s *fcxp; - u16 reqlen; - struct fchs_s fchs; - - fcxp = bfa_fcs_fcxp_alloc(fabric->fcs); - /** - * Do not expect this failure -- expect remote node to retry - */ - if (!fcxp) - return; - - reqlen = fc_flogi_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), - bfa_os_hton3b(FC_FABRIC_PORT), - n2n_port->reply_oxid, pcfg->pwwn, - pcfg->nwwn, bfa_fcport_get_maxfrsize(bfa), - bfa_fcport_get_rx_bbcredit(bfa)); - - bfa_fcxp_send(fcxp, NULL, fabric->vf_id, bfa_lps_get_tag(fabric->lps), - BFA_FALSE, FC_CLASS_3, reqlen, &fchs, - bfa_fcs_fabric_flogiacc_comp, fabric, - FC_MAX_PDUSZ, 0); /* Timeout 0 indicates no - * response expected - */ -} - -/** - * Flogi Acc completion callback. - */ -static void -bfa_fcs_fabric_flogiacc_comp(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg, - bfa_status_t status, u32 rsp_len, - u32 resid_len, struct fchs_s *rspfchs) -{ - struct bfa_fcs_fabric_s *fabric = cbarg; - - bfa_trc(fabric->fcs, status); -} - -/* - * - * @param[in] fabric - fabric - * @param[in] result - 1 - * - * @return - none - */ -void -bfa_fcs_auth_finished(struct bfa_fcs_fabric_s *fabric, enum auth_status status) -{ - bfa_trc(fabric->fcs, status); - - if (status == FC_AUTH_STATE_SUCCESS) - bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_AUTH_SUCCESS); - else - bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_AUTH_FAILED); -} - -/** - * Send AEN notification - */ -static void -bfa_fcs_fabric_aen_post(struct bfa_fcs_port_s *port, - enum bfa_port_aen_event event) -{ - union bfa_aen_data_u aen_data; - struct bfa_log_mod_s *logmod = port->fcs->logm; - wwn_t pwwn = bfa_fcs_port_get_pwwn(port); - wwn_t fwwn = bfa_fcs_port_get_fabric_name(port); - char pwwn_ptr[BFA_STRING_32]; - char fwwn_ptr[BFA_STRING_32]; - - wwn2str(pwwn_ptr, pwwn); - wwn2str(fwwn_ptr, fwwn); - - bfa_log(logmod, BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, event), - pwwn_ptr, fwwn_ptr); - - aen_data.port.pwwn = pwwn; - aen_data.port.fwwn = fwwn; -} - -/* - * - * @param[in] fabric - fabric - * @param[in] wwn_t - new fabric name - * - * @return - none - */ -void -bfa_fcs_fabric_set_fabric_name(struct bfa_fcs_fabric_s *fabric, - wwn_t fabric_name) -{ - bfa_trc(fabric->fcs, fabric_name); - - if (fabric->fabric_name == 0) { - /* - * With BRCD switches, we don't get Fabric Name in FLOGI. - * Don't generate a fabric name change event in this case. - */ - fabric->fabric_name = fabric_name; - } else { - fabric->fabric_name = fabric_name; - /* - * Generate a Event - */ - bfa_fcs_fabric_aen_post(&fabric->bport, - BFA_PORT_AEN_FABRIC_NAME_CHANGE); - } - -} - -/** - * - * @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. - */ -void -bfa_cb_lps_flogo_comp(void *bfad, void *uarg) -{ -} - - diff --git a/drivers/scsi/bfa/fcbuild.h b/drivers/scsi/bfa/fcbuild.h deleted file mode 100644 index 981d98d542b9..000000000000 --- a/drivers/scsi/bfa/fcbuild.h +++ /dev/null @@ -1,279 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ -/* - * fcbuild.h - FC link service frame building and parsing routines - */ - -#ifndef __FCBUILD_H__ -#define __FCBUILD_H__ - -#include <bfa_os_inc.h> -#include <protocol/fc.h> -#include <protocol/fcp.h> -#include <protocol/ct.h> -#include <defs/bfa_defs_port.h> -#include <defs/bfa_defs_pport.h> - -/* - * Utility Macros/functions - */ - -#define fcif_sof_set(_ifhdr, _sof) ((_ifhdr)->sof = FC_ ## _sof) -#define fcif_eof_set(_ifhdr, _eof) ((_ifhdr)->eof = FC_ ## _eof) - -#define wwn_is_equal(_wwn1, _wwn2) \ - (memcmp(&(_wwn1), &(_wwn2), sizeof(wwn_t)) == 0) - -#define fc_roundup(_l, _s) (((_l) + ((_s) - 1)) & ~((_s) - 1)) - -/* - * Given the fc response length, this routine will return - * the length of the actual payload bytes following the CT header. - * - * Assumes the input response length does not include the crc, eof, etc. - */ -static inline u32 -fc_get_ctresp_pyld_len(u32 resp_len) -{ - return resp_len - sizeof(struct ct_hdr_s); -} - -/* - * Convert bfa speed to rpsc speed value. - */ -static inline enum bfa_pport_speed -fc_rpsc_operspeed_to_bfa_speed(enum fc_rpsc_op_speed_s speed) -{ - switch (speed) { - - case RPSC_OP_SPEED_1G: - return BFA_PPORT_SPEED_1GBPS; - - case RPSC_OP_SPEED_2G: - return BFA_PPORT_SPEED_2GBPS; - - case RPSC_OP_SPEED_4G: - return BFA_PPORT_SPEED_4GBPS; - - case RPSC_OP_SPEED_8G: - return BFA_PPORT_SPEED_8GBPS; - - case RPSC_OP_SPEED_10G: - return BFA_PPORT_SPEED_10GBPS; - - default: - return BFA_PPORT_SPEED_UNKNOWN; - } -} - -/* - * Convert RPSC speed to bfa speed value. - */ -static inline enum fc_rpsc_op_speed_s -fc_bfa_speed_to_rpsc_operspeed(enum bfa_pport_speed op_speed) -{ - switch (op_speed) { - - case BFA_PPORT_SPEED_1GBPS: - return RPSC_OP_SPEED_1G; - - case BFA_PPORT_SPEED_2GBPS: - return RPSC_OP_SPEED_2G; - - case BFA_PPORT_SPEED_4GBPS: - return RPSC_OP_SPEED_4G; - - case BFA_PPORT_SPEED_8GBPS: - return RPSC_OP_SPEED_8G; - - case BFA_PPORT_SPEED_10GBPS: - return RPSC_OP_SPEED_10G; - - default: - return RPSC_OP_SPEED_NOT_EST; - } -} -enum fc_parse_status { - FC_PARSE_OK = 0, - FC_PARSE_FAILURE = 1, - FC_PARSE_BUSY = 2, - FC_PARSE_LEN_INVAL, - FC_PARSE_ACC_INVAL, - FC_PARSE_PWWN_NOT_EQUAL, - FC_PARSE_NWWN_NOT_EQUAL, - FC_PARSE_RXSZ_INVAL, - FC_PARSE_NOT_FCP, - FC_PARSE_OPAFLAG_INVAL, - FC_PARSE_RPAFLAG_INVAL, - FC_PARSE_OPA_INVAL, - FC_PARSE_RPA_INVAL, - -}; - -struct fc_templates_s { - struct fchs_s fc_els_req; - struct fchs_s fc_bls_req; - struct fc_logi_s plogi; - struct fc_rrq_s rrq; -}; - -void fcbuild_init(void); - -u16 fc_flogi_build(struct fchs_s *fchs, struct fc_logi_s *flogi, - u32 s_id, u16 ox_id, wwn_t port_name, - wwn_t node_name, u16 pdu_size, u8 set_npiv, - u8 set_auth, u16 local_bb_credits); -u16 fc_fdisc_build(struct fchs_s *buf, struct fc_logi_s *flogi, - u32 s_id, u16 ox_id, wwn_t port_name, - wwn_t node_name, u16 pdu_size); -u16 fc_flogi_acc_build(struct fchs_s *fchs, struct fc_logi_s *flogi, - u32 s_id, u16 ox_id, wwn_t port_name, - wwn_t node_name, u16 pdu_size, - u16 local_bb_credits); -u16 fc_plogi_build(struct fchs_s *fchs, void *pld, u32 d_id, - u32 s_id, u16 ox_id, wwn_t port_name, - wwn_t node_name, u16 pdu_size); -enum fc_parse_status fc_plogi_parse(struct fchs_s *fchs); -u16 fc_abts_build(struct fchs_s *buf, u32 d_id, u32 s_id, - u16 ox_id); -enum fc_parse_status fc_abts_rsp_parse(struct fchs_s *buf, int len); -u16 fc_rrq_build(struct fchs_s *buf, struct fc_rrq_s *rrq, u32 d_id, - u32 s_id, u16 ox_id, u16 rrq_oxid); -enum fc_parse_status fc_rrq_rsp_parse(struct fchs_s *buf, int len); -u16 fc_rspnid_build(struct fchs_s *fchs, void *pld, u32 s_id, - u16 ox_id, u8 *name); -u16 fc_rftid_build(struct fchs_s *fchs, void *pld, u32 s_id, - u16 ox_id, enum bfa_port_role role); -u16 fc_rftid_build_sol(struct fchs_s *fchs, void *pyld, u32 s_id, - u16 ox_id, u8 *fc4_bitmap, - u32 bitmap_size); -u16 fc_rffid_build(struct fchs_s *fchs, void *pyld, u32 s_id, - u16 ox_id, u8 fc4_type, u8 fc4_ftrs); -u16 fc_gidpn_build(struct fchs_s *fchs, void *pyld, u32 s_id, - u16 ox_id, wwn_t port_name); -u16 fc_gpnid_build(struct fchs_s *fchs, void *pld, u32 s_id, - u16 ox_id, u32 port_id); -u16 fc_scr_build(struct fchs_s *fchs, struct fc_scr_s *scr, - u8 set_br_reg, u32 s_id, u16 ox_id); -u16 fc_plogi_acc_build(struct fchs_s *fchs, void *pld, u32 d_id, - u32 s_id, u16 ox_id, - wwn_t port_name, wwn_t node_name, u16 pdu_size); - -u16 fc_adisc_build(struct fchs_s *fchs, struct fc_adisc_s *adisc, - u32 d_id, u32 s_id, u16 ox_id, - wwn_t port_name, wwn_t node_name); -enum fc_parse_status fc_adisc_parse(struct fchs_s *fchs, void *pld, - u32 host_dap, - wwn_t node_name, wwn_t port_name); -enum fc_parse_status fc_adisc_rsp_parse(struct fc_adisc_s *adisc, int len, - wwn_t port_name, wwn_t node_name); -u16 fc_adisc_acc_build(struct fchs_s *fchs, struct fc_adisc_s *adisc, - u32 d_id, u32 s_id, u16 ox_id, - wwn_t port_name, wwn_t node_name); -u16 fc_ls_rjt_build(struct fchs_s *fchs, struct fc_ls_rjt_s *ls_rjt, - u32 d_id, u32 s_id, u16 ox_id, - u8 reason_code, u8 reason_code_expl); -u16 fc_ls_acc_build(struct fchs_s *fchs, struct fc_els_cmd_s *els_cmd, - u32 d_id, u32 s_id, u16 ox_id); -u16 fc_prli_build(struct fchs_s *fchs, void *pld, u32 d_id, - u32 s_id, u16 ox_id); -enum fc_parse_status fc_prli_rsp_parse(struct fc_prli_s *prli, int len); - -u16 fc_prli_acc_build(struct fchs_s *fchs, void *pld, u32 d_id, - u32 s_id, u16 ox_id, - enum bfa_port_role role); -u16 fc_rnid_build(struct fchs_s *fchs, struct fc_rnid_cmd_s *rnid, - u32 d_id, u32 s_id, u16 ox_id, - u32 data_format); -u16 fc_rnid_acc_build(struct fchs_s *fchs, struct fc_rnid_acc_s *rnid_acc, - u32 d_id, u32 s_id, u16 ox_id, - u32 data_format, - struct fc_rnid_common_id_data_s *common_id_data, - struct fc_rnid_general_topology_data_s * - gen_topo_data); -u16 fc_rpsc2_build(struct fchs_s *fchs, struct fc_rpsc2_cmd_s *rps2c, - u32 d_id, u32 s_id, - u32 *pid_list, u16 npids); -u16 fc_rpsc_build(struct fchs_s *fchs, struct fc_rpsc_cmd_s *rpsc, - u32 d_id, u32 s_id, u16 ox_id); -u16 fc_rpsc_acc_build(struct fchs_s *fchs, struct fc_rpsc_acc_s *rpsc_acc, - u32 d_id, u32 s_id, u16 ox_id, - struct fc_rpsc_speed_info_s *oper_speed); -u16 fc_gid_ft_build(struct fchs_s *fchs, void *pld, u32 s_id, - u8 fc4_type); -u16 fc_rpnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, - u32 port_id, wwn_t port_name); -u16 fc_rnnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, - u32 port_id, wwn_t node_name); -u16 fc_rcsid_build(struct fchs_s *fchs, void *pyld, u32 s_id, - u32 port_id, u32 cos); -u16 fc_rptid_build(struct fchs_s *fchs, void *pyld, u32 s_id, - u32 port_id, u8 port_type); -u16 fc_ganxt_build(struct fchs_s *fchs, void *pyld, u32 s_id, - u32 port_id); -u16 fc_logo_build(struct fchs_s *fchs, struct fc_logo_s *logo, - u32 d_id, u32 s_id, u16 ox_id, - wwn_t port_name); -u16 fc_logo_acc_build(struct fchs_s *fchs, void *pld, u32 d_id, - u32 s_id, u16 ox_id); -u16 fc_fdmi_reqhdr_build(struct fchs_s *fchs, void *pyld, u32 s_id, - u16 cmd_code); -u16 fc_gmal_req_build(struct fchs_s *fchs, void *pyld, u32 s_id, - wwn_t wwn); -u16 fc_gfn_req_build(struct fchs_s *fchs, void *pyld, u32 s_id, - wwn_t wwn); -void fc_get_fc4type_bitmask(u8 fc4_type, u8 *bit_mask); -void fc_els_req_build(struct fchs_s *fchs, u32 d_id, u32 s_id, - u16 ox_id); -enum fc_parse_status fc_els_rsp_parse(struct fchs_s *fchs, int len); -enum fc_parse_status fc_plogi_rsp_parse(struct fchs_s *fchs, int len, - wwn_t port_name); -enum fc_parse_status fc_prli_parse(struct fc_prli_s *prli); -enum fc_parse_status fc_pdisc_parse(struct fchs_s *fchs, wwn_t node_name, - wwn_t port_name); -u16 fc_ba_acc_build(struct fchs_s *fchs, struct fc_ba_acc_s *ba_acc, - u32 d_id, u32 s_id, u16 ox_id, - u16 rx_id); -int fc_logout_params_pages(struct fchs_s *fc_frame, u8 els_code); -u16 fc_tprlo_acc_build(struct fchs_s *fchs, - struct fc_tprlo_acc_s *tprlo_acc, - u32 d_id, u32 s_id, u16 ox_id, - int num_pages); -u16 fc_prlo_acc_build(struct fchs_s *fchs, struct fc_prlo_acc_s *prlo_acc, - u32 d_id, u32 s_id, u16 ox_id, - int num_pages); -u16 fc_logo_rsp_parse(struct fchs_s *fchs, int len); -u16 fc_pdisc_build(struct fchs_s *fchs, u32 d_id, u32 s_id, - u16 ox_id, wwn_t port_name, wwn_t node_name, - u16 pdu_size); -u16 fc_pdisc_rsp_parse(struct fchs_s *fchs, int len, wwn_t port_name); -u16 fc_prlo_build(struct fchs_s *fchs, u32 d_id, u32 s_id, - u16 ox_id, int num_pages); -u16 fc_prlo_rsp_parse(struct fchs_s *fchs, int len); -u16 fc_tprlo_build(struct fchs_s *fchs, u32 d_id, u32 s_id, - u16 ox_id, int num_pages, - enum fc_tprlo_type tprlo_type, u32 tpr_id); -u16 fc_tprlo_rsp_parse(struct fchs_s *fchs, int len); -u16 fc_ba_rjt_build(struct fchs_s *fchs, u32 d_id, u32 s_id, - u16 ox_id, u32 reason_code, - u32 reason_expl); -u16 fc_gnnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, - u16 ox_id, u32 port_id); -u16 fc_ct_rsp_parse(struct ct_hdr_s *cthdr); -u16 fc_rscn_build(struct fchs_s *fchs, struct fc_rscn_pl_s *rscn, - u32 s_id, u16 ox_id); -#endif diff --git a/drivers/scsi/bfa/fcptm.c b/drivers/scsi/bfa/fcptm.c deleted file mode 100644 index 8c8b08c72e7a..000000000000 --- a/drivers/scsi/bfa/fcptm.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/** - * This file contains dummy FCPTM routines to aid in Initiator Mode only - * compilation of OS driver. - * - */ - -#include "bfa_os_inc.h" -#include "fcs_rport.h" -#include "fcs_fcptm.h" -#include "fcs/bfa_fcs_rport.h" - -struct bfa_fcs_tin_s * -bfa_fcs_tin_create(struct bfa_fcs_rport_s *rport) -{ - return NULL; -} - -void -bfa_fcs_tin_delete(struct bfa_fcs_tin_s *tin) -{ -} - -void -bfa_fcs_tin_rport_offline(struct bfa_fcs_tin_s *tin) -{ -} - -void -bfa_fcs_tin_rport_online(struct bfa_fcs_tin_s *tin) -{ -} - -void -bfa_fcs_tin_rx_prli(struct bfa_fcs_tin_s *tin, struct fchs_s *fchs, u16 len) -{ -} - -void -bfa_fcs_fcptm_uf_recv(struct bfa_fcs_tin_s *tin, struct fchs_s *fchs, u16 len) -{ -} - -void -bfa_fcs_tin_pause(struct bfa_fcs_tin_s *tin) -{ -} - -void -bfa_fcs_tin_resume(struct bfa_fcs_tin_s *tin) -{ -} diff --git a/drivers/scsi/bfa/fcs.h b/drivers/scsi/bfa/fcs.h deleted file mode 100644 index 8d08230e6295..000000000000 --- a/drivers/scsi/bfa/fcs.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/** - * fcs.h FCS module functions - */ - - -#ifndef __FCS_H__ -#define __FCS_H__ - -#define __fcs_min_cfg(__fcs) ((__fcs)->min_cfg) - -void bfa_fcs_modexit_comp(struct bfa_fcs_s *fcs); - -#endif /* __FCS_H__ */ diff --git a/drivers/scsi/bfa/fcs_auth.h b/drivers/scsi/bfa/fcs_auth.h deleted file mode 100644 index 65d155fea3d7..000000000000 --- a/drivers/scsi/bfa/fcs_auth.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/** - * fcs_uf.h FCS unsolicited frame receive - */ - - -#ifndef __FCS_AUTH_H__ -#define __FCS_AUTH_H__ - -#include <fcs/bfa_fcs.h> -#include <fcs/bfa_fcs_vport.h> -#include <fcs/bfa_fcs_lport.h> - -/* - * fcs friend functions: only between fcs modules - */ -void bfa_fcs_auth_uf_recv(struct bfa_fcs_fabric_s *fabric, int len); -void bfa_fcs_auth_start(struct bfa_fcs_fabric_s *fabric); -void bfa_fcs_auth_stop(struct bfa_fcs_fabric_s *fabric); - -#endif /* __FCS_UF_H__ */ diff --git a/drivers/scsi/bfa/fcs_fabric.h b/drivers/scsi/bfa/fcs_fabric.h deleted file mode 100644 index 432ab8ab8c3c..000000000000 --- a/drivers/scsi/bfa/fcs_fabric.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/** - * fcs_lport.h FCS logical port interfaces - */ - -#ifndef __FCS_FABRIC_H__ -#define __FCS_FABRIC_H__ - -#include <fcs/bfa_fcs.h> -#include <fcs/bfa_fcs_vport.h> -#include <fcs/bfa_fcs_lport.h> - -#define BFA_FCS_BRCD_SWITCH_OUI 0x051e - -/* -* fcs friend functions: only between fcs modules - */ -void bfa_fcs_fabric_attach(struct bfa_fcs_s *fcs); -void bfa_fcs_fabric_modinit(struct bfa_fcs_s *fcs); -void bfa_fcs_fabric_modexit(struct bfa_fcs_s *fcs); -void bfa_fcs_fabric_modsusp(struct bfa_fcs_s *fcs); -void bfa_fcs_fabric_link_up(struct bfa_fcs_fabric_s *fabric); -void bfa_fcs_fabric_link_down(struct bfa_fcs_fabric_s *fabric); -void bfa_fcs_fabric_addvport(struct bfa_fcs_fabric_s *fabric, - struct bfa_fcs_vport_s *vport); -void bfa_fcs_fabric_delvport(struct bfa_fcs_fabric_s *fabric, - struct bfa_fcs_vport_s *vport); -int bfa_fcs_fabric_is_online(struct bfa_fcs_fabric_s *fabric); -struct bfa_fcs_vport_s *bfa_fcs_fabric_vport_lookup( - struct bfa_fcs_fabric_s *fabric, wwn_t pwwn); -void bfa_fcs_fabric_modstart(struct bfa_fcs_s *fcs); -void bfa_fcs_fabric_uf_recv(struct bfa_fcs_fabric_s *fabric, - struct fchs_s *fchs, u16 len); -u16 bfa_fcs_fabric_vport_count(struct bfa_fcs_fabric_s *fabric); -bfa_boolean_t bfa_fcs_fabric_is_loopback(struct bfa_fcs_fabric_s *fabric); -bfa_boolean_t bfa_fcs_fabric_is_auth_failed(struct bfa_fcs_fabric_s *fabric); -enum bfa_pport_type bfa_fcs_fabric_port_type(struct bfa_fcs_fabric_s *fabric); -void bfa_fcs_fabric_psymb_init(struct bfa_fcs_fabric_s *fabric); -void bfa_fcs_fabric_port_delete_comp(struct bfa_fcs_fabric_s *fabric); - -bfa_status_t bfa_fcs_fabric_addvf(struct bfa_fcs_fabric_s *vf, - struct bfa_fcs_s *fcs, struct bfa_port_cfg_s *port_cfg, - struct bfad_vf_s *vf_drv); -void bfa_fcs_auth_finished(struct bfa_fcs_fabric_s *fabric, - enum auth_status status); - -void bfa_fcs_fabric_set_fabric_name(struct bfa_fcs_fabric_s *fabric, - wwn_t fabric_name); -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/fcs_fcpim.h b/drivers/scsi/bfa/fcs_fcpim.h deleted file mode 100644 index 11e6e7bce9f6..000000000000 --- a/drivers/scsi/bfa/fcs_fcpim.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ -#ifndef __FCS_FCPIM_H__ -#define __FCS_FCPIM_H__ - -#include <defs/bfa_defs_port.h> -#include <fcs/bfa_fcs_lport.h> -#include <fcs/bfa_fcs_rport.h> - -/* - * Following routines are from FCPIM and will be called by rport. - */ -struct bfa_fcs_itnim_s *bfa_fcs_itnim_create(struct bfa_fcs_rport_s *rport); -void bfa_fcs_itnim_delete(struct bfa_fcs_itnim_s *itnim); -void bfa_fcs_itnim_rport_offline(struct bfa_fcs_itnim_s *itnim); -void bfa_fcs_itnim_rport_online(struct bfa_fcs_itnim_s *itnim); -bfa_status_t bfa_fcs_itnim_get_online_state(struct bfa_fcs_itnim_s *itnim); - -void bfa_fcs_itnim_is_initiator(struct bfa_fcs_itnim_s *itnim); -void bfa_fcs_itnim_pause(struct bfa_fcs_itnim_s *itnim); -void bfa_fcs_itnim_resume(struct bfa_fcs_itnim_s *itnim); - -void bfa_fcs_fcpim_uf_recv(struct bfa_fcs_itnim_s *itnim, struct fchs_s *fchs, - u16 len); -#endif /* __FCS_FCPIM_H__ */ diff --git a/drivers/scsi/bfa/fcs_fcptm.h b/drivers/scsi/bfa/fcs_fcptm.h deleted file mode 100644 index ffff0829fd31..000000000000 --- a/drivers/scsi/bfa/fcs_fcptm.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __FCS_FCPTM_H__ -#define __FCS_FCPTM_H__ - -#include <defs/bfa_defs_port.h> -#include <fcs/bfa_fcs_lport.h> -#include <fcs/bfa_fcs_rport.h> - -/* - * Following routines are from FCPTM and will be called by rport. - */ -struct bfa_fcs_tin_s *bfa_fcs_tin_create(struct bfa_fcs_rport_s *rport); -void bfa_fcs_tin_rport_offline(struct bfa_fcs_tin_s *tin); -void bfa_fcs_tin_rport_online(struct bfa_fcs_tin_s *tin); -void bfa_fcs_tin_delete(struct bfa_fcs_tin_s *tin); -void bfa_fcs_tin_rx_prli(struct bfa_fcs_tin_s *tin, struct fchs_s *fchs, - u16 len); -void bfa_fcs_tin_pause(struct bfa_fcs_tin_s *tin); -void bfa_fcs_tin_resume(struct bfa_fcs_tin_s *tin); - -/* - * Modudle init/cleanup routines. - */ -void bfa_fcs_fcptm_modinit(struct bfa_fcs_s *fcs); -void bfa_fcs_fcptm_modexit(struct bfa_fcs_s *fcs); -void bfa_fcs_fcptm_uf_recv(struct bfa_fcs_tin_s *tin, struct fchs_s *fchs, - u16 len); - -#endif /* __FCS_FCPTM_H__ */ diff --git a/drivers/scsi/bfa/fcs_fcxp.h b/drivers/scsi/bfa/fcs_fcxp.h deleted file mode 100644 index 8277fe9c2b70..000000000000 --- a/drivers/scsi/bfa/fcs_fcxp.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/** - * fcs_fcxp.h FCXP helper macros for FCS - */ - - -#ifndef __FCS_FCXP_H__ -#define __FCS_FCXP_H__ - -#define bfa_fcs_fcxp_alloc(__fcs) \ - bfa_fcxp_alloc(NULL, (__fcs)->bfa, 0, 0, NULL, NULL, NULL, NULL) - -#endif /* __FCS_FCXP_H__ */ diff --git a/drivers/scsi/bfa/fcs_lport.h b/drivers/scsi/bfa/fcs_lport.h deleted file mode 100644 index a6508c8ab184..000000000000 --- a/drivers/scsi/bfa/fcs_lport.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/** - * fcs_lport.h FCS logical port interfaces - */ - -#ifndef __FCS_LPORT_H__ -#define __FCS_LPORT_H__ - -#define __VPORT_H__ -#include <defs/bfa_defs_port.h> -#include <bfa_svc.h> -#include <fcs/bfa_fcs_lport.h> -#include <fcs/bfa_fcs_rport.h> -#include <fcs/bfa_fcs_vport.h> -#include <fcs_fabric.h> -#include <fcs_ms.h> -#include <cs/bfa_q.h> -#include <fcbuild.h> - -/* - * PID used in P2P/N2N ( In Big Endian) - */ -#define N2N_LOCAL_PID 0x010000 -#define N2N_REMOTE_PID 0x020000 - -/* - * Misc Timeouts - */ -/* - * To be used when spawning a timer before retrying a failed command. Milli - * Secs. - */ -#define BFA_FCS_RETRY_TIMEOUT 2000 - -/* - * Check for Port/Vport Mode/Role - */ -#define BFA_FCS_VPORT_IS_INITIATOR_MODE(port) \ - (port->port_cfg.roles & BFA_PORT_ROLE_FCP_IM) - -#define BFA_FCS_VPORT_IS_TARGET_MODE(port) \ - (port->port_cfg.roles & BFA_PORT_ROLE_FCP_TM) - -#define BFA_FCS_VPORT_IS_IPFC_MODE(port) \ - (port->port_cfg.roles & BFA_PORT_ROLE_FCP_IPFC) - -/* - * Is this a Well Known Address - */ -#define BFA_FCS_PID_IS_WKA(pid) ((bfa_os_ntoh3b(pid) > 0xFFF000) ? 1 : 0) - -/* - * Pointer to elements within Port - */ -#define BFA_FCS_GET_HAL_FROM_PORT(port) (port->fcs->bfa) -#define BFA_FCS_GET_NS_FROM_PORT(port) (&port->port_topo.pfab.ns) -#define BFA_FCS_GET_SCN_FROM_PORT(port) (&port->port_topo.pfab.scn) -#define BFA_FCS_GET_MS_FROM_PORT(port) (&port->port_topo.pfab.ms) -#define BFA_FCS_GET_FDMI_FROM_PORT(port) (&port->port_topo.pfab.ms.fdmi) - -/* - * handler for unsolicied frames - */ -void bfa_fcs_port_uf_recv(struct bfa_fcs_port_s *lport, struct fchs_s *fchs, - u16 len); - -/* - * Following routines will be called by Fabric to indicate port - * online/offline to vport. - */ -void bfa_fcs_lport_attach(struct bfa_fcs_port_s *lport, struct bfa_fcs_s *fcs, - uint16_t vf_id, struct bfa_fcs_vport_s *vport); -void bfa_fcs_lport_init(struct bfa_fcs_port_s *lport, - struct bfa_port_cfg_s *port_cfg); -void bfa_fcs_port_online(struct bfa_fcs_port_s *port); -void bfa_fcs_port_offline(struct bfa_fcs_port_s *port); -void bfa_fcs_port_delete(struct bfa_fcs_port_s *port); -bfa_boolean_t bfa_fcs_port_is_online(struct bfa_fcs_port_s *port); - -/* - * Lookup rport based on PID - */ -struct bfa_fcs_rport_s *bfa_fcs_port_get_rport_by_pid( - struct bfa_fcs_port_s *port, u32 pid); - -/* - * Lookup rport based on PWWN - */ -struct bfa_fcs_rport_s *bfa_fcs_port_get_rport_by_pwwn( - struct bfa_fcs_port_s *port, wwn_t pwwn); -struct bfa_fcs_rport_s *bfa_fcs_port_get_rport_by_nwwn( - struct bfa_fcs_port_s *port, wwn_t nwwn); -void bfa_fcs_port_add_rport(struct bfa_fcs_port_s *port, - struct bfa_fcs_rport_s *rport); -void bfa_fcs_port_del_rport(struct bfa_fcs_port_s *port, - struct bfa_fcs_rport_s *rport); - -void bfa_fcs_port_modinit(struct bfa_fcs_s *fcs); -void bfa_fcs_port_modexit(struct bfa_fcs_s *fcs); -void bfa_fcs_port_lip(struct bfa_fcs_port_s *port); - -#endif /* __FCS_LPORT_H__ */ diff --git a/drivers/scsi/bfa/fcs_ms.h b/drivers/scsi/bfa/fcs_ms.h deleted file mode 100644 index b6a8c12876f4..000000000000 --- a/drivers/scsi/bfa/fcs_ms.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/** - * fcs_ms.h FCS ms interfaces - */ -#ifndef __FCS_MS_H__ -#define __FCS_MS_H__ - -/* MS FCS routines */ -void bfa_fcs_port_ms_init(struct bfa_fcs_port_s *port); -void bfa_fcs_port_ms_offline(struct bfa_fcs_port_s *port); -void bfa_fcs_port_ms_online(struct bfa_fcs_port_s *port); -void bfa_fcs_port_ms_fabric_rscn(struct bfa_fcs_port_s *port); - -/* FDMI FCS routines */ -void bfa_fcs_port_fdmi_init(struct bfa_fcs_port_ms_s *ms); -void bfa_fcs_port_fdmi_offline(struct bfa_fcs_port_ms_s *ms); -void bfa_fcs_port_fdmi_online(struct bfa_fcs_port_ms_s *ms); - -#endif diff --git a/drivers/scsi/bfa/fcs_port.h b/drivers/scsi/bfa/fcs_port.h deleted file mode 100644 index 408c06a7d164..000000000000 --- a/drivers/scsi/bfa/fcs_port.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/** - * fcs_pport.h FCS physical port interfaces - */ - - -#ifndef __FCS_PPORT_H__ -#define __FCS_PPORT_H__ - -/* - * fcs friend functions: only between fcs modules - */ -void bfa_fcs_pport_attach(struct bfa_fcs_s *fcs); - -#endif /* __FCS_PPORT_H__ */ diff --git a/drivers/scsi/bfa/fcs_rport.h b/drivers/scsi/bfa/fcs_rport.h deleted file mode 100644 index e634fb7a69b8..000000000000 --- a/drivers/scsi/bfa/fcs_rport.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/** - * fcs_rport.h FCS rport interfaces and defines - */ - -#ifndef __FCS_RPORT_H__ -#define __FCS_RPORT_H__ - -#include <fcs/bfa_fcs_rport.h> - -#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); - -struct bfa_fcs_rport_s *bfa_fcs_rport_create(struct bfa_fcs_port_s *port, - u32 pid); -void bfa_fcs_rport_delete(struct bfa_fcs_rport_s *rport); -void bfa_fcs_rport_online(struct bfa_fcs_rport_s *rport); -void bfa_fcs_rport_offline(struct bfa_fcs_rport_s *rport); -void bfa_fcs_rport_start(struct bfa_fcs_port_s *port, struct fchs_s *rx_fchs, - struct fc_logi_s *plogi_rsp); -void bfa_fcs_rport_plogi_create(struct bfa_fcs_port_s *port, - struct fchs_s *rx_fchs, - struct fc_logi_s *plogi); -void bfa_fcs_rport_plogi(struct bfa_fcs_rport_s *rport, struct fchs_s *fchs, - struct fc_logi_s *plogi); -void bfa_fcs_rport_logo_imp(struct bfa_fcs_rport_s *rport); -void bfa_fcs_rport_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); -void bfa_fcs_rport_fcptm_offline_done(struct bfa_fcs_rport_s *rport); -int bfa_fcs_rport_get_state(struct bfa_fcs_rport_s *rport); -struct bfa_fcs_rport_s *bfa_fcs_rport_create_by_wwn(struct bfa_fcs_port_s *port, - wwn_t wwn); - - -/* Rport Features */ -void bfa_fcs_rpf_init(struct bfa_fcs_rport_s *rport); -void bfa_fcs_rpf_rport_online(struct bfa_fcs_rport_s *rport); -void bfa_fcs_rpf_rport_offline(struct bfa_fcs_rport_s *rport); - -#endif /* __FCS_RPORT_H__ */ diff --git a/drivers/scsi/bfa/fcs_trcmod.h b/drivers/scsi/bfa/fcs_trcmod.h deleted file mode 100644 index 41b5ae8d7644..000000000000 --- a/drivers/scsi/bfa/fcs_trcmod.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/** - * fcs_trcmod.h BFA FCS trace modules - */ - -#ifndef __FCS_TRCMOD_H__ -#define __FCS_TRCMOD_H__ - -#include <cs/bfa_trc.h> - -/* - * !!! Only append to the enums defined here to avoid any versioning - * !!! needed between trace utility and driver version - */ -enum { - BFA_TRC_FCS_FABRIC = 1, - BFA_TRC_FCS_VFAPI = 2, - BFA_TRC_FCS_PORT = 3, - BFA_TRC_FCS_VPORT = 4, - BFA_TRC_FCS_VP_API = 5, - BFA_TRC_FCS_VPS = 6, - BFA_TRC_FCS_RPORT = 7, - BFA_TRC_FCS_FCPIM = 8, - BFA_TRC_FCS_FCPTM = 9, - BFA_TRC_FCS_NS = 10, - BFA_TRC_FCS_SCN = 11, - BFA_TRC_FCS_LOOP = 12, - BFA_TRC_FCS_UF = 13, - BFA_TRC_FCS_PPORT = 14, - BFA_TRC_FCS_FCPIP = 15, - BFA_TRC_FCS_PORT_API = 16, - BFA_TRC_FCS_RPORT_API = 17, - BFA_TRC_FCS_AUTH = 18, - BFA_TRC_FCS_N2N = 19, - BFA_TRC_FCS_MS = 20, - BFA_TRC_FCS_FDMI = 21, - BFA_TRC_FCS_RPORT_FTRS = 22, -}; - -#endif /* __FCS_TRCMOD_H__ */ diff --git a/drivers/scsi/bfa/fcs_uf.h b/drivers/scsi/bfa/fcs_uf.h deleted file mode 100644 index f591072214fe..000000000000 --- a/drivers/scsi/bfa/fcs_uf.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/** - * fcs_uf.h FCS unsolicited frame receive - */ - - -#ifndef __FCS_UF_H__ -#define __FCS_UF_H__ - -/* - * fcs friend functions: only between fcs modules - */ -void bfa_fcs_uf_attach(struct bfa_fcs_s *fcs); - -#endif /* __FCS_UF_H__ */ diff --git a/drivers/scsi/bfa/fcs_vport.h b/drivers/scsi/bfa/fcs_vport.h deleted file mode 100644 index bb647a4a5dde..000000000000 --- a/drivers/scsi/bfa/fcs_vport.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __FCS_VPORT_H__ -#define __FCS_VPORT_H__ - -#include <fcs/bfa_fcs_lport.h> -#include <fcs/bfa_fcs_vport.h> -#include <defs/bfa_defs_pci.h> - -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/fdmi.c b/drivers/scsi/bfa/fdmi.c deleted file mode 100644 index 2b50eabf4b1e..000000000000 --- a/drivers/scsi/bfa/fdmi.c +++ /dev/null @@ -1,1230 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/** - * port_api.c BFA FCS port - */ - - -#include <bfa.h> -#include <bfa_svc.h> -#include "fcs_lport.h" -#include "fcs_rport.h" -#include "lport_priv.h" -#include "fcs_trcmod.h" -#include "fcs_fcxp.h" -#include <fcs/bfa_fcs_fdmi.h> - -BFA_TRC_FILE(FCS, FDMI); - -#define BFA_FCS_FDMI_CMD_MAX_RETRIES 2 - -/* - * forward declarations - */ -static void bfa_fcs_port_fdmi_send_rhba(void *fdmi_cbarg, - struct bfa_fcxp_s *fcxp_alloced); -static void bfa_fcs_port_fdmi_send_rprt(void *fdmi_cbarg, - struct bfa_fcxp_s *fcxp_alloced); -static void bfa_fcs_port_fdmi_send_rpa(void *fdmi_cbarg, - struct bfa_fcxp_s *fcxp_alloced); -static void bfa_fcs_port_fdmi_rhba_response(void *fcsarg, - struct bfa_fcxp_s *fcxp, - void *cbarg, - bfa_status_t req_status, - u32 rsp_len, - u32 resid_len, - struct fchs_s *rsp_fchs); -static void bfa_fcs_port_fdmi_rprt_response(void *fcsarg, - struct bfa_fcxp_s *fcxp, - void *cbarg, - bfa_status_t req_status, - u32 rsp_len, - u32 resid_len, - struct fchs_s *rsp_fchs); -static void bfa_fcs_port_fdmi_rpa_response(void *fcsarg, - struct bfa_fcxp_s *fcxp, - void *cbarg, - bfa_status_t req_status, - u32 rsp_len, - u32 resid_len, - struct fchs_s *rsp_fchs); -static void bfa_fcs_port_fdmi_timeout(void *arg); -static u16 bfa_fcs_port_fdmi_build_rhba_pyld( - struct bfa_fcs_port_fdmi_s *fdmi, u8 *pyld); -static u16 bfa_fcs_port_fdmi_build_rprt_pyld( - struct bfa_fcs_port_fdmi_s *fdmi, u8 *pyld); -static u16 bfa_fcs_port_fdmi_build_rpa_pyld( - struct bfa_fcs_port_fdmi_s *fdmi, u8 *pyld); -static u16 bfa_fcs_port_fdmi_build_portattr_block( - struct bfa_fcs_port_fdmi_s *fdmi, u8 *pyld); -static void bfa_fcs_fdmi_get_hbaattr(struct bfa_fcs_port_fdmi_s *fdmi, - struct bfa_fcs_fdmi_hba_attr_s *hba_attr); -static void bfa_fcs_fdmi_get_portattr(struct bfa_fcs_port_fdmi_s *fdmi, - struct bfa_fcs_fdmi_port_attr_s *port_attr); -/** - * fcs_fdmi_sm FCS FDMI state machine - */ - -/** - * FDMI State Machine events - */ -enum port_fdmi_event { - FDMISM_EVENT_PORT_ONLINE = 1, - FDMISM_EVENT_PORT_OFFLINE = 2, - FDMISM_EVENT_RSP_OK = 4, - FDMISM_EVENT_RSP_ERROR = 5, - FDMISM_EVENT_TIMEOUT = 6, - FDMISM_EVENT_RHBA_SENT = 7, - FDMISM_EVENT_RPRT_SENT = 8, - FDMISM_EVENT_RPA_SENT = 9, -}; - -static void bfa_fcs_port_fdmi_sm_offline(struct bfa_fcs_port_fdmi_s *fdmi, - enum port_fdmi_event event); -static void bfa_fcs_port_fdmi_sm_sending_rhba(struct bfa_fcs_port_fdmi_s *fdmi, - enum port_fdmi_event event); -static void bfa_fcs_port_fdmi_sm_rhba(struct bfa_fcs_port_fdmi_s *fdmi, - enum port_fdmi_event event); -static void bfa_fcs_port_fdmi_sm_rhba_retry(struct bfa_fcs_port_fdmi_s *fdmi, - enum port_fdmi_event event); -static void bfa_fcs_port_fdmi_sm_sending_rprt(struct bfa_fcs_port_fdmi_s *fdmi, - enum port_fdmi_event event); -static void bfa_fcs_port_fdmi_sm_rprt(struct bfa_fcs_port_fdmi_s *fdmi, - enum port_fdmi_event event); -static void bfa_fcs_port_fdmi_sm_rprt_retry(struct bfa_fcs_port_fdmi_s *fdmi, - enum port_fdmi_event event); -static void bfa_fcs_port_fdmi_sm_sending_rpa(struct bfa_fcs_port_fdmi_s *fdmi, - enum port_fdmi_event event); -static void bfa_fcs_port_fdmi_sm_rpa(struct bfa_fcs_port_fdmi_s *fdmi, - enum port_fdmi_event event); -static void bfa_fcs_port_fdmi_sm_rpa_retry(struct bfa_fcs_port_fdmi_s *fdmi, - enum port_fdmi_event event); -static void bfa_fcs_port_fdmi_sm_online(struct bfa_fcs_port_fdmi_s *fdmi, - enum port_fdmi_event event); -static void bfa_fcs_port_fdmi_sm_disabled(struct bfa_fcs_port_fdmi_s *fdmi, - enum port_fdmi_event event); - -/** - * Start in offline state - awaiting MS to send start. - */ -static void -bfa_fcs_port_fdmi_sm_offline(struct bfa_fcs_port_fdmi_s *fdmi, - enum port_fdmi_event event) -{ - struct bfa_fcs_port_s *port = fdmi->ms->port; - - bfa_trc(port->fcs, port->port_cfg.pwwn); - bfa_trc(port->fcs, event); - - fdmi->retry_cnt = 0; - - switch (event) { - case FDMISM_EVENT_PORT_ONLINE: - if (port->vport) { - /* - * For Vports, register a new port. - */ - bfa_sm_set_state(fdmi, - bfa_fcs_port_fdmi_sm_sending_rprt); - bfa_fcs_port_fdmi_send_rprt(fdmi, NULL); - } else { - /* - * For a base port, we should first register the HBA - * atribute. The HBA attribute also contains the base - * port registration. - */ - bfa_sm_set_state(fdmi, - bfa_fcs_port_fdmi_sm_sending_rhba); - bfa_fcs_port_fdmi_send_rhba(fdmi, NULL); - } - break; - - case FDMISM_EVENT_PORT_OFFLINE: - break; - - default: - bfa_sm_fault(port->fcs, event); - } -} - -static void -bfa_fcs_port_fdmi_sm_sending_rhba(struct bfa_fcs_port_fdmi_s *fdmi, - enum port_fdmi_event event) -{ - struct bfa_fcs_port_s *port = fdmi->ms->port; - - bfa_trc(port->fcs, port->port_cfg.pwwn); - bfa_trc(port->fcs, event); - - switch (event) { - case FDMISM_EVENT_RHBA_SENT: - bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_rhba); - break; - - case FDMISM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline); - bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(port), - &fdmi->fcxp_wqe); - break; - - default: - bfa_sm_fault(port->fcs, event); - } -} - -static void -bfa_fcs_port_fdmi_sm_rhba(struct bfa_fcs_port_fdmi_s *fdmi, - enum port_fdmi_event event) -{ - struct bfa_fcs_port_s *port = fdmi->ms->port; - - bfa_trc(port->fcs, port->port_cfg.pwwn); - bfa_trc(port->fcs, event); - - switch (event) { - case FDMISM_EVENT_RSP_ERROR: - /* - * if max retries have not been reached, start timer for a - * delayed retry - */ - if (fdmi->retry_cnt++ < BFA_FCS_FDMI_CMD_MAX_RETRIES) { - bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_rhba_retry); - bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(port), - &fdmi->timer, bfa_fcs_port_fdmi_timeout, - fdmi, BFA_FCS_RETRY_TIMEOUT); - } else { - /* - * set state to offline - */ - bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline); - } - break; - - case FDMISM_EVENT_RSP_OK: - /* - * Initiate Register Port Attributes - */ - bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_sending_rpa); - fdmi->retry_cnt = 0; - bfa_fcs_port_fdmi_send_rpa(fdmi, NULL); - break; - - case FDMISM_EVENT_PORT_OFFLINE: - bfa_fcxp_discard(fdmi->fcxp); - bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline); - break; - - default: - bfa_sm_fault(port->fcs, event); - } -} - -static void -bfa_fcs_port_fdmi_sm_rhba_retry(struct bfa_fcs_port_fdmi_s *fdmi, - enum port_fdmi_event event) -{ - struct bfa_fcs_port_s *port = fdmi->ms->port; - - bfa_trc(port->fcs, port->port_cfg.pwwn); - bfa_trc(port->fcs, event); - - switch (event) { - case FDMISM_EVENT_TIMEOUT: - /* - * Retry Timer Expired. Re-send - */ - bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_sending_rhba); - bfa_fcs_port_fdmi_send_rhba(fdmi, NULL); - break; - - case FDMISM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline); - bfa_timer_stop(&fdmi->timer); - break; - - default: - bfa_sm_fault(port->fcs, event); - } -} - -/* -* RPRT : Register Port - */ -static void -bfa_fcs_port_fdmi_sm_sending_rprt(struct bfa_fcs_port_fdmi_s *fdmi, - enum port_fdmi_event event) -{ - struct bfa_fcs_port_s *port = fdmi->ms->port; - - bfa_trc(port->fcs, port->port_cfg.pwwn); - bfa_trc(port->fcs, event); - - switch (event) { - case FDMISM_EVENT_RPRT_SENT: - bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_rprt); - break; - - case FDMISM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline); - bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(port), - &fdmi->fcxp_wqe); - break; - - default: - bfa_sm_fault(port->fcs, event); - } -} - -static void -bfa_fcs_port_fdmi_sm_rprt(struct bfa_fcs_port_fdmi_s *fdmi, - enum port_fdmi_event event) -{ - struct bfa_fcs_port_s *port = fdmi->ms->port; - - bfa_trc(port->fcs, port->port_cfg.pwwn); - bfa_trc(port->fcs, event); - - switch (event) { - case FDMISM_EVENT_RSP_ERROR: - /* - * if max retries have not been reached, start timer for a - * delayed retry - */ - if (fdmi->retry_cnt++ < BFA_FCS_FDMI_CMD_MAX_RETRIES) { - bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_rprt_retry); - bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(port), - &fdmi->timer, bfa_fcs_port_fdmi_timeout, - fdmi, BFA_FCS_RETRY_TIMEOUT); - - } else { - /* - * set state to offline - */ - bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline); - fdmi->retry_cnt = 0; - } - break; - - case FDMISM_EVENT_RSP_OK: - fdmi->retry_cnt = 0; - bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_online); - break; - - case FDMISM_EVENT_PORT_OFFLINE: - bfa_fcxp_discard(fdmi->fcxp); - bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline); - break; - - default: - bfa_sm_fault(port->fcs, event); - } -} - -static void -bfa_fcs_port_fdmi_sm_rprt_retry(struct bfa_fcs_port_fdmi_s *fdmi, - enum port_fdmi_event event) -{ - struct bfa_fcs_port_s *port = fdmi->ms->port; - - bfa_trc(port->fcs, port->port_cfg.pwwn); - bfa_trc(port->fcs, event); - - switch (event) { - case FDMISM_EVENT_TIMEOUT: - /* - * Retry Timer Expired. Re-send - */ - bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_sending_rprt); - bfa_fcs_port_fdmi_send_rprt(fdmi, NULL); - break; - - case FDMISM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline); - bfa_timer_stop(&fdmi->timer); - break; - - default: - bfa_sm_fault(port->fcs, event); - } -} - -/* - * Register Port Attributes - */ -static void -bfa_fcs_port_fdmi_sm_sending_rpa(struct bfa_fcs_port_fdmi_s *fdmi, - enum port_fdmi_event event) -{ - struct bfa_fcs_port_s *port = fdmi->ms->port; - - bfa_trc(port->fcs, port->port_cfg.pwwn); - bfa_trc(port->fcs, event); - - switch (event) { - case FDMISM_EVENT_RPA_SENT: - bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_rpa); - break; - - case FDMISM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline); - bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(port), - &fdmi->fcxp_wqe); - break; - - default: - bfa_sm_fault(port->fcs, event); - } -} - -static void -bfa_fcs_port_fdmi_sm_rpa(struct bfa_fcs_port_fdmi_s *fdmi, - enum port_fdmi_event event) -{ - struct bfa_fcs_port_s *port = fdmi->ms->port; - - bfa_trc(port->fcs, port->port_cfg.pwwn); - bfa_trc(port->fcs, event); - - switch (event) { - case FDMISM_EVENT_RSP_ERROR: - /* - * if max retries have not been reached, start timer for a - * delayed retry - */ - if (fdmi->retry_cnt++ < BFA_FCS_FDMI_CMD_MAX_RETRIES) { - bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_rpa_retry); - bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(port), - &fdmi->timer, bfa_fcs_port_fdmi_timeout, - fdmi, BFA_FCS_RETRY_TIMEOUT); - } else { - /* - * set state to offline - */ - bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline); - fdmi->retry_cnt = 0; - } - break; - - case FDMISM_EVENT_RSP_OK: - bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_online); - fdmi->retry_cnt = 0; - break; - - case FDMISM_EVENT_PORT_OFFLINE: - bfa_fcxp_discard(fdmi->fcxp); - bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline); - break; - - default: - bfa_sm_fault(port->fcs, event); - } -} - -static void -bfa_fcs_port_fdmi_sm_rpa_retry(struct bfa_fcs_port_fdmi_s *fdmi, - enum port_fdmi_event event) -{ - struct bfa_fcs_port_s *port = fdmi->ms->port; - - bfa_trc(port->fcs, port->port_cfg.pwwn); - bfa_trc(port->fcs, event); - - switch (event) { - case FDMISM_EVENT_TIMEOUT: - /* - * Retry Timer Expired. Re-send - */ - bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_sending_rpa); - bfa_fcs_port_fdmi_send_rpa(fdmi, NULL); - break; - - case FDMISM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline); - bfa_timer_stop(&fdmi->timer); - break; - - default: - bfa_sm_fault(port->fcs, event); - } -} - -static void -bfa_fcs_port_fdmi_sm_online(struct bfa_fcs_port_fdmi_s *fdmi, - enum port_fdmi_event event) -{ - struct bfa_fcs_port_s *port = fdmi->ms->port; - - bfa_trc(port->fcs, port->port_cfg.pwwn); - bfa_trc(port->fcs, event); - - switch (event) { - case FDMISM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline); - break; - - default: - bfa_sm_fault(port->fcs, event); - } -} - -/** - * FDMI is disabled state. - */ -static void -bfa_fcs_port_fdmi_sm_disabled(struct bfa_fcs_port_fdmi_s *fdmi, - enum port_fdmi_event event) -{ - struct bfa_fcs_port_s *port = fdmi->ms->port; - - bfa_trc(port->fcs, port->port_cfg.pwwn); - bfa_trc(port->fcs, event); - - /* No op State. It can only be enabled at Driver Init. */ -} - -/** -* RHBA : Register HBA Attributes. - */ -static void -bfa_fcs_port_fdmi_send_rhba(void *fdmi_cbarg, struct bfa_fcxp_s *fcxp_alloced) -{ - struct bfa_fcs_port_fdmi_s *fdmi = fdmi_cbarg; - struct bfa_fcs_port_s *port = fdmi->ms->port; - struct fchs_s fchs; - int len, attr_len; - struct bfa_fcxp_s *fcxp; - u8 *pyld; - - bfa_trc(port->fcs, port->port_cfg.pwwn); - - fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); - if (!fcxp) { - bfa_fcxp_alloc_wait(port->fcs->bfa, &fdmi->fcxp_wqe, - bfa_fcs_port_fdmi_send_rhba, fdmi); - return; - } - fdmi->fcxp = fcxp; - - pyld = bfa_fcxp_get_reqbuf(fcxp); - bfa_os_memset(pyld, 0, FC_MAX_PDUSZ); - - len = fc_fdmi_reqhdr_build(&fchs, pyld, bfa_fcs_port_get_fcid(port), - FDMI_RHBA); - - attr_len = bfa_fcs_port_fdmi_build_rhba_pyld(fdmi, - (u8 *) ((struct ct_hdr_s *) pyld + 1)); - - bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, - FC_CLASS_3, (len + attr_len), &fchs, - bfa_fcs_port_fdmi_rhba_response, (void *)fdmi, - FC_MAX_PDUSZ, FC_FCCT_TOV); - - bfa_sm_send_event(fdmi, FDMISM_EVENT_RHBA_SENT); -} - -static u16 -bfa_fcs_port_fdmi_build_rhba_pyld(struct bfa_fcs_port_fdmi_s *fdmi, - u8 *pyld) -{ - struct bfa_fcs_port_s *port = fdmi->ms->port; - struct bfa_fcs_fdmi_hba_attr_s hba_attr; /* @todo */ - struct bfa_fcs_fdmi_hba_attr_s *fcs_hba_attr = &hba_attr; /* @todo */ - struct fdmi_rhba_s *rhba = (struct fdmi_rhba_s *) pyld; - struct fdmi_attr_s *attr; - u8 *curr_ptr; - u16 len, count; - - /* - * get hba attributes - */ - bfa_fcs_fdmi_get_hbaattr(fdmi, fcs_hba_attr); - - rhba->hba_id = bfa_fcs_port_get_pwwn(port); - rhba->port_list.num_ports = bfa_os_htonl(1); - rhba->port_list.port_entry = bfa_fcs_port_get_pwwn(port); - - len = sizeof(rhba->hba_id) + sizeof(rhba->port_list); - - count = 0; - len += sizeof(rhba->hba_attr_blk.attr_count); - - /* - * fill out the invididual entries of the HBA attrib Block - */ - curr_ptr = (u8 *) &rhba->hba_attr_blk.hba_attr; - - /* - * Node Name - */ - attr = (struct fdmi_attr_s *) curr_ptr; - attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_NODENAME); - attr->len = sizeof(wwn_t); - memcpy(attr->value, &bfa_fcs_port_get_nwwn(port), attr->len); - curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len; - len += attr->len; - count++; - attr->len = - bfa_os_htons(attr->len + sizeof(attr->type) + - sizeof(attr->len)); - - /* - * Manufacturer - */ - attr = (struct fdmi_attr_s *) curr_ptr; - attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_MANUFACTURER); - attr->len = (u16) strlen(fcs_hba_attr->manufacturer); - memcpy(attr->value, fcs_hba_attr->manufacturer, attr->len); - /* variable fields need to be 4 byte aligned */ - attr->len = fc_roundup(attr->len, sizeof(u32)); - curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len; - len += attr->len; - count++; - attr->len = - bfa_os_htons(attr->len + sizeof(attr->type) + - sizeof(attr->len)); - - /* - * Serial Number - */ - attr = (struct fdmi_attr_s *) curr_ptr; - attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_SERIALNUM); - attr->len = (u16) strlen(fcs_hba_attr->serial_num); - memcpy(attr->value, fcs_hba_attr->serial_num, attr->len); - /* variable fields need to be 4 byte aligned */ - attr->len = fc_roundup(attr->len, sizeof(u32)); - curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len; - len += attr->len; - count++; - attr->len = - bfa_os_htons(attr->len + sizeof(attr->type) + - sizeof(attr->len)); - - /* - * Model - */ - attr = (struct fdmi_attr_s *) curr_ptr; - attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_MODEL); - attr->len = (u16) strlen(fcs_hba_attr->model); - memcpy(attr->value, fcs_hba_attr->model, attr->len); - /* variable fields need to be 4 byte aligned */ - attr->len = fc_roundup(attr->len, sizeof(u32)); - curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len; - len += attr->len; - count++; - attr->len = - bfa_os_htons(attr->len + sizeof(attr->type) + - sizeof(attr->len)); - - /* - * Model Desc - */ - attr = (struct fdmi_attr_s *) curr_ptr; - attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_MODEL_DESC); - attr->len = (u16) strlen(fcs_hba_attr->model_desc); - memcpy(attr->value, fcs_hba_attr->model_desc, attr->len); - /* variable fields need to be 4 byte aligned */ - attr->len = fc_roundup(attr->len, sizeof(u32)); - curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len; - len += attr->len; - count++; - attr->len = - bfa_os_htons(attr->len + sizeof(attr->type) + - sizeof(attr->len)); - - /* - * H/W Version - */ - if (fcs_hba_attr->hw_version[0] != '\0') { - attr = (struct fdmi_attr_s *) curr_ptr; - attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_HW_VERSION); - attr->len = (u16) strlen(fcs_hba_attr->hw_version); - memcpy(attr->value, fcs_hba_attr->hw_version, attr->len); - /* variable fields need to be 4 byte aligned */ - attr->len = fc_roundup(attr->len, sizeof(u32)); - curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len; - len += attr->len; - count++; - attr->len = - bfa_os_htons(attr->len + sizeof(attr->type) + - sizeof(attr->len)); - } - - /* - * Driver Version - */ - attr = (struct fdmi_attr_s *) curr_ptr; - attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_DRIVER_VERSION); - attr->len = (u16) strlen(fcs_hba_attr->driver_version); - memcpy(attr->value, fcs_hba_attr->driver_version, attr->len); - /* variable fields need to be 4 byte aligned */ - attr->len = fc_roundup(attr->len, sizeof(u32)); - curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len; - len += attr->len;; - count++; - attr->len = - bfa_os_htons(attr->len + sizeof(attr->type) + - sizeof(attr->len)); - - /* - * Option Rom Version - */ - if (fcs_hba_attr->option_rom_ver[0] != '\0') { - attr = (struct fdmi_attr_s *) curr_ptr; - attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_ROM_VERSION); - attr->len = (u16) strlen(fcs_hba_attr->option_rom_ver); - memcpy(attr->value, fcs_hba_attr->option_rom_ver, attr->len); - /* variable fields need to be 4 byte aligned */ - attr->len = fc_roundup(attr->len, sizeof(u32)); - curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len; - len += attr->len; - count++; - attr->len = - bfa_os_htons(attr->len + sizeof(attr->type) + - sizeof(attr->len)); - } - - /* - * f/w Version = driver version - */ - attr = (struct fdmi_attr_s *) curr_ptr; - attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_FW_VERSION); - attr->len = (u16) strlen(fcs_hba_attr->driver_version); - memcpy(attr->value, fcs_hba_attr->driver_version, attr->len); - /* variable fields need to be 4 byte aligned */ - attr->len = fc_roundup(attr->len, sizeof(u32)); - curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len; - len += attr->len; - count++; - attr->len = - bfa_os_htons(attr->len + sizeof(attr->type) + - sizeof(attr->len)); - - /* - * OS Name - */ - if (fcs_hba_attr->os_name[0] != '\0') { - attr = (struct fdmi_attr_s *) curr_ptr; - attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_OS_NAME); - attr->len = (u16) strlen(fcs_hba_attr->os_name); - memcpy(attr->value, fcs_hba_attr->os_name, attr->len); - /* variable fields need to be 4 byte aligned */ - attr->len = fc_roundup(attr->len, sizeof(u32)); - curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len; - len += attr->len; - count++; - attr->len = - bfa_os_htons(attr->len + sizeof(attr->type) + - sizeof(attr->len)); - } - - /* - * MAX_CT_PAYLOAD - */ - attr = (struct fdmi_attr_s *) curr_ptr; - attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_MAX_CT); - attr->len = sizeof(fcs_hba_attr->max_ct_pyld); - memcpy(attr->value, &fcs_hba_attr->max_ct_pyld, attr->len); - len += attr->len; - count++; - attr->len = - bfa_os_htons(attr->len + sizeof(attr->type) + - sizeof(attr->len)); - - /* - * Update size of payload - */ - len += ((sizeof(attr->type) + sizeof(attr->len)) * count); - - rhba->hba_attr_blk.attr_count = bfa_os_htonl(count); - return len; -} - -static void -bfa_fcs_port_fdmi_rhba_response(void *fcsarg, struct bfa_fcxp_s *fcxp, - void *cbarg, bfa_status_t req_status, - u32 rsp_len, u32 resid_len, - struct fchs_s *rsp_fchs) -{ - struct bfa_fcs_port_fdmi_s *fdmi = (struct bfa_fcs_port_fdmi_s *)cbarg; - struct bfa_fcs_port_s *port = fdmi->ms->port; - struct ct_hdr_s *cthdr = NULL; - - bfa_trc(port->fcs, port->port_cfg.pwwn); - - /* - * Sanity Checks - */ - if (req_status != BFA_STATUS_OK) { - bfa_trc(port->fcs, req_status); - bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_ERROR); - return; - } - - cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp); - cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code); - - if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) { - bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_OK); - return; - } - - bfa_trc(port->fcs, cthdr->reason_code); - bfa_trc(port->fcs, cthdr->exp_code); - bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_ERROR); -} - -/** -* RPRT : Register Port - */ -static void -bfa_fcs_port_fdmi_send_rprt(void *fdmi_cbarg, struct bfa_fcxp_s *fcxp_alloced) -{ - struct bfa_fcs_port_fdmi_s *fdmi = fdmi_cbarg; - struct bfa_fcs_port_s *port = fdmi->ms->port; - struct fchs_s fchs; - u16 len, attr_len; - struct bfa_fcxp_s *fcxp; - u8 *pyld; - - bfa_trc(port->fcs, port->port_cfg.pwwn); - - fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); - if (!fcxp) { - bfa_fcxp_alloc_wait(port->fcs->bfa, &fdmi->fcxp_wqe, - bfa_fcs_port_fdmi_send_rprt, fdmi); - return; - } - fdmi->fcxp = fcxp; - - pyld = bfa_fcxp_get_reqbuf(fcxp); - bfa_os_memset(pyld, 0, FC_MAX_PDUSZ); - - len = fc_fdmi_reqhdr_build(&fchs, pyld, bfa_fcs_port_get_fcid(port), - FDMI_RPRT); - - attr_len = bfa_fcs_port_fdmi_build_rprt_pyld(fdmi, - (u8 *) ((struct ct_hdr_s *) pyld + 1)); - - bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, - FC_CLASS_3, len + attr_len, &fchs, - bfa_fcs_port_fdmi_rprt_response, (void *)fdmi, - FC_MAX_PDUSZ, FC_FCCT_TOV); - - bfa_sm_send_event(fdmi, FDMISM_EVENT_RPRT_SENT); -} - -/** - * This routine builds Port Attribute Block that used in RPA, RPRT commands. - */ -static u16 -bfa_fcs_port_fdmi_build_portattr_block(struct bfa_fcs_port_fdmi_s *fdmi, - u8 *pyld) -{ - struct bfa_fcs_fdmi_port_attr_s fcs_port_attr; - struct fdmi_port_attr_s *port_attrib = (struct fdmi_port_attr_s *) pyld; - struct fdmi_attr_s *attr; - u8 *curr_ptr; - u16 len; - u8 count = 0; - - /* - * get port attributes - */ - bfa_fcs_fdmi_get_portattr(fdmi, &fcs_port_attr); - - len = sizeof(port_attrib->attr_count); - - /* - * fill out the invididual entries - */ - curr_ptr = (u8 *) &port_attrib->port_attr; - - /* - * FC4 Types - */ - attr = (struct fdmi_attr_s *) curr_ptr; - attr->type = bfa_os_htons(FDMI_PORT_ATTRIB_FC4_TYPES); - attr->len = sizeof(fcs_port_attr.supp_fc4_types); - memcpy(attr->value, fcs_port_attr.supp_fc4_types, attr->len); - curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len; - len += attr->len; - ++count; - attr->len = - bfa_os_htons(attr->len + sizeof(attr->type) + - sizeof(attr->len)); - - /* - * Supported Speed - */ - attr = (struct fdmi_attr_s *) curr_ptr; - attr->type = bfa_os_htons(FDMI_PORT_ATTRIB_SUPP_SPEED); - attr->len = sizeof(fcs_port_attr.supp_speed); - memcpy(attr->value, &fcs_port_attr.supp_speed, attr->len); - curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len; - len += attr->len; - ++count; - attr->len = - bfa_os_htons(attr->len + sizeof(attr->type) + - sizeof(attr->len)); - - /* - * current Port Speed - */ - attr = (struct fdmi_attr_s *) curr_ptr; - attr->type = bfa_os_htons(FDMI_PORT_ATTRIB_PORT_SPEED); - attr->len = sizeof(fcs_port_attr.curr_speed); - memcpy(attr->value, &fcs_port_attr.curr_speed, attr->len); - curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len; - len += attr->len; - ++count; - attr->len = - bfa_os_htons(attr->len + sizeof(attr->type) + - sizeof(attr->len)); - - /* - * max frame size - */ - attr = (struct fdmi_attr_s *) curr_ptr; - attr->type = bfa_os_htons(FDMI_PORT_ATTRIB_FRAME_SIZE); - attr->len = sizeof(fcs_port_attr.max_frm_size); - memcpy(attr->value, &fcs_port_attr.max_frm_size, attr->len); - curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len; - len += attr->len; - ++count; - attr->len = - bfa_os_htons(attr->len + sizeof(attr->type) + - sizeof(attr->len)); - - /* - * OS Device Name - */ - if (fcs_port_attr.os_device_name[0] != '\0') { - attr = (struct fdmi_attr_s *) curr_ptr; - attr->type = bfa_os_htons(FDMI_PORT_ATTRIB_DEV_NAME); - attr->len = (u16) strlen(fcs_port_attr.os_device_name); - memcpy(attr->value, fcs_port_attr.os_device_name, attr->len); - /* variable fields need to be 4 byte aligned */ - attr->len = fc_roundup(attr->len, sizeof(u32)); - curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len; - len += attr->len; - ++count; - attr->len = - bfa_os_htons(attr->len + sizeof(attr->type) + - sizeof(attr->len)); - - } - /* - * Host Name - */ - if (fcs_port_attr.host_name[0] != '\0') { - attr = (struct fdmi_attr_s *) curr_ptr; - attr->type = bfa_os_htons(FDMI_PORT_ATTRIB_HOST_NAME); - attr->len = (u16) strlen(fcs_port_attr.host_name); - memcpy(attr->value, fcs_port_attr.host_name, attr->len); - /* variable fields need to be 4 byte aligned */ - attr->len = fc_roundup(attr->len, sizeof(u32)); - curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len; - len += attr->len; - ++count; - attr->len = - bfa_os_htons(attr->len + sizeof(attr->type) + - sizeof(attr->len)); - - } - - /* - * Update size of payload - */ - port_attrib->attr_count = bfa_os_htonl(count); - len += ((sizeof(attr->type) + sizeof(attr->len)) * count); - return len; -} - -static u16 -bfa_fcs_port_fdmi_build_rprt_pyld(struct bfa_fcs_port_fdmi_s *fdmi, - u8 *pyld) -{ - struct bfa_fcs_port_s *port = fdmi->ms->port; - struct fdmi_rprt_s *rprt = (struct fdmi_rprt_s *) pyld; - u16 len; - - rprt->hba_id = bfa_fcs_port_get_pwwn(bfa_fcs_get_base_port(port->fcs)); - rprt->port_name = bfa_fcs_port_get_pwwn(port); - - len = bfa_fcs_port_fdmi_build_portattr_block(fdmi, - (u8 *) &rprt->port_attr_blk); - - len += sizeof(rprt->hba_id) + sizeof(rprt->port_name); - - return len; -} - -static void -bfa_fcs_port_fdmi_rprt_response(void *fcsarg, struct bfa_fcxp_s *fcxp, - void *cbarg, bfa_status_t req_status, - u32 rsp_len, u32 resid_len, - struct fchs_s *rsp_fchs) -{ - struct bfa_fcs_port_fdmi_s *fdmi = (struct bfa_fcs_port_fdmi_s *)cbarg; - struct bfa_fcs_port_s *port = fdmi->ms->port; - struct ct_hdr_s *cthdr = NULL; - - bfa_trc(port->fcs, port->port_cfg.pwwn); - - /* - * Sanity Checks - */ - if (req_status != BFA_STATUS_OK) { - bfa_trc(port->fcs, req_status); - bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_ERROR); - return; - } - - cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp); - cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code); - - if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) { - bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_OK); - return; - } - - bfa_trc(port->fcs, cthdr->reason_code); - bfa_trc(port->fcs, cthdr->exp_code); - bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_ERROR); -} - -/** -* RPA : Register Port Attributes. - */ -static void -bfa_fcs_port_fdmi_send_rpa(void *fdmi_cbarg, struct bfa_fcxp_s *fcxp_alloced) -{ - struct bfa_fcs_port_fdmi_s *fdmi = fdmi_cbarg; - struct bfa_fcs_port_s *port = fdmi->ms->port; - struct fchs_s fchs; - u16 len, attr_len; - struct bfa_fcxp_s *fcxp; - u8 *pyld; - - bfa_trc(port->fcs, port->port_cfg.pwwn); - - fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); - if (!fcxp) { - bfa_fcxp_alloc_wait(port->fcs->bfa, &fdmi->fcxp_wqe, - bfa_fcs_port_fdmi_send_rpa, fdmi); - return; - } - fdmi->fcxp = fcxp; - - pyld = bfa_fcxp_get_reqbuf(fcxp); - bfa_os_memset(pyld, 0, FC_MAX_PDUSZ); - - len = fc_fdmi_reqhdr_build(&fchs, pyld, bfa_fcs_port_get_fcid(port), - FDMI_RPA); - - attr_len = bfa_fcs_port_fdmi_build_rpa_pyld(fdmi, - (u8 *) ((struct ct_hdr_s *) pyld + 1)); - - bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, - FC_CLASS_3, len + attr_len, &fchs, - bfa_fcs_port_fdmi_rpa_response, (void *)fdmi, - FC_MAX_PDUSZ, FC_FCCT_TOV); - - bfa_sm_send_event(fdmi, FDMISM_EVENT_RPA_SENT); -} - -static u16 -bfa_fcs_port_fdmi_build_rpa_pyld(struct bfa_fcs_port_fdmi_s *fdmi, - u8 *pyld) -{ - struct bfa_fcs_port_s *port = fdmi->ms->port; - struct fdmi_rpa_s *rpa = (struct fdmi_rpa_s *) pyld; - u16 len; - - rpa->port_name = bfa_fcs_port_get_pwwn(port); - - len = bfa_fcs_port_fdmi_build_portattr_block(fdmi, - (u8 *) &rpa->port_attr_blk); - - len += sizeof(rpa->port_name); - - return len; -} - -static void -bfa_fcs_port_fdmi_rpa_response(void *fcsarg, struct bfa_fcxp_s *fcxp, - void *cbarg, bfa_status_t req_status, - u32 rsp_len, u32 resid_len, - struct fchs_s *rsp_fchs) -{ - struct bfa_fcs_port_fdmi_s *fdmi = (struct bfa_fcs_port_fdmi_s *)cbarg; - struct bfa_fcs_port_s *port = fdmi->ms->port; - struct ct_hdr_s *cthdr = NULL; - - bfa_trc(port->fcs, port->port_cfg.pwwn); - - /* - * Sanity Checks - */ - if (req_status != BFA_STATUS_OK) { - bfa_trc(port->fcs, req_status); - bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_ERROR); - return; - } - - cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp); - cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code); - - if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) { - bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_OK); - return; - } - - bfa_trc(port->fcs, cthdr->reason_code); - bfa_trc(port->fcs, cthdr->exp_code); - bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_ERROR); -} - -static void -bfa_fcs_port_fdmi_timeout(void *arg) -{ - struct bfa_fcs_port_fdmi_s *fdmi = (struct bfa_fcs_port_fdmi_s *)arg; - - bfa_sm_send_event(fdmi, FDMISM_EVENT_TIMEOUT); -} - -static void -bfa_fcs_fdmi_get_hbaattr(struct bfa_fcs_port_fdmi_s *fdmi, - struct bfa_fcs_fdmi_hba_attr_s *hba_attr) -{ - struct bfa_fcs_port_s *port = fdmi->ms->port; - struct bfa_fcs_driver_info_s *driver_info = &port->fcs->driver_info; - - bfa_os_memset(hba_attr, 0, sizeof(struct bfa_fcs_fdmi_hba_attr_s)); - - bfa_ioc_get_adapter_manufacturer(&port->fcs->bfa->ioc, - hba_attr->manufacturer); - bfa_ioc_get_adapter_serial_num(&port->fcs->bfa->ioc, - hba_attr->serial_num); - bfa_ioc_get_adapter_model(&port->fcs->bfa->ioc, hba_attr->model); - bfa_ioc_get_adapter_model(&port->fcs->bfa->ioc, hba_attr->model_desc); - bfa_ioc_get_pci_chip_rev(&port->fcs->bfa->ioc, hba_attr->hw_version); - bfa_ioc_get_adapter_optrom_ver(&port->fcs->bfa->ioc, - hba_attr->option_rom_ver); - bfa_ioc_get_adapter_fw_ver(&port->fcs->bfa->ioc, hba_attr->fw_version); - - strncpy(hba_attr->driver_version, (char *)driver_info->version, - sizeof(hba_attr->driver_version)); - - strncpy(hba_attr->os_name, driver_info->host_os_name, - sizeof(hba_attr->os_name)); - - /* - * If there is a patch level, append it to the os name along with a - * separator - */ - if (driver_info->host_os_patch[0] != '\0') { - strncat(hba_attr->os_name, BFA_FCS_PORT_SYMBNAME_SEPARATOR, - sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR)); - strncat(hba_attr->os_name, driver_info->host_os_patch, - sizeof(driver_info->host_os_patch)); - } - - hba_attr->max_ct_pyld = bfa_os_htonl(FC_MAX_PDUSZ); - -} - -static void -bfa_fcs_fdmi_get_portattr(struct bfa_fcs_port_fdmi_s *fdmi, - struct bfa_fcs_fdmi_port_attr_s *port_attr) -{ - struct bfa_fcs_port_s *port = fdmi->ms->port; - struct bfa_fcs_driver_info_s *driver_info = &port->fcs->driver_info; - struct bfa_pport_attr_s pport_attr; - - bfa_os_memset(port_attr, 0, sizeof(struct bfa_fcs_fdmi_port_attr_s)); - - /* - * get pport attributes from hal - */ - bfa_fcport_get_attr(port->fcs->bfa, &pport_attr); - - /* - * get FC4 type Bitmask - */ - fc_get_fc4type_bitmask(FC_TYPE_FCP, port_attr->supp_fc4_types); - - /* - * Supported Speeds - */ - port_attr->supp_speed = bfa_os_htonl(BFA_FCS_FDMI_SUPORTED_SPEEDS); - - /* - * Current Speed - */ - port_attr->curr_speed = bfa_os_htonl(pport_attr.speed); - - /* - * Max PDU Size. - */ - port_attr->max_frm_size = bfa_os_htonl(FC_MAX_PDUSZ); - - /* - * OS device Name - */ - strncpy(port_attr->os_device_name, (char *)driver_info->os_device_name, - sizeof(port_attr->os_device_name)); - - /* - * Host name - */ - strncpy(port_attr->host_name, (char *)driver_info->host_machine_name, - sizeof(port_attr->host_name)); - -} - - -void -bfa_fcs_port_fdmi_init(struct bfa_fcs_port_ms_s *ms) -{ - struct bfa_fcs_port_fdmi_s *fdmi = &ms->fdmi; - - fdmi->ms = ms; - if (ms->port->fcs->fdmi_enabled) - bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline); - else - bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_disabled); -} - -void -bfa_fcs_port_fdmi_offline(struct bfa_fcs_port_ms_s *ms) -{ - struct bfa_fcs_port_fdmi_s *fdmi = &ms->fdmi; - - fdmi->ms = ms; - bfa_sm_send_event(fdmi, FDMISM_EVENT_PORT_OFFLINE); -} - -void -bfa_fcs_port_fdmi_online(struct bfa_fcs_port_ms_s *ms) -{ - struct bfa_fcs_port_fdmi_s *fdmi = &ms->fdmi; - - fdmi->ms = ms; - bfa_sm_send_event(fdmi, FDMISM_EVENT_PORT_ONLINE); -} diff --git a/drivers/scsi/bfa/include/aen/bfa_aen.h b/drivers/scsi/bfa/include/aen/bfa_aen.h deleted file mode 100644 index 6abbab005db6..000000000000 --- a/drivers/scsi/bfa/include/aen/bfa_aen.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ -#ifndef __BFA_AEN_H__ -#define __BFA_AEN_H__ - -#include "defs/bfa_defs_aen.h" -#include "defs/bfa_defs_status.h" -#include "cs/bfa_debug.h" - -#define BFA_AEN_MAX_ENTRY 512 - -extern int bfa_aen_max_cfg_entry; -struct bfa_aen_s { - void *bfad; - int max_entry; - int write_index; - int read_index; - int bfad_num; - int seq_num; - void (*aen_cb_notify)(void *bfad); - void (*gettimeofday)(struct bfa_timeval_s *tv); - struct bfa_trc_mod_s *trcmod; - int app_ri[BFA_AEN_MAX_APP]; /* For multiclient support */ - struct bfa_aen_entry_s list[BFA_AEN_MAX_ENTRY]; /* Must be the last */ -}; - - -/** - * Public APIs - */ -static inline void -bfa_aen_set_max_cfg_entry(int max_entry) -{ - bfa_aen_max_cfg_entry = max_entry; -} - -static inline int -bfa_aen_get_max_cfg_entry(void) -{ - return bfa_aen_max_cfg_entry; -} - -static inline int -bfa_aen_get_meminfo(void) -{ - return sizeof(struct bfa_aen_entry_s) * bfa_aen_get_max_cfg_entry(); -} - -static inline int -bfa_aen_get_wi(struct bfa_aen_s *aen) -{ - return aen->write_index; -} - -static inline int -bfa_aen_get_ri(struct bfa_aen_s *aen) -{ - return aen->read_index; -} - -static inline int -bfa_aen_fetch_count(struct bfa_aen_s *aen, enum bfa_aen_app app_id) -{ - bfa_assert((app_id < BFA_AEN_MAX_APP) && (app_id >= bfa_aen_app_bcu)); - return ((aen->write_index + aen->max_entry) - aen->app_ri[app_id]) - % aen->max_entry; -} - -int bfa_aen_init(struct bfa_aen_s *aen, struct bfa_trc_mod_s *trcmod, - void *bfad, int bfad_num, void (*aen_cb_notify)(void *), - void (*gettimeofday)(struct bfa_timeval_s *)); - -void bfa_aen_post(struct bfa_aen_s *aen, enum bfa_aen_category aen_category, - int aen_type, union bfa_aen_data_u *aen_data); - -bfa_status_t bfa_aen_fetch(struct bfa_aen_s *aen, - struct bfa_aen_entry_s *aen_entry, - int entry_req, enum bfa_aen_app app_id, int *entry_ret); - -int bfa_aen_get_inst(struct bfa_aen_s *aen); - -#endif /* __BFA_AEN_H__ */ diff --git a/drivers/scsi/bfa/include/aen/bfa_aen_adapter.h b/drivers/scsi/bfa/include/aen/bfa_aen_adapter.h deleted file mode 100644 index 260d3ea1cab3..000000000000 --- a/drivers/scsi/bfa/include/aen/bfa_aen_adapter.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/* messages define for BFA_AEN_CAT_ADAPTER Module */ -#ifndef __bfa_aen_adapter_h__ -#define __bfa_aen_adapter_h__ - -#include <cs/bfa_log.h> -#include <defs/bfa_defs_aen.h> - -#define BFA_AEN_ADAPTER_ADD \ - BFA_LOG_CREATE_ID(BFA_AEN_CAT_ADAPTER, BFA_ADAPTER_AEN_ADD) -#define BFA_AEN_ADAPTER_REMOVE \ - BFA_LOG_CREATE_ID(BFA_AEN_CAT_ADAPTER, BFA_ADAPTER_AEN_REMOVE) - -#endif - diff --git a/drivers/scsi/bfa/include/aen/bfa_aen_audit.h b/drivers/scsi/bfa/include/aen/bfa_aen_audit.h deleted file mode 100644 index 12cd7aab5d53..000000000000 --- a/drivers/scsi/bfa/include/aen/bfa_aen_audit.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/* messages define for BFA_AEN_CAT_AUDIT Module */ -#ifndef __bfa_aen_audit_h__ -#define __bfa_aen_audit_h__ - -#include <cs/bfa_log.h> -#include <defs/bfa_defs_aen.h> - -#define BFA_AEN_AUDIT_AUTH_ENABLE \ - BFA_LOG_CREATE_ID(BFA_AEN_CAT_AUDIT, BFA_AUDIT_AEN_AUTH_ENABLE) -#define BFA_AEN_AUDIT_AUTH_DISABLE \ - BFA_LOG_CREATE_ID(BFA_AEN_CAT_AUDIT, BFA_AUDIT_AEN_AUTH_DISABLE) - -#endif - diff --git a/drivers/scsi/bfa/include/aen/bfa_aen_ethport.h b/drivers/scsi/bfa/include/aen/bfa_aen_ethport.h deleted file mode 100644 index 507d0b58d149..000000000000 --- a/drivers/scsi/bfa/include/aen/bfa_aen_ethport.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/* messages define for BFA_AEN_CAT_ETHPORT Module */ -#ifndef __bfa_aen_ethport_h__ -#define __bfa_aen_ethport_h__ - -#include <cs/bfa_log.h> -#include <defs/bfa_defs_aen.h> - -#define BFA_AEN_ETHPORT_LINKUP \ - BFA_LOG_CREATE_ID(BFA_AEN_CAT_ETHPORT, BFA_ETHPORT_AEN_LINKUP) -#define BFA_AEN_ETHPORT_LINKDOWN \ - BFA_LOG_CREATE_ID(BFA_AEN_CAT_ETHPORT, BFA_ETHPORT_AEN_LINKDOWN) -#define BFA_AEN_ETHPORT_ENABLE \ - BFA_LOG_CREATE_ID(BFA_AEN_CAT_ETHPORT, BFA_ETHPORT_AEN_ENABLE) -#define BFA_AEN_ETHPORT_DISABLE \ - BFA_LOG_CREATE_ID(BFA_AEN_CAT_ETHPORT, BFA_ETHPORT_AEN_DISABLE) - -#endif - diff --git a/drivers/scsi/bfa/include/aen/bfa_aen_ioc.h b/drivers/scsi/bfa/include/aen/bfa_aen_ioc.h deleted file mode 100644 index 4daf96faa266..000000000000 --- a/drivers/scsi/bfa/include/aen/bfa_aen_ioc.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/* messages define for BFA_AEN_CAT_IOC Module */ -#ifndef __bfa_aen_ioc_h__ -#define __bfa_aen_ioc_h__ - -#include <cs/bfa_log.h> -#include <defs/bfa_defs_aen.h> - -#define BFA_AEN_IOC_HBGOOD \ - BFA_LOG_CREATE_ID(BFA_AEN_CAT_IOC, BFA_IOC_AEN_HBGOOD) -#define BFA_AEN_IOC_HBFAIL \ - BFA_LOG_CREATE_ID(BFA_AEN_CAT_IOC, BFA_IOC_AEN_HBFAIL) -#define BFA_AEN_IOC_ENABLE \ - BFA_LOG_CREATE_ID(BFA_AEN_CAT_IOC, BFA_IOC_AEN_ENABLE) -#define BFA_AEN_IOC_DISABLE \ - BFA_LOG_CREATE_ID(BFA_AEN_CAT_IOC, BFA_IOC_AEN_DISABLE) -#define BFA_AEN_IOC_FWMISMATCH \ - BFA_LOG_CREATE_ID(BFA_AEN_CAT_IOC, BFA_IOC_AEN_FWMISMATCH) -#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/aen/bfa_aen_itnim.h b/drivers/scsi/bfa/include/aen/bfa_aen_itnim.h deleted file mode 100644 index a7d8ddcfef99..000000000000 --- a/drivers/scsi/bfa/include/aen/bfa_aen_itnim.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/* messages define for BFA_AEN_CAT_ITNIM Module */ -#ifndef __bfa_aen_itnim_h__ -#define __bfa_aen_itnim_h__ - -#include <cs/bfa_log.h> -#include <defs/bfa_defs_aen.h> - -#define BFA_AEN_ITNIM_ONLINE \ - BFA_LOG_CREATE_ID(BFA_AEN_CAT_ITNIM, BFA_ITNIM_AEN_ONLINE) -#define BFA_AEN_ITNIM_OFFLINE \ - BFA_LOG_CREATE_ID(BFA_AEN_CAT_ITNIM, BFA_ITNIM_AEN_OFFLINE) -#define BFA_AEN_ITNIM_DISCONNECT \ - BFA_LOG_CREATE_ID(BFA_AEN_CAT_ITNIM, BFA_ITNIM_AEN_DISCONNECT) - -#endif - diff --git a/drivers/scsi/bfa/include/aen/bfa_aen_lport.h b/drivers/scsi/bfa/include/aen/bfa_aen_lport.h deleted file mode 100644 index 5a8ebb65193f..000000000000 --- a/drivers/scsi/bfa/include/aen/bfa_aen_lport.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/* messages define for BFA_AEN_CAT_LPORT Module */ -#ifndef __bfa_aen_lport_h__ -#define __bfa_aen_lport_h__ - -#include <cs/bfa_log.h> -#include <defs/bfa_defs_aen.h> - -#define BFA_AEN_LPORT_NEW \ - BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, BFA_LPORT_AEN_NEW) -#define BFA_AEN_LPORT_DELETE \ - BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, BFA_LPORT_AEN_DELETE) -#define BFA_AEN_LPORT_ONLINE \ - BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, BFA_LPORT_AEN_ONLINE) -#define BFA_AEN_LPORT_OFFLINE \ - BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, BFA_LPORT_AEN_OFFLINE) -#define BFA_AEN_LPORT_DISCONNECT \ - BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, BFA_LPORT_AEN_DISCONNECT) -#define BFA_AEN_LPORT_NEW_PROP \ - BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, BFA_LPORT_AEN_NEW_PROP) -#define BFA_AEN_LPORT_DELETE_PROP \ - BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, BFA_LPORT_AEN_DELETE_PROP) -#define BFA_AEN_LPORT_NEW_STANDARD \ - BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, BFA_LPORT_AEN_NEW_STANDARD) -#define BFA_AEN_LPORT_DELETE_STANDARD \ - BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, BFA_LPORT_AEN_DELETE_STANDARD) -#define BFA_AEN_LPORT_NPIV_DUP_WWN \ - BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, BFA_LPORT_AEN_NPIV_DUP_WWN) -#define BFA_AEN_LPORT_NPIV_FABRIC_MAX \ - BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, BFA_LPORT_AEN_NPIV_FABRIC_MAX) -#define BFA_AEN_LPORT_NPIV_UNKNOWN \ - BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, BFA_LPORT_AEN_NPIV_UNKNOWN) - -#endif - diff --git a/drivers/scsi/bfa/include/aen/bfa_aen_port.h b/drivers/scsi/bfa/include/aen/bfa_aen_port.h deleted file mode 100644 index 9add905a622d..000000000000 --- a/drivers/scsi/bfa/include/aen/bfa_aen_port.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/* messages define for BFA_AEN_CAT_PORT Module */ -#ifndef __bfa_aen_port_h__ -#define __bfa_aen_port_h__ - -#include <cs/bfa_log.h> -#include <defs/bfa_defs_aen.h> - -#define BFA_AEN_PORT_ONLINE \ - BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_ONLINE) -#define BFA_AEN_PORT_OFFLINE \ - BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_OFFLINE) -#define BFA_AEN_PORT_RLIR \ - BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_RLIR) -#define BFA_AEN_PORT_SFP_INSERT \ - BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_SFP_INSERT) -#define BFA_AEN_PORT_SFP_REMOVE \ - BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_SFP_REMOVE) -#define BFA_AEN_PORT_SFP_POM \ - BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_SFP_POM) -#define BFA_AEN_PORT_ENABLE \ - BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_ENABLE) -#define BFA_AEN_PORT_DISABLE \ - BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_DISABLE) -#define BFA_AEN_PORT_AUTH_ON \ - BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_AUTH_ON) -#define BFA_AEN_PORT_AUTH_OFF \ - BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_AUTH_OFF) -#define BFA_AEN_PORT_DISCONNECT \ - BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_DISCONNECT) -#define BFA_AEN_PORT_QOS_NEG \ - BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_QOS_NEG) -#define BFA_AEN_PORT_FABRIC_NAME_CHANGE \ - BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_FABRIC_NAME_CHANGE) -#define BFA_AEN_PORT_SFP_ACCESS_ERROR \ - BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_SFP_ACCESS_ERROR) -#define BFA_AEN_PORT_SFP_UNSUPPORT \ - BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_SFP_UNSUPPORT) - -#endif - diff --git a/drivers/scsi/bfa/include/aen/bfa_aen_rport.h b/drivers/scsi/bfa/include/aen/bfa_aen_rport.h deleted file mode 100644 index 7e4be1fd5e15..000000000000 --- a/drivers/scsi/bfa/include/aen/bfa_aen_rport.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/* messages define for BFA_AEN_CAT_RPORT Module */ -#ifndef __bfa_aen_rport_h__ -#define __bfa_aen_rport_h__ - -#include <cs/bfa_log.h> -#include <defs/bfa_defs_aen.h> - -#define BFA_AEN_RPORT_ONLINE \ - BFA_LOG_CREATE_ID(BFA_AEN_CAT_RPORT, BFA_RPORT_AEN_ONLINE) -#define BFA_AEN_RPORT_OFFLINE \ - BFA_LOG_CREATE_ID(BFA_AEN_CAT_RPORT, BFA_RPORT_AEN_OFFLINE) -#define BFA_AEN_RPORT_DISCONNECT \ - BFA_LOG_CREATE_ID(BFA_AEN_CAT_RPORT, BFA_RPORT_AEN_DISCONNECT) -#define BFA_AEN_RPORT_QOS_PRIO \ - BFA_LOG_CREATE_ID(BFA_AEN_CAT_RPORT, BFA_RPORT_AEN_QOS_PRIO) -#define BFA_AEN_RPORT_QOS_FLOWID \ - BFA_LOG_CREATE_ID(BFA_AEN_CAT_RPORT, BFA_RPORT_AEN_QOS_FLOWID) - -#endif - diff --git a/drivers/scsi/bfa/include/bfa.h b/drivers/scsi/bfa/include/bfa.h deleted file mode 100644 index d52b32f5695c..000000000000 --- a/drivers/scsi/bfa/include/bfa.h +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ -#ifndef __BFA_H__ -#define __BFA_H__ - -#include <bfa_os_inc.h> -#include <cs/bfa_debug.h> -#include <cs/bfa_q.h> -#include <cs/bfa_trc.h> -#include <cs/bfa_log.h> -#include <cs/bfa_plog.h> -#include <defs/bfa_defs_status.h> -#include <defs/bfa_defs_ioc.h> -#include <defs/bfa_defs_iocfc.h> -#include <aen/bfa_aen.h> -#include <bfi/bfi.h> - -struct bfa_s; -#include <bfa_intr_priv.h> - -struct bfa_pcidev_s; - -/** - * PCI devices supported by the current BFA - */ -struct bfa_pciid_s { - u16 device_id; - u16 vendor_id; -}; - -extern char bfa_version[]; - -/** - * BFA Power Mgmt Commands - */ -enum bfa_pm_cmd { - BFA_PM_CTL_D0 = 0, - BFA_PM_CTL_D1 = 1, - BFA_PM_CTL_D2 = 2, - BFA_PM_CTL_D3 = 3, -}; - -/** - * BFA memory resources - */ -enum bfa_mem_type { - BFA_MEM_TYPE_KVA = 1, /*! Kernel Virtual Memory *(non-dma-able) */ - BFA_MEM_TYPE_DMA = 2, /*! DMA-able memory */ - BFA_MEM_TYPE_MAX = BFA_MEM_TYPE_DMA, -}; - -struct bfa_mem_elem_s { - enum bfa_mem_type mem_type; /* see enum bfa_mem_type */ - u32 mem_len; /* Total Length in Bytes */ - u8 *kva; /* kernel virtual address */ - u64 dma; /* dma address if DMA memory */ - u8 *kva_curp; /* kva allocation cursor */ - u64 dma_curp; /* dma allocation cursor */ -}; - -struct bfa_meminfo_s { - struct bfa_mem_elem_s meminfo[BFA_MEM_TYPE_MAX]; -}; -#define bfa_meminfo_kva(_m) \ - ((_m)->meminfo[BFA_MEM_TYPE_KVA - 1].kva_curp) -#define bfa_meminfo_dma_virt(_m) \ - ((_m)->meminfo[BFA_MEM_TYPE_DMA - 1].kva_curp) -#define bfa_meminfo_dma_phys(_m) \ - ((_m)->meminfo[BFA_MEM_TYPE_DMA - 1].dma_curp) - -/** - * Generic Scatter Gather Element used by driver - */ -struct bfa_sge_s { - u32 sg_len; - void *sg_addr; -}; - -#define bfa_sge_to_be(__sge) do { \ - ((u32 *)(__sge))[0] = bfa_os_htonl(((u32 *)(__sge))[0]); \ - ((u32 *)(__sge))[1] = bfa_os_htonl(((u32 *)(__sge))[1]); \ - ((u32 *)(__sge))[2] = bfa_os_htonl(((u32 *)(__sge))[2]); \ -} while (0) - - -/* - * bfa stats interfaces - */ -#define bfa_stats(_mod, _stats) ((_mod)->stats._stats++) - -#define bfa_ioc_get_stats(__bfa, __ioc_stats) \ - bfa_ioc_fetch_stats(&(__bfa)->ioc, __ioc_stats) -#define bfa_ioc_clear_stats(__bfa) \ - bfa_ioc_clr_stats(&(__bfa)->ioc) -#define bfa_get_nports(__bfa) \ - bfa_ioc_get_nports(&(__bfa)->ioc) -#define bfa_get_adapter_manufacturer(__bfa, __manufacturer) \ - bfa_ioc_get_adapter_manufacturer(&(__bfa)->ioc, __manufacturer) -#define bfa_get_adapter_model(__bfa, __model) \ - bfa_ioc_get_adapter_model(&(__bfa)->ioc, __model) -#define bfa_get_adapter_serial_num(__bfa, __serial_num) \ - bfa_ioc_get_adapter_serial_num(&(__bfa)->ioc, __serial_num) -#define bfa_get_adapter_fw_ver(__bfa, __fw_ver) \ - bfa_ioc_get_adapter_fw_ver(&(__bfa)->ioc, __fw_ver) -#define bfa_get_adapter_optrom_ver(__bfa, __optrom_ver) \ - bfa_ioc_get_adapter_optrom_ver(&(__bfa)->ioc, __optrom_ver) -#define bfa_get_pci_chip_rev(__bfa, __chip_rev) \ - bfa_ioc_get_pci_chip_rev(&(__bfa)->ioc, __chip_rev) -#define bfa_get_ioc_state(__bfa) \ - bfa_ioc_get_state(&(__bfa)->ioc) -#define bfa_get_type(__bfa) \ - 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) - -/* - * bfa API functions - */ -void bfa_get_pciids(struct bfa_pciid_s **pciids, int *npciids); -void bfa_cfg_get_default(struct bfa_iocfc_cfg_s *cfg); -void bfa_cfg_get_min(struct bfa_iocfc_cfg_s *cfg); -void bfa_cfg_get_meminfo(struct bfa_iocfc_cfg_s *cfg, - struct bfa_meminfo_s *meminfo); -void bfa_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, - struct bfa_meminfo_s *meminfo, - struct bfa_pcidev_s *pcidev); -void bfa_init_trc(struct bfa_s *bfa, struct bfa_trc_mod_s *trcmod); -void bfa_init_log(struct bfa_s *bfa, struct bfa_log_mod_s *logmod); -void bfa_init_aen(struct bfa_s *bfa, struct bfa_aen_s *aen); -void bfa_init_plog(struct bfa_s *bfa, struct bfa_plog_s *plog); -void bfa_detach(struct bfa_s *bfa); -void bfa_init(struct bfa_s *bfa); -void bfa_start(struct bfa_s *bfa); -void bfa_stop(struct bfa_s *bfa); -void bfa_attach_fcs(struct bfa_s *bfa); -void bfa_cb_init(void *bfad, bfa_status_t status); -void bfa_cb_stop(void *bfad, bfa_status_t status); -void bfa_cb_updateq(void *bfad, bfa_status_t status); - -bfa_boolean_t bfa_intx(struct bfa_s *bfa); -void bfa_isr_enable(struct bfa_s *bfa); -void bfa_isr_disable(struct bfa_s *bfa); -void bfa_msix_getvecs(struct bfa_s *bfa, u32 *msix_vecs_bmap, - u32 *num_vecs, u32 *max_vec_bit); -#define bfa_msix(__bfa, __vec) ((__bfa)->msix.handler[__vec](__bfa, __vec)) - -void bfa_comp_deq(struct bfa_s *bfa, struct list_head *comp_q); -void bfa_comp_process(struct bfa_s *bfa, struct list_head *comp_q); -void bfa_comp_free(struct bfa_s *bfa, struct list_head *comp_q); - -typedef void (*bfa_cb_ioc_t) (void *cbarg, enum bfa_status status); -void bfa_iocfc_get_attr(struct bfa_s *bfa, struct bfa_iocfc_attr_s *attr); -bfa_status_t bfa_iocfc_get_stats(struct bfa_s *bfa, - struct bfa_iocfc_stats_s *stats, - bfa_cb_ioc_t cbfn, void *cbarg); -bfa_status_t bfa_iocfc_clear_stats(struct bfa_s *bfa, - bfa_cb_ioc_t cbfn, void *cbarg); -void bfa_get_attr(struct bfa_s *bfa, struct bfa_ioc_attr_s *ioc_attr); - -void bfa_adapter_get_attr(struct bfa_s *bfa, - struct bfa_adapter_attr_s *ad_attr); -u64 bfa_adapter_get_id(struct bfa_s *bfa); - -bfa_status_t bfa_iocfc_israttr_set(struct bfa_s *bfa, - struct bfa_iocfc_intr_attr_s *attr); - -void bfa_iocfc_enable(struct bfa_s *bfa); -void bfa_iocfc_disable(struct bfa_s *bfa); -void bfa_ioc_auto_recover(bfa_boolean_t auto_recover); -void bfa_chip_reset(struct bfa_s *bfa); -void bfa_cb_ioc_disable(void *bfad); -void bfa_timer_tick(struct bfa_s *bfa); -#define bfa_timer_start(_bfa, _timer, _timercb, _arg, _timeout) \ - bfa_timer_begin(&(_bfa)->timer_mod, _timer, _timercb, _arg, _timeout) - -/* - * BFA debug API functions - */ -bfa_status_t bfa_debug_fwtrc(struct bfa_s *bfa, void *trcdata, int *trclen); -bfa_status_t bfa_debug_fwsave(struct bfa_s *bfa, void *trcdata, int *trclen); -void bfa_debug_fwsave_clear(struct bfa_s *bfa); - -#include "bfa_priv.h" - -#endif /* __BFA_H__ */ diff --git a/drivers/scsi/bfa/include/bfa_fcpim.h b/drivers/scsi/bfa/include/bfa_fcpim.h deleted file mode 100644 index 4bc9453081df..000000000000 --- a/drivers/scsi/bfa/include/bfa_fcpim.h +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFA_FCPIM_H__ -#define __BFA_FCPIM_H__ - -#include <bfa.h> -#include <bfa_svc.h> -#include <bfi/bfi_fcpim.h> -#include <defs/bfa_defs_fcpim.h> - -/* - * forward declarations - */ -struct bfa_itnim_s; -struct bfa_ioim_s; -struct bfa_tskim_s; -struct bfad_ioim_s; -struct bfad_tskim_s; - -/* - * bfa fcpim module API functions - */ -void bfa_fcpim_path_tov_set(struct bfa_s *bfa, u16 path_tov); -u16 bfa_fcpim_path_tov_get(struct bfa_s *bfa); -void bfa_fcpim_qdepth_set(struct bfa_s *bfa, u16 q_depth); -u16 bfa_fcpim_qdepth_get(struct bfa_s *bfa); -bfa_status_t bfa_fcpim_get_modstats(struct bfa_s *bfa, - struct bfa_fcpim_stats_s *modstats); -bfa_status_t bfa_fcpim_clr_modstats(struct bfa_s *bfa); -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 - */ -struct bfa_itnim_s *bfa_itnim_create(struct bfa_s *bfa, - struct bfa_rport_s *rport, void *itnim); -void bfa_itnim_delete(struct bfa_itnim_s *itnim); -void bfa_itnim_online(struct bfa_itnim_s *itnim, - bfa_boolean_t seq_rec); -void bfa_itnim_offline(struct bfa_itnim_s *itnim); -void bfa_itnim_get_stats(struct bfa_itnim_s *itnim, - struct bfa_itnim_hal_stats_s *stats); -void bfa_itnim_clear_stats(struct bfa_itnim_s *itnim); - -#define bfa_itnim_get_reqq(__ioim) (((struct bfa_ioim_s *)__ioim)->itnim->reqq) - -/** - * BFA completion callback for bfa_itnim_online(). - * - * @param[in] itnim FCS or driver itnim instance - * - * return None - */ -void bfa_cb_itnim_online(void *itnim); - -/** - * BFA completion callback for bfa_itnim_offline(). - * - * @param[in] itnim FCS or driver itnim instance - * - * return None - */ -void bfa_cb_itnim_offline(void *itnim); -void bfa_cb_itnim_tov_begin(void *itnim); -void bfa_cb_itnim_tov(void *itnim); - -/** - * BFA notification to FCS/driver for second level error recovery. - * - * Atleast one I/O request has timedout and target is unresponsive to - * repeated abort requests. Second level error recovery should be initiated - * by starting implicit logout and recovery procedures. - * - * @param[in] itnim FCS or driver itnim instance - * - * return None - */ -void bfa_cb_itnim_sler(void *itnim); - -/* - * bfa ioim API functions - */ -struct bfa_ioim_s *bfa_ioim_alloc(struct bfa_s *bfa, - struct bfad_ioim_s *dio, - struct bfa_itnim_s *itnim, - u16 nsgles); - -void bfa_ioim_free(struct bfa_ioim_s *ioim); -void bfa_ioim_start(struct bfa_ioim_s *ioim); -void bfa_ioim_abort(struct bfa_ioim_s *ioim); -void bfa_ioim_delayed_comp(struct bfa_ioim_s *ioim, - bfa_boolean_t iotov); - - -/** - * I/O completion notification. - * - * @param[in] dio driver IO structure - * @param[in] io_status IO completion status - * @param[in] scsi_status SCSI status returned by target - * @param[in] sns_len SCSI sense length, 0 if none - * @param[in] sns_info SCSI sense data, if any - * @param[in] residue Residual length - * - * @return None - */ -void bfa_cb_ioim_done(void *bfad, struct bfad_ioim_s *dio, - enum bfi_ioim_status io_status, - u8 scsi_status, int sns_len, - u8 *sns_info, s32 residue); - -/** - * I/O good completion notification. - * - * @param[in] dio driver IO structure - * - * @return None - */ -void bfa_cb_ioim_good_comp(void *bfad, struct bfad_ioim_s *dio); - -/** - * I/O abort completion notification - * - * @param[in] dio driver IO that was aborted - * - * @return None - */ -void bfa_cb_ioim_abort(void *bfad, struct bfad_ioim_s *dio); -void bfa_cb_ioim_resfree(void *hcb_bfad); - -void bfa_cb_ioim_resfree(void *hcb_bfad); - -/* - * bfa tskim API functions - */ -struct bfa_tskim_s *bfa_tskim_alloc(struct bfa_s *bfa, - struct bfad_tskim_s *dtsk); -void bfa_tskim_free(struct bfa_tskim_s *tskim); -void bfa_tskim_start(struct bfa_tskim_s *tskim, - struct bfa_itnim_s *itnim, lun_t lun, - enum fcp_tm_cmnd tm, u8 t_secs); -void bfa_cb_tskim_done(void *bfad, struct bfad_tskim_s *dtsk, - enum bfi_tskim_status tsk_status); - -#endif /* __BFA_FCPIM_H__ */ diff --git a/drivers/scsi/bfa/include/bfa_fcptm.h b/drivers/scsi/bfa/include/bfa_fcptm.h deleted file mode 100644 index 5f5ffe0bb1bb..000000000000 --- a/drivers/scsi/bfa/include/bfa_fcptm.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFA_FCPTM_H__ -#define __BFA_FCPTM_H__ - -#include <bfa.h> -#include <bfa_svc.h> -#include <bfi/bfi_fcptm.h> - -/* - * forward declarations - */ -struct bfa_tin_s; -struct bfa_iotm_s; -struct bfa_tsktm_s; - -/* - * bfa fcptm module API functions - */ -void bfa_fcptm_path_tov_set(struct bfa_s *bfa, u16 path_tov); -u16 bfa_fcptm_path_tov_get(struct bfa_s *bfa); -void bfa_fcptm_qdepth_set(struct bfa_s *bfa, u16 q_depth); -u16 bfa_fcptm_qdepth_get(struct bfa_s *bfa); - -/* - * bfa tin API functions - */ -void bfa_tin_get_stats(struct bfa_tin_s *tin, struct bfa_tin_stats_s *stats); -void bfa_tin_clear_stats(struct bfa_tin_s *tin); - -#endif /* __BFA_FCPTM_H__ */ - diff --git a/drivers/scsi/bfa/include/bfa_svc.h b/drivers/scsi/bfa/include/bfa_svc.h deleted file mode 100644 index 7840943d73b0..000000000000 --- a/drivers/scsi/bfa/include/bfa_svc.h +++ /dev/null @@ -1,338 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ -#ifndef __BFA_SVC_H__ -#define __BFA_SVC_H__ - -/* - * forward declarations - */ -struct bfa_fcxp_s; - -#include <defs/bfa_defs_status.h> -#include <defs/bfa_defs_pport.h> -#include <defs/bfa_defs_rport.h> -#include <defs/bfa_defs_qos.h> -#include <defs/bfa_defs_fcport.h> -#include <cs/bfa_sm.h> -#include <bfa.h> - -/** - * BFA rport information. - */ -struct bfa_rport_info_s { - u16 max_frmsz; /* max rcv pdu size */ - u32 pid:24, /* remote port ID */ - lp_tag:8; /* tag */ - u32 local_pid:24, /* local port ID */ - cisc:8; /* CIRO supported */ - u8 fc_class; /* supported FC classes. enum fc_cos */ - u8 vf_en; /* virtual fabric enable */ - u16 vf_id; /* virtual fabric ID */ - enum bfa_pport_speed speed; /* Rport's current speed */ -}; - -/** - * BFA rport data structure - */ -struct bfa_rport_s { - struct list_head qe; /* queue element */ - bfa_sm_t sm; /* state machine */ - struct bfa_s *bfa; /* backpointer to BFA */ - void *rport_drv; /* fcs/driver rport object */ - u16 fw_handle; /* firmware rport handle */ - u16 rport_tag; /* BFA rport tag */ - struct bfa_rport_info_s rport_info; /* rport info from fcs/driver */ - struct bfa_reqq_wait_s reqq_wait; /* to wait for room in reqq */ - struct bfa_cb_qe_s hcb_qe; /* BFA callback qelem */ - struct bfa_rport_hal_stats_s stats; /* BFA rport statistics */ - struct bfa_rport_qos_attr_s qos_attr; - union a { - bfa_status_t status; /* f/w status */ - void *fw_msg; /* QoS scn event */ - } event_arg; -}; -#define BFA_RPORT_FC_COS(_rport) ((_rport)->rport_info.fc_class) - -/** - * Send completion callback. - */ -typedef void (*bfa_cb_fcxp_send_t) (void *bfad_fcxp, struct bfa_fcxp_s *fcxp, - void *cbarg, enum bfa_status req_status, - u32 rsp_len, u32 resid_len, - struct fchs_s *rsp_fchs); - -/** - * BFA fcxp allocation (asynchronous) - */ -typedef void (*bfa_fcxp_alloc_cbfn_t) (void *cbarg, struct bfa_fcxp_s *fcxp); - -struct bfa_fcxp_wqe_s { - struct list_head qe; - bfa_fcxp_alloc_cbfn_t alloc_cbfn; - void *alloc_cbarg; -}; - -typedef u64 (*bfa_fcxp_get_sgaddr_t) (void *bfad_fcxp, int sgeid); -typedef u32 (*bfa_fcxp_get_sglen_t) (void *bfad_fcxp, int sgeid); - -#define BFA_UF_BUFSZ (2 * 1024 + 256) - -/** - * @todo private - */ -struct bfa_uf_buf_s { - u8 d[BFA_UF_BUFSZ]; -}; - - -struct bfa_uf_s { - struct list_head qe; /* queue element */ - struct bfa_s *bfa; /* bfa instance */ - u16 uf_tag; /* identifying tag fw msgs */ - u16 vf_id; - u16 src_rport_handle; - u16 rsvd; - u8 *data_ptr; - u16 data_len; /* actual receive length */ - u16 pb_len; /* posted buffer length */ - void *buf_kva; /* buffer virtual address */ - u64 buf_pa; /* buffer physical address */ - struct bfa_cb_qe_s hcb_qe; /* comp: BFA comp qelem */ - struct bfa_sge_s sges[BFI_SGE_INLINE_MAX]; -}; - -typedef void (*bfa_cb_pport_t) (void *cbarg, enum bfa_status status); - -/** - * bfa lport login/logout service interface - */ -struct bfa_lps_s { - struct list_head qe; /* queue element */ - struct bfa_s *bfa; /* parent bfa instance */ - bfa_sm_t sm; /* finite state machine */ - u8 lp_tag; /* lport tag */ - u8 reqq; /* lport request queue */ - u8 alpa; /* ALPA for loop topologies */ - u32 lp_pid; /* lport port ID */ - bfa_boolean_t fdisc; /* send FDISC instead of FLOGI */ - bfa_boolean_t auth_en; /* enable authentication */ - bfa_boolean_t auth_req; /* authentication required */ - bfa_boolean_t npiv_en; /* NPIV is allowed by peer */ - bfa_boolean_t fport; /* attached peer is F_PORT */ - bfa_boolean_t brcd_switch;/* attached peer is brcd switch */ - bfa_status_t status; /* login status */ - u16 pdusz; /* max receive PDU size */ - u16 pr_bbcred; /* BB_CREDIT from peer */ - u8 lsrjt_rsn; /* LSRJT reason */ - u8 lsrjt_expl; /* LSRJT explanation */ - wwn_t pwwn; /* port wwn of lport */ - wwn_t nwwn; /* node wwn of lport */ - wwn_t pr_pwwn; /* port wwn of lport peer */ - wwn_t pr_nwwn; /* node wwn of lport peer */ - mac_t lp_mac; /* fpma/spma MAC for lport */ - mac_t fcf_mac; /* FCF MAC of lport */ - struct bfa_reqq_wait_s wqe; /* request wait queue element */ - void *uarg; /* user callback arg */ - struct bfa_cb_qe_s hcb_qe; /* comp: callback qelem */ - struct bfi_lps_login_rsp_s *loginrsp; - bfa_eproto_status_t ext_status; -}; - -#define BFA_FCPORT(_bfa) (&((_bfa)->modules.port)) - -/* - * bfa pport API functions - */ -bfa_status_t bfa_fcport_enable(struct bfa_s *bfa); -bfa_status_t bfa_fcport_disable(struct bfa_s *bfa); -bfa_status_t bfa_fcport_cfg_speed(struct bfa_s *bfa, - enum bfa_pport_speed speed); -enum bfa_pport_speed bfa_fcport_get_speed(struct bfa_s *bfa); -bfa_status_t bfa_fcport_cfg_topology(struct bfa_s *bfa, - enum bfa_pport_topology topo); -enum bfa_pport_topology bfa_fcport_get_topology(struct bfa_s *bfa); -bfa_status_t bfa_fcport_cfg_hardalpa(struct bfa_s *bfa, u8 alpa); -bfa_boolean_t bfa_fcport_get_hardalpa(struct bfa_s *bfa, u8 *alpa); -u8 bfa_fcport_get_myalpa(struct bfa_s *bfa); -bfa_status_t bfa_fcport_clr_hardalpa(struct bfa_s *bfa); -bfa_status_t bfa_fcport_cfg_maxfrsize(struct bfa_s *bfa, u16 maxsize); -u16 bfa_fcport_get_maxfrsize(struct bfa_s *bfa); -u32 bfa_fcport_mypid(struct bfa_s *bfa); -u8 bfa_fcport_get_rx_bbcredit(struct bfa_s *bfa); -bfa_status_t bfa_fcport_trunk_enable(struct bfa_s *bfa, u8 bitmap); -bfa_status_t bfa_fcport_trunk_disable(struct bfa_s *bfa); -bfa_boolean_t bfa_fcport_trunk_query(struct bfa_s *bfa, u32 *bitmap); -void bfa_fcport_get_attr(struct bfa_s *bfa, struct bfa_pport_attr_s *attr); -wwn_t bfa_fcport_get_wwn(struct bfa_s *bfa, bfa_boolean_t node); -void bfa_fcport_event_register(struct bfa_s *bfa, - void (*event_cbfn) (void *cbarg, - bfa_pport_event_t event), void *event_cbarg); -bfa_boolean_t bfa_fcport_is_disabled(struct bfa_s *bfa); -void bfa_fcport_cfg_qos(struct bfa_s *bfa, bfa_boolean_t on_off); -void bfa_fcport_cfg_ratelim(struct bfa_s *bfa, bfa_boolean_t on_off); -bfa_status_t bfa_fcport_cfg_ratelim_speed(struct bfa_s *bfa, - enum bfa_pport_speed speed); -enum bfa_pport_speed bfa_fcport_get_ratelim_speed(struct bfa_s *bfa); - -void bfa_fcport_set_tx_bbcredit(struct bfa_s *bfa, u16 tx_bbcredit); -void bfa_fcport_busy(struct bfa_s *bfa, bfa_boolean_t status); -void bfa_fcport_beacon(struct bfa_s *bfa, bfa_boolean_t beacon, - bfa_boolean_t link_e2e_beacon); -void bfa_cb_pport_event(void *cbarg, bfa_pport_event_t event); -void bfa_fcport_qos_get_attr(struct bfa_s *bfa, - struct bfa_qos_attr_s *qos_attr); -void bfa_fcport_qos_get_vc_attr(struct bfa_s *bfa, - struct bfa_qos_vc_attr_s *qos_vc_attr); -bfa_status_t bfa_fcport_get_qos_stats(struct bfa_s *bfa, - union bfa_fcport_stats_u *stats, - bfa_cb_pport_t cbfn, void *cbarg); -bfa_status_t bfa_fcport_clear_qos_stats(struct bfa_s *bfa, bfa_cb_pport_t cbfn, - void *cbarg); -bfa_status_t bfa_fcport_get_fcoe_stats(struct bfa_s *bfa, - union bfa_fcport_stats_u *stats, - bfa_cb_pport_t cbfn, void *cbarg); -bfa_status_t bfa_fcport_clear_fcoe_stats(struct bfa_s *bfa, bfa_cb_pport_t cbfn, - void *cbarg); - -bfa_boolean_t bfa_fcport_is_ratelim(struct bfa_s *bfa); -bfa_boolean_t bfa_fcport_is_linkup(struct bfa_s *bfa); -bfa_status_t bfa_fcport_get_stats(struct bfa_s *bfa, - union bfa_fcport_stats_u *stats, - 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 - */ -struct bfa_rport_s *bfa_rport_create(struct bfa_s *bfa, void *rport_drv); -void bfa_rport_delete(struct bfa_rport_s *rport); -void bfa_rport_online(struct bfa_rport_s *rport, - struct bfa_rport_info_s *rport_info); -void bfa_rport_offline(struct bfa_rport_s *rport); -void bfa_rport_speed(struct bfa_rport_s *rport, enum bfa_pport_speed speed); -void bfa_rport_get_stats(struct bfa_rport_s *rport, - struct bfa_rport_hal_stats_s *stats); -void bfa_rport_clear_stats(struct bfa_rport_s *rport); -void bfa_cb_rport_online(void *rport); -void bfa_cb_rport_offline(void *rport); -void bfa_cb_rport_qos_scn_flowid(void *rport, - struct bfa_rport_qos_attr_s old_qos_attr, - struct bfa_rport_qos_attr_s new_qos_attr); -void bfa_cb_rport_qos_scn_prio(void *rport, - struct bfa_rport_qos_attr_s old_qos_attr, - struct bfa_rport_qos_attr_s new_qos_attr); -void bfa_rport_get_qos_attr(struct bfa_rport_s *rport, - struct bfa_rport_qos_attr_s *qos_attr); - -/* - * bfa fcxp API functions - */ -struct bfa_fcxp_s *bfa_fcxp_alloc(void *bfad_fcxp, struct bfa_s *bfa, - int nreq_sgles, int nrsp_sgles, - bfa_fcxp_get_sgaddr_t get_req_sga, - bfa_fcxp_get_sglen_t get_req_sglen, - bfa_fcxp_get_sgaddr_t get_rsp_sga, - bfa_fcxp_get_sglen_t get_rsp_sglen); -void bfa_fcxp_alloc_wait(struct bfa_s *bfa, struct bfa_fcxp_wqe_s *wqe, - bfa_fcxp_alloc_cbfn_t alloc_cbfn, void *cbarg); -void bfa_fcxp_walloc_cancel(struct bfa_s *bfa, - struct bfa_fcxp_wqe_s *wqe); -void bfa_fcxp_discard(struct bfa_fcxp_s *fcxp); - -void *bfa_fcxp_get_reqbuf(struct bfa_fcxp_s *fcxp); -void *bfa_fcxp_get_rspbuf(struct bfa_fcxp_s *fcxp); - -void bfa_fcxp_free(struct bfa_fcxp_s *fcxp); - -void bfa_fcxp_send(struct bfa_fcxp_s *fcxp, - struct bfa_rport_s *rport, u16 vf_id, u8 lp_tag, - bfa_boolean_t cts, enum fc_cos cos, - u32 reqlen, struct fchs_s *fchs, - bfa_cb_fcxp_send_t cbfn, - void *cbarg, - u32 rsp_maxlen, u8 rsp_timeout); -bfa_status_t bfa_fcxp_abort(struct bfa_fcxp_s *fcxp); -u32 bfa_fcxp_get_reqbufsz(struct bfa_fcxp_s *fcxp); -u32 bfa_fcxp_get_maxrsp(struct bfa_s *bfa); - -static inline void * -bfa_uf_get_frmbuf(struct bfa_uf_s *uf) -{ - return uf->data_ptr; -} - -static inline u16 -bfa_uf_get_frmlen(struct bfa_uf_s *uf) -{ - return uf->data_len; -} - -/** - * Callback prototype for unsolicited frame receive handler. - * - * @param[in] cbarg callback arg for receive handler - * @param[in] uf unsolicited frame descriptor - * - * @return None - */ -typedef void (*bfa_cb_uf_recv_t) (void *cbarg, struct bfa_uf_s *uf); - -/* - * bfa uf API functions - */ -void bfa_uf_recv_register(struct bfa_s *bfa, bfa_cb_uf_recv_t ufrecv, - void *cbarg); -void bfa_uf_free(struct bfa_uf_s *uf); - -/** - * bfa lport service api - */ - -u32 bfa_lps_get_max_vport(struct bfa_s *bfa); -struct bfa_lps_s *bfa_lps_alloc(struct bfa_s *bfa); -void bfa_lps_delete(struct bfa_lps_s *lps); -void bfa_lps_discard(struct bfa_lps_s *lps); -void bfa_lps_flogi(struct bfa_lps_s *lps, void *uarg, u8 alpa, u16 pdusz, - wwn_t pwwn, wwn_t nwwn, bfa_boolean_t auth_en); -void bfa_lps_fdisc(struct bfa_lps_s *lps, void *uarg, u16 pdusz, wwn_t pwwn, - wwn_t nwwn); -void bfa_lps_flogo(struct bfa_lps_s *lps); -void bfa_lps_fdisclogo(struct bfa_lps_s *lps); -u8 bfa_lps_get_tag(struct bfa_lps_s *lps); -bfa_boolean_t bfa_lps_is_npiv_en(struct bfa_lps_s *lps); -bfa_boolean_t bfa_lps_is_fport(struct bfa_lps_s *lps); -bfa_boolean_t bfa_lps_is_brcd_fabric(struct bfa_lps_s *lps); -bfa_boolean_t bfa_lps_is_authreq(struct bfa_lps_s *lps); -bfa_eproto_status_t bfa_lps_get_extstatus(struct bfa_lps_s *lps); -u32 bfa_lps_get_pid(struct bfa_lps_s *lps); -u8 bfa_lps_get_tag_from_pid(struct bfa_s *bfa, u32 pid); -u16 bfa_lps_get_peer_bbcredit(struct bfa_lps_s *lps); -wwn_t bfa_lps_get_peer_pwwn(struct bfa_lps_s *lps); -wwn_t bfa_lps_get_peer_nwwn(struct bfa_lps_s *lps); -u8 bfa_lps_get_lsrjt_rsn(struct bfa_lps_s *lps); -u8 bfa_lps_get_lsrjt_expl(struct bfa_lps_s *lps); -mac_t bfa_lps_get_lp_mac(struct bfa_lps_s *lps); -void bfa_cb_lps_flogi_comp(void *bfad, void *uarg, bfa_status_t status); -void bfa_cb_lps_flogo_comp(void *bfad, void *uarg); -void bfa_cb_lps_fdisc_comp(void *bfad, void *uarg, bfa_status_t status); -void bfa_cb_lps_fdisclogo_comp(void *bfad, void *uarg); -void bfa_cb_lps_cvl_event(void *bfad, void *uarg); - -#endif /* __BFA_SVC_H__ */ - diff --git a/drivers/scsi/bfa/include/bfa_timer.h b/drivers/scsi/bfa/include/bfa_timer.h deleted file mode 100644 index f71087448222..000000000000 --- a/drivers/scsi/bfa/include/bfa_timer.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ -#ifndef __BFA_TIMER_H__ -#define __BFA_TIMER_H__ - -#include <bfa_os_inc.h> -#include <cs/bfa_q.h> - -struct bfa_s; - -typedef void (*bfa_timer_cbfn_t)(void *); - -/** - * BFA timer data structure - */ -struct bfa_timer_s { - struct list_head qe; - bfa_timer_cbfn_t timercb; - void *arg; - int timeout; /**< in millisecs. */ -}; - -/** - * Timer module structure - */ -struct bfa_timer_mod_s { - struct list_head timer_q; -}; - -#define BFA_TIMER_FREQ 200 /**< specified in millisecs */ - -void bfa_timer_beat(struct bfa_timer_mod_s *mod); -void bfa_timer_init(struct bfa_timer_mod_s *mod); -void bfa_timer_begin(struct bfa_timer_mod_s *mod, struct bfa_timer_s *timer, - bfa_timer_cbfn_t timercb, void *arg, - unsigned int timeout); -void bfa_timer_stop(struct bfa_timer_s *timer); - -#endif /* __BFA_TIMER_H__ */ diff --git a/drivers/scsi/bfa/include/bfi/bfi.h b/drivers/scsi/bfa/include/bfi/bfi.h deleted file mode 100644 index a550e80cabd2..000000000000 --- a/drivers/scsi/bfa/include/bfi/bfi.h +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFI_H__ -#define __BFI_H__ - -#include <bfa_os_inc.h> -#include <defs/bfa_defs_status.h> - -#pragma pack(1) - -/** - * Msg header common to all msgs - */ -struct bfi_mhdr_s { - u8 msg_class; /* @ref bfi_mclass_t */ - u8 msg_id; /* msg opcode with in the class */ - union { - struct { - u8 rsvd; - u8 lpu_id; /* msg destination */ - } h2i; - u16 i2htok; /* token in msgs to host */ - } mtag; -}; - -#define bfi_h2i_set(_mh, _mc, _op, _lpuid) do { \ - (_mh).msg_class = (_mc); \ - (_mh).msg_id = (_op); \ - (_mh).mtag.h2i.lpu_id = (_lpuid); \ -} while (0) - -#define bfi_i2h_set(_mh, _mc, _op, _i2htok) do { \ - (_mh).msg_class = (_mc); \ - (_mh).msg_id = (_op); \ - (_mh).mtag.i2htok = (_i2htok); \ -} while (0) - -/* - * Message opcodes: 0-127 to firmware, 128-255 to host - */ -#define BFI_I2H_OPCODE_BASE 128 -#define BFA_I2HM(_x) ((_x) + BFI_I2H_OPCODE_BASE) - -/** - **************************************************************************** - * - * Scatter Gather Element and Page definition - * - **************************************************************************** - */ - -#define BFI_SGE_INLINE 1 -#define BFI_SGE_INLINE_MAX (BFI_SGE_INLINE + 1) - -/** - * SG Flags - */ -enum { - BFI_SGE_DATA = 0, /* data address, not last */ - BFI_SGE_DATA_CPL = 1, /* data addr, last in current page */ - BFI_SGE_DATA_LAST = 3, /* data address, last */ - BFI_SGE_LINK = 2, /* link address */ - BFI_SGE_PGDLEN = 2, /* cumulative data length for page */ -}; - -/** - * DMA addresses - */ -union bfi_addr_u { - struct { - u32 addr_lo; - u32 addr_hi; - } a32; -}; - -/** - * Scatter Gather Element - */ -struct bfi_sge_s { -#ifdef __BIGENDIAN - u32 flags:2, - rsvd:2, - sg_len:28; -#else - u32 sg_len:28, - rsvd:2, - flags:2; -#endif - union bfi_addr_u sga; -}; - -/** - * Scatter Gather Page - */ -#define BFI_SGPG_DATA_SGES 7 -#define BFI_SGPG_SGES_MAX (BFI_SGPG_DATA_SGES + 1) -#define BFI_SGPG_RSVD_WD_LEN 8 -struct bfi_sgpg_s { - struct bfi_sge_s sges[BFI_SGPG_SGES_MAX]; - u32 rsvd[BFI_SGPG_RSVD_WD_LEN]; -}; - -/* - * Large Message structure - 128 Bytes size Msgs - */ -#define BFI_LMSG_SZ 128 -#define BFI_LMSG_PL_WSZ \ - ((BFI_LMSG_SZ - sizeof(struct bfi_mhdr_s)) / 4) - -struct bfi_msg_s { - struct bfi_mhdr_s mhdr; - u32 pl[BFI_LMSG_PL_WSZ]; -}; - -/** - * Mailbox message structure - */ -#define BFI_MBMSG_SZ 7 -struct bfi_mbmsg_s { - struct bfi_mhdr_s mh; - u32 pl[BFI_MBMSG_SZ]; -}; - -/** - * Message Classes - */ -enum bfi_mclass { - BFI_MC_IOC = 1, /* IO Controller (IOC) */ - BFI_MC_DIAG = 2, /* Diagnostic Msgs */ - BFI_MC_FLASH = 3, /* Flash message class */ - BFI_MC_CEE = 4, /* CEE */ - BFI_MC_FCPORT = 5, /* FC port */ - BFI_MC_IOCFC = 6, /* FC - IO Controller (IOC) */ - BFI_MC_LL = 7, /* Link Layer */ - BFI_MC_UF = 8, /* Unsolicited frame receive */ - BFI_MC_FCXP = 9, /* FC Transport */ - BFI_MC_LPS = 10, /* lport fc login services */ - BFI_MC_RPORT = 11, /* Remote port */ - BFI_MC_ITNIM = 12, /* I-T nexus (Initiator mode) */ - BFI_MC_IOIM_READ = 13, /* read IO (Initiator mode) */ - BFI_MC_IOIM_WRITE = 14, /* write IO (Initiator mode) */ - BFI_MC_IOIM_IO = 15, /* IO (Initiator mode) */ - BFI_MC_IOIM = 16, /* IO (Initiator mode) */ - BFI_MC_IOIM_IOCOM = 17, /* good IO completion */ - BFI_MC_TSKIM = 18, /* Initiator Task management */ - BFI_MC_SBOOT = 19, /* SAN boot services */ - BFI_MC_IPFC = 20, /* IP over FC Msgs */ - BFI_MC_PORT = 21, /* Physical port */ - BFI_MC_MAX = 32 -}; - -#define BFI_IOC_MAX_CQS 4 -#define BFI_IOC_MAX_CQS_ASIC 8 -#define BFI_IOC_MSGLEN_MAX 32 /* 32 bytes */ - -#pragma pack() - -#endif /* __BFI_H__ */ - diff --git a/drivers/scsi/bfa/include/bfi/bfi_boot.h b/drivers/scsi/bfa/include/bfi/bfi_boot.h deleted file mode 100644 index 5955afe7d108..000000000000 --- a/drivers/scsi/bfa/include/bfi/bfi_boot.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ -/* - * bfi_boot.h - */ - -#ifndef __BFI_BOOT_H__ -#define __BFI_BOOT_H__ - -#define BFI_BOOT_TYPE_OFF 8 -#define BFI_BOOT_PARAM_OFF 12 - -#define BFI_BOOT_TYPE_NORMAL 0 /* param is device id */ -#define BFI_BOOT_TYPE_FLASH 1 -#define BFI_BOOT_TYPE_MEMTEST 2 - -#define BFI_BOOT_MEMTEST_RES_ADDR 0x900 -#define BFI_BOOT_MEMTEST_RES_SIG 0xA0A1A2A3 - -#endif diff --git a/drivers/scsi/bfa/include/bfi/bfi_cee.h b/drivers/scsi/bfa/include/bfi/bfi_cee.h deleted file mode 100644 index 0970596583ea..000000000000 --- a/drivers/scsi/bfa/include/bfi/bfi_cee.h +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ -/** - * Copyright (c) 2006-2009 Brocade Communications Systems, Inc. - * All rights reserved. - * - * bfi_dcbx.h BFI Interface (Mailbox commands and related structures) - * between host driver and DCBX/LLDP firmware module. - * -**/ - -#ifndef __BFI_CEE_H__ -#define __BFI_CEE_H__ - -#include <bfi/bfi.h> - -#pragma pack(1) - - -enum bfi_cee_h2i_msgs_e { - BFI_CEE_H2I_GET_CFG_REQ = 1, - BFI_CEE_H2I_RESET_STATS = 2, - BFI_CEE_H2I_GET_STATS_REQ = 3, -}; - - -enum bfi_cee_i2h_msgs_e { - BFI_CEE_I2H_GET_CFG_RSP = BFA_I2HM(1), - BFI_CEE_I2H_RESET_STATS_RSP = BFA_I2HM(2), - BFI_CEE_I2H_GET_STATS_RSP = BFA_I2HM(3), -}; - - -/* Data structures */ - -/* - * BFI_CEE_H2I_RESET_STATS - */ -struct bfi_lldp_reset_stats_s { - struct bfi_mhdr_s mh; -}; - -/* - * BFI_CEE_H2I_RESET_STATS - */ -struct bfi_cee_reset_stats_s { - struct bfi_mhdr_s mh; -}; - -/* - * BFI_CEE_H2I_GET_CFG_REQ - */ -struct bfi_cee_get_req_s { - struct bfi_mhdr_s mh; - union bfi_addr_u dma_addr; -}; - - -/* - * BFI_CEE_I2H_GET_CFG_RSP - */ -struct bfi_cee_get_rsp_s { - struct bfi_mhdr_s mh; - u8 cmd_status; - u8 rsvd[3]; -}; - -/* - * BFI_CEE_H2I_GET_STATS_REQ - */ -struct bfi_cee_stats_req_s { - struct bfi_mhdr_s mh; - union bfi_addr_u dma_addr; -}; - - -/* - * BFI_CEE_I2H_GET_STATS_RSP - */ -struct bfi_cee_stats_rsp_s { - struct bfi_mhdr_s mh; - u8 cmd_status; - u8 rsvd[3]; -}; - - - -union bfi_cee_h2i_msg_u { - struct bfi_mhdr_s mh; - struct bfi_cee_get_req_s get_req; - struct bfi_cee_stats_req_s stats_req; -}; - - -union bfi_cee_i2h_msg_u { - struct bfi_mhdr_s mh; - struct bfi_cee_get_rsp_s get_rsp; - struct bfi_cee_stats_rsp_s stats_rsp; -}; - -#pragma pack() - - -#endif /* __BFI_CEE_H__ */ - diff --git a/drivers/scsi/bfa/include/bfi/bfi_ctreg.h b/drivers/scsi/bfa/include/bfi/bfi_ctreg.h deleted file mode 100644 index c0ef5a93b797..000000000000 --- a/drivers/scsi/bfa/include/bfi/bfi_ctreg.h +++ /dev/null @@ -1,640 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/* - * bfi_ctreg.h catapult host block register definitions - * - * !!! Do not edit. Auto generated. !!! - */ - -#ifndef __BFI_CTREG_H__ -#define __BFI_CTREG_H__ - - -#define HOSTFN0_LPU_MBOX0_0 0x00019200 -#define HOSTFN1_LPU_MBOX0_8 0x00019260 -#define LPU_HOSTFN0_MBOX0_0 0x00019280 -#define LPU_HOSTFN1_MBOX0_8 0x000192e0 -#define HOSTFN2_LPU_MBOX0_0 0x00019400 -#define HOSTFN3_LPU_MBOX0_8 0x00019460 -#define LPU_HOSTFN2_MBOX0_0 0x00019480 -#define LPU_HOSTFN3_MBOX0_8 0x000194e0 -#define HOSTFN0_INT_STATUS 0x00014000 -#define __HOSTFN0_HALT_OCCURRED 0x01000000 -#define __HOSTFN0_INT_STATUS_LVL_MK 0x00f00000 -#define __HOSTFN0_INT_STATUS_LVL_SH 20 -#define __HOSTFN0_INT_STATUS_LVL(_v) ((_v) << __HOSTFN0_INT_STATUS_LVL_SH) -#define __HOSTFN0_INT_STATUS_P_MK 0x000f0000 -#define __HOSTFN0_INT_STATUS_P_SH 16 -#define __HOSTFN0_INT_STATUS_P(_v) ((_v) << __HOSTFN0_INT_STATUS_P_SH) -#define __HOSTFN0_INT_STATUS_F 0x0000ffff -#define HOSTFN0_INT_MSK 0x00014004 -#define HOST_PAGE_NUM_FN0 0x00014008 -#define __HOST_PAGE_NUM_FN 0x000001ff -#define HOST_MSIX_ERR_INDEX_FN0 0x0001400c -#define __MSIX_ERR_INDEX_FN 0x000001ff -#define HOSTFN1_INT_STATUS 0x00014100 -#define __HOSTFN1_HALT_OCCURRED 0x01000000 -#define __HOSTFN1_INT_STATUS_LVL_MK 0x00f00000 -#define __HOSTFN1_INT_STATUS_LVL_SH 20 -#define __HOSTFN1_INT_STATUS_LVL(_v) ((_v) << __HOSTFN1_INT_STATUS_LVL_SH) -#define __HOSTFN1_INT_STATUS_P_MK 0x000f0000 -#define __HOSTFN1_INT_STATUS_P_SH 16 -#define __HOSTFN1_INT_STATUS_P(_v) ((_v) << __HOSTFN1_INT_STATUS_P_SH) -#define __HOSTFN1_INT_STATUS_F 0x0000ffff -#define HOSTFN1_INT_MSK 0x00014104 -#define HOST_PAGE_NUM_FN1 0x00014108 -#define HOST_MSIX_ERR_INDEX_FN1 0x0001410c -#define APP_PLL_425_CTL_REG 0x00014204 -#define __P_425_PLL_LOCK 0x80000000 -#define __APP_PLL_425_SRAM_USE_100MHZ 0x00100000 -#define __APP_PLL_425_RESET_TIMER_MK 0x000e0000 -#define __APP_PLL_425_RESET_TIMER_SH 17 -#define __APP_PLL_425_RESET_TIMER(_v) ((_v) << __APP_PLL_425_RESET_TIMER_SH) -#define __APP_PLL_425_LOGIC_SOFT_RESET 0x00010000 -#define __APP_PLL_425_CNTLMT0_1_MK 0x0000c000 -#define __APP_PLL_425_CNTLMT0_1_SH 14 -#define __APP_PLL_425_CNTLMT0_1(_v) ((_v) << __APP_PLL_425_CNTLMT0_1_SH) -#define __APP_PLL_425_JITLMT0_1_MK 0x00003000 -#define __APP_PLL_425_JITLMT0_1_SH 12 -#define __APP_PLL_425_JITLMT0_1(_v) ((_v) << __APP_PLL_425_JITLMT0_1_SH) -#define __APP_PLL_425_HREF 0x00000800 -#define __APP_PLL_425_HDIV 0x00000400 -#define __APP_PLL_425_P0_1_MK 0x00000300 -#define __APP_PLL_425_P0_1_SH 8 -#define __APP_PLL_425_P0_1(_v) ((_v) << __APP_PLL_425_P0_1_SH) -#define __APP_PLL_425_Z0_2_MK 0x000000e0 -#define __APP_PLL_425_Z0_2_SH 5 -#define __APP_PLL_425_Z0_2(_v) ((_v) << __APP_PLL_425_Z0_2_SH) -#define __APP_PLL_425_RSEL200500 0x00000010 -#define __APP_PLL_425_ENARST 0x00000008 -#define __APP_PLL_425_BYPASS 0x00000004 -#define __APP_PLL_425_LRESETN 0x00000002 -#define __APP_PLL_425_ENABLE 0x00000001 -#define APP_PLL_312_CTL_REG 0x00014208 -#define __P_312_PLL_LOCK 0x80000000 -#define __ENABLE_MAC_AHB_1 0x00800000 -#define __ENABLE_MAC_AHB_0 0x00400000 -#define __ENABLE_MAC_1 0x00200000 -#define __ENABLE_MAC_0 0x00100000 -#define __APP_PLL_312_RESET_TIMER_MK 0x000e0000 -#define __APP_PLL_312_RESET_TIMER_SH 17 -#define __APP_PLL_312_RESET_TIMER(_v) ((_v) << __APP_PLL_312_RESET_TIMER_SH) -#define __APP_PLL_312_LOGIC_SOFT_RESET 0x00010000 -#define __APP_PLL_312_CNTLMT0_1_MK 0x0000c000 -#define __APP_PLL_312_CNTLMT0_1_SH 14 -#define __APP_PLL_312_CNTLMT0_1(_v) ((_v) << __APP_PLL_312_CNTLMT0_1_SH) -#define __APP_PLL_312_JITLMT0_1_MK 0x00003000 -#define __APP_PLL_312_JITLMT0_1_SH 12 -#define __APP_PLL_312_JITLMT0_1(_v) ((_v) << __APP_PLL_312_JITLMT0_1_SH) -#define __APP_PLL_312_HREF 0x00000800 -#define __APP_PLL_312_HDIV 0x00000400 -#define __APP_PLL_312_P0_1_MK 0x00000300 -#define __APP_PLL_312_P0_1_SH 8 -#define __APP_PLL_312_P0_1(_v) ((_v) << __APP_PLL_312_P0_1_SH) -#define __APP_PLL_312_Z0_2_MK 0x000000e0 -#define __APP_PLL_312_Z0_2_SH 5 -#define __APP_PLL_312_Z0_2(_v) ((_v) << __APP_PLL_312_Z0_2_SH) -#define __APP_PLL_312_RSEL200500 0x00000010 -#define __APP_PLL_312_ENARST 0x00000008 -#define __APP_PLL_312_BYPASS 0x00000004 -#define __APP_PLL_312_LRESETN 0x00000002 -#define __APP_PLL_312_ENABLE 0x00000001 -#define MBIST_CTL_REG 0x00014220 -#define __EDRAM_BISTR_START 0x00000004 -#define __MBIST_RESET 0x00000002 -#define __MBIST_START 0x00000001 -#define MBIST_STAT_REG 0x00014224 -#define __EDRAM_BISTR_STATUS 0x00000008 -#define __EDRAM_BISTR_DONE 0x00000004 -#define __MEM_BIT_STATUS 0x00000002 -#define __MBIST_DONE 0x00000001 -#define HOST_SEM0_REG 0x00014230 -#define __HOST_SEMAPHORE 0x00000001 -#define HOST_SEM1_REG 0x00014234 -#define HOST_SEM2_REG 0x00014238 -#define HOST_SEM3_REG 0x0001423c -#define HOST_SEM0_INFO_REG 0x00014240 -#define HOST_SEM1_INFO_REG 0x00014244 -#define HOST_SEM2_INFO_REG 0x00014248 -#define HOST_SEM3_INFO_REG 0x0001424c -#define ETH_MAC_SER_REG 0x00014288 -#define __APP_EMS_CKBUFAMPIN 0x00000020 -#define __APP_EMS_REFCLKSEL 0x00000010 -#define __APP_EMS_CMLCKSEL 0x00000008 -#define __APP_EMS_REFCKBUFEN2 0x00000004 -#define __APP_EMS_REFCKBUFEN1 0x00000002 -#define __APP_EMS_CHANNEL_SEL 0x00000001 -#define HOSTFN2_INT_STATUS 0x00014300 -#define __HOSTFN2_HALT_OCCURRED 0x01000000 -#define __HOSTFN2_INT_STATUS_LVL_MK 0x00f00000 -#define __HOSTFN2_INT_STATUS_LVL_SH 20 -#define __HOSTFN2_INT_STATUS_LVL(_v) ((_v) << __HOSTFN2_INT_STATUS_LVL_SH) -#define __HOSTFN2_INT_STATUS_P_MK 0x000f0000 -#define __HOSTFN2_INT_STATUS_P_SH 16 -#define __HOSTFN2_INT_STATUS_P(_v) ((_v) << __HOSTFN2_INT_STATUS_P_SH) -#define __HOSTFN2_INT_STATUS_F 0x0000ffff -#define HOSTFN2_INT_MSK 0x00014304 -#define HOST_PAGE_NUM_FN2 0x00014308 -#define HOST_MSIX_ERR_INDEX_FN2 0x0001430c -#define HOSTFN3_INT_STATUS 0x00014400 -#define __HALT_OCCURRED 0x01000000 -#define __HOSTFN3_INT_STATUS_LVL_MK 0x00f00000 -#define __HOSTFN3_INT_STATUS_LVL_SH 20 -#define __HOSTFN3_INT_STATUS_LVL(_v) ((_v) << __HOSTFN3_INT_STATUS_LVL_SH) -#define __HOSTFN3_INT_STATUS_P_MK 0x000f0000 -#define __HOSTFN3_INT_STATUS_P_SH 16 -#define __HOSTFN3_INT_STATUS_P(_v) ((_v) << __HOSTFN3_INT_STATUS_P_SH) -#define __HOSTFN3_INT_STATUS_F 0x0000ffff -#define HOSTFN3_INT_MSK 0x00014404 -#define HOST_PAGE_NUM_FN3 0x00014408 -#define HOST_MSIX_ERR_INDEX_FN3 0x0001440c -#define FNC_ID_REG 0x00014600 -#define __FUNCTION_NUMBER 0x00000007 -#define FNC_PERS_REG 0x00014604 -#define __F3_FUNCTION_ACTIVE 0x80000000 -#define __F3_FUNCTION_MODE 0x40000000 -#define __F3_PORT_MAP_MK 0x30000000 -#define __F3_PORT_MAP_SH 28 -#define __F3_PORT_MAP(_v) ((_v) << __F3_PORT_MAP_SH) -#define __F3_VM_MODE 0x08000000 -#define __F3_INTX_STATUS_MK 0x07000000 -#define __F3_INTX_STATUS_SH 24 -#define __F3_INTX_STATUS(_v) ((_v) << __F3_INTX_STATUS_SH) -#define __F2_FUNCTION_ACTIVE 0x00800000 -#define __F2_FUNCTION_MODE 0x00400000 -#define __F2_PORT_MAP_MK 0x00300000 -#define __F2_PORT_MAP_SH 20 -#define __F2_PORT_MAP(_v) ((_v) << __F2_PORT_MAP_SH) -#define __F2_VM_MODE 0x00080000 -#define __F2_INTX_STATUS_MK 0x00070000 -#define __F2_INTX_STATUS_SH 16 -#define __F2_INTX_STATUS(_v) ((_v) << __F2_INTX_STATUS_SH) -#define __F1_FUNCTION_ACTIVE 0x00008000 -#define __F1_FUNCTION_MODE 0x00004000 -#define __F1_PORT_MAP_MK 0x00003000 -#define __F1_PORT_MAP_SH 12 -#define __F1_PORT_MAP(_v) ((_v) << __F1_PORT_MAP_SH) -#define __F1_VM_MODE 0x00000800 -#define __F1_INTX_STATUS_MK 0x00000700 -#define __F1_INTX_STATUS_SH 8 -#define __F1_INTX_STATUS(_v) ((_v) << __F1_INTX_STATUS_SH) -#define __F0_FUNCTION_ACTIVE 0x00000080 -#define __F0_FUNCTION_MODE 0x00000040 -#define __F0_PORT_MAP_MK 0x00000030 -#define __F0_PORT_MAP_SH 4 -#define __F0_PORT_MAP(_v) ((_v) << __F0_PORT_MAP_SH) -#define __F0_VM_MODE 0x00000008 -#define __F0_INTX_STATUS 0x00000007 -enum { - __F0_INTX_STATUS_MSIX = 0x0, - __F0_INTX_STATUS_INTA = 0x1, - __F0_INTX_STATUS_INTB = 0x2, - __F0_INTX_STATUS_INTC = 0x3, - __F0_INTX_STATUS_INTD = 0x4, -}; -#define OP_MODE 0x0001460c -#define __APP_ETH_CLK_LOWSPEED 0x00000004 -#define __GLOBAL_CORECLK_HALFSPEED 0x00000002 -#define __GLOBAL_FCOE_MODE 0x00000001 -#define HOST_SEM4_REG 0x00014610 -#define HOST_SEM5_REG 0x00014614 -#define HOST_SEM6_REG 0x00014618 -#define HOST_SEM7_REG 0x0001461c -#define HOST_SEM4_INFO_REG 0x00014620 -#define HOST_SEM5_INFO_REG 0x00014624 -#define HOST_SEM6_INFO_REG 0x00014628 -#define HOST_SEM7_INFO_REG 0x0001462c -#define HOSTFN0_LPU0_MBOX0_CMD_STAT 0x00019000 -#define __HOSTFN0_LPU0_MBOX0_INFO_MK 0xfffffffe -#define __HOSTFN0_LPU0_MBOX0_INFO_SH 1 -#define __HOSTFN0_LPU0_MBOX0_INFO(_v) ((_v) << __HOSTFN0_LPU0_MBOX0_INFO_SH) -#define __HOSTFN0_LPU0_MBOX0_CMD_STATUS 0x00000001 -#define HOSTFN0_LPU1_MBOX0_CMD_STAT 0x00019004 -#define __HOSTFN0_LPU1_MBOX0_INFO_MK 0xfffffffe -#define __HOSTFN0_LPU1_MBOX0_INFO_SH 1 -#define __HOSTFN0_LPU1_MBOX0_INFO(_v) ((_v) << __HOSTFN0_LPU1_MBOX0_INFO_SH) -#define __HOSTFN0_LPU1_MBOX0_CMD_STATUS 0x00000001 -#define LPU0_HOSTFN0_MBOX0_CMD_STAT 0x00019008 -#define __LPU0_HOSTFN0_MBOX0_INFO_MK 0xfffffffe -#define __LPU0_HOSTFN0_MBOX0_INFO_SH 1 -#define __LPU0_HOSTFN0_MBOX0_INFO(_v) ((_v) << __LPU0_HOSTFN0_MBOX0_INFO_SH) -#define __LPU0_HOSTFN0_MBOX0_CMD_STATUS 0x00000001 -#define LPU1_HOSTFN0_MBOX0_CMD_STAT 0x0001900c -#define __LPU1_HOSTFN0_MBOX0_INFO_MK 0xfffffffe -#define __LPU1_HOSTFN0_MBOX0_INFO_SH 1 -#define __LPU1_HOSTFN0_MBOX0_INFO(_v) ((_v) << __LPU1_HOSTFN0_MBOX0_INFO_SH) -#define __LPU1_HOSTFN0_MBOX0_CMD_STATUS 0x00000001 -#define HOSTFN1_LPU0_MBOX0_CMD_STAT 0x00019010 -#define __HOSTFN1_LPU0_MBOX0_INFO_MK 0xfffffffe -#define __HOSTFN1_LPU0_MBOX0_INFO_SH 1 -#define __HOSTFN1_LPU0_MBOX0_INFO(_v) ((_v) << __HOSTFN1_LPU0_MBOX0_INFO_SH) -#define __HOSTFN1_LPU0_MBOX0_CMD_STATUS 0x00000001 -#define HOSTFN1_LPU1_MBOX0_CMD_STAT 0x00019014 -#define __HOSTFN1_LPU1_MBOX0_INFO_MK 0xfffffffe -#define __HOSTFN1_LPU1_MBOX0_INFO_SH 1 -#define __HOSTFN1_LPU1_MBOX0_INFO(_v) ((_v) << __HOSTFN1_LPU1_MBOX0_INFO_SH) -#define __HOSTFN1_LPU1_MBOX0_CMD_STATUS 0x00000001 -#define LPU0_HOSTFN1_MBOX0_CMD_STAT 0x00019018 -#define __LPU0_HOSTFN1_MBOX0_INFO_MK 0xfffffffe -#define __LPU0_HOSTFN1_MBOX0_INFO_SH 1 -#define __LPU0_HOSTFN1_MBOX0_INFO(_v) ((_v) << __LPU0_HOSTFN1_MBOX0_INFO_SH) -#define __LPU0_HOSTFN1_MBOX0_CMD_STATUS 0x00000001 -#define LPU1_HOSTFN1_MBOX0_CMD_STAT 0x0001901c -#define __LPU1_HOSTFN1_MBOX0_INFO_MK 0xfffffffe -#define __LPU1_HOSTFN1_MBOX0_INFO_SH 1 -#define __LPU1_HOSTFN1_MBOX0_INFO(_v) ((_v) << __LPU1_HOSTFN1_MBOX0_INFO_SH) -#define __LPU1_HOSTFN1_MBOX0_CMD_STATUS 0x00000001 -#define HOSTFN2_LPU0_MBOX0_CMD_STAT 0x00019150 -#define __HOSTFN2_LPU0_MBOX0_INFO_MK 0xfffffffe -#define __HOSTFN2_LPU0_MBOX0_INFO_SH 1 -#define __HOSTFN2_LPU0_MBOX0_INFO(_v) ((_v) << __HOSTFN2_LPU0_MBOX0_INFO_SH) -#define __HOSTFN2_LPU0_MBOX0_CMD_STATUS 0x00000001 -#define HOSTFN2_LPU1_MBOX0_CMD_STAT 0x00019154 -#define __HOSTFN2_LPU1_MBOX0_INFO_MK 0xfffffffe -#define __HOSTFN2_LPU1_MBOX0_INFO_SH 1 -#define __HOSTFN2_LPU1_MBOX0_INFO(_v) ((_v) << __HOSTFN2_LPU1_MBOX0_INFO_SH) -#define __HOSTFN2_LPU1_MBOX0BOX0_CMD_STATUS 0x00000001 -#define LPU0_HOSTFN2_MBOX0_CMD_STAT 0x00019158 -#define __LPU0_HOSTFN2_MBOX0_INFO_MK 0xfffffffe -#define __LPU0_HOSTFN2_MBOX0_INFO_SH 1 -#define __LPU0_HOSTFN2_MBOX0_INFO(_v) ((_v) << __LPU0_HOSTFN2_MBOX0_INFO_SH) -#define __LPU0_HOSTFN2_MBOX0_CMD_STATUS 0x00000001 -#define LPU1_HOSTFN2_MBOX0_CMD_STAT 0x0001915c -#define __LPU1_HOSTFN2_MBOX0_INFO_MK 0xfffffffe -#define __LPU1_HOSTFN2_MBOX0_INFO_SH 1 -#define __LPU1_HOSTFN2_MBOX0_INFO(_v) ((_v) << __LPU1_HOSTFN2_MBOX0_INFO_SH) -#define __LPU1_HOSTFN2_MBOX0_CMD_STATUS 0x00000001 -#define HOSTFN3_LPU0_MBOX0_CMD_STAT 0x00019160 -#define __HOSTFN3_LPU0_MBOX0_INFO_MK 0xfffffffe -#define __HOSTFN3_LPU0_MBOX0_INFO_SH 1 -#define __HOSTFN3_LPU0_MBOX0_INFO(_v) ((_v) << __HOSTFN3_LPU0_MBOX0_INFO_SH) -#define __HOSTFN3_LPU0_MBOX0_CMD_STATUS 0x00000001 -#define HOSTFN3_LPU1_MBOX0_CMD_STAT 0x00019164 -#define __HOSTFN3_LPU1_MBOX0_INFO_MK 0xfffffffe -#define __HOSTFN3_LPU1_MBOX0_INFO_SH 1 -#define __HOSTFN3_LPU1_MBOX0_INFO(_v) ((_v) << __HOSTFN3_LPU1_MBOX0_INFO_SH) -#define __HOSTFN3_LPU1_MBOX0_CMD_STATUS 0x00000001 -#define LPU0_HOSTFN3_MBOX0_CMD_STAT 0x00019168 -#define __LPU0_HOSTFN3_MBOX0_INFO_MK 0xfffffffe -#define __LPU0_HOSTFN3_MBOX0_INFO_SH 1 -#define __LPU0_HOSTFN3_MBOX0_INFO(_v) ((_v) << __LPU0_HOSTFN3_MBOX0_INFO_SH) -#define __LPU0_HOSTFN3_MBOX0_CMD_STATUS 0x00000001 -#define LPU1_HOSTFN3_MBOX0_CMD_STAT 0x0001916c -#define __LPU1_HOSTFN3_MBOX0_INFO_MK 0xfffffffe -#define __LPU1_HOSTFN3_MBOX0_INFO_SH 1 -#define __LPU1_HOSTFN3_MBOX0_INFO(_v) ((_v) << __LPU1_HOSTFN3_MBOX0_INFO_SH) -#define __LPU1_HOSTFN3_MBOX0_CMD_STATUS 0x00000001 -#define FW_INIT_HALT_P0 0x000191ac -#define __FW_INIT_HALT_P 0x00000001 -#define FW_INIT_HALT_P1 0x000191bc -#define CPE_PI_PTR_Q0 0x00038000 -#define __CPE_PI_UNUSED_MK 0xffff0000 -#define __CPE_PI_UNUSED_SH 16 -#define __CPE_PI_UNUSED(_v) ((_v) << __CPE_PI_UNUSED_SH) -#define __CPE_PI_PTR 0x0000ffff -#define CPE_PI_PTR_Q1 0x00038040 -#define CPE_CI_PTR_Q0 0x00038004 -#define __CPE_CI_UNUSED_MK 0xffff0000 -#define __CPE_CI_UNUSED_SH 16 -#define __CPE_CI_UNUSED(_v) ((_v) << __CPE_CI_UNUSED_SH) -#define __CPE_CI_PTR 0x0000ffff -#define CPE_CI_PTR_Q1 0x00038044 -#define CPE_DEPTH_Q0 0x00038008 -#define __CPE_DEPTH_UNUSED_MK 0xf8000000 -#define __CPE_DEPTH_UNUSED_SH 27 -#define __CPE_DEPTH_UNUSED(_v) ((_v) << __CPE_DEPTH_UNUSED_SH) -#define __CPE_MSIX_VEC_INDEX_MK 0x07ff0000 -#define __CPE_MSIX_VEC_INDEX_SH 16 -#define __CPE_MSIX_VEC_INDEX(_v) ((_v) << __CPE_MSIX_VEC_INDEX_SH) -#define __CPE_DEPTH 0x0000ffff -#define CPE_DEPTH_Q1 0x00038048 -#define CPE_QCTRL_Q0 0x0003800c -#define __CPE_CTRL_UNUSED30_MK 0xfc000000 -#define __CPE_CTRL_UNUSED30_SH 26 -#define __CPE_CTRL_UNUSED30(_v) ((_v) << __CPE_CTRL_UNUSED30_SH) -#define __CPE_FUNC_INT_CTRL_MK 0x03000000 -#define __CPE_FUNC_INT_CTRL_SH 24 -#define __CPE_FUNC_INT_CTRL(_v) ((_v) << __CPE_FUNC_INT_CTRL_SH) -enum { - __CPE_FUNC_INT_CTRL_DISABLE = 0x0, - __CPE_FUNC_INT_CTRL_F2NF = 0x1, - __CPE_FUNC_INT_CTRL_3QUART = 0x2, - __CPE_FUNC_INT_CTRL_HALF = 0x3, -}; -#define __CPE_CTRL_UNUSED20_MK 0x00f00000 -#define __CPE_CTRL_UNUSED20_SH 20 -#define __CPE_CTRL_UNUSED20(_v) ((_v) << __CPE_CTRL_UNUSED20_SH) -#define __CPE_SCI_TH_MK 0x000f0000 -#define __CPE_SCI_TH_SH 16 -#define __CPE_SCI_TH(_v) ((_v) << __CPE_SCI_TH_SH) -#define __CPE_CTRL_UNUSED10_MK 0x0000c000 -#define __CPE_CTRL_UNUSED10_SH 14 -#define __CPE_CTRL_UNUSED10(_v) ((_v) << __CPE_CTRL_UNUSED10_SH) -#define __CPE_ACK_PENDING 0x00002000 -#define __CPE_CTRL_UNUSED40_MK 0x00001c00 -#define __CPE_CTRL_UNUSED40_SH 10 -#define __CPE_CTRL_UNUSED40(_v) ((_v) << __CPE_CTRL_UNUSED40_SH) -#define __CPE_PCIEID_MK 0x00000300 -#define __CPE_PCIEID_SH 8 -#define __CPE_PCIEID(_v) ((_v) << __CPE_PCIEID_SH) -#define __CPE_CTRL_UNUSED00_MK 0x000000fe -#define __CPE_CTRL_UNUSED00_SH 1 -#define __CPE_CTRL_UNUSED00(_v) ((_v) << __CPE_CTRL_UNUSED00_SH) -#define __CPE_ESIZE 0x00000001 -#define CPE_QCTRL_Q1 0x0003804c -#define __CPE_CTRL_UNUSED31_MK 0xfc000000 -#define __CPE_CTRL_UNUSED31_SH 26 -#define __CPE_CTRL_UNUSED31(_v) ((_v) << __CPE_CTRL_UNUSED31_SH) -#define __CPE_CTRL_UNUSED21_MK 0x00f00000 -#define __CPE_CTRL_UNUSED21_SH 20 -#define __CPE_CTRL_UNUSED21(_v) ((_v) << __CPE_CTRL_UNUSED21_SH) -#define __CPE_CTRL_UNUSED11_MK 0x0000c000 -#define __CPE_CTRL_UNUSED11_SH 14 -#define __CPE_CTRL_UNUSED11(_v) ((_v) << __CPE_CTRL_UNUSED11_SH) -#define __CPE_CTRL_UNUSED41_MK 0x00001c00 -#define __CPE_CTRL_UNUSED41_SH 10 -#define __CPE_CTRL_UNUSED41(_v) ((_v) << __CPE_CTRL_UNUSED41_SH) -#define __CPE_CTRL_UNUSED01_MK 0x000000fe -#define __CPE_CTRL_UNUSED01_SH 1 -#define __CPE_CTRL_UNUSED01(_v) ((_v) << __CPE_CTRL_UNUSED01_SH) -#define RME_PI_PTR_Q0 0x00038020 -#define __LATENCY_TIME_STAMP_MK 0xffff0000 -#define __LATENCY_TIME_STAMP_SH 16 -#define __LATENCY_TIME_STAMP(_v) ((_v) << __LATENCY_TIME_STAMP_SH) -#define __RME_PI_PTR 0x0000ffff -#define RME_PI_PTR_Q1 0x00038060 -#define RME_CI_PTR_Q0 0x00038024 -#define __DELAY_TIME_STAMP_MK 0xffff0000 -#define __DELAY_TIME_STAMP_SH 16 -#define __DELAY_TIME_STAMP(_v) ((_v) << __DELAY_TIME_STAMP_SH) -#define __RME_CI_PTR 0x0000ffff -#define RME_CI_PTR_Q1 0x00038064 -#define RME_DEPTH_Q0 0x00038028 -#define __RME_DEPTH_UNUSED_MK 0xf8000000 -#define __RME_DEPTH_UNUSED_SH 27 -#define __RME_DEPTH_UNUSED(_v) ((_v) << __RME_DEPTH_UNUSED_SH) -#define __RME_MSIX_VEC_INDEX_MK 0x07ff0000 -#define __RME_MSIX_VEC_INDEX_SH 16 -#define __RME_MSIX_VEC_INDEX(_v) ((_v) << __RME_MSIX_VEC_INDEX_SH) -#define __RME_DEPTH 0x0000ffff -#define RME_DEPTH_Q1 0x00038068 -#define RME_QCTRL_Q0 0x0003802c -#define __RME_INT_LATENCY_TIMER_MK 0xff000000 -#define __RME_INT_LATENCY_TIMER_SH 24 -#define __RME_INT_LATENCY_TIMER(_v) ((_v) << __RME_INT_LATENCY_TIMER_SH) -#define __RME_INT_DELAY_TIMER_MK 0x00ff0000 -#define __RME_INT_DELAY_TIMER_SH 16 -#define __RME_INT_DELAY_TIMER(_v) ((_v) << __RME_INT_DELAY_TIMER_SH) -#define __RME_INT_DELAY_DISABLE 0x00008000 -#define __RME_DLY_DELAY_DISABLE 0x00004000 -#define __RME_ACK_PENDING 0x00002000 -#define __RME_FULL_INTERRUPT_DISABLE 0x00001000 -#define __RME_CTRL_UNUSED10_MK 0x00000c00 -#define __RME_CTRL_UNUSED10_SH 10 -#define __RME_CTRL_UNUSED10(_v) ((_v) << __RME_CTRL_UNUSED10_SH) -#define __RME_PCIEID_MK 0x00000300 -#define __RME_PCIEID_SH 8 -#define __RME_PCIEID(_v) ((_v) << __RME_PCIEID_SH) -#define __RME_CTRL_UNUSED00_MK 0x000000fe -#define __RME_CTRL_UNUSED00_SH 1 -#define __RME_CTRL_UNUSED00(_v) ((_v) << __RME_CTRL_UNUSED00_SH) -#define __RME_ESIZE 0x00000001 -#define RME_QCTRL_Q1 0x0003806c -#define __RME_CTRL_UNUSED11_MK 0x00000c00 -#define __RME_CTRL_UNUSED11_SH 10 -#define __RME_CTRL_UNUSED11(_v) ((_v) << __RME_CTRL_UNUSED11_SH) -#define __RME_CTRL_UNUSED01_MK 0x000000fe -#define __RME_CTRL_UNUSED01_SH 1 -#define __RME_CTRL_UNUSED01(_v) ((_v) << __RME_CTRL_UNUSED01_SH) -#define PSS_CTL_REG 0x00018800 -#define __PSS_I2C_CLK_DIV_MK 0x007f0000 -#define __PSS_I2C_CLK_DIV_SH 16 -#define __PSS_I2C_CLK_DIV(_v) ((_v) << __PSS_I2C_CLK_DIV_SH) -#define __PSS_LMEM_INIT_DONE 0x00001000 -#define __PSS_LMEM_RESET 0x00000200 -#define __PSS_LMEM_INIT_EN 0x00000100 -#define __PSS_LPU1_RESET 0x00000002 -#define __PSS_LPU0_RESET 0x00000001 -#define PSS_ERR_STATUS_REG 0x00018810 -#define __PSS_LPU1_TCM_READ_ERR 0x00200000 -#define __PSS_LPU0_TCM_READ_ERR 0x00100000 -#define __PSS_LMEM5_CORR_ERR 0x00080000 -#define __PSS_LMEM4_CORR_ERR 0x00040000 -#define __PSS_LMEM3_CORR_ERR 0x00020000 -#define __PSS_LMEM2_CORR_ERR 0x00010000 -#define __PSS_LMEM1_CORR_ERR 0x00008000 -#define __PSS_LMEM0_CORR_ERR 0x00004000 -#define __PSS_LMEM5_UNCORR_ERR 0x00002000 -#define __PSS_LMEM4_UNCORR_ERR 0x00001000 -#define __PSS_LMEM3_UNCORR_ERR 0x00000800 -#define __PSS_LMEM2_UNCORR_ERR 0x00000400 -#define __PSS_LMEM1_UNCORR_ERR 0x00000200 -#define __PSS_LMEM0_UNCORR_ERR 0x00000100 -#define __PSS_BAL_PERR 0x00000080 -#define __PSS_DIP_IF_ERR 0x00000040 -#define __PSS_IOH_IF_ERR 0x00000020 -#define __PSS_TDS_IF_ERR 0x00000010 -#define __PSS_RDS_IF_ERR 0x00000008 -#define __PSS_SGM_IF_ERR 0x00000004 -#define __PSS_LPU1_RAM_ERR 0x00000002 -#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 -#define __RXQ0_PRD_PTR_P 0x0000ffff -#define HQM_QSET1_RXQ_DRBL_P0 0x00038080 -#define __RXQ1_ADD_VECTORS_P 0x80000000 -#define __RXQ1_STOP_P 0x40000000 -#define __RXQ1_PRD_PTR_P 0x0000ffff -#define HQM_QSET0_RXQ_DRBL_P1 0x0003c000 -#define HQM_QSET1_RXQ_DRBL_P1 0x0003c080 -#define HQM_QSET0_TXQ_DRBL_P0 0x00038020 -#define __TXQ0_ADD_VECTORS_P 0x80000000 -#define __TXQ0_STOP_P 0x40000000 -#define __TXQ0_PRD_PTR_P 0x0000ffff -#define HQM_QSET1_TXQ_DRBL_P0 0x000380a0 -#define __TXQ1_ADD_VECTORS_P 0x80000000 -#define __TXQ1_STOP_P 0x40000000 -#define __TXQ1_PRD_PTR_P 0x0000ffff -#define HQM_QSET0_TXQ_DRBL_P1 0x0003c020 -#define HQM_QSET1_TXQ_DRBL_P1 0x0003c0a0 -#define HQM_QSET0_IB_DRBL_1_P0 0x00038040 -#define __IB1_0_ACK_P 0x80000000 -#define __IB1_0_DISABLE_P 0x40000000 -#define __IB1_0_NUM_OF_ACKED_EVENTS_P 0x0000ffff -#define HQM_QSET1_IB_DRBL_1_P0 0x000380c0 -#define __IB1_1_ACK_P 0x80000000 -#define __IB1_1_DISABLE_P 0x40000000 -#define __IB1_1_NUM_OF_ACKED_EVENTS_P 0x0000ffff -#define HQM_QSET0_IB_DRBL_1_P1 0x0003c040 -#define HQM_QSET1_IB_DRBL_1_P1 0x0003c0c0 -#define HQM_QSET0_IB_DRBL_2_P0 0x00038060 -#define __IB2_0_ACK_P 0x80000000 -#define __IB2_0_DISABLE_P 0x40000000 -#define __IB2_0_NUM_OF_ACKED_EVENTS_P 0x0000ffff -#define HQM_QSET1_IB_DRBL_2_P0 0x000380e0 -#define __IB2_1_ACK_P 0x80000000 -#define __IB2_1_DISABLE_P 0x40000000 -#define __IB2_1_NUM_OF_ACKED_EVENTS_P 0x0000ffff -#define HQM_QSET0_IB_DRBL_2_P1 0x0003c060 -#define HQM_QSET1_IB_DRBL_2_P1 0x0003c0e0 - - -/* - * These definitions are either in error/missing in spec. Its auto-generated - * from hard coded values in regparse.pl. - */ -#define __EMPHPOST_AT_4G_MK_FIX 0x0000001c -#define __EMPHPOST_AT_4G_SH_FIX 0x00000002 -#define __EMPHPRE_AT_4G_FIX 0x00000003 -#define __SFP_TXRATE_EN_FIX 0x00000100 -#define __SFP_RXRATE_EN_FIX 0x00000080 - - -/* - * These register definitions are auto-generated from hard coded values - * in regparse.pl. - */ - - -/* - * These register mapping definitions are auto-generated from mapping tables - * in regparse.pl. - */ -#define BFA_IOC0_HBEAT_REG HOST_SEM0_INFO_REG -#define BFA_IOC0_STATE_REG HOST_SEM1_INFO_REG -#define BFA_IOC1_HBEAT_REG HOST_SEM2_INFO_REG -#define BFA_IOC1_STATE_REG HOST_SEM3_INFO_REG -#define BFA_FW_USE_COUNT HOST_SEM4_INFO_REG - -#define CPE_DEPTH_Q(__n) \ - (CPE_DEPTH_Q0 + (__n) * (CPE_DEPTH_Q1 - CPE_DEPTH_Q0)) -#define CPE_QCTRL_Q(__n) \ - (CPE_QCTRL_Q0 + (__n) * (CPE_QCTRL_Q1 - CPE_QCTRL_Q0)) -#define CPE_PI_PTR_Q(__n) \ - (CPE_PI_PTR_Q0 + (__n) * (CPE_PI_PTR_Q1 - CPE_PI_PTR_Q0)) -#define CPE_CI_PTR_Q(__n) \ - (CPE_CI_PTR_Q0 + (__n) * (CPE_CI_PTR_Q1 - CPE_CI_PTR_Q0)) -#define RME_DEPTH_Q(__n) \ - (RME_DEPTH_Q0 + (__n) * (RME_DEPTH_Q1 - RME_DEPTH_Q0)) -#define RME_QCTRL_Q(__n) \ - (RME_QCTRL_Q0 + (__n) * (RME_QCTRL_Q1 - RME_QCTRL_Q0)) -#define RME_PI_PTR_Q(__n) \ - (RME_PI_PTR_Q0 + (__n) * (RME_PI_PTR_Q1 - RME_PI_PTR_Q0)) -#define RME_CI_PTR_Q(__n) \ - (RME_CI_PTR_Q0 + (__n) * (RME_CI_PTR_Q1 - RME_CI_PTR_Q0)) -#define HQM_QSET_RXQ_DRBL_P0(__n) \ - (HQM_QSET0_RXQ_DRBL_P0 + (__n) * (HQM_QSET1_RXQ_DRBL_P0 - \ - HQM_QSET0_RXQ_DRBL_P0)) -#define HQM_QSET_TXQ_DRBL_P0(__n) \ - (HQM_QSET0_TXQ_DRBL_P0 + (__n) * (HQM_QSET1_TXQ_DRBL_P0 - \ - HQM_QSET0_TXQ_DRBL_P0)) -#define HQM_QSET_IB_DRBL_1_P0(__n) \ - (HQM_QSET0_IB_DRBL_1_P0 + (__n) * (HQM_QSET1_IB_DRBL_1_P0 - \ - HQM_QSET0_IB_DRBL_1_P0)) -#define HQM_QSET_IB_DRBL_2_P0(__n) \ - (HQM_QSET0_IB_DRBL_2_P0 + (__n) * (HQM_QSET1_IB_DRBL_2_P0 - \ - HQM_QSET0_IB_DRBL_2_P0)) -#define HQM_QSET_RXQ_DRBL_P1(__n) \ - (HQM_QSET0_RXQ_DRBL_P1 + (__n) * (HQM_QSET1_RXQ_DRBL_P1 - \ - HQM_QSET0_RXQ_DRBL_P1)) -#define HQM_QSET_TXQ_DRBL_P1(__n) \ - (HQM_QSET0_TXQ_DRBL_P1 + (__n) * (HQM_QSET1_TXQ_DRBL_P1 - \ - HQM_QSET0_TXQ_DRBL_P1)) -#define HQM_QSET_IB_DRBL_1_P1(__n) \ - (HQM_QSET0_IB_DRBL_1_P1 + (__n) * (HQM_QSET1_IB_DRBL_1_P1 - \ - HQM_QSET0_IB_DRBL_1_P1)) -#define HQM_QSET_IB_DRBL_2_P1(__n) \ - (HQM_QSET0_IB_DRBL_2_P1 + (__n) * (HQM_QSET1_IB_DRBL_2_P1 - \ - HQM_QSET0_IB_DRBL_2_P1)) - -#define CPE_Q_NUM(__fn, __q) (((__fn) << 2) + (__q)) -#define RME_Q_NUM(__fn, __q) (((__fn) << 2) + (__q)) -#define CPE_Q_MASK(__q) ((__q) & 0x3) -#define RME_Q_MASK(__q) ((__q) & 0x3) - - -/* - * PCI MSI-X vector defines - */ -enum { - BFA_MSIX_CPE_Q0 = 0, - BFA_MSIX_CPE_Q1 = 1, - BFA_MSIX_CPE_Q2 = 2, - BFA_MSIX_CPE_Q3 = 3, - BFA_MSIX_RME_Q0 = 4, - BFA_MSIX_RME_Q1 = 5, - BFA_MSIX_RME_Q2 = 6, - BFA_MSIX_RME_Q3 = 7, - BFA_MSIX_LPU_ERR = 8, - BFA_MSIX_CT_MAX = 9, -}; - -/* - * And corresponding host interrupt status bit field defines - */ -#define __HFN_INT_CPE_Q0 0x00000001U -#define __HFN_INT_CPE_Q1 0x00000002U -#define __HFN_INT_CPE_Q2 0x00000004U -#define __HFN_INT_CPE_Q3 0x00000008U -#define __HFN_INT_CPE_Q4 0x00000010U -#define __HFN_INT_CPE_Q5 0x00000020U -#define __HFN_INT_CPE_Q6 0x00000040U -#define __HFN_INT_CPE_Q7 0x00000080U -#define __HFN_INT_RME_Q0 0x00000100U -#define __HFN_INT_RME_Q1 0x00000200U -#define __HFN_INT_RME_Q2 0x00000400U -#define __HFN_INT_RME_Q3 0x00000800U -#define __HFN_INT_RME_Q4 0x00001000U -#define __HFN_INT_RME_Q5 0x00002000U -#define __HFN_INT_RME_Q6 0x00004000U -#define __HFN_INT_RME_Q7 0x00008000U -#define __HFN_INT_ERR_EMC 0x00010000U -#define __HFN_INT_ERR_LPU0 0x00020000U -#define __HFN_INT_ERR_LPU1 0x00040000U -#define __HFN_INT_ERR_PSS 0x00080000U -#define __HFN_INT_MBOX_LPU0 0x00100000U -#define __HFN_INT_MBOX_LPU1 0x00200000U -#define __HFN_INT_MBOX1_LPU0 0x00400000U -#define __HFN_INT_MBOX1_LPU1 0x00800000U -#define __HFN_INT_LL_HALT 0x01000000U -#define __HFN_INT_CPE_MASK 0x000000ffU -#define __HFN_INT_RME_MASK 0x0000ff00U - - -/* - * catapult memory map. - */ -#define LL_PGN_HQM0 0x0096 -#define LL_PGN_HQM1 0x0097 -#define PSS_SMEM_PAGE_START 0x8000 -#define PSS_SMEM_PGNUM(_pg0, _ma) ((_pg0) + ((_ma) >> 15)) -#define PSS_SMEM_PGOFF(_ma) ((_ma) & 0x7fff) - -/* - * End of catapult memory map - */ - - -#endif /* __BFI_CTREG_H__ */ - diff --git a/drivers/scsi/bfa/include/bfi/bfi_fabric.h b/drivers/scsi/bfa/include/bfi/bfi_fabric.h deleted file mode 100644 index c0669ed41078..000000000000 --- a/drivers/scsi/bfa/include/bfi/bfi_fabric.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFI_FABRIC_H__ -#define __BFI_FABRIC_H__ - -#include <bfi/bfi.h> - -#pragma pack(1) - -enum bfi_fabric_h2i_msgs { - BFI_FABRIC_H2I_CREATE_REQ = 1, - BFI_FABRIC_H2I_DELETE_REQ = 2, - BFI_FABRIC_H2I_SETAUTH = 3, -}; - -enum bfi_fabric_i2h_msgs { - BFI_FABRIC_I2H_CREATE_RSP = BFA_I2HM(1), - BFI_FABRIC_I2H_DELETE_RSP = BFA_I2HM(2), - BFI_FABRIC_I2H_SETAUTH_RSP = BFA_I2HM(3), - BFI_FABRIC_I2H_ONLINE = BFA_I2HM(4), - BFI_FABRIC_I2H_OFFLINE = BFA_I2HM(5), -}; - -struct bfi_fabric_create_req_s { - bfi_mhdr_t mh; /* common msg header */ - u8 vf_en; /* virtual fabric enable */ - u8 rsvd; - u16 vf_id; /* virtual fabric ID */ - wwn_t pwwn; /* port name */ - wwn_t nwwn; /* node name */ -}; - -struct bfi_fabric_create_rsp_s { - bfi_mhdr_t mh; /* common msg header */ - u16 bfa_handle; /* host fabric handle */ - u8 status; /* fabric create status */ - u8 rsvd; -}; - -struct bfi_fabric_delete_req_s { - bfi_mhdr_t mh; /* common msg header */ - u16 fw_handle; /* firmware fabric handle */ - u16 rsvd; -}; - -struct bfi_fabric_delete_rsp_s { - bfi_mhdr_t mh; /* common msg header */ - u16 bfa_handle; /* host fabric handle */ - u8 status; /* fabric deletion status */ - u8 rsvd; -}; - -#define BFI_FABRIC_AUTHSECRET_LEN 64 -struct bfi_fabric_setauth_req_s { - bfi_mhdr_t mh; /* common msg header */ - u16 fw_handle; /* f/w handle of fabric */ - u8 algorithm; - u8 group; - u8 secret[BFI_FABRIC_AUTHSECRET_LEN]; -}; - -union bfi_fabric_h2i_msg_u { - bfi_msg_t *msg; - struct bfi_fabric_create_req_s *create_req; - struct bfi_fabric_delete_req_s *delete_req; -}; - -union bfi_fabric_i2h_msg_u { - bfi_msg_t *msg; - struct bfi_fabric_create_rsp_s *create_rsp; - struct bfi_fabric_delete_rsp_s *delete_rsp; -}; - -#pragma pack() - -#endif /* __BFI_FABRIC_H__ */ - diff --git a/drivers/scsi/bfa/include/bfi/bfi_fcpim.h b/drivers/scsi/bfa/include/bfi/bfi_fcpim.h deleted file mode 100644 index 52c059fb4c3a..000000000000 --- a/drivers/scsi/bfa/include/bfi/bfi_fcpim.h +++ /dev/null @@ -1,301 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFI_FCPIM_H__ -#define __BFI_FCPIM_H__ - -#include "bfi.h" -#include <protocol/fcp.h> - -#pragma pack(1) - -/* - * Initiator mode I-T nexus interface defines. - */ - -enum bfi_itnim_h2i { - BFI_ITNIM_H2I_CREATE_REQ = 1, /* i-t nexus creation */ - BFI_ITNIM_H2I_DELETE_REQ = 2, /* i-t nexus deletion */ -}; - -enum bfi_itnim_i2h { - BFI_ITNIM_I2H_CREATE_RSP = BFA_I2HM(1), - BFI_ITNIM_I2H_DELETE_RSP = BFA_I2HM(2), - BFI_ITNIM_I2H_SLER_EVENT = BFA_I2HM(3), -}; - -struct bfi_itnim_create_req_s { - struct bfi_mhdr_s mh; /* common msg header */ - u16 fw_handle; /* f/w handle for itnim */ - u8 class; /* FC class for IO */ - u8 seq_rec; /* sequence recovery support */ - u8 msg_no; /* seq id of the msg */ -}; - -struct bfi_itnim_create_rsp_s { - struct bfi_mhdr_s mh; /* common msg header */ - u16 bfa_handle; /* bfa handle for itnim */ - u8 status; /* fcp request status */ - u8 seq_id; /* seq id of the msg */ -}; - -struct bfi_itnim_delete_req_s { - struct bfi_mhdr_s mh; /* common msg header */ - u16 fw_handle; /* f/w itnim handle */ - u8 seq_id; /* seq id of the msg */ - u8 rsvd; -}; - -struct bfi_itnim_delete_rsp_s { - struct bfi_mhdr_s mh; /* common msg header */ - u16 bfa_handle; /* bfa handle for itnim */ - u8 status; /* fcp request status */ - u8 seq_id; /* seq id of the msg */ -}; - -struct bfi_itnim_sler_event_s { - struct bfi_mhdr_s mh; /* common msg header */ - u16 bfa_handle; /* bfa handle for itnim */ - u16 rsvd; -}; - -union bfi_itnim_h2i_msg_u { - struct bfi_itnim_create_req_s *create_req; - struct bfi_itnim_delete_req_s *delete_req; - struct bfi_msg_s *msg; -}; - -union bfi_itnim_i2h_msg_u { - struct bfi_itnim_create_rsp_s *create_rsp; - struct bfi_itnim_delete_rsp_s *delete_rsp; - struct bfi_itnim_sler_event_s *sler_event; - struct bfi_msg_s *msg; -}; - -/* - * Initiator mode IO interface defines. - */ - -enum bfi_ioim_h2i { - BFI_IOIM_H2I_IOABORT_REQ = 1, /* IO abort request */ - BFI_IOIM_H2I_IOCLEANUP_REQ = 2, /* IO cleanup request */ -}; - -enum bfi_ioim_i2h { - BFI_IOIM_I2H_IO_RSP = BFA_I2HM(1), /* non-fp IO response */ - BFI_IOIM_I2H_IOABORT_RSP = BFA_I2HM(2),/* ABORT rsp */ -}; - -/** - * IO command DIF info - */ -struct bfi_ioim_dif_s { - u32 dif_info[4]; -}; - -/** - * FCP IO messages overview - * - * @note - * - Max CDB length supported is 64 bytes. - * - SCSI Linked commands and SCSI bi-directional Commands not - * supported. - * - */ -struct bfi_ioim_req_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u16 io_tag; /* I/O tag */ - u16 rport_hdl; /* itnim/rport firmware handle */ - struct fcp_cmnd_s cmnd; /* IO request info */ - - /** - * SG elements array within the IO request must be double word - * aligned. This aligment is required to optimize SGM setup for the IO. - */ - struct bfi_sge_s sges[BFI_SGE_INLINE_MAX]; - u8 io_timeout; - u8 dif_en; - u8 rsvd_a[2]; - struct bfi_ioim_dif_s dif; -}; - -/** - * This table shows various IO status codes from firmware and their - * meaning. Host driver can use these status codes to further process - * IO completions. - * - * BFI_IOIM_STS_OK : IO completed with error free SCSI & - * transport status. - * - io-tag can be reused. - * - * BFA_IOIM_STS_SCSI_ERR : IO completed with scsi error. - * - io-tag can be reused. - * - * BFI_IOIM_STS_HOST_ABORTED : IO was aborted successfully due to - * host request. - * - io-tag cannot be reused yet. - * - * BFI_IOIM_STS_ABORTED : IO was aborted successfully - * internally by f/w. - * - io-tag cannot be reused yet. - * - * BFI_IOIM_STS_TIMEDOUT : IO timedout and ABTS/RRQ is happening - * in the firmware and - * - io-tag cannot be reused yet. - * - * BFI_IOIM_STS_SQER_NEEDED : Firmware could not recover the IO - * with sequence level error - * logic and hence host needs to retry - * this IO with a different IO tag - * - io-tag cannot be used yet. - * - * BFI_IOIM_STS_NEXUS_ABORT : Second Level Error Recovery from host - * is required because 2 consecutive ABTS - * timedout and host needs logout and - * re-login with the target - * - io-tag cannot be used yet. - * - * BFI_IOIM_STS_UNDERRUN : IO completed with SCSI status good, - * but the data tranferred is less than - * the fcp data length in the command. - * ex. SCSI INQUIRY where transferred - * data length and residue count in FCP - * response accounts for total fcp-dl - * - io-tag can be reused. - * - * BFI_IOIM_STS_OVERRUN : IO completed with SCSI status good, - * but the data transerred is more than - * fcp data length in the command. ex. - * TAPE IOs where blocks can of unequal - * lengths. - * - io-tag can be reused. - * - * BFI_IOIM_STS_RES_FREE : Firmware has completed using io-tag - * during abort process - * - io-tag can be reused. - * - * BFI_IOIM_STS_PROTO_ERR : Firmware detected a protocol error. - * ex target sent more data than - * requested, or there was data frame - * loss and other reasons - * - io-tag cannot be used yet. - * - * BFI_IOIM_STS_DIF_ERR : Firwmare detected DIF error. ex: DIF - * CRC err or Ref Tag err or App tag err. - * - io-tag can be reused. - * - * BFA_IOIM_STS_TSK_MGT_ABORT : IO was aborted because of Task - * Management command from the host - * - io-tag can be reused. - * - * BFI_IOIM_STS_UTAG : Firmware does not know about this - * io_tag. - * - io-tag can be reused. - */ -enum bfi_ioim_status { - BFI_IOIM_STS_OK = 0, - BFI_IOIM_STS_HOST_ABORTED = 1, - BFI_IOIM_STS_ABORTED = 2, - BFI_IOIM_STS_TIMEDOUT = 3, - BFI_IOIM_STS_RES_FREE = 4, - BFI_IOIM_STS_SQER_NEEDED = 5, - BFI_IOIM_STS_PROTO_ERR = 6, - BFI_IOIM_STS_UTAG = 7, - BFI_IOIM_STS_PATHTOV = 8, -}; - -#define BFI_IOIM_SNSLEN (256) -/** - * I/O response message - */ -struct bfi_ioim_rsp_s { - struct bfi_mhdr_s mh; /* common msg header */ - u16 io_tag; /* completed IO tag */ - u16 bfa_rport_hndl; /* releated rport handle */ - u8 io_status; /* IO completion status */ - u8 reuse_io_tag; /* IO tag can be reused */ - u16 abort_tag; /* host abort request tag */ - u8 scsi_status; /* scsi status from target */ - u8 sns_len; /* scsi sense length */ - u8 resid_flags; /* IO residue flags */ - u8 rsvd_a; - u32 residue; /* IO residual length in bytes */ - u32 rsvd_b[3]; -}; - -struct bfi_ioim_abort_req_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u16 io_tag; /* I/O tag */ - u16 abort_tag; /* unique request tag */ -}; - -/* - * Initiator mode task management command interface defines. - */ - -enum bfi_tskim_h2i { - BFI_TSKIM_H2I_TM_REQ = 1, /* task-mgmt command */ - BFI_TSKIM_H2I_ABORT_REQ = 2, /* task-mgmt command */ -}; - -enum bfi_tskim_i2h { - BFI_TSKIM_I2H_TM_RSP = BFA_I2HM(1), -}; - -struct bfi_tskim_req_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u16 tsk_tag; /* task management tag */ - u16 itn_fhdl; /* itn firmware handle */ - lun_t lun; /* LU number */ - u8 tm_flags; /* see fcp_tm_cmnd_t */ - u8 t_secs; /* Timeout value in seconds */ - u8 rsvd[2]; -}; - -struct bfi_tskim_abortreq_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u16 tsk_tag; /* task management tag */ - u16 rsvd; -}; - -enum bfi_tskim_status { - /* - * Following are FCP-4 spec defined status codes, - * **DO NOT CHANGE THEM ** - */ - BFI_TSKIM_STS_OK = 0, - BFI_TSKIM_STS_NOT_SUPP = 4, - BFI_TSKIM_STS_FAILED = 5, - - /** - * Defined by BFA - */ - BFI_TSKIM_STS_TIMEOUT = 10, /* TM request timedout */ - BFI_TSKIM_STS_ABORTED = 11, /* Aborted on host request */ -}; - -struct bfi_tskim_rsp_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u16 tsk_tag; /* task mgmt cmnd tag */ - u8 tsk_status; /* @ref bfi_tskim_status */ - u8 rsvd; -}; - -#pragma pack() - -#endif /* __BFI_FCPIM_H__ */ - diff --git a/drivers/scsi/bfa/include/bfi/bfi_fcxp.h b/drivers/scsi/bfa/include/bfi/bfi_fcxp.h deleted file mode 100644 index e0e995a32828..000000000000 --- a/drivers/scsi/bfa/include/bfi/bfi_fcxp.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFI_FCXP_H__ -#define __BFI_FCXP_H__ - -#include "bfi.h" - -#pragma pack(1) - -enum bfi_fcxp_h2i { - BFI_FCXP_H2I_SEND_REQ = 1, -}; - -enum bfi_fcxp_i2h { - BFI_FCXP_I2H_SEND_RSP = BFA_I2HM(1), -}; - -#define BFA_FCXP_MAX_SGES 2 - -/** - * FCXP send request structure - */ -struct bfi_fcxp_send_req_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u16 fcxp_tag; /* driver request tag */ - u16 max_frmsz; /* max send frame size */ - u16 vf_id; /* vsan tag if applicable */ - u16 rport_fw_hndl; /* FW Handle for the remote port */ - u8 class; /* FC class used for req/rsp */ - u8 rsp_timeout; /* timeout in secs, 0-no response */ - u8 cts; /* continue sequence */ - u8 lp_tag; /* lport tag */ - struct fchs_s fchs; /* request FC header structure */ - u32 req_len; /* request payload length */ - u32 rsp_maxlen; /* max response length expected */ - struct bfi_sge_s req_sge[BFA_FCXP_MAX_SGES]; /* request buf */ - struct bfi_sge_s rsp_sge[BFA_FCXP_MAX_SGES]; /* response buf */ -}; - -/** - * FCXP send response structure - */ -struct bfi_fcxp_send_rsp_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u16 fcxp_tag; /* send request tag */ - u8 req_status; /* request status */ - u8 rsvd; - u32 rsp_len; /* actual response length */ - u32 residue_len; /* residual response length */ - struct fchs_s fchs; /* response FC header structure */ -}; - -#pragma pack() - -#endif /* __BFI_FCXP_H__ */ - diff --git a/drivers/scsi/bfa/include/bfi/bfi_ioc.h b/drivers/scsi/bfa/include/bfi/bfi_ioc.h deleted file mode 100644 index 450ded6e9bc2..000000000000 --- a/drivers/scsi/bfa/include/bfi/bfi_ioc.h +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFI_IOC_H__ -#define __BFI_IOC_H__ - -#include "bfi.h" -#include <defs/bfa_defs_ioc.h> - -#pragma pack(1) - -enum bfi_ioc_h2i_msgs { - BFI_IOC_H2I_ENABLE_REQ = 1, - BFI_IOC_H2I_DISABLE_REQ = 2, - BFI_IOC_H2I_GETATTR_REQ = 3, - BFI_IOC_H2I_DBG_SYNC = 4, - BFI_IOC_H2I_DBG_DUMP = 5, -}; - -enum bfi_ioc_i2h_msgs { - BFI_IOC_I2H_ENABLE_REPLY = BFA_I2HM(1), - BFI_IOC_I2H_DISABLE_REPLY = BFA_I2HM(2), - BFI_IOC_I2H_GETATTR_REPLY = BFA_I2HM(3), - BFI_IOC_I2H_READY_EVENT = BFA_I2HM(4), - BFI_IOC_I2H_HBEAT = BFA_I2HM(5), -}; - -/** - * BFI_IOC_H2I_GETATTR_REQ message - */ -struct bfi_ioc_getattr_req_s { - struct bfi_mhdr_s mh; - union bfi_addr_u attr_addr; -}; - -struct bfi_ioc_attr_s { - wwn_t mfg_pwwn; /* Mfg port wwn */ - wwn_t mfg_nwwn; /* Mfg node wwn */ - mac_t mfg_mac; /* Mfg mac */ - 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; - u8 pcie_lanes; - u8 rx_bbcredit; /* receive buffer credits */ - u32 adapter_prop; /* adapter properties */ - u16 maxfrsize; /* max receive frame size */ - char asic_rev; - u8 rsvd_c; - char fw_version[BFA_VERSION_LEN]; - char optrom_version[BFA_VERSION_LEN]; - struct bfa_mfg_vpd_s vpd; - u32 card_type; /* card type */ -}; - -/** - * BFI_IOC_I2H_GETATTR_REPLY message - */ -struct bfi_ioc_getattr_reply_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u8 status; /* cfg reply status */ - u8 rsvd[3]; -}; - -/** - * Firmware memory page offsets - */ -#define BFI_IOC_SMEM_PG0_CB (0x40) -#define BFI_IOC_SMEM_PG0_CT (0x180) - -/** - * Firmware trace offset - */ -#define BFI_IOC_TRC_OFF (0x4b00) -#define BFI_IOC_TRC_ENTS 256 - -#define BFI_IOC_FW_SIGNATURE (0xbfadbfad) -#define BFI_IOC_MD5SUM_SZ 4 -struct bfi_ioc_image_hdr_s { - u32 signature; /* constant signature */ - u32 rsvd_a; - u32 exec; /* exec vector */ - u32 param; /* parameters */ - u32 rsvd_b[4]; - u32 md5sum[BFI_IOC_MD5SUM_SZ]; -}; - -/** - * BFI_IOC_I2H_READY_EVENT message - */ -struct bfi_ioc_rdy_event_s { - struct bfi_mhdr_s mh; /* common msg header */ - u8 init_status; /* init event status */ - u8 rsvd[3]; -}; - -struct bfi_ioc_hbeat_s { - struct bfi_mhdr_s mh; /* common msg header */ - u32 hb_count; /* current heart beat count */ -}; - -/** - * IOC hardware/firmware state - */ -enum bfi_ioc_state { - BFI_IOC_UNINIT = 0, /* not initialized */ - BFI_IOC_INITING = 1, /* h/w is being initialized */ - BFI_IOC_HWINIT = 2, /* h/w is initialized */ - BFI_IOC_CFG = 3, /* IOC configuration in progress */ - BFI_IOC_OP = 4, /* IOC is operational */ - BFI_IOC_DISABLING = 5, /* IOC is being disabled */ - BFI_IOC_DISABLED = 6, /* IOC is disabled */ - BFI_IOC_CFG_DISABLED = 7, /* IOC is being disabled;transient */ - BFI_IOC_FAIL = 8, /* IOC heart-beat failure */ - BFI_IOC_MEMTEST = 9, /* IOC is doing memtest */ -}; - -#define BFI_IOC_ENDIAN_SIG 0x12345678 - -enum { - BFI_ADAPTER_TYPE_FC = 0x01, /* FC adapters */ - BFI_ADAPTER_TYPE_MK = 0x0f0000, /* adapter type mask */ - BFI_ADAPTER_TYPE_SH = 16, /* adapter type shift */ - BFI_ADAPTER_NPORTS_MK = 0xff00, /* number of ports mask */ - BFI_ADAPTER_NPORTS_SH = 8, /* number of ports shift */ - BFI_ADAPTER_SPEED_MK = 0xff, /* adapter speed mask */ - BFI_ADAPTER_SPEED_SH = 0, /* adapter speed shift */ - BFI_ADAPTER_PROTO = 0x100000, /* prototype adapaters */ - BFI_ADAPTER_TTV = 0x200000, /* TTV debug capable */ - BFI_ADAPTER_UNSUPP = 0x400000, /* unknown adapter type */ -}; - -#define BFI_ADAPTER_GETP(__prop, __adap_prop) \ - (((__adap_prop) & BFI_ADAPTER_ ## __prop ## _MK) >> \ - BFI_ADAPTER_ ## __prop ## _SH) -#define BFI_ADAPTER_SETP(__prop, __val) \ - ((__val) << BFI_ADAPTER_ ## __prop ## _SH) -#define BFI_ADAPTER_IS_PROTO(__adap_type) \ - ((__adap_type) & BFI_ADAPTER_PROTO) -#define BFI_ADAPTER_IS_TTV(__adap_type) \ - ((__adap_type) & BFI_ADAPTER_TTV) -#define BFI_ADAPTER_IS_UNSUPP(__adap_type) \ - ((__adap_type) & BFI_ADAPTER_UNSUPP) -#define BFI_ADAPTER_IS_SPECIAL(__adap_type) \ - ((__adap_type) & (BFI_ADAPTER_TTV | BFI_ADAPTER_PROTO | \ - BFI_ADAPTER_UNSUPP)) - -/** - * BFI_IOC_H2I_ENABLE_REQ & BFI_IOC_H2I_DISABLE_REQ messages - */ -struct bfi_ioc_ctrl_req_s { - struct bfi_mhdr_s mh; - u8 ioc_class; - u8 rsvd[3]; -}; - -/** - * BFI_IOC_I2H_ENABLE_REPLY & BFI_IOC_I2H_DISABLE_REPLY messages - */ -struct bfi_ioc_ctrl_reply_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u8 status; /* enable/disable status */ - u8 rsvd[3]; -}; - -#define BFI_IOC_MSGSZ 8 -/** - * H2I Messages - */ -union bfi_ioc_h2i_msg_u { - struct bfi_mhdr_s mh; - struct bfi_ioc_ctrl_req_s enable_req; - struct bfi_ioc_ctrl_req_s disable_req; - struct bfi_ioc_getattr_req_s getattr_req; - u32 mboxmsg[BFI_IOC_MSGSZ]; -}; - -/** - * I2H Messages - */ -union bfi_ioc_i2h_msg_u { - struct bfi_mhdr_s mh; - struct bfi_ioc_rdy_event_s rdy_event; - u32 mboxmsg[BFI_IOC_MSGSZ]; -}; - -#pragma pack() - -#endif /* __BFI_IOC_H__ */ - diff --git a/drivers/scsi/bfa/include/bfi/bfi_iocfc.h b/drivers/scsi/bfa/include/bfi/bfi_iocfc.h deleted file mode 100644 index ccdfcc5d7e0b..000000000000 --- a/drivers/scsi/bfa/include/bfi/bfi_iocfc.h +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFI_IOCFC_H__ -#define __BFI_IOCFC_H__ - -#include "bfi.h" -#include <bfi/bfi_pbc.h> -#include <defs/bfa_defs_ioc.h> -#include <defs/bfa_defs_iocfc.h> -#include <defs/bfa_defs_boot.h> - -#pragma pack(1) - -enum bfi_iocfc_h2i_msgs { - BFI_IOCFC_H2I_CFG_REQ = 1, - BFI_IOCFC_H2I_GET_STATS_REQ = 2, - BFI_IOCFC_H2I_CLEAR_STATS_REQ = 3, - BFI_IOCFC_H2I_SET_INTR_REQ = 4, - BFI_IOCFC_H2I_UPDATEQ_REQ = 5, -}; - -enum bfi_iocfc_i2h_msgs { - BFI_IOCFC_I2H_CFG_REPLY = BFA_I2HM(1), - BFI_IOCFC_I2H_GET_STATS_RSP = BFA_I2HM(2), - BFI_IOCFC_I2H_CLEAR_STATS_RSP = BFA_I2HM(3), - BFI_IOCFC_I2H_UPDATEQ_RSP = BFA_I2HM(5), -}; - -struct bfi_iocfc_cfg_s { - u8 num_cqs; /* Number of CQs to be used */ - u8 sense_buf_len; /* SCSI sense length */ - u8 trunk_enabled; /* port trunking enabled */ - u8 trunk_ports; /* trunk ports bit map */ - u32 endian_sig; /* endian signature of host */ - - /** - * Request and response circular queue base addresses, size and - * shadow index pointers. - */ - union bfi_addr_u req_cq_ba[BFI_IOC_MAX_CQS]; - union bfi_addr_u req_shadow_ci[BFI_IOC_MAX_CQS]; - u16 req_cq_elems[BFI_IOC_MAX_CQS]; - union bfi_addr_u rsp_cq_ba[BFI_IOC_MAX_CQS]; - union bfi_addr_u rsp_shadow_pi[BFI_IOC_MAX_CQS]; - u16 rsp_cq_elems[BFI_IOC_MAX_CQS]; - - union bfi_addr_u stats_addr; /* DMA-able address for stats */ - union bfi_addr_u cfgrsp_addr; /* config response dma address */ - union bfi_addr_u ioim_snsbase; /* IO sense buffer base address */ - struct bfa_iocfc_intr_attr_s intr_attr; /* IOC interrupt attributes */ -}; - -/** - * Boot target wwn information for this port. This contains either the stored - * or discovered boot target port wwns for the port. - */ -struct bfi_iocfc_bootwwns { - wwn_t wwn[BFA_BOOT_BOOTLUN_MAX]; - u8 nwwns; - u8 rsvd[7]; -}; - -struct bfi_iocfc_cfgrsp_s { - struct bfa_iocfc_fwcfg_s fwcfg; - struct bfa_iocfc_intr_attr_s intr_attr; - struct bfi_iocfc_bootwwns bootwwns; - struct bfi_pbc_s pbc_cfg; -}; - -/** - * BFI_IOCFC_H2I_CFG_REQ message - */ -struct bfi_iocfc_cfg_req_s { - struct bfi_mhdr_s mh; - union bfi_addr_u ioc_cfg_dma_addr; -}; - -/** - * BFI_IOCFC_I2H_CFG_REPLY message - */ -struct bfi_iocfc_cfg_reply_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u8 cfg_success; /* cfg reply status */ - u8 lpu_bm; /* LPUs assigned for this IOC */ - u8 rsvd[2]; -}; - -/** - * BFI_IOCFC_H2I_GET_STATS_REQ & BFI_IOCFC_H2I_CLEAR_STATS_REQ messages - */ -struct bfi_iocfc_stats_req_s { - struct bfi_mhdr_s mh; /* msg header */ - u32 msgtag; /* msgtag for reply */ -}; - -/** - * BFI_IOCFC_I2H_GET_STATS_RSP & BFI_IOCFC_I2H_CLEAR_STATS_RSP messages - */ -struct bfi_iocfc_stats_rsp_s { - struct bfi_mhdr_s mh; /* common msg header */ - u8 status; /* reply status */ - u8 rsvd[3]; - u32 msgtag; /* msgtag for reply */ -}; - -/** - * BFI_IOCFC_H2I_SET_INTR_REQ message - */ -struct bfi_iocfc_set_intr_req_s { - struct bfi_mhdr_s mh; /* common msg header */ - u8 coalesce; /* enable intr coalescing*/ - u8 rsvd[3]; - u16 delay; /* delay timer 0..1125us */ - u16 latency; /* latency timer 0..225us */ -}; - -/** - * BFI_IOCFC_H2I_UPDATEQ_REQ message - */ -struct bfi_iocfc_updateq_req_s { - struct bfi_mhdr_s mh; /* common msg header */ - u32 reqq_ba; /* reqq base addr */ - u32 rspq_ba; /* rspq base addr */ - u32 reqq_sci; /* reqq shadow ci */ - u32 rspq_spi; /* rspq shadow pi */ -}; - -/** - * BFI_IOCFC_I2H_UPDATEQ_RSP message - */ -struct bfi_iocfc_updateq_rsp_s { - struct bfi_mhdr_s mh; /* common msg header */ - u8 status; /* updateq status */ - u8 rsvd[3]; -}; - -/** - * H2I Messages - */ -union bfi_iocfc_h2i_msg_u { - struct bfi_mhdr_s mh; - struct bfi_iocfc_cfg_req_s cfg_req; - struct bfi_iocfc_stats_req_s stats_get; - struct bfi_iocfc_stats_req_s stats_clr; - struct bfi_iocfc_updateq_req_s updateq_req; - u32 mboxmsg[BFI_IOC_MSGSZ]; -}; - -/** - * I2H Messages - */ -union bfi_iocfc_i2h_msg_u { - struct bfi_mhdr_s mh; - struct bfi_iocfc_cfg_reply_s cfg_reply; - struct bfi_iocfc_stats_rsp_s stats_get_rsp; - struct bfi_iocfc_stats_rsp_s stats_clr_rsp; - struct bfi_iocfc_updateq_rsp_s updateq_rsp; - u32 mboxmsg[BFI_IOC_MSGSZ]; -}; - -#pragma pack() - -#endif /* __BFI_IOCFC_H__ */ - diff --git a/drivers/scsi/bfa/include/bfi/bfi_lport.h b/drivers/scsi/bfa/include/bfi/bfi_lport.h deleted file mode 100644 index 29010614bac9..000000000000 --- a/drivers/scsi/bfa/include/bfi/bfi_lport.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFI_LPORT_H__ -#define __BFI_LPORT_H__ - -#include <bfi/bfi.h> - -#pragma pack(1) - -enum bfi_lport_h2i_msgs { - BFI_LPORT_H2I_CREATE_REQ = 1, - BFI_LPORT_H2I_DELETE_REQ = 2, -}; - -enum bfi_lport_i2h_msgs { - BFI_LPORT_I2H_CREATE_RSP = BFA_I2HM(1), - BFI_LPORT_I2H_DELETE_RSP = BFA_I2HM(2), - BFI_LPORT_I2H_ONLINE = BFA_I2HM(3), - BFI_LPORT_I2H_OFFLINE = BFA_I2HM(4), -}; - -#define BFI_LPORT_MAX_SYNNAME 64 - -enum bfi_lport_role_e { - BFI_LPORT_ROLE_FCPIM = 1, - BFI_LPORT_ROLE_FCPTM = 2, - BFI_LPORT_ROLE_IPFC = 4, -}; - -struct bfi_lport_create_req_s { - bfi_mhdr_t mh; /* common msg header */ - u16 fabric_fwhdl; /* parent fabric instance */ - u8 roles; /* lport FC-4 roles */ - u8 rsvd; - wwn_t pwwn; /* port name */ - wwn_t nwwn; /* node name */ - u8 symname[BFI_LPORT_MAX_SYNNAME]; -}; - -struct bfi_lport_create_rsp_s { - bfi_mhdr_t mh; /* common msg header */ - u8 status; /* lport creation status */ - u8 rsvd[3]; -}; - -struct bfi_lport_delete_req_s { - bfi_mhdr_t mh; /* common msg header */ - u16 fw_handle; /* firmware lport handle */ - u16 rsvd; -}; - -struct bfi_lport_delete_rsp_s { - bfi_mhdr_t mh; /* common msg header */ - u16 bfa_handle; /* host lport handle */ - u8 status; /* lport deletion status */ - u8 rsvd; -}; - -union bfi_lport_h2i_msg_u { - bfi_msg_t *msg; - struct bfi_lport_create_req_s *create_req; - struct bfi_lport_delete_req_s *delete_req; -}; - -union bfi_lport_i2h_msg_u { - bfi_msg_t *msg; - struct bfi_lport_create_rsp_s *create_rsp; - struct bfi_lport_delete_rsp_s *delete_rsp; -}; - -#pragma pack() - -#endif /* __BFI_LPORT_H__ */ - diff --git a/drivers/scsi/bfa/include/bfi/bfi_lps.h b/drivers/scsi/bfa/include/bfi/bfi_lps.h deleted file mode 100644 index 7ed31bbb8696..000000000000 --- a/drivers/scsi/bfa/include/bfi/bfi_lps.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFI_LPS_H__ -#define __BFI_LPS_H__ - -#include <bfi/bfi.h> - -#pragma pack(1) - -enum bfi_lps_h2i_msgs { - BFI_LPS_H2I_LOGIN_REQ = 1, - BFI_LPS_H2I_LOGOUT_REQ = 2, -}; - -enum bfi_lps_i2h_msgs { - BFI_LPS_H2I_LOGIN_RSP = BFA_I2HM(1), - BFI_LPS_H2I_LOGOUT_RSP = BFA_I2HM(2), - BFI_LPS_H2I_CVL_EVENT = BFA_I2HM(3), -}; - -struct bfi_lps_login_req_s { - struct bfi_mhdr_s mh; /* common msg header */ - u8 lp_tag; - u8 alpa; - u16 pdu_size; - wwn_t pwwn; - wwn_t nwwn; - u8 fdisc; - u8 auth_en; - u8 rsvd[2]; -}; - -struct bfi_lps_login_rsp_s { - struct bfi_mhdr_s mh; /* common msg header */ - u8 lp_tag; - u8 status; - u8 lsrjt_rsn; - u8 lsrjt_expl; - wwn_t port_name; - wwn_t node_name; - u16 bb_credit; - u8 f_port; - u8 npiv_en; - u32 lp_pid:24; - u32 auth_req:8; - mac_t lp_mac; - mac_t fcf_mac; - u8 ext_status; - u8 brcd_switch;/* attached peer is brcd switch */ -}; - -struct bfi_lps_logout_req_s { - struct bfi_mhdr_s mh; /* common msg header */ - u8 lp_tag; - u8 rsvd[3]; - wwn_t port_name; -}; - -struct bfi_lps_logout_rsp_s { - struct bfi_mhdr_s mh; /* common msg header */ - u8 lp_tag; - u8 status; - u8 rsvd[2]; -}; - -struct bfi_lps_cvl_event_s { - struct bfi_mhdr_s mh; /* common msg header */ - u8 lp_tag; - u8 rsvd[3]; -}; - -union bfi_lps_h2i_msg_u { - struct bfi_mhdr_s *msg; - struct bfi_lps_login_req_s *login_req; - struct bfi_lps_logout_req_s *logout_req; -}; - -union bfi_lps_i2h_msg_u { - struct bfi_msg_s *msg; - struct bfi_lps_login_rsp_s *login_rsp; - struct bfi_lps_logout_rsp_s *logout_rsp; - struct bfi_lps_cvl_event_s *cvl_event; -}; - -#pragma pack() - -#endif /* __BFI_LPS_H__ */ - - diff --git a/drivers/scsi/bfa/include/bfi/bfi_pbc.h b/drivers/scsi/bfa/include/bfi/bfi_pbc.h deleted file mode 100644 index 88a4154c30c0..000000000000 --- a/drivers/scsi/bfa/include/bfi/bfi_pbc.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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/bfi/bfi_port.h b/drivers/scsi/bfa/include/bfi/bfi_port.h deleted file mode 100644 index 3ec3bea110ba..000000000000 --- a/drivers/scsi/bfa/include/bfi/bfi_port.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ -#ifndef __BFI_PORT_H__ -#define __BFI_PORT_H__ - -#include <bfi/bfi.h> -#include <defs/bfa_defs_pport.h> - -#pragma pack(1) - -enum bfi_port_h2i { - BFI_PORT_H2I_ENABLE_REQ = (1), - BFI_PORT_H2I_DISABLE_REQ = (2), - BFI_PORT_H2I_GET_STATS_REQ = (3), - BFI_PORT_H2I_CLEAR_STATS_REQ = (4), -}; - -enum bfi_port_i2h { - BFI_PORT_I2H_ENABLE_RSP = BFA_I2HM(1), - BFI_PORT_I2H_DISABLE_RSP = BFA_I2HM(2), - BFI_PORT_I2H_GET_STATS_RSP = BFA_I2HM(3), - BFI_PORT_I2H_CLEAR_STATS_RSP = BFA_I2HM(4), -}; - -/** - * Generic REQ type - */ -struct bfi_port_generic_req_s { - struct bfi_mhdr_s mh; /* msg header */ - u32 msgtag; /* msgtag for reply */ - u32 rsvd; -}; - -/** - * Generic RSP type - */ -struct bfi_port_generic_rsp_s { - struct bfi_mhdr_s mh; /* common msg header */ - u8 status; /* port enable status */ - u8 rsvd[3]; - u32 msgtag; /* msgtag for reply */ -}; - -/** - * @todo - * BFI_PORT_H2I_ENABLE_REQ - */ - -/** - * @todo - * BFI_PORT_I2H_ENABLE_RSP - */ - -/** - * BFI_PORT_H2I_DISABLE_REQ - */ - -/** - * BFI_PORT_I2H_DISABLE_RSP - */ - -/** - * BFI_PORT_H2I_GET_STATS_REQ - */ -struct bfi_port_get_stats_req_s { - struct bfi_mhdr_s mh; /* common msg header */ - union bfi_addr_u dma_addr; -}; - -/** - * BFI_PORT_I2H_GET_STATS_RSP - */ - -/** - * BFI_PORT_H2I_CLEAR_STATS_REQ - */ - -/** - * BFI_PORT_I2H_CLEAR_STATS_RSP - */ - -union bfi_port_h2i_msg_u { - struct bfi_mhdr_s mh; - struct bfi_port_generic_req_s enable_req; - struct bfi_port_generic_req_s disable_req; - struct bfi_port_get_stats_req_s getstats_req; - struct bfi_port_generic_req_s clearstats_req; -}; - -union bfi_port_i2h_msg_u { - struct bfi_mhdr_s mh; - struct bfi_port_generic_rsp_s enable_rsp; - struct bfi_port_generic_rsp_s disable_rsp; - struct bfi_port_generic_rsp_s getstats_rsp; - struct bfi_port_generic_rsp_s clearstats_rsp; -}; - -#pragma pack() - -#endif /* __BFI_PORT_H__ */ - diff --git a/drivers/scsi/bfa/include/bfi/bfi_pport.h b/drivers/scsi/bfa/include/bfi/bfi_pport.h deleted file mode 100644 index 50dcf45c7470..000000000000 --- a/drivers/scsi/bfa/include/bfi/bfi_pport.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ -#ifndef __BFI_PPORT_H__ -#define __BFI_PPORT_H__ - -#include <bfi/bfi.h> -#include <defs/bfa_defs_pport.h> - -#pragma pack(1) - -enum bfi_fcport_h2i { - BFI_FCPORT_H2I_ENABLE_REQ = (1), - BFI_FCPORT_H2I_DISABLE_REQ = (2), - BFI_FCPORT_H2I_SET_SVC_PARAMS_REQ = (3), - BFI_FCPORT_H2I_STATS_GET_REQ = (4), - BFI_FCPORT_H2I_STATS_CLEAR_REQ = (5), -}; - -enum bfi_fcport_i2h { - BFI_FCPORT_I2H_ENABLE_RSP = BFA_I2HM(1), - BFI_FCPORT_I2H_DISABLE_RSP = BFA_I2HM(2), - BFI_FCPORT_I2H_SET_SVC_PARAMS_RSP = BFA_I2HM(3), - BFI_FCPORT_I2H_STATS_GET_RSP = BFA_I2HM(4), - BFI_FCPORT_I2H_STATS_CLEAR_RSP = BFA_I2HM(5), - BFI_FCPORT_I2H_EVENT = BFA_I2HM(6), -}; - -/** - * Generic REQ type - */ -struct bfi_fcport_req_s { - struct bfi_mhdr_s mh; /* msg header */ - u32 msgtag; /* msgtag for reply */ -}; - -/** - * Generic RSP type - */ -struct bfi_fcport_rsp_s { - struct bfi_mhdr_s mh; /* common msg header */ - u8 status; /* port enable status */ - u8 rsvd[3]; - u32 msgtag; /* msgtag for reply */ -}; - -/** - * BFI_FCPORT_H2I_ENABLE_REQ - */ -struct bfi_fcport_enable_req_s { - struct bfi_mhdr_s mh; /* msg header */ - u32 rsvd1; - wwn_t nwwn; /* node wwn of physical port */ - wwn_t pwwn; /* port wwn of physical port */ - struct bfa_pport_cfg_s port_cfg; /* port configuration */ - union bfi_addr_u stats_dma_addr; /* DMA address for stats */ - u32 msgtag; /* msgtag for reply */ - u32 rsvd2; -}; - -/** - * BFI_FCPORT_H2I_SET_SVC_PARAMS_REQ - */ -struct bfi_fcport_set_svc_params_req_s { - struct bfi_mhdr_s mh; /* msg header */ - u16 tx_bbcredit; /* Tx credits */ - u16 rsvd; -}; - -/** - * BFI_FCPORT_I2H_EVENT - */ -struct bfi_fcport_event_s { - struct bfi_mhdr_s mh; /* common msg header */ - struct bfa_pport_link_s link_state; -}; - -/** - * fcport H2I message - */ -union bfi_fcport_h2i_msg_u { - struct bfi_mhdr_s *mhdr; - struct bfi_fcport_enable_req_s *penable; - struct bfi_fcport_req_s *pdisable; - struct bfi_fcport_set_svc_params_req_s *psetsvcparams; - struct bfi_fcport_req_s *pstatsget; - struct bfi_fcport_req_s *pstatsclear; -}; - -/** - * fcport I2H message - */ -union bfi_fcport_i2h_msg_u { - struct bfi_msg_s *msg; - struct bfi_fcport_rsp_s *penable_rsp; - struct bfi_fcport_rsp_s *pdisable_rsp; - struct bfi_fcport_rsp_s *psetsvcparams_rsp; - struct bfi_fcport_rsp_s *pstatsget_rsp; - struct bfi_fcport_rsp_s *pstatsclear_rsp; - struct bfi_fcport_event_s *event; -}; - -#pragma pack() - -#endif /* __BFI_PPORT_H__ */ diff --git a/drivers/scsi/bfa/include/bfi/bfi_rport.h b/drivers/scsi/bfa/include/bfi/bfi_rport.h deleted file mode 100644 index e1cd83b56ec6..000000000000 --- a/drivers/scsi/bfa/include/bfi/bfi_rport.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFI_RPORT_H__ -#define __BFI_RPORT_H__ - -#include <bfi/bfi.h> - -#pragma pack(1) - -enum bfi_rport_h2i_msgs { - BFI_RPORT_H2I_CREATE_REQ = 1, - BFI_RPORT_H2I_DELETE_REQ = 2, - BFI_RPORT_H2I_SET_SPEED_REQ = 3, -}; - -enum bfi_rport_i2h_msgs { - BFI_RPORT_I2H_CREATE_RSP = BFA_I2HM(1), - BFI_RPORT_I2H_DELETE_RSP = BFA_I2HM(2), - BFI_RPORT_I2H_QOS_SCN = BFA_I2HM(3), -}; - -struct bfi_rport_create_req_s { - struct bfi_mhdr_s mh; /* common msg header */ - u16 bfa_handle; /* host rport handle */ - u16 max_frmsz; /* max rcv pdu size */ - u32 pid:24, /* remote port ID */ - lp_tag:8; /* local port tag */ - u32 local_pid:24, /* local port ID */ - cisc:8; - u8 fc_class; /* supported FC classes */ - u8 vf_en; /* virtual fabric enable */ - u16 vf_id; /* virtual fabric ID */ -}; - -struct bfi_rport_create_rsp_s { - struct bfi_mhdr_s mh; /* common msg header */ - u8 status; /* rport creation status */ - u8 rsvd[3]; - u16 bfa_handle; /* host rport handle */ - u16 fw_handle; /* firmware rport handle */ - struct bfa_rport_qos_attr_s qos_attr; /* QoS Attributes */ -}; - -struct bfa_rport_speed_req_s { - struct bfi_mhdr_s mh; /* common msg header */ - u16 fw_handle; /* firmware rport handle */ - u8 speed; /*! rport's speed via RPSC */ - u8 rsvd; -}; - -struct bfi_rport_delete_req_s { - struct bfi_mhdr_s mh; /* common msg header */ - u16 fw_handle; /* firmware rport handle */ - u16 rsvd; -}; - -struct bfi_rport_delete_rsp_s { - struct bfi_mhdr_s mh; /* common msg header */ - u16 bfa_handle; /* host rport handle */ - u8 status; /* rport deletion status */ - u8 rsvd; -}; - -struct bfi_rport_qos_scn_s { - struct bfi_mhdr_s mh; /* common msg header */ - u16 bfa_handle; /* host rport handle */ - u16 rsvd; - struct bfa_rport_qos_attr_s old_qos_attr; /* Old QoS Attributes */ - struct bfa_rport_qos_attr_s new_qos_attr; /* New QoS Attributes */ -}; - -union bfi_rport_h2i_msg_u { - struct bfi_msg_s *msg; - struct bfi_rport_create_req_s *create_req; - struct bfi_rport_delete_req_s *delete_req; - struct bfi_rport_speed_req_s *speed_req; -}; - -union bfi_rport_i2h_msg_u { - struct bfi_msg_s *msg; - struct bfi_rport_create_rsp_s *create_rsp; - struct bfi_rport_delete_rsp_s *delete_rsp; - struct bfi_rport_qos_scn_s *qos_scn_evt; -}; - -#pragma pack() - -#endif /* __BFI_RPORT_H__ */ - diff --git a/drivers/scsi/bfa/include/bfi/bfi_uf.h b/drivers/scsi/bfa/include/bfi/bfi_uf.h deleted file mode 100644 index f328a9e7e622..000000000000 --- a/drivers/scsi/bfa/include/bfi/bfi_uf.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFI_UF_H__ -#define __BFI_UF_H__ - -#include "bfi.h" - -#pragma pack(1) - -enum bfi_uf_h2i { - BFI_UF_H2I_BUF_POST = 1, -}; - -enum bfi_uf_i2h { - BFI_UF_I2H_FRM_RCVD = BFA_I2HM(1), -}; - -#define BFA_UF_MAX_SGES 2 - -struct bfi_uf_buf_post_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u16 buf_tag; /* buffer tag */ - u16 buf_len; /* total buffer length */ - struct bfi_sge_s sge[BFA_UF_MAX_SGES]; /* buffer DMA SGEs */ -}; - -struct bfi_uf_frm_rcvd_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u16 buf_tag; /* buffer tag */ - u16 rsvd; - u16 frm_len; /* received frame length */ - u16 xfr_len; /* tranferred length */ -}; - -#pragma pack() - -#endif /* __BFI_UF_H__ */ diff --git a/drivers/scsi/bfa/include/cna/bfa_cna_trcmod.h b/drivers/scsi/bfa/include/cna/bfa_cna_trcmod.h deleted file mode 100644 index a75a1f3be315..000000000000 --- a/drivers/scsi/bfa/include/cna/bfa_cna_trcmod.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/** - * bfa_cna_trcmod.h CNA trace modules - */ - -#ifndef __BFA_CNA_TRCMOD_H__ -#define __BFA_CNA_TRCMOD_H__ - -#include <cs/bfa_trc.h> - -/* - * !!! Only append to the enums defined here to avoid any versioning - * !!! needed between trace utility and driver version - */ -enum { - BFA_TRC_CNA_CEE = 1, - BFA_TRC_CNA_PORT = 2, - BFA_TRC_CNA_IOC = 3, - BFA_TRC_CNA_DIAG = 4, - BFA_TRC_CNA_IOC_CB = 5, - BFA_TRC_CNA_IOC_CT = 6, -}; - -#endif /* __BFA_CNA_TRCMOD_H__ */ diff --git a/drivers/scsi/bfa/include/cna/cee/bfa_cee.h b/drivers/scsi/bfa/include/cna/cee/bfa_cee.h deleted file mode 100644 index 77f297f68046..000000000000 --- a/drivers/scsi/bfa/include/cna/cee/bfa_cee.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFA_CEE_H__ -#define __BFA_CEE_H__ - -#include <defs/bfa_defs_cee.h> -#include <bfa_ioc.h> -#include <cs/bfa_trc.h> -#include <cs/bfa_log.h> - -typedef void (*bfa_cee_get_attr_cbfn_t) (void *dev, bfa_status_t status); -typedef void (*bfa_cee_get_stats_cbfn_t) (void *dev, bfa_status_t status); -typedef void (*bfa_cee_reset_stats_cbfn_t) (void *dev, bfa_status_t status); -typedef void (*bfa_cee_hbfail_cbfn_t) (void *dev, bfa_status_t status); - -struct bfa_cee_cbfn_s { - bfa_cee_get_attr_cbfn_t get_attr_cbfn; - void *get_attr_cbarg; - bfa_cee_get_stats_cbfn_t get_stats_cbfn; - void *get_stats_cbarg; - bfa_cee_reset_stats_cbfn_t reset_stats_cbfn; - void *reset_stats_cbarg; -}; - -struct bfa_cee_s { - void *dev; - bfa_boolean_t get_attr_pending; - bfa_boolean_t get_stats_pending; - bfa_boolean_t reset_stats_pending; - bfa_status_t get_attr_status; - bfa_status_t get_stats_status; - bfa_status_t reset_stats_status; - struct bfa_cee_cbfn_s cbfn; - struct bfa_ioc_hbfail_notify_s hbfail; - struct bfa_trc_mod_s *trcmod; - struct bfa_log_mod_s *logmod; - struct bfa_cee_attr_s *attr; - struct bfa_cee_stats_s *stats; - struct bfa_dma_s attr_dma; - struct bfa_dma_s stats_dma; - struct bfa_ioc_s *ioc; - struct bfa_mbox_cmd_s get_cfg_mb; - struct bfa_mbox_cmd_s get_stats_mb; - struct bfa_mbox_cmd_s reset_stats_mb; -}; - -u32 bfa_cee_meminfo(void); -void bfa_cee_mem_claim(struct bfa_cee_s *cee, u8 *dma_kva, - u64 dma_pa); -void bfa_cee_attach(struct bfa_cee_s *cee, struct bfa_ioc_s *ioc, void *dev, - struct bfa_trc_mod_s *trcmod, - struct bfa_log_mod_s *logmod); -void bfa_cee_detach(struct bfa_cee_s *cee); -bfa_status_t bfa_cee_get_attr(struct bfa_cee_s *cee, - struct bfa_cee_attr_s *attr, - bfa_cee_get_attr_cbfn_t cbfn, void *cbarg); -bfa_status_t bfa_cee_get_stats(struct bfa_cee_s *cee, - struct bfa_cee_stats_s *stats, - bfa_cee_get_stats_cbfn_t cbfn, void *cbarg); -bfa_status_t bfa_cee_reset_stats(struct bfa_cee_s *cee, - bfa_cee_reset_stats_cbfn_t cbfn, void *cbarg); -#endif /* __BFA_CEE_H__ */ diff --git a/drivers/scsi/bfa/include/cna/port/bfa_port.h b/drivers/scsi/bfa/include/cna/port/bfa_port.h deleted file mode 100644 index d7babaf97848..000000000000 --- a/drivers/scsi/bfa/include/cna/port/bfa_port.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFA_PORT_H__ -#define __BFA_PORT_H__ - -#include <defs/bfa_defs_port.h> -#include <bfa_ioc.h> -#include <cs/bfa_trc.h> -#include <cs/bfa_log.h> - -typedef void (*bfa_port_stats_cbfn_t) (void *dev, bfa_status_t status); -typedef void (*bfa_port_endis_cbfn_t) (void *dev, bfa_status_t status); - -struct bfa_port_s { - void *dev; - struct bfa_ioc_s *ioc; - struct bfa_trc_mod_s *trcmod; - struct bfa_log_mod_s *logmod; - u32 msgtag; - bfa_boolean_t stats_busy; - struct bfa_mbox_cmd_s stats_mb; - bfa_port_stats_cbfn_t stats_cbfn; - void *stats_cbarg; - bfa_status_t stats_status; - u32 stats_reset_time; - union bfa_pport_stats_u *stats; - struct bfa_dma_s stats_dma; - bfa_boolean_t endis_pending; - struct bfa_mbox_cmd_s endis_mb; - bfa_port_endis_cbfn_t endis_cbfn; - void *endis_cbarg; - bfa_status_t endis_status; - struct bfa_ioc_hbfail_notify_s hbfail; -}; - -void bfa_port_attach(struct bfa_port_s *port, struct bfa_ioc_s *ioc, - void *dev, struct bfa_trc_mod_s *trcmod, - struct bfa_log_mod_s *logmod); -void bfa_port_detach(struct bfa_port_s *port); -void bfa_port_hbfail(void *arg); - -bfa_status_t bfa_port_get_stats(struct bfa_port_s *port, - union bfa_pport_stats_u *stats, - bfa_port_stats_cbfn_t cbfn, void *cbarg); -bfa_status_t bfa_port_clear_stats(struct bfa_port_s *port, - bfa_port_stats_cbfn_t cbfn, void *cbarg); -bfa_status_t bfa_port_enable(struct bfa_port_s *port, - bfa_port_endis_cbfn_t cbfn, void *cbarg); -bfa_status_t bfa_port_disable(struct bfa_port_s *port, - bfa_port_endis_cbfn_t cbfn, void *cbarg); -u32 bfa_port_meminfo(void); -void bfa_port_mem_claim(struct bfa_port_s *port, u8 *dma_kva, - u64 dma_pa); - -#endif /* __BFA_PORT_H__ */ diff --git a/drivers/scsi/bfa/include/cna/pstats/ethport_defs.h b/drivers/scsi/bfa/include/cna/pstats/ethport_defs.h deleted file mode 100644 index 1563ee512218..000000000000 --- a/drivers/scsi/bfa/include/cna/pstats/ethport_defs.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved. - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __ETHPORT_DEFS_H__ -#define __ETHPORT_DEFS_H__ - -struct bnad_drv_stats { - u64 netif_queue_stop; - u64 netif_queue_wakeup; - u64 tso4; - u64 tso6; - u64 tso_err; - u64 tcpcsum_offload; - u64 udpcsum_offload; - u64 csum_help; - u64 csum_help_err; - - u64 hw_stats_updates; - u64 netif_rx_schedule; - u64 netif_rx_complete; - u64 netif_rx_dropped; -}; -#endif diff --git a/drivers/scsi/bfa/include/cna/pstats/phyport_defs.h b/drivers/scsi/bfa/include/cna/pstats/phyport_defs.h deleted file mode 100644 index eb7548030d0f..000000000000 --- a/drivers/scsi/bfa/include/cna/pstats/phyport_defs.h +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved. - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __PHYPORT_DEFS_H__ -#define __PHYPORT_DEFS_H__ - -#define BNA_TXF_ID_MAX 64 -#define BNA_RXF_ID_MAX 64 - -/* - * Statistics - */ - -/* - * TxF Frame Statistics - */ -struct bna_stats_txf { - u64 ucast_octets; - u64 ucast; - u64 ucast_vlan; - - u64 mcast_octets; - u64 mcast; - u64 mcast_vlan; - - u64 bcast_octets; - u64 bcast; - u64 bcast_vlan; - - u64 errors; - u64 filter_vlan; /* frames filtered due to VLAN */ - u64 filter_mac_sa; /* frames filtered due to SA check */ -}; - -/* - * RxF Frame Statistics - */ -struct bna_stats_rxf { - u64 ucast_octets; - u64 ucast; - u64 ucast_vlan; - - u64 mcast_octets; - u64 mcast; - u64 mcast_vlan; - - u64 bcast_octets; - u64 bcast; - u64 bcast_vlan; - u64 frame_drops; -}; - -/* - * FC Tx Frame Statistics - */ -struct bna_stats_fc_tx { - u64 txf_ucast_octets; - u64 txf_ucast; - u64 txf_ucast_vlan; - - u64 txf_mcast_octets; - u64 txf_mcast; - u64 txf_mcast_vlan; - - u64 txf_bcast_octets; - u64 txf_bcast; - u64 txf_bcast_vlan; - - u64 txf_parity_errors; - u64 txf_timeout; - u64 txf_fid_parity_errors; -}; - -/* - * FC Rx Frame Statistics - */ -struct bna_stats_fc_rx { - u64 rxf_ucast_octets; - u64 rxf_ucast; - u64 rxf_ucast_vlan; - - u64 rxf_mcast_octets; - u64 rxf_mcast; - u64 rxf_mcast_vlan; - - u64 rxf_bcast_octets; - u64 rxf_bcast; - u64 rxf_bcast_vlan; -}; - -/* - * RAD Frame Statistics - */ -struct cna_stats_rad { - u64 rx_frames; - u64 rx_octets; - u64 rx_vlan_frames; - - u64 rx_ucast; - u64 rx_ucast_octets; - u64 rx_ucast_vlan; - - u64 rx_mcast; - u64 rx_mcast_octets; - u64 rx_mcast_vlan; - - u64 rx_bcast; - u64 rx_bcast_octets; - u64 rx_bcast_vlan; - - u64 rx_drops; -}; - -/* - * BPC Tx Registers - */ -struct cna_stats_bpc_tx { - u64 tx_pause[8]; - u64 tx_zero_pause[8]; /* Pause cancellation */ - u64 tx_first_pause[8]; /* Pause initiation rather - *than retention */ -}; - -/* - * BPC Rx Registers - */ -struct cna_stats_bpc_rx { - u64 rx_pause[8]; - u64 rx_zero_pause[8]; /* Pause cancellation */ - u64 rx_first_pause[8]; /* Pause initiation rather - *than retention */ -}; - -/* - * MAC Rx Statistics - */ -struct cna_stats_mac_rx { - u64 frame_64; /* both rx and tx counter */ - u64 frame_65_127; /* both rx and tx counter */ - u64 frame_128_255; /* both rx and tx counter */ - u64 frame_256_511; /* both rx and tx counter */ - u64 frame_512_1023; /* both rx and tx counter */ - u64 frame_1024_1518; /* both rx and tx counter */ - u64 frame_1518_1522; /* both rx and tx counter */ - u64 rx_bytes; - u64 rx_packets; - u64 rx_fcs_error; - u64 rx_multicast; - u64 rx_broadcast; - u64 rx_control_frames; - u64 rx_pause; - u64 rx_unknown_opcode; - u64 rx_alignment_error; - u64 rx_frame_length_error; - u64 rx_code_error; - u64 rx_carrier_sense_error; - u64 rx_undersize; - u64 rx_oversize; - u64 rx_fragments; - u64 rx_jabber; - u64 rx_drop; -}; - -/* - * MAC Tx Statistics - */ -struct cna_stats_mac_tx { - u64 tx_bytes; - u64 tx_packets; - u64 tx_multicast; - u64 tx_broadcast; - u64 tx_pause; - u64 tx_deferral; - u64 tx_excessive_deferral; - u64 tx_single_collision; - u64 tx_muliple_collision; - u64 tx_late_collision; - u64 tx_excessive_collision; - u64 tx_total_collision; - u64 tx_pause_honored; - u64 tx_drop; - u64 tx_jabber; - u64 tx_fcs_error; - u64 tx_control_frame; - u64 tx_oversize; - u64 tx_undersize; - u64 tx_fragments; -}; - -/* - * Complete statistics - */ -struct bna_stats { - struct cna_stats_mac_rx mac_rx_stats; - struct cna_stats_bpc_rx bpc_rx_stats; - struct cna_stats_rad rad_stats; - struct bna_stats_fc_rx fc_rx_stats; - struct cna_stats_mac_tx mac_tx_stats; - struct cna_stats_bpc_tx bpc_tx_stats; - struct bna_stats_fc_tx fc_tx_stats; - struct bna_stats_rxf rxf_stats[BNA_TXF_ID_MAX]; - struct bna_stats_txf txf_stats[BNA_RXF_ID_MAX]; -}; - -#endif diff --git a/drivers/scsi/bfa/include/cs/bfa_checksum.h b/drivers/scsi/bfa/include/cs/bfa_checksum.h deleted file mode 100644 index 650f8d0aaff9..000000000000 --- a/drivers/scsi/bfa/include/cs/bfa_checksum.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/** - * bfa_checksum.h BFA checksum utilities - */ - -#ifndef __BFA_CHECKSUM_H__ -#define __BFA_CHECKSUM_H__ - -static inline u32 -bfa_checksum_u32(u32 *buf, int sz) -{ - int i, m = sz >> 2; - u32 sum = 0; - - for (i = 0; i < m; i++) - sum ^= buf[i]; - - return sum; -} - -static inline u16 -bfa_checksum_u16(u16 *buf, int sz) -{ - int i, m = sz >> 1; - u16 sum = 0; - - for (i = 0; i < m; i++) - sum ^= buf[i]; - - return sum; -} - -static inline u8 -bfa_checksum_u8(u8 *buf, int sz) -{ - int i; - u8 sum = 0; - - for (i = 0; i < sz; i++) - sum ^= buf[i]; - - return sum; -} -#endif diff --git a/drivers/scsi/bfa/include/cs/bfa_debug.h b/drivers/scsi/bfa/include/cs/bfa_debug.h deleted file mode 100644 index 75a911ea7936..000000000000 --- a/drivers/scsi/bfa/include/cs/bfa_debug.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/** - * bfa_debug.h BFA debug interfaces - */ - -#ifndef __BFA_DEBUG_H__ -#define __BFA_DEBUG_H__ - -#define bfa_assert(__cond) do { \ - if (!(__cond)) \ - bfa_panic(__LINE__, __FILE__, #__cond); \ -} while (0) - -#define bfa_sm_fault(__mod, __event) do { \ - bfa_trc(__mod, (((uint32_t)0xDEAD << 16) | __event)); \ - bfa_sm_panic((__mod)->logm, __LINE__, __FILE__, __event); \ -} while (0) - -#ifndef BFA_PERF_BUILD -#define bfa_assert_fp(__cond) bfa_assert(__cond) -#else -#define bfa_assert_fp(__cond) -#endif - -struct bfa_log_mod_s; -void bfa_panic(int line, char *file, char *panicstr); -void bfa_sm_panic(struct bfa_log_mod_s *logm, int line, char *file, int event); - -#endif /* __BFA_DEBUG_H__ */ diff --git a/drivers/scsi/bfa/include/cs/bfa_log.h b/drivers/scsi/bfa/include/cs/bfa_log.h deleted file mode 100644 index bc334e0a93fa..000000000000 --- a/drivers/scsi/bfa/include/cs/bfa_log.h +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/** - * bfa_log.h BFA log library data structure and function definition - */ - -#ifndef __BFA_LOG_H__ -#define __BFA_LOG_H__ - -#include <bfa_os_inc.h> -#include <defs/bfa_defs_status.h> -#include <defs/bfa_defs_aen.h> - -/* - * BFA log module definition - * - * To create a new module id: - * Add a #define at the end of the list below. Select a value for your - * definition so that it is one (1) greater than the previous - * definition. Modify the definition of BFA_LOG_MODULE_ID_MAX to become - * your new definition. - * Should have no gaps in between the values because this is used in arrays. - * IMPORTANT: AEN_IDs must be at the begining, otherwise update bfa_defs_aen.h - */ - -enum bfa_log_module_id { - BFA_LOG_UNUSED_ID = 0, - - /* AEN defs begin */ - BFA_LOG_AEN_MIN = BFA_LOG_UNUSED_ID, - - BFA_LOG_AEN_ID_ADAPTER = BFA_LOG_AEN_MIN + BFA_AEN_CAT_ADAPTER,/* 1 */ - BFA_LOG_AEN_ID_PORT = BFA_LOG_AEN_MIN + BFA_AEN_CAT_PORT, /* 2 */ - BFA_LOG_AEN_ID_LPORT = BFA_LOG_AEN_MIN + BFA_AEN_CAT_LPORT, /* 3 */ - BFA_LOG_AEN_ID_RPORT = BFA_LOG_AEN_MIN + BFA_AEN_CAT_RPORT, /* 4 */ - BFA_LOG_AEN_ID_ITNIM = BFA_LOG_AEN_MIN + BFA_AEN_CAT_ITNIM, /* 5 */ - BFA_LOG_AEN_ID_TIN = BFA_LOG_AEN_MIN + BFA_AEN_CAT_TIN, /* 6 */ - BFA_LOG_AEN_ID_IPFC = BFA_LOG_AEN_MIN + BFA_AEN_CAT_IPFC, /* 7 */ - BFA_LOG_AEN_ID_AUDIT = BFA_LOG_AEN_MIN + BFA_AEN_CAT_AUDIT, /* 8 */ - BFA_LOG_AEN_ID_IOC = BFA_LOG_AEN_MIN + BFA_AEN_CAT_IOC, /* 9 */ - BFA_LOG_AEN_ID_ETHPORT = BFA_LOG_AEN_MIN + BFA_AEN_CAT_ETHPORT,/* 10 */ - - BFA_LOG_AEN_MAX = BFA_LOG_AEN_ID_ETHPORT, - /* AEN defs end */ - - BFA_LOG_MODULE_ID_MIN = BFA_LOG_AEN_MAX, - - BFA_LOG_FW_ID = BFA_LOG_MODULE_ID_MIN + 1, - BFA_LOG_HAL_ID = BFA_LOG_MODULE_ID_MIN + 2, - BFA_LOG_FCS_ID = BFA_LOG_MODULE_ID_MIN + 3, - BFA_LOG_WDRV_ID = BFA_LOG_MODULE_ID_MIN + 4, - BFA_LOG_LINUX_ID = BFA_LOG_MODULE_ID_MIN + 5, - BFA_LOG_SOLARIS_ID = BFA_LOG_MODULE_ID_MIN + 6, - - BFA_LOG_MODULE_ID_MAX = BFA_LOG_SOLARIS_ID, - - /* Not part of any arrays */ - BFA_LOG_MODULE_ID_ALL = BFA_LOG_MODULE_ID_MAX + 1, - BFA_LOG_AEN_ALL = BFA_LOG_MODULE_ID_MAX + 2, - BFA_LOG_DRV_ALL = BFA_LOG_MODULE_ID_MAX + 3, -}; - -/* - * BFA log catalog name - */ -#define BFA_LOG_CAT_NAME "BFA" - -/* - * bfa log severity values - */ -enum bfa_log_severity { - BFA_LOG_INVALID = 0, - BFA_LOG_CRITICAL = 1, - BFA_LOG_ERROR = 2, - BFA_LOG_WARNING = 3, - BFA_LOG_INFO = 4, - BFA_LOG_NONE = 5, - BFA_LOG_LEVEL_MAX = BFA_LOG_NONE -}; - -#define BFA_LOG_MODID_OFFSET 16 - - -struct bfa_log_msgdef_s { - u32 msg_id; /* message id */ - int attributes; /* attributes */ - int severity; /* severity level */ - char *msg_value; - /* msg string */ - char *message; - /* msg format string */ - int arg_type; /* argument type */ - int arg_num; /* number of argument */ -}; - -/* - * supported argument type - */ -enum bfa_log_arg_type { - BFA_LOG_S = 0, /* string */ - BFA_LOG_D, /* decimal */ - BFA_LOG_I, /* integer */ - BFA_LOG_O, /* oct number */ - BFA_LOG_U, /* unsigned integer */ - BFA_LOG_X, /* hex number */ - BFA_LOG_F, /* floating */ - BFA_LOG_C, /* character */ - BFA_LOG_L, /* double */ - BFA_LOG_P /* pointer */ -}; - -#define BFA_LOG_ARG_TYPE 2 -#define BFA_LOG_ARG0 (0 * BFA_LOG_ARG_TYPE) -#define BFA_LOG_ARG1 (1 * BFA_LOG_ARG_TYPE) -#define BFA_LOG_ARG2 (2 * BFA_LOG_ARG_TYPE) -#define BFA_LOG_ARG3 (3 * BFA_LOG_ARG_TYPE) - -#define BFA_LOG_GET_MOD_ID(msgid) ((msgid >> BFA_LOG_MODID_OFFSET) & 0xff) -#define BFA_LOG_GET_MSG_IDX(msgid) (msgid & 0xffff) -#define BFA_LOG_GET_MSG_ID(msgdef) ((msgdef)->msg_id) -#define BFA_LOG_GET_MSG_FMT_STRING(msgdef) ((msgdef)->message) -#define BFA_LOG_GET_SEVERITY(msgdef) ((msgdef)->severity) - -/* - * Event attributes - */ -#define BFA_LOG_ATTR_NONE 0 -#define BFA_LOG_ATTR_AUDIT 1 -#define BFA_LOG_ATTR_LOG 2 -#define BFA_LOG_ATTR_FFDC 4 - -#define BFA_LOG_CREATE_ID(msw, lsw) \ - (((u32)msw << BFA_LOG_MODID_OFFSET) | lsw) - -struct bfa_log_mod_s; - -/** - * callback function - */ -typedef void (*bfa_log_cb_t)(struct bfa_log_mod_s *log_mod, u32 msg_id, - const char *format, ...); - - -struct bfa_log_mod_s { - char instance_info[BFA_STRING_32]; /* instance info */ - int log_level[BFA_LOG_MODULE_ID_MAX + 1]; - /* log level for modules */ - bfa_log_cb_t cbfn; /* callback function */ -}; - -extern int bfa_log_init(struct bfa_log_mod_s *log_mod, - char *instance_name, bfa_log_cb_t cbfn); -extern int bfa_log(struct bfa_log_mod_s *log_mod, u32 msg_id, ...); -extern bfa_status_t bfa_log_set_level(struct bfa_log_mod_s *log_mod, - int mod_id, enum bfa_log_severity log_level); -extern bfa_status_t bfa_log_set_level_all(struct bfa_log_mod_s *log_mod, - enum bfa_log_severity log_level); -extern bfa_status_t bfa_log_set_level_aen(struct bfa_log_mod_s *log_mod, - enum bfa_log_severity log_level); -extern enum bfa_log_severity bfa_log_get_level(struct bfa_log_mod_s *log_mod, - int mod_id); -extern enum bfa_log_severity bfa_log_get_msg_level( - struct bfa_log_mod_s *log_mod, u32 msg_id); -/* - * array of messages generated from xml files - */ -extern struct bfa_log_msgdef_s bfa_log_msg_array[]; - -#endif diff --git a/drivers/scsi/bfa/include/cs/bfa_perf.h b/drivers/scsi/bfa/include/cs/bfa_perf.h deleted file mode 100644 index 45aa5f978ff5..000000000000 --- a/drivers/scsi/bfa/include/cs/bfa_perf.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ -#ifndef __BFAD_PERF_H__ -#define __BFAD_PERF_H__ - -#ifdef BFAD_PERF_BUILD - -#undef bfa_trc -#undef bfa_trc32 -#undef bfa_assert -#undef BFA_TRC_FILE - -#define bfa_trc(_trcp, _data) -#define bfa_trc32(_trcp, _data) -#define bfa_assert(__cond) -#define BFA_TRC_FILE(__mod, __submod) - -#endif - -#endif /* __BFAD_PERF_H__ */ diff --git a/drivers/scsi/bfa/include/cs/bfa_q.h b/drivers/scsi/bfa/include/cs/bfa_q.h deleted file mode 100644 index ea895facedbc..000000000000 --- a/drivers/scsi/bfa/include/cs/bfa_q.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/** - * bfa_q.h Circular queue definitions. - */ - -#ifndef __BFA_Q_H__ -#define __BFA_Q_H__ - -#define bfa_q_first(_q) ((void *)(((struct list_head *) (_q))->next)) -#define bfa_q_next(_qe) (((struct list_head *) (_qe))->next) -#define bfa_q_prev(_qe) (((struct list_head *) (_qe))->prev) - -/* - * bfa_q_qe_init - to initialize a queue element - */ -#define bfa_q_qe_init(_qe) { \ - bfa_q_next(_qe) = (struct list_head *) NULL; \ - bfa_q_prev(_qe) = (struct list_head *) NULL; \ -} - -/* - * bfa_q_deq - dequeue an element from head of the queue - */ -#define bfa_q_deq(_q, _qe) { \ - if (!list_empty(_q)) { \ - (*((struct list_head **) (_qe))) = bfa_q_next(_q); \ - bfa_q_prev(bfa_q_next(*((struct list_head **) _qe))) = \ - (struct list_head *) (_q); \ - bfa_q_next(_q) = bfa_q_next(*((struct list_head **) _qe)); \ - BFA_Q_DBG_INIT(*((struct list_head **) _qe)); \ - } else { \ - *((struct list_head **) (_qe)) = (struct list_head *) NULL; \ - } \ -} - -/* - * bfa_q_deq_tail - dequeue an element from tail of the queue - */ -#define bfa_q_deq_tail(_q, _qe) { \ - if (!list_empty(_q)) { \ - *((struct list_head **) (_qe)) = bfa_q_prev(_q); \ - bfa_q_next(bfa_q_prev(*((struct list_head **) _qe))) = \ - (struct list_head *) (_q); \ - bfa_q_prev(_q) = bfa_q_prev(*(struct list_head **) _qe); \ - BFA_Q_DBG_INIT(*((struct list_head **) _qe)); \ - } else { \ - *((struct list_head **) (_qe)) = (struct list_head *) NULL; \ - } \ -} - -/* - * #ifdef BFA_DEBUG (Using bfa_assert to check for debug_build is not - * consistent across modules) - */ -#ifndef BFA_PERF_BUILD -#define BFA_Q_DBG_INIT(_qe) bfa_q_qe_init(_qe) -#else -#define BFA_Q_DBG_INIT(_qe) -#endif - -#define bfa_q_is_on_q(_q, _qe) \ - bfa_q_is_on_q_func(_q, (struct list_head *)(_qe)) -extern int bfa_q_is_on_q_func(struct list_head *q, struct list_head *qe); - -#endif diff --git a/drivers/scsi/bfa/include/cs/bfa_sm.h b/drivers/scsi/bfa/include/cs/bfa_sm.h deleted file mode 100644 index 11fba9082f05..000000000000 --- a/drivers/scsi/bfa/include/cs/bfa_sm.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/** - * bfasm.h State machine defines - */ - -#ifndef __BFA_SM_H__ -#define __BFA_SM_H__ - -typedef void (*bfa_sm_t)(void *sm, int event); -/** - * oc - object class eg. bfa_ioc - * st - state, eg. reset - * otype - object type, eg. struct bfa_ioc_s - * etype - object type, eg. enum ioc_event - */ -#define bfa_sm_state_decl(oc, st, otype, etype) \ - static void oc ## _sm_ ## st(otype * fsm, etype event) - -#define bfa_sm_set_state(_sm, _state) ((_sm)->sm = (bfa_sm_t)(_state)) -#define bfa_sm_send_event(_sm, _event) ((_sm)->sm((_sm), (_event))) -#define bfa_sm_get_state(_sm) ((_sm)->sm) -#define bfa_sm_cmp_state(_sm, _state) ((_sm)->sm == (bfa_sm_t)(_state)) - -/** - * For converting from state machine function to state encoding. - */ -struct bfa_sm_table_s { - bfa_sm_t sm; /* state machine function */ - int state; /* state machine encoding */ - char *name; /* state name for display */ -}; -#define BFA_SM(_sm) ((bfa_sm_t)(_sm)) - -int bfa_sm_to_state(struct bfa_sm_table_s *smt, bfa_sm_t sm); - -/** - * State machine with entry actions. - */ -typedef void (*bfa_fsm_t)(void *fsm, int event); - -/** - * oc - object class eg. bfa_ioc - * st - state, eg. reset - * otype - object type, eg. struct bfa_ioc_s - * etype - object type, eg. enum ioc_event - */ -#define bfa_fsm_state_decl(oc, st, otype, etype) \ - static void oc ## _sm_ ## st(otype * fsm, etype event); \ - static void oc ## _sm_ ## st ## _entry(otype * fsm) - -#define bfa_fsm_set_state(_fsm, _state) do { \ - (_fsm)->fsm = (bfa_fsm_t)(_state); \ - _state ## _entry(_fsm); \ -} while (0) - -#define bfa_fsm_send_event(_fsm, _event) \ - ((_fsm)->fsm((_fsm), (_event))) -#define bfa_fsm_cmp_state(_fsm, _state) \ - ((_fsm)->fsm == (bfa_fsm_t)(_state)) - -#endif diff --git a/drivers/scsi/bfa/include/cs/bfa_trc.h b/drivers/scsi/bfa/include/cs/bfa_trc.h deleted file mode 100644 index 310771c888e7..000000000000 --- a/drivers/scsi/bfa/include/cs/bfa_trc.h +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ -#ifndef __BFA_TRC_H__ -#define __BFA_TRC_H__ - -#include <bfa_os_inc.h> - -#ifndef BFA_TRC_MAX -#define BFA_TRC_MAX (4 * 1024) -#endif - -#ifndef BFA_TRC_TS -#define BFA_TRC_TS(_trcm) ((_trcm)->ticks++) -#endif - -struct bfa_trc_s { -#ifdef __BIGENDIAN - u16 fileno; - u16 line; -#else - u16 line; - u16 fileno; -#endif - u32 timestamp; - union { - struct { - u32 rsvd; - u32 u32; - } u32; - u64 u64; - } data; -}; - - -struct bfa_trc_mod_s { - u32 head; - u32 tail; - u32 ntrc; - u32 stopped; - u32 ticks; - u32 rsvd[3]; - struct bfa_trc_s trc[BFA_TRC_MAX]; -}; - - -enum { - BFA_TRC_FW = 1, /* firmware modules */ - BFA_TRC_HAL = 2, /* BFA modules */ - BFA_TRC_FCS = 3, /* BFA FCS modules */ - BFA_TRC_LDRV = 4, /* Linux driver modules */ - BFA_TRC_SDRV = 5, /* Solaris driver modules */ - BFA_TRC_VDRV = 6, /* vmware driver modules */ - BFA_TRC_WDRV = 7, /* windows driver modules */ - BFA_TRC_AEN = 8, /* AEN module */ - BFA_TRC_BIOS = 9, /* bios driver modules */ - BFA_TRC_EFI = 10, /* EFI driver modules */ - BNA_TRC_WDRV = 11, /* BNA windows driver modules */ - BNA_TRC_VDRV = 12, /* BNA vmware driver modules */ - BNA_TRC_SDRV = 13, /* BNA Solaris driver modules */ - BNA_TRC_LDRV = 14, /* BNA Linux driver modules */ - BNA_TRC_HAL = 15, /* BNA modules */ - BFA_TRC_CNA = 16, /* Common modules */ - BNA_TRC_IMDRV = 17 /* BNA windows intermediate driver modules */ -}; -#define BFA_TRC_MOD_SH 10 -#define BFA_TRC_MOD(__mod) ((BFA_TRC_ ## __mod) << BFA_TRC_MOD_SH) - -/** - * Define a new tracing file (module). Module should match one defined above. - */ -#define BFA_TRC_FILE(__mod, __submod) \ - static int __trc_fileno = ((BFA_TRC_ ## __mod ## _ ## __submod) | \ - BFA_TRC_MOD(__mod)) - - -#define bfa_trc32(_trcp, _data) \ - __bfa_trc((_trcp)->trcmod, __trc_fileno, __LINE__, (u32)_data) - - -#ifndef BFA_BOOT_BUILD -#define bfa_trc(_trcp, _data) \ - __bfa_trc((_trcp)->trcmod, __trc_fileno, __LINE__, (u64)_data) -#else -void bfa_boot_trc(struct bfa_trc_mod_s *trcmod, u16 fileno, - u16 line, u32 data); -#define bfa_trc(_trcp, _data) \ - bfa_boot_trc((_trcp)->trcmod, __trc_fileno, __LINE__, (u32)_data) -#endif - - -static inline void -bfa_trc_init(struct bfa_trc_mod_s *trcm) -{ - trcm->head = trcm->tail = trcm->stopped = 0; - trcm->ntrc = BFA_TRC_MAX; -} - - -static inline void -bfa_trc_stop(struct bfa_trc_mod_s *trcm) -{ - trcm->stopped = 1; -} - -#ifdef FWTRC -extern void dc_flush(void *data); -#else -#define dc_flush(data) -#endif - - -static inline void -__bfa_trc(struct bfa_trc_mod_s *trcm, int fileno, int line, u64 data) -{ - int tail = trcm->tail; - struct bfa_trc_s *trc = &trcm->trc[tail]; - - if (trcm->stopped) - return; - - trc->fileno = (u16) fileno; - trc->line = (u16) line; - trc->data.u64 = data; - trc->timestamp = BFA_TRC_TS(trcm); - dc_flush(trc); - - trcm->tail = (trcm->tail + 1) & (BFA_TRC_MAX - 1); - if (trcm->tail == trcm->head) - trcm->head = (trcm->head + 1) & (BFA_TRC_MAX - 1); - dc_flush(trcm); -} - - -static inline void -__bfa_trc32(struct bfa_trc_mod_s *trcm, int fileno, int line, u32 data) -{ - int tail = trcm->tail; - struct bfa_trc_s *trc = &trcm->trc[tail]; - - if (trcm->stopped) - return; - - trc->fileno = (u16) fileno; - trc->line = (u16) line; - trc->data.u32.u32 = data; - trc->timestamp = BFA_TRC_TS(trcm); - dc_flush(trc); - - trcm->tail = (trcm->tail + 1) & (BFA_TRC_MAX - 1); - if (trcm->tail == trcm->head) - trcm->head = (trcm->head + 1) & (BFA_TRC_MAX - 1); - dc_flush(trcm); -} - -#ifndef BFA_PERF_BUILD -#define bfa_trc_fp(_trcp, _data) bfa_trc(_trcp, _data) -#else -#define bfa_trc_fp(_trcp, _data) -#endif - -#endif /* __BFA_TRC_H__ */ - diff --git a/drivers/scsi/bfa/include/cs/bfa_wc.h b/drivers/scsi/bfa/include/cs/bfa_wc.h deleted file mode 100644 index 0460bd4fc7c4..000000000000 --- a/drivers/scsi/bfa/include/cs/bfa_wc.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/** - * bfa_wc.h Generic wait counter. - */ - -#ifndef __BFA_WC_H__ -#define __BFA_WC_H__ - -typedef void (*bfa_wc_resume_t) (void *cbarg); - -struct bfa_wc_s { - bfa_wc_resume_t wc_resume; - void *wc_cbarg; - int wc_count; -}; - -static inline void -bfa_wc_up(struct bfa_wc_s *wc) -{ - wc->wc_count++; -} - -static inline void -bfa_wc_down(struct bfa_wc_s *wc) -{ - wc->wc_count--; - if (wc->wc_count == 0) - wc->wc_resume(wc->wc_cbarg); -} - -/** - * Initialize a waiting counter. - */ -static inline void -bfa_wc_init(struct bfa_wc_s *wc, bfa_wc_resume_t wc_resume, void *wc_cbarg) -{ - wc->wc_resume = wc_resume; - wc->wc_cbarg = wc_cbarg; - wc->wc_count = 0; - bfa_wc_up(wc); -} - -/** - * Wait for counter to reach zero - */ -static inline void -bfa_wc_wait(struct bfa_wc_s *wc) -{ - bfa_wc_down(wc); -} - -#endif diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_adapter.h b/drivers/scsi/bfa/include/defs/bfa_defs_adapter.h deleted file mode 100644 index aea0360d67d5..000000000000 --- a/drivers/scsi/bfa/include/defs/bfa_defs_adapter.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ -#ifndef __BFA_DEFS_ADAPTER_H__ -#define __BFA_DEFS_ADAPTER_H__ - -#include <protocol/types.h> -#include <defs/bfa_defs_version.h> -#include <defs/bfa_defs_mfg.h> - -/** - * BFA adapter level attributes. - */ -enum { - BFA_ADAPTER_SERIAL_NUM_LEN = STRSZ(BFA_MFG_SERIALNUM_SIZE), - /* - *!< adapter serial num length - */ - BFA_ADAPTER_MODEL_NAME_LEN = 16, /* model name length */ - BFA_ADAPTER_MODEL_DESCR_LEN = 128, /* model description length */ - BFA_ADAPTER_MFG_NAME_LEN = 8, /* manufacturer name length */ - BFA_ADAPTER_SYM_NAME_LEN = 64, /* adapter symbolic name length */ - BFA_ADAPTER_OS_TYPE_LEN = 64, /* adapter os type length */ -}; - -struct bfa_adapter_attr_s { - char manufacturer[BFA_ADAPTER_MFG_NAME_LEN]; - char serial_num[BFA_ADAPTER_SERIAL_NUM_LEN]; - u32 card_type; - char model[BFA_ADAPTER_MODEL_NAME_LEN]; - char model_descr[BFA_ADAPTER_MODEL_DESCR_LEN]; - wwn_t pwwn; - char node_symname[FC_SYMNAME_MAX]; - char hw_ver[BFA_VERSION_LEN]; - char fw_ver[BFA_VERSION_LEN]; - char optrom_ver[BFA_VERSION_LEN]; - char os_type[BFA_ADAPTER_OS_TYPE_LEN]; - struct bfa_mfg_vpd_s vpd; - struct mac_s mac; - - u8 nports; - u8 max_speed; - u8 prototype; - char asic_rev; - - u8 pcie_gen; - u8 pcie_lanes_orig; - u8 pcie_lanes; - u8 cna_capable; - u8 is_mezz; -}; - -/** - * BFA adapter level events - * Arguments below are in BFAL context from Mgmt - * BFA_PORT_AEN_ADD: [in]: None [out]: serial_num, pwwn, nports - * BFA_PORT_AEN_REMOVE: [in]: pwwn [out]: serial_num, pwwn, nports - */ -enum bfa_adapter_aen_event { - BFA_ADAPTER_AEN_ADD = 1, /* New Adapter found event */ - BFA_ADAPTER_AEN_REMOVE = 2, /* Adapter removed event */ -}; - -struct bfa_adapter_aen_data_s { - char serial_num[BFA_ADAPTER_SERIAL_NUM_LEN]; - u32 nports; /* Number of NPorts */ - wwn_t pwwn; /* WWN of one of its physical port */ -}; - -#endif /* __BFA_DEFS_ADAPTER_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_aen.h b/drivers/scsi/bfa/include/defs/bfa_defs_aen.h deleted file mode 100644 index 35244698fcdc..000000000000 --- a/drivers/scsi/bfa/include/defs/bfa_defs_aen.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFA_DEFS_AEN_H__ -#define __BFA_DEFS_AEN_H__ - -#include <defs/bfa_defs_types.h> -#include <defs/bfa_defs_ioc.h> -#include <defs/bfa_defs_adapter.h> -#include <defs/bfa_defs_port.h> -#include <defs/bfa_defs_lport.h> -#include <defs/bfa_defs_rport.h> -#include <defs/bfa_defs_itnim.h> -#include <defs/bfa_defs_tin.h> -#include <defs/bfa_defs_ipfc.h> -#include <defs/bfa_defs_audit.h> -#include <defs/bfa_defs_ethport.h> - -#define BFA_AEN_MAX_APP 5 - -enum bfa_aen_app { - bfa_aen_app_bcu = 0, /* No thread for bcu */ - bfa_aen_app_hcm = 1, - bfa_aen_app_cim = 2, - bfa_aen_app_snia = 3, - bfa_aen_app_test = 4, /* To be removed after unit test */ -}; - -enum bfa_aen_category { - BFA_AEN_CAT_ADAPTER = 1, - BFA_AEN_CAT_PORT = 2, - BFA_AEN_CAT_LPORT = 3, - BFA_AEN_CAT_RPORT = 4, - BFA_AEN_CAT_ITNIM = 5, - BFA_AEN_CAT_TIN = 6, - BFA_AEN_CAT_IPFC = 7, - BFA_AEN_CAT_AUDIT = 8, - BFA_AEN_CAT_IOC = 9, - BFA_AEN_CAT_ETHPORT = 10, - BFA_AEN_MAX_CAT = 10 -}; - -#pragma pack(1) -union bfa_aen_data_u { - struct bfa_adapter_aen_data_s adapter; - struct bfa_port_aen_data_s port; - struct bfa_lport_aen_data_s lport; - struct bfa_rport_aen_data_s rport; - struct bfa_itnim_aen_data_s itnim; - struct bfa_audit_aen_data_s audit; - struct bfa_ioc_aen_data_s ioc; - struct bfa_ethport_aen_data_s ethport; -}; - -struct bfa_aen_entry_s { - enum bfa_aen_category aen_category; - int aen_type; - union bfa_aen_data_u aen_data; - struct bfa_timeval_s aen_tv; - s32 seq_num; - s32 bfad_num; - s32 rsvd[1]; -}; - -#pragma pack() - -#define bfa_aen_event_t int - -#endif /* __BFA_DEFS_AEN_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_audit.h b/drivers/scsi/bfa/include/defs/bfa_defs_audit.h deleted file mode 100644 index 8e3a962bf20c..000000000000 --- a/drivers/scsi/bfa/include/defs/bfa_defs_audit.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFA_DEFS_AUDIT_H__ -#define __BFA_DEFS_AUDIT_H__ - -#include <bfa_os_inc.h> - -/** - * BFA audit events - */ -enum bfa_audit_aen_event { - BFA_AUDIT_AEN_AUTH_ENABLE = 1, - BFA_AUDIT_AEN_AUTH_DISABLE = 2, -}; - -/** - * audit event data - */ -struct bfa_audit_aen_data_s { - wwn_t pwwn; -}; - -#endif /* __BFA_DEFS_AUDIT_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_auth.h b/drivers/scsi/bfa/include/defs/bfa_defs_auth.h deleted file mode 100644 index f56ed871bb99..000000000000 --- a/drivers/scsi/bfa/include/defs/bfa_defs_auth.h +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ -#ifndef __BFA_DEFS_AUTH_H__ -#define __BFA_DEFS_AUTH_H__ - -#include <defs/bfa_defs_types.h> - -#define PUBLIC_KEY 15409 -#define PRIVATE_KEY 19009 -#define KEY_LEN 32399 -#define BFA_AUTH_SECRET_STRING_LEN 256 -#define BFA_AUTH_FAIL_NO_PASSWORD 0xFE -#define BFA_AUTH_FAIL_TIMEOUT 0xFF - -/** - * Authentication status - */ -enum bfa_auth_status { - BFA_AUTH_STATUS_NONE = 0, /* no authentication */ - BFA_AUTH_UNINIT = 1, /* state - uninit */ - BFA_AUTH_NEG_SEND = 2, /* state - negotiate send */ - BFA_AUTH_CHAL_WAIT = 3, /* state - challenge wait */ - BFA_AUTH_NEG_RETRY = 4, /* state - negotiate retry */ - BFA_AUTH_REPLY_SEND = 5, /* state - reply send */ - BFA_AUTH_STATUS_WAIT = 6, /* state - status wait */ - BFA_AUTH_SUCCESS = 7, /* state - success */ - BFA_AUTH_FAILED = 8, /* state - failed */ - BFA_AUTH_STATUS_UNKNOWN = 9, /* authentication status unknown */ -}; - -enum bfa_auth_rej_code { - BFA_AUTH_RJT_CODE_AUTH_FAILURE = 1, /* auth failure */ - BFA_AUTH_RJT_CODE_LOGICAL_ERR = 2, /* logical error */ -}; - -/** - * Authentication reject codes - */ -enum bfa_auth_rej_code_exp { - BFA_AUTH_MECH_NOT_USABLE = 1, /* auth. mechanism not usable */ - BFA_AUTH_DH_GROUP_NOT_USABLE = 2, /* DH Group not usable */ - BFA_AUTH_HASH_FUNC_NOT_USABLE = 3, /* hash Function not usable */ - BFA_AUTH_AUTH_XACT_STARTED = 4, /* auth xact started */ - BFA_AUTH_AUTH_FAILED = 5, /* auth failed */ - BFA_AUTH_INCORRECT_PLD = 6, /* incorrect payload */ - BFA_AUTH_INCORRECT_PROTO_MSG = 7, /* incorrect proto msg */ - BFA_AUTH_RESTART_AUTH_PROTO = 8, /* restart auth protocol */ - BFA_AUTH_AUTH_CONCAT_NOT_SUPP = 9, /* auth concat not supported */ - BFA_AUTH_PROTO_VER_NOT_SUPP = 10,/* proto version not supported */ -}; - -struct auth_proto_stats_s { - u32 auth_rjts; - u32 auth_negs; - u32 auth_dones; - - u32 dhchap_challenges; - u32 dhchap_replies; - u32 dhchap_successes; -}; - -/** - * Authentication related statistics - */ -struct bfa_auth_stats_s { - u32 auth_failures; /* authentication failures */ - u32 auth_successes; /* authentication successes*/ - struct auth_proto_stats_s auth_rx_stats; /* Rx protocol stats */ - struct auth_proto_stats_s auth_tx_stats; /* Tx protocol stats */ -}; - -/** - * Authentication hash function algorithms - */ -enum bfa_auth_algo { - BFA_AUTH_ALGO_MD5 = 1, /* Message-Digest algorithm 5 */ - BFA_AUTH_ALGO_SHA1 = 2, /* Secure Hash Algorithm 1 */ - BFA_AUTH_ALGO_MS = 3, /* MD5, then SHA-1 */ - BFA_AUTH_ALGO_SM = 4, /* SHA-1, then MD5 */ -}; - -/** - * DH Groups - * - * Current value could be combination of one or more of the following values - */ -enum bfa_auth_group { - BFA_AUTH_GROUP_DHNULL = 0, /* DH NULL (value == 0) */ - BFA_AUTH_GROUP_DH768 = 1, /* DH group 768 (value == 1) */ - BFA_AUTH_GROUP_DH1024 = 2, /* DH group 1024 (value == 2) */ - BFA_AUTH_GROUP_DH1280 = 4, /* DH group 1280 (value == 3) */ - BFA_AUTH_GROUP_DH1536 = 8, /* DH group 1536 (value == 4) */ - - BFA_AUTH_GROUP_ALL = 256 /* Use default DH group order - * 0, 1, 2, 3, 4 */ -}; - -/** - * Authentication secret sources - */ -enum bfa_auth_secretsource { - BFA_AUTH_SECSRC_LOCAL = 1, /* locally configured */ - BFA_AUTH_SECSRC_RADIUS = 2, /* use radius server */ - BFA_AUTH_SECSRC_TACACS = 3, /* TACACS server */ -}; - -/** - * Authentication attributes - */ -struct bfa_auth_attr_s { - enum bfa_auth_status status; - enum bfa_auth_algo algo; - enum bfa_auth_group dh_grp; - enum bfa_auth_rej_code rjt_code; - enum bfa_auth_rej_code_exp rjt_code_exp; - u8 secret_set; - u8 resv[3]; -}; - -#endif /* __BFA_DEFS_AUTH_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_boot.h b/drivers/scsi/bfa/include/defs/bfa_defs_boot.h deleted file mode 100644 index 0fca10b6ad10..000000000000 --- a/drivers/scsi/bfa/include/defs/bfa_defs_boot.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFA_DEFS_BOOT_H__ -#define __BFA_DEFS_BOOT_H__ - -#include <protocol/types.h> -#include <defs/bfa_defs_types.h> -#include <defs/bfa_defs_pport.h> - -enum { - BFA_BOOT_BOOTLUN_MAX = 4, /* maximum boot lun per IOC */ - BFA_PREBOOT_BOOTLUN_MAX = 8, /* maximum preboot lun per IOC */ - -}; - -#define BOOT_CFG_REV1 1 - -/** - * Boot options setting. Boot options setting determines from where - * to get the boot lun information - */ -enum bfa_boot_bootopt { - BFA_BOOT_AUTO_DISCOVER = 0, /* Boot from blun provided by fabric */ - BFA_BOOT_STORED_BLUN = 1, /* Boot from bluns stored in flash */ - BFA_BOOT_FIRST_LUN = 2, /* Boot from first discovered blun */ -}; - -/** - * Boot lun information. - */ -struct bfa_boot_bootlun_s { - wwn_t pwwn; /* port wwn of target */ - lun_t lun; /* 64-bit lun */ -}; - -/** - * BOOT boot configuraton - */ -struct bfa_boot_cfg_s { - u8 version; - u8 rsvd1; - u16 chksum; - - u8 enable; /* enable/disable SAN boot */ - u8 speed; /* boot speed settings */ - u8 topology; /* boot topology setting */ - u8 bootopt; /* bfa_boot_bootopt_t */ - - u32 nbluns; /* number of boot luns */ - - u32 rsvd2; - - struct bfa_boot_bootlun_s blun[BFA_BOOT_BOOTLUN_MAX]; - struct bfa_boot_bootlun_s blun_disc[BFA_BOOT_BOOTLUN_MAX]; -}; - -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_cee.h b/drivers/scsi/bfa/include/defs/bfa_defs_cee.h deleted file mode 100644 index 6eaf519eccdc..000000000000 --- a/drivers/scsi/bfa/include/defs/bfa_defs_cee.h +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * bfa_defs_cee.h Interface declarations between host based - * BFAL and DCBX/LLDP module in Firmware - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ -#ifndef __BFA_DEFS_CEE_H__ -#define __BFA_DEFS_CEE_H__ - -#include <defs/bfa_defs_types.h> -#include <defs/bfa_defs_pport.h> -#include <protocol/types.h> - -#pragma pack(1) - -#define BFA_CEE_LLDP_MAX_STRING_LEN (128) - -#define BFA_CEE_LLDP_SYS_CAP_OTHER 0x0001 -#define BFA_CEE_LLDP_SYS_CAP_REPEATER 0x0002 -#define BFA_CEE_LLDP_SYS_CAP_MAC_BRIDGE 0x0004 -#define BFA_CEE_LLDP_SYS_CAP_WLAN_AP 0x0008 -#define BFA_CEE_LLDP_SYS_CAP_ROUTER 0x0010 -#define BFA_CEE_LLDP_SYS_CAP_TELEPHONE 0x0020 -#define BFA_CEE_LLDP_SYS_CAP_DOCSIS_CD 0x0040 -#define BFA_CEE_LLDP_SYS_CAP_STATION 0x0080 -#define BFA_CEE_LLDP_SYS_CAP_CVLAN 0x0100 -#define BFA_CEE_LLDP_SYS_CAP_SVLAN 0x0200 -#define BFA_CEE_LLDP_SYS_CAP_TPMR 0x0400 - - -/* LLDP string type */ -struct bfa_cee_lldp_str_s { - u8 sub_type; - u8 len; - u8 rsvd[2]; - u8 value[BFA_CEE_LLDP_MAX_STRING_LEN]; -}; - - -/* LLDP parameters */ -struct bfa_cee_lldp_cfg_s { - struct bfa_cee_lldp_str_s chassis_id; - struct bfa_cee_lldp_str_s port_id; - struct bfa_cee_lldp_str_s port_desc; - struct bfa_cee_lldp_str_s sys_name; - struct bfa_cee_lldp_str_s sys_desc; - struct bfa_cee_lldp_str_s mgmt_addr; - u16 time_to_interval; - u16 enabled_system_cap; -}; - -enum bfa_cee_dcbx_version_e { - DCBX_PROTOCOL_PRECEE = 1, - DCBX_PROTOCOL_CEE = 2, -}; - -enum bfa_cee_lls_e { - CEE_LLS_DOWN_NO_TLV = 0, /* LLS is down because the TLV not sent by - * the peer */ - CEE_LLS_DOWN = 1, /* LLS is down as advertised by the peer */ - CEE_LLS_UP = 2, -}; - -/* CEE/DCBX parameters */ -struct bfa_cee_dcbx_cfg_s { - u8 pgid[8]; - u8 pg_percentage[8]; - u8 pfc_enabled; /* bitmap of priorties with PFC enabled */ - u8 fcoe_user_priority; /* bitmap of priorities used for FcoE - * traffic */ - u8 dcbx_version; /* operating version:CEE or preCEE */ - u8 lls_fcoe; /* FCoE Logical Link Status */ - u8 lls_lan; /* LAN Logical Link Status */ - u8 rsvd[3]; -}; - -/* CEE status */ -/* Making this to tri-state for the benefit of port list command */ -enum bfa_cee_status_e { - CEE_UP = 0, - CEE_PHY_UP = 1, - CEE_LOOPBACK = 2, - CEE_PHY_DOWN = 3, -}; - -/* CEE Query */ -struct bfa_cee_attr_s { - u8 cee_status; - u8 error_reason; - struct bfa_cee_lldp_cfg_s lldp_remote; - struct bfa_cee_dcbx_cfg_s dcbx_remote; - mac_t src_mac; - u8 link_speed; - u8 nw_priority; - u8 filler[2]; -}; - - - - -/* LLDP/DCBX/CEE Statistics */ - -struct bfa_cee_lldp_stats_s { - u32 frames_transmitted; - u32 frames_aged_out; - u32 frames_discarded; - u32 frames_in_error; - u32 frames_rcvd; - u32 tlvs_discarded; - u32 tlvs_unrecognized; -}; - -struct bfa_cee_dcbx_stats_s { - u32 subtlvs_unrecognized; - u32 negotiation_failed; - u32 remote_cfg_changed; - u32 tlvs_received; - u32 tlvs_invalid; - u32 seqno; - u32 ackno; - u32 recvd_seqno; - u32 recvd_ackno; -}; - -struct bfa_cee_cfg_stats_s { - u32 cee_status_down; - u32 cee_status_up; - u32 cee_hw_cfg_changed; - u32 recvd_invalid_cfg; -}; - - -struct bfa_cee_stats_s { - struct bfa_cee_lldp_stats_s lldp_stats; - struct bfa_cee_dcbx_stats_s dcbx_stats; - struct bfa_cee_cfg_stats_s cfg_stats; -}; - -#pragma pack() - - -#endif /* __BFA_DEFS_CEE_H__ */ - - diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_driver.h b/drivers/scsi/bfa/include/defs/bfa_defs_driver.h deleted file mode 100644 index 7d00d00d3969..000000000000 --- a/drivers/scsi/bfa/include/defs/bfa_defs_driver.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFA_DEFS_DRIVER_H__ -#define __BFA_DEFS_DRIVER_H__ - -/** - * Driver statistics - */ -struct bfa_driver_stats_s { - u16 tm_io_abort; - u16 tm_io_abort_comp; - u16 tm_lun_reset; - u16 tm_lun_reset_comp; - u16 tm_target_reset; - u16 tm_bus_reset; - u16 ioc_restart; /* IOC restart count */ - u16 rsvd; - u64 control_req; - u64 input_req; - u64 output_req; - u64 input_words; - u64 output_words; -}; - - -#endif /* __BFA_DEFS_DRIVER_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_ethport.h b/drivers/scsi/bfa/include/defs/bfa_defs_ethport.h deleted file mode 100644 index b4fa0923aa89..000000000000 --- a/drivers/scsi/bfa/include/defs/bfa_defs_ethport.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFA_DEFS_ETHPORT_H__ -#define __BFA_DEFS_ETHPORT_H__ - -#include <defs/bfa_defs_status.h> -#include <defs/bfa_defs_port.h> -#include <protocol/types.h> -#include <cna/pstats/phyport_defs.h> -#include <cna/pstats/ethport_defs.h> - -struct bna_tx_info_s { - u32 miniport_state; - u32 adapter_state; - u64 tx_count; - u64 tx_wi; - u64 tx_sg; - u64 tx_tcp_chksum; - u64 tx_udp_chksum; - u64 tx_ip_chksum; - u64 tx_lsov1; - u64 tx_lsov2; - u64 tx_max_sg_len ; -}; - -struct bna_rx_queue_info_s { - u16 q_id ; - u16 buf_size ; - u16 buf_count ; - u16 rsvd ; - u64 rx_count ; - u64 rx_dropped ; - u64 rx_unsupported ; - u64 rx_internal_err ; - u64 rss_count ; - u64 vlan_count ; - u64 rx_tcp_chksum ; - u64 rx_udp_chksum ; - u64 rx_ip_chksum ; - u64 rx_hds ; -}; - -struct bna_rx_q_set_s { - u16 q_set_type; - u32 miniport_state; - u32 adapter_state; - struct bna_rx_queue_info_s rx_queue[2]; -}; - -struct bna_port_stats_s { - struct bna_tx_info_s tx_stats; - u16 qset_count ; - struct bna_rx_q_set_s rx_qset[8]; -}; - -struct bfa_ethport_stats_s { - struct bna_stats_txf txf_stats[1]; - struct bna_stats_rxf rxf_stats[1]; - struct bnad_drv_stats drv_stats; -}; - -/** - * Ethernet port events - * Arguments below are in BFAL context from Mgmt - * BFA_PORT_AEN_ETH_LINKUP: [in]: mac [out]: mac - * BFA_PORT_AEN_ETH_LINKDOWN: [in]: mac [out]: mac - * BFA_PORT_AEN_ETH_ENABLE: [in]: mac [out]: mac - * BFA_PORT_AEN_ETH_DISABLE: [in]: mac [out]: mac - * - */ -enum bfa_ethport_aen_event { - BFA_ETHPORT_AEN_LINKUP = 1, /* Base Port Ethernet link up event */ - BFA_ETHPORT_AEN_LINKDOWN = 2, /* Base Port Ethernet link down event */ - BFA_ETHPORT_AEN_ENABLE = 3, /* Base Port Ethernet link enable event */ - BFA_ETHPORT_AEN_DISABLE = 4, /* Base Port Ethernet link disable - * event */ -}; - -struct bfa_ethport_aen_data_s { - mac_t mac; /* MAC address of the physical port */ -}; - - -#endif /* __BFA_DEFS_ETHPORT_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_fcpim.h b/drivers/scsi/bfa/include/defs/bfa_defs_fcpim.h deleted file mode 100644 index c08f4f5026ac..000000000000 --- a/drivers/scsi/bfa/include/defs/bfa_defs_fcpim.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ -#ifndef __BFA_DEFS_FCPIM_H__ -#define __BFA_DEFS_FCPIM_H__ - -struct bfa_fcpim_stats_s { - u32 total_ios; /* Total IO count */ - u32 qresumes; /* IO waiting for CQ space */ - u32 no_iotags; /* NO IO contexts */ - u32 io_aborts; /* IO abort requests */ - u32 no_tskims; /* NO task management contexts */ - u32 iocomp_ok; /* IO completions with OK status */ - u32 iocomp_underrun; /* IO underrun (good) */ - u32 iocomp_overrun; /* IO overrun (good) */ - u32 iocomp_aborted; /* Aborted IO requests */ - u32 iocomp_timedout; /* IO timeouts */ - u32 iocom_nexus_abort; /* IO selection timeouts */ - u32 iocom_proto_err; /* IO protocol errors */ - u32 iocom_dif_err; /* IO SBC-3 protection errors */ - u32 iocom_tm_abort; /* IO aborted by TM requests */ - u32 iocom_sqer_needed; /* IO retry for SQ error - *recovery */ - u32 iocom_res_free; /* Delayed freeing of IO resources */ - u32 iocomp_scsierr; /* IO with non-good SCSI status */ - u32 iocom_hostabrts; /* Host IO abort requests */ - u32 iocom_utags; /* IO comp with unknown tags */ - u32 io_cleanups; /* IO implicitly aborted */ - u32 io_tmaborts; /* IO aborted due to TM commands */ - u32 rsvd; -}; -#endif /*__BFA_DEFS_FCPIM_H__*/ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_fcport.h b/drivers/scsi/bfa/include/defs/bfa_defs_fcport.h deleted file mode 100644 index af86a6396439..000000000000 --- a/drivers/scsi/bfa/include/defs/bfa_defs_fcport.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * bfa_defs_fcport.h - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ -#ifndef __BFA_DEFS_FCPORT_H__ -#define __BFA_DEFS_FCPORT_H__ - -#include <defs/bfa_defs_types.h> -#include <protocol/types.h> - -#pragma pack(1) - -/** - * FCoE statistics - */ -struct bfa_fcoe_stats_s { - u64 secs_reset; /* Seconds since stats reset */ - u64 cee_linkups; /* CEE link up */ - u64 cee_linkdns; /* CEE link down */ - u64 fip_linkups; /* FIP link up */ - u64 fip_linkdns; /* FIP link down */ - u64 fip_fails; /* FIP failures */ - u64 mac_invalids; /* Invalid mac assignments */ - u64 vlan_req; /* Vlan requests */ - u64 vlan_notify; /* Vlan notifications */ - u64 vlan_err; /* Vlan notification errors */ - u64 vlan_timeouts; /* Vlan request timeouts */ - u64 vlan_invalids; /* Vlan invalids */ - u64 disc_req; /* Discovery requests */ - u64 disc_rsp; /* Discovery responses */ - u64 disc_err; /* Discovery error frames */ - u64 disc_unsol; /* Discovery unsolicited */ - u64 disc_timeouts; /* Discovery timeouts */ - 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 logos received */ - u64 clrvlink_req; /* Clear virtual link requests */ - u64 op_unsupp; /* FIP operation unsupp. */ - u64 untagged; /* FIP untagged frames */ - u64 txf_ucast; /* Tx FCoE unicast frames */ - u64 txf_ucast_vlan; /* Tx FCoE unicast vlan frames */ - u64 txf_ucast_octets; /* Tx FCoE unicast octets */ - u64 txf_mcast; /* Tx FCoE mutlicast frames */ - u64 txf_mcast_vlan; /* Tx FCoE mutlicast vlan frames */ - u64 txf_mcast_octets; /* Tx FCoE multicast octets */ - u64 txf_bcast; /* Tx FCoE broadcast frames */ - u64 txf_bcast_vlan; /* Tx FCoE broadcast vlan frames */ - u64 txf_bcast_octets; /* Tx FCoE broadcast octets */ - u64 txf_timeout; /* Tx timeouts */ - u64 txf_parity_errors; /* Transmit parity err */ - u64 txf_fid_parity_errors; /* Transmit FID parity err */ - 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 */ -}; - -/** - * QoS or FCoE stats (fcport stats excluding physical FC port stats) - */ -union bfa_fcport_stats_u { - struct bfa_qos_stats_s fcqos; - struct bfa_fcoe_stats_s fcoe; -}; - -#pragma pack() - -#endif /* __BFA_DEFS_FCPORT_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_ioc.h b/drivers/scsi/bfa/include/defs/bfa_defs_ioc.h deleted file mode 100644 index add0a05d941d..000000000000 --- a/drivers/scsi/bfa/include/defs/bfa_defs_ioc.h +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFA_DEFS_IOC_H__ -#define __BFA_DEFS_IOC_H__ - -#include <protocol/types.h> -#include <defs/bfa_defs_types.h> -#include <defs/bfa_defs_version.h> -#include <defs/bfa_defs_adapter.h> -#include <defs/bfa_defs_pm.h> - -enum { - BFA_IOC_DRIVER_LEN = 16, - BFA_IOC_CHIP_REV_LEN = 8, -}; - -/** - * Driver and firmware versions. - */ -struct bfa_ioc_driver_attr_s { - char driver[BFA_IOC_DRIVER_LEN]; /* driver name */ - char driver_ver[BFA_VERSION_LEN]; /* driver version */ - char fw_ver[BFA_VERSION_LEN]; /* firmware version*/ - char bios_ver[BFA_VERSION_LEN]; /* bios version */ - char efi_ver[BFA_VERSION_LEN]; /* EFI version */ - char ob_ver[BFA_VERSION_LEN]; /* openboot version*/ -}; - -/** - * IOC PCI device attributes - */ -struct bfa_ioc_pci_attr_s { - u16 vendor_id; /* PCI vendor ID */ - u16 device_id; /* PCI device ID */ - u16 ssid; /* subsystem ID */ - u16 ssvid; /* subsystem vendor ID */ - u32 pcifn; /* PCI device function */ - u32 rsvd; /* padding */ - u8 chip_rev[BFA_IOC_CHIP_REV_LEN]; /* chip revision */ -}; - -/** - * IOC states - */ -enum bfa_ioc_state { - BFA_IOC_RESET = 1, /* IOC is in reset state */ - BFA_IOC_SEMWAIT = 2, /* Waiting for IOC hardware semaphore */ - BFA_IOC_HWINIT = 3, /* IOC hardware is being initialized */ - BFA_IOC_GETATTR = 4, /* IOC is being configured */ - BFA_IOC_OPERATIONAL = 5, /* IOC is operational */ - BFA_IOC_INITFAIL = 6, /* IOC hardware failure */ - BFA_IOC_HBFAIL = 7, /* IOC heart-beat failure */ - BFA_IOC_DISABLING = 8, /* IOC is being disabled */ - BFA_IOC_DISABLED = 9, /* IOC is disabled */ - BFA_IOC_FWMISMATCH = 10, /* IOC firmware different from drivers */ -}; - -/** - * IOC firmware stats - */ -struct bfa_fw_ioc_stats_s { - u32 hb_count; - u32 cfg_reqs; - u32 enable_reqs; - u32 disable_reqs; - u32 stats_reqs; - u32 clrstats_reqs; - u32 unknown_reqs; - u32 ic_reqs; /* interrupt coalesce reqs */ -}; - -/** - * IOC driver stats - */ -struct bfa_ioc_drv_stats_s { - u32 ioc_isrs; - u32 ioc_enables; - u32 ioc_disables; - u32 ioc_hbfails; - u32 ioc_boots; - u32 stats_tmos; - u32 hb_count; - u32 disable_reqs; - u32 enable_reqs; - u32 disable_replies; - u32 enable_replies; -}; - -/** - * IOC statistics - */ -struct bfa_ioc_stats_s { - struct bfa_ioc_drv_stats_s drv_stats; /* driver IOC stats */ - struct bfa_fw_ioc_stats_s fw_stats; /* firmware IOC stats */ -}; - - -enum bfa_ioc_type_e { - BFA_IOC_TYPE_FC = 1, - BFA_IOC_TYPE_FCoE = 2, - BFA_IOC_TYPE_LL = 3, -}; - -/** - * IOC attributes returned in queries - */ -struct bfa_ioc_attr_s { - enum bfa_ioc_type_e ioc_type; - enum bfa_ioc_state state; /* IOC state */ - struct bfa_adapter_attr_s adapter_attr; /* HBA attributes */ - struct bfa_ioc_driver_attr_s driver_attr; /* driver attr */ - struct bfa_ioc_pci_attr_s pci_attr; - u8 port_id; /* port number */ - u8 rsvd[7]; /* 64bit align */ -}; - -/** - * BFA IOC level events - */ -enum bfa_ioc_aen_event { - BFA_IOC_AEN_HBGOOD = 1, /* Heart Beat restore event */ - BFA_IOC_AEN_HBFAIL = 2, /* Heart Beat failure event */ - BFA_IOC_AEN_ENABLE = 3, /* IOC enabled event */ - BFA_IOC_AEN_DISABLE = 4, /* IOC disabled event */ - BFA_IOC_AEN_FWMISMATCH = 5, /* IOC firmware mismatch */ - BFA_IOC_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 */ - -}; - -/** - * BFA IOC level event data, now just a place holder - */ -struct bfa_ioc_aen_data_s { - wwn_t pwwn; - s16 ioc_type; - mac_t mac; -}; - -#endif /* __BFA_DEFS_IOC_H__ */ - diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_iocfc.h b/drivers/scsi/bfa/include/defs/bfa_defs_iocfc.h deleted file mode 100644 index 31e728a631ed..000000000000 --- a/drivers/scsi/bfa/include/defs/bfa_defs_iocfc.h +++ /dev/null @@ -1,322 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFA_DEFS_IOCFC_H__ -#define __BFA_DEFS_IOCFC_H__ - -#include <protocol/types.h> -#include <defs/bfa_defs_types.h> -#include <defs/bfa_defs_version.h> -#include <defs/bfa_defs_adapter.h> -#include <defs/bfa_defs_pm.h> - -#define BFA_IOCFC_INTR_DELAY 1125 -#define BFA_IOCFC_INTR_LATENCY 225 -#define BFA_IOCFCOE_INTR_DELAY 25 -#define BFA_IOCFCOE_INTR_LATENCY 5 - -/** - * Interrupt coalescing configuration. - */ -struct bfa_iocfc_intr_attr_s { - bfa_boolean_t coalesce; /* enable/disable coalescing */ - u16 latency; /* latency in microseconds */ - u16 delay; /* delay in microseconds */ -}; - -/** - * IOC firmware configuraton - */ -struct bfa_iocfc_fwcfg_s { - u16 num_fabrics; /* number of fabrics */ - u16 num_lports; /* number of local lports */ - u16 num_rports; /* number of remote ports */ - u16 num_ioim_reqs; /* number of IO reqs */ - u16 num_tskim_reqs; /* task management requests */ - u16 num_iotm_reqs; /* number of TM IO reqs */ - u16 num_tsktm_reqs; /* TM task management requests*/ - u16 num_fcxp_reqs; /* unassisted FC exchanges */ - u16 num_uf_bufs; /* unsolicited recv buffers */ - u8 num_cqs; - u8 fw_tick_res; /*!< FW clock resolution in ms */ - u8 rsvd[4]; - -}; - -struct bfa_iocfc_drvcfg_s { - u16 num_reqq_elems; /* number of req queue elements */ - u16 num_rspq_elems; /* number of rsp queue elements */ - u16 num_sgpgs; /* number of total SG pages */ - u16 num_sboot_tgts; /* number of SAN boot targets */ - u16 num_sboot_luns; /* number of SAN boot luns */ - u16 ioc_recover; /* IOC recovery mode */ - u16 min_cfg; /* minimum configuration */ - u16 path_tov; /* device path timeout */ - bfa_boolean_t delay_comp; /* delay completion of - failed inflight IOs */ - u32 rsvd; -}; -/** - * IOC configuration - */ -struct bfa_iocfc_cfg_s { - struct bfa_iocfc_fwcfg_s fwcfg; /* firmware side config */ - struct bfa_iocfc_drvcfg_s drvcfg; /* driver side config */ -}; - -/** - * IOC firmware IO stats - */ -struct bfa_fw_io_stats_s { - u32 host_abort; /* IO aborted by host driver*/ - u32 host_cleanup; /* IO clean up by host driver */ - - u32 fw_io_timeout; /* IOs timedout */ - u32 fw_frm_parse; /* frame parsed by f/w */ - u32 fw_frm_data; /* fcp_data frame parsed by f/w */ - u32 fw_frm_rsp; /* fcp_rsp frame parsed by f/w */ - u32 fw_frm_xfer_rdy; /* xfer_rdy frame parsed by f/w */ - u32 fw_frm_bls_acc; /* BLS ACC frame parsed by f/w */ - u32 fw_frm_tgt_abort; /* target ABTS parsed by f/w */ - u32 fw_frm_unknown; /* unknown parsed by f/w */ - u32 fw_data_dma; /* f/w DMA'ed the data frame */ - u32 fw_frm_drop; /* f/w drop the frame */ - - u32 rec_timeout; /* FW rec timed out */ - u32 error_rec; /* FW sending rec on - * an error condition*/ - u32 wait_for_si; /* FW wait for SI */ - u32 rec_rsp_inval; /* REC rsp invalid */ - u32 seqr_io_abort; /* target does not know cmd so abort */ - u32 seqr_io_retry; /* SEQR failed so retry IO */ - - u32 itn_cisc_upd_rsp; /* ITN cisc updated on fcp_rsp */ - u32 itn_cisc_upd_data; /* ITN cisc updated on fcp_data */ - u32 itn_cisc_upd_xfer_rdy; /* ITN cisc updated on fcp_data */ - - u32 fcp_data_lost; /* fcp data lost */ - - u32 ro_set_in_xfer_rdy; /* Target set RO in Xfer_rdy frame */ - u32 xfer_rdy_ooo_err; /* Out of order Xfer_rdy received */ - u32 xfer_rdy_unknown_err; /* unknown error in xfer_rdy frame */ - - u32 io_abort_timeout; /* ABTS timedout */ - u32 sler_initiated; /* SLER initiated */ - - u32 unexp_fcp_rsp; /* fcp response in wrong state */ - - u32 fcp_rsp_under_run; /* fcp rsp IO underrun */ - u32 fcp_rsp_under_run_wr; /* fcp rsp IO underrun for write */ - u32 fcp_rsp_under_run_err; /* fcp rsp IO underrun error */ - u32 fcp_rsp_resid_inval; /* invalid residue */ - u32 fcp_rsp_over_run; /* fcp rsp IO overrun */ - u32 fcp_rsp_over_run_err; /* fcp rsp IO overrun error */ - u32 fcp_rsp_proto_err; /* protocol error in fcp rsp */ - u32 fcp_rsp_sense_err; /* error in sense info in fcp rsp */ - u32 fcp_conf_req; /* FCP conf requested */ - - u32 tgt_aborted_io; /* target initiated abort */ - - u32 ioh_edtov_timeout_event;/* IOH edtov timer popped */ - u32 ioh_fcp_rsp_excp_event; /* IOH FCP_RSP exception */ - u32 ioh_fcp_conf_event; /* IOH FCP_CONF */ - u32 ioh_mult_frm_rsp_event; /* IOH multi_frame FCP_RSP */ - u32 ioh_hit_class2_event; /* IOH hit class2 */ - u32 ioh_miss_other_event; /* IOH miss other */ - u32 ioh_seq_cnt_err_event; /* IOH seq cnt error */ - u32 ioh_len_err_event; /* IOH len error - fcp_dl != - * bytes xfered */ - u32 ioh_seq_len_err_event; /* IOH seq len error */ - u32 ioh_data_oor_event; /* Data out of range */ - u32 ioh_ro_ooo_event; /* Relative offset out of range */ - u32 ioh_cpu_owned_event; /* IOH hit -iost owned by f/w */ - u32 ioh_unexp_frame_event; /* unexpected frame recieved - * count */ - u32 ioh_err_int; /* IOH error int during data-phase - * for scsi write - */ -}; - -/** - * IOC port firmware stats - */ - -struct bfa_fw_port_fpg_stats_s { - u32 intr_evt; - u32 intr; - u32 intr_excess; - u32 intr_cause0; - u32 intr_other; - u32 intr_other_ign; - u32 sig_lost; - u32 sig_regained; - u32 sync_lost; - u32 sync_to; - u32 sync_regained; - u32 div2_overflow; - u32 div2_underflow; - u32 efifo_overflow; - u32 efifo_underflow; - u32 idle_rx; - u32 lrr_rx; - u32 lr_rx; - u32 ols_rx; - u32 nos_rx; - u32 lip_rx; - u32 arbf0_rx; - u32 arb_rx; - u32 mrk_rx; - u32 const_mrk_rx; - u32 prim_unknown; -}; - - -struct bfa_fw_port_lksm_stats_s { - u32 hwsm_success; /* hwsm state machine success */ - u32 hwsm_fails; /* hwsm fails */ - u32 hwsm_wdtov; /* hwsm timed out */ - u32 swsm_success; /* swsm success */ - u32 swsm_fails; /* swsm fails */ - u32 swsm_wdtov; /* swsm timed out */ - u32 busybufs; /* link init failed due to busybuf */ - u32 buf_waits; /* bufwait state entries */ - u32 link_fails; /* link failures */ - u32 psp_errors; /* primitive sequence protocol errors */ - u32 lr_unexp; /* No. of times LR rx-ed unexpectedly */ - u32 lrr_unexp; /* No. of times LRR rx-ed unexpectedly */ - u32 lr_tx; /* No. of times LR tx started */ - u32 lrr_tx; /* No. of times LRR tx started */ - u32 ols_tx; /* No. of times OLS tx started */ - u32 nos_tx; /* No. of times NOS tx started */ - u32 hwsm_lrr_rx; /* No. of times LRR rx-ed by HWSM */ - u32 hwsm_lr_rx; /* No. of times LR rx-ed by HWSM */ -}; - - -struct bfa_fw_port_snsm_stats_s { - u32 hwsm_success; /* Successful hwsm terminations */ - u32 hwsm_fails; /* hwsm fail count */ - u32 hwsm_wdtov; /* hwsm timed out */ - u32 swsm_success; /* swsm success */ - u32 swsm_wdtov; /* swsm timed out */ - u32 error_resets; /* error resets initiated by upsm */ - u32 sync_lost; /* Sync loss count */ - u32 sig_lost; /* Signal loss count */ -}; - - -struct bfa_fw_port_physm_stats_s { - u32 module_inserts; /* Module insert count */ - u32 module_xtracts; /* Module extracts count */ - u32 module_invalids; /* Invalid module inserted count */ - u32 module_read_ign; /* Module validation status ignored */ - u32 laser_faults; /* Laser fault count */ - u32 rsvd; -}; - - -struct bfa_fw_fip_stats_s { - u32 vlan_req; /* vlan discovery requests */ - u32 vlan_notify; /* vlan notifications */ - u32 vlan_err; /* vlan response error */ - u32 vlan_timeouts; /* vlan disvoery timeouts */ - u32 vlan_invalids; /* invalid vlan in discovery advert. */ - u32 disc_req; /* Discovery solicit requests */ - u32 disc_rsp; /* Discovery solicit response */ - u32 disc_err; /* Discovery advt. parse errors */ - u32 disc_unsol; /* Discovery unsolicited */ - u32 disc_timeouts; /* Discovery timeouts */ - u32 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; /* FIP logos received */ - u32 clrvlink_req; /* Clear virtual link req */ - u32 op_unsupp; /* Unsupported FIP operation */ - u32 untagged; /* Untagged frames (ignored) */ - u32 invalid_version; /*!< Invalid FIP version */ -}; - - -struct bfa_fw_lps_stats_s { - u32 mac_invalids; /* Invalid mac assigned */ - u32 rsvd; -}; - - -struct bfa_fw_fcoe_stats_s { - u32 cee_linkups; /* CEE link up count */ - u32 cee_linkdns; /* CEE link down count */ - u32 fip_linkups; /* FIP link up count */ - u32 fip_linkdns; /* FIP link up count */ - u32 fip_fails; /* FIP fail count */ - u32 mac_invalids; /* Invalid mac assigned */ -}; - -/** - * IOC firmware FCoE port stats - */ -struct bfa_fw_fcoe_port_stats_s { - struct bfa_fw_fcoe_stats_s fcoe_stats; - struct bfa_fw_fip_stats_s fip_stats; -}; - -/** - * IOC firmware FC port stats - */ -struct bfa_fw_fc_port_stats_s { - struct bfa_fw_port_fpg_stats_s fpg_stats; - struct bfa_fw_port_physm_stats_s physm_stats; - struct bfa_fw_port_snsm_stats_s snsm_stats; - struct bfa_fw_port_lksm_stats_s lksm_stats; -}; - -/** - * IOC firmware FC port stats - */ -union bfa_fw_port_stats_s { - struct bfa_fw_fc_port_stats_s fc_stats; - struct bfa_fw_fcoe_port_stats_s fcoe_stats; -}; - -/** - * IOC firmware stats - */ -struct bfa_fw_stats_s { - struct bfa_fw_ioc_stats_s ioc_stats; - struct bfa_fw_io_stats_s io_stats; - union bfa_fw_port_stats_s port_stats; -}; - -/** - * IOC statistics - */ -struct bfa_iocfc_stats_s { - struct bfa_fw_stats_s fw_stats; /* firmware IOC stats */ -}; - -/** - * IOC attributes returned in queries - */ -struct bfa_iocfc_attr_s { - struct bfa_iocfc_cfg_s config; /* IOCFC config */ - struct bfa_iocfc_intr_attr_s intr_attr; /* interrupt attr */ -}; - -#define BFA_IOCFC_PATHTOV_MAX 60 -#define BFA_IOCFC_QDEPTH_MAX 2000 - -#endif /* __BFA_DEFS_IOC_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_ipfc.h b/drivers/scsi/bfa/include/defs/bfa_defs_ipfc.h deleted file mode 100644 index 7cb63ea98f38..000000000000 --- a/drivers/scsi/bfa/include/defs/bfa_defs_ipfc.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ -#ifndef __BFA_DEFS_IPFC_H__ -#define __BFA_DEFS_IPFC_H__ - -#include <bfa_os_inc.h> -#include <protocol/types.h> -#include <defs/bfa_defs_types.h> - -/** - * FCS ip remote port states - */ -enum bfa_iprp_state { - BFA_IPRP_UNINIT = 0, /* PORT is not yet initialized */ - BFA_IPRP_ONLINE = 1, /* process login is complete */ - BFA_IPRP_OFFLINE = 2, /* iprp is offline */ -}; - -/** - * FCS remote port statistics - */ -struct bfa_iprp_stats_s { - u32 offlines; - u32 onlines; - u32 rscns; - u32 plogis; - u32 logos; - u32 plogi_timeouts; - u32 plogi_rejects; -}; - -/** - * FCS iprp attribute returned in queries - */ -struct bfa_iprp_attr_s { - enum bfa_iprp_state state; -}; - -struct bfa_ipfc_stats_s { - u32 arp_sent; - u32 arp_recv; - u32 arp_reply_sent; - u32 arp_reply_recv; - u32 farp_sent; - u32 farp_recv; - u32 farp_reply_sent; - u32 farp_reply_recv; - u32 farp_reject_sent; - u32 farp_reject_recv; -}; - -struct bfa_ipfc_attr_s { - bfa_boolean_t enabled; -}; - -#endif /* __BFA_DEFS_IPFC_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_itnim.h b/drivers/scsi/bfa/include/defs/bfa_defs_itnim.h deleted file mode 100644 index d77788b3999a..000000000000 --- a/drivers/scsi/bfa/include/defs/bfa_defs_itnim.h +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ -#ifndef __BFA_DEFS_ITNIM_H__ -#define __BFA_DEFS_ITNIM_H__ - -#include <bfa_os_inc.h> -#include <protocol/types.h> - -/** - * FCS itnim states - */ -enum bfa_itnim_state { - BFA_ITNIM_OFFLINE = 0, /* offline */ - BFA_ITNIM_PRLI_SEND = 1, /* prli send */ - BFA_ITNIM_PRLI_SENT = 2, /* prli sent */ - BFA_ITNIM_PRLI_RETRY = 3, /* prli retry */ - BFA_ITNIM_HCB_ONLINE = 4, /* online callback */ - BFA_ITNIM_ONLINE = 5, /* online */ - BFA_ITNIM_HCB_OFFLINE = 6, /* offline callback */ - BFA_ITNIM_INITIATIOR = 7, /* initiator */ -}; - -struct bfa_itnim_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 */ - u32 creates; /* ITN create requests */ - u32 deletes; /* ITN delete requests */ - u32 create_comps; /* ITN create completions */ - u32 delete_comps; /* ITN delete completions */ - u32 sler_events; /* SLER (sequence level error - * recovery) events */ - u32 ioc_disabled; /* Num IOC disables */ - u32 cleanup_comps; /* ITN cleanup completions */ - u32 tm_cmnds; /* task management(TM) cmnds sent */ - u32 tm_fw_rsps; /* TM cmds firmware responses */ - u32 tm_success; /* TM successes */ - u32 tm_failures; /* TM failures */ - u32 tm_io_comps; /* TM IO completions */ - u32 tm_qresumes; /* TM queue resumes (after waiting - * for resources) - */ - u32 tm_iocdowns; /* TM cmnds affected by IOC down */ - u32 tm_cleanups; /* TM cleanups */ - u32 tm_cleanup_comps; - /* TM cleanup completions */ - u32 ios; /* IO requests */ - u32 io_comps; /* IO completions */ - u64 input_reqs; /* INPUT requests */ - u64 output_reqs; /* OUTPUT requests */ -}; - -/** - * FCS remote port statistics - */ -struct bfa_itnim_stats_s { - u32 onlines; /* num rport online */ - u32 offlines; /* num rport offline */ - u32 prli_sent; /* num prli sent out */ - u32 fcxp_alloc_wait;/* num fcxp alloc waits */ - u32 prli_rsp_err; /* num prli rsp errors */ - u32 prli_rsp_acc; /* num prli rsp accepts */ - u32 initiator; /* rport is an initiator */ - u32 prli_rsp_parse_err; /* prli rsp parsing errors */ - u32 prli_rsp_rjt; /* num prli rsp rejects */ - u32 timeout; /* num timeouts detected */ - u32 sler; /* num sler notification from BFA */ - u32 rsvd; - struct bfa_itnim_hal_stats_s hal_stats; -}; - -/** - * FCS itnim attributes returned in queries - */ -struct bfa_itnim_attr_s { - enum bfa_itnim_state state; /* FCS itnim state */ - u8 retry; /* data retransmision support */ - u8 task_retry_id; /* task retry ident support */ - u8 rec_support; /* REC supported */ - u8 conf_comp; /* confirmed completion supp */ - struct bfa_itnim_latency_s io_latency; /* IO latency */ -}; - -/** - * BFA ITNIM events. - * Arguments below are in BFAL context from Mgmt - * BFA_ITNIM_AEN_NEW: [in]: None [out]: vf_id, lpwwn - * BFA_ITNIM_AEN_DELETE: [in]: vf_id, lpwwn, rpwwn (0 = all fcp4 targets), - * [out]: vf_id, ppwwn, lpwwn, rpwwn - * BFA_ITNIM_AEN_ONLINE: [in]: vf_id, lpwwn, rpwwn (0 = all fcp4 targets), - * [out]: vf_id, ppwwn, lpwwn, rpwwn - * BFA_ITNIM_AEN_OFFLINE: [in]: vf_id, lpwwn, rpwwn (0 = all fcp4 targets), - * [out]: vf_id, ppwwn, lpwwn, rpwwn - * BFA_ITNIM_AEN_DISCONNECT:[in]: vf_id, lpwwn, rpwwn (0 = all fcp4 targets), - * [out]: vf_id, ppwwn, lpwwn, rpwwn - */ -enum bfa_itnim_aen_event { - BFA_ITNIM_AEN_ONLINE = 1, /* Target online */ - BFA_ITNIM_AEN_OFFLINE = 2, /* Target offline */ - BFA_ITNIM_AEN_DISCONNECT = 3, /* Target disconnected */ -}; - -/** - * BFA ITNIM event data structure. - */ -struct bfa_itnim_aen_data_s { - u16 vf_id; /* vf_id of the IT nexus */ - u16 rsvd[3]; - wwn_t ppwwn; /* WWN of its physical port */ - wwn_t lpwwn; /* WWN of logical port */ - wwn_t rpwwn; /* WWN of remote(target) port */ -}; - -#endif /* __BFA_DEFS_ITNIM_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_led.h b/drivers/scsi/bfa/include/defs/bfa_defs_led.h deleted file mode 100644 index 62039273264e..000000000000 --- a/drivers/scsi/bfa/include/defs/bfa_defs_led.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFA_DEFS_LED_H__ -#define __BFA_DEFS_LED_H__ - -#define BFA_LED_MAX_NUM 3 - -enum bfa_led_op { - BFA_LED_OFF = 0, - BFA_LED_ON = 1, - BFA_LED_FLICK = 2, - BFA_LED_BLINK = 3, -}; - -enum bfa_led_color { - BFA_LED_GREEN = 0, - BFA_LED_AMBER = 1, -}; - -#endif /* __BFA_DEFS_LED_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_lport.h b/drivers/scsi/bfa/include/defs/bfa_defs_lport.h deleted file mode 100644 index 0952a139c47c..000000000000 --- a/drivers/scsi/bfa/include/defs/bfa_defs_lport.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFA_DEFS_LPORT_H__ -#define __BFA_DEFS_LPORT_H__ - -#include <defs/bfa_defs_types.h> -#include <defs/bfa_defs_port.h> - -/** - * BFA AEN logical port events. - * Arguments below are in BFAL context from Mgmt - * BFA_LPORT_AEN_NEW: [in]: None [out]: vf_id, ppwwn, lpwwn, roles - * BFA_LPORT_AEN_DELETE: [in]: lpwwn [out]: vf_id, ppwwn. lpwwn, roles - * BFA_LPORT_AEN_ONLINE: [in]: lpwwn [out]: vf_id, ppwwn. lpwwn, roles - * BFA_LPORT_AEN_OFFLINE: [in]: lpwwn [out]: vf_id, ppwwn. lpwwn, roles - * BFA_LPORT_AEN_DISCONNECT:[in]: lpwwn [out]: vf_id, ppwwn. lpwwn, roles - * BFA_LPORT_AEN_NEW_PROP: [in]: None [out]: vf_id, ppwwn. lpwwn, roles - * BFA_LPORT_AEN_DELETE_PROP: [in]: lpwwn [out]: vf_id, ppwwn. lpwwn, roles - * BFA_LPORT_AEN_NEW_STANDARD: [in]: None [out]: vf_id, ppwwn. lpwwn, roles - * BFA_LPORT_AEN_DELETE_STANDARD: [in]: lpwwn [out]: vf_id, ppwwn. lpwwn, roles - * BFA_LPORT_AEN_NPIV_DUP_WWN: [in]: lpwwn [out]: vf_id, ppwwn. lpwwn, roles - * BFA_LPORT_AEN_NPIV_FABRIC_MAX: [in]: lpwwn [out]: vf_id, ppwwn. lpwwn, roles - * BFA_LPORT_AEN_NPIV_UNKNOWN: [in]: lpwwn [out]: vf_id, ppwwn. lpwwn, roles - */ -enum bfa_lport_aen_event { - BFA_LPORT_AEN_NEW = 1, /* LPort created event */ - BFA_LPORT_AEN_DELETE = 2, /* LPort deleted event */ - BFA_LPORT_AEN_ONLINE = 3, /* LPort online event */ - BFA_LPORT_AEN_OFFLINE = 4, /* LPort offline event */ - BFA_LPORT_AEN_DISCONNECT = 5, /* LPort disconnect event */ - BFA_LPORT_AEN_NEW_PROP = 6, /* VPort created event */ - BFA_LPORT_AEN_DELETE_PROP = 7, /* VPort deleted event */ - BFA_LPORT_AEN_NEW_STANDARD = 8, /* VPort created event */ - BFA_LPORT_AEN_DELETE_STANDARD = 9, /* VPort deleted event */ - BFA_LPORT_AEN_NPIV_DUP_WWN = 10, /* VPort configured with - * duplicate WWN event - */ - BFA_LPORT_AEN_NPIV_FABRIC_MAX = 11, /* Max NPIV in fabric/fport */ - BFA_LPORT_AEN_NPIV_UNKNOWN = 12, /* Unknown NPIV Error code event */ -}; - -/** - * BFA AEN event data structure - */ -struct bfa_lport_aen_data_s { - u16 vf_id; /* vf_id of this logical port */ - s16 roles; /* Logical port mode,IM/TM/IP etc */ - u32 rsvd; - wwn_t ppwwn; /* WWN of its physical port */ - wwn_t lpwwn; /* WWN of this logical port */ -}; - -#endif /* __BFA_DEFS_LPORT_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_mfg.h b/drivers/scsi/bfa/include/defs/bfa_defs_mfg.h deleted file mode 100644 index d22fb7909643..000000000000 --- a/drivers/scsi/bfa/include/defs/bfa_defs_mfg.h +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ -#ifndef __BFA_DEFS_MFG_H__ -#define __BFA_DEFS_MFG_H__ - -#include <bfa_os_inc.h> - -/** - * Manufacturing block version - */ -#define BFA_MFG_VERSION 2 - -/** - * 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 - */ -#define BFA_MFG_SERIALNUM_SIZE 11 -#define BFA_MFG_PARTNUM_SIZE 14 -#define BFA_MFG_SUPPLIER_ID_SIZE 10 -#define BFA_MFG_SUPPLIER_PARTNUM_SIZE 20 -#define BFA_MFG_SUPPLIER_SERIALNUM_SIZE 20 -#define BFA_MFG_SUPPLIER_REVISION_SIZE 4 -#define STRSZ(_n) (((_n) + 4) & ~3) - -/** - * Manufacturing card type - */ -enum { - BFA_MFG_TYPE_CB_MAX = 825, /* Crossbow card type max */ - BFA_MFG_TYPE_FC8P2 = 825, /* 8G 2port FC card */ - BFA_MFG_TYPE_FC8P1 = 815, /* 8G 1port FC card */ - BFA_MFG_TYPE_FC4P2 = 425, /* 4G 2port FC card */ - 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) - -/** - * Card type to port number conversion - */ -#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. - */ -struct bfa_mfg_block_s { -}; - -/** - * VPD data length - */ -#define BFA_MFG_VPD_LEN 512 - -#define BFA_MFG_VPD_PCI_HDR_OFF 137 -#define BFA_MFG_VPD_PCI_VER_MASK 0x07 /* version mask 3 bits */ -#define BFA_MFG_VPD_PCI_VDR_MASK 0xf8 /* vendor mask 5 bits */ - -/** - * VPD vendor tag - */ -enum { - BFA_MFG_VPD_UNKNOWN = 0, /* vendor unknown */ - BFA_MFG_VPD_IBM = 1, /* vendor IBM */ - BFA_MFG_VPD_HP = 2, /* vendor HP */ - BFA_MFG_VPD_DELL = 3, /* vendor DELL */ - BFA_MFG_VPD_PCI_IBM = 0x08, /* PCI VPD IBM */ - BFA_MFG_VPD_PCI_HP = 0x10, /* PCI VPD HP */ - BFA_MFG_VPD_PCI_DELL = 0x20, /* PCI VPD DELL */ - BFA_MFG_VPD_PCI_BRCD = 0xf8, /* PCI VPD Brocade */ -}; - -/** - * All numerical fields are in big-endian format. - */ -struct bfa_mfg_vpd_s { - u8 version; /* vpd data version */ - u8 vpd_sig[3]; /* characters 'V', 'P', 'D' */ - u8 chksum; /* u8 checksum */ - u8 vendor; /* vendor */ - u8 len; /* vpd data length excluding header */ - u8 rsv; - u8 data[BFA_MFG_VPD_LEN]; /* vpd data */ -}; - -#pragma pack() - -#endif /* __BFA_DEFS_MFG_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_pci.h b/drivers/scsi/bfa/include/defs/bfa_defs_pci.h deleted file mode 100644 index ea7d89bbc0bb..000000000000 --- a/drivers/scsi/bfa/include/defs/bfa_defs_pci.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFA_DEFS_PCI_H__ -#define __BFA_DEFS_PCI_H__ - -/** - * PCI device and vendor ID information - */ -enum { - BFA_PCI_VENDOR_ID_BROCADE = 0x1657, - BFA_PCI_DEVICE_ID_FC_8G2P = 0x13, - BFA_PCI_DEVICE_ID_FC_8G1P = 0x17, - BFA_PCI_DEVICE_ID_CT = 0x14, - 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 - */ -enum { - BFA_PCI_FCOE_SSDEVICE_ID = 0x14, -}; - -/** - * Maximum number of device address ranges mapped through different BAR(s) - */ -#define BFA_PCI_ACCESS_RANGES 1 - -#endif /* __BFA_DEFS_PCI_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_pm.h b/drivers/scsi/bfa/include/defs/bfa_defs_pm.h deleted file mode 100644 index e8d6d959006e..000000000000 --- a/drivers/scsi/bfa/include/defs/bfa_defs_pm.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFA_DEFS_PM_H__ -#define __BFA_DEFS_PM_H__ - -#include <bfa_os_inc.h> - -/** - * BFA power management device states - */ -enum bfa_pm_ds { - BFA_PM_DS_D0 = 0, /* full power mode */ - BFA_PM_DS_D1 = 1, /* power save state 1 */ - BFA_PM_DS_D2 = 2, /* power save state 2 */ - BFA_PM_DS_D3 = 3, /* power off state */ -}; - -#endif /* __BFA_DEFS_PM_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_pom.h b/drivers/scsi/bfa/include/defs/bfa_defs_pom.h deleted file mode 100644 index d9fa278472b7..000000000000 --- a/drivers/scsi/bfa/include/defs/bfa_defs_pom.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ -#ifndef __BFA_DEFS_POM_H__ -#define __BFA_DEFS_POM_H__ - -#include <bfa_os_inc.h> -#include <defs/bfa_defs_types.h> - -/** - * POM health status levels for each attributes. - */ -enum bfa_pom_entry_health { - BFA_POM_HEALTH_NOINFO = 1, /* no information */ - BFA_POM_HEALTH_NORMAL = 2, /* health is normal */ - BFA_POM_HEALTH_WARNING = 3, /* warning level */ - BFA_POM_HEALTH_ALARM = 4, /* alarming level */ -}; - -/** - * Reading of temperature/voltage/current/power - */ -struct bfa_pom_entry_s { - enum bfa_pom_entry_health health; /* POM entry health */ - u32 curr_value; /* current value */ - u32 thr_warn_high; /* threshold warning high */ - u32 thr_warn_low; /* threshold warning low */ - u32 thr_alarm_low; /* threshold alaram low */ - u32 thr_alarm_high; /* threshold alarm high */ -}; - -/** - * POM attributes - */ -struct bfa_pom_attr_s { - struct bfa_pom_entry_s temperature; /* centigrade */ - struct bfa_pom_entry_s voltage; /* volts */ - struct bfa_pom_entry_s curr; /* milli amps */ - struct bfa_pom_entry_s txpower; /* micro watts */ - struct bfa_pom_entry_s rxpower; /* micro watts */ -}; - -#endif /* __BFA_DEFS_POM_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_port.h b/drivers/scsi/bfa/include/defs/bfa_defs_port.h deleted file mode 100644 index ebdf0d1731a4..000000000000 --- a/drivers/scsi/bfa/include/defs/bfa_defs_port.h +++ /dev/null @@ -1,248 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFA_DEFS_PORT_H__ -#define __BFA_DEFS_PORT_H__ - -#include <bfa_os_inc.h> -#include <protocol/types.h> -#include <defs/bfa_defs_pport.h> -#include <defs/bfa_defs_ioc.h> - -#define BFA_FCS_FABRIC_IPADDR_SZ 16 - -/** - * symbolic names for base port/virtual port - */ -#define BFA_SYMNAME_MAXLEN 128 /* vmware/windows uses 128 bytes */ -struct bfa_port_symname_s { - char symname[BFA_SYMNAME_MAXLEN]; -}; - -/** -* Roles of FCS port: - * - FCP IM and FCP TM roles cannot be enabled together for a FCS port - * - Create multiple ports if both IM and TM functions required. - * - Atleast one role must be specified. - */ -enum bfa_port_role { - BFA_PORT_ROLE_FCP_IM = 0x01, /* FCP initiator role */ - BFA_PORT_ROLE_FCP_TM = 0x02, /* FCP target role */ - BFA_PORT_ROLE_FCP_IPFC = 0x04, /* IP over FC role */ - BFA_PORT_ROLE_FCP_MAX = BFA_PORT_ROLE_FCP_IPFC | BFA_PORT_ROLE_FCP_IM -}; - -/** - * FCS port configuration. - */ -struct bfa_port_cfg_s { - wwn_t pwwn; /* port wwn */ - wwn_t nwwn; /* node wwn */ - struct bfa_port_symname_s sym_name; /* vm port symbolic name */ - bfa_boolean_t preboot_vp; /* vport created from PBC */ - enum bfa_port_role roles; /* FCS port roles */ - u8 tag[16]; /* opaque tag from application */ -}; - -/** - * FCS port states - */ -enum bfa_port_state { - BFA_PORT_UNINIT = 0, /* PORT is not yet initialized */ - BFA_PORT_FDISC = 1, /* FDISC is in progress */ - BFA_PORT_ONLINE = 2, /* login to fabric is complete */ - BFA_PORT_OFFLINE = 3, /* No login to fabric */ -}; - -/** - * FCS port type. Required for VmWare. - */ -enum bfa_port_type { - BFA_PORT_TYPE_PHYSICAL = 0, - BFA_PORT_TYPE_VIRTUAL, -}; - -/** - * FCS port offline reason. Required for VmWare. - */ -enum bfa_port_offline_reason { - BFA_PORT_OFFLINE_UNKNOWN = 0, - BFA_PORT_OFFLINE_LINKDOWN, - BFA_PORT_OFFLINE_FAB_UNSUPPORTED, /* NPIV not supported by the - * fabric */ - BFA_PORT_OFFLINE_FAB_NORESOURCES, - BFA_PORT_OFFLINE_FAB_LOGOUT, -}; - -/** - * FCS lport info. Required for VmWare. - */ -struct bfa_port_info_s { - u8 port_type; /* bfa_port_type_t : physical or - * virtual */ - u8 port_state; /* one of bfa_port_state values */ - u8 offline_reason; /* one of bfa_port_offline_reason_t - * values */ - wwn_t port_wwn; - wwn_t node_wwn; - - /* - * following 4 feilds are valid for Physical Ports only - */ - u32 max_vports_supp; /* Max supported vports */ - u32 num_vports_inuse; /* Num of in use vports */ - u32 max_rports_supp; /* Max supported rports */ - u32 num_rports_inuse; /* Num of doscovered rports */ - -}; - -/** - * FCS port statistics - */ -struct bfa_port_stats_s { - u32 ns_plogi_sent; - u32 ns_plogi_rsp_err; - u32 ns_plogi_acc_err; - u32 ns_plogi_accepts; - u32 ns_rejects; /* NS command rejects */ - u32 ns_plogi_unknown_rsp; - u32 ns_plogi_alloc_wait; - - u32 ns_retries; /* NS command retries */ - u32 ns_timeouts; /* NS command timeouts */ - - u32 ns_rspnid_sent; - u32 ns_rspnid_accepts; - u32 ns_rspnid_rsp_err; - u32 ns_rspnid_rejects; - u32 ns_rspnid_alloc_wait; - - u32 ns_rftid_sent; - u32 ns_rftid_accepts; - u32 ns_rftid_rsp_err; - u32 ns_rftid_rejects; - u32 ns_rftid_alloc_wait; - - u32 ns_rffid_sent; - u32 ns_rffid_accepts; - u32 ns_rffid_rsp_err; - u32 ns_rffid_rejects; - u32 ns_rffid_alloc_wait; - - u32 ns_gidft_sent; - u32 ns_gidft_accepts; - u32 ns_gidft_rsp_err; - u32 ns_gidft_rejects; - u32 ns_gidft_unknown_rsp; - u32 ns_gidft_alloc_wait; - - /* - * Mgmt Server stats - */ - u32 ms_retries; /* MS command retries */ - u32 ms_timeouts; /* MS command timeouts */ - u32 ms_plogi_sent; - u32 ms_plogi_rsp_err; - u32 ms_plogi_acc_err; - u32 ms_plogi_accepts; - u32 ms_rejects; /* MS command rejects */ - u32 ms_plogi_unknown_rsp; - u32 ms_plogi_alloc_wait; - - u32 num_rscn; /* Num of RSCN received */ - u32 num_portid_rscn;/* Num portid format RSCN - * received */ - - u32 uf_recvs; /* unsolicited recv frames */ - u32 uf_recv_drops; /* dropped received frames */ - - u32 rsvd; /* padding for 64 bit alignment */ -}; - -/** - * BFA port attribute returned in queries - */ -struct bfa_port_attr_s { - enum bfa_port_state state; /* port state */ - u32 pid; /* port ID */ - struct bfa_port_cfg_s port_cfg; /* port configuration */ - enum bfa_pport_type port_type; /* current topology */ - u32 loopback; /* cable is externally looped back */ - wwn_t fabric_name; /* attached switch's nwwn */ - u8 fabric_ip_addr[BFA_FCS_FABRIC_IPADDR_SZ]; /* attached - * fabric's ip addr */ - struct mac_s fpma_mac; /* Lport's FPMA Mac address */ - u16 authfail; /* auth failed state */ -}; - -/** - * BFA physical port Level events - * Arguments below are in BFAL context from Mgmt - * BFA_PORT_AEN_ONLINE: [in]: pwwn [out]: pwwn - * BFA_PORT_AEN_OFFLINE: [in]: pwwn [out]: pwwn - * BFA_PORT_AEN_RLIR: [in]: None [out]: pwwn, rlir_data, rlir_len - * BFA_PORT_AEN_SFP_INSERT: [in]: pwwn [out]: port_id, pwwn - * BFA_PORT_AEN_SFP_REMOVE: [in]: pwwn [out]: port_id, pwwn - * BFA_PORT_AEN_SFP_POM: [in]: pwwn [out]: level, port_id, pwwn - * BFA_PORT_AEN_ENABLE: [in]: pwwn [out]: pwwn - * BFA_PORT_AEN_DISABLE: [in]: pwwn [out]: pwwn - * BFA_PORT_AEN_AUTH_ON: [in]: pwwn [out]: pwwn - * BFA_PORT_AEN_AUTH_OFF: [in]: pwwn [out]: pwwn - * BFA_PORT_AEN_DISCONNECT: [in]: pwwn [out]: pwwn - * BFA_PORT_AEN_QOS_NEG: [in]: pwwn [out]: pwwn - * BFA_PORT_AEN_FABRIC_NAME_CHANGE: [in]: pwwn, [out]: pwwn, fwwn - * - */ -enum bfa_port_aen_event { - BFA_PORT_AEN_ONLINE = 1, /* Physical Port online event */ - BFA_PORT_AEN_OFFLINE = 2, /* Physical Port offline event */ - BFA_PORT_AEN_RLIR = 3, /* RLIR event, not supported */ - BFA_PORT_AEN_SFP_INSERT = 4, /* SFP inserted event */ - BFA_PORT_AEN_SFP_REMOVE = 5, /* SFP removed event */ - BFA_PORT_AEN_SFP_POM = 6, /* SFP POM event */ - BFA_PORT_AEN_ENABLE = 7, /* Physical Port enable event */ - BFA_PORT_AEN_DISABLE = 8, /* Physical Port disable event */ - BFA_PORT_AEN_AUTH_ON = 9, /* Physical Port auth success event */ - BFA_PORT_AEN_AUTH_OFF = 10, /* Physical Port auth fail event */ - BFA_PORT_AEN_DISCONNECT = 11, /* Physical Port disconnect event */ - BFA_PORT_AEN_QOS_NEG = 12, /* Base Port QOS negotiation event */ - BFA_PORT_AEN_FABRIC_NAME_CHANGE = 13, /* Fabric Name/WWN change - * event */ - BFA_PORT_AEN_SFP_ACCESS_ERROR = 14, /* SFP read error event */ - BFA_PORT_AEN_SFP_UNSUPPORT = 15, /* Unsupported SFP event */ -}; - -enum bfa_port_aen_sfp_pom { - BFA_PORT_AEN_SFP_POM_GREEN = 1, /* Normal */ - BFA_PORT_AEN_SFP_POM_AMBER = 2, /* Warning */ - BFA_PORT_AEN_SFP_POM_RED = 3, /* Critical */ - BFA_PORT_AEN_SFP_POM_MAX = BFA_PORT_AEN_SFP_POM_RED -}; - -struct bfa_port_aen_data_s { - wwn_t pwwn; /* WWN of the physical port */ - wwn_t fwwn; /* WWN of the fabric port */ - s32 phy_port_num; /*! For SFP related events */ - s16 ioc_type; - s16 level; /* Only transitions will - * be informed */ - struct mac_s mac; /* MAC address of the ethernet port, - * applicable to CNA port only */ - s16 rsvd; -}; - -#endif /* __BFA_DEFS_PORT_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_pport.h b/drivers/scsi/bfa/include/defs/bfa_defs_pport.h deleted file mode 100644 index 2de675839c2f..000000000000 --- a/drivers/scsi/bfa/include/defs/bfa_defs_pport.h +++ /dev/null @@ -1,393 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFA_DEFS_PPORT_H__ -#define __BFA_DEFS_PPORT_H__ - -#include <bfa_os_inc.h> -#include <protocol/fc.h> -#include <defs/bfa_defs_types.h> -#include <defs/bfa_defs_qos.h> -#include <cna/pstats/phyport_defs.h> - -/* Modify char* port_stt[] in bfal_port.c if a new state was added */ -enum bfa_pport_states { - BFA_PPORT_ST_UNINIT = 1, - BFA_PPORT_ST_ENABLING_QWAIT = 2, - BFA_PPORT_ST_ENABLING = 3, - BFA_PPORT_ST_LINKDOWN = 4, - BFA_PPORT_ST_LINKUP = 5, - BFA_PPORT_ST_DISABLING_QWAIT = 6, - BFA_PPORT_ST_DISABLING = 7, - BFA_PPORT_ST_DISABLED = 8, - BFA_PPORT_ST_STOPPED = 9, - BFA_PPORT_ST_IOCDOWN = 10, - BFA_PPORT_ST_IOCDIS = 11, - BFA_PPORT_ST_FWMISMATCH = 12, - BFA_PPORT_ST_PREBOOT_DISABLED = 13, - BFA_PPORT_ST_MAX_STATE, -}; - -/** - * Port speed settings. Each specific speed is a bit field. Use multiple - * bits to specify speeds to be selected for auto-negotiation. - */ -enum bfa_pport_speed { - BFA_PPORT_SPEED_UNKNOWN = 0, - BFA_PPORT_SPEED_1GBPS = 1, - BFA_PPORT_SPEED_2GBPS = 2, - BFA_PPORT_SPEED_4GBPS = 4, - BFA_PPORT_SPEED_8GBPS = 8, - BFA_PPORT_SPEED_10GBPS = 10, - BFA_PPORT_SPEED_AUTO = - (BFA_PPORT_SPEED_1GBPS | BFA_PPORT_SPEED_2GBPS | - BFA_PPORT_SPEED_4GBPS | BFA_PPORT_SPEED_8GBPS), -}; - -/** - * Port operational type (in sync with SNIA port type). - */ -enum bfa_pport_type { - BFA_PPORT_TYPE_UNKNOWN = 1, /* port type is unknown */ - BFA_PPORT_TYPE_TRUNKED = 2, /* Trunked mode */ - BFA_PPORT_TYPE_NPORT = 5, /* P2P with switched fabric */ - BFA_PPORT_TYPE_NLPORT = 6, /* public loop */ - BFA_PPORT_TYPE_LPORT = 20, /* private loop */ - BFA_PPORT_TYPE_P2P = 21, /* P2P with no switched fabric */ - BFA_PPORT_TYPE_VPORT = 22, /* NPIV - virtual port */ -}; - -/** - * Port topology setting. A port's topology and fabric login status - * determine its operational type. - */ -enum bfa_pport_topology { - BFA_PPORT_TOPOLOGY_NONE = 0, /* No valid topology */ - BFA_PPORT_TOPOLOGY_P2P = 1, /* P2P only */ - BFA_PPORT_TOPOLOGY_LOOP = 2, /* LOOP topology */ - BFA_PPORT_TOPOLOGY_AUTO = 3, /* auto topology selection */ -}; - -/** - * Physical port loopback types. - */ -enum bfa_pport_opmode { - BFA_PPORT_OPMODE_NORMAL = 0x00, /* normal non-loopback mode */ - BFA_PPORT_OPMODE_LB_INT = 0x01, /* internal loop back */ - BFA_PPORT_OPMODE_LB_SLW = 0x02, /* serial link wrapback (serdes) */ - BFA_PPORT_OPMODE_LB_EXT = 0x04, /* external loop back (serdes) */ - BFA_PPORT_OPMODE_LB_CBL = 0x08, /* cabled loop back */ - BFA_PPORT_OPMODE_LB_NLINT = 0x20, /* NL_Port internal loopback */ -}; - -#define BFA_PPORT_OPMODE_LB_HARD(_mode) \ - ((_mode == BFA_PPORT_OPMODE_LB_INT) || \ - (_mode == BFA_PPORT_OPMODE_LB_SLW) || \ - (_mode == BFA_PPORT_OPMODE_LB_EXT)) - -/** - Port State (in sync with SNIA port state). - */ -enum bfa_pport_snia_state { - BFA_PPORT_STATE_UNKNOWN = 1, /* port is not initialized */ - BFA_PPORT_STATE_ONLINE = 2, /* port is ONLINE */ - BFA_PPORT_STATE_DISABLED = 3, /* port is disabled by user */ - BFA_PPORT_STATE_BYPASSED = 4, /* port is bypassed (in LOOP) */ - BFA_PPORT_STATE_DIAG = 5, /* port diagnostics is active */ - BFA_PPORT_STATE_LINKDOWN = 6, /* link is down */ - BFA_PPORT_STATE_LOOPBACK = 8, /* port is looped back */ -}; - -/** - * Port link state - */ -enum bfa_pport_linkstate { - BFA_PPORT_LINKUP = 1, /* Physical port/Trunk link up */ - BFA_PPORT_LINKDOWN = 2, /* Physical port/Trunk link down */ - BFA_PPORT_TRUNK_LINKDOWN = 3, /* Trunk link down (new tmaster) */ -}; - -/** - * Port link state event - */ -#define bfa_pport_event_t enum bfa_pport_linkstate - -/** - * Port link state reason code - */ -enum bfa_pport_linkstate_rsn { - BFA_PPORT_LINKSTATE_RSN_NONE = 0, - BFA_PPORT_LINKSTATE_RSN_DISABLED = 1, - BFA_PPORT_LINKSTATE_RSN_RX_NOS = 2, - BFA_PPORT_LINKSTATE_RSN_RX_OLS = 3, - BFA_PPORT_LINKSTATE_RSN_RX_LIP = 4, - BFA_PPORT_LINKSTATE_RSN_RX_LIPF7 = 5, - BFA_PPORT_LINKSTATE_RSN_SFP_REMOVED = 6, - BFA_PPORT_LINKSTATE_RSN_PORT_FAULT = 7, - BFA_PPORT_LINKSTATE_RSN_RX_LOS = 8, - BFA_PPORT_LINKSTATE_RSN_LOCAL_FAULT = 9, - BFA_PPORT_LINKSTATE_RSN_REMOTE_FAULT = 10, - BFA_PPORT_LINKSTATE_RSN_TIMEOUT = 11, - - - - /* CEE related reason codes/errors */ - CEE_LLDP_INFO_AGED_OUT = 20, - CEE_LLDP_SHUTDOWN_TLV_RCVD = 21, - CEE_PEER_NOT_ADVERTISE_DCBX = 22, - CEE_PEER_NOT_ADVERTISE_PG = 23, - CEE_PEER_NOT_ADVERTISE_PFC = 24, - CEE_PEER_NOT_ADVERTISE_FCOE = 25, - CEE_PG_NOT_COMPATIBLE = 26, - CEE_PFC_NOT_COMPATIBLE = 27, - CEE_FCOE_NOT_COMPATIBLE = 28, - CEE_BAD_PG_RCVD = 29, - CEE_BAD_BW_RCVD = 30, - CEE_BAD_PFC_RCVD = 31, - CEE_BAD_FCOE_PRI_RCVD = 32, - CEE_FCOE_PRI_PFC_OFF = 33, - CEE_DUP_CONTROL_TLV_RCVD = 34, - CEE_DUP_FEAT_TLV_RCVD = 35, - CEE_APPLY_NEW_CFG = 36, /* reason, not an error */ - CEE_PROTOCOL_INIT = 37, /* reason, not an error */ - CEE_PHY_LINK_DOWN = 38, - CEE_LLS_FCOE_ABSENT = 39, - CEE_LLS_FCOE_DOWN = 40 -}; - -/** - * Default Target Rate Limiting Speed. - */ -#define BFA_PPORT_DEF_TRL_SPEED BFA_PPORT_SPEED_1GBPS - -/** - * Physical port configuration - */ -struct bfa_pport_cfg_s { - u8 topology; /* bfa_pport_topology */ - u8 speed; /* enum bfa_pport_speed */ - u8 trunked; /* trunked or not */ - u8 qos_enabled; /* qos enabled or not */ - u8 trunk_ports; /* bitmap of trunked ports */ - u8 cfg_hardalpa; /* is hard alpa configured */ - u16 maxfrsize; /* maximum frame size */ - u8 hardalpa; /* configured hard alpa */ - u8 rx_bbcredit; /* receive buffer credits */ - u8 tx_bbcredit; /* transmit buffer credits */ - u8 ratelimit; /* ratelimit enabled or not */ - u8 trl_def_speed; /* ratelimit default speed */ - u8 rsvd[3]; - u16 path_tov; /* device path timeout */ - u16 q_depth; /* SCSI Queue depth */ -}; - -/** - * Port attribute values. - */ -struct bfa_pport_attr_s { - /* - * Static fields - */ - wwn_t nwwn; /* node wwn */ - wwn_t pwwn; /* port wwn */ - 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 */ - enum bfa_pport_speed speed_supported; /* supported speeds */ - bfa_boolean_t pbind_enabled; /* Will be set if Persistent binding - * enabled. Relevant only in Windows - */ - - /* - * Configured values - */ - struct bfa_pport_cfg_s pport_cfg; /* pport cfg */ - - /* - * Dynamic field - info from BFA - */ - enum bfa_pport_states port_state; /* current port state */ - enum bfa_pport_speed speed; /* current speed */ - enum bfa_pport_topology topology; /* current topology */ - bfa_boolean_t beacon; /* current beacon status */ - bfa_boolean_t link_e2e_beacon;/* set if link beacon on */ - bfa_boolean_t plog_enabled; /* set if portlog is enabled*/ - - /* - * Dynamic field - info from FCS - */ - u32 pid; /* port ID */ - enum bfa_pport_type port_type; /* current topology */ - u32 loopback; /* external loopback */ - u32 authfail; /* auth fail state */ - u32 rsvd2; /* padding for 64 bit */ -}; - -/** - * FC Port statistics. - */ -struct bfa_pport_fc_stats_s { - u64 secs_reset; /* Seconds since stats is reset */ - u64 tx_frames; /* Tx frames */ - u64 tx_words; /* Tx words */ - u64 tx_lip; /* Tx LIP */ - u64 tx_nos; /* Tx NOS */ - u64 tx_ols; /* Tx OLS */ - u64 tx_lr; /* Tx LR */ - u64 tx_lrr; /* Tx LRR */ - u64 rx_frames; /* Rx frames */ - u64 rx_words; /* Rx words */ - u64 lip_count; /* Rx LIP */ - u64 nos_count; /* Rx NOS */ - u64 ols_count; /* Rx OLS */ - u64 lr_count; /* Rx LR */ - u64 lrr_count; /* Rx LRR */ - u64 invalid_crcs; /* Rx CRC err frames */ - u64 invalid_crc_gd_eof; /* Rx CRC err good EOF frames */ - u64 undersized_frm; /* Rx undersized frames */ - u64 oversized_frm; /* Rx oversized frames */ - u64 bad_eof_frm; /* Rx frames with bad EOF */ - u64 error_frames; /* Errored frames */ - u64 dropped_frames; /* Dropped frames */ - u64 link_failures; /* Link Failure (LF) count */ - u64 loss_of_syncs; /* Loss of sync count */ - u64 loss_of_signals;/* Loss of signal count */ - u64 primseq_errs; /* Primitive sequence protocol err. */ - u64 bad_os_count; /* Invalid ordered sets */ - u64 err_enc_out; /* Encoding err nonframe_8b10b */ - u64 err_enc; /* Encoding err frame_8b10b */ -}; - -/** - * Eth Port statistics. - */ -struct bfa_pport_eth_stats_s { - u64 secs_reset; /* Seconds since stats is reset */ - u64 frame_64; /* Frames 64 bytes */ - u64 frame_65_127; /* Frames 65-127 bytes */ - u64 frame_128_255; /* Frames 128-255 bytes */ - u64 frame_256_511; /* Frames 256-511 bytes */ - u64 frame_512_1023; /* Frames 512-1023 bytes */ - u64 frame_1024_1518; /* Frames 1024-1518 bytes */ - u64 frame_1519_1522; /* Frames 1519-1522 bytes */ - u64 tx_bytes; /* Tx bytes */ - u64 tx_packets; /* Tx packets */ - u64 tx_mcast_packets; /* Tx multicast packets */ - u64 tx_bcast_packets; /* Tx broadcast packets */ - u64 tx_control_frame; /* Tx control frame */ - u64 tx_drop; /* Tx drops */ - u64 tx_jabber; /* Tx jabber */ - u64 tx_fcs_error; /* Tx FCS error */ - u64 tx_fragments; /* Tx fragments */ - u64 rx_bytes; /* Rx bytes */ - u64 rx_packets; /* Rx packets */ - u64 rx_mcast_packets; /* Rx multicast packets */ - u64 rx_bcast_packets; /* Rx broadcast packets */ - u64 rx_control_frames; /* Rx control frames */ - u64 rx_unknown_opcode; /* Rx unknown opcode */ - u64 rx_drop; /* Rx drops */ - u64 rx_jabber; /* Rx jabber */ - u64 rx_fcs_error; /* Rx FCS errors */ - u64 rx_alignment_error; /* Rx alignment errors */ - u64 rx_frame_length_error; /* Rx frame len errors */ - u64 rx_code_error; /* Rx code errors */ - u64 rx_fragments; /* Rx fragments */ - u64 rx_pause; /* Rx pause */ - 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_zero_pause; /* Rx FCoE zero pause */ - u64 tx_fcoe_pause; /* Tx FCoE pause */ - u64 tx_fcoe_zero_pause; /* Tx FCoE zero pause */ -}; - -/** - * Port statistics. - */ -union bfa_pport_stats_u { - struct bfa_pport_fc_stats_s fc; - struct bfa_pport_eth_stats_s eth; -}; - -/** - * Port FCP mappings. - */ -struct bfa_pport_fcpmap_s { - char osdevname[256]; - u32 bus; - u32 target; - u32 oslun; - u32 fcid; - wwn_t nwwn; - wwn_t pwwn; - u64 fcplun; - char luid[256]; -}; - -/** - * Port RNI */ -struct bfa_pport_rnid_s { - wwn_t wwn; - u32 unittype; - u32 portid; - u32 attached_nodes_num; - u16 ip_version; - u16 udp_port; - u8 ipaddr[16]; - u16 rsvd; - u16 topologydiscoveryflags; -}; - -struct bfa_fcport_fcf_s { - wwn_t name; /* FCF name */ - wwn_t fabric_name; /* Fabric Name */ - u8 fipenabled; /* FIP enabled or not */ - u8 fipfailed; /* FIP failed or not */ - u8 resv[2]; - u8 pri; /* FCF priority */ - u8 version; /* FIP version used */ - u8 available; /* Available for login */ - u8 fka_disabled; /* FKA is disabled */ - u8 maxsz_verified; /* FCoE max size verified */ - u8 fc_map[3]; /* FC map */ - u16 vlan; /* FCoE vlan tag/priority */ - u32 fka_adv_per; /* FIP ka advert. period */ - struct mac_s mac; /* FCF mac */ -}; - -/** - * Link state information - */ -struct bfa_pport_link_s { - u8 linkstate; /* Link state bfa_pport_linkstate */ - u8 linkstate_rsn; /* bfa_pport_linkstate_rsn_t */ - u8 topology; /* P2P/LOOP bfa_pport_topology */ - u8 speed; /* Link speed (1/2/4/8 G) */ - u32 linkstate_opt; /* Linkstate optional data (debug) */ - u8 trunked; /* Trunked or not (1 or 0) */ - u8 resvd[3]; - struct bfa_qos_attr_s qos_attr; /* QoS Attributes */ - union { - 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__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_qos.h b/drivers/scsi/bfa/include/defs/bfa_defs_qos.h deleted file mode 100644 index aadbacd1d2d7..000000000000 --- a/drivers/scsi/bfa/include/defs/bfa_defs_qos.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFA_DEFS_QOS_H__ -#define __BFA_DEFS_QOS_H__ - -/** - * QoS states - */ -enum bfa_qos_state { - BFA_QOS_ONLINE = 1, /* QoS is online */ - BFA_QOS_OFFLINE = 2, /* QoS is offline */ -}; - - -/** - * QoS Priority levels. - */ -enum bfa_qos_priority { - BFA_QOS_UNKNOWN = 0, - BFA_QOS_HIGH = 1, /* QoS Priority Level High */ - BFA_QOS_MED = 2, /* QoS Priority Level Medium */ - BFA_QOS_LOW = 3, /* QoS Priority Level Low */ -}; - - -/** - * QoS bandwidth allocation for each priority level - */ -enum bfa_qos_bw_alloc { - BFA_QOS_BW_HIGH = 60, /* bandwidth allocation for High */ - BFA_QOS_BW_MED = 30, /* bandwidth allocation for Medium */ - BFA_QOS_BW_LOW = 10, /* bandwidth allocation for Low */ -}; - -/** - * QoS attribute returned in QoS Query - */ -struct bfa_qos_attr_s { - enum bfa_qos_state state; /* QoS current state */ - u32 total_bb_cr; /* Total BB Credits */ -}; - -/** - * These fields should be displayed only from the CLI. - * There will be a separate BFAL API (get_qos_vc_attr ?) - * to retrieve this. - * - */ -#define BFA_QOS_MAX_VC 16 - -struct bfa_qos_vc_info_s { - u8 vc_credit; - u8 borrow_credit; - u8 priority; - u8 resvd; -}; - -struct bfa_qos_vc_attr_s { - u16 total_vc_count; /* Total VC Count */ - u16 shared_credit; - u32 elp_opmode_flags; - struct bfa_qos_vc_info_s vc_info[BFA_QOS_MAX_VC]; /* as many as - * total_vc_count */ -}; - -/** - * QoS statistics - */ -struct bfa_qos_stats_s { - u32 flogi_sent; /* QoS Flogi sent */ - u32 flogi_acc_recvd; /* QoS Flogi Acc received */ - u32 flogi_rjt_recvd; /* QoS Flogi rejects received */ - u32 flogi_retries; /* QoS Flogi retries */ - - u32 elp_recvd; /* QoS ELP received */ - u32 elp_accepted; /* QoS ELP Accepted */ - u32 elp_rejected; /* QoS ELP rejected */ - u32 elp_dropped; /* QoS ELP dropped */ - - u32 qos_rscn_recvd; /* QoS RSCN received */ - u32 rsvd; /* padding for 64 bit alignment */ -}; - -#endif /* __BFA_DEFS_QOS_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_rport.h b/drivers/scsi/bfa/include/defs/bfa_defs_rport.h deleted file mode 100644 index e0af59d6d2f6..000000000000 --- a/drivers/scsi/bfa/include/defs/bfa_defs_rport.h +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFA_DEFS_RPORT_H__ -#define __BFA_DEFS_RPORT_H__ - -#include <bfa_os_inc.h> -#include <protocol/types.h> -#include <defs/bfa_defs_pport.h> -#include <defs/bfa_defs_port.h> -#include <defs/bfa_defs_qos.h> - -/** - * FCS remote port states - */ -enum bfa_rport_state { - BFA_RPORT_UNINIT = 0, /* PORT is not yet initialized */ - BFA_RPORT_OFFLINE = 1, /* rport is offline */ - BFA_RPORT_PLOGI = 2, /* PLOGI to rport is in progress */ - BFA_RPORT_ONLINE = 3, /* login to rport is complete */ - BFA_RPORT_PLOGI_RETRY = 4, /* retrying login to rport */ - BFA_RPORT_NSQUERY = 5, /* nameserver query */ - BFA_RPORT_ADISC = 6, /* ADISC authentication */ - BFA_RPORT_LOGO = 7, /* logging out with rport */ - BFA_RPORT_LOGORCV = 8, /* handling LOGO from rport */ - BFA_RPORT_NSDISC = 9, /* re-discover rport */ -}; - -/** - * Rport Scsi Function : Initiator/Target. - */ -enum bfa_rport_function { - BFA_RPORT_INITIATOR = 0x01, /* SCSI Initiator */ - BFA_RPORT_TARGET = 0x02, /* SCSI Target */ -}; - -/** - * port/node symbolic names for rport - */ -#define BFA_RPORT_SYMNAME_MAXLEN 255 -struct bfa_rport_symname_s { - char symname[BFA_RPORT_SYMNAME_MAXLEN]; -}; - -struct bfa_rport_hal_stats_s { - u32 sm_un_cr; /* uninit: create events */ - u32 sm_un_unexp; /* uninit: exception events */ - u32 sm_cr_on; /* created: online events */ - u32 sm_cr_del; /* created: delete events */ - u32 sm_cr_hwf; /* created: IOC down */ - u32 sm_cr_unexp; /* created: exception events */ - u32 sm_fwc_rsp; /* fw create: f/w responses */ - u32 sm_fwc_del; /* fw create: delete events */ - u32 sm_fwc_off; /* fw create: offline events */ - u32 sm_fwc_hwf; /* fw create: IOC down */ - u32 sm_fwc_unexp; /* fw create: exception events*/ - u32 sm_on_off; /* online: offline events */ - u32 sm_on_del; /* online: delete events */ - u32 sm_on_hwf; /* online: IOC down events */ - u32 sm_on_unexp; /* online: exception events */ - u32 sm_fwd_rsp; /* fw delete: fw responses */ - u32 sm_fwd_del; /* fw delete: delete events */ - u32 sm_fwd_hwf; /* fw delete: IOC down events */ - u32 sm_fwd_unexp; /* fw delete: exception events*/ - u32 sm_off_del; /* offline: delete events */ - u32 sm_off_on; /* offline: online events */ - u32 sm_off_hwf; /* offline: IOC down events */ - u32 sm_off_unexp; /* offline: exception events */ - u32 sm_del_fwrsp; /* delete: fw responses */ - u32 sm_del_hwf; /* delete: IOC down events */ - u32 sm_del_unexp; /* delete: exception events */ - u32 sm_delp_fwrsp; /* delete pend: fw responses */ - u32 sm_delp_hwf; /* delete pend: IOC downs */ - u32 sm_delp_unexp; /* delete pend: exceptions */ - u32 sm_offp_fwrsp; /* off-pending: fw responses */ - u32 sm_offp_del; /* off-pending: deletes */ - u32 sm_offp_hwf; /* off-pending: IOC downs */ - u32 sm_offp_unexp; /* off-pending: exceptions */ - u32 sm_iocd_off; /* IOC down: offline events */ - u32 sm_iocd_del; /* IOC down: delete events */ - u32 sm_iocd_on; /* IOC down: online events */ - u32 sm_iocd_unexp; /* IOC down: exceptions */ - u32 rsvd; -}; - -/** - * FCS remote port statistics - */ -struct bfa_rport_stats_s { - u32 offlines; /* remote port offline count */ - u32 onlines; /* remote port online count */ - u32 rscns; /* RSCN affecting rport */ - u32 plogis; /* plogis sent */ - u32 plogi_accs; /* plogi accepts */ - u32 plogi_timeouts; /* plogi timeouts */ - u32 plogi_rejects; /* rcvd plogi rejects */ - u32 plogi_failed; /* local failure */ - u32 plogi_rcvd; /* plogis rcvd */ - u32 prli_rcvd; /* inbound PRLIs */ - u32 adisc_rcvd; /* ADISCs received */ - u32 adisc_rejects; /* recvd ADISC rejects */ - u32 adisc_sent; /* ADISC requests sent */ - u32 adisc_accs; /* ADISC accepted by rport */ - u32 adisc_failed; /* ADISC failed (no response) */ - u32 adisc_rejected; /* ADISC rejected by us */ - u32 logos; /* logos sent */ - u32 logo_accs; /* LOGO accepts from rport */ - u32 logo_failed; /* LOGO failures */ - u32 logo_rejected; /* LOGO rejects from rport */ - u32 logo_rcvd; /* LOGO from remote port */ - - u32 rpsc_rcvd; /* RPSC received */ - u32 rpsc_rejects; /* recvd RPSC rejects */ - u32 rpsc_sent; /* RPSC requests sent */ - u32 rpsc_accs; /* RPSC accepted by rport */ - u32 rpsc_failed; /* RPSC failed (no response) */ - u32 rpsc_rejected; /* RPSC rejected by us */ - - u32 rsvd; - struct bfa_rport_hal_stats_s hal_stats; /* BFA rport stats */ -}; - -/** - * Rport's QoS attributes - */ -struct bfa_rport_qos_attr_s { - enum bfa_qos_priority qos_priority; /* rport's QoS priority */ - u32 qos_flow_id; /* QoS flow Id */ -}; - -/** - * FCS remote port attributes returned in queries - */ -struct bfa_rport_attr_s { - wwn_t nwwn; /* node wwn */ - wwn_t pwwn; /* port wwn */ - enum fc_cos cos_supported; /* supported class of services */ - u32 pid; /* port ID */ - u32 df_sz; /* Max payload size */ - enum bfa_rport_state state; /* Rport State machine state */ - enum fc_cos fc_cos; /* FC classes of services */ - bfa_boolean_t cisc; /* CISC capable device */ - struct bfa_rport_symname_s symname; /* Symbolic Name */ - enum bfa_rport_function scsi_function; /* Initiator/Target */ - struct bfa_rport_qos_attr_s qos_attr; /* qos attributes */ - enum bfa_pport_speed curr_speed; /* operating speed got from - * RPSC ELS. UNKNOWN, if RPSC - * is not supported */ - bfa_boolean_t trl_enforced; /* TRL enforced ? TRUE/FALSE */ - enum bfa_pport_speed assigned_speed; /* Speed assigned by the user. - * will be used if RPSC is not - * supported by the rport */ -}; - -#define bfa_rport_aen_qos_data_t struct bfa_rport_qos_attr_s - -/** - * BFA remote port events - * Arguments below are in BFAL context from Mgmt - * BFA_RPORT_AEN_ONLINE: [in]: lpwwn [out]: vf_id, lpwwn, rpwwn - * BFA_RPORT_AEN_OFFLINE: [in]: lpwwn [out]: vf_id, lpwwn, rpwwn - * BFA_RPORT_AEN_DISCONNECT:[in]: lpwwn [out]: vf_id, lpwwn, rpwwn - * BFA_RPORT_AEN_QOS_PRIO: [in]: lpwwn [out]: vf_id, lpwwn, rpwwn, prio - * BFA_RPORT_AEN_QOS_FLOWID:[in]: lpwwn [out]: vf_id, lpwwn, rpwwn, flow_id - */ -enum bfa_rport_aen_event { - BFA_RPORT_AEN_ONLINE = 1, /* RPort online event */ - BFA_RPORT_AEN_OFFLINE = 2, /* RPort offline event */ - BFA_RPORT_AEN_DISCONNECT = 3, /* RPort disconnect event */ - BFA_RPORT_AEN_QOS_PRIO = 4, /* QOS priority change event */ - BFA_RPORT_AEN_QOS_FLOWID = 5, /* QOS flow Id change event */ -}; - -struct bfa_rport_aen_data_s { - u16 vf_id; /* vf_id of this logical port */ - u16 rsvd[3]; - wwn_t ppwwn; /* WWN of its physical port */ - wwn_t lpwwn; /* WWN of this logical port */ - wwn_t rpwwn; /* WWN of this remote port */ - union { - bfa_rport_aen_qos_data_t qos; - } priv; -}; - -#endif /* __BFA_DEFS_RPORT_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_status.h b/drivers/scsi/bfa/include/defs/bfa_defs_status.h deleted file mode 100644 index 6eb4e62096fc..000000000000 --- a/drivers/scsi/bfa/include/defs/bfa_defs_status.h +++ /dev/null @@ -1,282 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ -#ifndef __BFA_DEFS_STATUS_H__ -#define __BFA_DEFS_STATUS_H__ - -/** - * API status return values - * - * NOTE: The error msgs are auto generated from the comments. Only singe line - * comments are supported - */ -enum bfa_status { - BFA_STATUS_OK = 0, /* Success */ - BFA_STATUS_FAILED = 1, /* Operation failed */ - BFA_STATUS_EINVAL = 2, /* Invalid params Check input - * parameters */ - BFA_STATUS_ENOMEM = 3, /* Out of resources */ - BFA_STATUS_ENOSYS = 4, /* Function not implemented */ - BFA_STATUS_ETIMER = 5, /* Timer expired - Retry, if - * persists, contact support */ - BFA_STATUS_EPROTOCOL = 6, /* Protocol error */ - BFA_STATUS_ENOFCPORTS = 7, /* No FC ports resources */ - BFA_STATUS_NOFLASH = 8, /* Flash not present */ - BFA_STATUS_BADFLASH = 9, /* Flash is corrupted or bad */ - BFA_STATUS_SFP_UNSUPP = 10, /* Unsupported SFP - Replace SFP */ - BFA_STATUS_UNKNOWN_VFID = 11, /* VF_ID not found */ - BFA_STATUS_DATACORRUPTED = 12, /* Diag returned data corrupted - * contact support */ - BFA_STATUS_DEVBUSY = 13, /* Device busy - Retry operation */ - BFA_STATUS_ABORTED = 14, /* Operation aborted */ - BFA_STATUS_NODEV = 15, /* Dev is not present */ - BFA_STATUS_HDMA_FAILED = 16, /* Host dma failed contact support */ - BFA_STATUS_FLASH_BAD_LEN = 17, /* Flash bad length */ - BFA_STATUS_UNKNOWN_LWWN = 18, /* LPORT PWWN not found */ - BFA_STATUS_UNKNOWN_RWWN = 19, /* RPORT PWWN not found */ - BFA_STATUS_FCPT_LS_RJT = 20, /* Got LS_RJT for FC Pass - * through Req */ - BFA_STATUS_VPORT_EXISTS = 21, /* VPORT already exists */ - BFA_STATUS_VPORT_MAX = 22, /* Reached max VPORT supported - * limit */ - BFA_STATUS_UNSUPP_SPEED = 23, /* Invalid Speed Check speed - * setting */ - BFA_STATUS_INVLD_DFSZ = 24, /* Invalid Max data field size */ - BFA_STATUS_CNFG_FAILED = 25, /* Setting can not be persisted */ - BFA_STATUS_CMD_NOTSUPP = 26, /* Command/API not supported */ - BFA_STATUS_NO_ADAPTER = 27, /* No Brocade Adapter Found */ - BFA_STATUS_LINKDOWN = 28, /* Link is down - Check or replace - * SFP/cable */ - BFA_STATUS_FABRIC_RJT = 29, /* Reject from attached fabric */ - BFA_STATUS_UNKNOWN_VWWN = 30, /* VPORT PWWN not found */ - BFA_STATUS_NSLOGIN_FAILED = 31, /* Nameserver login failed */ - BFA_STATUS_NO_RPORTS = 32, /* No remote ports found */ - BFA_STATUS_NSQUERY_FAILED = 33, /* Nameserver query failed */ - BFA_STATUS_PORT_OFFLINE = 34, /* Port is not online */ - BFA_STATUS_RPORT_OFFLINE = 35, /* RPORT is not online */ - BFA_STATUS_TGTOPEN_FAILED = 36, /* Remote SCSI target open failed */ - BFA_STATUS_BAD_LUNS = 37, /* No valid LUNs found */ - BFA_STATUS_IO_FAILURE = 38, /* SCSI target IO failure */ - BFA_STATUS_NO_FABRIC = 39, /* No switched fabric present */ - BFA_STATUS_EBADF = 40, /* Bad file descriptor */ - BFA_STATUS_EINTR = 41, /* A signal was caught during ioctl */ - BFA_STATUS_EIO = 42, /* I/O error */ - BFA_STATUS_ENOTTY = 43, /* Inappropriate I/O control - * operation */ - BFA_STATUS_ENXIO = 44, /* No such device or address */ - BFA_STATUS_EFOPEN = 45, /* Failed to open file */ - BFA_STATUS_VPORT_WWN_BP = 46, /* WWN is same as base port's WWN */ - BFA_STATUS_PORT_NOT_DISABLED = 47, /* Port not disabled disable port - * first */ - BFA_STATUS_BADFRMHDR = 48, /* Bad frame header */ - BFA_STATUS_BADFRMSZ = 49, /* Bad frame size check and replace - * SFP/cable */ - BFA_STATUS_MISSINGFRM = 50, /* Missing frame check and replace - * SFP/cable 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 - * rport */ - BFA_STATUS_CHECKSUM_FAIL = 53, /* checksum failure */ - BFA_STATUS_GZME_FAILED = 54, /* Get zone member query failed */ - BFA_STATUS_SCSISTART_REQD = 55, /* SCSI disk require START command */ - BFA_STATUS_IOC_FAILURE = 56, /* IOC failure - Retry, if persists - * contact support */ - BFA_STATUS_INVALID_WWN = 57, /* Invalid WWN */ - BFA_STATUS_MISMATCH = 58, /* Version mismatch */ - BFA_STATUS_IOC_ENABLED = 59, /* IOC is already enabled */ - BFA_STATUS_ADAPTER_ENABLED = 60, /* Adapter is not disabled disable - * adapter first */ - BFA_STATUS_IOC_NON_OP = 61, /* IOC is not operational. Enable IOC - * and if it still fails, - * contact support */ - BFA_STATUS_ADDR_MAP_FAILURE = 62, /* PCI base address not mapped - * in OS */ - BFA_STATUS_SAME_NAME = 63, /* Name exists! use a different - * name */ - BFA_STATUS_PENDING = 64, /* API completes asynchronously */ - BFA_STATUS_8G_SPD = 65, /* Speed setting not valid for - * 8G HBA */ - BFA_STATUS_4G_SPD = 66, /* Speed setting not valid for - * 4G HBA */ - BFA_STATUS_AD_IS_ENABLE = 67, /* Adapter is already enabled */ - BFA_STATUS_EINVAL_TOV = 68, /* Invalid path failover TOV */ - BFA_STATUS_EINVAL_QDEPTH = 69, /* Invalid queue depth value */ - BFA_STATUS_VERSION_FAIL = 70, /* Application/Driver version - * mismatch */ - BFA_STATUS_DIAG_BUSY = 71, /* diag busy */ - BFA_STATUS_BEACON_ON = 72, /* Port Beacon already on */ - BFA_STATUS_BEACON_OFF = 73, /* Port Beacon already off */ - BFA_STATUS_LBEACON_ON = 74, /* Link End-to-End Beacon already - * on */ - BFA_STATUS_LBEACON_OFF = 75, /* Link End-to-End Beacon already - * off */ - BFA_STATUS_PORT_NOT_INITED = 76, /* Port not initialized */ - BFA_STATUS_RPSC_ENABLED = 77, /* Target has a valid speed */ - BFA_STATUS_ENOFSAVE = 78, /* No saved firmware trace */ - BFA_STATUS_BAD_FILE = 79, /* Not a valid Brocade Boot Code - * file */ - BFA_STATUS_RLIM_EN = 80, /* Target rate limiting is already - * enabled */ - BFA_STATUS_RLIM_DIS = 81, /* Target rate limiting is already - * disabled */ - BFA_STATUS_IOC_DISABLED = 82, /* IOC is already disabled */ - BFA_STATUS_ADAPTER_DISABLED = 83, /* Adapter is already disabled */ - BFA_STATUS_BIOS_DISABLED = 84, /* Bios is already disabled */ - BFA_STATUS_AUTH_ENABLED = 85, /* Authentication is already - * enabled */ - BFA_STATUS_AUTH_DISABLED = 86, /* Authentication is already - * disabled */ - BFA_STATUS_ERROR_TRL_ENABLED = 87, /* Target rate limiting is - * enabled */ - BFA_STATUS_ERROR_QOS_ENABLED = 88, /* QoS is enabled */ - BFA_STATUS_NO_SFP_DEV = 89, /* No SFP device check or replace SFP */ - BFA_STATUS_MEMTEST_FAILED = 90, /* Memory test failed contact - * support */ - BFA_STATUS_INVALID_DEVID = 91, /* Invalid device id provided */ - BFA_STATUS_QOS_ENABLED = 92, /* QOS is already enabled */ - BFA_STATUS_QOS_DISABLED = 93, /* QOS is already disabled */ - BFA_STATUS_INCORRECT_DRV_CONFIG = 94, /* Check configuration - * key/value pair */ - BFA_STATUS_REG_FAIL = 95, /* Can't read windows registry */ - BFA_STATUS_IM_INV_CODE = 96, /* Invalid IOCTL code */ - BFA_STATUS_IM_INV_VLAN = 97, /* Invalid VLAN ID */ - BFA_STATUS_IM_INV_ADAPT_NAME = 98, /* Invalid adapter name */ - BFA_STATUS_IM_LOW_RESOURCES = 99, /* Memory allocation failure in - * driver */ - BFA_STATUS_IM_VLANID_IS_PVID = 100, /* Given VLAN id same as PVID */ - BFA_STATUS_IM_VLANID_EXISTS = 101, /* Given VLAN id already exists */ - BFA_STATUS_IM_FW_UPDATE_FAIL = 102, /* Updating firmware with new - * VLAN ID failed */ - BFA_STATUS_PORTLOG_ENABLED = 103, /* Port Log is already enabled */ - BFA_STATUS_PORTLOG_DISABLED = 104, /* Port Log is already disabled */ - BFA_STATUS_FILE_NOT_FOUND = 105, /* Specified file could not be - * found */ - BFA_STATUS_QOS_FC_ONLY = 106, /* QOS can be enabled for FC mode - * only */ - BFA_STATUS_RLIM_FC_ONLY = 107, /* RATELIM can be enabled for FC mode - * only */ - BFA_STATUS_CT_SPD = 108, /* Invalid speed selection for Catapult. */ - BFA_STATUS_LEDTEST_OP = 109, /* LED test is operating */ - BFA_STATUS_CEE_NOT_DN = 110, /* eth port is not at down state, please - * bring down first */ - BFA_STATUS_10G_SPD = 111, /* Speed setting not valid for 10G CNA */ - BFA_STATUS_IM_INV_TEAM_NAME = 112, /* Invalid team name */ - BFA_STATUS_IM_DUP_TEAM_NAME = 113, /* Given team name already - * exists */ - BFA_STATUS_IM_ADAPT_ALREADY_IN_TEAM = 114, /* Given adapter is part - * of another team */ - BFA_STATUS_IM_ADAPT_HAS_VLANS = 115, /* Adapter has VLANs configured. - * Delete all VLANs to become - * part of the team */ - BFA_STATUS_IM_PVID_MISMATCH = 116, /* Mismatching PVIDs configured - * for adapters */ - BFA_STATUS_IM_LINK_SPEED_MISMATCH = 117, /* Mismatching link speeds - * configured for adapters */ - BFA_STATUS_IM_MTU_MISMATCH = 118, /* Mismatching MTUs configured for - * adapters */ - BFA_STATUS_IM_RSS_MISMATCH = 119, /* Mismatching RSS parameters - * configured for adapters */ - BFA_STATUS_IM_HDS_MISMATCH = 120, /* Mismatching HDS parameters - * configured for adapters */ - BFA_STATUS_IM_OFFLOAD_MISMATCH = 121, /* Mismatching offload - * parameters configured for - * adapters */ - BFA_STATUS_IM_PORT_PARAMS = 122, /* Error setting port parameters */ - BFA_STATUS_IM_PORT_NOT_IN_TEAM = 123, /* Port is not part of team */ - BFA_STATUS_IM_CANNOT_REM_PRI = 124, /* Primary adapter cannot be - * removed. Change primary before - * removing */ - BFA_STATUS_IM_MAX_PORTS_REACHED = 125, /* Exceeding maximum ports - * per team */ - BFA_STATUS_IM_LAST_PORT_DELETE = 126, /* Last port in team being - * deleted */ - BFA_STATUS_IM_NO_DRIVER = 127, /* IM driver is not installed */ - BFA_STATUS_IM_MAX_VLANS_REACHED = 128, /* Exceeding maximum VLANs - * per port */ - BFA_STATUS_TOMCAT_SPD_NOT_ALLOWED = 129, /* Bios speed config not - * allowed for CNA */ - BFA_STATUS_NO_MINPORT_DRIVER = 130, /* Miniport driver is not - * loaded */ - BFA_STATUS_CARD_TYPE_MISMATCH = 131, /* Card type mismatch */ - BFA_STATUS_BAD_ASICBLK = 132, /* Bad ASIC block */ - BFA_STATUS_NO_DRIVER = 133, /* 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 */ - BFA_STATUS_IM_PVID_REMOVE = 137, /* Cannot remove port VLAN (PVID) */ - BFA_STATUS_IM_PVID_EDIT = 138, /* Cannot edit port VLAN (PVID) */ - BFA_STATUS_CNA_NO_BOOT = 139, /* Boot upload not allowed for CNA */ - BFA_STATUS_IM_PVID_NON_ZERO = 140, /* Port VLAN ID (PVID) is Set to - * Non-Zero Value */ - BFA_STATUS_IM_INETCFG_LOCK_FAILED = 141, /* Acquiring Network - * Subsystem Lock Failed.Please - * try after some time */ - BFA_STATUS_IM_GET_INETCFG_FAILED = 142, /* Acquiring Network Subsystem - * handle Failed. Please try - * after some time */ - BFA_STATUS_IM_NOT_BOUND = 143, /* IM driver is not active */ - BFA_STATUS_INSUFFICIENT_PERMS = 144, /* User doesn't have sufficient - * permissions to execute the BCU - * application */ - BFA_STATUS_IM_INV_VLAN_NAME = 145, /* Invalid/Reserved VLAN name - * string. The name is not allowed - * for the normal VLAN */ - BFA_STATUS_CMD_NOTSUPP_CNA = 146, /* Command not supported for CNA */ - 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 - * failed */ - BFA_STATUS_IM_PORT_IN_TEAM = 150, /* Port is already part of the - * team */ - BFA_STATUS_IM_VLAN_NOT_FOUND = 151, /* VLAN ID doesn't exists */ - BFA_STATUS_IM_TEAM_NOT_FOUND = 152, /* Teaming configuration doesn't - * exists */ - 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_DEVID_MISSING = 155, /* Boot image is not for the adapter(s) - * installed */ - 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 - -enum bfa_eproto_status { - BFA_EPROTO_BAD_ACCEPT = 0, - BFA_EPROTO_UNKNOWN_RSP = 1 -}; -#define bfa_eproto_status_t enum bfa_eproto_status - -#endif /* __BFA_DEFS_STATUS_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_tin.h b/drivers/scsi/bfa/include/defs/bfa_defs_tin.h deleted file mode 100644 index e05a2db7abed..000000000000 --- a/drivers/scsi/bfa/include/defs/bfa_defs_tin.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFA_DEFS_TIN_H__ -#define __BFA_DEFS_TIN_H__ - -#include <protocol/types.h> -#include <protocol/fc.h> - -/** - * FCS tin states - */ -enum bfa_tin_state_e { - BFA_TIN_SM_OFFLINE = 0, /* tin is offline */ - BFA_TIN_SM_WOS_LOGIN = 1, /* Waiting PRLI ACC/RJT from ULP */ - BFA_TIN_SM_WFW_ONLINE = 2, /* Waiting ACK to PRLI ACC from FW */ - BFA_TIN_SM_ONLINE = 3, /* tin login is complete */ - BFA_TIN_SM_WIO_RELOGIN = 4, /* tin relogin is in progress */ - BFA_TIN_SM_WIO_LOGOUT = 5, /* Processing of PRLO req from - * Initiator is in progress - */ - BFA_TIN_SM_WOS_LOGOUT = 6, /* Processing of PRLO req from - * Initiator is in progress - */ - BFA_TIN_SM_WIO_CLEAN = 7, /* Waiting for IO cleanup before tin - * is offline. This can be triggered - * by RPORT LOGO (rcvd/sent) or by - * PRLO (rcvd/sent) - */ -}; - -struct bfa_prli_req_s { - struct fchs_s fchs; - struct fc_prli_s prli_payload; -}; - -struct bfa_prlo_req_s { - struct fchs_s fchs; - struct fc_prlo_s prlo_payload; -}; - -void bfa_tin_send_login_rsp(void *bfa_tin, u32 login_rsp, - struct fc_ls_rjt_s rjt_payload); -void bfa_tin_send_logout_rsp(void *bfa_tin, u32 logout_rsp, - struct fc_ls_rjt_s rjt_payload); -/** - * FCS target port statistics - */ -struct bfa_tin_stats_s { - u32 onlines; /* ITN nexus onlines (PRLI done) */ - u32 offlines; /* ITN Nexus offlines */ - u32 prli_req_parse_err; /* prli req parsing errors */ - u32 prli_rsp_rjt; /* num prli rsp rejects sent */ - u32 prli_rsp_acc; /* num prli rsp accepts sent */ - u32 cleanup_comps; /* ITN cleanup completions */ -}; - -/** - * FCS tin attributes returned in queries - */ -struct bfa_tin_attr_s { - enum bfa_tin_state_e state; - u8 seq_retry; /* Sequence retry supported */ - u8 rsvd[3]; -}; - -/** - * BFA TIN async event data structure for BFAL - */ -enum bfa_tin_aen_event { - BFA_TIN_AEN_ONLINE = 1, /* Target online */ - BFA_TIN_AEN_OFFLINE = 2, /* Target offline */ - BFA_TIN_AEN_DISCONNECT = 3, /* Target disconnected */ -}; - -/** - * BFA TIN event data structure. - */ -struct bfa_tin_aen_data_s { - u16 vf_id; /* vf_id of the IT nexus */ - u16 rsvd[3]; - wwn_t lpwwn; /* WWN of logical port */ - wwn_t rpwwn; /* WWN of remote(target) port */ -}; - -/** - * Below APIs are needed from BFA driver - * Move these to BFA driver public header file? - */ -/* TIN rcvd new PRLI & gets bfad_tin_t ptr from driver this callback */ -void *bfad_tin_rcvd_login_req(void *bfad_tm_port, void *bfa_tin, - wwn_t rp_wwn, u32 rp_fcid, - struct bfa_prli_req_s prli_req); -/* TIN rcvd new PRLO */ -void bfad_tin_rcvd_logout_req(void *bfad_tin, wwn_t rp_wwn, u32 rp_fcid, - struct bfa_prlo_req_s prlo_req); -/* TIN is online and ready for IO */ -void bfad_tin_online(void *bfad_tin); -/* TIN is offline and BFA driver can shutdown its upper stack */ -void bfad_tin_offline(void *bfad_tin); -/* TIN does not need this BFA driver tin tag anymore, so can be freed */ -void bfad_tin_res_free(void *bfad_tin); - -#endif /* __BFA_DEFS_TIN_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_tsensor.h b/drivers/scsi/bfa/include/defs/bfa_defs_tsensor.h deleted file mode 100644 index ade763dbc8ce..000000000000 --- a/drivers/scsi/bfa/include/defs/bfa_defs_tsensor.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFA_DEFS_TSENSOR_H__ -#define __BFA_DEFS_TSENSOR_H__ - -#include <bfa_os_inc.h> -#include <defs/bfa_defs_types.h> - -/** - * Temperature sensor status values - */ -enum bfa_tsensor_status { - BFA_TSENSOR_STATUS_UNKNOWN = 1, /* unknown status */ - BFA_TSENSOR_STATUS_FAULTY = 2, /* sensor is faulty */ - BFA_TSENSOR_STATUS_BELOW_MIN = 3, /* temperature below mininum */ - BFA_TSENSOR_STATUS_NOMINAL = 4, /* normal temperature */ - BFA_TSENSOR_STATUS_ABOVE_MAX = 5, /* temperature above maximum */ -}; - -/** - * Temperature sensor attribute - */ -struct bfa_tsensor_attr_s { - enum bfa_tsensor_status status; /* temperature sensor status */ - u32 value; /* current temperature in celsius */ -}; - -#endif /* __BFA_DEFS_TSENSOR_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_types.h b/drivers/scsi/bfa/include/defs/bfa_defs_types.h deleted file mode 100644 index 4348332b107a..000000000000 --- a/drivers/scsi/bfa/include/defs/bfa_defs_types.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ -#ifndef __BFA_DEFS_TYPES_H__ -#define __BFA_DEFS_TYPES_H__ - -#include <bfa_os_inc.h> - -enum bfa_boolean { - BFA_FALSE = 0, - BFA_TRUE = 1 -}; -#define bfa_boolean_t enum bfa_boolean - -#define BFA_STRING_32 32 - -#endif /* __BFA_DEFS_TYPES_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_version.h b/drivers/scsi/bfa/include/defs/bfa_defs_version.h deleted file mode 100644 index f8902a2c9aad..000000000000 --- a/drivers/scsi/bfa/include/defs/bfa_defs_version.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ -#ifndef __BFA_DEFS_VERSION_H__ -#define __BFA_DEFS_VERSION_H__ - -#define BFA_VERSION_LEN 64 - -#endif diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_vf.h b/drivers/scsi/bfa/include/defs/bfa_defs_vf.h deleted file mode 100644 index 3235be5e9423..000000000000 --- a/drivers/scsi/bfa/include/defs/bfa_defs_vf.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFA_DEFS_VF_H__ -#define __BFA_DEFS_VF_H__ - -#include <bfa_os_inc.h> -#include <defs/bfa_defs_port.h> -#include <protocol/types.h> - -/** - * VF states - */ -enum bfa_vf_state { - BFA_VF_UNINIT = 0, /* fabric is not yet initialized */ - BFA_VF_LINK_DOWN = 1, /* link is down */ - BFA_VF_FLOGI = 2, /* flogi is in progress */ - BFA_VF_AUTH = 3, /* authentication in progress */ - BFA_VF_NOFABRIC = 4, /* fabric is not present */ - BFA_VF_ONLINE = 5, /* login to fabric is complete */ - BFA_VF_EVFP = 6, /* EVFP is in progress */ - BFA_VF_ISOLATED = 7, /* port isolated due to vf_id mismatch */ -}; - -/** - * VF statistics - */ -struct bfa_vf_stats_s { - u32 flogi_sent; /* Num FLOGIs sent */ - u32 flogi_rsp_err; /* FLOGI response errors */ - u32 flogi_acc_err; /* FLOGI accept errors */ - u32 flogi_accepts; /* FLOGI accepts received */ - u32 flogi_rejects; /* FLOGI rejects received */ - u32 flogi_unknown_rsp; /* Unknown responses for FLOGI */ - u32 flogi_alloc_wait; /* Allocation waits prior to - * sending FLOGI - */ - u32 flogi_rcvd; /* FLOGIs received */ - u32 flogi_rejected; /* Incoming FLOGIs rejected */ - u32 fabric_onlines; /* Internal fabric online - * notification sent to other - * modules - */ - u32 fabric_offlines; /* Internal fabric offline - * notification sent to other - * modules - */ - u32 resvd; -}; - -/** - * VF attributes returned in queries - */ -struct bfa_vf_attr_s { - enum bfa_vf_state state; /* VF state */ - u32 rsvd; - wwn_t fabric_name; /* fabric name */ -}; - -#endif /* __BFA_DEFS_VF_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_vport.h b/drivers/scsi/bfa/include/defs/bfa_defs_vport.h deleted file mode 100644 index 9f021f43b3b4..000000000000 --- a/drivers/scsi/bfa/include/defs/bfa_defs_vport.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFA_DEFS_VPORT_H__ -#define __BFA_DEFS_VPORT_H__ - -#include <bfa_os_inc.h> -#include <defs/bfa_defs_port.h> -#include <protocol/types.h> - -/** - * VPORT states - */ -enum bfa_vport_state { - BFA_FCS_VPORT_UNINIT = 0, - BFA_FCS_VPORT_CREATED = 1, - BFA_FCS_VPORT_OFFLINE = 1, - BFA_FCS_VPORT_FDISC_SEND = 2, - BFA_FCS_VPORT_FDISC = 3, - BFA_FCS_VPORT_FDISC_RETRY = 4, - BFA_FCS_VPORT_ONLINE = 5, - BFA_FCS_VPORT_DELETING = 6, - BFA_FCS_VPORT_CLEANUP = 6, - BFA_FCS_VPORT_LOGO_SEND = 7, - BFA_FCS_VPORT_LOGO = 8, - BFA_FCS_VPORT_ERROR = 9, - BFA_FCS_VPORT_MAX_STATE, -}; - -/** - * vport statistics - */ -struct bfa_vport_stats_s { - struct bfa_port_stats_s port_stats; /* base class (port) stats */ - /* - * TODO - remove - */ - - u32 fdisc_sent; /* num fdisc sent */ - u32 fdisc_accepts; /* fdisc accepts */ - u32 fdisc_retries; /* fdisc retries */ - u32 fdisc_timeouts; /* fdisc timeouts */ - u32 fdisc_rsp_err; /* fdisc response error */ - u32 fdisc_acc_bad; /* bad fdisc accepts */ - u32 fdisc_rejects; /* fdisc rejects */ - u32 fdisc_unknown_rsp; - /* - *!< fdisc rsp unknown error - */ - u32 fdisc_alloc_wait;/* fdisc req (fcxp)alloc wait */ - - u32 logo_alloc_wait;/* logo req (fcxp) alloc wait */ - u32 logo_sent; /* logo sent */ - u32 logo_accepts; /* logo accepts */ - u32 logo_rejects; /* logo rejects */ - u32 logo_rsp_err; /* logo rsp errors */ - u32 logo_unknown_rsp; - /* logo rsp unknown errors */ - - u32 fab_no_npiv; /* fabric does not support npiv */ - - u32 fab_offline; /* offline events from fab SM */ - u32 fab_online; /* online events from fab SM */ - u32 fab_cleanup; /* cleanup request from fab SM */ - u32 rsvd; -}; - -/** - * BFA vport attribute returned in queries - */ -struct bfa_vport_attr_s { - struct bfa_port_attr_s port_attr; /* base class (port) attributes */ - enum bfa_vport_state vport_state; /* vport state */ - u32 rsvd; -}; - -#endif /* __BFA_DEFS_VPORT_H__ */ diff --git a/drivers/scsi/bfa/include/fcb/bfa_fcb.h b/drivers/scsi/bfa/include/fcb/bfa_fcb.h deleted file mode 100644 index 2963b0bc30e7..000000000000 --- a/drivers/scsi/bfa/include/fcb/bfa_fcb.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/** - * bfa_fcb.h BFA FCS callback interfaces - */ - -#ifndef __BFA_FCB_H__ -#define __BFA_FCB_H__ - -/** - * fcb Main fcs callbacks - */ - -void bfa_fcb_exit(struct bfad_s *bfad); - - - -#endif /* __BFA_FCB_H__ */ diff --git a/drivers/scsi/bfa/include/fcb/bfa_fcb_fcpim.h b/drivers/scsi/bfa/include/fcb/bfa_fcb_fcpim.h deleted file mode 100644 index 52585d3dd891..000000000000 --- a/drivers/scsi/bfa/include/fcb/bfa_fcb_fcpim.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/** -* : bfad_fcpim.h - BFA FCS initiator mode remote port callbacks - */ - -#ifndef __BFAD_FCB_FCPIM_H__ -#define __BFAD_FCB_FCPIM_H__ - -struct bfad_itnim_s; - -/* - * RPIM callbacks - */ - -/** - * Memory allocation for remote port instance. Called before PRLI is - * initiated to the remote target port. - * - * @param[in] bfad - driver instance - * @param[out] itnim - FCS remote port (IM) instance - * @param[out] itnim_drv - driver remote port (IM) instance - * - * @return None - */ -void bfa_fcb_itnim_alloc(struct bfad_s *bfad, struct bfa_fcs_itnim_s **itnim, - struct bfad_itnim_s **itnim_drv); - -/** - * Free remote port (IM) instance. - * - * @param[in] bfad - driver instance - * @param[in] itnim_drv - driver remote port instance - * - * @return None - */ -void bfa_fcb_itnim_free(struct bfad_s *bfad, - struct bfad_itnim_s *itnim_drv); - -/** - * Notification of when login with a remote target device is complete. - * - * @param[in] itnim_drv - driver remote port instance - * - * @return None - */ -void bfa_fcb_itnim_online(struct bfad_itnim_s *itnim_drv); - -/** - * Notification when login with the remote device is severed. - * - * @param[in] itnim_drv - driver remote port instance - * - * @return None - */ -void bfa_fcb_itnim_offline(struct bfad_itnim_s *itnim_drv); - -void bfa_fcb_itnim_tov(struct bfad_itnim_s *itnim_drv); - -#endif /* __BFAD_FCB_FCPIM_H__ */ diff --git a/drivers/scsi/bfa/include/fcb/bfa_fcb_port.h b/drivers/scsi/bfa/include/fcb/bfa_fcb_port.h deleted file mode 100644 index 5fd7f986fa32..000000000000 --- a/drivers/scsi/bfa/include/fcb/bfa_fcb_port.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/** - * bfa_fcb_port.h BFA FCS virtual port driver interfaces - */ - -#ifndef __BFA_FCB_PORT_H__ -#define __BFA_FCB_PORT_H__ - -#include <fcb/bfa_fcb_vport.h> -/** - * fcs_port_fcb FCS port driver interfaces - */ - -/* - * Forward declarations - */ -struct bfad_port_s; - -/* - * Callback functions from BFA FCS to driver - */ - -/** - * Call from FCS to driver module when a port is instantiated. The port - * can be a base port or a virtual port with in the base fabric or - * a virtual fabric. - * - * On this callback, driver is supposed to create scsi_host, scsi_tgt or - * network interfaces bases on ports personality/roles. - * - * base port of base fabric: vf_drv == NULL && vp_drv == NULL - * vport of base fabric: vf_drv == NULL && vp_drv != NULL - * base port of VF: vf_drv != NULL && vp_drv == NULL - * vport of VF: vf_drv != NULL && vp_drv != NULL - * - * @param[in] bfad - driver instance - * @param[in] port - FCS port instance - * @param[in] roles - port roles: IM, TM, IP - * @param[in] vf_drv - VF driver instance, NULL if base fabric (no VF) - * @param[in] vp_drv - vport driver instance, NULL if base port - * - * @return None - */ -struct bfad_port_s *bfa_fcb_port_new(struct bfad_s *bfad, - struct bfa_fcs_port_s *port, - enum bfa_port_role roles, struct bfad_vf_s *vf_drv, - struct bfad_vport_s *vp_drv); - -/** - * Call from FCS to driver module when a port is deleted. The port - * can be a base port or a virtual port with in the base fabric or - * a virtual fabric. - * - * @param[in] bfad - driver instance - * @param[in] roles - port roles: IM, TM, IP - * @param[in] vf_drv - VF driver instance, NULL if base fabric (no VF) - * @param[in] vp_drv - vport driver instance, NULL if base port - * - * @return None - */ -void bfa_fcb_port_delete(struct bfad_s *bfad, enum bfa_port_role roles, - struct bfad_vf_s *vf_drv, struct bfad_vport_s *vp_drv); - -/** - * Notification when port transitions to ONLINE state. - * - * Online notification is a logical link up for the local port. This - * notification is sent after a successfull FLOGI, or a successful - * link initialization in proviate-loop or N2N topologies. - * - * @param[in] bfad - driver instance - * @param[in] roles - port roles: IM, TM, IP - * @param[in] vf_drv - VF driver instance, NULL if base fabric (no VF) - * @param[in] vp_drv - vport driver instance, NULL if base port - * - * @return None - */ -void bfa_fcb_port_online(struct bfad_s *bfad, enum bfa_port_role roles, - struct bfad_vf_s *vf_drv, struct bfad_vport_s *vp_drv); - -/** - * Notification when port transitions to OFFLINE state. - * - * Offline notification is a logical link down for the local port. - * - * @param[in] bfad - driver instance - * @param[in] roles - port roles: IM, TM, IP - * @param[in] vf_drv - VF driver instance, NULL if base fabric (no VF) - * @param[in] vp_drv - vport driver instance, NULL if base port - * - * @return None - */ -void bfa_fcb_port_offline(struct bfad_s *bfad, enum bfa_port_role roles, - struct bfad_vf_s *vf_drv, struct bfad_vport_s *vp_drv); - - -#endif /* __BFA_FCB_PORT_H__ */ diff --git a/drivers/scsi/bfa/include/fcb/bfa_fcb_rport.h b/drivers/scsi/bfa/include/fcb/bfa_fcb_rport.h deleted file mode 100644 index e0261bb6d1c1..000000000000 --- a/drivers/scsi/bfa/include/fcb/bfa_fcb_rport.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/** - * bfa_fcb_rport.h BFA FCS rport driver interfaces - */ - -#ifndef __BFA_FCB_RPORT_H__ -#define __BFA_FCB_RPORT_H__ - -/** - * fcs_rport_fcb Remote port driver interfaces - */ - - -struct bfad_rport_s; - -/* - * Callback functions from BFA FCS to driver - */ - -/** - * Completion callback for bfa_fcs_rport_add(). - * - * @param[in] rport_drv - driver instance of rport - * - * @return None - */ -void bfa_fcb_rport_add(struct bfad_rport_s *rport_drv); - -/** - * Completion callback for bfa_fcs_rport_remove(). - * - * @param[in] rport_drv - driver instance of rport - * - * @return None - */ -void bfa_fcb_rport_remove(struct bfad_rport_s *rport_drv); - -/** - * Call to allocate a rport instance. - * - * @param[in] bfad - driver instance - * @param[out] rport - BFA FCS instance of rport - * @param[out] rport_drv - driver instance of rport - * - * @retval BFA_STATUS_OK - successfully allocated - * @retval BFA_STATUS_ENOMEM - cannot allocate - */ -bfa_status_t bfa_fcb_rport_alloc(struct bfad_s *bfad, - struct bfa_fcs_rport_s **rport, - struct bfad_rport_s **rport_drv); - -/** - * Call to free rport memory resources. - * - * @param[in] bfad - driver instance - * @param[in] rport_drv - driver instance of rport - * - * @return None - */ -void bfa_fcb_rport_free(struct bfad_s *bfad, struct bfad_rport_s **rport_drv); - - - -#endif /* __BFA_FCB_RPORT_H__ */ diff --git a/drivers/scsi/bfa/include/fcb/bfa_fcb_vf.h b/drivers/scsi/bfa/include/fcb/bfa_fcb_vf.h deleted file mode 100644 index cfd3fac0a4e2..000000000000 --- a/drivers/scsi/bfa/include/fcb/bfa_fcb_vf.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/** - * bfa_fcb_vf.h BFA FCS virtual fabric driver interfaces - */ - -#ifndef __BFA_FCB_VF_H__ -#define __BFA_FCB_VF_H__ - -/** - * fcs_vf_fcb Virtual fabric driver intrefaces - */ - - -struct bfad_vf_s; - -/* - * Callback functions from BFA FCS to driver - */ - -/** - * Completion callback for bfa_fcs_vf_stop(). - * - * @param[in] vf_drv - driver instance of vf - * - * @return None - */ -void bfa_fcb_vf_stop(struct bfad_vf_s *vf_drv); - - - -#endif /* __BFA_FCB_VF_H__ */ diff --git a/drivers/scsi/bfa/include/fcb/bfa_fcb_vport.h b/drivers/scsi/bfa/include/fcb/bfa_fcb_vport.h deleted file mode 100644 index cfd6ba7c47ec..000000000000 --- a/drivers/scsi/bfa/include/fcb/bfa_fcb_vport.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/** - * bfa_fcb_vport.h BFA FCS virtual port driver interfaces - */ - -#ifndef __BFA_FCB_VPORT_H__ -#define __BFA_FCB_VPORT_H__ - -/** - * fcs_vport_fcb Virtual port driver interfaces - */ - - -struct bfad_vport_s; - -/* - * Callback functions from BFA FCS to driver - */ - -/** - * Completion callback for bfa_fcs_vport_delete(). - * - * @param[in] vport_drv - driver instance of vport - * - * @return None - */ -void bfa_fcb_vport_delete(struct bfad_vport_s *vport_drv); -void bfa_fcb_pbc_vport_create(struct bfad_s *bfad, struct bfi_pbc_vport_s); - - - -#endif /* __BFA_FCB_VPORT_H__ */ diff --git a/drivers/scsi/bfa/include/fcs/bfa_fcs.h b/drivers/scsi/bfa/include/fcs/bfa_fcs.h deleted file mode 100644 index 54e5b81ab2a3..000000000000 --- a/drivers/scsi/bfa/include/fcs/bfa_fcs.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFA_FCS_H__ -#define __BFA_FCS_H__ - -#include <cs/bfa_debug.h> -#include <defs/bfa_defs_status.h> -#include <defs/bfa_defs_version.h> -#include <bfa.h> -#include <fcs/bfa_fcs_fabric.h> - -#define BFA_FCS_OS_STR_LEN 64 - -struct bfa_fcs_stats_s { - struct { - u32 untagged; /* untagged receive frames */ - u32 tagged; /* tagged receive frames */ - u32 vfid_unknown; /* VF id is unknown */ - } uf; -}; - -struct bfa_fcs_driver_info_s { - u8 version[BFA_VERSION_LEN]; /* Driver Version */ - u8 host_machine_name[BFA_FCS_OS_STR_LEN]; - u8 host_os_name[BFA_FCS_OS_STR_LEN]; /* OS name and version */ - u8 host_os_patch[BFA_FCS_OS_STR_LEN];/* patch or service pack */ - u8 os_device_name[BFA_FCS_OS_STR_LEN]; /* Driver Device Name */ -}; - -struct bfa_fcs_s { - struct bfa_s *bfa; /* corresponding BFA bfa instance */ - struct bfad_s *bfad; /* corresponding BDA driver instance */ - struct bfa_log_mod_s *logm; /* driver logging module instance */ - struct bfa_trc_mod_s *trcmod; /* tracing module */ - struct bfa_aen_s *aen; /* aen component */ - bfa_boolean_t vf_enabled; /* VF mode is enabled */ - bfa_boolean_t fdmi_enabled; /*!< FDMI is enabled */ - bfa_boolean_t min_cfg; /* min cfg enabled/disabled */ - u16 port_vfid; /* port default VF ID */ - struct bfa_fcs_driver_info_s driver_info; - struct bfa_fcs_fabric_s fabric; /* base fabric state machine */ - struct bfa_fcs_stats_s stats; /* FCS statistics */ - struct bfa_wc_s wc; /* waiting counter */ -}; - -/* - * bfa fcs API functions - */ -void bfa_fcs_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); -void bfa_fcs_set_fdmi_param(struct bfa_fcs_s *fcs, bfa_boolean_t fdmi_enable); -void bfa_fcs_exit(struct bfa_fcs_s *fcs); -void bfa_fcs_trc_init(struct bfa_fcs_s *fcs, struct bfa_trc_mod_s *trcmod); -void bfa_fcs_log_init(struct bfa_fcs_s *fcs, struct bfa_log_mod_s *logmod); -void bfa_fcs_aen_init(struct bfa_fcs_s *fcs, struct bfa_aen_s *aen); -void bfa_fcs_start(struct bfa_fcs_s *fcs); - -#endif /* __BFA_FCS_H__ */ diff --git a/drivers/scsi/bfa/include/fcs/bfa_fcs_auth.h b/drivers/scsi/bfa/include/fcs/bfa_fcs_auth.h deleted file mode 100644 index 28c4c9ff08b3..000000000000 --- a/drivers/scsi/bfa/include/fcs/bfa_fcs_auth.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFA_FCS_AUTH_H__ -#define __BFA_FCS_AUTH_H__ - -struct bfa_fcs_s; - -#include <defs/bfa_defs_status.h> -#include <defs/bfa_defs_auth.h> -#include <defs/bfa_defs_vf.h> -#include <cs/bfa_q.h> -#include <cs/bfa_sm.h> -#include <defs/bfa_defs_pport.h> -#include <fcs/bfa_fcs_lport.h> -#include <protocol/fc_sp.h> - -struct bfa_fcs_fabric_s; - - - -struct bfa_fcs_auth_s { - bfa_sm_t sm; /* state machine */ - bfa_boolean_t policy; /* authentication enabled/disabled */ - enum bfa_auth_status status; /* authentication status */ - enum auth_rjt_codes rjt_code; /* auth reject status */ - enum auth_rjt_code_exps rjt_code_exp; /* auth reject reason */ - enum bfa_auth_algo algo; /* Authentication algorithm */ - struct bfa_auth_stats_s stats; /* Statistics */ - enum auth_dh_gid group; /* DH(diffie-hellman) Group */ - enum bfa_auth_secretsource source; /* Secret source */ - char secret[BFA_AUTH_SECRET_STRING_LEN]; - /* secret string */ - u8 secret_len; - /* secret string length */ - u8 nretries; - /* number of retries */ - struct bfa_fcs_fabric_s *fabric;/* pointer to fabric */ - u8 sentcode; /* pointer to response data */ - u8 *response; /* pointer to response data */ - struct bfa_timer_s delay_timer; /* delay timer */ - struct bfa_fcxp_s *fcxp; /* pointer to fcxp */ - struct bfa_fcxp_wqe_s fcxp_wqe; -}; - -/** - * bfa fcs authentication public functions - */ -bfa_status_t bfa_fcs_auth_get_attr(struct bfa_fcs_s *port, - struct bfa_auth_attr_s *attr); -bfa_status_t bfa_fcs_auth_set_policy(struct bfa_fcs_s *port, - bfa_boolean_t policy); -enum bfa_auth_status bfa_fcs_auth_get_status(struct bfa_fcs_s *port); -bfa_status_t bfa_fcs_auth_set_algo(struct bfa_fcs_s *port, - enum bfa_auth_algo algo); -bfa_status_t bfa_fcs_auth_get_stats(struct bfa_fcs_s *port, - struct bfa_auth_stats_s *stats); -bfa_status_t bfa_fcs_auth_set_dh_group(struct bfa_fcs_s *port, int group); -bfa_status_t bfa_fcs_auth_set_secretstring(struct bfa_fcs_s *port, - char *secret); -bfa_status_t bfa_fcs_auth_set_secretstring_encrypt(struct bfa_fcs_s *port, - u32 secret[], u32 len); -bfa_status_t bfa_fcs_auth_set_secretsource(struct bfa_fcs_s *port, - enum bfa_auth_secretsource src); -bfa_status_t bfa_fcs_auth_reset_stats(struct bfa_fcs_s *port); -bfa_status_t bfa_fcs_auth_reinit(struct bfa_fcs_s *port); - -#endif /* __BFA_FCS_AUTH_H__ */ diff --git a/drivers/scsi/bfa/include/fcs/bfa_fcs_fabric.h b/drivers/scsi/bfa/include/fcs/bfa_fcs_fabric.h deleted file mode 100644 index 08b79d5e46f3..000000000000 --- a/drivers/scsi/bfa/include/fcs/bfa_fcs_fabric.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFA_FCS_FABRIC_H__ -#define __BFA_FCS_FABRIC_H__ - -struct bfa_fcs_s; - -#include <defs/bfa_defs_status.h> -#include <defs/bfa_defs_vf.h> -#include <cs/bfa_q.h> -#include <cs/bfa_sm.h> -#include <defs/bfa_defs_pport.h> -#include <fcs/bfa_fcs_lport.h> -#include <protocol/fc_sp.h> -#include <fcs/bfa_fcs_auth.h> - -/* - * forward declaration - */ -struct bfad_vf_s; - -enum bfa_fcs_fabric_type { - BFA_FCS_FABRIC_UNKNOWN = 0, - BFA_FCS_FABRIC_SWITCHED = 1, - BFA_FCS_FABRIC_PLOOP = 2, - BFA_FCS_FABRIC_N2N = 3, -}; - - -struct bfa_fcs_fabric_s { - struct list_head qe; /* queue element */ - bfa_sm_t sm; /* state machine */ - struct bfa_fcs_s *fcs; /* FCS instance */ - struct bfa_fcs_port_s bport; /* base logical port */ - enum bfa_fcs_fabric_type fab_type; /* fabric type */ - enum bfa_pport_type oper_type; /* current link topology */ - u8 is_vf; /* is virtual fabric? */ - u8 is_npiv; /* is NPIV supported ? */ - u8 is_auth; /* is Security/Auth supported ? */ - u16 bb_credit; /* BB credit from fabric */ - u16 vf_id; /* virtual fabric ID */ - u16 num_vports; /* num vports */ - u16 rsvd; - struct list_head vport_q; /* queue of virtual ports */ - struct list_head vf_q; /* queue of virtual fabrics */ - struct bfad_vf_s *vf_drv; /* driver vf structure */ - struct bfa_timer_s link_timer; /* Link Failure timer. Vport */ - wwn_t fabric_name; /* attached fabric name */ - bfa_boolean_t auth_reqd; /* authentication required */ - struct bfa_timer_s delay_timer; /* delay timer */ - union { - u16 swp_vfid;/* switch port VF id */ - } event_arg; - struct bfa_fcs_auth_s auth; /* authentication config */ - struct bfa_wc_s wc; /* wait counter for delete */ - struct bfa_vf_stats_s stats; /* fabric/vf stats */ - struct bfa_lps_s *lps; /* lport login services */ - u8 fabric_ip_addr[BFA_FCS_FABRIC_IPADDR_SZ]; /* attached - * fabric's ip addr - */ -}; - -#define bfa_fcs_fabric_npiv_capable(__f) ((__f)->is_npiv) -#define bfa_fcs_fabric_is_switched(__f) \ - ((__f)->fab_type == BFA_FCS_FABRIC_SWITCHED) - -/** - * The design calls for a single implementation of base fabric and vf. - */ -#define bfa_fcs_vf_t struct bfa_fcs_fabric_s - -struct bfa_vf_event_s { - u32 undefined; -}; - -/** - * bfa fcs vf public functions - */ -bfa_status_t bfa_fcs_vf_mode_enable(struct bfa_fcs_s *fcs, u16 vf_id); -bfa_status_t bfa_fcs_vf_mode_disable(struct bfa_fcs_s *fcs); -bfa_status_t bfa_fcs_vf_create(bfa_fcs_vf_t *vf, struct bfa_fcs_s *fcs, - u16 vf_id, struct bfa_port_cfg_s *port_cfg, - struct bfad_vf_s *vf_drv); -bfa_status_t bfa_fcs_vf_delete(bfa_fcs_vf_t *vf); -void bfa_fcs_vf_start(bfa_fcs_vf_t *vf); -bfa_status_t bfa_fcs_vf_stop(bfa_fcs_vf_t *vf); -void bfa_fcs_vf_list(struct bfa_fcs_s *fcs, u16 *vf_ids, int *nvfs); -void bfa_fcs_vf_list_all(struct bfa_fcs_s *fcs, u16 *vf_ids, int *nvfs); -void bfa_fcs_vf_get_attr(bfa_fcs_vf_t *vf, struct bfa_vf_attr_s *vf_attr); -void bfa_fcs_vf_get_stats(bfa_fcs_vf_t *vf, - struct bfa_vf_stats_s *vf_stats); -void bfa_fcs_vf_clear_stats(bfa_fcs_vf_t *vf); -void bfa_fcs_vf_get_ports(bfa_fcs_vf_t *vf, wwn_t vpwwn[], int *nports); -bfa_fcs_vf_t *bfa_fcs_vf_lookup(struct bfa_fcs_s *fcs, u16 vf_id); -struct bfad_vf_s *bfa_fcs_vf_get_drv_vf(bfa_fcs_vf_t *vf); - -#endif /* __BFA_FCS_FABRIC_H__ */ diff --git a/drivers/scsi/bfa/include/fcs/bfa_fcs_fcpim.h b/drivers/scsi/bfa/include/fcs/bfa_fcs_fcpim.h deleted file mode 100644 index 9a35ecf5cdf0..000000000000 --- a/drivers/scsi/bfa/include/fcs/bfa_fcs_fcpim.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/** - * bfa_fcs_fcpim.h BFA FCS FCP Initiator Mode interfaces/defines. - */ - -#ifndef __BFA_FCS_FCPIM_H__ -#define __BFA_FCS_FCPIM_H__ - -#include <defs/bfa_defs_status.h> -#include <defs/bfa_defs_itnim.h> -#include <fcs/bfa_fcs.h> -#include <fcs/bfa_fcs_rport.h> -#include <fcs/bfa_fcs_lport.h> -#include <bfa_fcpim.h> - -/* - * forward declarations - */ -struct bfad_itnim_s; - -struct bfa_fcs_itnim_s { - bfa_sm_t sm; /* state machine */ - struct bfa_fcs_rport_s *rport; /* parent remote rport */ - struct bfad_itnim_s *itnim_drv; /* driver peer instance */ - struct bfa_fcs_s *fcs; /* fcs instance */ - struct bfa_timer_s timer; /* timer functions */ - struct bfa_itnim_s *bfa_itnim; /* BFA itnim struct */ - 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 */ - bfa_boolean_t task_retry_id; /* task retry id supp */ - struct bfa_fcxp_wqe_s fcxp_wqe; /* wait qelem for fcxp */ - struct bfa_fcxp_s *fcxp; /* FCXP in use */ - struct bfa_itnim_stats_s stats; /* itn statistics */ -}; - - -static inline struct bfad_port_s * -bfa_fcs_itnim_get_drvport(struct bfa_fcs_itnim_s *itnim) -{ - return itnim->rport->port->bfad_port; -} - - -static inline struct bfa_fcs_port_s * -bfa_fcs_itnim_get_port(struct bfa_fcs_itnim_s *itnim) -{ - return itnim->rport->port; -} - - -static inline wwn_t -bfa_fcs_itnim_get_nwwn(struct bfa_fcs_itnim_s *itnim) -{ - return itnim->rport->nwwn; -} - - -static inline wwn_t -bfa_fcs_itnim_get_pwwn(struct bfa_fcs_itnim_s *itnim) -{ - return itnim->rport->pwwn; -} - - -static inline u32 -bfa_fcs_itnim_get_fcid(struct bfa_fcs_itnim_s *itnim) -{ - return itnim->rport->pid; -} - - -static inline u32 -bfa_fcs_itnim_get_maxfrsize(struct bfa_fcs_itnim_s *itnim) -{ - return itnim->rport->maxfrsize; -} - - -static inline enum fc_cos -bfa_fcs_itnim_get_cos(struct bfa_fcs_itnim_s *itnim) -{ - return itnim->rport->fc_cos; -} - - -static inline struct bfad_itnim_s * -bfa_fcs_itnim_get_drvitn(struct bfa_fcs_itnim_s *itnim) -{ - return itnim->itnim_drv; -} - - -static inline struct bfa_itnim_s * -bfa_fcs_itnim_get_halitn(struct bfa_fcs_itnim_s *itnim) -{ - return itnim->bfa_itnim; -} - -/** - * bfa fcs FCP Initiator mode API functions - */ -void bfa_fcs_itnim_get_attr(struct bfa_fcs_itnim_s *itnim, - struct bfa_itnim_attr_s *attr); -void bfa_fcs_itnim_get_stats(struct bfa_fcs_itnim_s *itnim, - struct bfa_itnim_stats_s *stats); -struct bfa_fcs_itnim_s *bfa_fcs_itnim_lookup(struct bfa_fcs_port_s *port, - wwn_t rpwwn); -bfa_status_t bfa_fcs_itnim_attr_get(struct bfa_fcs_port_s *port, wwn_t rpwwn, - struct bfa_itnim_attr_s *attr); -bfa_status_t bfa_fcs_itnim_stats_get(struct bfa_fcs_port_s *port, wwn_t rpwwn, - struct bfa_itnim_stats_s *stats); -bfa_status_t bfa_fcs_itnim_stats_clear(struct bfa_fcs_port_s *port, - wwn_t rpwwn); -#endif /* __BFA_FCS_FCPIM_H__ */ diff --git a/drivers/scsi/bfa/include/fcs/bfa_fcs_fdmi.h b/drivers/scsi/bfa/include/fcs/bfa_fcs_fdmi.h deleted file mode 100644 index 4441fffc9c82..000000000000 --- a/drivers/scsi/bfa/include/fcs/bfa_fcs_fdmi.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/** - * bfa_fcs_fdmi.h BFA fcs fdmi module public interface - */ - -#ifndef __BFA_FCS_FDMI_H__ -#define __BFA_FCS_FDMI_H__ -#include <bfa_os_inc.h> -#include <protocol/fdmi.h> - -#define BFA_FCS_FDMI_SUPORTED_SPEEDS (FDMI_TRANS_SPEED_1G | \ - FDMI_TRANS_SPEED_2G | \ - FDMI_TRANS_SPEED_4G | \ - FDMI_TRANS_SPEED_8G) - -/* -* HBA Attribute Block : BFA internal representation. Note : Some variable -* sizes have been trimmed to suit BFA For Ex : Model will be "Brocade". Based - * on this the size has been reduced to 16 bytes from the standard's 64 bytes. - */ -struct bfa_fcs_fdmi_hba_attr_s { - wwn_t node_name; - u8 manufacturer[64]; - u8 serial_num[64]; - u8 model[16]; - u8 model_desc[256]; - u8 hw_version[8]; - u8 driver_version[8]; - u8 option_rom_ver[BFA_VERSION_LEN]; - u8 fw_version[8]; - u8 os_name[256]; - u32 max_ct_pyld; -}; - -/* - * Port Attribute Block - */ -struct bfa_fcs_fdmi_port_attr_s { - u8 supp_fc4_types[32]; /* supported FC4 types */ - u32 supp_speed; /* supported speed */ - u32 curr_speed; /* current Speed */ - u32 max_frm_size; /* max frame size */ - u8 os_device_name[256]; /* OS device Name */ - u8 host_name[256]; /* host name */ -}; - -#endif /* __BFA_FCS_FDMI_H__ */ diff --git a/drivers/scsi/bfa/include/fcs/bfa_fcs_lport.h b/drivers/scsi/bfa/include/fcs/bfa_fcs_lport.h deleted file mode 100644 index ceaefd3060f4..000000000000 --- a/drivers/scsi/bfa/include/fcs/bfa_fcs_lport.h +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/** - * bfa_fcs_port.h BFA fcs port module public interface - */ - -#ifndef __BFA_FCS_PORT_H__ -#define __BFA_FCS_PORT_H__ - -#include <defs/bfa_defs_status.h> -#include <defs/bfa_defs_port.h> -#include <defs/bfa_defs_pport.h> -#include <defs/bfa_defs_rport.h> -#include <cs/bfa_q.h> -#include <bfa_svc.h> -#include <cs/bfa_wc.h> - -struct bfa_fcs_s; -struct bfa_fcs_fabric_s; - -/* - * Maximum Rports supported per port (physical/logical). - */ -#define BFA_FCS_MAX_RPORTS_SUPP 256 /* @todo : tentative value */ - - -struct bfa_fcs_port_ns_s { - bfa_sm_t sm; /* state machine */ - struct bfa_timer_s timer; - struct bfa_fcs_port_s *port; /* parent port */ - struct bfa_fcxp_s *fcxp; - struct bfa_fcxp_wqe_s fcxp_wqe; -}; - - -struct bfa_fcs_port_scn_s { - bfa_sm_t sm; /* state machine */ - struct bfa_timer_s timer; - struct bfa_fcs_port_s *port; /* parent port */ - struct bfa_fcxp_s *fcxp; - struct bfa_fcxp_wqe_s fcxp_wqe; -}; - - -struct bfa_fcs_port_fdmi_s { - bfa_sm_t sm; /* state machine */ - struct bfa_timer_s timer; - struct bfa_fcs_port_ms_s *ms; /* parent ms */ - struct bfa_fcxp_s *fcxp; - struct bfa_fcxp_wqe_s fcxp_wqe; - u8 retry_cnt; /* retry count */ - u8 rsvd[3]; -}; - - -struct bfa_fcs_port_ms_s { - bfa_sm_t sm; /* state machine */ - struct bfa_timer_s timer; - struct bfa_fcs_port_s *port; /* parent port */ - struct bfa_fcxp_s *fcxp; - struct bfa_fcxp_wqe_s fcxp_wqe; - struct bfa_fcs_port_fdmi_s fdmi; /* FDMI component of MS */ - u8 retry_cnt; /* retry count */ - u8 rsvd[3]; -}; - - -struct bfa_fcs_port_fab_s { - struct bfa_fcs_port_ns_s ns; /* NS component of port */ - struct bfa_fcs_port_scn_s scn; /* scn component of port */ - struct bfa_fcs_port_ms_s ms; /* MS component of port */ -}; - - - -#define MAX_ALPA_COUNT 127 - -struct bfa_fcs_port_loop_s { - u8 num_alpa; /* Num of ALPA entries in the map */ - u8 alpa_pos_map[MAX_ALPA_COUNT]; /* ALPA Positional - *Map */ - struct bfa_fcs_port_s *port; /* parent port */ -}; - - - -struct bfa_fcs_port_n2n_s { - u32 rsvd; - u16 reply_oxid; /* ox_id from the req flogi to be - *used in flogi acc */ - wwn_t rem_port_wwn; /* Attached port's wwn */ -}; - - -union bfa_fcs_port_topo_u { - struct bfa_fcs_port_fab_s pfab; - struct bfa_fcs_port_loop_s ploop; - struct bfa_fcs_port_n2n_s pn2n; -}; - - -struct bfa_fcs_port_s { - struct list_head qe; /* used by port/vport */ - bfa_sm_t sm; /* state machine */ - struct bfa_fcs_fabric_s *fabric;/* parent fabric */ - struct bfa_port_cfg_s port_cfg;/* port configuration */ - struct bfa_timer_s link_timer; /* timer for link offline */ - u32 pid:24; /* FC address */ - u8 lp_tag; /* lport tag */ - u16 num_rports; /* Num of r-ports */ - struct list_head rport_q; /* queue of discovered r-ports */ - struct bfa_fcs_s *fcs; /* FCS instance */ - union bfa_fcs_port_topo_u port_topo; /* fabric/loop/n2n details */ - struct bfad_port_s *bfad_port; /* driver peer instance */ - struct bfa_fcs_vport_s *vport; /* NULL for base ports */ - struct bfa_fcxp_s *fcxp; - struct bfa_fcxp_wqe_s fcxp_wqe; - struct bfa_port_stats_s stats; - struct bfa_wc_s wc; /* waiting counter for events */ -}; - -#define bfa_fcs_lport_t struct bfa_fcs_port_s - -/** - * Symbolic Name related defines - * Total bytes 255. - * Physical Port's symbolic name 128 bytes. - * For Vports, Vport's symbolic name is appended to the Physical port's - * Symbolic Name. - * - * Physical Port's symbolic name Format : (Total 128 bytes) - * Adapter Model number/name : 12 bytes - * Driver Version : 10 bytes - * Host Machine Name : 30 bytes - * Host OS Info : 48 bytes - * Host OS PATCH Info : 16 bytes - * ( remaining 12 bytes reserved to be used for separator) - */ -#define BFA_FCS_PORT_SYMBNAME_SEPARATOR " | " - -#define BFA_FCS_PORT_SYMBNAME_MODEL_SZ 12 -#define BFA_FCS_PORT_SYMBNAME_VERSION_SZ 10 -#define BFA_FCS_PORT_SYMBNAME_MACHINENAME_SZ 30 -#define BFA_FCS_PORT_SYMBNAME_OSINFO_SZ 48 -#define BFA_FCS_PORT_SYMBNAME_OSPATCH_SZ 16 - -/** - * Get FC port ID for a logical port. - */ -#define bfa_fcs_port_get_fcid(_lport) ((_lport)->pid) -#define bfa_fcs_port_get_pwwn(_lport) ((_lport)->port_cfg.pwwn) -#define bfa_fcs_port_get_nwwn(_lport) ((_lport)->port_cfg.nwwn) -#define bfa_fcs_port_get_psym_name(_lport) ((_lport)->port_cfg.sym_name) -#define bfa_fcs_port_is_initiator(_lport) \ - ((_lport)->port_cfg.roles & BFA_PORT_ROLE_FCP_IM) -#define bfa_fcs_port_is_target(_lport) \ - ((_lport)->port_cfg.roles & BFA_PORT_ROLE_FCP_TM) -#define bfa_fcs_port_get_nrports(_lport) \ - ((_lport) ? (_lport)->num_rports : 0) - -static inline struct bfad_port_s * -bfa_fcs_port_get_drvport(struct bfa_fcs_port_s *port) -{ - return port->bfad_port; -} - - -#define bfa_fcs_port_get_opertype(_lport) ((_lport)->fabric->oper_type) - - -#define bfa_fcs_port_get_fabric_name(_lport) ((_lport)->fabric->fabric_name) - - -#define bfa_fcs_port_get_fabric_ipaddr(_lport) \ - ((_lport)->fabric->fabric_ip_addr) - -/** - * bfa fcs port public functions - */ -void bfa_fcs_cfg_base_port(struct bfa_fcs_s *fcs, - struct bfa_port_cfg_s *port_cfg); -struct bfa_fcs_port_s *bfa_fcs_get_base_port(struct bfa_fcs_s *fcs); -void bfa_fcs_port_get_rports(struct bfa_fcs_port_s *port, - wwn_t rport_wwns[], int *nrports); - -wwn_t bfa_fcs_port_get_rport(struct bfa_fcs_port_s *port, wwn_t wwn, - int index, int nrports, bfa_boolean_t bwwn); - -struct bfa_fcs_port_s *bfa_fcs_lookup_port(struct bfa_fcs_s *fcs, - u16 vf_id, wwn_t lpwwn); - -void bfa_fcs_port_get_info(struct bfa_fcs_port_s *port, - struct bfa_port_info_s *port_info); -void bfa_fcs_port_get_attr(struct bfa_fcs_port_s *port, - struct bfa_port_attr_s *port_attr); -void bfa_fcs_port_get_stats(struct bfa_fcs_port_s *fcs_port, - struct bfa_port_stats_s *port_stats); -void bfa_fcs_port_clear_stats(struct bfa_fcs_port_s *fcs_port); -enum bfa_pport_speed bfa_fcs_port_get_rport_max_speed( - struct bfa_fcs_port_s *port); -void bfa_fcs_port_enable_ipfc_roles(struct bfa_fcs_port_s *fcs_port); -void bfa_fcs_port_disable_ipfc_roles(struct bfa_fcs_port_s *fcs_port); - -#endif /* __BFA_FCS_PORT_H__ */ diff --git a/drivers/scsi/bfa/include/fcs/bfa_fcs_rport.h b/drivers/scsi/bfa/include/fcs/bfa_fcs_rport.h deleted file mode 100644 index 3027fc6c7722..000000000000 --- a/drivers/scsi/bfa/include/fcs/bfa_fcs_rport.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFA_FCS_RPORT_H__ -#define __BFA_FCS_RPORT_H__ - -#include <defs/bfa_defs_status.h> -#include <cs/bfa_q.h> -#include <fcs/bfa_fcs.h> -#include <defs/bfa_defs_rport.h> - -#define BFA_FCS_RPORT_DEF_DEL_TIMEOUT 90 /* in secs */ -/* - * forward declarations - */ -struct bfad_rport_s; - -struct bfa_fcs_itnim_s; -struct bfa_fcs_tin_s; -struct bfa_fcs_iprp_s; - -/* Rport Features (RPF) */ -struct bfa_fcs_rpf_s { - bfa_sm_t sm; /* state machine */ - struct bfa_fcs_rport_s *rport; /* parent rport */ - struct bfa_timer_s timer; /* general purpose timer */ - struct bfa_fcxp_s *fcxp; /* FCXP needed for discarding */ - struct bfa_fcxp_wqe_s fcxp_wqe; /* fcxp wait queue element */ - int rpsc_retries; /* max RPSC retry attempts */ - enum bfa_pport_speed rpsc_speed; /* Current Speed from RPSC. - * O if RPSC fails */ - enum bfa_pport_speed assigned_speed; /* Speed assigned by the user. - * will be used if RPSC is not - * supported by the rport */ -}; - -struct bfa_fcs_rport_s { - struct list_head qe; /* used by port/vport */ - struct bfa_fcs_port_s *port; /* parent FCS port */ - struct bfa_fcs_s *fcs; /* fcs instance */ - struct bfad_rport_s *rp_drv; /* driver peer instance */ - u32 pid; /* port ID of rport */ - u16 maxfrsize; /* maximum frame size */ - u16 reply_oxid; /* OX_ID of inbound requests */ - enum fc_cos fc_cos; /* FC classes of service supp */ - bfa_boolean_t cisc; /* CISC capable device */ - 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 */ - bfa_sm_t sm; /* state machine */ - struct bfa_timer_s timer; /* general purpose timer */ - struct bfa_fcs_itnim_s *itnim; /* ITN initiator mode role */ - struct bfa_fcs_tin_s *tin; /* ITN initiator mode role */ - struct bfa_fcs_iprp_s *iprp; /* IP/FC role */ - struct bfa_rport_s *bfa_rport; /* BFA Rport */ - struct bfa_fcxp_s *fcxp; /* FCXP needed for discarding */ - int plogi_retries; /* max plogi retry attempts */ - int ns_retries; /* max NS query retry attempts */ - struct bfa_fcxp_wqe_s fcxp_wqe; /* fcxp wait queue element */ - struct bfa_rport_stats_s stats; /* rport stats */ - enum bfa_rport_function scsi_function; /* Initiator/Target */ - struct bfa_fcs_rpf_s rpf; /* Rport features module */ -}; - -static inline struct bfa_rport_s * -bfa_fcs_rport_get_halrport(struct bfa_fcs_rport_s *rport) -{ - return rport->bfa_rport; -} - -/** - * bfa fcs rport API functions - */ -bfa_status_t bfa_fcs_rport_add(struct bfa_fcs_port_s *port, wwn_t *pwwn, - struct bfa_fcs_rport_s *rport, - struct bfad_rport_s *rport_drv); -bfa_status_t bfa_fcs_rport_remove(struct bfa_fcs_rport_s *rport); -void bfa_fcs_rport_get_attr(struct bfa_fcs_rport_s *rport, - struct bfa_rport_attr_s *attr); -void bfa_fcs_rport_get_stats(struct bfa_fcs_rport_s *rport, - struct bfa_rport_stats_s *stats); -void bfa_fcs_rport_clear_stats(struct bfa_fcs_rport_s *rport); -struct bfa_fcs_rport_s *bfa_fcs_rport_lookup(struct bfa_fcs_port_s *port, - wwn_t rpwwn); -struct bfa_fcs_rport_s *bfa_fcs_rport_lookup_by_nwwn( - struct bfa_fcs_port_s *port, wwn_t rnwwn); -void bfa_fcs_rport_set_del_timeout(u8 rport_tmo); -void bfa_fcs_rport_set_speed(struct bfa_fcs_rport_s *rport, - enum bfa_pport_speed speed); -#endif /* __BFA_FCS_RPORT_H__ */ diff --git a/drivers/scsi/bfa/include/fcs/bfa_fcs_vport.h b/drivers/scsi/bfa/include/fcs/bfa_fcs_vport.h deleted file mode 100644 index 0af262430860..000000000000 --- a/drivers/scsi/bfa/include/fcs/bfa_fcs_vport.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/** - * bfa_fcs_vport.h BFA fcs vport module public interface - */ - -#ifndef __BFA_FCS_VPORT_H__ -#define __BFA_FCS_VPORT_H__ - -#include <defs/bfa_defs_status.h> -#include <defs/bfa_defs_port.h> -#include <defs/bfa_defs_vport.h> -#include <fcs/bfa_fcs.h> -#include <fcb/bfa_fcb_vport.h> - -struct bfa_fcs_vport_s { - struct list_head qe; /* queue elem */ - bfa_sm_t sm; /* state machine */ - bfa_fcs_lport_t lport; /* logical port */ - struct bfa_timer_s timer; /* general purpose timer */ - struct bfad_vport_s *vport_drv; /* Driver private */ - struct bfa_vport_stats_s vport_stats; /* vport statistics */ - struct bfa_lps_s *lps; /* Lport login service */ - int fdisc_retries; -}; - -#define bfa_fcs_vport_get_port(vport) \ - ((struct bfa_fcs_port_s *)(&vport->port)) - -/** - * bfa fcs vport public functions - */ -bfa_status_t bfa_fcs_vport_create(struct bfa_fcs_vport_s *vport, - struct bfa_fcs_s *fcs, u16 vf_id, - struct bfa_port_cfg_s *port_cfg, - struct bfad_vport_s *vport_drv); -bfa_status_t bfa_fcs_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); -void bfa_fcs_vport_get_attr(struct bfa_fcs_vport_s *vport, - struct bfa_vport_attr_s *vport_attr); -void bfa_fcs_vport_get_stats(struct bfa_fcs_vport_s *vport, - struct bfa_vport_stats_s *vport_stats); -void bfa_fcs_vport_clr_stats(struct bfa_fcs_vport_s *vport); -struct bfa_fcs_vport_s *bfa_fcs_vport_lookup(struct bfa_fcs_s *fcs, - u16 vf_id, wwn_t vpwwn); - -#endif /* __BFA_FCS_VPORT_H__ */ diff --git a/drivers/scsi/bfa/include/log/bfa_log_fcs.h b/drivers/scsi/bfa/include/log/bfa_log_fcs.h deleted file mode 100644 index b6f5df8827f8..000000000000 --- a/drivers/scsi/bfa/include/log/bfa_log_fcs.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/* - * messages define for FCS Module - */ -#ifndef __BFA_LOG_FCS_H__ -#define __BFA_LOG_FCS_H__ -#include <cs/bfa_log.h> -#define BFA_LOG_FCS_FABRIC_NOSWITCH \ - (((u32) BFA_LOG_FCS_ID << BFA_LOG_MODID_OFFSET) | 1) -#define BFA_LOG_FCS_FABRIC_ISOLATED \ - (((u32) BFA_LOG_FCS_ID << BFA_LOG_MODID_OFFSET) | 2) -#endif diff --git a/drivers/scsi/bfa/include/log/bfa_log_hal.h b/drivers/scsi/bfa/include/log/bfa_log_hal.h deleted file mode 100644 index 5f8f5e30b9e8..000000000000 --- a/drivers/scsi/bfa/include/log/bfa_log_hal.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/* messages define for HAL Module */ -#ifndef __BFA_LOG_HAL_H__ -#define __BFA_LOG_HAL_H__ -#include <cs/bfa_log.h> -#define BFA_LOG_HAL_ASSERT \ - (((u32) BFA_LOG_HAL_ID << BFA_LOG_MODID_OFFSET) | 1) -#define BFA_LOG_HAL_HEARTBEAT_FAILURE \ - (((u32) BFA_LOG_HAL_ID << BFA_LOG_MODID_OFFSET) | 2) -#define BFA_LOG_HAL_FCPIM_PARM_INVALID \ - (((u32) BFA_LOG_HAL_ID << BFA_LOG_MODID_OFFSET) | 3) -#define BFA_LOG_HAL_SM_ASSERT \ - (((u32) BFA_LOG_HAL_ID << BFA_LOG_MODID_OFFSET) | 4) -#define BFA_LOG_HAL_DRIVER_ERROR \ - (((u32) BFA_LOG_HAL_ID << BFA_LOG_MODID_OFFSET) | 5) -#define BFA_LOG_HAL_DRIVER_CONFIG_ERROR \ - (((u32) BFA_LOG_HAL_ID << BFA_LOG_MODID_OFFSET) | 6) -#define BFA_LOG_HAL_MBOX_ERROR \ - (((u32) BFA_LOG_HAL_ID << BFA_LOG_MODID_OFFSET) | 7) -#endif diff --git a/drivers/scsi/bfa/include/log/bfa_log_linux.h b/drivers/scsi/bfa/include/log/bfa_log_linux.h deleted file mode 100644 index 44bc89768bda..000000000000 --- a/drivers/scsi/bfa/include/log/bfa_log_linux.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/* messages define for LINUX Module */ -#ifndef __BFA_LOG_LINUX_H__ -#define __BFA_LOG_LINUX_H__ -#include <cs/bfa_log.h> -#define BFA_LOG_LINUX_DEVICE_CLAIMED \ - (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 1) -#define BFA_LOG_LINUX_HASH_INIT_FAILED \ - (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 2) -#define BFA_LOG_LINUX_SYSFS_FAILED \ - (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 3) -#define BFA_LOG_LINUX_MEM_ALLOC_FAILED \ - (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 4) -#define BFA_LOG_LINUX_DRIVER_REGISTRATION_FAILED \ - (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 5) -#define BFA_LOG_LINUX_ITNIM_FREE \ - (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 6) -#define BFA_LOG_LINUX_ITNIM_ONLINE \ - (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 7) -#define BFA_LOG_LINUX_ITNIM_OFFLINE \ - (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 8) -#define BFA_LOG_LINUX_SCSI_HOST_FREE \ - (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 9) -#define BFA_LOG_LINUX_SCSI_ABORT \ - (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 10) -#define BFA_LOG_LINUX_SCSI_ABORT_COMP \ - (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 11) -#define BFA_LOG_LINUX_DRIVER_CONFIG_ERROR \ - (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 12) -#define BFA_LOG_LINUX_BNA_STATE_MACHINE \ - (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 13) -#define BFA_LOG_LINUX_IOC_ERROR \ - (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 14) -#define BFA_LOG_LINUX_RESOURCE_ALLOC_ERROR \ - (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 15) -#define BFA_LOG_LINUX_RING_BUFFER_ERROR \ - (((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_INFO \ - (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 18) -#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 diff --git a/drivers/scsi/bfa/include/log/bfa_log_wdrv.h b/drivers/scsi/bfa/include/log/bfa_log_wdrv.h deleted file mode 100644 index 809a95f7afe2..000000000000 --- a/drivers/scsi/bfa/include/log/bfa_log_wdrv.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/* - * messages define for WDRV Module - */ -#ifndef __BFA_LOG_WDRV_H__ -#define __BFA_LOG_WDRV_H__ -#include <cs/bfa_log.h> -#define BFA_LOG_WDRV_IOC_INIT_ERROR \ - (((u32) BFA_LOG_WDRV_ID << BFA_LOG_MODID_OFFSET) | 1) -#define BFA_LOG_WDRV_IOC_INTERNAL_ERROR \ - (((u32) BFA_LOG_WDRV_ID << BFA_LOG_MODID_OFFSET) | 2) -#define BFA_LOG_WDRV_IOC_START_ERROR \ - (((u32) BFA_LOG_WDRV_ID << BFA_LOG_MODID_OFFSET) | 3) -#define BFA_LOG_WDRV_IOC_STOP_ERROR \ - (((u32) BFA_LOG_WDRV_ID << BFA_LOG_MODID_OFFSET) | 4) -#define BFA_LOG_WDRV_INSUFFICIENT_RESOURCES \ - (((u32) BFA_LOG_WDRV_ID << BFA_LOG_MODID_OFFSET) | 5) -#define BFA_LOG_WDRV_BASE_ADDRESS_MAP_ERROR \ - (((u32) BFA_LOG_WDRV_ID << BFA_LOG_MODID_OFFSET) | 6) -#endif diff --git a/drivers/scsi/bfa/include/protocol/ct.h b/drivers/scsi/bfa/include/protocol/ct.h deleted file mode 100644 index b82540a230c4..000000000000 --- a/drivers/scsi/bfa/include/protocol/ct.h +++ /dev/null @@ -1,492 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __CT_H__ -#define __CT_H__ - -#include <protocol/types.h> - -#pragma pack(1) - -struct ct_hdr_s{ - u32 rev_id:8; /* Revision of the CT */ - u32 in_id:24; /* Initiator Id */ - u32 gs_type:8; /* Generic service Type */ - u32 gs_sub_type:8; /* Generic service sub type */ - u32 options:8; /* options */ - u32 rsvrd:8; /* reserved */ - u32 cmd_rsp_code:16;/* ct command/response code */ - u32 max_res_size:16;/* maximum/residual size */ - u32 frag_id:8; /* fragment ID */ - u32 reason_code:8; /* reason code */ - u32 exp_code:8; /* explanation code */ - u32 vendor_unq:8; /* vendor unique */ -}; - -/* - * defines for the Revision - */ -enum { - CT_GS3_REVISION = 0x01, -}; - -/* - * defines for gs_type - */ -enum { - CT_GSTYPE_KEYSERVICE = 0xF7, - CT_GSTYPE_ALIASSERVICE = 0xF8, - CT_GSTYPE_MGMTSERVICE = 0xFA, - CT_GSTYPE_TIMESERVICE = 0xFB, - CT_GSTYPE_DIRSERVICE = 0xFC, -}; - -/* - * defines for gs_sub_type for gs type directory service - */ -enum { - CT_GSSUBTYPE_NAMESERVER = 0x02, -}; - -/* - * defines for gs_sub_type for gs type management service - */ -enum { - CT_GSSUBTYPE_CFGSERVER = 0x01, - CT_GSSUBTYPE_UNZONED_NS = 0x02, - CT_GSSUBTYPE_ZONESERVER = 0x03, - CT_GSSUBTYPE_LOCKSERVER = 0x04, - CT_GSSUBTYPE_HBA_MGMTSERVER = 0x10, /* for FDMI */ -}; - -/* - * defines for CT response code field - */ -enum { - CT_RSP_REJECT = 0x8001, - CT_RSP_ACCEPT = 0x8002, -}; - -/* - * definitions for CT reason code - */ -enum { - CT_RSN_INV_CMD = 0x01, - CT_RSN_INV_VER = 0x02, - CT_RSN_LOGIC_ERR = 0x03, - CT_RSN_INV_SIZE = 0x04, - CT_RSN_LOGICAL_BUSY = 0x05, - CT_RSN_PROTO_ERR = 0x07, - CT_RSN_UNABLE_TO_PERF = 0x09, - CT_RSN_NOT_SUPP = 0x0B, - CT_RSN_SERVER_NOT_AVBL = 0x0D, - CT_RSN_SESSION_COULD_NOT_BE_ESTBD = 0x0E, - CT_RSN_VENDOR_SPECIFIC = 0xFF, - -}; - -/* - * definitions for explanations code for Name server - */ -enum { - CT_NS_EXP_NOADDITIONAL = 0x00, - CT_NS_EXP_ID_NOT_REG = 0x01, - CT_NS_EXP_PN_NOT_REG = 0x02, - CT_NS_EXP_NN_NOT_REG = 0x03, - CT_NS_EXP_CS_NOT_REG = 0x04, - CT_NS_EXP_IPN_NOT_REG = 0x05, - CT_NS_EXP_IPA_NOT_REG = 0x06, - CT_NS_EXP_FT_NOT_REG = 0x07, - CT_NS_EXP_SPN_NOT_REG = 0x08, - CT_NS_EXP_SNN_NOT_REG = 0x09, - CT_NS_EXP_PT_NOT_REG = 0x0A, - CT_NS_EXP_IPP_NOT_REG = 0x0B, - CT_NS_EXP_FPN_NOT_REG = 0x0C, - CT_NS_EXP_HA_NOT_REG = 0x0D, - CT_NS_EXP_FD_NOT_REG = 0x0E, - CT_NS_EXP_FF_NOT_REG = 0x0F, - CT_NS_EXP_ACCESSDENIED = 0x10, - CT_NS_EXP_UNACCEPTABLE_ID = 0x11, - CT_NS_EXP_DATABASEEMPTY = 0x12, - CT_NS_EXP_NOT_REG_IN_SCOPE = 0x13, - CT_NS_EXP_DOM_ID_NOT_PRESENT = 0x14, - CT_NS_EXP_PORT_NUM_NOT_PRESENT = 0x15, - CT_NS_EXP_NO_DEVICE_ATTACHED = 0x16 -}; - -/* - * definitions for the explanation code for all servers - */ -enum { - CT_EXP_AUTH_EXCEPTION = 0xF1, - CT_EXP_DB_FULL = 0xF2, - CT_EXP_DB_EMPTY = 0xF3, - CT_EXP_PROCESSING_REQ = 0xF4, - CT_EXP_UNABLE_TO_VERIFY_CONN = 0xF5, - CT_EXP_DEVICES_NOT_IN_CMN_ZONE = 0xF6 -}; - -/* - * Command codes for Name server - */ -enum { - GS_GID_PN = 0x0121, /* Get Id on port name */ - GS_GPN_ID = 0x0112, /* Get port name on ID */ - GS_GNN_ID = 0x0113, /* Get node name on ID */ - GS_GID_FT = 0x0171, /* Get Id on FC4 type */ - GS_GSPN_ID = 0x0118, /* Get symbolic PN on ID */ - GS_RFT_ID = 0x0217, /* Register fc4type on ID */ - GS_RSPN_ID = 0x0218, /* Register symbolic PN on ID */ - GS_RPN_ID = 0x0212, /* Register port name */ - GS_RNN_ID = 0x0213, /* Register node name */ - GS_RCS_ID = 0x0214, /* Register class of service */ - GS_RPT_ID = 0x021A, /* Register port type */ - GS_GA_NXT = 0x0100, /* Get all next */ - GS_RFF_ID = 0x021F, /* Register FC4 Feature */ -}; - -struct fcgs_id_req_s{ - u32 rsvd:8; - u32 dap:24; /* port identifier */ -}; -#define fcgs_gpnid_req_t struct fcgs_id_req_s -#define fcgs_gnnid_req_t struct fcgs_id_req_s -#define fcgs_gspnid_req_t struct fcgs_id_req_s - -struct fcgs_gidpn_req_s{ - wwn_t port_name; /* port wwn */ -}; - -struct fcgs_gidpn_resp_s{ - u32 rsvd:8; - u32 dap:24; /* port identifier */ -}; - -/** - * RFT_ID - */ -struct fcgs_rftid_req_s { - u32 rsvd:8; - u32 dap:24; /* port identifier */ - u32 fc4_type[8]; /* fc4 types */ -}; - -/** - * RFF_ID : Register FC4 features. - */ - -#define FC_GS_FCP_FC4_FEATURE_INITIATOR 0x02 -#define FC_GS_FCP_FC4_FEATURE_TARGET 0x01 - -struct fcgs_rffid_req_s{ - u32 rsvd:8; - u32 dap:24; /* port identifier */ - u32 rsvd1:16; - u32 fc4ftr_bits:8; /* fc4 feature bits */ - u32 fc4_type:8; /* corresponding FC4 Type */ -}; - -/** - * GID_FT Request - */ -struct fcgs_gidft_req_s{ - u8 reserved; - u8 domain_id; /* domain, 0 - all fabric */ - u8 area_id; /* area, 0 - whole domain */ - u8 fc4_type; /* FC_TYPE_FCP for SCSI devices */ -}; /* GID_FT Request */ - -/** - * GID_FT Response - */ -struct fcgs_gidft_resp_s { - u8 last:1; /* last port identifier flag */ - u8 reserved:7; - u32 pid:24; /* port identifier */ -}; /* GID_FT Response */ - -/** - * RSPN_ID - */ -struct fcgs_rspnid_req_s{ - u32 rsvd:8; - u32 dap:24; /* port identifier */ - u8 spn_len; /* symbolic port name length */ - u8 spn[256]; /* symbolic port name */ -}; - -/** - * RPN_ID - */ -struct fcgs_rpnid_req_s{ - u32 rsvd:8; - u32 port_id:24; - wwn_t port_name; -}; - -/** - * RNN_ID - */ -struct fcgs_rnnid_req_s{ - u32 rsvd:8; - u32 port_id:24; - wwn_t node_name; -}; - -/** - * RCS_ID - */ -struct fcgs_rcsid_req_s{ - u32 rsvd:8; - u32 port_id:24; - u32 cos; -}; - -/** - * RPT_ID - */ -struct fcgs_rptid_req_s{ - u32 rsvd:8; - u32 port_id:24; - u32 port_type:8; - u32 rsvd1:24; -}; - -/** - * GA_NXT Request - */ -struct fcgs_ganxt_req_s{ - u32 rsvd:8; - u32 port_id:24; -}; - -/** - * GA_NXT Response - */ -struct fcgs_ganxt_rsp_s{ - u32 port_type:8; /* Port Type */ - u32 port_id:24; /* Port Identifier */ - wwn_t port_name; /* Port Name */ - u8 spn_len; /* Length of Symbolic Port Name */ - char spn[255]; /* Symbolic Port Name */ - wwn_t node_name; /* Node Name */ - u8 snn_len; /* Length of Symbolic Node Name */ - char snn[255]; /* Symbolic Node Name */ - u8 ipa[8]; /* Initial Process Associator */ - u8 ip[16]; /* IP Address */ - u32 cos; /* Class of Service */ - u32 fc4types[8]; /* FC-4 TYPEs */ - wwn_t fabric_port_name; - /* Fabric Port Name */ - u32 rsvd:8; /* Reserved */ - u32 hard_addr:24; /* Hard Address */ -}; - -/* - * Fabric Config Server - */ - -/* - * Command codes for Fabric Configuration Server - */ -enum { - GS_FC_GFN_CMD = 0x0114, /* GS FC Get Fabric Name */ - GS_FC_GMAL_CMD = 0x0116, /* GS FC GMAL */ - GS_FC_TRACE_CMD = 0x0400, /* GS FC Trace Route */ - GS_FC_PING_CMD = 0x0401, /* GS FC Ping */ -}; - -/* - * Source or Destination Port Tags. - */ -enum { - GS_FTRACE_TAG_NPORT_ID = 1, - GS_FTRACE_TAG_NPORT_NAME = 2, -}; - -/* -* Port Value : Could be a Port id or wwn - */ -union fcgs_port_val_u{ - u32 nport_id; - wwn_t nport_wwn; -}; - -#define GS_FTRACE_MAX_HOP_COUNT 20 -#define GS_FTRACE_REVISION 1 - -/* - * Ftrace Related Structures. - */ - -/* - * STR (Switch Trace) Reject Reason Codes. From FC-SW. - */ -enum { - GS_FTRACE_STR_CMD_COMPLETED_SUCC = 0, - GS_FTRACE_STR_CMD_NOT_SUPP_IN_NEXT_SWITCH, - GS_FTRACE_STR_NO_RESP_FROM_NEXT_SWITCH, - GS_FTRACE_STR_MAX_HOP_CNT_REACHED, - GS_FTRACE_STR_SRC_PORT_NOT_FOUND, - GS_FTRACE_STR_DST_PORT_NOT_FOUND, - GS_FTRACE_STR_DEVICES_NOT_IN_COMMON_ZONE, - GS_FTRACE_STR_NO_ROUTE_BW_PORTS, - GS_FTRACE_STR_NO_ADDL_EXPLN, - GS_FTRACE_STR_FABRIC_BUSY, - GS_FTRACE_STR_FABRIC_BUILD_IN_PROGRESS, - GS_FTRACE_STR_VENDOR_SPECIFIC_ERR_START = 0xf0, - GS_FTRACE_STR_VENDOR_SPECIFIC_ERR_END = 0xff, -}; - -/* - * Ftrace Request - */ -struct fcgs_ftrace_req_s{ - u32 revision; - u16 src_port_tag; /* Source Port tag */ - u16 src_port_len; /* Source Port len */ - union fcgs_port_val_u src_port_val; /* Source Port value */ - u16 dst_port_tag; /* Destination Port tag */ - u16 dst_port_len; /* Destination Port len */ - union fcgs_port_val_u dst_port_val; /* Destination Port value */ - u32 token; - u8 vendor_id[8]; /* T10 Vendor Identifier */ - u8 vendor_info[8]; /* Vendor specific Info */ - u32 max_hop_cnt; /* Max Hop Count */ -}; - -/* - * Path info structure - */ -struct fcgs_ftrace_path_info_s{ - wwn_t switch_name; /* Switch WWN */ - u32 domain_id; - wwn_t ingress_port_name; /* Ingress ports wwn */ - u32 ingress_phys_port_num; /* Ingress ports physical port - * number - */ - wwn_t egress_port_name; /* Ingress ports wwn */ - u32 egress_phys_port_num; /* Ingress ports physical port - * number - */ -}; - -/* - * Ftrace Acc Response - */ -struct fcgs_ftrace_resp_s{ - u32 revision; - u32 token; - u8 vendor_id[8]; /* T10 Vendor Identifier */ - u8 vendor_info[8]; /* Vendor specific Info */ - u32 str_rej_reason_code; /* STR Reject Reason Code */ - u32 num_path_info_entries; /* No. of path info entries */ - /* - * path info entry/entries. - */ - struct fcgs_ftrace_path_info_s path_info[1]; - -}; - -/* -* Fabric Config Server : FCPing - */ - -/* - * FC Ping Request - */ -struct fcgs_fcping_req_s{ - u32 revision; - u16 port_tag; - u16 port_len; /* Port len */ - union fcgs_port_val_u port_val; /* Port value */ - u32 token; -}; - -/* - * FC Ping Response - */ -struct fcgs_fcping_resp_s{ - u32 token; -}; - -/* - * Command codes for zone server query. - */ -enum { - ZS_GZME = 0x0124, /* Get zone member extended */ -}; - -/* - * ZS GZME request - */ -#define ZS_GZME_ZNAMELEN 32 -struct zs_gzme_req_s{ - u8 znamelen; - u8 rsvd[3]; - u8 zname[ZS_GZME_ZNAMELEN]; -}; - -enum zs_mbr_type{ - ZS_MBR_TYPE_PWWN = 1, - ZS_MBR_TYPE_DOMPORT = 2, - ZS_MBR_TYPE_PORTID = 3, - ZS_MBR_TYPE_NWWN = 4, -}; - -struct zs_mbr_wwn_s{ - u8 mbr_type; - u8 rsvd[3]; - wwn_t wwn; -}; - -struct zs_query_resp_s{ - u32 nmbrs; /* number of zone members */ - struct zs_mbr_wwn_s mbr[1]; -}; - -/* - * GMAL Command ( Get ( interconnect Element) Management Address List) - * To retrieve the IP Address of a Switch. - */ - -#define CT_GMAL_RESP_PREFIX_TELNET "telnet://" -#define CT_GMAL_RESP_PREFIX_HTTP "http://" - -/* GMAL/GFN request */ -struct fcgs_req_s { - wwn_t wwn; /* PWWN/NWWN */ -}; - -#define fcgs_gmal_req_t struct fcgs_req_s -#define fcgs_gfn_req_t struct fcgs_req_s - -/* Accept Response to GMAL */ -struct fcgs_gmal_resp_s { - u32 ms_len; /* Num of entries */ - u8 ms_ma[256]; -}; - -struct fc_gmal_entry_s { - u8 len; - u8 prefix[7]; /* like "http://" */ - u8 ip_addr[248]; -}; - -#pragma pack() - -#endif diff --git a/drivers/scsi/bfa/include/protocol/fc_sp.h b/drivers/scsi/bfa/include/protocol/fc_sp.h deleted file mode 100644 index 55bb0b31d04b..000000000000 --- a/drivers/scsi/bfa/include/protocol/fc_sp.h +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __FC_SP_H__ -#define __FC_SP_H__ - -#include <protocol/types.h> - -#pragma pack(1) - -enum auth_els_flags{ - FC_AUTH_ELS_MORE_FRAGS_FLAG = 0x80, /*! bit-7. More Fragments - * Follow - */ - FC_AUTH_ELS_CONCAT_FLAG = 0x40, /*! bit-6. Concatenation Flag */ - FC_AUTH_ELS_SEQ_NUM_FLAG = 0x01 /*! bit-0. Sequence Number */ -}; - -enum auth_msg_codes{ - FC_AUTH_MC_AUTH_RJT = 0x0A, /*! Auth Reject */ - FC_AUTH_MC_AUTH_NEG = 0x0B, /*! Auth Negotiate */ - FC_AUTH_MC_AUTH_DONE = 0x0C, /*! Auth Done */ - - FC_AUTH_MC_DHCHAP_CHAL = 0x10, /*! DHCHAP Challenge */ - FC_AUTH_MC_DHCHAP_REPLY = 0x11, /*! DHCHAP Reply */ - FC_AUTH_MC_DHCHAP_SUCC = 0x12, /*! DHCHAP Success */ - - FC_AUTH_MC_FCAP_REQ = 0x13, /*! FCAP Request */ - FC_AUTH_MC_FCAP_ACK = 0x14, /*! FCAP Acknowledge */ - FC_AUTH_MC_FCAP_CONF = 0x15, /*! FCAP Confirm */ - - FC_AUTH_MC_FCPAP_INIT = 0x16, /*! FCPAP Init */ - FC_AUTH_MC_FCPAP_ACC = 0x17, /*! FCPAP Accept */ - FC_AUTH_MC_FCPAP_COMP = 0x18, /*! FCPAP Complete */ - - FC_AUTH_MC_IKE_SA_INIT = 0x22, /*! IKE SA INIT */ - FC_AUTH_MC_IKE_SA_AUTH = 0x23, /*! IKE SA Auth */ - FC_AUTH_MC_IKE_CREATE_CHILD_SA = 0x24, /*! IKE Create Child SA */ - FC_AUTH_MC_IKE_INFO = 0x25, /*! IKE informational */ -}; - -enum auth_proto_version{ - FC_AUTH_PROTO_VER_1 = 1, /*! Protocol Version 1 */ -}; - -enum { - FC_AUTH_ELS_COMMAND_CODE = 0x90,/*! Authentication ELS Command code */ - FC_AUTH_PROTO_PARAM_LEN_SZ = 4, /*! Size of Proto Parameter Len Field */ - FC_AUTH_PROTO_PARAM_VAL_SZ = 4, /*! Size of Proto Parameter Val Field */ - FC_MAX_AUTH_SECRET_LEN = 256, - /*! Maximum secret string length */ - FC_AUTH_NUM_USABLE_PROTO_LEN_SZ = 4, - /*! Size of usable protocols field */ - FC_AUTH_RESP_VALUE_LEN_SZ = 4, - /*! Size of response value length */ - FC_MAX_CHAP_KEY_LEN = 256, /*! Maximum md5 digest length */ - FC_MAX_AUTH_RETRIES = 3, /*! Maximum number of retries */ - FC_MD5_DIGEST_LEN = 16, /*! MD5 digest length */ - FC_SHA1_DIGEST_LEN = 20, /*! SHA1 digest length */ - FC_MAX_DHG_SUPPORTED = 1, /*! Maximum DH Groups supported */ - FC_MAX_ALG_SUPPORTED = 1, /*! Maximum algorithms supported */ - FC_MAX_PROTO_SUPPORTED = 1, /*! Maximum protocols supported */ - FC_START_TXN_ID = 2, /*! Starting transaction ID */ -}; - -enum auth_proto_id{ - FC_AUTH_PROTO_DHCHAP = 0x00000001, - FC_AUTH_PROTO_FCAP = 0x00000002, - FC_AUTH_PROTO_FCPAP = 0x00000003, - FC_AUTH_PROTO_IKEv2 = 0x00000004, - FC_AUTH_PROTO_IKEv2_AUTH = 0x00000005, -}; - -struct auth_name_s{ - u16 name_tag; /*! Name Tag = 1 for Authentication */ - u16 name_len; /*! Name Length = 8 for Authentication - */ - wwn_t name; /*! Name. TODO - is this PWWN */ -}; - - -enum auth_hash_func{ - FC_AUTH_HASH_FUNC_MD5 = 0x00000005, - FC_AUTH_HASH_FUNC_SHA_1 = 0x00000006, -}; - -enum auth_dh_gid{ - FC_AUTH_DH_GID_0_DHG_NULL = 0x00000000, - FC_AUTH_DH_GID_1_DHG_1024 = 0x00000001, - FC_AUTH_DH_GID_2_DHG_1280 = 0x00000002, - FC_AUTH_DH_GID_3_DHG_1536 = 0x00000003, - FC_AUTH_DH_GID_4_DHG_2048 = 0x00000004, - FC_AUTH_DH_GID_6_DHG_3072 = 0x00000006, - FC_AUTH_DH_GID_7_DHG_4096 = 0x00000007, - FC_AUTH_DH_GID_8_DHG_6144 = 0x00000008, - FC_AUTH_DH_GID_9_DHG_8192 = 0x00000009, -}; - -struct auth_els_msg_s { - u8 auth_els_code; /* Authentication ELS Code (0x90) */ - u8 auth_els_flag; /* Authentication ELS Flags */ - u8 auth_msg_code; /* Authentication Message Code */ - u8 proto_version; /* Protocol Version */ - u32 msg_len; /* Message Length */ - u32 trans_id; /* Transaction Identifier (T_ID) */ - - /* Msg payload follows... */ -}; - - -enum auth_neg_param_tags { - FC_AUTH_NEG_DHCHAP_HASHLIST = 0x0001, - FC_AUTH_NEG_DHCHAP_DHG_ID_LIST = 0x0002, -}; - - -struct dhchap_param_format_s { - u16 tag; /*! Parameter Tag. See - * auth_neg_param_tags_t - */ - u16 word_cnt; - - /* followed by variable length parameter value... */ -}; - -struct auth_proto_params_s { - u32 proto_param_len; - u32 proto_id; - - /* - * Followed by variable length Protocol specific parameters. DH-CHAP - * uses dhchap_param_format_t - */ -}; - -struct auth_neg_msg_s { - struct auth_name_s auth_ini_name; - u32 usable_auth_protos; - struct auth_proto_params_s proto_params[1]; /*! (1..usable_auth_proto) - * protocol params - */ -}; - -struct auth_dh_val_s { - u32 dh_val_len; - u32 dh_val[1]; -}; - -struct auth_dhchap_chal_msg_s { - struct auth_els_msg_s hdr; - struct auth_name_s auth_responder_name; /* TODO VRK - is auth_name_t - * type OK? - */ - u32 hash_id; - u32 dh_grp_id; - u32 chal_val_len; - char chal_val[1]; - - /* ...followed by variable Challenge length/value and DH length/value */ -}; - - -enum auth_rjt_codes { - FC_AUTH_RJT_CODE_AUTH_FAILURE = 0x01, - FC_AUTH_RJT_CODE_LOGICAL_ERR = 0x02, -}; - -enum auth_rjt_code_exps { - FC_AUTH_CEXP_AUTH_MECH_NOT_USABLE = 0x01, - FC_AUTH_CEXP_DH_GROUP_NOT_USABLE = 0x02, - FC_AUTH_CEXP_HASH_FUNC_NOT_USABLE = 0x03, - FC_AUTH_CEXP_AUTH_XACT_STARTED = 0x04, - FC_AUTH_CEXP_AUTH_FAILED = 0x05, - FC_AUTH_CEXP_INCORRECT_PLD = 0x06, - FC_AUTH_CEXP_INCORRECT_PROTO_MSG = 0x07, - FC_AUTH_CEXP_RESTART_AUTH_PROTO = 0x08, - FC_AUTH_CEXP_AUTH_CONCAT_NOT_SUPP = 0x09, - FC_AUTH_CEXP_PROTO_VER_NOT_SUPP = 0x0A, -}; - -enum auth_status { - FC_AUTH_STATE_INPROGRESS = 0, /*! authentication in progress */ - FC_AUTH_STATE_FAILED = 1, /*! authentication failed */ - FC_AUTH_STATE_SUCCESS = 2 /*! authentication successful */ -}; - -struct auth_rjt_msg_s { - struct auth_els_msg_s hdr; - u8 reason_code; - u8 reason_code_exp; - u8 rsvd[2]; -}; - - -struct auth_dhchap_neg_msg_s { - struct auth_els_msg_s hdr; - struct auth_neg_msg_s nego; -}; - -struct auth_dhchap_reply_msg_s { - struct auth_els_msg_s hdr; - - /* - * followed by response value length & Value + DH Value Length & Value - */ -}; - -#pragma pack() - -#endif /* __FC_SP_H__ */ diff --git a/drivers/scsi/bfa/include/protocol/fcp.h b/drivers/scsi/bfa/include/protocol/fcp.h deleted file mode 100644 index 74ea63ce84b7..000000000000 --- a/drivers/scsi/bfa/include/protocol/fcp.h +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __FCPPROTO_H__ -#define __FCPPROTO_H__ - -#include <linux/bitops.h> -#include <protocol/scsi.h> - -#pragma pack(1) - -enum { - FCP_RJT = 0x01000000, /* SRR reject */ - FCP_SRR_ACCEPT = 0x02000000, /* SRR accept */ - FCP_SRR = 0x14000000, /* Sequence Retransmission Request */ -}; - -/* - * SRR FC-4 LS payload - */ -struct fc_srr_s{ - u32 ls_cmd; - u32 ox_id:16; /* ox-id */ - u32 rx_id:16; /* rx-id */ - u32 ro; /* relative offset */ - u32 r_ctl:8; /* R_CTL for I.U. */ - u32 res:24; -}; - - -/* - * FCP_CMND definitions - */ -#define FCP_CMND_CDB_LEN 16 -#define FCP_CMND_LUN_LEN 8 - -struct fcp_cmnd_s{ - lun_t lun; /* 64-bit LU number */ - u8 crn; /* command reference number */ -#ifdef __BIGENDIAN - u8 resvd:1, - priority:4, /* FCP-3: SAM-3 priority */ - taskattr:3; /* scsi task attribute */ -#else - u8 taskattr:3, /* scsi task attribute */ - priority:4, /* FCP-3: SAM-3 priority */ - resvd:1; -#endif - u8 tm_flags; /* task management flags */ -#ifdef __BIGENDIAN - u8 addl_cdb_len:6, /* additional CDB length words */ - iodir:2; /* read/write FCP_DATA IUs */ -#else - u8 iodir:2, /* read/write FCP_DATA IUs */ - addl_cdb_len:6; /* additional CDB length */ -#endif - struct scsi_cdb_s cdb; - - /* - * !!! additional cdb bytes follows here!!! - */ - u32 fcp_dl; /* bytes to be transferred */ -}; - -#define fcp_cmnd_cdb_len(_cmnd) ((_cmnd)->addl_cdb_len * 4 + FCP_CMND_CDB_LEN) -#define fcp_cmnd_fcpdl(_cmnd) ((&(_cmnd)->fcp_dl)[(_cmnd)->addl_cdb_len]) - -/* - * fcp_cmnd_t.iodir field values - */ -enum fcp_iodir{ - FCP_IODIR_NONE = 0, - FCP_IODIR_WRITE = 1, - FCP_IODIR_READ = 2, - FCP_IODIR_RW = 3, -}; - -/* - * Task attribute field - */ -enum { - FCP_TASK_ATTR_SIMPLE = 0, - FCP_TASK_ATTR_HOQ = 1, - FCP_TASK_ATTR_ORDERED = 2, - FCP_TASK_ATTR_ACA = 4, - FCP_TASK_ATTR_UNTAGGED = 5, /* obsolete in FCP-3 */ -}; - -/* - * Task management flags field - only one bit shall be set - */ -enum fcp_tm_cmnd{ - FCP_TM_ABORT_TASK_SET = BIT(1), - FCP_TM_CLEAR_TASK_SET = BIT(2), - FCP_TM_LUN_RESET = BIT(4), - FCP_TM_TARGET_RESET = BIT(5), /* obsolete in FCP-3 */ - FCP_TM_CLEAR_ACA = BIT(6), -}; - -/* - * FCP_XFER_RDY IU defines - */ -struct fcp_xfer_rdy_s{ - u32 data_ro; - u32 burst_len; - u32 reserved; -}; - -/* - * FCP_RSP residue flags - */ -enum fcp_residue{ - FCP_NO_RESIDUE = 0, /* no residue */ - FCP_RESID_OVER = 1, /* more data left that was not sent */ - FCP_RESID_UNDER = 2, /* less data than requested */ -}; - -enum { - FCP_RSPINFO_GOOD = 0, - FCP_RSPINFO_DATALEN_MISMATCH = 1, - FCP_RSPINFO_CMND_INVALID = 2, - FCP_RSPINFO_ROLEN_MISMATCH = 3, - FCP_RSPINFO_TM_NOT_SUPP = 4, - FCP_RSPINFO_TM_FAILED = 5, -}; - -struct fcp_rspinfo_s{ - u32 res0:24; - u32 rsp_code:8; /* response code (as above) */ - u32 res1; -}; - -struct fcp_resp_s{ - u32 reserved[2]; /* 2 words reserved */ - u16 reserved2; -#ifdef __BIGENDIAN - u8 reserved3:3; - u8 fcp_conf_req:1; /* FCP_CONF is requested */ - u8 resid_flags:2; /* underflow/overflow */ - u8 sns_len_valid:1;/* sense len is valid */ - u8 rsp_len_valid:1;/* response len is valid */ -#else - u8 rsp_len_valid:1;/* response len is valid */ - u8 sns_len_valid:1;/* sense len is valid */ - u8 resid_flags:2; /* underflow/overflow */ - u8 fcp_conf_req:1; /* FCP_CONF is requested */ - u8 reserved3:3; -#endif - u8 scsi_status; /* one byte SCSI status */ - u32 residue; /* residual data bytes */ - u32 sns_len; /* length od sense info */ - u32 rsp_len; /* length of response info */ -}; - -#define fcp_snslen(__fcprsp) ((__fcprsp)->sns_len_valid ? \ - (__fcprsp)->sns_len : 0) -#define fcp_rsplen(__fcprsp) ((__fcprsp)->rsp_len_valid ? \ - (__fcprsp)->rsp_len : 0) -#define fcp_rspinfo(__fcprsp) ((struct fcp_rspinfo_s *)((__fcprsp) + 1)) -#define fcp_snsinfo(__fcprsp) (((u8 *)fcp_rspinfo(__fcprsp)) + \ - fcp_rsplen(__fcprsp)) - -struct fcp_cmnd_fr_s{ - struct fchs_s fchs; - struct fcp_cmnd_s fcp; -}; - -#pragma pack() - -#endif diff --git a/drivers/scsi/bfa/include/protocol/fdmi.h b/drivers/scsi/bfa/include/protocol/fdmi.h deleted file mode 100644 index 6c05c268c71b..000000000000 --- a/drivers/scsi/bfa/include/protocol/fdmi.h +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __FDMI_H__ -#define __FDMI_H__ - -#include <protocol/types.h> -#include <protocol/fc.h> -#include <protocol/ct.h> - -#pragma pack(1) - -/* - * FDMI Command Codes - */ -#define FDMI_GRHL 0x0100 -#define FDMI_GHAT 0x0101 -#define FDMI_GRPL 0x0102 -#define FDMI_GPAT 0x0110 -#define FDMI_RHBA 0x0200 -#define FDMI_RHAT 0x0201 -#define FDMI_RPRT 0x0210 -#define FDMI_RPA 0x0211 -#define FDMI_DHBA 0x0300 -#define FDMI_DPRT 0x0310 - -/* - * FDMI reason codes - */ -#define FDMI_NO_ADDITIONAL_EXP 0x00 -#define FDMI_HBA_ALREADY_REG 0x10 -#define FDMI_HBA_ATTRIB_NOT_REG 0x11 -#define FDMI_HBA_ATTRIB_MULTIPLE 0x12 -#define FDMI_HBA_ATTRIB_LENGTH_INVALID 0x13 -#define FDMI_HBA_ATTRIB_NOT_PRESENT 0x14 -#define FDMI_PORT_ORIG_NOT_IN_LIST 0x15 -#define FDMI_PORT_HBA_NOT_IN_LIST 0x16 -#define FDMI_PORT_ATTRIB_NOT_REG 0x20 -#define FDMI_PORT_NOT_REG 0x21 -#define FDMI_PORT_ATTRIB_MULTIPLE 0x22 -#define FDMI_PORT_ATTRIB_LENGTH_INVALID 0x23 -#define FDMI_PORT_ALREADY_REGISTEREED 0x24 - -/* - * FDMI Transmission Speed Mask values - */ -#define FDMI_TRANS_SPEED_1G 0x00000001 -#define FDMI_TRANS_SPEED_2G 0x00000002 -#define FDMI_TRANS_SPEED_10G 0x00000004 -#define FDMI_TRANS_SPEED_4G 0x00000008 -#define FDMI_TRANS_SPEED_8G 0x00000010 -#define FDMI_TRANS_SPEED_16G 0x00000020 -#define FDMI_TRANS_SPEED_UNKNOWN 0x00008000 - -/* - * FDMI HBA attribute types - */ -enum fdmi_hba_attribute_type { - FDMI_HBA_ATTRIB_NODENAME = 1, /* 0x0001 */ - FDMI_HBA_ATTRIB_MANUFACTURER, /* 0x0002 */ - FDMI_HBA_ATTRIB_SERIALNUM, /* 0x0003 */ - FDMI_HBA_ATTRIB_MODEL, /* 0x0004 */ - FDMI_HBA_ATTRIB_MODEL_DESC, /* 0x0005 */ - FDMI_HBA_ATTRIB_HW_VERSION, /* 0x0006 */ - FDMI_HBA_ATTRIB_DRIVER_VERSION, /* 0x0007 */ - FDMI_HBA_ATTRIB_ROM_VERSION, /* 0x0008 */ - FDMI_HBA_ATTRIB_FW_VERSION, /* 0x0009 */ - FDMI_HBA_ATTRIB_OS_NAME, /* 0x000A */ - FDMI_HBA_ATTRIB_MAX_CT, /* 0x000B */ - - FDMI_HBA_ATTRIB_MAX_TYPE -}; - -/* - * FDMI Port attribute types - */ -enum fdmi_port_attribute_type { - FDMI_PORT_ATTRIB_FC4_TYPES = 1, /* 0x0001 */ - FDMI_PORT_ATTRIB_SUPP_SPEED, /* 0x0002 */ - FDMI_PORT_ATTRIB_PORT_SPEED, /* 0x0003 */ - FDMI_PORT_ATTRIB_FRAME_SIZE, /* 0x0004 */ - FDMI_PORT_ATTRIB_DEV_NAME, /* 0x0005 */ - FDMI_PORT_ATTRIB_HOST_NAME, /* 0x0006 */ - - FDMI_PORT_ATTR_MAX_TYPE -}; - -/* - * FDMI attribute - */ -struct fdmi_attr_s { - u16 type; - u16 len; - u8 value[1]; -}; - -/* - * HBA Attribute Block - */ -struct fdmi_hba_attr_s { - u32 attr_count; /* # of attributes */ - struct fdmi_attr_s hba_attr; /* n attributes */ -}; - -/* - * Registered Port List - */ -struct fdmi_port_list_s { - u32 num_ports; /* number Of Port Entries */ - wwn_t port_entry; /* one or more */ -}; - -/* - * Port Attribute Block - */ -struct fdmi_port_attr_s { - u32 attr_count; /* # of attributes */ - struct fdmi_attr_s port_attr; /* n attributes */ -}; - -/* - * FDMI Register HBA Attributes - */ -struct fdmi_rhba_s { - wwn_t hba_id; /* HBA Identifier */ - struct fdmi_port_list_s port_list; /* Registered Port List */ - struct fdmi_hba_attr_s hba_attr_blk; /* HBA attribute block */ -}; - -/* - * FDMI Register Port - */ -struct fdmi_rprt_s { - wwn_t hba_id; /* HBA Identifier */ - wwn_t port_name; /* Port wwn */ - struct fdmi_port_attr_s port_attr_blk; /* Port Attr Block */ -}; - -/* - * FDMI Register Port Attributes - */ -struct fdmi_rpa_s { - wwn_t port_name; /* port wwn */ - struct fdmi_port_attr_s port_attr_blk; /* Port Attr Block */ -}; - -#pragma pack() - -#endif diff --git a/drivers/scsi/bfa/include/protocol/scsi.h b/drivers/scsi/bfa/include/protocol/scsi.h deleted file mode 100644 index b220e6b4f6e1..000000000000 --- a/drivers/scsi/bfa/include/protocol/scsi.h +++ /dev/null @@ -1,1648 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __SCSI_H__ -#define __SCSI_H__ - -#include <protocol/types.h> - -#pragma pack(1) - -/* - * generic SCSI cdb definition - */ -#define SCSI_MAX_CDBLEN 16 -struct scsi_cdb_s{ - u8 scsi_cdb[SCSI_MAX_CDBLEN]; -}; - -/* - * scsi lun serial number definition - */ -#define SCSI_LUN_SN_LEN 32 -struct scsi_lun_sn_s{ - u8 lun_sn[SCSI_LUN_SN_LEN]; -}; - -/* - * SCSI Direct Access Commands - */ -enum { - SCSI_OP_TEST_UNIT_READY = 0x00, - SCSI_OP_REQUEST_SENSE = 0x03, - SCSI_OP_FORMAT_UNIT = 0x04, - SCSI_OP_READ6 = 0x08, - SCSI_OP_WRITE6 = 0x0A, - SCSI_OP_WRITE_FILEMARKS = 0x10, - SCSI_OP_INQUIRY = 0x12, - SCSI_OP_MODE_SELECT6 = 0x15, - SCSI_OP_RESERVE6 = 0x16, - SCSI_OP_RELEASE6 = 0x17, - SCSI_OP_MODE_SENSE6 = 0x1A, - SCSI_OP_START_STOP_UNIT = 0x1B, - SCSI_OP_SEND_DIAGNOSTIC = 0x1D, - SCSI_OP_READ_CAPACITY = 0x25, - SCSI_OP_READ10 = 0x28, - SCSI_OP_WRITE10 = 0x2A, - SCSI_OP_VERIFY10 = 0x2F, - SCSI_OP_READ_DEFECT_DATA = 0x37, - SCSI_OP_LOG_SELECT = 0x4C, - SCSI_OP_LOG_SENSE = 0x4D, - SCSI_OP_MODE_SELECT10 = 0x55, - SCSI_OP_RESERVE10 = 0x56, - SCSI_OP_RELEASE10 = 0x57, - SCSI_OP_MODE_SENSE10 = 0x5A, - SCSI_OP_PER_RESERVE_IN = 0x5E, - SCSI_OP_PER_RESERVE_OUR = 0x5E, - SCSI_OP_READ16 = 0x88, - SCSI_OP_WRITE16 = 0x8A, - SCSI_OP_VERIFY16 = 0x8F, - SCSI_OP_READ_CAPACITY16 = 0x9E, - SCSI_OP_REPORT_LUNS = 0xA0, - SCSI_OP_READ12 = 0xA8, - SCSI_OP_WRITE12 = 0xAA, - SCSI_OP_UNDEF = 0xFF, -}; - -/* - * SCSI START_STOP_UNIT command - */ -struct scsi_start_stop_unit_s{ - u8 opcode; -#ifdef __BIGENDIAN - u8 lun:3; - u8 reserved1:4; - u8 immed:1; -#else - u8 immed:1; - u8 reserved1:4; - u8 lun:3; -#endif - u8 reserved2; - u8 reserved3; -#ifdef __BIGENDIAN - u8 power_conditions:4; - u8 reserved4:2; - u8 loEj:1; - u8 start:1; -#else - u8 start:1; - u8 loEj:1; - u8 reserved4:2; - u8 power_conditions:4; -#endif - u8 control; -}; - -/* - * SCSI SEND_DIAGNOSTIC command - */ -struct scsi_send_diagnostic_s{ - u8 opcode; -#ifdef __BIGENDIAN - u8 self_test_code:3; - u8 pf:1; - u8 reserved1:1; - u8 self_test:1; - u8 dev_offl:1; - u8 unit_offl:1; -#else - u8 unit_offl:1; - u8 dev_offl:1; - u8 self_test:1; - u8 reserved1:1; - u8 pf:1; - u8 self_test_code:3; -#endif - u8 reserved2; - - u8 param_list_length[2]; /* MSB first */ - u8 control; - -}; - -/* - * SCSI READ10/WRITE10 commands - */ -struct scsi_rw10_s{ - u8 opcode; -#ifdef __BIGENDIAN - u8 lun:3; - u8 dpo:1; /* Disable Page Out */ - u8 fua:1; /* Force Unit Access */ - u8 reserved1:2; - u8 rel_adr:1; /* relative address */ -#else - u8 rel_adr:1; - u8 reserved1:2; - u8 fua:1; - u8 dpo:1; - u8 lun:3; -#endif - u8 lba0; /* logical block address - MSB */ - u8 lba1; - u8 lba2; - u8 lba3; /* LSB */ - u8 reserved3; - u8 xfer_length0; /* transfer length in blocks - MSB */ - u8 xfer_length1; /* LSB */ - u8 control; -}; - -#define SCSI_CDB10_GET_LBA(cdb) \ - (((cdb)->lba0 << 24) | ((cdb)->lba1 << 16) | \ - ((cdb)->lba2 << 8) | (cdb)->lba3) - -#define SCSI_CDB10_SET_LBA(cdb, lba) { \ - (cdb)->lba0 = lba >> 24; \ - (cdb)->lba1 = (lba >> 16) & 0xFF; \ - (cdb)->lba2 = (lba >> 8) & 0xFF; \ - (cdb)->lba3 = lba & 0xFF; \ -} - -#define SCSI_CDB10_GET_TL(cdb) \ - ((cdb)->xfer_length0 << 8 | (cdb)->xfer_length1) -#define SCSI_CDB10_SET_TL(cdb, tl) { \ - (cdb)->xfer_length0 = tl >> 8; \ - (cdb)->xfer_length1 = tl & 0xFF; \ -} - -/* - * SCSI READ6/WRITE6 commands - */ -struct scsi_rw6_s{ - u8 opcode; -#ifdef __BIGENDIAN - u8 lun:3; - u8 lba0:5; /* MSb */ -#else - u8 lba0:5; /* MSb */ - u8 lun:3; -#endif - u8 lba1; - u8 lba2; /* LSB */ - u8 xfer_length; - u8 control; -}; - -#define SCSI_TAPE_CDB6_GET_TL(cdb) \ - (((cdb)->tl0 << 16) | ((cdb)->tl1 << 8) | (cdb)->tl2) - -#define SCSI_TAPE_CDB6_SET_TL(cdb, tl) { \ - (cdb)->tl0 = tl >> 16; \ - (cdb)->tl1 = (tl >> 8) & 0xFF; \ - (cdb)->tl2 = tl & 0xFF; \ -} - -/* - * SCSI sequential (TAPE) wrtie command - */ -struct scsi_tape_wr_s{ - u8 opcode; -#ifdef __BIGENDIAN - u8 rsvd:7; - u8 fixed:1; /* MSb */ -#else - u8 fixed:1; /* MSb */ - u8 rsvd:7; -#endif - u8 tl0; /* Msb */ - u8 tl1; - u8 tl2; /* Lsb */ - - u8 control; -}; - -#define SCSI_CDB6_GET_LBA(cdb) \ - (((cdb)->lba0 << 16) | ((cdb)->lba1 << 8) | (cdb)->lba2) - -#define SCSI_CDB6_SET_LBA(cdb, lba) { \ - (cdb)->lba0 = lba >> 16; \ - (cdb)->lba1 = (lba >> 8) & 0xFF; \ - (cdb)->lba2 = lba & 0xFF; \ -} - -#define SCSI_CDB6_GET_TL(cdb) ((cdb)->xfer_length) -#define SCSI_CDB6_SET_TL(cdb, tl) { \ - (cdb)->xfer_length = tl; \ -} - -/* - * SCSI sense data format - */ -struct scsi_sense_s{ -#ifdef __BIGENDIAN - u8 valid:1; - u8 rsp_code:7; -#else - u8 rsp_code:7; - u8 valid:1; -#endif - u8 seg_num; -#ifdef __BIGENDIAN - u8 file_mark:1; - u8 eom:1; /* end of media */ - u8 ili:1; /* incorrect length indicator */ - u8 reserved:1; - u8 sense_key:4; -#else - u8 sense_key:4; - u8 reserved:1; - u8 ili:1; /* incorrect length indicator */ - u8 eom:1; /* end of media */ - u8 file_mark:1; -#endif - u8 information[4]; /* device-type or command specific info - */ - u8 add_sense_length; - /* additional sense length */ - u8 command_info[4];/* command specific information - */ - u8 asc; /* additional sense code */ - u8 ascq; /* additional sense code qualifier */ - u8 fru_code; /* field replaceable unit code */ -#ifdef __BIGENDIAN - u8 sksv:1; /* sense key specific valid */ - u8 c_d:1; /* command/data bit */ - u8 res1:2; - u8 bpv:1; /* bit pointer valid */ - u8 bpointer:3; /* bit pointer */ -#else - u8 bpointer:3; /* bit pointer */ - u8 bpv:1; /* bit pointer valid */ - u8 res1:2; - u8 c_d:1; /* command/data bit */ - u8 sksv:1; /* sense key specific valid */ -#endif - u8 fpointer[2]; /* field pointer */ -}; - -#define SCSI_SENSE_CUR_ERR 0x70 -#define SCSI_SENSE_DEF_ERR 0x71 - -/* - * SCSI sense key values - */ -#define SCSI_SK_NO_SENSE 0x0 -#define SCSI_SK_REC_ERR 0x1 /* recovered error */ -#define SCSI_SK_NOT_READY 0x2 -#define SCSI_SK_MED_ERR 0x3 /* medium error */ -#define SCSI_SK_HW_ERR 0x4 /* hardware error */ -#define SCSI_SK_ILLEGAL_REQ 0x5 -#define SCSI_SK_UNIT_ATT 0x6 /* unit attention */ -#define SCSI_SK_DATA_PROTECT 0x7 -#define SCSI_SK_BLANK_CHECK 0x8 -#define SCSI_SK_VENDOR_SPEC 0x9 -#define SCSI_SK_COPY_ABORTED 0xA -#define SCSI_SK_ABORTED_CMND 0xB -#define SCSI_SK_VOL_OVERFLOW 0xD -#define SCSI_SK_MISCOMPARE 0xE - -/* - * SCSI additional sense codes - */ -#define SCSI_ASC_NO_ADD_SENSE 0x00 -#define SCSI_ASC_LUN_NOT_READY 0x04 -#define SCSI_ASC_LUN_COMMUNICATION 0x08 -#define SCSI_ASC_WRITE_ERROR 0x0C -#define SCSI_ASC_INVALID_CMND_CODE 0x20 -#define SCSI_ASC_BAD_LBA 0x21 -#define SCSI_ASC_INVALID_FIELD_IN_CDB 0x24 -#define SCSI_ASC_LUN_NOT_SUPPORTED 0x25 -#define SCSI_ASC_LUN_WRITE_PROTECT 0x27 -#define SCSI_ASC_POWERON_BDR 0x29 /* power on reset, bus reset, - * bus device reset - */ -#define SCSI_ASC_PARAMS_CHANGED 0x2A -#define SCSI_ASC_CMND_CLEARED_BY_A_I 0x2F -#define SCSI_ASC_SAVING_PARAM_NOTSUPP 0x39 -#define SCSI_ASC_TOCC 0x3F /* target operating condtions - * changed - */ -#define SCSI_ASC_PARITY_ERROR 0x47 -#define SCSI_ASC_CMND_PHASE_ERROR 0x4A -#define SCSI_ASC_DATA_PHASE_ERROR 0x4B -#define SCSI_ASC_VENDOR_SPEC 0x7F - -/* - * SCSI additional sense code qualifiers - */ -#define SCSI_ASCQ_CAUSE_NOT_REPORT 0x00 -#define SCSI_ASCQ_BECOMING_READY 0x01 -#define SCSI_ASCQ_INIT_CMD_REQ 0x02 -#define SCSI_ASCQ_FORMAT_IN_PROGRESS 0x04 -#define SCSI_ASCQ_OPERATION_IN_PROGRESS 0x07 -#define SCSI_ASCQ_SELF_TEST_IN_PROGRESS 0x09 -#define SCSI_ASCQ_WR_UNEXP_UNSOL_DATA 0x0C -#define SCSI_ASCQ_WR_NOTENG_UNSOL_DATA 0x0D - -#define SCSI_ASCQ_LBA_OUT_OF_RANGE 0x00 -#define SCSI_ASCQ_INVALID_ELEMENT_ADDR 0x01 - -#define SCSI_ASCQ_LUN_WRITE_PROTECTED 0x00 -#define SCSI_ASCQ_LUN_HW_WRITE_PROTECTED 0x01 -#define SCSI_ASCQ_LUN_SW_WRITE_PROTECTED 0x02 - -#define SCSI_ASCQ_POR 0x01 /* power on reset */ -#define SCSI_ASCQ_SBR 0x02 /* scsi bus reset */ -#define SCSI_ASCQ_BDR 0x03 /* bus device reset */ -#define SCSI_ASCQ_DIR 0x04 /* device internal reset */ - -#define SCSI_ASCQ_MODE_PARAMS_CHANGED 0x01 -#define SCSI_ASCQ_LOG_PARAMS_CHANGED 0x02 -#define SCSI_ASCQ_RESERVATIONS_PREEMPTED 0x03 -#define SCSI_ASCQ_RESERVATIONS_RELEASED 0x04 -#define SCSI_ASCQ_REGISTRATIONS_PREEMPTED 0x05 - -#define SCSI_ASCQ_MICROCODE_CHANGED 0x01 -#define SCSI_ASCQ_CHANGED_OPER_COND 0x02 -#define SCSI_ASCQ_INQ_CHANGED 0x03 /* inquiry data changed */ -#define SCSI_ASCQ_DI_CHANGED 0x05 /* device id changed */ -#define SCSI_ASCQ_RL_DATA_CHANGED 0x0E /* report luns data changed */ - -#define SCSI_ASCQ_DP_CRC_ERR 0x01 /* data phase crc error */ -#define SCSI_ASCQ_DP_SCSI_PARITY_ERR 0x02 /* data phase scsi parity error - */ -#define SCSI_ASCQ_IU_CRC_ERR 0x03 /* information unit crc error */ -#define SCSI_ASCQ_PROTO_SERV_CRC_ERR 0x05 - -#define SCSI_ASCQ_LUN_TIME_OUT 0x01 - -/* ------------------------------------------------------------ - * SCSI INQUIRY - * ------------------------------------------------------------*/ - -struct scsi_inquiry_s{ - u8 opcode; -#ifdef __BIGENDIAN - u8 lun:3; - u8 reserved1:3; - u8 cmd_dt:1; - u8 evpd:1; -#else - u8 evpd:1; - u8 cmd_dt:1; - u8 reserved1:3; - u8 lun:3; -#endif - u8 page_code; - u8 reserved2; - u8 alloc_length; - u8 control; -}; - -struct scsi_inquiry_vendor_s{ - u8 vendor_id[8]; -}; - -struct scsi_inquiry_prodid_s{ - u8 product_id[16]; -}; - -struct scsi_inquiry_prodrev_s{ - u8 product_rev[4]; -}; - -struct scsi_inquiry_data_s{ -#ifdef __BIGENDIAN - u8 peripheral_qual:3; /* peripheral qualifier */ - u8 device_type:5; /* peripheral device type */ - - u8 rmb:1; /* removable medium bit */ - u8 device_type_mod:7; /* device type modifier */ - - u8 version; - - u8 aenc:1; /* async event notification capability - */ - u8 trm_iop:1; /* terminate I/O process */ - u8 norm_aca:1; /* normal ACA supported */ - u8 hi_support:1; /* SCSI-3: supports REPORT LUNS */ - u8 rsp_data_format:4; - - u8 additional_len; - u8 sccs:1; - u8 reserved1:7; - - u8 reserved2:1; - u8 enc_serv:1; /* enclosure service component */ - u8 reserved3:1; - u8 multi_port:1; /* multi-port device */ - u8 m_chngr:1; /* device in medium transport element */ - u8 ack_req_q:1; /* SIP specific bit */ - u8 addr32:1; /* SIP specific bit */ - u8 addr16:1; /* SIP specific bit */ - - u8 rel_adr:1; /* relative address */ - u8 w_bus32:1; - u8 w_bus16:1; - u8 synchronous:1; - u8 linked_commands:1; - u8 trans_dis:1; - u8 cmd_queue:1; /* command queueing supported */ - u8 soft_reset:1; /* soft reset alternative (VS) */ -#else - u8 device_type:5; /* peripheral device type */ - u8 peripheral_qual:3; - /* peripheral qualifier */ - - u8 device_type_mod:7; - /* device type modifier */ - u8 rmb:1; /* removable medium bit */ - - u8 version; - - u8 rsp_data_format:4; - u8 hi_support:1; /* SCSI-3: supports REPORT LUNS */ - u8 norm_aca:1; /* normal ACA supported */ - u8 terminate_iop:1;/* terminate I/O process */ - u8 aenc:1; /* async event notification capability - */ - - u8 additional_len; - u8 reserved1:7; - u8 sccs:1; - - u8 addr16:1; /* SIP specific bit */ - u8 addr32:1; /* SIP specific bit */ - u8 ack_req_q:1; /* SIP specific bit */ - u8 m_chngr:1; /* device in medium transport element */ - u8 multi_port:1; /* multi-port device */ - u8 reserved3:1; /* TBD - Vendor Specific */ - u8 enc_serv:1; /* enclosure service component */ - u8 reserved2:1; - - u8 soft_seset:1; /* soft reset alternative (VS) */ - u8 cmd_queue:1; /* command queueing supported */ - u8 trans_dis:1; - u8 linked_commands:1; - u8 synchronous:1; - u8 w_bus16:1; - u8 w_bus32:1; - u8 rel_adr:1; /* relative address */ -#endif - struct scsi_inquiry_vendor_s vendor_id; - struct scsi_inquiry_prodid_s product_id; - struct scsi_inquiry_prodrev_s product_rev; - u8 vendor_specific[20]; - u8 reserved4[40]; -}; - -/* - * inquiry.peripheral_qual field values - */ -#define SCSI_DEVQUAL_DEFAULT 0 -#define SCSI_DEVQUAL_NOT_CONNECTED 1 -#define SCSI_DEVQUAL_NOT_SUPPORTED 3 - -/* - * inquiry.device_type field values - */ -#define SCSI_DEVICE_DIRECT_ACCESS 0x00 -#define SCSI_DEVICE_SEQ_ACCESS 0x01 -#define SCSI_DEVICE_ARRAY_CONTROLLER 0x0C -#define SCSI_DEVICE_UNKNOWN 0x1F - -/* - * inquiry.version - */ -#define SCSI_VERSION_ANSI_X3131 2 /* ANSI X3.131 SCSI-2 */ -#define SCSI_VERSION_SPC 3 /* SPC (SCSI-3), ANSI X3.301:1997 */ -#define SCSI_VERSION_SPC_2 4 /* SPC-2 */ - -/* - * response data format - */ -#define SCSI_RSP_DATA_FORMAT 2 /* SCSI-2 & SPC */ - -/* - * SCSI inquiry page codes - */ -#define SCSI_INQ_PAGE_VPD_PAGES 0x00 /* supported vpd pages */ -#define SCSI_INQ_PAGE_USN_PAGE 0x80 /* unit serial number page */ -#define SCSI_INQ_PAGE_DEV_IDENT 0x83 /* device indentification page - */ -#define SCSI_INQ_PAGES_MAX 3 - -/* - * supported vital product data pages - */ -struct scsi_inq_page_vpd_pages_s{ -#ifdef __BIGENDIAN - u8 peripheral_qual:3; - u8 device_type:5; -#else - u8 device_type:5; - u8 peripheral_qual:3; -#endif - u8 page_code; - u8 reserved; - u8 page_length; - u8 pages[SCSI_INQ_PAGES_MAX]; -}; - -/* - * Unit serial number page - */ -#define SCSI_INQ_USN_LEN 32 - -struct scsi_inq_usn_s{ - char usn[SCSI_INQ_USN_LEN]; -}; - -struct scsi_inq_page_usn_s{ -#ifdef __BIGENDIAN - u8 peripheral_qual:3; - u8 device_type:5; -#else - u8 device_type:5; - u8 peripheral_qual:3; -#endif - u8 page_code; - u8 reserved1; - u8 page_length; - struct scsi_inq_usn_s usn; -}; - -enum { - SCSI_INQ_DIP_CODE_BINARY = 1, /* identifier has binary value */ - SCSI_INQ_DIP_CODE_ASCII = 2, /* identifier has ascii value */ -}; - -enum { - SCSI_INQ_DIP_ASSOC_LUN = 0, /* id is associated with device */ - SCSI_INQ_DIP_ASSOC_PORT = 1, /* id is associated with port that - * received the request - */ -}; - -enum { - SCSI_INQ_ID_TYPE_VENDOR = 1, - SCSI_INQ_ID_TYPE_IEEE = 2, - SCSI_INQ_ID_TYPE_FC_FS = 3, - SCSI_INQ_ID_TYPE_OTHER = 4, -}; - -struct scsi_inq_dip_desc_s{ -#ifdef __BIGENDIAN - u8 res0:4; - u8 code_set:4; - u8 res1:2; - u8 association:2; - u8 id_type:4; -#else - u8 code_set:4; - u8 res0:4; - u8 id_type:4; - u8 association:2; - u8 res1:2; -#endif - u8 res2; - u8 id_len; - struct scsi_lun_sn_s id; -}; - -/* - * Device indentification page - */ -struct scsi_inq_page_dev_ident_s{ -#ifdef __BIGENDIAN - u8 peripheral_qual:3; - u8 device_type:5; -#else - u8 device_type:5; - u8 peripheral_qual:3; -#endif - u8 page_code; - u8 reserved1; - u8 page_length; - struct scsi_inq_dip_desc_s desc; -}; - -/* ------------------------------------------------------------ - * READ CAPACITY - * ------------------------------------------------------------ - */ - -struct scsi_read_capacity_s{ - u8 opcode; -#ifdef __BIGENDIAN - u8 lun:3; - u8 reserved1:4; - u8 rel_adr:1; -#else - u8 rel_adr:1; - u8 reserved1:4; - u8 lun:3; -#endif - u8 lba0; /* MSB */ - u8 lba1; - u8 lba2; - u8 lba3; /* LSB */ - u8 reserved2; - u8 reserved3; -#ifdef __BIGENDIAN - u8 reserved4:7; - u8 pmi:1; /* partial medium indicator */ -#else - u8 pmi:1; /* partial medium indicator */ - u8 reserved4:7; -#endif - u8 control; -}; - -struct scsi_read_capacity_data_s{ - u32 max_lba; /* maximum LBA available */ - u32 block_length; /* in bytes */ -}; - -struct scsi_read_capacity16_data_s{ - u64 lba; /* maximum LBA available */ - u32 block_length; /* in bytes */ -#ifdef __BIGENDIAN - u8 reserved1:4, - p_type:3, - prot_en:1; - u8 reserved2:4, - lb_pbe:4; /* logical blocks per physical block - * exponent */ - u16 reserved3:2, - lba_align:14; /* lowest aligned logical block - * address */ -#else - u16 lba_align:14, /* lowest aligned logical block - * address */ - reserved3:2; - u8 lb_pbe:4, /* logical blocks per physical block - * exponent */ - reserved2:4; - u8 prot_en:1, - p_type:3, - reserved1:4; -#endif - u64 reserved4; - u64 reserved5; -}; - -/* ------------------------------------------------------------ - * REPORT LUNS command - * ------------------------------------------------------------ - */ - -struct scsi_report_luns_s{ - u8 opcode; /* A0h - REPORT LUNS opCode */ - u8 reserved1[5]; - u8 alloc_length[4];/* allocation length MSB first */ - u8 reserved2; - u8 control; -}; - -#define SCSI_REPORT_LUN_ALLOC_LENGTH(rl) \ - ((rl->alloc_length[0] << 24) | (rl->alloc_length[1] << 16) | \ - (rl->alloc_length[2] << 8) | (rl->alloc_length[3])) - -#define SCSI_REPORT_LUNS_SET_ALLOCLEN(rl, alloc_len) { \ - (rl)->alloc_length[0] = (alloc_len) >> 24; \ - (rl)->alloc_length[1] = ((alloc_len) >> 16) & 0xFF; \ - (rl)->alloc_length[2] = ((alloc_len) >> 8) & 0xFF; \ - (rl)->alloc_length[3] = (alloc_len) & 0xFF; \ -} - -struct scsi_report_luns_data_s{ - u32 lun_list_length; /* length of LUN list length */ - u32 reserved; - lun_t lun[1]; /* first LUN in lun list */ -}; - -/* ------------------------------------------------------------- - * SCSI mode parameters - * ----------------------------------------------------------- - */ -enum { - SCSI_DA_MEDIUM_DEF = 0, /* direct access default medium type */ - SCSI_DA_MEDIUM_SS = 1, /* direct access single sided */ - SCSI_DA_MEDIUM_DS = 2, /* direct access double sided */ -}; - -/* - * SCSI Mode Select(6) cdb - */ -struct scsi_mode_select6_s{ - u8 opcode; -#ifdef __BIGENDIAN - u8 reserved1:3; - u8 pf:1; /* page format */ - u8 reserved2:3; - u8 sp:1; /* save pages if set to 1 */ -#else - u8 sp:1; /* save pages if set to 1 */ - u8 reserved2:3; - u8 pf:1; /* page format */ - u8 reserved1:3; -#endif - u8 reserved3[2]; - u8 alloc_len; - u8 control; -}; - -/* - * SCSI Mode Select(10) cdb - */ -struct scsi_mode_select10_s{ - u8 opcode; -#ifdef __BIGENDIAN - u8 reserved1:3; - u8 pf:1; /* page format */ - u8 reserved2:3; - u8 sp:1; /* save pages if set to 1 */ -#else - u8 sp:1; /* save pages if set to 1 */ - u8 reserved2:3; - u8 pf:1; /* page format */ - u8 reserved1:3; -#endif - u8 reserved3[5]; - u8 alloc_len_msb; - u8 alloc_len_lsb; - u8 control; -}; - -/* - * SCSI Mode Sense(6) cdb - */ -struct scsi_mode_sense6_s{ - u8 opcode; -#ifdef __BIGENDIAN - u8 reserved1:4; - u8 dbd:1; /* disable block discriptors if set to 1 */ - u8 reserved2:3; - - u8 pc:2; /* page control */ - u8 page_code:6; -#else - u8 reserved2:3; - u8 dbd:1; /* disable block descriptors if set to 1 */ - u8 reserved1:4; - - u8 page_code:6; - u8 pc:2; /* page control */ -#endif - u8 reserved3; - u8 alloc_len; - u8 control; -}; - -/* - * SCSI Mode Sense(10) cdb - */ -struct scsi_mode_sense10_s{ - u8 opcode; -#ifdef __BIGENDIAN - u8 reserved1:3; - u8 LLBAA:1; /* long LBA accepted if set to 1 */ - u8 dbd:1; /* disable block descriptors if set - * to 1 - */ - u8 reserved2:3; - - u8 pc:2; /* page control */ - u8 page_code:6; -#else - u8 reserved2:3; - u8 dbd:1; /* disable block descriptors if set to - * 1 - */ - u8 LLBAA:1; /* long LBA accepted if set to 1 */ - u8 reserved1:3; - - u8 page_code:6; - u8 pc:2; /* page control */ -#endif - u8 reserved3[4]; - u8 alloc_len_msb; - u8 alloc_len_lsb; - u8 control; -}; - -#define SCSI_CDB10_GET_AL(cdb) \ - ((cdb)->alloc_len_msb << 8 | (cdb)->alloc_len_lsb) - -#define SCSI_CDB10_SET_AL(cdb, al) { \ - (cdb)->alloc_len_msb = al >> 8; \ - (cdb)->alloc_len_lsb = al & 0xFF; \ -} - -#define SCSI_CDB6_GET_AL(cdb) ((cdb)->alloc_len) - -#define SCSI_CDB6_SET_AL(cdb, al) { \ - (cdb)->alloc_len = al; \ -} - -/* - * page control field values - */ -#define SCSI_PC_CURRENT_VALUES 0x0 -#define SCSI_PC_CHANGEABLE_VALUES 0x1 -#define SCSI_PC_DEFAULT_VALUES 0x2 -#define SCSI_PC_SAVED_VALUES 0x3 - -/* - * SCSI mode page codes - */ -#define SCSI_MP_VENDOR_SPEC 0x00 -#define SCSI_MP_DISC_RECN 0x02 /* disconnect-reconnect page */ -#define SCSI_MP_FORMAT_DEVICE 0x03 -#define SCSI_MP_RDG 0x04 /* rigid disk geometry page */ -#define SCSI_MP_FDP 0x05 /* flexible disk page */ -#define SCSI_MP_CACHING 0x08 /* caching page */ -#define SCSI_MP_CONTROL 0x0A /* control mode page */ -#define SCSI_MP_MED_TYPES_SUP 0x0B /* medium types supported page */ -#define SCSI_MP_INFO_EXCP_CNTL 0x1C /* informational exception control */ -#define SCSI_MP_ALL 0x3F /* return all pages - mode sense only */ - -/* - * mode parameter header - */ -struct scsi_mode_param_header6_s{ - u8 mode_datalen; - u8 medium_type; - - /* - * device specific parameters expanded for direct access devices - */ -#ifdef __BIGENDIAN - u32 wp:1; /* write protected */ - u32 reserved1:2; - u32 dpofua:1; /* disable page out + force unit access - */ - u32 reserved2:4; -#else - u32 reserved2:4; - u32 dpofua:1; /* disable page out + force unit access - */ - u32 reserved1:2; - u32 wp:1; /* write protected */ -#endif - - u8 block_desclen; -}; - -struct scsi_mode_param_header10_s{ - u32 mode_datalen:16; - u32 medium_type:8; - - /* - * device specific parameters expanded for direct access devices - */ -#ifdef __BIGENDIAN - u32 wp:1; /* write protected */ - u32 reserved1:2; - u32 dpofua:1; /* disable page out + force unit access - */ - u32 reserved2:4; -#else - u32 reserved2:4; - u32 dpofua:1; /* disable page out + force unit access - */ - u32 reserved1:2; - u32 wp:1; /* write protected */ -#endif - -#ifdef __BIGENDIAN - u32 reserved3:7; - u32 longlba:1; -#else - u32 longlba:1; - u32 reserved3:7; -#endif - u32 reserved4:8; - u32 block_desclen:16; -}; - -/* - * mode parameter block descriptor - */ -struct scsi_mode_param_desc_s{ - u32 nblks; - u32 density_code:8; - u32 block_length:24; -}; - -/* - * Disconnect-reconnect mode page format - */ -struct scsi_mp_disc_recn_s{ -#ifdef __BIGENDIAN - u8 ps:1; - u8 reserved1:1; - u8 page_code:6; -#else - u8 page_code:6; - u8 reserved1:1; - u8 ps:1; -#endif - u8 page_len; - u8 buf_full_ratio; - u8 buf_empty_ratio; - - u8 bil_msb; /* bus inactivity limit -MSB */ - u8 bil_lsb; /* bus inactivity limit -LSB */ - - u8 dtl_msb; /* disconnect time limit - MSB */ - u8 dtl_lsb; /* disconnect time limit - LSB */ - - u8 ctl_msb; /* connect time limit - MSB */ - u8 ctl_lsb; /* connect time limit - LSB */ - - u8 max_burst_len_msb; - u8 max_burst_len_lsb; -#ifdef __BIGENDIAN - u8 emdp:1; /* enable modify data pointers */ - u8 fa:3; /* fair arbitration */ - u8 dimm:1; /* disconnect immediate */ - u8 dtdc:3; /* data transfer disconnect control */ -#else - u8 dtdc:3; /* data transfer disconnect control */ - u8 dimm:1; /* disconnect immediate */ - u8 fa:3; /* fair arbitration */ - u8 emdp:1; /* enable modify data pointers */ -#endif - - u8 reserved3; - - u8 first_burst_len_msb; - u8 first_burst_len_lsb; -}; - -/* - * SCSI format device mode page - */ -struct scsi_mp_format_device_s{ -#ifdef __BIGENDIAN - u32 ps:1; - u32 reserved1:1; - u32 page_code:6; -#else - u32 page_code:6; - u32 reserved1:1; - u32 ps:1; -#endif - u32 page_len:8; - u32 tracks_per_zone:16; - - u32 a_sec_per_zone:16; - u32 a_tracks_per_zone:16; - - u32 a_tracks_per_lun:16; /* alternate tracks/lun-MSB */ - u32 sec_per_track:16; /* sectors/track-MSB */ - - u32 bytes_per_sector:16; - u32 interleave:16; - - u32 tsf:16; /* track skew factor-MSB */ - u32 csf:16; /* cylinder skew factor-MSB */ - -#ifdef __BIGENDIAN - u32 ssec:1; /* soft sector formatting */ - u32 hsec:1; /* hard sector formatting */ - u32 rmb:1; /* removable media */ - u32 surf:1; /* surface */ - u32 reserved2:4; -#else - u32 reserved2:4; - u32 surf:1; /* surface */ - u32 rmb:1; /* removable media */ - u32 hsec:1; /* hard sector formatting */ - u32 ssec:1; /* soft sector formatting */ -#endif - u32 reserved3:24; -}; - -/* - * SCSI rigid disk device geometry page - */ -struct scsi_mp_rigid_device_geometry_s{ -#ifdef __BIGENDIAN - u32 ps:1; - u32 reserved1:1; - u32 page_code:6; -#else - u32 page_code:6; - u32 reserved1:1; - u32 ps:1; -#endif - u32 page_len:8; - u32 num_cylinders0:8; - u32 num_cylinders1:8; - - u32 num_cylinders2:8; - u32 num_heads:8; - u32 scwp0:8; - u32 scwp1:8; - - u32 scwp2:8; - u32 scrwc0:8; - u32 scrwc1:8; - u32 scrwc2:8; - - u32 dsr:16; - u32 lscyl0:8; - u32 lscyl1:8; - - u32 lscyl2:8; -#ifdef __BIGENDIAN - u32 reserved2:6; - u32 rpl:2; /* rotational position locking */ -#else - u32 rpl:2; /* rotational position locking */ - u32 reserved2:6; -#endif - u32 rot_off:8; - u32 reserved3:8; - - u32 med_rot_rate:16; - u32 reserved4:16; -}; - -/* - * SCSI caching mode page - */ -struct scsi_mp_caching_s{ -#ifdef __BIGENDIAN - u8 ps:1; - u8 res1:1; - u8 page_code:6; -#else - u8 page_code:6; - u8 res1:1; - u8 ps:1; -#endif - u8 page_len; -#ifdef __BIGENDIAN - u8 ic:1; /* initiator control */ - u8 abpf:1; /* abort pre-fetch */ - u8 cap:1; /* caching analysis permitted */ - u8 disc:1; /* discontinuity */ - u8 size:1; /* size enable */ - u8 wce:1; /* write cache enable */ - u8 mf:1; /* multiplication factor */ - u8 rcd:1; /* read cache disable */ - - u8 drrp:4; /* demand read retention priority */ - u8 wrp:4; /* write retention priority */ -#else - u8 rcd:1; /* read cache disable */ - u8 mf:1; /* multiplication factor */ - u8 wce:1; /* write cache enable */ - u8 size:1; /* size enable */ - u8 disc:1; /* discontinuity */ - u8 cap:1; /* caching analysis permitted */ - u8 abpf:1; /* abort pre-fetch */ - u8 ic:1; /* initiator control */ - - u8 wrp:4; /* write retention priority */ - u8 drrp:4; /* demand read retention priority */ -#endif - u8 dptl[2];/* disable pre-fetch transfer length */ - u8 min_prefetch[2]; - u8 max_prefetch[2]; - u8 max_prefetch_limit[2]; -#ifdef __BIGENDIAN - u8 fsw:1; /* force sequential write */ - u8 lbcss:1;/* logical block cache segment size */ - u8 dra:1; /* disable read ahead */ - u8 vs:2; /* vendor specific */ - u8 res2:3; -#else - u8 res2:3; - u8 vs:2; /* vendor specific */ - u8 dra:1; /* disable read ahead */ - u8 lbcss:1;/* logical block cache segment size */ - u8 fsw:1; /* force sequential write */ -#endif - u8 num_cache_segs; - - u8 cache_seg_size[2]; - u8 res3; - u8 non_cache_seg_size[3]; -}; - -/* - * SCSI control mode page - */ -struct scsi_mp_control_page_s{ -#ifdef __BIGENDIAN -u8 ps:1; -u8 reserved1:1; -u8 page_code:6; -#else -u8 page_code:6; -u8 reserved1:1; -u8 ps:1; -#endif - u8 page_len; -#ifdef __BIGENDIAN - u8 tst:3; /* task set type */ - u8 reserved3:3; - u8 gltsd:1; /* global logging target save disable */ - u8 rlec:1; /* report log exception condition */ - - u8 qalgo_mod:4; /* queue alogorithm modifier */ - u8 reserved4:1; - u8 qerr:2; /* queue error management */ - u8 dque:1; /* disable queuing */ - - u8 reserved5:1; - u8 rac:1; /* report a check */ - u8 reserved6:2; - u8 swp:1; /* software write protect */ - u8 raerp:1; /* ready AER permission */ - u8 uaaerp:1; /* unit attenstion AER permission */ - u8 eaerp:1; /* error AER permission */ - - u8 reserved7:5; - u8 autoload_mod:3; -#else - u8 rlec:1; /* report log exception condition */ - u8 gltsd:1; /* global logging target save disable */ - u8 reserved3:3; - u8 tst:3; /* task set type */ - - u8 dque:1; /* disable queuing */ - u8 qerr:2; /* queue error management */ - u8 reserved4:1; - u8 qalgo_mod:4; /* queue alogorithm modifier */ - - u8 eaerp:1; /* error AER permission */ - u8 uaaerp:1; /* unit attenstion AER permission */ - u8 raerp:1; /* ready AER permission */ - u8 swp:1; /* software write protect */ - u8 reserved6:2; - u8 rac:1; /* report a check */ - u8 reserved5:1; - - u8 autoload_mod:3; - u8 reserved7:5; -#endif - u8 rahp_msb; /* ready AER holdoff period - MSB */ - u8 rahp_lsb; /* ready AER holdoff period - LSB */ - - u8 busy_timeout_period_msb; - u8 busy_timeout_period_lsb; - - u8 ext_selftest_compl_time_msb; - u8 ext_selftest_compl_time_lsb; -}; - -/* - * SCSI medium types supported mode page - */ -struct scsi_mp_medium_types_sup_s{ -#ifdef __BIGENDIAN - u8 ps:1; - u8 reserved1:1; - u8 page_code:6; -#else - u8 page_code:6; - u8 reserved1:1; - u8 ps:1; -#endif - u8 page_len; - - u8 reserved3[2]; - u8 med_type1_sup; /* medium type one supported */ - u8 med_type2_sup; /* medium type two supported */ - u8 med_type3_sup; /* medium type three supported */ - u8 med_type4_sup; /* medium type four supported */ -}; - -/* - * SCSI informational exception control mode page - */ -struct scsi_mp_info_excpt_cntl_s{ -#ifdef __BIGENDIAN - u8 ps:1; - u8 reserved1:1; - u8 page_code:6; -#else - u8 page_code:6; - u8 reserved1:1; - u8 ps:1; -#endif - u8 page_len; -#ifdef __BIGENDIAN - u8 perf:1; /* performance */ - u8 reserved3:1; - u8 ebf:1; /* enable background fucntion */ - u8 ewasc:1; /* enable warning */ - u8 dexcpt:1; /* disable exception control */ - u8 test:1; /* enable test device failure - * notification - */ - u8 reserved4:1; - u8 log_error:1; - - u8 reserved5:4; - u8 mrie:4; /* method of reporting info - * exceptions - */ -#else - u8 log_error:1; - u8 reserved4:1; - u8 test:1; /* enable test device failure - * notification - */ - u8 dexcpt:1; /* disable exception control */ - u8 ewasc:1; /* enable warning */ - u8 ebf:1; /* enable background fucntion */ - u8 reserved3:1; - u8 perf:1; /* performance */ - - u8 mrie:4; /* method of reporting info - * exceptions - */ - u8 reserved5:4; -#endif - u8 interval_timer_msb; - u8 interval_timer_lsb; - - u8 report_count_msb; - u8 report_count_lsb; -}; - -/* - * Methods of reporting informational exceptions - */ -#define SCSI_MP_IEC_NO_REPORT 0x0 /* no reporting of exceptions */ -#define SCSI_MP_IEC_AER 0x1 /* async event reporting */ -#define SCSI_MP_IEC_UNIT_ATTN 0x2 /* generate unit attenstion */ -#define SCSI_MO_IEC_COND_REC_ERR 0x3 /* conditionally generate recovered - * error - */ -#define SCSI_MP_IEC_UNCOND_REC_ERR 0x4 /* unconditionally generate recovered - * error - */ -#define SCSI_MP_IEC_NO_SENSE 0x5 /* generate no sense */ -#define SCSI_MP_IEC_ON_REQUEST 0x6 /* only report exceptions on request */ - -/* - * SCSI flexible disk page - */ -struct scsi_mp_flexible_disk_s{ -#ifdef __BIGENDIAN - u8 ps:1; - u8 reserved1:1; - u8 page_code:6; -#else - u8 page_code:6; - u8 reserved1:1; - u8 ps:1; -#endif - u8 page_len; - - u8 transfer_rate_msb; - u8 transfer_rate_lsb; - - u8 num_heads; - u8 num_sectors; - - u8 bytes_per_sector_msb; - u8 bytes_per_sector_lsb; - - u8 num_cylinders_msb; - u8 num_cylinders_lsb; - - u8 sc_wpc_msb; /* starting cylinder-write - * precompensation msb - */ - u8 sc_wpc_lsb; /* starting cylinder-write - * precompensation lsb - */ - u8 sc_rwc_msb; /* starting cylinder-reduced write - * current msb - */ - u8 sc_rwc_lsb; /* starting cylinder-reduced write - * current lsb - */ - - u8 dev_step_rate_msb; - u8 dev_step_rate_lsb; - - u8 dev_step_pulse_width; - - u8 head_sd_msb; /* head settle delay msb */ - u8 head_sd_lsb; /* head settle delay lsb */ - - u8 motor_on_delay; - u8 motor_off_delay; -#ifdef __BIGENDIAN - u8 trdy:1; /* true ready bit */ - u8 ssn:1; /* start sector number bit */ - u8 mo:1; /* motor on bit */ - u8 reserved3:5; - - u8 reserved4:4; - u8 spc:4; /* step pulse per cylinder */ -#else - u8 reserved3:5; - u8 mo:1; /* motor on bit */ - u8 ssn:1; /* start sector number bit */ - u8 trdy:1; /* true ready bit */ - - u8 spc:4; /* step pulse per cylinder */ - u8 reserved4:4; -#endif - u8 write_comp; - u8 head_load_delay; - u8 head_unload_delay; -#ifdef __BIGENDIAN - u8 pin34:4; /* pin34 usage */ - u8 pin2:4; /* pin2 usage */ - - u8 pin4:4; /* pin4 usage */ - u8 pin1:4; /* pin1 usage */ -#else - u8 pin2:4; /* pin2 usage */ - u8 pin34:4; /* pin34 usage */ - - u8 pin1:4; /* pin1 usage */ - u8 pin4:4; /* pin4 usage */ -#endif - u8 med_rot_rate_msb; - u8 med_rot_rate_lsb; - - u8 reserved5[2]; -}; - -struct scsi_mode_page_format_data6_s{ - struct scsi_mode_param_header6_s mph; /* mode page header */ - struct scsi_mode_param_desc_s desc; /* block descriptor */ - struct scsi_mp_format_device_s format; /* format device data */ -}; - -struct scsi_mode_page_format_data10_s{ - struct scsi_mode_param_header10_s mph; /* mode page header */ - struct scsi_mode_param_desc_s desc; /* block descriptor */ - struct scsi_mp_format_device_s format; /* format device data */ -}; - -struct scsi_mode_page_rdg_data6_s{ - struct scsi_mode_param_header6_s mph; /* mode page header */ - struct scsi_mode_param_desc_s desc; /* block descriptor */ - struct scsi_mp_rigid_device_geometry_s rdg; - /* rigid geometry data */ -}; - -struct scsi_mode_page_rdg_data10_s{ - struct scsi_mode_param_header10_s mph; /* mode page header */ - struct scsi_mode_param_desc_s desc; /* block descriptor */ - struct scsi_mp_rigid_device_geometry_s rdg; - /* rigid geometry data */ -}; - -struct scsi_mode_page_cache6_s{ - struct scsi_mode_param_header6_s mph; /* mode page header */ - struct scsi_mode_param_desc_s desc; /* block descriptor */ - struct scsi_mp_caching_s cache; /* cache page data */ -}; - -struct scsi_mode_page_cache10_s{ - struct scsi_mode_param_header10_s mph; /* mode page header */ - struct scsi_mode_param_desc_s desc; /* block descriptor */ - struct scsi_mp_caching_s cache; /* cache page data */ -}; - -/* -------------------------------------------------------------- - * Format Unit command - * ------------------------------------------------------------ - */ - -/* - * Format Unit CDB - */ -struct scsi_format_unit_s{ - u8 opcode; -#ifdef __BIGENDIAN - u8 res1:3; - u8 fmtdata:1; /* if set, data out phase has format - * data - */ - u8 cmplst:1; /* if set, defect list is complete */ - u8 def_list:3; /* format of defect descriptor is - * fmtdata =1 - */ -#else - u8 def_list:3; /* format of defect descriptor is - * fmtdata = 1 - */ - u8 cmplst:1; /* if set, defect list is complete */ - u8 fmtdata:1; /* if set, data out phase has format - * data - */ - u8 res1:3; -#endif - u8 interleave_msb; - u8 interleave_lsb; - u8 vendor_spec; - u8 control; -}; - -/* - * h - */ -struct scsi_reserve6_s{ - u8 opcode; -#ifdef __BIGENDIAN - u8 reserved:3; - u8 obsolete:4; - u8 extent:1; -#else - u8 extent:1; - u8 obsolete:4; - u8 reserved:3; -#endif - u8 reservation_id; - u16 param_list_len; - u8 control; -}; - -/* - * h - */ -struct scsi_release6_s{ - u8 opcode; -#ifdef __BIGENDIAN - u8 reserved1:3; - u8 obsolete:4; - u8 extent:1; -#else - u8 extent:1; - u8 obsolete:4; - u8 reserved1:3; -#endif - u8 reservation_id; - u16 reserved2; - u8 control; -}; - -/* - * h - */ -struct scsi_reserve10_s{ - u8 opcode; -#ifdef __BIGENDIAN - u8 reserved1:3; - u8 third_party:1; - u8 reserved2:2; - u8 long_id:1; - u8 extent:1; -#else - u8 extent:1; - u8 long_id:1; - u8 reserved2:2; - u8 third_party:1; - u8 reserved1:3; -#endif - u8 reservation_id; - u8 third_pty_dev_id; - u8 reserved3; - u8 reserved4; - u8 reserved5; - u16 param_list_len; - u8 control; -}; - -struct scsi_release10_s{ - u8 opcode; -#ifdef __BIGENDIAN - u8 reserved1:3; - u8 third_party:1; - u8 reserved2:2; - u8 long_id:1; - u8 extent:1; -#else - u8 extent:1; - u8 long_id:1; - u8 reserved2:2; - u8 third_party:1; - u8 reserved1:3; -#endif - u8 reservation_id; - u8 third_pty_dev_id; - u8 reserved3; - u8 reserved4; - u8 reserved5; - u16 param_list_len; - u8 control; -}; - -struct scsi_verify10_s{ - u8 opcode; -#ifdef __BIGENDIAN - u8 lun:3; - u8 dpo:1; - u8 reserved:2; - u8 bytchk:1; - u8 reladdr:1; -#else - u8 reladdr:1; - u8 bytchk:1; - u8 reserved:2; - u8 dpo:1; - u8 lun:3; -#endif - u8 lba0; - u8 lba1; - u8 lba2; - u8 lba3; - u8 reserved1; - u8 verification_len0; - u8 verification_len1; - u8 control_byte; -}; - -struct scsi_request_sense_s{ - u8 opcode; -#ifdef __BIGENDIAN - u8 lun:3; - u8 reserved:5; -#else - u8 reserved:5; - u8 lun:3; -#endif - u8 reserved0; - u8 reserved1; - u8 alloc_len; - u8 control_byte; -}; - -/* ------------------------------------------------------------ - * SCSI status byte values - * ------------------------------------------------------------ - */ -#define SCSI_STATUS_GOOD 0x00 -#define SCSI_STATUS_CHECK_CONDITION 0x02 -#define SCSI_STATUS_CONDITION_MET 0x04 -#define SCSI_STATUS_BUSY 0x08 -#define SCSI_STATUS_INTERMEDIATE 0x10 -#define SCSI_STATUS_ICM 0x14 /* intermediate condition met */ -#define SCSI_STATUS_RESERVATION_CONFLICT 0x18 -#define SCSI_STATUS_COMMAND_TERMINATED 0x22 -#define SCSI_STATUS_QUEUE_FULL 0x28 -#define SCSI_STATUS_ACA_ACTIVE 0x30 - -#define SCSI_MAX_ALLOC_LEN 0xFF /* maximum allocarion length - * in CDBs - */ - -#define SCSI_OP_WRITE_VERIFY10 0x2E -#define SCSI_OP_WRITE_VERIFY12 0xAE -#define SCSI_OP_UNDEF 0xFF - -/* - * SCSI WRITE-VERIFY(10) command - */ -struct scsi_write_verify10_s{ - u8 opcode; -#ifdef __BIGENDIAN - u8 reserved1:3; - u8 dpo:1; /* Disable Page Out */ - u8 reserved2:1; - u8 ebp:1; /* erse by-pass */ - u8 bytchk:1; /* byte check */ - u8 rel_adr:1; /* relative address */ -#else - u8 rel_adr:1; /* relative address */ - u8 bytchk:1; /* byte check */ - u8 ebp:1; /* erse by-pass */ - u8 reserved2:1; - u8 dpo:1; /* Disable Page Out */ - u8 reserved1:3; -#endif - u8 lba0; /* logical block address - MSB */ - u8 lba1; - u8 lba2; - u8 lba3; /* LSB */ - u8 reserved3; - u8 xfer_length0; /* transfer length in blocks - MSB */ - u8 xfer_length1; /* LSB */ - u8 control; -}; - -#pragma pack() - -#endif /* __SCSI_H__ */ diff --git a/drivers/scsi/bfa/include/protocol/types.h b/drivers/scsi/bfa/include/protocol/types.h deleted file mode 100644 index 2875a6cced3b..000000000000 --- a/drivers/scsi/bfa/include/protocol/types.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/** - * types.h Protocol defined base types - */ - -#ifndef __TYPES_H__ -#define __TYPES_H__ - -#include <bfa_os_inc.h> - -#define wwn_t u64 -#define lun_t u64 - -#define WWN_NULL (0) -#define FC_SYMNAME_MAX 256 /* max name server symbolic name size */ -#define FC_ALPA_MAX 128 - -#pragma pack(1) - -#define MAC_ADDRLEN (6) -struct mac_s { u8 mac[MAC_ADDRLEN]; }; -#define mac_t struct mac_s - -#pragma pack() - -#endif diff --git a/drivers/scsi/bfa/loop.c b/drivers/scsi/bfa/loop.c deleted file mode 100644 index f6342efb6a90..000000000000 --- a/drivers/scsi/bfa/loop.c +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/** - * port_loop.c vport private loop implementation. - */ -#include <bfa.h> -#include <bfa_svc.h> -#include "fcs_lport.h" -#include "fcs_rport.h" -#include "fcs_trcmod.h" -#include "lport_priv.h" - -BFA_TRC_FILE(FCS, LOOP); - -/** - * ALPA to LIXA bitmap mapping - * - * ALPA 0x00 (Word 0, Bit 30) is invalid for N_Ports. Also Word 0 Bit 31 - * is for L_bit (login required) and is filled as ALPA 0x00 here. - */ -static const u8 port_loop_alpa_map[] = { - 0xEF, 0xE8, 0xE4, 0xE2, 0xE1, 0xE0, 0xDC, 0xDA, /* Word 3 Bits 0..7 */ - 0xD9, 0xD6, 0xD5, 0xD4, 0xD3, 0xD2, 0xD1, 0xCE, /* Word 3 Bits 8..15 */ - 0xCD, 0xCC, 0xCB, 0xCA, 0xC9, 0xC7, 0xC6, 0xC5, /* Word 3 Bits 16..23 */ - 0xC3, 0xBC, 0xBA, 0xB9, 0xB6, 0xB5, 0xB4, 0xB3, /* Word 3 Bits 24..31 */ - - 0xB2, 0xB1, 0xAE, 0xAD, 0xAC, 0xAB, 0xAA, 0xA9, /* Word 2 Bits 0..7 */ - 0xA7, 0xA6, 0xA5, 0xA3, 0x9F, 0x9E, 0x9D, 0x9B, /* Word 2 Bits 8..15 */ - 0x98, 0x97, 0x90, 0x8F, 0x88, 0x84, 0x82, 0x81, /* Word 2 Bits 16..23 */ - 0x80, 0x7C, 0x7A, 0x79, 0x76, 0x75, 0x74, 0x73, /* Word 2 Bits 24..31 */ - - 0x72, 0x71, 0x6E, 0x6D, 0x6C, 0x6B, 0x6A, 0x69, /* Word 1 Bits 0..7 */ - 0x67, 0x66, 0x65, 0x63, 0x5C, 0x5A, 0x59, 0x56, /* Word 1 Bits 8..15 */ - 0x55, 0x54, 0x53, 0x52, 0x51, 0x4E, 0x4D, 0x4C, /* Word 1 Bits 16..23 */ - 0x4B, 0x4A, 0x49, 0x47, 0x46, 0x45, 0x43, 0x3C, /* Word 1 Bits 24..31 */ - - 0x3A, 0x39, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, /* Word 0 Bits 0..7 */ - 0x2E, 0x2D, 0x2C, 0x2B, 0x2A, 0x29, 0x27, 0x26, /* Word 0 Bits 8..15 */ - 0x25, 0x23, 0x1F, 0x1E, 0x1D, 0x1B, 0x18, 0x17, /* Word 0 Bits 16..23 */ - 0x10, 0x0F, 0x08, 0x04, 0x02, 0x01, 0x00, 0x00, /* Word 0 Bits 24..31 */ -}; - -/* - * Local Functions - */ -static bfa_status_t bfa_fcs_port_loop_send_plogi(struct bfa_fcs_port_s *port, - u8 alpa); - -static void bfa_fcs_port_loop_plogi_response(void *fcsarg, - struct bfa_fcxp_s *fcxp, - void *cbarg, - bfa_status_t req_status, - u32 rsp_len, - u32 resid_len, - struct fchs_s *rsp_fchs); -/** - * Called by port to initializar in provate LOOP topology. - */ -void -bfa_fcs_port_loop_init(struct bfa_fcs_port_s *port) -{ -} - -/** - * Called by port to notify transition to online state. - */ -void -bfa_fcs_port_loop_online(struct bfa_fcs_port_s *port) -{ - - u8 num_alpa = port->port_topo.ploop.num_alpa; - u8 *alpa_pos_map = port->port_topo.ploop.alpa_pos_map; - struct bfa_fcs_rport_s *r_port; - int ii = 0; - - /* - * If the port role is Initiator Mode, create Rports. - */ - if (port->port_cfg.roles == BFA_PORT_ROLE_FCP_IM) { - /* - * Check if the ALPA positional bitmap is available. - * if not, we send PLOGI to all possible ALPAs. - */ - if (num_alpa > 0) { - for (ii = 0; ii < num_alpa; ii++) { - /* - * ignore ALPA of bfa port - */ - if (alpa_pos_map[ii] != port->pid) { - r_port = bfa_fcs_rport_create(port, - alpa_pos_map[ii]); - } - } - } else { - for (ii = 0; ii < MAX_ALPA_COUNT; ii++) { - /* - * ignore ALPA of bfa port - */ - if ((port_loop_alpa_map[ii] > 0) - && (port_loop_alpa_map[ii] != port->pid)) - bfa_fcs_port_loop_send_plogi(port, - port_loop_alpa_map[ii]); - /**TBD */ - } - } - } else { - /* - * TBD Target Mode ?? - */ - } - -} - -/** - * Called by port to notify transition to offline state. - */ -void -bfa_fcs_port_loop_offline(struct bfa_fcs_port_s *port) -{ - -} - -/** - * Called by port to notify a LIP on the loop. - */ -void -bfa_fcs_port_loop_lip(struct bfa_fcs_port_s *port) -{ -} - -/** - * Local Functions. - */ -static bfa_status_t -bfa_fcs_port_loop_send_plogi(struct bfa_fcs_port_s *port, u8 alpa) -{ - struct fchs_s fchs; - struct bfa_fcxp_s *fcxp = NULL; - int len; - - bfa_trc(port->fcs, alpa); - - fcxp = bfa_fcxp_alloc(NULL, port->fcs->bfa, 0, 0, NULL, NULL, NULL, - NULL); - bfa_assert(fcxp); - - len = fc_plogi_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), alpa, - bfa_fcs_port_get_fcid(port), 0, - port->port_cfg.pwwn, port->port_cfg.nwwn, - bfa_fcport_get_maxfrsize(port->fcs->bfa)); - - bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, - FC_CLASS_3, len, &fchs, - bfa_fcs_port_loop_plogi_response, (void *)port, - FC_MAX_PDUSZ, FC_RA_TOV); - - return BFA_STATUS_OK; -} - -/** - * Called by fcxp to notify the Plogi response - */ -static void -bfa_fcs_port_loop_plogi_response(void *fcsarg, struct bfa_fcxp_s *fcxp, - void *cbarg, bfa_status_t req_status, - u32 rsp_len, u32 resid_len, - struct fchs_s *rsp_fchs) -{ - struct bfa_fcs_port_s *port = (struct bfa_fcs_port_s *) cbarg; - struct fc_logi_s *plogi_resp; - struct fc_els_cmd_s *els_cmd; - - bfa_trc(port->fcs, req_status); - - /* - * Sanity Checks - */ - if (req_status != BFA_STATUS_OK) { - bfa_trc(port->fcs, req_status); - /* - * @todo - * This could mean that the device with this APLA does not - * exist on the loop. - */ - - return; - } - - els_cmd = (struct fc_els_cmd_s *) BFA_FCXP_RSP_PLD(fcxp); - plogi_resp = (struct fc_logi_s *) els_cmd; - - if (els_cmd->els_code == FC_ELS_ACC) { - bfa_fcs_rport_start(port, rsp_fchs, plogi_resp); - } else { - bfa_trc(port->fcs, plogi_resp->els_cmd.els_code); - bfa_assert(0); - } -} diff --git a/drivers/scsi/bfa/lport_api.c b/drivers/scsi/bfa/lport_api.c deleted file mode 100644 index 72b3f508d0e9..000000000000 --- a/drivers/scsi/bfa/lport_api.c +++ /dev/null @@ -1,303 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/** - * port_api.c BFA FCS port - */ - -#include <fcs/bfa_fcs.h> -#include <fcs/bfa_fcs_lport.h> -#include <fcs/bfa_fcs_rport.h> -#include "fcs_rport.h" -#include "fcs_fabric.h" -#include "fcs_trcmod.h" -#include "fcs_vport.h" - -BFA_TRC_FILE(FCS, PORT_API); - - - -/** - * fcs_port_api BFA FCS port API - */ - -void -bfa_fcs_cfg_base_port(struct bfa_fcs_s *fcs, struct bfa_port_cfg_s *port_cfg) -{ -} - -struct bfa_fcs_port_s * -bfa_fcs_get_base_port(struct bfa_fcs_s *fcs) -{ - return &fcs->fabric.bport; -} - -wwn_t -bfa_fcs_port_get_rport(struct bfa_fcs_port_s *port, wwn_t wwn, int index, - int nrports, bfa_boolean_t bwwn) -{ - struct list_head *qh, *qe; - struct bfa_fcs_rport_s *rport = NULL; - int i; - struct bfa_fcs_s *fcs; - - if (port == NULL || nrports == 0) - return (wwn_t) 0; - - fcs = port->fcs; - bfa_trc(fcs, (u32) nrports); - - i = 0; - qh = &port->rport_q; - qe = bfa_q_first(qh); - - while ((qe != qh) && (i < nrports)) { - rport = (struct bfa_fcs_rport_s *)qe; - if (bfa_os_ntoh3b(rport->pid) > 0xFFF000) { - qe = bfa_q_next(qe); - bfa_trc(fcs, (u32) rport->pwwn); - bfa_trc(fcs, rport->pid); - bfa_trc(fcs, i); - continue; - } - - if (bwwn) { - if (!memcmp(&wwn, &rport->pwwn, 8)) - break; - } else { - if (i == index) - break; - } - - i++; - qe = bfa_q_next(qe); - } - - bfa_trc(fcs, i); - if (rport) - return rport->pwwn; - else - return (wwn_t) 0; -} - -void -bfa_fcs_port_get_rports(struct bfa_fcs_port_s *port, wwn_t rport_wwns[], - int *nrports) -{ - struct list_head *qh, *qe; - struct bfa_fcs_rport_s *rport = NULL; - int i; - struct bfa_fcs_s *fcs; - - if (port == NULL || rport_wwns == NULL || *nrports == 0) - return; - - fcs = port->fcs; - bfa_trc(fcs, (u32) *nrports); - - i = 0; - qh = &port->rport_q; - qe = bfa_q_first(qh); - - while ((qe != qh) && (i < *nrports)) { - rport = (struct bfa_fcs_rport_s *)qe; - if (bfa_os_ntoh3b(rport->pid) > 0xFFF000) { - qe = bfa_q_next(qe); - bfa_trc(fcs, (u32) rport->pwwn); - bfa_trc(fcs, rport->pid); - bfa_trc(fcs, i); - continue; - } - - rport_wwns[i] = rport->pwwn; - - i++; - qe = bfa_q_next(qe); - } - - bfa_trc(fcs, i); - *nrports = i; - return; -} - -/* - * Iterate's through all the rport's in the given port to - * determine the maximum operating speed. - * - * To be used in TRL Functionality only - */ -enum bfa_pport_speed -bfa_fcs_port_get_rport_max_speed(struct bfa_fcs_port_s *port) -{ - struct list_head *qh, *qe; - struct bfa_fcs_rport_s *rport = NULL; - struct bfa_fcs_s *fcs; - enum bfa_pport_speed max_speed = 0; - struct bfa_pport_attr_s pport_attr; - enum bfa_pport_speed pport_speed, rport_speed; - bfa_boolean_t trl_enabled = bfa_fcport_is_ratelim(port->fcs->bfa); - - if (port == NULL) - return 0; - - fcs = port->fcs; - - /* - * Get Physical port's current speed - */ - bfa_fcport_get_attr(port->fcs->bfa, &pport_attr); - pport_speed = pport_attr.speed; - bfa_trc(fcs, pport_speed); - - qh = &port->rport_q; - qe = bfa_q_first(qh); - - while (qe != qh) { - rport = (struct bfa_fcs_rport_s *) qe; - if ((bfa_os_ntoh3b(rport->pid) > 0xFFF000) || - (bfa_fcs_rport_get_state(rport) == - BFA_RPORT_OFFLINE)) { - qe = bfa_q_next(qe); - continue; - } - - 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_speed > max_speed) { - max_speed = rport_speed; - } - - qe = bfa_q_next(qe); - } - - bfa_trc(fcs, max_speed); - return max_speed; -} - -struct bfa_fcs_port_s * -bfa_fcs_lookup_port(struct bfa_fcs_s *fcs, u16 vf_id, wwn_t lpwwn) -{ - struct bfa_fcs_vport_s *vport; - bfa_fcs_vf_t *vf; - - bfa_assert(fcs != NULL); - - vf = bfa_fcs_vf_lookup(fcs, vf_id); - if (vf == NULL) { - bfa_trc(fcs, vf_id); - return NULL; - } - - if (!lpwwn || (vf->bport.port_cfg.pwwn == lpwwn)) - return &vf->bport; - - vport = bfa_fcs_fabric_vport_lookup(vf, lpwwn); - if (vport) - return &vport->lport; - - return NULL; -} - -/* - * API corresponding to VmWare's NPIV_VPORT_GETINFO. - */ -void -bfa_fcs_port_get_info(struct bfa_fcs_port_s *port, - struct bfa_port_info_s *port_info) -{ - - bfa_trc(port->fcs, port->fabric->fabric_name); - - if (port->vport == NULL) { - /* - * This is a Physical port - */ - port_info->port_type = BFA_PORT_TYPE_PHYSICAL; - - /* - * @todo : need to fix the state & reason - */ - port_info->port_state = 0; - port_info->offline_reason = 0; - - port_info->port_wwn = bfa_fcs_port_get_pwwn(port); - port_info->node_wwn = bfa_fcs_port_get_nwwn(port); - - port_info->max_vports_supp = - bfa_lps_get_max_vport(port->fcs->bfa); - port_info->num_vports_inuse = - bfa_fcs_fabric_vport_count(port->fabric); - port_info->max_rports_supp = BFA_FCS_MAX_RPORTS_SUPP; - port_info->num_rports_inuse = port->num_rports; - } else { - /* - * This is a virtual port - */ - port_info->port_type = BFA_PORT_TYPE_VIRTUAL; - - /* - * @todo : need to fix the state & reason - */ - port_info->port_state = 0; - port_info->offline_reason = 0; - - port_info->port_wwn = bfa_fcs_port_get_pwwn(port); - port_info->node_wwn = bfa_fcs_port_get_nwwn(port); - } -} - -void -bfa_fcs_port_get_stats(struct bfa_fcs_port_s *fcs_port, - struct bfa_port_stats_s *port_stats) -{ - bfa_os_memcpy(port_stats, &fcs_port->stats, - sizeof(struct bfa_port_stats_s)); - return; -} - -void -bfa_fcs_port_clear_stats(struct bfa_fcs_port_s *fcs_port) -{ - bfa_os_memset(&fcs_port->stats, 0, sizeof(struct bfa_port_stats_s)); - return; -} - -void -bfa_fcs_port_enable_ipfc_roles(struct bfa_fcs_port_s *fcs_port) -{ - fcs_port->port_cfg.roles |= BFA_PORT_ROLE_FCP_IPFC; - return; -} - -void -bfa_fcs_port_disable_ipfc_roles(struct bfa_fcs_port_s *fcs_port) -{ - fcs_port->port_cfg.roles &= ~BFA_PORT_ROLE_FCP_IPFC; - return; -} - - diff --git a/drivers/scsi/bfa/lport_priv.h b/drivers/scsi/bfa/lport_priv.h deleted file mode 100644 index dbae370a599a..000000000000 --- a/drivers/scsi/bfa/lport_priv.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __VP_PRIV_H__ -#define __VP_PRIV_H__ - -#include <fcs/bfa_fcs_lport.h> -#include <fcs/bfa_fcs_vport.h> - -/* - * Functions exported by vps - */ -void bfa_fcs_vport_init(struct bfa_fcs_vport_s *vport); - -/* - * Functions exported by vps - */ -void bfa_fcs_vps_online(struct bfa_fcs_port_s *port); -void bfa_fcs_vps_offline(struct bfa_fcs_port_s *port); -void bfa_fcs_vps_lip(struct bfa_fcs_port_s *port); - -/* - * Functions exported by port_fab - */ -void bfa_fcs_port_fab_init(struct bfa_fcs_port_s *vport); -void bfa_fcs_port_fab_online(struct bfa_fcs_port_s *vport); -void bfa_fcs_port_fab_offline(struct bfa_fcs_port_s *vport); -void bfa_fcs_port_fab_rx_frame(struct bfa_fcs_port_s *port, - u8 *rx_frame, u32 len); - -/* - * Functions exported by VP-NS. - */ -void bfa_fcs_port_ns_init(struct bfa_fcs_port_s *vport); -void bfa_fcs_port_ns_offline(struct bfa_fcs_port_s *vport); -void bfa_fcs_port_ns_online(struct bfa_fcs_port_s *vport); -void bfa_fcs_port_ns_query(struct bfa_fcs_port_s *port); - -/* - * Functions exported by VP-SCN - */ -void bfa_fcs_port_scn_init(struct bfa_fcs_port_s *vport); -void bfa_fcs_port_scn_offline(struct bfa_fcs_port_s *vport); -void bfa_fcs_port_scn_online(struct bfa_fcs_port_s *vport); -void bfa_fcs_port_scn_process_rscn(struct bfa_fcs_port_s *port, - struct fchs_s *rx_frame, u32 len); - -/* - * Functions exported by VP-N2N - */ - -void bfa_fcs_port_n2n_init(struct bfa_fcs_port_s *port); -void bfa_fcs_port_n2n_online(struct bfa_fcs_port_s *port); -void bfa_fcs_port_n2n_offline(struct bfa_fcs_port_s *port); -void bfa_fcs_port_n2n_rx_frame(struct bfa_fcs_port_s *port, - u8 *rx_frame, u32 len); - -/* - * Functions exported by VP-LOOP - */ -void bfa_fcs_port_loop_init(struct bfa_fcs_port_s *port); -void bfa_fcs_port_loop_online(struct bfa_fcs_port_s *port); -void bfa_fcs_port_loop_offline(struct bfa_fcs_port_s *port); -void bfa_fcs_port_loop_lip(struct bfa_fcs_port_s *port); -void bfa_fcs_port_loop_rx_frame(struct bfa_fcs_port_s *port, - u8 *rx_frame, u32 len); - -#endif /* __VP_PRIV_H__ */ diff --git a/drivers/scsi/bfa/ms.c b/drivers/scsi/bfa/ms.c deleted file mode 100644 index 1d579ef26122..000000000000 --- a/drivers/scsi/bfa/ms.c +++ /dev/null @@ -1,759 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - - -#include <bfa.h> -#include <bfa_svc.h> -#include "fcs_lport.h" -#include "fcs_rport.h" -#include "fcs_trcmod.h" -#include "fcs_fcxp.h" -#include "lport_priv.h" - -BFA_TRC_FILE(FCS, MS); - -#define BFA_FCS_MS_CMD_MAX_RETRIES 2 -/* - * forward declarations - */ -static void bfa_fcs_port_ms_send_plogi(void *ms_cbarg, - struct bfa_fcxp_s *fcxp_alloced); -static void bfa_fcs_port_ms_timeout(void *arg); -static void bfa_fcs_port_ms_plogi_response(void *fcsarg, - struct bfa_fcxp_s *fcxp, - void *cbarg, - bfa_status_t req_status, - u32 rsp_len, - u32 resid_len, - struct fchs_s *rsp_fchs); - -static void bfa_fcs_port_ms_send_gmal(void *ms_cbarg, - struct bfa_fcxp_s *fcxp_alloced); -static void bfa_fcs_port_ms_gmal_response(void *fcsarg, - struct bfa_fcxp_s *fcxp, - void *cbarg, - bfa_status_t req_status, - u32 rsp_len, - u32 resid_len, - struct fchs_s *rsp_fchs); -static void bfa_fcs_port_ms_send_gfn(void *ms_cbarg, - struct bfa_fcxp_s *fcxp_alloced); -static void bfa_fcs_port_ms_gfn_response(void *fcsarg, - struct bfa_fcxp_s *fcxp, - void *cbarg, - bfa_status_t req_status, - u32 rsp_len, - u32 resid_len, - struct fchs_s *rsp_fchs); -/** - * fcs_ms_sm FCS MS state machine - */ - -/** - * MS State Machine events - */ -enum port_ms_event { - MSSM_EVENT_PORT_ONLINE = 1, - MSSM_EVENT_PORT_OFFLINE = 2, - MSSM_EVENT_RSP_OK = 3, - MSSM_EVENT_RSP_ERROR = 4, - MSSM_EVENT_TIMEOUT = 5, - MSSM_EVENT_FCXP_SENT = 6, - MSSM_EVENT_PORT_FABRIC_RSCN = 7 -}; - -static void bfa_fcs_port_ms_sm_offline(struct bfa_fcs_port_ms_s *ms, - enum port_ms_event event); -static void bfa_fcs_port_ms_sm_plogi_sending(struct bfa_fcs_port_ms_s *ms, - enum port_ms_event event); -static void bfa_fcs_port_ms_sm_plogi(struct bfa_fcs_port_ms_s *ms, - enum port_ms_event event); -static void bfa_fcs_port_ms_sm_plogi_retry(struct bfa_fcs_port_ms_s *ms, - enum port_ms_event event); -static void bfa_fcs_port_ms_sm_gmal_sending(struct bfa_fcs_port_ms_s *ms, - enum port_ms_event event); -static void bfa_fcs_port_ms_sm_gmal(struct bfa_fcs_port_ms_s *ms, - enum port_ms_event event); -static void bfa_fcs_port_ms_sm_gmal_retry(struct bfa_fcs_port_ms_s *ms, - enum port_ms_event event); -static void bfa_fcs_port_ms_sm_gfn_sending(struct bfa_fcs_port_ms_s *ms, - enum port_ms_event event); -static void bfa_fcs_port_ms_sm_gfn(struct bfa_fcs_port_ms_s *ms, - enum port_ms_event event); -static void bfa_fcs_port_ms_sm_gfn_retry(struct bfa_fcs_port_ms_s *ms, - enum port_ms_event event); -static void bfa_fcs_port_ms_sm_online(struct bfa_fcs_port_ms_s *ms, - enum port_ms_event event); -/** - * Start in offline state - awaiting NS to send start. - */ -static void -bfa_fcs_port_ms_sm_offline(struct bfa_fcs_port_ms_s *ms, - enum port_ms_event event) -{ - bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn); - bfa_trc(ms->port->fcs, event); - - switch (event) { - case MSSM_EVENT_PORT_ONLINE: - bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_plogi_sending); - bfa_fcs_port_ms_send_plogi(ms, NULL); - break; - - case MSSM_EVENT_PORT_OFFLINE: - break; - - default: - bfa_sm_fault(ms->port->fcs, event); - } -} - -static void -bfa_fcs_port_ms_sm_plogi_sending(struct bfa_fcs_port_ms_s *ms, - enum port_ms_event event) -{ - bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn); - bfa_trc(ms->port->fcs, event); - - switch (event) { - case MSSM_EVENT_FCXP_SENT: - bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_plogi); - break; - - case MSSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline); - bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ms->port), - &ms->fcxp_wqe); - break; - - default: - bfa_sm_fault(ms->port->fcs, event); - } -} - -static void -bfa_fcs_port_ms_sm_plogi(struct bfa_fcs_port_ms_s *ms, enum port_ms_event event) -{ - bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn); - bfa_trc(ms->port->fcs, event); - - switch (event) { - case MSSM_EVENT_RSP_ERROR: - /* - * Start timer for a delayed retry - */ - bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_plogi_retry); - 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); - break; - - case MSSM_EVENT_RSP_OK: - /* - * since plogi is done, now invoke MS related sub-modules - */ - bfa_fcs_port_fdmi_online(ms); - - /** - * if this is a Vport, go to online state. - */ - if (ms->port->vport) { - bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_online); - break; - } - - /* - * For a base port we need to get the - * switch's IP address. - */ - bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_gmal_sending); - bfa_fcs_port_ms_send_gmal(ms, NULL); - break; - - case MSSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline); - bfa_fcxp_discard(ms->fcxp); - break; - - default: - bfa_sm_fault(ms->port->fcs, event); - } -} - -static void -bfa_fcs_port_ms_sm_plogi_retry(struct bfa_fcs_port_ms_s *ms, - enum port_ms_event event) -{ - bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn); - bfa_trc(ms->port->fcs, event); - - switch (event) { - case MSSM_EVENT_TIMEOUT: - /* - * Retry Timer Expired. Re-send - */ - bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_plogi_sending); - bfa_fcs_port_ms_send_plogi(ms, NULL); - break; - - case MSSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline); - bfa_timer_stop(&ms->timer); - break; - - default: - bfa_sm_fault(ms->port->fcs, event); - } -} - -static void -bfa_fcs_port_ms_sm_online(struct bfa_fcs_port_ms_s *ms, - enum port_ms_event event) -{ - bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn); - bfa_trc(ms->port->fcs, event); - - switch (event) { - case MSSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline); - break; - - case MSSM_EVENT_PORT_FABRIC_RSCN: - bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_gfn_sending); - ms->retry_cnt = 0; - bfa_fcs_port_ms_send_gfn(ms, NULL); - break; - - default: - bfa_sm_fault(ms->port->fcs, event); - } -} - -static void -bfa_fcs_port_ms_sm_gmal_sending(struct bfa_fcs_port_ms_s *ms, - enum port_ms_event event) -{ - bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn); - bfa_trc(ms->port->fcs, event); - - switch (event) { - case MSSM_EVENT_FCXP_SENT: - bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_gmal); - break; - - case MSSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline); - bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ms->port), - &ms->fcxp_wqe); - break; - - default: - bfa_sm_fault(ms->port->fcs, event); - } -} - -static void -bfa_fcs_port_ms_sm_gmal(struct bfa_fcs_port_ms_s *ms, enum port_ms_event event) -{ - bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn); - bfa_trc(ms->port->fcs, event); - - switch (event) { - case MSSM_EVENT_RSP_ERROR: - /* - * Start timer for a delayed retry - */ - if (ms->retry_cnt++ < BFA_FCS_MS_CMD_MAX_RETRIES) { - bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_gmal_retry); - 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); - } else { - bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_gfn_sending); - bfa_fcs_port_ms_send_gfn(ms, NULL); - ms->retry_cnt = 0; - } - break; - - case MSSM_EVENT_RSP_OK: - bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_gfn_sending); - bfa_fcs_port_ms_send_gfn(ms, NULL); - break; - - case MSSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline); - bfa_fcxp_discard(ms->fcxp); - break; - - default: - bfa_sm_fault(ms->port->fcs, event); - } -} - -static void -bfa_fcs_port_ms_sm_gmal_retry(struct bfa_fcs_port_ms_s *ms, - enum port_ms_event event) -{ - bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn); - bfa_trc(ms->port->fcs, event); - - switch (event) { - case MSSM_EVENT_TIMEOUT: - /* - * Retry Timer Expired. Re-send - */ - bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_gmal_sending); - bfa_fcs_port_ms_send_gmal(ms, NULL); - break; - - case MSSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline); - bfa_timer_stop(&ms->timer); - break; - - default: - bfa_sm_fault(ms->port->fcs, event); - } -} - -/** - * ms_pvt MS local functions - */ - -static void -bfa_fcs_port_ms_send_gmal(void *ms_cbarg, struct bfa_fcxp_s *fcxp_alloced) -{ - struct bfa_fcs_port_ms_s *ms = ms_cbarg; - struct bfa_fcs_port_s *port = ms->port; - struct fchs_s fchs; - int len; - struct bfa_fcxp_s *fcxp; - - bfa_trc(port->fcs, port->pid); - - fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); - if (!fcxp) { - bfa_fcxp_alloc_wait(port->fcs->bfa, &ms->fcxp_wqe, - bfa_fcs_port_ms_send_gmal, ms); - return; - } - ms->fcxp = fcxp; - - len = fc_gmal_req_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), - bfa_fcs_port_get_fcid(port), - bfa_lps_get_peer_nwwn(port->fabric->lps)); - - bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, - FC_CLASS_3, len, &fchs, bfa_fcs_port_ms_gmal_response, - (void *)ms, FC_MAX_PDUSZ, FC_FCCT_TOV); - - bfa_sm_send_event(ms, MSSM_EVENT_FCXP_SENT); -} - -static void -bfa_fcs_port_ms_gmal_response(void *fcsarg, struct bfa_fcxp_s *fcxp, - void *cbarg, bfa_status_t req_status, - u32 rsp_len, u32 resid_len, - struct fchs_s *rsp_fchs) -{ - struct bfa_fcs_port_ms_s *ms = (struct bfa_fcs_port_ms_s *)cbarg; - struct bfa_fcs_port_s *port = ms->port; - struct ct_hdr_s *cthdr = NULL; - struct fcgs_gmal_resp_s *gmal_resp; - struct fc_gmal_entry_s *gmal_entry; - u32 num_entries; - u8 *rsp_str; - - bfa_trc(port->fcs, req_status); - bfa_trc(port->fcs, port->port_cfg.pwwn); - - /* - * Sanity Checks - */ - if (req_status != BFA_STATUS_OK) { - bfa_trc(port->fcs, req_status); - bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR); - return; - } - - cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp); - cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code); - - if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) { - gmal_resp = (struct fcgs_gmal_resp_s *)(cthdr + 1); - num_entries = bfa_os_ntohl(gmal_resp->ms_len); - if (num_entries == 0) { - bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR); - return; - } - /* - * The response could contain multiple Entries. - * Entries for SNMP interface, etc. - * We look for the entry with a telnet prefix. - * First "http://" entry refers to IP addr - */ - - gmal_entry = (struct fc_gmal_entry_s *)gmal_resp->ms_ma; - while (num_entries > 0) { - if (strncmp - (gmal_entry->prefix, CT_GMAL_RESP_PREFIX_HTTP, - sizeof(gmal_entry->prefix)) == 0) { - - /* - * if the IP address is terminating with a '/', - * remove it. *Byte 0 consists of the length - * of the string. - */ - rsp_str = &(gmal_entry->prefix[0]); - if (rsp_str[gmal_entry->len - 1] == '/') - rsp_str[gmal_entry->len - 1] = 0; - /* - * copy IP Address to fabric - */ - strncpy(bfa_fcs_port_get_fabric_ipaddr(port), - gmal_entry->ip_addr, - BFA_FCS_FABRIC_IPADDR_SZ); - break; - } else { - --num_entries; - ++gmal_entry; - } - } - - bfa_sm_send_event(ms, MSSM_EVENT_RSP_OK); - return; - } - - bfa_trc(port->fcs, cthdr->reason_code); - bfa_trc(port->fcs, cthdr->exp_code); - bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR); -} - -static void -bfa_fcs_port_ms_sm_gfn_sending(struct bfa_fcs_port_ms_s *ms, - enum port_ms_event event) -{ - bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn); - bfa_trc(ms->port->fcs, event); - - switch (event) { - case MSSM_EVENT_FCXP_SENT: - bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_gfn); - break; - - case MSSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline); - bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ms->port), - &ms->fcxp_wqe); - break; - - default: - bfa_sm_fault(ms->port->fcs, event); - } -} - -static void -bfa_fcs_port_ms_sm_gfn(struct bfa_fcs_port_ms_s *ms, enum port_ms_event event) -{ - bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn); - bfa_trc(ms->port->fcs, event); - - switch (event) { - case MSSM_EVENT_RSP_ERROR: - /* - * Start timer for a delayed retry - */ - if (ms->retry_cnt++ < BFA_FCS_MS_CMD_MAX_RETRIES) { - bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_gfn_retry); - 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); - } else { - bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_online); - ms->retry_cnt = 0; - } - break; - - case MSSM_EVENT_RSP_OK: - bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_online); - break; - - case MSSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline); - bfa_fcxp_discard(ms->fcxp); - break; - - default: - bfa_sm_fault(ms->port->fcs, event); - } -} - -static void -bfa_fcs_port_ms_sm_gfn_retry(struct bfa_fcs_port_ms_s *ms, - enum port_ms_event event) -{ - bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn); - bfa_trc(ms->port->fcs, event); - - switch (event) { - case MSSM_EVENT_TIMEOUT: - /* - * Retry Timer Expired. Re-send - */ - bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_gfn_sending); - bfa_fcs_port_ms_send_gfn(ms, NULL); - break; - - case MSSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline); - bfa_timer_stop(&ms->timer); - break; - - default: - bfa_sm_fault(ms->port->fcs, event); - } -} - -/** - * ms_pvt MS local functions - */ - -static void -bfa_fcs_port_ms_send_gfn(void *ms_cbarg, struct bfa_fcxp_s *fcxp_alloced) -{ - struct bfa_fcs_port_ms_s *ms = ms_cbarg; - struct bfa_fcs_port_s *port = ms->port; - struct fchs_s fchs; - int len; - struct bfa_fcxp_s *fcxp; - - bfa_trc(port->fcs, port->pid); - - fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); - if (!fcxp) { - bfa_fcxp_alloc_wait(port->fcs->bfa, &ms->fcxp_wqe, - bfa_fcs_port_ms_send_gfn, ms); - return; - } - ms->fcxp = fcxp; - - len = fc_gfn_req_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), - bfa_fcs_port_get_fcid(port), - bfa_lps_get_peer_nwwn(port->fabric->lps)); - - bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, - FC_CLASS_3, len, &fchs, bfa_fcs_port_ms_gfn_response, - (void *)ms, FC_MAX_PDUSZ, FC_FCCT_TOV); - - bfa_sm_send_event(ms, MSSM_EVENT_FCXP_SENT); -} - -static void -bfa_fcs_port_ms_gfn_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg, - bfa_status_t req_status, u32 rsp_len, - u32 resid_len, struct fchs_s *rsp_fchs) -{ - struct bfa_fcs_port_ms_s *ms = (struct bfa_fcs_port_ms_s *)cbarg; - struct bfa_fcs_port_s *port = ms->port; - struct ct_hdr_s *cthdr = NULL; - wwn_t *gfn_resp; - - bfa_trc(port->fcs, req_status); - bfa_trc(port->fcs, port->port_cfg.pwwn); - - /* - * Sanity Checks - */ - if (req_status != BFA_STATUS_OK) { - bfa_trc(port->fcs, req_status); - bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR); - return; - } - - cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp); - cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code); - - if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) { - gfn_resp = (wwn_t *) (cthdr + 1); - /* - * check if it has actually changed - */ - if ((memcmp - ((void *)&bfa_fcs_port_get_fabric_name(port), gfn_resp, - sizeof(wwn_t)) != 0)) - bfa_fcs_fabric_set_fabric_name(port->fabric, *gfn_resp); - bfa_sm_send_event(ms, MSSM_EVENT_RSP_OK); - return; - } - - bfa_trc(port->fcs, cthdr->reason_code); - bfa_trc(port->fcs, cthdr->exp_code); - bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR); -} - -/** - * ms_pvt MS local functions - */ - -static void -bfa_fcs_port_ms_send_plogi(void *ms_cbarg, struct bfa_fcxp_s *fcxp_alloced) -{ - struct bfa_fcs_port_ms_s *ms = ms_cbarg; - struct bfa_fcs_port_s *port = ms->port; - struct fchs_s fchs; - int len; - struct bfa_fcxp_s *fcxp; - - bfa_trc(port->fcs, port->pid); - - fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); - if (!fcxp) { - port->stats.ms_plogi_alloc_wait++; - bfa_fcxp_alloc_wait(port->fcs->bfa, &ms->fcxp_wqe, - bfa_fcs_port_ms_send_plogi, ms); - return; - } - ms->fcxp = fcxp; - - len = fc_plogi_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), - bfa_os_hton3b(FC_MGMT_SERVER), - bfa_fcs_port_get_fcid(port), 0, - port->port_cfg.pwwn, port->port_cfg.nwwn, - bfa_fcport_get_maxfrsize(port->fcs->bfa)); - - bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, - FC_CLASS_3, len, &fchs, bfa_fcs_port_ms_plogi_response, - (void *)ms, FC_MAX_PDUSZ, FC_ELS_TOV); - - port->stats.ms_plogi_sent++; - bfa_sm_send_event(ms, MSSM_EVENT_FCXP_SENT); -} - -static void -bfa_fcs_port_ms_plogi_response(void *fcsarg, struct bfa_fcxp_s *fcxp, - void *cbarg, bfa_status_t req_status, - u32 rsp_len, u32 resid_len, - struct fchs_s *rsp_fchs) -{ - struct bfa_fcs_port_ms_s *ms = (struct bfa_fcs_port_ms_s *)cbarg; - - struct bfa_fcs_port_s *port = ms->port; - struct fc_els_cmd_s *els_cmd; - struct fc_ls_rjt_s *ls_rjt; - - bfa_trc(port->fcs, req_status); - bfa_trc(port->fcs, port->port_cfg.pwwn); - - /* - * Sanity Checks - */ - if (req_status != BFA_STATUS_OK) { - port->stats.ms_plogi_rsp_err++; - bfa_trc(port->fcs, req_status); - bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR); - return; - } - - els_cmd = (struct fc_els_cmd_s *) BFA_FCXP_RSP_PLD(fcxp); - - switch (els_cmd->els_code) { - - case FC_ELS_ACC: - if (rsp_len < sizeof(struct fc_logi_s)) { - bfa_trc(port->fcs, rsp_len); - port->stats.ms_plogi_acc_err++; - bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR); - break; - } - port->stats.ms_plogi_accepts++; - bfa_sm_send_event(ms, MSSM_EVENT_RSP_OK); - break; - - case FC_ELS_LS_RJT: - ls_rjt = (struct fc_ls_rjt_s *) BFA_FCXP_RSP_PLD(fcxp); - - bfa_trc(port->fcs, ls_rjt->reason_code); - bfa_trc(port->fcs, ls_rjt->reason_code_expl); - - port->stats.ms_rejects++; - bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR); - break; - - default: - port->stats.ms_plogi_unknown_rsp++; - bfa_trc(port->fcs, els_cmd->els_code); - bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR); - } -} - -static void -bfa_fcs_port_ms_timeout(void *arg) -{ - struct bfa_fcs_port_ms_s *ms = (struct bfa_fcs_port_ms_s *)arg; - - ms->port->stats.ms_timeouts++; - bfa_sm_send_event(ms, MSSM_EVENT_TIMEOUT); -} - - -void -bfa_fcs_port_ms_init(struct bfa_fcs_port_s *port) -{ - struct bfa_fcs_port_ms_s *ms = BFA_FCS_GET_MS_FROM_PORT(port); - - ms->port = port; - bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline); - - /* - * Invoke init routines of sub modules. - */ - bfa_fcs_port_fdmi_init(ms); -} - -void -bfa_fcs_port_ms_offline(struct bfa_fcs_port_s *port) -{ - struct bfa_fcs_port_ms_s *ms = BFA_FCS_GET_MS_FROM_PORT(port); - - ms->port = port; - bfa_sm_send_event(ms, MSSM_EVENT_PORT_OFFLINE); - bfa_fcs_port_fdmi_offline(ms); -} - -void -bfa_fcs_port_ms_online(struct bfa_fcs_port_s *port) -{ - struct bfa_fcs_port_ms_s *ms = BFA_FCS_GET_MS_FROM_PORT(port); - - ms->port = port; - bfa_sm_send_event(ms, MSSM_EVENT_PORT_ONLINE); -} - -void -bfa_fcs_port_ms_fabric_rscn(struct bfa_fcs_port_s *port) -{ - struct bfa_fcs_port_ms_s *ms = BFA_FCS_GET_MS_FROM_PORT(port); - - /* - * @todo. Handle this only when in Online state - */ - if (bfa_sm_cmp_state(ms, bfa_fcs_port_ms_sm_online)) - bfa_sm_send_event(ms, MSSM_EVENT_PORT_FABRIC_RSCN); -} diff --git a/drivers/scsi/bfa/n2n.c b/drivers/scsi/bfa/n2n.c deleted file mode 100644 index 735456824346..000000000000 --- a/drivers/scsi/bfa/n2n.c +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/** - * n2n.c n2n implementation. - */ -#include <bfa.h> -#include <bfa_svc.h> -#include "fcs_lport.h" -#include "fcs_rport.h" -#include "fcs_trcmod.h" -#include "lport_priv.h" - -BFA_TRC_FILE(FCS, N2N); - -/** - * Called by fcs/port to initialize N2N topology. - */ -void -bfa_fcs_port_n2n_init(struct bfa_fcs_port_s *port) -{ -} - -/** - * Called by fcs/port to notify transition to online state. - */ -void -bfa_fcs_port_n2n_online(struct bfa_fcs_port_s *port) -{ - struct bfa_fcs_port_n2n_s *n2n_port = &port->port_topo.pn2n; - struct bfa_port_cfg_s *pcfg = &port->port_cfg; - struct bfa_fcs_rport_s *rport; - - bfa_trc(port->fcs, pcfg->pwwn); - - /* - * If our PWWN is > than that of the r-port, we have to initiate PLOGI - * and assign an Address. if not, we need to wait for its PLOGI. - * - * If our PWWN is < than that of the remote port, it will send a PLOGI - * with the PIDs assigned. The rport state machine take care of this - * incoming PLOGI. - */ - if (memcmp - ((void *)&pcfg->pwwn, (void *)&n2n_port->rem_port_wwn, - sizeof(wwn_t)) > 0) { - port->pid = N2N_LOCAL_PID; - /** - * First, check if we know the device by pwwn. - */ - rport = bfa_fcs_port_get_rport_by_pwwn(port, - n2n_port->rem_port_wwn); - if (rport) { - bfa_trc(port->fcs, rport->pid); - bfa_trc(port->fcs, rport->pwwn); - rport->pid = N2N_REMOTE_PID; - bfa_fcs_rport_online(rport); - return; - } - - /* - * In n2n there can be only one rport. Delete the old one whose - * pid should be zero, because it is offline. - */ - if (port->num_rports > 0) { - rport = bfa_fcs_port_get_rport_by_pid(port, 0); - bfa_assert(rport != NULL); - if (rport) { - bfa_trc(port->fcs, rport->pwwn); - bfa_fcs_rport_delete(rport); - } - } - bfa_fcs_rport_create(port, N2N_REMOTE_PID); - } -} - -/** - * Called by fcs/port to notify transition to offline state. - */ -void -bfa_fcs_port_n2n_offline(struct bfa_fcs_port_s *port) -{ - struct bfa_fcs_port_n2n_s *n2n_port = &port->port_topo.pn2n; - - bfa_trc(port->fcs, port->pid); - port->pid = 0; - n2n_port->rem_port_wwn = 0; - n2n_port->reply_oxid = 0; -} - - diff --git a/drivers/scsi/bfa/ns.c b/drivers/scsi/bfa/ns.c deleted file mode 100644 index ae0edcc86ed5..000000000000 --- a/drivers/scsi/bfa/ns.c +++ /dev/null @@ -1,1242 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/** - * @page ns_sm_info VPORT NS State Machine - * - * @section ns_sm_interactions VPORT NS State Machine Interactions - * - * @section ns_sm VPORT NS State Machine - * img ns_sm.jpg - */ -#include <bfa.h> -#include <bfa_svc.h> -#include <bfa_iocfc.h> -#include "fcs_lport.h" -#include "fcs_rport.h" -#include "fcs_trcmod.h" -#include "fcs_fcxp.h" -#include "fcs.h" -#include "lport_priv.h" - -BFA_TRC_FILE(FCS, NS); - -/* - * forward declarations - */ -static void bfa_fcs_port_ns_send_plogi(void *ns_cbarg, - struct bfa_fcxp_s *fcxp_alloced); -static void bfa_fcs_port_ns_send_rspn_id(void *ns_cbarg, - struct bfa_fcxp_s *fcxp_alloced); -static void bfa_fcs_port_ns_send_rft_id(void *ns_cbarg, - struct bfa_fcxp_s *fcxp_alloced); -static void bfa_fcs_port_ns_send_rff_id(void *ns_cbarg, - struct bfa_fcxp_s *fcxp_alloced); -static void bfa_fcs_port_ns_send_gid_ft(void *ns_cbarg, - struct bfa_fcxp_s *fcxp_alloced); -static void bfa_fcs_port_ns_timeout(void *arg); -static void bfa_fcs_port_ns_plogi_response(void *fcsarg, - struct bfa_fcxp_s *fcxp, - void *cbarg, - bfa_status_t req_status, - u32 rsp_len, - u32 resid_len, - struct fchs_s *rsp_fchs); -static void bfa_fcs_port_ns_rspn_id_response(void *fcsarg, - struct bfa_fcxp_s *fcxp, - void *cbarg, - bfa_status_t req_status, - u32 rsp_len, - u32 resid_len, - struct fchs_s *rsp_fchs); -static void bfa_fcs_port_ns_rft_id_response(void *fcsarg, - struct bfa_fcxp_s *fcxp, - void *cbarg, - bfa_status_t req_status, - u32 rsp_len, - u32 resid_len, - struct fchs_s *rsp_fchs); -static void bfa_fcs_port_ns_rff_id_response(void *fcsarg, - struct bfa_fcxp_s *fcxp, - void *cbarg, - bfa_status_t req_status, - u32 rsp_len, - u32 resid_len, - struct fchs_s *rsp_fchs); -static void bfa_fcs_port_ns_gid_ft_response(void *fcsarg, - struct bfa_fcxp_s *fcxp, - void *cbarg, - bfa_status_t req_status, - u32 rsp_len, - u32 resid_len, - struct fchs_s *rsp_fchs); -static void bfa_fcs_port_ns_process_gidft_pids(struct bfa_fcs_port_s *port, - u32 *pid_buf, - u32 n_pids); - -static void bfa_fcs_port_ns_boot_target_disc(struct bfa_fcs_port_s *port); -/** - * fcs_ns_sm FCS nameserver interface state machine - */ - -/** - * VPort NS State Machine events - */ -enum vport_ns_event { - NSSM_EVENT_PORT_ONLINE = 1, - NSSM_EVENT_PORT_OFFLINE = 2, - NSSM_EVENT_PLOGI_SENT = 3, - NSSM_EVENT_RSP_OK = 4, - NSSM_EVENT_RSP_ERROR = 5, - NSSM_EVENT_TIMEOUT = 6, - NSSM_EVENT_NS_QUERY = 7, - NSSM_EVENT_RSPNID_SENT = 8, - NSSM_EVENT_RFTID_SENT = 9, - NSSM_EVENT_RFFID_SENT = 10, - NSSM_EVENT_GIDFT_SENT = 11, -}; - -static void bfa_fcs_port_ns_sm_offline(struct bfa_fcs_port_ns_s *ns, - enum vport_ns_event event); -static void bfa_fcs_port_ns_sm_plogi_sending(struct bfa_fcs_port_ns_s *ns, - enum vport_ns_event event); -static void bfa_fcs_port_ns_sm_plogi(struct bfa_fcs_port_ns_s *ns, - enum vport_ns_event event); -static void bfa_fcs_port_ns_sm_plogi_retry(struct bfa_fcs_port_ns_s *ns, - enum vport_ns_event event); -static void bfa_fcs_port_ns_sm_sending_rspn_id(struct bfa_fcs_port_ns_s *ns, - enum vport_ns_event event); -static void bfa_fcs_port_ns_sm_rspn_id(struct bfa_fcs_port_ns_s *ns, - enum vport_ns_event event); -static void bfa_fcs_port_ns_sm_rspn_id_retry(struct bfa_fcs_port_ns_s *ns, - enum vport_ns_event event); -static void bfa_fcs_port_ns_sm_sending_rft_id(struct bfa_fcs_port_ns_s *ns, - enum vport_ns_event event); -static void bfa_fcs_port_ns_sm_rft_id_retry(struct bfa_fcs_port_ns_s *ns, - enum vport_ns_event event); -static void bfa_fcs_port_ns_sm_rft_id(struct bfa_fcs_port_ns_s *ns, - enum vport_ns_event event); -static void bfa_fcs_port_ns_sm_sending_rff_id(struct bfa_fcs_port_ns_s *ns, - enum vport_ns_event event); -static void bfa_fcs_port_ns_sm_rff_id_retry(struct bfa_fcs_port_ns_s *ns, - enum vport_ns_event event); -static void bfa_fcs_port_ns_sm_rff_id(struct bfa_fcs_port_ns_s *ns, - enum vport_ns_event event); -static void bfa_fcs_port_ns_sm_sending_gid_ft(struct bfa_fcs_port_ns_s *ns, - enum vport_ns_event event); -static void bfa_fcs_port_ns_sm_gid_ft(struct bfa_fcs_port_ns_s *ns, - enum vport_ns_event event); -static void bfa_fcs_port_ns_sm_gid_ft_retry(struct bfa_fcs_port_ns_s *ns, - enum vport_ns_event event); -static void bfa_fcs_port_ns_sm_online(struct bfa_fcs_port_ns_s *ns, - enum vport_ns_event event); -/** - * Start in offline state - awaiting linkup - */ -static void -bfa_fcs_port_ns_sm_offline(struct bfa_fcs_port_ns_s *ns, - enum vport_ns_event event) -{ - bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); - bfa_trc(ns->port->fcs, event); - - switch (event) { - case NSSM_EVENT_PORT_ONLINE: - bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_plogi_sending); - bfa_fcs_port_ns_send_plogi(ns, NULL); - break; - - case NSSM_EVENT_PORT_OFFLINE: - break; - - default: - bfa_sm_fault(ns->port->fcs, event); - } -} - -static void -bfa_fcs_port_ns_sm_plogi_sending(struct bfa_fcs_port_ns_s *ns, - enum vport_ns_event event) -{ - bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); - bfa_trc(ns->port->fcs, event); - - switch (event) { - case NSSM_EVENT_PLOGI_SENT: - bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_plogi); - break; - - case NSSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline); - bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ns->port), - &ns->fcxp_wqe); - break; - - default: - bfa_sm_fault(ns->port->fcs, event); - } -} - -static void -bfa_fcs_port_ns_sm_plogi(struct bfa_fcs_port_ns_s *ns, - enum vport_ns_event event) -{ - bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); - bfa_trc(ns->port->fcs, event); - - switch (event) { - case NSSM_EVENT_RSP_ERROR: - /* - * Start timer for a delayed retry - */ - bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_plogi_retry); - ns->port->stats.ns_retries++; - bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ns->port), &ns->timer, - bfa_fcs_port_ns_timeout, ns, - BFA_FCS_RETRY_TIMEOUT); - break; - - case NSSM_EVENT_RSP_OK: - bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_sending_rspn_id); - bfa_fcs_port_ns_send_rspn_id(ns, NULL); - break; - - case NSSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline); - bfa_fcxp_discard(ns->fcxp); - break; - - default: - bfa_sm_fault(ns->port->fcs, event); - } -} - -static void -bfa_fcs_port_ns_sm_plogi_retry(struct bfa_fcs_port_ns_s *ns, - enum vport_ns_event event) -{ - bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); - bfa_trc(ns->port->fcs, event); - - switch (event) { - case NSSM_EVENT_TIMEOUT: - /* - * Retry Timer Expired. Re-send - */ - bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_plogi_sending); - bfa_fcs_port_ns_send_plogi(ns, NULL); - break; - - case NSSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline); - bfa_timer_stop(&ns->timer); - break; - - default: - bfa_sm_fault(ns->port->fcs, event); - } -} - -static void -bfa_fcs_port_ns_sm_sending_rspn_id(struct bfa_fcs_port_ns_s *ns, - enum vport_ns_event event) -{ - bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); - bfa_trc(ns->port->fcs, event); - - switch (event) { - case NSSM_EVENT_RSPNID_SENT: - bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_rspn_id); - break; - - case NSSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline); - bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ns->port), - &ns->fcxp_wqe); - break; - - default: - bfa_sm_fault(ns->port->fcs, event); - } -} - -static void -bfa_fcs_port_ns_sm_rspn_id(struct bfa_fcs_port_ns_s *ns, - enum vport_ns_event event) -{ - bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); - bfa_trc(ns->port->fcs, event); - - switch (event) { - case NSSM_EVENT_RSP_ERROR: - /* - * Start timer for a delayed retry - */ - bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_rspn_id_retry); - ns->port->stats.ns_retries++; - bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ns->port), &ns->timer, - bfa_fcs_port_ns_timeout, ns, - BFA_FCS_RETRY_TIMEOUT); - break; - - case NSSM_EVENT_RSP_OK: - bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_sending_rft_id); - bfa_fcs_port_ns_send_rft_id(ns, NULL); - break; - - case NSSM_EVENT_PORT_OFFLINE: - bfa_fcxp_discard(ns->fcxp); - bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline); - break; - - default: - bfa_sm_fault(ns->port->fcs, event); - } -} - -static void -bfa_fcs_port_ns_sm_rspn_id_retry(struct bfa_fcs_port_ns_s *ns, - enum vport_ns_event event) -{ - bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); - bfa_trc(ns->port->fcs, event); - - switch (event) { - case NSSM_EVENT_TIMEOUT: - /* - * Retry Timer Expired. Re-send - */ - bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_sending_rspn_id); - bfa_fcs_port_ns_send_rspn_id(ns, NULL); - break; - - case NSSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline); - bfa_timer_stop(&ns->timer); - break; - - default: - bfa_sm_fault(ns->port->fcs, event); - } -} - -static void -bfa_fcs_port_ns_sm_sending_rft_id(struct bfa_fcs_port_ns_s *ns, - enum vport_ns_event event) -{ - bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); - bfa_trc(ns->port->fcs, event); - - switch (event) { - case NSSM_EVENT_RFTID_SENT: - bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_rft_id); - break; - - case NSSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline); - bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ns->port), - &ns->fcxp_wqe); - break; - - default: - bfa_sm_fault(ns->port->fcs, event); - } -} - -static void -bfa_fcs_port_ns_sm_rft_id(struct bfa_fcs_port_ns_s *ns, - enum vport_ns_event event) -{ - bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); - bfa_trc(ns->port->fcs, event); - - switch (event) { - case NSSM_EVENT_RSP_OK: - /* - * Now move to register FC4 Features - */ - bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_sending_rff_id); - bfa_fcs_port_ns_send_rff_id(ns, NULL); - break; - - case NSSM_EVENT_RSP_ERROR: - /* - * Start timer for a delayed retry - */ - bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_rft_id_retry); - ns->port->stats.ns_retries++; - bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ns->port), &ns->timer, - bfa_fcs_port_ns_timeout, ns, - BFA_FCS_RETRY_TIMEOUT); - break; - - case NSSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline); - bfa_fcxp_discard(ns->fcxp); - break; - - default: - bfa_sm_fault(ns->port->fcs, event); - } -} - -static void -bfa_fcs_port_ns_sm_rft_id_retry(struct bfa_fcs_port_ns_s *ns, - enum vport_ns_event event) -{ - bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); - bfa_trc(ns->port->fcs, event); - - switch (event) { - case NSSM_EVENT_TIMEOUT: - bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_sending_rft_id); - bfa_fcs_port_ns_send_rft_id(ns, NULL); - break; - - case NSSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline); - bfa_timer_stop(&ns->timer); - break; - - default: - bfa_sm_fault(ns->port->fcs, event); - } -} - -static void -bfa_fcs_port_ns_sm_sending_rff_id(struct bfa_fcs_port_ns_s *ns, - enum vport_ns_event event) -{ - bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); - bfa_trc(ns->port->fcs, event); - - switch (event) { - case NSSM_EVENT_RFFID_SENT: - bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_rff_id); - break; - - case NSSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline); - bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ns->port), - &ns->fcxp_wqe); - break; - - default: - bfa_sm_fault(ns->port->fcs, event); - } -} - -static void -bfa_fcs_port_ns_sm_rff_id(struct bfa_fcs_port_ns_s *ns, - enum vport_ns_event event) -{ - bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); - bfa_trc(ns->port->fcs, event); - - switch (event) { - case NSSM_EVENT_RSP_OK: - - /* - * If min cfg mode is enabled, we donot initiate rport - * discovery with the fabric. Instead, we will retrieve the - * boot targets from HAL/FW. - */ - if (__fcs_min_cfg(ns->port->fcs)) { - bfa_fcs_port_ns_boot_target_disc(ns->port); - bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_online); - return; - } - - /* - * If the port role is Initiator Mode issue NS query. - * If it is Target Mode, skip this and go to online. - */ - if (BFA_FCS_VPORT_IS_INITIATOR_MODE(ns->port)) { - bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_sending_gid_ft); - bfa_fcs_port_ns_send_gid_ft(ns, NULL); - } else if (BFA_FCS_VPORT_IS_TARGET_MODE(ns->port)) { - bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_online); - } - /* - * kick off mgmt srvr state machine - */ - bfa_fcs_port_ms_online(ns->port); - break; - - case NSSM_EVENT_RSP_ERROR: - /* - * Start timer for a delayed retry - */ - bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_rff_id_retry); - ns->port->stats.ns_retries++; - bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ns->port), &ns->timer, - bfa_fcs_port_ns_timeout, ns, - BFA_FCS_RETRY_TIMEOUT); - break; - - case NSSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline); - bfa_fcxp_discard(ns->fcxp); - break; - - default: - bfa_sm_fault(ns->port->fcs, event); - } -} - -static void -bfa_fcs_port_ns_sm_rff_id_retry(struct bfa_fcs_port_ns_s *ns, - enum vport_ns_event event) -{ - bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); - bfa_trc(ns->port->fcs, event); - - switch (event) { - case NSSM_EVENT_TIMEOUT: - bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_sending_rff_id); - bfa_fcs_port_ns_send_rff_id(ns, NULL); - break; - - case NSSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline); - bfa_timer_stop(&ns->timer); - break; - - default: - bfa_sm_fault(ns->port->fcs, event); - } -} -static void -bfa_fcs_port_ns_sm_sending_gid_ft(struct bfa_fcs_port_ns_s *ns, - enum vport_ns_event event) -{ - bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); - bfa_trc(ns->port->fcs, event); - - switch (event) { - case NSSM_EVENT_GIDFT_SENT: - bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_gid_ft); - break; - - case NSSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline); - bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ns->port), - &ns->fcxp_wqe); - break; - - default: - bfa_sm_fault(ns->port->fcs, event); - } -} - -static void -bfa_fcs_port_ns_sm_gid_ft(struct bfa_fcs_port_ns_s *ns, - enum vport_ns_event event) -{ - bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); - bfa_trc(ns->port->fcs, event); - - switch (event) { - case NSSM_EVENT_RSP_OK: - bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_online); - break; - - case NSSM_EVENT_RSP_ERROR: - /* - * TBD: for certain reject codes, we don't need to retry - */ - /* - * Start timer for a delayed retry - */ - bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_gid_ft_retry); - ns->port->stats.ns_retries++; - bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ns->port), &ns->timer, - bfa_fcs_port_ns_timeout, ns, - BFA_FCS_RETRY_TIMEOUT); - break; - - case NSSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline); - bfa_fcxp_discard(ns->fcxp); - break; - - default: - bfa_sm_fault(ns->port->fcs, event); - } -} - -static void -bfa_fcs_port_ns_sm_gid_ft_retry(struct bfa_fcs_port_ns_s *ns, - enum vport_ns_event event) -{ - bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); - bfa_trc(ns->port->fcs, event); - - switch (event) { - case NSSM_EVENT_TIMEOUT: - bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_sending_gid_ft); - bfa_fcs_port_ns_send_gid_ft(ns, NULL); - break; - - case NSSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline); - bfa_timer_stop(&ns->timer); - break; - - default: - bfa_sm_fault(ns->port->fcs, event); - } -} - -static void -bfa_fcs_port_ns_sm_online(struct bfa_fcs_port_ns_s *ns, - enum vport_ns_event event) -{ - bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); - bfa_trc(ns->port->fcs, event); - - switch (event) { - case NSSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline); - break; - - case NSSM_EVENT_NS_QUERY: - /* - * If the port role is Initiator Mode issue NS query. - * If it is Target Mode, skip this and go to online. - */ - if (BFA_FCS_VPORT_IS_INITIATOR_MODE(ns->port)) { - bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_sending_gid_ft); - bfa_fcs_port_ns_send_gid_ft(ns, NULL); - }; - break; - - default: - bfa_sm_fault(ns->port->fcs, event); - } -} - - - -/** - * ns_pvt Nameserver local functions - */ - -static void -bfa_fcs_port_ns_send_plogi(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced) -{ - struct bfa_fcs_port_ns_s *ns = ns_cbarg; - struct bfa_fcs_port_s *port = ns->port; - struct fchs_s fchs; - int len; - struct bfa_fcxp_s *fcxp; - - bfa_trc(port->fcs, port->pid); - - fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); - if (!fcxp) { - port->stats.ns_plogi_alloc_wait++; - bfa_fcxp_alloc_wait(port->fcs->bfa, &ns->fcxp_wqe, - bfa_fcs_port_ns_send_plogi, ns); - return; - } - ns->fcxp = fcxp; - - len = fc_plogi_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), - bfa_os_hton3b(FC_NAME_SERVER), - bfa_fcs_port_get_fcid(port), 0, - port->port_cfg.pwwn, port->port_cfg.nwwn, - bfa_fcport_get_maxfrsize(port->fcs->bfa)); - - bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, - FC_CLASS_3, len, &fchs, bfa_fcs_port_ns_plogi_response, - (void *)ns, FC_MAX_PDUSZ, FC_ELS_TOV); - port->stats.ns_plogi_sent++; - - bfa_sm_send_event(ns, NSSM_EVENT_PLOGI_SENT); -} - -static void -bfa_fcs_port_ns_plogi_response(void *fcsarg, struct bfa_fcxp_s *fcxp, - void *cbarg, bfa_status_t req_status, - u32 rsp_len, u32 resid_len, - struct fchs_s *rsp_fchs) -{ - struct bfa_fcs_port_ns_s *ns = (struct bfa_fcs_port_ns_s *)cbarg; - struct bfa_fcs_port_s *port = ns->port; - /* struct fc_logi_s *plogi_resp; */ - struct fc_els_cmd_s *els_cmd; - struct fc_ls_rjt_s *ls_rjt; - - bfa_trc(port->fcs, req_status); - bfa_trc(port->fcs, port->port_cfg.pwwn); - - /* - * Sanity Checks - */ - if (req_status != BFA_STATUS_OK) { - bfa_trc(port->fcs, req_status); - port->stats.ns_plogi_rsp_err++; - bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); - return; - } - - els_cmd = (struct fc_els_cmd_s *) BFA_FCXP_RSP_PLD(fcxp); - - switch (els_cmd->els_code) { - - case FC_ELS_ACC: - if (rsp_len < sizeof(struct fc_logi_s)) { - bfa_trc(port->fcs, rsp_len); - port->stats.ns_plogi_acc_err++; - bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); - break; - } - port->stats.ns_plogi_accepts++; - bfa_sm_send_event(ns, NSSM_EVENT_RSP_OK); - break; - - case FC_ELS_LS_RJT: - ls_rjt = (struct fc_ls_rjt_s *) BFA_FCXP_RSP_PLD(fcxp); - - bfa_trc(port->fcs, ls_rjt->reason_code); - bfa_trc(port->fcs, ls_rjt->reason_code_expl); - - port->stats.ns_rejects++; - - bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); - break; - - default: - port->stats.ns_plogi_unknown_rsp++; - bfa_trc(port->fcs, els_cmd->els_code); - bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); - } -} - -/** - * Register the symbolic port name. - */ -static void -bfa_fcs_port_ns_send_rspn_id(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced) -{ - struct bfa_fcs_port_ns_s *ns = ns_cbarg; - struct bfa_fcs_port_s *port = ns->port; - struct fchs_s fchs; - int len; - struct bfa_fcxp_s *fcxp; - u8 symbl[256]; - u8 *psymbl = &symbl[0]; - - bfa_os_memset(symbl, 0, sizeof(symbl)); - - bfa_trc(port->fcs, port->port_cfg.pwwn); - - fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); - if (!fcxp) { - port->stats.ns_rspnid_alloc_wait++; - bfa_fcxp_alloc_wait(port->fcs->bfa, &ns->fcxp_wqe, - bfa_fcs_port_ns_send_rspn_id, ns); - return; - } - ns->fcxp = fcxp; - - /* - * for V-Port, form a Port Symbolic Name - */ - if (port->vport) { - /**For Vports, - * we append the vport's port symbolic name to that of the base port. - */ - - strncpy((char *)psymbl, - (char *) - &(bfa_fcs_port_get_psym_name - (bfa_fcs_get_base_port(port->fcs))), - strlen((char *) - &bfa_fcs_port_get_psym_name(bfa_fcs_get_base_port - (port->fcs)))); - - /* - * Ensure we have a null terminating string. - */ - ((char *) - psymbl)[strlen((char *) - &bfa_fcs_port_get_psym_name - (bfa_fcs_get_base_port(port->fcs)))] = 0; - - strncat((char *)psymbl, - (char *)&(bfa_fcs_port_get_psym_name(port)), - strlen((char *)&bfa_fcs_port_get_psym_name(port))); - } else { - psymbl = (u8 *) &(bfa_fcs_port_get_psym_name(port)); - } - - len = fc_rspnid_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), - bfa_fcs_port_get_fcid(port), 0, psymbl); - - bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, - FC_CLASS_3, len, &fchs, bfa_fcs_port_ns_rspn_id_response, - (void *)ns, FC_MAX_PDUSZ, FC_FCCT_TOV); - - port->stats.ns_rspnid_sent++; - - bfa_sm_send_event(ns, NSSM_EVENT_RSPNID_SENT); -} - -static void -bfa_fcs_port_ns_rspn_id_response(void *fcsarg, struct bfa_fcxp_s *fcxp, - void *cbarg, bfa_status_t req_status, - u32 rsp_len, u32 resid_len, - struct fchs_s *rsp_fchs) -{ - struct bfa_fcs_port_ns_s *ns = (struct bfa_fcs_port_ns_s *)cbarg; - struct bfa_fcs_port_s *port = ns->port; - struct ct_hdr_s *cthdr = NULL; - - bfa_trc(port->fcs, port->port_cfg.pwwn); - - /* - * Sanity Checks - */ - if (req_status != BFA_STATUS_OK) { - bfa_trc(port->fcs, req_status); - port->stats.ns_rspnid_rsp_err++; - bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); - return; - } - - cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp); - cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code); - - if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) { - port->stats.ns_rspnid_accepts++; - bfa_sm_send_event(ns, NSSM_EVENT_RSP_OK); - return; - } - - port->stats.ns_rspnid_rejects++; - bfa_trc(port->fcs, cthdr->reason_code); - bfa_trc(port->fcs, cthdr->exp_code); - bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); -} - -/** - * Register FC4-Types - * TBD, Need to retrieve this from the OS driver, in case IPFC is enabled ? - */ -static void -bfa_fcs_port_ns_send_rft_id(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced) -{ - struct bfa_fcs_port_ns_s *ns = ns_cbarg; - struct bfa_fcs_port_s *port = ns->port; - struct fchs_s fchs; - int len; - struct bfa_fcxp_s *fcxp; - - bfa_trc(port->fcs, port->port_cfg.pwwn); - - fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); - if (!fcxp) { - port->stats.ns_rftid_alloc_wait++; - bfa_fcxp_alloc_wait(port->fcs->bfa, &ns->fcxp_wqe, - bfa_fcs_port_ns_send_rft_id, ns); - return; - } - ns->fcxp = fcxp; - - len = fc_rftid_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), - bfa_fcs_port_get_fcid(port), 0, - port->port_cfg.roles); - - bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, - FC_CLASS_3, len, &fchs, bfa_fcs_port_ns_rft_id_response, - (void *)ns, FC_MAX_PDUSZ, FC_FCCT_TOV); - - port->stats.ns_rftid_sent++; - bfa_sm_send_event(ns, NSSM_EVENT_RFTID_SENT); -} - -static void -bfa_fcs_port_ns_rft_id_response(void *fcsarg, struct bfa_fcxp_s *fcxp, - void *cbarg, bfa_status_t req_status, - u32 rsp_len, u32 resid_len, - struct fchs_s *rsp_fchs) -{ - struct bfa_fcs_port_ns_s *ns = (struct bfa_fcs_port_ns_s *)cbarg; - struct bfa_fcs_port_s *port = ns->port; - struct ct_hdr_s *cthdr = NULL; - - bfa_trc(port->fcs, port->port_cfg.pwwn); - - /* - * Sanity Checks - */ - if (req_status != BFA_STATUS_OK) { - bfa_trc(port->fcs, req_status); - port->stats.ns_rftid_rsp_err++; - bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); - return; - } - - cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp); - cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code); - - if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) { - port->stats.ns_rftid_accepts++; - bfa_sm_send_event(ns, NSSM_EVENT_RSP_OK); - return; - } - - port->stats.ns_rftid_rejects++; - bfa_trc(port->fcs, cthdr->reason_code); - bfa_trc(port->fcs, cthdr->exp_code); - bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); -} - -/** -* Register FC4-Features : Should be done after RFT_ID - */ -static void -bfa_fcs_port_ns_send_rff_id(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced) -{ - struct bfa_fcs_port_ns_s *ns = ns_cbarg; - struct bfa_fcs_port_s *port = ns->port; - struct fchs_s fchs; - int len; - struct bfa_fcxp_s *fcxp; - u8 fc4_ftrs = 0; - - bfa_trc(port->fcs, port->port_cfg.pwwn); - - fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); - if (!fcxp) { - port->stats.ns_rffid_alloc_wait++; - bfa_fcxp_alloc_wait(port->fcs->bfa, &ns->fcxp_wqe, - bfa_fcs_port_ns_send_rff_id, ns); - return; - } - ns->fcxp = fcxp; - - if (BFA_FCS_VPORT_IS_INITIATOR_MODE(ns->port)) - fc4_ftrs = FC_GS_FCP_FC4_FEATURE_INITIATOR; - else if (BFA_FCS_VPORT_IS_TARGET_MODE(ns->port)) - fc4_ftrs = FC_GS_FCP_FC4_FEATURE_TARGET; - - len = fc_rffid_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), - bfa_fcs_port_get_fcid(port), 0, FC_TYPE_FCP, - fc4_ftrs); - - bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, - FC_CLASS_3, len, &fchs, bfa_fcs_port_ns_rff_id_response, - (void *)ns, FC_MAX_PDUSZ, FC_FCCT_TOV); - - port->stats.ns_rffid_sent++; - bfa_sm_send_event(ns, NSSM_EVENT_RFFID_SENT); -} - -static void -bfa_fcs_port_ns_rff_id_response(void *fcsarg, struct bfa_fcxp_s *fcxp, - void *cbarg, bfa_status_t req_status, - u32 rsp_len, u32 resid_len, - struct fchs_s *rsp_fchs) -{ - struct bfa_fcs_port_ns_s *ns = (struct bfa_fcs_port_ns_s *)cbarg; - struct bfa_fcs_port_s *port = ns->port; - struct ct_hdr_s *cthdr = NULL; - - bfa_trc(port->fcs, port->port_cfg.pwwn); - - /* - * Sanity Checks - */ - if (req_status != BFA_STATUS_OK) { - bfa_trc(port->fcs, req_status); - port->stats.ns_rffid_rsp_err++; - bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); - return; - } - - cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp); - cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code); - - if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) { - port->stats.ns_rffid_accepts++; - bfa_sm_send_event(ns, NSSM_EVENT_RSP_OK); - return; - } - - port->stats.ns_rffid_rejects++; - bfa_trc(port->fcs, cthdr->reason_code); - bfa_trc(port->fcs, cthdr->exp_code); - - if (cthdr->reason_code == CT_RSN_NOT_SUPP) { - /* - * if this command is not supported, we don't retry - */ - bfa_sm_send_event(ns, NSSM_EVENT_RSP_OK); - } else { - bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); - } -} - -/** - * Query Fabric for FC4-Types Devices. - * -* TBD : Need to use a local (FCS private) response buffer, since the response - * can be larger than 2K. - */ -static void -bfa_fcs_port_ns_send_gid_ft(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced) -{ - struct bfa_fcs_port_ns_s *ns = ns_cbarg; - struct bfa_fcs_port_s *port = ns->port; - struct fchs_s fchs; - int len; - struct bfa_fcxp_s *fcxp; - - bfa_trc(port->fcs, port->pid); - - fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); - if (!fcxp) { - port->stats.ns_gidft_alloc_wait++; - bfa_fcxp_alloc_wait(port->fcs->bfa, &ns->fcxp_wqe, - bfa_fcs_port_ns_send_gid_ft, ns); - return; - } - ns->fcxp = fcxp; - - /* - * This query is only initiated for FCP initiator mode. - */ - len = fc_gid_ft_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), ns->port->pid, - FC_TYPE_FCP); - - bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, - FC_CLASS_3, len, &fchs, bfa_fcs_port_ns_gid_ft_response, - (void *)ns, bfa_fcxp_get_maxrsp(port->fcs->bfa), - FC_FCCT_TOV); - - port->stats.ns_gidft_sent++; - - bfa_sm_send_event(ns, NSSM_EVENT_GIDFT_SENT); -} - -static void -bfa_fcs_port_ns_gid_ft_response(void *fcsarg, struct bfa_fcxp_s *fcxp, - void *cbarg, bfa_status_t req_status, - u32 rsp_len, u32 resid_len, - struct fchs_s *rsp_fchs) -{ - struct bfa_fcs_port_ns_s *ns = (struct bfa_fcs_port_ns_s *)cbarg; - struct bfa_fcs_port_s *port = ns->port; - struct ct_hdr_s *cthdr = NULL; - u32 n_pids; - - bfa_trc(port->fcs, port->port_cfg.pwwn); - - /* - * Sanity Checks - */ - if (req_status != BFA_STATUS_OK) { - bfa_trc(port->fcs, req_status); - port->stats.ns_gidft_rsp_err++; - bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); - return; - } - - if (resid_len != 0) { - /* - * TBD : we will need to allocate a larger buffer & retry the - * command - */ - bfa_trc(port->fcs, rsp_len); - bfa_trc(port->fcs, resid_len); - return; - } - - cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp); - cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code); - - switch (cthdr->cmd_rsp_code) { - - case CT_RSP_ACCEPT: - - port->stats.ns_gidft_accepts++; - n_pids = (fc_get_ctresp_pyld_len(rsp_len) / sizeof(u32)); - bfa_trc(port->fcs, n_pids); - bfa_fcs_port_ns_process_gidft_pids(port, - (u32 *) (cthdr + 1), - n_pids); - bfa_sm_send_event(ns, NSSM_EVENT_RSP_OK); - break; - - case CT_RSP_REJECT: - - /* - * Check the reason code & explanation. - * There may not have been any FC4 devices in the fabric - */ - port->stats.ns_gidft_rejects++; - bfa_trc(port->fcs, cthdr->reason_code); - bfa_trc(port->fcs, cthdr->exp_code); - - if ((cthdr->reason_code == CT_RSN_UNABLE_TO_PERF) - && (cthdr->exp_code == CT_NS_EXP_FT_NOT_REG)) { - - bfa_sm_send_event(ns, NSSM_EVENT_RSP_OK); - } else { - /* - * for all other errors, retry - */ - bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); - } - break; - - default: - port->stats.ns_gidft_unknown_rsp++; - bfa_trc(port->fcs, cthdr->cmd_rsp_code); - bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); - } -} - -/** - * This routine will be called by bfa_timer on timer timeouts. - * - * param[in] port - pointer to bfa_fcs_port_t. - * - * return - * void - * -* Special Considerations: - * - * note - */ -static void -bfa_fcs_port_ns_timeout(void *arg) -{ - struct bfa_fcs_port_ns_s *ns = (struct bfa_fcs_port_ns_s *)arg; - - ns->port->stats.ns_timeouts++; - bfa_sm_send_event(ns, NSSM_EVENT_TIMEOUT); -} - -/* - * Process the PID list in GID_FT response - */ -static void -bfa_fcs_port_ns_process_gidft_pids(struct bfa_fcs_port_s *port, - u32 *pid_buf, u32 n_pids) -{ - struct fcgs_gidft_resp_s *gidft_entry; - struct bfa_fcs_rport_s *rport; - u32 ii; - - for (ii = 0; ii < n_pids; ii++) { - gidft_entry = (struct fcgs_gidft_resp_s *) &pid_buf[ii]; - - if (gidft_entry->pid == port->pid) - continue; - - /* - * Check if this rport already exists - */ - rport = bfa_fcs_port_get_rport_by_pid(port, gidft_entry->pid); - if (rport == NULL) { - /* - * this is a new device. create rport - */ - rport = bfa_fcs_rport_create(port, gidft_entry->pid); - } else { - /* - * this rport already exists - */ - bfa_fcs_rport_scn(rport); - } - - bfa_trc(port->fcs, gidft_entry->pid); - - /* - * if the last entry bit is set, bail out. - */ - if (gidft_entry->last) - return; - } -} - -/** - * fcs_ns_public FCS nameserver public interfaces - */ - -/* - * Functions called by port/fab. - * These will send relevant Events to the ns state machine. - */ -void -bfa_fcs_port_ns_init(struct bfa_fcs_port_s *port) -{ - struct bfa_fcs_port_ns_s *ns = BFA_FCS_GET_NS_FROM_PORT(port); - - ns->port = port; - bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline); -} - -void -bfa_fcs_port_ns_offline(struct bfa_fcs_port_s *port) -{ - struct bfa_fcs_port_ns_s *ns = BFA_FCS_GET_NS_FROM_PORT(port); - - ns->port = port; - bfa_sm_send_event(ns, NSSM_EVENT_PORT_OFFLINE); -} - -void -bfa_fcs_port_ns_online(struct bfa_fcs_port_s *port) -{ - struct bfa_fcs_port_ns_s *ns = BFA_FCS_GET_NS_FROM_PORT(port); - - ns->port = port; - bfa_sm_send_event(ns, NSSM_EVENT_PORT_ONLINE); -} - -void -bfa_fcs_port_ns_query(struct bfa_fcs_port_s *port) -{ - struct bfa_fcs_port_ns_s *ns = BFA_FCS_GET_NS_FROM_PORT(port); - - bfa_trc(port->fcs, port->pid); - bfa_sm_send_event(ns, NSSM_EVENT_NS_QUERY); -} - -static void -bfa_fcs_port_ns_boot_target_disc(struct bfa_fcs_port_s *port) -{ - - struct bfa_fcs_rport_s *rport; - u8 nwwns; - wwn_t wwns[BFA_PREBOOT_BOOTLUN_MAX]; - int ii; - - bfa_iocfc_get_bootwwns(port->fcs->bfa, &nwwns, wwns); - - for (ii = 0; ii < nwwns; ++ii) { - rport = bfa_fcs_rport_create_by_wwn(port, wwns[ii]); - bfa_assert(rport); - } -} - - diff --git a/drivers/scsi/bfa/plog.c b/drivers/scsi/bfa/plog.c deleted file mode 100644 index fcb8864d3276..000000000000 --- a/drivers/scsi/bfa/plog.c +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#include <bfa_os_inc.h> -#include <cs/bfa_plog.h> -#include <cs/bfa_debug.h> - -static int -plkd_validate_logrec(struct bfa_plog_rec_s *pl_rec) -{ - if ((pl_rec->log_type != BFA_PL_LOG_TYPE_INT) - && (pl_rec->log_type != BFA_PL_LOG_TYPE_STRING)) - return 1; - - if ((pl_rec->log_type != BFA_PL_LOG_TYPE_INT) - && (pl_rec->log_num_ints > BFA_PL_INT_LOG_SZ)) - return 1; - - return 0; -} - -static void -bfa_plog_add(struct bfa_plog_s *plog, struct bfa_plog_rec_s *pl_rec) -{ - u16 tail; - struct bfa_plog_rec_s *pl_recp; - - if (plog->plog_enabled == 0) - return; - - if (plkd_validate_logrec(pl_rec)) { - bfa_assert(0); - return; - } - - tail = plog->tail; - - pl_recp = &(plog->plog_recs[tail]); - - bfa_os_memcpy(pl_recp, pl_rec, sizeof(struct bfa_plog_rec_s)); - - pl_recp->tv = BFA_TRC_TS(plog); - BFA_PL_LOG_REC_INCR(plog->tail); - - if (plog->head == plog->tail) - BFA_PL_LOG_REC_INCR(plog->head); -} - -void -bfa_plog_init(struct bfa_plog_s *plog) -{ - bfa_os_memset((char *)plog, 0, sizeof(struct bfa_plog_s)); - - bfa_os_memcpy(plog->plog_sig, BFA_PL_SIG_STR, BFA_PL_SIG_LEN); - plog->head = plog->tail = 0; - plog->plog_enabled = 1; -} - -void -bfa_plog_str(struct bfa_plog_s *plog, enum bfa_plog_mid mid, - enum bfa_plog_eid event, - u16 misc, char *log_str) -{ - struct bfa_plog_rec_s lp; - - if (plog->plog_enabled) { - bfa_os_memset(&lp, 0, sizeof(struct bfa_plog_rec_s)); - lp.mid = mid; - lp.eid = event; - lp.log_type = BFA_PL_LOG_TYPE_STRING; - lp.misc = misc; - strncpy(lp.log_entry.string_log, log_str, - BFA_PL_STRING_LOG_SZ - 1); - lp.log_entry.string_log[BFA_PL_STRING_LOG_SZ - 1] = '\0'; - bfa_plog_add(plog, &lp); - } -} - -void -bfa_plog_intarr(struct bfa_plog_s *plog, enum bfa_plog_mid mid, - enum bfa_plog_eid event, - u16 misc, u32 *intarr, u32 num_ints) -{ - struct bfa_plog_rec_s lp; - u32 i; - - if (num_ints > BFA_PL_INT_LOG_SZ) - num_ints = BFA_PL_INT_LOG_SZ; - - if (plog->plog_enabled) { - bfa_os_memset(&lp, 0, sizeof(struct bfa_plog_rec_s)); - lp.mid = mid; - lp.eid = event; - lp.log_type = BFA_PL_LOG_TYPE_INT; - lp.misc = misc; - - for (i = 0; i < num_ints; i++) - bfa_os_assign(lp.log_entry.int_log[i], - intarr[i]); - - lp.log_num_ints = (u8) num_ints; - - bfa_plog_add(plog, &lp); - } -} - -void -bfa_plog_fchdr(struct bfa_plog_s *plog, enum bfa_plog_mid mid, - enum bfa_plog_eid event, - u16 misc, struct fchs_s *fchdr) -{ - struct bfa_plog_rec_s lp; - u32 *tmp_int = (u32 *) fchdr; - u32 ints[BFA_PL_INT_LOG_SZ]; - - if (plog->plog_enabled) { - bfa_os_memset(&lp, 0, sizeof(struct bfa_plog_rec_s)); - - ints[0] = tmp_int[0]; - ints[1] = tmp_int[1]; - ints[2] = tmp_int[4]; - - bfa_plog_intarr(plog, mid, event, misc, ints, 3); - } -} - -void -bfa_plog_fchdr_and_pl(struct bfa_plog_s *plog, enum bfa_plog_mid mid, - enum bfa_plog_eid event, u16 misc, struct fchs_s *fchdr, - u32 pld_w0) -{ - struct bfa_plog_rec_s lp; - u32 *tmp_int = (u32 *) fchdr; - u32 ints[BFA_PL_INT_LOG_SZ]; - - if (plog->plog_enabled) { - bfa_os_memset(&lp, 0, sizeof(struct bfa_plog_rec_s)); - - ints[0] = tmp_int[0]; - ints[1] = tmp_int[1]; - ints[2] = tmp_int[4]; - ints[3] = pld_w0; - - bfa_plog_intarr(plog, mid, event, misc, ints, 4); - } -} - -void -bfa_plog_clear(struct bfa_plog_s *plog) -{ - plog->head = plog->tail = 0; -} - -void -bfa_plog_enable(struct bfa_plog_s *plog) -{ - plog->plog_enabled = 1; -} - -void -bfa_plog_disable(struct bfa_plog_s *plog) -{ - plog->plog_enabled = 0; -} - -bfa_boolean_t -bfa_plog_get_setting(struct bfa_plog_s *plog) -{ - return (bfa_boolean_t)plog->plog_enabled; -} diff --git a/drivers/scsi/bfa/rport_api.c b/drivers/scsi/bfa/rport_api.c deleted file mode 100644 index 15e0c470afd9..000000000000 --- a/drivers/scsi/bfa/rport_api.c +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ -#include <bfa.h> -#include <bfa_svc.h> -#include "fcs_vport.h" -#include "fcs_lport.h" -#include "fcs_rport.h" -#include "fcs_trcmod.h" - -BFA_TRC_FILE(FCS, RPORT_API); - -/** - * rport_api.c Remote port implementation. - */ - -/** - * fcs_rport_api FCS rport API. - */ - -/** - * Direct API to add a target by port wwn. This interface is used, for - * example, by bios when target pwwn is known from boot lun configuration. - */ -bfa_status_t -bfa_fcs_rport_add(struct bfa_fcs_port_s *port, wwn_t *pwwn, - struct bfa_fcs_rport_s *rport, - struct bfad_rport_s *rport_drv) -{ - bfa_trc(port->fcs, *pwwn); - - return BFA_STATUS_OK; -} - -/** - * Direct API to remove a target and its associated resources. This - * interface is used, for example, by vmware driver to remove target - * ports from the target list for a VM. - */ -bfa_status_t -bfa_fcs_rport_remove(struct bfa_fcs_rport_s *rport_in) -{ - - struct bfa_fcs_rport_s *rport; - - bfa_trc(rport_in->fcs, rport_in->pwwn); - - rport = bfa_fcs_port_get_rport_by_pwwn(rport_in->port, rport_in->pwwn); - if (rport == NULL) { - /* - * TBD Error handling - */ - bfa_trc(rport_in->fcs, rport_in->pid); - return BFA_STATUS_UNKNOWN_RWWN; - } - - /* - * TBD if this remote port is online, send a logo - */ - return BFA_STATUS_OK; - -} - -/** - * Remote device status for display/debug. - */ -void -bfa_fcs_rport_get_attr(struct bfa_fcs_rport_s *rport, - struct bfa_rport_attr_s *rport_attr) -{ - struct bfa_rport_qos_attr_s qos_attr; - struct bfa_fcs_port_s *port = rport->port; - enum bfa_pport_speed rport_speed = rport->rpf.rpsc_speed; - - bfa_os_memset(rport_attr, 0, sizeof(struct bfa_rport_attr_s)); - - rport_attr->pid = rport->pid; - rport_attr->pwwn = rport->pwwn; - rport_attr->nwwn = rport->nwwn; - rport_attr->cos_supported = rport->fc_cos; - rport_attr->df_sz = rport->maxfrsize; - rport_attr->state = bfa_fcs_rport_get_state(rport); - rport_attr->fc_cos = rport->fc_cos; - rport_attr->cisc = rport->cisc; - rport_attr->scsi_function = rport->scsi_function; - rport_attr->curr_speed = rport->rpf.rpsc_speed; - rport_attr->assigned_speed = rport->rpf.assigned_speed; - - bfa_rport_get_qos_attr(rport->bfa_rport, &qos_attr); - rport_attr->qos_attr = qos_attr; - - rport_attr->trl_enforced = BFA_FALSE; - - if (bfa_fcport_is_ratelim(port->fcs->bfa)) { - 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; - } - - /* - * TODO - * rport->symname - */ -} - -/** - * Per remote device statistics. - */ -void -bfa_fcs_rport_get_stats(struct bfa_fcs_rport_s *rport, - struct bfa_rport_stats_s *stats) -{ - *stats = rport->stats; -} - -void -bfa_fcs_rport_clear_stats(struct bfa_fcs_rport_s *rport) -{ - bfa_os_memset((char *)&rport->stats, 0, - sizeof(struct bfa_rport_stats_s)); -} - -struct bfa_fcs_rport_s * -bfa_fcs_rport_lookup(struct bfa_fcs_port_s *port, wwn_t rpwwn) -{ - struct bfa_fcs_rport_s *rport; - - rport = bfa_fcs_port_get_rport_by_pwwn(port, rpwwn); - if (rport == NULL) { - /* - * TBD Error handling - */ - } - - return rport; -} - -struct bfa_fcs_rport_s * -bfa_fcs_rport_lookup_by_nwwn(struct bfa_fcs_port_s *port, wwn_t rnwwn) -{ - struct bfa_fcs_rport_s *rport; - - rport = bfa_fcs_port_get_rport_by_nwwn(port, rnwwn); - if (rport == NULL) { - /* - * TBD Error handling - */ - } - - return rport; -} - -/* - * This API is to set the Rport's speed. Should be used when RPSC is not - * supported by the rport. - */ -void -bfa_fcs_rport_set_speed(struct bfa_fcs_rport_s *rport, - enum bfa_pport_speed speed) -{ - rport->rpf.assigned_speed = speed; - - /* Set this speed in f/w only if the RPSC speed is not available */ - if (rport->rpf.rpsc_speed == BFA_PPORT_SPEED_UNKNOWN) - bfa_rport_speed(rport->bfa_rport, speed); -} - - diff --git a/drivers/scsi/bfa/rport_ftrs.c b/drivers/scsi/bfa/rport_ftrs.c deleted file mode 100644 index f2a9361ce9a4..000000000000 --- a/drivers/scsi/bfa/rport_ftrs.c +++ /dev/null @@ -1,379 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/** - * rport_ftrs.c Remote port features (RPF) implementation. - */ - -#include <bfa.h> -#include <bfa_svc.h> -#include "fcbuild.h" -#include "fcs_rport.h" -#include "fcs_lport.h" -#include "fcs_trcmod.h" -#include "fcs_fcxp.h" -#include "fcs.h" - -BFA_TRC_FILE(FCS, RPORT_FTRS); - -#define BFA_FCS_RPF_RETRIES (3) -#define BFA_FCS_RPF_RETRY_TIMEOUT (1000) /* 1 sec (In millisecs) */ - -static void bfa_fcs_rpf_send_rpsc2(void *rport_cbarg, - struct bfa_fcxp_s *fcxp_alloced); -static void bfa_fcs_rpf_rpsc2_response(void *fcsarg, - struct bfa_fcxp_s *fcxp, void *cbarg, - bfa_status_t req_status, u32 rsp_len, - u32 resid_len, - struct fchs_s *rsp_fchs); -static void bfa_fcs_rpf_timeout(void *arg); - -/** - * fcs_rport_ftrs_sm FCS rport state machine events - */ - -enum rpf_event { - RPFSM_EVENT_RPORT_OFFLINE = 1, /* Rport offline */ - RPFSM_EVENT_RPORT_ONLINE = 2, /* Rport online */ - RPFSM_EVENT_FCXP_SENT = 3, /* Frame from has been sent */ - RPFSM_EVENT_TIMEOUT = 4, /* Rport SM timeout event */ - RPFSM_EVENT_RPSC_COMP = 5, - RPFSM_EVENT_RPSC_FAIL = 6, - RPFSM_EVENT_RPSC_ERROR = 7, -}; - -static void bfa_fcs_rpf_sm_uninit(struct bfa_fcs_rpf_s *rpf, - enum rpf_event event); -static void bfa_fcs_rpf_sm_rpsc_sending(struct bfa_fcs_rpf_s *rpf, - enum rpf_event event); -static void bfa_fcs_rpf_sm_rpsc(struct bfa_fcs_rpf_s *rpf, - enum rpf_event event); -static void bfa_fcs_rpf_sm_rpsc_retry(struct bfa_fcs_rpf_s *rpf, - enum rpf_event event); -static void bfa_fcs_rpf_sm_offline(struct bfa_fcs_rpf_s *rpf, - enum rpf_event event); -static void bfa_fcs_rpf_sm_online(struct bfa_fcs_rpf_s *rpf, - enum rpf_event event); - -static void -bfa_fcs_rpf_sm_uninit(struct bfa_fcs_rpf_s *rpf, enum rpf_event event) -{ - struct bfa_fcs_rport_s *rport = rpf->rport; - struct bfa_fcs_fabric_s *fabric = &rport->fcs->fabric; - - bfa_trc(rport->fcs, rport->pwwn); - bfa_trc(rport->fcs, rport->pid); - bfa_trc(rport->fcs, event); - - switch (event) { - case RPFSM_EVENT_RPORT_ONLINE: - /* 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; - - case RPFSM_EVENT_RPORT_OFFLINE: - break; - - default: - bfa_sm_fault(rport->fcs, event); - } -} - -static void -bfa_fcs_rpf_sm_rpsc_sending(struct bfa_fcs_rpf_s *rpf, enum rpf_event event) -{ - struct bfa_fcs_rport_s *rport = rpf->rport; - - bfa_trc(rport->fcs, event); - - switch (event) { - case RPFSM_EVENT_FCXP_SENT: - bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_rpsc); - break; - - case RPFSM_EVENT_RPORT_OFFLINE: - bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_offline); - bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rpf->fcxp_wqe); - rpf->rpsc_retries = 0; - break; - - default: - bfa_sm_fault(rport->fcs, event); - } -} - -static void -bfa_fcs_rpf_sm_rpsc(struct bfa_fcs_rpf_s *rpf, enum rpf_event event) -{ - struct bfa_fcs_rport_s *rport = rpf->rport; - - bfa_trc(rport->fcs, rport->pid); - bfa_trc(rport->fcs, event); - - switch (event) { - case RPFSM_EVENT_RPSC_COMP: - bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_online); - /* Update speed info in f/w via BFA */ - if (rpf->rpsc_speed != BFA_PPORT_SPEED_UNKNOWN) - bfa_rport_speed(rport->bfa_rport, rpf->rpsc_speed); - else if (rpf->assigned_speed != BFA_PPORT_SPEED_UNKNOWN) - bfa_rport_speed(rport->bfa_rport, rpf->assigned_speed); - break; - - case RPFSM_EVENT_RPSC_FAIL: - /* RPSC not supported by rport */ - bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_online); - break; - - case RPFSM_EVENT_RPSC_ERROR: - /* need to retry...delayed a bit. */ - if (rpf->rpsc_retries++ < BFA_FCS_RPF_RETRIES) { - bfa_timer_start(rport->fcs->bfa, &rpf->timer, - bfa_fcs_rpf_timeout, rpf, - BFA_FCS_RPF_RETRY_TIMEOUT); - bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_rpsc_retry); - } else { - bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_online); - } - break; - - case RPFSM_EVENT_RPORT_OFFLINE: - bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_offline); - bfa_fcxp_discard(rpf->fcxp); - rpf->rpsc_retries = 0; - break; - - default: - bfa_sm_fault(rport->fcs, event); - } -} - -static void -bfa_fcs_rpf_sm_rpsc_retry(struct bfa_fcs_rpf_s *rpf, enum rpf_event event) -{ - struct bfa_fcs_rport_s *rport = rpf->rport; - - bfa_trc(rport->fcs, rport->pid); - bfa_trc(rport->fcs, event); - - switch (event) { - case RPFSM_EVENT_TIMEOUT: - /* re-send the RPSC */ - bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_rpsc_sending); - bfa_fcs_rpf_send_rpsc2(rpf, NULL); - break; - - case RPFSM_EVENT_RPORT_OFFLINE: - bfa_timer_stop(&rpf->timer); - bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_offline); - rpf->rpsc_retries = 0; - break; - - default: - bfa_sm_fault(rport->fcs, event); - } -} - -static void -bfa_fcs_rpf_sm_online(struct bfa_fcs_rpf_s *rpf, enum rpf_event event) -{ - struct bfa_fcs_rport_s *rport = rpf->rport; - - bfa_trc(rport->fcs, rport->pwwn); - bfa_trc(rport->fcs, rport->pid); - bfa_trc(rport->fcs, event); - - switch (event) { - case RPFSM_EVENT_RPORT_OFFLINE: - bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_offline); - rpf->rpsc_retries = 0; - break; - - default: - bfa_sm_fault(rport->fcs, event); - } -} - -static void -bfa_fcs_rpf_sm_offline(struct bfa_fcs_rpf_s *rpf, enum rpf_event event) -{ - struct bfa_fcs_rport_s *rport = rpf->rport; - - bfa_trc(rport->fcs, rport->pwwn); - bfa_trc(rport->fcs, rport->pid); - bfa_trc(rport->fcs, event); - - switch (event) { - case RPFSM_EVENT_RPORT_ONLINE: - bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_rpsc_sending); - bfa_fcs_rpf_send_rpsc2(rpf, NULL); - break; - - case RPFSM_EVENT_RPORT_OFFLINE: - break; - - default: - bfa_sm_fault(rport->fcs, event); - } -} -/** - * Called when Rport is created. - */ -void bfa_fcs_rpf_init(struct bfa_fcs_rport_s *rport) -{ - struct bfa_fcs_rpf_s *rpf = &rport->rpf; - - bfa_trc(rport->fcs, rport->pid); - rpf->rport = rport; - - bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_uninit); -} - -/** - * Called when Rport becomes online - */ -void bfa_fcs_rpf_rport_online(struct bfa_fcs_rport_s *rport) -{ - bfa_trc(rport->fcs, rport->pid); - - if (__fcs_min_cfg(rport->port->fcs)) - return; - - if (bfa_fcs_fabric_is_switched(rport->port->fabric)) - bfa_sm_send_event(&rport->rpf, RPFSM_EVENT_RPORT_ONLINE); -} - -/** - * Called when Rport becomes offline - */ -void bfa_fcs_rpf_rport_offline(struct bfa_fcs_rport_s *rport) -{ - bfa_trc(rport->fcs, rport->pid); - - if (__fcs_min_cfg(rport->port->fcs)) - return; - - rport->rpf.rpsc_speed = 0; - bfa_sm_send_event(&rport->rpf, RPFSM_EVENT_RPORT_OFFLINE); -} - -static void -bfa_fcs_rpf_timeout(void *arg) -{ - struct bfa_fcs_rpf_s *rpf = (struct bfa_fcs_rpf_s *) arg; - struct bfa_fcs_rport_s *rport = rpf->rport; - - bfa_trc(rport->fcs, rport->pid); - bfa_sm_send_event(rpf, RPFSM_EVENT_TIMEOUT); -} - -static void -bfa_fcs_rpf_send_rpsc2(void *rpf_cbarg, struct bfa_fcxp_s *fcxp_alloced) -{ - struct bfa_fcs_rpf_s *rpf = (struct bfa_fcs_rpf_s *)rpf_cbarg; - struct bfa_fcs_rport_s *rport = rpf->rport; - struct bfa_fcs_port_s *port = rport->port; - struct fchs_s fchs; - int len; - struct bfa_fcxp_s *fcxp; - - bfa_trc(rport->fcs, rport->pwwn); - - fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); - if (!fcxp) { - bfa_fcxp_alloc_wait(port->fcs->bfa, &rpf->fcxp_wqe, - bfa_fcs_rpf_send_rpsc2, rpf); - return; - } - rpf->fcxp = fcxp; - - len = fc_rpsc2_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rport->pid, - bfa_fcs_port_get_fcid(port), &rport->pid, 1); - - bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, - FC_CLASS_3, len, &fchs, bfa_fcs_rpf_rpsc2_response, - rpf, FC_MAX_PDUSZ, FC_ELS_TOV); - rport->stats.rpsc_sent++; - bfa_sm_send_event(rpf, RPFSM_EVENT_FCXP_SENT); - -} - -static void -bfa_fcs_rpf_rpsc2_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg, - bfa_status_t req_status, u32 rsp_len, - u32 resid_len, struct fchs_s *rsp_fchs) -{ - struct bfa_fcs_rpf_s *rpf = (struct bfa_fcs_rpf_s *) cbarg; - struct bfa_fcs_rport_s *rport = rpf->rport; - struct fc_ls_rjt_s *ls_rjt; - struct fc_rpsc2_acc_s *rpsc2_acc; - u16 num_ents; - - bfa_trc(rport->fcs, req_status); - - if (req_status != BFA_STATUS_OK) { - bfa_trc(rport->fcs, req_status); - if (req_status == BFA_STATUS_ETIMER) - rport->stats.rpsc_failed++; - bfa_sm_send_event(rpf, RPFSM_EVENT_RPSC_ERROR); - return; - } - - rpsc2_acc = (struct fc_rpsc2_acc_s *) BFA_FCXP_RSP_PLD(fcxp); - if (rpsc2_acc->els_cmd == FC_ELS_ACC) { - rport->stats.rpsc_accs++; - num_ents = bfa_os_ntohs(rpsc2_acc->num_pids); - bfa_trc(rport->fcs, num_ents); - if (num_ents > 0) { - bfa_assert(rpsc2_acc->port_info[0].pid != rport->pid); - bfa_trc(rport->fcs, - bfa_os_ntohs(rpsc2_acc->port_info[0].pid)); - bfa_trc(rport->fcs, - bfa_os_ntohs(rpsc2_acc->port_info[0].speed)); - bfa_trc(rport->fcs, - bfa_os_ntohs(rpsc2_acc->port_info[0].index)); - bfa_trc(rport->fcs, - rpsc2_acc->port_info[0].type); - - if (rpsc2_acc->port_info[0].speed == 0) { - bfa_sm_send_event(rpf, RPFSM_EVENT_RPSC_ERROR); - return; - } - - rpf->rpsc_speed = fc_rpsc_operspeed_to_bfa_speed( - bfa_os_ntohs(rpsc2_acc->port_info[0].speed)); - - bfa_sm_send_event(rpf, RPFSM_EVENT_RPSC_COMP); - } - } else { - ls_rjt = (struct fc_ls_rjt_s *) BFA_FCXP_RSP_PLD(fcxp); - bfa_trc(rport->fcs, ls_rjt->reason_code); - bfa_trc(rport->fcs, ls_rjt->reason_code_expl); - rport->stats.rpsc_rejects++; - if (ls_rjt->reason_code == FC_LS_RJT_RSN_CMD_NOT_SUPP) - bfa_sm_send_event(rpf, RPFSM_EVENT_RPSC_FAIL); - else - bfa_sm_send_event(rpf, RPFSM_EVENT_RPSC_ERROR); - } -} diff --git a/drivers/scsi/bfa/scn.c b/drivers/scsi/bfa/scn.c deleted file mode 100644 index 8a60129e6307..000000000000 --- a/drivers/scsi/bfa/scn.c +++ /dev/null @@ -1,482 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#include <bfa.h> -#include <bfa_svc.h> -#include "fcs_lport.h" -#include "fcs_rport.h" -#include "fcs_ms.h" -#include "fcs_trcmod.h" -#include "fcs_fcxp.h" -#include "fcs.h" -#include "lport_priv.h" - -BFA_TRC_FILE(FCS, SCN); - -#define FC_QOS_RSCN_EVENT 0x0c -#define FC_FABRIC_NAME_RSCN_EVENT 0x0d - -/* - * forward declarations - */ -static void bfa_fcs_port_scn_send_scr(void *scn_cbarg, - struct bfa_fcxp_s *fcxp_alloced); -static void bfa_fcs_port_scn_scr_response(void *fcsarg, - struct bfa_fcxp_s *fcxp, - void *cbarg, - bfa_status_t req_status, - u32 rsp_len, - u32 resid_len, - struct fchs_s *rsp_fchs); -static void bfa_fcs_port_scn_send_ls_acc(struct bfa_fcs_port_s *port, - struct fchs_s *rx_fchs); -static void bfa_fcs_port_scn_timeout(void *arg); - -/** - * fcs_scm_sm FCS SCN state machine - */ - -/** - * VPort SCN State Machine events - */ -enum port_scn_event { - SCNSM_EVENT_PORT_ONLINE = 1, - SCNSM_EVENT_PORT_OFFLINE = 2, - SCNSM_EVENT_RSP_OK = 3, - SCNSM_EVENT_RSP_ERROR = 4, - SCNSM_EVENT_TIMEOUT = 5, - SCNSM_EVENT_SCR_SENT = 6, -}; - -static void bfa_fcs_port_scn_sm_offline(struct bfa_fcs_port_scn_s *scn, - enum port_scn_event event); -static void bfa_fcs_port_scn_sm_sending_scr(struct bfa_fcs_port_scn_s *scn, - enum port_scn_event event); -static void bfa_fcs_port_scn_sm_scr(struct bfa_fcs_port_scn_s *scn, - enum port_scn_event event); -static void bfa_fcs_port_scn_sm_scr_retry(struct bfa_fcs_port_scn_s *scn, - enum port_scn_event event); -static void bfa_fcs_port_scn_sm_online(struct bfa_fcs_port_scn_s *scn, - enum port_scn_event event); - -/** - * Starting state - awaiting link up. - */ -static void -bfa_fcs_port_scn_sm_offline(struct bfa_fcs_port_scn_s *scn, - enum port_scn_event event) -{ - switch (event) { - case SCNSM_EVENT_PORT_ONLINE: - bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_sending_scr); - bfa_fcs_port_scn_send_scr(scn, NULL); - break; - - case SCNSM_EVENT_PORT_OFFLINE: - break; - - default: - bfa_sm_fault(scn->port->fcs, event); - } -} - -static void -bfa_fcs_port_scn_sm_sending_scr(struct bfa_fcs_port_scn_s *scn, - enum port_scn_event event) -{ - switch (event) { - case SCNSM_EVENT_SCR_SENT: - bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_scr); - break; - - case SCNSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_offline); - bfa_fcxp_walloc_cancel(scn->port->fcs->bfa, &scn->fcxp_wqe); - break; - - default: - bfa_sm_fault(scn->port->fcs, event); - } -} - -static void -bfa_fcs_port_scn_sm_scr(struct bfa_fcs_port_scn_s *scn, - enum port_scn_event event) -{ - struct bfa_fcs_port_s *port = scn->port; - - switch (event) { - case SCNSM_EVENT_RSP_OK: - bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_online); - break; - - case SCNSM_EVENT_RSP_ERROR: - bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_scr_retry); - bfa_timer_start(port->fcs->bfa, &scn->timer, - bfa_fcs_port_scn_timeout, scn, - BFA_FCS_RETRY_TIMEOUT); - break; - - case SCNSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_offline); - bfa_fcxp_discard(scn->fcxp); - break; - - default: - bfa_sm_fault(scn->port->fcs, event); - } -} - -static void -bfa_fcs_port_scn_sm_scr_retry(struct bfa_fcs_port_scn_s *scn, - enum port_scn_event event) -{ - switch (event) { - case SCNSM_EVENT_TIMEOUT: - bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_sending_scr); - bfa_fcs_port_scn_send_scr(scn, NULL); - break; - - case SCNSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_offline); - bfa_timer_stop(&scn->timer); - break; - - default: - bfa_sm_fault(scn->port->fcs, event); - } -} - -static void -bfa_fcs_port_scn_sm_online(struct bfa_fcs_port_scn_s *scn, - enum port_scn_event event) -{ - switch (event) { - case SCNSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_offline); - break; - - default: - bfa_sm_fault(scn->port->fcs, event); - } -} - - - -/** - * fcs_scn_private FCS SCN private functions - */ - -/** - * This routine will be called to send a SCR command. - */ -static void -bfa_fcs_port_scn_send_scr(void *scn_cbarg, struct bfa_fcxp_s *fcxp_alloced) -{ - struct bfa_fcs_port_scn_s *scn = scn_cbarg; - struct bfa_fcs_port_s *port = scn->port; - struct fchs_s fchs; - int len; - struct bfa_fcxp_s *fcxp; - - bfa_trc(port->fcs, port->pid); - bfa_trc(port->fcs, port->port_cfg.pwwn); - - fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); - if (!fcxp) { - bfa_fcxp_alloc_wait(port->fcs->bfa, &scn->fcxp_wqe, - bfa_fcs_port_scn_send_scr, scn); - return; - } - scn->fcxp = fcxp; - - /* - * Handle VU registrations for Base port only - */ - if ((!port->vport) && bfa_ioc_get_fcmode(&port->fcs->bfa->ioc)) { - len = fc_scr_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), - bfa_lps_is_brcd_fabric(port->fabric->lps), - port->pid, 0); - } else { - len = fc_scr_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), BFA_FALSE, - port->pid, 0); - } - - bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, - FC_CLASS_3, len, &fchs, bfa_fcs_port_scn_scr_response, - (void *)scn, FC_MAX_PDUSZ, FC_ELS_TOV); - - bfa_sm_send_event(scn, SCNSM_EVENT_SCR_SENT); -} - -static void -bfa_fcs_port_scn_scr_response(void *fcsarg, struct bfa_fcxp_s *fcxp, - void *cbarg, bfa_status_t req_status, - u32 rsp_len, u32 resid_len, - struct fchs_s *rsp_fchs) -{ - struct bfa_fcs_port_scn_s *scn = (struct bfa_fcs_port_scn_s *)cbarg; - struct bfa_fcs_port_s *port = scn->port; - struct fc_els_cmd_s *els_cmd; - struct fc_ls_rjt_s *ls_rjt; - - bfa_trc(port->fcs, port->port_cfg.pwwn); - - /* - * Sanity Checks - */ - if (req_status != BFA_STATUS_OK) { - bfa_trc(port->fcs, req_status); - bfa_sm_send_event(scn, SCNSM_EVENT_RSP_ERROR); - return; - } - - els_cmd = (struct fc_els_cmd_s *) BFA_FCXP_RSP_PLD(fcxp); - - switch (els_cmd->els_code) { - - case FC_ELS_ACC: - bfa_sm_send_event(scn, SCNSM_EVENT_RSP_OK); - break; - - case FC_ELS_LS_RJT: - - ls_rjt = (struct fc_ls_rjt_s *) BFA_FCXP_RSP_PLD(fcxp); - - bfa_trc(port->fcs, ls_rjt->reason_code); - bfa_trc(port->fcs, ls_rjt->reason_code_expl); - - bfa_sm_send_event(scn, SCNSM_EVENT_RSP_ERROR); - break; - - default: - bfa_sm_send_event(scn, SCNSM_EVENT_RSP_ERROR); - } -} - -/* - * Send a LS Accept - */ -static void -bfa_fcs_port_scn_send_ls_acc(struct bfa_fcs_port_s *port, - struct fchs_s *rx_fchs) -{ - struct fchs_s fchs; - struct bfa_fcxp_s *fcxp; - struct bfa_rport_s *bfa_rport = NULL; - int len; - - bfa_trc(port->fcs, rx_fchs->s_id); - - fcxp = bfa_fcs_fcxp_alloc(port->fcs); - if (!fcxp) - return; - - len = fc_ls_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rx_fchs->s_id, - bfa_fcs_port_get_fcid(port), rx_fchs->ox_id); - - bfa_fcxp_send(fcxp, bfa_rport, port->fabric->vf_id, port->lp_tag, - BFA_FALSE, FC_CLASS_3, len, &fchs, NULL, NULL, - FC_MAX_PDUSZ, 0); -} - -/** - * This routine will be called by bfa_timer on timer timeouts. - * - * param[in] vport - pointer to bfa_fcs_port_t. - * param[out] vport_status - pointer to return vport status in - * - * return - * void - * -* Special Considerations: - * - * note - */ -static void -bfa_fcs_port_scn_timeout(void *arg) -{ - struct bfa_fcs_port_scn_s *scn = (struct bfa_fcs_port_scn_s *)arg; - - bfa_sm_send_event(scn, SCNSM_EVENT_TIMEOUT); -} - - - -/** - * fcs_scn_public FCS state change notification public interfaces - */ - -/* - * Functions called by port/fab - */ -void -bfa_fcs_port_scn_init(struct bfa_fcs_port_s *port) -{ - struct bfa_fcs_port_scn_s *scn = BFA_FCS_GET_SCN_FROM_PORT(port); - - scn->port = port; - bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_offline); -} - -void -bfa_fcs_port_scn_offline(struct bfa_fcs_port_s *port) -{ - struct bfa_fcs_port_scn_s *scn = BFA_FCS_GET_SCN_FROM_PORT(port); - - scn->port = port; - bfa_sm_send_event(scn, SCNSM_EVENT_PORT_OFFLINE); -} - -void -bfa_fcs_port_scn_online(struct bfa_fcs_port_s *port) -{ - struct bfa_fcs_port_scn_s *scn = BFA_FCS_GET_SCN_FROM_PORT(port); - - scn->port = port; - bfa_sm_send_event(scn, SCNSM_EVENT_PORT_ONLINE); -} - -static void -bfa_fcs_port_scn_portid_rscn(struct bfa_fcs_port_s *port, u32 rpid) -{ - struct bfa_fcs_rport_s *rport; - - bfa_trc(port->fcs, rpid); - - /** - * If this is an unknown device, then it just came online. - * Otherwise let rport handle the RSCN event. - */ - rport = bfa_fcs_port_get_rport_by_pid(port, rpid); - if (rport == NULL) { - /* - * If min cfg mode is enabled, we donot need to - * discover any new rports. - */ - if (!__fcs_min_cfg(port->fcs)) - rport = bfa_fcs_rport_create(port, rpid); - } else { - bfa_fcs_rport_scn(rport); - } -} - -/** - * rscn format based PID comparison - */ -#define __fc_pid_match(__c0, __c1, __fmt) \ - (((__fmt) == FC_RSCN_FORMAT_FABRIC) || \ - (((__fmt) == FC_RSCN_FORMAT_DOMAIN) && \ - ((__c0)[0] == (__c1)[0])) || \ - (((__fmt) == FC_RSCN_FORMAT_AREA) && \ - ((__c0)[0] == (__c1)[0]) && \ - ((__c0)[1] == (__c1)[1]))) - -static void -bfa_fcs_port_scn_multiport_rscn(struct bfa_fcs_port_s *port, - enum fc_rscn_format format, u32 rscn_pid) -{ - struct bfa_fcs_rport_s *rport; - struct list_head *qe, *qe_next; - u8 *c0, *c1; - - bfa_trc(port->fcs, format); - bfa_trc(port->fcs, rscn_pid); - - c0 = (u8 *) &rscn_pid; - - list_for_each_safe(qe, qe_next, &port->rport_q) { - rport = (struct bfa_fcs_rport_s *)qe; - c1 = (u8 *) &rport->pid; - if (__fc_pid_match(c0, c1, format)) - bfa_fcs_rport_scn(rport); - } -} - -void -bfa_fcs_port_scn_process_rscn(struct bfa_fcs_port_s *port, struct fchs_s *fchs, - u32 len) -{ - struct fc_rscn_pl_s *rscn = (struct fc_rscn_pl_s *) (fchs + 1); - int num_entries; - u32 rscn_pid; - bfa_boolean_t nsquery = BFA_FALSE; - int i = 0; - - num_entries = - (bfa_os_ntohs(rscn->payldlen) - - sizeof(u32)) / sizeof(rscn->event[0]); - - bfa_trc(port->fcs, num_entries); - - port->stats.num_rscn++; - - bfa_fcs_port_scn_send_ls_acc(port, fchs); - - for (i = 0; i < num_entries; i++) { - rscn_pid = rscn->event[i].portid; - - bfa_trc(port->fcs, rscn->event[i].format); - bfa_trc(port->fcs, rscn_pid); - - switch (rscn->event[i].format) { - case FC_RSCN_FORMAT_PORTID: - if (rscn->event[i].qualifier == FC_QOS_RSCN_EVENT) { - /* - * Ignore this event. f/w would have processed - * it - */ - bfa_trc(port->fcs, rscn_pid); - } else { - port->stats.num_portid_rscn++; - bfa_fcs_port_scn_portid_rscn(port, rscn_pid); - } - break; - - case FC_RSCN_FORMAT_FABRIC: - if (rscn->event[i].qualifier == - FC_FABRIC_NAME_RSCN_EVENT) { - bfa_fcs_port_ms_fabric_rscn(port); - break; - } - /* - * !!!!!!!!! Fall Through !!!!!!!!!!!!! - */ - - case FC_RSCN_FORMAT_AREA: - case FC_RSCN_FORMAT_DOMAIN: - nsquery = BFA_TRUE; - bfa_fcs_port_scn_multiport_rscn(port, - rscn->event[i].format, - rscn_pid); - break; - - default: - bfa_assert(0); - nsquery = BFA_TRUE; - } - } - - /** - * If any of area, domain or fabric RSCN is received, do a fresh discovery - * to find new devices. - */ - if (nsquery) - bfa_fcs_port_ns_query(port); -} - - diff --git a/drivers/scsi/bfa/vfapi.c b/drivers/scsi/bfa/vfapi.c deleted file mode 100644 index 391a4790bebd..000000000000 --- a/drivers/scsi/bfa/vfapi.c +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/** - * vfapi.c Fabric module implementation. - */ - -#include "fcs_fabric.h" -#include "fcs_trcmod.h" - -BFA_TRC_FILE(FCS, VFAPI); - -/** - * fcs_vf_api virtual fabrics API - */ - -/** - * Enable VF mode. - * - * @param[in] fcs fcs module instance - * @param[in] vf_id default vf_id of port, FC_VF_ID_NULL - * to use standard default vf_id of 1. - * - * @retval BFA_STATUS_OK vf mode is enabled - * @retval BFA_STATUS_BUSY Port is active. Port must be disabled - * before VF mode can be enabled. - */ -bfa_status_t -bfa_fcs_vf_mode_enable(struct bfa_fcs_s *fcs, u16 vf_id) -{ - return BFA_STATUS_OK; -} - -/** - * Disable VF mode. - * - * @param[in] fcs fcs module instance - * - * @retval BFA_STATUS_OK vf mode is disabled - * @retval BFA_STATUS_BUSY VFs are present and being used. All - * VFs must be deleted before disabling - * VF mode. - */ -bfa_status_t -bfa_fcs_vf_mode_disable(struct bfa_fcs_s *fcs) -{ - return BFA_STATUS_OK; -} - -/** - * Create a new VF instance. - * - * A new VF is created using the given VF configuration. A VF is identified - * by VF id. No duplicate VF creation is allowed with the same VF id. Once - * a VF is created, VF is automatically started after link initialization - * and EVFP exchange is completed. - * - * param[in] vf - FCS vf data structure. Memory is - * allocated by caller (driver) - * param[in] fcs - FCS module - * param[in] vf_cfg - VF configuration - * param[in] vf_drv - Opaque handle back to the driver's - * virtual vf structure - * - * retval BFA_STATUS_OK VF creation is successful - * retval BFA_STATUS_FAILED VF creation failed - * retval BFA_STATUS_EEXIST A VF exists with the given vf_id - */ -bfa_status_t -bfa_fcs_vf_create(bfa_fcs_vf_t *vf, struct bfa_fcs_s *fcs, u16 vf_id, - struct bfa_port_cfg_s *port_cfg, struct bfad_vf_s *vf_drv) -{ - bfa_trc(fcs, vf_id); - return BFA_STATUS_OK; -} - -/** - * Use this function to delete a BFA VF object. VF object should - * be stopped before this function call. - * - * param[in] vf - pointer to bfa_vf_t. - * - * retval BFA_STATUS_OK On vf deletion success - * retval BFA_STATUS_BUSY VF is not in a stopped state - * retval BFA_STATUS_INPROGRESS VF deletion in in progress - */ -bfa_status_t -bfa_fcs_vf_delete(bfa_fcs_vf_t *vf) -{ - bfa_trc(vf->fcs, vf->vf_id); - return BFA_STATUS_OK; -} - -/** - * Start participation in VF. This triggers login to the virtual fabric. - * - * param[in] vf - pointer to bfa_vf_t. - * - * return None - */ -void -bfa_fcs_vf_start(bfa_fcs_vf_t *vf) -{ - bfa_trc(vf->fcs, vf->vf_id); -} - -/** - * Logout with the virtual fabric. - * - * param[in] vf - pointer to bfa_vf_t. - * - * retval BFA_STATUS_OK On success. - * retval BFA_STATUS_INPROGRESS VF is being stopped. - */ -bfa_status_t -bfa_fcs_vf_stop(bfa_fcs_vf_t *vf) -{ - bfa_trc(vf->fcs, vf->vf_id); - return BFA_STATUS_OK; -} - -/** - * Returns attributes of the given VF. - * - * param[in] vf pointer to bfa_vf_t. - * param[out] vf_attr vf attributes returned - * - * return None - */ -void -bfa_fcs_vf_get_attr(bfa_fcs_vf_t *vf, struct bfa_vf_attr_s *vf_attr) -{ - bfa_trc(vf->fcs, vf->vf_id); -} - -/** - * Return statistics associated with the given vf. - * - * param[in] vf pointer to bfa_vf_t. - * param[out] vf_stats vf statistics returned - * - * @return None - */ -void -bfa_fcs_vf_get_stats(bfa_fcs_vf_t *vf, struct bfa_vf_stats_s *vf_stats) -{ - bfa_os_memcpy(vf_stats, &vf->stats, sizeof(struct bfa_vf_stats_s)); - return; -} - -void -/** - * clear statistics associated with the given vf. - * - * param[in] vf pointer to bfa_vf_t. - * - * @return None - */ -bfa_fcs_vf_clear_stats(bfa_fcs_vf_t *vf) -{ - bfa_os_memset(&vf->stats, 0, sizeof(struct bfa_vf_stats_s)); - return; -} - -/** - * Returns FCS vf structure for a given vf_id. - * - * param[in] vf_id - VF_ID - * - * return - * If lookup succeeds, retuns fcs vf object, otherwise returns NULL - */ -bfa_fcs_vf_t * -bfa_fcs_vf_lookup(struct bfa_fcs_s *fcs, u16 vf_id) -{ - bfa_trc(fcs, vf_id); - if (vf_id == FC_VF_ID_NULL) - return &fcs->fabric; - - /** - * @todo vf support - */ - - return NULL; -} - -/** - * Returns driver VF structure for a given FCS vf. - * - * param[in] vf - pointer to bfa_vf_t - * - * return Driver VF structure - */ -struct bfad_vf_s * -bfa_fcs_vf_get_drv_vf(bfa_fcs_vf_t *vf) -{ - bfa_assert(vf); - bfa_trc(vf->fcs, vf->vf_id); - return vf->vf_drv; -} - -/** - * Return the list of VFs configured. - * - * param[in] fcs fcs module instance - * param[out] vf_ids returned list of vf_ids - * param[in,out] nvfs in:size of vf_ids array, - * out:total elements present, - * actual elements returned is limited by the size - * - * return Driver VF structure - */ -void -bfa_fcs_vf_list(struct bfa_fcs_s *fcs, u16 *vf_ids, int *nvfs) -{ - bfa_trc(fcs, *nvfs); -} - -/** - * Return the list of all VFs visible from fabric. - * - * param[in] fcs fcs module instance - * param[out] vf_ids returned list of vf_ids - * param[in,out] nvfs in:size of vf_ids array, - * out:total elements present, - * actual elements returned is limited by the size - * - * return Driver VF structure - */ -void -bfa_fcs_vf_list_all(struct bfa_fcs_s *fcs, u16 *vf_ids, int *nvfs) -{ - bfa_trc(fcs, *nvfs); -} - -/** - * Return the list of local logical ports present in the given VF. - * - * param[in] vf vf for which logical ports are returned - * param[out] lpwwn returned logical port wwn list - * param[in,out] nlports in:size of lpwwn list; - * out:total elements present, - * actual elements returned is limited by the size - * - */ -void -bfa_fcs_vf_get_ports(bfa_fcs_vf_t *vf, wwn_t lpwwn[], int *nlports) -{ - struct list_head *qe; - struct bfa_fcs_vport_s *vport; - int i; - struct bfa_fcs_s *fcs; - - if (vf == NULL || lpwwn == NULL || *nlports == 0) - return; - - fcs = vf->fcs; - - bfa_trc(fcs, vf->vf_id); - bfa_trc(fcs, (u32) *nlports); - - i = 0; - lpwwn[i++] = vf->bport.port_cfg.pwwn; - - list_for_each(qe, &vf->vport_q) { - if (i >= *nlports) - break; - - vport = (struct bfa_fcs_vport_s *) qe; - lpwwn[i++] = vport->lport.port_cfg.pwwn; - } - - bfa_trc(fcs, i); - *nlports = i; - return; -} - - diff --git a/drivers/scsi/bfa/vport.c b/drivers/scsi/bfa/vport.c deleted file mode 100644 index b378ec79d386..000000000000 --- a/drivers/scsi/bfa/vport.c +++ /dev/null @@ -1,903 +0,0 @@ -/* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/** - * bfa_fcs_vport.c FCS virtual port state machine - */ - -#include <bfa.h> -#include <bfa_svc.h> -#include <fcbuild.h> -#include "fcs_fabric.h" -#include "fcs_lport.h" -#include "fcs_vport.h" -#include "fcs_trcmod.h" -#include "fcs.h" -#include <aen/bfa_aen_lport.h> - -BFA_TRC_FILE(FCS, VPORT); - -#define __vport_fcs(__vp) ((__vp)->lport.fcs) -#define __vport_pwwn(__vp) ((__vp)->lport.port_cfg.pwwn) -#define __vport_nwwn(__vp) ((__vp)->lport.port_cfg.nwwn) -#define __vport_bfa(__vp) ((__vp)->lport.fcs->bfa) -#define __vport_fcid(__vp) ((__vp)->lport.pid) -#define __vport_fabric(__vp) ((__vp)->lport.fabric) -#define __vport_vfid(__vp) ((__vp)->lport.fabric->vf_id) - -#define BFA_FCS_VPORT_MAX_RETRIES 5 -/* - * Forward declarations - */ -static void bfa_fcs_vport_do_fdisc(struct bfa_fcs_vport_s *vport); -static void bfa_fcs_vport_timeout(void *vport_arg); -static void bfa_fcs_vport_do_logo(struct bfa_fcs_vport_s *vport); -static void bfa_fcs_vport_free(struct bfa_fcs_vport_s *vport); - -/** - * fcs_vport_sm FCS virtual port state machine - */ - -/** - * VPort State Machine events - */ -enum bfa_fcs_vport_event { - BFA_FCS_VPORT_SM_CREATE = 1, /* vport create event */ - BFA_FCS_VPORT_SM_DELETE = 2, /* vport delete event */ - BFA_FCS_VPORT_SM_START = 3, /* vport start request */ - BFA_FCS_VPORT_SM_STOP = 4, /* stop: unsupported */ - BFA_FCS_VPORT_SM_ONLINE = 5, /* fabric online */ - BFA_FCS_VPORT_SM_OFFLINE = 6, /* fabric offline event */ - BFA_FCS_VPORT_SM_FRMSENT = 7, /* fdisc/logo sent events */ - BFA_FCS_VPORT_SM_RSP_OK = 8, /* good response */ - BFA_FCS_VPORT_SM_RSP_ERROR = 9, /* error/bad response */ - BFA_FCS_VPORT_SM_TIMEOUT = 10, /* delay timer event */ - BFA_FCS_VPORT_SM_DELCOMP = 11, /* lport delete completion */ - BFA_FCS_VPORT_SM_RSP_DUP_WWN = 12, /* Dup wnn error */ - BFA_FCS_VPORT_SM_RSP_FAILED = 13, /* non-retryable failure */ -}; - -static void bfa_fcs_vport_sm_uninit(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event); -static void bfa_fcs_vport_sm_created(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event); -static void bfa_fcs_vport_sm_offline(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event); -static void bfa_fcs_vport_sm_fdisc(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event); -static void bfa_fcs_vport_sm_fdisc_retry(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event); -static void bfa_fcs_vport_sm_online(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event); -static void bfa_fcs_vport_sm_deleting(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event); -static void bfa_fcs_vport_sm_cleanup(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event); -static void bfa_fcs_vport_sm_logo(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event); -static void bfa_fcs_vport_sm_error(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event); - -static struct bfa_sm_table_s vport_sm_table[] = { - {BFA_SM(bfa_fcs_vport_sm_uninit), BFA_FCS_VPORT_UNINIT}, - {BFA_SM(bfa_fcs_vport_sm_created), BFA_FCS_VPORT_CREATED}, - {BFA_SM(bfa_fcs_vport_sm_offline), BFA_FCS_VPORT_OFFLINE}, - {BFA_SM(bfa_fcs_vport_sm_fdisc), BFA_FCS_VPORT_FDISC}, - {BFA_SM(bfa_fcs_vport_sm_fdisc_retry), BFA_FCS_VPORT_FDISC_RETRY}, - {BFA_SM(bfa_fcs_vport_sm_online), BFA_FCS_VPORT_ONLINE}, - {BFA_SM(bfa_fcs_vport_sm_deleting), BFA_FCS_VPORT_DELETING}, - {BFA_SM(bfa_fcs_vport_sm_cleanup), BFA_FCS_VPORT_CLEANUP}, - {BFA_SM(bfa_fcs_vport_sm_logo), BFA_FCS_VPORT_LOGO}, - {BFA_SM(bfa_fcs_vport_sm_error), BFA_FCS_VPORT_ERROR} -}; - -/** - * Beginning state. - */ -static void -bfa_fcs_vport_sm_uninit(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event) -{ - bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); - bfa_trc(__vport_fcs(vport), event); - - switch (event) { - case BFA_FCS_VPORT_SM_CREATE: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_created); - bfa_fcs_fabric_addvport(__vport_fabric(vport), vport); - break; - - default: - bfa_sm_fault(__vport_fcs(vport), event); - } -} - -/** - * Created state - a start event is required to start up the state machine. - */ -static void -bfa_fcs_vport_sm_created(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event) -{ - bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); - bfa_trc(__vport_fcs(vport), event); - - switch (event) { - case BFA_FCS_VPORT_SM_START: - if (bfa_fcs_fabric_is_online(__vport_fabric(vport)) - && bfa_fcs_fabric_npiv_capable(__vport_fabric(vport))) { - bfa_sm_set_state(vport, bfa_fcs_vport_sm_fdisc); - bfa_fcs_vport_do_fdisc(vport); - } else { - /** - * Fabric is offline or not NPIV capable, stay in - * offline state. - */ - vport->vport_stats.fab_no_npiv++; - bfa_sm_set_state(vport, bfa_fcs_vport_sm_offline); - } - break; - - case BFA_FCS_VPORT_SM_DELETE: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_cleanup); - bfa_fcs_port_delete(&vport->lport); - break; - - case BFA_FCS_VPORT_SM_ONLINE: - case BFA_FCS_VPORT_SM_OFFLINE: - /** - * Ignore ONLINE/OFFLINE events from fabric till vport is started. - */ - break; - - default: - bfa_sm_fault(__vport_fcs(vport), event); - } -} - -/** - * Offline state - awaiting ONLINE event from fabric SM. - */ -static void -bfa_fcs_vport_sm_offline(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event) -{ - bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); - bfa_trc(__vport_fcs(vport), event); - - switch (event) { - case BFA_FCS_VPORT_SM_DELETE: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_cleanup); - bfa_fcs_port_delete(&vport->lport); - break; - - case BFA_FCS_VPORT_SM_ONLINE: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_fdisc); - vport->fdisc_retries = 0; - bfa_fcs_vport_do_fdisc(vport); - break; - - case BFA_FCS_VPORT_SM_OFFLINE: - /* - * This can happen if the vport couldn't be initialzied due - * the fact that the npiv was not enabled on the switch. In - * that case we will put the vport in offline state. However, - * the link can go down and cause the this event to be sent when - * we are already offline. Ignore it. - */ - break; - - default: - bfa_sm_fault(__vport_fcs(vport), event); - } -} - -/** - * FDISC is sent and awaiting reply from fabric. - */ -static void -bfa_fcs_vport_sm_fdisc(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event) -{ - bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); - bfa_trc(__vport_fcs(vport), event); - - switch (event) { - case BFA_FCS_VPORT_SM_DELETE: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_cleanup); - bfa_lps_discard(vport->lps); - bfa_fcs_port_delete(&vport->lport); - break; - - case BFA_FCS_VPORT_SM_OFFLINE: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_offline); - bfa_lps_discard(vport->lps); - break; - - case BFA_FCS_VPORT_SM_RSP_OK: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_online); - bfa_fcs_port_online(&vport->lport); - break; - - case BFA_FCS_VPORT_SM_RSP_ERROR: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_fdisc_retry); - bfa_timer_start(__vport_bfa(vport), &vport->timer, - bfa_fcs_vport_timeout, vport, - BFA_FCS_RETRY_TIMEOUT); - break; - - case BFA_FCS_VPORT_SM_RSP_FAILED: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_offline); - break; - - case BFA_FCS_VPORT_SM_RSP_DUP_WWN: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_error); - break; - - default: - bfa_sm_fault(__vport_fcs(vport), event); - } -} - -/** - * FDISC attempt failed - a timer is active to retry FDISC. - */ -static void -bfa_fcs_vport_sm_fdisc_retry(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event) -{ - bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); - bfa_trc(__vport_fcs(vport), event); - - switch (event) { - case BFA_FCS_VPORT_SM_DELETE: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_cleanup); - bfa_timer_stop(&vport->timer); - bfa_fcs_port_delete(&vport->lport); - break; - - case BFA_FCS_VPORT_SM_OFFLINE: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_offline); - bfa_timer_stop(&vport->timer); - break; - - case BFA_FCS_VPORT_SM_TIMEOUT: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_fdisc); - vport->vport_stats.fdisc_retries++; - vport->fdisc_retries++; - bfa_fcs_vport_do_fdisc(vport); - break; - - default: - bfa_sm_fault(__vport_fcs(vport), event); - } -} - -/** - * Vport is online (FDISC is complete). - */ -static void -bfa_fcs_vport_sm_online(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event) -{ - bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); - bfa_trc(__vport_fcs(vport), event); - - switch (event) { - case BFA_FCS_VPORT_SM_DELETE: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_deleting); - bfa_fcs_port_delete(&vport->lport); - break; - - case BFA_FCS_VPORT_SM_OFFLINE: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_offline); - bfa_lps_discard(vport->lps); - bfa_fcs_port_offline(&vport->lport); - break; - - default: - bfa_sm_fault(__vport_fcs(vport), event); - } -} - -/** - * Vport is being deleted - awaiting lport delete completion to send - * LOGO to fabric. - */ -static void -bfa_fcs_vport_sm_deleting(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event) -{ - bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); - bfa_trc(__vport_fcs(vport), event); - - switch (event) { - case BFA_FCS_VPORT_SM_DELETE: - break; - - case BFA_FCS_VPORT_SM_DELCOMP: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_logo); - bfa_fcs_vport_do_logo(vport); - break; - - case BFA_FCS_VPORT_SM_OFFLINE: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_cleanup); - break; - - default: - bfa_sm_fault(__vport_fcs(vport), event); - } -} - -/** - * Error State. - * This state will be set when the Vport Creation fails due to errors like - * Dup WWN. In this state only operation allowed is a Vport Delete. - */ -static void -bfa_fcs_vport_sm_error(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event) -{ - bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); - bfa_trc(__vport_fcs(vport), event); - - switch (event) { - case BFA_FCS_VPORT_SM_DELETE: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_cleanup); - bfa_fcs_port_delete(&vport->lport); - - break; - - default: - bfa_trc(__vport_fcs(vport), event); - } -} - -/** - * Lport cleanup is in progress since vport is being deleted. Fabric is - * offline, so no LOGO is needed to complete vport deletion. - */ -static void -bfa_fcs_vport_sm_cleanup(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event) -{ - bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); - bfa_trc(__vport_fcs(vport), event); - - switch (event) { - case BFA_FCS_VPORT_SM_DELCOMP: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_uninit); - bfa_fcs_vport_free(vport); - break; - - case BFA_FCS_VPORT_SM_DELETE: - break; - - default: - bfa_sm_fault(__vport_fcs(vport), event); - } -} - -/** - * LOGO is sent to fabric. Vport delete is in progress. Lport delete cleanup - * is done. - */ -static void -bfa_fcs_vport_sm_logo(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event) -{ - bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); - bfa_trc(__vport_fcs(vport), event); - - switch (event) { - case BFA_FCS_VPORT_SM_OFFLINE: - bfa_lps_discard(vport->lps); - /* - * !!! fall through !!! - */ - - case BFA_FCS_VPORT_SM_RSP_OK: - case BFA_FCS_VPORT_SM_RSP_ERROR: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_uninit); - bfa_fcs_vport_free(vport); - break; - - case BFA_FCS_VPORT_SM_DELETE: - break; - - default: - bfa_sm_fault(__vport_fcs(vport), event); - } -} - - - -/** - * fcs_vport_private FCS virtual port private functions - */ - -/** - * Send AEN notification - */ -static void -bfa_fcs_vport_aen_post(bfa_fcs_lport_t *port, enum bfa_lport_aen_event event) -{ - union bfa_aen_data_u aen_data; - struct bfa_log_mod_s *logmod = port->fcs->logm; - enum bfa_port_role role = port->port_cfg.roles; - wwn_t lpwwn = bfa_fcs_port_get_pwwn(port); - char lpwwn_ptr[BFA_STRING_32]; - char *role_str[BFA_PORT_ROLE_FCP_MAX / 2 + 1] = - { "Initiator", "Target", "IPFC" }; - - wwn2str(lpwwn_ptr, lpwwn); - - bfa_assert(role <= BFA_PORT_ROLE_FCP_MAX); - - bfa_log(logmod, BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, event), lpwwn_ptr, - role_str[role/2]); - - aen_data.lport.vf_id = port->fabric->vf_id; - aen_data.lport.roles = role; - aen_data.lport.ppwwn = - bfa_fcs_port_get_pwwn(bfa_fcs_get_base_port(port->fcs)); - aen_data.lport.lpwwn = lpwwn; -} - -/** - * This routine will be called to send a FDISC command. - */ -static void -bfa_fcs_vport_do_fdisc(struct bfa_fcs_vport_s *vport) -{ - bfa_lps_fdisc(vport->lps, vport, - bfa_fcport_get_maxfrsize(__vport_bfa(vport)), - __vport_pwwn(vport), __vport_nwwn(vport)); - vport->vport_stats.fdisc_sent++; -} - -static void -bfa_fcs_vport_fdisc_rejected(struct bfa_fcs_vport_s *vport) -{ - u8 lsrjt_rsn = bfa_lps_get_lsrjt_rsn(vport->lps); - u8 lsrjt_expl = bfa_lps_get_lsrjt_expl(vport->lps); - - bfa_trc(__vport_fcs(vport), lsrjt_rsn); - bfa_trc(__vport_fcs(vport), lsrjt_expl); - - /* - * For certain reason codes, we don't want to retry. - */ - switch (bfa_lps_get_lsrjt_expl(vport->lps)) { - case FC_LS_RJT_EXP_INV_PORT_NAME: /* by brocade */ - case FC_LS_RJT_EXP_INVALID_NPORT_ID: /* by Cisco */ - if (vport->fdisc_retries < BFA_FCS_VPORT_MAX_RETRIES) - bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_ERROR); - else { - bfa_fcs_vport_aen_post(&vport->lport, - BFA_LPORT_AEN_NPIV_DUP_WWN); - bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_DUP_WWN); - } - break; - - case FC_LS_RJT_EXP_INSUFF_RES: - /* - * This means max logins per port/switch setting on the - * switch was exceeded. - */ - if (vport->fdisc_retries < BFA_FCS_VPORT_MAX_RETRIES) - bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_ERROR); - else { - bfa_fcs_vport_aen_post(&vport->lport, - BFA_LPORT_AEN_NPIV_FABRIC_MAX); - bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_FAILED); - } - break; - - default: - if (vport->fdisc_retries == 0) /* Print only once */ - bfa_fcs_vport_aen_post(&vport->lport, - BFA_LPORT_AEN_NPIV_UNKNOWN); - bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_ERROR); - } -} - -/** - * Called to send a logout to the fabric. Used when a V-Port is - * deleted/stopped. - */ -static void -bfa_fcs_vport_do_logo(struct bfa_fcs_vport_s *vport) -{ - bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); - - vport->vport_stats.logo_sent++; - bfa_lps_fdisclogo(vport->lps); -} - -/** - * This routine will be called by bfa_timer on timer timeouts. - * - * param[in] vport - pointer to bfa_fcs_vport_t. - * param[out] vport_status - pointer to return vport status in - * - * return - * void - * -* Special Considerations: - * - * note - */ -static void -bfa_fcs_vport_timeout(void *vport_arg) -{ - struct bfa_fcs_vport_s *vport = (struct bfa_fcs_vport_s *)vport_arg; - - vport->vport_stats.fdisc_timeouts++; - bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_TIMEOUT); -} - -static void -bfa_fcs_vport_free(struct bfa_fcs_vport_s *vport) -{ - bfa_fcs_fabric_delvport(__vport_fabric(vport), vport); - bfa_fcb_vport_delete(vport->vport_drv); - bfa_lps_delete(vport->lps); -} - - - -/** - * fcs_vport_public FCS virtual port public interfaces - */ - -/** - * Online notification from fabric SM. - */ -void -bfa_fcs_vport_online(struct bfa_fcs_vport_s *vport) -{ - vport->vport_stats.fab_online++; - bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_ONLINE); -} - -/** - * Offline notification from fabric SM. - */ -void -bfa_fcs_vport_offline(struct bfa_fcs_vport_s *vport) -{ - vport->vport_stats.fab_offline++; - bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_OFFLINE); -} - -/** - * Cleanup notification from fabric SM on link timer expiry. - */ -void -bfa_fcs_vport_cleanup(struct bfa_fcs_vport_s *vport) -{ - vport->vport_stats.fab_cleanup++; -} - -/** - * delete 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 - */ -void -bfa_fcs_vport_delete_comp(struct bfa_fcs_vport_s *vport) -{ - bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_DELCOMP); -} - -/** - * fcs_vport_api Virtual port API - */ - -/** - * Use this function to instantiate a new FCS vport object. This - * function will not trigger any HW initialization process (which will be - * done in vport_start() call) - * - * param[in] vport - pointer to bfa_fcs_vport_t. This space - * needs to be allocated by the driver. - * param[in] fcs - FCS instance - * param[in] vport_cfg - vport configuration - * param[in] vf_id - VF_ID if vport is created within a VF. - * FC_VF_ID_NULL to specify base fabric. - * param[in] vport_drv - Opaque handle back to the driver's vport - * structure - * - * retval BFA_STATUS_OK - on success. - * retval BFA_STATUS_FAILED - on failure. - */ -bfa_status_t -bfa_fcs_vport_create(struct bfa_fcs_vport_s *vport, struct bfa_fcs_s *fcs, - u16 vf_id, struct bfa_port_cfg_s *vport_cfg, - struct bfad_vport_s *vport_drv) -{ - if (vport_cfg->pwwn == 0) - return BFA_STATUS_INVALID_WWN; - - if (bfa_fcs_port_get_pwwn(&fcs->fabric.bport) == vport_cfg->pwwn) - return BFA_STATUS_VPORT_WWN_BP; - - if (bfa_fcs_vport_lookup(fcs, vf_id, vport_cfg->pwwn) != NULL) - return BFA_STATUS_VPORT_EXISTS; - - if (bfa_fcs_fabric_vport_count(&fcs->fabric) == - bfa_lps_get_max_vport(fcs->bfa)) - return BFA_STATUS_VPORT_MAX; - - vport->lps = bfa_lps_alloc(fcs->bfa); - if (!vport->lps) - return BFA_STATUS_VPORT_MAX; - - vport->vport_drv = vport_drv; - 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); - bfa_fcs_lport_init(&vport->lport, vport_cfg); - - bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_CREATE); - - 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. - * - * @param[in] vport - pointer to bfa_fcs_vport_t. - * - * @returns None - */ -bfa_status_t -bfa_fcs_vport_start(struct bfa_fcs_vport_s *vport) -{ - bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_START); - - return BFA_STATUS_OK; -} - -/** - * Use this function quiese the vport object. This function will return - * immediately, when the vport is actually stopped, the - * bfa_drv_vport_stop_cb() will be called. - * - * param[in] vport - pointer to bfa_fcs_vport_t. - * - * return None - */ -bfa_status_t -bfa_fcs_vport_stop(struct bfa_fcs_vport_s *vport) -{ - bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_STOP); - - return BFA_STATUS_OK; -} - -/** - * Use this function to delete a vport object. Fabric object should - * be stopped before this function call. - * - * Donot invoke this from within FCS - * - * param[in] vport - pointer to bfa_fcs_vport_t. - * - * return None - */ -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; -} - -/** - * Use this function to get vport's current status info. - * - * param[in] vport pointer to bfa_fcs_vport_t. - * param[out] attr pointer to return vport attributes - * - * return None - */ -void -bfa_fcs_vport_get_attr(struct bfa_fcs_vport_s *vport, - struct bfa_vport_attr_s *attr) -{ - if (vport == NULL || attr == NULL) - return; - - bfa_os_memset(attr, 0, sizeof(struct bfa_vport_attr_s)); - - bfa_fcs_port_get_attr(&vport->lport, &attr->port_attr); - attr->vport_state = bfa_sm_to_state(vport_sm_table, vport->sm); -} - -/** - * Use this function to get vport's statistics. - * - * param[in] vport pointer to bfa_fcs_vport_t. - * param[out] stats pointer to return vport statistics in - * - * return None - */ -void -bfa_fcs_vport_get_stats(struct bfa_fcs_vport_s *vport, - struct bfa_vport_stats_s *stats) -{ - *stats = vport->vport_stats; -} - -/** - * Use this function to clear vport's statistics. - * - * param[in] vport pointer to bfa_fcs_vport_t. - * - * return None - */ -void -bfa_fcs_vport_clr_stats(struct bfa_fcs_vport_s *vport) -{ - bfa_os_memset(&vport->vport_stats, 0, sizeof(struct bfa_vport_stats_s)); -} - -/** - * Lookup a virtual port. Excludes base port from lookup. - */ -struct bfa_fcs_vport_s * -bfa_fcs_vport_lookup(struct bfa_fcs_s *fcs, u16 vf_id, wwn_t vpwwn) -{ - struct bfa_fcs_vport_s *vport; - struct bfa_fcs_fabric_s *fabric; - - bfa_trc(fcs, vf_id); - bfa_trc(fcs, vpwwn); - - fabric = bfa_fcs_vf_lookup(fcs, vf_id); - if (!fabric) { - bfa_trc(fcs, vf_id); - return NULL; - } - - vport = bfa_fcs_fabric_vport_lookup(fabric, vpwwn); - return vport; -} - -/** - * FDISC Response - */ -void -bfa_cb_lps_fdisc_comp(void *bfad, void *uarg, bfa_status_t status) -{ - struct bfa_fcs_vport_s *vport = uarg; - - bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); - bfa_trc(__vport_fcs(vport), status); - - switch (status) { - case BFA_STATUS_OK: - /* - * Initialize the V-Port fields - */ - __vport_fcid(vport) = bfa_lps_get_pid(vport->lps); - vport->vport_stats.fdisc_accepts++; - bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_OK); - break; - - case BFA_STATUS_INVALID_MAC: - /* - * Only for CNA - */ - vport->vport_stats.fdisc_acc_bad++; - bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_ERROR); - - break; - - case BFA_STATUS_EPROTOCOL: - switch (bfa_lps_get_extstatus(vport->lps)) { - case BFA_EPROTO_BAD_ACCEPT: - vport->vport_stats.fdisc_acc_bad++; - break; - - case BFA_EPROTO_UNKNOWN_RSP: - vport->vport_stats.fdisc_unknown_rsp++; - break; - - default: - break; - } - - bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_ERROR); - break; - - case BFA_STATUS_FABRIC_RJT: - vport->vport_stats.fdisc_rejects++; - bfa_fcs_vport_fdisc_rejected(vport); - break; - - default: - vport->vport_stats.fdisc_rsp_err++; - bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_ERROR); - } -} - -/** - * LOGO response - */ -void -bfa_cb_lps_fdisclogo_comp(void *bfad, void *uarg) -{ - struct bfa_fcs_vport_s *vport = uarg; - bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_OK); -} - -/** - * Received clear virtual link - */ -void -bfa_cb_lps_cvl_event(void *bfad, void *uarg) -{ - struct bfa_fcs_vport_s *vport = uarg; - - /* Send an Offline followed by an ONLINE */ - bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_OFFLINE); - bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_ONLINE); -} diff --git a/drivers/scsi/bnx2i/bnx2i.h b/drivers/scsi/bnx2i/bnx2i.h index 00c033511cbf..b6345d91bb66 100644 --- a/drivers/scsi/bnx2i/bnx2i.h +++ b/drivers/scsi/bnx2i/bnx2i.h @@ -753,7 +753,7 @@ extern int bnx2i_send_iscsi_tmf(struct bnx2i_conn *conn, extern int bnx2i_send_iscsi_scsicmd(struct bnx2i_conn *conn, struct bnx2i_cmd *cmnd); extern int bnx2i_send_iscsi_nopout(struct bnx2i_conn *conn, - struct iscsi_task *mtask, u32 ttt, + struct iscsi_task *mtask, char *datap, int data_len, int unsol); extern int bnx2i_send_iscsi_logout(struct bnx2i_conn *conn, struct iscsi_task *mtask); diff --git a/drivers/scsi/bnx2i/bnx2i_hwi.c b/drivers/scsi/bnx2i/bnx2i_hwi.c index d23fc256d585..90cef716b796 100644 --- a/drivers/scsi/bnx2i/bnx2i_hwi.c +++ b/drivers/scsi/bnx2i/bnx2i_hwi.c @@ -385,7 +385,6 @@ int bnx2i_send_iscsi_tmf(struct bnx2i_conn *bnx2i_conn, struct bnx2i_cmd *bnx2i_cmd; struct bnx2i_tmf_request *tmfabort_wqe; u32 dword; - u32 scsi_lun[2]; bnx2i_cmd = (struct bnx2i_cmd *)mtask->dd_data; tmfabort_hdr = (struct iscsi_tm *)mtask->hdr; @@ -393,38 +392,41 @@ int bnx2i_send_iscsi_tmf(struct bnx2i_conn *bnx2i_conn, bnx2i_conn->ep->qp.sq_prod_qe; tmfabort_wqe->op_code = tmfabort_hdr->opcode; - tmfabort_wqe->op_attr = 0; - tmfabort_wqe->op_attr = - ISCSI_TMF_REQUEST_ALWAYS_ONE | ISCSI_TM_FUNC_ABORT_TASK; + tmfabort_wqe->op_attr = tmfabort_hdr->flags; tmfabort_wqe->itt = (mtask->itt | (ISCSI_TASK_TYPE_MPATH << 14)); tmfabort_wqe->reserved2 = 0; tmfabort_wqe->cmd_sn = be32_to_cpu(tmfabort_hdr->cmdsn); - ctask = iscsi_itt_to_task(conn, tmfabort_hdr->rtt); - if (!ctask || !ctask->sc) - /* - * the iscsi layer must have completed the cmd while this - * was starting up. - * - * Note: In the case of a SCSI cmd timeout, the task's sc - * is still active; hence ctask->sc != 0 - * In this case, the task must be aborted - */ - return 0; - - ref_sc = ctask->sc; - - /* Retrieve LUN directly from the ref_sc */ - int_to_scsilun(ref_sc->device->lun, (struct scsi_lun *) scsi_lun); - tmfabort_wqe->lun[0] = be32_to_cpu(scsi_lun[0]); - tmfabort_wqe->lun[1] = be32_to_cpu(scsi_lun[1]); - - if (ref_sc->sc_data_direction == DMA_TO_DEVICE) - dword = (ISCSI_TASK_TYPE_WRITE << ISCSI_CMD_REQUEST_TYPE_SHIFT); - else - dword = (ISCSI_TASK_TYPE_READ << ISCSI_CMD_REQUEST_TYPE_SHIFT); - tmfabort_wqe->ref_itt = (dword | (tmfabort_hdr->rtt & ISCSI_ITT_MASK)); + switch (tmfabort_hdr->flags & ISCSI_FLAG_TM_FUNC_MASK) { + case ISCSI_TM_FUNC_ABORT_TASK: + case ISCSI_TM_FUNC_TASK_REASSIGN: + ctask = iscsi_itt_to_task(conn, tmfabort_hdr->rtt); + if (!ctask || !ctask->sc) + /* + * the iscsi layer must have completed the cmd while + * was starting up. + * + * Note: In the case of a SCSI cmd timeout, the task's + * sc is still active; hence ctask->sc != 0 + * In this case, the task must be aborted + */ + return 0; + + ref_sc = ctask->sc; + if (ref_sc->sc_data_direction == DMA_TO_DEVICE) + dword = (ISCSI_TASK_TYPE_WRITE << + ISCSI_CMD_REQUEST_TYPE_SHIFT); + else + dword = (ISCSI_TASK_TYPE_READ << + ISCSI_CMD_REQUEST_TYPE_SHIFT); + tmfabort_wqe->ref_itt = (dword | + (tmfabort_hdr->rtt & ISCSI_ITT_MASK)); + break; + default: + tmfabort_wqe->ref_itt = RESERVED_ITT; + } + memcpy(tmfabort_wqe->lun, tmfabort_hdr->lun, sizeof(struct scsi_lun)); tmfabort_wqe->ref_cmd_sn = be32_to_cpu(tmfabort_hdr->refcmdsn); tmfabort_wqe->bd_list_addr_lo = (u32) bnx2i_conn->hba->mp_bd_dma; @@ -464,7 +466,6 @@ int bnx2i_send_iscsi_scsicmd(struct bnx2i_conn *bnx2i_conn, * @conn: iscsi connection * @cmd: driver command structure which is requesting * a WQE to sent to chip for further processing - * @ttt: TTT to be used when building pdu header * @datap: payload buffer pointer * @data_len: payload data length * @unsol: indicated whether nopout pdu is unsolicited pdu or @@ -473,7 +474,7 @@ int bnx2i_send_iscsi_scsicmd(struct bnx2i_conn *bnx2i_conn, * prepare and post a nopout request WQE to CNIC firmware */ int bnx2i_send_iscsi_nopout(struct bnx2i_conn *bnx2i_conn, - struct iscsi_task *task, u32 ttt, + struct iscsi_task *task, char *datap, int data_len, int unsol) { struct bnx2i_endpoint *ep = bnx2i_conn->ep; @@ -498,7 +499,7 @@ int bnx2i_send_iscsi_nopout(struct bnx2i_conn *bnx2i_conn, nopout_wqe->itt = ((u16)task->itt | (ISCSI_TASK_TYPE_MPATH << ISCSI_TMF_REQUEST_TYPE_SHIFT)); - nopout_wqe->ttt = ttt; + nopout_wqe->ttt = nopout_hdr->ttt; nopout_wqe->flags = 0; if (!unsol) nopout_wqe->flags = ISCSI_NOP_OUT_REQUEST_LOCAL_COMPLETION; diff --git a/drivers/scsi/bnx2i/bnx2i_init.c b/drivers/scsi/bnx2i/bnx2i_init.c index a796f565f383..50c2aa3b8eb1 100644 --- a/drivers/scsi/bnx2i/bnx2i_init.c +++ b/drivers/scsi/bnx2i/bnx2i_init.c @@ -17,15 +17,17 @@ 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.2" -#define DRV_MODULE_RELDATE "Jun 28, 2010" +#define DRV_MODULE_VERSION "2.1.3" +#define DRV_MODULE_RELDATE "Aug 10, 2010" static char version[] __devinitdata = "Broadcom NetXtreme II iSCSI Driver " DRV_MODULE_NAME \ " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; -MODULE_AUTHOR("Anil Veerabhadrappa <anilgv@broadcom.com>"); +MODULE_AUTHOR("Anil Veerabhadrappa <anilgv@broadcom.com> and " + "Eddie Wai <eddie.wai@broadcom.com>"); + MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706/5708/5709/57710/57711" " iSCSI Driver"); MODULE_LICENSE("GPL"); @@ -167,6 +169,38 @@ void bnx2i_start(void *handle) /** + * bnx2i_chip_cleanup - local routine to handle chip cleanup + * @hba: Adapter instance to register + * + * Driver checks if adapter still has any active connections before + * executing the cleanup process + */ +static void bnx2i_chip_cleanup(struct bnx2i_hba *hba) +{ + struct bnx2i_endpoint *bnx2i_ep; + struct list_head *pos, *tmp; + + 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: (%s) chip cleanup for %d active " + "connections\n", hba->netdev->name, + 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); + bnx2i_ep->cm_sk = NULL; + } + mutex_unlock(&hba->net_dev_lock); + } +} + + +/** * bnx2i_stop - cnic callback to shutdown adapter instance * @handle: transparent handle pointing to adapter structure * @@ -176,8 +210,6 @@ 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 */ @@ -198,24 +230,7 @@ void bnx2i_stop(void *handle) 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); - } + bnx2i_chip_cleanup(hba); /* This flag should be cleared last so that ep_disconnect() gracefully * cleans up connection context @@ -457,6 +472,7 @@ static void __exit bnx2i_mod_exit(void) adapter_count--; if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) { + bnx2i_chip_cleanup(hba); hba->cnic->unregister_device(hba->cnic, CNIC_ULP_ISCSI); clear_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic); } diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c index a46ccc380ab1..fb50efbce087 100644 --- a/drivers/scsi/bnx2i/bnx2i_iscsi.c +++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c @@ -1078,11 +1078,9 @@ static int bnx2i_iscsi_send_generic_request(struct iscsi_task *task) buf = bnx2i_conn->gen_pdu.req_buf; if (data_len) rc = bnx2i_send_iscsi_nopout(bnx2i_conn, task, - RESERVED_ITT, buf, data_len, 1); else rc = bnx2i_send_iscsi_nopout(bnx2i_conn, task, - RESERVED_ITT, NULL, 0, 1); break; case ISCSI_OP_LOGOUT: @@ -1955,6 +1953,9 @@ int bnx2i_hw_ep_disconnect(struct bnx2i_endpoint *bnx2i_ep) if (!cnic) return 0; + if (bnx2i_ep->state == EP_STATE_IDLE) + return 0; + if (!bnx2i_ep_tcp_conn_active(bnx2i_ep)) goto destroy_conn; @@ -1998,11 +1999,13 @@ int bnx2i_hw_ep_disconnect(struct bnx2i_endpoint *bnx2i_ep) else close_ret = cnic->cm_abort(bnx2i_ep->cm_sk); + /* No longer allow CFC delete if cm_close/abort fails the request */ if (close_ret) - bnx2i_ep->state = EP_STATE_DISCONN_COMPL; - - /* wait for option-2 conn teardown */ - wait_event_interruptible(bnx2i_ep->ofld_wait, + printk(KERN_ALERT "bnx2i: %s close/abort(%d) returned %d\n", + bnx2i_ep->hba->netdev->name, close, close_ret); + else + /* wait for option-2 conn teardown */ + wait_event_interruptible(bnx2i_ep->ofld_wait, bnx2i_ep->state != EP_STATE_DISCONN_START); if (signal_pending(current)) diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c index d6532187f616..a15474eef5f7 100644 --- a/drivers/scsi/ch.c +++ b/drivers/scsi/ch.c @@ -22,7 +22,6 @@ #include <linux/chio.h> /* here are all the ioctls */ #include <linux/mutex.h> #include <linux/idr.h> -#include <linux/smp_lock.h> #include <linux/slab.h> #include <scsi/scsi.h> @@ -44,6 +43,7 @@ MODULE_LICENSE("GPL"); MODULE_ALIAS_CHARDEV_MAJOR(SCSI_CHANGER_MAJOR); MODULE_ALIAS_SCSI_DEVICE(TYPE_MEDIUM_CHANGER); +static DEFINE_MUTEX(ch_mutex); static int init = 1; module_param(init, int, 0444); MODULE_PARM_DESC(init, \ @@ -581,19 +581,19 @@ ch_open(struct inode *inode, struct file *file) scsi_changer *ch; int minor = iminor(inode); - lock_kernel(); + mutex_lock(&ch_mutex); spin_lock(&ch_index_lock); ch = idr_find(&ch_index_idr, minor); if (NULL == ch || scsi_device_get(ch->device)) { spin_unlock(&ch_index_lock); - unlock_kernel(); + mutex_unlock(&ch_mutex); return -ENXIO; } spin_unlock(&ch_index_lock); file->private_data = ch; - unlock_kernel(); + mutex_unlock(&ch_mutex); return 0; } @@ -981,6 +981,7 @@ static const struct file_operations changer_fops = { #ifdef CONFIG_COMPAT .compat_ioctl = ch_ioctl_compat, #endif + .llseek = noop_llseek, }; static int __init init_ch_module(void) diff --git a/drivers/scsi/cxgb3i/cxgb3i.h b/drivers/scsi/cxgb3i/cxgb3i.h deleted file mode 100644 index e3133b58e594..000000000000 --- a/drivers/scsi/cxgb3i/cxgb3i.h +++ /dev/null @@ -1,161 +0,0 @@ -/* - * cxgb3i.h: Chelsio S3xx iSCSI driver. - * - * Copyright (c) 2008 Chelsio Communications, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation. - * - * Written by: Karen Xie (kxie@chelsio.com) - */ - -#ifndef __CXGB3I_H__ -#define __CXGB3I_H__ - -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/errno.h> -#include <linux/types.h> -#include <linux/list.h> -#include <linux/netdevice.h> -#include <linux/scatterlist.h> -#include <linux/skbuff.h> -#include <scsi/libiscsi_tcp.h> - -/* from cxgb3 LLD */ -#include "common.h" -#include "t3_cpl.h" -#include "t3cdev.h" -#include "cxgb3_ctl_defs.h" -#include "cxgb3_offload.h" -#include "firmware_exports.h" - -#include "cxgb3i_offload.h" -#include "cxgb3i_ddp.h" - -#define CXGB3I_SCSI_HOST_QDEPTH 1024 -#define CXGB3I_MAX_TARGET CXGB3I_MAX_CONN -#define CXGB3I_MAX_LUN 512 -#define ISCSI_PDU_NONPAYLOAD_MAX \ - (sizeof(struct iscsi_hdr) + ISCSI_MAX_AHS_SIZE + 2*ISCSI_DIGEST_SIZE) - -struct cxgb3i_adapter; -struct cxgb3i_hba; -struct cxgb3i_endpoint; - -/** - * struct cxgb3i_hba - cxgb3i iscsi structure (per port) - * - * @snic: cxgb3i adapter containing this port - * @ndev: pointer to netdev structure - * @shost: pointer to scsi host structure - */ -struct cxgb3i_hba { - struct cxgb3i_adapter *snic; - struct net_device *ndev; - struct Scsi_Host *shost; -}; - -/** - * struct cxgb3i_adapter - cxgb3i adapter structure (per pci) - * - * @listhead: list head to link elements - * @lock: lock for this structure - * @tdev: pointer to t3cdev used by cxgb3 driver - * @pdev: pointer to pci dev - * @hba_cnt: # of hbas (the same as # of ports) - * @hba: all the hbas on this adapter - * @flags: bit flag for adapter event/status - * @tx_max_size: max. tx packet size supported - * @rx_max_size: max. rx packet size supported - * @tag_format: ddp tag format settings - */ -#define CXGB3I_ADAPTER_FLAG_RESET 0x1 -struct cxgb3i_adapter { - struct list_head list_head; - spinlock_t lock; - struct t3cdev *tdev; - struct pci_dev *pdev; - unsigned char hba_cnt; - struct cxgb3i_hba *hba[MAX_NPORTS]; - - unsigned int flags; - unsigned int tx_max_size; - unsigned int rx_max_size; - - struct cxgb3i_tag_format tag_format; -}; - -/** - * struct cxgb3i_conn - cxgb3i iscsi connection - * - * @listhead: list head to link elements - * @cep: pointer to iscsi_endpoint structure - * @conn: pointer to iscsi_conn structure - * @hba: pointer to the hba this conn. is going through - * @task_idx_bits: # of bits needed for session->cmds_max - */ -struct cxgb3i_conn { - struct list_head list_head; - struct cxgb3i_endpoint *cep; - struct iscsi_conn *conn; - struct cxgb3i_hba *hba; - unsigned int task_idx_bits; -}; - -/** - * struct cxgb3i_endpoint - iscsi tcp endpoint - * - * @c3cn: the h/w tcp connection representation - * @hba: pointer to the hba this conn. is going through - * @cconn: pointer to the associated cxgb3i iscsi connection - */ -struct cxgb3i_endpoint { - struct s3_conn *c3cn; - struct cxgb3i_hba *hba; - struct cxgb3i_conn *cconn; -}; - -/** - * struct cxgb3i_task_data - private iscsi task data - * - * @nr_frags: # of coalesced page frags (from scsi sgl) - * @frags: coalesced page frags (from scsi sgl) - * @skb: tx pdu skb - * @offset: data offset for the next pdu - * @count: max. possible pdu payload - * @sgoffset: offset to the first sg entry for a given offset - */ -#define MAX_PDU_FRAGS ((ULP2_MAX_PDU_PAYLOAD + 512 - 1) / 512) -struct cxgb3i_task_data { - unsigned short nr_frags; - skb_frag_t frags[MAX_PDU_FRAGS]; - struct sk_buff *skb; - unsigned int offset; - unsigned int count; - unsigned int sgoffset; -}; - -int cxgb3i_iscsi_init(void); -void cxgb3i_iscsi_cleanup(void); - -struct cxgb3i_adapter *cxgb3i_adapter_find_by_tdev(struct t3cdev *); -void cxgb3i_adapter_open(struct t3cdev *); -void cxgb3i_adapter_close(struct t3cdev *); - -struct cxgb3i_hba *cxgb3i_hba_host_add(struct cxgb3i_adapter *, - struct net_device *); -void cxgb3i_hba_host_remove(struct cxgb3i_hba *); - -int cxgb3i_pdu_init(void); -void cxgb3i_pdu_cleanup(void); -void cxgb3i_conn_cleanup_task(struct iscsi_task *); -int cxgb3i_conn_alloc_pdu(struct iscsi_task *, u8); -int cxgb3i_conn_init_pdu(struct iscsi_task *, unsigned int, unsigned int); -int cxgb3i_conn_xmit_pdu(struct iscsi_task *); - -void cxgb3i_release_itt(struct iscsi_task *task, itt_t hdr_itt); -int cxgb3i_reserve_itt(struct iscsi_task *task, itt_t *hdr_itt); - -#endif diff --git a/drivers/scsi/cxgb3i/cxgb3i_ddp.c b/drivers/scsi/cxgb3i/cxgb3i_ddp.c deleted file mode 100644 index be0e23042c76..000000000000 --- a/drivers/scsi/cxgb3i/cxgb3i_ddp.c +++ /dev/null @@ -1,773 +0,0 @@ -/* - * cxgb3i_ddp.c: Chelsio S3xx iSCSI DDP Manager. - * - * Copyright (c) 2008 Chelsio Communications, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation. - * - * Written by: Karen Xie (kxie@chelsio.com) - */ - -#include <linux/slab.h> -#include <linux/skbuff.h> -#include <linux/scatterlist.h> - -/* from cxgb3 LLD */ -#include "common.h" -#include "t3_cpl.h" -#include "t3cdev.h" -#include "cxgb3_ctl_defs.h" -#include "cxgb3_offload.h" -#include "firmware_exports.h" - -#include "cxgb3i_ddp.h" - -#define ddp_log_error(fmt...) printk(KERN_ERR "cxgb3i_ddp: ERR! " fmt) -#define ddp_log_warn(fmt...) printk(KERN_WARNING "cxgb3i_ddp: WARN! " fmt) -#define ddp_log_info(fmt...) printk(KERN_INFO "cxgb3i_ddp: " fmt) - -#ifdef __DEBUG_CXGB3I_DDP__ -#define ddp_log_debug(fmt, args...) \ - printk(KERN_INFO "cxgb3i_ddp: %s - " fmt, __func__ , ## args) -#else -#define ddp_log_debug(fmt...) -#endif - -/* - * iSCSI Direct Data Placement - * - * T3 h/w can directly place the iSCSI Data-In or Data-Out PDU's payload into - * pre-posted final destination host-memory buffers based on the Initiator - * Task Tag (ITT) in Data-In or Target Task Tag (TTT) in Data-Out PDUs. - * - * The host memory address is programmed into h/w in the format of pagepod - * entries. - * The location of the pagepod entry is encoded into ddp tag which is used or - * is the base for ITT/TTT. - */ - -#define DDP_PGIDX_MAX 4 -#define DDP_THRESHOLD 2048 -static unsigned char ddp_page_order[DDP_PGIDX_MAX] = {0, 1, 2, 4}; -static unsigned char ddp_page_shift[DDP_PGIDX_MAX] = {12, 13, 14, 16}; -static unsigned char page_idx = DDP_PGIDX_MAX; - -/* - * functions to program the pagepod in h/w - */ -static inline void ulp_mem_io_set_hdr(struct sk_buff *skb, unsigned int addr) -{ - struct ulp_mem_io *req = (struct ulp_mem_io *)skb->head; - - req->wr.wr_lo = 0; - req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_BYPASS)); - req->cmd_lock_addr = htonl(V_ULP_MEMIO_ADDR(addr >> 5) | - V_ULPTX_CMD(ULP_MEM_WRITE)); - req->len = htonl(V_ULP_MEMIO_DATA_LEN(PPOD_SIZE >> 5) | - V_ULPTX_NFLITS((PPOD_SIZE >> 3) + 1)); -} - -static int set_ddp_map(struct cxgb3i_ddp_info *ddp, struct pagepod_hdr *hdr, - unsigned int idx, unsigned int npods, - struct cxgb3i_gather_list *gl) -{ - unsigned int pm_addr = (idx << PPOD_SIZE_SHIFT) + ddp->llimit; - int i; - - for (i = 0; i < npods; i++, idx++, pm_addr += PPOD_SIZE) { - struct sk_buff *skb = ddp->gl_skb[idx]; - struct pagepod *ppod; - int j, pidx; - - /* hold on to the skb until we clear the ddp mapping */ - skb_get(skb); - - ulp_mem_io_set_hdr(skb, pm_addr); - ppod = (struct pagepod *) - (skb->head + sizeof(struct ulp_mem_io)); - memcpy(&(ppod->hdr), hdr, sizeof(struct pagepod)); - for (pidx = 4 * i, j = 0; j < 5; ++j, ++pidx) - ppod->addr[j] = pidx < gl->nelem ? - cpu_to_be64(gl->phys_addr[pidx]) : 0UL; - - skb->priority = CPL_PRIORITY_CONTROL; - cxgb3_ofld_send(ddp->tdev, skb); - } - return 0; -} - -static void clear_ddp_map(struct cxgb3i_ddp_info *ddp, unsigned int tag, - unsigned int idx, unsigned int npods) -{ - unsigned int pm_addr = (idx << PPOD_SIZE_SHIFT) + ddp->llimit; - int i; - - for (i = 0; i < npods; i++, idx++, pm_addr += PPOD_SIZE) { - struct sk_buff *skb = ddp->gl_skb[idx]; - - if (!skb) { - ddp_log_error("ddp tag 0x%x, 0x%x, %d/%u, skb NULL.\n", - tag, idx, i, npods); - continue; - } - ddp->gl_skb[idx] = NULL; - memset((skb->head + sizeof(struct ulp_mem_io)), 0, PPOD_SIZE); - ulp_mem_io_set_hdr(skb, pm_addr); - skb->priority = CPL_PRIORITY_CONTROL; - cxgb3_ofld_send(ddp->tdev, skb); - } -} - -static inline int ddp_find_unused_entries(struct cxgb3i_ddp_info *ddp, - unsigned int start, unsigned int max, - unsigned int count, - struct cxgb3i_gather_list *gl) -{ - unsigned int i, j, k; - - /* not enough entries */ - if ((max - start) < count) - return -EBUSY; - - max -= count; - spin_lock(&ddp->map_lock); - for (i = start; i < max;) { - for (j = 0, k = i; j < count; j++, k++) { - if (ddp->gl_map[k]) - break; - } - if (j == count) { - for (j = 0, k = i; j < count; j++, k++) - ddp->gl_map[k] = gl; - spin_unlock(&ddp->map_lock); - return i; - } - i += j + 1; - } - spin_unlock(&ddp->map_lock); - return -EBUSY; -} - -static inline void ddp_unmark_entries(struct cxgb3i_ddp_info *ddp, - int start, int count) -{ - spin_lock(&ddp->map_lock); - memset(&ddp->gl_map[start], 0, - count * sizeof(struct cxgb3i_gather_list *)); - spin_unlock(&ddp->map_lock); -} - -static inline void ddp_free_gl_skb(struct cxgb3i_ddp_info *ddp, - int idx, int count) -{ - int i; - - for (i = 0; i < count; i++, idx++) - if (ddp->gl_skb[idx]) { - kfree_skb(ddp->gl_skb[idx]); - ddp->gl_skb[idx] = NULL; - } -} - -static inline int ddp_alloc_gl_skb(struct cxgb3i_ddp_info *ddp, int idx, - int count, gfp_t gfp) -{ - int i; - - for (i = 0; i < count; i++) { - struct sk_buff *skb = alloc_skb(sizeof(struct ulp_mem_io) + - PPOD_SIZE, gfp); - if (skb) { - ddp->gl_skb[idx + i] = skb; - skb_put(skb, sizeof(struct ulp_mem_io) + PPOD_SIZE); - } else { - ddp_free_gl_skb(ddp, idx, i); - return -ENOMEM; - } - } - return 0; -} - -/** - * cxgb3i_ddp_find_page_index - return ddp page index for a given page size - * @pgsz: page size - * return the ddp page index, if no match is found return DDP_PGIDX_MAX. - */ -int cxgb3i_ddp_find_page_index(unsigned long pgsz) -{ - int i; - - for (i = 0; i < DDP_PGIDX_MAX; i++) { - if (pgsz == (1UL << ddp_page_shift[i])) - return i; - } - ddp_log_debug("ddp page size 0x%lx not supported.\n", pgsz); - return DDP_PGIDX_MAX; -} - -/** - * cxgb3i_ddp_adjust_page_table - adjust page table with PAGE_SIZE - * return the ddp page index, if no match is found return DDP_PGIDX_MAX. - */ -int cxgb3i_ddp_adjust_page_table(void) -{ - int i; - unsigned int base_order, order; - - if (PAGE_SIZE < (1UL << ddp_page_shift[0])) { - ddp_log_info("PAGE_SIZE 0x%lx too small, min. 0x%lx.\n", - PAGE_SIZE, 1UL << ddp_page_shift[0]); - return -EINVAL; - } - - base_order = get_order(1UL << ddp_page_shift[0]); - order = get_order(1 << PAGE_SHIFT); - for (i = 0; i < DDP_PGIDX_MAX; i++) { - /* first is the kernel page size, then just doubling the size */ - ddp_page_order[i] = order - base_order + i; - ddp_page_shift[i] = PAGE_SHIFT + i; - } - return 0; -} - -static inline void ddp_gl_unmap(struct pci_dev *pdev, - struct cxgb3i_gather_list *gl) -{ - int i; - - for (i = 0; i < gl->nelem; i++) - pci_unmap_page(pdev, gl->phys_addr[i], PAGE_SIZE, - PCI_DMA_FROMDEVICE); -} - -static inline int ddp_gl_map(struct pci_dev *pdev, - struct cxgb3i_gather_list *gl) -{ - int i; - - for (i = 0; i < gl->nelem; i++) { - gl->phys_addr[i] = pci_map_page(pdev, gl->pages[i], 0, - PAGE_SIZE, - PCI_DMA_FROMDEVICE); - if (unlikely(pci_dma_mapping_error(pdev, gl->phys_addr[i]))) - goto unmap; - } - - return i; - -unmap: - if (i) { - unsigned int nelem = gl->nelem; - - gl->nelem = i; - ddp_gl_unmap(pdev, gl); - gl->nelem = nelem; - } - return -ENOMEM; -} - -/** - * cxgb3i_ddp_make_gl - build ddp page buffer list - * @xferlen: total buffer length - * @sgl: page buffer scatter-gather list - * @sgcnt: # of page buffers - * @pdev: pci_dev, used for pci map - * @gfp: allocation mode - * - * construct a ddp page buffer list from the scsi scattergather list. - * coalesce buffers as much as possible, and obtain dma addresses for - * each page. - * - * Return the cxgb3i_gather_list constructed from the page buffers if the - * memory can be used for ddp. Return NULL otherwise. - */ -struct cxgb3i_gather_list *cxgb3i_ddp_make_gl(unsigned int xferlen, - struct scatterlist *sgl, - unsigned int sgcnt, - struct pci_dev *pdev, - gfp_t gfp) -{ - struct cxgb3i_gather_list *gl; - struct scatterlist *sg = sgl; - struct page *sgpage = sg_page(sg); - unsigned int sglen = sg->length; - unsigned int sgoffset = sg->offset; - unsigned int npages = (xferlen + sgoffset + PAGE_SIZE - 1) >> - PAGE_SHIFT; - int i = 1, j = 0; - - if (xferlen < DDP_THRESHOLD) { - ddp_log_debug("xfer %u < threshold %u, no ddp.\n", - xferlen, DDP_THRESHOLD); - return NULL; - } - - gl = kzalloc(sizeof(struct cxgb3i_gather_list) + - npages * (sizeof(dma_addr_t) + sizeof(struct page *)), - gfp); - if (!gl) - return NULL; - - gl->pages = (struct page **)&gl->phys_addr[npages]; - gl->length = xferlen; - gl->offset = sgoffset; - gl->pages[0] = sgpage; - - sg = sg_next(sg); - while (sg) { - struct page *page = sg_page(sg); - - if (sgpage == page && sg->offset == sgoffset + sglen) - sglen += sg->length; - else { - /* make sure the sgl is fit for ddp: - * each has the same page size, and - * all of the middle pages are used completely - */ - if ((j && sgoffset) || - ((i != sgcnt - 1) && - ((sglen + sgoffset) & ~PAGE_MASK))) - goto error_out; - - j++; - if (j == gl->nelem || sg->offset) - goto error_out; - gl->pages[j] = page; - sglen = sg->length; - sgoffset = sg->offset; - sgpage = page; - } - i++; - sg = sg_next(sg); - } - gl->nelem = ++j; - - if (ddp_gl_map(pdev, gl) < 0) - goto error_out; - - return gl; - -error_out: - kfree(gl); - return NULL; -} - -/** - * cxgb3i_ddp_release_gl - release a page buffer list - * @gl: a ddp page buffer list - * @pdev: pci_dev used for pci_unmap - * free a ddp page buffer list resulted from cxgb3i_ddp_make_gl(). - */ -void cxgb3i_ddp_release_gl(struct cxgb3i_gather_list *gl, - struct pci_dev *pdev) -{ - ddp_gl_unmap(pdev, gl); - kfree(gl); -} - -/** - * cxgb3i_ddp_tag_reserve - set up ddp for a data transfer - * @tdev: t3cdev adapter - * @tid: connection id - * @tformat: tag format - * @tagp: contains s/w tag initially, will be updated with ddp/hw tag - * @gl: the page momory list - * @gfp: allocation mode - * - * ddp setup for a given page buffer list and construct the ddp tag. - * return 0 if success, < 0 otherwise. - */ -int cxgb3i_ddp_tag_reserve(struct t3cdev *tdev, unsigned int tid, - struct cxgb3i_tag_format *tformat, u32 *tagp, - struct cxgb3i_gather_list *gl, gfp_t gfp) -{ - struct cxgb3i_ddp_info *ddp = tdev->ulp_iscsi; - struct pagepod_hdr hdr; - unsigned int npods; - int idx = -1; - int err = -ENOMEM; - u32 sw_tag = *tagp; - u32 tag; - - if (page_idx >= DDP_PGIDX_MAX || !ddp || !gl || !gl->nelem || - gl->length < DDP_THRESHOLD) { - ddp_log_debug("pgidx %u, xfer %u/%u, NO ddp.\n", - page_idx, gl->length, DDP_THRESHOLD); - return -EINVAL; - } - - npods = (gl->nelem + PPOD_PAGES_MAX - 1) >> PPOD_PAGES_SHIFT; - - if (ddp->idx_last == ddp->nppods) - idx = ddp_find_unused_entries(ddp, 0, ddp->nppods, npods, gl); - else { - idx = ddp_find_unused_entries(ddp, ddp->idx_last + 1, - ddp->nppods, npods, gl); - if (idx < 0 && ddp->idx_last >= npods) { - idx = ddp_find_unused_entries(ddp, 0, - min(ddp->idx_last + npods, ddp->nppods), - npods, gl); - } - } - if (idx < 0) { - ddp_log_debug("xferlen %u, gl %u, npods %u NO DDP.\n", - gl->length, gl->nelem, npods); - return idx; - } - - err = ddp_alloc_gl_skb(ddp, idx, npods, gfp); - if (err < 0) - goto unmark_entries; - - tag = cxgb3i_ddp_tag_base(tformat, sw_tag); - tag |= idx << PPOD_IDX_SHIFT; - - hdr.rsvd = 0; - hdr.vld_tid = htonl(F_PPOD_VALID | V_PPOD_TID(tid)); - hdr.pgsz_tag_clr = htonl(tag & ddp->rsvd_tag_mask); - hdr.maxoffset = htonl(gl->length); - hdr.pgoffset = htonl(gl->offset); - - err = set_ddp_map(ddp, &hdr, idx, npods, gl); - if (err < 0) - goto free_gl_skb; - - ddp->idx_last = idx; - ddp_log_debug("xfer %u, gl %u,%u, tid 0x%x, 0x%x -> 0x%x(%u,%u).\n", - gl->length, gl->nelem, gl->offset, tid, sw_tag, tag, - idx, npods); - *tagp = tag; - return 0; - -free_gl_skb: - ddp_free_gl_skb(ddp, idx, npods); -unmark_entries: - ddp_unmark_entries(ddp, idx, npods); - return err; -} - -/** - * cxgb3i_ddp_tag_release - release a ddp tag - * @tdev: t3cdev adapter - * @tag: ddp tag - * ddp cleanup for a given ddp tag and release all the resources held - */ -void cxgb3i_ddp_tag_release(struct t3cdev *tdev, u32 tag) -{ - struct cxgb3i_ddp_info *ddp = tdev->ulp_iscsi; - u32 idx; - - if (!ddp) { - ddp_log_error("release ddp tag 0x%x, ddp NULL.\n", tag); - return; - } - - idx = (tag >> PPOD_IDX_SHIFT) & ddp->idx_mask; - if (idx < ddp->nppods) { - struct cxgb3i_gather_list *gl = ddp->gl_map[idx]; - unsigned int npods; - - if (!gl || !gl->nelem) { - ddp_log_error("release 0x%x, idx 0x%x, gl 0x%p, %u.\n", - tag, idx, gl, gl ? gl->nelem : 0); - return; - } - npods = (gl->nelem + PPOD_PAGES_MAX - 1) >> PPOD_PAGES_SHIFT; - ddp_log_debug("ddp tag 0x%x, release idx 0x%x, npods %u.\n", - tag, idx, npods); - clear_ddp_map(ddp, tag, idx, npods); - ddp_unmark_entries(ddp, idx, npods); - cxgb3i_ddp_release_gl(gl, ddp->pdev); - } else - ddp_log_error("ddp tag 0x%x, idx 0x%x > max 0x%x.\n", - tag, idx, ddp->nppods); -} - -static int setup_conn_pgidx(struct t3cdev *tdev, unsigned int tid, int pg_idx, - int reply) -{ - struct sk_buff *skb = alloc_skb(sizeof(struct cpl_set_tcb_field), - GFP_KERNEL); - struct cpl_set_tcb_field *req; - u64 val = pg_idx < DDP_PGIDX_MAX ? pg_idx : 0; - - if (!skb) - return -ENOMEM; - - /* 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; - req->word = htons(31); - req->mask = cpu_to_be64(0xF0000000); - req->val = cpu_to_be64(val << 28); - skb->priority = CPL_PRIORITY_CONTROL; - - cxgb3_ofld_send(tdev, skb); - return 0; -} - -/** - * cxgb3i_setup_conn_host_pagesize - setup the conn.'s ddp page size - * @tdev: t3cdev adapter - * @tid: connection id - * @reply: request reply from h/w - * set up the ddp page size based on the host PAGE_SIZE for a connection - * identified by tid - */ -int cxgb3i_setup_conn_host_pagesize(struct t3cdev *tdev, unsigned int tid, - int reply) -{ - return setup_conn_pgidx(tdev, tid, page_idx, reply); -} - -/** - * cxgb3i_setup_conn_pagesize - setup the conn.'s ddp page size - * @tdev: t3cdev adapter - * @tid: connection id - * @reply: request reply from h/w - * @pgsz: ddp page size - * set up the ddp page size for a connection identified by tid - */ -int cxgb3i_setup_conn_pagesize(struct t3cdev *tdev, unsigned int tid, - int reply, unsigned long pgsz) -{ - int pgidx = cxgb3i_ddp_find_page_index(pgsz); - - return setup_conn_pgidx(tdev, tid, pgidx, reply); -} - -/** - * cxgb3i_setup_conn_digest - setup conn. digest setting - * @tdev: t3cdev adapter - * @tid: connection id - * @hcrc: header digest enabled - * @dcrc: data digest enabled - * @reply: request reply from h/w - * set up the iscsi digest settings for a connection identified by tid - */ -int cxgb3i_setup_conn_digest(struct t3cdev *tdev, unsigned int tid, - int hcrc, int dcrc, int reply) -{ - struct sk_buff *skb = alloc_skb(sizeof(struct cpl_set_tcb_field), - GFP_KERNEL); - struct cpl_set_tcb_field *req; - u64 val = (hcrc ? 1 : 0) | (dcrc ? 2 : 0); - - if (!skb) - return -ENOMEM; - - /* 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; - req->word = htons(31); - req->mask = cpu_to_be64(0x0F000000); - req->val = cpu_to_be64(val << 24); - skb->priority = CPL_PRIORITY_CONTROL; - - cxgb3_ofld_send(tdev, skb); - return 0; -} - - -/** - * cxgb3i_adapter_ddp_info - read the adapter's ddp information - * @tdev: t3cdev adapter - * @tformat: tag format - * @txsz: max tx pdu payload size, filled in by this func. - * @rxsz: max rx pdu payload size, filled in by this func. - * setup the tag format for a given iscsi entity - */ -int cxgb3i_adapter_ddp_info(struct t3cdev *tdev, - struct cxgb3i_tag_format *tformat, - unsigned int *txsz, unsigned int *rxsz) -{ - struct cxgb3i_ddp_info *ddp; - unsigned char idx_bits; - - if (!tformat) - return -EINVAL; - - if (!tdev->ulp_iscsi) - return -EINVAL; - - ddp = (struct cxgb3i_ddp_info *)tdev->ulp_iscsi; - - idx_bits = 32 - tformat->sw_bits; - tformat->rsvd_bits = ddp->idx_bits; - tformat->rsvd_shift = PPOD_IDX_SHIFT; - tformat->rsvd_mask = (1 << tformat->rsvd_bits) - 1; - - ddp_log_info("tag format: sw %u, rsvd %u,%u, mask 0x%x.\n", - tformat->sw_bits, tformat->rsvd_bits, - tformat->rsvd_shift, tformat->rsvd_mask); - - *txsz = min_t(unsigned int, ULP2_MAX_PDU_PAYLOAD, - ddp->max_txsz - ISCSI_PDU_NONPAYLOAD_LEN); - *rxsz = min_t(unsigned int, ULP2_MAX_PDU_PAYLOAD, - ddp->max_rxsz - ISCSI_PDU_NONPAYLOAD_LEN); - ddp_log_info("max payload size: %u/%u, %u/%u.\n", - *txsz, ddp->max_txsz, *rxsz, ddp->max_rxsz); - return 0; -} - -/** - * cxgb3i_ddp_cleanup - release the cxgb3 adapter's ddp resource - * @tdev: t3cdev adapter - * release all the resource held by the ddp pagepod manager for a given - * adapter if needed - */ - -static void ddp_cleanup(struct kref *kref) -{ - struct cxgb3i_ddp_info *ddp = container_of(kref, - struct cxgb3i_ddp_info, - refcnt); - int i = 0; - - ddp_log_info("kref release ddp 0x%p, t3dev 0x%p.\n", ddp, ddp->tdev); - - ddp->tdev->ulp_iscsi = NULL; - while (i < ddp->nppods) { - struct cxgb3i_gather_list *gl = ddp->gl_map[i]; - if (gl) { - int npods = (gl->nelem + PPOD_PAGES_MAX - 1) - >> PPOD_PAGES_SHIFT; - ddp_log_info("t3dev 0x%p, ddp %d + %d.\n", - ddp->tdev, i, npods); - kfree(gl); - ddp_free_gl_skb(ddp, i, npods); - i += npods; - } else - i++; - } - cxgb3i_free_big_mem(ddp); -} - -void cxgb3i_ddp_cleanup(struct t3cdev *tdev) -{ - struct cxgb3i_ddp_info *ddp = (struct cxgb3i_ddp_info *)tdev->ulp_iscsi; - - ddp_log_info("t3dev 0x%p, release ddp 0x%p.\n", tdev, ddp); - if (ddp) - kref_put(&ddp->refcnt, ddp_cleanup); -} - -/** - * ddp_init - initialize the cxgb3 adapter's ddp resource - * @tdev: t3cdev adapter - * initialize the ddp pagepod manager for a given adapter - */ -static void ddp_init(struct t3cdev *tdev) -{ - struct cxgb3i_ddp_info *ddp = tdev->ulp_iscsi; - struct ulp_iscsi_info uinfo; - unsigned int ppmax, bits; - int i, err; - - if (ddp) { - kref_get(&ddp->refcnt); - ddp_log_warn("t3dev 0x%p, ddp 0x%p already set up.\n", - tdev, tdev->ulp_iscsi); - return; - } - - err = tdev->ctl(tdev, ULP_ISCSI_GET_PARAMS, &uinfo); - if (err < 0) { - ddp_log_error("%s, failed to get iscsi param err=%d.\n", - tdev->name, err); - return; - } - - ppmax = (uinfo.ulimit - uinfo.llimit + 1) >> PPOD_SIZE_SHIFT; - bits = __ilog2_u32(ppmax) + 1; - if (bits > PPOD_IDX_MAX_SIZE) - bits = PPOD_IDX_MAX_SIZE; - ppmax = (1 << (bits - 1)) - 1; - - ddp = cxgb3i_alloc_big_mem(sizeof(struct cxgb3i_ddp_info) + - ppmax * - (sizeof(struct cxgb3i_gather_list *) + - sizeof(struct sk_buff *)), - GFP_KERNEL); - if (!ddp) { - ddp_log_warn("%s unable to alloc ddp 0x%d, ddp disabled.\n", - tdev->name, ppmax); - return; - } - ddp->gl_map = (struct cxgb3i_gather_list **)(ddp + 1); - ddp->gl_skb = (struct sk_buff **)(((char *)ddp->gl_map) + - ppmax * - sizeof(struct cxgb3i_gather_list *)); - spin_lock_init(&ddp->map_lock); - kref_init(&ddp->refcnt); - - ddp->tdev = tdev; - ddp->pdev = uinfo.pdev; - ddp->max_txsz = min_t(unsigned int, uinfo.max_txsz, ULP2_MAX_PKT_SIZE); - ddp->max_rxsz = min_t(unsigned int, uinfo.max_rxsz, ULP2_MAX_PKT_SIZE); - ddp->llimit = uinfo.llimit; - ddp->ulimit = uinfo.ulimit; - ddp->nppods = ppmax; - ddp->idx_last = ppmax; - ddp->idx_bits = bits; - ddp->idx_mask = (1 << bits) - 1; - ddp->rsvd_tag_mask = (1 << (bits + PPOD_IDX_SHIFT)) - 1; - - uinfo.tagmask = ddp->idx_mask << PPOD_IDX_SHIFT; - for (i = 0; i < DDP_PGIDX_MAX; i++) - uinfo.pgsz_factor[i] = ddp_page_order[i]; - uinfo.ulimit = uinfo.llimit + (ppmax << PPOD_SIZE_SHIFT); - - err = tdev->ctl(tdev, ULP_ISCSI_SET_PARAMS, &uinfo); - if (err < 0) { - ddp_log_warn("%s unable to set iscsi param err=%d, " - "ddp disabled.\n", tdev->name, err); - goto free_ddp_map; - } - - tdev->ulp_iscsi = ddp; - - ddp_log_info("tdev 0x%p, nppods %u, bits %u, mask 0x%x,0x%x pkt %u/%u," - " %u/%u.\n", - tdev, ppmax, ddp->idx_bits, ddp->idx_mask, - ddp->rsvd_tag_mask, ddp->max_txsz, uinfo.max_txsz, - ddp->max_rxsz, uinfo.max_rxsz); - return; - -free_ddp_map: - cxgb3i_free_big_mem(ddp); -} - -/** - * cxgb3i_ddp_init - initialize ddp functions - */ -void cxgb3i_ddp_init(struct t3cdev *tdev) -{ - if (page_idx == DDP_PGIDX_MAX) { - page_idx = cxgb3i_ddp_find_page_index(PAGE_SIZE); - - if (page_idx == DDP_PGIDX_MAX) { - ddp_log_info("system PAGE_SIZE %lu, update hw.\n", - PAGE_SIZE); - if (cxgb3i_ddp_adjust_page_table() < 0) { - ddp_log_info("PAGE_SIZE %lu, ddp disabled.\n", - PAGE_SIZE); - return; - } - page_idx = cxgb3i_ddp_find_page_index(PAGE_SIZE); - } - ddp_log_info("system PAGE_SIZE %lu, ddp idx %u.\n", - PAGE_SIZE, page_idx); - } - ddp_init(tdev); -} diff --git a/drivers/scsi/cxgb3i/cxgb3i_ddp.h b/drivers/scsi/cxgb3i/cxgb3i_ddp.h deleted file mode 100644 index 6761b329124d..000000000000 --- a/drivers/scsi/cxgb3i/cxgb3i_ddp.h +++ /dev/null @@ -1,312 +0,0 @@ -/* - * cxgb3i_ddp.h: Chelsio S3xx iSCSI DDP Manager. - * - * Copyright (c) 2008 Chelsio Communications, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation. - * - * Written by: Karen Xie (kxie@chelsio.com) - */ - -#ifndef __CXGB3I_ULP2_DDP_H__ -#define __CXGB3I_ULP2_DDP_H__ - -#include <linux/slab.h> -#include <linux/vmalloc.h> - -/** - * struct cxgb3i_tag_format - cxgb3i ulp tag format for an iscsi entity - * - * @sw_bits: # of bits used by iscsi software layer - * @rsvd_bits: # of bits used by h/w - * @rsvd_shift: h/w bits shift left - * @rsvd_mask: reserved bit mask - */ -struct cxgb3i_tag_format { - unsigned char sw_bits; - unsigned char rsvd_bits; - unsigned char rsvd_shift; - unsigned char filler[1]; - u32 rsvd_mask; -}; - -/** - * struct cxgb3i_gather_list - cxgb3i direct data placement memory - * - * @tag: ddp tag - * @length: total data buffer length - * @offset: initial offset to the 1st page - * @nelem: # of pages - * @pages: page pointers - * @phys_addr: physical address - */ -struct cxgb3i_gather_list { - u32 tag; - unsigned int length; - unsigned int offset; - unsigned int nelem; - struct page **pages; - dma_addr_t phys_addr[0]; -}; - -/** - * struct cxgb3i_ddp_info - cxgb3i direct data placement for pdu payload - * - * @list: list head to link elements - * @refcnt: ref. count - * @tdev: pointer to t3cdev used by cxgb3 driver - * @max_txsz: max tx packet size for ddp - * @max_rxsz: max rx packet size for ddp - * @llimit: lower bound of the page pod memory - * @ulimit: upper bound of the page pod memory - * @nppods: # of page pod entries - * @idx_last: page pod entry last used - * @idx_bits: # of bits the pagepod index would take - * @idx_mask: pagepod index mask - * @rsvd_tag_mask: tag mask - * @map_lock: lock to synchonize access to the page pod map - * @gl_map: ddp memory gather list - * @gl_skb: skb used to program the pagepod - */ -struct cxgb3i_ddp_info { - struct list_head list; - struct kref refcnt; - struct t3cdev *tdev; - struct pci_dev *pdev; - unsigned int max_txsz; - unsigned int max_rxsz; - unsigned int llimit; - unsigned int ulimit; - unsigned int nppods; - unsigned int idx_last; - unsigned char idx_bits; - unsigned char filler[3]; - u32 idx_mask; - u32 rsvd_tag_mask; - spinlock_t map_lock; - struct cxgb3i_gather_list **gl_map; - struct sk_buff **gl_skb; -}; - -#define ISCSI_PDU_NONPAYLOAD_LEN 312 /* bhs(48) + ahs(256) + digest(8) */ -#define ULP2_MAX_PKT_SIZE 16224 -#define ULP2_MAX_PDU_PAYLOAD (ULP2_MAX_PKT_SIZE - ISCSI_PDU_NONPAYLOAD_LEN) -#define PPOD_PAGES_MAX 4 -#define PPOD_PAGES_SHIFT 2 /* 4 pages per pod */ - -/* - * struct pagepod_hdr, pagepod - pagepod format - */ -struct pagepod_hdr { - u32 vld_tid; - u32 pgsz_tag_clr; - u32 maxoffset; - u32 pgoffset; - u64 rsvd; -}; - -struct pagepod { - struct pagepod_hdr hdr; - u64 addr[PPOD_PAGES_MAX + 1]; -}; - -#define PPOD_SIZE sizeof(struct pagepod) /* 64 */ -#define PPOD_SIZE_SHIFT 6 - -#define PPOD_COLOR_SHIFT 0 -#define PPOD_COLOR_SIZE 6 -#define PPOD_COLOR_MASK ((1 << PPOD_COLOR_SIZE) - 1) - -#define PPOD_IDX_SHIFT PPOD_COLOR_SIZE -#define PPOD_IDX_MAX_SIZE 24 - -#define S_PPOD_TID 0 -#define M_PPOD_TID 0xFFFFFF -#define V_PPOD_TID(x) ((x) << S_PPOD_TID) - -#define S_PPOD_VALID 24 -#define V_PPOD_VALID(x) ((x) << S_PPOD_VALID) -#define F_PPOD_VALID V_PPOD_VALID(1U) - -#define S_PPOD_COLOR 0 -#define M_PPOD_COLOR 0x3F -#define V_PPOD_COLOR(x) ((x) << S_PPOD_COLOR) - -#define S_PPOD_TAG 6 -#define M_PPOD_TAG 0xFFFFFF -#define V_PPOD_TAG(x) ((x) << S_PPOD_TAG) - -#define S_PPOD_PGSZ 30 -#define M_PPOD_PGSZ 0x3 -#define V_PPOD_PGSZ(x) ((x) << S_PPOD_PGSZ) - -/* - * large memory chunk allocation/release - * use vmalloc() if kmalloc() fails - */ -static inline void *cxgb3i_alloc_big_mem(unsigned int size, - gfp_t gfp) -{ - void *p = kmalloc(size, gfp); - if (!p) - p = vmalloc(size); - if (p) - memset(p, 0, size); - return p; -} - -static inline void cxgb3i_free_big_mem(void *addr) -{ - if (is_vmalloc_addr(addr)) - vfree(addr); - else - kfree(addr); -} - -/* - * cxgb3i ddp tag are 32 bits, it consists of reserved bits used by h/w and - * non-reserved bits that can be used by the iscsi s/w. - * The reserved bits are identified by the rsvd_bits and rsvd_shift fields - * in struct cxgb3i_tag_format. - * - * The upper most reserved bit can be used to check if a tag is ddp tag or not: - * if the bit is 0, the tag is a valid ddp tag - */ - -/** - * cxgb3i_is_ddp_tag - check if a given tag is a hw/ddp tag - * @tformat: tag format information - * @tag: tag to be checked - * - * return true if the tag is a ddp tag, false otherwise. - */ -static inline int cxgb3i_is_ddp_tag(struct cxgb3i_tag_format *tformat, u32 tag) -{ - return !(tag & (1 << (tformat->rsvd_bits + tformat->rsvd_shift - 1))); -} - -/** - * cxgb3i_sw_tag_usable - check if s/w tag has enough bits left for hw bits - * @tformat: tag format information - * @sw_tag: s/w tag to be checked - * - * return true if the tag can be used for hw ddp tag, false otherwise. - */ -static inline int cxgb3i_sw_tag_usable(struct cxgb3i_tag_format *tformat, - u32 sw_tag) -{ - sw_tag >>= (32 - tformat->rsvd_bits); - return !sw_tag; -} - -/** - * cxgb3i_set_non_ddp_tag - mark a given s/w tag as an invalid ddp tag - * @tformat: tag format information - * @sw_tag: s/w tag to be checked - * - * insert 1 at the upper most reserved bit to mark it as an invalid ddp tag. - */ -static inline u32 cxgb3i_set_non_ddp_tag(struct cxgb3i_tag_format *tformat, - u32 sw_tag) -{ - unsigned char shift = tformat->rsvd_bits + tformat->rsvd_shift - 1; - u32 mask = (1 << shift) - 1; - - if (sw_tag && (sw_tag & ~mask)) { - u32 v1 = sw_tag & ((1 << shift) - 1); - u32 v2 = (sw_tag >> (shift - 1)) << shift; - - return v2 | v1 | 1 << shift; - } - return sw_tag | 1 << shift; -} - -/** - * cxgb3i_ddp_tag_base - shift s/w tag bits so that reserved bits are not used - * @tformat: tag format information - * @sw_tag: s/w tag to be checked - */ -static inline u32 cxgb3i_ddp_tag_base(struct cxgb3i_tag_format *tformat, - u32 sw_tag) -{ - u32 mask = (1 << tformat->rsvd_shift) - 1; - - if (sw_tag && (sw_tag & ~mask)) { - u32 v1 = sw_tag & mask; - u32 v2 = sw_tag >> tformat->rsvd_shift; - - v2 <<= tformat->rsvd_shift + tformat->rsvd_bits; - return v2 | v1; - } - return sw_tag; -} - -/** - * cxgb3i_tag_rsvd_bits - get the reserved bits used by the h/w - * @tformat: tag format information - * @tag: tag to be checked - * - * return the reserved bits in the tag - */ -static inline u32 cxgb3i_tag_rsvd_bits(struct cxgb3i_tag_format *tformat, - u32 tag) -{ - if (cxgb3i_is_ddp_tag(tformat, tag)) - return (tag >> tformat->rsvd_shift) & tformat->rsvd_mask; - return 0; -} - -/** - * cxgb3i_tag_nonrsvd_bits - get the non-reserved bits used by the s/w - * @tformat: tag format information - * @tag: tag to be checked - * - * return the non-reserved bits in the tag. - */ -static inline u32 cxgb3i_tag_nonrsvd_bits(struct cxgb3i_tag_format *tformat, - u32 tag) -{ - unsigned char shift = tformat->rsvd_bits + tformat->rsvd_shift - 1; - u32 v1, v2; - - if (cxgb3i_is_ddp_tag(tformat, tag)) { - v1 = tag & ((1 << tformat->rsvd_shift) - 1); - v2 = (tag >> (shift + 1)) << tformat->rsvd_shift; - } else { - u32 mask = (1 << shift) - 1; - - tag &= ~(1 << shift); - v1 = tag & mask; - v2 = (tag >> 1) & ~mask; - } - return v1 | v2; -} - -int cxgb3i_ddp_tag_reserve(struct t3cdev *, unsigned int tid, - struct cxgb3i_tag_format *, u32 *tag, - struct cxgb3i_gather_list *, gfp_t gfp); -void cxgb3i_ddp_tag_release(struct t3cdev *, u32 tag); - -struct cxgb3i_gather_list *cxgb3i_ddp_make_gl(unsigned int xferlen, - struct scatterlist *sgl, - unsigned int sgcnt, - struct pci_dev *pdev, - gfp_t gfp); -void cxgb3i_ddp_release_gl(struct cxgb3i_gather_list *gl, - struct pci_dev *pdev); - -int cxgb3i_setup_conn_host_pagesize(struct t3cdev *, unsigned int tid, - int reply); -int cxgb3i_setup_conn_pagesize(struct t3cdev *, unsigned int tid, int reply, - unsigned long pgsz); -int cxgb3i_setup_conn_digest(struct t3cdev *, unsigned int tid, - int hcrc, int dcrc, int reply); -int cxgb3i_ddp_find_page_index(unsigned long pgsz); -int cxgb3i_adapter_ddp_info(struct t3cdev *, struct cxgb3i_tag_format *, - unsigned int *txsz, unsigned int *rxsz); - -void cxgb3i_ddp_init(struct t3cdev *); -void cxgb3i_ddp_cleanup(struct t3cdev *); -#endif diff --git a/drivers/scsi/cxgb3i/cxgb3i_init.c b/drivers/scsi/cxgb3i/cxgb3i_init.c deleted file mode 100644 index 685af3698518..000000000000 --- a/drivers/scsi/cxgb3i/cxgb3i_init.c +++ /dev/null @@ -1,132 +0,0 @@ -/* cxgb3i_init.c: Chelsio S3xx iSCSI driver. - * - * Copyright (c) 2008 Chelsio Communications, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation. - * - * Written by: Karen Xie (kxie@chelsio.com) - */ - -#include "cxgb3i.h" - -#define DRV_MODULE_NAME "cxgb3i" -#define DRV_MODULE_VERSION "1.0.2" -#define DRV_MODULE_RELDATE "Mar. 2009" - -static char version[] = - "Chelsio S3xx iSCSI Driver " DRV_MODULE_NAME - " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; - -MODULE_AUTHOR("Karen Xie <kxie@chelsio.com>"); -MODULE_DESCRIPTION("Chelsio S3xx iSCSI Driver"); -MODULE_LICENSE("GPL"); -MODULE_VERSION(DRV_MODULE_VERSION); - -static void open_s3_dev(struct t3cdev *); -static void close_s3_dev(struct t3cdev *); -static void s3_event_handler(struct t3cdev *tdev, u32 event, u32 port); - -static cxgb3_cpl_handler_func cxgb3i_cpl_handlers[NUM_CPL_CMDS]; -static struct cxgb3_client t3c_client = { - .name = "iscsi_cxgb3", - .handlers = cxgb3i_cpl_handlers, - .add = open_s3_dev, - .remove = close_s3_dev, - .event_handler = s3_event_handler, -}; - -/** - * open_s3_dev - register with cxgb3 LLD - * @t3dev: cxgb3 adapter instance - */ -static void open_s3_dev(struct t3cdev *t3dev) -{ - static int vers_printed; - - if (!vers_printed) { - printk(KERN_INFO "%s", version); - vers_printed = 1; - } - - cxgb3i_ddp_init(t3dev); - cxgb3i_sdev_add(t3dev, &t3c_client); - cxgb3i_adapter_open(t3dev); -} - -/** - * close_s3_dev - de-register with cxgb3 LLD - * @t3dev: cxgb3 adapter instance - */ -static void close_s3_dev(struct t3cdev *t3dev) -{ - cxgb3i_adapter_close(t3dev); - cxgb3i_sdev_remove(t3dev); - cxgb3i_ddp_cleanup(t3dev); -} - -static void s3_event_handler(struct t3cdev *tdev, u32 event, u32 port) -{ - struct cxgb3i_adapter *snic = cxgb3i_adapter_find_by_tdev(tdev); - - cxgb3i_log_info("snic 0x%p, tdev 0x%p, event 0x%x, port 0x%x.\n", - snic, tdev, event, port); - if (!snic) - return; - - switch (event) { - case OFFLOAD_STATUS_DOWN: - snic->flags |= CXGB3I_ADAPTER_FLAG_RESET; - break; - case OFFLOAD_STATUS_UP: - snic->flags &= ~CXGB3I_ADAPTER_FLAG_RESET; - break; - } -} - -/** - * cxgb3i_init_module - module init entry point - * - * initialize any driver wide global data structures and register itself - * with the cxgb3 module - */ -static int __init cxgb3i_init_module(void) -{ - int err; - - err = cxgb3i_sdev_init(cxgb3i_cpl_handlers); - if (err < 0) - return err; - - err = cxgb3i_iscsi_init(); - if (err < 0) - return err; - - err = cxgb3i_pdu_init(); - if (err < 0) { - cxgb3i_iscsi_cleanup(); - return err; - } - - cxgb3_register_client(&t3c_client); - - return 0; -} - -/** - * cxgb3i_exit_module - module cleanup/exit entry point - * - * go through the driver hba list and for each hba, release any resource held. - * and unregisters iscsi transport and the cxgb3 module - */ -static void __exit cxgb3i_exit_module(void) -{ - cxgb3_unregister_client(&t3c_client); - cxgb3i_pdu_cleanup(); - cxgb3i_iscsi_cleanup(); - cxgb3i_sdev_cleanup(); -} - -module_init(cxgb3i_init_module); -module_exit(cxgb3i_exit_module); diff --git a/drivers/scsi/cxgb3i/cxgb3i_iscsi.c b/drivers/scsi/cxgb3i/cxgb3i_iscsi.c deleted file mode 100644 index 7b686abaae64..000000000000 --- a/drivers/scsi/cxgb3i/cxgb3i_iscsi.c +++ /dev/null @@ -1,1018 +0,0 @@ -/* cxgb3i_iscsi.c: Chelsio S3xx iSCSI driver. - * - * Copyright (c) 2008 Chelsio Communications, Inc. - * Copyright (c) 2008 Mike Christie - * Copyright (c) 2008 Red Hat, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation. - * - * Written by: Karen Xie (kxie@chelsio.com) - */ - -#include <linux/inet.h> -#include <linux/slab.h> -#include <linux/crypto.h> -#include <linux/if_vlan.h> -#include <net/dst.h> -#include <net/tcp.h> -#include <scsi/scsi_cmnd.h> -#include <scsi/scsi_device.h> -#include <scsi/scsi_eh.h> -#include <scsi/scsi_host.h> -#include <scsi/scsi.h> -#include <scsi/iscsi_proto.h> -#include <scsi/libiscsi.h> -#include <scsi/scsi_transport_iscsi.h> - -#include "cxgb3i.h" -#include "cxgb3i_pdu.h" - -#ifdef __DEBUG_CXGB3I_TAG__ -#define cxgb3i_tag_debug cxgb3i_log_debug -#else -#define cxgb3i_tag_debug(fmt...) -#endif - -#ifdef __DEBUG_CXGB3I_API__ -#define cxgb3i_api_debug cxgb3i_log_debug -#else -#define cxgb3i_api_debug(fmt...) -#endif - -/* - * align pdu size to multiple of 512 for better performance - */ -#define align_pdu_size(n) do { n = (n) & (~511); } while (0) - -static struct scsi_transport_template *cxgb3i_scsi_transport; -static struct scsi_host_template cxgb3i_host_template; -static struct iscsi_transport cxgb3i_iscsi_transport; -static unsigned char sw_tag_idx_bits; -static unsigned char sw_tag_age_bits; - -static LIST_HEAD(cxgb3i_snic_list); -static DEFINE_RWLOCK(cxgb3i_snic_rwlock); - -/** - * cxgb3i_adpater_find_by_tdev - find the cxgb3i_adapter structure via t3cdev - * @tdev: t3cdev pointer - */ -struct cxgb3i_adapter *cxgb3i_adapter_find_by_tdev(struct t3cdev *tdev) -{ - struct cxgb3i_adapter *snic; - - read_lock(&cxgb3i_snic_rwlock); - list_for_each_entry(snic, &cxgb3i_snic_list, list_head) { - if (snic->tdev == tdev) { - read_unlock(&cxgb3i_snic_rwlock); - return snic; - } - } - read_unlock(&cxgb3i_snic_rwlock); - return NULL; -} - -static inline int adapter_update(struct cxgb3i_adapter *snic) -{ - cxgb3i_log_info("snic 0x%p, t3dev 0x%p, updating.\n", - snic, snic->tdev); - return cxgb3i_adapter_ddp_info(snic->tdev, &snic->tag_format, - &snic->tx_max_size, - &snic->rx_max_size); -} - -static int adapter_add(struct cxgb3i_adapter *snic) -{ - struct t3cdev *t3dev = snic->tdev; - struct adapter *adapter = tdev2adap(t3dev); - int i, err; - - snic->pdev = adapter->pdev; - snic->tag_format.sw_bits = sw_tag_idx_bits + sw_tag_age_bits; - - err = cxgb3i_adapter_ddp_info(t3dev, &snic->tag_format, - &snic->tx_max_size, - &snic->rx_max_size); - if (err < 0) - return err; - - for_each_port(adapter, i) { - snic->hba[i] = cxgb3i_hba_host_add(snic, adapter->port[i]); - if (!snic->hba[i]) - return -EINVAL; - } - snic->hba_cnt = adapter->params.nports; - - /* add to the list */ - write_lock(&cxgb3i_snic_rwlock); - list_add_tail(&snic->list_head, &cxgb3i_snic_list); - write_unlock(&cxgb3i_snic_rwlock); - - cxgb3i_log_info("t3dev 0x%p open, snic 0x%p, %u scsi hosts added.\n", - t3dev, snic, snic->hba_cnt); - return 0; -} - -/** - * cxgb3i_adapter_open - init a s3 adapter structure and any h/w settings - * @t3dev: t3cdev adapter - */ -void cxgb3i_adapter_open(struct t3cdev *t3dev) -{ - struct cxgb3i_adapter *snic = cxgb3i_adapter_find_by_tdev(t3dev); - int err; - - if (snic) - err = adapter_update(snic); - else { - snic = kzalloc(sizeof(*snic), GFP_KERNEL); - if (snic) { - spin_lock_init(&snic->lock); - snic->tdev = t3dev; - err = adapter_add(snic); - } else - err = -ENOMEM; - } - - if (err < 0) { - cxgb3i_log_info("snic 0x%p, f 0x%x, t3dev 0x%p open, err %d.\n", - snic, snic ? snic->flags : 0, t3dev, err); - if (snic) { - snic->flags &= ~CXGB3I_ADAPTER_FLAG_RESET; - cxgb3i_adapter_close(t3dev); - } - } -} - -/** - * cxgb3i_adapter_close - release the resources held and cleanup h/w settings - * @t3dev: t3cdev adapter - */ -void cxgb3i_adapter_close(struct t3cdev *t3dev) -{ - struct cxgb3i_adapter *snic = cxgb3i_adapter_find_by_tdev(t3dev); - int i; - - if (!snic || snic->flags & CXGB3I_ADAPTER_FLAG_RESET) { - cxgb3i_log_info("t3dev 0x%p close, snic 0x%p, f 0x%x.\n", - t3dev, snic, snic ? snic->flags : 0); - return; - } - - /* remove from the list */ - write_lock(&cxgb3i_snic_rwlock); - list_del(&snic->list_head); - write_unlock(&cxgb3i_snic_rwlock); - - for (i = 0; i < snic->hba_cnt; i++) { - if (snic->hba[i]) { - cxgb3i_hba_host_remove(snic->hba[i]); - snic->hba[i] = NULL; - } - } - cxgb3i_log_info("t3dev 0x%p close, snic 0x%p, %u scsi hosts removed.\n", - t3dev, snic, snic->hba_cnt); - kfree(snic); -} - -/** - * cxgb3i_hba_find_by_netdev - find the cxgb3i_hba structure via net_device - * @t3dev: t3cdev adapter - */ -static struct cxgb3i_hba *cxgb3i_hba_find_by_netdev(struct net_device *ndev) -{ - struct cxgb3i_adapter *snic; - int i; - - if (ndev->priv_flags & IFF_802_1Q_VLAN) - ndev = vlan_dev_real_dev(ndev); - - read_lock(&cxgb3i_snic_rwlock); - list_for_each_entry(snic, &cxgb3i_snic_list, list_head) { - for (i = 0; i < snic->hba_cnt; i++) { - if (snic->hba[i]->ndev == ndev) { - read_unlock(&cxgb3i_snic_rwlock); - return snic->hba[i]; - } - } - } - read_unlock(&cxgb3i_snic_rwlock); - return NULL; -} - -/** - * cxgb3i_hba_host_add - register a new host with scsi/iscsi - * @snic: the cxgb3i adapter - * @ndev: associated net_device - */ -struct cxgb3i_hba *cxgb3i_hba_host_add(struct cxgb3i_adapter *snic, - struct net_device *ndev) -{ - struct cxgb3i_hba *hba; - struct Scsi_Host *shost; - int err; - - shost = iscsi_host_alloc(&cxgb3i_host_template, - sizeof(struct cxgb3i_hba), 1); - if (!shost) { - cxgb3i_log_info("snic 0x%p, ndev 0x%p, host_alloc failed.\n", - snic, ndev); - return NULL; - } - - shost->transportt = cxgb3i_scsi_transport; - shost->max_lun = CXGB3I_MAX_LUN; - shost->max_id = CXGB3I_MAX_TARGET; - shost->max_channel = 0; - shost->max_cmd_len = 16; - - hba = iscsi_host_priv(shost); - hba->snic = snic; - hba->ndev = ndev; - hba->shost = shost; - - pci_dev_get(snic->pdev); - err = iscsi_host_add(shost, &snic->pdev->dev); - if (err) { - cxgb3i_log_info("snic 0x%p, ndev 0x%p, host_add failed.\n", - snic, ndev); - goto pci_dev_put; - } - - cxgb3i_api_debug("shost 0x%p, hba 0x%p, no %u.\n", - shost, hba, shost->host_no); - - return hba; - -pci_dev_put: - pci_dev_put(snic->pdev); - scsi_host_put(shost); - return NULL; -} - -/** - * cxgb3i_hba_host_remove - de-register the host with scsi/iscsi - * @hba: the cxgb3i hba - */ -void cxgb3i_hba_host_remove(struct cxgb3i_hba *hba) -{ - cxgb3i_api_debug("shost 0x%p, hba 0x%p, no %u.\n", - hba->shost, hba, hba->shost->host_no); - iscsi_host_remove(hba->shost); - pci_dev_put(hba->snic->pdev); - iscsi_host_free(hba->shost); -} - -/** - * cxgb3i_ep_connect - establish TCP connection to target portal - * @shost: scsi host to use - * @dst_addr: target IP address - * @non_blocking: blocking or non-blocking call - * - * Initiates a TCP/IP connection to the dst_addr - */ -static struct iscsi_endpoint *cxgb3i_ep_connect(struct Scsi_Host *shost, - struct sockaddr *dst_addr, - int non_blocking) -{ - struct iscsi_endpoint *ep; - struct cxgb3i_endpoint *cep; - struct cxgb3i_hba *hba = NULL; - struct s3_conn *c3cn = NULL; - int err = 0; - - if (shost) - hba = iscsi_host_priv(shost); - - cxgb3i_api_debug("shost 0x%p, hba 0x%p.\n", shost, hba); - - c3cn = cxgb3i_c3cn_create(); - if (!c3cn) { - cxgb3i_log_info("ep connect OOM.\n"); - err = -ENOMEM; - goto release_conn; - } - - err = cxgb3i_c3cn_connect(hba ? hba->ndev : NULL, c3cn, - (struct sockaddr_in *)dst_addr); - if (err < 0) { - cxgb3i_log_info("ep connect failed.\n"); - goto release_conn; - } - - hba = cxgb3i_hba_find_by_netdev(c3cn->dst_cache->dev); - if (!hba) { - err = -ENOSPC; - cxgb3i_log_info("NOT going through cxgbi device.\n"); - goto release_conn; - } - - if (shost && hba != iscsi_host_priv(shost)) { - err = -ENOSPC; - cxgb3i_log_info("Could not connect through request host%u\n", - shost->host_no); - goto release_conn; - } - - if (c3cn_is_closing(c3cn)) { - err = -ENOSPC; - cxgb3i_log_info("ep connect unable to connect.\n"); - goto release_conn; - } - - ep = iscsi_create_endpoint(sizeof(*cep)); - if (!ep) { - err = -ENOMEM; - cxgb3i_log_info("iscsi alloc ep, OOM.\n"); - goto release_conn; - } - cep = ep->dd_data; - cep->c3cn = c3cn; - cep->hba = hba; - - cxgb3i_api_debug("ep 0x%p, 0x%p, c3cn 0x%p, hba 0x%p.\n", - ep, cep, c3cn, hba); - return ep; - -release_conn: - cxgb3i_api_debug("conn 0x%p failed, release.\n", c3cn); - if (c3cn) - cxgb3i_c3cn_release(c3cn); - return ERR_PTR(err); -} - -/** - * cxgb3i_ep_poll - polls for TCP connection establishement - * @ep: TCP connection (endpoint) handle - * @timeout_ms: timeout value in milli secs - * - * polls for TCP connect request to complete - */ -static int cxgb3i_ep_poll(struct iscsi_endpoint *ep, int timeout_ms) -{ - struct cxgb3i_endpoint *cep = ep->dd_data; - struct s3_conn *c3cn = cep->c3cn; - - if (!c3cn_is_established(c3cn)) - return 0; - cxgb3i_api_debug("ep 0x%p, c3cn 0x%p established.\n", ep, c3cn); - return 1; -} - -/** - * cxgb3i_ep_disconnect - teardown TCP connection - * @ep: TCP connection (endpoint) handle - * - * teardown TCP connection - */ -static void cxgb3i_ep_disconnect(struct iscsi_endpoint *ep) -{ - struct cxgb3i_endpoint *cep = ep->dd_data; - struct cxgb3i_conn *cconn = cep->cconn; - - cxgb3i_api_debug("ep 0x%p, cep 0x%p.\n", ep, cep); - - if (cconn && cconn->conn) { - /* - * stop the xmit path so the xmit_pdu function is - * not being called - */ - iscsi_suspend_tx(cconn->conn); - - write_lock_bh(&cep->c3cn->callback_lock); - cep->c3cn->user_data = NULL; - cconn->cep = NULL; - write_unlock_bh(&cep->c3cn->callback_lock); - } - - cxgb3i_api_debug("ep 0x%p, cep 0x%p, release c3cn 0x%p.\n", - ep, cep, cep->c3cn); - cxgb3i_c3cn_release(cep->c3cn); - iscsi_destroy_endpoint(ep); -} - -/** - * cxgb3i_session_create - create a new iscsi session - * @cmds_max: max # of commands - * @qdepth: scsi queue depth - * @initial_cmdsn: initial iscsi CMDSN for this session - * - * Creates a new iSCSI session - */ -static struct iscsi_cls_session * -cxgb3i_session_create(struct iscsi_endpoint *ep, u16 cmds_max, u16 qdepth, - u32 initial_cmdsn) -{ - struct cxgb3i_endpoint *cep; - struct cxgb3i_hba *hba; - struct Scsi_Host *shost; - struct iscsi_cls_session *cls_session; - struct iscsi_session *session; - - if (!ep) { - cxgb3i_log_error("%s, missing endpoint.\n", __func__); - return NULL; - } - - cep = ep->dd_data; - hba = cep->hba; - shost = hba->shost; - cxgb3i_api_debug("ep 0x%p, cep 0x%p, hba 0x%p.\n", ep, cep, hba); - BUG_ON(hba != iscsi_host_priv(shost)); - - cls_session = iscsi_session_setup(&cxgb3i_iscsi_transport, shost, - cmds_max, 0, - sizeof(struct iscsi_tcp_task) + - sizeof(struct cxgb3i_task_data), - initial_cmdsn, ISCSI_MAX_TARGET); - if (!cls_session) - return NULL; - session = cls_session->dd_data; - if (iscsi_tcp_r2tpool_alloc(session)) - goto remove_session; - - return cls_session; - -remove_session: - iscsi_session_teardown(cls_session); - return NULL; -} - -/** - * cxgb3i_session_destroy - destroys iscsi session - * @cls_session: pointer to iscsi cls session - * - * Destroys an iSCSI session instance and releases its all resources held - */ -static void cxgb3i_session_destroy(struct iscsi_cls_session *cls_session) -{ - cxgb3i_api_debug("sess 0x%p.\n", cls_session); - iscsi_tcp_r2tpool_free(cls_session->dd_data); - iscsi_session_teardown(cls_session); -} - -/** - * cxgb3i_conn_max_xmit_dlength -- calc the max. xmit pdu segment size - * @conn: iscsi connection - * check the max. xmit pdu payload, reduce it if needed - */ -static inline int cxgb3i_conn_max_xmit_dlength(struct iscsi_conn *conn) - -{ - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; - struct cxgb3i_conn *cconn = tcp_conn->dd_data; - unsigned int max = max(512 * MAX_SKB_FRAGS, SKB_TX_HEADROOM); - - max = min(cconn->hba->snic->tx_max_size, max); - if (conn->max_xmit_dlength) - conn->max_xmit_dlength = min(conn->max_xmit_dlength, max); - else - conn->max_xmit_dlength = max; - align_pdu_size(conn->max_xmit_dlength); - cxgb3i_api_debug("conn 0x%p, max xmit %u.\n", - conn, conn->max_xmit_dlength); - return 0; -} - -/** - * cxgb3i_conn_max_recv_dlength -- check the max. recv pdu segment size - * @conn: iscsi connection - * return 0 if the value is valid, < 0 otherwise. - */ -static inline int cxgb3i_conn_max_recv_dlength(struct iscsi_conn *conn) -{ - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; - struct cxgb3i_conn *cconn = tcp_conn->dd_data; - unsigned int max = cconn->hba->snic->rx_max_size; - - align_pdu_size(max); - if (conn->max_recv_dlength) { - if (conn->max_recv_dlength > max) { - cxgb3i_log_error("MaxRecvDataSegmentLength %u too big." - " Need to be <= %u.\n", - conn->max_recv_dlength, max); - return -EINVAL; - } - conn->max_recv_dlength = min(conn->max_recv_dlength, max); - align_pdu_size(conn->max_recv_dlength); - } else - conn->max_recv_dlength = max; - cxgb3i_api_debug("conn 0x%p, max recv %u.\n", - conn, conn->max_recv_dlength); - return 0; -} - -/** - * cxgb3i_conn_create - create iscsi connection instance - * @cls_session: pointer to iscsi cls session - * @cid: iscsi cid - * - * Creates a new iSCSI connection instance for a given session - */ -static struct iscsi_cls_conn *cxgb3i_conn_create(struct iscsi_cls_session - *cls_session, u32 cid) -{ - struct iscsi_cls_conn *cls_conn; - struct iscsi_conn *conn; - struct iscsi_tcp_conn *tcp_conn; - struct cxgb3i_conn *cconn; - - cxgb3i_api_debug("sess 0x%p, cid %u.\n", cls_session, cid); - - cls_conn = iscsi_tcp_conn_setup(cls_session, sizeof(*cconn), cid); - if (!cls_conn) - return NULL; - conn = cls_conn->dd_data; - tcp_conn = conn->dd_data; - cconn = tcp_conn->dd_data; - - cconn->conn = conn; - return cls_conn; -} - -/** - * cxgb3i_conn_bind - binds iscsi sess, conn and endpoint together - * @cls_session: pointer to iscsi cls session - * @cls_conn: pointer to iscsi cls conn - * @transport_eph: 64-bit EP handle - * @is_leading: leading connection on this session? - * - * Binds together an iSCSI session, an iSCSI connection and a - * TCP connection. This routine returns error code if the TCP - * connection does not belong on the device iSCSI sess/conn is bound - */ - -static int cxgb3i_conn_bind(struct iscsi_cls_session *cls_session, - struct iscsi_cls_conn *cls_conn, - u64 transport_eph, int is_leading) -{ - struct iscsi_conn *conn = cls_conn->dd_data; - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; - struct cxgb3i_conn *cconn = tcp_conn->dd_data; - struct cxgb3i_adapter *snic; - struct iscsi_endpoint *ep; - struct cxgb3i_endpoint *cep; - struct s3_conn *c3cn; - int err; - - ep = iscsi_lookup_endpoint(transport_eph); - if (!ep) - return -EINVAL; - - /* setup ddp pagesize */ - cep = ep->dd_data; - c3cn = cep->c3cn; - snic = cep->hba->snic; - err = cxgb3i_setup_conn_host_pagesize(snic->tdev, c3cn->tid, 0); - if (err < 0) - return err; - - cxgb3i_api_debug("ep 0x%p, cls sess 0x%p, cls conn 0x%p.\n", - ep, cls_session, cls_conn); - - err = iscsi_conn_bind(cls_session, cls_conn, is_leading); - if (err) - return -EINVAL; - - /* calculate the tag idx bits needed for this conn based on cmds_max */ - cconn->task_idx_bits = (__ilog2_u32(conn->session->cmds_max - 1)) + 1; - cxgb3i_api_debug("session cmds_max 0x%x, bits %u.\n", - conn->session->cmds_max, cconn->task_idx_bits); - - read_lock(&c3cn->callback_lock); - c3cn->user_data = conn; - cconn->hba = cep->hba; - cconn->cep = cep; - cep->cconn = cconn; - read_unlock(&c3cn->callback_lock); - - cxgb3i_conn_max_xmit_dlength(conn); - cxgb3i_conn_max_recv_dlength(conn); - - spin_lock_bh(&conn->session->lock); - sprintf(conn->portal_address, "%pI4", &c3cn->daddr.sin_addr.s_addr); - conn->portal_port = ntohs(c3cn->daddr.sin_port); - spin_unlock_bh(&conn->session->lock); - - /* init recv engine */ - iscsi_tcp_hdr_recv_prep(tcp_conn); - - return 0; -} - -/** - * cxgb3i_conn_get_param - return iscsi connection parameter to caller - * @cls_conn: pointer to iscsi cls conn - * @param: parameter type identifier - * @buf: buffer pointer - * - * returns iSCSI connection parameters - */ -static int cxgb3i_conn_get_param(struct iscsi_cls_conn *cls_conn, - enum iscsi_param param, char *buf) -{ - struct iscsi_conn *conn = cls_conn->dd_data; - int len; - - cxgb3i_api_debug("cls_conn 0x%p, param %d.\n", cls_conn, param); - - switch (param) { - case ISCSI_PARAM_CONN_PORT: - spin_lock_bh(&conn->session->lock); - len = sprintf(buf, "%hu\n", conn->portal_port); - spin_unlock_bh(&conn->session->lock); - break; - case ISCSI_PARAM_CONN_ADDRESS: - spin_lock_bh(&conn->session->lock); - len = sprintf(buf, "%s\n", conn->portal_address); - spin_unlock_bh(&conn->session->lock); - break; - default: - return iscsi_conn_get_param(cls_conn, param, buf); - } - - return len; -} - -/** - * cxgb3i_conn_set_param - set iscsi connection parameter - * @cls_conn: pointer to iscsi cls conn - * @param: parameter type identifier - * @buf: buffer pointer - * @buflen: buffer length - * - * set iSCSI connection parameters - */ -static int cxgb3i_conn_set_param(struct iscsi_cls_conn *cls_conn, - enum iscsi_param param, char *buf, int buflen) -{ - struct iscsi_conn *conn = cls_conn->dd_data; - struct iscsi_session *session = conn->session; - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; - struct cxgb3i_conn *cconn = tcp_conn->dd_data; - struct cxgb3i_adapter *snic = cconn->hba->snic; - struct s3_conn *c3cn = cconn->cep->c3cn; - int value, err = 0; - - switch (param) { - case ISCSI_PARAM_HDRDGST_EN: - err = iscsi_set_param(cls_conn, param, buf, buflen); - if (!err && conn->hdrdgst_en) - err = cxgb3i_setup_conn_digest(snic->tdev, c3cn->tid, - conn->hdrdgst_en, - conn->datadgst_en, 0); - break; - case ISCSI_PARAM_DATADGST_EN: - err = iscsi_set_param(cls_conn, param, buf, buflen); - if (!err && conn->datadgst_en) - err = cxgb3i_setup_conn_digest(snic->tdev, c3cn->tid, - conn->hdrdgst_en, - conn->datadgst_en, 0); - break; - case ISCSI_PARAM_MAX_R2T: - sscanf(buf, "%d", &value); - if (value <= 0 || !is_power_of_2(value)) - return -EINVAL; - if (session->max_r2t == value) - break; - iscsi_tcp_r2tpool_free(session); - err = iscsi_set_param(cls_conn, param, buf, buflen); - if (!err && iscsi_tcp_r2tpool_alloc(session)) - return -ENOMEM; - case ISCSI_PARAM_MAX_RECV_DLENGTH: - err = iscsi_set_param(cls_conn, param, buf, buflen); - if (!err) - err = cxgb3i_conn_max_recv_dlength(conn); - break; - case ISCSI_PARAM_MAX_XMIT_DLENGTH: - err = iscsi_set_param(cls_conn, param, buf, buflen); - if (!err) - err = cxgb3i_conn_max_xmit_dlength(conn); - break; - default: - return iscsi_set_param(cls_conn, param, buf, buflen); - } - return err; -} - -/** - * cxgb3i_host_set_param - configure host (adapter) related parameters - * @shost: scsi host pointer - * @param: parameter type identifier - * @buf: buffer pointer - */ -static int cxgb3i_host_set_param(struct Scsi_Host *shost, - enum iscsi_host_param param, - char *buf, int buflen) -{ - struct cxgb3i_hba *hba = iscsi_host_priv(shost); - - if (!hba->ndev) { - shost_printk(KERN_ERR, shost, "Could not set host param. " - "Netdev for host not set.\n"); - return -ENODEV; - } - - cxgb3i_api_debug("param %d, buf %s.\n", param, buf); - - switch (param) { - case ISCSI_HOST_PARAM_IPADDRESS: - { - __be32 addr = in_aton(buf); - cxgb3i_set_private_ipv4addr(hba->ndev, addr); - return 0; - } - case ISCSI_HOST_PARAM_HWADDRESS: - case ISCSI_HOST_PARAM_NETDEV_NAME: - /* ignore */ - return 0; - default: - return iscsi_host_set_param(shost, param, buf, buflen); - } -} - -/** - * cxgb3i_host_get_param - returns host (adapter) related parameters - * @shost: scsi host pointer - * @param: parameter type identifier - * @buf: buffer pointer - */ -static int cxgb3i_host_get_param(struct Scsi_Host *shost, - enum iscsi_host_param param, char *buf) -{ - struct cxgb3i_hba *hba = iscsi_host_priv(shost); - int len = 0; - - if (!hba->ndev) { - shost_printk(KERN_ERR, shost, "Could not set host param. " - "Netdev for host not set.\n"); - return -ENODEV; - } - - cxgb3i_api_debug("hba %s, param %d.\n", hba->ndev->name, param); - - switch (param) { - case ISCSI_HOST_PARAM_HWADDRESS: - len = sysfs_format_mac(buf, hba->ndev->dev_addr, 6); - break; - case ISCSI_HOST_PARAM_NETDEV_NAME: - len = sprintf(buf, "%s\n", hba->ndev->name); - break; - case ISCSI_HOST_PARAM_IPADDRESS: - { - __be32 addr; - - addr = cxgb3i_get_private_ipv4addr(hba->ndev); - len = sprintf(buf, "%pI4", &addr); - break; - } - default: - return iscsi_host_get_param(shost, param, buf); - } - return len; -} - -/** - * cxgb3i_conn_get_stats - returns iSCSI stats - * @cls_conn: pointer to iscsi cls conn - * @stats: pointer to iscsi statistic struct - */ -static void cxgb3i_conn_get_stats(struct iscsi_cls_conn *cls_conn, - struct iscsi_stats *stats) -{ - struct iscsi_conn *conn = cls_conn->dd_data; - - stats->txdata_octets = conn->txdata_octets; - stats->rxdata_octets = conn->rxdata_octets; - stats->scsicmd_pdus = conn->scsicmd_pdus_cnt; - stats->dataout_pdus = conn->dataout_pdus_cnt; - stats->scsirsp_pdus = conn->scsirsp_pdus_cnt; - stats->datain_pdus = conn->datain_pdus_cnt; - stats->r2t_pdus = conn->r2t_pdus_cnt; - stats->tmfcmd_pdus = conn->tmfcmd_pdus_cnt; - stats->tmfrsp_pdus = conn->tmfrsp_pdus_cnt; - stats->digest_err = 0; - stats->timeout_err = 0; - stats->custom_length = 1; - strcpy(stats->custom[0].desc, "eh_abort_cnt"); - stats->custom[0].value = conn->eh_abort_cnt; -} - -/** - * cxgb3i_parse_itt - get the idx and age bits from a given tag - * @conn: iscsi connection - * @itt: itt tag - * @idx: task index, filled in by this function - * @age: session age, filled in by this function - */ -static void cxgb3i_parse_itt(struct iscsi_conn *conn, itt_t itt, - int *idx, int *age) -{ - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; - struct cxgb3i_conn *cconn = tcp_conn->dd_data; - struct cxgb3i_adapter *snic = cconn->hba->snic; - u32 tag = ntohl((__force u32) itt); - u32 sw_bits; - - sw_bits = cxgb3i_tag_nonrsvd_bits(&snic->tag_format, tag); - if (idx) - *idx = sw_bits & ((1 << cconn->task_idx_bits) - 1); - if (age) - *age = (sw_bits >> cconn->task_idx_bits) & ISCSI_AGE_MASK; - - cxgb3i_tag_debug("parse tag 0x%x/0x%x, sw 0x%x, itt 0x%x, age 0x%x.\n", - tag, itt, sw_bits, idx ? *idx : 0xFFFFF, - age ? *age : 0xFF); -} - -/** - * cxgb3i_reserve_itt - generate tag for a give task - * @task: iscsi task - * @hdr_itt: tag, filled in by this function - * Set up ddp for scsi read tasks if possible. - */ -int cxgb3i_reserve_itt(struct iscsi_task *task, itt_t *hdr_itt) -{ - struct scsi_cmnd *sc = task->sc; - struct iscsi_conn *conn = task->conn; - struct iscsi_session *sess = conn->session; - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; - struct cxgb3i_conn *cconn = tcp_conn->dd_data; - struct cxgb3i_adapter *snic = cconn->hba->snic; - struct cxgb3i_tag_format *tformat = &snic->tag_format; - u32 sw_tag = (sess->age << cconn->task_idx_bits) | task->itt; - u32 tag; - int err = -EINVAL; - - if (sc && - (scsi_bidi_cmnd(sc) || sc->sc_data_direction == DMA_FROM_DEVICE) && - cxgb3i_sw_tag_usable(tformat, sw_tag)) { - struct s3_conn *c3cn = cconn->cep->c3cn; - struct cxgb3i_gather_list *gl; - - gl = cxgb3i_ddp_make_gl(scsi_in(sc)->length, - scsi_in(sc)->table.sgl, - scsi_in(sc)->table.nents, - snic->pdev, - GFP_ATOMIC); - if (gl) { - tag = sw_tag; - err = cxgb3i_ddp_tag_reserve(snic->tdev, c3cn->tid, - tformat, &tag, - gl, GFP_ATOMIC); - if (err < 0) - cxgb3i_ddp_release_gl(gl, snic->pdev); - } - } - - if (err < 0) - tag = cxgb3i_set_non_ddp_tag(tformat, sw_tag); - /* the itt need to sent in big-endian order */ - *hdr_itt = (__force itt_t)htonl(tag); - - cxgb3i_tag_debug("new tag 0x%x/0x%x (itt 0x%x, age 0x%x).\n", - tag, *hdr_itt, task->itt, sess->age); - return 0; -} - -/** - * cxgb3i_release_itt - release the tag for a given task - * @task: iscsi task - * @hdr_itt: tag - * If the tag is a ddp tag, release the ddp setup - */ -void cxgb3i_release_itt(struct iscsi_task *task, itt_t hdr_itt) -{ - struct scsi_cmnd *sc = task->sc; - struct iscsi_tcp_conn *tcp_conn = task->conn->dd_data; - struct cxgb3i_conn *cconn = tcp_conn->dd_data; - struct cxgb3i_adapter *snic = cconn->hba->snic; - struct cxgb3i_tag_format *tformat = &snic->tag_format; - u32 tag = ntohl((__force u32)hdr_itt); - - cxgb3i_tag_debug("release tag 0x%x.\n", tag); - - if (sc && - (scsi_bidi_cmnd(sc) || sc->sc_data_direction == DMA_FROM_DEVICE) && - cxgb3i_is_ddp_tag(tformat, tag)) - cxgb3i_ddp_tag_release(snic->tdev, tag); -} - -/** - * cxgb3i_host_template -- Scsi_Host_Template structure - * used when registering with the scsi mid layer - */ -static struct scsi_host_template cxgb3i_host_template = { - .module = THIS_MODULE, - .name = "Chelsio S3xx iSCSI Initiator", - .proc_name = "cxgb3i", - .queuecommand = iscsi_queuecommand, - .change_queue_depth = iscsi_change_queue_depth, - .can_queue = CXGB3I_SCSI_HOST_QDEPTH, - .sg_tablesize = SG_ALL, - .max_sectors = 0xFFFF, - .cmd_per_lun = ISCSI_DEF_CMD_PER_LUN, - .eh_abort_handler = iscsi_eh_abort, - .eh_device_reset_handler = iscsi_eh_device_reset, - .eh_target_reset_handler = iscsi_eh_recover_target, - .target_alloc = iscsi_target_alloc, - .use_clustering = DISABLE_CLUSTERING, - .this_id = -1, -}; - -static struct iscsi_transport cxgb3i_iscsi_transport = { - .owner = THIS_MODULE, - .name = "cxgb3i", - .caps = CAP_RECOVERY_L0 | CAP_MULTI_R2T | CAP_HDRDGST - | CAP_DATADGST | CAP_DIGEST_OFFLOAD | - CAP_PADDING_OFFLOAD, - .param_mask = ISCSI_MAX_RECV_DLENGTH | - ISCSI_MAX_XMIT_DLENGTH | - ISCSI_HDRDGST_EN | - ISCSI_DATADGST_EN | - ISCSI_INITIAL_R2T_EN | - ISCSI_MAX_R2T | - ISCSI_IMM_DATA_EN | - ISCSI_FIRST_BURST | - ISCSI_MAX_BURST | - ISCSI_PDU_INORDER_EN | - ISCSI_DATASEQ_INORDER_EN | - ISCSI_ERL | - ISCSI_CONN_PORT | - ISCSI_CONN_ADDRESS | - ISCSI_EXP_STATSN | - ISCSI_PERSISTENT_PORT | - ISCSI_PERSISTENT_ADDRESS | - ISCSI_TARGET_NAME | ISCSI_TPGT | - ISCSI_USERNAME | ISCSI_PASSWORD | - ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN | - ISCSI_FAST_ABORT | ISCSI_ABORT_TMO | - ISCSI_LU_RESET_TMO | ISCSI_TGT_RESET_TMO | - ISCSI_PING_TMO | ISCSI_RECV_TMO | - ISCSI_IFACE_NAME | ISCSI_INITIATOR_NAME, - .host_param_mask = ISCSI_HOST_HWADDRESS | ISCSI_HOST_IPADDRESS | - ISCSI_HOST_INITIATOR_NAME | ISCSI_HOST_NETDEV_NAME, - .get_host_param = cxgb3i_host_get_param, - .set_host_param = cxgb3i_host_set_param, - /* session management */ - .create_session = cxgb3i_session_create, - .destroy_session = cxgb3i_session_destroy, - .get_session_param = iscsi_session_get_param, - /* connection management */ - .create_conn = cxgb3i_conn_create, - .bind_conn = cxgb3i_conn_bind, - .destroy_conn = iscsi_tcp_conn_teardown, - .start_conn = iscsi_conn_start, - .stop_conn = iscsi_conn_stop, - .get_conn_param = cxgb3i_conn_get_param, - .set_param = cxgb3i_conn_set_param, - .get_stats = cxgb3i_conn_get_stats, - /* pdu xmit req. from user space */ - .send_pdu = iscsi_conn_send_pdu, - /* task */ - .init_task = iscsi_tcp_task_init, - .xmit_task = iscsi_tcp_task_xmit, - .cleanup_task = cxgb3i_conn_cleanup_task, - - /* pdu */ - .alloc_pdu = cxgb3i_conn_alloc_pdu, - .init_pdu = cxgb3i_conn_init_pdu, - .xmit_pdu = cxgb3i_conn_xmit_pdu, - .parse_pdu_itt = cxgb3i_parse_itt, - - /* TCP connect/disconnect */ - .ep_connect = cxgb3i_ep_connect, - .ep_poll = cxgb3i_ep_poll, - .ep_disconnect = cxgb3i_ep_disconnect, - /* Error recovery timeout call */ - .session_recovery_timedout = iscsi_session_recovery_timedout, -}; - -int cxgb3i_iscsi_init(void) -{ - sw_tag_idx_bits = (__ilog2_u32(ISCSI_ITT_MASK)) + 1; - sw_tag_age_bits = (__ilog2_u32(ISCSI_AGE_MASK)) + 1; - cxgb3i_log_info("tag itt 0x%x, %u bits, age 0x%x, %u bits.\n", - ISCSI_ITT_MASK, sw_tag_idx_bits, - ISCSI_AGE_MASK, sw_tag_age_bits); - - cxgb3i_scsi_transport = - iscsi_register_transport(&cxgb3i_iscsi_transport); - if (!cxgb3i_scsi_transport) { - cxgb3i_log_error("Could not register cxgb3i transport.\n"); - return -ENODEV; - } - cxgb3i_api_debug("cxgb3i transport 0x%p.\n", cxgb3i_scsi_transport); - return 0; -} - -void cxgb3i_iscsi_cleanup(void) -{ - if (cxgb3i_scsi_transport) { - cxgb3i_api_debug("cxgb3i transport 0x%p.\n", - cxgb3i_scsi_transport); - iscsi_unregister_transport(&cxgb3i_iscsi_transport); - } -} diff --git a/drivers/scsi/cxgb3i/cxgb3i_offload.c b/drivers/scsi/cxgb3i/cxgb3i_offload.c deleted file mode 100644 index 3ee13cf9556b..000000000000 --- a/drivers/scsi/cxgb3i/cxgb3i_offload.c +++ /dev/null @@ -1,1944 +0,0 @@ -/* - * cxgb3i_offload.c: Chelsio S3xx iscsi offloaded tcp connection management - * - * Copyright (C) 2003-2008 Chelsio Communications. All rights reserved. - * - * 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 LICENSE file included in this - * release for licensing terms and conditions. - * - * Written by: Dimitris Michailidis (dm@chelsio.com) - * Karen Xie (kxie@chelsio.com) - */ - -#include <linux/if_vlan.h> -#include <linux/slab.h> -#include <linux/version.h> - -#include "cxgb3_defs.h" -#include "cxgb3_ctl_defs.h" -#include "firmware_exports.h" -#include "cxgb3i_offload.h" -#include "cxgb3i_pdu.h" -#include "cxgb3i_ddp.h" - -#ifdef __DEBUG_C3CN_CONN__ -#define c3cn_conn_debug cxgb3i_log_debug -#else -#define c3cn_conn_debug(fmt...) -#endif - -#ifdef __DEBUG_C3CN_TX__ -#define c3cn_tx_debug cxgb3i_log_debug -#else -#define c3cn_tx_debug(fmt...) -#endif - -#ifdef __DEBUG_C3CN_RX__ -#define c3cn_rx_debug cxgb3i_log_debug -#else -#define c3cn_rx_debug(fmt...) -#endif - -/* - * module parameters releated to offloaded iscsi connection - */ -static int cxgb3_rcv_win = 256 * 1024; -module_param(cxgb3_rcv_win, int, 0644); -MODULE_PARM_DESC(cxgb3_rcv_win, "TCP receive window in bytes (default=256KB)"); - -static int cxgb3_snd_win = 128 * 1024; -module_param(cxgb3_snd_win, int, 0644); -MODULE_PARM_DESC(cxgb3_snd_win, "TCP send window in bytes (default=128KB)"); - -static int cxgb3_rx_credit_thres = 10 * 1024; -module_param(cxgb3_rx_credit_thres, int, 0644); -MODULE_PARM_DESC(rx_credit_thres, - "RX credits return threshold in bytes (default=10KB)"); - -static unsigned int cxgb3_max_connect = 8 * 1024; -module_param(cxgb3_max_connect, uint, 0644); -MODULE_PARM_DESC(cxgb3_max_connect, "Max. # of connections (default=8092)"); - -static unsigned int cxgb3_sport_base = 20000; -module_param(cxgb3_sport_base, uint, 0644); -MODULE_PARM_DESC(cxgb3_sport_base, "starting port number (default=20000)"); - -/* - * cxgb3i tcp connection data(per adapter) list - */ -static LIST_HEAD(cdata_list); -static DEFINE_RWLOCK(cdata_rwlock); - -static int c3cn_push_tx_frames(struct s3_conn *c3cn, int req_completion); -static void c3cn_release_offload_resources(struct s3_conn *c3cn); - -/* - * iscsi source port management - * - * Find a free source port in the port allocation map. We use a very simple - * rotor scheme to look for the next free port. - * - * If a source port has been specified make sure that it doesn't collide with - * our normal source port allocation map. If it's outside the range of our - * allocation/deallocation scheme just let them use it. - * - * If the source port is outside our allocation range, the caller is - * responsible for keeping track of their port usage. - */ -static int c3cn_get_port(struct s3_conn *c3cn, struct cxgb3i_sdev_data *cdata) -{ - unsigned int start; - int idx; - - if (!cdata) - goto error_out; - - if (c3cn->saddr.sin_port) { - cxgb3i_log_error("connect, sin_port NON-ZERO %u.\n", - c3cn->saddr.sin_port); - return -EADDRINUSE; - } - - spin_lock_bh(&cdata->lock); - start = idx = cdata->sport_next; - do { - if (++idx >= cxgb3_max_connect) - idx = 0; - if (!cdata->sport_conn[idx]) { - c3cn->saddr.sin_port = htons(cxgb3_sport_base + idx); - cdata->sport_next = idx; - cdata->sport_conn[idx] = c3cn; - spin_unlock_bh(&cdata->lock); - - c3cn_conn_debug("%s reserve port %u.\n", - cdata->cdev->name, - cxgb3_sport_base + idx); - return 0; - } - } while (idx != start); - spin_unlock_bh(&cdata->lock); - -error_out: - return -EADDRNOTAVAIL; -} - -static void c3cn_put_port(struct s3_conn *c3cn) -{ - if (!c3cn->cdev) - return; - - if (c3cn->saddr.sin_port) { - struct cxgb3i_sdev_data *cdata = CXGB3_SDEV_DATA(c3cn->cdev); - int idx = ntohs(c3cn->saddr.sin_port) - cxgb3_sport_base; - - c3cn->saddr.sin_port = 0; - if (idx < 0 || idx >= cxgb3_max_connect) - return; - spin_lock_bh(&cdata->lock); - cdata->sport_conn[idx] = NULL; - spin_unlock_bh(&cdata->lock); - c3cn_conn_debug("%s, release port %u.\n", - cdata->cdev->name, cxgb3_sport_base + idx); - } -} - -static inline void c3cn_set_flag(struct s3_conn *c3cn, enum c3cn_flags flag) -{ - __set_bit(flag, &c3cn->flags); - c3cn_conn_debug("c3cn 0x%p, set %d, s %u, f 0x%lx.\n", - c3cn, flag, c3cn->state, c3cn->flags); -} - -static inline void c3cn_clear_flag(struct s3_conn *c3cn, enum c3cn_flags flag) -{ - __clear_bit(flag, &c3cn->flags); - c3cn_conn_debug("c3cn 0x%p, clear %d, s %u, f 0x%lx.\n", - c3cn, flag, c3cn->state, c3cn->flags); -} - -static inline int c3cn_flag(struct s3_conn *c3cn, enum c3cn_flags flag) -{ - if (c3cn == NULL) - return 0; - return test_bit(flag, &c3cn->flags); -} - -static void c3cn_set_state(struct s3_conn *c3cn, int state) -{ - c3cn_conn_debug("c3cn 0x%p state -> %u.\n", c3cn, state); - c3cn->state = state; -} - -static inline void c3cn_hold(struct s3_conn *c3cn) -{ - atomic_inc(&c3cn->refcnt); -} - -static inline void c3cn_put(struct s3_conn *c3cn) -{ - if (atomic_dec_and_test(&c3cn->refcnt)) { - c3cn_conn_debug("free c3cn 0x%p, s %u, f 0x%lx.\n", - c3cn, c3cn->state, c3cn->flags); - kfree(c3cn); - } -} - -static void c3cn_closed(struct s3_conn *c3cn) -{ - c3cn_conn_debug("c3cn 0x%p, state %u, flag 0x%lx.\n", - c3cn, c3cn->state, c3cn->flags); - - c3cn_put_port(c3cn); - c3cn_release_offload_resources(c3cn); - c3cn_set_state(c3cn, C3CN_STATE_CLOSED); - cxgb3i_conn_closing(c3cn); -} - -/* - * CPL (Chelsio Protocol Language) defines a message passing interface between - * the host driver and T3 asic. - * The section below implments CPLs that related to iscsi tcp connection - * open/close/abort and data send/receive. - */ - -/* - * CPL connection active open request: host -> - */ -static unsigned int find_best_mtu(const struct t3c_data *d, unsigned short mtu) -{ - int i = 0; - - while (i < d->nmtus - 1 && d->mtus[i + 1] <= mtu) - ++i; - return i; -} - -static unsigned int select_mss(struct s3_conn *c3cn, unsigned int pmtu) -{ - unsigned int idx; - struct dst_entry *dst = c3cn->dst_cache; - struct t3cdev *cdev = c3cn->cdev; - const struct t3c_data *td = T3C_DATA(cdev); - u16 advmss = dst_metric(dst, RTAX_ADVMSS); - - if (advmss > pmtu - 40) - advmss = pmtu - 40; - if (advmss < td->mtus[0] - 40) - advmss = td->mtus[0] - 40; - idx = find_best_mtu(td, advmss + 40); - return idx; -} - -static inline int compute_wscale(int win) -{ - int wscale = 0; - while (wscale < 14 && (65535<<wscale) < win) - wscale++; - return wscale; -} - -static inline unsigned int calc_opt0h(struct s3_conn *c3cn) -{ - int wscale = compute_wscale(cxgb3_rcv_win); - return V_KEEP_ALIVE(1) | - F_TCAM_BYPASS | - V_WND_SCALE(wscale) | - V_MSS_IDX(c3cn->mss_idx); -} - -static inline unsigned int calc_opt0l(struct s3_conn *c3cn) -{ - return V_ULP_MODE(ULP_MODE_ISCSI) | - V_RCV_BUFSIZ(cxgb3_rcv_win>>10); -} - -static void make_act_open_req(struct s3_conn *c3cn, struct sk_buff *skb, - unsigned int atid, const struct l2t_entry *e) -{ - struct cpl_act_open_req *req; - - c3cn_conn_debug("c3cn 0x%p, atid 0x%x.\n", c3cn, atid); - - 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; - req->local_ip = c3cn->saddr.sin_addr.s_addr; - req->peer_ip = c3cn->daddr.sin_addr.s_addr; - req->opt0h = htonl(calc_opt0h(c3cn) | V_L2T_IDX(e->idx) | - 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) -{ - c3cn_conn_debug("c3cn 0x%p, state %u, flag 0x%lx.\n", - c3cn, c3cn->state, c3cn->flags); - c3cn->err = errno; - c3cn_closed(c3cn); -} - -static void act_open_req_arp_failure(struct t3cdev *dev, struct sk_buff *skb) -{ - struct s3_conn *c3cn = (struct s3_conn *)skb->sk; - - c3cn_conn_debug("c3cn 0x%p, state %u.\n", c3cn, c3cn->state); - - c3cn_hold(c3cn); - spin_lock_bh(&c3cn->lock); - if (c3cn->state == C3CN_STATE_CONNECTING) - fail_act_open(c3cn, -EHOSTUNREACH); - spin_unlock_bh(&c3cn->lock); - c3cn_put(c3cn); - __kfree_skb(skb); -} - -/* - * CPL connection close request: host -> - * - * Close a connection by sending a CPL_CLOSE_CON_REQ message and queue it to - * the write queue (i.e., after any unsent txt data). - */ -static void skb_entail(struct s3_conn *c3cn, struct sk_buff *skb, - int flags) -{ - skb_tcp_seq(skb) = c3cn->write_seq; - skb_flags(skb) = flags; - __skb_queue_tail(&c3cn->write_queue, skb); -} - -static void send_close_req(struct s3_conn *c3cn) -{ - struct sk_buff *skb = c3cn->cpl_close; - struct cpl_close_con_req *req = (struct cpl_close_con_req *)skb->head; - unsigned int tid = c3cn->tid; - - c3cn_conn_debug("c3cn 0x%p, state 0x%x, flag 0x%lx.\n", - c3cn, c3cn->state, c3cn->flags); - - c3cn->cpl_close = NULL; - - req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_CLOSE_CON)); - req->wr.wr_lo = htonl(V_WR_TID(tid)); - OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_CLOSE_CON_REQ, tid)); - req->rsvd = htonl(c3cn->write_seq); - - skb_entail(c3cn, skb, C3CB_FLAG_NO_APPEND); - if (c3cn->state != C3CN_STATE_CONNECTING) - c3cn_push_tx_frames(c3cn, 1); -} - -/* - * CPL connection abort request: host -> - * - * Send an ABORT_REQ message. Makes sure we do not send multiple ABORT_REQs - * for the same connection and also that we do not try to send a message - * after the connection has closed. - */ -static void abort_arp_failure(struct t3cdev *cdev, struct sk_buff *skb) -{ - struct cpl_abort_req *req = cplhdr(skb); - - c3cn_conn_debug("tdev 0x%p.\n", cdev); - - req->cmd = CPL_ABORT_NO_RST; - cxgb3_ofld_send(cdev, skb); -} - -static inline void c3cn_purge_write_queue(struct s3_conn *c3cn) -{ - struct sk_buff *skb; - - while ((skb = __skb_dequeue(&c3cn->write_queue))) - __kfree_skb(skb); -} - -static void send_abort_req(struct s3_conn *c3cn) -{ - struct sk_buff *skb = c3cn->cpl_abort_req; - struct cpl_abort_req *req; - unsigned int tid = c3cn->tid; - - if (unlikely(c3cn->state == C3CN_STATE_ABORTING) || !skb || - !c3cn->cdev) - return; - - c3cn_set_state(c3cn, C3CN_STATE_ABORTING); - - c3cn_conn_debug("c3cn 0x%p, flag ABORT_RPL + ABORT_SHUT.\n", c3cn); - - c3cn_set_flag(c3cn, C3CN_ABORT_RPL_PENDING); - - /* Purge the send queue so we don't send anything after an abort. */ - c3cn_purge_write_queue(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); - - req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_HOST_ABORT_CON_REQ)); - req->wr.wr_lo = htonl(V_WR_TID(tid)); - OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_ABORT_REQ, tid)); - req->rsvd0 = htonl(c3cn->snd_nxt); - req->rsvd1 = !c3cn_flag(c3cn, C3CN_TX_DATA_SENT); - req->cmd = CPL_ABORT_SEND_RST; - - l2t_send(c3cn->cdev, skb, c3cn->l2t); -} - -/* - * CPL connection abort reply: host -> - * - * Send an ABORT_RPL message in response of the ABORT_REQ received. - */ -static void send_abort_rpl(struct s3_conn *c3cn, int rst_status) -{ - struct sk_buff *skb = c3cn->cpl_abort_rpl; - struct cpl_abort_rpl *rpl = (struct cpl_abort_rpl *)skb->head; - - 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)); - rpl->cmd = rst_status; - - cxgb3_ofld_send(c3cn->cdev, skb); -} - -/* - * CPL connection rx data ack: host -> - * Send RX credits through an RX_DATA_ACK CPL message. Returns the number of - * credits sent. - */ -static u32 send_rx_credits(struct s3_conn *c3cn, u32 credits, u32 dack) -{ - struct sk_buff *skb; - struct cpl_rx_data_ack *req; - - skb = alloc_skb(sizeof(*req), GFP_ATOMIC); - if (!skb) - return 0; - - 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; - cxgb3_ofld_send(c3cn->cdev, skb); - return credits; -} - -/* - * CPL connection tx data: host -> - * - * Send iscsi PDU via TX_DATA CPL message. Returns the number of - * credits sent. - * Each TX_DATA consumes work request credit (wrs), so we need to keep track of - * how many we've used so far and how many are pending (i.e., yet ack'ed by T3). - */ - -/* - * For ULP connections HW may inserts digest bytes into the pdu. Those digest - * bytes are not sent by the host but are part of the TCP payload and therefore - * consume TCP sequence space. - */ -static const unsigned int cxgb3_ulp_extra_len[] = { 0, 4, 4, 8 }; -static inline unsigned int ulp_extra_len(const struct sk_buff *skb) -{ - return cxgb3_ulp_extra_len[skb_ulp_mode(skb) & 3]; -} - -static unsigned int wrlen __read_mostly; - -/* - * The number of WRs needed for an skb depends on the number of fragments - * in the skb and whether it has any payload in its main body. This maps the - * length of the gather list represented by an skb into the # of necessary WRs. - * The extra two fragments are for iscsi bhs and payload padding. - */ -#define SKB_WR_LIST_SIZE (MAX_SKB_FRAGS + 2) -static unsigned int skb_wrs[SKB_WR_LIST_SIZE] __read_mostly; - -static void s3_init_wr_tab(unsigned int wr_len) -{ - int i; - - if (skb_wrs[1]) /* already initialized */ - return; - - for (i = 1; i < SKB_WR_LIST_SIZE; i++) { - int sgl_len = (3 * i) / 2 + (i & 1); - - sgl_len += 3; - skb_wrs[i] = (sgl_len <= wr_len - ? 1 : 1 + (sgl_len - 2) / (wr_len - 1)); - } - - wrlen = wr_len * 8; -} - -static inline void reset_wr_list(struct s3_conn *c3cn) -{ - c3cn->wr_pending_head = c3cn->wr_pending_tail = NULL; -} - -/* - * Add a WR to a connections's list of pending WRs. This is a singly-linked - * list of sk_buffs operating as a FIFO. The head is kept in wr_pending_head - * and the tail in wr_pending_tail. - */ -static inline void enqueue_wr(struct s3_conn *c3cn, - struct sk_buff *skb) -{ - skb_tx_wr_next(skb) = NULL; - - /* - * We want to take an extra reference since both us and the driver - * need to free the packet before it's really freed. We know there's - * just one user currently so we use atomic_set rather than skb_get - * to avoid the atomic op. - */ - atomic_set(&skb->users, 2); - - if (!c3cn->wr_pending_head) - c3cn->wr_pending_head = skb; - else - skb_tx_wr_next(c3cn->wr_pending_tail) = skb; - c3cn->wr_pending_tail = skb; -} - -static int count_pending_wrs(struct s3_conn *c3cn) -{ - int n = 0; - const struct sk_buff *skb = c3cn->wr_pending_head; - - while (skb) { - n += skb->csum; - skb = skb_tx_wr_next(skb); - } - return n; -} - -static inline struct sk_buff *peek_wr(const struct s3_conn *c3cn) -{ - return c3cn->wr_pending_head; -} - -static inline void free_wr_skb(struct sk_buff *skb) -{ - kfree_skb(skb); -} - -static inline struct sk_buff *dequeue_wr(struct s3_conn *c3cn) -{ - struct sk_buff *skb = c3cn->wr_pending_head; - - if (likely(skb)) { - /* Don't bother clearing the tail */ - c3cn->wr_pending_head = skb_tx_wr_next(skb); - skb_tx_wr_next(skb) = NULL; - } - return skb; -} - -static void purge_wr_queue(struct s3_conn *c3cn) -{ - struct sk_buff *skb; - while ((skb = dequeue_wr(c3cn)) != NULL) - free_wr_skb(skb); -} - -static inline void make_tx_data_wr(struct s3_conn *c3cn, struct sk_buff *skb, - int len, int req_completion) -{ - struct tx_data_wr *req; - - skb_reset_transport_header(skb); - req = (struct tx_data_wr *)__skb_push(skb, sizeof(*req)); - req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA) | - (req_completion ? F_WR_COMPL : 0)); - req->wr_lo = htonl(V_WR_TID(c3cn->tid)); - req->sndseq = htonl(c3cn->snd_nxt); - /* len includes the length of any HW ULP additions */ - req->len = htonl(len); - req->param = htonl(V_TX_PORT(c3cn->l2t->smt_idx)); - /* V_TX_ULP_SUBMODE sets both the mode and submode */ - req->flags = htonl(V_TX_ULP_SUBMODE(skb_ulp_mode(skb)) | - V_TX_SHOVE((skb_peek(&c3cn->write_queue) ? 0 : 1))); - - if (!c3cn_flag(c3cn, C3CN_TX_DATA_SENT)) { - req->flags |= htonl(V_TX_ACK_PAGES(2) | F_TX_INIT | - V_TX_CPU_IDX(c3cn->qset)); - /* Sendbuffer is in units of 32KB. */ - req->param |= htonl(V_TX_SNDBUF(cxgb3_snd_win >> 15)); - c3cn_set_flag(c3cn, C3CN_TX_DATA_SENT); - } -} - -/** - * c3cn_push_tx_frames -- start transmit - * @c3cn: the offloaded connection - * @req_completion: request wr_ack or not - * - * Prepends TX_DATA_WR or CPL_CLOSE_CON_REQ headers to buffers waiting in a - * connection's send queue and sends them on to T3. Must be called with the - * connection's lock held. Returns the amount of send buffer space that was - * freed as a result of sending queued data to T3. - */ -static void arp_failure_discard(struct t3cdev *cdev, struct sk_buff *skb) -{ - kfree_skb(skb); -} - -static int c3cn_push_tx_frames(struct s3_conn *c3cn, int req_completion) -{ - int total_size = 0; - struct sk_buff *skb; - struct t3cdev *cdev; - struct cxgb3i_sdev_data *cdata; - - if (unlikely(c3cn->state == C3CN_STATE_CONNECTING || - c3cn->state == C3CN_STATE_CLOSE_WAIT_1 || - c3cn->state >= C3CN_STATE_ABORTING)) { - c3cn_tx_debug("c3cn 0x%p, in closing state %u.\n", - c3cn, c3cn->state); - return 0; - } - - cdev = c3cn->cdev; - cdata = CXGB3_SDEV_DATA(cdev); - - while (c3cn->wr_avail - && (skb = skb_peek(&c3cn->write_queue)) != NULL) { - int len = skb->len; /* length before skb_push */ - int frags = skb_shinfo(skb)->nr_frags + (len != skb->data_len); - int wrs_needed = skb_wrs[frags]; - - if (wrs_needed > 1 && len + sizeof(struct tx_data_wr) <= wrlen) - wrs_needed = 1; - - WARN_ON(frags >= SKB_WR_LIST_SIZE || wrs_needed < 1); - - if (c3cn->wr_avail < wrs_needed) { - c3cn_tx_debug("c3cn 0x%p, skb len %u/%u, frag %u, " - "wr %d < %u.\n", - c3cn, skb->len, skb->data_len, frags, - wrs_needed, c3cn->wr_avail); - break; - } - - __skb_unlink(skb, &c3cn->write_queue); - skb->priority = CPL_PRIORITY_DATA; - skb->csum = wrs_needed; /* remember this until the WR_ACK */ - c3cn->wr_avail -= wrs_needed; - c3cn->wr_unacked += wrs_needed; - enqueue_wr(c3cn, skb); - - c3cn_tx_debug("c3cn 0x%p, enqueue, skb len %u/%u, frag %u, " - "wr %d, left %u, unack %u.\n", - c3cn, skb->len, skb->data_len, frags, - wrs_needed, c3cn->wr_avail, c3cn->wr_unacked); - - - if (likely(skb_flags(skb) & C3CB_FLAG_NEED_HDR)) { - if ((req_completion && - c3cn->wr_unacked == wrs_needed) || - (skb_flags(skb) & C3CB_FLAG_COMPL) || - c3cn->wr_unacked >= c3cn->wr_max / 2) { - req_completion = 1; - c3cn->wr_unacked = 0; - } - len += ulp_extra_len(skb); - make_tx_data_wr(c3cn, skb, len, req_completion); - c3cn->snd_nxt += len; - skb_flags(skb) &= ~C3CB_FLAG_NEED_HDR; - } - - total_size += skb->truesize; - set_arp_failure_handler(skb, arp_failure_discard); - l2t_send(cdev, skb, c3cn->l2t); - } - return total_size; -} - -/* - * process_cpl_msg: -> host - * Top-level CPL message processing used by most CPL messages that - * pertain to connections. - */ -static inline void process_cpl_msg(void (*fn)(struct s3_conn *, - struct sk_buff *), - struct s3_conn *c3cn, - struct sk_buff *skb) -{ - spin_lock_bh(&c3cn->lock); - fn(c3cn, skb); - spin_unlock_bh(&c3cn->lock); -} - -/* - * process_cpl_msg_ref: -> host - * Similar to process_cpl_msg() but takes an extra connection reference around - * the call to the handler. Should be used if the handler may drop a - * connection reference. - */ -static inline void process_cpl_msg_ref(void (*fn) (struct s3_conn *, - struct sk_buff *), - struct s3_conn *c3cn, - struct sk_buff *skb) -{ - c3cn_hold(c3cn); - process_cpl_msg(fn, c3cn, skb); - c3cn_put(c3cn); -} - -/* - * Process a CPL_ACT_ESTABLISH message: -> host - * Updates connection state from an active establish CPL message. Runs with - * the connection lock held. - */ - -static inline void s3_free_atid(struct t3cdev *cdev, unsigned int tid) -{ - struct s3_conn *c3cn = cxgb3_free_atid(cdev, tid); - if (c3cn) - c3cn_put(c3cn); -} - -static void c3cn_established(struct s3_conn *c3cn, u32 snd_isn, - unsigned int opt) -{ - c3cn_conn_debug("c3cn 0x%p, state %u.\n", c3cn, c3cn->state); - - c3cn->write_seq = c3cn->snd_nxt = c3cn->snd_una = snd_isn; - - /* - * Causes the first RX_DATA_ACK to supply any Rx credits we couldn't - * pass through opt0. - */ - if (cxgb3_rcv_win > (M_RCV_BUFSIZ << 10)) - c3cn->rcv_wup -= cxgb3_rcv_win - (M_RCV_BUFSIZ << 10); - - dst_confirm(c3cn->dst_cache); - - smp_mb(); - - c3cn_set_state(c3cn, C3CN_STATE_ESTABLISHED); -} - -static void process_act_establish(struct s3_conn *c3cn, struct sk_buff *skb) -{ - struct cpl_act_establish *req = cplhdr(skb); - u32 rcv_isn = ntohl(req->rcv_isn); /* real RCV_ISN + 1 */ - - c3cn_conn_debug("c3cn 0x%p, state %u, flag 0x%lx.\n", - c3cn, c3cn->state, c3cn->flags); - - if (unlikely(c3cn->state != C3CN_STATE_CONNECTING)) - cxgb3i_log_error("TID %u expected SYN_SENT, got EST., s %u\n", - c3cn->tid, c3cn->state); - - c3cn->copied_seq = c3cn->rcv_wup = c3cn->rcv_nxt = rcv_isn; - c3cn_established(c3cn, ntohl(req->snd_isn), ntohs(req->tcp_opt)); - - __kfree_skb(skb); - - if (unlikely(c3cn_flag(c3cn, C3CN_ACTIVE_CLOSE_NEEDED))) - /* upper layer has requested closing */ - send_abort_req(c3cn); - else { - if (skb_queue_len(&c3cn->write_queue)) - c3cn_push_tx_frames(c3cn, 1); - cxgb3i_conn_tx_open(c3cn); - } -} - -static int do_act_establish(struct t3cdev *cdev, struct sk_buff *skb, - void *ctx) -{ - struct cpl_act_establish *req = cplhdr(skb); - unsigned int tid = GET_TID(req); - unsigned int atid = G_PASS_OPEN_TID(ntohl(req->tos_tid)); - struct s3_conn *c3cn = ctx; - struct cxgb3i_sdev_data *cdata = CXGB3_SDEV_DATA(cdev); - - c3cn_conn_debug("rcv, tid 0x%x, c3cn 0x%p, s %u, f 0x%lx.\n", - tid, c3cn, c3cn->state, c3cn->flags); - - c3cn->tid = tid; - c3cn_hold(c3cn); - cxgb3_insert_tid(cdata->cdev, cdata->client, c3cn, tid); - s3_free_atid(cdev, atid); - - c3cn->qset = G_QNUM(ntohl(skb->csum)); - - process_cpl_msg(process_act_establish, c3cn, skb); - return 0; -} - -/* - * Process a CPL_ACT_OPEN_RPL message: -> host - * Handle active open failures. - */ -static int act_open_rpl_status_to_errno(int status) -{ - switch (status) { - case CPL_ERR_CONN_RESET: - return -ECONNREFUSED; - case CPL_ERR_ARP_MISS: - return -EHOSTUNREACH; - case CPL_ERR_CONN_TIMEDOUT: - return -ETIMEDOUT; - case CPL_ERR_TCAM_FULL: - return -ENOMEM; - case CPL_ERR_CONN_EXIST: - cxgb3i_log_error("ACTIVE_OPEN_RPL: 4-tuple in use\n"); - return -EADDRINUSE; - default: - return -EIO; - } -} - -static void act_open_retry_timer(unsigned long data) -{ - struct sk_buff *skb; - struct s3_conn *c3cn = (struct s3_conn *)data; - - c3cn_conn_debug("c3cn 0x%p, state %u.\n", c3cn, c3cn->state); - - spin_lock_bh(&c3cn->lock); - skb = alloc_skb(sizeof(struct cpl_act_open_req), GFP_ATOMIC); - if (!skb) - fail_act_open(c3cn, -ENOMEM); - else { - skb->sk = (struct sock *)c3cn; - set_arp_failure_handler(skb, act_open_req_arp_failure); - make_act_open_req(c3cn, skb, c3cn->tid, c3cn->l2t); - l2t_send(c3cn->cdev, skb, c3cn->l2t); - } - spin_unlock_bh(&c3cn->lock); - c3cn_put(c3cn); -} - -static void process_act_open_rpl(struct s3_conn *c3cn, struct sk_buff *skb) -{ - struct cpl_act_open_rpl *rpl = cplhdr(skb); - - c3cn_conn_debug("c3cn 0x%p, state %u, flag 0x%lx.\n", - c3cn, c3cn->state, c3cn->flags); - - if (rpl->status == CPL_ERR_CONN_EXIST && - c3cn->retry_timer.function != act_open_retry_timer) { - c3cn->retry_timer.function = act_open_retry_timer; - if (!mod_timer(&c3cn->retry_timer, jiffies + HZ / 2)) - c3cn_hold(c3cn); - } else - fail_act_open(c3cn, act_open_rpl_status_to_errno(rpl->status)); - __kfree_skb(skb); -} - -static int do_act_open_rpl(struct t3cdev *cdev, struct sk_buff *skb, void *ctx) -{ - struct s3_conn *c3cn = ctx; - struct cpl_act_open_rpl *rpl = cplhdr(skb); - - c3cn_conn_debug("rcv, status 0x%x, c3cn 0x%p, s %u, f 0x%lx.\n", - rpl->status, c3cn, c3cn->state, c3cn->flags); - - if (rpl->status != CPL_ERR_TCAM_FULL && - rpl->status != CPL_ERR_CONN_EXIST && - rpl->status != CPL_ERR_ARP_MISS) - cxgb3_queue_tid_release(cdev, GET_TID(rpl)); - - process_cpl_msg_ref(process_act_open_rpl, c3cn, skb); - return 0; -} - -/* - * Process PEER_CLOSE CPL messages: -> host - * Handle peer FIN. - */ -static void process_peer_close(struct s3_conn *c3cn, struct sk_buff *skb) -{ - c3cn_conn_debug("c3cn 0x%p, state %u, flag 0x%lx.\n", - c3cn, c3cn->state, c3cn->flags); - - if (c3cn_flag(c3cn, C3CN_ABORT_RPL_PENDING)) - goto out; - - switch (c3cn->state) { - case C3CN_STATE_ESTABLISHED: - c3cn_set_state(c3cn, C3CN_STATE_PASSIVE_CLOSE); - break; - case C3CN_STATE_ACTIVE_CLOSE: - c3cn_set_state(c3cn, C3CN_STATE_CLOSE_WAIT_2); - break; - case C3CN_STATE_CLOSE_WAIT_1: - c3cn_closed(c3cn); - break; - case C3CN_STATE_ABORTING: - break; - default: - cxgb3i_log_error("%s: peer close, TID %u in bad state %u\n", - c3cn->cdev->name, c3cn->tid, c3cn->state); - } - - cxgb3i_conn_closing(c3cn); -out: - __kfree_skb(skb); -} - -static int do_peer_close(struct t3cdev *cdev, struct sk_buff *skb, void *ctx) -{ - struct s3_conn *c3cn = ctx; - - c3cn_conn_debug("rcv, c3cn 0x%p, s %u, f 0x%lx.\n", - c3cn, c3cn->state, c3cn->flags); - process_cpl_msg_ref(process_peer_close, c3cn, skb); - return 0; -} - -/* - * Process CLOSE_CONN_RPL CPL message: -> host - * Process a peer ACK to our FIN. - */ -static void process_close_con_rpl(struct s3_conn *c3cn, struct sk_buff *skb) -{ - struct cpl_close_con_rpl *rpl = cplhdr(skb); - - c3cn_conn_debug("c3cn 0x%p, state %u, flag 0x%lx.\n", - c3cn, c3cn->state, c3cn->flags); - - c3cn->snd_una = ntohl(rpl->snd_nxt) - 1; /* exclude FIN */ - - if (c3cn_flag(c3cn, C3CN_ABORT_RPL_PENDING)) - goto out; - - switch (c3cn->state) { - case C3CN_STATE_ACTIVE_CLOSE: - c3cn_set_state(c3cn, C3CN_STATE_CLOSE_WAIT_1); - break; - case C3CN_STATE_CLOSE_WAIT_1: - case C3CN_STATE_CLOSE_WAIT_2: - c3cn_closed(c3cn); - break; - case C3CN_STATE_ABORTING: - break; - default: - cxgb3i_log_error("%s: close_rpl, TID %u in bad state %u\n", - c3cn->cdev->name, c3cn->tid, c3cn->state); - } - -out: - kfree_skb(skb); -} - -static int do_close_con_rpl(struct t3cdev *cdev, struct sk_buff *skb, - void *ctx) -{ - struct s3_conn *c3cn = ctx; - - c3cn_conn_debug("rcv, c3cn 0x%p, s %u, f 0x%lx.\n", - c3cn, c3cn->state, c3cn->flags); - - process_cpl_msg_ref(process_close_con_rpl, c3cn, skb); - return 0; -} - -/* - * Process ABORT_REQ_RSS CPL message: -> host - * Process abort requests. If we are waiting for an ABORT_RPL we ignore this - * request except that we need to reply to it. - */ - -static int abort_status_to_errno(struct s3_conn *c3cn, int abort_reason, - int *need_rst) -{ - switch (abort_reason) { - case CPL_ERR_BAD_SYN: /* fall through */ - case CPL_ERR_CONN_RESET: - return c3cn->state > C3CN_STATE_ESTABLISHED ? - -EPIPE : -ECONNRESET; - case CPL_ERR_XMIT_TIMEDOUT: - case CPL_ERR_PERSIST_TIMEDOUT: - case CPL_ERR_FINWAIT2_TIMEDOUT: - case CPL_ERR_KEEPALIVE_TIMEDOUT: - return -ETIMEDOUT; - default: - return -EIO; - } -} - -static void process_abort_req(struct s3_conn *c3cn, struct sk_buff *skb) -{ - int rst_status = CPL_ABORT_NO_RST; - const struct cpl_abort_req_rss *req = cplhdr(skb); - - c3cn_conn_debug("c3cn 0x%p, state %u, flag 0x%lx.\n", - c3cn, c3cn->state, c3cn->flags); - - if (!c3cn_flag(c3cn, C3CN_ABORT_REQ_RCVD)) { - c3cn_set_flag(c3cn, C3CN_ABORT_REQ_RCVD); - c3cn_set_state(c3cn, C3CN_STATE_ABORTING); - __kfree_skb(skb); - return; - } - - c3cn_clear_flag(c3cn, C3CN_ABORT_REQ_RCVD); - send_abort_rpl(c3cn, rst_status); - - if (!c3cn_flag(c3cn, C3CN_ABORT_RPL_PENDING)) { - c3cn->err = - abort_status_to_errno(c3cn, req->status, &rst_status); - c3cn_closed(c3cn); - } -} - -static int do_abort_req(struct t3cdev *cdev, struct sk_buff *skb, void *ctx) -{ - const struct cpl_abort_req_rss *req = cplhdr(skb); - struct s3_conn *c3cn = ctx; - - c3cn_conn_debug("rcv, c3cn 0x%p, s 0x%x, f 0x%lx.\n", - c3cn, c3cn->state, c3cn->flags); - - if (req->status == CPL_ERR_RTX_NEG_ADVICE || - req->status == CPL_ERR_PERSIST_NEG_ADVICE) { - __kfree_skb(skb); - return 0; - } - - process_cpl_msg_ref(process_abort_req, c3cn, skb); - return 0; -} - -/* - * Process ABORT_RPL_RSS CPL message: -> host - * Process abort replies. We only process these messages if we anticipate - * them as the coordination between SW and HW in this area is somewhat lacking - * and sometimes we get ABORT_RPLs after we are done with the connection that - * originated the ABORT_REQ. - */ -static void process_abort_rpl(struct s3_conn *c3cn, struct sk_buff *skb) -{ - c3cn_conn_debug("c3cn 0x%p, state %u, flag 0x%lx.\n", - c3cn, c3cn->state, c3cn->flags); - - if (c3cn_flag(c3cn, C3CN_ABORT_RPL_PENDING)) { - if (!c3cn_flag(c3cn, C3CN_ABORT_RPL_RCVD)) - c3cn_set_flag(c3cn, C3CN_ABORT_RPL_RCVD); - else { - c3cn_clear_flag(c3cn, C3CN_ABORT_RPL_RCVD); - c3cn_clear_flag(c3cn, C3CN_ABORT_RPL_PENDING); - if (c3cn_flag(c3cn, C3CN_ABORT_REQ_RCVD)) - cxgb3i_log_error("%s tid %u, ABORT_RPL_RSS\n", - c3cn->cdev->name, c3cn->tid); - c3cn_closed(c3cn); - } - } - __kfree_skb(skb); -} - -static int do_abort_rpl(struct t3cdev *cdev, struct sk_buff *skb, void *ctx) -{ - struct cpl_abort_rpl_rss *rpl = cplhdr(skb); - struct s3_conn *c3cn = ctx; - - c3cn_conn_debug("rcv, status 0x%x, c3cn 0x%p, s %u, 0x%lx.\n", - rpl->status, c3cn, c3cn ? c3cn->state : 0, - c3cn ? c3cn->flags : 0UL); - - /* - * Ignore replies to post-close aborts indicating that the abort was - * requested too late. These connections are terminated when we get - * PEER_CLOSE or CLOSE_CON_RPL and by the time the abort_rpl_rss - * arrives the TID is either no longer used or it has been recycled. - */ - if (rpl->status == CPL_ERR_ABORT_FAILED) - goto discard; - - /* - * Sometimes we've already closed the connection, e.g., a post-close - * abort races with ABORT_REQ_RSS, the latter frees the connection - * expecting the ABORT_REQ will fail with CPL_ERR_ABORT_FAILED, - * but FW turns the ABORT_REQ into a regular one and so we get - * ABORT_RPL_RSS with status 0 and no connection. - */ - if (!c3cn) - goto discard; - - process_cpl_msg_ref(process_abort_rpl, c3cn, skb); - return 0; - -discard: - __kfree_skb(skb); - return 0; -} - -/* - * Process RX_ISCSI_HDR CPL message: -> host - * Handle received PDUs, the payload could be DDP'ed. If not, the payload - * follow after the bhs. - */ -static void process_rx_iscsi_hdr(struct s3_conn *c3cn, struct sk_buff *skb) -{ - struct cpl_iscsi_hdr *hdr_cpl = cplhdr(skb); - struct cpl_iscsi_hdr_norss data_cpl; - struct cpl_rx_data_ddp_norss ddp_cpl; - unsigned int hdr_len, data_len, status; - unsigned int len; - int err; - - if (unlikely(c3cn->state >= C3CN_STATE_PASSIVE_CLOSE)) { - if (c3cn->state != C3CN_STATE_ABORTING) - send_abort_req(c3cn); - __kfree_skb(skb); - return; - } - - skb_tcp_seq(skb) = ntohl(hdr_cpl->seq); - skb_flags(skb) = 0; - - skb_reset_transport_header(skb); - __skb_pull(skb, sizeof(struct cpl_iscsi_hdr)); - - len = hdr_len = ntohs(hdr_cpl->len); - /* msg coalesce is off or not enough data received */ - if (skb->len <= hdr_len) { - cxgb3i_log_error("%s: TID %u, ISCSI_HDR, skb len %u < %u.\n", - c3cn->cdev->name, c3cn->tid, - skb->len, hdr_len); - goto abort_conn; - } - - err = skb_copy_bits(skb, skb->len - sizeof(ddp_cpl), &ddp_cpl, - sizeof(ddp_cpl)); - if (err < 0) - goto abort_conn; - - skb_ulp_mode(skb) = ULP2_FLAG_DATA_READY; - skb_rx_pdulen(skb) = ntohs(ddp_cpl.len); - skb_rx_ddigest(skb) = ntohl(ddp_cpl.ulp_crc); - status = ntohl(ddp_cpl.ddp_status); - - c3cn_rx_debug("rx skb 0x%p, len %u, pdulen %u, ddp status 0x%x.\n", - skb, skb->len, skb_rx_pdulen(skb), status); - - if (status & (1 << RX_DDP_STATUS_HCRC_SHIFT)) - skb_ulp_mode(skb) |= ULP2_FLAG_HCRC_ERROR; - if (status & (1 << RX_DDP_STATUS_DCRC_SHIFT)) - skb_ulp_mode(skb) |= ULP2_FLAG_DCRC_ERROR; - if (status & (1 << RX_DDP_STATUS_PAD_SHIFT)) - skb_ulp_mode(skb) |= ULP2_FLAG_PAD_ERROR; - - if (skb->len > (hdr_len + sizeof(ddp_cpl))) { - err = skb_copy_bits(skb, hdr_len, &data_cpl, sizeof(data_cpl)); - if (err < 0) - goto abort_conn; - data_len = ntohs(data_cpl.len); - len += sizeof(data_cpl) + data_len; - } else if (status & (1 << RX_DDP_STATUS_DDP_SHIFT)) - skb_ulp_mode(skb) |= ULP2_FLAG_DATA_DDPED; - - c3cn->rcv_nxt = ntohl(ddp_cpl.seq) + skb_rx_pdulen(skb); - __pskb_trim(skb, len); - __skb_queue_tail(&c3cn->receive_queue, skb); - cxgb3i_conn_pdu_ready(c3cn); - - return; - -abort_conn: - send_abort_req(c3cn); - __kfree_skb(skb); -} - -static int do_iscsi_hdr(struct t3cdev *t3dev, struct sk_buff *skb, void *ctx) -{ - struct s3_conn *c3cn = ctx; - - process_cpl_msg(process_rx_iscsi_hdr, c3cn, skb); - return 0; -} - -/* - * Process TX_DATA_ACK CPL messages: -> host - * Process an acknowledgment of WR completion. Advance snd_una and send the - * next batch of work requests from the write queue. - */ -static void check_wr_invariants(struct s3_conn *c3cn) -{ - int pending = count_pending_wrs(c3cn); - - if (unlikely(c3cn->wr_avail + pending != c3cn->wr_max)) - cxgb3i_log_error("TID %u: credit imbalance: avail %u, " - "pending %u, total should be %u\n", - c3cn->tid, c3cn->wr_avail, pending, - c3cn->wr_max); -} - -static void process_wr_ack(struct s3_conn *c3cn, struct sk_buff *skb) -{ - struct cpl_wr_ack *hdr = cplhdr(skb); - unsigned int credits = ntohs(hdr->credits); - u32 snd_una = ntohl(hdr->snd_una); - - c3cn_tx_debug("%u WR credits, avail %u, unack %u, TID %u, state %u.\n", - credits, c3cn->wr_avail, c3cn->wr_unacked, - c3cn->tid, c3cn->state); - - c3cn->wr_avail += credits; - if (c3cn->wr_unacked > c3cn->wr_max - c3cn->wr_avail) - c3cn->wr_unacked = c3cn->wr_max - c3cn->wr_avail; - - while (credits) { - struct sk_buff *p = peek_wr(c3cn); - - if (unlikely(!p)) { - cxgb3i_log_error("%u WR_ACK credits for TID %u with " - "nothing pending, state %u\n", - credits, c3cn->tid, c3cn->state); - break; - } - if (unlikely(credits < p->csum)) { - struct tx_data_wr *w = cplhdr(p); - cxgb3i_log_error("TID %u got %u WR credits need %u, " - "len %u, main body %u, frags %u, " - "seq # %u, ACK una %u, ACK nxt %u, " - "WR_AVAIL %u, WRs pending %u\n", - c3cn->tid, credits, p->csum, p->len, - p->len - p->data_len, - skb_shinfo(p)->nr_frags, - ntohl(w->sndseq), snd_una, - ntohl(hdr->snd_nxt), c3cn->wr_avail, - count_pending_wrs(c3cn) - credits); - p->csum -= credits; - break; - } else { - dequeue_wr(c3cn); - credits -= p->csum; - free_wr_skb(p); - } - } - - check_wr_invariants(c3cn); - - if (unlikely(before(snd_una, c3cn->snd_una))) { - cxgb3i_log_error("TID %u, unexpected sequence # %u in WR_ACK " - "snd_una %u\n", - c3cn->tid, snd_una, c3cn->snd_una); - goto out_free; - } - - if (c3cn->snd_una != snd_una) { - c3cn->snd_una = snd_una; - dst_confirm(c3cn->dst_cache); - } - - if (skb_queue_len(&c3cn->write_queue)) { - if (c3cn_push_tx_frames(c3cn, 0)) - cxgb3i_conn_tx_open(c3cn); - } else - cxgb3i_conn_tx_open(c3cn); -out_free: - __kfree_skb(skb); -} - -static int do_wr_ack(struct t3cdev *cdev, struct sk_buff *skb, void *ctx) -{ - struct s3_conn *c3cn = ctx; - - process_cpl_msg(process_wr_ack, c3cn, skb); - return 0; -} - -/* - * for each connection, pre-allocate skbs needed for close/abort requests. So - * that we can service the request right away. - */ -static void c3cn_free_cpl_skbs(struct s3_conn *c3cn) -{ - if (c3cn->cpl_close) - kfree_skb(c3cn->cpl_close); - if (c3cn->cpl_abort_req) - kfree_skb(c3cn->cpl_abort_req); - if (c3cn->cpl_abort_rpl) - kfree_skb(c3cn->cpl_abort_rpl); -} - -static int c3cn_alloc_cpl_skbs(struct s3_conn *c3cn) -{ - c3cn->cpl_close = alloc_skb(sizeof(struct cpl_close_con_req), - GFP_KERNEL); - if (!c3cn->cpl_close) - return -ENOMEM; - skb_put(c3cn->cpl_close, sizeof(struct cpl_close_con_req)); - - c3cn->cpl_abort_req = alloc_skb(sizeof(struct cpl_abort_req), - GFP_KERNEL); - if (!c3cn->cpl_abort_req) - goto free_cpl_skbs; - skb_put(c3cn->cpl_abort_req, sizeof(struct cpl_abort_req)); - - c3cn->cpl_abort_rpl = alloc_skb(sizeof(struct cpl_abort_rpl), - GFP_KERNEL); - if (!c3cn->cpl_abort_rpl) - goto free_cpl_skbs; - skb_put(c3cn->cpl_abort_rpl, sizeof(struct cpl_abort_rpl)); - - return 0; - -free_cpl_skbs: - c3cn_free_cpl_skbs(c3cn); - return -ENOMEM; -} - -/** - * c3cn_release_offload_resources - release offload resource - * @c3cn: the offloaded iscsi tcp connection. - * Release resources held by an offload connection (TID, L2T entry, etc.) - */ -static void c3cn_release_offload_resources(struct s3_conn *c3cn) -{ - struct t3cdev *cdev = c3cn->cdev; - unsigned int tid = c3cn->tid; - - c3cn->qset = 0; - c3cn_free_cpl_skbs(c3cn); - - if (c3cn->wr_avail != c3cn->wr_max) { - purge_wr_queue(c3cn); - reset_wr_list(c3cn); - } - - if (cdev) { - if (c3cn->l2t) { - l2t_release(L2DATA(cdev), c3cn->l2t); - c3cn->l2t = NULL; - } - if (c3cn->state == C3CN_STATE_CONNECTING) - /* we have ATID */ - s3_free_atid(cdev, tid); - else { - /* we have TID */ - cxgb3_remove_tid(cdev, (void *)c3cn, tid); - c3cn_put(c3cn); - } - } - - c3cn->dst_cache = NULL; - c3cn->cdev = NULL; -} - -/** - * cxgb3i_c3cn_create - allocate and initialize an s3_conn structure - * returns the s3_conn structure allocated. - */ -struct s3_conn *cxgb3i_c3cn_create(void) -{ - struct s3_conn *c3cn; - - c3cn = kzalloc(sizeof(*c3cn), GFP_KERNEL); - if (!c3cn) - return NULL; - - /* pre-allocate close/abort cpl, so we don't need to wait for memory - when close/abort is requested. */ - if (c3cn_alloc_cpl_skbs(c3cn) < 0) - goto free_c3cn; - - c3cn_conn_debug("alloc c3cn 0x%p.\n", c3cn); - - c3cn->flags = 0; - spin_lock_init(&c3cn->lock); - atomic_set(&c3cn->refcnt, 1); - skb_queue_head_init(&c3cn->receive_queue); - skb_queue_head_init(&c3cn->write_queue); - setup_timer(&c3cn->retry_timer, NULL, (unsigned long)c3cn); - rwlock_init(&c3cn->callback_lock); - - return c3cn; - -free_c3cn: - kfree(c3cn); - return NULL; -} - -static void c3cn_active_close(struct s3_conn *c3cn) -{ - int data_lost; - int close_req = 0; - - c3cn_conn_debug("c3cn 0x%p, state %u, flag 0x%lx.\n", - c3cn, c3cn->state, c3cn->flags); - - dst_confirm(c3cn->dst_cache); - - c3cn_hold(c3cn); - spin_lock_bh(&c3cn->lock); - - data_lost = skb_queue_len(&c3cn->receive_queue); - __skb_queue_purge(&c3cn->receive_queue); - - switch (c3cn->state) { - case C3CN_STATE_CLOSED: - case C3CN_STATE_ACTIVE_CLOSE: - case C3CN_STATE_CLOSE_WAIT_1: - case C3CN_STATE_CLOSE_WAIT_2: - case C3CN_STATE_ABORTING: - /* nothing need to be done */ - break; - case C3CN_STATE_CONNECTING: - /* defer until cpl_act_open_rpl or cpl_act_establish */ - c3cn_set_flag(c3cn, C3CN_ACTIVE_CLOSE_NEEDED); - break; - case C3CN_STATE_ESTABLISHED: - close_req = 1; - c3cn_set_state(c3cn, C3CN_STATE_ACTIVE_CLOSE); - break; - case C3CN_STATE_PASSIVE_CLOSE: - close_req = 1; - c3cn_set_state(c3cn, C3CN_STATE_CLOSE_WAIT_2); - break; - } - - if (close_req) { - if (data_lost) - /* Unread data was tossed, zap the connection. */ - send_abort_req(c3cn); - else - send_close_req(c3cn); - } - - spin_unlock_bh(&c3cn->lock); - c3cn_put(c3cn); -} - -/** - * cxgb3i_c3cn_release - close and release an iscsi tcp connection and any - * resource held - * @c3cn: the iscsi tcp connection - */ -void cxgb3i_c3cn_release(struct s3_conn *c3cn) -{ - c3cn_conn_debug("c3cn 0x%p, s %u, f 0x%lx.\n", - c3cn, c3cn->state, c3cn->flags); - if (unlikely(c3cn->state == C3CN_STATE_CONNECTING)) - c3cn_set_flag(c3cn, C3CN_ACTIVE_CLOSE_NEEDED); - else if (likely(c3cn->state != C3CN_STATE_CLOSED)) - c3cn_active_close(c3cn); - c3cn_put(c3cn); -} - -static int is_cxgb3_dev(struct net_device *dev) -{ - struct cxgb3i_sdev_data *cdata; - struct net_device *ndev = dev; - - if (dev->priv_flags & IFF_802_1Q_VLAN) - ndev = vlan_dev_real_dev(dev); - - write_lock(&cdata_rwlock); - list_for_each_entry(cdata, &cdata_list, list) { - struct adap_ports *ports = &cdata->ports; - int i; - - for (i = 0; i < ports->nports; i++) - if (ndev == ports->lldevs[i]) { - write_unlock(&cdata_rwlock); - return 1; - } - } - write_unlock(&cdata_rwlock); - return 0; -} - -/** - * cxgb3_egress_dev - return the cxgb3 egress device - * @root_dev: the root device anchoring the search - * @c3cn: the connection used to determine egress port in bonding mode - * @context: in bonding mode, indicates a connection set up or failover - * - * Return egress device or NULL if the egress device isn't one of our ports. - */ -static struct net_device *cxgb3_egress_dev(struct net_device *root_dev, - struct s3_conn *c3cn, - int context) -{ - while (root_dev) { - if (root_dev->priv_flags & IFF_802_1Q_VLAN) - root_dev = vlan_dev_real_dev(root_dev); - else if (is_cxgb3_dev(root_dev)) - return root_dev; - else - return NULL; - } - return NULL; -} - -static struct rtable *find_route(struct net_device *dev, - __be32 saddr, __be32 daddr, - __be16 sport, __be16 dport) -{ - struct rtable *rt; - struct flowi fl = { - .oif = dev ? dev->ifindex : 0, - .nl_u = { - .ip4_u = { - .daddr = daddr, - .saddr = saddr, - .tos = 0 } }, - .proto = IPPROTO_TCP, - .uli_u = { - .ports = { - .sport = sport, - .dport = dport } } }; - - if (ip_route_output_flow(&init_net, &rt, &fl, NULL, 0)) - return NULL; - return rt; -} - -/* - * Assign offload parameters to some connection fields. - */ -static void init_offload_conn(struct s3_conn *c3cn, - struct t3cdev *cdev, - struct dst_entry *dst) -{ - BUG_ON(c3cn->cdev != cdev); - c3cn->wr_max = c3cn->wr_avail = T3C_DATA(cdev)->max_wrs - 1; - c3cn->wr_unacked = 0; - c3cn->mss_idx = select_mss(c3cn, dst_mtu(dst)); - - reset_wr_list(c3cn); -} - -static int initiate_act_open(struct s3_conn *c3cn, struct net_device *dev) -{ - struct cxgb3i_sdev_data *cdata = NDEV2CDATA(dev); - struct t3cdev *cdev = cdata->cdev; - struct dst_entry *dst = c3cn->dst_cache; - struct sk_buff *skb; - - c3cn_conn_debug("c3cn 0x%p, state %u, flag 0x%lx.\n", - c3cn, c3cn->state, c3cn->flags); - /* - * Initialize connection data. Note that the flags and ULP mode are - * initialized higher up ... - */ - c3cn->dev = dev; - c3cn->cdev = cdev; - c3cn->tid = cxgb3_alloc_atid(cdev, cdata->client, c3cn); - if (c3cn->tid < 0) - goto out_err; - - c3cn->qset = 0; - c3cn->l2t = t3_l2t_get(cdev, dst->neighbour, dev); - if (!c3cn->l2t) - goto free_tid; - - skb = alloc_skb(sizeof(struct cpl_act_open_req), GFP_KERNEL); - if (!skb) - goto free_l2t; - - skb->sk = (struct sock *)c3cn; - set_arp_failure_handler(skb, act_open_req_arp_failure); - - c3cn_hold(c3cn); - - init_offload_conn(c3cn, cdev, dst); - c3cn->err = 0; - - make_act_open_req(c3cn, skb, c3cn->tid, c3cn->l2t); - l2t_send(cdev, skb, c3cn->l2t); - return 0; - -free_l2t: - l2t_release(L2DATA(cdev), c3cn->l2t); -free_tid: - s3_free_atid(cdev, c3cn->tid); - c3cn->tid = 0; -out_err: - return -EINVAL; -} - -/** - * cxgb3i_find_dev - find the interface associated with the given address - * @ipaddr: ip address - */ -static struct net_device * -cxgb3i_find_dev(struct net_device *dev, __be32 ipaddr) -{ - struct flowi fl; - int err; - struct rtable *rt; - - memset(&fl, 0, sizeof(fl)); - fl.nl_u.ip4_u.daddr = ipaddr; - - err = ip_route_output_key(dev ? dev_net(dev) : &init_net, &rt, &fl); - if (!err) - return (&rt->dst)->dev; - - return NULL; -} - -/** - * cxgb3i_c3cn_connect - initiates an iscsi tcp connection to a given address - * @c3cn: the iscsi tcp connection - * @usin: destination address - * - * return 0 if active open request is sent, < 0 otherwise. - */ -int cxgb3i_c3cn_connect(struct net_device *dev, struct s3_conn *c3cn, - struct sockaddr_in *usin) -{ - struct rtable *rt; - struct cxgb3i_sdev_data *cdata; - struct t3cdev *cdev; - __be32 sipv4; - struct net_device *dstdev; - int err; - - c3cn_conn_debug("c3cn 0x%p, dev 0x%p.\n", c3cn, dev); - - if (usin->sin_family != AF_INET) - return -EAFNOSUPPORT; - - c3cn->daddr.sin_port = usin->sin_port; - c3cn->daddr.sin_addr.s_addr = usin->sin_addr.s_addr; - - dstdev = cxgb3i_find_dev(dev, usin->sin_addr.s_addr); - if (!dstdev || !is_cxgb3_dev(dstdev)) - return -ENETUNREACH; - - if (dstdev->priv_flags & IFF_802_1Q_VLAN) - dev = dstdev; - - rt = find_route(dev, c3cn->saddr.sin_addr.s_addr, - c3cn->daddr.sin_addr.s_addr, - c3cn->saddr.sin_port, - c3cn->daddr.sin_port); - if (rt == NULL) { - c3cn_conn_debug("NO route to 0x%x, port %u, dev %s.\n", - c3cn->daddr.sin_addr.s_addr, - ntohs(c3cn->daddr.sin_port), - dev ? dev->name : "any"); - return -ENETUNREACH; - } - - if (rt->rt_flags & (RTCF_MULTICAST | RTCF_BROADCAST)) { - c3cn_conn_debug("multi-cast route to 0x%x, port %u, dev %s.\n", - c3cn->daddr.sin_addr.s_addr, - ntohs(c3cn->daddr.sin_port), - dev ? dev->name : "any"); - ip_rt_put(rt); - return -ENETUNREACH; - } - - if (!c3cn->saddr.sin_addr.s_addr) - c3cn->saddr.sin_addr.s_addr = rt->rt_src; - - /* now commit destination to connection */ - c3cn->dst_cache = &rt->dst; - - /* try to establish an offloaded connection */ - dev = cxgb3_egress_dev(c3cn->dst_cache->dev, c3cn, 0); - if (dev == NULL) { - c3cn_conn_debug("c3cn 0x%p, egress dev NULL.\n", c3cn); - return -ENETUNREACH; - } - cdata = NDEV2CDATA(dev); - cdev = cdata->cdev; - - /* get a source port if one hasn't been provided */ - err = c3cn_get_port(c3cn, cdata); - if (err) - return err; - - c3cn_conn_debug("c3cn 0x%p get port %u.\n", - c3cn, ntohs(c3cn->saddr.sin_port)); - - sipv4 = cxgb3i_get_private_ipv4addr(dev); - if (!sipv4) { - c3cn_conn_debug("c3cn 0x%p, iscsi ip not configured.\n", c3cn); - sipv4 = c3cn->saddr.sin_addr.s_addr; - cxgb3i_set_private_ipv4addr(dev, sipv4); - } else - c3cn->saddr.sin_addr.s_addr = sipv4; - - c3cn_conn_debug("c3cn 0x%p, %pI4,%u-%pI4,%u SYN_SENT.\n", - c3cn, - &c3cn->saddr.sin_addr.s_addr, - ntohs(c3cn->saddr.sin_port), - &c3cn->daddr.sin_addr.s_addr, - ntohs(c3cn->daddr.sin_port)); - - c3cn_set_state(c3cn, C3CN_STATE_CONNECTING); - if (!initiate_act_open(c3cn, dev)) - return 0; - - /* - * If we get here, we don't have an offload connection so simply - * return a failure. - */ - err = -ENOTSUPP; - - /* - * This trashes the connection and releases the local port, - * if necessary. - */ - c3cn_conn_debug("c3cn 0x%p -> CLOSED.\n", c3cn); - c3cn_set_state(c3cn, C3CN_STATE_CLOSED); - ip_rt_put(rt); - c3cn_put_port(c3cn); - return err; -} - -/** - * cxgb3i_c3cn_rx_credits - ack received tcp data. - * @c3cn: iscsi tcp connection - * @copied: # of bytes processed - * - * Called after some received data has been read. It returns RX credits - * to the HW for the amount of data processed. - */ -void cxgb3i_c3cn_rx_credits(struct s3_conn *c3cn, int copied) -{ - struct t3cdev *cdev; - int must_send; - u32 credits, dack = 0; - - if (c3cn->state != C3CN_STATE_ESTABLISHED) - return; - - credits = c3cn->copied_seq - c3cn->rcv_wup; - if (unlikely(!credits)) - return; - - cdev = c3cn->cdev; - - if (unlikely(cxgb3_rx_credit_thres == 0)) - return; - - dack = F_RX_DACK_CHANGE | V_RX_DACK_MODE(1); - - /* - * For coalescing to work effectively ensure the receive window has - * at least 16KB left. - */ - must_send = credits + 16384 >= cxgb3_rcv_win; - - if (must_send || credits >= cxgb3_rx_credit_thres) - c3cn->rcv_wup += send_rx_credits(c3cn, credits, dack); -} - -/** - * cxgb3i_c3cn_send_pdus - send the skbs containing iscsi pdus - * @c3cn: iscsi tcp connection - * @skb: skb contains the iscsi pdu - * - * Add a list of skbs to a connection send queue. The skbs must comply with - * the max size limit of the device and have a headroom of at least - * TX_HEADER_LEN bytes. - * Return # of bytes queued. - */ -int cxgb3i_c3cn_send_pdus(struct s3_conn *c3cn, struct sk_buff *skb) -{ - struct sk_buff *next; - int err, copied = 0; - - spin_lock_bh(&c3cn->lock); - - if (c3cn->state != C3CN_STATE_ESTABLISHED) { - c3cn_tx_debug("c3cn 0x%p, not in est. state %u.\n", - c3cn, c3cn->state); - err = -EAGAIN; - goto out_err; - } - - if (c3cn->err) { - c3cn_tx_debug("c3cn 0x%p, err %d.\n", c3cn, c3cn->err); - err = -EPIPE; - goto out_err; - } - - if (c3cn->write_seq - c3cn->snd_una >= cxgb3_snd_win) { - c3cn_tx_debug("c3cn 0x%p, snd %u - %u > %u.\n", - c3cn, c3cn->write_seq, c3cn->snd_una, - cxgb3_snd_win); - err = -ENOBUFS; - goto out_err; - } - - while (skb) { - int frags = skb_shinfo(skb)->nr_frags + - (skb->len != skb->data_len); - - if (unlikely(skb_headroom(skb) < TX_HEADER_LEN)) { - c3cn_tx_debug("c3cn 0x%p, skb head.\n", c3cn); - err = -EINVAL; - goto out_err; - } - - if (frags >= SKB_WR_LIST_SIZE) { - cxgb3i_log_error("c3cn 0x%p, tx frags %d, len %u,%u.\n", - c3cn, skb_shinfo(skb)->nr_frags, - skb->len, skb->data_len); - err = -EINVAL; - goto out_err; - } - - next = skb->next; - skb->next = NULL; - skb_entail(c3cn, skb, C3CB_FLAG_NO_APPEND | C3CB_FLAG_NEED_HDR); - copied += skb->len; - c3cn->write_seq += skb->len + ulp_extra_len(skb); - skb = next; - } -done: - if (likely(skb_queue_len(&c3cn->write_queue))) - c3cn_push_tx_frames(c3cn, 1); - spin_unlock_bh(&c3cn->lock); - return copied; - -out_err: - if (copied == 0 && err == -EPIPE) - copied = c3cn->err ? c3cn->err : -EPIPE; - else - copied = err; - goto done; -} - -static void sdev_data_cleanup(struct cxgb3i_sdev_data *cdata) -{ - struct adap_ports *ports = &cdata->ports; - struct s3_conn *c3cn; - int i; - - for (i = 0; i < cxgb3_max_connect; i++) { - if (cdata->sport_conn[i]) { - c3cn = cdata->sport_conn[i]; - cdata->sport_conn[i] = NULL; - - spin_lock_bh(&c3cn->lock); - c3cn->cdev = NULL; - c3cn_set_flag(c3cn, C3CN_OFFLOAD_DOWN); - c3cn_closed(c3cn); - spin_unlock_bh(&c3cn->lock); - } - } - - for (i = 0; i < ports->nports; i++) - NDEV2CDATA(ports->lldevs[i]) = NULL; - - cxgb3i_free_big_mem(cdata); -} - -void cxgb3i_sdev_cleanup(void) -{ - struct cxgb3i_sdev_data *cdata; - - write_lock(&cdata_rwlock); - list_for_each_entry(cdata, &cdata_list, list) { - list_del(&cdata->list); - sdev_data_cleanup(cdata); - } - write_unlock(&cdata_rwlock); -} - -int cxgb3i_sdev_init(cxgb3_cpl_handler_func *cpl_handlers) -{ - cpl_handlers[CPL_ACT_ESTABLISH] = do_act_establish; - cpl_handlers[CPL_ACT_OPEN_RPL] = do_act_open_rpl; - cpl_handlers[CPL_PEER_CLOSE] = do_peer_close; - cpl_handlers[CPL_ABORT_REQ_RSS] = do_abort_req; - cpl_handlers[CPL_ABORT_RPL_RSS] = do_abort_rpl; - cpl_handlers[CPL_CLOSE_CON_RPL] = do_close_con_rpl; - cpl_handlers[CPL_TX_DMA_ACK] = do_wr_ack; - cpl_handlers[CPL_ISCSI_HDR] = do_iscsi_hdr; - - if (cxgb3_max_connect > CXGB3I_MAX_CONN) - cxgb3_max_connect = CXGB3I_MAX_CONN; - return 0; -} - -/** - * cxgb3i_sdev_add - allocate and initialize resources for each adapter found - * @cdev: t3cdev adapter - * @client: cxgb3 driver client - */ -void cxgb3i_sdev_add(struct t3cdev *cdev, struct cxgb3_client *client) -{ - struct cxgb3i_sdev_data *cdata; - struct ofld_page_info rx_page_info; - unsigned int wr_len; - int mapsize = cxgb3_max_connect * sizeof(struct s3_conn *); - int i; - - cdata = cxgb3i_alloc_big_mem(sizeof(*cdata) + mapsize, GFP_KERNEL); - if (!cdata) { - cxgb3i_log_warn("t3dev 0x%p, offload up, OOM %d.\n", - cdev, mapsize); - return; - } - - if (cdev->ctl(cdev, GET_WR_LEN, &wr_len) < 0 || - cdev->ctl(cdev, GET_PORTS, &cdata->ports) < 0 || - cdev->ctl(cdev, GET_RX_PAGE_INFO, &rx_page_info) < 0) { - cxgb3i_log_warn("t3dev 0x%p, offload up, ioctl failed.\n", - cdev); - goto free_cdata; - } - - s3_init_wr_tab(wr_len); - - spin_lock_init(&cdata->lock); - INIT_LIST_HEAD(&cdata->list); - cdata->cdev = cdev; - cdata->client = client; - - for (i = 0; i < cdata->ports.nports; i++) - NDEV2CDATA(cdata->ports.lldevs[i]) = cdata; - - write_lock(&cdata_rwlock); - list_add_tail(&cdata->list, &cdata_list); - write_unlock(&cdata_rwlock); - - cxgb3i_log_info("t3dev 0x%p, offload up, added.\n", cdev); - return; - -free_cdata: - cxgb3i_free_big_mem(cdata); -} - -/** - * cxgb3i_sdev_remove - free the allocated resources for the adapter - * @cdev: t3cdev adapter - */ -void cxgb3i_sdev_remove(struct t3cdev *cdev) -{ - struct cxgb3i_sdev_data *cdata = CXGB3_SDEV_DATA(cdev); - - cxgb3i_log_info("t3dev 0x%p, offload down, remove.\n", cdev); - - write_lock(&cdata_rwlock); - list_del(&cdata->list); - write_unlock(&cdata_rwlock); - - sdev_data_cleanup(cdata); -} diff --git a/drivers/scsi/cxgb3i/cxgb3i_offload.h b/drivers/scsi/cxgb3i/cxgb3i_offload.h deleted file mode 100644 index 6a1d86b1fafe..000000000000 --- a/drivers/scsi/cxgb3i/cxgb3i_offload.h +++ /dev/null @@ -1,243 +0,0 @@ -/* - * cxgb3i_offload.h: Chelsio S3xx iscsi offloaded tcp connection management - * - * Copyright (C) 2003-2008 Chelsio Communications. All rights reserved. - * - * 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 LICENSE file included in this - * release for licensing terms and conditions. - * - * Written by: Dimitris Michailidis (dm@chelsio.com) - * Karen Xie (kxie@chelsio.com) - */ - -#ifndef _CXGB3I_OFFLOAD_H -#define _CXGB3I_OFFLOAD_H - -#include <linux/skbuff.h> -#include <linux/in.h> - -#include "common.h" -#include "adapter.h" -#include "t3cdev.h" -#include "cxgb3_offload.h" - -#define cxgb3i_log_error(fmt...) printk(KERN_ERR "cxgb3i: ERR! " fmt) -#define cxgb3i_log_warn(fmt...) printk(KERN_WARNING "cxgb3i: WARN! " fmt) -#define cxgb3i_log_info(fmt...) printk(KERN_INFO "cxgb3i: " fmt) -#define cxgb3i_log_debug(fmt, args...) \ - printk(KERN_INFO "cxgb3i: %s - " fmt, __func__ , ## args) - -/** - * struct s3_conn - an iscsi tcp connection structure - * - * @dev: net device of with connection - * @cdev: adapter t3cdev for net device - * @flags: see c3cn_flags below - * @tid: connection id assigned by the h/w - * @qset: queue set used by connection - * @mss_idx: Maximum Segment Size table index - * @l2t: ARP resolution entry for offload packets - * @wr_max: maximum in-flight writes - * @wr_avail: number of writes available - * @wr_unacked: writes since last request for completion notification - * @wr_pending_head: head of pending write queue - * @wr_pending_tail: tail of pending write queue - * @cpl_close: skb for cpl_close_req - * @cpl_abort_req: skb for cpl_abort_req - * @cpl_abort_rpl: skb for cpl_abort_rpl - * @lock: connection status lock - * @refcnt: reference count on connection - * @state: connection state - * @saddr: source ip/port address - * @daddr: destination ip/port address - * @dst_cache: reference to destination route - * @receive_queue: received PDUs - * @write_queue: un-pushed pending writes - * @retry_timer: retry timer for various operations - * @err: connection error status - * @callback_lock: lock for opaque user context - * @user_data: opaque user context - * @rcv_nxt: next receive seq. # - * @copied_seq: head of yet unread data - * @rcv_wup: rcv_nxt on last window update sent - * @snd_nxt: next sequence we send - * @snd_una: first byte we want an ack for - * @write_seq: tail+1 of data held in send buffer - */ -struct s3_conn { - struct net_device *dev; - struct t3cdev *cdev; - unsigned long flags; - int tid; - int qset; - int mss_idx; - struct l2t_entry *l2t; - int wr_max; - int wr_avail; - int wr_unacked; - struct sk_buff *wr_pending_head; - struct sk_buff *wr_pending_tail; - struct sk_buff *cpl_close; - struct sk_buff *cpl_abort_req; - struct sk_buff *cpl_abort_rpl; - spinlock_t lock; - atomic_t refcnt; - volatile unsigned int state; - struct sockaddr_in saddr; - struct sockaddr_in daddr; - struct dst_entry *dst_cache; - struct sk_buff_head receive_queue; - struct sk_buff_head write_queue; - struct timer_list retry_timer; - int err; - rwlock_t callback_lock; - void *user_data; - - u32 rcv_nxt; - u32 copied_seq; - u32 rcv_wup; - u32 snd_nxt; - u32 snd_una; - u32 write_seq; -}; - -/* - * connection state - */ -enum conn_states { - C3CN_STATE_CONNECTING = 1, - C3CN_STATE_ESTABLISHED, - C3CN_STATE_ACTIVE_CLOSE, - C3CN_STATE_PASSIVE_CLOSE, - C3CN_STATE_CLOSE_WAIT_1, - C3CN_STATE_CLOSE_WAIT_2, - C3CN_STATE_ABORTING, - C3CN_STATE_CLOSED, -}; - -static inline unsigned int c3cn_is_closing(const struct s3_conn *c3cn) -{ - return c3cn->state >= C3CN_STATE_ACTIVE_CLOSE; -} -static inline unsigned int c3cn_is_established(const struct s3_conn *c3cn) -{ - return c3cn->state == C3CN_STATE_ESTABLISHED; -} - -/* - * Connection flags -- many to track some close related events. - */ -enum c3cn_flags { - C3CN_ABORT_RPL_RCVD, /* received one ABORT_RPL_RSS message */ - C3CN_ABORT_REQ_RCVD, /* received one ABORT_REQ_RSS message */ - C3CN_ABORT_RPL_PENDING, /* expecting an abort reply */ - C3CN_TX_DATA_SENT, /* already sent a TX_DATA WR */ - C3CN_ACTIVE_CLOSE_NEEDED, /* need to be closed */ - C3CN_OFFLOAD_DOWN /* offload function off */ -}; - -/** - * cxgb3i_sdev_data - Per adapter data. - * Linked off of each Ethernet device port on the adapter. - * Also available via the t3cdev structure since we have pointers to our port - * net_device's there ... - * - * @list: list head to link elements - * @cdev: t3cdev adapter - * @client: CPL client pointer - * @ports: array of adapter ports - * @sport_next: next port - * @sport_conn: source port connection - */ -struct cxgb3i_sdev_data { - struct list_head list; - struct t3cdev *cdev; - struct cxgb3_client *client; - struct adap_ports ports; - spinlock_t lock; - unsigned int sport_next; - struct s3_conn *sport_conn[0]; -}; -#define NDEV2CDATA(ndev) (*(struct cxgb3i_sdev_data **)&(ndev)->ec_ptr) -#define CXGB3_SDEV_DATA(cdev) NDEV2CDATA((cdev)->lldev) - -void cxgb3i_sdev_cleanup(void); -int cxgb3i_sdev_init(cxgb3_cpl_handler_func *); -void cxgb3i_sdev_add(struct t3cdev *, struct cxgb3_client *); -void cxgb3i_sdev_remove(struct t3cdev *); - -struct s3_conn *cxgb3i_c3cn_create(void); -int cxgb3i_c3cn_connect(struct net_device *, struct s3_conn *, - struct sockaddr_in *); -void cxgb3i_c3cn_rx_credits(struct s3_conn *, int); -int cxgb3i_c3cn_send_pdus(struct s3_conn *, struct sk_buff *); -void cxgb3i_c3cn_release(struct s3_conn *); - -/** - * cxgb3_skb_cb - control block for received pdu state and ULP mode management. - * - * @flag: see C3CB_FLAG_* below - * @ulp_mode: ULP mode/submode of sk_buff - * @seq: tcp sequence number - */ -struct cxgb3_skb_rx_cb { - __u32 ddigest; /* data digest */ - __u32 pdulen; /* recovered pdu length */ -}; - -struct cxgb3_skb_tx_cb { - struct sk_buff *wr_next; /* next wr */ -}; - -struct cxgb3_skb_cb { - __u8 flags; - __u8 ulp_mode; - __u32 seq; - union { - struct cxgb3_skb_rx_cb rx; - struct cxgb3_skb_tx_cb tx; - }; -}; - -#define CXGB3_SKB_CB(skb) ((struct cxgb3_skb_cb *)&((skb)->cb[0])) -#define skb_flags(skb) (CXGB3_SKB_CB(skb)->flags) -#define skb_ulp_mode(skb) (CXGB3_SKB_CB(skb)->ulp_mode) -#define skb_tcp_seq(skb) (CXGB3_SKB_CB(skb)->seq) -#define skb_rx_ddigest(skb) (CXGB3_SKB_CB(skb)->rx.ddigest) -#define skb_rx_pdulen(skb) (CXGB3_SKB_CB(skb)->rx.pdulen) -#define skb_tx_wr_next(skb) (CXGB3_SKB_CB(skb)->tx.wr_next) - -enum c3cb_flags { - C3CB_FLAG_NEED_HDR = 1 << 0, /* packet needs a TX_DATA_WR header */ - C3CB_FLAG_NO_APPEND = 1 << 1, /* don't grow this skb */ - C3CB_FLAG_COMPL = 1 << 2, /* request WR completion */ -}; - -/** - * sge_opaque_hdr - - * Opaque version of structure the SGE stores at skb->head of TX_DATA packets - * and for which we must reserve space. - */ -struct sge_opaque_hdr { - void *dev; - dma_addr_t addr[MAX_SKB_FRAGS + 1]; -}; - -/* for TX: a skb must have a headroom of at least TX_HEADER_LEN bytes */ -#define TX_HEADER_LEN \ - (sizeof(struct tx_data_wr) + sizeof(struct sge_opaque_hdr)) -#define SKB_TX_HEADROOM SKB_MAX_HEAD(TX_HEADER_LEN) - -/* - * get and set private ip for iscsi traffic - */ -#define cxgb3i_get_private_ipv4addr(ndev) \ - (((struct port_info *)(netdev_priv(ndev)))->iscsi_ipv4addr) -#define cxgb3i_set_private_ipv4addr(ndev, addr) \ - (((struct port_info *)(netdev_priv(ndev)))->iscsi_ipv4addr) = addr - -/* max. connections per adapter */ -#define CXGB3I_MAX_CONN 16384 -#endif /* _CXGB3_OFFLOAD_H */ diff --git a/drivers/scsi/cxgb3i/cxgb3i_pdu.c b/drivers/scsi/cxgb3i/cxgb3i_pdu.c deleted file mode 100644 index dc5e3e77a351..000000000000 --- a/drivers/scsi/cxgb3i/cxgb3i_pdu.c +++ /dev/null @@ -1,495 +0,0 @@ -/* - * cxgb3i_pdu.c: Chelsio S3xx iSCSI driver. - * - * Copyright (c) 2008 Chelsio Communications, Inc. - * Copyright (c) 2008 Mike Christie - * Copyright (c) 2008 Red Hat, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation. - * - * Written by: Karen Xie (kxie@chelsio.com) - */ - -#include <linux/slab.h> -#include <linux/skbuff.h> -#include <linux/crypto.h> -#include <scsi/scsi_cmnd.h> -#include <scsi/scsi_host.h> - -#include "cxgb3i.h" -#include "cxgb3i_pdu.h" - -#ifdef __DEBUG_CXGB3I_RX__ -#define cxgb3i_rx_debug cxgb3i_log_debug -#else -#define cxgb3i_rx_debug(fmt...) -#endif - -#ifdef __DEBUG_CXGB3I_TX__ -#define cxgb3i_tx_debug cxgb3i_log_debug -#else -#define cxgb3i_tx_debug(fmt...) -#endif - -/* always allocate rooms for AHS */ -#define SKB_TX_PDU_HEADER_LEN \ - (sizeof(struct iscsi_hdr) + ISCSI_MAX_AHS_SIZE) -static unsigned int skb_extra_headroom; -static struct page *pad_page; - -/* - * pdu receive, interact with libiscsi_tcp - */ -static inline int read_pdu_skb(struct iscsi_conn *conn, struct sk_buff *skb, - unsigned int offset, int offloaded) -{ - int status = 0; - int bytes_read; - - bytes_read = iscsi_tcp_recv_skb(conn, skb, offset, offloaded, &status); - switch (status) { - case ISCSI_TCP_CONN_ERR: - return -EIO; - case ISCSI_TCP_SUSPENDED: - /* no transfer - just have caller flush queue */ - return bytes_read; - case ISCSI_TCP_SKB_DONE: - /* - * pdus should always fit in the skb and we should get - * segment done notifcation. - */ - iscsi_conn_printk(KERN_ERR, conn, "Invalid pdu or skb."); - return -EFAULT; - case ISCSI_TCP_SEGMENT_DONE: - return bytes_read; - default: - iscsi_conn_printk(KERN_ERR, conn, "Invalid iscsi_tcp_recv_skb " - "status %d\n", status); - return -EINVAL; - } -} - -static int cxgb3i_conn_read_pdu_skb(struct iscsi_conn *conn, - struct sk_buff *skb) -{ - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; - bool offloaded = 0; - unsigned int offset; - int rc; - - cxgb3i_rx_debug("conn 0x%p, skb 0x%p, len %u, flag 0x%x.\n", - conn, skb, skb->len, skb_ulp_mode(skb)); - - if (!iscsi_tcp_recv_segment_is_hdr(tcp_conn)) { - iscsi_conn_failure(conn, ISCSI_ERR_PROTO); - return -EIO; - } - - if (conn->hdrdgst_en && (skb_ulp_mode(skb) & ULP2_FLAG_HCRC_ERROR)) { - iscsi_conn_failure(conn, ISCSI_ERR_HDR_DGST); - return -EIO; - } - - if (conn->datadgst_en && (skb_ulp_mode(skb) & ULP2_FLAG_DCRC_ERROR)) { - iscsi_conn_failure(conn, ISCSI_ERR_DATA_DGST); - return -EIO; - } - - /* iscsi hdr */ - rc = read_pdu_skb(conn, skb, 0, 0); - if (rc <= 0) - return rc; - - if (iscsi_tcp_recv_segment_is_hdr(tcp_conn)) - return 0; - - offset = rc; - if (conn->hdrdgst_en) - offset += ISCSI_DIGEST_SIZE; - - /* iscsi data */ - if (skb_ulp_mode(skb) & ULP2_FLAG_DATA_DDPED) { - cxgb3i_rx_debug("skb 0x%p, opcode 0x%x, data %u, ddp'ed, " - "itt 0x%x.\n", - skb, - tcp_conn->in.hdr->opcode & ISCSI_OPCODE_MASK, - tcp_conn->in.datalen, - ntohl(tcp_conn->in.hdr->itt)); - offloaded = 1; - } else { - cxgb3i_rx_debug("skb 0x%p, opcode 0x%x, data %u, NOT ddp'ed, " - "itt 0x%x.\n", - skb, - tcp_conn->in.hdr->opcode & ISCSI_OPCODE_MASK, - tcp_conn->in.datalen, - ntohl(tcp_conn->in.hdr->itt)); - offset += sizeof(struct cpl_iscsi_hdr_norss); - } - - rc = read_pdu_skb(conn, skb, offset, offloaded); - if (rc < 0) - return rc; - else - return 0; -} - -/* - * pdu transmit, interact with libiscsi_tcp - */ -static inline void tx_skb_setmode(struct sk_buff *skb, int hcrc, int dcrc) -{ - u8 submode = 0; - - if (hcrc) - submode |= 1; - if (dcrc) - submode |= 2; - skb_ulp_mode(skb) = (ULP_MODE_ISCSI << 4) | submode; -} - -void cxgb3i_conn_cleanup_task(struct iscsi_task *task) -{ - struct cxgb3i_task_data *tdata = task->dd_data + - sizeof(struct iscsi_tcp_task); - - /* never reached the xmit task callout */ - if (tdata->skb) - __kfree_skb(tdata->skb); - memset(tdata, 0, sizeof(struct cxgb3i_task_data)); - - /* MNC - Do we need a check in case this is called but - * cxgb3i_conn_alloc_pdu has never been called on the task */ - cxgb3i_release_itt(task, task->hdr_itt); - iscsi_tcp_cleanup_task(task); -} - -static int sgl_seek_offset(struct scatterlist *sgl, unsigned int sgcnt, - unsigned int offset, unsigned int *off, - struct scatterlist **sgp) -{ - int i; - struct scatterlist *sg; - - for_each_sg(sgl, sg, sgcnt, i) { - if (offset < sg->length) { - *off = offset; - *sgp = sg; - return 0; - } - offset -= sg->length; - } - return -EFAULT; -} - -static int sgl_read_to_frags(struct scatterlist *sg, unsigned int sgoffset, - unsigned int dlen, skb_frag_t *frags, - int frag_max) -{ - unsigned int datalen = dlen; - unsigned int sglen = sg->length - sgoffset; - struct page *page = sg_page(sg); - int i; - - i = 0; - do { - unsigned int copy; - - if (!sglen) { - sg = sg_next(sg); - if (!sg) { - cxgb3i_log_error("%s, sg NULL, len %u/%u.\n", - __func__, datalen, dlen); - return -EINVAL; - } - sgoffset = 0; - sglen = sg->length; - page = sg_page(sg); - - } - copy = min(datalen, sglen); - if (i && page == frags[i - 1].page && - sgoffset + sg->offset == - frags[i - 1].page_offset + frags[i - 1].size) { - frags[i - 1].size += copy; - } else { - if (i >= frag_max) { - cxgb3i_log_error("%s, too many pages %u, " - "dlen %u.\n", __func__, - frag_max, dlen); - return -EINVAL; - } - - frags[i].page = page; - frags[i].page_offset = sg->offset + sgoffset; - frags[i].size = copy; - i++; - } - datalen -= copy; - sgoffset += copy; - sglen -= copy; - } while (datalen); - - return i; -} - -int cxgb3i_conn_alloc_pdu(struct iscsi_task *task, u8 opcode) -{ - struct iscsi_conn *conn = task->conn; - struct iscsi_tcp_task *tcp_task = task->dd_data; - struct cxgb3i_task_data *tdata = task->dd_data + sizeof(*tcp_task); - struct scsi_cmnd *sc = task->sc; - int headroom = SKB_TX_PDU_HEADER_LEN; - - tcp_task->dd_data = tdata; - task->hdr = NULL; - - /* write command, need to send data pdus */ - if (skb_extra_headroom && (opcode == ISCSI_OP_SCSI_DATA_OUT || - (opcode == ISCSI_OP_SCSI_CMD && - (scsi_bidi_cmnd(sc) || sc->sc_data_direction == DMA_TO_DEVICE)))) - headroom += min(skb_extra_headroom, conn->max_xmit_dlength); - - tdata->skb = alloc_skb(TX_HEADER_LEN + headroom, GFP_ATOMIC); - if (!tdata->skb) - return -ENOMEM; - skb_reserve(tdata->skb, TX_HEADER_LEN); - - cxgb3i_tx_debug("task 0x%p, opcode 0x%x, skb 0x%p.\n", - task, opcode, tdata->skb); - - task->hdr = (struct iscsi_hdr *)tdata->skb->data; - task->hdr_max = SKB_TX_PDU_HEADER_LEN; - - /* data_out uses scsi_cmd's itt */ - if (opcode != ISCSI_OP_SCSI_DATA_OUT) - cxgb3i_reserve_itt(task, &task->hdr->itt); - - return 0; -} - -int cxgb3i_conn_init_pdu(struct iscsi_task *task, unsigned int offset, - unsigned int count) -{ - struct iscsi_conn *conn = task->conn; - struct iscsi_tcp_task *tcp_task = task->dd_data; - struct cxgb3i_task_data *tdata = tcp_task->dd_data; - struct sk_buff *skb = tdata->skb; - unsigned int datalen = count; - int i, padlen = iscsi_padding(count); - struct page *pg; - - cxgb3i_tx_debug("task 0x%p,0x%p, offset %u, count %u, skb 0x%p.\n", - task, task->sc, offset, count, skb); - - skb_put(skb, task->hdr_len); - tx_skb_setmode(skb, conn->hdrdgst_en, datalen ? conn->datadgst_en : 0); - if (!count) - return 0; - - if (task->sc) { - struct scsi_data_buffer *sdb = scsi_out(task->sc); - struct scatterlist *sg = NULL; - int err; - - tdata->offset = offset; - tdata->count = count; - err = sgl_seek_offset(sdb->table.sgl, sdb->table.nents, - tdata->offset, &tdata->sgoffset, &sg); - if (err < 0) { - cxgb3i_log_warn("tpdu, sgl %u, bad offset %u/%u.\n", - sdb->table.nents, tdata->offset, - sdb->length); - return err; - } - err = sgl_read_to_frags(sg, tdata->sgoffset, tdata->count, - tdata->frags, MAX_PDU_FRAGS); - if (err < 0) { - cxgb3i_log_warn("tpdu, sgl %u, bad offset %u + %u.\n", - sdb->table.nents, tdata->offset, - tdata->count); - return err; - } - tdata->nr_frags = err; - - if (tdata->nr_frags > MAX_SKB_FRAGS || - (padlen && tdata->nr_frags == MAX_SKB_FRAGS)) { - char *dst = skb->data + task->hdr_len; - skb_frag_t *frag = tdata->frags; - - /* data fits in the skb's headroom */ - for (i = 0; i < tdata->nr_frags; i++, frag++) { - char *src = kmap_atomic(frag->page, - KM_SOFTIRQ0); - - memcpy(dst, src+frag->page_offset, frag->size); - dst += frag->size; - kunmap_atomic(src, KM_SOFTIRQ0); - } - if (padlen) { - memset(dst, 0, padlen); - padlen = 0; - } - skb_put(skb, count + padlen); - } else { - /* data fit into frag_list */ - for (i = 0; i < tdata->nr_frags; i++) - get_page(tdata->frags[i].page); - - memcpy(skb_shinfo(skb)->frags, tdata->frags, - sizeof(skb_frag_t) * tdata->nr_frags); - skb_shinfo(skb)->nr_frags = tdata->nr_frags; - skb->len += count; - skb->data_len += count; - skb->truesize += count; - } - - } else { - pg = virt_to_page(task->data); - - get_page(pg); - skb_fill_page_desc(skb, 0, pg, offset_in_page(task->data), - count); - skb->len += count; - skb->data_len += count; - skb->truesize += count; - } - - if (padlen) { - i = skb_shinfo(skb)->nr_frags; - get_page(pad_page); - skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags, pad_page, 0, - padlen); - - skb->data_len += padlen; - skb->truesize += padlen; - skb->len += padlen; - } - - return 0; -} - -int cxgb3i_conn_xmit_pdu(struct iscsi_task *task) -{ - struct iscsi_tcp_conn *tcp_conn = task->conn->dd_data; - struct cxgb3i_conn *cconn = tcp_conn->dd_data; - struct iscsi_tcp_task *tcp_task = task->dd_data; - struct cxgb3i_task_data *tdata = tcp_task->dd_data; - struct sk_buff *skb = tdata->skb; - unsigned int datalen; - int err; - - if (!skb) - return 0; - - datalen = skb->data_len; - tdata->skb = NULL; - err = cxgb3i_c3cn_send_pdus(cconn->cep->c3cn, skb); - if (err > 0) { - int pdulen = err; - - cxgb3i_tx_debug("task 0x%p, skb 0x%p, len %u/%u, rv %d.\n", - task, skb, skb->len, skb->data_len, err); - - if (task->conn->hdrdgst_en) - pdulen += ISCSI_DIGEST_SIZE; - if (datalen && task->conn->datadgst_en) - pdulen += ISCSI_DIGEST_SIZE; - - task->conn->txdata_octets += pdulen; - return 0; - } - - if (err == -EAGAIN || err == -ENOBUFS) { - /* reset skb to send when we are called again */ - tdata->skb = skb; - return err; - } - - kfree_skb(skb); - cxgb3i_tx_debug("itt 0x%x, skb 0x%p, len %u/%u, xmit err %d.\n", - task->itt, skb, skb->len, skb->data_len, err); - iscsi_conn_printk(KERN_ERR, task->conn, "xmit err %d.\n", err); - iscsi_conn_failure(task->conn, ISCSI_ERR_XMIT_FAILED); - return err; -} - -int cxgb3i_pdu_init(void) -{ - if (SKB_TX_HEADROOM > (512 * MAX_SKB_FRAGS)) - skb_extra_headroom = SKB_TX_HEADROOM; - pad_page = alloc_page(GFP_KERNEL); - if (!pad_page) - return -ENOMEM; - memset(page_address(pad_page), 0, PAGE_SIZE); - return 0; -} - -void cxgb3i_pdu_cleanup(void) -{ - if (pad_page) { - __free_page(pad_page); - pad_page = NULL; - } -} - -void cxgb3i_conn_pdu_ready(struct s3_conn *c3cn) -{ - struct sk_buff *skb; - unsigned int read = 0; - struct iscsi_conn *conn = c3cn->user_data; - int err = 0; - - cxgb3i_rx_debug("cn 0x%p.\n", c3cn); - - read_lock(&c3cn->callback_lock); - if (unlikely(!conn || conn->suspend_rx)) { - cxgb3i_rx_debug("conn 0x%p, id %d, suspend_rx %lu!\n", - conn, conn ? conn->id : 0xFF, - conn ? conn->suspend_rx : 0xFF); - read_unlock(&c3cn->callback_lock); - return; - } - skb = skb_peek(&c3cn->receive_queue); - while (!err && skb) { - __skb_unlink(skb, &c3cn->receive_queue); - read += skb_rx_pdulen(skb); - cxgb3i_rx_debug("conn 0x%p, cn 0x%p, rx skb 0x%p, pdulen %u.\n", - conn, c3cn, skb, skb_rx_pdulen(skb)); - err = cxgb3i_conn_read_pdu_skb(conn, skb); - __kfree_skb(skb); - skb = skb_peek(&c3cn->receive_queue); - } - read_unlock(&c3cn->callback_lock); - c3cn->copied_seq += read; - cxgb3i_c3cn_rx_credits(c3cn, read); - conn->rxdata_octets += read; - - if (err) { - cxgb3i_log_info("conn 0x%p rx failed err %d.\n", conn, err); - iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); - } -} - -void cxgb3i_conn_tx_open(struct s3_conn *c3cn) -{ - struct iscsi_conn *conn = c3cn->user_data; - - cxgb3i_tx_debug("cn 0x%p.\n", c3cn); - if (conn) { - cxgb3i_tx_debug("cn 0x%p, cid %d.\n", c3cn, conn->id); - iscsi_conn_queue_work(conn); - } -} - -void cxgb3i_conn_closing(struct s3_conn *c3cn) -{ - struct iscsi_conn *conn; - - read_lock(&c3cn->callback_lock); - conn = c3cn->user_data; - if (conn && c3cn->state != C3CN_STATE_ESTABLISHED) - iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); - read_unlock(&c3cn->callback_lock); -} diff --git a/drivers/scsi/cxgb3i/cxgb3i_pdu.h b/drivers/scsi/cxgb3i/cxgb3i_pdu.h deleted file mode 100644 index 0770b23d90da..000000000000 --- a/drivers/scsi/cxgb3i/cxgb3i_pdu.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * cxgb3i_ulp2.h: Chelsio S3xx iSCSI driver. - * - * Copyright (c) 2008 Chelsio Communications, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation. - * - * Written by: Karen Xie (kxie@chelsio.com) - */ - -#ifndef __CXGB3I_ULP2_PDU_H__ -#define __CXGB3I_ULP2_PDU_H__ - -struct cpl_iscsi_hdr_norss { - union opcode_tid ot; - u16 pdu_len_ddp; - u16 len; - u32 seq; - u16 urg; - u8 rsvd; - u8 status; -}; - -struct cpl_rx_data_ddp_norss { - union opcode_tid ot; - u16 urg; - u16 len; - u32 seq; - u32 nxt_seq; - u32 ulp_crc; - u32 ddp_status; -}; - -#define RX_DDP_STATUS_IPP_SHIFT 27 /* invalid pagepod */ -#define RX_DDP_STATUS_TID_SHIFT 26 /* tid mismatch */ -#define RX_DDP_STATUS_COLOR_SHIFT 25 /* color mismatch */ -#define RX_DDP_STATUS_OFFSET_SHIFT 24 /* offset mismatch */ -#define RX_DDP_STATUS_ULIMIT_SHIFT 23 /* ulimit error */ -#define RX_DDP_STATUS_TAG_SHIFT 22 /* tag mismatch */ -#define RX_DDP_STATUS_DCRC_SHIFT 21 /* dcrc error */ -#define RX_DDP_STATUS_HCRC_SHIFT 20 /* hcrc error */ -#define RX_DDP_STATUS_PAD_SHIFT 19 /* pad error */ -#define RX_DDP_STATUS_PPP_SHIFT 18 /* pagepod parity error */ -#define RX_DDP_STATUS_LLIMIT_SHIFT 17 /* llimit error */ -#define RX_DDP_STATUS_DDP_SHIFT 16 /* ddp'able */ -#define RX_DDP_STATUS_PMM_SHIFT 15 /* pagepod mismatch */ - -#define ULP2_FLAG_DATA_READY 0x1 -#define ULP2_FLAG_DATA_DDPED 0x2 -#define ULP2_FLAG_HCRC_ERROR 0x10 -#define ULP2_FLAG_DCRC_ERROR 0x20 -#define ULP2_FLAG_PAD_ERROR 0x40 - -void cxgb3i_conn_closing(struct s3_conn *c3cn); -void cxgb3i_conn_pdu_ready(struct s3_conn *c3cn); -void cxgb3i_conn_tx_open(struct s3_conn *c3cn); -#endif diff --git a/drivers/scsi/cxgbi/Kconfig b/drivers/scsi/cxgbi/Kconfig new file mode 100644 index 000000000000..17eb5d522f42 --- /dev/null +++ b/drivers/scsi/cxgbi/Kconfig @@ -0,0 +1,2 @@ +source "drivers/scsi/cxgbi/cxgb3i/Kconfig" +source "drivers/scsi/cxgbi/cxgb4i/Kconfig" diff --git a/drivers/scsi/cxgbi/Makefile b/drivers/scsi/cxgbi/Makefile new file mode 100644 index 000000000000..86007e344955 --- /dev/null +++ b/drivers/scsi/cxgbi/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_SCSI_CXGB3_ISCSI) += libcxgbi.o cxgb3i/ +obj-$(CONFIG_SCSI_CXGB4_ISCSI) += libcxgbi.o cxgb4i/ diff --git a/drivers/scsi/cxgb3i/Kbuild b/drivers/scsi/cxgbi/cxgb3i/Kbuild index 70d060b7ff4f..09dbf9efc8ea 100644 --- a/drivers/scsi/cxgb3i/Kbuild +++ b/drivers/scsi/cxgbi/cxgb3i/Kbuild @@ -1,4 +1,3 @@ EXTRA_CFLAGS += -I$(srctree)/drivers/net/cxgb3 -cxgb3i-y := cxgb3i_init.o cxgb3i_iscsi.o cxgb3i_pdu.o cxgb3i_offload.o cxgb3i_ddp.o obj-$(CONFIG_SCSI_CXGB3_ISCSI) += cxgb3i.o diff --git a/drivers/scsi/cxgb3i/Kconfig b/drivers/scsi/cxgbi/cxgb3i/Kconfig index bfdcaf5c9c57..5cf4e9831f1b 100644 --- a/drivers/scsi/cxgb3i/Kconfig +++ b/drivers/scsi/cxgbi/cxgb3i/Kconfig @@ -1,7 +1,7 @@ config SCSI_CXGB3_ISCSI - tristate "Chelsio S3xx iSCSI support" + tristate "Chelsio T3 iSCSI support" depends on CHELSIO_T3_DEPENDS select CHELSIO_T3 select SCSI_ISCSI_ATTRS ---help--- - This driver supports iSCSI offload for the Chelsio S3 series devices. + This driver supports iSCSI offload for the Chelsio T3 devices. diff --git a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c new file mode 100644 index 000000000000..a129a170b47b --- /dev/null +++ b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c @@ -0,0 +1,1465 @@ +/* + * cxgb3i_offload.c: Chelsio S3xx iscsi offloaded tcp connection management + * + * Copyright (C) 2003-2008 Chelsio Communications. All rights reserved. + * + * 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 LICENSE file included in this + * release for licensing terms and conditions. + * + * Written by: Dimitris Michailidis (dm@chelsio.com) + * Karen Xie (kxie@chelsio.com) + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ + +#include <linux/version.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <scsi/scsi_host.h> + +#include "common.h" +#include "t3_cpl.h" +#include "t3cdev.h" +#include "cxgb3_defs.h" +#include "cxgb3_ctl_defs.h" +#include "cxgb3_offload.h" +#include "firmware_exports.h" +#include "cxgb3i.h" + +static unsigned int dbg_level; +#include "../libcxgbi.h" + +#define DRV_MODULE_NAME "cxgb3i" +#define DRV_MODULE_DESC "Chelsio T3 iSCSI Driver" +#define DRV_MODULE_VERSION "2.0.0" +#define DRV_MODULE_RELDATE "Jun. 2010" + +static char version[] = + DRV_MODULE_DESC " " DRV_MODULE_NAME + " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; + +MODULE_AUTHOR("Chelsio Communications, Inc."); +MODULE_DESCRIPTION(DRV_MODULE_DESC); +MODULE_VERSION(DRV_MODULE_VERSION); +MODULE_LICENSE("GPL"); + +module_param(dbg_level, uint, 0644); +MODULE_PARM_DESC(dbg_level, "debug flag (default=0)"); + +static int cxgb3i_rcv_win = 256 * 1024; +module_param(cxgb3i_rcv_win, int, 0644); +MODULE_PARM_DESC(cxgb3i_rcv_win, "TCP receive window in bytes (default=256KB)"); + +static int cxgb3i_snd_win = 128 * 1024; +module_param(cxgb3i_snd_win, int, 0644); +MODULE_PARM_DESC(cxgb3i_snd_win, "TCP send window in bytes (default=128KB)"); + +static int cxgb3i_rx_credit_thres = 10 * 1024; +module_param(cxgb3i_rx_credit_thres, int, 0644); +MODULE_PARM_DESC(rx_credit_thres, + "RX credits return threshold in bytes (default=10KB)"); + +static unsigned int cxgb3i_max_connect = 8 * 1024; +module_param(cxgb3i_max_connect, uint, 0644); +MODULE_PARM_DESC(cxgb3i_max_connect, "Max. # of connections (default=8092)"); + +static unsigned int cxgb3i_sport_base = 20000; +module_param(cxgb3i_sport_base, uint, 0644); +MODULE_PARM_DESC(cxgb3i_sport_base, "starting port number (default=20000)"); + +static void cxgb3i_dev_open(struct t3cdev *); +static void cxgb3i_dev_close(struct t3cdev *); +static void cxgb3i_dev_event_handler(struct t3cdev *, u32, u32); + +static struct cxgb3_client t3_client = { + .name = DRV_MODULE_NAME, + .handlers = cxgb3i_cpl_handlers, + .add = cxgb3i_dev_open, + .remove = cxgb3i_dev_close, + .event_handler = cxgb3i_dev_event_handler, +}; + +static struct scsi_host_template cxgb3i_host_template = { + .module = THIS_MODULE, + .name = DRV_MODULE_NAME, + .proc_name = DRV_MODULE_NAME, + .can_queue = CXGB3I_SCSI_HOST_QDEPTH, + .queuecommand = iscsi_queuecommand, + .change_queue_depth = iscsi_change_queue_depth, + .sg_tablesize = SG_ALL, + .max_sectors = 0xFFFF, + .cmd_per_lun = ISCSI_DEF_CMD_PER_LUN, + .eh_abort_handler = iscsi_eh_abort, + .eh_device_reset_handler = iscsi_eh_device_reset, + .eh_target_reset_handler = iscsi_eh_recover_target, + .target_alloc = iscsi_target_alloc, + .use_clustering = DISABLE_CLUSTERING, + .this_id = -1, +}; + +static struct iscsi_transport cxgb3i_iscsi_transport = { + .owner = THIS_MODULE, + .name = DRV_MODULE_NAME, + /* owner and name should be set already */ + .caps = CAP_RECOVERY_L0 | CAP_MULTI_R2T | CAP_HDRDGST + | CAP_DATADGST | CAP_DIGEST_OFFLOAD | + CAP_PADDING_OFFLOAD, + .param_mask = ISCSI_MAX_RECV_DLENGTH | ISCSI_MAX_XMIT_DLENGTH | + ISCSI_HDRDGST_EN | ISCSI_DATADGST_EN | + ISCSI_INITIAL_R2T_EN | ISCSI_MAX_R2T | + ISCSI_IMM_DATA_EN | ISCSI_FIRST_BURST | + ISCSI_MAX_BURST | ISCSI_PDU_INORDER_EN | + ISCSI_DATASEQ_INORDER_EN | ISCSI_ERL | + ISCSI_CONN_PORT | ISCSI_CONN_ADDRESS | + ISCSI_EXP_STATSN | ISCSI_PERSISTENT_PORT | + ISCSI_PERSISTENT_ADDRESS | + ISCSI_TARGET_NAME | ISCSI_TPGT | + ISCSI_USERNAME | ISCSI_PASSWORD | + ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN | + ISCSI_FAST_ABORT | ISCSI_ABORT_TMO | + ISCSI_LU_RESET_TMO | ISCSI_TGT_RESET_TMO | + ISCSI_PING_TMO | ISCSI_RECV_TMO | + ISCSI_IFACE_NAME | ISCSI_INITIATOR_NAME, + .host_param_mask = ISCSI_HOST_HWADDRESS | ISCSI_HOST_IPADDRESS | + ISCSI_HOST_INITIATOR_NAME | + ISCSI_HOST_NETDEV_NAME, + .get_host_param = cxgbi_get_host_param, + .set_host_param = cxgbi_set_host_param, + /* session management */ + .create_session = cxgbi_create_session, + .destroy_session = cxgbi_destroy_session, + .get_session_param = iscsi_session_get_param, + /* connection management */ + .create_conn = cxgbi_create_conn, + .bind_conn = cxgbi_bind_conn, + .destroy_conn = iscsi_tcp_conn_teardown, + .start_conn = iscsi_conn_start, + .stop_conn = iscsi_conn_stop, + .get_conn_param = cxgbi_get_conn_param, + .set_param = cxgbi_set_conn_param, + .get_stats = cxgbi_get_conn_stats, + /* pdu xmit req from user space */ + .send_pdu = iscsi_conn_send_pdu, + /* task */ + .init_task = iscsi_tcp_task_init, + .xmit_task = iscsi_tcp_task_xmit, + .cleanup_task = cxgbi_cleanup_task, + /* pdu */ + .alloc_pdu = cxgbi_conn_alloc_pdu, + .init_pdu = cxgbi_conn_init_pdu, + .xmit_pdu = cxgbi_conn_xmit_pdu, + .parse_pdu_itt = cxgbi_parse_pdu_itt, + /* TCP connect/disconnect */ + .ep_connect = cxgbi_ep_connect, + .ep_poll = cxgbi_ep_poll, + .ep_disconnect = cxgbi_ep_disconnect, + /* Error recovery timeout call */ + .session_recovery_timedout = iscsi_session_recovery_timedout, +}; + +static struct scsi_transport_template *cxgb3i_stt; + +/* + * CPL (Chelsio Protocol Language) defines a message passing interface between + * the host driver and Chelsio asic. + * The section below implments CPLs that related to iscsi tcp connection + * open/close/abort and data send/receive. + */ + +static int push_tx_frames(struct cxgbi_sock *csk, int req_completion); + +static void send_act_open_req(struct cxgbi_sock *csk, struct sk_buff *skb, + const struct l2t_entry *e) +{ + unsigned int wscale = cxgbi_sock_compute_wscale(cxgb3i_rcv_win); + struct cpl_act_open_req *req = (struct cpl_act_open_req *)skb->head; + + skb->priority = CPL_PRIORITY_SETUP; + + req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); + OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_ACT_OPEN_REQ, csk->atid)); + req->local_port = csk->saddr.sin_port; + req->peer_port = csk->daddr.sin_port; + req->local_ip = csk->saddr.sin_addr.s_addr; + req->peer_ip = csk->daddr.sin_addr.s_addr; + + req->opt0h = htonl(V_KEEP_ALIVE(1) | F_TCAM_BYPASS | + V_WND_SCALE(wscale) | V_MSS_IDX(csk->mss_idx) | + V_L2T_IDX(e->idx) | V_TX_CHANNEL(e->smt_idx)); + req->opt0l = htonl(V_ULP_MODE(ULP2_MODE_ISCSI) | + V_RCV_BUFSIZ(cxgb3i_rcv_win>>10)); + + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, + "csk 0x%p,%u,0x%lx,%u, %pI4:%u-%pI4:%u, %u,%u,%u.\n", + csk, csk->state, csk->flags, csk->atid, + &req->local_ip, ntohs(req->local_port), + &req->peer_ip, ntohs(req->peer_port), + csk->mss_idx, e->idx, e->smt_idx); + + l2t_send(csk->cdev->lldev, skb, csk->l2t); +} + +static inline void act_open_arp_failure(struct t3cdev *dev, struct sk_buff *skb) +{ + cxgbi_sock_act_open_req_arp_failure(NULL, skb); +} + +/* + * CPL connection close request: host -> + * + * Close a connection by sending a CPL_CLOSE_CON_REQ message and queue it to + * the write queue (i.e., after any unsent txt data). + */ +static void send_close_req(struct cxgbi_sock *csk) +{ + struct sk_buff *skb = csk->cpl_close; + struct cpl_close_con_req *req = (struct cpl_close_con_req *)skb->head; + unsigned int tid = csk->tid; + + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, + "csk 0x%p,%u,0x%lx,%u.\n", + csk, csk->state, csk->flags, csk->tid); + + csk->cpl_close = NULL; + req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_CLOSE_CON)); + req->wr.wr_lo = htonl(V_WR_TID(tid)); + OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_CLOSE_CON_REQ, tid)); + req->rsvd = htonl(csk->write_seq); + + cxgbi_sock_skb_entail(csk, skb); + if (csk->state >= CTP_ESTABLISHED) + push_tx_frames(csk, 1); +} + +/* + * CPL connection abort request: host -> + * + * Send an ABORT_REQ message. Makes sure we do not send multiple ABORT_REQs + * for the same connection and also that we do not try to send a message + * after the connection has closed. + */ +static void abort_arp_failure(struct t3cdev *tdev, struct sk_buff *skb) +{ + struct cpl_abort_req *req = cplhdr(skb); + + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, + "t3dev 0x%p, tid %u, skb 0x%p.\n", + tdev, GET_TID(req), skb); + req->cmd = CPL_ABORT_NO_RST; + cxgb3_ofld_send(tdev, skb); +} + +static void send_abort_req(struct cxgbi_sock *csk) +{ + struct sk_buff *skb = csk->cpl_abort_req; + struct cpl_abort_req *req; + + if (unlikely(csk->state == CTP_ABORTING || !skb)) + return; + cxgbi_sock_set_state(csk, CTP_ABORTING); + cxgbi_sock_set_flag(csk, CTPF_ABORT_RPL_PENDING); + /* Purge the send queue so we don't send anything after an abort. */ + cxgbi_sock_purge_write_queue(csk); + + csk->cpl_abort_req = NULL; + req = (struct cpl_abort_req *)skb->head; + skb->priority = CPL_PRIORITY_DATA; + set_arp_failure_handler(skb, abort_arp_failure); + req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_HOST_ABORT_CON_REQ)); + req->wr.wr_lo = htonl(V_WR_TID(csk->tid)); + OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_ABORT_REQ, csk->tid)); + req->rsvd0 = htonl(csk->snd_nxt); + req->rsvd1 = !cxgbi_sock_flag(csk, CTPF_TX_DATA_SENT); + req->cmd = CPL_ABORT_SEND_RST; + + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, + "csk 0x%p,%u,0x%lx,%u, snd_nxt %u, 0x%x.\n", + csk, csk->state, csk->flags, csk->tid, csk->snd_nxt, + req->rsvd1); + + l2t_send(csk->cdev->lldev, skb, csk->l2t); +} + +/* + * CPL connection abort reply: host -> + * + * Send an ABORT_RPL message in response of the ABORT_REQ received. + */ +static void send_abort_rpl(struct cxgbi_sock *csk, int rst_status) +{ + struct sk_buff *skb = csk->cpl_abort_rpl; + struct cpl_abort_rpl *rpl = (struct cpl_abort_rpl *)skb->head; + + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, + "csk 0x%p,%u,0x%lx,%u, status %d.\n", + csk, csk->state, csk->flags, csk->tid, rst_status); + + csk->cpl_abort_rpl = NULL; + skb->priority = CPL_PRIORITY_DATA; + rpl->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_HOST_ABORT_CON_RPL)); + rpl->wr.wr_lo = htonl(V_WR_TID(csk->tid)); + OPCODE_TID(rpl) = htonl(MK_OPCODE_TID(CPL_ABORT_RPL, csk->tid)); + rpl->cmd = rst_status; + cxgb3_ofld_send(csk->cdev->lldev, skb); +} + +/* + * CPL connection rx data ack: host -> + * Send RX credits through an RX_DATA_ACK CPL message. Returns the number of + * credits sent. + */ +static u32 send_rx_credits(struct cxgbi_sock *csk, u32 credits) +{ + struct sk_buff *skb; + struct cpl_rx_data_ack *req; + u32 dack = F_RX_DACK_CHANGE | V_RX_DACK_MODE(1); + + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_RX, + "csk 0x%p,%u,0x%lx,%u, credit %u, dack %u.\n", + csk, csk->state, csk->flags, csk->tid, credits, dack); + + skb = alloc_wr(sizeof(*req), 0, GFP_ATOMIC); + if (!skb) { + pr_info("csk 0x%p, credit %u, OOM.\n", csk, credits); + return 0; + } + req = (struct cpl_rx_data_ack *)skb->head; + req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); + OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_RX_DATA_ACK, csk->tid)); + req->credit_dack = htonl(F_RX_DACK_CHANGE | V_RX_DACK_MODE(1) | + V_RX_CREDITS(credits)); + skb->priority = CPL_PRIORITY_ACK; + cxgb3_ofld_send(csk->cdev->lldev, skb); + return credits; +} + +/* + * CPL connection tx data: host -> + * + * Send iscsi PDU via TX_DATA CPL message. Returns the number of + * credits sent. + * Each TX_DATA consumes work request credit (wrs), so we need to keep track of + * how many we've used so far and how many are pending (i.e., yet ack'ed by T3). + */ + +static unsigned int wrlen __read_mostly; +static unsigned int skb_wrs[SKB_WR_LIST_SIZE] __read_mostly; + +static void init_wr_tab(unsigned int wr_len) +{ + int i; + + if (skb_wrs[1]) /* already initialized */ + return; + for (i = 1; i < SKB_WR_LIST_SIZE; i++) { + int sgl_len = (3 * i) / 2 + (i & 1); + + sgl_len += 3; + skb_wrs[i] = (sgl_len <= wr_len + ? 1 : 1 + (sgl_len - 2) / (wr_len - 1)); + } + wrlen = wr_len * 8; +} + +static inline void make_tx_data_wr(struct cxgbi_sock *csk, struct sk_buff *skb, + int len, int req_completion) +{ + struct tx_data_wr *req; + struct l2t_entry *l2t = csk->l2t; + + skb_reset_transport_header(skb); + req = (struct tx_data_wr *)__skb_push(skb, sizeof(*req)); + req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA) | + (req_completion ? F_WR_COMPL : 0)); + req->wr_lo = htonl(V_WR_TID(csk->tid)); + /* len includes the length of any HW ULP additions */ + req->len = htonl(len); + /* V_TX_ULP_SUBMODE sets both the mode and submode */ + req->flags = htonl(V_TX_ULP_SUBMODE(cxgbi_skcb_ulp_mode(skb)) | + V_TX_SHOVE((skb_peek(&csk->write_queue) ? 0 : 1))); + req->sndseq = htonl(csk->snd_nxt); + req->param = htonl(V_TX_PORT(l2t->smt_idx)); + + if (!cxgbi_sock_flag(csk, CTPF_TX_DATA_SENT)) { + req->flags |= htonl(V_TX_ACK_PAGES(2) | F_TX_INIT | + V_TX_CPU_IDX(csk->rss_qid)); + /* sendbuffer is in units of 32KB. */ + req->param |= htonl(V_TX_SNDBUF(cxgb3i_snd_win >> 15)); + cxgbi_sock_set_flag(csk, CTPF_TX_DATA_SENT); + } +} + +/** + * push_tx_frames -- start transmit + * @c3cn: the offloaded connection + * @req_completion: request wr_ack or not + * + * Prepends TX_DATA_WR or CPL_CLOSE_CON_REQ headers to buffers waiting in a + * connection's send queue and sends them on to T3. Must be called with the + * connection's lock held. Returns the amount of send buffer space that was + * freed as a result of sending queued data to T3. + */ + +static void arp_failure_skb_discard(struct t3cdev *dev, struct sk_buff *skb) +{ + kfree_skb(skb); +} + +static int push_tx_frames(struct cxgbi_sock *csk, int req_completion) +{ + int total_size = 0; + struct sk_buff *skb; + + if (unlikely(csk->state < CTP_ESTABLISHED || + csk->state == CTP_CLOSE_WAIT_1 || csk->state >= CTP_ABORTING)) { + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_TX, + "csk 0x%p,%u,0x%lx,%u, in closing state.\n", + csk, csk->state, csk->flags, csk->tid); + return 0; + } + + while (csk->wr_cred && (skb = skb_peek(&csk->write_queue)) != NULL) { + int len = skb->len; /* length before skb_push */ + int frags = skb_shinfo(skb)->nr_frags + (len != skb->data_len); + int wrs_needed = skb_wrs[frags]; + + if (wrs_needed > 1 && len + sizeof(struct tx_data_wr) <= wrlen) + wrs_needed = 1; + + WARN_ON(frags >= SKB_WR_LIST_SIZE || wrs_needed < 1); + + if (csk->wr_cred < wrs_needed) { + log_debug(1 << CXGBI_DBG_PDU_TX, + "csk 0x%p, skb len %u/%u, frag %u, wr %d<%u.\n", + csk, skb->len, skb->data_len, frags, + wrs_needed, csk->wr_cred); + break; + } + + __skb_unlink(skb, &csk->write_queue); + skb->priority = CPL_PRIORITY_DATA; + skb->csum = wrs_needed; /* remember this until the WR_ACK */ + csk->wr_cred -= wrs_needed; + csk->wr_una_cred += wrs_needed; + cxgbi_sock_enqueue_wr(csk, skb); + + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_TX, + "csk 0x%p, enqueue, skb len %u/%u, frag %u, wr %d, " + "left %u, unack %u.\n", + csk, skb->len, skb->data_len, frags, skb->csum, + csk->wr_cred, csk->wr_una_cred); + + if (likely(cxgbi_skcb_test_flag(skb, SKCBF_TX_NEED_HDR))) { + if ((req_completion && + csk->wr_una_cred == wrs_needed) || + csk->wr_una_cred >= csk->wr_max_cred / 2) { + req_completion = 1; + csk->wr_una_cred = 0; + } + len += cxgbi_ulp_extra_len(cxgbi_skcb_ulp_mode(skb)); + make_tx_data_wr(csk, skb, len, req_completion); + csk->snd_nxt += len; + cxgbi_skcb_clear_flag(skb, SKCBF_TX_NEED_HDR); + } + total_size += skb->truesize; + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_TX, + "csk 0x%p, tid 0x%x, send skb 0x%p.\n", + csk, csk->tid, skb); + set_arp_failure_handler(skb, arp_failure_skb_discard); + l2t_send(csk->cdev->lldev, skb, csk->l2t); + } + return total_size; +} + +/* + * Process a CPL_ACT_ESTABLISH message: -> host + * Updates connection state from an active establish CPL message. Runs with + * the connection lock held. + */ + +static inline void free_atid(struct cxgbi_sock *csk) +{ + if (cxgbi_sock_flag(csk, CTPF_HAS_ATID)) { + cxgb3_free_atid(csk->cdev->lldev, csk->atid); + cxgbi_sock_clear_flag(csk, CTPF_HAS_ATID); + cxgbi_sock_put(csk); + } +} + +static int do_act_establish(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) +{ + struct cxgbi_sock *csk = ctx; + struct cpl_act_establish *req = cplhdr(skb); + unsigned int tid = GET_TID(req); + unsigned int atid = G_PASS_OPEN_TID(ntohl(req->tos_tid)); + u32 rcv_isn = ntohl(req->rcv_isn); /* real RCV_ISN + 1 */ + + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, + "atid 0x%x,tid 0x%x, csk 0x%p,%u,0x%lx, isn %u.\n", + atid, atid, csk, csk->state, csk->flags, rcv_isn); + + cxgbi_sock_get(csk); + cxgbi_sock_set_flag(csk, CTPF_HAS_TID); + csk->tid = tid; + cxgb3_insert_tid(csk->cdev->lldev, &t3_client, csk, tid); + + free_atid(csk); + + csk->rss_qid = G_QNUM(ntohs(skb->csum)); + + spin_lock_bh(&csk->lock); + if (csk->retry_timer.function) { + del_timer(&csk->retry_timer); + csk->retry_timer.function = NULL; + } + + if (unlikely(csk->state != CTP_ACTIVE_OPEN)) + pr_info("csk 0x%p,%u,0x%lx,%u, got EST.\n", + csk, csk->state, csk->flags, csk->tid); + + csk->copied_seq = csk->rcv_wup = csk->rcv_nxt = rcv_isn; + if (cxgb3i_rcv_win > (M_RCV_BUFSIZ << 10)) + csk->rcv_wup -= cxgb3i_rcv_win - (M_RCV_BUFSIZ << 10); + + cxgbi_sock_established(csk, ntohl(req->snd_isn), ntohs(req->tcp_opt)); + + if (unlikely(cxgbi_sock_flag(csk, CTPF_ACTIVE_CLOSE_NEEDED))) + /* upper layer has requested closing */ + send_abort_req(csk); + else { + if (skb_queue_len(&csk->write_queue)) + push_tx_frames(csk, 1); + cxgbi_conn_tx_open(csk); + } + + spin_unlock_bh(&csk->lock); + __kfree_skb(skb); + return 0; +} + +/* + * Process a CPL_ACT_OPEN_RPL message: -> host + * Handle active open failures. + */ +static int act_open_rpl_status_to_errno(int status) +{ + switch (status) { + case CPL_ERR_CONN_RESET: + return -ECONNREFUSED; + case CPL_ERR_ARP_MISS: + return -EHOSTUNREACH; + case CPL_ERR_CONN_TIMEDOUT: + return -ETIMEDOUT; + case CPL_ERR_TCAM_FULL: + return -ENOMEM; + case CPL_ERR_CONN_EXIST: + return -EADDRINUSE; + default: + return -EIO; + } +} + +static void act_open_retry_timer(unsigned long data) +{ + struct sk_buff *skb; + struct cxgbi_sock *csk = (struct cxgbi_sock *)data; + + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, + "csk 0x%p,%u,0x%lx,%u.\n", + csk, csk->state, csk->flags, csk->tid); + + cxgbi_sock_get(csk); + spin_lock_bh(&csk->lock); + skb = alloc_wr(sizeof(struct cpl_act_open_req), 0, GFP_ATOMIC); + if (!skb) + cxgbi_sock_fail_act_open(csk, -ENOMEM); + else { + skb->sk = (struct sock *)csk; + set_arp_failure_handler(skb, act_open_arp_failure); + send_act_open_req(csk, skb, csk->l2t); + } + spin_unlock_bh(&csk->lock); + cxgbi_sock_put(csk); +} + +static int do_act_open_rpl(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) +{ + struct cxgbi_sock *csk = ctx; + struct cpl_act_open_rpl *rpl = cplhdr(skb); + + pr_info("csk 0x%p,%u,0x%lx,%u, status %u, %pI4:%u-%pI4:%u.\n", + csk, csk->state, csk->flags, csk->atid, rpl->status, + &csk->saddr.sin_addr.s_addr, ntohs(csk->saddr.sin_port), + &csk->daddr.sin_addr.s_addr, ntohs(csk->daddr.sin_port)); + + if (rpl->status != CPL_ERR_TCAM_FULL && + rpl->status != CPL_ERR_CONN_EXIST && + rpl->status != CPL_ERR_ARP_MISS) + cxgb3_queue_tid_release(tdev, GET_TID(rpl)); + + cxgbi_sock_get(csk); + spin_lock_bh(&csk->lock); + if (rpl->status == CPL_ERR_CONN_EXIST && + csk->retry_timer.function != act_open_retry_timer) { + csk->retry_timer.function = act_open_retry_timer; + mod_timer(&csk->retry_timer, jiffies + HZ / 2); + } else + cxgbi_sock_fail_act_open(csk, + act_open_rpl_status_to_errno(rpl->status)); + + spin_unlock_bh(&csk->lock); + cxgbi_sock_put(csk); + __kfree_skb(skb); + return 0; +} + +/* + * Process PEER_CLOSE CPL messages: -> host + * Handle peer FIN. + */ +static int do_peer_close(struct t3cdev *cdev, struct sk_buff *skb, void *ctx) +{ + struct cxgbi_sock *csk = ctx; + + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, + "csk 0x%p,%u,0x%lx,%u.\n", + csk, csk->state, csk->flags, csk->tid); + + cxgbi_sock_rcv_peer_close(csk); + __kfree_skb(skb); + return 0; +} + +/* + * Process CLOSE_CONN_RPL CPL message: -> host + * Process a peer ACK to our FIN. + */ +static int do_close_con_rpl(struct t3cdev *cdev, struct sk_buff *skb, + void *ctx) +{ + struct cxgbi_sock *csk = ctx; + struct cpl_close_con_rpl *rpl = cplhdr(skb); + + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, + "csk 0x%p,%u,0x%lx,%u, snxt %u.\n", + csk, csk->state, csk->flags, csk->tid, ntohl(rpl->snd_nxt)); + + cxgbi_sock_rcv_close_conn_rpl(csk, ntohl(rpl->snd_nxt)); + __kfree_skb(skb); + return 0; +} + +/* + * Process ABORT_REQ_RSS CPL message: -> host + * Process abort requests. If we are waiting for an ABORT_RPL we ignore this + * request except that we need to reply to it. + */ + +static int abort_status_to_errno(struct cxgbi_sock *csk, int abort_reason, + int *need_rst) +{ + switch (abort_reason) { + case CPL_ERR_BAD_SYN: /* fall through */ + case CPL_ERR_CONN_RESET: + return csk->state > CTP_ESTABLISHED ? -EPIPE : -ECONNRESET; + case CPL_ERR_XMIT_TIMEDOUT: + case CPL_ERR_PERSIST_TIMEDOUT: + case CPL_ERR_FINWAIT2_TIMEDOUT: + case CPL_ERR_KEEPALIVE_TIMEDOUT: + return -ETIMEDOUT; + default: + return -EIO; + } +} + +static int do_abort_req(struct t3cdev *cdev, struct sk_buff *skb, void *ctx) +{ + const struct cpl_abort_req_rss *req = cplhdr(skb); + struct cxgbi_sock *csk = ctx; + int rst_status = CPL_ABORT_NO_RST; + + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, + "csk 0x%p,%u,0x%lx,%u.\n", + csk, csk->state, csk->flags, csk->tid); + + if (req->status == CPL_ERR_RTX_NEG_ADVICE || + req->status == CPL_ERR_PERSIST_NEG_ADVICE) { + goto done; + } + + cxgbi_sock_get(csk); + spin_lock_bh(&csk->lock); + + if (!cxgbi_sock_flag(csk, CTPF_ABORT_REQ_RCVD)) { + cxgbi_sock_set_flag(csk, CTPF_ABORT_REQ_RCVD); + cxgbi_sock_set_state(csk, CTP_ABORTING); + goto out; + } + + cxgbi_sock_clear_flag(csk, CTPF_ABORT_REQ_RCVD); + send_abort_rpl(csk, rst_status); + + if (!cxgbi_sock_flag(csk, CTPF_ABORT_RPL_PENDING)) { + csk->err = abort_status_to_errno(csk, req->status, &rst_status); + cxgbi_sock_closed(csk); + } + +out: + spin_unlock_bh(&csk->lock); + cxgbi_sock_put(csk); +done: + __kfree_skb(skb); + return 0; +} + +/* + * Process ABORT_RPL_RSS CPL message: -> host + * Process abort replies. We only process these messages if we anticipate + * them as the coordination between SW and HW in this area is somewhat lacking + * and sometimes we get ABORT_RPLs after we are done with the connection that + * originated the ABORT_REQ. + */ +static int do_abort_rpl(struct t3cdev *cdev, struct sk_buff *skb, void *ctx) +{ + struct cpl_abort_rpl_rss *rpl = cplhdr(skb); + struct cxgbi_sock *csk = ctx; + + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, + "status 0x%x, csk 0x%p, s %u, 0x%lx.\n", + rpl->status, csk, csk ? csk->state : 0, + csk ? csk->flags : 0UL); + /* + * Ignore replies to post-close aborts indicating that the abort was + * requested too late. These connections are terminated when we get + * PEER_CLOSE or CLOSE_CON_RPL and by the time the abort_rpl_rss + * arrives the TID is either no longer used or it has been recycled. + */ + if (rpl->status == CPL_ERR_ABORT_FAILED) + goto rel_skb; + /* + * Sometimes we've already closed the connection, e.g., a post-close + * abort races with ABORT_REQ_RSS, the latter frees the connection + * expecting the ABORT_REQ will fail with CPL_ERR_ABORT_FAILED, + * but FW turns the ABORT_REQ into a regular one and so we get + * ABORT_RPL_RSS with status 0 and no connection. + */ + if (csk) + cxgbi_sock_rcv_abort_rpl(csk); +rel_skb: + __kfree_skb(skb); + return 0; +} + +/* + * Process RX_ISCSI_HDR CPL message: -> host + * Handle received PDUs, the payload could be DDP'ed. If not, the payload + * follow after the bhs. + */ +static int do_iscsi_hdr(struct t3cdev *t3dev, struct sk_buff *skb, void *ctx) +{ + struct cxgbi_sock *csk = ctx; + struct cpl_iscsi_hdr *hdr_cpl = cplhdr(skb); + struct cpl_iscsi_hdr_norss data_cpl; + struct cpl_rx_data_ddp_norss ddp_cpl; + unsigned int hdr_len, data_len, status; + unsigned int len; + int err; + + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_RX, + "csk 0x%p,%u,0x%lx,%u, skb 0x%p,%u.\n", + csk, csk->state, csk->flags, csk->tid, skb, skb->len); + + spin_lock_bh(&csk->lock); + + if (unlikely(csk->state >= CTP_PASSIVE_CLOSE)) { + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, + "csk 0x%p,%u,0x%lx,%u, bad state.\n", + csk, csk->state, csk->flags, csk->tid); + if (csk->state != CTP_ABORTING) + goto abort_conn; + else + goto discard; + } + + cxgbi_skcb_tcp_seq(skb) = ntohl(hdr_cpl->seq); + cxgbi_skcb_flags(skb) = 0; + + skb_reset_transport_header(skb); + __skb_pull(skb, sizeof(struct cpl_iscsi_hdr)); + + len = hdr_len = ntohs(hdr_cpl->len); + /* msg coalesce is off or not enough data received */ + if (skb->len <= hdr_len) { + pr_err("%s: tid %u, CPL_ISCSI_HDR, skb len %u < %u.\n", + csk->cdev->ports[csk->port_id]->name, csk->tid, + skb->len, hdr_len); + goto abort_conn; + } + cxgbi_skcb_set_flag(skb, SKCBF_RX_COALESCED); + + err = skb_copy_bits(skb, skb->len - sizeof(ddp_cpl), &ddp_cpl, + sizeof(ddp_cpl)); + if (err < 0) { + pr_err("%s: tid %u, copy cpl_ddp %u-%zu failed %d.\n", + csk->cdev->ports[csk->port_id]->name, csk->tid, + skb->len, sizeof(ddp_cpl), err); + goto abort_conn; + } + + cxgbi_skcb_set_flag(skb, SKCBF_RX_STATUS); + cxgbi_skcb_rx_pdulen(skb) = ntohs(ddp_cpl.len); + cxgbi_skcb_rx_ddigest(skb) = ntohl(ddp_cpl.ulp_crc); + status = ntohl(ddp_cpl.ddp_status); + + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_RX, + "csk 0x%p, skb 0x%p,%u, pdulen %u, status 0x%x.\n", + csk, skb, skb->len, cxgbi_skcb_rx_pdulen(skb), status); + + if (status & (1 << CPL_RX_DDP_STATUS_HCRC_SHIFT)) + cxgbi_skcb_set_flag(skb, SKCBF_RX_HCRC_ERR); + if (status & (1 << CPL_RX_DDP_STATUS_DCRC_SHIFT)) + cxgbi_skcb_set_flag(skb, SKCBF_RX_DCRC_ERR); + if (status & (1 << CPL_RX_DDP_STATUS_PAD_SHIFT)) + cxgbi_skcb_set_flag(skb, SKCBF_RX_PAD_ERR); + + if (skb->len > (hdr_len + sizeof(ddp_cpl))) { + err = skb_copy_bits(skb, hdr_len, &data_cpl, sizeof(data_cpl)); + if (err < 0) { + pr_err("%s: tid %u, cp %zu/%u failed %d.\n", + csk->cdev->ports[csk->port_id]->name, + csk->tid, sizeof(data_cpl), skb->len, err); + goto abort_conn; + } + data_len = ntohs(data_cpl.len); + log_debug(1 << CXGBI_DBG_DDP | 1 << CXGBI_DBG_PDU_RX, + "skb 0x%p, pdu not ddp'ed %u/%u, status 0x%x.\n", + skb, data_len, cxgbi_skcb_rx_pdulen(skb), status); + len += sizeof(data_cpl) + data_len; + } else if (status & (1 << CPL_RX_DDP_STATUS_DDP_SHIFT)) + cxgbi_skcb_set_flag(skb, SKCBF_RX_DATA_DDPD); + + csk->rcv_nxt = ntohl(ddp_cpl.seq) + cxgbi_skcb_rx_pdulen(skb); + __pskb_trim(skb, len); + __skb_queue_tail(&csk->receive_queue, skb); + cxgbi_conn_pdu_ready(csk); + + spin_unlock_bh(&csk->lock); + return 0; + +abort_conn: + send_abort_req(csk); +discard: + spin_unlock_bh(&csk->lock); + __kfree_skb(skb); + return 0; +} + +/* + * Process TX_DATA_ACK CPL messages: -> host + * Process an acknowledgment of WR completion. Advance snd_una and send the + * next batch of work requests from the write queue. + */ +static int do_wr_ack(struct t3cdev *cdev, struct sk_buff *skb, void *ctx) +{ + struct cxgbi_sock *csk = ctx; + struct cpl_wr_ack *hdr = cplhdr(skb); + + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_RX, + "csk 0x%p,%u,0x%lx,%u, cr %u.\n", + csk, csk->state, csk->flags, csk->tid, ntohs(hdr->credits)); + + cxgbi_sock_rcv_wr_ack(csk, ntohs(hdr->credits), ntohl(hdr->snd_una), 1); + __kfree_skb(skb); + return 0; +} + +/* + * for each connection, pre-allocate skbs needed for close/abort requests. So + * that we can service the request right away. + */ +static int alloc_cpls(struct cxgbi_sock *csk) +{ + csk->cpl_close = alloc_wr(sizeof(struct cpl_close_con_req), 0, + GFP_KERNEL); + if (!csk->cpl_close) + return -ENOMEM; + csk->cpl_abort_req = alloc_wr(sizeof(struct cpl_abort_req), 0, + GFP_KERNEL); + if (!csk->cpl_abort_req) + goto free_cpl_skbs; + + csk->cpl_abort_rpl = alloc_wr(sizeof(struct cpl_abort_rpl), 0, + GFP_KERNEL); + if (!csk->cpl_abort_rpl) + goto free_cpl_skbs; + + return 0; + +free_cpl_skbs: + cxgbi_sock_free_cpl_skbs(csk); + return -ENOMEM; +} + +/** + * release_offload_resources - release offload resource + * @c3cn: the offloaded iscsi tcp connection. + * Release resources held by an offload connection (TID, L2T entry, etc.) + */ +static void l2t_put(struct cxgbi_sock *csk) +{ + struct t3cdev *t3dev = (struct t3cdev *)csk->cdev->lldev; + + if (csk->l2t) { + l2t_release(L2DATA(t3dev), csk->l2t); + csk->l2t = NULL; + cxgbi_sock_put(csk); + } +} + +static void release_offload_resources(struct cxgbi_sock *csk) +{ + struct t3cdev *t3dev = (struct t3cdev *)csk->cdev->lldev; + + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, + "csk 0x%p,%u,0x%lx,%u.\n", + csk, csk->state, csk->flags, csk->tid); + + csk->rss_qid = 0; + cxgbi_sock_free_cpl_skbs(csk); + + if (csk->wr_cred != csk->wr_max_cred) { + cxgbi_sock_purge_wr_queue(csk); + cxgbi_sock_reset_wr_list(csk); + } + l2t_put(csk); + if (cxgbi_sock_flag(csk, CTPF_HAS_ATID)) + free_atid(csk); + else if (cxgbi_sock_flag(csk, CTPF_HAS_TID)) { + cxgb3_remove_tid(t3dev, (void *)csk, csk->tid); + cxgbi_sock_clear_flag(csk, CTPF_HAS_TID); + cxgbi_sock_put(csk); + } + csk->dst = NULL; + csk->cdev = NULL; +} + +static void update_address(struct cxgbi_hba *chba) +{ + if (chba->ipv4addr) { + if (chba->vdev && + chba->ipv4addr != cxgb3i_get_private_ipv4addr(chba->vdev)) { + cxgb3i_set_private_ipv4addr(chba->vdev, chba->ipv4addr); + cxgb3i_set_private_ipv4addr(chba->ndev, 0); + pr_info("%s set %pI4.\n", + chba->vdev->name, &chba->ipv4addr); + } else if (chba->ipv4addr != + cxgb3i_get_private_ipv4addr(chba->ndev)) { + cxgb3i_set_private_ipv4addr(chba->ndev, chba->ipv4addr); + pr_info("%s set %pI4.\n", + chba->ndev->name, &chba->ipv4addr); + } + } else if (cxgb3i_get_private_ipv4addr(chba->ndev)) { + if (chba->vdev) + cxgb3i_set_private_ipv4addr(chba->vdev, 0); + cxgb3i_set_private_ipv4addr(chba->ndev, 0); + } +} + +static int init_act_open(struct cxgbi_sock *csk) +{ + struct dst_entry *dst = csk->dst; + struct cxgbi_device *cdev = csk->cdev; + struct t3cdev *t3dev = (struct t3cdev *)cdev->lldev; + struct net_device *ndev = cdev->ports[csk->port_id]; + struct cxgbi_hba *chba = cdev->hbas[csk->port_id]; + struct sk_buff *skb = NULL; + + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, + "csk 0x%p,%u,0x%lx.\n", csk, csk->state, csk->flags); + + update_address(chba); + if (chba->ipv4addr) + csk->saddr.sin_addr.s_addr = chba->ipv4addr; + + csk->rss_qid = 0; + csk->l2t = t3_l2t_get(t3dev, dst->neighbour, ndev); + if (!csk->l2t) { + pr_err("NO l2t available.\n"); + return -EINVAL; + } + cxgbi_sock_get(csk); + + csk->atid = cxgb3_alloc_atid(t3dev, &t3_client, csk); + if (csk->atid < 0) { + pr_err("NO atid available.\n"); + goto rel_resource; + } + cxgbi_sock_set_flag(csk, CTPF_HAS_ATID); + cxgbi_sock_get(csk); + + skb = alloc_wr(sizeof(struct cpl_act_open_req), 0, GFP_KERNEL); + if (!skb) + goto rel_resource; + skb->sk = (struct sock *)csk; + set_arp_failure_handler(skb, act_open_arp_failure); + + csk->wr_max_cred = csk->wr_cred = T3C_DATA(t3dev)->max_wrs - 1; + csk->wr_una_cred = 0; + csk->mss_idx = cxgbi_sock_select_mss(csk, dst_mtu(dst)); + cxgbi_sock_reset_wr_list(csk); + csk->err = 0; + + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, + "csk 0x%p,%u,0x%lx, %pI4:%u-%pI4:%u.\n", + csk, csk->state, csk->flags, + &csk->saddr.sin_addr.s_addr, ntohs(csk->saddr.sin_port), + &csk->daddr.sin_addr.s_addr, ntohs(csk->daddr.sin_port)); + + cxgbi_sock_set_state(csk, CTP_ACTIVE_OPEN); + send_act_open_req(csk, skb, csk->l2t); + return 0; + +rel_resource: + if (skb) + __kfree_skb(skb); + return -EINVAL; +} + +cxgb3_cpl_handler_func cxgb3i_cpl_handlers[NUM_CPL_CMDS] = { + [CPL_ACT_ESTABLISH] = do_act_establish, + [CPL_ACT_OPEN_RPL] = do_act_open_rpl, + [CPL_PEER_CLOSE] = do_peer_close, + [CPL_ABORT_REQ_RSS] = do_abort_req, + [CPL_ABORT_RPL_RSS] = do_abort_rpl, + [CPL_CLOSE_CON_RPL] = do_close_con_rpl, + [CPL_TX_DMA_ACK] = do_wr_ack, + [CPL_ISCSI_HDR] = do_iscsi_hdr, +}; + +/** + * cxgb3i_ofld_init - allocate and initialize resources for each adapter found + * @cdev: cxgbi adapter + */ +int cxgb3i_ofld_init(struct cxgbi_device *cdev) +{ + struct t3cdev *t3dev = (struct t3cdev *)cdev->lldev; + struct adap_ports port; + struct ofld_page_info rx_page_info; + unsigned int wr_len; + int rc; + + if (t3dev->ctl(t3dev, GET_WR_LEN, &wr_len) < 0 || + t3dev->ctl(t3dev, GET_PORTS, &port) < 0 || + t3dev->ctl(t3dev, GET_RX_PAGE_INFO, &rx_page_info) < 0) { + pr_warn("t3 0x%p, offload up, ioctl failed.\n", t3dev); + return -EINVAL; + } + + if (cxgb3i_max_connect > CXGBI_MAX_CONN) + cxgb3i_max_connect = CXGBI_MAX_CONN; + + rc = cxgbi_device_portmap_create(cdev, cxgb3i_sport_base, + cxgb3i_max_connect); + if (rc < 0) + return rc; + + init_wr_tab(wr_len); + cdev->csk_release_offload_resources = release_offload_resources; + cdev->csk_push_tx_frames = push_tx_frames; + cdev->csk_send_abort_req = send_abort_req; + cdev->csk_send_close_req = send_close_req; + cdev->csk_send_rx_credits = send_rx_credits; + cdev->csk_alloc_cpls = alloc_cpls; + cdev->csk_init_act_open = init_act_open; + + pr_info("cdev 0x%p, offload up, added.\n", cdev); + return 0; +} + +/* + * functions to program the pagepod in h/w + */ +static inline void ulp_mem_io_set_hdr(struct sk_buff *skb, unsigned int addr) +{ + struct ulp_mem_io *req = (struct ulp_mem_io *)skb->head; + + memset(req, 0, sizeof(*req)); + + req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_BYPASS)); + req->cmd_lock_addr = htonl(V_ULP_MEMIO_ADDR(addr >> 5) | + V_ULPTX_CMD(ULP_MEM_WRITE)); + req->len = htonl(V_ULP_MEMIO_DATA_LEN(PPOD_SIZE >> 5) | + V_ULPTX_NFLITS((PPOD_SIZE >> 3) + 1)); +} + +static int ddp_set_map(struct cxgbi_sock *csk, struct cxgbi_pagepod_hdr *hdr, + unsigned int idx, unsigned int npods, + struct cxgbi_gather_list *gl) +{ + struct cxgbi_device *cdev = csk->cdev; + struct cxgbi_ddp_info *ddp = cdev->ddp; + unsigned int pm_addr = (idx << PPOD_SIZE_SHIFT) + ddp->llimit; + int i; + + log_debug(1 << CXGBI_DBG_DDP, + "csk 0x%p, idx %u, npods %u, gl 0x%p.\n", + csk, idx, npods, gl); + + for (i = 0; i < npods; i++, idx++, pm_addr += PPOD_SIZE) { + struct sk_buff *skb = ddp->gl_skb[idx]; + + /* hold on to the skb until we clear the ddp mapping */ + skb_get(skb); + + ulp_mem_io_set_hdr(skb, pm_addr); + cxgbi_ddp_ppod_set((struct cxgbi_pagepod *)(skb->head + + sizeof(struct ulp_mem_io)), + hdr, gl, i * PPOD_PAGES_MAX); + skb->priority = CPL_PRIORITY_CONTROL; + cxgb3_ofld_send(cdev->lldev, skb); + } + return 0; +} + +static void ddp_clear_map(struct cxgbi_hba *chba, unsigned int tag, + unsigned int idx, unsigned int npods) +{ + struct cxgbi_device *cdev = chba->cdev; + struct cxgbi_ddp_info *ddp = cdev->ddp; + unsigned int pm_addr = (idx << PPOD_SIZE_SHIFT) + ddp->llimit; + int i; + + log_debug(1 << CXGBI_DBG_DDP, + "cdev 0x%p, idx %u, npods %u, tag 0x%x.\n", + cdev, idx, npods, tag); + + for (i = 0; i < npods; i++, idx++, pm_addr += PPOD_SIZE) { + struct sk_buff *skb = ddp->gl_skb[idx]; + + if (!skb) { + pr_err("tag 0x%x, 0x%x, %d/%u, skb NULL.\n", + tag, idx, i, npods); + continue; + } + ddp->gl_skb[idx] = NULL; + memset(skb->head + sizeof(struct ulp_mem_io), 0, PPOD_SIZE); + ulp_mem_io_set_hdr(skb, pm_addr); + skb->priority = CPL_PRIORITY_CONTROL; + cxgb3_ofld_send(cdev->lldev, skb); + } +} + +static void ddp_free_gl_skb(struct cxgbi_ddp_info *ddp, int idx, int cnt) +{ + int i; + + log_debug(1 << CXGBI_DBG_DDP, + "ddp 0x%p, idx %d, cnt %d.\n", ddp, idx, cnt); + + for (i = 0; i < cnt; i++, idx++) + if (ddp->gl_skb[idx]) { + kfree_skb(ddp->gl_skb[idx]); + ddp->gl_skb[idx] = NULL; + } +} + +static int ddp_alloc_gl_skb(struct cxgbi_ddp_info *ddp, int idx, + int cnt, gfp_t gfp) +{ + int i; + + log_debug(1 << CXGBI_DBG_DDP, + "ddp 0x%p, idx %d, cnt %d.\n", ddp, idx, cnt); + + for (i = 0; i < cnt; i++) { + struct sk_buff *skb = alloc_wr(sizeof(struct ulp_mem_io) + + PPOD_SIZE, 0, gfp); + if (skb) + ddp->gl_skb[idx + i] = skb; + else { + ddp_free_gl_skb(ddp, idx, i); + return -ENOMEM; + } + } + return 0; +} + +static int ddp_setup_conn_pgidx(struct cxgbi_sock *csk, + unsigned int tid, int pg_idx, bool reply) +{ + struct sk_buff *skb = alloc_wr(sizeof(struct cpl_set_tcb_field), 0, + GFP_KERNEL); + struct cpl_set_tcb_field *req; + u64 val = pg_idx < DDP_PGIDX_MAX ? pg_idx : 0; + + log_debug(1 << CXGBI_DBG_DDP, + "csk 0x%p, tid %u, pg_idx %d.\n", csk, tid, pg_idx); + if (!skb) + return -ENOMEM; + + /* set up ulp submode and page size */ + req = (struct cpl_set_tcb_field *)skb->head; + req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); + OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, tid)); + req->reply = V_NO_REPLY(reply ? 0 : 1); + req->cpu_idx = 0; + req->word = htons(31); + req->mask = cpu_to_be64(0xF0000000); + req->val = cpu_to_be64(val << 28); + skb->priority = CPL_PRIORITY_CONTROL; + + cxgb3_ofld_send(csk->cdev->lldev, skb); + return 0; +} + +/** + * cxgb3i_setup_conn_digest - setup conn. digest setting + * @csk: cxgb tcp socket + * @tid: connection id + * @hcrc: header digest enabled + * @dcrc: data digest enabled + * @reply: request reply from h/w + * set up the iscsi digest settings for a connection identified by tid + */ +static int ddp_setup_conn_digest(struct cxgbi_sock *csk, unsigned int tid, + int hcrc, int dcrc, int reply) +{ + struct sk_buff *skb = alloc_wr(sizeof(struct cpl_set_tcb_field), 0, + GFP_KERNEL); + struct cpl_set_tcb_field *req; + u64 val = (hcrc ? 1 : 0) | (dcrc ? 2 : 0); + + log_debug(1 << CXGBI_DBG_DDP, + "csk 0x%p, tid %u, crc %d,%d.\n", csk, tid, hcrc, dcrc); + if (!skb) + return -ENOMEM; + + /* set up ulp submode and page size */ + req = (struct cpl_set_tcb_field *)skb->head; + req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); + OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, tid)); + req->reply = V_NO_REPLY(reply ? 0 : 1); + req->cpu_idx = 0; + req->word = htons(31); + req->mask = cpu_to_be64(0x0F000000); + req->val = cpu_to_be64(val << 24); + skb->priority = CPL_PRIORITY_CONTROL; + + cxgb3_ofld_send(csk->cdev->lldev, skb); + return 0; +} + +/** + * t3_ddp_cleanup - release the cxgb3 adapter's ddp resource + * @cdev: cxgb3i adapter + * release all the resource held by the ddp pagepod manager for a given + * adapter if needed + */ + +static void t3_ddp_cleanup(struct cxgbi_device *cdev) +{ + struct t3cdev *tdev = (struct t3cdev *)cdev->lldev; + + if (cxgbi_ddp_cleanup(cdev)) { + pr_info("t3dev 0x%p, ulp_iscsi no more user.\n", tdev); + tdev->ulp_iscsi = NULL; + } +} + +/** + * ddp_init - initialize the cxgb3 adapter's ddp resource + * @cdev: cxgb3i adapter + * initialize the ddp pagepod manager for a given adapter + */ +static int cxgb3i_ddp_init(struct cxgbi_device *cdev) +{ + struct t3cdev *tdev = (struct t3cdev *)cdev->lldev; + struct cxgbi_ddp_info *ddp = tdev->ulp_iscsi; + struct ulp_iscsi_info uinfo; + unsigned int pgsz_factor[4]; + int err; + + if (ddp) { + kref_get(&ddp->refcnt); + pr_warn("t3dev 0x%p, ddp 0x%p already set up.\n", + tdev, tdev->ulp_iscsi); + cdev->ddp = ddp; + return -EALREADY; + } + + err = tdev->ctl(tdev, ULP_ISCSI_GET_PARAMS, &uinfo); + if (err < 0) { + pr_err("%s, failed to get iscsi param err=%d.\n", + tdev->name, err); + return err; + } + + err = cxgbi_ddp_init(cdev, uinfo.llimit, uinfo.ulimit, + uinfo.max_txsz, uinfo.max_rxsz); + if (err < 0) + return err; + + ddp = cdev->ddp; + + uinfo.tagmask = ddp->idx_mask << PPOD_IDX_SHIFT; + cxgbi_ddp_page_size_factor(pgsz_factor); + uinfo.ulimit = uinfo.llimit + (ddp->nppods << PPOD_SIZE_SHIFT); + + err = tdev->ctl(tdev, ULP_ISCSI_SET_PARAMS, &uinfo); + if (err < 0) { + pr_warn("%s unable to set iscsi param err=%d, ddp disabled.\n", + tdev->name, err); + cxgbi_ddp_cleanup(cdev); + return err; + } + tdev->ulp_iscsi = ddp; + + cdev->csk_ddp_free_gl_skb = ddp_free_gl_skb; + cdev->csk_ddp_alloc_gl_skb = ddp_alloc_gl_skb; + cdev->csk_ddp_setup_digest = ddp_setup_conn_digest; + cdev->csk_ddp_setup_pgidx = ddp_setup_conn_pgidx; + cdev->csk_ddp_set = ddp_set_map; + cdev->csk_ddp_clear = ddp_clear_map; + + pr_info("tdev 0x%p, nppods %u, bits %u, mask 0x%x,0x%x pkt %u/%u, " + "%u/%u.\n", + tdev, ddp->nppods, ddp->idx_bits, ddp->idx_mask, + ddp->rsvd_tag_mask, ddp->max_txsz, uinfo.max_txsz, + ddp->max_rxsz, uinfo.max_rxsz); + return 0; +} + +static void cxgb3i_dev_close(struct t3cdev *t3dev) +{ + struct cxgbi_device *cdev = cxgbi_device_find_by_lldev(t3dev); + + if (!cdev || cdev->flags & CXGBI_FLAG_ADAPTER_RESET) { + pr_info("0x%p close, f 0x%x.\n", cdev, cdev ? cdev->flags : 0); + return; + } + + cxgbi_device_unregister(cdev); +} + +/** + * cxgb3i_dev_open - init a t3 adapter structure and any h/w settings + * @t3dev: t3cdev adapter + */ +static void cxgb3i_dev_open(struct t3cdev *t3dev) +{ + struct cxgbi_device *cdev = cxgbi_device_find_by_lldev(t3dev); + struct adapter *adapter = tdev2adap(t3dev); + int i, err; + + if (cdev) { + pr_info("0x%p, updating.\n", cdev); + return; + } + + cdev = cxgbi_device_register(0, adapter->params.nports); + if (!cdev) { + pr_warn("device 0x%p register failed.\n", t3dev); + return; + } + + cdev->flags = CXGBI_FLAG_DEV_T3 | CXGBI_FLAG_IPV4_SET; + cdev->lldev = t3dev; + cdev->pdev = adapter->pdev; + cdev->ports = adapter->port; + cdev->nports = adapter->params.nports; + cdev->mtus = adapter->params.mtus; + cdev->nmtus = NMTUS; + cdev->snd_win = cxgb3i_snd_win; + cdev->rcv_win = cxgb3i_rcv_win; + cdev->rx_credit_thres = cxgb3i_rx_credit_thres; + cdev->skb_tx_rsvd = CXGB3I_TX_HEADER_LEN; + cdev->skb_rx_extra = sizeof(struct cpl_iscsi_hdr_norss); + cdev->dev_ddp_cleanup = t3_ddp_cleanup; + cdev->itp = &cxgb3i_iscsi_transport; + + err = cxgb3i_ddp_init(cdev); + if (err) { + pr_info("0x%p ddp init failed\n", cdev); + goto err_out; + } + + err = cxgb3i_ofld_init(cdev); + if (err) { + pr_info("0x%p offload init failed\n", cdev); + goto err_out; + } + + err = cxgbi_hbas_add(cdev, CXGB3I_MAX_LUN, CXGBI_MAX_CONN, + &cxgb3i_host_template, cxgb3i_stt); + if (err) + goto err_out; + + for (i = 0; i < cdev->nports; i++) + cdev->hbas[i]->ipv4addr = + cxgb3i_get_private_ipv4addr(cdev->ports[i]); + + pr_info("cdev 0x%p, f 0x%x, t3dev 0x%p open, err %d.\n", + cdev, cdev ? cdev->flags : 0, t3dev, err); + return; + +err_out: + cxgbi_device_unregister(cdev); +} + +static void cxgb3i_dev_event_handler(struct t3cdev *t3dev, u32 event, u32 port) +{ + struct cxgbi_device *cdev = cxgbi_device_find_by_lldev(t3dev); + + log_debug(1 << CXGBI_DBG_TOE, + "0x%p, cdev 0x%p, event 0x%x, port 0x%x.\n", + t3dev, cdev, event, port); + if (!cdev) + return; + + switch (event) { + case OFFLOAD_STATUS_DOWN: + cdev->flags |= CXGBI_FLAG_ADAPTER_RESET; + break; + case OFFLOAD_STATUS_UP: + cdev->flags &= ~CXGBI_FLAG_ADAPTER_RESET; + break; + } +} + +/** + * cxgb3i_init_module - module init entry point + * + * initialize any driver wide global data structures and register itself + * with the cxgb3 module + */ +static int __init cxgb3i_init_module(void) +{ + int rc; + + printk(KERN_INFO "%s", version); + + rc = cxgbi_iscsi_init(&cxgb3i_iscsi_transport, &cxgb3i_stt); + if (rc < 0) + return rc; + + cxgb3_register_client(&t3_client); + return 0; +} + +/** + * cxgb3i_exit_module - module cleanup/exit entry point + * + * go through the driver hba list and for each hba, release any resource held. + * and unregisters iscsi transport and the cxgb3 module + */ +static void __exit cxgb3i_exit_module(void) +{ + cxgb3_unregister_client(&t3_client); + cxgbi_device_unregister_all(CXGBI_FLAG_DEV_T3); + cxgbi_iscsi_cleanup(&cxgb3i_iscsi_transport, &cxgb3i_stt); +} + +module_init(cxgb3i_init_module); +module_exit(cxgb3i_exit_module); diff --git a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.h b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.h new file mode 100644 index 000000000000..5f5e3394b594 --- /dev/null +++ b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.h @@ -0,0 +1,51 @@ +/* + * cxgb3i.h: Chelsio S3xx iSCSI driver. + * + * Copyright (c) 2008 Chelsio Communications, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation. + * + * Written by: Karen Xie (kxie@chelsio.com) + */ + +#ifndef __CXGB3I_H__ +#define __CXGB3I_H__ + +#define CXGB3I_SCSI_HOST_QDEPTH 1024 +#define CXGB3I_MAX_LUN 512 +#define ISCSI_PDU_NONPAYLOAD_MAX \ + (sizeof(struct iscsi_hdr) + ISCSI_MAX_AHS_SIZE + 2*ISCSI_DIGEST_SIZE) + +/*for TX: a skb must have a headroom of at least TX_HEADER_LEN bytes */ +#define CXGB3I_TX_HEADER_LEN \ + (sizeof(struct tx_data_wr) + sizeof(struct sge_opaque_hdr)) + +extern cxgb3_cpl_handler_func cxgb3i_cpl_handlers[NUM_CPL_CMDS]; + +#define cxgb3i_get_private_ipv4addr(ndev) \ + (((struct port_info *)(netdev_priv(ndev)))->iscsi_ipv4addr) +#define cxgb3i_set_private_ipv4addr(ndev, addr) \ + (((struct port_info *)(netdev_priv(ndev)))->iscsi_ipv4addr) = addr + +struct cpl_iscsi_hdr_norss { + union opcode_tid ot; + u16 pdu_len_ddp; + u16 len; + u32 seq; + u16 urg; + u8 rsvd; + u8 status; +}; + +struct cpl_rx_data_ddp_norss { + union opcode_tid ot; + u16 urg; + u16 len; + u32 seq; + u32 nxt_seq; + u32 ulp_crc; + u32 ddp_status; +}; +#endif diff --git a/drivers/scsi/cxgbi/cxgb4i/Kbuild b/drivers/scsi/cxgbi/cxgb4i/Kbuild new file mode 100644 index 000000000000..b9f4af7454b7 --- /dev/null +++ b/drivers/scsi/cxgbi/cxgb4i/Kbuild @@ -0,0 +1,3 @@ +EXTRA_CFLAGS += -I$(srctree)/drivers/net/cxgb4 + +obj-$(CONFIG_SCSI_CXGB4_ISCSI) += cxgb4i.o diff --git a/drivers/scsi/cxgbi/cxgb4i/Kconfig b/drivers/scsi/cxgbi/cxgb4i/Kconfig new file mode 100644 index 000000000000..bb94b39b17b3 --- /dev/null +++ b/drivers/scsi/cxgbi/cxgb4i/Kconfig @@ -0,0 +1,7 @@ +config SCSI_CXGB4_ISCSI + tristate "Chelsio T4 iSCSI support" + depends on CHELSIO_T4_DEPENDS + select CHELSIO_T4 + select SCSI_ISCSI_ATTRS + ---help--- + This driver supports iSCSI offload for the Chelsio T4 devices. diff --git a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c new file mode 100644 index 000000000000..99f2b8c5dd63 --- /dev/null +++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c @@ -0,0 +1,1604 @@ +/* + * cxgb4i.c: Chelsio T4 iSCSI driver. + * + * Copyright (c) 2010 Chelsio Communications, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation. + * + * Written by: Karen Xie (kxie@chelsio.com) + * Rakesh Ranjan (rranjan@chelsio.com) + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ + +#include <linux/version.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <scsi/scsi_host.h> +#include <net/tcp.h> +#include <net/dst.h> +#include <linux/netdevice.h> + +#include "t4_msg.h" +#include "cxgb4.h" +#include "cxgb4_uld.h" +#include "t4fw_api.h" +#include "l2t.h" +#include "cxgb4i.h" + +static unsigned int dbg_level; + +#include "../libcxgbi.h" + +#define DRV_MODULE_NAME "cxgb4i" +#define DRV_MODULE_DESC "Chelsio T4 iSCSI Driver" +#define DRV_MODULE_VERSION "0.9.1" +#define DRV_MODULE_RELDATE "Aug. 2010" + +static char version[] = + DRV_MODULE_DESC " " DRV_MODULE_NAME + " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; + +MODULE_AUTHOR("Chelsio Communications, Inc."); +MODULE_DESCRIPTION(DRV_MODULE_DESC); +MODULE_VERSION(DRV_MODULE_VERSION); +MODULE_LICENSE("GPL"); + +module_param(dbg_level, uint, 0644); +MODULE_PARM_DESC(dbg_level, "Debug flag (default=0)"); + +static int cxgb4i_rcv_win = 256 * 1024; +module_param(cxgb4i_rcv_win, int, 0644); +MODULE_PARM_DESC(cxgb4i_rcv_win, "TCP reveive window in bytes"); + +static int cxgb4i_snd_win = 128 * 1024; +module_param(cxgb4i_snd_win, int, 0644); +MODULE_PARM_DESC(cxgb4i_snd_win, "TCP send window in bytes"); + +static int cxgb4i_rx_credit_thres = 10 * 1024; +module_param(cxgb4i_rx_credit_thres, int, 0644); +MODULE_PARM_DESC(cxgb4i_rx_credit_thres, + "RX credits return threshold in bytes (default=10KB)"); + +static unsigned int cxgb4i_max_connect = (8 * 1024); +module_param(cxgb4i_max_connect, uint, 0644); +MODULE_PARM_DESC(cxgb4i_max_connect, "Maximum number of connections"); + +static unsigned short cxgb4i_sport_base = 20000; +module_param(cxgb4i_sport_base, ushort, 0644); +MODULE_PARM_DESC(cxgb4i_sport_base, "Starting port number (default 20000)"); + +typedef void (*cxgb4i_cplhandler_func)(struct cxgbi_device *, struct sk_buff *); + +static void *t4_uld_add(const struct cxgb4_lld_info *); +static int t4_uld_rx_handler(void *, const __be64 *, const struct pkt_gl *); +static int t4_uld_state_change(void *, enum cxgb4_state state); + +static const struct cxgb4_uld_info cxgb4i_uld_info = { + .name = DRV_MODULE_NAME, + .add = t4_uld_add, + .rx_handler = t4_uld_rx_handler, + .state_change = t4_uld_state_change, +}; + +static struct scsi_host_template cxgb4i_host_template = { + .module = THIS_MODULE, + .name = DRV_MODULE_NAME, + .proc_name = DRV_MODULE_NAME, + .can_queue = CXGB4I_SCSI_HOST_QDEPTH, + .queuecommand = iscsi_queuecommand, + .change_queue_depth = iscsi_change_queue_depth, + .sg_tablesize = SG_ALL, + .max_sectors = 0xFFFF, + .cmd_per_lun = ISCSI_DEF_CMD_PER_LUN, + .eh_abort_handler = iscsi_eh_abort, + .eh_device_reset_handler = iscsi_eh_device_reset, + .eh_target_reset_handler = iscsi_eh_recover_target, + .target_alloc = iscsi_target_alloc, + .use_clustering = DISABLE_CLUSTERING, + .this_id = -1, +}; + +static struct iscsi_transport cxgb4i_iscsi_transport = { + .owner = THIS_MODULE, + .name = DRV_MODULE_NAME, + .caps = CAP_RECOVERY_L0 | CAP_MULTI_R2T | CAP_HDRDGST | + CAP_DATADGST | CAP_DIGEST_OFFLOAD | + CAP_PADDING_OFFLOAD, + .param_mask = ISCSI_MAX_RECV_DLENGTH | ISCSI_MAX_XMIT_DLENGTH | + ISCSI_HDRDGST_EN | ISCSI_DATADGST_EN | + ISCSI_INITIAL_R2T_EN | ISCSI_MAX_R2T | + ISCSI_IMM_DATA_EN | ISCSI_FIRST_BURST | + ISCSI_MAX_BURST | ISCSI_PDU_INORDER_EN | + ISCSI_DATASEQ_INORDER_EN | ISCSI_ERL | + ISCSI_CONN_PORT | ISCSI_CONN_ADDRESS | + ISCSI_EXP_STATSN | ISCSI_PERSISTENT_PORT | + ISCSI_PERSISTENT_ADDRESS | + ISCSI_TARGET_NAME | ISCSI_TPGT | + ISCSI_USERNAME | ISCSI_PASSWORD | + ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN | + ISCSI_FAST_ABORT | ISCSI_ABORT_TMO | + ISCSI_LU_RESET_TMO | ISCSI_TGT_RESET_TMO | + ISCSI_PING_TMO | ISCSI_RECV_TMO | + ISCSI_IFACE_NAME | ISCSI_INITIATOR_NAME, + .host_param_mask = ISCSI_HOST_HWADDRESS | ISCSI_HOST_IPADDRESS | + ISCSI_HOST_INITIATOR_NAME | + ISCSI_HOST_NETDEV_NAME, + .get_host_param = cxgbi_get_host_param, + .set_host_param = cxgbi_set_host_param, + /* session management */ + .create_session = cxgbi_create_session, + .destroy_session = cxgbi_destroy_session, + .get_session_param = iscsi_session_get_param, + /* connection management */ + .create_conn = cxgbi_create_conn, + .bind_conn = cxgbi_bind_conn, + .destroy_conn = iscsi_tcp_conn_teardown, + .start_conn = iscsi_conn_start, + .stop_conn = iscsi_conn_stop, + .get_conn_param = cxgbi_get_conn_param, + .set_param = cxgbi_set_conn_param, + .get_stats = cxgbi_get_conn_stats, + /* pdu xmit req from user space */ + .send_pdu = iscsi_conn_send_pdu, + /* task */ + .init_task = iscsi_tcp_task_init, + .xmit_task = iscsi_tcp_task_xmit, + .cleanup_task = cxgbi_cleanup_task, + /* pdu */ + .alloc_pdu = cxgbi_conn_alloc_pdu, + .init_pdu = cxgbi_conn_init_pdu, + .xmit_pdu = cxgbi_conn_xmit_pdu, + .parse_pdu_itt = cxgbi_parse_pdu_itt, + /* TCP connect/disconnect */ + .ep_connect = cxgbi_ep_connect, + .ep_poll = cxgbi_ep_poll, + .ep_disconnect = cxgbi_ep_disconnect, + /* Error recovery timeout call */ + .session_recovery_timedout = iscsi_session_recovery_timedout, +}; + +static struct scsi_transport_template *cxgb4i_stt; + +/* + * CPL (Chelsio Protocol Language) defines a message passing interface between + * the host driver and Chelsio asic. + * The section below implments CPLs that related to iscsi tcp connection + * open/close/abort and data send/receive. + */ +#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) +#define RCV_BUFSIZ_MASK 0x3FFU +#define MAX_IMM_TX_PKT_LEN 128 + +static inline void set_queue(struct sk_buff *skb, unsigned int queue, + const struct cxgbi_sock *csk) +{ + skb->queue_mapping = queue; +} + +static int push_tx_frames(struct cxgbi_sock *, int); + +/* + * is_ofld_imm - check whether a packet can be sent as immediate data + * @skb: the packet + * + * Returns true if a packet can be sent as an offload WR with immediate + * data. We currently use the same limit as for Ethernet packets. + */ +static inline int is_ofld_imm(const struct sk_buff *skb) +{ + return skb->len <= (MAX_IMM_TX_PKT_LEN - + sizeof(struct fw_ofld_tx_data_wr)); +} + +static void send_act_open_req(struct cxgbi_sock *csk, struct sk_buff *skb, + struct l2t_entry *e) +{ + struct cpl_act_open_req *req; + int wscale = cxgbi_sock_compute_wscale(csk->mss_idx); + unsigned long long opt0; + unsigned int opt2; + unsigned int qid_atid = ((unsigned int)csk->atid) | + (((unsigned int)csk->rss_qid) << 14); + + opt0 = KEEP_ALIVE(1) | + WND_SCALE(wscale) | + MSS_IDX(csk->mss_idx) | + L2T_IDX(((struct l2t_entry *)csk->l2t)->idx) | + TX_CHAN(csk->tx_chan) | + SMAC_SEL(csk->smac_idx) | + ULP_MODE(ULP_MODE_ISCSI) | + RCV_BUFSIZ(cxgb4i_rcv_win >> 10); + opt2 = RX_CHANNEL(0) | + RSS_QUEUE_VALID | + (1 << 20) | (1 << 22) | + RSS_QUEUE(csk->rss_qid); + + set_wr_txq(skb, CPL_PRIORITY_SETUP, csk->port_id); + req = (struct cpl_act_open_req *)skb->head; + + INIT_TP_WR(req, 0); + OPCODE_TID(req) = cpu_to_be32(MK_OPCODE_TID(CPL_ACT_OPEN_REQ, + qid_atid)); + req->local_port = csk->saddr.sin_port; + req->peer_port = csk->daddr.sin_port; + req->local_ip = csk->saddr.sin_addr.s_addr; + req->peer_ip = csk->daddr.sin_addr.s_addr; + req->opt0 = cpu_to_be64(opt0); + req->params = 0; + req->opt2 = cpu_to_be32(opt2); + + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, + "csk 0x%p, %pI4:%u-%pI4:%u, atid %d, qid %u.\n", + csk, &req->local_ip, ntohs(req->local_port), + &req->peer_ip, ntohs(req->peer_port), + csk->atid, csk->rss_qid); + + cxgb4_l2t_send(csk->cdev->ports[csk->port_id], skb, csk->l2t); +} + +static void send_close_req(struct cxgbi_sock *csk) +{ + struct sk_buff *skb = csk->cpl_close; + struct cpl_close_con_req *req = (struct cpl_close_con_req *)skb->head; + unsigned int tid = csk->tid; + + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, + "csk 0x%p,%u,0x%lx, tid %u.\n", + csk, csk->state, csk->flags, csk->tid); + csk->cpl_close = NULL; + set_wr_txq(skb, CPL_PRIORITY_DATA, csk->port_id); + INIT_TP_WR(req, tid); + OPCODE_TID(req) = cpu_to_be32(MK_OPCODE_TID(CPL_CLOSE_CON_REQ, tid)); + req->rsvd = 0; + + cxgbi_sock_skb_entail(csk, skb); + if (csk->state >= CTP_ESTABLISHED) + push_tx_frames(csk, 1); +} + +static void abort_arp_failure(void *handle, struct sk_buff *skb) +{ + struct cxgbi_sock *csk = (struct cxgbi_sock *)handle; + struct cpl_abort_req *req; + + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, + "csk 0x%p,%u,0x%lx, tid %u, abort.\n", + csk, csk->state, csk->flags, csk->tid); + req = (struct cpl_abort_req *)skb->data; + req->cmd = CPL_ABORT_NO_RST; + cxgb4_ofld_send(csk->cdev->ports[csk->port_id], skb); +} + +static void send_abort_req(struct cxgbi_sock *csk) +{ + struct cpl_abort_req *req; + struct sk_buff *skb = csk->cpl_abort_req; + + if (unlikely(csk->state == CTP_ABORTING) || !skb || !csk->cdev) + return; + cxgbi_sock_set_state(csk, CTP_ABORTING); + cxgbi_sock_set_flag(csk, CTPF_ABORT_RPL_PENDING); + cxgbi_sock_purge_write_queue(csk); + + csk->cpl_abort_req = NULL; + req = (struct cpl_abort_req *)skb->head; + set_queue(skb, CPL_PRIORITY_DATA, csk); + req->cmd = CPL_ABORT_SEND_RST; + t4_set_arp_err_handler(skb, csk, abort_arp_failure); + INIT_TP_WR(req, csk->tid); + OPCODE_TID(req) = cpu_to_be32(MK_OPCODE_TID(CPL_ABORT_REQ, csk->tid)); + req->rsvd0 = htonl(csk->snd_nxt); + req->rsvd1 = !cxgbi_sock_flag(csk, CTPF_TX_DATA_SENT); + + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, + "csk 0x%p,%u,0x%lx,%u, snd_nxt %u, 0x%x.\n", + csk, csk->state, csk->flags, csk->tid, csk->snd_nxt, + req->rsvd1); + + cxgb4_l2t_send(csk->cdev->ports[csk->port_id], skb, csk->l2t); +} + +static void send_abort_rpl(struct cxgbi_sock *csk, int rst_status) +{ + struct sk_buff *skb = csk->cpl_abort_rpl; + struct cpl_abort_rpl *rpl = (struct cpl_abort_rpl *)skb->head; + + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, + "csk 0x%p,%u,0x%lx,%u, status %d.\n", + csk, csk->state, csk->flags, csk->tid, rst_status); + + csk->cpl_abort_rpl = NULL; + set_queue(skb, CPL_PRIORITY_DATA, csk); + INIT_TP_WR(rpl, csk->tid); + OPCODE_TID(rpl) = cpu_to_be32(MK_OPCODE_TID(CPL_ABORT_RPL, csk->tid)); + rpl->cmd = rst_status; + cxgb4_ofld_send(csk->cdev->ports[csk->port_id], skb); +} + +/* + * CPL connection rx data ack: host -> + * Send RX credits through an RX_DATA_ACK CPL message. Returns the number of + * credits sent. + */ +static u32 send_rx_credits(struct cxgbi_sock *csk, u32 credits) +{ + struct sk_buff *skb; + struct cpl_rx_data_ack *req; + + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_RX, + "csk 0x%p,%u,0x%lx,%u, credit %u.\n", + csk, csk->state, csk->flags, csk->tid, credits); + + skb = alloc_wr(sizeof(*req), 0, GFP_ATOMIC); + if (!skb) { + pr_info("csk 0x%p, credit %u, OOM.\n", csk, credits); + return 0; + } + req = (struct cpl_rx_data_ack *)skb->head; + + set_wr_txq(skb, CPL_PRIORITY_ACK, csk->port_id); + INIT_TP_WR(req, csk->tid); + OPCODE_TID(req) = cpu_to_be32(MK_OPCODE_TID(CPL_RX_DATA_ACK, + csk->tid)); + req->credit_dack = cpu_to_be32(RX_CREDITS(credits) | RX_FORCE_ACK(1)); + cxgb4_ofld_send(csk->cdev->ports[csk->port_id], skb); + return credits; +} + +/* + * sgl_len - calculates the size of an SGL of the given capacity + * @n: the number of SGL entries + * Calculates the number of flits needed for a scatter/gather list that + * can hold the given number of entries. + */ +static inline unsigned int sgl_len(unsigned int n) +{ + n--; + return (3 * n) / 2 + (n & 1) + 2; +} + +/* + * calc_tx_flits_ofld - calculate # of flits for an offload packet + * @skb: the packet + * + * Returns the number of flits needed for the given offload packet. + * These packets are already fully constructed and no additional headers + * will be added. + */ +static inline unsigned int calc_tx_flits_ofld(const struct sk_buff *skb) +{ + unsigned int flits, cnt; + + if (is_ofld_imm(skb)) + return DIV_ROUND_UP(skb->len, 8); + flits = skb_transport_offset(skb) / 8; + cnt = skb_shinfo(skb)->nr_frags; + if (skb->tail != skb->transport_header) + cnt++; + return flits + sgl_len(cnt); +} + +static inline void send_tx_flowc_wr(struct cxgbi_sock *csk) +{ + struct sk_buff *skb; + struct fw_flowc_wr *flowc; + int flowclen, i; + + flowclen = 80; + skb = alloc_wr(flowclen, 0, GFP_ATOMIC); + flowc = (struct fw_flowc_wr *)skb->head; + flowc->op_to_nparams = + htonl(FW_WR_OP(FW_FLOWC_WR) | FW_FLOWC_WR_NPARAMS(8)); + flowc->flowid_len16 = + htonl(FW_WR_LEN16(DIV_ROUND_UP(72, 16)) | + FW_WR_FLOWID(csk->tid)); + flowc->mnemval[0].mnemonic = FW_FLOWC_MNEM_PFNVFN; + flowc->mnemval[0].val = htonl(csk->cdev->pfvf); + flowc->mnemval[1].mnemonic = FW_FLOWC_MNEM_CH; + flowc->mnemval[1].val = htonl(csk->tx_chan); + flowc->mnemval[2].mnemonic = FW_FLOWC_MNEM_PORT; + flowc->mnemval[2].val = htonl(csk->tx_chan); + flowc->mnemval[3].mnemonic = FW_FLOWC_MNEM_IQID; + flowc->mnemval[3].val = htonl(csk->rss_qid); + flowc->mnemval[4].mnemonic = FW_FLOWC_MNEM_SNDNXT; + flowc->mnemval[4].val = htonl(csk->snd_nxt); + flowc->mnemval[5].mnemonic = FW_FLOWC_MNEM_RCVNXT; + flowc->mnemval[5].val = htonl(csk->rcv_nxt); + flowc->mnemval[6].mnemonic = FW_FLOWC_MNEM_SNDBUF; + flowc->mnemval[6].val = htonl(cxgb4i_snd_win); + flowc->mnemval[7].mnemonic = FW_FLOWC_MNEM_MSS; + flowc->mnemval[7].val = htonl(csk->advmss); + flowc->mnemval[8].mnemonic = 0; + flowc->mnemval[8].val = 0; + for (i = 0; i < 9; i++) { + flowc->mnemval[i].r4[0] = 0; + flowc->mnemval[i].r4[1] = 0; + flowc->mnemval[i].r4[2] = 0; + } + set_queue(skb, CPL_PRIORITY_DATA, csk); + + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, + "csk 0x%p, tid 0x%x, %u,%u,%u,%u,%u,%u,%u.\n", + csk, csk->tid, 0, csk->tx_chan, csk->rss_qid, + csk->snd_nxt, csk->rcv_nxt, cxgb4i_snd_win, + csk->advmss); + + cxgb4_ofld_send(csk->cdev->ports[csk->port_id], skb); +} + +static inline void make_tx_data_wr(struct cxgbi_sock *csk, struct sk_buff *skb, + int dlen, int len, u32 credits, int compl) +{ + struct fw_ofld_tx_data_wr *req; + unsigned int submode = cxgbi_skcb_ulp_mode(skb) & 3; + unsigned int wr_ulp_mode = 0; + + req = (struct fw_ofld_tx_data_wr *)__skb_push(skb, sizeof(*req)); + + if (is_ofld_imm(skb)) { + req->op_to_immdlen = htonl(FW_WR_OP(FW_OFLD_TX_DATA_WR) | + FW_WR_COMPL(1) | + FW_WR_IMMDLEN(dlen)); + req->flowid_len16 = htonl(FW_WR_FLOWID(csk->tid) | + FW_WR_LEN16(credits)); + } else { + req->op_to_immdlen = + cpu_to_be32(FW_WR_OP(FW_OFLD_TX_DATA_WR) | + FW_WR_COMPL(1) | + FW_WR_IMMDLEN(0)); + req->flowid_len16 = + cpu_to_be32(FW_WR_FLOWID(csk->tid) | + FW_WR_LEN16(credits)); + } + if (submode) + wr_ulp_mode = FW_OFLD_TX_DATA_WR_ULPMODE(ULP2_MODE_ISCSI) | + FW_OFLD_TX_DATA_WR_ULPSUBMODE(submode); + req->tunnel_to_proxy = htonl(wr_ulp_mode) | + FW_OFLD_TX_DATA_WR_SHOVE(skb_peek(&csk->write_queue) ? 0 : 1); + req->plen = htonl(len); + if (!cxgbi_sock_flag(csk, CTPF_TX_DATA_SENT)) + cxgbi_sock_set_flag(csk, CTPF_TX_DATA_SENT); +} + +static void arp_failure_skb_discard(void *handle, struct sk_buff *skb) +{ + kfree_skb(skb); +} + +static int push_tx_frames(struct cxgbi_sock *csk, int req_completion) +{ + int total_size = 0; + struct sk_buff *skb; + + if (unlikely(csk->state < CTP_ESTABLISHED || + csk->state == CTP_CLOSE_WAIT_1 || csk->state >= CTP_ABORTING)) { + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK | + 1 << CXGBI_DBG_PDU_TX, + "csk 0x%p,%u,0x%lx,%u, in closing state.\n", + csk, csk->state, csk->flags, csk->tid); + return 0; + } + + while (csk->wr_cred && (skb = skb_peek(&csk->write_queue)) != NULL) { + int dlen = skb->len; + int len = skb->len; + unsigned int credits_needed; + + skb_reset_transport_header(skb); + if (is_ofld_imm(skb)) + credits_needed = DIV_ROUND_UP(dlen + + sizeof(struct fw_ofld_tx_data_wr), 16); + else + credits_needed = DIV_ROUND_UP(8*calc_tx_flits_ofld(skb) + + sizeof(struct fw_ofld_tx_data_wr), + 16); + + if (csk->wr_cred < credits_needed) { + log_debug(1 << CXGBI_DBG_PDU_TX, + "csk 0x%p, skb %u/%u, wr %d < %u.\n", + csk, skb->len, skb->data_len, + credits_needed, csk->wr_cred); + break; + } + __skb_unlink(skb, &csk->write_queue); + set_queue(skb, CPL_PRIORITY_DATA, csk); + skb->csum = credits_needed; + csk->wr_cred -= credits_needed; + csk->wr_una_cred += credits_needed; + cxgbi_sock_enqueue_wr(csk, skb); + + log_debug(1 << CXGBI_DBG_PDU_TX, + "csk 0x%p, skb %u/%u, wr %d, left %u, unack %u.\n", + csk, skb->len, skb->data_len, credits_needed, + csk->wr_cred, csk->wr_una_cred); + + if (likely(cxgbi_skcb_test_flag(skb, SKCBF_TX_NEED_HDR))) { + if (!cxgbi_sock_flag(csk, CTPF_TX_DATA_SENT)) { + send_tx_flowc_wr(csk); + skb->csum += 5; + csk->wr_cred -= 5; + csk->wr_una_cred += 5; + } + len += cxgbi_ulp_extra_len(cxgbi_skcb_ulp_mode(skb)); + make_tx_data_wr(csk, skb, dlen, len, credits_needed, + req_completion); + csk->snd_nxt += len; + cxgbi_skcb_clear_flag(skb, SKCBF_TX_NEED_HDR); + } + total_size += skb->truesize; + t4_set_arp_err_handler(skb, csk, arp_failure_skb_discard); + + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_TX, + "csk 0x%p,%u,0x%lx,%u, skb 0x%p, %u.\n", + csk, csk->state, csk->flags, csk->tid, skb, len); + + cxgb4_l2t_send(csk->cdev->ports[csk->port_id], skb, csk->l2t); + } + return total_size; +} + +static inline void free_atid(struct cxgbi_sock *csk) +{ + struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(csk->cdev); + + if (cxgbi_sock_flag(csk, CTPF_HAS_ATID)) { + cxgb4_free_atid(lldi->tids, csk->atid); + cxgbi_sock_clear_flag(csk, CTPF_HAS_ATID); + cxgbi_sock_put(csk); + } +} + +static void do_act_establish(struct cxgbi_device *cdev, struct sk_buff *skb) +{ + struct cxgbi_sock *csk; + struct cpl_act_establish *req = (struct cpl_act_establish *)skb->data; + unsigned short tcp_opt = ntohs(req->tcp_opt); + unsigned int tid = GET_TID(req); + unsigned int atid = GET_TID_TID(ntohl(req->tos_atid)); + struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); + struct tid_info *t = lldi->tids; + u32 rcv_isn = be32_to_cpu(req->rcv_isn); + + csk = lookup_atid(t, atid); + if (unlikely(!csk)) { + pr_err("NO conn. for atid %u, cdev 0x%p.\n", atid, cdev); + goto rel_skb; + } + + if (csk->atid != atid) { + pr_err("bad conn atid %u, csk 0x%p,%u,0x%lx,tid %u, atid %u.\n", + atid, csk, csk->state, csk->flags, csk->tid, csk->atid); + goto rel_skb; + } + + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, + "csk 0x%p,%u,0x%lx, tid %u, atid %u, rseq %u.\n", + csk, csk->state, csk->flags, tid, atid, rcv_isn); + + cxgbi_sock_get(csk); + csk->tid = tid; + cxgb4_insert_tid(lldi->tids, csk, tid); + cxgbi_sock_set_flag(csk, CTPF_HAS_TID); + + free_atid(csk); + + spin_lock_bh(&csk->lock); + if (unlikely(csk->state != CTP_ACTIVE_OPEN)) + pr_info("csk 0x%p,%u,0x%lx,%u, got EST.\n", + csk, csk->state, csk->flags, csk->tid); + + if (csk->retry_timer.function) { + del_timer(&csk->retry_timer); + csk->retry_timer.function = NULL; + } + + csk->copied_seq = csk->rcv_wup = csk->rcv_nxt = rcv_isn; + /* + * Causes the first RX_DATA_ACK to supply any Rx credits we couldn't + * pass through opt0. + */ + if (cxgb4i_rcv_win > (RCV_BUFSIZ_MASK << 10)) + csk->rcv_wup -= cxgb4i_rcv_win - (RCV_BUFSIZ_MASK << 10); + + csk->advmss = lldi->mtus[GET_TCPOPT_MSS(tcp_opt)] - 40; + if (GET_TCPOPT_TSTAMP(tcp_opt)) + csk->advmss -= 12; + if (csk->advmss < 128) + csk->advmss = 128; + + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, + "csk 0x%p, mss_idx %u, advmss %u.\n", + csk, GET_TCPOPT_MSS(tcp_opt), csk->advmss); + + cxgbi_sock_established(csk, ntohl(req->snd_isn), ntohs(req->tcp_opt)); + + if (unlikely(cxgbi_sock_flag(csk, CTPF_ACTIVE_CLOSE_NEEDED))) + send_abort_req(csk); + else { + if (skb_queue_len(&csk->write_queue)) + push_tx_frames(csk, 0); + cxgbi_conn_tx_open(csk); + } + spin_unlock_bh(&csk->lock); + +rel_skb: + __kfree_skb(skb); +} + +static int act_open_rpl_status_to_errno(int status) +{ + switch (status) { + case CPL_ERR_CONN_RESET: + return -ECONNREFUSED; + case CPL_ERR_ARP_MISS: + return -EHOSTUNREACH; + case CPL_ERR_CONN_TIMEDOUT: + return -ETIMEDOUT; + case CPL_ERR_TCAM_FULL: + return -ENOMEM; + case CPL_ERR_CONN_EXIST: + return -EADDRINUSE; + default: + return -EIO; + } +} + +static void csk_act_open_retry_timer(unsigned long data) +{ + struct sk_buff *skb; + struct cxgbi_sock *csk = (struct cxgbi_sock *)data; + + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, + "csk 0x%p,%u,0x%lx,%u.\n", + csk, csk->state, csk->flags, csk->tid); + + cxgbi_sock_get(csk); + spin_lock_bh(&csk->lock); + skb = alloc_wr(sizeof(struct cpl_act_open_req), 0, GFP_ATOMIC); + if (!skb) + cxgbi_sock_fail_act_open(csk, -ENOMEM); + else { + skb->sk = (struct sock *)csk; + t4_set_arp_err_handler(skb, csk, + cxgbi_sock_act_open_req_arp_failure); + send_act_open_req(csk, skb, csk->l2t); + } + spin_unlock_bh(&csk->lock); + cxgbi_sock_put(csk); +} + +static void do_act_open_rpl(struct cxgbi_device *cdev, struct sk_buff *skb) +{ + struct cxgbi_sock *csk; + struct cpl_act_open_rpl *rpl = (struct cpl_act_open_rpl *)skb->data; + unsigned int tid = GET_TID(rpl); + unsigned int atid = + GET_TID_TID(GET_AOPEN_ATID(be32_to_cpu(rpl->atid_status))); + unsigned int status = GET_AOPEN_STATUS(be32_to_cpu(rpl->atid_status)); + struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); + struct tid_info *t = lldi->tids; + + csk = lookup_atid(t, atid); + if (unlikely(!csk)) { + pr_err("NO matching conn. atid %u, tid %u.\n", atid, tid); + goto rel_skb; + } + + pr_info("%pI4:%u-%pI4:%u, atid %u,%u, status %u, csk 0x%p,%u,0x%lx.\n", + &csk->saddr.sin_addr.s_addr, ntohs(csk->saddr.sin_port), + &csk->daddr.sin_addr.s_addr, ntohs(csk->daddr.sin_port), + atid, tid, status, csk, csk->state, csk->flags); + + if (status && status != CPL_ERR_TCAM_FULL && + status != CPL_ERR_CONN_EXIST && + status != CPL_ERR_ARP_MISS) + cxgb4_remove_tid(lldi->tids, csk->port_id, GET_TID(rpl)); + + cxgbi_sock_get(csk); + spin_lock_bh(&csk->lock); + + if (status == CPL_ERR_CONN_EXIST && + csk->retry_timer.function != csk_act_open_retry_timer) { + csk->retry_timer.function = csk_act_open_retry_timer; + mod_timer(&csk->retry_timer, jiffies + HZ / 2); + } else + cxgbi_sock_fail_act_open(csk, + act_open_rpl_status_to_errno(status)); + + spin_unlock_bh(&csk->lock); + cxgbi_sock_put(csk); +rel_skb: + __kfree_skb(skb); +} + +static void do_peer_close(struct cxgbi_device *cdev, struct sk_buff *skb) +{ + struct cxgbi_sock *csk; + struct cpl_peer_close *req = (struct cpl_peer_close *)skb->data; + unsigned int tid = GET_TID(req); + struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); + struct tid_info *t = lldi->tids; + + csk = lookup_tid(t, tid); + if (unlikely(!csk)) { + pr_err("can't find connection for tid %u.\n", tid); + goto rel_skb; + } + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, + "csk 0x%p,%u,0x%lx,%u.\n", + csk, csk->state, csk->flags, csk->tid); + cxgbi_sock_rcv_peer_close(csk); +rel_skb: + __kfree_skb(skb); +} + +static void do_close_con_rpl(struct cxgbi_device *cdev, struct sk_buff *skb) +{ + struct cxgbi_sock *csk; + struct cpl_close_con_rpl *rpl = (struct cpl_close_con_rpl *)skb->data; + unsigned int tid = GET_TID(rpl); + struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); + struct tid_info *t = lldi->tids; + + csk = lookup_tid(t, tid); + if (unlikely(!csk)) { + pr_err("can't find connection for tid %u.\n", tid); + goto rel_skb; + } + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, + "csk 0x%p,%u,0x%lx,%u.\n", + csk, csk->state, csk->flags, csk->tid); + cxgbi_sock_rcv_close_conn_rpl(csk, ntohl(rpl->snd_nxt)); +rel_skb: + __kfree_skb(skb); +} + +static int abort_status_to_errno(struct cxgbi_sock *csk, int abort_reason, + int *need_rst) +{ + switch (abort_reason) { + case CPL_ERR_BAD_SYN: /* fall through */ + case CPL_ERR_CONN_RESET: + return csk->state > CTP_ESTABLISHED ? + -EPIPE : -ECONNRESET; + case CPL_ERR_XMIT_TIMEDOUT: + case CPL_ERR_PERSIST_TIMEDOUT: + case CPL_ERR_FINWAIT2_TIMEDOUT: + case CPL_ERR_KEEPALIVE_TIMEDOUT: + return -ETIMEDOUT; + default: + return -EIO; + } +} + +static void do_abort_req_rss(struct cxgbi_device *cdev, struct sk_buff *skb) +{ + struct cxgbi_sock *csk; + struct cpl_abort_req_rss *req = (struct cpl_abort_req_rss *)skb->data; + unsigned int tid = GET_TID(req); + struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); + struct tid_info *t = lldi->tids; + int rst_status = CPL_ABORT_NO_RST; + + csk = lookup_tid(t, tid); + if (unlikely(!csk)) { + pr_err("can't find connection for tid %u.\n", tid); + goto rel_skb; + } + + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, + "csk 0x%p,%u,0x%lx, tid %u, status 0x%x.\n", + csk, csk->state, csk->flags, csk->tid, req->status); + + if (req->status == CPL_ERR_RTX_NEG_ADVICE || + req->status == CPL_ERR_PERSIST_NEG_ADVICE) + goto rel_skb; + + cxgbi_sock_get(csk); + spin_lock_bh(&csk->lock); + + if (!cxgbi_sock_flag(csk, CTPF_ABORT_REQ_RCVD)) { + cxgbi_sock_set_flag(csk, CTPF_ABORT_REQ_RCVD); + cxgbi_sock_set_state(csk, CTP_ABORTING); + goto done; + } + + cxgbi_sock_clear_flag(csk, CTPF_ABORT_REQ_RCVD); + send_abort_rpl(csk, rst_status); + + if (!cxgbi_sock_flag(csk, CTPF_ABORT_RPL_PENDING)) { + csk->err = abort_status_to_errno(csk, req->status, &rst_status); + cxgbi_sock_closed(csk); + } +done: + spin_unlock_bh(&csk->lock); + cxgbi_sock_put(csk); +rel_skb: + __kfree_skb(skb); +} + +static void do_abort_rpl_rss(struct cxgbi_device *cdev, struct sk_buff *skb) +{ + struct cxgbi_sock *csk; + struct cpl_abort_rpl_rss *rpl = (struct cpl_abort_rpl_rss *)skb->data; + unsigned int tid = GET_TID(rpl); + struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); + struct tid_info *t = lldi->tids; + + csk = lookup_tid(t, tid); + if (!csk) + goto rel_skb; + + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, + "status 0x%x, csk 0x%p, s %u, 0x%lx.\n", + rpl->status, csk, csk ? csk->state : 0, + csk ? csk->flags : 0UL); + + if (rpl->status == CPL_ERR_ABORT_FAILED) + goto rel_skb; + + cxgbi_sock_rcv_abort_rpl(csk); +rel_skb: + __kfree_skb(skb); +} + +static void do_rx_iscsi_hdr(struct cxgbi_device *cdev, struct sk_buff *skb) +{ + struct cxgbi_sock *csk; + struct cpl_iscsi_hdr *cpl = (struct cpl_iscsi_hdr *)skb->data; + unsigned short pdu_len_ddp = be16_to_cpu(cpl->pdu_len_ddp); + unsigned int tid = GET_TID(cpl); + struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); + struct tid_info *t = lldi->tids; + + csk = lookup_tid(t, tid); + if (unlikely(!csk)) { + pr_err("can't find conn. for tid %u.\n", tid); + goto rel_skb; + } + + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_RX, + "csk 0x%p,%u,0x%lx, tid %u, skb 0x%p,%u, 0x%x.\n", + csk, csk->state, csk->flags, csk->tid, skb, skb->len, + pdu_len_ddp); + + spin_lock_bh(&csk->lock); + + if (unlikely(csk->state >= CTP_PASSIVE_CLOSE)) { + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, + "csk 0x%p,%u,0x%lx,%u, bad state.\n", + csk, csk->state, csk->flags, csk->tid); + if (csk->state != CTP_ABORTING) + goto abort_conn; + else + goto discard; + } + + cxgbi_skcb_tcp_seq(skb) = ntohl(cpl->seq); + cxgbi_skcb_flags(skb) = 0; + + skb_reset_transport_header(skb); + __skb_pull(skb, sizeof(*cpl)); + __pskb_trim(skb, ntohs(cpl->len)); + + if (!csk->skb_ulp_lhdr) { + unsigned char *bhs; + unsigned int hlen, dlen; + + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_RX, + "csk 0x%p,%u,0x%lx, tid %u, skb 0x%p header.\n", + csk, csk->state, csk->flags, csk->tid, skb); + csk->skb_ulp_lhdr = skb; + cxgbi_skcb_set_flag(skb, SKCBF_RX_HDR); + + if (cxgbi_skcb_tcp_seq(skb) != csk->rcv_nxt) { + pr_info("tid %u, CPL_ISCSI_HDR, bad seq, 0x%x/0x%x.\n", + csk->tid, cxgbi_skcb_tcp_seq(skb), + csk->rcv_nxt); + goto abort_conn; + } + + bhs = skb->data; + hlen = ntohs(cpl->len); + dlen = ntohl(*(unsigned int *)(bhs + 4)) & 0xFFFFFF; + + if ((hlen + dlen) != ISCSI_PDU_LEN(pdu_len_ddp) - 40) { + pr_info("tid 0x%x, CPL_ISCSI_HDR, pdu len " + "mismatch %u != %u + %u, seq 0x%x.\n", + csk->tid, ISCSI_PDU_LEN(pdu_len_ddp) - 40, + hlen, dlen, cxgbi_skcb_tcp_seq(skb)); + goto abort_conn; + } + + cxgbi_skcb_rx_pdulen(skb) = (hlen + dlen + 3) & (~0x3); + if (dlen) + cxgbi_skcb_rx_pdulen(skb) += csk->dcrc_len; + csk->rcv_nxt += cxgbi_skcb_rx_pdulen(skb); + + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_RX, + "csk 0x%p, skb 0x%p, 0x%x,%u+%u,0x%x,0x%x.\n", + csk, skb, *bhs, hlen, dlen, + ntohl(*((unsigned int *)(bhs + 16))), + ntohl(*((unsigned int *)(bhs + 24)))); + + } else { + struct sk_buff *lskb = csk->skb_ulp_lhdr; + + cxgbi_skcb_set_flag(lskb, SKCBF_RX_DATA); + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_RX, + "csk 0x%p,%u,0x%lx, skb 0x%p data, 0x%p.\n", + csk, csk->state, csk->flags, skb, lskb); + } + + __skb_queue_tail(&csk->receive_queue, skb); + spin_unlock_bh(&csk->lock); + return; + +abort_conn: + send_abort_req(csk); +discard: + spin_unlock_bh(&csk->lock); +rel_skb: + __kfree_skb(skb); +} + +static void do_rx_data_ddp(struct cxgbi_device *cdev, + struct sk_buff *skb) +{ + struct cxgbi_sock *csk; + struct sk_buff *lskb; + struct cpl_rx_data_ddp *rpl = (struct cpl_rx_data_ddp *)skb->data; + unsigned int tid = GET_TID(rpl); + struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); + struct tid_info *t = lldi->tids; + unsigned int status = ntohl(rpl->ddpvld); + + csk = lookup_tid(t, tid); + if (unlikely(!csk)) { + pr_err("can't find connection for tid %u.\n", tid); + goto rel_skb; + } + + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_RX, + "csk 0x%p,%u,0x%lx, skb 0x%p,0x%x, lhdr 0x%p.\n", + csk, csk->state, csk->flags, skb, status, csk->skb_ulp_lhdr); + + spin_lock_bh(&csk->lock); + + if (unlikely(csk->state >= CTP_PASSIVE_CLOSE)) { + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, + "csk 0x%p,%u,0x%lx,%u, bad state.\n", + csk, csk->state, csk->flags, csk->tid); + if (csk->state != CTP_ABORTING) + goto abort_conn; + else + goto discard; + } + + if (!csk->skb_ulp_lhdr) { + pr_err("tid 0x%x, rcv RX_DATA_DDP w/o pdu bhs.\n", csk->tid); + goto abort_conn; + } + + lskb = csk->skb_ulp_lhdr; + csk->skb_ulp_lhdr = NULL; + + cxgbi_skcb_rx_ddigest(lskb) = ntohl(rpl->ulp_crc); + + if (ntohs(rpl->len) != cxgbi_skcb_rx_pdulen(lskb)) + pr_info("tid 0x%x, RX_DATA_DDP pdulen %u != %u.\n", + csk->tid, ntohs(rpl->len), cxgbi_skcb_rx_pdulen(lskb)); + + if (status & (1 << CPL_RX_DDP_STATUS_HCRC_SHIFT)) { + pr_info("csk 0x%p, lhdr 0x%p, status 0x%x, hcrc bad 0x%lx.\n", + csk, lskb, status, cxgbi_skcb_flags(lskb)); + cxgbi_skcb_set_flag(lskb, SKCBF_RX_HCRC_ERR); + } + if (status & (1 << CPL_RX_DDP_STATUS_DCRC_SHIFT)) { + pr_info("csk 0x%p, lhdr 0x%p, status 0x%x, dcrc bad 0x%lx.\n", + csk, lskb, status, cxgbi_skcb_flags(lskb)); + cxgbi_skcb_set_flag(lskb, SKCBF_RX_DCRC_ERR); + } + if (status & (1 << CPL_RX_DDP_STATUS_PAD_SHIFT)) { + log_debug(1 << CXGBI_DBG_PDU_RX, + "csk 0x%p, lhdr 0x%p, status 0x%x, pad bad.\n", + csk, lskb, status); + cxgbi_skcb_set_flag(lskb, SKCBF_RX_PAD_ERR); + } + if ((status & (1 << CPL_RX_DDP_STATUS_DDP_SHIFT)) && + !cxgbi_skcb_test_flag(lskb, SKCBF_RX_DATA)) { + log_debug(1 << CXGBI_DBG_PDU_RX, + "csk 0x%p, lhdr 0x%p, 0x%x, data ddp'ed.\n", + csk, lskb, status); + cxgbi_skcb_set_flag(lskb, SKCBF_RX_DATA_DDPD); + } + log_debug(1 << CXGBI_DBG_PDU_RX, + "csk 0x%p, lskb 0x%p, f 0x%lx.\n", + csk, lskb, cxgbi_skcb_flags(lskb)); + + cxgbi_skcb_set_flag(lskb, SKCBF_RX_STATUS); + cxgbi_conn_pdu_ready(csk); + spin_unlock_bh(&csk->lock); + goto rel_skb; + +abort_conn: + send_abort_req(csk); +discard: + spin_unlock_bh(&csk->lock); +rel_skb: + __kfree_skb(skb); +} + +static void do_fw4_ack(struct cxgbi_device *cdev, struct sk_buff *skb) +{ + struct cxgbi_sock *csk; + struct cpl_fw4_ack *rpl = (struct cpl_fw4_ack *)skb->data; + unsigned int tid = GET_TID(rpl); + struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); + struct tid_info *t = lldi->tids; + + csk = lookup_tid(t, tid); + if (unlikely(!csk)) + pr_err("can't find connection for tid %u.\n", tid); + else { + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, + "csk 0x%p,%u,0x%lx,%u.\n", + csk, csk->state, csk->flags, csk->tid); + cxgbi_sock_rcv_wr_ack(csk, rpl->credits, ntohl(rpl->snd_una), + rpl->seq_vld); + } + __kfree_skb(skb); +} + +static void do_set_tcb_rpl(struct cxgbi_device *cdev, struct sk_buff *skb) +{ + struct cpl_set_tcb_rpl *rpl = (struct cpl_set_tcb_rpl *)skb->data; + unsigned int tid = GET_TID(rpl); + struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); + struct tid_info *t = lldi->tids; + struct cxgbi_sock *csk; + + csk = lookup_tid(t, tid); + if (!csk) + pr_err("can't find conn. for tid %u.\n", tid); + + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, + "csk 0x%p,%u,%lx,%u, status 0x%x.\n", + csk, csk->state, csk->flags, csk->tid, rpl->status); + + if (rpl->status != CPL_ERR_NONE) + pr_err("csk 0x%p,%u, SET_TCB_RPL status %u.\n", + csk, tid, rpl->status); + + __kfree_skb(skb); +} + +static int alloc_cpls(struct cxgbi_sock *csk) +{ + csk->cpl_close = alloc_wr(sizeof(struct cpl_close_con_req), + 0, GFP_KERNEL); + if (!csk->cpl_close) + return -ENOMEM; + + csk->cpl_abort_req = alloc_wr(sizeof(struct cpl_abort_req), + 0, GFP_KERNEL); + if (!csk->cpl_abort_req) + goto free_cpls; + + csk->cpl_abort_rpl = alloc_wr(sizeof(struct cpl_abort_rpl), + 0, GFP_KERNEL); + if (!csk->cpl_abort_rpl) + goto free_cpls; + return 0; + +free_cpls: + cxgbi_sock_free_cpl_skbs(csk); + return -ENOMEM; +} + +static inline void l2t_put(struct cxgbi_sock *csk) +{ + if (csk->l2t) { + cxgb4_l2t_release(csk->l2t); + csk->l2t = NULL; + cxgbi_sock_put(csk); + } +} + +static void release_offload_resources(struct cxgbi_sock *csk) +{ + struct cxgb4_lld_info *lldi; + + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, + "csk 0x%p,%u,0x%lx,%u.\n", + csk, csk->state, csk->flags, csk->tid); + + cxgbi_sock_free_cpl_skbs(csk); + if (csk->wr_cred != csk->wr_max_cred) { + cxgbi_sock_purge_wr_queue(csk); + cxgbi_sock_reset_wr_list(csk); + } + + l2t_put(csk); + if (cxgbi_sock_flag(csk, CTPF_HAS_ATID)) + free_atid(csk); + else if (cxgbi_sock_flag(csk, CTPF_HAS_TID)) { + lldi = cxgbi_cdev_priv(csk->cdev); + cxgb4_remove_tid(lldi->tids, 0, csk->tid); + cxgbi_sock_clear_flag(csk, CTPF_HAS_TID); + cxgbi_sock_put(csk); + } + csk->dst = NULL; + csk->cdev = NULL; +} + +static int init_act_open(struct cxgbi_sock *csk) +{ + struct cxgbi_device *cdev = csk->cdev; + struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); + struct net_device *ndev = cdev->ports[csk->port_id]; + struct port_info *pi = netdev_priv(ndev); + struct sk_buff *skb = NULL; + unsigned int step; + + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, + "csk 0x%p,%u,0x%lx,%u.\n", + csk, csk->state, csk->flags, csk->tid); + + csk->atid = cxgb4_alloc_atid(lldi->tids, csk); + if (csk->atid < 0) { + pr_err("%s, NO atid available.\n", ndev->name); + return -EINVAL; + } + cxgbi_sock_set_flag(csk, CTPF_HAS_ATID); + cxgbi_sock_get(csk); + + csk->l2t = cxgb4_l2t_get(lldi->l2t, csk->dst->neighbour, ndev, 0); + if (!csk->l2t) { + pr_err("%s, cannot alloc l2t.\n", ndev->name); + goto rel_resource; + } + cxgbi_sock_get(csk); + + skb = alloc_wr(sizeof(struct cpl_act_open_req), 0, GFP_KERNEL); + if (!skb) + goto rel_resource; + skb->sk = (struct sock *)csk; + t4_set_arp_err_handler(skb, csk, cxgbi_sock_act_open_req_arp_failure); + + if (!csk->mtu) + csk->mtu = dst_mtu(csk->dst); + cxgb4_best_mtu(lldi->mtus, csk->mtu, &csk->mss_idx); + csk->tx_chan = cxgb4_port_chan(ndev); + /* SMT two entries per row */ + csk->smac_idx = ((cxgb4_port_viid(ndev) & 0x7F)) << 1; + step = lldi->ntxq / lldi->nchan; + csk->txq_idx = cxgb4_port_idx(ndev) * step; + step = lldi->nrxq / lldi->nchan; + csk->rss_qid = lldi->rxq_ids[cxgb4_port_idx(ndev) * step]; + csk->wr_max_cred = csk->wr_cred = lldi->wr_cred; + csk->wr_una_cred = 0; + cxgbi_sock_reset_wr_list(csk); + csk->err = 0; + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, + "csk 0x%p,p%d,%s, %u,%u,%u, mss %u,%u, smac %u.\n", + csk, pi->port_id, ndev->name, csk->tx_chan, + csk->txq_idx, csk->rss_qid, csk->mtu, csk->mss_idx, + csk->smac_idx); + + cxgbi_sock_set_state(csk, CTP_ACTIVE_OPEN); + send_act_open_req(csk, skb, csk->l2t); + return 0; + +rel_resource: + if (skb) + __kfree_skb(skb); + return -EINVAL; +} + +cxgb4i_cplhandler_func cxgb4i_cplhandlers[NUM_CPL_CMDS] = { + [CPL_ACT_ESTABLISH] = do_act_establish, + [CPL_ACT_OPEN_RPL] = do_act_open_rpl, + [CPL_PEER_CLOSE] = do_peer_close, + [CPL_ABORT_REQ_RSS] = do_abort_req_rss, + [CPL_ABORT_RPL_RSS] = do_abort_rpl_rss, + [CPL_CLOSE_CON_RPL] = do_close_con_rpl, + [CPL_FW4_ACK] = do_fw4_ack, + [CPL_ISCSI_HDR] = do_rx_iscsi_hdr, + [CPL_SET_TCB_RPL] = do_set_tcb_rpl, + [CPL_RX_DATA_DDP] = do_rx_data_ddp, +}; + +int cxgb4i_ofld_init(struct cxgbi_device *cdev) +{ + int rc; + + if (cxgb4i_max_connect > CXGB4I_MAX_CONN) + cxgb4i_max_connect = CXGB4I_MAX_CONN; + + rc = cxgbi_device_portmap_create(cdev, cxgb4i_sport_base, + cxgb4i_max_connect); + if (rc < 0) + return rc; + + cdev->csk_release_offload_resources = release_offload_resources; + cdev->csk_push_tx_frames = push_tx_frames; + cdev->csk_send_abort_req = send_abort_req; + cdev->csk_send_close_req = send_close_req; + cdev->csk_send_rx_credits = send_rx_credits; + cdev->csk_alloc_cpls = alloc_cpls; + cdev->csk_init_act_open = init_act_open; + + pr_info("cdev 0x%p, offload up, added.\n", cdev); + return 0; +} + +/* + * functions to program the pagepod in h/w + */ +#define ULPMEM_IDATA_MAX_NPPODS 4 /* 256/PPOD_SIZE */ +static inline void ulp_mem_io_set_hdr(struct ulp_mem_io *req, + unsigned int wr_len, unsigned int dlen, + unsigned int pm_addr) +{ + struct ulptx_idata *idata = (struct ulptx_idata *)(req + 1); + + INIT_ULPTX_WR(req, wr_len, 0, 0); + req->cmd = htonl(ULPTX_CMD(ULP_TX_MEM_WRITE) | (1 << 23)); + req->dlen = htonl(ULP_MEMIO_DATA_LEN(dlen >> 5)); + req->lock_addr = htonl(ULP_MEMIO_ADDR(pm_addr >> 5)); + req->len16 = htonl(DIV_ROUND_UP(wr_len - sizeof(req->wr), 16)); + + idata->cmd_more = htonl(ULPTX_CMD(ULP_TX_SC_IMM)); + idata->len = htonl(dlen); +} + +static int ddp_ppod_write_idata(struct cxgbi_device *cdev, unsigned int port_id, + struct cxgbi_pagepod_hdr *hdr, unsigned int idx, + unsigned int npods, + struct cxgbi_gather_list *gl, + unsigned int gl_pidx) +{ + struct cxgbi_ddp_info *ddp = cdev->ddp; + struct sk_buff *skb; + struct ulp_mem_io *req; + struct ulptx_idata *idata; + struct cxgbi_pagepod *ppod; + unsigned int pm_addr = idx * PPOD_SIZE + ddp->llimit; + unsigned int dlen = PPOD_SIZE * npods; + unsigned int wr_len = roundup(sizeof(struct ulp_mem_io) + + sizeof(struct ulptx_idata) + dlen, 16); + unsigned int i; + + skb = alloc_wr(wr_len, 0, GFP_ATOMIC); + if (!skb) { + pr_err("cdev 0x%p, idx %u, npods %u, OOM.\n", + cdev, idx, npods); + return -ENOMEM; + } + req = (struct ulp_mem_io *)skb->head; + set_queue(skb, CPL_PRIORITY_CONTROL, NULL); + + ulp_mem_io_set_hdr(req, wr_len, dlen, pm_addr); + idata = (struct ulptx_idata *)(req + 1); + ppod = (struct cxgbi_pagepod *)(idata + 1); + + for (i = 0; i < npods; i++, ppod++, gl_pidx += PPOD_PAGES_MAX) { + if (!hdr && !gl) + cxgbi_ddp_ppod_clear(ppod); + else + cxgbi_ddp_ppod_set(ppod, hdr, gl, gl_pidx); + } + + cxgb4_ofld_send(cdev->ports[port_id], skb); + return 0; +} + +static int ddp_set_map(struct cxgbi_sock *csk, struct cxgbi_pagepod_hdr *hdr, + unsigned int idx, unsigned int npods, + struct cxgbi_gather_list *gl) +{ + unsigned int i, cnt; + int err = 0; + + for (i = 0; i < npods; i += cnt, idx += cnt) { + cnt = npods - i; + if (cnt > ULPMEM_IDATA_MAX_NPPODS) + cnt = ULPMEM_IDATA_MAX_NPPODS; + err = ddp_ppod_write_idata(csk->cdev, csk->port_id, hdr, + idx, cnt, gl, 4 * i); + if (err < 0) + break; + } + return err; +} + +static void ddp_clear_map(struct cxgbi_hba *chba, unsigned int tag, + unsigned int idx, unsigned int npods) +{ + unsigned int i, cnt; + int err; + + for (i = 0; i < npods; i += cnt, idx += cnt) { + cnt = npods - i; + if (cnt > ULPMEM_IDATA_MAX_NPPODS) + cnt = ULPMEM_IDATA_MAX_NPPODS; + err = ddp_ppod_write_idata(chba->cdev, chba->port_id, NULL, + idx, cnt, NULL, 0); + if (err < 0) + break; + } +} + +static int ddp_setup_conn_pgidx(struct cxgbi_sock *csk, unsigned int tid, + int pg_idx, bool reply) +{ + struct sk_buff *skb; + struct cpl_set_tcb_field *req; + + if (!pg_idx || pg_idx >= DDP_PGIDX_MAX) + return 0; + + skb = alloc_wr(sizeof(*req), 0, GFP_KERNEL); + if (!skb) + return -ENOMEM; + + /* set up ulp page size */ + req = (struct cpl_set_tcb_field *)skb->head; + INIT_TP_WR(req, csk->tid); + OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, csk->tid)); + req->reply_ctrl = htons(NO_REPLY(reply) | QUEUENO(csk->rss_qid)); + req->word_cookie = htons(0); + req->mask = cpu_to_be64(0x3 << 8); + req->val = cpu_to_be64(pg_idx << 8); + set_wr_txq(skb, CPL_PRIORITY_CONTROL, csk->port_id); + + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, + "csk 0x%p, tid 0x%x, pg_idx %u.\n", csk, csk->tid, pg_idx); + + cxgb4_ofld_send(csk->cdev->ports[csk->port_id], skb); + return 0; +} + +static int ddp_setup_conn_digest(struct cxgbi_sock *csk, unsigned int tid, + int hcrc, int dcrc, int reply) +{ + struct sk_buff *skb; + struct cpl_set_tcb_field *req; + + if (!hcrc && !dcrc) + return 0; + + skb = alloc_wr(sizeof(*req), 0, GFP_KERNEL); + if (!skb) + return -ENOMEM; + + csk->hcrc_len = (hcrc ? 4 : 0); + csk->dcrc_len = (dcrc ? 4 : 0); + /* set up ulp submode */ + req = (struct cpl_set_tcb_field *)skb->head; + INIT_TP_WR(req, tid); + OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, tid)); + req->reply_ctrl = htons(NO_REPLY(reply) | QUEUENO(csk->rss_qid)); + req->word_cookie = htons(0); + req->mask = cpu_to_be64(0x3 << 4); + req->val = cpu_to_be64(((hcrc ? ULP_CRC_HEADER : 0) | + (dcrc ? ULP_CRC_DATA : 0)) << 4); + set_wr_txq(skb, CPL_PRIORITY_CONTROL, csk->port_id); + + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, + "csk 0x%p, tid 0x%x, crc %d,%d.\n", csk, csk->tid, hcrc, dcrc); + + cxgb4_ofld_send(csk->cdev->ports[csk->port_id], skb); + return 0; +} + +static int cxgb4i_ddp_init(struct cxgbi_device *cdev) +{ + struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); + struct cxgbi_ddp_info *ddp = cdev->ddp; + unsigned int tagmask, pgsz_factor[4]; + int err; + + if (ddp) { + kref_get(&ddp->refcnt); + pr_warn("cdev 0x%p, ddp 0x%p already set up.\n", + cdev, cdev->ddp); + return -EALREADY; + } + + err = cxgbi_ddp_init(cdev, lldi->vr->iscsi.start, + lldi->vr->iscsi.start + lldi->vr->iscsi.size - 1, + lldi->iscsi_iolen, lldi->iscsi_iolen); + if (err < 0) + return err; + + ddp = cdev->ddp; + + tagmask = ddp->idx_mask << PPOD_IDX_SHIFT; + cxgbi_ddp_page_size_factor(pgsz_factor); + cxgb4_iscsi_init(lldi->ports[0], tagmask, pgsz_factor); + + cdev->csk_ddp_free_gl_skb = NULL; + cdev->csk_ddp_alloc_gl_skb = NULL; + cdev->csk_ddp_setup_digest = ddp_setup_conn_digest; + cdev->csk_ddp_setup_pgidx = ddp_setup_conn_pgidx; + cdev->csk_ddp_set = ddp_set_map; + cdev->csk_ddp_clear = ddp_clear_map; + + pr_info("cxgb4i 0x%p tag: sw %u, rsvd %u,%u, mask 0x%x.\n", + cdev, cdev->tag_format.sw_bits, cdev->tag_format.rsvd_bits, + cdev->tag_format.rsvd_shift, cdev->tag_format.rsvd_mask); + pr_info("cxgb4i 0x%p, nppods %u, bits %u, mask 0x%x,0x%x pkt %u/%u, " + " %u/%u.\n", + cdev, ddp->nppods, ddp->idx_bits, ddp->idx_mask, + ddp->rsvd_tag_mask, ddp->max_txsz, lldi->iscsi_iolen, + ddp->max_rxsz, lldi->iscsi_iolen); + pr_info("cxgb4i 0x%p max payload size: %u/%u, %u/%u.\n", + cdev, cdev->tx_max_size, ddp->max_txsz, cdev->rx_max_size, + ddp->max_rxsz); + return 0; +} + +static void *t4_uld_add(const struct cxgb4_lld_info *lldi) +{ + struct cxgbi_device *cdev; + struct port_info *pi; + int i, rc; + + cdev = cxgbi_device_register(sizeof(*lldi), lldi->nports); + if (!cdev) { + pr_info("t4 device 0x%p, register failed.\n", lldi); + return NULL; + } + pr_info("0x%p,0x%x, ports %u,%s, chan %u, q %u,%u, wr %u.\n", + cdev, lldi->adapter_type, lldi->nports, + lldi->ports[0]->name, lldi->nchan, lldi->ntxq, + lldi->nrxq, lldi->wr_cred); + for (i = 0; i < lldi->nrxq; i++) + log_debug(1 << CXGBI_DBG_DEV, + "t4 0x%p, rxq id #%d: %u.\n", + cdev, i, lldi->rxq_ids[i]); + + memcpy(cxgbi_cdev_priv(cdev), lldi, sizeof(*lldi)); + cdev->flags = CXGBI_FLAG_DEV_T4; + cdev->pdev = lldi->pdev; + cdev->ports = lldi->ports; + cdev->nports = lldi->nports; + cdev->mtus = lldi->mtus; + cdev->nmtus = NMTUS; + cdev->snd_win = cxgb4i_snd_win; + cdev->rcv_win = cxgb4i_rcv_win; + cdev->rx_credit_thres = cxgb4i_rx_credit_thres; + cdev->skb_tx_rsvd = CXGB4I_TX_HEADER_LEN; + cdev->skb_rx_extra = sizeof(struct cpl_iscsi_hdr); + cdev->itp = &cxgb4i_iscsi_transport; + + cdev->pfvf = FW_VIID_PFN_GET(cxgb4_port_viid(lldi->ports[0])) << 8; + pr_info("cdev 0x%p,%s, pfvf %u.\n", + cdev, lldi->ports[0]->name, cdev->pfvf); + + rc = cxgb4i_ddp_init(cdev); + if (rc) { + pr_info("t4 0x%p ddp init failed.\n", cdev); + goto err_out; + } + rc = cxgb4i_ofld_init(cdev); + if (rc) { + pr_info("t4 0x%p ofld init failed.\n", cdev); + goto err_out; + } + + rc = cxgbi_hbas_add(cdev, CXGB4I_MAX_LUN, CXGBI_MAX_CONN, + &cxgb4i_host_template, cxgb4i_stt); + if (rc) + goto err_out; + + for (i = 0; i < cdev->nports; i++) { + pi = netdev_priv(lldi->ports[i]); + cdev->hbas[i]->port_id = pi->port_id; + } + return cdev; + +err_out: + cxgbi_device_unregister(cdev); + return ERR_PTR(-ENOMEM); +} + +#define RX_PULL_LEN 128 +static int t4_uld_rx_handler(void *handle, const __be64 *rsp, + const struct pkt_gl *pgl) +{ + const struct cpl_act_establish *rpl; + struct sk_buff *skb; + unsigned int opc; + struct cxgbi_device *cdev = handle; + + if (pgl == NULL) { + unsigned int len = 64 - sizeof(struct rsp_ctrl) - 8; + + skb = alloc_wr(len, 0, GFP_ATOMIC); + if (!skb) + goto nomem; + skb_copy_to_linear_data(skb, &rsp[1], len); + } else { + if (unlikely(*(u8 *)rsp != *(u8 *)pgl->va)) { + pr_info("? FL 0x%p,RSS%#llx,FL %#llx,len %u.\n", + pgl->va, be64_to_cpu(*rsp), + be64_to_cpu(*(u64 *)pgl->va), + pgl->tot_len); + return 0; + } + skb = cxgb4_pktgl_to_skb(pgl, RX_PULL_LEN, RX_PULL_LEN); + if (unlikely(!skb)) + goto nomem; + } + + rpl = (struct cpl_act_establish *)skb->data; + opc = rpl->ot.opcode; + log_debug(1 << CXGBI_DBG_TOE, + "cdev %p, opcode 0x%x(0x%x,0x%x), skb %p.\n", + cdev, opc, rpl->ot.opcode_tid, ntohl(rpl->ot.opcode_tid), skb); + if (cxgb4i_cplhandlers[opc]) + cxgb4i_cplhandlers[opc](cdev, skb); + else { + pr_err("No handler for opcode 0x%x.\n", opc); + __kfree_skb(skb); + } + return 0; +nomem: + log_debug(1 << CXGBI_DBG_TOE, "OOM bailing out.\n"); + return 1; +} + +static int t4_uld_state_change(void *handle, enum cxgb4_state state) +{ + struct cxgbi_device *cdev = handle; + + switch (state) { + case CXGB4_STATE_UP: + pr_info("cdev 0x%p, UP.\n", cdev); + /* re-initialize */ + break; + case CXGB4_STATE_START_RECOVERY: + pr_info("cdev 0x%p, RECOVERY.\n", cdev); + /* close all connections */ + break; + case CXGB4_STATE_DOWN: + pr_info("cdev 0x%p, DOWN.\n", cdev); + break; + case CXGB4_STATE_DETACH: + pr_info("cdev 0x%p, DETACH.\n", cdev); + break; + default: + pr_info("cdev 0x%p, unknown state %d.\n", cdev, state); + break; + } + return 0; +} + +static int __init cxgb4i_init_module(void) +{ + int rc; + + printk(KERN_INFO "%s", version); + + rc = cxgbi_iscsi_init(&cxgb4i_iscsi_transport, &cxgb4i_stt); + if (rc < 0) + return rc; + cxgb4_register_uld(CXGB4_ULD_ISCSI, &cxgb4i_uld_info); + return 0; +} + +static void __exit cxgb4i_exit_module(void) +{ + cxgb4_unregister_uld(CXGB4_ULD_ISCSI); + cxgbi_device_unregister_all(CXGBI_FLAG_DEV_T4); + cxgbi_iscsi_cleanup(&cxgb4i_iscsi_transport, &cxgb4i_stt); +} + +module_init(cxgb4i_init_module); +module_exit(cxgb4i_exit_module); diff --git a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.h b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.h new file mode 100644 index 000000000000..1096026ba241 --- /dev/null +++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.h @@ -0,0 +1,43 @@ +/* + * cxgb4i.h: Chelsio T4 iSCSI driver. + * + * Copyright (c) 2010 Chelsio Communications, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation. + * + * Written by: Karen Xie (kxie@chelsio.com) + * Written by: Rakesh Ranjan (rranjan@chelsio.com) + */ + +#ifndef __CXGB4I_H__ +#define __CXGB4I_H__ + +#define CXGB4I_SCSI_HOST_QDEPTH 1024 +#define CXGB4I_MAX_CONN 16384 +#define CXGB4I_MAX_TARGET CXGB4I_MAX_CONN +#define CXGB4I_MAX_LUN 0x1000 + +/* for TX: a skb must have a headroom of at least TX_HEADER_LEN bytes */ +#define CXGB4I_TX_HEADER_LEN \ + (sizeof(struct fw_ofld_tx_data_wr) + sizeof(struct sge_opaque_hdr)) + +struct ulptx_idata { + __be32 cmd_more; + __be32 len; +}; + +struct cpl_rx_data_ddp { + union opcode_tid ot; + __be16 urg; + __be16 len; + __be32 seq; + union { + __be32 nxt_seq; + __be32 ddp_report; + }; + __be32 ulp_crc; + __be32 ddpvld; +}; +#endif /* __CXGB4I_H__ */ diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c new file mode 100644 index 000000000000..be5661707dfa --- /dev/null +++ b/drivers/scsi/cxgbi/libcxgbi.c @@ -0,0 +1,2612 @@ +/* + * libcxgbi.c: Chelsio common library for T3/T4 iSCSI driver. + * + * Copyright (c) 2010 Chelsio Communications, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation. + * + * Written by: Karen Xie (kxie@chelsio.com) + * Written by: Rakesh Ranjan (rranjan@chelsio.com) + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ + +#include <linux/skbuff.h> +#include <linux/crypto.h> +#include <linux/scatterlist.h> +#include <linux/pci.h> +#include <scsi/scsi.h> +#include <scsi/scsi_cmnd.h> +#include <scsi/scsi_host.h> +#include <linux/if_vlan.h> +#include <linux/inet.h> +#include <net/dst.h> +#include <net/route.h> +#include <linux/inetdevice.h> /* ip_dev_find */ +#include <net/tcp.h> + +static unsigned int dbg_level; + +#include "libcxgbi.h" + +#define DRV_MODULE_NAME "libcxgbi" +#define DRV_MODULE_DESC "Chelsio iSCSI driver library" +#define DRV_MODULE_VERSION "0.9.0" +#define DRV_MODULE_RELDATE "Jun. 2010" + +MODULE_AUTHOR("Chelsio Communications, Inc."); +MODULE_DESCRIPTION(DRV_MODULE_DESC); +MODULE_VERSION(DRV_MODULE_VERSION); +MODULE_LICENSE("GPL"); + +module_param(dbg_level, uint, 0644); +MODULE_PARM_DESC(dbg_level, "libiscsi debug level (default=0)"); + + +/* + * cxgbi device management + * maintains a list of the cxgbi devices + */ +static LIST_HEAD(cdev_list); +static DEFINE_MUTEX(cdev_mutex); + +int cxgbi_device_portmap_create(struct cxgbi_device *cdev, unsigned int base, + unsigned int max_conn) +{ + struct cxgbi_ports_map *pmap = &cdev->pmap; + + pmap->port_csk = cxgbi_alloc_big_mem(max_conn * + sizeof(struct cxgbi_sock *), + GFP_KERNEL); + if (!pmap->port_csk) { + pr_warn("cdev 0x%p, portmap OOM %u.\n", cdev, max_conn); + return -ENOMEM; + } + + pmap->max_connect = max_conn; + pmap->sport_base = base; + spin_lock_init(&pmap->lock); + return 0; +} +EXPORT_SYMBOL_GPL(cxgbi_device_portmap_create); + +void cxgbi_device_portmap_cleanup(struct cxgbi_device *cdev) +{ + struct cxgbi_ports_map *pmap = &cdev->pmap; + struct cxgbi_sock *csk; + int i; + + for (i = 0; i < pmap->max_connect; i++) { + if (pmap->port_csk[i]) { + csk = pmap->port_csk[i]; + pmap->port_csk[i] = NULL; + log_debug(1 << CXGBI_DBG_SOCK, + "csk 0x%p, cdev 0x%p, offload down.\n", + csk, cdev); + spin_lock_bh(&csk->lock); + cxgbi_sock_set_flag(csk, CTPF_OFFLOAD_DOWN); + cxgbi_sock_closed(csk); + spin_unlock_bh(&csk->lock); + cxgbi_sock_put(csk); + } + } +} +EXPORT_SYMBOL_GPL(cxgbi_device_portmap_cleanup); + +static inline void cxgbi_device_destroy(struct cxgbi_device *cdev) +{ + log_debug(1 << CXGBI_DBG_DEV, + "cdev 0x%p, p# %u.\n", cdev, cdev->nports); + cxgbi_hbas_remove(cdev); + cxgbi_device_portmap_cleanup(cdev); + if (cdev->dev_ddp_cleanup) + cdev->dev_ddp_cleanup(cdev); + else + cxgbi_ddp_cleanup(cdev); + if (cdev->ddp) + cxgbi_ddp_cleanup(cdev); + if (cdev->pmap.max_connect) + cxgbi_free_big_mem(cdev->pmap.port_csk); + kfree(cdev); +} + +struct cxgbi_device *cxgbi_device_register(unsigned int extra, + unsigned int nports) +{ + struct cxgbi_device *cdev; + + cdev = kzalloc(sizeof(*cdev) + extra + nports * + (sizeof(struct cxgbi_hba *) + + sizeof(struct net_device *)), + GFP_KERNEL); + if (!cdev) { + pr_warn("nport %d, OOM.\n", nports); + return NULL; + } + cdev->ports = (struct net_device **)(cdev + 1); + cdev->hbas = (struct cxgbi_hba **)(((char*)cdev->ports) + nports * + sizeof(struct net_device *)); + if (extra) + cdev->dd_data = ((char *)cdev->hbas) + + nports * sizeof(struct cxgbi_hba *); + spin_lock_init(&cdev->pmap.lock); + + mutex_lock(&cdev_mutex); + list_add_tail(&cdev->list_head, &cdev_list); + mutex_unlock(&cdev_mutex); + + log_debug(1 << CXGBI_DBG_DEV, + "cdev 0x%p, p# %u.\n", cdev, nports); + return cdev; +} +EXPORT_SYMBOL_GPL(cxgbi_device_register); + +void cxgbi_device_unregister(struct cxgbi_device *cdev) +{ + log_debug(1 << CXGBI_DBG_DEV, + "cdev 0x%p, p# %u,%s.\n", + cdev, cdev->nports, cdev->nports ? cdev->ports[0]->name : ""); + mutex_lock(&cdev_mutex); + list_del(&cdev->list_head); + mutex_unlock(&cdev_mutex); + cxgbi_device_destroy(cdev); +} +EXPORT_SYMBOL_GPL(cxgbi_device_unregister); + +void cxgbi_device_unregister_all(unsigned int flag) +{ + struct cxgbi_device *cdev, *tmp; + + mutex_lock(&cdev_mutex); + list_for_each_entry_safe(cdev, tmp, &cdev_list, list_head) { + if ((cdev->flags & flag) == flag) { + log_debug(1 << CXGBI_DBG_DEV, + "cdev 0x%p, p# %u,%s.\n", + cdev, cdev->nports, cdev->nports ? + cdev->ports[0]->name : ""); + list_del(&cdev->list_head); + cxgbi_device_destroy(cdev); + } + } + mutex_unlock(&cdev_mutex); +} +EXPORT_SYMBOL_GPL(cxgbi_device_unregister_all); + +struct cxgbi_device *cxgbi_device_find_by_lldev(void *lldev) +{ + struct cxgbi_device *cdev, *tmp; + + mutex_lock(&cdev_mutex); + list_for_each_entry_safe(cdev, tmp, &cdev_list, list_head) { + if (cdev->lldev == lldev) { + mutex_unlock(&cdev_mutex); + return cdev; + } + } + mutex_unlock(&cdev_mutex); + log_debug(1 << CXGBI_DBG_DEV, + "lldev 0x%p, NO match found.\n", lldev); + return NULL; +} +EXPORT_SYMBOL_GPL(cxgbi_device_find_by_lldev); + +static struct cxgbi_device *cxgbi_device_find_by_netdev(struct net_device *ndev, + int *port) +{ + struct net_device *vdev = NULL; + struct cxgbi_device *cdev, *tmp; + int i; + + if (ndev->priv_flags & IFF_802_1Q_VLAN) { + vdev = ndev; + ndev = vlan_dev_real_dev(ndev); + log_debug(1 << CXGBI_DBG_DEV, + "vlan dev %s -> %s.\n", vdev->name, ndev->name); + } + + mutex_lock(&cdev_mutex); + list_for_each_entry_safe(cdev, tmp, &cdev_list, list_head) { + for (i = 0; i < cdev->nports; i++) { + if (ndev == cdev->ports[i]) { + cdev->hbas[i]->vdev = vdev; + mutex_unlock(&cdev_mutex); + if (port) + *port = i; + return cdev; + } + } + } + mutex_unlock(&cdev_mutex); + log_debug(1 << CXGBI_DBG_DEV, + "ndev 0x%p, %s, NO match found.\n", ndev, ndev->name); + return NULL; +} + +void cxgbi_hbas_remove(struct cxgbi_device *cdev) +{ + int i; + struct cxgbi_hba *chba; + + log_debug(1 << CXGBI_DBG_DEV, + "cdev 0x%p, p#%u.\n", cdev, cdev->nports); + + for (i = 0; i < cdev->nports; i++) { + chba = cdev->hbas[i]; + if (chba) { + cdev->hbas[i] = NULL; + iscsi_host_remove(chba->shost); + pci_dev_put(cdev->pdev); + iscsi_host_free(chba->shost); + } + } +} +EXPORT_SYMBOL_GPL(cxgbi_hbas_remove); + +int cxgbi_hbas_add(struct cxgbi_device *cdev, unsigned int max_lun, + unsigned int max_id, struct scsi_host_template *sht, + struct scsi_transport_template *stt) +{ + struct cxgbi_hba *chba; + struct Scsi_Host *shost; + int i, err; + + log_debug(1 << CXGBI_DBG_DEV, "cdev 0x%p, p#%u.\n", cdev, cdev->nports); + + for (i = 0; i < cdev->nports; i++) { + shost = iscsi_host_alloc(sht, sizeof(*chba), 1); + if (!shost) { + pr_info("0x%p, p%d, %s, host alloc failed.\n", + cdev, i, cdev->ports[i]->name); + err = -ENOMEM; + goto err_out; + } + + shost->transportt = stt; + shost->max_lun = max_lun; + shost->max_id = max_id; + shost->max_channel = 0; + shost->max_cmd_len = 16; + + chba = iscsi_host_priv(shost); + chba->cdev = cdev; + chba->ndev = cdev->ports[i]; + chba->shost = shost; + + log_debug(1 << CXGBI_DBG_DEV, + "cdev 0x%p, p#%d %s: chba 0x%p.\n", + cdev, i, cdev->ports[i]->name, chba); + + pci_dev_get(cdev->pdev); + err = iscsi_host_add(shost, &cdev->pdev->dev); + if (err) { + pr_info("cdev 0x%p, p#%d %s, host add failed.\n", + cdev, i, cdev->ports[i]->name); + pci_dev_put(cdev->pdev); + scsi_host_put(shost); + goto err_out; + } + + cdev->hbas[i] = chba; + } + + return 0; + +err_out: + cxgbi_hbas_remove(cdev); + return err; +} +EXPORT_SYMBOL_GPL(cxgbi_hbas_add); + +/* + * iSCSI offload + * + * - source port management + * To find a free source port in the port allocation map we use a very simple + * rotor scheme to look for the next free port. + * + * If a source port has been specified make sure that it doesn't collide with + * our normal source port allocation map. If it's outside the range of our + * allocation/deallocation scheme just let them use it. + * + * If the source port is outside our allocation range, the caller is + * responsible for keeping track of their port usage. + */ +static int sock_get_port(struct cxgbi_sock *csk) +{ + struct cxgbi_device *cdev = csk->cdev; + struct cxgbi_ports_map *pmap = &cdev->pmap; + unsigned int start; + int idx; + + if (!pmap->max_connect) { + pr_err("cdev 0x%p, p#%u %s, NO port map.\n", + cdev, csk->port_id, cdev->ports[csk->port_id]->name); + return -EADDRNOTAVAIL; + } + + if (csk->saddr.sin_port) { + pr_err("source port NON-ZERO %u.\n", + ntohs(csk->saddr.sin_port)); + return -EADDRINUSE; + } + + spin_lock_bh(&pmap->lock); + if (pmap->used >= pmap->max_connect) { + spin_unlock_bh(&pmap->lock); + pr_info("cdev 0x%p, p#%u %s, ALL ports used.\n", + cdev, csk->port_id, cdev->ports[csk->port_id]->name); + return -EADDRNOTAVAIL; + } + + start = idx = pmap->next; + do { + if (++idx >= pmap->max_connect) + idx = 0; + if (!pmap->port_csk[idx]) { + pmap->used++; + csk->saddr.sin_port = + htons(pmap->sport_base + idx); + pmap->next = idx; + pmap->port_csk[idx] = csk; + spin_unlock_bh(&pmap->lock); + cxgbi_sock_get(csk); + log_debug(1 << CXGBI_DBG_SOCK, + "cdev 0x%p, p#%u %s, p %u, %u.\n", + cdev, csk->port_id, + cdev->ports[csk->port_id]->name, + pmap->sport_base + idx, pmap->next); + return 0; + } + } while (idx != start); + spin_unlock_bh(&pmap->lock); + + /* should not happen */ + pr_warn("cdev 0x%p, p#%u %s, next %u?\n", + cdev, csk->port_id, cdev->ports[csk->port_id]->name, + pmap->next); + return -EADDRNOTAVAIL; +} + +static void sock_put_port(struct cxgbi_sock *csk) +{ + struct cxgbi_device *cdev = csk->cdev; + struct cxgbi_ports_map *pmap = &cdev->pmap; + + if (csk->saddr.sin_port) { + int idx = ntohs(csk->saddr.sin_port) - pmap->sport_base; + + csk->saddr.sin_port = 0; + if (idx < 0 || idx >= pmap->max_connect) { + pr_err("cdev 0x%p, p#%u %s, port %u OOR.\n", + cdev, csk->port_id, + cdev->ports[csk->port_id]->name, + ntohs(csk->saddr.sin_port)); + return; + } + + spin_lock_bh(&pmap->lock); + pmap->port_csk[idx] = NULL; + pmap->used--; + spin_unlock_bh(&pmap->lock); + + log_debug(1 << CXGBI_DBG_SOCK, + "cdev 0x%p, p#%u %s, release %u.\n", + cdev, csk->port_id, cdev->ports[csk->port_id]->name, + pmap->sport_base + idx); + + cxgbi_sock_put(csk); + } +} + +/* + * iscsi tcp connection + */ +void cxgbi_sock_free_cpl_skbs(struct cxgbi_sock *csk) +{ + if (csk->cpl_close) { + kfree_skb(csk->cpl_close); + csk->cpl_close = NULL; + } + if (csk->cpl_abort_req) { + kfree_skb(csk->cpl_abort_req); + csk->cpl_abort_req = NULL; + } + if (csk->cpl_abort_rpl) { + kfree_skb(csk->cpl_abort_rpl); + csk->cpl_abort_rpl = NULL; + } +} +EXPORT_SYMBOL_GPL(cxgbi_sock_free_cpl_skbs); + +static struct cxgbi_sock *cxgbi_sock_create(struct cxgbi_device *cdev) +{ + struct cxgbi_sock *csk = kzalloc(sizeof(*csk), GFP_NOIO); + + if (!csk) { + pr_info("alloc csk %zu failed.\n", sizeof(*csk)); + return NULL; + } + + if (cdev->csk_alloc_cpls(csk) < 0) { + pr_info("csk 0x%p, alloc cpls failed.\n", csk); + kfree(csk); + return NULL; + } + + spin_lock_init(&csk->lock); + kref_init(&csk->refcnt); + skb_queue_head_init(&csk->receive_queue); + skb_queue_head_init(&csk->write_queue); + setup_timer(&csk->retry_timer, NULL, (unsigned long)csk); + rwlock_init(&csk->callback_lock); + csk->cdev = cdev; + csk->flags = 0; + cxgbi_sock_set_state(csk, CTP_CLOSED); + + log_debug(1 << CXGBI_DBG_SOCK, "cdev 0x%p, new csk 0x%p.\n", cdev, csk); + + return csk; +} + +static struct rtable *find_route_ipv4(__be32 saddr, __be32 daddr, + __be16 sport, __be16 dport, u8 tos) +{ + struct rtable *rt; + struct flowi fl = { + .oif = 0, + .nl_u = { + .ip4_u = { + .daddr = daddr, + .saddr = saddr, + .tos = tos } + }, + .proto = IPPROTO_TCP, + .uli_u = { + .ports = { + .sport = sport, + .dport = dport } + } + }; + + if (ip_route_output_flow(&init_net, &rt, &fl, NULL, 0)) + return NULL; + + return rt; +} + +static struct cxgbi_sock *cxgbi_check_route(struct sockaddr *dst_addr) +{ + struct sockaddr_in *daddr = (struct sockaddr_in *)dst_addr; + struct dst_entry *dst; + struct net_device *ndev; + struct cxgbi_device *cdev; + struct rtable *rt = NULL; + struct cxgbi_sock *csk = NULL; + unsigned int mtu = 0; + int port = 0xFFFF; + int err = 0; + + if (daddr->sin_family != AF_INET) { + pr_info("address family 0x%x NOT supported.\n", + daddr->sin_family); + err = -EAFNOSUPPORT; + goto err_out; + } + + rt = find_route_ipv4(0, daddr->sin_addr.s_addr, 0, daddr->sin_port, 0); + if (!rt) { + pr_info("no route to ipv4 0x%x, port %u.\n", + daddr->sin_addr.s_addr, daddr->sin_port); + err = -ENETUNREACH; + goto err_out; + } + dst = &rt->dst; + ndev = dst->neighbour->dev; + + if (rt->rt_flags & (RTCF_MULTICAST | RTCF_BROADCAST)) { + pr_info("multi-cast route %pI4, port %u, dev %s.\n", + &daddr->sin_addr.s_addr, ntohs(daddr->sin_port), + ndev->name); + err = -ENETUNREACH; + goto rel_rt; + } + + if (ndev->flags & IFF_LOOPBACK) { + ndev = ip_dev_find(&init_net, daddr->sin_addr.s_addr); + mtu = ndev->mtu; + pr_info("rt dev %s, loopback -> %s, mtu %u.\n", + dst->neighbour->dev->name, ndev->name, mtu); + } + + cdev = cxgbi_device_find_by_netdev(ndev, &port); + if (!cdev) { + pr_info("dst %pI4, %s, NOT cxgbi device.\n", + &daddr->sin_addr.s_addr, ndev->name); + err = -ENETUNREACH; + goto rel_rt; + } + log_debug(1 << CXGBI_DBG_SOCK, + "route to %pI4 :%u, ndev p#%d,%s, cdev 0x%p.\n", + &daddr->sin_addr.s_addr, ntohs(daddr->sin_port), + port, ndev->name, cdev); + + csk = cxgbi_sock_create(cdev); + if (!csk) { + err = -ENOMEM; + goto rel_rt; + } + csk->cdev = cdev; + csk->port_id = port; + csk->mtu = mtu; + csk->dst = dst; + csk->daddr.sin_addr.s_addr = daddr->sin_addr.s_addr; + csk->daddr.sin_port = daddr->sin_port; + csk->saddr.sin_addr.s_addr = rt->rt_src; + + return csk; + +rel_rt: + ip_rt_put(rt); + if (csk) + cxgbi_sock_closed(csk); +err_out: + return ERR_PTR(err); +} + +void cxgbi_sock_established(struct cxgbi_sock *csk, unsigned int snd_isn, + unsigned int opt) +{ + csk->write_seq = csk->snd_nxt = csk->snd_una = snd_isn; + dst_confirm(csk->dst); + smp_mb(); + cxgbi_sock_set_state(csk, CTP_ESTABLISHED); +} +EXPORT_SYMBOL_GPL(cxgbi_sock_established); + +static void cxgbi_inform_iscsi_conn_closing(struct cxgbi_sock *csk) +{ + log_debug(1 << CXGBI_DBG_SOCK, + "csk 0x%p, state %u, flags 0x%lx, conn 0x%p.\n", + csk, csk->state, csk->flags, csk->user_data); + + if (csk->state != CTP_ESTABLISHED) { + read_lock_bh(&csk->callback_lock); + if (csk->user_data) + iscsi_conn_failure(csk->user_data, + ISCSI_ERR_CONN_FAILED); + read_unlock_bh(&csk->callback_lock); + } +} + +void cxgbi_sock_closed(struct cxgbi_sock *csk) +{ + log_debug(1 << CXGBI_DBG_SOCK, "csk 0x%p,%u,0x%lx,%u.\n", + csk, (csk)->state, (csk)->flags, (csk)->tid); + cxgbi_sock_set_flag(csk, CTPF_ACTIVE_CLOSE_NEEDED); + if (csk->state == CTP_ACTIVE_OPEN || csk->state == CTP_CLOSED) + return; + if (csk->saddr.sin_port) + sock_put_port(csk); + if (csk->dst) + dst_release(csk->dst); + csk->cdev->csk_release_offload_resources(csk); + cxgbi_sock_set_state(csk, CTP_CLOSED); + cxgbi_inform_iscsi_conn_closing(csk); + cxgbi_sock_put(csk); +} +EXPORT_SYMBOL_GPL(cxgbi_sock_closed); + +static void need_active_close(struct cxgbi_sock *csk) +{ + int data_lost; + int close_req = 0; + + log_debug(1 << CXGBI_DBG_SOCK, "csk 0x%p,%u,0x%lx,%u.\n", + csk, (csk)->state, (csk)->flags, (csk)->tid); + spin_lock_bh(&csk->lock); + dst_confirm(csk->dst); + data_lost = skb_queue_len(&csk->receive_queue); + __skb_queue_purge(&csk->receive_queue); + + if (csk->state == CTP_ACTIVE_OPEN) + cxgbi_sock_set_flag(csk, CTPF_ACTIVE_CLOSE_NEEDED); + else if (csk->state == CTP_ESTABLISHED) { + close_req = 1; + cxgbi_sock_set_state(csk, CTP_ACTIVE_CLOSE); + } else if (csk->state == CTP_PASSIVE_CLOSE) { + close_req = 1; + cxgbi_sock_set_state(csk, CTP_CLOSE_WAIT_2); + } + + if (close_req) { + if (data_lost) + csk->cdev->csk_send_abort_req(csk); + else + csk->cdev->csk_send_close_req(csk); + } + + spin_unlock_bh(&csk->lock); +} + +void cxgbi_sock_fail_act_open(struct cxgbi_sock *csk, int errno) +{ + pr_info("csk 0x%p,%u,%lx, %pI4:%u-%pI4:%u, err %d.\n", + csk, csk->state, csk->flags, + &csk->saddr.sin_addr.s_addr, csk->saddr.sin_port, + &csk->daddr.sin_addr.s_addr, csk->daddr.sin_port, + errno); + + cxgbi_sock_set_state(csk, CTP_CONNECTING); + csk->err = errno; + cxgbi_sock_closed(csk); +} +EXPORT_SYMBOL_GPL(cxgbi_sock_fail_act_open); + +void cxgbi_sock_act_open_req_arp_failure(void *handle, struct sk_buff *skb) +{ + struct cxgbi_sock *csk = (struct cxgbi_sock *)skb->sk; + + log_debug(1 << CXGBI_DBG_SOCK, "csk 0x%p,%u,0x%lx,%u.\n", + csk, (csk)->state, (csk)->flags, (csk)->tid); + cxgbi_sock_get(csk); + spin_lock_bh(&csk->lock); + if (csk->state == CTP_ACTIVE_OPEN) + cxgbi_sock_fail_act_open(csk, -EHOSTUNREACH); + spin_unlock_bh(&csk->lock); + cxgbi_sock_put(csk); + __kfree_skb(skb); +} +EXPORT_SYMBOL_GPL(cxgbi_sock_act_open_req_arp_failure); + +void cxgbi_sock_rcv_abort_rpl(struct cxgbi_sock *csk) +{ + cxgbi_sock_get(csk); + spin_lock_bh(&csk->lock); + if (cxgbi_sock_flag(csk, CTPF_ABORT_RPL_PENDING)) { + if (!cxgbi_sock_flag(csk, CTPF_ABORT_RPL_RCVD)) + cxgbi_sock_set_flag(csk, CTPF_ABORT_RPL_RCVD); + else { + cxgbi_sock_clear_flag(csk, CTPF_ABORT_RPL_RCVD); + cxgbi_sock_clear_flag(csk, CTPF_ABORT_RPL_PENDING); + if (cxgbi_sock_flag(csk, CTPF_ABORT_REQ_RCVD)) + pr_err("csk 0x%p,%u,0x%lx,%u,ABT_RPL_RSS.\n", + csk, csk->state, csk->flags, csk->tid); + cxgbi_sock_closed(csk); + } + } + spin_unlock_bh(&csk->lock); + cxgbi_sock_put(csk); +} +EXPORT_SYMBOL_GPL(cxgbi_sock_rcv_abort_rpl); + +void cxgbi_sock_rcv_peer_close(struct cxgbi_sock *csk) +{ + log_debug(1 << CXGBI_DBG_SOCK, "csk 0x%p,%u,0x%lx,%u.\n", + csk, (csk)->state, (csk)->flags, (csk)->tid); + cxgbi_sock_get(csk); + spin_lock_bh(&csk->lock); + + if (cxgbi_sock_flag(csk, CTPF_ABORT_RPL_PENDING)) + goto done; + + switch (csk->state) { + case CTP_ESTABLISHED: + cxgbi_sock_set_state(csk, CTP_PASSIVE_CLOSE); + break; + case CTP_ACTIVE_CLOSE: + cxgbi_sock_set_state(csk, CTP_CLOSE_WAIT_2); + break; + case CTP_CLOSE_WAIT_1: + cxgbi_sock_closed(csk); + break; + case CTP_ABORTING: + break; + default: + pr_err("csk 0x%p,%u,0x%lx,%u, bad state.\n", + csk, csk->state, csk->flags, csk->tid); + } + cxgbi_inform_iscsi_conn_closing(csk); +done: + spin_unlock_bh(&csk->lock); + cxgbi_sock_put(csk); +} +EXPORT_SYMBOL_GPL(cxgbi_sock_rcv_peer_close); + +void cxgbi_sock_rcv_close_conn_rpl(struct cxgbi_sock *csk, u32 snd_nxt) +{ + log_debug(1 << CXGBI_DBG_SOCK, "csk 0x%p,%u,0x%lx,%u.\n", + csk, (csk)->state, (csk)->flags, (csk)->tid); + cxgbi_sock_get(csk); + spin_lock_bh(&csk->lock); + + csk->snd_una = snd_nxt - 1; + if (cxgbi_sock_flag(csk, CTPF_ABORT_RPL_PENDING)) + goto done; + + switch (csk->state) { + case CTP_ACTIVE_CLOSE: + cxgbi_sock_set_state(csk, CTP_CLOSE_WAIT_1); + break; + case CTP_CLOSE_WAIT_1: + case CTP_CLOSE_WAIT_2: + cxgbi_sock_closed(csk); + break; + case CTP_ABORTING: + break; + default: + pr_err("csk 0x%p,%u,0x%lx,%u, bad state.\n", + csk, csk->state, csk->flags, csk->tid); + } +done: + spin_unlock_bh(&csk->lock); + cxgbi_sock_put(csk); +} +EXPORT_SYMBOL_GPL(cxgbi_sock_rcv_close_conn_rpl); + +void cxgbi_sock_rcv_wr_ack(struct cxgbi_sock *csk, unsigned int credits, + unsigned int snd_una, int seq_chk) +{ + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, + "csk 0x%p,%u,0x%lx,%u, cr %u,%u+%u, snd_una %u,%d.\n", + csk, csk->state, csk->flags, csk->tid, credits, + csk->wr_cred, csk->wr_una_cred, snd_una, seq_chk); + + spin_lock_bh(&csk->lock); + + csk->wr_cred += credits; + if (csk->wr_una_cred > csk->wr_max_cred - csk->wr_cred) + csk->wr_una_cred = csk->wr_max_cred - csk->wr_cred; + + while (credits) { + struct sk_buff *p = cxgbi_sock_peek_wr(csk); + + if (unlikely(!p)) { + pr_err("csk 0x%p,%u,0x%lx,%u, cr %u,%u+%u, empty.\n", + csk, csk->state, csk->flags, csk->tid, credits, + csk->wr_cred, csk->wr_una_cred); + break; + } + + if (unlikely(credits < p->csum)) { + pr_warn("csk 0x%p,%u,0x%lx,%u, cr %u,%u+%u, < %u.\n", + csk, csk->state, csk->flags, csk->tid, + credits, csk->wr_cred, csk->wr_una_cred, + p->csum); + p->csum -= credits; + break; + } else { + cxgbi_sock_dequeue_wr(csk); + credits -= p->csum; + kfree_skb(p); + } + } + + cxgbi_sock_check_wr_invariants(csk); + + if (seq_chk) { + if (unlikely(before(snd_una, csk->snd_una))) { + pr_warn("csk 0x%p,%u,0x%lx,%u, snd_una %u/%u.", + csk, csk->state, csk->flags, csk->tid, snd_una, + csk->snd_una); + goto done; + } + + if (csk->snd_una != snd_una) { + csk->snd_una = snd_una; + dst_confirm(csk->dst); + } + } + + if (skb_queue_len(&csk->write_queue)) { + if (csk->cdev->csk_push_tx_frames(csk, 0)) + cxgbi_conn_tx_open(csk); + } else + cxgbi_conn_tx_open(csk); +done: + spin_unlock_bh(&csk->lock); +} +EXPORT_SYMBOL_GPL(cxgbi_sock_rcv_wr_ack); + +static unsigned int cxgbi_sock_find_best_mtu(struct cxgbi_sock *csk, + unsigned short mtu) +{ + int i = 0; + + while (i < csk->cdev->nmtus - 1 && csk->cdev->mtus[i + 1] <= mtu) + ++i; + + return i; +} + +unsigned int cxgbi_sock_select_mss(struct cxgbi_sock *csk, unsigned int pmtu) +{ + unsigned int idx; + struct dst_entry *dst = csk->dst; + + csk->advmss = dst_metric(dst, RTAX_ADVMSS); + + if (csk->advmss > pmtu - 40) + csk->advmss = pmtu - 40; + if (csk->advmss < csk->cdev->mtus[0] - 40) + csk->advmss = csk->cdev->mtus[0] - 40; + idx = cxgbi_sock_find_best_mtu(csk, csk->advmss + 40); + + return idx; +} +EXPORT_SYMBOL_GPL(cxgbi_sock_select_mss); + +void cxgbi_sock_skb_entail(struct cxgbi_sock *csk, struct sk_buff *skb) +{ + cxgbi_skcb_tcp_seq(skb) = csk->write_seq; + __skb_queue_tail(&csk->write_queue, skb); +} +EXPORT_SYMBOL_GPL(cxgbi_sock_skb_entail); + +void cxgbi_sock_purge_wr_queue(struct cxgbi_sock *csk) +{ + struct sk_buff *skb; + + while ((skb = cxgbi_sock_dequeue_wr(csk)) != NULL) + kfree_skb(skb); +} +EXPORT_SYMBOL_GPL(cxgbi_sock_purge_wr_queue); + +void cxgbi_sock_check_wr_invariants(const struct cxgbi_sock *csk) +{ + int pending = cxgbi_sock_count_pending_wrs(csk); + + if (unlikely(csk->wr_cred + pending != csk->wr_max_cred)) + pr_err("csk 0x%p, tid %u, credit %u + %u != %u.\n", + csk, csk->tid, csk->wr_cred, pending, csk->wr_max_cred); +} +EXPORT_SYMBOL_GPL(cxgbi_sock_check_wr_invariants); + +static int cxgbi_sock_send_pdus(struct cxgbi_sock *csk, struct sk_buff *skb) +{ + struct cxgbi_device *cdev = csk->cdev; + struct sk_buff *next; + int err, copied = 0; + + spin_lock_bh(&csk->lock); + + if (csk->state != CTP_ESTABLISHED) { + log_debug(1 << CXGBI_DBG_PDU_TX, + "csk 0x%p,%u,0x%lx,%u, EAGAIN.\n", + csk, csk->state, csk->flags, csk->tid); + err = -EAGAIN; + goto out_err; + } + + if (csk->err) { + log_debug(1 << CXGBI_DBG_PDU_TX, + "csk 0x%p,%u,0x%lx,%u, EPIPE %d.\n", + csk, csk->state, csk->flags, csk->tid, csk->err); + err = -EPIPE; + goto out_err; + } + + if (csk->write_seq - csk->snd_una >= cdev->snd_win) { + log_debug(1 << CXGBI_DBG_PDU_TX, + "csk 0x%p,%u,0x%lx,%u, FULL %u-%u >= %u.\n", + csk, csk->state, csk->flags, csk->tid, csk->write_seq, + csk->snd_una, cdev->snd_win); + err = -ENOBUFS; + goto out_err; + } + + while (skb) { + int frags = skb_shinfo(skb)->nr_frags + + (skb->len != skb->data_len); + + if (unlikely(skb_headroom(skb) < cdev->skb_tx_rsvd)) { + pr_err("csk 0x%p, skb head %u < %u.\n", + csk, skb_headroom(skb), cdev->skb_tx_rsvd); + err = -EINVAL; + goto out_err; + } + + if (frags >= SKB_WR_LIST_SIZE) { + pr_err("csk 0x%p, frags %d, %u,%u >%u.\n", + csk, skb_shinfo(skb)->nr_frags, skb->len, + skb->data_len, (uint)(SKB_WR_LIST_SIZE)); + err = -EINVAL; + goto out_err; + } + + next = skb->next; + skb->next = NULL; + cxgbi_skcb_set_flag(skb, SKCBF_TX_NEED_HDR); + cxgbi_sock_skb_entail(csk, skb); + copied += skb->len; + csk->write_seq += skb->len + + cxgbi_ulp_extra_len(cxgbi_skcb_ulp_mode(skb)); + skb = next; + } +done: + if (likely(skb_queue_len(&csk->write_queue))) + cdev->csk_push_tx_frames(csk, 1); + spin_unlock_bh(&csk->lock); + return copied; + +out_err: + if (copied == 0 && err == -EPIPE) + copied = csk->err ? csk->err : -EPIPE; + else + copied = err; + goto done; +} + +/* + * Direct Data Placement - + * Directly place the iSCSI Data-In or Data-Out PDU's payload into pre-posted + * final destination host-memory buffers based on the Initiator Task Tag (ITT) + * in Data-In or Target Task Tag (TTT) in Data-Out PDUs. + * The host memory address is programmed into h/w in the format of pagepod + * entries. + * The location of the pagepod entry is encoded into ddp tag which is used as + * the base for ITT/TTT. + */ + +static unsigned char ddp_page_order[DDP_PGIDX_MAX] = {0, 1, 2, 4}; +static unsigned char ddp_page_shift[DDP_PGIDX_MAX] = {12, 13, 14, 16}; +static unsigned char page_idx = DDP_PGIDX_MAX; + +static unsigned char sw_tag_idx_bits; +static unsigned char sw_tag_age_bits; + +/* + * Direct-Data Placement page size adjustment + */ +static int ddp_adjust_page_table(void) +{ + int i; + unsigned int base_order, order; + + if (PAGE_SIZE < (1UL << ddp_page_shift[0])) { + pr_info("PAGE_SIZE 0x%lx too small, min 0x%lx\n", + PAGE_SIZE, 1UL << ddp_page_shift[0]); + return -EINVAL; + } + + base_order = get_order(1UL << ddp_page_shift[0]); + order = get_order(1UL << PAGE_SHIFT); + + for (i = 0; i < DDP_PGIDX_MAX; i++) { + /* first is the kernel page size, then just doubling */ + ddp_page_order[i] = order - base_order + i; + ddp_page_shift[i] = PAGE_SHIFT + i; + } + return 0; +} + +static int ddp_find_page_index(unsigned long pgsz) +{ + int i; + + for (i = 0; i < DDP_PGIDX_MAX; i++) { + if (pgsz == (1UL << ddp_page_shift[i])) + return i; + } + pr_info("ddp page size %lu not supported.\n", pgsz); + return DDP_PGIDX_MAX; +} + +static void ddp_setup_host_page_size(void) +{ + if (page_idx == DDP_PGIDX_MAX) { + page_idx = ddp_find_page_index(PAGE_SIZE); + + if (page_idx == DDP_PGIDX_MAX) { + pr_info("system PAGE %lu, update hw.\n", PAGE_SIZE); + if (ddp_adjust_page_table() < 0) { + pr_info("PAGE %lu, disable ddp.\n", PAGE_SIZE); + return; + } + page_idx = ddp_find_page_index(PAGE_SIZE); + } + pr_info("system PAGE %lu, ddp idx %u.\n", PAGE_SIZE, page_idx); + } +} + +void cxgbi_ddp_page_size_factor(int *pgsz_factor) +{ + int i; + + for (i = 0; i < DDP_PGIDX_MAX; i++) + pgsz_factor[i] = ddp_page_order[i]; +} +EXPORT_SYMBOL_GPL(cxgbi_ddp_page_size_factor); + +/* + * DDP setup & teardown + */ + +void cxgbi_ddp_ppod_set(struct cxgbi_pagepod *ppod, + struct cxgbi_pagepod_hdr *hdr, + struct cxgbi_gather_list *gl, unsigned int gidx) +{ + int i; + + memcpy(ppod, hdr, sizeof(*hdr)); + for (i = 0; i < (PPOD_PAGES_MAX + 1); i++, gidx++) { + ppod->addr[i] = gidx < gl->nelem ? + cpu_to_be64(gl->phys_addr[gidx]) : 0ULL; + } +} +EXPORT_SYMBOL_GPL(cxgbi_ddp_ppod_set); + +void cxgbi_ddp_ppod_clear(struct cxgbi_pagepod *ppod) +{ + memset(ppod, 0, sizeof(*ppod)); +} +EXPORT_SYMBOL_GPL(cxgbi_ddp_ppod_clear); + +static inline int ddp_find_unused_entries(struct cxgbi_ddp_info *ddp, + unsigned int start, unsigned int max, + unsigned int count, + struct cxgbi_gather_list *gl) +{ + unsigned int i, j, k; + + /* not enough entries */ + if ((max - start) < count) { + log_debug(1 << CXGBI_DBG_DDP, + "NOT enough entries %u+%u < %u.\n", start, count, max); + return -EBUSY; + } + + max -= count; + spin_lock(&ddp->map_lock); + for (i = start; i < max;) { + for (j = 0, k = i; j < count; j++, k++) { + if (ddp->gl_map[k]) + break; + } + if (j == count) { + for (j = 0, k = i; j < count; j++, k++) + ddp->gl_map[k] = gl; + spin_unlock(&ddp->map_lock); + return i; + } + i += j + 1; + } + spin_unlock(&ddp->map_lock); + log_debug(1 << CXGBI_DBG_DDP, + "NO suitable entries %u available.\n", count); + return -EBUSY; +} + +static inline void ddp_unmark_entries(struct cxgbi_ddp_info *ddp, + int start, int count) +{ + spin_lock(&ddp->map_lock); + memset(&ddp->gl_map[start], 0, + count * sizeof(struct cxgbi_gather_list *)); + spin_unlock(&ddp->map_lock); +} + +static inline void ddp_gl_unmap(struct pci_dev *pdev, + struct cxgbi_gather_list *gl) +{ + int i; + + for (i = 0; i < gl->nelem; i++) + dma_unmap_page(&pdev->dev, gl->phys_addr[i], PAGE_SIZE, + PCI_DMA_FROMDEVICE); +} + +static inline int ddp_gl_map(struct pci_dev *pdev, + struct cxgbi_gather_list *gl) +{ + int i; + + for (i = 0; i < gl->nelem; i++) { + gl->phys_addr[i] = dma_map_page(&pdev->dev, gl->pages[i], 0, + PAGE_SIZE, + PCI_DMA_FROMDEVICE); + if (unlikely(dma_mapping_error(&pdev->dev, gl->phys_addr[i]))) { + log_debug(1 << CXGBI_DBG_DDP, + "page %d 0x%p, 0x%p dma mapping err.\n", + i, gl->pages[i], pdev); + goto unmap; + } + } + return i; +unmap: + if (i) { + unsigned int nelem = gl->nelem; + + gl->nelem = i; + ddp_gl_unmap(pdev, gl); + gl->nelem = nelem; + } + return -EINVAL; +} + +static void ddp_release_gl(struct cxgbi_gather_list *gl, + struct pci_dev *pdev) +{ + ddp_gl_unmap(pdev, gl); + kfree(gl); +} + +static struct cxgbi_gather_list *ddp_make_gl(unsigned int xferlen, + struct scatterlist *sgl, + unsigned int sgcnt, + struct pci_dev *pdev, + gfp_t gfp) +{ + struct cxgbi_gather_list *gl; + struct scatterlist *sg = sgl; + struct page *sgpage = sg_page(sg); + unsigned int sglen = sg->length; + unsigned int sgoffset = sg->offset; + unsigned int npages = (xferlen + sgoffset + PAGE_SIZE - 1) >> + PAGE_SHIFT; + int i = 1, j = 0; + + if (xferlen < DDP_THRESHOLD) { + log_debug(1 << CXGBI_DBG_DDP, + "xfer %u < threshold %u, no ddp.\n", + xferlen, DDP_THRESHOLD); + return NULL; + } + + gl = kzalloc(sizeof(struct cxgbi_gather_list) + + npages * (sizeof(dma_addr_t) + + sizeof(struct page *)), gfp); + if (!gl) { + log_debug(1 << CXGBI_DBG_DDP, + "xfer %u, %u pages, OOM.\n", xferlen, npages); + return NULL; + } + + log_debug(1 << CXGBI_DBG_DDP, + "xfer %u, sgl %u, gl max %u.\n", xferlen, sgcnt, npages); + + gl->pages = (struct page **)&gl->phys_addr[npages]; + gl->nelem = npages; + gl->length = xferlen; + gl->offset = sgoffset; + gl->pages[0] = sgpage; + + for (i = 1, sg = sg_next(sgl), j = 0; i < sgcnt; + i++, sg = sg_next(sg)) { + struct page *page = sg_page(sg); + + if (sgpage == page && sg->offset == sgoffset + sglen) + sglen += sg->length; + else { + /* make sure the sgl is fit for ddp: + * each has the same page size, and + * all of the middle pages are used completely + */ + if ((j && sgoffset) || ((i != sgcnt - 1) && + ((sglen + sgoffset) & ~PAGE_MASK))) { + log_debug(1 << CXGBI_DBG_DDP, + "page %d/%u, %u + %u.\n", + i, sgcnt, sgoffset, sglen); + goto error_out; + } + + j++; + if (j == gl->nelem || sg->offset) { + log_debug(1 << CXGBI_DBG_DDP, + "page %d/%u, offset %u.\n", + j, gl->nelem, sg->offset); + goto error_out; + } + gl->pages[j] = page; + sglen = sg->length; + sgoffset = sg->offset; + sgpage = page; + } + } + gl->nelem = ++j; + + if (ddp_gl_map(pdev, gl) < 0) + goto error_out; + + return gl; + +error_out: + kfree(gl); + return NULL; +} + +static void ddp_tag_release(struct cxgbi_hba *chba, u32 tag) +{ + struct cxgbi_device *cdev = chba->cdev; + struct cxgbi_ddp_info *ddp = cdev->ddp; + u32 idx; + + idx = (tag >> PPOD_IDX_SHIFT) & ddp->idx_mask; + if (idx < ddp->nppods) { + struct cxgbi_gather_list *gl = ddp->gl_map[idx]; + unsigned int npods; + + if (!gl || !gl->nelem) { + pr_warn("tag 0x%x, idx %u, gl 0x%p, %u.\n", + tag, idx, gl, gl ? gl->nelem : 0); + return; + } + npods = (gl->nelem + PPOD_PAGES_MAX - 1) >> PPOD_PAGES_SHIFT; + log_debug(1 << CXGBI_DBG_DDP, + "tag 0x%x, release idx %u, npods %u.\n", + tag, idx, npods); + cdev->csk_ddp_clear(chba, tag, idx, npods); + ddp_unmark_entries(ddp, idx, npods); + ddp_release_gl(gl, ddp->pdev); + } else + pr_warn("tag 0x%x, idx %u > max %u.\n", tag, idx, ddp->nppods); +} + +static int ddp_tag_reserve(struct cxgbi_sock *csk, unsigned int tid, + u32 sw_tag, u32 *tagp, struct cxgbi_gather_list *gl, + gfp_t gfp) +{ + struct cxgbi_device *cdev = csk->cdev; + struct cxgbi_ddp_info *ddp = cdev->ddp; + struct cxgbi_tag_format *tformat = &cdev->tag_format; + struct cxgbi_pagepod_hdr hdr; + unsigned int npods; + int idx = -1; + int err = -ENOMEM; + u32 tag; + + npods = (gl->nelem + PPOD_PAGES_MAX - 1) >> PPOD_PAGES_SHIFT; + if (ddp->idx_last == ddp->nppods) + idx = ddp_find_unused_entries(ddp, 0, ddp->nppods, + npods, gl); + else { + idx = ddp_find_unused_entries(ddp, ddp->idx_last + 1, + ddp->nppods, npods, + gl); + if (idx < 0 && ddp->idx_last >= npods) { + idx = ddp_find_unused_entries(ddp, 0, + min(ddp->idx_last + npods, ddp->nppods), + npods, gl); + } + } + if (idx < 0) { + log_debug(1 << CXGBI_DBG_DDP, + "xferlen %u, gl %u, npods %u NO DDP.\n", + gl->length, gl->nelem, npods); + return idx; + } + + if (cdev->csk_ddp_alloc_gl_skb) { + err = cdev->csk_ddp_alloc_gl_skb(ddp, idx, npods, gfp); + if (err < 0) + goto unmark_entries; + } + + tag = cxgbi_ddp_tag_base(tformat, sw_tag); + tag |= idx << PPOD_IDX_SHIFT; + + hdr.rsvd = 0; + hdr.vld_tid = htonl(PPOD_VALID_FLAG | PPOD_TID(tid)); + hdr.pgsz_tag_clr = htonl(tag & ddp->rsvd_tag_mask); + hdr.max_offset = htonl(gl->length); + hdr.page_offset = htonl(gl->offset); + + err = cdev->csk_ddp_set(csk, &hdr, idx, npods, gl); + if (err < 0) { + if (cdev->csk_ddp_free_gl_skb) + cdev->csk_ddp_free_gl_skb(ddp, idx, npods); + goto unmark_entries; + } + + ddp->idx_last = idx; + log_debug(1 << CXGBI_DBG_DDP, + "xfer %u, gl %u,%u, tid 0x%x, tag 0x%x->0x%x(%u,%u).\n", + gl->length, gl->nelem, gl->offset, tid, sw_tag, tag, idx, + npods); + *tagp = tag; + return 0; + +unmark_entries: + ddp_unmark_entries(ddp, idx, npods); + return err; +} + +int cxgbi_ddp_reserve(struct cxgbi_sock *csk, unsigned int *tagp, + unsigned int sw_tag, unsigned int xferlen, + struct scatterlist *sgl, unsigned int sgcnt, gfp_t gfp) +{ + struct cxgbi_device *cdev = csk->cdev; + struct cxgbi_tag_format *tformat = &cdev->tag_format; + struct cxgbi_gather_list *gl; + int err; + + if (page_idx >= DDP_PGIDX_MAX || !cdev->ddp || + xferlen < DDP_THRESHOLD) { + log_debug(1 << CXGBI_DBG_DDP, + "pgidx %u, xfer %u, NO ddp.\n", page_idx, xferlen); + return -EINVAL; + } + + if (!cxgbi_sw_tag_usable(tformat, sw_tag)) { + log_debug(1 << CXGBI_DBG_DDP, + "sw_tag 0x%x NOT usable.\n", sw_tag); + return -EINVAL; + } + + gl = ddp_make_gl(xferlen, sgl, sgcnt, cdev->pdev, gfp); + if (!gl) + return -ENOMEM; + + err = ddp_tag_reserve(csk, csk->tid, sw_tag, tagp, gl, gfp); + if (err < 0) + ddp_release_gl(gl, cdev->pdev); + + return err; +} + +static void ddp_destroy(struct kref *kref) +{ + struct cxgbi_ddp_info *ddp = container_of(kref, + struct cxgbi_ddp_info, + refcnt); + struct cxgbi_device *cdev = ddp->cdev; + int i = 0; + + pr_info("kref 0, destroy ddp 0x%p, cdev 0x%p.\n", ddp, cdev); + + while (i < ddp->nppods) { + struct cxgbi_gather_list *gl = ddp->gl_map[i]; + + if (gl) { + int npods = (gl->nelem + PPOD_PAGES_MAX - 1) + >> PPOD_PAGES_SHIFT; + pr_info("cdev 0x%p, ddp %d + %d.\n", cdev, i, npods); + kfree(gl); + if (cdev->csk_ddp_free_gl_skb) + cdev->csk_ddp_free_gl_skb(ddp, i, npods); + i += npods; + } else + i++; + } + cxgbi_free_big_mem(ddp); +} + +int cxgbi_ddp_cleanup(struct cxgbi_device *cdev) +{ + struct cxgbi_ddp_info *ddp = cdev->ddp; + + log_debug(1 << CXGBI_DBG_DDP, + "cdev 0x%p, release ddp 0x%p.\n", cdev, ddp); + cdev->ddp = NULL; + if (ddp) + return kref_put(&ddp->refcnt, ddp_destroy); + return 0; +} +EXPORT_SYMBOL_GPL(cxgbi_ddp_cleanup); + +int cxgbi_ddp_init(struct cxgbi_device *cdev, + unsigned int llimit, unsigned int ulimit, + unsigned int max_txsz, unsigned int max_rxsz) +{ + struct cxgbi_ddp_info *ddp; + unsigned int ppmax, bits; + + ppmax = (ulimit - llimit + 1) >> PPOD_SIZE_SHIFT; + bits = __ilog2_u32(ppmax) + 1; + if (bits > PPOD_IDX_MAX_SIZE) + bits = PPOD_IDX_MAX_SIZE; + ppmax = (1 << (bits - 1)) - 1; + + ddp = cxgbi_alloc_big_mem(sizeof(struct cxgbi_ddp_info) + + ppmax * (sizeof(struct cxgbi_gather_list *) + + sizeof(struct sk_buff *)), + GFP_KERNEL); + if (!ddp) { + pr_warn("cdev 0x%p, ddp ppmax %u OOM.\n", cdev, ppmax); + return -ENOMEM; + } + ddp->gl_map = (struct cxgbi_gather_list **)(ddp + 1); + ddp->gl_skb = (struct sk_buff **)(((char *)ddp->gl_map) + + ppmax * sizeof(struct cxgbi_gather_list *)); + cdev->ddp = ddp; + + spin_lock_init(&ddp->map_lock); + kref_init(&ddp->refcnt); + + ddp->cdev = cdev; + ddp->pdev = cdev->pdev; + ddp->llimit = llimit; + ddp->ulimit = ulimit; + ddp->max_txsz = min_t(unsigned int, max_txsz, ULP2_MAX_PKT_SIZE); + ddp->max_rxsz = min_t(unsigned int, max_rxsz, ULP2_MAX_PKT_SIZE); + ddp->nppods = ppmax; + ddp->idx_last = ppmax; + ddp->idx_bits = bits; + ddp->idx_mask = (1 << bits) - 1; + ddp->rsvd_tag_mask = (1 << (bits + PPOD_IDX_SHIFT)) - 1; + + cdev->tag_format.sw_bits = sw_tag_idx_bits + sw_tag_age_bits; + cdev->tag_format.rsvd_bits = ddp->idx_bits; + cdev->tag_format.rsvd_shift = PPOD_IDX_SHIFT; + cdev->tag_format.rsvd_mask = (1 << cdev->tag_format.rsvd_bits) - 1; + + pr_info("%s tag format, sw %u, rsvd %u,%u, mask 0x%x.\n", + cdev->ports[0]->name, cdev->tag_format.sw_bits, + cdev->tag_format.rsvd_bits, cdev->tag_format.rsvd_shift, + cdev->tag_format.rsvd_mask); + + cdev->tx_max_size = min_t(unsigned int, ULP2_MAX_PDU_PAYLOAD, + ddp->max_txsz - ISCSI_PDU_NONPAYLOAD_LEN); + cdev->rx_max_size = min_t(unsigned int, ULP2_MAX_PDU_PAYLOAD, + ddp->max_rxsz - ISCSI_PDU_NONPAYLOAD_LEN); + + log_debug(1 << CXGBI_DBG_DDP, + "%s max payload size: %u/%u, %u/%u.\n", + cdev->ports[0]->name, cdev->tx_max_size, ddp->max_txsz, + cdev->rx_max_size, ddp->max_rxsz); + return 0; +} +EXPORT_SYMBOL_GPL(cxgbi_ddp_init); + +/* + * APIs interacting with open-iscsi libraries + */ + +static unsigned char padding[4]; + +static void task_release_itt(struct iscsi_task *task, itt_t hdr_itt) +{ + struct scsi_cmnd *sc = task->sc; + struct iscsi_tcp_conn *tcp_conn = task->conn->dd_data; + struct cxgbi_conn *cconn = tcp_conn->dd_data; + struct cxgbi_hba *chba = cconn->chba; + struct cxgbi_tag_format *tformat = &chba->cdev->tag_format; + u32 tag = ntohl((__force u32)hdr_itt); + + log_debug(1 << CXGBI_DBG_DDP, + "cdev 0x%p, release tag 0x%x.\n", chba->cdev, tag); + if (sc && + (scsi_bidi_cmnd(sc) || sc->sc_data_direction == DMA_FROM_DEVICE) && + cxgbi_is_ddp_tag(tformat, tag)) + ddp_tag_release(chba, tag); +} + +static int task_reserve_itt(struct iscsi_task *task, itt_t *hdr_itt) +{ + struct scsi_cmnd *sc = task->sc; + struct iscsi_conn *conn = task->conn; + struct iscsi_session *sess = conn->session; + struct iscsi_tcp_conn *tcp_conn = conn->dd_data; + struct cxgbi_conn *cconn = tcp_conn->dd_data; + struct cxgbi_hba *chba = cconn->chba; + struct cxgbi_tag_format *tformat = &chba->cdev->tag_format; + u32 sw_tag = (sess->age << cconn->task_idx_bits) | task->itt; + u32 tag = 0; + int err = -EINVAL; + + if (sc && + (scsi_bidi_cmnd(sc) || sc->sc_data_direction == DMA_FROM_DEVICE)) { + err = cxgbi_ddp_reserve(cconn->cep->csk, &tag, sw_tag, + scsi_in(sc)->length, + scsi_in(sc)->table.sgl, + scsi_in(sc)->table.nents, + GFP_ATOMIC); + if (err < 0) + log_debug(1 << CXGBI_DBG_DDP, + "csk 0x%p, R task 0x%p, %u,%u, no ddp.\n", + cconn->cep->csk, task, scsi_in(sc)->length, + scsi_in(sc)->table.nents); + } + + if (err < 0) + tag = cxgbi_set_non_ddp_tag(tformat, sw_tag); + /* the itt need to sent in big-endian order */ + *hdr_itt = (__force itt_t)htonl(tag); + + log_debug(1 << CXGBI_DBG_DDP, + "cdev 0x%p, task 0x%p, 0x%x(0x%x,0x%x)->0x%x/0x%x.\n", + chba->cdev, task, sw_tag, task->itt, sess->age, tag, *hdr_itt); + return 0; +} + +void cxgbi_parse_pdu_itt(struct iscsi_conn *conn, itt_t itt, int *idx, int *age) +{ + struct iscsi_tcp_conn *tcp_conn = conn->dd_data; + struct cxgbi_conn *cconn = tcp_conn->dd_data; + struct cxgbi_device *cdev = cconn->chba->cdev; + u32 tag = ntohl((__force u32) itt); + u32 sw_bits; + + sw_bits = cxgbi_tag_nonrsvd_bits(&cdev->tag_format, tag); + if (idx) + *idx = sw_bits & ((1 << cconn->task_idx_bits) - 1); + if (age) + *age = (sw_bits >> cconn->task_idx_bits) & ISCSI_AGE_MASK; + + log_debug(1 << CXGBI_DBG_DDP, + "cdev 0x%p, tag 0x%x/0x%x, -> 0x%x(0x%x,0x%x).\n", + cdev, tag, itt, sw_bits, idx ? *idx : 0xFFFFF, + age ? *age : 0xFF); +} +EXPORT_SYMBOL_GPL(cxgbi_parse_pdu_itt); + +void cxgbi_conn_tx_open(struct cxgbi_sock *csk) +{ + struct iscsi_conn *conn = csk->user_data; + + if (conn) { + log_debug(1 << CXGBI_DBG_SOCK, + "csk 0x%p, cid %d.\n", csk, conn->id); + iscsi_conn_queue_work(conn); + } +} +EXPORT_SYMBOL_GPL(cxgbi_conn_tx_open); + +/* + * pdu receive, interact with libiscsi_tcp + */ +static inline int read_pdu_skb(struct iscsi_conn *conn, + struct sk_buff *skb, + unsigned int offset, + int offloaded) +{ + int status = 0; + int bytes_read; + + bytes_read = iscsi_tcp_recv_skb(conn, skb, offset, offloaded, &status); + switch (status) { + case ISCSI_TCP_CONN_ERR: + pr_info("skb 0x%p, off %u, %d, TCP_ERR.\n", + skb, offset, offloaded); + return -EIO; + case ISCSI_TCP_SUSPENDED: + log_debug(1 << CXGBI_DBG_PDU_RX, + "skb 0x%p, off %u, %d, TCP_SUSPEND, rc %d.\n", + skb, offset, offloaded, bytes_read); + /* no transfer - just have caller flush queue */ + return bytes_read; + case ISCSI_TCP_SKB_DONE: + pr_info("skb 0x%p, off %u, %d, TCP_SKB_DONE.\n", + skb, offset, offloaded); + /* + * pdus should always fit in the skb and we should get + * segment done notifcation. + */ + iscsi_conn_printk(KERN_ERR, conn, "Invalid pdu or skb."); + return -EFAULT; + case ISCSI_TCP_SEGMENT_DONE: + log_debug(1 << CXGBI_DBG_PDU_RX, + "skb 0x%p, off %u, %d, TCP_SEG_DONE, rc %d.\n", + skb, offset, offloaded, bytes_read); + return bytes_read; + default: + pr_info("skb 0x%p, off %u, %d, invalid status %d.\n", + skb, offset, offloaded, status); + return -EINVAL; + } +} + +static int skb_read_pdu_bhs(struct iscsi_conn *conn, struct sk_buff *skb) +{ + struct iscsi_tcp_conn *tcp_conn = conn->dd_data; + + log_debug(1 << CXGBI_DBG_PDU_RX, + "conn 0x%p, skb 0x%p, len %u, flag 0x%lx.\n", + conn, skb, skb->len, cxgbi_skcb_flags(skb)); + + if (!iscsi_tcp_recv_segment_is_hdr(tcp_conn)) { + pr_info("conn 0x%p, skb 0x%p, not hdr.\n", conn, skb); + iscsi_conn_failure(conn, ISCSI_ERR_PROTO); + return -EIO; + } + + if (conn->hdrdgst_en && + cxgbi_skcb_test_flag(skb, SKCBF_RX_HCRC_ERR)) { + pr_info("conn 0x%p, skb 0x%p, hcrc.\n", conn, skb); + iscsi_conn_failure(conn, ISCSI_ERR_HDR_DGST); + return -EIO; + } + + return read_pdu_skb(conn, skb, 0, 0); +} + +static int skb_read_pdu_data(struct iscsi_conn *conn, struct sk_buff *lskb, + struct sk_buff *skb, unsigned int offset) +{ + struct iscsi_tcp_conn *tcp_conn = conn->dd_data; + bool offloaded = 0; + int opcode = tcp_conn->in.hdr->opcode & ISCSI_OPCODE_MASK; + + log_debug(1 << CXGBI_DBG_PDU_RX, + "conn 0x%p, skb 0x%p, len %u, flag 0x%lx.\n", + conn, skb, skb->len, cxgbi_skcb_flags(skb)); + + if (conn->datadgst_en && + cxgbi_skcb_test_flag(lskb, SKCBF_RX_DCRC_ERR)) { + pr_info("conn 0x%p, skb 0x%p, dcrc 0x%lx.\n", + conn, lskb, cxgbi_skcb_flags(lskb)); + iscsi_conn_failure(conn, ISCSI_ERR_DATA_DGST); + return -EIO; + } + + if (iscsi_tcp_recv_segment_is_hdr(tcp_conn)) + return 0; + + /* coalesced, add header digest length */ + if (lskb == skb && conn->hdrdgst_en) + offset += ISCSI_DIGEST_SIZE; + + if (cxgbi_skcb_test_flag(lskb, SKCBF_RX_DATA_DDPD)) + offloaded = 1; + + if (opcode == ISCSI_OP_SCSI_DATA_IN) + log_debug(1 << CXGBI_DBG_PDU_RX, + "skb 0x%p, op 0x%x, itt 0x%x, %u %s ddp'ed.\n", + skb, opcode, ntohl(tcp_conn->in.hdr->itt), + tcp_conn->in.datalen, offloaded ? "is" : "not"); + + return read_pdu_skb(conn, skb, offset, offloaded); +} + +static void csk_return_rx_credits(struct cxgbi_sock *csk, int copied) +{ + struct cxgbi_device *cdev = csk->cdev; + int must_send; + u32 credits; + + log_debug(1 << CXGBI_DBG_PDU_RX, + "csk 0x%p,%u,0x%lu,%u, seq %u, wup %u, thre %u, %u.\n", + csk, csk->state, csk->flags, csk->tid, csk->copied_seq, + csk->rcv_wup, cdev->rx_credit_thres, + cdev->rcv_win); + + if (csk->state != CTP_ESTABLISHED) + return; + + credits = csk->copied_seq - csk->rcv_wup; + if (unlikely(!credits)) + return; + if (unlikely(cdev->rx_credit_thres == 0)) + return; + + must_send = credits + 16384 >= cdev->rcv_win; + if (must_send || credits >= cdev->rx_credit_thres) + csk->rcv_wup += cdev->csk_send_rx_credits(csk, credits); +} + +void cxgbi_conn_pdu_ready(struct cxgbi_sock *csk) +{ + struct cxgbi_device *cdev = csk->cdev; + struct iscsi_conn *conn = csk->user_data; + struct sk_buff *skb; + unsigned int read = 0; + int err = 0; + + log_debug(1 << CXGBI_DBG_PDU_RX, + "csk 0x%p, conn 0x%p.\n", csk, conn); + + if (unlikely(!conn || conn->suspend_rx)) { + log_debug(1 << CXGBI_DBG_PDU_RX, + "csk 0x%p, conn 0x%p, id %d, suspend_rx %lu!\n", + csk, conn, conn ? conn->id : 0xFF, + conn ? conn->suspend_rx : 0xFF); + return; + } + + while (!err) { + skb = skb_peek(&csk->receive_queue); + if (!skb || + !(cxgbi_skcb_test_flag(skb, SKCBF_RX_STATUS))) { + if (skb) + log_debug(1 << CXGBI_DBG_PDU_RX, + "skb 0x%p, NOT ready 0x%lx.\n", + skb, cxgbi_skcb_flags(skb)); + break; + } + __skb_unlink(skb, &csk->receive_queue); + + read += cxgbi_skcb_rx_pdulen(skb); + log_debug(1 << CXGBI_DBG_PDU_RX, + "csk 0x%p, skb 0x%p,%u,f 0x%lx, pdu len %u.\n", + csk, skb, skb->len, cxgbi_skcb_flags(skb), + cxgbi_skcb_rx_pdulen(skb)); + + if (cxgbi_skcb_test_flag(skb, SKCBF_RX_COALESCED)) { + err = skb_read_pdu_bhs(conn, skb); + if (err < 0) { + pr_err("coalesced bhs, csk 0x%p, skb 0x%p,%u, " + "f 0x%lx, plen %u.\n", + csk, skb, skb->len, + cxgbi_skcb_flags(skb), + cxgbi_skcb_rx_pdulen(skb)); + goto skb_done; + } + err = skb_read_pdu_data(conn, skb, skb, + err + cdev->skb_rx_extra); + if (err < 0) + pr_err("coalesced data, csk 0x%p, skb 0x%p,%u, " + "f 0x%lx, plen %u.\n", + csk, skb, skb->len, + cxgbi_skcb_flags(skb), + cxgbi_skcb_rx_pdulen(skb)); + } else { + err = skb_read_pdu_bhs(conn, skb); + if (err < 0) { + pr_err("bhs, csk 0x%p, skb 0x%p,%u, " + "f 0x%lx, plen %u.\n", + csk, skb, skb->len, + cxgbi_skcb_flags(skb), + cxgbi_skcb_rx_pdulen(skb)); + goto skb_done; + } + + if (cxgbi_skcb_test_flag(skb, SKCBF_RX_DATA)) { + struct sk_buff *dskb; + + dskb = skb_peek(&csk->receive_queue); + if (!dskb) { + pr_err("csk 0x%p, skb 0x%p,%u, f 0x%lx," + " plen %u, NO data.\n", + csk, skb, skb->len, + cxgbi_skcb_flags(skb), + cxgbi_skcb_rx_pdulen(skb)); + err = -EIO; + goto skb_done; + } + __skb_unlink(dskb, &csk->receive_queue); + + err = skb_read_pdu_data(conn, skb, dskb, 0); + if (err < 0) + pr_err("data, csk 0x%p, skb 0x%p,%u, " + "f 0x%lx, plen %u, dskb 0x%p," + "%u.\n", + csk, skb, skb->len, + cxgbi_skcb_flags(skb), + cxgbi_skcb_rx_pdulen(skb), + dskb, dskb->len); + __kfree_skb(dskb); + } else + err = skb_read_pdu_data(conn, skb, skb, 0); + } +skb_done: + __kfree_skb(skb); + + if (err < 0) + break; + } + + log_debug(1 << CXGBI_DBG_PDU_RX, "csk 0x%p, read %u.\n", csk, read); + if (read) { + csk->copied_seq += read; + csk_return_rx_credits(csk, read); + conn->rxdata_octets += read; + } + + if (err < 0) { + pr_info("csk 0x%p, 0x%p, rx failed %d, read %u.\n", + csk, conn, err, read); + iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); + } +} +EXPORT_SYMBOL_GPL(cxgbi_conn_pdu_ready); + +static int sgl_seek_offset(struct scatterlist *sgl, unsigned int sgcnt, + unsigned int offset, unsigned int *off, + struct scatterlist **sgp) +{ + int i; + struct scatterlist *sg; + + for_each_sg(sgl, sg, sgcnt, i) { + if (offset < sg->length) { + *off = offset; + *sgp = sg; + return 0; + } + offset -= sg->length; + } + return -EFAULT; +} + +static int sgl_read_to_frags(struct scatterlist *sg, unsigned int sgoffset, + unsigned int dlen, skb_frag_t *frags, + int frag_max) +{ + unsigned int datalen = dlen; + unsigned int sglen = sg->length - sgoffset; + struct page *page = sg_page(sg); + int i; + + i = 0; + do { + unsigned int copy; + + if (!sglen) { + sg = sg_next(sg); + if (!sg) { + pr_warn("sg %d NULL, len %u/%u.\n", + i, datalen, dlen); + return -EINVAL; + } + sgoffset = 0; + sglen = sg->length; + page = sg_page(sg); + + } + copy = min(datalen, sglen); + if (i && page == frags[i - 1].page && + sgoffset + sg->offset == + frags[i - 1].page_offset + frags[i - 1].size) { + frags[i - 1].size += copy; + } else { + if (i >= frag_max) { + pr_warn("too many pages %u, dlen %u.\n", + frag_max, dlen); + return -EINVAL; + } + + frags[i].page = page; + frags[i].page_offset = sg->offset + sgoffset; + frags[i].size = copy; + i++; + } + datalen -= copy; + sgoffset += copy; + sglen -= copy; + } while (datalen); + + return i; +} + +int cxgbi_conn_alloc_pdu(struct iscsi_task *task, u8 opcode) +{ + struct iscsi_tcp_conn *tcp_conn = task->conn->dd_data; + struct cxgbi_conn *cconn = tcp_conn->dd_data; + struct cxgbi_device *cdev = cconn->chba->cdev; + struct iscsi_conn *conn = task->conn; + struct iscsi_tcp_task *tcp_task = task->dd_data; + struct cxgbi_task_data *tdata = iscsi_task_cxgbi_data(task); + struct scsi_cmnd *sc = task->sc; + int headroom = SKB_TX_ISCSI_PDU_HEADER_MAX; + + tcp_task->dd_data = tdata; + task->hdr = NULL; + + if (SKB_MAX_HEAD(cdev->skb_tx_rsvd) > (512 * MAX_SKB_FRAGS) && + (opcode == ISCSI_OP_SCSI_DATA_OUT || + (opcode == ISCSI_OP_SCSI_CMD && + (scsi_bidi_cmnd(sc) || sc->sc_data_direction == DMA_TO_DEVICE)))) + /* data could goes into skb head */ + headroom += min_t(unsigned int, + SKB_MAX_HEAD(cdev->skb_tx_rsvd), + conn->max_xmit_dlength); + + tdata->skb = alloc_skb(cdev->skb_tx_rsvd + headroom, GFP_ATOMIC); + if (!tdata->skb) { + pr_warn("alloc skb %u+%u, opcode 0x%x failed.\n", + cdev->skb_tx_rsvd, headroom, opcode); + return -ENOMEM; + } + + skb_reserve(tdata->skb, cdev->skb_tx_rsvd); + task->hdr = (struct iscsi_hdr *)tdata->skb->data; + task->hdr_max = SKB_TX_ISCSI_PDU_HEADER_MAX; /* BHS + AHS */ + + /* data_out uses scsi_cmd's itt */ + if (opcode != ISCSI_OP_SCSI_DATA_OUT) + task_reserve_itt(task, &task->hdr->itt); + + log_debug(1 << CXGBI_DBG_ISCSI | 1 << CXGBI_DBG_PDU_TX, + "task 0x%p, op 0x%x, skb 0x%p,%u+%u/%u, itt 0x%x.\n", + task, opcode, tdata->skb, cdev->skb_tx_rsvd, headroom, + conn->max_xmit_dlength, ntohl(task->hdr->itt)); + + return 0; +} +EXPORT_SYMBOL_GPL(cxgbi_conn_alloc_pdu); + +static inline void tx_skb_setmode(struct sk_buff *skb, int hcrc, int dcrc) +{ + u8 submode = 0; + + if (hcrc) + submode |= 1; + if (dcrc) + submode |= 2; + cxgbi_skcb_ulp_mode(skb) = (ULP2_MODE_ISCSI << 4) | submode; +} + +int cxgbi_conn_init_pdu(struct iscsi_task *task, unsigned int offset, + unsigned int count) +{ + struct iscsi_conn *conn = task->conn; + struct cxgbi_task_data *tdata = iscsi_task_cxgbi_data(task); + struct sk_buff *skb = tdata->skb; + unsigned int datalen = count; + int i, padlen = iscsi_padding(count); + struct page *pg; + + log_debug(1 << CXGBI_DBG_ISCSI | 1 << CXGBI_DBG_PDU_TX, + "task 0x%p,0x%p, skb 0x%p, 0x%x,0x%x,0x%x, %u+%u.\n", + task, task->sc, skb, (*skb->data) & ISCSI_OPCODE_MASK, + ntohl(task->cmdsn), ntohl(task->hdr->itt), offset, count); + + skb_put(skb, task->hdr_len); + tx_skb_setmode(skb, conn->hdrdgst_en, datalen ? conn->datadgst_en : 0); + if (!count) + return 0; + + if (task->sc) { + struct scsi_data_buffer *sdb = scsi_out(task->sc); + struct scatterlist *sg = NULL; + int err; + + tdata->offset = offset; + tdata->count = count; + err = sgl_seek_offset( + sdb->table.sgl, sdb->table.nents, + tdata->offset, &tdata->sgoffset, &sg); + if (err < 0) { + pr_warn("tpdu, sgl %u, bad offset %u/%u.\n", + sdb->table.nents, tdata->offset, sdb->length); + return err; + } + err = sgl_read_to_frags(sg, tdata->sgoffset, tdata->count, + tdata->frags, MAX_PDU_FRAGS); + if (err < 0) { + pr_warn("tpdu, sgl %u, bad offset %u + %u.\n", + sdb->table.nents, tdata->offset, tdata->count); + return err; + } + tdata->nr_frags = err; + + if (tdata->nr_frags > MAX_SKB_FRAGS || + (padlen && tdata->nr_frags == MAX_SKB_FRAGS)) { + char *dst = skb->data + task->hdr_len; + skb_frag_t *frag = tdata->frags; + + /* data fits in the skb's headroom */ + for (i = 0; i < tdata->nr_frags; i++, frag++) { + char *src = kmap_atomic(frag->page, + KM_SOFTIRQ0); + + memcpy(dst, src+frag->page_offset, frag->size); + dst += frag->size; + kunmap_atomic(src, KM_SOFTIRQ0); + } + if (padlen) { + memset(dst, 0, padlen); + padlen = 0; + } + skb_put(skb, count + padlen); + } else { + /* data fit into frag_list */ + for (i = 0; i < tdata->nr_frags; i++) + get_page(tdata->frags[i].page); + + memcpy(skb_shinfo(skb)->frags, tdata->frags, + sizeof(skb_frag_t) * tdata->nr_frags); + skb_shinfo(skb)->nr_frags = tdata->nr_frags; + skb->len += count; + skb->data_len += count; + skb->truesize += count; + } + + } else { + pg = virt_to_page(task->data); + + get_page(pg); + skb_fill_page_desc(skb, 0, pg, offset_in_page(task->data), + count); + skb->len += count; + skb->data_len += count; + skb->truesize += count; + } + + if (padlen) { + i = skb_shinfo(skb)->nr_frags; + skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags, + virt_to_page(padding), offset_in_page(padding), + padlen); + + skb->data_len += padlen; + skb->truesize += padlen; + skb->len += padlen; + } + + return 0; +} +EXPORT_SYMBOL_GPL(cxgbi_conn_init_pdu); + +int cxgbi_conn_xmit_pdu(struct iscsi_task *task) +{ + struct iscsi_tcp_conn *tcp_conn = task->conn->dd_data; + struct cxgbi_conn *cconn = tcp_conn->dd_data; + struct cxgbi_task_data *tdata = iscsi_task_cxgbi_data(task); + struct sk_buff *skb = tdata->skb; + unsigned int datalen; + int err; + + if (!skb) { + log_debug(1 << CXGBI_DBG_ISCSI | 1 << CXGBI_DBG_PDU_TX, + "task 0x%p, skb NULL.\n", task); + return 0; + } + + datalen = skb->data_len; + tdata->skb = NULL; + err = cxgbi_sock_send_pdus(cconn->cep->csk, skb); + if (err > 0) { + int pdulen = err; + + log_debug(1 << CXGBI_DBG_PDU_TX, + "task 0x%p,0x%p, skb 0x%p, len %u/%u, rv %d.\n", + task, task->sc, skb, skb->len, skb->data_len, err); + + if (task->conn->hdrdgst_en) + pdulen += ISCSI_DIGEST_SIZE; + + if (datalen && task->conn->datadgst_en) + pdulen += ISCSI_DIGEST_SIZE; + + task->conn->txdata_octets += pdulen; + return 0; + } + + if (err == -EAGAIN || err == -ENOBUFS) { + log_debug(1 << CXGBI_DBG_PDU_TX, + "task 0x%p, skb 0x%p, len %u/%u, %d EAGAIN.\n", + task, skb, skb->len, skb->data_len, err); + /* reset skb to send when we are called again */ + tdata->skb = skb; + return err; + } + + kfree_skb(skb); + log_debug(1 << CXGBI_DBG_ISCSI | 1 << CXGBI_DBG_PDU_TX, + "itt 0x%x, skb 0x%p, len %u/%u, xmit err %d.\n", + task->itt, skb, skb->len, skb->data_len, err); + iscsi_conn_printk(KERN_ERR, task->conn, "xmit err %d.\n", err); + iscsi_conn_failure(task->conn, ISCSI_ERR_XMIT_FAILED); + return err; +} +EXPORT_SYMBOL_GPL(cxgbi_conn_xmit_pdu); + +void cxgbi_cleanup_task(struct iscsi_task *task) +{ + struct cxgbi_task_data *tdata = iscsi_task_cxgbi_data(task); + + log_debug(1 << CXGBI_DBG_ISCSI, + "task 0x%p, skb 0x%p, itt 0x%x.\n", + task, tdata->skb, task->hdr_itt); + + /* never reached the xmit task callout */ + if (tdata->skb) + __kfree_skb(tdata->skb); + memset(tdata, 0, sizeof(*tdata)); + + task_release_itt(task, task->hdr_itt); + iscsi_tcp_cleanup_task(task); +} +EXPORT_SYMBOL_GPL(cxgbi_cleanup_task); + +void cxgbi_get_conn_stats(struct iscsi_cls_conn *cls_conn, + struct iscsi_stats *stats) +{ + struct iscsi_conn *conn = cls_conn->dd_data; + + stats->txdata_octets = conn->txdata_octets; + stats->rxdata_octets = conn->rxdata_octets; + stats->scsicmd_pdus = conn->scsicmd_pdus_cnt; + stats->dataout_pdus = conn->dataout_pdus_cnt; + stats->scsirsp_pdus = conn->scsirsp_pdus_cnt; + stats->datain_pdus = conn->datain_pdus_cnt; + stats->r2t_pdus = conn->r2t_pdus_cnt; + stats->tmfcmd_pdus = conn->tmfcmd_pdus_cnt; + stats->tmfrsp_pdus = conn->tmfrsp_pdus_cnt; + stats->digest_err = 0; + stats->timeout_err = 0; + stats->custom_length = 1; + strcpy(stats->custom[0].desc, "eh_abort_cnt"); + stats->custom[0].value = conn->eh_abort_cnt; +} +EXPORT_SYMBOL_GPL(cxgbi_get_conn_stats); + +static int cxgbi_conn_max_xmit_dlength(struct iscsi_conn *conn) +{ + struct iscsi_tcp_conn *tcp_conn = conn->dd_data; + struct cxgbi_conn *cconn = tcp_conn->dd_data; + struct cxgbi_device *cdev = cconn->chba->cdev; + unsigned int headroom = SKB_MAX_HEAD(cdev->skb_tx_rsvd); + unsigned int max_def = 512 * MAX_SKB_FRAGS; + unsigned int max = max(max_def, headroom); + + max = min(cconn->chba->cdev->tx_max_size, max); + if (conn->max_xmit_dlength) + conn->max_xmit_dlength = min(conn->max_xmit_dlength, max); + else + conn->max_xmit_dlength = max; + cxgbi_align_pdu_size(conn->max_xmit_dlength); + + return 0; +} + +static int cxgbi_conn_max_recv_dlength(struct iscsi_conn *conn) +{ + struct iscsi_tcp_conn *tcp_conn = conn->dd_data; + struct cxgbi_conn *cconn = tcp_conn->dd_data; + unsigned int max = cconn->chba->cdev->rx_max_size; + + cxgbi_align_pdu_size(max); + + if (conn->max_recv_dlength) { + if (conn->max_recv_dlength > max) { + pr_err("MaxRecvDataSegmentLength %u > %u.\n", + conn->max_recv_dlength, max); + return -EINVAL; + } + conn->max_recv_dlength = min(conn->max_recv_dlength, max); + cxgbi_align_pdu_size(conn->max_recv_dlength); + } else + conn->max_recv_dlength = max; + + return 0; +} + +int cxgbi_set_conn_param(struct iscsi_cls_conn *cls_conn, + enum iscsi_param param, char *buf, int buflen) +{ + struct iscsi_conn *conn = cls_conn->dd_data; + struct iscsi_session *session = conn->session; + struct iscsi_tcp_conn *tcp_conn = conn->dd_data; + struct cxgbi_conn *cconn = tcp_conn->dd_data; + struct cxgbi_sock *csk = cconn->cep->csk; + int value, err = 0; + + log_debug(1 << CXGBI_DBG_ISCSI, + "cls_conn 0x%p, param %d, buf(%d) %s.\n", + cls_conn, param, buflen, buf); + + switch (param) { + case ISCSI_PARAM_HDRDGST_EN: + err = iscsi_set_param(cls_conn, param, buf, buflen); + if (!err && conn->hdrdgst_en) + err = csk->cdev->csk_ddp_setup_digest(csk, csk->tid, + conn->hdrdgst_en, + conn->datadgst_en, 0); + break; + case ISCSI_PARAM_DATADGST_EN: + err = iscsi_set_param(cls_conn, param, buf, buflen); + if (!err && conn->datadgst_en) + err = csk->cdev->csk_ddp_setup_digest(csk, csk->tid, + conn->hdrdgst_en, + conn->datadgst_en, 0); + break; + case ISCSI_PARAM_MAX_R2T: + sscanf(buf, "%d", &value); + if (value <= 0 || !is_power_of_2(value)) + return -EINVAL; + if (session->max_r2t == value) + break; + iscsi_tcp_r2tpool_free(session); + err = iscsi_set_param(cls_conn, param, buf, buflen); + if (!err && iscsi_tcp_r2tpool_alloc(session)) + return -ENOMEM; + case ISCSI_PARAM_MAX_RECV_DLENGTH: + err = iscsi_set_param(cls_conn, param, buf, buflen); + if (!err) + err = cxgbi_conn_max_recv_dlength(conn); + break; + case ISCSI_PARAM_MAX_XMIT_DLENGTH: + err = iscsi_set_param(cls_conn, param, buf, buflen); + if (!err) + err = cxgbi_conn_max_xmit_dlength(conn); + break; + default: + return iscsi_set_param(cls_conn, param, buf, buflen); + } + return err; +} +EXPORT_SYMBOL_GPL(cxgbi_set_conn_param); + +int cxgbi_get_conn_param(struct iscsi_cls_conn *cls_conn, + enum iscsi_param param, char *buf) +{ + struct iscsi_conn *iconn = cls_conn->dd_data; + int len; + + log_debug(1 << CXGBI_DBG_ISCSI, + "cls_conn 0x%p, param %d.\n", cls_conn, param); + + switch (param) { + case ISCSI_PARAM_CONN_PORT: + spin_lock_bh(&iconn->session->lock); + len = sprintf(buf, "%hu\n", iconn->portal_port); + spin_unlock_bh(&iconn->session->lock); + break; + case ISCSI_PARAM_CONN_ADDRESS: + spin_lock_bh(&iconn->session->lock); + len = sprintf(buf, "%s\n", iconn->portal_address); + spin_unlock_bh(&iconn->session->lock); + break; + default: + return iscsi_conn_get_param(cls_conn, param, buf); + } + return len; +} +EXPORT_SYMBOL_GPL(cxgbi_get_conn_param); + +struct iscsi_cls_conn * +cxgbi_create_conn(struct iscsi_cls_session *cls_session, u32 cid) +{ + struct iscsi_cls_conn *cls_conn; + struct iscsi_conn *conn; + struct iscsi_tcp_conn *tcp_conn; + struct cxgbi_conn *cconn; + + cls_conn = iscsi_tcp_conn_setup(cls_session, sizeof(*cconn), cid); + if (!cls_conn) + return NULL; + + conn = cls_conn->dd_data; + tcp_conn = conn->dd_data; + cconn = tcp_conn->dd_data; + cconn->iconn = conn; + + log_debug(1 << CXGBI_DBG_ISCSI, + "cid %u(0x%x), cls 0x%p,0x%p, conn 0x%p,0x%p,0x%p.\n", + cid, cid, cls_session, cls_conn, conn, tcp_conn, cconn); + + return cls_conn; +} +EXPORT_SYMBOL_GPL(cxgbi_create_conn); + +int cxgbi_bind_conn(struct iscsi_cls_session *cls_session, + struct iscsi_cls_conn *cls_conn, + u64 transport_eph, int is_leading) +{ + struct iscsi_conn *conn = cls_conn->dd_data; + struct iscsi_tcp_conn *tcp_conn = conn->dd_data; + struct cxgbi_conn *cconn = tcp_conn->dd_data; + struct iscsi_endpoint *ep; + struct cxgbi_endpoint *cep; + struct cxgbi_sock *csk; + int err; + + ep = iscsi_lookup_endpoint(transport_eph); + if (!ep) + return -EINVAL; + + /* setup ddp pagesize */ + cep = ep->dd_data; + csk = cep->csk; + err = csk->cdev->csk_ddp_setup_pgidx(csk, csk->tid, page_idx, 0); + if (err < 0) + return err; + + err = iscsi_conn_bind(cls_session, cls_conn, is_leading); + if (err) + return -EINVAL; + + /* calculate the tag idx bits needed for this conn based on cmds_max */ + cconn->task_idx_bits = (__ilog2_u32(conn->session->cmds_max - 1)) + 1; + + write_lock_bh(&csk->callback_lock); + csk->user_data = conn; + cconn->chba = cep->chba; + cconn->cep = cep; + cep->cconn = cconn; + write_unlock_bh(&csk->callback_lock); + + cxgbi_conn_max_xmit_dlength(conn); + cxgbi_conn_max_recv_dlength(conn); + + spin_lock_bh(&conn->session->lock); + sprintf(conn->portal_address, "%pI4", &csk->daddr.sin_addr.s_addr); + conn->portal_port = ntohs(csk->daddr.sin_port); + spin_unlock_bh(&conn->session->lock); + + log_debug(1 << CXGBI_DBG_ISCSI, + "cls 0x%p,0x%p, ep 0x%p, cconn 0x%p, csk 0x%p.\n", + cls_session, cls_conn, ep, cconn, csk); + /* init recv engine */ + iscsi_tcp_hdr_recv_prep(tcp_conn); + + return 0; +} +EXPORT_SYMBOL_GPL(cxgbi_bind_conn); + +struct iscsi_cls_session *cxgbi_create_session(struct iscsi_endpoint *ep, + u16 cmds_max, u16 qdepth, + u32 initial_cmdsn) +{ + struct cxgbi_endpoint *cep; + struct cxgbi_hba *chba; + struct Scsi_Host *shost; + struct iscsi_cls_session *cls_session; + struct iscsi_session *session; + + if (!ep) { + pr_err("missing endpoint.\n"); + return NULL; + } + + cep = ep->dd_data; + chba = cep->chba; + shost = chba->shost; + + BUG_ON(chba != iscsi_host_priv(shost)); + + cls_session = iscsi_session_setup(chba->cdev->itp, shost, + cmds_max, 0, + sizeof(struct iscsi_tcp_task) + + sizeof(struct cxgbi_task_data), + initial_cmdsn, ISCSI_MAX_TARGET); + if (!cls_session) + return NULL; + + session = cls_session->dd_data; + if (iscsi_tcp_r2tpool_alloc(session)) + goto remove_session; + + log_debug(1 << CXGBI_DBG_ISCSI, + "ep 0x%p, cls sess 0x%p.\n", ep, cls_session); + return cls_session; + +remove_session: + iscsi_session_teardown(cls_session); + return NULL; +} +EXPORT_SYMBOL_GPL(cxgbi_create_session); + +void cxgbi_destroy_session(struct iscsi_cls_session *cls_session) +{ + log_debug(1 << CXGBI_DBG_ISCSI, + "cls sess 0x%p.\n", cls_session); + + iscsi_tcp_r2tpool_free(cls_session->dd_data); + iscsi_session_teardown(cls_session); +} +EXPORT_SYMBOL_GPL(cxgbi_destroy_session); + +int cxgbi_set_host_param(struct Scsi_Host *shost, enum iscsi_host_param param, + char *buf, int buflen) +{ + struct cxgbi_hba *chba = iscsi_host_priv(shost); + + if (!chba->ndev) { + shost_printk(KERN_ERR, shost, "Could not get host param. " + "netdev for host not set.\n"); + return -ENODEV; + } + + log_debug(1 << CXGBI_DBG_ISCSI, + "shost 0x%p, hba 0x%p,%s, param %d, buf(%d) %s.\n", + shost, chba, chba->ndev->name, param, buflen, buf); + + switch (param) { + case ISCSI_HOST_PARAM_IPADDRESS: + { + __be32 addr = in_aton(buf); + log_debug(1 << CXGBI_DBG_ISCSI, + "hba %s, req. ipv4 %pI4.\n", chba->ndev->name, &addr); + cxgbi_set_iscsi_ipv4(chba, addr); + return 0; + } + case ISCSI_HOST_PARAM_HWADDRESS: + case ISCSI_HOST_PARAM_NETDEV_NAME: + return 0; + default: + return iscsi_host_set_param(shost, param, buf, buflen); + } +} +EXPORT_SYMBOL_GPL(cxgbi_set_host_param); + +int cxgbi_get_host_param(struct Scsi_Host *shost, enum iscsi_host_param param, + char *buf) +{ + struct cxgbi_hba *chba = iscsi_host_priv(shost); + int len = 0; + + if (!chba->ndev) { + shost_printk(KERN_ERR, shost, "Could not get host param. " + "netdev for host not set.\n"); + return -ENODEV; + } + + log_debug(1 << CXGBI_DBG_ISCSI, + "shost 0x%p, hba 0x%p,%s, param %d.\n", + shost, chba, chba->ndev->name, param); + + switch (param) { + case ISCSI_HOST_PARAM_HWADDRESS: + len = sysfs_format_mac(buf, chba->ndev->dev_addr, 6); + break; + case ISCSI_HOST_PARAM_NETDEV_NAME: + len = sprintf(buf, "%s\n", chba->ndev->name); + break; + case ISCSI_HOST_PARAM_IPADDRESS: + { + __be32 addr; + + addr = cxgbi_get_iscsi_ipv4(chba); + len = sprintf(buf, "%pI4", &addr); + log_debug(1 << CXGBI_DBG_ISCSI, + "hba %s, ipv4 %pI4.\n", chba->ndev->name, &addr); + break; + } + default: + return iscsi_host_get_param(shost, param, buf); + } + + return len; +} +EXPORT_SYMBOL_GPL(cxgbi_get_host_param); + +struct iscsi_endpoint *cxgbi_ep_connect(struct Scsi_Host *shost, + struct sockaddr *dst_addr, + int non_blocking) +{ + struct iscsi_endpoint *ep; + struct cxgbi_endpoint *cep; + struct cxgbi_hba *hba = NULL; + struct cxgbi_sock *csk; + int err = -EINVAL; + + log_debug(1 << CXGBI_DBG_ISCSI | 1 << CXGBI_DBG_SOCK, + "shost 0x%p, non_blocking %d, dst_addr 0x%p.\n", + shost, non_blocking, dst_addr); + + if (shost) { + hba = iscsi_host_priv(shost); + if (!hba) { + pr_info("shost 0x%p, priv NULL.\n", shost); + goto err_out; + } + } + + csk = cxgbi_check_route(dst_addr); + if (IS_ERR(csk)) + return (struct iscsi_endpoint *)csk; + cxgbi_sock_get(csk); + + if (!hba) + hba = csk->cdev->hbas[csk->port_id]; + else if (hba != csk->cdev->hbas[csk->port_id]) { + pr_info("Could not connect through requested host %u" + "hba 0x%p != 0x%p (%u).\n", + shost->host_no, hba, + csk->cdev->hbas[csk->port_id], csk->port_id); + err = -ENOSPC; + goto release_conn; + } + + err = sock_get_port(csk); + if (err) + goto release_conn; + + cxgbi_sock_set_state(csk, CTP_CONNECTING); + err = csk->cdev->csk_init_act_open(csk); + if (err) + goto release_conn; + + if (cxgbi_sock_is_closing(csk)) { + err = -ENOSPC; + pr_info("csk 0x%p is closing.\n", csk); + goto release_conn; + } + + ep = iscsi_create_endpoint(sizeof(*cep)); + if (!ep) { + err = -ENOMEM; + pr_info("iscsi alloc ep, OOM.\n"); + goto release_conn; + } + + cep = ep->dd_data; + cep->csk = csk; + cep->chba = hba; + + log_debug(1 << CXGBI_DBG_ISCSI | 1 << CXGBI_DBG_SOCK, + "ep 0x%p, cep 0x%p, csk 0x%p, hba 0x%p,%s.\n", + ep, cep, csk, hba, hba->ndev->name); + return ep; + +release_conn: + cxgbi_sock_put(csk); + cxgbi_sock_closed(csk); +err_out: + return ERR_PTR(err); +} +EXPORT_SYMBOL_GPL(cxgbi_ep_connect); + +int cxgbi_ep_poll(struct iscsi_endpoint *ep, int timeout_ms) +{ + struct cxgbi_endpoint *cep = ep->dd_data; + struct cxgbi_sock *csk = cep->csk; + + if (!cxgbi_sock_is_established(csk)) + return 0; + return 1; +} +EXPORT_SYMBOL_GPL(cxgbi_ep_poll); + +void cxgbi_ep_disconnect(struct iscsi_endpoint *ep) +{ + struct cxgbi_endpoint *cep = ep->dd_data; + struct cxgbi_conn *cconn = cep->cconn; + struct cxgbi_sock *csk = cep->csk; + + log_debug(1 << CXGBI_DBG_ISCSI | 1 << CXGBI_DBG_SOCK, + "ep 0x%p, cep 0x%p, cconn 0x%p, csk 0x%p,%u,0x%lx.\n", + ep, cep, cconn, csk, csk->state, csk->flags); + + if (cconn && cconn->iconn) { + iscsi_suspend_tx(cconn->iconn); + write_lock_bh(&csk->callback_lock); + cep->csk->user_data = NULL; + cconn->cep = NULL; + write_unlock_bh(&csk->callback_lock); + } + iscsi_destroy_endpoint(ep); + + if (likely(csk->state >= CTP_ESTABLISHED)) + need_active_close(csk); + else + cxgbi_sock_closed(csk); + + cxgbi_sock_put(csk); +} +EXPORT_SYMBOL_GPL(cxgbi_ep_disconnect); + +int cxgbi_iscsi_init(struct iscsi_transport *itp, + struct scsi_transport_template **stt) +{ + *stt = iscsi_register_transport(itp); + if (*stt == NULL) { + pr_err("unable to register %s transport 0x%p.\n", + itp->name, itp); + return -ENODEV; + } + log_debug(1 << CXGBI_DBG_ISCSI, + "%s, registered iscsi transport 0x%p.\n", + itp->name, stt); + return 0; +} +EXPORT_SYMBOL_GPL(cxgbi_iscsi_init); + +void cxgbi_iscsi_cleanup(struct iscsi_transport *itp, + struct scsi_transport_template **stt) +{ + if (*stt) { + log_debug(1 << CXGBI_DBG_ISCSI, + "de-register transport 0x%p, %s, stt 0x%p.\n", + itp, itp->name, *stt); + *stt = NULL; + iscsi_unregister_transport(itp); + } +} +EXPORT_SYMBOL_GPL(cxgbi_iscsi_cleanup); + +static int __init libcxgbi_init_module(void) +{ + sw_tag_idx_bits = (__ilog2_u32(ISCSI_ITT_MASK)) + 1; + sw_tag_age_bits = (__ilog2_u32(ISCSI_AGE_MASK)) + 1; + + pr_info("tag itt 0x%x, %u bits, age 0x%x, %u bits.\n", + ISCSI_ITT_MASK, sw_tag_idx_bits, + ISCSI_AGE_MASK, sw_tag_age_bits); + + ddp_setup_host_page_size(); + return 0; +} + +static void __exit libcxgbi_exit_module(void) +{ + cxgbi_device_unregister_all(0xFF); + return; +} + +module_init(libcxgbi_init_module); +module_exit(libcxgbi_exit_module); diff --git a/drivers/scsi/cxgbi/libcxgbi.h b/drivers/scsi/cxgbi/libcxgbi.h new file mode 100644 index 000000000000..c57d59db000c --- /dev/null +++ b/drivers/scsi/cxgbi/libcxgbi.h @@ -0,0 +1,745 @@ +/* + * libcxgbi.h: Chelsio common library for T3/T4 iSCSI driver. + * + * Copyright (c) 2010 Chelsio Communications, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation. + * + * Written by: Karen Xie (kxie@chelsio.com) + * Written by: Rakesh Ranjan (rranjan@chelsio.com) + */ + +#ifndef __LIBCXGBI_H__ +#define __LIBCXGBI_H__ + +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/types.h> +#include <linux/debugfs.h> +#include <linux/list.h> +#include <linux/netdevice.h> +#include <linux/if_vlan.h> +#include <linux/scatterlist.h> +#include <linux/skbuff.h> +#include <linux/vmalloc.h> +#include <scsi/scsi_device.h> +#include <scsi/libiscsi_tcp.h> + +enum cxgbi_dbg_flag { + CXGBI_DBG_ISCSI, + CXGBI_DBG_DDP, + CXGBI_DBG_TOE, + CXGBI_DBG_SOCK, + + CXGBI_DBG_PDU_TX, + CXGBI_DBG_PDU_RX, + CXGBI_DBG_DEV, +}; + +#define log_debug(level, fmt, ...) \ + do { \ + if (dbg_level & (level)) \ + pr_info(fmt, ##__VA_ARGS__); \ + } while (0) + +/* max. connections per adapter */ +#define CXGBI_MAX_CONN 16384 + +/* always allocate rooms for AHS */ +#define SKB_TX_ISCSI_PDU_HEADER_MAX \ + (sizeof(struct iscsi_hdr) + ISCSI_MAX_AHS_SIZE) + +#define ISCSI_PDU_NONPAYLOAD_LEN 312 /* bhs(48) + ahs(256) + digest(8)*/ + +/* + * align pdu size to multiple of 512 for better performance + */ +#define cxgbi_align_pdu_size(n) do { n = (n) & (~511); } while (0) + +#define ULP2_MODE_ISCSI 2 + +#define ULP2_MAX_PKT_SIZE 16224 +#define ULP2_MAX_PDU_PAYLOAD \ + (ULP2_MAX_PKT_SIZE - ISCSI_PDU_NONPAYLOAD_LEN) + +/* + * For iscsi connections HW may inserts digest bytes into the pdu. Those digest + * bytes are not sent by the host but are part of the TCP payload and therefore + * consume TCP sequence space. + */ +static const unsigned int ulp2_extra_len[] = { 0, 4, 4, 8 }; +static inline unsigned int cxgbi_ulp_extra_len(int submode) +{ + return ulp2_extra_len[submode & 3]; +} + +/* + * struct pagepod_hdr, pagepod - pagepod format + */ + +#define CPL_RX_DDP_STATUS_DDP_SHIFT 16 /* ddp'able */ +#define CPL_RX_DDP_STATUS_PAD_SHIFT 19 /* pad error */ +#define CPL_RX_DDP_STATUS_HCRC_SHIFT 20 /* hcrc error */ +#define CPL_RX_DDP_STATUS_DCRC_SHIFT 21 /* dcrc error */ + +struct cxgbi_pagepod_hdr { + u32 vld_tid; + u32 pgsz_tag_clr; + u32 max_offset; + u32 page_offset; + u64 rsvd; +}; + +#define PPOD_PAGES_MAX 4 +struct cxgbi_pagepod { + struct cxgbi_pagepod_hdr hdr; + u64 addr[PPOD_PAGES_MAX + 1]; +}; + +struct cxgbi_tag_format { + unsigned char sw_bits; + unsigned char rsvd_bits; + unsigned char rsvd_shift; + unsigned char filler[1]; + u32 rsvd_mask; +}; + +struct cxgbi_gather_list { + unsigned int tag; + unsigned int length; + unsigned int offset; + unsigned int nelem; + struct page **pages; + dma_addr_t phys_addr[0]; +}; + +struct cxgbi_ddp_info { + struct kref refcnt; + struct cxgbi_device *cdev; + struct pci_dev *pdev; + unsigned int max_txsz; + unsigned int max_rxsz; + unsigned int llimit; + unsigned int ulimit; + unsigned int nppods; + unsigned int idx_last; + unsigned char idx_bits; + unsigned char filler[3]; + unsigned int idx_mask; + unsigned int rsvd_tag_mask; + spinlock_t map_lock; + struct cxgbi_gather_list **gl_map; + struct sk_buff **gl_skb; +}; + +#define DDP_PGIDX_MAX 4 +#define DDP_THRESHOLD 2048 + +#define PPOD_PAGES_SHIFT 2 /* 4 pages per pod */ + +#define PPOD_SIZE sizeof(struct cxgbi_pagepod) /* 64 */ +#define PPOD_SIZE_SHIFT 6 + +#define ULPMEM_DSGL_MAX_NPPODS 16 /* 1024/PPOD_SIZE */ +#define ULPMEM_IDATA_MAX_NPPODS 4 /* 256/PPOD_SIZE */ +#define PCIE_MEMWIN_MAX_NPPODS 16 /* 1024/PPOD_SIZE */ + +#define PPOD_COLOR_SHIFT 0 +#define PPOD_COLOR(x) ((x) << PPOD_COLOR_SHIFT) + +#define PPOD_IDX_SHIFT 6 +#define PPOD_IDX_MAX_SIZE 24 + +#define PPOD_TID_SHIFT 0 +#define PPOD_TID(x) ((x) << PPOD_TID_SHIFT) + +#define PPOD_TAG_SHIFT 6 +#define PPOD_TAG(x) ((x) << PPOD_TAG_SHIFT) + +#define PPOD_VALID_SHIFT 24 +#define PPOD_VALID(x) ((x) << PPOD_VALID_SHIFT) +#define PPOD_VALID_FLAG PPOD_VALID(1U) + +/* + * sge_opaque_hdr - + * Opaque version of structure the SGE stores at skb->head of TX_DATA packets + * and for which we must reserve space. + */ +struct sge_opaque_hdr { + void *dev; + dma_addr_t addr[MAX_SKB_FRAGS + 1]; +}; + +struct cxgbi_sock { + struct cxgbi_device *cdev; + + int tid; + int atid; + unsigned long flags; + unsigned int mtu; + unsigned short rss_qid; + unsigned short txq_idx; + unsigned short advmss; + unsigned int tx_chan; + unsigned int rx_chan; + unsigned int mss_idx; + unsigned int smac_idx; + unsigned char port_id; + int wr_max_cred; + int wr_cred; + int wr_una_cred; + unsigned char hcrc_len; + unsigned char dcrc_len; + + void *l2t; + struct sk_buff *wr_pending_head; + struct sk_buff *wr_pending_tail; + struct sk_buff *cpl_close; + struct sk_buff *cpl_abort_req; + struct sk_buff *cpl_abort_rpl; + struct sk_buff *skb_ulp_lhdr; + spinlock_t lock; + struct kref refcnt; + unsigned int state; + struct sockaddr_in saddr; + struct sockaddr_in daddr; + struct dst_entry *dst; + struct sk_buff_head receive_queue; + struct sk_buff_head write_queue; + struct timer_list retry_timer; + int err; + rwlock_t callback_lock; + void *user_data; + + u32 rcv_nxt; + u32 copied_seq; + u32 rcv_wup; + u32 snd_nxt; + u32 snd_una; + u32 write_seq; +}; + +/* + * connection states + */ +enum cxgbi_sock_states{ + CTP_CLOSED, + CTP_CONNECTING, + CTP_ACTIVE_OPEN, + CTP_ESTABLISHED, + CTP_ACTIVE_CLOSE, + CTP_PASSIVE_CLOSE, + CTP_CLOSE_WAIT_1, + CTP_CLOSE_WAIT_2, + CTP_ABORTING, +}; + +/* + * Connection flags -- many to track some close related events. + */ +enum cxgbi_sock_flags { + CTPF_ABORT_RPL_RCVD, /*received one ABORT_RPL_RSS message */ + CTPF_ABORT_REQ_RCVD, /*received one ABORT_REQ_RSS message */ + CTPF_ABORT_RPL_PENDING, /* expecting an abort reply */ + CTPF_TX_DATA_SENT, /* already sent a TX_DATA WR */ + CTPF_ACTIVE_CLOSE_NEEDED,/* need to be closed */ + CTPF_HAS_ATID, /* reserved atid */ + CTPF_HAS_TID, /* reserved hw tid */ + CTPF_OFFLOAD_DOWN, /* offload function off */ +}; + +struct cxgbi_skb_rx_cb { + __u32 ddigest; + __u32 pdulen; +}; + +struct cxgbi_skb_tx_cb { + void *l2t; + struct sk_buff *wr_next; +}; + +enum cxgbi_skcb_flags { + SKCBF_TX_NEED_HDR, /* packet needs a header */ + SKCBF_RX_COALESCED, /* received whole pdu */ + SKCBF_RX_HDR, /* recieved pdu header */ + SKCBF_RX_DATA, /* recieved pdu payload */ + SKCBF_RX_STATUS, /* recieved ddp status */ + SKCBF_RX_DATA_DDPD, /* pdu payload ddp'd */ + SKCBF_RX_HCRC_ERR, /* header digest error */ + SKCBF_RX_DCRC_ERR, /* data digest error */ + SKCBF_RX_PAD_ERR, /* padding byte error */ +}; + +struct cxgbi_skb_cb { + unsigned char ulp_mode; + unsigned long flags; + unsigned int seq; + union { + struct cxgbi_skb_rx_cb rx; + struct cxgbi_skb_tx_cb tx; + }; +}; + +#define CXGBI_SKB_CB(skb) ((struct cxgbi_skb_cb *)&((skb)->cb[0])) +#define cxgbi_skcb_flags(skb) (CXGBI_SKB_CB(skb)->flags) +#define cxgbi_skcb_ulp_mode(skb) (CXGBI_SKB_CB(skb)->ulp_mode) +#define cxgbi_skcb_tcp_seq(skb) (CXGBI_SKB_CB(skb)->seq) +#define cxgbi_skcb_rx_ddigest(skb) (CXGBI_SKB_CB(skb)->rx.ddigest) +#define cxgbi_skcb_rx_pdulen(skb) (CXGBI_SKB_CB(skb)->rx.pdulen) +#define cxgbi_skcb_tx_wr_next(skb) (CXGBI_SKB_CB(skb)->tx.wr_next) + +static inline void cxgbi_skcb_set_flag(struct sk_buff *skb, + enum cxgbi_skcb_flags flag) +{ + __set_bit(flag, &(cxgbi_skcb_flags(skb))); +} + +static inline void cxgbi_skcb_clear_flag(struct sk_buff *skb, + enum cxgbi_skcb_flags flag) +{ + __clear_bit(flag, &(cxgbi_skcb_flags(skb))); +} + +static inline int cxgbi_skcb_test_flag(struct sk_buff *skb, + enum cxgbi_skcb_flags flag) +{ + return test_bit(flag, &(cxgbi_skcb_flags(skb))); +} + +static inline void cxgbi_sock_set_flag(struct cxgbi_sock *csk, + enum cxgbi_sock_flags flag) +{ + __set_bit(flag, &csk->flags); + log_debug(1 << CXGBI_DBG_SOCK, + "csk 0x%p,%u,0x%lx, bit %d.\n", + csk, csk->state, csk->flags, flag); +} + +static inline void cxgbi_sock_clear_flag(struct cxgbi_sock *csk, + enum cxgbi_sock_flags flag) +{ + __clear_bit(flag, &csk->flags); + log_debug(1 << CXGBI_DBG_SOCK, + "csk 0x%p,%u,0x%lx, bit %d.\n", + csk, csk->state, csk->flags, flag); +} + +static inline int cxgbi_sock_flag(struct cxgbi_sock *csk, + enum cxgbi_sock_flags flag) +{ + if (csk == NULL) + return 0; + return test_bit(flag, &csk->flags); +} + +static inline void cxgbi_sock_set_state(struct cxgbi_sock *csk, int state) +{ + log_debug(1 << CXGBI_DBG_SOCK, + "csk 0x%p,%u,0x%lx, state -> %u.\n", + csk, csk->state, csk->flags, state); + csk->state = state; +} + +static inline void cxgbi_sock_free(struct kref *kref) +{ + struct cxgbi_sock *csk = container_of(kref, + struct cxgbi_sock, + refcnt); + if (csk) { + log_debug(1 << CXGBI_DBG_SOCK, + "free csk 0x%p, state %u, flags 0x%lx\n", + csk, csk->state, csk->flags); + kfree(csk); + } +} + +static inline void __cxgbi_sock_put(const char *fn, struct cxgbi_sock *csk) +{ + log_debug(1 << CXGBI_DBG_SOCK, + "%s, put csk 0x%p, ref %u-1.\n", + fn, csk, atomic_read(&csk->refcnt.refcount)); + kref_put(&csk->refcnt, cxgbi_sock_free); +} +#define cxgbi_sock_put(csk) __cxgbi_sock_put(__func__, csk) + +static inline void __cxgbi_sock_get(const char *fn, struct cxgbi_sock *csk) +{ + log_debug(1 << CXGBI_DBG_SOCK, + "%s, get csk 0x%p, ref %u+1.\n", + fn, csk, atomic_read(&csk->refcnt.refcount)); + kref_get(&csk->refcnt); +} +#define cxgbi_sock_get(csk) __cxgbi_sock_get(__func__, csk) + +static inline int cxgbi_sock_is_closing(struct cxgbi_sock *csk) +{ + return csk->state >= CTP_ACTIVE_CLOSE; +} + +static inline int cxgbi_sock_is_established(struct cxgbi_sock *csk) +{ + return csk->state == CTP_ESTABLISHED; +} + +static inline void cxgbi_sock_purge_write_queue(struct cxgbi_sock *csk) +{ + struct sk_buff *skb; + + while ((skb = __skb_dequeue(&csk->write_queue))) + __kfree_skb(skb); +} + +static inline unsigned int cxgbi_sock_compute_wscale(unsigned int win) +{ + unsigned int wscale = 0; + + while (wscale < 14 && (65535 << wscale) < win) + wscale++; + return wscale; +} + +static inline struct sk_buff *alloc_wr(int wrlen, int dlen, gfp_t gfp) +{ + struct sk_buff *skb = alloc_skb(wrlen + dlen, gfp); + + if (skb) { + __skb_put(skb, wrlen); + memset(skb->head, 0, wrlen + dlen); + } else + pr_info("alloc cpl wr skb %u+%u, OOM.\n", wrlen, dlen); + return skb; +} + + +/* + * The number of WRs needed for an skb depends on the number of fragments + * in the skb and whether it has any payload in its main body. This maps the + * length of the gather list represented by an skb into the # of necessary WRs. + * The extra two fragments are for iscsi bhs and payload padding. + */ +#define SKB_WR_LIST_SIZE (MAX_SKB_FRAGS + 2) + +static inline void cxgbi_sock_reset_wr_list(struct cxgbi_sock *csk) +{ + csk->wr_pending_head = csk->wr_pending_tail = NULL; +} + +static inline void cxgbi_sock_enqueue_wr(struct cxgbi_sock *csk, + struct sk_buff *skb) +{ + cxgbi_skcb_tx_wr_next(skb) = NULL; + /* + * We want to take an extra reference since both us and the driver + * need to free the packet before it's really freed. We know there's + * just one user currently so we use atomic_set rather than skb_get + * to avoid the atomic op. + */ + atomic_set(&skb->users, 2); + + if (!csk->wr_pending_head) + csk->wr_pending_head = skb; + else + cxgbi_skcb_tx_wr_next(csk->wr_pending_tail) = skb; + csk->wr_pending_tail = skb; +} + +static inline int cxgbi_sock_count_pending_wrs(const struct cxgbi_sock *csk) +{ + int n = 0; + const struct sk_buff *skb = csk->wr_pending_head; + + while (skb) { + n += skb->csum; + skb = cxgbi_skcb_tx_wr_next(skb); + } + return n; +} + +static inline struct sk_buff *cxgbi_sock_peek_wr(const struct cxgbi_sock *csk) +{ + return csk->wr_pending_head; +} + +static inline struct sk_buff *cxgbi_sock_dequeue_wr(struct cxgbi_sock *csk) +{ + struct sk_buff *skb = csk->wr_pending_head; + + if (likely(skb)) { + csk->wr_pending_head = cxgbi_skcb_tx_wr_next(skb); + cxgbi_skcb_tx_wr_next(skb) = NULL; + } + return skb; +} + +void cxgbi_sock_check_wr_invariants(const struct cxgbi_sock *); +void cxgbi_sock_purge_wr_queue(struct cxgbi_sock *); +void cxgbi_sock_skb_entail(struct cxgbi_sock *, struct sk_buff *); +void cxgbi_sock_fail_act_open(struct cxgbi_sock *, int); +void cxgbi_sock_act_open_req_arp_failure(void *, struct sk_buff *); +void cxgbi_sock_closed(struct cxgbi_sock *); +void cxgbi_sock_established(struct cxgbi_sock *, unsigned int, unsigned int); +void cxgbi_sock_rcv_abort_rpl(struct cxgbi_sock *); +void cxgbi_sock_rcv_peer_close(struct cxgbi_sock *); +void cxgbi_sock_rcv_close_conn_rpl(struct cxgbi_sock *, u32); +void cxgbi_sock_rcv_wr_ack(struct cxgbi_sock *, unsigned int, unsigned int, + int); +unsigned int cxgbi_sock_select_mss(struct cxgbi_sock *, unsigned int); +void cxgbi_sock_free_cpl_skbs(struct cxgbi_sock *); + +struct cxgbi_hba { + struct net_device *ndev; + struct net_device *vdev; /* vlan dev */ + struct Scsi_Host *shost; + struct cxgbi_device *cdev; + __be32 ipv4addr; + unsigned char port_id; +}; + +struct cxgbi_ports_map { + unsigned int max_connect; + unsigned int used; + unsigned short sport_base; + spinlock_t lock; + unsigned int next; + struct cxgbi_sock **port_csk; +}; + +#define CXGBI_FLAG_DEV_T3 0x1 +#define CXGBI_FLAG_DEV_T4 0x2 +#define CXGBI_FLAG_ADAPTER_RESET 0x4 +#define CXGBI_FLAG_IPV4_SET 0x10 +struct cxgbi_device { + struct list_head list_head; + unsigned int flags; + struct net_device **ports; + void *lldev; + struct cxgbi_hba **hbas; + const unsigned short *mtus; + unsigned char nmtus; + unsigned char nports; + struct pci_dev *pdev; + struct dentry *debugfs_root; + struct iscsi_transport *itp; + + unsigned int pfvf; + unsigned int snd_win; + unsigned int rcv_win; + unsigned int rx_credit_thres; + unsigned int skb_tx_rsvd; + unsigned int skb_rx_extra; /* for msg coalesced mode */ + unsigned int tx_max_size; + unsigned int rx_max_size; + struct cxgbi_ports_map pmap; + struct cxgbi_tag_format tag_format; + struct cxgbi_ddp_info *ddp; + + void (*dev_ddp_cleanup)(struct cxgbi_device *); + void (*csk_ddp_free_gl_skb)(struct cxgbi_ddp_info *, int, int); + int (*csk_ddp_alloc_gl_skb)(struct cxgbi_ddp_info *, int, int, gfp_t); + int (*csk_ddp_set)(struct cxgbi_sock *, struct cxgbi_pagepod_hdr *, + unsigned int, unsigned int, + struct cxgbi_gather_list *); + void (*csk_ddp_clear)(struct cxgbi_hba *, + unsigned int, unsigned int, unsigned int); + int (*csk_ddp_setup_digest)(struct cxgbi_sock *, + unsigned int, int, int, int); + int (*csk_ddp_setup_pgidx)(struct cxgbi_sock *, + unsigned int, int, bool); + + void (*csk_release_offload_resources)(struct cxgbi_sock *); + int (*csk_rx_pdu_ready)(struct cxgbi_sock *, struct sk_buff *); + u32 (*csk_send_rx_credits)(struct cxgbi_sock *, u32); + int (*csk_push_tx_frames)(struct cxgbi_sock *, int); + void (*csk_send_abort_req)(struct cxgbi_sock *); + void (*csk_send_close_req)(struct cxgbi_sock *); + int (*csk_alloc_cpls)(struct cxgbi_sock *); + int (*csk_init_act_open)(struct cxgbi_sock *); + + void *dd_data; +}; +#define cxgbi_cdev_priv(cdev) ((cdev)->dd_data) + +struct cxgbi_conn { + struct cxgbi_endpoint *cep; + struct iscsi_conn *iconn; + struct cxgbi_hba *chba; + u32 task_idx_bits; +}; + +struct cxgbi_endpoint { + struct cxgbi_conn *cconn; + struct cxgbi_hba *chba; + struct cxgbi_sock *csk; +}; + +#define MAX_PDU_FRAGS ((ULP2_MAX_PDU_PAYLOAD + 512 - 1) / 512) +struct cxgbi_task_data { + unsigned short nr_frags; + skb_frag_t frags[MAX_PDU_FRAGS]; + struct sk_buff *skb; + unsigned int offset; + unsigned int count; + unsigned int sgoffset; +}; +#define iscsi_task_cxgbi_data(task) \ + ((task)->dd_data + sizeof(struct iscsi_tcp_task)) + +static inline int cxgbi_is_ddp_tag(struct cxgbi_tag_format *tformat, u32 tag) +{ + return !(tag & (1 << (tformat->rsvd_bits + tformat->rsvd_shift - 1))); +} + +static inline int cxgbi_sw_tag_usable(struct cxgbi_tag_format *tformat, + u32 sw_tag) +{ + sw_tag >>= (32 - tformat->rsvd_bits); + return !sw_tag; +} + +static inline u32 cxgbi_set_non_ddp_tag(struct cxgbi_tag_format *tformat, + u32 sw_tag) +{ + unsigned char shift = tformat->rsvd_bits + tformat->rsvd_shift - 1; + u32 mask = (1 << shift) - 1; + + if (sw_tag && (sw_tag & ~mask)) { + u32 v1 = sw_tag & ((1 << shift) - 1); + u32 v2 = (sw_tag >> (shift - 1)) << shift; + + return v2 | v1 | 1 << shift; + } + + return sw_tag | 1 << shift; +} + +static inline u32 cxgbi_ddp_tag_base(struct cxgbi_tag_format *tformat, + u32 sw_tag) +{ + u32 mask = (1 << tformat->rsvd_shift) - 1; + + if (sw_tag && (sw_tag & ~mask)) { + u32 v1 = sw_tag & mask; + u32 v2 = sw_tag >> tformat->rsvd_shift; + + v2 <<= tformat->rsvd_bits + tformat->rsvd_shift; + + return v2 | v1; + } + + return sw_tag; +} + +static inline u32 cxgbi_tag_rsvd_bits(struct cxgbi_tag_format *tformat, + u32 tag) +{ + if (cxgbi_is_ddp_tag(tformat, tag)) + return (tag >> tformat->rsvd_shift) & tformat->rsvd_mask; + + return 0; +} + +static inline u32 cxgbi_tag_nonrsvd_bits(struct cxgbi_tag_format *tformat, + u32 tag) +{ + unsigned char shift = tformat->rsvd_bits + tformat->rsvd_shift - 1; + u32 v1, v2; + + if (cxgbi_is_ddp_tag(tformat, tag)) { + v1 = tag & ((1 << tformat->rsvd_shift) - 1); + v2 = (tag >> (shift + 1)) << tformat->rsvd_shift; + } else { + u32 mask = (1 << shift) - 1; + tag &= ~(1 << shift); + v1 = tag & mask; + v2 = (tag >> 1) & ~mask; + } + return v1 | v2; +} + +static inline void *cxgbi_alloc_big_mem(unsigned int size, + gfp_t gfp) +{ + void *p = kmalloc(size, gfp); + if (!p) + p = vmalloc(size); + if (p) + memset(p, 0, size); + return p; +} + +static inline void cxgbi_free_big_mem(void *addr) +{ + if (is_vmalloc_addr(addr)) + vfree(addr); + else + kfree(addr); +} + +static inline void cxgbi_set_iscsi_ipv4(struct cxgbi_hba *chba, __be32 ipaddr) +{ + if (chba->cdev->flags & CXGBI_FLAG_IPV4_SET) + chba->ipv4addr = ipaddr; + else + pr_info("set iscsi ipv4 NOT supported, using %s ipv4.\n", + chba->ndev->name); +} + +static inline __be32 cxgbi_get_iscsi_ipv4(struct cxgbi_hba *chba) +{ + return chba->ipv4addr; +} + +struct cxgbi_device *cxgbi_device_register(unsigned int, unsigned int); +void cxgbi_device_unregister(struct cxgbi_device *); +void cxgbi_device_unregister_all(unsigned int flag); +struct cxgbi_device *cxgbi_device_find_by_lldev(void *); +int cxgbi_hbas_add(struct cxgbi_device *, unsigned int, unsigned int, + struct scsi_host_template *, + struct scsi_transport_template *); +void cxgbi_hbas_remove(struct cxgbi_device *); + +int cxgbi_device_portmap_create(struct cxgbi_device *cdev, unsigned int base, + unsigned int max_conn); +void cxgbi_device_portmap_cleanup(struct cxgbi_device *cdev); + +void cxgbi_conn_tx_open(struct cxgbi_sock *); +void cxgbi_conn_pdu_ready(struct cxgbi_sock *); +int cxgbi_conn_alloc_pdu(struct iscsi_task *, u8); +int cxgbi_conn_init_pdu(struct iscsi_task *, unsigned int , unsigned int); +int cxgbi_conn_xmit_pdu(struct iscsi_task *); + +void cxgbi_cleanup_task(struct iscsi_task *task); + +void cxgbi_get_conn_stats(struct iscsi_cls_conn *, struct iscsi_stats *); +int cxgbi_set_conn_param(struct iscsi_cls_conn *, + enum iscsi_param, char *, int); +int cxgbi_get_conn_param(struct iscsi_cls_conn *, enum iscsi_param, char *); +struct iscsi_cls_conn *cxgbi_create_conn(struct iscsi_cls_session *, u32); +int cxgbi_bind_conn(struct iscsi_cls_session *, + struct iscsi_cls_conn *, u64, int); +void cxgbi_destroy_session(struct iscsi_cls_session *); +struct iscsi_cls_session *cxgbi_create_session(struct iscsi_endpoint *, + u16, u16, u32); +int cxgbi_set_host_param(struct Scsi_Host *, + enum iscsi_host_param, char *, int); +int cxgbi_get_host_param(struct Scsi_Host *, enum iscsi_host_param, char *); +struct iscsi_endpoint *cxgbi_ep_connect(struct Scsi_Host *, + struct sockaddr *, int); +int cxgbi_ep_poll(struct iscsi_endpoint *, int); +void cxgbi_ep_disconnect(struct iscsi_endpoint *); + +int cxgbi_iscsi_init(struct iscsi_transport *, + struct scsi_transport_template **); +void cxgbi_iscsi_cleanup(struct iscsi_transport *, + struct scsi_transport_template **); +void cxgbi_parse_pdu_itt(struct iscsi_conn *, itt_t, int *, int *); +int cxgbi_ddp_init(struct cxgbi_device *, unsigned int, unsigned int, + unsigned int, unsigned int); +int cxgbi_ddp_cleanup(struct cxgbi_device *); +void cxgbi_ddp_page_size_factor(int *); +void cxgbi_ddp_ppod_clear(struct cxgbi_pagepod *); +void cxgbi_ddp_ppod_set(struct cxgbi_pagepod *, struct cxgbi_pagepod_hdr *, + struct cxgbi_gather_list *, unsigned int); +#endif /*__LIBCXGBI_H__*/ diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index 1a970a76b1b9..6b729324b8d3 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -1,7 +1,7 @@ /* * Generic SCSI-3 ALUA SCSI Device Handler * - * Copyright (C) 2007, 2008 Hannes Reinecke, SUSE Linux Products GmbH. + * Copyright (C) 2007-2010 Hannes Reinecke, SUSE Linux Products GmbH. * All rights reserved. * * This program is free software; you can redistribute it and/or modify @@ -20,17 +20,19 @@ * */ #include <linux/slab.h> +#include <linux/delay.h> #include <scsi/scsi.h> #include <scsi/scsi_eh.h> #include <scsi/scsi_dh.h> #define ALUA_DH_NAME "alua" -#define ALUA_DH_VER "1.2" +#define ALUA_DH_VER "1.3" #define TPGS_STATE_OPTIMIZED 0x0 #define TPGS_STATE_NONOPTIMIZED 0x1 #define TPGS_STATE_STANDBY 0x2 #define TPGS_STATE_UNAVAILABLE 0x3 +#define TPGS_STATE_LBA_DEPENDENT 0x4 #define TPGS_STATE_OFFLINE 0xe #define TPGS_STATE_TRANSITIONING 0xf @@ -39,6 +41,7 @@ #define TPGS_SUPPORT_NONOPTIMIZED 0x02 #define TPGS_SUPPORT_STANDBY 0x04 #define TPGS_SUPPORT_UNAVAILABLE 0x08 +#define TPGS_SUPPORT_LBA_DEPENDENT 0x10 #define TPGS_SUPPORT_OFFLINE 0x40 #define TPGS_SUPPORT_TRANSITION 0x80 @@ -460,6 +463,8 @@ static char print_alua_state(int state) return 'S'; case TPGS_STATE_UNAVAILABLE: return 'U'; + case TPGS_STATE_LBA_DEPENDENT: + return 'L'; case TPGS_STATE_OFFLINE: return 'O'; case TPGS_STATE_TRANSITIONING: @@ -542,7 +547,9 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h) int len, k, off, valid_states = 0; char *ucp; unsigned err; + unsigned long expiry, interval = 10; + expiry = round_jiffies_up(jiffies + ALUA_FAILOVER_TIMEOUT); retry: err = submit_rtpg(sdev, h); @@ -553,7 +560,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h) return SCSI_DH_IO; err = alua_check_sense(sdev, &sense_hdr); - if (err == ADD_TO_MLQUEUE) + if (err == ADD_TO_MLQUEUE && time_before(jiffies, expiry)) goto retry; sdev_printk(KERN_INFO, sdev, "%s: rtpg sense code %02x/%02x/%02x\n", @@ -587,38 +594,37 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h) } sdev_printk(KERN_INFO, sdev, - "%s: port group %02x state %c supports %c%c%c%c%c%c\n", + "%s: port group %02x state %c supports %c%c%c%c%c%c%c\n", ALUA_DH_NAME, h->group_id, print_alua_state(h->state), valid_states&TPGS_SUPPORT_TRANSITION?'T':'t', valid_states&TPGS_SUPPORT_OFFLINE?'O':'o', + valid_states&TPGS_SUPPORT_LBA_DEPENDENT?'L':'l', valid_states&TPGS_SUPPORT_UNAVAILABLE?'U':'u', valid_states&TPGS_SUPPORT_STANDBY?'S':'s', valid_states&TPGS_SUPPORT_NONOPTIMIZED?'N':'n', valid_states&TPGS_SUPPORT_OPTIMIZED?'A':'a'); - if (h->tpgs & TPGS_MODE_EXPLICIT) { - switch (h->state) { - case TPGS_STATE_TRANSITIONING: + switch (h->state) { + case TPGS_STATE_TRANSITIONING: + if (time_before(jiffies, expiry)) { /* State transition, retry */ + interval *= 10; + msleep(interval); goto retry; - break; - case TPGS_STATE_OFFLINE: - /* Path is offline, fail */ - err = SCSI_DH_DEV_OFFLINED; - break; - default: - break; } - } else { - /* Only Implicit ALUA support */ - if (h->state == TPGS_STATE_OPTIMIZED || - h->state == TPGS_STATE_NONOPTIMIZED || - h->state == TPGS_STATE_STANDBY) - /* Useable path if active */ - err = SCSI_DH_OK; - else - /* Path unuseable for unavailable/offline */ - err = SCSI_DH_DEV_OFFLINED; + /* Transitioning time exceeded, set port to standby */ + err = SCSI_DH_RETRY; + h->state = TPGS_STATE_STANDBY; + break; + case TPGS_STATE_OFFLINE: + case TPGS_STATE_UNAVAILABLE: + /* Path unuseable for unavailable/offline */ + err = SCSI_DH_DEV_OFFLINED; + break; + default: + /* Useable path if active */ + err = SCSI_DH_OK; + break; } return err; } @@ -672,7 +678,9 @@ static int alua_activate(struct scsi_device *sdev, goto out; } - if (h->tpgs & TPGS_MODE_EXPLICIT && h->state != TPGS_STATE_OPTIMIZED) { + if (h->tpgs & TPGS_MODE_EXPLICIT && + h->state != TPGS_STATE_OPTIMIZED && + h->state != TPGS_STATE_LBA_DEPENDENT) { h->callback_fn = fn; h->callback_data = data; err = submit_stpg(h); @@ -698,8 +706,11 @@ static int alua_prep_fn(struct scsi_device *sdev, struct request *req) struct alua_dh_data *h = get_alua_data(sdev); int ret = BLKPREP_OK; - if (h->state != TPGS_STATE_OPTIMIZED && - h->state != TPGS_STATE_NONOPTIMIZED) { + if (h->state == TPGS_STATE_TRANSITIONING) + ret = BLKPREP_DEFER; + else if (h->state != TPGS_STATE_OPTIMIZED && + h->state != TPGS_STATE_NONOPTIMIZED && + h->state != TPGS_STATE_LBA_DEPENDENT) { ret = BLKPREP_KILL; req->cmd_flags |= REQ_QUIET; } diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c index ffc1edf5e80d..23dec0063385 100644 --- a/drivers/scsi/dpt_i2o.c +++ b/drivers/scsi/dpt_i2o.c @@ -49,7 +49,6 @@ MODULE_DESCRIPTION("Adaptec I2O RAID Driver"); #include <linux/kernel.h> /* for printk */ #include <linux/sched.h> #include <linux/reboot.h> -#include <linux/smp_lock.h> #include <linux/spinlock.h> #include <linux/dma-mapping.h> @@ -76,6 +75,7 @@ MODULE_DESCRIPTION("Adaptec I2O RAID Driver"); * Needed for our management apps *============================================================================ */ +static DEFINE_MUTEX(adpt_mutex); static dpt_sig_S DPTI_sig = { {'d', 'P', 't', 'S', 'i', 'G'}, SIG_VERSION, #ifdef __i386__ @@ -126,6 +126,7 @@ static const struct file_operations adpt_fops = { #ifdef CONFIG_COMPAT .compat_ioctl = compat_adpt_ioctl, #endif + .llseek = noop_llseek, }; /* Structures and definitions for synchronous message posting. @@ -1732,12 +1733,12 @@ static int adpt_open(struct inode *inode, struct file *file) int minor; adpt_hba* pHba; - lock_kernel(); + mutex_lock(&adpt_mutex); //TODO check for root access // minor = iminor(inode); if (minor >= hba_count) { - unlock_kernel(); + mutex_unlock(&adpt_mutex); return -ENXIO; } mutex_lock(&adpt_configuration_lock); @@ -1748,7 +1749,7 @@ static int adpt_open(struct inode *inode, struct file *file) } if (pHba == NULL) { mutex_unlock(&adpt_configuration_lock); - unlock_kernel(); + mutex_unlock(&adpt_mutex); return -ENXIO; } @@ -1759,7 +1760,7 @@ static int adpt_open(struct inode *inode, struct file *file) pHba->in_use = 1; mutex_unlock(&adpt_configuration_lock); - unlock_kernel(); + mutex_unlock(&adpt_mutex); return 0; } @@ -2160,9 +2161,9 @@ static long adpt_unlocked_ioctl(struct file *file, uint cmd, ulong arg) inode = file->f_dentry->d_inode; - lock_kernel(); + mutex_lock(&adpt_mutex); ret = adpt_ioctl(inode, file, cmd, arg); - unlock_kernel(); + mutex_unlock(&adpt_mutex); return ret; } @@ -2176,7 +2177,7 @@ static long compat_adpt_ioctl(struct file *file, inode = file->f_dentry->d_inode; - lock_kernel(); + mutex_lock(&adpt_mutex); switch(cmd) { case DPT_SIGNATURE: @@ -2194,7 +2195,7 @@ static long compat_adpt_ioctl(struct file *file, ret = -ENOIOCTLCMD; } - unlock_kernel(); + mutex_unlock(&adpt_mutex); return ret; } diff --git a/drivers/scsi/fnic/fnic_main.c b/drivers/scsi/fnic/fnic_main.c index 9eb7a9ebccae..bb63f1a1f808 100644 --- a/drivers/scsi/fnic/fnic_main.c +++ b/drivers/scsi/fnic/fnic_main.c @@ -80,8 +80,6 @@ static struct libfc_function_template fnic_transport_template = { static int fnic_slave_alloc(struct scsi_device *sdev) { struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); - struct fc_lport *lp = shost_priv(sdev->host); - struct fnic *fnic = lport_priv(lp); sdev->tagged_supported = 1; @@ -89,8 +87,6 @@ static int fnic_slave_alloc(struct scsi_device *sdev) return -ENXIO; scsi_activate_tcq(sdev, FNIC_DFLT_QUEUE_DEPTH); - rport->dev_loss_tmo = fnic->config.port_down_timeout / 1000; - return 0; } @@ -113,6 +109,15 @@ static struct scsi_host_template fnic_host_template = { .shost_attrs = fnic_attrs, }; +static void +fnic_set_rport_dev_loss_tmo(struct fc_rport *rport, u32 timeout) +{ + if (timeout) + rport->dev_loss_tmo = timeout; + else + rport->dev_loss_tmo = 1; +} + static void fnic_get_host_speed(struct Scsi_Host *shost); static struct scsi_transport_template *fnic_fc_transport; static struct fc_host_statistics *fnic_get_stats(struct Scsi_Host *); @@ -140,6 +145,7 @@ static struct fc_function_template fnic_fc_functions = { .show_starget_port_name = 1, .show_starget_port_id = 1, .show_rport_dev_loss_tmo = 1, + .set_rport_dev_loss_tmo = fnic_set_rport_dev_loss_tmo, .issue_fc_host_lip = fnic_reset, .get_fc_host_stats = fnic_get_stats, .dd_fcrport_size = sizeof(struct fc_rport_libfc_priv), @@ -706,6 +712,7 @@ static int __devinit fnic_probe(struct pci_dev *pdev, goto err_out_free_exch_mgr; } fc_host_maxframe_size(lp->host) = lp->mfs; + fc_host_dev_loss_tmo(lp->host) = fnic->config.port_down_timeout / 1000; sprintf(fc_host_symbolic_name(lp->host), DRV_NAME " v" DRV_VERSION " over %s", fnic->name); diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c index b860d650a563..5a3f93101017 100644 --- a/drivers/scsi/gdth.c +++ b/drivers/scsi/gdth.c @@ -120,7 +120,7 @@ #include <linux/timer.h> #include <linux/dma-mapping.h> #include <linux/list.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/slab.h> #ifdef GDTH_RTC @@ -140,6 +140,7 @@ #include <scsi/scsi_host.h> #include "gdth.h" +static DEFINE_MUTEX(gdth_mutex); static void gdth_delay(int milliseconds); static void gdth_eval_mapping(u32 size, u32 *cyls, int *heads, int *secs); static irqreturn_t gdth_interrupt(int irq, void *dev_id); @@ -372,6 +373,7 @@ static const struct file_operations gdth_fops = { .unlocked_ioctl = gdth_unlocked_ioctl, .open = gdth_open, .release = gdth_close, + .llseek = noop_llseek, }; #include "gdth_proc.h" @@ -4042,12 +4044,12 @@ static int gdth_open(struct inode *inode, struct file *filep) { gdth_ha_str *ha; - lock_kernel(); + mutex_lock(&gdth_mutex); list_for_each_entry(ha, &gdth_instances, list) { if (!ha->sdev) ha->sdev = scsi_get_host_dev(ha->shost); } - unlock_kernel(); + mutex_unlock(&gdth_mutex); TRACE(("gdth_open()\n")); return 0; @@ -4615,9 +4617,9 @@ static long gdth_unlocked_ioctl(struct file *file, unsigned int cmd, { int ret; - lock_kernel(); + mutex_lock(&gdth_mutex); ret = gdth_ioctl(file, cmd, arg); - unlock_kernel(); + mutex_unlock(&gdth_mutex); return ret; } diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index ba7f87acc00d..4f7a5829ea4c 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -376,6 +376,7 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) shost->this_id = sht->this_id; shost->can_queue = sht->can_queue; shost->sg_tablesize = sht->sg_tablesize; + shost->sg_prot_tablesize = sht->sg_prot_tablesize; shost->cmd_per_lun = sht->cmd_per_lun; shost->unchecked_isa_dma = sht->unchecked_isa_dma; shost->use_clustering = sht->use_clustering; diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index 9f75a6d519a2..00d08b25425f 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c @@ -50,7 +50,6 @@ static unsigned int max_lun = IBMVFC_MAX_LUN; static unsigned int max_targets = IBMVFC_MAX_TARGETS; static unsigned int max_requests = IBMVFC_MAX_REQUESTS_DEFAULT; static unsigned int disc_threads = IBMVFC_MAX_DISC_THREADS; -static unsigned int dev_loss_tmo = IBMVFC_DEV_LOSS_TMO; static unsigned int ibmvfc_debug = IBMVFC_DEBUG; static unsigned int log_level = IBMVFC_DEFAULT_LOG_LEVEL; static LIST_HEAD(ibmvfc_head); @@ -84,11 +83,6 @@ MODULE_PARM_DESC(disc_threads, "Number of device discovery threads to use. " module_param_named(debug, ibmvfc_debug, uint, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Enable driver debug information. " "[Default=" __stringify(IBMVFC_DEBUG) "]"); -module_param_named(dev_loss_tmo, dev_loss_tmo, uint, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(dev_loss_tmo, "Maximum number of seconds that the FC " - "transport should insulate the loss of a remote port. Once this " - "value is exceeded, the scsi target is removed. " - "[Default=" __stringify(IBMVFC_DEV_LOSS_TMO) "]"); module_param_named(log_level, log_level, uint, 0); MODULE_PARM_DESC(log_level, "Set to 0 - 4 for increasing verbosity of device driver. " "[Default=" __stringify(IBMVFC_DEFAULT_LOG_LEVEL) "]"); @@ -2496,41 +2490,66 @@ static void ibmvfc_terminate_rport_io(struct fc_rport *rport) LEAVE; } -static const struct { - enum ibmvfc_async_event ae; - const char *desc; -} ae_desc [] = { - { IBMVFC_AE_ELS_PLOGI, "PLOGI" }, - { IBMVFC_AE_ELS_LOGO, "LOGO" }, - { IBMVFC_AE_ELS_PRLO, "PRLO" }, - { IBMVFC_AE_SCN_NPORT, "N-Port SCN" }, - { IBMVFC_AE_SCN_GROUP, "Group SCN" }, - { IBMVFC_AE_SCN_DOMAIN, "Domain SCN" }, - { IBMVFC_AE_SCN_FABRIC, "Fabric SCN" }, - { IBMVFC_AE_LINK_UP, "Link Up" }, - { IBMVFC_AE_LINK_DOWN, "Link Down" }, - { IBMVFC_AE_LINK_DEAD, "Link Dead" }, - { IBMVFC_AE_HALT, "Halt" }, - { IBMVFC_AE_RESUME, "Resume" }, - { IBMVFC_AE_ADAPTER_FAILED, "Adapter Failed" }, +static const struct ibmvfc_async_desc ae_desc [] = { + { IBMVFC_AE_ELS_PLOGI, "PLOGI", IBMVFC_DEFAULT_LOG_LEVEL + 1 }, + { IBMVFC_AE_ELS_LOGO, "LOGO", IBMVFC_DEFAULT_LOG_LEVEL + 1 }, + { IBMVFC_AE_ELS_PRLO, "PRLO", IBMVFC_DEFAULT_LOG_LEVEL + 1 }, + { IBMVFC_AE_SCN_NPORT, "N-Port SCN", IBMVFC_DEFAULT_LOG_LEVEL + 1 }, + { IBMVFC_AE_SCN_GROUP, "Group SCN", IBMVFC_DEFAULT_LOG_LEVEL + 1 }, + { IBMVFC_AE_SCN_DOMAIN, "Domain SCN", IBMVFC_DEFAULT_LOG_LEVEL }, + { IBMVFC_AE_SCN_FABRIC, "Fabric SCN", IBMVFC_DEFAULT_LOG_LEVEL }, + { IBMVFC_AE_LINK_UP, "Link Up", IBMVFC_DEFAULT_LOG_LEVEL }, + { IBMVFC_AE_LINK_DOWN, "Link Down", IBMVFC_DEFAULT_LOG_LEVEL }, + { IBMVFC_AE_LINK_DEAD, "Link Dead", IBMVFC_DEFAULT_LOG_LEVEL }, + { IBMVFC_AE_HALT, "Halt", IBMVFC_DEFAULT_LOG_LEVEL }, + { IBMVFC_AE_RESUME, "Resume", IBMVFC_DEFAULT_LOG_LEVEL }, + { IBMVFC_AE_ADAPTER_FAILED, "Adapter Failed", IBMVFC_DEFAULT_LOG_LEVEL }, }; -static const char *unknown_ae = "Unknown async"; +static const struct ibmvfc_async_desc unknown_ae = { + 0, "Unknown async", IBMVFC_DEFAULT_LOG_LEVEL +}; /** * ibmvfc_get_ae_desc - Get text description for async event * @ae: async event * **/ -static const char *ibmvfc_get_ae_desc(u64 ae) +static const struct ibmvfc_async_desc *ibmvfc_get_ae_desc(u64 ae) { int i; for (i = 0; i < ARRAY_SIZE(ae_desc); i++) if (ae_desc[i].ae == ae) - return ae_desc[i].desc; + return &ae_desc[i]; + + return &unknown_ae; +} + +static const struct { + enum ibmvfc_ae_link_state state; + const char *desc; +} link_desc [] = { + { IBMVFC_AE_LS_LINK_UP, " link up" }, + { IBMVFC_AE_LS_LINK_BOUNCED, " link bounced" }, + { IBMVFC_AE_LS_LINK_DOWN, " link down" }, + { IBMVFC_AE_LS_LINK_DEAD, " link dead" }, +}; - return unknown_ae; +/** + * ibmvfc_get_link_state - Get text description for link state + * @state: link state + * + **/ +static const char *ibmvfc_get_link_state(enum ibmvfc_ae_link_state state) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(link_desc); i++) + if (link_desc[i].state == state) + return link_desc[i].desc; + + return ""; } /** @@ -2542,11 +2561,12 @@ static const char *ibmvfc_get_ae_desc(u64 ae) static void ibmvfc_handle_async(struct ibmvfc_async_crq *crq, struct ibmvfc_host *vhost) { - const char *desc = ibmvfc_get_ae_desc(crq->event); + const struct ibmvfc_async_desc *desc = ibmvfc_get_ae_desc(crq->event); struct ibmvfc_target *tgt; - ibmvfc_log(vhost, 3, "%s event received. scsi_id: %llx, wwpn: %llx," - " node_name: %llx\n", desc, crq->scsi_id, crq->wwpn, crq->node_name); + ibmvfc_log(vhost, desc->log_level, "%s event received. scsi_id: %llx, wwpn: %llx," + " node_name: %llx%s\n", desc->desc, crq->scsi_id, crq->wwpn, crq->node_name, + ibmvfc_get_link_state(crq->link_state)); switch (crq->event) { case IBMVFC_AE_RESUME: @@ -2788,7 +2808,6 @@ static int ibmvfc_target_alloc(struct scsi_target *starget) static int ibmvfc_slave_configure(struct scsi_device *sdev) { struct Scsi_Host *shost = sdev->host; - struct fc_rport *rport = starget_to_rport(sdev->sdev_target); unsigned long flags = 0; spin_lock_irqsave(shost->host_lock, flags); @@ -2800,8 +2819,6 @@ static int ibmvfc_slave_configure(struct scsi_device *sdev) scsi_activate_tcq(sdev, sdev->queue_depth); } else scsi_deactivate_tcq(sdev, sdev->queue_depth); - - rport->dev_loss_tmo = dev_loss_tmo; spin_unlock_irqrestore(shost->host_lock, flags); return 0; } @@ -4285,8 +4302,10 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost) 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)))) { + if (rc == H_CLOSED) + vio_enable_interrupts(to_vio_dev(vhost->dev)); + else 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); } @@ -4744,6 +4763,8 @@ static int ibmvfc_probe(struct vio_dev *vdev, const struct vio_device_id *id) if ((rc = scsi_add_host(shost, dev))) goto release_event_pool; + fc_host_dev_loss_tmo(shost) = IBMVFC_DEV_LOSS_TMO; + if ((rc = ibmvfc_create_trace_file(&shost->shost_dev.kobj, &ibmvfc_trace_attr))) { dev_err(dev, "Failed to create trace file. rc=%d\n", rc); diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h index 608af394c8cf..ef663e7c9bbc 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.h +++ b/drivers/scsi/ibmvscsi/ibmvfc.h @@ -541,6 +541,12 @@ enum ibmvfc_async_event { IBMVFC_AE_ADAPTER_FAILED = 0x1000, }; +struct ibmvfc_async_desc { + enum ibmvfc_async_event ae; + const char *desc; + int log_level; +}; + struct ibmvfc_crq { volatile u8 valid; volatile u8 format; diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 52568588039f..df9a12c8b373 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -1096,6 +1096,7 @@ static void ipr_init_res_entry(struct ipr_resource_entry *res, res->bus = cfgtew->u.cfgte->res_addr.bus; res->target = cfgtew->u.cfgte->res_addr.target; res->lun = cfgtew->u.cfgte->res_addr.lun; + res->lun_wwn = get_unaligned_be64(cfgtew->u.cfgte->lun_wwn); } ipr_update_ata_class(res, proto); @@ -1142,7 +1143,7 @@ static char *ipr_format_res_path(u8 *res_path, char *buffer, int len) int i; char *p = buffer; - res_path[0] = '\0'; + *p = '\0'; p += snprintf(p, buffer + len - p, "%02X", res_path[0]); for (i = 1; res_path[i] != 0xff && ((i * 3) < len); i++) p += snprintf(p, buffer + len - p, "-%02X", res_path[i]); @@ -1670,7 +1671,7 @@ static void ipr_log_enhanced_array_error(struct ipr_ioa_cfg *ioa_cfg, array_entry = error->array_member; num_entries = min_t(u32, be32_to_cpu(error->num_entries), - sizeof(error->array_member)); + ARRAY_SIZE(error->array_member)); for (i = 0; i < num_entries; i++, array_entry++) { if (!memcmp(array_entry->vpd.vpd.sn, zero_sn, IPR_SERIAL_NUM_LEN)) @@ -2151,8 +2152,8 @@ static void ipr_log_sis64_array_error(struct ipr_ioa_cfg *ioa_cfg, ipr_err_separator; array_entry = error->array_member; - num_entries = min_t(u32, be32_to_cpu(error->num_entries), - sizeof(error->array_member)); + num_entries = min_t(u32, error->num_entries, + ARRAY_SIZE(error->array_member)); for (i = 0; i < num_entries; i++, array_entry++) { @@ -2166,10 +2167,10 @@ static void ipr_log_sis64_array_error(struct ipr_ioa_cfg *ioa_cfg, ipr_err("Array Member %d:\n", i); ipr_log_ext_vpd(&array_entry->vpd); - ipr_err("Current Location: %s", + ipr_err("Current Location: %s\n", ipr_format_res_path(array_entry->res_path, buffer, sizeof(buffer))); - ipr_err("Expected Location: %s", + ipr_err("Expected Location: %s\n", ipr_format_res_path(array_entry->expected_res_path, buffer, sizeof(buffer))); @@ -4089,6 +4090,7 @@ static int ipr_change_queue_type(struct scsi_device *sdev, int tag_type) /** * ipr_show_adapter_handle - Show the adapter's resource handle for this device * @dev: device struct + * @attr: device attribute structure * @buf: buffer * * Return value: @@ -4122,6 +4124,7 @@ static struct device_attribute ipr_adapter_handle_attr = { * ipr_show_resource_path - Show the resource path or the resource address for * this device. * @dev: device struct + * @attr: device attribute structure * @buf: buffer * * Return value: @@ -4159,8 +4162,45 @@ static struct device_attribute ipr_resource_path_attr = { }; /** + * ipr_show_device_id - Show the device_id for this device. + * @dev: device struct + * @attr: device attribute structure + * @buf: buffer + * + * Return value: + * number of bytes printed to buffer + **/ +static ssize_t ipr_show_device_id(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 && ioa_cfg->sis64) + len = snprintf(buf, PAGE_SIZE, "0x%llx\n", res->dev_id); + else if (res) + len = snprintf(buf, PAGE_SIZE, "0x%llx\n", res->lun_wwn); + + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + return len; +} + +static struct device_attribute ipr_device_id_attr = { + .attr = { + .name = "device_id", + .mode = S_IRUGO, + }, + .show = ipr_show_device_id +}; + +/** * ipr_show_resource_type - Show the resource type for this device. * @dev: device struct + * @attr: device attribute structure * @buf: buffer * * Return value: @@ -4195,6 +4235,7 @@ static struct device_attribute ipr_resource_type_attr = { static struct device_attribute *ipr_dev_attrs[] = { &ipr_adapter_handle_attr, &ipr_resource_path_attr, + &ipr_device_id_attr, &ipr_resource_type_attr, NULL, }; @@ -4898,39 +4939,15 @@ static int ipr_eh_abort(struct scsi_cmnd * scsi_cmd) /** * ipr_handle_other_interrupt - Handle "other" interrupts * @ioa_cfg: ioa config struct + * @int_reg: interrupt register * * Return value: * IRQ_NONE / IRQ_HANDLED **/ -static irqreturn_t ipr_handle_other_interrupt(struct ipr_ioa_cfg *ioa_cfg) +static irqreturn_t ipr_handle_other_interrupt(struct ipr_ioa_cfg *ioa_cfg, + volatile u32 int_reg) { irqreturn_t rc = IRQ_HANDLED; - volatile u32 int_reg, int_mask_reg; - - int_mask_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg32); - int_reg = readl(ioa_cfg->regs.sense_interrupt_reg32) & ~int_mask_reg; - - /* If an interrupt on the adapter did not occur, ignore it. - * Or in the case of SIS 64, check for a stage change interrupt. - */ - if ((int_reg & IPR_PCII_OPER_INTERRUPTS) == 0) { - if (ioa_cfg->sis64) { - int_mask_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg); - int_reg = readl(ioa_cfg->regs.sense_interrupt_reg) & ~int_mask_reg; - if (int_reg & IPR_PCII_IPL_STAGE_CHANGE) { - - /* clear stage change */ - writel(IPR_PCII_IPL_STAGE_CHANGE, ioa_cfg->regs.clr_interrupt_reg); - int_reg = readl(ioa_cfg->regs.sense_interrupt_reg) & ~int_mask_reg; - list_del(&ioa_cfg->reset_cmd->queue); - del_timer(&ioa_cfg->reset_cmd->timer); - ipr_reset_ioa_job(ioa_cfg->reset_cmd); - return IRQ_HANDLED; - } - } - - return IRQ_NONE; - } if (int_reg & IPR_PCII_IOA_TRANS_TO_OPER) { /* Mask the interrupt */ @@ -4991,7 +5008,7 @@ static irqreturn_t ipr_isr(int irq, void *devp) { struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)devp; unsigned long lock_flags = 0; - volatile u32 int_reg; + volatile u32 int_reg, int_mask_reg; u32 ioasc; u16 cmd_index; int num_hrrq = 0; @@ -5006,6 +5023,33 @@ static irqreturn_t ipr_isr(int irq, void *devp) return IRQ_NONE; } + int_mask_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg32); + int_reg = readl(ioa_cfg->regs.sense_interrupt_reg32) & ~int_mask_reg; + + /* If an interrupt on the adapter did not occur, ignore it. + * Or in the case of SIS 64, check for a stage change interrupt. + */ + if (unlikely((int_reg & IPR_PCII_OPER_INTERRUPTS) == 0)) { + if (ioa_cfg->sis64) { + int_mask_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg); + int_reg = readl(ioa_cfg->regs.sense_interrupt_reg) & ~int_mask_reg; + if (int_reg & IPR_PCII_IPL_STAGE_CHANGE) { + + /* clear stage change */ + writel(IPR_PCII_IPL_STAGE_CHANGE, ioa_cfg->regs.clr_interrupt_reg); + int_reg = readl(ioa_cfg->regs.sense_interrupt_reg) & ~int_mask_reg; + list_del(&ioa_cfg->reset_cmd->queue); + del_timer(&ioa_cfg->reset_cmd->timer); + ipr_reset_ioa_job(ioa_cfg->reset_cmd); + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + return IRQ_HANDLED; + } + } + + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + return IRQ_NONE; + } + while (1) { ipr_cmd = NULL; @@ -5045,7 +5089,7 @@ static irqreturn_t ipr_isr(int irq, void *devp) /* Clear the PCI interrupt */ do { writel(IPR_PCII_HRRQ_UPDATED, ioa_cfg->regs.clr_interrupt_reg32); - int_reg = readl(ioa_cfg->regs.sense_interrupt_reg32); + int_reg = readl(ioa_cfg->regs.sense_interrupt_reg32) & ~int_mask_reg; } while (int_reg & IPR_PCII_HRRQ_UPDATED && num_hrrq++ < IPR_MAX_HRRQ_RETRIES); @@ -5060,7 +5104,7 @@ static irqreturn_t ipr_isr(int irq, void *devp) } if (unlikely(rc == IRQ_NONE)) - rc = ipr_handle_other_interrupt(ioa_cfg); + rc = ipr_handle_other_interrupt(ioa_cfg, int_reg); spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); return rc; diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h index 4d31625ab9cf..aa8bb2f2c6ee 100644 --- a/drivers/scsi/ipr.h +++ b/drivers/scsi/ipr.h @@ -26,6 +26,7 @@ #ifndef _IPR_H #define _IPR_H +#include <asm/unaligned.h> #include <linux/types.h> #include <linux/completion.h> #include <linux/libata.h> @@ -37,8 +38,8 @@ /* * Literals */ -#define IPR_DRIVER_VERSION "2.5.0" -#define IPR_DRIVER_DATE "(February 11, 2010)" +#define IPR_DRIVER_VERSION "2.5.1" +#define IPR_DRIVER_DATE "(August 10, 2010)" /* * IPR_MAX_CMD_PER_LUN: This defines the maximum number of outstanding @@ -318,6 +319,11 @@ struct ipr_ext_vpd { __be32 wwid[2]; }__attribute__((packed)); +struct ipr_ext_vpd64 { + struct ipr_vpd vpd; + __be32 wwid[4]; +}__attribute__((packed)); + struct ipr_std_inq_data { u8 peri_qual_dev_type; #define IPR_STD_INQ_PERI_QUAL(peri) ((peri) >> 5) @@ -372,7 +378,7 @@ struct ipr_config_table_entry { struct ipr_res_addr res_addr; __be32 res_handle; - __be32 reserved4[2]; + __be32 lun_wwn[2]; struct ipr_std_inq_data std_inq_data; }__attribute__ ((packed, aligned (4))); @@ -394,7 +400,7 @@ struct ipr_config_table_entry64 { __be64 res_path; struct ipr_std_inq_data std_inq_data; u8 reserved2[4]; - __be64 reserved3[2]; // description text + __be64 reserved3[2]; u8 reserved4[8]; }__attribute__ ((packed, aligned (8))); @@ -913,7 +919,7 @@ struct ipr_hostrcb_type_24_error { u8 array_id; u8 last_res_path[8]; u8 protection_level[8]; - struct ipr_ext_vpd array_vpd; + struct ipr_ext_vpd64 array_vpd; u8 description[16]; u8 reserved2[3]; u8 num_entries; @@ -1210,6 +1216,7 @@ struct ipr_resource_entry { __be32 res_handle; __be64 dev_id; + __be64 lun_wwn; struct scsi_lun dev_lun; u8 res_path[8]; diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index 042153cbbde1..e1a395b438ee 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c @@ -162,6 +162,10 @@ static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc) unsigned int xfer = 0; unsigned int si; + /* If the device fell off, no sense in issuing commands */ + if (dev->gone) + return AC_ERR_SYSTEM; + task = sas_alloc_task(GFP_ATOMIC); if (!task) return AC_ERR_SYSTEM; @@ -347,6 +351,7 @@ static int sas_ata_scr_read(struct ata_link *link, unsigned int sc_reg_in, static struct ata_port_operations sas_sata_ops = { .phy_reset = sas_ata_phy_reset, .post_internal_cmd = sas_ata_post_internal, + .qc_defer = ata_std_qc_defer, .qc_prep = ata_noop_qc_prep, .qc_issue = sas_ata_qc_issue, .qc_fill_rtf = sas_ata_qc_fill_rtf, diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index 83dd5070a15c..505ffe358293 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -175,10 +175,10 @@ static void sas_set_ex_phy(struct domain_device *dev, int phy_id, switch (resp->result) { case SMP_RESP_PHY_VACANT: phy->phy_state = PHY_VACANT; - return; + break; default: phy->phy_state = PHY_NOT_PRESENT; - return; + break; case SMP_RESP_FUNC_ACC: phy->phy_state = PHY_EMPTY; /* do not know yet */ break; @@ -209,7 +209,10 @@ static void sas_set_ex_phy(struct domain_device *dev, int phy_id, phy->phy->negotiated_linkrate = phy->linkrate; if (!rediscover) - sas_phy_add(phy->phy); + if (sas_phy_add(phy->phy)) { + sas_phy_free(phy->phy); + return; + } SAS_DPRINTK("ex %016llx phy%02d:%c attached: %016llx\n", SAS_ADDR(dev->sas_addr), phy->phy_id, @@ -1724,6 +1727,7 @@ static void sas_unregister_ex_tree(struct domain_device *dev) struct domain_device *child, *n; list_for_each_entry_safe(child, n, &ex->children, siblings) { + child->gone = 1; if (child->dev_type == EDGE_DEV || child->dev_type == FANOUT_DEV) sas_unregister_ex_tree(child); @@ -1744,6 +1748,7 @@ static void sas_unregister_devs_sas_addr(struct domain_device *parent, &ex_dev->children, siblings) { if (SAS_ADDR(child->sas_addr) == SAS_ADDR(phy->attached_sas_addr)) { + child->gone = 1; if (child->dev_type == EDGE_DEV || child->dev_type == FANOUT_DEV) sas_unregister_ex_tree(child); @@ -1752,6 +1757,7 @@ static void sas_unregister_devs_sas_addr(struct domain_device *parent, break; } } + parent->gone = 1; sas_disable_routing(parent, phy->attached_sas_addr); } memset(phy->attached_sas_addr, 0, SAS_ADDR_SIZE); diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index f0cfba9a1fc8..55f09e92ab59 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c @@ -130,17 +130,6 @@ static void sas_scsi_task_done(struct sas_task *task) sc->scsi_done(sc); } -static enum task_attribute sas_scsi_get_task_attr(struct scsi_cmnd *cmd) -{ - enum task_attribute ta = TASK_ATTR_SIMPLE; - if (cmd->request && blk_rq_tagged(cmd->request)) { - if (cmd->device->ordered_tags && - (cmd->request->cmd_flags & REQ_HARDBARRIER)) - ta = TASK_ATTR_ORDERED; - } - return ta; -} - static struct sas_task *sas_create_task(struct scsi_cmnd *cmd, struct domain_device *dev, gfp_t gfp_flags) @@ -160,7 +149,7 @@ static struct sas_task *sas_create_task(struct scsi_cmnd *cmd, task->ssp_task.retry_count = 1; int_to_scsilun(cmd->device->lun, &lun); memcpy(task->ssp_task.LUN, &lun.scsi_lun, 8); - task->ssp_task.task_attr = sas_scsi_get_task_attr(cmd); + task->ssp_task.task_attr = TASK_ATTR_SIMPLE; memcpy(task->ssp_task.cdb, cmd->cmnd, 16); task->scatter = scsi_sglist(cmd); @@ -228,6 +217,13 @@ int sas_queuecommand(struct scsi_cmnd *cmd, goto out; } + /* If the device fell off, no sense in issuing commands */ + if (dev->gone) { + cmd->result = DID_BAD_TARGET << 16; + scsi_done(cmd); + goto out; + } + res = -ENOMEM; task = sas_create_task(cmd, dev, GFP_ATOMIC); if (!task) diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 23ce45708335..f681eea57730 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -586,6 +586,11 @@ lpfc_issue_lip(struct Scsi_Host *shost) phba->cfg_link_speed); mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2); + if ((mbxstatus == MBX_SUCCESS) && + (pmboxq->u.mb.mbxStatus == MBXERR_SEC_NO_PERMISSION)) + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + "2859 SLI authentication is required " + "for INIT_LINK but has not done yet\n"); } lpfc_set_loopback_flag(phba); @@ -2159,6 +2164,11 @@ lpfc_nodev_tmo_set(struct lpfc_vport *vport, int val) if (val >= LPFC_MIN_DEVLOSS_TMO && val <= LPFC_MAX_DEVLOSS_TMO) { vport->cfg_nodev_tmo = val; vport->cfg_devloss_tmo = val; + /* + * For compat: set the fc_host dev loss so new rports + * will get the value. + */ + fc_host_dev_loss_tmo(lpfc_shost_from_vport(vport)) = val; lpfc_update_rport_devloss_tmo(vport); return 0; } @@ -2208,6 +2218,7 @@ lpfc_devloss_tmo_set(struct lpfc_vport *vport, int val) vport->cfg_nodev_tmo = val; vport->cfg_devloss_tmo = val; vport->dev_loss_tmo_changed = 1; + fc_host_dev_loss_tmo(lpfc_shost_from_vport(vport)) = val; lpfc_update_rport_devloss_tmo(vport); return 0; } @@ -3776,6 +3787,11 @@ sysfs_mbox_read(struct file *filp, struct kobject *kobj, case MBX_PORT_CAPABILITIES: case MBX_PORT_IOV_CONTROL: break; + case MBX_SECURITY_MGMT: + case MBX_AUTH_PORT: + if (phba->pci_dev_grp == LPFC_PCI_DEV_OC) + return -EPERM; + break; case MBX_READ_SPARM64: case MBX_READ_LA: case MBX_READ_LA64: diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index 49d0cf99c24c..f5d60b55f53a 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c @@ -259,6 +259,7 @@ lpfc_bsg_send_mgmt_cmd(struct fc_bsg_job *job) struct bsg_job_data *dd_data; uint32_t creg_val; int rc = 0; + int iocb_stat; /* in case no data is transferred */ job->reply->reply_payload_rcv_len = 0; @@ -373,14 +374,13 @@ lpfc_bsg_send_mgmt_cmd(struct fc_bsg_job *job) readl(phba->HCregaddr); /* flush */ } - rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 0); - - if (rc == IOCB_SUCCESS) + iocb_stat = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 0); + if (iocb_stat == IOCB_SUCCESS) return 0; /* done for now */ - else if (rc == IOCB_BUSY) - rc = EAGAIN; + else if (iocb_stat == IOCB_BUSY) + rc = -EAGAIN; else - rc = EIO; + rc = -EIO; /* iocb failed so cleanup */ @@ -631,9 +631,9 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job) if (rc == IOCB_SUCCESS) return 0; /* done for now */ else if (rc == IOCB_BUSY) - rc = EAGAIN; + rc = -EAGAIN; else - rc = EIO; + rc = -EIO; pci_unmap_sg(phba->pcidev, job->request_payload.sg_list, job->request_payload.sg_cnt, DMA_TO_DEVICE); @@ -1299,7 +1299,7 @@ lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct fc_bsg_job *job, uint32_t tag, /* Allocate buffer for command iocb */ ctiocb = lpfc_sli_get_iocbq(phba); if (!ctiocb) { - rc = ENOMEM; + rc = -ENOMEM; goto no_ctiocb; } @@ -1518,7 +1518,7 @@ lpfc_bsg_diag_mode(struct fc_bsg_job *job) loopback_mode = (struct diag_mode_set *) job->request->rqst_data.h_vendor.vendor_cmd; link_flags = loopback_mode->type; - timeout = loopback_mode->timeout; + timeout = loopback_mode->timeout * 100; if ((phba->link_state == LPFC_HBA_ERROR) || (psli->sli_flag & LPFC_BLOCK_MGMT_IO) || @@ -1649,17 +1649,18 @@ static int lpfcdiag_loop_self_reg(struct lpfc_hba *phba, uint16_t * rpi) mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mbox) - return ENOMEM; + return -ENOMEM; status = lpfc_reg_rpi(phba, 0, phba->pport->fc_myDID, (uint8_t *)&phba->pport->fc_sparam, mbox, 0); if (status) { mempool_free(mbox, phba->mbox_mem_pool); - return ENOMEM; + return -ENOMEM; } dmabuff = (struct lpfc_dmabuf *) mbox->context1; mbox->context1 = NULL; + mbox->context2 = NULL; status = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO); if ((status != MBX_SUCCESS) || (mbox->u.mb.mbxStatus)) { @@ -1667,7 +1668,7 @@ static int lpfcdiag_loop_self_reg(struct lpfc_hba *phba, uint16_t * rpi) kfree(dmabuff); if (status != MBX_TIMEOUT) mempool_free(mbox, phba->mbox_mem_pool); - return ENODEV; + return -ENODEV; } *rpi = mbox->u.mb.un.varWords[0]; @@ -1693,7 +1694,7 @@ static int lpfcdiag_loop_self_unreg(struct lpfc_hba *phba, uint16_t rpi) /* Allocate mboxq structure */ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (mbox == NULL) - return ENOMEM; + return -ENOMEM; lpfc_unreg_login(phba, 0, rpi, mbox); status = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO); @@ -1701,7 +1702,7 @@ static int lpfcdiag_loop_self_unreg(struct lpfc_hba *phba, uint16_t rpi) if ((status != MBX_SUCCESS) || (mbox->u.mb.mbxStatus)) { if (status != MBX_TIMEOUT) mempool_free(mbox, phba->mbox_mem_pool); - return EIO; + return -EIO; } mempool_free(mbox, phba->mbox_mem_pool); @@ -1730,6 +1731,8 @@ static int lpfcdiag_loop_get_xri(struct lpfc_hba *phba, uint16_t rpi, struct ulp_bde64 *bpl = NULL; struct lpfc_sli_ct_request *ctreq = NULL; int ret_val = 0; + int time_left; + int iocb_stat = 0; unsigned long flags; *txxri = 0; @@ -1737,7 +1740,7 @@ static int lpfcdiag_loop_get_xri(struct lpfc_hba *phba, uint16_t rpi, evt = lpfc_bsg_event_new(FC_REG_CT_EVENT, current->pid, SLI_CT_ELX_LOOPBACK); if (!evt) - return ENOMEM; + return -ENOMEM; spin_lock_irqsave(&phba->ct_ev_lock, flags); list_add(&evt->node, &phba->ct_ev_waiters); @@ -1770,7 +1773,7 @@ static int lpfcdiag_loop_get_xri(struct lpfc_hba *phba, uint16_t rpi, if (cmdiocbq == NULL || rspiocbq == NULL || dmabuf == NULL || bpl == NULL || ctreq == NULL || dmabuf->virt == NULL) { - ret_val = ENOMEM; + ret_val = -ENOMEM; goto err_get_xri_exit; } @@ -1806,24 +1809,24 @@ static int lpfcdiag_loop_get_xri(struct lpfc_hba *phba, uint16_t rpi, cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; cmdiocbq->vport = phba->pport; - ret_val = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq, + iocb_stat = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq, rspiocbq, (phba->fc_ratov * 2) + LPFC_DRVR_TIMEOUT); - if (ret_val) + if (iocb_stat) { + ret_val = -EIO; goto err_get_xri_exit; - + } *txxri = rsp->ulpContext; evt->waiting = 1; evt->wait_time_stamp = jiffies; - ret_val = wait_event_interruptible_timeout( + time_left = wait_event_interruptible_timeout( evt->wq, !list_empty(&evt->events_to_see), ((phba->fc_ratov * 2) + LPFC_DRVR_TIMEOUT) * HZ); if (list_empty(&evt->events_to_see)) - ret_val = (ret_val) ? EINTR : ETIMEDOUT; + ret_val = (time_left) ? -EINTR : -ETIMEDOUT; else { - ret_val = IOCB_SUCCESS; spin_lock_irqsave(&phba->ct_ev_lock, flags); list_move(evt->events_to_see.prev, &evt->events_to_get); spin_unlock_irqrestore(&phba->ct_ev_lock, flags); @@ -1845,7 +1848,7 @@ err_get_xri_exit: kfree(dmabuf); } - if (cmdiocbq && (ret_val != IOCB_TIMEDOUT)) + if (cmdiocbq && (iocb_stat != IOCB_TIMEDOUT)) lpfc_sli_release_iocbq(phba, cmdiocbq); if (rspiocbq) lpfc_sli_release_iocbq(phba, rspiocbq); @@ -1959,6 +1962,7 @@ static int lpfcdiag_loop_post_rxbufs(struct lpfc_hba *phba, uint16_t rxxri, uint32_t num_bde; struct lpfc_dmabufext *rxbuffer = NULL; int ret_val = 0; + int iocb_stat; int i = 0; cmdiocbq = lpfc_sli_get_iocbq(phba); @@ -1973,7 +1977,7 @@ static int lpfcdiag_loop_post_rxbufs(struct lpfc_hba *phba, uint16_t rxxri, } if (!cmdiocbq || !rxbmp || !rxbpl || !rxbuffer) { - ret_val = ENOMEM; + ret_val = -ENOMEM; goto err_post_rxbufs_exit; } @@ -2022,16 +2026,16 @@ static int lpfcdiag_loop_post_rxbufs(struct lpfc_hba *phba, uint16_t rxxri, cmd->ulpClass = CLASS3; cmd->ulpContext = rxxri; - ret_val = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 0); - - if (ret_val == IOCB_ERROR) { + iocb_stat = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, + 0); + if (iocb_stat == IOCB_ERROR) { diag_cmd_data_free(phba, (struct lpfc_dmabufext *)mp[0]); if (mp[1]) diag_cmd_data_free(phba, (struct lpfc_dmabufext *)mp[1]); dmp = list_entry(next, struct lpfc_dmabuf, list); - ret_val = EIO; + ret_val = -EIO; goto err_post_rxbufs_exit; } @@ -2045,7 +2049,7 @@ static int lpfcdiag_loop_post_rxbufs(struct lpfc_hba *phba, uint16_t rxxri, cmdiocbq = lpfc_sli_get_iocbq(phba); if (!cmdiocbq) { dmp = list_entry(next, struct lpfc_dmabuf, list); - ret_val = EIO; + ret_val = -EIO; goto err_post_rxbufs_exit; } @@ -2111,6 +2115,8 @@ lpfc_bsg_diag_test(struct fc_bsg_job *job) uint32_t num_bde; uint8_t *ptr = NULL, *rx_databuf = NULL; int rc = 0; + int time_left; + int iocb_stat; unsigned long flags; void *dataout = NULL; uint32_t total_mem; @@ -2185,22 +2191,18 @@ lpfc_bsg_diag_test(struct fc_bsg_job *job) ptr, size); rc = lpfcdiag_loop_self_reg(phba, &rpi); - if (rc) { - rc = -ENOMEM; + if (rc) goto loopback_test_exit; - } rc = lpfcdiag_loop_get_xri(phba, rpi, &txxri, &rxxri); if (rc) { lpfcdiag_loop_self_unreg(phba, rpi); - rc = -ENOMEM; goto loopback_test_exit; } rc = lpfcdiag_loop_post_rxbufs(phba, rxxri, full_size); if (rc) { lpfcdiag_loop_self_unreg(phba, rpi); - rc = -ENOMEM; goto loopback_test_exit; } @@ -2290,21 +2292,22 @@ lpfc_bsg_diag_test(struct fc_bsg_job *job) cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; cmdiocbq->vport = phba->pport; - rc = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq, rspiocbq, - (phba->fc_ratov * 2) + LPFC_DRVR_TIMEOUT); + iocb_stat = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq, + rspiocbq, (phba->fc_ratov * 2) + + LPFC_DRVR_TIMEOUT); - if ((rc != IOCB_SUCCESS) || (rsp->ulpStatus != IOCB_SUCCESS)) { + if ((iocb_stat != IOCB_SUCCESS) || (rsp->ulpStatus != IOCB_SUCCESS)) { rc = -EIO; goto err_loopback_test_exit; } evt->waiting = 1; - rc = wait_event_interruptible_timeout( + time_left = wait_event_interruptible_timeout( evt->wq, !list_empty(&evt->events_to_see), ((phba->fc_ratov * 2) + LPFC_DRVR_TIMEOUT) * HZ); evt->waiting = 0; if (list_empty(&evt->events_to_see)) - rc = (rc) ? -EINTR : -ETIMEDOUT; + rc = (time_left) ? -EINTR : -ETIMEDOUT; else { spin_lock_irqsave(&phba->ct_ev_lock, flags); list_move(evt->events_to_see.prev, &evt->events_to_get); @@ -2470,6 +2473,17 @@ lpfc_bsg_wake_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) to += sizeof(MAILBOX_t); size = pmboxq->u.mb.un.varWords[5]; memcpy(to, from, size); + } else if ((phba->sli_rev == LPFC_SLI_REV4) && + (pmboxq->u.mb.mbxCommand == MBX_SLI4_CONFIG)) { + struct lpfc_mbx_nembed_cmd *nembed_sge = + (struct lpfc_mbx_nembed_cmd *) + &pmboxq->u.mb.un.varWords[0]; + + from = (uint8_t *)dd_data->context_un.mbox.dmp->dma. + virt; + to += sizeof(MAILBOX_t); + size = nembed_sge->sge[0].length; + memcpy(to, from, size); } else if (pmboxq->u.mb.mbxCommand == MBX_READ_EVENT_LOG) { from = (uint8_t *)dd_data->context_un. mbox.dmp->dma.virt; @@ -2911,6 +2925,59 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job, from += sizeof(MAILBOX_t); memcpy((uint8_t *)dmp->dma.virt, from, bde->tus.f.bdeSize); + } else if (pmb->mbxCommand == MBX_SLI4_CONFIG) { + struct lpfc_mbx_nembed_cmd *nembed_sge; + struct mbox_header *header; + uint32_t receive_length; + + /* rebuild the command for sli4 using our own buffers + * like we do for biu diags + */ + header = (struct mbox_header *)&pmb->un.varWords[0]; + nembed_sge = (struct lpfc_mbx_nembed_cmd *) + &pmb->un.varWords[0]; + receive_length = nembed_sge->sge[0].length; + + /* receive length cannot be greater than mailbox + * extension size + */ + if ((receive_length == 0) || + (receive_length > MAILBOX_EXT_SIZE)) { + rc = -ERANGE; + goto job_done; + } + + rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); + if (!rxbmp) { + rc = -ENOMEM; + goto job_done; + } + + rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys); + if (!rxbmp->virt) { + rc = -ENOMEM; + goto job_done; + } + + INIT_LIST_HEAD(&rxbmp->list); + rxbpl = (struct ulp_bde64 *) rxbmp->virt; + dmp = diag_cmd_data_alloc(phba, rxbpl, receive_length, + 0); + if (!dmp) { + rc = -ENOMEM; + goto job_done; + } + + INIT_LIST_HEAD(&dmp->dma.list); + nembed_sge->sge[0].pa_hi = putPaddrHigh(dmp->dma.phys); + nembed_sge->sge[0].pa_lo = putPaddrLow(dmp->dma.phys); + /* copy the transmit data found in the mailbox + * extension area + */ + from = (uint8_t *)mb; + from += sizeof(MAILBOX_t); + memcpy((uint8_t *)dmp->dma.virt, from, + header->cfg_mhdr.payload_length); } } diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 8d09191c327e..e6ca12f6c6cb 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -3250,6 +3250,8 @@ lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) lpfc_sli4_free_rpi(phba, pmb->u.mb.un.varUnregLogin.rpi); pmb->context1 = NULL; + pmb->context2 = NULL; + lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); mempool_free(pmb, phba->mbox_mem_pool); diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 1f62ea8c165d..c3d7174e3469 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -1015,7 +1015,6 @@ static void lpfc_mbx_cmpl_reg_fcfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) { struct lpfc_vport *vport = mboxq->vport; - unsigned long flags; if (mboxq->u.mb.mbxStatus) { lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, @@ -1029,18 +1028,18 @@ lpfc_mbx_cmpl_reg_fcfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) /* Start FCoE discovery by sending a FLOGI. */ phba->fcf.fcfi = bf_get(lpfc_reg_fcfi_fcfi, &mboxq->u.mqe.un.reg_fcfi); /* Set the FCFI registered flag */ - spin_lock_irqsave(&phba->hbalock, flags); + spin_lock_irq(&phba->hbalock); phba->fcf.fcf_flag |= FCF_REGISTERED; - spin_unlock_irqrestore(&phba->hbalock, flags); + spin_unlock_irq(&phba->hbalock); /* If there is a pending FCoE event, restart FCF table scan. */ if (lpfc_check_pending_fcoe_event(phba, 1)) { mempool_free(mboxq, phba->mbox_mem_pool); return; } - spin_lock_irqsave(&phba->hbalock, flags); + spin_lock_irq(&phba->hbalock); phba->fcf.fcf_flag |= (FCF_SCAN_DONE | FCF_IN_USE); phba->hba_flag &= ~FCF_DISC_INPROGRESS; - spin_unlock_irqrestore(&phba->hbalock, flags); + spin_unlock_irq(&phba->hbalock); if (vport->port_state != LPFC_FLOGI) lpfc_initial_flogi(vport); @@ -1240,14 +1239,13 @@ lpfc_register_fcf(struct lpfc_hba *phba) { LPFC_MBOXQ_t *fcf_mbxq; int rc; - unsigned long flags; - spin_lock_irqsave(&phba->hbalock, flags); + spin_lock_irq(&phba->hbalock); /* If the FCF is not availabe do nothing. */ if (!(phba->fcf.fcf_flag & FCF_AVAILABLE)) { phba->hba_flag &= ~FCF_DISC_INPROGRESS; - spin_unlock_irqrestore(&phba->hbalock, flags); + spin_unlock_irq(&phba->hbalock); return; } @@ -1255,19 +1253,19 @@ lpfc_register_fcf(struct lpfc_hba *phba) if (phba->fcf.fcf_flag & FCF_REGISTERED) { phba->fcf.fcf_flag |= (FCF_SCAN_DONE | FCF_IN_USE); phba->hba_flag &= ~FCF_DISC_INPROGRESS; - spin_unlock_irqrestore(&phba->hbalock, flags); + spin_unlock_irq(&phba->hbalock); if (phba->pport->port_state != LPFC_FLOGI) lpfc_initial_flogi(phba->pport); return; } - spin_unlock_irqrestore(&phba->hbalock, flags); + spin_unlock_irq(&phba->hbalock); fcf_mbxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!fcf_mbxq) { - spin_lock_irqsave(&phba->hbalock, flags); + spin_lock_irq(&phba->hbalock); phba->hba_flag &= ~FCF_DISC_INPROGRESS; - spin_unlock_irqrestore(&phba->hbalock, flags); + spin_unlock_irq(&phba->hbalock); return; } @@ -1276,9 +1274,9 @@ lpfc_register_fcf(struct lpfc_hba *phba) fcf_mbxq->mbox_cmpl = lpfc_mbx_cmpl_reg_fcfi; rc = lpfc_sli_issue_mbox(phba, fcf_mbxq, MBX_NOWAIT); if (rc == MBX_NOT_FINISHED) { - spin_lock_irqsave(&phba->hbalock, flags); + spin_lock_irq(&phba->hbalock); phba->hba_flag &= ~FCF_DISC_INPROGRESS; - spin_unlock_irqrestore(&phba->hbalock, flags); + spin_unlock_irq(&phba->hbalock); mempool_free(fcf_mbxq, phba->mbox_mem_pool); } @@ -2851,6 +2849,7 @@ lpfc_mbx_cmpl_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) struct Scsi_Host *shost = lpfc_shost_from_vport(vport); pmb->context1 = NULL; + pmb->context2 = NULL; if (ndlp->nlp_flag & NLP_REG_LOGIN_SEND) ndlp->nlp_flag &= ~NLP_REG_LOGIN_SEND; @@ -3149,6 +3148,7 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) ndlp = (struct lpfc_nodelist *) pmb->context2; pmb->context1 = NULL; pmb->context2 = NULL; + if (mb->mbxStatus) { lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, "0258 Register Fabric login error: 0x%x\n", @@ -3218,6 +3218,9 @@ lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2; struct lpfc_vport *vport = pmb->vport; + pmb->context1 = NULL; + pmb->context2 = NULL; + if (mb->mbxStatus) { out: lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, @@ -3249,8 +3252,6 @@ out: return; } - pmb->context1 = NULL; - ndlp->nlp_rpi = mb->un.varWords[0]; ndlp->nlp_flag |= NLP_RPI_VALID; ndlp->nlp_type |= NLP_FABRIC; @@ -4784,6 +4785,7 @@ lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) struct lpfc_vport *vport = pmb->vport; pmb->context1 = NULL; + pmb->context2 = NULL; ndlp->nlp_rpi = mb->un.varWords[0]; ndlp->nlp_flag |= NLP_RPI_VALID; diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index 1676f61291e7..a631647051d9 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -1380,6 +1380,9 @@ typedef struct { /* FireFly BIU registers */ #define MBX_INIT_VFI 0xA3 #define MBX_INIT_VPI 0xA4 +#define MBX_AUTH_PORT 0xF8 +#define MBX_SECURITY_MGMT 0xF9 + /* IOCB Commands */ #define CMD_RCV_SEQUENCE_CX 0x01 @@ -1502,7 +1505,8 @@ typedef struct { /* FireFly BIU registers */ #define MBXERR_DMA_ERROR 15 #define MBXERR_ERROR 16 #define MBXERR_LINK_DOWN 0x33 -#define MBX_NOT_FINISHED 255 +#define MBXERR_SEC_NO_PERMISSION 0xF02 +#define MBX_NOT_FINISHED 255 #define MBX_BUSY 0xffffff /* Attempted cmd to busy Mailbox */ #define MBX_TIMEOUT 0xfffffe /* time-out expired waiting for */ diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index da9ba06ad583..295c7ddb36c1 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -1076,21 +1076,16 @@ lpfc_hb_timeout_handler(struct lpfc_hba *phba) } else { /* * If heart beat timeout called with hb_outstanding set - * we need to take the HBA offline. + * we need to give the hb mailbox cmd a chance to + * complete or TMO. */ - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0459 Adapter heartbeat failure, " - "taking this port offline.\n"); - - spin_lock_irq(&phba->hbalock); - psli->sli_flag &= ~LPFC_SLI_ACTIVE; - spin_unlock_irq(&phba->hbalock); - - lpfc_offline_prep(phba); - lpfc_offline(phba); - lpfc_unblock_mgmt_io(phba); - phba->link_state = LPFC_HBA_ERROR; - lpfc_hba_down_post(phba); + lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, + "0459 Adapter heartbeat still out" + "standing:last compl time was %d ms.\n", + jiffies_to_msecs(jiffies + - phba->last_completion_time)); + mod_timer(&phba->hb_tmofunc, + jiffies + HZ * LPFC_HB_MBOX_TIMEOUT); } } } @@ -1277,13 +1272,21 @@ lpfc_handle_eratt_s3(struct lpfc_hba *phba) if (phba->hba_flag & DEFER_ERATT) lpfc_handle_deferred_eratt(phba); - if (phba->work_hs & HS_FFER6) { - /* Re-establishing Link */ - lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT, - "1301 Re-establishing Link " - "Data: x%x x%x x%x\n", - phba->work_hs, - phba->work_status[0], phba->work_status[1]); + if ((phba->work_hs & HS_FFER6) || (phba->work_hs & HS_FFER8)) { + if (phba->work_hs & HS_FFER6) + /* Re-establishing Link */ + lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT, + "1301 Re-establishing Link " + "Data: x%x x%x x%x\n", + phba->work_hs, phba->work_status[0], + phba->work_status[1]); + if (phba->work_hs & HS_FFER8) + /* Device Zeroization */ + lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT, + "2861 Host Authentication device " + "zeroization Data:x%x x%x x%x\n", + phba->work_hs, phba->work_status[0], + phba->work_status[1]); spin_lock_irq(&phba->hbalock); psli->sli_flag &= ~LPFC_SLI_ACTIVE; @@ -2817,6 +2820,8 @@ void lpfc_host_attrib_init(struct Scsi_Host *shost) (((uint32_t) vport->fc_sparam.cmn.bbRcvSizeMsb & 0x0F) << 8) | (uint32_t) vport->fc_sparam.cmn.bbRcvSizeLsb; + fc_host_dev_loss_tmo(shost) = vport->cfg_devloss_tmo; + /* This value is also unchanging */ memset(fc_host_active_fc4s(shost), 0, sizeof(fc_host_active_fc4s(shost))); @@ -2883,65 +2888,6 @@ lpfc_stop_port(struct lpfc_hba *phba) } /** - * lpfc_sli4_remove_dflt_fcf - Remove the driver default fcf record from the port. - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to remove the driver default fcf record from - * the port. This routine currently acts on FCF Index 0. - * - **/ -void -lpfc_sli_remove_dflt_fcf(struct lpfc_hba *phba) -{ - int rc = 0; - LPFC_MBOXQ_t *mboxq; - struct lpfc_mbx_del_fcf_tbl_entry *del_fcf_record; - uint32_t mbox_tmo, req_len; - uint32_t shdr_status, shdr_add_status; - - mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mboxq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2020 Failed to allocate mbox for ADD_FCF cmd\n"); - return; - } - - req_len = sizeof(struct lpfc_mbx_del_fcf_tbl_entry) - - sizeof(struct lpfc_sli4_cfg_mhdr); - rc = lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_FCOE, - LPFC_MBOX_OPCODE_FCOE_DELETE_FCF, - req_len, LPFC_SLI4_MBX_EMBED); - /* - * In phase 1, there is a single FCF index, 0. In phase2, the driver - * supports multiple FCF indices. - */ - del_fcf_record = &mboxq->u.mqe.un.del_fcf_entry; - bf_set(lpfc_mbx_del_fcf_tbl_count, del_fcf_record, 1); - bf_set(lpfc_mbx_del_fcf_tbl_index, del_fcf_record, - phba->fcf.current_rec.fcf_indx); - - if (!phba->sli4_hba.intr_enable) - rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); - else { - mbox_tmo = lpfc_mbox_tmo_val(phba, MBX_SLI4_CONFIG); - rc = lpfc_sli_issue_mbox_wait(phba, mboxq, mbox_tmo); - } - /* The IOCTL status is embedded in the mailbox subheader. */ - shdr_status = bf_get(lpfc_mbox_hdr_status, - &del_fcf_record->header.cfg_shdr.response); - shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, - &del_fcf_record->header.cfg_shdr.response); - if (shdr_status || shdr_add_status || rc != MBX_SUCCESS) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2516 DEL FCF of default FCF Index failed " - "mbx status x%x, status x%x add_status x%x\n", - rc, shdr_status, shdr_add_status); - } - if (rc != MBX_TIMEOUT) - mempool_free(mboxq, phba->mbox_mem_pool); -} - -/** * lpfc_fcf_redisc_wait_start_timer - Start fcf rediscover wait timer * @phba: Pointer to hba for which this call is being executed. * @@ -4283,12 +4229,6 @@ lpfc_sli4_driver_resource_unset(struct lpfc_hba *phba) { struct lpfc_fcf_conn_entry *conn_entry, *next_conn_entry; - /* unregister default FCFI from the HBA */ - lpfc_sli4_fcfi_unreg(phba, phba->fcf.fcfi); - - /* Free the default FCR table */ - lpfc_sli_remove_dflt_fcf(phba); - /* Free memory allocated for msi-x interrupt vector entries */ kfree(phba->sli4_hba.msix_entries); @@ -4316,9 +4256,6 @@ lpfc_sli4_driver_resource_unset(struct lpfc_hba *phba) lpfc_sli4_cq_event_release_all(phba); lpfc_sli4_cq_event_pool_destroy(phba); - /* Reset SLI4 HBA FCoE function */ - lpfc_pci_function_reset(phba); - /* Free the bsmbx region. */ lpfc_destroy_bootstrap_mbox(phba); @@ -4545,7 +4482,6 @@ lpfc_free_sgl_list(struct lpfc_hba *phba) { struct lpfc_sglq *sglq_entry = NULL, *sglq_next = NULL; LIST_HEAD(sglq_list); - int rc = 0; spin_lock_irq(&phba->hbalock); list_splice_init(&phba->sli4_hba.lpfc_sgl_list, &sglq_list); @@ -4558,11 +4494,6 @@ lpfc_free_sgl_list(struct lpfc_hba *phba) kfree(sglq_entry); phba->sli4_hba.total_sglq_bufs--; } - rc = lpfc_sli4_remove_all_sgl_pages(phba); - if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2005 Unable to deregister pages from HBA: %x\n", rc); - } kfree(phba->sli4_hba.lpfc_els_sgl_array); } @@ -4725,8 +4656,8 @@ out_free_mem: * * Return codes * 0 - successful - * ENOMEM - No availble memory - * EIO - The mailbox failed to complete successfully. + * -ENOMEM - No availble memory + * -EIO - The mailbox failed to complete successfully. **/ int lpfc_sli4_init_rpi_hdrs(struct lpfc_hba *phba) @@ -5419,7 +5350,7 @@ lpfc_sli4_bar2_register_memmap(struct lpfc_hba *phba, uint32_t vf) * * Return codes * 0 - successful - * ENOMEM - could not allocated memory. + * -ENOMEM - could not allocated memory. **/ static int lpfc_create_bootstrap_mbox(struct lpfc_hba *phba) @@ -5518,8 +5449,8 @@ lpfc_destroy_bootstrap_mbox(struct lpfc_hba *phba) * * Return codes * 0 - successful - * ENOMEM - No availble memory - * EIO - The mailbox failed to complete successfully. + * -ENOMEM - No availble memory + * -EIO - The mailbox failed to complete successfully. **/ static int lpfc_sli4_read_config(struct lpfc_hba *phba) @@ -5622,8 +5553,8 @@ lpfc_sli4_read_config(struct lpfc_hba *phba) * * Return codes * 0 - successful - * ENOMEM - No availble memory - * EIO - The mailbox failed to complete successfully. + * -ENOMEM - No availble memory + * -EIO - The mailbox failed to complete successfully. **/ static int lpfc_setup_endian_order(struct lpfc_hba *phba) @@ -5671,8 +5602,8 @@ lpfc_setup_endian_order(struct lpfc_hba *phba) * * Return codes * 0 - successful - * ENOMEM - No availble memory - * EIO - The mailbox failed to complete successfully. + * -ENOMEM - No availble memory + * -EIO - The mailbox failed to complete successfully. **/ static int lpfc_sli4_queue_create(struct lpfc_hba *phba) @@ -5966,8 +5897,8 @@ out_error: * * Return codes * 0 - successful - * ENOMEM - No availble memory - * EIO - The mailbox failed to complete successfully. + * -ENOMEM - No availble memory + * -EIO - The mailbox failed to complete successfully. **/ static void lpfc_sli4_queue_destroy(struct lpfc_hba *phba) @@ -6030,8 +5961,8 @@ lpfc_sli4_queue_destroy(struct lpfc_hba *phba) * * Return codes * 0 - successful - * ENOMEM - No availble memory - * EIO - The mailbox failed to complete successfully. + * -ENOMEM - No availble memory + * -EIO - The mailbox failed to complete successfully. **/ int lpfc_sli4_queue_setup(struct lpfc_hba *phba) @@ -6275,8 +6206,8 @@ out_error: * * Return codes * 0 - successful - * ENOMEM - No availble memory - * EIO - The mailbox failed to complete successfully. + * -ENOMEM - No availble memory + * -EIO - The mailbox failed to complete successfully. **/ void lpfc_sli4_queue_unset(struct lpfc_hba *phba) @@ -6481,8 +6412,8 @@ lpfc_sli4_cq_event_release_all(struct lpfc_hba *phba) * * Return codes * 0 - successful - * ENOMEM - No availble memory - * EIO - The mailbox failed to complete successfully. + * -ENOMEM - No availble memory + * -EIO - The mailbox failed to complete successfully. **/ int lpfc_pci_function_reset(struct lpfc_hba *phba) @@ -6592,50 +6523,6 @@ lpfc_sli4_send_nop_mbox_cmds(struct lpfc_hba *phba, uint32_t cnt) } /** - * lpfc_sli4_fcfi_unreg - Unregister fcfi to device - * @phba: pointer to lpfc hba data structure. - * @fcfi: fcf index. - * - * This routine is invoked to unregister a FCFI from device. - **/ -void -lpfc_sli4_fcfi_unreg(struct lpfc_hba *phba, uint16_t fcfi) -{ - LPFC_MBOXQ_t *mbox; - uint32_t mbox_tmo; - int rc; - unsigned long flags; - - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - - if (!mbox) - return; - - lpfc_unreg_fcfi(mbox, fcfi); - - if (!phba->sli4_hba.intr_enable) - rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); - else { - mbox_tmo = lpfc_mbox_tmo_val(phba, MBX_SLI4_CONFIG); - rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo); - } - if (rc != MBX_TIMEOUT) - mempool_free(mbox, phba->mbox_mem_pool); - if (rc != MBX_SUCCESS) - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2517 Unregister FCFI command failed " - "status %d, mbxStatus x%x\n", rc, - bf_get(lpfc_mqe_status, &mbox->u.mqe)); - else { - spin_lock_irqsave(&phba->hbalock, flags); - /* Mark the FCFI is no longer registered */ - phba->fcf.fcf_flag &= - ~(FCF_AVAILABLE | FCF_REGISTERED | FCF_SCAN_DONE); - spin_unlock_irqrestore(&phba->hbalock, flags); - } -} - -/** * lpfc_sli4_pci_mem_setup - Setup SLI4 HBA PCI memory space. * @phba: pointer to lpfc hba data structure. * @@ -7372,10 +7259,14 @@ lpfc_sli4_unset_hba(struct lpfc_hba *phba) phba->pport->work_port_events = 0; - lpfc_sli4_hba_down(phba); + /* Stop the SLI4 device port */ + lpfc_stop_port(phba); lpfc_sli4_disable_intr(phba); + /* Reset SLI4 HBA FCoE function */ + lpfc_pci_function_reset(phba); + return; } @@ -7424,15 +7315,15 @@ lpfc_sli4_hba_unset(struct lpfc_hba *phba) spin_unlock_irq(&phba->hbalock); } - /* Tear down the queues in the HBA */ - lpfc_sli4_queue_unset(phba); - /* Disable PCI subsystem interrupt */ lpfc_sli4_disable_intr(phba); /* Stop kthread signal shall trigger work_done one more time */ kthread_stop(phba->worker_thread); + /* Reset SLI4 HBA FCoE function */ + lpfc_pci_function_reset(phba); + /* Stop the SLI4 device port */ phba->pport->work_port_events = 0; } @@ -8368,7 +8259,7 @@ lpfc_pci_remove_one_s4(struct pci_dev *pdev) list_del_init(&vport->listentry); spin_unlock_irq(&phba->hbalock); - /* Call scsi_free before lpfc_sli4_driver_resource_unset since scsi + /* Perform scsi free before driver resource_unset since scsi * buffers are released to their corresponding pools here. */ lpfc_scsi_free(phba); diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 2e51aa6b45b3..3a658953486c 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -599,6 +599,7 @@ lpfc_new_scsi_buf_s3(struct lpfc_vport *vport, int num_to_alloc) iocb->ulpClass = CLASS3; psb->status = IOSTAT_SUCCESS; /* Put it back into the SCSI buffer list */ + psb->cur_iocbq.context1 = psb; lpfc_release_scsi_buf_s3(phba, psb); } @@ -849,6 +850,7 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc) iocb->ulpBdeCount = 1; iocb->ulpLe = 1; iocb->ulpClass = CLASS3; + psb->cur_iocbq.context1 = psb; if (phba->cfg_sg_dma_buf_size > SGL_PAGE_SIZE) pdma_phys_bpl1 = pdma_phys_bpl + SGL_PAGE_SIZE; else @@ -2276,15 +2278,24 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, * Check SLI validation that all the transfer was actually done * (fcpi_parm should be zero). Apply check only to reads. */ - } else if ((scsi_status == SAM_STAT_GOOD) && fcpi_parm && - (cmnd->sc_data_direction == DMA_FROM_DEVICE)) { + } else if (fcpi_parm && (cmnd->sc_data_direction == DMA_FROM_DEVICE)) { lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP | LOG_FCP_ERROR, "9029 FCP Read Check Error Data: " - "x%x x%x x%x x%x\n", + "x%x x%x x%x x%x x%x\n", be32_to_cpu(fcpcmd->fcpDl), be32_to_cpu(fcprsp->rspResId), - fcpi_parm, cmnd->cmnd[0]); - host_status = DID_ERROR; + fcpi_parm, cmnd->cmnd[0], scsi_status); + switch (scsi_status) { + case SAM_STAT_GOOD: + case SAM_STAT_CHECK_CONDITION: + /* Fabric dropped a data frame. Fail any successful + * command in which we detected dropped frames. + * A status of good or some check conditions could + * be considered a successful command. + */ + host_status = DID_ERROR; + break; + } scsi_set_resid(cmnd, scsi_bufflen(cmnd)); } @@ -3072,7 +3083,14 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) if (ret) return ret; lpfc_cmd = (struct lpfc_scsi_buf *)cmnd->host_scribble; - BUG_ON(!lpfc_cmd); + if (!lpfc_cmd) { + lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, + "2873 SCSI Layer I/O Abort Request IO CMPL Status " + "x%x ID %d " + "LUN %d snum %#lx\n", ret, cmnd->device->id, + cmnd->device->lun, cmnd->serial_number); + return SUCCESS; + } /* * If pCmd field of the corresponding lpfc_scsi_buf structure @@ -3656,7 +3674,6 @@ lpfc_slave_alloc(struct scsi_device *sdev) * * This routine configures following items * - Tag command queuing support for @sdev if supported. - * - Dev loss time out value of fc_rport. * - Enable SLI polling for fcp ring if ENABLE_FCP_RING_POLLING flag is set. * * Return codes: @@ -3667,21 +3684,12 @@ lpfc_slave_configure(struct scsi_device *sdev) { struct lpfc_vport *vport = (struct lpfc_vport *) sdev->host->hostdata; struct lpfc_hba *phba = vport->phba; - struct fc_rport *rport = starget_to_rport(sdev->sdev_target); if (sdev->tagged_supported) scsi_activate_tcq(sdev, vport->cfg_lun_queue_depth); else scsi_deactivate_tcq(sdev, vport->cfg_lun_queue_depth); - /* - * Initialize the fc transport attributes for the target - * containing this scsi device. Also note that the driver's - * target pointer is stored in the starget_data for the - * driver's sysfs entry point functions. - */ - rport->dev_loss_tmo = vport->cfg_devloss_tmo; - if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) { lpfc_sli_handle_fast_ring_event(phba, &phba->sli.ring[LPFC_FCP_RING], HA_R0RE_REQ); diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index fb8905f893f5..0d1e187b005d 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -1677,6 +1677,8 @@ lpfc_sli_chk_mbx_command(uint8_t mbxCommand) case MBX_RESUME_RPI: case MBX_READ_EVENT_LOG_STATUS: case MBX_READ_EVENT_LOG: + case MBX_SECURITY_MGMT: + case MBX_AUTH_PORT: ret = mbxCommand; break; default: @@ -1730,10 +1732,11 @@ lpfc_sli_wake_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) void lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { + struct lpfc_vport *vport = pmb->vport; struct lpfc_dmabuf *mp; + struct lpfc_nodelist *ndlp; uint16_t rpi, vpi; int rc; - struct lpfc_vport *vport = pmb->vport; mp = (struct lpfc_dmabuf *) (pmb->context1); @@ -1774,6 +1777,19 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) return; } + if (pmb->u.mb.mbxCommand == MBX_REG_LOGIN64) { + ndlp = (struct lpfc_nodelist *)pmb->context2; + lpfc_nlp_put(ndlp); + pmb->context2 = NULL; + } + + /* Check security permission status on INIT_LINK mailbox command */ + if ((pmb->u.mb.mbxCommand == MBX_INIT_LINK) && + (pmb->u.mb.mbxStatus == MBXERR_SEC_NO_PERMISSION)) + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + "2860 SLI authentication is required " + "for INIT_LINK but has not done yet\n"); + if (bf_get(lpfc_mqe_command, &pmb->u.mqe) == MBX_SLI4_CONFIG) lpfc_sli4_mbox_cmd_free(phba, pmb); else @@ -3651,11 +3667,15 @@ lpfc_sli_chipset_init(struct lpfc_hba *phba) i = 0; while ((status & (HS_FFRDY | HS_MBRDY)) != (HS_FFRDY | HS_MBRDY)) { - /* Check every 100ms for 5 retries, then every 500ms for 5, then - * every 2.5 sec for 5, then reset board and every 2.5 sec for - * 4. + /* Check every 10ms for 10 retries, then every 100ms for 90 + * retries, then every 1 sec for 50 retires for a total of + * ~60 seconds before reset the board again and check every + * 1 sec for 50 retries. The up to 60 seconds before the + * board ready is required by the Falcon FIPS zeroization + * complete, and any reset the board in between shall cause + * restart of zeroization, further delay the board ready. */ - if (i++ >= 20) { + if (i++ >= 200) { /* Adapter failed to init, timeout, status reg <status> */ lpfc_printf_log(phba, KERN_ERR, LOG_INIT, @@ -3683,16 +3703,15 @@ lpfc_sli_chipset_init(struct lpfc_hba *phba) return -EIO; } - if (i <= 5) { + if (i <= 10) msleep(10); - } else if (i <= 10) { - msleep(500); - } else { - msleep(2500); - } + else if (i <= 100) + msleep(100); + else + msleep(1000); - if (i == 15) { - /* Do post */ + if (i == 150) { + /* Do post */ phba->pport->port_state = LPFC_VPORT_UNKNOWN; lpfc_sli_brdrestart(phba); } @@ -4186,7 +4205,7 @@ lpfc_sli4_read_fcoe_params(struct lpfc_hba *phba, * * Return codes * 0 - successful - * ENOMEM - could not allocated memory. + * -ENOMEM - could not allocated memory. **/ static int lpfc_sli4_read_rev(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq, @@ -5943,6 +5962,8 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, uint8_t command_type = ELS_COMMAND_NON_FIP; uint8_t cmnd; uint16_t xritag; + uint16_t abrt_iotag; + struct lpfc_iocbq *abrtiocbq; struct ulp_bde64 *bpl = NULL; uint32_t els_id = ELS_ID_DEFAULT; int numBdes, i; @@ -6155,9 +6176,17 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, case CMD_ABORT_XRI_CX: /* words 0-2 memcpy should be 0 rserved */ /* port will send abts */ - if (iocbq->iocb.ulpCommand == CMD_CLOSE_XRI_CN) + abrt_iotag = iocbq->iocb.un.acxri.abortContextTag; + if (abrt_iotag != 0 && abrt_iotag <= phba->sli.last_iotag) { + abrtiocbq = phba->sli.iocbq_lookup[abrt_iotag]; + fip = abrtiocbq->iocb_flag & LPFC_FIP_ELS_ID_MASK; + } else + fip = 0; + + if ((iocbq->iocb.ulpCommand == CMD_CLOSE_XRI_CN) || fip) /* - * The link is down so the fw does not need to send abts + * The link is down, or the command was ELS_FIP + * so the fw does not need to send abts * on the wire. */ bf_set(abort_cmd_ia, &wqe->abort_cmd, 1); @@ -6901,37 +6930,6 @@ lpfc_sli_hba_down(struct lpfc_hba *phba) } /** - * lpfc_sli4_hba_down - PCI function resource cleanup for the SLI4 HBA - * @phba: Pointer to HBA context object. - * - * This function cleans up all queues, iocb, buffers, mailbox commands while - * shutting down the SLI4 HBA FCoE function. This function is called with no - * lock held and always returns 1. - * - * This function does the following to cleanup driver FCoE function resources: - * - Free discovery resources for each virtual port - * - Cleanup any pending fabric iocbs - * - Iterate through the iocb txq and free each entry in the list. - * - Free up any buffer posted to the HBA. - * - Clean up all the queue entries: WQ, RQ, MQ, EQ, CQ, etc. - * - Free mailbox commands in the mailbox queue. - **/ -int -lpfc_sli4_hba_down(struct lpfc_hba *phba) -{ - /* Stop the SLI4 device port */ - lpfc_stop_port(phba); - - /* Tear down the queues in the HBA */ - lpfc_sli4_queue_unset(phba); - - /* unregister default FCFI from the HBA */ - lpfc_sli4_fcfi_unreg(phba, phba->fcf.fcfi); - - return 1; -} - -/** * lpfc_sli_pcimem_bcopy - SLI memory copy function * @srcp: Source memory pointer. * @destp: Destination memory pointer. @@ -7888,7 +7886,7 @@ lpfc_sli_eratt_read(struct lpfc_hba *phba) /* Check if there is a deferred error condition is active */ if ((HS_FFER1 & phba->work_hs) && ((HS_FFER2 | HS_FFER3 | HS_FFER4 | HS_FFER5 | - HS_FFER6 | HS_FFER7) & phba->work_hs)) { + HS_FFER6 | HS_FFER7 | HS_FFER8) & phba->work_hs)) { phba->hba_flag |= DEFER_ERATT; /* Clear all interrupt enable conditions */ writel(0, phba->HCregaddr); @@ -8204,7 +8202,8 @@ lpfc_sli_sp_intr_handler(int irq, void *dev_id) */ if ((HS_FFER1 & phba->work_hs) && ((HS_FFER2 | HS_FFER3 | HS_FFER4 | HS_FFER5 | - HS_FFER6 | HS_FFER7) & phba->work_hs)) { + HS_FFER6 | HS_FFER7 | HS_FFER8) & + phba->work_hs)) { phba->hba_flag |= DEFER_ERATT; /* Clear all interrupt enable conditions */ writel(0, phba->HCregaddr); @@ -8476,7 +8475,7 @@ lpfc_sli_intr_handler(int irq, void *dev_id) * If there is deferred error attention, do not check for any interrupt. */ if (unlikely(phba->hba_flag & DEFER_ERATT)) { - spin_unlock_irq(&phba->hbalock); + spin_unlock(&phba->hbalock); return IRQ_NONE; } @@ -9724,8 +9723,8 @@ out_fail: * command to finish before continuing. * * On success this function will return a zero. If unable to allocate enough - * memory this function will return ENOMEM. If the queue create mailbox command - * fails this function will return ENXIO. + * memory this function will return -ENOMEM. If the queue create mailbox command + * fails this function will return -ENXIO. **/ uint32_t lpfc_eq_create(struct lpfc_hba *phba, struct lpfc_queue *eq, uint16_t imax) @@ -9840,8 +9839,8 @@ lpfc_eq_create(struct lpfc_hba *phba, struct lpfc_queue *eq, uint16_t imax) * command to finish before continuing. * * On success this function will return a zero. If unable to allocate enough - * memory this function will return ENOMEM. If the queue create mailbox command - * fails this function will return ENXIO. + * memory this function will return -ENOMEM. If the queue create mailbox command + * fails this function will return -ENXIO. **/ uint32_t lpfc_cq_create(struct lpfc_hba *phba, struct lpfc_queue *cq, @@ -10011,8 +10010,8 @@ lpfc_mq_create_fb_init(struct lpfc_hba *phba, struct lpfc_queue *mq, * command to finish before continuing. * * On success this function will return a zero. If unable to allocate enough - * memory this function will return ENOMEM. If the queue create mailbox command - * fails this function will return ENXIO. + * memory this function will return -ENOMEM. If the queue create mailbox command + * fails this function will return -ENXIO. **/ int32_t lpfc_mq_create(struct lpfc_hba *phba, struct lpfc_queue *mq, @@ -10146,8 +10145,8 @@ out: * command to finish before continuing. * * On success this function will return a zero. If unable to allocate enough - * memory this function will return ENOMEM. If the queue create mailbox command - * fails this function will return ENXIO. + * memory this function will return -ENOMEM. If the queue create mailbox command + * fails this function will return -ENXIO. **/ uint32_t lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, @@ -10234,8 +10233,8 @@ out: * mailbox command to finish before continuing. * * On success this function will return a zero. If unable to allocate enough - * memory this function will return ENOMEM. If the queue create mailbox command - * fails this function will return ENXIO. + * memory this function will return -ENOMEM. If the queue create mailbox command + * fails this function will return -ENXIO. **/ uint32_t lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq, @@ -10403,7 +10402,7 @@ out: * The @eq struct is used to get the queue ID of the queue to destroy. * * On success this function will return a zero. If the queue destroy mailbox - * command fails this function will return ENXIO. + * command fails this function will return -ENXIO. **/ uint32_t lpfc_eq_destroy(struct lpfc_hba *phba, struct lpfc_queue *eq) @@ -10458,7 +10457,7 @@ lpfc_eq_destroy(struct lpfc_hba *phba, struct lpfc_queue *eq) * The @cq struct is used to get the queue ID of the queue to destroy. * * On success this function will return a zero. If the queue destroy mailbox - * command fails this function will return ENXIO. + * command fails this function will return -ENXIO. **/ uint32_t lpfc_cq_destroy(struct lpfc_hba *phba, struct lpfc_queue *cq) @@ -10511,7 +10510,7 @@ lpfc_cq_destroy(struct lpfc_hba *phba, struct lpfc_queue *cq) * The @mq struct is used to get the queue ID of the queue to destroy. * * On success this function will return a zero. If the queue destroy mailbox - * command fails this function will return ENXIO. + * command fails this function will return -ENXIO. **/ uint32_t lpfc_mq_destroy(struct lpfc_hba *phba, struct lpfc_queue *mq) @@ -10564,7 +10563,7 @@ lpfc_mq_destroy(struct lpfc_hba *phba, struct lpfc_queue *mq) * The @wq struct is used to get the queue ID of the queue to destroy. * * On success this function will return a zero. If the queue destroy mailbox - * command fails this function will return ENXIO. + * command fails this function will return -ENXIO. **/ uint32_t lpfc_wq_destroy(struct lpfc_hba *phba, struct lpfc_queue *wq) @@ -10616,7 +10615,7 @@ lpfc_wq_destroy(struct lpfc_hba *phba, struct lpfc_queue *wq) * The @rq struct is used to get the queue ID of the queue to destroy. * * On success this function will return a zero. If the queue destroy mailbox - * command fails this function will return ENXIO. + * command fails this function will return -ENXIO. **/ uint32_t lpfc_rq_destroy(struct lpfc_hba *phba, struct lpfc_queue *hrq, @@ -10758,51 +10757,6 @@ lpfc_sli4_post_sgl(struct lpfc_hba *phba, } return 0; } -/** - * lpfc_sli4_remove_all_sgl_pages - Post scatter gather list for an XRI to HBA - * @phba: The virtual port for which this call being executed. - * - * This routine will remove all of the sgl pages registered with the hba. - * - * Return codes: - * 0 - Success - * -ENXIO, -ENOMEM - Failure - **/ -int -lpfc_sli4_remove_all_sgl_pages(struct lpfc_hba *phba) -{ - LPFC_MBOXQ_t *mbox; - int rc; - uint32_t shdr_status, shdr_add_status; - union lpfc_sli4_cfg_shdr *shdr; - - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) - return -ENOMEM; - - lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE, - LPFC_MBOX_OPCODE_FCOE_REMOVE_SGL_PAGES, 0, - LPFC_SLI4_MBX_EMBED); - if (!phba->sli4_hba.intr_enable) - rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); - else - rc = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO); - /* The IOCTL status is embedded in the mailbox subheader. */ - shdr = (union lpfc_sli4_cfg_shdr *) - &mbox->u.mqe.un.sli4_config.header.cfg_shdr; - shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); - shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); - if (rc != MBX_TIMEOUT) - mempool_free(mbox, phba->mbox_mem_pool); - if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2512 REMOVE_ALL_SGL_PAGES mailbox failed with " - "status x%x add_status x%x, mbx status x%x\n", - shdr_status, shdr_add_status, rc); - rc = -ENXIO; - } - return rc; -} /** * lpfc_sli4_next_xritag - Get an xritag for the io @@ -11819,7 +11773,7 @@ lpfc_sli4_handle_received_buffer(struct lpfc_hba *phba, * * Return codes * 0 - successful - * EIO - The mailbox failed to complete successfully. + * -EIO - The mailbox failed to complete successfully. * When this error occurs, the driver is not guaranteed * to have any rpi regions posted to the device and * must either attempt to repost the regions or take a @@ -11857,8 +11811,8 @@ lpfc_sli4_post_all_rpi_hdrs(struct lpfc_hba *phba) * * Return codes * 0 - successful - * ENOMEM - No available memory - * EIO - The mailbox failed to complete successfully. + * -ENOMEM - No available memory + * -EIO - The mailbox failed to complete successfully. **/ int lpfc_sli4_post_rpi_hdr(struct lpfc_hba *phba, struct lpfc_rpi_hdr *rpi_page) @@ -12805,8 +12759,11 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport) LPFC_MBOXQ_t *mb, *nextmb; struct lpfc_dmabuf *mp; struct lpfc_nodelist *ndlp; + struct lpfc_nodelist *act_mbx_ndlp = NULL; struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + LIST_HEAD(mbox_cmd_list); + /* Clean up internally queued mailbox commands with the vport */ spin_lock_irq(&phba->hbalock); list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) { if (mb->vport != vport) @@ -12816,6 +12773,28 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport) (mb->u.mb.mbxCommand != MBX_REG_VPI)) continue; + list_del(&mb->list); + list_add_tail(&mb->list, &mbox_cmd_list); + } + /* Clean up active mailbox command with the vport */ + mb = phba->sli.mbox_active; + if (mb && (mb->vport == vport)) { + if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) || + (mb->u.mb.mbxCommand == MBX_REG_VPI)) + mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; + if (mb->u.mb.mbxCommand == MBX_REG_LOGIN64) { + act_mbx_ndlp = (struct lpfc_nodelist *)mb->context2; + /* Put reference count for delayed processing */ + act_mbx_ndlp = lpfc_nlp_get(act_mbx_ndlp); + /* Unregister the RPI when mailbox complete */ + mb->mbox_flag |= LPFC_MBX_IMED_UNREG; + } + } + spin_unlock_irq(&phba->hbalock); + + /* Release the cleaned-up mailbox commands */ + while (!list_empty(&mbox_cmd_list)) { + list_remove_head(&mbox_cmd_list, mb, LPFC_MBOXQ_t, list); if (mb->u.mb.mbxCommand == MBX_REG_LOGIN64) { if (phba->sli_rev == LPFC_SLI_REV4) __lpfc_sli4_free_rpi(phba, @@ -12826,36 +12805,24 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport) kfree(mp); } ndlp = (struct lpfc_nodelist *) mb->context2; + mb->context2 = NULL; if (ndlp) { - spin_lock_irq(shost->host_lock); + spin_lock(shost->host_lock); ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL; - spin_unlock_irq(shost->host_lock); + spin_unlock(shost->host_lock); lpfc_nlp_put(ndlp); - mb->context2 = NULL; } } - list_del(&mb->list); mempool_free(mb, phba->mbox_mem_pool); } - mb = phba->sli.mbox_active; - if (mb && (mb->vport == vport)) { - if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) || - (mb->u.mb.mbxCommand == MBX_REG_VPI)) - mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - 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; - } - /* Unregister the RPI when mailbox complete */ - mb->mbox_flag |= LPFC_MBX_IMED_UNREG; - } + + /* Release the ndlp with the cleaned-up active mailbox command */ + if (act_mbx_ndlp) { + spin_lock(shost->host_lock); + act_mbx_ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL; + spin_unlock(shost->host_lock); + lpfc_nlp_put(act_mbx_ndlp); } - spin_unlock_irq(&phba->hbalock); } /** diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index a3b24d99a2a7..a0ca572ec28b 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -481,7 +481,6 @@ struct lpfc_rpi_hdr { */ int lpfc_pci_function_reset(struct lpfc_hba *); int lpfc_sli4_hba_setup(struct lpfc_hba *); -int lpfc_sli4_hba_down(struct lpfc_hba *); int lpfc_sli4_config(struct lpfc_hba *, struct lpfcMboxq *, uint8_t, uint8_t, uint32_t, bool); void lpfc_sli4_mbox_cmd_free(struct lpfc_hba *, struct lpfcMboxq *); @@ -514,7 +513,6 @@ int lpfc_sli4_queue_setup(struct lpfc_hba *); void lpfc_sli4_queue_unset(struct lpfc_hba *); int lpfc_sli4_post_sgl(struct lpfc_hba *, dma_addr_t, dma_addr_t, uint16_t); int lpfc_sli4_repost_scsi_sgl_list(struct lpfc_hba *); -int lpfc_sli4_remove_all_sgl_pages(struct lpfc_hba *); uint16_t lpfc_sli4_next_xritag(struct lpfc_hba *); int lpfc_sli4_post_async_mbox(struct lpfc_hba *); int lpfc_sli4_post_sgl_list(struct lpfc_hba *phba); diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index 61afb3420a96..f93120e4c796 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.16" +#define LPFC_DRIVER_VERSION "8.3.17" #define LPFC_DRIVER_NAME "lpfc" #define LPFC_SP_DRIVER_HANDLER_NAME "lpfc:sp" #define LPFC_FP_DRIVER_HANDLER_NAME "lpfc:fp" diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c index 1655507a682c..a5281ce893d0 100644 --- a/drivers/scsi/lpfc/lpfc_vport.c +++ b/drivers/scsi/lpfc/lpfc_vport.c @@ -580,7 +580,9 @@ lpfc_vport_delete(struct fc_vport *fc_vport) "static vport.\n"); return VPORT_ERROR; } - + spin_lock_irq(&phba->hbalock); + vport->load_flag |= FC_UNLOADING; + spin_unlock_irq(&phba->hbalock); /* * If we are not unloading the driver then prevent the vport_delete * from happening until after this vport's discovery is finished. @@ -618,10 +620,6 @@ lpfc_vport_delete(struct fc_vport *fc_vport) scsi_host_put(shost); return VPORT_INVAL; } - spin_lock_irq(&phba->hbalock); - vport->load_flag |= FC_UNLOADING; - spin_unlock_irq(&phba->hbalock); - lpfc_free_sysfs_attr(vport); lpfc_debugfs_terminate(vport); diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index 0b6e3228610a..7ceb5cf12c6b 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -46,7 +46,7 @@ #include <linux/pci.h> #include <linux/init.h> #include <linux/dma-mapping.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/slab.h> #include <scsi/scsicam.h> @@ -62,6 +62,7 @@ MODULE_DESCRIPTION ("LSI Logic MegaRAID legacy driver"); MODULE_LICENSE ("GPL"); MODULE_VERSION(MEGARAID_MODULE_VERSION); +static DEFINE_MUTEX(megadev_mutex); static unsigned int max_cmd_per_lun = DEF_CMD_PER_LUN; module_param(max_cmd_per_lun, uint, 0); MODULE_PARM_DESC(max_cmd_per_lun, "Maximum number of commands which can be issued to a single LUN (default=DEF_CMD_PER_LUN=63)"); @@ -101,6 +102,7 @@ static const struct file_operations megadev_fops = { .owner = THIS_MODULE, .unlocked_ioctl = megadev_unlocked_ioctl, .open = megadev_open, + .llseek = noop_llseek, }; /* @@ -3282,7 +3284,6 @@ mega_init_scb(adapter_t *adapter) static int megadev_open (struct inode *inode, struct file *filep) { - cycle_kernel_lock(); /* * Only allow superuser to access private ioctl interface */ @@ -3701,9 +3702,9 @@ megadev_unlocked_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) { int ret; - lock_kernel(); + mutex_lock(&megadev_mutex); ret = megadev_ioctl(filep, cmd, arg); - unlock_kernel(); + mutex_unlock(&megadev_mutex); return ret; } diff --git a/drivers/scsi/megaraid/megaraid_mm.c b/drivers/scsi/megaraid/megaraid_mm.c index 41f82f76d884..a7008c0c24f9 100644 --- a/drivers/scsi/megaraid/megaraid_mm.c +++ b/drivers/scsi/megaraid/megaraid_mm.c @@ -16,11 +16,12 @@ */ #include <linux/sched.h> #include <linux/slab.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include "megaraid_mm.h" // Entry points for char node driver +static DEFINE_MUTEX(mraid_mm_mutex); static int mraid_mm_open(struct inode *, struct file *); static long mraid_mm_unlocked_ioctl(struct file *, uint, unsigned long); @@ -75,6 +76,7 @@ static const struct file_operations lsi_fops = { .compat_ioctl = mraid_mm_compat_ioctl, #endif .owner = THIS_MODULE, + .llseek = noop_llseek, }; static struct miscdevice megaraid_mm_dev = { @@ -98,7 +100,6 @@ mraid_mm_open(struct inode *inode, struct file *filep) */ if (!capable(CAP_SYS_ADMIN)) return (-EACCES); - cycle_kernel_lock(); return 0; } @@ -224,9 +225,9 @@ mraid_mm_unlocked_ioctl(struct file *filep, unsigned int cmd, int err; /* inconsistant: mraid_mm_compat_ioctl doesn't take the BKL */ - lock_kernel(); + mutex_lock(&mraid_mm_mutex); err = mraid_mm_ioctl(filep, cmd, arg); - unlock_kernel(); + mutex_unlock(&mraid_mm_mutex); return err; } diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c index 99e4478c3f3e..d3c9cdee292b 100644 --- a/drivers/scsi/megaraid/megaraid_sas.c +++ b/drivers/scsi/megaraid/megaraid_sas.c @@ -33,7 +33,6 @@ #include <linux/spinlock.h> #include <linux/interrupt.h> #include <linux/delay.h> -#include <linux/smp_lock.h> #include <linux/uio.h> #include <linux/slab.h> #include <asm/uaccess.h> @@ -62,6 +61,11 @@ MODULE_VERSION(MEGASAS_VERSION); MODULE_AUTHOR("megaraidlinux@lsi.com"); MODULE_DESCRIPTION("LSI MegaRAID SAS Driver"); +static int megasas_transition_to_ready(struct megasas_instance *instance); +static int megasas_get_pd_list(struct megasas_instance *instance); +static int megasas_issue_init_mfi(struct megasas_instance *instance); +static int megasas_register_aen(struct megasas_instance *instance, + u32 seq_num, u32 class_locale_word); /* * PCI ID table for all supported controllers */ @@ -164,7 +168,7 @@ megasas_return_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd) static inline void megasas_enable_intr_xscale(struct megasas_register_set __iomem * regs) { - writel(1, &(regs)->outbound_intr_mask); + writel(0, &(regs)->outbound_intr_mask); /* Dummy readl to force pci flush */ readl(®s->outbound_intr_mask); @@ -200,24 +204,27 @@ static int megasas_clear_intr_xscale(struct megasas_register_set __iomem * regs) { u32 status; + u32 mfiStatus = 0; /* * Check if it is our interrupt */ status = readl(®s->outbound_intr_status); - if (!(status & MFI_OB_INTR_STATUS_MASK)) { - return 1; - } + if (status & MFI_OB_INTR_STATUS_MASK) + mfiStatus = MFI_INTR_FLAG_REPLY_MESSAGE; + if (status & MFI_XSCALE_OMR0_CHANGE_INTERRUPT) + mfiStatus |= MFI_INTR_FLAG_FIRMWARE_STATE_CHANGE; /* * Clear the interrupt by writing back the same value */ - writel(status, ®s->outbound_intr_status); + if (mfiStatus) + writel(status, ®s->outbound_intr_status); /* Dummy readl to force pci flush */ readl(®s->outbound_intr_status); - return 0; + return mfiStatus; } /** @@ -232,8 +239,69 @@ megasas_fire_cmd_xscale(struct megasas_instance *instance, u32 frame_count, struct megasas_register_set __iomem *regs) { + unsigned long flags; + spin_lock_irqsave(&instance->hba_lock, flags); writel((frame_phys_addr >> 3)|(frame_count), &(regs)->inbound_queue_port); + spin_unlock_irqrestore(&instance->hba_lock, flags); +} + +/** + * megasas_adp_reset_xscale - For controller reset + * @regs: MFI register set + */ +static int +megasas_adp_reset_xscale(struct megasas_instance *instance, + struct megasas_register_set __iomem *regs) +{ + u32 i; + u32 pcidata; + writel(MFI_ADP_RESET, ®s->inbound_doorbell); + + for (i = 0; i < 3; i++) + msleep(1000); /* sleep for 3 secs */ + pcidata = 0; + pci_read_config_dword(instance->pdev, MFI_1068_PCSR_OFFSET, &pcidata); + printk(KERN_NOTICE "pcidata = %x\n", pcidata); + if (pcidata & 0x2) { + printk(KERN_NOTICE "mfi 1068 offset read=%x\n", pcidata); + pcidata &= ~0x2; + pci_write_config_dword(instance->pdev, + MFI_1068_PCSR_OFFSET, pcidata); + + for (i = 0; i < 2; i++) + msleep(1000); /* need to wait 2 secs again */ + + pcidata = 0; + pci_read_config_dword(instance->pdev, + MFI_1068_FW_HANDSHAKE_OFFSET, &pcidata); + printk(KERN_NOTICE "1068 offset handshake read=%x\n", pcidata); + if ((pcidata & 0xffff0000) == MFI_1068_FW_READY) { + printk(KERN_NOTICE "1068 offset pcidt=%x\n", pcidata); + pcidata = 0; + pci_write_config_dword(instance->pdev, + MFI_1068_FW_HANDSHAKE_OFFSET, pcidata); + } + } + return 0; +} + +/** + * megasas_check_reset_xscale - For controller reset check + * @regs: MFI register set + */ +static int +megasas_check_reset_xscale(struct megasas_instance *instance, + struct megasas_register_set __iomem *regs) +{ + u32 consumer; + consumer = *instance->consumer; + + if ((instance->adprecovery != MEGASAS_HBA_OPERATIONAL) && + (*instance->consumer == MEGASAS_ADPRESET_INPROG_SIGN)) { + return 1; + } + return 0; } static struct megasas_instance_template megasas_instance_template_xscale = { @@ -243,6 +311,8 @@ static struct megasas_instance_template megasas_instance_template_xscale = { .disable_intr = megasas_disable_intr_xscale, .clear_intr = megasas_clear_intr_xscale, .read_fw_status_reg = megasas_read_fw_status_reg_xscale, + .adp_reset = megasas_adp_reset_xscale, + .check_reset = megasas_check_reset_xscale, }; /** @@ -264,7 +334,7 @@ megasas_enable_intr_ppc(struct megasas_register_set __iomem * regs) { writel(0xFFFFFFFF, &(regs)->outbound_doorbell_clear); - writel(~0x80000004, &(regs)->outbound_intr_mask); + writel(~0x80000000, &(regs)->outbound_intr_mask); /* Dummy readl to force pci flush */ readl(®s->outbound_intr_mask); @@ -307,7 +377,7 @@ megasas_clear_intr_ppc(struct megasas_register_set __iomem * regs) status = readl(®s->outbound_intr_status); if (!(status & MFI_REPLY_1078_MESSAGE_INTERRUPT)) { - return 1; + return 0; } /* @@ -318,7 +388,7 @@ megasas_clear_intr_ppc(struct megasas_register_set __iomem * regs) /* Dummy readl to force pci flush */ readl(®s->outbound_doorbell_clear); - return 0; + return 1; } /** * megasas_fire_cmd_ppc - Sends command to the FW @@ -332,10 +402,34 @@ megasas_fire_cmd_ppc(struct megasas_instance *instance, u32 frame_count, struct megasas_register_set __iomem *regs) { + unsigned long flags; + spin_lock_irqsave(&instance->hba_lock, flags); writel((frame_phys_addr | (frame_count<<1))|1, &(regs)->inbound_queue_port); + spin_unlock_irqrestore(&instance->hba_lock, flags); +} + +/** + * megasas_adp_reset_ppc - For controller reset + * @regs: MFI register set + */ +static int +megasas_adp_reset_ppc(struct megasas_instance *instance, + struct megasas_register_set __iomem *regs) +{ + return 0; } +/** + * megasas_check_reset_ppc - For controller reset check + * @regs: MFI register set + */ +static int +megasas_check_reset_ppc(struct megasas_instance *instance, + struct megasas_register_set __iomem *regs) +{ + return 0; +} static struct megasas_instance_template megasas_instance_template_ppc = { .fire_cmd = megasas_fire_cmd_ppc, @@ -343,6 +437,8 @@ static struct megasas_instance_template megasas_instance_template_ppc = { .disable_intr = megasas_disable_intr_ppc, .clear_intr = megasas_clear_intr_ppc, .read_fw_status_reg = megasas_read_fw_status_reg_ppc, + .adp_reset = megasas_adp_reset_ppc, + .check_reset = megasas_check_reset_ppc, }; /** @@ -397,7 +493,7 @@ megasas_clear_intr_skinny(struct megasas_register_set __iomem *regs) status = readl(®s->outbound_intr_status); if (!(status & MFI_SKINNY_ENABLE_INTERRUPT_MASK)) { - return 1; + return 0; } /* @@ -410,7 +506,7 @@ megasas_clear_intr_skinny(struct megasas_register_set __iomem *regs) */ readl(®s->outbound_intr_status); - return 0; + return 1; } /** @@ -426,11 +522,33 @@ megasas_fire_cmd_skinny(struct megasas_instance *instance, struct megasas_register_set __iomem *regs) { unsigned long flags; - spin_lock_irqsave(&instance->fire_lock, flags); + spin_lock_irqsave(&instance->hba_lock, flags); writel(0, &(regs)->inbound_high_queue_port); writel((frame_phys_addr | (frame_count<<1))|1, &(regs)->inbound_low_queue_port); - spin_unlock_irqrestore(&instance->fire_lock, flags); + spin_unlock_irqrestore(&instance->hba_lock, flags); +} + +/** + * megasas_adp_reset_skinny - For controller reset + * @regs: MFI register set + */ +static int +megasas_adp_reset_skinny(struct megasas_instance *instance, + struct megasas_register_set __iomem *regs) +{ + return 0; +} + +/** + * megasas_check_reset_skinny - For controller reset check + * @regs: MFI register set + */ +static int +megasas_check_reset_skinny(struct megasas_instance *instance, + struct megasas_register_set __iomem *regs) +{ + return 0; } static struct megasas_instance_template megasas_instance_template_skinny = { @@ -440,6 +558,8 @@ static struct megasas_instance_template megasas_instance_template_skinny = { .disable_intr = megasas_disable_intr_skinny, .clear_intr = megasas_clear_intr_skinny, .read_fw_status_reg = megasas_read_fw_status_reg_skinny, + .adp_reset = megasas_adp_reset_skinny, + .check_reset = megasas_check_reset_skinny, }; @@ -495,23 +615,29 @@ static int megasas_clear_intr_gen2(struct megasas_register_set __iomem *regs) { u32 status; + u32 mfiStatus = 0; /* * Check if it is our interrupt */ status = readl(®s->outbound_intr_status); - if (!(status & MFI_GEN2_ENABLE_INTERRUPT_MASK)) - return 1; + if (status & MFI_GEN2_ENABLE_INTERRUPT_MASK) { + mfiStatus = MFI_INTR_FLAG_REPLY_MESSAGE; + } + if (status & MFI_G2_OUTBOUND_DOORBELL_CHANGE_INTERRUPT) { + mfiStatus |= MFI_INTR_FLAG_FIRMWARE_STATE_CHANGE; + } /* * Clear the interrupt by writing back the same value */ - writel(status, ®s->outbound_doorbell_clear); + if (mfiStatus) + writel(status, ®s->outbound_doorbell_clear); /* Dummy readl to force pci flush */ readl(®s->outbound_intr_status); - return 0; + return mfiStatus; } /** * megasas_fire_cmd_gen2 - Sends command to the FW @@ -525,8 +651,74 @@ megasas_fire_cmd_gen2(struct megasas_instance *instance, u32 frame_count, struct megasas_register_set __iomem *regs) { + unsigned long flags; + spin_lock_irqsave(&instance->hba_lock, flags); writel((frame_phys_addr | (frame_count<<1))|1, &(regs)->inbound_queue_port); + spin_unlock_irqrestore(&instance->hba_lock, flags); +} + +/** + * megasas_adp_reset_gen2 - For controller reset + * @regs: MFI register set + */ +static int +megasas_adp_reset_gen2(struct megasas_instance *instance, + struct megasas_register_set __iomem *reg_set) +{ + u32 retry = 0 ; + u32 HostDiag; + + writel(0, ®_set->seq_offset); + writel(4, ®_set->seq_offset); + writel(0xb, ®_set->seq_offset); + writel(2, ®_set->seq_offset); + writel(7, ®_set->seq_offset); + writel(0xd, ®_set->seq_offset); + msleep(1000); + + HostDiag = (u32)readl(®_set->host_diag); + + while ( !( HostDiag & DIAG_WRITE_ENABLE) ) { + msleep(100); + HostDiag = (u32)readl(®_set->host_diag); + printk(KERN_NOTICE "RESETGEN2: retry=%x, hostdiag=%x\n", + retry, HostDiag); + + if (retry++ >= 100) + return 1; + + } + + printk(KERN_NOTICE "ADP_RESET_GEN2: HostDiag=%x\n", HostDiag); + + writel((HostDiag | DIAG_RESET_ADAPTER), ®_set->host_diag); + + ssleep(10); + + HostDiag = (u32)readl(®_set->host_diag); + while ( ( HostDiag & DIAG_RESET_ADAPTER) ) { + msleep(100); + HostDiag = (u32)readl(®_set->host_diag); + printk(KERN_NOTICE "RESET_GEN2: retry=%x, hostdiag=%x\n", + retry, HostDiag); + + if (retry++ >= 1000) + return 1; + + } + return 0; +} + +/** + * megasas_check_reset_gen2 - For controller reset check + * @regs: MFI register set + */ +static int +megasas_check_reset_gen2(struct megasas_instance *instance, + struct megasas_register_set __iomem *regs) +{ + return 0; } static struct megasas_instance_template megasas_instance_template_gen2 = { @@ -536,11 +728,13 @@ static struct megasas_instance_template megasas_instance_template_gen2 = { .disable_intr = megasas_disable_intr_gen2, .clear_intr = megasas_clear_intr_gen2, .read_fw_status_reg = megasas_read_fw_status_reg_gen2, + .adp_reset = megasas_adp_reset_gen2, + .check_reset = megasas_check_reset_gen2, }; /** * This is the end of set of functions & definitions -* specific to ppc (deviceid : 0x60) controllers +* specific to gen2 (deviceid : 0x78, 0x79) controllers */ /** @@ -599,8 +793,7 @@ megasas_issue_blocked_cmd(struct megasas_instance *instance, instance->instancet->fire_cmd(instance, cmd->frame_phys_addr, 0, instance->reg_set); - wait_event_timeout(instance->int_cmd_wait_q, (cmd->cmd_status != ENODATA), - MEGASAS_INTERNAL_CMD_WAIT_TIME*HZ); + wait_event(instance->int_cmd_wait_q, cmd->cmd_status != ENODATA); return 0; } @@ -648,8 +841,8 @@ megasas_issue_blocked_abort_cmd(struct megasas_instance *instance, /* * Wait for this cmd to complete */ - wait_event_timeout(instance->abort_cmd_wait_q, (cmd->cmd_status != 0xFF), - MEGASAS_INTERNAL_CMD_WAIT_TIME*HZ); + wait_event(instance->abort_cmd_wait_q, cmd->cmd_status != 0xFF); + cmd->sync_cmd = 0; megasas_return_cmd(instance, cmd); return 0; @@ -1131,14 +1324,22 @@ megasas_queue_command(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *)) u32 frame_count; struct megasas_cmd *cmd; struct megasas_instance *instance; + unsigned long flags; instance = (struct megasas_instance *) scmd->device->host->hostdata; - /* Don't process if we have already declared adapter dead */ - if (instance->hw_crit_error) + if (instance->issuepend_done == 0) return SCSI_MLQUEUE_HOST_BUSY; + spin_lock_irqsave(&instance->hba_lock, flags); + if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) { + spin_unlock_irqrestore(&instance->hba_lock, flags); + return SCSI_MLQUEUE_HOST_BUSY; + } + + spin_unlock_irqrestore(&instance->hba_lock, flags); + scmd->scsi_done = done; scmd->result = 0; @@ -1274,6 +1475,18 @@ static int megasas_slave_alloc(struct scsi_device *sdev) return 0; } +static void megaraid_sas_kill_hba(struct megasas_instance *instance) +{ + if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) || + (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY)) { + writel(MFI_STOP_ADP, + &instance->reg_set->reserved_0[0]); + } else { + writel(MFI_STOP_ADP, + &instance->reg_set->inbound_doorbell); + } +} + /** * megasas_complete_cmd_dpc - Returns FW's controller structure * @instance_addr: Address of adapter soft state @@ -1291,7 +1504,7 @@ static void megasas_complete_cmd_dpc(unsigned long instance_addr) unsigned long flags; /* If we have already declared adapter dead, donot complete cmds */ - if (instance->hw_crit_error) + if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR ) return; spin_lock_irqsave(&instance->completion_lock, flags); @@ -1301,6 +1514,11 @@ static void megasas_complete_cmd_dpc(unsigned long instance_addr) while (consumer != producer) { context = instance->reply_queue[consumer]; + if (context >= instance->max_fw_cmds) { + printk(KERN_ERR "Unexpected context value %x\n", + context); + BUG(); + } cmd = instance->cmd_list[context]; @@ -1350,7 +1568,76 @@ static void megasas_complete_cmd_dpc(unsigned long instance_addr) static int megasas_wait_for_outstanding(struct megasas_instance *instance) { int i; + u32 reset_index; u32 wait_time = MEGASAS_RESET_WAIT_TIME; + u8 adprecovery; + unsigned long flags; + struct list_head clist_local; + struct megasas_cmd *reset_cmd; + + spin_lock_irqsave(&instance->hba_lock, flags); + adprecovery = instance->adprecovery; + spin_unlock_irqrestore(&instance->hba_lock, flags); + + if (adprecovery != MEGASAS_HBA_OPERATIONAL) { + + INIT_LIST_HEAD(&clist_local); + spin_lock_irqsave(&instance->hba_lock, flags); + list_splice_init(&instance->internal_reset_pending_q, + &clist_local); + spin_unlock_irqrestore(&instance->hba_lock, flags); + + printk(KERN_NOTICE "megasas: HBA reset wait ...\n"); + for (i = 0; i < wait_time; i++) { + msleep(1000); + spin_lock_irqsave(&instance->hba_lock, flags); + adprecovery = instance->adprecovery; + spin_unlock_irqrestore(&instance->hba_lock, flags); + if (adprecovery == MEGASAS_HBA_OPERATIONAL) + break; + } + + if (adprecovery != MEGASAS_HBA_OPERATIONAL) { + printk(KERN_NOTICE "megasas: reset: Stopping HBA.\n"); + spin_lock_irqsave(&instance->hba_lock, flags); + instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR; + spin_unlock_irqrestore(&instance->hba_lock, flags); + return FAILED; + } + + reset_index = 0; + while (!list_empty(&clist_local)) { + reset_cmd = list_entry((&clist_local)->next, + struct megasas_cmd, list); + list_del_init(&reset_cmd->list); + if (reset_cmd->scmd) { + reset_cmd->scmd->result = DID_RESET << 16; + printk(KERN_NOTICE "%d:%p reset [%02x], %#lx\n", + reset_index, reset_cmd, + reset_cmd->scmd->cmnd[0], + reset_cmd->scmd->serial_number); + + reset_cmd->scmd->scsi_done(reset_cmd->scmd); + megasas_return_cmd(instance, reset_cmd); + } else if (reset_cmd->sync_cmd) { + printk(KERN_NOTICE "megasas:%p synch cmds" + "reset queue\n", + reset_cmd); + + reset_cmd->cmd_status = ENODATA; + instance->instancet->fire_cmd(instance, + reset_cmd->frame_phys_addr, + 0, instance->reg_set); + } else { + printk(KERN_NOTICE "megasas: %p unexpected" + "cmds lst\n", + reset_cmd); + } + reset_index++; + } + + return SUCCESS; + } for (i = 0; i < wait_time; i++) { @@ -1373,6 +1660,7 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance) } if (atomic_read(&instance->fw_outstanding)) { + printk(KERN_NOTICE "megaraid_sas: pending cmds after reset\n"); /* * Send signal to FW to stop processing any pending cmds. * The controller will be taken offline by the OS now. @@ -1388,10 +1676,14 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance) &instance->reg_set->inbound_doorbell); } megasas_dump_pending_frames(instance); - instance->hw_crit_error = 1; + spin_lock_irqsave(&instance->hba_lock, flags); + instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR; + spin_unlock_irqrestore(&instance->hba_lock, flags); return FAILED; } + printk(KERN_NOTICE "megaraid_sas: no pending cmds after reset\n"); + return SUCCESS; } @@ -1413,7 +1705,7 @@ static int megasas_generic_reset(struct scsi_cmnd *scmd) scmd_printk(KERN_NOTICE, scmd, "megasas: RESET -%ld cmd=%x retries=%x\n", scmd->serial_number, scmd->cmnd[0], scmd->retries); - if (instance->hw_crit_error) { + if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) { printk(KERN_ERR "megasas: cannot recover from previous reset " "failures\n"); return FAILED; @@ -1568,7 +1860,8 @@ megasas_service_aen(struct megasas_instance *instance, struct megasas_cmd *cmd) instance->aen_cmd = NULL; megasas_return_cmd(instance, cmd); - if (instance->unload == 0) { + if ((instance->unload == 0) && + ((instance->issuepend_done == 1))) { struct megasas_aen_event *ev; ev = kzalloc(sizeof(*ev), GFP_ATOMIC); if (!ev) { @@ -1663,6 +1956,9 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd, struct megasas_header *hdr = &cmd->frame->hdr; unsigned long flags; + /* flag for the retry reset */ + cmd->retry_for_fw_reset = 0; + if (cmd->scmd) cmd->scmd->SCp.ptr = NULL; @@ -1783,39 +2079,301 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd, } /** + * megasas_issue_pending_cmds_again - issue all pending cmds + * in FW again because of the fw reset + * @instance: Adapter soft state + */ +static inline void +megasas_issue_pending_cmds_again(struct megasas_instance *instance) +{ + struct megasas_cmd *cmd; + struct list_head clist_local; + union megasas_evt_class_locale class_locale; + unsigned long flags; + u32 seq_num; + + INIT_LIST_HEAD(&clist_local); + spin_lock_irqsave(&instance->hba_lock, flags); + list_splice_init(&instance->internal_reset_pending_q, &clist_local); + spin_unlock_irqrestore(&instance->hba_lock, flags); + + while (!list_empty(&clist_local)) { + cmd = list_entry((&clist_local)->next, + struct megasas_cmd, list); + list_del_init(&cmd->list); + + if (cmd->sync_cmd || cmd->scmd) { + printk(KERN_NOTICE "megaraid_sas: command %p, %p:%d" + "detected to be pending while HBA reset.\n", + cmd, cmd->scmd, cmd->sync_cmd); + + cmd->retry_for_fw_reset++; + + if (cmd->retry_for_fw_reset == 3) { + printk(KERN_NOTICE "megaraid_sas: cmd %p, %p:%d" + "was tried multiple times during reset." + "Shutting down the HBA\n", + cmd, cmd->scmd, cmd->sync_cmd); + megaraid_sas_kill_hba(instance); + + instance->adprecovery = + MEGASAS_HW_CRITICAL_ERROR; + return; + } + } + + if (cmd->sync_cmd == 1) { + if (cmd->scmd) { + printk(KERN_NOTICE "megaraid_sas: unexpected" + "cmd attached to internal command!\n"); + } + printk(KERN_NOTICE "megasas: %p synchronous cmd" + "on the internal reset queue," + "issue it again.\n", cmd); + cmd->cmd_status = ENODATA; + instance->instancet->fire_cmd(instance, + cmd->frame_phys_addr , + 0, instance->reg_set); + } else if (cmd->scmd) { + printk(KERN_NOTICE "megasas: %p scsi cmd [%02x],%#lx" + "detected on the internal queue, issue again.\n", + cmd, cmd->scmd->cmnd[0], cmd->scmd->serial_number); + + atomic_inc(&instance->fw_outstanding); + instance->instancet->fire_cmd(instance, + cmd->frame_phys_addr, + cmd->frame_count-1, instance->reg_set); + } else { + printk(KERN_NOTICE "megasas: %p unexpected cmd on the" + "internal reset defer list while re-issue!!\n", + cmd); + } + } + + if (instance->aen_cmd) { + printk(KERN_NOTICE "megaraid_sas: aen_cmd in def process\n"); + megasas_return_cmd(instance, instance->aen_cmd); + + instance->aen_cmd = NULL; + } + + /* + * Initiate AEN (Asynchronous Event Notification) + */ + seq_num = instance->last_seq_num; + class_locale.members.reserved = 0; + class_locale.members.locale = MR_EVT_LOCALE_ALL; + class_locale.members.class = MR_EVT_CLASS_DEBUG; + + megasas_register_aen(instance, seq_num, class_locale.word); +} + +/** + * Move the internal reset pending commands to a deferred queue. + * + * We move the commands pending at internal reset time to a + * pending queue. This queue would be flushed after successful + * completion of the internal reset sequence. if the internal reset + * did not complete in time, the kernel reset handler would flush + * these commands. + **/ +static void +megasas_internal_reset_defer_cmds(struct megasas_instance *instance) +{ + struct megasas_cmd *cmd; + int i; + u32 max_cmd = instance->max_fw_cmds; + u32 defer_index; + unsigned long flags; + + defer_index = 0; + spin_lock_irqsave(&instance->cmd_pool_lock, flags); + for (i = 0; i < max_cmd; i++) { + cmd = instance->cmd_list[i]; + if (cmd->sync_cmd == 1 || cmd->scmd) { + printk(KERN_NOTICE "megasas: moving cmd[%d]:%p:%d:%p" + "on the defer queue as internal\n", + defer_index, cmd, cmd->sync_cmd, cmd->scmd); + + if (!list_empty(&cmd->list)) { + printk(KERN_NOTICE "megaraid_sas: ERROR while" + " moving this cmd:%p, %d %p, it was" + "discovered on some list?\n", + cmd, cmd->sync_cmd, cmd->scmd); + + list_del_init(&cmd->list); + } + defer_index++; + list_add_tail(&cmd->list, + &instance->internal_reset_pending_q); + } + } + spin_unlock_irqrestore(&instance->cmd_pool_lock, flags); +} + + +static void +process_fw_state_change_wq(struct work_struct *work) +{ + struct megasas_instance *instance = + container_of(work, struct megasas_instance, work_init); + u32 wait; + unsigned long flags; + + if (instance->adprecovery != MEGASAS_ADPRESET_SM_INFAULT) { + printk(KERN_NOTICE "megaraid_sas: error, recovery st %x \n", + instance->adprecovery); + return ; + } + + if (instance->adprecovery == MEGASAS_ADPRESET_SM_INFAULT) { + printk(KERN_NOTICE "megaraid_sas: FW detected to be in fault" + "state, restarting it...\n"); + + instance->instancet->disable_intr(instance->reg_set); + atomic_set(&instance->fw_outstanding, 0); + + atomic_set(&instance->fw_reset_no_pci_access, 1); + instance->instancet->adp_reset(instance, instance->reg_set); + atomic_set(&instance->fw_reset_no_pci_access, 0 ); + + printk(KERN_NOTICE "megaraid_sas: FW restarted successfully," + "initiating next stage...\n"); + + printk(KERN_NOTICE "megaraid_sas: HBA recovery state machine," + "state 2 starting...\n"); + + /*waitting for about 20 second before start the second init*/ + for (wait = 0; wait < 30; wait++) { + msleep(1000); + } + + if (megasas_transition_to_ready(instance)) { + printk(KERN_NOTICE "megaraid_sas:adapter not ready\n"); + + megaraid_sas_kill_hba(instance); + instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR; + return ; + } + + if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS1064R) || + (instance->pdev->device == PCI_DEVICE_ID_DELL_PERC5) || + (instance->pdev->device == PCI_DEVICE_ID_LSI_VERDE_ZCR) + ) { + *instance->consumer = *instance->producer; + } else { + *instance->consumer = 0; + *instance->producer = 0; + } + + megasas_issue_init_mfi(instance); + + spin_lock_irqsave(&instance->hba_lock, flags); + instance->adprecovery = MEGASAS_HBA_OPERATIONAL; + spin_unlock_irqrestore(&instance->hba_lock, flags); + instance->instancet->enable_intr(instance->reg_set); + + megasas_issue_pending_cmds_again(instance); + instance->issuepend_done = 1; + } + return ; +} + +/** * megasas_deplete_reply_queue - Processes all completed commands * @instance: Adapter soft state * @alt_status: Alternate status to be returned to * SCSI mid-layer instead of the status * returned by the FW + * Note: this must be called with hba lock held */ static int -megasas_deplete_reply_queue(struct megasas_instance *instance, u8 alt_status) +megasas_deplete_reply_queue(struct megasas_instance *instance, + u8 alt_status) { - /* - * Check if it is our interrupt - * Clear the interrupt - */ - if(instance->instancet->clear_intr(instance->reg_set)) + u32 mfiStatus; + u32 fw_state; + + if ((mfiStatus = instance->instancet->check_reset(instance, + instance->reg_set)) == 1) { + return IRQ_HANDLED; + } + + if ((mfiStatus = instance->instancet->clear_intr( + instance->reg_set) + ) == 0) { return IRQ_NONE; + } + + instance->mfiStatus = mfiStatus; + + if ((mfiStatus & MFI_INTR_FLAG_FIRMWARE_STATE_CHANGE)) { + fw_state = instance->instancet->read_fw_status_reg( + instance->reg_set) & MFI_STATE_MASK; + + if (fw_state != MFI_STATE_FAULT) { + printk(KERN_NOTICE "megaraid_sas: fw state:%x\n", + fw_state); + } + + if ((fw_state == MFI_STATE_FAULT) && + (instance->disableOnlineCtrlReset == 0)) { + printk(KERN_NOTICE "megaraid_sas: wait adp restart\n"); + + if ((instance->pdev->device == + PCI_DEVICE_ID_LSI_SAS1064R) || + (instance->pdev->device == + PCI_DEVICE_ID_DELL_PERC5) || + (instance->pdev->device == + PCI_DEVICE_ID_LSI_VERDE_ZCR)) { + + *instance->consumer = + MEGASAS_ADPRESET_INPROG_SIGN; + } + + + instance->instancet->disable_intr(instance->reg_set); + instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT; + instance->issuepend_done = 0; + + atomic_set(&instance->fw_outstanding, 0); + megasas_internal_reset_defer_cmds(instance); + + printk(KERN_NOTICE "megasas: fwState=%x, stage:%d\n", + fw_state, instance->adprecovery); + + schedule_work(&instance->work_init); + return IRQ_HANDLED; + + } else { + printk(KERN_NOTICE "megasas: fwstate:%x, dis_OCR=%x\n", + fw_state, instance->disableOnlineCtrlReset); + } + } - if (instance->hw_crit_error) - goto out_done; - /* - * Schedule the tasklet for cmd completion - */ tasklet_schedule(&instance->isr_tasklet); -out_done: return IRQ_HANDLED; } - /** * megasas_isr - isr entry point */ static irqreturn_t megasas_isr(int irq, void *devp) { - return megasas_deplete_reply_queue((struct megasas_instance *)devp, - DID_OK); + struct megasas_instance *instance; + unsigned long flags; + irqreturn_t rc; + + if (atomic_read( + &(((struct megasas_instance *)devp)->fw_reset_no_pci_access))) + return IRQ_HANDLED; + + instance = (struct megasas_instance *)devp; + + spin_lock_irqsave(&instance->hba_lock, flags); + rc = megasas_deplete_reply_queue(instance, DID_OK); + spin_unlock_irqrestore(&instance->hba_lock, flags); + + return rc; } /** @@ -1972,7 +2530,7 @@ megasas_transition_to_ready(struct megasas_instance* instance) "in %d secs\n", fw_state, max_wait); return -ENODEV; } - }; + } printk(KERN_INFO "megasas: FW now in Ready state\n"); return 0; @@ -2054,6 +2612,7 @@ static int megasas_create_frame_pool(struct megasas_instance *instance) */ sgl_sz = sge_sz * instance->max_num_sge; frame_count = (sgl_sz + MEGAMFI_FRAME_SIZE - 1) / MEGAMFI_FRAME_SIZE; + frame_count = 15; /* * We need one extra frame for the MFI command @@ -2201,6 +2760,7 @@ static int megasas_alloc_cmds(struct megasas_instance *instance) cmd = instance->cmd_list[i]; memset(cmd, 0, sizeof(struct megasas_cmd)); cmd->index = i; + cmd->scmd = NULL; cmd->instance = instance; list_add_tail(&cmd->list, &instance->cmd_pool); @@ -2368,7 +2928,7 @@ megasas_get_ld_list(struct megasas_instance *instance) /* the following function will get the instance PD LIST */ - if ((ret == 0) && (ci->ldCount < MAX_LOGICAL_DRIVES)) { + if ((ret == 0) && (ci->ldCount <= MAX_LOGICAL_DRIVES)) { memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS); for (ld_index = 0; ld_index < ci->ldCount; ld_index++) { @@ -2682,6 +3242,21 @@ static int megasas_init_mfi(struct megasas_instance *instance) if (megasas_issue_init_mfi(instance)) goto fail_fw_init; + instance->fw_support_ieee = 0; + instance->fw_support_ieee = + (instance->instancet->read_fw_status_reg(reg_set) & + 0x04000000); + + printk(KERN_NOTICE "megasas_init_mfi: fw_support_ieee=%d", + instance->fw_support_ieee); + + if (instance->fw_support_ieee) + instance->flag_ieee = 1; + + /** for passthrough + * the following function will get the PD LIST. + */ + memset(instance->pd_list, 0 , (MEGASAS_MAX_PD * sizeof(struct megasas_pd_list))); megasas_get_pd_list(instance); @@ -2708,6 +3283,8 @@ static int megasas_init_mfi(struct megasas_instance *instance) max_sectors_2 = ctrl_info->max_request_size; tmp_sectors = min_t(u32, max_sectors_1 , max_sectors_2); + instance->disableOnlineCtrlReset = + ctrl_info->properties.OnOffProperties.disableOnlineCtrlReset; } instance->max_sectors_per_req = instance->max_num_sge * @@ -2929,6 +3506,7 @@ megasas_register_aen(struct megasas_instance *instance, u32 seq_num, dcmd->flags = MFI_FRAME_DIR_READ; dcmd->timeout = 0; dcmd->pad_0 = 0; + instance->last_seq_num = seq_num; dcmd->data_xfer_len = sizeof(struct megasas_evt_detail); dcmd->opcode = MR_DCMD_CTRL_EVENT_WAIT; dcmd->mbox.w[0] = seq_num; @@ -3097,6 +3675,7 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) instance = (struct megasas_instance *)host->hostdata; memset(instance, 0, sizeof(*instance)); + atomic_set( &instance->fw_reset_no_pci_access, 0 ); instance->producer = pci_alloc_consistent(pdev, sizeof(u32), &instance->producer_h); @@ -3114,6 +3693,9 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) megasas_poll_wait_aen = 0; instance->flag_ieee = 0; instance->ev = NULL; + instance->issuepend_done = 1; + instance->adprecovery = MEGASAS_HBA_OPERATIONAL; + megasas_poll_wait_aen = 0; instance->evt_detail = pci_alloc_consistent(pdev, sizeof(struct @@ -3130,6 +3712,7 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) * Initialize locks and queues */ INIT_LIST_HEAD(&instance->cmd_pool); + INIT_LIST_HEAD(&instance->internal_reset_pending_q); atomic_set(&instance->fw_outstanding,0); @@ -3137,7 +3720,7 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) init_waitqueue_head(&instance->abort_cmd_wait_q); spin_lock_init(&instance->cmd_pool_lock); - spin_lock_init(&instance->fire_lock); + spin_lock_init(&instance->hba_lock); spin_lock_init(&instance->completion_lock); spin_lock_init(&poll_aen_lock); @@ -3162,6 +3745,9 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) instance->flag = 0; instance->unload = 1; instance->last_time = 0; + instance->disableOnlineCtrlReset = 1; + + INIT_WORK(&instance->work_init, process_fw_state_change_wq); /* * Initialize MFI Firmware @@ -3253,6 +3839,9 @@ static void megasas_flush_cache(struct megasas_instance *instance) struct megasas_cmd *cmd; struct megasas_dcmd_frame *dcmd; + if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) + return; + cmd = megasas_get_cmd(instance); if (!cmd) @@ -3290,6 +3879,9 @@ static void megasas_shutdown_controller(struct megasas_instance *instance, struct megasas_cmd *cmd; struct megasas_dcmd_frame *dcmd; + if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) + return; + cmd = megasas_get_cmd(instance); if (!cmd) @@ -3557,7 +4149,6 @@ static void megasas_shutdown(struct pci_dev *pdev) */ static int megasas_mgmt_open(struct inode *inode, struct file *filep) { - cycle_kernel_lock(); /* * Allow only those users with admin rights */ @@ -3781,6 +4372,9 @@ static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg) struct megasas_iocpacket *ioc; struct megasas_instance *instance; int error; + int i; + unsigned long flags; + u32 wait_time = MEGASAS_RESET_WAIT_TIME; ioc = kmalloc(sizeof(*ioc), GFP_KERNEL); if (!ioc) @@ -3797,8 +4391,8 @@ static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg) goto out_kfree_ioc; } - if (instance->hw_crit_error == 1) { - printk(KERN_DEBUG "Controller in Crit ERROR\n"); + if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) { + printk(KERN_ERR "Controller in crit error\n"); error = -ENODEV; goto out_kfree_ioc; } @@ -3815,6 +4409,35 @@ static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg) error = -ERESTARTSYS; goto out_kfree_ioc; } + + for (i = 0; i < wait_time; i++) { + + spin_lock_irqsave(&instance->hba_lock, flags); + if (instance->adprecovery == MEGASAS_HBA_OPERATIONAL) { + spin_unlock_irqrestore(&instance->hba_lock, flags); + break; + } + spin_unlock_irqrestore(&instance->hba_lock, flags); + + if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) { + printk(KERN_NOTICE "megasas: waiting" + "for controller reset to finish\n"); + } + + msleep(1000); + } + + spin_lock_irqsave(&instance->hba_lock, flags); + if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) { + spin_unlock_irqrestore(&instance->hba_lock, flags); + + printk(KERN_ERR "megaraid_sas: timed out while" + "waiting for HBA to recover\n"); + error = -ENODEV; + goto out_kfree_ioc; + } + spin_unlock_irqrestore(&instance->hba_lock, flags); + error = megasas_mgmt_fw_ioctl(instance, user_ioc, ioc); up(&instance->ioctl_sem); @@ -3828,6 +4451,9 @@ static int megasas_mgmt_ioctl_aen(struct file *file, unsigned long arg) struct megasas_instance *instance; struct megasas_aen aen; int error; + int i; + unsigned long flags; + u32 wait_time = MEGASAS_RESET_WAIT_TIME; if (file->private_data != file) { printk(KERN_DEBUG "megasas: fasync_helper was not " @@ -3843,14 +4469,42 @@ static int megasas_mgmt_ioctl_aen(struct file *file, unsigned long arg) if (!instance) return -ENODEV; - if (instance->hw_crit_error == 1) { - error = -ENODEV; + if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) { + return -ENODEV; } if (instance->unload == 1) { return -ENODEV; } + for (i = 0; i < wait_time; i++) { + + spin_lock_irqsave(&instance->hba_lock, flags); + if (instance->adprecovery == MEGASAS_HBA_OPERATIONAL) { + spin_unlock_irqrestore(&instance->hba_lock, + flags); + break; + } + + spin_unlock_irqrestore(&instance->hba_lock, flags); + + if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) { + printk(KERN_NOTICE "megasas: waiting for" + "controller reset to finish\n"); + } + + msleep(1000); + } + + spin_lock_irqsave(&instance->hba_lock, flags); + if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) { + spin_unlock_irqrestore(&instance->hba_lock, flags); + printk(KERN_ERR "megaraid_sas: timed out while waiting" + "for HBA to recover.\n"); + return -ENODEV; + } + spin_unlock_irqrestore(&instance->hba_lock, flags); + mutex_lock(&instance->aen_mutex); error = megasas_register_aen(instance, aen.seq_num, aen.class_locale_word); @@ -3957,6 +4611,7 @@ static const struct file_operations megasas_mgmt_fops = { #ifdef CONFIG_COMPAT .compat_ioctl = megasas_mgmt_compat_ioctl, #endif + .llseek = noop_llseek, }; /* diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 9d8b6bf605aa..16a4f68a34b0 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -60,6 +60,7 @@ #define MFI_STATE_READY 0xB0000000 #define MFI_STATE_OPERATIONAL 0xC0000000 #define MFI_STATE_FAULT 0xF0000000 +#define MFI_RESET_REQUIRED 0x00000001 #define MEGAMFI_FRAME_SIZE 64 @@ -73,6 +74,12 @@ * HOTPLUG : Resume from Hotplug * MFI_STOP_ADP : Send signal to FW to stop processing */ +#define WRITE_SEQUENCE_OFFSET (0x0000000FC) /* I20 */ +#define HOST_DIAGNOSTIC_OFFSET (0x000000F8) /* I20 */ +#define DIAG_WRITE_ENABLE (0x00000080) +#define DIAG_RESET_ADAPTER (0x00000004) + +#define MFI_ADP_RESET 0x00000040 #define MFI_INIT_ABORT 0x00000001 #define MFI_INIT_READY 0x00000002 #define MFI_INIT_MFIMODE 0x00000004 @@ -402,8 +409,40 @@ struct megasas_ctrl_prop { u16 ecc_bucket_leak_rate; u8 restore_hotspare_on_insertion; u8 expose_encl_devices; - u8 reserved[38]; + u8 maintainPdFailHistory; + u8 disallowHostRequestReordering; + u8 abortCCOnError; + u8 loadBalanceMode; + u8 disableAutoDetectBackplane; + + u8 snapVDSpace; + + /* + * Add properties that can be controlled by + * a bit in the following structure. + */ + struct { + u32 copyBackDisabled : 1; + u32 SMARTerEnabled : 1; + u32 prCorrectUnconfiguredAreas : 1; + u32 useFdeOnly : 1; + u32 disableNCQ : 1; + u32 SSDSMARTerEnabled : 1; + u32 SSDPatrolReadEnabled : 1; + u32 enableSpinDownUnconfigured : 1; + u32 autoEnhancedImport : 1; + u32 enableSecretKeyControl : 1; + u32 disableOnlineCtrlReset : 1; + u32 allowBootWithPinnedCache : 1; + u32 disableSpinDownHS : 1; + u32 enableJBOD : 1; + u32 reserved :18; + } OnOffProperties; + u8 autoSnapVDSpace; + u8 viewSpace; + u16 spinDownTime; + u8 reserved[24]; } __packed; /* @@ -704,6 +743,12 @@ struct megasas_ctrl_info { */ #define IS_DMA64 (sizeof(dma_addr_t) == 8) +#define MFI_XSCALE_OMR0_CHANGE_INTERRUPT 0x00000001 + +#define MFI_INTR_FLAG_REPLY_MESSAGE 0x00000001 +#define MFI_INTR_FLAG_FIRMWARE_STATE_CHANGE 0x00000002 +#define MFI_G2_OUTBOUND_DOORBELL_CHANGE_INTERRUPT 0x00000004 + #define MFI_OB_INTR_STATUS_MASK 0x00000002 #define MFI_POLL_TIMEOUT_SECS 60 #define MEGASAS_COMPLETION_TIMER_INTERVAL (HZ/10) @@ -714,6 +759,9 @@ struct megasas_ctrl_info { #define MFI_REPLY_SKINNY_MESSAGE_INTERRUPT 0x40000000 #define MFI_SKINNY_ENABLE_INTERRUPT_MASK (0x00000001) +#define MFI_1068_PCSR_OFFSET 0x84 +#define MFI_1068_FW_HANDSHAKE_OFFSET 0x64 +#define MFI_1068_FW_READY 0xDDDD0000 /* * register set for both 1068 and 1078 controllers * structure extended for 1078 registers @@ -755,8 +803,10 @@ struct megasas_register_set { u32 inbound_high_queue_port ; /*00C4h*/ u32 reserved_5; /*00C8h*/ - u32 index_registers[820]; /*00CCh*/ - + u32 res_6[11]; /*CCh*/ + u32 host_diag; + u32 seq_offset; + u32 index_registers[807]; /*00CCh*/ } __attribute__ ((packed)); struct megasas_sge32 { @@ -1226,11 +1276,12 @@ struct megasas_instance { struct megasas_cmd **cmd_list; struct list_head cmd_pool; + /* used to sync fire the cmd to fw */ spinlock_t cmd_pool_lock; + /* used to sync fire the cmd to fw */ + spinlock_t hba_lock; /* used to synch producer, consumer ptrs in dpc */ spinlock_t completion_lock; - /* used to sync fire the cmd to fw */ - spinlock_t fire_lock; struct dma_pool *frame_dma_pool; struct dma_pool *sense_dma_pool; @@ -1247,19 +1298,36 @@ struct megasas_instance { struct pci_dev *pdev; u32 unique_id; + u32 fw_support_ieee; atomic_t fw_outstanding; - u32 hw_crit_error; + atomic_t fw_reset_no_pci_access; struct megasas_instance_template *instancet; struct tasklet_struct isr_tasklet; + struct work_struct work_init; u8 flag; u8 unload; u8 flag_ieee; + u8 issuepend_done; + u8 disableOnlineCtrlReset; + u8 adprecovery; unsigned long last_time; + u32 mfiStatus; + u32 last_seq_num; struct timer_list io_completion_timer; + struct list_head internal_reset_pending_q; +}; + +enum { + MEGASAS_HBA_OPERATIONAL = 0, + MEGASAS_ADPRESET_SM_INFAULT = 1, + MEGASAS_ADPRESET_SM_FW_RESET_SUCCESS = 2, + MEGASAS_ADPRESET_SM_OPERATIONAL = 3, + MEGASAS_HW_CRITICAL_ERROR = 4, + MEGASAS_ADPRESET_INPROG_SIGN = 0xDEADDEAD, }; struct megasas_instance_template { @@ -1272,6 +1340,10 @@ struct megasas_instance_template { int (*clear_intr)(struct megasas_register_set __iomem *); u32 (*read_fw_status_reg)(struct megasas_register_set __iomem *); + int (*adp_reset)(struct megasas_instance *, \ + struct megasas_register_set __iomem *); + int (*check_reset)(struct megasas_instance *, \ + struct megasas_register_set __iomem *); }; #define MEGASAS_IS_LOGICAL(scp) \ @@ -1291,7 +1363,9 @@ struct megasas_cmd { u32 index; u8 sync_cmd; u8 cmd_status; - u16 abort_aen; + u8 abort_aen; + u8 retry_for_fw_reset; + struct list_head list; struct scsi_cmnd *scmd; diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c index 57bcd5c9dcff..12faf64f91b0 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/drivers/scsi/mpt2sas/mpt2sas_base.c @@ -534,7 +534,7 @@ _base_display_event_data(struct MPT2SAS_ADAPTER *ioc, if (event_data->DiscoveryStatus) printk("discovery_status(0x%08x)", le32_to_cpu(event_data->DiscoveryStatus)); - printk("\n"); + printk("\n"); return; } case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE: diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c index b774973f0765..40cb8aeb21b1 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c +++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c @@ -51,7 +51,7 @@ #include <linux/types.h> #include <linux/pci.h> #include <linux/delay.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/compat.h> #include <linux/poll.h> @@ -61,6 +61,7 @@ #include "mpt2sas_base.h" #include "mpt2sas_ctl.h" +static DEFINE_MUTEX(_ctl_mutex); static struct fasync_struct *async_queue; static DECLARE_WAIT_QUEUE_HEAD(ctl_poll_wait); @@ -2238,9 +2239,9 @@ _ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { long ret; - lock_kernel(); + mutex_lock(&_ctl_mutex); ret = _ctl_ioctl_main(file, cmd, (void __user *)arg); - unlock_kernel(); + mutex_unlock(&_ctl_mutex); return ret; } @@ -2309,12 +2310,12 @@ _ctl_ioctl_compat(struct file *file, unsigned cmd, unsigned long arg) { long ret; - lock_kernel(); + mutex_lock(&_ctl_mutex); if (cmd == MPT2COMMAND32) ret = _ctl_compat_mpt_command(file, cmd, arg); else ret = _ctl_ioctl_main(file, cmd, (void __user *)arg); - unlock_kernel(); + mutex_unlock(&_ctl_mutex); return ret; } #endif @@ -2952,6 +2953,7 @@ static const struct file_operations ctl_fops = { #ifdef CONFIG_COMPAT .compat_ioctl = _ctl_ioctl_compat, #endif + .llseek = noop_llseek, }; static struct miscdevice ctl_dev = { diff --git a/drivers/scsi/osd/osd_uld.c b/drivers/scsi/osd/osd_uld.c index ffdd9fdb9995..b31a8e3841d7 100644 --- a/drivers/scsi/osd/osd_uld.c +++ b/drivers/scsi/osd/osd_uld.c @@ -182,6 +182,7 @@ static const struct file_operations osd_fops = { .open = osd_uld_open, .release = osd_uld_release, .unlocked_ioctl = osd_uld_ioctl, + .llseek = noop_llseek, }; struct osd_dev *osduld_path_lookup(const char *name) diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c index 278b352ae78d..54de1d1af1a7 100644 --- a/drivers/scsi/osst.c +++ b/drivers/scsi/osst.c @@ -51,7 +51,7 @@ static const char * osst_version = "0.99.4"; #include <linux/moduleparam.h> #include <linux/delay.h> #include <linux/jiffies.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <asm/uaccess.h> #include <asm/dma.h> #include <asm/system.h> @@ -80,6 +80,7 @@ static const char * osst_version = "0.99.4"; #include "osst_options.h" #include "osst_detect.h" +static DEFINE_MUTEX(osst_int_mutex); static int max_dev = 0; static int write_threshold_kbs = 0; static int max_sg_segs = 0; @@ -4807,9 +4808,9 @@ static int os_scsi_tape_open(struct inode * inode, struct file * filp) { int ret; - lock_kernel(); + mutex_lock(&osst_int_mutex); ret = __os_scsi_tape_open(inode, filp); - unlock_kernel(); + mutex_unlock(&osst_int_mutex); return ret; } @@ -4943,9 +4944,9 @@ static long osst_ioctl(struct file * file, char * name = tape_name(STp); void __user * p = (void __user *)arg; - lock_kernel(); + mutex_lock(&osst_int_mutex); if (mutex_lock_interruptible(&STp->lock)) { - unlock_kernel(); + mutex_unlock(&osst_int_mutex); return -ERESTARTSYS; } @@ -5260,14 +5261,14 @@ static long osst_ioctl(struct file * file, mutex_unlock(&STp->lock); retval = scsi_ioctl(STp->device, cmd_in, p); - unlock_kernel(); + mutex_unlock(&osst_int_mutex); return retval; out: if (SRpnt) osst_release_request(SRpnt); mutex_unlock(&STp->lock); - unlock_kernel(); + mutex_unlock(&osst_int_mutex); return retval; } diff --git a/drivers/scsi/pcmcia/Kconfig b/drivers/scsi/pcmcia/Kconfig index 53857c6b6d4d..ecc855c550aa 100644 --- a/drivers/scsi/pcmcia/Kconfig +++ b/drivers/scsi/pcmcia/Kconfig @@ -11,7 +11,6 @@ if SCSI_LOWLEVEL_PCMCIA && SCSI && PCMCIA && m config PCMCIA_AHA152X tristate "Adaptec AHA152X PCMCIA support" - depends on !64BIT select SCSI_SPI_ATTRS help Say Y here if you intend to attach this type of PCMCIA SCSI host diff --git a/drivers/scsi/pcmcia/aha152x_stub.c b/drivers/scsi/pcmcia/aha152x_stub.c index 61f49bdcc0c2..e77dd02eccdd 100644 --- a/drivers/scsi/pcmcia/aha152x_stub.c +++ b/drivers/scsi/pcmcia/aha152x_stub.c @@ -49,7 +49,6 @@ #include <scsi/scsi_host.h> #include "aha152x.h" -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/ds.h> @@ -86,8 +85,6 @@ static void aha152x_release_cs(struct pcmcia_device *link); static void aha152x_detach(struct pcmcia_device *p_dev); static int aha152x_config_cs(struct pcmcia_device *link); -static struct pcmcia_device *dev_list; - static int aha152x_probe(struct pcmcia_device *link) { scsi_info_t *info; @@ -100,11 +97,8 @@ static int aha152x_probe(struct pcmcia_device *link) info->p_dev = link; link->priv = info; - link->resource[0]->end = 0x20; - link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; - link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.IntType = INT_MEMORY_AND_IO; - link->conf.Present = PRESENT_OPTION; + link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; + link->config_regs = PRESENT_OPTION; return aha152x_config_cs(link); } /* aha152x_attach */ @@ -123,25 +117,24 @@ static void aha152x_detach(struct pcmcia_device *link) /*====================================================================*/ -static int aha152x_config_check(struct pcmcia_device *p_dev, - cistpl_cftable_entry_t *cfg, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, - void *priv_data) +static int aha152x_config_check(struct pcmcia_device *p_dev, void *priv_data) { p_dev->io_lines = 10; + /* For New Media T&J, look for a SCSI window */ - if (cfg->io.win[0].len >= 0x20) - p_dev->resource[0]->start = cfg->io.win[0].base; - else if ((cfg->io.nwin > 1) && - (cfg->io.win[1].len >= 0x20)) - p_dev->resource[0]->start = cfg->io.win[1].base; - if ((cfg->io.nwin > 0) && - (p_dev->resource[0]->start < 0xffff)) { - if (!pcmcia_request_io(p_dev)) - return 0; - } - return -EINVAL; + if ((p_dev->resource[0]->end < 0x20) && + (p_dev->resource[1]->end >= 0x20)) + p_dev->resource[0]->start = p_dev->resource[1]->start; + + if (p_dev->resource[0]->start >= 0xffff) + return -EINVAL; + + p_dev->resource[1]->start = p_dev->resource[1]->end = 0; + p_dev->resource[0]->end = 0x20; + p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; + p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; + + return pcmcia_request_io(p_dev); } static int aha152x_config_cs(struct pcmcia_device *link) @@ -160,7 +153,7 @@ static int aha152x_config_cs(struct pcmcia_device *link) if (!link->irq) goto failed; - ret = pcmcia_request_configuration(link, &link->conf); + ret = pcmcia_enable_device(link); if (ret) goto failed; @@ -221,9 +214,7 @@ MODULE_DEVICE_TABLE(pcmcia, aha152x_ids); static struct pcmcia_driver aha152x_cs_driver = { .owner = THIS_MODULE, - .drv = { - .name = "aha152x_cs", - }, + .name = "aha152x_cs", .probe = aha152x_probe, .remove = aha152x_detach, .id_table = aha152x_ids, @@ -238,7 +229,6 @@ static int __init init_aha152x_cs(void) static void __exit exit_aha152x_cs(void) { pcmcia_unregister_driver(&aha152x_cs_driver); - BUG_ON(dev_list != NULL); } module_init(init_aha152x_cs); diff --git a/drivers/scsi/pcmcia/fdomain_stub.c b/drivers/scsi/pcmcia/fdomain_stub.c index 13dbe5c48492..cd69c2670f81 100644 --- a/drivers/scsi/pcmcia/fdomain_stub.c +++ b/drivers/scsi/pcmcia/fdomain_stub.c @@ -46,7 +46,6 @@ #include <scsi/scsi_host.h> #include "fdomain.h" -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/ds.h> @@ -83,11 +82,8 @@ static int fdomain_probe(struct pcmcia_device *link) info->p_dev = link; link->priv = info; - link->resource[0]->end = 0x10; - link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; - link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.IntType = INT_MEMORY_AND_IO; - link->conf.Present = PRESENT_OPTION; + link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; + link->config_regs = PRESENT_OPTION; return fdomain_config(link); } /* fdomain_attach */ @@ -105,14 +101,12 @@ static void fdomain_detach(struct pcmcia_device *link) /*====================================================================*/ -static int fdomain_config_check(struct pcmcia_device *p_dev, - cistpl_cftable_entry_t *cfg, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, - void *priv_data) +static int fdomain_config_check(struct pcmcia_device *p_dev, void *priv_data) { p_dev->io_lines = 10; - p_dev->resource[0]->start = cfg->io.win[0].base; + p_dev->resource[0]->end = 0x10; + p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; + p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; return pcmcia_request_io(p_dev); } @@ -132,7 +126,7 @@ static int fdomain_config(struct pcmcia_device *link) if (!link->irq) goto failed; - ret = pcmcia_request_configuration(link, &link->conf); + ret = pcmcia_enable_device(link); if (ret) goto failed; @@ -194,9 +188,7 @@ MODULE_DEVICE_TABLE(pcmcia, fdomain_ids); static struct pcmcia_driver fdomain_cs_driver = { .owner = THIS_MODULE, - .drv = { - .name = "fdomain_cs", - }, + .name = "fdomain_cs", .probe = fdomain_probe, .remove = fdomain_detach, .id_table = fdomain_ids, diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c index dd9b40306f3d..9326c2c14880 100644 --- a/drivers/scsi/pcmcia/nsp_cs.c +++ b/drivers/scsi/pcmcia/nsp_cs.c @@ -47,7 +47,6 @@ #include <scsi/scsi.h> #include <scsi/scsi_ioctl.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/cisreg.h> #include <pcmcia/ds.h> @@ -1531,15 +1530,6 @@ static int nsp_eh_host_reset(struct scsi_cmnd *SCpnt) PCMCIA functions **********************************************************************/ -/*====================================================================== - nsp_cs_attach() creates an "instance" of the driver, allocating - local data structures for one device. The device is registered - with Card Services. - - The dev_link structure is initialized, but we don't actually - configure the card at this point -- we wait until we receive a - card insertion event. -======================================================================*/ static int nsp_cs_probe(struct pcmcia_device *link) { scsi_info_t *info; @@ -1557,14 +1547,6 @@ static int nsp_cs_probe(struct pcmcia_device *link) nsp_dbg(NSP_DEBUG_INIT, "info=0x%p", info); - /* The io structure describes IO port mapping */ - link->resource[0]->end = 0x10; - link->resource[0]->flags = IO_DATA_PATH_WIDTH_AUTO; - - /* General socket configuration */ - link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.IntType = INT_MEMORY_AND_IO; - ret = nsp_cs_config(link); nsp_dbg(NSP_DEBUG_INIT, "link=0x%p", link); @@ -1572,12 +1554,6 @@ static int nsp_cs_probe(struct pcmcia_device *link) } /* nsp_cs_attach */ -/*====================================================================== - This deletes a driver "instance". The device is de-registered - with Card Services. If it has been released, all local data - structures are freed. Otherwise, the structures will be freed - when the device is released. -======================================================================*/ static void nsp_cs_detach(struct pcmcia_device *link) { nsp_dbg(NSP_DEBUG_INIT, "in, link=0x%p", link); @@ -1590,98 +1566,36 @@ static void nsp_cs_detach(struct pcmcia_device *link) } /* nsp_cs_detach */ -/*====================================================================== - nsp_cs_config() is scheduled to run after a CARD_INSERTION event - is received, to configure the PCMCIA socket, and to make the - ethernet device available to the system. -======================================================================*/ - -struct nsp_cs_configdata { - nsp_hw_data *data; - win_req_t req; -}; - -static int nsp_cs_config_check(struct pcmcia_device *p_dev, - cistpl_cftable_entry_t *cfg, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, - void *priv_data) +static int nsp_cs_config_check(struct pcmcia_device *p_dev, void *priv_data) { - struct nsp_cs_configdata *cfg_mem = priv_data; + nsp_hw_data *data = priv_data; - if (cfg->index == 0) + if (p_dev->config_index == 0) return -ENODEV; - /* Does this card need audio output? */ - if (cfg->flags & CISTPL_CFTABLE_AUDIO) { - p_dev->conf.Attributes |= CONF_ENABLE_SPKR; - p_dev->conf.Status = CCSR_AUDIO_ENA; - } - - /* Use power settings for Vcc and Vpp if present */ - /* Note that the CIS values need to be rescaled */ - if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) { - if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM]/10000) - return -ENODEV; - else if (dflt->vcc.present & (1<<CISTPL_POWER_VNOM)) { - if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM]/10000) - return -ENODEV; - } - - if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) { - p_dev->conf.Vpp = - cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; - } else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM)) { - p_dev->conf.Vpp = - dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000; - } - - /* Do we need to allocate an interrupt? */ - p_dev->conf.Attributes |= CONF_ENABLE_IRQ; - - /* IO window settings */ - p_dev->resource[0]->end = p_dev->resource[1]->end = 0; - if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) { - cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io; - p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK; - p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; - p_dev->resource[0]->flags |= - pcmcia_io_cfg_data_width(io->flags); - p_dev->resource[0]->start = io->win[0].base; - p_dev->resource[0]->end = io->win[0].len; - if (io->nwin > 1) { - p_dev->resource[1]->flags = - p_dev->resource[0]->flags; - p_dev->resource[1]->start = io->win[1].base; - p_dev->resource[1]->end = io->win[1].len; - } - /* This reserves IO space but doesn't actually enable it */ - if (pcmcia_request_io(p_dev) != 0) - goto next_entry; - } - - if ((cfg->mem.nwin > 0) || (dflt->mem.nwin > 0)) { - cistpl_mem_t *mem = - (cfg->mem.nwin) ? &cfg->mem : &dflt->mem; - cfg_mem->req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM; - cfg_mem->req.Attributes |= WIN_ENABLE; - cfg_mem->req.Base = mem->win[0].host_addr; - cfg_mem->req.Size = mem->win[0].len; - if (cfg_mem->req.Size < 0x1000) - cfg_mem->req.Size = 0x1000; - cfg_mem->req.AccessSpeed = 0; - if (pcmcia_request_window(p_dev, &cfg_mem->req, &p_dev->win) != 0) - goto next_entry; - if (pcmcia_map_mem_page(p_dev, p_dev->win, - mem->win[0].card_addr) != 0) - goto next_entry; - - cfg_mem->data->MmioAddress = (unsigned long) ioremap_nocache(cfg_mem->req.Base, cfg_mem->req.Size); - cfg_mem->data->MmioLength = cfg_mem->req.Size; - } - /* If we got this far, we're cool! */ - return 0; + /* This reserves IO space but doesn't actually enable it */ + if (pcmcia_request_io(p_dev) != 0) + goto next_entry; + + if (resource_size(p_dev->resource[2])) { + p_dev->resource[2]->flags |= (WIN_DATA_WIDTH_16 | + WIN_MEMORY_TYPE_CM | + WIN_ENABLE); + if (p_dev->resource[2]->end < 0x1000) + p_dev->resource[2]->end = 0x1000; + if (pcmcia_request_window(p_dev, p_dev->resource[2], 0) != 0) + goto next_entry; + if (pcmcia_map_mem_page(p_dev, p_dev->resource[2], + p_dev->card_addr) != 0) + goto next_entry; + + data->MmioAddress = (unsigned long) + ioremap_nocache(p_dev->resource[2]->start, + resource_size(p_dev->resource[2])); + data->MmioLength = resource_size(p_dev->resource[2]); } + /* If we got this far, we're cool! */ + return 0; next_entry: nsp_dbg(NSP_DEBUG_INIT, "next"); @@ -1693,25 +1607,23 @@ static int nsp_cs_config(struct pcmcia_device *link) { int ret; scsi_info_t *info = link->priv; - struct nsp_cs_configdata *cfg_mem; struct Scsi_Host *host; nsp_hw_data *data = &nsp_data_base; nsp_dbg(NSP_DEBUG_INIT, "in"); - cfg_mem = kzalloc(sizeof(*cfg_mem), GFP_KERNEL); - if (!cfg_mem) - return -ENOMEM; - cfg_mem->data = data; + link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_CHECK_VCC | + CONF_AUTO_SET_VPP | CONF_AUTO_AUDIO | CONF_AUTO_SET_IOMEM | + CONF_AUTO_SET_IO; - ret = pcmcia_loop_config(link, nsp_cs_config_check, cfg_mem); + ret = pcmcia_loop_config(link, nsp_cs_config_check, data); if (ret) goto cs_failed; if (pcmcia_request_irq(link, nspintr)) goto cs_failed; - ret = pcmcia_request_configuration(link, &link->conf); + ret = pcmcia_enable_device(link); if (ret) goto cs_failed; @@ -1754,41 +1666,16 @@ static int nsp_cs_config(struct pcmcia_device *link) info->host = host; - /* Finally, report what we've done */ - printk(KERN_INFO "nsp_cs: index 0x%02x: ", - link->conf.ConfigIndex); - if (link->conf.Vpp) { - printk(", Vpp %d.%d", link->conf.Vpp/10, link->conf.Vpp%10); - } - if (link->conf.Attributes & CONF_ENABLE_IRQ) { - printk(", irq %d", link->irq); - } - if (link->resource[0]) - printk(", io %pR", link->resource[0]); - if (link->resource[1]) - printk(" & %pR", link->resource[1]); - if (link->win) - printk(", mem 0x%06lx-0x%06lx", cfg_mem->req.Base, - cfg_mem->req.Base+cfg_mem->req.Size-1); - printk("\n"); - - kfree(cfg_mem); return 0; cs_failed: nsp_dbg(NSP_DEBUG_INIT, "config fail"); nsp_cs_release(link); - kfree(cfg_mem); return -ENODEV; } /* nsp_cs_config */ -/*====================================================================== - After a card is removed, nsp_cs_release() will unregister the net - device, and release the PCMCIA configuration. If the device is - still open, this will be postponed until it is closed. -======================================================================*/ static void nsp_cs_release(struct pcmcia_device *link) { scsi_info_t *info = link->priv; @@ -1807,7 +1694,7 @@ static void nsp_cs_release(struct pcmcia_device *link) scsi_remove_host(info->host); } - if (link->win) { + if (resource_size(link->resource[2])) { if (data != NULL) { iounmap((void *)(data->MmioAddress)); } @@ -1877,9 +1764,7 @@ MODULE_DEVICE_TABLE(pcmcia, nsp_cs_ids); static struct pcmcia_driver nsp_driver = { .owner = THIS_MODULE, - .drv = { - .name = "nsp_cs", - }, + .name = "nsp_cs", .probe = nsp_cs_probe, .remove = nsp_cs_detach, .id_table = nsp_cs_ids, @@ -1889,14 +1774,11 @@ static struct pcmcia_driver nsp_driver = { static int __init nsp_cs_init(void) { - nsp_msg(KERN_INFO, "loading..."); - return pcmcia_register_driver(&nsp_driver); } static void __exit nsp_cs_exit(void) { - nsp_msg(KERN_INFO, "unloading..."); pcmcia_unregister_driver(&nsp_driver); } diff --git a/drivers/scsi/pcmcia/qlogic_stub.c b/drivers/scsi/pcmcia/qlogic_stub.c index eb775f1a523c..9c96ca889ec9 100644 --- a/drivers/scsi/pcmcia/qlogic_stub.c +++ b/drivers/scsi/pcmcia/qlogic_stub.c @@ -48,7 +48,6 @@ #include <scsi/scsi_host.h> #include "../qlogicfas408.h" -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/ds.h> #include <pcmcia/ciscode.h> @@ -156,11 +155,8 @@ static int qlogic_probe(struct pcmcia_device *link) return -ENOMEM; info->p_dev = link; link->priv = info; - link->resource[0]->end = 16; - link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; - link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.IntType = INT_MEMORY_AND_IO; - link->conf.Present = PRESENT_OPTION; + link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; + link->config_regs = PRESENT_OPTION; return qlogic_config(link); } /* qlogic_attach */ @@ -178,15 +174,11 @@ static void qlogic_detach(struct pcmcia_device *link) /*====================================================================*/ -static int qlogic_config_check(struct pcmcia_device *p_dev, - cistpl_cftable_entry_t *cfg, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, - void *priv_data) +static int qlogic_config_check(struct pcmcia_device *p_dev, void *priv_data) { p_dev->io_lines = 10; - p_dev->resource[0]->start = cfg->io.win[0].base; - p_dev->resource[0]->end = cfg->io.win[0].len; + p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; + p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; if (p_dev->resource[0]->start == 0) return -ENODEV; @@ -209,7 +201,7 @@ static int qlogic_config(struct pcmcia_device * link) if (!link->irq) goto failed; - ret = pcmcia_request_configuration(link, &link->conf); + ret = pcmcia_enable_device(link); if (ret) goto failed; @@ -264,7 +256,7 @@ static int qlogic_resume(struct pcmcia_device *link) { scsi_info_t *info = link->priv; - pcmcia_request_configuration(link, &link->conf); + pcmcia_enable_device(link); if ((info->manf_id == MANFID_MACNICA) || (info->manf_id == MANFID_PIONEER) || (info->manf_id == 0x0098)) { @@ -302,9 +294,7 @@ MODULE_DEVICE_TABLE(pcmcia, qlogic_ids); static struct pcmcia_driver qlogic_cs_driver = { .owner = THIS_MODULE, - .drv = { .name = "qlogic_cs", - }, .probe = qlogic_probe, .remove = qlogic_detach, .id_table = qlogic_ids, diff --git a/drivers/scsi/pcmcia/sym53c500_cs.c b/drivers/scsi/pcmcia/sym53c500_cs.c index 321e390c9120..0ae27cb5cd6f 100644 --- a/drivers/scsi/pcmcia/sym53c500_cs.c +++ b/drivers/scsi/pcmcia/sym53c500_cs.c @@ -71,7 +71,6 @@ #include <scsi/scsi.h> #include <scsi/scsi_host.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/ds.h> #include <pcmcia/ciscode.h> @@ -684,15 +683,11 @@ static struct scsi_host_template sym53c500_driver_template = { .shost_attrs = SYM53C500_shost_attrs }; -static int SYM53C500_config_check(struct pcmcia_device *p_dev, - cistpl_cftable_entry_t *cfg, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, - void *priv_data) +static int SYM53C500_config_check(struct pcmcia_device *p_dev, void *priv_data) { p_dev->io_lines = 10; - p_dev->resource[0]->start = cfg->io.win[0].base; - p_dev->resource[0]->end = cfg->io.win[0].len; + p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; + p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; if (p_dev->resource[0]->start == 0) return -ENODEV; @@ -721,7 +716,7 @@ SYM53C500_config(struct pcmcia_device *link) if (!link->irq) goto failed; - ret = pcmcia_request_configuration(link, &link->conf); + ret = pcmcia_enable_device(link); if (ret) goto failed; @@ -859,10 +854,7 @@ SYM53C500_probe(struct pcmcia_device *link) return -ENOMEM; info->p_dev = link; link->priv = info; - link->resource[0]->end = 16; - link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; - link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.IntType = INT_MEMORY_AND_IO; + link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; return SYM53C500_config(link); } /* SYM53C500_attach */ @@ -881,9 +873,7 @@ MODULE_DEVICE_TABLE(pcmcia, sym53c500_ids); static struct pcmcia_driver sym53c500_cs_driver = { .owner = THIS_MODULE, - .drv = { - .name = "sym53c500_cs", - }, + .name = "sym53c500_cs", .probe = SYM53C500_probe, .remove = SYM53C500_detach, .id_table = sym53c500_ids, diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c index 9793aa6afb10..d8db0137c0c7 100644 --- a/drivers/scsi/pm8001/pm8001_hwi.c +++ b/drivers/scsi/pm8001/pm8001_hwi.c @@ -4194,6 +4194,8 @@ static int pm8001_chip_get_nvmd_req(struct pm8001_hba_info *pm8001_ha, nvmd_type = ioctl_payload->minor_function; fw_control_context = kzalloc(sizeof(struct fw_control_ex), GFP_KERNEL); + if (!fw_control_context) + return -ENOMEM; fw_control_context->usrAddr = (u8 *)&ioctl_payload->func_specific[0]; fw_control_context->len = ioctl_payload->length; circularQ = &pm8001_ha->inbnd_q_tbl[0]; @@ -4272,6 +4274,8 @@ static int pm8001_chip_set_nvmd_req(struct pm8001_hba_info *pm8001_ha, nvmd_type = ioctl_payload->minor_function; fw_control_context = kzalloc(sizeof(struct fw_control_ex), GFP_KERNEL); + if (!fw_control_context) + return -ENOMEM; circularQ = &pm8001_ha->inbnd_q_tbl[0]; memcpy(pm8001_ha->memoryMap.region[NVMD].virt_ptr, ioctl_payload->func_specific, @@ -4381,6 +4385,8 @@ pm8001_chip_fw_flash_update_req(struct pm8001_hba_info *pm8001_ha, struct pm8001_ioctl_payload *ioctl_payload = payload; fw_control_context = kzalloc(sizeof(struct fw_control_ex), GFP_KERNEL); + if (!fw_control_context) + return -ENOMEM; fw_control = (struct fw_control_info *)&ioctl_payload->func_specific[0]; if (fw_control->len != 0) { if (pm8001_mem_alloc(pm8001_ha->pdev, diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c index ecc45c8b4e6b..4b8765785aeb 100644 --- a/drivers/scsi/pmcraid.c +++ b/drivers/scsi/pmcraid.c @@ -4165,6 +4165,7 @@ static const struct file_operations pmcraid_fops = { #ifdef CONFIG_COMPAT .compat_ioctl = pmcraid_chr_ioctl, #endif + .llseek = noop_llseek, }; diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 114bc5a81171..2ff4342ae362 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -1538,22 +1538,22 @@ qla2x00_dev_loss_tmo_callbk(struct fc_rport *rport) if (!fcport) return; - if (test_bit(ABORT_ISP_ACTIVE, &fcport->vha->dpc_flags)) - return; - - if (unlikely(pci_channel_offline(fcport->vha->hw->pdev))) { - qla2x00_abort_all_cmds(fcport->vha, DID_NO_CONNECT << 16); - return; - } - /* * Transport has effectively 'deleted' the rport, clear * all local references. */ spin_lock_irq(host->host_lock); - fcport->rport = NULL; + fcport->rport = fcport->drport = NULL; *((fc_port_t **)rport->dd_data) = NULL; spin_unlock_irq(host->host_lock); + + if (test_bit(ABORT_ISP_ACTIVE, &fcport->vha->dpc_flags)) + return; + + if (unlikely(pci_channel_offline(fcport->vha->hw->pdev))) { + qla2x00_abort_all_cmds(fcport->vha, DID_NO_CONNECT << 16); + return; + } } static void @@ -1676,14 +1676,14 @@ static void qla2x00_get_host_fabric_name(struct Scsi_Host *shost) { scsi_qla_host_t *vha = shost_priv(shost); - u64 node_name; + uint8_t node_name[WWN_SIZE] = { 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF}; + u64 fabric_name = wwn_to_u64(node_name); if (vha->device_flags & SWITCH_FOUND) - node_name = wwn_to_u64(vha->fabric_node_name); - else - node_name = wwn_to_u64(vha->node_name); + fabric_name = wwn_to_u64(vha->fabric_node_name); - fc_host_fabric_name(shost) = node_name; + fc_host_fabric_name(shost) = fabric_name; } static void @@ -1776,6 +1776,7 @@ qla24xx_vport_create(struct fc_vport *fc_vport, bool disable) } /* initialize attributes */ + fc_host_dev_loss_tmo(vha->host) = ha->port_down_retry_count; fc_host_node_name(vha->host) = wwn_to_u64(vha->node_name); fc_host_port_name(vha->host) = wwn_to_u64(vha->port_name); fc_host_supported_classes(vha->host) = @@ -1984,6 +1985,7 @@ qla2x00_init_host_attr(scsi_qla_host_t *vha) struct qla_hw_data *ha = vha->hw; u32 speed = FC_PORTSPEED_UNKNOWN; + fc_host_dev_loss_tmo(vha->host) = ha->port_down_retry_count; fc_host_node_name(vha->host) = wwn_to_u64(vha->node_name); fc_host_port_name(vha->host) = wwn_to_u64(vha->port_name); fc_host_supported_classes(vha->host) = FC_COS_CLASS3; diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c index 9067629817ea..fdfbf83a6330 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.c +++ b/drivers/scsi/qla2xxx/qla_bsg.c @@ -1254,10 +1254,9 @@ 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)); + if (atomic_read(&fcport->state) != FCS_ONLINE) { + DEBUG2(printk(KERN_ERR "%s(%ld): Port not online\n", + __func__, vha->host_no)); return -EINVAL; } diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index d2a4e1530708..e1d3ad40a946 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -706,6 +706,11 @@ typedef struct { #define MBC_SET_PORT_CONFIG 0x122 /* Set port configuration */ #define MBC_GET_PORT_CONFIG 0x123 /* Get port configuration */ +/* + * ISP81xx mailbox commands + */ +#define MBC_WRITE_MPI_REGISTER 0x01 /* Write MPI Register. */ + /* Firmware return data sizes */ #define FCAL_MAP_SIZE 128 @@ -2860,6 +2865,7 @@ typedef struct scsi_qla_host { #define NPIV_CONFIG_NEEDED 16 #define ISP_UNRECOVERABLE 17 #define FCOE_CTX_RESET_NEEDED 18 /* Initiate FCoE context reset */ +#define MPI_RESET_NEEDED 19 /* Initiate MPI FW reset */ uint32_t device_flags; #define SWITCH_FOUND BIT_0 @@ -3003,6 +3009,8 @@ typedef struct scsi_qla_host { #define CMD_SP(Cmnd) ((Cmnd)->SCp.ptr) +#define QLA_SG_ALL 1024 + enum nexus_wait_type { WAIT_HOST = 0, WAIT_TARGET, diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 1a1b281cea33..c33dec827e1e 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -352,6 +352,8 @@ qla2x00_read_ram_word(scsi_qla_host_t *, uint32_t, uint32_t *); extern int qla2x00_write_ram_word(scsi_qla_host_t *, uint32_t, uint32_t); +extern int +qla81xx_write_mpi_register(scsi_qla_host_t *, uint16_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 *); @@ -501,7 +503,6 @@ extern void qla24xx_wrt_rsp_reg(struct qla_hw_data *, uint16_t, uint16_t); /* PCI related functions */ extern int qla82xx_pci_config(struct scsi_qla_host *); 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_iospace_config(struct qla_hw_data *); @@ -509,8 +510,8 @@ 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_pinit_from_rom(scsi_qla_host_t *); extern void qla82xx_watchdog(scsi_qla_host_t *); +extern int qla82xx_start_firmware(scsi_qla_host_t *); /* Firmware and flash related functions */ extern int qla82xx_load_risc(scsi_qla_host_t *, uint32_t *); @@ -533,25 +534,17 @@ extern irqreturn_t qla82xx_msix_default(int, void *); extern irqreturn_t qla82xx_msix_rsp_q(int, void *); extern void qla82xx_enable_intrs(struct qla_hw_data *); extern void qla82xx_disable_intrs(struct qla_hw_data *); -extern void qla82xx_mbx_completion(scsi_qla_host_t *, uint16_t); extern void qla82xx_poll(int, void *); extern void qla82xx_init_flags(struct qla_hw_data *); /* ISP 8021 hardware related */ -extern int qla82xx_crb_win_lock(struct qla_hw_data *); +extern void qla82xx_set_drv_active(scsi_qla_host_t *); extern void qla82xx_crb_win_unlock(struct qla_hw_data *); -extern int qla82xx_pci_get_crb_addr_2M(struct qla_hw_data *, ulong *); extern int qla82xx_wr_32(struct qla_hw_data *, ulong, u32); extern int qla82xx_rd_32(struct qla_hw_data *, ulong); extern int qla82xx_rdmem(struct qla_hw_data *, u64, void *, int); extern int qla82xx_wrmem(struct qla_hw_data *, u64, void *, int); -extern int qla82xx_check_for_bad_spd(struct qla_hw_data *); -extern int qla82xx_load_fw(scsi_qla_host_t *); -extern int qla82xx_rom_lock(struct qla_hw_data *); extern void qla82xx_rom_unlock(struct qla_hw_data *); -extern int qla82xx_rom_fast_read(struct qla_hw_data *, int , int *); -extern int qla82xx_do_rom_fast_read(struct qla_hw_data *, int, int *); -extern unsigned long qla82xx_decode_crb_addr(unsigned long); /* ISP 8021 IDC */ extern void qla82xx_clear_drv_active(struct qla_hw_data *); diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 9c383baebe27..3cafbef40737 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -954,6 +954,19 @@ qla2x00_reset_chip(scsi_qla_host_t *vha) } /** + * qla81xx_reset_mpi() - Reset's MPI FW via Write MPI Register MBC. + * + * Returns 0 on success. + */ +int +qla81xx_reset_mpi(scsi_qla_host_t *vha) +{ + uint16_t mb[4] = {0x1010, 0, 1, 0}; + + return qla81xx_write_mpi_register(vha, mb); +} + +/** * qla24xx_reset_risc() - Perform full reset of ISP24xx RISC. * @ha: HA context * @@ -967,6 +980,7 @@ qla24xx_reset_risc(scsi_qla_host_t *vha) struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; uint32_t cnt, d2; uint16_t wd; + static int abts_cnt; /* ISP abort retry counts */ spin_lock_irqsave(&ha->hardware_lock, flags); @@ -1000,6 +1014,23 @@ qla24xx_reset_risc(scsi_qla_host_t *vha) barrier(); } + /* If required, do an MPI FW reset now */ + if (test_and_clear_bit(MPI_RESET_NEEDED, &vha->dpc_flags)) { + if (qla81xx_reset_mpi(vha) != QLA_SUCCESS) { + if (++abts_cnt < 5) { + set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); + set_bit(MPI_RESET_NEEDED, &vha->dpc_flags); + } else { + /* + * We exhausted the ISP abort retries. We have to + * set the board offline. + */ + abts_cnt = 0; + vha->flags.online = 0; + } + } + } + WRT_REG_DWORD(®->hccr, HCCRX_SET_RISC_RESET); RD_REG_DWORD(®->hccr); @@ -2799,6 +2830,9 @@ qla2x00_iidma_fcport(scsi_qla_host_t *vha, fc_port_t *fcport) if (!IS_IIDMA_CAPABLE(ha)) return; + if (atomic_read(&fcport->state) != FCS_ONLINE) + return; + if (fcport->fp_speed == PORT_SPEED_UNKNOWN || fcport->fp_speed > ha->link_data_rate) return; @@ -3878,17 +3912,19 @@ qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha) LOOP_DOWN_TIME); } - /* Make sure for ISP 82XX IO DMA is complete */ - 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")); + if (!ha->flags.eeh_busy) { + /* Make sure for ISP 82XX IO DMA is complete */ + 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); + /* Requeue all commands in outstanding command list. */ + qla2x00_abort_all_cmds(vha, DID_RESET << 16); + } } /* diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 28f65be19dad..e0e43d9e7ed1 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -412,8 +412,14 @@ skip_rio: "Unrecoverable Hardware Error: adapter " "marked OFFLINE!\n"); vha->flags.online = 0; - } else + } else { + /* Check to see if MPI timeout occured */ + if ((mbx & MBX_3) && (ha->flags.port0)) + set_bit(MPI_RESET_NEEDED, + &vha->dpc_flags); + set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); + } } else if (mb[1] == 0) { qla_printk(KERN_INFO, ha, "Unrecoverable Hardware Error: adapter marked " diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index a595ec8264f8..effd8a1403d9 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -3828,8 +3828,6 @@ qla2x00_loopback_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq, /* Copy mailbox information */ memcpy( mresp, mcp->mb, 64); - mresp[3] = mcp->mb[18]; - mresp[4] = mcp->mb[19]; return rval; } @@ -3890,9 +3888,10 @@ qla2x00_echo_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq, } /* Copy mailbox information */ - memcpy( mresp, mcp->mb, 32); + memcpy(mresp, mcp->mb, 64); return rval; } + int qla84xx_reset_chip(scsi_qla_host_t *ha, uint16_t enable_diagnostic) { @@ -3953,6 +3952,67 @@ qla2x00_write_ram_word(scsi_qla_host_t *vha, uint32_t risc_addr, uint32_t data) } int +qla81xx_write_mpi_register(scsi_qla_host_t *vha, uint16_t *mb) +{ + int rval; + uint32_t stat, timer; + uint16_t mb0 = 0; + struct qla_hw_data *ha = vha->hw; + struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; + + rval = QLA_SUCCESS; + + DEBUG11(qla_printk(KERN_INFO, ha, + "%s(%ld): entered.\n", __func__, vha->host_no)); + + clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); + + /* Write the MBC data to the registers */ + WRT_REG_WORD(®->mailbox0, MBC_WRITE_MPI_REGISTER); + WRT_REG_WORD(®->mailbox1, mb[0]); + WRT_REG_WORD(®->mailbox2, mb[1]); + WRT_REG_WORD(®->mailbox3, mb[2]); + WRT_REG_WORD(®->mailbox4, mb[3]); + + WRT_REG_DWORD(®->hccr, HCCRX_SET_HOST_INT); + + /* Poll for MBC interrupt */ + for (timer = 6000000; timer; timer--) { + /* Check for pending interrupts. */ + stat = RD_REG_DWORD(®->host_status); + if (stat & HSRX_RISC_INT) { + stat &= 0xff; + + if (stat == 0x1 || stat == 0x2 || + stat == 0x10 || stat == 0x11) { + set_bit(MBX_INTERRUPT, + &ha->mbx_cmd_flags); + mb0 = RD_REG_WORD(®->mailbox0); + WRT_REG_DWORD(®->hccr, + HCCRX_CLR_RISC_INT); + RD_REG_DWORD(®->hccr); + break; + } + } + udelay(5); + } + + if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) + rval = mb0 & MBS_MASK; + else + rval = QLA_FUNCTION_FAILED; + + if (rval != QLA_SUCCESS) { + DEBUG2_3_11(printk(KERN_INFO "%s(%ld): failed=%x mb[0]=%x.\n", + __func__, vha->host_no, rval, mb[0])); + } else { + DEBUG11(printk(KERN_INFO + "%s(%ld): done.\n", __func__, vha->host_no)); + } + + return rval; +} +int qla2x00_get_data_rate(scsi_qla_host_t *vha) { int rval; diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index 0a71cc71eab2..8d9edfb39803 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c @@ -403,6 +403,54 @@ qla82xx_pci_set_crbwindow(struct qla_hw_data *ha, u64 off) return off; } +static int +qla82xx_pci_get_crb_addr_2M(struct qla_hw_data *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; +} + +#define CRB_WIN_LOCK_TIMEOUT 100000000 +static int qla82xx_crb_win_lock(struct qla_hw_data *ha) +{ + int done = 0, timeout = 0; + + while (!done) { + /* acquire semaphore3 from PCI HW block */ + done = qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM7_LOCK)); + if (done == 1) + break; + if (timeout >= CRB_WIN_LOCK_TIMEOUT) + return -1; + timeout++; + } + qla82xx_wr_32(ha, QLA82XX_CRB_WIN_LOCK_ID, ha->portnum); + return 0; +} + int qla82xx_wr_32(struct qla_hw_data *ha, ulong off, u32 data) { @@ -453,24 +501,6 @@ qla82xx_rd_32(struct qla_hw_data *ha, ulong off) return data; } -#define CRB_WIN_LOCK_TIMEOUT 100000000 -int qla82xx_crb_win_lock(struct qla_hw_data *ha) -{ - int done = 0, timeout = 0; - - while (!done) { - /* acquire semaphore3 from PCI HW block */ - done = qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM7_LOCK)); - if (done == 1) - break; - if (timeout >= CRB_WIN_LOCK_TIMEOUT) - return -1; - timeout++; - } - qla82xx_wr_32(ha, QLA82XX_CRB_WIN_LOCK_ID, ha->portnum); - return 0; -} - #define IDC_LOCK_TIMEOUT 100000000 int qla82xx_idc_lock(struct qla_hw_data *ha) { @@ -504,36 +534,6 @@ void qla82xx_idc_unlock(struct qla_hw_data *ha) qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM5_UNLOCK)); } -int -qla82xx_pci_get_crb_addr_2M(struct qla_hw_data *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))) @@ -557,7 +557,7 @@ qla82xx_pci_mem_bound_check(struct qla_hw_data *ha, int qla82xx_pci_set_window_warning_count; -unsigned long +static unsigned long qla82xx_pci_set_window(struct qla_hw_data *ha, unsigned long long addr) { int window; @@ -798,7 +798,8 @@ qla82xx_pci_mem_write_direct(struct qla_hw_data *ha, } #define MTU_FUDGE_FACTOR 100 -unsigned long qla82xx_decode_crb_addr(unsigned long addr) +static unsigned long +qla82xx_decode_crb_addr(unsigned long addr) { int i; unsigned long base_addr, offset, pci_base; @@ -824,7 +825,7 @@ unsigned long qla82xx_decode_crb_addr(unsigned long addr) static long rom_max_timeout = 100; static long qla82xx_rom_lock_timeout = 100; -int +static int qla82xx_rom_lock(struct qla_hw_data *ha) { int done = 0, timeout = 0; @@ -842,7 +843,7 @@ qla82xx_rom_lock(struct qla_hw_data *ha) return 0; } -int +static int qla82xx_wait_rom_busy(struct qla_hw_data *ha) { long timeout = 0; @@ -862,7 +863,7 @@ qla82xx_wait_rom_busy(struct qla_hw_data *ha) return 0; } -int +static int qla82xx_wait_rom_done(struct qla_hw_data *ha) { long timeout = 0; @@ -882,7 +883,7 @@ qla82xx_wait_rom_done(struct qla_hw_data *ha) return 0; } -int +static int qla82xx_do_rom_fast_read(struct qla_hw_data *ha, int addr, int *valp) { qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_ADDRESS, addr); @@ -905,7 +906,7 @@ qla82xx_do_rom_fast_read(struct qla_hw_data *ha, int addr, int *valp) return 0; } -int +static int qla82xx_rom_fast_read(struct qla_hw_data *ha, int addr, int *valp) { int ret, loops = 0; @@ -926,7 +927,7 @@ qla82xx_rom_fast_read(struct qla_hw_data *ha, int addr, int *valp) return ret; } -int +static int qla82xx_read_status_reg(struct qla_hw_data *ha, uint32_t *val) { qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, M25P_INSTR_RDSR); @@ -940,7 +941,7 @@ qla82xx_read_status_reg(struct qla_hw_data *ha, uint32_t *val) return 0; } -int +static int qla82xx_flash_wait_write_finish(struct qla_hw_data *ha) { long timeout = 0; @@ -964,7 +965,7 @@ qla82xx_flash_wait_write_finish(struct qla_hw_data *ha) return ret; } -int +static int qla82xx_flash_set_write_enable(struct qla_hw_data *ha) { uint32_t val; @@ -981,7 +982,7 @@ qla82xx_flash_set_write_enable(struct qla_hw_data *ha) return 0; } -int +static int qla82xx_write_status_reg(struct qla_hw_data *ha, uint32_t val) { if (qla82xx_flash_set_write_enable(ha)) @@ -996,7 +997,7 @@ qla82xx_write_status_reg(struct qla_hw_data *ha, uint32_t val) return qla82xx_flash_wait_write_finish(ha); } -int +static int qla82xx_write_disable_flash(struct qla_hw_data *ha) { qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, M25P_INSTR_WRDI); @@ -1008,7 +1009,7 @@ qla82xx_write_disable_flash(struct qla_hw_data *ha) return 0; } -int +static int ql82xx_rom_lock_d(struct qla_hw_data *ha) { int loops = 0; @@ -1024,7 +1025,7 @@ ql82xx_rom_lock_d(struct qla_hw_data *ha) return 0;; } -int +static int qla82xx_write_flash_dword(struct qla_hw_data *ha, uint32_t flashaddr, uint32_t data) { @@ -1061,7 +1062,8 @@ done_write: /* This routine does CRB initialize sequence * to put the ISP into operational state */ -int qla82xx_pinit_from_rom(scsi_qla_host_t *vha) +static int +qla82xx_pinit_from_rom(scsi_qla_host_t *vha) { int addr, val; int i ; @@ -1207,7 +1209,8 @@ int qla82xx_pinit_from_rom(scsi_qla_host_t *vha) return 0; } -int qla82xx_check_for_bad_spd(struct qla_hw_data *ha) +static int +qla82xx_check_for_bad_spd(struct qla_hw_data *ha) { u32 val = 0; val = qla82xx_rd_32(ha, BOOT_LOADER_DIMM_STATUS); @@ -1225,7 +1228,116 @@ int qla82xx_check_for_bad_spd(struct qla_hw_data *ha) return 0; } -int +static int +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, 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 (qla82xx_pci_mem_bound_check(ha, off, size) == 0) + return qla82xx_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 (qla82xx_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); + } + + /* + * don't lock here - write_wx gets the lock if each time + * write_lock_irqsave(&adapter->adapter_lock, flags); + * netxen_nic_pci_change_crbwindow_128M(adapter, 0); + */ + for (i = 0; i < loop; i++) { + temp = off8 + (i << shift_amount); + 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 * scale] & 0xffffffff; + 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); + 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); + 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) { + if (printk_ratelimit()) + dev_err(&ha->pdev->dev, + "failed to write through agent\n"); + ret = -1; + break; + } + } + + return ret; +} + +static int qla82xx_fw_load_from_flash(struct qla_hw_data *ha) { int i; @@ -1357,114 +1469,6 @@ qla82xx_pci_mem_read_2M(struct qla_hw_data *ha, return 0; } -int -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, 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 (qla82xx_pci_mem_bound_check(ha, off, size) == 0) - return qla82xx_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 (qla82xx_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); - } - - /* - * don't lock here - write_wx gets the lock if each time - * write_lock_irqsave(&adapter->adapter_lock, flags); - * netxen_nic_pci_change_crbwindow_128M(adapter, 0); - */ - for (i = 0; i < loop; i++) { - temp = off8 + (i << shift_amount); - 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 * scale] & 0xffffffff; - 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); - 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); - 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) { - if (printk_ratelimit()) - dev_err(&ha->pdev->dev, - "failed to write through agent\n"); - ret = -1; - break; - } - } - - return ret; -} static struct qla82xx_uri_table_desc * qla82xx_get_table_desc(const u8 *unirom, int section) @@ -1725,7 +1729,8 @@ void qla82xx_reset_adapter(struct scsi_qla_host *vha) ha->isp_ops->disable_intrs(ha); } -int qla82xx_fw_load_from_blob(struct qla_hw_data *ha) +static int +qla82xx_fw_load_from_blob(struct qla_hw_data *ha) { u64 *ptr64; u32 i, flashaddr, size; @@ -1836,7 +1841,8 @@ qla82xx_validate_firmware_blob(scsi_qla_host_t *vha, uint8_t fw_type) return 0; } -int qla82xx_check_cmdpeg_state(struct qla_hw_data *ha) +static int +qla82xx_check_cmdpeg_state(struct qla_hw_data *ha) { u32 val = 0; int retries = 60; @@ -1874,7 +1880,8 @@ int qla82xx_check_cmdpeg_state(struct qla_hw_data *ha) return QLA_FUNCTION_FAILED; } -int qla82xx_check_rcvpeg_state(struct qla_hw_data *ha) +static int +qla82xx_check_rcvpeg_state(struct qla_hw_data *ha) { u32 val = 0; int retries = 60; @@ -1933,7 +1940,7 @@ static struct qla82xx_legacy_intr_set legacy_intr[] = \ * @ha: SCSI driver HA context * @mb0: Mailbox0 register */ -void +static void qla82xx_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0) { uint16_t cnt; @@ -2257,7 +2264,7 @@ void qla82xx_init_flags(struct qla_hw_data *ha) ha->nx_legacy_intr.pci_int_reg = nx_legacy_intr->pci_int_reg; } -static inline void +inline void qla82xx_set_drv_active(scsi_qla_host_t *vha) { uint32_t drv_active; @@ -2267,10 +2274,11 @@ qla82xx_set_drv_active(scsi_qla_host_t *vha) /* If reset value is all FF's, initialize DRV_ACTIVE */ if (drv_active == 0xffffffff) { - qla82xx_wr_32(ha, QLA82XX_CRB_DRV_ACTIVE, 0); + qla82xx_wr_32(ha, QLA82XX_CRB_DRV_ACTIVE, + QLA82XX_DRV_NOT_ACTIVE); drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE); } - drv_active |= (1 << (ha->portnum * 4)); + drv_active |= (QLA82XX_DRV_ACTIVE << (ha->portnum * 4)); qla82xx_wr_32(ha, QLA82XX_CRB_DRV_ACTIVE, drv_active); } @@ -2280,7 +2288,7 @@ qla82xx_clear_drv_active(struct qla_hw_data *ha) uint32_t drv_active; drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE); - drv_active &= ~(1 << (ha->portnum * 4)); + drv_active &= ~(QLA82XX_DRV_ACTIVE << (ha->portnum * 4)); qla82xx_wr_32(ha, QLA82XX_CRB_DRV_ACTIVE, drv_active); } @@ -2291,7 +2299,7 @@ qla82xx_need_reset(struct qla_hw_data *ha) int rval; drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE); - rval = drv_state & (1 << (ha->portnum * 4)); + rval = drv_state & (QLA82XX_DRVST_RST_RDY << (ha->portnum * 4)); return rval; } @@ -2305,7 +2313,7 @@ qla82xx_set_rst_ready(struct qla_hw_data *ha) /* If reset value is all FF's, initialize DRV_STATE */ if (drv_state == 0xffffffff) { - qla82xx_wr_32(ha, QLA82XX_CRB_DRV_STATE, 0); + qla82xx_wr_32(ha, QLA82XX_CRB_DRV_STATE, QLA82XX_DRVST_NOT_RDY); drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE); } drv_state |= (QLA82XX_DRVST_RST_RDY << (ha->portnum * 4)); @@ -2335,7 +2343,8 @@ qla82xx_set_qsnt_ready(struct qla_hw_data *ha) qla82xx_wr_32(ha, QLA82XX_CRB_DRV_STATE, qsnt_state); } -int qla82xx_load_fw(scsi_qla_host_t *vha) +static int +qla82xx_load_fw(scsi_qla_host_t *vha) { int rst; struct fw_blob *blob; @@ -2411,7 +2420,7 @@ fw_load_failed: return QLA_FUNCTION_FAILED; } -static int +int qla82xx_start_firmware(scsi_qla_host_t *vha) { int pcie_cap; @@ -2419,7 +2428,7 @@ qla82xx_start_firmware(scsi_qla_host_t *vha) struct qla_hw_data *ha = vha->hw; /* scrub dma mask expansion register */ - qla82xx_wr_32(ha, CRB_DMA_SHIFT, 0x55555555); + qla82xx_wr_32(ha, CRB_DMA_SHIFT, QLA82XX_DMA_SHIFT_VALUE); /* Put both the PEG CMD and RCV PEG to default state * of 0 before resetting the hardware @@ -2882,7 +2891,7 @@ queuing_error: return QLA_FUNCTION_FAILED; } -uint32_t * +static uint32_t * qla82xx_read_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr, uint32_t length) { @@ -2903,7 +2912,7 @@ done_read: return dwptr; } -int +static int qla82xx_unprotect_flash(struct qla_hw_data *ha) { int ret; @@ -2934,7 +2943,7 @@ done_unprotect: return ret; } -int +static int qla82xx_protect_flash(struct qla_hw_data *ha) { int ret; @@ -2963,7 +2972,7 @@ done_protect: return ret; } -int +static int qla82xx_erase_sector(struct qla_hw_data *ha, int addr) { int ret = 0; @@ -3156,6 +3165,20 @@ qla82xx_start_iocbs(srb_t *sp) } } +void qla82xx_rom_lock_recovery(struct qla_hw_data *ha) +{ + if (qla82xx_rom_lock(ha)) + /* Someone else is holding the lock. */ + qla_printk(KERN_INFO, ha, "Resetting rom_lock\n"); + + /* + * Either we got the lock, or someone + * else died while holding it. + * In either case, unlock. + */ + qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_UNLOCK)); +} + /* * qla82xx_device_bootstrap * Initialize device, set DEV_READY, start fw @@ -3170,12 +3193,13 @@ qla82xx_start_iocbs(srb_t *sp) static int qla82xx_device_bootstrap(scsi_qla_host_t *vha) { - int rval, i, timeout; + int rval = QLA_SUCCESS; + int i, timeout; uint32_t old_count, count; struct qla_hw_data *ha = vha->hw; + int need_reset = 0, peg_stuck = 1; - if (qla82xx_need_reset(ha)) - goto dev_initialize; + need_reset = qla82xx_need_reset(ha); old_count = qla82xx_rd_32(ha, QLA82XX_PEG_ALIVE_COUNTER); @@ -3189,9 +3213,27 @@ qla82xx_device_bootstrap(scsi_qla_host_t *vha) count = qla82xx_rd_32(ha, QLA82XX_PEG_ALIVE_COUNTER); if (count != old_count) + peg_stuck = 0; + } + + if (need_reset) { + /* We are trying to perform a recovery here. */ + if (peg_stuck) + qla82xx_rom_lock_recovery(ha); + goto dev_initialize; + } else { + /* Start of day for this ha context. */ + if (peg_stuck) { + /* Either we are the first or recovery in progress. */ + qla82xx_rom_lock_recovery(ha); + goto dev_initialize; + } else + /* Firmware already running. */ goto dev_ready; } + return rval; + dev_initialize: /* set to DEV_INITIALIZING */ qla_printk(KERN_INFO, ha, "HW State: INITIALIZING\n"); @@ -3304,6 +3346,9 @@ qla82xx_check_fw_alive(scsi_qla_host_t *vha) struct qla_hw_data *ha = vha->hw; fw_heartbeat_counter = qla82xx_rd_32(ha, QLA82XX_PEG_ALIVE_COUNTER); + /* all 0xff, assume AER/EEH in progress, ignore */ + if (fw_heartbeat_counter == 0xffffffff) + return; if (vha->fw_heartbeat_counter == fw_heartbeat_counter) { vha->seconds_since_last_heartbeat++; /* FW not alive after 2 seconds */ diff --git a/drivers/scsi/qla2xxx/qla_nx.h b/drivers/scsi/qla2xxx/qla_nx.h index 15559cab39f8..51ec0c5380e8 100644 --- a/drivers/scsi/qla2xxx/qla_nx.h +++ b/drivers/scsi/qla2xxx/qla_nx.h @@ -26,6 +26,7 @@ #define CRB_RCVPEG_STATE QLA82XX_REG(0x13c) #define BOOT_LOADER_DIMM_STATUS QLA82XX_REG(0x54) #define CRB_DMA_SHIFT QLA82XX_REG(0xcc) +#define QLA82XX_DMA_SHIFT_VALUE 0x55555555 #define QLA82XX_HW_H0_CH_HUB_ADR 0x05 #define QLA82XX_HW_H1_CH_HUB_ADR 0x0E @@ -583,6 +584,10 @@ #define QLA82XX_DRVST_RST_RDY 1 #define QLA82XX_DRVST_QSNT_RDY 2 +/* Different drive active state */ +#define QLA82XX_DRV_NOT_ACTIVE 0 +#define QLA82XX_DRV_ACTIVE 1 + /* * The PCI VendorID and DeviceID for our board. */ diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 1e4bff695254..800ea9269752 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1295,17 +1295,12 @@ static int qla2xxx_slave_configure(struct scsi_device *sdev) { scsi_qla_host_t *vha = shost_priv(sdev->host); - struct qla_hw_data *ha = vha->hw; - struct fc_rport *rport = starget_to_rport(sdev->sdev_target); struct req_que *req = vha->req; if (sdev->tagged_supported) scsi_activate_tcq(sdev, req->max_q_depth); else scsi_deactivate_tcq(sdev, req->max_q_depth); - - rport->dev_loss_tmo = ha->port_down_retry_count; - return 0; } @@ -2141,8 +2136,16 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) else base_vha->mgmt_svr_loop_id = MANAGEMENT_SERVER + base_vha->vp_idx; - if (IS_QLA2100(ha)) - host->sg_tablesize = 32; + + /* Set the SG table size based on ISP type */ + if (!IS_FWI2_CAPABLE(ha)) { + if (IS_QLA2100(ha)) + host->sg_tablesize = 32; + } else { + if (!IS_QLA82XX(ha)) + host->sg_tablesize = QLA_SG_ALL; + } + host->max_id = max_id; host->this_id = 255; host->cmd_per_lun = 3; @@ -3553,6 +3556,11 @@ qla2x00_timer(scsi_qla_host_t *vha) struct qla_hw_data *ha = vha->hw; struct req_que *req; + if (ha->flags.eeh_busy) { + qla2x00_restart_timer(vha, WATCH_INTERVAL); + return; + } + if (IS_QLA82XX(ha)) qla82xx_watchdog(vha); @@ -3782,8 +3790,21 @@ qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) return PCI_ERS_RESULT_CAN_RECOVER; case pci_channel_io_frozen: ha->flags.eeh_busy = 1; + /* For ISP82XX complete any pending mailbox cmd */ + if (IS_QLA82XX(ha)) { + ha->flags.fw_hung = 1; + if (ha->flags.mbox_busy) { + ha->flags.mbox_int = 1; + DEBUG2(qla_printk(KERN_ERR, ha, + "Due to pci channel io frozen, doing premature " + "completion of mbx command\n")); + complete(&ha->mbx_intr_comp); + } + } qla2x00_free_irqs(vha); pci_disable_device(pdev); + /* Return back all IOs */ + qla2x00_abort_all_cmds(vha, DID_RESET << 16); return PCI_ERS_RESULT_NEED_RESET; case pci_channel_io_perm_failure: ha->flags.pci_channel_io_perm_failure = 1; @@ -3804,6 +3825,9 @@ qla2xxx_pci_mmio_enabled(struct pci_dev *pdev) struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; struct device_reg_24xx __iomem *reg24 = &ha->iobase->isp24; + if (IS_QLA82XX(ha)) + return PCI_ERS_RESULT_RECOVERED; + spin_lock_irqsave(&ha->hardware_lock, flags); if (IS_QLA2100(ha) || IS_QLA2200(ha)){ stat = RD_REG_DWORD(®->hccr); @@ -3830,6 +3854,109 @@ qla2xxx_pci_mmio_enabled(struct pci_dev *pdev) return PCI_ERS_RESULT_RECOVERED; } +uint32_t qla82xx_error_recovery(scsi_qla_host_t *base_vha) +{ + uint32_t rval = QLA_FUNCTION_FAILED; + uint32_t drv_active = 0; + struct qla_hw_data *ha = base_vha->hw; + int fn; + struct pci_dev *other_pdev = NULL; + + DEBUG17(qla_printk(KERN_INFO, ha, + "scsi(%ld): In qla82xx_error_recovery\n", base_vha->host_no)); + + set_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); + + if (base_vha->flags.online) { + /* Abort all outstanding commands, + * so as to be requeued later */ + qla2x00_abort_isp_cleanup(base_vha); + } + + + fn = PCI_FUNC(ha->pdev->devfn); + while (fn > 0) { + fn--; + DEBUG17(qla_printk(KERN_INFO, ha, + "Finding pci device at function = 0x%x\n", fn)); + other_pdev = + pci_get_domain_bus_and_slot(pci_domain_nr(ha->pdev->bus), + ha->pdev->bus->number, PCI_DEVFN(PCI_SLOT(ha->pdev->devfn), + fn)); + + if (!other_pdev) + continue; + if (atomic_read(&other_pdev->enable_cnt)) { + DEBUG17(qla_printk(KERN_INFO, ha, + "Found PCI func availabe and enabled at 0x%x\n", + fn)); + pci_dev_put(other_pdev); + break; + } + pci_dev_put(other_pdev); + } + + if (!fn) { + /* Reset owner */ + DEBUG17(qla_printk(KERN_INFO, ha, + "This devfn is reset owner = 0x%x\n", ha->pdev->devfn)); + qla82xx_idc_lock(ha); + + qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, + QLA82XX_DEV_INITIALIZING); + + qla82xx_wr_32(ha, QLA82XX_CRB_DRV_IDC_VERSION, + QLA82XX_IDC_VERSION); + + drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE); + DEBUG17(qla_printk(KERN_INFO, ha, + "drv_active = 0x%x\n", drv_active)); + + qla82xx_idc_unlock(ha); + /* Reset if device is not already reset + * drv_active would be 0 if a reset has already been done + */ + if (drv_active) + rval = qla82xx_start_firmware(base_vha); + else + rval = QLA_SUCCESS; + qla82xx_idc_lock(ha); + + if (rval != QLA_SUCCESS) { + qla_printk(KERN_INFO, ha, "HW State: FAILED\n"); + qla82xx_clear_drv_active(ha); + qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, + QLA82XX_DEV_FAILED); + } else { + qla_printk(KERN_INFO, ha, "HW State: READY\n"); + qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, + QLA82XX_DEV_READY); + qla82xx_idc_unlock(ha); + ha->flags.fw_hung = 0; + rval = qla82xx_restart_isp(base_vha); + qla82xx_idc_lock(ha); + /* Clear driver state register */ + qla82xx_wr_32(ha, QLA82XX_CRB_DRV_STATE, 0); + qla82xx_set_drv_active(base_vha); + } + qla82xx_idc_unlock(ha); + } else { + DEBUG17(qla_printk(KERN_INFO, ha, + "This devfn is not reset owner = 0x%x\n", ha->pdev->devfn)); + if ((qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE) == + QLA82XX_DEV_READY)) { + ha->flags.fw_hung = 0; + rval = qla82xx_restart_isp(base_vha); + qla82xx_idc_lock(ha); + qla82xx_set_drv_active(base_vha); + qla82xx_idc_unlock(ha); + } + } + clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); + + return rval; +} + static pci_ers_result_t qla2xxx_pci_slot_reset(struct pci_dev *pdev) { @@ -3862,15 +3989,23 @@ qla2xxx_pci_slot_reset(struct pci_dev *pdev) if (rc) { qla_printk(KERN_WARNING, ha, "Can't re-enable PCI device after reset.\n"); - return ret; + goto exit_slot_reset; } rsp = ha->rsp_q_map[0]; if (qla2x00_request_irqs(ha, rsp)) - return ret; + goto exit_slot_reset; if (ha->isp_ops->pci_config(base_vha)) - return ret; + goto exit_slot_reset; + + if (IS_QLA82XX(ha)) { + if (qla82xx_error_recovery(base_vha) == QLA_SUCCESS) { + ret = PCI_ERS_RESULT_RECOVERED; + goto exit_slot_reset; + } else + goto exit_slot_reset; + } while (ha->flags.mbox_busy && retries--) msleep(1000); @@ -3881,6 +4016,7 @@ qla2xxx_pci_slot_reset(struct pci_dev *pdev) clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); +exit_slot_reset: DEBUG17(qla_printk(KERN_WARNING, ha, "slot_reset-return:ret=%x\n", ret)); @@ -3948,6 +4084,7 @@ static struct pci_driver qla2xxx_pci_driver = { static struct file_operations apidev_fops = { .owner = THIS_MODULE, + .llseek = noop_llseek, }; /** diff --git a/drivers/scsi/qla4xxx/ql4_nx.c b/drivers/scsi/qla4xxx/ql4_nx.c index 5d4a3822382d..449256f2c5f8 100644 --- a/drivers/scsi/qla4xxx/ql4_nx.c +++ b/drivers/scsi/qla4xxx/ql4_nx.c @@ -5,6 +5,7 @@ * See LICENSE.qla4xxx for copyright and licensing details. */ #include <linux/delay.h> +#include <linux/io.h> #include <linux/pci.h> #include "ql4_def.h" #include "ql4_glbl.h" diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index b02bdc6c2cd1..2c36bae3bd4b 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -109,10 +109,12 @@ static const char * scsi_debug_version_date = "20100324"; #define DEF_PHYSBLK_EXP 0 #define DEF_LOWEST_ALIGNED 0 #define DEF_OPT_BLKS 64 -#define DEF_UNMAP_MAX_BLOCKS 0 -#define DEF_UNMAP_MAX_DESC 0 -#define DEF_UNMAP_GRANULARITY 0 +#define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF +#define DEF_UNMAP_MAX_DESC 256 +#define DEF_UNMAP_GRANULARITY 1 #define DEF_UNMAP_ALIGNMENT 0 +#define DEF_TPWS 0 +#define DEF_TPU 0 /* bit mask values for scsi_debug_opts */ #define SCSI_DEBUG_OPT_NOISE 1 @@ -177,10 +179,12 @@ static int scsi_debug_ato = DEF_ATO; static int scsi_debug_physblk_exp = DEF_PHYSBLK_EXP; static int scsi_debug_lowest_aligned = DEF_LOWEST_ALIGNED; static int scsi_debug_opt_blks = DEF_OPT_BLKS; -static int scsi_debug_unmap_max_desc = DEF_UNMAP_MAX_DESC; -static int scsi_debug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS; -static int scsi_debug_unmap_granularity = DEF_UNMAP_GRANULARITY; -static int scsi_debug_unmap_alignment = DEF_UNMAP_ALIGNMENT; +static unsigned int scsi_debug_unmap_max_desc = DEF_UNMAP_MAX_DESC; +static unsigned int scsi_debug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS; +static unsigned int scsi_debug_unmap_granularity = DEF_UNMAP_GRANULARITY; +static unsigned int scsi_debug_unmap_alignment = DEF_UNMAP_ALIGNMENT; +static unsigned int scsi_debug_tpws = DEF_TPWS; +static unsigned int scsi_debug_tpu = DEF_TPU; static int scsi_debug_cmnd_count = 0; @@ -723,16 +727,9 @@ static int inquiry_evpd_b0(unsigned char * arr) /* Optimal Transfer Length */ put_unaligned_be32(scsi_debug_opt_blks, &arr[8]); - if (scsi_debug_unmap_max_desc) { - unsigned int blocks; - - if (scsi_debug_unmap_max_blocks) - blocks = scsi_debug_unmap_max_blocks; - else - blocks = 0xffffffff; - + if (scsi_debug_tpu) { /* Maximum Unmap LBA Count */ - put_unaligned_be32(blocks, &arr[16]); + put_unaligned_be32(scsi_debug_unmap_max_blocks, &arr[16]); /* Maximum Unmap Block Descriptor Count */ put_unaligned_be32(scsi_debug_unmap_max_desc, &arr[20]); @@ -745,10 +742,9 @@ static int inquiry_evpd_b0(unsigned char * arr) } /* Optimal Unmap Granularity */ - if (scsi_debug_unmap_granularity) { - put_unaligned_be32(scsi_debug_unmap_granularity, &arr[24]); - return 0x3c; /* Mandatory page length for thin provisioning */ - } + put_unaligned_be32(scsi_debug_unmap_granularity, &arr[24]); + + return 0x3c; /* Mandatory page length for thin provisioning */ return sizeof(vpdb0_data); } @@ -765,6 +761,21 @@ static int inquiry_evpd_b1(unsigned char *arr) return 0x3c; } +/* Thin provisioning VPD page (SBC-3) */ +static int inquiry_evpd_b2(unsigned char *arr) +{ + memset(arr, 0, 0x8); + arr[0] = 0; /* threshold exponent */ + + if (scsi_debug_tpu) + arr[1] = 1 << 7; + + if (scsi_debug_tpws) + arr[1] |= 1 << 6; + + return 0x8; +} + #define SDEBUG_LONG_INQ_SZ 96 #define SDEBUG_MAX_INQ_ARR_SZ 584 @@ -820,6 +831,7 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target, arr[n++] = 0x89; /* ATA information */ arr[n++] = 0xb0; /* Block limits (SBC) */ arr[n++] = 0xb1; /* Block characteristics (SBC) */ + arr[n++] = 0xb2; /* Thin provisioning (SBC) */ arr[3] = n - 4; /* number of supported VPD pages */ } else if (0x80 == cmd[2]) { /* unit serial number */ arr[1] = cmd[2]; /*sanity */ @@ -867,6 +879,9 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target, } else if (0xb1 == cmd[2]) { /* Block characteristics (SBC) */ arr[1] = cmd[2]; /*sanity */ arr[3] = inquiry_evpd_b1(&arr[4]); + } else if (0xb2 == cmd[2]) { /* Thin provisioning (SBC) */ + arr[1] = cmd[2]; /*sanity */ + arr[3] = inquiry_evpd_b2(&arr[4]); } else { /* Illegal request, invalid field in cdb */ mk_sense_buffer(devip, ILLEGAL_REQUEST, @@ -1038,7 +1053,7 @@ static int resp_readcap16(struct scsi_cmnd * scp, arr[13] = scsi_debug_physblk_exp & 0xf; arr[14] = (scsi_debug_lowest_aligned >> 8) & 0x3f; - if (scsi_debug_unmap_granularity) + if (scsi_debug_tpu || scsi_debug_tpws) arr[14] |= 0x80; /* TPE */ arr[15] = scsi_debug_lowest_aligned & 0xff; @@ -2708,6 +2723,8 @@ module_param_named(unmap_max_blocks, scsi_debug_unmap_max_blocks, int, S_IRUGO); module_param_named(unmap_max_desc, scsi_debug_unmap_max_desc, int, S_IRUGO); module_param_named(unmap_granularity, scsi_debug_unmap_granularity, int, S_IRUGO); module_param_named(unmap_alignment, scsi_debug_unmap_alignment, int, S_IRUGO); +module_param_named(tpu, scsi_debug_tpu, int, S_IRUGO); +module_param_named(tpws, scsi_debug_tpws, int, S_IRUGO); MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); MODULE_DESCRIPTION("SCSI debug adapter driver"); @@ -2739,10 +2756,12 @@ MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)"); MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)"); MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)"); MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)"); -MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0)"); -MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=0)"); -MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=0)"); +MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)"); +MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)"); +MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)"); MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)"); +MODULE_PARM_DESC(tpu, "enable TP, support UNMAP command (def=0)"); +MODULE_PARM_DESC(tpws, "enable TP, support WRITE SAME(16) with UNMAP bit (def=0)"); static char sdebug_info[256]; @@ -3130,7 +3149,7 @@ static ssize_t sdebug_map_show(struct device_driver *ddp, char *buf) { ssize_t count; - if (scsi_debug_unmap_granularity == 0) + if (scsi_debug_tpu == 0 && scsi_debug_tpws == 0) return scnprintf(buf, PAGE_SIZE, "0-%u\n", sdebug_store_sectors); @@ -3207,16 +3226,7 @@ static void do_remove_driverfs_files(void) driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host); } -static void pseudo_0_release(struct device *dev) -{ - if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) - printk(KERN_INFO "scsi_debug: pseudo_0_release() called\n"); -} - -static struct device pseudo_primary = { - .init_name = "pseudo_0", - .release = pseudo_0_release, -}; +struct device *pseudo_primary; static int __init scsi_debug_init(void) { @@ -3322,10 +3332,21 @@ static int __init scsi_debug_init(void) memset(dif_storep, 0xff, dif_size); } - if (scsi_debug_unmap_granularity) { + /* Thin Provisioning */ + if (scsi_debug_tpu || scsi_debug_tpws) { unsigned int map_bytes; - if (scsi_debug_unmap_granularity < scsi_debug_unmap_alignment) { + scsi_debug_unmap_max_blocks = + clamp(scsi_debug_unmap_max_blocks, 0U, 0xffffffffU); + + scsi_debug_unmap_max_desc = + clamp(scsi_debug_unmap_max_desc, 0U, 256U); + + scsi_debug_unmap_granularity = + clamp(scsi_debug_unmap_granularity, 1U, 0xffffffffU); + + if (scsi_debug_unmap_alignment && + scsi_debug_unmap_granularity < scsi_debug_unmap_alignment) { printk(KERN_ERR "%s: ERR: unmap_granularity < unmap_alignment\n", __func__); @@ -3352,10 +3373,10 @@ static int __init scsi_debug_init(void) map_region(0, 2); } - ret = device_register(&pseudo_primary); - if (ret < 0) { - printk(KERN_WARNING "scsi_debug: device_register error: %d\n", - ret); + pseudo_primary = root_device_register("pseudo_0"); + if (IS_ERR(pseudo_primary)) { + printk(KERN_WARNING "scsi_debug: root_device_register() error\n"); + ret = PTR_ERR(pseudo_primary); goto free_vm; } ret = bus_register(&pseudo_lld_bus); @@ -3402,7 +3423,7 @@ del_files: bus_unreg: bus_unregister(&pseudo_lld_bus); dev_unreg: - device_unregister(&pseudo_primary); + root_device_unregister(pseudo_primary); free_vm: if (map_storep) vfree(map_storep); @@ -3423,7 +3444,7 @@ static void __exit scsi_debug_exit(void) do_remove_driverfs_files(); driver_unregister(&sdebug_driverfs_driver); bus_unregister(&pseudo_lld_bus); - device_unregister(&pseudo_primary); + root_device_unregister(pseudo_primary); if (dif_storep) vfree(dif_storep); @@ -3474,7 +3495,7 @@ static int sdebug_add_adapter(void) spin_unlock(&sdebug_host_list_lock); sdbg_host->dev.bus = &pseudo_lld_bus; - sdbg_host->dev.parent = &pseudo_primary; + sdbg_host->dev.parent = pseudo_primary; sdbg_host->dev.release = &sdebug_release_adapter; dev_set_name(&sdbg_host->dev, "adapter%d", scsi_debug_add_host); @@ -3642,7 +3663,7 @@ int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done) errsts = resp_readcap16(SCpnt, devip); else if (cmd[1] == SAI_GET_LBA_STATUS) { - if (scsi_debug_unmap_max_desc == 0) { + if (scsi_debug_tpu == 0 && scsi_debug_tpws == 0) { mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_COMMAND_OPCODE, 0); errsts = check_condition_result; @@ -3753,8 +3774,16 @@ write: } break; case WRITE_SAME_16: - if (cmd[1] & 0x8) - unmap = 1; + if (cmd[1] & 0x8) { + if (scsi_debug_tpws == 0) { + mk_sense_buffer(devip, ILLEGAL_REQUEST, + INVALID_FIELD_IN_CDB, 0); + errsts = check_condition_result; + } else + unmap = 1; + } + if (errsts) + break; /* fall through */ case WRITE_SAME: errsts = check_readiness(SCpnt, 0, devip); @@ -3768,7 +3797,7 @@ write: if (errsts) break; - if (scsi_debug_unmap_max_desc == 0) { + if (scsi_debug_unmap_max_desc == 0 || scsi_debug_tpu == 0) { mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_COMMAND_OPCODE, 0); errsts = check_condition_result; diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index ee02d3838a0a..8041fe1ab179 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -968,11 +968,13 @@ static int scsi_init_sgtable(struct request *req, struct scsi_data_buffer *sdb, */ int scsi_init_io(struct scsi_cmnd *cmd, gfp_t gfp_mask) { - int error = scsi_init_sgtable(cmd->request, &cmd->sdb, gfp_mask); + struct request *rq = cmd->request; + + int error = scsi_init_sgtable(rq, &cmd->sdb, gfp_mask); if (error) goto err_exit; - if (blk_bidi_rq(cmd->request)) { + if (blk_bidi_rq(rq)) { struct scsi_data_buffer *bidi_sdb = kmem_cache_zalloc( scsi_sdb_cache, GFP_ATOMIC); if (!bidi_sdb) { @@ -980,28 +982,28 @@ int scsi_init_io(struct scsi_cmnd *cmd, gfp_t gfp_mask) goto err_exit; } - cmd->request->next_rq->special = bidi_sdb; - error = scsi_init_sgtable(cmd->request->next_rq, bidi_sdb, - GFP_ATOMIC); + rq->next_rq->special = bidi_sdb; + error = scsi_init_sgtable(rq->next_rq, bidi_sdb, GFP_ATOMIC); if (error) goto err_exit; } - if (blk_integrity_rq(cmd->request)) { + if (blk_integrity_rq(rq)) { struct scsi_data_buffer *prot_sdb = cmd->prot_sdb; int ivecs, count; BUG_ON(prot_sdb == NULL); - ivecs = blk_rq_count_integrity_sg(cmd->request); + ivecs = blk_rq_count_integrity_sg(rq->q, rq->bio); if (scsi_alloc_sgtable(prot_sdb, ivecs, gfp_mask)) { error = BLKPREP_DEFER; goto err_exit; } - count = blk_rq_map_integrity_sg(cmd->request, + count = blk_rq_map_integrity_sg(rq->q, rq->bio, prot_sdb->table.sgl); BUG_ON(unlikely(count > ivecs)); + BUG_ON(unlikely(count > queue_max_integrity_segments(rq->q))); cmd->prot_sdb = prot_sdb; cmd->prot_sdb->table.nents = count; @@ -1625,6 +1627,14 @@ struct request_queue *__scsi_alloc_queue(struct Scsi_Host *shost, blk_queue_max_segments(q, min_t(unsigned short, shost->sg_tablesize, SCSI_MAX_SG_CHAIN_SEGMENTS)); + if (scsi_host_prot_dma(shost)) { + shost->sg_prot_tablesize = + min_not_zero(shost->sg_prot_tablesize, + (unsigned short)SCSI_MAX_PROT_SG_SEGMENTS); + BUG_ON(shost->sg_prot_tablesize < shost->sg_tablesize); + blk_queue_max_integrity_segments(q, shost->sg_prot_tablesize); + } + blk_queue_max_hw_sectors(q, shost->max_sectors); blk_queue_bounce_limit(q, scsi_calculate_bounce_limit(shost)); blk_queue_segment_boundary(q, shost->dma_boundary); diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index c3f67373a4f8..20ad59dff730 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -251,6 +251,7 @@ shost_rd_attr(host_busy, "%hu\n"); shost_rd_attr(cmd_per_lun, "%hd\n"); shost_rd_attr(can_queue, "%hd\n"); shost_rd_attr(sg_tablesize, "%hu\n"); +shost_rd_attr(sg_prot_tablesize, "%hu\n"); shost_rd_attr(unchecked_isa_dma, "%d\n"); shost_rd_attr(prot_capabilities, "%u\n"); shost_rd_attr(prot_guard_type, "%hd\n"); @@ -262,6 +263,7 @@ static struct attribute *scsi_sysfs_shost_attrs[] = { &dev_attr_cmd_per_lun.attr, &dev_attr_can_queue.attr, &dev_attr_sg_tablesize.attr, + &dev_attr_sg_prot_tablesize.attr, &dev_attr_unchecked_isa_dma.attr, &dev_attr_proc_name.attr, &dev_attr_scan.attr, diff --git a/drivers/scsi/scsi_tgt_if.c b/drivers/scsi/scsi_tgt_if.c index a87e21c35ef2..0172de197008 100644 --- a/drivers/scsi/scsi_tgt_if.c +++ b/drivers/scsi/scsi_tgt_if.c @@ -22,7 +22,6 @@ #include <linux/miscdevice.h> #include <linux/gfp.h> #include <linux/file.h> -#include <linux/smp_lock.h> #include <net/tcp.h> #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> @@ -323,7 +322,6 @@ static int tgt_open(struct inode *inode, struct file *file) { tx_ring.tr_idx = rx_ring.tr_idx = 0; - cycle_kernel_lock(); return 0; } @@ -333,6 +331,7 @@ static const struct file_operations tgt_fops = { .poll = tgt_poll, .write = tgt_write, .mmap = tgt_mmap, + .llseek = noop_llseek, }; static struct miscdevice tgt_miscdev = { diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index d7e470a06180..998c01be3234 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -53,6 +53,25 @@ static void fc_bsg_remove(struct request_queue *); static void fc_bsg_goose_queue(struct fc_rport *); /* + * Module Parameters + */ + +/* + * dev_loss_tmo: the default number of seconds that the FC transport + * should insulate the loss of a remote port. + * The maximum will be capped by the value of SCSI_DEVICE_BLOCK_MAX_TIMEOUT. + */ +static unsigned int fc_dev_loss_tmo = 60; /* seconds */ + +module_param_named(dev_loss_tmo, fc_dev_loss_tmo, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(dev_loss_tmo, + "Maximum number of seconds that the FC transport should" + " insulate the loss of a remote port. Once this value is" + " exceeded, the scsi target is removed. Value should be" + " between 1 and SCSI_DEVICE_BLOCK_MAX_TIMEOUT if" + " fast_io_fail_tmo is not set."); + +/* * Redefine so that we can have same named attributes in the * sdev/starget/host objects. */ @@ -408,6 +427,7 @@ static int fc_host_setup(struct transport_container *tc, struct device *dev, if (!fc_host->work_q) return -ENOMEM; + fc_host->dev_loss_tmo = fc_dev_loss_tmo; snprintf(fc_host->devloss_work_q_name, sizeof(fc_host->devloss_work_q_name), "fc_dl_%d", shost->host_no); @@ -462,25 +482,6 @@ static DECLARE_TRANSPORT_CLASS(fc_vport_class, NULL); /* - * Module Parameters - */ - -/* - * dev_loss_tmo: the default number of seconds that the FC transport - * should insulate the loss of a remote port. - * The maximum will be capped by the value of SCSI_DEVICE_BLOCK_MAX_TIMEOUT. - */ -static unsigned int fc_dev_loss_tmo = 60; /* seconds */ - -module_param_named(dev_loss_tmo, fc_dev_loss_tmo, uint, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(dev_loss_tmo, - "Maximum number of seconds that the FC transport should" - " insulate the loss of a remote port. Once this value is" - " exceeded, the scsi target is removed. Value should be" - " between 1 and SCSI_DEVICE_BLOCK_MAX_TIMEOUT if" - " fast_io_fail_tmo is not set."); - -/* * Netlink Infrastructure */ @@ -830,24 +831,32 @@ static FC_DEVICE_ATTR(rport, supported_classes, S_IRUGO, /* * dev_loss_tmo attribute */ -fc_rport_show_function(dev_loss_tmo, "%d\n", 20, ) -static ssize_t -store_fc_rport_dev_loss_tmo(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static int fc_str_to_dev_loss(const char *buf, unsigned long *val) +{ + char *cp; + + *val = simple_strtoul(buf, &cp, 0); + if ((*cp && (*cp != '\n')) || (*val < 0)) + return -EINVAL; + /* + * Check for overflow; dev_loss_tmo is u32 + */ + if (*val > UINT_MAX) + return -EINVAL; + + return 0; +} + +static int fc_rport_set_dev_loss_tmo(struct fc_rport *rport, + unsigned long val) { - unsigned long val; - struct fc_rport *rport = transport_class_to_rport(dev); struct Scsi_Host *shost = rport_to_shost(rport); struct fc_internal *i = to_fc_internal(shost->transportt); - char *cp; + if ((rport->port_state == FC_PORTSTATE_BLOCKED) || (rport->port_state == FC_PORTSTATE_DELETED) || (rport->port_state == FC_PORTSTATE_NOTPRESENT)) return -EBUSY; - val = simple_strtoul(buf, &cp, 0); - if ((*cp && (*cp != '\n')) || (val < 0)) - return -EINVAL; - /* * Check for overflow; dev_loss_tmo is u32 */ @@ -863,6 +872,25 @@ store_fc_rport_dev_loss_tmo(struct device *dev, struct device_attribute *attr, return -EINVAL; i->f->set_rport_dev_loss_tmo(rport, val); + return 0; +} + +fc_rport_show_function(dev_loss_tmo, "%d\n", 20, ) +static ssize_t +store_fc_rport_dev_loss_tmo(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fc_rport *rport = transport_class_to_rport(dev); + unsigned long val; + int rc; + + rc = fc_str_to_dev_loss(buf, &val); + if (rc) + return rc; + + rc = fc_rport_set_dev_loss_tmo(rport, val); + if (rc) + return rc; return count; } static FC_DEVICE_ATTR(rport, dev_loss_tmo, S_IRUGO | S_IWUSR, @@ -1608,8 +1636,35 @@ store_fc_private_host_issue_lip(struct device *dev, static FC_DEVICE_ATTR(host, issue_lip, S_IWUSR, NULL, store_fc_private_host_issue_lip); -fc_private_host_rd_attr(npiv_vports_inuse, "%u\n", 20); +static ssize_t +store_fc_private_host_dev_loss_tmo(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct Scsi_Host *shost = transport_class_to_shost(dev); + struct fc_host_attrs *fc_host = shost_to_fc_host(shost); + struct fc_rport *rport; + unsigned long val, flags; + int rc; + rc = fc_str_to_dev_loss(buf, &val); + if (rc) + return rc; + + fc_host_dev_loss_tmo(shost) = val; + spin_lock_irqsave(shost->host_lock, flags); + list_for_each_entry(rport, &fc_host->rports, peers) + fc_rport_set_dev_loss_tmo(rport, val); + spin_unlock_irqrestore(shost->host_lock, flags); + return count; +} + +fc_private_host_show_function(dev_loss_tmo, "%d\n", 20, ); +static FC_DEVICE_ATTR(host, dev_loss_tmo, S_IRUGO | S_IWUSR, + show_fc_host_dev_loss_tmo, + store_fc_private_host_dev_loss_tmo); + +fc_private_host_rd_attr(npiv_vports_inuse, "%u\n", 20); /* * Host Statistics Management @@ -2165,6 +2220,7 @@ fc_attach_transport(struct fc_function_template *ft) SETUP_HOST_ATTRIBUTE_RW(system_hostname); /* Transport-managed attributes */ + SETUP_PRIVATE_HOST_ATTRIBUTE_RW(dev_loss_tmo); SETUP_PRIVATE_HOST_ATTRIBUTE_RW(tgtid_bind_type); if (ft->issue_fc_host_lip) SETUP_PRIVATE_HOST_ATTRIBUTE_RW(issue_lip); @@ -2525,7 +2581,7 @@ fc_rport_create(struct Scsi_Host *shost, int channel, rport->maxframe_size = -1; rport->supported_classes = FC_COS_UNSPECIFIED; - rport->dev_loss_tmo = fc_dev_loss_tmo; + rport->dev_loss_tmo = fc_host->dev_loss_tmo; memcpy(&rport->node_name, &ids->node_name, sizeof(rport->node_name)); memcpy(&rport->port_name, &ids->port_name, sizeof(rport->port_name)); rport->port_id = ids->port_id; @@ -4044,11 +4100,54 @@ fc_bsg_rportadd(struct Scsi_Host *shost, struct fc_rport *rport) /** * fc_bsg_remove - Deletes the bsg hooks on fchosts/rports * @q: the request_queue that is to be torn down. + * + * Notes: + * Before unregistering the queue empty any requests that are blocked + * + * */ static void fc_bsg_remove(struct request_queue *q) { + struct request *req; /* block request */ + int counts; /* totals for request_list count and starved */ + if (q) { + /* Stop taking in new requests */ + spin_lock_irq(q->queue_lock); + blk_stop_queue(q); + + /* drain all requests in the queue */ + while (1) { + /* need the lock to fetch a request + * this may fetch the same reqeust as the previous pass + */ + req = blk_fetch_request(q); + /* save requests in use and starved */ + counts = q->rq.count[0] + q->rq.count[1] + + q->rq.starved[0] + q->rq.starved[1]; + spin_unlock_irq(q->queue_lock); + /* any requests still outstanding? */ + if (counts == 0) + break; + + /* This may be the same req as the previous iteration, + * always send the blk_end_request_all after a prefetch. + * It is not okay to not end the request because the + * prefetch started the request. + */ + if (req) { + /* return -ENXIO to indicate that this queue is + * going away + */ + req->errors = -ENXIO; + blk_end_request_all(req, -ENXIO); + } + + msleep(200); /* allow bsg to possibly finish */ + spin_lock_irq(q->queue_lock); + } + bsg_unregister_queue(q); blk_cleanup_queue(q); } diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index e84026def1f4..332387a6bc25 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -537,7 +537,7 @@ static void iscsi_scan_session(struct work_struct *work) /** * iscsi_block_scsi_eh - block scsi eh until session state has transistioned - * cmd: scsi cmd passed to scsi eh handler + * @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 diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index ffa0689ee840..20295774bf70 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -477,7 +477,7 @@ static int scsi_setup_discard_cmnd(struct scsi_device *sdp, struct request *rq) static int scsi_setup_flush_cmnd(struct scsi_device *sdp, struct request *rq) { - rq->timeout = SD_TIMEOUT; + rq->timeout = SD_FLUSH_TIMEOUT; rq->retries = SD_MAX_RETRIES; rq->cmd[0] = SYNCHRONIZE_CACHE; rq->cmd_len = 10; @@ -1072,7 +1072,7 @@ static int sd_sync_cache(struct scsi_disk *sdkp) * flush everything. */ res = scsi_execute_req(sdp, cmd, DMA_NONE, NULL, 0, &sshdr, - SD_TIMEOUT, SD_MAX_RETRIES, NULL); + SD_FLUSH_TIMEOUT, SD_MAX_RETRIES, NULL); if (res == 0) break; } @@ -1554,7 +1554,7 @@ static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp, } /* Logical blocks per physical block exponent */ - sdkp->hw_sector_size = (1 << (buffer[13] & 0xf)) * sector_size; + sdkp->physical_block_size = (1 << (buffer[13] & 0xf)) * sector_size; /* Lowest aligned logical block */ alignment = ((buffer[14] & 0x3f) << 8 | buffer[15]) * sector_size; @@ -1567,7 +1567,7 @@ static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp, struct request_queue *q = sdp->request_queue; sdkp->thin_provisioning = 1; - q->limits.discard_granularity = sdkp->hw_sector_size; + q->limits.discard_granularity = sdkp->physical_block_size; q->limits.max_discard_sectors = 0xffffffff; if (buffer[14] & 0x40) /* TPRZ */ @@ -1635,7 +1635,7 @@ static int read_capacity_10(struct scsi_disk *sdkp, struct scsi_device *sdp, } sdkp->capacity = lba + 1; - sdkp->hw_sector_size = sector_size; + sdkp->physical_block_size = sector_size; return sector_size; } @@ -1756,10 +1756,10 @@ got_data: (unsigned long long)sdkp->capacity, sector_size, cap_str_10, cap_str_2); - if (sdkp->hw_sector_size != sector_size) + if (sdkp->physical_block_size != sector_size) sd_printk(KERN_NOTICE, sdkp, "%u-byte physical blocks\n", - sdkp->hw_sector_size); + sdkp->physical_block_size); } } @@ -1773,7 +1773,8 @@ got_data: else if (sector_size == 256) sdkp->capacity >>= 1; - blk_queue_physical_block_size(sdp->request_queue, sdkp->hw_sector_size); + blk_queue_physical_block_size(sdp->request_queue, + sdkp->physical_block_size); sdkp->device->sector_size = sector_size; } @@ -2039,14 +2040,24 @@ static void sd_read_block_limits(struct scsi_disk *sdkp) lba_count = get_unaligned_be32(&buffer[20]); desc_count = get_unaligned_be32(&buffer[24]); - if (lba_count) { - q->limits.max_discard_sectors = - lba_count * sector_sz >> 9; - - if (desc_count) + if (lba_count && desc_count) { + if (sdkp->tpvpd && !sdkp->tpu) + sdkp->unmap = 0; + else sdkp->unmap = 1; } + if (sdkp->tpvpd && !sdkp->tpu && !sdkp->tpws) { + sd_printk(KERN_ERR, sdkp, "Thin provisioning is " \ + "enabled but neither TPU, nor TPWS are " \ + "set. Disabling discard!\n"); + goto out; + } + + if (lba_count) + q->limits.max_discard_sectors = + lba_count * sector_sz >> 9; + granularity = get_unaligned_be32(&buffer[28]); if (granularity) @@ -2087,6 +2098,31 @@ static void sd_read_block_characteristics(struct scsi_disk *sdkp) kfree(buffer); } +/** + * sd_read_thin_provisioning - Query thin provisioning VPD page + * @disk: disk to query + */ +static void sd_read_thin_provisioning(struct scsi_disk *sdkp) +{ + unsigned char *buffer; + const int vpd_len = 8; + + if (sdkp->thin_provisioning == 0) + return; + + buffer = kmalloc(vpd_len, GFP_KERNEL); + + if (!buffer || scsi_get_vpd_page(sdkp->device, 0xb2, buffer, vpd_len)) + goto out; + + sdkp->tpvpd = 1; + sdkp->tpu = (buffer[5] >> 7) & 1; /* UNMAP */ + sdkp->tpws = (buffer[5] >> 6) & 1; /* WRITE SAME(16) with UNMAP */ + + out: + kfree(buffer); +} + static int sd_try_extended_inquiry(struct scsi_device *sdp) { /* @@ -2109,7 +2145,7 @@ static int sd_revalidate_disk(struct gendisk *disk) struct scsi_disk *sdkp = scsi_disk(disk); struct scsi_device *sdp = sdkp->device; unsigned char *buffer; - unsigned ordered; + unsigned flush = 0; SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_revalidate_disk\n")); @@ -2138,6 +2174,7 @@ static int sd_revalidate_disk(struct gendisk *disk) sd_read_capacity(sdkp, buffer); if (sd_try_extended_inquiry(sdp)) { + sd_read_thin_provisioning(sdkp); sd_read_block_limits(sdkp); sd_read_block_characteristics(sdkp); } @@ -2151,17 +2188,15 @@ static int sd_revalidate_disk(struct gendisk *disk) /* * We now have all cache related info, determine how we deal - * with ordered requests. Note that as the current SCSI - * dispatch function can alter request order, we cannot use - * QUEUE_ORDERED_TAG_* even when ordered tag is supported. + * with flush requests. */ - if (sdkp->WCE) - ordered = sdkp->DPOFUA - ? QUEUE_ORDERED_DRAIN_FUA : QUEUE_ORDERED_DRAIN_FLUSH; - else - ordered = QUEUE_ORDERED_DRAIN; + if (sdkp->WCE) { + flush |= REQ_FLUSH; + if (sdkp->DPOFUA) + flush |= REQ_FUA; + } - blk_queue_ordered(sdkp->disk->queue, ordered); + blk_queue_flush(sdkp->disk->queue, flush); set_capacity(disk, sdkp->capacity); kfree(buffer); @@ -2252,11 +2287,10 @@ static void sd_probe_async(void *data, async_cookie_t cookie) index = sdkp->index; dev = &sdp->sdev_gendev; - if (index < SD_MAX_DISKS) { - gd->major = sd_major((index & 0xf0) >> 4); - gd->first_minor = ((index & 0xf) << 4) | (index & 0xfff00); - gd->minors = SD_MINORS; - } + gd->major = sd_major((index & 0xf0) >> 4); + gd->first_minor = ((index & 0xf) << 4) | (index & 0xfff00); + gd->minors = SD_MINORS; + gd->fops = &sd_fops; gd->private_data = &sdkp->driver; gd->queue = sdkp->device->request_queue; @@ -2346,6 +2380,12 @@ static int sd_probe(struct device *dev) if (error) goto out_put; + if (index >= SD_MAX_DISKS) { + error = -ENODEV; + sdev_printk(KERN_WARNING, sdp, "SCSI disk (sd) name space exhausted.\n"); + goto out_free_index; + } + error = sd_format_disk_name("sd", index, gd->disk_name, DISK_NAME_LEN); if (error) goto out_free_index; diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h index f81a9309e6de..55488faf0815 100644 --- a/drivers/scsi/sd.h +++ b/drivers/scsi/sd.h @@ -19,6 +19,7 @@ */ #define SD_TIMEOUT (30 * HZ) #define SD_MOD_TIMEOUT (75 * HZ) +#define SD_FLUSH_TIMEOUT (60 * HZ) /* * Number of allowed retries @@ -50,7 +51,7 @@ struct scsi_disk { atomic_t openers; sector_t capacity; /* size in 512-byte sectors */ u32 index; - unsigned short hw_sector_size; + unsigned int physical_block_size; u8 media_present; u8 write_prot; u8 protection_type;/* Data Integrity Field */ @@ -62,6 +63,9 @@ struct scsi_disk { unsigned first_scan : 1; unsigned thin_provisioning : 1; unsigned unmap : 1; + unsigned tpws : 1; + unsigned tpu : 1; + unsigned tpvpd : 1; }; #define to_scsi_disk(obj) container_of(obj,struct scsi_disk,dev) diff --git a/drivers/scsi/sd_dif.c b/drivers/scsi/sd_dif.c index 84be62149c6c..0cb39ff21171 100644 --- a/drivers/scsi/sd_dif.c +++ b/drivers/scsi/sd_dif.c @@ -375,21 +375,20 @@ int sd_dif_prepare(struct request *rq, sector_t hw_sector, unsigned int sector_s unsigned int i, j; u32 phys, virt; - /* Already remapped? */ - if (rq->cmd_flags & REQ_INTEGRITY) - return 0; - sdkp = rq->bio->bi_bdev->bd_disk->private_data; if (sdkp->protection_type == SD_DIF_TYPE3_PROTECTION) return 0; - rq->cmd_flags |= REQ_INTEGRITY; phys = hw_sector & 0xffffffff; __rq_for_each_bio(bio, rq) { struct bio_vec *iv; + /* Already remapped? */ + if (bio_flagged(bio, BIO_MAPPED_INTEGRITY)) + break; + virt = bio->bi_integrity->bip_sector & 0xffffffff; bip_for_each_vec(iv, bio->bi_integrity, i) { @@ -408,6 +407,8 @@ int sd_dif_prepare(struct request *rq, sector_t hw_sector, unsigned int sector_s kunmap_atomic(sdt, KM_USER0); } + + bio->bi_flags |= BIO_MAPPED_INTEGRITY; } return 0; diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 78d616315d8e..5428d53f5a13 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -49,7 +49,7 @@ static int sg_version_num = 30534; /* 2 digits for each component */ #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/blktrace_api.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include "scsi.h" #include <scsi/scsi_dbg.h> @@ -103,6 +103,8 @@ static int scatter_elem_sz_prev = SG_SCATTER_SZ; static int sg_add(struct device *, struct class_interface *); static void sg_remove(struct device *, struct class_interface *); +static DEFINE_MUTEX(sg_mutex); + static DEFINE_IDR(sg_index_idr); static DEFINE_RWLOCK(sg_index_lock); /* Also used to lock file descriptor list for device */ @@ -229,7 +231,7 @@ sg_open(struct inode *inode, struct file *filp) int res; int retval; - lock_kernel(); + mutex_lock(&sg_mutex); nonseekable_open(inode, filp); SCSI_LOG_TIMEOUT(3, printk("sg_open: dev=%d, flags=0x%x\n", dev, flags)); sdp = sg_get_dev(dev); @@ -314,7 +316,7 @@ sdp_put: sg_put: if (sdp) sg_put_dev(sdp); - unlock_kernel(); + mutex_unlock(&sg_mutex); return retval; } @@ -1092,9 +1094,9 @@ sg_unlocked_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) { int ret; - lock_kernel(); + mutex_lock(&sg_mutex); ret = sg_ioctl(filp, cmd_in, arg); - unlock_kernel(); + mutex_unlock(&sg_mutex); return ret; } @@ -1351,6 +1353,7 @@ static const struct file_operations sg_fops = { .mmap = sg_mmap, .release = sg_release, .fasync = sg_fasync, + .llseek = no_llseek, }; static struct class *sg_sysfs_class; @@ -1657,7 +1660,7 @@ static int sg_start_req(Sg_request *srp, unsigned char *cmd) if (sg_allow_dio && hp->flags & SG_FLAG_DIRECT_IO && dxfer_dir != SG_DXFER_UNKNOWN && !iov_count && !sfp->parentdp->device->host->unchecked_isa_dma && - blk_rq_aligned(q, hp->dxferp, dxfer_len)) + blk_rq_aligned(q, (unsigned long)hp->dxferp, dxfer_len)) md = NULL; else md = &map_data; diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index ba9c3e0387ce..e148341079b5 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -44,7 +44,6 @@ #include <linux/init.h> #include <linux/blkdev.h> #include <linux/mutex.h> -#include <linux/smp_lock.h> #include <linux/slab.h> #include <asm/uaccess.h> @@ -76,6 +75,7 @@ MODULE_ALIAS_SCSI_DEVICE(TYPE_WORM); CDC_CD_R|CDC_CD_RW|CDC_DVD|CDC_DVD_R|CDC_DVD_RAM|CDC_GENERIC_PACKET| \ CDC_MRW|CDC_MRW_W|CDC_RAM) +static DEFINE_MUTEX(sr_mutex); static int sr_probe(struct device *); static int sr_remove(struct device *); static int sr_done(struct scsi_cmnd *); @@ -470,24 +470,24 @@ static int sr_block_open(struct block_device *bdev, fmode_t mode) struct scsi_cd *cd; int ret = -ENXIO; - lock_kernel(); + mutex_lock(&sr_mutex); cd = scsi_cd_get(bdev->bd_disk); if (cd) { ret = cdrom_open(&cd->cdi, bdev, mode); if (ret) scsi_cd_put(cd); } - unlock_kernel(); + mutex_unlock(&sr_mutex); return ret; } static int sr_block_release(struct gendisk *disk, fmode_t mode) { struct scsi_cd *cd = scsi_cd(disk); - lock_kernel(); + mutex_lock(&sr_mutex); cdrom_release(&cd->cdi, mode); scsi_cd_put(cd); - unlock_kernel(); + mutex_unlock(&sr_mutex); return 0; } @@ -499,7 +499,7 @@ static int sr_block_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd, void __user *argp = (void __user *)arg; int ret; - lock_kernel(); + mutex_lock(&sr_mutex); /* * Send SCSI addressing ioctls directly to mid level, send other @@ -529,7 +529,7 @@ static int sr_block_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd, ret = scsi_ioctl(sdev, cmd, argp); out: - unlock_kernel(); + mutex_unlock(&sr_mutex); return ret; } diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 24211d0efa6d..5b7388f1c835 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -9,7 +9,7 @@ Steve Hirsch, Andreas Koppenh"ofer, Michael Leodolter, Eyal Lebedinsky, Michael Schaefer, J"org Weule, and Eric Youngdale. - Copyright 1992 - 2008 Kai Makisara + Copyright 1992 - 2010 Kai Makisara email Kai.Makisara@kolumbus.fi Some small formal changes - aeb, 950809 @@ -17,7 +17,7 @@ Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support */ -static const char *verstr = "20081215"; +static const char *verstr = "20100829"; #include <linux/module.h> @@ -39,7 +39,6 @@ static const char *verstr = "20081215"; #include <linux/cdev.h> #include <linux/delay.h> #include <linux/mutex.h> -#include <linux/smp_lock.h> #include <asm/uaccess.h> #include <asm/dma.h> @@ -76,6 +75,7 @@ static const char *verstr = "20081215"; #include "st_options.h" #include "st.h" +static DEFINE_MUTEX(st_mutex); static int buffer_kbs; static int max_sg_segs; static int try_direct_io = TRY_DIRECT_IO; @@ -1180,7 +1180,7 @@ static int st_open(struct inode *inode, struct file *filp) int dev = TAPE_NR(inode); char *name; - lock_kernel(); + mutex_lock(&st_mutex); /* * We really want to do nonseekable_open(inode, filp); here, but some * versions of tar incorrectly call lseek on tapes and bail out if that @@ -1189,7 +1189,7 @@ static int st_open(struct inode *inode, struct file *filp) filp->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE); if (!(STp = scsi_tape_get(dev))) { - unlock_kernel(); + mutex_unlock(&st_mutex); return -ENXIO; } @@ -1200,7 +1200,7 @@ static int st_open(struct inode *inode, struct file *filp) if (STp->in_use) { write_unlock(&st_dev_arr_lock); scsi_tape_put(STp); - unlock_kernel(); + mutex_unlock(&st_mutex); DEB( printk(ST_DEB_MSG "%s: Device already in use.\n", name); ) return (-EBUSY); } @@ -1249,14 +1249,14 @@ static int st_open(struct inode *inode, struct file *filp) retval = (-EIO); goto err_out; } - unlock_kernel(); + mutex_unlock(&st_mutex); return 0; err_out: normalize_buffer(STp->buffer); STp->in_use = 0; scsi_tape_put(STp); - unlock_kernel(); + mutex_unlock(&st_mutex); return retval; } @@ -2696,18 +2696,21 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon } break; case MTWEOF: + case MTWEOFI: case MTWSM: if (STp->write_prot) return (-EACCES); cmd[0] = WRITE_FILEMARKS; if (cmd_in == MTWSM) cmd[1] = 2; + if (cmd_in == MTWEOFI) + cmd[1] |= 1; cmd[2] = (arg >> 16); cmd[3] = (arg >> 8); cmd[4] = arg; timeout = STp->device->request_queue->rq_timeout; DEBC( - if (cmd_in == MTWEOF) + if (cmd_in != MTWSM) printk(ST_DEB_MSG "%s: Writing %d filemarks.\n", name, cmd[2] * 65536 + cmd[3] * 256 + cmd[4]); else @@ -2883,8 +2886,8 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon else if (chg_eof) STps->eof = ST_NOEOF; - if (cmd_in == MTWEOF) - STps->rw = ST_IDLE; + if (cmd_in == MTWEOF || cmd_in == MTWEOFI) + STps->rw = ST_IDLE; /* prevent automatic WEOF at close */ } else { /* SCSI command was not completely successful. Don't return from this block without releasing the SCSI command block! */ struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat; @@ -2901,7 +2904,7 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon else undone = 0; - if (cmd_in == MTWEOF && + if ((cmd_in == MTWEOF || cmd_in == MTWEOFI) && cmdstatp->have_sense && (cmdstatp->flags & SENSE_EOM)) { if (cmdstatp->sense_hdr.sense_key == NO_SENSE || diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 12900f7083b0..3198c5335f0b 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -458,6 +458,7 @@ config SERIAL_SAMSUNG_UARTS int depends on ARM && PLAT_SAMSUNG default 2 if ARCH_S3C2400 + default 6 if ARCH_S5P6450 default 4 if SERIAL_SAMSUNG_UARTS_4 default 3 help @@ -526,12 +527,12 @@ config SERIAL_S3C24A0 Serial port support for the Samsung S3C24A0 SoC config SERIAL_S3C6400 - tristate "Samsung S3C6400/S3C6410/S5P6440/S5PC100 Serial port support" - depends on SERIAL_SAMSUNG && (CPU_S3C6400 || CPU_S3C6410 || CPU_S5P6440 || CPU_S5PC100) + tristate "Samsung S3C6400/S3C6410/S5P6440/S5P6450/S5PC100 Serial port support" + depends on SERIAL_SAMSUNG && (CPU_S3C6400 || CPU_S3C6410 || CPU_S5P6440 || CPU_S5P6450 || CPU_S5PC100) select SERIAL_SAMSUNG_UARTS_4 default y help - Serial port support for the Samsung S3C6400, S3C6410, S5P6440 + Serial port support for the Samsung S3C6400, S3C6410, S5P6440, S5P6450 and S5PC100 SoCs config SERIAL_S5PV210 diff --git a/drivers/serial/ioc3_serial.c b/drivers/serial/ioc3_serial.c index 800c54602339..ee43efc7bdcc 100644 --- a/drivers/serial/ioc3_serial.c +++ b/drivers/serial/ioc3_serial.c @@ -2017,6 +2017,7 @@ ioc3uart_probe(struct ioc3_submodule *is, struct ioc3_driver_data *idd) struct ioc3_port *port; struct ioc3_port *ports[PORTS_PER_CARD]; int phys_port; + int cnt; DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __func__, is, idd)); @@ -2147,6 +2148,9 @@ ioc3uart_probe(struct ioc3_submodule *is, struct ioc3_driver_data *idd) /* error exits that give back resources */ out4: + for (cnt = 0; cnt < phys_port; cnt++) + kfree(ports[cnt]); + kfree(card_ptr); return ret; } diff --git a/drivers/serial/mfd.c b/drivers/serial/mfd.c index 5dff45c76d32..dc0967fb9ea6 100644 --- a/drivers/serial/mfd.c +++ b/drivers/serial/mfd.c @@ -228,12 +228,14 @@ static const struct file_operations port_regs_ops = { .owner = THIS_MODULE, .open = hsu_show_regs_open, .read = port_show_regs, + .llseek = default_llseek, }; static const struct file_operations dma_regs_ops = { .owner = THIS_MODULE, .open = hsu_show_regs_open, .read = dma_show_regs, + .llseek = default_llseek, }; static int hsu_debugfs_init(struct hsu_port *hsu) diff --git a/drivers/serial/samsung.c b/drivers/serial/samsung.c index b1156ba8ad14..7ac2bf5167cd 100644 --- a/drivers/serial/samsung.c +++ b/drivers/serial/samsung.c @@ -1101,7 +1101,7 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, dbg("resource %p (%lx..%lx)\n", res, res->start, res->end); port->mapbase = res->start; - port->membase = S3C_VA_UART + res->start - (S3C_PA_UART & 0xfff00000); + port->membase = S3C_VA_UART + (res->start & 0xfffff); ret = platform_get_irq(platdev, 0); if (ret < 0) port->irq = 0; diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c index 7d475b2a79e8..93760b2ea172 100644 --- a/drivers/serial/serial_cs.c +++ b/drivers/serial/serial_cs.c @@ -45,7 +45,6 @@ #include <asm/io.h> #include <asm/system.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/ciscode.h> #include <pcmcia/ds.h> @@ -183,10 +182,8 @@ static void quirk_config_socket(struct pcmcia_device *link) { struct serial_info *info = link->priv; - if (info->multi) { - link->conf.Present |= PRESENT_EXT_STATUS; - link->conf.ExtStatus = ESR_REQ_ATTN_ENA; - } + if (info->multi) + link->config_flags |= CONF_ENABLE_ESR; } static const struct serial_quirk quirks[] = { @@ -265,13 +262,6 @@ static const struct serial_quirk quirks[] = { static int serial_config(struct pcmcia_device * link); -/*====================================================================== - - After a card is removed, serial_remove() will unregister - the serial device(s), and release the PCMCIA configuration. - -======================================================================*/ - static void serial_remove(struct pcmcia_device *link) { struct serial_info *info = link->priv; @@ -314,14 +304,6 @@ static int serial_resume(struct pcmcia_device *link) return 0; } -/*====================================================================== - - serial_attach() creates an "instance" of the driver, allocating - local data structures for one device. The device is registered - with Card Services. - -======================================================================*/ - static int serial_probe(struct pcmcia_device *link) { struct serial_info *info; @@ -335,25 +317,13 @@ static int serial_probe(struct pcmcia_device *link) info->p_dev = link; link->priv = info; - link->conf.Attributes = CONF_ENABLE_IRQ; - if (do_sound) { - link->conf.Attributes |= CONF_ENABLE_SPKR; - link->conf.Status = CCSR_AUDIO_ENA; - } - link->conf.IntType = INT_MEMORY_AND_IO; + link->config_flags |= CONF_ENABLE_IRQ; + if (do_sound) + link->config_flags |= CONF_ENABLE_SPKR; return serial_config(link); } -/*====================================================================== - - This deletes a driver "instance". The device is de-registered - with Card Services. If it has been released, all local data - structures are freed. Otherwise, the structures will be freed - when the device is released. - -======================================================================*/ - static void serial_detach(struct pcmcia_device *link) { struct serial_info *info = link->priv; @@ -361,11 +331,6 @@ static void serial_detach(struct pcmcia_device *link) dev_dbg(&link->dev, "serial_detach\n"); /* - * Ensure any outstanding scheduled tasks are completed. - */ - flush_scheduled_work(); - - /* * Ensure that the ports have been released. */ serial_remove(link); @@ -430,47 +395,45 @@ static int pfc_config(struct pcmcia_device *p_dev) return -ENODEV; } -static int simple_config_check(struct pcmcia_device *p_dev, - cistpl_cftable_entry_t *cf, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, - void *priv_data) +static int simple_config_check(struct pcmcia_device *p_dev, void *priv_data) { static const int size_table[2] = { 8, 16 }; int *try = priv_data; - if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM)) - p_dev->conf.Vpp = - cf->vpp1.param[CISTPL_POWER_VNOM] / 10000; + if (p_dev->resource[0]->start == 0) + return -ENODEV; - p_dev->io_lines = ((*try & 0x1) == 0) ? - 16 : cf->io.flags & CISTPL_IO_LINES_MASK; + if ((*try & 0x1) == 0) + p_dev->io_lines = 16; - if ((cf->io.nwin > 0) && (cf->io.win[0].len == size_table[(*try >> 1)]) - && (cf->io.win[0].base != 0)) { - p_dev->resource[0]->start = cf->io.win[0].base; - if (!pcmcia_request_io(p_dev)) - return 0; - } - return -EINVAL; + if (p_dev->resource[0]->end != size_table[(*try >> 1)]) + return -ENODEV; + + p_dev->resource[0]->end = 8; + p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; + p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; + + return pcmcia_request_io(p_dev); } static int simple_config_check_notpicky(struct pcmcia_device *p_dev, - cistpl_cftable_entry_t *cf, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, void *priv_data) { static const unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 }; int j; - if ((cf->io.nwin > 0) && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) { - for (j = 0; j < 5; j++) { - p_dev->resource[0]->start = base[j]; - p_dev->io_lines = base[j] ? 16 : 3; - if (!pcmcia_request_io(p_dev)) - return 0; - } + if (p_dev->io_lines > 3) + return -ENODEV; + + p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; + p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; + p_dev->resource[0]->end = 8; + + for (j = 0; j < 5; j++) { + p_dev->resource[0]->start = base[j]; + p_dev->io_lines = base[j] ? 16 : 3; + if (!pcmcia_request_io(p_dev)) + return 0; } return -ENODEV; } @@ -480,11 +443,9 @@ static int simple_config(struct pcmcia_device *link) struct serial_info *info = link->priv; int i = -ENODEV, try; - link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; - link->resource[0]->end = 8; - /* First pass: look for a config entry that looks normal. * Two tries: without IO aliases, then with aliases */ + link->config_flags |= CONF_AUTO_SET_VPP | CONF_AUTO_SET_IO; for (try = 0; try < 4; try++) if (!pcmcia_loop_config(link, simple_config_check, &try)) goto found_port; @@ -500,7 +461,7 @@ static int simple_config(struct pcmcia_device *link) found_port: if (info->multi && (info->manfid == MANFID_3COM)) - link->conf.ConfigIndex &= ~(0x08); + link->config_index &= ~(0x08); /* * Apply any configuration quirks. @@ -508,51 +469,50 @@ found_port: if (info->quirk && info->quirk->config) info->quirk->config(link); - i = pcmcia_request_configuration(link, &link->conf); + i = pcmcia_enable_device(link); if (i != 0) return -1; return setup_serial(link, info, link->resource[0]->start, link->irq); } -static int multi_config_check(struct pcmcia_device *p_dev, - cistpl_cftable_entry_t *cf, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, - void *priv_data) +static int multi_config_check(struct pcmcia_device *p_dev, void *priv_data) { - int *base2 = priv_data; + int *multi = priv_data; + + if (p_dev->resource[1]->end) + return -EINVAL; /* The quad port cards have bad CIS's, so just look for a window larger than 8 ports and assume it will be right */ - if ((cf->io.nwin == 1) && (cf->io.win[0].len > 8)) { - p_dev->resource[0]->start = cf->io.win[0].base; - p_dev->io_lines = cf->io.flags & CISTPL_IO_LINES_MASK; - if (!pcmcia_request_io(p_dev)) { - *base2 = p_dev->resource[0]->start + 8; - return 0; - } - } - return -ENODEV; + if (p_dev->resource[0]->end <= 8) + return -EINVAL; + + p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; + p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; + p_dev->resource[0]->end = *multi * 8; + + if (pcmcia_request_io(p_dev)) + return -ENODEV; + return 0; } static int multi_config_check_notpicky(struct pcmcia_device *p_dev, - cistpl_cftable_entry_t *cf, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, void *priv_data) { int *base2 = priv_data; - if (cf->io.nwin == 2) { - p_dev->resource[0]->start = cf->io.win[0].base; - p_dev->resource[1]->start = cf->io.win[1].base; - p_dev->io_lines = cf->io.flags & CISTPL_IO_LINES_MASK; - if (!pcmcia_request_io(p_dev)) { - *base2 = p_dev->resource[1]->start; - return 0; - } - } - return -ENODEV; + if (!p_dev->resource[0]->end || !p_dev->resource[1]->end) + return -ENODEV; + + p_dev->resource[0]->end = p_dev->resource[1]->end = 8; + p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; + p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; + + if (pcmcia_request_io(p_dev)) + return -ENODEV; + + *base2 = p_dev->resource[0]->start + 8; + return 0; } static int multi_config(struct pcmcia_device *link) @@ -560,12 +520,12 @@ static int multi_config(struct pcmcia_device *link) struct serial_info *info = link->priv; int i, base2 = 0; + link->config_flags |= CONF_AUTO_SET_IO; /* First, look for a generic full-sized window */ - link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; - link->resource[0]->end = info->multi * 8; - if (pcmcia_loop_config(link, multi_config_check, &base2)) { + if (!pcmcia_loop_config(link, multi_config_check, &info->multi)) + base2 = link->resource[0]->start + 8; + else { /* If that didn't work, look for two windows */ - link->resource[0]->end = link->resource[1]->end = 8; info->multi = 2; if (pcmcia_loop_config(link, multi_config_check_notpicky, &base2)) { @@ -584,7 +544,7 @@ static int multi_config(struct pcmcia_device *link) if (info->quirk && info->quirk->config) info->quirk->config(link); - i = pcmcia_request_configuration(link, &link->conf); + i = pcmcia_enable_device(link); if (i != 0) return -ENODEV; @@ -596,11 +556,11 @@ static int multi_config(struct pcmcia_device *link) info->prodid == PRODID_POSSIO_GCC)) { int err; - if (link->conf.ConfigIndex == 1 || - link->conf.ConfigIndex == 3) { + if (link->config_index == 1 || + link->config_index == 3) { err = setup_serial(link, info, base2, link->irq); - base2 = link->resource[0]->start;; + base2 = link->resource[0]->start; } else { err = setup_serial(link, info, link->resource[0]->start, link->irq); @@ -624,33 +584,24 @@ static int multi_config(struct pcmcia_device *link) return 0; } -static int serial_check_for_multi(struct pcmcia_device *p_dev, - cistpl_cftable_entry_t *cf, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, - void *priv_data) +static int serial_check_for_multi(struct pcmcia_device *p_dev, void *priv_data) { struct serial_info *info = p_dev->priv; - if ((cf->io.nwin == 1) && (cf->io.win[0].len % 8 == 0)) - info->multi = cf->io.win[0].len >> 3; + if (!p_dev->resource[0]->end) + return -EINVAL; + + if ((!p_dev->resource[1]->end) && (p_dev->resource[0]->end % 8 == 0)) + info->multi = p_dev->resource[0]->end >> 3; - if ((cf->io.nwin == 2) && (cf->io.win[0].len == 8) && - (cf->io.win[1].len == 8)) + if ((p_dev->resource[1]->end) && (p_dev->resource[0]->end == 8) + && (p_dev->resource[1]->end == 8)) info->multi = 2; return 0; /* break */ } -/*====================================================================== - - serial_config() is scheduled to run after a CARD_INSERTION event - is received, to configure the PCMCIA socket, and to make the - serial device available to the system. - -======================================================================*/ - static int serial_config(struct pcmcia_device * link) { struct serial_info *info = link->priv; @@ -894,9 +845,7 @@ MODULE_FIRMWARE("cis/RS-COM-2P.cis"); static struct pcmcia_driver serial_cs_driver = { .owner = THIS_MODULE, - .drv = { - .name = "serial_cs", - }, + .name = "serial_cs", .probe = serial_probe, .remove = serial_detach, .id_table = serial_ids, diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 91c2f4f3af10..4b9eec68fad6 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -143,10 +143,26 @@ config SPI_GPIO GPIO operations, you should be able to leverage that for better speed with a custom version of this driver; see the source code. +config SPI_IMX_VER_IMX1 + def_bool y if SOC_IMX1 + +config SPI_IMX_VER_0_0 + def_bool y if SOC_IMX21 || SOC_IMX27 + +config SPI_IMX_VER_0_4 + def_bool y if ARCH_MX31 + +config SPI_IMX_VER_0_7 + def_bool y if ARCH_MX25 || ARCH_MX35 || ARCH_MX51 + +config SPI_IMX_VER_2_3 + def_bool y if ARCH_MX51 + config SPI_IMX tristate "Freescale i.MX SPI controllers" depends on ARCH_MXC select SPI_BITBANG + default m if IMX_HAVE_PLATFORM_SPI_IMX help This enables using the Freescale i.MX SPI controllers in master mode. @@ -182,12 +198,27 @@ config SPI_MPC512x_PSC This enables using the Freescale MPC5121 Programmable Serial Controller in SPI master mode. -config SPI_MPC8xxx - tristate "Freescale MPC8xxx SPI controller" +config SPI_FSL_LIB + tristate + depends on FSL_SOC + +config SPI_FSL_SPI + tristate "Freescale SPI controller" depends on FSL_SOC + select SPI_FSL_LIB help - This enables using the Freescale MPC8xxx SPI controllers in master - mode. + This enables using the Freescale SPI controllers in master mode. + MPC83xx platform uses the controller in cpu mode or CPM/QE mode. + MPC8569 uses the controller in QE mode, MPC8610 in cpu mode. + +config SPI_FSL_ESPI + tristate "Freescale eSPI controller" + depends on FSL_SOC + select SPI_FSL_LIB + help + This enables using the Freescale eSPI controllers in master mode. + From MPC8536, 85xx platform uses the controller, and all P10xx, + P20xx, P30xx,P40xx, P50xx uses this controller. config SPI_OMAP_UWIRE tristate "OMAP1 MicroWire" @@ -298,6 +329,13 @@ config SPI_STMP3XXX help SPI driver for Freescale STMP37xx/378x SoC SSP interface +config SPI_TOPCLIFF_PCH + tristate "Topcliff PCH SPI Controller" + depends on PCI + help + SPI driver for the Topcliff PCH (Platform Controller Hub) SPI bus + used in some x86 embedded processors. + config SPI_TXX9 tristate "Toshiba TXx9 SPI controller" depends on GENERIC_GPIO && CPU_TX49XX diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index e9cbd18217a0..557aaadf56b2 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -2,9 +2,7 @@ # Makefile for kernel SPI drivers. # -ifeq ($(CONFIG_SPI_DEBUG),y) -EXTRA_CFLAGS += -DDEBUG -endif +ccflags-$(CONFIG_SPI_DEBUG) := -DDEBUG # small core, mostly translating board-specific # config declarations into driver model code @@ -34,11 +32,14 @@ obj-$(CONFIG_SPI_PL022) += amba-pl022.o obj-$(CONFIG_SPI_MPC512x_PSC) += mpc512x_psc_spi.o obj-$(CONFIG_SPI_MPC52xx_PSC) += mpc52xx_psc_spi.o obj-$(CONFIG_SPI_MPC52xx) += mpc52xx_spi.o -obj-$(CONFIG_SPI_MPC8xxx) += spi_mpc8xxx.o +obj-$(CONFIG_SPI_FSL_LIB) += spi_fsl_lib.o +obj-$(CONFIG_SPI_FSL_ESPI) += spi_fsl_espi.o +obj-$(CONFIG_SPI_FSL_SPI) += spi_fsl_spi.o obj-$(CONFIG_SPI_PPC4xx) += spi_ppc4xx.o obj-$(CONFIG_SPI_S3C24XX_GPIO) += spi_s3c24xx_gpio.o obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24xx_hw.o obj-$(CONFIG_SPI_S3C64XX) += spi_s3c64xx.o +obj-$(CONFIG_SPI_TOPCLIFF_PCH) += spi_topcliff_pch.o obj-$(CONFIG_SPI_TXX9) += spi_txx9.o obj-$(CONFIG_SPI_XILINX) += xilinx_spi.o obj-$(CONFIG_SPI_XILINX_OF) += xilinx_spi_of.o diff --git a/drivers/spi/amba-pl022.c b/drivers/spi/amba-pl022.c index 4c37c4e28647..fb3d1b31772d 100644 --- a/drivers/spi/amba-pl022.c +++ b/drivers/spi/amba-pl022.c @@ -27,7 +27,6 @@ /* * TODO: * - add timeout on polled transfers - * - add generic DMA framework support */ #include <linux/init.h> @@ -45,6 +44,9 @@ #include <linux/amba/pl022.h> #include <linux/io.h> #include <linux/slab.h> +#include <linux/dmaengine.h> +#include <linux/dma-mapping.h> +#include <linux/scatterlist.h> /* * This macro is used to define some register default values. @@ -381,6 +383,14 @@ struct pl022 { enum ssp_reading read; enum ssp_writing write; u32 exp_fifo_level; + /* DMA settings */ +#ifdef CONFIG_DMA_ENGINE + struct dma_chan *dma_rx_channel; + struct dma_chan *dma_tx_channel; + struct sg_table sgt_rx; + struct sg_table sgt_tx; + char *dummypage; +#endif }; /** @@ -406,7 +416,7 @@ struct chip_data { u16 dmacr; u16 cpsr; u8 n_bytes; - u8 enable_dma:1; + bool enable_dma; enum ssp_reading read; enum ssp_writing write; void (*cs_control) (u32 command); @@ -763,6 +773,371 @@ static void *next_transfer(struct pl022 *pl022) } return STATE_DONE; } + +/* + * This DMA functionality is only compiled in if we have + * access to the generic DMA devices/DMA engine. + */ +#ifdef CONFIG_DMA_ENGINE +static void unmap_free_dma_scatter(struct pl022 *pl022) +{ + /* Unmap and free the SG tables */ + dma_unmap_sg(&pl022->adev->dev, pl022->sgt_tx.sgl, + pl022->sgt_tx.nents, DMA_TO_DEVICE); + dma_unmap_sg(&pl022->adev->dev, pl022->sgt_rx.sgl, + pl022->sgt_rx.nents, DMA_FROM_DEVICE); + sg_free_table(&pl022->sgt_rx); + sg_free_table(&pl022->sgt_tx); +} + +static void dma_callback(void *data) +{ + struct pl022 *pl022 = data; + struct spi_message *msg = pl022->cur_msg; + + BUG_ON(!pl022->sgt_rx.sgl); + +#ifdef VERBOSE_DEBUG + /* + * Optionally dump out buffers to inspect contents, this is + * good if you want to convince yourself that the loopback + * read/write contents are the same, when adopting to a new + * DMA engine. + */ + { + struct scatterlist *sg; + unsigned int i; + + dma_sync_sg_for_cpu(&pl022->adev->dev, + pl022->sgt_rx.sgl, + pl022->sgt_rx.nents, + DMA_FROM_DEVICE); + + for_each_sg(pl022->sgt_rx.sgl, sg, pl022->sgt_rx.nents, i) { + dev_dbg(&pl022->adev->dev, "SPI RX SG ENTRY: %d", i); + print_hex_dump(KERN_ERR, "SPI RX: ", + DUMP_PREFIX_OFFSET, + 16, + 1, + sg_virt(sg), + sg_dma_len(sg), + 1); + } + for_each_sg(pl022->sgt_tx.sgl, sg, pl022->sgt_tx.nents, i) { + dev_dbg(&pl022->adev->dev, "SPI TX SG ENTRY: %d", i); + print_hex_dump(KERN_ERR, "SPI TX: ", + DUMP_PREFIX_OFFSET, + 16, + 1, + sg_virt(sg), + sg_dma_len(sg), + 1); + } + } +#endif + + unmap_free_dma_scatter(pl022); + + /* Update total bytes transfered */ + msg->actual_length += pl022->cur_transfer->len; + if (pl022->cur_transfer->cs_change) + pl022->cur_chip-> + cs_control(SSP_CHIP_DESELECT); + + /* Move to next transfer */ + msg->state = next_transfer(pl022); + tasklet_schedule(&pl022->pump_transfers); +} + +static void setup_dma_scatter(struct pl022 *pl022, + void *buffer, + unsigned int length, + struct sg_table *sgtab) +{ + struct scatterlist *sg; + int bytesleft = length; + void *bufp = buffer; + int mapbytes; + int i; + + if (buffer) { + for_each_sg(sgtab->sgl, sg, sgtab->nents, i) { + /* + * If there are less bytes left than what fits + * in the current page (plus page alignment offset) + * we just feed in this, else we stuff in as much + * as we can. + */ + if (bytesleft < (PAGE_SIZE - offset_in_page(bufp))) + mapbytes = bytesleft; + else + mapbytes = PAGE_SIZE - offset_in_page(bufp); + sg_set_page(sg, virt_to_page(bufp), + mapbytes, offset_in_page(bufp)); + bufp += mapbytes; + bytesleft -= mapbytes; + dev_dbg(&pl022->adev->dev, + "set RX/TX target page @ %p, %d bytes, %d left\n", + bufp, mapbytes, bytesleft); + } + } else { + /* Map the dummy buffer on every page */ + for_each_sg(sgtab->sgl, sg, sgtab->nents, i) { + if (bytesleft < PAGE_SIZE) + mapbytes = bytesleft; + else + mapbytes = PAGE_SIZE; + sg_set_page(sg, virt_to_page(pl022->dummypage), + mapbytes, 0); + bytesleft -= mapbytes; + dev_dbg(&pl022->adev->dev, + "set RX/TX to dummy page %d bytes, %d left\n", + mapbytes, bytesleft); + + } + } + BUG_ON(bytesleft); +} + +/** + * configure_dma - configures the channels for the next transfer + * @pl022: SSP driver's private data structure + */ +static int configure_dma(struct pl022 *pl022) +{ + struct dma_slave_config rx_conf = { + .src_addr = SSP_DR(pl022->phybase), + .direction = DMA_FROM_DEVICE, + .src_maxburst = pl022->vendor->fifodepth >> 1, + }; + struct dma_slave_config tx_conf = { + .dst_addr = SSP_DR(pl022->phybase), + .direction = DMA_TO_DEVICE, + .dst_maxburst = pl022->vendor->fifodepth >> 1, + }; + unsigned int pages; + int ret; + int sglen; + struct dma_chan *rxchan = pl022->dma_rx_channel; + struct dma_chan *txchan = pl022->dma_tx_channel; + struct dma_async_tx_descriptor *rxdesc; + struct dma_async_tx_descriptor *txdesc; + dma_cookie_t cookie; + + /* Check that the channels are available */ + if (!rxchan || !txchan) + return -ENODEV; + + switch (pl022->read) { + case READING_NULL: + /* Use the same as for writing */ + rx_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_UNDEFINED; + break; + case READING_U8: + rx_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + break; + case READING_U16: + rx_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; + break; + case READING_U32: + rx_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + break; + } + + switch (pl022->write) { + case WRITING_NULL: + /* Use the same as for reading */ + tx_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_UNDEFINED; + break; + case WRITING_U8: + tx_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + break; + case WRITING_U16: + tx_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; + break; + case WRITING_U32: + tx_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;; + break; + } + + /* SPI pecularity: we need to read and write the same width */ + if (rx_conf.src_addr_width == DMA_SLAVE_BUSWIDTH_UNDEFINED) + rx_conf.src_addr_width = tx_conf.dst_addr_width; + if (tx_conf.dst_addr_width == DMA_SLAVE_BUSWIDTH_UNDEFINED) + tx_conf.dst_addr_width = rx_conf.src_addr_width; + BUG_ON(rx_conf.src_addr_width != tx_conf.dst_addr_width); + + rxchan->device->device_control(rxchan, DMA_SLAVE_CONFIG, + (unsigned long) &rx_conf); + txchan->device->device_control(txchan, DMA_SLAVE_CONFIG, + (unsigned long) &tx_conf); + + /* Create sglists for the transfers */ + pages = (pl022->cur_transfer->len >> PAGE_SHIFT) + 1; + dev_dbg(&pl022->adev->dev, "using %d pages for transfer\n", pages); + + ret = sg_alloc_table(&pl022->sgt_rx, pages, GFP_KERNEL); + if (ret) + goto err_alloc_rx_sg; + + ret = sg_alloc_table(&pl022->sgt_tx, pages, GFP_KERNEL); + if (ret) + goto err_alloc_tx_sg; + + /* Fill in the scatterlists for the RX+TX buffers */ + setup_dma_scatter(pl022, pl022->rx, + pl022->cur_transfer->len, &pl022->sgt_rx); + setup_dma_scatter(pl022, pl022->tx, + pl022->cur_transfer->len, &pl022->sgt_tx); + + /* Map DMA buffers */ + sglen = dma_map_sg(&pl022->adev->dev, pl022->sgt_rx.sgl, + pl022->sgt_rx.nents, DMA_FROM_DEVICE); + if (!sglen) + goto err_rx_sgmap; + + sglen = dma_map_sg(&pl022->adev->dev, pl022->sgt_tx.sgl, + pl022->sgt_tx.nents, DMA_TO_DEVICE); + if (!sglen) + goto err_tx_sgmap; + + /* Send both scatterlists */ + rxdesc = rxchan->device->device_prep_slave_sg(rxchan, + pl022->sgt_rx.sgl, + pl022->sgt_rx.nents, + DMA_FROM_DEVICE, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!rxdesc) + goto err_rxdesc; + + txdesc = txchan->device->device_prep_slave_sg(txchan, + pl022->sgt_tx.sgl, + pl022->sgt_tx.nents, + DMA_TO_DEVICE, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!txdesc) + goto err_txdesc; + + /* Put the callback on the RX transfer only, that should finish last */ + rxdesc->callback = dma_callback; + rxdesc->callback_param = pl022; + + /* Submit and fire RX and TX with TX last so we're ready to read! */ + cookie = rxdesc->tx_submit(rxdesc); + if (dma_submit_error(cookie)) + goto err_submit_rx; + cookie = txdesc->tx_submit(txdesc); + if (dma_submit_error(cookie)) + goto err_submit_tx; + rxchan->device->device_issue_pending(rxchan); + txchan->device->device_issue_pending(txchan); + + return 0; + +err_submit_tx: +err_submit_rx: +err_txdesc: + txchan->device->device_control(txchan, DMA_TERMINATE_ALL, 0); +err_rxdesc: + rxchan->device->device_control(rxchan, DMA_TERMINATE_ALL, 0); + dma_unmap_sg(&pl022->adev->dev, pl022->sgt_tx.sgl, + pl022->sgt_tx.nents, DMA_TO_DEVICE); +err_tx_sgmap: + dma_unmap_sg(&pl022->adev->dev, pl022->sgt_rx.sgl, + pl022->sgt_tx.nents, DMA_FROM_DEVICE); +err_rx_sgmap: + sg_free_table(&pl022->sgt_tx); +err_alloc_tx_sg: + sg_free_table(&pl022->sgt_rx); +err_alloc_rx_sg: + return -ENOMEM; +} + +static int __init pl022_dma_probe(struct pl022 *pl022) +{ + dma_cap_mask_t mask; + + /* Try to acquire a generic DMA engine slave channel */ + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + /* + * We need both RX and TX channels to do DMA, else do none + * of them. + */ + pl022->dma_rx_channel = dma_request_channel(mask, + pl022->master_info->dma_filter, + pl022->master_info->dma_rx_param); + if (!pl022->dma_rx_channel) { + dev_err(&pl022->adev->dev, "no RX DMA channel!\n"); + goto err_no_rxchan; + } + + pl022->dma_tx_channel = dma_request_channel(mask, + pl022->master_info->dma_filter, + pl022->master_info->dma_tx_param); + if (!pl022->dma_tx_channel) { + dev_err(&pl022->adev->dev, "no TX DMA channel!\n"); + goto err_no_txchan; + } + + pl022->dummypage = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!pl022->dummypage) { + dev_err(&pl022->adev->dev, "no DMA dummypage!\n"); + goto err_no_dummypage; + } + + dev_info(&pl022->adev->dev, "setup for DMA on RX %s, TX %s\n", + dma_chan_name(pl022->dma_rx_channel), + dma_chan_name(pl022->dma_tx_channel)); + + return 0; + +err_no_dummypage: + dma_release_channel(pl022->dma_tx_channel); +err_no_txchan: + dma_release_channel(pl022->dma_rx_channel); + pl022->dma_rx_channel = NULL; +err_no_rxchan: + return -ENODEV; +} + +static void terminate_dma(struct pl022 *pl022) +{ + struct dma_chan *rxchan = pl022->dma_rx_channel; + struct dma_chan *txchan = pl022->dma_tx_channel; + + rxchan->device->device_control(rxchan, DMA_TERMINATE_ALL, 0); + txchan->device->device_control(txchan, DMA_TERMINATE_ALL, 0); + unmap_free_dma_scatter(pl022); +} + +static void pl022_dma_remove(struct pl022 *pl022) +{ + if (pl022->busy) + terminate_dma(pl022); + if (pl022->dma_tx_channel) + dma_release_channel(pl022->dma_tx_channel); + if (pl022->dma_rx_channel) + dma_release_channel(pl022->dma_rx_channel); + kfree(pl022->dummypage); +} + +#else +static inline int configure_dma(struct pl022 *pl022) +{ + return -ENODEV; +} + +static inline int pl022_dma_probe(struct pl022 *pl022) +{ + return 0; +} + +static inline void pl022_dma_remove(struct pl022 *pl022) +{ +} +#endif + /** * pl022_interrupt_handler - Interrupt handler for SSP controller * @@ -794,14 +1169,17 @@ static irqreturn_t pl022_interrupt_handler(int irq, void *dev_id) if (unlikely(!irq_status)) return IRQ_NONE; - /* This handles the error code interrupts */ + /* + * This handles the FIFO interrupts, the timeout + * interrupts are flatly ignored, they cannot be + * trusted. + */ if (unlikely(irq_status & SSP_MIS_MASK_RORMIS)) { /* * Overrun interrupt - bail out since our Data has been * corrupted */ - dev_err(&pl022->adev->dev, - "FIFO overrun\n"); + dev_err(&pl022->adev->dev, "FIFO overrun\n"); if (readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_RFF) dev_err(&pl022->adev->dev, "RXFIFO is full\n"); @@ -896,8 +1274,8 @@ static int set_up_next_transfer(struct pl022 *pl022, } /** - * pump_transfers - Tasklet function which schedules next interrupt transfer - * when running in interrupt transfer mode. + * pump_transfers - Tasklet function which schedules next transfer + * when running in interrupt or DMA transfer mode. * @data: SSP driver private data structure * */ @@ -954,65 +1332,23 @@ static void pump_transfers(unsigned long data) } /* Flush the FIFOs and let's go! */ flush(pl022); - writew(ENABLE_ALL_INTERRUPTS, SSP_IMSC(pl022->virtbase)); -} - -/** - * NOT IMPLEMENTED - * configure_dma - It configures the DMA pipes for DMA transfers - * @data: SSP driver's private data structure - * - */ -static int configure_dma(void *data) -{ - struct pl022 *pl022 = data; - dev_dbg(&pl022->adev->dev, "configure DMA\n"); - return -ENOTSUPP; -} - -/** - * do_dma_transfer - It handles transfers of the current message - * if it is DMA xfer. - * NOT FULLY IMPLEMENTED - * @data: SSP driver's private data structure - */ -static void do_dma_transfer(void *data) -{ - struct pl022 *pl022 = data; - - if (configure_dma(data)) { - dev_dbg(&pl022->adev->dev, "configuration of DMA Failed!\n"); - goto err_config_dma; - } - /* TODO: Implememt DMA setup of pipes here */ - - /* Enable target chip, set up transfer */ - pl022->cur_chip->cs_control(SSP_CHIP_SELECT); - if (set_up_next_transfer(pl022, pl022->cur_transfer)) { - /* Error path */ - pl022->cur_msg->state = STATE_ERROR; - pl022->cur_msg->status = -EIO; - giveback(pl022); + if (pl022->cur_chip->enable_dma) { + if (configure_dma(pl022)) { + dev_dbg(&pl022->adev->dev, + "configuration of DMA failed, fall back to interrupt mode\n"); + goto err_config_dma; + } return; } - /* Enable SSP */ - writew((readw(SSP_CR1(pl022->virtbase)) | SSP_CR1_MASK_SSE), - SSP_CR1(pl022->virtbase)); - - /* TODO: Enable the DMA transfer here */ - return; - err_config_dma: - pl022->cur_msg->state = STATE_ERROR; - pl022->cur_msg->status = -EIO; - giveback(pl022); - return; +err_config_dma: + writew(ENABLE_ALL_INTERRUPTS, SSP_IMSC(pl022->virtbase)); } -static void do_interrupt_transfer(void *data) +static void do_interrupt_dma_transfer(struct pl022 *pl022) { - struct pl022 *pl022 = data; + u32 irqflags = ENABLE_ALL_INTERRUPTS; /* Enable target chip */ pl022->cur_chip->cs_control(SSP_CHIP_SELECT); @@ -1023,15 +1359,26 @@ static void do_interrupt_transfer(void *data) giveback(pl022); return; } + /* If we're using DMA, set up DMA here */ + if (pl022->cur_chip->enable_dma) { + /* Configure DMA transfer */ + if (configure_dma(pl022)) { + dev_dbg(&pl022->adev->dev, + "configuration of DMA failed, fall back to interrupt mode\n"); + goto err_config_dma; + } + /* Disable interrupts in DMA mode, IRQ from DMA controller */ + irqflags = DISABLE_ALL_INTERRUPTS; + } +err_config_dma: /* Enable SSP, turn on interrupts */ writew((readw(SSP_CR1(pl022->virtbase)) | SSP_CR1_MASK_SSE), SSP_CR1(pl022->virtbase)); - writew(ENABLE_ALL_INTERRUPTS, SSP_IMSC(pl022->virtbase)); + writew(irqflags, SSP_IMSC(pl022->virtbase)); } -static void do_polling_transfer(void *data) +static void do_polling_transfer(struct pl022 *pl022) { - struct pl022 *pl022 = data; struct spi_message *message = NULL; struct spi_transfer *transfer = NULL; struct spi_transfer *previous = NULL; @@ -1101,7 +1448,7 @@ static void do_polling_transfer(void *data) * * This function checks if there is any spi message in the queue that * needs processing and delegate control to appropriate function - * do_polling_transfer()/do_interrupt_transfer()/do_dma_transfer() + * do_polling_transfer()/do_interrupt_dma_transfer() * based on the kind of the transfer * */ @@ -1150,10 +1497,8 @@ static void pump_messages(struct work_struct *work) if (pl022->cur_chip->xfer_type == POLLING_TRANSFER) do_polling_transfer(pl022); - else if (pl022->cur_chip->xfer_type == INTERRUPT_TRANSFER) - do_interrupt_transfer(pl022); else - do_dma_transfer(pl022); + do_interrupt_dma_transfer(pl022); } @@ -1248,100 +1593,56 @@ static int destroy_queue(struct pl022 *pl022) } static int verify_controller_parameters(struct pl022 *pl022, - struct pl022_config_chip *chip_info) + struct pl022_config_chip const *chip_info) { - if ((chip_info->lbm != LOOPBACK_ENABLED) - && (chip_info->lbm != LOOPBACK_DISABLED)) { - dev_err(chip_info->dev, - "loopback Mode is configured incorrectly\n"); - return -EINVAL; - } if ((chip_info->iface < SSP_INTERFACE_MOTOROLA_SPI) || (chip_info->iface > SSP_INTERFACE_UNIDIRECTIONAL)) { - dev_err(chip_info->dev, + dev_err(&pl022->adev->dev, "interface is configured incorrectly\n"); return -EINVAL; } if ((chip_info->iface == SSP_INTERFACE_UNIDIRECTIONAL) && (!pl022->vendor->unidir)) { - dev_err(chip_info->dev, + dev_err(&pl022->adev->dev, "unidirectional mode not supported in this " "hardware version\n"); return -EINVAL; } if ((chip_info->hierarchy != SSP_MASTER) && (chip_info->hierarchy != SSP_SLAVE)) { - dev_err(chip_info->dev, + dev_err(&pl022->adev->dev, "hierarchy is configured incorrectly\n"); return -EINVAL; } - if (((chip_info->clk_freq).cpsdvsr < CPSDVR_MIN) - || ((chip_info->clk_freq).cpsdvsr > CPSDVR_MAX)) { - dev_err(chip_info->dev, - "cpsdvsr is configured incorrectly\n"); - return -EINVAL; - } - if ((chip_info->endian_rx != SSP_RX_MSB) - && (chip_info->endian_rx != SSP_RX_LSB)) { - dev_err(chip_info->dev, - "RX FIFO endianess is configured incorrectly\n"); - return -EINVAL; - } - if ((chip_info->endian_tx != SSP_TX_MSB) - && (chip_info->endian_tx != SSP_TX_LSB)) { - dev_err(chip_info->dev, - "TX FIFO endianess is configured incorrectly\n"); - return -EINVAL; - } - if ((chip_info->data_size < SSP_DATA_BITS_4) - || (chip_info->data_size > SSP_DATA_BITS_32)) { - dev_err(chip_info->dev, - "DATA Size is configured incorrectly\n"); - return -EINVAL; - } if ((chip_info->com_mode != INTERRUPT_TRANSFER) && (chip_info->com_mode != DMA_TRANSFER) && (chip_info->com_mode != POLLING_TRANSFER)) { - dev_err(chip_info->dev, + dev_err(&pl022->adev->dev, "Communication mode is configured incorrectly\n"); return -EINVAL; } if ((chip_info->rx_lev_trig < SSP_RX_1_OR_MORE_ELEM) || (chip_info->rx_lev_trig > SSP_RX_32_OR_MORE_ELEM)) { - dev_err(chip_info->dev, + dev_err(&pl022->adev->dev, "RX FIFO Trigger Level is configured incorrectly\n"); return -EINVAL; } if ((chip_info->tx_lev_trig < SSP_TX_1_OR_MORE_EMPTY_LOC) || (chip_info->tx_lev_trig > SSP_TX_32_OR_MORE_EMPTY_LOC)) { - dev_err(chip_info->dev, + dev_err(&pl022->adev->dev, "TX FIFO Trigger Level is configured incorrectly\n"); return -EINVAL; } - if (chip_info->iface == SSP_INTERFACE_MOTOROLA_SPI) { - if ((chip_info->clk_phase != SSP_CLK_FIRST_EDGE) - && (chip_info->clk_phase != SSP_CLK_SECOND_EDGE)) { - dev_err(chip_info->dev, - "Clock Phase is configured incorrectly\n"); - return -EINVAL; - } - if ((chip_info->clk_pol != SSP_CLK_POL_IDLE_LOW) - && (chip_info->clk_pol != SSP_CLK_POL_IDLE_HIGH)) { - dev_err(chip_info->dev, - "Clock Polarity is configured incorrectly\n"); - return -EINVAL; - } - } if (chip_info->iface == SSP_INTERFACE_NATIONAL_MICROWIRE) { if ((chip_info->ctrl_len < SSP_BITS_4) || (chip_info->ctrl_len > SSP_BITS_32)) { - dev_err(chip_info->dev, + dev_err(&pl022->adev->dev, "CTRL LEN is configured incorrectly\n"); return -EINVAL; } if ((chip_info->wait_state != SSP_MWIRE_WAIT_ZERO) && (chip_info->wait_state != SSP_MWIRE_WAIT_ONE)) { - dev_err(chip_info->dev, + dev_err(&pl022->adev->dev, "Wait State is configured incorrectly\n"); return -EINVAL; } @@ -1350,24 +1651,20 @@ static int verify_controller_parameters(struct pl022 *pl022, if ((chip_info->duplex != SSP_MICROWIRE_CHANNEL_FULL_DUPLEX) && (chip_info->duplex != - SSP_MICROWIRE_CHANNEL_HALF_DUPLEX)) - dev_err(chip_info->dev, + SSP_MICROWIRE_CHANNEL_HALF_DUPLEX)) { + dev_err(&pl022->adev->dev, "Microwire duplex mode is configured incorrectly\n"); return -EINVAL; + } } else { if (chip_info->duplex != SSP_MICROWIRE_CHANNEL_FULL_DUPLEX) - dev_err(chip_info->dev, + dev_err(&pl022->adev->dev, "Microwire half duplex mode requested," " but this is only available in the" " ST version of PL022\n"); return -EINVAL; } } - if (chip_info->cs_control == NULL) { - dev_warn(chip_info->dev, - "Chip Select Function is NULL for this chip\n"); - chip_info->cs_control = null_cs_control; - } return 0; } @@ -1467,22 +1764,24 @@ static int calculate_effective_freq(struct pl022 *pl022, return 0; } -/** - * NOT IMPLEMENTED - * process_dma_info - Processes the DMA info provided by client drivers - * @chip_info: chip info provided by client device - * @chip: Runtime state maintained by the SSP controller for each spi device - * - * This function processes and stores DMA config provided by client driver - * into the runtime state maintained by the SSP controller driver + +/* + * A piece of default chip info unless the platform + * supplies it. */ -static int process_dma_info(struct pl022_config_chip *chip_info, - struct chip_data *chip) -{ - dev_err(chip_info->dev, - "cannot process DMA info, DMA not implemented!\n"); - return -ENOTSUPP; -} +static const struct pl022_config_chip pl022_default_chip_info = { + .com_mode = POLLING_TRANSFER, + .iface = SSP_INTERFACE_MOTOROLA_SPI, + .hierarchy = SSP_SLAVE, + .slave_tx_disable = DO_NOT_DRIVE_TX, + .rx_lev_trig = SSP_RX_1_OR_MORE_ELEM, + .tx_lev_trig = SSP_TX_1_OR_MORE_EMPTY_LOC, + .ctrl_len = SSP_BITS_8, + .wait_state = SSP_MWIRE_WAIT_ZERO, + .duplex = SSP_MICROWIRE_CHANNEL_FULL_DUPLEX, + .cs_control = null_cs_control, +}; + /** * pl022_setup - setup function registered to SPI master framework @@ -1496,23 +1795,15 @@ static int process_dma_info(struct pl022_config_chip *chip_info, * controller hardware here, that is not done until the actual transfer * commence. */ - -/* FIXME: JUST GUESSING the spi->mode bits understood by this driver */ -#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH \ - | SPI_LSB_FIRST | SPI_LOOP) - static int pl022_setup(struct spi_device *spi) { - struct pl022_config_chip *chip_info; + struct pl022_config_chip const *chip_info; struct chip_data *chip; + struct ssp_clock_params clk_freq; int status = 0; struct pl022 *pl022 = spi_master_get_devdata(spi->master); - - if (spi->mode & ~MODEBITS) { - dev_dbg(&spi->dev, "unsupported mode bits %x\n", - spi->mode & ~MODEBITS); - return -EINVAL; - } + unsigned int bits = spi->bits_per_word; + u32 tmp; if (!spi->max_speed_hz) return -EINVAL; @@ -1535,48 +1826,13 @@ static int pl022_setup(struct spi_device *spi) chip_info = spi->controller_data; if (chip_info == NULL) { + chip_info = &pl022_default_chip_info; /* spi_board_info.controller_data not is supplied */ dev_dbg(&spi->dev, "using default controller_data settings\n"); - - chip_info = - kzalloc(sizeof(struct pl022_config_chip), GFP_KERNEL); - - if (!chip_info) { - dev_err(&spi->dev, - "cannot allocate controller data\n"); - status = -ENOMEM; - goto err_first_setup; - } - - dev_dbg(&spi->dev, "allocated memory for controller data\n"); - - /* Pointer back to the SPI device */ - chip_info->dev = &spi->dev; - /* - * Set controller data default values: - * Polling is supported by default - */ - chip_info->lbm = LOOPBACK_DISABLED; - chip_info->com_mode = POLLING_TRANSFER; - chip_info->iface = SSP_INTERFACE_MOTOROLA_SPI; - chip_info->hierarchy = SSP_SLAVE; - chip_info->slave_tx_disable = DO_NOT_DRIVE_TX; - chip_info->endian_tx = SSP_TX_LSB; - chip_info->endian_rx = SSP_RX_LSB; - chip_info->data_size = SSP_DATA_BITS_12; - chip_info->rx_lev_trig = SSP_RX_1_OR_MORE_ELEM; - chip_info->tx_lev_trig = SSP_TX_1_OR_MORE_EMPTY_LOC; - chip_info->clk_phase = SSP_CLK_SECOND_EDGE; - chip_info->clk_pol = SSP_CLK_POL_IDLE_LOW; - chip_info->ctrl_len = SSP_BITS_8; - chip_info->wait_state = SSP_MWIRE_WAIT_ZERO; - chip_info->duplex = SSP_MICROWIRE_CHANNEL_FULL_DUPLEX; - chip_info->cs_control = null_cs_control; - } else { + } else dev_dbg(&spi->dev, "using user supplied controller_data settings\n"); - } /* * We can override with custom divisors, else we use the board @@ -1586,29 +1842,48 @@ static int pl022_setup(struct spi_device *spi) && (0 == chip_info->clk_freq.scr)) { status = calculate_effective_freq(pl022, spi->max_speed_hz, - &chip_info->clk_freq); + &clk_freq); if (status < 0) goto err_config_params; } else { - if ((chip_info->clk_freq.cpsdvsr % 2) != 0) - chip_info->clk_freq.cpsdvsr = - chip_info->clk_freq.cpsdvsr - 1; + memcpy(&clk_freq, &chip_info->clk_freq, sizeof(clk_freq)); + if ((clk_freq.cpsdvsr % 2) != 0) + clk_freq.cpsdvsr = + clk_freq.cpsdvsr - 1; + } + if ((clk_freq.cpsdvsr < CPSDVR_MIN) + || (clk_freq.cpsdvsr > CPSDVR_MAX)) { + dev_err(&spi->dev, + "cpsdvsr is configured incorrectly\n"); + goto err_config_params; } + + status = verify_controller_parameters(pl022, chip_info); if (status) { dev_err(&spi->dev, "controller data is incorrect"); goto err_config_params; } + /* Now set controller state based on controller data */ chip->xfer_type = chip_info->com_mode; - chip->cs_control = chip_info->cs_control; - - if (chip_info->data_size <= 8) { - dev_dbg(&spi->dev, "1 <= n <=8 bits per word\n"); + if (!chip_info->cs_control) { + chip->cs_control = null_cs_control; + dev_warn(&spi->dev, + "chip select function is NULL for this chip\n"); + } else + chip->cs_control = chip_info->cs_control; + + if (bits <= 3) { + /* PL022 doesn't support less than 4-bits */ + status = -ENOTSUPP; + goto err_config_params; + } else if (bits <= 8) { + dev_dbg(&spi->dev, "4 <= n <=8 bits per word\n"); chip->n_bytes = 1; chip->read = READING_U8; chip->write = WRITING_U8; - } else if (chip_info->data_size <= 16) { + } else if (bits <= 16) { dev_dbg(&spi->dev, "9 <= n <= 16 bits per word\n"); chip->n_bytes = 2; chip->read = READING_U16; @@ -1625,6 +1900,7 @@ static int pl022_setup(struct spi_device *spi) dev_err(&spi->dev, "a standard pl022 can only handle " "1 <= n <= 16 bit words\n"); + status = -ENOTSUPP; goto err_config_params; } } @@ -1636,9 +1912,8 @@ static int pl022_setup(struct spi_device *spi) chip->cpsr = 0; if ((chip_info->com_mode == DMA_TRANSFER) && ((pl022->master_info)->enable_dma)) { - chip->enable_dma = 1; + chip->enable_dma = true; dev_dbg(&spi->dev, "DMA mode set in controller state\n"); - status = process_dma_info(chip_info, chip); if (status < 0) goto err_config_params; SSP_WRITE_BITS(chip->dmacr, SSP_DMA_ENABLED, @@ -1646,7 +1921,7 @@ static int pl022_setup(struct spi_device *spi) SSP_WRITE_BITS(chip->dmacr, SSP_DMA_ENABLED, SSP_DMACR_MASK_TXDMAE, 1); } else { - chip->enable_dma = 0; + chip->enable_dma = false; dev_dbg(&spi->dev, "DMA mode NOT set in controller state\n"); SSP_WRITE_BITS(chip->dmacr, SSP_DMA_DISABLED, SSP_DMACR_MASK_RXDMAE, 0); @@ -1654,10 +1929,12 @@ static int pl022_setup(struct spi_device *spi) SSP_DMACR_MASK_TXDMAE, 1); } - chip->cpsr = chip_info->clk_freq.cpsdvsr; + chip->cpsr = clk_freq.cpsdvsr; /* Special setup for the ST micro extended control registers */ if (pl022->vendor->extended_cr) { + u32 etx; + if (pl022->vendor->pl023) { /* These bits are only in the PL023 */ SSP_WRITE_BITS(chip->cr1, chip_info->clkdelay, @@ -1673,29 +1950,51 @@ static int pl022_setup(struct spi_device *spi) SSP_WRITE_BITS(chip->cr1, chip_info->wait_state, SSP_CR1_MASK_MWAIT_ST, 6); } - SSP_WRITE_BITS(chip->cr0, chip_info->data_size, + SSP_WRITE_BITS(chip->cr0, bits - 1, SSP_CR0_MASK_DSS_ST, 0); - SSP_WRITE_BITS(chip->cr1, chip_info->endian_rx, - SSP_CR1_MASK_RENDN_ST, 4); - SSP_WRITE_BITS(chip->cr1, chip_info->endian_tx, - SSP_CR1_MASK_TENDN_ST, 5); + + if (spi->mode & SPI_LSB_FIRST) { + tmp = SSP_RX_LSB; + etx = SSP_TX_LSB; + } else { + tmp = SSP_RX_MSB; + etx = SSP_TX_MSB; + } + SSP_WRITE_BITS(chip->cr1, tmp, SSP_CR1_MASK_RENDN_ST, 4); + SSP_WRITE_BITS(chip->cr1, etx, SSP_CR1_MASK_TENDN_ST, 5); SSP_WRITE_BITS(chip->cr1, chip_info->rx_lev_trig, SSP_CR1_MASK_RXIFLSEL_ST, 7); SSP_WRITE_BITS(chip->cr1, chip_info->tx_lev_trig, SSP_CR1_MASK_TXIFLSEL_ST, 10); } else { - SSP_WRITE_BITS(chip->cr0, chip_info->data_size, + SSP_WRITE_BITS(chip->cr0, bits - 1, SSP_CR0_MASK_DSS, 0); SSP_WRITE_BITS(chip->cr0, chip_info->iface, SSP_CR0_MASK_FRF, 4); } + /* Stuff that is common for all versions */ - SSP_WRITE_BITS(chip->cr0, chip_info->clk_pol, SSP_CR0_MASK_SPO, 6); - SSP_WRITE_BITS(chip->cr0, chip_info->clk_phase, SSP_CR0_MASK_SPH, 7); - SSP_WRITE_BITS(chip->cr0, chip_info->clk_freq.scr, SSP_CR0_MASK_SCR, 8); + if (spi->mode & SPI_CPOL) + tmp = SSP_CLK_POL_IDLE_HIGH; + else + tmp = SSP_CLK_POL_IDLE_LOW; + SSP_WRITE_BITS(chip->cr0, tmp, SSP_CR0_MASK_SPO, 6); + + if (spi->mode & SPI_CPHA) + tmp = SSP_CLK_SECOND_EDGE; + else + tmp = SSP_CLK_FIRST_EDGE; + SSP_WRITE_BITS(chip->cr0, tmp, SSP_CR0_MASK_SPH, 7); + + SSP_WRITE_BITS(chip->cr0, clk_freq.scr, SSP_CR0_MASK_SCR, 8); /* Loopback is available on all versions except PL023 */ - if (!pl022->vendor->pl023) - SSP_WRITE_BITS(chip->cr1, chip_info->lbm, SSP_CR1_MASK_LBM, 0); + if (!pl022->vendor->pl023) { + if (spi->mode & SPI_LOOP) + tmp = LOOPBACK_ENABLED; + else + tmp = LOOPBACK_DISABLED; + SSP_WRITE_BITS(chip->cr1, tmp, SSP_CR1_MASK_LBM, 0); + } SSP_WRITE_BITS(chip->cr1, SSP_DISABLED, SSP_CR1_MASK_SSE, 1); SSP_WRITE_BITS(chip->cr1, chip_info->hierarchy, SSP_CR1_MASK_MS, 2); SSP_WRITE_BITS(chip->cr1, chip_info->slave_tx_disable, SSP_CR1_MASK_SOD, 3); @@ -1704,7 +2003,7 @@ static int pl022_setup(struct spi_device *spi) spi_set_ctldata(spi, chip); return status; err_config_params: - err_first_setup: + spi_set_ctldata(spi, NULL); kfree(chip); return status; } @@ -1766,12 +2065,21 @@ pl022_probe(struct amba_device *adev, struct amba_id *id) master->setup = pl022_setup; master->transfer = pl022_transfer; + /* + * Supports mode 0-3, loopback, and active low CS. Transfers are + * always MS bit first on the original pl022. + */ + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP; + if (pl022->vendor->extended_cr) + master->mode_bits |= SPI_LSB_FIRST; + dev_dbg(&adev->dev, "BUSNO: %d\n", master->bus_num); status = amba_request_regions(adev, NULL); if (status) goto err_no_ioregion; + pl022->phybase = adev->res.start; pl022->virtbase = ioremap(adev->res.start, resource_size(&adev->res)); if (pl022->virtbase == NULL) { status = -ENOMEM; @@ -1798,6 +2106,14 @@ pl022_probe(struct amba_device *adev, struct amba_id *id) dev_err(&adev->dev, "probe - cannot get IRQ (%d)\n", status); goto err_no_irq; } + + /* Get DMA channels */ + if (platform_info->enable_dma) { + status = pl022_dma_probe(pl022); + if (status != 0) + goto err_no_dma; + } + /* Initialize and start queue */ status = init_queue(pl022); if (status != 0) { @@ -1826,6 +2142,8 @@ pl022_probe(struct amba_device *adev, struct amba_id *id) err_start_queue: err_init_queue: destroy_queue(pl022); + pl022_dma_remove(pl022); + err_no_dma: free_irq(adev->irq[0], pl022); err_no_irq: clk_put(pl022->clk); @@ -1856,6 +2174,7 @@ pl022_remove(struct amba_device *adev) return status; } load_ssp_default_config(pl022); + pl022_dma_remove(pl022); free_irq(adev->irq[0], pl022); clk_disable(pl022->clk); clk_put(pl022->clk); diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c index c4e04428992d..154529aacc03 100644 --- a/drivers/spi/atmel_spi.c +++ b/drivers/spi/atmel_spi.c @@ -654,6 +654,8 @@ static int atmel_spi_transfer(struct spi_device *spi, struct spi_message *msg) struct spi_transfer *xfer; unsigned long flags; struct device *controller = spi->master->dev.parent; + u8 bits; + struct atmel_spi_device *asd; as = spi_master_get_devdata(spi->master); @@ -672,8 +674,18 @@ static int atmel_spi_transfer(struct spi_device *spi, struct spi_message *msg) return -EINVAL; } + if (xfer->bits_per_word) { + asd = spi->controller_state; + bits = (asd->csr >> 4) & 0xf; + if (bits != xfer->bits_per_word - 8) { + dev_dbg(&spi->dev, "you can't yet change " + "bits_per_word in transfers\n"); + return -ENOPROTOOPT; + } + } + /* FIXME implement these protocol options!! */ - if (xfer->bits_per_word || xfer->speed_hz) { + if (xfer->speed_hz) { dev_dbg(&spi->dev, "no protocol options yet\n"); return -ENOPROTOOPT; } diff --git a/drivers/spi/dw_spi.c b/drivers/spi/dw_spi.c index 56247853c298..90439314cf67 100644 --- a/drivers/spi/dw_spi.c +++ b/drivers/spi/dw_spi.c @@ -131,6 +131,7 @@ static const struct file_operations mrst_spi_regs_ops = { .owner = THIS_MODULE, .open = spi_show_regs_open, .read = spi_show_regs, + .llseek = default_llseek, }; static int mrst_spi_debugfs_init(struct dw_spi *dws) diff --git a/drivers/spi/omap2_mcspi.c b/drivers/spi/omap2_mcspi.c index b3a94ca0a75a..2a651e61bfbf 100644 --- a/drivers/spi/omap2_mcspi.c +++ b/drivers/spi/omap2_mcspi.c @@ -296,6 +296,19 @@ static int omap2_mcspi_enable_clocks(struct omap2_mcspi *mcspi) return 0; } +static int mcspi_wait_for_reg_bit(void __iomem *reg, unsigned long bit) +{ + unsigned long timeout; + + timeout = jiffies + msecs_to_jiffies(1000); + while (!(__raw_readl(reg) & bit)) { + if (time_after(jiffies, timeout)) + return -1; + cpu_relax(); + } + return 0; +} + static unsigned omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) { @@ -309,11 +322,14 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) u32 l; u8 * rx; const u8 * tx; + void __iomem *chstat_reg; mcspi = spi_master_get_devdata(spi->master); mcspi_dma = &mcspi->dma_channels[spi->chip_select]; l = mcspi_cached_chconf0(spi); + chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0; + count = xfer->len; c = count; word_len = cs->word_len; @@ -382,6 +398,16 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) if (tx != NULL) { wait_for_completion(&mcspi_dma->dma_tx_completion); dma_unmap_single(NULL, xfer->tx_dma, count, DMA_TO_DEVICE); + + /* for TX_ONLY mode, be sure all words have shifted out */ + if (rx == NULL) { + if (mcspi_wait_for_reg_bit(chstat_reg, + OMAP2_MCSPI_CHSTAT_TXS) < 0) + dev_err(&spi->dev, "TXS timed out\n"); + else if (mcspi_wait_for_reg_bit(chstat_reg, + OMAP2_MCSPI_CHSTAT_EOT) < 0) + dev_err(&spi->dev, "EOT timed out\n"); + } } if (rx != NULL) { @@ -435,19 +461,6 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) return count; } -static int mcspi_wait_for_reg_bit(void __iomem *reg, unsigned long bit) -{ - unsigned long timeout; - - timeout = jiffies + msecs_to_jiffies(1000); - while (!(__raw_readl(reg) & bit)) { - if (time_after(jiffies, timeout)) - return -1; - cpu_relax(); - } - return 0; -} - static unsigned omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer) { @@ -489,10 +502,8 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer) dev_err(&spi->dev, "TXS timed out\n"); goto out; } -#ifdef VERBOSE - dev_dbg(&spi->dev, "write-%d %02x\n", + dev_vdbg(&spi->dev, "write-%d %02x\n", word_len, *tx); -#endif __raw_writel(*tx++, tx_reg); } if (rx != NULL) { @@ -506,10 +517,8 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer) (l & OMAP2_MCSPI_CHCONF_TURBO)) { omap2_mcspi_set_enable(spi, 0); *rx++ = __raw_readl(rx_reg); -#ifdef VERBOSE - dev_dbg(&spi->dev, "read-%d %02x\n", + dev_vdbg(&spi->dev, "read-%d %02x\n", word_len, *(rx - 1)); -#endif if (mcspi_wait_for_reg_bit(chstat_reg, OMAP2_MCSPI_CHSTAT_RXS) < 0) { dev_err(&spi->dev, @@ -522,10 +531,8 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer) } *rx++ = __raw_readl(rx_reg); -#ifdef VERBOSE - dev_dbg(&spi->dev, "read-%d %02x\n", + dev_vdbg(&spi->dev, "read-%d %02x\n", word_len, *(rx - 1)); -#endif } } while (c); } else if (word_len <= 16) { @@ -542,10 +549,8 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer) dev_err(&spi->dev, "TXS timed out\n"); goto out; } -#ifdef VERBOSE - dev_dbg(&spi->dev, "write-%d %04x\n", + dev_vdbg(&spi->dev, "write-%d %04x\n", word_len, *tx); -#endif __raw_writel(*tx++, tx_reg); } if (rx != NULL) { @@ -559,10 +564,8 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer) (l & OMAP2_MCSPI_CHCONF_TURBO)) { omap2_mcspi_set_enable(spi, 0); *rx++ = __raw_readl(rx_reg); -#ifdef VERBOSE - dev_dbg(&spi->dev, "read-%d %04x\n", + dev_vdbg(&spi->dev, "read-%d %04x\n", word_len, *(rx - 1)); -#endif if (mcspi_wait_for_reg_bit(chstat_reg, OMAP2_MCSPI_CHSTAT_RXS) < 0) { dev_err(&spi->dev, @@ -575,10 +578,8 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer) } *rx++ = __raw_readl(rx_reg); -#ifdef VERBOSE - dev_dbg(&spi->dev, "read-%d %04x\n", + dev_vdbg(&spi->dev, "read-%d %04x\n", word_len, *(rx - 1)); -#endif } } while (c); } else if (word_len <= 32) { @@ -595,10 +596,8 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer) dev_err(&spi->dev, "TXS timed out\n"); goto out; } -#ifdef VERBOSE - dev_dbg(&spi->dev, "write-%d %08x\n", + dev_vdbg(&spi->dev, "write-%d %08x\n", word_len, *tx); -#endif __raw_writel(*tx++, tx_reg); } if (rx != NULL) { @@ -612,10 +611,8 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer) (l & OMAP2_MCSPI_CHCONF_TURBO)) { omap2_mcspi_set_enable(spi, 0); *rx++ = __raw_readl(rx_reg); -#ifdef VERBOSE - dev_dbg(&spi->dev, "read-%d %08x\n", + dev_vdbg(&spi->dev, "read-%d %08x\n", word_len, *(rx - 1)); -#endif if (mcspi_wait_for_reg_bit(chstat_reg, OMAP2_MCSPI_CHSTAT_RXS) < 0) { dev_err(&spi->dev, @@ -628,10 +625,8 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer) } *rx++ = __raw_readl(rx_reg); -#ifdef VERBOSE - dev_dbg(&spi->dev, "read-%d %08x\n", + dev_vdbg(&spi->dev, "read-%d %08x\n", word_len, *(rx - 1)); -#endif } } while (c); } @@ -644,6 +639,12 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer) } else if (mcspi_wait_for_reg_bit(chstat_reg, OMAP2_MCSPI_CHSTAT_EOT) < 0) dev_err(&spi->dev, "EOT timed out\n"); + + /* disable chan to purge rx datas received in TX_ONLY transfer, + * otherwise these rx datas will affect the direct following + * RX_ONLY transfer. + */ + omap2_mcspi_set_enable(spi, 0); } out: omap2_mcspi_set_enable(spi, 1); diff --git a/drivers/spi/orion_spi.c b/drivers/spi/orion_spi.c index 3aea50da7b29..0b677dc041ad 100644 --- a/drivers/spi/orion_spi.c +++ b/drivers/spi/orion_spi.c @@ -404,7 +404,7 @@ static int orion_spi_transfer(struct spi_device *spi, struct spi_message *m) goto msg_rejected; } - if ((t != NULL) && t->bits_per_word) + if (t->bits_per_word) bits_per_word = t->bits_per_word; if ((bits_per_word != 8) && (bits_per_word != 16)) { @@ -415,7 +415,7 @@ static int orion_spi_transfer(struct spi_device *spi, struct spi_message *m) goto msg_rejected; } /*make sure buffer length is even when working in 16 bit mode*/ - if ((t != NULL) && (t->bits_per_word == 16) && (t->len & 1)) { + if ((t->bits_per_word == 16) && (t->len & 1)) { dev_err(&spi->dev, "message rejected : " "odd data length (%d) while in 16 bit mode\n", diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c index 10a6dc3d37ac..ab483a0ec6d0 100644 --- a/drivers/spi/spi_bfin5xx.c +++ b/drivers/spi/spi_bfin5xx.c @@ -1,7 +1,7 @@ /* * Blackfin On-Chip SPI Driver * - * Copyright 2004-2007 Analog Devices Inc. + * Copyright 2004-2010 Analog Devices Inc. * * Enter bugs at http://blackfin.uclinux.org/ * @@ -41,13 +41,16 @@ MODULE_LICENSE("GPL"); #define RUNNING_STATE ((void *)1) #define DONE_STATE ((void *)2) #define ERROR_STATE ((void *)-1) -#define QUEUE_RUNNING 0 -#define QUEUE_STOPPED 1 -/* Value to send if no TX value is supplied */ -#define SPI_IDLE_TXVAL 0x0000 +struct bfin_spi_master_data; -struct driver_data { +struct bfin_spi_transfer_ops { + void (*write) (struct bfin_spi_master_data *); + void (*read) (struct bfin_spi_master_data *); + void (*duplex) (struct bfin_spi_master_data *); +}; + +struct bfin_spi_master_data { /* Driver model hookup */ struct platform_device *pdev; @@ -69,7 +72,7 @@ struct driver_data { spinlock_t lock; struct list_head queue; int busy; - int run; + bool running; /* Message Transfer pump */ struct tasklet_struct pump_transfers; @@ -77,7 +80,7 @@ struct driver_data { /* Current message transfer state info */ struct spi_message *cur_msg; struct spi_transfer *cur_transfer; - struct chip_data *cur_chip; + struct bfin_spi_slave_data *cur_chip; size_t len_in_bytes; size_t len; void *tx; @@ -92,38 +95,37 @@ struct driver_data { dma_addr_t rx_dma; dma_addr_t tx_dma; + int irq_requested; + int spi_irq; + size_t rx_map_len; size_t tx_map_len; u8 n_bytes; + u16 ctrl_reg; + u16 flag_reg; + int cs_change; - void (*write) (struct driver_data *); - void (*read) (struct driver_data *); - void (*duplex) (struct driver_data *); + const struct bfin_spi_transfer_ops *ops; }; -struct chip_data { +struct bfin_spi_slave_data { u16 ctl_reg; u16 baud; u16 flag; u8 chip_select_num; - u8 n_bytes; - u8 width; /* 0 or 1 */ u8 enable_dma; - u8 bits_per_word; /* 8 or 16 */ - u8 cs_change_per_word; u16 cs_chg_udelay; /* Some devices require > 255usec delay */ u32 cs_gpio; u16 idle_tx_val; - void (*write) (struct driver_data *); - void (*read) (struct driver_data *); - void (*duplex) (struct driver_data *); + u8 pio_interrupt; /* use spi data irq */ + const struct bfin_spi_transfer_ops *ops; }; #define DEFINE_SPI_REG(reg, off) \ -static inline u16 read_##reg(struct driver_data *drv_data) \ +static inline u16 read_##reg(struct bfin_spi_master_data *drv_data) \ { return bfin_read16(drv_data->regs_base + off); } \ -static inline void write_##reg(struct driver_data *drv_data, u16 v) \ +static inline void write_##reg(struct bfin_spi_master_data *drv_data, u16 v) \ { bfin_write16(drv_data->regs_base + off, v); } DEFINE_SPI_REG(CTRL, 0x00) @@ -134,7 +136,7 @@ DEFINE_SPI_REG(RDBR, 0x10) DEFINE_SPI_REG(BAUD, 0x14) DEFINE_SPI_REG(SHAW, 0x18) -static void bfin_spi_enable(struct driver_data *drv_data) +static void bfin_spi_enable(struct bfin_spi_master_data *drv_data) { u16 cr; @@ -142,7 +144,7 @@ static void bfin_spi_enable(struct driver_data *drv_data) write_CTRL(drv_data, (cr | BIT_CTL_ENABLE)); } -static void bfin_spi_disable(struct driver_data *drv_data) +static void bfin_spi_disable(struct bfin_spi_master_data *drv_data) { u16 cr; @@ -165,7 +167,7 @@ static u16 hz_to_spi_baud(u32 speed_hz) return spi_baud; } -static int bfin_spi_flush(struct driver_data *drv_data) +static int bfin_spi_flush(struct bfin_spi_master_data *drv_data) { unsigned long limit = loops_per_jiffy << 1; @@ -179,13 +181,12 @@ static int bfin_spi_flush(struct driver_data *drv_data) } /* Chip select operation functions for cs_change flag */ -static void bfin_spi_cs_active(struct driver_data *drv_data, struct chip_data *chip) +static void bfin_spi_cs_active(struct bfin_spi_master_data *drv_data, struct bfin_spi_slave_data *chip) { - if (likely(chip->chip_select_num)) { + if (likely(chip->chip_select_num < MAX_CTRL_CS)) { u16 flag = read_FLAG(drv_data); - flag |= chip->flag; - flag &= ~(chip->flag << 8); + flag &= ~chip->flag; write_FLAG(drv_data, flag); } else { @@ -193,13 +194,13 @@ static void bfin_spi_cs_active(struct driver_data *drv_data, struct chip_data *c } } -static void bfin_spi_cs_deactive(struct driver_data *drv_data, struct chip_data *chip) +static void bfin_spi_cs_deactive(struct bfin_spi_master_data *drv_data, + struct bfin_spi_slave_data *chip) { - if (likely(chip->chip_select_num)) { + if (likely(chip->chip_select_num < MAX_CTRL_CS)) { u16 flag = read_FLAG(drv_data); - flag &= ~chip->flag; - flag |= (chip->flag << 8); + flag |= chip->flag; write_FLAG(drv_data, flag); } else { @@ -211,16 +212,43 @@ static void bfin_spi_cs_deactive(struct driver_data *drv_data, struct chip_data udelay(chip->cs_chg_udelay); } +/* enable or disable the pin muxed by GPIO and SPI CS to work as SPI CS */ +static inline void bfin_spi_cs_enable(struct bfin_spi_master_data *drv_data, + struct bfin_spi_slave_data *chip) +{ + if (chip->chip_select_num < MAX_CTRL_CS) { + u16 flag = read_FLAG(drv_data); + + flag |= (chip->flag >> 8); + + write_FLAG(drv_data, flag); + } +} + +static inline void bfin_spi_cs_disable(struct bfin_spi_master_data *drv_data, + struct bfin_spi_slave_data *chip) +{ + if (chip->chip_select_num < MAX_CTRL_CS) { + u16 flag = read_FLAG(drv_data); + + flag &= ~(chip->flag >> 8); + + write_FLAG(drv_data, flag); + } +} + /* stop controller and re-config current chip*/ -static void bfin_spi_restore_state(struct driver_data *drv_data) +static void bfin_spi_restore_state(struct bfin_spi_master_data *drv_data) { - struct chip_data *chip = drv_data->cur_chip; + struct bfin_spi_slave_data *chip = drv_data->cur_chip; /* Clear status and disable clock */ write_STAT(drv_data, BIT_STAT_CLR); bfin_spi_disable(drv_data); dev_dbg(&drv_data->pdev->dev, "restoring spi ctl state\n"); + SSYNC(); + /* Load the registers */ write_CTRL(drv_data, chip->ctl_reg); write_BAUD(drv_data, chip->baud); @@ -230,49 +258,12 @@ static void bfin_spi_restore_state(struct driver_data *drv_data) } /* used to kick off transfer in rx mode and read unwanted RX data */ -static inline void bfin_spi_dummy_read(struct driver_data *drv_data) +static inline void bfin_spi_dummy_read(struct bfin_spi_master_data *drv_data) { (void) read_RDBR(drv_data); } -static void bfin_spi_null_writer(struct driver_data *drv_data) -{ - u8 n_bytes = drv_data->n_bytes; - u16 tx_val = drv_data->cur_chip->idle_tx_val; - - /* clear RXS (we check for RXS inside the loop) */ - bfin_spi_dummy_read(drv_data); - - while (drv_data->tx < drv_data->tx_end) { - write_TDBR(drv_data, tx_val); - drv_data->tx += n_bytes; - /* wait until transfer finished. - checking SPIF or TXS may not guarantee transfer completion */ - while (!(read_STAT(drv_data) & BIT_STAT_RXS)) - cpu_relax(); - /* discard RX data and clear RXS */ - bfin_spi_dummy_read(drv_data); - } -} - -static void bfin_spi_null_reader(struct driver_data *drv_data) -{ - u8 n_bytes = drv_data->n_bytes; - u16 tx_val = drv_data->cur_chip->idle_tx_val; - - /* discard old RX data and clear RXS */ - bfin_spi_dummy_read(drv_data); - - while (drv_data->rx < drv_data->rx_end) { - write_TDBR(drv_data, tx_val); - drv_data->rx += n_bytes; - while (!(read_STAT(drv_data) & BIT_STAT_RXS)) - cpu_relax(); - bfin_spi_dummy_read(drv_data); - } -} - -static void bfin_spi_u8_writer(struct driver_data *drv_data) +static void bfin_spi_u8_writer(struct bfin_spi_master_data *drv_data) { /* clear RXS (we check for RXS inside the loop) */ bfin_spi_dummy_read(drv_data); @@ -288,25 +279,7 @@ static void bfin_spi_u8_writer(struct driver_data *drv_data) } } -static void bfin_spi_u8_cs_chg_writer(struct driver_data *drv_data) -{ - struct chip_data *chip = drv_data->cur_chip; - - /* clear RXS (we check for RXS inside the loop) */ - bfin_spi_dummy_read(drv_data); - - while (drv_data->tx < drv_data->tx_end) { - bfin_spi_cs_active(drv_data, chip); - write_TDBR(drv_data, (*(u8 *) (drv_data->tx++))); - /* make sure transfer finished before deactiving CS */ - while (!(read_STAT(drv_data) & BIT_STAT_RXS)) - cpu_relax(); - bfin_spi_dummy_read(drv_data); - bfin_spi_cs_deactive(drv_data, chip); - } -} - -static void bfin_spi_u8_reader(struct driver_data *drv_data) +static void bfin_spi_u8_reader(struct bfin_spi_master_data *drv_data) { u16 tx_val = drv_data->cur_chip->idle_tx_val; @@ -321,25 +294,7 @@ static void bfin_spi_u8_reader(struct driver_data *drv_data) } } -static void bfin_spi_u8_cs_chg_reader(struct driver_data *drv_data) -{ - struct chip_data *chip = drv_data->cur_chip; - u16 tx_val = chip->idle_tx_val; - - /* discard old RX data and clear RXS */ - bfin_spi_dummy_read(drv_data); - - while (drv_data->rx < drv_data->rx_end) { - bfin_spi_cs_active(drv_data, chip); - write_TDBR(drv_data, tx_val); - while (!(read_STAT(drv_data) & BIT_STAT_RXS)) - cpu_relax(); - *(u8 *) (drv_data->rx++) = read_RDBR(drv_data); - bfin_spi_cs_deactive(drv_data, chip); - } -} - -static void bfin_spi_u8_duplex(struct driver_data *drv_data) +static void bfin_spi_u8_duplex(struct bfin_spi_master_data *drv_data) { /* discard old RX data and clear RXS */ bfin_spi_dummy_read(drv_data); @@ -352,24 +307,13 @@ static void bfin_spi_u8_duplex(struct driver_data *drv_data) } } -static void bfin_spi_u8_cs_chg_duplex(struct driver_data *drv_data) -{ - struct chip_data *chip = drv_data->cur_chip; - - /* discard old RX data and clear RXS */ - bfin_spi_dummy_read(drv_data); - - while (drv_data->rx < drv_data->rx_end) { - bfin_spi_cs_active(drv_data, chip); - write_TDBR(drv_data, (*(u8 *) (drv_data->tx++))); - while (!(read_STAT(drv_data) & BIT_STAT_RXS)) - cpu_relax(); - *(u8 *) (drv_data->rx++) = read_RDBR(drv_data); - bfin_spi_cs_deactive(drv_data, chip); - } -} +static const struct bfin_spi_transfer_ops bfin_bfin_spi_transfer_ops_u8 = { + .write = bfin_spi_u8_writer, + .read = bfin_spi_u8_reader, + .duplex = bfin_spi_u8_duplex, +}; -static void bfin_spi_u16_writer(struct driver_data *drv_data) +static void bfin_spi_u16_writer(struct bfin_spi_master_data *drv_data) { /* clear RXS (we check for RXS inside the loop) */ bfin_spi_dummy_read(drv_data); @@ -386,26 +330,7 @@ static void bfin_spi_u16_writer(struct driver_data *drv_data) } } -static void bfin_spi_u16_cs_chg_writer(struct driver_data *drv_data) -{ - struct chip_data *chip = drv_data->cur_chip; - - /* clear RXS (we check for RXS inside the loop) */ - bfin_spi_dummy_read(drv_data); - - while (drv_data->tx < drv_data->tx_end) { - bfin_spi_cs_active(drv_data, chip); - write_TDBR(drv_data, (*(u16 *) (drv_data->tx))); - drv_data->tx += 2; - /* make sure transfer finished before deactiving CS */ - while (!(read_STAT(drv_data) & BIT_STAT_RXS)) - cpu_relax(); - bfin_spi_dummy_read(drv_data); - bfin_spi_cs_deactive(drv_data, chip); - } -} - -static void bfin_spi_u16_reader(struct driver_data *drv_data) +static void bfin_spi_u16_reader(struct bfin_spi_master_data *drv_data) { u16 tx_val = drv_data->cur_chip->idle_tx_val; @@ -421,26 +346,7 @@ static void bfin_spi_u16_reader(struct driver_data *drv_data) } } -static void bfin_spi_u16_cs_chg_reader(struct driver_data *drv_data) -{ - struct chip_data *chip = drv_data->cur_chip; - u16 tx_val = chip->idle_tx_val; - - /* discard old RX data and clear RXS */ - bfin_spi_dummy_read(drv_data); - - while (drv_data->rx < drv_data->rx_end) { - bfin_spi_cs_active(drv_data, chip); - write_TDBR(drv_data, tx_val); - while (!(read_STAT(drv_data) & BIT_STAT_RXS)) - cpu_relax(); - *(u16 *) (drv_data->rx) = read_RDBR(drv_data); - drv_data->rx += 2; - bfin_spi_cs_deactive(drv_data, chip); - } -} - -static void bfin_spi_u16_duplex(struct driver_data *drv_data) +static void bfin_spi_u16_duplex(struct bfin_spi_master_data *drv_data) { /* discard old RX data and clear RXS */ bfin_spi_dummy_read(drv_data); @@ -455,27 +361,14 @@ static void bfin_spi_u16_duplex(struct driver_data *drv_data) } } -static void bfin_spi_u16_cs_chg_duplex(struct driver_data *drv_data) -{ - struct chip_data *chip = drv_data->cur_chip; - - /* discard old RX data and clear RXS */ - bfin_spi_dummy_read(drv_data); - - while (drv_data->rx < drv_data->rx_end) { - bfin_spi_cs_active(drv_data, chip); - write_TDBR(drv_data, (*(u16 *) (drv_data->tx))); - drv_data->tx += 2; - while (!(read_STAT(drv_data) & BIT_STAT_RXS)) - cpu_relax(); - *(u16 *) (drv_data->rx) = read_RDBR(drv_data); - drv_data->rx += 2; - bfin_spi_cs_deactive(drv_data, chip); - } -} +static const struct bfin_spi_transfer_ops bfin_bfin_spi_transfer_ops_u16 = { + .write = bfin_spi_u16_writer, + .read = bfin_spi_u16_reader, + .duplex = bfin_spi_u16_duplex, +}; -/* test if ther is more transfer to be done */ -static void *bfin_spi_next_transfer(struct driver_data *drv_data) +/* test if there is more transfer to be done */ +static void *bfin_spi_next_transfer(struct bfin_spi_master_data *drv_data) { struct spi_message *msg = drv_data->cur_msg; struct spi_transfer *trans = drv_data->cur_transfer; @@ -494,9 +387,9 @@ static void *bfin_spi_next_transfer(struct driver_data *drv_data) * caller already set message->status; * dma and pio irqs are blocked give finished message back */ -static void bfin_spi_giveback(struct driver_data *drv_data) +static void bfin_spi_giveback(struct bfin_spi_master_data *drv_data) { - struct chip_data *chip = drv_data->cur_chip; + struct bfin_spi_slave_data *chip = drv_data->cur_chip; struct spi_transfer *last_transfer; unsigned long flags; struct spi_message *msg; @@ -525,10 +418,83 @@ static void bfin_spi_giveback(struct driver_data *drv_data) msg->complete(msg->context); } +/* spi data irq handler */ +static irqreturn_t bfin_spi_pio_irq_handler(int irq, void *dev_id) +{ + struct bfin_spi_master_data *drv_data = dev_id; + struct bfin_spi_slave_data *chip = drv_data->cur_chip; + struct spi_message *msg = drv_data->cur_msg; + int n_bytes = drv_data->n_bytes; + + /* wait until transfer finished. */ + while (!(read_STAT(drv_data) & BIT_STAT_RXS)) + cpu_relax(); + + if ((drv_data->tx && drv_data->tx >= drv_data->tx_end) || + (drv_data->rx && drv_data->rx >= (drv_data->rx_end - n_bytes))) { + /* last read */ + if (drv_data->rx) { + dev_dbg(&drv_data->pdev->dev, "last read\n"); + if (n_bytes == 2) + *(u16 *) (drv_data->rx) = read_RDBR(drv_data); + else if (n_bytes == 1) + *(u8 *) (drv_data->rx) = read_RDBR(drv_data); + drv_data->rx += n_bytes; + } + + msg->actual_length += drv_data->len_in_bytes; + if (drv_data->cs_change) + bfin_spi_cs_deactive(drv_data, chip); + /* Move to next transfer */ + msg->state = bfin_spi_next_transfer(drv_data); + + disable_irq_nosync(drv_data->spi_irq); + + /* Schedule transfer tasklet */ + tasklet_schedule(&drv_data->pump_transfers); + return IRQ_HANDLED; + } + + if (drv_data->rx && drv_data->tx) { + /* duplex */ + dev_dbg(&drv_data->pdev->dev, "duplex: write_TDBR\n"); + if (drv_data->n_bytes == 2) { + *(u16 *) (drv_data->rx) = read_RDBR(drv_data); + write_TDBR(drv_data, (*(u16 *) (drv_data->tx))); + } else if (drv_data->n_bytes == 1) { + *(u8 *) (drv_data->rx) = read_RDBR(drv_data); + write_TDBR(drv_data, (*(u8 *) (drv_data->tx))); + } + } else if (drv_data->rx) { + /* read */ + dev_dbg(&drv_data->pdev->dev, "read: write_TDBR\n"); + if (drv_data->n_bytes == 2) + *(u16 *) (drv_data->rx) = read_RDBR(drv_data); + else if (drv_data->n_bytes == 1) + *(u8 *) (drv_data->rx) = read_RDBR(drv_data); + write_TDBR(drv_data, chip->idle_tx_val); + } else if (drv_data->tx) { + /* write */ + dev_dbg(&drv_data->pdev->dev, "write: write_TDBR\n"); + bfin_spi_dummy_read(drv_data); + if (drv_data->n_bytes == 2) + write_TDBR(drv_data, (*(u16 *) (drv_data->tx))); + else if (drv_data->n_bytes == 1) + write_TDBR(drv_data, (*(u8 *) (drv_data->tx))); + } + + if (drv_data->tx) + drv_data->tx += n_bytes; + if (drv_data->rx) + drv_data->rx += n_bytes; + + return IRQ_HANDLED; +} + static irqreturn_t bfin_spi_dma_irq_handler(int irq, void *dev_id) { - struct driver_data *drv_data = dev_id; - struct chip_data *chip = drv_data->cur_chip; + struct bfin_spi_master_data *drv_data = dev_id; + struct bfin_spi_slave_data *chip = drv_data->cur_chip; struct spi_message *msg = drv_data->cur_msg; unsigned long timeout; unsigned short dmastat = get_dma_curr_irqstat(drv_data->dma_channel); @@ -540,10 +506,6 @@ static irqreturn_t bfin_spi_dma_irq_handler(int irq, void *dev_id) clear_dma_irqstat(drv_data->dma_channel); - /* Wait for DMA to complete */ - while (get_dma_curr_irqstat(drv_data->dma_channel) & DMA_RUN) - cpu_relax(); - /* * wait for the last transaction shifted out. HRM states: * at this point there may still be data in the SPI DMA FIFO waiting @@ -551,8 +513,8 @@ static irqreturn_t bfin_spi_dma_irq_handler(int irq, void *dev_id) * register until it goes low for 2 successive reads */ if (drv_data->tx != NULL) { - while ((read_STAT(drv_data) & TXS) || - (read_STAT(drv_data) & TXS)) + while ((read_STAT(drv_data) & BIT_STAT_TXS) || + (read_STAT(drv_data) & BIT_STAT_TXS)) cpu_relax(); } @@ -561,14 +523,14 @@ static irqreturn_t bfin_spi_dma_irq_handler(int irq, void *dev_id) dmastat, read_STAT(drv_data)); timeout = jiffies + HZ; - while (!(read_STAT(drv_data) & SPIF)) + while (!(read_STAT(drv_data) & BIT_STAT_SPIF)) if (!time_before(jiffies, timeout)) { dev_warn(&drv_data->pdev->dev, "timeout waiting for SPIF"); break; } else cpu_relax(); - if ((dmastat & DMA_ERR) && (spistat & RBSY)) { + if ((dmastat & DMA_ERR) && (spistat & BIT_STAT_RBSY)) { msg->state = ERROR_STATE; dev_err(&drv_data->pdev->dev, "dma receive: fifo/buffer overflow\n"); } else { @@ -588,20 +550,20 @@ static irqreturn_t bfin_spi_dma_irq_handler(int irq, void *dev_id) dev_dbg(&drv_data->pdev->dev, "disable dma channel irq%d\n", drv_data->dma_channel); - dma_disable_irq(drv_data->dma_channel); + dma_disable_irq_nosync(drv_data->dma_channel); return IRQ_HANDLED; } static void bfin_spi_pump_transfers(unsigned long data) { - struct driver_data *drv_data = (struct driver_data *)data; + struct bfin_spi_master_data *drv_data = (struct bfin_spi_master_data *)data; struct spi_message *message = NULL; struct spi_transfer *transfer = NULL; struct spi_transfer *previous = NULL; - struct chip_data *chip = NULL; - u8 width; - u16 cr, dma_width, dma_config; + struct bfin_spi_slave_data *chip = NULL; + unsigned int bits_per_word; + u16 cr, cr_width, dma_width, dma_config; u32 tranf_success = 1; u8 full_duplex = 0; @@ -639,7 +601,7 @@ static void bfin_spi_pump_transfers(unsigned long data) udelay(previous->delay_usecs); } - /* Setup the transfer state based on the type of transfer */ + /* Flush any existing transfers that may be sitting in the hardware */ if (bfin_spi_flush(drv_data) == 0) { dev_err(&drv_data->pdev->dev, "pump_transfers: flush failed\n"); message->status = -EIO; @@ -679,52 +641,31 @@ static void bfin_spi_pump_transfers(unsigned long data) drv_data->cs_change = transfer->cs_change; /* Bits per word setup */ - switch (transfer->bits_per_word) { - case 8: + bits_per_word = transfer->bits_per_word ? : message->spi->bits_per_word; + if (bits_per_word == 8) { drv_data->n_bytes = 1; - width = CFG_SPI_WORDSIZE8; - drv_data->read = chip->cs_change_per_word ? - bfin_spi_u8_cs_chg_reader : bfin_spi_u8_reader; - drv_data->write = chip->cs_change_per_word ? - bfin_spi_u8_cs_chg_writer : bfin_spi_u8_writer; - drv_data->duplex = chip->cs_change_per_word ? - bfin_spi_u8_cs_chg_duplex : bfin_spi_u8_duplex; - break; - - case 16: + drv_data->len = transfer->len; + cr_width = 0; + drv_data->ops = &bfin_bfin_spi_transfer_ops_u8; + } else if (bits_per_word == 16) { drv_data->n_bytes = 2; - width = CFG_SPI_WORDSIZE16; - drv_data->read = chip->cs_change_per_word ? - bfin_spi_u16_cs_chg_reader : bfin_spi_u16_reader; - drv_data->write = chip->cs_change_per_word ? - bfin_spi_u16_cs_chg_writer : bfin_spi_u16_writer; - drv_data->duplex = chip->cs_change_per_word ? - bfin_spi_u16_cs_chg_duplex : bfin_spi_u16_duplex; - break; - - default: - /* No change, the same as default setting */ - drv_data->n_bytes = chip->n_bytes; - width = chip->width; - drv_data->write = drv_data->tx ? chip->write : bfin_spi_null_writer; - drv_data->read = drv_data->rx ? chip->read : bfin_spi_null_reader; - drv_data->duplex = chip->duplex ? chip->duplex : bfin_spi_null_writer; - break; - } - cr = (read_CTRL(drv_data) & (~BIT_CTL_TIMOD)); - cr |= (width << 8); - write_CTRL(drv_data, cr); - - if (width == CFG_SPI_WORDSIZE16) { drv_data->len = (transfer->len) >> 1; + cr_width = BIT_CTL_WORDSIZE; + drv_data->ops = &bfin_bfin_spi_transfer_ops_u16; } else { - drv_data->len = transfer->len; + dev_err(&drv_data->pdev->dev, "transfer: unsupported bits_per_word\n"); + message->status = -EINVAL; + bfin_spi_giveback(drv_data); + return; } + cr = read_CTRL(drv_data) & ~(BIT_CTL_TIMOD | BIT_CTL_WORDSIZE); + cr |= cr_width; + write_CTRL(drv_data, cr); + dev_dbg(&drv_data->pdev->dev, - "transfer: drv_data->write is %p, chip->write is %p, null_wr is %p\n", - drv_data->write, chip->write, bfin_spi_null_writer); + "transfer: drv_data->ops is %p, chip->ops is %p, u8_ops is %p\n", + drv_data->ops, chip->ops, &bfin_bfin_spi_transfer_ops_u8); - /* speed and width has been set on per message */ message->state = RUNNING_STATE; dma_config = 0; @@ -735,13 +676,11 @@ static void bfin_spi_pump_transfers(unsigned long data) write_BAUD(drv_data, chip->baud); write_STAT(drv_data, BIT_STAT_CLR); - cr = (read_CTRL(drv_data) & (~BIT_CTL_TIMOD)); - if (drv_data->cs_change) - bfin_spi_cs_active(drv_data, chip); + bfin_spi_cs_active(drv_data, chip); dev_dbg(&drv_data->pdev->dev, "now pumping a transfer: width is %d, len is %d\n", - width, transfer->len); + cr_width, transfer->len); /* * Try to map dma buffer and do a dma transfer. If successful use, @@ -760,7 +699,7 @@ static void bfin_spi_pump_transfers(unsigned long data) /* config dma channel */ dev_dbg(&drv_data->pdev->dev, "doing dma transfer\n"); set_dma_x_count(drv_data->dma_channel, drv_data->len); - if (width == CFG_SPI_WORDSIZE16) { + if (cr_width == BIT_CTL_WORDSIZE) { set_dma_x_modify(drv_data->dma_channel, 2); dma_width = WDSIZE_16; } else { @@ -846,73 +785,100 @@ static void bfin_spi_pump_transfers(unsigned long data) dma_enable_irq(drv_data->dma_channel); local_irq_restore(flags); - } else { - /* IO mode write then read */ - dev_dbg(&drv_data->pdev->dev, "doing IO transfer\n"); - - /* we always use SPI_WRITE mode. SPI_READ mode - seems to have problems with setting up the - output value in TDBR prior to the transfer. */ - write_CTRL(drv_data, (cr | CFG_SPI_WRITE)); - - if (full_duplex) { - /* full duplex mode */ - BUG_ON((drv_data->tx_end - drv_data->tx) != - (drv_data->rx_end - drv_data->rx)); - dev_dbg(&drv_data->pdev->dev, - "IO duplex: cr is 0x%x\n", cr); - - drv_data->duplex(drv_data); + return; + } - if (drv_data->tx != drv_data->tx_end) - tranf_success = 0; - } else if (drv_data->tx != NULL) { - /* write only half duplex */ - dev_dbg(&drv_data->pdev->dev, - "IO write: cr is 0x%x\n", cr); + /* + * We always use SPI_WRITE mode (transfer starts with TDBR write). + * SPI_READ mode (transfer starts with RDBR read) seems to have + * problems with setting up the output value in TDBR prior to the + * start of the transfer. + */ + write_CTRL(drv_data, cr | BIT_CTL_TXMOD); - drv_data->write(drv_data); + if (chip->pio_interrupt) { + /* SPI irq should have been disabled by now */ - if (drv_data->tx != drv_data->tx_end) - tranf_success = 0; - } else if (drv_data->rx != NULL) { - /* read only half duplex */ - dev_dbg(&drv_data->pdev->dev, - "IO read: cr is 0x%x\n", cr); + /* discard old RX data and clear RXS */ + bfin_spi_dummy_read(drv_data); - drv_data->read(drv_data); - if (drv_data->rx != drv_data->rx_end) - tranf_success = 0; + /* start transfer */ + if (drv_data->tx == NULL) + write_TDBR(drv_data, chip->idle_tx_val); + else { + if (bits_per_word == 8) + write_TDBR(drv_data, (*(u8 *) (drv_data->tx))); + else + write_TDBR(drv_data, (*(u16 *) (drv_data->tx))); + drv_data->tx += drv_data->n_bytes; } - if (!tranf_success) { - dev_dbg(&drv_data->pdev->dev, - "IO write error!\n"); - message->state = ERROR_STATE; - } else { - /* Update total byte transfered */ - message->actual_length += drv_data->len_in_bytes; - /* Move to next transfer of this msg */ - message->state = bfin_spi_next_transfer(drv_data); - if (drv_data->cs_change) - bfin_spi_cs_deactive(drv_data, chip); - } - /* Schedule next transfer tasklet */ - tasklet_schedule(&drv_data->pump_transfers); + /* once TDBR is empty, interrupt is triggered */ + enable_irq(drv_data->spi_irq); + return; + } + + /* IO mode */ + dev_dbg(&drv_data->pdev->dev, "doing IO transfer\n"); + + if (full_duplex) { + /* full duplex mode */ + BUG_ON((drv_data->tx_end - drv_data->tx) != + (drv_data->rx_end - drv_data->rx)); + dev_dbg(&drv_data->pdev->dev, + "IO duplex: cr is 0x%x\n", cr); + + drv_data->ops->duplex(drv_data); + + if (drv_data->tx != drv_data->tx_end) + tranf_success = 0; + } else if (drv_data->tx != NULL) { + /* write only half duplex */ + dev_dbg(&drv_data->pdev->dev, + "IO write: cr is 0x%x\n", cr); + + drv_data->ops->write(drv_data); + + if (drv_data->tx != drv_data->tx_end) + tranf_success = 0; + } else if (drv_data->rx != NULL) { + /* read only half duplex */ + dev_dbg(&drv_data->pdev->dev, + "IO read: cr is 0x%x\n", cr); + + drv_data->ops->read(drv_data); + if (drv_data->rx != drv_data->rx_end) + tranf_success = 0; + } + + if (!tranf_success) { + dev_dbg(&drv_data->pdev->dev, + "IO write error!\n"); + message->state = ERROR_STATE; + } else { + /* Update total byte transfered */ + message->actual_length += drv_data->len_in_bytes; + /* Move to next transfer of this msg */ + message->state = bfin_spi_next_transfer(drv_data); + if (drv_data->cs_change) + bfin_spi_cs_deactive(drv_data, chip); } + + /* Schedule next transfer tasklet */ + tasklet_schedule(&drv_data->pump_transfers); } /* pop a msg from queue and kick off real transfer */ static void bfin_spi_pump_messages(struct work_struct *work) { - struct driver_data *drv_data; + struct bfin_spi_master_data *drv_data; unsigned long flags; - drv_data = container_of(work, struct driver_data, pump_messages); + drv_data = container_of(work, struct bfin_spi_master_data, pump_messages); /* Lock queue and check for queue work */ spin_lock_irqsave(&drv_data->lock, flags); - if (list_empty(&drv_data->queue) || drv_data->run == QUEUE_STOPPED) { + if (list_empty(&drv_data->queue) || !drv_data->running) { /* pumper kicked off but no work to do */ drv_data->busy = 0; spin_unlock_irqrestore(&drv_data->lock, flags); @@ -962,12 +928,12 @@ static void bfin_spi_pump_messages(struct work_struct *work) */ static int bfin_spi_transfer(struct spi_device *spi, struct spi_message *msg) { - struct driver_data *drv_data = spi_master_get_devdata(spi->master); + struct bfin_spi_master_data *drv_data = spi_master_get_devdata(spi->master); unsigned long flags; spin_lock_irqsave(&drv_data->lock, flags); - if (drv_data->run == QUEUE_STOPPED) { + if (!drv_data->running) { spin_unlock_irqrestore(&drv_data->lock, flags); return -ESHUTDOWN; } @@ -979,7 +945,7 @@ static int bfin_spi_transfer(struct spi_device *spi, struct spi_message *msg) dev_dbg(&spi->dev, "adding an msg in transfer() \n"); list_add_tail(&msg->queue, &drv_data->queue); - if (drv_data->run == QUEUE_RUNNING && !drv_data->busy) + if (drv_data->running && !drv_data->busy) queue_work(drv_data->workqueue, &drv_data->pump_messages); spin_unlock_irqrestore(&drv_data->lock, flags); @@ -1003,147 +969,184 @@ static u16 ssel[][MAX_SPI_SSEL] = { P_SPI2_SSEL6, P_SPI2_SSEL7}, }; -/* first setup for new devices */ +/* setup for devices (may be called multiple times -- not just first setup) */ static int bfin_spi_setup(struct spi_device *spi) { - struct bfin5xx_spi_chip *chip_info = NULL; - struct chip_data *chip; - struct driver_data *drv_data = spi_master_get_devdata(spi->master); - int ret; - - if (spi->bits_per_word != 8 && spi->bits_per_word != 16) - return -EINVAL; + struct bfin5xx_spi_chip *chip_info; + struct bfin_spi_slave_data *chip = NULL; + struct bfin_spi_master_data *drv_data = spi_master_get_devdata(spi->master); + u16 bfin_ctl_reg; + int ret = -EINVAL; /* Only alloc (or use chip_info) on first setup */ + chip_info = NULL; chip = spi_get_ctldata(spi); if (chip == NULL) { - chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL); - if (!chip) - return -ENOMEM; + chip = kzalloc(sizeof(*chip), GFP_KERNEL); + if (!chip) { + dev_err(&spi->dev, "cannot allocate chip data\n"); + ret = -ENOMEM; + goto error; + } chip->enable_dma = 0; chip_info = spi->controller_data; } + /* Let people set non-standard bits directly */ + bfin_ctl_reg = BIT_CTL_OPENDRAIN | BIT_CTL_EMISO | + BIT_CTL_PSSE | BIT_CTL_GM | BIT_CTL_SZ; + /* chip_info isn't always needed */ if (chip_info) { /* Make sure people stop trying to set fields via ctl_reg * when they should actually be using common SPI framework. - * Currently we let through: WOM EMISO PSSE GM SZ TIMOD. + * Currently we let through: WOM EMISO PSSE GM SZ. * Not sure if a user actually needs/uses any of these, * but let's assume (for now) they do. */ - if (chip_info->ctl_reg & (SPE|MSTR|CPOL|CPHA|LSBF|SIZE)) { + if (chip_info->ctl_reg & ~bfin_ctl_reg) { dev_err(&spi->dev, "do not set bits in ctl_reg " "that the SPI framework manages\n"); - return -EINVAL; + goto error; } - chip->enable_dma = chip_info->enable_dma != 0 && drv_data->master_info->enable_dma; chip->ctl_reg = chip_info->ctl_reg; - chip->bits_per_word = chip_info->bits_per_word; - chip->cs_change_per_word = chip_info->cs_change_per_word; chip->cs_chg_udelay = chip_info->cs_chg_udelay; - chip->cs_gpio = chip_info->cs_gpio; chip->idle_tx_val = chip_info->idle_tx_val; + chip->pio_interrupt = chip_info->pio_interrupt; + spi->bits_per_word = chip_info->bits_per_word; + } else { + /* force a default base state */ + chip->ctl_reg &= bfin_ctl_reg; + } + + if (spi->bits_per_word != 8 && spi->bits_per_word != 16) { + dev_err(&spi->dev, "%d bits_per_word is not supported\n", + spi->bits_per_word); + goto error; } /* translate common spi framework into our register */ + if (spi->mode & ~(SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST)) { + dev_err(&spi->dev, "unsupported spi modes detected\n"); + goto error; + } if (spi->mode & SPI_CPOL) - chip->ctl_reg |= CPOL; + chip->ctl_reg |= BIT_CTL_CPOL; if (spi->mode & SPI_CPHA) - chip->ctl_reg |= CPHA; + chip->ctl_reg |= BIT_CTL_CPHA; if (spi->mode & SPI_LSB_FIRST) - chip->ctl_reg |= LSBF; + chip->ctl_reg |= BIT_CTL_LSBF; /* we dont support running in slave mode (yet?) */ - chip->ctl_reg |= MSTR; + chip->ctl_reg |= BIT_CTL_MASTER; /* + * Notice: for blackfin, the speed_hz is the value of register + * SPI_BAUD, not the real baudrate + */ + chip->baud = hz_to_spi_baud(spi->max_speed_hz); + chip->chip_select_num = spi->chip_select; + if (chip->chip_select_num < MAX_CTRL_CS) { + if (!(spi->mode & SPI_CPHA)) + dev_warn(&spi->dev, "Warning: SPI CPHA not set:" + " Slave Select not under software control!\n" + " See Documentation/blackfin/bfin-spi-notes.txt"); + + chip->flag = (1 << spi->chip_select) << 8; + } else + chip->cs_gpio = chip->chip_select_num - MAX_CTRL_CS; + + if (chip->enable_dma && chip->pio_interrupt) { + dev_err(&spi->dev, "enable_dma is set, " + "do not set pio_interrupt\n"); + goto error; + } + /* * if any one SPI chip is registered and wants DMA, request the * DMA channel for it */ if (chip->enable_dma && !drv_data->dma_requested) { /* register dma irq handler */ - if (request_dma(drv_data->dma_channel, "BFIN_SPI_DMA") < 0) { - dev_dbg(&spi->dev, + ret = request_dma(drv_data->dma_channel, "BFIN_SPI_DMA"); + if (ret) { + dev_err(&spi->dev, "Unable to request BlackFin SPI DMA channel\n"); - return -ENODEV; + goto error; } - if (set_dma_callback(drv_data->dma_channel, - bfin_spi_dma_irq_handler, drv_data) < 0) { - dev_dbg(&spi->dev, "Unable to set dma callback\n"); - return -EPERM; + drv_data->dma_requested = 1; + + ret = set_dma_callback(drv_data->dma_channel, + bfin_spi_dma_irq_handler, drv_data); + if (ret) { + dev_err(&spi->dev, "Unable to set dma callback\n"); + goto error; } dma_disable_irq(drv_data->dma_channel); - drv_data->dma_requested = 1; } - /* - * Notice: for blackfin, the speed_hz is the value of register - * SPI_BAUD, not the real baudrate - */ - chip->baud = hz_to_spi_baud(spi->max_speed_hz); - chip->flag = 1 << (spi->chip_select); - chip->chip_select_num = spi->chip_select; + if (chip->pio_interrupt && !drv_data->irq_requested) { + ret = request_irq(drv_data->spi_irq, bfin_spi_pio_irq_handler, + IRQF_DISABLED, "BFIN_SPI", drv_data); + if (ret) { + dev_err(&spi->dev, "Unable to register spi IRQ\n"); + goto error; + } + drv_data->irq_requested = 1; + /* we use write mode, spi irq has to be disabled here */ + disable_irq(drv_data->spi_irq); + } - if (chip->chip_select_num == 0) { + if (chip->chip_select_num >= MAX_CTRL_CS) { ret = gpio_request(chip->cs_gpio, spi->modalias); if (ret) { - if (drv_data->dma_requested) - free_dma(drv_data->dma_channel); - return ret; + dev_err(&spi->dev, "gpio_request() error\n"); + goto pin_error; } gpio_direction_output(chip->cs_gpio, 1); } - switch (chip->bits_per_word) { - case 8: - chip->n_bytes = 1; - chip->width = CFG_SPI_WORDSIZE8; - chip->read = chip->cs_change_per_word ? - bfin_spi_u8_cs_chg_reader : bfin_spi_u8_reader; - chip->write = chip->cs_change_per_word ? - bfin_spi_u8_cs_chg_writer : bfin_spi_u8_writer; - chip->duplex = chip->cs_change_per_word ? - bfin_spi_u8_cs_chg_duplex : bfin_spi_u8_duplex; - break; - - case 16: - chip->n_bytes = 2; - chip->width = CFG_SPI_WORDSIZE16; - chip->read = chip->cs_change_per_word ? - bfin_spi_u16_cs_chg_reader : bfin_spi_u16_reader; - chip->write = chip->cs_change_per_word ? - bfin_spi_u16_cs_chg_writer : bfin_spi_u16_writer; - chip->duplex = chip->cs_change_per_word ? - bfin_spi_u16_cs_chg_duplex : bfin_spi_u16_duplex; - break; - - default: - dev_err(&spi->dev, "%d bits_per_word is not supported\n", - chip->bits_per_word); - if (chip_info) - kfree(chip); - return -ENODEV; - } - dev_dbg(&spi->dev, "setup spi chip %s, width is %d, dma is %d\n", - spi->modalias, chip->width, chip->enable_dma); + spi->modalias, spi->bits_per_word, chip->enable_dma); dev_dbg(&spi->dev, "ctl_reg is 0x%x, flag_reg is 0x%x\n", chip->ctl_reg, chip->flag); spi_set_ctldata(spi, chip); dev_dbg(&spi->dev, "chip select number is %d\n", chip->chip_select_num); - if ((chip->chip_select_num > 0) - && (chip->chip_select_num <= spi->master->num_chipselect)) - peripheral_request(ssel[spi->master->bus_num] - [chip->chip_select_num-1], spi->modalias); + if (chip->chip_select_num < MAX_CTRL_CS) { + ret = peripheral_request(ssel[spi->master->bus_num] + [chip->chip_select_num-1], spi->modalias); + if (ret) { + dev_err(&spi->dev, "peripheral_request() error\n"); + goto pin_error; + } + } + bfin_spi_cs_enable(drv_data, chip); bfin_spi_cs_deactive(drv_data, chip); return 0; + + pin_error: + if (chip->chip_select_num >= MAX_CTRL_CS) + gpio_free(chip->cs_gpio); + else + peripheral_free(ssel[spi->master->bus_num] + [chip->chip_select_num - 1]); + error: + if (chip) { + if (drv_data->dma_requested) + free_dma(drv_data->dma_channel); + drv_data->dma_requested = 0; + + kfree(chip); + /* prevent free 'chip' twice */ + spi_set_ctldata(spi, NULL); + } + + return ret; } /* @@ -1152,28 +1155,30 @@ static int bfin_spi_setup(struct spi_device *spi) */ static void bfin_spi_cleanup(struct spi_device *spi) { - struct chip_data *chip = spi_get_ctldata(spi); + struct bfin_spi_slave_data *chip = spi_get_ctldata(spi); + struct bfin_spi_master_data *drv_data = spi_master_get_devdata(spi->master); if (!chip) return; - if ((chip->chip_select_num > 0) - && (chip->chip_select_num <= spi->master->num_chipselect)) + if (chip->chip_select_num < MAX_CTRL_CS) { peripheral_free(ssel[spi->master->bus_num] [chip->chip_select_num-1]); - - if (chip->chip_select_num == 0) + bfin_spi_cs_disable(drv_data, chip); + } else gpio_free(chip->cs_gpio); kfree(chip); + /* prevent free 'chip' twice */ + spi_set_ctldata(spi, NULL); } -static inline int bfin_spi_init_queue(struct driver_data *drv_data) +static inline int bfin_spi_init_queue(struct bfin_spi_master_data *drv_data) { INIT_LIST_HEAD(&drv_data->queue); spin_lock_init(&drv_data->lock); - drv_data->run = QUEUE_STOPPED; + drv_data->running = false; drv_data->busy = 0; /* init transfer tasklet */ @@ -1190,18 +1195,18 @@ static inline int bfin_spi_init_queue(struct driver_data *drv_data) return 0; } -static inline int bfin_spi_start_queue(struct driver_data *drv_data) +static inline int bfin_spi_start_queue(struct bfin_spi_master_data *drv_data) { unsigned long flags; spin_lock_irqsave(&drv_data->lock, flags); - if (drv_data->run == QUEUE_RUNNING || drv_data->busy) { + if (drv_data->running || drv_data->busy) { spin_unlock_irqrestore(&drv_data->lock, flags); return -EBUSY; } - drv_data->run = QUEUE_RUNNING; + drv_data->running = true; drv_data->cur_msg = NULL; drv_data->cur_transfer = NULL; drv_data->cur_chip = NULL; @@ -1212,7 +1217,7 @@ static inline int bfin_spi_start_queue(struct driver_data *drv_data) return 0; } -static inline int bfin_spi_stop_queue(struct driver_data *drv_data) +static inline int bfin_spi_stop_queue(struct bfin_spi_master_data *drv_data) { unsigned long flags; unsigned limit = 500; @@ -1226,7 +1231,7 @@ static inline int bfin_spi_stop_queue(struct driver_data *drv_data) * execution path (pump_messages) would be required to call wake_up or * friends on every SPI message. Do this instead */ - drv_data->run = QUEUE_STOPPED; + drv_data->running = false; while (!list_empty(&drv_data->queue) && drv_data->busy && limit--) { spin_unlock_irqrestore(&drv_data->lock, flags); msleep(10); @@ -1241,7 +1246,7 @@ static inline int bfin_spi_stop_queue(struct driver_data *drv_data) return status; } -static inline int bfin_spi_destroy_queue(struct driver_data *drv_data) +static inline int bfin_spi_destroy_queue(struct bfin_spi_master_data *drv_data) { int status; @@ -1259,14 +1264,14 @@ static int __init bfin_spi_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct bfin5xx_spi_master *platform_info; struct spi_master *master; - struct driver_data *drv_data = 0; + struct bfin_spi_master_data *drv_data; struct resource *res; int status = 0; platform_info = dev->platform_data; /* Allocate master with space for drv_data */ - master = spi_alloc_master(dev, sizeof(struct driver_data) + 16); + master = spi_alloc_master(dev, sizeof(*drv_data)); if (!master) { dev_err(&pdev->dev, "can not alloc spi_master\n"); return -ENOMEM; @@ -1302,11 +1307,19 @@ static int __init bfin_spi_probe(struct platform_device *pdev) goto out_error_ioremap; } - drv_data->dma_channel = platform_get_irq(pdev, 0); - if (drv_data->dma_channel < 0) { + res = platform_get_resource(pdev, IORESOURCE_DMA, 0); + if (res == NULL) { dev_err(dev, "No DMA channel specified\n"); status = -ENOENT; - goto out_error_no_dma_ch; + goto out_error_free_io; + } + drv_data->dma_channel = res->start; + + drv_data->spi_irq = platform_get_irq(pdev, 0); + if (drv_data->spi_irq < 0) { + dev_err(dev, "No spi pio irq specified\n"); + status = -ENOENT; + goto out_error_free_io; } /* Initial and start queue */ @@ -1328,6 +1341,12 @@ static int __init bfin_spi_probe(struct platform_device *pdev) goto out_error_queue_alloc; } + /* Reset SPI registers. If these registers were used by the boot loader, + * the sky may fall on your head if you enable the dma controller. + */ + write_CTRL(drv_data, BIT_CTL_CPHA | BIT_CTL_MASTER); + write_FLAG(drv_data, 0xFF00); + /* Register with the SPI framework */ platform_set_drvdata(pdev, drv_data); status = spi_register_master(master); @@ -1343,7 +1362,7 @@ static int __init bfin_spi_probe(struct platform_device *pdev) out_error_queue_alloc: bfin_spi_destroy_queue(drv_data); -out_error_no_dma_ch: +out_error_free_io: iounmap((void *) drv_data->regs_base); out_error_ioremap: out_error_get_res: @@ -1355,7 +1374,7 @@ out_error_get_res: /* stop hardware and remove the driver */ static int __devexit bfin_spi_remove(struct platform_device *pdev) { - struct driver_data *drv_data = platform_get_drvdata(pdev); + struct bfin_spi_master_data *drv_data = platform_get_drvdata(pdev); int status = 0; if (!drv_data) @@ -1375,6 +1394,11 @@ static int __devexit bfin_spi_remove(struct platform_device *pdev) free_dma(drv_data->dma_channel); } + if (drv_data->irq_requested) { + free_irq(drv_data->spi_irq, drv_data); + drv_data->irq_requested = 0; + } + /* Disconnect from the SPI framework */ spi_unregister_master(drv_data->master); @@ -1389,26 +1413,32 @@ static int __devexit bfin_spi_remove(struct platform_device *pdev) #ifdef CONFIG_PM static int bfin_spi_suspend(struct platform_device *pdev, pm_message_t state) { - struct driver_data *drv_data = platform_get_drvdata(pdev); + struct bfin_spi_master_data *drv_data = platform_get_drvdata(pdev); int status = 0; status = bfin_spi_stop_queue(drv_data); if (status != 0) return status; - /* stop hardware */ - bfin_spi_disable(drv_data); + drv_data->ctrl_reg = read_CTRL(drv_data); + drv_data->flag_reg = read_FLAG(drv_data); + + /* + * reset SPI_CTL and SPI_FLG registers + */ + write_CTRL(drv_data, BIT_CTL_CPHA | BIT_CTL_MASTER); + write_FLAG(drv_data, 0xFF00); return 0; } static int bfin_spi_resume(struct platform_device *pdev) { - struct driver_data *drv_data = platform_get_drvdata(pdev); + struct bfin_spi_master_data *drv_data = platform_get_drvdata(pdev); int status = 0; - /* Enable the SPI interface */ - bfin_spi_enable(drv_data); + write_CTRL(drv_data, drv_data->ctrl_reg); + write_FLAG(drv_data, drv_data->flag_reg); /* Start the queue running */ status = bfin_spi_start_queue(drv_data); @@ -1439,7 +1469,7 @@ static int __init bfin_spi_init(void) { return platform_driver_probe(&bfin_spi_driver, bfin_spi_probe); } -module_init(bfin_spi_init); +subsys_initcall(bfin_spi_init); static void __exit bfin_spi_exit(void) { diff --git a/drivers/spi/spi_fsl_espi.c b/drivers/spi/spi_fsl_espi.c new file mode 100644 index 000000000000..e3b4f6451966 --- /dev/null +++ b/drivers/spi/spi_fsl_espi.c @@ -0,0 +1,748 @@ +/* + * Freescale eSPI controller driver. + * + * Copyright 2010 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/irq.h> +#include <linux/spi/spi.h> +#include <linux/platform_device.h> +#include <linux/fsl_devices.h> +#include <linux/mm.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/of_spi.h> +#include <linux/interrupt.h> +#include <linux/err.h> +#include <sysdev/fsl_soc.h> + +#include "spi_fsl_lib.h" + +/* eSPI Controller registers */ +struct fsl_espi_reg { + __be32 mode; /* 0x000 - eSPI mode register */ + __be32 event; /* 0x004 - eSPI event register */ + __be32 mask; /* 0x008 - eSPI mask register */ + __be32 command; /* 0x00c - eSPI command register */ + __be32 transmit; /* 0x010 - eSPI transmit FIFO access register*/ + __be32 receive; /* 0x014 - eSPI receive FIFO access register*/ + u8 res[8]; /* 0x018 - 0x01c reserved */ + __be32 csmode[4]; /* 0x020 - 0x02c eSPI cs mode register */ +}; + +struct fsl_espi_transfer { + const void *tx_buf; + void *rx_buf; + unsigned len; + unsigned n_tx; + unsigned n_rx; + unsigned actual_length; + int status; +}; + +/* eSPI Controller mode register definitions */ +#define SPMODE_ENABLE (1 << 31) +#define SPMODE_LOOP (1 << 30) +#define SPMODE_TXTHR(x) ((x) << 8) +#define SPMODE_RXTHR(x) ((x) << 0) + +/* eSPI Controller CS mode register definitions */ +#define CSMODE_CI_INACTIVEHIGH (1 << 31) +#define CSMODE_CP_BEGIN_EDGECLK (1 << 30) +#define CSMODE_REV (1 << 29) +#define CSMODE_DIV16 (1 << 28) +#define CSMODE_PM(x) ((x) << 24) +#define CSMODE_POL_1 (1 << 20) +#define CSMODE_LEN(x) ((x) << 16) +#define CSMODE_BEF(x) ((x) << 12) +#define CSMODE_AFT(x) ((x) << 8) +#define CSMODE_CG(x) ((x) << 3) + +/* Default mode/csmode for eSPI controller */ +#define SPMODE_INIT_VAL (SPMODE_TXTHR(4) | SPMODE_RXTHR(3)) +#define CSMODE_INIT_VAL (CSMODE_POL_1 | CSMODE_BEF(0) \ + | CSMODE_AFT(0) | CSMODE_CG(1)) + +/* SPIE register values */ +#define SPIE_NE 0x00000200 /* Not empty */ +#define SPIE_NF 0x00000100 /* Not full */ + +/* SPIM register values */ +#define SPIM_NE 0x00000200 /* Not empty */ +#define SPIM_NF 0x00000100 /* Not full */ +#define SPIE_RXCNT(reg) ((reg >> 24) & 0x3F) +#define SPIE_TXCNT(reg) ((reg >> 16) & 0x3F) + +/* SPCOM register values */ +#define SPCOM_CS(x) ((x) << 30) +#define SPCOM_TRANLEN(x) ((x) << 0) +#define SPCOM_TRANLEN_MAX 0xFFFF /* Max transaction length */ + +static void fsl_espi_change_mode(struct spi_device *spi) +{ + struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master); + struct spi_mpc8xxx_cs *cs = spi->controller_state; + struct fsl_espi_reg *reg_base = mspi->reg_base; + __be32 __iomem *mode = ®_base->csmode[spi->chip_select]; + __be32 __iomem *espi_mode = ®_base->mode; + u32 tmp; + unsigned long flags; + + /* Turn off IRQs locally to minimize time that SPI is disabled. */ + local_irq_save(flags); + + /* Turn off SPI unit prior changing mode */ + tmp = mpc8xxx_spi_read_reg(espi_mode); + mpc8xxx_spi_write_reg(espi_mode, tmp & ~SPMODE_ENABLE); + mpc8xxx_spi_write_reg(mode, cs->hw_mode); + mpc8xxx_spi_write_reg(espi_mode, tmp); + + local_irq_restore(flags); +} + +static u32 fsl_espi_tx_buf_lsb(struct mpc8xxx_spi *mpc8xxx_spi) +{ + u32 data; + u16 data_h; + u16 data_l; + const u32 *tx = mpc8xxx_spi->tx; + + if (!tx) + return 0; + + data = *tx++ << mpc8xxx_spi->tx_shift; + data_l = data & 0xffff; + data_h = (data >> 16) & 0xffff; + swab16s(&data_l); + swab16s(&data_h); + data = data_h | data_l; + + mpc8xxx_spi->tx = tx; + return data; +} + +static int fsl_espi_setup_transfer(struct spi_device *spi, + struct spi_transfer *t) +{ + struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master); + int bits_per_word = 0; + u8 pm; + u32 hz = 0; + struct spi_mpc8xxx_cs *cs = spi->controller_state; + + if (t) { + bits_per_word = t->bits_per_word; + hz = t->speed_hz; + } + + /* spi_transfer level calls that work per-word */ + if (!bits_per_word) + bits_per_word = spi->bits_per_word; + + /* Make sure its a bit width we support [4..16] */ + if ((bits_per_word < 4) || (bits_per_word > 16)) + return -EINVAL; + + if (!hz) + hz = spi->max_speed_hz; + + cs->rx_shift = 0; + cs->tx_shift = 0; + cs->get_rx = mpc8xxx_spi_rx_buf_u32; + cs->get_tx = mpc8xxx_spi_tx_buf_u32; + if (bits_per_word <= 8) { + cs->rx_shift = 8 - bits_per_word; + } else if (bits_per_word <= 16) { + cs->rx_shift = 16 - bits_per_word; + if (spi->mode & SPI_LSB_FIRST) + cs->get_tx = fsl_espi_tx_buf_lsb; + } else { + return -EINVAL; + } + + mpc8xxx_spi->rx_shift = cs->rx_shift; + mpc8xxx_spi->tx_shift = cs->tx_shift; + mpc8xxx_spi->get_rx = cs->get_rx; + mpc8xxx_spi->get_tx = cs->get_tx; + + bits_per_word = bits_per_word - 1; + + /* mask out bits we are going to set */ + cs->hw_mode &= ~(CSMODE_LEN(0xF) | CSMODE_DIV16 | CSMODE_PM(0xF)); + + cs->hw_mode |= CSMODE_LEN(bits_per_word); + + if ((mpc8xxx_spi->spibrg / hz) > 64) { + cs->hw_mode |= CSMODE_DIV16; + pm = (mpc8xxx_spi->spibrg - 1) / (hz * 64) + 1; + + WARN_ONCE(pm > 16, "%s: Requested speed is too low: %d Hz. " + "Will use %d Hz instead.\n", dev_name(&spi->dev), + hz, mpc8xxx_spi->spibrg / 1024); + if (pm > 16) + pm = 16; + } else { + pm = (mpc8xxx_spi->spibrg - 1) / (hz * 4) + 1; + } + if (pm) + pm--; + + cs->hw_mode |= CSMODE_PM(pm); + + fsl_espi_change_mode(spi); + return 0; +} + +static int fsl_espi_cpu_bufs(struct mpc8xxx_spi *mspi, struct spi_transfer *t, + unsigned int len) +{ + u32 word; + struct fsl_espi_reg *reg_base = mspi->reg_base; + + mspi->count = len; + + /* enable rx ints */ + mpc8xxx_spi_write_reg(®_base->mask, SPIM_NE); + + /* transmit word */ + word = mspi->get_tx(mspi); + mpc8xxx_spi_write_reg(®_base->transmit, word); + + return 0; +} + +static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t) +{ + struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master); + struct fsl_espi_reg *reg_base = mpc8xxx_spi->reg_base; + unsigned int len = t->len; + u8 bits_per_word; + int ret; + + bits_per_word = spi->bits_per_word; + if (t->bits_per_word) + bits_per_word = t->bits_per_word; + + mpc8xxx_spi->len = t->len; + len = roundup(len, 4) / 4; + + mpc8xxx_spi->tx = t->tx_buf; + mpc8xxx_spi->rx = t->rx_buf; + + INIT_COMPLETION(mpc8xxx_spi->done); + + /* Set SPCOM[CS] and SPCOM[TRANLEN] field */ + if ((t->len - 1) > SPCOM_TRANLEN_MAX) { + dev_err(mpc8xxx_spi->dev, "Transaction length (%d)" + " beyond the SPCOM[TRANLEN] field\n", t->len); + return -EINVAL; + } + mpc8xxx_spi_write_reg(®_base->command, + (SPCOM_CS(spi->chip_select) | SPCOM_TRANLEN(t->len - 1))); + + ret = fsl_espi_cpu_bufs(mpc8xxx_spi, t, len); + if (ret) + return ret; + + wait_for_completion(&mpc8xxx_spi->done); + + /* disable rx ints */ + mpc8xxx_spi_write_reg(®_base->mask, 0); + + return mpc8xxx_spi->count; +} + +static void fsl_espi_addr2cmd(unsigned int addr, u8 *cmd) +{ + if (cmd[1] && cmd[2] && cmd[3]) { + cmd[1] = (u8)(addr >> 16); + cmd[2] = (u8)(addr >> 8); + cmd[3] = (u8)(addr >> 0); + } +} + +static unsigned int fsl_espi_cmd2addr(u8 *cmd) +{ + if (cmd[1] && cmd[2] && cmd[3]) + return cmd[1] << 16 | cmd[2] << 8 | cmd[3] << 0; + + return 0; +} + +static void fsl_espi_do_trans(struct spi_message *m, + struct fsl_espi_transfer *tr) +{ + struct spi_device *spi = m->spi; + struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master); + struct fsl_espi_transfer *espi_trans = tr; + struct spi_message message; + struct spi_transfer *t, *first, trans; + int status = 0; + + spi_message_init(&message); + memset(&trans, 0, sizeof(trans)); + + first = list_first_entry(&m->transfers, struct spi_transfer, + transfer_list); + list_for_each_entry(t, &m->transfers, transfer_list) { + if ((first->bits_per_word != t->bits_per_word) || + (first->speed_hz != t->speed_hz)) { + espi_trans->status = -EINVAL; + dev_err(mspi->dev, "bits_per_word/speed_hz should be" + " same for the same SPI transfer\n"); + return; + } + + trans.speed_hz = t->speed_hz; + trans.bits_per_word = t->bits_per_word; + trans.delay_usecs = max(first->delay_usecs, t->delay_usecs); + } + + trans.len = espi_trans->len; + trans.tx_buf = espi_trans->tx_buf; + trans.rx_buf = espi_trans->rx_buf; + spi_message_add_tail(&trans, &message); + + list_for_each_entry(t, &message.transfers, transfer_list) { + if (t->bits_per_word || t->speed_hz) { + status = -EINVAL; + + status = fsl_espi_setup_transfer(spi, t); + if (status < 0) + break; + } + + if (t->len) + status = fsl_espi_bufs(spi, t); + + if (status) { + status = -EMSGSIZE; + break; + } + + if (t->delay_usecs) + udelay(t->delay_usecs); + } + + espi_trans->status = status; + fsl_espi_setup_transfer(spi, NULL); +} + +static void fsl_espi_cmd_trans(struct spi_message *m, + struct fsl_espi_transfer *trans, u8 *rx_buff) +{ + struct spi_transfer *t; + u8 *local_buf; + int i = 0; + struct fsl_espi_transfer *espi_trans = trans; + + local_buf = kzalloc(SPCOM_TRANLEN_MAX, GFP_KERNEL); + if (!local_buf) { + espi_trans->status = -ENOMEM; + return; + } + + list_for_each_entry(t, &m->transfers, transfer_list) { + if (t->tx_buf) { + memcpy(local_buf + i, t->tx_buf, t->len); + i += t->len; + } + } + + espi_trans->tx_buf = local_buf; + espi_trans->rx_buf = local_buf + espi_trans->n_tx; + fsl_espi_do_trans(m, espi_trans); + + espi_trans->actual_length = espi_trans->len; + kfree(local_buf); +} + +static void fsl_espi_rw_trans(struct spi_message *m, + struct fsl_espi_transfer *trans, u8 *rx_buff) +{ + struct fsl_espi_transfer *espi_trans = trans; + unsigned int n_tx = espi_trans->n_tx; + unsigned int n_rx = espi_trans->n_rx; + struct spi_transfer *t; + u8 *local_buf; + u8 *rx_buf = rx_buff; + unsigned int trans_len; + unsigned int addr; + int i, pos, loop; + + local_buf = kzalloc(SPCOM_TRANLEN_MAX, GFP_KERNEL); + if (!local_buf) { + espi_trans->status = -ENOMEM; + return; + } + + for (pos = 0, loop = 0; pos < n_rx; pos += trans_len, loop++) { + trans_len = n_rx - pos; + if (trans_len > SPCOM_TRANLEN_MAX - n_tx) + trans_len = SPCOM_TRANLEN_MAX - n_tx; + + i = 0; + list_for_each_entry(t, &m->transfers, transfer_list) { + if (t->tx_buf) { + memcpy(local_buf + i, t->tx_buf, t->len); + i += t->len; + } + } + + addr = fsl_espi_cmd2addr(local_buf); + addr += pos; + fsl_espi_addr2cmd(addr, local_buf); + + espi_trans->n_tx = n_tx; + espi_trans->n_rx = trans_len; + espi_trans->len = trans_len + n_tx; + espi_trans->tx_buf = local_buf; + espi_trans->rx_buf = local_buf + n_tx; + fsl_espi_do_trans(m, espi_trans); + + memcpy(rx_buf + pos, espi_trans->rx_buf + n_tx, trans_len); + + if (loop > 0) + espi_trans->actual_length += espi_trans->len - n_tx; + else + espi_trans->actual_length += espi_trans->len; + } + + kfree(local_buf); +} + +static void fsl_espi_do_one_msg(struct spi_message *m) +{ + struct spi_transfer *t; + u8 *rx_buf = NULL; + unsigned int n_tx = 0; + unsigned int n_rx = 0; + struct fsl_espi_transfer espi_trans; + + list_for_each_entry(t, &m->transfers, transfer_list) { + if (t->tx_buf) + n_tx += t->len; + if (t->rx_buf) { + n_rx += t->len; + rx_buf = t->rx_buf; + } + } + + espi_trans.n_tx = n_tx; + espi_trans.n_rx = n_rx; + espi_trans.len = n_tx + n_rx; + espi_trans.actual_length = 0; + espi_trans.status = 0; + + if (!rx_buf) + fsl_espi_cmd_trans(m, &espi_trans, NULL); + else + fsl_espi_rw_trans(m, &espi_trans, rx_buf); + + m->actual_length = espi_trans.actual_length; + m->status = espi_trans.status; + m->complete(m->context); +} + +static int fsl_espi_setup(struct spi_device *spi) +{ + struct mpc8xxx_spi *mpc8xxx_spi; + struct fsl_espi_reg *reg_base; + int retval; + u32 hw_mode; + u32 loop_mode; + struct spi_mpc8xxx_cs *cs = spi->controller_state; + + if (!spi->max_speed_hz) + return -EINVAL; + + if (!cs) { + cs = kzalloc(sizeof *cs, GFP_KERNEL); + if (!cs) + return -ENOMEM; + spi->controller_state = cs; + } + + mpc8xxx_spi = spi_master_get_devdata(spi->master); + reg_base = mpc8xxx_spi->reg_base; + + hw_mode = cs->hw_mode; /* Save orginal settings */ + cs->hw_mode = mpc8xxx_spi_read_reg( + ®_base->csmode[spi->chip_select]); + /* mask out bits we are going to set */ + cs->hw_mode &= ~(CSMODE_CP_BEGIN_EDGECLK | CSMODE_CI_INACTIVEHIGH + | CSMODE_REV); + + if (spi->mode & SPI_CPHA) + cs->hw_mode |= CSMODE_CP_BEGIN_EDGECLK; + if (spi->mode & SPI_CPOL) + cs->hw_mode |= CSMODE_CI_INACTIVEHIGH; + if (!(spi->mode & SPI_LSB_FIRST)) + cs->hw_mode |= CSMODE_REV; + + /* Handle the loop mode */ + loop_mode = mpc8xxx_spi_read_reg(®_base->mode); + loop_mode &= ~SPMODE_LOOP; + if (spi->mode & SPI_LOOP) + loop_mode |= SPMODE_LOOP; + mpc8xxx_spi_write_reg(®_base->mode, loop_mode); + + retval = fsl_espi_setup_transfer(spi, NULL); + if (retval < 0) { + cs->hw_mode = hw_mode; /* Restore settings */ + return retval; + } + return 0; +} + +void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events) +{ + struct fsl_espi_reg *reg_base = mspi->reg_base; + + /* We need handle RX first */ + if (events & SPIE_NE) { + u32 rx_data; + + /* Spin until RX is done */ + while (SPIE_RXCNT(events) < min(4, mspi->len)) { + cpu_relax(); + events = mpc8xxx_spi_read_reg(®_base->event); + } + mspi->len -= 4; + + rx_data = mpc8xxx_spi_read_reg(®_base->receive); + + if (mspi->rx) + mspi->get_rx(rx_data, mspi); + } + + if (!(events & SPIE_NF)) { + int ret; + + /* spin until TX is done */ + ret = spin_event_timeout(((events = mpc8xxx_spi_read_reg( + ®_base->event)) & SPIE_NF) == 0, 1000, 0); + if (!ret) { + dev_err(mspi->dev, "tired waiting for SPIE_NF\n"); + return; + } + } + + /* Clear the events */ + mpc8xxx_spi_write_reg(®_base->event, events); + + mspi->count -= 1; + if (mspi->count) { + u32 word = mspi->get_tx(mspi); + + mpc8xxx_spi_write_reg(®_base->transmit, word); + } else { + complete(&mspi->done); + } +} + +static irqreturn_t fsl_espi_irq(s32 irq, void *context_data) +{ + struct mpc8xxx_spi *mspi = context_data; + struct fsl_espi_reg *reg_base = mspi->reg_base; + irqreturn_t ret = IRQ_NONE; + u32 events; + + /* Get interrupt events(tx/rx) */ + events = mpc8xxx_spi_read_reg(®_base->event); + if (events) + ret = IRQ_HANDLED; + + dev_vdbg(mspi->dev, "%s: events %x\n", __func__, events); + + fsl_espi_cpu_irq(mspi, events); + + return ret; +} + +static void fsl_espi_remove(struct mpc8xxx_spi *mspi) +{ + iounmap(mspi->reg_base); +} + +static struct spi_master * __devinit fsl_espi_probe(struct device *dev, + struct resource *mem, unsigned int irq) +{ + struct fsl_spi_platform_data *pdata = dev->platform_data; + struct spi_master *master; + struct mpc8xxx_spi *mpc8xxx_spi; + struct fsl_espi_reg *reg_base; + u32 regval; + int i, ret = 0; + + master = spi_alloc_master(dev, sizeof(struct mpc8xxx_spi)); + if (!master) { + ret = -ENOMEM; + goto err; + } + + dev_set_drvdata(dev, master); + + ret = mpc8xxx_spi_probe(dev, mem, irq); + if (ret) + goto err_probe; + + master->setup = fsl_espi_setup; + + mpc8xxx_spi = spi_master_get_devdata(master); + mpc8xxx_spi->spi_do_one_msg = fsl_espi_do_one_msg; + mpc8xxx_spi->spi_remove = fsl_espi_remove; + + mpc8xxx_spi->reg_base = ioremap(mem->start, resource_size(mem)); + if (!mpc8xxx_spi->reg_base) { + ret = -ENOMEM; + goto err_probe; + } + + reg_base = mpc8xxx_spi->reg_base; + + /* Register for SPI Interrupt */ + ret = request_irq(mpc8xxx_spi->irq, fsl_espi_irq, + 0, "fsl_espi", mpc8xxx_spi); + if (ret) + goto free_irq; + + if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) { + mpc8xxx_spi->rx_shift = 16; + mpc8xxx_spi->tx_shift = 24; + } + + /* SPI controller initializations */ + mpc8xxx_spi_write_reg(®_base->mode, 0); + mpc8xxx_spi_write_reg(®_base->mask, 0); + mpc8xxx_spi_write_reg(®_base->command, 0); + mpc8xxx_spi_write_reg(®_base->event, 0xffffffff); + + /* Init eSPI CS mode register */ + for (i = 0; i < pdata->max_chipselect; i++) + mpc8xxx_spi_write_reg(®_base->csmode[i], CSMODE_INIT_VAL); + + /* Enable SPI interface */ + regval = pdata->initial_spmode | SPMODE_INIT_VAL | SPMODE_ENABLE; + + mpc8xxx_spi_write_reg(®_base->mode, regval); + + ret = spi_register_master(master); + if (ret < 0) + goto unreg_master; + + dev_info(dev, "at 0x%p (irq = %d)\n", reg_base, mpc8xxx_spi->irq); + + return master; + +unreg_master: + free_irq(mpc8xxx_spi->irq, mpc8xxx_spi); +free_irq: + iounmap(mpc8xxx_spi->reg_base); +err_probe: + spi_master_put(master); +err: + return ERR_PTR(ret); +} + +static int of_fsl_espi_get_chipselects(struct device *dev) +{ + struct device_node *np = dev->of_node; + struct fsl_spi_platform_data *pdata = dev->platform_data; + const u32 *prop; + int len; + + prop = of_get_property(np, "fsl,espi-num-chipselects", &len); + if (!prop || len < sizeof(*prop)) { + dev_err(dev, "No 'fsl,espi-num-chipselects' property\n"); + return -EINVAL; + } + + pdata->max_chipselect = *prop; + pdata->cs_control = NULL; + + return 0; +} + +static int __devinit of_fsl_espi_probe(struct platform_device *ofdev, + const struct of_device_id *ofid) +{ + struct device *dev = &ofdev->dev; + struct device_node *np = ofdev->dev.of_node; + struct spi_master *master; + struct resource mem; + struct resource irq; + int ret = -ENOMEM; + + ret = of_mpc8xxx_spi_probe(ofdev, ofid); + if (ret) + return ret; + + ret = of_fsl_espi_get_chipselects(dev); + if (ret) + goto err; + + ret = of_address_to_resource(np, 0, &mem); + if (ret) + goto err; + + ret = of_irq_to_resource(np, 0, &irq); + if (!ret) { + ret = -EINVAL; + goto err; + } + + master = fsl_espi_probe(dev, &mem, irq.start); + if (IS_ERR(master)) { + ret = PTR_ERR(master); + goto err; + } + + return 0; + +err: + return ret; +} + +static int __devexit of_fsl_espi_remove(struct platform_device *dev) +{ + return mpc8xxx_spi_remove(&dev->dev); +} + +static const struct of_device_id of_fsl_espi_match[] = { + { .compatible = "fsl,mpc8536-espi" }, + {} +}; +MODULE_DEVICE_TABLE(of, of_fsl_espi_match); + +static struct of_platform_driver fsl_espi_driver = { + .driver = { + .name = "fsl_espi", + .owner = THIS_MODULE, + .of_match_table = of_fsl_espi_match, + }, + .probe = of_fsl_espi_probe, + .remove = __devexit_p(of_fsl_espi_remove), +}; + +static int __init fsl_espi_init(void) +{ + return of_register_platform_driver(&fsl_espi_driver); +} +module_init(fsl_espi_init); + +static void __exit fsl_espi_exit(void) +{ + of_unregister_platform_driver(&fsl_espi_driver); +} +module_exit(fsl_espi_exit); + +MODULE_AUTHOR("Mingkai Hu"); +MODULE_DESCRIPTION("Enhanced Freescale SPI Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/spi/spi_fsl_lib.c b/drivers/spi/spi_fsl_lib.c new file mode 100644 index 000000000000..5cd741fdb5c3 --- /dev/null +++ b/drivers/spi/spi_fsl_lib.c @@ -0,0 +1,237 @@ +/* + * Freescale SPI/eSPI controller driver library. + * + * Maintainer: Kumar Gala + * + * Copyright (C) 2006 Polycom, Inc. + * + * CPM SPI and QE buffer descriptors mode support: + * Copyright (c) 2009 MontaVista Software, Inc. + * Author: Anton Vorontsov <avorontsov@ru.mvista.com> + * + * Copyright 2010 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +#include <linux/kernel.h> +#include <linux/interrupt.h> +#include <linux/fsl_devices.h> +#include <linux/dma-mapping.h> +#include <linux/mm.h> +#include <linux/of_platform.h> +#include <linux/of_spi.h> +#include <sysdev/fsl_soc.h> + +#include "spi_fsl_lib.h" + +#define MPC8XXX_SPI_RX_BUF(type) \ +void mpc8xxx_spi_rx_buf_##type(u32 data, struct mpc8xxx_spi *mpc8xxx_spi) \ +{ \ + type *rx = mpc8xxx_spi->rx; \ + *rx++ = (type)(data >> mpc8xxx_spi->rx_shift); \ + mpc8xxx_spi->rx = rx; \ +} + +#define MPC8XXX_SPI_TX_BUF(type) \ +u32 mpc8xxx_spi_tx_buf_##type(struct mpc8xxx_spi *mpc8xxx_spi) \ +{ \ + u32 data; \ + const type *tx = mpc8xxx_spi->tx; \ + if (!tx) \ + return 0; \ + data = *tx++ << mpc8xxx_spi->tx_shift; \ + mpc8xxx_spi->tx = tx; \ + return data; \ +} + +MPC8XXX_SPI_RX_BUF(u8) +MPC8XXX_SPI_RX_BUF(u16) +MPC8XXX_SPI_RX_BUF(u32) +MPC8XXX_SPI_TX_BUF(u8) +MPC8XXX_SPI_TX_BUF(u16) +MPC8XXX_SPI_TX_BUF(u32) + +struct mpc8xxx_spi_probe_info *to_of_pinfo(struct fsl_spi_platform_data *pdata) +{ + return container_of(pdata, struct mpc8xxx_spi_probe_info, pdata); +} + +void mpc8xxx_spi_work(struct work_struct *work) +{ + struct mpc8xxx_spi *mpc8xxx_spi = container_of(work, struct mpc8xxx_spi, + work); + + spin_lock_irq(&mpc8xxx_spi->lock); + while (!list_empty(&mpc8xxx_spi->queue)) { + struct spi_message *m = container_of(mpc8xxx_spi->queue.next, + struct spi_message, queue); + + list_del_init(&m->queue); + spin_unlock_irq(&mpc8xxx_spi->lock); + + if (mpc8xxx_spi->spi_do_one_msg) + mpc8xxx_spi->spi_do_one_msg(m); + + spin_lock_irq(&mpc8xxx_spi->lock); + } + spin_unlock_irq(&mpc8xxx_spi->lock); +} + +int mpc8xxx_spi_transfer(struct spi_device *spi, + struct spi_message *m) +{ + struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master); + unsigned long flags; + + m->actual_length = 0; + m->status = -EINPROGRESS; + + spin_lock_irqsave(&mpc8xxx_spi->lock, flags); + list_add_tail(&m->queue, &mpc8xxx_spi->queue); + queue_work(mpc8xxx_spi->workqueue, &mpc8xxx_spi->work); + spin_unlock_irqrestore(&mpc8xxx_spi->lock, flags); + + return 0; +} + +void mpc8xxx_spi_cleanup(struct spi_device *spi) +{ + kfree(spi->controller_state); +} + +const char *mpc8xxx_spi_strmode(unsigned int flags) +{ + if (flags & SPI_QE_CPU_MODE) { + return "QE CPU"; + } else if (flags & SPI_CPM_MODE) { + if (flags & SPI_QE) + return "QE"; + else if (flags & SPI_CPM2) + return "CPM2"; + else + return "CPM1"; + } + return "CPU"; +} + +int mpc8xxx_spi_probe(struct device *dev, struct resource *mem, + unsigned int irq) +{ + struct fsl_spi_platform_data *pdata = dev->platform_data; + struct spi_master *master; + struct mpc8xxx_spi *mpc8xxx_spi; + int ret = 0; + + master = dev_get_drvdata(dev); + + /* the spi->mode bits understood by this driver: */ + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH + | SPI_LSB_FIRST | SPI_LOOP; + + master->transfer = mpc8xxx_spi_transfer; + master->cleanup = mpc8xxx_spi_cleanup; + master->dev.of_node = dev->of_node; + + mpc8xxx_spi = spi_master_get_devdata(master); + mpc8xxx_spi->dev = dev; + mpc8xxx_spi->get_rx = mpc8xxx_spi_rx_buf_u8; + mpc8xxx_spi->get_tx = mpc8xxx_spi_tx_buf_u8; + mpc8xxx_spi->flags = pdata->flags; + mpc8xxx_spi->spibrg = pdata->sysclk; + mpc8xxx_spi->irq = irq; + + mpc8xxx_spi->rx_shift = 0; + mpc8xxx_spi->tx_shift = 0; + + init_completion(&mpc8xxx_spi->done); + + master->bus_num = pdata->bus_num; + master->num_chipselect = pdata->max_chipselect; + + spin_lock_init(&mpc8xxx_spi->lock); + init_completion(&mpc8xxx_spi->done); + INIT_WORK(&mpc8xxx_spi->work, mpc8xxx_spi_work); + INIT_LIST_HEAD(&mpc8xxx_spi->queue); + + mpc8xxx_spi->workqueue = create_singlethread_workqueue( + dev_name(master->dev.parent)); + if (mpc8xxx_spi->workqueue == NULL) { + ret = -EBUSY; + goto err; + } + + return 0; + +err: + return ret; +} + +int __devexit mpc8xxx_spi_remove(struct device *dev) +{ + struct mpc8xxx_spi *mpc8xxx_spi; + struct spi_master *master; + + master = dev_get_drvdata(dev); + mpc8xxx_spi = spi_master_get_devdata(master); + + flush_workqueue(mpc8xxx_spi->workqueue); + destroy_workqueue(mpc8xxx_spi->workqueue); + spi_unregister_master(master); + + free_irq(mpc8xxx_spi->irq, mpc8xxx_spi); + + if (mpc8xxx_spi->spi_remove) + mpc8xxx_spi->spi_remove(mpc8xxx_spi); + + return 0; +} + +int __devinit of_mpc8xxx_spi_probe(struct platform_device *ofdev, + const struct of_device_id *ofid) +{ + struct device *dev = &ofdev->dev; + struct device_node *np = ofdev->dev.of_node; + struct mpc8xxx_spi_probe_info *pinfo; + struct fsl_spi_platform_data *pdata; + const void *prop; + int ret = -ENOMEM; + + pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL); + if (!pinfo) + return -ENOMEM; + + pdata = &pinfo->pdata; + dev->platform_data = pdata; + + /* Allocate bus num dynamically. */ + pdata->bus_num = -1; + + /* SPI controller is either clocked from QE or SoC clock. */ + pdata->sysclk = get_brgfreq(); + if (pdata->sysclk == -1) { + pdata->sysclk = fsl_get_sys_freq(); + if (pdata->sysclk == -1) { + ret = -ENODEV; + goto err; + } + } + + prop = of_get_property(np, "mode", NULL); + if (prop && !strcmp(prop, "cpu-qe")) + pdata->flags = SPI_QE_CPU_MODE; + else if (prop && !strcmp(prop, "qe")) + pdata->flags = SPI_CPM_MODE | SPI_QE; + else if (of_device_is_compatible(np, "fsl,cpm2-spi")) + pdata->flags = SPI_CPM_MODE | SPI_CPM2; + else if (of_device_is_compatible(np, "fsl,cpm1-spi")) + pdata->flags = SPI_CPM_MODE | SPI_CPM1; + + return 0; + +err: + kfree(pinfo); + return ret; +} diff --git a/drivers/spi/spi_fsl_lib.h b/drivers/spi/spi_fsl_lib.h new file mode 100644 index 000000000000..281e060977cd --- /dev/null +++ b/drivers/spi/spi_fsl_lib.h @@ -0,0 +1,124 @@ +/* + * Freescale SPI/eSPI controller driver library. + * + * Maintainer: Kumar Gala + * + * Copyright 2010 Freescale Semiconductor, Inc. + * Copyright (C) 2006 Polycom, Inc. + * + * CPM SPI and QE buffer descriptors mode support: + * Copyright (c) 2009 MontaVista Software, Inc. + * Author: Anton Vorontsov <avorontsov@ru.mvista.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +#ifndef __SPI_FSL_LIB_H__ +#define __SPI_FSL_LIB_H__ + +#include <asm/io.h> + +/* SPI/eSPI Controller driver's private data. */ +struct mpc8xxx_spi { + struct device *dev; + void *reg_base; + + /* rx & tx bufs from the spi_transfer */ + const void *tx; + void *rx; +#ifdef CONFIG_SPI_FSL_ESPI + int len; +#endif + + int subblock; + struct spi_pram __iomem *pram; + struct cpm_buf_desc __iomem *tx_bd; + struct cpm_buf_desc __iomem *rx_bd; + + struct spi_transfer *xfer_in_progress; + + /* dma addresses for CPM transfers */ + dma_addr_t tx_dma; + dma_addr_t rx_dma; + bool map_tx_dma; + bool map_rx_dma; + + dma_addr_t dma_dummy_tx; + dma_addr_t dma_dummy_rx; + + /* functions to deal with different sized buffers */ + void (*get_rx) (u32 rx_data, struct mpc8xxx_spi *); + u32(*get_tx) (struct mpc8xxx_spi *); + + /* hooks for different controller driver */ + void (*spi_do_one_msg) (struct spi_message *m); + void (*spi_remove) (struct mpc8xxx_spi *mspi); + + unsigned int count; + unsigned int irq; + + unsigned nsecs; /* (clock cycle time)/2 */ + + u32 spibrg; /* SPIBRG input clock */ + u32 rx_shift; /* RX data reg shift when in qe mode */ + u32 tx_shift; /* TX data reg shift when in qe mode */ + + unsigned int flags; + + struct workqueue_struct *workqueue; + struct work_struct work; + + struct list_head queue; + spinlock_t lock; + + struct completion done; +}; + +struct spi_mpc8xxx_cs { + /* functions to deal with different sized buffers */ + void (*get_rx) (u32 rx_data, struct mpc8xxx_spi *); + u32 (*get_tx) (struct mpc8xxx_spi *); + u32 rx_shift; /* RX data reg shift when in qe mode */ + u32 tx_shift; /* TX data reg shift when in qe mode */ + u32 hw_mode; /* Holds HW mode register settings */ +}; + +static inline void mpc8xxx_spi_write_reg(__be32 __iomem *reg, u32 val) +{ + out_be32(reg, val); +} + +static inline u32 mpc8xxx_spi_read_reg(__be32 __iomem *reg) +{ + return in_be32(reg); +} + +struct mpc8xxx_spi_probe_info { + struct fsl_spi_platform_data pdata; + int *gpios; + bool *alow_flags; +}; + +extern u32 mpc8xxx_spi_tx_buf_u8(struct mpc8xxx_spi *mpc8xxx_spi); +extern u32 mpc8xxx_spi_tx_buf_u16(struct mpc8xxx_spi *mpc8xxx_spi); +extern u32 mpc8xxx_spi_tx_buf_u32(struct mpc8xxx_spi *mpc8xxx_spi); +extern void mpc8xxx_spi_rx_buf_u8(u32 data, struct mpc8xxx_spi *mpc8xxx_spi); +extern void mpc8xxx_spi_rx_buf_u16(u32 data, struct mpc8xxx_spi *mpc8xxx_spi); +extern void mpc8xxx_spi_rx_buf_u32(u32 data, struct mpc8xxx_spi *mpc8xxx_spi); + +extern struct mpc8xxx_spi_probe_info *to_of_pinfo( + struct fsl_spi_platform_data *pdata); +extern int mpc8xxx_spi_bufs(struct mpc8xxx_spi *mspi, + struct spi_transfer *t, unsigned int len); +extern int mpc8xxx_spi_transfer(struct spi_device *spi, struct spi_message *m); +extern void mpc8xxx_spi_cleanup(struct spi_device *spi); +extern const char *mpc8xxx_spi_strmode(unsigned int flags); +extern int mpc8xxx_spi_probe(struct device *dev, struct resource *mem, + unsigned int irq); +extern int mpc8xxx_spi_remove(struct device *dev); +extern int of_mpc8xxx_spi_probe(struct platform_device *ofdev, + const struct of_device_id *ofid); + +#endif /* __SPI_FSL_LIB_H__ */ diff --git a/drivers/spi/spi_mpc8xxx.c b/drivers/spi/spi_fsl_spi.c index 1dd86b835cd8..7ca52d3ae8f8 100644 --- a/drivers/spi/spi_mpc8xxx.c +++ b/drivers/spi/spi_fsl_spi.c @@ -1,9 +1,10 @@ /* - * MPC8xxx SPI controller driver. + * Freescale SPI controller driver. * * Maintainer: Kumar Gala * * Copyright (C) 2006 Polycom, Inc. + * Copyright 2010 Freescale Semiconductor, Inc. * * CPM SPI and QE buffer descriptors mode support: * Copyright (c) 2009 MontaVista Software, Inc. @@ -15,18 +16,11 @@ * option) any later version. */ #include <linux/module.h> -#include <linux/init.h> #include <linux/types.h> #include <linux/kernel.h> -#include <linux/bug.h> -#include <linux/errno.h> -#include <linux/err.h> -#include <linux/io.h> -#include <linux/completion.h> #include <linux/interrupt.h> #include <linux/delay.h> #include <linux/irq.h> -#include <linux/device.h> #include <linux/spi/spi.h> #include <linux/spi/spi_bitbang.h> #include <linux/platform_device.h> @@ -38,12 +32,12 @@ #include <linux/of_platform.h> #include <linux/gpio.h> #include <linux/of_gpio.h> -#include <linux/slab.h> #include <sysdev/fsl_soc.h> #include <asm/cpm.h> #include <asm/qe.h> -#include <asm/irq.h> + +#include "spi_fsl_lib.h" /* CPM1 and CPM2 are mutually exclusive. */ #ifdef CONFIG_CPM1 @@ -55,7 +49,7 @@ #endif /* SPI Controller registers */ -struct mpc8xxx_spi_reg { +struct fsl_spi_reg { u8 res1[0x20]; __be32 mode; __be32 event; @@ -80,7 +74,7 @@ struct mpc8xxx_spi_reg { /* * Default for SPI Mode: - * SPI MODE 0 (inactive low, phase middle, MSB, 8-bit length, slow clk + * SPI MODE 0 (inactive low, phase middle, MSB, 8-bit length, slow clk */ #define SPMODE_INIT_VAL (SPMODE_CI_INACTIVEHIGH | SPMODE_DIV16 | SPMODE_REV | \ SPMODE_MS | SPMODE_LEN(7) | SPMODE_PM(0xf)) @@ -102,112 +96,16 @@ struct mpc8xxx_spi_reg { #define SPI_PRAM_SIZE 0x100 #define SPI_MRBLR ((unsigned int)PAGE_SIZE) -/* SPI Controller driver's private data. */ -struct mpc8xxx_spi { - struct device *dev; - struct mpc8xxx_spi_reg __iomem *base; - - /* rx & tx bufs from the spi_transfer */ - const void *tx; - void *rx; - - int subblock; - struct spi_pram __iomem *pram; - struct cpm_buf_desc __iomem *tx_bd; - struct cpm_buf_desc __iomem *rx_bd; - - struct spi_transfer *xfer_in_progress; - - /* dma addresses for CPM transfers */ - dma_addr_t tx_dma; - dma_addr_t rx_dma; - bool map_tx_dma; - bool map_rx_dma; - - dma_addr_t dma_dummy_tx; - dma_addr_t dma_dummy_rx; - - /* functions to deal with different sized buffers */ - void (*get_rx) (u32 rx_data, struct mpc8xxx_spi *); - u32(*get_tx) (struct mpc8xxx_spi *); - - unsigned int count; - unsigned int irq; - - unsigned nsecs; /* (clock cycle time)/2 */ - - u32 spibrg; /* SPIBRG input clock */ - u32 rx_shift; /* RX data reg shift when in qe mode */ - u32 tx_shift; /* TX data reg shift when in qe mode */ - - unsigned int flags; - - struct workqueue_struct *workqueue; - struct work_struct work; - - struct list_head queue; - spinlock_t lock; - - struct completion done; -}; - -static void *mpc8xxx_dummy_rx; -static DEFINE_MUTEX(mpc8xxx_dummy_rx_lock); -static int mpc8xxx_dummy_rx_refcnt; - -struct spi_mpc8xxx_cs { - /* functions to deal with different sized buffers */ - void (*get_rx) (u32 rx_data, struct mpc8xxx_spi *); - u32 (*get_tx) (struct mpc8xxx_spi *); - u32 rx_shift; /* RX data reg shift when in qe mode */ - u32 tx_shift; /* TX data reg shift when in qe mode */ - u32 hw_mode; /* Holds HW mode register settings */ -}; - -static inline void mpc8xxx_spi_write_reg(__be32 __iomem *reg, u32 val) -{ - out_be32(reg, val); -} - -static inline u32 mpc8xxx_spi_read_reg(__be32 __iomem *reg) -{ - return in_be32(reg); -} - -#define MPC83XX_SPI_RX_BUF(type) \ -static \ -void mpc8xxx_spi_rx_buf_##type(u32 data, struct mpc8xxx_spi *mpc8xxx_spi) \ -{ \ - type *rx = mpc8xxx_spi->rx; \ - *rx++ = (type)(data >> mpc8xxx_spi->rx_shift); \ - mpc8xxx_spi->rx = rx; \ -} - -#define MPC83XX_SPI_TX_BUF(type) \ -static \ -u32 mpc8xxx_spi_tx_buf_##type(struct mpc8xxx_spi *mpc8xxx_spi) \ -{ \ - u32 data; \ - const type *tx = mpc8xxx_spi->tx; \ - if (!tx) \ - return 0; \ - data = *tx++ << mpc8xxx_spi->tx_shift; \ - mpc8xxx_spi->tx = tx; \ - return data; \ -} +static void *fsl_dummy_rx; +static DEFINE_MUTEX(fsl_dummy_rx_lock); +static int fsl_dummy_rx_refcnt; -MPC83XX_SPI_RX_BUF(u8) -MPC83XX_SPI_RX_BUF(u16) -MPC83XX_SPI_RX_BUF(u32) -MPC83XX_SPI_TX_BUF(u8) -MPC83XX_SPI_TX_BUF(u16) -MPC83XX_SPI_TX_BUF(u32) - -static void mpc8xxx_spi_change_mode(struct spi_device *spi) +static void fsl_spi_change_mode(struct spi_device *spi) { struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master); struct spi_mpc8xxx_cs *cs = spi->controller_state; - __be32 __iomem *mode = &mspi->base->mode; + struct fsl_spi_reg *reg_base = mspi->reg_base; + __be32 __iomem *mode = ®_base->mode; unsigned long flags; if (cs->hw_mode == mpc8xxx_spi_read_reg(mode)) @@ -238,7 +136,7 @@ static void mpc8xxx_spi_change_mode(struct spi_device *spi) local_irq_restore(flags); } -static void mpc8xxx_spi_chipselect(struct spi_device *spi, int value) +static void fsl_spi_chipselect(struct spi_device *spi, int value) { struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master); struct fsl_spi_platform_data *pdata = spi->dev.parent->platform_data; @@ -256,18 +154,17 @@ static void mpc8xxx_spi_chipselect(struct spi_device *spi, int value) mpc8xxx_spi->get_rx = cs->get_rx; mpc8xxx_spi->get_tx = cs->get_tx; - mpc8xxx_spi_change_mode(spi); + fsl_spi_change_mode(spi); if (pdata->cs_control) pdata->cs_control(spi, pol); } } -static int -mspi_apply_cpu_mode_quirks(struct spi_mpc8xxx_cs *cs, - struct spi_device *spi, - struct mpc8xxx_spi *mpc8xxx_spi, - int bits_per_word) +static int mspi_apply_cpu_mode_quirks(struct spi_mpc8xxx_cs *cs, + struct spi_device *spi, + struct mpc8xxx_spi *mpc8xxx_spi, + int bits_per_word) { cs->rx_shift = 0; cs->tx_shift = 0; @@ -307,10 +204,9 @@ mspi_apply_cpu_mode_quirks(struct spi_mpc8xxx_cs *cs, return bits_per_word; } -static int -mspi_apply_qe_mode_quirks(struct spi_mpc8xxx_cs *cs, - struct spi_device *spi, - int bits_per_word) +static int mspi_apply_qe_mode_quirks(struct spi_mpc8xxx_cs *cs, + struct spi_device *spi, + int bits_per_word) { /* QE uses Little Endian for words > 8 * so transform all words > 8 into 8 bits @@ -326,13 +222,13 @@ mspi_apply_qe_mode_quirks(struct spi_mpc8xxx_cs *cs, return bits_per_word; } -static -int mpc8xxx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) +static int fsl_spi_setup_transfer(struct spi_device *spi, + struct spi_transfer *t) { struct mpc8xxx_spi *mpc8xxx_spi; - int bits_per_word; + int bits_per_word = 0; u8 pm; - u32 hz; + u32 hz = 0; struct spi_mpc8xxx_cs *cs = spi->controller_state; mpc8xxx_spi = spi_master_get_devdata(spi->master); @@ -340,9 +236,6 @@ int mpc8xxx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) if (t) { bits_per_word = t->bits_per_word; hz = t->speed_hz; - } else { - bits_per_word = 0; - hz = 0; } /* spi_transfer level calls that work per-word */ @@ -388,23 +281,25 @@ int mpc8xxx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) hz, mpc8xxx_spi->spibrg / 1024); if (pm > 16) pm = 16; - } else + } else { pm = (mpc8xxx_spi->spibrg - 1) / (hz * 4) + 1; + } if (pm) pm--; cs->hw_mode |= SPMODE_PM(pm); - mpc8xxx_spi_change_mode(spi); + fsl_spi_change_mode(spi); return 0; } -static void mpc8xxx_spi_cpm_bufs_start(struct mpc8xxx_spi *mspi) +static void fsl_spi_cpm_bufs_start(struct mpc8xxx_spi *mspi) { struct cpm_buf_desc __iomem *tx_bd = mspi->tx_bd; struct cpm_buf_desc __iomem *rx_bd = mspi->rx_bd; unsigned int xfer_len = min(mspi->count, SPI_MRBLR); unsigned int xfer_ofs; + struct fsl_spi_reg *reg_base = mspi->reg_base; xfer_ofs = mspi->xfer_in_progress->len - mspi->count; @@ -424,13 +319,14 @@ static void mpc8xxx_spi_cpm_bufs_start(struct mpc8xxx_spi *mspi) BD_SC_LAST); /* start transfer */ - mpc8xxx_spi_write_reg(&mspi->base->command, SPCOM_STR); + mpc8xxx_spi_write_reg(®_base->command, SPCOM_STR); } -static int mpc8xxx_spi_cpm_bufs(struct mpc8xxx_spi *mspi, +static int fsl_spi_cpm_bufs(struct mpc8xxx_spi *mspi, struct spi_transfer *t, bool is_dma_mapped) { struct device *dev = mspi->dev; + struct fsl_spi_reg *reg_base = mspi->reg_base; if (is_dma_mapped) { mspi->map_tx_dma = 0; @@ -475,13 +371,13 @@ static int mpc8xxx_spi_cpm_bufs(struct mpc8xxx_spi *mspi, } /* enable rx ints */ - mpc8xxx_spi_write_reg(&mspi->base->mask, SPIE_RXB); + mpc8xxx_spi_write_reg(®_base->mask, SPIE_RXB); mspi->xfer_in_progress = t; mspi->count = t->len; /* start CPM transfers */ - mpc8xxx_spi_cpm_bufs_start(mspi); + fsl_spi_cpm_bufs_start(mspi); return 0; @@ -491,7 +387,7 @@ err_rx_dma: return -ENOMEM; } -static void mpc8xxx_spi_cpm_bufs_complete(struct mpc8xxx_spi *mspi) +static void fsl_spi_cpm_bufs_complete(struct mpc8xxx_spi *mspi) { struct device *dev = mspi->dev; struct spi_transfer *t = mspi->xfer_in_progress; @@ -503,31 +399,34 @@ static void mpc8xxx_spi_cpm_bufs_complete(struct mpc8xxx_spi *mspi) mspi->xfer_in_progress = NULL; } -static int mpc8xxx_spi_cpu_bufs(struct mpc8xxx_spi *mspi, +static int fsl_spi_cpu_bufs(struct mpc8xxx_spi *mspi, struct spi_transfer *t, unsigned int len) { u32 word; + struct fsl_spi_reg *reg_base = mspi->reg_base; mspi->count = len; /* enable rx ints */ - mpc8xxx_spi_write_reg(&mspi->base->mask, SPIM_NE); + mpc8xxx_spi_write_reg(®_base->mask, SPIM_NE); /* transmit word */ word = mspi->get_tx(mspi); - mpc8xxx_spi_write_reg(&mspi->base->transmit, word); + mpc8xxx_spi_write_reg(®_base->transmit, word); return 0; } -static int mpc8xxx_spi_bufs(struct spi_device *spi, struct spi_transfer *t, +static int fsl_spi_bufs(struct spi_device *spi, struct spi_transfer *t, bool is_dma_mapped) { struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master); + struct fsl_spi_reg *reg_base; unsigned int len = t->len; u8 bits_per_word; int ret; + reg_base = mpc8xxx_spi->reg_base; bits_per_word = spi->bits_per_word; if (t->bits_per_word) bits_per_word = t->bits_per_word; @@ -551,24 +450,24 @@ static int mpc8xxx_spi_bufs(struct spi_device *spi, struct spi_transfer *t, INIT_COMPLETION(mpc8xxx_spi->done); if (mpc8xxx_spi->flags & SPI_CPM_MODE) - ret = mpc8xxx_spi_cpm_bufs(mpc8xxx_spi, t, is_dma_mapped); + ret = fsl_spi_cpm_bufs(mpc8xxx_spi, t, is_dma_mapped); else - ret = mpc8xxx_spi_cpu_bufs(mpc8xxx_spi, t, len); + ret = fsl_spi_cpu_bufs(mpc8xxx_spi, t, len); if (ret) return ret; wait_for_completion(&mpc8xxx_spi->done); /* disable rx ints */ - mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mask, 0); + mpc8xxx_spi_write_reg(®_base->mask, 0); if (mpc8xxx_spi->flags & SPI_CPM_MODE) - mpc8xxx_spi_cpm_bufs_complete(mpc8xxx_spi); + fsl_spi_cpm_bufs_complete(mpc8xxx_spi); return mpc8xxx_spi->count; } -static void mpc8xxx_spi_do_one_msg(struct spi_message *m) +static void fsl_spi_do_one_msg(struct spi_message *m) { struct spi_device *spi = m->spi; struct spi_transfer *t; @@ -584,18 +483,18 @@ static void mpc8xxx_spi_do_one_msg(struct spi_message *m) status = -EINVAL; if (cs_change) - status = mpc8xxx_spi_setup_transfer(spi, t); + status = fsl_spi_setup_transfer(spi, t); if (status < 0) break; } if (cs_change) { - mpc8xxx_spi_chipselect(spi, BITBANG_CS_ACTIVE); + fsl_spi_chipselect(spi, BITBANG_CS_ACTIVE); ndelay(nsecs); } cs_change = t->cs_change; if (t->len) - status = mpc8xxx_spi_bufs(spi, t, m->is_dma_mapped); + status = fsl_spi_bufs(spi, t, m->is_dma_mapped); if (status) { status = -EMSGSIZE; break; @@ -607,7 +506,7 @@ static void mpc8xxx_spi_do_one_msg(struct spi_message *m) if (cs_change) { ndelay(nsecs); - mpc8xxx_spi_chipselect(spi, BITBANG_CS_INACTIVE); + fsl_spi_chipselect(spi, BITBANG_CS_INACTIVE); ndelay(nsecs); } } @@ -617,35 +516,16 @@ static void mpc8xxx_spi_do_one_msg(struct spi_message *m) if (status || !cs_change) { ndelay(nsecs); - mpc8xxx_spi_chipselect(spi, BITBANG_CS_INACTIVE); + fsl_spi_chipselect(spi, BITBANG_CS_INACTIVE); } - mpc8xxx_spi_setup_transfer(spi, NULL); -} - -static void mpc8xxx_spi_work(struct work_struct *work) -{ - struct mpc8xxx_spi *mpc8xxx_spi = container_of(work, struct mpc8xxx_spi, - work); - - spin_lock_irq(&mpc8xxx_spi->lock); - while (!list_empty(&mpc8xxx_spi->queue)) { - struct spi_message *m = container_of(mpc8xxx_spi->queue.next, - struct spi_message, queue); - - list_del_init(&m->queue); - spin_unlock_irq(&mpc8xxx_spi->lock); - - mpc8xxx_spi_do_one_msg(m); - - spin_lock_irq(&mpc8xxx_spi->lock); - } - spin_unlock_irq(&mpc8xxx_spi->lock); + fsl_spi_setup_transfer(spi, NULL); } -static int mpc8xxx_spi_setup(struct spi_device *spi) +static int fsl_spi_setup(struct spi_device *spi) { struct mpc8xxx_spi *mpc8xxx_spi; + struct fsl_spi_reg *reg_base; int retval; u32 hw_mode; struct spi_mpc8xxx_cs *cs = spi->controller_state; @@ -661,8 +541,10 @@ static int mpc8xxx_spi_setup(struct spi_device *spi) } mpc8xxx_spi = spi_master_get_devdata(spi->master); + reg_base = mpc8xxx_spi->reg_base; + hw_mode = cs->hw_mode; /* Save original settings */ - cs->hw_mode = mpc8xxx_spi_read_reg(&mpc8xxx_spi->base->mode); + cs->hw_mode = mpc8xxx_spi_read_reg(®_base->mode); /* mask out bits we are going to set */ cs->hw_mode &= ~(SPMODE_CP_BEGIN_EDGECLK | SPMODE_CI_INACTIVEHIGH | SPMODE_REV | SPMODE_LOOP); @@ -676,7 +558,7 @@ static int mpc8xxx_spi_setup(struct spi_device *spi) if (spi->mode & SPI_LOOP) cs->hw_mode |= SPMODE_LOOP; - retval = mpc8xxx_spi_setup_transfer(spi, NULL); + retval = fsl_spi_setup_transfer(spi, NULL); if (retval < 0) { cs->hw_mode = hw_mode; /* Restore settings */ return retval; @@ -684,9 +566,10 @@ static int mpc8xxx_spi_setup(struct spi_device *spi) return 0; } -static void mpc8xxx_spi_cpm_irq(struct mpc8xxx_spi *mspi, u32 events) +static void fsl_spi_cpm_irq(struct mpc8xxx_spi *mspi, u32 events) { u16 len; + struct fsl_spi_reg *reg_base = mspi->reg_base; dev_dbg(mspi->dev, "%s: bd datlen %d, count %d\n", __func__, in_be16(&mspi->rx_bd->cbd_datlen), mspi->count); @@ -698,20 +581,22 @@ static void mpc8xxx_spi_cpm_irq(struct mpc8xxx_spi *mspi, u32 events) } /* Clear the events */ - mpc8xxx_spi_write_reg(&mspi->base->event, events); + mpc8xxx_spi_write_reg(®_base->event, events); mspi->count -= len; if (mspi->count) - mpc8xxx_spi_cpm_bufs_start(mspi); + fsl_spi_cpm_bufs_start(mspi); else complete(&mspi->done); } -static void mpc8xxx_spi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events) +static void fsl_spi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events) { + struct fsl_spi_reg *reg_base = mspi->reg_base; + /* We need handle RX first */ if (events & SPIE_NE) { - u32 rx_data = mpc8xxx_spi_read_reg(&mspi->base->receive); + u32 rx_data = mpc8xxx_spi_read_reg(®_base->receive); if (mspi->rx) mspi->get_rx(rx_data, mspi); @@ -720,102 +605,80 @@ static void mpc8xxx_spi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events) if ((events & SPIE_NF) == 0) /* spin until TX is done */ while (((events = - mpc8xxx_spi_read_reg(&mspi->base->event)) & + mpc8xxx_spi_read_reg(®_base->event)) & SPIE_NF) == 0) cpu_relax(); /* Clear the events */ - mpc8xxx_spi_write_reg(&mspi->base->event, events); + mpc8xxx_spi_write_reg(®_base->event, events); mspi->count -= 1; if (mspi->count) { u32 word = mspi->get_tx(mspi); - mpc8xxx_spi_write_reg(&mspi->base->transmit, word); + mpc8xxx_spi_write_reg(®_base->transmit, word); } else { complete(&mspi->done); } } -static irqreturn_t mpc8xxx_spi_irq(s32 irq, void *context_data) +static irqreturn_t fsl_spi_irq(s32 irq, void *context_data) { struct mpc8xxx_spi *mspi = context_data; irqreturn_t ret = IRQ_NONE; u32 events; + struct fsl_spi_reg *reg_base = mspi->reg_base; /* Get interrupt events(tx/rx) */ - events = mpc8xxx_spi_read_reg(&mspi->base->event); + events = mpc8xxx_spi_read_reg(®_base->event); if (events) ret = IRQ_HANDLED; dev_dbg(mspi->dev, "%s: events %x\n", __func__, events); if (mspi->flags & SPI_CPM_MODE) - mpc8xxx_spi_cpm_irq(mspi, events); + fsl_spi_cpm_irq(mspi, events); else - mpc8xxx_spi_cpu_irq(mspi, events); + fsl_spi_cpu_irq(mspi, events); return ret; } -static int mpc8xxx_spi_transfer(struct spi_device *spi, - struct spi_message *m) +static void *fsl_spi_alloc_dummy_rx(void) { - struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master); - unsigned long flags; + mutex_lock(&fsl_dummy_rx_lock); - m->actual_length = 0; - m->status = -EINPROGRESS; + if (!fsl_dummy_rx) + fsl_dummy_rx = kmalloc(SPI_MRBLR, GFP_KERNEL); + if (fsl_dummy_rx) + fsl_dummy_rx_refcnt++; - spin_lock_irqsave(&mpc8xxx_spi->lock, flags); - list_add_tail(&m->queue, &mpc8xxx_spi->queue); - queue_work(mpc8xxx_spi->workqueue, &mpc8xxx_spi->work); - spin_unlock_irqrestore(&mpc8xxx_spi->lock, flags); + mutex_unlock(&fsl_dummy_rx_lock); - return 0; + return fsl_dummy_rx; } - -static void mpc8xxx_spi_cleanup(struct spi_device *spi) +static void fsl_spi_free_dummy_rx(void) { - kfree(spi->controller_state); -} + mutex_lock(&fsl_dummy_rx_lock); -static void *mpc8xxx_spi_alloc_dummy_rx(void) -{ - mutex_lock(&mpc8xxx_dummy_rx_lock); - - if (!mpc8xxx_dummy_rx) - mpc8xxx_dummy_rx = kmalloc(SPI_MRBLR, GFP_KERNEL); - if (mpc8xxx_dummy_rx) - mpc8xxx_dummy_rx_refcnt++; - - mutex_unlock(&mpc8xxx_dummy_rx_lock); - - return mpc8xxx_dummy_rx; -} - -static void mpc8xxx_spi_free_dummy_rx(void) -{ - mutex_lock(&mpc8xxx_dummy_rx_lock); - - switch (mpc8xxx_dummy_rx_refcnt) { + switch (fsl_dummy_rx_refcnt) { case 0: WARN_ON(1); break; case 1: - kfree(mpc8xxx_dummy_rx); - mpc8xxx_dummy_rx = NULL; + kfree(fsl_dummy_rx); + fsl_dummy_rx = NULL; /* fall through */ default: - mpc8xxx_dummy_rx_refcnt--; + fsl_dummy_rx_refcnt--; break; } - mutex_unlock(&mpc8xxx_dummy_rx_lock); + mutex_unlock(&fsl_dummy_rx_lock); } -static unsigned long mpc8xxx_spi_cpm_get_pram(struct mpc8xxx_spi *mspi) +static unsigned long fsl_spi_cpm_get_pram(struct mpc8xxx_spi *mspi) { struct device *dev = mspi->dev; struct device_node *np = dev->of_node; @@ -869,7 +732,7 @@ static unsigned long mpc8xxx_spi_cpm_get_pram(struct mpc8xxx_spi *mspi) return pram_ofs; } -static int mpc8xxx_spi_cpm_init(struct mpc8xxx_spi *mspi) +static int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi) { struct device *dev = mspi->dev; struct device_node *np = dev->of_node; @@ -881,7 +744,7 @@ static int mpc8xxx_spi_cpm_init(struct mpc8xxx_spi *mspi) if (!(mspi->flags & SPI_CPM_MODE)) return 0; - if (!mpc8xxx_spi_alloc_dummy_rx()) + if (!fsl_spi_alloc_dummy_rx()) return -ENOMEM; if (mspi->flags & SPI_QE) { @@ -902,7 +765,7 @@ static int mpc8xxx_spi_cpm_init(struct mpc8xxx_spi *mspi) } } - pram_ofs = mpc8xxx_spi_cpm_get_pram(mspi); + pram_ofs = fsl_spi_cpm_get_pram(mspi); if (IS_ERR_VALUE(pram_ofs)) { dev_err(dev, "can't allocate spi parameter ram\n"); goto err_pram; @@ -922,7 +785,7 @@ static int mpc8xxx_spi_cpm_init(struct mpc8xxx_spi *mspi) goto err_dummy_tx; } - mspi->dma_dummy_rx = dma_map_single(dev, mpc8xxx_dummy_rx, SPI_MRBLR, + mspi->dma_dummy_rx = dma_map_single(dev, fsl_dummy_rx, SPI_MRBLR, DMA_FROM_DEVICE); if (dma_mapping_error(dev, mspi->dma_dummy_rx)) { dev_err(dev, "unable to map dummy rx buffer\n"); @@ -960,11 +823,11 @@ err_dummy_tx: err_bds: cpm_muram_free(pram_ofs); err_pram: - mpc8xxx_spi_free_dummy_rx(); + fsl_spi_free_dummy_rx(); return -ENOMEM; } -static void mpc8xxx_spi_cpm_free(struct mpc8xxx_spi *mspi) +static void fsl_spi_cpm_free(struct mpc8xxx_spi *mspi) { struct device *dev = mspi->dev; @@ -972,30 +835,22 @@ static void mpc8xxx_spi_cpm_free(struct mpc8xxx_spi *mspi) dma_unmap_single(dev, mspi->dma_dummy_tx, PAGE_SIZE, DMA_TO_DEVICE); cpm_muram_free(cpm_muram_offset(mspi->tx_bd)); cpm_muram_free(cpm_muram_offset(mspi->pram)); - mpc8xxx_spi_free_dummy_rx(); + fsl_spi_free_dummy_rx(); } -static const char *mpc8xxx_spi_strmode(unsigned int flags) +static void fsl_spi_remove(struct mpc8xxx_spi *mspi) { - if (flags & SPI_QE_CPU_MODE) { - return "QE CPU"; - } else if (flags & SPI_CPM_MODE) { - if (flags & SPI_QE) - return "QE"; - else if (flags & SPI_CPM2) - return "CPM2"; - else - return "CPM1"; - } - return "CPU"; + iounmap(mspi->reg_base); + fsl_spi_cpm_free(mspi); } -static struct spi_master * __devinit -mpc8xxx_spi_probe(struct device *dev, struct resource *mem, unsigned int irq) +static struct spi_master * __devinit fsl_spi_probe(struct device *dev, + struct resource *mem, unsigned int irq) { struct fsl_spi_platform_data *pdata = dev->platform_data; struct spi_master *master; struct mpc8xxx_spi *mpc8xxx_spi; + struct fsl_spi_reg *reg_base; u32 regval; int ret = 0; @@ -1007,132 +862,77 @@ mpc8xxx_spi_probe(struct device *dev, struct resource *mem, unsigned int irq) dev_set_drvdata(dev, master); - /* the spi->mode bits understood by this driver: */ - master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH - | SPI_LSB_FIRST | SPI_LOOP; + ret = mpc8xxx_spi_probe(dev, mem, irq); + if (ret) + goto err_probe; - master->setup = mpc8xxx_spi_setup; - master->transfer = mpc8xxx_spi_transfer; - master->cleanup = mpc8xxx_spi_cleanup; - master->dev.of_node = dev->of_node; + master->setup = fsl_spi_setup; mpc8xxx_spi = spi_master_get_devdata(master); - mpc8xxx_spi->dev = dev; - mpc8xxx_spi->get_rx = mpc8xxx_spi_rx_buf_u8; - mpc8xxx_spi->get_tx = mpc8xxx_spi_tx_buf_u8; - mpc8xxx_spi->flags = pdata->flags; - mpc8xxx_spi->spibrg = pdata->sysclk; + mpc8xxx_spi->spi_do_one_msg = fsl_spi_do_one_msg; + mpc8xxx_spi->spi_remove = fsl_spi_remove; + - ret = mpc8xxx_spi_cpm_init(mpc8xxx_spi); + ret = fsl_spi_cpm_init(mpc8xxx_spi); if (ret) goto err_cpm_init; - mpc8xxx_spi->rx_shift = 0; - mpc8xxx_spi->tx_shift = 0; if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) { mpc8xxx_spi->rx_shift = 16; mpc8xxx_spi->tx_shift = 24; } - init_completion(&mpc8xxx_spi->done); - - mpc8xxx_spi->base = ioremap(mem->start, resource_size(mem)); - if (mpc8xxx_spi->base == NULL) { + mpc8xxx_spi->reg_base = ioremap(mem->start, resource_size(mem)); + if (mpc8xxx_spi->reg_base == NULL) { ret = -ENOMEM; goto err_ioremap; } - mpc8xxx_spi->irq = irq; - /* Register for SPI Interrupt */ - ret = request_irq(mpc8xxx_spi->irq, mpc8xxx_spi_irq, - 0, "mpc8xxx_spi", mpc8xxx_spi); + ret = request_irq(mpc8xxx_spi->irq, fsl_spi_irq, + 0, "fsl_spi", mpc8xxx_spi); if (ret != 0) - goto unmap_io; + goto free_irq; - master->bus_num = pdata->bus_num; - master->num_chipselect = pdata->max_chipselect; + reg_base = mpc8xxx_spi->reg_base; /* SPI controller initializations */ - mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mode, 0); - mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mask, 0); - mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->command, 0); - mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->event, 0xffffffff); + mpc8xxx_spi_write_reg(®_base->mode, 0); + mpc8xxx_spi_write_reg(®_base->mask, 0); + mpc8xxx_spi_write_reg(®_base->command, 0); + mpc8xxx_spi_write_reg(®_base->event, 0xffffffff); /* Enable SPI interface */ regval = pdata->initial_spmode | SPMODE_INIT_VAL | SPMODE_ENABLE; if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) regval |= SPMODE_OP; - mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mode, regval); - spin_lock_init(&mpc8xxx_spi->lock); - init_completion(&mpc8xxx_spi->done); - INIT_WORK(&mpc8xxx_spi->work, mpc8xxx_spi_work); - INIT_LIST_HEAD(&mpc8xxx_spi->queue); - - mpc8xxx_spi->workqueue = create_singlethread_workqueue( - dev_name(master->dev.parent)); - if (mpc8xxx_spi->workqueue == NULL) { - ret = -EBUSY; - goto free_irq; - } + mpc8xxx_spi_write_reg(®_base->mode, regval); ret = spi_register_master(master); if (ret < 0) goto unreg_master; - dev_info(dev, "at 0x%p (irq = %d), %s mode\n", mpc8xxx_spi->base, + dev_info(dev, "at 0x%p (irq = %d), %s mode\n", reg_base, mpc8xxx_spi->irq, mpc8xxx_spi_strmode(mpc8xxx_spi->flags)); return master; unreg_master: - destroy_workqueue(mpc8xxx_spi->workqueue); -free_irq: free_irq(mpc8xxx_spi->irq, mpc8xxx_spi); -unmap_io: - iounmap(mpc8xxx_spi->base); +free_irq: + iounmap(mpc8xxx_spi->reg_base); err_ioremap: - mpc8xxx_spi_cpm_free(mpc8xxx_spi); + fsl_spi_cpm_free(mpc8xxx_spi); err_cpm_init: +err_probe: spi_master_put(master); err: return ERR_PTR(ret); } -static int __devexit mpc8xxx_spi_remove(struct device *dev) -{ - struct mpc8xxx_spi *mpc8xxx_spi; - struct spi_master *master; - - master = dev_get_drvdata(dev); - mpc8xxx_spi = spi_master_get_devdata(master); - - flush_workqueue(mpc8xxx_spi->workqueue); - destroy_workqueue(mpc8xxx_spi->workqueue); - spi_unregister_master(master); - - free_irq(mpc8xxx_spi->irq, mpc8xxx_spi); - iounmap(mpc8xxx_spi->base); - mpc8xxx_spi_cpm_free(mpc8xxx_spi); - - return 0; -} - -struct mpc8xxx_spi_probe_info { - struct fsl_spi_platform_data pdata; - int *gpios; - bool *alow_flags; -}; - -static struct mpc8xxx_spi_probe_info * -to_of_pinfo(struct fsl_spi_platform_data *pdata) -{ - return container_of(pdata, struct mpc8xxx_spi_probe_info, pdata); -} - -static void mpc8xxx_spi_cs_control(struct spi_device *spi, bool on) +static void fsl_spi_cs_control(struct spi_device *spi, bool on) { struct device *dev = spi->dev.parent; struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(dev->platform_data); @@ -1143,7 +943,7 @@ static void mpc8xxx_spi_cs_control(struct spi_device *spi, bool on) gpio_set_value(gpio, on ^ alow); } -static int of_mpc8xxx_spi_get_chipselects(struct device *dev) +static int of_fsl_spi_get_chipselects(struct device *dev) { struct device_node *np = dev->of_node; struct fsl_spi_platform_data *pdata = dev->platform_data; @@ -1204,7 +1004,7 @@ static int of_mpc8xxx_spi_get_chipselects(struct device *dev) } pdata->max_chipselect = ngpios; - pdata->cs_control = mpc8xxx_spi_cs_control; + pdata->cs_control = fsl_spi_cs_control; return 0; @@ -1223,7 +1023,7 @@ err_alloc_flags: return ret; } -static int of_mpc8xxx_spi_free_chipselects(struct device *dev) +static int of_fsl_spi_free_chipselects(struct device *dev) { struct fsl_spi_platform_data *pdata = dev->platform_data; struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata); @@ -1242,50 +1042,21 @@ static int of_mpc8xxx_spi_free_chipselects(struct device *dev) return 0; } -static int __devinit of_mpc8xxx_spi_probe(struct platform_device *ofdev, - const struct of_device_id *ofid) +static int __devinit of_fsl_spi_probe(struct platform_device *ofdev, + const struct of_device_id *ofid) { struct device *dev = &ofdev->dev; struct device_node *np = ofdev->dev.of_node; - struct mpc8xxx_spi_probe_info *pinfo; - struct fsl_spi_platform_data *pdata; struct spi_master *master; struct resource mem; struct resource irq; - const void *prop; int ret = -ENOMEM; - pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL); - if (!pinfo) - return -ENOMEM; - - pdata = &pinfo->pdata; - dev->platform_data = pdata; - - /* Allocate bus num dynamically. */ - pdata->bus_num = -1; - - /* SPI controller is either clocked from QE or SoC clock. */ - pdata->sysclk = get_brgfreq(); - if (pdata->sysclk == -1) { - pdata->sysclk = fsl_get_sys_freq(); - if (pdata->sysclk == -1) { - ret = -ENODEV; - goto err_clk; - } - } + ret = of_mpc8xxx_spi_probe(ofdev, ofid); + if (ret) + return ret; - prop = of_get_property(np, "mode", NULL); - if (prop && !strcmp(prop, "cpu-qe")) - pdata->flags = SPI_QE_CPU_MODE; - else if (prop && !strcmp(prop, "qe")) - pdata->flags = SPI_CPM_MODE | SPI_QE; - else if (of_device_is_compatible(np, "fsl,cpm2-spi")) - pdata->flags = SPI_CPM_MODE | SPI_CPM2; - else if (of_device_is_compatible(np, "fsl,cpm1-spi")) - pdata->flags = SPI_CPM_MODE | SPI_CPM1; - - ret = of_mpc8xxx_spi_get_chipselects(dev); + ret = of_fsl_spi_get_chipselects(dev); if (ret) goto err; @@ -1299,7 +1070,7 @@ static int __devinit of_mpc8xxx_spi_probe(struct platform_device *ofdev, goto err; } - master = mpc8xxx_spi_probe(dev, &mem, irq.start); + master = fsl_spi_probe(dev, &mem, irq.start); if (IS_ERR(master)) { ret = PTR_ERR(master); goto err; @@ -1308,42 +1079,40 @@ static int __devinit of_mpc8xxx_spi_probe(struct platform_device *ofdev, return 0; err: - of_mpc8xxx_spi_free_chipselects(dev); -err_clk: - kfree(pinfo); + of_fsl_spi_free_chipselects(dev); return ret; } -static int __devexit of_mpc8xxx_spi_remove(struct platform_device *ofdev) +static int __devexit of_fsl_spi_remove(struct platform_device *ofdev) { int ret; ret = mpc8xxx_spi_remove(&ofdev->dev); if (ret) return ret; - of_mpc8xxx_spi_free_chipselects(&ofdev->dev); + of_fsl_spi_free_chipselects(&ofdev->dev); return 0; } -static const struct of_device_id of_mpc8xxx_spi_match[] = { +static const struct of_device_id of_fsl_spi_match[] = { { .compatible = "fsl,spi" }, - {}, + {} }; -MODULE_DEVICE_TABLE(of, of_mpc8xxx_spi_match); +MODULE_DEVICE_TABLE(of, of_fsl_spi_match); -static struct of_platform_driver of_mpc8xxx_spi_driver = { +static struct of_platform_driver of_fsl_spi_driver = { .driver = { - .name = "mpc8xxx_spi", + .name = "fsl_spi", .owner = THIS_MODULE, - .of_match_table = of_mpc8xxx_spi_match, + .of_match_table = of_fsl_spi_match, }, - .probe = of_mpc8xxx_spi_probe, - .remove = __devexit_p(of_mpc8xxx_spi_remove), + .probe = of_fsl_spi_probe, + .remove = __devexit_p(of_fsl_spi_remove), }; #ifdef CONFIG_MPC832x_RDB /* - * XXX XXX XXX + * XXX XXX XXX * This is "legacy" platform driver, was used by the MPC8323E-RDB boards * only. The driver should go away soon, since newer MPC8323E-RDB's device * tree can work with OpenFirmware driver. But for now we support old trees @@ -1366,7 +1135,7 @@ static int __devinit plat_mpc8xxx_spi_probe(struct platform_device *pdev) if (irq <= 0) return -EINVAL; - master = mpc8xxx_spi_probe(&pdev->dev, mem, irq); + master = fsl_spi_probe(&pdev->dev, mem, irq); if (IS_ERR(master)) return PTR_ERR(master); return 0; @@ -1405,21 +1174,20 @@ static void __init legacy_driver_register(void) {} static void __exit legacy_driver_unregister(void) {} #endif /* CONFIG_MPC832x_RDB */ -static int __init mpc8xxx_spi_init(void) +static int __init fsl_spi_init(void) { legacy_driver_register(); - return of_register_platform_driver(&of_mpc8xxx_spi_driver); + return of_register_platform_driver(&of_fsl_spi_driver); } +module_init(fsl_spi_init); -static void __exit mpc8xxx_spi_exit(void) +static void __exit fsl_spi_exit(void) { - of_unregister_platform_driver(&of_mpc8xxx_spi_driver); + of_unregister_platform_driver(&of_fsl_spi_driver); legacy_driver_unregister(); } - -module_init(mpc8xxx_spi_init); -module_exit(mpc8xxx_spi_exit); +module_exit(fsl_spi_exit); MODULE_AUTHOR("Kumar Gala"); -MODULE_DESCRIPTION("Simple MPC8xxx SPI Driver"); +MODULE_DESCRIPTION("Simple Freescale SPI Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/spi/spi_imx.c b/drivers/spi/spi_imx.c index 7972e9077473..55a38e2c6c13 100644 --- a/drivers/spi/spi_imx.c +++ b/drivers/spi/spi_imx.c @@ -56,7 +56,28 @@ struct spi_imx_config { unsigned int speed_hz; unsigned int bpw; unsigned int mode; - int cs; + u8 cs; +}; + +enum spi_imx_devtype { + SPI_IMX_VER_IMX1, + SPI_IMX_VER_0_0, + SPI_IMX_VER_0_4, + SPI_IMX_VER_0_5, + SPI_IMX_VER_0_7, + SPI_IMX_VER_2_3, + SPI_IMX_VER_AUTODETECT, +}; + +struct spi_imx_data; + +struct spi_imx_devtype_data { + void (*intctrl)(struct spi_imx_data *, int); + int (*config)(struct spi_imx_data *, struct spi_imx_config *); + void (*trigger)(struct spi_imx_data *); + int (*rx_available)(struct spi_imx_data *); + void (*reset)(struct spi_imx_data *); + unsigned int fifosize; }; struct spi_imx_data { @@ -76,11 +97,7 @@ struct spi_imx_data { const void *tx_buf; unsigned int txfifo; /* number of words pushed in tx FIFO */ - /* SoC specific functions */ - void (*intctrl)(struct spi_imx_data *, int); - int (*config)(struct spi_imx_data *, struct spi_imx_config *); - void (*trigger)(struct spi_imx_data *); - int (*rx_available)(struct spi_imx_data *); + struct spi_imx_devtype_data devtype_data; }; #define MXC_SPI_BUF_RX(type) \ @@ -140,7 +157,7 @@ static unsigned int spi_imx_clkdiv_1(unsigned int fin, return max; } -/* MX1, MX31, MX35 */ +/* MX1, MX31, MX35, MX51 CSPI */ static unsigned int spi_imx_clkdiv_2(unsigned int fin, unsigned int fspi) { @@ -155,6 +172,128 @@ static unsigned int spi_imx_clkdiv_2(unsigned int fin, return 7; } +#define SPI_IMX2_3_CTRL 0x08 +#define SPI_IMX2_3_CTRL_ENABLE (1 << 0) +#define SPI_IMX2_3_CTRL_XCH (1 << 2) +#define SPI_IMX2_3_CTRL_MODE(cs) (1 << ((cs) + 4)) +#define SPI_IMX2_3_CTRL_POSTDIV_OFFSET 8 +#define SPI_IMX2_3_CTRL_PREDIV_OFFSET 12 +#define SPI_IMX2_3_CTRL_CS(cs) ((cs) << 18) +#define SPI_IMX2_3_CTRL_BL_OFFSET 20 + +#define SPI_IMX2_3_CONFIG 0x0c +#define SPI_IMX2_3_CONFIG_SCLKPHA(cs) (1 << ((cs) + 0)) +#define SPI_IMX2_3_CONFIG_SCLKPOL(cs) (1 << ((cs) + 4)) +#define SPI_IMX2_3_CONFIG_SBBCTRL(cs) (1 << ((cs) + 8)) +#define SPI_IMX2_3_CONFIG_SSBPOL(cs) (1 << ((cs) + 12)) + +#define SPI_IMX2_3_INT 0x10 +#define SPI_IMX2_3_INT_TEEN (1 << 0) +#define SPI_IMX2_3_INT_RREN (1 << 3) + +#define SPI_IMX2_3_STAT 0x18 +#define SPI_IMX2_3_STAT_RR (1 << 3) + +/* MX51 eCSPI */ +static unsigned int spi_imx2_3_clkdiv(unsigned int fin, unsigned int fspi) +{ + /* + * there are two 4-bit dividers, the pre-divider divides by + * $pre, the post-divider by 2^$post + */ + unsigned int pre, post; + + if (unlikely(fspi > fin)) + return 0; + + post = fls(fin) - fls(fspi); + if (fin > fspi << post) + post++; + + /* now we have: (fin <= fspi << post) with post being minimal */ + + post = max(4U, post) - 4; + if (unlikely(post > 0xf)) { + pr_err("%s: cannot set clock freq: %u (base freq: %u)\n", + __func__, fspi, fin); + return 0xff; + } + + pre = DIV_ROUND_UP(fin, fspi << post) - 1; + + pr_debug("%s: fin: %u, fspi: %u, post: %u, pre: %u\n", + __func__, fin, fspi, post, pre); + return (pre << SPI_IMX2_3_CTRL_PREDIV_OFFSET) | + (post << SPI_IMX2_3_CTRL_POSTDIV_OFFSET); +} + +static void __maybe_unused spi_imx2_3_intctrl(struct spi_imx_data *spi_imx, int enable) +{ + unsigned val = 0; + + if (enable & MXC_INT_TE) + val |= SPI_IMX2_3_INT_TEEN; + + if (enable & MXC_INT_RR) + val |= SPI_IMX2_3_INT_RREN; + + writel(val, spi_imx->base + SPI_IMX2_3_INT); +} + +static void __maybe_unused spi_imx2_3_trigger(struct spi_imx_data *spi_imx) +{ + u32 reg; + + reg = readl(spi_imx->base + SPI_IMX2_3_CTRL); + reg |= SPI_IMX2_3_CTRL_XCH; + writel(reg, spi_imx->base + SPI_IMX2_3_CTRL); +} + +static int __maybe_unused spi_imx2_3_config(struct spi_imx_data *spi_imx, + struct spi_imx_config *config) +{ + u32 ctrl = SPI_IMX2_3_CTRL_ENABLE, cfg = 0; + + /* set master mode */ + ctrl |= SPI_IMX2_3_CTRL_MODE(config->cs); + + /* set clock speed */ + ctrl |= spi_imx2_3_clkdiv(spi_imx->spi_clk, config->speed_hz); + + /* set chip select to use */ + ctrl |= SPI_IMX2_3_CTRL_CS(config->cs); + + ctrl |= (config->bpw - 1) << SPI_IMX2_3_CTRL_BL_OFFSET; + + cfg |= SPI_IMX2_3_CONFIG_SBBCTRL(config->cs); + + if (config->mode & SPI_CPHA) + cfg |= SPI_IMX2_3_CONFIG_SCLKPHA(config->cs); + + if (config->mode & SPI_CPOL) + cfg |= SPI_IMX2_3_CONFIG_SCLKPOL(config->cs); + + if (config->mode & SPI_CS_HIGH) + cfg |= SPI_IMX2_3_CONFIG_SSBPOL(config->cs); + + writel(ctrl, spi_imx->base + SPI_IMX2_3_CTRL); + writel(cfg, spi_imx->base + SPI_IMX2_3_CONFIG); + + return 0; +} + +static int __maybe_unused spi_imx2_3_rx_available(struct spi_imx_data *spi_imx) +{ + return readl(spi_imx->base + SPI_IMX2_3_STAT) & SPI_IMX2_3_STAT_RR; +} + +static void __maybe_unused spi_imx2_3_reset(struct spi_imx_data *spi_imx) +{ + /* drain receive buffer */ + while (spi_imx2_3_rx_available(spi_imx)) + readl(spi_imx->base + MXC_CSPIRXDATA); +} + #define MX31_INTREG_TEEN (1 << 0) #define MX31_INTREG_RREN (1 << 3) @@ -178,7 +317,7 @@ static unsigned int spi_imx_clkdiv_2(unsigned int fin, * the i.MX35 has a slightly different register layout for bits * we do not use here. */ -static void mx31_intctrl(struct spi_imx_data *spi_imx, int enable) +static void __maybe_unused mx31_intctrl(struct spi_imx_data *spi_imx, int enable) { unsigned int val = 0; @@ -190,7 +329,7 @@ static void mx31_intctrl(struct spi_imx_data *spi_imx, int enable) writel(val, spi_imx->base + MXC_CSPIINT); } -static void mx31_trigger(struct spi_imx_data *spi_imx) +static void __maybe_unused mx31_trigger(struct spi_imx_data *spi_imx) { unsigned int reg; @@ -199,20 +338,16 @@ static void mx31_trigger(struct spi_imx_data *spi_imx) writel(reg, spi_imx->base + MXC_CSPICTRL); } -static int mx31_config(struct spi_imx_data *spi_imx, +static int __maybe_unused spi_imx0_4_config(struct spi_imx_data *spi_imx, struct spi_imx_config *config) { unsigned int reg = MX31_CSPICTRL_ENABLE | MX31_CSPICTRL_MASTER; + int cs = spi_imx->chipselect[config->cs]; reg |= spi_imx_clkdiv_2(spi_imx->spi_clk, config->speed_hz) << MX31_CSPICTRL_DR_SHIFT; - if (cpu_is_mx31()) - reg |= (config->bpw - 1) << MX31_CSPICTRL_BC_SHIFT; - else if (cpu_is_mx25() || cpu_is_mx35()) { - reg |= (config->bpw - 1) << MX35_CSPICTRL_BL_SHIFT; - reg |= MX31_CSPICTRL_SSCTL; - } + reg |= (config->bpw - 1) << MX31_CSPICTRL_BC_SHIFT; if (config->mode & SPI_CPHA) reg |= MX31_CSPICTRL_PHA; @@ -220,23 +355,52 @@ static int mx31_config(struct spi_imx_data *spi_imx, reg |= MX31_CSPICTRL_POL; if (config->mode & SPI_CS_HIGH) reg |= MX31_CSPICTRL_SSPOL; - if (config->cs < 0) { - if (cpu_is_mx31()) - reg |= (config->cs + 32) << MX31_CSPICTRL_CS_SHIFT; - else if (cpu_is_mx25() || cpu_is_mx35()) - reg |= (config->cs + 32) << MX35_CSPICTRL_CS_SHIFT; - } + if (cs < 0) + reg |= (cs + 32) << MX31_CSPICTRL_CS_SHIFT; + + writel(reg, spi_imx->base + MXC_CSPICTRL); + + return 0; +} + +static int __maybe_unused spi_imx0_7_config(struct spi_imx_data *spi_imx, + struct spi_imx_config *config) +{ + unsigned int reg = MX31_CSPICTRL_ENABLE | MX31_CSPICTRL_MASTER; + int cs = spi_imx->chipselect[config->cs]; + + reg |= spi_imx_clkdiv_2(spi_imx->spi_clk, config->speed_hz) << + MX31_CSPICTRL_DR_SHIFT; + + reg |= (config->bpw - 1) << MX35_CSPICTRL_BL_SHIFT; + reg |= MX31_CSPICTRL_SSCTL; + + if (config->mode & SPI_CPHA) + reg |= MX31_CSPICTRL_PHA; + if (config->mode & SPI_CPOL) + reg |= MX31_CSPICTRL_POL; + if (config->mode & SPI_CS_HIGH) + reg |= MX31_CSPICTRL_SSPOL; + if (cs < 0) + reg |= (cs + 32) << MX35_CSPICTRL_CS_SHIFT; writel(reg, spi_imx->base + MXC_CSPICTRL); return 0; } -static int mx31_rx_available(struct spi_imx_data *spi_imx) +static int __maybe_unused mx31_rx_available(struct spi_imx_data *spi_imx) { return readl(spi_imx->base + MX31_CSPISTATUS) & MX31_STATUS_RR; } +static void __maybe_unused spi_imx0_4_reset(struct spi_imx_data *spi_imx) +{ + /* drain receive buffer */ + while (readl(spi_imx->base + MX3_CSPISTAT) & MX3_CSPISTAT_RR) + readl(spi_imx->base + MXC_CSPIRXDATA); +} + #define MX27_INTREG_RR (1 << 4) #define MX27_INTREG_TEEN (1 << 9) #define MX27_INTREG_RREN (1 << 13) @@ -250,7 +414,7 @@ static int mx31_rx_available(struct spi_imx_data *spi_imx) #define MX27_CSPICTRL_DR_SHIFT 14 #define MX27_CSPICTRL_CS_SHIFT 19 -static void mx27_intctrl(struct spi_imx_data *spi_imx, int enable) +static void __maybe_unused mx27_intctrl(struct spi_imx_data *spi_imx, int enable) { unsigned int val = 0; @@ -262,7 +426,7 @@ static void mx27_intctrl(struct spi_imx_data *spi_imx, int enable) writel(val, spi_imx->base + MXC_CSPIINT); } -static void mx27_trigger(struct spi_imx_data *spi_imx) +static void __maybe_unused mx27_trigger(struct spi_imx_data *spi_imx) { unsigned int reg; @@ -271,10 +435,11 @@ static void mx27_trigger(struct spi_imx_data *spi_imx) writel(reg, spi_imx->base + MXC_CSPICTRL); } -static int mx27_config(struct spi_imx_data *spi_imx, +static int __maybe_unused mx27_config(struct spi_imx_data *spi_imx, struct spi_imx_config *config) { unsigned int reg = MX27_CSPICTRL_ENABLE | MX27_CSPICTRL_MASTER; + int cs = spi_imx->chipselect[config->cs]; reg |= spi_imx_clkdiv_1(spi_imx->spi_clk, config->speed_hz) << MX27_CSPICTRL_DR_SHIFT; @@ -286,19 +451,24 @@ static int mx27_config(struct spi_imx_data *spi_imx, reg |= MX27_CSPICTRL_POL; if (config->mode & SPI_CS_HIGH) reg |= MX27_CSPICTRL_SSPOL; - if (config->cs < 0) - reg |= (config->cs + 32) << MX27_CSPICTRL_CS_SHIFT; + if (cs < 0) + reg |= (cs + 32) << MX27_CSPICTRL_CS_SHIFT; writel(reg, spi_imx->base + MXC_CSPICTRL); return 0; } -static int mx27_rx_available(struct spi_imx_data *spi_imx) +static int __maybe_unused mx27_rx_available(struct spi_imx_data *spi_imx) { return readl(spi_imx->base + MXC_CSPIINT) & MX27_INTREG_RR; } +static void __maybe_unused spi_imx0_0_reset(struct spi_imx_data *spi_imx) +{ + writel(1, spi_imx->base + MXC_RESET); +} + #define MX1_INTREG_RR (1 << 3) #define MX1_INTREG_TEEN (1 << 8) #define MX1_INTREG_RREN (1 << 11) @@ -310,7 +480,7 @@ static int mx27_rx_available(struct spi_imx_data *spi_imx) #define MX1_CSPICTRL_MASTER (1 << 10) #define MX1_CSPICTRL_DR_SHIFT 13 -static void mx1_intctrl(struct spi_imx_data *spi_imx, int enable) +static void __maybe_unused mx1_intctrl(struct spi_imx_data *spi_imx, int enable) { unsigned int val = 0; @@ -322,7 +492,7 @@ static void mx1_intctrl(struct spi_imx_data *spi_imx, int enable) writel(val, spi_imx->base + MXC_CSPIINT); } -static void mx1_trigger(struct spi_imx_data *spi_imx) +static void __maybe_unused mx1_trigger(struct spi_imx_data *spi_imx) { unsigned int reg; @@ -331,7 +501,7 @@ static void mx1_trigger(struct spi_imx_data *spi_imx) writel(reg, spi_imx->base + MXC_CSPICTRL); } -static int mx1_config(struct spi_imx_data *spi_imx, +static int __maybe_unused mx1_config(struct spi_imx_data *spi_imx, struct spi_imx_config *config) { unsigned int reg = MX1_CSPICTRL_ENABLE | MX1_CSPICTRL_MASTER; @@ -350,11 +520,73 @@ static int mx1_config(struct spi_imx_data *spi_imx, return 0; } -static int mx1_rx_available(struct spi_imx_data *spi_imx) +static int __maybe_unused mx1_rx_available(struct spi_imx_data *spi_imx) { return readl(spi_imx->base + MXC_CSPIINT) & MX1_INTREG_RR; } +static void __maybe_unused mx1_reset(struct spi_imx_data *spi_imx) +{ + writel(1, spi_imx->base + MXC_RESET); +} + +/* + * These version numbers are taken from the Freescale driver. Unfortunately it + * doesn't support i.MX1, so this entry doesn't match the scheme. :-( + */ +static struct spi_imx_devtype_data spi_imx_devtype_data[] __devinitdata = { +#ifdef CONFIG_SPI_IMX_VER_IMX1 + [SPI_IMX_VER_IMX1] = { + .intctrl = mx1_intctrl, + .config = mx1_config, + .trigger = mx1_trigger, + .rx_available = mx1_rx_available, + .reset = mx1_reset, + .fifosize = 8, + }, +#endif +#ifdef CONFIG_SPI_IMX_VER_0_0 + [SPI_IMX_VER_0_0] = { + .intctrl = mx27_intctrl, + .config = mx27_config, + .trigger = mx27_trigger, + .rx_available = mx27_rx_available, + .reset = spi_imx0_0_reset, + .fifosize = 8, + }, +#endif +#ifdef CONFIG_SPI_IMX_VER_0_4 + [SPI_IMX_VER_0_4] = { + .intctrl = mx31_intctrl, + .config = spi_imx0_4_config, + .trigger = mx31_trigger, + .rx_available = mx31_rx_available, + .reset = spi_imx0_4_reset, + .fifosize = 8, + }, +#endif +#ifdef CONFIG_SPI_IMX_VER_0_7 + [SPI_IMX_VER_0_7] = { + .intctrl = mx31_intctrl, + .config = spi_imx0_7_config, + .trigger = mx31_trigger, + .rx_available = mx31_rx_available, + .reset = spi_imx0_4_reset, + .fifosize = 8, + }, +#endif +#ifdef CONFIG_SPI_IMX_VER_2_3 + [SPI_IMX_VER_2_3] = { + .intctrl = spi_imx2_3_intctrl, + .config = spi_imx2_3_config, + .trigger = spi_imx2_3_trigger, + .rx_available = spi_imx2_3_rx_available, + .reset = spi_imx2_3_reset, + .fifosize = 64, + }, +#endif +}; + static void spi_imx_chipselect(struct spi_device *spi, int is_active) { struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master); @@ -370,21 +602,21 @@ static void spi_imx_chipselect(struct spi_device *spi, int is_active) static void spi_imx_push(struct spi_imx_data *spi_imx) { - while (spi_imx->txfifo < 8) { + while (spi_imx->txfifo < spi_imx->devtype_data.fifosize) { if (!spi_imx->count) break; spi_imx->tx(spi_imx); spi_imx->txfifo++; } - spi_imx->trigger(spi_imx); + spi_imx->devtype_data.trigger(spi_imx); } static irqreturn_t spi_imx_isr(int irq, void *dev_id) { struct spi_imx_data *spi_imx = dev_id; - while (spi_imx->rx_available(spi_imx)) { + while (spi_imx->devtype_data.rx_available(spi_imx)) { spi_imx->rx(spi_imx); spi_imx->txfifo--; } @@ -398,11 +630,12 @@ static irqreturn_t spi_imx_isr(int irq, void *dev_id) /* No data left to push, but still waiting for rx data, * enable receive data available interrupt. */ - spi_imx->intctrl(spi_imx, MXC_INT_RR); + spi_imx->devtype_data.intctrl( + spi_imx, MXC_INT_RR); return IRQ_HANDLED; } - spi_imx->intctrl(spi_imx, 0); + spi_imx->devtype_data.intctrl(spi_imx, 0); complete(&spi_imx->xfer_done); return IRQ_HANDLED; @@ -417,7 +650,7 @@ static int spi_imx_setupxfer(struct spi_device *spi, config.bpw = t ? t->bits_per_word : spi->bits_per_word; config.speed_hz = t ? t->speed_hz : spi->max_speed_hz; config.mode = spi->mode; - config.cs = spi_imx->chipselect[spi->chip_select]; + config.cs = spi->chip_select; if (!config.speed_hz) config.speed_hz = spi->max_speed_hz; @@ -439,7 +672,7 @@ static int spi_imx_setupxfer(struct spi_device *spi, } else BUG(); - spi_imx->config(spi_imx, &config); + spi_imx->devtype_data.config(spi_imx, &config); return 0; } @@ -458,7 +691,7 @@ static int spi_imx_transfer(struct spi_device *spi, spi_imx_push(spi_imx); - spi_imx->intctrl(spi_imx, MXC_INT_TE); + spi_imx->devtype_data.intctrl(spi_imx, MXC_INT_TE); wait_for_completion(&spi_imx->xfer_done); @@ -485,6 +718,39 @@ static void spi_imx_cleanup(struct spi_device *spi) { } +static struct platform_device_id spi_imx_devtype[] = { + { + .name = DRIVER_NAME, + .driver_data = SPI_IMX_VER_AUTODETECT, + }, { + .name = "imx1-cspi", + .driver_data = SPI_IMX_VER_IMX1, + }, { + .name = "imx21-cspi", + .driver_data = SPI_IMX_VER_0_0, + }, { + .name = "imx25-cspi", + .driver_data = SPI_IMX_VER_0_7, + }, { + .name = "imx27-cspi", + .driver_data = SPI_IMX_VER_0_0, + }, { + .name = "imx31-cspi", + .driver_data = SPI_IMX_VER_0_4, + }, { + .name = "imx35-cspi", + .driver_data = SPI_IMX_VER_0_7, + }, { + .name = "imx51-cspi", + .driver_data = SPI_IMX_VER_0_7, + }, { + .name = "imx51-ecspi", + .driver_data = SPI_IMX_VER_2_3, + }, { + /* sentinel */ + } +}; + static int __devinit spi_imx_probe(struct platform_device *pdev) { struct spi_imx_master *mxc_platform_info; @@ -536,6 +802,31 @@ static int __devinit spi_imx_probe(struct platform_device *pdev) init_completion(&spi_imx->xfer_done); + if (pdev->id_entry->driver_data == SPI_IMX_VER_AUTODETECT) { + if (cpu_is_mx25() || cpu_is_mx35()) + spi_imx->devtype_data = + spi_imx_devtype_data[SPI_IMX_VER_0_7]; + else if (cpu_is_mx25() || cpu_is_mx31() || cpu_is_mx35()) + spi_imx->devtype_data = + spi_imx_devtype_data[SPI_IMX_VER_0_4]; + else if (cpu_is_mx27() || cpu_is_mx21()) + spi_imx->devtype_data = + spi_imx_devtype_data[SPI_IMX_VER_0_0]; + else if (cpu_is_mx1()) + spi_imx->devtype_data = + spi_imx_devtype_data[SPI_IMX_VER_IMX1]; + else + BUG(); + } else + spi_imx->devtype_data = + spi_imx_devtype_data[pdev->id_entry->driver_data]; + + if (!spi_imx->devtype_data.intctrl) { + dev_err(&pdev->dev, "no support for this device compiled in\n"); + ret = -ENODEV; + goto out_gpio_free; + } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(&pdev->dev, "can't get platform resource\n"); @@ -567,24 +858,6 @@ static int __devinit spi_imx_probe(struct platform_device *pdev) goto out_iounmap; } - if (cpu_is_mx25() || cpu_is_mx31() || cpu_is_mx35()) { - spi_imx->intctrl = mx31_intctrl; - spi_imx->config = mx31_config; - spi_imx->trigger = mx31_trigger; - spi_imx->rx_available = mx31_rx_available; - } else if (cpu_is_mx27() || cpu_is_mx21()) { - spi_imx->intctrl = mx27_intctrl; - spi_imx->config = mx27_config; - spi_imx->trigger = mx27_trigger; - spi_imx->rx_available = mx27_rx_available; - } else if (cpu_is_mx1()) { - spi_imx->intctrl = mx1_intctrl; - spi_imx->config = mx1_config; - spi_imx->trigger = mx1_trigger; - spi_imx->rx_available = mx1_rx_available; - } else - BUG(); - spi_imx->clk = clk_get(&pdev->dev, NULL); if (IS_ERR(spi_imx->clk)) { dev_err(&pdev->dev, "unable to get clock\n"); @@ -595,15 +868,9 @@ static int __devinit spi_imx_probe(struct platform_device *pdev) clk_enable(spi_imx->clk); spi_imx->spi_clk = clk_get_rate(spi_imx->clk); - if (cpu_is_mx1() || cpu_is_mx21() || cpu_is_mx27()) - writel(1, spi_imx->base + MXC_RESET); - - /* drain receive buffer */ - if (cpu_is_mx25() || cpu_is_mx31() || cpu_is_mx35()) - while (readl(spi_imx->base + MX3_CSPISTAT) & MX3_CSPISTAT_RR) - readl(spi_imx->base + MXC_CSPIRXDATA); + spi_imx->devtype_data.reset(spi_imx); - spi_imx->intctrl(spi_imx, 0); + spi_imx->devtype_data.intctrl(spi_imx, 0); ret = spi_bitbang_start(&spi_imx->bitbang); if (ret) { @@ -668,6 +935,7 @@ static struct platform_driver spi_imx_driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, }, + .id_table = spi_imx_devtype, .probe = spi_imx_probe, .remove = __devexit_p(spi_imx_remove), }; diff --git a/drivers/spi/spi_s3c64xx.c b/drivers/spi/spi_s3c64xx.c index c3038da2648a..795828b90f45 100644 --- a/drivers/spi/spi_s3c64xx.c +++ b/drivers/spi/spi_s3c64xx.c @@ -261,15 +261,25 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd, chcfg |= S3C64XX_SPI_CH_TXCH_ON; if (dma_mode) { modecfg |= S3C64XX_SPI_MODE_TXDMA_ON; - s3c2410_dma_config(sdd->tx_dmach, 1); + s3c2410_dma_config(sdd->tx_dmach, sdd->cur_bpw / 8); s3c2410_dma_enqueue(sdd->tx_dmach, (void *)sdd, xfer->tx_dma, xfer->len); s3c2410_dma_ctrl(sdd->tx_dmach, S3C2410_DMAOP_START); } else { - unsigned char *buf = (unsigned char *) xfer->tx_buf; - int i = 0; - while (i < xfer->len) - writeb(buf[i++], regs + S3C64XX_SPI_TX_DATA); + switch (sdd->cur_bpw) { + case 32: + iowrite32_rep(regs + S3C64XX_SPI_TX_DATA, + xfer->tx_buf, xfer->len / 4); + break; + case 16: + iowrite16_rep(regs + S3C64XX_SPI_TX_DATA, + xfer->tx_buf, xfer->len / 2); + break; + default: + iowrite8_rep(regs + S3C64XX_SPI_TX_DATA, + xfer->tx_buf, xfer->len); + break; + } } } @@ -286,7 +296,7 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd, writel(((xfer->len * 8 / sdd->cur_bpw) & 0xffff) | S3C64XX_SPI_PACKET_CNT_EN, regs + S3C64XX_SPI_PACKET_CNT); - s3c2410_dma_config(sdd->rx_dmach, 1); + s3c2410_dma_config(sdd->rx_dmach, sdd->cur_bpw / 8); s3c2410_dma_enqueue(sdd->rx_dmach, (void *)sdd, xfer->rx_dma, xfer->len); s3c2410_dma_ctrl(sdd->rx_dmach, S3C2410_DMAOP_START); @@ -366,20 +376,26 @@ static int wait_for_xfer(struct s3c64xx_spi_driver_data *sdd, return -EIO; } } else { - unsigned char *buf; - int i; - /* If it was only Tx */ if (xfer->rx_buf == NULL) { sdd->state &= ~TXBUSY; return 0; } - i = 0; - buf = xfer->rx_buf; - while (i < xfer->len) - buf[i++] = readb(regs + S3C64XX_SPI_RX_DATA); - + switch (sdd->cur_bpw) { + case 32: + ioread32_rep(regs + S3C64XX_SPI_RX_DATA, + xfer->rx_buf, xfer->len / 4); + break; + case 16: + ioread16_rep(regs + S3C64XX_SPI_RX_DATA, + xfer->rx_buf, xfer->len / 2); + break; + default: + ioread8_rep(regs + S3C64XX_SPI_RX_DATA, + xfer->rx_buf, xfer->len); + break; + } sdd->state &= ~RXBUSY; } @@ -399,13 +415,18 @@ static inline void disable_cs(struct s3c64xx_spi_driver_data *sdd, static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd) { + struct s3c64xx_spi_info *sci = sdd->cntrlr_info; void __iomem *regs = sdd->regs; u32 val; /* Disable Clock */ - val = readl(regs + S3C64XX_SPI_CLK_CFG); - val &= ~S3C64XX_SPI_ENCLK_ENABLE; - writel(val, regs + S3C64XX_SPI_CLK_CFG); + if (sci->clk_from_cmu) { + clk_disable(sdd->src_clk); + } else { + val = readl(regs + S3C64XX_SPI_CLK_CFG); + val &= ~S3C64XX_SPI_ENCLK_ENABLE; + writel(val, regs + S3C64XX_SPI_CLK_CFG); + } /* Set Polarity and Phase */ val = readl(regs + S3C64XX_SPI_CH_CFG); @@ -429,29 +450,39 @@ static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd) switch (sdd->cur_bpw) { case 32: val |= S3C64XX_SPI_MODE_BUS_TSZ_WORD; + val |= S3C64XX_SPI_MODE_CH_TSZ_WORD; break; case 16: val |= S3C64XX_SPI_MODE_BUS_TSZ_HALFWORD; + val |= S3C64XX_SPI_MODE_CH_TSZ_HALFWORD; break; default: val |= S3C64XX_SPI_MODE_BUS_TSZ_BYTE; + val |= S3C64XX_SPI_MODE_CH_TSZ_BYTE; break; } - val |= S3C64XX_SPI_MODE_CH_TSZ_BYTE; /* Always 8bits wide */ writel(val, regs + S3C64XX_SPI_MODE_CFG); - /* Configure Clock */ - val = readl(regs + S3C64XX_SPI_CLK_CFG); - val &= ~S3C64XX_SPI_PSR_MASK; - val |= ((clk_get_rate(sdd->src_clk) / sdd->cur_speed / 2 - 1) - & S3C64XX_SPI_PSR_MASK); - writel(val, regs + S3C64XX_SPI_CLK_CFG); - - /* Enable Clock */ - val = readl(regs + S3C64XX_SPI_CLK_CFG); - val |= S3C64XX_SPI_ENCLK_ENABLE; - writel(val, regs + S3C64XX_SPI_CLK_CFG); + if (sci->clk_from_cmu) { + /* Configure Clock */ + /* There is half-multiplier before the SPI */ + clk_set_rate(sdd->src_clk, sdd->cur_speed * 2); + /* Enable Clock */ + clk_enable(sdd->src_clk); + } else { + /* Configure Clock */ + val = readl(regs + S3C64XX_SPI_CLK_CFG); + val &= ~S3C64XX_SPI_PSR_MASK; + val |= ((clk_get_rate(sdd->src_clk) / sdd->cur_speed / 2 - 1) + & S3C64XX_SPI_PSR_MASK); + writel(val, regs + S3C64XX_SPI_CLK_CFG); + + /* Enable Clock */ + val = readl(regs + S3C64XX_SPI_CLK_CFG); + val |= S3C64XX_SPI_ENCLK_ENABLE; + writel(val, regs + S3C64XX_SPI_CLK_CFG); + } } static void s3c64xx_spi_dma_rxcb(struct s3c2410_dma_chan *chan, void *buf_id, @@ -499,6 +530,7 @@ static void s3c64xx_spi_dma_txcb(struct s3c2410_dma_chan *chan, void *buf_id, static int s3c64xx_spi_map_mssg(struct s3c64xx_spi_driver_data *sdd, struct spi_message *msg) { + struct s3c64xx_spi_info *sci = sdd->cntrlr_info; struct device *dev = &sdd->pdev->dev; struct spi_transfer *xfer; @@ -514,6 +546,9 @@ static int s3c64xx_spi_map_mssg(struct s3c64xx_spi_driver_data *sdd, /* Map until end or first fail */ list_for_each_entry(xfer, &msg->transfers, transfer_list) { + if (xfer->len <= ((sci->fifo_lvl_mask >> 1) + 1)) + continue; + if (xfer->tx_buf != NULL) { xfer->tx_dma = dma_map_single(dev, (void *)xfer->tx_buf, xfer->len, @@ -545,6 +580,7 @@ static int s3c64xx_spi_map_mssg(struct s3c64xx_spi_driver_data *sdd, static void s3c64xx_spi_unmap_mssg(struct s3c64xx_spi_driver_data *sdd, struct spi_message *msg) { + struct s3c64xx_spi_info *sci = sdd->cntrlr_info; struct device *dev = &sdd->pdev->dev; struct spi_transfer *xfer; @@ -553,6 +589,9 @@ static void s3c64xx_spi_unmap_mssg(struct s3c64xx_spi_driver_data *sdd, list_for_each_entry(xfer, &msg->transfers, transfer_list) { + if (xfer->len <= ((sci->fifo_lvl_mask >> 1) + 1)) + continue; + if (xfer->rx_buf != NULL && xfer->rx_dma != XFER_DMAADDR_INVALID) dma_unmap_single(dev, xfer->rx_dma, @@ -608,6 +647,14 @@ static void handle_msg(struct s3c64xx_spi_driver_data *sdd, bpw = xfer->bits_per_word ? : spi->bits_per_word; speed = xfer->speed_hz ? : spi->max_speed_hz; + if (xfer->len % (bpw / 8)) { + dev_err(&spi->dev, + "Xfer length(%u) not a multiple of word size(%u)\n", + xfer->len, bpw / 8); + status = -EIO; + goto out; + } + if (bpw != sdd->cur_bpw || speed != sdd->cur_speed) { sdd->cur_bpw = bpw; sdd->cur_speed = speed; @@ -798,7 +845,6 @@ static int s3c64xx_spi_setup(struct spi_device *spi) struct s3c64xx_spi_driver_data *sdd; struct s3c64xx_spi_info *sci; struct spi_message *msg; - u32 psr, speed; unsigned long flags; int err = 0; @@ -841,32 +887,37 @@ static int s3c64xx_spi_setup(struct spi_device *spi) } /* Check if we can provide the requested rate */ - speed = clk_get_rate(sdd->src_clk) / 2 / (0 + 1); /* Max possible */ - - if (spi->max_speed_hz > speed) - spi->max_speed_hz = speed; - - psr = clk_get_rate(sdd->src_clk) / 2 / spi->max_speed_hz - 1; - psr &= S3C64XX_SPI_PSR_MASK; - if (psr == S3C64XX_SPI_PSR_MASK) - psr--; + if (!sci->clk_from_cmu) { + u32 psr, speed; + + /* Max possible */ + speed = clk_get_rate(sdd->src_clk) / 2 / (0 + 1); + + if (spi->max_speed_hz > speed) + spi->max_speed_hz = speed; + + psr = clk_get_rate(sdd->src_clk) / 2 / spi->max_speed_hz - 1; + psr &= S3C64XX_SPI_PSR_MASK; + if (psr == S3C64XX_SPI_PSR_MASK) + psr--; + + speed = clk_get_rate(sdd->src_clk) / 2 / (psr + 1); + if (spi->max_speed_hz < speed) { + if (psr+1 < S3C64XX_SPI_PSR_MASK) { + psr++; + } else { + err = -EINVAL; + goto setup_exit; + } + } - speed = clk_get_rate(sdd->src_clk) / 2 / (psr + 1); - if (spi->max_speed_hz < speed) { - if (psr+1 < S3C64XX_SPI_PSR_MASK) { - psr++; - } else { + speed = clk_get_rate(sdd->src_clk) / 2 / (psr + 1); + if (spi->max_speed_hz >= speed) + spi->max_speed_hz = speed; + else err = -EINVAL; - goto setup_exit; - } } - speed = clk_get_rate(sdd->src_clk) / 2 / (psr + 1); - if (spi->max_speed_hz >= speed) - spi->max_speed_hz = speed; - else - err = -EINVAL; - setup_exit: /* setup() returns with device de-selected */ @@ -888,7 +939,8 @@ static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd, int channel) /* Disable Interrupts - we use Polling if not DMA mode */ writel(0, regs + S3C64XX_SPI_INT_EN); - writel(sci->src_clk_nr << S3C64XX_SPI_CLKSEL_SRCSHFT, + if (!sci->clk_from_cmu) + writel(sci->src_clk_nr << S3C64XX_SPI_CLKSEL_SRCSHFT, regs + S3C64XX_SPI_CLK_CFG); writel(0, regs + S3C64XX_SPI_MODE_CFG); writel(0, regs + S3C64XX_SPI_PACKET_CNT); diff --git a/drivers/spi/spi_topcliff_pch.c b/drivers/spi/spi_topcliff_pch.c new file mode 100644 index 000000000000..58e187f45ec7 --- /dev/null +++ b/drivers/spi/spi_topcliff_pch.c @@ -0,0 +1,1303 @@ +/* + * SPI bus driver for the Topcliff PCH used by Intel SoCs + * + * Copyright (C) 2010 OKI SEMICONDUCTOR Co., LTD. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <linux/delay.h> +#include <linux/pci.h> +#include <linux/wait.h> +#include <linux/spi/spi.h> +#include <linux/interrupt.h> +#include <linux/sched.h> +#include <linux/spi/spidev.h> +#include <linux/module.h> +#include <linux/device.h> + +/* Register offsets */ +#define PCH_SPCR 0x00 /* SPI control register */ +#define PCH_SPBRR 0x04 /* SPI baud rate register */ +#define PCH_SPSR 0x08 /* SPI status register */ +#define PCH_SPDWR 0x0C /* SPI write data register */ +#define PCH_SPDRR 0x10 /* SPI read data register */ +#define PCH_SSNXCR 0x18 /* SSN Expand Control Register */ +#define PCH_SRST 0x1C /* SPI reset register */ + +#define PCH_SPSR_TFD 0x000007C0 +#define PCH_SPSR_RFD 0x0000F800 + +#define PCH_READABLE(x) (((x) & PCH_SPSR_RFD)>>11) +#define PCH_WRITABLE(x) (((x) & PCH_SPSR_TFD)>>6) + +#define PCH_RX_THOLD 7 +#define PCH_RX_THOLD_MAX 15 + +#define PCH_MAX_BAUDRATE 5000000 +#define PCH_MAX_FIFO_DEPTH 16 + +#define STATUS_RUNNING 1 +#define STATUS_EXITING 2 +#define PCH_SLEEP_TIME 10 + +#define PCH_ADDRESS_SIZE 0x20 + +#define SSN_LOW 0x02U +#define SSN_NO_CONTROL 0x00U +#define PCH_MAX_CS 0xFF +#define PCI_DEVICE_ID_GE_SPI 0x8816 + +#define SPCR_SPE_BIT (1 << 0) +#define SPCR_MSTR_BIT (1 << 1) +#define SPCR_LSBF_BIT (1 << 4) +#define SPCR_CPHA_BIT (1 << 5) +#define SPCR_CPOL_BIT (1 << 6) +#define SPCR_TFIE_BIT (1 << 8) +#define SPCR_RFIE_BIT (1 << 9) +#define SPCR_FIE_BIT (1 << 10) +#define SPCR_ORIE_BIT (1 << 11) +#define SPCR_MDFIE_BIT (1 << 12) +#define SPCR_FICLR_BIT (1 << 24) +#define SPSR_TFI_BIT (1 << 0) +#define SPSR_RFI_BIT (1 << 1) +#define SPSR_FI_BIT (1 << 2) +#define SPBRR_SIZE_BIT (1 << 10) + +#define PCH_ALL (SPCR_TFIE_BIT|SPCR_RFIE_BIT|SPCR_FIE_BIT|SPCR_ORIE_BIT|SPCR_MDFIE_BIT) + +#define SPCR_RFIC_FIELD 20 +#define SPCR_TFIC_FIELD 16 + +#define SPSR_INT_BITS 0x1F +#define MASK_SPBRR_SPBR_BITS (~((1 << 10) - 1)) +#define MASK_RFIC_SPCR_BITS (~(0xf << 20)) +#define MASK_TFIC_SPCR_BITS (~(0xf000f << 12)) + +#define PCH_CLOCK_HZ 50000000 +#define PCH_MAX_SPBR 1023 + + +/** + * struct pch_spi_data - Holds the SPI channel specific details + * @io_remap_addr: The remapped PCI base address + * @master: Pointer to the SPI master structure + * @work: Reference to work queue handler + * @wk: Workqueue for carrying out execution of the + * requests + * @wait: Wait queue for waking up upon receiving an + * interrupt. + * @transfer_complete: Status of SPI Transfer + * @bcurrent_msg_processing: Status flag for message processing + * @lock: Lock for protecting this structure + * @queue: SPI Message queue + * @status: Status of the SPI driver + * @bpw_len: Length of data to be transferred in bits per + * word + * @transfer_active: Flag showing active transfer + * @tx_index: Transmit data count; for bookkeeping during + * transfer + * @rx_index: Receive data count; for bookkeeping during + * transfer + * @tx_buff: Buffer for data to be transmitted + * @rx_index: Buffer for Received data + * @n_curnt_chip: The chip number that this SPI driver currently + * operates on + * @current_chip: Reference to the current chip that this SPI + * driver currently operates on + * @current_msg: The current message that this SPI driver is + * handling + * @cur_trans: The current transfer that this SPI driver is + * handling + * @board_dat: Reference to the SPI device data structure + */ +struct pch_spi_data { + void __iomem *io_remap_addr; + struct spi_master *master; + struct work_struct work; + struct workqueue_struct *wk; + wait_queue_head_t wait; + u8 transfer_complete; + u8 bcurrent_msg_processing; + spinlock_t lock; + struct list_head queue; + u8 status; + u32 bpw_len; + u8 transfer_active; + u32 tx_index; + u32 rx_index; + u16 *pkt_tx_buff; + u16 *pkt_rx_buff; + u8 n_curnt_chip; + struct spi_device *current_chip; + struct spi_message *current_msg; + struct spi_transfer *cur_trans; + struct pch_spi_board_data *board_dat; +}; + +/** + * struct pch_spi_board_data - Holds the SPI device specific details + * @pdev: Pointer to the PCI device + * @irq_reg_sts: Status of IRQ registration + * @pci_req_sts: Status of pci_request_regions + * @suspend_sts: Status of suspend + * @data: Pointer to SPI channel data structure + */ +struct pch_spi_board_data { + struct pci_dev *pdev; + u8 irq_reg_sts; + u8 pci_req_sts; + u8 suspend_sts; + struct pch_spi_data *data; +}; + +static struct pci_device_id pch_spi_pcidev_id[] = { + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_GE_SPI)}, + {0,} +}; + +/** + * pch_spi_writereg() - Performs register writes + * @master: Pointer to struct spi_master. + * @idx: Register offset. + * @val: Value to be written to register. + */ +static inline void pch_spi_writereg(struct spi_master *master, int idx, u32 val) +{ + struct pch_spi_data *data = spi_master_get_devdata(master); + iowrite32(val, (data->io_remap_addr + idx)); +} + +/** + * pch_spi_readreg() - Performs register reads + * @master: Pointer to struct spi_master. + * @idx: Register offset. + */ +static inline u32 pch_spi_readreg(struct spi_master *master, int idx) +{ + struct pch_spi_data *data = spi_master_get_devdata(master); + return ioread32(data->io_remap_addr + idx); +} + +static inline void pch_spi_setclr_reg(struct spi_master *master, int idx, + u32 set, u32 clr) +{ + u32 tmp = pch_spi_readreg(master, idx); + tmp = (tmp & ~clr) | set; + pch_spi_writereg(master, idx, tmp); +} + +static void pch_spi_set_master_mode(struct spi_master *master) +{ + pch_spi_setclr_reg(master, PCH_SPCR, SPCR_MSTR_BIT, 0); +} + +/** + * pch_spi_clear_fifo() - Clears the Transmit and Receive FIFOs + * @master: Pointer to struct spi_master. + */ +static void pch_spi_clear_fifo(struct spi_master *master) +{ + pch_spi_setclr_reg(master, PCH_SPCR, SPCR_FICLR_BIT, 0); + pch_spi_setclr_reg(master, PCH_SPCR, 0, SPCR_FICLR_BIT); +} + +static void pch_spi_handler_sub(struct pch_spi_data *data, u32 reg_spsr_val, + void __iomem *io_remap_addr) +{ + u32 n_read, tx_index, rx_index, bpw_len; + u16 *pkt_rx_buffer, *pkt_tx_buff; + int read_cnt; + u32 reg_spcr_val; + void __iomem *spsr; + void __iomem *spdrr; + void __iomem *spdwr; + + spsr = io_remap_addr + PCH_SPSR; + iowrite32(reg_spsr_val, spsr); + + if (data->transfer_active) { + rx_index = data->rx_index; + tx_index = data->tx_index; + bpw_len = data->bpw_len; + pkt_rx_buffer = data->pkt_rx_buff; + pkt_tx_buff = data->pkt_tx_buff; + + spdrr = io_remap_addr + PCH_SPDRR; + spdwr = io_remap_addr + PCH_SPDWR; + + n_read = PCH_READABLE(reg_spsr_val); + + for (read_cnt = 0; (read_cnt < n_read); read_cnt++) { + pkt_rx_buffer[rx_index++] = ioread32(spdrr); + if (tx_index < bpw_len) + iowrite32(pkt_tx_buff[tx_index++], spdwr); + } + + /* disable RFI if not needed */ + if ((bpw_len - rx_index) <= PCH_MAX_FIFO_DEPTH) { + reg_spcr_val = ioread32(io_remap_addr + PCH_SPCR); + reg_spcr_val &= ~SPCR_RFIE_BIT; /* disable RFI */ + + /* reset rx threshold */ + reg_spcr_val &= MASK_RFIC_SPCR_BITS; + reg_spcr_val |= (PCH_RX_THOLD_MAX << SPCR_RFIC_FIELD); + iowrite32(((reg_spcr_val) &= (~(SPCR_RFIE_BIT))), + (io_remap_addr + PCH_SPCR)); + } + + /* update counts */ + data->tx_index = tx_index; + data->rx_index = rx_index; + + } + + /* if transfer complete interrupt */ + if (reg_spsr_val & SPSR_FI_BIT) { + /* disable FI & RFI interrupts */ + pch_spi_setclr_reg(data->master, PCH_SPCR, 0, + SPCR_FIE_BIT | SPCR_TFIE_BIT); + + /* transfer is completed;inform pch_spi_process_messages */ + data->transfer_complete = true; + wake_up(&data->wait); + } +} + +/** + * pch_spi_handler() - Interrupt handler + * @irq: The interrupt number. + * @dev_id: Pointer to struct pch_spi_board_data. + */ +static irqreturn_t pch_spi_handler(int irq, void *dev_id) +{ + u32 reg_spsr_val; + struct pch_spi_data *data; + void __iomem *spsr; + void __iomem *io_remap_addr; + irqreturn_t ret = IRQ_NONE; + struct pch_spi_board_data *board_dat = dev_id; + + if (board_dat->suspend_sts) { + dev_dbg(&board_dat->pdev->dev, + "%s returning due to suspend\n", __func__); + return IRQ_NONE; + } + + data = board_dat->data; + io_remap_addr = data->io_remap_addr; + spsr = io_remap_addr + PCH_SPSR; + + reg_spsr_val = ioread32(spsr); + + /* Check if the interrupt is for SPI device */ + if (reg_spsr_val & (SPSR_FI_BIT | SPSR_RFI_BIT)) { + pch_spi_handler_sub(data, reg_spsr_val, io_remap_addr); + ret = IRQ_HANDLED; + } + + dev_dbg(&board_dat->pdev->dev, "%s EXIT return value=%d\n", + __func__, ret); + + return ret; +} + +/** + * pch_spi_set_baud_rate() - Sets SPBR field in SPBRR + * @master: Pointer to struct spi_master. + * @speed_hz: Baud rate. + */ +static void pch_spi_set_baud_rate(struct spi_master *master, u32 speed_hz) +{ + u32 n_spbr = PCH_CLOCK_HZ / (speed_hz * 2); + + /* if baud rate is less than we can support limit it */ + if (n_spbr > PCH_MAX_SPBR) + n_spbr = PCH_MAX_SPBR; + + pch_spi_setclr_reg(master, PCH_SPBRR, n_spbr, ~MASK_SPBRR_SPBR_BITS); +} + +/** + * pch_spi_set_bits_per_word() - Sets SIZE field in SPBRR + * @master: Pointer to struct spi_master. + * @bits_per_word: Bits per word for SPI transfer. + */ +static void pch_spi_set_bits_per_word(struct spi_master *master, + u8 bits_per_word) +{ + if (bits_per_word == 8) + pch_spi_setclr_reg(master, PCH_SPBRR, 0, SPBRR_SIZE_BIT); + else + pch_spi_setclr_reg(master, PCH_SPBRR, SPBRR_SIZE_BIT, 0); +} + +/** + * pch_spi_setup_transfer() - Configures the PCH SPI hardware for transfer + * @spi: Pointer to struct spi_device. + */ +static void pch_spi_setup_transfer(struct spi_device *spi) +{ + u32 flags = 0; + + dev_dbg(&spi->dev, "%s SPBRR content =%x setting baud rate=%d\n", + __func__, pch_spi_readreg(spi->master, PCH_SPBRR), + spi->max_speed_hz); + pch_spi_set_baud_rate(spi->master, spi->max_speed_hz); + + /* set bits per word */ + pch_spi_set_bits_per_word(spi->master, spi->bits_per_word); + + if (!(spi->mode & SPI_LSB_FIRST)) + flags |= SPCR_LSBF_BIT; + if (spi->mode & SPI_CPOL) + flags |= SPCR_CPOL_BIT; + if (spi->mode & SPI_CPHA) + flags |= SPCR_CPHA_BIT; + pch_spi_setclr_reg(spi->master, PCH_SPCR, flags, + (SPCR_LSBF_BIT | SPCR_CPOL_BIT | SPCR_CPHA_BIT)); + + /* Clear the FIFO by toggling FICLR to 1 and back to 0 */ + pch_spi_clear_fifo(spi->master); +} + +/** + * pch_spi_reset() - Clears SPI registers + * @master: Pointer to struct spi_master. + */ +static void pch_spi_reset(struct spi_master *master) +{ + /* write 1 to reset SPI */ + pch_spi_writereg(master, PCH_SRST, 0x1); + + /* clear reset */ + pch_spi_writereg(master, PCH_SRST, 0x0); +} + +static int pch_spi_setup(struct spi_device *pspi) +{ + /* check bits per word */ + if (pspi->bits_per_word == 0) { + pspi->bits_per_word = 8; + dev_dbg(&pspi->dev, "%s 8 bits per word\n", __func__); + } + + if ((pspi->bits_per_word != 8) && (pspi->bits_per_word != 16)) { + dev_err(&pspi->dev, "%s Invalid bits per word\n", __func__); + return -EINVAL; + } + + /* Check baud rate setting */ + /* if baud rate of chip is greater than + max we can support,return error */ + if ((pspi->max_speed_hz) > PCH_MAX_BAUDRATE) + pspi->max_speed_hz = PCH_MAX_BAUDRATE; + + dev_dbg(&pspi->dev, "%s MODE = %x\n", __func__, + (pspi->mode) & (SPI_CPOL | SPI_CPHA)); + + return 0; +} + +static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg) +{ + + struct spi_transfer *transfer; + struct pch_spi_data *data = spi_master_get_devdata(pspi->master); + int retval; + unsigned long flags; + + /* validate spi message and baud rate */ + if (unlikely(list_empty(&pmsg->transfers) == 1)) { + dev_err(&pspi->dev, "%s list empty\n", __func__); + retval = -EINVAL; + goto err_out; + } + + if (unlikely(pspi->max_speed_hz == 0)) { + dev_err(&pspi->dev, "%s pch_spi_tranfer maxspeed=%d\n", + __func__, pspi->max_speed_hz); + retval = -EINVAL; + goto err_out; + } + + dev_dbg(&pspi->dev, "%s Transfer List not empty. " + "Transfer Speed is set.\n", __func__); + + /* validate Tx/Rx buffers and Transfer length */ + list_for_each_entry(transfer, &pmsg->transfers, transfer_list) { + if (!transfer->tx_buf && !transfer->rx_buf) { + dev_err(&pspi->dev, + "%s Tx and Rx buffer NULL\n", __func__); + retval = -EINVAL; + goto err_out; + } + + if (!transfer->len) { + dev_err(&pspi->dev, "%s Transfer length invalid\n", + __func__); + retval = -EINVAL; + goto err_out; + } + + dev_dbg(&pspi->dev, "%s Tx/Rx buffer valid. Transfer length" + " valid\n", __func__); + + /* if baud rate hs been specified validate the same */ + if (transfer->speed_hz > PCH_MAX_BAUDRATE) + transfer->speed_hz = PCH_MAX_BAUDRATE; + + /* if bits per word has been specified validate the same */ + if (transfer->bits_per_word) { + if ((transfer->bits_per_word != 8) + && (transfer->bits_per_word != 16)) { + retval = -EINVAL; + dev_err(&pspi->dev, + "%s Invalid bits per word\n", __func__); + goto err_out; + } + } + } + + spin_lock_irqsave(&data->lock, flags); + + /* We won't process any messages if we have been asked to terminate */ + if (data->status == STATUS_EXITING) { + dev_err(&pspi->dev, "%s status = STATUS_EXITING.\n", __func__); + retval = -ESHUTDOWN; + goto err_return_spinlock; + } + + /* If suspended ,return -EINVAL */ + if (data->board_dat->suspend_sts) { + dev_err(&pspi->dev, "%s suspend; returning EINVAL\n", __func__); + retval = -EINVAL; + goto err_return_spinlock; + } + + /* set status of message */ + pmsg->actual_length = 0; + dev_dbg(&pspi->dev, "%s - pmsg->status =%d\n", __func__, pmsg->status); + + pmsg->status = -EINPROGRESS; + + /* add message to queue */ + list_add_tail(&pmsg->queue, &data->queue); + dev_dbg(&pspi->dev, "%s - Invoked list_add_tail\n", __func__); + + /* schedule work queue to run */ + queue_work(data->wk, &data->work); + dev_dbg(&pspi->dev, "%s - Invoked queue work\n", __func__); + + retval = 0; + +err_return_spinlock: + spin_unlock_irqrestore(&data->lock, flags); +err_out: + dev_dbg(&pspi->dev, "%s RETURN=%d\n", __func__, retval); + return retval; +} + +static inline void pch_spi_select_chip(struct pch_spi_data *data, + struct spi_device *pspi) +{ + if (data->current_chip != NULL) { + if (pspi->chip_select != data->n_curnt_chip) { + dev_dbg(&pspi->dev, "%s : different slave\n", __func__); + data->current_chip = NULL; + } + } + + data->current_chip = pspi; + + data->n_curnt_chip = data->current_chip->chip_select; + + dev_dbg(&pspi->dev, "%s :Invoking pch_spi_setup_transfer\n", __func__); + pch_spi_setup_transfer(pspi); +} + +static void pch_spi_set_tx(struct pch_spi_data *data, int *bpw, + struct spi_message **ppmsg) +{ + int size; + u32 n_writes; + int j; + struct spi_message *pmsg; + const u8 *tx_buf; + const u16 *tx_sbuf; + + pmsg = *ppmsg; + + /* set baud rate if needed */ + if (data->cur_trans->speed_hz) { + dev_dbg(&data->master->dev, "%s:setting baud rate\n", __func__); + pch_spi_set_baud_rate(data->master, data->cur_trans->speed_hz); + } + + /* set bits per word if needed */ + if (data->cur_trans->bits_per_word && + (data->current_msg->spi->bits_per_word != data->cur_trans->bits_per_word)) { + dev_dbg(&data->master->dev, "%s:set bits per word\n", __func__); + pch_spi_set_bits_per_word(data->master, + data->cur_trans->bits_per_word); + *bpw = data->cur_trans->bits_per_word; + } else { + *bpw = data->current_msg->spi->bits_per_word; + } + + /* reset Tx/Rx index */ + data->tx_index = 0; + data->rx_index = 0; + + data->bpw_len = data->cur_trans->len / (*bpw / 8); + + /* find alloc size */ + size = data->cur_trans->len * sizeof(*data->pkt_tx_buff); + + /* allocate memory for pkt_tx_buff & pkt_rx_buffer */ + data->pkt_tx_buff = kzalloc(size, GFP_KERNEL); + if (data->pkt_tx_buff != NULL) { + data->pkt_rx_buff = kzalloc(size, GFP_KERNEL); + if (!data->pkt_rx_buff) + kfree(data->pkt_tx_buff); + } + + if (!data->pkt_rx_buff) { + /* flush queue and set status of all transfers to -ENOMEM */ + dev_err(&data->master->dev, "%s :kzalloc failed\n", __func__); + list_for_each_entry(pmsg, data->queue.next, queue) { + pmsg->status = -ENOMEM; + + if (pmsg->complete != 0) + pmsg->complete(pmsg->context); + + /* delete from queue */ + list_del_init(&pmsg->queue); + } + return; + } + + /* copy Tx Data */ + if (data->cur_trans->tx_buf != NULL) { + if (*bpw == 8) { + tx_buf = data->cur_trans->tx_buf; + for (j = 0; j < data->bpw_len; j++) + data->pkt_tx_buff[j] = *tx_buf++; + } else { + tx_sbuf = data->cur_trans->tx_buf; + for (j = 0; j < data->bpw_len; j++) + data->pkt_tx_buff[j] = *tx_sbuf++; + } + } + + /* if len greater than PCH_MAX_FIFO_DEPTH, write 16,else len bytes */ + n_writes = data->bpw_len; + if (n_writes > PCH_MAX_FIFO_DEPTH) + n_writes = PCH_MAX_FIFO_DEPTH; + + dev_dbg(&data->master->dev, "\n%s:Pulling down SSN low - writing " + "0x2 to SSNXCR\n", __func__); + pch_spi_writereg(data->master, PCH_SSNXCR, SSN_LOW); + + for (j = 0; j < n_writes; j++) + pch_spi_writereg(data->master, PCH_SPDWR, data->pkt_tx_buff[j]); + + /* update tx_index */ + data->tx_index = j; + + /* reset transfer complete flag */ + data->transfer_complete = false; + data->transfer_active = true; +} + + +static void pch_spi_nomore_transfer(struct pch_spi_data *data, + struct spi_message *pmsg) +{ + dev_dbg(&data->master->dev, "%s called\n", __func__); + /* Invoke complete callback + * [To the spi core..indicating end of transfer] */ + data->current_msg->status = 0; + + if (data->current_msg->complete != 0) { + dev_dbg(&data->master->dev, + "%s:Invoking callback of SPI core\n", __func__); + data->current_msg->complete(data->current_msg->context); + } + + /* update status in global variable */ + data->bcurrent_msg_processing = false; + + dev_dbg(&data->master->dev, + "%s:data->bcurrent_msg_processing = false\n", __func__); + + data->current_msg = NULL; + data->cur_trans = NULL; + + /* check if we have items in list and not suspending + * return 1 if list empty */ + if ((list_empty(&data->queue) == 0) && + (!data->board_dat->suspend_sts) && + (data->status != STATUS_EXITING)) { + /* We have some more work to do (either there is more tranint + * bpw;sfer requests in the current message or there are + *more messages) + */ + dev_dbg(&data->master->dev, "%s:Invoke queue_work\n", __func__); + queue_work(data->wk, &data->work); + } else if (data->board_dat->suspend_sts || + data->status == STATUS_EXITING) { + dev_dbg(&data->master->dev, + "%s suspend/remove initiated, flushing queue\n", + __func__); + list_for_each_entry(pmsg, data->queue.next, queue) { + pmsg->status = -EIO; + + if (pmsg->complete) + pmsg->complete(pmsg->context); + + /* delete from queue */ + list_del_init(&pmsg->queue); + } + } +} + +static void pch_spi_set_ir(struct pch_spi_data *data) +{ + /* enable interrupts */ + if ((data->bpw_len) > PCH_MAX_FIFO_DEPTH) { + /* set receive threhold to PCH_RX_THOLD */ + pch_spi_setclr_reg(data->master, PCH_SPCR, + PCH_RX_THOLD << SPCR_TFIC_FIELD, + ~MASK_TFIC_SPCR_BITS); + /* enable FI and RFI interrupts */ + pch_spi_setclr_reg(data->master, PCH_SPCR, + SPCR_RFIE_BIT | SPCR_TFIE_BIT, 0); + } else { + /* set receive threhold to maximum */ + pch_spi_setclr_reg(data->master, PCH_SPCR, + PCH_RX_THOLD_MAX << SPCR_TFIC_FIELD, + ~MASK_TFIC_SPCR_BITS); + /* enable FI interrupt */ + pch_spi_setclr_reg(data->master, PCH_SPCR, SPCR_FIE_BIT, 0); + } + + dev_dbg(&data->master->dev, + "%s:invoking pch_spi_set_enable to enable SPI\n", __func__); + + /* SPI set enable */ + pch_spi_setclr_reg(data->current_chip->master, PCH_SPCR, SPCR_SPE_BIT, 0); + + /* Wait until the transfer completes; go to sleep after + initiating the transfer. */ + dev_dbg(&data->master->dev, + "%s:waiting for transfer to get over\n", __func__); + + wait_event_interruptible(data->wait, data->transfer_complete); + + pch_spi_writereg(data->master, PCH_SSNXCR, SSN_NO_CONTROL); + dev_dbg(&data->master->dev, + "%s:no more control over SSN-writing 0 to SSNXCR.", __func__); + + data->transfer_active = false; + dev_dbg(&data->master->dev, + "%s set data->transfer_active = false\n", __func__); + + /* clear all interrupts */ + pch_spi_writereg(data->master, PCH_SPSR, + pch_spi_readreg(data->master, PCH_SPSR)); + /* disable interrupts */ + pch_spi_setclr_reg(data->master, PCH_SPCR, 0, PCH_ALL); +} + +static void pch_spi_copy_rx_data(struct pch_spi_data *data, int bpw) +{ + int j; + u8 *rx_buf; + u16 *rx_sbuf; + + /* copy Rx Data */ + if (!data->cur_trans->rx_buf) + return; + + if (bpw == 8) { + rx_buf = data->cur_trans->rx_buf; + for (j = 0; j < data->bpw_len; j++) + *rx_buf++ = data->pkt_rx_buff[j] & 0xFF; + } else { + rx_sbuf = data->cur_trans->rx_buf; + for (j = 0; j < data->bpw_len; j++) + *rx_sbuf++ = data->pkt_rx_buff[j]; + } +} + + +static void pch_spi_process_messages(struct work_struct *pwork) +{ + struct spi_message *pmsg; + struct pch_spi_data *data; + int bpw; + + data = container_of(pwork, struct pch_spi_data, work); + dev_dbg(&data->master->dev, "%s data initialized\n", __func__); + + spin_lock(&data->lock); + + /* check if suspend has been initiated;if yes flush queue */ + if (data->board_dat->suspend_sts || (data->status == STATUS_EXITING)) { + dev_dbg(&data->master->dev, + "%s suspend/remove initiated,flushing queue\n", + __func__); + + list_for_each_entry(pmsg, data->queue.next, queue) { + pmsg->status = -EIO; + + if (pmsg->complete != 0) { + spin_unlock(&data->lock); + pmsg->complete(pmsg->context); + spin_lock(&data->lock); + } + + /* delete from queue */ + list_del_init(&pmsg->queue); + } + + spin_unlock(&data->lock); + return; + } + + data->bcurrent_msg_processing = true; + dev_dbg(&data->master->dev, + "%s Set data->bcurrent_msg_processing= true\n", __func__); + + /* Get the message from the queue and delete it from there. */ + data->current_msg = list_entry(data->queue.next, struct spi_message, + queue); + + list_del_init(&data->current_msg->queue); + + data->current_msg->status = 0; + + pch_spi_select_chip(data, data->current_msg->spi); + + spin_unlock(&data->lock); + + do { + /* If we are already processing a message get the next + transfer structure from the message otherwise retrieve + the 1st transfer request from the message. */ + spin_lock(&data->lock); + + if (data->cur_trans == NULL) { + data->cur_trans = + list_entry(data->current_msg->transfers. + next, struct spi_transfer, + transfer_list); + dev_dbg(&data->master->dev, + "%s :Getting 1st transfer message\n", __func__); + } else { + data->cur_trans = + list_entry(data->cur_trans->transfer_list.next, + struct spi_transfer, + transfer_list); + dev_dbg(&data->master->dev, + "%s :Getting next transfer message\n", + __func__); + } + + spin_unlock(&data->lock); + + pch_spi_set_tx(data, &bpw, &pmsg); + + /* Control interrupt*/ + pch_spi_set_ir(data); + + /* Disable SPI transfer */ + pch_spi_setclr_reg(data->current_chip->master, PCH_SPCR, 0, + SPCR_SPE_BIT); + + /* clear FIFO */ + pch_spi_clear_fifo(data->master); + + /* copy Rx Data */ + pch_spi_copy_rx_data(data, bpw); + + /* free memory */ + kfree(data->pkt_rx_buff); + data->pkt_rx_buff = NULL; + + kfree(data->pkt_tx_buff); + data->pkt_tx_buff = NULL; + + /* increment message count */ + data->current_msg->actual_length += data->cur_trans->len; + + dev_dbg(&data->master->dev, + "%s:data->current_msg->actual_length=%d\n", + __func__, data->current_msg->actual_length); + + /* check for delay */ + if (data->cur_trans->delay_usecs) { + dev_dbg(&data->master->dev, "%s:" + "delay in usec=%d\n", __func__, + data->cur_trans->delay_usecs); + udelay(data->cur_trans->delay_usecs); + } + + spin_lock(&data->lock); + + /* No more transfer in this message. */ + if ((data->cur_trans->transfer_list.next) == + &(data->current_msg->transfers)) { + pch_spi_nomore_transfer(data, pmsg); + } + + spin_unlock(&data->lock); + + } while (data->cur_trans != NULL); +} + +static void pch_spi_free_resources(struct pch_spi_board_data *board_dat) +{ + dev_dbg(&board_dat->pdev->dev, "%s ENTRY\n", __func__); + + /* free workqueue */ + if (board_dat->data->wk != NULL) { + destroy_workqueue(board_dat->data->wk); + board_dat->data->wk = NULL; + dev_dbg(&board_dat->pdev->dev, + "%s destroy_workqueue invoked successfully\n", + __func__); + } + + /* disable interrupts & free IRQ */ + if (board_dat->irq_reg_sts) { + /* disable interrupts */ + pch_spi_setclr_reg(board_dat->data->master, PCH_SPCR, 0, + PCH_ALL); + + /* free IRQ */ + free_irq(board_dat->pdev->irq, board_dat); + + dev_dbg(&board_dat->pdev->dev, + "%s free_irq invoked successfully\n", __func__); + + board_dat->irq_reg_sts = false; + } + + /* unmap PCI base address */ + if (board_dat->data->io_remap_addr != 0) { + pci_iounmap(board_dat->pdev, board_dat->data->io_remap_addr); + + board_dat->data->io_remap_addr = 0; + + dev_dbg(&board_dat->pdev->dev, + "%s pci_iounmap invoked successfully\n", __func__); + } + + /* release PCI region */ + if (board_dat->pci_req_sts) { + pci_release_regions(board_dat->pdev); + dev_dbg(&board_dat->pdev->dev, + "%s pci_release_regions invoked successfully\n", + __func__); + board_dat->pci_req_sts = false; + } +} + +static int pch_spi_get_resources(struct pch_spi_board_data *board_dat) +{ + void __iomem *io_remap_addr; + int retval; + dev_dbg(&board_dat->pdev->dev, "%s ENTRY\n", __func__); + + /* create workqueue */ + board_dat->data->wk = create_singlethread_workqueue(KBUILD_MODNAME); + if (!board_dat->data->wk) { + dev_err(&board_dat->pdev->dev, + "%s create_singlet hread_workqueue failed\n", __func__); + retval = -EBUSY; + goto err_return; + } + + dev_dbg(&board_dat->pdev->dev, + "%s create_singlethread_workqueue success\n", __func__); + + retval = pci_request_regions(board_dat->pdev, KBUILD_MODNAME); + if (retval != 0) { + dev_err(&board_dat->pdev->dev, + "%s request_region failed\n", __func__); + goto err_return; + } + + board_dat->pci_req_sts = true; + + io_remap_addr = pci_iomap(board_dat->pdev, 1, 0); + if (io_remap_addr == 0) { + dev_err(&board_dat->pdev->dev, + "%s pci_iomap failed\n", __func__); + retval = -ENOMEM; + goto err_return; + } + + /* calculate base address for all channels */ + board_dat->data->io_remap_addr = io_remap_addr; + + /* reset PCH SPI h/w */ + pch_spi_reset(board_dat->data->master); + dev_dbg(&board_dat->pdev->dev, + "%s pch_spi_reset invoked successfully\n", __func__); + + /* register IRQ */ + retval = request_irq(board_dat->pdev->irq, pch_spi_handler, + IRQF_SHARED, KBUILD_MODNAME, board_dat); + if (retval != 0) { + dev_err(&board_dat->pdev->dev, + "%s request_irq failed\n", __func__); + goto err_return; + } + + dev_dbg(&board_dat->pdev->dev, "%s request_irq returned=%d\n", + __func__, retval); + + board_dat->irq_reg_sts = true; + dev_dbg(&board_dat->pdev->dev, "%s data->irq_reg_sts=true\n", __func__); + +err_return: + if (retval != 0) { + dev_err(&board_dat->pdev->dev, + "%s FAIL:invoking pch_spi_free_resources\n", __func__); + pch_spi_free_resources(board_dat); + } + + dev_dbg(&board_dat->pdev->dev, "%s Return=%d\n", __func__, retval); + + return retval; +} + +static int pch_spi_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + + struct spi_master *master; + + struct pch_spi_board_data *board_dat; + int retval; + + dev_dbg(&pdev->dev, "%s ENTRY\n", __func__); + + /* allocate memory for private data */ + board_dat = kzalloc(sizeof(struct pch_spi_board_data), GFP_KERNEL); + if (board_dat == NULL) { + dev_err(&pdev->dev, + " %s memory allocation for private data failed\n", + __func__); + retval = -ENOMEM; + goto err_kmalloc; + } + + dev_dbg(&pdev->dev, + "%s memory allocation for private data success\n", __func__); + + /* enable PCI device */ + retval = pci_enable_device(pdev); + if (retval != 0) { + dev_err(&pdev->dev, "%s pci_enable_device FAILED\n", __func__); + + goto err_pci_en_device; + } + + dev_dbg(&pdev->dev, "%s pci_enable_device returned=%d\n", + __func__, retval); + + board_dat->pdev = pdev; + + /* alllocate memory for SPI master */ + master = spi_alloc_master(&pdev->dev, sizeof(struct pch_spi_data)); + if (master == NULL) { + retval = -ENOMEM; + dev_err(&pdev->dev, "%s Fail.\n", __func__); + goto err_spi_alloc_master; + } + + dev_dbg(&pdev->dev, + "%s spi_alloc_master returned non NULL\n", __func__); + + /* initialize members of SPI master */ + master->bus_num = -1; + master->num_chipselect = PCH_MAX_CS; + master->setup = pch_spi_setup; + master->transfer = pch_spi_transfer; + dev_dbg(&pdev->dev, + "%s transfer member of SPI master initialized\n", __func__); + + board_dat->data = spi_master_get_devdata(master); + + board_dat->data->master = master; + board_dat->data->n_curnt_chip = 255; + board_dat->data->board_dat = board_dat; + board_dat->data->status = STATUS_RUNNING; + + INIT_LIST_HEAD(&board_dat->data->queue); + spin_lock_init(&board_dat->data->lock); + INIT_WORK(&board_dat->data->work, pch_spi_process_messages); + init_waitqueue_head(&board_dat->data->wait); + + /* allocate resources for PCH SPI */ + retval = pch_spi_get_resources(board_dat); + if (retval) { + dev_err(&pdev->dev, "%s fail(retval=%d)\n", __func__, retval); + goto err_spi_get_resources; + } + + dev_dbg(&pdev->dev, "%s pch_spi_get_resources returned=%d\n", + __func__, retval); + + /* save private data in dev */ + pci_set_drvdata(pdev, board_dat); + dev_dbg(&pdev->dev, "%s invoked pci_set_drvdata\n", __func__); + + /* set master mode */ + pch_spi_set_master_mode(master); + dev_dbg(&pdev->dev, + "%s invoked pch_spi_set_master_mode\n", __func__); + + /* Register the controller with the SPI core. */ + retval = spi_register_master(master); + if (retval != 0) { + dev_err(&pdev->dev, + "%s spi_register_master FAILED\n", __func__); + goto err_spi_reg_master; + } + + dev_dbg(&pdev->dev, "%s spi_register_master returned=%d\n", + __func__, retval); + + + return 0; + +err_spi_reg_master: + spi_unregister_master(master); +err_spi_get_resources: +err_spi_alloc_master: + spi_master_put(master); + pci_disable_device(pdev); +err_pci_en_device: + kfree(board_dat); +err_kmalloc: + return retval; +} + +static void pch_spi_remove(struct pci_dev *pdev) +{ + struct pch_spi_board_data *board_dat = pci_get_drvdata(pdev); + int count; + + dev_dbg(&pdev->dev, "%s ENTRY\n", __func__); + + if (!board_dat) { + dev_err(&pdev->dev, + "%s pci_get_drvdata returned NULL\n", __func__); + return; + } + + /* check for any pending messages; no action is taken if the queue + * is still full; but at least we tried. Unload anyway */ + count = 500; + spin_lock(&board_dat->data->lock); + board_dat->data->status = STATUS_EXITING; + while ((list_empty(&board_dat->data->queue) == 0) && --count) { + dev_dbg(&board_dat->pdev->dev, "%s :queue not empty\n", + __func__); + spin_unlock(&board_dat->data->lock); + msleep(PCH_SLEEP_TIME); + spin_lock(&board_dat->data->lock); + } + spin_unlock(&board_dat->data->lock); + + /* Free resources allocated for PCH SPI */ + pch_spi_free_resources(board_dat); + + spi_unregister_master(board_dat->data->master); + + /* free memory for private data */ + kfree(board_dat); + + pci_set_drvdata(pdev, NULL); + + /* disable PCI device */ + pci_disable_device(pdev); + + dev_dbg(&pdev->dev, "%s invoked pci_disable_device\n", __func__); +} + +#ifdef CONFIG_PM +static int pch_spi_suspend(struct pci_dev *pdev, pm_message_t state) +{ + u8 count; + int retval; + + struct pch_spi_board_data *board_dat = pci_get_drvdata(pdev); + + dev_dbg(&pdev->dev, "%s ENTRY\n", __func__); + + if (!board_dat) { + dev_err(&pdev->dev, + "%s pci_get_drvdata returned NULL\n", __func__); + return -EFAULT; + } + + retval = 0; + board_dat->suspend_sts = true; + + /* check if the current message is processed: + Only after thats done the transfer will be suspended */ + count = 255; + while ((--count) > 0) { + if (!(board_dat->data->bcurrent_msg_processing)) { + dev_dbg(&pdev->dev, "%s board_dat->data->bCurrent_" + "msg_processing = false\n", __func__); + break; + } else { + dev_dbg(&pdev->dev, "%s board_dat->data->bCurrent_msg_" + "processing = true\n", __func__); + } + msleep(PCH_SLEEP_TIME); + } + + /* Free IRQ */ + if (board_dat->irq_reg_sts) { + /* disable all interrupts */ + pch_spi_setclr_reg(board_dat->data->master, PCH_SPCR, 0, + PCH_ALL); + pch_spi_reset(board_dat->data->master); + + free_irq(board_dat->pdev->irq, board_dat); + + board_dat->irq_reg_sts = false; + dev_dbg(&pdev->dev, + "%s free_irq invoked successfully.\n", __func__); + } + + /* save config space */ + retval = pci_save_state(pdev); + + if (retval == 0) { + dev_dbg(&pdev->dev, "%s pci_save_state returned=%d\n", + __func__, retval); + /* disable PM notifications */ + pci_enable_wake(pdev, PCI_D3hot, 0); + dev_dbg(&pdev->dev, + "%s pci_enable_wake invoked successfully\n", __func__); + /* disable PCI device */ + pci_disable_device(pdev); + dev_dbg(&pdev->dev, + "%s pci_disable_device invoked successfully\n", + __func__); + /* move device to D3hot state */ + pci_set_power_state(pdev, PCI_D3hot); + dev_dbg(&pdev->dev, + "%s pci_set_power_state invoked successfully\n", + __func__); + } else { + dev_err(&pdev->dev, "%s pci_save_state failed\n", __func__); + } + + dev_dbg(&pdev->dev, "%s return=%d\n", __func__, retval); + + return retval; +} + +static int pch_spi_resume(struct pci_dev *pdev) +{ + int retval; + + struct pch_spi_board_data *board = pci_get_drvdata(pdev); + dev_dbg(&pdev->dev, "%s ENTRY\n", __func__); + + if (!board) { + dev_err(&pdev->dev, + "%s pci_get_drvdata returned NULL\n", __func__); + return -EFAULT; + } + + /* move device to DO power state */ + pci_set_power_state(pdev, PCI_D0); + + /* restore state */ + pci_restore_state(pdev); + + retval = pci_enable_device(pdev); + if (retval < 0) { + dev_err(&pdev->dev, + "%s pci_enable_device failed\n", __func__); + } else { + /* disable PM notifications */ + pci_enable_wake(pdev, PCI_D3hot, 0); + + /* register IRQ handler */ + if (!board->irq_reg_sts) { + /* register IRQ */ + retval = request_irq(board->pdev->irq, pch_spi_handler, + IRQF_SHARED, KBUILD_MODNAME, + board); + if (retval < 0) { + dev_err(&pdev->dev, + "%s request_irq failed\n", __func__); + return retval; + } + board->irq_reg_sts = true; + + /* reset PCH SPI h/w */ + pch_spi_reset(board->data->master); + pch_spi_set_master_mode(board->data->master); + + /* set suspend status to false */ + board->suspend_sts = false; + + } + } + + dev_dbg(&pdev->dev, "%s returning=%d\n", __func__, retval); + + return retval; +} +#else +#define pch_spi_suspend NULL +#define pch_spi_resume NULL + +#endif + +static struct pci_driver pch_spi_pcidev = { + .name = "pch_spi", + .id_table = pch_spi_pcidev_id, + .probe = pch_spi_probe, + .remove = pch_spi_remove, + .suspend = pch_spi_suspend, + .resume = pch_spi_resume, +}; + +static int __init pch_spi_init(void) +{ + return pci_register_driver(&pch_spi_pcidev); +} +module_init(pch_spi_init); + +static void __exit pch_spi_exit(void) +{ + pci_unregister_driver(&pch_spi_pcidev); +} +module_exit(pch_spi_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Topcliff PCH SPI PCI Driver"); diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c index ea1bec3c9a13..4e6245e67995 100644 --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c @@ -545,6 +545,7 @@ static const struct file_operations spidev_fops = { .unlocked_ioctl = spidev_ioctl, .open = spidev_open, .release = spidev_release, + .llseek = no_llseek, }; /*-------------------------------------------------------------------------*/ diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index 7892ac163522..c68b3dc19e11 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c @@ -20,7 +20,6 @@ #include <linux/mmc/sdio_func.h> #include <linux/slab.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/ds.h> diff --git a/drivers/ssb/pcmcia.c b/drivers/ssb/pcmcia.c index 526682d68de8..c7345dbf43fa 100644 --- a/drivers/ssb/pcmcia.c +++ b/drivers/ssb/pcmcia.c @@ -13,7 +13,6 @@ #include <linux/io.h> #include <linux/etherdevice.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/ciscode.h> #include <pcmcia/ds.h> diff --git a/drivers/ssb/scan.c b/drivers/ssb/scan.c index 9738cad4ba13..ee079ab9fb28 100644 --- a/drivers/ssb/scan.c +++ b/drivers/ssb/scan.c @@ -17,7 +17,6 @@ #include <linux/pci.h> #include <linux/io.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/ds.h> diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index 14091313cebb..fecb89e8c663 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -1922,6 +1922,7 @@ const struct file_operations comedi_fops = { .mmap = comedi_mmap, .poll = comedi_poll, .fasync = comedi_fasync, + .llseek = noop_llseek, }; struct class *comedi_class; diff --git a/drivers/staging/comedi/drivers/cb_das16_cs.c b/drivers/staging/comedi/drivers/cb_das16_cs.c index f8ede1182ccc..0345b4caba73 100644 --- a/drivers/staging/comedi/drivers/cb_das16_cs.c +++ b/drivers/staging/comedi/drivers/cb_das16_cs.c @@ -37,7 +37,6 @@ Status: experimental #include <linux/delay.h> #include <linux/pci.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/ds.h> @@ -692,10 +691,6 @@ static int das16cs_pcmcia_attach(struct pcmcia_device *link) local->link = link; link->priv = local; - /* Initialize the pcmcia_device structure */ - link->conf.Attributes = 0; - link->conf.IntType = INT_MEMORY_AND_IO; - cur_dev = link; das16cs_pcmcia_config(link); @@ -715,37 +710,12 @@ static void das16cs_pcmcia_detach(struct pcmcia_device *link) static int das16cs_pcmcia_config_loop(struct pcmcia_device *p_dev, - cistpl_cftable_entry_t *cfg, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, void *priv_data) { - if (cfg->index == 0) + if (p_dev->config_index == 0) return -EINVAL; - /* Do we need to allocate an interrupt? */ - p_dev->conf.Attributes |= CONF_ENABLE_IRQ; - - /* IO window settings */ - p_dev->resource[0]->end = p_dev->resource[1]->end = 0; - if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) { - cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io; - p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK; - p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; - p_dev->resource[0]->flags |= - pcmcia_io_cfg_data_width(io->flags); - p_dev->resource[0]->start = io->win[0].base; - p_dev->resource[0]->end = io->win[0].len; - if (io->nwin > 1) { - p_dev->resource[1]->flags = p_dev->resource[0]->flags; - p_dev->resource[1]->start = io->win[1].base; - p_dev->resource[1]->end = io->win[1].len; - } - /* This reserves IO space but doesn't actually enable it */ - return pcmcia_request_io(p_dev); - } - - return 0; + return pcmcia_request_io(p_dev); } static void das16cs_pcmcia_config(struct pcmcia_device *link) @@ -754,6 +724,9 @@ static void das16cs_pcmcia_config(struct pcmcia_device *link) dev_dbg(&link->dev, "das16cs_pcmcia_config\n"); + /* Do we need to allocate an interrupt? */ + link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; + ret = pcmcia_loop_config(link, das16cs_pcmcia_config_loop, NULL); if (ret) { dev_warn(&link->dev, "no configuration found\n"); @@ -763,25 +736,10 @@ static void das16cs_pcmcia_config(struct pcmcia_device *link) if (!link->irq) goto failed; - /* - This actually configures the PCMCIA socket -- setting up - the I/O windows and the interrupt mapping, and putting the - card and host interface into "Memory and IO" mode. - */ - ret = pcmcia_request_configuration(link, &link->conf); + ret = pcmcia_enable_device(link); if (ret) goto failed; - /* Finally, report what we've done */ - dev_info(&link->dev, "index 0x%02x", link->conf.ConfigIndex); - if (link->conf.Attributes & CONF_ENABLE_IRQ) - printk(", irq %u", link->irq); - if (link->resource[0]) - printk(", io %pR", link->resource[0]); - if (link->resource[1]) - printk(", io %pR", link->resource[1]); - printk("\n"); - return; failed: @@ -832,9 +790,7 @@ struct pcmcia_driver das16cs_driver = { .resume = das16cs_pcmcia_resume, .id_table = das16cs_id_table, .owner = THIS_MODULE, - .drv = { - .name = "cb_das16_cs", - }, + .name = "cb_das16_cs", }; static int __init init_das16cs_pcmcia_cs(void) diff --git a/drivers/staging/comedi/drivers/das08_cs.c b/drivers/staging/comedi/drivers/das08_cs.c index 48d9fb1227df..0b32a2df7768 100644 --- a/drivers/staging/comedi/drivers/das08_cs.c +++ b/drivers/staging/comedi/drivers/das08_cs.c @@ -48,7 +48,6 @@ Command support does not exist, but could be added for this board. #include "das08.h" /* pcmcia includes */ -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/ds.h> @@ -115,40 +114,15 @@ static void das08_pcmcia_release(struct pcmcia_device *link); static int das08_pcmcia_suspend(struct pcmcia_device *p_dev); static int das08_pcmcia_resume(struct pcmcia_device *p_dev); -/* - The attach() and detach() entry points are used to create and destroy - "instances" of the driver, where each instance represents everything - needed to manage one actual PCMCIA card. -*/ - static int das08_pcmcia_attach(struct pcmcia_device *); static void das08_pcmcia_detach(struct pcmcia_device *); -/* - You'll also need to prototype all the functions that will actually - be used to talk to your device. See 'memory_cs' for a good example - of a fully self-sufficient driver; the other drivers rely more or - less on other parts of the kernel. -*/ - struct local_info_t { struct pcmcia_device *link; int stop; struct bus_operations *bus; }; -/*====================================================================== - - das08_pcmcia_attach() creates an "instance" of the driver, allocating - local data structures for one device. The device is registered - with Card Services. - - The dev_link structure is initialized, but we don't actually - configure the card at this point -- we wait until we receive a - card insertion event. - -======================================================================*/ - static int das08_pcmcia_attach(struct pcmcia_device *link) { struct local_info_t *local; @@ -162,16 +136,6 @@ static int das08_pcmcia_attach(struct pcmcia_device *link) local->link = link; link->priv = local; - /* - General socket configuration defaults can go here. In this - client, we assume very little, and rely on the CIS for almost - everything. In most clients, many details (i.e., number, sizes, - and attributes of IO windows) are fixed by the nature of the - device, and can be hard-wired here. - */ - link->conf.Attributes = 0; - link->conf.IntType = INT_MEMORY_AND_IO; - cur_dev = link; das08_pcmcia_config(link); @@ -179,15 +143,6 @@ static int das08_pcmcia_attach(struct pcmcia_device *link) return 0; } /* das08_pcmcia_attach */ -/*====================================================================== - - This deletes a driver "instance". The device is de-registered - with Card Services. If it has been released, all local data - structures are freed. Otherwise, the structures will be freed - when the device is released. - -======================================================================*/ - static void das08_pcmcia_detach(struct pcmcia_device *link) { @@ -203,46 +158,13 @@ static void das08_pcmcia_detach(struct pcmcia_device *link) static int das08_pcmcia_config_loop(struct pcmcia_device *p_dev, - cistpl_cftable_entry_t *cfg, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, void *priv_data) { - if (cfg->index == 0) - return -ENODEV; - - /* Do we need to allocate an interrupt? */ - p_dev->conf.Attributes |= CONF_ENABLE_IRQ; - - /* IO window settings */ - p_dev->resource[0]->end = p_dev->resource[1]->end = 0; - if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) { - cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io; - p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK; - p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; - p_dev->resource[0]->flags |= - pcmcia_io_cfg_data_width(io->flags); - p_dev->resource[0]->start = io->win[0].base; - p_dev->resource[0]->end = io->win[0].len; - if (io->nwin > 1) { - p_dev->resource[1]->flags = p_dev->resource[0]->flags; - p_dev->resource[1]->start = io->win[1].base; - p_dev->resource[1]->end = io->win[1].len; - } - /* This reserves IO space but doesn't actually enable it */ - return pcmcia_request_io(p_dev); - } - return 0; -} - - -/*====================================================================== - - das08_pcmcia_config() is scheduled to run after a CARD_INSERTION event - is received, to configure the PCMCIA socket, and to make the - device available to the system. + if (p_dev->config_index == 0) + return -EINVAL; -======================================================================*/ + return pcmcia_request_io(p_dev); +} static void das08_pcmcia_config(struct pcmcia_device *link) { @@ -250,6 +172,8 @@ static void das08_pcmcia_config(struct pcmcia_device *link) dev_dbg(&link->dev, "das08_pcmcia_config\n"); + link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; + ret = pcmcia_loop_config(link, das08_pcmcia_config_loop, NULL); if (ret) { dev_warn(&link->dev, "no configuration found\n"); @@ -259,25 +183,10 @@ static void das08_pcmcia_config(struct pcmcia_device *link) if (!link->irq) goto failed; - /* - This actually configures the PCMCIA socket -- setting up - the I/O windows and the interrupt mapping, and putting the - card and host interface into "Memory and IO" mode. - */ - ret = pcmcia_request_configuration(link, &link->conf); + ret = pcmcia_enable_device(link); if (ret) goto failed; - /* Finally, report what we've done */ - dev_info(&link->dev, "index 0x%02x", link->conf.ConfigIndex); - if (link->conf.Attributes & CONF_ENABLE_IRQ) - printk(", irq %u", link->irq); - if (link->resource[0]) - printk(", io %pR", link->resource[0]); - if (link->resource[1]) - printk(" & %pR", link->resource[1]); - printk("\n"); - return; failed: @@ -285,32 +194,12 @@ failed: } /* das08_pcmcia_config */ -/*====================================================================== - - After a card is removed, das08_pcmcia_release() will unregister the - device, and release the PCMCIA configuration. If the device is - still open, this will be postponed until it is closed. - -======================================================================*/ - static void das08_pcmcia_release(struct pcmcia_device *link) { dev_dbg(&link->dev, "das08_pcmcia_release\n"); pcmcia_disable_device(link); } /* das08_pcmcia_release */ -/*====================================================================== - - The card status event handler. Mostly, this schedules other - stuff to run after an event is received. - - When a CARD_REMOVAL event is received, we immediately set a - private flag to block future accesses to this device. All the - functions that actually access the device should check this flag - to make sure the card is still present. - -======================================================================*/ - static int das08_pcmcia_suspend(struct pcmcia_device *link) { struct local_info_t *local = link->priv; @@ -348,9 +237,7 @@ struct pcmcia_driver das08_cs_driver = { .resume = das08_pcmcia_resume, .id_table = das08_cs_id_table, .owner = THIS_MODULE, - .drv = { - .name = "pcm-das08", - }, + .name = "pcm-das08", }; static int __init init_das08_pcmcia_cs(void) diff --git a/drivers/staging/comedi/drivers/ni_daq_700.c b/drivers/staging/comedi/drivers/ni_daq_700.c index cc15666e5cc1..6b7372eed90d 100644 --- a/drivers/staging/comedi/drivers/ni_daq_700.c +++ b/drivers/staging/comedi/drivers/ni_daq_700.c @@ -47,7 +47,6 @@ IRQ is assigned but not used. #include <linux/ioport.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/cisreg.h> #include <pcmcia/ds.h> @@ -435,47 +434,20 @@ static int dio700_detach(struct comedi_device *dev) return 0; }; -/* PCMCIA crap -- watch your words, please! */ - static void dio700_config(struct pcmcia_device *link); static void dio700_release(struct pcmcia_device *link); static int dio700_cs_suspend(struct pcmcia_device *p_dev); static int dio700_cs_resume(struct pcmcia_device *p_dev); -/* - The attach() and detach() entry points are used to create and destroy - "instances" of the driver, where each instance represents everything - needed to manage one actual PCMCIA card. -*/ - static int dio700_cs_attach(struct pcmcia_device *); static void dio700_cs_detach(struct pcmcia_device *); -/* - You'll also need to prototype all the functions that will actually - be used to talk to your device. See 'memory_cs' for a good example - of a fully self-sufficient driver; the other drivers rely more or - less on other parts of the kernel. -*/ - struct local_info_t { struct pcmcia_device *link; int stop; struct bus_operations *bus; }; -/*====================================================================== - - dio700_cs_attach() creates an "instance" of the driver, allocating - local data structures for one device. The device is registered - with Card Services. - - The dev_link structure is initialized, but we don't actually - configure the card at this point -- we wait until we receive a - card insertion event. - -======================================================================*/ - static int dio700_cs_attach(struct pcmcia_device *link) { struct local_info_t *local; @@ -491,16 +463,6 @@ static int dio700_cs_attach(struct pcmcia_device *link) local->link = link; link->priv = local; - /* - General socket configuration defaults can go here. In this - client, we assume very little, and rely on the CIS for almost - everything. In most clients, many details (i.e., number, sizes, - and attributes of IO windows) are fixed by the nature of the - device, and can be hard-wired here. - */ - link->conf.Attributes = 0; - link->conf.IntType = INT_MEMORY_AND_IO; - pcmcia_cur_dev = link; dio700_config(link); @@ -508,15 +470,6 @@ static int dio700_cs_attach(struct pcmcia_device *link) return 0; } /* dio700_cs_attach */ -/*====================================================================== - - This deletes a driver "instance". The device is de-registered - with Card Services. If it has been released, all local data - structures are freed. Otherwise, the structures will be freed - when the device is released. - -======================================================================*/ - static void dio700_cs_detach(struct pcmcia_device *link) { @@ -532,65 +485,26 @@ static void dio700_cs_detach(struct pcmcia_device *link) } /* dio700_cs_detach */ -/*====================================================================== - - dio700_config() is scheduled to run after a CARD_INSERTION event - is received, to configure the PCMCIA socket, and to make the - device available to the system. - -======================================================================*/ - static int dio700_pcmcia_config_loop(struct pcmcia_device *p_dev, - cistpl_cftable_entry_t *cfg, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, void *priv_data) { - if (cfg->index == 0) - return -ENODEV; - - /* Does this card need audio output? */ - if (cfg->flags & CISTPL_CFTABLE_AUDIO) { - p_dev->conf.Attributes |= CONF_ENABLE_SPKR; - p_dev->conf.Status = CCSR_AUDIO_ENA; - } - - /* Do we need to allocate an interrupt? */ - p_dev->conf.Attributes |= CONF_ENABLE_IRQ; - - /* IO window settings */ - p_dev->resource[0]->end = p_dev->resource[1]->end = 0; - if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) { - cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io; - p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK; - p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; - p_dev->resource[0]->flags |= - pcmcia_io_cfg_data_width(io->flags); - p_dev->resource[0]->start = io->win[0].base; - p_dev->resource[0]->end = io->win[0].len; - if (io->nwin > 1) { - p_dev->resource[1]->flags = p_dev->resource[0]->flags; - p_dev->resource[1]->start = io->win[1].base; - p_dev->resource[1]->end = io->win[1].len; - } - /* This reserves IO space but doesn't actually enable it */ - if (pcmcia_request_io(p_dev) != 0) - return -ENODEV; - } + if (p_dev->config_index == 0) + return -EINVAL; - /* If we got this far, we're cool! */ - return 0; + return pcmcia_request_io(p_dev); } static void dio700_config(struct pcmcia_device *link) { - win_req_t req; int ret; printk(KERN_INFO "ni_daq_700: cs-config\n"); dev_dbg(&link->dev, "dio700_config\n"); + link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_AUDIO | + CONF_AUTO_SET_IO; + ret = pcmcia_loop_config(link, dio700_pcmcia_config_loop, NULL); if (ret) { dev_warn(&link->dev, "no configuration found\n"); @@ -600,25 +514,10 @@ static void dio700_config(struct pcmcia_device *link) if (!link->irq) goto failed; - /* - This actually configures the PCMCIA socket -- setting up - the I/O windows and the interrupt mapping, and putting the - card and host interface into "Memory and IO" mode. - */ - ret = pcmcia_request_configuration(link, &link->conf); + ret = pcmcia_enable_device(link); if (ret != 0) goto failed; - /* Finally, report what we've done */ - dev_info(&link->dev, "index 0x%02x", link->conf.ConfigIndex); - if (link->conf.Attributes & CONF_ENABLE_IRQ) - printk(", irq %d", link->irq); - if (link->resource[0]) - printk(", io %pR", link->resource[0]); - if (link->resource[1]) - printk(" & %pR", link->resource[1]); - printk("\n"); - return; failed: @@ -634,18 +533,6 @@ static void dio700_release(struct pcmcia_device *link) pcmcia_disable_device(link); } /* dio700_release */ -/*====================================================================== - - The card status event handler. Mostly, this schedules other - stuff to run after an event is received. - - When a CARD_REMOVAL event is received, we immediately set a - private flag to block future accesses to this device. All the - functions that actually access the device should check this flag - to make sure the card is still present. - -======================================================================*/ - static int dio700_cs_suspend(struct pcmcia_device *link) { struct local_info_t *local = link->priv; @@ -685,9 +572,7 @@ struct pcmcia_driver dio700_cs_driver = { .resume = dio700_cs_resume, .id_table = dio700_cs_ids, .owner = THIS_MODULE, - .drv = { - .name = "ni_daq_700", - }, + .name = "ni_daq_700", }; static int __init init_dio700_cs(void) diff --git a/drivers/staging/comedi/drivers/ni_daq_dio24.c b/drivers/staging/comedi/drivers/ni_daq_dio24.c index 773ae2044e0e..c9c28584db67 100644 --- a/drivers/staging/comedi/drivers/ni_daq_dio24.c +++ b/drivers/staging/comedi/drivers/ni_daq_dio24.c @@ -48,7 +48,6 @@ the PCMCIA interface. #include "8255.h" -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/cisreg.h> #include <pcmcia/ds.h> @@ -187,47 +186,20 @@ static int dio24_detach(struct comedi_device *dev) return 0; }; -/* PCMCIA crap -- watch your words! */ - static void dio24_config(struct pcmcia_device *link); static void dio24_release(struct pcmcia_device *link); static int dio24_cs_suspend(struct pcmcia_device *p_dev); static int dio24_cs_resume(struct pcmcia_device *p_dev); -/* - The attach() and detach() entry points are used to create and destroy - "instances" of the driver, where each instance represents everything - needed to manage one actual PCMCIA card. -*/ - static int dio24_cs_attach(struct pcmcia_device *); static void dio24_cs_detach(struct pcmcia_device *); -/* - You'll also need to prototype all the functions that will actually - be used to talk to your device. See 'memory_cs' for a good example - of a fully self-sufficient driver; the other drivers rely more or - less on other parts of the kernel. -*/ - struct local_info_t { struct pcmcia_device *link; int stop; struct bus_operations *bus; }; -/*====================================================================== - - dio24_cs_attach() creates an "instance" of the driver, allocating - local data structures for one device. The device is registered - with Card Services. - - The dev_link structure is initialized, but we don't actually - configure the card at this point -- we wait until we receive a - card insertion event. - -======================================================================*/ - static int dio24_cs_attach(struct pcmcia_device *link) { struct local_info_t *local; @@ -243,16 +215,6 @@ static int dio24_cs_attach(struct pcmcia_device *link) local->link = link; link->priv = local; - /* - General socket configuration defaults can go here. In this - client, we assume very little, and rely on the CIS for almost - everything. In most clients, many details (i.e., number, sizes, - and attributes of IO windows) are fixed by the nature of the - device, and can be hard-wired here. - */ - link->conf.Attributes = 0; - link->conf.IntType = INT_MEMORY_AND_IO; - pcmcia_cur_dev = link; dio24_config(link); @@ -260,15 +222,6 @@ static int dio24_cs_attach(struct pcmcia_device *link) return 0; } /* dio24_cs_attach */ -/*====================================================================== - - This deletes a driver "instance". The device is de-registered - with Card Services. If it has been released, all local data - structures are freed. Otherwise, the structures will be freed - when the device is released. - -======================================================================*/ - static void dio24_cs_detach(struct pcmcia_device *link) { @@ -284,54 +237,13 @@ static void dio24_cs_detach(struct pcmcia_device *link) } /* dio24_cs_detach */ -/*====================================================================== - - dio24_config() is scheduled to run after a CARD_INSERTION event - is received, to configure the PCMCIA socket, and to make the - device available to the system. - -======================================================================*/ - static int dio24_pcmcia_config_loop(struct pcmcia_device *p_dev, - cistpl_cftable_entry_t *cfg, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, void *priv_data) { - if (cfg->index == 0) - return -ENODEV; - - /* Does this card need audio output? */ - if (cfg->flags & CISTPL_CFTABLE_AUDIO) { - p_dev->conf.Attributes |= CONF_ENABLE_SPKR; - p_dev->conf.Status = CCSR_AUDIO_ENA; - } - - /* Do we need to allocate an interrupt? */ - p_dev->conf.Attributes |= CONF_ENABLE_IRQ; - - /* IO window settings */ - p_dev->resource[0]->end = p_dev->resource[1]->end = 0; - if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) { - cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io; - p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK; - p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; - p_dev->resource[0]->flags |= - pcmcia_io_cfg_data_width(io->flags); - p_dev->resource[0]->start = io->win[0].base; - p_dev->resource[0]->end = io->win[0].len; - if (io->nwin > 1) { - p_dev->resource[1]->flags = p_dev->resource[0]->flags; - p_dev->resource[1]->start = io->win[1].base; - p_dev->resource[1]->end = io->win[1].len; - } - /* This reserves IO space but doesn't actually enable it */ - if (pcmcia_request_io(p_dev) != 0) - return -ENODEV; - } + if (p_dev->config_index == 0) + return -EINVAL; - /* If we got this far, we're cool! */ - return 0; + return pcmcia_request_io(p_dev); } static void dio24_config(struct pcmcia_device *link) @@ -342,6 +254,9 @@ static void dio24_config(struct pcmcia_device *link) dev_dbg(&link->dev, "dio24_config\n"); + link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_AUDIO | + CONF_AUTO_SET_IO; + ret = pcmcia_loop_config(link, dio24_pcmcia_config_loop, NULL); if (ret) { dev_warn(&link->dev, "no configuration found\n"); @@ -351,25 +266,10 @@ static void dio24_config(struct pcmcia_device *link) if (!link->irq) goto failed; - /* - This actually configures the PCMCIA socket -- setting up - the I/O windows and the interrupt mapping, and putting the - card and host interface into "Memory and IO" mode. - */ - ret = pcmcia_request_configuration(link, &link->conf); + ret = pcmcia_enable_device(link); if (ret) goto failed; - /* Finally, report what we've done */ - dev_info(&link->dev, "index 0x%02x", link->conf.ConfigIndex); - if (link->conf.Attributes & CONF_ENABLE_IRQ) - printk(", irq %d", link->irq); - if (link->resource[0]) - printk(" & %pR", link->resource[0]); - if (link->resource[1]) - printk(" & %pR", link->resource[1]); - printk("\n"); - return; failed: @@ -385,18 +285,6 @@ static void dio24_release(struct pcmcia_device *link) pcmcia_disable_device(link); } /* dio24_release */ -/*====================================================================== - - The card status event handler. Mostly, this schedules other - stuff to run after an event is received. - - When a CARD_REMOVAL event is received, we immediately set a - private flag to block future accesses to this device. All the - functions that actually access the device should check this flag - to make sure the card is still present. - -======================================================================*/ - static int dio24_cs_suspend(struct pcmcia_device *link) { struct local_info_t *local = link->priv; @@ -435,9 +323,7 @@ struct pcmcia_driver dio24_cs_driver = { .resume = dio24_cs_resume, .id_table = dio24_cs_ids, .owner = THIS_MODULE, - .drv = { - .name = "ni_daq_dio24", - }, + .name = "ni_daq_dio24", }; static int __init init_dio24_cs(void) diff --git a/drivers/staging/comedi/drivers/ni_labpc_cs.c b/drivers/staging/comedi/drivers/ni_labpc_cs.c index 68c4ecbd93ae..6facbc8bf776 100644 --- a/drivers/staging/comedi/drivers/ni_labpc_cs.c +++ b/drivers/staging/comedi/drivers/ni_labpc_cs.c @@ -71,7 +71,6 @@ NI manuals: #include "comedi_fc.h" #include "ni_labpc.h" -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/cisreg.h> #include <pcmcia/ds.h> @@ -153,59 +152,20 @@ static int labpc_attach(struct comedi_device *dev, struct comedi_devconfig *it) return labpc_common_attach(dev, iobase, irq, 0); } -/*====================================================================*/ - -/* - The event() function is this driver's Card Services event handler. - It will be called by Card Services when an appropriate card status - event is received. The config() and release() entry points are - used to configure or release a socket, in response to card - insertion and ejection events. They are invoked from the dummy - event handler. - - Kernel version 2.6.16 upwards uses suspend() and resume() functions - instead of an event() function. -*/ - static void labpc_config(struct pcmcia_device *link); static void labpc_release(struct pcmcia_device *link); static int labpc_cs_suspend(struct pcmcia_device *p_dev); static int labpc_cs_resume(struct pcmcia_device *p_dev); -/* - The attach() and detach() entry points are used to create and destroy - "instances" of the driver, where each instance represents everything - needed to manage one actual PCMCIA card. -*/ - static int labpc_cs_attach(struct pcmcia_device *); static void labpc_cs_detach(struct pcmcia_device *); -/* - You'll also need to prototype all the functions that will actually - be used to talk to your device. See 'memory_cs' for a good example - of a fully self-sufficient driver; the other drivers rely more or - less on other parts of the kernel. -*/ - struct local_info_t { struct pcmcia_device *link; int stop; struct bus_operations *bus; }; -/*====================================================================== - - labpc_cs_attach() creates an "instance" of the driver, allocating - local data structures for one device. The device is registered - with Card Services. - - The dev_link structure is initialized, but we don't actually - configure the card at this point -- we wait until we receive a - card insertion event. - -======================================================================*/ - static int labpc_cs_attach(struct pcmcia_device *link) { struct local_info_t *local; @@ -219,16 +179,6 @@ static int labpc_cs_attach(struct pcmcia_device *link) local->link = link; link->priv = local; - /* - General socket configuration defaults can go here. In this - client, we assume very little, and rely on the CIS for almost - everything. In most clients, many details (i.e., number, sizes, - and attributes of IO windows) are fixed by the nature of the - device, and can be hard-wired here. - */ - link->conf.Attributes = 0; - link->conf.IntType = INT_MEMORY_AND_IO; - pcmcia_cur_dev = link; labpc_config(link); @@ -236,15 +186,6 @@ static int labpc_cs_attach(struct pcmcia_device *link) return 0; } /* labpc_cs_attach */ -/*====================================================================== - - This deletes a driver "instance". The device is de-registered - with Card Services. If it has been released, all local data - structures are freed. Otherwise, the structures will be freed - when the device is released. - -======================================================================*/ - static void labpc_cs_detach(struct pcmcia_device *link) { dev_dbg(&link->dev, "labpc_cs_detach\n"); @@ -263,54 +204,13 @@ static void labpc_cs_detach(struct pcmcia_device *link) } /* labpc_cs_detach */ -/*====================================================================== - - labpc_config() is scheduled to run after a CARD_INSERTION event - is received, to configure the PCMCIA socket, and to make the - device available to the system. - -======================================================================*/ - static int labpc_pcmcia_config_loop(struct pcmcia_device *p_dev, - cistpl_cftable_entry_t *cfg, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, void *priv_data) { - if (cfg->index == 0) - return -ENODEV; - - /* Does this card need audio output? */ - if (cfg->flags & CISTPL_CFTABLE_AUDIO) { - p_dev->conf.Attributes |= CONF_ENABLE_SPKR; - p_dev->conf.Status = CCSR_AUDIO_ENA; - } - - /* Do we need to allocate an interrupt? */ - p_dev->conf.Attributes |= CONF_ENABLE_IRQ | CONF_ENABLE_PULSE_IRQ; - - /* IO window settings */ - p_dev->resource[0]->end = p_dev->resource[1]->end = 0; - if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) { - cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io; - p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK; - p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; - p_dev->resource[0]->flags |= - pcmcia_io_cfg_data_width(io->flags); - p_dev->resource[0]->start = io->win[0].base; - p_dev->resource[0]->end = io->win[0].len; - if (io->nwin > 1) { - p_dev->resource[1]->flags = p_dev->resource[0]->flags; - p_dev->resource[1]->start = io->win[1].base; - p_dev->resource[1]->end = io->win[1].len; - } - /* This reserves IO space but doesn't actually enable it */ - if (pcmcia_request_io(p_dev) != 0) - return -ENODEV; - } + if (p_dev->config_index == 0) + return -EINVAL; - /* If we got this far, we're cool! */ - return 0; + return pcmcia_request_io(p_dev); } @@ -320,6 +220,9 @@ static void labpc_config(struct pcmcia_device *link) dev_dbg(&link->dev, "labpc_config\n"); + link->config_flags |= CONF_ENABLE_IRQ | CONF_ENABLE_PULSE_IRQ | + CONF_AUTO_AUDIO | CONF_AUTO_SET_IO; + ret = pcmcia_loop_config(link, labpc_pcmcia_config_loop, NULL); if (ret) { dev_warn(&link->dev, "no configuration found\n"); @@ -329,25 +232,10 @@ static void labpc_config(struct pcmcia_device *link) if (!link->irq) goto failed; - /* - This actually configures the PCMCIA socket -- setting up - the I/O windows and the interrupt mapping, and putting the - card and host interface into "Memory and IO" mode. - */ - ret = pcmcia_request_configuration(link, &link->conf); + ret = pcmcia_enable_device(link); if (ret) goto failed; - /* Finally, report what we've done */ - dev_info(&link->dev, "index 0x%02x", link->conf.ConfigIndex); - if (link->conf.Attributes & CONF_ENABLE_IRQ) - printk(", irq %d", link->irq); - if (link->resource[0]) - printk(" & %pR", link->resource[0]); - if (link->resource[1]) - printk(" & %pR", link->resource[1]); - printk("\n"); - return; failed: @@ -362,18 +250,6 @@ static void labpc_release(struct pcmcia_device *link) pcmcia_disable_device(link); } /* labpc_release */ -/*====================================================================== - - The card status event handler. Mostly, this schedules other - stuff to run after an event is received. - - When a CARD_REMOVAL event is received, we immediately set a - private flag to block future accesses to this device. All the - functions that actually access the device should check this flag - to make sure the card is still present. - -======================================================================*/ - static int labpc_cs_suspend(struct pcmcia_device *link) { struct local_info_t *local = link->priv; @@ -391,8 +267,6 @@ static int labpc_cs_resume(struct pcmcia_device *link) return 0; } /* labpc_cs_resume */ -/*====================================================================*/ - static struct pcmcia_device_id labpc_cs_ids[] = { /* N.B. These IDs should match those in labpc_cs_boards (ni_labpc.c) */ PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0103), /* daqcard-1200 */ @@ -411,9 +285,7 @@ struct pcmcia_driver labpc_cs_driver = { .resume = labpc_cs_resume, .id_table = labpc_cs_ids, .owner = THIS_MODULE, - .drv = { - .name = "daqcard-1200", - }, + .name = "daqcard-1200", }; static int __init init_labpc_cs(void) diff --git a/drivers/staging/comedi/drivers/ni_mio_cs.c b/drivers/staging/comedi/drivers/ni_mio_cs.c index 1f2426352eb5..49563273f605 100644 --- a/drivers/staging/comedi/drivers/ni_mio_cs.c +++ b/drivers/staging/comedi/drivers/ni_mio_cs.c @@ -48,7 +48,6 @@ See the notes in the ni_atmio.o driver. #include "ni_stc.h" #include "8255.h" -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/ds.h> @@ -263,11 +262,6 @@ static struct pcmcia_device *cur_dev = NULL; static int cs_attach(struct pcmcia_device *link) { - link->resource[0]->flags |= IO_DATA_PATH_WIDTH_16; - link->resource[0]->end = 16; - link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.IntType = INT_MEMORY_AND_IO; - cur_dev = link; mio_cs_config(link); @@ -301,16 +295,12 @@ static int mio_cs_resume(struct pcmcia_device *link) } -static int mio_pcmcia_config_loop(struct pcmcia_device *p_dev, - cistpl_cftable_entry_t *cfg, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, - void *priv_data) +static int mio_pcmcia_config_loop(struct pcmcia_device *p_dev, void *priv_data) { int base, ret; - p_dev->resource[0]->end = cfg->io.win[0].len; - p_dev->io_lines = cfg->io.flags & CISTPL_IO_LINES_MASK; + p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; + p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_16; for (base = 0x000; base < 0x400; base += 0x20) { p_dev->resource[0]->start = base; @@ -327,6 +317,7 @@ static void mio_cs_config(struct pcmcia_device *link) int ret; DPRINTK("mio_cs_config(link=%p)\n", link); + link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; ret = pcmcia_loop_config(link, mio_pcmcia_config_loop, NULL); if (ret) { @@ -337,7 +328,7 @@ static void mio_cs_config(struct pcmcia_device *link) if (!link->irq) dev_info(&link->dev, "no IRQ available\n"); - ret = pcmcia_request_configuration(link, &link->conf); + ret = pcmcia_enable_device(link); } static int mio_cs_attach(struct comedi_device *dev, struct comedi_devconfig *it) @@ -446,9 +437,7 @@ struct pcmcia_driver ni_mio_cs_driver = { .resume = &mio_cs_resume, .id_table = ni_mio_cs_ids, .owner = THIS_MODULE, - .drv = { - .name = "ni_mio_cs", - }, + .name = "ni_mio_cs", }; int init_module(void) diff --git a/drivers/staging/comedi/drivers/quatech_daqp_cs.c b/drivers/staging/comedi/drivers/quatech_daqp_cs.c index bf489d7f4990..ebba9bb47777 100644 --- a/drivers/staging/comedi/drivers/quatech_daqp_cs.c +++ b/drivers/staging/comedi/drivers/quatech_daqp_cs.c @@ -50,7 +50,6 @@ Devices: [Quatech] DAQP-208 (daqp), DAQP-308 #include "../comedidev.h" #include <linux/semaphore.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/cisreg.h> #include <pcmcia/ds.h> @@ -969,43 +968,14 @@ static int daqp_detach(struct comedi_device *dev) ======================================================================*/ -/* - The event() function is this driver's Card Services event handler. - It will be called by Card Services when an appropriate card status - event is received. The config() and release() entry points are - used to configure or release a socket, in response to card - insertion and ejection events. - - Kernel version 2.6.16 upwards uses suspend() and resume() functions - instead of an event() function. -*/ - static void daqp_cs_config(struct pcmcia_device *link); static void daqp_cs_release(struct pcmcia_device *link); static int daqp_cs_suspend(struct pcmcia_device *p_dev); static int daqp_cs_resume(struct pcmcia_device *p_dev); -/* - The attach() and detach() entry points are used to create and destroy - "instances" of the driver, where each instance represents everything - needed to manage one actual PCMCIA card. -*/ - static int daqp_cs_attach(struct pcmcia_device *); static void daqp_cs_detach(struct pcmcia_device *); -/*====================================================================== - - daqp_cs_attach() creates an "instance" of the driver, allocating - local data structures for one device. The device is registered - with Card Services. - - The dev_link structure is initialized, but we don't actually - configure the card at this point -- we wait until we receive a - card insertion event. - -======================================================================*/ - static int daqp_cs_attach(struct pcmcia_device *link) { struct local_info_t *local; @@ -1031,30 +1001,11 @@ static int daqp_cs_attach(struct pcmcia_device *link) local->link = link; link->priv = local; - /* - General socket configuration defaults can go here. In this - client, we assume very little, and rely on the CIS for almost - everything. In most clients, many details (i.e., number, sizes, - and attributes of IO windows) are fixed by the nature of the - device, and can be hard-wired here. - */ - link->conf.Attributes = 0; - link->conf.IntType = INT_MEMORY_AND_IO; - daqp_cs_config(link); return 0; } /* daqp_cs_attach */ -/*====================================================================== - - This deletes a driver "instance". The device is de-registered - with Card Services. If it has been released, all local data - structures are freed. Otherwise, the structures will be freed - when the device is released. - -======================================================================*/ - static void daqp_cs_detach(struct pcmcia_device *link) { struct local_info_t *dev = link->priv; @@ -1070,45 +1021,11 @@ static void daqp_cs_detach(struct pcmcia_device *link) } /* daqp_cs_detach */ -/*====================================================================== - - daqp_cs_config() is scheduled to run after a CARD_INSERTION event - is received, to configure the PCMCIA socket, and to make the - device available to the system. - -======================================================================*/ - - -static int daqp_pcmcia_config_loop(struct pcmcia_device *p_dev, - cistpl_cftable_entry_t *cfg, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, - void *priv_data) +static int daqp_pcmcia_config_loop(struct pcmcia_device *p_dev, void *priv_data) { - if (cfg->index == 0) - return -ENODEV; + if (p_dev->config_index == 0) + return -EINVAL; - /* Do we need to allocate an interrupt? */ - p_dev->conf.Attributes |= CONF_ENABLE_IRQ; - - /* IO window settings */ - p_dev->resource[0]->end = p_dev->resource[1]->end = 0; - if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) { - cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io; - p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK; - p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; - p_dev->resource[0]->flags |= - pcmcia_io_cfg_data_width(io->flags); - p_dev->resource[0]->start = io->win[0].base; - p_dev->resource[0]->end = io->win[0].len; - if (io->nwin > 1) { - p_dev->resource[1]->flags = p_dev->resource[0]->flags; - p_dev->resource[1]->start = io->win[1].base; - p_dev->resource[1]->end = io->win[1].len; - } - } - - /* This reserves IO space but doesn't actually enable it */ return pcmcia_request_io(p_dev); } @@ -1118,6 +1035,8 @@ static void daqp_cs_config(struct pcmcia_device *link) dev_dbg(&link->dev, "daqp_cs_config\n"); + link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; + ret = pcmcia_loop_config(link, daqp_pcmcia_config_loop, NULL); if (ret) { dev_warn(&link->dev, "no configuration found\n"); @@ -1128,25 +1047,10 @@ static void daqp_cs_config(struct pcmcia_device *link) if (ret) goto failed; - /* - This actually configures the PCMCIA socket -- setting up - the I/O windows and the interrupt mapping, and putting the - card and host interface into "Memory and IO" mode. - */ - ret = pcmcia_request_configuration(link, &link->conf); + ret = pcmcia_enable_device(link); if (ret) goto failed; - /* Finally, report what we've done */ - dev_info(&link->dev, "index 0x%02x", link->conf.ConfigIndex); - if (link->conf.Attributes & CONF_ENABLE_IRQ) - printk(", irq %u", link->irq); - if (link->resource[0]) - printk(" & %pR", link->resource[0]); - if (link->resource[1]) - printk(" & %pR", link->resource[1]); - printk("\n"); - return; failed: @@ -1161,18 +1065,6 @@ static void daqp_cs_release(struct pcmcia_device *link) pcmcia_disable_device(link); } /* daqp_cs_release */ -/*====================================================================== - - The card status event handler. Mostly, this schedules other - stuff to run after an event is received. - - When a CARD_REMOVAL event is received, we immediately set a - private flag to block future accesses to this device. All the - functions that actually access the device should check this flag - to make sure the card is still present. - -======================================================================*/ - static int daqp_cs_suspend(struct pcmcia_device *link) { struct local_info_t *local = link->priv; @@ -1212,9 +1104,7 @@ static struct pcmcia_driver daqp_cs_driver = { .resume = daqp_cs_resume, .id_table = daqp_cs_id_table, .owner = THIS_MODULE, - .drv = { - .name = "quatech_daqp_cs", - }, + .name = "quatech_daqp_cs", }; int __init init_module(void) diff --git a/drivers/staging/crystalhd/crystalhd_lnx.c b/drivers/staging/crystalhd/crystalhd_lnx.c index fbb80f09a3d9..af258991fe7f 100644 --- a/drivers/staging/crystalhd/crystalhd_lnx.c +++ b/drivers/staging/crystalhd/crystalhd_lnx.c @@ -351,6 +351,7 @@ static const struct file_operations chd_dec_fops = { .unlocked_ioctl = chd_dec_ioctl, .open = chd_dec_open, .release = chd_dec_close, + .llseek = noop_llseek, }; static int __devinit chd_dec_init_chdev(struct crystalhd_adp *adp) diff --git a/drivers/staging/cx25821/Kconfig b/drivers/staging/cx25821/Kconfig index df7756a95fad..813cb355ac01 100644 --- a/drivers/staging/cx25821/Kconfig +++ b/drivers/staging/cx25821/Kconfig @@ -1,6 +1,7 @@ config VIDEO_CX25821 tristate "Conexant cx25821 support" depends on DVB_CORE && VIDEO_DEV && PCI && I2C && INPUT + depends on BKL # please fix select I2C_ALGOBIT select VIDEO_BTCX select VIDEO_TVEEPROM diff --git a/drivers/staging/dream/camera/msm_camera.c b/drivers/staging/dream/camera/msm_camera.c index 81bd71fd816e..de4ab61efd4b 100644 --- a/drivers/staging/dream/camera/msm_camera.c +++ b/drivers/staging/dream/camera/msm_camera.c @@ -1941,6 +1941,7 @@ static const struct file_operations msm_fops_config = { .open = msm_open, .unlocked_ioctl = msm_ioctl_config, .release = msm_release_config, + .llseek = no_llseek, }; static const struct file_operations msm_fops_control = { @@ -1948,6 +1949,7 @@ static const struct file_operations msm_fops_control = { .open = msm_open_control, .unlocked_ioctl = msm_ioctl_control, .release = msm_release_control, + .llseek = no_llseek, }; static const struct file_operations msm_fops_frame = { @@ -1956,6 +1958,7 @@ static const struct file_operations msm_fops_frame = { .unlocked_ioctl = msm_ioctl_frame, .release = msm_release_frame, .poll = msm_poll_frame, + .llseek = no_llseek, }; static int msm_setup_cdev(struct msm_device *msm, diff --git a/drivers/staging/dream/pmem.c b/drivers/staging/dream/pmem.c index 7d6bbadd7fc7..3640d1f2376d 100644 --- a/drivers/staging/dream/pmem.c +++ b/drivers/staging/dream/pmem.c @@ -180,6 +180,7 @@ const struct file_operations pmem_fops = { .mmap = pmem_mmap, .open = pmem_open, .unlocked_ioctl = pmem_ioctl, + .llseek = noop_llseek, }; static int get_id(struct file *file) @@ -1204,6 +1205,7 @@ static ssize_t debug_read(struct file *file, char __user *buf, size_t count, static struct file_operations debug_fops = { .read = debug_read, .open = debug_open, + .llseek = default_llseek, }; #endif diff --git a/drivers/staging/dream/qdsp5/adsp_driver.c b/drivers/staging/dream/qdsp5/adsp_driver.c index 8197765aae1e..28a6f8da9477 100644 --- a/drivers/staging/dream/qdsp5/adsp_driver.c +++ b/drivers/staging/dream/qdsp5/adsp_driver.c @@ -582,6 +582,7 @@ static struct file_operations adsp_fops = { .open = adsp_open, .unlocked_ioctl = adsp_ioctl, .release = adsp_release, + .llseek = no_llseek, }; static void adsp_create(struct adsp_device *adev, const char *name, diff --git a/drivers/staging/dream/qdsp5/audio_aac.c b/drivers/staging/dream/qdsp5/audio_aac.c index a373f3522384..45f4c78ab6e7 100644 --- a/drivers/staging/dream/qdsp5/audio_aac.c +++ b/drivers/staging/dream/qdsp5/audio_aac.c @@ -1030,6 +1030,7 @@ static struct file_operations audio_aac_fops = { .read = audio_read, .write = audio_write, .unlocked_ioctl = audio_ioctl, + .llseek = noop_llseek, }; struct miscdevice audio_aac_misc = { diff --git a/drivers/staging/dream/qdsp5/audio_amrnb.c b/drivers/staging/dream/qdsp5/audio_amrnb.c index 07b79d5836e5..402bbc13281a 100644 --- a/drivers/staging/dream/qdsp5/audio_amrnb.c +++ b/drivers/staging/dream/qdsp5/audio_amrnb.c @@ -841,6 +841,7 @@ static struct file_operations audio_amrnb_fops = { .read = audamrnb_read, .write = audamrnb_write, .unlocked_ioctl = audamrnb_ioctl, + .llseek = noop_llseek, }; struct miscdevice audio_amrnb_misc = { diff --git a/drivers/staging/dream/qdsp5/audio_evrc.c b/drivers/staging/dream/qdsp5/audio_evrc.c index ad989ee87690..24a892647370 100644 --- a/drivers/staging/dream/qdsp5/audio_evrc.c +++ b/drivers/staging/dream/qdsp5/audio_evrc.c @@ -813,6 +813,7 @@ static struct file_operations audio_evrc_fops = { .read = audevrc_read, .write = audevrc_write, .unlocked_ioctl = audevrc_ioctl, + .llseek = noop_llseek, }; struct miscdevice audio_evrc_misc = { diff --git a/drivers/staging/dream/qdsp5/audio_in.c b/drivers/staging/dream/qdsp5/audio_in.c index 6ae48e72d145..b51fa096074e 100644 --- a/drivers/staging/dream/qdsp5/audio_in.c +++ b/drivers/staging/dream/qdsp5/audio_in.c @@ -921,12 +921,14 @@ static struct file_operations audio_fops = { .read = audio_in_read, .write = audio_in_write, .unlocked_ioctl = audio_in_ioctl, + .llseek = noop_llseek, }; static struct file_operations audpre_fops = { .owner = THIS_MODULE, .open = audpre_open, .unlocked_ioctl = audpre_ioctl, + .llseek = noop_llseek, }; struct miscdevice audio_in_misc = { diff --git a/drivers/staging/dream/qdsp5/audio_mp3.c b/drivers/staging/dream/qdsp5/audio_mp3.c index 530e1f35eed3..409a19ce6039 100644 --- a/drivers/staging/dream/qdsp5/audio_mp3.c +++ b/drivers/staging/dream/qdsp5/audio_mp3.c @@ -948,6 +948,7 @@ static struct file_operations audio_mp3_fops = { .read = audio_read, .write = audio_write, .unlocked_ioctl = audio_ioctl, + .llseek = noop_llseek, }; struct miscdevice audio_mp3_misc = { diff --git a/drivers/staging/dream/qdsp5/audio_out.c b/drivers/staging/dream/qdsp5/audio_out.c index 76d7fa5667d5..d20e89541567 100644 --- a/drivers/staging/dream/qdsp5/audio_out.c +++ b/drivers/staging/dream/qdsp5/audio_out.c @@ -807,12 +807,14 @@ static struct file_operations audio_fops = { .read = audio_read, .write = audio_write, .unlocked_ioctl = audio_ioctl, + .llseek = noop_llseek, }; static struct file_operations audpp_fops = { .owner = THIS_MODULE, .open = audpp_open, .unlocked_ioctl = audpp_ioctl, + .llseek = noop_llseek, }; struct miscdevice audio_misc = { diff --git a/drivers/staging/dream/qdsp5/audio_qcelp.c b/drivers/staging/dream/qdsp5/audio_qcelp.c index effa96f34fdc..911bab416b85 100644 --- a/drivers/staging/dream/qdsp5/audio_qcelp.c +++ b/drivers/staging/dream/qdsp5/audio_qcelp.c @@ -824,6 +824,7 @@ static struct file_operations audio_qcelp_fops = { .read = audqcelp_read, .write = audqcelp_write, .unlocked_ioctl = audqcelp_ioctl, + .llseek = noop_llseek, }; struct miscdevice audio_qcelp_misc = { diff --git a/drivers/staging/dream/qdsp5/evlog.h b/drivers/staging/dream/qdsp5/evlog.h index 922ce670a32a..e5ab86b9dd7c 100644 --- a/drivers/staging/dream/qdsp5/evlog.h +++ b/drivers/staging/dream/qdsp5/evlog.h @@ -123,6 +123,7 @@ static int ev_log_open(struct inode *inode, struct file *file) static const struct file_operations ev_log_ops = { .read = ev_log_read, .open = ev_log_open, + .llseek = default_llseek, }; static int ev_log_init(struct ev_log *log) diff --git a/drivers/staging/dream/qdsp5/snd.c b/drivers/staging/dream/qdsp5/snd.c index 037d7ffb7e67..e0f2f7bca29e 100644 --- a/drivers/staging/dream/qdsp5/snd.c +++ b/drivers/staging/dream/qdsp5/snd.c @@ -247,6 +247,7 @@ static struct file_operations snd_fops = { .open = snd_open, .release = snd_release, .unlocked_ioctl = snd_ioctl, + .llseek = noop_llseek, }; struct miscdevice snd_misc = { diff --git a/drivers/staging/easycap/Kconfig b/drivers/staging/easycap/Kconfig index bd96f39f2735..9d5fe4ddc30a 100644 --- a/drivers/staging/easycap/Kconfig +++ b/drivers/staging/easycap/Kconfig @@ -1,6 +1,7 @@ config EASYCAP tristate "EasyCAP USB ID 05e1:0408 support" depends on USB && VIDEO_DEV + depends on BKL # please fix ---help--- This is an integrated audio/video driver for EasyCAP cards with diff --git a/drivers/staging/frontier/alphatrack.c b/drivers/staging/frontier/alphatrack.c index 4e52105e6070..689099b57fd2 100644 --- a/drivers/staging/frontier/alphatrack.c +++ b/drivers/staging/frontier/alphatrack.c @@ -641,6 +641,7 @@ static const struct file_operations usb_alphatrack_fops = { .open = usb_alphatrack_open, .release = usb_alphatrack_release, .poll = usb_alphatrack_poll, + .llseek = no_llseek, }; /* diff --git a/drivers/staging/frontier/tranzport.c b/drivers/staging/frontier/tranzport.c index eed74f0fe0b6..3d12c1737edc 100644 --- a/drivers/staging/frontier/tranzport.c +++ b/drivers/staging/frontier/tranzport.c @@ -767,6 +767,7 @@ static const struct file_operations usb_tranzport_fops = { .open = usb_tranzport_open, .release = usb_tranzport_release, .poll = usb_tranzport_poll, + .llseek = no_llseek, }; /* diff --git a/drivers/staging/go7007/Kconfig b/drivers/staging/go7007/Kconfig index e47f683a323e..75fa46805527 100644 --- a/drivers/staging/go7007/Kconfig +++ b/drivers/staging/go7007/Kconfig @@ -1,6 +1,7 @@ config VIDEO_GO7007 tristate "WIS GO7007 MPEG encoder support" depends on VIDEO_DEV && PCI && I2C && INPUT + depends on BKL # please fix depends on SND select VIDEOBUF_DMA_SG select VIDEO_IR diff --git a/drivers/staging/hv/blkvsc_drv.c b/drivers/staging/hv/blkvsc_drv.c index ff1d24720f11..8284297b30e9 100644 --- a/drivers/staging/hv/blkvsc_drv.c +++ b/drivers/staging/hv/blkvsc_drv.c @@ -25,7 +25,7 @@ #include <linux/major.h> #include <linux/delay.h> #include <linux/hdreg.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/slab.h> #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> @@ -124,6 +124,7 @@ struct blkvsc_driver_context { }; /* Static decl */ +static DEFINE_MUTEX(blkvsc_mutex); static int blkvsc_probe(struct device *dev); static int blkvsc_remove(struct device *device); static void blkvsc_shutdown(struct device *device); @@ -1309,7 +1310,7 @@ static int blkvsc_open(struct block_device *bdev, fmode_t mode) DPRINT_DBG(BLKVSC_DRV, "- users %d disk %s\n", blkdev->users, blkdev->gd->disk_name); - lock_kernel(); + mutex_lock(&blkvsc_mutex); spin_lock(&blkdev->lock); if (!blkdev->users && blkdev->device_type == DVD_TYPE) { @@ -1321,7 +1322,7 @@ static int blkvsc_open(struct block_device *bdev, fmode_t mode) blkdev->users++; spin_unlock(&blkdev->lock); - unlock_kernel(); + mutex_unlock(&blkvsc_mutex); return 0; } @@ -1332,7 +1333,7 @@ static int blkvsc_release(struct gendisk *disk, fmode_t mode) DPRINT_DBG(BLKVSC_DRV, "- users %d disk %s\n", blkdev->users, blkdev->gd->disk_name); - lock_kernel(); + mutex_lock(&blkvsc_mutex); spin_lock(&blkdev->lock); if (blkdev->users == 1) { spin_unlock(&blkdev->lock); @@ -1343,7 +1344,7 @@ static int blkvsc_release(struct gendisk *disk, fmode_t mode) blkdev->users--; spin_unlock(&blkdev->lock); - unlock_kernel(); + mutex_unlock(&blkvsc_mutex); return 0; } diff --git a/drivers/staging/iio/industrialio-core.c b/drivers/staging/iio/industrialio-core.c index dd4d87a8bcaf..92a212f064bd 100644 --- a/drivers/staging/iio/industrialio-core.c +++ b/drivers/staging/iio/industrialio-core.c @@ -349,6 +349,7 @@ static const struct file_operations iio_event_chrdev_fileops = { .release = iio_event_chrdev_release, .open = iio_event_chrdev_open, .owner = THIS_MODULE, + .llseek = noop_llseek, }; static void iio_event_dev_release(struct device *dev) diff --git a/drivers/staging/iio/industrialio-ring.c b/drivers/staging/iio/industrialio-ring.c index 6ab578e4f5f3..1c5f67253b82 100644 --- a/drivers/staging/iio/industrialio-ring.c +++ b/drivers/staging/iio/industrialio-ring.c @@ -133,6 +133,7 @@ static const struct file_operations iio_ring_fileops = { .release = iio_ring_release, .open = iio_ring_open, .owner = THIS_MODULE, + .llseek = noop_llseek, }; /** diff --git a/drivers/staging/lirc/lirc_imon.c b/drivers/staging/lirc/lirc_imon.c index 66493253042e..ed5c5fe022c9 100644 --- a/drivers/staging/lirc/lirc_imon.c +++ b/drivers/staging/lirc/lirc_imon.c @@ -115,7 +115,8 @@ static const struct file_operations display_fops = { .owner = THIS_MODULE, .open = &display_open, .write = &vfd_write, - .release = &display_close + .release = &display_close, + .llseek = noop_llseek, }; /* diff --git a/drivers/staging/lirc/lirc_it87.c b/drivers/staging/lirc/lirc_it87.c index ec11c0e949a0..543c5c3bf907 100644 --- a/drivers/staging/lirc/lirc_it87.c +++ b/drivers/staging/lirc/lirc_it87.c @@ -342,6 +342,7 @@ static const struct file_operations lirc_fops = { .unlocked_ioctl = lirc_ioctl, .open = lirc_open, .release = lirc_close, + .llseek = noop_llseek, }; static int set_use_inc(void *data) diff --git a/drivers/staging/lirc/lirc_sasem.c b/drivers/staging/lirc/lirc_sasem.c index 73166c3f581f..8f72a84f34ec 100644 --- a/drivers/staging/lirc/lirc_sasem.c +++ b/drivers/staging/lirc/lirc_sasem.c @@ -125,6 +125,7 @@ static const struct file_operations vfd_fops = { .write = &vfd_write, .unlocked_ioctl = &vfd_ioctl, .release = &vfd_close, + .llseek = noop_llseek, }; /* USB Device ID for Sasem USB Control Board */ diff --git a/drivers/staging/lirc/lirc_serial.c b/drivers/staging/lirc/lirc_serial.c index 9456f8e3f9ef..8da382492612 100644 --- a/drivers/staging/lirc/lirc_serial.c +++ b/drivers/staging/lirc/lirc_serial.c @@ -1058,6 +1058,7 @@ static const struct file_operations lirc_fops = { .poll = lirc_dev_fop_poll, .open = lirc_dev_fop_open, .release = lirc_dev_fop_close, + .llseek = no_llseek, }; static struct lirc_driver driver = { diff --git a/drivers/staging/lirc/lirc_sir.c b/drivers/staging/lirc/lirc_sir.c index eb08fa7138ba..2478871bd95e 100644 --- a/drivers/staging/lirc/lirc_sir.c +++ b/drivers/staging/lirc/lirc_sir.c @@ -459,6 +459,7 @@ static const struct file_operations lirc_fops = { .unlocked_ioctl = lirc_ioctl, .open = lirc_dev_fop_open, .release = lirc_dev_fop_close, + .llseek = no_llseek, }; static int set_use_inc(void *data) diff --git a/drivers/staging/memrar/memrar_handler.c b/drivers/staging/memrar/memrar_handler.c index a98b3f1f11e0..cfcaa8e5b8e6 100644 --- a/drivers/staging/memrar/memrar_handler.c +++ b/drivers/staging/memrar/memrar_handler.c @@ -890,6 +890,7 @@ static const struct file_operations memrar_fops = { .mmap = memrar_mmap, .open = memrar_open, .release = memrar_release, + .llseek = no_llseek, }; static struct miscdevice memrar_miscdev = { diff --git a/drivers/staging/panel/panel.c b/drivers/staging/panel/panel.c index 3221814a856e..6885f9a46609 100644 --- a/drivers/staging/panel/panel.c +++ b/drivers/staging/panel/panel.c @@ -1631,6 +1631,7 @@ static const struct file_operations keypad_fops = { .read = keypad_read, /* read */ .open = keypad_open, /* open */ .release = keypad_release, /* close */ + .llseek = default_llseek, }; static struct miscdevice keypad_dev = { diff --git a/drivers/staging/spectra/ffsport.c b/drivers/staging/spectra/ffsport.c index fa21a0fd8e84..c7932da03c56 100644 --- a/drivers/staging/spectra/ffsport.c +++ b/drivers/staging/spectra/ffsport.c @@ -27,7 +27,6 @@ #include <linux/kthread.h> #include <linux/log2.h> #include <linux/init.h> -#include <linux/smp_lock.h> #include <linux/slab.h> /**** Helper functions used for Div, Remainder operation on u64 ****/ @@ -590,14 +589,16 @@ int GLOB_SBD_ioctl(struct block_device *bdev, fmode_t mode, return -ENOTTY; } +static DEFINE_MUTEX(ffsport_mutex); + int GLOB_SBD_unlocked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg) { int ret; - lock_kernel(); + mutex_lock(&ffsport_mutex); ret = GLOB_SBD_ioctl(bdev, mode, cmd, arg); - unlock_kernel(); + mutex_unlock(&ffsport_mutex); return ret; } diff --git a/drivers/staging/tidspbridge/rmgr/drv_interface.c b/drivers/staging/tidspbridge/rmgr/drv_interface.c index 7ee89492a755..7b3a7d04a109 100644 --- a/drivers/staging/tidspbridge/rmgr/drv_interface.c +++ b/drivers/staging/tidspbridge/rmgr/drv_interface.c @@ -144,6 +144,7 @@ static const struct file_operations bridge_fops = { .release = bridge_release, .unlocked_ioctl = bridge_ioctl, .mmap = bridge_mmap, + .llseek = noop_llseek, }; #ifdef CONFIG_PM diff --git a/drivers/staging/usbip/Kconfig b/drivers/staging/usbip/Kconfig index 2c1d10acb8b5..b11ec379b5c2 100644 --- a/drivers/staging/usbip/Kconfig +++ b/drivers/staging/usbip/Kconfig @@ -1,6 +1,6 @@ config USB_IP_COMMON tristate "USB IP support (EXPERIMENTAL)" - depends on USB && NET && EXPERIMENTAL + depends on USB && NET && EXPERIMENTAL && BKL default N ---help--- This enables pushing USB packets over IP to allow remote diff --git a/drivers/staging/wlags49_h2/wl_cs.c b/drivers/staging/wlags49_h2/wl_cs.c index 19c335458653..6555891e149c 100644 --- a/drivers/staging/wlags49_h2/wl_cs.c +++ b/drivers/staging/wlags49_h2/wl_cs.c @@ -83,7 +83,6 @@ #include <linux/if_arp.h> #include <linux/ioport.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/cisreg.h> #include <pcmcia/ciscode.h> @@ -147,10 +146,9 @@ static int wl_adapter_attach(struct pcmcia_device *link) link->resource[0]->end = HCF_NUM_IO_PORTS; link->resource[0]->flags= IO_DATA_PATH_WIDTH_16; - link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.IntType = INT_MEMORY_AND_IO; - link->conf.ConfigIndex = 5; - link->conf.Present = PRESENT_OPTION; + link->config_flags |= CONF_ENABLE_IRQ; + link->config_index = 5; + link->config_regs = PRESENT_OPTION; link->priv = dev; lp = wl_priv(dev); @@ -165,27 +163,6 @@ static int wl_adapter_attach(struct pcmcia_device *link) -/******************************************************************************* - * wl_adapter_detach() - ******************************************************************************* - * - * DESCRIPTION: - * - * This deletes a driver "instance". The device is de-registered with Card - * Services. If it has been released, then the net device is unregistered, and - * all local data structures are freed. Otherwise, the structures will be - * freed when the device is released. - * - * PARAMETERS: - * - * link - pointer to the dev_link_t structure representing the device to - * detach - * - * RETURNS: - * - * N/A - * - ******************************************************************************/ static void wl_adapter_detach(struct pcmcia_device *link) { struct net_device *dev = link->priv; @@ -209,26 +186,6 @@ static void wl_adapter_detach(struct pcmcia_device *link) /*============================================================================*/ -/******************************************************************************* - * wl_adapter_release() - ******************************************************************************* - * - * DESCRIPTION: - * - * After a card is removed, this routine will release the PCMCIA - * configuration. If the device is still open, this will be postponed until it - * is closed. - * - * PARAMETERS: - * - * arg - a u_long representing a pointer to a dev_link_t structure for the - * device to be released. - * - * RETURNS: - * - * N/A - * - ******************************************************************************/ void wl_adapter_release(struct pcmcia_device *link) { DBG_FUNC("wl_adapter_release"); @@ -268,26 +225,6 @@ static int wl_adapter_resume(struct pcmcia_device *link) return 0; } /* wl_adapter_resume */ -/******************************************************************************* - * wl_adapter_insert() - ******************************************************************************* - * - * DESCRIPTION: - * - * wl_adapter_insert() is scheduled to run after a CARD_INSERTION event is - * received, to configure the PCMCIA socket, and to make the ethernet device - * available to the system. - * - * PARAMETERS: - * - * link - pointer to the dev_link_t structure representing the device to - * insert - * - * RETURNS: - * - * N/A - * - ******************************************************************************/ void wl_adapter_insert(struct pcmcia_device *link) { struct net_device *dev; @@ -302,7 +239,7 @@ void wl_adapter_insert(struct pcmcia_device *link) dev = link->priv; /* Do we need to allocate an interrupt? */ - link->conf.Attributes |= CONF_ENABLE_IRQ; + link->config_flags |= CONF_ENABLE_IRQ; link->io_lines = 6; ret = pcmcia_request_io(link); @@ -313,7 +250,7 @@ void wl_adapter_insert(struct pcmcia_device *link) if (ret != 0) goto failed; - ret = pcmcia_request_configuration(link, &link->conf); + ret = pcmcia_enable_device(link); if (ret != 0) goto failed; @@ -457,9 +394,7 @@ MODULE_DEVICE_TABLE(pcmcia, wl_adapter_ids); static struct pcmcia_driver wlags49_driver = { .owner = THIS_MODULE, - .drv = { - .name = DRIVER_NAME, - }, + .name = DRIVER_NAME, .probe = wl_adapter_attach, .remove = wl_adapter_detach, .id_table = wl_adapter_ids, diff --git a/drivers/staging/wlags49_h2/wl_internal.h b/drivers/staging/wlags49_h2/wl_internal.h index 02f0a20e178a..cd129b3ee6c0 100644 --- a/drivers/staging/wlags49_h2/wl_internal.h +++ b/drivers/staging/wlags49_h2/wl_internal.h @@ -69,7 +69,6 @@ ******************************************************************************/ #include <linux/version.h> #ifdef BUS_PCMCIA -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/cisreg.h> #include <pcmcia/ciscode.h> diff --git a/drivers/staging/wlags49_h2/wl_main.c b/drivers/staging/wlags49_h2/wl_main.c index 88d0d472142f..8e3536acbf46 100644 --- a/drivers/staging/wlags49_h2/wl_main.c +++ b/drivers/staging/wlags49_h2/wl_main.c @@ -414,25 +414,6 @@ extern memimage fw_image; // firmware image to be downloaded #endif /* HCF_STA */ -/******************************************************************************* - * wl_insert() - ******************************************************************************* - * - * DESCRIPTION: - * - * wl_insert() is scheduled to run after a CARD_INSERTION event is - * received, to configure the PCMCIA socket, and to make the ethernet device - * available to the system. - * - * PARAMETERS: - * - * dev - a pointer to the net_device struct of the wireless device - * - * RETURNS: - * - * TRUE or FALSE - * - ******************************************************************************/ int wl_insert( struct net_device *dev ) { int result = 0; diff --git a/drivers/telephony/ixj.c b/drivers/telephony/ixj.c index b53deee25d74..0d236f4bb8c2 100644 --- a/drivers/telephony/ixj.c +++ b/drivers/telephony/ixj.c @@ -257,7 +257,7 @@ #include <linux/fs.h> /* everything... */ #include <linux/errno.h> /* error codes */ #include <linux/slab.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/mm.h> #include <linux/ioport.h> #include <linux/interrupt.h> @@ -277,6 +277,7 @@ #define TYPE(inode) (iminor(inode) >> 4) #define NUM(inode) (iminor(inode) & 0xf) +static DEFINE_MUTEX(ixj_mutex); static int ixjdebug; static int hertz = HZ; static int samplerate = 100; @@ -6655,9 +6656,9 @@ static long do_ixj_ioctl(struct file *file_p, unsigned int cmd, unsigned long ar static long ixj_ioctl(struct file *file_p, unsigned int cmd, unsigned long arg) { long ret; - lock_kernel(); + mutex_lock(&ixj_mutex); ret = do_ixj_ioctl(file_p, cmd, arg); - unlock_kernel(); + mutex_unlock(&ixj_mutex); return ret; } @@ -6676,7 +6677,8 @@ static const struct file_operations ixj_fops = .poll = ixj_poll, .unlocked_ioctl = ixj_ioctl, .release = ixj_release, - .fasync = ixj_fasync + .fasync = ixj_fasync, + .llseek = default_llseek, }; static int ixj_linetest(IXJ *j) diff --git a/drivers/telephony/ixj_pcmcia.c b/drivers/telephony/ixj_pcmcia.c index a1900e502518..d005b9eeebbc 100644 --- a/drivers/telephony/ixj_pcmcia.c +++ b/drivers/telephony/ixj_pcmcia.c @@ -8,7 +8,6 @@ #include <linux/errno.h> /* error codes */ #include <linux/slab.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/ds.h> @@ -32,9 +31,6 @@ static int ixj_probe(struct pcmcia_device *p_dev) { dev_dbg(&p_dev->dev, "ixj_attach()\n"); /* Create new ixj device */ - p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; - p_dev->resource[1]->flags |= IO_DATA_PATH_WIDTH_8; - p_dev->conf.IntType = INT_MEMORY_AND_IO; p_dev->priv = kzalloc(sizeof(struct ixj_info_t), GFP_KERNEL); if (!p_dev->priv) { return -ENOMEM; @@ -111,40 +107,31 @@ failed: return; } -static int ixj_config_check(struct pcmcia_device *p_dev, - cistpl_cftable_entry_t *cfg, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, - void *priv_data) +static int ixj_config_check(struct pcmcia_device *p_dev, void *priv_data) { - if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) { - cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io; - p_dev->resource[0]->start = io->win[0].base; - p_dev->resource[0]->end = io->win[0].len; - p_dev->io_lines = 3; - if (io->nwin == 2) { - p_dev->resource[1]->start = io->win[1].base; - p_dev->resource[1]->end = io->win[1].len; - } - if (!pcmcia_request_io(p_dev)) - return 0; - } - return -ENODEV; + p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; + p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; + p_dev->resource[1]->flags &= ~IO_DATA_PATH_WIDTH; + p_dev->resource[1]->flags |= IO_DATA_PATH_WIDTH_8; + p_dev->io_lines = 3; + + return pcmcia_request_io(p_dev); } static int ixj_config(struct pcmcia_device * link) { IXJ *j; ixj_info_t *info; - cistpl_cftable_entry_t dflt = { 0 }; info = link->priv; dev_dbg(&link->dev, "ixj_config\n"); - if (pcmcia_loop_config(link, ixj_config_check, &dflt)) + link->config_flags = CONF_AUTO_SET_IO; + + if (pcmcia_loop_config(link, ixj_config_check, NULL)) goto failed; - if (pcmcia_request_configuration(link, &link->conf)) + if (pcmcia_enable_device(link)) goto failed; /* @@ -178,9 +165,7 @@ MODULE_DEVICE_TABLE(pcmcia, ixj_ids); static struct pcmcia_driver ixj_driver = { .owner = THIS_MODULE, - .drv = { - .name = "ixj_cs", - }, + .name = "ixj_cs", .probe = ixj_probe, .remove = ixj_detach, .id_table = ixj_ids, diff --git a/drivers/telephony/phonedev.c b/drivers/telephony/phonedev.c index f3873f650bb4..1915af201175 100644 --- a/drivers/telephony/phonedev.c +++ b/drivers/telephony/phonedev.c @@ -130,6 +130,7 @@ static const struct file_operations phone_fops = { .owner = THIS_MODULE, .open = phone_open, + .llseek = noop_llseek, }; /* diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c index 3fe9a9da42d1..a858d2b87b94 100644 --- a/drivers/uio/uio.c +++ b/drivers/uio/uio.c @@ -717,6 +717,7 @@ static const struct file_operations uio_fops = { .mmap = uio_mmap, .poll = uio_poll, .fasync = uio_fasync, + .llseek = noop_llseek, }; static int uio_major_init(void) diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 094c76b5de17..6ee4451bfe2d 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -584,7 +584,8 @@ static const struct file_operations wdm_fops = { .open = wdm_open, .flush = wdm_flush, .release = wdm_release, - .poll = wdm_poll + .poll = wdm_poll, + .llseek = noop_llseek, }; static struct usb_class_driver wdm_class = { diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index e325162859b0..9eca4053312e 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -1043,6 +1043,7 @@ static const struct file_operations usblp_fops = { .compat_ioctl = usblp_ioctl, .open = usblp_open, .release = usblp_release, + .llseek = noop_llseek, }; static char *usblp_devnode(struct device *dev, mode_t *mode) diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index 3e7c1b800ebb..6a54634ab823 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -987,6 +987,7 @@ static const struct file_operations fops = { .open = usbtmc_open, .release = usbtmc_release, .unlocked_ioctl = usbtmc_ioctl, + .llseek = default_llseek, }; static struct usb_class_driver usbtmc_class = { diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c index 1e6ccef2cf0c..9fe34fb78ef1 100644 --- a/drivers/usb/core/file.c +++ b/drivers/usb/core/file.c @@ -59,6 +59,7 @@ static int usb_open(struct inode * inode, struct file * file) static const struct file_operations usb_fops = { .owner = THIS_MODULE, .open = usb_open, + .llseek = noop_llseek, }; static struct usb_class { diff --git a/drivers/usb/gadget/f_hid.c b/drivers/usb/gadget/f_hid.c index 53e120208e99..2b98bd26364b 100644 --- a/drivers/usb/gadget/f_hid.c +++ b/drivers/usb/gadget/f_hid.c @@ -451,6 +451,7 @@ const struct file_operations f_hidg_fops = { .write = f_hidg_write, .read = f_hidg_read, .poll = f_hidg_poll, + .llseek = noop_llseek, }; static int __init hidg_bind(struct usb_configuration *c, struct usb_function *f) diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index fc35406fc80c..3f1d771c8be5 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -33,7 +33,6 @@ #include <linux/sched.h> #include <linux/slab.h> #include <linux/poll.h> -#include <linux/smp_lock.h> #include <linux/device.h> #include <linux/moduleparam.h> diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c index cf241c371a71..327a92a137b4 100644 --- a/drivers/usb/gadget/printer.c +++ b/drivers/usb/gadget/printer.c @@ -884,7 +884,8 @@ static const struct file_operations printer_io_operations = { .fsync = printer_fsync, .poll = printer_poll, .unlocked_ioctl = printer_ioctl, - .release = printer_close + .release = printer_close, + .llseek = noop_llseek, }; /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index 76b7fd2d838a..86afdc73322f 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c @@ -369,18 +369,21 @@ static const struct file_operations debug_async_fops = { .open = debug_async_open, .read = debug_output, .release = debug_close, + .llseek = default_llseek, }; static const struct file_operations debug_periodic_fops = { .owner = THIS_MODULE, .open = debug_periodic_open, .read = debug_output, .release = debug_close, + .llseek = default_llseek, }; static const struct file_operations debug_registers_fops = { .owner = THIS_MODULE, .open = debug_registers_open, .read = debug_output, .release = debug_close, + .llseek = default_llseek, }; static const struct file_operations debug_lpm_fops = { .owner = THIS_MODULE, @@ -388,6 +391,7 @@ static const struct file_operations debug_lpm_fops = { .read = debug_lpm_read, .write = debug_lpm_write, .release = debug_lpm_close, + .llseek = noop_llseek, }; static struct dentry *ehci_debug_root; diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c index 36abd2baa3ea..d7d34492934a 100644 --- a/drivers/usb/host/ohci-dbg.c +++ b/drivers/usb/host/ohci-dbg.c @@ -413,18 +413,21 @@ static const struct file_operations debug_async_fops = { .open = debug_async_open, .read = debug_output, .release = debug_close, + .llseek = default_llseek, }; static const struct file_operations debug_periodic_fops = { .owner = THIS_MODULE, .open = debug_periodic_open, .read = debug_output, .release = debug_close, + .llseek = default_llseek, }; static const struct file_operations debug_registers_fops = { .owner = THIS_MODULE, .open = debug_registers_open, .read = debug_output, .release = debug_close, + .llseek = default_llseek, }; static struct dentry *ohci_debug_root; diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c index 418163894775..afef7b0a4195 100644 --- a/drivers/usb/host/ohci-pxa27x.c +++ b/drivers/usb/host/ohci-pxa27x.c @@ -24,6 +24,7 @@ #include <linux/platform_device.h> #include <linux/clk.h> #include <mach/ohci.h> +#include <mach/pxa3xx-u2d.h> /* * UHC: USB Host Controller (OHCI-like) register definitions @@ -235,6 +236,9 @@ static int pxa27x_start_hc(struct pxa27x_ohci *ohci, struct device *dev) if (retval < 0) return retval; + if (cpu_is_pxa3xx()) + pxa3xx_u2d_start_hc(&ohci_to_hcd(&ohci->ohci)->self); + uhchr = __raw_readl(ohci->mmio_base + UHCHR) & ~UHCHR_SSE; __raw_writel(uhchr, ohci->mmio_base + UHCHR); __raw_writel(UHCHIE_UPRIE | UHCHIE_RWIE, ohci->mmio_base + UHCHIE); @@ -251,6 +255,9 @@ static void pxa27x_stop_hc(struct pxa27x_ohci *ohci, struct device *dev) inf = dev->platform_data; + if (cpu_is_pxa3xx()) + pxa3xx_u2d_stop_hc(&ohci_to_hcd(&ohci->ohci)->self); + if (inf->exit) inf->exit(dev); diff --git a/drivers/usb/host/sl811_cs.c b/drivers/usb/host/sl811_cs.c index 0e13a00eb2ed..3775c035a6c5 100644 --- a/drivers/usb/host/sl811_cs.c +++ b/drivers/usb/host/sl811_cs.c @@ -20,7 +20,6 @@ #include <linux/ioport.h> #include <linux/platform_device.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/cisreg.h> #include <pcmcia/ds.h> @@ -132,49 +131,12 @@ static void sl811_cs_release(struct pcmcia_device * link) platform_device_unregister(&platform_dev); } -static int sl811_cs_config_check(struct pcmcia_device *p_dev, - cistpl_cftable_entry_t *cfg, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, - void *priv_data) +static int sl811_cs_config_check(struct pcmcia_device *p_dev, void *priv_data) { - if (cfg->index == 0) - return -ENODEV; - - /* Use power settings for Vcc and Vpp if present */ - /* Note that the CIS values need to be rescaled */ - if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) { - if (cfg->vcc.param[CISTPL_POWER_VNOM]/10000 != vcc) - return -ENODEV; - } else if (dflt->vcc.present & (1<<CISTPL_POWER_VNOM)) { - if (dflt->vcc.param[CISTPL_POWER_VNOM]/10000 != vcc) - return -ENODEV; - } - - if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM)) - p_dev->conf.Vpp = - cfg->vpp1.param[CISTPL_POWER_VNOM]/10000; - else if (dflt->vpp1.present & (1<<CISTPL_POWER_VNOM)) - p_dev->conf.Vpp = - dflt->vpp1.param[CISTPL_POWER_VNOM]/10000; - - /* we need an interrupt */ - p_dev->conf.Attributes |= CONF_ENABLE_IRQ; - - /* IO window settings */ - p_dev->resource[0]->end = p_dev->resource[1]->end = 0; - if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) { - cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io; - p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK; - - p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; - p_dev->resource[0]->start = io->win[0].base; - p_dev->resource[0]->end = io->win[0].len; - - return pcmcia_request_io(p_dev); - } - pcmcia_disable_device(p_dev); - return -ENODEV; + if (p_dev->config_index == 0) + return -EINVAL; + + return pcmcia_request_io(p_dev); } @@ -185,6 +147,9 @@ static int sl811_cs_config(struct pcmcia_device *link) dev_dbg(&link->dev, "sl811_cs_config\n"); + link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_VPP | + CONF_AUTO_CHECK_VCC | CONF_AUTO_SET_IO; + if (pcmcia_loop_config(link, sl811_cs_config_check, NULL)) goto failed; @@ -195,18 +160,10 @@ static int sl811_cs_config(struct pcmcia_device *link) if (!link->irq) goto failed; - ret = pcmcia_request_configuration(link, &link->conf); + ret = pcmcia_enable_device(link); if (ret) goto failed; - dev_info(&link->dev, "index 0x%02x: ", - link->conf.ConfigIndex); - if (link->conf.Vpp) - printk(", Vpp %d.%d", link->conf.Vpp/10, link->conf.Vpp%10); - printk(", irq %d", link->irq); - printk(", io %pR", link->resource[0]); - printk("\n"); - if (sl811_hc_init(parent, link->resource[0]->start, link->irq) < 0) { failed: @@ -227,9 +184,6 @@ static int sl811_cs_probe(struct pcmcia_device *link) local->p_dev = link; link->priv = local; - link->conf.Attributes = 0; - link->conf.IntType = INT_MEMORY_AND_IO; - return sl811_cs_config(link); } @@ -241,9 +195,7 @@ MODULE_DEVICE_TABLE(pcmcia, sl811_ids); static struct pcmcia_driver sl811_cs_driver = { .owner = THIS_MODULE, - .drv = { - .name = "sl811_cs", - }, + .name = "sl811_cs", .probe = sl811_cs_probe, .remove = sl811_cs_detach, .id_table = sl811_ids, diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c index e192e8f7c560..575b56c79e97 100644 --- a/drivers/usb/image/mdc800.c +++ b/drivers/usb/image/mdc800.c @@ -963,6 +963,7 @@ static const struct file_operations mdc800_device_ops = .write = mdc800_device_write, .open = mdc800_device_open, .release = mdc800_device_release, + .llseek = noop_llseek, }; diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c index 801324af9470..44f8b9225054 100644 --- a/drivers/usb/misc/adutux.c +++ b/drivers/usb/misc/adutux.c @@ -679,6 +679,7 @@ static const struct file_operations adu_fops = { .write = adu_write, .open = adu_open, .release = adu_release, + .llseek = noop_llseek, }; /* diff --git a/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c index a54c3cb804ce..c6184b4d1695 100644 --- a/drivers/usb/misc/idmouse.c +++ b/drivers/usb/misc/idmouse.c @@ -105,6 +105,7 @@ static const struct file_operations idmouse_fops = { .read = idmouse_read, .open = idmouse_open, .release = idmouse_release, + .llseek = default_llseek, }; /* class driver information */ diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c index bc88c79875a1..9b50db257019 100644 --- a/drivers/usb/misc/iowarrior.c +++ b/drivers/usb/misc/iowarrior.c @@ -730,6 +730,7 @@ static const struct file_operations iowarrior_fops = { .open = iowarrior_open, .release = iowarrior_release, .poll = iowarrior_poll, + .llseek = noop_llseek, }; static char *iowarrior_devnode(struct device *dev, mode_t *mode) diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c index dd41d8710043..edffef642337 100644 --- a/drivers/usb/misc/ldusb.c +++ b/drivers/usb/misc/ldusb.c @@ -613,6 +613,7 @@ static const struct file_operations ld_usb_fops = { .open = ld_usb_open, .release = ld_usb_release, .poll = ld_usb_poll, + .llseek = no_llseek, }; /* diff --git a/drivers/usb/misc/rio500.c b/drivers/usb/misc/rio500.c index cc13ae61712a..4e23d3841b43 100644 --- a/drivers/usb/misc/rio500.c +++ b/drivers/usb/misc/rio500.c @@ -439,6 +439,7 @@ static const struct file_operations usb_rio_fops = { .unlocked_ioctl = ioctl_rio, .open = open_rio, .release = close_rio, + .llseek = noop_llseek, }; static struct usb_class_driver usb_rio_class = { diff --git a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c index d00dde19194c..51648154bb44 100644 --- a/drivers/usb/misc/usblcd.c +++ b/drivers/usb/misc/usblcd.c @@ -282,6 +282,7 @@ static const struct file_operations lcd_fops = { .open = lcd_open, .unlocked_ioctl = lcd_ioctl, .release = lcd_release, + .llseek = noop_llseek, }; /* diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c index 552679b8dbd1..e24ce3123071 100644 --- a/drivers/usb/usb-skeleton.c +++ b/drivers/usb/usb-skeleton.c @@ -507,6 +507,7 @@ static const struct file_operations skel_fops = { .open = skel_open, .release = skel_release, .flush = skel_flush, + .llseek = noop_llseek, }; /* diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index 7c8008225ee3..861af4a8b79c 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -127,7 +127,10 @@ static void handle_tx(struct vhost_net *net) size_t len, total_len = 0; int err, wmem; size_t hdr_size; - struct socket *sock = rcu_dereference(vq->private_data); + struct socket *sock; + + sock = rcu_dereference_check(vq->private_data, + lockdep_is_held(&vq->mutex)); if (!sock) return; @@ -582,7 +585,10 @@ static void vhost_net_disable_vq(struct vhost_net *n, static void vhost_net_enable_vq(struct vhost_net *n, struct vhost_virtqueue *vq) { - struct socket *sock = vq->private_data; + struct socket *sock; + + sock = rcu_dereference_protected(vq->private_data, + lockdep_is_held(&vq->mutex)); if (!sock) return; if (vq == n->vqs + VHOST_NET_VQ_TX) { @@ -598,7 +604,8 @@ static struct socket *vhost_net_stop_vq(struct vhost_net *n, struct socket *sock; mutex_lock(&vq->mutex); - sock = vq->private_data; + sock = rcu_dereference_protected(vq->private_data, + lockdep_is_held(&vq->mutex)); vhost_net_disable_vq(n, vq); rcu_assign_pointer(vq->private_data, NULL); mutex_unlock(&vq->mutex); @@ -736,7 +743,8 @@ static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd) } /* start polling new socket */ - oldsock = vq->private_data; + oldsock = rcu_dereference_protected(vq->private_data, + lockdep_is_held(&vq->mutex)); if (sock != oldsock) { vhost_net_disable_vq(n, vq); rcu_assign_pointer(vq->private_data, sock); @@ -869,6 +877,7 @@ static const struct file_operations vhost_net_fops = { .compat_ioctl = vhost_net_compat_ioctl, #endif .open = vhost_net_open, + .llseek = noop_llseek, }; static struct miscdevice vhost_net_misc = { diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index dd3d6f7406f8..8b5a1b33d0fe 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -320,7 +320,7 @@ long vhost_dev_reset_owner(struct vhost_dev *dev) vhost_dev_cleanup(dev); memory->nregions = 0; - dev->memory = memory; + RCU_INIT_POINTER(dev->memory, memory); return 0; } @@ -352,8 +352,9 @@ void vhost_dev_cleanup(struct vhost_dev *dev) fput(dev->log_file); dev->log_file = NULL; /* No one will access memory at this point */ - kfree(dev->memory); - dev->memory = NULL; + kfree(rcu_dereference_protected(dev->memory, + lockdep_is_held(&dev->mutex))); + RCU_INIT_POINTER(dev->memory, NULL); if (dev->mm) mmput(dev->mm); dev->mm = NULL; @@ -440,14 +441,22 @@ static int vq_access_ok(unsigned int num, /* Caller should have device mutex but not vq mutex */ int vhost_log_access_ok(struct vhost_dev *dev) { - return memory_access_ok(dev, dev->memory, 1); + struct vhost_memory *mp; + + mp = rcu_dereference_protected(dev->memory, + lockdep_is_held(&dev->mutex)); + return memory_access_ok(dev, mp, 1); } /* Verify access for write logging. */ /* Caller should have vq mutex and device mutex */ static int vq_log_access_ok(struct vhost_virtqueue *vq, void __user *log_base) { - return vq_memory_access_ok(log_base, vq->dev->memory, + struct vhost_memory *mp; + + mp = rcu_dereference_protected(vq->dev->memory, + lockdep_is_held(&vq->mutex)); + return vq_memory_access_ok(log_base, mp, vhost_has_feature(vq->dev, VHOST_F_LOG_ALL)) && (!vq->log_used || log_access_ok(log_base, vq->log_addr, sizeof *vq->used + @@ -487,7 +496,8 @@ static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m) kfree(newmem); return -EFAULT; } - oldmem = d->memory; + oldmem = rcu_dereference_protected(d->memory, + lockdep_is_held(&d->mutex)); rcu_assign_pointer(d->memory, newmem); synchronize_rcu(); kfree(oldmem); diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h index afd77295971c..af3c11ded5fd 100644 --- a/drivers/vhost/vhost.h +++ b/drivers/vhost/vhost.h @@ -106,7 +106,7 @@ struct vhost_virtqueue { * vhost_work execution acts instead of rcu_read_lock() and the end of * vhost_work execution acts instead of rcu_read_lock(). * Writers use virtqueue mutex. */ - void *private_data; + void __rcu *private_data; /* Log write descriptors */ void __user *log_base; struct vhost_log log[VHOST_NET_MAX_SG]; @@ -116,7 +116,7 @@ struct vhost_dev { /* Readers use RCU to access memory table pointer * log base pointer and features. * Writers use mutex below.*/ - struct vhost_memory *memory; + struct vhost_memory __rcu *memory; struct mm_struct *mm; struct mutex mutex; unsigned acked_features; @@ -173,7 +173,11 @@ enum { static inline int vhost_has_feature(struct vhost_dev *dev, int bit) { - unsigned acked_features = rcu_dereference(dev->acked_features); + unsigned acked_features; + + acked_features = + rcu_dereference_index_check(dev->acked_features, + lockdep_is_held(&dev->mutex)); return acked_features & (1 << bit); } diff --git a/drivers/video/atafb.c b/drivers/video/atafb.c index f3aada20fa02..5b2b5ef4edba 100644 --- a/drivers/video/atafb.c +++ b/drivers/video/atafb.c @@ -1718,11 +1718,9 @@ static int falcon_setcolreg(unsigned int regno, unsigned int red, (((red & 0xe000) >> 13) | ((red & 0x1000) >> 12) << 8) | (((green & 0xe000) >> 13) | ((green & 0x1000) >> 12) << 4) | ((blue & 0xe000) >> 13) | ((blue & 0x1000) >> 12); -#ifdef ATAFB_FALCON ((u32 *)info->pseudo_palette)[regno] = ((red & 0xf800) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11)); -#endif } return 0; } diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index b06647517c0e..42e303ff862a 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -1439,6 +1439,7 @@ static const struct file_operations fb_fops = { #ifdef CONFIG_FB_DEFERRED_IO .fsync = fb_deferred_io_fsync, #endif + .llseek = default_llseek, }; struct class *fb_class; diff --git a/drivers/video/mbx/mbxdebugfs.c b/drivers/video/mbx/mbxdebugfs.c index ecad96524570..12dec7634c55 100644 --- a/drivers/video/mbx/mbxdebugfs.c +++ b/drivers/video/mbx/mbxdebugfs.c @@ -175,36 +175,42 @@ static const struct file_operations sysconf_fops = { .read = sysconf_read_file, .write = write_file_dummy, .open = open_file_generic, + .llseek = default_llseek, }; static const struct file_operations clock_fops = { .read = clock_read_file, .write = write_file_dummy, .open = open_file_generic, + .llseek = default_llseek, }; static const struct file_operations display_fops = { .read = display_read_file, .write = write_file_dummy, .open = open_file_generic, + .llseek = default_llseek, }; static const struct file_operations gsctl_fops = { .read = gsctl_read_file, .write = write_file_dummy, .open = open_file_generic, + .llseek = default_llseek, }; static const struct file_operations sdram_fops = { .read = sdram_read_file, .write = write_file_dummy, .open = open_file_generic, + .llseek = default_llseek, }; static const struct file_operations misc_fops = { .read = misc_read_file, .write = write_file_dummy, .open = open_file_generic, + .llseek = default_llseek, }; static void __devinit mbxfb_debugfs_init(struct fb_info *fbi) diff --git a/drivers/video/omap2/vram.c b/drivers/video/omap2/vram.c index f6fdc2085f3e..fed2a72bc6b6 100644 --- a/drivers/video/omap2/vram.c +++ b/drivers/video/omap2/vram.c @@ -554,12 +554,8 @@ void __init omap_vram_reserve_sdram_memblock(void) size = PAGE_ALIGN(size); if (paddr) { - struct memblock_property res; - - res.base = paddr; - res.size = size; - if ((paddr & ~PAGE_MASK) || memblock_find(&res) || - res.base != paddr || res.size != size) { + if ((paddr & ~PAGE_MASK) || + !memblock_is_region_memory(paddr, size)) { pr_err("Illegal SDRAM region for VRAM\n"); return; } diff --git a/drivers/video/pxa168fb.c b/drivers/video/pxa168fb.c index a31a77ff6f3d..cea6403ae71c 100644 --- a/drivers/video/pxa168fb.c +++ b/drivers/video/pxa168fb.c @@ -784,12 +784,53 @@ failed: return ret; } +static int __devexit pxa168fb_remove(struct platform_device *pdev) +{ + struct pxa168fb_info *fbi = platform_get_drvdata(pdev); + struct fb_info *info; + int irq; + unsigned int data; + + if (!fbi) + return 0; + + /* disable DMA transfer */ + data = readl(fbi->reg_base + LCD_SPU_DMA_CTRL0); + data &= ~CFG_GRA_ENA_MASK; + writel(data, fbi->reg_base + LCD_SPU_DMA_CTRL0); + + info = fbi->info; + + unregister_framebuffer(info); + + writel(GRA_FRAME_IRQ0_ENA(0x0), fbi->reg_base + SPU_IRQ_ENA); + + if (info->cmap.len) + fb_dealloc_cmap(&info->cmap); + + irq = platform_get_irq(pdev, 0); + free_irq(irq, fbi); + + dma_free_writecombine(fbi->dev, PAGE_ALIGN(info->fix.smem_len), + info->screen_base, info->fix.smem_start); + + iounmap(fbi->reg_base); + + clk_disable(fbi->clk); + clk_put(fbi->clk); + + framebuffer_release(info); + + return 0; +} + static struct platform_driver pxa168fb_driver = { .driver = { .name = "pxa168-fb", .owner = THIS_MODULE, }, .probe = pxa168fb_probe, + .remove = __devexit_p(pxa168fb_remove), }; static int __init pxa168fb_init(void) @@ -798,6 +839,12 @@ static int __init pxa168fb_init(void) } module_init(pxa168fb_init); +static void __exit pxa168fb_exit(void) +{ + platform_driver_unregister(&pxa168fb_driver); +} +module_exit(pxa168fb_exit); + MODULE_AUTHOR("Lennert Buytenhek <buytenh@marvell.com> " "Green Wan <gwan@marvell.com>"); MODULE_DESCRIPTION("Framebuffer driver for PXA168/910"); diff --git a/drivers/video/q40fb.c b/drivers/video/q40fb.c index fc32c323a381..f5a39f5aa900 100644 --- a/drivers/video/q40fb.c +++ b/drivers/video/q40fb.c @@ -28,7 +28,7 @@ #define Q40_PHYS_SCREEN_ADDR 0xFE800000 -static struct fb_fix_screeninfo q40fb_fix __initdata = { +static struct fb_fix_screeninfo q40fb_fix __devinitdata = { .id = "Q40", .smem_len = 1024*1024, .type = FB_TYPE_PACKED_PIXELS, @@ -37,7 +37,7 @@ static struct fb_fix_screeninfo q40fb_fix __initdata = { .accel = FB_ACCEL_NONE, }; -static struct fb_var_screeninfo q40fb_var __initdata = { +static struct fb_var_screeninfo q40fb_var __devinitdata = { .xres = 1024, .yres = 512, .xres_virtual = 1024, diff --git a/drivers/vlynq/vlynq.c b/drivers/vlynq/vlynq.c index f2d9e667972d..f885c868a04d 100644 --- a/drivers/vlynq/vlynq.c +++ b/drivers/vlynq/vlynq.c @@ -31,6 +31,7 @@ #include <linux/delay.h> #include <linux/io.h> #include <linux/slab.h> +#include <linux/irq.h> #include <linux/vlynq.h> diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 24efd8ea41bb..c356146bd712 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -957,12 +957,32 @@ config PIKA_WDT the Warp platform. config BOOKE_WDT - bool "PowerPC Book-E Watchdog Timer" + tristate "PowerPC Book-E Watchdog Timer" depends on BOOKE || 4xx ---help--- + Watchdog driver for PowerPC Book-E chips, such as the Freescale + MPC85xx SOCs and the IBM PowerPC 440. + Please see Documentation/watchdog/watchdog-api.txt for more information. +config BOOKE_WDT_DEFAULT_TIMEOUT + int "PowerPC Book-E Watchdog Timer Default Timeout" + depends on BOOKE_WDT + default 38 if FSL_BOOKE + range 0 63 if FSL_BOOKE + default 3 if !FSL_BOOKE + range 0 3 if !FSL_BOOKE + help + Select the default watchdog timer period to be used by the PowerPC + Book-E watchdog driver. A watchdog "event" occurs when the bit + position represented by this number transitions from zero to one. + + For Freescale Book-E processors, this is a number between 0 and 63. + For other Book-E processors, this is a number between 0 and 3. + + The value can be overidden by the wdt_period command-line parameter. + # PPC64 Architecture config WATCHDOG_RTAS diff --git a/drivers/watchdog/ar7_wdt.c b/drivers/watchdog/ar7_wdt.c index c764c52412e4..b29221783598 100644 --- a/drivers/watchdog/ar7_wdt.c +++ b/drivers/watchdog/ar7_wdt.c @@ -267,6 +267,7 @@ static const struct file_operations ar7_wdt_fops = { .unlocked_ioctl = ar7_wdt_ioctl, .open = ar7_wdt_open, .release = ar7_wdt_release, + .llseek = no_llseek, }; static struct miscdevice ar7_wdt_miscdev = { diff --git a/drivers/watchdog/booke_wdt.c b/drivers/watchdog/booke_wdt.c index 3d49671cdf5a..d11ffb091b0d 100644 --- a/drivers/watchdog/booke_wdt.c +++ b/drivers/watchdog/booke_wdt.c @@ -4,7 +4,7 @@ * Author: Matthew McClintock * Maintainer: Kumar Gala <galak@kernel.crashing.org> * - * Copyright 2005, 2008 Freescale Semiconductor Inc. + * Copyright 2005, 2008, 2010 Freescale Semiconductor Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -33,14 +33,8 @@ * occur, and the final time the board will reset. */ -#ifdef CONFIG_FSL_BOOKE -#define WDT_PERIOD_DEFAULT 38 /* Ex. wdt_period=28 bus=333Mhz,reset=~40sec */ -#else -#define WDT_PERIOD_DEFAULT 3 /* Refer to the PPC40x and PPC4xx manuals */ -#endif /* for timing information */ - u32 booke_wdt_enabled; -u32 booke_wdt_period = WDT_PERIOD_DEFAULT; +u32 booke_wdt_period = CONFIG_BOOKE_WDT_DEFAULT_TIMEOUT; #ifdef CONFIG_FSL_BOOKE #define WDTP(x) ((((x)&0x3)<<30)|(((x)&0x3c)<<15)) @@ -114,6 +108,27 @@ static void __booke_wdt_enable(void *data) mtspr(SPRN_TCR, val); } +/** + * booke_wdt_disable - disable the watchdog on the given CPU + * + * This function is called on each CPU. It disables the watchdog on that CPU. + * + * TCR[WRC] cannot be changed once it has been set to non-zero, but we can + * effectively disable the watchdog by setting its period to the maximum value. + */ +static void __booke_wdt_disable(void *data) +{ + u32 val; + + val = mfspr(SPRN_TCR); + val &= ~(TCR_WIE | WDTP_MASK); + mtspr(SPRN_TCR, val); + + /* clear status to make sure nothing is pending */ + __booke_wdt_ping(NULL); + +} + static ssize_t booke_wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { @@ -193,12 +208,21 @@ static int booke_wdt_open(struct inode *inode, struct file *file) return nonseekable_open(inode, file); } +static int booke_wdt_release(struct inode *inode, struct file *file) +{ + on_each_cpu(__booke_wdt_disable, NULL, 0); + booke_wdt_enabled = 0; + + return 0; +} + static const struct file_operations booke_wdt_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .write = booke_wdt_write, .unlocked_ioctl = booke_wdt_ioctl, .open = booke_wdt_open, + .release = booke_wdt_release, }; static struct miscdevice booke_wdt_miscdev = { @@ -237,4 +261,9 @@ static int __init booke_wdt_init(void) return ret; } -device_initcall(booke_wdt_init); + +module_init(booke_wdt_init); +module_exit(booke_wdt_exit); + +MODULE_DESCRIPTION("PowerPC Book-E watchdog driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/watchdog/cpwd.c b/drivers/watchdog/cpwd.c index 566343b3c131..eca855a55c0d 100644 --- a/drivers/watchdog/cpwd.c +++ b/drivers/watchdog/cpwd.c @@ -25,7 +25,7 @@ #include <linux/ioport.h> #include <linux/timer.h> #include <linux/slab.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/io.h> #include <linux/of.h> #include <linux/of_device.h> @@ -89,6 +89,7 @@ struct cpwd { } devs[WD_NUMDEVS]; }; +static DEFINE_MUTEX(cpwd_mutex); static struct cpwd *cpwd_device; /* Sun uses Altera PLD EPF8820ATC144-4 @@ -368,7 +369,7 @@ static int cpwd_open(struct inode *inode, struct file *f) { struct cpwd *p = cpwd_device; - lock_kernel(); + mutex_lock(&cpwd_mutex); switch (iminor(inode)) { case WD0_MINOR: case WD1_MINOR: @@ -376,7 +377,7 @@ static int cpwd_open(struct inode *inode, struct file *f) break; default: - unlock_kernel(); + mutex_unlock(&cpwd_mutex); return -ENODEV; } @@ -386,13 +387,13 @@ static int cpwd_open(struct inode *inode, struct file *f) IRQF_SHARED, DRIVER_NAME, p)) { printk(KERN_ERR PFX "Cannot register IRQ %d\n", p->irq); - unlock_kernel(); + mutex_unlock(&cpwd_mutex); return -EBUSY; } p->initialized = true; } - unlock_kernel(); + mutex_unlock(&cpwd_mutex); return nonseekable_open(inode, f); } @@ -482,9 +483,9 @@ static long cpwd_compat_ioctl(struct file *file, unsigned int cmd, case WIOCSTART: case WIOCSTOP: case WIOCGSTAT: - lock_kernel(); + mutex_lock(&cpwd_mutex); rval = cpwd_ioctl(file, cmd, arg); - unlock_kernel(); + mutex_unlock(&cpwd_mutex); break; /* everything else is handled by the generic compat layer */ @@ -524,6 +525,7 @@ static const struct file_operations cpwd_fops = { .write = cpwd_write, .read = cpwd_read, .release = cpwd_release, + .llseek = no_llseek, }; static int __devinit cpwd_probe(struct platform_device *op, diff --git a/drivers/watchdog/ep93xx_wdt.c b/drivers/watchdog/ep93xx_wdt.c index 59359c9a5e01..726b7df61fd0 100644 --- a/drivers/watchdog/ep93xx_wdt.c +++ b/drivers/watchdog/ep93xx_wdt.c @@ -188,6 +188,7 @@ static const struct file_operations ep93xx_wdt_fops = { .unlocked_ioctl = ep93xx_wdt_ioctl, .open = ep93xx_wdt_open, .release = ep93xx_wdt_release, + .llseek = no_llseek, }; static struct miscdevice ep93xx_wdt_miscdev = { diff --git a/drivers/watchdog/octeon-wdt-main.c b/drivers/watchdog/octeon-wdt-main.c index 2a410170eca6..909923800a02 100644 --- a/drivers/watchdog/octeon-wdt-main.c +++ b/drivers/watchdog/octeon-wdt-main.c @@ -64,6 +64,7 @@ #include <linux/cpu.h> #include <linux/smp.h> #include <linux/fs.h> +#include <linux/irq.h> #include <asm/mipsregs.h> #include <asm/uasm.h> diff --git a/drivers/watchdog/omap_wdt.c b/drivers/watchdog/omap_wdt.c index 76b58abf4451..81e3d6100894 100644 --- a/drivers/watchdog/omap_wdt.c +++ b/drivers/watchdog/omap_wdt.c @@ -258,6 +258,7 @@ static const struct file_operations omap_wdt_fops = { .unlocked_ioctl = omap_wdt_ioctl, .open = omap_wdt_open, .release = omap_wdt_release, + .llseek = no_llseek, }; static int __devinit omap_wdt_probe(struct platform_device *pdev) diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 13365ba35218..7d24b0d94ed4 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -338,30 +338,29 @@ static void unmask_evtchn(int port) static int find_unbound_irq(void) { - int irq; - struct irq_desc *desc; + struct irq_data *data; + int irq, res; for (irq = 0; irq < nr_irqs; irq++) { - desc = irq_to_desc(irq); + data = irq_get_irq_data(irq); /* only 0->15 have init'd desc; handle irq > 16 */ - if (desc == NULL) + if (!data) break; - if (desc->chip == &no_irq_chip) + if (data->chip == &no_irq_chip) break; - if (desc->chip != &xen_dynamic_chip) + if (data->chip != &xen_dynamic_chip) continue; if (irq_info[irq].type == IRQT_UNBOUND) - break; + return irq; } if (irq == nr_irqs) panic("No available IRQ to bind to: increase nr_irqs!\n"); - desc = irq_to_desc_alloc_node(irq, 0); - if (WARN_ON(desc == NULL)) - return -1; + res = irq_alloc_desc_at(irq, 0); - dynamic_irq_init_keep_chip_data(irq); + if (WARN_ON(res != irq)) + return -1; return irq; } @@ -495,7 +494,7 @@ static void unbind_from_irq(unsigned int irq) if (irq_info[irq].type != IRQT_UNBOUND) { irq_info[irq] = mk_unbound_info(); - dynamic_irq_cleanup(irq); + irq_free_desc(irq); } spin_unlock(&irq_mapping_update_lock); diff --git a/drivers/xen/evtchn.c b/drivers/xen/evtchn.c index 66e185cfe92f..fec6ba3c08a8 100644 --- a/drivers/xen/evtchn.c +++ b/drivers/xen/evtchn.c @@ -467,6 +467,7 @@ static const struct file_operations evtchn_fops = { .fasync = evtchn_fasync, .open = evtchn_open, .release = evtchn_release, + .llseek = noop_llseek, }; static struct miscdevice evtchn_miscdev = { diff --git a/drivers/xen/xenfs/super.c b/drivers/xen/xenfs/super.c index 78bfab0700ba..bd96340063c1 100644 --- a/drivers/xen/xenfs/super.c +++ b/drivers/xen/xenfs/super.c @@ -35,6 +35,7 @@ static ssize_t capabilities_read(struct file *file, char __user *buf, static const struct file_operations capabilities_file_ops = { .read = capabilities_read, + .llseek = default_llseek, }; static int xenfs_fill_super(struct super_block *sb, void *data, int silent) diff --git a/drivers/xen/xenfs/xenbus.c b/drivers/xen/xenfs/xenbus.c index 3b39c3752e21..1c1236087f78 100644 --- a/drivers/xen/xenfs/xenbus.c +++ b/drivers/xen/xenfs/xenbus.c @@ -594,4 +594,5 @@ const struct file_operations xenbus_file_ops = { .open = xenbus_file_open, .release = xenbus_file_release, .poll = xenbus_file_poll, + .llseek = no_llseek, }; diff --git a/drivers/zorro/zorro.c b/drivers/zorro/zorro.c index 6455f3a244c5..e0c2807b0970 100644 --- a/drivers/zorro/zorro.c +++ b/drivers/zorro/zorro.c @@ -142,6 +142,7 @@ static int __init amiga_zorro_probe(struct platform_device *pdev) error = device_register(&bus->dev); if (error) { pr_err("Zorro: Error registering zorro_bus\n"); + put_device(&bus->dev); kfree(bus); return error; } @@ -175,6 +176,7 @@ static int __init amiga_zorro_probe(struct platform_device *pdev) if (error) { dev_err(&bus->dev, "Error registering device %s\n", z->name); + put_device(&z->dev); continue; } error = zorro_create_sysfs_dev_files(z); |