diff options
Diffstat (limited to 'drivers/scsi')
140 files changed, 32414 insertions, 13840 deletions
diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c index 5311317c2e4..a12783ebb42 100644 --- a/drivers/scsi/3w-9xxx.c +++ b/drivers/scsi/3w-9xxx.c @@ -4,7 +4,7 @@ Written By: Adam Radford <linuxraid@amcc.com> Modifications By: Tom Couch <linuxraid@amcc.com> - Copyright (C) 2004-2008 Applied Micro Circuits Corporation. + Copyright (C) 2004-2009 Applied Micro Circuits Corporation. 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 @@ -75,6 +75,7 @@ Add MSI support and "use_msi" module parameter. Fix bug in twa_get_param() on 4GB+. Use pci_resource_len() for ioremap(). + 2.26.02.012 - Add power management support. */ #include <linux/module.h> @@ -99,7 +100,7 @@ #include "3w-9xxx.h" /* Globals */ -#define TW_DRIVER_VERSION "2.26.02.011" +#define TW_DRIVER_VERSION "2.26.02.012" static TW_Device_Extension *twa_device_extension_list[TW_MAX_SLOT]; static unsigned int twa_device_extension_count; static int twa_major = -1; @@ -2182,6 +2183,98 @@ static void twa_remove(struct pci_dev *pdev) twa_device_extension_count--; } /* End twa_remove() */ +#ifdef CONFIG_PM +/* This function is called on PCI suspend */ +static int twa_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct Scsi_Host *host = pci_get_drvdata(pdev); + TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata; + + printk(KERN_WARNING "3w-9xxx: Suspending host %d.\n", tw_dev->host->host_no); + + TW_DISABLE_INTERRUPTS(tw_dev); + free_irq(tw_dev->tw_pci_dev->irq, tw_dev); + + if (test_bit(TW_USING_MSI, &tw_dev->flags)) + pci_disable_msi(pdev); + + /* Tell the card we are shutting down */ + if (twa_initconnection(tw_dev, 1, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL)) { + TW_PRINTK(tw_dev->host, TW_DRIVER, 0x38, "Connection shutdown failed during suspend"); + } else { + printk(KERN_WARNING "3w-9xxx: Suspend complete.\n"); + } + TW_CLEAR_ALL_INTERRUPTS(tw_dev); + + pci_save_state(pdev); + pci_disable_device(pdev); + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + + return 0; +} /* End twa_suspend() */ + +/* This function is called on PCI resume */ +static int twa_resume(struct pci_dev *pdev) +{ + int retval = 0; + struct Scsi_Host *host = pci_get_drvdata(pdev); + TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata; + + printk(KERN_WARNING "3w-9xxx: Resuming host %d.\n", tw_dev->host->host_no); + pci_set_power_state(pdev, PCI_D0); + pci_enable_wake(pdev, PCI_D0, 0); + pci_restore_state(pdev); + + retval = pci_enable_device(pdev); + if (retval) { + TW_PRINTK(tw_dev->host, TW_DRIVER, 0x39, "Enable device failed during resume"); + return retval; + } + + pci_set_master(pdev); + pci_try_set_mwi(pdev); + + if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) + || pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) + if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) + || pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) { + TW_PRINTK(host, TW_DRIVER, 0x40, "Failed to set dma mask during resume"); + retval = -ENODEV; + goto out_disable_device; + } + + /* Initialize the card */ + if (twa_reset_sequence(tw_dev, 0)) { + retval = -ENODEV; + goto out_disable_device; + } + + /* Now setup the interrupt handler */ + retval = request_irq(pdev->irq, twa_interrupt, IRQF_SHARED, "3w-9xxx", tw_dev); + if (retval) { + TW_PRINTK(tw_dev->host, TW_DRIVER, 0x42, "Error requesting IRQ during resume"); + retval = -ENODEV; + goto out_disable_device; + } + + /* Now enable MSI if enabled */ + if (test_bit(TW_USING_MSI, &tw_dev->flags)) + pci_enable_msi(pdev); + + /* Re-enable interrupts on the card */ + TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev); + + printk(KERN_WARNING "3w-9xxx: Resume complete.\n"); + return 0; + +out_disable_device: + scsi_remove_host(host); + pci_disable_device(pdev); + + return retval; +} /* End twa_resume() */ +#endif + /* PCI Devices supported by this driver */ static struct pci_device_id twa_pci_tbl[] __devinitdata = { { PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9000, @@ -2202,6 +2295,10 @@ static struct pci_driver twa_driver = { .id_table = twa_pci_tbl, .probe = twa_probe, .remove = twa_remove, +#ifdef CONFIG_PM + .suspend = twa_suspend, + .resume = twa_resume, +#endif .shutdown = twa_shutdown }; diff --git a/drivers/scsi/3w-9xxx.h b/drivers/scsi/3w-9xxx.h index 1729a8785fe..2893eec78ed 100644 --- a/drivers/scsi/3w-9xxx.h +++ b/drivers/scsi/3w-9xxx.h @@ -4,7 +4,7 @@ Written By: Adam Radford <linuxraid@amcc.com> Modifications By: Tom Couch <linuxraid@amcc.com> - Copyright (C) 2004-2008 Applied Micro Circuits Corporation. + Copyright (C) 2004-2009 Applied Micro Circuits Corporation. 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 diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 256c7bec7bd..8ed2990c826 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -121,10 +121,11 @@ config BLK_DEV_SR tristate "SCSI CDROM support" depends on SCSI ---help--- - If you want to use a SCSI or FireWire CD-ROM under Linux, - say Y and read the SCSI-HOWTO and the CDROM-HOWTO at - <http://www.tldp.org/docs.html#howto>. Also make sure to say - Y or M to "ISO 9660 CD-ROM file system support" later. + If you want to use a CD or DVD drive attached to your computer + by SCSI, FireWire, USB or ATAPI, say Y and read the SCSI-HOWTO + and the CDROM-HOWTO at <http://www.tldp.org/docs.html#howto>. + + Make sure to say Y or M to "ISO 9660 CD-ROM file system support". To compile this driver as a module, choose M here and read <file:Documentation/scsi/scsi.txt>. @@ -224,14 +225,15 @@ config SCSI_LOGGING can enable logging by saying Y to "/proc file system support" and "Sysctl support" below and executing the command - echo "scsi log token [level]" > /proc/scsi/scsi + echo <bitmask> > /proc/sys/dev/scsi/logging_level - at boot time after the /proc file system has been mounted. + where <bitmask> is a four byte value representing the logging type + and logging level for each type of logging selected. - There are a number of things that can be used for 'token' (you can - find them in the source: <file:drivers/scsi/scsi.c>), and this - allows you to select the types of information you want, and the - level allows you to select the level of verbosity. + There are a number of logging types and you can find them in the + source at <file:drivers/scsi/scsi_logging.h>. The logging levels + are also described in that file and they determine the verbosity of + the logging for each logging type. If you say N here, it may be harder to track down some types of SCSI problems. If you say Y here your kernel will be somewhat larger, but @@ -570,6 +572,7 @@ config SCSI_ARCMSR_AER To enable this function, choose Y here. source "drivers/scsi/megaraid/Kconfig.megaraid" +source "drivers/scsi/mpt2sas/Kconfig" config SCSI_HPTIOP tristate "HighPoint RocketRAID 3xxx/4xxx Controller support" @@ -608,13 +611,20 @@ config SCSI_FLASHPOINT config LIBFC tristate "LibFC module" select SCSI_FC_ATTRS + select CRC32 ---help--- Fibre Channel library module +config LIBFCOE + tristate "LibFCoE module" + select LIBFC + ---help--- + Library for Fibre Channel over Ethernet module + config FCOE tristate "FCoE module" depends on PCI - select LIBFC + select LIBFCOE ---help--- Fibre Channel over Ethernet module @@ -1377,7 +1387,7 @@ config SCSI_LPFC_DEBUG_FS bool "Emulex LightPulse Fibre Channel debugfs Support" depends on SCSI_LPFC && DEBUG_FS help - This makes debugging infomation from the lpfc driver + This makes debugging information from the lpfc driver available via the debugfs filesystem. config SCSI_SIM710 @@ -1385,7 +1395,7 @@ config SCSI_SIM710 depends on (EISA || MCA) && SCSI select SCSI_SPI_ATTRS ---help--- - This driver for NCR53c710 based SCSI host adapters. + This driver is for NCR53c710 based SCSI host adapters. It currently supports Compaq EISA cards and NCR MCA cards @@ -1535,6 +1545,7 @@ config SCSI_NSP32 config SCSI_DEBUG tristate "SCSI debugging host simulator" depends on SCSI + select CRC_T10DIF help This is a host adapter simulator that can simulate multiple hosts each with multiple dummy SCSI devices (disks). It defaults to one @@ -1803,4 +1814,6 @@ source "drivers/scsi/pcmcia/Kconfig" source "drivers/scsi/device_handler/Kconfig" +source "drivers/scsi/osd/Kconfig" + endmenu diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 7461eb09a03..e7c861ac417 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -37,6 +37,7 @@ obj-$(CONFIG_SCSI_SRP_ATTRS) += scsi_transport_srp.o obj-$(CONFIG_SCSI_DH) += device_handler/ obj-$(CONFIG_LIBFC) += libfc/ +obj-$(CONFIG_LIBFCOE) += fcoe/ obj-$(CONFIG_FCOE) += fcoe/ obj-$(CONFIG_ISCSI_TCP) += libiscsi.o libiscsi_tcp.o iscsi_tcp.o obj-$(CONFIG_INFINIBAND_ISER) += libiscsi.o @@ -99,6 +100,7 @@ obj-$(CONFIG_SCSI_DC390T) += tmscsim.o obj-$(CONFIG_MEGARAID_LEGACY) += megaraid.o obj-$(CONFIG_MEGARAID_NEWGEN) += megaraid/ obj-$(CONFIG_MEGARAID_SAS) += megaraid/ +obj-$(CONFIG_SCSI_MPT2SAS) += mpt2sas/ obj-$(CONFIG_SCSI_ACARD) += atp870u.o obj-$(CONFIG_SCSI_SUNESP) += esp_scsi.o sun_esp.o obj-$(CONFIG_SCSI_GDTH) += gdth.o @@ -137,6 +139,8 @@ obj-$(CONFIG_CHR_DEV_SG) += sg.o obj-$(CONFIG_CHR_DEV_SCH) += ch.o obj-$(CONFIG_SCSI_ENCLOSURE) += ses.o +obj-$(CONFIG_SCSI_OSD_INITIATOR) += osd/ + # This goes last, so that "real" scsi devices probe earlier obj-$(CONFIG_SCSI_DEBUG) += scsi_debug.o diff --git a/drivers/scsi/a2091.c b/drivers/scsi/a2091.c index 37dd47136fb..4b38c4750f7 100644 --- a/drivers/scsi/a2091.c +++ b/drivers/scsi/a2091.c @@ -23,6 +23,8 @@ #define DMA(ptr) ((a2091_scsiregs *)((ptr)->base)) #define HDATA(ptr) ((struct WD33C93_hostdata *)((ptr)->hostdata)) +static int a2091_release(struct Scsi_Host *instance); + static irqreturn_t a2091_intr (int irq, void *_instance) { unsigned long flags; @@ -144,7 +146,7 @@ static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt, } } -int __init a2091_detect(struct scsi_host_template *tpnt) +static int __init a2091_detect(struct scsi_host_template *tpnt) { static unsigned char called = 0; struct Scsi_Host *instance; @@ -233,7 +235,7 @@ static struct scsi_host_template driver_template = { #include "scsi_module.c" -int a2091_release(struct Scsi_Host *instance) +static int a2091_release(struct Scsi_Host *instance) { #ifdef MODULE DMA(instance)->CNTR = 0; diff --git a/drivers/scsi/a2091.h b/drivers/scsi/a2091.h index fe809bc88d7..252528f2672 100644 --- a/drivers/scsi/a2091.h +++ b/drivers/scsi/a2091.h @@ -11,9 +11,6 @@ #include <linux/types.h> -int a2091_detect(struct scsi_host_template *); -int a2091_release(struct Scsi_Host *); - #ifndef CMD_PER_LUN #define CMD_PER_LUN 2 #endif diff --git a/drivers/scsi/a3000.c b/drivers/scsi/a3000.c index 8b449d8acac..6970ce82c4a 100644 --- a/drivers/scsi/a3000.c +++ b/drivers/scsi/a3000.c @@ -25,6 +25,8 @@ static struct Scsi_Host *a3000_host = NULL; +static int a3000_release(struct Scsi_Host *instance); + static irqreturn_t a3000_intr (int irq, void *dummy) { unsigned long flags; @@ -157,7 +159,7 @@ static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt, } } -int __init a3000_detect(struct scsi_host_template *tpnt) +static int __init a3000_detect(struct scsi_host_template *tpnt) { wd33c93_regs regs; @@ -232,7 +234,7 @@ static struct scsi_host_template driver_template = { #include "scsi_module.c" -int a3000_release(struct Scsi_Host *instance) +static int a3000_release(struct Scsi_Host *instance) { wd33c93_release(); DMA(instance)->CNTR = 0; diff --git a/drivers/scsi/a3000.h b/drivers/scsi/a3000.h index 44a4ec7b465..c7afe16fd6e 100644 --- a/drivers/scsi/a3000.h +++ b/drivers/scsi/a3000.h @@ -11,9 +11,6 @@ #include <linux/types.h> -int a3000_detect(struct scsi_host_template *); -int a3000_release(struct Scsi_Host *); - #ifndef CMD_PER_LUN #define CMD_PER_LUN 2 #endif diff --git a/drivers/scsi/a4000t.c b/drivers/scsi/a4000t.c index d4bda201774..61af3d91ac8 100644 --- a/drivers/scsi/a4000t.c +++ b/drivers/scsi/a4000t.c @@ -35,7 +35,7 @@ static struct platform_device *a4000t_scsi_device; #define A4000T_SCSI_ADDR 0xdd0040 -static int __devinit a4000t_probe(struct device *dev) +static int __devinit a4000t_probe(struct platform_device *dev) { struct Scsi_Host *host; struct NCR_700_Host_Parameters *hostdata; @@ -61,7 +61,8 @@ static int __devinit a4000t_probe(struct device *dev) hostdata->dcntl_extra = EA_710; /* and register the chip */ - host = NCR_700_detect(&a4000t_scsi_driver_template, hostdata, dev); + host = NCR_700_detect(&a4000t_scsi_driver_template, hostdata, + &dev->dev); if (!host) { printk(KERN_ERR "a4000t-scsi: No host detected; " "board configuration problem?\n"); @@ -78,7 +79,7 @@ static int __devinit a4000t_probe(struct device *dev) goto out_put_host; } - dev_set_drvdata(dev, host); + platform_set_drvdata(dev, host); scsi_scan_host(host); return 0; @@ -93,9 +94,9 @@ static int __devinit a4000t_probe(struct device *dev) return -ENODEV; } -static __devexit int a4000t_device_remove(struct device *dev) +static __devexit int a4000t_device_remove(struct platform_device *dev) { - struct Scsi_Host *host = dev_get_drvdata(dev); + struct Scsi_Host *host = platform_get_drvdata(dev); struct NCR_700_Host_Parameters *hostdata = shost_priv(host); scsi_remove_host(host); @@ -108,25 +109,27 @@ static __devexit int a4000t_device_remove(struct device *dev) return 0; } -static struct device_driver a4000t_scsi_driver = { - .name = "a4000t-scsi", - .bus = &platform_bus_type, - .probe = a4000t_probe, - .remove = __devexit_p(a4000t_device_remove), +static struct platform_driver a4000t_scsi_driver = { + .driver = { + .name = "a4000t-scsi", + .owner = THIS_MODULE, + }, + .probe = a4000t_probe, + .remove = __devexit_p(a4000t_device_remove), }; static int __init a4000t_scsi_init(void) { int err; - err = driver_register(&a4000t_scsi_driver); + err = platform_driver_register(&a4000t_scsi_driver); if (err) return err; a4000t_scsi_device = platform_device_register_simple("a4000t-scsi", -1, NULL, 0); if (IS_ERR(a4000t_scsi_device)) { - driver_unregister(&a4000t_scsi_driver); + platform_driver_register(&a4000t_scsi_driver); return PTR_ERR(a4000t_scsi_device); } @@ -136,7 +139,7 @@ static int __init a4000t_scsi_init(void) static void __exit a4000t_scsi_exit(void) { platform_device_unregister(a4000t_scsi_device); - driver_unregister(&a4000t_scsi_driver); + platform_driver_unregister(&a4000t_scsi_driver); } module_init(a4000t_scsi_init); diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index 90d1d0878cb..21964aaebca 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c @@ -143,7 +143,7 @@ static char *aac_get_status_string(u32 status); */ static int nondasd = -1; -static int aac_cache; +static int aac_cache = 2; /* WCE=0 to avoid performance problems */ static int dacmode = -1; int aac_msi; int aac_commit = -1; @@ -157,7 +157,7 @@ module_param_named(cache, aac_cache, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(cache, "Disable Queue Flush commands:\n" "\tbit 0 - Disable FUA in WRITE SCSI commands\n" "\tbit 1 - Disable SYNCHRONIZE_CACHE SCSI command\n" - "\tbit 2 - Disable only if Battery not protecting Cache"); + "\tbit 2 - Disable only if Battery is protecting Cache"); module_param(dacmode, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(dacmode, "Control whether dma addressing is using 64 bit DAC." " 0=off, 1=on"); @@ -217,6 +217,14 @@ int aac_reset_devices; module_param_named(reset_devices, aac_reset_devices, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(reset_devices, "Force an adapter reset at initialization."); +int aac_wwn = 1; +module_param_named(wwn, aac_wwn, int, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(wwn, "Select a WWN type for the arrays:\n" + "\t0 - Disable\n" + "\t1 - Array Meta Data Signature (default)\n" + "\t2 - Adapter Serial Number"); + + static inline int aac_valid_context(struct scsi_cmnd *scsicmd, struct fib *fibptr) { struct scsi_device *device; @@ -1206,9 +1214,8 @@ static int aac_scsi_32(struct fib * fib, struct scsi_cmnd * cmd) static int aac_scsi_32_64(struct fib * fib, struct scsi_cmnd * cmd) { - if ((sizeof(dma_addr_t) > 4) && - (num_physpages > (0xFFFFFFFFULL >> PAGE_SHIFT)) && - (fib->dev->adapter_info.options & AAC_OPT_SGMAP_HOST64)) + if ((sizeof(dma_addr_t) > 4) && fib->dev->needs_dac && + (fib->dev->adapter_info.options & AAC_OPT_SGMAP_HOST64)) return FAILED; return aac_scsi_32(fib, cmd); } @@ -1371,8 +1378,11 @@ int aac_get_adapter_info(struct aac_dev* dev) if (dev->nondasd_support && !dev->in_reset) printk(KERN_INFO "%s%d: Non-DASD support enabled.\n",dev->name, dev->id); + if (dma_get_required_mask(&dev->pdev->dev) > DMA_32BIT_MASK) + dev->needs_dac = 1; dev->dac_support = 0; - if( (sizeof(dma_addr_t) > 4) && (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64)){ + if ((sizeof(dma_addr_t) > 4) && dev->needs_dac && + (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64)) { if (!dev->in_reset) printk(KERN_INFO "%s%d: 64bit support enabled.\n", dev->name, dev->id); @@ -1382,6 +1392,15 @@ int aac_get_adapter_info(struct aac_dev* dev) if(dacmode != -1) { dev->dac_support = (dacmode!=0); } + + /* avoid problems with AAC_QUIRK_SCSI_32 controllers */ + if (dev->dac_support && (aac_get_driver_ident(dev->cardtype)->quirks + & AAC_QUIRK_SCSI_32)) { + dev->nondasd_support = 0; + dev->jbod = 0; + expose_physicals = 0; + } + if(dev->dac_support != 0) { if (!pci_set_dma_mask(dev->pdev, DMA_64BIT_MASK) && !pci_set_consistent_dma_mask(dev->pdev, DMA_64BIT_MASK)) { @@ -2058,7 +2077,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) dprintk((KERN_DEBUG "INQUIRY command, ID: %d.\n", cid)); memset(&inq_data, 0, sizeof (struct inquiry_data)); - if (scsicmd->cmnd[1] & 0x1) { + if ((scsicmd->cmnd[1] & 0x1) && aac_wwn) { char *arr = (char *)&inq_data; /* EVPD bit set */ @@ -2081,7 +2100,12 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) arr[1] = scsicmd->cmnd[2]; scsi_sg_copy_from_buffer(scsicmd, &inq_data, sizeof(inq_data)); - return aac_get_container_serial(scsicmd); + if (aac_wwn != 2) + return aac_get_container_serial( + scsicmd); + /* SLES 10 SP1 special */ + scsicmd->result = DID_OK << 16 | + COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; } else { /* vpd page not implemented */ scsicmd->result = DID_OK << 16 | diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h index 73916adb8f8..cdbdec9f4fb 100644 --- a/drivers/scsi/aacraid/aacraid.h +++ b/drivers/scsi/aacraid/aacraid.h @@ -12,7 +12,7 @@ *----------------------------------------------------------------------------*/ #ifndef AAC_DRIVER_BUILD -# define AAC_DRIVER_BUILD 2456 +# define AAC_DRIVER_BUILD 2461 # define AAC_DRIVER_BRANCH "-ms" #endif #define MAXIMUM_NUM_CONTAINERS 32 @@ -865,7 +865,11 @@ struct aac_supplement_adapter_info u8 MfgPcbaSerialNo[12]; u8 MfgWWNName[8]; __le32 SupportedOptions2; - __le32 ReservedGrowth[1]; + __le32 StructExpansion; + /* StructExpansion == 1 */ + __le32 FeatureBits3; + __le32 SupportedPerformanceModes; + __le32 ReservedForFutureGrowth[80]; }; #define AAC_FEATURE_FALCON cpu_to_le32(0x00000010) #define AAC_FEATURE_JBOD cpu_to_le32(0x08000000) @@ -1020,6 +1024,7 @@ struct aac_dev u8 jbod; u8 cache_protected; u8 dac_support; + u8 needs_dac; u8 raid_scsi_mode; u8 comm_interface; # define AAC_COMM_PRODUCER 0 diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c index 16310443b55..d598eba630d 100644 --- a/drivers/scsi/aacraid/comminit.c +++ b/drivers/scsi/aacraid/comminit.c @@ -54,6 +54,7 @@ static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long co const unsigned long printfbufsiz = 256; struct aac_init *init; dma_addr_t phys; + unsigned long aac_max_hostphysmempages; size = fibsize + sizeof(struct aac_init) + commsize + commalign + printfbufsiz; @@ -90,7 +91,18 @@ static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long co init->AdapterFibsPhysicalAddress = cpu_to_le32((u32)phys); init->AdapterFibsSize = cpu_to_le32(fibsize); init->AdapterFibAlign = cpu_to_le32(sizeof(struct hw_fib)); - init->HostPhysMemPages = cpu_to_le32(AAC_MAX_HOSTPHYSMEMPAGES); + /* + * number of 4k pages of host physical memory. The aacraid fw needs + * this number to be less than 4gb worth of pages. New firmware doesn't + * have any issues with the mapping system, but older Firmware did, and + * had *troubles* dealing with the math overloading past 32 bits, thus + * we must limit this field. + */ + aac_max_hostphysmempages = dma_get_required_mask(&dev->pdev->dev) >> 12; + if (aac_max_hostphysmempages < AAC_MAX_HOSTPHYSMEMPAGES) + init->HostPhysMemPages = cpu_to_le32(aac_max_hostphysmempages); + else + init->HostPhysMemPages = cpu_to_le32(AAC_MAX_HOSTPHYSMEMPAGES); init->InitFlags = 0; if (dev->comm_interface == AAC_COMM_MESSAGE) { diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index 36d8aab97ef..c507719c0d4 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -86,7 +86,13 @@ char aac_driver_version[] = AAC_DRIVER_FULL_VERSION; * * Note: The last field is used to index into aac_drivers below. */ -static struct pci_device_id aac_pci_tbl[] = { +#ifdef DECLARE_PCI_DEVICE_TABLE +static DECLARE_PCI_DEVICE_TABLE(aac_pci_tbl) = { +#elif defined(__devinitconst) +static const struct pci_device_id aac_pci_tbl[] __devinitconst = { +#else +static const struct pci_device_id aac_pci_tbl[] __devinitdata = { +#endif { 0x1028, 0x0001, 0x1028, 0x0001, 0, 0, 0 }, /* PERC 2/Si (Iguana/PERC2Si) */ { 0x1028, 0x0002, 0x1028, 0x0002, 0, 0, 1 }, /* PERC 3/Di (Opal/PERC3Di) */ { 0x1028, 0x0003, 0x1028, 0x0003, 0, 0, 2 }, /* PERC 3/Si (SlimFast/PERC3Si */ diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index 7507d8bc57a..b756041f0b2 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c @@ -38,6 +38,7 @@ #include <linux/pci.h> #include <linux/spinlock.h> #include <linux/dma-mapping.h> +#include <linux/firmware.h> #include <asm/io.h> #include <asm/system.h> @@ -4519,8 +4520,8 @@ static void AscWriteLramByte(PortAddr iop_base, ushort addr, uchar byte_val) * and is maintained in little-endian order when written to LRAM. */ static void -AscMemWordCopyPtrToLram(PortAddr iop_base, - ushort s_addr, uchar *s_buffer, int words) +AscMemWordCopyPtrToLram(PortAddr iop_base, ushort s_addr, + const uchar *s_buffer, int words) { int i; @@ -4642,8 +4643,8 @@ static ushort AscInitLram(ASC_DVC_VAR *asc_dvc) } static ASC_DCNT -AscLoadMicroCode(PortAddr iop_base, - ushort s_addr, uchar *mcode_buf, ushort mcode_size) +AscLoadMicroCode(PortAddr iop_base, ushort s_addr, + const uchar *mcode_buf, ushort mcode_size) { ASC_DCNT chksum; ushort mcode_word_size; @@ -4668,1618 +4669,6 @@ AscLoadMicroCode(PortAddr iop_base, return chksum; } -/* Microcode buffer is kept after initialization for error recovery. */ -static uchar _asc_mcode_buf[] = { - 0x01, 0x03, 0x01, 0x19, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC3, 0x12, 0x0D, 0x05, - 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0x80, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xE4, 0x88, 0x00, 0x00, 0x00, 0x00, 0x80, 0x73, 0x48, 0x04, - 0x36, 0x00, 0x00, 0xA2, 0xC2, 0x00, 0x80, 0x73, 0x03, 0x23, 0x36, 0x40, - 0xB6, 0x00, 0x36, 0x00, 0x05, 0xD6, 0x0C, 0xD2, 0x12, 0xDA, 0x00, 0xA2, - 0xC2, 0x00, 0x92, 0x80, 0x1E, 0x98, 0x50, 0x00, 0xF5, 0x00, 0x48, 0x98, - 0xDF, 0x23, 0x36, 0x60, 0xB6, 0x00, 0x92, 0x80, 0x4F, 0x00, 0xF5, 0x00, - 0x48, 0x98, 0xEF, 0x23, 0x36, 0x60, 0xB6, 0x00, 0x92, 0x80, 0x80, 0x62, - 0x92, 0x80, 0x00, 0x46, 0x15, 0xEE, 0x13, 0xEA, 0x02, 0x01, 0x09, 0xD8, - 0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xD6, 0x00, 0xA6, 0x97, 0x7F, 0x23, - 0x04, 0x61, 0x84, 0x01, 0xE6, 0x84, 0xD2, 0xC1, 0x80, 0x73, 0xCD, 0x04, - 0x4D, 0x00, 0x00, 0xA3, 0xDA, 0x01, 0xA6, 0x97, 0xC6, 0x81, 0xC2, 0x88, - 0x80, 0x73, 0x80, 0x77, 0x00, 0x01, 0x01, 0xA1, 0xFE, 0x00, 0x4F, 0x00, - 0x84, 0x97, 0x07, 0xA6, 0x08, 0x01, 0x00, 0x33, 0x03, 0x00, 0xC2, 0x88, - 0x03, 0x03, 0x01, 0xDE, 0xC2, 0x88, 0xCE, 0x00, 0x69, 0x60, 0xCE, 0x00, - 0x02, 0x03, 0x4A, 0x60, 0x00, 0xA2, 0x78, 0x01, 0x80, 0x63, 0x07, 0xA6, - 0x24, 0x01, 0x78, 0x81, 0x03, 0x03, 0x80, 0x63, 0xE2, 0x00, 0x07, 0xA6, - 0x34, 0x01, 0x00, 0x33, 0x04, 0x00, 0xC2, 0x88, 0x03, 0x07, 0x02, 0x01, - 0x04, 0xCA, 0x0D, 0x23, 0x68, 0x98, 0x4D, 0x04, 0x04, 0x85, 0x05, 0xD8, - 0x0D, 0x23, 0x68, 0x98, 0xCD, 0x04, 0x15, 0x23, 0xF8, 0x88, 0xFB, 0x23, - 0x02, 0x61, 0x82, 0x01, 0x80, 0x63, 0x02, 0x03, 0x06, 0xA3, 0x62, 0x01, - 0x00, 0x33, 0x0A, 0x00, 0xC2, 0x88, 0x4E, 0x00, 0x07, 0xA3, 0x6E, 0x01, - 0x00, 0x33, 0x0B, 0x00, 0xC2, 0x88, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33, - 0x1A, 0x00, 0xC2, 0x88, 0x50, 0x04, 0x88, 0x81, 0x06, 0xAB, 0x82, 0x01, - 0x88, 0x81, 0x4E, 0x00, 0x07, 0xA3, 0x92, 0x01, 0x50, 0x00, 0x00, 0xA3, - 0x3C, 0x01, 0x00, 0x05, 0x7C, 0x81, 0x46, 0x97, 0x02, 0x01, 0x05, 0xC6, - 0x04, 0x23, 0xA0, 0x01, 0x15, 0x23, 0xA1, 0x01, 0xBE, 0x81, 0xFD, 0x23, - 0x02, 0x61, 0x82, 0x01, 0x0A, 0xDA, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0, - 0xB4, 0x01, 0x80, 0x63, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33, 0x1B, 0x00, - 0xC2, 0x88, 0x06, 0x23, 0x68, 0x98, 0xCD, 0x04, 0xE6, 0x84, 0x06, 0x01, - 0x00, 0xA2, 0xD4, 0x01, 0x57, 0x60, 0x00, 0xA0, 0xDA, 0x01, 0xE6, 0x84, - 0x80, 0x23, 0xA0, 0x01, 0xE6, 0x84, 0x80, 0x73, 0x4B, 0x00, 0x06, 0x61, - 0x00, 0xA2, 0x00, 0x02, 0x04, 0x01, 0x0C, 0xDE, 0x02, 0x01, 0x03, 0xCC, - 0x4F, 0x00, 0x84, 0x97, 0xFC, 0x81, 0x08, 0x23, 0x02, 0x41, 0x82, 0x01, - 0x4F, 0x00, 0x62, 0x97, 0x48, 0x04, 0x84, 0x80, 0xF0, 0x97, 0x00, 0x46, - 0x56, 0x00, 0x03, 0xC0, 0x01, 0x23, 0xE8, 0x00, 0x81, 0x73, 0x06, 0x29, - 0x03, 0x42, 0x06, 0xE2, 0x03, 0xEE, 0x6B, 0xEB, 0x11, 0x23, 0xF8, 0x88, - 0x04, 0x98, 0xF0, 0x80, 0x80, 0x73, 0x80, 0x77, 0x07, 0xA4, 0x2A, 0x02, - 0x7C, 0x95, 0x06, 0xA6, 0x34, 0x02, 0x03, 0xA6, 0x4C, 0x04, 0x46, 0x82, - 0x04, 0x01, 0x03, 0xD8, 0xB4, 0x98, 0x6A, 0x96, 0x46, 0x82, 0xFE, 0x95, - 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0xB6, 0x2D, 0x02, 0xA6, 0x6C, 0x02, - 0x07, 0xA6, 0x5A, 0x02, 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x62, 0x02, - 0xC2, 0x88, 0x7C, 0x95, 0x48, 0x82, 0x60, 0x96, 0x48, 0x82, 0x04, 0x23, - 0xA0, 0x01, 0x14, 0x23, 0xA1, 0x01, 0x3C, 0x84, 0x04, 0x01, 0x0C, 0xDC, - 0xE0, 0x23, 0x25, 0x61, 0xEF, 0x00, 0x14, 0x01, 0x4F, 0x04, 0xA8, 0x01, - 0x6F, 0x00, 0xA5, 0x01, 0x03, 0x23, 0xA4, 0x01, 0x06, 0x23, 0x9C, 0x01, - 0x24, 0x2B, 0x1C, 0x01, 0x02, 0xA6, 0xAA, 0x02, 0x07, 0xA6, 0x5A, 0x02, - 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x20, 0x04, 0x01, 0xA6, 0xB4, 0x02, - 0x00, 0xA6, 0xB4, 0x02, 0x00, 0x33, 0x12, 0x00, 0xC2, 0x88, 0x00, 0x0E, - 0x80, 0x63, 0x00, 0x43, 0x00, 0xA0, 0x8C, 0x02, 0x4D, 0x04, 0x04, 0x01, - 0x0B, 0xDC, 0xE7, 0x23, 0x04, 0x61, 0x84, 0x01, 0x10, 0x31, 0x12, 0x35, - 0x14, 0x01, 0xEC, 0x00, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00, 0xEA, 0x82, - 0x18, 0x23, 0x04, 0x61, 0x18, 0xA0, 0xE2, 0x02, 0x04, 0x01, 0xA2, 0xC8, - 0x00, 0x33, 0x1F, 0x00, 0xC2, 0x88, 0x08, 0x31, 0x0A, 0x35, 0x0C, 0x39, - 0x0E, 0x3D, 0x7E, 0x98, 0xB6, 0x2D, 0x01, 0xA6, 0x14, 0x03, 0x00, 0xA6, - 0x14, 0x03, 0x07, 0xA6, 0x0C, 0x03, 0x06, 0xA6, 0x10, 0x03, 0x03, 0xA6, - 0x20, 0x04, 0x02, 0xA6, 0x6C, 0x02, 0x00, 0x33, 0x33, 0x00, 0xC2, 0x88, - 0x7C, 0x95, 0xEE, 0x82, 0x60, 0x96, 0xEE, 0x82, 0x82, 0x98, 0x80, 0x42, - 0x7E, 0x98, 0x64, 0xE4, 0x04, 0x01, 0x2D, 0xC8, 0x31, 0x05, 0x07, 0x01, - 0x00, 0xA2, 0x54, 0x03, 0x00, 0x43, 0x87, 0x01, 0x05, 0x05, 0x86, 0x98, - 0x7E, 0x98, 0x00, 0xA6, 0x16, 0x03, 0x07, 0xA6, 0x4C, 0x03, 0x03, 0xA6, - 0x3C, 0x04, 0x06, 0xA6, 0x50, 0x03, 0x01, 0xA6, 0x16, 0x03, 0x00, 0x33, - 0x25, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0x32, 0x83, 0x60, 0x96, 0x32, 0x83, - 0x04, 0x01, 0x10, 0xCE, 0x07, 0xC8, 0x05, 0x05, 0xEB, 0x04, 0x00, 0x33, - 0x00, 0x20, 0xC0, 0x20, 0x81, 0x62, 0x72, 0x83, 0x00, 0x01, 0x05, 0x05, - 0xFF, 0xA2, 0x7A, 0x03, 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x2E, 0x83, - 0x05, 0x05, 0x15, 0x01, 0x00, 0xA2, 0x9A, 0x03, 0xEC, 0x00, 0x6E, 0x00, - 0x95, 0x01, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00, 0x01, 0xA6, 0x96, 0x03, - 0x00, 0xA6, 0x96, 0x03, 0x10, 0x84, 0x80, 0x42, 0x7E, 0x98, 0x01, 0xA6, - 0xA4, 0x03, 0x00, 0xA6, 0xBC, 0x03, 0x10, 0x84, 0xA8, 0x98, 0x80, 0x42, - 0x01, 0xA6, 0xA4, 0x03, 0x07, 0xA6, 0xB2, 0x03, 0xD4, 0x83, 0x7C, 0x95, - 0xA8, 0x83, 0x00, 0x33, 0x2F, 0x00, 0xC2, 0x88, 0xA8, 0x98, 0x80, 0x42, - 0x00, 0xA6, 0xBC, 0x03, 0x07, 0xA6, 0xCA, 0x03, 0xD4, 0x83, 0x7C, 0x95, - 0xC0, 0x83, 0x00, 0x33, 0x26, 0x00, 0xC2, 0x88, 0x38, 0x2B, 0x80, 0x32, - 0x80, 0x36, 0x04, 0x23, 0xA0, 0x01, 0x12, 0x23, 0xA1, 0x01, 0x10, 0x84, - 0x07, 0xF0, 0x06, 0xA4, 0xF4, 0x03, 0x80, 0x6B, 0x80, 0x67, 0x05, 0x23, - 0x83, 0x03, 0x80, 0x63, 0x03, 0xA6, 0x0E, 0x04, 0x07, 0xA6, 0x06, 0x04, - 0x06, 0xA6, 0x0A, 0x04, 0x00, 0x33, 0x17, 0x00, 0xC2, 0x88, 0x7C, 0x95, - 0xF4, 0x83, 0x60, 0x96, 0xF4, 0x83, 0x20, 0x84, 0x07, 0xF0, 0x06, 0xA4, - 0x20, 0x04, 0x80, 0x6B, 0x80, 0x67, 0x05, 0x23, 0x83, 0x03, 0x80, 0x63, - 0xB6, 0x2D, 0x03, 0xA6, 0x3C, 0x04, 0x07, 0xA6, 0x34, 0x04, 0x06, 0xA6, - 0x38, 0x04, 0x00, 0x33, 0x30, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0x20, 0x84, - 0x60, 0x96, 0x20, 0x84, 0x1D, 0x01, 0x06, 0xCC, 0x00, 0x33, 0x00, 0x84, - 0xC0, 0x20, 0x00, 0x23, 0xEA, 0x00, 0x81, 0x62, 0xA2, 0x0D, 0x80, 0x63, - 0x07, 0xA6, 0x5A, 0x04, 0x00, 0x33, 0x18, 0x00, 0xC2, 0x88, 0x03, 0x03, - 0x80, 0x63, 0xA3, 0x01, 0x07, 0xA4, 0x64, 0x04, 0x23, 0x01, 0x00, 0xA2, - 0x86, 0x04, 0x0A, 0xA0, 0x76, 0x04, 0xE0, 0x00, 0x00, 0x33, 0x1D, 0x00, - 0xC2, 0x88, 0x0B, 0xA0, 0x82, 0x04, 0xE0, 0x00, 0x00, 0x33, 0x1E, 0x00, - 0xC2, 0x88, 0x42, 0x23, 0xF8, 0x88, 0x00, 0x23, 0x22, 0xA3, 0xE6, 0x04, - 0x08, 0x23, 0x22, 0xA3, 0xA2, 0x04, 0x28, 0x23, 0x22, 0xA3, 0xAE, 0x04, - 0x02, 0x23, 0x22, 0xA3, 0xC4, 0x04, 0x42, 0x23, 0xF8, 0x88, 0x4A, 0x00, - 0x06, 0x61, 0x00, 0xA0, 0xAE, 0x04, 0x45, 0x23, 0xF8, 0x88, 0x04, 0x98, - 0x00, 0xA2, 0xC0, 0x04, 0xB4, 0x98, 0x00, 0x33, 0x00, 0x82, 0xC0, 0x20, - 0x81, 0x62, 0xE8, 0x81, 0x47, 0x23, 0xF8, 0x88, 0x04, 0x01, 0x0B, 0xDE, - 0x04, 0x98, 0xB4, 0x98, 0x00, 0x33, 0x00, 0x81, 0xC0, 0x20, 0x81, 0x62, - 0x14, 0x01, 0x00, 0xA0, 0x00, 0x02, 0x43, 0x23, 0xF8, 0x88, 0x04, 0x23, - 0xA0, 0x01, 0x44, 0x23, 0xA1, 0x01, 0x80, 0x73, 0x4D, 0x00, 0x03, 0xA3, - 0xF4, 0x04, 0x00, 0x33, 0x27, 0x00, 0xC2, 0x88, 0x04, 0x01, 0x04, 0xDC, - 0x02, 0x23, 0xA2, 0x01, 0x04, 0x23, 0xA0, 0x01, 0x04, 0x98, 0x26, 0x95, - 0x4B, 0x00, 0xF6, 0x00, 0x4F, 0x04, 0x4F, 0x00, 0x00, 0xA3, 0x22, 0x05, - 0x00, 0x05, 0x76, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x1C, 0x05, 0x0A, 0x85, - 0x46, 0x97, 0xCD, 0x04, 0x24, 0x85, 0x48, 0x04, 0x84, 0x80, 0x02, 0x01, - 0x03, 0xDA, 0x80, 0x23, 0x82, 0x01, 0x34, 0x85, 0x02, 0x23, 0xA0, 0x01, - 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x40, 0x05, 0x1D, 0x01, 0x04, 0xD6, - 0xFF, 0x23, 0x86, 0x41, 0x4B, 0x60, 0xCB, 0x00, 0xFF, 0x23, 0x80, 0x01, - 0x49, 0x00, 0x81, 0x01, 0x04, 0x01, 0x02, 0xC8, 0x30, 0x01, 0x80, 0x01, - 0xF7, 0x04, 0x03, 0x01, 0x49, 0x04, 0x80, 0x01, 0xC9, 0x00, 0x00, 0x05, - 0x00, 0x01, 0xFF, 0xA0, 0x60, 0x05, 0x77, 0x04, 0x01, 0x23, 0xEA, 0x00, - 0x5D, 0x00, 0xFE, 0xC7, 0x00, 0x62, 0x00, 0x23, 0xEA, 0x00, 0x00, 0x63, - 0x07, 0xA4, 0xF8, 0x05, 0x03, 0x03, 0x02, 0xA0, 0x8E, 0x05, 0xF4, 0x85, - 0x00, 0x33, 0x2D, 0x00, 0xC2, 0x88, 0x04, 0xA0, 0xB8, 0x05, 0x80, 0x63, - 0x00, 0x23, 0xDF, 0x00, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0xA4, 0x05, - 0x1D, 0x01, 0x06, 0xD6, 0x02, 0x23, 0x02, 0x41, 0x82, 0x01, 0x50, 0x00, - 0x62, 0x97, 0x04, 0x85, 0x04, 0x23, 0x02, 0x41, 0x82, 0x01, 0x04, 0x85, - 0x08, 0xA0, 0xBE, 0x05, 0xF4, 0x85, 0x03, 0xA0, 0xC4, 0x05, 0xF4, 0x85, - 0x01, 0xA0, 0xCE, 0x05, 0x88, 0x00, 0x80, 0x63, 0xCC, 0x86, 0x07, 0xA0, - 0xEE, 0x05, 0x5F, 0x00, 0x00, 0x2B, 0xDF, 0x08, 0x00, 0xA2, 0xE6, 0x05, - 0x80, 0x67, 0x80, 0x63, 0x01, 0xA2, 0x7A, 0x06, 0x7C, 0x85, 0x06, 0x23, - 0x68, 0x98, 0x48, 0x23, 0xF8, 0x88, 0x07, 0x23, 0x80, 0x00, 0x06, 0x87, - 0x80, 0x63, 0x7C, 0x85, 0x00, 0x23, 0xDF, 0x00, 0x00, 0x63, 0x4A, 0x00, - 0x06, 0x61, 0x00, 0xA2, 0x36, 0x06, 0x1D, 0x01, 0x16, 0xD4, 0xC0, 0x23, - 0x07, 0x41, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, 0x1C, 0x06, 0x00, 0x33, - 0x37, 0x00, 0xC2, 0x88, 0x1D, 0x01, 0x01, 0xD6, 0x20, 0x23, 0x63, 0x60, - 0x83, 0x03, 0x80, 0x63, 0x02, 0x23, 0xDF, 0x00, 0x07, 0xA6, 0x7C, 0x05, - 0xEF, 0x04, 0x6F, 0x00, 0x00, 0x63, 0x4B, 0x00, 0x06, 0x41, 0xCB, 0x00, - 0x52, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x4E, 0x06, 0x1D, 0x01, 0x03, 0xCA, - 0xC0, 0x23, 0x07, 0x41, 0x00, 0x63, 0x1D, 0x01, 0x04, 0xCC, 0x00, 0x33, - 0x00, 0x83, 0xC0, 0x20, 0x81, 0x62, 0x80, 0x23, 0x07, 0x41, 0x00, 0x63, - 0x80, 0x67, 0x08, 0x23, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63, 0x01, 0x23, - 0xDF, 0x00, 0x06, 0xA6, 0x84, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x80, 0x67, - 0x80, 0x63, 0x00, 0x33, 0x00, 0x40, 0xC0, 0x20, 0x81, 0x62, 0x00, 0x63, - 0x00, 0x00, 0xFE, 0x95, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, 0x94, 0x06, - 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x00, 0x01, 0xA0, 0x14, 0x07, 0x00, 0x2B, - 0x40, 0x0E, 0x80, 0x63, 0x01, 0x00, 0x06, 0xA6, 0xAA, 0x06, 0x07, 0xA6, - 0x7C, 0x05, 0x40, 0x0E, 0x80, 0x63, 0x00, 0x43, 0x00, 0xA0, 0xA2, 0x06, - 0x06, 0xA6, 0xBC, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x80, 0x67, 0x40, 0x0E, - 0x80, 0x63, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x23, 0xDF, 0x00, 0x00, 0x63, - 0x07, 0xA6, 0xD6, 0x06, 0x00, 0x33, 0x2A, 0x00, 0xC2, 0x88, 0x03, 0x03, - 0x80, 0x63, 0x89, 0x00, 0x0A, 0x2B, 0x07, 0xA6, 0xE8, 0x06, 0x00, 0x33, - 0x29, 0x00, 0xC2, 0x88, 0x00, 0x43, 0x00, 0xA2, 0xF4, 0x06, 0xC0, 0x0E, - 0x80, 0x63, 0xDE, 0x86, 0xC0, 0x0E, 0x00, 0x33, 0x00, 0x80, 0xC0, 0x20, - 0x81, 0x62, 0x04, 0x01, 0x02, 0xDA, 0x80, 0x63, 0x7C, 0x85, 0x80, 0x7B, - 0x80, 0x63, 0x06, 0xA6, 0x8C, 0x06, 0x00, 0x33, 0x2C, 0x00, 0xC2, 0x88, - 0x0C, 0xA2, 0x2E, 0x07, 0xFE, 0x95, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, - 0x2C, 0x07, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x33, 0x3D, 0x00, 0xC2, 0x88, - 0x00, 0x00, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0x0C, 0xA0, 0x44, 0x07, - 0x07, 0xA6, 0x7C, 0x05, 0xBF, 0x23, 0x04, 0x61, 0x84, 0x01, 0xE6, 0x84, - 0x00, 0x63, 0xF0, 0x04, 0x01, 0x01, 0xF1, 0x00, 0x00, 0x01, 0xF2, 0x00, - 0x01, 0x05, 0x80, 0x01, 0x72, 0x04, 0x71, 0x00, 0x81, 0x01, 0x70, 0x04, - 0x80, 0x05, 0x81, 0x05, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, - 0x01, 0x01, 0xF1, 0x00, 0x70, 0x00, 0x81, 0x01, 0x70, 0x04, 0x71, 0x00, - 0x81, 0x01, 0x72, 0x00, 0x80, 0x01, 0x71, 0x04, 0x70, 0x00, 0x80, 0x01, - 0x70, 0x04, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x00, 0x01, - 0xF1, 0x00, 0x70, 0x00, 0x80, 0x01, 0x70, 0x04, 0x71, 0x00, 0x80, 0x01, - 0x72, 0x00, 0x81, 0x01, 0x71, 0x04, 0x70, 0x00, 0x81, 0x01, 0x70, 0x04, - 0x00, 0x63, 0x00, 0x23, 0xB3, 0x01, 0x83, 0x05, 0xA3, 0x01, 0xA2, 0x01, - 0xA1, 0x01, 0x01, 0x23, 0xA0, 0x01, 0x00, 0x01, 0xC8, 0x00, 0x03, 0xA1, - 0xC4, 0x07, 0x00, 0x33, 0x07, 0x00, 0xC2, 0x88, 0x80, 0x05, 0x81, 0x05, - 0x04, 0x01, 0x11, 0xC8, 0x48, 0x00, 0xB0, 0x01, 0xB1, 0x01, 0x08, 0x23, - 0xB2, 0x01, 0x05, 0x01, 0x48, 0x04, 0x00, 0x43, 0x00, 0xA2, 0xE4, 0x07, - 0x00, 0x05, 0xDA, 0x87, 0x00, 0x01, 0xC8, 0x00, 0xFF, 0x23, 0x80, 0x01, - 0x05, 0x05, 0x00, 0x63, 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, - 0x00, 0x02, 0x80, 0x43, 0x76, 0x08, 0x80, 0x02, 0x77, 0x04, 0x00, 0x63, - 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, 0x00, 0x02, 0x00, 0xA0, - 0x14, 0x08, 0x16, 0x88, 0x00, 0x43, 0x76, 0x08, 0x80, 0x02, 0x77, 0x04, - 0x00, 0x63, 0xF3, 0x04, 0x00, 0x23, 0xF4, 0x00, 0x74, 0x00, 0x80, 0x43, - 0xF4, 0x00, 0xCF, 0x40, 0x00, 0xA2, 0x44, 0x08, 0x74, 0x04, 0x02, 0x01, - 0xF7, 0xC9, 0xF6, 0xD9, 0x00, 0x01, 0x01, 0xA1, 0x24, 0x08, 0x04, 0x98, - 0x26, 0x95, 0x24, 0x88, 0x73, 0x04, 0x00, 0x63, 0xF3, 0x04, 0x75, 0x04, - 0x5A, 0x88, 0x02, 0x01, 0x04, 0xD8, 0x46, 0x97, 0x04, 0x98, 0x26, 0x95, - 0x4A, 0x88, 0x75, 0x00, 0x00, 0xA3, 0x64, 0x08, 0x00, 0x05, 0x4E, 0x88, - 0x73, 0x04, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6, 0x76, 0x08, - 0x00, 0x33, 0x3E, 0x00, 0xC2, 0x88, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, - 0x00, 0x63, 0x38, 0x2B, 0x9C, 0x88, 0x38, 0x2B, 0x92, 0x88, 0x32, 0x09, - 0x31, 0x05, 0x92, 0x98, 0x05, 0x05, 0xB2, 0x09, 0x00, 0x63, 0x00, 0x32, - 0x00, 0x36, 0x00, 0x3A, 0x00, 0x3E, 0x00, 0x63, 0x80, 0x32, 0x80, 0x36, - 0x80, 0x3A, 0x80, 0x3E, 0xB4, 0x3D, 0x00, 0x63, 0x38, 0x2B, 0x40, 0x32, - 0x40, 0x36, 0x40, 0x3A, 0x40, 0x3E, 0x00, 0x63, 0x5A, 0x20, 0xC9, 0x40, - 0x00, 0xA0, 0xB4, 0x08, 0x5D, 0x00, 0xFE, 0xC3, 0x00, 0x63, 0x80, 0x73, - 0xE6, 0x20, 0x02, 0x23, 0xE8, 0x00, 0x82, 0x73, 0xFF, 0xFD, 0x80, 0x73, - 0x13, 0x23, 0xF8, 0x88, 0x66, 0x20, 0xC0, 0x20, 0x04, 0x23, 0xA0, 0x01, - 0xA1, 0x23, 0xA1, 0x01, 0x81, 0x62, 0xE2, 0x88, 0x80, 0x73, 0x80, 0x77, - 0x68, 0x00, 0x00, 0xA2, 0x80, 0x00, 0x03, 0xC2, 0xF1, 0xC7, 0x41, 0x23, - 0xF8, 0x88, 0x11, 0x23, 0xA1, 0x01, 0x04, 0x23, 0xA0, 0x01, 0xE6, 0x84, -}; - -static unsigned short _asc_mcode_size = sizeof(_asc_mcode_buf); -static ADV_DCNT _asc_mcode_chksum = 0x012C453FUL; - -/* Microcode buffer is kept after initialization for error recovery. */ -static unsigned char _adv_asc3550_buf[] = { - 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0x16, 0x18, 0xe4, 0x00, 0xfc, - 0x01, 0x00, 0x48, 0xe4, 0xbe, 0x18, 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, - 0x00, 0xfa, 0xff, 0xff, 0x28, 0x0e, 0x9e, 0xe7, 0xff, 0x00, 0x82, 0xe7, - 0x00, 0xea, 0x00, 0xf6, 0x01, 0xe6, 0x09, 0xe7, 0x55, 0xf0, 0x01, 0xf6, - 0x01, 0xfa, 0x08, 0x00, 0x03, 0x00, 0x04, 0x00, 0x18, 0xf4, 0x10, 0x00, - 0x00, 0xec, 0x85, 0xf0, 0xbc, 0x00, 0xd5, 0xf0, 0x8e, 0x0c, 0x38, 0x54, - 0x00, 0xe6, 0x1e, 0xf0, 0x86, 0xf0, 0xb4, 0x00, 0x98, 0x57, 0xd0, 0x01, - 0x0c, 0x1c, 0x3e, 0x1c, 0x0c, 0x00, 0xbb, 0x00, 0xaa, 0x18, 0x02, 0x80, - 0x32, 0xf0, 0x01, 0xfc, 0x88, 0x0c, 0xc6, 0x12, 0x02, 0x13, 0x18, 0x40, - 0x00, 0x57, 0x01, 0xea, 0x3c, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12, - 0x3e, 0x57, 0x00, 0x80, 0x03, 0xe6, 0xb6, 0x00, 0xc0, 0x00, 0x01, 0x01, - 0x3e, 0x01, 0xda, 0x0f, 0x22, 0x10, 0x08, 0x12, 0x02, 0x4a, 0xb9, 0x54, - 0x03, 0x58, 0x1b, 0x80, 0x30, 0xe4, 0x4b, 0xe4, 0x20, 0x00, 0x32, 0x00, - 0x3e, 0x00, 0x80, 0x00, 0x24, 0x01, 0x3c, 0x01, 0x68, 0x01, 0x6a, 0x01, - 0x70, 0x01, 0x72, 0x01, 0x74, 0x01, 0x76, 0x01, 0x78, 0x01, 0x62, 0x0a, - 0x92, 0x0c, 0x2c, 0x10, 0x2e, 0x10, 0x06, 0x13, 0x4c, 0x1c, 0xbb, 0x55, - 0x3c, 0x56, 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, 0xb1, 0xf0, - 0x03, 0xf7, 0x06, 0xf7, 0x03, 0xfc, 0x0f, 0x00, 0x40, 0x00, 0xbe, 0x00, - 0x00, 0x01, 0xb0, 0x08, 0x30, 0x13, 0x64, 0x15, 0x32, 0x1c, 0x38, 0x1c, - 0x4e, 0x1c, 0x10, 0x44, 0x02, 0x48, 0x00, 0x4c, 0x04, 0xea, 0x5d, 0xf0, - 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x34, 0x00, 0x36, 0x00, 0x98, 0x00, - 0xcc, 0x00, 0x20, 0x01, 0x4e, 0x01, 0x4e, 0x0b, 0x1e, 0x0e, 0x0c, 0x10, - 0x0a, 0x12, 0x04, 0x13, 0x40, 0x13, 0x30, 0x1c, 0x00, 0x4e, 0xbd, 0x56, - 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0, 0x59, 0xf0, 0xa7, 0xf0, - 0xb8, 0xf0, 0x0e, 0xf7, 0x06, 0x00, 0x19, 0x00, 0x33, 0x00, 0x9b, 0x00, - 0xa4, 0x00, 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00, 0xe7, 0x00, - 0xde, 0x03, 0x56, 0x0a, 0x14, 0x0e, 0x02, 0x10, 0x04, 0x10, 0x0a, 0x10, - 0x36, 0x10, 0x0a, 0x13, 0x12, 0x13, 0x52, 0x13, 0x10, 0x15, 0x14, 0x15, - 0xac, 0x16, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c, 0x08, 0x44, 0x38, 0x44, - 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, 0x01, 0x48, 0x68, 0x54, 0x83, 0x55, - 0xb0, 0x57, 0x01, 0x58, 0x83, 0x59, 0x05, 0xe6, 0x0b, 0xf0, 0x0c, 0xf0, - 0x5c, 0xf0, 0x4b, 0xf4, 0x04, 0xf8, 0x05, 0xf8, 0x02, 0xfa, 0x03, 0xfa, - 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x1c, 0x00, - 0x9e, 0x00, 0xa8, 0x00, 0xaa, 0x00, 0xb9, 0x00, 0xe0, 0x00, 0x22, 0x01, - 0x26, 0x01, 0x79, 0x01, 0x7a, 0x01, 0xc0, 0x01, 0xc2, 0x01, 0x7c, 0x02, - 0x5a, 0x03, 0xea, 0x04, 0xe8, 0x07, 0x68, 0x08, 0x69, 0x08, 0xba, 0x08, - 0xe9, 0x09, 0x06, 0x0b, 0x3a, 0x0e, 0x00, 0x10, 0x1a, 0x10, 0xed, 0x10, - 0xf1, 0x10, 0x06, 0x12, 0x0c, 0x13, 0x16, 0x13, 0x1e, 0x13, 0x82, 0x13, - 0x42, 0x14, 0xd6, 0x14, 0x8a, 0x15, 0xc6, 0x17, 0xd2, 0x17, 0x6b, 0x18, - 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40, 0x0e, 0x47, 0x48, 0x47, - 0x41, 0x48, 0x89, 0x48, 0x80, 0x4c, 0x00, 0x54, 0x44, 0x55, 0xe5, 0x55, - 0x14, 0x56, 0x77, 0x57, 0xbf, 0x57, 0x40, 0x5c, 0x06, 0x80, 0x08, 0x90, - 0x03, 0xa1, 0xfe, 0x9c, 0xf0, 0x29, 0x02, 0xfe, 0xb8, 0x0c, 0xff, 0x10, - 0x00, 0x00, 0xd0, 0xfe, 0xcc, 0x18, 0x00, 0xcf, 0xfe, 0x80, 0x01, 0xff, - 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00, - 0x00, 0xfe, 0x57, 0x24, 0x00, 0xfe, 0x48, 0x00, 0x4f, 0xff, 0x04, 0x00, - 0x00, 0x10, 0xff, 0x09, 0x00, 0x00, 0xff, 0x08, 0x01, 0x01, 0xff, 0x08, - 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10, 0xff, 0xff, 0xff, 0x0f, - 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00, - 0xfe, 0x04, 0xf7, 0xcf, 0x2a, 0x67, 0x0b, 0x01, 0xfe, 0xce, 0x0e, 0xfe, - 0x04, 0xf7, 0xcf, 0x67, 0x0b, 0x3c, 0x2a, 0xfe, 0x3d, 0xf0, 0xfe, 0x02, - 0x02, 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x91, 0xf0, 0xfe, 0xf0, 0x01, 0xfe, - 0x90, 0xf0, 0xfe, 0xf0, 0x01, 0xfe, 0x8f, 0xf0, 0x9c, 0x05, 0x51, 0x3b, - 0x02, 0xfe, 0xd4, 0x0c, 0x01, 0xfe, 0x44, 0x0d, 0xfe, 0xdd, 0x12, 0xfe, - 0xfc, 0x10, 0xfe, 0x28, 0x1c, 0x05, 0xfe, 0xa6, 0x00, 0xfe, 0xd3, 0x12, - 0x47, 0x18, 0xfe, 0xa6, 0x00, 0xb5, 0xfe, 0x48, 0xf0, 0xfe, 0x86, 0x02, - 0xfe, 0x49, 0xf0, 0xfe, 0xa0, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xbe, 0x02, - 0xfe, 0x46, 0xf0, 0xfe, 0x50, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x56, 0x02, - 0xfe, 0x43, 0xf0, 0xfe, 0x44, 0x02, 0xfe, 0x44, 0xf0, 0xfe, 0x48, 0x02, - 0xfe, 0x45, 0xf0, 0xfe, 0x4c, 0x02, 0x17, 0x0b, 0xa0, 0x17, 0x06, 0x18, - 0x96, 0x02, 0x29, 0xfe, 0x00, 0x1c, 0xde, 0xfe, 0x02, 0x1c, 0xdd, 0xfe, - 0x1e, 0x1c, 0xfe, 0xe9, 0x10, 0x01, 0xfe, 0x20, 0x17, 0xfe, 0xe7, 0x10, - 0xfe, 0x06, 0xfc, 0xc7, 0x0a, 0x6b, 0x01, 0x9e, 0x02, 0x29, 0x14, 0x4d, - 0x37, 0x97, 0x01, 0xfe, 0x64, 0x0f, 0x0a, 0x6b, 0x01, 0x82, 0xfe, 0xbd, - 0x10, 0x0a, 0x6b, 0x01, 0x82, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe, - 0x58, 0x1c, 0x17, 0x06, 0x18, 0x96, 0x2a, 0x25, 0x29, 0xfe, 0x3d, 0xf0, - 0xfe, 0x02, 0x02, 0x21, 0xfe, 0x94, 0x02, 0xfe, 0x5a, 0x1c, 0xea, 0xfe, - 0x14, 0x1c, 0x14, 0xfe, 0x30, 0x00, 0x37, 0x97, 0x01, 0xfe, 0x54, 0x0f, - 0x17, 0x06, 0x18, 0x96, 0x02, 0xd0, 0x1e, 0x20, 0x07, 0x10, 0x34, 0xfe, - 0x69, 0x10, 0x17, 0x06, 0x18, 0x96, 0xfe, 0x04, 0xec, 0x20, 0x46, 0x3d, - 0x12, 0x20, 0xfe, 0x05, 0xf6, 0xc7, 0x01, 0xfe, 0x52, 0x16, 0x09, 0x4a, - 0x4c, 0x35, 0x11, 0x2d, 0x3c, 0x8a, 0x01, 0xe6, 0x02, 0x29, 0x0a, 0x40, - 0x01, 0x0e, 0x07, 0x00, 0x5d, 0x01, 0x6f, 0xfe, 0x18, 0x10, 0xfe, 0x41, - 0x58, 0x0a, 0x99, 0x01, 0x0e, 0xfe, 0xc8, 0x54, 0x64, 0xfe, 0x0c, 0x03, - 0x01, 0xe6, 0x02, 0x29, 0x2a, 0x46, 0xfe, 0x02, 0xe8, 0x27, 0xf8, 0xfe, - 0x9e, 0x43, 0xf7, 0xfe, 0x27, 0xf0, 0xfe, 0xdc, 0x01, 0xfe, 0x07, 0x4b, - 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x40, 0x1c, 0x25, 0xd2, 0xfe, 0x26, 0xf0, - 0xfe, 0x56, 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x44, 0x03, 0xfe, 0x11, 0xf0, - 0x9c, 0xfe, 0xef, 0x10, 0xfe, 0x9f, 0xf0, 0xfe, 0x64, 0x03, 0xeb, 0x0f, - 0xfe, 0x11, 0x00, 0x02, 0x5a, 0x2a, 0xfe, 0x48, 0x1c, 0xeb, 0x09, 0x04, - 0x1d, 0xfe, 0x18, 0x13, 0x23, 0x1e, 0x98, 0xac, 0x12, 0x98, 0x0a, 0x40, - 0x01, 0x0e, 0xac, 0x75, 0x01, 0xfe, 0xbc, 0x15, 0x11, 0xca, 0x25, 0xd2, - 0xfe, 0x01, 0xf0, 0xd2, 0xfe, 0x82, 0xf0, 0xfe, 0x92, 0x03, 0xec, 0x11, - 0xfe, 0xe4, 0x00, 0x65, 0xfe, 0xa4, 0x03, 0x25, 0x32, 0x1f, 0xfe, 0xb4, - 0x03, 0x01, 0x43, 0xfe, 0x06, 0xf0, 0xfe, 0xc4, 0x03, 0x8d, 0x81, 0xfe, - 0x0a, 0xf0, 0xfe, 0x7a, 0x06, 0x02, 0x22, 0x05, 0x6b, 0x28, 0x16, 0xfe, - 0xf6, 0x04, 0x14, 0x2c, 0x01, 0x33, 0x8f, 0xfe, 0x66, 0x02, 0x02, 0xd1, - 0xeb, 0x2a, 0x67, 0x1a, 0xfe, 0x67, 0x1b, 0xf8, 0xf7, 0xfe, 0x48, 0x1c, - 0x70, 0x01, 0x6e, 0x87, 0x0a, 0x40, 0x01, 0x0e, 0x07, 0x00, 0x16, 0xd3, - 0x0a, 0xca, 0x01, 0x0e, 0x74, 0x60, 0x59, 0x76, 0x27, 0x05, 0x6b, 0x28, - 0xfe, 0x10, 0x12, 0x14, 0x2c, 0x01, 0x33, 0x8f, 0xfe, 0x66, 0x02, 0x02, - 0xd1, 0xbc, 0x7d, 0xbd, 0x7f, 0x25, 0x22, 0x65, 0xfe, 0x3c, 0x04, 0x1f, - 0xfe, 0x38, 0x04, 0x68, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e, - 0x12, 0x2b, 0xff, 0x02, 0x00, 0x10, 0x01, 0x08, 0x1f, 0xfe, 0xe0, 0x04, - 0x2b, 0x01, 0x08, 0x1f, 0x22, 0x30, 0x2e, 0xd5, 0xfe, 0x4c, 0x44, 0xfe, - 0x4c, 0x12, 0x60, 0xfe, 0x44, 0x48, 0x13, 0x2c, 0xfe, 0x4c, 0x54, 0x64, - 0xd3, 0x46, 0x76, 0x27, 0xfa, 0xef, 0xfe, 0x62, 0x13, 0x09, 0x04, 0x1d, - 0xfe, 0x2a, 0x13, 0x2f, 0x07, 0x7e, 0xa5, 0xfe, 0x20, 0x10, 0x13, 0x2c, - 0xfe, 0x4c, 0x54, 0x64, 0xd3, 0xfa, 0xef, 0x86, 0x09, 0x04, 0x1d, 0xfe, - 0x08, 0x13, 0x2f, 0x07, 0x7e, 0x6e, 0x09, 0x04, 0x1d, 0xfe, 0x1c, 0x12, - 0x14, 0x92, 0x09, 0x04, 0x06, 0x3b, 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe, - 0x70, 0x0c, 0x02, 0x22, 0x2b, 0x11, 0xfe, 0xe6, 0x00, 0xfe, 0x1c, 0x90, - 0xf9, 0x03, 0x14, 0x92, 0x01, 0x33, 0x02, 0x29, 0xfe, 0x42, 0x5b, 0x67, - 0x1a, 0xfe, 0x46, 0x59, 0xf8, 0xf7, 0xfe, 0x87, 0x80, 0xfe, 0x31, 0xe4, - 0x4f, 0x09, 0x04, 0x0b, 0xfe, 0x78, 0x13, 0xfe, 0x20, 0x80, 0x07, 0x1a, - 0xfe, 0x70, 0x12, 0x49, 0x04, 0x06, 0xfe, 0x60, 0x13, 0x05, 0xfe, 0xa2, - 0x00, 0x28, 0x16, 0xfe, 0x80, 0x05, 0xfe, 0x31, 0xe4, 0x6a, 0x49, 0x04, - 0x0b, 0xfe, 0x4a, 0x13, 0x05, 0xfe, 0xa0, 0x00, 0x28, 0xfe, 0x42, 0x12, - 0x5e, 0x01, 0x08, 0x25, 0x32, 0xf1, 0x01, 0x08, 0x26, 0xfe, 0x98, 0x05, - 0x11, 0xfe, 0xe3, 0x00, 0x23, 0x49, 0xfe, 0x4a, 0xf0, 0xfe, 0x6a, 0x05, - 0xfe, 0x49, 0xf0, 0xfe, 0x64, 0x05, 0x83, 0x24, 0xfe, 0x21, 0x00, 0xa1, - 0x24, 0xfe, 0x22, 0x00, 0xa0, 0x24, 0x4c, 0xfe, 0x09, 0x48, 0x01, 0x08, - 0x26, 0xfe, 0x98, 0x05, 0xfe, 0xe2, 0x08, 0x49, 0x04, 0xc5, 0x3b, 0x01, - 0x86, 0x24, 0x06, 0x12, 0xcc, 0x37, 0xfe, 0x27, 0x01, 0x09, 0x04, 0x1d, - 0xfe, 0x22, 0x12, 0x47, 0x01, 0xa7, 0x14, 0x92, 0x09, 0x04, 0x06, 0x3b, - 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe, 0x70, 0x0c, 0x02, 0x22, 0x05, 0xfe, - 0x9c, 0x00, 0x28, 0xfe, 0x3e, 0x12, 0x05, 0x50, 0x28, 0xfe, 0x36, 0x13, - 0x47, 0x01, 0xa7, 0x26, 0xfe, 0x08, 0x06, 0x0a, 0x06, 0x49, 0x04, 0x19, - 0xfe, 0x02, 0x12, 0x5f, 0x01, 0xfe, 0xaa, 0x14, 0x1f, 0xfe, 0xfe, 0x05, - 0x11, 0x9a, 0x01, 0x43, 0x11, 0xfe, 0xe5, 0x00, 0x05, 0x50, 0xb4, 0x0c, - 0x50, 0x05, 0xc6, 0x28, 0xfe, 0x62, 0x12, 0x05, 0x3f, 0x28, 0xfe, 0x5a, - 0x13, 0x01, 0xfe, 0x14, 0x18, 0x01, 0xfe, 0x66, 0x18, 0xfe, 0x43, 0x48, - 0xb7, 0x19, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0x1c, 0x3d, - 0x85, 0xb7, 0x69, 0x47, 0x01, 0xa7, 0x26, 0xfe, 0x72, 0x06, 0x49, 0x04, - 0x1b, 0xdf, 0x89, 0x0a, 0x4d, 0x01, 0xfe, 0xd8, 0x14, 0x1f, 0xfe, 0x68, - 0x06, 0x11, 0x9a, 0x01, 0x43, 0x11, 0xfe, 0xe5, 0x00, 0x05, 0x3f, 0xb4, - 0x0c, 0x3f, 0x17, 0x06, 0x01, 0xa7, 0xec, 0x72, 0x70, 0x01, 0x6e, 0x87, - 0x11, 0xfe, 0xe2, 0x00, 0x01, 0x08, 0x25, 0x32, 0xfe, 0x0a, 0xf0, 0xfe, - 0xa6, 0x06, 0x8c, 0xfe, 0x5c, 0x07, 0xfe, 0x06, 0xf0, 0xfe, 0x64, 0x07, - 0x8d, 0x81, 0x02, 0x22, 0x09, 0x04, 0x0b, 0xfe, 0x2e, 0x12, 0x15, 0x1a, - 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, - 0x01, 0x08, 0xfe, 0x99, 0xa4, 0x01, 0x08, 0x15, 0x00, 0x02, 0xfe, 0x32, - 0x08, 0x61, 0x04, 0x1b, 0xfe, 0x38, 0x12, 0x09, 0x04, 0x1b, 0x6e, 0x15, - 0xfe, 0x1b, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01, - 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x06, 0x01, 0x08, 0x15, 0x00, 0x02, - 0xd9, 0x66, 0x4c, 0xfe, 0x3a, 0x55, 0x5f, 0xfe, 0x9a, 0x81, 0x4b, 0x1d, - 0xba, 0xfe, 0x32, 0x07, 0x0a, 0x1d, 0xfe, 0x09, 0x6f, 0xaf, 0xfe, 0xca, - 0x45, 0xfe, 0x32, 0x12, 0x62, 0x2c, 0x85, 0x66, 0x7b, 0x01, 0x08, 0x25, - 0x32, 0xfe, 0x0a, 0xf0, 0xfe, 0x32, 0x07, 0x8d, 0x81, 0x8c, 0xfe, 0x5c, - 0x07, 0x02, 0x22, 0x01, 0x43, 0x02, 0xfe, 0x8a, 0x06, 0x15, 0x19, 0x02, - 0xfe, 0x8a, 0x06, 0xfe, 0x9c, 0xf7, 0xd4, 0xfe, 0x2c, 0x90, 0xfe, 0xae, - 0x90, 0x77, 0xfe, 0xca, 0x07, 0x0c, 0x54, 0x18, 0x55, 0x09, 0x4a, 0x6a, - 0x35, 0x1e, 0x20, 0x07, 0x10, 0xfe, 0x0e, 0x12, 0x74, 0xfe, 0x80, 0x80, - 0x37, 0x20, 0x63, 0x27, 0xfe, 0x06, 0x10, 0xfe, 0x83, 0xe7, 0xc4, 0xa1, - 0xfe, 0x03, 0x40, 0x09, 0x4a, 0x4f, 0x35, 0x01, 0xa8, 0xad, 0xfe, 0x1f, - 0x40, 0x12, 0x58, 0x01, 0xa5, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe, - 0x44, 0x51, 0xfe, 0xc6, 0x51, 0x83, 0xfb, 0xfe, 0x8a, 0x90, 0x0c, 0x52, - 0x18, 0x53, 0xfe, 0x0c, 0x90, 0xfe, 0x8e, 0x90, 0xfe, 0x40, 0x50, 0xfe, - 0xc2, 0x50, 0x0c, 0x39, 0x18, 0x3a, 0xfe, 0x4a, 0x10, 0x09, 0x04, 0x6a, - 0xfe, 0x2a, 0x12, 0xfe, 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x0c, 0x54, 0x18, - 0x55, 0x09, 0x04, 0x4f, 0x85, 0x01, 0xa8, 0xfe, 0x1f, 0x80, 0x12, 0x58, - 0xfe, 0x44, 0x90, 0xfe, 0xc6, 0x90, 0x0c, 0x56, 0x18, 0x57, 0xfb, 0xfe, - 0x8a, 0x90, 0x0c, 0x52, 0x18, 0x53, 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90, - 0x0c, 0x39, 0x18, 0x3a, 0x0c, 0x38, 0x18, 0x4e, 0x09, 0x4a, 0x19, 0x35, - 0x2a, 0x13, 0xfe, 0x4e, 0x11, 0x65, 0xfe, 0x48, 0x08, 0xfe, 0x9e, 0xf0, - 0xfe, 0x5c, 0x08, 0xb1, 0x16, 0x32, 0x2a, 0x73, 0xdd, 0xb8, 0xfe, 0x80, - 0x08, 0xb9, 0xfe, 0x9e, 0x08, 0x8c, 0xfe, 0x74, 0x08, 0xfe, 0x06, 0xf0, - 0xfe, 0x7a, 0x08, 0x8d, 0x81, 0x02, 0x22, 0x01, 0x43, 0xfe, 0xc9, 0x10, - 0x15, 0x19, 0xfe, 0xc9, 0x10, 0x61, 0x04, 0x06, 0xfe, 0x10, 0x12, 0x61, - 0x04, 0x0b, 0x45, 0x09, 0x04, 0x0b, 0xfe, 0x68, 0x12, 0xfe, 0x2e, 0x1c, - 0x02, 0xfe, 0x24, 0x0a, 0x61, 0x04, 0x06, 0x45, 0x61, 0x04, 0x0b, 0xfe, - 0x52, 0x12, 0xfe, 0x2c, 0x1c, 0xfe, 0xaa, 0xf0, 0xfe, 0x1e, 0x09, 0xfe, - 0xac, 0xf0, 0xfe, 0xbe, 0x08, 0xfe, 0x8a, 0x10, 0xaa, 0xfe, 0xf3, 0x10, - 0xfe, 0xad, 0xf0, 0xfe, 0xca, 0x08, 0x02, 0xfe, 0x24, 0x0a, 0xab, 0xfe, - 0xe7, 0x10, 0xfe, 0x2b, 0xf0, 0x9d, 0xe9, 0x1c, 0xfe, 0x00, 0xfe, 0xfe, - 0x1c, 0x12, 0xb5, 0xfe, 0xd2, 0xf0, 0x9d, 0xfe, 0x76, 0x18, 0x1c, 0x1a, - 0x16, 0x9d, 0x05, 0xcb, 0x1c, 0x06, 0x16, 0x9d, 0xb8, 0x6d, 0xb9, 0x6d, - 0xaa, 0xab, 0xfe, 0xb1, 0x10, 0x70, 0x5e, 0x2b, 0x14, 0x92, 0x01, 0x33, - 0x0f, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x5a, 0x0f, 0x7c, 0x02, 0x5a, - 0xfe, 0x74, 0x18, 0x1c, 0xfe, 0x00, 0xf8, 0x16, 0x6d, 0x67, 0x1b, 0x01, - 0xfe, 0x44, 0x0d, 0x3b, 0x01, 0xe6, 0x1e, 0x27, 0x74, 0x67, 0x1a, 0x02, - 0x6d, 0x09, 0x04, 0x0b, 0x21, 0xfe, 0x06, 0x0a, 0x09, 0x04, 0x6a, 0xfe, - 0x82, 0x12, 0x09, 0x04, 0x19, 0xfe, 0x66, 0x13, 0x1e, 0x58, 0xac, 0xfc, - 0xfe, 0x83, 0x80, 0xfe, 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91, - 0xfe, 0x86, 0x91, 0x63, 0x27, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x77, - 0xd7, 0x05, 0x54, 0x31, 0x55, 0x0c, 0x7b, 0x18, 0x7c, 0xbe, 0x54, 0xbf, - 0x55, 0x01, 0xa8, 0xad, 0x63, 0x27, 0x12, 0x58, 0xc0, 0x38, 0xc1, 0x4e, - 0x79, 0x56, 0x68, 0x57, 0xf4, 0xf5, 0xfe, 0x04, 0xfa, 0x38, 0xfe, 0x05, - 0xfa, 0x4e, 0x01, 0xa5, 0xa2, 0x23, 0x0c, 0x7b, 0x0c, 0x7c, 0x79, 0x56, - 0x68, 0x57, 0xfe, 0x12, 0x10, 0x09, 0x04, 0x19, 0x16, 0xd7, 0x79, 0x39, - 0x68, 0x3a, 0x09, 0x04, 0xfe, 0xf7, 0x00, 0x35, 0x05, 0x52, 0x31, 0x53, - 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, - 0x02, 0x6d, 0x09, 0x04, 0x19, 0x16, 0xd7, 0x09, 0x04, 0xfe, 0xf7, 0x00, - 0x35, 0xfe, 0x3a, 0x55, 0xfe, 0x19, 0x81, 0x5f, 0xfe, 0x10, 0x90, 0xfe, - 0x92, 0x90, 0xfe, 0xd7, 0x10, 0x2f, 0x07, 0x9b, 0x16, 0xfe, 0xc6, 0x08, - 0x11, 0x9b, 0x09, 0x04, 0x0b, 0xfe, 0x14, 0x13, 0x05, 0x39, 0x31, 0x3a, - 0x77, 0xfe, 0xc6, 0x08, 0xfe, 0x0c, 0x58, 0xfe, 0x8d, 0x58, 0x02, 0x6d, - 0x23, 0x47, 0xfe, 0x19, 0x80, 0xde, 0x09, 0x04, 0x0b, 0xfe, 0x1a, 0x12, - 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xe9, 0xb5, 0xfe, 0xd1, 0xf0, 0xd9, - 0x14, 0x7a, 0x01, 0x33, 0x0f, 0xfe, 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, - 0x6c, 0x19, 0xbe, 0x39, 0xfe, 0xed, 0x19, 0xbf, 0x3a, 0xfe, 0x0c, 0x51, - 0xfe, 0x8e, 0x51, 0xe9, 0x1c, 0xfe, 0x00, 0xff, 0x34, 0xfe, 0x74, 0x10, - 0xb5, 0xfe, 0xd2, 0xf0, 0xfe, 0xb2, 0x0a, 0xfe, 0x76, 0x18, 0x1c, 0x1a, - 0x84, 0x05, 0xcb, 0x1c, 0x06, 0xfe, 0x08, 0x13, 0x0f, 0xfe, 0x16, 0x00, - 0x02, 0x5a, 0xfe, 0xd1, 0xf0, 0xfe, 0xc4, 0x0a, 0x14, 0x7a, 0x01, 0x33, - 0x0f, 0xfe, 0x17, 0x00, 0xfe, 0x42, 0x10, 0xfe, 0xce, 0xf0, 0xfe, 0xca, - 0x0a, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xd6, 0x0a, 0x0f, 0xfe, - 0x22, 0x00, 0x02, 0x5a, 0xfe, 0xcb, 0xf0, 0xfe, 0xe2, 0x0a, 0x0f, 0xfe, - 0x24, 0x00, 0x02, 0x5a, 0xfe, 0xd0, 0xf0, 0xfe, 0xec, 0x0a, 0x0f, 0x93, - 0xdc, 0xfe, 0xcf, 0xf0, 0xfe, 0xf6, 0x0a, 0x0f, 0x4c, 0xfe, 0x10, 0x10, - 0xfe, 0xcc, 0xf0, 0xd9, 0x61, 0x04, 0x19, 0x3b, 0x0f, 0xfe, 0x12, 0x00, - 0x2a, 0x13, 0xfe, 0x4e, 0x11, 0x65, 0xfe, 0x0c, 0x0b, 0xfe, 0x9e, 0xf0, - 0xfe, 0x20, 0x0b, 0xb1, 0x16, 0x32, 0x2a, 0x73, 0xdd, 0xb8, 0x22, 0xb9, - 0x22, 0x2a, 0xec, 0x65, 0xfe, 0x2c, 0x0b, 0x25, 0x32, 0x8c, 0xfe, 0x48, - 0x0b, 0x8d, 0x81, 0xb8, 0xd4, 0xb9, 0xd4, 0x02, 0x22, 0x01, 0x43, 0xfe, - 0xdb, 0x10, 0x11, 0xfe, 0xe8, 0x00, 0xaa, 0xab, 0x70, 0xbc, 0x7d, 0xbd, - 0x7f, 0xfe, 0x89, 0xf0, 0x22, 0x30, 0x2e, 0xd8, 0xbc, 0x7d, 0xbd, 0x7f, - 0x01, 0x08, 0x1f, 0x22, 0x30, 0x2e, 0xd6, 0xb1, 0x45, 0x0f, 0xfe, 0x42, - 0x00, 0x02, 0x5a, 0x78, 0x06, 0xfe, 0x81, 0x49, 0x16, 0xfe, 0x38, 0x0c, - 0x09, 0x04, 0x0b, 0xfe, 0x44, 0x13, 0x0f, 0x00, 0x4b, 0x0b, 0xfe, 0x54, - 0x12, 0x4b, 0xfe, 0x28, 0x00, 0x21, 0xfe, 0xa6, 0x0c, 0x0a, 0x40, 0x01, - 0x0e, 0x07, 0x00, 0x5d, 0x3e, 0xfe, 0x28, 0x00, 0xfe, 0xe2, 0x10, 0x01, - 0xe7, 0x01, 0xe8, 0x0a, 0x99, 0x01, 0xfe, 0x32, 0x0e, 0x59, 0x11, 0x2d, - 0x01, 0x6f, 0x02, 0x29, 0x0f, 0xfe, 0x44, 0x00, 0x4b, 0x0b, 0xdf, 0x3e, - 0x0b, 0xfe, 0xb4, 0x10, 0x01, 0x86, 0x3e, 0x0b, 0xfe, 0xaa, 0x10, 0x01, - 0x86, 0xfe, 0x19, 0x82, 0xfe, 0x34, 0x46, 0xa3, 0x3e, 0x0b, 0x0f, 0xfe, - 0x43, 0x00, 0xfe, 0x96, 0x10, 0x09, 0x4a, 0x0b, 0x35, 0x01, 0xe7, 0x01, - 0xe8, 0x59, 0x11, 0x2d, 0x01, 0x6f, 0x67, 0x0b, 0x59, 0x3c, 0x8a, 0x02, - 0xfe, 0x2a, 0x03, 0x09, 0x04, 0x0b, 0x84, 0x3e, 0x0b, 0x0f, 0x00, 0xfe, - 0x5c, 0x10, 0x61, 0x04, 0x1b, 0xfe, 0x58, 0x12, 0x09, 0x04, 0x1b, 0xfe, - 0x50, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x5c, 0x0c, 0xfe, - 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x62, 0x0c, 0x09, 0x4a, 0x1b, 0x35, - 0xfe, 0xa9, 0x10, 0x0f, 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0b, 0x5f, - 0x5c, 0x0f, 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10, 0x0f, 0xfe, 0x47, 0x00, - 0xa1, 0x0f, 0xfe, 0x41, 0x00, 0xa0, 0x0f, 0xfe, 0x24, 0x00, 0x87, 0xaa, - 0xab, 0x70, 0x05, 0x6b, 0x28, 0x21, 0xd1, 0x5f, 0xfe, 0x04, 0xe6, 0x1b, - 0xfe, 0x9d, 0x41, 0xfe, 0x1c, 0x42, 0x59, 0x01, 0xda, 0x02, 0x29, 0xea, - 0x14, 0x0b, 0x37, 0x95, 0xa9, 0x14, 0xfe, 0x31, 0x00, 0x37, 0x97, 0x01, - 0xfe, 0x54, 0x0f, 0x02, 0xd0, 0x3c, 0xfe, 0x06, 0xec, 0xc9, 0xee, 0x3e, - 0x1d, 0xfe, 0xce, 0x45, 0x34, 0x3c, 0xfe, 0x06, 0xea, 0xc9, 0xfe, 0x47, - 0x4b, 0x89, 0xfe, 0x75, 0x57, 0x05, 0x51, 0xfe, 0x98, 0x56, 0xfe, 0x38, - 0x12, 0x0a, 0x42, 0x01, 0x0e, 0xfe, 0x44, 0x48, 0x46, 0x09, 0x04, 0x1d, - 0xfe, 0x1a, 0x13, 0x0a, 0x40, 0x01, 0x0e, 0x47, 0xfe, 0x41, 0x58, 0x0a, - 0x99, 0x01, 0x0e, 0xfe, 0x49, 0x54, 0x8e, 0xfe, 0x2a, 0x0d, 0x02, 0xfe, - 0x2a, 0x03, 0x0a, 0x51, 0xfe, 0xee, 0x14, 0xee, 0x3e, 0x1d, 0xfe, 0xce, - 0x45, 0x34, 0x3c, 0xfe, 0xce, 0x47, 0xfe, 0xad, 0x13, 0x02, 0x29, 0x1e, - 0x20, 0x07, 0x10, 0xfe, 0x9e, 0x12, 0x23, 0x12, 0x4d, 0x12, 0x94, 0x12, - 0xce, 0x1e, 0x2d, 0x47, 0x37, 0x2d, 0xb1, 0xe0, 0xfe, 0xbc, 0xf0, 0xfe, - 0xec, 0x0d, 0x13, 0x06, 0x12, 0x4d, 0x01, 0xfe, 0xe2, 0x15, 0x05, 0xfe, - 0x38, 0x01, 0x31, 0xfe, 0x3a, 0x01, 0x77, 0xfe, 0xf0, 0x0d, 0xfe, 0x02, - 0xec, 0xce, 0x62, 0x00, 0x5d, 0xfe, 0x04, 0xec, 0x20, 0x46, 0xfe, 0x05, - 0xf6, 0xfe, 0x34, 0x01, 0x01, 0xfe, 0x52, 0x16, 0xfb, 0xfe, 0x48, 0xf4, - 0x0d, 0xfe, 0x18, 0x13, 0xaf, 0xfe, 0x02, 0xea, 0xce, 0x62, 0x7a, 0xfe, - 0xc5, 0x13, 0x14, 0x1b, 0x37, 0x95, 0xa9, 0x5c, 0x05, 0xfe, 0x38, 0x01, - 0x1c, 0xfe, 0xf0, 0xff, 0x0c, 0xfe, 0x60, 0x01, 0x05, 0xfe, 0x3a, 0x01, - 0x0c, 0xfe, 0x62, 0x01, 0x3d, 0x12, 0x20, 0x24, 0x06, 0x12, 0x2d, 0x11, - 0x2d, 0x8a, 0x13, 0x06, 0x03, 0x23, 0x03, 0x1e, 0x4d, 0xfe, 0xf7, 0x12, - 0x1e, 0x94, 0xac, 0x12, 0x94, 0x07, 0x7a, 0xfe, 0x71, 0x13, 0xfe, 0x24, - 0x1c, 0x14, 0x1a, 0x37, 0x95, 0xa9, 0xfe, 0xd9, 0x10, 0xb6, 0xfe, 0x03, - 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x03, 0xb6, 0xfe, 0x03, 0xdc, - 0xfe, 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x03, 0xfe, 0x03, 0x57, 0xb6, 0x23, - 0xfe, 0x00, 0xcc, 0x03, 0xfe, 0x03, 0x57, 0xb6, 0x75, 0x03, 0x09, 0x04, - 0x4c, 0xfe, 0x22, 0x13, 0xfe, 0x1c, 0x80, 0x07, 0x06, 0xfe, 0x1a, 0x13, - 0xfe, 0x1e, 0x80, 0xe1, 0xfe, 0x1d, 0x80, 0xa4, 0xfe, 0x0c, 0x90, 0xfe, - 0x0e, 0x13, 0xfe, 0x0e, 0x90, 0xa3, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4, - 0x0b, 0xfe, 0x3c, 0x50, 0xa0, 0x01, 0xfe, 0x82, 0x16, 0x2f, 0x07, 0x2d, - 0xe0, 0x01, 0xfe, 0xbc, 0x15, 0x09, 0x04, 0x1d, 0x45, 0x01, 0xe7, 0x01, - 0xe8, 0x11, 0xfe, 0xe9, 0x00, 0x09, 0x04, 0x4c, 0xfe, 0x2c, 0x13, 0x01, - 0xfe, 0x14, 0x16, 0xfe, 0x1e, 0x1c, 0xfe, 0x14, 0x90, 0xfe, 0x96, 0x90, - 0x0c, 0xfe, 0x64, 0x01, 0x18, 0xfe, 0x66, 0x01, 0x09, 0x04, 0x4f, 0xfe, - 0x12, 0x12, 0xfe, 0x03, 0x80, 0x74, 0xfe, 0x01, 0xec, 0x20, 0xfe, 0x80, - 0x40, 0x12, 0x20, 0x63, 0x27, 0x11, 0xc8, 0x59, 0x1e, 0x20, 0xed, 0x76, - 0x20, 0x03, 0xfe, 0x08, 0x1c, 0x05, 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58, - 0x05, 0xfe, 0xae, 0x00, 0xfe, 0x07, 0x58, 0x05, 0xfe, 0xb0, 0x00, 0xfe, - 0x08, 0x58, 0x05, 0xfe, 0xb2, 0x00, 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c, - 0x24, 0x69, 0x12, 0xc9, 0x23, 0x0c, 0x50, 0x0c, 0x3f, 0x13, 0x40, 0x48, - 0x5f, 0x17, 0x1d, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x21, 0xfe, 0x08, - 0x0f, 0x3e, 0x10, 0x13, 0x42, 0x48, 0x17, 0x4c, 0xfe, 0x90, 0x4d, 0xfe, - 0x91, 0x54, 0x21, 0xfe, 0x1e, 0x0f, 0x24, 0x10, 0x12, 0x20, 0x78, 0x2c, - 0x46, 0x1e, 0x20, 0xed, 0x76, 0x20, 0x11, 0xc8, 0xf6, 0xfe, 0xd6, 0xf0, - 0xfe, 0x32, 0x0f, 0xea, 0x70, 0xfe, 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe, - 0x18, 0x1c, 0x03, 0x3c, 0xfe, 0x0c, 0x14, 0xee, 0xfe, 0x07, 0xe6, 0x1d, - 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x03, 0x01, 0x86, 0x78, 0x2c, 0x46, - 0xfa, 0xef, 0xfe, 0x42, 0x13, 0x2f, 0x07, 0x2d, 0xfe, 0x34, 0x13, 0x0a, - 0x42, 0x01, 0x0e, 0xb0, 0xfe, 0x36, 0x12, 0xf0, 0xfe, 0x45, 0x48, 0x01, - 0xe3, 0xfe, 0x00, 0xcc, 0xb0, 0xfe, 0xf3, 0x13, 0x3d, 0x75, 0x07, 0x10, - 0xa3, 0x0a, 0x80, 0x01, 0x0e, 0xfe, 0x80, 0x5c, 0x01, 0x6f, 0xfe, 0x0e, - 0x10, 0x07, 0x7e, 0x45, 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x6c, 0x0f, 0x03, - 0xfe, 0x44, 0x58, 0x74, 0xfe, 0x01, 0xec, 0x97, 0xfe, 0x9e, 0x40, 0xfe, - 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1b, 0x76, 0x27, 0x01, 0xda, 0xfe, - 0xdd, 0x10, 0x2a, 0xbc, 0x7d, 0xbd, 0x7f, 0x30, 0x2e, 0xd5, 0x07, 0x1b, - 0xfe, 0x48, 0x12, 0x07, 0x0b, 0xfe, 0x56, 0x12, 0x07, 0x1a, 0xfe, 0x30, - 0x12, 0x07, 0xc2, 0x16, 0xfe, 0x3e, 0x11, 0x07, 0xfe, 0x23, 0x00, 0x16, - 0xfe, 0x4a, 0x11, 0x07, 0x06, 0x16, 0xfe, 0xa8, 0x11, 0x07, 0x19, 0xfe, - 0x12, 0x12, 0x07, 0x00, 0x16, 0x22, 0x14, 0xc2, 0x01, 0x33, 0x9f, 0x2b, - 0x01, 0x08, 0x8c, 0x43, 0x03, 0x2b, 0xfe, 0x62, 0x08, 0x0a, 0xca, 0x01, - 0xfe, 0x32, 0x0e, 0x11, 0x7e, 0x02, 0x29, 0x2b, 0x2f, 0x07, 0x9b, 0xfe, - 0xd9, 0x13, 0x79, 0x39, 0x68, 0x3a, 0x77, 0xfe, 0xfc, 0x10, 0x09, 0x04, - 0x6a, 0xfe, 0x72, 0x12, 0xc0, 0x38, 0xc1, 0x4e, 0xf4, 0xf5, 0x8e, 0xfe, - 0xc6, 0x10, 0x1e, 0x58, 0xfe, 0x26, 0x13, 0x05, 0x7b, 0x31, 0x7c, 0x77, - 0xfe, 0x82, 0x0c, 0x0c, 0x54, 0x18, 0x55, 0x23, 0x0c, 0x7b, 0x0c, 0x7c, - 0x01, 0xa8, 0x24, 0x69, 0x73, 0x12, 0x58, 0x01, 0xa5, 0xc0, 0x38, 0xc1, - 0x4e, 0xfe, 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x38, 0xfe, - 0x05, 0xfa, 0x4e, 0xfe, 0x91, 0x10, 0x05, 0x56, 0x31, 0x57, 0xfe, 0x40, - 0x56, 0xfe, 0xe1, 0x56, 0x0c, 0x56, 0x18, 0x57, 0x83, 0xc0, 0x38, 0xc1, - 0x4e, 0xf4, 0xf5, 0x05, 0x52, 0x31, 0x53, 0xfe, 0x00, 0x56, 0xfe, 0xa1, - 0x56, 0x0c, 0x52, 0x18, 0x53, 0x09, 0x04, 0x6a, 0xfe, 0x1e, 0x12, 0x1e, - 0x58, 0xfe, 0x1f, 0x40, 0x05, 0x54, 0x31, 0x55, 0xfe, 0x2c, 0x50, 0xfe, - 0xae, 0x50, 0x05, 0x56, 0x31, 0x57, 0xfe, 0x44, 0x50, 0xfe, 0xc6, 0x50, - 0x05, 0x52, 0x31, 0x53, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x05, 0x39, - 0x31, 0x3a, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x02, 0x5c, 0x24, 0x06, - 0x12, 0xcd, 0x02, 0x5b, 0x2b, 0x01, 0x08, 0x1f, 0x44, 0x30, 0x2e, 0xd5, - 0x07, 0x06, 0x21, 0x44, 0x2f, 0x07, 0x9b, 0x21, 0x5b, 0x01, 0x6e, 0x1c, - 0x3d, 0x16, 0x44, 0x09, 0x04, 0x0b, 0xe2, 0x79, 0x39, 0x68, 0x3a, 0xfe, - 0x0a, 0x55, 0x34, 0xfe, 0x8b, 0x55, 0xbe, 0x39, 0xbf, 0x3a, 0xfe, 0x0c, - 0x51, 0xfe, 0x8e, 0x51, 0x02, 0x5b, 0xfe, 0x19, 0x81, 0xaf, 0xfe, 0x19, - 0x41, 0x02, 0x5b, 0x2b, 0x01, 0x08, 0x25, 0x32, 0x1f, 0xa2, 0x30, 0x2e, - 0xd8, 0x4b, 0x1a, 0xfe, 0xa6, 0x12, 0x4b, 0x0b, 0x3b, 0x02, 0x44, 0x01, - 0x08, 0x25, 0x32, 0x1f, 0xa2, 0x30, 0x2e, 0xd6, 0x07, 0x1a, 0x21, 0x44, - 0x01, 0x08, 0x1f, 0xa2, 0x30, 0x2e, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, - 0x60, 0x05, 0xfe, 0x9c, 0x00, 0x28, 0x84, 0x49, 0x04, 0x19, 0x34, 0x9f, - 0xfe, 0xbb, 0x45, 0x4b, 0x00, 0x45, 0x3e, 0x06, 0x78, 0x3d, 0xfe, 0xda, - 0x14, 0x01, 0x6e, 0x87, 0xfe, 0x4b, 0x45, 0xe2, 0x2f, 0x07, 0x9a, 0xe1, - 0x05, 0xc6, 0x28, 0x84, 0x05, 0x3f, 0x28, 0x34, 0x5e, 0x02, 0x5b, 0xfe, - 0xc0, 0x5d, 0xfe, 0xf8, 0x14, 0xfe, 0x03, 0x17, 0x05, 0x50, 0xb4, 0x0c, - 0x50, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01, 0xfe, 0xaa, 0x14, 0x02, - 0x5c, 0x01, 0x08, 0x25, 0x32, 0x1f, 0x44, 0x30, 0x2e, 0xd6, 0x07, 0x06, - 0x21, 0x44, 0x01, 0xfe, 0x8e, 0x13, 0xfe, 0x42, 0x58, 0xfe, 0x82, 0x14, - 0xfe, 0xa4, 0x14, 0x87, 0xfe, 0x4a, 0xf4, 0x0b, 0x16, 0x44, 0xfe, 0x4a, - 0xf4, 0x06, 0xfe, 0x0c, 0x12, 0x2f, 0x07, 0x9a, 0x85, 0x02, 0x5b, 0x05, - 0x3f, 0xb4, 0x0c, 0x3f, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01, 0xfe, - 0xd8, 0x14, 0x02, 0x5c, 0x13, 0x06, 0x65, 0xfe, 0xca, 0x12, 0x26, 0xfe, - 0xe0, 0x12, 0x72, 0xf1, 0x01, 0x08, 0x23, 0x72, 0x03, 0x8f, 0xfe, 0xdc, - 0x12, 0x25, 0xfe, 0xdc, 0x12, 0x1f, 0xfe, 0xca, 0x12, 0x5e, 0x2b, 0x01, - 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, - 0x1c, 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x13, - 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0x1c, 0x3d, 0xfe, 0x30, 0x56, - 0xfe, 0x00, 0x5c, 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, - 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0xfe, 0x0b, 0x58, - 0x03, 0x0a, 0x50, 0x01, 0x82, 0x0a, 0x3f, 0x01, 0x82, 0x03, 0xfc, 0x1c, - 0x10, 0xff, 0x03, 0x00, 0x54, 0xfe, 0x00, 0xf4, 0x19, 0x48, 0xfe, 0x00, - 0x7d, 0xfe, 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe, 0x03, 0x7c, 0x63, 0x27, - 0x0c, 0x52, 0x18, 0x53, 0xbe, 0x56, 0xbf, 0x57, 0x03, 0xfe, 0x62, 0x08, - 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x74, 0x03, 0x01, - 0xfe, 0x14, 0x18, 0xfe, 0x42, 0x48, 0x5f, 0x60, 0x89, 0x01, 0x08, 0x1f, - 0xfe, 0xa2, 0x14, 0x30, 0x2e, 0xd8, 0x01, 0x08, 0x1f, 0xfe, 0xa2, 0x14, - 0x30, 0x2e, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, 0x05, 0xc6, 0x28, 0xfe, - 0xcc, 0x12, 0x49, 0x04, 0x1b, 0xfe, 0xc4, 0x13, 0x23, 0x62, 0x1b, 0xe2, - 0x4b, 0xc3, 0x64, 0xfe, 0xe8, 0x13, 0x3b, 0x13, 0x06, 0x17, 0xc3, 0x78, - 0xdb, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xa1, 0xff, 0x02, 0x83, - 0x55, 0x62, 0x1a, 0xa4, 0xbb, 0xfe, 0x30, 0x00, 0x8e, 0xe4, 0x17, 0x2c, - 0x13, 0x06, 0xfe, 0x56, 0x10, 0x62, 0x0b, 0xe1, 0xbb, 0xfe, 0x64, 0x00, - 0x8e, 0xe4, 0x0a, 0xfe, 0x64, 0x00, 0x17, 0x93, 0x13, 0x06, 0xfe, 0x28, - 0x10, 0x62, 0x06, 0xfe, 0x60, 0x13, 0xbb, 0xfe, 0xc8, 0x00, 0x8e, 0xe4, - 0x0a, 0xfe, 0xc8, 0x00, 0x17, 0x4d, 0x13, 0x06, 0x83, 0xbb, 0xfe, 0x90, - 0x01, 0xba, 0xfe, 0x4e, 0x14, 0x89, 0xfe, 0x12, 0x10, 0xfe, 0x43, 0xf4, - 0x94, 0xfe, 0x56, 0xf0, 0xfe, 0x60, 0x14, 0xfe, 0x04, 0xf4, 0x6c, 0xfe, - 0x43, 0xf4, 0x93, 0xfe, 0xf3, 0x10, 0xf9, 0x01, 0xfe, 0x22, 0x13, 0x1c, - 0x3d, 0xfe, 0x10, 0x13, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x69, 0xba, - 0xfe, 0x9c, 0x14, 0xb7, 0x69, 0xfe, 0x1c, 0x10, 0xfe, 0x00, 0x17, 0xfe, - 0x4d, 0xe4, 0x19, 0xba, 0xfe, 0x9c, 0x14, 0xb7, 0x19, 0x83, 0x60, 0x23, - 0xfe, 0x4d, 0xf4, 0x00, 0xdf, 0x89, 0x13, 0x06, 0xfe, 0xb4, 0x56, 0xfe, - 0xc3, 0x58, 0x03, 0x60, 0x13, 0x0b, 0x03, 0x15, 0x06, 0x01, 0x08, 0x26, - 0xe5, 0x15, 0x0b, 0x01, 0x08, 0x26, 0xe5, 0x15, 0x1a, 0x01, 0x08, 0x26, - 0xe5, 0x72, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x03, 0x15, 0x06, 0x01, 0x08, - 0x26, 0xa6, 0x15, 0x1a, 0x01, 0x08, 0x26, 0xa6, 0x15, 0x06, 0x01, 0x08, - 0x26, 0xa6, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x26, 0xa6, 0x72, 0xfe, 0x89, - 0x4a, 0x01, 0x08, 0x03, 0x60, 0x03, 0x1e, 0xcc, 0x07, 0x06, 0xfe, 0x44, - 0x13, 0xad, 0x12, 0xcc, 0xfe, 0x49, 0xf4, 0x00, 0x3b, 0x72, 0x9f, 0x5e, - 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xf1, 0x01, 0x08, 0x2f, 0x07, 0xfe, - 0xe3, 0x00, 0xfe, 0x20, 0x13, 0x1f, 0xfe, 0x5a, 0x15, 0x23, 0x12, 0xcd, - 0x01, 0x43, 0x1e, 0xcd, 0x07, 0x06, 0x45, 0x09, 0x4a, 0x06, 0x35, 0x03, - 0x0a, 0x42, 0x01, 0x0e, 0xed, 0x88, 0x07, 0x10, 0xa4, 0x0a, 0x80, 0x01, - 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, 0x0a, 0x80, 0x01, 0x0e, 0x88, - 0xfe, 0x80, 0xe7, 0x10, 0x07, 0x10, 0x84, 0xfe, 0x45, 0x58, 0x01, 0xe3, - 0x88, 0x03, 0x0a, 0x42, 0x01, 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, - 0x0a, 0x42, 0x01, 0x0e, 0xfe, 0x80, 0x80, 0xf2, 0xfe, 0x49, 0xe4, 0x10, - 0xa4, 0x0a, 0x80, 0x01, 0x0e, 0xf2, 0x0a, 0x51, 0x01, 0x82, 0x03, 0x17, - 0x10, 0x71, 0x66, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, - 0xfe, 0x24, 0x1c, 0xfe, 0x1d, 0xf7, 0x1d, 0x90, 0xfe, 0xf6, 0x15, 0x01, - 0xfe, 0xfc, 0x16, 0xe0, 0x91, 0x1d, 0x66, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, - 0x19, 0x03, 0xae, 0x21, 0xfe, 0xe6, 0x15, 0xfe, 0xda, 0x10, 0x17, 0x10, - 0x71, 0x05, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x19, 0xfe, 0x18, 0x58, - 0x05, 0xfe, 0x66, 0x01, 0xfe, 0x19, 0x58, 0x91, 0x19, 0xfe, 0x3c, 0x90, - 0xfe, 0x30, 0xf4, 0x06, 0xfe, 0x3c, 0x50, 0x66, 0xfe, 0x38, 0x00, 0xfe, - 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x19, 0x90, 0xfe, 0x40, 0x16, 0xfe, 0xb6, - 0x14, 0x34, 0x03, 0xae, 0x21, 0xfe, 0x18, 0x16, 0xfe, 0x9c, 0x10, 0x17, - 0x10, 0x71, 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, - 0x1d, 0xf7, 0x38, 0x90, 0xfe, 0x62, 0x16, 0xfe, 0x94, 0x14, 0xfe, 0x10, - 0x13, 0x91, 0x38, 0x66, 0x1b, 0xfe, 0xaf, 0x19, 0xfe, 0x98, 0xe7, 0x00, - 0x03, 0xae, 0x21, 0xfe, 0x56, 0x16, 0xfe, 0x6c, 0x10, 0x17, 0x10, 0x71, - 0xfe, 0x30, 0xbc, 0xfe, 0xb2, 0xbc, 0x91, 0xc5, 0x66, 0x1b, 0xfe, 0x0f, - 0x79, 0xfe, 0x1c, 0xf7, 0xc5, 0x90, 0xfe, 0x9a, 0x16, 0xfe, 0x5c, 0x14, - 0x34, 0x03, 0xae, 0x21, 0xfe, 0x86, 0x16, 0xfe, 0x42, 0x10, 0xfe, 0x02, - 0xf6, 0x10, 0x71, 0xfe, 0x18, 0xfe, 0x54, 0xfe, 0x19, 0xfe, 0x55, 0xfc, - 0xfe, 0x1d, 0xf7, 0x4f, 0x90, 0xfe, 0xc0, 0x16, 0xfe, 0x36, 0x14, 0xfe, - 0x1c, 0x13, 0x91, 0x4f, 0x47, 0xfe, 0x83, 0x58, 0xfe, 0xaf, 0x19, 0xfe, - 0x80, 0xe7, 0x10, 0xfe, 0x81, 0xe7, 0x10, 0x11, 0xfe, 0xdd, 0x00, 0x63, - 0x27, 0x03, 0x63, 0x27, 0xfe, 0x12, 0x45, 0x21, 0xfe, 0xb0, 0x16, 0x14, - 0x06, 0x37, 0x95, 0xa9, 0x02, 0x29, 0xfe, 0x39, 0xf0, 0xfe, 0x04, 0x17, - 0x23, 0x03, 0xfe, 0x7e, 0x18, 0x1c, 0x1a, 0x5d, 0x13, 0x0d, 0x03, 0x71, - 0x05, 0xcb, 0x1c, 0x06, 0xfe, 0xef, 0x12, 0xfe, 0xe1, 0x10, 0x78, 0x2c, - 0x46, 0x2f, 0x07, 0x2d, 0xfe, 0x3c, 0x13, 0xfe, 0x82, 0x14, 0xfe, 0x42, - 0x13, 0x3c, 0x8a, 0x0a, 0x42, 0x01, 0x0e, 0xb0, 0xfe, 0x3e, 0x12, 0xf0, - 0xfe, 0x45, 0x48, 0x01, 0xe3, 0xfe, 0x00, 0xcc, 0xb0, 0xfe, 0xf3, 0x13, - 0x3d, 0x75, 0x07, 0x10, 0xa3, 0x0a, 0x80, 0x01, 0x0e, 0xf2, 0x01, 0x6f, - 0xfe, 0x16, 0x10, 0x07, 0x7e, 0x85, 0xfe, 0x40, 0x14, 0xfe, 0x24, 0x12, - 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x24, 0x17, 0x17, 0x0b, 0x03, 0xfe, 0x9c, - 0xe7, 0x0b, 0x0f, 0xfe, 0x15, 0x00, 0x59, 0x76, 0x27, 0x01, 0xda, 0x17, - 0x06, 0x03, 0x3c, 0x8a, 0x09, 0x4a, 0x1d, 0x35, 0x11, 0x2d, 0x01, 0x6f, - 0x17, 0x06, 0x03, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, 0x79, 0xc7, 0x68, - 0xc8, 0xfe, 0x48, 0x55, 0x34, 0xfe, 0xc9, 0x55, 0x03, 0x1e, 0x98, 0x73, - 0x12, 0x98, 0x03, 0x0a, 0x99, 0x01, 0x0e, 0xf0, 0x0a, 0x40, 0x01, 0x0e, - 0xfe, 0x49, 0x44, 0x16, 0xfe, 0xf0, 0x17, 0x73, 0x75, 0x03, 0x0a, 0x42, - 0x01, 0x0e, 0x07, 0x10, 0x45, 0x0a, 0x51, 0x01, 0x9e, 0x0a, 0x40, 0x01, - 0x0e, 0x73, 0x75, 0x03, 0xfe, 0x4e, 0xe4, 0x1a, 0x64, 0xfe, 0x24, 0x18, - 0x05, 0xfe, 0x90, 0x00, 0xfe, 0x3a, 0x45, 0x5b, 0xfe, 0x4e, 0xe4, 0xc2, - 0x64, 0xfe, 0x36, 0x18, 0x05, 0xfe, 0x92, 0x00, 0xfe, 0x02, 0xe6, 0x1b, - 0xdc, 0xfe, 0x4e, 0xe4, 0xfe, 0x0b, 0x00, 0x64, 0xfe, 0x48, 0x18, 0x05, - 0xfe, 0x94, 0x00, 0xfe, 0x02, 0xe6, 0x19, 0xfe, 0x08, 0x10, 0x05, 0xfe, - 0x96, 0x00, 0xfe, 0x02, 0xe6, 0x2c, 0xfe, 0x4e, 0x45, 0xfe, 0x0c, 0x12, - 0xaf, 0xff, 0x04, 0x68, 0x54, 0xde, 0x1c, 0x69, 0x03, 0x07, 0x7a, 0xfe, - 0x5a, 0xf0, 0xfe, 0x74, 0x18, 0x24, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10, - 0x07, 0x1b, 0xfe, 0x5a, 0xf0, 0xfe, 0x82, 0x18, 0x24, 0xc3, 0xfe, 0x26, - 0x10, 0x07, 0x1a, 0x5d, 0x24, 0x2c, 0xdc, 0x07, 0x0b, 0x5d, 0x24, 0x93, - 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x5d, 0x24, 0x4d, 0x9f, 0xad, 0x03, 0x14, - 0xfe, 0x09, 0x00, 0x01, 0x33, 0xfe, 0x04, 0xfe, 0x7d, 0x05, 0x7f, 0xf9, - 0x03, 0x25, 0xfe, 0xca, 0x18, 0xfe, 0x14, 0xf0, 0x08, 0x65, 0xfe, 0xc6, - 0x18, 0x03, 0xff, 0x1a, 0x00, 0x00, -}; - -static unsigned short _adv_asc3550_size = sizeof(_adv_asc3550_buf); /* 0x13AD */ -static ADV_DCNT _adv_asc3550_chksum = 0x04D52DDDUL; /* Expanded little-endian checksum. */ - -/* Microcode buffer is kept after initialization for error recovery. */ -static unsigned char _adv_asc38C0800_buf[] = { - 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0xfc, 0x00, 0x16, 0x18, 0xe4, - 0x01, 0x00, 0x48, 0xe4, 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, 0xce, 0x19, - 0x00, 0xfa, 0xff, 0xff, 0x1c, 0x0f, 0x00, 0xf6, 0x9e, 0xe7, 0xff, 0x00, - 0x82, 0xe7, 0x00, 0xea, 0x01, 0xfa, 0x01, 0xe6, 0x09, 0xe7, 0x55, 0xf0, - 0x01, 0xf6, 0x03, 0x00, 0x04, 0x00, 0x10, 0x00, 0x1e, 0xf0, 0x85, 0xf0, - 0x18, 0xf4, 0x08, 0x00, 0xbc, 0x00, 0x38, 0x54, 0x00, 0xec, 0xd5, 0xf0, - 0x82, 0x0d, 0x00, 0xe6, 0x86, 0xf0, 0xb1, 0xf0, 0x98, 0x57, 0x01, 0xfc, - 0xb4, 0x00, 0xd4, 0x01, 0x0c, 0x1c, 0x3e, 0x1c, 0x3c, 0x00, 0xbb, 0x00, - 0x00, 0x10, 0xba, 0x19, 0x02, 0x80, 0x32, 0xf0, 0x7c, 0x0d, 0x02, 0x13, - 0xba, 0x13, 0x18, 0x40, 0x00, 0x57, 0x01, 0xea, 0x02, 0xfc, 0x03, 0xfc, - 0x3e, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x74, 0x01, 0x76, 0x01, 0xb9, 0x54, - 0x3e, 0x57, 0x00, 0x80, 0x03, 0xe6, 0xb6, 0x00, 0xc0, 0x00, 0x01, 0x01, - 0x3e, 0x01, 0x7a, 0x01, 0xca, 0x08, 0xce, 0x10, 0x16, 0x11, 0x04, 0x12, - 0x08, 0x12, 0x02, 0x4a, 0xbb, 0x55, 0x3c, 0x56, 0x03, 0x58, 0x1b, 0x80, - 0x30, 0xe4, 0x4b, 0xe4, 0x5d, 0xf0, 0x02, 0xfa, 0x20, 0x00, 0x32, 0x00, - 0x40, 0x00, 0x80, 0x00, 0x24, 0x01, 0x3c, 0x01, 0x68, 0x01, 0x6a, 0x01, - 0x70, 0x01, 0x72, 0x01, 0x78, 0x01, 0x7c, 0x01, 0x62, 0x0a, 0x86, 0x0d, - 0x06, 0x13, 0x4c, 0x1c, 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, - 0x03, 0xf7, 0x0c, 0x00, 0x0f, 0x00, 0x47, 0x00, 0xbe, 0x00, 0x00, 0x01, - 0x20, 0x11, 0x5c, 0x16, 0x32, 0x1c, 0x38, 0x1c, 0x4e, 0x1c, 0x10, 0x44, - 0x00, 0x4c, 0x04, 0xea, 0x5c, 0xf0, 0xa7, 0xf0, 0x04, 0xf6, 0x03, 0xfa, - 0x05, 0x00, 0x34, 0x00, 0x36, 0x00, 0x98, 0x00, 0xcc, 0x00, 0x20, 0x01, - 0x4e, 0x01, 0x4a, 0x0b, 0x42, 0x0c, 0x12, 0x0f, 0x0c, 0x10, 0x22, 0x11, - 0x0a, 0x12, 0x04, 0x13, 0x30, 0x1c, 0x02, 0x48, 0x00, 0x4e, 0x42, 0x54, - 0x44, 0x55, 0xbd, 0x56, 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0, - 0x59, 0xf0, 0xb8, 0xf0, 0x4b, 0xf4, 0x06, 0xf7, 0x0e, 0xf7, 0x04, 0xfc, - 0x05, 0xfc, 0x06, 0x00, 0x19, 0x00, 0x33, 0x00, 0x9b, 0x00, 0xa4, 0x00, - 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00, 0xe7, 0x00, 0xe2, 0x03, - 0x08, 0x0f, 0x02, 0x10, 0x04, 0x10, 0x0a, 0x10, 0x0a, 0x13, 0x0c, 0x13, - 0x12, 0x13, 0x24, 0x14, 0x34, 0x14, 0x04, 0x16, 0x08, 0x16, 0xa4, 0x17, - 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c, 0x08, 0x44, 0x38, 0x44, 0x91, 0x44, - 0x0a, 0x45, 0x48, 0x46, 0x01, 0x48, 0x68, 0x54, 0x3a, 0x55, 0x83, 0x55, - 0xe5, 0x55, 0xb0, 0x57, 0x01, 0x58, 0x83, 0x59, 0x05, 0xe6, 0x0b, 0xf0, - 0x0c, 0xf0, 0x04, 0xf8, 0x05, 0xf8, 0x07, 0x00, 0x0a, 0x00, 0x1c, 0x00, - 0x1e, 0x00, 0x9e, 0x00, 0xa8, 0x00, 0xaa, 0x00, 0xb9, 0x00, 0xe0, 0x00, - 0x22, 0x01, 0x26, 0x01, 0x79, 0x01, 0x7e, 0x01, 0xc4, 0x01, 0xc6, 0x01, - 0x80, 0x02, 0x5e, 0x03, 0xee, 0x04, 0x9a, 0x06, 0xf8, 0x07, 0x62, 0x08, - 0x68, 0x08, 0x69, 0x08, 0xd6, 0x08, 0xe9, 0x09, 0xfa, 0x0b, 0x2e, 0x0f, - 0x12, 0x10, 0x1a, 0x10, 0xed, 0x10, 0xf1, 0x10, 0x2a, 0x11, 0x06, 0x12, - 0x0c, 0x12, 0x3e, 0x12, 0x10, 0x13, 0x16, 0x13, 0x1e, 0x13, 0x46, 0x14, - 0x76, 0x14, 0x82, 0x14, 0x36, 0x15, 0xca, 0x15, 0x6b, 0x18, 0xbe, 0x18, - 0xca, 0x18, 0xe6, 0x19, 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40, - 0x0e, 0x47, 0xfe, 0x9c, 0xf0, 0x2b, 0x02, 0xfe, 0xac, 0x0d, 0xff, 0x10, - 0x00, 0x00, 0xd7, 0xfe, 0xe8, 0x19, 0x00, 0xd6, 0xfe, 0x84, 0x01, 0xff, - 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00, - 0x00, 0xfe, 0x57, 0x24, 0x00, 0xfe, 0x4c, 0x00, 0x5b, 0xff, 0x04, 0x00, - 0x00, 0x11, 0xff, 0x09, 0x00, 0x00, 0xff, 0x08, 0x01, 0x01, 0xff, 0x08, - 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10, 0xff, 0xff, 0xff, 0x11, - 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00, - 0xfe, 0x04, 0xf7, 0xd6, 0x2c, 0x99, 0x0a, 0x01, 0xfe, 0xc2, 0x0f, 0xfe, - 0x04, 0xf7, 0xd6, 0x99, 0x0a, 0x42, 0x2c, 0xfe, 0x3d, 0xf0, 0xfe, 0x06, - 0x02, 0xfe, 0x20, 0xf0, 0xa7, 0xfe, 0x91, 0xf0, 0xfe, 0xf4, 0x01, 0xfe, - 0x90, 0xf0, 0xfe, 0xf4, 0x01, 0xfe, 0x8f, 0xf0, 0xa7, 0x03, 0x5d, 0x4d, - 0x02, 0xfe, 0xc8, 0x0d, 0x01, 0xfe, 0x38, 0x0e, 0xfe, 0xdd, 0x12, 0xfe, - 0xfc, 0x10, 0xfe, 0x28, 0x1c, 0x03, 0xfe, 0xa6, 0x00, 0xfe, 0xd3, 0x12, - 0x41, 0x14, 0xfe, 0xa6, 0x00, 0xc2, 0xfe, 0x48, 0xf0, 0xfe, 0x8a, 0x02, - 0xfe, 0x49, 0xf0, 0xfe, 0xa4, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc2, 0x02, - 0xfe, 0x46, 0xf0, 0xfe, 0x54, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x5a, 0x02, - 0xfe, 0x43, 0xf0, 0xfe, 0x48, 0x02, 0xfe, 0x44, 0xf0, 0xfe, 0x4c, 0x02, - 0xfe, 0x45, 0xf0, 0xfe, 0x50, 0x02, 0x18, 0x0a, 0xaa, 0x18, 0x06, 0x14, - 0xa1, 0x02, 0x2b, 0xfe, 0x00, 0x1c, 0xe7, 0xfe, 0x02, 0x1c, 0xe6, 0xfe, - 0x1e, 0x1c, 0xfe, 0xe9, 0x10, 0x01, 0xfe, 0x18, 0x18, 0xfe, 0xe7, 0x10, - 0xfe, 0x06, 0xfc, 0xce, 0x09, 0x70, 0x01, 0xa8, 0x02, 0x2b, 0x15, 0x59, - 0x39, 0xa2, 0x01, 0xfe, 0x58, 0x10, 0x09, 0x70, 0x01, 0x87, 0xfe, 0xbd, - 0x10, 0x09, 0x70, 0x01, 0x87, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe, - 0x58, 0x1c, 0x18, 0x06, 0x14, 0xa1, 0x2c, 0x1c, 0x2b, 0xfe, 0x3d, 0xf0, - 0xfe, 0x06, 0x02, 0x23, 0xfe, 0x98, 0x02, 0xfe, 0x5a, 0x1c, 0xf8, 0xfe, - 0x14, 0x1c, 0x15, 0xfe, 0x30, 0x00, 0x39, 0xa2, 0x01, 0xfe, 0x48, 0x10, - 0x18, 0x06, 0x14, 0xa1, 0x02, 0xd7, 0x22, 0x20, 0x07, 0x11, 0x35, 0xfe, - 0x69, 0x10, 0x18, 0x06, 0x14, 0xa1, 0xfe, 0x04, 0xec, 0x20, 0x4f, 0x43, - 0x13, 0x20, 0xfe, 0x05, 0xf6, 0xce, 0x01, 0xfe, 0x4a, 0x17, 0x08, 0x54, - 0x58, 0x37, 0x12, 0x2f, 0x42, 0x92, 0x01, 0xfe, 0x82, 0x16, 0x02, 0x2b, - 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66, 0x01, 0x73, 0xfe, 0x18, 0x10, - 0xfe, 0x41, 0x58, 0x09, 0xa4, 0x01, 0x0e, 0xfe, 0xc8, 0x54, 0x6b, 0xfe, - 0x10, 0x03, 0x01, 0xfe, 0x82, 0x16, 0x02, 0x2b, 0x2c, 0x4f, 0xfe, 0x02, - 0xe8, 0x2a, 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43, 0xfe, 0x77, 0x57, 0xfe, - 0x27, 0xf0, 0xfe, 0xe0, 0x01, 0xfe, 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xa7, - 0xfe, 0x40, 0x1c, 0x1c, 0xd9, 0xfe, 0x26, 0xf0, 0xfe, 0x5a, 0x03, 0xfe, - 0xa0, 0xf0, 0xfe, 0x48, 0x03, 0xfe, 0x11, 0xf0, 0xa7, 0xfe, 0xef, 0x10, - 0xfe, 0x9f, 0xf0, 0xfe, 0x68, 0x03, 0xf9, 0x10, 0xfe, 0x11, 0x00, 0x02, - 0x65, 0x2c, 0xfe, 0x48, 0x1c, 0xf9, 0x08, 0x05, 0x1b, 0xfe, 0x18, 0x13, - 0x21, 0x22, 0xa3, 0xb7, 0x13, 0xa3, 0x09, 0x46, 0x01, 0x0e, 0xb7, 0x78, - 0x01, 0xfe, 0xb4, 0x16, 0x12, 0xd1, 0x1c, 0xd9, 0xfe, 0x01, 0xf0, 0xd9, - 0xfe, 0x82, 0xf0, 0xfe, 0x96, 0x03, 0xfa, 0x12, 0xfe, 0xe4, 0x00, 0x27, - 0xfe, 0xa8, 0x03, 0x1c, 0x34, 0x1d, 0xfe, 0xb8, 0x03, 0x01, 0x4b, 0xfe, - 0x06, 0xf0, 0xfe, 0xc8, 0x03, 0x95, 0x86, 0xfe, 0x0a, 0xf0, 0xfe, 0x8a, - 0x06, 0x02, 0x24, 0x03, 0x70, 0x28, 0x17, 0xfe, 0xfa, 0x04, 0x15, 0x6d, - 0x01, 0x36, 0x7b, 0xfe, 0x6a, 0x02, 0x02, 0xd8, 0xf9, 0x2c, 0x99, 0x19, - 0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0xfe, 0x48, 0x1c, - 0x74, 0x01, 0xaf, 0x8c, 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x17, 0xda, - 0x09, 0xd1, 0x01, 0x0e, 0x8d, 0x51, 0x64, 0x79, 0x2a, 0x03, 0x70, 0x28, - 0xfe, 0x10, 0x12, 0x15, 0x6d, 0x01, 0x36, 0x7b, 0xfe, 0x6a, 0x02, 0x02, - 0xd8, 0xc7, 0x81, 0xc8, 0x83, 0x1c, 0x24, 0x27, 0xfe, 0x40, 0x04, 0x1d, - 0xfe, 0x3c, 0x04, 0x3b, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e, - 0x12, 0x2d, 0xff, 0x02, 0x00, 0x10, 0x01, 0x0b, 0x1d, 0xfe, 0xe4, 0x04, - 0x2d, 0x01, 0x0b, 0x1d, 0x24, 0x33, 0x31, 0xde, 0xfe, 0x4c, 0x44, 0xfe, - 0x4c, 0x12, 0x51, 0xfe, 0x44, 0x48, 0x0f, 0x6f, 0xfe, 0x4c, 0x54, 0x6b, - 0xda, 0x4f, 0x79, 0x2a, 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x62, - 0x13, 0x08, 0x05, 0x1b, 0xfe, 0x2a, 0x13, 0x32, 0x07, 0x82, 0xfe, 0x52, - 0x13, 0xfe, 0x20, 0x10, 0x0f, 0x6f, 0xfe, 0x4c, 0x54, 0x6b, 0xda, 0xfe, - 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x40, 0x13, 0x08, 0x05, 0x1b, 0xfe, - 0x08, 0x13, 0x32, 0x07, 0x82, 0xfe, 0x30, 0x13, 0x08, 0x05, 0x1b, 0xfe, - 0x1c, 0x12, 0x15, 0x9d, 0x08, 0x05, 0x06, 0x4d, 0x15, 0xfe, 0x0d, 0x00, - 0x01, 0x36, 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24, 0x2d, 0x12, 0xfe, 0xe6, - 0x00, 0xfe, 0x1c, 0x90, 0xfe, 0x40, 0x5c, 0x04, 0x15, 0x9d, 0x01, 0x36, - 0x02, 0x2b, 0xfe, 0x42, 0x5b, 0x99, 0x19, 0xfe, 0x46, 0x59, 0xfe, 0xbf, - 0x57, 0xfe, 0x77, 0x57, 0xfe, 0x87, 0x80, 0xfe, 0x31, 0xe4, 0x5b, 0x08, - 0x05, 0x0a, 0xfe, 0x84, 0x13, 0xfe, 0x20, 0x80, 0x07, 0x19, 0xfe, 0x7c, - 0x12, 0x53, 0x05, 0x06, 0xfe, 0x6c, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x28, - 0x17, 0xfe, 0x90, 0x05, 0xfe, 0x31, 0xe4, 0x5a, 0x53, 0x05, 0x0a, 0xfe, - 0x56, 0x13, 0x03, 0xfe, 0xa0, 0x00, 0x28, 0xfe, 0x4e, 0x12, 0x67, 0xff, - 0x02, 0x00, 0x10, 0x27, 0xfe, 0x48, 0x05, 0x1c, 0x34, 0xfe, 0x89, 0x48, - 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x56, 0x05, 0x26, 0xfe, 0xa8, 0x05, - 0x12, 0xfe, 0xe3, 0x00, 0x21, 0x53, 0xfe, 0x4a, 0xf0, 0xfe, 0x76, 0x05, - 0xfe, 0x49, 0xf0, 0xfe, 0x70, 0x05, 0x88, 0x25, 0xfe, 0x21, 0x00, 0xab, - 0x25, 0xfe, 0x22, 0x00, 0xaa, 0x25, 0x58, 0xfe, 0x09, 0x48, 0xff, 0x02, - 0x00, 0x10, 0x27, 0xfe, 0x86, 0x05, 0x26, 0xfe, 0xa8, 0x05, 0xfe, 0xe2, - 0x08, 0x53, 0x05, 0xcb, 0x4d, 0x01, 0xb0, 0x25, 0x06, 0x13, 0xd3, 0x39, - 0xfe, 0x27, 0x01, 0x08, 0x05, 0x1b, 0xfe, 0x22, 0x12, 0x41, 0x01, 0xb2, - 0x15, 0x9d, 0x08, 0x05, 0x06, 0x4d, 0x15, 0xfe, 0x0d, 0x00, 0x01, 0x36, - 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0xeb, - 0x03, 0x5c, 0x28, 0xfe, 0x36, 0x13, 0x41, 0x01, 0xb2, 0x26, 0xfe, 0x18, - 0x06, 0x09, 0x06, 0x53, 0x05, 0x1f, 0xfe, 0x02, 0x12, 0x50, 0x01, 0xfe, - 0x9e, 0x15, 0x1d, 0xfe, 0x0e, 0x06, 0x12, 0xa5, 0x01, 0x4b, 0x12, 0xfe, - 0xe5, 0x00, 0x03, 0x5c, 0xc1, 0x0c, 0x5c, 0x03, 0xcd, 0x28, 0xfe, 0x62, - 0x12, 0x03, 0x45, 0x28, 0xfe, 0x5a, 0x13, 0x01, 0xfe, 0x0c, 0x19, 0x01, - 0xfe, 0x76, 0x19, 0xfe, 0x43, 0x48, 0xc4, 0xcc, 0x0f, 0x71, 0xff, 0x02, - 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0x8b, 0xc4, 0x6e, 0x41, 0x01, 0xb2, - 0x26, 0xfe, 0x82, 0x06, 0x53, 0x05, 0x1a, 0xe9, 0x91, 0x09, 0x59, 0x01, - 0xfe, 0xcc, 0x15, 0x1d, 0xfe, 0x78, 0x06, 0x12, 0xa5, 0x01, 0x4b, 0x12, - 0xfe, 0xe5, 0x00, 0x03, 0x45, 0xc1, 0x0c, 0x45, 0x18, 0x06, 0x01, 0xb2, - 0xfa, 0x76, 0x74, 0x01, 0xaf, 0x8c, 0x12, 0xfe, 0xe2, 0x00, 0x27, 0xdb, - 0x1c, 0x34, 0xfe, 0x0a, 0xf0, 0xfe, 0xb6, 0x06, 0x94, 0xfe, 0x6c, 0x07, - 0xfe, 0x06, 0xf0, 0xfe, 0x74, 0x07, 0x95, 0x86, 0x02, 0x24, 0x08, 0x05, - 0x0a, 0xfe, 0x2e, 0x12, 0x16, 0x19, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b, - 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b, 0xfe, 0x99, 0xa4, 0x01, - 0x0b, 0x16, 0x00, 0x02, 0xfe, 0x42, 0x08, 0x68, 0x05, 0x1a, 0xfe, 0x38, - 0x12, 0x08, 0x05, 0x1a, 0xfe, 0x30, 0x13, 0x16, 0xfe, 0x1b, 0x00, 0x01, - 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, - 0x0b, 0x16, 0x06, 0x01, 0x0b, 0x16, 0x00, 0x02, 0xe2, 0x6c, 0x58, 0xbe, - 0x50, 0xfe, 0x9a, 0x81, 0x55, 0x1b, 0x7a, 0xfe, 0x42, 0x07, 0x09, 0x1b, - 0xfe, 0x09, 0x6f, 0xba, 0xfe, 0xca, 0x45, 0xfe, 0x32, 0x12, 0x69, 0x6d, - 0x8b, 0x6c, 0x7f, 0x27, 0xfe, 0x54, 0x07, 0x1c, 0x34, 0xfe, 0x0a, 0xf0, - 0xfe, 0x42, 0x07, 0x95, 0x86, 0x94, 0xfe, 0x6c, 0x07, 0x02, 0x24, 0x01, - 0x4b, 0x02, 0xdb, 0x16, 0x1f, 0x02, 0xdb, 0xfe, 0x9c, 0xf7, 0xdc, 0xfe, - 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x56, 0xfe, 0xda, 0x07, 0x0c, 0x60, 0x14, - 0x61, 0x08, 0x54, 0x5a, 0x37, 0x22, 0x20, 0x07, 0x11, 0xfe, 0x0e, 0x12, - 0x8d, 0xfe, 0x80, 0x80, 0x39, 0x20, 0x6a, 0x2a, 0xfe, 0x06, 0x10, 0xfe, - 0x83, 0xe7, 0xfe, 0x48, 0x00, 0xab, 0xfe, 0x03, 0x40, 0x08, 0x54, 0x5b, - 0x37, 0x01, 0xb3, 0xb8, 0xfe, 0x1f, 0x40, 0x13, 0x62, 0x01, 0xef, 0xfe, - 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, 0xfe, 0xc6, 0x51, 0x88, - 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90, 0x0c, 0x5e, 0x14, 0x5f, 0xfe, 0x0c, - 0x90, 0xfe, 0x8e, 0x90, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x0c, 0x3d, - 0x14, 0x3e, 0xfe, 0x4a, 0x10, 0x08, 0x05, 0x5a, 0xfe, 0x2a, 0x12, 0xfe, - 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x0c, 0x60, 0x14, 0x61, 0x08, 0x05, 0x5b, - 0x8b, 0x01, 0xb3, 0xfe, 0x1f, 0x80, 0x13, 0x62, 0xfe, 0x44, 0x90, 0xfe, - 0xc6, 0x90, 0x0c, 0x3f, 0x14, 0x40, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90, - 0x0c, 0x5e, 0x14, 0x5f, 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90, 0x0c, 0x3d, - 0x14, 0x3e, 0x0c, 0x2e, 0x14, 0x3c, 0x21, 0x0c, 0x49, 0x0c, 0x63, 0x08, - 0x54, 0x1f, 0x37, 0x2c, 0x0f, 0xfe, 0x4e, 0x11, 0x27, 0xdd, 0xfe, 0x9e, - 0xf0, 0xfe, 0x76, 0x08, 0xbc, 0x17, 0x34, 0x2c, 0x77, 0xe6, 0xc5, 0xfe, - 0x9a, 0x08, 0xc6, 0xfe, 0xb8, 0x08, 0x94, 0xfe, 0x8e, 0x08, 0xfe, 0x06, - 0xf0, 0xfe, 0x94, 0x08, 0x95, 0x86, 0x02, 0x24, 0x01, 0x4b, 0xfe, 0xc9, - 0x10, 0x16, 0x1f, 0xfe, 0xc9, 0x10, 0x68, 0x05, 0x06, 0xfe, 0x10, 0x12, - 0x68, 0x05, 0x0a, 0x4e, 0x08, 0x05, 0x0a, 0xfe, 0x90, 0x12, 0xfe, 0x2e, - 0x1c, 0x02, 0xfe, 0x18, 0x0b, 0x68, 0x05, 0x06, 0x4e, 0x68, 0x05, 0x0a, - 0xfe, 0x7a, 0x12, 0xfe, 0x2c, 0x1c, 0xfe, 0xaa, 0xf0, 0xfe, 0xd2, 0x09, - 0xfe, 0xac, 0xf0, 0xfe, 0x00, 0x09, 0x02, 0xfe, 0xde, 0x09, 0xfe, 0xb7, - 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0x02, 0xf6, 0x1a, 0x50, 0xfe, 0x70, 0x18, - 0xfe, 0xf1, 0x18, 0xfe, 0x40, 0x55, 0xfe, 0xe1, 0x55, 0xfe, 0x10, 0x58, - 0xfe, 0x91, 0x58, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x1c, 0x85, 0xfe, - 0x8c, 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0xac, 0xf0, 0xfe, 0xf0, 0x08, 0xb5, - 0xfe, 0xcb, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0x0c, 0x09, 0x02, 0xfe, 0x18, - 0x0b, 0xb6, 0xfe, 0xbf, 0x10, 0xfe, 0x2b, 0xf0, 0x85, 0xf4, 0x1e, 0xfe, - 0x00, 0xfe, 0xfe, 0x1c, 0x12, 0xc2, 0xfe, 0xd2, 0xf0, 0x85, 0xfe, 0x76, - 0x18, 0x1e, 0x19, 0x17, 0x85, 0x03, 0xd2, 0x1e, 0x06, 0x17, 0x85, 0xc5, - 0x4a, 0xc6, 0x4a, 0xb5, 0xb6, 0xfe, 0x89, 0x10, 0x74, 0x67, 0x2d, 0x15, - 0x9d, 0x01, 0x36, 0x10, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x65, 0x10, - 0x80, 0x02, 0x65, 0xfe, 0x98, 0x80, 0xfe, 0x19, 0xe4, 0x0a, 0xfe, 0x1a, - 0x12, 0x51, 0xfe, 0x19, 0x82, 0xfe, 0x6c, 0x18, 0xfe, 0x44, 0x54, 0xbe, - 0xfe, 0x19, 0x81, 0xfe, 0x74, 0x18, 0x8f, 0x90, 0x17, 0xfe, 0xce, 0x08, - 0x02, 0x4a, 0x08, 0x05, 0x5a, 0xec, 0x03, 0x2e, 0x29, 0x3c, 0x0c, 0x3f, - 0x14, 0x40, 0x9b, 0x2e, 0x9c, 0x3c, 0xfe, 0x6c, 0x18, 0xfe, 0xed, 0x18, - 0xfe, 0x44, 0x54, 0xfe, 0xe5, 0x54, 0x3a, 0x3f, 0x3b, 0x40, 0x03, 0x49, - 0x29, 0x63, 0x8f, 0xfe, 0xe3, 0x54, 0xfe, 0x74, 0x18, 0xfe, 0xf5, 0x18, - 0x8f, 0xfe, 0xe3, 0x54, 0x90, 0xc0, 0x56, 0xfe, 0xce, 0x08, 0x02, 0x4a, - 0xfe, 0x37, 0xf0, 0xfe, 0xda, 0x09, 0xfe, 0x8b, 0xf0, 0xfe, 0x60, 0x09, - 0x02, 0x4a, 0x08, 0x05, 0x0a, 0x23, 0xfe, 0xfa, 0x0a, 0x3a, 0x49, 0x3b, - 0x63, 0x56, 0xfe, 0x3e, 0x0a, 0x0f, 0xfe, 0xc0, 0x07, 0x41, 0x98, 0x00, - 0xad, 0xfe, 0x01, 0x59, 0xfe, 0x52, 0xf0, 0xfe, 0x0c, 0x0a, 0x8f, 0x7a, - 0xfe, 0x24, 0x0a, 0x3a, 0x49, 0x8f, 0xfe, 0xe3, 0x54, 0x57, 0x49, 0x7d, - 0x63, 0xfe, 0x14, 0x58, 0xfe, 0x95, 0x58, 0x02, 0x4a, 0x3a, 0x49, 0x3b, - 0x63, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0xbe, 0x57, 0x49, 0x57, 0x63, - 0x02, 0x4a, 0x08, 0x05, 0x5a, 0xfe, 0x82, 0x12, 0x08, 0x05, 0x1f, 0xfe, - 0x66, 0x13, 0x22, 0x62, 0xb7, 0xfe, 0x03, 0xa1, 0xfe, 0x83, 0x80, 0xfe, - 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91, 0xfe, 0x86, 0x91, 0x6a, - 0x2a, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x56, 0xe0, 0x03, 0x60, 0x29, - 0x61, 0x0c, 0x7f, 0x14, 0x80, 0x57, 0x60, 0x7d, 0x61, 0x01, 0xb3, 0xb8, - 0x6a, 0x2a, 0x13, 0x62, 0x9b, 0x2e, 0x9c, 0x3c, 0x3a, 0x3f, 0x3b, 0x40, - 0x90, 0xc0, 0xfe, 0x04, 0xfa, 0x2e, 0xfe, 0x05, 0xfa, 0x3c, 0x01, 0xef, - 0xfe, 0x36, 0x10, 0x21, 0x0c, 0x7f, 0x0c, 0x80, 0x3a, 0x3f, 0x3b, 0x40, - 0xe4, 0x08, 0x05, 0x1f, 0x17, 0xe0, 0x3a, 0x3d, 0x3b, 0x3e, 0x08, 0x05, - 0xfe, 0xf7, 0x00, 0x37, 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x10, 0x58, 0xfe, - 0x91, 0x58, 0x57, 0x49, 0x7d, 0x63, 0x02, 0xfe, 0xf4, 0x09, 0x08, 0x05, - 0x1f, 0x17, 0xe0, 0x08, 0x05, 0xfe, 0xf7, 0x00, 0x37, 0xbe, 0xfe, 0x19, - 0x81, 0x50, 0xfe, 0x10, 0x90, 0xfe, 0x92, 0x90, 0xfe, 0xd3, 0x10, 0x32, - 0x07, 0xa6, 0x17, 0xfe, 0x08, 0x09, 0x12, 0xa6, 0x08, 0x05, 0x0a, 0xfe, - 0x14, 0x13, 0x03, 0x3d, 0x29, 0x3e, 0x56, 0xfe, 0x08, 0x09, 0xfe, 0x0c, - 0x58, 0xfe, 0x8d, 0x58, 0x02, 0x4a, 0x21, 0x41, 0xfe, 0x19, 0x80, 0xe7, - 0x08, 0x05, 0x0a, 0xfe, 0x1a, 0x12, 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, - 0xf4, 0xc2, 0xfe, 0xd1, 0xf0, 0xe2, 0x15, 0x7e, 0x01, 0x36, 0x10, 0xfe, - 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19, 0x57, 0x3d, 0xfe, 0xed, - 0x19, 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xf4, 0x1e, 0xfe, - 0x00, 0xff, 0x35, 0xfe, 0x74, 0x10, 0xc2, 0xfe, 0xd2, 0xf0, 0xfe, 0xa6, - 0x0b, 0xfe, 0x76, 0x18, 0x1e, 0x19, 0x8a, 0x03, 0xd2, 0x1e, 0x06, 0xfe, - 0x08, 0x13, 0x10, 0xfe, 0x16, 0x00, 0x02, 0x65, 0xfe, 0xd1, 0xf0, 0xfe, - 0xb8, 0x0b, 0x15, 0x7e, 0x01, 0x36, 0x10, 0xfe, 0x17, 0x00, 0xfe, 0x42, - 0x10, 0xfe, 0xce, 0xf0, 0xfe, 0xbe, 0x0b, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, - 0xf0, 0xfe, 0xca, 0x0b, 0x10, 0xfe, 0x22, 0x00, 0x02, 0x65, 0xfe, 0xcb, - 0xf0, 0xfe, 0xd6, 0x0b, 0x10, 0xfe, 0x24, 0x00, 0x02, 0x65, 0xfe, 0xd0, - 0xf0, 0xfe, 0xe0, 0x0b, 0x10, 0x9e, 0xe5, 0xfe, 0xcf, 0xf0, 0xfe, 0xea, - 0x0b, 0x10, 0x58, 0xfe, 0x10, 0x10, 0xfe, 0xcc, 0xf0, 0xe2, 0x68, 0x05, - 0x1f, 0x4d, 0x10, 0xfe, 0x12, 0x00, 0x2c, 0x0f, 0xfe, 0x4e, 0x11, 0x27, - 0xfe, 0x00, 0x0c, 0xfe, 0x9e, 0xf0, 0xfe, 0x14, 0x0c, 0xbc, 0x17, 0x34, - 0x2c, 0x77, 0xe6, 0xc5, 0x24, 0xc6, 0x24, 0x2c, 0xfa, 0x27, 0xfe, 0x20, - 0x0c, 0x1c, 0x34, 0x94, 0xfe, 0x3c, 0x0c, 0x95, 0x86, 0xc5, 0xdc, 0xc6, - 0xdc, 0x02, 0x24, 0x01, 0x4b, 0xfe, 0xdb, 0x10, 0x12, 0xfe, 0xe8, 0x00, - 0xb5, 0xb6, 0x74, 0xc7, 0x81, 0xc8, 0x83, 0xfe, 0x89, 0xf0, 0x24, 0x33, - 0x31, 0xe1, 0xc7, 0x81, 0xc8, 0x83, 0x27, 0xfe, 0x66, 0x0c, 0x1d, 0x24, - 0x33, 0x31, 0xdf, 0xbc, 0x4e, 0x10, 0xfe, 0x42, 0x00, 0x02, 0x65, 0x7c, - 0x06, 0xfe, 0x81, 0x49, 0x17, 0xfe, 0x2c, 0x0d, 0x08, 0x05, 0x0a, 0xfe, - 0x44, 0x13, 0x10, 0x00, 0x55, 0x0a, 0xfe, 0x54, 0x12, 0x55, 0xfe, 0x28, - 0x00, 0x23, 0xfe, 0x9a, 0x0d, 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66, - 0x44, 0xfe, 0x28, 0x00, 0xfe, 0xe2, 0x10, 0x01, 0xf5, 0x01, 0xf6, 0x09, - 0xa4, 0x01, 0xfe, 0x26, 0x0f, 0x64, 0x12, 0x2f, 0x01, 0x73, 0x02, 0x2b, - 0x10, 0xfe, 0x44, 0x00, 0x55, 0x0a, 0xe9, 0x44, 0x0a, 0xfe, 0xb4, 0x10, - 0x01, 0xb0, 0x44, 0x0a, 0xfe, 0xaa, 0x10, 0x01, 0xb0, 0xfe, 0x19, 0x82, - 0xfe, 0x34, 0x46, 0xac, 0x44, 0x0a, 0x10, 0xfe, 0x43, 0x00, 0xfe, 0x96, - 0x10, 0x08, 0x54, 0x0a, 0x37, 0x01, 0xf5, 0x01, 0xf6, 0x64, 0x12, 0x2f, - 0x01, 0x73, 0x99, 0x0a, 0x64, 0x42, 0x92, 0x02, 0xfe, 0x2e, 0x03, 0x08, - 0x05, 0x0a, 0x8a, 0x44, 0x0a, 0x10, 0x00, 0xfe, 0x5c, 0x10, 0x68, 0x05, - 0x1a, 0xfe, 0x58, 0x12, 0x08, 0x05, 0x1a, 0xfe, 0x50, 0x13, 0xfe, 0x1c, - 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x50, 0x0d, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, - 0xf0, 0xfe, 0x56, 0x0d, 0x08, 0x54, 0x1a, 0x37, 0xfe, 0xa9, 0x10, 0x10, - 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0a, 0x50, 0xfe, 0x2e, 0x10, 0x10, - 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10, 0x10, 0x6f, 0xab, 0x10, 0xfe, 0x41, - 0x00, 0xaa, 0x10, 0xfe, 0x24, 0x00, 0x8c, 0xb5, 0xb6, 0x74, 0x03, 0x70, - 0x28, 0x23, 0xd8, 0x50, 0xfe, 0x04, 0xe6, 0x1a, 0xfe, 0x9d, 0x41, 0xfe, - 0x1c, 0x42, 0x64, 0x01, 0xe3, 0x02, 0x2b, 0xf8, 0x15, 0x0a, 0x39, 0xa0, - 0xb4, 0x15, 0xfe, 0x31, 0x00, 0x39, 0xa2, 0x01, 0xfe, 0x48, 0x10, 0x02, - 0xd7, 0x42, 0xfe, 0x06, 0xec, 0xd0, 0xfc, 0x44, 0x1b, 0xfe, 0xce, 0x45, - 0x35, 0x42, 0xfe, 0x06, 0xea, 0xd0, 0xfe, 0x47, 0x4b, 0x91, 0xfe, 0x75, - 0x57, 0x03, 0x5d, 0xfe, 0x98, 0x56, 0xfe, 0x38, 0x12, 0x09, 0x48, 0x01, - 0x0e, 0xfe, 0x44, 0x48, 0x4f, 0x08, 0x05, 0x1b, 0xfe, 0x1a, 0x13, 0x09, - 0x46, 0x01, 0x0e, 0x41, 0xfe, 0x41, 0x58, 0x09, 0xa4, 0x01, 0x0e, 0xfe, - 0x49, 0x54, 0x96, 0xfe, 0x1e, 0x0e, 0x02, 0xfe, 0x2e, 0x03, 0x09, 0x5d, - 0xfe, 0xee, 0x14, 0xfc, 0x44, 0x1b, 0xfe, 0xce, 0x45, 0x35, 0x42, 0xfe, - 0xce, 0x47, 0xfe, 0xad, 0x13, 0x02, 0x2b, 0x22, 0x20, 0x07, 0x11, 0xfe, - 0x9e, 0x12, 0x21, 0x13, 0x59, 0x13, 0x9f, 0x13, 0xd5, 0x22, 0x2f, 0x41, - 0x39, 0x2f, 0xbc, 0xad, 0xfe, 0xbc, 0xf0, 0xfe, 0xe0, 0x0e, 0x0f, 0x06, - 0x13, 0x59, 0x01, 0xfe, 0xda, 0x16, 0x03, 0xfe, 0x38, 0x01, 0x29, 0xfe, - 0x3a, 0x01, 0x56, 0xfe, 0xe4, 0x0e, 0xfe, 0x02, 0xec, 0xd5, 0x69, 0x00, - 0x66, 0xfe, 0x04, 0xec, 0x20, 0x4f, 0xfe, 0x05, 0xf6, 0xfe, 0x34, 0x01, - 0x01, 0xfe, 0x4a, 0x17, 0xfe, 0x08, 0x90, 0xfe, 0x48, 0xf4, 0x0d, 0xfe, - 0x18, 0x13, 0xba, 0xfe, 0x02, 0xea, 0xd5, 0x69, 0x7e, 0xfe, 0xc5, 0x13, - 0x15, 0x1a, 0x39, 0xa0, 0xb4, 0xfe, 0x2e, 0x10, 0x03, 0xfe, 0x38, 0x01, - 0x1e, 0xfe, 0xf0, 0xff, 0x0c, 0xfe, 0x60, 0x01, 0x03, 0xfe, 0x3a, 0x01, - 0x0c, 0xfe, 0x62, 0x01, 0x43, 0x13, 0x20, 0x25, 0x06, 0x13, 0x2f, 0x12, - 0x2f, 0x92, 0x0f, 0x06, 0x04, 0x21, 0x04, 0x22, 0x59, 0xfe, 0xf7, 0x12, - 0x22, 0x9f, 0xb7, 0x13, 0x9f, 0x07, 0x7e, 0xfe, 0x71, 0x13, 0xfe, 0x24, - 0x1c, 0x15, 0x19, 0x39, 0xa0, 0xb4, 0xfe, 0xd9, 0x10, 0xc3, 0xfe, 0x03, - 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x04, 0xc3, 0xfe, 0x03, 0xdc, - 0xfe, 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x04, 0xfe, 0x03, 0x57, 0xc3, 0x21, - 0xfe, 0x00, 0xcc, 0x04, 0xfe, 0x03, 0x57, 0xc3, 0x78, 0x04, 0x08, 0x05, - 0x58, 0xfe, 0x22, 0x13, 0xfe, 0x1c, 0x80, 0x07, 0x06, 0xfe, 0x1a, 0x13, - 0xfe, 0x1e, 0x80, 0xed, 0xfe, 0x1d, 0x80, 0xae, 0xfe, 0x0c, 0x90, 0xfe, - 0x0e, 0x13, 0xfe, 0x0e, 0x90, 0xac, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4, - 0x0a, 0xfe, 0x3c, 0x50, 0xaa, 0x01, 0xfe, 0x7a, 0x17, 0x32, 0x07, 0x2f, - 0xad, 0x01, 0xfe, 0xb4, 0x16, 0x08, 0x05, 0x1b, 0x4e, 0x01, 0xf5, 0x01, - 0xf6, 0x12, 0xfe, 0xe9, 0x00, 0x08, 0x05, 0x58, 0xfe, 0x2c, 0x13, 0x01, - 0xfe, 0x0c, 0x17, 0xfe, 0x1e, 0x1c, 0xfe, 0x14, 0x90, 0xfe, 0x96, 0x90, - 0x0c, 0xfe, 0x64, 0x01, 0x14, 0xfe, 0x66, 0x01, 0x08, 0x05, 0x5b, 0xfe, - 0x12, 0x12, 0xfe, 0x03, 0x80, 0x8d, 0xfe, 0x01, 0xec, 0x20, 0xfe, 0x80, - 0x40, 0x13, 0x20, 0x6a, 0x2a, 0x12, 0xcf, 0x64, 0x22, 0x20, 0xfb, 0x79, - 0x20, 0x04, 0xfe, 0x08, 0x1c, 0x03, 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58, - 0x03, 0xfe, 0xae, 0x00, 0xfe, 0x07, 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, - 0x08, 0x58, 0x03, 0xfe, 0xb2, 0x00, 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c, - 0x25, 0x6e, 0x13, 0xd0, 0x21, 0x0c, 0x5c, 0x0c, 0x45, 0x0f, 0x46, 0x52, - 0x50, 0x18, 0x1b, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x23, 0xfe, 0xfc, - 0x0f, 0x44, 0x11, 0x0f, 0x48, 0x52, 0x18, 0x58, 0xfe, 0x90, 0x4d, 0xfe, - 0x91, 0x54, 0x23, 0xe4, 0x25, 0x11, 0x13, 0x20, 0x7c, 0x6f, 0x4f, 0x22, - 0x20, 0xfb, 0x79, 0x20, 0x12, 0xcf, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0, - 0xfe, 0x26, 0x10, 0xf8, 0x74, 0xfe, 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe, - 0x18, 0x1c, 0x04, 0x42, 0xfe, 0x0c, 0x14, 0xfc, 0xfe, 0x07, 0xe6, 0x1b, - 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x04, 0x01, 0xb0, 0x7c, 0x6f, 0x4f, - 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42, 0x13, 0x32, 0x07, 0x2f, - 0xfe, 0x34, 0x13, 0x09, 0x48, 0x01, 0x0e, 0xbb, 0xfe, 0x36, 0x12, 0xfe, - 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01, 0xf0, 0xfe, 0x00, 0xcc, 0xbb, 0xfe, - 0xf3, 0x13, 0x43, 0x78, 0x07, 0x11, 0xac, 0x09, 0x84, 0x01, 0x0e, 0xfe, - 0x80, 0x5c, 0x01, 0x73, 0xfe, 0x0e, 0x10, 0x07, 0x82, 0x4e, 0xfe, 0x14, - 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x60, 0x10, 0x04, 0xfe, 0x44, 0x58, 0x8d, - 0xfe, 0x01, 0xec, 0xa2, 0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, - 0x9c, 0xe7, 0x1a, 0x79, 0x2a, 0x01, 0xe3, 0xfe, 0xdd, 0x10, 0x2c, 0xc7, - 0x81, 0xc8, 0x83, 0x33, 0x31, 0xde, 0x07, 0x1a, 0xfe, 0x48, 0x12, 0x07, - 0x0a, 0xfe, 0x56, 0x12, 0x07, 0x19, 0xfe, 0x30, 0x12, 0x07, 0xc9, 0x17, - 0xfe, 0x32, 0x12, 0x07, 0xfe, 0x23, 0x00, 0x17, 0xeb, 0x07, 0x06, 0x17, - 0xfe, 0x9c, 0x12, 0x07, 0x1f, 0xfe, 0x12, 0x12, 0x07, 0x00, 0x17, 0x24, - 0x15, 0xc9, 0x01, 0x36, 0xa9, 0x2d, 0x01, 0x0b, 0x94, 0x4b, 0x04, 0x2d, - 0xdd, 0x09, 0xd1, 0x01, 0xfe, 0x26, 0x0f, 0x12, 0x82, 0x02, 0x2b, 0x2d, - 0x32, 0x07, 0xa6, 0xfe, 0xd9, 0x13, 0x3a, 0x3d, 0x3b, 0x3e, 0x56, 0xfe, - 0xf0, 0x11, 0x08, 0x05, 0x5a, 0xfe, 0x72, 0x12, 0x9b, 0x2e, 0x9c, 0x3c, - 0x90, 0xc0, 0x96, 0xfe, 0xba, 0x11, 0x22, 0x62, 0xfe, 0x26, 0x13, 0x03, - 0x7f, 0x29, 0x80, 0x56, 0xfe, 0x76, 0x0d, 0x0c, 0x60, 0x14, 0x61, 0x21, - 0x0c, 0x7f, 0x0c, 0x80, 0x01, 0xb3, 0x25, 0x6e, 0x77, 0x13, 0x62, 0x01, - 0xef, 0x9b, 0x2e, 0x9c, 0x3c, 0xfe, 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe, - 0x04, 0xfa, 0x2e, 0xfe, 0x05, 0xfa, 0x3c, 0xfe, 0x91, 0x10, 0x03, 0x3f, - 0x29, 0x40, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56, 0x0c, 0x3f, 0x14, 0x40, - 0x88, 0x9b, 0x2e, 0x9c, 0x3c, 0x90, 0xc0, 0x03, 0x5e, 0x29, 0x5f, 0xfe, - 0x00, 0x56, 0xfe, 0xa1, 0x56, 0x0c, 0x5e, 0x14, 0x5f, 0x08, 0x05, 0x5a, - 0xfe, 0x1e, 0x12, 0x22, 0x62, 0xfe, 0x1f, 0x40, 0x03, 0x60, 0x29, 0x61, - 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x03, 0x3f, 0x29, 0x40, 0xfe, 0x44, - 0x50, 0xfe, 0xc6, 0x50, 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x08, 0x50, 0xfe, - 0x8a, 0x50, 0x03, 0x3d, 0x29, 0x3e, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, - 0x02, 0x89, 0x25, 0x06, 0x13, 0xd4, 0x02, 0x72, 0x2d, 0x01, 0x0b, 0x1d, - 0x4c, 0x33, 0x31, 0xde, 0x07, 0x06, 0x23, 0x4c, 0x32, 0x07, 0xa6, 0x23, - 0x72, 0x01, 0xaf, 0x1e, 0x43, 0x17, 0x4c, 0x08, 0x05, 0x0a, 0xee, 0x3a, - 0x3d, 0x3b, 0x3e, 0xfe, 0x0a, 0x55, 0x35, 0xfe, 0x8b, 0x55, 0x57, 0x3d, - 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0x02, 0x72, 0xfe, 0x19, - 0x81, 0xba, 0xfe, 0x19, 0x41, 0x02, 0x72, 0x2d, 0x01, 0x0b, 0x1c, 0x34, - 0x1d, 0xe8, 0x33, 0x31, 0xe1, 0x55, 0x19, 0xfe, 0xa6, 0x12, 0x55, 0x0a, - 0x4d, 0x02, 0x4c, 0x01, 0x0b, 0x1c, 0x34, 0x1d, 0xe8, 0x33, 0x31, 0xdf, - 0x07, 0x19, 0x23, 0x4c, 0x01, 0x0b, 0x1d, 0xe8, 0x33, 0x31, 0xfe, 0xe8, - 0x09, 0xfe, 0xc2, 0x49, 0x51, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0x8a, 0x53, - 0x05, 0x1f, 0x35, 0xa9, 0xfe, 0xbb, 0x45, 0x55, 0x00, 0x4e, 0x44, 0x06, - 0x7c, 0x43, 0xfe, 0xda, 0x14, 0x01, 0xaf, 0x8c, 0xfe, 0x4b, 0x45, 0xee, - 0x32, 0x07, 0xa5, 0xed, 0x03, 0xcd, 0x28, 0x8a, 0x03, 0x45, 0x28, 0x35, - 0x67, 0x02, 0x72, 0xfe, 0xc0, 0x5d, 0xfe, 0xf8, 0x14, 0xfe, 0x03, 0x17, - 0x03, 0x5c, 0xc1, 0x0c, 0x5c, 0x67, 0x2d, 0x01, 0x0b, 0x26, 0x89, 0x01, - 0xfe, 0x9e, 0x15, 0x02, 0x89, 0x01, 0x0b, 0x1c, 0x34, 0x1d, 0x4c, 0x33, - 0x31, 0xdf, 0x07, 0x06, 0x23, 0x4c, 0x01, 0xf1, 0xfe, 0x42, 0x58, 0xf1, - 0xfe, 0xa4, 0x14, 0x8c, 0xfe, 0x4a, 0xf4, 0x0a, 0x17, 0x4c, 0xfe, 0x4a, - 0xf4, 0x06, 0xea, 0x32, 0x07, 0xa5, 0x8b, 0x02, 0x72, 0x03, 0x45, 0xc1, - 0x0c, 0x45, 0x67, 0x2d, 0x01, 0x0b, 0x26, 0x89, 0x01, 0xfe, 0xcc, 0x15, - 0x02, 0x89, 0x0f, 0x06, 0x27, 0xfe, 0xbe, 0x13, 0x26, 0xfe, 0xd4, 0x13, - 0x76, 0xfe, 0x89, 0x48, 0x01, 0x0b, 0x21, 0x76, 0x04, 0x7b, 0xfe, 0xd0, - 0x13, 0x1c, 0xfe, 0xd0, 0x13, 0x1d, 0xfe, 0xbe, 0x13, 0x67, 0x2d, 0x01, - 0x0b, 0xfe, 0xd5, 0x10, 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, - 0x1e, 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x04, 0x0f, - 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0xfe, 0x30, 0x56, - 0xfe, 0x00, 0x5c, 0x04, 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, - 0x04, 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0xfe, 0x0b, 0x58, - 0x04, 0x09, 0x5c, 0x01, 0x87, 0x09, 0x45, 0x01, 0x87, 0x04, 0xfe, 0x03, - 0xa1, 0x1e, 0x11, 0xff, 0x03, 0x00, 0x54, 0xfe, 0x00, 0xf4, 0x1f, 0x52, - 0xfe, 0x00, 0x7d, 0xfe, 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe, 0x03, 0x7c, - 0x6a, 0x2a, 0x0c, 0x5e, 0x14, 0x5f, 0x57, 0x3f, 0x7d, 0x40, 0x04, 0xdd, - 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x8d, 0x04, 0x01, - 0xfe, 0x0c, 0x19, 0xfe, 0x42, 0x48, 0x50, 0x51, 0x91, 0x01, 0x0b, 0x1d, - 0xfe, 0x96, 0x15, 0x33, 0x31, 0xe1, 0x01, 0x0b, 0x1d, 0xfe, 0x96, 0x15, - 0x33, 0x31, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, 0x03, 0xcd, 0x28, 0xfe, - 0xcc, 0x12, 0x53, 0x05, 0x1a, 0xfe, 0xc4, 0x13, 0x21, 0x69, 0x1a, 0xee, - 0x55, 0xca, 0x6b, 0xfe, 0xdc, 0x14, 0x4d, 0x0f, 0x06, 0x18, 0xca, 0x7c, - 0x30, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xab, 0xff, 0x02, 0x83, - 0x55, 0x69, 0x19, 0xae, 0x98, 0xfe, 0x30, 0x00, 0x96, 0xf2, 0x18, 0x6d, - 0x0f, 0x06, 0xfe, 0x56, 0x10, 0x69, 0x0a, 0xed, 0x98, 0xfe, 0x64, 0x00, - 0x96, 0xf2, 0x09, 0xfe, 0x64, 0x00, 0x18, 0x9e, 0x0f, 0x06, 0xfe, 0x28, - 0x10, 0x69, 0x06, 0xfe, 0x60, 0x13, 0x98, 0xfe, 0xc8, 0x00, 0x96, 0xf2, - 0x09, 0xfe, 0xc8, 0x00, 0x18, 0x59, 0x0f, 0x06, 0x88, 0x98, 0xfe, 0x90, - 0x01, 0x7a, 0xfe, 0x42, 0x15, 0x91, 0xe4, 0xfe, 0x43, 0xf4, 0x9f, 0xfe, - 0x56, 0xf0, 0xfe, 0x54, 0x15, 0xfe, 0x04, 0xf4, 0x71, 0xfe, 0x43, 0xf4, - 0x9e, 0xfe, 0xf3, 0x10, 0xfe, 0x40, 0x5c, 0x01, 0xfe, 0x16, 0x14, 0x1e, - 0x43, 0xec, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x6e, 0x7a, 0xfe, 0x90, - 0x15, 0xc4, 0x6e, 0xfe, 0x1c, 0x10, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, - 0xcc, 0x7a, 0xfe, 0x90, 0x15, 0xc4, 0xcc, 0x88, 0x51, 0x21, 0xfe, 0x4d, - 0xf4, 0x00, 0xe9, 0x91, 0x0f, 0x06, 0xfe, 0xb4, 0x56, 0xfe, 0xc3, 0x58, - 0x04, 0x51, 0x0f, 0x0a, 0x04, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xf3, 0x16, - 0x0a, 0x01, 0x0b, 0x26, 0xf3, 0x16, 0x19, 0x01, 0x0b, 0x26, 0xf3, 0x76, - 0xfe, 0x89, 0x49, 0x01, 0x0b, 0x04, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1, - 0x16, 0x19, 0x01, 0x0b, 0x26, 0xb1, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1, - 0xfe, 0x89, 0x49, 0x01, 0x0b, 0x26, 0xb1, 0x76, 0xfe, 0x89, 0x4a, 0x01, - 0x0b, 0x04, 0x51, 0x04, 0x22, 0xd3, 0x07, 0x06, 0xfe, 0x48, 0x13, 0xb8, - 0x13, 0xd3, 0xfe, 0x49, 0xf4, 0x00, 0x4d, 0x76, 0xa9, 0x67, 0xfe, 0x01, - 0xec, 0xfe, 0x27, 0x01, 0xfe, 0x89, 0x48, 0xff, 0x02, 0x00, 0x10, 0x27, - 0xfe, 0x2e, 0x16, 0x32, 0x07, 0xfe, 0xe3, 0x00, 0xfe, 0x20, 0x13, 0x1d, - 0xfe, 0x52, 0x16, 0x21, 0x13, 0xd4, 0x01, 0x4b, 0x22, 0xd4, 0x07, 0x06, - 0x4e, 0x08, 0x54, 0x06, 0x37, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfb, 0x8e, - 0x07, 0x11, 0xae, 0x09, 0x84, 0x01, 0x0e, 0x8e, 0x09, 0x5d, 0x01, 0xa8, - 0x04, 0x09, 0x84, 0x01, 0x0e, 0x8e, 0xfe, 0x80, 0xe7, 0x11, 0x07, 0x11, - 0x8a, 0xfe, 0x45, 0x58, 0x01, 0xf0, 0x8e, 0x04, 0x09, 0x48, 0x01, 0x0e, - 0x8e, 0x09, 0x5d, 0x01, 0xa8, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfe, 0x80, - 0x80, 0xfe, 0x80, 0x4c, 0xfe, 0x49, 0xe4, 0x11, 0xae, 0x09, 0x84, 0x01, - 0x0e, 0xfe, 0x80, 0x4c, 0x09, 0x5d, 0x01, 0x87, 0x04, 0x18, 0x11, 0x75, - 0x6c, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x24, - 0x1c, 0xfe, 0x1d, 0xf7, 0x1b, 0x97, 0xfe, 0xee, 0x16, 0x01, 0xfe, 0xf4, - 0x17, 0xad, 0x9a, 0x1b, 0x6c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x04, - 0xb9, 0x23, 0xfe, 0xde, 0x16, 0xfe, 0xda, 0x10, 0x18, 0x11, 0x75, 0x03, - 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x1f, 0xfe, 0x18, 0x58, 0x03, 0xfe, - 0x66, 0x01, 0xfe, 0x19, 0x58, 0x9a, 0x1f, 0xfe, 0x3c, 0x90, 0xfe, 0x30, - 0xf4, 0x06, 0xfe, 0x3c, 0x50, 0x6c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, - 0xfe, 0x1c, 0xf7, 0x1f, 0x97, 0xfe, 0x38, 0x17, 0xfe, 0xb6, 0x14, 0x35, - 0x04, 0xb9, 0x23, 0xfe, 0x10, 0x17, 0xfe, 0x9c, 0x10, 0x18, 0x11, 0x75, - 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7, - 0x2e, 0x97, 0xfe, 0x5a, 0x17, 0xfe, 0x94, 0x14, 0xec, 0x9a, 0x2e, 0x6c, - 0x1a, 0xfe, 0xaf, 0x19, 0xfe, 0x98, 0xe7, 0x00, 0x04, 0xb9, 0x23, 0xfe, - 0x4e, 0x17, 0xfe, 0x6c, 0x10, 0x18, 0x11, 0x75, 0xfe, 0x30, 0xbc, 0xfe, - 0xb2, 0xbc, 0x9a, 0xcb, 0x6c, 0x1a, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, - 0xcb, 0x97, 0xfe, 0x92, 0x17, 0xfe, 0x5c, 0x14, 0x35, 0x04, 0xb9, 0x23, - 0xfe, 0x7e, 0x17, 0xfe, 0x42, 0x10, 0xfe, 0x02, 0xf6, 0x11, 0x75, 0xfe, - 0x18, 0xfe, 0x60, 0xfe, 0x19, 0xfe, 0x61, 0xfe, 0x03, 0xa1, 0xfe, 0x1d, - 0xf7, 0x5b, 0x97, 0xfe, 0xb8, 0x17, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13, - 0x9a, 0x5b, 0x41, 0xfe, 0x83, 0x58, 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, - 0x11, 0xfe, 0x81, 0xe7, 0x11, 0x12, 0xfe, 0xdd, 0x00, 0x6a, 0x2a, 0x04, - 0x6a, 0x2a, 0xfe, 0x12, 0x45, 0x23, 0xfe, 0xa8, 0x17, 0x15, 0x06, 0x39, - 0xa0, 0xb4, 0x02, 0x2b, 0xfe, 0x39, 0xf0, 0xfe, 0xfc, 0x17, 0x21, 0x04, - 0xfe, 0x7e, 0x18, 0x1e, 0x19, 0x66, 0x0f, 0x0d, 0x04, 0x75, 0x03, 0xd2, - 0x1e, 0x06, 0xfe, 0xef, 0x12, 0xfe, 0xe1, 0x10, 0x7c, 0x6f, 0x4f, 0x32, - 0x07, 0x2f, 0xfe, 0x3c, 0x13, 0xf1, 0xfe, 0x42, 0x13, 0x42, 0x92, 0x09, - 0x48, 0x01, 0x0e, 0xbb, 0xeb, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01, - 0xf0, 0xfe, 0x00, 0xcc, 0xbb, 0xfe, 0xf3, 0x13, 0x43, 0x78, 0x07, 0x11, - 0xac, 0x09, 0x84, 0x01, 0x0e, 0xfe, 0x80, 0x4c, 0x01, 0x73, 0xfe, 0x16, - 0x10, 0x07, 0x82, 0x8b, 0xfe, 0x40, 0x14, 0xfe, 0x24, 0x12, 0xfe, 0x14, - 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x1c, 0x18, 0x18, 0x0a, 0x04, 0xfe, 0x9c, - 0xe7, 0x0a, 0x10, 0xfe, 0x15, 0x00, 0x64, 0x79, 0x2a, 0x01, 0xe3, 0x18, - 0x06, 0x04, 0x42, 0x92, 0x08, 0x54, 0x1b, 0x37, 0x12, 0x2f, 0x01, 0x73, - 0x18, 0x06, 0x04, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, 0x3a, 0xce, 0x3b, - 0xcf, 0xfe, 0x48, 0x55, 0x35, 0xfe, 0xc9, 0x55, 0x04, 0x22, 0xa3, 0x77, - 0x13, 0xa3, 0x04, 0x09, 0xa4, 0x01, 0x0e, 0xfe, 0x41, 0x48, 0x09, 0x46, - 0x01, 0x0e, 0xfe, 0x49, 0x44, 0x17, 0xfe, 0xe8, 0x18, 0x77, 0x78, 0x04, - 0x09, 0x48, 0x01, 0x0e, 0x07, 0x11, 0x4e, 0x09, 0x5d, 0x01, 0xa8, 0x09, - 0x46, 0x01, 0x0e, 0x77, 0x78, 0x04, 0xfe, 0x4e, 0xe4, 0x19, 0x6b, 0xfe, - 0x1c, 0x19, 0x03, 0xfe, 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, - 0xfe, 0x4e, 0xe4, 0xc9, 0x6b, 0xfe, 0x2e, 0x19, 0x03, 0xfe, 0x92, 0x00, - 0xfe, 0x02, 0xe6, 0x1a, 0xe5, 0xfe, 0x4e, 0xe4, 0xfe, 0x0b, 0x00, 0x6b, - 0xfe, 0x40, 0x19, 0x03, 0xfe, 0x94, 0x00, 0xfe, 0x02, 0xe6, 0x1f, 0xfe, - 0x08, 0x10, 0x03, 0xfe, 0x96, 0x00, 0xfe, 0x02, 0xe6, 0x6d, 0xfe, 0x4e, - 0x45, 0xea, 0xba, 0xff, 0x04, 0x68, 0x54, 0xe7, 0x1e, 0x6e, 0xfe, 0x08, - 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c, 0xfe, 0x1a, 0xf4, 0xfe, 0x00, - 0x04, 0xea, 0xfe, 0x48, 0xf4, 0x19, 0x7a, 0xfe, 0x74, 0x19, 0x0f, 0x19, - 0x04, 0x07, 0x7e, 0xfe, 0x5a, 0xf0, 0xfe, 0x84, 0x19, 0x25, 0xfe, 0x09, - 0x00, 0xfe, 0x34, 0x10, 0x07, 0x1a, 0xfe, 0x5a, 0xf0, 0xfe, 0x92, 0x19, - 0x25, 0xca, 0xfe, 0x26, 0x10, 0x07, 0x19, 0x66, 0x25, 0x6d, 0xe5, 0x07, - 0x0a, 0x66, 0x25, 0x9e, 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x66, 0x25, 0x59, - 0xa9, 0xb8, 0x04, 0x15, 0xfe, 0x09, 0x00, 0x01, 0x36, 0xfe, 0x04, 0xfe, - 0x81, 0x03, 0x83, 0xfe, 0x40, 0x5c, 0x04, 0x1c, 0xf7, 0xfe, 0x14, 0xf0, - 0x0b, 0x27, 0xfe, 0xd6, 0x19, 0x1c, 0xf7, 0x7b, 0xf7, 0xfe, 0x82, 0xf0, - 0xfe, 0xda, 0x19, 0x04, 0xff, 0xcc, 0x00, 0x00, -}; - -static unsigned short _adv_asc38C0800_size = sizeof(_adv_asc38C0800_buf); /* 0x14E1 */ -static ADV_DCNT _adv_asc38C0800_chksum = 0x050D3FD8UL; /* Expanded little-endian checksum. */ - -/* Microcode buffer is kept after initialization for error recovery. */ -static unsigned char _adv_asc38C1600_buf[] = { - 0x00, 0x00, 0x00, 0xf2, 0x00, 0x16, 0x00, 0xfc, 0x00, 0x10, 0x00, 0xf0, - 0x18, 0xe4, 0x01, 0x00, 0x04, 0x1e, 0x48, 0xe4, 0x03, 0xf6, 0xf7, 0x13, - 0x2e, 0x1e, 0x02, 0x00, 0x07, 0x17, 0xc0, 0x5f, 0x00, 0xfa, 0xff, 0xff, - 0x04, 0x00, 0x00, 0xf6, 0x09, 0xe7, 0x82, 0xe7, 0x85, 0xf0, 0x86, 0xf0, - 0x4e, 0x10, 0x9e, 0xe7, 0xff, 0x00, 0x55, 0xf0, 0x01, 0xf6, 0x03, 0x00, - 0x98, 0x57, 0x01, 0xe6, 0x00, 0xea, 0x00, 0xec, 0x01, 0xfa, 0x18, 0xf4, - 0x08, 0x00, 0xf0, 0x1d, 0x38, 0x54, 0x32, 0xf0, 0x10, 0x00, 0xc2, 0x0e, - 0x1e, 0xf0, 0xd5, 0xf0, 0xbc, 0x00, 0x4b, 0xe4, 0x00, 0xe6, 0xb1, 0xf0, - 0xb4, 0x00, 0x02, 0x13, 0x3e, 0x1c, 0xc8, 0x47, 0x3e, 0x00, 0xd8, 0x01, - 0x06, 0x13, 0x0c, 0x1c, 0x5e, 0x1e, 0x00, 0x57, 0xc8, 0x57, 0x01, 0xfc, - 0xbc, 0x0e, 0xa2, 0x12, 0xb9, 0x54, 0x00, 0x80, 0x62, 0x0a, 0x5a, 0x12, - 0xc8, 0x15, 0x3e, 0x1e, 0x18, 0x40, 0xbd, 0x56, 0x03, 0xe6, 0x01, 0xea, - 0x5c, 0xf0, 0x0f, 0x00, 0x20, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12, - 0x04, 0x13, 0xbb, 0x55, 0x3c, 0x56, 0x3e, 0x57, 0x03, 0x58, 0x4a, 0xe4, - 0x40, 0x00, 0xb6, 0x00, 0xbb, 0x00, 0xc0, 0x00, 0x00, 0x01, 0x01, 0x01, - 0x3e, 0x01, 0x58, 0x0a, 0x44, 0x10, 0x0a, 0x12, 0x4c, 0x1c, 0x4e, 0x1c, - 0x02, 0x4a, 0x30, 0xe4, 0x05, 0xe6, 0x0c, 0x00, 0x3c, 0x00, 0x80, 0x00, - 0x24, 0x01, 0x3c, 0x01, 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01, - 0x74, 0x01, 0x76, 0x01, 0x78, 0x01, 0x7c, 0x01, 0xc6, 0x0e, 0x0c, 0x10, - 0xac, 0x12, 0xae, 0x12, 0x16, 0x1a, 0x32, 0x1c, 0x6e, 0x1e, 0x02, 0x48, - 0x3a, 0x55, 0xc9, 0x57, 0x02, 0xee, 0x5b, 0xf0, 0x03, 0xf7, 0x06, 0xf7, - 0x03, 0xfc, 0x06, 0x00, 0x1e, 0x00, 0xbe, 0x00, 0xe1, 0x00, 0x0c, 0x12, - 0x18, 0x1a, 0x70, 0x1a, 0x30, 0x1c, 0x38, 0x1c, 0x10, 0x44, 0x00, 0x4c, - 0xb0, 0x57, 0x40, 0x5c, 0x4d, 0xe4, 0x04, 0xea, 0x5d, 0xf0, 0xa7, 0xf0, - 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x09, 0x00, 0x19, 0x00, 0x32, 0x00, - 0x33, 0x00, 0x34, 0x00, 0x36, 0x00, 0x98, 0x00, 0x9e, 0x00, 0xcc, 0x00, - 0x20, 0x01, 0x4e, 0x01, 0x79, 0x01, 0x3c, 0x09, 0x68, 0x0d, 0x02, 0x10, - 0x04, 0x10, 0x3a, 0x10, 0x08, 0x12, 0x0a, 0x13, 0x40, 0x16, 0x50, 0x16, - 0x00, 0x17, 0x4a, 0x19, 0x00, 0x4e, 0x00, 0x54, 0x01, 0x58, 0x00, 0xdc, - 0x05, 0xf0, 0x09, 0xf0, 0x59, 0xf0, 0xb8, 0xf0, 0x48, 0xf4, 0x0e, 0xf7, - 0x0a, 0x00, 0x9b, 0x00, 0x9c, 0x00, 0xa4, 0x00, 0xb5, 0x00, 0xba, 0x00, - 0xd0, 0x00, 0xe7, 0x00, 0xf0, 0x03, 0x69, 0x08, 0xe9, 0x09, 0x5c, 0x0c, - 0xb6, 0x12, 0xbc, 0x19, 0xd8, 0x1b, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c, - 0x42, 0x1d, 0x08, 0x44, 0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, - 0x89, 0x48, 0x68, 0x54, 0x83, 0x55, 0x83, 0x59, 0x31, 0xe4, 0x02, 0xe6, - 0x07, 0xf0, 0x08, 0xf0, 0x0b, 0xf0, 0x0c, 0xf0, 0x4b, 0xf4, 0x04, 0xf8, - 0x05, 0xf8, 0x02, 0xfa, 0x03, 0xfa, 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00, - 0xa8, 0x00, 0xaa, 0x00, 0xb9, 0x00, 0xe0, 0x00, 0xe5, 0x00, 0x22, 0x01, - 0x26, 0x01, 0x60, 0x01, 0x7a, 0x01, 0x82, 0x01, 0xc8, 0x01, 0xca, 0x01, - 0x86, 0x02, 0x6a, 0x03, 0x18, 0x05, 0xb2, 0x07, 0x68, 0x08, 0x10, 0x0d, - 0x06, 0x10, 0x0a, 0x10, 0x0e, 0x10, 0x12, 0x10, 0x60, 0x10, 0xed, 0x10, - 0xf3, 0x10, 0x06, 0x12, 0x10, 0x12, 0x1e, 0x12, 0x0c, 0x13, 0x0e, 0x13, - 0x10, 0x13, 0xfe, 0x9c, 0xf0, 0x35, 0x05, 0xfe, 0xec, 0x0e, 0xff, 0x10, - 0x00, 0x00, 0xe9, 0xfe, 0x34, 0x1f, 0x00, 0xe8, 0xfe, 0x88, 0x01, 0xff, - 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00, - 0x00, 0xfe, 0x57, 0x24, 0x00, 0xfe, 0x4c, 0x00, 0x65, 0xff, 0x04, 0x00, - 0x00, 0x1a, 0xff, 0x09, 0x00, 0x00, 0xff, 0x08, 0x01, 0x01, 0xff, 0x08, - 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10, 0xff, 0xff, 0xff, 0x13, - 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00, - 0xfe, 0x04, 0xf7, 0xe8, 0x37, 0x7d, 0x0d, 0x01, 0xfe, 0x4a, 0x11, 0xfe, - 0x04, 0xf7, 0xe8, 0x7d, 0x0d, 0x51, 0x37, 0xfe, 0x3d, 0xf0, 0xfe, 0x0c, - 0x02, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x91, 0xf0, 0xfe, 0xf8, 0x01, 0xfe, - 0x90, 0xf0, 0xfe, 0xf8, 0x01, 0xfe, 0x8f, 0xf0, 0xbc, 0x03, 0x67, 0x4d, - 0x05, 0xfe, 0x08, 0x0f, 0x01, 0xfe, 0x78, 0x0f, 0xfe, 0xdd, 0x12, 0x05, - 0xfe, 0x0e, 0x03, 0xfe, 0x28, 0x1c, 0x03, 0xfe, 0xa6, 0x00, 0xfe, 0xd1, - 0x12, 0x3e, 0x22, 0xfe, 0xa6, 0x00, 0xac, 0xfe, 0x48, 0xf0, 0xfe, 0x90, - 0x02, 0xfe, 0x49, 0xf0, 0xfe, 0xaa, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc8, - 0x02, 0xfe, 0x46, 0xf0, 0xfe, 0x5a, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x60, - 0x02, 0xfe, 0x43, 0xf0, 0xfe, 0x4e, 0x02, 0xfe, 0x44, 0xf0, 0xfe, 0x52, - 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x56, 0x02, 0x1c, 0x0d, 0xa2, 0x1c, 0x07, - 0x22, 0xb7, 0x05, 0x35, 0xfe, 0x00, 0x1c, 0xfe, 0xf1, 0x10, 0xfe, 0x02, - 0x1c, 0xf5, 0xfe, 0x1e, 0x1c, 0xfe, 0xe9, 0x10, 0x01, 0x5f, 0xfe, 0xe7, - 0x10, 0xfe, 0x06, 0xfc, 0xde, 0x0a, 0x81, 0x01, 0xa3, 0x05, 0x35, 0x1f, - 0x95, 0x47, 0xb8, 0x01, 0xfe, 0xe4, 0x11, 0x0a, 0x81, 0x01, 0x5c, 0xfe, - 0xbd, 0x10, 0x0a, 0x81, 0x01, 0x5c, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, - 0xfe, 0x58, 0x1c, 0x1c, 0x07, 0x22, 0xb7, 0x37, 0x2a, 0x35, 0xfe, 0x3d, - 0xf0, 0xfe, 0x0c, 0x02, 0x2b, 0xfe, 0x9e, 0x02, 0xfe, 0x5a, 0x1c, 0xfe, - 0x12, 0x1c, 0xfe, 0x14, 0x1c, 0x1f, 0xfe, 0x30, 0x00, 0x47, 0xb8, 0x01, - 0xfe, 0xd4, 0x11, 0x1c, 0x07, 0x22, 0xb7, 0x05, 0xe9, 0x21, 0x2c, 0x09, - 0x1a, 0x31, 0xfe, 0x69, 0x10, 0x1c, 0x07, 0x22, 0xb7, 0xfe, 0x04, 0xec, - 0x2c, 0x60, 0x01, 0xfe, 0x1e, 0x1e, 0x20, 0x2c, 0xfe, 0x05, 0xf6, 0xde, - 0x01, 0xfe, 0x62, 0x1b, 0x01, 0x0c, 0x61, 0x4a, 0x44, 0x15, 0x56, 0x51, - 0x01, 0xfe, 0x9e, 0x1e, 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x0a, 0x57, - 0x01, 0x18, 0x09, 0x00, 0x36, 0x01, 0x85, 0xfe, 0x18, 0x10, 0xfe, 0x41, - 0x58, 0x0a, 0xba, 0x01, 0x18, 0xfe, 0xc8, 0x54, 0x7b, 0xfe, 0x1c, 0x03, - 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x37, 0x60, 0xfe, 0x02, 0xe8, 0x30, - 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43, 0xfe, 0x77, 0x57, 0xfe, 0x27, 0xf0, - 0xfe, 0xe4, 0x01, 0xfe, 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x40, - 0x1c, 0x2a, 0xeb, 0xfe, 0x26, 0xf0, 0xfe, 0x66, 0x03, 0xfe, 0xa0, 0xf0, - 0xfe, 0x54, 0x03, 0xfe, 0x11, 0xf0, 0xbc, 0xfe, 0xef, 0x10, 0xfe, 0x9f, - 0xf0, 0xfe, 0x74, 0x03, 0xfe, 0x46, 0x1c, 0x19, 0xfe, 0x11, 0x00, 0x05, - 0x70, 0x37, 0xfe, 0x48, 0x1c, 0xfe, 0x46, 0x1c, 0x01, 0x0c, 0x06, 0x28, - 0xfe, 0x18, 0x13, 0x26, 0x21, 0xb9, 0xc7, 0x20, 0xb9, 0x0a, 0x57, 0x01, - 0x18, 0xc7, 0x89, 0x01, 0xfe, 0xc8, 0x1a, 0x15, 0xe1, 0x2a, 0xeb, 0xfe, - 0x01, 0xf0, 0xeb, 0xfe, 0x82, 0xf0, 0xfe, 0xa4, 0x03, 0xfe, 0x9c, 0x32, - 0x15, 0xfe, 0xe4, 0x00, 0x2f, 0xfe, 0xb6, 0x03, 0x2a, 0x3c, 0x16, 0xfe, - 0xc6, 0x03, 0x01, 0x41, 0xfe, 0x06, 0xf0, 0xfe, 0xd6, 0x03, 0xaf, 0xa0, - 0xfe, 0x0a, 0xf0, 0xfe, 0xa2, 0x07, 0x05, 0x29, 0x03, 0x81, 0x1e, 0x1b, - 0xfe, 0x24, 0x05, 0x1f, 0x63, 0x01, 0x42, 0x8f, 0xfe, 0x70, 0x02, 0x05, - 0xea, 0xfe, 0x46, 0x1c, 0x37, 0x7d, 0x1d, 0xfe, 0x67, 0x1b, 0xfe, 0xbf, - 0x57, 0xfe, 0x77, 0x57, 0xfe, 0x48, 0x1c, 0x75, 0x01, 0xa6, 0x86, 0x0a, - 0x57, 0x01, 0x18, 0x09, 0x00, 0x1b, 0xec, 0x0a, 0xe1, 0x01, 0x18, 0x77, - 0x50, 0x40, 0x8d, 0x30, 0x03, 0x81, 0x1e, 0xf8, 0x1f, 0x63, 0x01, 0x42, - 0x8f, 0xfe, 0x70, 0x02, 0x05, 0xea, 0xd7, 0x99, 0xd8, 0x9c, 0x2a, 0x29, - 0x2f, 0xfe, 0x4e, 0x04, 0x16, 0xfe, 0x4a, 0x04, 0x7e, 0xfe, 0xa0, 0x00, - 0xfe, 0x9b, 0x57, 0xfe, 0x54, 0x12, 0x32, 0xff, 0x02, 0x00, 0x10, 0x01, - 0x08, 0x16, 0xfe, 0x02, 0x05, 0x32, 0x01, 0x08, 0x16, 0x29, 0x27, 0x25, - 0xee, 0xfe, 0x4c, 0x44, 0xfe, 0x58, 0x12, 0x50, 0xfe, 0x44, 0x48, 0x13, - 0x34, 0xfe, 0x4c, 0x54, 0x7b, 0xec, 0x60, 0x8d, 0x30, 0x01, 0xfe, 0x4e, - 0x1e, 0xfe, 0x48, 0x47, 0xfe, 0x7c, 0x13, 0x01, 0x0c, 0x06, 0x28, 0xfe, - 0x32, 0x13, 0x01, 0x43, 0x09, 0x9b, 0xfe, 0x68, 0x13, 0xfe, 0x26, 0x10, - 0x13, 0x34, 0xfe, 0x4c, 0x54, 0x7b, 0xec, 0x01, 0xfe, 0x4e, 0x1e, 0xfe, - 0x48, 0x47, 0xfe, 0x54, 0x13, 0x01, 0x0c, 0x06, 0x28, 0xa5, 0x01, 0x43, - 0x09, 0x9b, 0xfe, 0x40, 0x13, 0x01, 0x0c, 0x06, 0x28, 0xf9, 0x1f, 0x7f, - 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe, 0x0d, 0x00, 0x01, 0x42, 0x8f, - 0xfe, 0xa4, 0x0e, 0x05, 0x29, 0x32, 0x15, 0xfe, 0xe6, 0x00, 0x0f, 0xfe, - 0x1c, 0x90, 0x04, 0xfe, 0x9c, 0x93, 0x3a, 0x0b, 0x0e, 0x8b, 0x02, 0x1f, - 0x7f, 0x01, 0x42, 0x05, 0x35, 0xfe, 0x42, 0x5b, 0x7d, 0x1d, 0xfe, 0x46, - 0x59, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0x0f, 0xfe, 0x87, 0x80, 0x04, - 0xfe, 0x87, 0x83, 0xfe, 0xc9, 0x47, 0x0b, 0x0e, 0xd0, 0x65, 0x01, 0x0c, - 0x06, 0x0d, 0xfe, 0x98, 0x13, 0x0f, 0xfe, 0x20, 0x80, 0x04, 0xfe, 0xa0, - 0x83, 0x33, 0x0b, 0x0e, 0x09, 0x1d, 0xfe, 0x84, 0x12, 0x01, 0x38, 0x06, - 0x07, 0xfe, 0x70, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x1e, 0x1b, 0xfe, 0xda, - 0x05, 0xd0, 0x54, 0x01, 0x38, 0x06, 0x0d, 0xfe, 0x58, 0x13, 0x03, 0xfe, - 0xa0, 0x00, 0x1e, 0xfe, 0x50, 0x12, 0x5e, 0xff, 0x02, 0x00, 0x10, 0x2f, - 0xfe, 0x90, 0x05, 0x2a, 0x3c, 0xcc, 0xff, 0x02, 0x00, 0x10, 0x2f, 0xfe, - 0x9e, 0x05, 0x17, 0xfe, 0xf4, 0x05, 0x15, 0xfe, 0xe3, 0x00, 0x26, 0x01, - 0x38, 0xfe, 0x4a, 0xf0, 0xfe, 0xc0, 0x05, 0xfe, 0x49, 0xf0, 0xfe, 0xba, - 0x05, 0x71, 0x2e, 0xfe, 0x21, 0x00, 0xf1, 0x2e, 0xfe, 0x22, 0x00, 0xa2, - 0x2e, 0x4a, 0xfe, 0x09, 0x48, 0xff, 0x02, 0x00, 0x10, 0x2f, 0xfe, 0xd0, - 0x05, 0x17, 0xfe, 0xf4, 0x05, 0xfe, 0xe2, 0x08, 0x01, 0x38, 0x06, 0xfe, - 0x1c, 0x00, 0x4d, 0x01, 0xa7, 0x2e, 0x07, 0x20, 0xe4, 0x47, 0xfe, 0x27, - 0x01, 0x01, 0x0c, 0x06, 0x28, 0xfe, 0x24, 0x12, 0x3e, 0x01, 0x84, 0x1f, - 0x7f, 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe, 0x0d, 0x00, 0x01, 0x42, - 0x8f, 0xfe, 0xa4, 0x0e, 0x05, 0x29, 0x03, 0xe6, 0x1e, 0xfe, 0xca, 0x13, - 0x03, 0xb6, 0x1e, 0xfe, 0x40, 0x12, 0x03, 0x66, 0x1e, 0xfe, 0x38, 0x13, - 0x3e, 0x01, 0x84, 0x17, 0xfe, 0x72, 0x06, 0x0a, 0x07, 0x01, 0x38, 0x06, - 0x24, 0xfe, 0x02, 0x12, 0x4f, 0x01, 0xfe, 0x56, 0x19, 0x16, 0xfe, 0x68, - 0x06, 0x15, 0x82, 0x01, 0x41, 0x15, 0xe2, 0x03, 0x66, 0x8a, 0x10, 0x66, - 0x03, 0x9a, 0x1e, 0xfe, 0x70, 0x12, 0x03, 0x55, 0x1e, 0xfe, 0x68, 0x13, - 0x01, 0xc6, 0x09, 0x12, 0x48, 0xfe, 0x92, 0x06, 0x2e, 0x12, 0x01, 0xfe, - 0xac, 0x1d, 0xfe, 0x43, 0x48, 0x62, 0x80, 0x13, 0x58, 0xff, 0x02, 0x00, - 0x57, 0x52, 0xad, 0x23, 0x3f, 0x4e, 0x62, 0x49, 0x3e, 0x01, 0x84, 0x17, - 0xfe, 0xea, 0x06, 0x01, 0x38, 0x06, 0x12, 0xf7, 0x45, 0x0a, 0x95, 0x01, - 0xfe, 0x84, 0x19, 0x16, 0xfe, 0xe0, 0x06, 0x15, 0x82, 0x01, 0x41, 0x15, - 0xe2, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x1c, 0x07, 0x01, 0x84, 0xfe, 0xae, - 0x10, 0x03, 0x6f, 0x1e, 0xfe, 0x9e, 0x13, 0x3e, 0x01, 0x84, 0x03, 0x9a, - 0x1e, 0xfe, 0x1a, 0x12, 0x01, 0x38, 0x06, 0x12, 0xfc, 0x01, 0xc6, 0x01, - 0xfe, 0xac, 0x1d, 0xfe, 0x43, 0x48, 0x62, 0x80, 0xf0, 0x45, 0x0a, 0x95, - 0x03, 0xb6, 0x1e, 0xf8, 0x01, 0x38, 0x06, 0x24, 0x36, 0xfe, 0x02, 0xf6, - 0x07, 0x71, 0x78, 0x8c, 0x00, 0x4d, 0x62, 0x49, 0x3e, 0x2d, 0x93, 0x4e, - 0xd0, 0x0d, 0x17, 0xfe, 0x9a, 0x07, 0x01, 0xfe, 0xc0, 0x19, 0x16, 0xfe, - 0x90, 0x07, 0x26, 0x20, 0x9e, 0x15, 0x82, 0x01, 0x41, 0x15, 0xe2, 0x21, - 0x9e, 0x09, 0x07, 0xfb, 0x03, 0xe6, 0xfe, 0x58, 0x57, 0x10, 0xe6, 0x05, - 0xfe, 0x2a, 0x06, 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x1c, 0x07, 0x01, 0x84, - 0xfe, 0x9c, 0x32, 0x5f, 0x75, 0x01, 0xa6, 0x86, 0x15, 0xfe, 0xe2, 0x00, - 0x2f, 0xed, 0x2a, 0x3c, 0xfe, 0x0a, 0xf0, 0xfe, 0xce, 0x07, 0xae, 0xfe, - 0x96, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x9e, 0x08, 0xaf, 0xa0, 0x05, 0x29, - 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x2e, 0x12, 0x14, 0x1d, 0x01, 0x08, 0x14, - 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0xfe, - 0x99, 0xa4, 0x01, 0x08, 0x14, 0x00, 0x05, 0xfe, 0xc6, 0x09, 0x01, 0x76, - 0x06, 0x12, 0xfe, 0x3a, 0x12, 0x01, 0x0c, 0x06, 0x12, 0xfe, 0x30, 0x13, - 0x14, 0xfe, 0x1b, 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, 0x00, - 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, 0x07, 0x01, 0x08, 0x14, 0x00, - 0x05, 0xef, 0x7c, 0x4a, 0x78, 0x4f, 0x0f, 0xfe, 0x9a, 0x81, 0x04, 0xfe, - 0x9a, 0x83, 0xfe, 0xcb, 0x47, 0x0b, 0x0e, 0x2d, 0x28, 0x48, 0xfe, 0x6c, - 0x08, 0x0a, 0x28, 0xfe, 0x09, 0x6f, 0xca, 0xfe, 0xca, 0x45, 0xfe, 0x32, - 0x12, 0x53, 0x63, 0x4e, 0x7c, 0x97, 0x2f, 0xfe, 0x7e, 0x08, 0x2a, 0x3c, - 0xfe, 0x0a, 0xf0, 0xfe, 0x6c, 0x08, 0xaf, 0xa0, 0xae, 0xfe, 0x96, 0x08, - 0x05, 0x29, 0x01, 0x41, 0x05, 0xed, 0x14, 0x24, 0x05, 0xed, 0xfe, 0x9c, - 0xf7, 0x9f, 0x01, 0xfe, 0xae, 0x1e, 0xfe, 0x18, 0x58, 0x01, 0xfe, 0xbe, - 0x1e, 0xfe, 0x99, 0x58, 0xfe, 0x78, 0x18, 0xfe, 0xf9, 0x18, 0x8e, 0xfe, - 0x16, 0x09, 0x10, 0x6a, 0x22, 0x6b, 0x01, 0x0c, 0x61, 0x54, 0x44, 0x21, - 0x2c, 0x09, 0x1a, 0xf8, 0x77, 0x01, 0xfe, 0x7e, 0x1e, 0x47, 0x2c, 0x7a, - 0x30, 0xf0, 0xfe, 0x83, 0xe7, 0xfe, 0x3f, 0x00, 0x71, 0xfe, 0x03, 0x40, - 0x01, 0x0c, 0x61, 0x65, 0x44, 0x01, 0xc2, 0xc8, 0xfe, 0x1f, 0x40, 0x20, - 0x6e, 0x01, 0xfe, 0x6a, 0x16, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe, - 0x44, 0x51, 0xfe, 0xc6, 0x51, 0xfe, 0x10, 0x10, 0x01, 0xfe, 0xce, 0x1e, - 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x01, 0xfe, 0xee, 0x1e, - 0x01, 0xfe, 0xfe, 0x1e, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x10, 0x4b, - 0x22, 0x4c, 0xfe, 0x8a, 0x10, 0x01, 0x0c, 0x06, 0x54, 0xfe, 0x50, 0x12, - 0x01, 0xfe, 0xae, 0x1e, 0x01, 0xfe, 0xbe, 0x1e, 0x10, 0x6a, 0x22, 0x6b, - 0x01, 0x0c, 0x06, 0x65, 0x4e, 0x01, 0xc2, 0x0f, 0xfe, 0x1f, 0x80, 0x04, - 0xfe, 0x9f, 0x83, 0x33, 0x0b, 0x0e, 0x20, 0x6e, 0x0f, 0xfe, 0x44, 0x90, - 0x04, 0xfe, 0xc4, 0x93, 0x3a, 0x0b, 0xfe, 0xc6, 0x90, 0x04, 0xfe, 0xc6, - 0x93, 0x79, 0x0b, 0x0e, 0x10, 0x6c, 0x22, 0x6d, 0x01, 0xfe, 0xce, 0x1e, - 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x0f, 0xfe, 0x40, 0x90, - 0x04, 0xfe, 0xc0, 0x93, 0x3a, 0x0b, 0xfe, 0xc2, 0x90, 0x04, 0xfe, 0xc2, - 0x93, 0x79, 0x0b, 0x0e, 0x10, 0x4b, 0x22, 0x4c, 0x10, 0x64, 0x22, 0x34, - 0x01, 0x0c, 0x61, 0x24, 0x44, 0x37, 0x13, 0xfe, 0x4e, 0x11, 0x2f, 0xfe, - 0xde, 0x09, 0xfe, 0x9e, 0xf0, 0xfe, 0xf2, 0x09, 0xfe, 0x01, 0x48, 0x1b, - 0x3c, 0x37, 0x88, 0xf5, 0xd4, 0xfe, 0x1e, 0x0a, 0xd5, 0xfe, 0x42, 0x0a, - 0xd2, 0xfe, 0x1e, 0x0a, 0xd3, 0xfe, 0x42, 0x0a, 0xae, 0xfe, 0x12, 0x0a, - 0xfe, 0x06, 0xf0, 0xfe, 0x18, 0x0a, 0xaf, 0xa0, 0x05, 0x29, 0x01, 0x41, - 0xfe, 0xc1, 0x10, 0x14, 0x24, 0xfe, 0xc1, 0x10, 0x01, 0x76, 0x06, 0x07, - 0xfe, 0x14, 0x12, 0x01, 0x76, 0x06, 0x0d, 0x5d, 0x01, 0x0c, 0x06, 0x0d, - 0xfe, 0x74, 0x12, 0xfe, 0x2e, 0x1c, 0x05, 0xfe, 0x1a, 0x0c, 0x01, 0x76, - 0x06, 0x07, 0x5d, 0x01, 0x76, 0x06, 0x0d, 0x41, 0xfe, 0x2c, 0x1c, 0xfe, - 0xaa, 0xf0, 0xfe, 0xce, 0x0a, 0xfe, 0xac, 0xf0, 0xfe, 0x66, 0x0a, 0xfe, - 0x92, 0x10, 0xc4, 0xf6, 0xfe, 0xad, 0xf0, 0xfe, 0x72, 0x0a, 0x05, 0xfe, - 0x1a, 0x0c, 0xc5, 0xfe, 0xe7, 0x10, 0xfe, 0x2b, 0xf0, 0xbf, 0xfe, 0x6b, - 0x18, 0x23, 0xfe, 0x00, 0xfe, 0xfe, 0x1c, 0x12, 0xac, 0xfe, 0xd2, 0xf0, - 0xbf, 0xfe, 0x76, 0x18, 0x23, 0x1d, 0x1b, 0xbf, 0x03, 0xe3, 0x23, 0x07, - 0x1b, 0xbf, 0xd4, 0x5b, 0xd5, 0x5b, 0xd2, 0x5b, 0xd3, 0x5b, 0xc4, 0xc5, - 0xfe, 0xa9, 0x10, 0x75, 0x5e, 0x32, 0x1f, 0x7f, 0x01, 0x42, 0x19, 0xfe, - 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x70, 0x19, 0x98, 0x05, 0x70, 0xfe, 0x74, - 0x18, 0x23, 0xfe, 0x00, 0xf8, 0x1b, 0x5b, 0x7d, 0x12, 0x01, 0xfe, 0x78, - 0x0f, 0x4d, 0x01, 0xfe, 0x96, 0x1a, 0x21, 0x30, 0x77, 0x7d, 0x1d, 0x05, - 0x5b, 0x01, 0x0c, 0x06, 0x0d, 0x2b, 0xfe, 0xe2, 0x0b, 0x01, 0x0c, 0x06, - 0x54, 0xfe, 0xa6, 0x12, 0x01, 0x0c, 0x06, 0x24, 0xfe, 0x88, 0x13, 0x21, - 0x6e, 0xc7, 0x01, 0xfe, 0x1e, 0x1f, 0x0f, 0xfe, 0x83, 0x80, 0x04, 0xfe, - 0x83, 0x83, 0xfe, 0xc9, 0x47, 0x0b, 0x0e, 0xfe, 0xc8, 0x44, 0xfe, 0x42, - 0x13, 0x0f, 0xfe, 0x04, 0x91, 0x04, 0xfe, 0x84, 0x93, 0xfe, 0xca, 0x57, - 0x0b, 0xfe, 0x86, 0x91, 0x04, 0xfe, 0x86, 0x93, 0xfe, 0xcb, 0x57, 0x0b, - 0x0e, 0x7a, 0x30, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x8e, 0x40, 0x03, - 0x6a, 0x3b, 0x6b, 0x10, 0x97, 0x22, 0x98, 0xd9, 0x6a, 0xda, 0x6b, 0x01, - 0xc2, 0xc8, 0x7a, 0x30, 0x20, 0x6e, 0xdb, 0x64, 0xdc, 0x34, 0x91, 0x6c, - 0x7e, 0x6d, 0xfe, 0x44, 0x55, 0xfe, 0xe5, 0x55, 0xfe, 0x04, 0xfa, 0x64, - 0xfe, 0x05, 0xfa, 0x34, 0x01, 0xfe, 0x6a, 0x16, 0xa3, 0x26, 0x10, 0x97, - 0x10, 0x98, 0x91, 0x6c, 0x7e, 0x6d, 0xfe, 0x14, 0x10, 0x01, 0x0c, 0x06, - 0x24, 0x1b, 0x40, 0x91, 0x4b, 0x7e, 0x4c, 0x01, 0x0c, 0x06, 0xfe, 0xf7, - 0x00, 0x44, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, - 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x05, 0x5b, 0x01, 0x0c, 0x06, 0x24, - 0x1b, 0x40, 0x01, 0x0c, 0x06, 0xfe, 0xf7, 0x00, 0x44, 0x78, 0x01, 0xfe, - 0x8e, 0x1e, 0x4f, 0x0f, 0xfe, 0x10, 0x90, 0x04, 0xfe, 0x90, 0x93, 0x3a, - 0x0b, 0xfe, 0x92, 0x90, 0x04, 0xfe, 0x92, 0x93, 0x79, 0x0b, 0x0e, 0xfe, - 0xbd, 0x10, 0x01, 0x43, 0x09, 0xbb, 0x1b, 0xfe, 0x6e, 0x0a, 0x15, 0xbb, - 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x14, 0x13, 0x03, 0x4b, 0x3b, 0x4c, 0x8e, - 0xfe, 0x6e, 0x0a, 0xfe, 0x0c, 0x58, 0xfe, 0x8d, 0x58, 0x05, 0x5b, 0x26, - 0x3e, 0x0f, 0xfe, 0x19, 0x80, 0x04, 0xfe, 0x99, 0x83, 0x33, 0x0b, 0x0e, - 0xfe, 0xe5, 0x10, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1a, 0x12, 0xfe, 0x6c, - 0x19, 0xfe, 0x19, 0x41, 0xfe, 0x6b, 0x18, 0xac, 0xfe, 0xd1, 0xf0, 0xef, - 0x1f, 0x92, 0x01, 0x42, 0x19, 0xfe, 0x44, 0x00, 0xfe, 0x90, 0x10, 0xfe, - 0x6c, 0x19, 0xd9, 0x4b, 0xfe, 0xed, 0x19, 0xda, 0x4c, 0xfe, 0x0c, 0x51, - 0xfe, 0x8e, 0x51, 0xfe, 0x6b, 0x18, 0x23, 0xfe, 0x00, 0xff, 0x31, 0xfe, - 0x76, 0x10, 0xac, 0xfe, 0xd2, 0xf0, 0xfe, 0xba, 0x0c, 0xfe, 0x76, 0x18, - 0x23, 0x1d, 0x5d, 0x03, 0xe3, 0x23, 0x07, 0xfe, 0x08, 0x13, 0x19, 0xfe, - 0x16, 0x00, 0x05, 0x70, 0xfe, 0xd1, 0xf0, 0xfe, 0xcc, 0x0c, 0x1f, 0x92, - 0x01, 0x42, 0x19, 0xfe, 0x17, 0x00, 0x5c, 0xfe, 0xce, 0xf0, 0xfe, 0xd2, - 0x0c, 0xfe, 0x3e, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xde, 0x0c, 0x19, 0xfe, - 0x22, 0x00, 0x05, 0x70, 0xfe, 0xcb, 0xf0, 0xfe, 0xea, 0x0c, 0x19, 0xfe, - 0x24, 0x00, 0x05, 0x70, 0xfe, 0xd0, 0xf0, 0xfe, 0xf4, 0x0c, 0x19, 0x94, - 0xfe, 0x1c, 0x10, 0xfe, 0xcf, 0xf0, 0xfe, 0xfe, 0x0c, 0x19, 0x4a, 0xf3, - 0xfe, 0xcc, 0xf0, 0xef, 0x01, 0x76, 0x06, 0x24, 0x4d, 0x19, 0xfe, 0x12, - 0x00, 0x37, 0x13, 0xfe, 0x4e, 0x11, 0x2f, 0xfe, 0x16, 0x0d, 0xfe, 0x9e, - 0xf0, 0xfe, 0x2a, 0x0d, 0xfe, 0x01, 0x48, 0x1b, 0x3c, 0x37, 0x88, 0xf5, - 0xd4, 0x29, 0xd5, 0x29, 0xd2, 0x29, 0xd3, 0x29, 0x37, 0xfe, 0x9c, 0x32, - 0x2f, 0xfe, 0x3e, 0x0d, 0x2a, 0x3c, 0xae, 0xfe, 0x62, 0x0d, 0xaf, 0xa0, - 0xd4, 0x9f, 0xd5, 0x9f, 0xd2, 0x9f, 0xd3, 0x9f, 0x05, 0x29, 0x01, 0x41, - 0xfe, 0xd3, 0x10, 0x15, 0xfe, 0xe8, 0x00, 0xc4, 0xc5, 0x75, 0xd7, 0x99, - 0xd8, 0x9c, 0xfe, 0x89, 0xf0, 0x29, 0x27, 0x25, 0xbe, 0xd7, 0x99, 0xd8, - 0x9c, 0x2f, 0xfe, 0x8c, 0x0d, 0x16, 0x29, 0x27, 0x25, 0xbd, 0xfe, 0x01, - 0x48, 0xa4, 0x19, 0xfe, 0x42, 0x00, 0x05, 0x70, 0x90, 0x07, 0xfe, 0x81, - 0x49, 0x1b, 0xfe, 0x64, 0x0e, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x44, 0x13, - 0x19, 0x00, 0x2d, 0x0d, 0xfe, 0x54, 0x12, 0x2d, 0xfe, 0x28, 0x00, 0x2b, - 0xfe, 0xda, 0x0e, 0x0a, 0x57, 0x01, 0x18, 0x09, 0x00, 0x36, 0x46, 0xfe, - 0x28, 0x00, 0xfe, 0xfa, 0x10, 0x01, 0xfe, 0xf4, 0x1c, 0x01, 0xfe, 0x00, - 0x1d, 0x0a, 0xba, 0x01, 0xfe, 0x58, 0x10, 0x40, 0x15, 0x56, 0x01, 0x85, - 0x05, 0x35, 0x19, 0xfe, 0x44, 0x00, 0x2d, 0x0d, 0xf7, 0x46, 0x0d, 0xfe, - 0xcc, 0x10, 0x01, 0xa7, 0x46, 0x0d, 0xfe, 0xc2, 0x10, 0x01, 0xa7, 0x0f, - 0xfe, 0x19, 0x82, 0x04, 0xfe, 0x99, 0x83, 0xfe, 0xcc, 0x47, 0x0b, 0x0e, - 0xfe, 0x34, 0x46, 0xa5, 0x46, 0x0d, 0x19, 0xfe, 0x43, 0x00, 0xfe, 0xa2, - 0x10, 0x01, 0x0c, 0x61, 0x0d, 0x44, 0x01, 0xfe, 0xf4, 0x1c, 0x01, 0xfe, - 0x00, 0x1d, 0x40, 0x15, 0x56, 0x01, 0x85, 0x7d, 0x0d, 0x40, 0x51, 0x01, - 0xfe, 0x9e, 0x1e, 0x05, 0xfe, 0x3a, 0x03, 0x01, 0x0c, 0x06, 0x0d, 0x5d, - 0x46, 0x0d, 0x19, 0x00, 0xfe, 0x62, 0x10, 0x01, 0x76, 0x06, 0x12, 0xfe, - 0x5c, 0x12, 0x01, 0x0c, 0x06, 0x12, 0xfe, 0x52, 0x13, 0xfe, 0x1c, 0x1c, - 0xfe, 0x9d, 0xf0, 0xfe, 0x8e, 0x0e, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, - 0xfe, 0x94, 0x0e, 0x01, 0x0c, 0x61, 0x12, 0x44, 0xfe, 0x9f, 0x10, 0x19, - 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0d, 0x4f, 0xfe, 0x2e, 0x10, 0x19, - 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10, 0x19, 0xfe, 0x47, 0x00, 0xf1, 0x19, - 0xfe, 0x41, 0x00, 0xa2, 0x19, 0xfe, 0x24, 0x00, 0x86, 0xc4, 0xc5, 0x75, - 0x03, 0x81, 0x1e, 0x2b, 0xea, 0x4f, 0xfe, 0x04, 0xe6, 0x12, 0xfe, 0x9d, - 0x41, 0xfe, 0x1c, 0x42, 0x40, 0x01, 0xf4, 0x05, 0x35, 0xfe, 0x12, 0x1c, - 0x1f, 0x0d, 0x47, 0xb5, 0xc3, 0x1f, 0xfe, 0x31, 0x00, 0x47, 0xb8, 0x01, - 0xfe, 0xd4, 0x11, 0x05, 0xe9, 0x51, 0xfe, 0x06, 0xec, 0xe0, 0xfe, 0x0e, - 0x47, 0x46, 0x28, 0xfe, 0xce, 0x45, 0x31, 0x51, 0xfe, 0x06, 0xea, 0xe0, - 0xfe, 0x47, 0x4b, 0x45, 0xfe, 0x75, 0x57, 0x03, 0x67, 0xfe, 0x98, 0x56, - 0xfe, 0x38, 0x12, 0x0a, 0x5a, 0x01, 0x18, 0xfe, 0x44, 0x48, 0x60, 0x01, - 0x0c, 0x06, 0x28, 0xfe, 0x18, 0x13, 0x0a, 0x57, 0x01, 0x18, 0x3e, 0xfe, - 0x41, 0x58, 0x0a, 0xba, 0xfe, 0xfa, 0x14, 0xfe, 0x49, 0x54, 0xb0, 0xfe, - 0x5e, 0x0f, 0x05, 0xfe, 0x3a, 0x03, 0x0a, 0x67, 0xfe, 0xe0, 0x14, 0xfe, - 0x0e, 0x47, 0x46, 0x28, 0xfe, 0xce, 0x45, 0x31, 0x51, 0xfe, 0xce, 0x47, - 0xfe, 0xad, 0x13, 0x05, 0x35, 0x21, 0x2c, 0x09, 0x1a, 0xfe, 0x98, 0x12, - 0x26, 0x20, 0x96, 0x20, 0xe7, 0xfe, 0x08, 0x1c, 0xfe, 0x7c, 0x19, 0xfe, - 0xfd, 0x19, 0xfe, 0x0a, 0x1c, 0x03, 0xe5, 0xfe, 0x48, 0x55, 0xa5, 0x3b, - 0xfe, 0x62, 0x01, 0xfe, 0xc9, 0x55, 0x31, 0xfe, 0x74, 0x10, 0x01, 0xfe, - 0xf0, 0x1a, 0x03, 0xfe, 0x38, 0x01, 0x3b, 0xfe, 0x3a, 0x01, 0x8e, 0xfe, - 0x1e, 0x10, 0xfe, 0x02, 0xec, 0xe7, 0x53, 0x00, 0x36, 0xfe, 0x04, 0xec, - 0x2c, 0x60, 0xfe, 0x05, 0xf6, 0xfe, 0x34, 0x01, 0x01, 0xfe, 0x62, 0x1b, - 0x01, 0xfe, 0xce, 0x1e, 0xb2, 0x11, 0xfe, 0x18, 0x13, 0xca, 0xfe, 0x02, - 0xea, 0xe7, 0x53, 0x92, 0xfe, 0xc3, 0x13, 0x1f, 0x12, 0x47, 0xb5, 0xc3, - 0xfe, 0x2a, 0x10, 0x03, 0xfe, 0x38, 0x01, 0x23, 0xfe, 0xf0, 0xff, 0x10, - 0xe5, 0x03, 0xfe, 0x3a, 0x01, 0x10, 0xfe, 0x62, 0x01, 0x01, 0xfe, 0x1e, - 0x1e, 0x20, 0x2c, 0x15, 0x56, 0x01, 0xfe, 0x9e, 0x1e, 0x13, 0x07, 0x02, - 0x26, 0x02, 0x21, 0x96, 0xc7, 0x20, 0x96, 0x09, 0x92, 0xfe, 0x79, 0x13, - 0x1f, 0x1d, 0x47, 0xb5, 0xc3, 0xfe, 0xe1, 0x10, 0xcf, 0xfe, 0x03, 0xdc, - 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xcf, 0xfe, 0x03, 0xdc, 0xfe, - 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xfe, 0x03, 0x57, 0xcf, 0x26, 0xfe, - 0x00, 0xcc, 0x02, 0xfe, 0x03, 0x57, 0xcf, 0x89, 0x02, 0x01, 0x0c, 0x06, - 0x4a, 0xfe, 0x4e, 0x13, 0x0f, 0xfe, 0x1c, 0x80, 0x04, 0xfe, 0x9c, 0x83, - 0x33, 0x0b, 0x0e, 0x09, 0x07, 0xfe, 0x3a, 0x13, 0x0f, 0xfe, 0x1e, 0x80, - 0x04, 0xfe, 0x9e, 0x83, 0x33, 0x0b, 0x0e, 0xfe, 0x2a, 0x13, 0x0f, 0xfe, - 0x1d, 0x80, 0x04, 0xfe, 0x9d, 0x83, 0xfe, 0xf9, 0x13, 0x0e, 0xfe, 0x1c, - 0x13, 0x01, 0xfe, 0xee, 0x1e, 0xac, 0xfe, 0x14, 0x13, 0x01, 0xfe, 0xfe, - 0x1e, 0xfe, 0x81, 0x58, 0xfa, 0x01, 0xfe, 0x0e, 0x1f, 0xfe, 0x30, 0xf4, - 0x0d, 0xfe, 0x3c, 0x50, 0xa2, 0x01, 0xfe, 0x92, 0x1b, 0x01, 0x43, 0x09, - 0x56, 0xfb, 0x01, 0xfe, 0xc8, 0x1a, 0x01, 0x0c, 0x06, 0x28, 0xa4, 0x01, - 0xfe, 0xf4, 0x1c, 0x01, 0xfe, 0x00, 0x1d, 0x15, 0xfe, 0xe9, 0x00, 0x01, - 0x0c, 0x06, 0x4a, 0xfe, 0x4e, 0x13, 0x01, 0xfe, 0x22, 0x1b, 0xfe, 0x1e, - 0x1c, 0x0f, 0xfe, 0x14, 0x90, 0x04, 0xfe, 0x94, 0x93, 0x3a, 0x0b, 0xfe, - 0x96, 0x90, 0x04, 0xfe, 0x96, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0xfe, 0x64, - 0x01, 0x22, 0xfe, 0x66, 0x01, 0x01, 0x0c, 0x06, 0x65, 0xf9, 0x0f, 0xfe, - 0x03, 0x80, 0x04, 0xfe, 0x83, 0x83, 0x33, 0x0b, 0x0e, 0x77, 0xfe, 0x01, - 0xec, 0x2c, 0xfe, 0x80, 0x40, 0x20, 0x2c, 0x7a, 0x30, 0x15, 0xdf, 0x40, - 0x21, 0x2c, 0xfe, 0x00, 0x40, 0x8d, 0x2c, 0x02, 0xfe, 0x08, 0x1c, 0x03, - 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58, 0x03, 0xfe, 0xae, 0x00, 0xfe, 0x07, - 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58, 0x03, 0xfe, 0xb2, 0x00, - 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c, 0x2e, 0x49, 0x20, 0xe0, 0x26, 0x10, - 0x66, 0x10, 0x55, 0x10, 0x6f, 0x13, 0x57, 0x52, 0x4f, 0x1c, 0x28, 0xfe, - 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x2b, 0xfe, 0x88, 0x11, 0x46, 0x1a, 0x13, - 0x5a, 0x52, 0x1c, 0x4a, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x2b, 0xfe, - 0x9e, 0x11, 0x2e, 0x1a, 0x20, 0x2c, 0x90, 0x34, 0x60, 0x21, 0x2c, 0xfe, - 0x00, 0x40, 0x8d, 0x2c, 0x15, 0xdf, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0, - 0xfe, 0xb2, 0x11, 0xfe, 0x12, 0x1c, 0x75, 0xfe, 0x14, 0x1c, 0xfe, 0x10, - 0x1c, 0xfe, 0x18, 0x1c, 0x02, 0x51, 0xfe, 0x0c, 0x14, 0xfe, 0x0e, 0x47, - 0xfe, 0x07, 0xe6, 0x28, 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x02, 0x01, - 0xa7, 0x90, 0x34, 0x60, 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42, - 0x13, 0xfe, 0x02, 0x80, 0x09, 0x56, 0xfe, 0x34, 0x13, 0x0a, 0x5a, 0x01, - 0x18, 0xcb, 0xfe, 0x36, 0x12, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01, - 0xfe, 0xb2, 0x16, 0xfe, 0x00, 0xcc, 0xcb, 0xfe, 0xf3, 0x13, 0x3f, 0x89, - 0x09, 0x1a, 0xa5, 0x0a, 0x9d, 0x01, 0x18, 0xfe, 0x80, 0x5c, 0x01, 0x85, - 0xf2, 0x09, 0x9b, 0xa4, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0xec, - 0x11, 0x02, 0xfe, 0x44, 0x58, 0x77, 0xfe, 0x01, 0xec, 0xb8, 0xfe, 0x9e, - 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x12, 0x8d, 0x30, 0x01, - 0xf4, 0xfe, 0xdd, 0x10, 0x37, 0xd7, 0x99, 0xd8, 0x9c, 0x27, 0x25, 0xee, - 0x09, 0x12, 0xfe, 0x48, 0x12, 0x09, 0x0d, 0xfe, 0x56, 0x12, 0x09, 0x1d, - 0xfe, 0x30, 0x12, 0x09, 0xdd, 0x1b, 0xfe, 0xc4, 0x13, 0x09, 0xfe, 0x23, - 0x00, 0x1b, 0xfe, 0xd0, 0x13, 0x09, 0x07, 0x1b, 0xfe, 0x34, 0x14, 0x09, - 0x24, 0xfe, 0x12, 0x12, 0x09, 0x00, 0x1b, 0x29, 0x1f, 0xdd, 0x01, 0x42, - 0xa1, 0x32, 0x01, 0x08, 0xae, 0x41, 0x02, 0x32, 0xfe, 0x62, 0x08, 0x0a, - 0xe1, 0x01, 0xfe, 0x58, 0x10, 0x15, 0x9b, 0x05, 0x35, 0x32, 0x01, 0x43, - 0x09, 0xbb, 0xfe, 0xd7, 0x13, 0x91, 0x4b, 0x7e, 0x4c, 0x8e, 0xfe, 0x80, - 0x13, 0x01, 0x0c, 0x06, 0x54, 0xfe, 0x72, 0x12, 0xdb, 0x64, 0xdc, 0x34, - 0xfe, 0x44, 0x55, 0xfe, 0xe5, 0x55, 0xb0, 0xfe, 0x4a, 0x13, 0x21, 0x6e, - 0xfe, 0x26, 0x13, 0x03, 0x97, 0x3b, 0x98, 0x8e, 0xfe, 0xb6, 0x0e, 0x10, - 0x6a, 0x22, 0x6b, 0x26, 0x10, 0x97, 0x10, 0x98, 0x01, 0xc2, 0x2e, 0x49, - 0x88, 0x20, 0x6e, 0x01, 0xfe, 0x6a, 0x16, 0xdb, 0x64, 0xdc, 0x34, 0xfe, - 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x64, 0xfe, 0x05, 0xfa, - 0x34, 0xfe, 0x8f, 0x10, 0x03, 0x6c, 0x3b, 0x6d, 0xfe, 0x40, 0x56, 0xfe, - 0xe1, 0x56, 0x10, 0x6c, 0x22, 0x6d, 0x71, 0xdb, 0x64, 0xdc, 0x34, 0xfe, - 0x44, 0x55, 0xfe, 0xe5, 0x55, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x00, 0x56, - 0xfe, 0xa1, 0x56, 0x10, 0x68, 0x22, 0x69, 0x01, 0x0c, 0x06, 0x54, 0xf9, - 0x21, 0x6e, 0xfe, 0x1f, 0x40, 0x03, 0x6a, 0x3b, 0x6b, 0xfe, 0x2c, 0x50, - 0xfe, 0xae, 0x50, 0x03, 0x6c, 0x3b, 0x6d, 0xfe, 0x44, 0x50, 0xfe, 0xc6, - 0x50, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x03, - 0x4b, 0x3b, 0x4c, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x05, 0x73, 0x2e, - 0x07, 0x20, 0x9e, 0x05, 0x72, 0x32, 0x01, 0x08, 0x16, 0x3d, 0x27, 0x25, - 0xee, 0x09, 0x07, 0x2b, 0x3d, 0x01, 0x43, 0x09, 0xbb, 0x2b, 0x72, 0x01, - 0xa6, 0x23, 0x3f, 0x1b, 0x3d, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1e, 0x13, - 0x91, 0x4b, 0x7e, 0x4c, 0xfe, 0x0a, 0x55, 0x31, 0xfe, 0x8b, 0x55, 0xd9, - 0x4b, 0xda, 0x4c, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0x05, 0x72, 0x01, - 0xfe, 0x8e, 0x1e, 0xca, 0xfe, 0x19, 0x41, 0x05, 0x72, 0x32, 0x01, 0x08, - 0x2a, 0x3c, 0x16, 0xc0, 0x27, 0x25, 0xbe, 0x2d, 0x1d, 0xc0, 0x2d, 0x0d, - 0x83, 0x2d, 0x7f, 0x1b, 0xfe, 0x66, 0x15, 0x05, 0x3d, 0x01, 0x08, 0x2a, - 0x3c, 0x16, 0xc0, 0x27, 0x25, 0xbd, 0x09, 0x1d, 0x2b, 0x3d, 0x01, 0x08, - 0x16, 0xc0, 0x27, 0x25, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, 0x50, 0x03, - 0xb6, 0x1e, 0x83, 0x01, 0x38, 0x06, 0x24, 0x31, 0xa1, 0xfe, 0xbb, 0x45, - 0x2d, 0x00, 0xa4, 0x46, 0x07, 0x90, 0x3f, 0x01, 0xfe, 0xf8, 0x15, 0x01, - 0xa6, 0x86, 0xfe, 0x4b, 0x45, 0xfe, 0x20, 0x13, 0x01, 0x43, 0x09, 0x82, - 0xfe, 0x16, 0x13, 0x03, 0x9a, 0x1e, 0x5d, 0x03, 0x55, 0x1e, 0x31, 0x5e, - 0x05, 0x72, 0xfe, 0xc0, 0x5d, 0x01, 0xa7, 0xfe, 0x03, 0x17, 0x03, 0x66, - 0x8a, 0x10, 0x66, 0x5e, 0x32, 0x01, 0x08, 0x17, 0x73, 0x01, 0xfe, 0x56, - 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0x3d, 0x27, 0x25, 0xbd, - 0x09, 0x07, 0x2b, 0x3d, 0x01, 0xfe, 0xbe, 0x16, 0xfe, 0x42, 0x58, 0xfe, - 0xe8, 0x14, 0x01, 0xa6, 0x86, 0xfe, 0x4a, 0xf4, 0x0d, 0x1b, 0x3d, 0xfe, - 0x4a, 0xf4, 0x07, 0xfe, 0x0e, 0x12, 0x01, 0x43, 0x09, 0x82, 0x4e, 0x05, - 0x72, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x5e, 0x32, 0x01, 0x08, 0x17, 0x73, - 0x01, 0xfe, 0x84, 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0x3d, - 0x27, 0x25, 0xbd, 0x09, 0x12, 0x2b, 0x3d, 0x01, 0xfe, 0xe8, 0x17, 0x8b, - 0xfe, 0xaa, 0x14, 0xfe, 0xb6, 0x14, 0x86, 0xa8, 0xb2, 0x0d, 0x1b, 0x3d, - 0xb2, 0x07, 0xfe, 0x0e, 0x12, 0x01, 0x43, 0x09, 0x82, 0x4e, 0x05, 0x72, - 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x5e, 0x32, 0x01, 0x08, 0x17, 0x73, 0x01, - 0xfe, 0xc0, 0x19, 0x05, 0x73, 0x13, 0x07, 0x2f, 0xfe, 0xcc, 0x15, 0x17, - 0xfe, 0xe2, 0x15, 0x5f, 0xcc, 0x01, 0x08, 0x26, 0x5f, 0x02, 0x8f, 0xfe, - 0xde, 0x15, 0x2a, 0xfe, 0xde, 0x15, 0x16, 0xfe, 0xcc, 0x15, 0x5e, 0x32, - 0x01, 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, - 0xad, 0x23, 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x02, - 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xad, 0x23, 0x3f, 0xfe, 0x30, - 0x56, 0xfe, 0x00, 0x5c, 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, - 0xad, 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xfe, 0x00, 0x5e, - 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xad, 0xfe, 0x0b, 0x58, - 0x02, 0x0a, 0x66, 0x01, 0x5c, 0x0a, 0x55, 0x01, 0x5c, 0x0a, 0x6f, 0x01, - 0x5c, 0x02, 0x01, 0xfe, 0x1e, 0x1f, 0x23, 0x1a, 0xff, 0x03, 0x00, 0x54, - 0xfe, 0x00, 0xf4, 0x24, 0x52, 0x0f, 0xfe, 0x00, 0x7c, 0x04, 0xfe, 0x07, - 0x7c, 0x3a, 0x0b, 0x0e, 0xfe, 0x00, 0x71, 0xfe, 0xf9, 0x18, 0xfe, 0x7a, - 0x19, 0xfe, 0xfb, 0x19, 0xfe, 0x1a, 0xf7, 0x00, 0xfe, 0x1b, 0xf7, 0x00, - 0x7a, 0x30, 0x10, 0x68, 0x22, 0x69, 0xd9, 0x6c, 0xda, 0x6d, 0x02, 0xfe, - 0x62, 0x08, 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x77, - 0x02, 0x01, 0xc6, 0xfe, 0x42, 0x48, 0x4f, 0x50, 0x45, 0x01, 0x08, 0x16, - 0xfe, 0xe0, 0x17, 0x27, 0x25, 0xbe, 0x01, 0x08, 0x16, 0xfe, 0xe0, 0x17, - 0x27, 0x25, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, 0x03, 0x9a, 0x1e, 0xfe, - 0xda, 0x12, 0x01, 0x38, 0x06, 0x12, 0xfe, 0xd0, 0x13, 0x26, 0x53, 0x12, - 0x48, 0xfe, 0x08, 0x17, 0xd1, 0x12, 0x53, 0x12, 0xfe, 0x1e, 0x13, 0x2d, - 0xb4, 0x7b, 0xfe, 0x26, 0x17, 0x4d, 0x13, 0x07, 0x1c, 0xb4, 0x90, 0x04, - 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xf1, 0xff, 0x02, 0x83, 0x55, - 0x53, 0x1d, 0xfe, 0x12, 0x13, 0xd6, 0xfe, 0x30, 0x00, 0xb0, 0xfe, 0x80, - 0x17, 0x1c, 0x63, 0x13, 0x07, 0xfe, 0x56, 0x10, 0x53, 0x0d, 0xfe, 0x16, - 0x13, 0xd6, 0xfe, 0x64, 0x00, 0xb0, 0xfe, 0x80, 0x17, 0x0a, 0xfe, 0x64, - 0x00, 0x1c, 0x94, 0x13, 0x07, 0xfe, 0x28, 0x10, 0x53, 0x07, 0xfe, 0x60, - 0x13, 0xd6, 0xfe, 0xc8, 0x00, 0xb0, 0xfe, 0x80, 0x17, 0x0a, 0xfe, 0xc8, - 0x00, 0x1c, 0x95, 0x13, 0x07, 0x71, 0xd6, 0xfe, 0x90, 0x01, 0x48, 0xfe, - 0x8c, 0x17, 0x45, 0xf3, 0xfe, 0x43, 0xf4, 0x96, 0xfe, 0x56, 0xf0, 0xfe, - 0x9e, 0x17, 0xfe, 0x04, 0xf4, 0x58, 0xfe, 0x43, 0xf4, 0x94, 0xf6, 0x8b, - 0x01, 0xfe, 0x24, 0x16, 0x23, 0x3f, 0xfc, 0xa8, 0x8c, 0x49, 0x48, 0xfe, - 0xda, 0x17, 0x62, 0x49, 0xfe, 0x1c, 0x10, 0xa8, 0x8c, 0x80, 0x48, 0xfe, - 0xda, 0x17, 0x62, 0x80, 0x71, 0x50, 0x26, 0xfe, 0x4d, 0xf4, 0x00, 0xf7, - 0x45, 0x13, 0x07, 0xfe, 0xb4, 0x56, 0xfe, 0xc3, 0x58, 0x02, 0x50, 0x13, - 0x0d, 0x02, 0x50, 0x3e, 0x78, 0x4f, 0x45, 0x01, 0x08, 0x16, 0xa9, 0x27, - 0x25, 0xbe, 0xfe, 0x03, 0xea, 0xfe, 0x7e, 0x01, 0x01, 0x08, 0x16, 0xa9, - 0x27, 0x25, 0xfe, 0xe9, 0x0a, 0x01, 0x08, 0x16, 0xa9, 0x27, 0x25, 0xfe, - 0xe9, 0x0a, 0xfe, 0x05, 0xea, 0xfe, 0x7f, 0x01, 0x01, 0x08, 0x16, 0xa9, - 0x27, 0x25, 0xfe, 0x69, 0x09, 0xfe, 0x02, 0xea, 0xfe, 0x80, 0x01, 0x01, - 0x08, 0x16, 0xa9, 0x27, 0x25, 0xfe, 0xe8, 0x08, 0x47, 0xfe, 0x81, 0x01, - 0x03, 0xb6, 0x1e, 0x83, 0x01, 0x38, 0x06, 0x24, 0x31, 0xa2, 0x78, 0xf2, - 0x53, 0x07, 0x36, 0xfe, 0x34, 0xf4, 0x3f, 0xa1, 0x78, 0x03, 0x9a, 0x1e, - 0x83, 0x01, 0x38, 0x06, 0x12, 0x31, 0xf0, 0x4f, 0x45, 0xfe, 0x90, 0x10, - 0xfe, 0x40, 0x5a, 0x23, 0x3f, 0xfb, 0x8c, 0x49, 0x48, 0xfe, 0xaa, 0x18, - 0x62, 0x49, 0x71, 0x8c, 0x80, 0x48, 0xfe, 0xaa, 0x18, 0x62, 0x80, 0xfe, - 0xb4, 0x56, 0xfe, 0x40, 0x5d, 0x01, 0xc6, 0x01, 0xfe, 0xac, 0x1d, 0xfe, - 0x02, 0x17, 0xfe, 0xc8, 0x45, 0xfe, 0x5a, 0xf0, 0xfe, 0xc0, 0x18, 0xfe, - 0x43, 0x48, 0x2d, 0x93, 0x36, 0xfe, 0x34, 0xf4, 0xfe, 0x00, 0x11, 0xfe, - 0x40, 0x10, 0x2d, 0xb4, 0x36, 0xfe, 0x34, 0xf4, 0x04, 0xfe, 0x34, 0x10, - 0x2d, 0xfe, 0x0b, 0x00, 0x36, 0x46, 0x63, 0xfe, 0x28, 0x10, 0xfe, 0xc0, - 0x49, 0xff, 0x02, 0x00, 0x54, 0xb2, 0xfe, 0x90, 0x01, 0x48, 0xfe, 0xfa, - 0x18, 0x45, 0xfe, 0x1c, 0xf4, 0x3f, 0xf3, 0xfe, 0x40, 0xf4, 0x96, 0xfe, - 0x56, 0xf0, 0xfe, 0x0c, 0x19, 0xfe, 0x04, 0xf4, 0x58, 0xfe, 0x40, 0xf4, - 0x94, 0xf6, 0x3e, 0x2d, 0x93, 0x4e, 0xd0, 0x0d, 0x21, 0xfe, 0x7f, 0x01, - 0xfe, 0xc8, 0x46, 0xfe, 0x24, 0x13, 0x8c, 0x00, 0x5d, 0x26, 0x21, 0xfe, - 0x7e, 0x01, 0xfe, 0xc8, 0x45, 0xfe, 0x14, 0x13, 0x21, 0xfe, 0x80, 0x01, - 0xfe, 0x48, 0x45, 0xfa, 0x21, 0xfe, 0x81, 0x01, 0xfe, 0xc8, 0x44, 0x4e, - 0x26, 0x02, 0x13, 0x07, 0x02, 0x78, 0x45, 0x50, 0x13, 0x0d, 0x02, 0x14, - 0x07, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x14, 0x0d, 0x01, 0x08, 0x17, - 0xfe, 0x82, 0x19, 0x14, 0x1d, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x5f, - 0xfe, 0x89, 0x49, 0x01, 0x08, 0x02, 0x14, 0x07, 0x01, 0x08, 0x17, 0xc1, - 0x14, 0x1d, 0x01, 0x08, 0x17, 0xc1, 0x14, 0x07, 0x01, 0x08, 0x17, 0xc1, - 0xfe, 0x89, 0x49, 0x01, 0x08, 0x17, 0xc1, 0x5f, 0xfe, 0x89, 0x4a, 0x01, - 0x08, 0x02, 0x50, 0x02, 0x14, 0x07, 0x01, 0x08, 0x17, 0x74, 0x14, 0x7f, - 0x01, 0x08, 0x17, 0x74, 0x14, 0x12, 0x01, 0x08, 0x17, 0x74, 0xfe, 0x89, - 0x49, 0x01, 0x08, 0x17, 0x74, 0x14, 0x00, 0x01, 0x08, 0x17, 0x74, 0xfe, - 0x89, 0x4a, 0x01, 0x08, 0x17, 0x74, 0xfe, 0x09, 0x49, 0x01, 0x08, 0x17, - 0x74, 0x5f, 0xcc, 0x01, 0x08, 0x02, 0x21, 0xe4, 0x09, 0x07, 0xfe, 0x4c, - 0x13, 0xc8, 0x20, 0xe4, 0xfe, 0x49, 0xf4, 0x00, 0x4d, 0x5f, 0xa1, 0x5e, - 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xcc, 0xff, 0x02, 0x00, 0x10, 0x2f, - 0xfe, 0x3e, 0x1a, 0x01, 0x43, 0x09, 0xfe, 0xe3, 0x00, 0xfe, 0x22, 0x13, - 0x16, 0xfe, 0x64, 0x1a, 0x26, 0x20, 0x9e, 0x01, 0x41, 0x21, 0x9e, 0x09, - 0x07, 0x5d, 0x01, 0x0c, 0x61, 0x07, 0x44, 0x02, 0x0a, 0x5a, 0x01, 0x18, - 0xfe, 0x00, 0x40, 0xaa, 0x09, 0x1a, 0xfe, 0x12, 0x13, 0x0a, 0x9d, 0x01, - 0x18, 0xaa, 0x0a, 0x67, 0x01, 0xa3, 0x02, 0x0a, 0x9d, 0x01, 0x18, 0xaa, - 0xfe, 0x80, 0xe7, 0x1a, 0x09, 0x1a, 0x5d, 0xfe, 0x45, 0x58, 0x01, 0xfe, - 0xb2, 0x16, 0xaa, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0xaa, 0x0a, 0x67, 0x01, - 0xa3, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x01, 0xfe, 0x7e, 0x1e, 0xfe, 0x80, - 0x4c, 0xfe, 0x49, 0xe4, 0x1a, 0xfe, 0x12, 0x13, 0x0a, 0x9d, 0x01, 0x18, - 0xfe, 0x80, 0x4c, 0x0a, 0x67, 0x01, 0x5c, 0x02, 0x1c, 0x1a, 0x87, 0x7c, - 0xe5, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x24, 0x1c, 0xfe, 0x1d, - 0xf7, 0x28, 0xb1, 0xfe, 0x04, 0x1b, 0x01, 0xfe, 0x2a, 0x1c, 0xfa, 0xb3, - 0x28, 0x7c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x02, 0xc9, 0x2b, 0xfe, - 0xf4, 0x1a, 0xfe, 0xfa, 0x10, 0x1c, 0x1a, 0x87, 0x03, 0xfe, 0x64, 0x01, - 0xfe, 0x00, 0xf4, 0x24, 0xfe, 0x18, 0x58, 0x03, 0xfe, 0x66, 0x01, 0xfe, - 0x19, 0x58, 0xb3, 0x24, 0x01, 0xfe, 0x0e, 0x1f, 0xfe, 0x30, 0xf4, 0x07, - 0xfe, 0x3c, 0x50, 0x7c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, - 0xf7, 0x24, 0xb1, 0xfe, 0x50, 0x1b, 0xfe, 0xd4, 0x14, 0x31, 0x02, 0xc9, - 0x2b, 0xfe, 0x26, 0x1b, 0xfe, 0xba, 0x10, 0x1c, 0x1a, 0x87, 0xfe, 0x83, - 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7, 0x54, 0xb1, - 0xfe, 0x72, 0x1b, 0xfe, 0xb2, 0x14, 0xfc, 0xb3, 0x54, 0x7c, 0x12, 0xfe, - 0xaf, 0x19, 0xfe, 0x98, 0xe7, 0x00, 0x02, 0xc9, 0x2b, 0xfe, 0x66, 0x1b, - 0xfe, 0x8a, 0x10, 0x1c, 0x1a, 0x87, 0x8b, 0x0f, 0xfe, 0x30, 0x90, 0x04, - 0xfe, 0xb0, 0x93, 0x3a, 0x0b, 0xfe, 0x18, 0x58, 0xfe, 0x32, 0x90, 0x04, - 0xfe, 0xb2, 0x93, 0x3a, 0x0b, 0xfe, 0x19, 0x58, 0x0e, 0xa8, 0xb3, 0x4a, - 0x7c, 0x12, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x4a, 0xb1, 0xfe, 0xc6, - 0x1b, 0xfe, 0x5e, 0x14, 0x31, 0x02, 0xc9, 0x2b, 0xfe, 0x96, 0x1b, 0x5c, - 0xfe, 0x02, 0xf6, 0x1a, 0x87, 0xfe, 0x18, 0xfe, 0x6a, 0xfe, 0x19, 0xfe, - 0x6b, 0x01, 0xfe, 0x1e, 0x1f, 0xfe, 0x1d, 0xf7, 0x65, 0xb1, 0xfe, 0xee, - 0x1b, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13, 0xb3, 0x65, 0x3e, 0xfe, 0x83, - 0x58, 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x1a, 0xfe, 0x81, 0xe7, 0x1a, - 0x15, 0xfe, 0xdd, 0x00, 0x7a, 0x30, 0x02, 0x7a, 0x30, 0xfe, 0x12, 0x45, - 0x2b, 0xfe, 0xdc, 0x1b, 0x1f, 0x07, 0x47, 0xb5, 0xc3, 0x05, 0x35, 0xfe, - 0x39, 0xf0, 0x75, 0x26, 0x02, 0xfe, 0x7e, 0x18, 0x23, 0x1d, 0x36, 0x13, - 0x11, 0x02, 0x87, 0x03, 0xe3, 0x23, 0x07, 0xfe, 0xef, 0x12, 0xfe, 0xe1, - 0x10, 0x90, 0x34, 0x60, 0xfe, 0x02, 0x80, 0x09, 0x56, 0xfe, 0x3c, 0x13, - 0xfe, 0x82, 0x14, 0xfe, 0x42, 0x13, 0x51, 0xfe, 0x06, 0x83, 0x0a, 0x5a, - 0x01, 0x18, 0xcb, 0xfe, 0x3e, 0x12, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, - 0x01, 0xfe, 0xb2, 0x16, 0xfe, 0x00, 0xcc, 0xcb, 0xfe, 0xf3, 0x13, 0x3f, - 0x89, 0x09, 0x1a, 0xa5, 0x0a, 0x9d, 0x01, 0x18, 0xfe, 0x80, 0x4c, 0x01, - 0x85, 0xfe, 0x16, 0x10, 0x09, 0x9b, 0x4e, 0xfe, 0x40, 0x14, 0xfe, 0x24, - 0x12, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x52, 0x1c, 0x1c, 0x0d, - 0x02, 0xfe, 0x9c, 0xe7, 0x0d, 0x19, 0xfe, 0x15, 0x00, 0x40, 0x8d, 0x30, - 0x01, 0xf4, 0x1c, 0x07, 0x02, 0x51, 0xfe, 0x06, 0x83, 0xfe, 0x18, 0x80, - 0x61, 0x28, 0x44, 0x15, 0x56, 0x01, 0x85, 0x1c, 0x07, 0x02, 0xfe, 0x38, - 0x90, 0xfe, 0xba, 0x90, 0x91, 0xde, 0x7e, 0xdf, 0xfe, 0x48, 0x55, 0x31, - 0xfe, 0xc9, 0x55, 0x02, 0x21, 0xb9, 0x88, 0x20, 0xb9, 0x02, 0x0a, 0xba, - 0x01, 0x18, 0xfe, 0x41, 0x48, 0x0a, 0x57, 0x01, 0x18, 0xfe, 0x49, 0x44, - 0x1b, 0xfe, 0x1e, 0x1d, 0x88, 0x89, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x09, - 0x1a, 0xa4, 0x0a, 0x67, 0x01, 0xa3, 0x0a, 0x57, 0x01, 0x18, 0x88, 0x89, - 0x02, 0xfe, 0x4e, 0xe4, 0x1d, 0x7b, 0xfe, 0x52, 0x1d, 0x03, 0xfe, 0x90, - 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xfe, 0x4e, 0xe4, 0xdd, 0x7b, - 0xfe, 0x64, 0x1d, 0x03, 0xfe, 0x92, 0x00, 0xd1, 0x12, 0xfe, 0x1a, 0x10, - 0xfe, 0x4e, 0xe4, 0xfe, 0x0b, 0x00, 0x7b, 0xfe, 0x76, 0x1d, 0x03, 0xfe, - 0x94, 0x00, 0xd1, 0x24, 0xfe, 0x08, 0x10, 0x03, 0xfe, 0x96, 0x00, 0xd1, - 0x63, 0xfe, 0x4e, 0x45, 0x83, 0xca, 0xff, 0x04, 0x68, 0x54, 0xfe, 0xf1, - 0x10, 0x23, 0x49, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c, - 0xfe, 0x1a, 0xf4, 0xfe, 0x00, 0x04, 0x83, 0xb2, 0x1d, 0x48, 0xfe, 0xaa, - 0x1d, 0x13, 0x1d, 0x02, 0x09, 0x92, 0xfe, 0x5a, 0xf0, 0xfe, 0xba, 0x1d, - 0x2e, 0x93, 0xfe, 0x34, 0x10, 0x09, 0x12, 0xfe, 0x5a, 0xf0, 0xfe, 0xc8, - 0x1d, 0x2e, 0xb4, 0xfe, 0x26, 0x10, 0x09, 0x1d, 0x36, 0x2e, 0x63, 0xfe, - 0x1a, 0x10, 0x09, 0x0d, 0x36, 0x2e, 0x94, 0xf2, 0x09, 0x07, 0x36, 0x2e, - 0x95, 0xa1, 0xc8, 0x02, 0x1f, 0x93, 0x01, 0x42, 0xfe, 0x04, 0xfe, 0x99, - 0x03, 0x9c, 0x8b, 0x02, 0x2a, 0xfe, 0x1c, 0x1e, 0xfe, 0x14, 0xf0, 0x08, - 0x2f, 0xfe, 0x0c, 0x1e, 0x2a, 0xfe, 0x1c, 0x1e, 0x8f, 0xfe, 0x1c, 0x1e, - 0xfe, 0x82, 0xf0, 0xfe, 0x10, 0x1e, 0x02, 0x0f, 0x3f, 0x04, 0xfe, 0x80, - 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x18, 0x80, 0x04, 0xfe, 0x98, - 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x02, 0x80, 0x04, 0xfe, 0x82, - 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, 0x80, 0x04, 0xfe, 0x86, - 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x1b, 0x80, 0x04, 0xfe, 0x9b, - 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x04, 0x80, 0x04, 0xfe, 0x84, - 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x80, 0x80, 0x04, 0xfe, 0x80, - 0x83, 0xfe, 0xc9, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x19, 0x81, 0x04, - 0xfe, 0x99, 0x83, 0xfe, 0xca, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, - 0x83, 0x04, 0xfe, 0x86, 0x83, 0xfe, 0xce, 0x47, 0x0b, 0x0e, 0x02, 0x0f, - 0xfe, 0x2c, 0x90, 0x04, 0xfe, 0xac, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f, - 0xfe, 0xae, 0x90, 0x04, 0xfe, 0xae, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f, - 0xfe, 0x08, 0x90, 0x04, 0xfe, 0x88, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f, - 0xfe, 0x8a, 0x90, 0x04, 0xfe, 0x8a, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f, - 0xfe, 0x0c, 0x90, 0x04, 0xfe, 0x8c, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f, - 0xfe, 0x8e, 0x90, 0x04, 0xfe, 0x8e, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f, - 0xfe, 0x3c, 0x90, 0x04, 0xfe, 0xbc, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x8b, - 0x0f, 0xfe, 0x03, 0x80, 0x04, 0xfe, 0x83, 0x83, 0x33, 0x0b, 0x77, 0x0e, - 0xa8, 0x02, 0xff, 0x66, 0x00, 0x00, -}; - -static unsigned short _adv_asc38C1600_size = sizeof(_adv_asc38C1600_buf); /* 0x1673 */ -static ADV_DCNT _adv_asc38C1600_chksum = 0x0604EF77UL; /* Expanded little-endian checksum. */ - static void AscInitQLinkVar(ASC_DVC_VAR *asc_dvc) { PortAddr iop_base; @@ -6362,6 +4751,10 @@ static ushort AscInitMicroCodeVar(ASC_DVC_VAR *asc_dvc) static ushort AscInitAsc1000Driver(ASC_DVC_VAR *asc_dvc) { + const struct firmware *fw; + const char fwname[] = "advansys/mcode.bin"; + int err; + unsigned long chksum; ushort warn_code; PortAddr iop_base; @@ -6383,12 +4776,29 @@ static ushort AscInitAsc1000Driver(ASC_DVC_VAR *asc_dvc) warn_code |= AscInitLram(asc_dvc); if (asc_dvc->err_code != 0) return UW_ERR; - ASC_DBG(1, "_asc_mcode_chksum 0x%lx\n", (ulong)_asc_mcode_chksum); - if (AscLoadMicroCode(iop_base, 0, _asc_mcode_buf, - _asc_mcode_size) != _asc_mcode_chksum) { + + err = request_firmware(&fw, fwname, asc_dvc->drv_ptr->dev); + if (err) { + printk(KERN_ERR "Failed to load image \"%s\" err %d\n", + fwname, err); + return err; + } + if (fw->size < 4) { + printk(KERN_ERR "Bogus length %zu in image \"%s\"\n", + fw->size, fwname); + release_firmware(fw); + return -EINVAL; + } + chksum = (fw->data[3] << 24) | (fw->data[2] << 16) | + (fw->data[1] << 8) | fw->data[0]; + ASC_DBG(1, "_asc_mcode_chksum 0x%lx\n", (ulong)chksum); + if (AscLoadMicroCode(iop_base, 0, &fw->data[4], + fw->size - 4) != chksum) { asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM; + release_firmware(fw); return warn_code; } + release_firmware(fw); warn_code |= AscInitMicroCodeVar(asc_dvc); asc_dvc->init_state |= ASC_INIT_STATE_END_LOAD_MC; AscEnableInterrupt(iop_base); @@ -6417,8 +4827,8 @@ static ushort AscInitAsc1000Driver(ASC_DVC_VAR *asc_dvc) * * Returns 0 or an error if the checksum doesn't match */ -static int AdvLoadMicrocode(AdvPortAddr iop_base, unsigned char *buf, int size, - int memsize, int chksum) +static int AdvLoadMicrocode(AdvPortAddr iop_base, const unsigned char *buf, + int size, int memsize, int chksum) { int i, j, end, len = 0; ADV_DCNT sum; @@ -6627,6 +5037,8 @@ static int AdvResetSB(ADV_DVC_VAR *asc_dvc) */ static int AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc) { + const struct firmware *fw; + const char fwname[] = "advansys/3550.bin"; AdvPortAddr iop_base; ushort warn_code; int begin_addr; @@ -6634,6 +5046,8 @@ static int AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc) ushort code_sum; int word; int i; + int err; + unsigned long chksum; ushort scsi_cfg1; uchar tid; ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */ @@ -6692,9 +5106,24 @@ static int AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc) max_cmd[tid]); } - asc_dvc->err_code = AdvLoadMicrocode(iop_base, _adv_asc3550_buf, - _adv_asc3550_size, ADV_3550_MEMSIZE, - _adv_asc3550_chksum); + err = request_firmware(&fw, fwname, asc_dvc->drv_ptr->dev); + if (err) { + printk(KERN_ERR "Failed to load image \"%s\" err %d\n", + fwname, err); + return err; + } + if (fw->size < 4) { + printk(KERN_ERR "Bogus length %zu in image \"%s\"\n", + fw->size, fwname); + release_firmware(fw); + return -EINVAL; + } + chksum = (fw->data[3] << 24) | (fw->data[2] << 16) | + (fw->data[1] << 8) | fw->data[0]; + asc_dvc->err_code = AdvLoadMicrocode(iop_base, &fw->data[4], + fw->size - 4, ADV_3550_MEMSIZE, + chksum); + release_firmware(fw); if (asc_dvc->err_code) return ADV_ERROR; @@ -7065,6 +5494,8 @@ static int AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc) */ static int AdvInitAsc38C0800Driver(ADV_DVC_VAR *asc_dvc) { + const struct firmware *fw; + const char fwname[] = "advansys/38C0800.bin"; AdvPortAddr iop_base; ushort warn_code; int begin_addr; @@ -7072,6 +5503,8 @@ static int AdvInitAsc38C0800Driver(ADV_DVC_VAR *asc_dvc) ushort code_sum; int word; int i; + int err; + unsigned long chksum; ushort scsi_cfg1; uchar byte; uchar tid; @@ -7187,9 +5620,24 @@ static int AdvInitAsc38C0800Driver(ADV_DVC_VAR *asc_dvc) /* We need to reset back to normal mode after LRAM test passes. */ AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE); - asc_dvc->err_code = AdvLoadMicrocode(iop_base, _adv_asc38C0800_buf, - _adv_asc38C0800_size, ADV_38C0800_MEMSIZE, - _adv_asc38C0800_chksum); + err = request_firmware(&fw, fwname, asc_dvc->drv_ptr->dev); + if (err) { + printk(KERN_ERR "Failed to load image \"%s\" err %d\n", + fwname, err); + return err; + } + if (fw->size < 4) { + printk(KERN_ERR "Bogus length %zu in image \"%s\"\n", + fw->size, fwname); + release_firmware(fw); + return -EINVAL; + } + chksum = (fw->data[3] << 24) | (fw->data[2] << 16) | + (fw->data[1] << 8) | fw->data[0]; + asc_dvc->err_code = AdvLoadMicrocode(iop_base, &fw->data[4], + fw->size - 4, ADV_38C0800_MEMSIZE, + chksum); + release_firmware(fw); if (asc_dvc->err_code) return ADV_ERROR; @@ -7544,6 +5992,8 @@ static int AdvInitAsc38C0800Driver(ADV_DVC_VAR *asc_dvc) */ static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *asc_dvc) { + const struct firmware *fw; + const char fwname[] = "advansys/38C1600.bin"; AdvPortAddr iop_base; ushort warn_code; int begin_addr; @@ -7551,6 +6001,8 @@ static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *asc_dvc) ushort code_sum; long word; int i; + int err; + unsigned long chksum; ushort scsi_cfg1; uchar byte; uchar tid; @@ -7668,9 +6120,24 @@ static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *asc_dvc) /* We need to reset back to normal mode after LRAM test passes. */ AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE); - asc_dvc->err_code = AdvLoadMicrocode(iop_base, _adv_asc38C1600_buf, - _adv_asc38C1600_size, ADV_38C1600_MEMSIZE, - _adv_asc38C1600_chksum); + err = request_firmware(&fw, fwname, asc_dvc->drv_ptr->dev); + if (err) { + printk(KERN_ERR "Failed to load image \"%s\" err %d\n", + fwname, err); + return err; + } + if (fw->size < 4) { + printk(KERN_ERR "Bogus length %zu in image \"%s\"\n", + fw->size, fwname); + release_firmware(fw); + return -EINVAL; + } + chksum = (fw->data[3] << 24) | (fw->data[2] << 16) | + (fw->data[1] << 8) | fw->data[0]; + asc_dvc->err_code = AdvLoadMicrocode(iop_base, &fw->data[4], + fw->size - 4, ADV_38C1600_MEMSIZE, + chksum); + release_firmware(fw); if (asc_dvc->err_code) return ADV_ERROR; @@ -14353,3 +12820,7 @@ module_init(advansys_init); module_exit(advansys_exit); MODULE_LICENSE("GPL"); +MODULE_FIRMWARE("advansys/mcode.bin"); +MODULE_FIRMWARE("advansys/3550.bin"); +MODULE_FIRMWARE("advansys/38C0800.bin"); +MODULE_FIRMWARE("advansys/38C1600.bin"); diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c index bdad54ec088..63b521d615f 100644 --- a/drivers/scsi/aic7xxx/aic79xx_core.c +++ b/drivers/scsi/aic7xxx/aic79xx_core.c @@ -1034,7 +1034,7 @@ ahd_intr(struct ahd_softc *ahd) } /******************************** Private Inlines *****************************/ -static __inline void +static inline void ahd_assert_atn(struct ahd_softc *ahd) { ahd_outb(ahd, SCSISIGO, ATNO); @@ -1069,7 +1069,7 @@ ahd_currently_packetized(struct ahd_softc *ahd) return (packetized); } -static __inline int +static inline int ahd_set_active_fifo(struct ahd_softc *ahd) { u_int active_fifo; @@ -1086,7 +1086,7 @@ ahd_set_active_fifo(struct ahd_softc *ahd) } } -static __inline void +static inline void ahd_unbusy_tcl(struct ahd_softc *ahd, u_int tcl) { ahd_busy_tcl(ahd, tcl, SCB_LIST_NULL); @@ -1096,7 +1096,7 @@ ahd_unbusy_tcl(struct ahd_softc *ahd, u_int tcl) * Determine whether the sequencer reported a residual * for this SCB/transaction. */ -static __inline void +static inline void ahd_update_residual(struct ahd_softc *ahd, struct scb *scb) { uint32_t sgptr; @@ -1106,7 +1106,7 @@ ahd_update_residual(struct ahd_softc *ahd, struct scb *scb) ahd_calc_residual(ahd, scb); } -static __inline void +static inline void ahd_complete_scb(struct ahd_softc *ahd, struct scb *scb) { uint32_t sgptr; @@ -7987,7 +7987,7 @@ ahd_resume(struct ahd_softc *ahd) * scbid that should be restored once manipualtion * of the TCL entry is complete. */ -static __inline u_int +static inline u_int ahd_index_busy_tcl(struct ahd_softc *ahd, u_int *saved_scbid, u_int tcl) { /* diff --git a/drivers/scsi/aic7xxx/aic79xx_inline.h b/drivers/scsi/aic7xxx/aic79xx_inline.h index 5f12cf9d99d..09335a3c869 100644 --- a/drivers/scsi/aic7xxx/aic79xx_inline.h +++ b/drivers/scsi/aic7xxx/aic79xx_inline.h @@ -46,21 +46,20 @@ #define _AIC79XX_INLINE_H_ /******************************** Debugging ***********************************/ -static __inline char *ahd_name(struct ahd_softc *ahd); +static inline char *ahd_name(struct ahd_softc *ahd); -static __inline char * -ahd_name(struct ahd_softc *ahd) +static inline char *ahd_name(struct ahd_softc *ahd) { return (ahd->name); } /************************ Sequencer Execution Control *************************/ -static __inline void ahd_known_modes(struct ahd_softc *ahd, +static inline void ahd_known_modes(struct ahd_softc *ahd, ahd_mode src, ahd_mode dst); -static __inline ahd_mode_state ahd_build_mode_state(struct ahd_softc *ahd, +static inline ahd_mode_state ahd_build_mode_state(struct ahd_softc *ahd, ahd_mode src, ahd_mode dst); -static __inline void ahd_extract_mode_state(struct ahd_softc *ahd, +static inline void ahd_extract_mode_state(struct ahd_softc *ahd, ahd_mode_state state, ahd_mode *src, ahd_mode *dst); @@ -73,7 +72,7 @@ int ahd_is_paused(struct ahd_softc *ahd); void ahd_pause(struct ahd_softc *ahd); void ahd_unpause(struct ahd_softc *ahd); -static __inline void +static inline void ahd_known_modes(struct ahd_softc *ahd, ahd_mode src, ahd_mode dst) { ahd->src_mode = src; @@ -82,13 +81,13 @@ ahd_known_modes(struct ahd_softc *ahd, ahd_mode src, ahd_mode dst) ahd->saved_dst_mode = dst; } -static __inline ahd_mode_state +static inline ahd_mode_state ahd_build_mode_state(struct ahd_softc *ahd, ahd_mode src, ahd_mode dst) { return ((src << SRC_MODE_SHIFT) | (dst << DST_MODE_SHIFT)); } -static __inline void +static inline void ahd_extract_mode_state(struct ahd_softc *ahd, ahd_mode_state state, ahd_mode *src, ahd_mode *dst) { @@ -102,13 +101,12 @@ void *ahd_sg_setup(struct ahd_softc *ahd, struct scb *scb, bus_size_t len, int last); /************************** Memory mapping routines ***************************/ -static __inline size_t ahd_sg_size(struct ahd_softc *ahd); +static inline size_t ahd_sg_size(struct ahd_softc *ahd); void ahd_sync_sglist(struct ahd_softc *ahd, struct scb *scb, int op); -static __inline size_t -ahd_sg_size(struct ahd_softc *ahd) +static inline size_t ahd_sg_size(struct ahd_softc *ahd) { if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) return (sizeof(struct ahd_dma64_seg)); @@ -141,11 +139,9 @@ struct scb * ahd_lookup_scb(struct ahd_softc *ahd, u_int tag); void ahd_queue_scb(struct ahd_softc *ahd, struct scb *scb); -static __inline uint8_t * - ahd_get_sense_buf(struct ahd_softc *ahd, +static inline uint8_t *ahd_get_sense_buf(struct ahd_softc *ahd, struct scb *scb); -static __inline uint32_t - ahd_get_sense_bufaddr(struct ahd_softc *ahd, +static inline uint32_t ahd_get_sense_bufaddr(struct ahd_softc *ahd, struct scb *scb); #if 0 /* unused */ @@ -158,13 +154,13 @@ do { \ #endif -static __inline uint8_t * +static inline uint8_t * ahd_get_sense_buf(struct ahd_softc *ahd, struct scb *scb) { return (scb->sense_data); } -static __inline uint32_t +static inline uint32_t ahd_get_sense_bufaddr(struct ahd_softc *ahd, struct scb *scb) { return (scb->sense_busaddr); diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h index 8d6612c1992..55c1fe07969 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.h +++ b/drivers/scsi/aic7xxx/aic79xx_osm.h @@ -395,19 +395,19 @@ struct info_str { }; /******************************** Locking *************************************/ -static __inline void +static inline void ahd_lockinit(struct ahd_softc *ahd) { spin_lock_init(&ahd->platform_data->spin_lock); } -static __inline void +static inline void ahd_lock(struct ahd_softc *ahd, unsigned long *flags) { spin_lock_irqsave(&ahd->platform_data->spin_lock, *flags); } -static __inline void +static inline void ahd_unlock(struct ahd_softc *ahd, unsigned long *flags) { spin_unlock_irqrestore(&ahd->platform_data->spin_lock, *flags); @@ -490,29 +490,29 @@ void ahd_pci_write_config(ahd_dev_softc_t pci, int reg, uint32_t value, int width); -static __inline int ahd_get_pci_function(ahd_dev_softc_t); -static __inline int +static inline int ahd_get_pci_function(ahd_dev_softc_t); +static inline int ahd_get_pci_function(ahd_dev_softc_t pci) { return (PCI_FUNC(pci->devfn)); } -static __inline int ahd_get_pci_slot(ahd_dev_softc_t); -static __inline int +static inline int ahd_get_pci_slot(ahd_dev_softc_t); +static inline int ahd_get_pci_slot(ahd_dev_softc_t pci) { return (PCI_SLOT(pci->devfn)); } -static __inline int ahd_get_pci_bus(ahd_dev_softc_t); -static __inline int +static inline int ahd_get_pci_bus(ahd_dev_softc_t); +static inline int ahd_get_pci_bus(ahd_dev_softc_t pci) { return (pci->bus->number); } -static __inline void ahd_flush_device_writes(struct ahd_softc *); -static __inline void +static inline void ahd_flush_device_writes(struct ahd_softc *); +static inline void ahd_flush_device_writes(struct ahd_softc *ahd) { /* XXX Is this sufficient for all architectures??? */ @@ -524,81 +524,81 @@ int ahd_linux_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int); /*********************** Transaction Access Wrappers **************************/ -static __inline void ahd_cmd_set_transaction_status(struct scsi_cmnd *, uint32_t); -static __inline void ahd_set_transaction_status(struct scb *, uint32_t); -static __inline void ahd_cmd_set_scsi_status(struct scsi_cmnd *, uint32_t); -static __inline void ahd_set_scsi_status(struct scb *, uint32_t); -static __inline uint32_t ahd_cmd_get_transaction_status(struct scsi_cmnd *cmd); -static __inline uint32_t ahd_get_transaction_status(struct scb *); -static __inline uint32_t ahd_cmd_get_scsi_status(struct scsi_cmnd *cmd); -static __inline uint32_t ahd_get_scsi_status(struct scb *); -static __inline void ahd_set_transaction_tag(struct scb *, int, u_int); -static __inline u_long ahd_get_transfer_length(struct scb *); -static __inline int ahd_get_transfer_dir(struct scb *); -static __inline void ahd_set_residual(struct scb *, u_long); -static __inline void ahd_set_sense_residual(struct scb *scb, u_long resid); -static __inline u_long ahd_get_residual(struct scb *); -static __inline u_long ahd_get_sense_residual(struct scb *); -static __inline int ahd_perform_autosense(struct scb *); -static __inline uint32_t ahd_get_sense_bufsize(struct ahd_softc *, +static inline void ahd_cmd_set_transaction_status(struct scsi_cmnd *, uint32_t); +static inline void ahd_set_transaction_status(struct scb *, uint32_t); +static inline void ahd_cmd_set_scsi_status(struct scsi_cmnd *, uint32_t); +static inline void ahd_set_scsi_status(struct scb *, uint32_t); +static inline uint32_t ahd_cmd_get_transaction_status(struct scsi_cmnd *cmd); +static inline uint32_t ahd_get_transaction_status(struct scb *); +static inline uint32_t ahd_cmd_get_scsi_status(struct scsi_cmnd *cmd); +static inline uint32_t ahd_get_scsi_status(struct scb *); +static inline void ahd_set_transaction_tag(struct scb *, int, u_int); +static inline u_long ahd_get_transfer_length(struct scb *); +static inline int ahd_get_transfer_dir(struct scb *); +static inline void ahd_set_residual(struct scb *, u_long); +static inline void ahd_set_sense_residual(struct scb *scb, u_long resid); +static inline u_long ahd_get_residual(struct scb *); +static inline u_long ahd_get_sense_residual(struct scb *); +static inline int ahd_perform_autosense(struct scb *); +static inline uint32_t ahd_get_sense_bufsize(struct ahd_softc *, struct scb *); -static __inline void ahd_notify_xfer_settings_change(struct ahd_softc *, +static inline void ahd_notify_xfer_settings_change(struct ahd_softc *, struct ahd_devinfo *); -static __inline void ahd_platform_scb_free(struct ahd_softc *ahd, +static inline void ahd_platform_scb_free(struct ahd_softc *ahd, struct scb *scb); -static __inline void ahd_freeze_scb(struct scb *scb); +static inline void ahd_freeze_scb(struct scb *scb); -static __inline +static inline void ahd_cmd_set_transaction_status(struct scsi_cmnd *cmd, uint32_t status) { cmd->result &= ~(CAM_STATUS_MASK << 16); cmd->result |= status << 16; } -static __inline +static inline void ahd_set_transaction_status(struct scb *scb, uint32_t status) { ahd_cmd_set_transaction_status(scb->io_ctx,status); } -static __inline +static inline void ahd_cmd_set_scsi_status(struct scsi_cmnd *cmd, uint32_t status) { cmd->result &= ~0xFFFF; cmd->result |= status; } -static __inline +static inline void ahd_set_scsi_status(struct scb *scb, uint32_t status) { ahd_cmd_set_scsi_status(scb->io_ctx, status); } -static __inline +static inline uint32_t ahd_cmd_get_transaction_status(struct scsi_cmnd *cmd) { return ((cmd->result >> 16) & CAM_STATUS_MASK); } -static __inline +static inline uint32_t ahd_get_transaction_status(struct scb *scb) { return (ahd_cmd_get_transaction_status(scb->io_ctx)); } -static __inline +static inline uint32_t ahd_cmd_get_scsi_status(struct scsi_cmnd *cmd) { return (cmd->result & 0xFFFF); } -static __inline +static inline uint32_t ahd_get_scsi_status(struct scb *scb) { return (ahd_cmd_get_scsi_status(scb->io_ctx)); } -static __inline +static inline void ahd_set_transaction_tag(struct scb *scb, int enabled, u_int type) { /* @@ -607,43 +607,43 @@ void ahd_set_transaction_tag(struct scb *scb, int enabled, u_int type) */ } -static __inline +static inline u_long ahd_get_transfer_length(struct scb *scb) { return (scb->platform_data->xfer_len); } -static __inline +static inline int ahd_get_transfer_dir(struct scb *scb) { return (scb->io_ctx->sc_data_direction); } -static __inline +static inline void ahd_set_residual(struct scb *scb, u_long resid) { scsi_set_resid(scb->io_ctx, resid); } -static __inline +static inline void ahd_set_sense_residual(struct scb *scb, u_long resid) { scb->platform_data->sense_resid = resid; } -static __inline +static inline u_long ahd_get_residual(struct scb *scb) { return scsi_get_resid(scb->io_ctx); } -static __inline +static inline u_long ahd_get_sense_residual(struct scb *scb) { return (scb->platform_data->sense_resid); } -static __inline +static inline int ahd_perform_autosense(struct scb *scb) { /* @@ -654,20 +654,20 @@ int ahd_perform_autosense(struct scb *scb) return (1); } -static __inline uint32_t +static inline uint32_t ahd_get_sense_bufsize(struct ahd_softc *ahd, struct scb *scb) { return (sizeof(struct scsi_sense_data)); } -static __inline void +static inline void ahd_notify_xfer_settings_change(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) { /* Nothing to do here for linux */ } -static __inline void +static inline void ahd_platform_scb_free(struct ahd_softc *ahd, struct scb *scb) { ahd->flags &= ~AHD_RESOURCE_SHORTAGE; @@ -678,7 +678,7 @@ void ahd_platform_free(struct ahd_softc *ahd); void ahd_platform_init(struct ahd_softc *ahd); void ahd_platform_freeze_devq(struct ahd_softc *ahd, struct scb *scb); -static __inline void +static inline void ahd_freeze_scb(struct scb *scb) { if ((scb->io_ctx->result & (CAM_DEV_QFRZN << 16)) == 0) { diff --git a/drivers/scsi/aic7xxx/aic79xx_pci.c b/drivers/scsi/aic7xxx/aic79xx_pci.c index a734d77e880..90a04a37b4f 100644 --- a/drivers/scsi/aic7xxx/aic79xx_pci.c +++ b/drivers/scsi/aic7xxx/aic79xx_pci.c @@ -51,7 +51,7 @@ #include "aic79xx_pci.h" -static __inline uint64_t +static inline uint64_t ahd_compose_id(u_int device, u_int vendor, u_int subdevice, u_int subvendor) { uint64_t id; @@ -377,14 +377,12 @@ ahd_pci_config(struct ahd_softc *ahd, const struct ahd_pci_identity *entry) error = ahd_init(ahd); if (error != 0) return (error); + ahd->init_level++; /* * Allow interrupts now that we are completely setup. */ - error = ahd_pci_map_int(ahd); - if (!error) - ahd->init_level++; - return error; + return ahd_pci_map_int(ahd); } #ifdef CONFIG_PM diff --git a/drivers/scsi/aic7xxx/aic7xxx_inline.h b/drivers/scsi/aic7xxx/aic7xxx_inline.h index 09bf2f4d78d..0b57b783ef4 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_inline.h +++ b/drivers/scsi/aic7xxx/aic7xxx_inline.h @@ -55,10 +55,9 @@ void ahc_sync_sglist(struct ahc_softc *ahc, struct scb *scb, int op); /******************************** Debugging ***********************************/ -static __inline char *ahc_name(struct ahc_softc *ahc); +static inline char *ahc_name(struct ahc_softc *ahc); -static __inline char * -ahc_name(struct ahc_softc *ahc) +static inline char *ahc_name(struct ahc_softc *ahc) { return (ahc->name); } diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h index 3f7238db35e..56f07e527b4 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.h +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h @@ -230,7 +230,7 @@ int ahc_dmamap_unload(struct ahc_softc *, bus_dma_tag_t, bus_dmamap_t); #include "aic7xxx.h" /***************************** Timer Facilities *******************************/ -static __inline void +static inline void ahc_scb_timer_reset(struct scb *scb, u_int usec) { } @@ -401,19 +401,19 @@ struct info_str { /******************************** Locking *************************************/ /* Lock protecting internal data structures */ -static __inline void +static inline void ahc_lockinit(struct ahc_softc *ahc) { spin_lock_init(&ahc->platform_data->spin_lock); } -static __inline void +static inline void ahc_lock(struct ahc_softc *ahc, unsigned long *flags) { spin_lock_irqsave(&ahc->platform_data->spin_lock, *flags); } -static __inline void +static inline void ahc_unlock(struct ahc_softc *ahc, unsigned long *flags) { spin_unlock_irqrestore(&ahc->platform_data->spin_lock, *flags); @@ -493,22 +493,22 @@ void ahc_pci_write_config(ahc_dev_softc_t pci, int reg, uint32_t value, int width); -static __inline int ahc_get_pci_function(ahc_dev_softc_t); -static __inline int +static inline int ahc_get_pci_function(ahc_dev_softc_t); +static inline int ahc_get_pci_function(ahc_dev_softc_t pci) { return (PCI_FUNC(pci->devfn)); } -static __inline int ahc_get_pci_slot(ahc_dev_softc_t); -static __inline int +static inline int ahc_get_pci_slot(ahc_dev_softc_t); +static inline int ahc_get_pci_slot(ahc_dev_softc_t pci) { return (PCI_SLOT(pci->devfn)); } -static __inline int ahc_get_pci_bus(ahc_dev_softc_t); -static __inline int +static inline int ahc_get_pci_bus(ahc_dev_softc_t); +static inline int ahc_get_pci_bus(ahc_dev_softc_t pci) { return (pci->bus->number); @@ -521,8 +521,8 @@ static inline void ahc_linux_pci_exit(void) { } #endif -static __inline void ahc_flush_device_writes(struct ahc_softc *); -static __inline void +static inline void ahc_flush_device_writes(struct ahc_softc *); +static inline void ahc_flush_device_writes(struct ahc_softc *ahc) { /* XXX Is this sufficient for all architectures??? */ @@ -535,81 +535,81 @@ int ahc_linux_proc_info(struct Scsi_Host *, char *, char **, /*************************** Domain Validation ********************************/ /*********************** Transaction Access Wrappers *************************/ -static __inline void ahc_cmd_set_transaction_status(struct scsi_cmnd *, uint32_t); -static __inline void ahc_set_transaction_status(struct scb *, uint32_t); -static __inline void ahc_cmd_set_scsi_status(struct scsi_cmnd *, uint32_t); -static __inline void ahc_set_scsi_status(struct scb *, uint32_t); -static __inline uint32_t ahc_cmd_get_transaction_status(struct scsi_cmnd *cmd); -static __inline uint32_t ahc_get_transaction_status(struct scb *); -static __inline uint32_t ahc_cmd_get_scsi_status(struct scsi_cmnd *cmd); -static __inline uint32_t ahc_get_scsi_status(struct scb *); -static __inline void ahc_set_transaction_tag(struct scb *, int, u_int); -static __inline u_long ahc_get_transfer_length(struct scb *); -static __inline int ahc_get_transfer_dir(struct scb *); -static __inline void ahc_set_residual(struct scb *, u_long); -static __inline void ahc_set_sense_residual(struct scb *scb, u_long resid); -static __inline u_long ahc_get_residual(struct scb *); -static __inline u_long ahc_get_sense_residual(struct scb *); -static __inline int ahc_perform_autosense(struct scb *); -static __inline uint32_t ahc_get_sense_bufsize(struct ahc_softc *, +static inline void ahc_cmd_set_transaction_status(struct scsi_cmnd *, uint32_t); +static inline void ahc_set_transaction_status(struct scb *, uint32_t); +static inline void ahc_cmd_set_scsi_status(struct scsi_cmnd *, uint32_t); +static inline void ahc_set_scsi_status(struct scb *, uint32_t); +static inline uint32_t ahc_cmd_get_transaction_status(struct scsi_cmnd *cmd); +static inline uint32_t ahc_get_transaction_status(struct scb *); +static inline uint32_t ahc_cmd_get_scsi_status(struct scsi_cmnd *cmd); +static inline uint32_t ahc_get_scsi_status(struct scb *); +static inline void ahc_set_transaction_tag(struct scb *, int, u_int); +static inline u_long ahc_get_transfer_length(struct scb *); +static inline int ahc_get_transfer_dir(struct scb *); +static inline void ahc_set_residual(struct scb *, u_long); +static inline void ahc_set_sense_residual(struct scb *scb, u_long resid); +static inline u_long ahc_get_residual(struct scb *); +static inline u_long ahc_get_sense_residual(struct scb *); +static inline int ahc_perform_autosense(struct scb *); +static inline uint32_t ahc_get_sense_bufsize(struct ahc_softc *, struct scb *); -static __inline void ahc_notify_xfer_settings_change(struct ahc_softc *, +static inline void ahc_notify_xfer_settings_change(struct ahc_softc *, struct ahc_devinfo *); -static __inline void ahc_platform_scb_free(struct ahc_softc *ahc, +static inline void ahc_platform_scb_free(struct ahc_softc *ahc, struct scb *scb); -static __inline void ahc_freeze_scb(struct scb *scb); +static inline void ahc_freeze_scb(struct scb *scb); -static __inline +static inline void ahc_cmd_set_transaction_status(struct scsi_cmnd *cmd, uint32_t status) { cmd->result &= ~(CAM_STATUS_MASK << 16); cmd->result |= status << 16; } -static __inline +static inline void ahc_set_transaction_status(struct scb *scb, uint32_t status) { ahc_cmd_set_transaction_status(scb->io_ctx,status); } -static __inline +static inline void ahc_cmd_set_scsi_status(struct scsi_cmnd *cmd, uint32_t status) { cmd->result &= ~0xFFFF; cmd->result |= status; } -static __inline +static inline void ahc_set_scsi_status(struct scb *scb, uint32_t status) { ahc_cmd_set_scsi_status(scb->io_ctx, status); } -static __inline +static inline uint32_t ahc_cmd_get_transaction_status(struct scsi_cmnd *cmd) { return ((cmd->result >> 16) & CAM_STATUS_MASK); } -static __inline +static inline uint32_t ahc_get_transaction_status(struct scb *scb) { return (ahc_cmd_get_transaction_status(scb->io_ctx)); } -static __inline +static inline uint32_t ahc_cmd_get_scsi_status(struct scsi_cmnd *cmd) { return (cmd->result & 0xFFFF); } -static __inline +static inline uint32_t ahc_get_scsi_status(struct scb *scb) { return (ahc_cmd_get_scsi_status(scb->io_ctx)); } -static __inline +static inline void ahc_set_transaction_tag(struct scb *scb, int enabled, u_int type) { /* @@ -618,43 +618,43 @@ void ahc_set_transaction_tag(struct scb *scb, int enabled, u_int type) */ } -static __inline +static inline u_long ahc_get_transfer_length(struct scb *scb) { return (scb->platform_data->xfer_len); } -static __inline +static inline int ahc_get_transfer_dir(struct scb *scb) { return (scb->io_ctx->sc_data_direction); } -static __inline +static inline void ahc_set_residual(struct scb *scb, u_long resid) { scsi_set_resid(scb->io_ctx, resid); } -static __inline +static inline void ahc_set_sense_residual(struct scb *scb, u_long resid) { scb->platform_data->sense_resid = resid; } -static __inline +static inline u_long ahc_get_residual(struct scb *scb) { return scsi_get_resid(scb->io_ctx); } -static __inline +static inline u_long ahc_get_sense_residual(struct scb *scb) { return (scb->platform_data->sense_resid); } -static __inline +static inline int ahc_perform_autosense(struct scb *scb) { /* @@ -665,20 +665,20 @@ int ahc_perform_autosense(struct scb *scb) return (1); } -static __inline uint32_t +static inline uint32_t ahc_get_sense_bufsize(struct ahc_softc *ahc, struct scb *scb) { return (sizeof(struct scsi_sense_data)); } -static __inline void +static inline void ahc_notify_xfer_settings_change(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) { /* Nothing to do here for linux */ } -static __inline void +static inline void ahc_platform_scb_free(struct ahc_softc *ahc, struct scb *scb) { } @@ -687,7 +687,7 @@ int ahc_platform_alloc(struct ahc_softc *ahc, void *platform_arg); void ahc_platform_free(struct ahc_softc *ahc); void ahc_platform_freeze_devq(struct ahc_softc *ahc, struct scb *scb); -static __inline void +static inline void ahc_freeze_scb(struct scb *scb) { if ((scb->io_ctx->result & (CAM_DEV_QFRZN << 16)) == 0) { diff --git a/drivers/scsi/aic7xxx/aic7xxx_pci.c b/drivers/scsi/aic7xxx/aic7xxx_pci.c index c07cb6eebb0..27014b9de12 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_pci.c +++ b/drivers/scsi/aic7xxx/aic7xxx_pci.c @@ -54,7 +54,7 @@ #include "aic7xxx_pci.h" -static __inline uint64_t +static inline uint64_t ahc_compose_id(u_int device, u_int vendor, u_int subdevice, u_int subvendor) { uint64_t id; @@ -960,16 +960,12 @@ ahc_pci_config(struct ahc_softc *ahc, const struct ahc_pci_identity *entry) error = ahc_init(ahc); if (error != 0) return (error); + ahc->init_level++; /* * Allow interrupts now that we are completely setup. */ - error = ahc_pci_map_int(ahc); - if (error != 0) - return (error); - - ahc->init_level++; - return (0); + return ahc_pci_map_int(ahc); } /* diff --git a/drivers/scsi/aic7xxx/aiclib.h b/drivers/scsi/aic7xxx/aiclib.h index 3bfbf0fe1ec..f8fd198aafb 100644 --- a/drivers/scsi/aic7xxx/aiclib.h +++ b/drivers/scsi/aic7xxx/aiclib.h @@ -133,7 +133,7 @@ struct scsi_sense_data #define SCSI_STATUS_TASK_ABORTED 0x40 /************************* Large Disk Handling ********************************/ -static __inline int +static inline int aic_sector_div(sector_t capacity, int heads, int sectors) { /* ugly, ugly sector_div calling convention.. */ @@ -141,7 +141,7 @@ aic_sector_div(sector_t capacity, int heads, int sectors) return (int)capacity; } -static __inline uint32_t +static inline uint32_t scsi_4btoul(uint8_t *bytes) { uint32_t rv; diff --git a/drivers/scsi/arm/cumana_2.c b/drivers/scsi/arm/cumana_2.c index 68a64123af8..c9902b5c1f2 100644 --- a/drivers/scsi/arm/cumana_2.c +++ b/drivers/scsi/arm/cumana_2.c @@ -318,7 +318,7 @@ cumanascsi_2_set_proc_info(struct Scsi_Host *host, char *buffer, int length) { int ret = length; - if (length >= 11 && strcmp(buffer, "CUMANASCSI2") == 0) { + if (length >= 11 && strncmp(buffer, "CUMANASCSI2", 11) == 0) { buffer += 11; length -= 11; @@ -390,7 +390,8 @@ static struct scsi_host_template cumanascsi2_template = { .eh_abort_handler = fas216_eh_abort, .can_queue = 1, .this_id = 7, - .sg_tablesize = SG_ALL, + .sg_tablesize = SCSI_MAX_SG_CHAIN_SEGMENTS, + .dma_boundary = IOMD_DMA_BOUNDARY, .cmd_per_lun = 1, .use_clustering = DISABLE_CLUSTERING, .proc_name = "cumanascsi2", diff --git a/drivers/scsi/arm/eesox.c b/drivers/scsi/arm/eesox.c index bb2477b3fb0..d8435132f46 100644 --- a/drivers/scsi/arm/eesox.c +++ b/drivers/scsi/arm/eesox.c @@ -508,7 +508,8 @@ static struct scsi_host_template eesox_template = { .eh_abort_handler = fas216_eh_abort, .can_queue = 1, .this_id = 7, - .sg_tablesize = SG_ALL, + .sg_tablesize = SCSI_MAX_SG_CHAIN_SEGMENTS, + .dma_boundary = IOMD_DMA_BOUNDARY, .cmd_per_lun = 1, .use_clustering = DISABLE_CLUSTERING, .proc_name = "eesox", diff --git a/drivers/scsi/arm/powertec.c b/drivers/scsi/arm/powertec.c index d9a546d1917..e2297b4c1b9 100644 --- a/drivers/scsi/arm/powertec.c +++ b/drivers/scsi/arm/powertec.c @@ -302,7 +302,8 @@ static struct scsi_host_template powertecscsi_template = { .can_queue = 8, .this_id = 7, - .sg_tablesize = SG_ALL, + .sg_tablesize = SCSI_MAX_SG_CHAIN_SEGMENTS, + .dma_boundary = IOMD_DMA_BOUNDARY, .cmd_per_lun = 2, .use_clustering = ENABLE_CLUSTERING, .proc_name = "powertec", diff --git a/drivers/scsi/atari_NCR5380.c b/drivers/scsi/atari_NCR5380.c index 93b61f14865..0471f880048 100644 --- a/drivers/scsi/atari_NCR5380.c +++ b/drivers/scsi/atari_NCR5380.c @@ -844,7 +844,7 @@ static char *lprint_Scsi_Cmnd(Scsi_Cmnd *cmd, char *pos, char *buffer, int lengt * */ -static int NCR5380_init(struct Scsi_Host *instance, int flags) +static int __init NCR5380_init(struct Scsi_Host *instance, int flags) { int i; SETUP_HOSTDATA(instance); diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c index 21fe07f9df8..ad7a23aef0e 100644 --- a/drivers/scsi/atari_scsi.c +++ b/drivers/scsi/atari_scsi.c @@ -589,7 +589,7 @@ int atari_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) #endif -int atari_scsi_detect(struct scsi_host_template *host) +int __init atari_scsi_detect(struct scsi_host_template *host) { static int called = 0; struct Scsi_Host *instance; diff --git a/drivers/scsi/bvme6000_scsi.c b/drivers/scsi/bvme6000_scsi.c index d858f3d4127..5799cb5cba6 100644 --- a/drivers/scsi/bvme6000_scsi.c +++ b/drivers/scsi/bvme6000_scsi.c @@ -34,7 +34,7 @@ static struct scsi_host_template bvme6000_scsi_driver_template = { static struct platform_device *bvme6000_scsi_device; static __devinit int -bvme6000_probe(struct device *dev) +bvme6000_probe(struct platform_device *dev) { struct Scsi_Host *host; struct NCR_700_Host_Parameters *hostdata; @@ -58,7 +58,8 @@ bvme6000_probe(struct device *dev) hostdata->ctest7_extra = CTEST7_TT1; /* and register the chip */ - host = NCR_700_detect(&bvme6000_scsi_driver_template, hostdata, dev); + host = NCR_700_detect(&bvme6000_scsi_driver_template, hostdata, + &dev->dev); if (!host) { printk(KERN_ERR "bvme6000-scsi: No host detected; " "board configuration problem?\n"); @@ -73,7 +74,7 @@ bvme6000_probe(struct device *dev) goto out_put_host; } - dev_set_drvdata(dev, host); + platform_set_drvdata(dev, host); scsi_scan_host(host); return 0; @@ -87,9 +88,9 @@ bvme6000_probe(struct device *dev) } static __devexit int -bvme6000_device_remove(struct device *dev) +bvme6000_device_remove(struct platform_device *dev) { - struct Scsi_Host *host = dev_get_drvdata(dev); + struct Scsi_Host *host = platform_get_drvdata(dev); struct NCR_700_Host_Parameters *hostdata = shost_priv(host); scsi_remove_host(host); @@ -100,25 +101,27 @@ bvme6000_device_remove(struct device *dev) return 0; } -static struct device_driver bvme6000_scsi_driver = { - .name = "bvme6000-scsi", - .bus = &platform_bus_type, - .probe = bvme6000_probe, - .remove = __devexit_p(bvme6000_device_remove), +static struct platform_driver bvme6000_scsi_driver = { + .driver = { + .name = "bvme6000-scsi", + .owner = THIS_MODULE, + }, + .probe = bvme6000_probe, + .remove = __devexit_p(bvme6000_device_remove), }; static int __init bvme6000_scsi_init(void) { int err; - err = driver_register(&bvme6000_scsi_driver); + err = platform_driver_register(&bvme6000_scsi_driver); if (err) return err; bvme6000_scsi_device = platform_device_register_simple("bvme6000-scsi", -1, NULL, 0); if (IS_ERR(bvme6000_scsi_device)) { - driver_unregister(&bvme6000_scsi_driver); + platform_driver_unregister(&bvme6000_scsi_driver); return PTR_ERR(bvme6000_scsi_device); } @@ -128,7 +131,7 @@ static int __init bvme6000_scsi_init(void) static void __exit bvme6000_scsi_exit(void) { platform_device_unregister(bvme6000_scsi_device); - driver_unregister(&bvme6000_scsi_driver); + platform_driver_unregister(&bvme6000_scsi_driver); } module_init(bvme6000_scsi_init); diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c index af9725409f4..7b1633a8c15 100644 --- a/drivers/scsi/ch.c +++ b/drivers/scsi/ch.c @@ -41,6 +41,7 @@ MODULE_DESCRIPTION("device driver for scsi media changer devices"); MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org>"); MODULE_LICENSE("GPL"); MODULE_ALIAS_CHARDEV_MAJOR(SCSI_CHANGER_MAJOR); +MODULE_ALIAS_SCSI_DEVICE(TYPE_MEDIUM_CHANGER); static int init = 1; module_param(init, int, 0444); diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c index 4003deefb7d..e79e18101f8 100644 --- a/drivers/scsi/constants.c +++ b/drivers/scsi/constants.c @@ -1373,21 +1373,14 @@ static const char * const driverbyte_table[]={ "DRIVER_INVALID", "DRIVER_TIMEOUT", "DRIVER_HARD", "DRIVER_SENSE"}; #define NUM_DRIVERBYTE_STRS ARRAY_SIZE(driverbyte_table) -static const char * const driversuggest_table[]={"SUGGEST_OK", -"SUGGEST_RETRY", "SUGGEST_ABORT", "SUGGEST_REMAP", "SUGGEST_DIE", -"SUGGEST_5", "SUGGEST_6", "SUGGEST_7", "SUGGEST_SENSE"}; -#define NUM_SUGGEST_STRS ARRAY_SIZE(driversuggest_table) - void scsi_show_result(int result) { int hb = host_byte(result); - int db = (driver_byte(result) & DRIVER_MASK); - int su = ((driver_byte(result) & SUGGEST_MASK) >> 4); + int db = driver_byte(result); - printk("Result: hostbyte=%s driverbyte=%s,%s\n", + printk("Result: hostbyte=%s driverbyte=%s\n", (hb < NUM_HOSTBYTE_STRS ? hostbyte_table[hb] : "invalid"), - (db < NUM_DRIVERBYTE_STRS ? driverbyte_table[db] : "invalid"), - (su < NUM_SUGGEST_STRS ? driversuggest_table[su] : "invalid")); + (db < NUM_DRIVERBYTE_STRS ? driverbyte_table[db] : "invalid")); } #else diff --git a/drivers/scsi/cxgb3i/Kbuild b/drivers/scsi/cxgb3i/Kbuild index ee7d6d2f9c3..25a2032bfa2 100644 --- a/drivers/scsi/cxgb3i/Kbuild +++ b/drivers/scsi/cxgb3i/Kbuild @@ -1,4 +1,4 @@ EXTRA_CFLAGS += -I$(TOPDIR)/drivers/net/cxgb3 -cxgb3i-y := cxgb3i_init.o cxgb3i_iscsi.o cxgb3i_pdu.o cxgb3i_offload.o -obj-$(CONFIG_SCSI_CXGB3_ISCSI) += cxgb3i_ddp.o cxgb3i.o +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/cxgb3i.h b/drivers/scsi/cxgb3i/cxgb3i.h index fde6e4c634e..d362860e750 100644 --- a/drivers/scsi/cxgb3i/cxgb3i.h +++ b/drivers/scsi/cxgb3i/cxgb3i.h @@ -20,6 +20,7 @@ #include <linux/list.h> #include <linux/netdevice.h> #include <linux/scatterlist.h> +#include <linux/skbuff.h> #include <scsi/libiscsi_tcp.h> /* from cxgb3 LLD */ @@ -65,10 +66,12 @@ struct cxgb3i_hba { * @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; @@ -77,6 +80,7 @@ struct cxgb3i_adapter { unsigned char hba_cnt; struct cxgb3i_hba *hba[MAX_NPORTS]; + unsigned int flags; unsigned int tx_max_size; unsigned int rx_max_size; @@ -113,13 +117,32 @@ struct cxgb3i_endpoint { 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_add(struct t3cdev *); -void cxgb3i_adapter_remove(struct t3cdev *); -int cxgb3i_adapter_ulp_init(struct cxgb3i_adapter *); -void cxgb3i_adapter_ulp_cleanup(struct cxgb3i_adapter *); +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_find_by_netdev(struct net_device *); struct cxgb3i_hba *cxgb3i_hba_host_add(struct cxgb3i_adapter *, diff --git a/drivers/scsi/cxgb3i/cxgb3i_ddp.c b/drivers/scsi/cxgb3i/cxgb3i_ddp.c index 08f3a09d923..d06a661c209 100644 --- a/drivers/scsi/cxgb3i/cxgb3i_ddp.c +++ b/drivers/scsi/cxgb3i/cxgb3i_ddp.c @@ -23,19 +23,6 @@ #include "cxgb3i_ddp.h" -#define DRV_MODULE_NAME "cxgb3i_ddp" -#define DRV_MODULE_VERSION "1.0.0" -#define DRV_MODULE_RELDATE "Dec. 1, 2008" - -static char version[] = - "Chelsio S3xx iSCSI DDP " DRV_MODULE_NAME - " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; - -MODULE_AUTHOR("Karen Xie <kxie@chelsio.com>"); -MODULE_DESCRIPTION("cxgb3i ddp pagepod manager"); -MODULE_LICENSE("GPL"); -MODULE_VERSION(DRV_MODULE_VERSION); - #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) @@ -66,9 +53,6 @@ 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 LIST_HEAD(cxgb3i_ddp_list); -static DEFINE_RWLOCK(cxgb3i_ddp_rwlock); - /* * functions to program the pagepod in h/w */ @@ -113,8 +97,8 @@ static int set_ddp_map(struct cxgb3i_ddp_info *ddp, struct pagepod_hdr *hdr, return 0; } -static int clear_ddp_map(struct cxgb3i_ddp_info *ddp, unsigned int idx, - unsigned int npods) +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; @@ -122,13 +106,17 @@ static int clear_ddp_map(struct cxgb3i_ddp_info *ddp, unsigned int idx, 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); } - return 0; } static inline int ddp_find_unused_entries(struct cxgb3i_ddp_info *ddp, @@ -196,7 +184,7 @@ static inline int ddp_alloc_gl_skb(struct cxgb3i_ddp_info *ddp, int idx, } /** - * cxgb3i_ddp_find_page_index - return ddp page index for a given page size. + * 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. */ @@ -211,7 +199,6 @@ int cxgb3i_ddp_find_page_index(unsigned long pgsz) ddp_log_debug("ddp page size 0x%lx not supported.\n", pgsz); return DDP_PGIDX_MAX; } -EXPORT_SYMBOL_GPL(cxgb3i_ddp_find_page_index); static inline void ddp_gl_unmap(struct pci_dev *pdev, struct cxgb3i_gather_list *gl) @@ -334,7 +321,6 @@ error_out: kfree(gl); return NULL; } -EXPORT_SYMBOL_GPL(cxgb3i_ddp_make_gl); /** * cxgb3i_ddp_release_gl - release a page buffer list @@ -348,15 +334,13 @@ void cxgb3i_ddp_release_gl(struct cxgb3i_gather_list *gl, ddp_gl_unmap(pdev, gl); kfree(gl); } -EXPORT_SYMBOL_GPL(cxgb3i_ddp_release_gl); /** * cxgb3i_ddp_tag_reserve - set up ddp for a data transfer * @tdev: t3cdev adapter * @tid: connection id * @tformat: tag format - * @tagp: the s/w tag, if ddp setup is successful, it will be updated with - * ddp/hw tag + * @tagp: contains s/w tag initially, will be updated with ddp/hw tag * @gl: the page momory list * @gfp: allocation mode * @@ -431,7 +415,6 @@ unmark_entries: ddp_unmark_entries(ddp, idx, npods); return err; } -EXPORT_SYMBOL_GPL(cxgb3i_ddp_tag_reserve); /** * cxgb3i_ddp_tag_release - release a ddp tag @@ -454,22 +437,21 @@ void cxgb3i_ddp_tag_release(struct t3cdev *tdev, u32 tag) struct cxgb3i_gather_list *gl = ddp->gl_map[idx]; unsigned int npods; - if (!gl) { - ddp_log_error("release ddp 0x%x, idx 0x%x, gl NULL.\n", - tag, idx); + 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, 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); } -EXPORT_SYMBOL_GPL(cxgb3i_ddp_tag_release); static int setup_conn_pgidx(struct t3cdev *tdev, unsigned int tid, int pg_idx, int reply) @@ -510,7 +492,6 @@ int cxgb3i_setup_conn_host_pagesize(struct t3cdev *tdev, unsigned int tid, { return setup_conn_pgidx(tdev, tid, page_idx, reply); } -EXPORT_SYMBOL_GPL(cxgb3i_setup_conn_host_pagesize); /** * cxgb3i_setup_conn_pagesize - setup the conn.'s ddp page size @@ -527,7 +508,6 @@ int cxgb3i_setup_conn_pagesize(struct t3cdev *tdev, unsigned int tid, return setup_conn_pgidx(tdev, tid, pgidx, reply); } -EXPORT_SYMBOL_GPL(cxgb3i_setup_conn_pagesize); /** * cxgb3i_setup_conn_digest - setup conn. digest setting @@ -563,26 +543,104 @@ int cxgb3i_setup_conn_digest(struct t3cdev *tdev, unsigned int tid, cxgb3_ofld_send(tdev, skb); return 0; } -EXPORT_SYMBOL_GPL(cxgb3i_setup_conn_digest); -static int ddp_init(struct t3cdev *tdev) + +/** + * 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 + */ +void cxgb3i_ddp_cleanup(struct t3cdev *tdev) +{ + int i = 0; + 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) { + 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", + tdev, i, npods); + kfree(gl); + ddp_free_gl_skb(ddp, i, npods); + i += npods; + } else + i++; + } + cxgb3i_free_big_mem(ddp); + } +} + +/** + * 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; struct ulp_iscsi_info uinfo; unsigned int ppmax, bits; int i, err; - static int vers_printed; - if (!vers_printed) { - printk(KERN_INFO "%s", version); - vers_printed = 1; + if (tdev->ulp_iscsi) { + 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 err; + return; } ppmax = (uinfo.ulimit - uinfo.llimit + 1) >> PPOD_SIZE_SHIFT; @@ -599,7 +657,7 @@ static int ddp_init(struct t3cdev *tdev) if (!ddp) { ddp_log_warn("%s unable to alloc ddp 0x%d, ddp disabled.\n", tdev->name, ppmax); - return 0; + return; } ddp->gl_map = (struct cxgb3i_gather_list **)(ddp + 1); ddp->gl_skb = (struct sk_buff **)(((char *)ddp->gl_map) + @@ -633,139 +691,26 @@ static int ddp_init(struct t3cdev *tdev) tdev->ulp_iscsi = ddp; - /* add to the list */ - write_lock(&cxgb3i_ddp_rwlock); - list_add_tail(&ddp->list, &cxgb3i_ddp_list); - write_unlock(&cxgb3i_ddp_rwlock); - - ddp_log_info("nppods %u (0x%x ~ 0x%x), bits %u, mask 0x%x,0x%x " - "pkt %u,%u.\n", - ppmax, ddp->llimit, ddp->ulimit, ddp->idx_bits, - ddp->idx_mask, ddp->rsvd_tag_mask, - ddp->max_txsz, ddp->max_rxsz); - return 0; + 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); - return err; -} - -/** - * cxgb3i_adapter_ddp_init - initialize the adapter's ddp resource - * @tdev: t3cdev adapter - * @tformat: tag format - * @txsz: max tx pkt size, filled in by this func. - * @rxsz: max rx pkt size, filled in by this func. - * initialize the ddp pagepod manager for a given adapter if needed and - * setup the tag format for a given iscsi entity - */ -int cxgb3i_adapter_ddp_init(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) { - int err = ddp_init(tdev); - if (err < 0) - return err; - } - 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 = ddp->max_txsz; - *rxsz = ddp->max_rxsz; - ddp_log_info("ddp max pkt size: %u, %u.\n", - ddp->max_txsz, ddp->max_rxsz); - return 0; -} -EXPORT_SYMBOL_GPL(cxgb3i_adapter_ddp_init); - -static void ddp_release(struct cxgb3i_ddp_info *ddp) -{ - int i = 0; - struct t3cdev *tdev = ddp->tdev; - - 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; - - kfree(gl); - ddp_free_gl_skb(ddp, i, npods); - } else - i++; - } - cxgb3i_free_big_mem(ddp); -} - -/** - * cxgb3i_adapter_ddp_cleanup - release the adapter's ddp resource - * @tdev: t3cdev adapter - * release all the resource held by the ddp pagepod manager for a given - * adapter if needed - */ -void cxgb3i_adapter_ddp_cleanup(struct t3cdev *tdev) -{ - struct cxgb3i_ddp_info *ddp; - - /* remove from the list */ - write_lock(&cxgb3i_ddp_rwlock); - list_for_each_entry(ddp, &cxgb3i_ddp_list, list) { - if (ddp->tdev == tdev) { - list_del(&ddp->list); - break; - } - } - write_unlock(&cxgb3i_ddp_rwlock); - - if (ddp) - ddp_release(ddp); -} -EXPORT_SYMBOL_GPL(cxgb3i_adapter_ddp_cleanup); - -/** - * cxgb3i_ddp_init_module - module init entry point - * initialize any driver wide global data structures - */ -static int __init cxgb3i_ddp_init_module(void) -{ - page_idx = cxgb3i_ddp_find_page_index(PAGE_SIZE); - ddp_log_info("system PAGE_SIZE %lu, ddp idx %u.\n", - PAGE_SIZE, page_idx); - return 0; } /** - * cxgb3i_ddp_exit_module - module cleanup/exit entry point - * go through the ddp list and release any resource held. + * cxgb3i_ddp_init - initialize ddp functions */ -static void __exit cxgb3i_ddp_exit_module(void) +void cxgb3i_ddp_init(struct t3cdev *tdev) { - struct cxgb3i_ddp_info *ddp; - - /* release all ddp manager if there is any */ - write_lock(&cxgb3i_ddp_rwlock); - list_for_each_entry(ddp, &cxgb3i_ddp_list, list) { - list_del(&ddp->list); - ddp_release(ddp); + if (page_idx == DDP_PGIDX_MAX) { + page_idx = cxgb3i_ddp_find_page_index(PAGE_SIZE); + ddp_log_info("system PAGE_SIZE %lu, ddp idx %u.\n", + PAGE_SIZE, page_idx); } - write_unlock(&cxgb3i_ddp_rwlock); + ddp_init(tdev); } - -module_init(cxgb3i_ddp_init_module); -module_exit(cxgb3i_ddp_exit_module); diff --git a/drivers/scsi/cxgb3i/cxgb3i_ddp.h b/drivers/scsi/cxgb3i/cxgb3i_ddp.h index 5c7c4d95c49..0d296de7cf3 100644 --- a/drivers/scsi/cxgb3i/cxgb3i_ddp.h +++ b/drivers/scsi/cxgb3i/cxgb3i_ddp.h @@ -13,6 +13,8 @@ #ifndef __CXGB3I_ULP2_DDP_H__ #define __CXGB3I_ULP2_DDP_H__ +#include <linux/vmalloc.h> + /** * struct cxgb3i_tag_format - cxgb3i ulp tag format for an iscsi entity * @@ -85,8 +87,9 @@ struct cxgb3i_ddp_info { 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_MAX) +#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 */ @@ -182,12 +185,11 @@ static inline int cxgb3i_is_ddp_tag(struct cxgb3i_tag_format *tformat, u32 tag) } /** - * cxgb3i_sw_tag_usable - check if a given s/w tag has enough bits left for - * the reserved/hw bits + * 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 is a ddp tag, false otherwise. + * 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) @@ -219,8 +221,7 @@ static inline u32 cxgb3i_set_non_ddp_tag(struct cxgb3i_tag_format *tformat, } /** - * cxgb3i_ddp_tag_base - shift the s/w tag bits so that reserved bits are not - * used. + * 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 */ @@ -300,7 +301,9 @@ int cxgb3i_setup_conn_pagesize(struct t3cdev *, unsigned int tid, int reply, 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_init(struct t3cdev *, struct cxgb3i_tag_format *, +int cxgb3i_adapter_ddp_info(struct t3cdev *, struct cxgb3i_tag_format *, unsigned int *txsz, unsigned int *rxsz); -void cxgb3i_adapter_ddp_cleanup(struct t3cdev *); + +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 index 091ecb4d9f3..042d9bce991 100644 --- a/drivers/scsi/cxgb3i/cxgb3i_init.c +++ b/drivers/scsi/cxgb3i/cxgb3i_init.c @@ -12,8 +12,8 @@ #include "cxgb3i.h" #define DRV_MODULE_NAME "cxgb3i" -#define DRV_MODULE_VERSION "1.0.0" -#define DRV_MODULE_RELDATE "Jun. 1, 2008" +#define DRV_MODULE_VERSION "1.0.2" +#define DRV_MODULE_RELDATE "Mar. 2009" static char version[] = "Chelsio S3xx iSCSI Driver " DRV_MODULE_NAME @@ -26,6 +26,7 @@ MODULE_VERSION(DRV_MODULE_VERSION); static void open_s3_dev(struct t3cdev *); static void close_s3_dev(struct t3cdev *); +static void s3_err_handler(struct t3cdev *tdev, u32 status, u32 error); static cxgb3_cpl_handler_func cxgb3i_cpl_handlers[NUM_CPL_CMDS]; static struct cxgb3_client t3c_client = { @@ -33,6 +34,7 @@ static struct cxgb3_client t3c_client = { .handlers = cxgb3i_cpl_handlers, .add = open_s3_dev, .remove = close_s3_dev, + .err_handler = s3_err_handler, }; /** @@ -48,8 +50,9 @@ static void open_s3_dev(struct t3cdev *t3dev) vers_printed = 1; } + cxgb3i_ddp_init(t3dev); cxgb3i_sdev_add(t3dev, &t3c_client); - cxgb3i_adapter_add(t3dev); + cxgb3i_adapter_open(t3dev); } /** @@ -58,8 +61,28 @@ static void open_s3_dev(struct t3cdev *t3dev) */ static void close_s3_dev(struct t3cdev *t3dev) { - cxgb3i_adapter_remove(t3dev); + cxgb3i_adapter_close(t3dev); cxgb3i_sdev_remove(t3dev); + cxgb3i_ddp_cleanup(t3dev); +} + +static void s3_err_handler(struct t3cdev *tdev, u32 status, u32 error) +{ + struct cxgb3i_adapter *snic = cxgb3i_adapter_find_by_tdev(tdev); + + cxgb3i_log_info("snic 0x%p, tdev 0x%p, status 0x%x, err 0x%x.\n", + snic, tdev, status, error); + if (!snic) + return; + + switch (status) { + case OFFLOAD_STATUS_DOWN: + snic->flags |= CXGB3I_ADAPTER_FLAG_RESET; + break; + case OFFLOAD_STATUS_UP: + snic->flags &= ~CXGB3I_ADAPTER_FLAG_RESET; + break; + } } /** diff --git a/drivers/scsi/cxgb3i/cxgb3i_iscsi.c b/drivers/scsi/cxgb3i/cxgb3i_iscsi.c index d83464b9b3f..fff8e432764 100644 --- a/drivers/scsi/cxgb3i/cxgb3i_iscsi.c +++ b/drivers/scsi/cxgb3i/cxgb3i_iscsi.c @@ -53,36 +53,52 @@ static LIST_HEAD(cxgb3i_snic_list); static DEFINE_RWLOCK(cxgb3i_snic_rwlock); /** - * cxgb3i_adapter_add - init a s3 adapter structure and any h/w settings - * @t3dev: t3cdev adapter - * return the resulting cxgb3i_adapter struct + * cxgb3i_adpater_find_by_tdev - find the cxgb3i_adapter structure via t3cdev + * @tdev: t3cdev pointer */ -struct cxgb3i_adapter *cxgb3i_adapter_add(struct t3cdev *t3dev) +struct cxgb3i_adapter *cxgb3i_adapter_find_by_tdev(struct t3cdev *tdev) { struct cxgb3i_adapter *snic; - struct adapter *adapter = tdev2adap(t3dev); - int i; - snic = kzalloc(sizeof(*snic), GFP_KERNEL); - if (!snic) { - cxgb3i_api_debug("cxgb3 %s, OOM.\n", t3dev->name); - return NULL; + 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; + } } - spin_lock_init(&snic->lock); + 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->tdev = t3dev; snic->pdev = adapter->pdev; snic->tag_format.sw_bits = sw_tag_idx_bits + sw_tag_age_bits; - if (cxgb3i_adapter_ddp_init(t3dev, &snic->tag_format, + err = cxgb3i_adapter_ddp_info(t3dev, &snic->tag_format, &snic->tx_max_size, - &snic->rx_max_size) < 0) - goto free_snic; + &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]) - goto ulp_cleanup; + return -EINVAL; } snic->hba_cnt = adapter->params.nports; @@ -91,52 +107,75 @@ struct cxgb3i_adapter *cxgb3i_adapter_add(struct t3cdev *t3dev) list_add_tail(&snic->list_head, &cxgb3i_snic_list); write_unlock(&cxgb3i_snic_rwlock); - return snic; + cxgb3i_log_info("t3dev 0x%p open, snic 0x%p, %u scsi hosts added.\n", + t3dev, snic, snic->hba_cnt); + return 0; +} -ulp_cleanup: - cxgb3i_adapter_ddp_cleanup(t3dev); -free_snic: - kfree(snic); - return NULL; +/** + * 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_remove - release all the resources held and cleanup any - * h/w settings + * cxgb3i_adapter_close - release the resources held and cleanup h/w settings * @t3dev: t3cdev adapter */ -void cxgb3i_adapter_remove(struct t3cdev *t3dev) +void cxgb3i_adapter_close(struct t3cdev *t3dev) { + struct cxgb3i_adapter *snic = cxgb3i_adapter_find_by_tdev(t3dev); int i; - struct cxgb3i_adapter *snic; + + 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_for_each_entry(snic, &cxgb3i_snic_list, list_head) { - if (snic->tdev == t3dev) { - list_del(&snic->list_head); - break; - } - } + list_del(&snic->list_head); write_unlock(&cxgb3i_snic_rwlock); - if (snic) { - for (i = 0; i < snic->hba_cnt; i++) { - if (snic->hba[i]) { - cxgb3i_hba_host_remove(snic->hba[i]); - snic->hba[i] = NULL; - } + for (i = 0; i < snic->hba_cnt; i++) { + if (snic->hba[i]) { + cxgb3i_hba_host_remove(snic->hba[i]); + snic->hba[i] = NULL; } - - /* release ddp resources */ - cxgb3i_adapter_ddp_cleanup(snic->tdev); - kfree(snic); } + 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 with a given - * net_device + * cxgb3i_hba_find_by_netdev - find the cxgb3i_hba structure via net_device * @t3dev: t3cdev adapter */ struct cxgb3i_hba *cxgb3i_hba_find_by_netdev(struct net_device *ndev) @@ -170,10 +209,10 @@ struct cxgb3i_hba *cxgb3i_hba_host_add(struct cxgb3i_adapter *snic, int err; shost = iscsi_host_alloc(&cxgb3i_host_template, - sizeof(struct cxgb3i_hba), - CXGB3I_SCSI_QDEPTH_DFLT); + sizeof(struct cxgb3i_hba), 1); if (!shost) { - cxgb3i_log_info("iscsi_host_alloc failed.\n"); + cxgb3i_log_info("snic 0x%p, ndev 0x%p, host_alloc failed.\n", + snic, ndev); return NULL; } @@ -191,7 +230,8 @@ struct cxgb3i_hba *cxgb3i_hba_host_add(struct cxgb3i_adapter *snic, pci_dev_get(snic->pdev); err = iscsi_host_add(shost, &snic->pdev->dev); if (err) { - cxgb3i_log_info("iscsi_host_add failed.\n"); + cxgb3i_log_info("snic 0x%p, ndev 0x%p, host_add failed.\n", + snic, ndev); goto pci_dev_put; } @@ -335,13 +375,12 @@ static void cxgb3i_ep_disconnect(struct iscsi_endpoint *ep) * @cmds_max: max # of commands * @qdepth: scsi queue depth * @initial_cmdsn: initial iscsi CMDSN for this session - * @host_no: pointer to return host no * * 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, u32 *host_no) + u32 initial_cmdsn) { struct cxgb3i_endpoint *cep; struct cxgb3i_hba *hba; @@ -360,11 +399,10 @@ cxgb3i_session_create(struct iscsi_endpoint *ep, u16 cmds_max, u16 qdepth, cxgb3i_api_debug("ep 0x%p, cep 0x%p, hba 0x%p.\n", ep, cep, hba); BUG_ON(hba != iscsi_host_priv(shost)); - *host_no = shost->host_no; - cls_session = iscsi_session_setup(&cxgb3i_iscsi_transport, shost, cmds_max, - sizeof(struct iscsi_tcp_task), + sizeof(struct iscsi_tcp_task) + + sizeof(struct cxgb3i_task_data), initial_cmdsn, ISCSI_MAX_TARGET); if (!cls_session) return NULL; @@ -393,33 +431,30 @@ static void cxgb3i_session_destroy(struct iscsi_cls_session *cls_session) } /** - * cxgb3i_conn_max_xmit_dlength -- check the max. xmit pdu segment size, - * reduce it to be within the hardware limit if needed + * 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 = min_t(unsigned int, ULP2_MAX_PDU_PAYLOAD, - cconn->hba->snic->tx_max_size - - ISCSI_PDU_NONPAYLOAD_MAX); + 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_t(unsigned int, - conn->max_xmit_dlength, max); + conn->max_xmit_dlength = min(conn->max_xmit_dlength, max); else conn->max_xmit_dlength = max; align_pdu_size(conn->max_xmit_dlength); - cxgb3i_log_info("conn 0x%p, max xmit %u.\n", + 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 against - * the hardware limit + * cxgb3i_conn_max_recv_dlength -- check the max. recv pdu segment size * @conn: iscsi connection * return 0 if the value is valid, < 0 otherwise. */ @@ -427,9 +462,7 @@ 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 = min_t(unsigned int, ULP2_MAX_PDU_PAYLOAD, - cconn->hba->snic->rx_max_size - - ISCSI_PDU_NONPAYLOAD_MAX); + unsigned int max = cconn->hba->snic->rx_max_size; align_pdu_size(max); if (conn->max_recv_dlength) { @@ -439,8 +472,7 @@ static inline int cxgb3i_conn_max_recv_dlength(struct iscsi_conn *conn) conn->max_recv_dlength, max); return -EINVAL; } - conn->max_recv_dlength = min_t(unsigned int, - conn->max_recv_dlength, max); + conn->max_recv_dlength = min(conn->max_recv_dlength, max); align_pdu_size(conn->max_recv_dlength); } else conn->max_recv_dlength = max; @@ -763,9 +795,9 @@ static void cxgb3i_parse_itt(struct iscsi_conn *conn, itt_t itt, /** * cxgb3i_reserve_itt - generate tag for a give task - * Try to set up ddp for a scsi read 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) { @@ -813,9 +845,9 @@ int cxgb3i_reserve_itt(struct iscsi_task *task, itt_t *hdr_itt) /** * cxgb3i_release_itt - release the tag for a given task - * if the tag is a ddp tag, release the ddp setup * @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) { @@ -844,10 +876,10 @@ static struct scsi_host_template cxgb3i_host_template = { .proc_name = "cxgb3i", .queuecommand = iscsi_queuecommand, .change_queue_depth = iscsi_change_queue_depth, - .can_queue = 128 * (ISCSI_DEF_XMIT_CMDS_MAX - 1), + .can_queue = CXGB3I_SCSI_QDEPTH_DFLT - 1, .sg_tablesize = SG_ALL, .max_sectors = 0xFFFF, - .cmd_per_lun = ISCSI_DEF_CMD_PER_LUN, + .cmd_per_lun = CXGB3I_SCSI_QDEPTH_DFLT, .eh_abort_handler = iscsi_eh_abort, .eh_device_reset_handler = iscsi_eh_device_reset, .eh_target_reset_handler = iscsi_eh_target_reset, diff --git a/drivers/scsi/cxgb3i/cxgb3i_offload.c b/drivers/scsi/cxgb3i/cxgb3i_offload.c index a865f1fefe8..4d8654cdbda 100644 --- a/drivers/scsi/cxgb3i/cxgb3i_offload.c +++ b/drivers/scsi/cxgb3i/cxgb3i_offload.c @@ -23,19 +23,19 @@ #include "cxgb3i_ddp.h" #ifdef __DEBUG_C3CN_CONN__ -#define c3cn_conn_debug cxgb3i_log_info +#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 +#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 +#define c3cn_rx_debug cxgb3i_log_debug #else #define c3cn_rx_debug(fmt...) #endif @@ -47,9 +47,9 @@ 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 = 64 * 1024; +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=64KB)"); +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); @@ -94,29 +94,30 @@ static int c3cn_get_port(struct s3_conn *c3cn, struct cxgb3i_sdev_data *cdata) if (!cdata) goto error_out; - if (c3cn->saddr.sin_port != 0) { - idx = ntohs(c3cn->saddr.sin_port) - cxgb3_sport_base; - if (idx < 0 || idx >= cxgb3_max_connect) - return 0; - if (!test_and_set_bit(idx, cdata->sport_map)) - return -EADDRINUSE; + if (c3cn->saddr.sin_port) { + cxgb3i_log_error("connect, sin_port NON-ZERO %u.\n", + c3cn->saddr.sin_port); + return -EADDRINUSE; } - /* the sport_map_next may not be accurate but that is okay, sport_map - should be */ - start = idx = cdata->sport_map_next; + spin_lock_bh(&cdata->lock); + start = idx = cdata->sport_next; do { if (++idx >= cxgb3_max_connect) idx = 0; - if (!(test_and_set_bit(idx, cdata->sport_map))) { + if (!cdata->sport_conn[idx]) { c3cn->saddr.sin_port = htons(cxgb3_sport_base + idx); - cdata->sport_map_next = 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; @@ -124,15 +125,19 @@ error_out: static void c3cn_put_port(struct s3_conn *c3cn) { - struct cxgb3i_sdev_data *cdata = CXGB3_SDEV_DATA(c3cn->cdev); + 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; - clear_bit(idx, cdata->sport_map); + 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); } @@ -301,8 +306,8 @@ static void act_open_req_arp_failure(struct t3cdev *dev, struct sk_buff *skb) static void skb_entail(struct s3_conn *c3cn, struct sk_buff *skb, int flags) { - CXGB3_SKB_CB(skb)->seq = c3cn->write_seq; - CXGB3_SKB_CB(skb)->flags = flags; + skb_tcp_seq(skb) = c3cn->write_seq; + skb_flags(skb) = flags; __skb_queue_tail(&c3cn->write_queue, skb); } @@ -457,12 +462,9 @@ 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 max. length of an skb is controlled by the max pdu size which is ~16K. - * Also, assume the min. fragment length is the sector size (512), then add - * extra fragment counts for iscsi bhs and payload padding. + * The extra two fragments are for iscsi bhs and payload padding. */ -#define SKB_WR_LIST_SIZE (16384/512 + 3) +#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) @@ -485,7 +487,7 @@ static void s3_init_wr_tab(unsigned int wr_len) static inline void reset_wr_list(struct s3_conn *c3cn) { - c3cn->wr_pending_head = NULL; + c3cn->wr_pending_head = c3cn->wr_pending_tail = NULL; } /* @@ -496,7 +498,7 @@ static inline void reset_wr_list(struct s3_conn *c3cn) static inline void enqueue_wr(struct s3_conn *c3cn, struct sk_buff *skb) { - skb_wr_data(skb) = NULL; + skb_tx_wr_next(skb) = NULL; /* * We want to take an extra reference since both us and the driver @@ -509,10 +511,22 @@ static inline void enqueue_wr(struct s3_conn *c3cn, if (!c3cn->wr_pending_head) c3cn->wr_pending_head = skb; else - skb_wr_data(skb) = skb; + 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; @@ -529,8 +543,8 @@ static inline struct sk_buff *dequeue_wr(struct s3_conn *c3cn) if (likely(skb)) { /* Don't bother clearing the tail */ - c3cn->wr_pending_head = skb_wr_data(skb); - skb_wr_data(skb) = NULL; + c3cn->wr_pending_head = skb_tx_wr_next(skb); + skb_tx_wr_next(skb) = NULL; } return skb; } @@ -543,13 +557,14 @@ static void purge_wr_queue(struct s3_conn *c3cn) } static inline void make_tx_data_wr(struct s3_conn *c3cn, struct sk_buff *skb, - int len) + 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->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 */ @@ -592,7 +607,7 @@ static int c3cn_push_tx_frames(struct s3_conn *c3cn, int req_completion) if (unlikely(c3cn->state == C3CN_STATE_CONNECTING || c3cn->state == C3CN_STATE_CLOSE_WAIT_1 || - c3cn->state == C3CN_STATE_ABORTING)) { + c3cn->state >= C3CN_STATE_ABORTING)) { c3cn_tx_debug("c3cn 0x%p, in closing state %u.\n", c3cn, c3cn->state); return 0; @@ -615,7 +630,7 @@ static int c3cn_push_tx_frames(struct s3_conn *c3cn, int req_completion) 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->datalen, frags, + c3cn, skb->len, skb->data_len, frags, wrs_needed, c3cn->wr_avail); break; } @@ -627,20 +642,24 @@ static int c3cn_push_tx_frames(struct s3_conn *c3cn, int req_completion) c3cn->wr_unacked += wrs_needed; enqueue_wr(c3cn, skb); - if (likely(CXGB3_SKB_CB(skb)->flags & C3CB_FLAG_NEED_HDR)) { - len += ulp_extra_len(skb); - make_tx_data_wr(c3cn, skb, len); - c3cn->snd_nxt += len; - if ((req_completion - && c3cn->wr_unacked == wrs_needed) - || (CXGB3_SKB_CB(skb)->flags & C3CB_FLAG_COMPL) - || c3cn->wr_unacked >= c3cn->wr_max / 2) { - struct work_request_hdr *wr = cplhdr(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); - wr->wr_hi |= htonl(F_WR_COMPL); + + 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; } - CXGB3_SKB_CB(skb)->flags &= ~C3CB_FLAG_NEED_HDR; + 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; @@ -735,8 +754,11 @@ static void process_act_establish(struct s3_conn *c3cn, struct sk_buff *skb) if (unlikely(c3cn_flag(c3cn, C3CN_ACTIVE_CLOSE_NEEDED))) /* upper layer has requested closing */ send_abort_req(c3cn); - else if (c3cn_push_tx_frames(c3cn, 1)) + 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, @@ -1082,8 +1104,8 @@ static void process_rx_iscsi_hdr(struct s3_conn *c3cn, struct sk_buff *skb) return; } - CXGB3_SKB_CB(skb)->seq = ntohl(hdr_cpl->seq); - CXGB3_SKB_CB(skb)->flags = 0; + 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)); @@ -1103,12 +1125,12 @@ static void process_rx_iscsi_hdr(struct s3_conn *c3cn, struct sk_buff *skb) goto abort_conn; skb_ulp_mode(skb) = ULP2_FLAG_DATA_READY; - skb_ulp_pdulen(skb) = ntohs(ddp_cpl.len); - skb_ulp_ddigest(skb) = ntohl(ddp_cpl.ulp_crc); + 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_ulp_pdulen(skb), status); + skb, skb->len, skb_rx_pdulen(skb), status); if (status & (1 << RX_DDP_STATUS_HCRC_SHIFT)) skb_ulp_mode(skb) |= ULP2_FLAG_HCRC_ERROR; @@ -1126,7 +1148,7 @@ static void process_rx_iscsi_hdr(struct s3_conn *c3cn, struct sk_buff *skb) } 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_ulp_pdulen(skb); + 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); @@ -1151,12 +1173,27 @@ static int do_iscsi_hdr(struct t3cdev *t3dev, struct sk_buff *skb, void *ctx) * 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; @@ -1171,6 +1208,17 @@ static void process_wr_ack(struct s3_conn *c3cn, struct sk_buff *skb) 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 { @@ -1180,15 +1228,24 @@ static void process_wr_ack(struct s3_conn *c3cn, struct sk_buff *skb) } } - if (unlikely(before(snd_una, c3cn->snd_una))) + 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) && c3cn_push_tx_frames(c3cn, 0)) + 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); @@ -1253,11 +1310,7 @@ static void c3cn_release_offload_resources(struct s3_conn *c3cn) struct t3cdev *cdev = c3cn->cdev; unsigned int tid = c3cn->tid; - if (!cdev) - return; - c3cn->qset = 0; - c3cn_free_cpl_skbs(c3cn); if (c3cn->wr_avail != c3cn->wr_max) { @@ -1265,18 +1318,22 @@ static void c3cn_release_offload_resources(struct s3_conn *c3cn) reset_wr_list(c3cn); } - 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); + 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; } @@ -1373,10 +1430,10 @@ 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 (likely(c3cn->state != C3CN_STATE_CONNECTING)) - c3cn_active_close(c3cn); - else + 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); } @@ -1452,7 +1509,7 @@ static void init_offload_conn(struct s3_conn *c3cn, struct dst_entry *dst) { BUG_ON(c3cn->cdev != cdev); - c3cn->wr_max = c3cn->wr_avail = T3C_DATA(cdev)->max_wrs; + 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)); @@ -1605,7 +1662,6 @@ int cxgb3i_c3cn_connect(struct s3_conn *c3cn, struct sockaddr_in *usin) c3cn_set_state(c3cn, C3CN_STATE_CLOSED); ip_rt_put(rt); c3cn_put_port(c3cn); - c3cn->daddr.sin_port = 0; return err; } @@ -1671,9 +1727,17 @@ int cxgb3i_c3cn_send_pdus(struct s3_conn *c3cn, struct sk_buff *skb) goto out_err; } - err = -EPIPE; 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 = -EAGAIN; goto out_err; } @@ -1717,10 +1781,25 @@ out_err: 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); } @@ -1762,21 +1841,27 @@ 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 = DIV_ROUND_UP(cxgb3_max_connect, - 8 * sizeof(unsigned long)); + int mapsize = cxgb3_max_connect * sizeof(struct s3_conn *); int i; cdata = cxgb3i_alloc_big_mem(sizeof(*cdata) + mapsize, GFP_KERNEL); - if (!cdata) + 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) + 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; @@ -1788,6 +1873,7 @@ void cxgb3i_sdev_add(struct t3cdev *cdev, struct cxgb3_client *client) 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: @@ -1802,6 +1888,8 @@ 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); diff --git a/drivers/scsi/cxgb3i/cxgb3i_offload.h b/drivers/scsi/cxgb3i/cxgb3i_offload.h index d23156907ff..ebfca960c0a 100644 --- a/drivers/scsi/cxgb3i/cxgb3i_offload.h +++ b/drivers/scsi/cxgb3i/cxgb3i_offload.h @@ -16,7 +16,7 @@ #define _CXGB3I_OFFLOAD_H #include <linux/skbuff.h> -#include <net/tcp.h> +#include <linux/in.h> #include "common.h" #include "adapter.h" @@ -135,6 +135,7 @@ enum c3cn_flags { 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 */ }; /** @@ -147,16 +148,17 @@ enum c3cn_flags { * @cdev: t3cdev adapter * @client: CPL client pointer * @ports: array of adapter ports - * @sport_map_next: next index into the port map - * @sport_map: source port map + * @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; - unsigned int sport_map_next; - unsigned long sport_map[0]; + 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) @@ -178,25 +180,33 @@ void cxgb3i_c3cn_release(struct s3_conn *); * @flag: see C3CB_FLAG_* below * @ulp_mode: ULP mode/submode of sk_buff * @seq: tcp sequence number - * @ddigest: pdu data digest - * @pdulen: recovered pdu length - * @wr_data: scratch area for tx wr */ +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; - __u32 ddigest; - __u32 pdulen; - struct sk_buff *wr_data; + 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_ulp_ddigest(skb) (CXGB3_SKB_CB(skb)->ddigest) -#define skb_ulp_pdulen(skb) (CXGB3_SKB_CB(skb)->pdulen) -#define skb_wr_data(skb) (CXGB3_SKB_CB(skb)->wr_data) +#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 */ @@ -217,6 +227,7 @@ struct sge_opaque_hdr { /* 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 diff --git a/drivers/scsi/cxgb3i/cxgb3i_pdu.c b/drivers/scsi/cxgb3i/cxgb3i_pdu.c index ce7ce8c6094..7eebc9a7cb3 100644 --- a/drivers/scsi/cxgb3i/cxgb3i_pdu.c +++ b/drivers/scsi/cxgb3i/cxgb3i_pdu.c @@ -32,6 +32,10 @@ #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; /* @@ -146,12 +150,13 @@ static inline void tx_skb_setmode(struct sk_buff *skb, int hcrc, int dcrc) void cxgb3i_conn_cleanup_task(struct iscsi_task *task) { - struct iscsi_tcp_task *tcp_task = task->dd_data; + struct cxgb3i_task_data *tdata = task->dd_data + + sizeof(struct iscsi_tcp_task); /* never reached the xmit task callout */ - if (tcp_task->dd_data) - kfree_skb(tcp_task->dd_data); - tcp_task->dd_data = NULL; + 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 */ @@ -159,28 +164,102 @@ void cxgb3i_conn_cleanup_task(struct iscsi_task *task) iscsi_tcp_cleanup_task(task); } -/* - * We do not support ahs yet - */ +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 sk_buff *skb; + 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; - /* always allocate rooms for AHS */ - skb = alloc_skb(sizeof(struct iscsi_hdr) + ISCSI_MAX_AHS_SIZE + - TX_HEADER_LEN, GFP_ATOMIC); - if (!skb) + + /* 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, skb); + task, opcode, tdata->skb); - tcp_task->dd_data = skb; - skb_reserve(skb, TX_HEADER_LEN); - task->hdr = (struct iscsi_hdr *)skb->data; - task->hdr_max = sizeof(struct iscsi_hdr); + 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) @@ -192,13 +271,13 @@ int cxgb3i_conn_alloc_pdu(struct iscsi_task *task, u8 opcode) int cxgb3i_conn_init_pdu(struct iscsi_task *task, unsigned int offset, unsigned int count) { - struct iscsi_tcp_task *tcp_task = task->dd_data; - struct sk_buff *skb = tcp_task->dd_data; struct iscsi_conn *conn = task->conn; - struct page *pg; + 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); - skb_frag_t *frag; + 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); @@ -209,90 +288,94 @@ int cxgb3i_conn_init_pdu(struct iscsi_task *task, unsigned int offset, return 0; if (task->sc) { - struct scatterlist *sg; - struct scsi_data_buffer *sdb; - unsigned int sgoffset = offset; - struct page *sgpg; - unsigned int sglen; - - sdb = scsi_out(task->sc); - sg = sdb->table.sgl; - - for_each_sg(sdb->table.sgl, sg, sdb->table.nents, i) { - cxgb3i_tx_debug("sg %d, page 0x%p, len %u offset %u\n", - i, sg_page(sg), sg->length, sg->offset); - - if (sgoffset < sg->length) - break; - sgoffset -= sg->length; + 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; } - sgpg = sg_page(sg); - sglen = sg->length - sgoffset; - - do { - int j = skb_shinfo(skb)->nr_frags; - unsigned int copy; - - if (!sglen) { - sg = sg_next(sg); - sgpg = sg_page(sg); - sgoffset = 0; - sglen = sg->length; - ++i; + 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); } - copy = min(sglen, datalen); - if (j && skb_can_coalesce(skb, j, sgpg, - sg->offset + sgoffset)) { - skb_shinfo(skb)->frags[j - 1].size += copy; - } else { - get_page(sgpg); - skb_fill_page_desc(skb, j, sgpg, - sg->offset + sgoffset, copy); + if (padlen) { + memset(dst, 0, padlen); + padlen = 0; } - sgoffset += copy; - sglen -= copy; - datalen -= copy; - } while (datalen); + 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); - while (datalen) { - i = skb_shinfo(skb)->nr_frags; - frag = &skb_shinfo(skb)->frags[i]; - - get_page(pg); - frag->page = pg; - frag->page_offset = 0; - frag->size = min((unsigned int)PAGE_SIZE, datalen); - - skb_shinfo(skb)->nr_frags++; - datalen -= frag->size; - pg++; - } + 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; - frag = &skb_shinfo(skb)->frags[i]; - frag->page = pad_page; - frag->page_offset = 0; - frag->size = padlen; - 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; } - datalen = count + padlen; - skb->data_len += datalen; - skb->truesize += datalen; - skb->len += datalen; return 0; } int cxgb3i_conn_xmit_pdu(struct iscsi_task *task) { - struct iscsi_tcp_task *tcp_task = task->dd_data; - struct sk_buff *skb = tcp_task->dd_data; 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; @@ -300,13 +383,14 @@ int cxgb3i_conn_xmit_pdu(struct iscsi_task *task) return 0; datalen = skb->data_len; - tcp_task->dd_data = NULL; + tdata->skb = NULL; err = cxgb3i_c3cn_send_pdus(cconn->cep->c3cn, skb); - cxgb3i_tx_debug("task 0x%p, skb 0x%p, len %u/%u, rv %d.\n", - task, skb, skb->len, skb->data_len, err); 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) @@ -325,12 +409,14 @@ int cxgb3i_conn_xmit_pdu(struct iscsi_task *task) return err; } /* reset skb to send when we are called again */ - tcp_task->dd_data = skb; + tdata->skb = skb; return -EAGAIN; } 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; @@ -366,7 +452,9 @@ void cxgb3i_conn_pdu_ready(struct s3_conn *c3cn) skb = skb_peek(&c3cn->receive_queue); while (!err && skb) { __skb_unlink(skb, &c3cn->receive_queue); - read += skb_ulp_pdulen(skb); + 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); @@ -377,6 +465,11 @@ void cxgb3i_conn_pdu_ready(struct s3_conn *c3cn) 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) @@ -386,7 +479,7 @@ void cxgb3i_conn_tx_open(struct s3_conn *c3cn) cxgb3i_tx_debug("cn 0x%p.\n", c3cn); if (conn) { cxgb3i_tx_debug("cn 0x%p, cid %d.\n", c3cn, conn->id); - scsi_queue_work(conn->session->host, &conn->xmitwork); + iscsi_conn_queue_work(conn); } } diff --git a/drivers/scsi/cxgb3i/cxgb3i_pdu.h b/drivers/scsi/cxgb3i/cxgb3i_pdu.h index a3f685cc236..0770b23d90d 100644 --- a/drivers/scsi/cxgb3i/cxgb3i_pdu.h +++ b/drivers/scsi/cxgb3i/cxgb3i_pdu.h @@ -53,7 +53,7 @@ struct cpl_rx_data_ddp_norss { #define ULP2_FLAG_DCRC_ERROR 0x20 #define ULP2_FLAG_PAD_ERROR 0x40 -void cxgb3i_conn_closing(struct s3_conn *); +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/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index e356b43753f..dba154c8ff6 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -247,8 +247,8 @@ static unsigned submit_stpg(struct scsi_device *sdev, struct alua_dh_data *h) /* Prepare the data buffer */ memset(h->buff, 0, stpg_len); h->buff[4] = TPGS_STATE_OPTIMIZED & 0x0f; - h->buff[6] = (h->group_id >> 8) & 0x0f; - h->buff[7] = h->group_id & 0x0f; + h->buff[6] = (h->group_id >> 8) & 0xff; + h->buff[7] = h->group_id & 0xff; rq = get_alua_req(sdev, h->buff, stpg_len, WRITE); if (!rq) @@ -461,6 +461,15 @@ static int alua_check_sense(struct scsi_device *sdev, */ return ADD_TO_MLQUEUE; } + if (sense_hdr->asc == 0x3f && sense_hdr->ascq == 0x0e) { + /* + * REPORTED_LUNS_DATA_HAS_CHANGED is reported + * when switching controllers on targets like + * Intel Multi-Flex. We can just retry. + */ + return ADD_TO_MLQUEUE; + } + break; } @@ -691,6 +700,7 @@ static const struct scsi_dh_devlist alua_dev_list[] = { {"IBM", "2107900" }, {"IBM", "2145" }, {"Pillar", "Axiom" }, + {"Intel", "Multi-Flex"}, {NULL, NULL} }; diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c index 53664765570..43b8c51e98d 100644 --- a/drivers/scsi/device_handler/scsi_dh_rdac.c +++ b/drivers/scsi/device_handler/scsi_dh_rdac.c @@ -449,28 +449,40 @@ static int mode_select_handle_sense(struct scsi_device *sdev, unsigned char *sensebuf) { struct scsi_sense_hdr sense_hdr; - int sense, err = SCSI_DH_IO, ret; + int err = SCSI_DH_IO, ret; ret = scsi_normalize_sense(sensebuf, SCSI_SENSE_BUFFERSIZE, &sense_hdr); if (!ret) goto done; err = SCSI_DH_OK; - sense = (sense_hdr.sense_key << 16) | (sense_hdr.asc << 8) | - sense_hdr.ascq; - /* If it is retryable failure, submit the c9 inquiry again */ - if (sense == 0x59136 || sense == 0x68b02 || sense == 0xb8b02 || - sense == 0x62900) { - /* 0x59136 - Command lock contention - * 0x[6b]8b02 - Quiesense in progress or achieved - * 0x62900 - Power On, Reset, or Bus Device Reset - */ + + switch (sense_hdr.sense_key) { + case NO_SENSE: + case ABORTED_COMMAND: + case UNIT_ATTENTION: err = SCSI_DH_RETRY; + break; + case NOT_READY: + if (sense_hdr.asc == 0x04 && sense_hdr.ascq == 0x01) + /* LUN Not Ready and is in the Process of Becoming + * Ready + */ + err = SCSI_DH_RETRY; + break; + case ILLEGAL_REQUEST: + if (sense_hdr.asc == 0x91 && sense_hdr.ascq == 0x36) + /* + * Command Lock contention + */ + err = SCSI_DH_RETRY; + break; + default: + sdev_printk(KERN_INFO, sdev, + "MODE_SELECT failed with sense %02x/%02x/%02x.\n", + sense_hdr.sense_key, sense_hdr.asc, sense_hdr.ascq); } - if (sense) - sdev_printk(KERN_INFO, sdev, - "MODE_SELECT failed with sense 0x%x.\n", sense); done: return err; } @@ -562,6 +574,12 @@ static int rdac_check_sense(struct scsi_device *sdev, * Just retry and wait. */ return ADD_TO_MLQUEUE; + if (sense_hdr->asc == 0xA1 && sense_hdr->ascq == 0x02) + /* LUN Not Ready - Quiescense in progress + * or has been achieved + * Just retry. + */ + return ADD_TO_MLQUEUE; break; case ILLEGAL_REQUEST: if (sense_hdr->asc == 0x94 && sense_hdr->ascq == 0x01) { @@ -579,6 +597,11 @@ static int rdac_check_sense(struct scsi_device *sdev, * Power On, Reset, or Bus Device Reset, just retry. */ return ADD_TO_MLQUEUE; + if (sense_hdr->asc == 0x8b && sense_hdr->ascq == 0x02) + /* + * Quiescence in progress , just retry. + */ + return ADD_TO_MLQUEUE; break; } /* success just means we do not care what scsi-ml does */ diff --git a/drivers/scsi/fcoe/Makefile b/drivers/scsi/fcoe/Makefile index b78da06d7c0..950f27615c7 100644 --- a/drivers/scsi/fcoe/Makefile +++ b/drivers/scsi/fcoe/Makefile @@ -1,8 +1,2 @@ -# $Id: Makefile - obj-$(CONFIG_FCOE) += fcoe.o - -fcoe-y := \ - libfcoe.o \ - fcoe_sw.o \ - fc_transport_fcoe.o +obj-$(CONFIG_LIBFCOE) += libfcoe.o diff --git a/drivers/scsi/fcoe/fc_transport_fcoe.c b/drivers/scsi/fcoe/fc_transport_fcoe.c deleted file mode 100644 index bf7fe6fc082..00000000000 --- a/drivers/scsi/fcoe/fc_transport_fcoe.c +++ /dev/null @@ -1,446 +0,0 @@ -/* - * Copyright(c) 2007 - 2008 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * 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., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * Maintained at www.Open-FCoE.org - */ - -#include <linux/pci.h> -#include <scsi/libfcoe.h> -#include <scsi/fc_transport_fcoe.h> - -/* internal fcoe transport */ -struct fcoe_transport_internal { - struct fcoe_transport *t; - struct net_device *netdev; - struct list_head list; -}; - -/* fcoe transports list and its lock */ -static LIST_HEAD(fcoe_transports); -static DEFINE_MUTEX(fcoe_transports_lock); - -/** - * fcoe_transport_default - returns ptr to the default transport fcoe_sw - **/ -struct fcoe_transport *fcoe_transport_default(void) -{ - return &fcoe_sw_transport; -} - -/** - * fcoe_transport_to_pcidev - get the pci dev from a netdev - * @netdev: the netdev that pci dev will be retrived from - * - * Returns: NULL or the corrsponding pci_dev - **/ -struct pci_dev *fcoe_transport_pcidev(const struct net_device *netdev) -{ - if (!netdev->dev.parent) - return NULL; - return to_pci_dev(netdev->dev.parent); -} - -/** - * fcoe_transport_device_lookup - find out netdev is managed by the - * transport - * assign a transport to a device - * @netdev: the netdev the transport to be attached to - * - * This will look for existing offload driver, if not found, it falls back to - * the default sw hba (fcoe_sw) as its fcoe transport. - * - * Returns: 0 for success - **/ -static struct fcoe_transport_internal *fcoe_transport_device_lookup( - struct fcoe_transport *t, struct net_device *netdev) -{ - struct fcoe_transport_internal *ti; - - /* assign the transpor to this device */ - mutex_lock(&t->devlock); - list_for_each_entry(ti, &t->devlist, list) { - if (ti->netdev == netdev) { - mutex_unlock(&t->devlock); - return ti; - } - } - mutex_unlock(&t->devlock); - return NULL; -} -/** - * fcoe_transport_device_add - assign a transport to a device - * @netdev: the netdev the transport to be attached to - * - * This will look for existing offload driver, if not found, it falls back to - * the default sw hba (fcoe_sw) as its fcoe transport. - * - * Returns: 0 for success - **/ -static int fcoe_transport_device_add(struct fcoe_transport *t, - struct net_device *netdev) -{ - struct fcoe_transport_internal *ti; - - ti = fcoe_transport_device_lookup(t, netdev); - if (ti) { - printk(KERN_DEBUG "fcoe_transport_device_add:" - "device %s is already added to transport %s\n", - netdev->name, t->name); - return -EEXIST; - } - /* allocate an internal struct to host the netdev and the list */ - ti = kzalloc(sizeof(*ti), GFP_KERNEL); - if (!ti) - return -ENOMEM; - - ti->t = t; - ti->netdev = netdev; - INIT_LIST_HEAD(&ti->list); - dev_hold(ti->netdev); - - mutex_lock(&t->devlock); - list_add(&ti->list, &t->devlist); - mutex_unlock(&t->devlock); - - printk(KERN_DEBUG "fcoe_transport_device_add:" - "device %s added to transport %s\n", - netdev->name, t->name); - - return 0; -} - -/** - * fcoe_transport_device_remove - remove a device from its transport - * @netdev: the netdev the transport to be attached to - * - * this removes the device from the transport so the given transport will - * not manage this device any more - * - * Returns: 0 for success - **/ -static int fcoe_transport_device_remove(struct fcoe_transport *t, - struct net_device *netdev) -{ - struct fcoe_transport_internal *ti; - - ti = fcoe_transport_device_lookup(t, netdev); - if (!ti) { - printk(KERN_DEBUG "fcoe_transport_device_remove:" - "device %s is not managed by transport %s\n", - netdev->name, t->name); - return -ENODEV; - } - mutex_lock(&t->devlock); - list_del(&ti->list); - mutex_unlock(&t->devlock); - printk(KERN_DEBUG "fcoe_transport_device_remove:" - "device %s removed from transport %s\n", - netdev->name, t->name); - dev_put(ti->netdev); - kfree(ti); - return 0; -} - -/** - * fcoe_transport_device_remove_all - remove all from transport devlist - * - * this removes the device from the transport so the given transport will - * not manage this device any more - * - * Returns: 0 for success - **/ -static void fcoe_transport_device_remove_all(struct fcoe_transport *t) -{ - struct fcoe_transport_internal *ti, *tmp; - - mutex_lock(&t->devlock); - list_for_each_entry_safe(ti, tmp, &t->devlist, list) { - list_del(&ti->list); - kfree(ti); - } - mutex_unlock(&t->devlock); -} - -/** - * fcoe_transport_match - use the bus device match function to match the hw - * @t: the fcoe transport - * @netdev: - * - * This function is used to check if the givne transport wants to manage the - * input netdev. if the transports implements the match function, it will be - * called, o.w. we just compare the pci vendor and device id. - * - * Returns: true for match up - **/ -static bool fcoe_transport_match(struct fcoe_transport *t, - struct net_device *netdev) -{ - /* match transport by vendor and device id */ - struct pci_dev *pci; - - pci = fcoe_transport_pcidev(netdev); - - if (pci) { - printk(KERN_DEBUG "fcoe_transport_match:" - "%s:%x:%x -- %s:%x:%x\n", - t->name, t->vendor, t->device, - netdev->name, pci->vendor, pci->device); - - /* if transport supports match */ - if (t->match) - return t->match(netdev); - - /* else just compare the vendor and device id: pci only */ - return (t->vendor == pci->vendor) && (t->device == pci->device); - } - return false; -} - -/** - * fcoe_transport_lookup - check if the transport is already registered - * @t: the transport to be looked up - * - * This compares the parent device (pci) vendor and device id - * - * Returns: NULL if not found - * - * TODO - return default sw transport if no other transport is found - **/ -static struct fcoe_transport *fcoe_transport_lookup( - struct net_device *netdev) -{ - struct fcoe_transport *t; - - mutex_lock(&fcoe_transports_lock); - list_for_each_entry(t, &fcoe_transports, list) { - if (fcoe_transport_match(t, netdev)) { - mutex_unlock(&fcoe_transports_lock); - return t; - } - } - mutex_unlock(&fcoe_transports_lock); - - printk(KERN_DEBUG "fcoe_transport_lookup:" - "use default transport for %s\n", netdev->name); - return fcoe_transport_default(); -} - -/** - * fcoe_transport_register - adds a fcoe transport to the fcoe transports list - * @t: ptr to the fcoe transport to be added - * - * Returns: 0 for success - **/ -int fcoe_transport_register(struct fcoe_transport *t) -{ - struct fcoe_transport *tt; - - /* TODO - add fcoe_transport specific initialization here */ - mutex_lock(&fcoe_transports_lock); - list_for_each_entry(tt, &fcoe_transports, list) { - if (tt == t) { - mutex_unlock(&fcoe_transports_lock); - return -EEXIST; - } - } - list_add_tail(&t->list, &fcoe_transports); - mutex_unlock(&fcoe_transports_lock); - - mutex_init(&t->devlock); - INIT_LIST_HEAD(&t->devlist); - - printk(KERN_DEBUG "fcoe_transport_register:%s\n", t->name); - - return 0; -} -EXPORT_SYMBOL_GPL(fcoe_transport_register); - -/** - * fcoe_transport_unregister - remove the tranport fro the fcoe transports list - * @t: ptr to the fcoe transport to be removed - * - * Returns: 0 for success - **/ -int fcoe_transport_unregister(struct fcoe_transport *t) -{ - struct fcoe_transport *tt, *tmp; - - mutex_lock(&fcoe_transports_lock); - list_for_each_entry_safe(tt, tmp, &fcoe_transports, list) { - if (tt == t) { - list_del(&t->list); - mutex_unlock(&fcoe_transports_lock); - fcoe_transport_device_remove_all(t); - printk(KERN_DEBUG "fcoe_transport_unregister:%s\n", - t->name); - return 0; - } - } - mutex_unlock(&fcoe_transports_lock); - return -ENODEV; -} -EXPORT_SYMBOL_GPL(fcoe_transport_unregister); - -/* - * fcoe_load_transport_driver - load an offload driver by alias name - * @netdev: the target net device - * - * Requests for an offload driver module as the fcoe transport, if fails, it - * falls back to use the SW HBA (fcoe_sw) as its transport - * - * TODO - - * 1. supports only PCI device - * 2. needs fix for VLAn and bonding - * 3. pure hw fcoe hba may not have netdev - * - * Returns: 0 for success - **/ -int fcoe_load_transport_driver(struct net_device *netdev) -{ - struct pci_dev *pci; - struct device *dev = netdev->dev.parent; - - if (fcoe_transport_lookup(netdev)) { - /* load default transport */ - printk(KERN_DEBUG "fcoe: already loaded transport for %s\n", - netdev->name); - return -EEXIST; - } - - pci = to_pci_dev(dev); - if (dev->bus != &pci_bus_type) { - printk(KERN_DEBUG "fcoe: support noly PCI device\n"); - return -ENODEV; - } - printk(KERN_DEBUG "fcoe: loading driver fcoe-pci-0x%04x-0x%04x\n", - pci->vendor, pci->device); - - return request_module("fcoe-pci-0x%04x-0x%04x", - pci->vendor, pci->device); - -} -EXPORT_SYMBOL_GPL(fcoe_load_transport_driver); - -/** - * fcoe_transport_attach - load transport to fcoe - * @netdev: the netdev the transport to be attached to - * - * This will look for existing offload driver, if not found, it falls back to - * the default sw hba (fcoe_sw) as its fcoe transport. - * - * Returns: 0 for success - **/ -int fcoe_transport_attach(struct net_device *netdev) -{ - struct fcoe_transport *t; - - /* find the corresponding transport */ - t = fcoe_transport_lookup(netdev); - if (!t) { - printk(KERN_DEBUG "fcoe_transport_attach" - ":no transport for %s:use %s\n", - netdev->name, t->name); - return -ENODEV; - } - /* add to the transport */ - if (fcoe_transport_device_add(t, netdev)) { - printk(KERN_DEBUG "fcoe_transport_attach" - ":failed to add %s to tramsport %s\n", - netdev->name, t->name); - return -EIO; - } - /* transport create function */ - if (t->create) - t->create(netdev); - - printk(KERN_DEBUG "fcoe_transport_attach:transport %s for %s\n", - t->name, netdev->name); - return 0; -} -EXPORT_SYMBOL_GPL(fcoe_transport_attach); - -/** - * fcoe_transport_release - unload transport from fcoe - * @netdev: the net device on which fcoe is to be released - * - * Returns: 0 for success - **/ -int fcoe_transport_release(struct net_device *netdev) -{ - struct fcoe_transport *t; - - /* find the corresponding transport */ - t = fcoe_transport_lookup(netdev); - if (!t) { - printk(KERN_DEBUG "fcoe_transport_release:" - "no transport for %s:use %s\n", - netdev->name, t->name); - return -ENODEV; - } - /* remove the device from the transport */ - if (fcoe_transport_device_remove(t, netdev)) { - printk(KERN_DEBUG "fcoe_transport_release:" - "failed to add %s to tramsport %s\n", - netdev->name, t->name); - return -EIO; - } - /* transport destroy function */ - if (t->destroy) - t->destroy(netdev); - - printk(KERN_DEBUG "fcoe_transport_release:" - "device %s dettached from transport %s\n", - netdev->name, t->name); - - return 0; -} -EXPORT_SYMBOL_GPL(fcoe_transport_release); - -/** - * fcoe_transport_init - initializes fcoe transport layer - * - * This prepares for the fcoe transport layer - * - * Returns: none - **/ -int __init fcoe_transport_init(void) -{ - INIT_LIST_HEAD(&fcoe_transports); - mutex_init(&fcoe_transports_lock); - return 0; -} - -/** - * fcoe_transport_exit - cleans up the fcoe transport layer - * This cleans up the fcoe transport layer. removing any transport on the list, - * note that the transport destroy func is not called here. - * - * Returns: none - **/ -int __exit fcoe_transport_exit(void) -{ - struct fcoe_transport *t, *tmp; - - mutex_lock(&fcoe_transports_lock); - list_for_each_entry_safe(t, tmp, &fcoe_transports, list) { - list_del(&t->list); - mutex_unlock(&fcoe_transports_lock); - fcoe_transport_device_remove_all(t); - mutex_lock(&fcoe_transports_lock); - } - mutex_unlock(&fcoe_transports_lock); - return 0; -} diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c new file mode 100644 index 00000000000..94e1e318977 --- /dev/null +++ b/drivers/scsi/fcoe/fcoe.c @@ -0,0 +1,1878 @@ +/* + * Copyright(c) 2007 - 2008 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * 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., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * Maintained at www.Open-FCoE.org + */ + +#include <linux/module.h> +#include <linux/version.h> +#include <linux/spinlock.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/ethtool.h> +#include <linux/if_ether.h> +#include <linux/if_vlan.h> +#include <linux/crc32.h> +#include <linux/cpu.h> +#include <linux/fs.h> +#include <linux/sysfs.h> +#include <linux/ctype.h> +#include <scsi/scsi_tcq.h> +#include <scsi/scsicam.h> +#include <scsi/scsi_transport.h> +#include <scsi/scsi_transport_fc.h> +#include <net/rtnetlink.h> + +#include <scsi/fc/fc_encaps.h> +#include <scsi/fc/fc_fip.h> + +#include <scsi/libfc.h> +#include <scsi/fc_frame.h> +#include <scsi/libfcoe.h> + +#include "fcoe.h" + +static int debug_fcoe; + +MODULE_AUTHOR("Open-FCoE.org"); +MODULE_DESCRIPTION("FCoE"); +MODULE_LICENSE("GPL v2"); + +/* fcoe host list */ +LIST_HEAD(fcoe_hostlist); +DEFINE_RWLOCK(fcoe_hostlist_lock); +DEFINE_TIMER(fcoe_timer, NULL, 0, 0); +DEFINE_PER_CPU(struct fcoe_percpu_s, fcoe_percpu); + +/* Function Prototyes */ +static int fcoe_reset(struct Scsi_Host *shost); +static int fcoe_xmit(struct fc_lport *, struct fc_frame *); +static int fcoe_rcv(struct sk_buff *, struct net_device *, + struct packet_type *, struct net_device *); +static int fcoe_percpu_receive_thread(void *arg); +static void fcoe_clean_pending_queue(struct fc_lport *lp); +static void fcoe_percpu_clean(struct fc_lport *lp); +static int fcoe_link_ok(struct fc_lport *lp); + +static struct fc_lport *fcoe_hostlist_lookup(const struct net_device *); +static int fcoe_hostlist_add(const struct fc_lport *); +static int fcoe_hostlist_remove(const struct fc_lport *); + +static int fcoe_check_wait_queue(struct fc_lport *); +static int fcoe_device_notification(struct notifier_block *, ulong, void *); +static void fcoe_dev_setup(void); +static void fcoe_dev_cleanup(void); + +/* notification function from net device */ +static struct notifier_block fcoe_notifier = { + .notifier_call = fcoe_device_notification, +}; + +static struct scsi_transport_template *scsi_transport_fcoe_sw; + +struct fc_function_template fcoe_transport_function = { + .show_host_node_name = 1, + .show_host_port_name = 1, + .show_host_supported_classes = 1, + .show_host_supported_fc4s = 1, + .show_host_active_fc4s = 1, + .show_host_maxframe_size = 1, + + .show_host_port_id = 1, + .show_host_supported_speeds = 1, + .get_host_speed = fc_get_host_speed, + .show_host_speed = 1, + .show_host_port_type = 1, + .get_host_port_state = fc_get_host_port_state, + .show_host_port_state = 1, + .show_host_symbolic_name = 1, + + .dd_fcrport_size = sizeof(struct fc_rport_libfc_priv), + .show_rport_maxframe_size = 1, + .show_rport_supported_classes = 1, + + .show_host_fabric_name = 1, + .show_starget_node_name = 1, + .show_starget_port_name = 1, + .show_starget_port_id = 1, + .set_rport_dev_loss_tmo = fc_set_rport_loss_tmo, + .show_rport_dev_loss_tmo = 1, + .get_fc_host_stats = fc_get_host_stats, + .issue_fc_host_lip = fcoe_reset, + + .terminate_rport_io = fc_rport_terminate_io, +}; + +static struct scsi_host_template fcoe_shost_template = { + .module = THIS_MODULE, + .name = "FCoE Driver", + .proc_name = FCOE_NAME, + .queuecommand = fc_queuecommand, + .eh_abort_handler = fc_eh_abort, + .eh_device_reset_handler = fc_eh_device_reset, + .eh_host_reset_handler = fc_eh_host_reset, + .slave_alloc = fc_slave_alloc, + .change_queue_depth = fc_change_queue_depth, + .change_queue_type = fc_change_queue_type, + .this_id = -1, + .cmd_per_lun = 32, + .can_queue = FCOE_MAX_OUTSTANDING_COMMANDS, + .use_clustering = ENABLE_CLUSTERING, + .sg_tablesize = SG_ALL, + .max_sectors = 0xffff, +}; + +/** + * fcoe_lport_config() - sets up the fc_lport + * @lp: ptr to the fc_lport + * @shost: ptr to the parent scsi host + * + * Returns: 0 for success + */ +static int fcoe_lport_config(struct fc_lport *lp) +{ + lp->link_up = 0; + lp->qfull = 0; + lp->max_retry_count = 3; + lp->e_d_tov = 2 * 1000; /* FC-FS default */ + lp->r_a_tov = 2 * 2 * 1000; + lp->service_params = (FCP_SPPF_INIT_FCN | FCP_SPPF_RD_XRDY_DIS | + FCP_SPPF_RETRY | FCP_SPPF_CONF_COMPL); + + fc_lport_init_stats(lp); + + /* lport fc_lport related configuration */ + fc_lport_config(lp); + + /* offload related configuration */ + lp->crc_offload = 0; + lp->seq_offload = 0; + lp->lro_enabled = 0; + lp->lro_xid = 0; + lp->lso_max = 0; + + return 0; +} + +/** + * fcoe_netdev_config() - Set up netdev for SW FCoE + * @lp : ptr to the fc_lport + * @netdev : ptr to the associated netdevice struct + * + * Must be called after fcoe_lport_config() as it will use lport mutex + * + * Returns : 0 for success + */ +static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev) +{ + u32 mfs; + u64 wwnn, wwpn; + struct fcoe_softc *fc; + u8 flogi_maddr[ETH_ALEN]; + + /* Setup lport private data to point to fcoe softc */ + fc = lport_priv(lp); + fc->ctlr.lp = lp; + fc->real_dev = netdev; + fc->phys_dev = netdev; + + /* Require support for get_pauseparam ethtool op. */ + if (netdev->priv_flags & IFF_802_1Q_VLAN) + fc->phys_dev = vlan_dev_real_dev(netdev); + + /* Do not support for bonding device */ + if ((fc->real_dev->priv_flags & IFF_MASTER_ALB) || + (fc->real_dev->priv_flags & IFF_SLAVE_INACTIVE) || + (fc->real_dev->priv_flags & IFF_MASTER_8023AD)) { + return -EOPNOTSUPP; + } + + /* + * Determine max frame size based on underlying device and optional + * user-configured limit. If the MFS is too low, fcoe_link_ok() + * will return 0, so do this first. + */ + mfs = fc->real_dev->mtu - (sizeof(struct fcoe_hdr) + + sizeof(struct fcoe_crc_eof)); + if (fc_set_mfs(lp, mfs)) + return -EINVAL; + + /* offload features support */ + if (fc->real_dev->features & NETIF_F_SG) + lp->sg_supp = 1; + +#ifdef NETIF_F_FCOE_CRC + if (netdev->features & NETIF_F_FCOE_CRC) { + lp->crc_offload = 1; + printk(KERN_DEBUG "fcoe:%s supports FCCRC offload\n", + netdev->name); + } +#endif +#ifdef NETIF_F_FSO + if (netdev->features & NETIF_F_FSO) { + lp->seq_offload = 1; + lp->lso_max = netdev->gso_max_size; + printk(KERN_DEBUG "fcoe:%s supports LSO for max len 0x%x\n", + netdev->name, lp->lso_max); + } +#endif + if (netdev->fcoe_ddp_xid) { + lp->lro_enabled = 1; + lp->lro_xid = netdev->fcoe_ddp_xid; + printk(KERN_DEBUG "fcoe:%s supports LRO for max xid 0x%x\n", + netdev->name, lp->lro_xid); + } + skb_queue_head_init(&fc->fcoe_pending_queue); + fc->fcoe_pending_queue_active = 0; + + /* setup Source Mac Address */ + memcpy(fc->ctlr.ctl_src_addr, fc->real_dev->dev_addr, + fc->real_dev->addr_len); + + wwnn = fcoe_wwn_from_mac(fc->real_dev->dev_addr, 1, 0); + fc_set_wwnn(lp, wwnn); + /* XXX - 3rd arg needs to be vlan id */ + wwpn = fcoe_wwn_from_mac(fc->real_dev->dev_addr, 2, 0); + fc_set_wwpn(lp, wwpn); + + /* + * Add FCoE MAC address as second unicast MAC address + * or enter promiscuous mode if not capable of listening + * for multiple unicast MACs. + */ + rtnl_lock(); + memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); + dev_unicast_add(fc->real_dev, flogi_maddr, ETH_ALEN); + rtnl_unlock(); + + /* + * setup the receive function from ethernet driver + * on the ethertype for the given device + */ + fc->fcoe_packet_type.func = fcoe_rcv; + fc->fcoe_packet_type.type = __constant_htons(ETH_P_FCOE); + fc->fcoe_packet_type.dev = fc->real_dev; + dev_add_pack(&fc->fcoe_packet_type); + + return 0; +} + +/** + * fcoe_shost_config() - Sets up fc_lport->host + * @lp : ptr to the fc_lport + * @shost : ptr to the associated scsi host + * @dev : device associated to scsi host + * + * Must be called after fcoe_lport_config() and fcoe_netdev_config() + * + * Returns : 0 for success + */ +static int fcoe_shost_config(struct fc_lport *lp, struct Scsi_Host *shost, + struct device *dev) +{ + int rc = 0; + + /* lport scsi host config */ + lp->host = shost; + + lp->host->max_lun = FCOE_MAX_LUN; + lp->host->max_id = FCOE_MAX_FCP_TARGET; + lp->host->max_channel = 0; + lp->host->transportt = scsi_transport_fcoe_sw; + + /* add the new host to the SCSI-ml */ + rc = scsi_add_host(lp->host, dev); + if (rc) { + FC_DBG("fcoe_shost_config:error on scsi_add_host\n"); + return rc; + } + sprintf(fc_host_symbolic_name(lp->host), "%s v%s over %s", + FCOE_NAME, FCOE_VERSION, + fcoe_netdev(lp)->name); + + return 0; +} + +/** + * fcoe_em_config() - allocates em for this lport + * @lp: the port that em is to allocated for + * + * Returns : 0 on success + */ +static inline int fcoe_em_config(struct fc_lport *lp) +{ + BUG_ON(lp->emp); + + lp->emp = fc_exch_mgr_alloc(lp, FC_CLASS_3, + FCOE_MIN_XID, FCOE_MAX_XID); + if (!lp->emp) + return -ENOMEM; + + return 0; +} + +/** + * fcoe_if_destroy() - FCoE software HBA tear-down function + * @netdev: ptr to the associated net_device + * + * Returns: 0 if link is OK for use by FCoE. + */ +static int fcoe_if_destroy(struct net_device *netdev) +{ + struct fc_lport *lp = NULL; + struct fcoe_softc *fc; + u8 flogi_maddr[ETH_ALEN]; + + BUG_ON(!netdev); + + printk(KERN_DEBUG "fcoe_if_destroy:interface on %s\n", + netdev->name); + + lp = fcoe_hostlist_lookup(netdev); + if (!lp) + return -ENODEV; + + fc = lport_priv(lp); + + /* Logout of the fabric */ + fc_fabric_logoff(lp); + + /* Remove the instance from fcoe's list */ + fcoe_hostlist_remove(lp); + + /* Don't listen for Ethernet packets anymore */ + dev_remove_pack(&fc->fcoe_packet_type); + dev_remove_pack(&fc->fip_packet_type); + fcoe_ctlr_destroy(&fc->ctlr); + + /* Cleanup the fc_lport */ + fc_lport_destroy(lp); + fc_fcp_destroy(lp); + + /* Detach from the scsi-ml */ + fc_remove_host(lp->host); + scsi_remove_host(lp->host); + + /* There are no more rports or I/O, free the EM */ + if (lp->emp) + fc_exch_mgr_free(lp->emp); + + /* Delete secondary MAC addresses */ + rtnl_lock(); + memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); + dev_unicast_delete(fc->real_dev, flogi_maddr, ETH_ALEN); + if (!is_zero_ether_addr(fc->ctlr.data_src_addr)) + dev_unicast_delete(fc->real_dev, + fc->ctlr.data_src_addr, ETH_ALEN); + dev_mc_delete(fc->real_dev, FIP_ALL_ENODE_MACS, ETH_ALEN, 0); + rtnl_unlock(); + + /* Free the per-CPU revieve threads */ + fcoe_percpu_clean(lp); + + /* Free existing skbs */ + fcoe_clean_pending_queue(lp); + + /* Free memory used by statistical counters */ + fc_lport_free_stats(lp); + + /* Release the net_device and Scsi_Host */ + dev_put(fc->real_dev); + scsi_host_put(lp->host); + + return 0; +} + +/* + * fcoe_ddp_setup - calls LLD's ddp_setup through net_device + * @lp: the corresponding fc_lport + * @xid: the exchange id for this ddp transfer + * @sgl: the scatterlist describing this transfer + * @sgc: number of sg items + * + * Returns : 0 no ddp + */ +static int fcoe_ddp_setup(struct fc_lport *lp, u16 xid, + struct scatterlist *sgl, unsigned int sgc) +{ + struct net_device *n = fcoe_netdev(lp); + + if (n->netdev_ops && n->netdev_ops->ndo_fcoe_ddp_setup) + return n->netdev_ops->ndo_fcoe_ddp_setup(n, xid, sgl, sgc); + + return 0; +} + +/* + * fcoe_ddp_done - calls LLD's ddp_done through net_device + * @lp: the corresponding fc_lport + * @xid: the exchange id for this ddp transfer + * + * Returns : the length of data that have been completed by ddp + */ +static int fcoe_ddp_done(struct fc_lport *lp, u16 xid) +{ + struct net_device *n = fcoe_netdev(lp); + + if (n->netdev_ops && n->netdev_ops->ndo_fcoe_ddp_done) + return n->netdev_ops->ndo_fcoe_ddp_done(n, xid); + return 0; +} + +static struct libfc_function_template fcoe_libfc_fcn_templ = { + .frame_send = fcoe_xmit, + .ddp_setup = fcoe_ddp_setup, + .ddp_done = fcoe_ddp_done, +}; + +/** + * fcoe_fip_recv - handle a received FIP frame. + * @skb: the receive skb + * @dev: associated &net_device + * @ptype: the &packet_type structure which was used to register this handler. + * @orig_dev: original receive &net_device, in case @dev is a bond. + * + * Returns: 0 for success + */ +static int fcoe_fip_recv(struct sk_buff *skb, struct net_device *dev, + struct packet_type *ptype, + struct net_device *orig_dev) +{ + struct fcoe_softc *fc; + + fc = container_of(ptype, struct fcoe_softc, fip_packet_type); + fcoe_ctlr_recv(&fc->ctlr, skb); + return 0; +} + +/** + * fcoe_fip_send() - send an Ethernet-encapsulated FIP frame. + * @fip: FCoE controller. + * @skb: FIP Packet. + */ +static void fcoe_fip_send(struct fcoe_ctlr *fip, struct sk_buff *skb) +{ + skb->dev = fcoe_from_ctlr(fip)->real_dev; + dev_queue_xmit(skb); +} + +/** + * fcoe_update_src_mac() - Update Ethernet MAC filters. + * @fip: FCoE controller. + * @old: Unicast MAC address to delete if the MAC is non-zero. + * @new: Unicast MAC address to add. + * + * Remove any previously-set unicast MAC filter. + * Add secondary FCoE MAC address filter for our OUI. + */ +static void fcoe_update_src_mac(struct fcoe_ctlr *fip, u8 *old, u8 *new) +{ + struct fcoe_softc *fc; + + fc = fcoe_from_ctlr(fip); + rtnl_lock(); + if (!is_zero_ether_addr(old)) + dev_unicast_delete(fc->real_dev, old, ETH_ALEN); + dev_unicast_add(fc->real_dev, new, ETH_ALEN); + rtnl_unlock(); +} + +/** + * fcoe_if_create() - this function creates the fcoe interface + * @netdev: pointer the associated netdevice + * + * Creates fc_lport struct and scsi_host for lport, configures lport + * and starts fabric login. + * + * Returns : 0 on success + */ +static int fcoe_if_create(struct net_device *netdev) +{ + int rc; + struct fc_lport *lp = NULL; + struct fcoe_softc *fc; + struct Scsi_Host *shost; + + BUG_ON(!netdev); + + printk(KERN_DEBUG "fcoe_if_create:interface on %s\n", + netdev->name); + + lp = fcoe_hostlist_lookup(netdev); + if (lp) + return -EEXIST; + + shost = libfc_host_alloc(&fcoe_shost_template, + sizeof(struct fcoe_softc)); + if (!shost) { + FC_DBG("Could not allocate host structure\n"); + return -ENOMEM; + } + lp = shost_priv(shost); + fc = lport_priv(lp); + + /* configure fc_lport, e.g., em */ + rc = fcoe_lport_config(lp); + if (rc) { + FC_DBG("Could not configure lport\n"); + goto out_host_put; + } + + /* configure lport network properties */ + rc = fcoe_netdev_config(lp, netdev); + if (rc) { + FC_DBG("Could not configure netdev for lport\n"); + goto out_host_put; + } + + /* + * Initialize FIP. + */ + fcoe_ctlr_init(&fc->ctlr); + fc->ctlr.send = fcoe_fip_send; + fc->ctlr.update_mac = fcoe_update_src_mac; + + fc->fip_packet_type.func = fcoe_fip_recv; + fc->fip_packet_type.type = htons(ETH_P_FIP); + fc->fip_packet_type.dev = fc->real_dev; + dev_add_pack(&fc->fip_packet_type); + + /* configure lport scsi host properties */ + rc = fcoe_shost_config(lp, shost, &netdev->dev); + if (rc) { + FC_DBG("Could not configure shost for lport\n"); + goto out_host_put; + } + + /* lport exch manager allocation */ + rc = fcoe_em_config(lp); + if (rc) { + FC_DBG("Could not configure em for lport\n"); + goto out_host_put; + } + + /* Initialize the library */ + rc = fcoe_libfc_config(lp, &fcoe_libfc_fcn_templ); + if (rc) { + FC_DBG("Could not configure libfc for lport!\n"); + goto out_lp_destroy; + } + + /* add to lports list */ + fcoe_hostlist_add(lp); + + lp->boot_time = jiffies; + + fc_fabric_login(lp); + + if (!fcoe_link_ok(lp)) + fcoe_ctlr_link_up(&fc->ctlr); + + dev_hold(netdev); + + return rc; + +out_lp_destroy: + fc_exch_mgr_free(lp->emp); /* Free the EM */ +out_host_put: + scsi_host_put(lp->host); + return rc; +} + +/** + * fcoe_if_init() - attach to scsi transport + * + * Returns : 0 on success + */ +static int __init fcoe_if_init(void) +{ + /* attach to scsi transport */ + scsi_transport_fcoe_sw = + fc_attach_transport(&fcoe_transport_function); + + if (!scsi_transport_fcoe_sw) { + printk(KERN_ERR "fcoe_init:fc_attach_transport() failed\n"); + return -ENODEV; + } + + return 0; +} + +/** + * fcoe_if_exit() - detach from scsi transport + * + * Returns : 0 on success + */ +int __exit fcoe_if_exit(void) +{ + fc_release_transport(scsi_transport_fcoe_sw); + return 0; +} + +/** + * fcoe_percpu_thread_create() - Create a receive thread for an online cpu + * @cpu: cpu index for the online cpu + */ +static void fcoe_percpu_thread_create(unsigned int cpu) +{ + struct fcoe_percpu_s *p; + struct task_struct *thread; + + p = &per_cpu(fcoe_percpu, cpu); + + thread = kthread_create(fcoe_percpu_receive_thread, + (void *)p, "fcoethread/%d", cpu); + + if (likely(!IS_ERR(p->thread))) { + kthread_bind(thread, cpu); + wake_up_process(thread); + + spin_lock_bh(&p->fcoe_rx_list.lock); + p->thread = thread; + spin_unlock_bh(&p->fcoe_rx_list.lock); + } +} + +/** + * fcoe_percpu_thread_destroy() - removes the rx thread for the given cpu + * @cpu: cpu index the rx thread is to be removed + * + * Destroys a per-CPU Rx thread. Any pending skbs are moved to the + * current CPU's Rx thread. If the thread being destroyed is bound to + * the CPU processing this context the skbs will be freed. + */ +static void fcoe_percpu_thread_destroy(unsigned int cpu) +{ + struct fcoe_percpu_s *p; + struct task_struct *thread; + struct page *crc_eof; + struct sk_buff *skb; +#ifdef CONFIG_SMP + struct fcoe_percpu_s *p0; + unsigned targ_cpu = smp_processor_id(); +#endif /* CONFIG_SMP */ + + printk(KERN_DEBUG "fcoe: Destroying receive thread for CPU %d\n", cpu); + + /* Prevent any new skbs from being queued for this CPU. */ + p = &per_cpu(fcoe_percpu, cpu); + spin_lock_bh(&p->fcoe_rx_list.lock); + thread = p->thread; + p->thread = NULL; + crc_eof = p->crc_eof_page; + p->crc_eof_page = NULL; + p->crc_eof_offset = 0; + spin_unlock_bh(&p->fcoe_rx_list.lock); + +#ifdef CONFIG_SMP + /* + * Don't bother moving the skb's if this context is running + * on the same CPU that is having its thread destroyed. This + * can easily happen when the module is removed. + */ + if (cpu != targ_cpu) { + p0 = &per_cpu(fcoe_percpu, targ_cpu); + spin_lock_bh(&p0->fcoe_rx_list.lock); + if (p0->thread) { + FC_DBG("Moving frames from CPU %d to CPU %d\n", + cpu, targ_cpu); + + while ((skb = __skb_dequeue(&p->fcoe_rx_list)) != NULL) + __skb_queue_tail(&p0->fcoe_rx_list, skb); + spin_unlock_bh(&p0->fcoe_rx_list.lock); + } else { + /* + * The targeted CPU is not initialized and cannot accept + * new skbs. Unlock the targeted CPU and drop the skbs + * on the CPU that is going offline. + */ + while ((skb = __skb_dequeue(&p->fcoe_rx_list)) != NULL) + kfree_skb(skb); + spin_unlock_bh(&p0->fcoe_rx_list.lock); + } + } else { + /* + * This scenario occurs when the module is being removed + * and all threads are being destroyed. skbs will continue + * to be shifted from the CPU thread that is being removed + * to the CPU thread associated with the CPU that is processing + * the module removal. Once there is only one CPU Rx thread it + * will reach this case and we will drop all skbs and later + * stop the thread. + */ + spin_lock_bh(&p->fcoe_rx_list.lock); + while ((skb = __skb_dequeue(&p->fcoe_rx_list)) != NULL) + kfree_skb(skb); + spin_unlock_bh(&p->fcoe_rx_list.lock); + } +#else + /* + * This a non-SMP scenario where the singluar Rx thread is + * being removed. Free all skbs and stop the thread. + */ + spin_lock_bh(&p->fcoe_rx_list.lock); + while ((skb = __skb_dequeue(&p->fcoe_rx_list)) != NULL) + kfree_skb(skb); + spin_unlock_bh(&p->fcoe_rx_list.lock); +#endif + + if (thread) + kthread_stop(thread); + + if (crc_eof) + put_page(crc_eof); +} + +/** + * fcoe_cpu_callback() - fcoe cpu hotplug event callback + * @nfb: callback data block + * @action: event triggering the callback + * @hcpu: index for the cpu of this event + * + * This creates or destroys per cpu data for fcoe + * + * Returns NOTIFY_OK always. + */ +static int fcoe_cpu_callback(struct notifier_block *nfb, + unsigned long action, void *hcpu) +{ + unsigned cpu = (unsigned long)hcpu; + + switch (action) { + case CPU_ONLINE: + case CPU_ONLINE_FROZEN: + FC_DBG("CPU %x online: Create Rx thread\n", cpu); + fcoe_percpu_thread_create(cpu); + break; + case CPU_DEAD: + case CPU_DEAD_FROZEN: + FC_DBG("CPU %x offline: Remove Rx thread\n", cpu); + fcoe_percpu_thread_destroy(cpu); + break; + default: + break; + } + return NOTIFY_OK; +} + +static struct notifier_block fcoe_cpu_notifier = { + .notifier_call = fcoe_cpu_callback, +}; + +/** + * fcoe_rcv() - this is the fcoe receive function called by NET_RX_SOFTIRQ + * @skb: the receive skb + * @dev: associated net device + * @ptype: context + * @odldev: last device + * + * this function will receive the packet and build fc frame and pass it up + * + * Returns: 0 for success + */ +int fcoe_rcv(struct sk_buff *skb, struct net_device *dev, + struct packet_type *ptype, struct net_device *olddev) +{ + struct fc_lport *lp; + struct fcoe_rcv_info *fr; + struct fcoe_softc *fc; + struct fc_frame_header *fh; + struct fcoe_percpu_s *fps; + unsigned short oxid; + unsigned int cpu = 0; + + fc = container_of(ptype, struct fcoe_softc, fcoe_packet_type); + lp = fc->ctlr.lp; + if (unlikely(lp == NULL)) { + FC_DBG("cannot find hba structure"); + goto err2; + } + if (!lp->link_up) + goto err2; + + if (unlikely(debug_fcoe)) { + FC_DBG("skb_info: len:%d data_len:%d head:%p data:%p tail:%p " + "end:%p sum:%d dev:%s", skb->len, skb->data_len, + skb->head, skb->data, skb_tail_pointer(skb), + skb_end_pointer(skb), skb->csum, + skb->dev ? skb->dev->name : "<NULL>"); + + } + + /* check for FCOE packet type */ + if (unlikely(eth_hdr(skb)->h_proto != htons(ETH_P_FCOE))) { + FC_DBG("wrong FC type frame"); + goto err; + } + + /* + * Check for minimum frame length, and make sure required FCoE + * and FC headers are pulled into the linear data area. + */ + if (unlikely((skb->len < FCOE_MIN_FRAME) || + !pskb_may_pull(skb, FCOE_HEADER_LEN))) + goto err; + + skb_set_transport_header(skb, sizeof(struct fcoe_hdr)); + fh = (struct fc_frame_header *) skb_transport_header(skb); + + oxid = ntohs(fh->fh_ox_id); + + fr = fcoe_dev_from_skb(skb); + fr->fr_dev = lp; + fr->ptype = ptype; + +#ifdef CONFIG_SMP + /* + * The incoming frame exchange id(oxid) is ANDed with num of online + * cpu bits to get cpu and then this cpu is used for selecting + * a per cpu kernel thread from fcoe_percpu. + */ + cpu = oxid & (num_online_cpus() - 1); +#endif + + fps = &per_cpu(fcoe_percpu, cpu); + spin_lock_bh(&fps->fcoe_rx_list.lock); + if (unlikely(!fps->thread)) { + /* + * The targeted CPU is not ready, let's target + * the first CPU now. For non-SMP systems this + * will check the same CPU twice. + */ + FC_DBG("CPU is online, but no receive thread ready " + "for incoming skb- using first online CPU.\n"); + + spin_unlock_bh(&fps->fcoe_rx_list.lock); + cpu = first_cpu(cpu_online_map); + fps = &per_cpu(fcoe_percpu, cpu); + spin_lock_bh(&fps->fcoe_rx_list.lock); + if (!fps->thread) { + spin_unlock_bh(&fps->fcoe_rx_list.lock); + goto err; + } + } + + /* + * We now have a valid CPU that we're targeting for + * this skb. We also have this receive thread locked, + * so we're free to queue skbs into it's queue. + */ + __skb_queue_tail(&fps->fcoe_rx_list, skb); + if (fps->fcoe_rx_list.qlen == 1) + wake_up_process(fps->thread); + + spin_unlock_bh(&fps->fcoe_rx_list.lock); + + return 0; +err: + fc_lport_get_stats(lp)->ErrorFrames++; + +err2: + kfree_skb(skb); + return -1; +} +EXPORT_SYMBOL_GPL(fcoe_rcv); + +/** + * fcoe_start_io() - pass to netdev to start xmit for fcoe + * @skb: the skb to be xmitted + * + * Returns: 0 for success + */ +static inline int fcoe_start_io(struct sk_buff *skb) +{ + int rc; + + skb_get(skb); + rc = dev_queue_xmit(skb); + if (rc != 0) + return rc; + kfree_skb(skb); + return 0; +} + +/** + * fcoe_get_paged_crc_eof() - in case we need alloc a page for crc_eof + * @skb: the skb to be xmitted + * @tlen: total len + * + * Returns: 0 for success + */ +static int fcoe_get_paged_crc_eof(struct sk_buff *skb, int tlen) +{ + struct fcoe_percpu_s *fps; + struct page *page; + + fps = &get_cpu_var(fcoe_percpu); + page = fps->crc_eof_page; + if (!page) { + page = alloc_page(GFP_ATOMIC); + if (!page) { + put_cpu_var(fcoe_percpu); + return -ENOMEM; + } + fps->crc_eof_page = page; + fps->crc_eof_offset = 0; + } + + get_page(page); + skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags, page, + fps->crc_eof_offset, tlen); + skb->len += tlen; + skb->data_len += tlen; + skb->truesize += tlen; + fps->crc_eof_offset += sizeof(struct fcoe_crc_eof); + + if (fps->crc_eof_offset >= PAGE_SIZE) { + fps->crc_eof_page = NULL; + fps->crc_eof_offset = 0; + put_page(page); + } + put_cpu_var(fcoe_percpu); + return 0; +} + +/** + * fcoe_fc_crc() - calculates FC CRC in this fcoe skb + * @fp: the fc_frame containg data to be checksummed + * + * This uses crc32() to calculate the crc for fc frame + * Return : 32 bit crc + */ +u32 fcoe_fc_crc(struct fc_frame *fp) +{ + struct sk_buff *skb = fp_skb(fp); + struct skb_frag_struct *frag; + unsigned char *data; + unsigned long off, len, clen; + u32 crc; + unsigned i; + + crc = crc32(~0, skb->data, skb_headlen(skb)); + + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + frag = &skb_shinfo(skb)->frags[i]; + off = frag->page_offset; + len = frag->size; + while (len > 0) { + clen = min(len, PAGE_SIZE - (off & ~PAGE_MASK)); + data = kmap_atomic(frag->page + (off >> PAGE_SHIFT), + KM_SKB_DATA_SOFTIRQ); + crc = crc32(crc, data + (off & ~PAGE_MASK), clen); + kunmap_atomic(data, KM_SKB_DATA_SOFTIRQ); + off += clen; + len -= clen; + } + } + return crc; +} + +/** + * fcoe_xmit() - FCoE frame transmit function + * @lp: the associated local port + * @fp: the fc_frame to be transmitted + * + * Return : 0 for success + */ +int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp) +{ + int wlen, rc = 0; + u32 crc; + struct ethhdr *eh; + struct fcoe_crc_eof *cp; + struct sk_buff *skb; + struct fcoe_dev_stats *stats; + struct fc_frame_header *fh; + unsigned int hlen; /* header length implies the version */ + unsigned int tlen; /* trailer length */ + unsigned int elen; /* eth header, may include vlan */ + struct fcoe_softc *fc; + u8 sof, eof; + struct fcoe_hdr *hp; + + WARN_ON((fr_len(fp) % sizeof(u32)) != 0); + + fc = lport_priv(lp); + fh = fc_frame_header_get(fp); + skb = fp_skb(fp); + wlen = skb->len / FCOE_WORD_TO_BYTE; + + if (!lp->link_up) { + kfree(skb); + return 0; + } + + if (unlikely(fh->fh_r_ctl == FC_RCTL_ELS_REQ) && + fcoe_ctlr_els_send(&fc->ctlr, skb)) + return 0; + + sof = fr_sof(fp); + eof = fr_eof(fp); + + elen = (fc->real_dev->priv_flags & IFF_802_1Q_VLAN) ? + sizeof(struct vlan_ethhdr) : sizeof(struct ethhdr); + hlen = sizeof(struct fcoe_hdr); + tlen = sizeof(struct fcoe_crc_eof); + wlen = (skb->len - tlen + sizeof(crc)) / FCOE_WORD_TO_BYTE; + + /* crc offload */ + if (likely(lp->crc_offload)) { + skb->ip_summed = CHECKSUM_PARTIAL; + skb->csum_start = skb_headroom(skb); + skb->csum_offset = skb->len; + crc = 0; + } else { + skb->ip_summed = CHECKSUM_NONE; + crc = fcoe_fc_crc(fp); + } + + /* copy fc crc and eof to the skb buff */ + if (skb_is_nonlinear(skb)) { + skb_frag_t *frag; + if (fcoe_get_paged_crc_eof(skb, tlen)) { + kfree_skb(skb); + return -ENOMEM; + } + frag = &skb_shinfo(skb)->frags[skb_shinfo(skb)->nr_frags - 1]; + cp = kmap_atomic(frag->page, KM_SKB_DATA_SOFTIRQ) + + frag->page_offset; + } else { + cp = (struct fcoe_crc_eof *)skb_put(skb, tlen); + } + + memset(cp, 0, sizeof(*cp)); + cp->fcoe_eof = eof; + cp->fcoe_crc32 = cpu_to_le32(~crc); + + if (skb_is_nonlinear(skb)) { + kunmap_atomic(cp, KM_SKB_DATA_SOFTIRQ); + cp = NULL; + } + + /* adjust skb netowrk/transport offsets to match mac/fcoe/fc */ + skb_push(skb, elen + hlen); + skb_reset_mac_header(skb); + skb_reset_network_header(skb); + skb->mac_len = elen; + skb->protocol = htons(ETH_P_FCOE); + skb->dev = fc->real_dev; + + /* fill up mac and fcoe headers */ + eh = eth_hdr(skb); + eh->h_proto = htons(ETH_P_FCOE); + if (fc->ctlr.map_dest) + fc_fcoe_set_mac(eh->h_dest, fh->fh_d_id); + else + /* insert GW address */ + memcpy(eh->h_dest, fc->ctlr.dest_addr, ETH_ALEN); + + if (unlikely(fc->ctlr.flogi_oxid != FC_XID_UNKNOWN)) + memcpy(eh->h_source, fc->ctlr.ctl_src_addr, ETH_ALEN); + else + memcpy(eh->h_source, fc->ctlr.data_src_addr, ETH_ALEN); + + hp = (struct fcoe_hdr *)(eh + 1); + memset(hp, 0, sizeof(*hp)); + if (FC_FCOE_VER) + FC_FCOE_ENCAPS_VER(hp, FC_FCOE_VER); + hp->fcoe_sof = sof; + +#ifdef NETIF_F_FSO + /* fcoe lso, mss is in max_payload which is non-zero for FCP data */ + if (lp->seq_offload && fr_max_payload(fp)) { + skb_shinfo(skb)->gso_type = SKB_GSO_FCOE; + skb_shinfo(skb)->gso_size = fr_max_payload(fp); + } else { + skb_shinfo(skb)->gso_type = 0; + skb_shinfo(skb)->gso_size = 0; + } +#endif + /* update tx stats: regardless if LLD fails */ + stats = fc_lport_get_stats(lp); + stats->TxFrames++; + stats->TxWords += wlen; + + /* send down to lld */ + fr_dev(fp) = lp; + if (fc->fcoe_pending_queue.qlen) + rc = fcoe_check_wait_queue(lp); + + if (rc == 0) + rc = fcoe_start_io(skb); + + if (rc) { + spin_lock_bh(&fc->fcoe_pending_queue.lock); + __skb_queue_tail(&fc->fcoe_pending_queue, skb); + spin_unlock_bh(&fc->fcoe_pending_queue.lock); + if (fc->fcoe_pending_queue.qlen > FCOE_MAX_QUEUE_DEPTH) + lp->qfull = 1; + } + + return 0; +} +EXPORT_SYMBOL_GPL(fcoe_xmit); + +/** + * fcoe_percpu_receive_thread() - recv thread per cpu + * @arg: ptr to the fcoe per cpu struct + * + * Return: 0 for success + */ +int fcoe_percpu_receive_thread(void *arg) +{ + struct fcoe_percpu_s *p = arg; + u32 fr_len; + struct fc_lport *lp; + struct fcoe_rcv_info *fr; + struct fcoe_dev_stats *stats; + struct fc_frame_header *fh; + struct sk_buff *skb; + struct fcoe_crc_eof crc_eof; + struct fc_frame *fp; + u8 *mac = NULL; + struct fcoe_softc *fc; + struct fcoe_hdr *hp; + + set_user_nice(current, -20); + + while (!kthread_should_stop()) { + + spin_lock_bh(&p->fcoe_rx_list.lock); + while ((skb = __skb_dequeue(&p->fcoe_rx_list)) == NULL) { + set_current_state(TASK_INTERRUPTIBLE); + spin_unlock_bh(&p->fcoe_rx_list.lock); + schedule(); + set_current_state(TASK_RUNNING); + if (kthread_should_stop()) + return 0; + spin_lock_bh(&p->fcoe_rx_list.lock); + } + spin_unlock_bh(&p->fcoe_rx_list.lock); + fr = fcoe_dev_from_skb(skb); + lp = fr->fr_dev; + if (unlikely(lp == NULL)) { + FC_DBG("invalid HBA Structure"); + kfree_skb(skb); + continue; + } + + if (unlikely(debug_fcoe)) { + FC_DBG("skb_info: len:%d data_len:%d head:%p data:%p " + "tail:%p end:%p sum:%d dev:%s", + skb->len, skb->data_len, + skb->head, skb->data, skb_tail_pointer(skb), + skb_end_pointer(skb), skb->csum, + skb->dev ? skb->dev->name : "<NULL>"); + } + + /* + * Save source MAC address before discarding header. + */ + fc = lport_priv(lp); + if (skb_is_nonlinear(skb)) + skb_linearize(skb); /* not ideal */ + mac = eth_hdr(skb)->h_source; + + /* + * Frame length checks and setting up the header pointers + * was done in fcoe_rcv already. + */ + hp = (struct fcoe_hdr *) skb_network_header(skb); + fh = (struct fc_frame_header *) skb_transport_header(skb); + + stats = fc_lport_get_stats(lp); + if (unlikely(FC_FCOE_DECAPS_VER(hp) != FC_FCOE_VER)) { + if (stats->ErrorFrames < 5) + printk(KERN_WARNING "FCoE version " + "mismatch: The frame has " + "version %x, but the " + "initiator supports version " + "%x\n", FC_FCOE_DECAPS_VER(hp), + FC_FCOE_VER); + stats->ErrorFrames++; + kfree_skb(skb); + continue; + } + + skb_pull(skb, sizeof(struct fcoe_hdr)); + fr_len = skb->len - sizeof(struct fcoe_crc_eof); + + stats->RxFrames++; + stats->RxWords += fr_len / FCOE_WORD_TO_BYTE; + + fp = (struct fc_frame *)skb; + fc_frame_init(fp); + fr_dev(fp) = lp; + fr_sof(fp) = hp->fcoe_sof; + + /* Copy out the CRC and EOF trailer for access */ + if (skb_copy_bits(skb, fr_len, &crc_eof, sizeof(crc_eof))) { + kfree_skb(skb); + continue; + } + fr_eof(fp) = crc_eof.fcoe_eof; + fr_crc(fp) = crc_eof.fcoe_crc32; + if (pskb_trim(skb, fr_len)) { + kfree_skb(skb); + continue; + } + + /* + * We only check CRC if no offload is available and if it is + * it's solicited data, in which case, the FCP layer would + * check it during the copy. + */ + if (lp->crc_offload && skb->ip_summed == CHECKSUM_UNNECESSARY) + fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED; + else + fr_flags(fp) |= FCPHF_CRC_UNCHECKED; + + fh = fc_frame_header_get(fp); + if (fh->fh_r_ctl == FC_RCTL_DD_SOL_DATA && + fh->fh_type == FC_TYPE_FCP) { + fc_exch_recv(lp, lp->emp, fp); + continue; + } + if (fr_flags(fp) & FCPHF_CRC_UNCHECKED) { + if (le32_to_cpu(fr_crc(fp)) != + ~crc32(~0, skb->data, fr_len)) { + if (debug_fcoe || stats->InvalidCRCCount < 5) + printk(KERN_WARNING "fcoe: dropping " + "frame with CRC error\n"); + stats->InvalidCRCCount++; + stats->ErrorFrames++; + fc_frame_free(fp); + continue; + } + fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED; + } + if (unlikely(fc->ctlr.flogi_oxid != FC_XID_UNKNOWN) && + fcoe_ctlr_recv_flogi(&fc->ctlr, fp, mac)) { + fc_frame_free(fp); + continue; + } + fc_exch_recv(lp, lp->emp, fp); + } + return 0; +} + +/** + * fcoe_watchdog() - fcoe timer callback + * @vp: + * + * This checks the pending queue length for fcoe and set lport qfull + * if the FCOE_MAX_QUEUE_DEPTH is reached. This is done for all fc_lport on the + * fcoe_hostlist. + * + * Returns: 0 for success + */ +void fcoe_watchdog(ulong vp) +{ + struct fcoe_softc *fc; + + read_lock(&fcoe_hostlist_lock); + list_for_each_entry(fc, &fcoe_hostlist, list) { + if (fc->ctlr.lp) + fcoe_check_wait_queue(fc->ctlr.lp); + } + read_unlock(&fcoe_hostlist_lock); + + fcoe_timer.expires = jiffies + (1 * HZ); + add_timer(&fcoe_timer); +} + + +/** + * fcoe_check_wait_queue() - put the skb into fcoe pending xmit queue + * @lp: the fc_port for this skb + * @skb: the associated skb to be xmitted + * + * This empties the wait_queue, dequeue the head of the wait_queue queue + * and calls fcoe_start_io() for each packet, if all skb have been + * transmitted, return qlen or -1 if a error occurs, then restore + * wait_queue and try again later. + * + * The wait_queue is used when the skb transmit fails. skb will go + * in the wait_queue which will be emptied by the time function OR + * by the next skb transmit. + * + * Returns: 0 for success + */ +static int fcoe_check_wait_queue(struct fc_lport *lp) +{ + struct fcoe_softc *fc = lport_priv(lp); + struct sk_buff *skb; + int rc = -1; + + spin_lock_bh(&fc->fcoe_pending_queue.lock); + if (fc->fcoe_pending_queue_active) + goto out; + fc->fcoe_pending_queue_active = 1; + + while (fc->fcoe_pending_queue.qlen) { + /* keep qlen > 0 until fcoe_start_io succeeds */ + fc->fcoe_pending_queue.qlen++; + skb = __skb_dequeue(&fc->fcoe_pending_queue); + + spin_unlock_bh(&fc->fcoe_pending_queue.lock); + rc = fcoe_start_io(skb); + spin_lock_bh(&fc->fcoe_pending_queue.lock); + + if (rc) { + __skb_queue_head(&fc->fcoe_pending_queue, skb); + /* undo temporary increment above */ + fc->fcoe_pending_queue.qlen--; + break; + } + /* undo temporary increment above */ + fc->fcoe_pending_queue.qlen--; + } + + if (fc->fcoe_pending_queue.qlen < FCOE_LOW_QUEUE_DEPTH) + lp->qfull = 0; + fc->fcoe_pending_queue_active = 0; + rc = fc->fcoe_pending_queue.qlen; +out: + spin_unlock_bh(&fc->fcoe_pending_queue.lock); + return rc; +} + +/** + * fcoe_dev_setup() - setup link change notification interface + */ +static void fcoe_dev_setup() +{ + /* + * here setup a interface specific wd time to + * monitor the link state + */ + register_netdevice_notifier(&fcoe_notifier); +} + +/** + * fcoe_dev_setup() - cleanup link change notification interface + */ +static void fcoe_dev_cleanup(void) +{ + unregister_netdevice_notifier(&fcoe_notifier); +} + +/** + * fcoe_device_notification() - netdev event notification callback + * @notifier: context of the notification + * @event: type of event + * @ptr: fixed array for output parsed ifname + * + * This function is called by the ethernet driver in case of link change event + * + * Returns: 0 for success + */ +static int fcoe_device_notification(struct notifier_block *notifier, + ulong event, void *ptr) +{ + struct fc_lport *lp = NULL; + struct net_device *real_dev = ptr; + struct fcoe_softc *fc; + struct fcoe_dev_stats *stats; + u32 link_possible = 1; + u32 mfs; + int rc = NOTIFY_OK; + + read_lock(&fcoe_hostlist_lock); + list_for_each_entry(fc, &fcoe_hostlist, list) { + if (fc->real_dev == real_dev) { + lp = fc->ctlr.lp; + break; + } + } + read_unlock(&fcoe_hostlist_lock); + if (lp == NULL) { + rc = NOTIFY_DONE; + goto out; + } + + switch (event) { + case NETDEV_DOWN: + case NETDEV_GOING_DOWN: + link_possible = 0; + break; + case NETDEV_UP: + case NETDEV_CHANGE: + break; + case NETDEV_CHANGEMTU: + mfs = fc->real_dev->mtu - + (sizeof(struct fcoe_hdr) + + sizeof(struct fcoe_crc_eof)); + if (mfs >= FC_MIN_MAX_FRAME) + fc_set_mfs(lp, mfs); + break; + case NETDEV_REGISTER: + break; + default: + FC_DBG("Unknown event %ld from netdev netlink\n", event); + } + if (link_possible && !fcoe_link_ok(lp)) + fcoe_ctlr_link_up(&fc->ctlr); + else if (fcoe_ctlr_link_down(&fc->ctlr)) { + stats = fc_lport_get_stats(lp); + stats->LinkFailureCount++; + fcoe_clean_pending_queue(lp); + } +out: + return rc; +} + +/** + * fcoe_if_to_netdev() - parse a name buffer to get netdev + * @ifname: fixed array for output parsed ifname + * @buffer: incoming buffer to be copied + * + * Returns: NULL or ptr to netdeive + */ +static struct net_device *fcoe_if_to_netdev(const char *buffer) +{ + char *cp; + char ifname[IFNAMSIZ + 2]; + + if (buffer) { + strlcpy(ifname, buffer, IFNAMSIZ); + cp = ifname + strlen(ifname); + while (--cp >= ifname && *cp == '\n') + *cp = '\0'; + return dev_get_by_name(&init_net, ifname); + } + return NULL; +} + +/** + * fcoe_netdev_to_module_owner() - finds out the nic drive moddule of the netdev + * @netdev: the target netdev + * + * Returns: ptr to the struct module, NULL for failure + */ +static struct module * +fcoe_netdev_to_module_owner(const struct net_device *netdev) +{ + struct device *dev; + + if (!netdev) + return NULL; + + dev = netdev->dev.parent; + if (!dev) + return NULL; + + if (!dev->driver) + return NULL; + + return dev->driver->owner; +} + +/** + * fcoe_ethdrv_get() - Hold the Ethernet driver + * @netdev: the target netdev + * + * Holds the Ethernet driver module by try_module_get() for + * the corresponding netdev. + * + * Returns: 0 for succsss + */ +static int fcoe_ethdrv_get(const struct net_device *netdev) +{ + struct module *owner; + + owner = fcoe_netdev_to_module_owner(netdev); + if (owner) { + printk(KERN_DEBUG "fcoe:hold driver module %s for %s\n", + module_name(owner), netdev->name); + return try_module_get(owner); + } + return -ENODEV; +} + +/** + * fcoe_ethdrv_put() - Release the Ethernet driver + * @netdev: the target netdev + * + * Releases the Ethernet driver module by module_put for + * the corresponding netdev. + * + * Returns: 0 for succsss + */ +static int fcoe_ethdrv_put(const struct net_device *netdev) +{ + struct module *owner; + + owner = fcoe_netdev_to_module_owner(netdev); + if (owner) { + printk(KERN_DEBUG "fcoe:release driver module %s for %s\n", + module_name(owner), netdev->name); + module_put(owner); + return 0; + } + return -ENODEV; +} + +/** + * fcoe_destroy() - handles the destroy from sysfs + * @buffer: expcted to be a eth if name + * @kp: associated kernel param + * + * Returns: 0 for success + */ +static int fcoe_destroy(const char *buffer, struct kernel_param *kp) +{ + int rc; + struct net_device *netdev; + + netdev = fcoe_if_to_netdev(buffer); + if (!netdev) { + rc = -ENODEV; + goto out_nodev; + } + /* look for existing lport */ + if (!fcoe_hostlist_lookup(netdev)) { + rc = -ENODEV; + goto out_putdev; + } + rc = fcoe_if_destroy(netdev); + if (rc) { + printk(KERN_ERR "fcoe: fcoe_if_destroy(%s) failed\n", + netdev->name); + rc = -EIO; + goto out_putdev; + } + fcoe_ethdrv_put(netdev); + rc = 0; +out_putdev: + dev_put(netdev); +out_nodev: + return rc; +} + +/** + * fcoe_create() - Handles the create call from sysfs + * @buffer: expcted to be a eth if name + * @kp: associated kernel param + * + * Returns: 0 for success + */ +static int fcoe_create(const char *buffer, struct kernel_param *kp) +{ + int rc; + struct net_device *netdev; + + netdev = fcoe_if_to_netdev(buffer); + if (!netdev) { + rc = -ENODEV; + goto out_nodev; + } + /* look for existing lport */ + if (fcoe_hostlist_lookup(netdev)) { + rc = -EEXIST; + goto out_putdev; + } + fcoe_ethdrv_get(netdev); + + rc = fcoe_if_create(netdev); + if (rc) { + printk(KERN_ERR "fcoe: fcoe_if_create(%s) failed\n", + netdev->name); + fcoe_ethdrv_put(netdev); + rc = -EIO; + goto out_putdev; + } + rc = 0; +out_putdev: + dev_put(netdev); +out_nodev: + return rc; +} + +module_param_call(create, fcoe_create, NULL, NULL, S_IWUSR); +__MODULE_PARM_TYPE(create, "string"); +MODULE_PARM_DESC(create, "Create fcoe port using net device passed in."); +module_param_call(destroy, fcoe_destroy, NULL, NULL, S_IWUSR); +__MODULE_PARM_TYPE(destroy, "string"); +MODULE_PARM_DESC(destroy, "Destroy fcoe port"); + +/** + * fcoe_link_ok() - Check if link is ok for the fc_lport + * @lp: ptr to the fc_lport + * + * Any permanently-disqualifying conditions have been previously checked. + * This also updates the speed setting, which may change with link for 100/1000. + * + * This function should probably be checking for PAUSE support at some point + * in the future. Currently Per-priority-pause is not determinable using + * ethtool, so we shouldn't be restrictive until that problem is resolved. + * + * Returns: 0 if link is OK for use by FCoE. + * + */ +int fcoe_link_ok(struct fc_lport *lp) +{ + struct fcoe_softc *fc = lport_priv(lp); + struct net_device *dev = fc->real_dev; + struct ethtool_cmd ecmd = { ETHTOOL_GSET }; + int rc = 0; + + if ((dev->flags & IFF_UP) && netif_carrier_ok(dev)) { + dev = fc->phys_dev; + if (dev->ethtool_ops->get_settings) { + dev->ethtool_ops->get_settings(dev, &ecmd); + lp->link_supported_speeds &= + ~(FC_PORTSPEED_1GBIT | FC_PORTSPEED_10GBIT); + if (ecmd.supported & (SUPPORTED_1000baseT_Half | + SUPPORTED_1000baseT_Full)) + lp->link_supported_speeds |= FC_PORTSPEED_1GBIT; + if (ecmd.supported & SUPPORTED_10000baseT_Full) + lp->link_supported_speeds |= + FC_PORTSPEED_10GBIT; + if (ecmd.speed == SPEED_1000) + lp->link_speed = FC_PORTSPEED_1GBIT; + if (ecmd.speed == SPEED_10000) + lp->link_speed = FC_PORTSPEED_10GBIT; + } + } else + rc = -1; + + return rc; +} +EXPORT_SYMBOL_GPL(fcoe_link_ok); + +/** + * fcoe_percpu_clean() - Clear the pending skbs for an lport + * @lp: the fc_lport + */ +void fcoe_percpu_clean(struct fc_lport *lp) +{ + struct fcoe_percpu_s *pp; + struct fcoe_rcv_info *fr; + struct sk_buff_head *list; + struct sk_buff *skb, *next; + struct sk_buff *head; + unsigned int cpu; + + for_each_possible_cpu(cpu) { + pp = &per_cpu(fcoe_percpu, cpu); + spin_lock_bh(&pp->fcoe_rx_list.lock); + list = &pp->fcoe_rx_list; + head = list->next; + for (skb = head; skb != (struct sk_buff *)list; + skb = next) { + next = skb->next; + fr = fcoe_dev_from_skb(skb); + if (fr->fr_dev == lp) { + __skb_unlink(skb, list); + kfree_skb(skb); + } + } + spin_unlock_bh(&pp->fcoe_rx_list.lock); + } +} +EXPORT_SYMBOL_GPL(fcoe_percpu_clean); + +/** + * fcoe_clean_pending_queue() - Dequeue a skb and free it + * @lp: the corresponding fc_lport + * + * Returns: none + */ +void fcoe_clean_pending_queue(struct fc_lport *lp) +{ + struct fcoe_softc *fc = lport_priv(lp); + struct sk_buff *skb; + + spin_lock_bh(&fc->fcoe_pending_queue.lock); + while ((skb = __skb_dequeue(&fc->fcoe_pending_queue)) != NULL) { + spin_unlock_bh(&fc->fcoe_pending_queue.lock); + kfree_skb(skb); + spin_lock_bh(&fc->fcoe_pending_queue.lock); + } + spin_unlock_bh(&fc->fcoe_pending_queue.lock); +} +EXPORT_SYMBOL_GPL(fcoe_clean_pending_queue); + +/** + * fcoe_reset() - Resets the fcoe + * @shost: shost the reset is from + * + * Returns: always 0 + */ +int fcoe_reset(struct Scsi_Host *shost) +{ + struct fc_lport *lport = shost_priv(shost); + fc_lport_reset(lport); + return 0; +} +EXPORT_SYMBOL_GPL(fcoe_reset); + +/** + * fcoe_hostlist_lookup_softc() - find the corresponding lport by a given device + * @device: this is currently ptr to net_device + * + * Returns: NULL or the located fcoe_softc + */ +static struct fcoe_softc * +fcoe_hostlist_lookup_softc(const struct net_device *dev) +{ + struct fcoe_softc *fc; + + read_lock(&fcoe_hostlist_lock); + list_for_each_entry(fc, &fcoe_hostlist, list) { + if (fc->real_dev == dev) { + read_unlock(&fcoe_hostlist_lock); + return fc; + } + } + read_unlock(&fcoe_hostlist_lock); + return NULL; +} + +/** + * fcoe_hostlist_lookup() - Find the corresponding lport by netdev + * @netdev: ptr to net_device + * + * Returns: 0 for success + */ +struct fc_lport *fcoe_hostlist_lookup(const struct net_device *netdev) +{ + struct fcoe_softc *fc; + + fc = fcoe_hostlist_lookup_softc(netdev); + + return (fc) ? fc->ctlr.lp : NULL; +} +EXPORT_SYMBOL_GPL(fcoe_hostlist_lookup); + +/** + * fcoe_hostlist_add() - Add a lport to lports list + * @lp: ptr to the fc_lport to badded + * + * Returns: 0 for success + */ +int fcoe_hostlist_add(const struct fc_lport *lp) +{ + struct fcoe_softc *fc; + + fc = fcoe_hostlist_lookup_softc(fcoe_netdev(lp)); + if (!fc) { + fc = lport_priv(lp); + write_lock_bh(&fcoe_hostlist_lock); + list_add_tail(&fc->list, &fcoe_hostlist); + write_unlock_bh(&fcoe_hostlist_lock); + } + return 0; +} +EXPORT_SYMBOL_GPL(fcoe_hostlist_add); + +/** + * fcoe_hostlist_remove() - remove a lport from lports list + * @lp: ptr to the fc_lport to badded + * + * Returns: 0 for success + */ +int fcoe_hostlist_remove(const struct fc_lport *lp) +{ + struct fcoe_softc *fc; + + fc = fcoe_hostlist_lookup_softc(fcoe_netdev(lp)); + BUG_ON(!fc); + write_lock_bh(&fcoe_hostlist_lock); + list_del(&fc->list); + write_unlock_bh(&fcoe_hostlist_lock); + + return 0; +} +EXPORT_SYMBOL_GPL(fcoe_hostlist_remove); + +/** + * fcoe_init() - fcoe module loading initialization + * + * Returns 0 on success, negative on failure + */ +static int __init fcoe_init(void) +{ + unsigned int cpu; + int rc = 0; + struct fcoe_percpu_s *p; + + INIT_LIST_HEAD(&fcoe_hostlist); + rwlock_init(&fcoe_hostlist_lock); + + for_each_possible_cpu(cpu) { + p = &per_cpu(fcoe_percpu, cpu); + skb_queue_head_init(&p->fcoe_rx_list); + } + + for_each_online_cpu(cpu) + fcoe_percpu_thread_create(cpu); + + /* Initialize per CPU interrupt thread */ + rc = register_hotcpu_notifier(&fcoe_cpu_notifier); + if (rc) + goto out_free; + + /* Setup link change notification */ + fcoe_dev_setup(); + + setup_timer(&fcoe_timer, fcoe_watchdog, 0); + + mod_timer(&fcoe_timer, jiffies + (10 * HZ)); + + fcoe_if_init(); + + return 0; + +out_free: + for_each_online_cpu(cpu) { + fcoe_percpu_thread_destroy(cpu); + } + + return rc; +} +module_init(fcoe_init); + +/** + * fcoe_exit() - fcoe module unloading cleanup + * + * Returns 0 on success, negative on failure + */ +static void __exit fcoe_exit(void) +{ + unsigned int cpu; + struct fcoe_softc *fc, *tmp; + + fcoe_dev_cleanup(); + + /* Stop the timer */ + del_timer_sync(&fcoe_timer); + + /* releases the associated fcoe hosts */ + list_for_each_entry_safe(fc, tmp, &fcoe_hostlist, list) + fcoe_if_destroy(fc->real_dev); + + unregister_hotcpu_notifier(&fcoe_cpu_notifier); + + for_each_online_cpu(cpu) { + fcoe_percpu_thread_destroy(cpu); + } + + /* detach from scsi transport */ + fcoe_if_exit(); +} +module_exit(fcoe_exit); diff --git a/drivers/scsi/fcoe/fcoe.h b/drivers/scsi/fcoe/fcoe.h new file mode 100644 index 00000000000..917aae88689 --- /dev/null +++ b/drivers/scsi/fcoe/fcoe.h @@ -0,0 +1,75 @@ +/* + * Copyright(c) 2009 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * 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., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * Maintained at www.Open-FCoE.org + */ + +#ifndef _FCOE_H_ +#define _FCOE_H_ + +#include <linux/skbuff.h> +#include <linux/kthread.h> + +#define FCOE_MAX_QUEUE_DEPTH 256 +#define FCOE_LOW_QUEUE_DEPTH 32 + +#define FCOE_WORD_TO_BYTE 4 + +#define FCOE_VERSION "0.1" +#define FCOE_NAME "fcoe" +#define FCOE_VENDOR "Open-FCoE.org" + +#define FCOE_MAX_LUN 255 +#define FCOE_MAX_FCP_TARGET 256 + +#define FCOE_MAX_OUTSTANDING_COMMANDS 1024 + +#define FCOE_MIN_XID 0x0001 /* the min xid supported by fcoe_sw */ +#define FCOE_MAX_XID 0x07ef /* the max xid supported by fcoe_sw */ + +/* + * this percpu struct for fcoe + */ +struct fcoe_percpu_s { + struct task_struct *thread; + struct sk_buff_head fcoe_rx_list; + struct page *crc_eof_page; + int crc_eof_offset; +}; + +/* + * the fcoe sw transport private data + */ +struct fcoe_softc { + struct list_head list; + struct net_device *real_dev; + struct net_device *phys_dev; /* device with ethtool_ops */ + struct packet_type fcoe_packet_type; + struct packet_type fip_packet_type; + struct sk_buff_head fcoe_pending_queue; + u8 fcoe_pending_queue_active; + struct fcoe_ctlr ctlr; +}; + +#define fcoe_from_ctlr(fc) container_of(fc, struct fcoe_softc, ctlr) + +static inline struct net_device *fcoe_netdev( + const struct fc_lport *lp) +{ + return ((struct fcoe_softc *)lport_priv(lp))->real_dev; +} + +#endif /* _FCOE_H_ */ diff --git a/drivers/scsi/fcoe/fcoe_sw.c b/drivers/scsi/fcoe/fcoe_sw.c deleted file mode 100644 index dc4cd5e2576..00000000000 --- a/drivers/scsi/fcoe/fcoe_sw.c +++ /dev/null @@ -1,494 +0,0 @@ -/* - * Copyright(c) 2007 - 2008 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * 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., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * Maintained at www.Open-FCoE.org - */ - -#include <linux/module.h> -#include <linux/version.h> -#include <linux/kernel.h> -#include <linux/pci.h> -#include <linux/init.h> -#include <linux/spinlock.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/if_vlan.h> -#include <net/rtnetlink.h> - -#include <scsi/fc/fc_els.h> -#include <scsi/fc/fc_encaps.h> -#include <scsi/fc/fc_fs.h> -#include <scsi/scsi_transport.h> -#include <scsi/scsi_transport_fc.h> - -#include <scsi/libfc.h> -#include <scsi/libfcoe.h> -#include <scsi/fc_transport_fcoe.h> - -#define FCOE_SW_VERSION "0.1" -#define FCOE_SW_NAME "fcoesw" -#define FCOE_SW_VENDOR "Open-FCoE.org" - -#define FCOE_MAX_LUN 255 -#define FCOE_MAX_FCP_TARGET 256 - -#define FCOE_MAX_OUTSTANDING_COMMANDS 1024 - -#define FCOE_MIN_XID 0x0001 /* the min xid supported by fcoe_sw */ -#define FCOE_MAX_XID 0x07ef /* the max xid supported by fcoe_sw */ - -static struct scsi_transport_template *scsi_transport_fcoe_sw; - -struct fc_function_template fcoe_sw_transport_function = { - .show_host_node_name = 1, - .show_host_port_name = 1, - .show_host_supported_classes = 1, - .show_host_supported_fc4s = 1, - .show_host_active_fc4s = 1, - .show_host_maxframe_size = 1, - - .show_host_port_id = 1, - .show_host_supported_speeds = 1, - .get_host_speed = fc_get_host_speed, - .show_host_speed = 1, - .show_host_port_type = 1, - .get_host_port_state = fc_get_host_port_state, - .show_host_port_state = 1, - .show_host_symbolic_name = 1, - - .dd_fcrport_size = sizeof(struct fc_rport_libfc_priv), - .show_rport_maxframe_size = 1, - .show_rport_supported_classes = 1, - - .show_host_fabric_name = 1, - .show_starget_node_name = 1, - .show_starget_port_name = 1, - .show_starget_port_id = 1, - .set_rport_dev_loss_tmo = fc_set_rport_loss_tmo, - .show_rport_dev_loss_tmo = 1, - .get_fc_host_stats = fc_get_host_stats, - .issue_fc_host_lip = fcoe_reset, - - .terminate_rport_io = fc_rport_terminate_io, -}; - -static struct scsi_host_template fcoe_sw_shost_template = { - .module = THIS_MODULE, - .name = "FCoE Driver", - .proc_name = FCOE_SW_NAME, - .queuecommand = fc_queuecommand, - .eh_abort_handler = fc_eh_abort, - .eh_device_reset_handler = fc_eh_device_reset, - .eh_host_reset_handler = fc_eh_host_reset, - .slave_alloc = fc_slave_alloc, - .change_queue_depth = fc_change_queue_depth, - .change_queue_type = fc_change_queue_type, - .this_id = -1, - .cmd_per_lun = 32, - .can_queue = FCOE_MAX_OUTSTANDING_COMMANDS, - .use_clustering = ENABLE_CLUSTERING, - .sg_tablesize = SG_ALL, - .max_sectors = 0xffff, -}; - -/* - * fcoe_sw_lport_config - sets up the fc_lport - * @lp: ptr to the fc_lport - * @shost: ptr to the parent scsi host - * - * Returns: 0 for success - * - */ -static int fcoe_sw_lport_config(struct fc_lport *lp) -{ - int i = 0; - - lp->link_status = 0; - lp->max_retry_count = 3; - lp->e_d_tov = 2 * 1000; /* FC-FS default */ - lp->r_a_tov = 2 * 2 * 1000; - lp->service_params = (FCP_SPPF_INIT_FCN | FCP_SPPF_RD_XRDY_DIS | - FCP_SPPF_RETRY | FCP_SPPF_CONF_COMPL); - - /* - * allocate per cpu stats block - */ - for_each_online_cpu(i) - lp->dev_stats[i] = kzalloc(sizeof(struct fcoe_dev_stats), - GFP_KERNEL); - - /* lport fc_lport related configuration */ - fc_lport_config(lp); - - return 0; -} - -/* - * fcoe_sw_netdev_config - sets up fcoe_softc for lport and network - * related properties - * @lp : ptr to the fc_lport - * @netdev : ptr to the associated netdevice struct - * - * Must be called after fcoe_sw_lport_config() as it will use lport mutex - * - * Returns : 0 for success - * - */ -static int fcoe_sw_netdev_config(struct fc_lport *lp, struct net_device *netdev) -{ - u32 mfs; - u64 wwnn, wwpn; - struct fcoe_softc *fc; - u8 flogi_maddr[ETH_ALEN]; - - /* Setup lport private data to point to fcoe softc */ - fc = lport_priv(lp); - fc->lp = lp; - fc->real_dev = netdev; - fc->phys_dev = netdev; - - /* Require support for get_pauseparam ethtool op. */ - if (netdev->priv_flags & IFF_802_1Q_VLAN) - fc->phys_dev = vlan_dev_real_dev(netdev); - - /* Do not support for bonding device */ - if ((fc->real_dev->priv_flags & IFF_MASTER_ALB) || - (fc->real_dev->priv_flags & IFF_SLAVE_INACTIVE) || - (fc->real_dev->priv_flags & IFF_MASTER_8023AD)) { - return -EOPNOTSUPP; - } - - /* - * Determine max frame size based on underlying device and optional - * user-configured limit. If the MFS is too low, fcoe_link_ok() - * will return 0, so do this first. - */ - mfs = fc->real_dev->mtu - (sizeof(struct fcoe_hdr) + - sizeof(struct fcoe_crc_eof)); - if (fc_set_mfs(lp, mfs)) - return -EINVAL; - - lp->link_status = ~FC_PAUSE & ~FC_LINK_UP; - if (!fcoe_link_ok(lp)) - lp->link_status |= FC_LINK_UP; - - /* offload features support */ - if (fc->real_dev->features & NETIF_F_SG) - lp->sg_supp = 1; - - - skb_queue_head_init(&fc->fcoe_pending_queue); - - /* setup Source Mac Address */ - memcpy(fc->ctl_src_addr, fc->real_dev->dev_addr, - fc->real_dev->addr_len); - - wwnn = fcoe_wwn_from_mac(fc->real_dev->dev_addr, 1, 0); - fc_set_wwnn(lp, wwnn); - /* XXX - 3rd arg needs to be vlan id */ - wwpn = fcoe_wwn_from_mac(fc->real_dev->dev_addr, 2, 0); - fc_set_wwpn(lp, wwpn); - - /* - * Add FCoE MAC address as second unicast MAC address - * or enter promiscuous mode if not capable of listening - * for multiple unicast MACs. - */ - rtnl_lock(); - memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); - dev_unicast_add(fc->real_dev, flogi_maddr, ETH_ALEN); - rtnl_unlock(); - - /* - * setup the receive function from ethernet driver - * on the ethertype for the given device - */ - fc->fcoe_packet_type.func = fcoe_rcv; - fc->fcoe_packet_type.type = __constant_htons(ETH_P_FCOE); - fc->fcoe_packet_type.dev = fc->real_dev; - dev_add_pack(&fc->fcoe_packet_type); - - return 0; -} - -/* - * fcoe_sw_shost_config - sets up fc_lport->host - * @lp : ptr to the fc_lport - * @shost : ptr to the associated scsi host - * @dev : device associated to scsi host - * - * Must be called after fcoe_sw_lport_config) and fcoe_sw_netdev_config() - * - * Returns : 0 for success - * - */ -static int fcoe_sw_shost_config(struct fc_lport *lp, struct Scsi_Host *shost, - struct device *dev) -{ - int rc = 0; - - /* lport scsi host config */ - lp->host = shost; - - lp->host->max_lun = FCOE_MAX_LUN; - lp->host->max_id = FCOE_MAX_FCP_TARGET; - lp->host->max_channel = 0; - lp->host->transportt = scsi_transport_fcoe_sw; - - /* add the new host to the SCSI-ml */ - rc = scsi_add_host(lp->host, dev); - if (rc) { - FC_DBG("fcoe_sw_shost_config:error on scsi_add_host\n"); - return rc; - } - sprintf(fc_host_symbolic_name(lp->host), "%s v%s over %s", - FCOE_SW_NAME, FCOE_SW_VERSION, - fcoe_netdev(lp)->name); - - return 0; -} - -/* - * fcoe_sw_em_config - allocates em for this lport - * @lp: the port that em is to allocated for - * - * Returns : 0 on success - */ -static inline int fcoe_sw_em_config(struct fc_lport *lp) -{ - BUG_ON(lp->emp); - - lp->emp = fc_exch_mgr_alloc(lp, FC_CLASS_3, - FCOE_MIN_XID, FCOE_MAX_XID); - if (!lp->emp) - return -ENOMEM; - - return 0; -} - -/* - * fcoe_sw_destroy - FCoE software HBA tear-down function - * @netdev: ptr to the associated net_device - * - * Returns: 0 if link is OK for use by FCoE. - */ -static int fcoe_sw_destroy(struct net_device *netdev) -{ - int cpu; - struct fc_lport *lp = NULL; - struct fcoe_softc *fc; - u8 flogi_maddr[ETH_ALEN]; - - BUG_ON(!netdev); - - printk(KERN_DEBUG "fcoe_sw_destroy:interface on %s\n", - netdev->name); - - lp = fcoe_hostlist_lookup(netdev); - if (!lp) - return -ENODEV; - - fc = fcoe_softc(lp); - - /* Logout of the fabric */ - fc_fabric_logoff(lp); - - /* Remove the instance from fcoe's list */ - fcoe_hostlist_remove(lp); - - /* Don't listen for Ethernet packets anymore */ - dev_remove_pack(&fc->fcoe_packet_type); - - /* Cleanup the fc_lport */ - fc_lport_destroy(lp); - fc_fcp_destroy(lp); - - /* Detach from the scsi-ml */ - fc_remove_host(lp->host); - scsi_remove_host(lp->host); - - /* There are no more rports or I/O, free the EM */ - if (lp->emp) - fc_exch_mgr_free(lp->emp); - - /* Delete secondary MAC addresses */ - rtnl_lock(); - memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); - dev_unicast_delete(fc->real_dev, flogi_maddr, ETH_ALEN); - if (compare_ether_addr(fc->data_src_addr, (u8[6]) { 0 })) - dev_unicast_delete(fc->real_dev, fc->data_src_addr, ETH_ALEN); - rtnl_unlock(); - - /* Free the per-CPU revieve threads */ - fcoe_percpu_clean(lp); - - /* Free existing skbs */ - fcoe_clean_pending_queue(lp); - - /* Free memory used by statistical counters */ - for_each_online_cpu(cpu) - kfree(lp->dev_stats[cpu]); - - /* Release the net_device and Scsi_Host */ - dev_put(fc->real_dev); - scsi_host_put(lp->host); - - return 0; -} - -static struct libfc_function_template fcoe_sw_libfc_fcn_templ = { - .frame_send = fcoe_xmit, -}; - -/* - * fcoe_sw_create - this function creates the fcoe interface - * @netdev: pointer the associated netdevice - * - * Creates fc_lport struct and scsi_host for lport, configures lport - * and starts fabric login. - * - * Returns : 0 on success - */ -static int fcoe_sw_create(struct net_device *netdev) -{ - int rc; - struct fc_lport *lp = NULL; - struct fcoe_softc *fc; - struct Scsi_Host *shost; - - BUG_ON(!netdev); - - printk(KERN_DEBUG "fcoe_sw_create:interface on %s\n", - netdev->name); - - lp = fcoe_hostlist_lookup(netdev); - if (lp) - return -EEXIST; - - shost = fcoe_host_alloc(&fcoe_sw_shost_template, - sizeof(struct fcoe_softc)); - if (!shost) { - FC_DBG("Could not allocate host structure\n"); - return -ENOMEM; - } - lp = shost_priv(shost); - fc = lport_priv(lp); - - /* configure fc_lport, e.g., em */ - rc = fcoe_sw_lport_config(lp); - if (rc) { - FC_DBG("Could not configure lport\n"); - goto out_host_put; - } - - /* configure lport network properties */ - rc = fcoe_sw_netdev_config(lp, netdev); - if (rc) { - FC_DBG("Could not configure netdev for lport\n"); - goto out_host_put; - } - - /* configure lport scsi host properties */ - rc = fcoe_sw_shost_config(lp, shost, &netdev->dev); - if (rc) { - FC_DBG("Could not configure shost for lport\n"); - goto out_host_put; - } - - /* lport exch manager allocation */ - rc = fcoe_sw_em_config(lp); - if (rc) { - FC_DBG("Could not configure em for lport\n"); - goto out_host_put; - } - - /* Initialize the library */ - rc = fcoe_libfc_config(lp, &fcoe_sw_libfc_fcn_templ); - if (rc) { - FC_DBG("Could not configure libfc for lport!\n"); - goto out_lp_destroy; - } - - /* add to lports list */ - fcoe_hostlist_add(lp); - - lp->boot_time = jiffies; - - fc_fabric_login(lp); - - dev_hold(netdev); - - return rc; - -out_lp_destroy: - fc_exch_mgr_free(lp->emp); /* Free the EM */ -out_host_put: - scsi_host_put(lp->host); - return rc; -} - -/* - * fcoe_sw_match - the fcoe sw transport match function - * - * Returns : false always - */ -static bool fcoe_sw_match(struct net_device *netdev) -{ - /* FIXME - for sw transport, always return false */ - return false; -} - -/* the sw hba fcoe transport */ -struct fcoe_transport fcoe_sw_transport = { - .name = "fcoesw", - .create = fcoe_sw_create, - .destroy = fcoe_sw_destroy, - .match = fcoe_sw_match, - .vendor = 0x0, - .device = 0xffff, -}; - -/* - * fcoe_sw_init - registers fcoe_sw_transport - * - * Returns : 0 on success - */ -int __init fcoe_sw_init(void) -{ - /* attach to scsi transport */ - scsi_transport_fcoe_sw = - fc_attach_transport(&fcoe_sw_transport_function); - if (!scsi_transport_fcoe_sw) { - printk(KERN_ERR "fcoe_sw_init:fc_attach_transport() failed\n"); - return -ENODEV; - } - /* register sw transport */ - fcoe_transport_register(&fcoe_sw_transport); - return 0; -} - -/* - * fcoe_sw_exit - unregisters fcoe_sw_transport - * - * Returns : 0 on success - */ -int __exit fcoe_sw_exit(void) -{ - /* dettach the transport */ - fc_release_transport(scsi_transport_fcoe_sw); - fcoe_transport_unregister(&fcoe_sw_transport); - return 0; -} diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c index e419f486cdb..f410f4abb54 100644 --- a/drivers/scsi/fcoe/libfcoe.c +++ b/drivers/scsi/fcoe/libfcoe.c @@ -1,5 +1,6 @@ /* - * Copyright(c) 2007 - 2008 Intel Corporation. All rights reserved. + * Copyright (c) 2008-2009 Cisco Systems, Inc. All rights reserved. + * Copyright (c) 2009 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -17,1237 +18,1263 @@ * Maintained at www.Open-FCoE.org */ +#include <linux/types.h> #include <linux/module.h> -#include <linux/version.h> #include <linux/kernel.h> +#include <linux/list.h> #include <linux/spinlock.h> -#include <linux/skbuff.h> +#include <linux/timer.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/ethtool.h> #include <linux/if_ether.h> #include <linux/if_vlan.h> -#include <linux/kthread.h> -#include <linux/crc32.h> -#include <linux/cpu.h> -#include <linux/fs.h> -#include <linux/sysfs.h> -#include <linux/ctype.h> -#include <scsi/scsi_tcq.h> -#include <scsi/scsicam.h> -#include <scsi/scsi_transport.h> -#include <scsi/scsi_transport_fc.h> +#include <linux/netdevice.h> +#include <linux/errno.h> +#include <linux/bitops.h> #include <net/rtnetlink.h> +#include <scsi/fc/fc_els.h> +#include <scsi/fc/fc_fs.h> +#include <scsi/fc/fc_fip.h> #include <scsi/fc/fc_encaps.h> +#include <scsi/fc/fc_fcoe.h> #include <scsi/libfc.h> -#include <scsi/fc_frame.h> #include <scsi/libfcoe.h> -#include <scsi/fc_transport_fcoe.h> -static int debug_fcoe; +MODULE_AUTHOR("Open-FCoE.org"); +MODULE_DESCRIPTION("FIP discovery protocol support for FCoE HBAs"); +MODULE_LICENSE("GPL v2"); + +#define FCOE_CTLR_MIN_FKA 500 /* min keep alive (mS) */ +#define FCOE_CTLR_DEF_FKA FIP_DEF_FKA /* default keep alive (mS) */ -#define FCOE_MAX_QUEUE_DEPTH 256 +static void fcoe_ctlr_timeout(unsigned long); +static void fcoe_ctlr_link_work(struct work_struct *); +static void fcoe_ctlr_recv_work(struct work_struct *); -/* destination address mode */ -#define FCOE_GW_ADDR_MODE 0x00 -#define FCOE_FCOUI_ADDR_MODE 0x01 +static u8 fcoe_all_fcfs[ETH_ALEN] = FIP_ALL_FCF_MACS; -#define FCOE_WORD_TO_BYTE 4 +static u32 fcoe_ctlr_debug; /* 1 for basic, 2 for noisy debug */ -MODULE_AUTHOR("Open-FCoE.org"); -MODULE_DESCRIPTION("FCoE"); -MODULE_LICENSE("GPL"); - -/* fcoe host list */ -LIST_HEAD(fcoe_hostlist); -DEFINE_RWLOCK(fcoe_hostlist_lock); -DEFINE_TIMER(fcoe_timer, NULL, 0, 0); -struct fcoe_percpu_s *fcoe_percpu[NR_CPUS]; - - -/* Function Prototyes */ -static int fcoe_check_wait_queue(struct fc_lport *); -static void fcoe_insert_wait_queue_head(struct fc_lport *, struct sk_buff *); -static void fcoe_insert_wait_queue(struct fc_lport *, struct sk_buff *); -static void fcoe_recv_flogi(struct fcoe_softc *, struct fc_frame *, u8 *); -#ifdef CONFIG_HOTPLUG_CPU -static int fcoe_cpu_callback(struct notifier_block *, ulong, void *); -#endif /* CONFIG_HOTPLUG_CPU */ -static int fcoe_device_notification(struct notifier_block *, ulong, void *); -static void fcoe_dev_setup(void); -static void fcoe_dev_cleanup(void); - -/* notification function from net device */ -static struct notifier_block fcoe_notifier = { - .notifier_call = fcoe_device_notification, -}; - - -#ifdef CONFIG_HOTPLUG_CPU -static struct notifier_block fcoe_cpu_notifier = { - .notifier_call = fcoe_cpu_callback, -}; +#define FIP_DBG_LVL(level, fmt, args...) \ + do { \ + if (fcoe_ctlr_debug >= (level)) \ + FC_DBG(fmt, ##args); \ + } while (0) + +#define FIP_DBG(fmt, args...) FIP_DBG_LVL(1, fmt, ##args) + +/* + * Return non-zero if FCF fcoe_size has been validated. + */ +static inline int fcoe_ctlr_mtu_valid(const struct fcoe_fcf *fcf) +{ + return (fcf->flags & FIP_FL_SOL) != 0; +} + +/* + * Return non-zero if the FCF is usable. + */ +static inline int fcoe_ctlr_fcf_usable(struct fcoe_fcf *fcf) +{ + u16 flags = FIP_FL_SOL | FIP_FL_AVAIL; + + return (fcf->flags & flags) == flags; +} /** - * fcoe_create_percpu_data - creates the associated cpu data - * @cpu: index for the cpu where fcoe cpu data will be created - * - * create percpu stats block, from cpu add notifier - * - * Returns: none - **/ -static void fcoe_create_percpu_data(int cpu) + * fcoe_ctlr_init() - Initialize the FCoE Controller instance. + * @fip: FCoE controller. + */ +void fcoe_ctlr_init(struct fcoe_ctlr *fip) { - struct fc_lport *lp; - struct fcoe_softc *fc; - - write_lock_bh(&fcoe_hostlist_lock); - list_for_each_entry(fc, &fcoe_hostlist, list) { - lp = fc->lp; - if (lp->dev_stats[cpu] == NULL) - lp->dev_stats[cpu] = - kzalloc(sizeof(struct fcoe_dev_stats), - GFP_KERNEL); - } - write_unlock_bh(&fcoe_hostlist_lock); + fip->state = FIP_ST_LINK_WAIT; + INIT_LIST_HEAD(&fip->fcfs); + spin_lock_init(&fip->lock); + fip->flogi_oxid = FC_XID_UNKNOWN; + setup_timer(&fip->timer, fcoe_ctlr_timeout, (unsigned long)fip); + INIT_WORK(&fip->link_work, fcoe_ctlr_link_work); + INIT_WORK(&fip->recv_work, fcoe_ctlr_recv_work); + skb_queue_head_init(&fip->fip_recv_list); } +EXPORT_SYMBOL(fcoe_ctlr_init); /** - * fcoe_destroy_percpu_data - destroys the associated cpu data - * @cpu: index for the cpu where fcoe cpu data will destroyed + * fcoe_ctlr_reset_fcfs() - Reset and free all FCFs for a controller. + * @fip: FCoE controller. * - * destroy percpu stats block called by cpu add/remove notifier - * - * Retuns: none - **/ -static void fcoe_destroy_percpu_data(int cpu) + * Called with &fcoe_ctlr lock held. + */ +static void fcoe_ctlr_reset_fcfs(struct fcoe_ctlr *fip) { - struct fc_lport *lp; - struct fcoe_softc *fc; + struct fcoe_fcf *fcf; + struct fcoe_fcf *next; - write_lock_bh(&fcoe_hostlist_lock); - list_for_each_entry(fc, &fcoe_hostlist, list) { - lp = fc->lp; - kfree(lp->dev_stats[cpu]); - lp->dev_stats[cpu] = NULL; + fip->sel_fcf = NULL; + list_for_each_entry_safe(fcf, next, &fip->fcfs, list) { + list_del(&fcf->list); + kfree(fcf); } - write_unlock_bh(&fcoe_hostlist_lock); + fip->fcf_count = 0; + fip->sel_time = 0; } /** - * fcoe_cpu_callback - fcoe cpu hotplug event callback - * @nfb: callback data block - * @action: event triggering the callback - * @hcpu: index for the cpu of this event + * fcoe_ctrl_destroy() - Disable and tear-down the FCoE controller. + * @fip: FCoE controller. + * + * This is called by FCoE drivers before freeing the &fcoe_ctlr. * - * this creates or destroys per cpu data for fcoe + * The receive handler will have been deleted before this to guarantee + * that no more recv_work will be scheduled. * - * Returns NOTIFY_OK always. - **/ -static int fcoe_cpu_callback(struct notifier_block *nfb, unsigned long action, - void *hcpu) + * The timer routine will simply return once we set FIP_ST_DISABLED. + * This guarantees that no further timeouts or work will be scheduled. + */ +void fcoe_ctlr_destroy(struct fcoe_ctlr *fip) { - unsigned int cpu = (unsigned long)hcpu; - - switch (action) { - case CPU_ONLINE: - fcoe_create_percpu_data(cpu); - break; - case CPU_DEAD: - fcoe_destroy_percpu_data(cpu); - break; - default: - break; - } - return NOTIFY_OK; + flush_work(&fip->recv_work); + spin_lock_bh(&fip->lock); + fip->state = FIP_ST_DISABLED; + fcoe_ctlr_reset_fcfs(fip); + spin_unlock_bh(&fip->lock); + del_timer_sync(&fip->timer); + flush_work(&fip->link_work); } -#endif /* CONFIG_HOTPLUG_CPU */ +EXPORT_SYMBOL(fcoe_ctlr_destroy); /** - * fcoe_rcv - this is the fcoe receive function called by NET_RX_SOFTIRQ - * @skb: the receive skb - * @dev: associated net device - * @ptype: context - * @odldev: last device + * fcoe_ctlr_fcoe_size() - Return the maximum FCoE size required for VN_Port. + * @fip: FCoE controller. * - * this function will receive the packet and build fc frame and pass it up - * - * Returns: 0 for success - **/ -int fcoe_rcv(struct sk_buff *skb, struct net_device *dev, - struct packet_type *ptype, struct net_device *olddev) + * Returns the maximum packet size including the FCoE header and trailer, + * but not including any Ethernet or VLAN headers. + */ +static inline u32 fcoe_ctlr_fcoe_size(struct fcoe_ctlr *fip) { - struct fc_lport *lp; - struct fcoe_rcv_info *fr; - struct fcoe_softc *fc; - struct fcoe_dev_stats *stats; - struct fc_frame_header *fh; - unsigned short oxid; - int cpu_idx; - struct fcoe_percpu_s *fps; - - fc = container_of(ptype, struct fcoe_softc, fcoe_packet_type); - lp = fc->lp; - if (unlikely(lp == NULL)) { - FC_DBG("cannot find hba structure"); - goto err2; - } - - if (unlikely(debug_fcoe)) { - FC_DBG("skb_info: len:%d data_len:%d head:%p data:%p tail:%p " - "end:%p sum:%d dev:%s", skb->len, skb->data_len, - skb->head, skb->data, skb_tail_pointer(skb), - skb_end_pointer(skb), skb->csum, - skb->dev ? skb->dev->name : "<NULL>"); + /* + * Determine the max FCoE frame size allowed, including + * FCoE header and trailer. + * Note: lp->mfs is currently the payload size, not the frame size. + */ + return fip->lp->mfs + sizeof(struct fc_frame_header) + + sizeof(struct fcoe_hdr) + sizeof(struct fcoe_crc_eof); +} - } +/** + * fcoe_ctlr_solicit() - Send a solicitation. + * @fip: FCoE controller. + * @fcf: Destination FCF. If NULL, a multicast solicitation is sent. + */ +static void fcoe_ctlr_solicit(struct fcoe_ctlr *fip, struct fcoe_fcf *fcf) +{ + struct sk_buff *skb; + struct fip_sol { + struct ethhdr eth; + struct fip_header fip; + struct { + struct fip_mac_desc mac; + struct fip_wwn_desc wwnn; + struct fip_size_desc size; + } __attribute__((packed)) desc; + } __attribute__((packed)) *sol; + u32 fcoe_size; + + skb = dev_alloc_skb(sizeof(*sol)); + if (!skb) + return; - /* check for FCOE packet type */ - if (unlikely(eth_hdr(skb)->h_proto != htons(ETH_P_FCOE))) { - FC_DBG("wrong FC type frame"); - goto err; - } + sol = (struct fip_sol *)skb->data; - /* - * Check for minimum frame length, and make sure required FCoE - * and FC headers are pulled into the linear data area. - */ - if (unlikely((skb->len < FCOE_MIN_FRAME) || - !pskb_may_pull(skb, FCOE_HEADER_LEN))) - goto err; + memset(sol, 0, sizeof(*sol)); + memcpy(sol->eth.h_dest, fcf ? fcf->fcf_mac : fcoe_all_fcfs, ETH_ALEN); + memcpy(sol->eth.h_source, fip->ctl_src_addr, ETH_ALEN); + sol->eth.h_proto = htons(ETH_P_FIP); - skb_set_transport_header(skb, sizeof(struct fcoe_hdr)); - fh = (struct fc_frame_header *) skb_transport_header(skb); + sol->fip.fip_ver = FIP_VER_ENCAPS(FIP_VER); + sol->fip.fip_op = htons(FIP_OP_DISC); + sol->fip.fip_subcode = FIP_SC_SOL; + sol->fip.fip_dl_len = htons(sizeof(sol->desc) / FIP_BPW); + sol->fip.fip_flags = htons(FIP_FL_FPMA); - oxid = ntohs(fh->fh_ox_id); + sol->desc.mac.fd_desc.fip_dtype = FIP_DT_MAC; + sol->desc.mac.fd_desc.fip_dlen = sizeof(sol->desc.mac) / FIP_BPW; + memcpy(sol->desc.mac.fd_mac, fip->ctl_src_addr, ETH_ALEN); - fr = fcoe_dev_from_skb(skb); - fr->fr_dev = lp; - fr->ptype = ptype; - cpu_idx = 0; -#ifdef CONFIG_SMP - /* - * The incoming frame exchange id(oxid) is ANDed with num of online - * cpu bits to get cpu_idx and then this cpu_idx is used for selecting - * a per cpu kernel thread from fcoe_percpu. In case the cpu is - * offline or no kernel thread for derived cpu_idx then cpu_idx is - * initialize to first online cpu index. - */ - cpu_idx = oxid & (num_online_cpus() - 1); - if (!fcoe_percpu[cpu_idx] || !cpu_online(cpu_idx)) - cpu_idx = first_cpu(cpu_online_map); -#endif - fps = fcoe_percpu[cpu_idx]; + sol->desc.wwnn.fd_desc.fip_dtype = FIP_DT_NAME; + sol->desc.wwnn.fd_desc.fip_dlen = sizeof(sol->desc.wwnn) / FIP_BPW; + put_unaligned_be64(fip->lp->wwnn, &sol->desc.wwnn.fd_wwn); - spin_lock_bh(&fps->fcoe_rx_list.lock); - __skb_queue_tail(&fps->fcoe_rx_list, skb); - if (fps->fcoe_rx_list.qlen == 1) - wake_up_process(fps->thread); + fcoe_size = fcoe_ctlr_fcoe_size(fip); + sol->desc.size.fd_desc.fip_dtype = FIP_DT_FCOE_SIZE; + sol->desc.size.fd_desc.fip_dlen = sizeof(sol->desc.size) / FIP_BPW; + sol->desc.size.fd_size = htons(fcoe_size); - spin_unlock_bh(&fps->fcoe_rx_list.lock); + skb_put(skb, sizeof(*sol)); + skb->protocol = htons(ETH_P_802_3); + skb_reset_mac_header(skb); + skb_reset_network_header(skb); + fip->send(fip, skb); - return 0; -err: -#ifdef CONFIG_SMP - stats = lp->dev_stats[smp_processor_id()]; -#else - stats = lp->dev_stats[0]; -#endif - if (stats) - stats->ErrorFrames++; - -err2: - kfree_skb(skb); - return -1; + if (!fcf) + fip->sol_time = jiffies; } -EXPORT_SYMBOL_GPL(fcoe_rcv); /** - * fcoe_start_io - pass to netdev to start xmit for fcoe - * @skb: the skb to be xmitted + * fcoe_ctlr_link_up() - Start FCoE controller. + * @fip: FCoE controller. * - * Returns: 0 for success - **/ -static inline int fcoe_start_io(struct sk_buff *skb) + * Called from the LLD when the network link is ready. + */ +void fcoe_ctlr_link_up(struct fcoe_ctlr *fip) { - int rc; - - skb_get(skb); - rc = dev_queue_xmit(skb); - if (rc != 0) - return rc; - kfree_skb(skb); - return 0; + spin_lock_bh(&fip->lock); + if (fip->state == FIP_ST_NON_FIP || fip->state == FIP_ST_AUTO) { + fip->last_link = 1; + fip->link = 1; + spin_unlock_bh(&fip->lock); + fc_linkup(fip->lp); + } else if (fip->state == FIP_ST_LINK_WAIT) { + fip->state = FIP_ST_AUTO; + fip->last_link = 1; + fip->link = 1; + spin_unlock_bh(&fip->lock); + FIP_DBG("%s", "setting AUTO mode.\n"); + fc_linkup(fip->lp); + fcoe_ctlr_solicit(fip, NULL); + } else + spin_unlock_bh(&fip->lock); } +EXPORT_SYMBOL(fcoe_ctlr_link_up); /** - * fcoe_get_paged_crc_eof - in case we need alloc a page for crc_eof - * @skb: the skb to be xmitted - * @tlen: total len + * fcoe_ctlr_reset() - Reset FIP. + * @fip: FCoE controller. + * @new_state: FIP state to be entered. * - * Returns: 0 for success - **/ -static int fcoe_get_paged_crc_eof(struct sk_buff *skb, int tlen) + * Returns non-zero if the link was up and now isn't. + */ +static int fcoe_ctlr_reset(struct fcoe_ctlr *fip, enum fip_state new_state) { - struct fcoe_percpu_s *fps; - struct page *page; - int cpu_idx; - - cpu_idx = get_cpu(); - fps = fcoe_percpu[cpu_idx]; - page = fps->crc_eof_page; - if (!page) { - page = alloc_page(GFP_ATOMIC); - if (!page) { - put_cpu(); - return -ENOMEM; - } - fps->crc_eof_page = page; - WARN_ON(fps->crc_eof_offset != 0); + struct fc_lport *lp = fip->lp; + int link_dropped; + + spin_lock_bh(&fip->lock); + fcoe_ctlr_reset_fcfs(fip); + del_timer(&fip->timer); + fip->state = new_state; + fip->ctlr_ka_time = 0; + fip->port_ka_time = 0; + fip->sol_time = 0; + fip->flogi_oxid = FC_XID_UNKNOWN; + fip->map_dest = 0; + fip->last_link = 0; + link_dropped = fip->link; + fip->link = 0; + spin_unlock_bh(&fip->lock); + + if (link_dropped) + fc_linkdown(lp); + + if (new_state == FIP_ST_ENABLED) { + fcoe_ctlr_solicit(fip, NULL); + fc_linkup(lp); + link_dropped = 0; } - - get_page(page); - skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags, page, - fps->crc_eof_offset, tlen); - skb->len += tlen; - skb->data_len += tlen; - skb->truesize += tlen; - fps->crc_eof_offset += sizeof(struct fcoe_crc_eof); - - if (fps->crc_eof_offset >= PAGE_SIZE) { - fps->crc_eof_page = NULL; - fps->crc_eof_offset = 0; - put_page(page); - } - put_cpu(); - return 0; + return link_dropped; } /** - * fcoe_fc_crc - calculates FC CRC in this fcoe skb - * @fp: the fc_frame containg data to be checksummed + * fcoe_ctlr_link_down() - Stop FCoE controller. + * @fip: FCoE controller. * - * This uses crc32() to calculate the crc for fc frame - * Return : 32 bit crc + * Returns non-zero if the link was up and now isn't. * - **/ -u32 fcoe_fc_crc(struct fc_frame *fp) + * Called from the LLD when the network link is not ready. + * There may be multiple calls while the link is down. + */ +int fcoe_ctlr_link_down(struct fcoe_ctlr *fip) { - struct sk_buff *skb = fp_skb(fp); - struct skb_frag_struct *frag; - unsigned char *data; - unsigned long off, len, clen; - u32 crc; - unsigned i; - - crc = crc32(~0, skb->data, skb_headlen(skb)); - - for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { - frag = &skb_shinfo(skb)->frags[i]; - off = frag->page_offset; - len = frag->size; - while (len > 0) { - clen = min(len, PAGE_SIZE - (off & ~PAGE_MASK)); - data = kmap_atomic(frag->page + (off >> PAGE_SHIFT), - KM_SKB_DATA_SOFTIRQ); - crc = crc32(crc, data + (off & ~PAGE_MASK), clen); - kunmap_atomic(data, KM_SKB_DATA_SOFTIRQ); - off += clen; - len -= clen; - } - } - return crc; + return fcoe_ctlr_reset(fip, FIP_ST_LINK_WAIT); } -EXPORT_SYMBOL_GPL(fcoe_fc_crc); +EXPORT_SYMBOL(fcoe_ctlr_link_down); /** - * fcoe_xmit - FCoE frame transmit function - * @lp: the associated local port - * @fp: the fc_frame to be transmitted + * fcoe_ctlr_send_keep_alive() - Send a keep-alive to the selected FCF. + * @fip: FCoE controller. + * @ports: 0 for controller keep-alive, 1 for port keep-alive. + * @sa: source MAC address. * - * Return : 0 for success + * A controller keep-alive is sent every fka_period (typically 8 seconds). + * The source MAC is the native MAC address. * - **/ -int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp) + * A port keep-alive is sent every 90 seconds while logged in. + * The source MAC is the assigned mapped source address. + * The destination is the FCF's F-port. + */ +static void fcoe_ctlr_send_keep_alive(struct fcoe_ctlr *fip, int ports, u8 *sa) { - int wlen, rc = 0; - u32 crc; - struct ethhdr *eh; - struct fcoe_crc_eof *cp; struct sk_buff *skb; - struct fcoe_dev_stats *stats; - struct fc_frame_header *fh; - unsigned int hlen; /* header length implies the version */ - unsigned int tlen; /* trailer length */ - unsigned int elen; /* eth header, may include vlan */ - int flogi_in_progress = 0; - struct fcoe_softc *fc; - u8 sof, eof; - struct fcoe_hdr *hp; - - WARN_ON((fr_len(fp) % sizeof(u32)) != 0); - - fc = fcoe_softc(lp); - /* - * if it is a flogi then we need to learn gw-addr - * and my own fcid - */ - fh = fc_frame_header_get(fp); - if (unlikely(fh->fh_r_ctl == FC_RCTL_ELS_REQ)) { - if (fc_frame_payload_op(fp) == ELS_FLOGI) { - fc->flogi_oxid = ntohs(fh->fh_ox_id); - fc->address_mode = FCOE_FCOUI_ADDR_MODE; - fc->flogi_progress = 1; - flogi_in_progress = 1; - } else if (fc->flogi_progress && ntoh24(fh->fh_s_id) != 0) { - /* - * Here we must've gotten an SID by accepting an FLOGI - * from a point-to-point connection. Switch to using - * the source mac based on the SID. The destination - * MAC in this case would have been set by receving the - * FLOGI. - */ - fc_fcoe_set_mac(fc->data_src_addr, fh->fh_s_id); - fc->flogi_progress = 0; - } - } - - skb = fp_skb(fp); - sof = fr_sof(fp); - eof = fr_eof(fp); - - elen = (fc->real_dev->priv_flags & IFF_802_1Q_VLAN) ? - sizeof(struct vlan_ethhdr) : sizeof(struct ethhdr); - hlen = sizeof(struct fcoe_hdr); - tlen = sizeof(struct fcoe_crc_eof); - wlen = (skb->len - tlen + sizeof(crc)) / FCOE_WORD_TO_BYTE; - - /* crc offload */ - if (likely(lp->crc_offload)) { - skb->ip_summed = CHECKSUM_COMPLETE; - skb->csum_start = skb_headroom(skb); - skb->csum_offset = skb->len; - crc = 0; - } else { - skb->ip_summed = CHECKSUM_NONE; - crc = fcoe_fc_crc(fp); - } + struct fip_kal { + struct ethhdr eth; + struct fip_header fip; + struct fip_mac_desc mac; + } __attribute__((packed)) *kal; + struct fip_vn_desc *vn; + u32 len; + struct fc_lport *lp; + struct fcoe_fcf *fcf; - /* copy fc crc and eof to the skb buff */ - if (skb_is_nonlinear(skb)) { - skb_frag_t *frag; - if (fcoe_get_paged_crc_eof(skb, tlen)) { - kfree(skb); - return -ENOMEM; - } - frag = &skb_shinfo(skb)->frags[skb_shinfo(skb)->nr_frags - 1]; - cp = kmap_atomic(frag->page, KM_SKB_DATA_SOFTIRQ) - + frag->page_offset; - } else { - cp = (struct fcoe_crc_eof *)skb_put(skb, tlen); - } + fcf = fip->sel_fcf; + lp = fip->lp; + if (!fcf || !fc_host_port_id(lp->host)) + return; - memset(cp, 0, sizeof(*cp)); - cp->fcoe_eof = eof; - cp->fcoe_crc32 = cpu_to_le32(~crc); + len = fcoe_ctlr_fcoe_size(fip) + sizeof(struct ethhdr); + BUG_ON(len < sizeof(*kal) + sizeof(*vn)); + skb = dev_alloc_skb(len); + if (!skb) + return; - if (skb_is_nonlinear(skb)) { - kunmap_atomic(cp, KM_SKB_DATA_SOFTIRQ); - cp = NULL; + kal = (struct fip_kal *)skb->data; + memset(kal, 0, len); + memcpy(kal->eth.h_dest, fcf->fcf_mac, ETH_ALEN); + memcpy(kal->eth.h_source, sa, ETH_ALEN); + kal->eth.h_proto = htons(ETH_P_FIP); + + kal->fip.fip_ver = FIP_VER_ENCAPS(FIP_VER); + kal->fip.fip_op = htons(FIP_OP_CTRL); + kal->fip.fip_subcode = FIP_SC_KEEP_ALIVE; + kal->fip.fip_dl_len = htons((sizeof(kal->mac) + + ports * sizeof(*vn)) / FIP_BPW); + kal->fip.fip_flags = htons(FIP_FL_FPMA); + + kal->mac.fd_desc.fip_dtype = FIP_DT_MAC; + kal->mac.fd_desc.fip_dlen = sizeof(kal->mac) / FIP_BPW; + memcpy(kal->mac.fd_mac, fip->ctl_src_addr, ETH_ALEN); + + if (ports) { + vn = (struct fip_vn_desc *)(kal + 1); + vn->fd_desc.fip_dtype = FIP_DT_VN_ID; + vn->fd_desc.fip_dlen = sizeof(*vn) / FIP_BPW; + memcpy(vn->fd_mac, fip->data_src_addr, ETH_ALEN); + hton24(vn->fd_fc_id, fc_host_port_id(lp->host)); + put_unaligned_be64(lp->wwpn, &vn->fd_wwpn); } - /* adjust skb netowrk/transport offsets to match mac/fcoe/fc */ - skb_push(skb, elen + hlen); + skb_put(skb, len); + skb->protocol = htons(ETH_P_802_3); skb_reset_mac_header(skb); skb_reset_network_header(skb); - skb->mac_len = elen; - skb->protocol = htons(ETH_P_802_3); - skb->dev = fc->real_dev; - - /* fill up mac and fcoe headers */ - eh = eth_hdr(skb); - eh->h_proto = htons(ETH_P_FCOE); - if (fc->address_mode == FCOE_FCOUI_ADDR_MODE) - fc_fcoe_set_mac(eh->h_dest, fh->fh_d_id); - else - /* insert GW address */ - memcpy(eh->h_dest, fc->dest_addr, ETH_ALEN); - - if (unlikely(flogi_in_progress)) - memcpy(eh->h_source, fc->ctl_src_addr, ETH_ALEN); - else - memcpy(eh->h_source, fc->data_src_addr, ETH_ALEN); - - hp = (struct fcoe_hdr *)(eh + 1); - memset(hp, 0, sizeof(*hp)); - if (FC_FCOE_VER) - FC_FCOE_ENCAPS_VER(hp, FC_FCOE_VER); - hp->fcoe_sof = sof; - - /* update tx stats: regardless if LLD fails */ - stats = lp->dev_stats[smp_processor_id()]; - if (stats) { - stats->TxFrames++; - stats->TxWords += wlen; - } - - /* send down to lld */ - fr_dev(fp) = lp; - if (fc->fcoe_pending_queue.qlen) - rc = fcoe_check_wait_queue(lp); - - if (rc == 0) - rc = fcoe_start_io(skb); - - if (rc) { - fcoe_insert_wait_queue(lp, skb); - if (fc->fcoe_pending_queue.qlen > FCOE_MAX_QUEUE_DEPTH) - fc_pause(lp); - } - - return 0; + fip->send(fip, skb); } -EXPORT_SYMBOL_GPL(fcoe_xmit); -/* - * fcoe_percpu_receive_thread - recv thread per cpu - * @arg: ptr to the fcoe per cpu struct +/** + * fcoe_ctlr_encaps() - Encapsulate an ELS frame for FIP, without sending it. + * @fip: FCoE controller. + * @dtype: FIP descriptor type for the frame. + * @skb: FCoE ELS frame including FC header but no FCoE headers. + * + * Returns non-zero error code on failure. * - * Return: 0 for success + * The caller must check that the length is a multiple of 4. * + * The @skb must have enough headroom (28 bytes) and tailroom (8 bytes). + * Headroom includes the FIP encapsulation description, FIP header, and + * Ethernet header. The tailroom is for the FIP MAC descriptor. */ -int fcoe_percpu_receive_thread(void *arg) +static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip, + u8 dtype, struct sk_buff *skb) { - struct fcoe_percpu_s *p = arg; - u32 fr_len; - struct fc_lport *lp; - struct fcoe_rcv_info *fr; - struct fcoe_dev_stats *stats; - struct fc_frame_header *fh; - struct sk_buff *skb; - struct fcoe_crc_eof crc_eof; - struct fc_frame *fp; - u8 *mac = NULL; - struct fcoe_softc *fc; - struct fcoe_hdr *hp; - - set_user_nice(current, 19); - - while (!kthread_should_stop()) { - - spin_lock_bh(&p->fcoe_rx_list.lock); - while ((skb = __skb_dequeue(&p->fcoe_rx_list)) == NULL) { - set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_bh(&p->fcoe_rx_list.lock); - schedule(); - set_current_state(TASK_RUNNING); - if (kthread_should_stop()) - return 0; - spin_lock_bh(&p->fcoe_rx_list.lock); - } - spin_unlock_bh(&p->fcoe_rx_list.lock); - fr = fcoe_dev_from_skb(skb); - lp = fr->fr_dev; - if (unlikely(lp == NULL)) { - FC_DBG("invalid HBA Structure"); - kfree_skb(skb); - continue; - } - - stats = lp->dev_stats[smp_processor_id()]; - - if (unlikely(debug_fcoe)) { - FC_DBG("skb_info: len:%d data_len:%d head:%p data:%p " - "tail:%p end:%p sum:%d dev:%s", - skb->len, skb->data_len, - skb->head, skb->data, skb_tail_pointer(skb), - skb_end_pointer(skb), skb->csum, - skb->dev ? skb->dev->name : "<NULL>"); - } - - /* - * Save source MAC address before discarding header. - */ - fc = lport_priv(lp); - if (unlikely(fc->flogi_progress)) - mac = eth_hdr(skb)->h_source; - - if (skb_is_nonlinear(skb)) - skb_linearize(skb); /* not ideal */ - - /* - * Frame length checks and setting up the header pointers - * was done in fcoe_rcv already. - */ - hp = (struct fcoe_hdr *) skb_network_header(skb); - fh = (struct fc_frame_header *) skb_transport_header(skb); - - if (unlikely(FC_FCOE_DECAPS_VER(hp) != FC_FCOE_VER)) { - if (stats) { - if (stats->ErrorFrames < 5) - FC_DBG("unknown FCoE version %x", - FC_FCOE_DECAPS_VER(hp)); - stats->ErrorFrames++; - } - kfree_skb(skb); - continue; - } - - skb_pull(skb, sizeof(struct fcoe_hdr)); - fr_len = skb->len - sizeof(struct fcoe_crc_eof); - - if (stats) { - stats->RxFrames++; - stats->RxWords += fr_len / FCOE_WORD_TO_BYTE; - } + struct fip_encaps_head { + struct ethhdr eth; + struct fip_header fip; + struct fip_encaps encaps; + } __attribute__((packed)) *cap; + struct fip_mac_desc *mac; + struct fcoe_fcf *fcf; + size_t dlen; + + fcf = fip->sel_fcf; + if (!fcf) + return -ENODEV; + dlen = sizeof(struct fip_encaps) + skb->len; /* len before push */ + cap = (struct fip_encaps_head *)skb_push(skb, sizeof(*cap)); + + memset(cap, 0, sizeof(*cap)); + memcpy(cap->eth.h_dest, fcf->fcf_mac, ETH_ALEN); + memcpy(cap->eth.h_source, fip->ctl_src_addr, ETH_ALEN); + cap->eth.h_proto = htons(ETH_P_FIP); + + cap->fip.fip_ver = FIP_VER_ENCAPS(FIP_VER); + cap->fip.fip_op = htons(FIP_OP_LS); + cap->fip.fip_subcode = FIP_SC_REQ; + cap->fip.fip_dl_len = htons((dlen + sizeof(*mac)) / FIP_BPW); + cap->fip.fip_flags = htons(FIP_FL_FPMA); + + cap->encaps.fd_desc.fip_dtype = dtype; + cap->encaps.fd_desc.fip_dlen = dlen / FIP_BPW; + + mac = (struct fip_mac_desc *)skb_put(skb, sizeof(*mac)); + memset(mac, 0, sizeof(mac)); + mac->fd_desc.fip_dtype = FIP_DT_MAC; + mac->fd_desc.fip_dlen = sizeof(*mac) / FIP_BPW; + if (dtype != ELS_FLOGI) + memcpy(mac->fd_mac, fip->data_src_addr, ETH_ALEN); - fp = (struct fc_frame *)skb; - fc_frame_init(fp); - fr_dev(fp) = lp; - fr_sof(fp) = hp->fcoe_sof; - - /* Copy out the CRC and EOF trailer for access */ - if (skb_copy_bits(skb, fr_len, &crc_eof, sizeof(crc_eof))) { - kfree_skb(skb); - continue; - } - fr_eof(fp) = crc_eof.fcoe_eof; - fr_crc(fp) = crc_eof.fcoe_crc32; - if (pskb_trim(skb, fr_len)) { - kfree_skb(skb); - continue; - } - - /* - * We only check CRC if no offload is available and if it is - * it's solicited data, in which case, the FCP layer would - * check it during the copy. - */ - if (lp->crc_offload) - fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED; - else - fr_flags(fp) |= FCPHF_CRC_UNCHECKED; - - fh = fc_frame_header_get(fp); - if (fh->fh_r_ctl == FC_RCTL_DD_SOL_DATA && - fh->fh_type == FC_TYPE_FCP) { - fc_exch_recv(lp, lp->emp, fp); - continue; - } - if (fr_flags(fp) & FCPHF_CRC_UNCHECKED) { - if (le32_to_cpu(fr_crc(fp)) != - ~crc32(~0, skb->data, fr_len)) { - if (debug_fcoe || stats->InvalidCRCCount < 5) - printk(KERN_WARNING "fcoe: dropping " - "frame with CRC error\n"); - stats->InvalidCRCCount++; - stats->ErrorFrames++; - fc_frame_free(fp); - continue; - } - fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED; - } - /* non flogi and non data exchanges are handled here */ - if (unlikely(fc->flogi_progress)) - fcoe_recv_flogi(fc, fp, mac); - fc_exch_recv(lp, lp->emp, fp); - } + skb->protocol = htons(ETH_P_802_3); + skb_reset_mac_header(skb); + skb_reset_network_header(skb); return 0; } /** - * fcoe_recv_flogi - flogi receive function - * @fc: associated fcoe_softc - * @fp: the recieved frame - * @sa: the source address of this flogi + * fcoe_ctlr_els_send() - Send an ELS frame encapsulated by FIP if appropriate. + * @fip: FCoE controller. + * @skb: FCoE ELS frame including FC header but no FCoE headers. * - * This is responsible to parse the flogi response and sets the corresponding - * mac address for the initiator, eitehr OUI based or GW based. + * Returns a non-zero error code if the frame should not be sent. + * Returns zero if the caller should send the frame with FCoE encapsulation. * - * Returns: none - **/ -static void fcoe_recv_flogi(struct fcoe_softc *fc, struct fc_frame *fp, u8 *sa) + * The caller must check that the length is a multiple of 4. + * The SKB must have enough headroom (28 bytes) and tailroom (8 bytes). + */ +int fcoe_ctlr_els_send(struct fcoe_ctlr *fip, struct sk_buff *skb) { struct fc_frame_header *fh; + u16 old_xid; u8 op; - fh = fc_frame_header_get(fp); - if (fh->fh_type != FC_TYPE_ELS) - return; - op = fc_frame_payload_op(fp); - if (op == ELS_LS_ACC && fh->fh_r_ctl == FC_RCTL_ELS_REP && - fc->flogi_oxid == ntohs(fh->fh_ox_id)) { - /* - * FLOGI accepted. - * If the src mac addr is FC_OUI-based, then we mark the - * address_mode flag to use FC_OUI-based Ethernet DA. - * Otherwise we use the FCoE gateway addr - */ - if (!compare_ether_addr(sa, (u8[6]) FC_FCOE_FLOGI_MAC)) { - fc->address_mode = FCOE_FCOUI_ADDR_MODE; - } else { - memcpy(fc->dest_addr, sa, ETH_ALEN); - fc->address_mode = FCOE_GW_ADDR_MODE; - } + if (fip->state == FIP_ST_NON_FIP) + return 0; + fh = (struct fc_frame_header *)skb->data; + op = *(u8 *)(fh + 1); + + switch (op) { + case ELS_FLOGI: + old_xid = fip->flogi_oxid; + fip->flogi_oxid = ntohs(fh->fh_ox_id); + if (fip->state == FIP_ST_AUTO) { + if (old_xid == FC_XID_UNKNOWN) + fip->flogi_count = 0; + fip->flogi_count++; + if (fip->flogi_count < 3) + goto drop; + fip->map_dest = 1; + return 0; + } + op = FIP_DT_FLOGI; + break; + case ELS_FDISC: + if (ntoh24(fh->fh_s_id)) + return 0; + op = FIP_DT_FDISC; + break; + case ELS_LOGO: + if (fip->state != FIP_ST_ENABLED) + return 0; + if (ntoh24(fh->fh_d_id) != FC_FID_FLOGI) + return 0; + op = FIP_DT_LOGO; + break; + case ELS_LS_ACC: + if (fip->flogi_oxid == FC_XID_UNKNOWN) + return 0; + if (!ntoh24(fh->fh_s_id)) + return 0; + if (fip->state == FIP_ST_AUTO) + return 0; /* - * Remove any previously-set unicast MAC filter. - * Add secondary FCoE MAC address filter for our OUI. - */ - rtnl_lock(); - if (compare_ether_addr(fc->data_src_addr, (u8[6]) { 0 })) - dev_unicast_delete(fc->real_dev, fc->data_src_addr, - ETH_ALEN); - fc_fcoe_set_mac(fc->data_src_addr, fh->fh_d_id); - dev_unicast_add(fc->real_dev, fc->data_src_addr, ETH_ALEN); - rtnl_unlock(); - - fc->flogi_progress = 0; - } else if (op == ELS_FLOGI && fh->fh_r_ctl == FC_RCTL_ELS_REQ && sa) { - /* - * Save source MAC for point-to-point responses. + * Here we must've gotten an SID by accepting an FLOGI + * from a point-to-point connection. Switch to using + * the source mac based on the SID. The destination + * MAC in this case would have been set by receving the + * FLOGI. */ - memcpy(fc->dest_addr, sa, ETH_ALEN); - fc->address_mode = FCOE_GW_ADDR_MODE; + fip->flogi_oxid = FC_XID_UNKNOWN; + fc_fcoe_set_mac(fip->data_src_addr, fh->fh_s_id); + return 0; + default: + if (fip->state != FIP_ST_ENABLED) + goto drop; + return 0; } + if (fcoe_ctlr_encaps(fip, op, skb)) + goto drop; + fip->send(fip, skb); + return -EINPROGRESS; +drop: + kfree_skb(skb); + return -EINVAL; } +EXPORT_SYMBOL(fcoe_ctlr_els_send); -/** - * fcoe_watchdog - fcoe timer callback - * @vp: +/* + * fcoe_ctlr_age_fcfs() - Reset and free all old FCFs for a controller. + * @fip: FCoE controller. + * + * Called with lock held. * - * This checks the pending queue length for fcoe and put fcoe to be paused state - * if the FCOE_MAX_QUEUE_DEPTH is reached. This is done for all fc_lport on the - * fcoe_hostlist. + * An FCF is considered old if we have missed three advertisements. + * That is, there have been no valid advertisement from it for three + * times its keep-alive period including fuzz. * - * Returns: 0 for success - **/ -void fcoe_watchdog(ulong vp) + * In addition, determine the time when an FCF selection can occur. + */ +static void fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip) { - struct fc_lport *lp; - struct fcoe_softc *fc; - int paused = 0; - - read_lock(&fcoe_hostlist_lock); - list_for_each_entry(fc, &fcoe_hostlist, list) { - lp = fc->lp; - if (lp) { - if (fc->fcoe_pending_queue.qlen > FCOE_MAX_QUEUE_DEPTH) - paused = 1; - if (fcoe_check_wait_queue(lp) < FCOE_MAX_QUEUE_DEPTH) { - if (paused) - fc_unpause(lp); - } + struct fcoe_fcf *fcf; + struct fcoe_fcf *next; + unsigned long sel_time = 0; + + list_for_each_entry_safe(fcf, next, &fip->fcfs, list) { + if (time_after(jiffies, fcf->time + fcf->fka_period * 3 + + msecs_to_jiffies(FIP_FCF_FUZZ * 3))) { + if (fip->sel_fcf == fcf) + fip->sel_fcf = NULL; + list_del(&fcf->list); + WARN_ON(!fip->fcf_count); + fip->fcf_count--; + kfree(fcf); + } else if (fcoe_ctlr_mtu_valid(fcf) && + (!sel_time || time_before(sel_time, fcf->time))) { + sel_time = fcf->time; } } - read_unlock(&fcoe_hostlist_lock); - - fcoe_timer.expires = jiffies + (1 * HZ); - add_timer(&fcoe_timer); + if (sel_time) { + sel_time += msecs_to_jiffies(FCOE_CTLR_START_DELAY); + fip->sel_time = sel_time; + if (time_before(sel_time, fip->timer.expires)) + mod_timer(&fip->timer, sel_time); + } else { + fip->sel_time = 0; + } } - /** - * fcoe_check_wait_queue - put the skb into fcoe pending xmit queue - * @lp: the fc_port for this skb - * @skb: the associated skb to be xmitted + * fcoe_ctlr_parse_adv() - Decode a FIP advertisement into a new FCF entry. + * @skb: received FIP advertisement frame + * @fcf: resulting FCF entry. * - * This empties the wait_queue, dequeue the head of the wait_queue queue - * and calls fcoe_start_io() for each packet, if all skb have been - * transmitted, return 0 if a error occurs, then restore wait_queue and - * try again later. - * - * The wait_queue is used when the skb transmit fails. skb will go - * in the wait_queue which will be emptied by the time function OR - * by the next skb transmit. - * - * Returns: 0 for success - **/ -static int fcoe_check_wait_queue(struct fc_lport *lp) + * Returns zero on a valid parsed advertisement, + * otherwise returns non zero value. + */ +static int fcoe_ctlr_parse_adv(struct sk_buff *skb, struct fcoe_fcf *fcf) { - int rc, unpause = 0; - int paused = 0; - struct sk_buff *skb; - struct fcoe_softc *fc; - - fc = fcoe_softc(lp); - spin_lock_bh(&fc->fcoe_pending_queue.lock); - - /* - * is this interface paused? - */ - if (fc->fcoe_pending_queue.qlen > FCOE_MAX_QUEUE_DEPTH) - paused = 1; - if (fc->fcoe_pending_queue.qlen) { - while ((skb = __skb_dequeue(&fc->fcoe_pending_queue)) != NULL) { - spin_unlock_bh(&fc->fcoe_pending_queue.lock); - rc = fcoe_start_io(skb); - if (rc) { - fcoe_insert_wait_queue_head(lp, skb); - return rc; + struct fip_header *fiph; + struct fip_desc *desc = NULL; + struct fip_wwn_desc *wwn; + struct fip_fab_desc *fab; + struct fip_fka_desc *fka; + unsigned long t; + size_t rlen; + size_t dlen; + + memset(fcf, 0, sizeof(*fcf)); + fcf->fka_period = msecs_to_jiffies(FCOE_CTLR_DEF_FKA); + + fiph = (struct fip_header *)skb->data; + fcf->flags = ntohs(fiph->fip_flags); + + rlen = ntohs(fiph->fip_dl_len) * 4; + if (rlen + sizeof(*fiph) > skb->len) + return -EINVAL; + + desc = (struct fip_desc *)(fiph + 1); + while (rlen > 0) { + dlen = desc->fip_dlen * FIP_BPW; + if (dlen < sizeof(*desc) || dlen > rlen) + return -EINVAL; + switch (desc->fip_dtype) { + case FIP_DT_PRI: + if (dlen != sizeof(struct fip_pri_desc)) + goto len_err; + fcf->pri = ((struct fip_pri_desc *)desc)->fd_pri; + break; + case FIP_DT_MAC: + if (dlen != sizeof(struct fip_mac_desc)) + goto len_err; + memcpy(fcf->fcf_mac, + ((struct fip_mac_desc *)desc)->fd_mac, + ETH_ALEN); + if (!is_valid_ether_addr(fcf->fcf_mac)) { + FIP_DBG("invalid MAC addr in FIP adv\n"); + return -EINVAL; } - spin_lock_bh(&fc->fcoe_pending_queue.lock); + break; + case FIP_DT_NAME: + if (dlen != sizeof(struct fip_wwn_desc)) + goto len_err; + wwn = (struct fip_wwn_desc *)desc; + fcf->switch_name = get_unaligned_be64(&wwn->fd_wwn); + break; + case FIP_DT_FAB: + if (dlen != sizeof(struct fip_fab_desc)) + goto len_err; + fab = (struct fip_fab_desc *)desc; + fcf->fabric_name = get_unaligned_be64(&fab->fd_wwn); + fcf->vfid = ntohs(fab->fd_vfid); + fcf->fc_map = ntoh24(fab->fd_map); + break; + case FIP_DT_FKA: + if (dlen != sizeof(struct fip_fka_desc)) + goto len_err; + fka = (struct fip_fka_desc *)desc; + t = ntohl(fka->fd_fka_period); + if (t >= FCOE_CTLR_MIN_FKA) + fcf->fka_period = msecs_to_jiffies(t); + break; + case FIP_DT_MAP_OUI: + case FIP_DT_FCOE_SIZE: + case FIP_DT_FLOGI: + case FIP_DT_FDISC: + case FIP_DT_LOGO: + case FIP_DT_ELP: + default: + FIP_DBG("unexpected descriptor type %x in FIP adv\n", + desc->fip_dtype); + /* standard says ignore unknown descriptors >= 128 */ + if (desc->fip_dtype < FIP_DT_VENDOR_BASE) + return -EINVAL; + continue; } - if (fc->fcoe_pending_queue.qlen < FCOE_MAX_QUEUE_DEPTH) - unpause = 1; + desc = (struct fip_desc *)((char *)desc + dlen); + rlen -= dlen; } - spin_unlock_bh(&fc->fcoe_pending_queue.lock); - if ((unpause) && (paused)) - fc_unpause(lp); - return fc->fcoe_pending_queue.qlen; + if (!fcf->fc_map || (fcf->fc_map & 0x10000)) + return -EINVAL; + if (!fcf->switch_name || !fcf->fabric_name) + return -EINVAL; + return 0; + +len_err: + FIP_DBG("FIP length error in descriptor type %x len %zu\n", + desc->fip_dtype, dlen); + return -EINVAL; } /** - * fcoe_insert_wait_queue_head - puts skb to fcoe pending queue head - * @lp: the fc_port for this skb - * @skb: the associated skb to be xmitted - * - * Returns: none - **/ -static void fcoe_insert_wait_queue_head(struct fc_lport *lp, - struct sk_buff *skb) + * fcoe_ctlr_recv_adv() - Handle an incoming advertisement. + * @fip: FCoE controller. + * @skb: Received FIP packet. + */ +static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb) { - struct fcoe_softc *fc; + struct fcoe_fcf *fcf; + struct fcoe_fcf new; + struct fcoe_fcf *found; + unsigned long sol_tov = msecs_to_jiffies(FCOE_CTRL_SOL_TOV); + int first = 0; + int mtu_valid; + + if (fcoe_ctlr_parse_adv(skb, &new)) + return; - fc = fcoe_softc(lp); - spin_lock_bh(&fc->fcoe_pending_queue.lock); - __skb_queue_head(&fc->fcoe_pending_queue, skb); - spin_unlock_bh(&fc->fcoe_pending_queue.lock); -} + spin_lock_bh(&fip->lock); + first = list_empty(&fip->fcfs); + found = NULL; + list_for_each_entry(fcf, &fip->fcfs, list) { + if (fcf->switch_name == new.switch_name && + fcf->fabric_name == new.fabric_name && + fcf->fc_map == new.fc_map && + compare_ether_addr(fcf->fcf_mac, new.fcf_mac) == 0) { + found = fcf; + break; + } + } + if (!found) { + if (fip->fcf_count >= FCOE_CTLR_FCF_LIMIT) + goto out; -/** - * fcoe_insert_wait_queue - put the skb into fcoe pending queue tail - * @lp: the fc_port for this skb - * @skb: the associated skb to be xmitted - * - * Returns: none - **/ -static void fcoe_insert_wait_queue(struct fc_lport *lp, - struct sk_buff *skb) -{ - struct fcoe_softc *fc; + fcf = kmalloc(sizeof(*fcf), GFP_ATOMIC); + if (!fcf) + goto out; - fc = fcoe_softc(lp); - spin_lock_bh(&fc->fcoe_pending_queue.lock); - __skb_queue_tail(&fc->fcoe_pending_queue, skb); - spin_unlock_bh(&fc->fcoe_pending_queue.lock); -} + fip->fcf_count++; + memcpy(fcf, &new, sizeof(new)); + list_add(&fcf->list, &fip->fcfs); + } else { + /* + * Flags in advertisements are ignored once the FCF is + * selected. Flags in unsolicited advertisements are + * ignored after a usable solicited advertisement + * has been received. + */ + if (fcf == fip->sel_fcf) { + fip->ctlr_ka_time -= fcf->fka_period; + fip->ctlr_ka_time += new.fka_period; + if (time_before(fip->ctlr_ka_time, fip->timer.expires)) + mod_timer(&fip->timer, fip->ctlr_ka_time); + } else if (!fcoe_ctlr_fcf_usable(fcf)) + fcf->flags = new.flags; + fcf->fka_period = new.fka_period; + memcpy(fcf->fcf_mac, new.fcf_mac, ETH_ALEN); + } + mtu_valid = fcoe_ctlr_mtu_valid(fcf); + fcf->time = jiffies; + FIP_DBG_LVL(found ? 2 : 1, "%s FCF for fab %llx map %x val %d\n", + found ? "old" : "new", + fcf->fabric_name, fcf->fc_map, mtu_valid); -/** - * fcoe_dev_setup - setup link change notification interface - * - **/ -static void fcoe_dev_setup(void) -{ /* - * here setup a interface specific wd time to - * monitor the link state + * If this advertisement is not solicited and our max receive size + * hasn't been verified, send a solicited advertisement. */ - register_netdevice_notifier(&fcoe_notifier); -} + if (!mtu_valid) + fcoe_ctlr_solicit(fip, fcf); -/** - * fcoe_dev_setup - cleanup link change notification interface - **/ -static void fcoe_dev_cleanup(void) -{ - unregister_netdevice_notifier(&fcoe_notifier); + /* + * If its been a while since we did a solicit, and this is + * the first advertisement we've received, do a multicast + * solicitation to gather as many advertisements as we can + * before selection occurs. + */ + if (first && time_after(jiffies, fip->sol_time + sol_tov)) + fcoe_ctlr_solicit(fip, NULL); + + /* + * If this is the first validated FCF, note the time and + * set a timer to trigger selection. + */ + if (mtu_valid && !fip->sel_time && fcoe_ctlr_fcf_usable(fcf)) { + fip->sel_time = jiffies + + msecs_to_jiffies(FCOE_CTLR_START_DELAY); + if (!timer_pending(&fip->timer) || + time_before(fip->sel_time, fip->timer.expires)) + mod_timer(&fip->timer, fip->sel_time); + } +out: + spin_unlock_bh(&fip->lock); } /** - * fcoe_device_notification - netdev event notification callback - * @notifier: context of the notification - * @event: type of event - * @ptr: fixed array for output parsed ifname - * - * This function is called by the ethernet driver in case of link change event - * - * Returns: 0 for success - **/ -static int fcoe_device_notification(struct notifier_block *notifier, - ulong event, void *ptr) + * fcoe_ctlr_recv_els() - Handle an incoming FIP-encapsulated ELS frame. + * @fip: FCoE controller. + * @skb: Received FIP packet. + */ +static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb) { - struct fc_lport *lp = NULL; - struct net_device *real_dev = ptr; - struct fcoe_softc *fc; + struct fc_lport *lp = fip->lp; + struct fip_header *fiph; + struct fc_frame *fp; + struct fc_frame_header *fh = NULL; + struct fip_desc *desc; + struct fip_encaps *els; struct fcoe_dev_stats *stats; - u16 new_status; - u32 mfs; - int rc = NOTIFY_OK; - - read_lock(&fcoe_hostlist_lock); - list_for_each_entry(fc, &fcoe_hostlist, list) { - if (fc->real_dev == real_dev) { - lp = fc->lp; + enum fip_desc_type els_dtype = 0; + u8 els_op; + u8 sub; + u8 granted_mac[ETH_ALEN] = { 0 }; + size_t els_len = 0; + size_t rlen; + size_t dlen; + + fiph = (struct fip_header *)skb->data; + sub = fiph->fip_subcode; + if (sub != FIP_SC_REQ && sub != FIP_SC_REP) + goto drop; + + rlen = ntohs(fiph->fip_dl_len) * 4; + if (rlen + sizeof(*fiph) > skb->len) + goto drop; + + desc = (struct fip_desc *)(fiph + 1); + while (rlen > 0) { + dlen = desc->fip_dlen * FIP_BPW; + if (dlen < sizeof(*desc) || dlen > rlen) + goto drop; + switch (desc->fip_dtype) { + case FIP_DT_MAC: + if (dlen != sizeof(struct fip_mac_desc)) + goto len_err; + memcpy(granted_mac, + ((struct fip_mac_desc *)desc)->fd_mac, + ETH_ALEN); + if (!is_valid_ether_addr(granted_mac)) { + FIP_DBG("invalid MAC addrs in FIP ELS\n"); + goto drop; + } + break; + case FIP_DT_FLOGI: + case FIP_DT_FDISC: + case FIP_DT_LOGO: + case FIP_DT_ELP: + if (fh) + goto drop; + if (dlen < sizeof(*els) + sizeof(*fh) + 1) + goto len_err; + els_len = dlen - sizeof(*els); + els = (struct fip_encaps *)desc; + fh = (struct fc_frame_header *)(els + 1); + els_dtype = desc->fip_dtype; break; + default: + FIP_DBG("unexpected descriptor type %x " + "in FIP adv\n", desc->fip_dtype); + /* standard says ignore unknown descriptors >= 128 */ + if (desc->fip_dtype < FIP_DT_VENDOR_BASE) + goto drop; + continue; } - } - read_unlock(&fcoe_hostlist_lock); - if (lp == NULL) { - rc = NOTIFY_DONE; - goto out; + desc = (struct fip_desc *)((char *)desc + dlen); + rlen -= dlen; } - new_status = lp->link_status; - switch (event) { - case NETDEV_DOWN: - case NETDEV_GOING_DOWN: - new_status &= ~FC_LINK_UP; - break; - case NETDEV_UP: - case NETDEV_CHANGE: - new_status &= ~FC_LINK_UP; - if (!fcoe_link_ok(lp)) - new_status |= FC_LINK_UP; - break; - case NETDEV_CHANGEMTU: - mfs = fc->real_dev->mtu - - (sizeof(struct fcoe_hdr) + - sizeof(struct fcoe_crc_eof)); - if (mfs >= FC_MIN_MAX_FRAME) - fc_set_mfs(lp, mfs); - new_status &= ~FC_LINK_UP; - if (!fcoe_link_ok(lp)) - new_status |= FC_LINK_UP; - break; - case NETDEV_REGISTER: - break; - default: - FC_DBG("unknown event %ld call", event); - } - if (lp->link_status != new_status) { - if ((new_status & FC_LINK_UP) == FC_LINK_UP) - fc_linkup(lp); - else { - stats = lp->dev_stats[smp_processor_id()]; - if (stats) - stats->LinkFailureCount++; - fc_linkdown(lp); - fcoe_clean_pending_queue(lp); - } - } -out: - return rc; -} + if (!fh) + goto drop; + els_op = *(u8 *)(fh + 1); -/** - * fcoe_if_to_netdev - parse a name buffer to get netdev - * @ifname: fixed array for output parsed ifname - * @buffer: incoming buffer to be copied - * - * Returns: NULL or ptr to netdeive - **/ -static struct net_device *fcoe_if_to_netdev(const char *buffer) -{ - char *cp; - char ifname[IFNAMSIZ + 2]; - - if (buffer) { - strlcpy(ifname, buffer, IFNAMSIZ); - cp = ifname + strlen(ifname); - while (--cp >= ifname && *cp == '\n') - *cp = '\0'; - return dev_get_by_name(&init_net, ifname); + if (els_dtype == FIP_DT_FLOGI && sub == FIP_SC_REP && + fip->flogi_oxid == ntohs(fh->fh_ox_id) && + els_op == ELS_LS_ACC && is_valid_ether_addr(granted_mac)) { + fip->flogi_oxid = FC_XID_UNKNOWN; + fip->update_mac(fip, fip->data_src_addr, granted_mac); + memcpy(fip->data_src_addr, granted_mac, ETH_ALEN); } - return NULL; + + /* + * Convert skb into an fc_frame containing only the ELS. + */ + skb_pull(skb, (u8 *)fh - skb->data); + skb_trim(skb, els_len); + fp = (struct fc_frame *)skb; + fc_frame_init(fp); + fr_sof(fp) = FC_SOF_I3; + fr_eof(fp) = FC_EOF_T; + fr_dev(fp) = lp; + + stats = fc_lport_get_stats(lp); + stats->RxFrames++; + stats->RxWords += skb->len / FIP_BPW; + + fc_exch_recv(lp, lp->emp, fp); + return; + +len_err: + FIP_DBG("FIP length error in descriptor type %x len %zu\n", + desc->fip_dtype, dlen); +drop: + kfree_skb(skb); } /** - * fcoe_netdev_to_module_owner - finds out the nic drive moddule of the netdev - * @netdev: the target netdev + * fcoe_ctlr_recv_els() - Handle an incoming link reset frame. + * @fip: FCoE controller. + * @fh: Received FIP header. * - * Returns: ptr to the struct module, NULL for failure - **/ -static struct module *fcoe_netdev_to_module_owner( - const struct net_device *netdev) + * There may be multiple VN_Port descriptors. + * The overall length has already been checked. + */ +static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip, + struct fip_header *fh) { - struct device *dev; - - if (!netdev) - return NULL; - - dev = netdev->dev.parent; - if (!dev) - return NULL; + struct fip_desc *desc; + struct fip_mac_desc *mp; + struct fip_wwn_desc *wp; + struct fip_vn_desc *vp; + size_t rlen; + size_t dlen; + struct fcoe_fcf *fcf = fip->sel_fcf; + struct fc_lport *lp = fip->lp; + u32 desc_mask; + + FIP_DBG("Clear Virtual Link received\n"); + if (!fcf) + return; + if (!fcf || !fc_host_port_id(lp->host)) + return; - if (!dev->driver) - return NULL; + /* + * mask of required descriptors. Validating each one clears its bit. + */ + desc_mask = BIT(FIP_DT_MAC) | BIT(FIP_DT_NAME) | BIT(FIP_DT_VN_ID); + + rlen = ntohs(fh->fip_dl_len) * FIP_BPW; + desc = (struct fip_desc *)(fh + 1); + while (rlen >= sizeof(*desc)) { + dlen = desc->fip_dlen * FIP_BPW; + if (dlen > rlen) + return; + switch (desc->fip_dtype) { + case FIP_DT_MAC: + mp = (struct fip_mac_desc *)desc; + if (dlen < sizeof(*mp)) + return; + if (compare_ether_addr(mp->fd_mac, fcf->fcf_mac)) + return; + desc_mask &= ~BIT(FIP_DT_MAC); + break; + case FIP_DT_NAME: + wp = (struct fip_wwn_desc *)desc; + if (dlen < sizeof(*wp)) + return; + if (get_unaligned_be64(&wp->fd_wwn) != fcf->switch_name) + return; + desc_mask &= ~BIT(FIP_DT_NAME); + break; + case FIP_DT_VN_ID: + vp = (struct fip_vn_desc *)desc; + if (dlen < sizeof(*vp)) + return; + if (compare_ether_addr(vp->fd_mac, + fip->data_src_addr) == 0 && + get_unaligned_be64(&vp->fd_wwpn) == lp->wwpn && + ntoh24(vp->fd_fc_id) == fc_host_port_id(lp->host)) + desc_mask &= ~BIT(FIP_DT_VN_ID); + break; + default: + /* standard says ignore unknown descriptors >= 128 */ + if (desc->fip_dtype < FIP_DT_VENDOR_BASE) + return; + break; + } + desc = (struct fip_desc *)((char *)desc + dlen); + rlen -= dlen; + } - return dev->driver->owner; + /* + * reset only if all required descriptors were present and valid. + */ + if (desc_mask) { + FIP_DBG("missing descriptors mask %x\n", desc_mask); + } else { + FIP_DBG("performing Clear Virtual Link\n"); + fcoe_ctlr_reset(fip, FIP_ST_ENABLED); + } } /** - * fcoe_ethdrv_get - holds the nic driver module by try_module_get() for - * the corresponding netdev. - * @netdev: the target netdev + * fcoe_ctlr_recv() - Receive a FIP frame. + * @fip: FCoE controller. + * @skb: Received FIP packet. * - * Returns: 0 for succsss - **/ -static int fcoe_ethdrv_get(const struct net_device *netdev) + * This is called from NET_RX_SOFTIRQ. + */ +void fcoe_ctlr_recv(struct fcoe_ctlr *fip, struct sk_buff *skb) { - struct module *owner; - - owner = fcoe_netdev_to_module_owner(netdev); - if (owner) { - printk(KERN_DEBUG "fcoe:hold driver module %s for %s\n", - module_name(owner), netdev->name); - return try_module_get(owner); - } - return -ENODEV; + spin_lock_bh(&fip->fip_recv_list.lock); + __skb_queue_tail(&fip->fip_recv_list, skb); + spin_unlock_bh(&fip->fip_recv_list.lock); + schedule_work(&fip->recv_work); } +EXPORT_SYMBOL(fcoe_ctlr_recv); /** - * fcoe_ethdrv_get - releases the nic driver module by module_put for - * the corresponding netdev. - * @netdev: the target netdev + * fcoe_ctlr_recv_handler() - Receive a FIP frame. + * @fip: FCoE controller. + * @skb: Received FIP packet. * - * Returns: 0 for succsss - **/ -static int fcoe_ethdrv_put(const struct net_device *netdev) + * Returns non-zero if the frame is dropped. + */ +static int fcoe_ctlr_recv_handler(struct fcoe_ctlr *fip, struct sk_buff *skb) { - struct module *owner; + struct fip_header *fiph; + struct ethhdr *eh; + enum fip_state state; + u16 op; + u8 sub; + + if (skb_linearize(skb)) + goto drop; + if (skb->len < sizeof(*fiph)) + goto drop; + eh = eth_hdr(skb); + if (compare_ether_addr(eh->h_dest, fip->ctl_src_addr) && + compare_ether_addr(eh->h_dest, FIP_ALL_ENODE_MACS)) + goto drop; + fiph = (struct fip_header *)skb->data; + op = ntohs(fiph->fip_op); + sub = fiph->fip_subcode; + + FIP_DBG_LVL(2, "ver %x op %x/%x dl %x fl %x\n", + FIP_VER_DECAPS(fiph->fip_ver), op, sub, + ntohs(fiph->fip_dl_len), ntohs(fiph->fip_flags)); + + if (FIP_VER_DECAPS(fiph->fip_ver) != FIP_VER) + goto drop; + if (ntohs(fiph->fip_dl_len) * FIP_BPW + sizeof(*fiph) > skb->len) + goto drop; + + spin_lock_bh(&fip->lock); + state = fip->state; + if (state == FIP_ST_AUTO) { + fip->map_dest = 0; + fip->state = FIP_ST_ENABLED; + state = FIP_ST_ENABLED; + FIP_DBG("using FIP mode\n"); + } + spin_unlock_bh(&fip->lock); + if (state != FIP_ST_ENABLED) + goto drop; - owner = fcoe_netdev_to_module_owner(netdev); - if (owner) { - printk(KERN_DEBUG "fcoe:release driver module %s for %s\n", - module_name(owner), netdev->name); - module_put(owner); + if (op == FIP_OP_LS) { + fcoe_ctlr_recv_els(fip, skb); /* consumes skb */ return 0; } - return -ENODEV; + if (op == FIP_OP_DISC && sub == FIP_SC_ADV) + fcoe_ctlr_recv_adv(fip, skb); + else if (op == FIP_OP_CTRL && sub == FIP_SC_CLR_VLINK) + fcoe_ctlr_recv_clr_vlink(fip, fiph); + kfree_skb(skb); + return 0; +drop: + kfree_skb(skb); + return -1; } /** - * fcoe_destroy- handles the destroy from sysfs - * @buffer: expcted to be a eth if name - * @kp: associated kernel param + * fcoe_ctlr_select() - Select the best FCF, if possible. + * @fip: FCoE controller. + * + * If there are conflicting advertisements, no FCF can be chosen. * - * Returns: 0 for success - **/ -static int fcoe_destroy(const char *buffer, struct kernel_param *kp) + * Called with lock held. + */ +static void fcoe_ctlr_select(struct fcoe_ctlr *fip) { - int rc; - struct net_device *netdev; - - netdev = fcoe_if_to_netdev(buffer); - if (!netdev) { - rc = -ENODEV; - goto out_nodev; - } - /* look for existing lport */ - if (!fcoe_hostlist_lookup(netdev)) { - rc = -ENODEV; - goto out_putdev; - } - /* pass to transport */ - rc = fcoe_transport_release(netdev); - if (rc) { - printk(KERN_ERR "fcoe: fcoe_transport_release(%s) failed\n", - netdev->name); - rc = -EIO; - goto out_putdev; + struct fcoe_fcf *fcf; + struct fcoe_fcf *best = NULL; + + list_for_each_entry(fcf, &fip->fcfs, list) { + FIP_DBG("consider FCF for fab %llx VFID %d map %x val %d\n", + fcf->fabric_name, fcf->vfid, + fcf->fc_map, fcoe_ctlr_mtu_valid(fcf)); + if (!fcoe_ctlr_fcf_usable(fcf)) { + FIP_DBG("FCF for fab %llx map %x %svalid %savailable\n", + fcf->fabric_name, fcf->fc_map, + (fcf->flags & FIP_FL_SOL) ? "" : "in", + (fcf->flags & FIP_FL_AVAIL) ? "" : "un"); + continue; + } + if (!best) { + best = fcf; + continue; + } + if (fcf->fabric_name != best->fabric_name || + fcf->vfid != best->vfid || + fcf->fc_map != best->fc_map) { + FIP_DBG("conflicting fabric, VFID, or FC-MAP\n"); + return; + } + if (fcf->pri < best->pri) + best = fcf; } - fcoe_ethdrv_put(netdev); - rc = 0; -out_putdev: - dev_put(netdev); -out_nodev: - return rc; + fip->sel_fcf = best; } /** - * fcoe_create - handles the create call from sysfs - * @buffer: expcted to be a eth if name - * @kp: associated kernel param + * fcoe_ctlr_timeout() - FIP timer function. + * @arg: &fcoe_ctlr pointer. * - * Returns: 0 for success - **/ -static int fcoe_create(const char *buffer, struct kernel_param *kp) + * Ages FCFs. Triggers FCF selection if possible. Sends keep-alives. + */ +static void fcoe_ctlr_timeout(unsigned long arg) { - int rc; - struct net_device *netdev; - - netdev = fcoe_if_to_netdev(buffer); - if (!netdev) { - rc = -ENODEV; - goto out_nodev; + struct fcoe_ctlr *fip = (struct fcoe_ctlr *)arg; + struct fcoe_fcf *sel; + struct fcoe_fcf *fcf; + unsigned long next_timer = jiffies + msecs_to_jiffies(FIP_VN_KA_PERIOD); + DECLARE_MAC_BUF(buf); + u8 send_ctlr_ka; + u8 send_port_ka; + + spin_lock_bh(&fip->lock); + if (fip->state == FIP_ST_DISABLED) { + spin_unlock_bh(&fip->lock); + return; } - /* look for existing lport */ - if (fcoe_hostlist_lookup(netdev)) { - rc = -EEXIST; - goto out_putdev; + + fcf = fip->sel_fcf; + fcoe_ctlr_age_fcfs(fip); + + sel = fip->sel_fcf; + if (!sel && fip->sel_time && time_after_eq(jiffies, fip->sel_time)) { + fcoe_ctlr_select(fip); + sel = fip->sel_fcf; + fip->sel_time = 0; } - fcoe_ethdrv_get(netdev); - - /* pass to transport */ - rc = fcoe_transport_attach(netdev); - if (rc) { - printk(KERN_ERR "fcoe: fcoe_transport_attach(%s) failed\n", - netdev->name); - fcoe_ethdrv_put(netdev); - rc = -EIO; - goto out_putdev; + + if (sel != fcf) { + fcf = sel; /* the old FCF may have been freed */ + if (sel) { + printk(KERN_INFO "host%d: FIP selected " + "Fibre-Channel Forwarder MAC %s\n", + fip->lp->host->host_no, + print_mac(buf, sel->fcf_mac)); + memcpy(fip->dest_addr, sel->fcf_mac, ETH_ALEN); + fip->port_ka_time = jiffies + + msecs_to_jiffies(FIP_VN_KA_PERIOD); + fip->ctlr_ka_time = jiffies + sel->fka_period; + fip->link = 1; + } else { + printk(KERN_NOTICE "host%d: " + "FIP Fibre-Channel Forwarder timed out. " + "Starting FCF discovery.\n", + fip->lp->host->host_no); + fip->link = 0; + } + schedule_work(&fip->link_work); } - rc = 0; -out_putdev: - dev_put(netdev); -out_nodev: - return rc; -} -module_param_call(create, fcoe_create, NULL, NULL, S_IWUSR); -__MODULE_PARM_TYPE(create, "string"); -MODULE_PARM_DESC(create, "Create fcoe port using net device passed in."); -module_param_call(destroy, fcoe_destroy, NULL, NULL, S_IWUSR); -__MODULE_PARM_TYPE(destroy, "string"); -MODULE_PARM_DESC(destroy, "Destroy fcoe port"); + send_ctlr_ka = 0; + send_port_ka = 0; + if (sel) { + if (time_after_eq(jiffies, fip->ctlr_ka_time)) { + fip->ctlr_ka_time = jiffies + sel->fka_period; + send_ctlr_ka = 1; + } + if (time_after(next_timer, fip->ctlr_ka_time)) + next_timer = fip->ctlr_ka_time; -/* - * fcoe_link_ok - check if link is ok for the fc_lport - * @lp: ptr to the fc_lport - * - * Any permanently-disqualifying conditions have been previously checked. - * This also updates the speed setting, which may change with link for 100/1000. - * - * This function should probably be checking for PAUSE support at some point - * in the future. Currently Per-priority-pause is not determinable using - * ethtool, so we shouldn't be restrictive until that problem is resolved. - * - * Returns: 0 if link is OK for use by FCoE. - * - */ -int fcoe_link_ok(struct fc_lport *lp) -{ - struct fcoe_softc *fc = fcoe_softc(lp); - struct net_device *dev = fc->real_dev; - struct ethtool_cmd ecmd = { ETHTOOL_GSET }; - int rc = 0; - - if ((dev->flags & IFF_UP) && netif_carrier_ok(dev)) { - dev = fc->phys_dev; - if (dev->ethtool_ops->get_settings) { - dev->ethtool_ops->get_settings(dev, &ecmd); - lp->link_supported_speeds &= - ~(FC_PORTSPEED_1GBIT | FC_PORTSPEED_10GBIT); - if (ecmd.supported & (SUPPORTED_1000baseT_Half | - SUPPORTED_1000baseT_Full)) - lp->link_supported_speeds |= FC_PORTSPEED_1GBIT; - if (ecmd.supported & SUPPORTED_10000baseT_Full) - lp->link_supported_speeds |= - FC_PORTSPEED_10GBIT; - if (ecmd.speed == SPEED_1000) - lp->link_speed = FC_PORTSPEED_1GBIT; - if (ecmd.speed == SPEED_10000) - lp->link_speed = FC_PORTSPEED_10GBIT; + if (time_after_eq(jiffies, fip->port_ka_time)) { + fip->port_ka_time += jiffies + + msecs_to_jiffies(FIP_VN_KA_PERIOD); + send_port_ka = 1; } - } else - rc = -1; + if (time_after(next_timer, fip->port_ka_time)) + next_timer = fip->port_ka_time; + mod_timer(&fip->timer, next_timer); + } else if (fip->sel_time) { + next_timer = fip->sel_time + + msecs_to_jiffies(FCOE_CTLR_START_DELAY); + mod_timer(&fip->timer, next_timer); + } + spin_unlock_bh(&fip->lock); - return rc; + if (send_ctlr_ka) + fcoe_ctlr_send_keep_alive(fip, 0, fip->ctl_src_addr); + if (send_port_ka) + fcoe_ctlr_send_keep_alive(fip, 1, fip->data_src_addr); } -EXPORT_SYMBOL_GPL(fcoe_link_ok); -/* - * fcoe_percpu_clean - frees skb of the corresponding lport from the per - * cpu queue. - * @lp: the fc_lport +/** + * fcoe_ctlr_link_work() - worker thread function for link changes. + * @work: pointer to link_work member inside &fcoe_ctlr. + * + * See if the link status has changed and if so, report it. + * + * This is here because fc_linkup() and fc_linkdown() must not + * be called from the timer directly, since they use a mutex. */ -void fcoe_percpu_clean(struct fc_lport *lp) +static void fcoe_ctlr_link_work(struct work_struct *work) { - int idx; - struct fcoe_percpu_s *pp; - struct fcoe_rcv_info *fr; - struct sk_buff_head *list; - struct sk_buff *skb, *next; - struct sk_buff *head; - - for (idx = 0; idx < NR_CPUS; idx++) { - if (fcoe_percpu[idx]) { - pp = fcoe_percpu[idx]; - spin_lock_bh(&pp->fcoe_rx_list.lock); - list = &pp->fcoe_rx_list; - head = list->next; - for (skb = head; skb != (struct sk_buff *)list; - skb = next) { - next = skb->next; - fr = fcoe_dev_from_skb(skb); - if (fr->fr_dev == lp) { - __skb_unlink(skb, list); - kfree_skb(skb); - } - } - spin_unlock_bh(&pp->fcoe_rx_list.lock); - } + struct fcoe_ctlr *fip; + int link; + int last_link; + + fip = container_of(work, struct fcoe_ctlr, link_work); + spin_lock_bh(&fip->lock); + last_link = fip->last_link; + link = fip->link; + fip->last_link = link; + spin_unlock_bh(&fip->lock); + + if (last_link != link) { + if (link) + fc_linkup(fip->lp); + else + fcoe_ctlr_reset(fip, FIP_ST_LINK_WAIT); } } -EXPORT_SYMBOL_GPL(fcoe_percpu_clean); /** - * fcoe_clean_pending_queue - dequeue skb and free it - * @lp: the corresponding fc_lport - * - * Returns: none - **/ -void fcoe_clean_pending_queue(struct fc_lport *lp) + * fcoe_ctlr_recv_work() - Worker thread function for receiving FIP frames. + * @recv_work: pointer to recv_work member inside &fcoe_ctlr. + */ +static void fcoe_ctlr_recv_work(struct work_struct *recv_work) { - struct fcoe_softc *fc = lport_priv(lp); + struct fcoe_ctlr *fip; struct sk_buff *skb; - spin_lock_bh(&fc->fcoe_pending_queue.lock); - while ((skb = __skb_dequeue(&fc->fcoe_pending_queue)) != NULL) { - spin_unlock_bh(&fc->fcoe_pending_queue.lock); - kfree_skb(skb); - spin_lock_bh(&fc->fcoe_pending_queue.lock); + fip = container_of(recv_work, struct fcoe_ctlr, recv_work); + spin_lock_bh(&fip->fip_recv_list.lock); + while ((skb = __skb_dequeue(&fip->fip_recv_list))) { + spin_unlock_bh(&fip->fip_recv_list.lock); + fcoe_ctlr_recv_handler(fip, skb); + spin_lock_bh(&fip->fip_recv_list.lock); } - spin_unlock_bh(&fc->fcoe_pending_queue.lock); + spin_unlock_bh(&fip->fip_recv_list.lock); } -EXPORT_SYMBOL_GPL(fcoe_clean_pending_queue); /** - * libfc_host_alloc - allocate a Scsi_Host with room for the fc_lport - * @sht: ptr to the scsi host templ - * @priv_size: size of private data after fc_lport + * fcoe_ctlr_recv_flogi() - snoop Pre-FIP receipt of FLOGI response or request. + * @fip: FCoE controller. + * @fp: FC frame. + * @sa: Ethernet source MAC address from received FCoE frame. * - * Returns: ptr to Scsi_Host - * TODO - to libfc? - */ -static inline struct Scsi_Host *libfc_host_alloc( - struct scsi_host_template *sht, int priv_size) -{ - return scsi_host_alloc(sht, sizeof(struct fc_lport) + priv_size); -} - -/** - * fcoe_host_alloc - allocate a Scsi_Host with room for the fcoe_softc - * @sht: ptr to the scsi host templ - * @priv_size: size of private data after fc_lport + * Snoop potential response to FLOGI or even incoming FLOGI. * - * Returns: ptr to Scsi_Host - */ -struct Scsi_Host *fcoe_host_alloc(struct scsi_host_template *sht, int priv_size) -{ - return libfc_host_alloc(sht, sizeof(struct fcoe_softc) + priv_size); -} -EXPORT_SYMBOL_GPL(fcoe_host_alloc); - -/* - * fcoe_reset - resets the fcoe - * @shost: shost the reset is from + * The caller has checked that we are waiting for login as indicated + * by fip->flogi_oxid != FC_XID_UNKNOWN. + * + * The caller is responsible for freeing the frame. * - * Returns: always 0 + * Return non-zero if the frame should not be delivered to libfc. */ -int fcoe_reset(struct Scsi_Host *shost) +int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *fip, struct fc_frame *fp, u8 *sa) { - struct fc_lport *lport = shost_priv(shost); - fc_lport_reset(lport); + struct fc_frame_header *fh; + u8 op; + u8 mac[ETH_ALEN]; + + fh = fc_frame_header_get(fp); + if (fh->fh_type != FC_TYPE_ELS) + return 0; + + op = fc_frame_payload_op(fp); + if (op == ELS_LS_ACC && fh->fh_r_ctl == FC_RCTL_ELS_REP && + fip->flogi_oxid == ntohs(fh->fh_ox_id)) { + + spin_lock_bh(&fip->lock); + if (fip->state != FIP_ST_AUTO && fip->state != FIP_ST_NON_FIP) { + spin_unlock_bh(&fip->lock); + return -EINVAL; + } + fip->state = FIP_ST_NON_FIP; + FIP_DBG("received FLOGI LS_ACC using non-FIP mode\n"); + + /* + * FLOGI accepted. + * If the src mac addr is FC_OUI-based, then we mark the + * address_mode flag to use FC_OUI-based Ethernet DA. + * Otherwise we use the FCoE gateway addr + */ + if (!compare_ether_addr(sa, (u8[6])FC_FCOE_FLOGI_MAC)) { + fip->map_dest = 1; + } else { + memcpy(fip->dest_addr, sa, ETH_ALEN); + fip->map_dest = 0; + } + fip->flogi_oxid = FC_XID_UNKNOWN; + memcpy(mac, fip->data_src_addr, ETH_ALEN); + fc_fcoe_set_mac(fip->data_src_addr, fh->fh_d_id); + spin_unlock_bh(&fip->lock); + + fip->update_mac(fip, mac, fip->data_src_addr); + } else if (op == ELS_FLOGI && fh->fh_r_ctl == FC_RCTL_ELS_REQ && sa) { + /* + * Save source MAC for point-to-point responses. + */ + spin_lock_bh(&fip->lock); + if (fip->state == FIP_ST_AUTO || fip->state == FIP_ST_NON_FIP) { + memcpy(fip->dest_addr, sa, ETH_ALEN); + fip->map_dest = 0; + if (fip->state == FIP_ST_NON_FIP) + FIP_DBG("received FLOGI REQ, " + "using non-FIP mode\n"); + fip->state = FIP_ST_NON_FIP; + } + spin_unlock_bh(&fip->lock); + } return 0; } -EXPORT_SYMBOL_GPL(fcoe_reset); +EXPORT_SYMBOL(fcoe_ctlr_recv_flogi); -/* - * fcoe_wwn_from_mac - converts 48-bit IEEE MAC address to 64-bit FC WWN. +/** + * fcoe_wwn_from_mac() - Converts 48-bit IEEE MAC address to 64-bit FC WWN. * @mac: mac address * @scheme: check port * @port: port indicator for converting @@ -1286,92 +1313,14 @@ u64 fcoe_wwn_from_mac(unsigned char mac[MAX_ADDR_LEN], return wwn; } EXPORT_SYMBOL_GPL(fcoe_wwn_from_mac); -/* - * fcoe_hostlist_lookup_softc - find the corresponding lport by a given device - * @device: this is currently ptr to net_device - * - * Returns: NULL or the located fcoe_softc - */ -static struct fcoe_softc *fcoe_hostlist_lookup_softc( - const struct net_device *dev) -{ - struct fcoe_softc *fc; - - read_lock(&fcoe_hostlist_lock); - list_for_each_entry(fc, &fcoe_hostlist, list) { - if (fc->real_dev == dev) { - read_unlock(&fcoe_hostlist_lock); - return fc; - } - } - read_unlock(&fcoe_hostlist_lock); - return NULL; -} - -/* - * fcoe_hostlist_lookup - find the corresponding lport by netdev - * @netdev: ptr to net_device - * - * Returns: 0 for success - */ -struct fc_lport *fcoe_hostlist_lookup(const struct net_device *netdev) -{ - struct fcoe_softc *fc; - - fc = fcoe_hostlist_lookup_softc(netdev); - - return (fc) ? fc->lp : NULL; -} -EXPORT_SYMBOL_GPL(fcoe_hostlist_lookup); - -/* - * fcoe_hostlist_add - add a lport to lports list - * @lp: ptr to the fc_lport to badded - * - * Returns: 0 for success - */ -int fcoe_hostlist_add(const struct fc_lport *lp) -{ - struct fcoe_softc *fc; - - fc = fcoe_hostlist_lookup_softc(fcoe_netdev(lp)); - if (!fc) { - fc = fcoe_softc(lp); - write_lock_bh(&fcoe_hostlist_lock); - list_add_tail(&fc->list, &fcoe_hostlist); - write_unlock_bh(&fcoe_hostlist_lock); - } - return 0; -} -EXPORT_SYMBOL_GPL(fcoe_hostlist_add); - -/* - * fcoe_hostlist_remove - remove a lport from lports list - * @lp: ptr to the fc_lport to badded - * - * Returns: 0 for success - */ -int fcoe_hostlist_remove(const struct fc_lport *lp) -{ - struct fcoe_softc *fc; - - fc = fcoe_hostlist_lookup_softc(fcoe_netdev(lp)); - BUG_ON(!fc); - write_lock_bh(&fcoe_hostlist_lock); - list_del(&fc->list); - write_unlock_bh(&fcoe_hostlist_lock); - - return 0; -} -EXPORT_SYMBOL_GPL(fcoe_hostlist_remove); /** - * fcoe_libfc_config - sets up libfc related properties for lport + * fcoe_libfc_config() - sets up libfc related properties for lport * @lp: ptr to the fc_lport * @tt: libfc function template * * Returns : 0 for success - **/ + */ int fcoe_libfc_config(struct fc_lport *lp, struct libfc_function_template *tt) { /* Set the function pointers set by the LLDD */ @@ -1387,124 +1336,3 @@ int fcoe_libfc_config(struct fc_lport *lp, struct libfc_function_template *tt) return 0; } EXPORT_SYMBOL_GPL(fcoe_libfc_config); - -/** - * fcoe_init - fcoe module loading initialization - * - * Initialization routine - * 1. Will create fc transport software structure - * 2. initialize the link list of port information structure - * - * Returns 0 on success, negative on failure - **/ -static int __init fcoe_init(void) -{ - int cpu; - struct fcoe_percpu_s *p; - - - INIT_LIST_HEAD(&fcoe_hostlist); - rwlock_init(&fcoe_hostlist_lock); - -#ifdef CONFIG_HOTPLUG_CPU - register_cpu_notifier(&fcoe_cpu_notifier); -#endif /* CONFIG_HOTPLUG_CPU */ - - /* - * initialize per CPU interrupt thread - */ - for_each_online_cpu(cpu) { - p = kzalloc(sizeof(struct fcoe_percpu_s), GFP_KERNEL); - if (p) { - p->thread = kthread_create(fcoe_percpu_receive_thread, - (void *)p, - "fcoethread/%d", cpu); - - /* - * if there is no error then bind the thread to the cpu - * initialize the semaphore and skb queue head - */ - if (likely(!IS_ERR(p->thread))) { - p->cpu = cpu; - fcoe_percpu[cpu] = p; - skb_queue_head_init(&p->fcoe_rx_list); - kthread_bind(p->thread, cpu); - wake_up_process(p->thread); - } else { - fcoe_percpu[cpu] = NULL; - kfree(p); - - } - } - } - - /* - * setup link change notification - */ - fcoe_dev_setup(); - - init_timer(&fcoe_timer); - fcoe_timer.data = 0; - fcoe_timer.function = fcoe_watchdog; - fcoe_timer.expires = (jiffies + (10 * HZ)); - add_timer(&fcoe_timer); - - /* initiatlize the fcoe transport */ - fcoe_transport_init(); - - fcoe_sw_init(); - - return 0; -} -module_init(fcoe_init); - -/** - * fcoe_exit - fcoe module unloading cleanup - * - * Returns 0 on success, negative on failure - **/ -static void __exit fcoe_exit(void) -{ - u32 idx; - struct fcoe_softc *fc, *tmp; - struct fcoe_percpu_s *p; - struct sk_buff *skb; - - /* - * Stop all call back interfaces - */ -#ifdef CONFIG_HOTPLUG_CPU - unregister_cpu_notifier(&fcoe_cpu_notifier); -#endif /* CONFIG_HOTPLUG_CPU */ - fcoe_dev_cleanup(); - - /* - * stop timer - */ - del_timer_sync(&fcoe_timer); - - /* releases the assocaited fcoe transport for each lport */ - list_for_each_entry_safe(fc, tmp, &fcoe_hostlist, list) - fcoe_transport_release(fc->real_dev); - - for (idx = 0; idx < NR_CPUS; idx++) { - if (fcoe_percpu[idx]) { - kthread_stop(fcoe_percpu[idx]->thread); - p = fcoe_percpu[idx]; - spin_lock_bh(&p->fcoe_rx_list.lock); - while ((skb = __skb_dequeue(&p->fcoe_rx_list)) != NULL) - kfree_skb(skb); - spin_unlock_bh(&p->fcoe_rx_list.lock); - if (fcoe_percpu[idx]->crc_eof_page) - put_page(fcoe_percpu[idx]->crc_eof_page); - kfree(fcoe_percpu[idx]); - } - } - - /* remove sw trasnport */ - fcoe_sw_exit(); - - /* detach the transport */ - fcoe_transport_exit(); -} -module_exit(fcoe_exit); diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index aa670a1d151..89d41a424b3 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -176,7 +176,6 @@ void scsi_remove_host(struct Scsi_Host *shost) transport_unregister_device(&shost->shost_gendev); device_unregister(&shost->shost_dev); device_del(&shost->shost_gendev); - scsi_proc_hostdir_rm(shost->hostt); } EXPORT_SYMBOL(scsi_remove_host); @@ -270,6 +269,8 @@ static void scsi_host_dev_release(struct device *dev) struct Scsi_Host *shost = dev_to_shost(dev); struct device *parent = dev->parent; + scsi_proc_hostdir_rm(shost->hostt); + if (shost->ehandler) kthread_stop(shost->ehandler); if (shost->work_q) diff --git a/drivers/scsi/hptiop.c b/drivers/scsi/hptiop.c index a48e4990fe1..af1f0af0c5a 100644 --- a/drivers/scsi/hptiop.c +++ b/drivers/scsi/hptiop.c @@ -580,8 +580,7 @@ static void hptiop_finish_scsi_req(struct hptiop_hba *hba, u32 tag, break; default: - scp->result = ((DRIVER_INVALID|SUGGEST_ABORT)<<24) | - (DID_ABORT<<16); + scp->result = DRIVER_INVALID << 24 | DID_ABORT << 16; break; } @@ -1251,6 +1250,7 @@ static struct pci_device_id hptiop_id_table[] = { { PCI_VDEVICE(TTI, 0x3530), (kernel_ulong_t)&hptiop_itl_ops }, { PCI_VDEVICE(TTI, 0x3560), (kernel_ulong_t)&hptiop_itl_ops }, { PCI_VDEVICE(TTI, 0x4322), (kernel_ulong_t)&hptiop_itl_ops }, + { PCI_VDEVICE(TTI, 0x4321), (kernel_ulong_t)&hptiop_itl_ops }, { PCI_VDEVICE(TTI, 0x4210), (kernel_ulong_t)&hptiop_itl_ops }, { PCI_VDEVICE(TTI, 0x4211), (kernel_ulong_t)&hptiop_itl_ops }, { PCI_VDEVICE(TTI, 0x4310), (kernel_ulong_t)&hptiop_itl_ops }, diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index a1a511bdec8..ea4abee7a2a 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c @@ -75,7 +75,7 @@ MODULE_PARM_DESC(max_lun, "Maximum allowed LUN. " module_param_named(max_targets, max_targets, uint, S_IRUGO); MODULE_PARM_DESC(max_targets, "Maximum allowed targets. " "[Default=" __stringify(IBMVFC_MAX_TARGETS) "]"); -module_param_named(disc_threads, disc_threads, uint, S_IRUGO | S_IWUSR); +module_param_named(disc_threads, disc_threads, uint, S_IRUGO); MODULE_PARM_DESC(disc_threads, "Number of device discovery threads to use. " "[Default=" __stringify(IBMVFC_MAX_DISC_THREADS) "]"); module_param_named(debug, ibmvfc_debug, uint, S_IRUGO | S_IWUSR); @@ -640,6 +640,7 @@ static void ibmvfc_release_crq_queue(struct ibmvfc_host *vhost) ibmvfc_dbg(vhost, "Releasing CRQ\n"); free_irq(vdev->irq, vhost); + tasklet_kill(&vhost->tasklet); do { rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address); } while (rc == H_BUSY || H_IS_LONG_BUSY(rc)); @@ -1573,9 +1574,6 @@ static int ibmvfc_queuecommand(struct scsi_cmnd *cmnd, vfc_cmd->resp_len = sizeof(vfc_cmd->rsp); vfc_cmd->cancel_key = (unsigned long)cmnd->device->hostdata; vfc_cmd->tgt_scsi_id = rport->port_id; - if ((rport->supported_classes & FC_COS_CLASS3) && - (fc_host_supported_classes(vhost->host) & FC_COS_CLASS3)) - vfc_cmd->flags = IBMVFC_CLASS_3_ERR; vfc_cmd->iu.xfer_len = scsi_bufflen(cmnd); int_to_scsilun(cmnd->device->lun, &vfc_cmd->iu.lun); memcpy(vfc_cmd->iu.cdb, cmnd->cmnd, cmnd->cmd_len); @@ -2702,6 +2700,25 @@ static struct ibmvfc_crq *ibmvfc_next_crq(struct ibmvfc_host *vhost) static irqreturn_t ibmvfc_interrupt(int irq, void *dev_instance) { struct ibmvfc_host *vhost = (struct ibmvfc_host *)dev_instance; + unsigned long flags; + + spin_lock_irqsave(vhost->host->host_lock, flags); + vio_disable_interrupts(to_vio_dev(vhost->dev)); + tasklet_schedule(&vhost->tasklet); + spin_unlock_irqrestore(vhost->host->host_lock, flags); + return IRQ_HANDLED; +} + +/** + * ibmvfc_tasklet - Interrupt handler tasklet + * @data: ibmvfc host struct + * + * Returns: + * Nothing + **/ +static void ibmvfc_tasklet(void *data) +{ + struct ibmvfc_host *vhost = data; struct vio_dev *vdev = to_vio_dev(vhost->dev); struct ibmvfc_crq *crq; struct ibmvfc_async_crq *async; @@ -2709,7 +2726,6 @@ static irqreturn_t ibmvfc_interrupt(int irq, void *dev_instance) int done = 0; spin_lock_irqsave(vhost->host->host_lock, flags); - vio_disable_interrupts(to_vio_dev(vhost->dev)); while (!done) { /* Pull all the valid messages off the CRQ */ while ((crq = ibmvfc_next_crq(vhost)) != NULL) { @@ -2737,7 +2753,6 @@ static irqreturn_t ibmvfc_interrupt(int irq, void *dev_instance) } spin_unlock_irqrestore(vhost->host->host_lock, flags); - return IRQ_HANDLED; } /** @@ -2770,6 +2785,40 @@ static void ibmvfc_retry_tgt_init(struct ibmvfc_target *tgt, ibmvfc_init_tgt(tgt, job_step); } +/* Defined in FC-LS */ +static const struct { + int code; + int retry; + int logged_in; +} prli_rsp [] = { + { 0, 1, 0 }, + { 1, 0, 1 }, + { 2, 1, 0 }, + { 3, 1, 0 }, + { 4, 0, 0 }, + { 5, 0, 0 }, + { 6, 0, 1 }, + { 7, 0, 0 }, + { 8, 1, 0 }, +}; + +/** + * ibmvfc_get_prli_rsp - Find PRLI response index + * @flags: PRLI response flags + * + **/ +static int ibmvfc_get_prli_rsp(u16 flags) +{ + int i; + int code = (flags & 0x0f00) >> 8; + + for (i = 0; i < ARRAY_SIZE(prli_rsp); i++) + if (prli_rsp[i].code == code) + return i; + + return 0; +} + /** * ibmvfc_tgt_prli_done - Completion handler for Process Login * @evt: ibmvfc event struct @@ -2780,15 +2829,36 @@ static void ibmvfc_tgt_prli_done(struct ibmvfc_event *evt) struct ibmvfc_target *tgt = evt->tgt; struct ibmvfc_host *vhost = evt->vhost; struct ibmvfc_process_login *rsp = &evt->xfer_iu->prli; + struct ibmvfc_prli_svc_parms *parms = &rsp->parms; u32 status = rsp->common.status; + int index; vhost->discovery_threads--; ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); switch (status) { case IBMVFC_MAD_SUCCESS: - tgt_dbg(tgt, "Process Login succeeded\n"); - tgt->need_login = 0; - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_ADD_RPORT); + tgt_dbg(tgt, "Process Login succeeded: %X %02X %04X\n", + parms->type, parms->flags, parms->service_parms); + + if (parms->type == IBMVFC_SCSI_FCP_TYPE) { + index = ibmvfc_get_prli_rsp(parms->flags); + if (prli_rsp[index].logged_in) { + if (parms->flags & IBMVFC_PRLI_EST_IMG_PAIR) { + tgt->need_login = 0; + tgt->ids.roles = 0; + if (parms->service_parms & IBMVFC_PRLI_TARGET_FUNC) + tgt->ids.roles |= FC_PORT_ROLE_FCP_TARGET; + if (parms->service_parms & IBMVFC_PRLI_INITIATOR_FUNC) + tgt->ids.roles |= FC_PORT_ROLE_FCP_INITIATOR; + ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_ADD_RPORT); + } else + ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); + } else if (prli_rsp[index].retry) + ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_prli); + else + ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); + } else + ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); break; case IBMVFC_MAD_DRIVER_FAILED: break; @@ -2877,7 +2947,6 @@ static void ibmvfc_tgt_plogi_done(struct ibmvfc_event *evt) tgt->ids.node_name = wwn_to_u64(rsp->service_parms.node_name); tgt->ids.port_name = wwn_to_u64(rsp->service_parms.port_name); tgt->ids.port_id = tgt->scsi_id; - tgt->ids.roles = FC_PORT_ROLE_FCP_TARGET; memcpy(&tgt->service_parms, &rsp->service_parms, sizeof(tgt->service_parms)); memcpy(&tgt->service_parms_change, &rsp->service_parms_change, @@ -3054,6 +3123,7 @@ static void ibmvfc_tgt_adisc_done(struct ibmvfc_event *evt) vhost->discovery_threads--; ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); + del_timer(&tgt->timer); switch (status) { case IBMVFC_MAD_SUCCESS: @@ -3110,9 +3180,89 @@ static void ibmvfc_init_passthru(struct ibmvfc_event *evt) } /** + * ibmvfc_tgt_adisc_cancel_done - Completion handler when cancelling an ADISC + * @evt: ibmvfc event struct + * + * Just cleanup this event struct. Everything else is handled by + * the ADISC completion handler. If the ADISC never actually comes + * back, we still have the timer running on the ADISC event struct + * which will fire and cause the CRQ to get reset. + * + **/ +static void ibmvfc_tgt_adisc_cancel_done(struct ibmvfc_event *evt) +{ + struct ibmvfc_host *vhost = evt->vhost; + struct ibmvfc_target *tgt = evt->tgt; + + tgt_dbg(tgt, "ADISC cancel complete\n"); + vhost->abort_threads--; + ibmvfc_free_event(evt); + kref_put(&tgt->kref, ibmvfc_release_tgt); + wake_up(&vhost->work_wait_q); +} + +/** + * ibmvfc_adisc_timeout - Handle an ADISC timeout + * @tgt: ibmvfc target struct + * + * If an ADISC times out, send a cancel. If the cancel times + * out, reset the CRQ. When the ADISC comes back as cancelled, + * log back into the target. + **/ +static void ibmvfc_adisc_timeout(struct ibmvfc_target *tgt) +{ + struct ibmvfc_host *vhost = tgt->vhost; + struct ibmvfc_event *evt; + struct ibmvfc_tmf *tmf; + unsigned long flags; + int rc; + + tgt_dbg(tgt, "ADISC timeout\n"); + spin_lock_irqsave(vhost->host->host_lock, flags); + if (vhost->abort_threads >= disc_threads || + tgt->action != IBMVFC_TGT_ACTION_INIT_WAIT || + vhost->state != IBMVFC_INITIALIZING || + vhost->action != IBMVFC_HOST_ACTION_QUERY_TGTS) { + spin_unlock_irqrestore(vhost->host->host_lock, flags); + return; + } + + vhost->abort_threads++; + kref_get(&tgt->kref); + evt = ibmvfc_get_event(vhost); + ibmvfc_init_event(evt, ibmvfc_tgt_adisc_cancel_done, IBMVFC_MAD_FORMAT); + + evt->tgt = tgt; + tmf = &evt->iu.tmf; + memset(tmf, 0, sizeof(*tmf)); + tmf->common.version = 1; + tmf->common.opcode = IBMVFC_TMF_MAD; + tmf->common.length = sizeof(*tmf); + tmf->scsi_id = tgt->scsi_id; + tmf->cancel_key = tgt->cancel_key; + + rc = ibmvfc_send_event(evt, vhost, default_timeout); + + if (rc) { + tgt_err(tgt, "Failed to send cancel event for ADISC. rc=%d\n", rc); + vhost->abort_threads--; + kref_put(&tgt->kref, ibmvfc_release_tgt); + __ibmvfc_reset_host(vhost); + } else + tgt_dbg(tgt, "Attempting to cancel ADISC\n"); + spin_unlock_irqrestore(vhost->host->host_lock, flags); +} + +/** * ibmvfc_tgt_adisc - Initiate an ADISC for specified target * @tgt: ibmvfc target struct * + * When sending an ADISC we end up with two timers running. The + * first timer is the timer in the ibmvfc target struct. If this + * fires, we send a cancel to the target. The second timer is the + * timer on the ibmvfc event for the ADISC, which is longer. If that + * fires, it means the ADISC timed out and our attempt to cancel it + * also failed, so we need to reset the CRQ. **/ static void ibmvfc_tgt_adisc(struct ibmvfc_target *tgt) { @@ -3133,6 +3283,7 @@ static void ibmvfc_tgt_adisc(struct ibmvfc_target *tgt) mad = &evt->iu.passthru; mad->iu.flags = IBMVFC_FC_ELS; mad->iu.scsi_id = tgt->scsi_id; + mad->iu.cancel_key = tgt->cancel_key; mad->fc_iu.payload[0] = IBMVFC_ADISC; memcpy(&mad->fc_iu.payload[2], &vhost->login_buf->resp.port_name, @@ -3141,9 +3292,19 @@ static void ibmvfc_tgt_adisc(struct ibmvfc_target *tgt) sizeof(vhost->login_buf->resp.node_name)); mad->fc_iu.payload[6] = vhost->login_buf->resp.scsi_id & 0x00ffffff; + if (timer_pending(&tgt->timer)) + mod_timer(&tgt->timer, jiffies + (IBMVFC_ADISC_TIMEOUT * HZ)); + else { + tgt->timer.data = (unsigned long) tgt; + tgt->timer.expires = jiffies + (IBMVFC_ADISC_TIMEOUT * HZ); + tgt->timer.function = (void (*)(unsigned long))ibmvfc_adisc_timeout; + add_timer(&tgt->timer); + } + ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT_WAIT); - if (ibmvfc_send_event(evt, vhost, default_timeout)) { + if (ibmvfc_send_event(evt, vhost, IBMVFC_ADISC_PLUS_CANCEL_TIMEOUT)) { vhost->discovery_threads--; + del_timer(&tgt->timer); ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); kref_put(&tgt->kref, ibmvfc_release_tgt); } else @@ -3266,10 +3427,13 @@ static int ibmvfc_alloc_target(struct ibmvfc_host *vhost, u64 scsi_id) return -ENOMEM; } + memset(tgt, 0, sizeof(*tgt)); tgt->scsi_id = scsi_id; tgt->new_scsi_id = scsi_id; tgt->vhost = vhost; tgt->need_login = 1; + tgt->cancel_key = vhost->task_set++; + init_timer(&tgt->timer); kref_init(&tgt->kref); ibmvfc_init_tgt(tgt, ibmvfc_tgt_implicit_logout); spin_lock_irqsave(vhost->host->host_lock, flags); @@ -3576,9 +3740,18 @@ static void ibmvfc_log_ae(struct ibmvfc_host *vhost, int events) static void ibmvfc_tgt_add_rport(struct ibmvfc_target *tgt) { struct ibmvfc_host *vhost = tgt->vhost; - struct fc_rport *rport; + struct fc_rport *rport = tgt->rport; unsigned long flags; + if (rport) { + tgt_dbg(tgt, "Setting rport roles\n"); + fc_remote_port_rolechg(rport, tgt->ids.roles); + spin_lock_irqsave(vhost->host->host_lock, flags); + ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); + spin_unlock_irqrestore(vhost->host->host_lock, flags); + return; + } + tgt_dbg(tgt, "Adding rport\n"); rport = fc_remote_port_add(vhost->host, 0, &tgt->ids); spin_lock_irqsave(vhost->host->host_lock, flags); @@ -3655,6 +3828,7 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost) spin_unlock_irqrestore(vhost->host->host_lock, flags); if (rport) fc_remote_port_delete(rport); + del_timer_sync(&tgt->timer); kref_put(&tgt->kref, ibmvfc_release_tgt); return; } @@ -3798,6 +3972,8 @@ static int ibmvfc_init_crq(struct ibmvfc_host *vhost) retrc = 0; + tasklet_init(&vhost->tasklet, (void *)ibmvfc_tasklet, (unsigned long)vhost); + if ((rc = request_irq(vdev->irq, ibmvfc_interrupt, 0, IBMVFC_NAME, vhost))) { dev_err(dev, "Couldn't register irq 0x%x. rc=%d\n", vdev->irq, rc); goto req_irq_failed; @@ -3813,6 +3989,7 @@ static int ibmvfc_init_crq(struct ibmvfc_host *vhost) return retrc; req_irq_failed: + tasklet_kill(&vhost->tasklet); do { rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address); } while (rc == H_BUSY || H_IS_LONG_BUSY(rc)); @@ -3979,6 +4156,7 @@ static int ibmvfc_probe(struct vio_dev *vdev, const struct vio_device_id *id) vhost->dev = dev; vhost->partition_number = -1; vhost->log_level = log_level; + vhost->task_set = 1; strcpy(vhost->partition_name, "UNKNOWN"); init_waitqueue_head(&vhost->work_wait_q); init_waitqueue_head(&vhost->init_wait_q); @@ -4113,6 +4291,7 @@ static struct fc_function_template ibmvfc_transport_functions = { .show_host_supported_classes = 1, .show_host_port_type = 1, .show_host_port_id = 1, + .show_host_maxframe_size = 1, .get_host_port_state = ibmvfc_get_host_port_state, .show_host_port_state = 1, diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h index 87dafd0f8d4..ca1dcf7a756 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.h +++ b/drivers/scsi/ibmvscsi/ibmvfc.h @@ -29,10 +29,14 @@ #include "viosrp.h" #define IBMVFC_NAME "ibmvfc" -#define IBMVFC_DRIVER_VERSION "1.0.4" -#define IBMVFC_DRIVER_DATE "(November 14, 2008)" - -#define IBMVFC_DEFAULT_TIMEOUT 15 +#define IBMVFC_DRIVER_VERSION "1.0.5" +#define IBMVFC_DRIVER_DATE "(March 19, 2009)" + +#define IBMVFC_DEFAULT_TIMEOUT 60 +#define IBMVFC_ADISC_CANCEL_TIMEOUT 45 +#define IBMVFC_ADISC_TIMEOUT 15 +#define IBMVFC_ADISC_PLUS_CANCEL_TIMEOUT \ + (IBMVFC_ADISC_TIMEOUT + IBMVFC_ADISC_CANCEL_TIMEOUT) #define IBMVFC_INIT_TIMEOUT 120 #define IBMVFC_MAX_REQUESTS_DEFAULT 100 @@ -53,9 +57,9 @@ * Ensure we have resources for ERP and initialization: * 1 for ERP * 1 for initialization - * 1 for each discovery thread + * 2 for each discovery thread */ -#define IBMVFC_NUM_INTERNAL_REQ (1 + 1 + disc_threads) +#define IBMVFC_NUM_INTERNAL_REQ (1 + 1 + (disc_threads * 2)) #define IBMVFC_MAD_SUCCESS 0x00 #define IBMVFC_MAD_NOT_SUPPORTED 0xF1 @@ -585,10 +589,12 @@ struct ibmvfc_target { enum ibmvfc_target_action action; int need_login; int init_retries; + u32 cancel_key; struct ibmvfc_service_parms service_parms; struct ibmvfc_service_parms service_parms_change; struct fc_rport_identifiers ids; void (*job_step) (struct ibmvfc_target *); + struct timer_list timer; struct kref kref; }; @@ -672,6 +678,7 @@ struct ibmvfc_host { int task_set; int init_retries; int discovery_threads; + int abort_threads; int client_migrated; int reinit; int delay_init; @@ -684,6 +691,7 @@ struct ibmvfc_host { char partition_name[97]; void (*job_step) (struct ibmvfc_host *); struct task_struct *work_thread; + struct tasklet_struct tasklet; wait_queue_head_t init_wait_q; wait_queue_head_t work_wait_q; }; diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index 74d07d137da..c9aa7611e40 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -432,6 +432,7 @@ static int map_sg_data(struct scsi_cmnd *cmd, sdev_printk(KERN_ERR, cmd->device, "Can't allocate memory " "for indirect table\n"); + scsi_dma_unmap(cmd); return 0; } } diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 07829009a8b..def473f0a98 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -152,13 +152,13 @@ module_param_named(log_level, ipr_log_level, uint, 0); MODULE_PARM_DESC(log_level, "Set to 0 - 4 for increasing verbosity of device driver"); module_param_named(testmode, ipr_testmode, int, 0); MODULE_PARM_DESC(testmode, "DANGEROUS!!! Allows unsupported configurations"); -module_param_named(fastfail, ipr_fastfail, int, 0); +module_param_named(fastfail, ipr_fastfail, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(fastfail, "Reduce timeouts and retries"); module_param_named(transop_timeout, ipr_transop_timeout, int, 0); MODULE_PARM_DESC(transop_timeout, "Time in seconds to wait for adapter to come operational (default: 300)"); module_param_named(enable_cache, ipr_enable_cache, int, 0); MODULE_PARM_DESC(enable_cache, "Enable adapter's non-volatile write cache (default: 1)"); -module_param_named(debug, ipr_debug, int, 0); +module_param_named(debug, ipr_debug, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Enable device driver debugging logging. Set to 1 to enable. (default: 0)"); module_param_named(dual_ioa_raid, ipr_dual_ioa_raid, int, 0); MODULE_PARM_DESC(dual_ioa_raid, "Enable dual adapter RAID support. Set to 1 to enable. (default: 1)"); @@ -354,6 +354,8 @@ struct ipr_error_table_t ipr_error_table[] = { "9076: Configuration error, missing remote IOA"}, {0x06679100, 0, IPR_DEFAULT_LOG_LEVEL, "4050: Enclosure does not support a required multipath function"}, + {0x06690000, 0, IPR_DEFAULT_LOG_LEVEL, + "4070: Logically bad block written on device"}, {0x06690200, 0, IPR_DEFAULT_LOG_LEVEL, "9041: Array protection temporarily suspended"}, {0x06698200, 0, IPR_DEFAULT_LOG_LEVEL, @@ -7147,6 +7149,7 @@ static void ipr_free_all_resources(struct ipr_ioa_cfg *ioa_cfg) ENTER; free_irq(pdev->irq, ioa_cfg); + pci_disable_msi(pdev); iounmap(ioa_cfg->hdw_dma_regs); pci_release_regions(pdev); ipr_free_mem(ioa_cfg); @@ -7432,6 +7435,11 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev, goto out; } + if (!(rc = pci_enable_msi(pdev))) + dev_info(&pdev->dev, "MSI enabled\n"); + else if (ipr_debug) + dev_info(&pdev->dev, "Cannot enable MSI\n"); + dev_info(&pdev->dev, "Found IOA with IRQ: %d\n", pdev->irq); host = scsi_host_alloc(&driver_template, sizeof(*ioa_cfg)); @@ -7574,6 +7582,7 @@ out_release_regions: out_scsi_host_put: scsi_host_put(host); out_disable: + pci_disable_msi(pdev); pci_disable_device(pdev); goto out; } diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h index 8f872f816fe..79a3ae4fb2c 100644 --- a/drivers/scsi/ipr.h +++ b/drivers/scsi/ipr.h @@ -37,8 +37,8 @@ /* * Literals */ -#define IPR_DRIVER_VERSION "2.4.1" -#define IPR_DRIVER_DATE "(April 24, 2007)" +#define IPR_DRIVER_VERSION "2.4.2" +#define IPR_DRIVER_DATE "(January 21, 2009)" /* * IPR_MAX_CMD_PER_LUN: This defines the maximum number of outstanding diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c index ef683f0d2b5..457d76a4cfe 100644 --- a/drivers/scsi/ips.c +++ b/drivers/scsi/ips.c @@ -1004,8 +1004,7 @@ static int __ips_eh_reset(struct scsi_cmnd *SC) DEBUG_VAR(1, "(%s%d) Failing active commands", ips_name, ha->host_num); while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) { - scb->scsi_cmd->result = - (DID_RESET << 16) | (SUGGEST_RETRY << 24); + scb->scsi_cmd->result = DID_RESET << 16; scb->scsi_cmd->scsi_done(scb->scsi_cmd); ips_freescb(ha, scb); } diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 23808dfe22b..b3e5e08e44a 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -48,13 +48,6 @@ MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu>, " "Alex Aizman <itn780@yahoo.com>"); MODULE_DESCRIPTION("iSCSI/TCP data-path"); MODULE_LICENSE("GPL"); -#undef DEBUG_TCP - -#ifdef DEBUG_TCP -#define debug_tcp(fmt...) printk(KERN_INFO "tcp: " fmt) -#else -#define debug_tcp(fmt...) -#endif static struct scsi_transport_template *iscsi_sw_tcp_scsi_transport; static struct scsi_host_template iscsi_sw_tcp_sht; @@ -63,6 +56,21 @@ static struct iscsi_transport iscsi_sw_tcp_transport; static unsigned int iscsi_max_lun = 512; module_param_named(max_lun, iscsi_max_lun, uint, S_IRUGO); +static int iscsi_sw_tcp_dbg; +module_param_named(debug_iscsi_tcp, iscsi_sw_tcp_dbg, int, + S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug_iscsi_tcp, "Turn on debugging for iscsi_tcp module " + "Set to 1 to turn on, and zero to turn off. Default is off."); + +#define ISCSI_SW_TCP_DBG(_conn, dbg_fmt, arg...) \ + do { \ + if (iscsi_sw_tcp_dbg) \ + iscsi_conn_printk(KERN_INFO, _conn, \ + "%s " dbg_fmt, \ + __func__, ##arg); \ + } while (0); + + /** * iscsi_sw_tcp_recv - TCP receive in sendfile fashion * @rd_desc: read descriptor @@ -77,7 +85,7 @@ static int iscsi_sw_tcp_recv(read_descriptor_t *rd_desc, struct sk_buff *skb, unsigned int consumed, total_consumed = 0; int status; - debug_tcp("in %d bytes\n", skb->len - offset); + ISCSI_SW_TCP_DBG(conn, "in %d bytes\n", skb->len - offset); do { status = 0; @@ -86,7 +94,8 @@ static int iscsi_sw_tcp_recv(read_descriptor_t *rd_desc, struct sk_buff *skb, total_consumed += consumed; } while (consumed != 0 && status != ISCSI_TCP_SKB_DONE); - debug_tcp("read %d bytes status %d\n", skb->len - offset, status); + ISCSI_SW_TCP_DBG(conn, "read %d bytes status %d\n", + skb->len - offset, status); return total_consumed; } @@ -131,7 +140,8 @@ static void iscsi_sw_tcp_state_change(struct sock *sk) if ((sk->sk_state == TCP_CLOSE_WAIT || sk->sk_state == TCP_CLOSE) && !atomic_read(&sk->sk_rmem_alloc)) { - debug_tcp("iscsi_tcp_state_change: TCP_CLOSE|TCP_CLOSE_WAIT\n"); + ISCSI_SW_TCP_DBG(conn, "iscsi_tcp_state_change: " + "TCP_CLOSE|TCP_CLOSE_WAIT\n"); iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); } @@ -155,8 +165,8 @@ static void iscsi_sw_tcp_write_space(struct sock *sk) struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; tcp_sw_conn->old_write_space(sk); - debug_tcp("iscsi_write_space: cid %d\n", conn->id); - scsi_queue_work(conn->session->host, &conn->xmitwork); + ISCSI_SW_TCP_DBG(conn, "iscsi_write_space\n"); + iscsi_conn_queue_work(conn); } static void iscsi_sw_tcp_conn_set_callbacks(struct iscsi_conn *conn) @@ -283,7 +293,7 @@ static int iscsi_sw_tcp_xmit(struct iscsi_conn *conn) } } - debug_tcp("xmit %d bytes\n", consumed); + ISCSI_SW_TCP_DBG(conn, "xmit %d bytes\n", consumed); conn->txdata_octets += consumed; return consumed; @@ -291,7 +301,7 @@ static int iscsi_sw_tcp_xmit(struct iscsi_conn *conn) error: /* Transmit error. We could initiate error recovery * here. */ - debug_tcp("Error sending PDU, errno=%d\n", rc); + ISCSI_SW_TCP_DBG(conn, "Error sending PDU, errno=%d\n", rc); iscsi_conn_failure(conn, rc); return -EIO; } @@ -334,9 +344,10 @@ static int iscsi_sw_tcp_send_hdr_done(struct iscsi_tcp_conn *tcp_conn, struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; tcp_sw_conn->out.segment = tcp_sw_conn->out.data_segment; - debug_tcp("Header done. Next segment size %u total_size %u\n", - tcp_sw_conn->out.segment.size, - tcp_sw_conn->out.segment.total_size); + ISCSI_SW_TCP_DBG(tcp_conn->iscsi_conn, + "Header done. Next segment size %u total_size %u\n", + tcp_sw_conn->out.segment.size, + tcp_sw_conn->out.segment.total_size); return 0; } @@ -346,8 +357,8 @@ static void iscsi_sw_tcp_send_hdr_prep(struct iscsi_conn *conn, void *hdr, struct iscsi_tcp_conn *tcp_conn = conn->dd_data; struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; - debug_tcp("%s(%p%s)\n", __func__, tcp_conn, - conn->hdrdgst_en? ", digest enabled" : ""); + ISCSI_SW_TCP_DBG(conn, "%s\n", conn->hdrdgst_en ? + "digest enabled" : "digest disabled"); /* Clear the data segment - needs to be filled in by the * caller using iscsi_tcp_send_data_prep() */ @@ -389,9 +400,9 @@ iscsi_sw_tcp_send_data_prep(struct iscsi_conn *conn, struct scatterlist *sg, struct hash_desc *tx_hash = NULL; unsigned int hdr_spec_len; - debug_tcp("%s(%p, offset=%d, datalen=%d%s)\n", __func__, - tcp_conn, offset, len, - conn->datadgst_en? ", digest enabled" : ""); + ISCSI_SW_TCP_DBG(conn, "offset=%d, datalen=%d %s\n", offset, len, + conn->datadgst_en ? + "digest enabled" : "digest disabled"); /* Make sure the datalen matches what the caller said he would send. */ @@ -415,8 +426,8 @@ iscsi_sw_tcp_send_linear_data_prep(struct iscsi_conn *conn, void *data, struct hash_desc *tx_hash = NULL; unsigned int hdr_spec_len; - debug_tcp("%s(%p, datalen=%d%s)\n", __func__, tcp_conn, len, - conn->datadgst_en? ", digest enabled" : ""); + ISCSI_SW_TCP_DBG(conn, "datalen=%zd %s\n", len, conn->datadgst_en ? + "digest enabled" : "digest disabled"); /* Make sure the datalen matches what the caller said he would send. */ @@ -754,8 +765,7 @@ iscsi_sw_tcp_conn_get_stats(struct iscsi_cls_conn *cls_conn, static struct iscsi_cls_session * iscsi_sw_tcp_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max, - uint16_t qdepth, uint32_t initial_cmdsn, - uint32_t *hostno) + uint16_t qdepth, uint32_t initial_cmdsn) { struct iscsi_cls_session *cls_session; struct iscsi_session *session; @@ -766,10 +776,11 @@ iscsi_sw_tcp_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max, return NULL; } - shost = iscsi_host_alloc(&iscsi_sw_tcp_sht, 0, qdepth); + shost = iscsi_host_alloc(&iscsi_sw_tcp_sht, 0, 1); if (!shost) return NULL; shost->transportt = iscsi_sw_tcp_scsi_transport; + shost->cmd_per_lun = qdepth; shost->max_lun = iscsi_max_lun; shost->max_id = 0; shost->max_channel = 0; @@ -777,7 +788,6 @@ iscsi_sw_tcp_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max, if (iscsi_host_add(shost, NULL)) goto free_host; - *hostno = shost->host_no; cls_session = iscsi_session_setup(&iscsi_sw_tcp_transport, shost, cmds_max, @@ -813,6 +823,12 @@ static void iscsi_sw_tcp_session_destroy(struct iscsi_cls_session *cls_session) iscsi_host_free(shost); } +static int iscsi_sw_tcp_slave_alloc(struct scsi_device *sdev) +{ + set_bit(QUEUE_FLAG_BIDI, &sdev->request_queue->queue_flags); + return 0; +} + static int iscsi_sw_tcp_slave_configure(struct scsi_device *sdev) { blk_queue_bounce_limit(sdev->request_queue, BLK_BOUNCE_ANY); @@ -833,6 +849,7 @@ static struct scsi_host_template iscsi_sw_tcp_sht = { .eh_device_reset_handler= iscsi_eh_device_reset, .eh_target_reset_handler= iscsi_eh_target_reset, .use_clustering = DISABLE_CLUSTERING, + .slave_alloc = iscsi_sw_tcp_slave_alloc, .slave_configure = iscsi_sw_tcp_slave_configure, .proc_name = "iscsi_tcp", .this_id = -1, diff --git a/drivers/scsi/lasi700.c b/drivers/scsi/lasi700.c index 4a4e6954ec7..f23c4ca9a2e 100644 --- a/drivers/scsi/lasi700.c +++ b/drivers/scsi/lasi700.c @@ -103,7 +103,7 @@ lasi700_probe(struct parisc_device *dev) hostdata = kzalloc(sizeof(*hostdata), GFP_KERNEL); if (!hostdata) { - dev_printk(KERN_ERR, dev, "Failed to allocate host data\n"); + dev_printk(KERN_ERR, &dev->dev, "Failed to allocate host data\n"); return -ENOMEM; } diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index dd1564c9e04..e57556ea5b4 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -64,7 +64,7 @@ static void fc_disc_single(struct fc_disc *, struct fc_disc_port *); static void fc_disc_restart(struct fc_disc *); /** - * fc_disc_lookup_rport - lookup a remote port by port_id + * fc_disc_lookup_rport() - lookup a remote port by port_id * @lport: Fibre Channel host port instance * @port_id: remote port port_id to match */ @@ -92,7 +92,7 @@ struct fc_rport *fc_disc_lookup_rport(const struct fc_lport *lport, } /** - * fc_disc_stop_rports - delete all the remote ports associated with the lport + * fc_disc_stop_rports() - delete all the remote ports associated with the lport * @disc: The discovery job to stop rports on * * Locking Note: This function expects that the lport mutex is locked before @@ -117,7 +117,7 @@ void fc_disc_stop_rports(struct fc_disc *disc) } /** - * fc_disc_rport_callback - Event handler for rport events + * fc_disc_rport_callback() - Event handler for rport events * @lport: The lport which is receiving the event * @rport: The rport which the event has occured on * @event: The event that occured @@ -151,7 +151,7 @@ static void fc_disc_rport_callback(struct fc_lport *lport, } /** - * fc_disc_recv_rscn_req - Handle Registered State Change Notification (RSCN) + * fc_disc_recv_rscn_req() - Handle Registered State Change Notification (RSCN) * @sp: Current sequence of the RSCN exchange * @fp: RSCN Frame * @lport: Fibre Channel host port instance @@ -246,7 +246,7 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp, list_del(&dp->peers); rport = lport->tt.rport_lookup(lport, dp->ids.port_id); if (rport) { - rdata = RPORT_TO_PRIV(rport); + rdata = rport->dd_data; list_del(&rdata->peers); lport->tt.rport_logoff(rport); } @@ -265,7 +265,7 @@ reject: } /** - * fc_disc_recv_req - Handle incoming requests + * fc_disc_recv_req() - Handle incoming requests * @sp: Current sequence of the request exchange * @fp: The frame * @lport: The FC local port @@ -294,7 +294,7 @@ static void fc_disc_recv_req(struct fc_seq *sp, struct fc_frame *fp, } /** - * fc_disc_restart - Restart discovery + * fc_disc_restart() - Restart discovery * @lport: FC discovery context * * Locking Note: This function expects that the disc mutex @@ -322,7 +322,7 @@ static void fc_disc_restart(struct fc_disc *disc) } /** - * fc_disc_start - Fibre Channel Target discovery + * fc_disc_start() - Fibre Channel Target discovery * @lport: FC local port * * Returns non-zero if discovery cannot be started. @@ -383,7 +383,7 @@ static struct fc_rport_operations fc_disc_rport_ops = { }; /** - * fc_disc_new_target - Handle new target found by discovery + * fc_disc_new_target() - Handle new target found by discovery * @lport: FC local port * @rport: The previous FC remote port (NULL if new remote port) * @ids: Identifiers for the new FC remote port @@ -396,7 +396,7 @@ static int fc_disc_new_target(struct fc_disc *disc, struct fc_rport_identifiers *ids) { struct fc_lport *lport = disc->lport; - struct fc_rport_libfc_priv *rp; + struct fc_rport_libfc_priv *rdata; int error = 0; if (rport && ids->port_name) { @@ -430,15 +430,15 @@ static int fc_disc_new_target(struct fc_disc *disc, dp.ids.port_name = ids->port_name; dp.ids.node_name = ids->node_name; dp.ids.roles = ids->roles; - rport = fc_rport_rogue_create(&dp); + rport = lport->tt.rport_create(&dp); } if (!rport) error = -ENOMEM; } if (rport) { - rp = rport->dd_data; - rp->ops = &fc_disc_rport_ops; - rp->rp_state = RPORT_ST_INIT; + rdata = rport->dd_data; + rdata->ops = &fc_disc_rport_ops; + rdata->rp_state = RPORT_ST_INIT; lport->tt.rport_login(rport); } } @@ -446,20 +446,20 @@ static int fc_disc_new_target(struct fc_disc *disc, } /** - * fc_disc_del_target - Delete a target + * fc_disc_del_target() - Delete a target * @disc: FC discovery context * @rport: The remote port to be removed */ static void fc_disc_del_target(struct fc_disc *disc, struct fc_rport *rport) { struct fc_lport *lport = disc->lport; - struct fc_rport_libfc_priv *rdata = RPORT_TO_PRIV(rport); + struct fc_rport_libfc_priv *rdata = rport->dd_data; list_del(&rdata->peers); lport->tt.rport_logoff(rport); } /** - * fc_disc_done - Discovery has been completed + * fc_disc_done() - Discovery has been completed * @disc: FC discovery context */ static void fc_disc_done(struct fc_disc *disc) @@ -479,7 +479,7 @@ static void fc_disc_done(struct fc_disc *disc) } /** - * fc_disc_error - Handle error on dNS request + * fc_disc_error() - Handle error on dNS request * @disc: FC discovery context * @fp: The frame pointer */ @@ -519,7 +519,7 @@ static void fc_disc_error(struct fc_disc *disc, struct fc_frame *fp) } /** - * fc_disc_gpn_ft_req - Send Get Port Names by FC-4 type (GPN_FT) request + * fc_disc_gpn_ft_req() - Send Get Port Names by FC-4 type (GPN_FT) request * @lport: FC discovery context * * Locking Note: This function expects that the disc_mutex is locked @@ -553,7 +553,7 @@ err: } /** - * fc_disc_gpn_ft_parse - Parse the list of IDs and names resulting from a request + * fc_disc_gpn_ft_parse() - Parse the list of IDs and names resulting from a request * @lport: Fibre Channel host port instance * @buf: GPN_FT response buffer * @len: size of response buffer @@ -617,7 +617,7 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len) if ((dp.ids.port_id != fc_host_port_id(lport->host)) && (dp.ids.port_name != lport->wwpn)) { - rport = fc_rport_rogue_create(&dp); + rport = lport->tt.rport_create(&dp); if (rport) { rdata = rport->dd_data; rdata->ops = &fc_disc_rport_ops; @@ -658,7 +658,10 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len) return error; } -/* +/** + * fc_disc_timeout() - Retry handler for the disc component + * @work: Structure holding disc obj that needs retry discovery + * * Handle retry of memory allocation for remote ports. */ static void fc_disc_timeout(struct work_struct *work) @@ -673,7 +676,7 @@ static void fc_disc_timeout(struct work_struct *work) } /** - * fc_disc_gpn_ft_resp - Handle a response frame from Get Port Names (GPN_FT) + * fc_disc_gpn_ft_resp() - Handle a response frame from Get Port Names (GPN_FT) * @sp: Current sequence of GPN_FT exchange * @fp: response frame * @lp_arg: Fibre Channel host port instance @@ -712,9 +715,7 @@ static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp, fr_len(fp)); } else if (ntohs(cp->ct_cmd) == FC_FS_ACC) { - /* - * Accepted. Parse response. - */ + /* Accepted, parse the response. */ buf = cp + 1; len -= sizeof(*cp); } else if (ntohs(cp->ct_cmd) == FC_FS_RJT) { @@ -746,7 +747,7 @@ static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp, } /** - * fc_disc_single - Discover the directory information for a single target + * fc_disc_single() - Discover the directory information for a single target * @lport: FC local port * @dp: The port to rediscover * @@ -769,7 +770,7 @@ static void fc_disc_single(struct fc_disc *disc, struct fc_disc_port *dp) if (rport) fc_disc_del_target(disc, rport); - new_rport = fc_rport_rogue_create(dp); + new_rport = lport->tt.rport_create(dp); if (new_rport) { rdata = new_rport->dd_data; rdata->ops = &fc_disc_rport_ops; @@ -782,7 +783,7 @@ out: } /** - * fc_disc_stop - Stop discovery for a given lport + * fc_disc_stop() - Stop discovery for a given lport * @lport: The lport that discovery should stop for */ void fc_disc_stop(struct fc_lport *lport) @@ -796,7 +797,7 @@ void fc_disc_stop(struct fc_lport *lport) } /** - * fc_disc_stop_final - Stop discovery for a given lport + * fc_disc_stop_final() - Stop discovery for a given lport * @lport: The lport that discovery should stop for * * This function will block until discovery has been @@ -809,7 +810,7 @@ void fc_disc_stop_final(struct fc_lport *lport) } /** - * fc_disc_init - Initialize the discovery block + * fc_disc_init() - Initialize the discovery block * @lport: FC local port */ int fc_disc_init(struct fc_lport *lport) diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index 66db08a5f27..992af05aacf 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c @@ -32,8 +32,6 @@ #include <scsi/libfc.h> #include <scsi/fc_encode.h> -#define FC_DEF_R_A_TOV (10 * 1000) /* resource allocation timeout */ - /* * fc_exch_debug can be set in debugger or at compile time to get more logs. */ @@ -283,7 +281,7 @@ static void fc_exch_release(struct fc_exch *ep) ep->destructor(&ep->seq, ep->arg); if (ep->lp->tt.exch_put) ep->lp->tt.exch_put(ep->lp, mp, ep->xid); - WARN_ON(!ep->esb_stat & ESB_ST_COMPLETE); + WARN_ON(!(ep->esb_stat & ESB_ST_COMPLETE)); mempool_free(ep, mp->ep_pool); } } @@ -491,7 +489,7 @@ static u16 fc_em_alloc_xid(struct fc_exch_mgr *mp, const struct fc_frame *fp) struct fc_exch *ep = NULL; if (mp->max_read) { - if (fc_frame_is_read(fp)) { + if (fc_fcp_is_read(fr_fsp(fp))) { min = mp->min_xid; max = mp->max_read; plast = &mp->last_read; @@ -627,7 +625,6 @@ static struct fc_exch *fc_exch_resp(struct fc_exch_mgr *mp, struct fc_frame *fp) { struct fc_exch *ep; struct fc_frame_header *fh; - u16 rxid; ep = mp->lp->tt.exch_get(mp->lp, fp); if (ep) { @@ -654,18 +651,6 @@ static struct fc_exch *fc_exch_resp(struct fc_exch_mgr *mp, struct fc_frame *fp) if ((ntoh24(fh->fh_f_ctl) & FC_FC_SEQ_INIT) == 0) ep->esb_stat &= ~ESB_ST_SEQ_INIT; - /* - * Set the responder ID in the frame header. - * The old one should've been 0xffff. - * If it isn't, don't assign one. - * Incoming basic link service frames may specify - * a referenced RX_ID. - */ - if (fh->fh_type != FC_TYPE_BLS) { - rxid = ntohs(fh->fh_rx_id); - WARN_ON(rxid != FC_XID_UNKNOWN); - fh->fh_rx_id = htons(ep->rxid); - } fc_exch_hold(ep); /* hold for caller */ spin_unlock_bh(&ep->ex_lock); /* lock from exch_get */ } @@ -677,8 +662,8 @@ static struct fc_exch *fc_exch_resp(struct fc_exch_mgr *mp, struct fc_frame *fp) * If fc_pf_rjt_reason is FC_RJT_NONE then this function will have a hold * on the ep that should be released by the caller. */ -static enum fc_pf_rjt_reason -fc_seq_lookup_recip(struct fc_exch_mgr *mp, struct fc_frame *fp) +static enum fc_pf_rjt_reason fc_seq_lookup_recip(struct fc_exch_mgr *mp, + struct fc_frame *fp) { struct fc_frame_header *fh = fc_frame_header_get(fp); struct fc_exch *ep = NULL; @@ -996,9 +981,9 @@ static void fc_seq_send_ack(struct fc_seq *sp, const struct fc_frame *rx_fp) * Send BLS Reject. * This is for rejecting BA_ABTS only. */ -static void -fc_exch_send_ba_rjt(struct fc_frame *rx_fp, enum fc_ba_rjt_reason reason, - enum fc_ba_rjt_explan explan) +static void fc_exch_send_ba_rjt(struct fc_frame *rx_fp, + enum fc_ba_rjt_reason reason, + enum fc_ba_rjt_explan explan) { struct fc_frame *fp; struct fc_frame_header *rx_fh; @@ -1096,7 +1081,7 @@ static void fc_exch_recv_abts(struct fc_exch *ep, struct fc_frame *rx_fp) ap->ba_high_seq_cnt = fh->fh_seq_cnt; ap->ba_low_seq_cnt = htons(sp->cnt); } - sp = fc_seq_start_next(sp); + sp = fc_seq_start_next_locked(sp); spin_unlock_bh(&ep->ex_lock); fc_seq_send_last(sp, fp, FC_RCTL_BA_ACC, FC_TYPE_BLS); fc_frame_free(rx_fp); @@ -1480,10 +1465,11 @@ static void fc_exch_reset(struct fc_exch *ep) * If sid is non-zero, reset only exchanges we source from that FID. * If did is non-zero, reset only exchanges destined to that FID. */ -void fc_exch_mgr_reset(struct fc_exch_mgr *mp, u32 sid, u32 did) +void fc_exch_mgr_reset(struct fc_lport *lp, u32 sid, u32 did) { struct fc_exch *ep; struct fc_exch *next; + struct fc_exch_mgr *mp = lp->emp; spin_lock_bh(&mp->em_lock); restart: @@ -1607,7 +1593,7 @@ static void fc_exch_rrq_resp(struct fc_seq *sp, struct fc_frame *fp, void *arg) if (IS_ERR(fp)) { int err = PTR_ERR(fp); - if (err == -FC_EX_CLOSED) + if (err == -FC_EX_CLOSED || err == -FC_EX_TIMEOUT) goto cleanup; FC_DBG("Cannot process RRQ, because of frame error %d\n", err); return; @@ -1855,6 +1841,8 @@ struct fc_seq *fc_exch_seq_send(struct fc_lport *lp, fc_exch_setup_hdr(ep, fp, ep->f_ctl); sp->cnt++; + fc_fcp_ddp_setup(fr_fsp(fp), ep->xid); + if (unlikely(lp->tt.frame_send(lp, fp))) goto err; diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c index 404e63ff46b..f555ae99ad4 100644 --- a/drivers/scsi/libfc/fc_fcp.c +++ b/drivers/scsi/libfc/fc_fcp.c @@ -41,7 +41,7 @@ MODULE_AUTHOR("Open-FCoE.org"); MODULE_DESCRIPTION("libfc"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); static int fc_fcp_debug; @@ -161,7 +161,7 @@ static struct fc_fcp_pkt *fc_fcp_pkt_alloc(struct fc_lport *lp, gfp_t gfp) } /** - * fc_fcp_pkt_release - release hold on scsi_pkt packet + * fc_fcp_pkt_release() - release hold on scsi_pkt packet * @fsp: fcp packet struct * * This is used by upper layer scsi driver. @@ -183,8 +183,7 @@ static void fc_fcp_pkt_hold(struct fc_fcp_pkt *fsp) } /** - * fc_fcp_pkt_destory - release hold on scsi_pkt packet - * + * fc_fcp_pkt_destory() - release hold on scsi_pkt packet * @seq: exchange sequence * @fsp: fcp packet struct * @@ -199,7 +198,7 @@ static void fc_fcp_pkt_destroy(struct fc_seq *seq, void *fsp) } /** - * fc_fcp_lock_pkt - lock a packet and get a ref to it. + * fc_fcp_lock_pkt() - lock a packet and get a ref to it. * @fsp: fcp packet * * We should only return error if we return a command to scsi-ml before @@ -260,12 +259,62 @@ static void fc_fcp_retry_cmd(struct fc_fcp_pkt *fsp) } fsp->state &= ~FC_SRB_ABORT_PENDING; - fsp->io_status = SUGGEST_RETRY << 24; + fsp->io_status = 0; fsp->status_code = FC_ERROR; fc_fcp_complete_locked(fsp); } /* + * fc_fcp_ddp_setup - calls to LLD's ddp_setup to set up DDP + * transfer for a read I/O indicated by the fc_fcp_pkt. + * @fsp: ptr to the fc_fcp_pkt + * + * This is called in exch_seq_send() when we have a newly allocated + * exchange with a valid exchange id to setup ddp. + * + * returns: none + */ +void fc_fcp_ddp_setup(struct fc_fcp_pkt *fsp, u16 xid) +{ + struct fc_lport *lp; + + if (!fsp) + return; + + lp = fsp->lp; + if ((fsp->req_flags & FC_SRB_READ) && + (lp->lro_enabled) && (lp->tt.ddp_setup)) { + if (lp->tt.ddp_setup(lp, xid, scsi_sglist(fsp->cmd), + scsi_sg_count(fsp->cmd))) + fsp->xfer_ddp = xid; + } +} +EXPORT_SYMBOL(fc_fcp_ddp_setup); + +/* + * fc_fcp_ddp_done - calls to LLD's ddp_done to release any + * DDP related resources for this I/O if it is initialized + * as a ddp transfer + * @fsp: ptr to the fc_fcp_pkt + * + * returns: none + */ +static void fc_fcp_ddp_done(struct fc_fcp_pkt *fsp) +{ + struct fc_lport *lp; + + if (!fsp) + return; + + lp = fsp->lp; + if (fsp->xfer_ddp && lp->tt.ddp_done) { + fsp->xfer_len = lp->tt.ddp_done(lp, fsp->xfer_ddp); + fsp->xfer_ddp = 0; + } +} + + +/* * Receive SCSI data from target. * Called after receiving solicited data. */ @@ -290,10 +339,11 @@ static void fc_fcp_recv_data(struct fc_fcp_pkt *fsp, struct fc_frame *fp) len = fr_len(fp) - sizeof(*fh); buf = fc_frame_payload_get(fp, 0); + /* if this I/O is ddped, update xfer len */ + fc_fcp_ddp_done(fsp); + if (offset + len > fsp->data_len) { - /* - * this should never happen - */ + /* this should never happen */ if ((fr_flags(fp) & FCPHF_CRC_UNCHECKED) && fc_frame_crc_check(fp)) goto crc_err; @@ -357,10 +407,12 @@ static void fc_fcp_recv_data(struct fc_fcp_pkt *fsp, struct fc_frame *fp) if (~crc != le32_to_cpu(fr_crc(fp))) { crc_err: - stats = lp->dev_stats[smp_processor_id()]; + stats = fc_lport_get_stats(lp); stats->ErrorFrames++; + /* FIXME - per cpu count, not total count! */ if (stats->InvalidCRCCount++ < 5) - FC_DBG("CRC error on data frame\n"); + printk(KERN_WARNING "CRC error on data frame for port (%6x)\n", + fc_host_port_id(lp->host)); /* * Assume the frame is total garbage. * We may have copied it over the good part @@ -387,8 +439,8 @@ crc_err: fc_fcp_complete_locked(fsp); } -/* - * fc_fcp_send_data - Send SCSI data to target. +/** + * fc_fcp_send_data() - Send SCSI data to target. * @fsp: ptr to fc_fcp_pkt * @sp: ptr to this sequence * @offset: starting offset for this data request @@ -438,7 +490,13 @@ static int fc_fcp_send_data(struct fc_fcp_pkt *fsp, struct fc_seq *seq, * burst length (t_blen) to seq_blen, otherwise set t_blen * to max FC frame payload previously set in fsp->max_payload. */ - t_blen = lp->seq_offload ? seq_blen : fsp->max_payload; + t_blen = fsp->max_payload; + if (lp->seq_offload) { + t_blen = min(seq_blen, (size_t)lp->lso_max); + FC_DEBUG_FCP("fsp=%p:lso:blen=%zx lso_max=0x%x t_blen=%zx\n", + fsp, seq_blen, lp->lso_max, t_blen); + } + WARN_ON(t_blen < FC_MIN_MAX_PAYLOAD); if (t_blen > 512) t_blen &= ~(512 - 1); /* round down to block size */ @@ -610,8 +668,8 @@ static void fc_fcp_abts_resp(struct fc_fcp_pkt *fsp, struct fc_frame *fp) } } -/* - * fc_fcp_reduce_can_queue - drop can_queue +/** + * fc_fcp_reduce_can_queue() - drop can_queue * @lp: lport to drop queueing for * * If we are getting memory allocation failures, then we may @@ -642,9 +700,11 @@ done: spin_unlock_irqrestore(lp->host->host_lock, flags); } -/* - * exch mgr calls this routine to process scsi - * exchanges. +/** + * fc_fcp_recv() - Reveive FCP frames + * @seq: The sequence the frame is on + * @fp: The FC frame + * @arg: The related FCP packet * * Return : None * Context : called from Soft IRQ context @@ -745,6 +805,9 @@ static void fc_fcp_resp(struct fc_fcp_pkt *fsp, struct fc_frame *fp) fsp->scsi_comp_flags = flags; expected_len = fsp->data_len; + /* if ddp, update xfer len */ + fc_fcp_ddp_done(fsp); + if (unlikely((flags & ~FCP_CONF_REQ) || fc_rp->fr_status)) { rp_ex = (void *)(fc_rp + 1); if (flags & (FCP_RSP_LEN_VAL | FCP_SNS_LEN_VAL)) { @@ -832,7 +895,7 @@ err: } /** - * fc_fcp_complete_locked - complete processing of a fcp packet + * fc_fcp_complete_locked() - complete processing of a fcp packet * @fsp: fcp packet * * This function may sleep if a timer is pending. The packet lock must be @@ -860,7 +923,7 @@ static void fc_fcp_complete_locked(struct fc_fcp_pkt *fsp) (!(fsp->scsi_comp_flags & FCP_RESID_UNDER) || fsp->xfer_len < fsp->data_len - fsp->scsi_resid)) { fsp->status_code = FC_DATA_UNDRUN; - fsp->io_status = SUGGEST_RETRY << 24; + fsp->io_status = 0; } } @@ -900,7 +963,7 @@ static void fc_fcp_cleanup_cmd(struct fc_fcp_pkt *fsp, int error) } /** - * fc_fcp_cleanup_each_cmd - run fn on each active command + * fc_fcp_cleanup_each_cmd() - Cleanup active commads * @lp: logical port * @id: target id * @lun: lun @@ -952,7 +1015,7 @@ static void fc_fcp_abort_io(struct fc_lport *lp) } /** - * fc_fcp_pkt_send - send a fcp packet to the lower level. + * fc_fcp_pkt_send() - send a fcp packet to the lower level. * @lp: fc lport * @fsp: fc packet. * @@ -1007,7 +1070,7 @@ static int fc_fcp_cmd_send(struct fc_lport *lp, struct fc_fcp_pkt *fsp, } memcpy(fc_frame_payload_get(fp, len), &fsp->cdb_cmd, len); - fr_cmd(fp) = fsp->cmd; + fr_fsp(fp) = fsp; rport = fsp->rport; fsp->max_payload = rport->maxframe_size; rp = rport->dd_data; @@ -1268,7 +1331,7 @@ static void fc_fcp_rec(struct fc_fcp_pkt *fsp) rp = rport->dd_data; if (!fsp->seq_ptr || rp->rp_state != RPORT_ST_READY) { fsp->status_code = FC_HRD_ERROR; - fsp->io_status = SUGGEST_RETRY << 24; + fsp->io_status = 0; fc_fcp_complete_locked(fsp); return; } @@ -1621,7 +1684,7 @@ out: static inline int fc_fcp_lport_queue_ready(struct fc_lport *lp) { /* lock ? */ - return (lp->state == LPORT_ST_READY) && (lp->link_status & FC_LINK_UP); + return (lp->state == LPORT_ST_READY) && lp->link_up && !lp->qfull; } /** @@ -1691,7 +1754,7 @@ int fc_queuecommand(struct scsi_cmnd *sc_cmd, void (*done)(struct scsi_cmnd *)) /* * setup the data direction */ - stats = lp->dev_stats[smp_processor_id()]; + stats = fc_lport_get_stats(lp); if (sc_cmd->sc_data_direction == DMA_FROM_DEVICE) { fsp->req_flags = FC_SRB_READ; stats->InputRequests++; @@ -1727,7 +1790,7 @@ out: EXPORT_SYMBOL(fc_queuecommand); /** - * fc_io_compl - Handle responses for completed commands + * fc_io_compl() - Handle responses for completed commands * @fsp: scsi packet * * Translates a error to a Linux SCSI error. @@ -1741,6 +1804,9 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp) struct fc_lport *lp; unsigned long flags; + /* release outstanding ddp context */ + fc_fcp_ddp_done(fsp); + fsp->state |= FC_SRB_COMPL; if (!(fsp->state & FC_SRB_FCP_PROCESSING_TMO)) { spin_unlock_bh(&fsp->scsi_pkt_lock); @@ -1810,12 +1876,12 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp) sc_cmd->result = DID_ERROR << 16; break; case FC_DATA_UNDRUN: - if (fsp->cdb_status == 0) { + if ((fsp->cdb_status == 0) && !(fsp->req_flags & FC_SRB_READ)) { /* * scsi status is good but transport level - * underrun. for read it should be an error?? + * underrun. */ - sc_cmd->result = (DID_OK << 16) | fsp->cdb_status; + sc_cmd->result = DID_OK << 16; } else { /* * scsi got underrun, this is an error @@ -1857,7 +1923,7 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp) } /** - * fc_fcp_complete - complete processing of a fcp packet + * fc_fcp_complete() - complete processing of a fcp packet * @fsp: fcp packet * * This function may sleep if a fsp timer is pending. @@ -1874,9 +1940,10 @@ void fc_fcp_complete(struct fc_fcp_pkt *fsp) EXPORT_SYMBOL(fc_fcp_complete); /** - * fc_eh_abort - Abort a command...from scsi host template + * fc_eh_abort() - Abort a command * @sc_cmd: scsi command to abort * + * From scsi host template. * send ABTS to the target device and wait for the response * sc_cmd is the pointer to the command to be aborted. */ @@ -1890,7 +1957,7 @@ int fc_eh_abort(struct scsi_cmnd *sc_cmd) lp = shost_priv(sc_cmd->device->host); if (lp->state != LPORT_ST_READY) return rc; - else if (!(lp->link_status & FC_LINK_UP)) + else if (!lp->link_up) return rc; spin_lock_irqsave(lp->host->host_lock, flags); @@ -1920,7 +1987,7 @@ release_pkt: EXPORT_SYMBOL(fc_eh_abort); /** - * fc_eh_device_reset: Reset a single LUN + * fc_eh_device_reset() Reset a single LUN * @sc_cmd: scsi command * * Set from scsi host template to send tm cmd to the target and wait for the @@ -1973,7 +2040,7 @@ out: EXPORT_SYMBOL(fc_eh_device_reset); /** - * fc_eh_host_reset - The reset function will reset the ports on the host. + * fc_eh_host_reset() - The reset function will reset the ports on the host. * @sc_cmd: scsi command */ int fc_eh_host_reset(struct scsi_cmnd *sc_cmd) @@ -1999,7 +2066,7 @@ int fc_eh_host_reset(struct scsi_cmnd *sc_cmd) EXPORT_SYMBOL(fc_eh_host_reset); /** - * fc_slave_alloc - configure queue depth + * fc_slave_alloc() - configure queue depth * @sdev: scsi device * * Configures queue depth based on host's cmd_per_len. If not set diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index 0b9bdb1fb80..b8178ef398d 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -139,7 +139,7 @@ static int fc_frame_drop(struct fc_lport *lport, struct fc_frame *fp) } /** - * fc_lport_rport_callback - Event handler for rport events + * fc_lport_rport_callback() - Event handler for rport events * @lport: The lport which is receiving the event * @rport: The rport which the event has occured on * @event: The event that occured @@ -195,7 +195,7 @@ static void fc_lport_rport_callback(struct fc_lport *lport, } /** - * fc_lport_state - Return a string which represents the lport's state + * fc_lport_state() - Return a string which represents the lport's state * @lport: The lport whose state is to converted to a string */ static const char *fc_lport_state(struct fc_lport *lport) @@ -209,7 +209,7 @@ static const char *fc_lport_state(struct fc_lport *lport) } /** - * fc_lport_ptp_setup - Create an rport for point-to-point mode + * fc_lport_ptp_setup() - Create an rport for point-to-point mode * @lport: The lport to attach the ptp rport to * @fid: The FID of the ptp rport * @remote_wwpn: The WWPN of the ptp rport @@ -232,7 +232,7 @@ static void fc_lport_ptp_setup(struct fc_lport *lport, lport->ptp_rp = NULL; } - lport->ptp_rp = fc_rport_rogue_create(&dp); + lport->ptp_rp = lport->tt.rport_create(&dp); lport->tt.rport_login(lport->ptp_rp); @@ -250,7 +250,7 @@ void fc_get_host_port_state(struct Scsi_Host *shost) { struct fc_lport *lp = shost_priv(shost); - if ((lp->link_status & FC_LINK_UP) == FC_LINK_UP) + if (lp->link_up) fc_host_port_state(shost) = FC_PORTSTATE_ONLINE; else fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE; @@ -267,10 +267,10 @@ EXPORT_SYMBOL(fc_get_host_speed); struct fc_host_statistics *fc_get_host_stats(struct Scsi_Host *shost) { - int i; struct fc_host_statistics *fcoe_stats; struct fc_lport *lp = shost_priv(shost); struct timespec v0, v1; + unsigned int cpu; fcoe_stats = &lp->host_stats; memset(fcoe_stats, 0, sizeof(struct fc_host_statistics)); @@ -279,10 +279,11 @@ struct fc_host_statistics *fc_get_host_stats(struct Scsi_Host *shost) jiffies_to_timespec(lp->boot_time, &v1); fcoe_stats->seconds_since_last_reset = (v0.tv_sec - v1.tv_sec); - for_each_online_cpu(i) { - struct fcoe_dev_stats *stats = lp->dev_stats[i]; - if (stats == NULL) - continue; + for_each_possible_cpu(cpu) { + struct fcoe_dev_stats *stats; + + stats = per_cpu_ptr(lp->dev_stats, cpu); + fcoe_stats->tx_frames += stats->TxFrames; fcoe_stats->tx_words += stats->TxWords; fcoe_stats->rx_frames += stats->RxFrames; @@ -351,7 +352,7 @@ static void fc_lport_add_fc4_type(struct fc_lport *lport, enum fc_fh_type type) } /** - * fc_lport_recv_rlir_req - Handle received Registered Link Incident Report. + * fc_lport_recv_rlir_req() - Handle received Registered Link Incident Report. * @lport: Fibre Channel local port recieving the RLIR * @sp: current sequence in the RLIR exchange * @fp: RLIR request frame @@ -370,7 +371,7 @@ static void fc_lport_recv_rlir_req(struct fc_seq *sp, struct fc_frame *fp, } /** - * fc_lport_recv_echo_req - Handle received ECHO request + * fc_lport_recv_echo_req() - Handle received ECHO request * @lport: Fibre Channel local port recieving the ECHO * @sp: current sequence in the ECHO exchange * @fp: ECHO request frame @@ -412,7 +413,7 @@ static void fc_lport_recv_echo_req(struct fc_seq *sp, struct fc_frame *in_fp, } /** - * fc_lport_recv_echo_req - Handle received Request Node ID data request + * fc_lport_recv_echo_req() - Handle received Request Node ID data request * @lport: Fibre Channel local port recieving the RNID * @sp: current sequence in the RNID exchange * @fp: RNID request frame @@ -479,7 +480,7 @@ static void fc_lport_recv_rnid_req(struct fc_seq *sp, struct fc_frame *in_fp, } /** - * fc_lport_recv_adisc_req - Handle received Address Discovery Request + * fc_lport_recv_adisc_req() - Handle received Address Discovery Request * @lport: Fibre Channel local port recieving the ADISC * @sp: current sequence in the ADISC exchange * @fp: ADISC request frame @@ -529,7 +530,7 @@ static void fc_lport_recv_adisc_req(struct fc_seq *sp, struct fc_frame *in_fp, } /** - * fc_lport_recv_logo_req - Handle received fabric LOGO request + * fc_lport_recv_logo_req() - Handle received fabric LOGO request * @lport: Fibre Channel local port recieving the LOGO * @sp: current sequence in the LOGO exchange * @fp: LOGO request frame @@ -546,7 +547,7 @@ static void fc_lport_recv_logo_req(struct fc_seq *sp, struct fc_frame *fp, } /** - * fc_fabric_login - Start the lport state machine + * fc_fabric_login() - Start the lport state machine * @lport: The lport that should log into the fabric * * Locking Note: This function should not be called @@ -568,7 +569,7 @@ int fc_fabric_login(struct fc_lport *lport) EXPORT_SYMBOL(fc_fabric_login); /** - * fc_linkup - Handler for transport linkup events + * fc_linkup() - Handler for transport linkup events * @lport: The lport whose link is up */ void fc_linkup(struct fc_lport *lport) @@ -577,8 +578,8 @@ void fc_linkup(struct fc_lport *lport) fc_host_port_id(lport->host)); mutex_lock(&lport->lp_mutex); - if ((lport->link_status & FC_LINK_UP) != FC_LINK_UP) { - lport->link_status |= FC_LINK_UP; + if (!lport->link_up) { + lport->link_up = 1; if (lport->state == LPORT_ST_RESET) fc_lport_enter_flogi(lport); @@ -588,7 +589,7 @@ void fc_linkup(struct fc_lport *lport) EXPORT_SYMBOL(fc_linkup); /** - * fc_linkdown - Handler for transport linkdown events + * fc_linkdown() - Handler for transport linkdown events * @lport: The lport whose link is down */ void fc_linkdown(struct fc_lport *lport) @@ -597,8 +598,8 @@ void fc_linkdown(struct fc_lport *lport) FC_DEBUG_LPORT("Link is down for port (%6x)\n", fc_host_port_id(lport->host)); - if ((lport->link_status & FC_LINK_UP) == FC_LINK_UP) { - lport->link_status &= ~(FC_LINK_UP); + if (lport->link_up) { + lport->link_up = 0; fc_lport_enter_reset(lport); lport->tt.fcp_cleanup(lport); } @@ -607,48 +608,25 @@ void fc_linkdown(struct fc_lport *lport) EXPORT_SYMBOL(fc_linkdown); /** - * fc_pause - Pause the flow of frames - * @lport: The lport to be paused - */ -void fc_pause(struct fc_lport *lport) -{ - mutex_lock(&lport->lp_mutex); - lport->link_status |= FC_PAUSE; - mutex_unlock(&lport->lp_mutex); -} -EXPORT_SYMBOL(fc_pause); - -/** - * fc_unpause - Unpause the flow of frames - * @lport: The lport to be unpaused - */ -void fc_unpause(struct fc_lport *lport) -{ - mutex_lock(&lport->lp_mutex); - lport->link_status &= ~(FC_PAUSE); - mutex_unlock(&lport->lp_mutex); -} -EXPORT_SYMBOL(fc_unpause); - -/** - * fc_fabric_logoff - Logout of the fabric + * fc_fabric_logoff() - Logout of the fabric * @lport: fc_lport pointer to logoff the fabric * * Return value: * 0 for success, -1 for failure - **/ + */ int fc_fabric_logoff(struct fc_lport *lport) { lport->tt.disc_stop_final(lport); mutex_lock(&lport->lp_mutex); fc_lport_enter_logo(lport); mutex_unlock(&lport->lp_mutex); + cancel_delayed_work_sync(&lport->retry_work); return 0; } EXPORT_SYMBOL(fc_fabric_logoff); /** - * fc_lport_destroy - unregister a fc_lport + * fc_lport_destroy() - unregister a fc_lport * @lport: fc_lport pointer to unregister * * Return value: @@ -658,26 +636,25 @@ EXPORT_SYMBOL(fc_fabric_logoff); * clean-up all the allocated memory * and free up other system resources. * - **/ + */ int fc_lport_destroy(struct fc_lport *lport) { lport->tt.frame_send = fc_frame_drop; lport->tt.fcp_abort_io(lport); - lport->tt.exch_mgr_reset(lport->emp, 0, 0); + lport->tt.exch_mgr_reset(lport, 0, 0); return 0; } EXPORT_SYMBOL(fc_lport_destroy); /** - * fc_set_mfs - sets up the mfs for the corresponding fc_lport + * fc_set_mfs() - sets up the mfs for the corresponding fc_lport * @lport: fc_lport pointer to unregister * @mfs: the new mfs for fc_lport * * Set mfs for the given fc_lport to the new mfs. * * Return: 0 for success - * - **/ + */ int fc_set_mfs(struct fc_lport *lport, u32 mfs) { unsigned int old_mfs; @@ -706,7 +683,7 @@ int fc_set_mfs(struct fc_lport *lport, u32 mfs) EXPORT_SYMBOL(fc_set_mfs); /** - * fc_lport_disc_callback - Callback for discovery events + * fc_lport_disc_callback() - Callback for discovery events * @lport: FC local port * @event: The discovery event */ @@ -731,7 +708,7 @@ void fc_lport_disc_callback(struct fc_lport *lport, enum fc_disc_event event) } /** - * fc_rport_enter_ready - Enter the ready state and start discovery + * fc_rport_enter_ready() - Enter the ready state and start discovery * @lport: Fibre Channel local port that is ready * * Locking Note: The lport lock is expected to be held before calling @@ -748,7 +725,7 @@ static void fc_lport_enter_ready(struct fc_lport *lport) } /** - * fc_lport_recv_flogi_req - Receive a FLOGI request + * fc_lport_recv_flogi_req() - Receive a FLOGI request * @sp_in: The sequence the FLOGI is on * @rx_fp: The frame the FLOGI is in * @lport: The lport that recieved the request @@ -786,10 +763,11 @@ static void fc_lport_recv_flogi_req(struct fc_seq *sp_in, remote_wwpn = get_unaligned_be64(&flp->fl_wwpn); if (remote_wwpn == lport->wwpn) { FC_DBG("FLOGI from port with same WWPN %llx " - "possible configuration error\n", remote_wwpn); + "possible configuration error\n", + (unsigned long long)remote_wwpn); goto out; } - FC_DBG("FLOGI from port WWPN %llx\n", remote_wwpn); + FC_DBG("FLOGI from port WWPN %llx\n", (unsigned long long)remote_wwpn); /* * XXX what is the right thing to do for FIDs? @@ -838,7 +816,7 @@ out: } /** - * fc_lport_recv_req - The generic lport request handler + * fc_lport_recv_req() - The generic lport request handler * @lport: The lport that received the request * @sp: The sequence the request is on * @fp: The frame the request is in @@ -934,7 +912,7 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp, } /** - * fc_lport_reset - Reset an lport + * fc_lport_reset() - Reset an lport * @lport: The lport which should be reset * * Locking Note: This functions should not be called with the @@ -942,6 +920,7 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp, */ int fc_lport_reset(struct fc_lport *lport) { + cancel_delayed_work_sync(&lport->retry_work); mutex_lock(&lport->lp_mutex); fc_lport_enter_reset(lport); mutex_unlock(&lport->lp_mutex); @@ -950,7 +929,7 @@ int fc_lport_reset(struct fc_lport *lport) EXPORT_SYMBOL(fc_lport_reset); /** - * fc_rport_enter_reset - Reset the local port + * fc_rport_enter_reset() - Reset the local port * @lport: Fibre Channel local port to be reset * * Locking Note: The lport lock is expected to be held before calling @@ -973,16 +952,16 @@ static void fc_lport_enter_reset(struct fc_lport *lport) lport->tt.disc_stop(lport); - lport->tt.exch_mgr_reset(lport->emp, 0, 0); + lport->tt.exch_mgr_reset(lport, 0, 0); fc_host_fabric_name(lport->host) = 0; fc_host_port_id(lport->host) = 0; - if ((lport->link_status & FC_LINK_UP) == FC_LINK_UP) + if (lport->link_up) fc_lport_enter_flogi(lport); } /** - * fc_lport_error - Handler for any errors + * fc_lport_error() - Handler for any errors * @lport: The fc_lport object * @fp: The frame pointer * @@ -1029,8 +1008,8 @@ static void fc_lport_error(struct fc_lport *lport, struct fc_frame *fp) } /** - * fc_lport_rft_id_resp - Handle response to Register Fibre - * Channel Types by ID (RPN_ID) request + * fc_lport_rft_id_resp() - Handle response to Register Fibre + * Channel Types by ID (RPN_ID) request * @sp: current sequence in RPN_ID exchange * @fp: response frame * @lp_arg: Fibre Channel host port instance @@ -1053,17 +1032,17 @@ static void fc_lport_rft_id_resp(struct fc_seq *sp, struct fc_frame *fp, FC_DEBUG_LPORT("Received a RFT_ID response\n"); + if (IS_ERR(fp)) { + fc_lport_error(lport, fp); + goto err; + } + if (lport->state != LPORT_ST_RFT_ID) { FC_DBG("Received a RFT_ID response, but in state %s\n", fc_lport_state(lport)); goto out; } - if (IS_ERR(fp)) { - fc_lport_error(lport, fp); - goto err; - } - fh = fc_frame_header_get(fp); ct = fc_frame_payload_get(fp, sizeof(*ct)); @@ -1081,8 +1060,8 @@ err: } /** - * fc_lport_rpn_id_resp - Handle response to Register Port - * Name by ID (RPN_ID) request + * fc_lport_rpn_id_resp() - Handle response to Register Port + * Name by ID (RPN_ID) request * @sp: current sequence in RPN_ID exchange * @fp: response frame * @lp_arg: Fibre Channel host port instance @@ -1105,17 +1084,17 @@ static void fc_lport_rpn_id_resp(struct fc_seq *sp, struct fc_frame *fp, FC_DEBUG_LPORT("Received a RPN_ID response\n"); + if (IS_ERR(fp)) { + fc_lport_error(lport, fp); + goto err; + } + if (lport->state != LPORT_ST_RPN_ID) { FC_DBG("Received a RPN_ID response, but in state %s\n", fc_lport_state(lport)); goto out; } - if (IS_ERR(fp)) { - fc_lport_error(lport, fp); - goto err; - } - fh = fc_frame_header_get(fp); ct = fc_frame_payload_get(fp, sizeof(*ct)); if (fh && ct && fh->fh_type == FC_TYPE_CT && @@ -1133,7 +1112,7 @@ err: } /** - * fc_lport_scr_resp - Handle response to State Change Register (SCR) request + * fc_lport_scr_resp() - Handle response to State Change Register (SCR) request * @sp: current sequence in SCR exchange * @fp: response frame * @lp_arg: Fibre Channel lport port instance that sent the registration request @@ -1155,17 +1134,17 @@ static void fc_lport_scr_resp(struct fc_seq *sp, struct fc_frame *fp, FC_DEBUG_LPORT("Received a SCR response\n"); + if (IS_ERR(fp)) { + fc_lport_error(lport, fp); + goto err; + } + if (lport->state != LPORT_ST_SCR) { FC_DBG("Received a SCR response, but in state %s\n", fc_lport_state(lport)); goto out; } - if (IS_ERR(fp)) { - fc_lport_error(lport, fp); - goto err; - } - op = fc_frame_payload_op(fp); if (op == ELS_LS_ACC) fc_lport_enter_ready(lport); @@ -1179,7 +1158,7 @@ err: } /** - * fc_lport_enter_scr - Send a State Change Register (SCR) request + * fc_lport_enter_scr() - Send a State Change Register (SCR) request * @lport: Fibre Channel local port to register for state changes * * Locking Note: The lport lock is expected to be held before calling @@ -1206,7 +1185,7 @@ static void fc_lport_enter_scr(struct fc_lport *lport) } /** - * fc_lport_enter_rft_id - Register FC4-types with the name server + * fc_lport_enter_rft_id() - Register FC4-types with the name server * @lport: Fibre Channel local port to register * * Locking Note: The lport lock is expected to be held before calling @@ -1248,7 +1227,7 @@ static void fc_lport_enter_rft_id(struct fc_lport *lport) } /** - * fc_rport_enter_rft_id - Register port name with the name server + * fc_rport_enter_rft_id() - Register port name with the name server * @lport: Fibre Channel local port to register * * Locking Note: The lport lock is expected to be held before calling @@ -1281,7 +1260,7 @@ static struct fc_rport_operations fc_lport_rport_ops = { }; /** - * fc_rport_enter_dns - Create a rport to the name server + * fc_rport_enter_dns() - Create a rport to the name server * @lport: Fibre Channel local port requesting a rport for the name server * * Locking Note: The lport lock is expected to be held before calling @@ -1304,7 +1283,7 @@ static void fc_lport_enter_dns(struct fc_lport *lport) fc_lport_state_enter(lport, LPORT_ST_DNS); - rport = fc_rport_rogue_create(&dp); + rport = lport->tt.rport_create(&dp); if (!rport) goto err; @@ -1318,7 +1297,7 @@ err: } /** - * fc_lport_timeout - Handler for the retry_work timer. + * fc_lport_timeout() - Handler for the retry_work timer. * @work: The work struct of the fc_lport */ static void fc_lport_timeout(struct work_struct *work) @@ -1359,7 +1338,7 @@ static void fc_lport_timeout(struct work_struct *work) } /** - * fc_lport_logo_resp - Handle response to LOGO request + * fc_lport_logo_resp() - Handle response to LOGO request * @sp: current sequence in LOGO exchange * @fp: response frame * @lp_arg: Fibre Channel lport port instance that sent the LOGO request @@ -1381,17 +1360,17 @@ static void fc_lport_logo_resp(struct fc_seq *sp, struct fc_frame *fp, FC_DEBUG_LPORT("Received a LOGO response\n"); + if (IS_ERR(fp)) { + fc_lport_error(lport, fp); + goto err; + } + if (lport->state != LPORT_ST_LOGO) { FC_DBG("Received a LOGO response, but in state %s\n", fc_lport_state(lport)); goto out; } - if (IS_ERR(fp)) { - fc_lport_error(lport, fp); - goto err; - } - op = fc_frame_payload_op(fp); if (op == ELS_LS_ACC) fc_lport_enter_reset(lport); @@ -1405,7 +1384,7 @@ err: } /** - * fc_rport_enter_logo - Logout of the fabric + * fc_rport_enter_logo() - Logout of the fabric * @lport: Fibre Channel local port to be logged out * * Locking Note: The lport lock is expected to be held before calling @@ -1437,7 +1416,7 @@ static void fc_lport_enter_logo(struct fc_lport *lport) } /** - * fc_lport_flogi_resp - Handle response to FLOGI request + * fc_lport_flogi_resp() - Handle response to FLOGI request * @sp: current sequence in FLOGI exchange * @fp: response frame * @lp_arg: Fibre Channel lport port instance that sent the FLOGI request @@ -1465,17 +1444,17 @@ static void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp, FC_DEBUG_LPORT("Received a FLOGI response\n"); + if (IS_ERR(fp)) { + fc_lport_error(lport, fp); + goto err; + } + if (lport->state != LPORT_ST_FLOGI) { FC_DBG("Received a FLOGI response, but in state %s\n", fc_lport_state(lport)); goto out; } - if (IS_ERR(fp)) { - fc_lport_error(lport, fp); - goto err; - } - fh = fc_frame_header_get(fp); did = ntoh24(fh->fh_d_id); if (fc_frame_payload_op(fp) == ELS_LS_ACC && did != 0) { @@ -1532,7 +1511,7 @@ err: } /** - * fc_rport_enter_flogi - Send a FLOGI request to the fabric manager + * fc_rport_enter_flogi() - Send a FLOGI request to the fabric manager * @lport: Fibre Channel local port to be logged in to the fabric * * Locking Note: The lport lock is expected to be held before calling diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index e780d8caf70..0472bb73221 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -81,6 +81,7 @@ static void fc_rport_recv_logo_req(struct fc_rport *, struct fc_seq *, struct fc_frame *); static void fc_rport_timeout(struct work_struct *); static void fc_rport_error(struct fc_rport *, struct fc_frame *); +static void fc_rport_error_retry(struct fc_rport *, struct fc_frame *); static void fc_rport_work(struct work_struct *); static const char *fc_rport_state_names[] = { @@ -145,7 +146,7 @@ struct fc_rport *fc_rport_rogue_create(struct fc_disc_port *dp) } /** - * fc_rport_state - return a string for the state the rport is in + * fc_rport_state() - return a string for the state the rport is in * @rport: The rport whose state we want to get a string for */ static const char *fc_rport_state(struct fc_rport *rport) @@ -160,7 +161,7 @@ static const char *fc_rport_state(struct fc_rport *rport) } /** - * fc_set_rport_loss_tmo - Set the remote port loss timeout in seconds. + * fc_set_rport_loss_tmo() - Set the remote port loss timeout in seconds. * @rport: Pointer to Fibre Channel remote port structure * @timeout: timeout in seconds */ @@ -174,12 +175,12 @@ void fc_set_rport_loss_tmo(struct fc_rport *rport, u32 timeout) EXPORT_SYMBOL(fc_set_rport_loss_tmo); /** - * fc_plogi_get_maxframe - Get max payload from the common service parameters + * fc_plogi_get_maxframe() - Get max payload from the common service parameters * @flp: FLOGI payload structure * @maxval: upper limit, may be less than what is in the service parameters */ -static unsigned int -fc_plogi_get_maxframe(struct fc_els_flogi *flp, unsigned int maxval) +static unsigned int fc_plogi_get_maxframe(struct fc_els_flogi *flp, + unsigned int maxval) { unsigned int mfs; @@ -197,7 +198,7 @@ fc_plogi_get_maxframe(struct fc_els_flogi *flp, unsigned int maxval) } /** - * fc_rport_state_enter - Change the rport's state + * fc_rport_state_enter() - Change the rport's state * @rport: The rport whose state should change * @new: The new state of the rport * @@ -214,6 +215,7 @@ static void fc_rport_state_enter(struct fc_rport *rport, static void fc_rport_work(struct work_struct *work) { + u32 port_id; struct fc_rport_libfc_priv *rdata = container_of(work, struct fc_rport_libfc_priv, event_work); enum fc_rport_event event; @@ -279,14 +281,18 @@ static void fc_rport_work(struct work_struct *work) rport_ops->event_callback(lport, rport, event); if (trans_state == FC_PORTSTATE_ROGUE) put_device(&rport->dev); - else + else { + port_id = rport->port_id; fc_remote_port_delete(rport); + lport->tt.exch_mgr_reset(lport, 0, port_id); + lport->tt.exch_mgr_reset(lport, port_id, 0); + } } else mutex_unlock(&rdata->rp_mutex); } /** - * fc_rport_login - Start the remote port login state machine + * fc_rport_login() - Start the remote port login state machine * @rport: Fibre Channel remote port * * Locking Note: Called without the rport lock held. This @@ -309,7 +315,7 @@ int fc_rport_login(struct fc_rport *rport) } /** - * fc_rport_logoff - Logoff and remove an rport + * fc_rport_logoff() - Logoff and remove an rport * @rport: Fibre Channel remote port to be removed * * Locking Note: Called without the rport lock held. This @@ -347,7 +353,7 @@ int fc_rport_logoff(struct fc_rport *rport) } /** - * fc_rport_enter_ready - The rport is ready + * fc_rport_enter_ready() - The rport is ready * @rport: Fibre Channel remote port that is ready * * Locking Note: The rport lock is expected to be held before calling @@ -366,7 +372,7 @@ static void fc_rport_enter_ready(struct fc_rport *rport) } /** - * fc_rport_timeout - Handler for the retry_work timer. + * fc_rport_timeout() - Handler for the retry_work timer. * @work: The work struct of the fc_rport_libfc_priv * * Locking Note: Called without the rport lock held. This @@ -405,59 +411,75 @@ static void fc_rport_timeout(struct work_struct *work) } /** - * fc_rport_error - Handler for any errors + * fc_rport_error() - Error handler, called once retries have been exhausted * @rport: The fc_rport object * @fp: The frame pointer * - * If the error was caused by a resource allocation failure - * then wait for half a second and retry, otherwise retry - * immediately. - * * Locking Note: The rport lock is expected to be held before * calling this routine */ static void fc_rport_error(struct fc_rport *rport, struct fc_frame *fp) { struct fc_rport_libfc_priv *rdata = rport->dd_data; - unsigned long delay = 0; FC_DEBUG_RPORT("Error %ld in state %s, retries %d\n", PTR_ERR(fp), fc_rport_state(rport), rdata->retries); - if (!fp || PTR_ERR(fp) == -FC_EX_TIMEOUT) { - /* - * Memory allocation failure, or the exchange timed out. - * Retry after delay - */ - if (rdata->retries < rdata->local_port->max_retry_count) { - rdata->retries++; - if (!fp) - delay = msecs_to_jiffies(500); - get_device(&rport->dev); - schedule_delayed_work(&rdata->retry_work, delay); - } else { - switch (rdata->rp_state) { - case RPORT_ST_PLOGI: - case RPORT_ST_PRLI: - case RPORT_ST_LOGO: - rdata->event = RPORT_EV_FAILED; - queue_work(rport_event_queue, - &rdata->event_work); - break; - case RPORT_ST_RTV: - fc_rport_enter_ready(rport); - break; - case RPORT_ST_NONE: - case RPORT_ST_READY: - case RPORT_ST_INIT: - break; - } - } + switch (rdata->rp_state) { + case RPORT_ST_PLOGI: + case RPORT_ST_PRLI: + case RPORT_ST_LOGO: + rdata->event = RPORT_EV_FAILED; + queue_work(rport_event_queue, + &rdata->event_work); + break; + case RPORT_ST_RTV: + fc_rport_enter_ready(rport); + break; + case RPORT_ST_NONE: + case RPORT_ST_READY: + case RPORT_ST_INIT: + break; } } /** - * fc_rport_plogi_recv_resp - Handle incoming ELS PLOGI response + * fc_rport_error_retry() - Error handler when retries are desired + * @rport: The fc_rport object + * @fp: The frame pointer + * + * If the error was an exchange timeout retry immediately, + * otherwise wait for E_D_TOV. + * + * Locking Note: The rport lock is expected to be held before + * calling this routine + */ +static void fc_rport_error_retry(struct fc_rport *rport, struct fc_frame *fp) +{ + struct fc_rport_libfc_priv *rdata = rport->dd_data; + unsigned long delay = FC_DEF_E_D_TOV; + + /* make sure this isn't an FC_EX_CLOSED error, never retry those */ + if (PTR_ERR(fp) == -FC_EX_CLOSED) + return fc_rport_error(rport, fp); + + if (rdata->retries < rdata->local_port->max_retry_count) { + FC_DEBUG_RPORT("Error %ld in state %s, retrying\n", + PTR_ERR(fp), fc_rport_state(rport)); + rdata->retries++; + /* no additional delay on exchange timeouts */ + if (PTR_ERR(fp) == -FC_EX_TIMEOUT) + delay = 0; + get_device(&rport->dev); + schedule_delayed_work(&rdata->retry_work, delay); + return; + } + + return fc_rport_error(rport, fp); +} + +/** + * fc_rport_plogi_recv_resp() - Handle incoming ELS PLOGI response * @sp: current sequence in the PLOGI exchange * @fp: response frame * @rp_arg: Fibre Channel remote port @@ -483,17 +505,17 @@ static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp, FC_DEBUG_RPORT("Received a PLOGI response from port (%6x)\n", rport->port_id); + if (IS_ERR(fp)) { + fc_rport_error_retry(rport, fp); + goto err; + } + if (rdata->rp_state != RPORT_ST_PLOGI) { FC_DBG("Received a PLOGI response, but in state %s\n", fc_rport_state(rport)); goto out; } - if (IS_ERR(fp)) { - fc_rport_error(rport, fp); - goto err; - } - op = fc_frame_payload_op(fp); if (op == ELS_LS_ACC && (plp = fc_frame_payload_get(fp, sizeof(*plp))) != NULL) { @@ -522,7 +544,7 @@ static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp, else fc_rport_enter_prli(rport); } else - fc_rport_error(rport, fp); + fc_rport_error_retry(rport, fp); out: fc_frame_free(fp); @@ -532,7 +554,7 @@ err: } /** - * fc_rport_enter_plogi - Send Port Login (PLOGI) request to peer + * fc_rport_enter_plogi() - Send Port Login (PLOGI) request to peer * @rport: Fibre Channel remote port to send PLOGI to * * Locking Note: The rport lock is expected to be held before calling @@ -552,20 +574,20 @@ static void fc_rport_enter_plogi(struct fc_rport *rport) rport->maxframe_size = FC_MIN_MAX_PAYLOAD; fp = fc_frame_alloc(lport, sizeof(struct fc_els_flogi)); if (!fp) { - fc_rport_error(rport, fp); + fc_rport_error_retry(rport, fp); return; } rdata->e_d_tov = lport->e_d_tov; if (!lport->tt.elsct_send(lport, rport, fp, ELS_PLOGI, fc_rport_plogi_resp, rport, lport->e_d_tov)) - fc_rport_error(rport, fp); + fc_rport_error_retry(rport, fp); else get_device(&rport->dev); } /** - * fc_rport_prli_resp - Process Login (PRLI) response handler + * fc_rport_prli_resp() - Process Login (PRLI) response handler * @sp: current sequence in the PRLI exchange * @fp: response frame * @rp_arg: Fibre Channel remote port @@ -592,17 +614,17 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp, FC_DEBUG_RPORT("Received a PRLI response from port (%6x)\n", rport->port_id); + if (IS_ERR(fp)) { + fc_rport_error_retry(rport, fp); + goto err; + } + if (rdata->rp_state != RPORT_ST_PRLI) { FC_DBG("Received a PRLI response, but in state %s\n", fc_rport_state(rport)); goto out; } - if (IS_ERR(fp)) { - fc_rport_error(rport, fp); - goto err; - } - op = fc_frame_payload_op(fp); if (op == ELS_LS_ACC) { pp = fc_frame_payload_get(fp, sizeof(*pp)); @@ -635,7 +657,7 @@ err: } /** - * fc_rport_logo_resp - Logout (LOGO) response handler + * fc_rport_logo_resp() - Logout (LOGO) response handler * @sp: current sequence in the LOGO exchange * @fp: response frame * @rp_arg: Fibre Channel remote port @@ -657,7 +679,7 @@ static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp, rport->port_id); if (IS_ERR(fp)) { - fc_rport_error(rport, fp); + fc_rport_error_retry(rport, fp); goto err; } @@ -684,7 +706,7 @@ err: } /** - * fc_rport_enter_prli - Send Process Login (PRLI) request to peer + * fc_rport_enter_prli() - Send Process Login (PRLI) request to peer * @rport: Fibre Channel remote port to send PRLI to * * Locking Note: The rport lock is expected to be held before calling @@ -707,19 +729,19 @@ static void fc_rport_enter_prli(struct fc_rport *rport) fp = fc_frame_alloc(lport, sizeof(*pp)); if (!fp) { - fc_rport_error(rport, fp); + fc_rport_error_retry(rport, fp); return; } if (!lport->tt.elsct_send(lport, rport, fp, ELS_PRLI, fc_rport_prli_resp, rport, lport->e_d_tov)) - fc_rport_error(rport, fp); + fc_rport_error_retry(rport, fp); else get_device(&rport->dev); } /** - * fc_rport_els_rtv_resp - Request Timeout Value response handler + * fc_rport_els_rtv_resp() - Request Timeout Value response handler * @sp: current sequence in the RTV exchange * @fp: response frame * @rp_arg: Fibre Channel remote port @@ -742,17 +764,17 @@ static void fc_rport_rtv_resp(struct fc_seq *sp, struct fc_frame *fp, FC_DEBUG_RPORT("Received a RTV response from port (%6x)\n", rport->port_id); + if (IS_ERR(fp)) { + fc_rport_error(rport, fp); + goto err; + } + if (rdata->rp_state != RPORT_ST_RTV) { FC_DBG("Received a RTV response, but in state %s\n", fc_rport_state(rport)); goto out; } - if (IS_ERR(fp)) { - fc_rport_error(rport, fp); - goto err; - } - op = fc_frame_payload_op(fp); if (op == ELS_LS_ACC) { struct fc_els_rtv_acc *rtv; @@ -785,7 +807,7 @@ err: } /** - * fc_rport_enter_rtv - Send Request Timeout Value (RTV) request to peer + * fc_rport_enter_rtv() - Send Request Timeout Value (RTV) request to peer * @rport: Fibre Channel remote port to send RTV to * * Locking Note: The rport lock is expected to be held before calling @@ -804,19 +826,19 @@ static void fc_rport_enter_rtv(struct fc_rport *rport) fp = fc_frame_alloc(lport, sizeof(struct fc_els_rtv)); if (!fp) { - fc_rport_error(rport, fp); + fc_rport_error_retry(rport, fp); return; } if (!lport->tt.elsct_send(lport, rport, fp, ELS_RTV, fc_rport_rtv_resp, rport, lport->e_d_tov)) - fc_rport_error(rport, fp); + fc_rport_error_retry(rport, fp); else get_device(&rport->dev); } /** - * fc_rport_enter_logo - Send Logout (LOGO) request to peer + * fc_rport_enter_logo() - Send Logout (LOGO) request to peer * @rport: Fibre Channel remote port to send LOGO to * * Locking Note: The rport lock is expected to be held before calling @@ -835,20 +857,20 @@ static void fc_rport_enter_logo(struct fc_rport *rport) fp = fc_frame_alloc(lport, sizeof(struct fc_els_logo)); if (!fp) { - fc_rport_error(rport, fp); + fc_rport_error_retry(rport, fp); return; } if (!lport->tt.elsct_send(lport, rport, fp, ELS_LOGO, fc_rport_logo_resp, rport, lport->e_d_tov)) - fc_rport_error(rport, fp); + fc_rport_error_retry(rport, fp); else get_device(&rport->dev); } /** - * fc_rport_recv_req - Receive a request from a rport + * fc_rport_recv_req() - Receive a request from a rport * @sp: current sequence in the PLOGI exchange * @fp: response frame * @rp_arg: Fibre Channel remote port @@ -909,7 +931,7 @@ void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, } /** - * fc_rport_recv_plogi_req - Handle incoming Port Login (PLOGI) request + * fc_rport_recv_plogi_req() - Handle incoming Port Login (PLOGI) request * @rport: Fibre Channel remote port that initiated PLOGI * @sp: current sequence in the PLOGI exchange * @fp: PLOGI request frame @@ -966,7 +988,7 @@ static void fc_rport_recv_plogi_req(struct fc_rport *rport, switch (rdata->rp_state) { case RPORT_ST_INIT: FC_DEBUG_RPORT("incoming PLOGI from %6x wwpn %llx state INIT " - "- reject\n", sid, wwpn); + "- reject\n", sid, (unsigned long long)wwpn); reject = ELS_RJT_UNSUP; break; case RPORT_ST_PLOGI: @@ -1031,7 +1053,7 @@ static void fc_rport_recv_plogi_req(struct fc_rport *rport, } /** - * fc_rport_recv_prli_req - Handle incoming Process Login (PRLI) request + * fc_rport_recv_prli_req() - Handle incoming Process Login (PRLI) request * @rport: Fibre Channel remote port that initiated PRLI * @sp: current sequence in the PRLI exchange * @fp: PRLI request frame @@ -1182,7 +1204,7 @@ static void fc_rport_recv_prli_req(struct fc_rport *rport, } /** - * fc_rport_recv_prlo_req - Handle incoming Process Logout (PRLO) request + * fc_rport_recv_prlo_req() - Handle incoming Process Logout (PRLO) request * @rport: Fibre Channel remote port that initiated PRLO * @sp: current sequence in the PRLO exchange * @fp: PRLO request frame @@ -1213,7 +1235,7 @@ static void fc_rport_recv_prlo_req(struct fc_rport *rport, struct fc_seq *sp, } /** - * fc_rport_recv_logo_req - Handle incoming Logout (LOGO) request + * fc_rport_recv_logo_req() - Handle incoming Logout (LOGO) request * @rport: Fibre Channel remote port that initiated LOGO * @sp: current sequence in the LOGO exchange * @fp: LOGO request frame @@ -1249,6 +1271,9 @@ static void fc_rport_flush_queue(void) int fc_rport_init(struct fc_lport *lport) { + if (!lport->tt.rport_create) + lport->tt.rport_create = fc_rport_rogue_create; + if (!lport->tt.rport_login) lport->tt.rport_login = fc_rport_login; @@ -1285,7 +1310,7 @@ void fc_rport_terminate_io(struct fc_rport *rport) struct fc_rport_libfc_priv *rdata = rport->dd_data; struct fc_lport *lport = rdata->local_port; - lport->tt.exch_mgr_reset(lport->emp, 0, rport->port_id); - lport->tt.exch_mgr_reset(lport->emp, rport->port_id, 0); + lport->tt.exch_mgr_reset(lport, 0, rport->port_id); + lport->tt.exch_mgr_reset(lport, rport->port_id, 0); } EXPORT_SYMBOL(fc_rport_terminate_io); diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 257c24115de..68962835916 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -38,6 +38,28 @@ #include <scsi/scsi_transport_iscsi.h> #include <scsi/libiscsi.h> +static int iscsi_dbg_lib; +module_param_named(debug_libiscsi, iscsi_dbg_lib, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug_libiscsi, "Turn on debugging for libiscsi module. " + "Set to 1 to turn on, and zero to turn off. Default " + "is off."); + +#define ISCSI_DBG_CONN(_conn, dbg_fmt, arg...) \ + do { \ + if (iscsi_dbg_lib) \ + iscsi_conn_printk(KERN_INFO, _conn, \ + "%s " dbg_fmt, \ + __func__, ##arg); \ + } while (0); + +#define ISCSI_DBG_SESSION(_session, dbg_fmt, arg...) \ + do { \ + if (iscsi_dbg_lib) \ + iscsi_session_printk(KERN_INFO, _session, \ + "%s " dbg_fmt, \ + __func__, ##arg); \ + } while (0); + /* Serial Number Arithmetic, 32 bits, less than, RFC1982 */ #define SNA32_CHECK 2147483648UL @@ -54,6 +76,15 @@ static int iscsi_sna_lte(u32 n1, u32 n2) (n1 > n2 && (n2 - n1 < SNA32_CHECK))); } +inline void iscsi_conn_queue_work(struct iscsi_conn *conn) +{ + struct Scsi_Host *shost = conn->session->host; + struct iscsi_host *ihost = shost_priv(shost); + + queue_work(ihost->workq, &conn->xmitwork); +} +EXPORT_SYMBOL_GPL(iscsi_conn_queue_work); + void iscsi_update_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr) { @@ -81,8 +112,7 @@ iscsi_update_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr) if (!list_empty(&session->leadconn->xmitqueue) || !list_empty(&session->leadconn->mgmtqueue)) { if (!(session->tt->caps & CAP_DATA_PATH_OFFLOAD)) - scsi_queue_work(session->host, - &session->leadconn->xmitwork); + iscsi_conn_queue_work(session->leadconn); } } } @@ -176,10 +206,11 @@ static int iscsi_prep_ecdb_ahs(struct iscsi_task *task) ecdb_ahdr->reserved = 0; memcpy(ecdb_ahdr->ecdb, cmd->cmnd + ISCSI_CDB_SIZE, rlen); - debug_scsi("iscsi_prep_ecdb_ahs: varlen_cdb_len %d " - "rlen %d pad_len %d ahs_length %d iscsi_headers_size %u\n", - cmd->cmd_len, rlen, pad_len, ahslength, task->hdr_len); - + ISCSI_DBG_SESSION(task->conn->session, + "iscsi_prep_ecdb_ahs: varlen_cdb_len %d " + "rlen %d pad_len %d ahs_length %d iscsi_headers_size " + "%u\n", cmd->cmd_len, rlen, pad_len, ahslength, + task->hdr_len); return 0; } @@ -201,10 +232,11 @@ static int iscsi_prep_bidi_ahs(struct iscsi_task *task) rlen_ahdr->reserved = 0; rlen_ahdr->read_length = cpu_to_be32(scsi_in(sc)->length); - debug_scsi("bidi-in rlen_ahdr->read_length(%d) " - "rlen_ahdr->ahslength(%d)\n", - be32_to_cpu(rlen_ahdr->read_length), - be16_to_cpu(rlen_ahdr->ahslength)); + ISCSI_DBG_SESSION(task->conn->session, + "bidi-in rlen_ahdr->read_length(%d) " + "rlen_ahdr->ahslength(%d)\n", + be32_to_cpu(rlen_ahdr->read_length), + be16_to_cpu(rlen_ahdr->ahslength)); return 0; } @@ -335,13 +367,15 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task) list_move_tail(&task->running, &conn->run_list); conn->scsicmd_pdus_cnt++; - debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x len %d " - "bidi_len %d cmdsn %d win %d]\n", scsi_bidi_cmnd(sc) ? - "bidirectional" : sc->sc_data_direction == DMA_TO_DEVICE ? - "write" : "read", conn->id, sc, sc->cmnd[0], task->itt, - scsi_bufflen(sc), - scsi_bidi_cmnd(sc) ? scsi_in(sc)->length : 0, - session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1); + ISCSI_DBG_SESSION(session, "iscsi prep [%s cid %d sc %p cdb 0x%x " + "itt 0x%x len %d bidi_len %d cmdsn %d win %d]\n", + scsi_bidi_cmnd(sc) ? "bidirectional" : + sc->sc_data_direction == DMA_TO_DEVICE ? + "write" : "read", conn->id, sc, sc->cmnd[0], + task->itt, scsi_bufflen(sc), + scsi_bidi_cmnd(sc) ? scsi_in(sc)->length : 0, + session->cmdsn, + session->max_cmdsn - session->exp_cmdsn + 1); return 0; } @@ -483,9 +517,9 @@ static int iscsi_prep_mgmt_task(struct iscsi_conn *conn, task->state = ISCSI_TASK_RUNNING; list_move_tail(&task->running, &conn->mgmt_run_list); - debug_scsi("mgmtpdu [op 0x%x hdr->itt 0x%x datalen %d]\n", - hdr->opcode & ISCSI_OPCODE_MASK, hdr->itt, - task->data_count); + ISCSI_DBG_SESSION(session, "mgmtpdu [op 0x%x hdr->itt 0x%x " + "datalen %d]\n", hdr->opcode & ISCSI_OPCODE_MASK, + hdr->itt, task->data_count); return 0; } @@ -560,7 +594,7 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, goto free_task; } else - scsi_queue_work(conn->session->host, &conn->xmitwork); + iscsi_conn_queue_work(conn); return task; @@ -637,8 +671,9 @@ invalid_datalen: memcpy(sc->sense_buffer, data + 2, min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE)); - debug_scsi("copied %d bytes of sense\n", - min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE)); + ISCSI_DBG_SESSION(session, "copied %d bytes of sense\n", + min_t(uint16_t, senselen, + SCSI_SENSE_BUFFERSIZE)); } if (rhdr->flags & (ISCSI_FLAG_CMD_BIDI_UNDERFLOW | @@ -666,8 +701,8 @@ invalid_datalen: sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status; } out: - debug_scsi("done [sc %lx res %d itt 0x%x]\n", - (long)sc, sc->result, task->itt); + ISCSI_DBG_SESSION(session, "done [sc %p res %d itt 0x%x]\n", + sc, sc->result, task->itt); conn->scsirsp_pdus_cnt++; __iscsi_put_task(task); @@ -835,8 +870,8 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, else itt = ~0U; - debug_scsi("[op 0x%x cid %d itt 0x%x len %d]\n", - opcode, conn->id, itt, datalen); + ISCSI_DBG_SESSION(session, "[op 0x%x cid %d itt 0x%x len %d]\n", + opcode, conn->id, itt, datalen); if (itt == ~0U) { iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr); @@ -1034,10 +1069,9 @@ struct iscsi_task *iscsi_itt_to_ctask(struct iscsi_conn *conn, itt_t itt) } EXPORT_SYMBOL_GPL(iscsi_itt_to_ctask); -void iscsi_session_failure(struct iscsi_cls_session *cls_session, +void iscsi_session_failure(struct iscsi_session *session, enum iscsi_err err) { - struct iscsi_session *session = cls_session->dd_data; struct iscsi_conn *conn; struct device *dev; unsigned long flags; @@ -1095,10 +1129,10 @@ static int iscsi_check_cmdsn_window_closed(struct iscsi_conn *conn) * Check for iSCSI window and take care of CmdSN wrap-around */ if (!iscsi_sna_lte(session->queued_cmdsn, session->max_cmdsn)) { - debug_scsi("iSCSI CmdSN closed. ExpCmdSn %u MaxCmdSN %u " - "CmdSN %u/%u\n", session->exp_cmdsn, - session->max_cmdsn, session->cmdsn, - session->queued_cmdsn); + ISCSI_DBG_SESSION(session, "iSCSI CmdSN closed. ExpCmdSn " + "%u MaxCmdSN %u CmdSN %u/%u\n", + session->exp_cmdsn, session->max_cmdsn, + session->cmdsn, session->queued_cmdsn); return -ENOSPC; } return 0; @@ -1133,7 +1167,7 @@ void iscsi_requeue_task(struct iscsi_task *task) struct iscsi_conn *conn = task->conn; list_move_tail(&task->running, &conn->requeue); - scsi_queue_work(conn->session->host, &conn->xmitwork); + iscsi_conn_queue_work(conn); } EXPORT_SYMBOL_GPL(iscsi_requeue_task); @@ -1152,7 +1186,7 @@ static int iscsi_data_xmit(struct iscsi_conn *conn) spin_lock_bh(&conn->session->lock); if (unlikely(conn->suspend_tx)) { - debug_scsi("conn %d Tx suspended!\n", conn->id); + ISCSI_DBG_SESSION(conn->session, "Tx suspended!\n"); spin_unlock_bh(&conn->session->lock); return -ENODATA; } @@ -1386,7 +1420,7 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) goto prepd_reject; } } else - scsi_queue_work(session->host, &conn->xmitwork); + iscsi_conn_queue_work(conn); session->queued_cmdsn++; spin_unlock(&session->lock); @@ -1398,7 +1432,8 @@ prepd_reject: iscsi_complete_command(task); reject: spin_unlock(&session->lock); - debug_scsi("cmd 0x%x rejected (%d)\n", sc->cmnd[0], reason); + ISCSI_DBG_SESSION(session, "cmd 0x%x rejected (%d)\n", + sc->cmnd[0], reason); spin_lock(host->host_lock); return SCSI_MLQUEUE_TARGET_BUSY; @@ -1407,7 +1442,8 @@ prepd_fault: iscsi_complete_command(task); fault: spin_unlock(&session->lock); - debug_scsi("iscsi: cmd 0x%x is not queued (%d)\n", sc->cmnd[0], reason); + ISCSI_DBG_SESSION(session, "iscsi: cmd 0x%x is not queued (%d)\n", + sc->cmnd[0], reason); if (!scsi_bidi_cmnd(sc)) scsi_set_resid(sc, scsi_bufflen(sc)); else { @@ -1422,8 +1458,6 @@ EXPORT_SYMBOL_GPL(iscsi_queuecommand); int iscsi_change_queue_depth(struct scsi_device *sdev, int depth) { - if (depth > ISCSI_MAX_CMD_PER_LUN) - depth = ISCSI_MAX_CMD_PER_LUN; scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth); return sdev->queue_depth; } @@ -1457,8 +1491,10 @@ int iscsi_eh_target_reset(struct scsi_cmnd *sc) spin_lock_bh(&session->lock); if (session->state == ISCSI_STATE_TERMINATE) { failed: - debug_scsi("failing target reset: session terminated " - "[CID %d age %d]\n", conn->id, session->age); + iscsi_session_printk(KERN_INFO, session, + "failing target reset: Could not log " + "back into target [age %d]\n", + session->age); spin_unlock_bh(&session->lock); mutex_unlock(&session->eh_mutex); return FAILED; @@ -1472,7 +1508,7 @@ failed: */ iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); - debug_scsi("iscsi_eh_target_reset wait for relogin\n"); + ISCSI_DBG_SESSION(session, "wait for relogin\n"); wait_event_interruptible(conn->ehwait, session->state == ISCSI_STATE_TERMINATE || session->state == ISCSI_STATE_LOGGED_IN || @@ -1501,7 +1537,7 @@ static void iscsi_tmf_timedout(unsigned long data) spin_lock(&session->lock); if (conn->tmf_state == TMF_QUEUED) { conn->tmf_state = TMF_TIMEDOUT; - debug_scsi("tmf timedout\n"); + ISCSI_DBG_SESSION(session, "tmf timedout\n"); /* unblock eh_abort() */ wake_up(&conn->ehwait); } @@ -1521,7 +1557,7 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn, spin_unlock_bh(&session->lock); iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); spin_lock_bh(&session->lock); - debug_scsi("tmf exec failure\n"); + ISCSI_DBG_SESSION(session, "tmf exec failure\n"); return -EPERM; } conn->tmfcmd_pdus_cnt++; @@ -1529,7 +1565,7 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn, conn->tmf_timer.function = iscsi_tmf_timedout; conn->tmf_timer.data = (unsigned long)conn; add_timer(&conn->tmf_timer); - debug_scsi("tmf set timeout\n"); + ISCSI_DBG_SESSION(session, "tmf set timeout\n"); spin_unlock_bh(&session->lock); mutex_unlock(&session->eh_mutex); @@ -1567,22 +1603,27 @@ static void fail_all_commands(struct iscsi_conn *conn, unsigned lun, { struct iscsi_task *task, *tmp; - if (conn->task && (conn->task->sc->device->lun == lun || lun == -1)) - conn->task = NULL; + if (conn->task) { + if (lun == -1 || + (conn->task->sc && conn->task->sc->device->lun == lun)) + conn->task = NULL; + } /* flush pending */ list_for_each_entry_safe(task, tmp, &conn->xmitqueue, running) { if (lun == task->sc->device->lun || lun == -1) { - debug_scsi("failing pending sc %p itt 0x%x\n", - task->sc, task->itt); + ISCSI_DBG_SESSION(conn->session, + "failing pending sc %p itt 0x%x\n", + task->sc, task->itt); fail_command(conn, task, error << 16); } } list_for_each_entry_safe(task, tmp, &conn->requeue, running) { if (lun == task->sc->device->lun || lun == -1) { - debug_scsi("failing requeued sc %p itt 0x%x\n", - task->sc, task->itt); + ISCSI_DBG_SESSION(conn->session, + "failing requeued sc %p itt 0x%x\n", + task->sc, task->itt); fail_command(conn, task, error << 16); } } @@ -1590,8 +1631,9 @@ static void fail_all_commands(struct iscsi_conn *conn, unsigned lun, /* fail all other running */ list_for_each_entry_safe(task, tmp, &conn->run_list, running) { if (lun == task->sc->device->lun || lun == -1) { - debug_scsi("failing in progress sc %p itt 0x%x\n", - task->sc, task->itt); + ISCSI_DBG_SESSION(conn->session, + "failing in progress sc %p itt 0x%x\n", + task->sc, task->itt); fail_command(conn, task, error << 16); } } @@ -1599,9 +1641,12 @@ static void fail_all_commands(struct iscsi_conn *conn, unsigned lun, void iscsi_suspend_tx(struct iscsi_conn *conn) { + struct Scsi_Host *shost = conn->session->host; + struct iscsi_host *ihost = shost_priv(shost); + set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); if (!(conn->session->tt->caps & CAP_DATA_PATH_OFFLOAD)) - scsi_flush_work(conn->session->host); + flush_workqueue(ihost->workq); } EXPORT_SYMBOL_GPL(iscsi_suspend_tx); @@ -1609,7 +1654,7 @@ static void iscsi_start_tx(struct iscsi_conn *conn) { clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); if (!(conn->session->tt->caps & CAP_DATA_PATH_OFFLOAD)) - scsi_queue_work(conn->session->host, &conn->xmitwork); + iscsi_conn_queue_work(conn); } static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd) @@ -1622,7 +1667,7 @@ static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd) cls_session = starget_to_session(scsi_target(scmd->device)); session = cls_session->dd_data; - debug_scsi("scsi cmd %p timedout\n", scmd); + ISCSI_DBG_SESSION(session, "scsi cmd %p timedout\n", scmd); spin_lock(&session->lock); if (session->state != ISCSI_STATE_LOGGED_IN) { @@ -1662,8 +1707,8 @@ static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd) rc = BLK_EH_RESET_TIMER; done: spin_unlock(&session->lock); - debug_scsi("return %s\n", rc == BLK_EH_RESET_TIMER ? - "timer reset" : "nh"); + ISCSI_DBG_SESSION(session, "return %s\n", rc == BLK_EH_RESET_TIMER ? + "timer reset" : "nh"); return rc; } @@ -1697,13 +1742,13 @@ static void iscsi_check_transport_timeouts(unsigned long data) if (time_before_eq(last_recv + recv_timeout, jiffies)) { /* send a ping to try to provoke some traffic */ - debug_scsi("Sending nopout as ping on conn %p\n", conn); + ISCSI_DBG_CONN(conn, "Sending nopout as ping\n"); iscsi_send_nopout(conn, NULL); next_timeout = conn->last_ping + (conn->ping_timeout * HZ); } else next_timeout = last_recv + recv_timeout; - debug_scsi("Setting next tmo %lu\n", next_timeout); + ISCSI_DBG_CONN(conn, "Setting next tmo %lu\n", next_timeout); mod_timer(&conn->transport_timer, next_timeout); done: spin_unlock(&session->lock); @@ -1740,7 +1785,8 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) * got the command. */ if (!sc->SCp.ptr) { - debug_scsi("sc never reached iscsi layer or it completed.\n"); + ISCSI_DBG_SESSION(session, "sc never reached iscsi layer or " + "it completed.\n"); spin_unlock_bh(&session->lock); mutex_unlock(&session->eh_mutex); return SUCCESS; @@ -1762,11 +1808,13 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) age = session->age; task = (struct iscsi_task *)sc->SCp.ptr; - debug_scsi("aborting [sc %p itt 0x%x]\n", sc, task->itt); + ISCSI_DBG_SESSION(session, "aborting [sc %p itt 0x%x]\n", + sc, task->itt); /* task completed before time out */ if (!task->sc) { - debug_scsi("sc completed while abort in progress\n"); + ISCSI_DBG_SESSION(session, "sc completed while abort in " + "progress\n"); goto success; } @@ -1815,7 +1863,8 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) if (!sc->SCp.ptr) { conn->tmf_state = TMF_INITIAL; /* task completed before tmf abort response */ - debug_scsi("sc completed while abort in progress\n"); + ISCSI_DBG_SESSION(session, "sc completed while abort " + "in progress\n"); goto success; } /* fall through */ @@ -1827,15 +1876,16 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) success: spin_unlock_bh(&session->lock); success_unlocked: - debug_scsi("abort success [sc %lx itt 0x%x]\n", (long)sc, task->itt); + ISCSI_DBG_SESSION(session, "abort success [sc %p itt 0x%x]\n", + sc, task->itt); mutex_unlock(&session->eh_mutex); return SUCCESS; failed: spin_unlock_bh(&session->lock); failed_unlocked: - debug_scsi("abort failed [sc %p itt 0x%x]\n", sc, - task ? task->itt : 0); + ISCSI_DBG_SESSION(session, "abort failed [sc %p itt 0x%x]\n", sc, + task ? task->itt : 0); mutex_unlock(&session->eh_mutex); return FAILED; } @@ -1862,7 +1912,8 @@ int iscsi_eh_device_reset(struct scsi_cmnd *sc) cls_session = starget_to_session(scsi_target(sc->device)); session = cls_session->dd_data; - debug_scsi("LU Reset [sc %p lun %u]\n", sc, sc->device->lun); + ISCSI_DBG_SESSION(session, "LU Reset [sc %p lun %u]\n", + sc, sc->device->lun); mutex_lock(&session->eh_mutex); spin_lock_bh(&session->lock); @@ -1916,8 +1967,8 @@ int iscsi_eh_device_reset(struct scsi_cmnd *sc) unlock: spin_unlock_bh(&session->lock); done: - debug_scsi("iscsi_eh_device_reset %s\n", - rc == SUCCESS ? "SUCCESS" : "FAILED"); + ISCSI_DBG_SESSION(session, "dev reset result = %s\n", + rc == SUCCESS ? "SUCCESS" : "FAILED"); mutex_unlock(&session->eh_mutex); return rc; } @@ -1944,12 +1995,14 @@ iscsi_pool_init(struct iscsi_pool *q, int max, void ***items, int item_size) num_arrays++; q->pool = kzalloc(num_arrays * max * sizeof(void*), GFP_KERNEL); if (q->pool == NULL) - goto enomem; + return -ENOMEM; q->queue = kfifo_init((void*)q->pool, max * sizeof(void*), GFP_KERNEL, NULL); - if (q->queue == ERR_PTR(-ENOMEM)) + if (IS_ERR(q->queue)) { + q->queue = NULL; goto enomem; + } for (i = 0; i < max; i++) { q->pool[i] = kzalloc(item_size, GFP_KERNEL); @@ -1979,8 +2032,7 @@ void iscsi_pool_free(struct iscsi_pool *q) for (i = 0; i < q->max; i++) kfree(q->pool[i]); - if (q->pool) - kfree(q->pool); + kfree(q->pool); kfree(q->queue); } EXPORT_SYMBOL_GPL(iscsi_pool_free); @@ -1998,6 +2050,11 @@ int iscsi_host_add(struct Scsi_Host *shost, struct device *pdev) if (!shost->can_queue) shost->can_queue = ISCSI_DEF_XMIT_CMDS_MAX; + if (!shost->cmd_per_lun) + shost->cmd_per_lun = ISCSI_DEF_CMD_PER_LUN; + + if (!shost->transportt->eh_timed_out) + shost->transportt->eh_timed_out = iscsi_eh_cmd_timed_out; return scsi_add_host(shost, pdev); } EXPORT_SYMBOL_GPL(iscsi_host_add); @@ -2006,13 +2063,13 @@ EXPORT_SYMBOL_GPL(iscsi_host_add); * iscsi_host_alloc - allocate a host and driver data * @sht: scsi host template * @dd_data_size: driver host data size - * @qdepth: default device queue depth + * @xmit_can_sleep: bool indicating if LLD will queue IO from a work queue * * This should be called by partial offload and software iscsi drivers. * To access the driver specific memory use the iscsi_host_priv() macro. */ struct Scsi_Host *iscsi_host_alloc(struct scsi_host_template *sht, - int dd_data_size, uint16_t qdepth) + int dd_data_size, bool xmit_can_sleep) { struct Scsi_Host *shost; struct iscsi_host *ihost; @@ -2020,29 +2077,31 @@ struct Scsi_Host *iscsi_host_alloc(struct scsi_host_template *sht, shost = scsi_host_alloc(sht, sizeof(struct iscsi_host) + dd_data_size); if (!shost) return NULL; - shost->transportt->eh_timed_out = iscsi_eh_cmd_timed_out; + ihost = shost_priv(shost); - if (qdepth > ISCSI_MAX_CMD_PER_LUN || qdepth < 1) { - if (qdepth != 0) - printk(KERN_ERR "iscsi: invalid queue depth of %d. " - "Queue depth must be between 1 and %d.\n", - qdepth, ISCSI_MAX_CMD_PER_LUN); - qdepth = ISCSI_DEF_CMD_PER_LUN; + if (xmit_can_sleep) { + snprintf(ihost->workq_name, sizeof(ihost->workq_name), + "iscsi_q_%d", shost->host_no); + ihost->workq = create_singlethread_workqueue(ihost->workq_name); + if (!ihost->workq) + goto free_host; } - shost->cmd_per_lun = qdepth; - ihost = shost_priv(shost); spin_lock_init(&ihost->lock); ihost->state = ISCSI_HOST_SETUP; ihost->num_sessions = 0; init_waitqueue_head(&ihost->session_removal_wq); return shost; + +free_host: + scsi_host_put(shost); + return NULL; } EXPORT_SYMBOL_GPL(iscsi_host_alloc); static void iscsi_notify_host_removed(struct iscsi_cls_session *cls_session) { - iscsi_session_failure(cls_session, ISCSI_ERR_INVALID_HOST); + iscsi_session_failure(cls_session->dd_data, ISCSI_ERR_INVALID_HOST); } /** @@ -2068,6 +2127,8 @@ void iscsi_host_remove(struct Scsi_Host *shost) flush_signals(current); scsi_remove_host(shost); + if (ihost->workq) + destroy_workqueue(ihost->workq); } EXPORT_SYMBOL_GPL(iscsi_host_remove); @@ -2466,14 +2527,16 @@ flush_control_queues(struct iscsi_session *session, struct iscsi_conn *conn) /* handle pending */ list_for_each_entry_safe(task, tmp, &conn->mgmtqueue, running) { - debug_scsi("flushing pending mgmt task itt 0x%x\n", task->itt); + ISCSI_DBG_SESSION(session, "flushing pending mgmt task " + "itt 0x%x\n", task->itt); /* release ref from prep task */ __iscsi_put_task(task); } /* handle running */ list_for_each_entry_safe(task, tmp, &conn->mgmt_run_list, running) { - debug_scsi("flushing running mgmt task itt 0x%x\n", task->itt); + ISCSI_DBG_SESSION(session, "flushing running mgmt task " + "itt 0x%x\n", task->itt); /* release ref from prep task */ __iscsi_put_task(task); } @@ -2523,7 +2586,7 @@ static void iscsi_start_session_recovery(struct iscsi_session *session, conn->datadgst_en = 0; if (session->state == ISCSI_STATE_IN_RECOVERY && old_stop_stage != STOP_CONN_RECOVER) { - debug_scsi("blocking session\n"); + ISCSI_DBG_SESSION(session, "blocking session\n"); iscsi_block_session(session->cls_session); } } diff --git a/drivers/scsi/libiscsi_tcp.c b/drivers/scsi/libiscsi_tcp.c index e7705d3532c..91f8ce4d8d0 100644 --- a/drivers/scsi/libiscsi_tcp.c +++ b/drivers/scsi/libiscsi_tcp.c @@ -49,13 +49,21 @@ MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu>, " "Alex Aizman <itn780@yahoo.com>"); MODULE_DESCRIPTION("iSCSI/TCP data-path"); MODULE_LICENSE("GPL"); -#undef DEBUG_TCP -#ifdef DEBUG_TCP -#define debug_tcp(fmt...) printk(KERN_INFO "tcp: " fmt) -#else -#define debug_tcp(fmt...) -#endif +static int iscsi_dbg_libtcp; +module_param_named(debug_libiscsi_tcp, iscsi_dbg_libtcp, int, + S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug_libiscsi_tcp, "Turn on debugging for libiscsi_tcp " + "module. Set to 1 to turn on, and zero to turn off. Default " + "is off."); + +#define ISCSI_DBG_TCP(_conn, dbg_fmt, arg...) \ + do { \ + if (iscsi_dbg_libtcp) \ + iscsi_conn_printk(KERN_INFO, _conn, \ + "%s " dbg_fmt, \ + __func__, ##arg); \ + } while (0); static int iscsi_tcp_hdr_recv_done(struct iscsi_tcp_conn *tcp_conn, struct iscsi_segment *segment); @@ -123,18 +131,13 @@ static void iscsi_tcp_segment_map(struct iscsi_segment *segment, int recv) if (page_count(sg_page(sg)) >= 1 && !recv) return; - debug_tcp("iscsi_tcp_segment_map %s %p\n", recv ? "recv" : "xmit", - segment); segment->sg_mapped = kmap_atomic(sg_page(sg), KM_SOFTIRQ0); segment->data = segment->sg_mapped + sg->offset + segment->sg_offset; } void iscsi_tcp_segment_unmap(struct iscsi_segment *segment) { - debug_tcp("iscsi_tcp_segment_unmap %p\n", segment); - if (segment->sg_mapped) { - debug_tcp("iscsi_tcp_segment_unmap valid\n"); kunmap_atomic(segment->sg_mapped, KM_SOFTIRQ0); segment->sg_mapped = NULL; segment->data = NULL; @@ -180,8 +183,9 @@ int iscsi_tcp_segment_done(struct iscsi_tcp_conn *tcp_conn, struct scatterlist sg; unsigned int pad; - debug_tcp("copied %u %u size %u %s\n", segment->copied, copied, - segment->size, recv ? "recv" : "xmit"); + ISCSI_DBG_TCP(tcp_conn->iscsi_conn, "copied %u %u size %u %s\n", + segment->copied, copied, segment->size, + recv ? "recv" : "xmit"); if (segment->hash && copied) { /* * If a segment is kmapd we must unmap it before sending @@ -214,8 +218,8 @@ int iscsi_tcp_segment_done(struct iscsi_tcp_conn *tcp_conn, iscsi_tcp_segment_unmap(segment); /* Do we have more scatterlist entries? */ - debug_tcp("total copied %u total size %u\n", segment->total_copied, - segment->total_size); + ISCSI_DBG_TCP(tcp_conn->iscsi_conn, "total copied %u total size %u\n", + segment->total_copied, segment->total_size); if (segment->total_copied < segment->total_size) { /* Proceed to the next entry in the scatterlist. */ iscsi_tcp_segment_init_sg(segment, sg_next(segment->sg), @@ -229,7 +233,8 @@ int iscsi_tcp_segment_done(struct iscsi_tcp_conn *tcp_conn, if (!(tcp_conn->iscsi_conn->session->tt->caps & CAP_PADDING_OFFLOAD)) { pad = iscsi_padding(segment->total_copied); if (pad != 0) { - debug_tcp("consume %d pad bytes\n", pad); + ISCSI_DBG_TCP(tcp_conn->iscsi_conn, + "consume %d pad bytes\n", pad); segment->total_size += pad; segment->size = pad; segment->data = segment->padbuf; @@ -278,13 +283,13 @@ iscsi_tcp_segment_recv(struct iscsi_tcp_conn *tcp_conn, while (!iscsi_tcp_segment_done(tcp_conn, segment, 1, copy)) { if (copied == len) { - debug_tcp("iscsi_tcp_segment_recv copied %d bytes\n", - len); + ISCSI_DBG_TCP(tcp_conn->iscsi_conn, + "copied %d bytes\n", len); break; } copy = min(len - copied, segment->size - segment->copied); - debug_tcp("iscsi_tcp_segment_recv copying %d\n", copy); + ISCSI_DBG_TCP(tcp_conn->iscsi_conn, "copying %d\n", copy); memcpy(segment->data + segment->copied, ptr + copied, copy); copied += copy; } @@ -311,7 +316,7 @@ iscsi_tcp_dgst_verify(struct iscsi_tcp_conn *tcp_conn, if (memcmp(segment->recv_digest, segment->digest, segment->digest_len)) { - debug_scsi("digest mismatch\n"); + ISCSI_DBG_TCP(tcp_conn->iscsi_conn, "digest mismatch\n"); return 0; } @@ -355,12 +360,8 @@ iscsi_segment_seek_sg(struct iscsi_segment *segment, struct scatterlist *sg; unsigned int i; - debug_scsi("iscsi_segment_seek_sg offset %u size %llu\n", - offset, size); __iscsi_segment_init(segment, size, done, hash); for_each_sg(sg_list, sg, sg_count, i) { - debug_scsi("sg %d, len %u offset %u\n", i, sg->length, - sg->offset); if (offset < sg->length) { iscsi_tcp_segment_init_sg(segment, sg, offset); return 0; @@ -382,8 +383,9 @@ EXPORT_SYMBOL_GPL(iscsi_segment_seek_sg); */ void iscsi_tcp_hdr_recv_prep(struct iscsi_tcp_conn *tcp_conn) { - debug_tcp("iscsi_tcp_hdr_recv_prep(%p%s)\n", tcp_conn, - tcp_conn->iscsi_conn->hdrdgst_en ? ", digest enabled" : ""); + ISCSI_DBG_TCP(tcp_conn->iscsi_conn, + "(%s)\n", tcp_conn->iscsi_conn->hdrdgst_en ? + "digest enabled" : "digest disabled"); iscsi_segment_init_linear(&tcp_conn->in.segment, tcp_conn->in.hdr_buf, sizeof(struct iscsi_hdr), iscsi_tcp_hdr_recv_done, NULL); @@ -446,7 +448,7 @@ void iscsi_tcp_cleanup_task(struct iscsi_task *task) while (__kfifo_get(tcp_task->r2tqueue, (void*)&r2t, sizeof(void*))) { __kfifo_put(tcp_task->r2tpool.queue, (void*)&r2t, sizeof(void*)); - debug_scsi("iscsi_tcp_cleanup_task pending r2t dropped\n"); + ISCSI_DBG_TCP(task->conn, "pending r2t dropped\n"); } r2t = tcp_task->r2t; @@ -476,8 +478,8 @@ static int iscsi_tcp_data_in(struct iscsi_conn *conn, struct iscsi_task *task) return 0; if (tcp_task->exp_datasn != datasn) { - debug_tcp("%s: task->exp_datasn(%d) != rhdr->datasn(%d)\n", - __func__, tcp_task->exp_datasn, datasn); + ISCSI_DBG_TCP(conn, "task->exp_datasn(%d) != rhdr->datasn(%d)" + "\n", tcp_task->exp_datasn, datasn); return ISCSI_ERR_DATASN; } @@ -485,9 +487,9 @@ static int iscsi_tcp_data_in(struct iscsi_conn *conn, struct iscsi_task *task) tcp_task->data_offset = be32_to_cpu(rhdr->offset); if (tcp_task->data_offset + tcp_conn->in.datalen > total_in_length) { - debug_tcp("%s: data_offset(%d) + data_len(%d) > total_length_in(%d)\n", - __func__, tcp_task->data_offset, - tcp_conn->in.datalen, total_in_length); + ISCSI_DBG_TCP(conn, "data_offset(%d) + data_len(%d) > " + "total_length_in(%d)\n", tcp_task->data_offset, + tcp_conn->in.datalen, total_in_length); return ISCSI_ERR_DATA_OFFSET; } @@ -518,8 +520,8 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task) } if (tcp_task->exp_datasn != r2tsn){ - debug_tcp("%s: task->exp_datasn(%d) != rhdr->r2tsn(%d)\n", - __func__, tcp_task->exp_datasn, r2tsn); + ISCSI_DBG_TCP(conn, "task->exp_datasn(%d) != rhdr->r2tsn(%d)\n", + tcp_task->exp_datasn, r2tsn); return ISCSI_ERR_R2TSN; } @@ -552,9 +554,9 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task) } if (r2t->data_length > session->max_burst) - debug_scsi("invalid R2T with data len %u and max burst %u." - "Attempting to execute request.\n", - r2t->data_length, session->max_burst); + ISCSI_DBG_TCP(conn, "invalid R2T with data len %u and max " + "burst %u. Attempting to execute request.\n", + r2t->data_length, session->max_burst); r2t->data_offset = be32_to_cpu(rhdr->data_offset); if (r2t->data_offset + r2t->data_length > scsi_out(task->sc)->length) { @@ -641,8 +643,8 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr) if (rc) return rc; - debug_tcp("opcode 0x%x ahslen %d datalen %d\n", - opcode, ahslen, tcp_conn->in.datalen); + ISCSI_DBG_TCP(conn, "opcode 0x%x ahslen %d datalen %d\n", + opcode, ahslen, tcp_conn->in.datalen); switch(opcode) { case ISCSI_OP_SCSI_DATA_IN: @@ -674,10 +676,10 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr) !(conn->session->tt->caps & CAP_DIGEST_OFFLOAD)) rx_hash = tcp_conn->rx_hash; - debug_tcp("iscsi_tcp_begin_data_in(%p, offset=%d, " - "datalen=%d)\n", tcp_conn, - tcp_task->data_offset, - tcp_conn->in.datalen); + ISCSI_DBG_TCP(conn, "iscsi_tcp_begin_data_in( " + "offset=%d, datalen=%d)\n", + tcp_task->data_offset, + tcp_conn->in.datalen); rc = iscsi_segment_seek_sg(&tcp_conn->in.segment, sdb->table.sgl, sdb->table.nents, @@ -854,10 +856,10 @@ int iscsi_tcp_recv_skb(struct iscsi_conn *conn, struct sk_buff *skb, unsigned int consumed = 0; int rc = 0; - debug_tcp("in %d bytes\n", skb->len - offset); + ISCSI_DBG_TCP(conn, "in %d bytes\n", skb->len - offset); if (unlikely(conn->suspend_rx)) { - debug_tcp("conn %d Rx suspended!\n", conn->id); + ISCSI_DBG_TCP(conn, "Rx suspended!\n"); *status = ISCSI_TCP_SUSPENDED; return 0; } @@ -874,15 +876,16 @@ int iscsi_tcp_recv_skb(struct iscsi_conn *conn, struct sk_buff *skb, avail = skb_seq_read(consumed, &ptr, &seq); if (avail == 0) { - debug_tcp("no more data avail. Consumed %d\n", - consumed); + ISCSI_DBG_TCP(conn, "no more data avail. Consumed %d\n", + consumed); *status = ISCSI_TCP_SKB_DONE; skb_abort_seq_read(&seq); goto skb_done; } BUG_ON(segment->copied >= segment->size); - debug_tcp("skb %p ptr=%p avail=%u\n", skb, ptr, avail); + ISCSI_DBG_TCP(conn, "skb %p ptr=%p avail=%u\n", skb, ptr, + avail); rc = iscsi_tcp_segment_recv(tcp_conn, segment, ptr, avail); BUG_ON(rc == 0); consumed += rc; @@ -895,11 +898,11 @@ int iscsi_tcp_recv_skb(struct iscsi_conn *conn, struct sk_buff *skb, segment_done: *status = ISCSI_TCP_SEGMENT_DONE; - debug_tcp("segment done\n"); + ISCSI_DBG_TCP(conn, "segment done\n"); rc = segment->done(tcp_conn, segment); if (rc != 0) { *status = ISCSI_TCP_CONN_ERR; - debug_tcp("Error receiving PDU, errno=%d\n", rc); + ISCSI_DBG_TCP(conn, "Error receiving PDU, errno=%d\n", rc); iscsi_conn_failure(conn, rc); return 0; } @@ -929,8 +932,7 @@ int iscsi_tcp_task_init(struct iscsi_task *task) * mgmt tasks do not have a scatterlist since they come * in from the iscsi interface. */ - debug_scsi("mtask deq [cid %d itt 0x%x]\n", conn->id, - task->itt); + ISCSI_DBG_TCP(conn, "mtask deq [itt 0x%x]\n", task->itt); return conn->session->tt->init_pdu(task, 0, task->data_count); } @@ -939,9 +941,8 @@ int iscsi_tcp_task_init(struct iscsi_task *task) tcp_task->exp_datasn = 0; /* Prepare PDU, optionally w/ immediate data */ - debug_scsi("task deq [cid %d itt 0x%x imm %d unsol %d]\n", - conn->id, task->itt, task->imm_count, - task->unsol_r2t.data_length); + ISCSI_DBG_TCP(conn, "task deq [itt 0x%x imm %d unsol %d]\n", + task->itt, task->imm_count, task->unsol_r2t.data_length); err = conn->session->tt->init_pdu(task, 0, task->imm_count); if (err) @@ -965,7 +966,8 @@ static struct iscsi_r2t_info *iscsi_tcp_get_curr_r2t(struct iscsi_task *task) r2t = tcp_task->r2t; /* Continue with this R2T? */ if (r2t->data_length <= r2t->sent) { - debug_scsi(" done with r2t %p\n", r2t); + ISCSI_DBG_TCP(task->conn, + " done with r2t %p\n", r2t); __kfifo_put(tcp_task->r2tpool.queue, (void *)&tcp_task->r2t, sizeof(void *)); @@ -1019,7 +1021,7 @@ flush: r2t = iscsi_tcp_get_curr_r2t(task); if (r2t == NULL) { /* Waiting for more R2Ts to arrive. */ - debug_tcp("no R2Ts yet\n"); + ISCSI_DBG_TCP(conn, "no R2Ts yet\n"); return 0; } @@ -1028,9 +1030,9 @@ flush: return rc; iscsi_prep_data_out_pdu(task, r2t, (struct iscsi_data *) task->hdr); - debug_scsi("sol dout %p [dsn %d itt 0x%x doff %d dlen %d]\n", - r2t, r2t->datasn - 1, task->hdr->itt, - r2t->data_offset + r2t->sent, r2t->data_count); + ISCSI_DBG_TCP(conn, "sol dout %p [dsn %d itt 0x%x doff %d dlen %d]\n", + r2t, r2t->datasn - 1, task->hdr->itt, + r2t->data_offset + r2t->sent, r2t->data_count); rc = conn->session->tt->init_pdu(task, r2t->data_offset + r2t->sent, r2t->data_count); diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c index b615eda361d..81cdcf46c47 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/drivers/scsi/lpfc/lpfc_debugfs.c @@ -1132,7 +1132,7 @@ lpfc_debugfs_dumpDataDif_release(struct inode *inode, struct file *file) } #undef lpfc_debugfs_op_disc_trc -static struct file_operations lpfc_debugfs_op_disc_trc = { +static const struct file_operations lpfc_debugfs_op_disc_trc = { .owner = THIS_MODULE, .open = lpfc_debugfs_disc_trc_open, .llseek = lpfc_debugfs_lseek, @@ -1141,7 +1141,7 @@ static struct file_operations lpfc_debugfs_op_disc_trc = { }; #undef lpfc_debugfs_op_nodelist -static struct file_operations lpfc_debugfs_op_nodelist = { +static const struct file_operations lpfc_debugfs_op_nodelist = { .owner = THIS_MODULE, .open = lpfc_debugfs_nodelist_open, .llseek = lpfc_debugfs_lseek, @@ -1150,7 +1150,7 @@ static struct file_operations lpfc_debugfs_op_nodelist = { }; #undef lpfc_debugfs_op_hbqinfo -static struct file_operations lpfc_debugfs_op_hbqinfo = { +static const struct file_operations lpfc_debugfs_op_hbqinfo = { .owner = THIS_MODULE, .open = lpfc_debugfs_hbqinfo_open, .llseek = lpfc_debugfs_lseek, @@ -1159,7 +1159,7 @@ static struct file_operations lpfc_debugfs_op_hbqinfo = { }; #undef lpfc_debugfs_op_dumpHBASlim -static struct file_operations lpfc_debugfs_op_dumpHBASlim = { +static const struct file_operations lpfc_debugfs_op_dumpHBASlim = { .owner = THIS_MODULE, .open = lpfc_debugfs_dumpHBASlim_open, .llseek = lpfc_debugfs_lseek, @@ -1168,7 +1168,7 @@ static struct file_operations lpfc_debugfs_op_dumpHBASlim = { }; #undef lpfc_debugfs_op_dumpHostSlim -static struct file_operations lpfc_debugfs_op_dumpHostSlim = { +static const struct file_operations lpfc_debugfs_op_dumpHostSlim = { .owner = THIS_MODULE, .open = lpfc_debugfs_dumpHostSlim_open, .llseek = lpfc_debugfs_lseek, @@ -1177,7 +1177,7 @@ static struct file_operations lpfc_debugfs_op_dumpHostSlim = { }; #undef lpfc_debugfs_op_dumpData -static struct file_operations lpfc_debugfs_op_dumpData = { +static const struct file_operations lpfc_debugfs_op_dumpData = { .owner = THIS_MODULE, .open = lpfc_debugfs_dumpData_open, .llseek = lpfc_debugfs_lseek, @@ -1187,7 +1187,7 @@ static struct file_operations lpfc_debugfs_op_dumpData = { }; #undef lpfc_debugfs_op_dumpDif -static struct file_operations lpfc_debugfs_op_dumpDif = { +static const struct file_operations lpfc_debugfs_op_dumpDif = { .owner = THIS_MODULE, .open = lpfc_debugfs_dumpDif_open, .llseek = lpfc_debugfs_lseek, @@ -1197,7 +1197,7 @@ static struct file_operations lpfc_debugfs_op_dumpDif = { }; #undef lpfc_debugfs_op_slow_ring_trc -static struct file_operations lpfc_debugfs_op_slow_ring_trc = { +static const struct file_operations lpfc_debugfs_op_slow_ring_trc = { .owner = THIS_MODULE, .open = lpfc_debugfs_slow_ring_trc_open, .llseek = lpfc_debugfs_lseek, diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index a8f30bdaff6..a7302480bc4 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -5258,6 +5258,7 @@ lpfc_send_els_event(struct lpfc_vport *vport, sizeof(struct lpfc_name)); break; default: + kfree(els_data); return; } memcpy(els_data->wwpn, &ndlp->nlp_portname, sizeof(struct lpfc_name)); diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index b103b6ed497..b1bd3fc7bae 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -1357,7 +1357,7 @@ lpfc_parse_bg_err(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd, scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST, 0x10, 0x1); - cmd->result = (DRIVER_SENSE|SUGGEST_DIE) << 24 + cmd->result = DRIVER_SENSE << 24 | ScsiResult(DID_ABORT, SAM_STAT_CHECK_CONDITION); phba->bg_guard_err_cnt++; printk(KERN_ERR "BLKGRD: guard_tag error\n"); @@ -1368,7 +1368,7 @@ lpfc_parse_bg_err(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd, scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST, 0x10, 0x3); - cmd->result = (DRIVER_SENSE|SUGGEST_DIE) << 24 + cmd->result = DRIVER_SENSE << 24 | ScsiResult(DID_ABORT, SAM_STAT_CHECK_CONDITION); phba->bg_reftag_err_cnt++; @@ -1380,7 +1380,7 @@ lpfc_parse_bg_err(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd, scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST, 0x10, 0x2); - cmd->result = (DRIVER_SENSE|SUGGEST_DIE) << 24 + cmd->result = DRIVER_SENSE << 24 | ScsiResult(DID_ABORT, SAM_STAT_CHECK_CONDITION); phba->bg_apptag_err_cnt++; diff --git a/drivers/scsi/mpt2sas/Kconfig b/drivers/scsi/mpt2sas/Kconfig new file mode 100644 index 00000000000..4a86855c23b --- /dev/null +++ b/drivers/scsi/mpt2sas/Kconfig @@ -0,0 +1,66 @@ +# +# Kernel configuration file for the MPT2SAS +# +# This code is based on drivers/scsi/mpt2sas/Kconfig +# Copyright (C) 2007-2008 LSI Corporation +# (mailto:DL-MPTFusionLinux@lsi.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. + +# NO WARRANTY +# THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT +# LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, +# MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is +# solely responsible for determining the appropriateness of using and +# distributing the Program and assumes all risks associated with its +# exercise of rights under this Agreement, including but not limited to +# the risks and costs of program errors, damage to or loss of data, +# programs or equipment, and unavailability or interruption of operations. + +# DISCLAIMER OF LIABILITY +# NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +# USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED +# HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES + +# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +# USA. + +config SCSI_MPT2SAS + tristate "LSI MPT Fusion SAS 2.0 Device Driver" + depends on PCI && SCSI + select SCSI_SAS_ATTRS + ---help--- + This driver supports PCI-Express SAS 6Gb/s Host Adapters. + +config SCSI_MPT2SAS_MAX_SGE + int "LSI MPT Fusion Max number of SG Entries (16 - 128)" + depends on PCI && SCSI && SCSI_MPT2SAS + default "128" + range 16 128 + ---help--- + This option allows you to specify the maximum number of scatter- + gather entries per I/O. The driver default is 128, which matches + SAFE_PHYS_SEGMENTS. However, it may decreased down to 16. + Decreasing this parameter will reduce memory requirements + on a per controller instance. + +config SCSI_MPT2SAS_LOGGING + bool "LSI MPT Fusion logging facility" + depends on PCI && SCSI && SCSI_MPT2SAS + ---help--- + This turns on a logging facility. diff --git a/drivers/scsi/mpt2sas/Makefile b/drivers/scsi/mpt2sas/Makefile new file mode 100644 index 00000000000..728f0475711 --- /dev/null +++ b/drivers/scsi/mpt2sas/Makefile @@ -0,0 +1,7 @@ +# mpt2sas makefile +obj-$(CONFIG_SCSI_MPT2SAS) += mpt2sas.o +mpt2sas-y += mpt2sas_base.o \ + mpt2sas_config.o \ + mpt2sas_scsih.o \ + mpt2sas_transport.o \ + mpt2sas_ctl.o diff --git a/drivers/scsi/mpt2sas/mpi/mpi2.h b/drivers/scsi/mpt2sas/mpi/mpi2.h new file mode 100644 index 00000000000..7bb2ece8b2e --- /dev/null +++ b/drivers/scsi/mpt2sas/mpi/mpi2.h @@ -0,0 +1,1067 @@ +/* + * Copyright (c) 2000-2009 LSI Corporation. + * + * + * Name: mpi2.h + * Title: MPI Message independent structures and definitions + * including System Interface Register Set and + * scatter/gather formats. + * Creation Date: June 21, 2006 + * + * mpi2.h Version: 02.00.11 + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * 06-04-07 02.00.01 Bumped MPI2_HEADER_VERSION_UNIT. + * 06-26-07 02.00.02 Bumped MPI2_HEADER_VERSION_UNIT. + * 08-31-07 02.00.03 Bumped MPI2_HEADER_VERSION_UNIT. + * Moved ReplyPostHostIndex register to offset 0x6C of the + * MPI2_SYSTEM_INTERFACE_REGS and modified the define for + * MPI2_REPLY_POST_HOST_INDEX_OFFSET. + * Added union of request descriptors. + * Added union of reply descriptors. + * 10-31-07 02.00.04 Bumped MPI2_HEADER_VERSION_UNIT. + * Added define for MPI2_VERSION_02_00. + * Fixed the size of the FunctionDependent5 field in the + * MPI2_DEFAULT_REPLY structure. + * 12-18-07 02.00.05 Bumped MPI2_HEADER_VERSION_UNIT. + * Removed the MPI-defined Fault Codes and extended the + * product specific codes up to 0xEFFF. + * Added a sixth key value for the WriteSequence register + * and changed the flush value to 0x0. + * Added message function codes for Diagnostic Buffer Post + * and Diagnsotic Release. + * New IOCStatus define: MPI2_IOCSTATUS_DIAGNOSTIC_RELEASED + * Moved MPI2_VERSION_UNION from mpi2_ioc.h. + * 02-29-08 02.00.06 Bumped MPI2_HEADER_VERSION_UNIT. + * 03-03-08 02.00.07 Bumped MPI2_HEADER_VERSION_UNIT. + * 05-21-08 02.00.08 Bumped MPI2_HEADER_VERSION_UNIT. + * Added #defines for marking a reply descriptor as unused. + * 06-27-08 02.00.09 Bumped MPI2_HEADER_VERSION_UNIT. + * 10-02-08 02.00.10 Bumped MPI2_HEADER_VERSION_UNIT. + * Moved LUN field defines from mpi2_init.h. + * 01-19-09 02.00.11 Bumped MPI2_HEADER_VERSION_UNIT. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI2_H +#define MPI2_H + + +/***************************************************************************** +* +* MPI Version Definitions +* +*****************************************************************************/ + +#define MPI2_VERSION_MAJOR (0x02) +#define MPI2_VERSION_MINOR (0x00) +#define MPI2_VERSION_MAJOR_MASK (0xFF00) +#define MPI2_VERSION_MAJOR_SHIFT (8) +#define MPI2_VERSION_MINOR_MASK (0x00FF) +#define MPI2_VERSION_MINOR_SHIFT (0) +#define MPI2_VERSION ((MPI2_VERSION_MAJOR << MPI2_VERSION_MAJOR_SHIFT) | \ + MPI2_VERSION_MINOR) + +#define MPI2_VERSION_02_00 (0x0200) + +/* versioning for this MPI header set */ +#define MPI2_HEADER_VERSION_UNIT (0x0B) +#define MPI2_HEADER_VERSION_DEV (0x00) +#define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00) +#define MPI2_HEADER_VERSION_UNIT_SHIFT (8) +#define MPI2_HEADER_VERSION_DEV_MASK (0x00FF) +#define MPI2_HEADER_VERSION_DEV_SHIFT (0) +#define MPI2_HEADER_VERSION ((MPI2_HEADER_VERSION_UNIT << 8) | MPI2_HEADER_VERSION_DEV) + + +/***************************************************************************** +* +* IOC State Definitions +* +*****************************************************************************/ + +#define MPI2_IOC_STATE_RESET (0x00000000) +#define MPI2_IOC_STATE_READY (0x10000000) +#define MPI2_IOC_STATE_OPERATIONAL (0x20000000) +#define MPI2_IOC_STATE_FAULT (0x40000000) + +#define MPI2_IOC_STATE_MASK (0xF0000000) +#define MPI2_IOC_STATE_SHIFT (28) + +/* Fault state range for prodcut specific codes */ +#define MPI2_FAULT_PRODUCT_SPECIFIC_MIN (0x0000) +#define MPI2_FAULT_PRODUCT_SPECIFIC_MAX (0xEFFF) + + +/***************************************************************************** +* +* System Interface Register Definitions +* +*****************************************************************************/ + +typedef volatile struct _MPI2_SYSTEM_INTERFACE_REGS +{ + U32 Doorbell; /* 0x00 */ + U32 WriteSequence; /* 0x04 */ + U32 HostDiagnostic; /* 0x08 */ + U32 Reserved1; /* 0x0C */ + U32 DiagRWData; /* 0x10 */ + U32 DiagRWAddressLow; /* 0x14 */ + U32 DiagRWAddressHigh; /* 0x18 */ + U32 Reserved2[5]; /* 0x1C */ + U32 HostInterruptStatus; /* 0x30 */ + U32 HostInterruptMask; /* 0x34 */ + U32 DCRData; /* 0x38 */ + U32 DCRAddress; /* 0x3C */ + U32 Reserved3[2]; /* 0x40 */ + U32 ReplyFreeHostIndex; /* 0x48 */ + U32 Reserved4[8]; /* 0x4C */ + U32 ReplyPostHostIndex; /* 0x6C */ + U32 Reserved5; /* 0x70 */ + U32 HCBSize; /* 0x74 */ + U32 HCBAddressLow; /* 0x78 */ + U32 HCBAddressHigh; /* 0x7C */ + U32 Reserved6[16]; /* 0x80 */ + U32 RequestDescriptorPostLow; /* 0xC0 */ + U32 RequestDescriptorPostHigh; /* 0xC4 */ + U32 Reserved7[14]; /* 0xC8 */ +} MPI2_SYSTEM_INTERFACE_REGS, MPI2_POINTER PTR_MPI2_SYSTEM_INTERFACE_REGS, + Mpi2SystemInterfaceRegs_t, MPI2_POINTER pMpi2SystemInterfaceRegs_t; + +/* + * Defines for working with the Doorbell register. + */ +#define MPI2_DOORBELL_OFFSET (0x00000000) + +/* IOC --> System values */ +#define MPI2_DOORBELL_USED (0x08000000) +#define MPI2_DOORBELL_WHO_INIT_MASK (0x07000000) +#define MPI2_DOORBELL_WHO_INIT_SHIFT (24) +#define MPI2_DOORBELL_FAULT_CODE_MASK (0x0000FFFF) +#define MPI2_DOORBELL_DATA_MASK (0x0000FFFF) + +/* System --> IOC values */ +#define MPI2_DOORBELL_FUNCTION_MASK (0xFF000000) +#define MPI2_DOORBELL_FUNCTION_SHIFT (24) +#define MPI2_DOORBELL_ADD_DWORDS_MASK (0x00FF0000) +#define MPI2_DOORBELL_ADD_DWORDS_SHIFT (16) + + +/* + * Defines for the WriteSequence register + */ +#define MPI2_WRITE_SEQUENCE_OFFSET (0x00000004) +#define MPI2_WRSEQ_KEY_VALUE_MASK (0x0000000F) +#define MPI2_WRSEQ_FLUSH_KEY_VALUE (0x0) +#define MPI2_WRSEQ_1ST_KEY_VALUE (0xF) +#define MPI2_WRSEQ_2ND_KEY_VALUE (0x4) +#define MPI2_WRSEQ_3RD_KEY_VALUE (0xB) +#define MPI2_WRSEQ_4TH_KEY_VALUE (0x2) +#define MPI2_WRSEQ_5TH_KEY_VALUE (0x7) +#define MPI2_WRSEQ_6TH_KEY_VALUE (0xD) + +/* + * Defines for the HostDiagnostic register + */ +#define MPI2_HOST_DIAGNOSTIC_OFFSET (0x00000008) + +#define MPI2_DIAG_BOOT_DEVICE_SELECT_MASK (0x00001800) +#define MPI2_DIAG_BOOT_DEVICE_SELECT_DEFAULT (0x00000000) +#define MPI2_DIAG_BOOT_DEVICE_SELECT_HCDW (0x00000800) + +#define MPI2_DIAG_CLEAR_FLASH_BAD_SIG (0x00000400) +#define MPI2_DIAG_FORCE_HCB_ON_RESET (0x00000200) +#define MPI2_DIAG_HCB_MODE (0x00000100) +#define MPI2_DIAG_DIAG_WRITE_ENABLE (0x00000080) +#define MPI2_DIAG_FLASH_BAD_SIG (0x00000040) +#define MPI2_DIAG_RESET_HISTORY (0x00000020) +#define MPI2_DIAG_DIAG_RW_ENABLE (0x00000010) +#define MPI2_DIAG_RESET_ADAPTER (0x00000004) +#define MPI2_DIAG_HOLD_IOC_RESET (0x00000002) + +/* + * Offsets for DiagRWData and address + */ +#define MPI2_DIAG_RW_DATA_OFFSET (0x00000010) +#define MPI2_DIAG_RW_ADDRESS_LOW_OFFSET (0x00000014) +#define MPI2_DIAG_RW_ADDRESS_HIGH_OFFSET (0x00000018) + +/* + * Defines for the HostInterruptStatus register + */ +#define MPI2_HOST_INTERRUPT_STATUS_OFFSET (0x00000030) +#define MPI2_HIS_SYS2IOC_DB_STATUS (0x80000000) +#define MPI2_HIS_IOP_DOORBELL_STATUS MPI2_HIS_SYS2IOC_DB_STATUS +#define MPI2_HIS_RESET_IRQ_STATUS (0x40000000) +#define MPI2_HIS_REPLY_DESCRIPTOR_INTERRUPT (0x00000008) +#define MPI2_HIS_IOC2SYS_DB_STATUS (0x00000001) +#define MPI2_HIS_DOORBELL_INTERRUPT MPI2_HIS_IOC2SYS_DB_STATUS + +/* + * Defines for the HostInterruptMask register + */ +#define MPI2_HOST_INTERRUPT_MASK_OFFSET (0x00000034) +#define MPI2_HIM_RESET_IRQ_MASK (0x40000000) +#define MPI2_HIM_REPLY_INT_MASK (0x00000008) +#define MPI2_HIM_RIM MPI2_HIM_REPLY_INT_MASK +#define MPI2_HIM_IOC2SYS_DB_MASK (0x00000001) +#define MPI2_HIM_DIM MPI2_HIM_IOC2SYS_DB_MASK + +/* + * Offsets for DCRData and address + */ +#define MPI2_DCR_DATA_OFFSET (0x00000038) +#define MPI2_DCR_ADDRESS_OFFSET (0x0000003C) + +/* + * Offset for the Reply Free Queue + */ +#define MPI2_REPLY_FREE_HOST_INDEX_OFFSET (0x00000048) + +/* + * Offset for the Reply Descriptor Post Queue + */ +#define MPI2_REPLY_POST_HOST_INDEX_OFFSET (0x0000006C) + +/* + * Defines for the HCBSize and address + */ +#define MPI2_HCB_SIZE_OFFSET (0x00000074) +#define MPI2_HCB_SIZE_SIZE_MASK (0xFFFFF000) +#define MPI2_HCB_SIZE_HCB_ENABLE (0x00000001) + +#define MPI2_HCB_ADDRESS_LOW_OFFSET (0x00000078) +#define MPI2_HCB_ADDRESS_HIGH_OFFSET (0x0000007C) + +/* + * Offsets for the Request Queue + */ +#define MPI2_REQUEST_DESCRIPTOR_POST_LOW_OFFSET (0x000000C0) +#define MPI2_REQUEST_DESCRIPTOR_POST_HIGH_OFFSET (0x000000C4) + + +/***************************************************************************** +* +* Message Descriptors +* +*****************************************************************************/ + +/* Request Descriptors */ + +/* Default Request Descriptor */ +typedef struct _MPI2_DEFAULT_REQUEST_DESCRIPTOR +{ + U8 RequestFlags; /* 0x00 */ + U8 VF_ID; /* 0x01 */ + U16 SMID; /* 0x02 */ + U16 LMID; /* 0x04 */ + U16 DescriptorTypeDependent; /* 0x06 */ +} MPI2_DEFAULT_REQUEST_DESCRIPTOR, + MPI2_POINTER PTR_MPI2_DEFAULT_REQUEST_DESCRIPTOR, + Mpi2DefaultRequestDescriptor_t, MPI2_POINTER pMpi2DefaultRequestDescriptor_t; + +/* defines for the RequestFlags field */ +#define MPI2_REQ_DESCRIPT_FLAGS_TYPE_MASK (0x0E) +#define MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO (0x00) +#define MPI2_REQ_DESCRIPT_FLAGS_SCSI_TARGET (0x02) +#define MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY (0x06) +#define MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE (0x08) + +#define MPI2_REQ_DESCRIPT_FLAGS_IOC_FIFO_MARKER (0x01) + + +/* High Priority Request Descriptor */ +typedef struct _MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR +{ + U8 RequestFlags; /* 0x00 */ + U8 VF_ID; /* 0x01 */ + U16 SMID; /* 0x02 */ + U16 LMID; /* 0x04 */ + U16 Reserved1; /* 0x06 */ +} MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR, + MPI2_POINTER PTR_MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR, + Mpi2HighPriorityRequestDescriptor_t, + MPI2_POINTER pMpi2HighPriorityRequestDescriptor_t; + + +/* SCSI IO Request Descriptor */ +typedef struct _MPI2_SCSI_IO_REQUEST_DESCRIPTOR +{ + U8 RequestFlags; /* 0x00 */ + U8 VF_ID; /* 0x01 */ + U16 SMID; /* 0x02 */ + U16 LMID; /* 0x04 */ + U16 DevHandle; /* 0x06 */ +} MPI2_SCSI_IO_REQUEST_DESCRIPTOR, + MPI2_POINTER PTR_MPI2_SCSI_IO_REQUEST_DESCRIPTOR, + Mpi2SCSIIORequestDescriptor_t, MPI2_POINTER pMpi2SCSIIORequestDescriptor_t; + + +/* SCSI Target Request Descriptor */ +typedef struct _MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR +{ + U8 RequestFlags; /* 0x00 */ + U8 VF_ID; /* 0x01 */ + U16 SMID; /* 0x02 */ + U16 LMID; /* 0x04 */ + U16 IoIndex; /* 0x06 */ +} MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR, + MPI2_POINTER PTR_MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR, + Mpi2SCSITargetRequestDescriptor_t, + MPI2_POINTER pMpi2SCSITargetRequestDescriptor_t; + +/* union of Request Descriptors */ +typedef union _MPI2_REQUEST_DESCRIPTOR_UNION +{ + MPI2_DEFAULT_REQUEST_DESCRIPTOR Default; + MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR HighPriority; + MPI2_SCSI_IO_REQUEST_DESCRIPTOR SCSIIO; + MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR SCSITarget; + U64 Words; +} MPI2_REQUEST_DESCRIPTOR_UNION, MPI2_POINTER PTR_MPI2_REQUEST_DESCRIPTOR_UNION, + Mpi2RequestDescriptorUnion_t, MPI2_POINTER pMpi2RequestDescriptorUnion_t; + + +/* Reply Descriptors */ + +/* Default Reply Descriptor */ +typedef struct _MPI2_DEFAULT_REPLY_DESCRIPTOR +{ + U8 ReplyFlags; /* 0x00 */ + U8 VF_ID; /* 0x01 */ + U16 DescriptorTypeDependent1; /* 0x02 */ + U32 DescriptorTypeDependent2; /* 0x04 */ +} MPI2_DEFAULT_REPLY_DESCRIPTOR, MPI2_POINTER PTR_MPI2_DEFAULT_REPLY_DESCRIPTOR, + Mpi2DefaultReplyDescriptor_t, MPI2_POINTER pMpi2DefaultReplyDescriptor_t; + +/* defines for the ReplyFlags field */ +#define MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK (0x0F) +#define MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS (0x00) +#define MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY (0x01) +#define MPI2_RPY_DESCRIPT_FLAGS_TARGETASSIST_SUCCESS (0x02) +#define MPI2_RPY_DESCRIPT_FLAGS_TARGET_COMMAND_BUFFER (0x03) +#define MPI2_RPY_DESCRIPT_FLAGS_UNUSED (0x0F) + +/* values for marking a reply descriptor as unused */ +#define MPI2_RPY_DESCRIPT_UNUSED_WORD0_MARK (0xFFFFFFFF) +#define MPI2_RPY_DESCRIPT_UNUSED_WORD1_MARK (0xFFFFFFFF) + +/* Address Reply Descriptor */ +typedef struct _MPI2_ADDRESS_REPLY_DESCRIPTOR +{ + U8 ReplyFlags; /* 0x00 */ + U8 VF_ID; /* 0x01 */ + U16 SMID; /* 0x02 */ + U32 ReplyFrameAddress; /* 0x04 */ +} MPI2_ADDRESS_REPLY_DESCRIPTOR, MPI2_POINTER PTR_MPI2_ADDRESS_REPLY_DESCRIPTOR, + Mpi2AddressReplyDescriptor_t, MPI2_POINTER pMpi2AddressReplyDescriptor_t; + +#define MPI2_ADDRESS_REPLY_SMID_INVALID (0x00) + + +/* SCSI IO Success Reply Descriptor */ +typedef struct _MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR +{ + U8 ReplyFlags; /* 0x00 */ + U8 VF_ID; /* 0x01 */ + U16 SMID; /* 0x02 */ + U16 TaskTag; /* 0x04 */ + U16 DevHandle; /* 0x06 */ +} MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR, + MPI2_POINTER PTR_MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR, + Mpi2SCSIIOSuccessReplyDescriptor_t, + MPI2_POINTER pMpi2SCSIIOSuccessReplyDescriptor_t; + + +/* TargetAssist Success Reply Descriptor */ +typedef struct _MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR +{ + U8 ReplyFlags; /* 0x00 */ + U8 VF_ID; /* 0x01 */ + U16 SMID; /* 0x02 */ + U8 SequenceNumber; /* 0x04 */ + U8 Reserved1; /* 0x05 */ + U16 IoIndex; /* 0x06 */ +} MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR, + MPI2_POINTER PTR_MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR, + Mpi2TargetAssistSuccessReplyDescriptor_t, + MPI2_POINTER pMpi2TargetAssistSuccessReplyDescriptor_t; + + +/* Target Command Buffer Reply Descriptor */ +typedef struct _MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR +{ + U8 ReplyFlags; /* 0x00 */ + U8 VF_ID; /* 0x01 */ + U8 VP_ID; /* 0x02 */ + U8 Flags; /* 0x03 */ + U16 InitiatorDevHandle; /* 0x04 */ + U16 IoIndex; /* 0x06 */ +} MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR, + MPI2_POINTER PTR_MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR, + Mpi2TargetCommandBufferReplyDescriptor_t, + MPI2_POINTER pMpi2TargetCommandBufferReplyDescriptor_t; + +/* defines for Flags field */ +#define MPI2_RPY_DESCRIPT_TCB_FLAGS_PHYNUM_MASK (0x3F) + + +/* union of Reply Descriptors */ +typedef union _MPI2_REPLY_DESCRIPTORS_UNION +{ + MPI2_DEFAULT_REPLY_DESCRIPTOR Default; + MPI2_ADDRESS_REPLY_DESCRIPTOR AddressReply; + MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR SCSIIOSuccess; + MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR TargetAssistSuccess; + MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR TargetCommandBuffer; + U64 Words; +} MPI2_REPLY_DESCRIPTORS_UNION, MPI2_POINTER PTR_MPI2_REPLY_DESCRIPTORS_UNION, + Mpi2ReplyDescriptorsUnion_t, MPI2_POINTER pMpi2ReplyDescriptorsUnion_t; + + + +/***************************************************************************** +* +* Message Functions +* 0x80 -> 0x8F reserved for private message use per product +* +* +*****************************************************************************/ + +#define MPI2_FUNCTION_SCSI_IO_REQUEST (0x00) /* SCSI IO */ +#define MPI2_FUNCTION_SCSI_TASK_MGMT (0x01) /* SCSI Task Management */ +#define MPI2_FUNCTION_IOC_INIT (0x02) /* IOC Init */ +#define MPI2_FUNCTION_IOC_FACTS (0x03) /* IOC Facts */ +#define MPI2_FUNCTION_CONFIG (0x04) /* Configuration */ +#define MPI2_FUNCTION_PORT_FACTS (0x05) /* Port Facts */ +#define MPI2_FUNCTION_PORT_ENABLE (0x06) /* Port Enable */ +#define MPI2_FUNCTION_EVENT_NOTIFICATION (0x07) /* Event Notification */ +#define MPI2_FUNCTION_EVENT_ACK (0x08) /* Event Acknowledge */ +#define MPI2_FUNCTION_FW_DOWNLOAD (0x09) /* FW Download */ +#define MPI2_FUNCTION_TARGET_ASSIST (0x0B) /* Target Assist */ +#define MPI2_FUNCTION_TARGET_STATUS_SEND (0x0C) /* Target Status Send */ +#define MPI2_FUNCTION_TARGET_MODE_ABORT (0x0D) /* Target Mode Abort */ +#define MPI2_FUNCTION_FW_UPLOAD (0x12) /* FW Upload */ +#define MPI2_FUNCTION_RAID_ACTION (0x15) /* RAID Action */ +#define MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH (0x16) /* SCSI IO RAID Passthrough */ +#define MPI2_FUNCTION_TOOLBOX (0x17) /* Toolbox */ +#define MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR (0x18) /* SCSI Enclosure Processor */ +#define MPI2_FUNCTION_SMP_PASSTHROUGH (0x1A) /* SMP Passthrough */ +#define MPI2_FUNCTION_SAS_IO_UNIT_CONTROL (0x1B) /* SAS IO Unit Control */ +#define MPI2_FUNCTION_SATA_PASSTHROUGH (0x1C) /* SATA Passthrough */ +#define MPI2_FUNCTION_DIAG_BUFFER_POST (0x1D) /* Diagnostic Buffer Post */ +#define MPI2_FUNCTION_DIAG_RELEASE (0x1E) /* Diagnostic Release */ +#define MPI2_FUNCTION_TARGET_CMD_BUF_BASE_POST (0x24) /* Target Command Buffer Post Base */ +#define MPI2_FUNCTION_TARGET_CMD_BUF_LIST_POST (0x25) /* Target Command Buffer Post List */ + + + +/* Doorbell functions */ +#define MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET (0x40) +/* #define MPI2_FUNCTION_IO_UNIT_RESET (0x41) */ +#define MPI2_FUNCTION_HANDSHAKE (0x42) + + +/***************************************************************************** +* +* IOC Status Values +* +*****************************************************************************/ + +/* mask for IOCStatus status value */ +#define MPI2_IOCSTATUS_MASK (0x7FFF) + +/**************************************************************************** +* Common IOCStatus values for all replies +****************************************************************************/ + +#define MPI2_IOCSTATUS_SUCCESS (0x0000) +#define MPI2_IOCSTATUS_INVALID_FUNCTION (0x0001) +#define MPI2_IOCSTATUS_BUSY (0x0002) +#define MPI2_IOCSTATUS_INVALID_SGL (0x0003) +#define MPI2_IOCSTATUS_INTERNAL_ERROR (0x0004) +#define MPI2_IOCSTATUS_INVALID_VPID (0x0005) +#define MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES (0x0006) +#define MPI2_IOCSTATUS_INVALID_FIELD (0x0007) +#define MPI2_IOCSTATUS_INVALID_STATE (0x0008) +#define MPI2_IOCSTATUS_OP_STATE_NOT_SUPPORTED (0x0009) + +/**************************************************************************** +* Config IOCStatus values +****************************************************************************/ + +#define MPI2_IOCSTATUS_CONFIG_INVALID_ACTION (0x0020) +#define MPI2_IOCSTATUS_CONFIG_INVALID_TYPE (0x0021) +#define MPI2_IOCSTATUS_CONFIG_INVALID_PAGE (0x0022) +#define MPI2_IOCSTATUS_CONFIG_INVALID_DATA (0x0023) +#define MPI2_IOCSTATUS_CONFIG_NO_DEFAULTS (0x0024) +#define MPI2_IOCSTATUS_CONFIG_CANT_COMMIT (0x0025) + +/**************************************************************************** +* SCSI IO Reply +****************************************************************************/ + +#define MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR (0x0040) +#define MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE (0x0042) +#define MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE (0x0043) +#define MPI2_IOCSTATUS_SCSI_DATA_OVERRUN (0x0044) +#define MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN (0x0045) +#define MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR (0x0046) +#define MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR (0x0047) +#define MPI2_IOCSTATUS_SCSI_TASK_TERMINATED (0x0048) +#define MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH (0x0049) +#define MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED (0x004A) +#define MPI2_IOCSTATUS_SCSI_IOC_TERMINATED (0x004B) +#define MPI2_IOCSTATUS_SCSI_EXT_TERMINATED (0x004C) + +/**************************************************************************** +* For use by SCSI Initiator and SCSI Target end-to-end data protection +****************************************************************************/ + +#define MPI2_IOCSTATUS_EEDP_GUARD_ERROR (0x004D) +#define MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR (0x004E) +#define MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR (0x004F) + +/**************************************************************************** +* SCSI Target values +****************************************************************************/ + +#define MPI2_IOCSTATUS_TARGET_INVALID_IO_INDEX (0x0062) +#define MPI2_IOCSTATUS_TARGET_ABORTED (0x0063) +#define MPI2_IOCSTATUS_TARGET_NO_CONN_RETRYABLE (0x0064) +#define MPI2_IOCSTATUS_TARGET_NO_CONNECTION (0x0065) +#define MPI2_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH (0x006A) +#define MPI2_IOCSTATUS_TARGET_DATA_OFFSET_ERROR (0x006D) +#define MPI2_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA (0x006E) +#define MPI2_IOCSTATUS_TARGET_IU_TOO_SHORT (0x006F) +#define MPI2_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT (0x0070) +#define MPI2_IOCSTATUS_TARGET_NAK_RECEIVED (0x0071) + +/**************************************************************************** +* Serial Attached SCSI values +****************************************************************************/ + +#define MPI2_IOCSTATUS_SAS_SMP_REQUEST_FAILED (0x0090) +#define MPI2_IOCSTATUS_SAS_SMP_DATA_OVERRUN (0x0091) + +/**************************************************************************** +* Diagnostic Buffer Post / Diagnostic Release values +****************************************************************************/ + +#define MPI2_IOCSTATUS_DIAGNOSTIC_RELEASED (0x00A0) + + +/**************************************************************************** +* IOCStatus flag to indicate that log info is available +****************************************************************************/ + +#define MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE (0x8000) + +/**************************************************************************** +* IOCLogInfo Types +****************************************************************************/ + +#define MPI2_IOCLOGINFO_TYPE_MASK (0xF0000000) +#define MPI2_IOCLOGINFO_TYPE_SHIFT (28) +#define MPI2_IOCLOGINFO_TYPE_NONE (0x0) +#define MPI2_IOCLOGINFO_TYPE_SCSI (0x1) +#define MPI2_IOCLOGINFO_TYPE_FC (0x2) +#define MPI2_IOCLOGINFO_TYPE_SAS (0x3) +#define MPI2_IOCLOGINFO_TYPE_ISCSI (0x4) +#define MPI2_IOCLOGINFO_LOG_DATA_MASK (0x0FFFFFFF) + + +/***************************************************************************** +* +* Standard Message Structures +* +*****************************************************************************/ + +/**************************************************************************** +* Request Message Header for all request messages +****************************************************************************/ + +typedef struct _MPI2_REQUEST_HEADER +{ + U16 FunctionDependent1; /* 0x00 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 FunctionDependent2; /* 0x04 */ + U8 FunctionDependent3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved1; /* 0x0A */ +} MPI2_REQUEST_HEADER, MPI2_POINTER PTR_MPI2_REQUEST_HEADER, + MPI2RequestHeader_t, MPI2_POINTER pMPI2RequestHeader_t; + + +/**************************************************************************** +* Default Reply +****************************************************************************/ + +typedef struct _MPI2_DEFAULT_REPLY +{ + U16 FunctionDependent1; /* 0x00 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 FunctionDependent2; /* 0x04 */ + U8 FunctionDependent3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved1; /* 0x0A */ + U16 FunctionDependent5; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ +} MPI2_DEFAULT_REPLY, MPI2_POINTER PTR_MPI2_DEFAULT_REPLY, + MPI2DefaultReply_t, MPI2_POINTER pMPI2DefaultReply_t; + + +/* common version structure/union used in messages and configuration pages */ + +typedef struct _MPI2_VERSION_STRUCT +{ + U8 Dev; /* 0x00 */ + U8 Unit; /* 0x01 */ + U8 Minor; /* 0x02 */ + U8 Major; /* 0x03 */ +} MPI2_VERSION_STRUCT; + +typedef union _MPI2_VERSION_UNION +{ + MPI2_VERSION_STRUCT Struct; + U32 Word; +} MPI2_VERSION_UNION; + + +/* LUN field defines, common to many structures */ +#define MPI2_LUN_FIRST_LEVEL_ADDRESSING (0x0000FFFF) +#define MPI2_LUN_SECOND_LEVEL_ADDRESSING (0xFFFF0000) +#define MPI2_LUN_THIRD_LEVEL_ADDRESSING (0x0000FFFF) +#define MPI2_LUN_FOURTH_LEVEL_ADDRESSING (0xFFFF0000) +#define MPI2_LUN_LEVEL_1_WORD (0xFF00) +#define MPI2_LUN_LEVEL_1_DWORD (0x0000FF00) + + +/***************************************************************************** +* +* Fusion-MPT MPI Scatter Gather Elements +* +*****************************************************************************/ + +/**************************************************************************** +* MPI Simple Element structures +****************************************************************************/ + +typedef struct _MPI2_SGE_SIMPLE32 +{ + U32 FlagsLength; + U32 Address; +} MPI2_SGE_SIMPLE32, MPI2_POINTER PTR_MPI2_SGE_SIMPLE32, + Mpi2SGESimple32_t, MPI2_POINTER pMpi2SGESimple32_t; + +typedef struct _MPI2_SGE_SIMPLE64 +{ + U32 FlagsLength; + U64 Address; +} MPI2_SGE_SIMPLE64, MPI2_POINTER PTR_MPI2_SGE_SIMPLE64, + Mpi2SGESimple64_t, MPI2_POINTER pMpi2SGESimple64_t; + +typedef struct _MPI2_SGE_SIMPLE_UNION +{ + U32 FlagsLength; + union + { + U32 Address32; + U64 Address64; + } u; +} MPI2_SGE_SIMPLE_UNION, MPI2_POINTER PTR_MPI2_SGE_SIMPLE_UNION, + Mpi2SGESimpleUnion_t, MPI2_POINTER pMpi2SGESimpleUnion_t; + + +/**************************************************************************** +* MPI Chain Element structures +****************************************************************************/ + +typedef struct _MPI2_SGE_CHAIN32 +{ + U16 Length; + U8 NextChainOffset; + U8 Flags; + U32 Address; +} MPI2_SGE_CHAIN32, MPI2_POINTER PTR_MPI2_SGE_CHAIN32, + Mpi2SGEChain32_t, MPI2_POINTER pMpi2SGEChain32_t; + +typedef struct _MPI2_SGE_CHAIN64 +{ + U16 Length; + U8 NextChainOffset; + U8 Flags; + U64 Address; +} MPI2_SGE_CHAIN64, MPI2_POINTER PTR_MPI2_SGE_CHAIN64, + Mpi2SGEChain64_t, MPI2_POINTER pMpi2SGEChain64_t; + +typedef struct _MPI2_SGE_CHAIN_UNION +{ + U16 Length; + U8 NextChainOffset; + U8 Flags; + union + { + U32 Address32; + U64 Address64; + } u; +} MPI2_SGE_CHAIN_UNION, MPI2_POINTER PTR_MPI2_SGE_CHAIN_UNION, + Mpi2SGEChainUnion_t, MPI2_POINTER pMpi2SGEChainUnion_t; + + +/**************************************************************************** +* MPI Transaction Context Element structures +****************************************************************************/ + +typedef struct _MPI2_SGE_TRANSACTION32 +{ + U8 Reserved; + U8 ContextSize; + U8 DetailsLength; + U8 Flags; + U32 TransactionContext[1]; + U32 TransactionDetails[1]; +} MPI2_SGE_TRANSACTION32, MPI2_POINTER PTR_MPI2_SGE_TRANSACTION32, + Mpi2SGETransaction32_t, MPI2_POINTER pMpi2SGETransaction32_t; + +typedef struct _MPI2_SGE_TRANSACTION64 +{ + U8 Reserved; + U8 ContextSize; + U8 DetailsLength; + U8 Flags; + U32 TransactionContext[2]; + U32 TransactionDetails[1]; +} MPI2_SGE_TRANSACTION64, MPI2_POINTER PTR_MPI2_SGE_TRANSACTION64, + Mpi2SGETransaction64_t, MPI2_POINTER pMpi2SGETransaction64_t; + +typedef struct _MPI2_SGE_TRANSACTION96 +{ + U8 Reserved; + U8 ContextSize; + U8 DetailsLength; + U8 Flags; + U32 TransactionContext[3]; + U32 TransactionDetails[1]; +} MPI2_SGE_TRANSACTION96, MPI2_POINTER PTR_MPI2_SGE_TRANSACTION96, + Mpi2SGETransaction96_t, MPI2_POINTER pMpi2SGETransaction96_t; + +typedef struct _MPI2_SGE_TRANSACTION128 +{ + U8 Reserved; + U8 ContextSize; + U8 DetailsLength; + U8 Flags; + U32 TransactionContext[4]; + U32 TransactionDetails[1]; +} MPI2_SGE_TRANSACTION128, MPI2_POINTER PTR_MPI2_SGE_TRANSACTION128, + Mpi2SGETransaction_t128, MPI2_POINTER pMpi2SGETransaction_t128; + +typedef struct _MPI2_SGE_TRANSACTION_UNION +{ + U8 Reserved; + U8 ContextSize; + U8 DetailsLength; + U8 Flags; + union + { + U32 TransactionContext32[1]; + U32 TransactionContext64[2]; + U32 TransactionContext96[3]; + U32 TransactionContext128[4]; + } u; + U32 TransactionDetails[1]; +} MPI2_SGE_TRANSACTION_UNION, MPI2_POINTER PTR_MPI2_SGE_TRANSACTION_UNION, + Mpi2SGETransactionUnion_t, MPI2_POINTER pMpi2SGETransactionUnion_t; + + +/**************************************************************************** +* MPI SGE union for IO SGL's +****************************************************************************/ + +typedef struct _MPI2_MPI_SGE_IO_UNION +{ + union + { + MPI2_SGE_SIMPLE_UNION Simple; + MPI2_SGE_CHAIN_UNION Chain; + } u; +} MPI2_MPI_SGE_IO_UNION, MPI2_POINTER PTR_MPI2_MPI_SGE_IO_UNION, + Mpi2MpiSGEIOUnion_t, MPI2_POINTER pMpi2MpiSGEIOUnion_t; + + +/**************************************************************************** +* MPI SGE union for SGL's with Simple and Transaction elements +****************************************************************************/ + +typedef struct _MPI2_SGE_TRANS_SIMPLE_UNION +{ + union + { + MPI2_SGE_SIMPLE_UNION Simple; + MPI2_SGE_TRANSACTION_UNION Transaction; + } u; +} MPI2_SGE_TRANS_SIMPLE_UNION, MPI2_POINTER PTR_MPI2_SGE_TRANS_SIMPLE_UNION, + Mpi2SGETransSimpleUnion_t, MPI2_POINTER pMpi2SGETransSimpleUnion_t; + + +/**************************************************************************** +* All MPI SGE types union +****************************************************************************/ + +typedef struct _MPI2_MPI_SGE_UNION +{ + union + { + MPI2_SGE_SIMPLE_UNION Simple; + MPI2_SGE_CHAIN_UNION Chain; + MPI2_SGE_TRANSACTION_UNION Transaction; + } u; +} MPI2_MPI_SGE_UNION, MPI2_POINTER PTR_MPI2_MPI_SGE_UNION, + Mpi2MpiSgeUnion_t, MPI2_POINTER pMpi2MpiSgeUnion_t; + + +/**************************************************************************** +* MPI SGE field definition and masks +****************************************************************************/ + +/* Flags field bit definitions */ + +#define MPI2_SGE_FLAGS_LAST_ELEMENT (0x80) +#define MPI2_SGE_FLAGS_END_OF_BUFFER (0x40) +#define MPI2_SGE_FLAGS_ELEMENT_TYPE_MASK (0x30) +#define MPI2_SGE_FLAGS_LOCAL_ADDRESS (0x08) +#define MPI2_SGE_FLAGS_DIRECTION (0x04) +#define MPI2_SGE_FLAGS_ADDRESS_SIZE (0x02) +#define MPI2_SGE_FLAGS_END_OF_LIST (0x01) + +#define MPI2_SGE_FLAGS_SHIFT (24) + +#define MPI2_SGE_LENGTH_MASK (0x00FFFFFF) +#define MPI2_SGE_CHAIN_LENGTH_MASK (0x0000FFFF) + +/* Element Type */ + +#define MPI2_SGE_FLAGS_TRANSACTION_ELEMENT (0x00) +#define MPI2_SGE_FLAGS_SIMPLE_ELEMENT (0x10) +#define MPI2_SGE_FLAGS_CHAIN_ELEMENT (0x30) +#define MPI2_SGE_FLAGS_ELEMENT_MASK (0x30) + +/* Address location */ + +#define MPI2_SGE_FLAGS_SYSTEM_ADDRESS (0x00) + +/* Direction */ + +#define MPI2_SGE_FLAGS_IOC_TO_HOST (0x00) +#define MPI2_SGE_FLAGS_HOST_TO_IOC (0x04) + +/* Address Size */ + +#define MPI2_SGE_FLAGS_32_BIT_ADDRESSING (0x00) +#define MPI2_SGE_FLAGS_64_BIT_ADDRESSING (0x02) + +/* Context Size */ + +#define MPI2_SGE_FLAGS_32_BIT_CONTEXT (0x00) +#define MPI2_SGE_FLAGS_64_BIT_CONTEXT (0x02) +#define MPI2_SGE_FLAGS_96_BIT_CONTEXT (0x04) +#define MPI2_SGE_FLAGS_128_BIT_CONTEXT (0x06) + +#define MPI2_SGE_CHAIN_OFFSET_MASK (0x00FF0000) +#define MPI2_SGE_CHAIN_OFFSET_SHIFT (16) + +/**************************************************************************** +* MPI SGE operation Macros +****************************************************************************/ + +/* SIMPLE FlagsLength manipulations... */ +#define MPI2_SGE_SET_FLAGS(f) ((U32)(f) << MPI2_SGE_FLAGS_SHIFT) +#define MPI2_SGE_GET_FLAGS(f) (((f) & ~MPI2_SGE_LENGTH_MASK) >> MPI2_SGE_FLAGS_SHIFT) +#define MPI2_SGE_LENGTH(f) ((f) & MPI2_SGE_LENGTH_MASK) +#define MPI2_SGE_CHAIN_LENGTH(f) ((f) & MPI2_SGE_CHAIN_LENGTH_MASK) + +#define MPI2_SGE_SET_FLAGS_LENGTH(f,l) (MPI2_SGE_SET_FLAGS(f) | MPI2_SGE_LENGTH(l)) + +#define MPI2_pSGE_GET_FLAGS(psg) MPI2_SGE_GET_FLAGS((psg)->FlagsLength) +#define MPI2_pSGE_GET_LENGTH(psg) MPI2_SGE_LENGTH((psg)->FlagsLength) +#define MPI2_pSGE_SET_FLAGS_LENGTH(psg,f,l) (psg)->FlagsLength = MPI2_SGE_SET_FLAGS_LENGTH(f,l) + +/* CAUTION - The following are READ-MODIFY-WRITE! */ +#define MPI2_pSGE_SET_FLAGS(psg,f) (psg)->FlagsLength |= MPI2_SGE_SET_FLAGS(f) +#define MPI2_pSGE_SET_LENGTH(psg,l) (psg)->FlagsLength |= MPI2_SGE_LENGTH(l) + +#define MPI2_GET_CHAIN_OFFSET(x) ((x & MPI2_SGE_CHAIN_OFFSET_MASK) >> MPI2_SGE_CHAIN_OFFSET_SHIFT) + + +/***************************************************************************** +* +* Fusion-MPT IEEE Scatter Gather Elements +* +*****************************************************************************/ + +/**************************************************************************** +* IEEE Simple Element structures +****************************************************************************/ + +typedef struct _MPI2_IEEE_SGE_SIMPLE32 +{ + U32 Address; + U32 FlagsLength; +} MPI2_IEEE_SGE_SIMPLE32, MPI2_POINTER PTR_MPI2_IEEE_SGE_SIMPLE32, + Mpi2IeeeSgeSimple32_t, MPI2_POINTER pMpi2IeeeSgeSimple32_t; + +typedef struct _MPI2_IEEE_SGE_SIMPLE64 +{ + U64 Address; + U32 Length; + U16 Reserved1; + U8 Reserved2; + U8 Flags; +} MPI2_IEEE_SGE_SIMPLE64, MPI2_POINTER PTR_MPI2_IEEE_SGE_SIMPLE64, + Mpi2IeeeSgeSimple64_t, MPI2_POINTER pMpi2IeeeSgeSimple64_t; + +typedef union _MPI2_IEEE_SGE_SIMPLE_UNION +{ + MPI2_IEEE_SGE_SIMPLE32 Simple32; + MPI2_IEEE_SGE_SIMPLE64 Simple64; +} MPI2_IEEE_SGE_SIMPLE_UNION, MPI2_POINTER PTR_MPI2_IEEE_SGE_SIMPLE_UNION, + Mpi2IeeeSgeSimpleUnion_t, MPI2_POINTER pMpi2IeeeSgeSimpleUnion_t; + + +/**************************************************************************** +* IEEE Chain Element structures +****************************************************************************/ + +typedef MPI2_IEEE_SGE_SIMPLE32 MPI2_IEEE_SGE_CHAIN32; + +typedef MPI2_IEEE_SGE_SIMPLE64 MPI2_IEEE_SGE_CHAIN64; + +typedef union _MPI2_IEEE_SGE_CHAIN_UNION +{ + MPI2_IEEE_SGE_CHAIN32 Chain32; + MPI2_IEEE_SGE_CHAIN64 Chain64; +} MPI2_IEEE_SGE_CHAIN_UNION, MPI2_POINTER PTR_MPI2_IEEE_SGE_CHAIN_UNION, + Mpi2IeeeSgeChainUnion_t, MPI2_POINTER pMpi2IeeeSgeChainUnion_t; + + +/**************************************************************************** +* All IEEE SGE types union +****************************************************************************/ + +typedef struct _MPI2_IEEE_SGE_UNION +{ + union + { + MPI2_IEEE_SGE_SIMPLE_UNION Simple; + MPI2_IEEE_SGE_CHAIN_UNION Chain; + } u; +} MPI2_IEEE_SGE_UNION, MPI2_POINTER PTR_MPI2_IEEE_SGE_UNION, + Mpi2IeeeSgeUnion_t, MPI2_POINTER pMpi2IeeeSgeUnion_t; + + +/**************************************************************************** +* IEEE SGE field definitions and masks +****************************************************************************/ + +/* Flags field bit definitions */ + +#define MPI2_IEEE_SGE_FLAGS_ELEMENT_TYPE_MASK (0x80) + +#define MPI2_IEEE32_SGE_FLAGS_SHIFT (24) + +#define MPI2_IEEE32_SGE_LENGTH_MASK (0x00FFFFFF) + +/* Element Type */ + +#define MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT (0x00) +#define MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT (0x80) + +/* Data Location Address Space */ + +#define MPI2_IEEE_SGE_FLAGS_ADDR_MASK (0x03) +#define MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR (0x00) +#define MPI2_IEEE_SGE_FLAGS_IOCDDR_ADDR (0x01) +#define MPI2_IEEE_SGE_FLAGS_IOCPLB_ADDR (0x02) +#define MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR (0x03) + + +/**************************************************************************** +* IEEE SGE operation Macros +****************************************************************************/ + +/* SIMPLE FlagsLength manipulations... */ +#define MPI2_IEEE32_SGE_SET_FLAGS(f) ((U32)(f) << MPI2_IEEE32_SGE_FLAGS_SHIFT) +#define MPI2_IEEE32_SGE_GET_FLAGS(f) (((f) & ~MPI2_IEEE32_SGE_LENGTH_MASK) >> MPI2_IEEE32_SGE_FLAGS_SHIFT) +#define MPI2_IEEE32_SGE_LENGTH(f) ((f) & MPI2_IEEE32_SGE_LENGTH_MASK) + +#define MPI2_IEEE32_SGE_SET_FLAGS_LENGTH(f, l) (MPI2_IEEE32_SGE_SET_FLAGS(f) | MPI2_IEEE32_SGE_LENGTH(l)) + +#define MPI2_IEEE32_pSGE_GET_FLAGS(psg) MPI2_IEEE32_SGE_GET_FLAGS((psg)->FlagsLength) +#define MPI2_IEEE32_pSGE_GET_LENGTH(psg) MPI2_IEEE32_SGE_LENGTH((psg)->FlagsLength) +#define MPI2_IEEE32_pSGE_SET_FLAGS_LENGTH(psg,f,l) (psg)->FlagsLength = MPI2_IEEE32_SGE_SET_FLAGS_LENGTH(f,l) + +/* CAUTION - The following are READ-MODIFY-WRITE! */ +#define MPI2_IEEE32_pSGE_SET_FLAGS(psg,f) (psg)->FlagsLength |= MPI2_IEEE32_SGE_SET_FLAGS(f) +#define MPI2_IEEE32_pSGE_SET_LENGTH(psg,l) (psg)->FlagsLength |= MPI2_IEEE32_SGE_LENGTH(l) + + + + +/***************************************************************************** +* +* Fusion-MPT MPI/IEEE Scatter Gather Unions +* +*****************************************************************************/ + +typedef union _MPI2_SIMPLE_SGE_UNION +{ + MPI2_SGE_SIMPLE_UNION MpiSimple; + MPI2_IEEE_SGE_SIMPLE_UNION IeeeSimple; +} MPI2_SIMPLE_SGE_UNION, MPI2_POINTER PTR_MPI2_SIMPLE_SGE_UNION, + Mpi2SimpleSgeUntion_t, MPI2_POINTER pMpi2SimpleSgeUntion_t; + + +typedef union _MPI2_SGE_IO_UNION +{ + MPI2_SGE_SIMPLE_UNION MpiSimple; + MPI2_SGE_CHAIN_UNION MpiChain; + MPI2_IEEE_SGE_SIMPLE_UNION IeeeSimple; + MPI2_IEEE_SGE_CHAIN_UNION IeeeChain; +} MPI2_SGE_IO_UNION, MPI2_POINTER PTR_MPI2_SGE_IO_UNION, + Mpi2SGEIOUnion_t, MPI2_POINTER pMpi2SGEIOUnion_t; + + +/**************************************************************************** +* +* Values for SGLFlags field, used in many request messages with an SGL +* +****************************************************************************/ + +/* values for MPI SGL Data Location Address Space subfield */ +#define MPI2_SGLFLAGS_ADDRESS_SPACE_MASK (0x0C) +#define MPI2_SGLFLAGS_SYSTEM_ADDRESS_SPACE (0x00) +#define MPI2_SGLFLAGS_IOCDDR_ADDRESS_SPACE (0x04) +#define MPI2_SGLFLAGS_IOCPLB_ADDRESS_SPACE (0x08) +#define MPI2_SGLFLAGS_IOCPLBNTA_ADDRESS_SPACE (0x0C) +/* values for SGL Type subfield */ +#define MPI2_SGLFLAGS_SGL_TYPE_MASK (0x03) +#define MPI2_SGLFLAGS_SGL_TYPE_MPI (0x00) +#define MPI2_SGLFLAGS_SGL_TYPE_IEEE32 (0x01) +#define MPI2_SGLFLAGS_SGL_TYPE_IEEE64 (0x02) + + +#endif + diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h new file mode 100644 index 00000000000..2f27cf6d6c6 --- /dev/null +++ b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h @@ -0,0 +1,2151 @@ +/* + * Copyright (c) 2000-2009 LSI Corporation. + * + * + * Name: mpi2_cnfg.h + * Title: MPI Configuration messages and pages + * Creation Date: November 10, 2006 + * + * mpi2_cnfg.h Version: 02.00.10 + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * 06-04-07 02.00.01 Added defines for SAS IO Unit Page 2 PhyFlags. + * Added Manufacturing Page 11. + * Added MPI2_SAS_EXPANDER0_FLAGS_CONNECTOR_END_DEVICE + * define. + * 06-26-07 02.00.02 Adding generic structure for product-specific + * Manufacturing pages: MPI2_CONFIG_PAGE_MANUFACTURING_PS. + * Rework of BIOS Page 2 configuration page. + * Fixed MPI2_BIOSPAGE2_BOOT_DEVICE to be a union of the + * forms. + * Added configuration pages IOC Page 8 and Driver + * Persistent Mapping Page 0. + * 08-31-07 02.00.03 Modified configuration pages dealing with Integrated + * RAID (Manufacturing Page 4, RAID Volume Pages 0 and 1, + * RAID Physical Disk Pages 0 and 1, RAID Configuration + * Page 0). + * Added new value for AccessStatus field of SAS Device + * Page 0 (_SATA_NEEDS_INITIALIZATION). + * 10-31-07 02.00.04 Added missing SEPDevHandle field to + * MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0. + * 12-18-07 02.00.05 Modified IO Unit Page 0 to use 32-bit version fields for + * NVDATA. + * Modified IOC Page 7 to use masks and added field for + * SASBroadcastPrimitiveMasks. + * Added MPI2_CONFIG_PAGE_BIOS_4. + * Added MPI2_CONFIG_PAGE_LOG_0. + * 02-29-08 02.00.06 Modified various names to make them 32-character unique. + * Added SAS Device IDs. + * Updated Integrated RAID configuration pages including + * Manufacturing Page 4, IOC Page 6, and RAID Configuration + * Page 0. + * 05-21-08 02.00.07 Added define MPI2_MANPAGE4_MIX_SSD_SAS_SATA. + * Added define MPI2_MANPAGE4_PHYSDISK_128MB_COERCION. + * Fixed define MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING. + * Added missing MaxNumRoutedSasAddresses field to + * MPI2_CONFIG_PAGE_EXPANDER_0. + * Added SAS Port Page 0. + * Modified structure layout for + * MPI2_CONFIG_PAGE_DRIVER_MAPPING_0. + * 06-27-08 02.00.08 Changed MPI2_CONFIG_PAGE_RD_PDISK_1 to use + * MPI2_RAID_PHYS_DISK1_PATH_MAX to size the array. + * 10-02-08 02.00.09 Changed MPI2_RAID_PGAD_CONFIGNUM_MASK from 0x0000FFFF + * to 0x000000FF. + * Added two new values for the Physical Disk Coercion Size + * bits in the Flags field of Manufacturing Page 4. + * Added product-specific Manufacturing pages 16 to 31. + * Modified Flags bits for controlling write cache on SATA + * drives in IO Unit Page 1. + * Added new bit to AdditionalControlFlags of SAS IO Unit + * Page 1 to control Invalid Topology Correction. + * Added additional defines for RAID Volume Page 0 + * VolumeStatusFlags field. + * Modified meaning of RAID Volume Page 0 VolumeSettings + * define for auto-configure of hot-swap drives. + * Added SupportedPhysDisks field to RAID Volume Page 1 and + * added related defines. + * Added PhysDiskAttributes field (and related defines) to + * RAID Physical Disk Page 0. + * Added MPI2_SAS_PHYINFO_PHY_VACANT define. + * Added three new DiscoveryStatus bits for SAS IO Unit + * Page 0 and SAS Expander Page 0. + * Removed multiplexing information from SAS IO Unit pages. + * Added BootDeviceWaitTime field to SAS IO Unit Page 4. + * Removed Zone Address Resolved bit from PhyInfo and from + * Expander Page 0 Flags field. + * Added two new AccessStatus values to SAS Device Page 0 + * for indicating routing problems. Added 3 reserved words + * to this page. + * 01-19-09 02.00.10 Fixed defines for GPIOVal field of IO Unit Page 3. + * Inserted missing reserved field into structure for IOC + * Page 6. + * Added more pending task bits to RAID Volume Page 0 + * VolumeStatusFlags defines. + * Added MPI2_PHYSDISK0_STATUS_FLAG_NOT_CERTIFIED define. + * Added a new DiscoveryStatus bit for SAS IO Unit Page 0 + * and SAS Expander Page 0 to flag a downstream initiator + * when in simplified routing mode. + * Removed SATA Init Failure defines for DiscoveryStatus + * fields of SAS IO Unit Page 0 and SAS Expander Page 0. + * Added MPI2_SAS_DEVICE0_ASTATUS_DEVICE_BLOCKED define. + * Added PortGroups, DmaGroup, and ControlGroup fields to + * SAS Device Page 0. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI2_CNFG_H +#define MPI2_CNFG_H + +/***************************************************************************** +* Configuration Page Header and defines +*****************************************************************************/ + +/* Config Page Header */ +typedef struct _MPI2_CONFIG_PAGE_HEADER +{ + U8 PageVersion; /* 0x00 */ + U8 PageLength; /* 0x01 */ + U8 PageNumber; /* 0x02 */ + U8 PageType; /* 0x03 */ +} MPI2_CONFIG_PAGE_HEADER, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_HEADER, + Mpi2ConfigPageHeader_t, MPI2_POINTER pMpi2ConfigPageHeader_t; + +typedef union _MPI2_CONFIG_PAGE_HEADER_UNION +{ + MPI2_CONFIG_PAGE_HEADER Struct; + U8 Bytes[4]; + U16 Word16[2]; + U32 Word32; +} MPI2_CONFIG_PAGE_HEADER_UNION, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_HEADER_UNION, + Mpi2ConfigPageHeaderUnion, MPI2_POINTER pMpi2ConfigPageHeaderUnion; + +/* Extended Config Page Header */ +typedef struct _MPI2_CONFIG_EXTENDED_PAGE_HEADER +{ + U8 PageVersion; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 PageNumber; /* 0x02 */ + U8 PageType; /* 0x03 */ + U16 ExtPageLength; /* 0x04 */ + U8 ExtPageType; /* 0x06 */ + U8 Reserved2; /* 0x07 */ +} MPI2_CONFIG_EXTENDED_PAGE_HEADER, + MPI2_POINTER PTR_MPI2_CONFIG_EXTENDED_PAGE_HEADER, + Mpi2ConfigExtendedPageHeader_t, MPI2_POINTER pMpi2ConfigExtendedPageHeader_t; + +typedef union _MPI2_CONFIG_EXT_PAGE_HEADER_UNION +{ + MPI2_CONFIG_PAGE_HEADER Struct; + MPI2_CONFIG_EXTENDED_PAGE_HEADER Ext; + U8 Bytes[8]; + U16 Word16[4]; + U32 Word32[2]; +} MPI2_CONFIG_EXT_PAGE_HEADER_UNION, MPI2_POINTER PTR_MPI2_CONFIG_EXT_PAGE_HEADER_UNION, + Mpi2ConfigPageExtendedHeaderUnion, MPI2_POINTER pMpi2ConfigPageExtendedHeaderUnion; + + +/* PageType field values */ +#define MPI2_CONFIG_PAGEATTR_READ_ONLY (0x00) +#define MPI2_CONFIG_PAGEATTR_CHANGEABLE (0x10) +#define MPI2_CONFIG_PAGEATTR_PERSISTENT (0x20) +#define MPI2_CONFIG_PAGEATTR_MASK (0xF0) + +#define MPI2_CONFIG_PAGETYPE_IO_UNIT (0x00) +#define MPI2_CONFIG_PAGETYPE_IOC (0x01) +#define MPI2_CONFIG_PAGETYPE_BIOS (0x02) +#define MPI2_CONFIG_PAGETYPE_RAID_VOLUME (0x08) +#define MPI2_CONFIG_PAGETYPE_MANUFACTURING (0x09) +#define MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK (0x0A) +#define MPI2_CONFIG_PAGETYPE_EXTENDED (0x0F) +#define MPI2_CONFIG_PAGETYPE_MASK (0x0F) + +#define MPI2_CONFIG_TYPENUM_MASK (0x0FFF) + + +/* ExtPageType field values */ +#define MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT (0x10) +#define MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER (0x11) +#define MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE (0x12) +#define MPI2_CONFIG_EXTPAGETYPE_SAS_PHY (0x13) +#define MPI2_CONFIG_EXTPAGETYPE_LOG (0x14) +#define MPI2_CONFIG_EXTPAGETYPE_ENCLOSURE (0x15) +#define MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG (0x16) +#define MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING (0x17) +#define MPI2_CONFIG_EXTPAGETYPE_SAS_PORT (0x18) + + +/***************************************************************************** +* PageAddress defines +*****************************************************************************/ + +/* RAID Volume PageAddress format */ +#define MPI2_RAID_VOLUME_PGAD_FORM_MASK (0xF0000000) +#define MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE (0x00000000) +#define MPI2_RAID_VOLUME_PGAD_FORM_HANDLE (0x10000000) + +#define MPI2_RAID_VOLUME_PGAD_HANDLE_MASK (0x0000FFFF) + + +/* RAID Physical Disk PageAddress format */ +#define MPI2_PHYSDISK_PGAD_FORM_MASK (0xF0000000) +#define MPI2_PHYSDISK_PGAD_FORM_GET_NEXT_PHYSDISKNUM (0x00000000) +#define MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM (0x10000000) +#define MPI2_PHYSDISK_PGAD_FORM_DEVHANDLE (0x20000000) + +#define MPI2_PHYSDISK_PGAD_PHYSDISKNUM_MASK (0x000000FF) +#define MPI2_PHYSDISK_PGAD_DEVHANDLE_MASK (0x0000FFFF) + + +/* SAS Expander PageAddress format */ +#define MPI2_SAS_EXPAND_PGAD_FORM_MASK (0xF0000000) +#define MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL (0x00000000) +#define MPI2_SAS_EXPAND_PGAD_FORM_HNDL_PHY_NUM (0x10000000) +#define MPI2_SAS_EXPAND_PGAD_FORM_HNDL (0x20000000) + +#define MPI2_SAS_EXPAND_PGAD_HANDLE_MASK (0x0000FFFF) +#define MPI2_SAS_EXPAND_PGAD_PHYNUM_MASK (0x00FF0000) +#define MPI2_SAS_EXPAND_PGAD_PHYNUM_SHIFT (16) + + +/* SAS Device PageAddress format */ +#define MPI2_SAS_DEVICE_PGAD_FORM_MASK (0xF0000000) +#define MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE (0x00000000) +#define MPI2_SAS_DEVICE_PGAD_FORM_HANDLE (0x20000000) + +#define MPI2_SAS_DEVICE_PGAD_HANDLE_MASK (0x0000FFFF) + + +/* SAS PHY PageAddress format */ +#define MPI2_SAS_PHY_PGAD_FORM_MASK (0xF0000000) +#define MPI2_SAS_PHY_PGAD_FORM_PHY_NUMBER (0x00000000) +#define MPI2_SAS_PHY_PGAD_FORM_PHY_TBL_INDEX (0x10000000) + +#define MPI2_SAS_PHY_PGAD_PHY_NUMBER_MASK (0x000000FF) +#define MPI2_SAS_PHY_PGAD_PHY_TBL_INDEX_MASK (0x0000FFFF) + + +/* SAS Port PageAddress format */ +#define MPI2_SASPORT_PGAD_FORM_MASK (0xF0000000) +#define MPI2_SASPORT_PGAD_FORM_GET_NEXT_PORT (0x00000000) +#define MPI2_SASPORT_PGAD_FORM_PORT_NUM (0x10000000) + +#define MPI2_SASPORT_PGAD_PORTNUMBER_MASK (0x00000FFF) + + +/* SAS Enclosure PageAddress format */ +#define MPI2_SAS_ENCLOS_PGAD_FORM_MASK (0xF0000000) +#define MPI2_SAS_ENCLOS_PGAD_FORM_GET_NEXT_HANDLE (0x00000000) +#define MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE (0x10000000) + +#define MPI2_SAS_ENCLOS_PGAD_HANDLE_MASK (0x0000FFFF) + + +/* RAID Configuration PageAddress format */ +#define MPI2_RAID_PGAD_FORM_MASK (0xF0000000) +#define MPI2_RAID_PGAD_FORM_GET_NEXT_CONFIGNUM (0x00000000) +#define MPI2_RAID_PGAD_FORM_CONFIGNUM (0x10000000) +#define MPI2_RAID_PGAD_FORM_ACTIVE_CONFIG (0x20000000) + +#define MPI2_RAID_PGAD_CONFIGNUM_MASK (0x000000FF) + + +/* Driver Persistent Mapping PageAddress format */ +#define MPI2_DPM_PGAD_FORM_MASK (0xF0000000) +#define MPI2_DPM_PGAD_FORM_ENTRY_RANGE (0x00000000) + +#define MPI2_DPM_PGAD_ENTRY_COUNT_MASK (0x0FFF0000) +#define MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT (16) +#define MPI2_DPM_PGAD_START_ENTRY_MASK (0x0000FFFF) + + +/**************************************************************************** +* Configuration messages +****************************************************************************/ + +/* Configuration Request Message */ +typedef struct _MPI2_CONFIG_REQUEST +{ + U8 Action; /* 0x00 */ + U8 SGLFlags; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 ExtPageLength; /* 0x04 */ + U8 ExtPageType; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved1; /* 0x0A */ + U32 Reserved2; /* 0x0C */ + U32 Reserved3; /* 0x10 */ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x14 */ + U32 PageAddress; /* 0x18 */ + MPI2_SGE_IO_UNION PageBufferSGE; /* 0x1C */ +} MPI2_CONFIG_REQUEST, MPI2_POINTER PTR_MPI2_CONFIG_REQUEST, + Mpi2ConfigRequest_t, MPI2_POINTER pMpi2ConfigRequest_t; + +/* values for the Action field */ +#define MPI2_CONFIG_ACTION_PAGE_HEADER (0x00) +#define MPI2_CONFIG_ACTION_PAGE_READ_CURRENT (0x01) +#define MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT (0x02) +#define MPI2_CONFIG_ACTION_PAGE_DEFAULT (0x03) +#define MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM (0x04) +#define MPI2_CONFIG_ACTION_PAGE_READ_DEFAULT (0x05) +#define MPI2_CONFIG_ACTION_PAGE_READ_NVRAM (0x06) +#define MPI2_CONFIG_ACTION_PAGE_GET_CHANGEABLE (0x07) + +/* values for SGLFlags field are in the SGL section of mpi2.h */ + + +/* Config Reply Message */ +typedef struct _MPI2_CONFIG_REPLY +{ + U8 Action; /* 0x00 */ + U8 SGLFlags; /* 0x01 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 ExtPageLength; /* 0x04 */ + U8 ExtPageType; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved1; /* 0x0A */ + U16 Reserved2; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x14 */ +} MPI2_CONFIG_REPLY, MPI2_POINTER PTR_MPI2_CONFIG_REPLY, + Mpi2ConfigReply_t, MPI2_POINTER pMpi2ConfigReply_t; + + + +/***************************************************************************** +* +* C o n f i g u r a t i o n P a g e s +* +*****************************************************************************/ + +/**************************************************************************** +* Manufacturing Config pages +****************************************************************************/ + +#define MPI2_MFGPAGE_VENDORID_LSI (0x1000) + +/* SAS */ +#define MPI2_MFGPAGE_DEVID_SAS2004 (0x0070) +#define MPI2_MFGPAGE_DEVID_SAS2008 (0x0072) +#define MPI2_MFGPAGE_DEVID_SAS2108_1 (0x0074) +#define MPI2_MFGPAGE_DEVID_SAS2108_2 (0x0076) +#define MPI2_MFGPAGE_DEVID_SAS2108_3 (0x0077) +#define MPI2_MFGPAGE_DEVID_SAS2116_1 (0x0064) +#define MPI2_MFGPAGE_DEVID_SAS2116_2 (0x0065) + + +/* Manufacturing Page 0 */ + +typedef struct _MPI2_CONFIG_PAGE_MAN_0 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U8 ChipName[16]; /* 0x04 */ + U8 ChipRevision[8]; /* 0x14 */ + U8 BoardName[16]; /* 0x1C */ + U8 BoardAssembly[16]; /* 0x2C */ + U8 BoardTracerNumber[16]; /* 0x3C */ +} MPI2_CONFIG_PAGE_MAN_0, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_0, + Mpi2ManufacturingPage0_t, MPI2_POINTER pMpi2ManufacturingPage0_t; + +#define MPI2_MANUFACTURING0_PAGEVERSION (0x00) + + +/* Manufacturing Page 1 */ + +typedef struct _MPI2_CONFIG_PAGE_MAN_1 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U8 VPD[256]; /* 0x04 */ +} MPI2_CONFIG_PAGE_MAN_1, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_1, + Mpi2ManufacturingPage1_t, MPI2_POINTER pMpi2ManufacturingPage1_t; + +#define MPI2_MANUFACTURING1_PAGEVERSION (0x00) + + +typedef struct _MPI2_CHIP_REVISION_ID +{ + U16 DeviceID; /* 0x00 */ + U8 PCIRevisionID; /* 0x02 */ + U8 Reserved; /* 0x03 */ +} MPI2_CHIP_REVISION_ID, MPI2_POINTER PTR_MPI2_CHIP_REVISION_ID, + Mpi2ChipRevisionId_t, MPI2_POINTER pMpi2ChipRevisionId_t; + + +/* Manufacturing Page 2 */ + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check Header.PageLength at runtime. + */ +#ifndef MPI2_MAN_PAGE_2_HW_SETTINGS_WORDS +#define MPI2_MAN_PAGE_2_HW_SETTINGS_WORDS (1) +#endif + +typedef struct _MPI2_CONFIG_PAGE_MAN_2 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + MPI2_CHIP_REVISION_ID ChipId; /* 0x04 */ + U32 HwSettings[MPI2_MAN_PAGE_2_HW_SETTINGS_WORDS];/* 0x08 */ +} MPI2_CONFIG_PAGE_MAN_2, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_2, + Mpi2ManufacturingPage2_t, MPI2_POINTER pMpi2ManufacturingPage2_t; + +#define MPI2_MANUFACTURING2_PAGEVERSION (0x00) + + +/* Manufacturing Page 3 */ + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check Header.PageLength at runtime. + */ +#ifndef MPI2_MAN_PAGE_3_INFO_WORDS +#define MPI2_MAN_PAGE_3_INFO_WORDS (1) +#endif + +typedef struct _MPI2_CONFIG_PAGE_MAN_3 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + MPI2_CHIP_REVISION_ID ChipId; /* 0x04 */ + U32 Info[MPI2_MAN_PAGE_3_INFO_WORDS];/* 0x08 */ +} MPI2_CONFIG_PAGE_MAN_3, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_3, + Mpi2ManufacturingPage3_t, MPI2_POINTER pMpi2ManufacturingPage3_t; + +#define MPI2_MANUFACTURING3_PAGEVERSION (0x00) + + +/* Manufacturing Page 4 */ + +typedef struct _MPI2_MANPAGE4_PWR_SAVE_SETTINGS +{ + U8 PowerSaveFlags; /* 0x00 */ + U8 InternalOperationsSleepTime; /* 0x01 */ + U8 InternalOperationsRunTime; /* 0x02 */ + U8 HostIdleTime; /* 0x03 */ +} MPI2_MANPAGE4_PWR_SAVE_SETTINGS, + MPI2_POINTER PTR_MPI2_MANPAGE4_PWR_SAVE_SETTINGS, + Mpi2ManPage4PwrSaveSettings_t, MPI2_POINTER pMpi2ManPage4PwrSaveSettings_t; + +/* defines for the PowerSaveFlags field */ +#define MPI2_MANPAGE4_MASK_POWERSAVE_MODE (0x03) +#define MPI2_MANPAGE4_POWERSAVE_MODE_DISABLED (0x00) +#define MPI2_MANPAGE4_CUSTOM_POWERSAVE_MODE (0x01) +#define MPI2_MANPAGE4_FULL_POWERSAVE_MODE (0x02) + +typedef struct _MPI2_CONFIG_PAGE_MAN_4 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved1; /* 0x04 */ + U32 Flags; /* 0x08 */ + U8 InquirySize; /* 0x0C */ + U8 Reserved2; /* 0x0D */ + U16 Reserved3; /* 0x0E */ + U8 InquiryData[56]; /* 0x10 */ + U32 RAID0VolumeSettings; /* 0x48 */ + U32 RAID1EVolumeSettings; /* 0x4C */ + U32 RAID1VolumeSettings; /* 0x50 */ + U32 RAID10VolumeSettings; /* 0x54 */ + U32 Reserved4; /* 0x58 */ + U32 Reserved5; /* 0x5C */ + MPI2_MANPAGE4_PWR_SAVE_SETTINGS PowerSaveSettings; /* 0x60 */ + U8 MaxOCEDisks; /* 0x64 */ + U8 ResyncRate; /* 0x65 */ + U16 DataScrubDuration; /* 0x66 */ + U8 MaxHotSpares; /* 0x68 */ + U8 MaxPhysDisksPerVol; /* 0x69 */ + U8 MaxPhysDisks; /* 0x6A */ + U8 MaxVolumes; /* 0x6B */ +} MPI2_CONFIG_PAGE_MAN_4, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_4, + Mpi2ManufacturingPage4_t, MPI2_POINTER pMpi2ManufacturingPage4_t; + +#define MPI2_MANUFACTURING4_PAGEVERSION (0x0A) + +/* Manufacturing Page 4 Flags field */ +#define MPI2_MANPAGE4_METADATA_SIZE_MASK (0x00030000) +#define MPI2_MANPAGE4_METADATA_512MB (0x00000000) + +#define MPI2_MANPAGE4_MIX_SSD_SAS_SATA (0x00008000) +#define MPI2_MANPAGE4_MIX_SSD_AND_NON_SSD (0x00004000) +#define MPI2_MANPAGE4_HIDE_PHYSDISK_NON_IR (0x00002000) + +#define MPI2_MANPAGE4_MASK_PHYSDISK_COERCION (0x00001C00) +#define MPI2_MANPAGE4_PHYSDISK_COERCION_1GB (0x00000000) +#define MPI2_MANPAGE4_PHYSDISK_128MB_COERCION (0x00000400) +#define MPI2_MANPAGE4_PHYSDISK_ADAPTIVE_COERCION (0x00000800) +#define MPI2_MANPAGE4_PHYSDISK_ZERO_COERCION (0x00000C00) + +#define MPI2_MANPAGE4_MASK_BAD_BLOCK_MARKING (0x00000300) +#define MPI2_MANPAGE4_DEFAULT_BAD_BLOCK_MARKING (0x00000000) +#define MPI2_MANPAGE4_TABLE_BAD_BLOCK_MARKING (0x00000100) +#define MPI2_MANPAGE4_WRITE_LONG_BAD_BLOCK_MARKING (0x00000200) + +#define MPI2_MANPAGE4_FORCE_OFFLINE_FAILOVER (0x00000080) +#define MPI2_MANPAGE4_RAID10_DISABLE (0x00000040) +#define MPI2_MANPAGE4_RAID1E_DISABLE (0x00000020) +#define MPI2_MANPAGE4_RAID1_DISABLE (0x00000010) +#define MPI2_MANPAGE4_RAID0_DISABLE (0x00000008) +#define MPI2_MANPAGE4_IR_MODEPAGE8_DISABLE (0x00000004) +#define MPI2_MANPAGE4_IM_RESYNC_CACHE_ENABLE (0x00000002) +#define MPI2_MANPAGE4_IR_NO_MIX_SAS_SATA (0x00000001) + + +/* Manufacturing Page 5 */ + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check Header.PageLength or NumPhys at runtime. + */ +#ifndef MPI2_MAN_PAGE_5_PHY_ENTRIES +#define MPI2_MAN_PAGE_5_PHY_ENTRIES (1) +#endif + +typedef struct _MPI2_MANUFACTURING5_ENTRY +{ + U64 WWID; /* 0x00 */ + U64 DeviceName; /* 0x08 */ +} MPI2_MANUFACTURING5_ENTRY, MPI2_POINTER PTR_MPI2_MANUFACTURING5_ENTRY, + Mpi2Manufacturing5Entry_t, MPI2_POINTER pMpi2Manufacturing5Entry_t; + +typedef struct _MPI2_CONFIG_PAGE_MAN_5 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U8 NumPhys; /* 0x04 */ + U8 Reserved1; /* 0x05 */ + U16 Reserved2; /* 0x06 */ + U32 Reserved3; /* 0x08 */ + U32 Reserved4; /* 0x0C */ + MPI2_MANUFACTURING5_ENTRY Phy[MPI2_MAN_PAGE_5_PHY_ENTRIES];/* 0x08 */ +} MPI2_CONFIG_PAGE_MAN_5, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_5, + Mpi2ManufacturingPage5_t, MPI2_POINTER pMpi2ManufacturingPage5_t; + +#define MPI2_MANUFACTURING5_PAGEVERSION (0x03) + + +/* Manufacturing Page 6 */ + +typedef struct _MPI2_CONFIG_PAGE_MAN_6 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 ProductSpecificInfo;/* 0x04 */ +} MPI2_CONFIG_PAGE_MAN_6, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_6, + Mpi2ManufacturingPage6_t, MPI2_POINTER pMpi2ManufacturingPage6_t; + +#define MPI2_MANUFACTURING6_PAGEVERSION (0x00) + + +/* Manufacturing Page 7 */ + +typedef struct _MPI2_MANPAGE7_CONNECTOR_INFO +{ + U32 Pinout; /* 0x00 */ + U8 Connector[16]; /* 0x04 */ + U8 Location; /* 0x14 */ + U8 Reserved1; /* 0x15 */ + U16 Slot; /* 0x16 */ + U32 Reserved2; /* 0x18 */ +} MPI2_MANPAGE7_CONNECTOR_INFO, MPI2_POINTER PTR_MPI2_MANPAGE7_CONNECTOR_INFO, + Mpi2ManPage7ConnectorInfo_t, MPI2_POINTER pMpi2ManPage7ConnectorInfo_t; + +/* defines for the Pinout field */ +#define MPI2_MANPAGE7_PINOUT_SFF_8484_L4 (0x00080000) +#define MPI2_MANPAGE7_PINOUT_SFF_8484_L3 (0x00040000) +#define MPI2_MANPAGE7_PINOUT_SFF_8484_L2 (0x00020000) +#define MPI2_MANPAGE7_PINOUT_SFF_8484_L1 (0x00010000) +#define MPI2_MANPAGE7_PINOUT_SFF_8470_L4 (0x00000800) +#define MPI2_MANPAGE7_PINOUT_SFF_8470_L3 (0x00000400) +#define MPI2_MANPAGE7_PINOUT_SFF_8470_L2 (0x00000200) +#define MPI2_MANPAGE7_PINOUT_SFF_8470_L1 (0x00000100) +#define MPI2_MANPAGE7_PINOUT_SFF_8482 (0x00000002) +#define MPI2_MANPAGE7_PINOUT_CONNECTION_UNKNOWN (0x00000001) + +/* defines for the Location field */ +#define MPI2_MANPAGE7_LOCATION_UNKNOWN (0x01) +#define MPI2_MANPAGE7_LOCATION_INTERNAL (0x02) +#define MPI2_MANPAGE7_LOCATION_EXTERNAL (0x04) +#define MPI2_MANPAGE7_LOCATION_SWITCHABLE (0x08) +#define MPI2_MANPAGE7_LOCATION_AUTO (0x10) +#define MPI2_MANPAGE7_LOCATION_NOT_PRESENT (0x20) +#define MPI2_MANPAGE7_LOCATION_NOT_CONNECTED (0x80) + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check NumPhys at runtime. + */ +#ifndef MPI2_MANPAGE7_CONNECTOR_INFO_MAX +#define MPI2_MANPAGE7_CONNECTOR_INFO_MAX (1) +#endif + +typedef struct _MPI2_CONFIG_PAGE_MAN_7 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved1; /* 0x04 */ + U32 Reserved2; /* 0x08 */ + U32 Flags; /* 0x0C */ + U8 EnclosureName[16]; /* 0x10 */ + U8 NumPhys; /* 0x20 */ + U8 Reserved3; /* 0x21 */ + U16 Reserved4; /* 0x22 */ + MPI2_MANPAGE7_CONNECTOR_INFO ConnectorInfo[MPI2_MANPAGE7_CONNECTOR_INFO_MAX]; /* 0x24 */ +} MPI2_CONFIG_PAGE_MAN_7, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_7, + Mpi2ManufacturingPage7_t, MPI2_POINTER pMpi2ManufacturingPage7_t; + +#define MPI2_MANUFACTURING7_PAGEVERSION (0x00) + +/* defines for the Flags field */ +#define MPI2_MANPAGE7_FLAG_USE_SLOT_INFO (0x00000001) + + +/* + * Generic structure to use for product-specific manufacturing pages + * (currently Manufacturing Page 8 through Manufacturing Page 31). + */ + +typedef struct _MPI2_CONFIG_PAGE_MAN_PS +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 ProductSpecificInfo;/* 0x04 */ +} MPI2_CONFIG_PAGE_MAN_PS, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_PS, + Mpi2ManufacturingPagePS_t, MPI2_POINTER pMpi2ManufacturingPagePS_t; + +#define MPI2_MANUFACTURING8_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING9_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING10_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING11_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING12_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING13_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING14_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING15_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING16_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING17_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING18_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING19_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING20_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING21_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING22_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING23_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING24_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING25_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING26_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING27_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING28_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING29_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING30_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING31_PAGEVERSION (0x00) + + +/**************************************************************************** +* IO Unit Config Pages +****************************************************************************/ + +/* IO Unit Page 0 */ + +typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_0 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U64 UniqueValue; /* 0x04 */ + MPI2_VERSION_UNION NvdataVersionDefault; /* 0x08 */ + MPI2_VERSION_UNION NvdataVersionPersistent; /* 0x0A */ +} MPI2_CONFIG_PAGE_IO_UNIT_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_0, + Mpi2IOUnitPage0_t, MPI2_POINTER pMpi2IOUnitPage0_t; + +#define MPI2_IOUNITPAGE0_PAGEVERSION (0x02) + + +/* IO Unit Page 1 */ + +typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_1 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Flags; /* 0x04 */ +} MPI2_CONFIG_PAGE_IO_UNIT_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_1, + Mpi2IOUnitPage1_t, MPI2_POINTER pMpi2IOUnitPage1_t; + +#define MPI2_IOUNITPAGE1_PAGEVERSION (0x04) + +/* IO Unit Page 1 Flags defines */ +#define MPI2_IOUNITPAGE1_MASK_SATA_WRITE_CACHE (0x00000600) +#define MPI2_IOUNITPAGE1_ENABLE_SATA_WRITE_CACHE (0x00000000) +#define MPI2_IOUNITPAGE1_DISABLE_SATA_WRITE_CACHE (0x00000200) +#define MPI2_IOUNITPAGE1_UNCHANGED_SATA_WRITE_CACHE (0x00000400) +#define MPI2_IOUNITPAGE1_NATIVE_COMMAND_Q_DISABLE (0x00000100) +#define MPI2_IOUNITPAGE1_DISABLE_IR (0x00000040) +#define MPI2_IOUNITPAGE1_DISABLE_TASK_SET_FULL_HANDLING (0x00000020) +#define MPI2_IOUNITPAGE1_IR_USE_STATIC_VOLUME_ID (0x00000004) +#define MPI2_IOUNITPAGE1_MULTI_PATHING (0x00000002) +#define MPI2_IOUNITPAGE1_SINGLE_PATHING (0x00000000) + + +/* IO Unit Page 3 */ + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check Header.PageLength at runtime. + */ +#ifndef MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX +#define MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX (1) +#endif + +typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_3 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U8 GPIOCount; /* 0x04 */ + U8 Reserved1; /* 0x05 */ + U16 Reserved2; /* 0x06 */ + U16 GPIOVal[MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX];/* 0x08 */ +} MPI2_CONFIG_PAGE_IO_UNIT_3, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_3, + Mpi2IOUnitPage3_t, MPI2_POINTER pMpi2IOUnitPage3_t; + +#define MPI2_IOUNITPAGE3_PAGEVERSION (0x01) + +/* defines for IO Unit Page 3 GPIOVal field */ +#define MPI2_IOUNITPAGE3_GPIO_FUNCTION_MASK (0xFFFC) +#define MPI2_IOUNITPAGE3_GPIO_FUNCTION_SHIFT (2) +#define MPI2_IOUNITPAGE3_GPIO_SETTING_OFF (0x0000) +#define MPI2_IOUNITPAGE3_GPIO_SETTING_ON (0x0001) + + +/**************************************************************************** +* IOC Config Pages +****************************************************************************/ + +/* IOC Page 0 */ + +typedef struct _MPI2_CONFIG_PAGE_IOC_0 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved1; /* 0x04 */ + U32 Reserved2; /* 0x08 */ + U16 VendorID; /* 0x0C */ + U16 DeviceID; /* 0x0E */ + U8 RevisionID; /* 0x10 */ + U8 Reserved3; /* 0x11 */ + U16 Reserved4; /* 0x12 */ + U32 ClassCode; /* 0x14 */ + U16 SubsystemVendorID; /* 0x18 */ + U16 SubsystemID; /* 0x1A */ +} MPI2_CONFIG_PAGE_IOC_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IOC_0, + Mpi2IOCPage0_t, MPI2_POINTER pMpi2IOCPage0_t; + +#define MPI2_IOCPAGE0_PAGEVERSION (0x02) + + +/* IOC Page 1 */ + +typedef struct _MPI2_CONFIG_PAGE_IOC_1 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Flags; /* 0x04 */ + U32 CoalescingTimeout; /* 0x08 */ + U8 CoalescingDepth; /* 0x0C */ + U8 PCISlotNum; /* 0x0D */ + U8 PCIBusNum; /* 0x0E */ + U8 PCIDomainSegment; /* 0x0F */ + U32 Reserved1; /* 0x10 */ + U32 Reserved2; /* 0x14 */ +} MPI2_CONFIG_PAGE_IOC_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IOC_1, + Mpi2IOCPage1_t, MPI2_POINTER pMpi2IOCPage1_t; + +#define MPI2_IOCPAGE1_PAGEVERSION (0x05) + +/* defines for IOC Page 1 Flags field */ +#define MPI2_IOCPAGE1_REPLY_COALESCING (0x00000001) + +#define MPI2_IOCPAGE1_PCISLOTNUM_UNKNOWN (0xFF) +#define MPI2_IOCPAGE1_PCIBUSNUM_UNKNOWN (0xFF) +#define MPI2_IOCPAGE1_PCIDOMAIN_UNKNOWN (0xFF) + +/* IOC Page 6 */ + +typedef struct _MPI2_CONFIG_PAGE_IOC_6 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 CapabilitiesFlags; /* 0x04 */ + U8 MaxDrivesRAID0; /* 0x08 */ + U8 MaxDrivesRAID1; /* 0x09 */ + U8 MaxDrivesRAID1E; /* 0x0A */ + U8 MaxDrivesRAID10; /* 0x0B */ + U8 MinDrivesRAID0; /* 0x0C */ + U8 MinDrivesRAID1; /* 0x0D */ + U8 MinDrivesRAID1E; /* 0x0E */ + U8 MinDrivesRAID10; /* 0x0F */ + U32 Reserved1; /* 0x10 */ + U8 MaxGlobalHotSpares; /* 0x14 */ + U8 MaxPhysDisks; /* 0x15 */ + U8 MaxVolumes; /* 0x16 */ + U8 MaxConfigs; /* 0x17 */ + U8 MaxOCEDisks; /* 0x18 */ + U8 Reserved2; /* 0x19 */ + U16 Reserved3; /* 0x1A */ + U32 SupportedStripeSizeMapRAID0; /* 0x1C */ + U32 SupportedStripeSizeMapRAID1E; /* 0x20 */ + U32 SupportedStripeSizeMapRAID10; /* 0x24 */ + U32 Reserved4; /* 0x28 */ + U32 Reserved5; /* 0x2C */ + U16 DefaultMetadataSize; /* 0x30 */ + U16 Reserved6; /* 0x32 */ + U16 MaxBadBlockTableEntries; /* 0x34 */ + U16 Reserved7; /* 0x36 */ + U32 IRNvsramVersion; /* 0x38 */ +} MPI2_CONFIG_PAGE_IOC_6, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IOC_6, + Mpi2IOCPage6_t, MPI2_POINTER pMpi2IOCPage6_t; + +#define MPI2_IOCPAGE6_PAGEVERSION (0x04) + +/* defines for IOC Page 6 CapabilitiesFlags */ +#define MPI2_IOCPAGE6_CAP_FLAGS_RAID10_SUPPORT (0x00000010) +#define MPI2_IOCPAGE6_CAP_FLAGS_RAID1_SUPPORT (0x00000008) +#define MPI2_IOCPAGE6_CAP_FLAGS_RAID1E_SUPPORT (0x00000004) +#define MPI2_IOCPAGE6_CAP_FLAGS_RAID0_SUPPORT (0x00000002) +#define MPI2_IOCPAGE6_CAP_FLAGS_GLOBAL_HOT_SPARE (0x00000001) + + +/* IOC Page 7 */ + +#define MPI2_IOCPAGE7_EVENTMASK_WORDS (4) + +typedef struct _MPI2_CONFIG_PAGE_IOC_7 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved1; /* 0x04 */ + U32 EventMasks[MPI2_IOCPAGE7_EVENTMASK_WORDS];/* 0x08 */ + U16 SASBroadcastPrimitiveMasks; /* 0x18 */ + U16 Reserved2; /* 0x1A */ + U32 Reserved3; /* 0x1C */ +} MPI2_CONFIG_PAGE_IOC_7, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IOC_7, + Mpi2IOCPage7_t, MPI2_POINTER pMpi2IOCPage7_t; + +#define MPI2_IOCPAGE7_PAGEVERSION (0x01) + + +/* IOC Page 8 */ + +typedef struct _MPI2_CONFIG_PAGE_IOC_8 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U8 NumDevsPerEnclosure; /* 0x04 */ + U8 Reserved1; /* 0x05 */ + U16 Reserved2; /* 0x06 */ + U16 MaxPersistentEntries; /* 0x08 */ + U16 MaxNumPhysicalMappedIDs; /* 0x0A */ + U16 Flags; /* 0x0C */ + U16 Reserved3; /* 0x0E */ + U16 IRVolumeMappingFlags; /* 0x10 */ + U16 Reserved4; /* 0x12 */ + U32 Reserved5; /* 0x14 */ +} MPI2_CONFIG_PAGE_IOC_8, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IOC_8, + Mpi2IOCPage8_t, MPI2_POINTER pMpi2IOCPage8_t; + +#define MPI2_IOCPAGE8_PAGEVERSION (0x00) + +/* defines for IOC Page 8 Flags field */ +#define MPI2_IOCPAGE8_FLAGS_DA_START_SLOT_1 (0x00000020) +#define MPI2_IOCPAGE8_FLAGS_RESERVED_TARGETID_0 (0x00000010) + +#define MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE (0x0000000E) +#define MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING (0x00000000) +#define MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING (0x00000002) + +#define MPI2_IOCPAGE8_FLAGS_DISABLE_PERSISTENT_MAPPING (0x00000001) +#define MPI2_IOCPAGE8_FLAGS_ENABLE_PERSISTENT_MAPPING (0x00000000) + +/* defines for IOC Page 8 IRVolumeMappingFlags */ +#define MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE (0x00000003) +#define MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING (0x00000000) +#define MPI2_IOCPAGE8_IRFLAGS_HIGH_VOLUME_MAPPING (0x00000001) + + +/**************************************************************************** +* BIOS Config Pages +****************************************************************************/ + +/* BIOS Page 1 */ + +typedef struct _MPI2_CONFIG_PAGE_BIOS_1 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 BiosOptions; /* 0x04 */ + U32 IOCSettings; /* 0x08 */ + U32 Reserved1; /* 0x0C */ + U32 DeviceSettings; /* 0x10 */ + U16 NumberOfDevices; /* 0x14 */ + U16 Reserved2; /* 0x16 */ + U16 IOTimeoutBlockDevicesNonRM; /* 0x18 */ + U16 IOTimeoutSequential; /* 0x1A */ + U16 IOTimeoutOther; /* 0x1C */ + U16 IOTimeoutBlockDevicesRM; /* 0x1E */ +} MPI2_CONFIG_PAGE_BIOS_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_BIOS_1, + Mpi2BiosPage1_t, MPI2_POINTER pMpi2BiosPage1_t; + +#define MPI2_BIOSPAGE1_PAGEVERSION (0x04) + +/* values for BIOS Page 1 BiosOptions field */ +#define MPI2_BIOSPAGE1_OPTIONS_DISABLE_BIOS (0x00000001) + +/* values for BIOS Page 1 IOCSettings field */ +#define MPI2_BIOSPAGE1_IOCSET_MASK_BOOT_PREFERENCE (0x00030000) +#define MPI2_BIOSPAGE1_IOCSET_ENCLOSURE_SLOT_BOOT (0x00000000) +#define MPI2_BIOSPAGE1_IOCSET_SAS_ADDRESS_BOOT (0x00010000) + +#define MPI2_BIOSPAGE1_IOCSET_MASK_RM_SETTING (0x000000C0) +#define MPI2_BIOSPAGE1_IOCSET_NONE_RM_SETTING (0x00000000) +#define MPI2_BIOSPAGE1_IOCSET_BOOT_RM_SETTING (0x00000040) +#define MPI2_BIOSPAGE1_IOCSET_MEDIA_RM_SETTING (0x00000080) + +#define MPI2_BIOSPAGE1_IOCSET_MASK_ADAPTER_SUPPORT (0x00000030) +#define MPI2_BIOSPAGE1_IOCSET_NO_SUPPORT (0x00000000) +#define MPI2_BIOSPAGE1_IOCSET_BIOS_SUPPORT (0x00000010) +#define MPI2_BIOSPAGE1_IOCSET_OS_SUPPORT (0x00000020) +#define MPI2_BIOSPAGE1_IOCSET_ALL_SUPPORT (0x00000030) + +#define MPI2_BIOSPAGE1_IOCSET_ALTERNATE_CHS (0x00000008) + +/* values for BIOS Page 1 DeviceSettings field */ +#define MPI2_BIOSPAGE1_DEVSET_DISABLE_SMART_POLLING (0x00000010) +#define MPI2_BIOSPAGE1_DEVSET_DISABLE_SEQ_LUN (0x00000008) +#define MPI2_BIOSPAGE1_DEVSET_DISABLE_RM_LUN (0x00000004) +#define MPI2_BIOSPAGE1_DEVSET_DISABLE_NON_RM_LUN (0x00000002) +#define MPI2_BIOSPAGE1_DEVSET_DISABLE_OTHER_LUN (0x00000001) + + +/* BIOS Page 2 */ + +typedef struct _MPI2_BOOT_DEVICE_ADAPTER_ORDER +{ + U32 Reserved1; /* 0x00 */ + U32 Reserved2; /* 0x04 */ + U32 Reserved3; /* 0x08 */ + U32 Reserved4; /* 0x0C */ + U32 Reserved5; /* 0x10 */ + U32 Reserved6; /* 0x14 */ +} MPI2_BOOT_DEVICE_ADAPTER_ORDER, + MPI2_POINTER PTR_MPI2_BOOT_DEVICE_ADAPTER_ORDER, + Mpi2BootDeviceAdapterOrder_t, MPI2_POINTER pMpi2BootDeviceAdapterOrder_t; + +typedef struct _MPI2_BOOT_DEVICE_SAS_WWID +{ + U64 SASAddress; /* 0x00 */ + U8 LUN[8]; /* 0x08 */ + U32 Reserved1; /* 0x10 */ + U32 Reserved2; /* 0x14 */ +} MPI2_BOOT_DEVICE_SAS_WWID, MPI2_POINTER PTR_MPI2_BOOT_DEVICE_SAS_WWID, + Mpi2BootDeviceSasWwid_t, MPI2_POINTER pMpi2BootDeviceSasWwid_t; + +typedef struct _MPI2_BOOT_DEVICE_ENCLOSURE_SLOT +{ + U64 EnclosureLogicalID; /* 0x00 */ + U32 Reserved1; /* 0x08 */ + U32 Reserved2; /* 0x0C */ + U16 SlotNumber; /* 0x10 */ + U16 Reserved3; /* 0x12 */ + U32 Reserved4; /* 0x14 */ +} MPI2_BOOT_DEVICE_ENCLOSURE_SLOT, + MPI2_POINTER PTR_MPI2_BOOT_DEVICE_ENCLOSURE_SLOT, + Mpi2BootDeviceEnclosureSlot_t, MPI2_POINTER pMpi2BootDeviceEnclosureSlot_t; + +typedef struct _MPI2_BOOT_DEVICE_DEVICE_NAME +{ + U64 DeviceName; /* 0x00 */ + U8 LUN[8]; /* 0x08 */ + U32 Reserved1; /* 0x10 */ + U32 Reserved2; /* 0x14 */ +} MPI2_BOOT_DEVICE_DEVICE_NAME, MPI2_POINTER PTR_MPI2_BOOT_DEVICE_DEVICE_NAME, + Mpi2BootDeviceDeviceName_t, MPI2_POINTER pMpi2BootDeviceDeviceName_t; + +typedef union _MPI2_MPI2_BIOSPAGE2_BOOT_DEVICE +{ + MPI2_BOOT_DEVICE_ADAPTER_ORDER AdapterOrder; + MPI2_BOOT_DEVICE_SAS_WWID SasWwid; + MPI2_BOOT_DEVICE_ENCLOSURE_SLOT EnclosureSlot; + MPI2_BOOT_DEVICE_DEVICE_NAME DeviceName; +} MPI2_BIOSPAGE2_BOOT_DEVICE, MPI2_POINTER PTR_MPI2_BIOSPAGE2_BOOT_DEVICE, + Mpi2BiosPage2BootDevice_t, MPI2_POINTER pMpi2BiosPage2BootDevice_t; + +typedef struct _MPI2_CONFIG_PAGE_BIOS_2 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved1; /* 0x04 */ + U32 Reserved2; /* 0x08 */ + U32 Reserved3; /* 0x0C */ + U32 Reserved4; /* 0x10 */ + U32 Reserved5; /* 0x14 */ + U32 Reserved6; /* 0x18 */ + U8 ReqBootDeviceForm; /* 0x1C */ + U8 Reserved7; /* 0x1D */ + U16 Reserved8; /* 0x1E */ + MPI2_BIOSPAGE2_BOOT_DEVICE RequestedBootDevice; /* 0x20 */ + U8 ReqAltBootDeviceForm; /* 0x38 */ + U8 Reserved9; /* 0x39 */ + U16 Reserved10; /* 0x3A */ + MPI2_BIOSPAGE2_BOOT_DEVICE RequestedAltBootDevice; /* 0x3C */ + U8 CurrentBootDeviceForm; /* 0x58 */ + U8 Reserved11; /* 0x59 */ + U16 Reserved12; /* 0x5A */ + MPI2_BIOSPAGE2_BOOT_DEVICE CurrentBootDevice; /* 0x58 */ +} MPI2_CONFIG_PAGE_BIOS_2, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_BIOS_2, + Mpi2BiosPage2_t, MPI2_POINTER pMpi2BiosPage2_t; + +#define MPI2_BIOSPAGE2_PAGEVERSION (0x04) + +/* values for BIOS Page 2 BootDeviceForm fields */ +#define MPI2_BIOSPAGE2_FORM_MASK (0x0F) +#define MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED (0x00) +#define MPI2_BIOSPAGE2_FORM_SAS_WWID (0x05) +#define MPI2_BIOSPAGE2_FORM_ENCLOSURE_SLOT (0x06) +#define MPI2_BIOSPAGE2_FORM_DEVICE_NAME (0x07) + + +/* BIOS Page 3 */ + +typedef struct _MPI2_ADAPTER_INFO +{ + U8 PciBusNumber; /* 0x00 */ + U8 PciDeviceAndFunctionNumber; /* 0x01 */ + U16 AdapterFlags; /* 0x02 */ +} MPI2_ADAPTER_INFO, MPI2_POINTER PTR_MPI2_ADAPTER_INFO, + Mpi2AdapterInfo_t, MPI2_POINTER pMpi2AdapterInfo_t; + +#define MPI2_ADAPTER_INFO_FLAGS_EMBEDDED (0x0001) +#define MPI2_ADAPTER_INFO_FLAGS_INIT_STATUS (0x0002) + +typedef struct _MPI2_CONFIG_PAGE_BIOS_3 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 GlobalFlags; /* 0x04 */ + U32 BiosVersion; /* 0x08 */ + MPI2_ADAPTER_INFO AdapterOrder[4]; /* 0x0C */ + U32 Reserved1; /* 0x1C */ +} MPI2_CONFIG_PAGE_BIOS_3, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_BIOS_3, + Mpi2BiosPage3_t, MPI2_POINTER pMpi2BiosPage3_t; + +#define MPI2_BIOSPAGE3_PAGEVERSION (0x00) + +/* values for BIOS Page 3 GlobalFlags */ +#define MPI2_BIOSPAGE3_FLAGS_PAUSE_ON_ERROR (0x00000002) +#define MPI2_BIOSPAGE3_FLAGS_VERBOSE_ENABLE (0x00000004) +#define MPI2_BIOSPAGE3_FLAGS_HOOK_INT_40_DISABLE (0x00000010) + +#define MPI2_BIOSPAGE3_FLAGS_DEV_LIST_DISPLAY_MASK (0x000000E0) +#define MPI2_BIOSPAGE3_FLAGS_INSTALLED_DEV_DISPLAY (0x00000000) +#define MPI2_BIOSPAGE3_FLAGS_ADAPTER_DISPLAY (0x00000020) +#define MPI2_BIOSPAGE3_FLAGS_ADAPTER_DEV_DISPLAY (0x00000040) + + +/* BIOS Page 4 */ + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check Header.PageLength or NumPhys at runtime. + */ +#ifndef MPI2_BIOS_PAGE_4_PHY_ENTRIES +#define MPI2_BIOS_PAGE_4_PHY_ENTRIES (1) +#endif + +typedef struct _MPI2_BIOS4_ENTRY +{ + U64 ReassignmentWWID; /* 0x00 */ + U64 ReassignmentDeviceName; /* 0x08 */ +} MPI2_BIOS4_ENTRY, MPI2_POINTER PTR_MPI2_BIOS4_ENTRY, + Mpi2MBios4Entry_t, MPI2_POINTER pMpi2Bios4Entry_t; + +typedef struct _MPI2_CONFIG_PAGE_BIOS_4 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U8 NumPhys; /* 0x04 */ + U8 Reserved1; /* 0x05 */ + U16 Reserved2; /* 0x06 */ + MPI2_BIOS4_ENTRY Phy[MPI2_BIOS_PAGE_4_PHY_ENTRIES]; /* 0x08 */ +} MPI2_CONFIG_PAGE_BIOS_4, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_BIOS_4, + Mpi2BiosPage4_t, MPI2_POINTER pMpi2BiosPage4_t; + +#define MPI2_BIOSPAGE4_PAGEVERSION (0x01) + + +/**************************************************************************** +* RAID Volume Config Pages +****************************************************************************/ + +/* RAID Volume Page 0 */ + +typedef struct _MPI2_RAIDVOL0_PHYS_DISK +{ + U8 RAIDSetNum; /* 0x00 */ + U8 PhysDiskMap; /* 0x01 */ + U8 PhysDiskNum; /* 0x02 */ + U8 Reserved; /* 0x03 */ +} MPI2_RAIDVOL0_PHYS_DISK, MPI2_POINTER PTR_MPI2_RAIDVOL0_PHYS_DISK, + Mpi2RaidVol0PhysDisk_t, MPI2_POINTER pMpi2RaidVol0PhysDisk_t; + +/* defines for the PhysDiskMap field */ +#define MPI2_RAIDVOL0_PHYSDISK_PRIMARY (0x01) +#define MPI2_RAIDVOL0_PHYSDISK_SECONDARY (0x02) + +typedef struct _MPI2_RAIDVOL0_SETTINGS +{ + U16 Settings; /* 0x00 */ + U8 HotSparePool; /* 0x01 */ + U8 Reserved; /* 0x02 */ +} MPI2_RAIDVOL0_SETTINGS, MPI2_POINTER PTR_MPI2_RAIDVOL0_SETTINGS, + Mpi2RaidVol0Settings_t, MPI2_POINTER pMpi2RaidVol0Settings_t; + +/* RAID Volume Page 0 HotSparePool defines, also used in RAID Physical Disk */ +#define MPI2_RAID_HOT_SPARE_POOL_0 (0x01) +#define MPI2_RAID_HOT_SPARE_POOL_1 (0x02) +#define MPI2_RAID_HOT_SPARE_POOL_2 (0x04) +#define MPI2_RAID_HOT_SPARE_POOL_3 (0x08) +#define MPI2_RAID_HOT_SPARE_POOL_4 (0x10) +#define MPI2_RAID_HOT_SPARE_POOL_5 (0x20) +#define MPI2_RAID_HOT_SPARE_POOL_6 (0x40) +#define MPI2_RAID_HOT_SPARE_POOL_7 (0x80) + +/* RAID Volume Page 0 VolumeSettings defines */ +#define MPI2_RAIDVOL0_SETTING_USE_PRODUCT_ID_SUFFIX (0x0008) +#define MPI2_RAIDVOL0_SETTING_AUTO_CONFIG_HSWAP_DISABLE (0x0004) + +#define MPI2_RAIDVOL0_SETTING_MASK_WRITE_CACHING (0x0003) +#define MPI2_RAIDVOL0_SETTING_UNCHANGED (0x0000) +#define MPI2_RAIDVOL0_SETTING_DISABLE_WRITE_CACHING (0x0001) +#define MPI2_RAIDVOL0_SETTING_ENABLE_WRITE_CACHING (0x0002) + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check Header.PageLength at runtime. + */ +#ifndef MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX +#define MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX (1) +#endif + +typedef struct _MPI2_CONFIG_PAGE_RAID_VOL_0 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U16 DevHandle; /* 0x04 */ + U8 VolumeState; /* 0x06 */ + U8 VolumeType; /* 0x07 */ + U32 VolumeStatusFlags; /* 0x08 */ + MPI2_RAIDVOL0_SETTINGS VolumeSettings; /* 0x0C */ + U64 MaxLBA; /* 0x10 */ + U32 StripeSize; /* 0x18 */ + U16 BlockSize; /* 0x1C */ + U16 Reserved1; /* 0x1E */ + U8 SupportedPhysDisks; /* 0x20 */ + U8 ResyncRate; /* 0x21 */ + U16 DataScrubDuration; /* 0x22 */ + U8 NumPhysDisks; /* 0x24 */ + U8 Reserved2; /* 0x25 */ + U8 Reserved3; /* 0x26 */ + U8 InactiveStatus; /* 0x27 */ + MPI2_RAIDVOL0_PHYS_DISK PhysDisk[MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX]; /* 0x28 */ +} MPI2_CONFIG_PAGE_RAID_VOL_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_RAID_VOL_0, + Mpi2RaidVolPage0_t, MPI2_POINTER pMpi2RaidVolPage0_t; + +#define MPI2_RAIDVOLPAGE0_PAGEVERSION (0x0A) + +/* values for RAID VolumeState */ +#define MPI2_RAID_VOL_STATE_MISSING (0x00) +#define MPI2_RAID_VOL_STATE_FAILED (0x01) +#define MPI2_RAID_VOL_STATE_INITIALIZING (0x02) +#define MPI2_RAID_VOL_STATE_ONLINE (0x03) +#define MPI2_RAID_VOL_STATE_DEGRADED (0x04) +#define MPI2_RAID_VOL_STATE_OPTIMAL (0x05) + +/* values for RAID VolumeType */ +#define MPI2_RAID_VOL_TYPE_RAID0 (0x00) +#define MPI2_RAID_VOL_TYPE_RAID1E (0x01) +#define MPI2_RAID_VOL_TYPE_RAID1 (0x02) +#define MPI2_RAID_VOL_TYPE_RAID10 (0x05) +#define MPI2_RAID_VOL_TYPE_UNKNOWN (0xFF) + +/* values for RAID Volume Page 0 VolumeStatusFlags field */ +#define MPI2_RAIDVOL0_STATUS_FLAG_PENDING_RESYNC (0x02000000) +#define MPI2_RAIDVOL0_STATUS_FLAG_BACKG_INIT_PENDING (0x01000000) +#define MPI2_RAIDVOL0_STATUS_FLAG_MDC_PENDING (0x00800000) +#define MPI2_RAIDVOL0_STATUS_FLAG_USER_CONSIST_PENDING (0x00400000) +#define MPI2_RAIDVOL0_STATUS_FLAG_MAKE_DATA_CONSISTENT (0x00200000) +#define MPI2_RAIDVOL0_STATUS_FLAG_DATA_SCRUB (0x00100000) +#define MPI2_RAIDVOL0_STATUS_FLAG_CONSISTENCY_CHECK (0x00080000) +#define MPI2_RAIDVOL0_STATUS_FLAG_CAPACITY_EXPANSION (0x00040000) +#define MPI2_RAIDVOL0_STATUS_FLAG_BACKGROUND_INIT (0x00020000) +#define MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS (0x00010000) +#define MPI2_RAIDVOL0_STATUS_FLAG_OCE_ALLOWED (0x00000040) +#define MPI2_RAIDVOL0_STATUS_FLAG_BGI_COMPLETE (0x00000020) +#define MPI2_RAIDVOL0_STATUS_FLAG_1E_OFFSET_MIRROR (0x00000000) +#define MPI2_RAIDVOL0_STATUS_FLAG_1E_ADJACENT_MIRROR (0x00000010) +#define MPI2_RAIDVOL0_STATUS_FLAG_BAD_BLOCK_TABLE_FULL (0x00000008) +#define MPI2_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE (0x00000004) +#define MPI2_RAIDVOL0_STATUS_FLAG_QUIESCED (0x00000002) +#define MPI2_RAIDVOL0_STATUS_FLAG_ENABLED (0x00000001) + +/* values for RAID Volume Page 0 SupportedPhysDisks field */ +#define MPI2_RAIDVOL0_SUPPORT_SOLID_STATE_DISKS (0x08) +#define MPI2_RAIDVOL0_SUPPORT_HARD_DISKS (0x04) +#define MPI2_RAIDVOL0_SUPPORT_SAS_PROTOCOL (0x02) +#define MPI2_RAIDVOL0_SUPPORT_SATA_PROTOCOL (0x01) + +/* values for RAID Volume Page 0 InactiveStatus field */ +#define MPI2_RAIDVOLPAGE0_UNKNOWN_INACTIVE (0x00) +#define MPI2_RAIDVOLPAGE0_STALE_METADATA_INACTIVE (0x01) +#define MPI2_RAIDVOLPAGE0_FOREIGN_VOLUME_INACTIVE (0x02) +#define MPI2_RAIDVOLPAGE0_INSUFFICIENT_RESOURCE_INACTIVE (0x03) +#define MPI2_RAIDVOLPAGE0_CLONE_VOLUME_INACTIVE (0x04) +#define MPI2_RAIDVOLPAGE0_INSUFFICIENT_METADATA_INACTIVE (0x05) +#define MPI2_RAIDVOLPAGE0_PREVIOUSLY_DELETED (0x06) + + +/* RAID Volume Page 1 */ + +typedef struct _MPI2_CONFIG_PAGE_RAID_VOL_1 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U16 DevHandle; /* 0x04 */ + U16 Reserved0; /* 0x06 */ + U8 GUID[24]; /* 0x08 */ + U8 Name[16]; /* 0x20 */ + U64 WWID; /* 0x30 */ + U32 Reserved1; /* 0x38 */ + U32 Reserved2; /* 0x3C */ +} MPI2_CONFIG_PAGE_RAID_VOL_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_RAID_VOL_1, + Mpi2RaidVolPage1_t, MPI2_POINTER pMpi2RaidVolPage1_t; + +#define MPI2_RAIDVOLPAGE1_PAGEVERSION (0x03) + + +/**************************************************************************** +* RAID Physical Disk Config Pages +****************************************************************************/ + +/* RAID Physical Disk Page 0 */ + +typedef struct _MPI2_RAIDPHYSDISK0_SETTINGS +{ + U16 Reserved1; /* 0x00 */ + U8 HotSparePool; /* 0x02 */ + U8 Reserved2; /* 0x03 */ +} MPI2_RAIDPHYSDISK0_SETTINGS, MPI2_POINTER PTR_MPI2_RAIDPHYSDISK0_SETTINGS, + Mpi2RaidPhysDisk0Settings_t, MPI2_POINTER pMpi2RaidPhysDisk0Settings_t; + +/* use MPI2_RAID_HOT_SPARE_POOL_ defines for the HotSparePool field */ + +typedef struct _MPI2_RAIDPHYSDISK0_INQUIRY_DATA +{ + U8 VendorID[8]; /* 0x00 */ + U8 ProductID[16]; /* 0x08 */ + U8 ProductRevLevel[4]; /* 0x18 */ + U8 SerialNum[32]; /* 0x1C */ +} MPI2_RAIDPHYSDISK0_INQUIRY_DATA, + MPI2_POINTER PTR_MPI2_RAIDPHYSDISK0_INQUIRY_DATA, + Mpi2RaidPhysDisk0InquiryData_t, MPI2_POINTER pMpi2RaidPhysDisk0InquiryData_t; + +typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_0 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U16 DevHandle; /* 0x04 */ + U8 Reserved1; /* 0x06 */ + U8 PhysDiskNum; /* 0x07 */ + MPI2_RAIDPHYSDISK0_SETTINGS PhysDiskSettings; /* 0x08 */ + U32 Reserved2; /* 0x0C */ + MPI2_RAIDPHYSDISK0_INQUIRY_DATA InquiryData; /* 0x10 */ + U32 Reserved3; /* 0x4C */ + U8 PhysDiskState; /* 0x50 */ + U8 OfflineReason; /* 0x51 */ + U8 IncompatibleReason; /* 0x52 */ + U8 PhysDiskAttributes; /* 0x53 */ + U32 PhysDiskStatusFlags; /* 0x54 */ + U64 DeviceMaxLBA; /* 0x58 */ + U64 HostMaxLBA; /* 0x60 */ + U64 CoercedMaxLBA; /* 0x68 */ + U16 BlockSize; /* 0x70 */ + U16 Reserved5; /* 0x72 */ + U32 Reserved6; /* 0x74 */ +} MPI2_CONFIG_PAGE_RD_PDISK_0, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_RD_PDISK_0, + Mpi2RaidPhysDiskPage0_t, MPI2_POINTER pMpi2RaidPhysDiskPage0_t; + +#define MPI2_RAIDPHYSDISKPAGE0_PAGEVERSION (0x05) + +/* PhysDiskState defines */ +#define MPI2_RAID_PD_STATE_NOT_CONFIGURED (0x00) +#define MPI2_RAID_PD_STATE_NOT_COMPATIBLE (0x01) +#define MPI2_RAID_PD_STATE_OFFLINE (0x02) +#define MPI2_RAID_PD_STATE_ONLINE (0x03) +#define MPI2_RAID_PD_STATE_HOT_SPARE (0x04) +#define MPI2_RAID_PD_STATE_DEGRADED (0x05) +#define MPI2_RAID_PD_STATE_REBUILDING (0x06) +#define MPI2_RAID_PD_STATE_OPTIMAL (0x07) + +/* OfflineReason defines */ +#define MPI2_PHYSDISK0_ONLINE (0x00) +#define MPI2_PHYSDISK0_OFFLINE_MISSING (0x01) +#define MPI2_PHYSDISK0_OFFLINE_FAILED (0x03) +#define MPI2_PHYSDISK0_OFFLINE_INITIALIZING (0x04) +#define MPI2_PHYSDISK0_OFFLINE_REQUESTED (0x05) +#define MPI2_PHYSDISK0_OFFLINE_FAILED_REQUESTED (0x06) +#define MPI2_PHYSDISK0_OFFLINE_OTHER (0xFF) + +/* IncompatibleReason defines */ +#define MPI2_PHYSDISK0_COMPATIBLE (0x00) +#define MPI2_PHYSDISK0_INCOMPATIBLE_PROTOCOL (0x01) +#define MPI2_PHYSDISK0_INCOMPATIBLE_BLOCKSIZE (0x02) +#define MPI2_PHYSDISK0_INCOMPATIBLE_MAX_LBA (0x03) +#define MPI2_PHYSDISK0_INCOMPATIBLE_SATA_EXTENDED_CMD (0x04) +#define MPI2_PHYSDISK0_INCOMPATIBLE_REMOVEABLE_MEDIA (0x05) +#define MPI2_PHYSDISK0_INCOMPATIBLE_UNKNOWN (0xFF) + +/* PhysDiskAttributes defines */ +#define MPI2_PHYSDISK0_ATTRIB_SOLID_STATE_DRIVE (0x08) +#define MPI2_PHYSDISK0_ATTRIB_HARD_DISK_DRIVE (0x04) +#define MPI2_PHYSDISK0_ATTRIB_SAS_PROTOCOL (0x02) +#define MPI2_PHYSDISK0_ATTRIB_SATA_PROTOCOL (0x01) + +/* PhysDiskStatusFlags defines */ +#define MPI2_PHYSDISK0_STATUS_FLAG_NOT_CERTIFIED (0x00000040) +#define MPI2_PHYSDISK0_STATUS_FLAG_OCE_TARGET (0x00000020) +#define MPI2_PHYSDISK0_STATUS_FLAG_WRITE_CACHE_ENABLED (0x00000010) +#define MPI2_PHYSDISK0_STATUS_FLAG_OPTIMAL_PREVIOUS (0x00000000) +#define MPI2_PHYSDISK0_STATUS_FLAG_NOT_OPTIMAL_PREVIOUS (0x00000008) +#define MPI2_PHYSDISK0_STATUS_FLAG_INACTIVE_VOLUME (0x00000004) +#define MPI2_PHYSDISK0_STATUS_FLAG_QUIESCED (0x00000002) +#define MPI2_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC (0x00000001) + + +/* RAID Physical Disk Page 1 */ + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check Header.PageLength or NumPhysDiskPaths at runtime. + */ +#ifndef MPI2_RAID_PHYS_DISK1_PATH_MAX +#define MPI2_RAID_PHYS_DISK1_PATH_MAX (1) +#endif + +typedef struct _MPI2_RAIDPHYSDISK1_PATH +{ + U16 DevHandle; /* 0x00 */ + U16 Reserved1; /* 0x02 */ + U64 WWID; /* 0x04 */ + U64 OwnerWWID; /* 0x0C */ + U8 OwnerIdentifier; /* 0x14 */ + U8 Reserved2; /* 0x15 */ + U16 Flags; /* 0x16 */ +} MPI2_RAIDPHYSDISK1_PATH, MPI2_POINTER PTR_MPI2_RAIDPHYSDISK1_PATH, + Mpi2RaidPhysDisk1Path_t, MPI2_POINTER pMpi2RaidPhysDisk1Path_t; + +/* RAID Physical Disk Page 1 Physical Disk Path Flags field defines */ +#define MPI2_RAID_PHYSDISK1_FLAG_PRIMARY (0x0004) +#define MPI2_RAID_PHYSDISK1_FLAG_BROKEN (0x0002) +#define MPI2_RAID_PHYSDISK1_FLAG_INVALID (0x0001) + +typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_1 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U8 NumPhysDiskPaths; /* 0x04 */ + U8 PhysDiskNum; /* 0x05 */ + U16 Reserved1; /* 0x06 */ + U32 Reserved2; /* 0x08 */ + MPI2_RAIDPHYSDISK1_PATH PhysicalDiskPath[MPI2_RAID_PHYS_DISK1_PATH_MAX];/* 0x0C */ +} MPI2_CONFIG_PAGE_RD_PDISK_1, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_RD_PDISK_1, + Mpi2RaidPhysDiskPage1_t, MPI2_POINTER pMpi2RaidPhysDiskPage1_t; + +#define MPI2_RAIDPHYSDISKPAGE1_PAGEVERSION (0x02) + + +/**************************************************************************** +* values for fields used by several types of SAS Config Pages +****************************************************************************/ + +/* values for NegotiatedLinkRates fields */ +#define MPI2_SAS_NEG_LINK_RATE_MASK_LOGICAL (0xF0) +#define MPI2_SAS_NEG_LINK_RATE_SHIFT_LOGICAL (4) +#define MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL (0x0F) +/* link rates used for Negotiated Physical and Logical Link Rate */ +#define MPI2_SAS_NEG_LINK_RATE_UNKNOWN_LINK_RATE (0x00) +#define MPI2_SAS_NEG_LINK_RATE_PHY_DISABLED (0x01) +#define MPI2_SAS_NEG_LINK_RATE_NEGOTIATION_FAILED (0x02) +#define MPI2_SAS_NEG_LINK_RATE_SATA_OOB_COMPLETE (0x03) +#define MPI2_SAS_NEG_LINK_RATE_PORT_SELECTOR (0x04) +#define MPI2_SAS_NEG_LINK_RATE_SMP_RESET_IN_PROGRESS (0x05) +#define MPI2_SAS_NEG_LINK_RATE_1_5 (0x08) +#define MPI2_SAS_NEG_LINK_RATE_3_0 (0x09) +#define MPI2_SAS_NEG_LINK_RATE_6_0 (0x0A) + + +/* values for AttachedPhyInfo fields */ +#define MPI2_SAS_APHYINFO_INSIDE_ZPSDS_PERSISTENT (0x00000040) +#define MPI2_SAS_APHYINFO_REQUESTED_INSIDE_ZPSDS (0x00000020) +#define MPI2_SAS_APHYINFO_BREAK_REPLY_CAPABLE (0x00000010) + +#define MPI2_SAS_APHYINFO_REASON_MASK (0x0000000F) +#define MPI2_SAS_APHYINFO_REASON_UNKNOWN (0x00000000) +#define MPI2_SAS_APHYINFO_REASON_POWER_ON (0x00000001) +#define MPI2_SAS_APHYINFO_REASON_HARD_RESET (0x00000002) +#define MPI2_SAS_APHYINFO_REASON_SMP_PHY_CONTROL (0x00000003) +#define MPI2_SAS_APHYINFO_REASON_LOSS_OF_SYNC (0x00000004) +#define MPI2_SAS_APHYINFO_REASON_MULTIPLEXING_SEQ (0x00000005) +#define MPI2_SAS_APHYINFO_REASON_IT_NEXUS_LOSS_TIMER (0x00000006) +#define MPI2_SAS_APHYINFO_REASON_BREAK_TIMEOUT (0x00000007) +#define MPI2_SAS_APHYINFO_REASON_PHY_TEST_STOPPED (0x00000008) + + +/* values for PhyInfo fields */ +#define MPI2_SAS_PHYINFO_PHY_VACANT (0x80000000) +#define MPI2_SAS_PHYINFO_CHANGED_REQ_INSIDE_ZPSDS (0x04000000) +#define MPI2_SAS_PHYINFO_INSIDE_ZPSDS_PERSISTENT (0x02000000) +#define MPI2_SAS_PHYINFO_REQ_INSIDE_ZPSDS (0x01000000) +#define MPI2_SAS_PHYINFO_ZONE_GROUP_PERSISTENT (0x00400000) +#define MPI2_SAS_PHYINFO_INSIDE_ZPSDS (0x00200000) +#define MPI2_SAS_PHYINFO_ZONING_ENABLED (0x00100000) + +#define MPI2_SAS_PHYINFO_REASON_MASK (0x000F0000) +#define MPI2_SAS_PHYINFO_REASON_UNKNOWN (0x00000000) +#define MPI2_SAS_PHYINFO_REASON_POWER_ON (0x00010000) +#define MPI2_SAS_PHYINFO_REASON_HARD_RESET (0x00020000) +#define MPI2_SAS_PHYINFO_REASON_SMP_PHY_CONTROL (0x00030000) +#define MPI2_SAS_PHYINFO_REASON_LOSS_OF_SYNC (0x00040000) +#define MPI2_SAS_PHYINFO_REASON_MULTIPLEXING_SEQ (0x00050000) +#define MPI2_SAS_PHYINFO_REASON_IT_NEXUS_LOSS_TIMER (0x00060000) +#define MPI2_SAS_PHYINFO_REASON_BREAK_TIMEOUT (0x00070000) +#define MPI2_SAS_PHYINFO_REASON_PHY_TEST_STOPPED (0x00080000) + +#define MPI2_SAS_PHYINFO_MULTIPLEXING_SUPPORTED (0x00008000) +#define MPI2_SAS_PHYINFO_SATA_PORT_ACTIVE (0x00004000) +#define MPI2_SAS_PHYINFO_SATA_PORT_SELECTOR_PRESENT (0x00002000) +#define MPI2_SAS_PHYINFO_VIRTUAL_PHY (0x00001000) + +#define MPI2_SAS_PHYINFO_MASK_PARTIAL_PATHWAY_TIME (0x00000F00) +#define MPI2_SAS_PHYINFO_SHIFT_PARTIAL_PATHWAY_TIME (8) + +#define MPI2_SAS_PHYINFO_MASK_ROUTING_ATTRIBUTE (0x000000F0) +#define MPI2_SAS_PHYINFO_DIRECT_ROUTING (0x00000000) +#define MPI2_SAS_PHYINFO_SUBTRACTIVE_ROUTING (0x00000010) +#define MPI2_SAS_PHYINFO_TABLE_ROUTING (0x00000020) + + +/* values for SAS ProgrammedLinkRate fields */ +#define MPI2_SAS_PRATE_MAX_RATE_MASK (0xF0) +#define MPI2_SAS_PRATE_MAX_RATE_NOT_PROGRAMMABLE (0x00) +#define MPI2_SAS_PRATE_MAX_RATE_1_5 (0x80) +#define MPI2_SAS_PRATE_MAX_RATE_3_0 (0x90) +#define MPI2_SAS_PRATE_MAX_RATE_6_0 (0xA0) +#define MPI2_SAS_PRATE_MIN_RATE_MASK (0x0F) +#define MPI2_SAS_PRATE_MIN_RATE_NOT_PROGRAMMABLE (0x00) +#define MPI2_SAS_PRATE_MIN_RATE_1_5 (0x08) +#define MPI2_SAS_PRATE_MIN_RATE_3_0 (0x09) +#define MPI2_SAS_PRATE_MIN_RATE_6_0 (0x0A) + + +/* values for SAS HwLinkRate fields */ +#define MPI2_SAS_HWRATE_MAX_RATE_MASK (0xF0) +#define MPI2_SAS_HWRATE_MAX_RATE_1_5 (0x80) +#define MPI2_SAS_HWRATE_MAX_RATE_3_0 (0x90) +#define MPI2_SAS_HWRATE_MAX_RATE_6_0 (0xA0) +#define MPI2_SAS_HWRATE_MIN_RATE_MASK (0x0F) +#define MPI2_SAS_HWRATE_MIN_RATE_1_5 (0x08) +#define MPI2_SAS_HWRATE_MIN_RATE_3_0 (0x09) +#define MPI2_SAS_HWRATE_MIN_RATE_6_0 (0x0A) + + + +/**************************************************************************** +* SAS IO Unit Config Pages +****************************************************************************/ + +/* SAS IO Unit Page 0 */ + +typedef struct _MPI2_SAS_IO_UNIT0_PHY_DATA +{ + U8 Port; /* 0x00 */ + U8 PortFlags; /* 0x01 */ + U8 PhyFlags; /* 0x02 */ + U8 NegotiatedLinkRate; /* 0x03 */ + U32 ControllerPhyDeviceInfo;/* 0x04 */ + U16 AttachedDevHandle; /* 0x08 */ + U16 ControllerDevHandle; /* 0x0A */ + U32 DiscoveryStatus; /* 0x0C */ + U32 Reserved; /* 0x10 */ +} MPI2_SAS_IO_UNIT0_PHY_DATA, MPI2_POINTER PTR_MPI2_SAS_IO_UNIT0_PHY_DATA, + Mpi2SasIOUnit0PhyData_t, MPI2_POINTER pMpi2SasIOUnit0PhyData_t; + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check Header.ExtPageLength or NumPhys at runtime. + */ +#ifndef MPI2_SAS_IOUNIT0_PHY_MAX +#define MPI2_SAS_IOUNIT0_PHY_MAX (1) +#endif + +typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_0 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved1; /* 0x08 */ + U8 NumPhys; /* 0x0C */ + U8 Reserved2; /* 0x0D */ + U16 Reserved3; /* 0x0E */ + MPI2_SAS_IO_UNIT0_PHY_DATA PhyData[MPI2_SAS_IOUNIT0_PHY_MAX]; /* 0x10 */ +} MPI2_CONFIG_PAGE_SASIOUNIT_0, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_0, + Mpi2SasIOUnitPage0_t, MPI2_POINTER pMpi2SasIOUnitPage0_t; + +#define MPI2_SASIOUNITPAGE0_PAGEVERSION (0x05) + +/* values for SAS IO Unit Page 0 PortFlags */ +#define MPI2_SASIOUNIT0_PORTFLAGS_DISCOVERY_IN_PROGRESS (0x08) +#define MPI2_SASIOUNIT0_PORTFLAGS_AUTO_PORT_CONFIG (0x01) + +/* values for SAS IO Unit Page 0 PhyFlags */ +#define MPI2_SASIOUNIT0_PHYFLAGS_ZONING_ENABLED (0x10) +#define MPI2_SASIOUNIT0_PHYFLAGS_PHY_DISABLED (0x08) + +/* use MPI2_SAS_NEG_LINK_RATE_ defines for the NegotiatedLinkRate field */ + +/* see mpi2_sas.h for values for SAS IO Unit Page 0 ControllerPhyDeviceInfo values */ + +/* values for SAS IO Unit Page 0 DiscoveryStatus */ +#define MPI2_SASIOUNIT0_DS_MAX_ENCLOSURES_EXCEED (0x80000000) +#define MPI2_SASIOUNIT0_DS_MAX_EXPANDERS_EXCEED (0x40000000) +#define MPI2_SASIOUNIT0_DS_MAX_DEVICES_EXCEED (0x20000000) +#define MPI2_SASIOUNIT0_DS_MAX_TOPO_PHYS_EXCEED (0x10000000) +#define MPI2_SASIOUNIT0_DS_DOWNSTREAM_INITIATOR (0x08000000) +#define MPI2_SASIOUNIT0_DS_MULTI_SUBTRACTIVE_SUBTRACTIVE (0x00008000) +#define MPI2_SASIOUNIT0_DS_EXP_MULTI_SUBTRACTIVE (0x00004000) +#define MPI2_SASIOUNIT0_DS_MULTI_PORT_DOMAIN (0x00002000) +#define MPI2_SASIOUNIT0_DS_TABLE_TO_SUBTRACTIVE_LINK (0x00001000) +#define MPI2_SASIOUNIT0_DS_UNSUPPORTED_DEVICE (0x00000800) +#define MPI2_SASIOUNIT0_DS_TABLE_LINK (0x00000400) +#define MPI2_SASIOUNIT0_DS_SUBTRACTIVE_LINK (0x00000200) +#define MPI2_SASIOUNIT0_DS_SMP_CRC_ERROR (0x00000100) +#define MPI2_SASIOUNIT0_DS_SMP_FUNCTION_FAILED (0x00000080) +#define MPI2_SASIOUNIT0_DS_INDEX_NOT_EXIST (0x00000040) +#define MPI2_SASIOUNIT0_DS_OUT_ROUTE_ENTRIES (0x00000020) +#define MPI2_SASIOUNIT0_DS_SMP_TIMEOUT (0x00000010) +#define MPI2_SASIOUNIT0_DS_MULTIPLE_PORTS (0x00000004) +#define MPI2_SASIOUNIT0_DS_UNADDRESSABLE_DEVICE (0x00000002) +#define MPI2_SASIOUNIT0_DS_LOOP_DETECTED (0x00000001) + + +/* SAS IO Unit Page 1 */ + +typedef struct _MPI2_SAS_IO_UNIT1_PHY_DATA +{ + U8 Port; /* 0x00 */ + U8 PortFlags; /* 0x01 */ + U8 PhyFlags; /* 0x02 */ + U8 MaxMinLinkRate; /* 0x03 */ + U32 ControllerPhyDeviceInfo; /* 0x04 */ + U16 MaxTargetPortConnectTime; /* 0x08 */ + U16 Reserved1; /* 0x0A */ +} MPI2_SAS_IO_UNIT1_PHY_DATA, MPI2_POINTER PTR_MPI2_SAS_IO_UNIT1_PHY_DATA, + Mpi2SasIOUnit1PhyData_t, MPI2_POINTER pMpi2SasIOUnit1PhyData_t; + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check Header.ExtPageLength or NumPhys at runtime. + */ +#ifndef MPI2_SAS_IOUNIT1_PHY_MAX +#define MPI2_SAS_IOUNIT1_PHY_MAX (1) +#endif + +typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_1 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U16 ControlFlags; /* 0x08 */ + U16 SASNarrowMaxQueueDepth; /* 0x0A */ + U16 AdditionalControlFlags; /* 0x0C */ + U16 SASWideMaxQueueDepth; /* 0x0E */ + U8 NumPhys; /* 0x10 */ + U8 SATAMaxQDepth; /* 0x11 */ + U8 ReportDeviceMissingDelay; /* 0x12 */ + U8 IODeviceMissingDelay; /* 0x13 */ + MPI2_SAS_IO_UNIT1_PHY_DATA PhyData[MPI2_SAS_IOUNIT1_PHY_MAX]; /* 0x14 */ +} MPI2_CONFIG_PAGE_SASIOUNIT_1, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_1, + Mpi2SasIOUnitPage1_t, MPI2_POINTER pMpi2SasIOUnitPage1_t; + +#define MPI2_SASIOUNITPAGE1_PAGEVERSION (0x09) + +/* values for SAS IO Unit Page 1 ControlFlags */ +#define MPI2_SASIOUNIT1_CONTROL_DEVICE_SELF_TEST (0x8000) +#define MPI2_SASIOUNIT1_CONTROL_SATA_3_0_MAX (0x4000) +#define MPI2_SASIOUNIT1_CONTROL_SATA_1_5_MAX (0x2000) +#define MPI2_SASIOUNIT1_CONTROL_SATA_SW_PRESERVE (0x1000) + +#define MPI2_SASIOUNIT1_CONTROL_MASK_DEV_SUPPORT (0x0600) +#define MPI2_SASIOUNIT1_CONTROL_SHIFT_DEV_SUPPORT (9) +#define MPI2_SASIOUNIT1_CONTROL_DEV_SUPPORT_BOTH (0x0) +#define MPI2_SASIOUNIT1_CONTROL_DEV_SAS_SUPPORT (0x1) +#define MPI2_SASIOUNIT1_CONTROL_DEV_SATA_SUPPORT (0x2) + +#define MPI2_SASIOUNIT1_CONTROL_SATA_48BIT_LBA_REQUIRED (0x0080) +#define MPI2_SASIOUNIT1_CONTROL_SATA_SMART_REQUIRED (0x0040) +#define MPI2_SASIOUNIT1_CONTROL_SATA_NCQ_REQUIRED (0x0020) +#define MPI2_SASIOUNIT1_CONTROL_SATA_FUA_REQUIRED (0x0010) +#define MPI2_SASIOUNIT1_CONTROL_TABLE_SUBTRACTIVE_ILLEGAL (0x0008) +#define MPI2_SASIOUNIT1_CONTROL_SUBTRACTIVE_ILLEGAL (0x0004) +#define MPI2_SASIOUNIT1_CONTROL_FIRST_LVL_DISC_ONLY (0x0002) +#define MPI2_SASIOUNIT1_CONTROL_CLEAR_AFFILIATION (0x0001) + +/* values for SAS IO Unit Page 1 AdditionalControlFlags */ +#define MPI2_SASIOUNIT1_ACONTROL_MULTI_PORT_DOMAIN_ILLEGAL (0x0080) +#define MPI2_SASIOUNIT1_ACONTROL_SATA_ASYNCHROUNOUS_NOTIFICATION (0x0040) +#define MPI2_SASIOUNIT1_ACONTROL_INVALID_TOPOLOGY_CORRECTION (0x0020) +#define MPI2_SASIOUNIT1_ACONTROL_PORT_ENABLE_ONLY_SATA_LINK_RESET (0x0010) +#define MPI2_SASIOUNIT1_ACONTROL_OTHER_AFFILIATION_SATA_LINK_RESET (0x0008) +#define MPI2_SASIOUNIT1_ACONTROL_SELF_AFFILIATION_SATA_LINK_RESET (0x0004) +#define MPI2_SASIOUNIT1_ACONTROL_NO_AFFILIATION_SATA_LINK_RESET (0x0002) +#define MPI2_SASIOUNIT1_ACONTROL_ALLOW_TABLE_TO_TABLE (0x0001) + +/* defines for SAS IO Unit Page 1 ReportDeviceMissingDelay */ +#define MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK (0x7F) +#define MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16 (0x80) + +/* values for SAS IO Unit Page 1 PortFlags */ +#define MPI2_SASIOUNIT1_PORT_FLAGS_AUTO_PORT_CONFIG (0x01) + +/* values for SAS IO Unit Page 2 PhyFlags */ +#define MPI2_SASIOUNIT1_PHYFLAGS_ZONING_ENABLE (0x10) +#define MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE (0x08) + +/* values for SAS IO Unit Page 0 MaxMinLinkRate */ +#define MPI2_SASIOUNIT1_MAX_RATE_MASK (0xF0) +#define MPI2_SASIOUNIT1_MAX_RATE_1_5 (0x80) +#define MPI2_SASIOUNIT1_MAX_RATE_3_0 (0x90) +#define MPI2_SASIOUNIT1_MAX_RATE_6_0 (0xA0) +#define MPI2_SASIOUNIT1_MIN_RATE_MASK (0x0F) +#define MPI2_SASIOUNIT1_MIN_RATE_1_5 (0x08) +#define MPI2_SASIOUNIT1_MIN_RATE_3_0 (0x09) +#define MPI2_SASIOUNIT1_MIN_RATE_6_0 (0x0A) + +/* see mpi2_sas.h for values for SAS IO Unit Page 1 ControllerPhyDeviceInfo values */ + + +/* SAS IO Unit Page 4 */ + +typedef struct _MPI2_SAS_IOUNIT4_SPINUP_GROUP +{ + U8 MaxTargetSpinup; /* 0x00 */ + U8 SpinupDelay; /* 0x01 */ + U16 Reserved1; /* 0x02 */ +} MPI2_SAS_IOUNIT4_SPINUP_GROUP, MPI2_POINTER PTR_MPI2_SAS_IOUNIT4_SPINUP_GROUP, + Mpi2SasIOUnit4SpinupGroup_t, MPI2_POINTER pMpi2SasIOUnit4SpinupGroup_t; + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * four and check Header.ExtPageLength or NumPhys at runtime. + */ +#ifndef MPI2_SAS_IOUNIT4_PHY_MAX +#define MPI2_SAS_IOUNIT4_PHY_MAX (4) +#endif + +typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_4 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + MPI2_SAS_IOUNIT4_SPINUP_GROUP SpinupGroupParameters[4]; /* 0x08 */ + U32 Reserved1; /* 0x18 */ + U32 Reserved2; /* 0x1C */ + U32 Reserved3; /* 0x20 */ + U8 BootDeviceWaitTime; /* 0x24 */ + U8 Reserved4; /* 0x25 */ + U16 Reserved5; /* 0x26 */ + U8 NumPhys; /* 0x28 */ + U8 PEInitialSpinupDelay; /* 0x29 */ + U8 PEReplyDelay; /* 0x2A */ + U8 Flags; /* 0x2B */ + U8 PHY[MPI2_SAS_IOUNIT4_PHY_MAX]; /* 0x2C */ +} MPI2_CONFIG_PAGE_SASIOUNIT_4, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_4, + Mpi2SasIOUnitPage4_t, MPI2_POINTER pMpi2SasIOUnitPage4_t; + +#define MPI2_SASIOUNITPAGE4_PAGEVERSION (0x02) + +/* defines for Flags field */ +#define MPI2_SASIOUNIT4_FLAGS_AUTO_PORTENABLE (0x01) + +/* defines for PHY field */ +#define MPI2_SASIOUNIT4_PHY_SPINUP_GROUP_MASK (0x03) + + +/**************************************************************************** +* SAS Expander Config Pages +****************************************************************************/ + +/* SAS Expander Page 0 */ + +typedef struct _MPI2_CONFIG_PAGE_EXPANDER_0 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U8 PhysicalPort; /* 0x08 */ + U8 ReportGenLength; /* 0x09 */ + U16 EnclosureHandle; /* 0x0A */ + U64 SASAddress; /* 0x0C */ + U32 DiscoveryStatus; /* 0x14 */ + U16 DevHandle; /* 0x18 */ + U16 ParentDevHandle; /* 0x1A */ + U16 ExpanderChangeCount; /* 0x1C */ + U16 ExpanderRouteIndexes; /* 0x1E */ + U8 NumPhys; /* 0x20 */ + U8 SASLevel; /* 0x21 */ + U16 Flags; /* 0x22 */ + U16 STPBusInactivityTimeLimit; /* 0x24 */ + U16 STPMaxConnectTimeLimit; /* 0x26 */ + U16 STP_SMP_NexusLossTime; /* 0x28 */ + U16 MaxNumRoutedSasAddresses; /* 0x2A */ + U64 ActiveZoneManagerSASAddress;/* 0x2C */ + U16 ZoneLockInactivityLimit; /* 0x34 */ + U16 Reserved1; /* 0x36 */ +} MPI2_CONFIG_PAGE_EXPANDER_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_EXPANDER_0, + Mpi2ExpanderPage0_t, MPI2_POINTER pMpi2ExpanderPage0_t; + +#define MPI2_SASEXPANDER0_PAGEVERSION (0x05) + +/* values for SAS Expander Page 0 DiscoveryStatus field */ +#define MPI2_SAS_EXPANDER0_DS_MAX_ENCLOSURES_EXCEED (0x80000000) +#define MPI2_SAS_EXPANDER0_DS_MAX_EXPANDERS_EXCEED (0x40000000) +#define MPI2_SAS_EXPANDER0_DS_MAX_DEVICES_EXCEED (0x20000000) +#define MPI2_SAS_EXPANDER0_DS_MAX_TOPO_PHYS_EXCEED (0x10000000) +#define MPI2_SAS_EXPANDER0_DS_DOWNSTREAM_INITIATOR (0x08000000) +#define MPI2_SAS_EXPANDER0_DS_MULTI_SUBTRACTIVE_SUBTRACTIVE (0x00008000) +#define MPI2_SAS_EXPANDER0_DS_EXP_MULTI_SUBTRACTIVE (0x00004000) +#define MPI2_SAS_EXPANDER0_DS_MULTI_PORT_DOMAIN (0x00002000) +#define MPI2_SAS_EXPANDER0_DS_TABLE_TO_SUBTRACTIVE_LINK (0x00001000) +#define MPI2_SAS_EXPANDER0_DS_UNSUPPORTED_DEVICE (0x00000800) +#define MPI2_SAS_EXPANDER0_DS_TABLE_LINK (0x00000400) +#define MPI2_SAS_EXPANDER0_DS_SUBTRACTIVE_LINK (0x00000200) +#define MPI2_SAS_EXPANDER0_DS_SMP_CRC_ERROR (0x00000100) +#define MPI2_SAS_EXPANDER0_DS_SMP_FUNCTION_FAILED (0x00000080) +#define MPI2_SAS_EXPANDER0_DS_INDEX_NOT_EXIST (0x00000040) +#define MPI2_SAS_EXPANDER0_DS_OUT_ROUTE_ENTRIES (0x00000020) +#define MPI2_SAS_EXPANDER0_DS_SMP_TIMEOUT (0x00000010) +#define MPI2_SAS_EXPANDER0_DS_MULTIPLE_PORTS (0x00000004) +#define MPI2_SAS_EXPANDER0_DS_UNADDRESSABLE_DEVICE (0x00000002) +#define MPI2_SAS_EXPANDER0_DS_LOOP_DETECTED (0x00000001) + +/* values for SAS Expander Page 0 Flags field */ +#define MPI2_SAS_EXPANDER0_FLAGS_ZONE_LOCKED (0x1000) +#define MPI2_SAS_EXPANDER0_FLAGS_SUPPORTED_PHYSICAL_PRES (0x0800) +#define MPI2_SAS_EXPANDER0_FLAGS_ASSERTED_PHYSICAL_PRES (0x0400) +#define MPI2_SAS_EXPANDER0_FLAGS_ZONING_SUPPORT (0x0200) +#define MPI2_SAS_EXPANDER0_FLAGS_ENABLED_ZONING (0x0100) +#define MPI2_SAS_EXPANDER0_FLAGS_TABLE_TO_TABLE_SUPPORT (0x0080) +#define MPI2_SAS_EXPANDER0_FLAGS_CONNECTOR_END_DEVICE (0x0010) +#define MPI2_SAS_EXPANDER0_FLAGS_OTHERS_CONFIG (0x0004) +#define MPI2_SAS_EXPANDER0_FLAGS_CONFIG_IN_PROGRESS (0x0002) +#define MPI2_SAS_EXPANDER0_FLAGS_ROUTE_TABLE_CONFIG (0x0001) + + +/* SAS Expander Page 1 */ + +typedef struct _MPI2_CONFIG_PAGE_EXPANDER_1 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U8 PhysicalPort; /* 0x08 */ + U8 Reserved1; /* 0x09 */ + U16 Reserved2; /* 0x0A */ + U8 NumPhys; /* 0x0C */ + U8 Phy; /* 0x0D */ + U16 NumTableEntriesProgrammed; /* 0x0E */ + U8 ProgrammedLinkRate; /* 0x10 */ + U8 HwLinkRate; /* 0x11 */ + U16 AttachedDevHandle; /* 0x12 */ + U32 PhyInfo; /* 0x14 */ + U32 AttachedDeviceInfo; /* 0x18 */ + U16 ExpanderDevHandle; /* 0x1C */ + U8 ChangeCount; /* 0x1E */ + U8 NegotiatedLinkRate; /* 0x1F */ + U8 PhyIdentifier; /* 0x20 */ + U8 AttachedPhyIdentifier; /* 0x21 */ + U8 Reserved3; /* 0x22 */ + U8 DiscoveryInfo; /* 0x23 */ + U32 AttachedPhyInfo; /* 0x24 */ + U8 ZoneGroup; /* 0x28 */ + U8 SelfConfigStatus; /* 0x29 */ + U16 Reserved4; /* 0x2A */ +} MPI2_CONFIG_PAGE_EXPANDER_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_EXPANDER_1, + Mpi2ExpanderPage1_t, MPI2_POINTER pMpi2ExpanderPage1_t; + +#define MPI2_SASEXPANDER1_PAGEVERSION (0x02) + +/* use MPI2_SAS_PRATE_ defines for the ProgrammedLinkRate field */ + +/* use MPI2_SAS_HWRATE_ defines for the HwLinkRate field */ + +/* use MPI2_SAS_PHYINFO_ for the PhyInfo field */ + +/* see mpi2_sas.h for the MPI2_SAS_DEVICE_INFO_ defines used for the AttachedDeviceInfo field */ + +/* use MPI2_SAS_NEG_LINK_RATE_ defines for the NegotiatedLinkRate field */ + +/* use MPI2_SAS_APHYINFO_ defines for AttachedPhyInfo field */ + +/* values for SAS Expander Page 1 DiscoveryInfo field */ +#define MPI2_SAS_EXPANDER1_DISCINFO_BAD_PHY_DISABLED (0x04) +#define MPI2_SAS_EXPANDER1_DISCINFO_LINK_STATUS_CHANGE (0x02) +#define MPI2_SAS_EXPANDER1_DISCINFO_NO_ROUTING_ENTRIES (0x01) + + +/**************************************************************************** +* SAS Device Config Pages +****************************************************************************/ + +/* SAS Device Page 0 */ + +typedef struct _MPI2_CONFIG_PAGE_SAS_DEV_0 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U16 Slot; /* 0x08 */ + U16 EnclosureHandle; /* 0x0A */ + U64 SASAddress; /* 0x0C */ + U16 ParentDevHandle; /* 0x14 */ + U8 PhyNum; /* 0x16 */ + U8 AccessStatus; /* 0x17 */ + U16 DevHandle; /* 0x18 */ + U8 AttachedPhyIdentifier; /* 0x1A */ + U8 ZoneGroup; /* 0x1B */ + U32 DeviceInfo; /* 0x1C */ + U16 Flags; /* 0x20 */ + U8 PhysicalPort; /* 0x22 */ + U8 MaxPortConnections; /* 0x23 */ + U64 DeviceName; /* 0x24 */ + U8 PortGroups; /* 0x2C */ + U8 DmaGroup; /* 0x2D */ + U8 ControlGroup; /* 0x2E */ + U8 Reserved1; /* 0x2F */ + U32 Reserved2; /* 0x30 */ + U32 Reserved3; /* 0x34 */ +} MPI2_CONFIG_PAGE_SAS_DEV_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_DEV_0, + Mpi2SasDevicePage0_t, MPI2_POINTER pMpi2SasDevicePage0_t; + +#define MPI2_SASDEVICE0_PAGEVERSION (0x08) + +/* values for SAS Device Page 0 AccessStatus field */ +#define MPI2_SAS_DEVICE0_ASTATUS_NO_ERRORS (0x00) +#define MPI2_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED (0x01) +#define MPI2_SAS_DEVICE0_ASTATUS_SATA_CAPABILITY_FAILED (0x02) +#define MPI2_SAS_DEVICE0_ASTATUS_SATA_AFFILIATION_CONFLICT (0x03) +#define MPI2_SAS_DEVICE0_ASTATUS_SATA_NEEDS_INITIALIZATION (0x04) +#define MPI2_SAS_DEVICE0_ASTATUS_ROUTE_NOT_ADDRESSABLE (0x05) +#define MPI2_SAS_DEVICE0_ASTATUS_SMP_ERROR_NOT_ADDRESSABLE (0x06) +#define MPI2_SAS_DEVICE0_ASTATUS_DEVICE_BLOCKED (0x07) +/* specific values for SATA Init failures */ +#define MPI2_SAS_DEVICE0_ASTATUS_SIF_UNKNOWN (0x10) +#define MPI2_SAS_DEVICE0_ASTATUS_SIF_AFFILIATION_CONFLICT (0x11) +#define MPI2_SAS_DEVICE0_ASTATUS_SIF_DIAG (0x12) +#define MPI2_SAS_DEVICE0_ASTATUS_SIF_IDENTIFICATION (0x13) +#define MPI2_SAS_DEVICE0_ASTATUS_SIF_CHECK_POWER (0x14) +#define MPI2_SAS_DEVICE0_ASTATUS_SIF_PIO_SN (0x15) +#define MPI2_SAS_DEVICE0_ASTATUS_SIF_MDMA_SN (0x16) +#define MPI2_SAS_DEVICE0_ASTATUS_SIF_UDMA_SN (0x17) +#define MPI2_SAS_DEVICE0_ASTATUS_SIF_ZONING_VIOLATION (0x18) +#define MPI2_SAS_DEVICE0_ASTATUS_SIF_NOT_ADDRESSABLE (0x19) +#define MPI2_SAS_DEVICE0_ASTATUS_SIF_MAX (0x1F) + +/* see mpi2_sas.h for values for SAS Device Page 0 DeviceInfo values */ + +/* values for SAS Device Page 0 Flags field */ +#define MPI2_SAS_DEVICE0_FLAGS_SATA_ASYNCHRONOUS_NOTIFY (0x0400) +#define MPI2_SAS_DEVICE0_FLAGS_SATA_SW_PRESERVE (0x0200) +#define MPI2_SAS_DEVICE0_FLAGS_UNSUPPORTED_DEVICE (0x0100) +#define MPI2_SAS_DEVICE0_FLAGS_SATA_48BIT_LBA_SUPPORTED (0x0080) +#define MPI2_SAS_DEVICE0_FLAGS_SATA_SMART_SUPPORTED (0x0040) +#define MPI2_SAS_DEVICE0_FLAGS_SATA_NCQ_SUPPORTED (0x0020) +#define MPI2_SAS_DEVICE0_FLAGS_SATA_FUA_SUPPORTED (0x0010) +#define MPI2_SAS_DEVICE0_FLAGS_PORT_SELECTOR_ATTACH (0x0008) +#define MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT (0x0001) + + +/* SAS Device Page 1 */ + +typedef struct _MPI2_CONFIG_PAGE_SAS_DEV_1 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved1; /* 0x08 */ + U64 SASAddress; /* 0x0C */ + U32 Reserved2; /* 0x14 */ + U16 DevHandle; /* 0x18 */ + U16 Reserved3; /* 0x1A */ + U8 InitialRegDeviceFIS[20];/* 0x1C */ +} MPI2_CONFIG_PAGE_SAS_DEV_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_DEV_1, + Mpi2SasDevicePage1_t, MPI2_POINTER pMpi2SasDevicePage1_t; + +#define MPI2_SASDEVICE1_PAGEVERSION (0x01) + + +/**************************************************************************** +* SAS PHY Config Pages +****************************************************************************/ + +/* SAS PHY Page 0 */ + +typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_0 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U16 OwnerDevHandle; /* 0x08 */ + U16 Reserved1; /* 0x0A */ + U16 AttachedDevHandle; /* 0x0C */ + U8 AttachedPhyIdentifier; /* 0x0E */ + U8 Reserved2; /* 0x0F */ + U32 AttachedPhyInfo; /* 0x10 */ + U8 ProgrammedLinkRate; /* 0x14 */ + U8 HwLinkRate; /* 0x15 */ + U8 ChangeCount; /* 0x16 */ + U8 Flags; /* 0x17 */ + U32 PhyInfo; /* 0x18 */ + U8 NegotiatedLinkRate; /* 0x1C */ + U8 Reserved3; /* 0x1D */ + U16 Reserved4; /* 0x1E */ +} MPI2_CONFIG_PAGE_SAS_PHY_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_0, + Mpi2SasPhyPage0_t, MPI2_POINTER pMpi2SasPhyPage0_t; + +#define MPI2_SASPHY0_PAGEVERSION (0x03) + +/* use MPI2_SAS_PRATE_ defines for the ProgrammedLinkRate field */ + +/* use MPI2_SAS_HWRATE_ defines for the HwLinkRate field */ + +/* values for SAS PHY Page 0 Flags field */ +#define MPI2_SAS_PHY0_FLAGS_SGPIO_DIRECT_ATTACH_ENC (0x01) + +/* use MPI2_SAS_APHYINFO_ defines for AttachedPhyInfo field */ + +/* use MPI2_SAS_NEG_LINK_RATE_ defines for the NegotiatedLinkRate field */ + +/* use MPI2_SAS_PHYINFO_ for the PhyInfo field */ + + +/* SAS PHY Page 1 */ + +typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_1 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved1; /* 0x08 */ + U32 InvalidDwordCount; /* 0x0C */ + U32 RunningDisparityErrorCount; /* 0x10 */ + U32 LossDwordSynchCount; /* 0x14 */ + U32 PhyResetProblemCount; /* 0x18 */ +} MPI2_CONFIG_PAGE_SAS_PHY_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_1, + Mpi2SasPhyPage1_t, MPI2_POINTER pMpi2SasPhyPage1_t; + +#define MPI2_SASPHY1_PAGEVERSION (0x01) + + +/**************************************************************************** +* SAS Port Config Pages +****************************************************************************/ + +/* SAS Port Page 0 */ + +typedef struct _MPI2_CONFIG_PAGE_SAS_PORT_0 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U8 PortNumber; /* 0x08 */ + U8 PhysicalPort; /* 0x09 */ + U8 PortWidth; /* 0x0A */ + U8 PhysicalPortWidth; /* 0x0B */ + U8 ZoneGroup; /* 0x0C */ + U8 Reserved1; /* 0x0D */ + U16 Reserved2; /* 0x0E */ + U64 SASAddress; /* 0x10 */ + U32 DeviceInfo; /* 0x18 */ + U32 Reserved3; /* 0x1C */ + U32 Reserved4; /* 0x20 */ +} MPI2_CONFIG_PAGE_SAS_PORT_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PORT_0, + Mpi2SasPortPage0_t, MPI2_POINTER pMpi2SasPortPage0_t; + +#define MPI2_SASPORT0_PAGEVERSION (0x00) + +/* see mpi2_sas.h for values for SAS Port Page 0 DeviceInfo values */ + + +/**************************************************************************** +* SAS Enclosure Config Pages +****************************************************************************/ + +/* SAS Enclosure Page 0 */ + +typedef struct _MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved1; /* 0x08 */ + U64 EnclosureLogicalID; /* 0x0C */ + U16 Flags; /* 0x14 */ + U16 EnclosureHandle; /* 0x16 */ + U16 NumSlots; /* 0x18 */ + U16 StartSlot; /* 0x1A */ + U16 Reserved2; /* 0x1C */ + U16 SEPDevHandle; /* 0x1E */ + U32 Reserved3; /* 0x20 */ + U32 Reserved4; /* 0x24 */ +} MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0, + Mpi2SasEnclosurePage0_t, MPI2_POINTER pMpi2SasEnclosurePage0_t; + +#define MPI2_SASENCLOSURE0_PAGEVERSION (0x03) + +/* values for SAS Enclosure Page 0 Flags field */ +#define MPI2_SAS_ENCLS0_FLAGS_MNG_MASK (0x000F) +#define MPI2_SAS_ENCLS0_FLAGS_MNG_UNKNOWN (0x0000) +#define MPI2_SAS_ENCLS0_FLAGS_MNG_IOC_SES (0x0001) +#define MPI2_SAS_ENCLS0_FLAGS_MNG_IOC_SGPIO (0x0002) +#define MPI2_SAS_ENCLS0_FLAGS_MNG_EXP_SGPIO (0x0003) +#define MPI2_SAS_ENCLS0_FLAGS_MNG_SES_ENCLOSURE (0x0004) +#define MPI2_SAS_ENCLS0_FLAGS_MNG_IOC_GPIO (0x0005) + + +/**************************************************************************** +* Log Config Page +****************************************************************************/ + +/* Log Page 0 */ + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check Header.ExtPageLength or NumPhys at runtime. + */ +#ifndef MPI2_LOG_0_NUM_LOG_ENTRIES +#define MPI2_LOG_0_NUM_LOG_ENTRIES (1) +#endif + +#define MPI2_LOG_0_LOG_DATA_LENGTH (0x1C) + +typedef struct _MPI2_LOG_0_ENTRY +{ + U64 TimeStamp; /* 0x00 */ + U32 Reserved1; /* 0x08 */ + U16 LogSequence; /* 0x0C */ + U16 LogEntryQualifier; /* 0x0E */ + U8 VP_ID; /* 0x10 */ + U8 VF_ID; /* 0x11 */ + U16 Reserved2; /* 0x12 */ + U8 LogData[MPI2_LOG_0_LOG_DATA_LENGTH];/* 0x14 */ +} MPI2_LOG_0_ENTRY, MPI2_POINTER PTR_MPI2_LOG_0_ENTRY, + Mpi2Log0Entry_t, MPI2_POINTER pMpi2Log0Entry_t; + +/* values for Log Page 0 LogEntry LogEntryQualifier field */ +#define MPI2_LOG_0_ENTRY_QUAL_ENTRY_UNUSED (0x0000) +#define MPI2_LOG_0_ENTRY_QUAL_POWER_ON_RESET (0x0001) +#define MPI2_LOG_0_ENTRY_QUAL_TIMESTAMP_UPDATE (0x0002) +#define MPI2_LOG_0_ENTRY_QUAL_MIN_IMPLEMENT_SPEC (0x8000) +#define MPI2_LOG_0_ENTRY_QUAL_MAX_IMPLEMENT_SPEC (0xFFFF) + +typedef struct _MPI2_CONFIG_PAGE_LOG_0 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved1; /* 0x08 */ + U32 Reserved2; /* 0x0C */ + U16 NumLogEntries; /* 0x10 */ + U16 Reserved3; /* 0x12 */ + MPI2_LOG_0_ENTRY LogEntry[MPI2_LOG_0_NUM_LOG_ENTRIES]; /* 0x14 */ +} MPI2_CONFIG_PAGE_LOG_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_LOG_0, + Mpi2LogPage0_t, MPI2_POINTER pMpi2LogPage0_t; + +#define MPI2_LOG_0_PAGEVERSION (0x02) + + +/**************************************************************************** +* RAID Config Page +****************************************************************************/ + +/* RAID Page 0 */ + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check Header.ExtPageLength or NumPhys at runtime. + */ +#ifndef MPI2_RAIDCONFIG0_MAX_ELEMENTS +#define MPI2_RAIDCONFIG0_MAX_ELEMENTS (1) +#endif + +typedef struct _MPI2_RAIDCONFIG0_CONFIG_ELEMENT +{ + U16 ElementFlags; /* 0x00 */ + U16 VolDevHandle; /* 0x02 */ + U8 HotSparePool; /* 0x04 */ + U8 PhysDiskNum; /* 0x05 */ + U16 PhysDiskDevHandle; /* 0x06 */ +} MPI2_RAIDCONFIG0_CONFIG_ELEMENT, + MPI2_POINTER PTR_MPI2_RAIDCONFIG0_CONFIG_ELEMENT, + Mpi2RaidConfig0ConfigElement_t, MPI2_POINTER pMpi2RaidConfig0ConfigElement_t; + +/* values for the ElementFlags field */ +#define MPI2_RAIDCONFIG0_EFLAGS_MASK_ELEMENT_TYPE (0x000F) +#define MPI2_RAIDCONFIG0_EFLAGS_VOLUME_ELEMENT (0x0000) +#define MPI2_RAIDCONFIG0_EFLAGS_VOL_PHYS_DISK_ELEMENT (0x0001) +#define MPI2_RAIDCONFIG0_EFLAGS_HOT_SPARE_ELEMENT (0x0002) +#define MPI2_RAIDCONFIG0_EFLAGS_OCE_ELEMENT (0x0003) + + +typedef struct _MPI2_CONFIG_PAGE_RAID_CONFIGURATION_0 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U8 NumHotSpares; /* 0x08 */ + U8 NumPhysDisks; /* 0x09 */ + U8 NumVolumes; /* 0x0A */ + U8 ConfigNum; /* 0x0B */ + U32 Flags; /* 0x0C */ + U8 ConfigGUID[24]; /* 0x10 */ + U32 Reserved1; /* 0x28 */ + U8 NumElements; /* 0x2C */ + U8 Reserved2; /* 0x2D */ + U16 Reserved3; /* 0x2E */ + MPI2_RAIDCONFIG0_CONFIG_ELEMENT ConfigElement[MPI2_RAIDCONFIG0_MAX_ELEMENTS]; /* 0x30 */ +} MPI2_CONFIG_PAGE_RAID_CONFIGURATION_0, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_RAID_CONFIGURATION_0, + Mpi2RaidConfigurationPage0_t, MPI2_POINTER pMpi2RaidConfigurationPage0_t; + +#define MPI2_RAIDCONFIG0_PAGEVERSION (0x00) + +/* values for RAID Configuration Page 0 Flags field */ +#define MPI2_RAIDCONFIG0_FLAG_FOREIGN_CONFIG (0x00000001) + + +/**************************************************************************** +* Driver Persistent Mapping Config Pages +****************************************************************************/ + +/* Driver Persistent Mapping Page 0 */ + +typedef struct _MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY +{ + U64 PhysicalIdentifier; /* 0x00 */ + U16 MappingInformation; /* 0x08 */ + U16 DeviceIndex; /* 0x0A */ + U32 PhysicalBitsMapping; /* 0x0C */ + U32 Reserved1; /* 0x10 */ +} MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY, + Mpi2DriverMap0Entry_t, MPI2_POINTER pMpi2DriverMap0Entry_t; + +typedef struct _MPI2_CONFIG_PAGE_DRIVER_MAPPING_0 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY Entry; /* 0x08 */ +} MPI2_CONFIG_PAGE_DRIVER_MAPPING_0, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_DRIVER_MAPPING_0, + Mpi2DriverMappingPage0_t, MPI2_POINTER pMpi2DriverMappingPage0_t; + +#define MPI2_DRIVERMAPPING0_PAGEVERSION (0x00) + +/* values for Driver Persistent Mapping Page 0 MappingInformation field */ +#define MPI2_DRVMAP0_MAPINFO_SLOT_MASK (0x07F0) +#define MPI2_DRVMAP0_MAPINFO_SLOT_SHIFT (4) +#define MPI2_DRVMAP0_MAPINFO_MISSING_MASK (0x000F) + + +#endif + diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_init.h b/drivers/scsi/mpt2sas/mpi/mpi2_init.h new file mode 100644 index 00000000000..f1115f0f0eb --- /dev/null +++ b/drivers/scsi/mpt2sas/mpi/mpi2_init.h @@ -0,0 +1,420 @@ +/* + * Copyright (c) 2000-2008 LSI Corporation. + * + * + * Name: mpi2_init.h + * Title: MPI SCSI initiator mode messages and structures + * Creation Date: June 23, 2006 + * + * mpi2_init.h Version: 02.00.06 + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * 10-31-07 02.00.01 Fixed name for pMpi2SCSITaskManagementRequest_t. + * 12-18-07 02.00.02 Modified Task Management Target Reset Method defines. + * 02-29-08 02.00.03 Added Query Task Set and Query Unit Attention. + * 03-03-08 02.00.04 Fixed name of struct _MPI2_SCSI_TASK_MANAGE_REPLY. + * 05-21-08 02.00.05 Fixed typo in name of Mpi2SepRequest_t. + * 10-02-08 02.00.06 Removed Untagged and No Disconnect values from SCSI IO + * Control field Task Attribute flags. + * Moved LUN field defines to mpi2.h becasue they are + * common to many structures. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI2_INIT_H +#define MPI2_INIT_H + +/***************************************************************************** +* +* SCSI Initiator Messages +* +*****************************************************************************/ + +/**************************************************************************** +* SCSI IO messages and associated structures +****************************************************************************/ + +typedef struct +{ + U8 CDB[20]; /* 0x00 */ + U32 PrimaryReferenceTag; /* 0x14 */ + U16 PrimaryApplicationTag; /* 0x18 */ + U16 PrimaryApplicationTagMask; /* 0x1A */ + U32 TransferLength; /* 0x1C */ +} MPI2_SCSI_IO_CDB_EEDP32, MPI2_POINTER PTR_MPI2_SCSI_IO_CDB_EEDP32, + Mpi2ScsiIoCdbEedp32_t, MPI2_POINTER pMpi2ScsiIoCdbEedp32_t; + +/* TBD: I don't think this is needed for MPI2/Gen2 */ +#if 0 +typedef struct +{ + U8 CDB[16]; /* 0x00 */ + U32 DataLength; /* 0x10 */ + U32 PrimaryReferenceTag; /* 0x14 */ + U16 PrimaryApplicationTag; /* 0x18 */ + U16 PrimaryApplicationTagMask; /* 0x1A */ + U32 TransferLength; /* 0x1C */ +} MPI2_SCSI_IO32_CDB_EEDP16, MPI2_POINTER PTR_MPI2_SCSI_IO32_CDB_EEDP16, + Mpi2ScsiIo32CdbEedp16_t, MPI2_POINTER pMpi2ScsiIo32CdbEedp16_t; +#endif + +typedef union +{ + U8 CDB32[32]; + MPI2_SCSI_IO_CDB_EEDP32 EEDP32; + MPI2_SGE_SIMPLE_UNION SGE; +} MPI2_SCSI_IO_CDB_UNION, MPI2_POINTER PTR_MPI2_SCSI_IO_CDB_UNION, + Mpi2ScsiIoCdb_t, MPI2_POINTER pMpi2ScsiIoCdb_t; + +/* SCSI IO Request Message */ +typedef struct _MPI2_SCSI_IO_REQUEST +{ + U16 DevHandle; /* 0x00 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved1; /* 0x04 */ + U8 Reserved2; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved3; /* 0x0A */ + U32 SenseBufferLowAddress; /* 0x0C */ + U16 SGLFlags; /* 0x10 */ + U8 SenseBufferLength; /* 0x12 */ + U8 Reserved4; /* 0x13 */ + U8 SGLOffset0; /* 0x14 */ + U8 SGLOffset1; /* 0x15 */ + U8 SGLOffset2; /* 0x16 */ + U8 SGLOffset3; /* 0x17 */ + U32 SkipCount; /* 0x18 */ + U32 DataLength; /* 0x1C */ + U32 BidirectionalDataLength; /* 0x20 */ + U16 IoFlags; /* 0x24 */ + U16 EEDPFlags; /* 0x26 */ + U32 EEDPBlockSize; /* 0x28 */ + U32 SecondaryReferenceTag; /* 0x2C */ + U16 SecondaryApplicationTag; /* 0x30 */ + U16 ApplicationTagTranslationMask; /* 0x32 */ + U8 LUN[8]; /* 0x34 */ + U32 Control; /* 0x3C */ + MPI2_SCSI_IO_CDB_UNION CDB; /* 0x40 */ + MPI2_SGE_IO_UNION SGL; /* 0x60 */ +} MPI2_SCSI_IO_REQUEST, MPI2_POINTER PTR_MPI2_SCSI_IO_REQUEST, + Mpi2SCSIIORequest_t, MPI2_POINTER pMpi2SCSIIORequest_t; + +/* SCSI IO MsgFlags bits */ + +/* MsgFlags for SenseBufferAddressSpace */ +#define MPI2_SCSIIO_MSGFLAGS_MASK_SENSE_ADDR (0x0C) +#define MPI2_SCSIIO_MSGFLAGS_SYSTEM_SENSE_ADDR (0x00) +#define MPI2_SCSIIO_MSGFLAGS_IOCDDR_SENSE_ADDR (0x04) +#define MPI2_SCSIIO_MSGFLAGS_IOCPLB_SENSE_ADDR (0x08) +#define MPI2_SCSIIO_MSGFLAGS_IOCPLBNTA_SENSE_ADDR (0x0C) + +/* SCSI IO SGLFlags bits */ + +/* base values for Data Location Address Space */ +#define MPI2_SCSIIO_SGLFLAGS_ADDR_MASK (0x0C) +#define MPI2_SCSIIO_SGLFLAGS_SYSTEM_ADDR (0x00) +#define MPI2_SCSIIO_SGLFLAGS_IOCDDR_ADDR (0x04) +#define MPI2_SCSIIO_SGLFLAGS_IOCPLB_ADDR (0x08) +#define MPI2_SCSIIO_SGLFLAGS_IOCPLBNTA_ADDR (0x0C) + +/* base values for Type */ +#define MPI2_SCSIIO_SGLFLAGS_TYPE_MASK (0x03) +#define MPI2_SCSIIO_SGLFLAGS_TYPE_MPI (0x00) +#define MPI2_SCSIIO_SGLFLAGS_TYPE_IEEE32 (0x01) +#define MPI2_SCSIIO_SGLFLAGS_TYPE_IEEE64 (0x02) + +/* shift values for each sub-field */ +#define MPI2_SCSIIO_SGLFLAGS_SGL3_SHIFT (12) +#define MPI2_SCSIIO_SGLFLAGS_SGL2_SHIFT (8) +#define MPI2_SCSIIO_SGLFLAGS_SGL1_SHIFT (4) +#define MPI2_SCSIIO_SGLFLAGS_SGL0_SHIFT (0) + +/* SCSI IO IoFlags bits */ + +/* Large CDB Address Space */ +#define MPI2_SCSIIO_CDB_ADDR_MASK (0x6000) +#define MPI2_SCSIIO_CDB_ADDR_SYSTEM (0x0000) +#define MPI2_SCSIIO_CDB_ADDR_IOCDDR (0x2000) +#define MPI2_SCSIIO_CDB_ADDR_IOCPLB (0x4000) +#define MPI2_SCSIIO_CDB_ADDR_IOCPLBNTA (0x6000) + +#define MPI2_SCSIIO_IOFLAGS_LARGE_CDB (0x1000) +#define MPI2_SCSIIO_IOFLAGS_BIDIRECTIONAL (0x0800) +#define MPI2_SCSIIO_IOFLAGS_MULTICAST (0x0400) +#define MPI2_SCSIIO_IOFLAGS_CMD_DETERMINES_DATA_DIR (0x0200) +#define MPI2_SCSIIO_IOFLAGS_CDBLENGTH_MASK (0x01FF) + +/* SCSI IO EEDPFlags bits */ + +#define MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG (0x8000) +#define MPI2_SCSIIO_EEDPFLAGS_INC_SEC_REFTAG (0x4000) +#define MPI2_SCSIIO_EEDPFLAGS_INC_PRI_APPTAG (0x2000) +#define MPI2_SCSIIO_EEDPFLAGS_INC_SEC_APPTAG (0x1000) + +#define MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG (0x0400) +#define MPI2_SCSIIO_EEDPFLAGS_CHECK_APPTAG (0x0200) +#define MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD (0x0100) + +#define MPI2_SCSIIO_EEDPFLAGS_PASSTHRU_REFTAG (0x0008) + +#define MPI2_SCSIIO_EEDPFLAGS_MASK_OP (0x0007) +#define MPI2_SCSIIO_EEDPFLAGS_NOOP_OP (0x0000) +#define MPI2_SCSIIO_EEDPFLAGS_CHECK_OP (0x0001) +#define MPI2_SCSIIO_EEDPFLAGS_STRIP_OP (0x0002) +#define MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP (0x0003) +#define MPI2_SCSIIO_EEDPFLAGS_INSERT_OP (0x0004) +#define MPI2_SCSIIO_EEDPFLAGS_REPLACE_OP (0x0006) +#define MPI2_SCSIIO_EEDPFLAGS_CHECK_REGEN_OP (0x0007) + +/* SCSI IO LUN fields: use MPI2_LUN_ from mpi2.h */ + +/* SCSI IO Control bits */ +#define MPI2_SCSIIO_CONTROL_ADDCDBLEN_MASK (0xFC000000) +#define MPI2_SCSIIO_CONTROL_ADDCDBLEN_SHIFT (26) + +#define MPI2_SCSIIO_CONTROL_DATADIRECTION_MASK (0x03000000) +#define MPI2_SCSIIO_CONTROL_NODATATRANSFER (0x00000000) +#define MPI2_SCSIIO_CONTROL_WRITE (0x01000000) +#define MPI2_SCSIIO_CONTROL_READ (0x02000000) +#define MPI2_SCSIIO_CONTROL_BIDIRECTIONAL (0x03000000) + +#define MPI2_SCSIIO_CONTROL_TASKPRI_MASK (0x00007800) +#define MPI2_SCSIIO_CONTROL_TASKPRI_SHIFT (11) + +#define MPI2_SCSIIO_CONTROL_TASKATTRIBUTE_MASK (0x00000700) +#define MPI2_SCSIIO_CONTROL_SIMPLEQ (0x00000000) +#define MPI2_SCSIIO_CONTROL_HEADOFQ (0x00000100) +#define MPI2_SCSIIO_CONTROL_ORDEREDQ (0x00000200) +#define MPI2_SCSIIO_CONTROL_ACAQ (0x00000400) + +#define MPI2_SCSIIO_CONTROL_TLR_MASK (0x000000C0) +#define MPI2_SCSIIO_CONTROL_NO_TLR (0x00000000) +#define MPI2_SCSIIO_CONTROL_TLR_ON (0x00000040) +#define MPI2_SCSIIO_CONTROL_TLR_OFF (0x00000080) + + +/* SCSI IO Error Reply Message */ +typedef struct _MPI2_SCSI_IO_REPLY +{ + U16 DevHandle; /* 0x00 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved1; /* 0x04 */ + U8 Reserved2; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved3; /* 0x0A */ + U8 SCSIStatus; /* 0x0C */ + U8 SCSIState; /* 0x0D */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ + U32 TransferCount; /* 0x14 */ + U32 SenseCount; /* 0x18 */ + U32 ResponseInfo; /* 0x1C */ + U16 TaskTag; /* 0x20 */ + U16 Reserved4; /* 0x22 */ + U32 BidirectionalTransferCount; /* 0x24 */ + U32 Reserved5; /* 0x28 */ + U32 Reserved6; /* 0x2C */ +} MPI2_SCSI_IO_REPLY, MPI2_POINTER PTR_MPI2_SCSI_IO_REPLY, + Mpi2SCSIIOReply_t, MPI2_POINTER pMpi2SCSIIOReply_t; + +/* SCSI IO Reply SCSIStatus values (SAM-4 status codes) */ + +#define MPI2_SCSI_STATUS_GOOD (0x00) +#define MPI2_SCSI_STATUS_CHECK_CONDITION (0x02) +#define MPI2_SCSI_STATUS_CONDITION_MET (0x04) +#define MPI2_SCSI_STATUS_BUSY (0x08) +#define MPI2_SCSI_STATUS_INTERMEDIATE (0x10) +#define MPI2_SCSI_STATUS_INTERMEDIATE_CONDMET (0x14) +#define MPI2_SCSI_STATUS_RESERVATION_CONFLICT (0x18) +#define MPI2_SCSI_STATUS_COMMAND_TERMINATED (0x22) /* obsolete */ +#define MPI2_SCSI_STATUS_TASK_SET_FULL (0x28) +#define MPI2_SCSI_STATUS_ACA_ACTIVE (0x30) +#define MPI2_SCSI_STATUS_TASK_ABORTED (0x40) + +/* SCSI IO Reply SCSIState flags */ + +#define MPI2_SCSI_STATE_RESPONSE_INFO_VALID (0x10) +#define MPI2_SCSI_STATE_TERMINATED (0x08) +#define MPI2_SCSI_STATE_NO_SCSI_STATUS (0x04) +#define MPI2_SCSI_STATE_AUTOSENSE_FAILED (0x02) +#define MPI2_SCSI_STATE_AUTOSENSE_VALID (0x01) + +#define MPI2_SCSI_TASKTAG_UNKNOWN (0xFFFF) + + +/**************************************************************************** +* SCSI Task Management messages +****************************************************************************/ + +/* SCSI Task Management Request Message */ +typedef struct _MPI2_SCSI_TASK_MANAGE_REQUEST +{ + U16 DevHandle; /* 0x00 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U8 Reserved1; /* 0x04 */ + U8 TaskType; /* 0x05 */ + U8 Reserved2; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved3; /* 0x0A */ + U8 LUN[8]; /* 0x0C */ + U32 Reserved4[7]; /* 0x14 */ + U16 TaskMID; /* 0x30 */ + U16 Reserved5; /* 0x32 */ +} MPI2_SCSI_TASK_MANAGE_REQUEST, + MPI2_POINTER PTR_MPI2_SCSI_TASK_MANAGE_REQUEST, + Mpi2SCSITaskManagementRequest_t, + MPI2_POINTER pMpi2SCSITaskManagementRequest_t; + +/* TaskType values */ + +#define MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK (0x01) +#define MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET (0x02) +#define MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET (0x03) +#define MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET (0x05) +#define MPI2_SCSITASKMGMT_TASKTYPE_CLEAR_TASK_SET (0x06) +#define MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK (0x07) +#define MPI2_SCSITASKMGMT_TASKTYPE_CLR_ACA (0x08) +#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_TASK_SET (0x09) +#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_UNIT_ATTENTION (0x0A) + +/* MsgFlags bits */ + +#define MPI2_SCSITASKMGMT_MSGFLAGS_MASK_TARGET_RESET (0x18) +#define MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET (0x00) +#define MPI2_SCSITASKMGMT_MSGFLAGS_NEXUS_RESET_SRST (0x08) +#define MPI2_SCSITASKMGMT_MSGFLAGS_SAS_HARD_LINK_RESET (0x10) + +#define MPI2_SCSITASKMGMT_MSGFLAGS_DO_NOT_SEND_TASK_IU (0x01) + + + +/* SCSI Task Management Reply Message */ +typedef struct _MPI2_SCSI_TASK_MANAGE_REPLY +{ + U16 DevHandle; /* 0x00 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U8 ResponseCode; /* 0x04 */ + U8 TaskType; /* 0x05 */ + U8 Reserved1; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved2; /* 0x0A */ + U16 Reserved3; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ + U32 TerminationCount; /* 0x14 */ +} MPI2_SCSI_TASK_MANAGE_REPLY, + MPI2_POINTER PTR_MPI2_SCSI_TASK_MANAGE_REPLY, + Mpi2SCSITaskManagementReply_t, MPI2_POINTER pMpi2SCSIManagementReply_t; + +/* ResponseCode values */ + +#define MPI2_SCSITASKMGMT_RSP_TM_COMPLETE (0x00) +#define MPI2_SCSITASKMGMT_RSP_INVALID_FRAME (0x02) +#define MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED (0x04) +#define MPI2_SCSITASKMGMT_RSP_TM_FAILED (0x05) +#define MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED (0x08) +#define MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN (0x09) +#define MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC (0x80) + + +/**************************************************************************** +* SCSI Enclosure Processor messages +****************************************************************************/ + +/* SCSI Enclosure Processor Request Message */ +typedef struct _MPI2_SEP_REQUEST +{ + U16 DevHandle; /* 0x00 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U8 Action; /* 0x04 */ + U8 Flags; /* 0x05 */ + U8 Reserved1; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved2; /* 0x0A */ + U32 SlotStatus; /* 0x0C */ + U32 Reserved3; /* 0x10 */ + U32 Reserved4; /* 0x14 */ + U32 Reserved5; /* 0x18 */ + U16 Slot; /* 0x1C */ + U16 EnclosureHandle; /* 0x1E */ +} MPI2_SEP_REQUEST, MPI2_POINTER PTR_MPI2_SEP_REQUEST, + Mpi2SepRequest_t, MPI2_POINTER pMpi2SepRequest_t; + +/* Action defines */ +#define MPI2_SEP_REQ_ACTION_WRITE_STATUS (0x00) +#define MPI2_SEP_REQ_ACTION_READ_STATUS (0x01) + +/* Flags defines */ +#define MPI2_SEP_REQ_FLAGS_DEVHANDLE_ADDRESS (0x00) +#define MPI2_SEP_REQ_FLAGS_ENCLOSURE_SLOT_ADDRESS (0x01) + +/* SlotStatus defines */ +#define MPI2_SEP_REQ_SLOTSTATUS_REQUEST_REMOVE (0x00040000) +#define MPI2_SEP_REQ_SLOTSTATUS_IDENTIFY_REQUEST (0x00020000) +#define MPI2_SEP_REQ_SLOTSTATUS_REBUILD_STOPPED (0x00000200) +#define MPI2_SEP_REQ_SLOTSTATUS_HOT_SPARE (0x00000100) +#define MPI2_SEP_REQ_SLOTSTATUS_UNCONFIGURED (0x00000080) +#define MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT (0x00000040) +#define MPI2_SEP_REQ_SLOTSTATUS_DEV_REBUILDING (0x00000004) +#define MPI2_SEP_REQ_SLOTSTATUS_DEV_FAULTY (0x00000002) +#define MPI2_SEP_REQ_SLOTSTATUS_NO_ERROR (0x00000001) + + +/* SCSI Enclosure Processor Reply Message */ +typedef struct _MPI2_SEP_REPLY +{ + U16 DevHandle; /* 0x00 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U8 Action; /* 0x04 */ + U8 Flags; /* 0x05 */ + U8 Reserved1; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved2; /* 0x0A */ + U16 Reserved3; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ + U32 SlotStatus; /* 0x14 */ + U32 Reserved4; /* 0x18 */ + U16 Slot; /* 0x1C */ + U16 EnclosureHandle; /* 0x1E */ +} MPI2_SEP_REPLY, MPI2_POINTER PTR_MPI2_SEP_REPLY, + Mpi2SepReply_t, MPI2_POINTER pMpi2SepReply_t; + +/* SlotStatus defines */ +#define MPI2_SEP_REPLY_SLOTSTATUS_REMOVE_READY (0x00040000) +#define MPI2_SEP_REPLY_SLOTSTATUS_IDENTIFY_REQUEST (0x00020000) +#define MPI2_SEP_REPLY_SLOTSTATUS_REBUILD_STOPPED (0x00000200) +#define MPI2_SEP_REPLY_SLOTSTATUS_HOT_SPARE (0x00000100) +#define MPI2_SEP_REPLY_SLOTSTATUS_UNCONFIGURED (0x00000080) +#define MPI2_SEP_REPLY_SLOTSTATUS_PREDICTED_FAULT (0x00000040) +#define MPI2_SEP_REPLY_SLOTSTATUS_DEV_REBUILDING (0x00000004) +#define MPI2_SEP_REPLY_SLOTSTATUS_DEV_FAULTY (0x00000002) +#define MPI2_SEP_REPLY_SLOTSTATUS_NO_ERROR (0x00000001) + + +#endif + + diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h new file mode 100644 index 00000000000..8c5d81870c0 --- /dev/null +++ b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h @@ -0,0 +1,1295 @@ +/* + * Copyright (c) 2000-2009 LSI Corporation. + * + * + * Name: mpi2_ioc.h + * Title: MPI IOC, Port, Event, FW Download, and FW Upload messages + * Creation Date: October 11, 2006 + * + * mpi2_ioc.h Version: 02.00.10 + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * 06-04-07 02.00.01 In IOCFacts Reply structure, renamed MaxDevices to + * MaxTargets. + * Added TotalImageSize field to FWDownload Request. + * Added reserved words to FWUpload Request. + * 06-26-07 02.00.02 Added IR Configuration Change List Event. + * 08-31-07 02.00.03 Removed SystemReplyQueueDepth field from the IOCInit + * request and replaced it with + * ReplyDescriptorPostQueueDepth and ReplyFreeQueueDepth. + * Replaced the MinReplyQueueDepth field of the IOCFacts + * reply with MaxReplyDescriptorPostQueueDepth. + * Added MPI2_RDPQ_DEPTH_MIN define to specify the minimum + * depth for the Reply Descriptor Post Queue. + * Added SASAddress field to Initiator Device Table + * Overflow Event data. + * 10-31-07 02.00.04 Added ReasonCode MPI2_EVENT_SAS_INIT_RC_NOT_RESPONDING + * for SAS Initiator Device Status Change Event data. + * Modified Reason Code defines for SAS Topology Change + * List Event data, including adding a bit for PHY Vacant + * status, and adding a mask for the Reason Code. + * Added define for + * MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING. + * Added define for MPI2_EXT_IMAGE_TYPE_MEGARAID. + * 12-18-07 02.00.05 Added Boot Status defines for the IOCExceptions field of + * the IOCFacts Reply. + * Removed MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER define. + * Moved MPI2_VERSION_UNION to mpi2.h. + * Changed MPI2_EVENT_NOTIFICATION_REQUEST to use masks + * instead of enables, and added SASBroadcastPrimitiveMasks + * field. + * Added Log Entry Added Event and related structure. + * 02-29-08 02.00.06 Added define MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID. + * Removed define MPI2_IOCFACTS_PROTOCOL_SMP_TARGET. + * Added MaxVolumes and MaxPersistentEntries fields to + * IOCFacts reply. + * Added ProtocalFlags and IOCCapabilities fields to + * MPI2_FW_IMAGE_HEADER. + * Removed MPI2_PORTENABLE_FLAGS_ENABLE_SINGLE_PORT. + * 03-03-08 02.00.07 Fixed MPI2_FW_IMAGE_HEADER by changing Reserved26 to + * a U16 (from a U32). + * Removed extra 's' from EventMasks name. + * 06-27-08 02.00.08 Fixed an offset in a comment. + * 10-02-08 02.00.09 Removed SystemReplyFrameSize from MPI2_IOC_INIT_REQUEST. + * Removed CurReplyFrameSize from MPI2_IOC_FACTS_REPLY and + * renamed MinReplyFrameSize to ReplyFrameSize. + * Added MPI2_IOCFACTS_EXCEPT_IR_FOREIGN_CONFIG_MAX. + * Added two new RAIDOperation values for Integrated RAID + * Operations Status Event data. + * Added four new IR Configuration Change List Event data + * ReasonCode values. + * Added two new ReasonCode defines for SAS Device Status + * Change Event data. + * Added three new DiscoveryStatus bits for the SAS + * Discovery event data. + * Added Multiplexing Status Change bit to the PhyStatus + * field of the SAS Topology Change List event data. + * Removed define for MPI2_INIT_IMAGE_BOOTFLAGS_XMEMCOPY. + * BootFlags are now product-specific. + * Added defines for the indivdual signature bytes + * for MPI2_INIT_IMAGE_FOOTER. + * 01-19-09 02.00.10 Added MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY define. + * Added MPI2_EVENT_SAS_DISC_DS_DOWNSTREAM_INITIATOR + * define. + * Added MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE + * define. + * Removed MPI2_EVENT_SAS_DISC_DS_SATA_INIT_FAILURE define. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI2_IOC_H +#define MPI2_IOC_H + +/***************************************************************************** +* +* IOC Messages +* +*****************************************************************************/ + +/**************************************************************************** +* IOCInit message +****************************************************************************/ + +/* IOCInit Request message */ +typedef struct _MPI2_IOC_INIT_REQUEST +{ + U8 WhoInit; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U16 MsgVersion; /* 0x0C */ + U16 HeaderVersion; /* 0x0E */ + U32 Reserved5; /* 0x10 */ + U32 Reserved6; /* 0x14 */ + U16 Reserved7; /* 0x18 */ + U16 SystemRequestFrameSize; /* 0x1A */ + U16 ReplyDescriptorPostQueueDepth; /* 0x1C */ + U16 ReplyFreeQueueDepth; /* 0x1E */ + U32 SenseBufferAddressHigh; /* 0x20 */ + U32 SystemReplyAddressHigh; /* 0x24 */ + U64 SystemRequestFrameBaseAddress; /* 0x28 */ + U64 ReplyDescriptorPostQueueAddress;/* 0x30 */ + U64 ReplyFreeQueueAddress; /* 0x38 */ + U64 TimeStamp; /* 0x40 */ +} MPI2_IOC_INIT_REQUEST, MPI2_POINTER PTR_MPI2_IOC_INIT_REQUEST, + Mpi2IOCInitRequest_t, MPI2_POINTER pMpi2IOCInitRequest_t; + +/* WhoInit values */ +#define MPI2_WHOINIT_NOT_INITIALIZED (0x00) +#define MPI2_WHOINIT_SYSTEM_BIOS (0x01) +#define MPI2_WHOINIT_ROM_BIOS (0x02) +#define MPI2_WHOINIT_PCI_PEER (0x03) +#define MPI2_WHOINIT_HOST_DRIVER (0x04) +#define MPI2_WHOINIT_MANUFACTURER (0x05) + +/* MsgVersion */ +#define MPI2_IOCINIT_MSGVERSION_MAJOR_MASK (0xFF00) +#define MPI2_IOCINIT_MSGVERSION_MAJOR_SHIFT (8) +#define MPI2_IOCINIT_MSGVERSION_MINOR_MASK (0x00FF) +#define MPI2_IOCINIT_MSGVERSION_MINOR_SHIFT (0) + +/* HeaderVersion */ +#define MPI2_IOCINIT_HDRVERSION_UNIT_MASK (0xFF00) +#define MPI2_IOCINIT_HDRVERSION_UNIT_SHIFT (8) +#define MPI2_IOCINIT_HDRVERSION_DEV_MASK (0x00FF) +#define MPI2_IOCINIT_HDRVERSION_DEV_SHIFT (0) + +/* minimum depth for the Reply Descriptor Post Queue */ +#define MPI2_RDPQ_DEPTH_MIN (16) + + +/* IOCInit Reply message */ +typedef struct _MPI2_IOC_INIT_REPLY +{ + U8 WhoInit; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U16 Reserved5; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ +} MPI2_IOC_INIT_REPLY, MPI2_POINTER PTR_MPI2_IOC_INIT_REPLY, + Mpi2IOCInitReply_t, MPI2_POINTER pMpi2IOCInitReply_t; + + +/**************************************************************************** +* IOCFacts message +****************************************************************************/ + +/* IOCFacts Request message */ +typedef struct _MPI2_IOC_FACTS_REQUEST +{ + U16 Reserved1; /* 0x00 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ +} MPI2_IOC_FACTS_REQUEST, MPI2_POINTER PTR_MPI2_IOC_FACTS_REQUEST, + Mpi2IOCFactsRequest_t, MPI2_POINTER pMpi2IOCFactsRequest_t; + + +/* IOCFacts Reply message */ +typedef struct _MPI2_IOC_FACTS_REPLY +{ + U16 MsgVersion; /* 0x00 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 HeaderVersion; /* 0x04 */ + U8 IOCNumber; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved1; /* 0x0A */ + U16 IOCExceptions; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ + U8 MaxChainDepth; /* 0x14 */ + U8 WhoInit; /* 0x15 */ + U8 NumberOfPorts; /* 0x16 */ + U8 Reserved2; /* 0x17 */ + U16 RequestCredit; /* 0x18 */ + U16 ProductID; /* 0x1A */ + U32 IOCCapabilities; /* 0x1C */ + MPI2_VERSION_UNION FWVersion; /* 0x20 */ + U16 IOCRequestFrameSize; /* 0x24 */ + U16 Reserved3; /* 0x26 */ + U16 MaxInitiators; /* 0x28 */ + U16 MaxTargets; /* 0x2A */ + U16 MaxSasExpanders; /* 0x2C */ + U16 MaxEnclosures; /* 0x2E */ + U16 ProtocolFlags; /* 0x30 */ + U16 HighPriorityCredit; /* 0x32 */ + U16 MaxReplyDescriptorPostQueueDepth; /* 0x34 */ + U8 ReplyFrameSize; /* 0x36 */ + U8 MaxVolumes; /* 0x37 */ + U16 MaxDevHandle; /* 0x38 */ + U16 MaxPersistentEntries; /* 0x3A */ + U32 Reserved4; /* 0x3C */ +} MPI2_IOC_FACTS_REPLY, MPI2_POINTER PTR_MPI2_IOC_FACTS_REPLY, + Mpi2IOCFactsReply_t, MPI2_POINTER pMpi2IOCFactsReply_t; + +/* MsgVersion */ +#define MPI2_IOCFACTS_MSGVERSION_MAJOR_MASK (0xFF00) +#define MPI2_IOCFACTS_MSGVERSION_MAJOR_SHIFT (8) +#define MPI2_IOCFACTS_MSGVERSION_MINOR_MASK (0x00FF) +#define MPI2_IOCFACTS_MSGVERSION_MINOR_SHIFT (0) + +/* HeaderVersion */ +#define MPI2_IOCFACTS_HDRVERSION_UNIT_MASK (0xFF00) +#define MPI2_IOCFACTS_HDRVERSION_UNIT_SHIFT (8) +#define MPI2_IOCFACTS_HDRVERSION_DEV_MASK (0x00FF) +#define MPI2_IOCFACTS_HDRVERSION_DEV_SHIFT (0) + +/* IOCExceptions */ +#define MPI2_IOCFACTS_EXCEPT_IR_FOREIGN_CONFIG_MAX (0x0100) + +#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_MASK (0x00E0) +#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_GOOD (0x0000) +#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_BACKUP (0x0020) +#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_RESTORED (0x0040) +#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_CORRUPT_BACKUP (0x0060) + +#define MPI2_IOCFACTS_EXCEPT_METADATA_UNSUPPORTED (0x0010) +#define MPI2_IOCFACTS_EXCEPT_MANUFACT_CHECKSUM_FAIL (0x0008) +#define MPI2_IOCFACTS_EXCEPT_FW_CHECKSUM_FAIL (0x0004) +#define MPI2_IOCFACTS_EXCEPT_RAID_CONFIG_INVALID (0x0002) +#define MPI2_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL (0x0001) + +/* defines for WhoInit field are after the IOCInit Request */ + +/* ProductID field uses MPI2_FW_HEADER_PID_ */ + +/* IOCCapabilities */ +#define MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY (0x00002000) +#define MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID (0x00001000) +#define MPI2_IOCFACTS_CAPABILITY_TLR (0x00000800) +#define MPI2_IOCFACTS_CAPABILITY_MULTICAST (0x00000100) +#define MPI2_IOCFACTS_CAPABILITY_BIDIRECTIONAL_TARGET (0x00000080) +#define MPI2_IOCFACTS_CAPABILITY_EEDP (0x00000040) +#define MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER (0x00000010) +#define MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER (0x00000008) +#define MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING (0x00000004) + +/* ProtocolFlags */ +#define MPI2_IOCFACTS_PROTOCOL_SCSI_TARGET (0x0001) +#define MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR (0x0002) + + +/**************************************************************************** +* PortFacts message +****************************************************************************/ + +/* PortFacts Request message */ +typedef struct _MPI2_PORT_FACTS_REQUEST +{ + U16 Reserved1; /* 0x00 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 PortNumber; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved3; /* 0x0A */ +} MPI2_PORT_FACTS_REQUEST, MPI2_POINTER PTR_MPI2_PORT_FACTS_REQUEST, + Mpi2PortFactsRequest_t, MPI2_POINTER pMpi2PortFactsRequest_t; + +/* PortFacts Reply message */ +typedef struct _MPI2_PORT_FACTS_REPLY +{ + U16 Reserved1; /* 0x00 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 PortNumber; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved3; /* 0x0A */ + U16 Reserved4; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ + U8 Reserved5; /* 0x14 */ + U8 PortType; /* 0x15 */ + U16 Reserved6; /* 0x16 */ + U16 MaxPostedCmdBuffers; /* 0x18 */ + U16 Reserved7; /* 0x1A */ +} MPI2_PORT_FACTS_REPLY, MPI2_POINTER PTR_MPI2_PORT_FACTS_REPLY, + Mpi2PortFactsReply_t, MPI2_POINTER pMpi2PortFactsReply_t; + +/* PortType values */ +#define MPI2_PORTFACTS_PORTTYPE_INACTIVE (0x00) +#define MPI2_PORTFACTS_PORTTYPE_FC (0x10) +#define MPI2_PORTFACTS_PORTTYPE_ISCSI (0x20) +#define MPI2_PORTFACTS_PORTTYPE_SAS_PHYSICAL (0x30) +#define MPI2_PORTFACTS_PORTTYPE_SAS_VIRTUAL (0x31) + + +/**************************************************************************** +* PortEnable message +****************************************************************************/ + +/* PortEnable Request message */ +typedef struct _MPI2_PORT_ENABLE_REQUEST +{ + U16 Reserved1; /* 0x00 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U8 Reserved2; /* 0x04 */ + U8 PortFlags; /* 0x05 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ +} MPI2_PORT_ENABLE_REQUEST, MPI2_POINTER PTR_MPI2_PORT_ENABLE_REQUEST, + Mpi2PortEnableRequest_t, MPI2_POINTER pMpi2PortEnableRequest_t; + + +/* PortEnable Reply message */ +typedef struct _MPI2_PORT_ENABLE_REPLY +{ + U16 Reserved1; /* 0x00 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U8 Reserved2; /* 0x04 */ + U8 PortFlags; /* 0x05 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U16 Reserved5; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ +} MPI2_PORT_ENABLE_REPLY, MPI2_POINTER PTR_MPI2_PORT_ENABLE_REPLY, + Mpi2PortEnableReply_t, MPI2_POINTER pMpi2PortEnableReply_t; + + +/**************************************************************************** +* EventNotification message +****************************************************************************/ + +/* EventNotification Request message */ +#define MPI2_EVENT_NOTIFY_EVENTMASK_WORDS (4) + +typedef struct _MPI2_EVENT_NOTIFICATION_REQUEST +{ + U16 Reserved1; /* 0x00 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U32 Reserved5; /* 0x0C */ + U32 Reserved6; /* 0x10 */ + U32 EventMasks[MPI2_EVENT_NOTIFY_EVENTMASK_WORDS];/* 0x14 */ + U16 SASBroadcastPrimitiveMasks; /* 0x24 */ + U16 Reserved7; /* 0x26 */ + U32 Reserved8; /* 0x28 */ +} MPI2_EVENT_NOTIFICATION_REQUEST, + MPI2_POINTER PTR_MPI2_EVENT_NOTIFICATION_REQUEST, + Mpi2EventNotificationRequest_t, MPI2_POINTER pMpi2EventNotificationRequest_t; + + +/* EventNotification Reply message */ +typedef struct _MPI2_EVENT_NOTIFICATION_REPLY +{ + U16 EventDataLength; /* 0x00 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved1; /* 0x04 */ + U8 AckRequired; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved2; /* 0x0A */ + U16 Reserved3; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ + U16 Event; /* 0x14 */ + U16 Reserved4; /* 0x16 */ + U32 EventContext; /* 0x18 */ + U32 EventData[1]; /* 0x1C */ +} MPI2_EVENT_NOTIFICATION_REPLY, MPI2_POINTER PTR_MPI2_EVENT_NOTIFICATION_REPLY, + Mpi2EventNotificationReply_t, MPI2_POINTER pMpi2EventNotificationReply_t; + +/* AckRequired */ +#define MPI2_EVENT_NOTIFICATION_ACK_NOT_REQUIRED (0x00) +#define MPI2_EVENT_NOTIFICATION_ACK_REQUIRED (0x01) + +/* Event */ +#define MPI2_EVENT_LOG_DATA (0x0001) +#define MPI2_EVENT_STATE_CHANGE (0x0002) +#define MPI2_EVENT_HARD_RESET_RECEIVED (0x0005) +#define MPI2_EVENT_EVENT_CHANGE (0x000A) +#define MPI2_EVENT_TASK_SET_FULL (0x000E) +#define MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE (0x000F) +#define MPI2_EVENT_IR_OPERATION_STATUS (0x0014) +#define MPI2_EVENT_SAS_DISCOVERY (0x0016) +#define MPI2_EVENT_SAS_BROADCAST_PRIMITIVE (0x0017) +#define MPI2_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE (0x0018) +#define MPI2_EVENT_SAS_INIT_TABLE_OVERFLOW (0x0019) +#define MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST (0x001C) +#define MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE (0x001D) +#define MPI2_EVENT_IR_VOLUME (0x001E) +#define MPI2_EVENT_IR_PHYSICAL_DISK (0x001F) +#define MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST (0x0020) +#define MPI2_EVENT_LOG_ENTRY_ADDED (0x0021) + + +/* Log Entry Added Event data */ + +/* the following structure matches MPI2_LOG_0_ENTRY in mpi2_cnfg.h */ +#define MPI2_EVENT_DATA_LOG_DATA_LENGTH (0x1C) + +typedef struct _MPI2_EVENT_DATA_LOG_ENTRY_ADDED +{ + U64 TimeStamp; /* 0x00 */ + U32 Reserved1; /* 0x08 */ + U16 LogSequence; /* 0x0C */ + U16 LogEntryQualifier; /* 0x0E */ + U8 VP_ID; /* 0x10 */ + U8 VF_ID; /* 0x11 */ + U16 Reserved2; /* 0x12 */ + U8 LogData[MPI2_EVENT_DATA_LOG_DATA_LENGTH];/* 0x14 */ +} MPI2_EVENT_DATA_LOG_ENTRY_ADDED, + MPI2_POINTER PTR_MPI2_EVENT_DATA_LOG_ENTRY_ADDED, + Mpi2EventDataLogEntryAdded_t, MPI2_POINTER pMpi2EventDataLogEntryAdded_t; + +/* Hard Reset Received Event data */ + +typedef struct _MPI2_EVENT_DATA_HARD_RESET_RECEIVED +{ + U8 Reserved1; /* 0x00 */ + U8 Port; /* 0x01 */ + U16 Reserved2; /* 0x02 */ +} MPI2_EVENT_DATA_HARD_RESET_RECEIVED, + MPI2_POINTER PTR_MPI2_EVENT_DATA_HARD_RESET_RECEIVED, + Mpi2EventDataHardResetReceived_t, + MPI2_POINTER pMpi2EventDataHardResetReceived_t; + +/* Task Set Full Event data */ + +typedef struct _MPI2_EVENT_DATA_TASK_SET_FULL +{ + U16 DevHandle; /* 0x00 */ + U16 CurrentDepth; /* 0x02 */ +} MPI2_EVENT_DATA_TASK_SET_FULL, MPI2_POINTER PTR_MPI2_EVENT_DATA_TASK_SET_FULL, + Mpi2EventDataTaskSetFull_t, MPI2_POINTER pMpi2EventDataTaskSetFull_t; + + +/* SAS Device Status Change Event data */ + +typedef struct _MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE +{ + U16 TaskTag; /* 0x00 */ + U8 ReasonCode; /* 0x02 */ + U8 Reserved1; /* 0x03 */ + U8 ASC; /* 0x04 */ + U8 ASCQ; /* 0x05 */ + U16 DevHandle; /* 0x06 */ + U32 Reserved2; /* 0x08 */ + U64 SASAddress; /* 0x0C */ + U8 LUN[8]; /* 0x14 */ +} MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE, + MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE, + Mpi2EventDataSasDeviceStatusChange_t, + MPI2_POINTER pMpi2EventDataSasDeviceStatusChange_t; + +/* SAS Device Status Change Event data ReasonCode values */ +#define MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA (0x05) +#define MPI2_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED (0x07) +#define MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET (0x08) +#define MPI2_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL (0x09) +#define MPI2_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL (0x0A) +#define MPI2_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL (0x0B) +#define MPI2_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL (0x0C) +#define MPI2_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION (0x0D) +#define MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET (0x0E) +#define MPI2_EVENT_SAS_DEV_STAT_RC_CMP_TASK_ABORT_INTERNAL (0x0F) +#define MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE (0x10) + + +/* Integrated RAID Operation Status Event data */ + +typedef struct _MPI2_EVENT_DATA_IR_OPERATION_STATUS +{ + U16 VolDevHandle; /* 0x00 */ + U16 Reserved1; /* 0x02 */ + U8 RAIDOperation; /* 0x04 */ + U8 PercentComplete; /* 0x05 */ + U16 Reserved2; /* 0x06 */ + U32 Resereved3; /* 0x08 */ +} MPI2_EVENT_DATA_IR_OPERATION_STATUS, + MPI2_POINTER PTR_MPI2_EVENT_DATA_IR_OPERATION_STATUS, + Mpi2EventDataIrOperationStatus_t, + MPI2_POINTER pMpi2EventDataIrOperationStatus_t; + +/* Integrated RAID Operation Status Event data RAIDOperation values */ +#define MPI2_EVENT_IR_RAIDOP_RESYNC (0x00) +#define MPI2_EVENT_IR_RAIDOP_ONLINE_CAP_EXPANSION (0x01) +#define MPI2_EVENT_IR_RAIDOP_CONSISTENCY_CHECK (0x02) +#define MPI2_EVENT_IR_RAIDOP_BACKGROUND_INIT (0x03) +#define MPI2_EVENT_IR_RAIDOP_MAKE_DATA_CONSISTENT (0x04) + + +/* Integrated RAID Volume Event data */ + +typedef struct _MPI2_EVENT_DATA_IR_VOLUME +{ + U16 VolDevHandle; /* 0x00 */ + U8 ReasonCode; /* 0x02 */ + U8 Reserved1; /* 0x03 */ + U32 NewValue; /* 0x04 */ + U32 PreviousValue; /* 0x08 */ +} MPI2_EVENT_DATA_IR_VOLUME, MPI2_POINTER PTR_MPI2_EVENT_DATA_IR_VOLUME, + Mpi2EventDataIrVolume_t, MPI2_POINTER pMpi2EventDataIrVolume_t; + +/* Integrated RAID Volume Event data ReasonCode values */ +#define MPI2_EVENT_IR_VOLUME_RC_SETTINGS_CHANGED (0x01) +#define MPI2_EVENT_IR_VOLUME_RC_STATUS_FLAGS_CHANGED (0x02) +#define MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED (0x03) + + +/* Integrated RAID Physical Disk Event data */ + +typedef struct _MPI2_EVENT_DATA_IR_PHYSICAL_DISK +{ + U16 Reserved1; /* 0x00 */ + U8 ReasonCode; /* 0x02 */ + U8 PhysDiskNum; /* 0x03 */ + U16 PhysDiskDevHandle; /* 0x04 */ + U16 Reserved2; /* 0x06 */ + U16 Slot; /* 0x08 */ + U16 EnclosureHandle; /* 0x0A */ + U32 NewValue; /* 0x0C */ + U32 PreviousValue; /* 0x10 */ +} MPI2_EVENT_DATA_IR_PHYSICAL_DISK, + MPI2_POINTER PTR_MPI2_EVENT_DATA_IR_PHYSICAL_DISK, + Mpi2EventDataIrPhysicalDisk_t, MPI2_POINTER pMpi2EventDataIrPhysicalDisk_t; + +/* Integrated RAID Physical Disk Event data ReasonCode values */ +#define MPI2_EVENT_IR_PHYSDISK_RC_SETTINGS_CHANGED (0x01) +#define MPI2_EVENT_IR_PHYSDISK_RC_STATUS_FLAGS_CHANGED (0x02) +#define MPI2_EVENT_IR_PHYSDISK_RC_STATE_CHANGED (0x03) + + +/* Integrated RAID Configuration Change List Event data */ + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check NumElements at runtime. + */ +#ifndef MPI2_EVENT_IR_CONFIG_ELEMENT_COUNT +#define MPI2_EVENT_IR_CONFIG_ELEMENT_COUNT (1) +#endif + +typedef struct _MPI2_EVENT_IR_CONFIG_ELEMENT +{ + U16 ElementFlags; /* 0x00 */ + U16 VolDevHandle; /* 0x02 */ + U8 ReasonCode; /* 0x04 */ + U8 PhysDiskNum; /* 0x05 */ + U16 PhysDiskDevHandle; /* 0x06 */ +} MPI2_EVENT_IR_CONFIG_ELEMENT, MPI2_POINTER PTR_MPI2_EVENT_IR_CONFIG_ELEMENT, + Mpi2EventIrConfigElement_t, MPI2_POINTER pMpi2EventIrConfigElement_t; + +/* IR Configuration Change List Event data ElementFlags values */ +#define MPI2_EVENT_IR_CHANGE_EFLAGS_ELEMENT_TYPE_MASK (0x000F) +#define MPI2_EVENT_IR_CHANGE_EFLAGS_VOLUME_ELEMENT (0x0000) +#define MPI2_EVENT_IR_CHANGE_EFLAGS_VOLPHYSDISK_ELEMENT (0x0001) +#define MPI2_EVENT_IR_CHANGE_EFLAGS_HOTSPARE_ELEMENT (0x0002) + +/* IR Configuration Change List Event data ReasonCode values */ +#define MPI2_EVENT_IR_CHANGE_RC_ADDED (0x01) +#define MPI2_EVENT_IR_CHANGE_RC_REMOVED (0x02) +#define MPI2_EVENT_IR_CHANGE_RC_NO_CHANGE (0x03) +#define MPI2_EVENT_IR_CHANGE_RC_HIDE (0x04) +#define MPI2_EVENT_IR_CHANGE_RC_UNHIDE (0x05) +#define MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED (0x06) +#define MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED (0x07) +#define MPI2_EVENT_IR_CHANGE_RC_PD_CREATED (0x08) +#define MPI2_EVENT_IR_CHANGE_RC_PD_DELETED (0x09) + +typedef struct _MPI2_EVENT_DATA_IR_CONFIG_CHANGE_LIST +{ + U8 NumElements; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 Reserved2; /* 0x02 */ + U8 ConfigNum; /* 0x03 */ + U32 Flags; /* 0x04 */ + MPI2_EVENT_IR_CONFIG_ELEMENT ConfigElement[MPI2_EVENT_IR_CONFIG_ELEMENT_COUNT]; /* 0x08 */ +} MPI2_EVENT_DATA_IR_CONFIG_CHANGE_LIST, + MPI2_POINTER PTR_MPI2_EVENT_DATA_IR_CONFIG_CHANGE_LIST, + Mpi2EventDataIrConfigChangeList_t, + MPI2_POINTER pMpi2EventDataIrConfigChangeList_t; + +/* IR Configuration Change List Event data Flags values */ +#define MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG (0x00000001) + + +/* SAS Discovery Event data */ + +typedef struct _MPI2_EVENT_DATA_SAS_DISCOVERY +{ + U8 Flags; /* 0x00 */ + U8 ReasonCode; /* 0x01 */ + U8 PhysicalPort; /* 0x02 */ + U8 Reserved1; /* 0x03 */ + U32 DiscoveryStatus; /* 0x04 */ +} MPI2_EVENT_DATA_SAS_DISCOVERY, + MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_DISCOVERY, + Mpi2EventDataSasDiscovery_t, MPI2_POINTER pMpi2EventDataSasDiscovery_t; + +/* SAS Discovery Event data Flags values */ +#define MPI2_EVENT_SAS_DISC_DEVICE_CHANGE (0x02) +#define MPI2_EVENT_SAS_DISC_IN_PROGRESS (0x01) + +/* SAS Discovery Event data ReasonCode values */ +#define MPI2_EVENT_SAS_DISC_RC_STARTED (0x01) +#define MPI2_EVENT_SAS_DISC_RC_COMPLETED (0x02) + +/* SAS Discovery Event data DiscoveryStatus values */ +#define MPI2_EVENT_SAS_DISC_DS_MAX_ENCLOSURES_EXCEED (0x80000000) +#define MPI2_EVENT_SAS_DISC_DS_MAX_EXPANDERS_EXCEED (0x40000000) +#define MPI2_EVENT_SAS_DISC_DS_MAX_DEVICES_EXCEED (0x20000000) +#define MPI2_EVENT_SAS_DISC_DS_MAX_TOPO_PHYS_EXCEED (0x10000000) +#define MPI2_EVENT_SAS_DISC_DS_DOWNSTREAM_INITIATOR (0x08000000) +#define MPI2_EVENT_SAS_DISC_DS_MULTI_SUBTRACTIVE_SUBTRACTIVE (0x00008000) +#define MPI2_EVENT_SAS_DISC_DS_EXP_MULTI_SUBTRACTIVE (0x00004000) +#define MPI2_EVENT_SAS_DISC_DS_MULTI_PORT_DOMAIN (0x00002000) +#define MPI2_EVENT_SAS_DISC_DS_TABLE_TO_SUBTRACTIVE_LINK (0x00001000) +#define MPI2_EVENT_SAS_DISC_DS_UNSUPPORTED_DEVICE (0x00000800) +#define MPI2_EVENT_SAS_DISC_DS_TABLE_LINK (0x00000400) +#define MPI2_EVENT_SAS_DISC_DS_SUBTRACTIVE_LINK (0x00000200) +#define MPI2_EVENT_SAS_DISC_DS_SMP_CRC_ERROR (0x00000100) +#define MPI2_EVENT_SAS_DISC_DS_SMP_FUNCTION_FAILED (0x00000080) +#define MPI2_EVENT_SAS_DISC_DS_INDEX_NOT_EXIST (0x00000040) +#define MPI2_EVENT_SAS_DISC_DS_OUT_ROUTE_ENTRIES (0x00000020) +#define MPI2_EVENT_SAS_DISC_DS_SMP_TIMEOUT (0x00000010) +#define MPI2_EVENT_SAS_DISC_DS_MULTIPLE_PORTS (0x00000004) +#define MPI2_EVENT_SAS_DISC_DS_UNADDRESSABLE_DEVICE (0x00000002) +#define MPI2_EVENT_SAS_DISC_DS_LOOP_DETECTED (0x00000001) + + +/* SAS Broadcast Primitive Event data */ + +typedef struct _MPI2_EVENT_DATA_SAS_BROADCAST_PRIMITIVE +{ + U8 PhyNum; /* 0x00 */ + U8 Port; /* 0x01 */ + U8 PortWidth; /* 0x02 */ + U8 Primitive; /* 0x03 */ +} MPI2_EVENT_DATA_SAS_BROADCAST_PRIMITIVE, + MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_BROADCAST_PRIMITIVE, + Mpi2EventDataSasBroadcastPrimitive_t, + MPI2_POINTER pMpi2EventDataSasBroadcastPrimitive_t; + +/* defines for the Primitive field */ +#define MPI2_EVENT_PRIMITIVE_CHANGE (0x01) +#define MPI2_EVENT_PRIMITIVE_SES (0x02) +#define MPI2_EVENT_PRIMITIVE_EXPANDER (0x03) +#define MPI2_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT (0x04) +#define MPI2_EVENT_PRIMITIVE_RESERVED3 (0x05) +#define MPI2_EVENT_PRIMITIVE_RESERVED4 (0x06) +#define MPI2_EVENT_PRIMITIVE_CHANGE0_RESERVED (0x07) +#define MPI2_EVENT_PRIMITIVE_CHANGE1_RESERVED (0x08) + + +/* SAS Initiator Device Status Change Event data */ + +typedef struct _MPI2_EVENT_DATA_SAS_INIT_DEV_STATUS_CHANGE +{ + U8 ReasonCode; /* 0x00 */ + U8 PhysicalPort; /* 0x01 */ + U16 DevHandle; /* 0x02 */ + U64 SASAddress; /* 0x04 */ +} MPI2_EVENT_DATA_SAS_INIT_DEV_STATUS_CHANGE, + MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_INIT_DEV_STATUS_CHANGE, + Mpi2EventDataSasInitDevStatusChange_t, + MPI2_POINTER pMpi2EventDataSasInitDevStatusChange_t; + +/* SAS Initiator Device Status Change event ReasonCode values */ +#define MPI2_EVENT_SAS_INIT_RC_ADDED (0x01) +#define MPI2_EVENT_SAS_INIT_RC_NOT_RESPONDING (0x02) + + +/* SAS Initiator Device Table Overflow Event data */ + +typedef struct _MPI2_EVENT_DATA_SAS_INIT_TABLE_OVERFLOW +{ + U16 MaxInit; /* 0x00 */ + U16 CurrentInit; /* 0x02 */ + U64 SASAddress; /* 0x04 */ +} MPI2_EVENT_DATA_SAS_INIT_TABLE_OVERFLOW, + MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_INIT_TABLE_OVERFLOW, + Mpi2EventDataSasInitTableOverflow_t, + MPI2_POINTER pMpi2EventDataSasInitTableOverflow_t; + + +/* SAS Topology Change List Event data */ + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check NumEntries at runtime. + */ +#ifndef MPI2_EVENT_SAS_TOPO_PHY_COUNT +#define MPI2_EVENT_SAS_TOPO_PHY_COUNT (1) +#endif + +typedef struct _MPI2_EVENT_SAS_TOPO_PHY_ENTRY +{ + U16 AttachedDevHandle; /* 0x00 */ + U8 LinkRate; /* 0x02 */ + U8 PhyStatus; /* 0x03 */ +} MPI2_EVENT_SAS_TOPO_PHY_ENTRY, MPI2_POINTER PTR_MPI2_EVENT_SAS_TOPO_PHY_ENTRY, + Mpi2EventSasTopoPhyEntry_t, MPI2_POINTER pMpi2EventSasTopoPhyEntry_t; + +typedef struct _MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST +{ + U16 EnclosureHandle; /* 0x00 */ + U16 ExpanderDevHandle; /* 0x02 */ + U8 NumPhys; /* 0x04 */ + U8 Reserved1; /* 0x05 */ + U16 Reserved2; /* 0x06 */ + U8 NumEntries; /* 0x08 */ + U8 StartPhyNum; /* 0x09 */ + U8 ExpStatus; /* 0x0A */ + U8 PhysicalPort; /* 0x0B */ + MPI2_EVENT_SAS_TOPO_PHY_ENTRY PHY[MPI2_EVENT_SAS_TOPO_PHY_COUNT]; /* 0x0C*/ +} MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST, + MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST, + Mpi2EventDataSasTopologyChangeList_t, + MPI2_POINTER pMpi2EventDataSasTopologyChangeList_t; + +/* values for the ExpStatus field */ +#define MPI2_EVENT_SAS_TOPO_ES_ADDED (0x01) +#define MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING (0x02) +#define MPI2_EVENT_SAS_TOPO_ES_RESPONDING (0x03) +#define MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING (0x04) + +/* defines for the LinkRate field */ +#define MPI2_EVENT_SAS_TOPO_LR_CURRENT_MASK (0xF0) +#define MPI2_EVENT_SAS_TOPO_LR_CURRENT_SHIFT (4) +#define MPI2_EVENT_SAS_TOPO_LR_PREV_MASK (0x0F) +#define MPI2_EVENT_SAS_TOPO_LR_PREV_SHIFT (0) + +#define MPI2_EVENT_SAS_TOPO_LR_UNKNOWN_LINK_RATE (0x00) +#define MPI2_EVENT_SAS_TOPO_LR_PHY_DISABLED (0x01) +#define MPI2_EVENT_SAS_TOPO_LR_NEGOTIATION_FAILED (0x02) +#define MPI2_EVENT_SAS_TOPO_LR_SATA_OOB_COMPLETE (0x03) +#define MPI2_EVENT_SAS_TOPO_LR_PORT_SELECTOR (0x04) +#define MPI2_EVENT_SAS_TOPO_LR_SMP_RESET_IN_PROGRESS (0x05) +#define MPI2_EVENT_SAS_TOPO_LR_RATE_1_5 (0x08) +#define MPI2_EVENT_SAS_TOPO_LR_RATE_3_0 (0x09) +#define MPI2_EVENT_SAS_TOPO_LR_RATE_6_0 (0x0A) + +/* values for the PhyStatus field */ +#define MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT (0x80) +#define MPI2_EVENT_SAS_TOPO_PS_MULTIPLEX_CHANGE (0x10) +/* values for the PhyStatus ReasonCode sub-field */ +#define MPI2_EVENT_SAS_TOPO_RC_MASK (0x0F) +#define MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED (0x01) +#define MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING (0x02) +#define MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED (0x03) +#define MPI2_EVENT_SAS_TOPO_RC_NO_CHANGE (0x04) +#define MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING (0x05) + + +/* SAS Enclosure Device Status Change Event data */ + +typedef struct _MPI2_EVENT_DATA_SAS_ENCL_DEV_STATUS_CHANGE +{ + U16 EnclosureHandle; /* 0x00 */ + U8 ReasonCode; /* 0x02 */ + U8 PhysicalPort; /* 0x03 */ + U64 EnclosureLogicalID; /* 0x04 */ + U16 NumSlots; /* 0x0C */ + U16 StartSlot; /* 0x0E */ + U32 PhyBits; /* 0x10 */ +} MPI2_EVENT_DATA_SAS_ENCL_DEV_STATUS_CHANGE, + MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_ENCL_DEV_STATUS_CHANGE, + Mpi2EventDataSasEnclDevStatusChange_t, + MPI2_POINTER pMpi2EventDataSasEnclDevStatusChange_t; + +/* SAS Enclosure Device Status Change event ReasonCode values */ +#define MPI2_EVENT_SAS_ENCL_RC_ADDED (0x01) +#define MPI2_EVENT_SAS_ENCL_RC_NOT_RESPONDING (0x02) + + +/**************************************************************************** +* EventAck message +****************************************************************************/ + +/* EventAck Request message */ +typedef struct _MPI2_EVENT_ACK_REQUEST +{ + U16 Reserved1; /* 0x00 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U16 Event; /* 0x0C */ + U16 Reserved5; /* 0x0E */ + U32 EventContext; /* 0x10 */ +} MPI2_EVENT_ACK_REQUEST, MPI2_POINTER PTR_MPI2_EVENT_ACK_REQUEST, + Mpi2EventAckRequest_t, MPI2_POINTER pMpi2EventAckRequest_t; + + +/* EventAck Reply message */ +typedef struct _MPI2_EVENT_ACK_REPLY +{ + U16 Reserved1; /* 0x00 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U16 Reserved5; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ +} MPI2_EVENT_ACK_REPLY, MPI2_POINTER PTR_MPI2_EVENT_ACK_REPLY, + Mpi2EventAckReply_t, MPI2_POINTER pMpi2EventAckReply_t; + + +/**************************************************************************** +* FWDownload message +****************************************************************************/ + +/* FWDownload Request message */ +typedef struct _MPI2_FW_DOWNLOAD_REQUEST +{ + U8 ImageType; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U32 TotalImageSize; /* 0x0C */ + U32 Reserved5; /* 0x10 */ + MPI2_MPI_SGE_UNION SGL; /* 0x14 */ +} MPI2_FW_DOWNLOAD_REQUEST, MPI2_POINTER PTR_MPI2_FW_DOWNLOAD_REQUEST, + Mpi2FWDownloadRequest, MPI2_POINTER pMpi2FWDownloadRequest; + +#define MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT (0x01) + +#define MPI2_FW_DOWNLOAD_ITYPE_FW (0x01) +#define MPI2_FW_DOWNLOAD_ITYPE_BIOS (0x02) +#define MPI2_FW_DOWNLOAD_ITYPE_MANUFACTURING (0x06) +#define MPI2_FW_DOWNLOAD_ITYPE_CONFIG_1 (0x07) +#define MPI2_FW_DOWNLOAD_ITYPE_CONFIG_2 (0x08) +#define MPI2_FW_DOWNLOAD_ITYPE_MEGARAID (0x09) +#define MPI2_FW_DOWNLOAD_ITYPE_COMMON_BOOT_BLOCK (0x0B) + +/* FWDownload TransactionContext Element */ +typedef struct _MPI2_FW_DOWNLOAD_TCSGE +{ + U8 Reserved1; /* 0x00 */ + U8 ContextSize; /* 0x01 */ + U8 DetailsLength; /* 0x02 */ + U8 Flags; /* 0x03 */ + U32 Reserved2; /* 0x04 */ + U32 ImageOffset; /* 0x08 */ + U32 ImageSize; /* 0x0C */ +} MPI2_FW_DOWNLOAD_TCSGE, MPI2_POINTER PTR_MPI2_FW_DOWNLOAD_TCSGE, + Mpi2FWDownloadTCSGE_t, MPI2_POINTER pMpi2FWDownloadTCSGE_t; + +/* FWDownload Reply message */ +typedef struct _MPI2_FW_DOWNLOAD_REPLY +{ + U8 ImageType; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U16 Reserved5; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ +} MPI2_FW_DOWNLOAD_REPLY, MPI2_POINTER PTR_MPI2_FW_DOWNLOAD_REPLY, + Mpi2FWDownloadReply_t, MPI2_POINTER pMpi2FWDownloadReply_t; + + +/**************************************************************************** +* FWUpload message +****************************************************************************/ + +/* FWUpload Request message */ +typedef struct _MPI2_FW_UPLOAD_REQUEST +{ + U8 ImageType; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U32 Reserved5; /* 0x0C */ + U32 Reserved6; /* 0x10 */ + MPI2_MPI_SGE_UNION SGL; /* 0x14 */ +} MPI2_FW_UPLOAD_REQUEST, MPI2_POINTER PTR_MPI2_FW_UPLOAD_REQUEST, + Mpi2FWUploadRequest_t, MPI2_POINTER pMpi2FWUploadRequest_t; + +#define MPI2_FW_UPLOAD_ITYPE_FW_CURRENT (0x00) +#define MPI2_FW_UPLOAD_ITYPE_FW_FLASH (0x01) +#define MPI2_FW_UPLOAD_ITYPE_BIOS_FLASH (0x02) +#define MPI2_FW_UPLOAD_ITYPE_FW_BACKUP (0x05) +#define MPI2_FW_UPLOAD_ITYPE_MANUFACTURING (0x06) +#define MPI2_FW_UPLOAD_ITYPE_CONFIG_1 (0x07) +#define MPI2_FW_UPLOAD_ITYPE_CONFIG_2 (0x08) +#define MPI2_FW_UPLOAD_ITYPE_MEGARAID (0x09) +#define MPI2_FW_UPLOAD_ITYPE_COMPLETE (0x0A) +#define MPI2_FW_UPLOAD_ITYPE_COMMON_BOOT_BLOCK (0x0B) + +typedef struct _MPI2_FW_UPLOAD_TCSGE +{ + U8 Reserved1; /* 0x00 */ + U8 ContextSize; /* 0x01 */ + U8 DetailsLength; /* 0x02 */ + U8 Flags; /* 0x03 */ + U32 Reserved2; /* 0x04 */ + U32 ImageOffset; /* 0x08 */ + U32 ImageSize; /* 0x0C */ +} MPI2_FW_UPLOAD_TCSGE, MPI2_POINTER PTR_MPI2_FW_UPLOAD_TCSGE, + Mpi2FWUploadTCSGE_t, MPI2_POINTER pMpi2FWUploadTCSGE_t; + +/* FWUpload Reply message */ +typedef struct _MPI2_FW_UPLOAD_REPLY +{ + U8 ImageType; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U16 Reserved5; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ + U32 ActualImageSize; /* 0x14 */ +} MPI2_FW_UPLOAD_REPLY, MPI2_POINTER PTR_MPI2_FW_UPLOAD_REPLY, + Mpi2FWUploadReply_t, MPI2_POINTER pMPi2FWUploadReply_t; + + +/* FW Image Header */ +typedef struct _MPI2_FW_IMAGE_HEADER +{ + U32 Signature; /* 0x00 */ + U32 Signature0; /* 0x04 */ + U32 Signature1; /* 0x08 */ + U32 Signature2; /* 0x0C */ + MPI2_VERSION_UNION MPIVersion; /* 0x10 */ + MPI2_VERSION_UNION FWVersion; /* 0x14 */ + MPI2_VERSION_UNION NVDATAVersion; /* 0x18 */ + MPI2_VERSION_UNION PackageVersion; /* 0x1C */ + U16 VendorID; /* 0x20 */ + U16 ProductID; /* 0x22 */ + U16 ProtocolFlags; /* 0x24 */ + U16 Reserved26; /* 0x26 */ + U32 IOCCapabilities; /* 0x28 */ + U32 ImageSize; /* 0x2C */ + U32 NextImageHeaderOffset; /* 0x30 */ + U32 Checksum; /* 0x34 */ + U32 Reserved38; /* 0x38 */ + U32 Reserved3C; /* 0x3C */ + U32 Reserved40; /* 0x40 */ + U32 Reserved44; /* 0x44 */ + U32 Reserved48; /* 0x48 */ + U32 Reserved4C; /* 0x4C */ + U32 Reserved50; /* 0x50 */ + U32 Reserved54; /* 0x54 */ + U32 Reserved58; /* 0x58 */ + U32 Reserved5C; /* 0x5C */ + U32 Reserved60; /* 0x60 */ + U32 FirmwareVersionNameWhat; /* 0x64 */ + U8 FirmwareVersionName[32]; /* 0x68 */ + U32 VendorNameWhat; /* 0x88 */ + U8 VendorName[32]; /* 0x8C */ + U32 PackageNameWhat; /* 0x88 */ + U8 PackageName[32]; /* 0x8C */ + U32 ReservedD0; /* 0xD0 */ + U32 ReservedD4; /* 0xD4 */ + U32 ReservedD8; /* 0xD8 */ + U32 ReservedDC; /* 0xDC */ + U32 ReservedE0; /* 0xE0 */ + U32 ReservedE4; /* 0xE4 */ + U32 ReservedE8; /* 0xE8 */ + U32 ReservedEC; /* 0xEC */ + U32 ReservedF0; /* 0xF0 */ + U32 ReservedF4; /* 0xF4 */ + U32 ReservedF8; /* 0xF8 */ + U32 ReservedFC; /* 0xFC */ +} MPI2_FW_IMAGE_HEADER, MPI2_POINTER PTR_MPI2_FW_IMAGE_HEADER, + Mpi2FWImageHeader_t, MPI2_POINTER pMpi2FWImageHeader_t; + +/* Signature field */ +#define MPI2_FW_HEADER_SIGNATURE_OFFSET (0x00) +#define MPI2_FW_HEADER_SIGNATURE_MASK (0xFF000000) +#define MPI2_FW_HEADER_SIGNATURE (0xEA000000) + +/* Signature0 field */ +#define MPI2_FW_HEADER_SIGNATURE0_OFFSET (0x04) +#define MPI2_FW_HEADER_SIGNATURE0 (0x5AFAA55A) + +/* Signature1 field */ +#define MPI2_FW_HEADER_SIGNATURE1_OFFSET (0x08) +#define MPI2_FW_HEADER_SIGNATURE1 (0xA55AFAA5) + +/* Signature2 field */ +#define MPI2_FW_HEADER_SIGNATURE2_OFFSET (0x0C) +#define MPI2_FW_HEADER_SIGNATURE2 (0x5AA55AFA) + + +/* defines for using the ProductID field */ +#define MPI2_FW_HEADER_PID_TYPE_MASK (0xF000) +#define MPI2_FW_HEADER_PID_TYPE_SAS (0x2000) + +#define MPI2_FW_HEADER_PID_PROD_MASK (0x0F00) +#define MPI2_FW_HEADER_PID_PROD_A (0x0000) + +#define MPI2_FW_HEADER_PID_FAMILY_MASK (0x00FF) +/* SAS */ +#define MPI2_FW_HEADER_PID_FAMILY_2108_SAS (0x0010) + +/* use MPI2_IOCFACTS_PROTOCOL_ defines for ProtocolFlags field */ + +/* use MPI2_IOCFACTS_CAPABILITY_ defines for IOCCapabilities field */ + + +#define MPI2_FW_HEADER_IMAGESIZE_OFFSET (0x2C) +#define MPI2_FW_HEADER_NEXTIMAGE_OFFSET (0x30) +#define MPI2_FW_HEADER_VERNMHWAT_OFFSET (0x64) + +#define MPI2_FW_HEADER_WHAT_SIGNATURE (0x29232840) + +#define MPI2_FW_HEADER_SIZE (0x100) + + +/* Extended Image Header */ +typedef struct _MPI2_EXT_IMAGE_HEADER + +{ + U8 ImageType; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U16 Reserved2; /* 0x02 */ + U32 Checksum; /* 0x04 */ + U32 ImageSize; /* 0x08 */ + U32 NextImageHeaderOffset; /* 0x0C */ + U32 PackageVersion; /* 0x10 */ + U32 Reserved3; /* 0x14 */ + U32 Reserved4; /* 0x18 */ + U32 Reserved5; /* 0x1C */ + U8 IdentifyString[32]; /* 0x20 */ +} MPI2_EXT_IMAGE_HEADER, MPI2_POINTER PTR_MPI2_EXT_IMAGE_HEADER, + Mpi2ExtImageHeader_t, MPI2_POINTER pMpi2ExtImageHeader_t; + +/* useful offsets */ +#define MPI2_EXT_IMAGE_IMAGETYPE_OFFSET (0x00) +#define MPI2_EXT_IMAGE_IMAGESIZE_OFFSET (0x08) +#define MPI2_EXT_IMAGE_NEXTIMAGE_OFFSET (0x0C) + +#define MPI2_EXT_IMAGE_HEADER_SIZE (0x40) + +/* defines for the ImageType field */ +#define MPI2_EXT_IMAGE_TYPE_UNSPECIFIED (0x00) +#define MPI2_EXT_IMAGE_TYPE_FW (0x01) +#define MPI2_EXT_IMAGE_TYPE_NVDATA (0x03) +#define MPI2_EXT_IMAGE_TYPE_BOOTLOADER (0x04) +#define MPI2_EXT_IMAGE_TYPE_INITIALIZATION (0x05) +#define MPI2_EXT_IMAGE_TYPE_FLASH_LAYOUT (0x06) +#define MPI2_EXT_IMAGE_TYPE_SUPPORTED_DEVICES (0x07) +#define MPI2_EXT_IMAGE_TYPE_MEGARAID (0x08) + +#define MPI2_EXT_IMAGE_TYPE_MAX (MPI2_EXT_IMAGE_TYPE_MEGARAID) + + + +/* FLASH Layout Extended Image Data */ + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check RegionsPerLayout at runtime. + */ +#ifndef MPI2_FLASH_NUMBER_OF_REGIONS +#define MPI2_FLASH_NUMBER_OF_REGIONS (1) +#endif + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check NumberOfLayouts at runtime. + */ +#ifndef MPI2_FLASH_NUMBER_OF_LAYOUTS +#define MPI2_FLASH_NUMBER_OF_LAYOUTS (1) +#endif + +typedef struct _MPI2_FLASH_REGION +{ + U8 RegionType; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U16 Reserved2; /* 0x02 */ + U32 RegionOffset; /* 0x04 */ + U32 RegionSize; /* 0x08 */ + U32 Reserved3; /* 0x0C */ +} MPI2_FLASH_REGION, MPI2_POINTER PTR_MPI2_FLASH_REGION, + Mpi2FlashRegion_t, MPI2_POINTER pMpi2FlashRegion_t; + +typedef struct _MPI2_FLASH_LAYOUT +{ + U32 FlashSize; /* 0x00 */ + U32 Reserved1; /* 0x04 */ + U32 Reserved2; /* 0x08 */ + U32 Reserved3; /* 0x0C */ + MPI2_FLASH_REGION Region[MPI2_FLASH_NUMBER_OF_REGIONS];/* 0x10 */ +} MPI2_FLASH_LAYOUT, MPI2_POINTER PTR_MPI2_FLASH_LAYOUT, + Mpi2FlashLayout_t, MPI2_POINTER pMpi2FlashLayout_t; + +typedef struct _MPI2_FLASH_LAYOUT_DATA +{ + U8 ImageRevision; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 SizeOfRegion; /* 0x02 */ + U8 Reserved2; /* 0x03 */ + U16 NumberOfLayouts; /* 0x04 */ + U16 RegionsPerLayout; /* 0x06 */ + U16 MinimumSectorAlignment; /* 0x08 */ + U16 Reserved3; /* 0x0A */ + U32 Reserved4; /* 0x0C */ + MPI2_FLASH_LAYOUT Layout[MPI2_FLASH_NUMBER_OF_LAYOUTS];/* 0x10 */ +} MPI2_FLASH_LAYOUT_DATA, MPI2_POINTER PTR_MPI2_FLASH_LAYOUT_DATA, + Mpi2FlashLayoutData_t, MPI2_POINTER pMpi2FlashLayoutData_t; + +/* defines for the RegionType field */ +#define MPI2_FLASH_REGION_UNUSED (0x00) +#define MPI2_FLASH_REGION_FIRMWARE (0x01) +#define MPI2_FLASH_REGION_BIOS (0x02) +#define MPI2_FLASH_REGION_NVDATA (0x03) +#define MPI2_FLASH_REGION_FIRMWARE_BACKUP (0x05) +#define MPI2_FLASH_REGION_MFG_INFORMATION (0x06) +#define MPI2_FLASH_REGION_CONFIG_1 (0x07) +#define MPI2_FLASH_REGION_CONFIG_2 (0x08) +#define MPI2_FLASH_REGION_MEGARAID (0x09) +#define MPI2_FLASH_REGION_INIT (0x0A) + +/* ImageRevision */ +#define MPI2_FLASH_LAYOUT_IMAGE_REVISION (0x00) + + + +/* Supported Devices Extended Image Data */ + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check NumberOfDevices at runtime. + */ +#ifndef MPI2_SUPPORTED_DEVICES_IMAGE_NUM_DEVICES +#define MPI2_SUPPORTED_DEVICES_IMAGE_NUM_DEVICES (1) +#endif + +typedef struct _MPI2_SUPPORTED_DEVICE +{ + U16 DeviceID; /* 0x00 */ + U16 VendorID; /* 0x02 */ + U16 DeviceIDMask; /* 0x04 */ + U16 Reserved1; /* 0x06 */ + U8 LowPCIRev; /* 0x08 */ + U8 HighPCIRev; /* 0x09 */ + U16 Reserved2; /* 0x0A */ + U32 Reserved3; /* 0x0C */ +} MPI2_SUPPORTED_DEVICE, MPI2_POINTER PTR_MPI2_SUPPORTED_DEVICE, + Mpi2SupportedDevice_t, MPI2_POINTER pMpi2SupportedDevice_t; + +typedef struct _MPI2_SUPPORTED_DEVICES_DATA +{ + U8 ImageRevision; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 NumberOfDevices; /* 0x02 */ + U8 Reserved2; /* 0x03 */ + U32 Reserved3; /* 0x04 */ + MPI2_SUPPORTED_DEVICE SupportedDevice[MPI2_SUPPORTED_DEVICES_IMAGE_NUM_DEVICES]; /* 0x08 */ +} MPI2_SUPPORTED_DEVICES_DATA, MPI2_POINTER PTR_MPI2_SUPPORTED_DEVICES_DATA, + Mpi2SupportedDevicesData_t, MPI2_POINTER pMpi2SupportedDevicesData_t; + +/* ImageRevision */ +#define MPI2_SUPPORTED_DEVICES_IMAGE_REVISION (0x00) + + +/* Init Extended Image Data */ + +typedef struct _MPI2_INIT_IMAGE_FOOTER + +{ + U32 BootFlags; /* 0x00 */ + U32 ImageSize; /* 0x04 */ + U32 Signature0; /* 0x08 */ + U32 Signature1; /* 0x0C */ + U32 Signature2; /* 0x10 */ + U32 ResetVector; /* 0x14 */ +} MPI2_INIT_IMAGE_FOOTER, MPI2_POINTER PTR_MPI2_INIT_IMAGE_FOOTER, + Mpi2InitImageFooter_t, MPI2_POINTER pMpi2InitImageFooter_t; + +/* defines for the BootFlags field */ +#define MPI2_INIT_IMAGE_BOOTFLAGS_OFFSET (0x00) + +/* defines for the ImageSize field */ +#define MPI2_INIT_IMAGE_IMAGESIZE_OFFSET (0x04) + +/* defines for the Signature0 field */ +#define MPI2_INIT_IMAGE_SIGNATURE0_OFFSET (0x08) +#define MPI2_INIT_IMAGE_SIGNATURE0 (0x5AA55AEA) + +/* defines for the Signature1 field */ +#define MPI2_INIT_IMAGE_SIGNATURE1_OFFSET (0x0C) +#define MPI2_INIT_IMAGE_SIGNATURE1 (0xA55AEAA5) + +/* defines for the Signature2 field */ +#define MPI2_INIT_IMAGE_SIGNATURE2_OFFSET (0x10) +#define MPI2_INIT_IMAGE_SIGNATURE2 (0x5AEAA55A) + +/* Signature fields as individual bytes */ +#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_0 (0xEA) +#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_1 (0x5A) +#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_2 (0xA5) +#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_3 (0x5A) + +#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_4 (0xA5) +#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_5 (0xEA) +#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_6 (0x5A) +#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_7 (0xA5) + +#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_8 (0x5A) +#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_9 (0xA5) +#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_A (0xEA) +#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_B (0x5A) + +/* defines for the ResetVector field */ +#define MPI2_INIT_IMAGE_RESETVECTOR_OFFSET (0x14) + + +#endif + diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_raid.h b/drivers/scsi/mpt2sas/mpi/mpi2_raid.h new file mode 100644 index 00000000000..7134816d904 --- /dev/null +++ b/drivers/scsi/mpt2sas/mpi/mpi2_raid.h @@ -0,0 +1,295 @@ +/* + * Copyright (c) 2000-2008 LSI Corporation. + * + * + * Name: mpi2_raid.h + * Title: MPI Integrated RAID messages and structures + * Creation Date: April 26, 2007 + * + * mpi2_raid.h Version: 02.00.03 + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * 08-31-07 02.00.01 Modifications to RAID Action request and reply, + * including the Actions and ActionData. + * 02-29-08 02.00.02 Added MPI2_RAID_ACTION_ADATA_DISABL_FULL_REBUILD. + * 05-21-08 02.00.03 Added MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS so that + * the PhysDisk array in MPI2_RAID_VOLUME_CREATION_STRUCT + * can be sized by the build environment. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI2_RAID_H +#define MPI2_RAID_H + +/***************************************************************************** +* +* Integrated RAID Messages +* +*****************************************************************************/ + +/**************************************************************************** +* RAID Action messages +****************************************************************************/ + +/* ActionDataWord defines for use with MPI2_RAID_ACTION_DELETE_VOLUME action */ +#define MPI2_RAID_ACTION_ADATA_KEEP_LBA0 (0x00000000) +#define MPI2_RAID_ACTION_ADATA_ZERO_LBA0 (0x00000001) + +/* use MPI2_RAIDVOL0_SETTING_ defines from mpi2_cnfg.h for MPI2_RAID_ACTION_CHANGE_VOL_WRITE_CACHE action */ + +/* ActionDataWord defines for use with MPI2_RAID_ACTION_DISABLE_ALL_VOLUMES action */ +#define MPI2_RAID_ACTION_ADATA_DISABL_FULL_REBUILD (0x00000001) + +/* ActionDataWord for MPI2_RAID_ACTION_SET_RAID_FUNCTION_RATE Action */ +typedef struct _MPI2_RAID_ACTION_RATE_DATA +{ + U8 RateToChange; /* 0x00 */ + U8 RateOrMode; /* 0x01 */ + U16 DataScrubDuration; /* 0x02 */ +} MPI2_RAID_ACTION_RATE_DATA, MPI2_POINTER PTR_MPI2_RAID_ACTION_RATE_DATA, + Mpi2RaidActionRateData_t, MPI2_POINTER pMpi2RaidActionRateData_t; + +#define MPI2_RAID_ACTION_SET_RATE_RESYNC (0x00) +#define MPI2_RAID_ACTION_SET_RATE_DATA_SCRUB (0x01) +#define MPI2_RAID_ACTION_SET_RATE_POWERSAVE_MODE (0x02) + +/* ActionDataWord for MPI2_RAID_ACTION_START_RAID_FUNCTION Action */ +typedef struct _MPI2_RAID_ACTION_START_RAID_FUNCTION +{ + U8 RAIDFunction; /* 0x00 */ + U8 Flags; /* 0x01 */ + U16 Reserved1; /* 0x02 */ +} MPI2_RAID_ACTION_START_RAID_FUNCTION, + MPI2_POINTER PTR_MPI2_RAID_ACTION_START_RAID_FUNCTION, + Mpi2RaidActionStartRaidFunction_t, + MPI2_POINTER pMpi2RaidActionStartRaidFunction_t; + +/* defines for the RAIDFunction field */ +#define MPI2_RAID_ACTION_START_BACKGROUND_INIT (0x00) +#define MPI2_RAID_ACTION_START_ONLINE_CAP_EXPANSION (0x01) +#define MPI2_RAID_ACTION_START_CONSISTENCY_CHECK (0x02) + +/* defines for the Flags field */ +#define MPI2_RAID_ACTION_START_NEW (0x00) +#define MPI2_RAID_ACTION_START_RESUME (0x01) + +/* ActionDataWord for MPI2_RAID_ACTION_STOP_RAID_FUNCTION Action */ +typedef struct _MPI2_RAID_ACTION_STOP_RAID_FUNCTION +{ + U8 RAIDFunction; /* 0x00 */ + U8 Flags; /* 0x01 */ + U16 Reserved1; /* 0x02 */ +} MPI2_RAID_ACTION_STOP_RAID_FUNCTION, + MPI2_POINTER PTR_MPI2_RAID_ACTION_STOP_RAID_FUNCTION, + Mpi2RaidActionStopRaidFunction_t, + MPI2_POINTER pMpi2RaidActionStopRaidFunction_t; + +/* defines for the RAIDFunction field */ +#define MPI2_RAID_ACTION_STOP_BACKGROUND_INIT (0x00) +#define MPI2_RAID_ACTION_STOP_ONLINE_CAP_EXPANSION (0x01) +#define MPI2_RAID_ACTION_STOP_CONSISTENCY_CHECK (0x02) + +/* defines for the Flags field */ +#define MPI2_RAID_ACTION_STOP_ABORT (0x00) +#define MPI2_RAID_ACTION_STOP_PAUSE (0x01) + +/* ActionDataWord for MPI2_RAID_ACTION_CREATE_HOT_SPARE Action */ +typedef struct _MPI2_RAID_ACTION_HOT_SPARE +{ + U8 HotSparePool; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U16 DevHandle; /* 0x02 */ +} MPI2_RAID_ACTION_HOT_SPARE, MPI2_POINTER PTR_MPI2_RAID_ACTION_HOT_SPARE, + Mpi2RaidActionHotSpare_t, MPI2_POINTER pMpi2RaidActionHotSpare_t; + +/* ActionDataWord for MPI2_RAID_ACTION_DEVICE_FW_UPDATE_MODE Action */ +typedef struct _MPI2_RAID_ACTION_FW_UPDATE_MODE +{ + U8 Flags; /* 0x00 */ + U8 DeviceFirmwareUpdateModeTimeout; /* 0x01 */ + U16 Reserved1; /* 0x02 */ +} MPI2_RAID_ACTION_FW_UPDATE_MODE, + MPI2_POINTER PTR_MPI2_RAID_ACTION_FW_UPDATE_MODE, + Mpi2RaidActionFwUpdateMode_t, MPI2_POINTER pMpi2RaidActionFwUpdateMode_t; + +/* ActionDataWord defines for use with MPI2_RAID_ACTION_DEVICE_FW_UPDATE_MODE action */ +#define MPI2_RAID_ACTION_ADATA_DISABLE_FW_UPDATE (0x00) +#define MPI2_RAID_ACTION_ADATA_ENABLE_FW_UPDATE (0x01) + +typedef union _MPI2_RAID_ACTION_DATA +{ + U32 Word; + MPI2_RAID_ACTION_RATE_DATA Rates; + MPI2_RAID_ACTION_START_RAID_FUNCTION StartRaidFunction; + MPI2_RAID_ACTION_STOP_RAID_FUNCTION StopRaidFunction; + MPI2_RAID_ACTION_HOT_SPARE HotSpare; + MPI2_RAID_ACTION_FW_UPDATE_MODE FwUpdateMode; +} MPI2_RAID_ACTION_DATA, MPI2_POINTER PTR_MPI2_RAID_ACTION_DATA, + Mpi2RaidActionData_t, MPI2_POINTER pMpi2RaidActionData_t; + + +/* RAID Action Request Message */ +typedef struct _MPI2_RAID_ACTION_REQUEST +{ + U8 Action; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 VolDevHandle; /* 0x04 */ + U8 PhysDiskNum; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved2; /* 0x0A */ + U32 Reserved3; /* 0x0C */ + MPI2_RAID_ACTION_DATA ActionDataWord; /* 0x10 */ + MPI2_SGE_SIMPLE_UNION ActionDataSGE; /* 0x14 */ +} MPI2_RAID_ACTION_REQUEST, MPI2_POINTER PTR_MPI2_RAID_ACTION_REQUEST, + Mpi2RaidActionRequest_t, MPI2_POINTER pMpi2RaidActionRequest_t; + +/* RAID Action request Action values */ + +#define MPI2_RAID_ACTION_INDICATOR_STRUCT (0x01) +#define MPI2_RAID_ACTION_CREATE_VOLUME (0x02) +#define MPI2_RAID_ACTION_DELETE_VOLUME (0x03) +#define MPI2_RAID_ACTION_DISABLE_ALL_VOLUMES (0x04) +#define MPI2_RAID_ACTION_ENABLE_ALL_VOLUMES (0x05) +#define MPI2_RAID_ACTION_PHYSDISK_OFFLINE (0x0A) +#define MPI2_RAID_ACTION_PHYSDISK_ONLINE (0x0B) +#define MPI2_RAID_ACTION_FAIL_PHYSDISK (0x0F) +#define MPI2_RAID_ACTION_ACTIVATE_VOLUME (0x11) +#define MPI2_RAID_ACTION_DEVICE_FW_UPDATE_MODE (0x15) +#define MPI2_RAID_ACTION_CHANGE_VOL_WRITE_CACHE (0x17) +#define MPI2_RAID_ACTION_SET_VOLUME_NAME (0x18) +#define MPI2_RAID_ACTION_SET_RAID_FUNCTION_RATE (0x19) +#define MPI2_RAID_ACTION_ENABLE_FAILED_VOLUME (0x1C) +#define MPI2_RAID_ACTION_CREATE_HOT_SPARE (0x1D) +#define MPI2_RAID_ACTION_DELETE_HOT_SPARE (0x1E) +#define MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED (0x20) +#define MPI2_RAID_ACTION_START_RAID_FUNCTION (0x21) +#define MPI2_RAID_ACTION_STOP_RAID_FUNCTION (0x22) + + +/* RAID Volume Creation Structure */ + +/* + * The following define can be customized for the targeted product. + */ +#ifndef MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS +#define MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS (1) +#endif + +typedef struct _MPI2_RAID_VOLUME_PHYSDISK +{ + U8 RAIDSetNum; /* 0x00 */ + U8 PhysDiskMap; /* 0x01 */ + U16 PhysDiskDevHandle; /* 0x02 */ +} MPI2_RAID_VOLUME_PHYSDISK, MPI2_POINTER PTR_MPI2_RAID_VOLUME_PHYSDISK, + Mpi2RaidVolumePhysDisk_t, MPI2_POINTER pMpi2RaidVolumePhysDisk_t; + +/* defines for the PhysDiskMap field */ +#define MPI2_RAIDACTION_PHYSDISK_PRIMARY (0x01) +#define MPI2_RAIDACTION_PHYSDISK_SECONDARY (0x02) + +typedef struct _MPI2_RAID_VOLUME_CREATION_STRUCT +{ + U8 NumPhysDisks; /* 0x00 */ + U8 VolumeType; /* 0x01 */ + U16 Reserved1; /* 0x02 */ + U32 VolumeCreationFlags; /* 0x04 */ + U32 VolumeSettings; /* 0x08 */ + U8 Reserved2; /* 0x0C */ + U8 ResyncRate; /* 0x0D */ + U16 DataScrubDuration; /* 0x0E */ + U64 VolumeMaxLBA; /* 0x10 */ + U32 StripeSize; /* 0x18 */ + U8 Name[16]; /* 0x1C */ + MPI2_RAID_VOLUME_PHYSDISK PhysDisk[MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS];/* 0x2C */ +} MPI2_RAID_VOLUME_CREATION_STRUCT, + MPI2_POINTER PTR_MPI2_RAID_VOLUME_CREATION_STRUCT, + Mpi2RaidVolumeCreationStruct_t, MPI2_POINTER pMpi2RaidVolumeCreationStruct_t; + +/* use MPI2_RAID_VOL_TYPE_ defines from mpi2_cnfg.h for VolumeType */ + +/* defines for the VolumeCreationFlags field */ +#define MPI2_RAID_VOL_CREATION_USE_DEFAULT_SETTINGS (0x80) +#define MPI2_RAID_VOL_CREATION_BACKGROUND_INIT (0x04) +#define MPI2_RAID_VOL_CREATION_LOW_LEVEL_INIT (0x02) +#define MPI2_RAID_VOL_CREATION_MIGRATE_DATA (0x01) + + +/* RAID Online Capacity Expansion Structure */ + +typedef struct _MPI2_RAID_ONLINE_CAPACITY_EXPANSION +{ + U32 Flags; /* 0x00 */ + U16 DevHandle0; /* 0x04 */ + U16 Reserved1; /* 0x06 */ + U16 DevHandle1; /* 0x08 */ + U16 Reserved2; /* 0x0A */ +} MPI2_RAID_ONLINE_CAPACITY_EXPANSION, + MPI2_POINTER PTR_MPI2_RAID_ONLINE_CAPACITY_EXPANSION, + Mpi2RaidOnlineCapacityExpansion_t, + MPI2_POINTER pMpi2RaidOnlineCapacityExpansion_t; + + +/* RAID Volume Indicator Structure */ + +typedef struct _MPI2_RAID_VOL_INDICATOR +{ + U64 TotalBlocks; /* 0x00 */ + U64 BlocksRemaining; /* 0x08 */ + U32 Flags; /* 0x10 */ +} MPI2_RAID_VOL_INDICATOR, MPI2_POINTER PTR_MPI2_RAID_VOL_INDICATOR, + Mpi2RaidVolIndicator_t, MPI2_POINTER pMpi2RaidVolIndicator_t; + +/* defines for RAID Volume Indicator Flags field */ +#define MPI2_RAID_VOL_FLAGS_OP_MASK (0x0000000F) +#define MPI2_RAID_VOL_FLAGS_OP_BACKGROUND_INIT (0x00000000) +#define MPI2_RAID_VOL_FLAGS_OP_ONLINE_CAP_EXPANSION (0x00000001) +#define MPI2_RAID_VOL_FLAGS_OP_CONSISTENCY_CHECK (0x00000002) +#define MPI2_RAID_VOL_FLAGS_OP_RESYNC (0x00000003) + + +/* RAID Action Reply ActionData union */ +typedef union _MPI2_RAID_ACTION_REPLY_DATA +{ + U32 Word[5]; + MPI2_RAID_VOL_INDICATOR RaidVolumeIndicator; + U16 VolDevHandle; + U8 VolumeState; + U8 PhysDiskNum; +} MPI2_RAID_ACTION_REPLY_DATA, MPI2_POINTER PTR_MPI2_RAID_ACTION_REPLY_DATA, + Mpi2RaidActionReplyData_t, MPI2_POINTER pMpi2RaidActionReplyData_t; + +/* use MPI2_RAIDVOL0_SETTING_ defines from mpi2_cnfg.h for MPI2_RAID_ACTION_CHANGE_VOL_WRITE_CACHE action */ + + +/* RAID Action Reply Message */ +typedef struct _MPI2_RAID_ACTION_REPLY +{ + U8 Action; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 VolDevHandle; /* 0x04 */ + U8 PhysDiskNum; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved2; /* 0x0A */ + U16 Reserved3; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ + MPI2_RAID_ACTION_REPLY_DATA ActionData; /* 0x14 */ +} MPI2_RAID_ACTION_REPLY, MPI2_POINTER PTR_MPI2_RAID_ACTION_REPLY, + Mpi2RaidActionReply_t, MPI2_POINTER pMpi2RaidActionReply_t; + + +#endif + diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_sas.h b/drivers/scsi/mpt2sas/mpi/mpi2_sas.h new file mode 100644 index 00000000000..8a42b136cf5 --- /dev/null +++ b/drivers/scsi/mpt2sas/mpi/mpi2_sas.h @@ -0,0 +1,282 @@ +/* + * Copyright (c) 2000-2007 LSI Corporation. + * + * + * Name: mpi2_sas.h + * Title: MPI Serial Attached SCSI structures and definitions + * Creation Date: February 9, 2007 + * + * mpi2.h Version: 02.00.02 + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * 06-26-07 02.00.01 Added Clear All Persistent Operation to SAS IO Unit + * Control Request. + * 10-02-08 02.00.02 Added Set IOC Parameter Operation to SAS IO Unit Control + * Request. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI2_SAS_H +#define MPI2_SAS_H + +/* + * Values for SASStatus. + */ +#define MPI2_SASSTATUS_SUCCESS (0x00) +#define MPI2_SASSTATUS_UNKNOWN_ERROR (0x01) +#define MPI2_SASSTATUS_INVALID_FRAME (0x02) +#define MPI2_SASSTATUS_UTC_BAD_DEST (0x03) +#define MPI2_SASSTATUS_UTC_BREAK_RECEIVED (0x04) +#define MPI2_SASSTATUS_UTC_CONNECT_RATE_NOT_SUPPORTED (0x05) +#define MPI2_SASSTATUS_UTC_PORT_LAYER_REQUEST (0x06) +#define MPI2_SASSTATUS_UTC_PROTOCOL_NOT_SUPPORTED (0x07) +#define MPI2_SASSTATUS_UTC_STP_RESOURCES_BUSY (0x08) +#define MPI2_SASSTATUS_UTC_WRONG_DESTINATION (0x09) +#define MPI2_SASSTATUS_SHORT_INFORMATION_UNIT (0x0A) +#define MPI2_SASSTATUS_LONG_INFORMATION_UNIT (0x0B) +#define MPI2_SASSTATUS_XFER_RDY_INCORRECT_WRITE_DATA (0x0C) +#define MPI2_SASSTATUS_XFER_RDY_REQUEST_OFFSET_ERROR (0x0D) +#define MPI2_SASSTATUS_XFER_RDY_NOT_EXPECTED (0x0E) +#define MPI2_SASSTATUS_DATA_INCORRECT_DATA_LENGTH (0x0F) +#define MPI2_SASSTATUS_DATA_TOO_MUCH_READ_DATA (0x10) +#define MPI2_SASSTATUS_DATA_OFFSET_ERROR (0x11) +#define MPI2_SASSTATUS_SDSF_NAK_RECEIVED (0x12) +#define MPI2_SASSTATUS_SDSF_CONNECTION_FAILED (0x13) +#define MPI2_SASSTATUS_INITIATOR_RESPONSE_TIMEOUT (0x14) + + +/* + * Values for the SAS DeviceInfo field used in SAS Device Status Change Event + * data and SAS Configuration pages. + */ +#define MPI2_SAS_DEVICE_INFO_SEP (0x00004000) +#define MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE (0x00002000) +#define MPI2_SAS_DEVICE_INFO_LSI_DEVICE (0x00001000) +#define MPI2_SAS_DEVICE_INFO_DIRECT_ATTACH (0x00000800) +#define MPI2_SAS_DEVICE_INFO_SSP_TARGET (0x00000400) +#define MPI2_SAS_DEVICE_INFO_STP_TARGET (0x00000200) +#define MPI2_SAS_DEVICE_INFO_SMP_TARGET (0x00000100) +#define MPI2_SAS_DEVICE_INFO_SATA_DEVICE (0x00000080) +#define MPI2_SAS_DEVICE_INFO_SSP_INITIATOR (0x00000040) +#define MPI2_SAS_DEVICE_INFO_STP_INITIATOR (0x00000020) +#define MPI2_SAS_DEVICE_INFO_SMP_INITIATOR (0x00000010) +#define MPI2_SAS_DEVICE_INFO_SATA_HOST (0x00000008) + +#define MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE (0x00000007) +#define MPI2_SAS_DEVICE_INFO_NO_DEVICE (0x00000000) +#define MPI2_SAS_DEVICE_INFO_END_DEVICE (0x00000001) +#define MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER (0x00000002) +#define MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER (0x00000003) + + +/***************************************************************************** +* +* SAS Messages +* +*****************************************************************************/ + +/**************************************************************************** +* SMP Passthrough messages +****************************************************************************/ + +/* SMP Passthrough Request Message */ +typedef struct _MPI2_SMP_PASSTHROUGH_REQUEST +{ + U8 PassthroughFlags; /* 0x00 */ + U8 PhysicalPort; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 RequestDataLength; /* 0x04 */ + U8 SGLFlags; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved1; /* 0x0A */ + U32 Reserved2; /* 0x0C */ + U64 SASAddress; /* 0x10 */ + U32 Reserved3; /* 0x18 */ + U32 Reserved4; /* 0x1C */ + MPI2_SIMPLE_SGE_UNION SGL; /* 0x20 */ +} MPI2_SMP_PASSTHROUGH_REQUEST, MPI2_POINTER PTR_MPI2_SMP_PASSTHROUGH_REQUEST, + Mpi2SmpPassthroughRequest_t, MPI2_POINTER pMpi2SmpPassthroughRequest_t; + +/* values for PassthroughFlags field */ +#define MPI2_SMP_PT_REQ_PT_FLAGS_IMMEDIATE (0x80) + +/* values for SGLFlags field are in the SGL section of mpi2.h */ + + +/* SMP Passthrough Reply Message */ +typedef struct _MPI2_SMP_PASSTHROUGH_REPLY +{ + U8 PassthroughFlags; /* 0x00 */ + U8 PhysicalPort; /* 0x01 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 ResponseDataLength; /* 0x04 */ + U8 SGLFlags; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved1; /* 0x0A */ + U8 Reserved2; /* 0x0C */ + U8 SASStatus; /* 0x0D */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ + U32 Reserved3; /* 0x14 */ + U8 ResponseData[4]; /* 0x18 */ +} MPI2_SMP_PASSTHROUGH_REPLY, MPI2_POINTER PTR_MPI2_SMP_PASSTHROUGH_REPLY, + Mpi2SmpPassthroughReply_t, MPI2_POINTER pMpi2SmpPassthroughReply_t; + +/* values for PassthroughFlags field */ +#define MPI2_SMP_PT_REPLY_PT_FLAGS_IMMEDIATE (0x80) + +/* values for SASStatus field are at the top of this file */ + + +/**************************************************************************** +* SATA Passthrough messages +****************************************************************************/ + +/* SATA Passthrough Request Message */ +typedef struct _MPI2_SATA_PASSTHROUGH_REQUEST +{ + U16 DevHandle; /* 0x00 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 PassthroughFlags; /* 0x04 */ + U8 SGLFlags; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved1; /* 0x0A */ + U32 Reserved2; /* 0x0C */ + U32 Reserved3; /* 0x10 */ + U32 Reserved4; /* 0x14 */ + U32 DataLength; /* 0x18 */ + U8 CommandFIS[20]; /* 0x1C */ + MPI2_SIMPLE_SGE_UNION SGL; /* 0x20 */ +} MPI2_SATA_PASSTHROUGH_REQUEST, MPI2_POINTER PTR_MPI2_SATA_PASSTHROUGH_REQUEST, + Mpi2SataPassthroughRequest_t, MPI2_POINTER pMpi2SataPassthroughRequest_t; + +/* values for PassthroughFlags field */ +#define MPI2_SATA_PT_REQ_PT_FLAGS_EXECUTE_DIAG (0x0100) +#define MPI2_SATA_PT_REQ_PT_FLAGS_DMA (0x0020) +#define MPI2_SATA_PT_REQ_PT_FLAGS_PIO (0x0010) +#define MPI2_SATA_PT_REQ_PT_FLAGS_UNSPECIFIED_VU (0x0004) +#define MPI2_SATA_PT_REQ_PT_FLAGS_WRITE (0x0002) +#define MPI2_SATA_PT_REQ_PT_FLAGS_READ (0x0001) + +/* values for SGLFlags field are in the SGL section of mpi2.h */ + + +/* SATA Passthrough Reply Message */ +typedef struct _MPI2_SATA_PASSTHROUGH_REPLY +{ + U16 DevHandle; /* 0x00 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 PassthroughFlags; /* 0x04 */ + U8 SGLFlags; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved1; /* 0x0A */ + U8 Reserved2; /* 0x0C */ + U8 SASStatus; /* 0x0D */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ + U8 StatusFIS[20]; /* 0x14 */ + U32 StatusControlRegisters; /* 0x28 */ + U32 TransferCount; /* 0x2C */ +} MPI2_SATA_PASSTHROUGH_REPLY, MPI2_POINTER PTR_MPI2_SATA_PASSTHROUGH_REPLY, + Mpi2SataPassthroughReply_t, MPI2_POINTER pMpi2SataPassthroughReply_t; + +/* values for SASStatus field are at the top of this file */ + + +/**************************************************************************** +* SAS IO Unit Control messages +****************************************************************************/ + +/* SAS IO Unit Control Request Message */ +typedef struct _MPI2_SAS_IOUNIT_CONTROL_REQUEST +{ + U8 Operation; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 DevHandle; /* 0x04 */ + U8 IOCParameter; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved3; /* 0x0A */ + U16 Reserved4; /* 0x0C */ + U8 PhyNum; /* 0x0E */ + U8 PrimFlags; /* 0x0F */ + U32 Primitive; /* 0x10 */ + U8 LookupMethod; /* 0x14 */ + U8 Reserved5; /* 0x15 */ + U16 SlotNumber; /* 0x16 */ + U64 LookupAddress; /* 0x18 */ + U32 IOCParameterValue; /* 0x20 */ + U32 Reserved7; /* 0x24 */ + U32 Reserved8; /* 0x28 */ +} MPI2_SAS_IOUNIT_CONTROL_REQUEST, + MPI2_POINTER PTR_MPI2_SAS_IOUNIT_CONTROL_REQUEST, + Mpi2SasIoUnitControlRequest_t, MPI2_POINTER pMpi2SasIoUnitControlRequest_t; + +/* values for the Operation field */ +#define MPI2_SAS_OP_CLEAR_ALL_PERSISTENT (0x02) +#define MPI2_SAS_OP_PHY_LINK_RESET (0x06) +#define MPI2_SAS_OP_PHY_HARD_RESET (0x07) +#define MPI2_SAS_OP_PHY_CLEAR_ERROR_LOG (0x08) +#define MPI2_SAS_OP_SEND_PRIMITIVE (0x0A) +#define MPI2_SAS_OP_FORCE_FULL_DISCOVERY (0x0B) +#define MPI2_SAS_OP_TRANSMIT_PORT_SELECT_SIGNAL (0x0C) +#define MPI2_SAS_OP_REMOVE_DEVICE (0x0D) +#define MPI2_SAS_OP_LOOKUP_MAPPING (0x0E) +#define MPI2_SAS_OP_SET_IOC_PARAMETER (0x0F) +#define MPI2_SAS_OP_PRODUCT_SPECIFIC_MIN (0x80) + +/* values for the PrimFlags field */ +#define MPI2_SAS_PRIMFLAGS_SINGLE (0x08) +#define MPI2_SAS_PRIMFLAGS_TRIPLE (0x02) +#define MPI2_SAS_PRIMFLAGS_REDUNDANT (0x01) + +/* values for the LookupMethod field */ +#define MPI2_SAS_LOOKUP_METHOD_SAS_ADDRESS (0x01) +#define MPI2_SAS_LOOKUP_METHOD_SAS_ENCLOSURE_SLOT (0x02) +#define MPI2_SAS_LOOKUP_METHOD_SAS_DEVICE_NAME (0x03) + + +/* SAS IO Unit Control Reply Message */ +typedef struct _MPI2_SAS_IOUNIT_CONTROL_REPLY +{ + U8 Operation; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 DevHandle; /* 0x04 */ + U8 IOCParameter; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved3; /* 0x0A */ + U16 Reserved4; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ +} MPI2_SAS_IOUNIT_CONTROL_REPLY, + MPI2_POINTER PTR_MPI2_SAS_IOUNIT_CONTROL_REPLY, + Mpi2SasIoUnitControlReply_t, MPI2_POINTER pMpi2SasIoUnitControlReply_t; + + +#endif + + diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_tool.h b/drivers/scsi/mpt2sas/mpi/mpi2_tool.h new file mode 100644 index 00000000000..2ff4e936bd3 --- /dev/null +++ b/drivers/scsi/mpt2sas/mpi/mpi2_tool.h @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2000-2008 LSI Corporation. + * + * + * Name: mpi2_tool.h + * Title: MPI diagnostic tool structures and definitions + * Creation Date: March 26, 2007 + * + * mpi2_tool.h Version: 02.00.02 + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * 12-18-07 02.00.01 Added Diagnostic Buffer Post and Diagnostic Release + * structures and defines. + * 02-29-08 02.00.02 Modified various names to make them 32-character unique. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI2_TOOL_H +#define MPI2_TOOL_H + +/***************************************************************************** +* +* Toolbox Messages +* +*****************************************************************************/ + +/* defines for the Tools */ +#define MPI2_TOOLBOX_CLEAN_TOOL (0x00) +#define MPI2_TOOLBOX_MEMORY_MOVE_TOOL (0x01) +#define MPI2_TOOLBOX_BEACON_TOOL (0x05) + +/**************************************************************************** +* Toolbox reply +****************************************************************************/ + +typedef struct _MPI2_TOOLBOX_REPLY +{ + U8 Tool; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U16 Reserved5; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ +} MPI2_TOOLBOX_REPLY, MPI2_POINTER PTR_MPI2_TOOLBOX_REPLY, + Mpi2ToolboxReply_t, MPI2_POINTER pMpi2ToolboxReply_t; + + +/**************************************************************************** +* Toolbox Clean Tool request +****************************************************************************/ + +typedef struct _MPI2_TOOLBOX_CLEAN_REQUEST +{ + U8 Tool; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U32 Flags; /* 0x0C */ + } MPI2_TOOLBOX_CLEAN_REQUEST, MPI2_POINTER PTR_MPI2_TOOLBOX_CLEAN_REQUEST, + Mpi2ToolboxCleanRequest_t, MPI2_POINTER pMpi2ToolboxCleanRequest_t; + +/* values for the Flags field */ +#define MPI2_TOOLBOX_CLEAN_BOOT_SERVICES (0x80000000) +#define MPI2_TOOLBOX_CLEAN_PERSIST_MANUFACT_PAGES (0x40000000) +#define MPI2_TOOLBOX_CLEAN_OTHER_PERSIST_PAGES (0x20000000) +#define MPI2_TOOLBOX_CLEAN_FW_CURRENT (0x10000000) +#define MPI2_TOOLBOX_CLEAN_FW_BACKUP (0x08000000) +#define MPI2_TOOLBOX_CLEAN_MEGARAID (0x02000000) +#define MPI2_TOOLBOX_CLEAN_INITIALIZATION (0x01000000) +#define MPI2_TOOLBOX_CLEAN_FLASH (0x00000004) +#define MPI2_TOOLBOX_CLEAN_SEEPROM (0x00000002) +#define MPI2_TOOLBOX_CLEAN_NVSRAM (0x00000001) + + +/**************************************************************************** +* Toolbox Memory Move request +****************************************************************************/ + +typedef struct _MPI2_TOOLBOX_MEM_MOVE_REQUEST +{ + U8 Tool; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + MPI2_SGE_SIMPLE_UNION SGL; /* 0x0C */ +} MPI2_TOOLBOX_MEM_MOVE_REQUEST, MPI2_POINTER PTR_MPI2_TOOLBOX_MEM_MOVE_REQUEST, + Mpi2ToolboxMemMoveRequest_t, MPI2_POINTER pMpi2ToolboxMemMoveRequest_t; + + +/**************************************************************************** +* Toolbox Beacon Tool request +****************************************************************************/ + +typedef struct _MPI2_TOOLBOX_BEACON_REQUEST +{ + U8 Tool; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U8 Reserved5; /* 0x0C */ + U8 PhysicalPort; /* 0x0D */ + U8 Reserved6; /* 0x0E */ + U8 Flags; /* 0x0F */ +} MPI2_TOOLBOX_BEACON_REQUEST, MPI2_POINTER PTR_MPI2_TOOLBOX_BEACON_REQUEST, + Mpi2ToolboxBeaconRequest_t, MPI2_POINTER pMpi2ToolboxBeaconRequest_t; + +/* values for the Flags field */ +#define MPI2_TOOLBOX_FLAGS_BEACONMODE_OFF (0x00) +#define MPI2_TOOLBOX_FLAGS_BEACONMODE_ON (0x01) + + +/***************************************************************************** +* +* Diagnostic Buffer Messages +* +*****************************************************************************/ + + +/**************************************************************************** +* Diagnostic Buffer Post request +****************************************************************************/ + +typedef struct _MPI2_DIAG_BUFFER_POST_REQUEST +{ + U8 Reserved1; /* 0x00 */ + U8 BufferType; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U64 BufferAddress; /* 0x0C */ + U32 BufferLength; /* 0x14 */ + U32 Reserved5; /* 0x18 */ + U32 Reserved6; /* 0x1C */ + U32 Flags; /* 0x20 */ + U32 ProductSpecific[23]; /* 0x24 */ +} MPI2_DIAG_BUFFER_POST_REQUEST, MPI2_POINTER PTR_MPI2_DIAG_BUFFER_POST_REQUEST, + Mpi2DiagBufferPostRequest_t, MPI2_POINTER pMpi2DiagBufferPostRequest_t; + +/* values for the BufferType field */ +#define MPI2_DIAG_BUF_TYPE_TRACE (0x00) +#define MPI2_DIAG_BUF_TYPE_SNAPSHOT (0x01) +/* count of the number of buffer types */ +#define MPI2_DIAG_BUF_TYPE_COUNT (0x02) + + +/**************************************************************************** +* Diagnostic Buffer Post reply +****************************************************************************/ + +typedef struct _MPI2_DIAG_BUFFER_POST_REPLY +{ + U8 Reserved1; /* 0x00 */ + U8 BufferType; /* 0x01 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U16 Reserved5; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ + U32 TransferLength; /* 0x14 */ +} MPI2_DIAG_BUFFER_POST_REPLY, MPI2_POINTER PTR_MPI2_DIAG_BUFFER_POST_REPLY, + Mpi2DiagBufferPostReply_t, MPI2_POINTER pMpi2DiagBufferPostReply_t; + + +/**************************************************************************** +* Diagnostic Release request +****************************************************************************/ + +typedef struct _MPI2_DIAG_RELEASE_REQUEST +{ + U8 Reserved1; /* 0x00 */ + U8 BufferType; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ +} MPI2_DIAG_RELEASE_REQUEST, MPI2_POINTER PTR_MPI2_DIAG_RELEASE_REQUEST, + Mpi2DiagReleaseRequest_t, MPI2_POINTER pMpi2DiagReleaseRequest_t; + + +/**************************************************************************** +* Diagnostic Buffer Post reply +****************************************************************************/ + +typedef struct _MPI2_DIAG_RELEASE_REPLY +{ + U8 Reserved1; /* 0x00 */ + U8 BufferType; /* 0x01 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U16 Reserved5; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ +} MPI2_DIAG_RELEASE_REPLY, MPI2_POINTER PTR_MPI2_DIAG_RELEASE_REPLY, + Mpi2DiagReleaseReply_t, MPI2_POINTER pMpi2DiagReleaseReply_t; + + +#endif + diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_type.h b/drivers/scsi/mpt2sas/mpi/mpi2_type.h new file mode 100644 index 00000000000..cfde017bf16 --- /dev/null +++ b/drivers/scsi/mpt2sas/mpi/mpi2_type.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2000-2007 LSI Corporation. + * + * + * Name: mpi2_type.h + * Title: MPI basic type definitions + * Creation Date: August 16, 2006 + * + * mpi2_type.h Version: 02.00.00 + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI2_TYPE_H +#define MPI2_TYPE_H + + +/******************************************************************************* + * Define MPI2_POINTER if it hasn't already been defined. By default + * MPI2_POINTER is defined to be a near pointer. MPI2_POINTER can be defined as + * a far pointer by defining MPI2_POINTER as "far *" before this header file is + * included. + */ +#ifndef MPI2_POINTER +#define MPI2_POINTER * +#endif + +/* the basic types may have already been included by mpi_type.h */ +#ifndef MPI_TYPE_H +/***************************************************************************** +* +* Basic Types +* +*****************************************************************************/ + +typedef u8 U8; +typedef __le16 U16; +typedef __le32 U32; +typedef __le64 U64 __attribute__((aligned(4))); + +/***************************************************************************** +* +* Pointer Types +* +*****************************************************************************/ + +typedef U8 *PU8; +typedef U16 *PU16; +typedef U32 *PU32; +typedef U64 *PU64; + +#endif + +#endif + diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c new file mode 100644 index 00000000000..52427a8324f --- /dev/null +++ b/drivers/scsi/mpt2sas/mpt2sas_base.c @@ -0,0 +1,3435 @@ +/* + * This is the Fusion MPT base driver providing common API layer interface + * for access to MPT (Message Passing Technology) firmware. + * + * This code is based on drivers/scsi/mpt2sas/mpt2_base.c + * Copyright (C) 2007-2008 LSI Corporation + * (mailto:DL-MPTFusionLinux@lsi.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. + * + * NO WARRANTY + * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT + * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is + * solely responsible for determining the appropriateness of using and + * distributing the Program and assumes all risks associated with its + * exercise of rights under this Agreement, including but not limited to + * the risks and costs of program errors, damage to or loss of data, + * programs or equipment, and unavailability or interruption of operations. + + * DISCLAIMER OF LIABILITY + * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED + * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES + + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ + +#include <linux/version.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/kdev_t.h> +#include <linux/blkdev.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/dma-mapping.h> +#include <linux/sort.h> +#include <linux/io.h> + +#include "mpt2sas_base.h" + +static MPT_CALLBACK mpt_callbacks[MPT_MAX_CALLBACKS]; + +#define FAULT_POLLING_INTERVAL 1000 /* in milliseconds */ +#define MPT2SAS_MAX_REQUEST_QUEUE 500 /* maximum controller queue depth */ + +static int max_queue_depth = -1; +module_param(max_queue_depth, int, 0); +MODULE_PARM_DESC(max_queue_depth, " max controller queue depth "); + +static int max_sgl_entries = -1; +module_param(max_sgl_entries, int, 0); +MODULE_PARM_DESC(max_sgl_entries, " max sg entries "); + +static int msix_disable = -1; +module_param(msix_disable, int, 0); +MODULE_PARM_DESC(msix_disable, " disable msix routed interrupts (default=0)"); + +/** + * _base_fault_reset_work - workq handling ioc fault conditions + * @work: input argument, used to derive ioc + * Context: sleep. + * + * Return nothing. + */ +static void +_base_fault_reset_work(struct work_struct *work) +{ + struct MPT2SAS_ADAPTER *ioc = + container_of(work, struct MPT2SAS_ADAPTER, fault_reset_work.work); + unsigned long flags; + u32 doorbell; + int rc; + + spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); + if (ioc->ioc_reset_in_progress) + goto rearm_timer; + spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); + + doorbell = mpt2sas_base_get_iocstate(ioc, 0); + if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) { + rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, + FORCE_BIG_HAMMER); + printk(MPT2SAS_WARN_FMT "%s: hard reset: %s\n", ioc->name, + __func__, (rc == 0) ? "success" : "failed"); + doorbell = mpt2sas_base_get_iocstate(ioc, 0); + if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) + mpt2sas_base_fault_info(ioc, doorbell & + MPI2_DOORBELL_DATA_MASK); + } + + spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); + rearm_timer: + if (ioc->fault_reset_work_q) + queue_delayed_work(ioc->fault_reset_work_q, + &ioc->fault_reset_work, + msecs_to_jiffies(FAULT_POLLING_INTERVAL)); + spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); +} + +#ifdef CONFIG_SCSI_MPT2SAS_LOGGING +/** + * _base_sas_ioc_info - verbose translation of the ioc status + * @ioc: pointer to scsi command object + * @mpi_reply: reply mf payload returned from firmware + * @request_hdr: request mf + * + * Return nothing. + */ +static void +_base_sas_ioc_info(struct MPT2SAS_ADAPTER *ioc, MPI2DefaultReply_t *mpi_reply, + MPI2RequestHeader_t *request_hdr) +{ + u16 ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & + MPI2_IOCSTATUS_MASK; + char *desc = NULL; + u16 frame_sz; + char *func_str = NULL; + + /* SCSI_IO, RAID_PASS are handled from _scsih_scsi_ioc_info */ + if (request_hdr->Function == MPI2_FUNCTION_SCSI_IO_REQUEST || + request_hdr->Function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH || + request_hdr->Function == MPI2_FUNCTION_EVENT_NOTIFICATION) + return; + + switch (ioc_status) { + +/**************************************************************************** +* Common IOCStatus values for all replies +****************************************************************************/ + + case MPI2_IOCSTATUS_INVALID_FUNCTION: + desc = "invalid function"; + break; + case MPI2_IOCSTATUS_BUSY: + desc = "busy"; + break; + case MPI2_IOCSTATUS_INVALID_SGL: + desc = "invalid sgl"; + break; + case MPI2_IOCSTATUS_INTERNAL_ERROR: + desc = "internal error"; + break; + case MPI2_IOCSTATUS_INVALID_VPID: + desc = "invalid vpid"; + break; + case MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES: + desc = "insufficient resources"; + break; + case MPI2_IOCSTATUS_INVALID_FIELD: + desc = "invalid field"; + break; + case MPI2_IOCSTATUS_INVALID_STATE: + desc = "invalid state"; + break; + case MPI2_IOCSTATUS_OP_STATE_NOT_SUPPORTED: + desc = "op state not supported"; + break; + +/**************************************************************************** +* Config IOCStatus values +****************************************************************************/ + + case MPI2_IOCSTATUS_CONFIG_INVALID_ACTION: + desc = "config invalid action"; + break; + case MPI2_IOCSTATUS_CONFIG_INVALID_TYPE: + desc = "config invalid type"; + break; + case MPI2_IOCSTATUS_CONFIG_INVALID_PAGE: + desc = "config invalid page"; + break; + case MPI2_IOCSTATUS_CONFIG_INVALID_DATA: + desc = "config invalid data"; + break; + case MPI2_IOCSTATUS_CONFIG_NO_DEFAULTS: + desc = "config no defaults"; + break; + case MPI2_IOCSTATUS_CONFIG_CANT_COMMIT: + desc = "config cant commit"; + break; + +/**************************************************************************** +* SCSI IO Reply +****************************************************************************/ + + case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR: + case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE: + case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE: + case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN: + case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN: + case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR: + case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR: + case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED: + case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: + case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED: + case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED: + case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED: + break; + +/**************************************************************************** +* For use by SCSI Initiator and SCSI Target end-to-end data protection +****************************************************************************/ + + case MPI2_IOCSTATUS_EEDP_GUARD_ERROR: + desc = "eedp guard error"; + break; + case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR: + desc = "eedp ref tag error"; + break; + case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR: + desc = "eedp app tag error"; + break; + +/**************************************************************************** +* SCSI Target values +****************************************************************************/ + + case MPI2_IOCSTATUS_TARGET_INVALID_IO_INDEX: + desc = "target invalid io index"; + break; + case MPI2_IOCSTATUS_TARGET_ABORTED: + desc = "target aborted"; + break; + case MPI2_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: + desc = "target no conn retryable"; + break; + case MPI2_IOCSTATUS_TARGET_NO_CONNECTION: + desc = "target no connection"; + break; + case MPI2_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: + desc = "target xfer count mismatch"; + break; + case MPI2_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: + desc = "target data offset error"; + break; + case MPI2_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: + desc = "target too much write data"; + break; + case MPI2_IOCSTATUS_TARGET_IU_TOO_SHORT: + desc = "target iu too short"; + break; + case MPI2_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: + desc = "target ack nak timeout"; + break; + case MPI2_IOCSTATUS_TARGET_NAK_RECEIVED: + desc = "target nak received"; + break; + +/**************************************************************************** +* Serial Attached SCSI values +****************************************************************************/ + + case MPI2_IOCSTATUS_SAS_SMP_REQUEST_FAILED: + desc = "smp request failed"; + break; + case MPI2_IOCSTATUS_SAS_SMP_DATA_OVERRUN: + desc = "smp data overrun"; + break; + +/**************************************************************************** +* Diagnostic Buffer Post / Diagnostic Release values +****************************************************************************/ + + case MPI2_IOCSTATUS_DIAGNOSTIC_RELEASED: + desc = "diagnostic released"; + break; + default: + break; + } + + if (!desc) + return; + + switch (request_hdr->Function) { + case MPI2_FUNCTION_CONFIG: + frame_sz = sizeof(Mpi2ConfigRequest_t) + ioc->sge_size; + func_str = "config_page"; + break; + case MPI2_FUNCTION_SCSI_TASK_MGMT: + frame_sz = sizeof(Mpi2SCSITaskManagementRequest_t); + func_str = "task_mgmt"; + break; + case MPI2_FUNCTION_SAS_IO_UNIT_CONTROL: + frame_sz = sizeof(Mpi2SasIoUnitControlRequest_t); + func_str = "sas_iounit_ctl"; + break; + case MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR: + frame_sz = sizeof(Mpi2SepRequest_t); + func_str = "enclosure"; + break; + case MPI2_FUNCTION_IOC_INIT: + frame_sz = sizeof(Mpi2IOCInitRequest_t); + func_str = "ioc_init"; + break; + case MPI2_FUNCTION_PORT_ENABLE: + frame_sz = sizeof(Mpi2PortEnableRequest_t); + func_str = "port_enable"; + break; + case MPI2_FUNCTION_SMP_PASSTHROUGH: + frame_sz = sizeof(Mpi2SmpPassthroughRequest_t) + ioc->sge_size; + func_str = "smp_passthru"; + break; + default: + frame_sz = 32; + func_str = "unknown"; + break; + } + + printk(MPT2SAS_WARN_FMT "ioc_status: %s(0x%04x), request(0x%p)," + " (%s)\n", ioc->name, desc, ioc_status, request_hdr, func_str); + + _debug_dump_mf(request_hdr, frame_sz/4); +} + +/** + * _base_display_event_data - verbose translation of firmware asyn events + * @ioc: pointer to scsi command object + * @mpi_reply: reply mf payload returned from firmware + * + * Return nothing. + */ +static void +_base_display_event_data(struct MPT2SAS_ADAPTER *ioc, + Mpi2EventNotificationReply_t *mpi_reply) +{ + char *desc = NULL; + u16 event; + + if (!(ioc->logging_level & MPT_DEBUG_EVENTS)) + return; + + event = le16_to_cpu(mpi_reply->Event); + + switch (event) { + case MPI2_EVENT_LOG_DATA: + desc = "Log Data"; + break; + case MPI2_EVENT_STATE_CHANGE: + desc = "Status Change"; + break; + case MPI2_EVENT_HARD_RESET_RECEIVED: + desc = "Hard Reset Received"; + break; + case MPI2_EVENT_EVENT_CHANGE: + desc = "Event Change"; + break; + case MPI2_EVENT_TASK_SET_FULL: + desc = "Task Set Full"; + break; + case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE: + desc = "Device Status Change"; + break; + case MPI2_EVENT_IR_OPERATION_STATUS: + desc = "IR Operation Status"; + break; + case MPI2_EVENT_SAS_DISCOVERY: + desc = "Discovery"; + break; + case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE: + desc = "SAS Broadcast Primitive"; + break; + case MPI2_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE: + desc = "SAS Init Device Status Change"; + break; + case MPI2_EVENT_SAS_INIT_TABLE_OVERFLOW: + desc = "SAS Init Table Overflow"; + break; + case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST: + desc = "SAS Topology Change List"; + break; + case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE: + desc = "SAS Enclosure Device Status Change"; + break; + case MPI2_EVENT_IR_VOLUME: + desc = "IR Volume"; + break; + case MPI2_EVENT_IR_PHYSICAL_DISK: + desc = "IR Physical Disk"; + break; + case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST: + desc = "IR Configuration Change List"; + break; + case MPI2_EVENT_LOG_ENTRY_ADDED: + desc = "Log Entry Added"; + break; + } + + if (!desc) + return; + + printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, desc); +} +#endif + +/** + * _base_sas_log_info - verbose translation of firmware log info + * @ioc: pointer to scsi command object + * @log_info: log info + * + * Return nothing. + */ +static void +_base_sas_log_info(struct MPT2SAS_ADAPTER *ioc , u32 log_info) +{ + union loginfo_type { + u32 loginfo; + struct { + u32 subcode:16; + u32 code:8; + u32 originator:4; + u32 bus_type:4; + } dw; + }; + union loginfo_type sas_loginfo; + char *originator_str = NULL; + + sas_loginfo.loginfo = log_info; + if (sas_loginfo.dw.bus_type != 3 /*SAS*/) + return; + + /* eat the loginfos associated with task aborts */ + if (ioc->ignore_loginfos && (log_info == 30050000 || log_info == + 0x31140000 || log_info == 0x31130000)) + return; + + switch (sas_loginfo.dw.originator) { + case 0: + originator_str = "IOP"; + break; + case 1: + originator_str = "PL"; + break; + case 2: + originator_str = "IR"; + break; + } + + printk(MPT2SAS_WARN_FMT "log_info(0x%08x): originator(%s), " + "code(0x%02x), sub_code(0x%04x)\n", ioc->name, log_info, + originator_str, sas_loginfo.dw.code, + sas_loginfo.dw.subcode); +} + +/** + * mpt2sas_base_fault_info - verbose translation of firmware FAULT code + * @ioc: pointer to scsi command object + * @fault_code: fault code + * + * Return nothing. + */ +void +mpt2sas_base_fault_info(struct MPT2SAS_ADAPTER *ioc , u16 fault_code) +{ + printk(MPT2SAS_ERR_FMT "fault_state(0x%04x)!\n", + ioc->name, fault_code); +} + +/** + * _base_display_reply_info - + * @ioc: pointer to scsi command object + * @smid: system request message index + * @VF_ID: virtual function id + * @reply: reply message frame(lower 32bit addr) + * + * Return nothing. + */ +static void +_base_display_reply_info(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, + u32 reply) +{ + MPI2DefaultReply_t *mpi_reply; + u16 ioc_status; + + mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); + ioc_status = le16_to_cpu(mpi_reply->IOCStatus); +#ifdef CONFIG_SCSI_MPT2SAS_LOGGING + if ((ioc_status & MPI2_IOCSTATUS_MASK) && + (ioc->logging_level & MPT_DEBUG_REPLY)) { + _base_sas_ioc_info(ioc , mpi_reply, + mpt2sas_base_get_msg_frame(ioc, smid)); + } +#endif + if (ioc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) + _base_sas_log_info(ioc, le32_to_cpu(mpi_reply->IOCLogInfo)); +} + +/** + * mpt2sas_base_done - base internal command completion routine + * @ioc: pointer to scsi command object + * @smid: system request message index + * @VF_ID: virtual function id + * @reply: reply message frame(lower 32bit addr) + * + * Return nothing. + */ +void +mpt2sas_base_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply) +{ + MPI2DefaultReply_t *mpi_reply; + + mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); + if (mpi_reply && mpi_reply->Function == MPI2_FUNCTION_EVENT_ACK) + return; + + if (ioc->base_cmds.status == MPT2_CMD_NOT_USED) + return; + + ioc->base_cmds.status |= MPT2_CMD_COMPLETE; + if (mpi_reply) { + ioc->base_cmds.status |= MPT2_CMD_REPLY_VALID; + memcpy(ioc->base_cmds.reply, mpi_reply, mpi_reply->MsgLength*4); + } + ioc->base_cmds.status &= ~MPT2_CMD_PENDING; + complete(&ioc->base_cmds.done); +} + +/** + * _base_async_event - main callback handler for firmware asyn events + * @ioc: pointer to scsi command object + * @VF_ID: virtual function id + * @reply: reply message frame(lower 32bit addr) + * + * Return nothing. + */ +static void +_base_async_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply) +{ + Mpi2EventNotificationReply_t *mpi_reply; + Mpi2EventAckRequest_t *ack_request; + u16 smid; + + mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); + if (!mpi_reply) + return; + if (mpi_reply->Function != MPI2_FUNCTION_EVENT_NOTIFICATION) + return; +#ifdef CONFIG_SCSI_MPT2SAS_LOGGING + _base_display_event_data(ioc, mpi_reply); +#endif + if (!(mpi_reply->AckRequired & MPI2_EVENT_NOTIFICATION_ACK_REQUIRED)) + goto out; + smid = mpt2sas_base_get_smid(ioc, ioc->base_cb_idx); + if (!smid) { + printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", + ioc->name, __func__); + goto out; + } + + ack_request = mpt2sas_base_get_msg_frame(ioc, smid); + memset(ack_request, 0, sizeof(Mpi2EventAckRequest_t)); + ack_request->Function = MPI2_FUNCTION_EVENT_ACK; + ack_request->Event = mpi_reply->Event; + ack_request->EventContext = mpi_reply->EventContext; + ack_request->VF_ID = VF_ID; + mpt2sas_base_put_smid_default(ioc, smid, VF_ID); + + out: + + /* scsih callback handler */ + mpt2sas_scsih_event_callback(ioc, VF_ID, reply); + + /* ctl callback handler */ + mpt2sas_ctl_event_callback(ioc, VF_ID, reply); +} + +/** + * _base_mask_interrupts - disable interrupts + * @ioc: pointer to scsi command object + * + * Disabling ResetIRQ, Reply and Doorbell Interrupts + * + * Return nothing. + */ +static void +_base_mask_interrupts(struct MPT2SAS_ADAPTER *ioc) +{ + u32 him_register; + + ioc->mask_interrupts = 1; + him_register = readl(&ioc->chip->HostInterruptMask); + him_register |= MPI2_HIM_DIM + MPI2_HIM_RIM + MPI2_HIM_RESET_IRQ_MASK; + writel(him_register, &ioc->chip->HostInterruptMask); + readl(&ioc->chip->HostInterruptMask); +} + +/** + * _base_unmask_interrupts - enable interrupts + * @ioc: pointer to scsi command object + * + * Enabling only Reply Interrupts + * + * Return nothing. + */ +static void +_base_unmask_interrupts(struct MPT2SAS_ADAPTER *ioc) +{ + u32 him_register; + + writel(0, &ioc->chip->HostInterruptStatus); + him_register = readl(&ioc->chip->HostInterruptMask); + him_register &= ~MPI2_HIM_RIM; + writel(him_register, &ioc->chip->HostInterruptMask); + ioc->mask_interrupts = 0; +} + +/** + * _base_interrupt - MPT adapter (IOC) specific interrupt handler. + * @irq: irq number (not used) + * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure + * @r: pt_regs pointer (not used) + * + * Return IRQ_HANDLE if processed, else IRQ_NONE. + */ +static irqreturn_t +_base_interrupt(int irq, void *bus_id) +{ + u32 post_index, post_index_next, completed_cmds; + u8 request_desript_type; + u16 smid; + u8 cb_idx; + u32 reply; + u8 VF_ID; + int i; + struct MPT2SAS_ADAPTER *ioc = bus_id; + + if (ioc->mask_interrupts) + return IRQ_NONE; + + post_index = ioc->reply_post_host_index; + request_desript_type = ioc->reply_post_free[post_index]. + Default.ReplyFlags & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; + if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) + return IRQ_NONE; + + completed_cmds = 0; + do { + if (ioc->reply_post_free[post_index].Words == ~0ULL) + goto out; + reply = 0; + cb_idx = 0xFF; + smid = le16_to_cpu(ioc->reply_post_free[post_index]. + Default.DescriptorTypeDependent1); + VF_ID = ioc->reply_post_free[post_index]. + Default.VF_ID; + if (request_desript_type == + MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY) { + reply = le32_to_cpu(ioc->reply_post_free[post_index]. + AddressReply.ReplyFrameAddress); + } else if (request_desript_type == + MPI2_RPY_DESCRIPT_FLAGS_TARGET_COMMAND_BUFFER) + goto next; + else if (request_desript_type == + MPI2_RPY_DESCRIPT_FLAGS_TARGETASSIST_SUCCESS) + goto next; + if (smid) + cb_idx = ioc->scsi_lookup[smid - 1].cb_idx; + if (smid && cb_idx != 0xFF) { + mpt_callbacks[cb_idx](ioc, smid, VF_ID, reply); + if (reply) + _base_display_reply_info(ioc, smid, VF_ID, + reply); + mpt2sas_base_free_smid(ioc, smid); + } + if (!smid) + _base_async_event(ioc, VF_ID, reply); + + /* reply free queue handling */ + if (reply) { + ioc->reply_free_host_index = + (ioc->reply_free_host_index == + (ioc->reply_free_queue_depth - 1)) ? + 0 : ioc->reply_free_host_index + 1; + ioc->reply_free[ioc->reply_free_host_index] = + cpu_to_le32(reply); + writel(ioc->reply_free_host_index, + &ioc->chip->ReplyFreeHostIndex); + wmb(); + } + + next: + post_index_next = (post_index == (ioc->reply_post_queue_depth - + 1)) ? 0 : post_index + 1; + request_desript_type = + ioc->reply_post_free[post_index_next].Default.ReplyFlags + & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; + completed_cmds++; + if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) + goto out; + post_index = post_index_next; + } while (1); + + out: + + if (!completed_cmds) + return IRQ_NONE; + + /* reply post descriptor handling */ + post_index_next = ioc->reply_post_host_index; + for (i = 0 ; i < completed_cmds; i++) { + post_index = post_index_next; + /* poison the reply post descriptor */ + ioc->reply_post_free[post_index_next].Words = ~0ULL; + post_index_next = (post_index == + (ioc->reply_post_queue_depth - 1)) + ? 0 : post_index + 1; + } + ioc->reply_post_host_index = post_index_next; + writel(post_index_next, &ioc->chip->ReplyPostHostIndex); + wmb(); + return IRQ_HANDLED; +} + +/** + * mpt2sas_base_release_callback_handler - clear interupt callback handler + * @cb_idx: callback index + * + * Return nothing. + */ +void +mpt2sas_base_release_callback_handler(u8 cb_idx) +{ + mpt_callbacks[cb_idx] = NULL; +} + +/** + * mpt2sas_base_register_callback_handler - obtain index for the interrupt callback handler + * @cb_func: callback function + * + * Returns cb_func. + */ +u8 +mpt2sas_base_register_callback_handler(MPT_CALLBACK cb_func) +{ + u8 cb_idx; + + for (cb_idx = MPT_MAX_CALLBACKS-1; cb_idx; cb_idx--) + if (mpt_callbacks[cb_idx] == NULL) + break; + + mpt_callbacks[cb_idx] = cb_func; + return cb_idx; +} + +/** + * mpt2sas_base_initialize_callback_handler - initialize the interrupt callback handler + * + * Return nothing. + */ +void +mpt2sas_base_initialize_callback_handler(void) +{ + u8 cb_idx; + + for (cb_idx = 0; cb_idx < MPT_MAX_CALLBACKS; cb_idx++) + mpt2sas_base_release_callback_handler(cb_idx); +} + +/** + * mpt2sas_base_build_zero_len_sge - build zero length sg entry + * @ioc: per adapter object + * @paddr: virtual address for SGE + * + * Create a zero length scatter gather entry to insure the IOCs hardware has + * something to use if the target device goes brain dead and tries + * to send data even when none is asked for. + * + * Return nothing. + */ +void +mpt2sas_base_build_zero_len_sge(struct MPT2SAS_ADAPTER *ioc, void *paddr) +{ + u32 flags_length = (u32)((MPI2_SGE_FLAGS_LAST_ELEMENT | + MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_END_OF_LIST | + MPI2_SGE_FLAGS_SIMPLE_ELEMENT) << + MPI2_SGE_FLAGS_SHIFT); + ioc->base_add_sg_single(paddr, flags_length, -1); +} + +/** + * _base_add_sg_single_32 - Place a simple 32 bit SGE at address pAddr. + * @paddr: virtual address for SGE + * @flags_length: SGE flags and data transfer length + * @dma_addr: Physical address + * + * Return nothing. + */ +static void +_base_add_sg_single_32(void *paddr, u32 flags_length, dma_addr_t dma_addr) +{ + Mpi2SGESimple32_t *sgel = paddr; + + flags_length |= (MPI2_SGE_FLAGS_32_BIT_ADDRESSING | + MPI2_SGE_FLAGS_SYSTEM_ADDRESS) << MPI2_SGE_FLAGS_SHIFT; + sgel->FlagsLength = cpu_to_le32(flags_length); + sgel->Address = cpu_to_le32(dma_addr); +} + + +/** + * _base_add_sg_single_64 - Place a simple 64 bit SGE at address pAddr. + * @paddr: virtual address for SGE + * @flags_length: SGE flags and data transfer length + * @dma_addr: Physical address + * + * Return nothing. + */ +static void +_base_add_sg_single_64(void *paddr, u32 flags_length, dma_addr_t dma_addr) +{ + Mpi2SGESimple64_t *sgel = paddr; + + flags_length |= (MPI2_SGE_FLAGS_64_BIT_ADDRESSING | + MPI2_SGE_FLAGS_SYSTEM_ADDRESS) << MPI2_SGE_FLAGS_SHIFT; + sgel->FlagsLength = cpu_to_le32(flags_length); + sgel->Address = cpu_to_le64(dma_addr); +} + +#define convert_to_kb(x) ((x) << (PAGE_SHIFT - 10)) + +/** + * _base_config_dma_addressing - set dma addressing + * @ioc: per adapter object + * @pdev: PCI device struct + * + * Returns 0 for success, non-zero for failure. + */ +static int +_base_config_dma_addressing(struct MPT2SAS_ADAPTER *ioc, struct pci_dev *pdev) +{ + struct sysinfo s; + char *desc = NULL; + + if (sizeof(dma_addr_t) > 4) { + const uint64_t required_mask = + dma_get_required_mask(&pdev->dev); + if ((required_mask > DMA_32BIT_MASK) && !pci_set_dma_mask(pdev, + DMA_64BIT_MASK) && !pci_set_consistent_dma_mask(pdev, + DMA_64BIT_MASK)) { + ioc->base_add_sg_single = &_base_add_sg_single_64; + ioc->sge_size = sizeof(Mpi2SGESimple64_t); + desc = "64"; + goto out; + } + } + + if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK) + && !pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) { + ioc->base_add_sg_single = &_base_add_sg_single_32; + ioc->sge_size = sizeof(Mpi2SGESimple32_t); + desc = "32"; + } else + return -ENODEV; + + out: + si_meminfo(&s); + printk(MPT2SAS_INFO_FMT "%s BIT PCI BUS DMA ADDRESSING SUPPORTED, " + "total mem (%ld kB)\n", ioc->name, desc, convert_to_kb(s.totalram)); + + return 0; +} + +/** + * _base_save_msix_table - backup msix vector table + * @ioc: per adapter object + * + * This address an errata where diag reset clears out the table + */ +static void +_base_save_msix_table(struct MPT2SAS_ADAPTER *ioc) +{ + int i; + + if (!ioc->msix_enable || ioc->msix_table_backup == NULL) + return; + + for (i = 0; i < ioc->msix_vector_count; i++) + ioc->msix_table_backup[i] = ioc->msix_table[i]; +} + +/** + * _base_restore_msix_table - this restores the msix vector table + * @ioc: per adapter object + * + */ +static void +_base_restore_msix_table(struct MPT2SAS_ADAPTER *ioc) +{ + int i; + + if (!ioc->msix_enable || ioc->msix_table_backup == NULL) + return; + + for (i = 0; i < ioc->msix_vector_count; i++) + ioc->msix_table[i] = ioc->msix_table_backup[i]; +} + +/** + * _base_check_enable_msix - checks MSIX capabable. + * @ioc: per adapter object + * + * Check to see if card is capable of MSIX, and set number + * of avaliable msix vectors + */ +static int +_base_check_enable_msix(struct MPT2SAS_ADAPTER *ioc) +{ + int base; + u16 message_control; + u32 msix_table_offset; + + base = pci_find_capability(ioc->pdev, PCI_CAP_ID_MSIX); + if (!base) { + dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "msix not " + "supported\n", ioc->name)); + return -EINVAL; + } + + /* get msix vector count */ + pci_read_config_word(ioc->pdev, base + 2, &message_control); + ioc->msix_vector_count = (message_control & 0x3FF) + 1; + + /* get msix table */ + pci_read_config_dword(ioc->pdev, base + 4, &msix_table_offset); + msix_table_offset &= 0xFFFFFFF8; + ioc->msix_table = (u32 *)((void *)ioc->chip + msix_table_offset); + + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "msix is supported, " + "vector_count(%d), table_offset(0x%08x), table(%p)\n", ioc->name, + ioc->msix_vector_count, msix_table_offset, ioc->msix_table)); + return 0; +} + +/** + * _base_disable_msix - disables msix + * @ioc: per adapter object + * + */ +static void +_base_disable_msix(struct MPT2SAS_ADAPTER *ioc) +{ + if (ioc->msix_enable) { + pci_disable_msix(ioc->pdev); + kfree(ioc->msix_table_backup); + ioc->msix_table_backup = NULL; + ioc->msix_enable = 0; + } +} + +/** + * _base_enable_msix - enables msix, failback to io_apic + * @ioc: per adapter object + * + */ +static int +_base_enable_msix(struct MPT2SAS_ADAPTER *ioc) +{ + struct msix_entry entries; + int r; + u8 try_msix = 0; + + if (msix_disable == -1 || msix_disable == 0) + try_msix = 1; + + if (!try_msix) + goto try_ioapic; + + if (_base_check_enable_msix(ioc) != 0) + goto try_ioapic; + + ioc->msix_table_backup = kcalloc(ioc->msix_vector_count, + sizeof(u32), GFP_KERNEL); + if (!ioc->msix_table_backup) { + dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "allocation for " + "msix_table_backup failed!!!\n", ioc->name)); + goto try_ioapic; + } + + memset(&entries, 0, sizeof(struct msix_entry)); + r = pci_enable_msix(ioc->pdev, &entries, 1); + if (r) { + dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "pci_enable_msix " + "failed (r=%d) !!!\n", ioc->name, r)); + goto try_ioapic; + } + + r = request_irq(entries.vector, _base_interrupt, IRQF_SHARED, + ioc->name, ioc); + if (r) { + dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "unable to allocate " + "interrupt %d !!!\n", ioc->name, entries.vector)); + pci_disable_msix(ioc->pdev); + goto try_ioapic; + } + + ioc->pci_irq = entries.vector; + ioc->msix_enable = 1; + return 0; + +/* failback to io_apic interrupt routing */ + try_ioapic: + + r = request_irq(ioc->pdev->irq, _base_interrupt, IRQF_SHARED, + ioc->name, ioc); + if (r) { + printk(MPT2SAS_ERR_FMT "unable to allocate interrupt %d!\n", + ioc->name, ioc->pdev->irq); + r = -EBUSY; + goto out_fail; + } + + ioc->pci_irq = ioc->pdev->irq; + return 0; + + out_fail: + return r; +} + +/** + * mpt2sas_base_map_resources - map in controller resources (io/irq/memap) + * @ioc: per adapter object + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc) +{ + struct pci_dev *pdev = ioc->pdev; + u32 memap_sz; + u32 pio_sz; + int i, r = 0; + + dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", + ioc->name, __func__)); + + ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM); + if (pci_enable_device_mem(pdev)) { + printk(MPT2SAS_WARN_FMT "pci_enable_device_mem: " + "failed\n", ioc->name); + return -ENODEV; + } + + + if (pci_request_selected_regions(pdev, ioc->bars, + MPT2SAS_DRIVER_NAME)) { + printk(MPT2SAS_WARN_FMT "pci_request_selected_regions: " + "failed\n", ioc->name); + r = -ENODEV; + goto out_fail; + } + + pci_set_master(pdev); + + if (_base_config_dma_addressing(ioc, pdev) != 0) { + printk(MPT2SAS_WARN_FMT "no suitable DMA mask for %s\n", + ioc->name, pci_name(pdev)); + r = -ENODEV; + goto out_fail; + } + + for (i = 0, memap_sz = 0, pio_sz = 0 ; i < DEVICE_COUNT_RESOURCE; i++) { + if (pci_resource_flags(pdev, i) & PCI_BASE_ADDRESS_SPACE_IO) { + if (pio_sz) + continue; + ioc->pio_chip = pci_resource_start(pdev, i); + pio_sz = pci_resource_len(pdev, i); + } else { + if (memap_sz) + continue; + ioc->chip_phys = pci_resource_start(pdev, i); + memap_sz = pci_resource_len(pdev, i); + ioc->chip = ioremap(ioc->chip_phys, memap_sz); + if (ioc->chip == NULL) { + printk(MPT2SAS_ERR_FMT "unable to map adapter " + "memory!\n", ioc->name); + r = -EINVAL; + goto out_fail; + } + } + } + + pci_set_drvdata(pdev, ioc->shost); + _base_mask_interrupts(ioc); + r = _base_enable_msix(ioc); + if (r) + goto out_fail; + + printk(MPT2SAS_INFO_FMT "%s: IRQ %d\n", + ioc->name, ((ioc->msix_enable) ? "PCI-MSI-X enabled" : + "IO-APIC enabled"), ioc->pci_irq); + printk(MPT2SAS_INFO_FMT "iomem(0x%lx), mapped(0x%p), size(%d)\n", + ioc->name, ioc->chip_phys, ioc->chip, memap_sz); + printk(MPT2SAS_INFO_FMT "ioport(0x%lx), size(%d)\n", + ioc->name, ioc->pio_chip, pio_sz); + + return 0; + + out_fail: + if (ioc->chip_phys) + iounmap(ioc->chip); + ioc->chip_phys = 0; + ioc->pci_irq = -1; + pci_release_selected_regions(ioc->pdev, ioc->bars); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + return r; +} + +/** + * mpt2sas_base_get_msg_frame_dma - obtain request mf pointer phys addr + * @ioc: per adapter object + * @smid: system request message index(smid zero is invalid) + * + * Returns phys pointer to message frame. + */ +dma_addr_t +mpt2sas_base_get_msg_frame_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid) +{ + return ioc->request_dma + (smid * ioc->request_sz); +} + +/** + * mpt2sas_base_get_msg_frame - obtain request mf pointer + * @ioc: per adapter object + * @smid: system request message index(smid zero is invalid) + * + * Returns virt pointer to message frame. + */ +void * +mpt2sas_base_get_msg_frame(struct MPT2SAS_ADAPTER *ioc, u16 smid) +{ + return (void *)(ioc->request + (smid * ioc->request_sz)); +} + +/** + * mpt2sas_base_get_sense_buffer - obtain a sense buffer assigned to a mf request + * @ioc: per adapter object + * @smid: system request message index + * + * Returns virt pointer to sense buffer. + */ +void * +mpt2sas_base_get_sense_buffer(struct MPT2SAS_ADAPTER *ioc, u16 smid) +{ + return (void *)(ioc->sense + ((smid - 1) * SCSI_SENSE_BUFFERSIZE)); +} + +/** + * mpt2sas_base_get_sense_buffer_dma - obtain a sense buffer assigned to a mf request + * @ioc: per adapter object + * @smid: system request message index + * + * Returns phys pointer to sense buffer. + */ +dma_addr_t +mpt2sas_base_get_sense_buffer_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid) +{ + return ioc->sense_dma + ((smid - 1) * SCSI_SENSE_BUFFERSIZE); +} + +/** + * mpt2sas_base_get_reply_virt_addr - obtain reply frames virt address + * @ioc: per adapter object + * @phys_addr: lower 32 physical addr of the reply + * + * Converts 32bit lower physical addr into a virt address. + */ +void * +mpt2sas_base_get_reply_virt_addr(struct MPT2SAS_ADAPTER *ioc, u32 phys_addr) +{ + if (!phys_addr) + return NULL; + return ioc->reply + (phys_addr - (u32)ioc->reply_dma); +} + +/** + * mpt2sas_base_get_smid - obtain a free smid + * @ioc: per adapter object + * @cb_idx: callback index + * + * Returns smid (zero is invalid) + */ +u16 +mpt2sas_base_get_smid(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx) +{ + unsigned long flags; + struct request_tracker *request; + u16 smid; + + spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); + if (list_empty(&ioc->free_list)) { + spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); + printk(MPT2SAS_ERR_FMT "%s: smid not available\n", + ioc->name, __func__); + return 0; + } + + request = list_entry(ioc->free_list.next, + struct request_tracker, tracker_list); + request->cb_idx = cb_idx; + smid = request->smid; + list_del(&request->tracker_list); + spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); + return smid; +} + + +/** + * mpt2sas_base_free_smid - put smid back on free_list + * @ioc: per adapter object + * @smid: system request message index + * + * Return nothing. + */ +void +mpt2sas_base_free_smid(struct MPT2SAS_ADAPTER *ioc, u16 smid) +{ + unsigned long flags; + + spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); + ioc->scsi_lookup[smid - 1].cb_idx = 0xFF; + list_add_tail(&ioc->scsi_lookup[smid - 1].tracker_list, + &ioc->free_list); + spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); + + /* + * See _wait_for_commands_to_complete() call with regards to this code. + */ + if (ioc->shost_recovery && ioc->pending_io_count) { + if (ioc->pending_io_count == 1) + wake_up(&ioc->reset_wq); + ioc->pending_io_count--; + } +} + +/** + * _base_writeq - 64 bit write to MMIO + * @ioc: per adapter object + * @b: data payload + * @addr: address in MMIO space + * @writeq_lock: spin lock + * + * Glue for handling an atomic 64 bit word to MMIO. This special handling takes + * care of 32 bit environment where its not quarenteed to send the entire word + * in one transfer. + */ +#ifndef writeq +static inline void _base_writeq(__u64 b, volatile void __iomem *addr, + spinlock_t *writeq_lock) +{ + unsigned long flags; + __u64 data_out = cpu_to_le64(b); + + spin_lock_irqsave(writeq_lock, flags); + writel((u32)(data_out), addr); + writel((u32)(data_out >> 32), (addr + 4)); + spin_unlock_irqrestore(writeq_lock, flags); +} +#else +static inline void _base_writeq(__u64 b, volatile void __iomem *addr, + spinlock_t *writeq_lock) +{ + writeq(cpu_to_le64(b), addr); +} +#endif + +/** + * mpt2sas_base_put_smid_scsi_io - send SCSI_IO request to firmware + * @ioc: per adapter object + * @smid: system request message index + * @vf_id: virtual function id + * @handle: device handle + * + * Return nothing. + */ +void +mpt2sas_base_put_smid_scsi_io(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 vf_id, + u16 handle) +{ + Mpi2RequestDescriptorUnion_t descriptor; + u64 *request = (u64 *)&descriptor; + + + descriptor.SCSIIO.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO; + descriptor.SCSIIO.VF_ID = vf_id; + descriptor.SCSIIO.SMID = cpu_to_le16(smid); + descriptor.SCSIIO.DevHandle = cpu_to_le16(handle); + descriptor.SCSIIO.LMID = 0; + _base_writeq(*request, &ioc->chip->RequestDescriptorPostLow, + &ioc->scsi_lookup_lock); +} + + +/** + * mpt2sas_base_put_smid_hi_priority - send Task Managment request to firmware + * @ioc: per adapter object + * @smid: system request message index + * @vf_id: virtual function id + * + * Return nothing. + */ +void +mpt2sas_base_put_smid_hi_priority(struct MPT2SAS_ADAPTER *ioc, u16 smid, + u8 vf_id) +{ + Mpi2RequestDescriptorUnion_t descriptor; + u64 *request = (u64 *)&descriptor; + + descriptor.HighPriority.RequestFlags = + MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; + descriptor.HighPriority.VF_ID = vf_id; + descriptor.HighPriority.SMID = cpu_to_le16(smid); + descriptor.HighPriority.LMID = 0; + descriptor.HighPriority.Reserved1 = 0; + _base_writeq(*request, &ioc->chip->RequestDescriptorPostLow, + &ioc->scsi_lookup_lock); +} + +/** + * mpt2sas_base_put_smid_default - Default, primarily used for config pages + * @ioc: per adapter object + * @smid: system request message index + * @vf_id: virtual function id + * + * Return nothing. + */ +void +mpt2sas_base_put_smid_default(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 vf_id) +{ + Mpi2RequestDescriptorUnion_t descriptor; + u64 *request = (u64 *)&descriptor; + + descriptor.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + descriptor.Default.VF_ID = vf_id; + descriptor.Default.SMID = cpu_to_le16(smid); + descriptor.Default.LMID = 0; + descriptor.Default.DescriptorTypeDependent = 0; + _base_writeq(*request, &ioc->chip->RequestDescriptorPostLow, + &ioc->scsi_lookup_lock); +} + +/** + * mpt2sas_base_put_smid_target_assist - send Target Assist/Status to firmware + * @ioc: per adapter object + * @smid: system request message index + * @vf_id: virtual function id + * @io_index: value used to track the IO + * + * Return nothing. + */ +void +mpt2sas_base_put_smid_target_assist(struct MPT2SAS_ADAPTER *ioc, u16 smid, + u8 vf_id, u16 io_index) +{ + Mpi2RequestDescriptorUnion_t descriptor; + u64 *request = (u64 *)&descriptor; + + descriptor.SCSITarget.RequestFlags = + MPI2_REQ_DESCRIPT_FLAGS_SCSI_TARGET; + descriptor.SCSITarget.VF_ID = vf_id; + descriptor.SCSITarget.SMID = cpu_to_le16(smid); + descriptor.SCSITarget.LMID = 0; + descriptor.SCSITarget.IoIndex = cpu_to_le16(io_index); + _base_writeq(*request, &ioc->chip->RequestDescriptorPostLow, + &ioc->scsi_lookup_lock); +} + +/** + * _base_display_ioc_capabilities - Disply IOC's capabilities. + * @ioc: per adapter object + * + * Return nothing. + */ +static void +_base_display_ioc_capabilities(struct MPT2SAS_ADAPTER *ioc) +{ + int i = 0; + char desc[16]; + u8 revision; + u32 iounit_pg1_flags; + + pci_read_config_byte(ioc->pdev, PCI_CLASS_REVISION, &revision); + strncpy(desc, ioc->manu_pg0.ChipName, 16); + printk(MPT2SAS_INFO_FMT "%s: FWVersion(%02d.%02d.%02d.%02d), " + "ChipRevision(0x%02x), BiosVersion(%02d.%02d.%02d.%02d)\n", + ioc->name, desc, + (ioc->facts.FWVersion.Word & 0xFF000000) >> 24, + (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16, + (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8, + ioc->facts.FWVersion.Word & 0x000000FF, + revision, + (ioc->bios_pg3.BiosVersion & 0xFF000000) >> 24, + (ioc->bios_pg3.BiosVersion & 0x00FF0000) >> 16, + (ioc->bios_pg3.BiosVersion & 0x0000FF00) >> 8, + ioc->bios_pg3.BiosVersion & 0x000000FF); + + printk(MPT2SAS_INFO_FMT "Protocol=(", ioc->name); + + if (ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR) { + printk("Initiator"); + i++; + } + + if (ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_TARGET) { + printk("%sTarget", i ? "," : ""); + i++; + } + + i = 0; + printk("), "); + printk("Capabilities=("); + + if (ioc->facts.IOCCapabilities & + MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID) { + printk("Raid"); + i++; + } + + if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TLR) { + printk("%sTLR", i ? "," : ""); + i++; + } + + if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_MULTICAST) { + printk("%sMulticast", i ? "," : ""); + i++; + } + + if (ioc->facts.IOCCapabilities & + MPI2_IOCFACTS_CAPABILITY_BIDIRECTIONAL_TARGET) { + printk("%sBIDI Target", i ? "," : ""); + i++; + } + + if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_EEDP) { + printk("%sEEDP", i ? "," : ""); + i++; + } + + if (ioc->facts.IOCCapabilities & + MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER) { + printk("%sSnapshot Buffer", i ? "," : ""); + i++; + } + + if (ioc->facts.IOCCapabilities & + MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER) { + printk("%sDiag Trace Buffer", i ? "," : ""); + i++; + } + + if (ioc->facts.IOCCapabilities & + MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING) { + printk("%sTask Set Full", i ? "," : ""); + i++; + } + + iounit_pg1_flags = le32_to_cpu(ioc->iounit_pg1.Flags); + if (!(iounit_pg1_flags & MPI2_IOUNITPAGE1_NATIVE_COMMAND_Q_DISABLE)) { + printk("%sNCQ", i ? "," : ""); + i++; + } + + printk(")\n"); +} + +/** + * _base_static_config_pages - static start of day config pages + * @ioc: per adapter object + * + * Return nothing. + */ +static void +_base_static_config_pages(struct MPT2SAS_ADAPTER *ioc) +{ + Mpi2ConfigReply_t mpi_reply; + u32 iounit_pg1_flags; + + mpt2sas_config_get_manufacturing_pg0(ioc, &mpi_reply, &ioc->manu_pg0); + mpt2sas_config_get_bios_pg2(ioc, &mpi_reply, &ioc->bios_pg2); + mpt2sas_config_get_bios_pg3(ioc, &mpi_reply, &ioc->bios_pg3); + mpt2sas_config_get_ioc_pg8(ioc, &mpi_reply, &ioc->ioc_pg8); + mpt2sas_config_get_iounit_pg0(ioc, &mpi_reply, &ioc->iounit_pg0); + mpt2sas_config_get_iounit_pg1(ioc, &mpi_reply, &ioc->iounit_pg1); + _base_display_ioc_capabilities(ioc); + + /* + * Enable task_set_full handling in iounit_pg1 when the + * facts capabilities indicate that its supported. + */ + iounit_pg1_flags = le32_to_cpu(ioc->iounit_pg1.Flags); + if ((ioc->facts.IOCCapabilities & + MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING)) + iounit_pg1_flags &= + ~MPI2_IOUNITPAGE1_DISABLE_TASK_SET_FULL_HANDLING; + else + iounit_pg1_flags |= + MPI2_IOUNITPAGE1_DISABLE_TASK_SET_FULL_HANDLING; + ioc->iounit_pg1.Flags = cpu_to_le32(iounit_pg1_flags); + mpt2sas_config_set_iounit_pg1(ioc, &mpi_reply, ioc->iounit_pg1); +} + +/** + * _base_release_memory_pools - release memory + * @ioc: per adapter object + * + * Free memory allocated from _base_allocate_memory_pools. + * + * Return nothing. + */ +static void +_base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc) +{ + dexitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + __func__)); + + if (ioc->request) { + pci_free_consistent(ioc->pdev, ioc->request_dma_sz, + ioc->request, ioc->request_dma); + dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "request_pool(0x%p)" + ": free\n", ioc->name, ioc->request)); + ioc->request = NULL; + } + + if (ioc->sense) { + pci_pool_free(ioc->sense_dma_pool, ioc->sense, ioc->sense_dma); + if (ioc->sense_dma_pool) + pci_pool_destroy(ioc->sense_dma_pool); + dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "sense_pool(0x%p)" + ": free\n", ioc->name, ioc->sense)); + ioc->sense = NULL; + } + + if (ioc->reply) { + pci_pool_free(ioc->reply_dma_pool, ioc->reply, ioc->reply_dma); + if (ioc->reply_dma_pool) + pci_pool_destroy(ioc->reply_dma_pool); + dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply_pool(0x%p)" + ": free\n", ioc->name, ioc->reply)); + ioc->reply = NULL; + } + + if (ioc->reply_free) { + pci_pool_free(ioc->reply_free_dma_pool, ioc->reply_free, + ioc->reply_free_dma); + if (ioc->reply_free_dma_pool) + pci_pool_destroy(ioc->reply_free_dma_pool); + dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply_free_pool" + "(0x%p): free\n", ioc->name, ioc->reply_free)); + ioc->reply_free = NULL; + } + + if (ioc->reply_post_free) { + pci_pool_free(ioc->reply_post_free_dma_pool, + ioc->reply_post_free, ioc->reply_post_free_dma); + if (ioc->reply_post_free_dma_pool) + pci_pool_destroy(ioc->reply_post_free_dma_pool); + dexitprintk(ioc, printk(MPT2SAS_INFO_FMT + "reply_post_free_pool(0x%p): free\n", ioc->name, + ioc->reply_post_free)); + ioc->reply_post_free = NULL; + } + + if (ioc->config_page) { + dexitprintk(ioc, printk(MPT2SAS_INFO_FMT + "config_page(0x%p): free\n", ioc->name, + ioc->config_page)); + pci_free_consistent(ioc->pdev, ioc->config_page_sz, + ioc->config_page, ioc->config_page_dma); + } + + kfree(ioc->scsi_lookup); +} + + +/** + * _base_allocate_memory_pools - allocate start of day memory pools + * @ioc: per adapter object + * @sleep_flag: CAN_SLEEP or NO_SLEEP + * + * Returns 0 success, anything else error + */ +static int +_base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) +{ + Mpi2IOCFactsReply_t *facts; + u32 queue_size, queue_diff; + u16 max_sge_elements; + u16 num_of_reply_frames; + u16 chains_needed_per_io; + u32 sz, total_sz; + u16 i; + u32 retry_sz; + u16 max_request_credit; + + dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + __func__)); + + retry_sz = 0; + facts = &ioc->facts; + + /* command line tunables for max sgl entries */ + if (max_sgl_entries != -1) { + ioc->shost->sg_tablesize = (max_sgl_entries < + MPT2SAS_SG_DEPTH) ? max_sgl_entries : + MPT2SAS_SG_DEPTH; + } else { + ioc->shost->sg_tablesize = MPT2SAS_SG_DEPTH; + } + + /* command line tunables for max controller queue depth */ + if (max_queue_depth != -1) { + max_request_credit = (max_queue_depth < facts->RequestCredit) + ? max_queue_depth : facts->RequestCredit; + } else { + max_request_credit = (facts->RequestCredit > + MPT2SAS_MAX_REQUEST_QUEUE) ? MPT2SAS_MAX_REQUEST_QUEUE : + facts->RequestCredit; + } + ioc->request_depth = max_request_credit; + + /* request frame size */ + ioc->request_sz = facts->IOCRequestFrameSize * 4; + + /* reply frame size */ + ioc->reply_sz = facts->ReplyFrameSize * 4; + + retry_allocation: + total_sz = 0; + /* calculate number of sg elements left over in the 1st frame */ + max_sge_elements = ioc->request_sz - ((sizeof(Mpi2SCSIIORequest_t) - + sizeof(Mpi2SGEIOUnion_t)) + ioc->sge_size); + ioc->max_sges_in_main_message = max_sge_elements/ioc->sge_size; + + /* now do the same for a chain buffer */ + max_sge_elements = ioc->request_sz - ioc->sge_size; + ioc->max_sges_in_chain_message = max_sge_elements/ioc->sge_size; + + ioc->chain_offset_value_for_main_message = + ((sizeof(Mpi2SCSIIORequest_t) - sizeof(Mpi2SGEIOUnion_t)) + + (ioc->max_sges_in_chain_message * ioc->sge_size)) / 4; + + /* + * MPT2SAS_SG_DEPTH = CONFIG_FUSION_MAX_SGE + */ + chains_needed_per_io = ((ioc->shost->sg_tablesize - + ioc->max_sges_in_main_message)/ioc->max_sges_in_chain_message) + + 1; + if (chains_needed_per_io > facts->MaxChainDepth) { + chains_needed_per_io = facts->MaxChainDepth; + ioc->shost->sg_tablesize = min_t(u16, + ioc->max_sges_in_main_message + (ioc->max_sges_in_chain_message + * chains_needed_per_io), ioc->shost->sg_tablesize); + } + ioc->chains_needed_per_io = chains_needed_per_io; + + /* reply free queue sizing - taking into account for events */ + num_of_reply_frames = ioc->request_depth + 32; + + /* number of replies frames can't be a multiple of 16 */ + /* decrease number of reply frames by 1 */ + if (!(num_of_reply_frames % 16)) + num_of_reply_frames--; + + /* calculate number of reply free queue entries + * (must be multiple of 16) + */ + + /* (we know reply_free_queue_depth is not a multiple of 16) */ + queue_size = num_of_reply_frames; + queue_size += 16 - (queue_size % 16); + ioc->reply_free_queue_depth = queue_size; + + /* reply descriptor post queue sizing */ + /* this size should be the number of request frames + number of reply + * frames + */ + + queue_size = ioc->request_depth + num_of_reply_frames + 1; + /* round up to 16 byte boundary */ + if (queue_size % 16) + queue_size += 16 - (queue_size % 16); + + /* check against IOC maximum reply post queue depth */ + if (queue_size > facts->MaxReplyDescriptorPostQueueDepth) { + queue_diff = queue_size - + facts->MaxReplyDescriptorPostQueueDepth; + + /* round queue_diff up to multiple of 16 */ + if (queue_diff % 16) + queue_diff += 16 - (queue_diff % 16); + + /* adjust request_depth, reply_free_queue_depth, + * and queue_size + */ + ioc->request_depth -= queue_diff; + ioc->reply_free_queue_depth -= queue_diff; + queue_size -= queue_diff; + } + ioc->reply_post_queue_depth = queue_size; + + /* max scsi host queue depth */ + ioc->shost->can_queue = ioc->request_depth - INTERNAL_CMDS_COUNT; + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "scsi host queue: depth" + "(%d)\n", ioc->name, ioc->shost->can_queue)); + + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "scatter gather: " + "sge_in_main_msg(%d), sge_per_chain(%d), sge_per_io(%d), " + "chains_per_io(%d)\n", ioc->name, ioc->max_sges_in_main_message, + ioc->max_sges_in_chain_message, ioc->shost->sg_tablesize, + ioc->chains_needed_per_io)); + + /* contiguous pool for request and chains, 16 byte align, one extra " + * "frame for smid=0 + */ + ioc->chain_depth = ioc->chains_needed_per_io * ioc->request_depth; + sz = ((ioc->request_depth + 1 + ioc->chain_depth) * ioc->request_sz); + + ioc->request_dma_sz = sz; + ioc->request = pci_alloc_consistent(ioc->pdev, sz, &ioc->request_dma); + if (!ioc->request) { + printk(MPT2SAS_ERR_FMT "request pool: pci_alloc_consistent " + "failed: req_depth(%d), chains_per_io(%d), frame_sz(%d), " + "total(%d kB)\n", ioc->name, ioc->request_depth, + ioc->chains_needed_per_io, ioc->request_sz, sz/1024); + if (ioc->request_depth < MPT2SAS_SAS_QUEUE_DEPTH) + goto out; + retry_sz += 64; + ioc->request_depth = max_request_credit - retry_sz; + goto retry_allocation; + } + + if (retry_sz) + printk(MPT2SAS_ERR_FMT "request pool: pci_alloc_consistent " + "succeed: req_depth(%d), chains_per_io(%d), frame_sz(%d), " + "total(%d kb)\n", ioc->name, ioc->request_depth, + ioc->chains_needed_per_io, ioc->request_sz, sz/1024); + + ioc->chain = ioc->request + ((ioc->request_depth + 1) * + ioc->request_sz); + ioc->chain_dma = ioc->request_dma + ((ioc->request_depth + 1) * + ioc->request_sz); + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "request pool(0x%p): " + "depth(%d), frame_size(%d), pool_size(%d kB)\n", ioc->name, + ioc->request, ioc->request_depth, ioc->request_sz, + ((ioc->request_depth + 1) * ioc->request_sz)/1024)); + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "chain pool(0x%p): depth" + "(%d), frame_size(%d), pool_size(%d kB)\n", ioc->name, ioc->chain, + ioc->chain_depth, ioc->request_sz, ((ioc->chain_depth * + ioc->request_sz))/1024)); + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "request pool: dma(0x%llx)\n", + ioc->name, (unsigned long long) ioc->request_dma)); + total_sz += sz; + + ioc->scsi_lookup = kcalloc(ioc->request_depth, + sizeof(struct request_tracker), GFP_KERNEL); + if (!ioc->scsi_lookup) { + printk(MPT2SAS_ERR_FMT "scsi_lookup: kcalloc failed\n", + ioc->name); + goto out; + } + + /* initialize some bits */ + for (i = 0; i < ioc->request_depth; i++) + ioc->scsi_lookup[i].smid = i + 1; + + /* sense buffers, 4 byte align */ + sz = ioc->request_depth * SCSI_SENSE_BUFFERSIZE; + ioc->sense_dma_pool = pci_pool_create("sense pool", ioc->pdev, sz, 4, + 0); + if (!ioc->sense_dma_pool) { + printk(MPT2SAS_ERR_FMT "sense pool: pci_pool_create failed\n", + ioc->name); + goto out; + } + ioc->sense = pci_pool_alloc(ioc->sense_dma_pool , GFP_KERNEL, + &ioc->sense_dma); + if (!ioc->sense) { + printk(MPT2SAS_ERR_FMT "sense pool: pci_pool_alloc failed\n", + ioc->name); + goto out; + } + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT + "sense pool(0x%p): depth(%d), element_size(%d), pool_size" + "(%d kB)\n", ioc->name, ioc->sense, ioc->request_depth, + SCSI_SENSE_BUFFERSIZE, sz/1024)); + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "sense_dma(0x%llx)\n", + ioc->name, (unsigned long long)ioc->sense_dma)); + total_sz += sz; + + /* reply pool, 4 byte align */ + sz = ioc->reply_free_queue_depth * ioc->reply_sz; + ioc->reply_dma_pool = pci_pool_create("reply pool", ioc->pdev, sz, 4, + 0); + if (!ioc->reply_dma_pool) { + printk(MPT2SAS_ERR_FMT "reply pool: pci_pool_create failed\n", + ioc->name); + goto out; + } + ioc->reply = pci_pool_alloc(ioc->reply_dma_pool , GFP_KERNEL, + &ioc->reply_dma); + if (!ioc->reply) { + printk(MPT2SAS_ERR_FMT "reply pool: pci_pool_alloc failed\n", + ioc->name); + goto out; + } + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply pool(0x%p): depth" + "(%d), frame_size(%d), pool_size(%d kB)\n", ioc->name, ioc->reply, + ioc->reply_free_queue_depth, ioc->reply_sz, sz/1024)); + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply_dma(0x%llx)\n", + ioc->name, (unsigned long long)ioc->reply_dma)); + total_sz += sz; + + /* reply free queue, 16 byte align */ + sz = ioc->reply_free_queue_depth * 4; + ioc->reply_free_dma_pool = pci_pool_create("reply_free pool", + ioc->pdev, sz, 16, 0); + if (!ioc->reply_free_dma_pool) { + printk(MPT2SAS_ERR_FMT "reply_free pool: pci_pool_create " + "failed\n", ioc->name); + goto out; + } + ioc->reply_free = pci_pool_alloc(ioc->reply_free_dma_pool , GFP_KERNEL, + &ioc->reply_free_dma); + if (!ioc->reply_free) { + printk(MPT2SAS_ERR_FMT "reply_free pool: pci_pool_alloc " + "failed\n", ioc->name); + goto out; + } + memset(ioc->reply_free, 0, sz); + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply_free pool(0x%p): " + "depth(%d), element_size(%d), pool_size(%d kB)\n", ioc->name, + ioc->reply_free, ioc->reply_free_queue_depth, 4, sz/1024)); + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply_free_dma" + "(0x%llx)\n", ioc->name, (unsigned long long)ioc->reply_free_dma)); + total_sz += sz; + + /* reply post queue, 16 byte align */ + sz = ioc->reply_post_queue_depth * sizeof(Mpi2DefaultReplyDescriptor_t); + ioc->reply_post_free_dma_pool = pci_pool_create("reply_post_free pool", + ioc->pdev, sz, 16, 0); + if (!ioc->reply_post_free_dma_pool) { + printk(MPT2SAS_ERR_FMT "reply_post_free pool: pci_pool_create " + "failed\n", ioc->name); + goto out; + } + ioc->reply_post_free = pci_pool_alloc(ioc->reply_post_free_dma_pool , + GFP_KERNEL, &ioc->reply_post_free_dma); + if (!ioc->reply_post_free) { + printk(MPT2SAS_ERR_FMT "reply_post_free pool: pci_pool_alloc " + "failed\n", ioc->name); + goto out; + } + memset(ioc->reply_post_free, 0, sz); + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply post free pool" + "(0x%p): depth(%d), element_size(%d), pool_size(%d kB)\n", + ioc->name, ioc->reply_post_free, ioc->reply_post_queue_depth, 8, + sz/1024)); + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply_post_free_dma = " + "(0x%llx)\n", ioc->name, (unsigned long long) + ioc->reply_post_free_dma)); + total_sz += sz; + + ioc->config_page_sz = 512; + ioc->config_page = pci_alloc_consistent(ioc->pdev, + ioc->config_page_sz, &ioc->config_page_dma); + if (!ioc->config_page) { + printk(MPT2SAS_ERR_FMT "config page: pci_pool_alloc " + "failed\n", ioc->name); + goto out; + } + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "config page(0x%p): size" + "(%d)\n", ioc->name, ioc->config_page, ioc->config_page_sz)); + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "config_page_dma" + "(0x%llx)\n", ioc->name, (unsigned long long)ioc->config_page_dma)); + total_sz += ioc->config_page_sz; + + printk(MPT2SAS_INFO_FMT "Allocated physical memory: size(%d kB)\n", + ioc->name, total_sz/1024); + printk(MPT2SAS_INFO_FMT "Current Controller Queue Depth(%d), " + "Max Controller Queue Depth(%d)\n", + ioc->name, ioc->shost->can_queue, facts->RequestCredit); + printk(MPT2SAS_INFO_FMT "Scatter Gather Elements per IO(%d)\n", + ioc->name, ioc->shost->sg_tablesize); + return 0; + + out: + _base_release_memory_pools(ioc); + return -ENOMEM; +} + + +/** + * mpt2sas_base_get_iocstate - Get the current state of a MPT adapter. + * @ioc: Pointer to MPT_ADAPTER structure + * @cooked: Request raw or cooked IOC state + * + * Returns all IOC Doorbell register bits if cooked==0, else just the + * Doorbell bits in MPI_IOC_STATE_MASK. + */ +u32 +mpt2sas_base_get_iocstate(struct MPT2SAS_ADAPTER *ioc, int cooked) +{ + u32 s, sc; + + s = readl(&ioc->chip->Doorbell); + sc = s & MPI2_IOC_STATE_MASK; + return cooked ? sc : s; +} + +/** + * _base_wait_on_iocstate - waiting on a particular ioc state + * @ioc_state: controller state { READY, OPERATIONAL, or RESET } + * @timeout: timeout in second + * @sleep_flag: CAN_SLEEP or NO_SLEEP + * + * Returns 0 for success, non-zero for failure. + */ +static int +_base_wait_on_iocstate(struct MPT2SAS_ADAPTER *ioc, u32 ioc_state, int timeout, + int sleep_flag) +{ + u32 count, cntdn; + u32 current_state; + + count = 0; + cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout; + do { + current_state = mpt2sas_base_get_iocstate(ioc, 1); + if (current_state == ioc_state) + return 0; + if (count && current_state == MPI2_IOC_STATE_FAULT) + break; + if (sleep_flag == CAN_SLEEP) + msleep(1); + else + udelay(500); + count++; + } while (--cntdn); + + return current_state; +} + +/** + * _base_wait_for_doorbell_int - waiting for controller interrupt(generated by + * a write to the doorbell) + * @ioc: per adapter object + * @timeout: timeout in second + * @sleep_flag: CAN_SLEEP or NO_SLEEP + * + * Returns 0 for success, non-zero for failure. + * + * Notes: MPI2_HIS_IOC2SYS_DB_STATUS - set to one when IOC writes to doorbell. + */ +static int +_base_wait_for_doorbell_int(struct MPT2SAS_ADAPTER *ioc, int timeout, + int sleep_flag) +{ + u32 cntdn, count; + u32 int_status; + + count = 0; + cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout; + do { + int_status = readl(&ioc->chip->HostInterruptStatus); + if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) { + dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " + "successfull count(%d), timeout(%d)\n", ioc->name, + __func__, count, timeout)); + return 0; + } + if (sleep_flag == CAN_SLEEP) + msleep(1); + else + udelay(500); + count++; + } while (--cntdn); + + printk(MPT2SAS_ERR_FMT "%s: failed due to timeout count(%d), " + "int_status(%x)!\n", ioc->name, __func__, count, int_status); + return -EFAULT; +} + +/** + * _base_wait_for_doorbell_ack - waiting for controller to read the doorbell. + * @ioc: per adapter object + * @timeout: timeout in second + * @sleep_flag: CAN_SLEEP or NO_SLEEP + * + * Returns 0 for success, non-zero for failure. + * + * Notes: MPI2_HIS_SYS2IOC_DB_STATUS - set to one when host writes to + * doorbell. + */ +static int +_base_wait_for_doorbell_ack(struct MPT2SAS_ADAPTER *ioc, int timeout, + int sleep_flag) +{ + u32 cntdn, count; + u32 int_status; + u32 doorbell; + + count = 0; + cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout; + do { + int_status = readl(&ioc->chip->HostInterruptStatus); + if (!(int_status & MPI2_HIS_SYS2IOC_DB_STATUS)) { + dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " + "successfull count(%d), timeout(%d)\n", ioc->name, + __func__, count, timeout)); + return 0; + } else if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) { + doorbell = readl(&ioc->chip->Doorbell); + if ((doorbell & MPI2_IOC_STATE_MASK) == + MPI2_IOC_STATE_FAULT) { + mpt2sas_base_fault_info(ioc , doorbell); + return -EFAULT; + } + } else if (int_status == 0xFFFFFFFF) + goto out; + + if (sleep_flag == CAN_SLEEP) + msleep(1); + else + udelay(500); + count++; + } while (--cntdn); + + out: + printk(MPT2SAS_ERR_FMT "%s: failed due to timeout count(%d), " + "int_status(%x)!\n", ioc->name, __func__, count, int_status); + return -EFAULT; +} + +/** + * _base_wait_for_doorbell_not_used - waiting for doorbell to not be in use + * @ioc: per adapter object + * @timeout: timeout in second + * @sleep_flag: CAN_SLEEP or NO_SLEEP + * + * Returns 0 for success, non-zero for failure. + * + */ +static int +_base_wait_for_doorbell_not_used(struct MPT2SAS_ADAPTER *ioc, int timeout, + int sleep_flag) +{ + u32 cntdn, count; + u32 doorbell_reg; + + count = 0; + cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout; + do { + doorbell_reg = readl(&ioc->chip->Doorbell); + if (!(doorbell_reg & MPI2_DOORBELL_USED)) { + dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " + "successfull count(%d), timeout(%d)\n", ioc->name, + __func__, count, timeout)); + return 0; + } + if (sleep_flag == CAN_SLEEP) + msleep(1); + else + udelay(500); + count++; + } while (--cntdn); + + printk(MPT2SAS_ERR_FMT "%s: failed due to timeout count(%d), " + "doorbell_reg(%x)!\n", ioc->name, __func__, count, doorbell_reg); + return -EFAULT; +} + +/** + * _base_send_ioc_reset - send doorbell reset + * @ioc: per adapter object + * @reset_type: currently only supports: MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET + * @timeout: timeout in second + * @sleep_flag: CAN_SLEEP or NO_SLEEP + * + * Returns 0 for success, non-zero for failure. + */ +static int +_base_send_ioc_reset(struct MPT2SAS_ADAPTER *ioc, u8 reset_type, int timeout, + int sleep_flag) +{ + u32 ioc_state; + int r = 0; + + if (reset_type != MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET) { + printk(MPT2SAS_ERR_FMT "%s: unknown reset_type\n", + ioc->name, __func__); + return -EFAULT; + } + + if (!(ioc->facts.IOCCapabilities & + MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY)) + return -EFAULT; + + printk(MPT2SAS_INFO_FMT "sending message unit reset !!\n", ioc->name); + + writel(reset_type << MPI2_DOORBELL_FUNCTION_SHIFT, + &ioc->chip->Doorbell); + if ((_base_wait_for_doorbell_ack(ioc, 15, sleep_flag))) { + r = -EFAULT; + goto out; + } + ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY, + timeout, sleep_flag); + if (ioc_state) { + printk(MPT2SAS_ERR_FMT "%s: failed going to ready state " + " (ioc_state=0x%x)\n", ioc->name, __func__, ioc_state); + r = -EFAULT; + goto out; + } + out: + printk(MPT2SAS_INFO_FMT "message unit reset: %s\n", + ioc->name, ((r == 0) ? "SUCCESS" : "FAILED")); + return r; +} + +/** + * _base_handshake_req_reply_wait - send request thru doorbell interface + * @ioc: per adapter object + * @request_bytes: request length + * @request: pointer having request payload + * @reply_bytes: reply length + * @reply: pointer to reply payload + * @timeout: timeout in second + * @sleep_flag: CAN_SLEEP or NO_SLEEP + * + * Returns 0 for success, non-zero for failure. + */ +static int +_base_handshake_req_reply_wait(struct MPT2SAS_ADAPTER *ioc, int request_bytes, + u32 *request, int reply_bytes, u16 *reply, int timeout, int sleep_flag) +{ + MPI2DefaultReply_t *default_reply = (MPI2DefaultReply_t *)reply; + int i; + u8 failed; + u16 dummy; + u32 *mfp; + + /* make sure doorbell is not in use */ + if ((readl(&ioc->chip->Doorbell) & MPI2_DOORBELL_USED)) { + printk(MPT2SAS_ERR_FMT "doorbell is in use " + " (line=%d)\n", ioc->name, __LINE__); + return -EFAULT; + } + + /* clear pending doorbell interrupts from previous state changes */ + if (readl(&ioc->chip->HostInterruptStatus) & + MPI2_HIS_IOC2SYS_DB_STATUS) + writel(0, &ioc->chip->HostInterruptStatus); + + /* send message to ioc */ + writel(((MPI2_FUNCTION_HANDSHAKE<<MPI2_DOORBELL_FUNCTION_SHIFT) | + ((request_bytes/4)<<MPI2_DOORBELL_ADD_DWORDS_SHIFT)), + &ioc->chip->Doorbell); + + if ((_base_wait_for_doorbell_int(ioc, 5, sleep_flag))) { + printk(MPT2SAS_ERR_FMT "doorbell handshake " + "int failed (line=%d)\n", ioc->name, __LINE__); + return -EFAULT; + } + writel(0, &ioc->chip->HostInterruptStatus); + + if ((_base_wait_for_doorbell_ack(ioc, 5, sleep_flag))) { + printk(MPT2SAS_ERR_FMT "doorbell handshake " + "ack failed (line=%d)\n", ioc->name, __LINE__); + return -EFAULT; + } + + /* send message 32-bits at a time */ + for (i = 0, failed = 0; i < request_bytes/4 && !failed; i++) { + writel(cpu_to_le32(request[i]), &ioc->chip->Doorbell); + if ((_base_wait_for_doorbell_ack(ioc, 5, sleep_flag))) + failed = 1; + } + + if (failed) { + printk(MPT2SAS_ERR_FMT "doorbell handshake " + "sending request failed (line=%d)\n", ioc->name, __LINE__); + return -EFAULT; + } + + /* now wait for the reply */ + if ((_base_wait_for_doorbell_int(ioc, timeout, sleep_flag))) { + printk(MPT2SAS_ERR_FMT "doorbell handshake " + "int failed (line=%d)\n", ioc->name, __LINE__); + return -EFAULT; + } + + /* read the first two 16-bits, it gives the total length of the reply */ + reply[0] = le16_to_cpu(readl(&ioc->chip->Doorbell) + & MPI2_DOORBELL_DATA_MASK); + writel(0, &ioc->chip->HostInterruptStatus); + if ((_base_wait_for_doorbell_int(ioc, 5, sleep_flag))) { + printk(MPT2SAS_ERR_FMT "doorbell handshake " + "int failed (line=%d)\n", ioc->name, __LINE__); + return -EFAULT; + } + reply[1] = le16_to_cpu(readl(&ioc->chip->Doorbell) + & MPI2_DOORBELL_DATA_MASK); + writel(0, &ioc->chip->HostInterruptStatus); + + for (i = 2; i < default_reply->MsgLength * 2; i++) { + if ((_base_wait_for_doorbell_int(ioc, 5, sleep_flag))) { + printk(MPT2SAS_ERR_FMT "doorbell " + "handshake int failed (line=%d)\n", ioc->name, + __LINE__); + return -EFAULT; + } + if (i >= reply_bytes/2) /* overflow case */ + dummy = readl(&ioc->chip->Doorbell); + else + reply[i] = le16_to_cpu(readl(&ioc->chip->Doorbell) + & MPI2_DOORBELL_DATA_MASK); + writel(0, &ioc->chip->HostInterruptStatus); + } + + _base_wait_for_doorbell_int(ioc, 5, sleep_flag); + if (_base_wait_for_doorbell_not_used(ioc, 5, sleep_flag) != 0) { + dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "doorbell is in use " + " (line=%d)\n", ioc->name, __LINE__)); + } + writel(0, &ioc->chip->HostInterruptStatus); + + if (ioc->logging_level & MPT_DEBUG_INIT) { + mfp = (u32 *)reply; + printk(KERN_DEBUG "\toffset:data\n"); + for (i = 0; i < reply_bytes/4; i++) + printk(KERN_DEBUG "\t[0x%02x]:%08x\n", i*4, + le32_to_cpu(mfp[i])); + } + return 0; +} + +/** + * mpt2sas_base_sas_iounit_control - send sas iounit control to FW + * @ioc: per adapter object + * @mpi_reply: the reply payload from FW + * @mpi_request: the request payload sent to FW + * + * The SAS IO Unit Control Request message allows the host to perform low-level + * operations, such as resets on the PHYs of the IO Unit, also allows the host + * to obtain the IOC assigned device handles for a device if it has other + * identifying information about the device, in addition allows the host to + * remove IOC resources associated with the device. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt2sas_base_sas_iounit_control(struct MPT2SAS_ADAPTER *ioc, + Mpi2SasIoUnitControlReply_t *mpi_reply, + Mpi2SasIoUnitControlRequest_t *mpi_request) +{ + u16 smid; + u32 ioc_state; + unsigned long timeleft; + u8 issue_reset; + int rc; + void *request; + u16 wait_state_count; + + dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + __func__)); + + mutex_lock(&ioc->base_cmds.mutex); + + if (ioc->base_cmds.status != MPT2_CMD_NOT_USED) { + printk(MPT2SAS_ERR_FMT "%s: base_cmd in use\n", + ioc->name, __func__); + rc = -EAGAIN; + goto out; + } + + wait_state_count = 0; + ioc_state = mpt2sas_base_get_iocstate(ioc, 1); + while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { + if (wait_state_count++ == 10) { + printk(MPT2SAS_ERR_FMT + "%s: failed due to ioc not operational\n", + ioc->name, __func__); + rc = -EFAULT; + goto out; + } + ssleep(1); + ioc_state = mpt2sas_base_get_iocstate(ioc, 1); + printk(MPT2SAS_INFO_FMT "%s: waiting for " + "operational state(count=%d)\n", ioc->name, + __func__, wait_state_count); + } + + smid = mpt2sas_base_get_smid(ioc, ioc->base_cb_idx); + if (!smid) { + printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", + ioc->name, __func__); + rc = -EAGAIN; + goto out; + } + + rc = 0; + ioc->base_cmds.status = MPT2_CMD_PENDING; + request = mpt2sas_base_get_msg_frame(ioc, smid); + ioc->base_cmds.smid = smid; + memcpy(request, mpi_request, sizeof(Mpi2SasIoUnitControlRequest_t)); + if (mpi_request->Operation == MPI2_SAS_OP_PHY_HARD_RESET || + mpi_request->Operation == MPI2_SAS_OP_PHY_LINK_RESET) + ioc->ioc_link_reset_in_progress = 1; + mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID); + timeleft = wait_for_completion_timeout(&ioc->base_cmds.done, + msecs_to_jiffies(10000)); + if ((mpi_request->Operation == MPI2_SAS_OP_PHY_HARD_RESET || + mpi_request->Operation == MPI2_SAS_OP_PHY_LINK_RESET) && + ioc->ioc_link_reset_in_progress) + ioc->ioc_link_reset_in_progress = 0; + if (!(ioc->base_cmds.status & MPT2_CMD_COMPLETE)) { + printk(MPT2SAS_ERR_FMT "%s: timeout\n", + ioc->name, __func__); + _debug_dump_mf(mpi_request, + sizeof(Mpi2SasIoUnitControlRequest_t)/4); + if (!(ioc->base_cmds.status & MPT2_CMD_RESET)) + issue_reset = 1; + goto issue_host_reset; + } + if (ioc->base_cmds.status & MPT2_CMD_REPLY_VALID) + memcpy(mpi_reply, ioc->base_cmds.reply, + sizeof(Mpi2SasIoUnitControlReply_t)); + else + memset(mpi_reply, 0, sizeof(Mpi2SasIoUnitControlReply_t)); + ioc->base_cmds.status = MPT2_CMD_NOT_USED; + goto out; + + issue_host_reset: + if (issue_reset) + mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, + FORCE_BIG_HAMMER); + ioc->base_cmds.status = MPT2_CMD_NOT_USED; + rc = -EFAULT; + out: + mutex_unlock(&ioc->base_cmds.mutex); + return rc; +} + + +/** + * mpt2sas_base_scsi_enclosure_processor - sending request to sep device + * @ioc: per adapter object + * @mpi_reply: the reply payload from FW + * @mpi_request: the request payload sent to FW + * + * The SCSI Enclosure Processor request message causes the IOC to + * communicate with SES devices to control LED status signals. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt2sas_base_scsi_enclosure_processor(struct MPT2SAS_ADAPTER *ioc, + Mpi2SepReply_t *mpi_reply, Mpi2SepRequest_t *mpi_request) +{ + u16 smid; + u32 ioc_state; + unsigned long timeleft; + u8 issue_reset; + int rc; + void *request; + u16 wait_state_count; + + dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + __func__)); + + mutex_lock(&ioc->base_cmds.mutex); + + if (ioc->base_cmds.status != MPT2_CMD_NOT_USED) { + printk(MPT2SAS_ERR_FMT "%s: base_cmd in use\n", + ioc->name, __func__); + rc = -EAGAIN; + goto out; + } + + wait_state_count = 0; + ioc_state = mpt2sas_base_get_iocstate(ioc, 1); + while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { + if (wait_state_count++ == 10) { + printk(MPT2SAS_ERR_FMT + "%s: failed due to ioc not operational\n", + ioc->name, __func__); + rc = -EFAULT; + goto out; + } + ssleep(1); + ioc_state = mpt2sas_base_get_iocstate(ioc, 1); + printk(MPT2SAS_INFO_FMT "%s: waiting for " + "operational state(count=%d)\n", ioc->name, + __func__, wait_state_count); + } + + smid = mpt2sas_base_get_smid(ioc, ioc->base_cb_idx); + if (!smid) { + printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", + ioc->name, __func__); + rc = -EAGAIN; + goto out; + } + + rc = 0; + ioc->base_cmds.status = MPT2_CMD_PENDING; + request = mpt2sas_base_get_msg_frame(ioc, smid); + ioc->base_cmds.smid = smid; + memcpy(request, mpi_request, sizeof(Mpi2SepReply_t)); + mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID); + timeleft = wait_for_completion_timeout(&ioc->base_cmds.done, + msecs_to_jiffies(10000)); + if (!(ioc->base_cmds.status & MPT2_CMD_COMPLETE)) { + printk(MPT2SAS_ERR_FMT "%s: timeout\n", + ioc->name, __func__); + _debug_dump_mf(mpi_request, + sizeof(Mpi2SepRequest_t)/4); + if (!(ioc->base_cmds.status & MPT2_CMD_RESET)) + issue_reset = 1; + goto issue_host_reset; + } + if (ioc->base_cmds.status & MPT2_CMD_REPLY_VALID) + memcpy(mpi_reply, ioc->base_cmds.reply, + sizeof(Mpi2SepReply_t)); + else + memset(mpi_reply, 0, sizeof(Mpi2SepReply_t)); + ioc->base_cmds.status = MPT2_CMD_NOT_USED; + goto out; + + issue_host_reset: + if (issue_reset) + mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, + FORCE_BIG_HAMMER); + ioc->base_cmds.status = MPT2_CMD_NOT_USED; + rc = -EFAULT; + out: + mutex_unlock(&ioc->base_cmds.mutex); + return rc; +} + +/** + * _base_get_port_facts - obtain port facts reply and save in ioc + * @ioc: per adapter object + * @sleep_flag: CAN_SLEEP or NO_SLEEP + * + * Returns 0 for success, non-zero for failure. + */ +static int +_base_get_port_facts(struct MPT2SAS_ADAPTER *ioc, int port, int sleep_flag) +{ + Mpi2PortFactsRequest_t mpi_request; + Mpi2PortFactsReply_t mpi_reply, *pfacts; + int mpi_reply_sz, mpi_request_sz, r; + + dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + __func__)); + + mpi_reply_sz = sizeof(Mpi2PortFactsReply_t); + mpi_request_sz = sizeof(Mpi2PortFactsRequest_t); + memset(&mpi_request, 0, mpi_request_sz); + mpi_request.Function = MPI2_FUNCTION_PORT_FACTS; + mpi_request.PortNumber = port; + r = _base_handshake_req_reply_wait(ioc, mpi_request_sz, + (u32 *)&mpi_request, mpi_reply_sz, (u16 *)&mpi_reply, 5, CAN_SLEEP); + + if (r != 0) { + printk(MPT2SAS_ERR_FMT "%s: handshake failed (r=%d)\n", + ioc->name, __func__, r); + return r; + } + + pfacts = &ioc->pfacts[port]; + memset(pfacts, 0, sizeof(Mpi2PortFactsReply_t)); + pfacts->PortNumber = mpi_reply.PortNumber; + pfacts->VP_ID = mpi_reply.VP_ID; + pfacts->VF_ID = mpi_reply.VF_ID; + pfacts->MaxPostedCmdBuffers = + le16_to_cpu(mpi_reply.MaxPostedCmdBuffers); + + return 0; +} + +/** + * _base_get_ioc_facts - obtain ioc facts reply and save in ioc + * @ioc: per adapter object + * @sleep_flag: CAN_SLEEP or NO_SLEEP + * + * Returns 0 for success, non-zero for failure. + */ +static int +_base_get_ioc_facts(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) +{ + Mpi2IOCFactsRequest_t mpi_request; + Mpi2IOCFactsReply_t mpi_reply, *facts; + int mpi_reply_sz, mpi_request_sz, r; + + dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + __func__)); + + mpi_reply_sz = sizeof(Mpi2IOCFactsReply_t); + mpi_request_sz = sizeof(Mpi2IOCFactsRequest_t); + memset(&mpi_request, 0, mpi_request_sz); + mpi_request.Function = MPI2_FUNCTION_IOC_FACTS; + r = _base_handshake_req_reply_wait(ioc, mpi_request_sz, + (u32 *)&mpi_request, mpi_reply_sz, (u16 *)&mpi_reply, 5, CAN_SLEEP); + + if (r != 0) { + printk(MPT2SAS_ERR_FMT "%s: handshake failed (r=%d)\n", + ioc->name, __func__, r); + return r; + } + + facts = &ioc->facts; + memset(facts, 0, sizeof(Mpi2IOCFactsReply_t)); + facts->MsgVersion = le16_to_cpu(mpi_reply.MsgVersion); + facts->HeaderVersion = le16_to_cpu(mpi_reply.HeaderVersion); + facts->VP_ID = mpi_reply.VP_ID; + facts->VF_ID = mpi_reply.VF_ID; + facts->IOCExceptions = le16_to_cpu(mpi_reply.IOCExceptions); + facts->MaxChainDepth = mpi_reply.MaxChainDepth; + facts->WhoInit = mpi_reply.WhoInit; + facts->NumberOfPorts = mpi_reply.NumberOfPorts; + facts->RequestCredit = le16_to_cpu(mpi_reply.RequestCredit); + facts->MaxReplyDescriptorPostQueueDepth = + le16_to_cpu(mpi_reply.MaxReplyDescriptorPostQueueDepth); + facts->ProductID = le16_to_cpu(mpi_reply.ProductID); + facts->IOCCapabilities = le32_to_cpu(mpi_reply.IOCCapabilities); + if ((facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID)) + ioc->ir_firmware = 1; + facts->FWVersion.Word = le32_to_cpu(mpi_reply.FWVersion.Word); + facts->IOCRequestFrameSize = + le16_to_cpu(mpi_reply.IOCRequestFrameSize); + facts->MaxInitiators = le16_to_cpu(mpi_reply.MaxInitiators); + facts->MaxTargets = le16_to_cpu(mpi_reply.MaxTargets); + ioc->shost->max_id = -1; + facts->MaxSasExpanders = le16_to_cpu(mpi_reply.MaxSasExpanders); + facts->MaxEnclosures = le16_to_cpu(mpi_reply.MaxEnclosures); + facts->ProtocolFlags = le16_to_cpu(mpi_reply.ProtocolFlags); + facts->HighPriorityCredit = + le16_to_cpu(mpi_reply.HighPriorityCredit); + facts->ReplyFrameSize = mpi_reply.ReplyFrameSize; + facts->MaxDevHandle = le16_to_cpu(mpi_reply.MaxDevHandle); + + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "hba queue depth(%d), " + "max chains per io(%d)\n", ioc->name, facts->RequestCredit, + facts->MaxChainDepth)); + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "request frame size(%d), " + "reply frame size(%d)\n", ioc->name, + facts->IOCRequestFrameSize * 4, facts->ReplyFrameSize * 4)); + return 0; +} + +/** + * _base_send_ioc_init - send ioc_init to firmware + * @ioc: per adapter object + * @VF_ID: virtual function id + * @sleep_flag: CAN_SLEEP or NO_SLEEP + * + * Returns 0 for success, non-zero for failure. + */ +static int +_base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, int sleep_flag) +{ + Mpi2IOCInitRequest_t mpi_request; + Mpi2IOCInitReply_t mpi_reply; + int r; + + dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + __func__)); + + memset(&mpi_request, 0, sizeof(Mpi2IOCInitRequest_t)); + mpi_request.Function = MPI2_FUNCTION_IOC_INIT; + mpi_request.WhoInit = MPI2_WHOINIT_HOST_DRIVER; + mpi_request.VF_ID = VF_ID; + mpi_request.MsgVersion = cpu_to_le16(MPI2_VERSION); + mpi_request.HeaderVersion = cpu_to_le16(MPI2_HEADER_VERSION); + + /* In MPI Revision I (0xA), the SystemReplyFrameSize(offset 0x18) was + * removed and made reserved. For those with older firmware will need + * this fix. It was decided that the Reply and Request frame sizes are + * the same. + */ + if ((ioc->facts.HeaderVersion >> 8) < 0xA) { + mpi_request.Reserved7 = cpu_to_le16(ioc->reply_sz); +/* mpi_request.SystemReplyFrameSize = + * cpu_to_le16(ioc->reply_sz); + */ + } + + mpi_request.SystemRequestFrameSize = cpu_to_le16(ioc->request_sz/4); + mpi_request.ReplyDescriptorPostQueueDepth = + cpu_to_le16(ioc->reply_post_queue_depth); + mpi_request.ReplyFreeQueueDepth = + cpu_to_le16(ioc->reply_free_queue_depth); + +#if BITS_PER_LONG > 32 + mpi_request.SenseBufferAddressHigh = + cpu_to_le32(ioc->sense_dma >> 32); + mpi_request.SystemReplyAddressHigh = + cpu_to_le32(ioc->reply_dma >> 32); + mpi_request.SystemRequestFrameBaseAddress = + cpu_to_le64(ioc->request_dma); + mpi_request.ReplyFreeQueueAddress = + cpu_to_le64(ioc->reply_free_dma); + mpi_request.ReplyDescriptorPostQueueAddress = + cpu_to_le64(ioc->reply_post_free_dma); +#else + mpi_request.SystemRequestFrameBaseAddress = + cpu_to_le32(ioc->request_dma); + mpi_request.ReplyFreeQueueAddress = + cpu_to_le32(ioc->reply_free_dma); + mpi_request.ReplyDescriptorPostQueueAddress = + cpu_to_le32(ioc->reply_post_free_dma); +#endif + + if (ioc->logging_level & MPT_DEBUG_INIT) { + u32 *mfp; + int i; + + mfp = (u32 *)&mpi_request; + printk(KERN_DEBUG "\toffset:data\n"); + for (i = 0; i < sizeof(Mpi2IOCInitRequest_t)/4; i++) + printk(KERN_DEBUG "\t[0x%02x]:%08x\n", i*4, + le32_to_cpu(mfp[i])); + } + + r = _base_handshake_req_reply_wait(ioc, + sizeof(Mpi2IOCInitRequest_t), (u32 *)&mpi_request, + sizeof(Mpi2IOCInitReply_t), (u16 *)&mpi_reply, 10, + sleep_flag); + + if (r != 0) { + printk(MPT2SAS_ERR_FMT "%s: handshake failed (r=%d)\n", + ioc->name, __func__, r); + return r; + } + + if (mpi_reply.IOCStatus != MPI2_IOCSTATUS_SUCCESS || + mpi_reply.IOCLogInfo) { + printk(MPT2SAS_ERR_FMT "%s: failed\n", ioc->name, __func__); + r = -EIO; + } + + return 0; +} + +/** + * _base_send_port_enable - send port_enable(discovery stuff) to firmware + * @ioc: per adapter object + * @VF_ID: virtual function id + * @sleep_flag: CAN_SLEEP or NO_SLEEP + * + * Returns 0 for success, non-zero for failure. + */ +static int +_base_send_port_enable(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, int sleep_flag) +{ + Mpi2PortEnableRequest_t *mpi_request; + u32 ioc_state; + unsigned long timeleft; + int r = 0; + u16 smid; + + printk(MPT2SAS_INFO_FMT "sending port enable !!\n", ioc->name); + + if (ioc->base_cmds.status & MPT2_CMD_PENDING) { + printk(MPT2SAS_ERR_FMT "%s: internal command already in use\n", + ioc->name, __func__); + return -EAGAIN; + } + + smid = mpt2sas_base_get_smid(ioc, ioc->base_cb_idx); + if (!smid) { + printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", + ioc->name, __func__); + return -EAGAIN; + } + + ioc->base_cmds.status = MPT2_CMD_PENDING; + mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); + ioc->base_cmds.smid = smid; + memset(mpi_request, 0, sizeof(Mpi2PortEnableRequest_t)); + mpi_request->Function = MPI2_FUNCTION_PORT_ENABLE; + mpi_request->VF_ID = VF_ID; + + mpt2sas_base_put_smid_default(ioc, smid, VF_ID); + timeleft = wait_for_completion_timeout(&ioc->base_cmds.done, + 300*HZ); + if (!(ioc->base_cmds.status & MPT2_CMD_COMPLETE)) { + printk(MPT2SAS_ERR_FMT "%s: timeout\n", + ioc->name, __func__); + _debug_dump_mf(mpi_request, + sizeof(Mpi2PortEnableRequest_t)/4); + if (ioc->base_cmds.status & MPT2_CMD_RESET) + r = -EFAULT; + else + r = -ETIME; + goto out; + } else + dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: complete\n", + ioc->name, __func__)); + + ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_OPERATIONAL, + 60, sleep_flag); + if (ioc_state) { + printk(MPT2SAS_ERR_FMT "%s: failed going to operational state " + " (ioc_state=0x%x)\n", ioc->name, __func__, ioc_state); + r = -EFAULT; + } + out: + ioc->base_cmds.status = MPT2_CMD_NOT_USED; + printk(MPT2SAS_INFO_FMT "port enable: %s\n", + ioc->name, ((r == 0) ? "SUCCESS" : "FAILED")); + return r; +} + +/** + * _base_unmask_events - turn on notification for this event + * @ioc: per adapter object + * @event: firmware event + * + * The mask is stored in ioc->event_masks. + */ +static void +_base_unmask_events(struct MPT2SAS_ADAPTER *ioc, u16 event) +{ + u32 desired_event; + + if (event >= 128) + return; + + desired_event = (1 << (event % 32)); + + if (event < 32) + ioc->event_masks[0] &= ~desired_event; + else if (event < 64) + ioc->event_masks[1] &= ~desired_event; + else if (event < 96) + ioc->event_masks[2] &= ~desired_event; + else if (event < 128) + ioc->event_masks[3] &= ~desired_event; +} + +/** + * _base_event_notification - send event notification + * @ioc: per adapter object + * @VF_ID: virtual function id + * @sleep_flag: CAN_SLEEP or NO_SLEEP + * + * Returns 0 for success, non-zero for failure. + */ +static int +_base_event_notification(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, int sleep_flag) +{ + Mpi2EventNotificationRequest_t *mpi_request; + unsigned long timeleft; + u16 smid; + int r = 0; + int i; + + dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + __func__)); + + if (ioc->base_cmds.status & MPT2_CMD_PENDING) { + printk(MPT2SAS_ERR_FMT "%s: internal command already in use\n", + ioc->name, __func__); + return -EAGAIN; + } + + smid = mpt2sas_base_get_smid(ioc, ioc->base_cb_idx); + if (!smid) { + printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", + ioc->name, __func__); + return -EAGAIN; + } + ioc->base_cmds.status = MPT2_CMD_PENDING; + mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); + ioc->base_cmds.smid = smid; + memset(mpi_request, 0, sizeof(Mpi2EventNotificationRequest_t)); + mpi_request->Function = MPI2_FUNCTION_EVENT_NOTIFICATION; + mpi_request->VF_ID = VF_ID; + for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++) + mpi_request->EventMasks[i] = + le32_to_cpu(ioc->event_masks[i]); + mpt2sas_base_put_smid_default(ioc, smid, VF_ID); + timeleft = wait_for_completion_timeout(&ioc->base_cmds.done, 30*HZ); + if (!(ioc->base_cmds.status & MPT2_CMD_COMPLETE)) { + printk(MPT2SAS_ERR_FMT "%s: timeout\n", + ioc->name, __func__); + _debug_dump_mf(mpi_request, + sizeof(Mpi2EventNotificationRequest_t)/4); + if (ioc->base_cmds.status & MPT2_CMD_RESET) + r = -EFAULT; + else + r = -ETIME; + } else + dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: complete\n", + ioc->name, __func__)); + ioc->base_cmds.status = MPT2_CMD_NOT_USED; + return r; +} + +/** + * mpt2sas_base_validate_event_type - validating event types + * @ioc: per adapter object + * @event: firmware event + * + * This will turn on firmware event notification when application + * ask for that event. We don't mask events that are already enabled. + */ +void +mpt2sas_base_validate_event_type(struct MPT2SAS_ADAPTER *ioc, u32 *event_type) +{ + int i, j; + u32 event_mask, desired_event; + u8 send_update_to_fw; + + for (i = 0, send_update_to_fw = 0; i < + MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++) { + event_mask = ~event_type[i]; + desired_event = 1; + for (j = 0; j < 32; j++) { + if (!(event_mask & desired_event) && + (ioc->event_masks[i] & desired_event)) { + ioc->event_masks[i] &= ~desired_event; + send_update_to_fw = 1; + } + desired_event = (desired_event << 1); + } + } + + if (!send_update_to_fw) + return; + + mutex_lock(&ioc->base_cmds.mutex); + _base_event_notification(ioc, 0, CAN_SLEEP); + mutex_unlock(&ioc->base_cmds.mutex); +} + +/** + * _base_diag_reset - the "big hammer" start of day reset + * @ioc: per adapter object + * @sleep_flag: CAN_SLEEP or NO_SLEEP + * + * Returns 0 for success, non-zero for failure. + */ +static int +_base_diag_reset(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) +{ + u32 host_diagnostic; + u32 ioc_state; + u32 count; + u32 hcb_size; + + printk(MPT2SAS_INFO_FMT "sending diag reset !!\n", ioc->name); + + _base_save_msix_table(ioc); + + drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "clear interrupts\n", + ioc->name)); + writel(0, &ioc->chip->HostInterruptStatus); + + count = 0; + do { + /* Write magic sequence to WriteSequence register + * Loop until in diagnostic mode + */ + drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "write magic " + "sequence\n", ioc->name)); + writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &ioc->chip->WriteSequence); + writel(MPI2_WRSEQ_1ST_KEY_VALUE, &ioc->chip->WriteSequence); + writel(MPI2_WRSEQ_2ND_KEY_VALUE, &ioc->chip->WriteSequence); + writel(MPI2_WRSEQ_3RD_KEY_VALUE, &ioc->chip->WriteSequence); + writel(MPI2_WRSEQ_4TH_KEY_VALUE, &ioc->chip->WriteSequence); + writel(MPI2_WRSEQ_5TH_KEY_VALUE, &ioc->chip->WriteSequence); + writel(MPI2_WRSEQ_6TH_KEY_VALUE, &ioc->chip->WriteSequence); + + /* wait 100 msec */ + if (sleep_flag == CAN_SLEEP) + msleep(100); + else + mdelay(100); + + if (count++ > 20) + goto out; + + host_diagnostic = readl(&ioc->chip->HostDiagnostic); + drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "wrote magic " + "sequence: count(%d), host_diagnostic(0x%08x)\n", + ioc->name, count, host_diagnostic)); + + } while ((host_diagnostic & MPI2_DIAG_DIAG_WRITE_ENABLE) == 0); + + hcb_size = readl(&ioc->chip->HCBSize); + + drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "diag reset: issued\n", + ioc->name)); + writel(host_diagnostic | MPI2_DIAG_RESET_ADAPTER, + &ioc->chip->HostDiagnostic); + + /* don't access any registers for 50 milliseconds */ + msleep(50); + + /* 300 second max wait */ + for (count = 0; count < 3000000 ; count++) { + + host_diagnostic = readl(&ioc->chip->HostDiagnostic); + + if (host_diagnostic == 0xFFFFFFFF) + goto out; + if (!(host_diagnostic & MPI2_DIAG_RESET_ADAPTER)) + break; + + /* wait 100 msec */ + if (sleep_flag == CAN_SLEEP) + msleep(1); + else + mdelay(1); + } + + if (host_diagnostic & MPI2_DIAG_HCB_MODE) { + + drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "restart the adapter " + "assuming the HCB Address points to good F/W\n", + ioc->name)); + host_diagnostic &= ~MPI2_DIAG_BOOT_DEVICE_SELECT_MASK; + host_diagnostic |= MPI2_DIAG_BOOT_DEVICE_SELECT_HCDW; + writel(host_diagnostic, &ioc->chip->HostDiagnostic); + + drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT + "re-enable the HCDW\n", ioc->name)); + writel(hcb_size | MPI2_HCB_SIZE_HCB_ENABLE, + &ioc->chip->HCBSize); + } + + drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "restart the adapter\n", + ioc->name)); + writel(host_diagnostic & ~MPI2_DIAG_HOLD_IOC_RESET, + &ioc->chip->HostDiagnostic); + + drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "disable writes to the " + "diagnostic register\n", ioc->name)); + writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &ioc->chip->WriteSequence); + + drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "Wait for FW to go to the " + "READY state\n", ioc->name)); + ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY, 20, + sleep_flag); + if (ioc_state) { + printk(MPT2SAS_ERR_FMT "%s: failed going to ready state " + " (ioc_state=0x%x)\n", ioc->name, __func__, ioc_state); + goto out; + } + + _base_restore_msix_table(ioc); + printk(MPT2SAS_INFO_FMT "diag reset: SUCCESS\n", ioc->name); + return 0; + + out: + printk(MPT2SAS_ERR_FMT "diag reset: FAILED\n", ioc->name); + return -EFAULT; +} + +/** + * _base_make_ioc_ready - put controller in READY state + * @ioc: per adapter object + * @sleep_flag: CAN_SLEEP or NO_SLEEP + * @type: FORCE_BIG_HAMMER or SOFT_RESET + * + * Returns 0 for success, non-zero for failure. + */ +static int +_base_make_ioc_ready(struct MPT2SAS_ADAPTER *ioc, int sleep_flag, + enum reset_type type) +{ + u32 ioc_state; + + dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + __func__)); + + ioc_state = mpt2sas_base_get_iocstate(ioc, 0); + dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: ioc_state(0x%08x)\n", + ioc->name, __func__, ioc_state)); + + if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_READY) + return 0; + + if (ioc_state & MPI2_DOORBELL_USED) { + dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "unexpected doorbell " + "active!\n", ioc->name)); + goto issue_diag_reset; + } + + if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) { + mpt2sas_base_fault_info(ioc, ioc_state & + MPI2_DOORBELL_DATA_MASK); + goto issue_diag_reset; + } + + if (type == FORCE_BIG_HAMMER) + goto issue_diag_reset; + + if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_OPERATIONAL) + if (!(_base_send_ioc_reset(ioc, + MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET, 15, CAN_SLEEP))) + return 0; + + issue_diag_reset: + return _base_diag_reset(ioc, CAN_SLEEP); +} + +/** + * _base_make_ioc_operational - put controller in OPERATIONAL state + * @ioc: per adapter object + * @VF_ID: virtual function id + * @sleep_flag: CAN_SLEEP or NO_SLEEP + * + * Returns 0 for success, non-zero for failure. + */ +static int +_base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, + int sleep_flag) +{ + int r, i; + unsigned long flags; + u32 reply_address; + + dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + __func__)); + + /* initialize the scsi lookup free list */ + spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); + INIT_LIST_HEAD(&ioc->free_list); + for (i = 0; i < ioc->request_depth; i++) { + ioc->scsi_lookup[i].cb_idx = 0xFF; + list_add_tail(&ioc->scsi_lookup[i].tracker_list, + &ioc->free_list); + } + spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); + + /* initialize Reply Free Queue */ + for (i = 0, reply_address = (u32)ioc->reply_dma ; + i < ioc->reply_free_queue_depth ; i++, reply_address += + ioc->reply_sz) + ioc->reply_free[i] = cpu_to_le32(reply_address); + + /* initialize Reply Post Free Queue */ + for (i = 0; i < ioc->reply_post_queue_depth; i++) + ioc->reply_post_free[i].Words = ~0ULL; + + r = _base_send_ioc_init(ioc, VF_ID, sleep_flag); + if (r) + return r; + + /* initialize the index's */ + ioc->reply_free_host_index = ioc->reply_free_queue_depth - 1; + ioc->reply_post_host_index = 0; + writel(ioc->reply_free_host_index, &ioc->chip->ReplyFreeHostIndex); + writel(0, &ioc->chip->ReplyPostHostIndex); + + _base_unmask_interrupts(ioc); + r = _base_event_notification(ioc, VF_ID, sleep_flag); + if (r) + return r; + + if (sleep_flag == CAN_SLEEP) + _base_static_config_pages(ioc); + + r = _base_send_port_enable(ioc, VF_ID, sleep_flag); + if (r) + return r; + + return r; +} + +/** + * mpt2sas_base_free_resources - free resources controller resources (io/irq/memap) + * @ioc: per adapter object + * + * Return nothing. + */ +void +mpt2sas_base_free_resources(struct MPT2SAS_ADAPTER *ioc) +{ + struct pci_dev *pdev = ioc->pdev; + + dexitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + __func__)); + + _base_mask_interrupts(ioc); + _base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET); + if (ioc->pci_irq) { + synchronize_irq(pdev->irq); + free_irq(ioc->pci_irq, ioc); + } + _base_disable_msix(ioc); + if (ioc->chip_phys) + iounmap(ioc->chip); + ioc->pci_irq = -1; + ioc->chip_phys = 0; + pci_release_selected_regions(ioc->pdev, ioc->bars); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + return; +} + +/** + * mpt2sas_base_attach - attach controller instance + * @ioc: per adapter object + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc) +{ + int r, i; + unsigned long flags; + + dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + __func__)); + + r = mpt2sas_base_map_resources(ioc); + if (r) + return r; + + r = _base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET); + if (r) + goto out_free_resources; + + r = _base_get_ioc_facts(ioc, CAN_SLEEP); + if (r) + goto out_free_resources; + + r = _base_allocate_memory_pools(ioc, CAN_SLEEP); + if (r) + goto out_free_resources; + + init_waitqueue_head(&ioc->reset_wq); + + /* base internal command bits */ + mutex_init(&ioc->base_cmds.mutex); + init_completion(&ioc->base_cmds.done); + ioc->base_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); + ioc->base_cmds.status = MPT2_CMD_NOT_USED; + + /* transport internal command bits */ + ioc->transport_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); + ioc->transport_cmds.status = MPT2_CMD_NOT_USED; + mutex_init(&ioc->transport_cmds.mutex); + init_completion(&ioc->transport_cmds.done); + + /* task management internal command bits */ + ioc->tm_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); + ioc->tm_cmds.status = MPT2_CMD_NOT_USED; + mutex_init(&ioc->tm_cmds.mutex); + init_completion(&ioc->tm_cmds.done); + + /* config page internal command bits */ + ioc->config_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); + ioc->config_cmds.status = MPT2_CMD_NOT_USED; + mutex_init(&ioc->config_cmds.mutex); + init_completion(&ioc->config_cmds.done); + + /* ctl module internal command bits */ + ioc->ctl_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); + ioc->ctl_cmds.status = MPT2_CMD_NOT_USED; + mutex_init(&ioc->ctl_cmds.mutex); + init_completion(&ioc->ctl_cmds.done); + + for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++) + ioc->event_masks[i] = -1; + + /* here we enable the events we care about */ + _base_unmask_events(ioc, MPI2_EVENT_SAS_DISCOVERY); + _base_unmask_events(ioc, MPI2_EVENT_SAS_BROADCAST_PRIMITIVE); + _base_unmask_events(ioc, MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST); + _base_unmask_events(ioc, MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE); + _base_unmask_events(ioc, MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE); + _base_unmask_events(ioc, MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST); + _base_unmask_events(ioc, MPI2_EVENT_IR_VOLUME); + _base_unmask_events(ioc, MPI2_EVENT_IR_PHYSICAL_DISK); + _base_unmask_events(ioc, MPI2_EVENT_IR_OPERATION_STATUS); + _base_unmask_events(ioc, MPI2_EVENT_TASK_SET_FULL); + _base_unmask_events(ioc, MPI2_EVENT_LOG_ENTRY_ADDED); + + ioc->pfacts = kcalloc(ioc->facts.NumberOfPorts, + sizeof(Mpi2PortFactsReply_t), GFP_KERNEL); + if (!ioc->pfacts) + goto out_free_resources; + + for (i = 0 ; i < ioc->facts.NumberOfPorts; i++) { + r = _base_get_port_facts(ioc, i, CAN_SLEEP); + if (r) + goto out_free_resources; + } + r = _base_make_ioc_operational(ioc, 0, CAN_SLEEP); + if (r) + goto out_free_resources; + + /* initialize fault polling */ + INIT_DELAYED_WORK(&ioc->fault_reset_work, _base_fault_reset_work); + snprintf(ioc->fault_reset_work_q_name, + sizeof(ioc->fault_reset_work_q_name), "poll_%d_status", ioc->id); + ioc->fault_reset_work_q = + create_singlethread_workqueue(ioc->fault_reset_work_q_name); + if (!ioc->fault_reset_work_q) { + printk(MPT2SAS_ERR_FMT "%s: failed (line=%d)\n", + ioc->name, __func__, __LINE__); + goto out_free_resources; + } + spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); + if (ioc->fault_reset_work_q) + queue_delayed_work(ioc->fault_reset_work_q, + &ioc->fault_reset_work, + msecs_to_jiffies(FAULT_POLLING_INTERVAL)); + spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); + return 0; + + out_free_resources: + + ioc->remove_host = 1; + mpt2sas_base_free_resources(ioc); + _base_release_memory_pools(ioc); + kfree(ioc->tm_cmds.reply); + kfree(ioc->transport_cmds.reply); + kfree(ioc->config_cmds.reply); + kfree(ioc->base_cmds.reply); + kfree(ioc->ctl_cmds.reply); + kfree(ioc->pfacts); + ioc->ctl_cmds.reply = NULL; + ioc->base_cmds.reply = NULL; + ioc->tm_cmds.reply = NULL; + ioc->transport_cmds.reply = NULL; + ioc->config_cmds.reply = NULL; + ioc->pfacts = NULL; + return r; +} + + +/** + * mpt2sas_base_detach - remove controller instance + * @ioc: per adapter object + * + * Return nothing. + */ +void +mpt2sas_base_detach(struct MPT2SAS_ADAPTER *ioc) +{ + unsigned long flags; + struct workqueue_struct *wq; + + dexitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + __func__)); + + spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); + wq = ioc->fault_reset_work_q; + ioc->fault_reset_work_q = NULL; + spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); + if (!cancel_delayed_work(&ioc->fault_reset_work)) + flush_workqueue(wq); + destroy_workqueue(wq); + + mpt2sas_base_free_resources(ioc); + _base_release_memory_pools(ioc); + kfree(ioc->pfacts); + kfree(ioc->ctl_cmds.reply); + kfree(ioc->base_cmds.reply); + kfree(ioc->tm_cmds.reply); + kfree(ioc->transport_cmds.reply); + kfree(ioc->config_cmds.reply); +} + +/** + * _base_reset_handler - reset callback handler (for base) + * @ioc: per adapter object + * @reset_phase: phase + * + * The handler for doing any required cleanup or initialization. + * + * The reset phase can be MPT2_IOC_PRE_RESET, MPT2_IOC_AFTER_RESET, + * MPT2_IOC_DONE_RESET + * + * Return nothing. + */ +static void +_base_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase) +{ + switch (reset_phase) { + case MPT2_IOC_PRE_RESET: + dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " + "MPT2_IOC_PRE_RESET\n", ioc->name, __func__)); + break; + case MPT2_IOC_AFTER_RESET: + dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " + "MPT2_IOC_AFTER_RESET\n", ioc->name, __func__)); + if (ioc->transport_cmds.status & MPT2_CMD_PENDING) { + ioc->transport_cmds.status |= MPT2_CMD_RESET; + mpt2sas_base_free_smid(ioc, ioc->transport_cmds.smid); + complete(&ioc->transport_cmds.done); + } + if (ioc->base_cmds.status & MPT2_CMD_PENDING) { + ioc->base_cmds.status |= MPT2_CMD_RESET; + mpt2sas_base_free_smid(ioc, ioc->base_cmds.smid); + complete(&ioc->base_cmds.done); + } + if (ioc->config_cmds.status & MPT2_CMD_PENDING) { + ioc->config_cmds.status |= MPT2_CMD_RESET; + mpt2sas_base_free_smid(ioc, ioc->config_cmds.smid); + complete(&ioc->config_cmds.done); + } + break; + case MPT2_IOC_DONE_RESET: + dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " + "MPT2_IOC_DONE_RESET\n", ioc->name, __func__)); + break; + } + mpt2sas_scsih_reset_handler(ioc, reset_phase); + mpt2sas_ctl_reset_handler(ioc, reset_phase); +} + +/** + * _wait_for_commands_to_complete - reset controller + * @ioc: Pointer to MPT_ADAPTER structure + * @sleep_flag: CAN_SLEEP or NO_SLEEP + * + * This function waiting(3s) for all pending commands to complete + * prior to putting controller in reset. + */ +static void +_wait_for_commands_to_complete(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) +{ + u32 ioc_state; + unsigned long flags; + u16 i; + + ioc->pending_io_count = 0; + if (sleep_flag != CAN_SLEEP) + return; + + ioc_state = mpt2sas_base_get_iocstate(ioc, 0); + if ((ioc_state & MPI2_IOC_STATE_MASK) != MPI2_IOC_STATE_OPERATIONAL) + return; + + /* pending command count */ + spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); + for (i = 0; i < ioc->request_depth; i++) + if (ioc->scsi_lookup[i].cb_idx != 0xFF) + ioc->pending_io_count++; + spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); + + if (!ioc->pending_io_count) + return; + + /* wait for pending commands to complete */ + wait_event_timeout(ioc->reset_wq, ioc->pending_io_count == 0, 3 * HZ); +} + +/** + * mpt2sas_base_hard_reset_handler - reset controller + * @ioc: Pointer to MPT_ADAPTER structure + * @sleep_flag: CAN_SLEEP or NO_SLEEP + * @type: FORCE_BIG_HAMMER or SOFT_RESET + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag, + enum reset_type type) +{ + int r, i; + unsigned long flags; + + dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name, + __func__)); + + spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); + if (ioc->ioc_reset_in_progress) { + spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); + printk(MPT2SAS_ERR_FMT "%s: busy\n", + ioc->name, __func__); + return -EBUSY; + } + ioc->ioc_reset_in_progress = 1; + ioc->shost_recovery = 1; + if (ioc->shost->shost_state == SHOST_RUNNING) { + /* set back to SHOST_RUNNING in mpt2sas_scsih.c */ + scsi_host_set_state(ioc->shost, SHOST_RECOVERY); + printk(MPT2SAS_INFO_FMT "putting controller into " + "SHOST_RECOVERY\n", ioc->name); + } + spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); + + _base_reset_handler(ioc, MPT2_IOC_PRE_RESET); + _wait_for_commands_to_complete(ioc, sleep_flag); + _base_mask_interrupts(ioc); + r = _base_make_ioc_ready(ioc, sleep_flag, type); + if (r) + goto out; + _base_reset_handler(ioc, MPT2_IOC_AFTER_RESET); + for (i = 0 ; i < ioc->facts.NumberOfPorts; i++) + r = _base_make_ioc_operational(ioc, ioc->pfacts[i].VF_ID, + sleep_flag); + if (!r) + _base_reset_handler(ioc, MPT2_IOC_DONE_RESET); + out: + dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: %s\n", + ioc->name, __func__, ((r == 0) ? "SUCCESS" : "FAILED"))); + + spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); + ioc->ioc_reset_in_progress = 0; + spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); + return r; +} diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h new file mode 100644 index 00000000000..6945ff4d382 --- /dev/null +++ b/drivers/scsi/mpt2sas/mpt2sas_base.h @@ -0,0 +1,779 @@ +/* + * This is the Fusion MPT base driver providing common API layer interface + * for access to MPT (Message Passing Technology) firmware. + * + * This code is based on drivers/scsi/mpt2sas/mpt2_base.h + * Copyright (C) 2007-2008 LSI Corporation + * (mailto:DL-MPTFusionLinux@lsi.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. + * + * NO WARRANTY + * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT + * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is + * solely responsible for determining the appropriateness of using and + * distributing the Program and assumes all risks associated with its + * exercise of rights under this Agreement, including but not limited to + * the risks and costs of program errors, damage to or loss of data, + * programs or equipment, and unavailability or interruption of operations. + + * DISCLAIMER OF LIABILITY + * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED + * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES + + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ + +#ifndef MPT2SAS_BASE_H_INCLUDED +#define MPT2SAS_BASE_H_INCLUDED + +#include "mpi/mpi2_type.h" +#include "mpi/mpi2.h" +#include "mpi/mpi2_ioc.h" +#include "mpi/mpi2_cnfg.h" +#include "mpi/mpi2_init.h" +#include "mpi/mpi2_raid.h" +#include "mpi/mpi2_tool.h" +#include "mpi/mpi2_sas.h" + +#include <scsi/scsi.h> +#include <scsi/scsi_cmnd.h> +#include <scsi/scsi_device.h> +#include <scsi/scsi_host.h> +#include <scsi/scsi_tcq.h> +#include <scsi/scsi_transport_sas.h> +#include <scsi/scsi_dbg.h> + +#include "mpt2sas_debug.h" + +/* driver versioning info */ +#define MPT2SAS_DRIVER_NAME "mpt2sas" +#define MPT2SAS_AUTHOR "LSI Corporation <DL-MPTFusionLinux@lsi.com>" +#define MPT2SAS_DESCRIPTION "LSI MPT Fusion SAS 2.0 Device Driver" +#define MPT2SAS_DRIVER_VERSION "00.100.11.16" +#define MPT2SAS_MAJOR_VERSION 00 +#define MPT2SAS_MINOR_VERSION 100 +#define MPT2SAS_BUILD_VERSION 11 +#define MPT2SAS_RELEASE_VERSION 16 + +/* + * Set MPT2SAS_SG_DEPTH value based on user input. + */ +#ifdef CONFIG_SCSI_MPT2SAS_MAX_SGE +#if CONFIG_SCSI_MPT2SAS_MAX_SGE < 16 +#define MPT2SAS_SG_DEPTH 16 +#elif CONFIG_SCSI_MPT2SAS_MAX_SGE > 128 +#define MPT2SAS_SG_DEPTH 128 +#else +#define MPT2SAS_SG_DEPTH CONFIG_SCSI_MPT2SAS_MAX_SGE +#endif +#else +#define MPT2SAS_SG_DEPTH 128 /* MAX_HW_SEGMENTS */ +#endif + + +/* + * Generic Defines + */ +#define MPT2SAS_SATA_QUEUE_DEPTH 32 +#define MPT2SAS_SAS_QUEUE_DEPTH 254 +#define MPT2SAS_RAID_QUEUE_DEPTH 128 + +#define MPT_NAME_LENGTH 32 /* generic length of strings */ +#define MPT_STRING_LENGTH 64 + +#define MPT_MAX_CALLBACKS 16 + +#define CAN_SLEEP 1 +#define NO_SLEEP 0 + +#define INTERNAL_CMDS_COUNT 10 /* reserved cmds */ + +#define MPI2_HIM_MASK 0xFFFFFFFF /* mask every bit*/ + +#define MPT2SAS_INVALID_DEVICE_HANDLE 0xFFFF + + +/* + * reset phases + */ +#define MPT2_IOC_PRE_RESET 1 /* prior to host reset */ +#define MPT2_IOC_AFTER_RESET 2 /* just after host reset */ +#define MPT2_IOC_DONE_RESET 3 /* links re-initialized */ + +/* + * logging format + */ +#define MPT2SAS_FMT "%s: " +#define MPT2SAS_DEBUG_FMT KERN_DEBUG MPT2SAS_FMT +#define MPT2SAS_INFO_FMT KERN_INFO MPT2SAS_FMT +#define MPT2SAS_NOTE_FMT KERN_NOTICE MPT2SAS_FMT +#define MPT2SAS_WARN_FMT KERN_WARNING MPT2SAS_FMT +#define MPT2SAS_ERR_FMT KERN_ERR MPT2SAS_FMT + +/* + * per target private data + */ +#define MPT_TARGET_FLAGS_RAID_COMPONENT 0x01 +#define MPT_TARGET_FLAGS_VOLUME 0x02 +#define MPT_TARGET_FLAGS_DELETED 0x04 + +/** + * struct MPT2SAS_TARGET - starget private hostdata + * @starget: starget object + * @sas_address: target sas address + * @handle: device handle + * @num_luns: number luns + * @flags: MPT_TARGET_FLAGS_XXX flags + * @deleted: target flaged for deletion + * @tm_busy: target is busy with TM request. + */ +struct MPT2SAS_TARGET { + struct scsi_target *starget; + u64 sas_address; + u16 handle; + int num_luns; + u32 flags; + u8 deleted; + u8 tm_busy; +}; + +/* + * per device private data + */ +#define MPT_DEVICE_FLAGS_INIT 0x01 +#define MPT_DEVICE_TLR_ON 0x02 + +/** + * struct MPT2SAS_DEVICE - sdev private hostdata + * @sas_target: starget private hostdata + * @lun: lun number + * @flags: MPT_DEVICE_XXX flags + * @configured_lun: lun is configured + * @block: device is in SDEV_BLOCK state + * @tlr_snoop_check: flag used in determining whether to disable TLR + */ +struct MPT2SAS_DEVICE { + struct MPT2SAS_TARGET *sas_target; + unsigned int lun; + u32 flags; + u8 configured_lun; + u8 block; + u8 tlr_snoop_check; +}; + +#define MPT2_CMD_NOT_USED 0x8000 /* free */ +#define MPT2_CMD_COMPLETE 0x0001 /* completed */ +#define MPT2_CMD_PENDING 0x0002 /* pending */ +#define MPT2_CMD_REPLY_VALID 0x0004 /* reply is valid */ +#define MPT2_CMD_RESET 0x0008 /* host reset dropped the command */ + +/** + * struct _internal_cmd - internal commands struct + * @mutex: mutex + * @done: completion + * @reply: reply message pointer + * @status: MPT2_CMD_XXX status + * @smid: system message id + */ +struct _internal_cmd { + struct mutex mutex; + struct completion done; + void *reply; + u16 status; + u16 smid; +}; + +/* + * SAS Topology Structures + */ + +/** + * struct _sas_device - attached device information + * @list: sas device list + * @starget: starget object + * @sas_address: device sas address + * @device_name: retrieved from the SAS IDENTIFY frame. + * @handle: device handle + * @parent_handle: handle to parent device + * @enclosure_handle: enclosure handle + * @enclosure_logical_id: enclosure logical identifier + * @volume_handle: volume handle (valid when hidden raid member) + * @volume_wwid: volume unique identifier + * @device_info: bitfield provides detailed info about the device + * @id: target id + * @channel: target channel + * @slot: number number + * @hidden_raid_component: set to 1 when this is a raid member + * @responding: used in _scsih_sas_device_mark_responding + */ +struct _sas_device { + struct list_head list; + struct scsi_target *starget; + u64 sas_address; + u64 device_name; + u16 handle; + u16 parent_handle; + u16 enclosure_handle; + u64 enclosure_logical_id; + u16 volume_handle; + u64 volume_wwid; + u32 device_info; + int id; + int channel; + u16 slot; + u8 hidden_raid_component; + u8 responding; +}; + +/** + * struct _raid_device - raid volume link list + * @list: sas device list + * @starget: starget object + * @sdev: scsi device struct (volumes are single lun) + * @wwid: unique identifier for the volume + * @handle: device handle + * @id: target id + * @channel: target channel + * @volume_type: the raid level + * @device_info: bitfield provides detailed info about the hidden components + * @num_pds: number of hidden raid components + * @responding: used in _scsih_raid_device_mark_responding + */ +struct _raid_device { + struct list_head list; + struct scsi_target *starget; + struct scsi_device *sdev; + u64 wwid; + u16 handle; + int id; + int channel; + u8 volume_type; + u32 device_info; + u8 num_pds; + u8 responding; +}; + +/** + * struct _boot_device - boot device info + * @is_raid: flag to indicate whether this is volume + * @device: holds pointer for either struct _sas_device or + * struct _raid_device + */ +struct _boot_device { + u8 is_raid; + void *device; +}; + +/** + * struct _sas_port - wide/narrow sas port information + * @port_list: list of ports belonging to expander + * @handle: device handle for this port + * @sas_address: sas address of this port + * @num_phys: number of phys belonging to this port + * @remote_identify: attached device identification + * @rphy: sas transport rphy object + * @port: sas transport wide/narrow port object + * @phy_list: _sas_phy list objects belonging to this port + */ +struct _sas_port { + struct list_head port_list; + u16 handle; + u64 sas_address; + u8 num_phys; + struct sas_identify remote_identify; + struct sas_rphy *rphy; + struct sas_port *port; + struct list_head phy_list; +}; + +/** + * struct _sas_phy - phy information + * @port_siblings: list of phys belonging to a port + * @identify: phy identification + * @remote_identify: attached device identification + * @phy: sas transport phy object + * @phy_id: unique phy id + * @handle: device handle for this phy + * @attached_handle: device handle for attached device + */ +struct _sas_phy { + struct list_head port_siblings; + struct sas_identify identify; + struct sas_identify remote_identify; + struct sas_phy *phy; + u8 phy_id; + u16 handle; + u16 attached_handle; +}; + +/** + * struct _sas_node - sas_host/expander information + * @list: list of expanders + * @parent_dev: parent device class + * @num_phys: number phys belonging to this sas_host/expander + * @sas_address: sas address of this sas_host/expander + * @handle: handle for this sas_host/expander + * @parent_handle: parent handle + * @enclosure_handle: handle for this a member of an enclosure + * @device_info: bitwise defining capabilities of this sas_host/expander + * @responding: used in _scsih_expander_device_mark_responding + * @phy: a list of phys that make up this sas_host/expander + * @sas_port_list: list of ports attached to this sas_host/expander + */ +struct _sas_node { + struct list_head list; + struct device *parent_dev; + u8 num_phys; + u64 sas_address; + u16 handle; + u16 parent_handle; + u16 enclosure_handle; + u64 enclosure_logical_id; + u8 responding; + struct _sas_phy *phy; + struct list_head sas_port_list; +}; + +/** + * enum reset_type - reset state + * @FORCE_BIG_HAMMER: issue diagnostic reset + * @SOFT_RESET: issue message_unit_reset, if fails to to big hammer + */ +enum reset_type { + FORCE_BIG_HAMMER, + SOFT_RESET, +}; + +/** + * struct request_tracker - firmware request tracker + * @smid: system message id + * @scmd: scsi request pointer + * @cb_idx: callback index + * @chain_list: list of chains associated to this IO + * @tracker_list: list of free request (ioc->free_list) + */ +struct request_tracker { + u16 smid; + struct scsi_cmnd *scmd; + u8 cb_idx; + struct list_head tracker_list; +}; + +typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr); + +/** + * struct MPT2SAS_ADAPTER - per adapter struct + * @list: ioc_list + * @shost: shost object + * @id: unique adapter id + * @pci_irq: irq number + * @name: generic ioc string + * @tmp_string: tmp string used for logging + * @pdev: pci pdev object + * @chip: memory mapped register space + * @chip_phys: physical addrss prior to mapping + * @pio_chip: I/O mapped register space + * @logging_level: see mpt2sas_debug.h + * @ir_firmware: IR firmware present + * @bars: bitmask of BAR's that must be configured + * @mask_interrupts: ignore interrupt + * @fault_reset_work_q_name: fw fault work queue + * @fault_reset_work_q: "" + * @fault_reset_work: "" + * @firmware_event_name: fw event work queue + * @firmware_event_thread: "" + * @fw_events_off: flag to turn off fw event handling + * @fw_event_lock: + * @fw_event_list: list of fw events + * @aen_event_read_flag: event log was read + * @broadcast_aen_busy: broadcast aen waiting to be serviced + * @ioc_reset_in_progress: host reset in progress + * @ioc_reset_in_progress_lock: + * @ioc_link_reset_in_progress: phy/hard reset in progress + * @ignore_loginfos: ignore loginfos during task managment + * @remove_host: flag for when driver unloads, to avoid sending dev resets + * @wait_for_port_enable_to_complete: + * @msix_enable: flag indicating msix is enabled + * @msix_vector_count: number msix vectors + * @msix_table: virt address to the msix table + * @msix_table_backup: backup msix table + * @scsi_io_cb_idx: shost generated commands + * @tm_cb_idx: task management commands + * @transport_cb_idx: transport internal commands + * @ctl_cb_idx: clt internal commands + * @base_cb_idx: base internal commands + * @config_cb_idx: base internal commands + * @base_cmds: + * @transport_cmds: + * @tm_cmds: + * @ctl_cmds: + * @config_cmds: + * @base_add_sg_single: handler for either 32/64 bit sgl's + * @event_type: bits indicating which events to log + * @event_context: unique id for each logged event + * @event_log: event log pointer + * @event_masks: events that are masked + * @facts: static facts data + * @pfacts: static port facts data + * @manu_pg0: static manufacturing page 0 + * @bios_pg2: static bios page 2 + * @bios_pg3: static bios page 3 + * @ioc_pg8: static ioc page 8 + * @iounit_pg0: static iounit page 0 + * @iounit_pg1: static iounit page 1 + * @sas_hba: sas host object + * @sas_expander_list: expander object list + * @sas_node_lock: + * @sas_device_list: sas device object list + * @sas_device_init_list: sas device object list (used only at init time) + * @sas_device_lock: + * @io_missing_delay: time for IO completed by fw when PDR enabled + * @device_missing_delay: time for device missing by fw when PDR enabled + * @config_page_sz: config page size + * @config_page: reserve memory for config page payload + * @config_page_dma: + * @sge_size: sg element size for either 32/64 bit + * @request_depth: hba request queue depth + * @request_sz: per request frame size + * @request: pool of request frames + * @request_dma: + * @request_dma_sz: + * @scsi_lookup: firmware request tracker list + * @scsi_lookup_lock: + * @free_list: free list of request + * @chain: pool of chains + * @pending_io_count: + * @reset_wq: + * @chain_dma: + * @max_sges_in_main_message: number sg elements in main message + * @max_sges_in_chain_message: number sg elements per chain + * @chains_needed_per_io: max chains per io + * @chain_offset_value_for_main_message: location 1st sg in main + * @chain_depth: total chains allocated + * @sense: pool of sense + * @sense_dma: + * @sense_dma_pool: + * @reply_depth: hba reply queue depth: + * @reply_sz: per reply frame size: + * @reply: pool of replys: + * @reply_dma: + * @reply_dma_pool: + * @reply_free_queue_depth: reply free depth + * @reply_free: pool for reply free queue (32 bit addr) + * @reply_free_dma: + * @reply_free_dma_pool: + * @reply_free_host_index: tail index in pool to insert free replys + * @reply_post_queue_depth: reply post queue depth + * @reply_post_free: pool for reply post (64bit descriptor) + * @reply_post_free_dma: + * @reply_post_free_dma_pool: + * @reply_post_host_index: head index in the pool where FW completes IO + */ +struct MPT2SAS_ADAPTER { + struct list_head list; + struct Scsi_Host *shost; + u8 id; + u32 pci_irq; + char name[MPT_NAME_LENGTH]; + char tmp_string[MPT_STRING_LENGTH]; + struct pci_dev *pdev; + Mpi2SystemInterfaceRegs_t __iomem *chip; + unsigned long chip_phys; + unsigned long pio_chip; + int logging_level; + u8 ir_firmware; + int bars; + u8 mask_interrupts; + + /* fw fault handler */ + char fault_reset_work_q_name[20]; + struct workqueue_struct *fault_reset_work_q; + struct delayed_work fault_reset_work; + + /* fw event handler */ + char firmware_event_name[20]; + struct workqueue_struct *firmware_event_thread; + u8 fw_events_off; + spinlock_t fw_event_lock; + struct list_head fw_event_list; + + /* misc flags */ + int aen_event_read_flag; + u8 broadcast_aen_busy; + u8 ioc_reset_in_progress; + u8 shost_recovery; + spinlock_t ioc_reset_in_progress_lock; + u8 ioc_link_reset_in_progress; + u8 ignore_loginfos; + u8 remove_host; + u8 wait_for_port_enable_to_complete; + + u8 msix_enable; + u16 msix_vector_count; + u32 *msix_table; + u32 *msix_table_backup; + + /* internal commands, callback index */ + u8 scsi_io_cb_idx; + u8 tm_cb_idx; + u8 transport_cb_idx; + u8 ctl_cb_idx; + u8 base_cb_idx; + u8 config_cb_idx; + struct _internal_cmd base_cmds; + struct _internal_cmd transport_cmds; + struct _internal_cmd tm_cmds; + struct _internal_cmd ctl_cmds; + struct _internal_cmd config_cmds; + + MPT_ADD_SGE base_add_sg_single; + + /* event log */ + u32 event_type[MPI2_EVENT_NOTIFY_EVENTMASK_WORDS]; + u32 event_context; + void *event_log; + u32 event_masks[MPI2_EVENT_NOTIFY_EVENTMASK_WORDS]; + + /* static config pages */ + Mpi2IOCFactsReply_t facts; + Mpi2PortFactsReply_t *pfacts; + Mpi2ManufacturingPage0_t manu_pg0; + Mpi2BiosPage2_t bios_pg2; + Mpi2BiosPage3_t bios_pg3; + Mpi2IOCPage8_t ioc_pg8; + Mpi2IOUnitPage0_t iounit_pg0; + Mpi2IOUnitPage1_t iounit_pg1; + + struct _boot_device req_boot_device; + struct _boot_device req_alt_boot_device; + struct _boot_device current_boot_device; + + /* sas hba, expander, and device list */ + struct _sas_node sas_hba; + struct list_head sas_expander_list; + spinlock_t sas_node_lock; + struct list_head sas_device_list; + struct list_head sas_device_init_list; + spinlock_t sas_device_lock; + struct list_head raid_device_list; + spinlock_t raid_device_lock; + u8 io_missing_delay; + u16 device_missing_delay; + int sas_id; + + /* config page */ + u16 config_page_sz; + void *config_page; + dma_addr_t config_page_dma; + + /* request */ + u16 sge_size; + u16 request_depth; + u16 request_sz; + u8 *request; + dma_addr_t request_dma; + u32 request_dma_sz; + struct request_tracker *scsi_lookup; + spinlock_t scsi_lookup_lock; + struct list_head free_list; + int pending_io_count; + wait_queue_head_t reset_wq; + + /* chain */ + u8 *chain; + dma_addr_t chain_dma; + u16 max_sges_in_main_message; + u16 max_sges_in_chain_message; + u16 chains_needed_per_io; + u16 chain_offset_value_for_main_message; + u16 chain_depth; + + /* sense */ + u8 *sense; + dma_addr_t sense_dma; + struct dma_pool *sense_dma_pool; + + /* reply */ + u16 reply_sz; + u8 *reply; + dma_addr_t reply_dma; + struct dma_pool *reply_dma_pool; + + /* reply free queue */ + u16 reply_free_queue_depth; + u32 *reply_free; + dma_addr_t reply_free_dma; + struct dma_pool *reply_free_dma_pool; + u32 reply_free_host_index; + + /* reply post queue */ + u16 reply_post_queue_depth; + Mpi2ReplyDescriptorsUnion_t *reply_post_free; + dma_addr_t reply_post_free_dma; + struct dma_pool *reply_post_free_dma_pool; + u32 reply_post_host_index; + + /* diag buffer support */ + u8 *diag_buffer[MPI2_DIAG_BUF_TYPE_COUNT]; + u32 diag_buffer_sz[MPI2_DIAG_BUF_TYPE_COUNT]; + dma_addr_t diag_buffer_dma[MPI2_DIAG_BUF_TYPE_COUNT]; + u8 diag_buffer_status[MPI2_DIAG_BUF_TYPE_COUNT]; + u32 unique_id[MPI2_DIAG_BUF_TYPE_COUNT]; + u32 product_specific[MPI2_DIAG_BUF_TYPE_COUNT][23]; + u32 diagnostic_flags[MPI2_DIAG_BUF_TYPE_COUNT]; +}; + +typedef void (*MPT_CALLBACK)(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, + u32 reply); + + +/* base shared API */ +extern struct list_head mpt2sas_ioc_list; + +int mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc); +void mpt2sas_base_detach(struct MPT2SAS_ADAPTER *ioc); +int mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc); +void mpt2sas_base_free_resources(struct MPT2SAS_ADAPTER *ioc); +int mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag, + enum reset_type type); + +void *mpt2sas_base_get_msg_frame(struct MPT2SAS_ADAPTER *ioc, u16 smid); +void *mpt2sas_base_get_sense_buffer(struct MPT2SAS_ADAPTER *ioc, u16 smid); +void mpt2sas_base_build_zero_len_sge(struct MPT2SAS_ADAPTER *ioc, void *paddr); +dma_addr_t mpt2sas_base_get_msg_frame_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid); +dma_addr_t mpt2sas_base_get_sense_buffer_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid); + +u16 mpt2sas_base_get_smid(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx); +void mpt2sas_base_free_smid(struct MPT2SAS_ADAPTER *ioc, u16 smid); +void mpt2sas_base_put_smid_scsi_io(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 vf_id, + u16 handle); +void mpt2sas_base_put_smid_hi_priority(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 vf_id); +void mpt2sas_base_put_smid_target_assist(struct MPT2SAS_ADAPTER *ioc, u16 smid, + u8 vf_id, u16 io_index); +void mpt2sas_base_put_smid_default(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 vf_id); +void mpt2sas_base_initialize_callback_handler(void); +u8 mpt2sas_base_register_callback_handler(MPT_CALLBACK cb_func); +void mpt2sas_base_release_callback_handler(u8 cb_idx); + +void mpt2sas_base_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply); +void *mpt2sas_base_get_reply_virt_addr(struct MPT2SAS_ADAPTER *ioc, u32 phys_addr); + +u32 mpt2sas_base_get_iocstate(struct MPT2SAS_ADAPTER *ioc, int cooked); + +void mpt2sas_base_fault_info(struct MPT2SAS_ADAPTER *ioc , u16 fault_code); +int mpt2sas_base_sas_iounit_control(struct MPT2SAS_ADAPTER *ioc, + Mpi2SasIoUnitControlReply_t *mpi_reply, Mpi2SasIoUnitControlRequest_t + *mpi_request); +int mpt2sas_base_scsi_enclosure_processor(struct MPT2SAS_ADAPTER *ioc, + Mpi2SepReply_t *mpi_reply, Mpi2SepRequest_t *mpi_request); +void mpt2sas_base_validate_event_type(struct MPT2SAS_ADAPTER *ioc, u32 *event_type); + +/* scsih shared API */ +void mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun, + u8 type, u16 smid_task, ulong timeout); +void mpt2sas_scsih_set_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle); +void mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle); +struct _sas_node *mpt2sas_scsih_expander_find_by_handle(struct MPT2SAS_ADAPTER *ioc, + u16 handle); +struct _sas_node *mpt2sas_scsih_expander_find_by_sas_address(struct MPT2SAS_ADAPTER + *ioc, u64 sas_address); +struct _sas_device *mpt2sas_scsih_sas_device_find_by_sas_address( + struct MPT2SAS_ADAPTER *ioc, u64 sas_address); + +void mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply); +void mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase); + +/* config shared API */ +void mpt2sas_config_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply); +int mpt2sas_config_get_number_hba_phys(struct MPT2SAS_ADAPTER *ioc, u8 *num_phys); +int mpt2sas_config_get_manufacturing_pg0(struct MPT2SAS_ADAPTER *ioc, + Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage0_t *config_page); +int mpt2sas_config_get_bios_pg2(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t + *mpi_reply, Mpi2BiosPage2_t *config_page); +int mpt2sas_config_get_bios_pg3(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t + *mpi_reply, Mpi2BiosPage3_t *config_page); +int mpt2sas_config_get_iounit_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t + *mpi_reply, Mpi2IOUnitPage0_t *config_page); +int mpt2sas_config_get_sas_device_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t + *mpi_reply, Mpi2SasDevicePage0_t *config_page, u32 form, u32 handle); +int mpt2sas_config_get_sas_device_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t + *mpi_reply, Mpi2SasDevicePage1_t *config_page, u32 form, u32 handle); +int mpt2sas_config_get_sas_iounit_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t + *mpi_reply, Mpi2SasIOUnitPage0_t *config_page, u16 sz); +int mpt2sas_config_get_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t + *mpi_reply, Mpi2IOUnitPage1_t *config_page); +int mpt2sas_config_set_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t + *mpi_reply, Mpi2IOUnitPage1_t config_page); +int mpt2sas_config_get_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t + *mpi_reply, Mpi2SasIOUnitPage1_t *config_page, u16 sz); +int mpt2sas_config_get_ioc_pg8(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t + *mpi_reply, Mpi2IOCPage8_t *config_page); +int mpt2sas_config_get_expander_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t + *mpi_reply, Mpi2ExpanderPage0_t *config_page, u32 form, u32 handle); +int mpt2sas_config_get_expander_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t + *mpi_reply, Mpi2ExpanderPage1_t *config_page, u32 phy_number, u16 handle); +int mpt2sas_config_get_enclosure_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t + *mpi_reply, Mpi2SasEnclosurePage0_t *config_page, u32 form, u32 handle); +int mpt2sas_config_get_phy_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t + *mpi_reply, Mpi2SasPhyPage0_t *config_page, u32 phy_number); +int mpt2sas_config_get_phy_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t + *mpi_reply, Mpi2SasPhyPage1_t *config_page, u32 phy_number); +int mpt2sas_config_get_raid_volume_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t + *mpi_reply, Mpi2RaidVolPage1_t *config_page, u32 form, u32 handle); +int mpt2sas_config_get_number_pds(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 *num_pds); +int mpt2sas_config_get_raid_volume_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t + *mpi_reply, Mpi2RaidVolPage0_t *config_page, u32 form, u32 handle, u16 sz); +int mpt2sas_config_get_phys_disk_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t + *mpi_reply, Mpi2RaidPhysDiskPage0_t *config_page, u32 form, + u32 form_specific); +int mpt2sas_config_get_volume_handle(struct MPT2SAS_ADAPTER *ioc, u16 pd_handle, + u16 *volume_handle); +int mpt2sas_config_get_volume_wwid(struct MPT2SAS_ADAPTER *ioc, u16 volume_handle, + u64 *wwid); + +/* ctl shared API */ +extern struct device_attribute *mpt2sas_host_attrs[]; +extern struct device_attribute *mpt2sas_dev_attrs[]; +void mpt2sas_ctl_init(void); +void mpt2sas_ctl_exit(void); +void mpt2sas_ctl_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply); +void mpt2sas_ctl_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase); +void mpt2sas_ctl_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply); +void mpt2sas_ctl_add_to_event_log(struct MPT2SAS_ADAPTER *ioc, + Mpi2EventNotificationReply_t *mpi_reply); + +/* transport shared API */ +void mpt2sas_transport_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply); +struct _sas_port *mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, + u16 handle, u16 parent_handle); +void mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address, + u16 parent_handle); +int mpt2sas_transport_add_host_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy + *mpt2sas_phy, Mpi2SasPhyPage0_t phy_pg0, struct device *parent_dev); +int mpt2sas_transport_add_expander_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy + *mpt2sas_phy, Mpi2ExpanderPage1_t expander_pg1, struct device *parent_dev); +void mpt2sas_transport_update_phy_link_change(struct MPT2SAS_ADAPTER *ioc, u16 handle, + u16 attached_handle, u8 phy_number, u8 link_rate); +extern struct sas_function_template mpt2sas_transport_functions; +extern struct scsi_transport_template *mpt2sas_transport_template; + +#endif /* MPT2SAS_BASE_H_INCLUDED */ diff --git a/drivers/scsi/mpt2sas/mpt2sas_config.c b/drivers/scsi/mpt2sas/mpt2sas_config.c new file mode 100644 index 00000000000..58cfb97846f --- /dev/null +++ b/drivers/scsi/mpt2sas/mpt2sas_config.c @@ -0,0 +1,1873 @@ +/* + * This module provides common API for accessing firmware configuration pages + * + * This code is based on drivers/scsi/mpt2sas/mpt2_base.c + * Copyright (C) 2007-2008 LSI Corporation + * (mailto:DL-MPTFusionLinux@lsi.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. + * + * NO WARRANTY + * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT + * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is + * solely responsible for determining the appropriateness of using and + * distributing the Program and assumes all risks associated with its + * exercise of rights under this Agreement, including but not limited to + * the risks and costs of program errors, damage to or loss of data, + * programs or equipment, and unavailability or interruption of operations. + + * DISCLAIMER OF LIABILITY + * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED + * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES + + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ + +#include <linux/version.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/blkdev.h> +#include <linux/sched.h> +#include <linux/workqueue.h> +#include <linux/delay.h> +#include <linux/pci.h> + +#include "mpt2sas_base.h" + +/* local definitions */ + +/* Timeout for config page request (in seconds) */ +#define MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT 15 + +/* Common sgl flags for READING a config page. */ +#define MPT2_CONFIG_COMMON_SGLFLAGS ((MPI2_SGE_FLAGS_SIMPLE_ELEMENT | \ + MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER \ + | MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT) + +/* Common sgl flags for WRITING a config page. */ +#define MPT2_CONFIG_COMMON_WRITE_SGLFLAGS ((MPI2_SGE_FLAGS_SIMPLE_ELEMENT | \ + MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER \ + | MPI2_SGE_FLAGS_END_OF_LIST | MPI2_SGE_FLAGS_HOST_TO_IOC) \ + << MPI2_SGE_FLAGS_SHIFT) + +/** + * struct config_request - obtain dma memory via routine + * @config_page_sz: size + * @config_page: virt pointer + * @config_page_dma: phys pointer + * + */ +struct config_request{ + u16 config_page_sz; + void *config_page; + dma_addr_t config_page_dma; +}; + +#ifdef CONFIG_SCSI_MPT2SAS_LOGGING +/** + * _config_display_some_debug - debug routine + * @ioc: per adapter object + * @smid: system request message index + * @calling_function_name: string pass from calling function + * @mpi_reply: reply message frame + * Context: none. + * + * Function for displaying debug info helpfull when debugging issues + * in this module. + */ +static void +_config_display_some_debug(struct MPT2SAS_ADAPTER *ioc, u16 smid, + char *calling_function_name, MPI2DefaultReply_t *mpi_reply) +{ + Mpi2ConfigRequest_t *mpi_request; + char *desc = NULL; + + if (!(ioc->logging_level & MPT_DEBUG_CONFIG)) + return; + + mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); + switch (mpi_request->Header.PageType & MPI2_CONFIG_PAGETYPE_MASK) { + case MPI2_CONFIG_PAGETYPE_IO_UNIT: + desc = "io_unit"; + break; + case MPI2_CONFIG_PAGETYPE_IOC: + desc = "ioc"; + break; + case MPI2_CONFIG_PAGETYPE_BIOS: + desc = "bios"; + break; + case MPI2_CONFIG_PAGETYPE_RAID_VOLUME: + desc = "raid_volume"; + break; + case MPI2_CONFIG_PAGETYPE_MANUFACTURING: + desc = "manufaucturing"; + break; + case MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK: + desc = "physdisk"; + break; + case MPI2_CONFIG_PAGETYPE_EXTENDED: + switch (mpi_request->ExtPageType) { + case MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT: + desc = "sas_io_unit"; + break; + case MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER: + desc = "sas_expander"; + break; + case MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE: + desc = "sas_device"; + break; + case MPI2_CONFIG_EXTPAGETYPE_SAS_PHY: + desc = "sas_phy"; + break; + case MPI2_CONFIG_EXTPAGETYPE_LOG: + desc = "log"; + break; + case MPI2_CONFIG_EXTPAGETYPE_ENCLOSURE: + desc = "enclosure"; + break; + case MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG: + desc = "raid_config"; + break; + case MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING: + desc = "driver_mappping"; + break; + } + break; + } + + if (!desc) + return; + + printk(MPT2SAS_DEBUG_FMT "%s: %s(%d), action(%d), form(0x%08x), " + "smid(%d)\n", ioc->name, calling_function_name, desc, + mpi_request->Header.PageNumber, mpi_request->Action, + le32_to_cpu(mpi_request->PageAddress), smid); + + if (!mpi_reply) + return; + + if (mpi_reply->IOCStatus || mpi_reply->IOCLogInfo) + printk(MPT2SAS_DEBUG_FMT + "\tiocstatus(0x%04x), loginfo(0x%08x)\n", + ioc->name, le16_to_cpu(mpi_reply->IOCStatus), + le32_to_cpu(mpi_reply->IOCLogInfo)); +} +#endif + +/** + * mpt2sas_config_done - config page completion routine + * @ioc: per adapter object + * @smid: system request message index + * @VF_ID: virtual function id + * @reply: reply message frame(lower 32bit addr) + * Context: none. + * + * The callback handler when using _config_request. + * + * Return nothing. + */ +void +mpt2sas_config_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply) +{ + MPI2DefaultReply_t *mpi_reply; + + if (ioc->config_cmds.status == MPT2_CMD_NOT_USED) + return; + if (ioc->config_cmds.smid != smid) + return; + ioc->config_cmds.status |= MPT2_CMD_COMPLETE; + mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); + if (mpi_reply) { + ioc->config_cmds.status |= MPT2_CMD_REPLY_VALID; + memcpy(ioc->config_cmds.reply, mpi_reply, + mpi_reply->MsgLength*4); + } + ioc->config_cmds.status &= ~MPT2_CMD_PENDING; +#ifdef CONFIG_SCSI_MPT2SAS_LOGGING + _config_display_some_debug(ioc, smid, "config_done", mpi_reply); +#endif + complete(&ioc->config_cmds.done); +} + +/** + * _config_request - main routine for sending config page requests + * @ioc: per adapter object + * @mpi_request: request message frame + * @mpi_reply: reply mf payload returned from firmware + * @timeout: timeout in seconds + * Context: sleep, the calling function needs to acquire the config_cmds.mutex + * + * A generic API for config page requests to firmware. + * + * The ioc->config_cmds.status flag should be MPT2_CMD_NOT_USED before calling + * this API. + * + * The callback index is set inside `ioc->config_cb_idx. + * + * Returns 0 for success, non-zero for failure. + */ +static int +_config_request(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigRequest_t + *mpi_request, Mpi2ConfigReply_t *mpi_reply, int timeout) +{ + u16 smid; + u32 ioc_state; + unsigned long timeleft; + Mpi2ConfigRequest_t *config_request; + int r; + u8 retry_count; + u8 issue_reset; + u16 wait_state_count; + + if (ioc->config_cmds.status != MPT2_CMD_NOT_USED) { + printk(MPT2SAS_ERR_FMT "%s: config_cmd in use\n", + ioc->name, __func__); + return -EAGAIN; + } + retry_count = 0; + + retry_config: + wait_state_count = 0; + ioc_state = mpt2sas_base_get_iocstate(ioc, 1); + while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { + if (wait_state_count++ == MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT) { + printk(MPT2SAS_ERR_FMT + "%s: failed due to ioc not operational\n", + ioc->name, __func__); + ioc->config_cmds.status = MPT2_CMD_NOT_USED; + return -EFAULT; + } + ssleep(1); + ioc_state = mpt2sas_base_get_iocstate(ioc, 1); + printk(MPT2SAS_INFO_FMT "%s: waiting for " + "operational state(count=%d)\n", ioc->name, + __func__, wait_state_count); + } + if (wait_state_count) + printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n", + ioc->name, __func__); + + smid = mpt2sas_base_get_smid(ioc, ioc->config_cb_idx); + if (!smid) { + printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", + ioc->name, __func__); + ioc->config_cmds.status = MPT2_CMD_NOT_USED; + return -EAGAIN; + } + + r = 0; + memset(mpi_reply, 0, sizeof(Mpi2ConfigReply_t)); + ioc->config_cmds.status = MPT2_CMD_PENDING; + config_request = mpt2sas_base_get_msg_frame(ioc, smid); + ioc->config_cmds.smid = smid; + memcpy(config_request, mpi_request, sizeof(Mpi2ConfigRequest_t)); +#ifdef CONFIG_SCSI_MPT2SAS_LOGGING + _config_display_some_debug(ioc, smid, "config_request", NULL); +#endif + mpt2sas_base_put_smid_default(ioc, smid, config_request->VF_ID); + timeleft = wait_for_completion_timeout(&ioc->config_cmds.done, + timeout*HZ); + if (!(ioc->config_cmds.status & MPT2_CMD_COMPLETE)) { + printk(MPT2SAS_ERR_FMT "%s: timeout\n", + ioc->name, __func__); + _debug_dump_mf(mpi_request, + sizeof(Mpi2ConfigRequest_t)/4); + if (!(ioc->config_cmds.status & MPT2_CMD_RESET)) + issue_reset = 1; + goto issue_host_reset; + } + if (ioc->config_cmds.status & MPT2_CMD_REPLY_VALID) + memcpy(mpi_reply, ioc->config_cmds.reply, + sizeof(Mpi2ConfigReply_t)); + if (retry_count) + printk(MPT2SAS_INFO_FMT "%s: retry completed!!\n", + ioc->name, __func__); + ioc->config_cmds.status = MPT2_CMD_NOT_USED; + return r; + + issue_host_reset: + if (issue_reset) + mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, + FORCE_BIG_HAMMER); + ioc->config_cmds.status = MPT2_CMD_NOT_USED; + if (!retry_count) { + printk(MPT2SAS_INFO_FMT "%s: attempting retry\n", + ioc->name, __func__); + retry_count++; + goto retry_config; + } + return -EFAULT; +} + +/** + * _config_alloc_config_dma_memory - obtain physical memory + * @ioc: per adapter object + * @mem: struct config_request + * + * A wrapper for obtaining dma-able memory for config page request. + * + * Returns 0 for success, non-zero for failure. + */ +static int +_config_alloc_config_dma_memory(struct MPT2SAS_ADAPTER *ioc, + struct config_request *mem) +{ + int r = 0; + + mem->config_page = pci_alloc_consistent(ioc->pdev, mem->config_page_sz, + &mem->config_page_dma); + if (!mem->config_page) + r = -ENOMEM; + return r; +} + +/** + * _config_free_config_dma_memory - wrapper to free the memory + * @ioc: per adapter object + * @mem: struct config_request + * + * A wrapper to free dma-able memory when using _config_alloc_config_dma_memory. + * + * Returns 0 for success, non-zero for failure. + */ +static void +_config_free_config_dma_memory(struct MPT2SAS_ADAPTER *ioc, + struct config_request *mem) +{ + pci_free_consistent(ioc->pdev, mem->config_page_sz, mem->config_page, + mem->config_page_dma); +} + +/** + * mpt2sas_config_get_manufacturing_pg0 - obtain manufacturing page 0 + * @ioc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt2sas_config_get_manufacturing_pg0(struct MPT2SAS_ADAPTER *ioc, + Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage0_t *config_page) +{ + Mpi2ConfigRequest_t mpi_request; + int r; + struct config_request mem; + + mutex_lock(&ioc->config_cmds.mutex); + memset(config_page, 0, sizeof(Mpi2ManufacturingPage0_t)); + memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); + mpi_request.Function = MPI2_FUNCTION_CONFIG; + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_MANUFACTURING; + mpi_request.Header.PageNumber = 0; + mpi_request.Header.PageVersion = MPI2_MANUFACTURING0_PAGEVERSION; + mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + if (r) + goto out; + + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion; + mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber; + mpi_request.Header.PageType = mpi_reply->Header.PageType; + mpi_request.Header.PageLength = mpi_reply->Header.PageLength; + mem.config_page_sz = le16_to_cpu(mpi_reply->Header.PageLength) * 4; + if (mem.config_page_sz > ioc->config_page_sz) { + r = _config_alloc_config_dma_memory(ioc, &mem); + if (r) + goto out; + } else { + mem.config_page_dma = ioc->config_page_dma; + mem.config_page = ioc->config_page; + } + ioc->base_add_sg_single(&mpi_request.PageBufferSGE, + MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz, + mem.config_page_dma); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + if (!r) + memcpy(config_page, mem.config_page, + min_t(u16, mem.config_page_sz, + sizeof(Mpi2ManufacturingPage0_t))); + + if (mem.config_page_sz > ioc->config_page_sz) + _config_free_config_dma_memory(ioc, &mem); + + out: + mutex_unlock(&ioc->config_cmds.mutex); + return r; +} + +/** + * mpt2sas_config_get_bios_pg2 - obtain bios page 2 + * @ioc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt2sas_config_get_bios_pg2(struct MPT2SAS_ADAPTER *ioc, + Mpi2ConfigReply_t *mpi_reply, Mpi2BiosPage2_t *config_page) +{ + Mpi2ConfigRequest_t mpi_request; + int r; + struct config_request mem; + + mutex_lock(&ioc->config_cmds.mutex); + memset(config_page, 0, sizeof(Mpi2BiosPage2_t)); + memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); + mpi_request.Function = MPI2_FUNCTION_CONFIG; + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_BIOS; + mpi_request.Header.PageNumber = 2; + mpi_request.Header.PageVersion = MPI2_BIOSPAGE2_PAGEVERSION; + mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + if (r) + goto out; + + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion; + mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber; + mpi_request.Header.PageType = mpi_reply->Header.PageType; + mpi_request.Header.PageLength = mpi_reply->Header.PageLength; + mem.config_page_sz = le16_to_cpu(mpi_reply->Header.PageLength) * 4; + if (mem.config_page_sz > ioc->config_page_sz) { + r = _config_alloc_config_dma_memory(ioc, &mem); + if (r) + goto out; + } else { + mem.config_page_dma = ioc->config_page_dma; + mem.config_page = ioc->config_page; + } + ioc->base_add_sg_single(&mpi_request.PageBufferSGE, + MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz, + mem.config_page_dma); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + if (!r) + memcpy(config_page, mem.config_page, + min_t(u16, mem.config_page_sz, + sizeof(Mpi2BiosPage2_t))); + + if (mem.config_page_sz > ioc->config_page_sz) + _config_free_config_dma_memory(ioc, &mem); + + out: + mutex_unlock(&ioc->config_cmds.mutex); + return r; +} + +/** + * mpt2sas_config_get_bios_pg3 - obtain bios page 3 + * @ioc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt2sas_config_get_bios_pg3(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t + *mpi_reply, Mpi2BiosPage3_t *config_page) +{ + Mpi2ConfigRequest_t mpi_request; + int r; + struct config_request mem; + + mutex_lock(&ioc->config_cmds.mutex); + memset(config_page, 0, sizeof(Mpi2BiosPage3_t)); + memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); + mpi_request.Function = MPI2_FUNCTION_CONFIG; + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_BIOS; + mpi_request.Header.PageNumber = 3; + mpi_request.Header.PageVersion = MPI2_BIOSPAGE3_PAGEVERSION; + mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + if (r) + goto out; + + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion; + mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber; + mpi_request.Header.PageType = mpi_reply->Header.PageType; + mpi_request.Header.PageLength = mpi_reply->Header.PageLength; + mem.config_page_sz = le16_to_cpu(mpi_reply->Header.PageLength) * 4; + if (mem.config_page_sz > ioc->config_page_sz) { + r = _config_alloc_config_dma_memory(ioc, &mem); + if (r) + goto out; + } else { + mem.config_page_dma = ioc->config_page_dma; + mem.config_page = ioc->config_page; + } + ioc->base_add_sg_single(&mpi_request.PageBufferSGE, + MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz, + mem.config_page_dma); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + if (!r) + memcpy(config_page, mem.config_page, + min_t(u16, mem.config_page_sz, + sizeof(Mpi2BiosPage3_t))); + + if (mem.config_page_sz > ioc->config_page_sz) + _config_free_config_dma_memory(ioc, &mem); + + out: + mutex_unlock(&ioc->config_cmds.mutex); + return r; +} + +/** + * mpt2sas_config_get_iounit_pg0 - obtain iounit page 0 + * @ioc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt2sas_config_get_iounit_pg0(struct MPT2SAS_ADAPTER *ioc, + Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage0_t *config_page) +{ + Mpi2ConfigRequest_t mpi_request; + int r; + struct config_request mem; + + mutex_lock(&ioc->config_cmds.mutex); + memset(config_page, 0, sizeof(Mpi2IOUnitPage0_t)); + memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); + mpi_request.Function = MPI2_FUNCTION_CONFIG; + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT; + mpi_request.Header.PageNumber = 0; + mpi_request.Header.PageVersion = MPI2_IOUNITPAGE0_PAGEVERSION; + mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + if (r) + goto out; + + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion; + mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber; + mpi_request.Header.PageType = mpi_reply->Header.PageType; + mpi_request.Header.PageLength = mpi_reply->Header.PageLength; + mem.config_page_sz = le16_to_cpu(mpi_reply->Header.PageLength) * 4; + if (mem.config_page_sz > ioc->config_page_sz) { + r = _config_alloc_config_dma_memory(ioc, &mem); + if (r) + goto out; + } else { + mem.config_page_dma = ioc->config_page_dma; + mem.config_page = ioc->config_page; + } + ioc->base_add_sg_single(&mpi_request.PageBufferSGE, + MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz, + mem.config_page_dma); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + if (!r) + memcpy(config_page, mem.config_page, + min_t(u16, mem.config_page_sz, + sizeof(Mpi2IOUnitPage0_t))); + + if (mem.config_page_sz > ioc->config_page_sz) + _config_free_config_dma_memory(ioc, &mem); + + out: + mutex_unlock(&ioc->config_cmds.mutex); + return r; +} + +/** + * mpt2sas_config_get_iounit_pg1 - obtain iounit page 1 + * @ioc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt2sas_config_get_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, + Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage1_t *config_page) +{ + Mpi2ConfigRequest_t mpi_request; + int r; + struct config_request mem; + + mutex_lock(&ioc->config_cmds.mutex); + memset(config_page, 0, sizeof(Mpi2IOUnitPage1_t)); + memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); + mpi_request.Function = MPI2_FUNCTION_CONFIG; + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT; + mpi_request.Header.PageNumber = 1; + mpi_request.Header.PageVersion = MPI2_IOUNITPAGE1_PAGEVERSION; + mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + if (r) + goto out; + + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion; + mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber; + mpi_request.Header.PageType = mpi_reply->Header.PageType; + mpi_request.Header.PageLength = mpi_reply->Header.PageLength; + mem.config_page_sz = le16_to_cpu(mpi_reply->Header.PageLength) * 4; + if (mem.config_page_sz > ioc->config_page_sz) { + r = _config_alloc_config_dma_memory(ioc, &mem); + if (r) + goto out; + } else { + mem.config_page_dma = ioc->config_page_dma; + mem.config_page = ioc->config_page; + } + ioc->base_add_sg_single(&mpi_request.PageBufferSGE, + MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz, + mem.config_page_dma); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + if (!r) + memcpy(config_page, mem.config_page, + min_t(u16, mem.config_page_sz, + sizeof(Mpi2IOUnitPage1_t))); + + if (mem.config_page_sz > ioc->config_page_sz) + _config_free_config_dma_memory(ioc, &mem); + + out: + mutex_unlock(&ioc->config_cmds.mutex); + return r; +} + +/** + * mpt2sas_config_set_iounit_pg1 - set iounit page 1 + * @ioc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt2sas_config_set_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, + Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage1_t config_page) +{ + Mpi2ConfigRequest_t mpi_request; + int r; + struct config_request mem; + + mutex_lock(&ioc->config_cmds.mutex); + memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); + mpi_request.Function = MPI2_FUNCTION_CONFIG; + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT; + mpi_request.Header.PageNumber = 1; + mpi_request.Header.PageVersion = MPI2_IOUNITPAGE1_PAGEVERSION; + mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + if (r) + goto out; + + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT; + mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion; + mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber; + mpi_request.Header.PageType = mpi_reply->Header.PageType; + mpi_request.Header.PageLength = mpi_reply->Header.PageLength; + mem.config_page_sz = le16_to_cpu(mpi_reply->Header.PageLength) * 4; + if (mem.config_page_sz > ioc->config_page_sz) { + r = _config_alloc_config_dma_memory(ioc, &mem); + if (r) + goto out; + } else { + mem.config_page_dma = ioc->config_page_dma; + mem.config_page = ioc->config_page; + } + + memset(mem.config_page, 0, mem.config_page_sz); + memcpy(mem.config_page, &config_page, + sizeof(Mpi2IOUnitPage1_t)); + + ioc->base_add_sg_single(&mpi_request.PageBufferSGE, + MPT2_CONFIG_COMMON_WRITE_SGLFLAGS | mem.config_page_sz, + mem.config_page_dma); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + + if (mem.config_page_sz > ioc->config_page_sz) + _config_free_config_dma_memory(ioc, &mem); + + out: + mutex_unlock(&ioc->config_cmds.mutex); + return r; +} + +/** + * mpt2sas_config_get_ioc_pg8 - obtain ioc page 8 + * @ioc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt2sas_config_get_ioc_pg8(struct MPT2SAS_ADAPTER *ioc, + Mpi2ConfigReply_t *mpi_reply, Mpi2IOCPage8_t *config_page) +{ + Mpi2ConfigRequest_t mpi_request; + int r; + struct config_request mem; + + mutex_lock(&ioc->config_cmds.mutex); + memset(config_page, 0, sizeof(Mpi2IOCPage8_t)); + memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); + mpi_request.Function = MPI2_FUNCTION_CONFIG; + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IOC; + mpi_request.Header.PageNumber = 8; + mpi_request.Header.PageVersion = MPI2_IOCPAGE8_PAGEVERSION; + mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + if (r) + goto out; + + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion; + mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber; + mpi_request.Header.PageType = mpi_reply->Header.PageType; + mpi_request.Header.PageLength = mpi_reply->Header.PageLength; + mem.config_page_sz = le16_to_cpu(mpi_reply->Header.PageLength) * 4; + if (mem.config_page_sz > ioc->config_page_sz) { + r = _config_alloc_config_dma_memory(ioc, &mem); + if (r) + goto out; + } else { + mem.config_page_dma = ioc->config_page_dma; + mem.config_page = ioc->config_page; + } + ioc->base_add_sg_single(&mpi_request.PageBufferSGE, + MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz, + mem.config_page_dma); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + if (!r) + memcpy(config_page, mem.config_page, + min_t(u16, mem.config_page_sz, + sizeof(Mpi2IOCPage8_t))); + + if (mem.config_page_sz > ioc->config_page_sz) + _config_free_config_dma_memory(ioc, &mem); + + out: + mutex_unlock(&ioc->config_cmds.mutex); + return r; +} + +/** + * mpt2sas_config_get_sas_device_pg0 - obtain sas device page 0 + * @ioc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * @form: GET_NEXT_HANDLE or HANDLE + * @handle: device handle + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt2sas_config_get_sas_device_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t + *mpi_reply, Mpi2SasDevicePage0_t *config_page, u32 form, u32 handle) +{ + Mpi2ConfigRequest_t mpi_request; + int r; + struct config_request mem; + + mutex_lock(&ioc->config_cmds.mutex); + memset(config_page, 0, sizeof(Mpi2SasDevicePage0_t)); + memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); + mpi_request.Function = MPI2_FUNCTION_CONFIG; + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; + mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE; + mpi_request.Header.PageVersion = MPI2_SASDEVICE0_PAGEVERSION; + mpi_request.Header.PageNumber = 0; + mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + if (r) + goto out; + + mpi_request.PageAddress = cpu_to_le32(form | handle); + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion; + mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber; + mpi_request.Header.PageType = mpi_reply->Header.PageType; + mpi_request.ExtPageLength = mpi_reply->ExtPageLength; + mpi_request.ExtPageType = mpi_reply->ExtPageType; + mem.config_page_sz = le16_to_cpu(mpi_reply->ExtPageLength) * 4; + if (mem.config_page_sz > ioc->config_page_sz) { + r = _config_alloc_config_dma_memory(ioc, &mem); + if (r) + goto out; + } else { + mem.config_page_dma = ioc->config_page_dma; + mem.config_page = ioc->config_page; + } + ioc->base_add_sg_single(&mpi_request.PageBufferSGE, + MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz, + mem.config_page_dma); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + if (!r) + memcpy(config_page, mem.config_page, + min_t(u16, mem.config_page_sz, + sizeof(Mpi2SasDevicePage0_t))); + + if (mem.config_page_sz > ioc->config_page_sz) + _config_free_config_dma_memory(ioc, &mem); + + out: + mutex_unlock(&ioc->config_cmds.mutex); + return r; +} + +/** + * mpt2sas_config_get_sas_device_pg1 - obtain sas device page 1 + * @ioc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * @form: GET_NEXT_HANDLE or HANDLE + * @handle: device handle + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt2sas_config_get_sas_device_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t + *mpi_reply, Mpi2SasDevicePage1_t *config_page, u32 form, u32 handle) +{ + Mpi2ConfigRequest_t mpi_request; + int r; + struct config_request mem; + + mutex_lock(&ioc->config_cmds.mutex); + memset(config_page, 0, sizeof(Mpi2SasDevicePage1_t)); + memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); + mpi_request.Function = MPI2_FUNCTION_CONFIG; + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; + mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE; + mpi_request.Header.PageVersion = MPI2_SASDEVICE1_PAGEVERSION; + mpi_request.Header.PageNumber = 1; + mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + if (r) + goto out; + + mpi_request.PageAddress = cpu_to_le32(form | handle); + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion; + mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber; + mpi_request.Header.PageType = mpi_reply->Header.PageType; + mpi_request.ExtPageLength = mpi_reply->ExtPageLength; + mpi_request.ExtPageType = mpi_reply->ExtPageType; + mem.config_page_sz = le16_to_cpu(mpi_reply->ExtPageLength) * 4; + if (mem.config_page_sz > ioc->config_page_sz) { + r = _config_alloc_config_dma_memory(ioc, &mem); + if (r) + goto out; + } else { + mem.config_page_dma = ioc->config_page_dma; + mem.config_page = ioc->config_page; + } + ioc->base_add_sg_single(&mpi_request.PageBufferSGE, + MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz, + mem.config_page_dma); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + if (!r) + memcpy(config_page, mem.config_page, + min_t(u16, mem.config_page_sz, + sizeof(Mpi2SasDevicePage1_t))); + + if (mem.config_page_sz > ioc->config_page_sz) + _config_free_config_dma_memory(ioc, &mem); + + out: + mutex_unlock(&ioc->config_cmds.mutex); + return r; +} + +/** + * mpt2sas_config_get_number_hba_phys - obtain number of phys on the host + * @ioc: per adapter object + * @num_phys: pointer returned with the number of phys + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt2sas_config_get_number_hba_phys(struct MPT2SAS_ADAPTER *ioc, u8 *num_phys) +{ + Mpi2ConfigRequest_t mpi_request; + int r; + struct config_request mem; + u16 ioc_status; + Mpi2ConfigReply_t mpi_reply; + Mpi2SasIOUnitPage0_t config_page; + + mutex_lock(&ioc->config_cmds.mutex); + memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); + mpi_request.Function = MPI2_FUNCTION_CONFIG; + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; + mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT; + mpi_request.Header.PageNumber = 0; + mpi_request.Header.PageVersion = MPI2_SASIOUNITPAGE0_PAGEVERSION; + mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); + r = _config_request(ioc, &mpi_request, &mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + if (r) + goto out; + + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + mpi_request.Header.PageVersion = mpi_reply.Header.PageVersion; + mpi_request.Header.PageNumber = mpi_reply.Header.PageNumber; + mpi_request.Header.PageType = mpi_reply.Header.PageType; + mpi_request.ExtPageLength = mpi_reply.ExtPageLength; + mpi_request.ExtPageType = mpi_reply.ExtPageType; + mem.config_page_sz = le16_to_cpu(mpi_reply.ExtPageLength) * 4; + if (mem.config_page_sz > ioc->config_page_sz) { + r = _config_alloc_config_dma_memory(ioc, &mem); + if (r) + goto out; + } else { + mem.config_page_dma = ioc->config_page_dma; + mem.config_page = ioc->config_page; + } + ioc->base_add_sg_single(&mpi_request.PageBufferSGE, + MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz, + mem.config_page_dma); + r = _config_request(ioc, &mpi_request, &mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + if (!r) { + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { + memcpy(&config_page, mem.config_page, + min_t(u16, mem.config_page_sz, + sizeof(Mpi2SasIOUnitPage0_t))); + *num_phys = config_page.NumPhys; + } + } + + if (mem.config_page_sz > ioc->config_page_sz) + _config_free_config_dma_memory(ioc, &mem); + + out: + mutex_unlock(&ioc->config_cmds.mutex); + return r; +} + +/** + * mpt2sas_config_get_sas_iounit_pg0 - obtain sas iounit page 0 + * @ioc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * @sz: size of buffer passed in config_page + * Context: sleep. + * + * Calling function should call config_get_number_hba_phys prior to + * this function, so enough memory is allocated for config_page. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt2sas_config_get_sas_iounit_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t + *mpi_reply, Mpi2SasIOUnitPage0_t *config_page, u16 sz) +{ + Mpi2ConfigRequest_t mpi_request; + int r; + struct config_request mem; + + mutex_lock(&ioc->config_cmds.mutex); + memset(config_page, 0, sz); + memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); + mpi_request.Function = MPI2_FUNCTION_CONFIG; + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; + mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT; + mpi_request.Header.PageNumber = 0; + mpi_request.Header.PageVersion = MPI2_SASIOUNITPAGE0_PAGEVERSION; + mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + if (r) + goto out; + + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion; + mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber; + mpi_request.Header.PageType = mpi_reply->Header.PageType; + mpi_request.ExtPageLength = mpi_reply->ExtPageLength; + mpi_request.ExtPageType = mpi_reply->ExtPageType; + mem.config_page_sz = le16_to_cpu(mpi_reply->ExtPageLength) * 4; + if (mem.config_page_sz > ioc->config_page_sz) { + r = _config_alloc_config_dma_memory(ioc, &mem); + if (r) + goto out; + } else { + mem.config_page_dma = ioc->config_page_dma; + mem.config_page = ioc->config_page; + } + ioc->base_add_sg_single(&mpi_request.PageBufferSGE, + MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz, + mem.config_page_dma); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + if (!r) + memcpy(config_page, mem.config_page, + min_t(u16, sz, mem.config_page_sz)); + + if (mem.config_page_sz > ioc->config_page_sz) + _config_free_config_dma_memory(ioc, &mem); + + out: + mutex_unlock(&ioc->config_cmds.mutex); + return r; +} + +/** + * mpt2sas_config_get_sas_iounit_pg1 - obtain sas iounit page 0 + * @ioc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * @sz: size of buffer passed in config_page + * Context: sleep. + * + * Calling function should call config_get_number_hba_phys prior to + * this function, so enough memory is allocated for config_page. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt2sas_config_get_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t + *mpi_reply, Mpi2SasIOUnitPage1_t *config_page, u16 sz) +{ + Mpi2ConfigRequest_t mpi_request; + int r; + struct config_request mem; + + mutex_lock(&ioc->config_cmds.mutex); + memset(config_page, 0, sz); + memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); + mpi_request.Function = MPI2_FUNCTION_CONFIG; + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; + mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT; + mpi_request.Header.PageNumber = 1; + mpi_request.Header.PageVersion = MPI2_SASIOUNITPAGE0_PAGEVERSION; + mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + if (r) + goto out; + + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion; + mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber; + mpi_request.Header.PageType = mpi_reply->Header.PageType; + mpi_request.ExtPageLength = mpi_reply->ExtPageLength; + mpi_request.ExtPageType = mpi_reply->ExtPageType; + mem.config_page_sz = le16_to_cpu(mpi_reply->ExtPageLength) * 4; + if (mem.config_page_sz > ioc->config_page_sz) { + r = _config_alloc_config_dma_memory(ioc, &mem); + if (r) + goto out; + } else { + mem.config_page_dma = ioc->config_page_dma; + mem.config_page = ioc->config_page; + } + ioc->base_add_sg_single(&mpi_request.PageBufferSGE, + MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz, + mem.config_page_dma); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + if (!r) + memcpy(config_page, mem.config_page, + min_t(u16, sz, mem.config_page_sz)); + + if (mem.config_page_sz > ioc->config_page_sz) + _config_free_config_dma_memory(ioc, &mem); + + out: + mutex_unlock(&ioc->config_cmds.mutex); + return r; +} + +/** + * mpt2sas_config_get_expander_pg0 - obtain expander page 0 + * @ioc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * @form: GET_NEXT_HANDLE or HANDLE + * @handle: expander handle + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt2sas_config_get_expander_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t + *mpi_reply, Mpi2ExpanderPage0_t *config_page, u32 form, u32 handle) +{ + Mpi2ConfigRequest_t mpi_request; + int r; + struct config_request mem; + + mutex_lock(&ioc->config_cmds.mutex); + memset(config_page, 0, sizeof(Mpi2ExpanderPage0_t)); + memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); + mpi_request.Function = MPI2_FUNCTION_CONFIG; + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; + mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER; + mpi_request.Header.PageNumber = 0; + mpi_request.Header.PageVersion = MPI2_SASEXPANDER0_PAGEVERSION; + mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + if (r) + goto out; + + mpi_request.PageAddress = cpu_to_le32(form | handle); + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion; + mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber; + mpi_request.Header.PageType = mpi_reply->Header.PageType; + mpi_request.ExtPageLength = mpi_reply->ExtPageLength; + mpi_request.ExtPageType = mpi_reply->ExtPageType; + mem.config_page_sz = le16_to_cpu(mpi_reply->ExtPageLength) * 4; + if (mem.config_page_sz > ioc->config_page_sz) { + r = _config_alloc_config_dma_memory(ioc, &mem); + if (r) + goto out; + } else { + mem.config_page_dma = ioc->config_page_dma; + mem.config_page = ioc->config_page; + } + ioc->base_add_sg_single(&mpi_request.PageBufferSGE, + MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz, + mem.config_page_dma); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + if (!r) + memcpy(config_page, mem.config_page, + min_t(u16, mem.config_page_sz, + sizeof(Mpi2ExpanderPage0_t))); + + if (mem.config_page_sz > ioc->config_page_sz) + _config_free_config_dma_memory(ioc, &mem); + + out: + mutex_unlock(&ioc->config_cmds.mutex); + return r; +} + +/** + * mpt2sas_config_get_expander_pg1 - obtain expander page 1 + * @ioc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * @phy_number: phy number + * @handle: expander handle + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt2sas_config_get_expander_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t + *mpi_reply, Mpi2ExpanderPage1_t *config_page, u32 phy_number, + u16 handle) +{ + Mpi2ConfigRequest_t mpi_request; + int r; + struct config_request mem; + + mutex_lock(&ioc->config_cmds.mutex); + memset(config_page, 0, sizeof(Mpi2ExpanderPage1_t)); + memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); + mpi_request.Function = MPI2_FUNCTION_CONFIG; + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; + mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER; + mpi_request.Header.PageNumber = 1; + mpi_request.Header.PageVersion = MPI2_SASEXPANDER1_PAGEVERSION; + mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + if (r) + goto out; + + mpi_request.PageAddress = + cpu_to_le32(MPI2_SAS_EXPAND_PGAD_FORM_HNDL_PHY_NUM | + (phy_number << MPI2_SAS_EXPAND_PGAD_PHYNUM_SHIFT) | handle); + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion; + mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber; + mpi_request.Header.PageType = mpi_reply->Header.PageType; + mpi_request.ExtPageLength = mpi_reply->ExtPageLength; + mpi_request.ExtPageType = mpi_reply->ExtPageType; + mem.config_page_sz = le16_to_cpu(mpi_reply->ExtPageLength) * 4; + if (mem.config_page_sz > ioc->config_page_sz) { + r = _config_alloc_config_dma_memory(ioc, &mem); + if (r) + goto out; + } else { + mem.config_page_dma = ioc->config_page_dma; + mem.config_page = ioc->config_page; + } + ioc->base_add_sg_single(&mpi_request.PageBufferSGE, + MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz, + mem.config_page_dma); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + if (!r) + memcpy(config_page, mem.config_page, + min_t(u16, mem.config_page_sz, + sizeof(Mpi2ExpanderPage1_t))); + + if (mem.config_page_sz > ioc->config_page_sz) + _config_free_config_dma_memory(ioc, &mem); + + out: + mutex_unlock(&ioc->config_cmds.mutex); + return r; +} + +/** + * mpt2sas_config_get_enclosure_pg0 - obtain enclosure page 0 + * @ioc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * @form: GET_NEXT_HANDLE or HANDLE + * @handle: expander handle + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt2sas_config_get_enclosure_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t + *mpi_reply, Mpi2SasEnclosurePage0_t *config_page, u32 form, u32 handle) +{ + Mpi2ConfigRequest_t mpi_request; + int r; + struct config_request mem; + + mutex_lock(&ioc->config_cmds.mutex); + memset(config_page, 0, sizeof(Mpi2SasEnclosurePage0_t)); + memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); + mpi_request.Function = MPI2_FUNCTION_CONFIG; + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; + mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_ENCLOSURE; + mpi_request.Header.PageNumber = 0; + mpi_request.Header.PageVersion = MPI2_SASENCLOSURE0_PAGEVERSION; + mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + if (r) + goto out; + + mpi_request.PageAddress = cpu_to_le32(form | handle); + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion; + mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber; + mpi_request.Header.PageType = mpi_reply->Header.PageType; + mpi_request.ExtPageLength = mpi_reply->ExtPageLength; + mpi_request.ExtPageType = mpi_reply->ExtPageType; + mem.config_page_sz = le16_to_cpu(mpi_reply->ExtPageLength) * 4; + if (mem.config_page_sz > ioc->config_page_sz) { + r = _config_alloc_config_dma_memory(ioc, &mem); + if (r) + goto out; + } else { + mem.config_page_dma = ioc->config_page_dma; + mem.config_page = ioc->config_page; + } + ioc->base_add_sg_single(&mpi_request.PageBufferSGE, + MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz, + mem.config_page_dma); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + if (!r) + memcpy(config_page, mem.config_page, + min_t(u16, mem.config_page_sz, + sizeof(Mpi2SasEnclosurePage0_t))); + + if (mem.config_page_sz > ioc->config_page_sz) + _config_free_config_dma_memory(ioc, &mem); + + out: + mutex_unlock(&ioc->config_cmds.mutex); + return r; +} + +/** + * mpt2sas_config_get_phy_pg0 - obtain phy page 0 + * @ioc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * @phy_number: phy number + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt2sas_config_get_phy_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t + *mpi_reply, Mpi2SasPhyPage0_t *config_page, u32 phy_number) +{ + Mpi2ConfigRequest_t mpi_request; + int r; + struct config_request mem; + + mutex_lock(&ioc->config_cmds.mutex); + memset(config_page, 0, sizeof(Mpi2SasPhyPage0_t)); + memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); + mpi_request.Function = MPI2_FUNCTION_CONFIG; + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; + mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_PHY; + mpi_request.Header.PageNumber = 0; + mpi_request.Header.PageVersion = MPI2_SASPHY0_PAGEVERSION; + mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + if (r) + goto out; + + mpi_request.PageAddress = + cpu_to_le32(MPI2_SAS_PHY_PGAD_FORM_PHY_NUMBER | phy_number); + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion; + mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber; + mpi_request.Header.PageType = mpi_reply->Header.PageType; + mpi_request.ExtPageLength = mpi_reply->ExtPageLength; + mpi_request.ExtPageType = mpi_reply->ExtPageType; + mem.config_page_sz = le16_to_cpu(mpi_reply->ExtPageLength) * 4; + if (mem.config_page_sz > ioc->config_page_sz) { + r = _config_alloc_config_dma_memory(ioc, &mem); + if (r) + goto out; + } else { + mem.config_page_dma = ioc->config_page_dma; + mem.config_page = ioc->config_page; + } + ioc->base_add_sg_single(&mpi_request.PageBufferSGE, + MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz, + mem.config_page_dma); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + if (!r) + memcpy(config_page, mem.config_page, + min_t(u16, mem.config_page_sz, + sizeof(Mpi2SasPhyPage0_t))); + + if (mem.config_page_sz > ioc->config_page_sz) + _config_free_config_dma_memory(ioc, &mem); + + out: + mutex_unlock(&ioc->config_cmds.mutex); + return r; +} + +/** + * mpt2sas_config_get_phy_pg1 - obtain phy page 1 + * @ioc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * @phy_number: phy number + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt2sas_config_get_phy_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t + *mpi_reply, Mpi2SasPhyPage1_t *config_page, u32 phy_number) +{ + Mpi2ConfigRequest_t mpi_request; + int r; + struct config_request mem; + + mutex_lock(&ioc->config_cmds.mutex); + memset(config_page, 0, sizeof(Mpi2SasPhyPage1_t)); + memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); + mpi_request.Function = MPI2_FUNCTION_CONFIG; + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; + mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_PHY; + mpi_request.Header.PageNumber = 1; + mpi_request.Header.PageVersion = MPI2_SASPHY1_PAGEVERSION; + mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + if (r) + goto out; + + mpi_request.PageAddress = + cpu_to_le32(MPI2_SAS_PHY_PGAD_FORM_PHY_NUMBER | phy_number); + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion; + mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber; + mpi_request.Header.PageType = mpi_reply->Header.PageType; + mpi_request.ExtPageLength = mpi_reply->ExtPageLength; + mpi_request.ExtPageType = mpi_reply->ExtPageType; + mem.config_page_sz = le16_to_cpu(mpi_reply->ExtPageLength) * 4; + if (mem.config_page_sz > ioc->config_page_sz) { + r = _config_alloc_config_dma_memory(ioc, &mem); + if (r) + goto out; + } else { + mem.config_page_dma = ioc->config_page_dma; + mem.config_page = ioc->config_page; + } + ioc->base_add_sg_single(&mpi_request.PageBufferSGE, + MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz, + mem.config_page_dma); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + if (!r) + memcpy(config_page, mem.config_page, + min_t(u16, mem.config_page_sz, + sizeof(Mpi2SasPhyPage1_t))); + + if (mem.config_page_sz > ioc->config_page_sz) + _config_free_config_dma_memory(ioc, &mem); + + out: + mutex_unlock(&ioc->config_cmds.mutex); + return r; +} + +/** + * mpt2sas_config_get_raid_volume_pg1 - obtain raid volume page 1 + * @ioc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * @form: GET_NEXT_HANDLE or HANDLE + * @handle: volume handle + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt2sas_config_get_raid_volume_pg1(struct MPT2SAS_ADAPTER *ioc, + Mpi2ConfigReply_t *mpi_reply, Mpi2RaidVolPage1_t *config_page, u32 form, + u32 handle) +{ + Mpi2ConfigRequest_t mpi_request; + int r; + struct config_request mem; + + mutex_lock(&ioc->config_cmds.mutex); + memset(config_page, 0, sizeof(Mpi2RaidVolPage1_t)); + memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); + mpi_request.Function = MPI2_FUNCTION_CONFIG; + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME; + mpi_request.Header.PageNumber = 1; + mpi_request.Header.PageVersion = MPI2_RAIDVOLPAGE1_PAGEVERSION; + mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + if (r) + goto out; + + mpi_request.PageAddress = cpu_to_le32(form | handle); + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion; + mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber; + mpi_request.Header.PageType = mpi_reply->Header.PageType; + mpi_request.Header.PageLength = mpi_reply->Header.PageLength; + mem.config_page_sz = le16_to_cpu(mpi_reply->Header.PageLength) * 4; + if (mem.config_page_sz > ioc->config_page_sz) { + r = _config_alloc_config_dma_memory(ioc, &mem); + if (r) + goto out; + } else { + mem.config_page_dma = ioc->config_page_dma; + mem.config_page = ioc->config_page; + } + ioc->base_add_sg_single(&mpi_request.PageBufferSGE, + MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz, + mem.config_page_dma); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + if (!r) + memcpy(config_page, mem.config_page, + min_t(u16, mem.config_page_sz, + sizeof(Mpi2RaidVolPage1_t))); + + if (mem.config_page_sz > ioc->config_page_sz) + _config_free_config_dma_memory(ioc, &mem); + + out: + mutex_unlock(&ioc->config_cmds.mutex); + return r; +} + +/** + * mpt2sas_config_get_number_pds - obtain number of phys disk assigned to volume + * @ioc: per adapter object + * @handle: volume handle + * @num_pds: returns pds count + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt2sas_config_get_number_pds(struct MPT2SAS_ADAPTER *ioc, u16 handle, + u8 *num_pds) +{ + Mpi2ConfigRequest_t mpi_request; + Mpi2RaidVolPage0_t *config_page; + Mpi2ConfigReply_t mpi_reply; + int r; + struct config_request mem; + u16 ioc_status; + + mutex_lock(&ioc->config_cmds.mutex); + memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); + *num_pds = 0; + mpi_request.Function = MPI2_FUNCTION_CONFIG; + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME; + mpi_request.Header.PageNumber = 0; + mpi_request.Header.PageVersion = MPI2_RAIDVOLPAGE0_PAGEVERSION; + mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); + r = _config_request(ioc, &mpi_request, &mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + if (r) + goto out; + + mpi_request.PageAddress = + cpu_to_le32(MPI2_RAID_VOLUME_PGAD_FORM_HANDLE | handle); + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + mpi_request.Header.PageVersion = mpi_reply.Header.PageVersion; + mpi_request.Header.PageNumber = mpi_reply.Header.PageNumber; + mpi_request.Header.PageType = mpi_reply.Header.PageType; + mpi_request.Header.PageLength = mpi_reply.Header.PageLength; + mem.config_page_sz = le16_to_cpu(mpi_reply.Header.PageLength) * 4; + if (mem.config_page_sz > ioc->config_page_sz) { + r = _config_alloc_config_dma_memory(ioc, &mem); + if (r) + goto out; + } else { + mem.config_page_dma = ioc->config_page_dma; + mem.config_page = ioc->config_page; + } + ioc->base_add_sg_single(&mpi_request.PageBufferSGE, + MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz, + mem.config_page_dma); + r = _config_request(ioc, &mpi_request, &mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + if (!r) { + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { + config_page = mem.config_page; + *num_pds = config_page->NumPhysDisks; + } + } + + if (mem.config_page_sz > ioc->config_page_sz) + _config_free_config_dma_memory(ioc, &mem); + + out: + mutex_unlock(&ioc->config_cmds.mutex); + return r; +} + +/** + * mpt2sas_config_get_raid_volume_pg0 - obtain raid volume page 0 + * @ioc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * @form: GET_NEXT_HANDLE or HANDLE + * @handle: volume handle + * @sz: size of buffer passed in config_page + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt2sas_config_get_raid_volume_pg0(struct MPT2SAS_ADAPTER *ioc, + Mpi2ConfigReply_t *mpi_reply, Mpi2RaidVolPage0_t *config_page, u32 form, + u32 handle, u16 sz) +{ + Mpi2ConfigRequest_t mpi_request; + int r; + struct config_request mem; + + mutex_lock(&ioc->config_cmds.mutex); + memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); + memset(config_page, 0, sz); + mpi_request.Function = MPI2_FUNCTION_CONFIG; + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME; + mpi_request.Header.PageNumber = 0; + mpi_request.Header.PageVersion = MPI2_RAIDVOLPAGE0_PAGEVERSION; + mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + if (r) + goto out; + + mpi_request.PageAddress = cpu_to_le32(form | handle); + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion; + mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber; + mpi_request.Header.PageType = mpi_reply->Header.PageType; + mpi_request.Header.PageLength = mpi_reply->Header.PageLength; + mem.config_page_sz = le16_to_cpu(mpi_reply->Header.PageLength) * 4; + if (mem.config_page_sz > ioc->config_page_sz) { + r = _config_alloc_config_dma_memory(ioc, &mem); + if (r) + goto out; + } else { + mem.config_page_dma = ioc->config_page_dma; + mem.config_page = ioc->config_page; + } + ioc->base_add_sg_single(&mpi_request.PageBufferSGE, + MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz, + mem.config_page_dma); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + if (!r) + memcpy(config_page, mem.config_page, + min_t(u16, sz, mem.config_page_sz)); + + if (mem.config_page_sz > ioc->config_page_sz) + _config_free_config_dma_memory(ioc, &mem); + + out: + mutex_unlock(&ioc->config_cmds.mutex); + return r; +} + +/** + * mpt2sas_config_get_phys_disk_pg0 - obtain phys disk page 0 + * @ioc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * @form: GET_NEXT_PHYSDISKNUM, PHYSDISKNUM, DEVHANDLE + * @form_specific: specific to the form + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt2sas_config_get_phys_disk_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t + *mpi_reply, Mpi2RaidPhysDiskPage0_t *config_page, u32 form, + u32 form_specific) +{ + Mpi2ConfigRequest_t mpi_request; + int r; + struct config_request mem; + + mutex_lock(&ioc->config_cmds.mutex); + memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); + memset(config_page, 0, sizeof(Mpi2RaidPhysDiskPage0_t)); + mpi_request.Function = MPI2_FUNCTION_CONFIG; + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK; + mpi_request.Header.PageNumber = 0; + mpi_request.Header.PageVersion = MPI2_RAIDPHYSDISKPAGE0_PAGEVERSION; + mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + if (r) + goto out; + + mpi_request.PageAddress = cpu_to_le32(form | form_specific); + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion; + mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber; + mpi_request.Header.PageType = mpi_reply->Header.PageType; + mpi_request.Header.PageLength = mpi_reply->Header.PageLength; + mem.config_page_sz = le16_to_cpu(mpi_reply->Header.PageLength) * 4; + if (mem.config_page_sz > ioc->config_page_sz) { + r = _config_alloc_config_dma_memory(ioc, &mem); + if (r) + goto out; + } else { + mem.config_page_dma = ioc->config_page_dma; + mem.config_page = ioc->config_page; + } + ioc->base_add_sg_single(&mpi_request.PageBufferSGE, + MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz, + mem.config_page_dma); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + if (!r) + memcpy(config_page, mem.config_page, + min_t(u16, mem.config_page_sz, + sizeof(Mpi2RaidPhysDiskPage0_t))); + + if (mem.config_page_sz > ioc->config_page_sz) + _config_free_config_dma_memory(ioc, &mem); + + out: + mutex_unlock(&ioc->config_cmds.mutex); + return r; +} + +/** + * mpt2sas_config_get_volume_handle - returns volume handle for give hidden raid components + * @ioc: per adapter object + * @pd_handle: phys disk handle + * @volume_handle: volume handle + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt2sas_config_get_volume_handle(struct MPT2SAS_ADAPTER *ioc, u16 pd_handle, + u16 *volume_handle) +{ + Mpi2RaidConfigurationPage0_t *config_page; + Mpi2ConfigRequest_t mpi_request; + Mpi2ConfigReply_t mpi_reply; + int r, i; + struct config_request mem; + u16 ioc_status; + + mutex_lock(&ioc->config_cmds.mutex); + *volume_handle = 0; + memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); + mpi_request.Function = MPI2_FUNCTION_CONFIG; + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; + mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG; + mpi_request.Header.PageVersion = MPI2_RAIDCONFIG0_PAGEVERSION; + mpi_request.Header.PageNumber = 0; + mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); + r = _config_request(ioc, &mpi_request, &mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + if (r) + goto out; + + mpi_request.PageAddress = + cpu_to_le32(MPI2_RAID_PGAD_FORM_ACTIVE_CONFIG); + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + mpi_request.Header.PageVersion = mpi_reply.Header.PageVersion; + mpi_request.Header.PageNumber = mpi_reply.Header.PageNumber; + mpi_request.Header.PageType = mpi_reply.Header.PageType; + mpi_request.ExtPageLength = mpi_reply.ExtPageLength; + mpi_request.ExtPageType = mpi_reply.ExtPageType; + mem.config_page_sz = le16_to_cpu(mpi_reply.ExtPageLength) * 4; + if (mem.config_page_sz > ioc->config_page_sz) { + r = _config_alloc_config_dma_memory(ioc, &mem); + if (r) + goto out; + } else { + mem.config_page_dma = ioc->config_page_dma; + mem.config_page = ioc->config_page; + } + ioc->base_add_sg_single(&mpi_request.PageBufferSGE, + MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz, + mem.config_page_dma); + r = _config_request(ioc, &mpi_request, &mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + if (r) + goto out; + + r = -1; + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) + goto done; + config_page = mem.config_page; + for (i = 0; i < config_page->NumElements; i++) { + if ((config_page->ConfigElement[i].ElementFlags & + MPI2_RAIDCONFIG0_EFLAGS_MASK_ELEMENT_TYPE) != + MPI2_RAIDCONFIG0_EFLAGS_VOL_PHYS_DISK_ELEMENT) + continue; + if (config_page->ConfigElement[i].PhysDiskDevHandle == + pd_handle) { + *volume_handle = le16_to_cpu(config_page-> + ConfigElement[i].VolDevHandle); + r = 0; + goto done; + } + } + + done: + if (mem.config_page_sz > ioc->config_page_sz) + _config_free_config_dma_memory(ioc, &mem); + + out: + mutex_unlock(&ioc->config_cmds.mutex); + return r; +} + +/** + * mpt2sas_config_get_volume_wwid - returns wwid given the volume handle + * @ioc: per adapter object + * @volume_handle: volume handle + * @wwid: volume wwid + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt2sas_config_get_volume_wwid(struct MPT2SAS_ADAPTER *ioc, u16 volume_handle, + u64 *wwid) +{ + Mpi2ConfigReply_t mpi_reply; + Mpi2RaidVolPage1_t raid_vol_pg1; + + *wwid = 0; + if (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply, + &raid_vol_pg1, MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, + volume_handle))) { + *wwid = le64_to_cpu(raid_vol_pg1.WWID); + return 0; + } else + return -1; +} diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c new file mode 100644 index 00000000000..2d4f85c9d7a --- /dev/null +++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c @@ -0,0 +1,2516 @@ +/* + * Management Module Support for MPT (Message Passing Technology) based + * controllers + * + * This code is based on drivers/scsi/mpt2sas/mpt2_ctl.c + * Copyright (C) 2007-2008 LSI Corporation + * (mailto:DL-MPTFusionLinux@lsi.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. + * + * NO WARRANTY + * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT + * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is + * solely responsible for determining the appropriateness of using and + * distributing the Program and assumes all risks associated with its + * exercise of rights under this Agreement, including but not limited to + * the risks and costs of program errors, damage to or loss of data, + * programs or equipment, and unavailability or interruption of operations. + + * DISCLAIMER OF LIABILITY + * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED + * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES + + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ + +#include <linux/version.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/delay.h> +#include <linux/smp_lock.h> +#include <linux/compat.h> +#include <linux/poll.h> + +#include <linux/io.h> +#include <linux/uaccess.h> + +#include "mpt2sas_base.h" +#include "mpt2sas_ctl.h" + +static struct fasync_struct *async_queue; +static DECLARE_WAIT_QUEUE_HEAD(ctl_poll_wait); + +/** + * enum block_state - blocking state + * @NON_BLOCKING: non blocking + * @BLOCKING: blocking + * + * These states are for ioctls that need to wait for a response + * from firmware, so they probably require sleep. + */ +enum block_state { + NON_BLOCKING, + BLOCKING, +}; + +#ifdef CONFIG_SCSI_MPT2SAS_LOGGING +/** + * _ctl_display_some_debug - debug routine + * @ioc: per adapter object + * @smid: system request message index + * @calling_function_name: string pass from calling function + * @mpi_reply: reply message frame + * Context: none. + * + * Function for displaying debug info helpfull when debugging issues + * in this module. + */ +static void +_ctl_display_some_debug(struct MPT2SAS_ADAPTER *ioc, u16 smid, + char *calling_function_name, MPI2DefaultReply_t *mpi_reply) +{ + Mpi2ConfigRequest_t *mpi_request; + char *desc = NULL; + + if (!(ioc->logging_level & MPT_DEBUG_IOCTL)) + return; + + mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); + switch (mpi_request->Function) { + case MPI2_FUNCTION_SCSI_IO_REQUEST: + { + Mpi2SCSIIORequest_t *scsi_request = + (Mpi2SCSIIORequest_t *)mpi_request; + + snprintf(ioc->tmp_string, MPT_STRING_LENGTH, + "scsi_io, cmd(0x%02x), cdb_len(%d)", + scsi_request->CDB.CDB32[0], + le16_to_cpu(scsi_request->IoFlags) & 0xF); + desc = ioc->tmp_string; + break; + } + case MPI2_FUNCTION_SCSI_TASK_MGMT: + desc = "task_mgmt"; + break; + case MPI2_FUNCTION_IOC_INIT: + desc = "ioc_init"; + break; + case MPI2_FUNCTION_IOC_FACTS: + desc = "ioc_facts"; + break; + case MPI2_FUNCTION_CONFIG: + { + Mpi2ConfigRequest_t *config_request = + (Mpi2ConfigRequest_t *)mpi_request; + + snprintf(ioc->tmp_string, MPT_STRING_LENGTH, + "config, type(0x%02x), ext_type(0x%02x), number(%d)", + (config_request->Header.PageType & + MPI2_CONFIG_PAGETYPE_MASK), config_request->ExtPageType, + config_request->Header.PageNumber); + desc = ioc->tmp_string; + break; + } + case MPI2_FUNCTION_PORT_FACTS: + desc = "port_facts"; + break; + case MPI2_FUNCTION_PORT_ENABLE: + desc = "port_enable"; + break; + case MPI2_FUNCTION_EVENT_NOTIFICATION: + desc = "event_notification"; + break; + case MPI2_FUNCTION_FW_DOWNLOAD: + desc = "fw_download"; + break; + case MPI2_FUNCTION_FW_UPLOAD: + desc = "fw_upload"; + break; + case MPI2_FUNCTION_RAID_ACTION: + desc = "raid_action"; + break; + case MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH: + { + Mpi2SCSIIORequest_t *scsi_request = + (Mpi2SCSIIORequest_t *)mpi_request; + + snprintf(ioc->tmp_string, MPT_STRING_LENGTH, + "raid_pass, cmd(0x%02x), cdb_len(%d)", + scsi_request->CDB.CDB32[0], + le16_to_cpu(scsi_request->IoFlags) & 0xF); + desc = ioc->tmp_string; + break; + } + case MPI2_FUNCTION_SAS_IO_UNIT_CONTROL: + desc = "sas_iounit_cntl"; + break; + case MPI2_FUNCTION_SATA_PASSTHROUGH: + desc = "sata_pass"; + break; + case MPI2_FUNCTION_DIAG_BUFFER_POST: + desc = "diag_buffer_post"; + break; + case MPI2_FUNCTION_DIAG_RELEASE: + desc = "diag_release"; + break; + case MPI2_FUNCTION_SMP_PASSTHROUGH: + desc = "smp_passthrough"; + break; + } + + if (!desc) + return; + + printk(MPT2SAS_DEBUG_FMT "%s: %s, smid(%d)\n", + ioc->name, calling_function_name, desc, smid); + + if (!mpi_reply) + return; + + if (mpi_reply->IOCStatus || mpi_reply->IOCLogInfo) + printk(MPT2SAS_DEBUG_FMT + "\tiocstatus(0x%04x), loginfo(0x%08x)\n", + ioc->name, le16_to_cpu(mpi_reply->IOCStatus), + le32_to_cpu(mpi_reply->IOCLogInfo)); + + if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST || + mpi_request->Function == + MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) { + Mpi2SCSIIOReply_t *scsi_reply = + (Mpi2SCSIIOReply_t *)mpi_reply; + if (scsi_reply->SCSIState || scsi_reply->SCSIStatus) + printk(MPT2SAS_DEBUG_FMT + "\tscsi_state(0x%02x), scsi_status" + "(0x%02x)\n", ioc->name, + scsi_reply->SCSIState, + scsi_reply->SCSIStatus); + } +} +#endif + +/** + * mpt2sas_ctl_done - ctl module completion routine + * @ioc: per adapter object + * @smid: system request message index + * @VF_ID: virtual function id + * @reply: reply message frame(lower 32bit addr) + * Context: none. + * + * The callback handler when using ioc->ctl_cb_idx. + * + * Return nothing. + */ +void +mpt2sas_ctl_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply) +{ + MPI2DefaultReply_t *mpi_reply; + + if (ioc->ctl_cmds.status == MPT2_CMD_NOT_USED) + return; + if (ioc->ctl_cmds.smid != smid) + return; + ioc->ctl_cmds.status |= MPT2_CMD_COMPLETE; + mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); + if (mpi_reply) { + memcpy(ioc->ctl_cmds.reply, mpi_reply, mpi_reply->MsgLength*4); + ioc->ctl_cmds.status |= MPT2_CMD_REPLY_VALID; + } +#ifdef CONFIG_SCSI_MPT2SAS_LOGGING + _ctl_display_some_debug(ioc, smid, "ctl_done", mpi_reply); +#endif + ioc->ctl_cmds.status &= ~MPT2_CMD_PENDING; + complete(&ioc->ctl_cmds.done); +} + +/** + * _ctl_check_event_type - determines when an event needs logging + * @ioc: per adapter object + * @event: firmware event + * + * The bitmask in ioc->event_type[] indicates which events should be + * be saved in the driver event_log. This bitmask is set by application. + * + * Returns 1 when event should be captured, or zero means no match. + */ +static int +_ctl_check_event_type(struct MPT2SAS_ADAPTER *ioc, u16 event) +{ + u16 i; + u32 desired_event; + + if (event >= 128 || !event || !ioc->event_log) + return 0; + + desired_event = (1 << (event % 32)); + if (!desired_event) + desired_event = 1; + i = event / 32; + return desired_event & ioc->event_type[i]; +} + +/** + * mpt2sas_ctl_add_to_event_log - add event + * @ioc: per adapter object + * @mpi_reply: reply message frame + * + * Return nothing. + */ +void +mpt2sas_ctl_add_to_event_log(struct MPT2SAS_ADAPTER *ioc, + Mpi2EventNotificationReply_t *mpi_reply) +{ + struct MPT2_IOCTL_EVENTS *event_log; + u16 event; + int i; + u32 sz, event_data_sz; + u8 send_aen = 0; + + if (!ioc->event_log) + return; + + event = le16_to_cpu(mpi_reply->Event); + + if (_ctl_check_event_type(ioc, event)) { + + /* insert entry into circular event_log */ + i = ioc->event_context % MPT2SAS_CTL_EVENT_LOG_SIZE; + event_log = ioc->event_log; + event_log[i].event = event; + event_log[i].context = ioc->event_context++; + + event_data_sz = le16_to_cpu(mpi_reply->EventDataLength)*4; + sz = min_t(u32, event_data_sz, MPT2_EVENT_DATA_SIZE); + memset(event_log[i].data, 0, MPT2_EVENT_DATA_SIZE); + memcpy(event_log[i].data, mpi_reply->EventData, sz); + send_aen = 1; + } + + /* This aen_event_read_flag flag is set until the + * application has read the event log. + * For MPI2_EVENT_LOG_ENTRY_ADDED, we always notify. + */ + if (event == MPI2_EVENT_LOG_ENTRY_ADDED || + (send_aen && !ioc->aen_event_read_flag)) { + ioc->aen_event_read_flag = 1; + wake_up_interruptible(&ctl_poll_wait); + if (async_queue) + kill_fasync(&async_queue, SIGIO, POLL_IN); + } +} + +/** + * mpt2sas_ctl_event_callback - firmware event handler (called at ISR time) + * @ioc: per adapter object + * @VF_ID: virtual function id + * @reply: reply message frame(lower 32bit addr) + * Context: interrupt. + * + * This function merely adds a new work task into ioc->firmware_event_thread. + * The tasks are worked from _firmware_event_work in user context. + * + * Return nothing. + */ +void +mpt2sas_ctl_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply) +{ + Mpi2EventNotificationReply_t *mpi_reply; + + mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); + mpt2sas_ctl_add_to_event_log(ioc, mpi_reply); +} + +/** + * _ctl_verify_adapter - validates ioc_number passed from application + * @ioc: per adapter object + * @iocpp: The ioc pointer is returned in this. + * + * Return (-1) means error, else ioc_number. + */ +static int +_ctl_verify_adapter(int ioc_number, struct MPT2SAS_ADAPTER **iocpp) +{ + struct MPT2SAS_ADAPTER *ioc; + + list_for_each_entry(ioc, &mpt2sas_ioc_list, list) { + if (ioc->id != ioc_number) + continue; + *iocpp = ioc; + return ioc_number; + } + *iocpp = NULL; + return -1; +} + +/** + * mpt2sas_ctl_reset_handler - reset callback handler (for ctl) + * @ioc: per adapter object + * @reset_phase: phase + * + * The handler for doing any required cleanup or initialization. + * + * The reset phase can be MPT2_IOC_PRE_RESET, MPT2_IOC_AFTER_RESET, + * MPT2_IOC_DONE_RESET + */ +void +mpt2sas_ctl_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase) +{ + switch (reset_phase) { + case MPT2_IOC_PRE_RESET: + dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " + "MPT2_IOC_PRE_RESET\n", ioc->name, __func__)); + break; + case MPT2_IOC_AFTER_RESET: + dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " + "MPT2_IOC_AFTER_RESET\n", ioc->name, __func__)); + if (ioc->ctl_cmds.status & MPT2_CMD_PENDING) { + ioc->ctl_cmds.status |= MPT2_CMD_RESET; + mpt2sas_base_free_smid(ioc, ioc->ctl_cmds.smid); + complete(&ioc->ctl_cmds.done); + } + break; + case MPT2_IOC_DONE_RESET: + dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " + "MPT2_IOC_DONE_RESET\n", ioc->name, __func__)); + break; + } +} + +/** + * _ctl_fasync - + * @fd - + * @filep - + * @mode - + * + * Called when application request fasyn callback handler. + */ +static int +_ctl_fasync(int fd, struct file *filep, int mode) +{ + return fasync_helper(fd, filep, mode, &async_queue); +} + +/** + * _ctl_release - + * @inode - + * @filep - + * + * Called when application releases the fasyn callback handler. + */ +static int +_ctl_release(struct inode *inode, struct file *filep) +{ + return fasync_helper(-1, filep, 0, &async_queue); +} + +/** + * _ctl_poll - + * @file - + * @wait - + * + */ +static unsigned int +_ctl_poll(struct file *filep, poll_table *wait) +{ + struct MPT2SAS_ADAPTER *ioc; + + poll_wait(filep, &ctl_poll_wait, wait); + + list_for_each_entry(ioc, &mpt2sas_ioc_list, list) { + if (ioc->aen_event_read_flag) + return POLLIN | POLLRDNORM; + } + return 0; +} + +/** + * _ctl_do_task_abort - assign an active smid to the abort_task + * @ioc: per adapter object + * @karg - (struct mpt2_ioctl_command) + * @tm_request - pointer to mf from user space + * + * Returns 0 when an smid if found, else fail. + * during failure, the reply frame is filled. + */ +static int +_ctl_do_task_abort(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command *karg, + Mpi2SCSITaskManagementRequest_t *tm_request) +{ + u8 found = 0; + u16 i; + u16 handle; + struct scsi_cmnd *scmd; + struct MPT2SAS_DEVICE *priv_data; + unsigned long flags; + Mpi2SCSITaskManagementReply_t *tm_reply; + u32 sz; + u32 lun; + + lun = scsilun_to_int((struct scsi_lun *)tm_request->LUN); + + handle = le16_to_cpu(tm_request->DevHandle); + spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); + for (i = ioc->request_depth; i && !found; i--) { + scmd = ioc->scsi_lookup[i - 1].scmd; + if (scmd == NULL || scmd->device == NULL || + scmd->device->hostdata == NULL) + continue; + if (lun != scmd->device->lun) + continue; + priv_data = scmd->device->hostdata; + if (priv_data->sas_target == NULL) + continue; + if (priv_data->sas_target->handle != handle) + continue; + tm_request->TaskMID = cpu_to_le16(ioc->scsi_lookup[i - 1].smid); + found = 1; + } + spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); + + if (!found) { + dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "ABORT_TASK: " + "DevHandle(0x%04x), lun(%d), no active mid!!\n", ioc->name, + tm_request->DevHandle, lun)); + tm_reply = ioc->ctl_cmds.reply; + tm_reply->DevHandle = tm_request->DevHandle; + tm_reply->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; + tm_reply->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK; + tm_reply->MsgLength = sizeof(Mpi2SCSITaskManagementReply_t)/4; + tm_reply->VP_ID = tm_request->VP_ID; + tm_reply->VF_ID = tm_request->VF_ID; + sz = min_t(u32, karg->max_reply_bytes, ioc->reply_sz); + if (copy_to_user(karg->reply_frame_buf_ptr, ioc->ctl_cmds.reply, + sz)) + printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, + __LINE__, __func__); + return 1; + } + + dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "ABORT_TASK: " + "DevHandle(0x%04x), lun(%d), smid(%d)\n", ioc->name, + tm_request->DevHandle, lun, tm_request->TaskMID)); + return 0; +} + +/** + * _ctl_do_mpt_command - main handler for MPT2COMMAND opcode + * @ioc: per adapter object + * @karg - (struct mpt2_ioctl_command) + * @mf - pointer to mf in user space + * @state - NON_BLOCKING or BLOCKING + */ +static long +_ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, + struct mpt2_ioctl_command karg, void __user *mf, enum block_state state) +{ + MPI2RequestHeader_t *mpi_request; + MPI2DefaultReply_t *mpi_reply; + u32 ioc_state; + u16 ioc_status; + u16 smid; + unsigned long timeout, timeleft; + u8 issue_reset; + u32 sz; + void *psge; + void *priv_sense = NULL; + void *data_out = NULL; + dma_addr_t data_out_dma; + size_t data_out_sz = 0; + void *data_in = NULL; + dma_addr_t data_in_dma; + size_t data_in_sz = 0; + u32 sgl_flags; + long ret; + u16 wait_state_count; + + issue_reset = 0; + + if (state == NON_BLOCKING && !mutex_trylock(&ioc->ctl_cmds.mutex)) + return -EAGAIN; + else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex)) + return -ERESTARTSYS; + + if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) { + printk(MPT2SAS_ERR_FMT "%s: ctl_cmd in use\n", + ioc->name, __func__); + ret = -EAGAIN; + goto out; + } + + wait_state_count = 0; + ioc_state = mpt2sas_base_get_iocstate(ioc, 1); + while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { + if (wait_state_count++ == 10) { + printk(MPT2SAS_ERR_FMT + "%s: failed due to ioc not operational\n", + ioc->name, __func__); + ret = -EFAULT; + goto out; + } + ssleep(1); + ioc_state = mpt2sas_base_get_iocstate(ioc, 1); + printk(MPT2SAS_INFO_FMT "%s: waiting for " + "operational state(count=%d)\n", ioc->name, + __func__, wait_state_count); + } + if (wait_state_count) + printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n", + ioc->name, __func__); + + smid = mpt2sas_base_get_smid(ioc, ioc->ctl_cb_idx); + if (!smid) { + printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", + ioc->name, __func__); + ret = -EAGAIN; + goto out; + } + + ret = 0; + ioc->ctl_cmds.status = MPT2_CMD_PENDING; + memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz); + mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); + ioc->ctl_cmds.smid = smid; + data_out_sz = karg.data_out_size; + data_in_sz = karg.data_in_size; + + /* copy in request message frame from user */ + if (copy_from_user(mpi_request, mf, karg.data_sge_offset*4)) { + printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, __LINE__, + __func__); + ret = -EFAULT; + mpt2sas_base_free_smid(ioc, smid); + goto out; + } + + if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST || + mpi_request->Function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) { + if (!mpi_request->FunctionDependent1 || + mpi_request->FunctionDependent1 > + cpu_to_le16(ioc->facts.MaxDevHandle)) { + ret = -EINVAL; + mpt2sas_base_free_smid(ioc, smid); + goto out; + } + } + + /* obtain dma-able memory for data transfer */ + if (data_out_sz) /* WRITE */ { + data_out = pci_alloc_consistent(ioc->pdev, data_out_sz, + &data_out_dma); + if (!data_out) { + printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, + __LINE__, __func__); + ret = -ENOMEM; + mpt2sas_base_free_smid(ioc, smid); + goto out; + } + if (copy_from_user(data_out, karg.data_out_buf_ptr, + data_out_sz)) { + printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, + __LINE__, __func__); + ret = -EFAULT; + mpt2sas_base_free_smid(ioc, smid); + goto out; + } + } + + if (data_in_sz) /* READ */ { + data_in = pci_alloc_consistent(ioc->pdev, data_in_sz, + &data_in_dma); + if (!data_in) { + printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, + __LINE__, __func__); + ret = -ENOMEM; + mpt2sas_base_free_smid(ioc, smid); + goto out; + } + } + + /* add scatter gather elements */ + psge = (void *)mpi_request + (karg.data_sge_offset*4); + + if (!data_out_sz && !data_in_sz) { + mpt2sas_base_build_zero_len_sge(ioc, psge); + } else if (data_out_sz && data_in_sz) { + /* WRITE sgel first */ + sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | + MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC); + sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; + ioc->base_add_sg_single(psge, sgl_flags | + data_out_sz, data_out_dma); + + /* incr sgel */ + psge += ioc->sge_size; + + /* READ sgel last */ + sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | + MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER | + MPI2_SGE_FLAGS_END_OF_LIST); + sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; + ioc->base_add_sg_single(psge, sgl_flags | + data_in_sz, data_in_dma); + } else if (data_out_sz) /* WRITE */ { + sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | + MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER | + MPI2_SGE_FLAGS_END_OF_LIST | MPI2_SGE_FLAGS_HOST_TO_IOC); + sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; + ioc->base_add_sg_single(psge, sgl_flags | + data_out_sz, data_out_dma); + } else if (data_in_sz) /* READ */ { + sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | + MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER | + MPI2_SGE_FLAGS_END_OF_LIST); + sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; + ioc->base_add_sg_single(psge, sgl_flags | + data_in_sz, data_in_dma); + } + + /* send command to firmware */ +#ifdef CONFIG_SCSI_MPT2SAS_LOGGING + _ctl_display_some_debug(ioc, smid, "ctl_request", NULL); +#endif + + switch (mpi_request->Function) { + case MPI2_FUNCTION_SCSI_IO_REQUEST: + case MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH: + { + Mpi2SCSIIORequest_t *scsiio_request = + (Mpi2SCSIIORequest_t *)mpi_request; + scsiio_request->SenseBufferLowAddress = + (u32)mpt2sas_base_get_sense_buffer_dma(ioc, smid); + priv_sense = mpt2sas_base_get_sense_buffer(ioc, smid); + memset(priv_sense, 0, SCSI_SENSE_BUFFERSIZE); + mpt2sas_base_put_smid_scsi_io(ioc, smid, 0, + le16_to_cpu(mpi_request->FunctionDependent1)); + break; + } + case MPI2_FUNCTION_SCSI_TASK_MGMT: + { + Mpi2SCSITaskManagementRequest_t *tm_request = + (Mpi2SCSITaskManagementRequest_t *)mpi_request; + + if (tm_request->TaskType == + MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK) { + if (_ctl_do_task_abort(ioc, &karg, tm_request)) + goto out; + } + + mutex_lock(&ioc->tm_cmds.mutex); + mpt2sas_scsih_set_tm_flag(ioc, le16_to_cpu( + tm_request->DevHandle)); + mpt2sas_base_put_smid_hi_priority(ioc, smid, + mpi_request->VF_ID); + break; + } + case MPI2_FUNCTION_SMP_PASSTHROUGH: + { + Mpi2SmpPassthroughRequest_t *smp_request = + (Mpi2SmpPassthroughRequest_t *)mpi_request; + u8 *data; + + /* ioc determines which port to use */ + smp_request->PhysicalPort = 0xFF; + if (smp_request->PassthroughFlags & + MPI2_SMP_PT_REQ_PT_FLAGS_IMMEDIATE) + data = (u8 *)&smp_request->SGL; + else + data = data_out; + + if (data[1] == 0x91 && (data[10] == 1 || data[10] == 2)) { + ioc->ioc_link_reset_in_progress = 1; + ioc->ignore_loginfos = 1; + } + mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID); + break; + } + case MPI2_FUNCTION_SAS_IO_UNIT_CONTROL: + { + Mpi2SasIoUnitControlRequest_t *sasiounit_request = + (Mpi2SasIoUnitControlRequest_t *)mpi_request; + + if (sasiounit_request->Operation == MPI2_SAS_OP_PHY_HARD_RESET + || sasiounit_request->Operation == + MPI2_SAS_OP_PHY_LINK_RESET) { + ioc->ioc_link_reset_in_progress = 1; + ioc->ignore_loginfos = 1; + } + mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID); + break; + } + default: + mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID); + break; + } + + if (karg.timeout < MPT2_IOCTL_DEFAULT_TIMEOUT) + timeout = MPT2_IOCTL_DEFAULT_TIMEOUT; + else + timeout = karg.timeout; + timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done, + timeout*HZ); + if (mpi_request->Function == MPI2_FUNCTION_SCSI_TASK_MGMT) { + Mpi2SCSITaskManagementRequest_t *tm_request = + (Mpi2SCSITaskManagementRequest_t *)mpi_request; + mutex_unlock(&ioc->tm_cmds.mutex); + mpt2sas_scsih_clear_tm_flag(ioc, le16_to_cpu( + tm_request->DevHandle)); + } else if ((mpi_request->Function == MPI2_FUNCTION_SMP_PASSTHROUGH || + mpi_request->Function == MPI2_FUNCTION_SAS_IO_UNIT_CONTROL) && + ioc->ioc_link_reset_in_progress) { + ioc->ioc_link_reset_in_progress = 0; + ioc->ignore_loginfos = 0; + } + if (!(ioc->ctl_cmds.status & MPT2_CMD_COMPLETE)) { + printk(MPT2SAS_ERR_FMT "%s: timeout\n", ioc->name, + __func__); + _debug_dump_mf(mpi_request, karg.data_sge_offset); + if (!(ioc->ctl_cmds.status & MPT2_CMD_RESET)) + issue_reset = 1; + goto issue_host_reset; + } + + mpi_reply = ioc->ctl_cmds.reply; + ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK; + +#ifdef CONFIG_SCSI_MPT2SAS_LOGGING + if (mpi_reply->Function == MPI2_FUNCTION_SCSI_TASK_MGMT && + (ioc->logging_level & MPT_DEBUG_TM)) { + Mpi2SCSITaskManagementReply_t *tm_reply = + (Mpi2SCSITaskManagementReply_t *)mpi_reply; + + printk(MPT2SAS_DEBUG_FMT "TASK_MGMT: " + "IOCStatus(0x%04x), IOCLogInfo(0x%08x), " + "TerminationCount(0x%08x)\n", ioc->name, + tm_reply->IOCStatus, tm_reply->IOCLogInfo, + tm_reply->TerminationCount); + } +#endif + /* copy out xdata to user */ + if (data_in_sz) { + if (copy_to_user(karg.data_in_buf_ptr, data_in, + data_in_sz)) { + printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, + __LINE__, __func__); + ret = -ENODATA; + goto out; + } + } + + /* copy out reply message frame to user */ + if (karg.max_reply_bytes) { + sz = min_t(u32, karg.max_reply_bytes, ioc->reply_sz); + if (copy_to_user(karg.reply_frame_buf_ptr, ioc->ctl_cmds.reply, + sz)) { + printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, + __LINE__, __func__); + ret = -ENODATA; + goto out; + } + } + + /* copy out sense to user */ + if (karg.max_sense_bytes && (mpi_request->Function == + MPI2_FUNCTION_SCSI_IO_REQUEST || mpi_request->Function == + MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) { + sz = min_t(u32, karg.max_sense_bytes, SCSI_SENSE_BUFFERSIZE); + if (copy_to_user(karg.sense_data_ptr, priv_sense, sz)) { + printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, + __LINE__, __func__); + ret = -ENODATA; + goto out; + } + } + + issue_host_reset: + if (issue_reset) { + if ((mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST || + mpi_request->Function == + MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) { + printk(MPT2SAS_INFO_FMT "issue target reset: handle " + "= (0x%04x)\n", ioc->name, + mpi_request->FunctionDependent1); + mutex_lock(&ioc->tm_cmds.mutex); + mpt2sas_scsih_issue_tm(ioc, + mpi_request->FunctionDependent1, 0, + MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 10); + ioc->tm_cmds.status = MPT2_CMD_NOT_USED; + mutex_unlock(&ioc->tm_cmds.mutex); + } else + mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, + FORCE_BIG_HAMMER); + } + + out: + + /* free memory associated with sg buffers */ + if (data_in) + pci_free_consistent(ioc->pdev, data_in_sz, data_in, + data_in_dma); + + if (data_out) + pci_free_consistent(ioc->pdev, data_out_sz, data_out, + data_out_dma); + + ioc->ctl_cmds.status = MPT2_CMD_NOT_USED; + mutex_unlock(&ioc->ctl_cmds.mutex); + return ret; +} + +/** + * _ctl_getiocinfo - main handler for MPT2IOCINFO opcode + * @arg - user space buffer containing ioctl content + */ +static long +_ctl_getiocinfo(void __user *arg) +{ + struct mpt2_ioctl_iocinfo karg; + struct MPT2SAS_ADAPTER *ioc; + u8 revision; + + if (copy_from_user(&karg, arg, sizeof(karg))) { + printk(KERN_ERR "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); + return -EFAULT; + } + if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) + return -ENODEV; + + dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name, + __func__)); + + memset(&karg, 0 , sizeof(karg)); + karg.adapter_type = MPT2_IOCTL_INTERFACE_SAS2; + if (ioc->pfacts) + karg.port_number = ioc->pfacts[0].PortNumber; + pci_read_config_byte(ioc->pdev, PCI_CLASS_REVISION, &revision); + karg.hw_rev = revision; + karg.pci_id = ioc->pdev->device; + karg.subsystem_device = ioc->pdev->subsystem_device; + karg.subsystem_vendor = ioc->pdev->subsystem_vendor; + karg.pci_information.u.bits.bus = ioc->pdev->bus->number; + karg.pci_information.u.bits.device = PCI_SLOT(ioc->pdev->devfn); + karg.pci_information.u.bits.function = PCI_FUNC(ioc->pdev->devfn); + karg.pci_information.segment_id = pci_domain_nr(ioc->pdev->bus); + karg.firmware_version = ioc->facts.FWVersion.Word; + strncpy(karg.driver_version, MPT2SAS_DRIVER_VERSION, + MPT2_IOCTL_VERSION_LENGTH); + karg.driver_version[MPT2_IOCTL_VERSION_LENGTH - 1] = '\0'; + karg.bios_version = le32_to_cpu(ioc->bios_pg3.BiosVersion); + + if (copy_to_user(arg, &karg, sizeof(karg))) { + printk(KERN_ERR "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); + return -EFAULT; + } + return 0; +} + +/** + * _ctl_eventquery - main handler for MPT2EVENTQUERY opcode + * @arg - user space buffer containing ioctl content + */ +static long +_ctl_eventquery(void __user *arg) +{ + struct mpt2_ioctl_eventquery karg; + struct MPT2SAS_ADAPTER *ioc; + + if (copy_from_user(&karg, arg, sizeof(karg))) { + printk(KERN_ERR "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); + return -EFAULT; + } + if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) + return -ENODEV; + + dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name, + __func__)); + + karg.event_entries = MPT2SAS_CTL_EVENT_LOG_SIZE; + memcpy(karg.event_types, ioc->event_type, + MPI2_EVENT_NOTIFY_EVENTMASK_WORDS * sizeof(u32)); + + if (copy_to_user(arg, &karg, sizeof(karg))) { + printk(KERN_ERR "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); + return -EFAULT; + } + return 0; +} + +/** + * _ctl_eventenable - main handler for MPT2EVENTENABLE opcode + * @arg - user space buffer containing ioctl content + */ +static long +_ctl_eventenable(void __user *arg) +{ + struct mpt2_ioctl_eventenable karg; + struct MPT2SAS_ADAPTER *ioc; + + if (copy_from_user(&karg, arg, sizeof(karg))) { + printk(KERN_ERR "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); + return -EFAULT; + } + if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) + return -ENODEV; + + dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name, + __func__)); + + if (ioc->event_log) + return 0; + memcpy(ioc->event_type, karg.event_types, + MPI2_EVENT_NOTIFY_EVENTMASK_WORDS * sizeof(u32)); + mpt2sas_base_validate_event_type(ioc, ioc->event_type); + + /* initialize event_log */ + ioc->event_context = 0; + ioc->aen_event_read_flag = 0; + ioc->event_log = kcalloc(MPT2SAS_CTL_EVENT_LOG_SIZE, + sizeof(struct MPT2_IOCTL_EVENTS), GFP_KERNEL); + if (!ioc->event_log) { + printk(KERN_ERR "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); + return -ENOMEM; + } + return 0; +} + +/** + * _ctl_eventreport - main handler for MPT2EVENTREPORT opcode + * @arg - user space buffer containing ioctl content + */ +static long +_ctl_eventreport(void __user *arg) +{ + struct mpt2_ioctl_eventreport karg; + struct MPT2SAS_ADAPTER *ioc; + u32 number_bytes, max_events, max; + struct mpt2_ioctl_eventreport __user *uarg = arg; + + if (copy_from_user(&karg, arg, sizeof(karg))) { + printk(KERN_ERR "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); + return -EFAULT; + } + if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) + return -ENODEV; + + dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name, + __func__)); + + number_bytes = karg.hdr.max_data_size - + sizeof(struct mpt2_ioctl_header); + max_events = number_bytes/sizeof(struct MPT2_IOCTL_EVENTS); + max = min_t(u32, MPT2SAS_CTL_EVENT_LOG_SIZE, max_events); + + /* If fewer than 1 event is requested, there must have + * been some type of error. + */ + if (!max || !ioc->event_log) + return -ENODATA; + + number_bytes = max * sizeof(struct MPT2_IOCTL_EVENTS); + if (copy_to_user(uarg->event_data, ioc->event_log, number_bytes)) { + printk(KERN_ERR "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); + return -EFAULT; + } + + /* reset flag so SIGIO can restart */ + ioc->aen_event_read_flag = 0; + return 0; +} + +/** + * _ctl_do_reset - main handler for MPT2HARDRESET opcode + * @arg - user space buffer containing ioctl content + */ +static long +_ctl_do_reset(void __user *arg) +{ + struct mpt2_ioctl_diag_reset karg; + struct MPT2SAS_ADAPTER *ioc; + int retval; + + if (copy_from_user(&karg, arg, sizeof(karg))) { + printk(KERN_ERR "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); + return -EFAULT; + } + if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) + return -ENODEV; + + dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name, + __func__)); + + retval = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, + FORCE_BIG_HAMMER); + printk(MPT2SAS_INFO_FMT "host reset: %s\n", + ioc->name, ((!retval) ? "SUCCESS" : "FAILED")); + return 0; +} + +/** + * _ctl_btdh_search_sas_device - searching for sas device + * @ioc: per adapter object + * @btdh: btdh ioctl payload + */ +static int +_ctl_btdh_search_sas_device(struct MPT2SAS_ADAPTER *ioc, + struct mpt2_ioctl_btdh_mapping *btdh) +{ + struct _sas_device *sas_device; + unsigned long flags; + int rc = 0; + + if (list_empty(&ioc->sas_device_list)) + return rc; + + spin_lock_irqsave(&ioc->sas_device_lock, flags); + list_for_each_entry(sas_device, &ioc->sas_device_list, list) { + if (btdh->bus == 0xFFFFFFFF && btdh->id == 0xFFFFFFFF && + btdh->handle == sas_device->handle) { + btdh->bus = sas_device->channel; + btdh->id = sas_device->id; + rc = 1; + goto out; + } else if (btdh->bus == sas_device->channel && btdh->id == + sas_device->id && btdh->handle == 0xFFFF) { + btdh->handle = sas_device->handle; + rc = 1; + goto out; + } + } + out: + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + return rc; +} + +/** + * _ctl_btdh_search_raid_device - searching for raid device + * @ioc: per adapter object + * @btdh: btdh ioctl payload + */ +static int +_ctl_btdh_search_raid_device(struct MPT2SAS_ADAPTER *ioc, + struct mpt2_ioctl_btdh_mapping *btdh) +{ + struct _raid_device *raid_device; + unsigned long flags; + int rc = 0; + + if (list_empty(&ioc->raid_device_list)) + return rc; + + spin_lock_irqsave(&ioc->raid_device_lock, flags); + list_for_each_entry(raid_device, &ioc->raid_device_list, list) { + if (btdh->bus == 0xFFFFFFFF && btdh->id == 0xFFFFFFFF && + btdh->handle == raid_device->handle) { + btdh->bus = raid_device->channel; + btdh->id = raid_device->id; + rc = 1; + goto out; + } else if (btdh->bus == raid_device->channel && btdh->id == + raid_device->id && btdh->handle == 0xFFFF) { + btdh->handle = raid_device->handle; + rc = 1; + goto out; + } + } + out: + spin_unlock_irqrestore(&ioc->raid_device_lock, flags); + return rc; +} + +/** + * _ctl_btdh_mapping - main handler for MPT2BTDHMAPPING opcode + * @arg - user space buffer containing ioctl content + */ +static long +_ctl_btdh_mapping(void __user *arg) +{ + struct mpt2_ioctl_btdh_mapping karg; + struct MPT2SAS_ADAPTER *ioc; + int rc; + + if (copy_from_user(&karg, arg, sizeof(karg))) { + printk(KERN_ERR "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); + return -EFAULT; + } + if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) + return -ENODEV; + + dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + __func__)); + + rc = _ctl_btdh_search_sas_device(ioc, &karg); + if (!rc) + _ctl_btdh_search_raid_device(ioc, &karg); + + if (copy_to_user(arg, &karg, sizeof(karg))) { + printk(KERN_ERR "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); + return -EFAULT; + } + return 0; +} + +/** + * _ctl_diag_capability - return diag buffer capability + * @ioc: per adapter object + * @buffer_type: specifies either TRACE or SNAPSHOT + * + * returns 1 when diag buffer support is enabled in firmware + */ +static u8 +_ctl_diag_capability(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type) +{ + u8 rc = 0; + + switch (buffer_type) { + case MPI2_DIAG_BUF_TYPE_TRACE: + if (ioc->facts.IOCCapabilities & + MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER) + rc = 1; + break; + case MPI2_DIAG_BUF_TYPE_SNAPSHOT: + if (ioc->facts.IOCCapabilities & + MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER) + rc = 1; + break; + } + + return rc; +} + +/** + * _ctl_diag_register - application register with driver + * @arg - user space buffer containing ioctl content + * @state - NON_BLOCKING or BLOCKING + * + * This will allow the driver to setup any required buffers that will be + * needed by firmware to communicate with the driver. + */ +static long +_ctl_diag_register(void __user *arg, enum block_state state) +{ + struct mpt2_diag_register karg; + struct MPT2SAS_ADAPTER *ioc; + int rc, i; + void *request_data = NULL; + dma_addr_t request_data_dma; + u32 request_data_sz = 0; + Mpi2DiagBufferPostRequest_t *mpi_request; + Mpi2DiagBufferPostReply_t *mpi_reply; + u8 buffer_type; + unsigned long timeleft; + u16 smid; + u16 ioc_status; + u8 issue_reset = 0; + + if (copy_from_user(&karg, arg, sizeof(karg))) { + printk(KERN_ERR "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); + return -EFAULT; + } + if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) + return -ENODEV; + + dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + __func__)); + + buffer_type = karg.buffer_type; + if (!_ctl_diag_capability(ioc, buffer_type)) { + printk(MPT2SAS_ERR_FMT "%s: doesn't have capability for " + "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type); + return -EPERM; + } + + if (ioc->diag_buffer_status[buffer_type] & + MPT2_DIAG_BUFFER_IS_REGISTERED) { + printk(MPT2SAS_ERR_FMT "%s: already has a registered " + "buffer for buffer_type(0x%02x)\n", ioc->name, __func__, + buffer_type); + return -EINVAL; + } + + if (karg.requested_buffer_size % 4) { + printk(MPT2SAS_ERR_FMT "%s: the requested_buffer_size " + "is not 4 byte aligned\n", ioc->name, __func__); + return -EINVAL; + } + + if (state == NON_BLOCKING && !mutex_trylock(&ioc->ctl_cmds.mutex)) + return -EAGAIN; + else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex)) + return -ERESTARTSYS; + + if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) { + printk(MPT2SAS_ERR_FMT "%s: ctl_cmd in use\n", + ioc->name, __func__); + rc = -EAGAIN; + goto out; + } + + smid = mpt2sas_base_get_smid(ioc, ioc->ctl_cb_idx); + if (!smid) { + printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", + ioc->name, __func__); + rc = -EAGAIN; + goto out; + } + + rc = 0; + ioc->ctl_cmds.status = MPT2_CMD_PENDING; + memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz); + mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); + ioc->ctl_cmds.smid = smid; + + request_data = ioc->diag_buffer[buffer_type]; + request_data_sz = karg.requested_buffer_size; + ioc->unique_id[buffer_type] = karg.unique_id; + ioc->diag_buffer_status[buffer_type] = 0; + memcpy(ioc->product_specific[buffer_type], karg.product_specific, + MPT2_PRODUCT_SPECIFIC_DWORDS); + ioc->diagnostic_flags[buffer_type] = karg.diagnostic_flags; + + if (request_data) { + request_data_dma = ioc->diag_buffer_dma[buffer_type]; + if (request_data_sz != ioc->diag_buffer_sz[buffer_type]) { + pci_free_consistent(ioc->pdev, + ioc->diag_buffer_sz[buffer_type], + request_data, request_data_dma); + request_data = NULL; + } + } + + if (request_data == NULL) { + ioc->diag_buffer_sz[buffer_type] = 0; + ioc->diag_buffer_dma[buffer_type] = 0; + request_data = pci_alloc_consistent( + ioc->pdev, request_data_sz, &request_data_dma); + if (request_data == NULL) { + printk(MPT2SAS_ERR_FMT "%s: failed allocating memory" + " for diag buffers, requested size(%d)\n", + ioc->name, __func__, request_data_sz); + mpt2sas_base_free_smid(ioc, smid); + return -ENOMEM; + } + ioc->diag_buffer[buffer_type] = request_data; + ioc->diag_buffer_sz[buffer_type] = request_data_sz; + ioc->diag_buffer_dma[buffer_type] = request_data_dma; + } + + mpi_request->Function = MPI2_FUNCTION_DIAG_BUFFER_POST; + mpi_request->BufferType = karg.buffer_type; + mpi_request->Flags = cpu_to_le32(karg.diagnostic_flags); + mpi_request->BufferAddress = cpu_to_le64(request_data_dma); + mpi_request->BufferLength = cpu_to_le32(request_data_sz); + + dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: diag_buffer(0x%p), " + "dma(0x%llx), sz(%d)\n", ioc->name, __func__, request_data, + (unsigned long long)request_data_dma, mpi_request->BufferLength)); + + for (i = 0; i < MPT2_PRODUCT_SPECIFIC_DWORDS; i++) + mpi_request->ProductSpecific[i] = + cpu_to_le32(ioc->product_specific[buffer_type][i]); + + mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID); + timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done, + MPT2_IOCTL_DEFAULT_TIMEOUT*HZ); + + if (!(ioc->ctl_cmds.status & MPT2_CMD_COMPLETE)) { + printk(MPT2SAS_ERR_FMT "%s: timeout\n", ioc->name, + __func__); + _debug_dump_mf(mpi_request, + sizeof(Mpi2DiagBufferPostRequest_t)/4); + if (!(ioc->ctl_cmds.status & MPT2_CMD_RESET)) + issue_reset = 1; + goto issue_host_reset; + } + + /* process the completed Reply Message Frame */ + if ((ioc->ctl_cmds.status & MPT2_CMD_REPLY_VALID) == 0) { + printk(MPT2SAS_ERR_FMT "%s: no reply message\n", + ioc->name, __func__); + rc = -EFAULT; + goto out; + } + + mpi_reply = ioc->ctl_cmds.reply; + ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK; + + if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { + ioc->diag_buffer_status[buffer_type] |= + MPT2_DIAG_BUFFER_IS_REGISTERED; + dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: success\n", + ioc->name, __func__)); + } else { + printk(MPT2SAS_DEBUG_FMT "%s: ioc_status(0x%04x) " + "log_info(0x%08x)\n", ioc->name, __func__, + ioc_status, mpi_reply->IOCLogInfo); + rc = -EFAULT; + } + + issue_host_reset: + if (issue_reset) + mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, + FORCE_BIG_HAMMER); + + out: + + if (rc && request_data) + pci_free_consistent(ioc->pdev, request_data_sz, + request_data, request_data_dma); + + ioc->ctl_cmds.status = MPT2_CMD_NOT_USED; + mutex_unlock(&ioc->ctl_cmds.mutex); + return rc; +} + +/** + * _ctl_diag_unregister - application unregister with driver + * @arg - user space buffer containing ioctl content + * + * This will allow the driver to cleanup any memory allocated for diag + * messages and to free up any resources. + */ +static long +_ctl_diag_unregister(void __user *arg) +{ + struct mpt2_diag_unregister karg; + struct MPT2SAS_ADAPTER *ioc; + void *request_data; + dma_addr_t request_data_dma; + u32 request_data_sz; + u8 buffer_type; + + if (copy_from_user(&karg, arg, sizeof(karg))) { + printk(KERN_ERR "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); + return -EFAULT; + } + if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) + return -ENODEV; + + dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + __func__)); + + buffer_type = karg.unique_id & 0x000000ff; + if (!_ctl_diag_capability(ioc, buffer_type)) { + printk(MPT2SAS_ERR_FMT "%s: doesn't have capability for " + "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type); + return -EPERM; + } + + if ((ioc->diag_buffer_status[buffer_type] & + MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) { + printk(MPT2SAS_ERR_FMT "%s: buffer_type(0x%02x) is not " + "registered\n", ioc->name, __func__, buffer_type); + return -EINVAL; + } + if ((ioc->diag_buffer_status[buffer_type] & + MPT2_DIAG_BUFFER_IS_RELEASED) == 0) { + printk(MPT2SAS_ERR_FMT "%s: buffer_type(0x%02x) has not been " + "released\n", ioc->name, __func__, buffer_type); + return -EINVAL; + } + + if (karg.unique_id != ioc->unique_id[buffer_type]) { + printk(MPT2SAS_ERR_FMT "%s: unique_id(0x%08x) is not " + "registered\n", ioc->name, __func__, karg.unique_id); + return -EINVAL; + } + + request_data = ioc->diag_buffer[buffer_type]; + if (!request_data) { + printk(MPT2SAS_ERR_FMT "%s: doesn't have memory allocated for " + "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type); + return -ENOMEM; + } + + request_data_sz = ioc->diag_buffer_sz[buffer_type]; + request_data_dma = ioc->diag_buffer_dma[buffer_type]; + pci_free_consistent(ioc->pdev, request_data_sz, + request_data, request_data_dma); + ioc->diag_buffer[buffer_type] = NULL; + ioc->diag_buffer_status[buffer_type] = 0; + return 0; +} + +/** + * _ctl_diag_query - query relevant info associated with diag buffers + * @arg - user space buffer containing ioctl content + * + * The application will send only buffer_type and unique_id. Driver will + * inspect unique_id first, if valid, fill in all the info. If unique_id is + * 0x00, the driver will return info specified by Buffer Type. + */ +static long +_ctl_diag_query(void __user *arg) +{ + struct mpt2_diag_query karg; + struct MPT2SAS_ADAPTER *ioc; + void *request_data; + int i; + u8 buffer_type; + + if (copy_from_user(&karg, arg, sizeof(karg))) { + printk(KERN_ERR "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); + return -EFAULT; + } + if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) + return -ENODEV; + + dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + __func__)); + + karg.application_flags = 0; + buffer_type = karg.buffer_type; + + if (!_ctl_diag_capability(ioc, buffer_type)) { + printk(MPT2SAS_ERR_FMT "%s: doesn't have capability for " + "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type); + return -EPERM; + } + + if ((ioc->diag_buffer_status[buffer_type] & + MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) { + printk(MPT2SAS_ERR_FMT "%s: buffer_type(0x%02x) is not " + "registered\n", ioc->name, __func__, buffer_type); + return -EINVAL; + } + + if (karg.unique_id & 0xffffff00) { + if (karg.unique_id != ioc->unique_id[buffer_type]) { + printk(MPT2SAS_ERR_FMT "%s: unique_id(0x%08x) is not " + "registered\n", ioc->name, __func__, + karg.unique_id); + return -EINVAL; + } + } + + request_data = ioc->diag_buffer[buffer_type]; + if (!request_data) { + printk(MPT2SAS_ERR_FMT "%s: doesn't have buffer for " + "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type); + return -ENOMEM; + } + + if (ioc->diag_buffer_status[buffer_type] & MPT2_DIAG_BUFFER_IS_RELEASED) + karg.application_flags = (MPT2_APP_FLAGS_APP_OWNED | + MPT2_APP_FLAGS_BUFFER_VALID); + else + karg.application_flags = (MPT2_APP_FLAGS_APP_OWNED | + MPT2_APP_FLAGS_BUFFER_VALID | + MPT2_APP_FLAGS_FW_BUFFER_ACCESS); + + for (i = 0; i < MPT2_PRODUCT_SPECIFIC_DWORDS; i++) + karg.product_specific[i] = + ioc->product_specific[buffer_type][i]; + + karg.total_buffer_size = ioc->diag_buffer_sz[buffer_type]; + karg.driver_added_buffer_size = 0; + karg.unique_id = ioc->unique_id[buffer_type]; + karg.diagnostic_flags = ioc->diagnostic_flags[buffer_type]; + + if (copy_to_user(arg, &karg, sizeof(struct mpt2_diag_query))) { + printk(MPT2SAS_ERR_FMT "%s: unable to write mpt2_diag_query " + "data @ %p\n", ioc->name, __func__, arg); + return -EFAULT; + } + return 0; +} + +/** + * _ctl_diag_release - request to send Diag Release Message to firmware + * @arg - user space buffer containing ioctl content + * @state - NON_BLOCKING or BLOCKING + * + * This allows ownership of the specified buffer to returned to the driver, + * allowing an application to read the buffer without fear that firmware is + * overwritting information in the buffer. + */ +static long +_ctl_diag_release(void __user *arg, enum block_state state) +{ + struct mpt2_diag_release karg; + struct MPT2SAS_ADAPTER *ioc; + void *request_data; + int rc; + Mpi2DiagReleaseRequest_t *mpi_request; + Mpi2DiagReleaseReply_t *mpi_reply; + u8 buffer_type; + unsigned long timeleft; + u16 smid; + u16 ioc_status; + u8 issue_reset = 0; + + if (copy_from_user(&karg, arg, sizeof(karg))) { + printk(KERN_ERR "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); + return -EFAULT; + } + if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) + return -ENODEV; + + dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + __func__)); + + buffer_type = karg.unique_id & 0x000000ff; + if (!_ctl_diag_capability(ioc, buffer_type)) { + printk(MPT2SAS_ERR_FMT "%s: doesn't have capability for " + "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type); + return -EPERM; + } + + if ((ioc->diag_buffer_status[buffer_type] & + MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) { + printk(MPT2SAS_ERR_FMT "%s: buffer_type(0x%02x) is not " + "registered\n", ioc->name, __func__, buffer_type); + return -EINVAL; + } + + if (karg.unique_id != ioc->unique_id[buffer_type]) { + printk(MPT2SAS_ERR_FMT "%s: unique_id(0x%08x) is not " + "registered\n", ioc->name, __func__, karg.unique_id); + return -EINVAL; + } + + if (ioc->diag_buffer_status[buffer_type] & + MPT2_DIAG_BUFFER_IS_RELEASED) { + printk(MPT2SAS_ERR_FMT "%s: buffer_type(0x%02x) " + "is already released\n", ioc->name, __func__, + buffer_type); + return 0; + } + + request_data = ioc->diag_buffer[buffer_type]; + + if (!request_data) { + printk(MPT2SAS_ERR_FMT "%s: doesn't have memory allocated for " + "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type); + return -ENOMEM; + } + + if (state == NON_BLOCKING && !mutex_trylock(&ioc->ctl_cmds.mutex)) + return -EAGAIN; + else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex)) + return -ERESTARTSYS; + + if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) { + printk(MPT2SAS_ERR_FMT "%s: ctl_cmd in use\n", + ioc->name, __func__); + rc = -EAGAIN; + goto out; + } + + smid = mpt2sas_base_get_smid(ioc, ioc->ctl_cb_idx); + if (!smid) { + printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", + ioc->name, __func__); + rc = -EAGAIN; + goto out; + } + + rc = 0; + ioc->ctl_cmds.status = MPT2_CMD_PENDING; + memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz); + mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); + ioc->ctl_cmds.smid = smid; + + mpi_request->Function = MPI2_FUNCTION_DIAG_RELEASE; + mpi_request->BufferType = buffer_type; + + mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID); + timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done, + MPT2_IOCTL_DEFAULT_TIMEOUT*HZ); + + if (!(ioc->ctl_cmds.status & MPT2_CMD_COMPLETE)) { + printk(MPT2SAS_ERR_FMT "%s: timeout\n", ioc->name, + __func__); + _debug_dump_mf(mpi_request, + sizeof(Mpi2DiagReleaseRequest_t)/4); + if (!(ioc->ctl_cmds.status & MPT2_CMD_RESET)) + issue_reset = 1; + goto issue_host_reset; + } + + /* process the completed Reply Message Frame */ + if ((ioc->ctl_cmds.status & MPT2_CMD_REPLY_VALID) == 0) { + printk(MPT2SAS_ERR_FMT "%s: no reply message\n", + ioc->name, __func__); + rc = -EFAULT; + goto out; + } + + mpi_reply = ioc->ctl_cmds.reply; + ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK; + + if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { + ioc->diag_buffer_status[buffer_type] |= + MPT2_DIAG_BUFFER_IS_RELEASED; + dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: success\n", + ioc->name, __func__)); + } else { + printk(MPT2SAS_DEBUG_FMT "%s: ioc_status(0x%04x) " + "log_info(0x%08x)\n", ioc->name, __func__, + ioc_status, mpi_reply->IOCLogInfo); + rc = -EFAULT; + } + + issue_host_reset: + if (issue_reset) + mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, + FORCE_BIG_HAMMER); + + out: + + ioc->ctl_cmds.status = MPT2_CMD_NOT_USED; + mutex_unlock(&ioc->ctl_cmds.mutex); + return rc; +} + +/** + * _ctl_diag_read_buffer - request for copy of the diag buffer + * @arg - user space buffer containing ioctl content + * @state - NON_BLOCKING or BLOCKING + */ +static long +_ctl_diag_read_buffer(void __user *arg, enum block_state state) +{ + struct mpt2_diag_read_buffer karg; + struct mpt2_diag_read_buffer __user *uarg = arg; + struct MPT2SAS_ADAPTER *ioc; + void *request_data, *diag_data; + Mpi2DiagBufferPostRequest_t *mpi_request; + Mpi2DiagBufferPostReply_t *mpi_reply; + int rc, i; + u8 buffer_type; + unsigned long timeleft; + u16 smid; + u16 ioc_status; + u8 issue_reset = 0; + + if (copy_from_user(&karg, arg, sizeof(karg))) { + printk(KERN_ERR "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); + return -EFAULT; + } + if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) + return -ENODEV; + + dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + __func__)); + + buffer_type = karg.unique_id & 0x000000ff; + if (!_ctl_diag_capability(ioc, buffer_type)) { + printk(MPT2SAS_ERR_FMT "%s: doesn't have capability for " + "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type); + return -EPERM; + } + + if (karg.unique_id != ioc->unique_id[buffer_type]) { + printk(MPT2SAS_ERR_FMT "%s: unique_id(0x%08x) is not " + "registered\n", ioc->name, __func__, karg.unique_id); + return -EINVAL; + } + + request_data = ioc->diag_buffer[buffer_type]; + if (!request_data) { + printk(MPT2SAS_ERR_FMT "%s: doesn't have buffer for " + "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type); + return -ENOMEM; + } + + if ((karg.starting_offset % 4) || (karg.bytes_to_read % 4)) { + printk(MPT2SAS_ERR_FMT "%s: either the starting_offset " + "or bytes_to_read are not 4 byte aligned\n", ioc->name, + __func__); + return -EINVAL; + } + + diag_data = (void *)(request_data + karg.starting_offset); + dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: diag_buffer(%p), " + "offset(%d), sz(%d)\n", ioc->name, __func__, + diag_data, karg.starting_offset, karg.bytes_to_read)); + + if (copy_to_user((void __user *)uarg->diagnostic_data, + diag_data, karg.bytes_to_read)) { + printk(MPT2SAS_ERR_FMT "%s: Unable to write " + "mpt_diag_read_buffer_t data @ %p\n", ioc->name, + __func__, diag_data); + return -EFAULT; + } + + if ((karg.flags & MPT2_FLAGS_REREGISTER) == 0) + return 0; + + dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: Reregister " + "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type)); + if ((ioc->diag_buffer_status[buffer_type] & + MPT2_DIAG_BUFFER_IS_RELEASED) == 0) { + dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " + "buffer_type(0x%02x) is still registered\n", ioc->name, + __func__, buffer_type)); + return 0; + } + /* Get a free request frame and save the message context. + */ + if (state == NON_BLOCKING && !mutex_trylock(&ioc->ctl_cmds.mutex)) + return -EAGAIN; + else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex)) + return -ERESTARTSYS; + + if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) { + printk(MPT2SAS_ERR_FMT "%s: ctl_cmd in use\n", + ioc->name, __func__); + rc = -EAGAIN; + goto out; + } + + smid = mpt2sas_base_get_smid(ioc, ioc->ctl_cb_idx); + if (!smid) { + printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", + ioc->name, __func__); + rc = -EAGAIN; + goto out; + } + + rc = 0; + ioc->ctl_cmds.status = MPT2_CMD_PENDING; + memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz); + mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); + ioc->ctl_cmds.smid = smid; + + mpi_request->Function = MPI2_FUNCTION_DIAG_BUFFER_POST; + mpi_request->BufferType = buffer_type; + mpi_request->BufferLength = + cpu_to_le32(ioc->diag_buffer_sz[buffer_type]); + mpi_request->BufferAddress = + cpu_to_le64(ioc->diag_buffer_dma[buffer_type]); + for (i = 0; i < MPT2_PRODUCT_SPECIFIC_DWORDS; i++) + mpi_request->ProductSpecific[i] = + cpu_to_le32(ioc->product_specific[buffer_type][i]); + + mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID); + timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done, + MPT2_IOCTL_DEFAULT_TIMEOUT*HZ); + + if (!(ioc->ctl_cmds.status & MPT2_CMD_COMPLETE)) { + printk(MPT2SAS_ERR_FMT "%s: timeout\n", ioc->name, + __func__); + _debug_dump_mf(mpi_request, + sizeof(Mpi2DiagBufferPostRequest_t)/4); + if (!(ioc->ctl_cmds.status & MPT2_CMD_RESET)) + issue_reset = 1; + goto issue_host_reset; + } + + /* process the completed Reply Message Frame */ + if ((ioc->ctl_cmds.status & MPT2_CMD_REPLY_VALID) == 0) { + printk(MPT2SAS_ERR_FMT "%s: no reply message\n", + ioc->name, __func__); + rc = -EFAULT; + goto out; + } + + mpi_reply = ioc->ctl_cmds.reply; + ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK; + + if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { + ioc->diag_buffer_status[buffer_type] |= + MPT2_DIAG_BUFFER_IS_REGISTERED; + dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: success\n", + ioc->name, __func__)); + } else { + printk(MPT2SAS_DEBUG_FMT "%s: ioc_status(0x%04x) " + "log_info(0x%08x)\n", ioc->name, __func__, + ioc_status, mpi_reply->IOCLogInfo); + rc = -EFAULT; + } + + issue_host_reset: + if (issue_reset) + mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, + FORCE_BIG_HAMMER); + + out: + + ioc->ctl_cmds.status = MPT2_CMD_NOT_USED; + mutex_unlock(&ioc->ctl_cmds.mutex); + return rc; +} + +/** + * _ctl_ioctl_main - main ioctl entry point + * @file - (struct file) + * @cmd - ioctl opcode + * @arg - + */ +static long +_ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg) +{ + enum block_state state; + long ret = -EINVAL; + unsigned long flags; + + state = (file->f_flags & O_NONBLOCK) ? NON_BLOCKING : + BLOCKING; + + switch (cmd) { + case MPT2IOCINFO: + if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_iocinfo)) + ret = _ctl_getiocinfo(arg); + break; + case MPT2COMMAND: + { + struct mpt2_ioctl_command karg; + struct mpt2_ioctl_command __user *uarg; + struct MPT2SAS_ADAPTER *ioc; + + if (copy_from_user(&karg, arg, sizeof(karg))) { + printk(KERN_ERR "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); + return -EFAULT; + } + + if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || + !ioc) + return -ENODEV; + + spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); + if (ioc->shost_recovery) { + spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, + flags); + return -EAGAIN; + } + spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); + + if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_command)) { + uarg = arg; + ret = _ctl_do_mpt_command(ioc, karg, &uarg->mf, state); + } + break; + } + case MPT2EVENTQUERY: + if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_eventquery)) + ret = _ctl_eventquery(arg); + break; + case MPT2EVENTENABLE: + if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_eventenable)) + ret = _ctl_eventenable(arg); + break; + case MPT2EVENTREPORT: + ret = _ctl_eventreport(arg); + break; + case MPT2HARDRESET: + if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_diag_reset)) + ret = _ctl_do_reset(arg); + break; + case MPT2BTDHMAPPING: + if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_btdh_mapping)) + ret = _ctl_btdh_mapping(arg); + break; + case MPT2DIAGREGISTER: + if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_register)) + ret = _ctl_diag_register(arg, state); + break; + case MPT2DIAGUNREGISTER: + if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_unregister)) + ret = _ctl_diag_unregister(arg); + break; + case MPT2DIAGQUERY: + if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_query)) + ret = _ctl_diag_query(arg); + break; + case MPT2DIAGRELEASE: + if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_release)) + ret = _ctl_diag_release(arg, state); + break; + case MPT2DIAGREADBUFFER: + if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_read_buffer)) + ret = _ctl_diag_read_buffer(arg, state); + break; + default: + { + struct mpt2_ioctl_command karg; + struct MPT2SAS_ADAPTER *ioc; + + if (copy_from_user(&karg, arg, sizeof(karg))) { + printk(KERN_ERR "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); + return -EFAULT; + } + + if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || + !ioc) + return -ENODEV; + + dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT + "unsupported ioctl opcode(0x%08x)\n", ioc->name, cmd)); + break; + } + } + return ret; +} + +/** + * _ctl_ioctl - main ioctl entry point (unlocked) + * @file - (struct file) + * @cmd - ioctl opcode + * @arg - + */ +static long +_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + long ret; + lock_kernel(); + ret = _ctl_ioctl_main(file, cmd, (void __user *)arg); + unlock_kernel(); + return ret; +} + +#ifdef CONFIG_COMPAT +/** + * _ctl_compat_mpt_command - convert 32bit pointers to 64bit. + * @file - (struct file) + * @cmd - ioctl opcode + * @arg - (struct mpt2_ioctl_command32) + * + * MPT2COMMAND32 - Handle 32bit applications running on 64bit os. + */ +static long +_ctl_compat_mpt_command(struct file *file, unsigned cmd, unsigned long arg) +{ + struct mpt2_ioctl_command32 karg32; + struct mpt2_ioctl_command32 __user *uarg; + struct mpt2_ioctl_command karg; + struct MPT2SAS_ADAPTER *ioc; + enum block_state state; + unsigned long flags; + + if (_IOC_SIZE(cmd) != sizeof(struct mpt2_ioctl_command32)) + return -EINVAL; + + uarg = (struct mpt2_ioctl_command32 __user *) arg; + + if (copy_from_user(&karg32, (char __user *)arg, sizeof(karg32))) { + printk(KERN_ERR "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); + return -EFAULT; + } + if (_ctl_verify_adapter(karg32.hdr.ioc_number, &ioc) == -1 || !ioc) + return -ENODEV; + + spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); + if (ioc->shost_recovery) { + spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, + flags); + return -EAGAIN; + } + spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); + + memset(&karg, 0, sizeof(struct mpt2_ioctl_command)); + karg.hdr.ioc_number = karg32.hdr.ioc_number; + karg.hdr.port_number = karg32.hdr.port_number; + karg.hdr.max_data_size = karg32.hdr.max_data_size; + karg.timeout = karg32.timeout; + karg.max_reply_bytes = karg32.max_reply_bytes; + karg.data_in_size = karg32.data_in_size; + karg.data_out_size = karg32.data_out_size; + karg.max_sense_bytes = karg32.max_sense_bytes; + karg.data_sge_offset = karg32.data_sge_offset; + memcpy(&karg.reply_frame_buf_ptr, &karg32.reply_frame_buf_ptr, + sizeof(uint32_t)); + memcpy(&karg.data_in_buf_ptr, &karg32.data_in_buf_ptr, + sizeof(uint32_t)); + memcpy(&karg.data_out_buf_ptr, &karg32.data_out_buf_ptr, + sizeof(uint32_t)); + memcpy(&karg.sense_data_ptr, &karg32.sense_data_ptr, + sizeof(uint32_t)); + state = (file->f_flags & O_NONBLOCK) ? NON_BLOCKING : BLOCKING; + return _ctl_do_mpt_command(ioc, karg, &uarg->mf, state); +} + +/** + * _ctl_ioctl_compat - main ioctl entry point (compat) + * @file - + * @cmd - + * @arg - + * + * This routine handles 32 bit applications in 64bit os. + */ +static long +_ctl_ioctl_compat(struct file *file, unsigned cmd, unsigned long arg) +{ + long ret; + lock_kernel(); + if (cmd == MPT2COMMAND32) + ret = _ctl_compat_mpt_command(file, cmd, arg); + else + ret = _ctl_ioctl_main(file, cmd, (void __user *)arg); + unlock_kernel(); + return ret; +} +#endif + +/* scsi host attributes */ + +/** + * _ctl_version_fw_show - firmware version + * @cdev - pointer to embedded class device + * @buf - the buffer returned + * + * A sysfs 'read-only' shost attribute. + */ +static ssize_t +_ctl_version_fw_show(struct device *cdev, struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + + return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n", + (ioc->facts.FWVersion.Word & 0xFF000000) >> 24, + (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16, + (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8, + ioc->facts.FWVersion.Word & 0x000000FF); +} +static DEVICE_ATTR(version_fw, S_IRUGO, _ctl_version_fw_show, NULL); + +/** + * _ctl_version_bios_show - bios version + * @cdev - pointer to embedded class device + * @buf - the buffer returned + * + * A sysfs 'read-only' shost attribute. + */ +static ssize_t +_ctl_version_bios_show(struct device *cdev, struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + + u32 version = le32_to_cpu(ioc->bios_pg3.BiosVersion); + + return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n", + (version & 0xFF000000) >> 24, + (version & 0x00FF0000) >> 16, + (version & 0x0000FF00) >> 8, + version & 0x000000FF); +} +static DEVICE_ATTR(version_bios, S_IRUGO, _ctl_version_bios_show, NULL); + +/** + * _ctl_version_mpi_show - MPI (message passing interface) version + * @cdev - pointer to embedded class device + * @buf - the buffer returned + * + * A sysfs 'read-only' shost attribute. + */ +static ssize_t +_ctl_version_mpi_show(struct device *cdev, struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + + return snprintf(buf, PAGE_SIZE, "%03x.%02x\n", + ioc->facts.MsgVersion, ioc->facts.HeaderVersion >> 8); +} +static DEVICE_ATTR(version_mpi, S_IRUGO, _ctl_version_mpi_show, NULL); + +/** + * _ctl_version_product_show - product name + * @cdev - pointer to embedded class device + * @buf - the buffer returned + * + * A sysfs 'read-only' shost attribute. + */ +static ssize_t +_ctl_version_product_show(struct device *cdev, struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + + return snprintf(buf, 16, "%s\n", ioc->manu_pg0.ChipName); +} +static DEVICE_ATTR(version_product, S_IRUGO, + _ctl_version_product_show, NULL); + +/** + * _ctl_version_nvdata_persistent_show - ndvata persistent version + * @cdev - pointer to embedded class device + * @buf - the buffer returned + * + * A sysfs 'read-only' shost attribute. + */ +static ssize_t +_ctl_version_nvdata_persistent_show(struct device *cdev, + struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + + return snprintf(buf, PAGE_SIZE, "%02xh\n", + le16_to_cpu(ioc->iounit_pg0.NvdataVersionPersistent.Word)); +} +static DEVICE_ATTR(version_nvdata_persistent, S_IRUGO, + _ctl_version_nvdata_persistent_show, NULL); + +/** + * _ctl_version_nvdata_default_show - nvdata default version + * @cdev - pointer to embedded class device + * @buf - the buffer returned + * + * A sysfs 'read-only' shost attribute. + */ +static ssize_t +_ctl_version_nvdata_default_show(struct device *cdev, + struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + + return snprintf(buf, PAGE_SIZE, "%02xh\n", + le16_to_cpu(ioc->iounit_pg0.NvdataVersionDefault.Word)); +} +static DEVICE_ATTR(version_nvdata_default, S_IRUGO, + _ctl_version_nvdata_default_show, NULL); + +/** + * _ctl_board_name_show - board name + * @cdev - pointer to embedded class device + * @buf - the buffer returned + * + * A sysfs 'read-only' shost attribute. + */ +static ssize_t +_ctl_board_name_show(struct device *cdev, struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + + return snprintf(buf, 16, "%s\n", ioc->manu_pg0.BoardName); +} +static DEVICE_ATTR(board_name, S_IRUGO, _ctl_board_name_show, NULL); + +/** + * _ctl_board_assembly_show - board assembly name + * @cdev - pointer to embedded class device + * @buf - the buffer returned + * + * A sysfs 'read-only' shost attribute. + */ +static ssize_t +_ctl_board_assembly_show(struct device *cdev, struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + + return snprintf(buf, 16, "%s\n", ioc->manu_pg0.BoardAssembly); +} +static DEVICE_ATTR(board_assembly, S_IRUGO, + _ctl_board_assembly_show, NULL); + +/** + * _ctl_board_tracer_show - board tracer number + * @cdev - pointer to embedded class device + * @buf - the buffer returned + * + * A sysfs 'read-only' shost attribute. + */ +static ssize_t +_ctl_board_tracer_show(struct device *cdev, struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + + return snprintf(buf, 16, "%s\n", ioc->manu_pg0.BoardTracerNumber); +} +static DEVICE_ATTR(board_tracer, S_IRUGO, + _ctl_board_tracer_show, NULL); + +/** + * _ctl_io_delay_show - io missing delay + * @cdev - pointer to embedded class device + * @buf - the buffer returned + * + * This is for firmware implemention for deboucing device + * removal events. + * + * A sysfs 'read-only' shost attribute. + */ +static ssize_t +_ctl_io_delay_show(struct device *cdev, struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + + return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->io_missing_delay); +} +static DEVICE_ATTR(io_delay, S_IRUGO, + _ctl_io_delay_show, NULL); + +/** + * _ctl_device_delay_show - device missing delay + * @cdev - pointer to embedded class device + * @buf - the buffer returned + * + * This is for firmware implemention for deboucing device + * removal events. + * + * A sysfs 'read-only' shost attribute. + */ +static ssize_t +_ctl_device_delay_show(struct device *cdev, struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + + return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->device_missing_delay); +} +static DEVICE_ATTR(device_delay, S_IRUGO, + _ctl_device_delay_show, NULL); + +/** + * _ctl_fw_queue_depth_show - global credits + * @cdev - pointer to embedded class device + * @buf - the buffer returned + * + * This is firmware queue depth limit + * + * A sysfs 'read-only' shost attribute. + */ +static ssize_t +_ctl_fw_queue_depth_show(struct device *cdev, struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + + return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->facts.RequestCredit); +} +static DEVICE_ATTR(fw_queue_depth, S_IRUGO, + _ctl_fw_queue_depth_show, NULL); + +/** + * _ctl_sas_address_show - sas address + * @cdev - pointer to embedded class device + * @buf - the buffer returned + * + * This is the controller sas address + * + * A sysfs 'read-only' shost attribute. + */ +static ssize_t +_ctl_host_sas_address_show(struct device *cdev, struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + + return snprintf(buf, PAGE_SIZE, "0x%016llx\n", + (unsigned long long)ioc->sas_hba.sas_address); +} +static DEVICE_ATTR(host_sas_address, S_IRUGO, + _ctl_host_sas_address_show, NULL); + +/** + * _ctl_logging_level_show - logging level + * @cdev - pointer to embedded class device + * @buf - the buffer returned + * + * A sysfs 'read/write' shost attribute. + */ +static ssize_t +_ctl_logging_level_show(struct device *cdev, struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + + return snprintf(buf, PAGE_SIZE, "%08xh\n", ioc->logging_level); +} +static ssize_t +_ctl_logging_level_store(struct device *cdev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + int val = 0; + + if (sscanf(buf, "%x", &val) != 1) + return -EINVAL; + + ioc->logging_level = val; + printk(MPT2SAS_INFO_FMT "logging_level=%08xh\n", ioc->name, + ioc->logging_level); + return strlen(buf); +} +static DEVICE_ATTR(logging_level, S_IRUGO | S_IWUSR, + _ctl_logging_level_show, _ctl_logging_level_store); + +struct device_attribute *mpt2sas_host_attrs[] = { + &dev_attr_version_fw, + &dev_attr_version_bios, + &dev_attr_version_mpi, + &dev_attr_version_product, + &dev_attr_version_nvdata_persistent, + &dev_attr_version_nvdata_default, + &dev_attr_board_name, + &dev_attr_board_assembly, + &dev_attr_board_tracer, + &dev_attr_io_delay, + &dev_attr_device_delay, + &dev_attr_logging_level, + &dev_attr_fw_queue_depth, + &dev_attr_host_sas_address, + NULL, +}; + +/* device attributes */ + +/** + * _ctl_device_sas_address_show - sas address + * @cdev - pointer to embedded class device + * @buf - the buffer returned + * + * This is the sas address for the target + * + * A sysfs 'read-only' shost attribute. + */ +static ssize_t +_ctl_device_sas_address_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct scsi_device *sdev = to_scsi_device(dev); + struct MPT2SAS_DEVICE *sas_device_priv_data = sdev->hostdata; + + return snprintf(buf, PAGE_SIZE, "0x%016llx\n", + (unsigned long long)sas_device_priv_data->sas_target->sas_address); +} +static DEVICE_ATTR(sas_address, S_IRUGO, _ctl_device_sas_address_show, NULL); + +/** + * _ctl_device_handle_show - device handle + * @cdev - pointer to embedded class device + * @buf - the buffer returned + * + * This is the firmware assigned device handle + * + * A sysfs 'read-only' shost attribute. + */ +static ssize_t +_ctl_device_handle_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct scsi_device *sdev = to_scsi_device(dev); + struct MPT2SAS_DEVICE *sas_device_priv_data = sdev->hostdata; + + return snprintf(buf, PAGE_SIZE, "0x%04x\n", + sas_device_priv_data->sas_target->handle); +} +static DEVICE_ATTR(sas_device_handle, S_IRUGO, _ctl_device_handle_show, NULL); + +struct device_attribute *mpt2sas_dev_attrs[] = { + &dev_attr_sas_address, + &dev_attr_sas_device_handle, + NULL, +}; + +static const struct file_operations ctl_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = _ctl_ioctl, + .release = _ctl_release, + .poll = _ctl_poll, + .fasync = _ctl_fasync, +#ifdef CONFIG_COMPAT + .compat_ioctl = _ctl_ioctl_compat, +#endif +}; + +static struct miscdevice ctl_dev = { + .minor = MPT2SAS_MINOR, + .name = MPT2SAS_DEV_NAME, + .fops = &ctl_fops, +}; + +/** + * mpt2sas_ctl_init - main entry point for ctl. + * + */ +void +mpt2sas_ctl_init(void) +{ + async_queue = NULL; + if (misc_register(&ctl_dev) < 0) + printk(KERN_ERR "%s can't register misc device [minor=%d]\n", + MPT2SAS_DRIVER_NAME, MPT2SAS_MINOR); + + init_waitqueue_head(&ctl_poll_wait); +} + +/** + * mpt2sas_ctl_exit - exit point for ctl + * + */ +void +mpt2sas_ctl_exit(void) +{ + struct MPT2SAS_ADAPTER *ioc; + int i; + + list_for_each_entry(ioc, &mpt2sas_ioc_list, list) { + + /* free memory associated to diag buffers */ + for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) { + if (!ioc->diag_buffer[i]) + continue; + pci_free_consistent(ioc->pdev, ioc->diag_buffer_sz[i], + ioc->diag_buffer[i], ioc->diag_buffer_dma[i]); + ioc->diag_buffer[i] = NULL; + ioc->diag_buffer_status[i] = 0; + } + + kfree(ioc->event_log); + } + misc_deregister(&ctl_dev); +} + diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.h b/drivers/scsi/mpt2sas/mpt2sas_ctl.h new file mode 100644 index 00000000000..dbb6c0cf888 --- /dev/null +++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.h @@ -0,0 +1,416 @@ +/* + * Management Module Support for MPT (Message Passing Technology) based + * controllers + * + * This code is based on drivers/scsi/mpt2sas/mpt2_ctl.h + * Copyright (C) 2007-2008 LSI Corporation + * (mailto:DL-MPTFusionLinux@lsi.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. + * + * NO WARRANTY + * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT + * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is + * solely responsible for determining the appropriateness of using and + * distributing the Program and assumes all risks associated with its + * exercise of rights under this Agreement, including but not limited to + * the risks and costs of program errors, damage to or loss of data, + * programs or equipment, and unavailability or interruption of operations. + + * DISCLAIMER OF LIABILITY + * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED + * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES + + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ + +#ifndef MPT2SAS_CTL_H_INCLUDED +#define MPT2SAS_CTL_H_INCLUDED + +#ifdef __KERNEL__ +#include <linux/miscdevice.h> +#endif + +#define MPT2SAS_DEV_NAME "mpt2ctl" +#define MPT2_MAGIC_NUMBER 'm' +#define MPT2_IOCTL_DEFAULT_TIMEOUT (10) /* in seconds */ + +/** + * IOCTL opcodes + */ +#define MPT2IOCINFO _IOWR(MPT2_MAGIC_NUMBER, 17, \ + struct mpt2_ioctl_iocinfo) +#define MPT2COMMAND _IOWR(MPT2_MAGIC_NUMBER, 20, \ + struct mpt2_ioctl_command) +#ifdef CONFIG_COMPAT +#define MPT2COMMAND32 _IOWR(MPT2_MAGIC_NUMBER, 20, \ + struct mpt2_ioctl_command32) +#endif +#define MPT2EVENTQUERY _IOWR(MPT2_MAGIC_NUMBER, 21, \ + struct mpt2_ioctl_eventquery) +#define MPT2EVENTENABLE _IOWR(MPT2_MAGIC_NUMBER, 22, \ + struct mpt2_ioctl_eventenable) +#define MPT2EVENTREPORT _IOWR(MPT2_MAGIC_NUMBER, 23, \ + struct mpt2_ioctl_eventreport) +#define MPT2HARDRESET _IOWR(MPT2_MAGIC_NUMBER, 24, \ + struct mpt2_ioctl_diag_reset) +#define MPT2BTDHMAPPING _IOWR(MPT2_MAGIC_NUMBER, 31, \ + struct mpt2_ioctl_btdh_mapping) + +/* diag buffer support */ +#define MPT2DIAGREGISTER _IOWR(MPT2_MAGIC_NUMBER, 26, \ + struct mpt2_diag_register) +#define MPT2DIAGRELEASE _IOWR(MPT2_MAGIC_NUMBER, 27, \ + struct mpt2_diag_release) +#define MPT2DIAGUNREGISTER _IOWR(MPT2_MAGIC_NUMBER, 28, \ + struct mpt2_diag_unregister) +#define MPT2DIAGQUERY _IOWR(MPT2_MAGIC_NUMBER, 29, \ + struct mpt2_diag_query) +#define MPT2DIAGREADBUFFER _IOWR(MPT2_MAGIC_NUMBER, 30, \ + struct mpt2_diag_read_buffer) + +/** + * struct mpt2_ioctl_header - main header structure + * @ioc_number - IOC unit number + * @port_number - IOC port number + * @max_data_size - maximum number bytes to transfer on read + */ +struct mpt2_ioctl_header { + uint32_t ioc_number; + uint32_t port_number; + uint32_t max_data_size; +}; + +/** + * struct mpt2_ioctl_diag_reset - diagnostic reset + * @hdr - generic header + */ +struct mpt2_ioctl_diag_reset { + struct mpt2_ioctl_header hdr; +}; + + +/** + * struct mpt2_ioctl_pci_info - pci device info + * @device - pci device id + * @function - pci function id + * @bus - pci bus id + * @segment_id - pci segment id + */ +struct mpt2_ioctl_pci_info { + union { + struct { + uint32_t device:5; + uint32_t function:3; + uint32_t bus:24; + } bits; + uint32_t word; + } u; + uint32_t segment_id; +}; + + +#define MPT2_IOCTL_INTERFACE_SCSI (0x00) +#define MPT2_IOCTL_INTERFACE_FC (0x01) +#define MPT2_IOCTL_INTERFACE_FC_IP (0x02) +#define MPT2_IOCTL_INTERFACE_SAS (0x03) +#define MPT2_IOCTL_INTERFACE_SAS2 (0x04) +#define MPT2_IOCTL_VERSION_LENGTH (32) + +/** + * struct mpt2_ioctl_iocinfo - generic controller info + * @hdr - generic header + * @adapter_type - type of adapter (spi, fc, sas) + * @port_number - port number + * @pci_id - PCI Id + * @hw_rev - hardware revision + * @sub_system_device - PCI subsystem Device ID + * @sub_system_vendor - PCI subsystem Vendor ID + * @rsvd0 - reserved + * @firmware_version - firmware version + * @bios_version - BIOS version + * @driver_version - driver version - 32 ASCII characters + * @rsvd1 - reserved + * @scsi_id - scsi id of adapter 0 + * @rsvd2 - reserved + * @pci_information - pci info (2nd revision) + */ +struct mpt2_ioctl_iocinfo { + struct mpt2_ioctl_header hdr; + uint32_t adapter_type; + uint32_t port_number; + uint32_t pci_id; + uint32_t hw_rev; + uint32_t subsystem_device; + uint32_t subsystem_vendor; + uint32_t rsvd0; + uint32_t firmware_version; + uint32_t bios_version; + uint8_t driver_version[MPT2_IOCTL_VERSION_LENGTH]; + uint8_t rsvd1; + uint8_t scsi_id; + uint16_t rsvd2; + struct mpt2_ioctl_pci_info pci_information; +}; + + +/* number of event log entries */ +#define MPT2SAS_CTL_EVENT_LOG_SIZE (50) + +/** + * struct mpt2_ioctl_eventquery - query event count and type + * @hdr - generic header + * @event_entries - number of events returned by get_event_report + * @rsvd - reserved + * @event_types - type of events currently being captured + */ +struct mpt2_ioctl_eventquery { + struct mpt2_ioctl_header hdr; + uint16_t event_entries; + uint16_t rsvd; + uint32_t event_types[MPI2_EVENT_NOTIFY_EVENTMASK_WORDS]; +}; + +/** + * struct mpt2_ioctl_eventenable - enable/disable event capturing + * @hdr - generic header + * @event_types - toggle off/on type of events to be captured + */ +struct mpt2_ioctl_eventenable { + struct mpt2_ioctl_header hdr; + uint32_t event_types[4]; +}; + +#define MPT2_EVENT_DATA_SIZE (192) +/** + * struct MPT2_IOCTL_EVENTS - + * @event - the event that was reported + * @context - unique value for each event assigned by driver + * @data - event data returned in fw reply message + */ +struct MPT2_IOCTL_EVENTS { + uint32_t event; + uint32_t context; + uint8_t data[MPT2_EVENT_DATA_SIZE]; +}; + +/** + * struct mpt2_ioctl_eventreport - returing event log + * @hdr - generic header + * @event_data - (see struct MPT2_IOCTL_EVENTS) + */ +struct mpt2_ioctl_eventreport { + struct mpt2_ioctl_header hdr; + struct MPT2_IOCTL_EVENTS event_data[1]; +}; + +/** + * struct mpt2_ioctl_command - generic mpt firmware passthru ioclt + * @hdr - generic header + * @timeout - command timeout in seconds. (if zero then use driver default + * value). + * @reply_frame_buf_ptr - reply location + * @data_in_buf_ptr - destination for read + * @data_out_buf_ptr - data source for write + * @sense_data_ptr - sense data location + * @max_reply_bytes - maximum number of reply bytes to be sent to app. + * @data_in_size - number bytes for data transfer in (read) + * @data_out_size - number bytes for data transfer out (write) + * @max_sense_bytes - maximum number of bytes for auto sense buffers + * @data_sge_offset - offset in words from the start of the request message to + * the first SGL + * @mf[1]; + */ +struct mpt2_ioctl_command { + struct mpt2_ioctl_header hdr; + uint32_t timeout; + void __user *reply_frame_buf_ptr; + void __user *data_in_buf_ptr; + void __user *data_out_buf_ptr; + void __user *sense_data_ptr; + uint32_t max_reply_bytes; + uint32_t data_in_size; + uint32_t data_out_size; + uint32_t max_sense_bytes; + uint32_t data_sge_offset; + uint8_t mf[1]; +}; + +#ifdef CONFIG_COMPAT +struct mpt2_ioctl_command32 { + struct mpt2_ioctl_header hdr; + uint32_t timeout; + uint32_t reply_frame_buf_ptr; + uint32_t data_in_buf_ptr; + uint32_t data_out_buf_ptr; + uint32_t sense_data_ptr; + uint32_t max_reply_bytes; + uint32_t data_in_size; + uint32_t data_out_size; + uint32_t max_sense_bytes; + uint32_t data_sge_offset; + uint8_t mf[1]; +}; +#endif + +/** + * struct mpt2_ioctl_btdh_mapping - mapping info + * @hdr - generic header + * @id - target device identification number + * @bus - SCSI bus number that the target device exists on + * @handle - device handle for the target device + * @rsvd - reserved + * + * To obtain a bus/id the application sets + * handle to valid handle, and bus/id to 0xFFFF. + * + * To obtain the device handle the application sets + * bus/id valid value, and the handle to 0xFFFF. + */ +struct mpt2_ioctl_btdh_mapping { + struct mpt2_ioctl_header hdr; + uint32_t id; + uint32_t bus; + uint16_t handle; + uint16_t rsvd; +}; + + +/* status bits for ioc->diag_buffer_status */ +#define MPT2_DIAG_BUFFER_IS_REGISTERED (0x01) +#define MPT2_DIAG_BUFFER_IS_RELEASED (0x02) + +/* application flags for mpt2_diag_register, mpt2_diag_query */ +#define MPT2_APP_FLAGS_APP_OWNED (0x0001) +#define MPT2_APP_FLAGS_BUFFER_VALID (0x0002) +#define MPT2_APP_FLAGS_FW_BUFFER_ACCESS (0x0004) + +/* flags for mpt2_diag_read_buffer */ +#define MPT2_FLAGS_REREGISTER (0x0001) + +#define MPT2_PRODUCT_SPECIFIC_DWORDS 23 + +/** + * struct mpt2_diag_register - application register with driver + * @hdr - generic header + * @reserved - + * @buffer_type - specifies either TRACE or SNAPSHOT + * @application_flags - misc flags + * @diagnostic_flags - specifies flags affecting command processing + * @product_specific - product specific information + * @requested_buffer_size - buffers size in bytes + * @unique_id - tag specified by application that is used to signal ownership + * of the buffer. + * + * This will allow the driver to setup any required buffers that will be + * needed by firmware to communicate with the driver. + */ +struct mpt2_diag_register { + struct mpt2_ioctl_header hdr; + uint8_t reserved; + uint8_t buffer_type; + uint16_t application_flags; + uint32_t diagnostic_flags; + uint32_t product_specific[MPT2_PRODUCT_SPECIFIC_DWORDS]; + uint32_t requested_buffer_size; + uint32_t unique_id; +}; + +/** + * struct mpt2_diag_unregister - application unregister with driver + * @hdr - generic header + * @unique_id - tag uniquely identifies the buffer to be unregistered + * + * This will allow the driver to cleanup any memory allocated for diag + * messages and to free up any resources. + */ +struct mpt2_diag_unregister { + struct mpt2_ioctl_header hdr; + uint32_t unique_id; +}; + +/** + * struct mpt2_diag_query - query relevant info associated with diag buffers + * @hdr - generic header + * @reserved - + * @buffer_type - specifies either TRACE or SNAPSHOT + * @application_flags - misc flags + * @diagnostic_flags - specifies flags affecting command processing + * @product_specific - product specific information + * @total_buffer_size - diag buffer size in bytes + * @driver_added_buffer_size - size of extra space appended to end of buffer + * @unique_id - unique id associated with this buffer. + * + * The application will send only buffer_type and unique_id. Driver will + * inspect unique_id first, if valid, fill in all the info. If unique_id is + * 0x00, the driver will return info specified by Buffer Type. + */ +struct mpt2_diag_query { + struct mpt2_ioctl_header hdr; + uint8_t reserved; + uint8_t buffer_type; + uint16_t application_flags; + uint32_t diagnostic_flags; + uint32_t product_specific[MPT2_PRODUCT_SPECIFIC_DWORDS]; + uint32_t total_buffer_size; + uint32_t driver_added_buffer_size; + uint32_t unique_id; +}; + +/** + * struct mpt2_diag_release - request to send Diag Release Message to firmware + * @hdr - generic header + * @unique_id - tag uniquely identifies the buffer to be released + * + * This allows ownership of the specified buffer to returned to the driver, + * allowing an application to read the buffer without fear that firmware is + * overwritting information in the buffer. + */ +struct mpt2_diag_release { + struct mpt2_ioctl_header hdr; + uint32_t unique_id; +}; + +/** + * struct mpt2_diag_read_buffer - request for copy of the diag buffer + * @hdr - generic header + * @status - + * @reserved - + * @flags - misc flags + * @starting_offset - starting offset within drivers buffer where to start + * reading data at into the specified application buffer + * @bytes_to_read - number of bytes to copy from the drivers buffer into the + * application buffer starting at starting_offset. + * @unique_id - unique id associated with this buffer. + * @diagnostic_data - data payload + */ +struct mpt2_diag_read_buffer { + struct mpt2_ioctl_header hdr; + uint8_t status; + uint8_t reserved; + uint16_t flags; + uint32_t starting_offset; + uint32_t bytes_to_read; + uint32_t unique_id; + uint32_t diagnostic_data[1]; +}; + +#endif /* MPT2SAS_CTL_H_INCLUDED */ diff --git a/drivers/scsi/mpt2sas/mpt2sas_debug.h b/drivers/scsi/mpt2sas/mpt2sas_debug.h new file mode 100644 index 00000000000..ad325096e84 --- /dev/null +++ b/drivers/scsi/mpt2sas/mpt2sas_debug.h @@ -0,0 +1,181 @@ +/* + * Logging Support for MPT (Message Passing Technology) based controllers + * + * This code is based on drivers/scsi/mpt2sas/mpt2_debug.c + * Copyright (C) 2007-2008 LSI Corporation + * (mailto:DL-MPTFusionLinux@lsi.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. + * + * NO WARRANTY + * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT + * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is + * solely responsible for determining the appropriateness of using and + * distributing the Program and assumes all risks associated with its + * exercise of rights under this Agreement, including but not limited to + * the risks and costs of program errors, damage to or loss of data, + * programs or equipment, and unavailability or interruption of operations. + + * DISCLAIMER OF LIABILITY + * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED + * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES + + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ + +#ifndef MPT2SAS_DEBUG_H_INCLUDED +#define MPT2SAS_DEBUG_H_INCLUDED + +#define MPT_DEBUG 0x00000001 +#define MPT_DEBUG_MSG_FRAME 0x00000002 +#define MPT_DEBUG_SG 0x00000004 +#define MPT_DEBUG_EVENTS 0x00000008 +#define MPT_DEBUG_EVENT_WORK_TASK 0x00000010 +#define MPT_DEBUG_INIT 0x00000020 +#define MPT_DEBUG_EXIT 0x00000040 +#define MPT_DEBUG_FAIL 0x00000080 +#define MPT_DEBUG_TM 0x00000100 +#define MPT_DEBUG_REPLY 0x00000200 +#define MPT_DEBUG_HANDSHAKE 0x00000400 +#define MPT_DEBUG_CONFIG 0x00000800 +#define MPT_DEBUG_DL 0x00001000 +#define MPT_DEBUG_RESET 0x00002000 +#define MPT_DEBUG_SCSI 0x00004000 +#define MPT_DEBUG_IOCTL 0x00008000 +#define MPT_DEBUG_CSMISAS 0x00010000 +#define MPT_DEBUG_SAS 0x00020000 +#define MPT_DEBUG_TRANSPORT 0x00040000 +#define MPT_DEBUG_TASK_SET_FULL 0x00080000 + +#define MPT_DEBUG_TARGET_MODE 0x00100000 + + +/* + * CONFIG_SCSI_MPT2SAS_LOGGING - enabled in Kconfig + */ + +#ifdef CONFIG_SCSI_MPT2SAS_LOGGING +#define MPT_CHECK_LOGGING(IOC, CMD, BITS) \ +{ \ + if (IOC->logging_level & BITS) \ + CMD; \ +} +#else +#define MPT_CHECK_LOGGING(IOC, CMD, BITS) +#endif /* CONFIG_SCSI_MPT2SAS_LOGGING */ + + +/* + * debug macros + */ + +#define dprintk(IOC, CMD) \ + MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG) + +#define dsgprintk(IOC, CMD) \ + MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SG) + +#define devtprintk(IOC, CMD) \ + MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_EVENTS) + +#define dewtprintk(IOC, CMD) \ + MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_EVENT_WORK_TASK) + +#define dinitprintk(IOC, CMD) \ + MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_INIT) + +#define dexitprintk(IOC, CMD) \ + MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_EXIT) + +#define dfailprintk(IOC, CMD) \ + MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_FAIL) + +#define dtmprintk(IOC, CMD) \ + MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_TM) + +#define dreplyprintk(IOC, CMD) \ + MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_REPLY) + +#define dhsprintk(IOC, CMD) \ + MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_HANDSHAKE) + +#define dcprintk(IOC, CMD) \ + MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_CONFIG) + +#define ddlprintk(IOC, CMD) \ + MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_DL) + +#define drsprintk(IOC, CMD) \ + MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_RESET) + +#define dsprintk(IOC, CMD) \ + MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SCSI) + +#define dctlprintk(IOC, CMD) \ + MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_IOCTL) + +#define dcsmisasprintk(IOC, CMD) \ + MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_CSMISAS) + +#define dsasprintk(IOC, CMD) \ + MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SAS) + +#define dsastransport(IOC, CMD) \ + MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SAS_WIDE) + +#define dmfprintk(IOC, CMD) \ + MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_MSG_FRAME) + +#define dtsfprintk(IOC, CMD) \ + MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_TASK_SET_FULL) + +#define dtransportprintk(IOC, CMD) \ + MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_TRANSPORT) + +#define dTMprintk(IOC, CMD) \ + MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_TARGET_MODE) + +/* inline functions for dumping debug data*/ +#ifdef CONFIG_SCSI_MPT2SAS_LOGGING +/** + * _debug_dump_mf - print message frame contents + * @mpi_request: pointer to message frame + * @sz: number of dwords + */ +static inline void +_debug_dump_mf(void *mpi_request, int sz) +{ + int i; + u32 *mfp = (u32 *)mpi_request; + + printk(KERN_INFO "mf:\n\t"); + for (i = 0; i < sz; i++) { + if (i && ((i % 8) == 0)) + printk("\n\t"); + printk("%08x ", le32_to_cpu(mfp[i])); + } + printk("\n"); +} +#else +#define _debug_dump_mf(mpi_request, sz) +#endif /* CONFIG_SCSI_MPT2SAS_LOGGING */ + +#endif /* MPT2SAS_DEBUG_H_INCLUDED */ diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c new file mode 100644 index 00000000000..0c463c483c0 --- /dev/null +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -0,0 +1,5687 @@ +/* + * Scsi Host Layer for MPT (Message Passing Technology) based controllers + * + * This code is based on drivers/scsi/mpt2sas/mpt2_scsih.c + * Copyright (C) 2007-2008 LSI Corporation + * (mailto:DL-MPTFusionLinux@lsi.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. + * + * NO WARRANTY + * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT + * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is + * solely responsible for determining the appropriateness of using and + * distributing the Program and assumes all risks associated with its + * exercise of rights under this Agreement, including but not limited to + * the risks and costs of program errors, damage to or loss of data, + * programs or equipment, and unavailability or interruption of operations. + + * DISCLAIMER OF LIABILITY + * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED + * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES + + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ + +#include <linux/version.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/blkdev.h> +#include <linux/sched.h> +#include <linux/workqueue.h> +#include <linux/delay.h> +#include <linux/pci.h> +#include <linux/interrupt.h> + +#include "mpt2sas_base.h" + +MODULE_AUTHOR(MPT2SAS_AUTHOR); +MODULE_DESCRIPTION(MPT2SAS_DESCRIPTION); +MODULE_LICENSE("GPL"); +MODULE_VERSION(MPT2SAS_DRIVER_VERSION); + +#define RAID_CHANNEL 1 + +/* forward proto's */ +static void _scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc, + struct _sas_node *sas_expander); +static void _firmware_event_work(struct work_struct *work); + +/* global parameters */ +LIST_HEAD(mpt2sas_ioc_list); + +/* local parameters */ +static u8 scsi_io_cb_idx = -1; +static u8 tm_cb_idx = -1; +static u8 ctl_cb_idx = -1; +static u8 base_cb_idx = -1; +static u8 transport_cb_idx = -1; +static u8 config_cb_idx = -1; +static int mpt_ids; + +/* command line options */ +static u32 logging_level; +MODULE_PARM_DESC(logging_level, " bits for enabling additional logging info " + "(default=0)"); + +/* scsi-mid layer global parmeter is max_report_luns, which is 511 */ +#define MPT2SAS_MAX_LUN (16895) +static int max_lun = MPT2SAS_MAX_LUN; +module_param(max_lun, int, 0); +MODULE_PARM_DESC(max_lun, " max lun, default=16895 "); + +/** + * struct sense_info - common structure for obtaining sense keys + * @skey: sense key + * @asc: additional sense code + * @ascq: additional sense code qualifier + */ +struct sense_info { + u8 skey; + u8 asc; + u8 ascq; +}; + + +#define MPT2SAS_RESCAN_AFTER_HOST_RESET (0xFFFF) +/** + * struct fw_event_work - firmware event struct + * @list: link list framework + * @work: work object (ioc->fault_reset_work_q) + * @ioc: per adapter object + * @VF_ID: virtual function id + * @host_reset_handling: handling events during host reset + * @ignore: flag meaning this event has been marked to ignore + * @event: firmware event MPI2_EVENT_XXX defined in mpt2_ioc.h + * @event_data: reply event data payload follows + * + * This object stored on ioc->fw_event_list. + */ +struct fw_event_work { + struct list_head list; + struct delayed_work work; + struct MPT2SAS_ADAPTER *ioc; + u8 VF_ID; + u8 host_reset_handling; + u8 ignore; + u16 event; + void *event_data; +}; + +/** + * struct _scsi_io_transfer - scsi io transfer + * @handle: sas device handle (assigned by firmware) + * @is_raid: flag set for hidden raid components + * @dir: DMA_TO_DEVICE, DMA_FROM_DEVICE, + * @data_length: data transfer length + * @data_dma: dma pointer to data + * @sense: sense data + * @lun: lun number + * @cdb_length: cdb length + * @cdb: cdb contents + * @valid_reply: flag set for reply message + * @timeout: timeout for this command + * @sense_length: sense length + * @ioc_status: ioc status + * @scsi_state: scsi state + * @scsi_status: scsi staus + * @log_info: log information + * @transfer_length: data length transfer when there is a reply message + * + * Used for sending internal scsi commands to devices within this module. + * Refer to _scsi_send_scsi_io(). + */ +struct _scsi_io_transfer { + u16 handle; + u8 is_raid; + enum dma_data_direction dir; + u32 data_length; + dma_addr_t data_dma; + u8 sense[SCSI_SENSE_BUFFERSIZE]; + u32 lun; + u8 cdb_length; + u8 cdb[32]; + u8 timeout; + u8 valid_reply; + /* the following bits are only valid when 'valid_reply = 1' */ + u32 sense_length; + u16 ioc_status; + u8 scsi_state; + u8 scsi_status; + u32 log_info; + u32 transfer_length; +}; + +/* + * The pci device ids are defined in mpi/mpi2_cnfg.h. + */ +static struct pci_device_id scsih_pci_table[] = { + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2004, + PCI_ANY_ID, PCI_ANY_ID }, + /* Falcon ~ 2008*/ + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2008, + PCI_ANY_ID, PCI_ANY_ID }, + /* Liberator ~ 2108 */ + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_1, + PCI_ANY_ID, PCI_ANY_ID }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_2, + PCI_ANY_ID, PCI_ANY_ID }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_3, + PCI_ANY_ID, PCI_ANY_ID }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_1, + PCI_ANY_ID, PCI_ANY_ID }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_2, + PCI_ANY_ID, PCI_ANY_ID }, + {0} /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(pci, scsih_pci_table); + +/** + * scsih_set_debug_level - global setting of ioc->logging_level. + * + * Note: The logging levels are defined in mpt2sas_debug.h. + */ +static int +scsih_set_debug_level(const char *val, struct kernel_param *kp) +{ + int ret = param_set_int(val, kp); + struct MPT2SAS_ADAPTER *ioc; + + if (ret) + return ret; + + printk(KERN_INFO "setting logging_level(0x%08x)\n", logging_level); + list_for_each_entry(ioc, &mpt2sas_ioc_list, list) + ioc->logging_level = logging_level; + return 0; +} +module_param_call(logging_level, scsih_set_debug_level, param_get_int, + &logging_level, 0644); + +/** + * _scsih_srch_boot_sas_address - search based on sas_address + * @sas_address: sas address + * @boot_device: boot device object from bios page 2 + * + * Returns 1 when there's a match, 0 means no match. + */ +static inline int +_scsih_srch_boot_sas_address(u64 sas_address, + Mpi2BootDeviceSasWwid_t *boot_device) +{ + return (sas_address == le64_to_cpu(boot_device->SASAddress)) ? 1 : 0; +} + +/** + * _scsih_srch_boot_device_name - search based on device name + * @device_name: device name specified in INDENTIFY fram + * @boot_device: boot device object from bios page 2 + * + * Returns 1 when there's a match, 0 means no match. + */ +static inline int +_scsih_srch_boot_device_name(u64 device_name, + Mpi2BootDeviceDeviceName_t *boot_device) +{ + return (device_name == le64_to_cpu(boot_device->DeviceName)) ? 1 : 0; +} + +/** + * _scsih_srch_boot_encl_slot - search based on enclosure_logical_id/slot + * @enclosure_logical_id: enclosure logical id + * @slot_number: slot number + * @boot_device: boot device object from bios page 2 + * + * Returns 1 when there's a match, 0 means no match. + */ +static inline int +_scsih_srch_boot_encl_slot(u64 enclosure_logical_id, u16 slot_number, + Mpi2BootDeviceEnclosureSlot_t *boot_device) +{ + return (enclosure_logical_id == le64_to_cpu(boot_device-> + EnclosureLogicalID) && slot_number == le16_to_cpu(boot_device-> + SlotNumber)) ? 1 : 0; +} + +/** + * _scsih_is_boot_device - search for matching boot device. + * @sas_address: sas address + * @device_name: device name specified in INDENTIFY fram + * @enclosure_logical_id: enclosure logical id + * @slot_number: slot number + * @form: specifies boot device form + * @boot_device: boot device object from bios page 2 + * + * Returns 1 when there's a match, 0 means no match. + */ +static int +_scsih_is_boot_device(u64 sas_address, u64 device_name, + u64 enclosure_logical_id, u16 slot, u8 form, + Mpi2BiosPage2BootDevice_t *boot_device) +{ + int rc = 0; + + switch (form) { + case MPI2_BIOSPAGE2_FORM_SAS_WWID: + if (!sas_address) + break; + rc = _scsih_srch_boot_sas_address( + sas_address, &boot_device->SasWwid); + break; + case MPI2_BIOSPAGE2_FORM_ENCLOSURE_SLOT: + if (!enclosure_logical_id) + break; + rc = _scsih_srch_boot_encl_slot( + enclosure_logical_id, + slot, &boot_device->EnclosureSlot); + break; + case MPI2_BIOSPAGE2_FORM_DEVICE_NAME: + if (!device_name) + break; + rc = _scsih_srch_boot_device_name( + device_name, &boot_device->DeviceName); + break; + case MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED: + break; + } + + return rc; +} + +/** + * _scsih_determine_boot_device - determine boot device. + * @ioc: per adapter object + * @device: either sas_device or raid_device object + * @is_raid: [flag] 1 = raid object, 0 = sas object + * + * Determines whether this device should be first reported device to + * to scsi-ml or sas transport, this purpose is for persistant boot device. + * There are primary, alternate, and current entries in bios page 2. The order + * priority is primary, alternate, then current. This routine saves + * the corresponding device object and is_raid flag in the ioc object. + * The saved data to be used later in _scsih_probe_boot_devices(). + */ +static void +_scsih_determine_boot_device(struct MPT2SAS_ADAPTER *ioc, + void *device, u8 is_raid) +{ + struct _sas_device *sas_device; + struct _raid_device *raid_device; + u64 sas_address; + u64 device_name; + u64 enclosure_logical_id; + u16 slot; + + /* only process this function when driver loads */ + if (!ioc->wait_for_port_enable_to_complete) + return; + + if (!is_raid) { + sas_device = device; + sas_address = sas_device->sas_address; + device_name = sas_device->device_name; + enclosure_logical_id = sas_device->enclosure_logical_id; + slot = sas_device->slot; + } else { + raid_device = device; + sas_address = raid_device->wwid; + device_name = 0; + enclosure_logical_id = 0; + slot = 0; + } + + if (!ioc->req_boot_device.device) { + if (_scsih_is_boot_device(sas_address, device_name, + enclosure_logical_id, slot, + (ioc->bios_pg2.ReqBootDeviceForm & + MPI2_BIOSPAGE2_FORM_MASK), + &ioc->bios_pg2.RequestedBootDevice)) { + dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT + "%s: req_boot_device(0x%016llx)\n", + ioc->name, __func__, + (unsigned long long)sas_address)); + ioc->req_boot_device.device = device; + ioc->req_boot_device.is_raid = is_raid; + } + } + + if (!ioc->req_alt_boot_device.device) { + if (_scsih_is_boot_device(sas_address, device_name, + enclosure_logical_id, slot, + (ioc->bios_pg2.ReqAltBootDeviceForm & + MPI2_BIOSPAGE2_FORM_MASK), + &ioc->bios_pg2.RequestedAltBootDevice)) { + dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT + "%s: req_alt_boot_device(0x%016llx)\n", + ioc->name, __func__, + (unsigned long long)sas_address)); + ioc->req_alt_boot_device.device = device; + ioc->req_alt_boot_device.is_raid = is_raid; + } + } + + if (!ioc->current_boot_device.device) { + if (_scsih_is_boot_device(sas_address, device_name, + enclosure_logical_id, slot, + (ioc->bios_pg2.CurrentBootDeviceForm & + MPI2_BIOSPAGE2_FORM_MASK), + &ioc->bios_pg2.CurrentBootDevice)) { + dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT + "%s: current_boot_device(0x%016llx)\n", + ioc->name, __func__, + (unsigned long long)sas_address)); + ioc->current_boot_device.device = device; + ioc->current_boot_device.is_raid = is_raid; + } + } +} + +/** + * mpt2sas_scsih_sas_device_find_by_sas_address - sas device search + * @ioc: per adapter object + * @sas_address: sas address + * Context: Calling function should acquire ioc->sas_device_lock + * + * This searches for sas_device based on sas_address, then return sas_device + * object. + */ +struct _sas_device * +mpt2sas_scsih_sas_device_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc, + u64 sas_address) +{ + struct _sas_device *sas_device, *r; + + r = NULL; + /* check the sas_device_init_list */ + list_for_each_entry(sas_device, &ioc->sas_device_init_list, + list) { + if (sas_device->sas_address != sas_address) + continue; + r = sas_device; + goto out; + } + + /* then check the sas_device_list */ + list_for_each_entry(sas_device, &ioc->sas_device_list, list) { + if (sas_device->sas_address != sas_address) + continue; + r = sas_device; + goto out; + } + out: + return r; +} + +/** + * _scsih_sas_device_find_by_handle - sas device search + * @ioc: per adapter object + * @handle: sas device handle (assigned by firmware) + * Context: Calling function should acquire ioc->sas_device_lock + * + * This searches for sas_device based on sas_address, then return sas_device + * object. + */ +static struct _sas_device * +_scsih_sas_device_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle) +{ + struct _sas_device *sas_device, *r; + + r = NULL; + if (ioc->wait_for_port_enable_to_complete) { + list_for_each_entry(sas_device, &ioc->sas_device_init_list, + list) { + if (sas_device->handle != handle) + continue; + r = sas_device; + goto out; + } + } else { + list_for_each_entry(sas_device, &ioc->sas_device_list, list) { + if (sas_device->handle != handle) + continue; + r = sas_device; + goto out; + } + } + + out: + return r; +} + +/** + * _scsih_sas_device_remove - remove sas_device from list. + * @ioc: per adapter object + * @sas_device: the sas_device object + * Context: This function will acquire ioc->sas_device_lock. + * + * Removing object and freeing associated memory from the ioc->sas_device_list. + */ +static void +_scsih_sas_device_remove(struct MPT2SAS_ADAPTER *ioc, + struct _sas_device *sas_device) +{ + unsigned long flags; + + spin_lock_irqsave(&ioc->sas_device_lock, flags); + list_del(&sas_device->list); + memset(sas_device, 0, sizeof(struct _sas_device)); + kfree(sas_device); + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); +} + +/** + * _scsih_sas_device_add - insert sas_device to the list. + * @ioc: per adapter object + * @sas_device: the sas_device object + * Context: This function will acquire ioc->sas_device_lock. + * + * Adding new object to the ioc->sas_device_list. + */ +static void +_scsih_sas_device_add(struct MPT2SAS_ADAPTER *ioc, + struct _sas_device *sas_device) +{ + unsigned long flags; + u16 handle, parent_handle; + u64 sas_address; + + dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle" + "(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__, + sas_device->handle, (unsigned long long)sas_device->sas_address)); + + spin_lock_irqsave(&ioc->sas_device_lock, flags); + list_add_tail(&sas_device->list, &ioc->sas_device_list); + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + + handle = sas_device->handle; + parent_handle = sas_device->parent_handle; + sas_address = sas_device->sas_address; + if (!mpt2sas_transport_port_add(ioc, handle, parent_handle)) { + _scsih_sas_device_remove(ioc, sas_device); + } else if (!sas_device->starget) { + mpt2sas_transport_port_remove(ioc, sas_address, parent_handle); + _scsih_sas_device_remove(ioc, sas_device); + } +} + +/** + * _scsih_sas_device_init_add - insert sas_device to the list. + * @ioc: per adapter object + * @sas_device: the sas_device object + * Context: This function will acquire ioc->sas_device_lock. + * + * Adding new object at driver load time to the ioc->sas_device_init_list. + */ +static void +_scsih_sas_device_init_add(struct MPT2SAS_ADAPTER *ioc, + struct _sas_device *sas_device) +{ + unsigned long flags; + + dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle" + "(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__, + sas_device->handle, (unsigned long long)sas_device->sas_address)); + + spin_lock_irqsave(&ioc->sas_device_lock, flags); + list_add_tail(&sas_device->list, &ioc->sas_device_init_list); + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + _scsih_determine_boot_device(ioc, sas_device, 0); +} + +/** + * mpt2sas_scsih_expander_find_by_handle - expander device search + * @ioc: per adapter object + * @handle: expander handle (assigned by firmware) + * Context: Calling function should acquire ioc->sas_device_lock + * + * This searches for expander device based on handle, then returns the + * sas_node object. + */ +struct _sas_node * +mpt2sas_scsih_expander_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle) +{ + struct _sas_node *sas_expander, *r; + + r = NULL; + list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) { + if (sas_expander->handle != handle) + continue; + r = sas_expander; + goto out; + } + out: + return r; +} + +/** + * _scsih_raid_device_find_by_id - raid device search + * @ioc: per adapter object + * @id: sas device target id + * @channel: sas device channel + * Context: Calling function should acquire ioc->raid_device_lock + * + * This searches for raid_device based on target id, then return raid_device + * object. + */ +static struct _raid_device * +_scsih_raid_device_find_by_id(struct MPT2SAS_ADAPTER *ioc, int id, int channel) +{ + struct _raid_device *raid_device, *r; + + r = NULL; + list_for_each_entry(raid_device, &ioc->raid_device_list, list) { + if (raid_device->id == id && raid_device->channel == channel) { + r = raid_device; + goto out; + } + } + + out: + return r; +} + +/** + * _scsih_raid_device_find_by_handle - raid device search + * @ioc: per adapter object + * @handle: sas device handle (assigned by firmware) + * Context: Calling function should acquire ioc->raid_device_lock + * + * This searches for raid_device based on handle, then return raid_device + * object. + */ +static struct _raid_device * +_scsih_raid_device_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle) +{ + struct _raid_device *raid_device, *r; + + r = NULL; + list_for_each_entry(raid_device, &ioc->raid_device_list, list) { + if (raid_device->handle != handle) + continue; + r = raid_device; + goto out; + } + + out: + return r; +} + +/** + * _scsih_raid_device_find_by_wwid - raid device search + * @ioc: per adapter object + * @handle: sas device handle (assigned by firmware) + * Context: Calling function should acquire ioc->raid_device_lock + * + * This searches for raid_device based on wwid, then return raid_device + * object. + */ +static struct _raid_device * +_scsih_raid_device_find_by_wwid(struct MPT2SAS_ADAPTER *ioc, u64 wwid) +{ + struct _raid_device *raid_device, *r; + + r = NULL; + list_for_each_entry(raid_device, &ioc->raid_device_list, list) { + if (raid_device->wwid != wwid) + continue; + r = raid_device; + goto out; + } + + out: + return r; +} + +/** + * _scsih_raid_device_add - add raid_device object + * @ioc: per adapter object + * @raid_device: raid_device object + * + * This is added to the raid_device_list link list. + */ +static void +_scsih_raid_device_add(struct MPT2SAS_ADAPTER *ioc, + struct _raid_device *raid_device) +{ + unsigned long flags; + + dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle" + "(0x%04x), wwid(0x%016llx)\n", ioc->name, __func__, + raid_device->handle, (unsigned long long)raid_device->wwid)); + + spin_lock_irqsave(&ioc->raid_device_lock, flags); + list_add_tail(&raid_device->list, &ioc->raid_device_list); + spin_unlock_irqrestore(&ioc->raid_device_lock, flags); +} + +/** + * _scsih_raid_device_remove - delete raid_device object + * @ioc: per adapter object + * @raid_device: raid_device object + * + * This is removed from the raid_device_list link list. + */ +static void +_scsih_raid_device_remove(struct MPT2SAS_ADAPTER *ioc, + struct _raid_device *raid_device) +{ + unsigned long flags; + + spin_lock_irqsave(&ioc->raid_device_lock, flags); + list_del(&raid_device->list); + memset(raid_device, 0, sizeof(struct _raid_device)); + kfree(raid_device); + spin_unlock_irqrestore(&ioc->raid_device_lock, flags); +} + +/** + * mpt2sas_scsih_expander_find_by_sas_address - expander device search + * @ioc: per adapter object + * @sas_address: sas address + * Context: Calling function should acquire ioc->sas_node_lock. + * + * This searches for expander device based on sas_address, then returns the + * sas_node object. + */ +struct _sas_node * +mpt2sas_scsih_expander_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc, + u64 sas_address) +{ + struct _sas_node *sas_expander, *r; + + r = NULL; + list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) { + if (sas_expander->sas_address != sas_address) + continue; + r = sas_expander; + goto out; + } + out: + return r; +} + +/** + * _scsih_expander_node_add - insert expander device to the list. + * @ioc: per adapter object + * @sas_expander: the sas_device object + * Context: This function will acquire ioc->sas_node_lock. + * + * Adding new object to the ioc->sas_expander_list. + * + * Return nothing. + */ +static void +_scsih_expander_node_add(struct MPT2SAS_ADAPTER *ioc, + struct _sas_node *sas_expander) +{ + unsigned long flags; + + spin_lock_irqsave(&ioc->sas_node_lock, flags); + list_add_tail(&sas_expander->list, &ioc->sas_expander_list); + spin_unlock_irqrestore(&ioc->sas_node_lock, flags); +} + +/** + * _scsih_is_end_device - determines if device is an end device + * @device_info: bitfield providing information about the device. + * Context: none + * + * Returns 1 if end device. + */ +static int +_scsih_is_end_device(u32 device_info) +{ + if (device_info & MPI2_SAS_DEVICE_INFO_END_DEVICE && + ((device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) | + (device_info & MPI2_SAS_DEVICE_INFO_STP_TARGET) | + (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE))) + return 1; + else + return 0; +} + +/** + * _scsih_scsi_lookup_get - returns scmd entry + * @ioc: per adapter object + * @smid: system request message index + * Context: This function will acquire ioc->scsi_lookup_lock. + * + * Returns the smid stored scmd pointer. + */ +static struct scsi_cmnd * +_scsih_scsi_lookup_get(struct MPT2SAS_ADAPTER *ioc, u16 smid) +{ + unsigned long flags; + struct scsi_cmnd *scmd; + + spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); + scmd = ioc->scsi_lookup[smid - 1].scmd; + spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); + return scmd; +} + +/** + * mptscsih_getclear_scsi_lookup - returns scmd entry + * @ioc: per adapter object + * @smid: system request message index + * Context: This function will acquire ioc->scsi_lookup_lock. + * + * Returns the smid stored scmd pointer, as well as clearing the scmd pointer. + */ +static struct scsi_cmnd * +_scsih_scsi_lookup_getclear(struct MPT2SAS_ADAPTER *ioc, u16 smid) +{ + unsigned long flags; + struct scsi_cmnd *scmd; + + spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); + scmd = ioc->scsi_lookup[smid - 1].scmd; + ioc->scsi_lookup[smid - 1].scmd = NULL; + spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); + return scmd; +} + +/** + * _scsih_scsi_lookup_set - updates scmd entry in lookup + * @ioc: per adapter object + * @smid: system request message index + * @scmd: pointer to scsi command object + * Context: This function will acquire ioc->scsi_lookup_lock. + * + * This will save scmd pointer in the scsi_lookup array. + * + * Return nothing. + */ +static void +_scsih_scsi_lookup_set(struct MPT2SAS_ADAPTER *ioc, u16 smid, + struct scsi_cmnd *scmd) +{ + unsigned long flags; + + spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); + ioc->scsi_lookup[smid - 1].scmd = scmd; + spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); +} + +/** + * _scsih_scsi_lookup_find_by_scmd - scmd lookup + * @ioc: per adapter object + * @smid: system request message index + * @scmd: pointer to scsi command object + * Context: This function will acquire ioc->scsi_lookup_lock. + * + * This will search for a scmd pointer in the scsi_lookup array, + * returning the revelent smid. A returned value of zero means invalid. + */ +static u16 +_scsih_scsi_lookup_find_by_scmd(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd + *scmd) +{ + u16 smid; + unsigned long flags; + int i; + + spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); + smid = 0; + for (i = 0; i < ioc->request_depth; i++) { + if (ioc->scsi_lookup[i].scmd == scmd) { + smid = i + 1; + goto out; + } + } + out: + spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); + return smid; +} + +/** + * _scsih_scsi_lookup_find_by_target - search for matching channel:id + * @ioc: per adapter object + * @id: target id + * @channel: channel + * Context: This function will acquire ioc->scsi_lookup_lock. + * + * This will search for a matching channel:id in the scsi_lookup array, + * returning 1 if found. + */ +static u8 +_scsih_scsi_lookup_find_by_target(struct MPT2SAS_ADAPTER *ioc, int id, + int channel) +{ + u8 found; + unsigned long flags; + int i; + + spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); + found = 0; + for (i = 0 ; i < ioc->request_depth; i++) { + if (ioc->scsi_lookup[i].scmd && + (ioc->scsi_lookup[i].scmd->device->id == id && + ioc->scsi_lookup[i].scmd->device->channel == channel)) { + found = 1; + goto out; + } + } + out: + spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); + return found; +} + +/** + * _scsih_get_chain_buffer_dma - obtain block of chains (dma address) + * @ioc: per adapter object + * @smid: system request message index + * + * Returns phys pointer to chain buffer. + */ +static dma_addr_t +_scsih_get_chain_buffer_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid) +{ + return ioc->chain_dma + ((smid - 1) * (ioc->request_sz * + ioc->chains_needed_per_io)); +} + +/** + * _scsih_get_chain_buffer - obtain block of chains assigned to a mf request + * @ioc: per adapter object + * @smid: system request message index + * + * Returns virt pointer to chain buffer. + */ +static void * +_scsih_get_chain_buffer(struct MPT2SAS_ADAPTER *ioc, u16 smid) +{ + return (void *)(ioc->chain + ((smid - 1) * (ioc->request_sz * + ioc->chains_needed_per_io))); +} + +/** + * _scsih_build_scatter_gather - main sg creation routine + * @ioc: per adapter object + * @scmd: scsi command + * @smid: system request message index + * Context: none. + * + * The main routine that builds scatter gather table from a given + * scsi request sent via the .queuecommand main handler. + * + * Returns 0 success, anything else error + */ +static int +_scsih_build_scatter_gather(struct MPT2SAS_ADAPTER *ioc, + struct scsi_cmnd *scmd, u16 smid) +{ + Mpi2SCSIIORequest_t *mpi_request; + dma_addr_t chain_dma; + struct scatterlist *sg_scmd; + void *sg_local, *chain; + u32 chain_offset; + u32 chain_length; + u32 chain_flags; + u32 sges_left; + u32 sges_in_segment; + u32 sgl_flags; + u32 sgl_flags_last_element; + u32 sgl_flags_end_buffer; + + mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); + + /* init scatter gather flags */ + sgl_flags = MPI2_SGE_FLAGS_SIMPLE_ELEMENT; + if (scmd->sc_data_direction == DMA_TO_DEVICE) + sgl_flags |= MPI2_SGE_FLAGS_HOST_TO_IOC; + sgl_flags_last_element = (sgl_flags | MPI2_SGE_FLAGS_LAST_ELEMENT) + << MPI2_SGE_FLAGS_SHIFT; + sgl_flags_end_buffer = (sgl_flags | MPI2_SGE_FLAGS_LAST_ELEMENT | + MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_END_OF_LIST) + << MPI2_SGE_FLAGS_SHIFT; + sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; + + sg_scmd = scsi_sglist(scmd); + sges_left = scsi_dma_map(scmd); + if (!sges_left) { + sdev_printk(KERN_ERR, scmd->device, "pci_map_sg" + " failed: request for %d bytes!\n", scsi_bufflen(scmd)); + return -ENOMEM; + } + + sg_local = &mpi_request->SGL; + sges_in_segment = ioc->max_sges_in_main_message; + if (sges_left <= sges_in_segment) + goto fill_in_last_segment; + + mpi_request->ChainOffset = (offsetof(Mpi2SCSIIORequest_t, SGL) + + (sges_in_segment * ioc->sge_size))/4; + + /* fill in main message segment when there is a chain following */ + while (sges_in_segment) { + if (sges_in_segment == 1) + ioc->base_add_sg_single(sg_local, + sgl_flags_last_element | sg_dma_len(sg_scmd), + sg_dma_address(sg_scmd)); + else + ioc->base_add_sg_single(sg_local, sgl_flags | + sg_dma_len(sg_scmd), sg_dma_address(sg_scmd)); + sg_scmd = sg_next(sg_scmd); + sg_local += ioc->sge_size; + sges_left--; + sges_in_segment--; + } + + /* initializing the chain flags and pointers */ + chain_flags = MPI2_SGE_FLAGS_CHAIN_ELEMENT << MPI2_SGE_FLAGS_SHIFT; + chain = _scsih_get_chain_buffer(ioc, smid); + chain_dma = _scsih_get_chain_buffer_dma(ioc, smid); + do { + sges_in_segment = (sges_left <= + ioc->max_sges_in_chain_message) ? sges_left : + ioc->max_sges_in_chain_message; + chain_offset = (sges_left == sges_in_segment) ? + 0 : (sges_in_segment * ioc->sge_size)/4; + chain_length = sges_in_segment * ioc->sge_size; + if (chain_offset) { + chain_offset = chain_offset << + MPI2_SGE_CHAIN_OFFSET_SHIFT; + chain_length += ioc->sge_size; + } + ioc->base_add_sg_single(sg_local, chain_flags | chain_offset | + chain_length, chain_dma); + sg_local = chain; + if (!chain_offset) + goto fill_in_last_segment; + + /* fill in chain segments */ + while (sges_in_segment) { + if (sges_in_segment == 1) + ioc->base_add_sg_single(sg_local, + sgl_flags_last_element | + sg_dma_len(sg_scmd), + sg_dma_address(sg_scmd)); + else + ioc->base_add_sg_single(sg_local, sgl_flags | + sg_dma_len(sg_scmd), + sg_dma_address(sg_scmd)); + sg_scmd = sg_next(sg_scmd); + sg_local += ioc->sge_size; + sges_left--; + sges_in_segment--; + } + + chain_dma += ioc->request_sz; + chain += ioc->request_sz; + } while (1); + + + fill_in_last_segment: + + /* fill the last segment */ + while (sges_left) { + if (sges_left == 1) + ioc->base_add_sg_single(sg_local, sgl_flags_end_buffer | + sg_dma_len(sg_scmd), sg_dma_address(sg_scmd)); + else + ioc->base_add_sg_single(sg_local, sgl_flags | + sg_dma_len(sg_scmd), sg_dma_address(sg_scmd)); + sg_scmd = sg_next(sg_scmd); + sg_local += ioc->sge_size; + sges_left--; + } + + return 0; +} + +/** + * scsih_change_queue_depth - setting device queue depth + * @sdev: scsi device struct + * @qdepth: requested queue depth + * + * Returns queue depth. + */ +static int +scsih_change_queue_depth(struct scsi_device *sdev, int qdepth) +{ + struct Scsi_Host *shost = sdev->host; + int max_depth; + int tag_type; + + max_depth = shost->can_queue; + if (!sdev->tagged_supported) + max_depth = 1; + if (qdepth > max_depth) + qdepth = max_depth; + tag_type = (qdepth == 1) ? 0 : MSG_SIMPLE_TAG; + scsi_adjust_queue_depth(sdev, tag_type, qdepth); + + if (sdev->inquiry_len > 7) + sdev_printk(KERN_INFO, sdev, "qdepth(%d), tagged(%d), " + "simple(%d), ordered(%d), scsi_level(%d), cmd_que(%d)\n", + sdev->queue_depth, sdev->tagged_supported, sdev->simple_tags, + sdev->ordered_tags, sdev->scsi_level, + (sdev->inquiry[7] & 2) >> 1); + + return sdev->queue_depth; +} + +/** + * scsih_change_queue_depth - changing device queue tag type + * @sdev: scsi device struct + * @tag_type: requested tag type + * + * Returns queue tag type. + */ +static int +scsih_change_queue_type(struct scsi_device *sdev, int tag_type) +{ + if (sdev->tagged_supported) { + scsi_set_tag_type(sdev, tag_type); + if (tag_type) + scsi_activate_tcq(sdev, sdev->queue_depth); + else + scsi_deactivate_tcq(sdev, sdev->queue_depth); + } else + tag_type = 0; + + return tag_type; +} + +/** + * scsih_target_alloc - target add routine + * @starget: scsi target struct + * + * Returns 0 if ok. Any other return is assumed to be an error and + * the device is ignored. + */ +static int +scsih_target_alloc(struct scsi_target *starget) +{ + struct Scsi_Host *shost = dev_to_shost(&starget->dev); + struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + struct MPT2SAS_TARGET *sas_target_priv_data; + struct _sas_device *sas_device; + struct _raid_device *raid_device; + unsigned long flags; + struct sas_rphy *rphy; + + sas_target_priv_data = kzalloc(sizeof(struct scsi_target), GFP_KERNEL); + if (!sas_target_priv_data) + return -ENOMEM; + + starget->hostdata = sas_target_priv_data; + sas_target_priv_data->starget = starget; + sas_target_priv_data->handle = MPT2SAS_INVALID_DEVICE_HANDLE; + + /* RAID volumes */ + if (starget->channel == RAID_CHANNEL) { + spin_lock_irqsave(&ioc->raid_device_lock, flags); + raid_device = _scsih_raid_device_find_by_id(ioc, starget->id, + starget->channel); + if (raid_device) { + sas_target_priv_data->handle = raid_device->handle; + sas_target_priv_data->sas_address = raid_device->wwid; + sas_target_priv_data->flags |= MPT_TARGET_FLAGS_VOLUME; + raid_device->starget = starget; + } + spin_unlock_irqrestore(&ioc->raid_device_lock, flags); + return 0; + } + + /* sas/sata devices */ + spin_lock_irqsave(&ioc->sas_device_lock, flags); + rphy = dev_to_rphy(starget->dev.parent); + sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, + rphy->identify.sas_address); + + if (sas_device) { + sas_target_priv_data->handle = sas_device->handle; + sas_target_priv_data->sas_address = sas_device->sas_address; + sas_device->starget = starget; + sas_device->id = starget->id; + sas_device->channel = starget->channel; + if (sas_device->hidden_raid_component) + sas_target_priv_data->flags |= + MPT_TARGET_FLAGS_RAID_COMPONENT; + } + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + + return 0; +} + +/** + * scsih_target_destroy - target destroy routine + * @starget: scsi target struct + * + * Returns nothing. + */ +static void +scsih_target_destroy(struct scsi_target *starget) +{ + struct Scsi_Host *shost = dev_to_shost(&starget->dev); + struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + struct MPT2SAS_TARGET *sas_target_priv_data; + struct _sas_device *sas_device; + struct _raid_device *raid_device; + unsigned long flags; + struct sas_rphy *rphy; + + sas_target_priv_data = starget->hostdata; + if (!sas_target_priv_data) + return; + + if (starget->channel == RAID_CHANNEL) { + spin_lock_irqsave(&ioc->raid_device_lock, flags); + raid_device = _scsih_raid_device_find_by_id(ioc, starget->id, + starget->channel); + if (raid_device) { + raid_device->starget = NULL; + raid_device->sdev = NULL; + } + spin_unlock_irqrestore(&ioc->raid_device_lock, flags); + goto out; + } + + spin_lock_irqsave(&ioc->sas_device_lock, flags); + rphy = dev_to_rphy(starget->dev.parent); + sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, + rphy->identify.sas_address); + if (sas_device) + sas_device->starget = NULL; + + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + + out: + kfree(sas_target_priv_data); + starget->hostdata = NULL; +} + +/** + * scsih_slave_alloc - device add routine + * @sdev: scsi device struct + * + * Returns 0 if ok. Any other return is assumed to be an error and + * the device is ignored. + */ +static int +scsih_slave_alloc(struct scsi_device *sdev) +{ + struct Scsi_Host *shost; + struct MPT2SAS_ADAPTER *ioc; + struct MPT2SAS_TARGET *sas_target_priv_data; + struct MPT2SAS_DEVICE *sas_device_priv_data; + struct scsi_target *starget; + struct _raid_device *raid_device; + struct _sas_device *sas_device; + unsigned long flags; + + sas_device_priv_data = kzalloc(sizeof(struct scsi_device), GFP_KERNEL); + if (!sas_device_priv_data) + return -ENOMEM; + + sas_device_priv_data->lun = sdev->lun; + sas_device_priv_data->flags = MPT_DEVICE_FLAGS_INIT; + + starget = scsi_target(sdev); + sas_target_priv_data = starget->hostdata; + sas_target_priv_data->num_luns++; + sas_device_priv_data->sas_target = sas_target_priv_data; + sdev->hostdata = sas_device_priv_data; + if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT)) + sdev->no_uld_attach = 1; + + shost = dev_to_shost(&starget->dev); + ioc = shost_priv(shost); + if (starget->channel == RAID_CHANNEL) { + spin_lock_irqsave(&ioc->raid_device_lock, flags); + raid_device = _scsih_raid_device_find_by_id(ioc, + starget->id, starget->channel); + if (raid_device) + raid_device->sdev = sdev; /* raid is single lun */ + spin_unlock_irqrestore(&ioc->raid_device_lock, flags); + } else { + /* set TLR bit for SSP devices */ + if (!(ioc->facts.IOCCapabilities & + MPI2_IOCFACTS_CAPABILITY_TLR)) + goto out; + spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, + sas_device_priv_data->sas_target->sas_address); + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + if (sas_device && sas_device->device_info & + MPI2_SAS_DEVICE_INFO_SSP_TARGET) + sas_device_priv_data->flags |= MPT_DEVICE_TLR_ON; + } + + out: + return 0; +} + +/** + * scsih_slave_destroy - device destroy routine + * @sdev: scsi device struct + * + * Returns nothing. + */ +static void +scsih_slave_destroy(struct scsi_device *sdev) +{ + struct MPT2SAS_TARGET *sas_target_priv_data; + struct scsi_target *starget; + + if (!sdev->hostdata) + return; + + starget = scsi_target(sdev); + sas_target_priv_data = starget->hostdata; + sas_target_priv_data->num_luns--; + kfree(sdev->hostdata); + sdev->hostdata = NULL; +} + +/** + * scsih_display_sata_capabilities - sata capabilities + * @ioc: per adapter object + * @sas_device: the sas_device object + * @sdev: scsi device struct + */ +static void +scsih_display_sata_capabilities(struct MPT2SAS_ADAPTER *ioc, + struct _sas_device *sas_device, struct scsi_device *sdev) +{ + Mpi2ConfigReply_t mpi_reply; + Mpi2SasDevicePage0_t sas_device_pg0; + u32 ioc_status; + u16 flags; + u32 device_info; + + if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, + MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, sas_device->handle))) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + return; + } + + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + return; + } + + flags = le16_to_cpu(sas_device_pg0.Flags); + device_info = le16_to_cpu(sas_device_pg0.DeviceInfo); + + sdev_printk(KERN_INFO, sdev, + "atapi(%s), ncq(%s), asyn_notify(%s), smart(%s), fua(%s), " + "sw_preserve(%s)\n", + (device_info & MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE) ? "y" : "n", + (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_NCQ_SUPPORTED) ? "y" : "n", + (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_ASYNCHRONOUS_NOTIFY) ? "y" : + "n", + (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_SMART_SUPPORTED) ? "y" : "n", + (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_FUA_SUPPORTED) ? "y" : "n", + (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_SW_PRESERVE) ? "y" : "n"); +} + +/** + * _scsih_get_volume_capabilities - volume capabilities + * @ioc: per adapter object + * @sas_device: the raid_device object + */ +static void +_scsih_get_volume_capabilities(struct MPT2SAS_ADAPTER *ioc, + struct _raid_device *raid_device) +{ + Mpi2RaidVolPage0_t *vol_pg0; + Mpi2RaidPhysDiskPage0_t pd_pg0; + Mpi2SasDevicePage0_t sas_device_pg0; + Mpi2ConfigReply_t mpi_reply; + u16 sz; + u8 num_pds; + + if ((mpt2sas_config_get_number_pds(ioc, raid_device->handle, + &num_pds)) || !num_pds) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + return; + } + + raid_device->num_pds = num_pds; + sz = offsetof(Mpi2RaidVolPage0_t, PhysDisk) + (num_pds * + sizeof(Mpi2RaidVol0PhysDisk_t)); + vol_pg0 = kzalloc(sz, GFP_KERNEL); + if (!vol_pg0) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + return; + } + + if ((mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, vol_pg0, + MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, sz))) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + kfree(vol_pg0); + return; + } + + raid_device->volume_type = vol_pg0->VolumeType; + + /* figure out what the underlying devices are by + * obtaining the device_info bits for the 1st device + */ + if (!(mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply, + &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM, + vol_pg0->PhysDisk[0].PhysDiskNum))) { + if (!(mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, + &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, + le16_to_cpu(pd_pg0.DevHandle)))) { + raid_device->device_info = + le32_to_cpu(sas_device_pg0.DeviceInfo); + } + } + + kfree(vol_pg0); +} + +/** + * scsih_slave_configure - device configure routine. + * @sdev: scsi device struct + * + * Returns 0 if ok. Any other return is assumed to be an error and + * the device is ignored. + */ +static int +scsih_slave_configure(struct scsi_device *sdev) +{ + struct Scsi_Host *shost = sdev->host; + struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + struct MPT2SAS_DEVICE *sas_device_priv_data; + struct MPT2SAS_TARGET *sas_target_priv_data; + struct _sas_device *sas_device; + struct _raid_device *raid_device; + unsigned long flags; + int qdepth; + u8 ssp_target = 0; + char *ds = ""; + char *r_level = ""; + + qdepth = 1; + sas_device_priv_data = sdev->hostdata; + sas_device_priv_data->configured_lun = 1; + sas_device_priv_data->flags &= ~MPT_DEVICE_FLAGS_INIT; + sas_target_priv_data = sas_device_priv_data->sas_target; + + /* raid volume handling */ + if (sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME) { + + spin_lock_irqsave(&ioc->raid_device_lock, flags); + raid_device = _scsih_raid_device_find_by_handle(ioc, + sas_target_priv_data->handle); + spin_unlock_irqrestore(&ioc->raid_device_lock, flags); + if (!raid_device) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + return 0; + } + + _scsih_get_volume_capabilities(ioc, raid_device); + + /* RAID Queue Depth Support + * IS volume = underlying qdepth of drive type, either + * MPT2SAS_SAS_QUEUE_DEPTH or MPT2SAS_SATA_QUEUE_DEPTH + * IM/IME/R10 = 128 (MPT2SAS_RAID_QUEUE_DEPTH) + */ + if (raid_device->device_info & + MPI2_SAS_DEVICE_INFO_SSP_TARGET) { + qdepth = MPT2SAS_SAS_QUEUE_DEPTH; + ds = "SSP"; + } else { + qdepth = MPT2SAS_SATA_QUEUE_DEPTH; + if (raid_device->device_info & + MPI2_SAS_DEVICE_INFO_SATA_DEVICE) + ds = "SATA"; + else + ds = "STP"; + } + + switch (raid_device->volume_type) { + case MPI2_RAID_VOL_TYPE_RAID0: + r_level = "RAID0"; + break; + case MPI2_RAID_VOL_TYPE_RAID1E: + qdepth = MPT2SAS_RAID_QUEUE_DEPTH; + r_level = "RAID1E"; + break; + case MPI2_RAID_VOL_TYPE_RAID1: + qdepth = MPT2SAS_RAID_QUEUE_DEPTH; + r_level = "RAID1"; + break; + case MPI2_RAID_VOL_TYPE_RAID10: + qdepth = MPT2SAS_RAID_QUEUE_DEPTH; + r_level = "RAID10"; + break; + case MPI2_RAID_VOL_TYPE_UNKNOWN: + default: + qdepth = MPT2SAS_RAID_QUEUE_DEPTH; + r_level = "RAIDX"; + break; + } + + sdev_printk(KERN_INFO, sdev, "%s: " + "handle(0x%04x), wwid(0x%016llx), pd_count(%d), type(%s)\n", + r_level, raid_device->handle, + (unsigned long long)raid_device->wwid, + raid_device->num_pds, ds); + scsih_change_queue_depth(sdev, qdepth); + return 0; + } + + /* non-raid handling */ + spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, + sas_device_priv_data->sas_target->sas_address); + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + if (sas_device) { + if (sas_target_priv_data->flags & + MPT_TARGET_FLAGS_RAID_COMPONENT) { + mpt2sas_config_get_volume_handle(ioc, + sas_device->handle, &sas_device->volume_handle); + mpt2sas_config_get_volume_wwid(ioc, + sas_device->volume_handle, + &sas_device->volume_wwid); + } + if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) { + qdepth = MPT2SAS_SAS_QUEUE_DEPTH; + ssp_target = 1; + ds = "SSP"; + } else { + qdepth = MPT2SAS_SATA_QUEUE_DEPTH; + if (sas_device->device_info & + MPI2_SAS_DEVICE_INFO_STP_TARGET) + ds = "STP"; + else if (sas_device->device_info & + MPI2_SAS_DEVICE_INFO_SATA_DEVICE) + ds = "SATA"; + } + + sdev_printk(KERN_INFO, sdev, "%s: handle(0x%04x), " + "sas_addr(0x%016llx), device_name(0x%016llx)\n", + ds, sas_device->handle, + (unsigned long long)sas_device->sas_address, + (unsigned long long)sas_device->device_name); + sdev_printk(KERN_INFO, sdev, "%s: " + "enclosure_logical_id(0x%016llx), slot(%d)\n", ds, + (unsigned long long) sas_device->enclosure_logical_id, + sas_device->slot); + + if (!ssp_target) + scsih_display_sata_capabilities(ioc, sas_device, sdev); + } + + scsih_change_queue_depth(sdev, qdepth); + + if (ssp_target) + sas_read_port_mode_page(sdev); + return 0; +} + +/** + * scsih_bios_param - fetch head, sector, cylinder info for a disk + * @sdev: scsi device struct + * @bdev: pointer to block device context + * @capacity: device size (in 512 byte sectors) + * @params: three element array to place output: + * params[0] number of heads (max 255) + * params[1] number of sectors (max 63) + * params[2] number of cylinders + * + * Return nothing. + */ +static int +scsih_bios_param(struct scsi_device *sdev, struct block_device *bdev, + sector_t capacity, int params[]) +{ + int heads; + int sectors; + sector_t cylinders; + ulong dummy; + + heads = 64; + sectors = 32; + + dummy = heads * sectors; + cylinders = capacity; + sector_div(cylinders, dummy); + + /* + * Handle extended translation size for logical drives + * > 1Gb + */ + if ((ulong)capacity >= 0x200000) { + heads = 255; + sectors = 63; + dummy = heads * sectors; + cylinders = capacity; + sector_div(cylinders, dummy); + } + + /* return result */ + params[0] = heads; + params[1] = sectors; + params[2] = cylinders; + + return 0; +} + +/** + * _scsih_response_code - translation of device response code + * @ioc: per adapter object + * @response_code: response code returned by the device + * + * Return nothing. + */ +static void +_scsih_response_code(struct MPT2SAS_ADAPTER *ioc, u8 response_code) +{ + char *desc; + + switch (response_code) { + case MPI2_SCSITASKMGMT_RSP_TM_COMPLETE: + desc = "task management request completed"; + break; + case MPI2_SCSITASKMGMT_RSP_INVALID_FRAME: + desc = "invalid frame"; + break; + case MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED: + desc = "task management request not supported"; + break; + case MPI2_SCSITASKMGMT_RSP_TM_FAILED: + desc = "task management request failed"; + break; + case MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED: + desc = "task management request succeeded"; + break; + case MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN: + desc = "invalid lun"; + break; + case 0xA: + desc = "overlapped tag attempted"; + break; + case MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC: + desc = "task queued, however not sent to target"; + break; + default: + desc = "unknown"; + break; + } + printk(MPT2SAS_WARN_FMT "response_code(0x%01x): %s\n", + ioc->name, response_code, desc); +} + +/** + * scsih_tm_done - tm completion routine + * @ioc: per adapter object + * @smid: system request message index + * @VF_ID: virtual function id + * @reply: reply message frame(lower 32bit addr) + * Context: none. + * + * The callback handler when using scsih_issue_tm. + * + * Return nothing. + */ +static void +scsih_tm_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply) +{ + MPI2DefaultReply_t *mpi_reply; + + if (ioc->tm_cmds.status == MPT2_CMD_NOT_USED) + return; + if (ioc->tm_cmds.smid != smid) + return; + ioc->tm_cmds.status |= MPT2_CMD_COMPLETE; + mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); + if (mpi_reply) { + memcpy(ioc->tm_cmds.reply, mpi_reply, mpi_reply->MsgLength*4); + ioc->tm_cmds.status |= MPT2_CMD_REPLY_VALID; + } + ioc->tm_cmds.status &= ~MPT2_CMD_PENDING; + complete(&ioc->tm_cmds.done); +} + +/** + * mpt2sas_scsih_set_tm_flag - set per target tm_busy + * @ioc: per adapter object + * @handle: device handle + * + * During taskmangement request, we need to freeze the device queue. + */ +void +mpt2sas_scsih_set_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle) +{ + struct MPT2SAS_DEVICE *sas_device_priv_data; + struct scsi_device *sdev; + u8 skip = 0; + + shost_for_each_device(sdev, ioc->shost) { + if (skip) + continue; + sas_device_priv_data = sdev->hostdata; + if (!sas_device_priv_data) + continue; + if (sas_device_priv_data->sas_target->handle == handle) { + sas_device_priv_data->sas_target->tm_busy = 1; + skip = 1; + ioc->ignore_loginfos = 1; + } + } +} + +/** + * mpt2sas_scsih_clear_tm_flag - clear per target tm_busy + * @ioc: per adapter object + * @handle: device handle + * + * During taskmangement request, we need to freeze the device queue. + */ +void +mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle) +{ + struct MPT2SAS_DEVICE *sas_device_priv_data; + struct scsi_device *sdev; + u8 skip = 0; + + shost_for_each_device(sdev, ioc->shost) { + if (skip) + continue; + sas_device_priv_data = sdev->hostdata; + if (!sas_device_priv_data) + continue; + if (sas_device_priv_data->sas_target->handle == handle) { + sas_device_priv_data->sas_target->tm_busy = 0; + skip = 1; + ioc->ignore_loginfos = 0; + } + } +} + +/** + * mpt2sas_scsih_issue_tm - main routine for sending tm requests + * @ioc: per adapter struct + * @device_handle: device handle + * @lun: lun number + * @type: MPI2_SCSITASKMGMT_TASKTYPE__XXX (defined in mpi2_init.h) + * @smid_task: smid assigned to the task + * @timeout: timeout in seconds + * Context: The calling function needs to acquire the tm_cmds.mutex + * + * A generic API for sending task management requests to firmware. + * + * The ioc->tm_cmds.status flag should be MPT2_CMD_NOT_USED before calling + * this API. + * + * The callback index is set inside `ioc->tm_cb_idx`. + * + * Return nothing. + */ +void +mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun, + u8 type, u16 smid_task, ulong timeout) +{ + Mpi2SCSITaskManagementRequest_t *mpi_request; + Mpi2SCSITaskManagementReply_t *mpi_reply; + u16 smid = 0; + u32 ioc_state; + unsigned long timeleft; + u8 VF_ID = 0; + unsigned long flags; + + spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); + if (ioc->tm_cmds.status != MPT2_CMD_NOT_USED || + ioc->shost_recovery) { + spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); + printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n", + __func__, ioc->name); + return; + } + spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); + + ioc_state = mpt2sas_base_get_iocstate(ioc, 0); + if (ioc_state & MPI2_DOORBELL_USED) { + dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "unexpected doorbell " + "active!\n", ioc->name)); + goto issue_host_reset; + } + + if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) { + mpt2sas_base_fault_info(ioc, ioc_state & + MPI2_DOORBELL_DATA_MASK); + goto issue_host_reset; + } + + smid = mpt2sas_base_get_smid(ioc, ioc->tm_cb_idx); + if (!smid) { + printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", + ioc->name, __func__); + return; + } + + dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "sending tm: handle(0x%04x)," + " task_type(0x%02x), smid(%d)\n", ioc->name, handle, type, smid)); + ioc->tm_cmds.status = MPT2_CMD_PENDING; + mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); + ioc->tm_cmds.smid = smid; + memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t)); + mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; + mpi_request->DevHandle = cpu_to_le16(handle); + mpi_request->TaskType = type; + mpi_request->TaskMID = cpu_to_le16(smid_task); + int_to_scsilun(lun, (struct scsi_lun *)mpi_request->LUN); + mpt2sas_scsih_set_tm_flag(ioc, handle); + mpt2sas_base_put_smid_hi_priority(ioc, smid, VF_ID); + timeleft = wait_for_completion_timeout(&ioc->tm_cmds.done, timeout*HZ); + mpt2sas_scsih_clear_tm_flag(ioc, handle); + if (!(ioc->tm_cmds.status & MPT2_CMD_COMPLETE)) { + printk(MPT2SAS_ERR_FMT "%s: timeout\n", + ioc->name, __func__); + _debug_dump_mf(mpi_request, + sizeof(Mpi2SCSITaskManagementRequest_t)/4); + if (!(ioc->tm_cmds.status & MPT2_CMD_RESET)) + goto issue_host_reset; + } + + if (ioc->tm_cmds.status & MPT2_CMD_REPLY_VALID) { + mpi_reply = ioc->tm_cmds.reply; + dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "complete tm: " + "ioc_status(0x%04x), loginfo(0x%08x), term_count(0x%08x)\n", + ioc->name, le16_to_cpu(mpi_reply->IOCStatus), + le32_to_cpu(mpi_reply->IOCLogInfo), + le32_to_cpu(mpi_reply->TerminationCount))); + if (ioc->logging_level & MPT_DEBUG_TM) + _scsih_response_code(ioc, mpi_reply->ResponseCode); + } + return; + issue_host_reset: + mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, FORCE_BIG_HAMMER); +} + +/** + * scsih_abort - eh threads main abort routine + * @sdev: scsi device struct + * + * Returns SUCCESS if command aborted else FAILED + */ +static int +scsih_abort(struct scsi_cmnd *scmd) +{ + struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host); + struct MPT2SAS_DEVICE *sas_device_priv_data; + u16 smid; + u16 handle; + int r; + struct scsi_cmnd *scmd_lookup; + + printk(MPT2SAS_INFO_FMT "attempting task abort! scmd(%p)\n", + ioc->name, scmd); + scsi_print_command(scmd); + + sas_device_priv_data = scmd->device->hostdata; + if (!sas_device_priv_data || !sas_device_priv_data->sas_target) { + printk(MPT2SAS_INFO_FMT "device been deleted! scmd(%p)\n", + ioc->name, scmd); + scmd->result = DID_NO_CONNECT << 16; + scmd->scsi_done(scmd); + r = SUCCESS; + goto out; + } + + /* search for the command */ + smid = _scsih_scsi_lookup_find_by_scmd(ioc, scmd); + if (!smid) { + scmd->result = DID_RESET << 16; + r = SUCCESS; + goto out; + } + + /* for hidden raid components and volumes this is not supported */ + if (sas_device_priv_data->sas_target->flags & + MPT_TARGET_FLAGS_RAID_COMPONENT || + sas_device_priv_data->sas_target->flags & MPT_TARGET_FLAGS_VOLUME) { + scmd->result = DID_RESET << 16; + r = FAILED; + goto out; + } + + mutex_lock(&ioc->tm_cmds.mutex); + handle = sas_device_priv_data->sas_target->handle; + mpt2sas_scsih_issue_tm(ioc, handle, sas_device_priv_data->lun, + MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30); + + /* sanity check - see whether command actually completed */ + scmd_lookup = _scsih_scsi_lookup_get(ioc, smid); + if (scmd_lookup && (scmd_lookup->serial_number == scmd->serial_number)) + r = FAILED; + else + r = SUCCESS; + ioc->tm_cmds.status = MPT2_CMD_NOT_USED; + mutex_unlock(&ioc->tm_cmds.mutex); + + out: + printk(MPT2SAS_INFO_FMT "task abort: %s scmd(%p)\n", + ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); + return r; +} + + +/** + * scsih_dev_reset - eh threads main device reset routine + * @sdev: scsi device struct + * + * Returns SUCCESS if command aborted else FAILED + */ +static int +scsih_dev_reset(struct scsi_cmnd *scmd) +{ + struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host); + struct MPT2SAS_DEVICE *sas_device_priv_data; + struct _sas_device *sas_device; + unsigned long flags; + u16 handle; + int r; + + printk(MPT2SAS_INFO_FMT "attempting target reset! scmd(%p)\n", + ioc->name, scmd); + scsi_print_command(scmd); + + sas_device_priv_data = scmd->device->hostdata; + if (!sas_device_priv_data || !sas_device_priv_data->sas_target) { + printk(MPT2SAS_INFO_FMT "device been deleted! scmd(%p)\n", + ioc->name, scmd); + scmd->result = DID_NO_CONNECT << 16; + scmd->scsi_done(scmd); + r = SUCCESS; + goto out; + } + + /* for hidden raid components obtain the volume_handle */ + handle = 0; + if (sas_device_priv_data->sas_target->flags & + MPT_TARGET_FLAGS_RAID_COMPONENT) { + spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_device = _scsih_sas_device_find_by_handle(ioc, + sas_device_priv_data->sas_target->handle); + if (sas_device) + handle = sas_device->volume_handle; + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + } else + handle = sas_device_priv_data->sas_target->handle; + + if (!handle) { + scmd->result = DID_RESET << 16; + r = FAILED; + goto out; + } + + mutex_lock(&ioc->tm_cmds.mutex); + mpt2sas_scsih_issue_tm(ioc, handle, 0, + MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 30); + + /* + * sanity check see whether all commands to this target been + * completed + */ + if (_scsih_scsi_lookup_find_by_target(ioc, scmd->device->id, + scmd->device->channel)) + r = FAILED; + else + r = SUCCESS; + ioc->tm_cmds.status = MPT2_CMD_NOT_USED; + mutex_unlock(&ioc->tm_cmds.mutex); + + out: + printk(MPT2SAS_INFO_FMT "target reset: %s scmd(%p)\n", + ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); + return r; +} + +/** + * scsih_abort - eh threads main host reset routine + * @sdev: scsi device struct + * + * Returns SUCCESS if command aborted else FAILED + */ +static int +scsih_host_reset(struct scsi_cmnd *scmd) +{ + struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host); + int r, retval; + + printk(MPT2SAS_INFO_FMT "attempting host reset! scmd(%p)\n", + ioc->name, scmd); + scsi_print_command(scmd); + + retval = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, + FORCE_BIG_HAMMER); + r = (retval < 0) ? FAILED : SUCCESS; + printk(MPT2SAS_INFO_FMT "host reset: %s scmd(%p)\n", + ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); + + return r; +} + +/** + * _scsih_fw_event_add - insert and queue up fw_event + * @ioc: per adapter object + * @fw_event: object describing the event + * Context: This function will acquire ioc->fw_event_lock. + * + * This adds the firmware event object into link list, then queues it up to + * be processed from user context. + * + * Return nothing. + */ +static void +_scsih_fw_event_add(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work *fw_event) +{ + unsigned long flags; + + if (ioc->firmware_event_thread == NULL) + return; + + spin_lock_irqsave(&ioc->fw_event_lock, flags); + list_add_tail(&fw_event->list, &ioc->fw_event_list); + INIT_DELAYED_WORK(&fw_event->work, _firmware_event_work); + queue_delayed_work(ioc->firmware_event_thread, &fw_event->work, 1); + spin_unlock_irqrestore(&ioc->fw_event_lock, flags); +} + +/** + * _scsih_fw_event_free - delete fw_event + * @ioc: per adapter object + * @fw_event: object describing the event + * Context: This function will acquire ioc->fw_event_lock. + * + * This removes firmware event object from link list, frees associated memory. + * + * Return nothing. + */ +static void +_scsih_fw_event_free(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work + *fw_event) +{ + unsigned long flags; + + spin_lock_irqsave(&ioc->fw_event_lock, flags); + list_del(&fw_event->list); + kfree(fw_event->event_data); + kfree(fw_event); + spin_unlock_irqrestore(&ioc->fw_event_lock, flags); +} + +/** + * _scsih_fw_event_add - requeue an event + * @ioc: per adapter object + * @fw_event: object describing the event + * Context: This function will acquire ioc->fw_event_lock. + * + * Return nothing. + */ +static void +_scsih_fw_event_requeue(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work + *fw_event, unsigned long delay) +{ + unsigned long flags; + if (ioc->firmware_event_thread == NULL) + return; + + spin_lock_irqsave(&ioc->fw_event_lock, flags); + queue_delayed_work(ioc->firmware_event_thread, &fw_event->work, delay); + spin_unlock_irqrestore(&ioc->fw_event_lock, flags); +} + +/** + * _scsih_fw_event_off - turn flag off preventing event handling + * @ioc: per adapter object + * + * Used to prevent handling of firmware events during adapter reset + * driver unload. + * + * Return nothing. + */ +static void +_scsih_fw_event_off(struct MPT2SAS_ADAPTER *ioc) +{ + unsigned long flags; + + spin_lock_irqsave(&ioc->fw_event_lock, flags); + ioc->fw_events_off = 1; + spin_unlock_irqrestore(&ioc->fw_event_lock, flags); + +} + +/** + * _scsih_fw_event_on - turn flag on allowing firmware event handling + * @ioc: per adapter object + * + * Returns nothing. + */ +static void +_scsih_fw_event_on(struct MPT2SAS_ADAPTER *ioc) +{ + unsigned long flags; + + spin_lock_irqsave(&ioc->fw_event_lock, flags); + ioc->fw_events_off = 0; + spin_unlock_irqrestore(&ioc->fw_event_lock, flags); +} + +/** + * _scsih_ublock_io_device - set the device state to SDEV_RUNNING + * @ioc: per adapter object + * @handle: device handle + * + * During device pull we need to appropiately set the sdev state. + */ +static void +_scsih_ublock_io_device(struct MPT2SAS_ADAPTER *ioc, u16 handle) +{ + struct MPT2SAS_DEVICE *sas_device_priv_data; + struct scsi_device *sdev; + + shost_for_each_device(sdev, ioc->shost) { + sas_device_priv_data = sdev->hostdata; + if (!sas_device_priv_data) + continue; + if (!sas_device_priv_data->block) + continue; + if (sas_device_priv_data->sas_target->handle == handle) { + dewtprintk(ioc, sdev_printk(KERN_INFO, sdev, + MPT2SAS_INFO_FMT "SDEV_RUNNING: " + "handle(0x%04x)\n", ioc->name, handle)); + sas_device_priv_data->block = 0; + scsi_device_set_state(sdev, SDEV_RUNNING); + } + } +} + +/** + * _scsih_block_io_device - set the device state to SDEV_BLOCK + * @ioc: per adapter object + * @handle: device handle + * + * During device pull we need to appropiately set the sdev state. + */ +static void +_scsih_block_io_device(struct MPT2SAS_ADAPTER *ioc, u16 handle) +{ + struct MPT2SAS_DEVICE *sas_device_priv_data; + struct scsi_device *sdev; + + shost_for_each_device(sdev, ioc->shost) { + sas_device_priv_data = sdev->hostdata; + if (!sas_device_priv_data) + continue; + if (sas_device_priv_data->block) + continue; + if (sas_device_priv_data->sas_target->handle == handle) { + dewtprintk(ioc, sdev_printk(KERN_INFO, sdev, + MPT2SAS_INFO_FMT "SDEV_BLOCK: " + "handle(0x%04x)\n", ioc->name, handle)); + sas_device_priv_data->block = 1; + scsi_device_set_state(sdev, SDEV_BLOCK); + } + } +} + +/** + * _scsih_block_io_to_children_attached_to_ex + * @ioc: per adapter object + * @sas_expander: the sas_device object + * + * This routine set sdev state to SDEV_BLOCK for all devices + * attached to this expander. This function called when expander is + * pulled. + */ +static void +_scsih_block_io_to_children_attached_to_ex(struct MPT2SAS_ADAPTER *ioc, + struct _sas_node *sas_expander) +{ + struct _sas_port *mpt2sas_port; + struct _sas_device *sas_device; + struct _sas_node *expander_sibling; + unsigned long flags; + + if (!sas_expander) + return; + + list_for_each_entry(mpt2sas_port, + &sas_expander->sas_port_list, port_list) { + if (mpt2sas_port->remote_identify.device_type == + SAS_END_DEVICE) { + spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_device = + mpt2sas_scsih_sas_device_find_by_sas_address(ioc, + mpt2sas_port->remote_identify.sas_address); + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + if (!sas_device) + continue; + _scsih_block_io_device(ioc, sas_device->handle); + } + } + + list_for_each_entry(mpt2sas_port, + &sas_expander->sas_port_list, port_list) { + + if (mpt2sas_port->remote_identify.device_type == + MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER || + mpt2sas_port->remote_identify.device_type == + MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER) { + + spin_lock_irqsave(&ioc->sas_node_lock, flags); + expander_sibling = + mpt2sas_scsih_expander_find_by_sas_address( + ioc, mpt2sas_port->remote_identify.sas_address); + spin_unlock_irqrestore(&ioc->sas_node_lock, flags); + _scsih_block_io_to_children_attached_to_ex(ioc, + expander_sibling); + } + } +} + +/** + * _scsih_block_io_to_children_attached_directly + * @ioc: per adapter object + * @event_data: topology change event data + * + * This routine set sdev state to SDEV_BLOCK for all devices + * direct attached during device pull. + */ +static void +_scsih_block_io_to_children_attached_directly(struct MPT2SAS_ADAPTER *ioc, + Mpi2EventDataSasTopologyChangeList_t *event_data) +{ + int i; + u16 handle; + u16 reason_code; + u8 phy_number; + + for (i = 0; i < event_data->NumEntries; i++) { + handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle); + if (!handle) + continue; + phy_number = event_data->StartPhyNum + i; + reason_code = event_data->PHY[i].PhyStatus & + MPI2_EVENT_SAS_TOPO_RC_MASK; + if (reason_code == MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING) + _scsih_block_io_device(ioc, handle); + } +} + +/** + * _scsih_check_topo_delete_events - sanity check on topo events + * @ioc: per adapter object + * @event_data: the event data payload + * + * This routine added to better handle cable breaker. + * + * This handles the case where driver recieves multiple expander + * add and delete events in a single shot. When there is a delete event + * the routine will void any pending add events waiting in the event queue. + * + * Return nothing. + */ +static void +_scsih_check_topo_delete_events(struct MPT2SAS_ADAPTER *ioc, + Mpi2EventDataSasTopologyChangeList_t *event_data) +{ + struct fw_event_work *fw_event; + Mpi2EventDataSasTopologyChangeList_t *local_event_data; + u16 expander_handle; + struct _sas_node *sas_expander; + unsigned long flags; + + expander_handle = le16_to_cpu(event_data->ExpanderDevHandle); + if (expander_handle < ioc->sas_hba.num_phys) { + _scsih_block_io_to_children_attached_directly(ioc, event_data); + return; + } + + if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING + || event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING) { + spin_lock_irqsave(&ioc->sas_node_lock, flags); + sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc, + expander_handle); + spin_unlock_irqrestore(&ioc->sas_node_lock, flags); + _scsih_block_io_to_children_attached_to_ex(ioc, sas_expander); + } else if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_RESPONDING) + _scsih_block_io_to_children_attached_directly(ioc, event_data); + + if (event_data->ExpStatus != MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING) + return; + + /* mark ignore flag for pending events */ + spin_lock_irqsave(&ioc->fw_event_lock, flags); + list_for_each_entry(fw_event, &ioc->fw_event_list, list) { + if (fw_event->event != MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST || + fw_event->ignore) + continue; + local_event_data = fw_event->event_data; + if (local_event_data->ExpStatus == + MPI2_EVENT_SAS_TOPO_ES_ADDED || + local_event_data->ExpStatus == + MPI2_EVENT_SAS_TOPO_ES_RESPONDING) { + if (le16_to_cpu(local_event_data->ExpanderDevHandle) == + expander_handle) { + dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT + "setting ignoring flag\n", ioc->name)); + fw_event->ignore = 1; + } + } + } + spin_unlock_irqrestore(&ioc->fw_event_lock, flags); +} + +/** + * _scsih_queue_rescan - queue a topology rescan from user context + * @ioc: per adapter object + * + * Return nothing. + */ +static void +_scsih_queue_rescan(struct MPT2SAS_ADAPTER *ioc) +{ + struct fw_event_work *fw_event; + + if (ioc->wait_for_port_enable_to_complete) + return; + fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC); + if (!fw_event) + return; + fw_event->event = MPT2SAS_RESCAN_AFTER_HOST_RESET; + fw_event->ioc = ioc; + _scsih_fw_event_add(ioc, fw_event); +} + +/** + * _scsih_flush_running_cmds - completing outstanding commands. + * @ioc: per adapter object + * + * The flushing out of all pending scmd commands following host reset, + * where all IO is dropped to the floor. + * + * Return nothing. + */ +static void +_scsih_flush_running_cmds(struct MPT2SAS_ADAPTER *ioc) +{ + struct scsi_cmnd *scmd; + u16 smid; + u16 count = 0; + + for (smid = 1; smid <= ioc->request_depth; smid++) { + scmd = _scsih_scsi_lookup_getclear(ioc, smid); + if (!scmd) + continue; + count++; + mpt2sas_base_free_smid(ioc, smid); + scsi_dma_unmap(scmd); + scmd->result = DID_RESET << 16; + scmd->scsi_done(scmd); + } + dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "completing %d cmds\n", + ioc->name, count)); +} + +/** + * mpt2sas_scsih_reset_handler - reset callback handler (for scsih) + * @ioc: per adapter object + * @reset_phase: phase + * + * The handler for doing any required cleanup or initialization. + * + * The reset phase can be MPT2_IOC_PRE_RESET, MPT2_IOC_AFTER_RESET, + * MPT2_IOC_DONE_RESET + * + * Return nothing. + */ +void +mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase) +{ + switch (reset_phase) { + case MPT2_IOC_PRE_RESET: + dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " + "MPT2_IOC_PRE_RESET\n", ioc->name, __func__)); + _scsih_fw_event_off(ioc); + break; + case MPT2_IOC_AFTER_RESET: + dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " + "MPT2_IOC_AFTER_RESET\n", ioc->name, __func__)); + if (ioc->tm_cmds.status & MPT2_CMD_PENDING) { + ioc->tm_cmds.status |= MPT2_CMD_RESET; + mpt2sas_base_free_smid(ioc, ioc->tm_cmds.smid); + complete(&ioc->tm_cmds.done); + } + _scsih_fw_event_on(ioc); + _scsih_flush_running_cmds(ioc); + break; + case MPT2_IOC_DONE_RESET: + dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " + "MPT2_IOC_DONE_RESET\n", ioc->name, __func__)); + _scsih_queue_rescan(ioc); + break; + } +} + +/** + * scsih_qcmd - main scsi request entry point + * @scmd: pointer to scsi command object + * @done: function pointer to be invoked on completion + * + * The callback index is set inside `ioc->scsi_io_cb_idx`. + * + * Returns 0 on success. If there's a failure, return either: + * SCSI_MLQUEUE_DEVICE_BUSY if the device queue is full, or + * SCSI_MLQUEUE_HOST_BUSY if the entire host queue is full + */ +static int +scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *)) +{ + struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host); + struct MPT2SAS_DEVICE *sas_device_priv_data; + struct MPT2SAS_TARGET *sas_target_priv_data; + Mpi2SCSIIORequest_t *mpi_request; + u32 mpi_control; + u16 smid; + unsigned long flags; + + scmd->scsi_done = done; + sas_device_priv_data = scmd->device->hostdata; + if (!sas_device_priv_data) { + scmd->result = DID_NO_CONNECT << 16; + scmd->scsi_done(scmd); + return 0; + } + + sas_target_priv_data = sas_device_priv_data->sas_target; + if (!sas_target_priv_data || sas_target_priv_data->handle == + MPT2SAS_INVALID_DEVICE_HANDLE || sas_target_priv_data->deleted) { + scmd->result = DID_NO_CONNECT << 16; + scmd->scsi_done(scmd); + return 0; + } + + /* see if we are busy with task managment stuff */ + spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); + if (sas_target_priv_data->tm_busy || + ioc->shost_recovery || ioc->ioc_link_reset_in_progress) { + spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); + return SCSI_MLQUEUE_HOST_BUSY; + } + spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); + + if (scmd->sc_data_direction == DMA_FROM_DEVICE) + mpi_control = MPI2_SCSIIO_CONTROL_READ; + else if (scmd->sc_data_direction == DMA_TO_DEVICE) + mpi_control = MPI2_SCSIIO_CONTROL_WRITE; + else + mpi_control = MPI2_SCSIIO_CONTROL_NODATATRANSFER; + + /* set tags */ + if (!(sas_device_priv_data->flags & MPT_DEVICE_FLAGS_INIT)) { + if (scmd->device->tagged_supported) { + if (scmd->device->ordered_tags) + mpi_control |= MPI2_SCSIIO_CONTROL_ORDEREDQ; + else + mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ; + } else +/* MPI Revision I (UNIT = 0xA) - removed MPI2_SCSIIO_CONTROL_UNTAGGED */ +/* mpi_control |= MPI2_SCSIIO_CONTROL_UNTAGGED; + */ + mpi_control |= (0x500); + + } else + mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ; + + if ((sas_device_priv_data->flags & MPT_DEVICE_TLR_ON)) + mpi_control |= MPI2_SCSIIO_CONTROL_TLR_ON; + + smid = mpt2sas_base_get_smid(ioc, ioc->scsi_io_cb_idx); + if (!smid) { + printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", + ioc->name, __func__); + goto out; + } + mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); + memset(mpi_request, 0, sizeof(Mpi2SCSIIORequest_t)); + mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST; + if (sas_device_priv_data->sas_target->flags & + MPT_TARGET_FLAGS_RAID_COMPONENT) + mpi_request->Function = MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH; + else + mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST; + mpi_request->DevHandle = + cpu_to_le16(sas_device_priv_data->sas_target->handle); + mpi_request->DataLength = cpu_to_le32(scsi_bufflen(scmd)); + mpi_request->Control = cpu_to_le32(mpi_control); + mpi_request->IoFlags = cpu_to_le16(scmd->cmd_len); + mpi_request->MsgFlags = MPI2_SCSIIO_MSGFLAGS_SYSTEM_SENSE_ADDR; + mpi_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE; + mpi_request->SenseBufferLowAddress = + (u32)mpt2sas_base_get_sense_buffer_dma(ioc, smid); + mpi_request->SGLOffset0 = offsetof(Mpi2SCSIIORequest_t, SGL) / 4; + mpi_request->SGLFlags = cpu_to_le16(MPI2_SCSIIO_SGLFLAGS_TYPE_MPI + + MPI2_SCSIIO_SGLFLAGS_SYSTEM_ADDR); + + int_to_scsilun(sas_device_priv_data->lun, (struct scsi_lun *) + mpi_request->LUN); + memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len); + + if (!mpi_request->DataLength) { + mpt2sas_base_build_zero_len_sge(ioc, &mpi_request->SGL); + } else { + if (_scsih_build_scatter_gather(ioc, scmd, smid)) { + mpt2sas_base_free_smid(ioc, smid); + goto out; + } + } + + _scsih_scsi_lookup_set(ioc, smid, scmd); + mpt2sas_base_put_smid_scsi_io(ioc, smid, 0, + sas_device_priv_data->sas_target->handle); + return 0; + + out: + return SCSI_MLQUEUE_HOST_BUSY; +} + +/** + * _scsih_normalize_sense - normalize descriptor and fixed format sense data + * @sense_buffer: sense data returned by target + * @data: normalized skey/asc/ascq + * + * Return nothing. + */ +static void +_scsih_normalize_sense(char *sense_buffer, struct sense_info *data) +{ + if ((sense_buffer[0] & 0x7F) >= 0x72) { + /* descriptor format */ + data->skey = sense_buffer[1] & 0x0F; + data->asc = sense_buffer[2]; + data->ascq = sense_buffer[3]; + } else { + /* fixed format */ + data->skey = sense_buffer[2] & 0x0F; + data->asc = sense_buffer[12]; + data->ascq = sense_buffer[13]; + } +} + +#ifdef CONFIG_SCSI_MPT2SAS_LOGGING +/** + * _scsih_scsi_ioc_info - translated non-succesfull SCSI_IO request + * @ioc: per adapter object + * @scmd: pointer to scsi command object + * @mpi_reply: reply mf payload returned from firmware + * + * scsi_status - SCSI Status code returned from target device + * scsi_state - state info associated with SCSI_IO determined by ioc + * ioc_status - ioc supplied status info + * + * Return nothing. + */ +static void +_scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, + Mpi2SCSIIOReply_t *mpi_reply, u16 smid) +{ + u32 response_info; + u8 *response_bytes; + u16 ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & + MPI2_IOCSTATUS_MASK; + u8 scsi_state = mpi_reply->SCSIState; + u8 scsi_status = mpi_reply->SCSIStatus; + char *desc_ioc_state = NULL; + char *desc_scsi_status = NULL; + char *desc_scsi_state = ioc->tmp_string; + + switch (ioc_status) { + case MPI2_IOCSTATUS_SUCCESS: + desc_ioc_state = "success"; + break; + case MPI2_IOCSTATUS_INVALID_FUNCTION: + desc_ioc_state = "invalid function"; + break; + case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR: + desc_ioc_state = "scsi recovered error"; + break; + case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE: + desc_ioc_state = "scsi invalid dev handle"; + break; + case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE: + desc_ioc_state = "scsi device not there"; + break; + case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN: + desc_ioc_state = "scsi data overrun"; + break; + case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN: + desc_ioc_state = "scsi data underrun"; + break; + case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR: + desc_ioc_state = "scsi io data error"; + break; + case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR: + desc_ioc_state = "scsi protocol error"; + break; + case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED: + desc_ioc_state = "scsi task terminated"; + break; + case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: + desc_ioc_state = "scsi residual mismatch"; + break; + case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED: + desc_ioc_state = "scsi task mgmt failed"; + break; + case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED: + desc_ioc_state = "scsi ioc terminated"; + break; + case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED: + desc_ioc_state = "scsi ext terminated"; + break; + default: + desc_ioc_state = "unknown"; + break; + } + + switch (scsi_status) { + case MPI2_SCSI_STATUS_GOOD: + desc_scsi_status = "good"; + break; + case MPI2_SCSI_STATUS_CHECK_CONDITION: + desc_scsi_status = "check condition"; + break; + case MPI2_SCSI_STATUS_CONDITION_MET: + desc_scsi_status = "condition met"; + break; + case MPI2_SCSI_STATUS_BUSY: + desc_scsi_status = "busy"; + break; + case MPI2_SCSI_STATUS_INTERMEDIATE: + desc_scsi_status = "intermediate"; + break; + case MPI2_SCSI_STATUS_INTERMEDIATE_CONDMET: + desc_scsi_status = "intermediate condmet"; + break; + case MPI2_SCSI_STATUS_RESERVATION_CONFLICT: + desc_scsi_status = "reservation conflict"; + break; + case MPI2_SCSI_STATUS_COMMAND_TERMINATED: + desc_scsi_status = "command terminated"; + break; + case MPI2_SCSI_STATUS_TASK_SET_FULL: + desc_scsi_status = "task set full"; + break; + case MPI2_SCSI_STATUS_ACA_ACTIVE: + desc_scsi_status = "aca active"; + break; + case MPI2_SCSI_STATUS_TASK_ABORTED: + desc_scsi_status = "task aborted"; + break; + default: + desc_scsi_status = "unknown"; + break; + } + + desc_scsi_state[0] = '\0'; + if (!scsi_state) + desc_scsi_state = " "; + if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) + strcat(desc_scsi_state, "response info "); + if (scsi_state & MPI2_SCSI_STATE_TERMINATED) + strcat(desc_scsi_state, "state terminated "); + if (scsi_state & MPI2_SCSI_STATE_NO_SCSI_STATUS) + strcat(desc_scsi_state, "no status "); + if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_FAILED) + strcat(desc_scsi_state, "autosense failed "); + if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) + strcat(desc_scsi_state, "autosense valid "); + + scsi_print_command(scmd); + printk(MPT2SAS_WARN_FMT "\tdev handle(0x%04x), " + "ioc_status(%s)(0x%04x), smid(%d)\n", ioc->name, + le16_to_cpu(mpi_reply->DevHandle), desc_ioc_state, + ioc_status, smid); + printk(MPT2SAS_WARN_FMT "\trequest_len(%d), underflow(%d), " + "resid(%d)\n", ioc->name, scsi_bufflen(scmd), scmd->underflow, + scsi_get_resid(scmd)); + printk(MPT2SAS_WARN_FMT "\ttag(%d), transfer_count(%d), " + "sc->result(0x%08x)\n", ioc->name, le16_to_cpu(mpi_reply->TaskTag), + le32_to_cpu(mpi_reply->TransferCount), scmd->result); + printk(MPT2SAS_WARN_FMT "\tscsi_status(%s)(0x%02x), " + "scsi_state(%s)(0x%02x)\n", ioc->name, desc_scsi_status, + scsi_status, desc_scsi_state, scsi_state); + + if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) { + struct sense_info data; + _scsih_normalize_sense(scmd->sense_buffer, &data); + printk(MPT2SAS_WARN_FMT "\t[sense_key,asc,ascq]: " + "[0x%02x,0x%02x,0x%02x]\n", ioc->name, data.skey, + data.asc, data.ascq); + } + + if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) { + response_info = le32_to_cpu(mpi_reply->ResponseInfo); + response_bytes = (u8 *)&response_info; + _scsih_response_code(ioc, response_bytes[3]); + } +} +#endif + +/** + * _scsih_smart_predicted_fault - illuminate Fault LED + * @ioc: per adapter object + * @handle: device handle + * + * Return nothing. + */ +static void +_scsih_smart_predicted_fault(struct MPT2SAS_ADAPTER *ioc, u16 handle) +{ + Mpi2SepReply_t mpi_reply; + Mpi2SepRequest_t mpi_request; + struct scsi_target *starget; + struct MPT2SAS_TARGET *sas_target_priv_data; + Mpi2EventNotificationReply_t *event_reply; + Mpi2EventDataSasDeviceStatusChange_t *event_data; + struct _sas_device *sas_device; + ssize_t sz; + unsigned long flags; + + /* only handle non-raid devices */ + spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_device = _scsih_sas_device_find_by_handle(ioc, handle); + if (!sas_device) { + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + return; + } + starget = sas_device->starget; + sas_target_priv_data = starget->hostdata; + + if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) || + ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME))) { + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + return; + } + starget_printk(KERN_WARNING, starget, "predicted fault\n"); + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + + if (ioc->pdev->subsystem_vendor == PCI_VENDOR_ID_IBM) { + memset(&mpi_request, 0, sizeof(Mpi2SepRequest_t)); + mpi_request.Function = MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR; + mpi_request.Action = MPI2_SEP_REQ_ACTION_WRITE_STATUS; + mpi_request.SlotStatus = + MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT; + mpi_request.DevHandle = cpu_to_le16(handle); + mpi_request.Flags = MPI2_SEP_REQ_FLAGS_DEVHANDLE_ADDRESS; + if ((mpt2sas_base_scsi_enclosure_processor(ioc, &mpi_reply, + &mpi_request)) != 0) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + return; + } + + if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo) { + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT + "enclosure_processor: ioc_status (0x%04x), " + "loginfo(0x%08x)\n", ioc->name, + le16_to_cpu(mpi_reply.IOCStatus), + le32_to_cpu(mpi_reply.IOCLogInfo))); + return; + } + } + + /* insert into event log */ + sz = offsetof(Mpi2EventNotificationReply_t, EventData) + + sizeof(Mpi2EventDataSasDeviceStatusChange_t); + event_reply = kzalloc(sz, GFP_KERNEL); + if (!event_reply) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + return; + } + + event_reply->Function = MPI2_FUNCTION_EVENT_NOTIFICATION; + event_reply->Event = + cpu_to_le16(MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE); + event_reply->MsgLength = sz/4; + event_reply->EventDataLength = + cpu_to_le16(sizeof(Mpi2EventDataSasDeviceStatusChange_t)/4); + event_data = (Mpi2EventDataSasDeviceStatusChange_t *) + event_reply->EventData; + event_data->ReasonCode = MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA; + event_data->ASC = 0x5D; + event_data->DevHandle = cpu_to_le16(handle); + event_data->SASAddress = cpu_to_le64(sas_target_priv_data->sas_address); + mpt2sas_ctl_add_to_event_log(ioc, event_reply); + kfree(event_reply); +} + +/** + * scsih_io_done - scsi request callback + * @ioc: per adapter object + * @smid: system request message index + * @VF_ID: virtual function id + * @reply: reply message frame(lower 32bit addr) + * + * Callback handler when using scsih_qcmd. + * + * Return nothing. + */ +static void +scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply) +{ + Mpi2SCSIIORequest_t *mpi_request; + Mpi2SCSIIOReply_t *mpi_reply; + struct scsi_cmnd *scmd; + u16 ioc_status; + u32 xfer_cnt; + u8 scsi_state; + u8 scsi_status; + u32 log_info; + struct MPT2SAS_DEVICE *sas_device_priv_data; + u32 response_code; + + mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); + scmd = _scsih_scsi_lookup_getclear(ioc, smid); + if (scmd == NULL) + return; + + mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); + + if (mpi_reply == NULL) { + scmd->result = DID_OK << 16; + goto out; + } + + sas_device_priv_data = scmd->device->hostdata; + if (!sas_device_priv_data || !sas_device_priv_data->sas_target || + sas_device_priv_data->sas_target->deleted) { + scmd->result = DID_NO_CONNECT << 16; + goto out; + } + + /* turning off TLR */ + if (!sas_device_priv_data->tlr_snoop_check) { + sas_device_priv_data->tlr_snoop_check++; + if (sas_device_priv_data->flags & MPT_DEVICE_TLR_ON) { + response_code = (le32_to_cpu(mpi_reply->ResponseInfo) + >> 24); + if (response_code == + MPI2_SCSITASKMGMT_RSP_INVALID_FRAME) + sas_device_priv_data->flags &= + ~MPT_DEVICE_TLR_ON; + } + } + + xfer_cnt = le32_to_cpu(mpi_reply->TransferCount); + scsi_set_resid(scmd, scsi_bufflen(scmd) - xfer_cnt); + ioc_status = le16_to_cpu(mpi_reply->IOCStatus); + if (ioc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) + log_info = le32_to_cpu(mpi_reply->IOCLogInfo); + else + log_info = 0; + ioc_status &= MPI2_IOCSTATUS_MASK; + scsi_state = mpi_reply->SCSIState; + scsi_status = mpi_reply->SCSIStatus; + + if (ioc_status == MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 && + (scsi_status == MPI2_SCSI_STATUS_BUSY || + scsi_status == MPI2_SCSI_STATUS_RESERVATION_CONFLICT || + scsi_status == MPI2_SCSI_STATUS_TASK_SET_FULL)) { + ioc_status = MPI2_IOCSTATUS_SUCCESS; + } + + if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) { + struct sense_info data; + const void *sense_data = mpt2sas_base_get_sense_buffer(ioc, + smid); + memcpy(scmd->sense_buffer, sense_data, + le32_to_cpu(mpi_reply->SenseCount)); + _scsih_normalize_sense(scmd->sense_buffer, &data); + /* failure prediction threshold exceeded */ + if (data.asc == 0x5D) + _scsih_smart_predicted_fault(ioc, + le16_to_cpu(mpi_reply->DevHandle)); + } + + switch (ioc_status) { + case MPI2_IOCSTATUS_BUSY: + case MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES: + scmd->result = SAM_STAT_BUSY; + break; + + case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE: + scmd->result = DID_NO_CONNECT << 16; + break; + + case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED: + if (sas_device_priv_data->block) { + scmd->result = (DID_BUS_BUSY << 16); + break; + } + + case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED: + case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED: + scmd->result = DID_RESET << 16; + break; + + case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: + if ((xfer_cnt == 0) || (scmd->underflow > xfer_cnt)) + scmd->result = DID_SOFT_ERROR << 16; + else + scmd->result = (DID_OK << 16) | scsi_status; + break; + + case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN: + scmd->result = (DID_OK << 16) | scsi_status; + + if ((scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID)) + break; + + if (xfer_cnt < scmd->underflow) { + if (scsi_status == SAM_STAT_BUSY) + scmd->result = SAM_STAT_BUSY; + else + scmd->result = DID_SOFT_ERROR << 16; + } else if (scsi_state & (MPI2_SCSI_STATE_AUTOSENSE_FAILED | + MPI2_SCSI_STATE_NO_SCSI_STATUS)) + scmd->result = DID_SOFT_ERROR << 16; + else if (scsi_state & MPI2_SCSI_STATE_TERMINATED) + scmd->result = DID_RESET << 16; + else if (!xfer_cnt && scmd->cmnd[0] == REPORT_LUNS) { + mpi_reply->SCSIState = MPI2_SCSI_STATE_AUTOSENSE_VALID; + mpi_reply->SCSIStatus = SAM_STAT_CHECK_CONDITION; + scmd->result = (DRIVER_SENSE << 24) | + SAM_STAT_CHECK_CONDITION; + scmd->sense_buffer[0] = 0x70; + scmd->sense_buffer[2] = ILLEGAL_REQUEST; + scmd->sense_buffer[12] = 0x20; + scmd->sense_buffer[13] = 0; + } + break; + + case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN: + scsi_set_resid(scmd, 0); + case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR: + case MPI2_IOCSTATUS_SUCCESS: + scmd->result = (DID_OK << 16) | scsi_status; + if (scsi_state & (MPI2_SCSI_STATE_AUTOSENSE_FAILED | + MPI2_SCSI_STATE_NO_SCSI_STATUS)) + scmd->result = DID_SOFT_ERROR << 16; + else if (scsi_state & MPI2_SCSI_STATE_TERMINATED) + scmd->result = DID_RESET << 16; + break; + + case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR: + case MPI2_IOCSTATUS_INVALID_FUNCTION: + case MPI2_IOCSTATUS_INVALID_SGL: + case MPI2_IOCSTATUS_INTERNAL_ERROR: + case MPI2_IOCSTATUS_INVALID_FIELD: + case MPI2_IOCSTATUS_INVALID_STATE: + case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR: + case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED: + default: + scmd->result = DID_SOFT_ERROR << 16; + break; + + } + +#ifdef CONFIG_SCSI_MPT2SAS_LOGGING + if (scmd->result && (ioc->logging_level & MPT_DEBUG_REPLY)) + _scsih_scsi_ioc_info(ioc , scmd, mpi_reply, smid); +#endif + + out: + scsi_dma_unmap(scmd); + scmd->scsi_done(scmd); +} + +/** + * _scsih_link_change - process phy link changes + * @ioc: per adapter object + * @handle: phy handle + * @attached_handle: valid for devices attached to link + * @phy_number: phy number + * @link_rate: new link rate + * Context: user. + * + * Return nothing. + */ +static void +_scsih_link_change(struct MPT2SAS_ADAPTER *ioc, u16 handle, u16 attached_handle, + u8 phy_number, u8 link_rate) +{ + mpt2sas_transport_update_phy_link_change(ioc, handle, attached_handle, + phy_number, link_rate); +} + +/** + * _scsih_sas_host_refresh - refreshing sas host object contents + * @ioc: per adapter object + * @update: update link information + * Context: user + * + * During port enable, fw will send topology events for every device. Its + * possible that the handles may change from the previous setting, so this + * code keeping handles updating if changed. + * + * Return nothing. + */ +static void +_scsih_sas_host_refresh(struct MPT2SAS_ADAPTER *ioc, u8 update) +{ + u16 sz; + u16 ioc_status; + int i; + Mpi2ConfigReply_t mpi_reply; + Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL; + + dtmprintk(ioc, printk(MPT2SAS_INFO_FMT + "updating handles for sas_host(0x%016llx)\n", + ioc->name, (unsigned long long)ioc->sas_hba.sas_address)); + + sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys + * sizeof(Mpi2SasIOUnit0PhyData_t)); + sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL); + if (!sas_iounit_pg0) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + return; + } + if (!(mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply, + sas_iounit_pg0, sz))) { + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) + goto out; + for (i = 0; i < ioc->sas_hba.num_phys ; i++) { + ioc->sas_hba.phy[i].handle = + le16_to_cpu(sas_iounit_pg0->PhyData[i]. + ControllerDevHandle); + if (update) + _scsih_link_change(ioc, + ioc->sas_hba.phy[i].handle, + le16_to_cpu(sas_iounit_pg0->PhyData[i]. + AttachedDevHandle), i, + sas_iounit_pg0->PhyData[i]. + NegotiatedLinkRate >> 4); + } + } + + out: + kfree(sas_iounit_pg0); +} + +/** + * _scsih_sas_host_add - create sas host object + * @ioc: per adapter object + * + * Creating host side data object, stored in ioc->sas_hba + * + * Return nothing. + */ +static void +_scsih_sas_host_add(struct MPT2SAS_ADAPTER *ioc) +{ + int i; + Mpi2ConfigReply_t mpi_reply; + Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL; + Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL; + Mpi2SasPhyPage0_t phy_pg0; + Mpi2SasDevicePage0_t sas_device_pg0; + Mpi2SasEnclosurePage0_t enclosure_pg0; + u16 ioc_status; + u16 sz; + u16 device_missing_delay; + + mpt2sas_config_get_number_hba_phys(ioc, &ioc->sas_hba.num_phys); + if (!ioc->sas_hba.num_phys) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + return; + } + + /* sas_iounit page 0 */ + sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys * + sizeof(Mpi2SasIOUnit0PhyData_t)); + sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL); + if (!sas_iounit_pg0) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + return; + } + if ((mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply, + sas_iounit_pg0, sz))) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + goto out; + } + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + goto out; + } + + /* sas_iounit page 1 */ + sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys * + sizeof(Mpi2SasIOUnit1PhyData_t)); + sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL); + if (!sas_iounit_pg1) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + goto out; + } + if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply, + sas_iounit_pg1, sz))) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + goto out; + } + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + goto out; + } + + ioc->io_missing_delay = + le16_to_cpu(sas_iounit_pg1->IODeviceMissingDelay); + device_missing_delay = + le16_to_cpu(sas_iounit_pg1->ReportDeviceMissingDelay); + if (device_missing_delay & MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16) + ioc->device_missing_delay = (device_missing_delay & + MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16; + else + ioc->device_missing_delay = device_missing_delay & + MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK; + + ioc->sas_hba.parent_dev = &ioc->shost->shost_gendev; + ioc->sas_hba.phy = kcalloc(ioc->sas_hba.num_phys, + sizeof(struct _sas_phy), GFP_KERNEL); + if (!ioc->sas_hba.phy) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + goto out; + } + for (i = 0; i < ioc->sas_hba.num_phys ; i++) { + if ((mpt2sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0, + i))) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + goto out; + } + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + goto out; + } + ioc->sas_hba.phy[i].handle = + le16_to_cpu(sas_iounit_pg0->PhyData[i].ControllerDevHandle); + ioc->sas_hba.phy[i].phy_id = i; + mpt2sas_transport_add_host_phy(ioc, &ioc->sas_hba.phy[i], + phy_pg0, ioc->sas_hba.parent_dev); + } + if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, + MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, ioc->sas_hba.phy[0].handle))) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + goto out; + } + ioc->sas_hba.handle = le16_to_cpu(sas_device_pg0.DevHandle); + ioc->sas_hba.enclosure_handle = + le16_to_cpu(sas_device_pg0.EnclosureHandle); + ioc->sas_hba.sas_address = le64_to_cpu(sas_device_pg0.SASAddress); + printk(MPT2SAS_INFO_FMT "host_add: handle(0x%04x), " + "sas_addr(0x%016llx), phys(%d)\n", ioc->name, ioc->sas_hba.handle, + (unsigned long long) ioc->sas_hba.sas_address, + ioc->sas_hba.num_phys) ; + + if (ioc->sas_hba.enclosure_handle) { + if (!(mpt2sas_config_get_enclosure_pg0(ioc, &mpi_reply, + &enclosure_pg0, + MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE, + ioc->sas_hba.enclosure_handle))) { + ioc->sas_hba.enclosure_logical_id = + le64_to_cpu(enclosure_pg0.EnclosureLogicalID); + } + } + + out: + kfree(sas_iounit_pg1); + kfree(sas_iounit_pg0); +} + +/** + * _scsih_expander_add - creating expander object + * @ioc: per adapter object + * @handle: expander handle + * + * Creating expander object, stored in ioc->sas_expander_list. + * + * Return 0 for success, else error. + */ +static int +_scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle) +{ + struct _sas_node *sas_expander; + Mpi2ConfigReply_t mpi_reply; + Mpi2ExpanderPage0_t expander_pg0; + Mpi2ExpanderPage1_t expander_pg1; + Mpi2SasEnclosurePage0_t enclosure_pg0; + u32 ioc_status; + u16 parent_handle; + __le64 sas_address; + int i; + unsigned long flags; + struct _sas_port *mpt2sas_port; + int rc = 0; + + if (!handle) + return -1; + + if ((mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0, + MPI2_SAS_EXPAND_PGAD_FORM_HNDL, handle))) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + return -1; + } + + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + return -1; + } + + /* handle out of order topology events */ + parent_handle = le16_to_cpu(expander_pg0.ParentDevHandle); + if (parent_handle >= ioc->sas_hba.num_phys) { + spin_lock_irqsave(&ioc->sas_node_lock, flags); + sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc, + parent_handle); + spin_unlock_irqrestore(&ioc->sas_node_lock, flags); + if (!sas_expander) { + rc = _scsih_expander_add(ioc, parent_handle); + if (rc != 0) + return rc; + } + } + + sas_address = le64_to_cpu(expander_pg0.SASAddress); + + spin_lock_irqsave(&ioc->sas_node_lock, flags); + sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc, + sas_address); + spin_unlock_irqrestore(&ioc->sas_node_lock, flags); + + if (sas_expander) + return 0; + + sas_expander = kzalloc(sizeof(struct _sas_node), + GFP_KERNEL); + if (!sas_expander) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + return -1; + } + + sas_expander->handle = handle; + sas_expander->num_phys = expander_pg0.NumPhys; + sas_expander->parent_handle = parent_handle; + sas_expander->enclosure_handle = + le16_to_cpu(expander_pg0.EnclosureHandle); + sas_expander->sas_address = sas_address; + + printk(MPT2SAS_INFO_FMT "expander_add: handle(0x%04x)," + " parent(0x%04x), sas_addr(0x%016llx), phys(%d)\n", ioc->name, + handle, sas_expander->parent_handle, (unsigned long long) + sas_expander->sas_address, sas_expander->num_phys); + + if (!sas_expander->num_phys) + goto out_fail; + sas_expander->phy = kcalloc(sas_expander->num_phys, + sizeof(struct _sas_phy), GFP_KERNEL); + if (!sas_expander->phy) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + rc = -1; + goto out_fail; + } + + INIT_LIST_HEAD(&sas_expander->sas_port_list); + mpt2sas_port = mpt2sas_transport_port_add(ioc, handle, + sas_expander->parent_handle); + if (!mpt2sas_port) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + rc = -1; + goto out_fail; + } + sas_expander->parent_dev = &mpt2sas_port->rphy->dev; + + for (i = 0 ; i < sas_expander->num_phys ; i++) { + if ((mpt2sas_config_get_expander_pg1(ioc, &mpi_reply, + &expander_pg1, i, handle))) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + continue; + } + sas_expander->phy[i].handle = handle; + sas_expander->phy[i].phy_id = i; + mpt2sas_transport_add_expander_phy(ioc, &sas_expander->phy[i], + expander_pg1, sas_expander->parent_dev); + } + + if (sas_expander->enclosure_handle) { + if (!(mpt2sas_config_get_enclosure_pg0(ioc, &mpi_reply, + &enclosure_pg0, MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE, + sas_expander->enclosure_handle))) { + sas_expander->enclosure_logical_id = + le64_to_cpu(enclosure_pg0.EnclosureLogicalID); + } + } + + _scsih_expander_node_add(ioc, sas_expander); + return 0; + + out_fail: + + if (sas_expander) + kfree(sas_expander->phy); + kfree(sas_expander); + return rc; +} + +/** + * _scsih_expander_remove - removing expander object + * @ioc: per adapter object + * @handle: expander handle + * + * Return nothing. + */ +static void +_scsih_expander_remove(struct MPT2SAS_ADAPTER *ioc, u16 handle) +{ + struct _sas_node *sas_expander; + unsigned long flags; + + spin_lock_irqsave(&ioc->sas_node_lock, flags); + sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc, handle); + spin_unlock_irqrestore(&ioc->sas_node_lock, flags); + _scsih_expander_node_remove(ioc, sas_expander); +} + +/** + * _scsih_add_device - creating sas device object + * @ioc: per adapter object + * @handle: sas device handle + * @phy_num: phy number end device attached to + * @is_pd: is this hidden raid component + * + * Creating end device object, stored in ioc->sas_device_list. + * + * Returns 0 for success, non-zero for failure. + */ +static int +_scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd) +{ + Mpi2ConfigReply_t mpi_reply; + Mpi2SasDevicePage0_t sas_device_pg0; + Mpi2SasEnclosurePage0_t enclosure_pg0; + struct _sas_device *sas_device; + u32 ioc_status; + __le64 sas_address; + u32 device_info; + unsigned long flags; + + if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, + MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + return -1; + } + + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + return -1; + } + + /* check if device is present */ + if (!(le16_to_cpu(sas_device_pg0.Flags) & + MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + printk(MPT2SAS_ERR_FMT "Flags = 0x%04x\n", + ioc->name, le16_to_cpu(sas_device_pg0.Flags)); + return -1; + } + + /* check if there were any issus with discovery */ + if (sas_device_pg0.AccessStatus == + MPI2_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + printk(MPT2SAS_ERR_FMT "AccessStatus = 0x%02x\n", + ioc->name, sas_device_pg0.AccessStatus); + return -1; + } + + /* check if this is end device */ + device_info = le32_to_cpu(sas_device_pg0.DeviceInfo); + if (!(_scsih_is_end_device(device_info))) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + return -1; + } + + sas_address = le64_to_cpu(sas_device_pg0.SASAddress); + + spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, + sas_address); + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + + if (sas_device) { + _scsih_ublock_io_device(ioc, handle); + return 0; + } + + sas_device = kzalloc(sizeof(struct _sas_device), + GFP_KERNEL); + if (!sas_device) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + return -1; + } + + sas_device->handle = handle; + sas_device->parent_handle = + le16_to_cpu(sas_device_pg0.ParentDevHandle); + sas_device->enclosure_handle = + le16_to_cpu(sas_device_pg0.EnclosureHandle); + sas_device->slot = + le16_to_cpu(sas_device_pg0.Slot); + sas_device->device_info = device_info; + sas_device->sas_address = sas_address; + sas_device->hidden_raid_component = is_pd; + + /* get enclosure_logical_id */ + if (!(mpt2sas_config_get_enclosure_pg0(ioc, &mpi_reply, &enclosure_pg0, + MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE, + sas_device->enclosure_handle))) { + sas_device->enclosure_logical_id = + le64_to_cpu(enclosure_pg0.EnclosureLogicalID); + } + + /* get device name */ + sas_device->device_name = le64_to_cpu(sas_device_pg0.DeviceName); + + if (ioc->wait_for_port_enable_to_complete) + _scsih_sas_device_init_add(ioc, sas_device); + else + _scsih_sas_device_add(ioc, sas_device); + + return 0; +} + +/** + * _scsih_remove_device - removing sas device object + * @ioc: per adapter object + * @handle: sas device handle + * + * Return nothing. + */ +static void +_scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, u16 handle) +{ + struct MPT2SAS_TARGET *sas_target_priv_data; + struct _sas_device *sas_device; + unsigned long flags; + Mpi2SasIoUnitControlReply_t mpi_reply; + Mpi2SasIoUnitControlRequest_t mpi_request; + u16 device_handle; + + /* lookup sas_device */ + spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_device = _scsih_sas_device_find_by_handle(ioc, handle); + if (!sas_device) { + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + return; + } + + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: handle" + "(0x%04x)\n", ioc->name, __func__, handle)); + + if (sas_device->starget && sas_device->starget->hostdata) { + sas_target_priv_data = sas_device->starget->hostdata; + sas_target_priv_data->deleted = 1; + } + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + + if (ioc->remove_host) + goto out; + + /* Target Reset to flush out all the outstanding IO */ + device_handle = (sas_device->hidden_raid_component) ? + sas_device->volume_handle : handle; + if (device_handle) { + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset: " + "handle(0x%04x)\n", ioc->name, device_handle)); + mutex_lock(&ioc->tm_cmds.mutex); + mpt2sas_scsih_issue_tm(ioc, device_handle, 0, + MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 10); + ioc->tm_cmds.status = MPT2_CMD_NOT_USED; + mutex_unlock(&ioc->tm_cmds.mutex); + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset " + "done: handle(0x%04x)\n", ioc->name, device_handle)); + } + + /* SAS_IO_UNIT_CNTR - send REMOVE_DEVICE */ + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sas_iounit: handle" + "(0x%04x)\n", ioc->name, handle)); + memset(&mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t)); + mpi_request.Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL; + mpi_request.Operation = MPI2_SAS_OP_REMOVE_DEVICE; + mpi_request.DevHandle = handle; + mpi_request.VF_ID = 0; + if ((mpt2sas_base_sas_iounit_control(ioc, &mpi_reply, + &mpi_request)) != 0) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + } + + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sas_iounit: ioc_status" + "(0x%04x), loginfo(0x%08x)\n", ioc->name, + le16_to_cpu(mpi_reply.IOCStatus), + le32_to_cpu(mpi_reply.IOCLogInfo))); + + out: + mpt2sas_transport_port_remove(ioc, sas_device->sas_address, + sas_device->parent_handle); + + printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), sas_addr" + "(0x%016llx)\n", ioc->name, sas_device->handle, + (unsigned long long) sas_device->sas_address); + _scsih_sas_device_remove(ioc, sas_device); + + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit: handle" + "(0x%04x)\n", ioc->name, __func__, handle)); +} + +#ifdef CONFIG_SCSI_MPT2SAS_LOGGING +/** + * _scsih_sas_topology_change_event_debug - debug for topology event + * @ioc: per adapter object + * @event_data: event data payload + * Context: user. + */ +static void +_scsih_sas_topology_change_event_debug(struct MPT2SAS_ADAPTER *ioc, + Mpi2EventDataSasTopologyChangeList_t *event_data) +{ + int i; + u16 handle; + u16 reason_code; + u8 phy_number; + char *status_str = NULL; + char link_rate[25]; + + switch (event_data->ExpStatus) { + case MPI2_EVENT_SAS_TOPO_ES_ADDED: + status_str = "add"; + break; + case MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING: + status_str = "remove"; + break; + case MPI2_EVENT_SAS_TOPO_ES_RESPONDING: + status_str = "responding"; + break; + case MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING: + status_str = "remove delay"; + break; + default: + status_str = "unknown status"; + break; + } + printk(MPT2SAS_DEBUG_FMT "sas topology change: (%s)\n", + ioc->name, status_str); + printk(KERN_DEBUG "\thandle(0x%04x), enclosure_handle(0x%04x) " + "start_phy(%02d), count(%d)\n", + le16_to_cpu(event_data->ExpanderDevHandle), + le16_to_cpu(event_data->EnclosureHandle), + event_data->StartPhyNum, event_data->NumEntries); + for (i = 0; i < event_data->NumEntries; i++) { + handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle); + if (!handle) + continue; + phy_number = event_data->StartPhyNum + i; + reason_code = event_data->PHY[i].PhyStatus & + MPI2_EVENT_SAS_TOPO_RC_MASK; + switch (reason_code) { + case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED: + snprintf(link_rate, 25, ": add, link(0x%02x)", + (event_data->PHY[i].LinkRate >> 4)); + status_str = link_rate; + break; + case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING: + status_str = ": remove"; + break; + case MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING: + status_str = ": remove_delay"; + break; + case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED: + snprintf(link_rate, 25, ": link(0x%02x)", + (event_data->PHY[i].LinkRate >> 4)); + status_str = link_rate; + break; + case MPI2_EVENT_SAS_TOPO_RC_NO_CHANGE: + status_str = ": responding"; + break; + default: + status_str = ": unknown"; + break; + } + printk(KERN_DEBUG "\tphy(%02d), attached_handle(0x%04x)%s\n", + phy_number, handle, status_str); + } +} +#endif + +/** + * _scsih_sas_topology_change_event - handle topology changes + * @ioc: per adapter object + * @VF_ID: + * @event_data: event data payload + * fw_event: + * Context: user. + * + */ +static void +_scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, + Mpi2EventDataSasTopologyChangeList_t *event_data, + struct fw_event_work *fw_event) +{ + int i; + u16 parent_handle, handle; + u16 reason_code; + u8 phy_number; + struct _sas_node *sas_expander; + unsigned long flags; + u8 link_rate_; + +#ifdef CONFIG_SCSI_MPT2SAS_LOGGING + if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) + _scsih_sas_topology_change_event_debug(ioc, event_data); +#endif + + if (!ioc->sas_hba.num_phys) + _scsih_sas_host_add(ioc); + else + _scsih_sas_host_refresh(ioc, 0); + + if (fw_event->ignore) { + dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "ignoring expander " + "event\n", ioc->name)); + return; + } + + parent_handle = le16_to_cpu(event_data->ExpanderDevHandle); + + /* handle expander add */ + if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_ADDED) + if (_scsih_expander_add(ioc, parent_handle) != 0) + return; + + /* handle siblings events */ + for (i = 0; i < event_data->NumEntries; i++) { + if (fw_event->ignore) { + dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "ignoring " + "expander event\n", ioc->name)); + return; + } + if (event_data->PHY[i].PhyStatus & + MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT) + continue; + handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle); + if (!handle) + continue; + phy_number = event_data->StartPhyNum + i; + reason_code = event_data->PHY[i].PhyStatus & + MPI2_EVENT_SAS_TOPO_RC_MASK; + link_rate_ = event_data->PHY[i].LinkRate >> 4; + switch (reason_code) { + case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED: + case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED: + if (!parent_handle) { + if (phy_number < ioc->sas_hba.num_phys) + _scsih_link_change(ioc, + ioc->sas_hba.phy[phy_number].handle, + handle, phy_number, link_rate_); + } else { + spin_lock_irqsave(&ioc->sas_node_lock, flags); + sas_expander = + mpt2sas_scsih_expander_find_by_handle(ioc, + parent_handle); + spin_unlock_irqrestore(&ioc->sas_node_lock, + flags); + if (sas_expander) { + if (phy_number < sas_expander->num_phys) + _scsih_link_change(ioc, + sas_expander-> + phy[phy_number].handle, + handle, phy_number, + link_rate_); + } + } + if (reason_code == MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED) { + if (link_rate_ >= MPI2_SAS_NEG_LINK_RATE_1_5) + _scsih_ublock_io_device(ioc, handle); + } + if (reason_code == MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED) { + if (link_rate_ < MPI2_SAS_NEG_LINK_RATE_1_5) + break; + _scsih_add_device(ioc, handle, phy_number, 0); + } + break; + case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING: + _scsih_remove_device(ioc, handle); + break; + } + } + + /* handle expander removal */ + if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING) + _scsih_expander_remove(ioc, parent_handle); + +} + +#ifdef CONFIG_SCSI_MPT2SAS_LOGGING +/** + * _scsih_sas_device_status_change_event_debug - debug for device event + * @event_data: event data payload + * Context: user. + * + * Return nothing. + */ +static void +_scsih_sas_device_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc, + Mpi2EventDataSasDeviceStatusChange_t *event_data) +{ + char *reason_str = NULL; + + switch (event_data->ReasonCode) { + case MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA: + reason_str = "smart data"; + break; + case MPI2_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED: + reason_str = "unsupported device discovered"; + break; + case MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET: + reason_str = "internal device reset"; + break; + case MPI2_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL: + reason_str = "internal task abort"; + break; + case MPI2_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL: + reason_str = "internal task abort set"; + break; + case MPI2_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL: + reason_str = "internal clear task set"; + break; + case MPI2_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL: + reason_str = "internal query task"; + break; + case MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE: + reason_str = "sata init failure"; + break; + case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET: + reason_str = "internal device reset complete"; + break; + case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_TASK_ABORT_INTERNAL: + reason_str = "internal task abort complete"; + break; + case MPI2_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION: + reason_str = "internal async notification"; + break; + default: + reason_str = "unknown reason"; + break; + } + printk(MPT2SAS_DEBUG_FMT "device status change: (%s)\n" + "\thandle(0x%04x), sas address(0x%016llx)", ioc->name, + reason_str, le16_to_cpu(event_data->DevHandle), + (unsigned long long)le64_to_cpu(event_data->SASAddress)); + if (event_data->ReasonCode == MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA) + printk(MPT2SAS_DEBUG_FMT ", ASC(0x%x), ASCQ(0x%x)\n", ioc->name, + event_data->ASC, event_data->ASCQ); + printk(KERN_INFO "\n"); +} +#endif + +/** + * _scsih_sas_device_status_change_event - handle device status change + * @ioc: per adapter object + * @VF_ID: + * @event_data: event data payload + * Context: user. + * + * Return nothing. + */ +static void +_scsih_sas_device_status_change_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, + Mpi2EventDataSasDeviceStatusChange_t *event_data) +{ +#ifdef CONFIG_SCSI_MPT2SAS_LOGGING + if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) + _scsih_sas_device_status_change_event_debug(ioc, event_data); +#endif +} + +#ifdef CONFIG_SCSI_MPT2SAS_LOGGING +/** + * _scsih_sas_enclosure_dev_status_change_event_debug - debug for enclosure event + * @ioc: per adapter object + * @event_data: event data payload + * Context: user. + * + * Return nothing. + */ +static void +_scsih_sas_enclosure_dev_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc, + Mpi2EventDataSasEnclDevStatusChange_t *event_data) +{ + char *reason_str = NULL; + + switch (event_data->ReasonCode) { + case MPI2_EVENT_SAS_ENCL_RC_ADDED: + reason_str = "enclosure add"; + break; + case MPI2_EVENT_SAS_ENCL_RC_NOT_RESPONDING: + reason_str = "enclosure remove"; + break; + default: + reason_str = "unknown reason"; + break; + } + + printk(MPT2SAS_DEBUG_FMT "enclosure status change: (%s)\n" + "\thandle(0x%04x), enclosure logical id(0x%016llx)" + " number slots(%d)\n", ioc->name, reason_str, + le16_to_cpu(event_data->EnclosureHandle), + (unsigned long long)le64_to_cpu(event_data->EnclosureLogicalID), + le16_to_cpu(event_data->StartSlot)); +} +#endif + +/** + * _scsih_sas_enclosure_dev_status_change_event - handle enclosure events + * @ioc: per adapter object + * @VF_ID: + * @event_data: event data payload + * Context: user. + * + * Return nothing. + */ +static void +_scsih_sas_enclosure_dev_status_change_event(struct MPT2SAS_ADAPTER *ioc, + u8 VF_ID, Mpi2EventDataSasEnclDevStatusChange_t *event_data) +{ +#ifdef CONFIG_SCSI_MPT2SAS_LOGGING + if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) + _scsih_sas_enclosure_dev_status_change_event_debug(ioc, + event_data); +#endif +} + +/** + * _scsih_sas_broadcast_primative_event - handle broadcast events + * @ioc: per adapter object + * @event_data: event data payload + * Context: user. + * + * Return nothing. + */ +static void +_scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, + Mpi2EventDataSasBroadcastPrimitive_t *event_data) +{ + struct scsi_cmnd *scmd; + u16 smid, handle; + u32 lun; + struct MPT2SAS_DEVICE *sas_device_priv_data; + u32 termination_count; + u32 query_count; + Mpi2SCSITaskManagementReply_t *mpi_reply; + + dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "broadcast primative: " + "phy number(%d), width(%d)\n", ioc->name, event_data->PhyNum, + event_data->PortWidth)); + + dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name, + __func__)); + + mutex_lock(&ioc->tm_cmds.mutex); + termination_count = 0; + query_count = 0; + mpi_reply = ioc->tm_cmds.reply; + for (smid = 1; smid <= ioc->request_depth; smid++) { + scmd = _scsih_scsi_lookup_get(ioc, smid); + if (!scmd) + continue; + sas_device_priv_data = scmd->device->hostdata; + if (!sas_device_priv_data || !sas_device_priv_data->sas_target) + continue; + /* skip hidden raid components */ + if (sas_device_priv_data->sas_target->flags & + MPT_TARGET_FLAGS_RAID_COMPONENT) + continue; + /* skip volumes */ + if (sas_device_priv_data->sas_target->flags & + MPT_TARGET_FLAGS_VOLUME) + continue; + + handle = sas_device_priv_data->sas_target->handle; + lun = sas_device_priv_data->lun; + query_count++; + + mpt2sas_scsih_issue_tm(ioc, handle, lun, + MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK, smid, 30); + termination_count += le32_to_cpu(mpi_reply->TerminationCount); + + if ((mpi_reply->IOCStatus == MPI2_IOCSTATUS_SUCCESS) && + (mpi_reply->ResponseCode == + MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED || + mpi_reply->ResponseCode == + MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC)) + continue; + + mpt2sas_scsih_issue_tm(ioc, handle, lun, + MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET, smid, 30); + termination_count += le32_to_cpu(mpi_reply->TerminationCount); + } + ioc->tm_cmds.status = MPT2_CMD_NOT_USED; + ioc->broadcast_aen_busy = 0; + mutex_unlock(&ioc->tm_cmds.mutex); + + dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT + "%s - exit, query_count = %d termination_count = %d\n", + ioc->name, __func__, query_count, termination_count)); +} + +/** + * _scsih_sas_discovery_event - handle discovery events + * @ioc: per adapter object + * @event_data: event data payload + * Context: user. + * + * Return nothing. + */ +static void +_scsih_sas_discovery_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, + Mpi2EventDataSasDiscovery_t *event_data) +{ +#ifdef CONFIG_SCSI_MPT2SAS_LOGGING + if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) { + printk(MPT2SAS_DEBUG_FMT "discovery event: (%s)", ioc->name, + (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED) ? + "start" : "stop"); + if (event_data->DiscoveryStatus) + printk(MPT2SAS_DEBUG_FMT ", discovery_status(0x%08x)", + ioc->name, le32_to_cpu(event_data->DiscoveryStatus)); + printk("\n"); + } +#endif + + if (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED && + !ioc->sas_hba.num_phys) + _scsih_sas_host_add(ioc); +} + +/** + * _scsih_reprobe_lun - reprobing lun + * @sdev: scsi device struct + * @no_uld_attach: sdev->no_uld_attach flag setting + * + **/ +static void +_scsih_reprobe_lun(struct scsi_device *sdev, void *no_uld_attach) +{ + int rc; + + sdev->no_uld_attach = no_uld_attach ? 1 : 0; + sdev_printk(KERN_INFO, sdev, "%s raid component\n", + sdev->no_uld_attach ? "hidding" : "exposing"); + rc = scsi_device_reprobe(sdev); +} + +/** + * _scsih_reprobe_target - reprobing target + * @starget: scsi target struct + * @no_uld_attach: sdev->no_uld_attach flag setting + * + * Note: no_uld_attach flag determines whether the disk device is attached + * to block layer. A value of `1` means to not attach. + **/ +static void +_scsih_reprobe_target(struct scsi_target *starget, int no_uld_attach) +{ + struct MPT2SAS_TARGET *sas_target_priv_data = starget->hostdata; + + if (no_uld_attach) + sas_target_priv_data->flags |= MPT_TARGET_FLAGS_RAID_COMPONENT; + else + sas_target_priv_data->flags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT; + + starget_for_each_device(starget, no_uld_attach ? (void *)1 : NULL, + _scsih_reprobe_lun); +} +/** + * _scsih_sas_volume_add - add new volume + * @ioc: per adapter object + * @element: IR config element data + * Context: user. + * + * Return nothing. + */ +static void +_scsih_sas_volume_add(struct MPT2SAS_ADAPTER *ioc, + Mpi2EventIrConfigElement_t *element) +{ + struct _raid_device *raid_device; + unsigned long flags; + u64 wwid; + u16 handle = le16_to_cpu(element->VolDevHandle); + int rc; + +#if 0 /* RAID_HACKS */ + if (le32_to_cpu(event_data->Flags) & + MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) + return; +#endif + + mpt2sas_config_get_volume_wwid(ioc, handle, &wwid); + if (!wwid) { + printk(MPT2SAS_ERR_FMT + "failure at %s:%d/%s()!\n", ioc->name, + __FILE__, __LINE__, __func__); + return; + } + + spin_lock_irqsave(&ioc->raid_device_lock, flags); + raid_device = _scsih_raid_device_find_by_wwid(ioc, wwid); + spin_unlock_irqrestore(&ioc->raid_device_lock, flags); + + if (raid_device) + return; + + raid_device = kzalloc(sizeof(struct _raid_device), GFP_KERNEL); + if (!raid_device) { + printk(MPT2SAS_ERR_FMT + "failure at %s:%d/%s()!\n", ioc->name, + __FILE__, __LINE__, __func__); + return; + } + + raid_device->id = ioc->sas_id++; + raid_device->channel = RAID_CHANNEL; + raid_device->handle = handle; + raid_device->wwid = wwid; + _scsih_raid_device_add(ioc, raid_device); + if (!ioc->wait_for_port_enable_to_complete) { + rc = scsi_add_device(ioc->shost, RAID_CHANNEL, + raid_device->id, 0); + if (rc) + _scsih_raid_device_remove(ioc, raid_device); + } else + _scsih_determine_boot_device(ioc, raid_device, 1); +} + +/** + * _scsih_sas_volume_delete - delete volume + * @ioc: per adapter object + * @element: IR config element data + * Context: user. + * + * Return nothing. + */ +static void +_scsih_sas_volume_delete(struct MPT2SAS_ADAPTER *ioc, + Mpi2EventIrConfigElement_t *element) +{ + struct _raid_device *raid_device; + u16 handle = le16_to_cpu(element->VolDevHandle); + unsigned long flags; + struct MPT2SAS_TARGET *sas_target_priv_data; + +#if 0 /* RAID_HACKS */ + if (le32_to_cpu(event_data->Flags) & + MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) + return; +#endif + + spin_lock_irqsave(&ioc->raid_device_lock, flags); + raid_device = _scsih_raid_device_find_by_handle(ioc, handle); + spin_unlock_irqrestore(&ioc->raid_device_lock, flags); + if (!raid_device) + return; + if (raid_device->starget) { + sas_target_priv_data = raid_device->starget->hostdata; + sas_target_priv_data->deleted = 1; + scsi_remove_target(&raid_device->starget->dev); + } + _scsih_raid_device_remove(ioc, raid_device); +} + +/** + * _scsih_sas_pd_expose - expose pd component to /dev/sdX + * @ioc: per adapter object + * @element: IR config element data + * Context: user. + * + * Return nothing. + */ +static void +_scsih_sas_pd_expose(struct MPT2SAS_ADAPTER *ioc, + Mpi2EventIrConfigElement_t *element) +{ + struct _sas_device *sas_device; + unsigned long flags; + u16 handle = le16_to_cpu(element->PhysDiskDevHandle); + + spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_device = _scsih_sas_device_find_by_handle(ioc, handle); + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + if (!sas_device) + return; + + /* exposing raid component */ + sas_device->volume_handle = 0; + sas_device->volume_wwid = 0; + sas_device->hidden_raid_component = 0; + _scsih_reprobe_target(sas_device->starget, 0); +} + +/** + * _scsih_sas_pd_hide - hide pd component from /dev/sdX + * @ioc: per adapter object + * @element: IR config element data + * Context: user. + * + * Return nothing. + */ +static void +_scsih_sas_pd_hide(struct MPT2SAS_ADAPTER *ioc, + Mpi2EventIrConfigElement_t *element) +{ + struct _sas_device *sas_device; + unsigned long flags; + u16 handle = le16_to_cpu(element->PhysDiskDevHandle); + + spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_device = _scsih_sas_device_find_by_handle(ioc, handle); + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + if (!sas_device) + return; + + /* hiding raid component */ + mpt2sas_config_get_volume_handle(ioc, handle, + &sas_device->volume_handle); + mpt2sas_config_get_volume_wwid(ioc, sas_device->volume_handle, + &sas_device->volume_wwid); + sas_device->hidden_raid_component = 1; + _scsih_reprobe_target(sas_device->starget, 1); +} + +/** + * _scsih_sas_pd_delete - delete pd component + * @ioc: per adapter object + * @element: IR config element data + * Context: user. + * + * Return nothing. + */ +static void +_scsih_sas_pd_delete(struct MPT2SAS_ADAPTER *ioc, + Mpi2EventIrConfigElement_t *element) +{ + struct _sas_device *sas_device; + unsigned long flags; + u16 handle = le16_to_cpu(element->PhysDiskDevHandle); + + spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_device = _scsih_sas_device_find_by_handle(ioc, handle); + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + if (!sas_device) + return; + _scsih_remove_device(ioc, handle); +} + +/** + * _scsih_sas_pd_add - remove pd component + * @ioc: per adapter object + * @element: IR config element data + * Context: user. + * + * Return nothing. + */ +static void +_scsih_sas_pd_add(struct MPT2SAS_ADAPTER *ioc, + Mpi2EventIrConfigElement_t *element) +{ + struct _sas_device *sas_device; + unsigned long flags; + u16 handle = le16_to_cpu(element->PhysDiskDevHandle); + + spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_device = _scsih_sas_device_find_by_handle(ioc, handle); + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + if (sas_device) + sas_device->hidden_raid_component = 1; + else + _scsih_add_device(ioc, handle, 0, 1); +} + +#ifdef CONFIG_SCSI_MPT2SAS_LOGGING +/** + * _scsih_sas_ir_config_change_event_debug - debug for IR Config Change events + * @ioc: per adapter object + * @event_data: event data payload + * Context: user. + * + * Return nothing. + */ +static void +_scsih_sas_ir_config_change_event_debug(struct MPT2SAS_ADAPTER *ioc, + Mpi2EventDataIrConfigChangeList_t *event_data) +{ + Mpi2EventIrConfigElement_t *element; + u8 element_type; + int i; + char *reason_str = NULL, *element_str = NULL; + + element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0]; + + printk(MPT2SAS_DEBUG_FMT "raid config change: (%s), elements(%d)\n", + ioc->name, (le32_to_cpu(event_data->Flags) & + MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ? + "foreign" : "native", event_data->NumElements); + for (i = 0; i < event_data->NumElements; i++, element++) { + switch (element->ReasonCode) { + case MPI2_EVENT_IR_CHANGE_RC_ADDED: + reason_str = "add"; + break; + case MPI2_EVENT_IR_CHANGE_RC_REMOVED: + reason_str = "remove"; + break; + case MPI2_EVENT_IR_CHANGE_RC_NO_CHANGE: + reason_str = "no change"; + break; + case MPI2_EVENT_IR_CHANGE_RC_HIDE: + reason_str = "hide"; + break; + case MPI2_EVENT_IR_CHANGE_RC_UNHIDE: + reason_str = "unhide"; + break; + case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED: + reason_str = "volume_created"; + break; + case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED: + reason_str = "volume_deleted"; + break; + case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED: + reason_str = "pd_created"; + break; + case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED: + reason_str = "pd_deleted"; + break; + default: + reason_str = "unknown reason"; + break; + } + element_type = le16_to_cpu(element->ElementFlags) & + MPI2_EVENT_IR_CHANGE_EFLAGS_ELEMENT_TYPE_MASK; + switch (element_type) { + case MPI2_EVENT_IR_CHANGE_EFLAGS_VOLUME_ELEMENT: + element_str = "volume"; + break; + case MPI2_EVENT_IR_CHANGE_EFLAGS_VOLPHYSDISK_ELEMENT: + element_str = "phys disk"; + break; + case MPI2_EVENT_IR_CHANGE_EFLAGS_HOTSPARE_ELEMENT: + element_str = "hot spare"; + break; + default: + element_str = "unknown element"; + break; + } + printk(KERN_DEBUG "\t(%s:%s), vol handle(0x%04x), " + "pd handle(0x%04x), pd num(0x%02x)\n", element_str, + reason_str, le16_to_cpu(element->VolDevHandle), + le16_to_cpu(element->PhysDiskDevHandle), + element->PhysDiskNum); + } +} +#endif + +/** + * _scsih_sas_ir_config_change_event - handle ir configuration change events + * @ioc: per adapter object + * @VF_ID: + * @event_data: event data payload + * Context: user. + * + * Return nothing. + */ +static void +_scsih_sas_ir_config_change_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, + Mpi2EventDataIrConfigChangeList_t *event_data) +{ + Mpi2EventIrConfigElement_t *element; + int i; + +#ifdef CONFIG_SCSI_MPT2SAS_LOGGING + if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) + _scsih_sas_ir_config_change_event_debug(ioc, event_data); + +#endif + + element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0]; + for (i = 0; i < event_data->NumElements; i++, element++) { + + switch (element->ReasonCode) { + case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED: + case MPI2_EVENT_IR_CHANGE_RC_ADDED: + _scsih_sas_volume_add(ioc, element); + break; + case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED: + case MPI2_EVENT_IR_CHANGE_RC_REMOVED: + _scsih_sas_volume_delete(ioc, element); + break; + case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED: + _scsih_sas_pd_hide(ioc, element); + break; + case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED: + _scsih_sas_pd_expose(ioc, element); + break; + case MPI2_EVENT_IR_CHANGE_RC_HIDE: + _scsih_sas_pd_add(ioc, element); + break; + case MPI2_EVENT_IR_CHANGE_RC_UNHIDE: + _scsih_sas_pd_delete(ioc, element); + break; + } + } +} + +/** + * _scsih_sas_ir_volume_event - IR volume event + * @ioc: per adapter object + * @event_data: event data payload + * Context: user. + * + * Return nothing. + */ +static void +_scsih_sas_ir_volume_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, + Mpi2EventDataIrVolume_t *event_data) +{ + u64 wwid; + unsigned long flags; + struct _raid_device *raid_device; + u16 handle; + u32 state; + int rc; + struct MPT2SAS_TARGET *sas_target_priv_data; + + if (event_data->ReasonCode != MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED) + return; + + handle = le16_to_cpu(event_data->VolDevHandle); + state = le32_to_cpu(event_data->NewValue); + dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle(0x%04x), " + "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle, + le32_to_cpu(event_data->PreviousValue), state)); + + spin_lock_irqsave(&ioc->raid_device_lock, flags); + raid_device = _scsih_raid_device_find_by_handle(ioc, handle); + spin_unlock_irqrestore(&ioc->raid_device_lock, flags); + + switch (state) { + case MPI2_RAID_VOL_STATE_MISSING: + case MPI2_RAID_VOL_STATE_FAILED: + if (!raid_device) + break; + if (raid_device->starget) { + sas_target_priv_data = raid_device->starget->hostdata; + sas_target_priv_data->deleted = 1; + scsi_remove_target(&raid_device->starget->dev); + } + _scsih_raid_device_remove(ioc, raid_device); + break; + + case MPI2_RAID_VOL_STATE_ONLINE: + case MPI2_RAID_VOL_STATE_DEGRADED: + case MPI2_RAID_VOL_STATE_OPTIMAL: + if (raid_device) + break; + + mpt2sas_config_get_volume_wwid(ioc, handle, &wwid); + if (!wwid) { + printk(MPT2SAS_ERR_FMT + "failure at %s:%d/%s()!\n", ioc->name, + __FILE__, __LINE__, __func__); + break; + } + + raid_device = kzalloc(sizeof(struct _raid_device), GFP_KERNEL); + if (!raid_device) { + printk(MPT2SAS_ERR_FMT + "failure at %s:%d/%s()!\n", ioc->name, + __FILE__, __LINE__, __func__); + break; + } + + raid_device->id = ioc->sas_id++; + raid_device->channel = RAID_CHANNEL; + raid_device->handle = handle; + raid_device->wwid = wwid; + _scsih_raid_device_add(ioc, raid_device); + rc = scsi_add_device(ioc->shost, RAID_CHANNEL, + raid_device->id, 0); + if (rc) + _scsih_raid_device_remove(ioc, raid_device); + break; + + case MPI2_RAID_VOL_STATE_INITIALIZING: + default: + break; + } +} + +/** + * _scsih_sas_ir_physical_disk_event - PD event + * @ioc: per adapter object + * @event_data: event data payload + * Context: user. + * + * Return nothing. + */ +static void +_scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, + Mpi2EventDataIrPhysicalDisk_t *event_data) +{ + u16 handle; + u32 state; + struct _sas_device *sas_device; + unsigned long flags; + + if (event_data->ReasonCode != MPI2_EVENT_IR_PHYSDISK_RC_STATE_CHANGED) + return; + + handle = le16_to_cpu(event_data->PhysDiskDevHandle); + state = le32_to_cpu(event_data->NewValue); + + dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle(0x%04x), " + "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle, + le32_to_cpu(event_data->PreviousValue), state)); + + spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_device = _scsih_sas_device_find_by_handle(ioc, handle); + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + + switch (state) { +#if 0 + case MPI2_RAID_PD_STATE_OFFLINE: + if (sas_device) + _scsih_remove_device(ioc, handle); + break; +#endif + case MPI2_RAID_PD_STATE_ONLINE: + case MPI2_RAID_PD_STATE_DEGRADED: + case MPI2_RAID_PD_STATE_REBUILDING: + case MPI2_RAID_PD_STATE_OPTIMAL: + if (sas_device) + sas_device->hidden_raid_component = 1; + else + _scsih_add_device(ioc, handle, 0, 1); + break; + + case MPI2_RAID_PD_STATE_NOT_CONFIGURED: + case MPI2_RAID_PD_STATE_NOT_COMPATIBLE: + case MPI2_RAID_PD_STATE_HOT_SPARE: + default: + break; + } +} + +#ifdef CONFIG_SCSI_MPT2SAS_LOGGING +/** + * _scsih_sas_ir_operation_status_event_debug - debug for IR op event + * @ioc: per adapter object + * @event_data: event data payload + * Context: user. + * + * Return nothing. + */ +static void +_scsih_sas_ir_operation_status_event_debug(struct MPT2SAS_ADAPTER *ioc, + Mpi2EventDataIrOperationStatus_t *event_data) +{ + char *reason_str = NULL; + + switch (event_data->RAIDOperation) { + case MPI2_EVENT_IR_RAIDOP_RESYNC: + reason_str = "resync"; + break; + case MPI2_EVENT_IR_RAIDOP_ONLINE_CAP_EXPANSION: + reason_str = "online capacity expansion"; + break; + case MPI2_EVENT_IR_RAIDOP_CONSISTENCY_CHECK: + reason_str = "consistency check"; + break; + default: + reason_str = "unknown reason"; + break; + } + + printk(MPT2SAS_INFO_FMT "raid operational status: (%s)" + "\thandle(0x%04x), percent complete(%d)\n", + ioc->name, reason_str, + le16_to_cpu(event_data->VolDevHandle), + event_data->PercentComplete); +} +#endif + +/** + * _scsih_sas_ir_operation_status_event - handle RAID operation events + * @ioc: per adapter object + * @VF_ID: + * @event_data: event data payload + * Context: user. + * + * Return nothing. + */ +static void +_scsih_sas_ir_operation_status_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, + Mpi2EventDataIrOperationStatus_t *event_data) +{ +#ifdef CONFIG_SCSI_MPT2SAS_LOGGING + if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) + _scsih_sas_ir_operation_status_event_debug(ioc, event_data); +#endif +} + +/** + * _scsih_task_set_full - handle task set full + * @ioc: per adapter object + * @event_data: event data payload + * Context: user. + * + * Throttle back qdepth. + */ +static void +_scsih_task_set_full(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, + Mpi2EventDataTaskSetFull_t *event_data) +{ + unsigned long flags; + struct _sas_device *sas_device; + static struct _raid_device *raid_device; + struct scsi_device *sdev; + int depth; + u16 current_depth; + u16 handle; + int id, channel; + u64 sas_address; + + current_depth = le16_to_cpu(event_data->CurrentDepth); + handle = le16_to_cpu(event_data->DevHandle); + spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_device = _scsih_sas_device_find_by_handle(ioc, handle); + if (!sas_device) { + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + return; + } + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + id = sas_device->id; + channel = sas_device->channel; + sas_address = sas_device->sas_address; + + /* if hidden raid component, then change to volume characteristics */ + if (sas_device->hidden_raid_component && sas_device->volume_handle) { + spin_lock_irqsave(&ioc->raid_device_lock, flags); + raid_device = _scsih_raid_device_find_by_handle( + ioc, sas_device->volume_handle); + spin_unlock_irqrestore(&ioc->raid_device_lock, flags); + if (raid_device) { + id = raid_device->id; + channel = raid_device->channel; + handle = raid_device->handle; + sas_address = raid_device->wwid; + } + } + + if (ioc->logging_level & MPT_DEBUG_TASK_SET_FULL) + starget_printk(KERN_DEBUG, sas_device->starget, "task set " + "full: handle(0x%04x), sas_addr(0x%016llx), depth(%d)\n", + handle, (unsigned long long)sas_address, current_depth); + + shost_for_each_device(sdev, ioc->shost) { + if (sdev->id == id && sdev->channel == channel) { + if (current_depth > sdev->queue_depth) { + if (ioc->logging_level & + MPT_DEBUG_TASK_SET_FULL) + sdev_printk(KERN_INFO, sdev, "strange " + "observation, the queue depth is" + " (%d) meanwhile fw queue depth " + "is (%d)\n", sdev->queue_depth, + current_depth); + continue; + } + depth = scsi_track_queue_full(sdev, + current_depth - 1); + if (depth > 0) + sdev_printk(KERN_INFO, sdev, "Queue depth " + "reduced to (%d)\n", depth); + else if (depth < 0) + sdev_printk(KERN_INFO, sdev, "Tagged Command " + "Queueing is being disabled\n"); + else if (depth == 0) + if (ioc->logging_level & + MPT_DEBUG_TASK_SET_FULL) + sdev_printk(KERN_INFO, sdev, + "Queue depth not changed yet\n"); + } + } +} + +/** + * _scsih_mark_responding_sas_device - mark a sas_devices as responding + * @ioc: per adapter object + * @sas_address: sas address + * @slot: enclosure slot id + * @handle: device handle + * + * After host reset, find out whether devices are still responding. + * Used in _scsi_remove_unresponsive_sas_devices. + * + * Return nothing. + */ +static void +_scsih_mark_responding_sas_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address, + u16 slot, u16 handle) +{ + struct MPT2SAS_TARGET *sas_target_priv_data; + struct scsi_target *starget; + struct _sas_device *sas_device; + unsigned long flags; + + spin_lock_irqsave(&ioc->sas_device_lock, flags); + list_for_each_entry(sas_device, &ioc->sas_device_list, list) { + if (sas_device->sas_address == sas_address && + sas_device->slot == slot && sas_device->starget) { + sas_device->responding = 1; + starget_printk(KERN_INFO, sas_device->starget, + "handle(0x%04x), sas_addr(0x%016llx), enclosure " + "logical id(0x%016llx), slot(%d)\n", handle, + (unsigned long long)sas_device->sas_address, + (unsigned long long) + sas_device->enclosure_logical_id, + sas_device->slot); + if (sas_device->handle == handle) + goto out; + printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n", + sas_device->handle); + sas_device->handle = handle; + starget = sas_device->starget; + sas_target_priv_data = starget->hostdata; + sas_target_priv_data->handle = handle; + goto out; + } + } + out: + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); +} + +/** + * _scsih_search_responding_sas_devices - + * @ioc: per adapter object + * + * After host reset, find out whether devices are still responding. + * If not remove. + * + * Return nothing. + */ +static void +_scsih_search_responding_sas_devices(struct MPT2SAS_ADAPTER *ioc) +{ + Mpi2SasDevicePage0_t sas_device_pg0; + Mpi2ConfigReply_t mpi_reply; + u16 ioc_status; + __le64 sas_address; + u16 handle; + u32 device_info; + u16 slot; + + printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__); + + if (list_empty(&ioc->sas_device_list)) + return; + + handle = 0xFFFF; + while (!(mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, + &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE, + handle))) { + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) + break; + handle = le16_to_cpu(sas_device_pg0.DevHandle); + device_info = le32_to_cpu(sas_device_pg0.DeviceInfo); + if (!(_scsih_is_end_device(device_info))) + continue; + sas_address = le64_to_cpu(sas_device_pg0.SASAddress); + slot = le16_to_cpu(sas_device_pg0.Slot); + _scsih_mark_responding_sas_device(ioc, sas_address, slot, + handle); + } +} + +/** + * _scsih_mark_responding_raid_device - mark a raid_device as responding + * @ioc: per adapter object + * @wwid: world wide identifier for raid volume + * @handle: device handle + * + * After host reset, find out whether devices are still responding. + * Used in _scsi_remove_unresponsive_raid_devices. + * + * Return nothing. + */ +static void +_scsih_mark_responding_raid_device(struct MPT2SAS_ADAPTER *ioc, u64 wwid, + u16 handle) +{ + struct MPT2SAS_TARGET *sas_target_priv_data; + struct scsi_target *starget; + struct _raid_device *raid_device; + unsigned long flags; + + spin_lock_irqsave(&ioc->raid_device_lock, flags); + list_for_each_entry(raid_device, &ioc->raid_device_list, list) { + if (raid_device->wwid == wwid && raid_device->starget) { + raid_device->responding = 1; + starget_printk(KERN_INFO, raid_device->starget, + "handle(0x%04x), wwid(0x%016llx)\n", handle, + (unsigned long long)raid_device->wwid); + if (raid_device->handle == handle) + goto out; + printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n", + raid_device->handle); + raid_device->handle = handle; + starget = raid_device->starget; + sas_target_priv_data = starget->hostdata; + sas_target_priv_data->handle = handle; + goto out; + } + } + out: + spin_unlock_irqrestore(&ioc->raid_device_lock, flags); +} + +/** + * _scsih_search_responding_raid_devices - + * @ioc: per adapter object + * + * After host reset, find out whether devices are still responding. + * If not remove. + * + * Return nothing. + */ +static void +_scsih_search_responding_raid_devices(struct MPT2SAS_ADAPTER *ioc) +{ + Mpi2RaidVolPage1_t volume_pg1; + Mpi2ConfigReply_t mpi_reply; + u16 ioc_status; + u16 handle; + + printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__); + + if (list_empty(&ioc->raid_device_list)) + return; + + handle = 0xFFFF; + while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply, + &volume_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) { + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) + break; + handle = le16_to_cpu(volume_pg1.DevHandle); + _scsih_mark_responding_raid_device(ioc, + le64_to_cpu(volume_pg1.WWID), handle); + } +} + +/** + * _scsih_mark_responding_expander - mark a expander as responding + * @ioc: per adapter object + * @sas_address: sas address + * @handle: + * + * After host reset, find out whether devices are still responding. + * Used in _scsi_remove_unresponsive_expanders. + * + * Return nothing. + */ +static void +_scsih_mark_responding_expander(struct MPT2SAS_ADAPTER *ioc, u64 sas_address, + u16 handle) +{ + struct _sas_node *sas_expander; + unsigned long flags; + + spin_lock_irqsave(&ioc->sas_node_lock, flags); + list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) { + if (sas_expander->sas_address == sas_address) { + sas_expander->responding = 1; + if (sas_expander->handle != handle) { + printk(KERN_INFO "old handle(0x%04x)\n", + sas_expander->handle); + sas_expander->handle = handle; + } + goto out; + } + } + out: + spin_unlock_irqrestore(&ioc->sas_node_lock, flags); +} + +/** + * _scsih_search_responding_expanders - + * @ioc: per adapter object + * + * After host reset, find out whether devices are still responding. + * If not remove. + * + * Return nothing. + */ +static void +_scsih_search_responding_expanders(struct MPT2SAS_ADAPTER *ioc) +{ + Mpi2ExpanderPage0_t expander_pg0; + Mpi2ConfigReply_t mpi_reply; + u16 ioc_status; + __le64 sas_address; + u16 handle; + + printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__); + + if (list_empty(&ioc->sas_expander_list)) + return; + + handle = 0xFFFF; + while (!(mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0, + MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL, handle))) { + + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) + break; + + handle = le16_to_cpu(expander_pg0.DevHandle); + sas_address = le64_to_cpu(expander_pg0.SASAddress); + printk(KERN_INFO "\texpander present: handle(0x%04x), " + "sas_addr(0x%016llx)\n", handle, + (unsigned long long)sas_address); + _scsih_mark_responding_expander(ioc, sas_address, handle); + } + +} + +/** + * _scsih_remove_unresponding_devices - removing unresponding devices + * @ioc: per adapter object + * + * Return nothing. + */ +static void +_scsih_remove_unresponding_devices(struct MPT2SAS_ADAPTER *ioc) +{ + struct _sas_device *sas_device, *sas_device_next; + struct _sas_node *sas_expander, *sas_expander_next; + struct _raid_device *raid_device, *raid_device_next; + unsigned long flags; + + _scsih_search_responding_sas_devices(ioc); + _scsih_search_responding_raid_devices(ioc); + _scsih_search_responding_expanders(ioc); + + spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); + ioc->shost_recovery = 0; + if (ioc->shost->shost_state == SHOST_RECOVERY) { + printk(MPT2SAS_INFO_FMT "putting controller into " + "SHOST_RUNNING\n", ioc->name); + scsi_host_set_state(ioc->shost, SHOST_RUNNING); + } + spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); + + list_for_each_entry_safe(sas_device, sas_device_next, + &ioc->sas_device_list, list) { + if (sas_device->responding) { + sas_device->responding = 0; + continue; + } + if (sas_device->starget) + starget_printk(KERN_INFO, sas_device->starget, + "removing: handle(0x%04x), sas_addr(0x%016llx), " + "enclosure logical id(0x%016llx), slot(%d)\n", + sas_device->handle, + (unsigned long long)sas_device->sas_address, + (unsigned long long) + sas_device->enclosure_logical_id, + sas_device->slot); + _scsih_remove_device(ioc, sas_device->handle); + } + + list_for_each_entry_safe(raid_device, raid_device_next, + &ioc->raid_device_list, list) { + if (raid_device->responding) { + raid_device->responding = 0; + continue; + } + if (raid_device->starget) { + starget_printk(KERN_INFO, raid_device->starget, + "removing: handle(0x%04x), wwid(0x%016llx)\n", + raid_device->handle, + (unsigned long long)raid_device->wwid); + scsi_remove_target(&raid_device->starget->dev); + } + _scsih_raid_device_remove(ioc, raid_device); + } + + list_for_each_entry_safe(sas_expander, sas_expander_next, + &ioc->sas_expander_list, list) { + if (sas_expander->responding) { + sas_expander->responding = 0; + continue; + } + printk("\tremoving expander: handle(0x%04x), " + " sas_addr(0x%016llx)\n", sas_expander->handle, + (unsigned long long)sas_expander->sas_address); + _scsih_expander_remove(ioc, sas_expander->handle); + } +} + +/** + * _firmware_event_work - delayed task for processing firmware events + * @ioc: per adapter object + * @work: equal to the fw_event_work object + * Context: user. + * + * Return nothing. + */ +static void +_firmware_event_work(struct work_struct *work) +{ + struct fw_event_work *fw_event = container_of(work, + struct fw_event_work, work.work); + unsigned long flags; + struct MPT2SAS_ADAPTER *ioc = fw_event->ioc; + + /* This is invoked by calling _scsih_queue_rescan(). */ + if (fw_event->event == MPT2SAS_RESCAN_AFTER_HOST_RESET) { + _scsih_fw_event_free(ioc, fw_event); + _scsih_sas_host_refresh(ioc, 1); + _scsih_remove_unresponding_devices(ioc); + return; + } + + /* the queue is being flushed so ignore this event */ + spin_lock_irqsave(&ioc->fw_event_lock, flags); + if (ioc->fw_events_off || ioc->remove_host) { + spin_unlock_irqrestore(&ioc->fw_event_lock, flags); + _scsih_fw_event_free(ioc, fw_event); + return; + } + spin_unlock_irqrestore(&ioc->fw_event_lock, flags); + + spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); + if (ioc->shost_recovery) { + spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); + _scsih_fw_event_requeue(ioc, fw_event, 1000); + return; + } + spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); + + switch (fw_event->event) { + case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST: + _scsih_sas_topology_change_event(ioc, fw_event->VF_ID, + fw_event->event_data, fw_event); + break; + case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE: + _scsih_sas_device_status_change_event(ioc, fw_event->VF_ID, + fw_event->event_data); + break; + case MPI2_EVENT_SAS_DISCOVERY: + _scsih_sas_discovery_event(ioc, fw_event->VF_ID, + fw_event->event_data); + break; + case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE: + _scsih_sas_broadcast_primative_event(ioc, fw_event->VF_ID, + fw_event->event_data); + break; + case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE: + _scsih_sas_enclosure_dev_status_change_event(ioc, + fw_event->VF_ID, fw_event->event_data); + break; + case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST: + _scsih_sas_ir_config_change_event(ioc, fw_event->VF_ID, + fw_event->event_data); + break; + case MPI2_EVENT_IR_VOLUME: + _scsih_sas_ir_volume_event(ioc, fw_event->VF_ID, + fw_event->event_data); + break; + case MPI2_EVENT_IR_PHYSICAL_DISK: + _scsih_sas_ir_physical_disk_event(ioc, fw_event->VF_ID, + fw_event->event_data); + break; + case MPI2_EVENT_IR_OPERATION_STATUS: + _scsih_sas_ir_operation_status_event(ioc, fw_event->VF_ID, + fw_event->event_data); + break; + case MPI2_EVENT_TASK_SET_FULL: + _scsih_task_set_full(ioc, fw_event->VF_ID, + fw_event->event_data); + break; + } + _scsih_fw_event_free(ioc, fw_event); +} + +/** + * mpt2sas_scsih_event_callback - firmware event handler (called at ISR time) + * @ioc: per adapter object + * @VF_ID: virtual function id + * @reply: reply message frame(lower 32bit addr) + * Context: interrupt. + * + * This function merely adds a new work task into ioc->firmware_event_thread. + * The tasks are worked from _firmware_event_work in user context. + * + * Return nothing. + */ +void +mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply) +{ + struct fw_event_work *fw_event; + Mpi2EventNotificationReply_t *mpi_reply; + unsigned long flags; + u16 event; + + /* events turned off due to host reset or driver unloading */ + spin_lock_irqsave(&ioc->fw_event_lock, flags); + if (ioc->fw_events_off || ioc->remove_host) { + spin_unlock_irqrestore(&ioc->fw_event_lock, flags); + return; + } + spin_unlock_irqrestore(&ioc->fw_event_lock, flags); + + mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); + event = le16_to_cpu(mpi_reply->Event); + + switch (event) { + /* handle these */ + case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE: + { + Mpi2EventDataSasBroadcastPrimitive_t *baen_data = + (Mpi2EventDataSasBroadcastPrimitive_t *) + mpi_reply->EventData; + + if (baen_data->Primitive != + MPI2_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT || + ioc->broadcast_aen_busy) + return; + ioc->broadcast_aen_busy = 1; + break; + } + + case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST: + _scsih_check_topo_delete_events(ioc, + (Mpi2EventDataSasTopologyChangeList_t *) + mpi_reply->EventData); + break; + + case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE: + case MPI2_EVENT_IR_OPERATION_STATUS: + case MPI2_EVENT_SAS_DISCOVERY: + case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE: + case MPI2_EVENT_IR_VOLUME: + case MPI2_EVENT_IR_PHYSICAL_DISK: + case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST: + case MPI2_EVENT_TASK_SET_FULL: + break; + + default: /* ignore the rest */ + return; + } + + fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC); + if (!fw_event) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + return; + } + fw_event->event_data = + kzalloc(mpi_reply->EventDataLength*4, GFP_ATOMIC); + if (!fw_event->event_data) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + kfree(fw_event); + return; + } + + memcpy(fw_event->event_data, mpi_reply->EventData, + mpi_reply->EventDataLength*4); + fw_event->ioc = ioc; + fw_event->VF_ID = VF_ID; + fw_event->event = event; + _scsih_fw_event_add(ioc, fw_event); +} + +/* shost template */ +static struct scsi_host_template scsih_driver_template = { + .module = THIS_MODULE, + .name = "Fusion MPT SAS Host", + .proc_name = MPT2SAS_DRIVER_NAME, + .queuecommand = scsih_qcmd, + .target_alloc = scsih_target_alloc, + .slave_alloc = scsih_slave_alloc, + .slave_configure = scsih_slave_configure, + .target_destroy = scsih_target_destroy, + .slave_destroy = scsih_slave_destroy, + .change_queue_depth = scsih_change_queue_depth, + .change_queue_type = scsih_change_queue_type, + .eh_abort_handler = scsih_abort, + .eh_device_reset_handler = scsih_dev_reset, + .eh_host_reset_handler = scsih_host_reset, + .bios_param = scsih_bios_param, + .can_queue = 1, + .this_id = -1, + .sg_tablesize = MPT2SAS_SG_DEPTH, + .max_sectors = 8192, + .cmd_per_lun = 7, + .use_clustering = ENABLE_CLUSTERING, + .shost_attrs = mpt2sas_host_attrs, + .sdev_attrs = mpt2sas_dev_attrs, +}; + +/** + * _scsih_expander_node_remove - removing expander device from list. + * @ioc: per adapter object + * @sas_expander: the sas_device object + * Context: Calling function should acquire ioc->sas_node_lock. + * + * Removing object and freeing associated memory from the + * ioc->sas_expander_list. + * + * Return nothing. + */ +static void +_scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc, + struct _sas_node *sas_expander) +{ + struct _sas_port *mpt2sas_port; + struct _sas_device *sas_device; + struct _sas_node *expander_sibling; + unsigned long flags; + + if (!sas_expander) + return; + + /* remove sibling ports attached to this expander */ + retry_device_search: + list_for_each_entry(mpt2sas_port, + &sas_expander->sas_port_list, port_list) { + if (mpt2sas_port->remote_identify.device_type == + SAS_END_DEVICE) { + spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_device = + mpt2sas_scsih_sas_device_find_by_sas_address(ioc, + mpt2sas_port->remote_identify.sas_address); + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + if (!sas_device) + continue; + _scsih_remove_device(ioc, sas_device->handle); + goto retry_device_search; + } + } + + retry_expander_search: + list_for_each_entry(mpt2sas_port, + &sas_expander->sas_port_list, port_list) { + + if (mpt2sas_port->remote_identify.device_type == + MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER || + mpt2sas_port->remote_identify.device_type == + MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER) { + + spin_lock_irqsave(&ioc->sas_node_lock, flags); + expander_sibling = + mpt2sas_scsih_expander_find_by_sas_address( + ioc, mpt2sas_port->remote_identify.sas_address); + spin_unlock_irqrestore(&ioc->sas_node_lock, flags); + if (!expander_sibling) + continue; + _scsih_expander_remove(ioc, expander_sibling->handle); + goto retry_expander_search; + } + } + + mpt2sas_transport_port_remove(ioc, sas_expander->sas_address, + sas_expander->parent_handle); + + printk(MPT2SAS_INFO_FMT "expander_remove: handle" + "(0x%04x), sas_addr(0x%016llx)\n", ioc->name, + sas_expander->handle, (unsigned long long) + sas_expander->sas_address); + + list_del(&sas_expander->list); + kfree(sas_expander->phy); + kfree(sas_expander); +} + +/** + * scsih_remove - detach and remove add host + * @pdev: PCI device struct + * + * Return nothing. + */ +static void __devexit +scsih_remove(struct pci_dev *pdev) +{ + struct Scsi_Host *shost = pci_get_drvdata(pdev); + struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + struct _sas_port *mpt2sas_port; + struct _sas_device *sas_device; + struct _sas_node *expander_sibling; + struct workqueue_struct *wq; + unsigned long flags; + + ioc->remove_host = 1; + _scsih_fw_event_off(ioc); + + spin_lock_irqsave(&ioc->fw_event_lock, flags); + wq = ioc->firmware_event_thread; + ioc->firmware_event_thread = NULL; + spin_unlock_irqrestore(&ioc->fw_event_lock, flags); + if (wq) + destroy_workqueue(wq); + + /* free ports attached to the sas_host */ + retry_again: + list_for_each_entry(mpt2sas_port, + &ioc->sas_hba.sas_port_list, port_list) { + if (mpt2sas_port->remote_identify.device_type == + SAS_END_DEVICE) { + sas_device = + mpt2sas_scsih_sas_device_find_by_sas_address(ioc, + mpt2sas_port->remote_identify.sas_address); + if (sas_device) { + _scsih_remove_device(ioc, sas_device->handle); + goto retry_again; + } + } else { + expander_sibling = + mpt2sas_scsih_expander_find_by_sas_address(ioc, + mpt2sas_port->remote_identify.sas_address); + if (expander_sibling) { + _scsih_expander_remove(ioc, + expander_sibling->handle); + goto retry_again; + } + } + } + + /* free phys attached to the sas_host */ + if (ioc->sas_hba.num_phys) { + kfree(ioc->sas_hba.phy); + ioc->sas_hba.phy = NULL; + ioc->sas_hba.num_phys = 0; + } + + sas_remove_host(shost); + mpt2sas_base_detach(ioc); + list_del(&ioc->list); + scsi_remove_host(shost); + scsi_host_put(shost); +} + +/** + * _scsih_probe_boot_devices - reports 1st device + * @ioc: per adapter object + * + * If specified in bios page 2, this routine reports the 1st + * device scsi-ml or sas transport for persistent boot device + * purposes. Please refer to function _scsih_determine_boot_device() + */ +static void +_scsih_probe_boot_devices(struct MPT2SAS_ADAPTER *ioc) +{ + u8 is_raid; + void *device; + struct _sas_device *sas_device; + struct _raid_device *raid_device; + u16 handle, parent_handle; + u64 sas_address; + unsigned long flags; + int rc; + + device = NULL; + if (ioc->req_boot_device.device) { + device = ioc->req_boot_device.device; + is_raid = ioc->req_boot_device.is_raid; + } else if (ioc->req_alt_boot_device.device) { + device = ioc->req_alt_boot_device.device; + is_raid = ioc->req_alt_boot_device.is_raid; + } else if (ioc->current_boot_device.device) { + device = ioc->current_boot_device.device; + is_raid = ioc->current_boot_device.is_raid; + } + + if (!device) + return; + + if (is_raid) { + raid_device = device; + rc = scsi_add_device(ioc->shost, RAID_CHANNEL, + raid_device->id, 0); + if (rc) + _scsih_raid_device_remove(ioc, raid_device); + } else { + sas_device = device; + handle = sas_device->handle; + parent_handle = sas_device->parent_handle; + sas_address = sas_device->sas_address; + spin_lock_irqsave(&ioc->sas_device_lock, flags); + list_move_tail(&sas_device->list, &ioc->sas_device_list); + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + if (!mpt2sas_transport_port_add(ioc, sas_device->handle, + sas_device->parent_handle)) { + _scsih_sas_device_remove(ioc, sas_device); + } else if (!sas_device->starget) { + mpt2sas_transport_port_remove(ioc, sas_address, + parent_handle); + _scsih_sas_device_remove(ioc, sas_device); + } + } +} + +/** + * _scsih_probe_raid - reporting raid volumes to scsi-ml + * @ioc: per adapter object + * + * Called during initial loading of the driver. + */ +static void +_scsih_probe_raid(struct MPT2SAS_ADAPTER *ioc) +{ + struct _raid_device *raid_device, *raid_next; + int rc; + + list_for_each_entry_safe(raid_device, raid_next, + &ioc->raid_device_list, list) { + if (raid_device->starget) + continue; + rc = scsi_add_device(ioc->shost, RAID_CHANNEL, + raid_device->id, 0); + if (rc) + _scsih_raid_device_remove(ioc, raid_device); + } +} + +/** + * _scsih_probe_sas - reporting raid volumes to sas transport + * @ioc: per adapter object + * + * Called during initial loading of the driver. + */ +static void +_scsih_probe_sas(struct MPT2SAS_ADAPTER *ioc) +{ + struct _sas_device *sas_device, *next; + unsigned long flags; + u16 handle, parent_handle; + u64 sas_address; + + /* SAS Device List */ + list_for_each_entry_safe(sas_device, next, &ioc->sas_device_init_list, + list) { + spin_lock_irqsave(&ioc->sas_device_lock, flags); + list_move_tail(&sas_device->list, &ioc->sas_device_list); + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + + handle = sas_device->handle; + parent_handle = sas_device->parent_handle; + sas_address = sas_device->sas_address; + if (!mpt2sas_transport_port_add(ioc, handle, parent_handle)) { + _scsih_sas_device_remove(ioc, sas_device); + } else if (!sas_device->starget) { + mpt2sas_transport_port_remove(ioc, sas_address, + parent_handle); + _scsih_sas_device_remove(ioc, sas_device); + } + } +} + +/** + * _scsih_probe_devices - probing for devices + * @ioc: per adapter object + * + * Called during initial loading of the driver. + */ +static void +_scsih_probe_devices(struct MPT2SAS_ADAPTER *ioc) +{ + u16 volume_mapping_flags = + le16_to_cpu(ioc->ioc_pg8.IRVolumeMappingFlags) & + MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE; + + if (!(ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR)) + return; /* return when IOC doesn't support initiator mode */ + + _scsih_probe_boot_devices(ioc); + + if (ioc->ir_firmware) { + if ((volume_mapping_flags & + MPI2_IOCPAGE8_IRFLAGS_HIGH_VOLUME_MAPPING)) { + _scsih_probe_sas(ioc); + _scsih_probe_raid(ioc); + } else { + _scsih_probe_raid(ioc); + _scsih_probe_sas(ioc); + } + } else + _scsih_probe_sas(ioc); +} + +/** + * scsih_probe - attach and add scsi host + * @pdev: PCI device struct + * @id: pci device id + * + * Returns 0 success, anything else error. + */ +static int +scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct MPT2SAS_ADAPTER *ioc; + struct Scsi_Host *shost; + + shost = scsi_host_alloc(&scsih_driver_template, + sizeof(struct MPT2SAS_ADAPTER)); + if (!shost) + return -ENODEV; + + /* init local params */ + ioc = shost_priv(shost); + memset(ioc, 0, sizeof(struct MPT2SAS_ADAPTER)); + INIT_LIST_HEAD(&ioc->list); + list_add_tail(&ioc->list, &mpt2sas_ioc_list); + ioc->shost = shost; + ioc->id = mpt_ids++; + sprintf(ioc->name, "%s%d", MPT2SAS_DRIVER_NAME, ioc->id); + ioc->pdev = pdev; + ioc->scsi_io_cb_idx = scsi_io_cb_idx; + ioc->tm_cb_idx = tm_cb_idx; + ioc->ctl_cb_idx = ctl_cb_idx; + ioc->base_cb_idx = base_cb_idx; + ioc->transport_cb_idx = transport_cb_idx; + ioc->config_cb_idx = config_cb_idx; + ioc->logging_level = logging_level; + /* misc semaphores and spin locks */ + spin_lock_init(&ioc->ioc_reset_in_progress_lock); + spin_lock_init(&ioc->scsi_lookup_lock); + spin_lock_init(&ioc->sas_device_lock); + spin_lock_init(&ioc->sas_node_lock); + spin_lock_init(&ioc->fw_event_lock); + spin_lock_init(&ioc->raid_device_lock); + + INIT_LIST_HEAD(&ioc->sas_device_list); + INIT_LIST_HEAD(&ioc->sas_device_init_list); + INIT_LIST_HEAD(&ioc->sas_expander_list); + INIT_LIST_HEAD(&ioc->fw_event_list); + INIT_LIST_HEAD(&ioc->raid_device_list); + INIT_LIST_HEAD(&ioc->sas_hba.sas_port_list); + + /* init shost parameters */ + shost->max_cmd_len = 16; + shost->max_lun = max_lun; + shost->transportt = mpt2sas_transport_template; + shost->unique_id = ioc->id; + + if ((scsi_add_host(shost, &pdev->dev))) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + list_del(&ioc->list); + goto out_add_shost_fail; + } + + /* event thread */ + snprintf(ioc->firmware_event_name, sizeof(ioc->firmware_event_name), + "fw_event%d", ioc->id); + ioc->firmware_event_thread = create_singlethread_workqueue( + ioc->firmware_event_name); + if (!ioc->firmware_event_thread) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + goto out_thread_fail; + } + + ioc->wait_for_port_enable_to_complete = 1; + if ((mpt2sas_base_attach(ioc))) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + goto out_attach_fail; + } + + ioc->wait_for_port_enable_to_complete = 0; + _scsih_probe_devices(ioc); + return 0; + + out_attach_fail: + destroy_workqueue(ioc->firmware_event_thread); + out_thread_fail: + list_del(&ioc->list); + scsi_remove_host(shost); + out_add_shost_fail: + return -ENODEV; +} + +#ifdef CONFIG_PM +/** + * scsih_suspend - power management suspend main entry point + * @pdev: PCI device struct + * @state: PM state change to (usually PCI_D3) + * + * Returns 0 success, anything else error. + */ +static int +scsih_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct Scsi_Host *shost = pci_get_drvdata(pdev); + struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + u32 device_state; + + flush_scheduled_work(); + scsi_block_requests(shost); + device_state = pci_choose_state(pdev, state); + printk(MPT2SAS_INFO_FMT "pdev=0x%p, slot=%s, entering " + "operating state [D%d]\n", ioc->name, pdev, + pci_name(pdev), device_state); + + mpt2sas_base_free_resources(ioc); + pci_save_state(pdev); + pci_disable_device(pdev); + pci_set_power_state(pdev, device_state); + return 0; +} + +/** + * scsih_resume - power management resume main entry point + * @pdev: PCI device struct + * + * Returns 0 success, anything else error. + */ +static int +scsih_resume(struct pci_dev *pdev) +{ + struct Scsi_Host *shost = pci_get_drvdata(pdev); + struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + u32 device_state = pdev->current_state; + int r; + + printk(MPT2SAS_INFO_FMT "pdev=0x%p, slot=%s, previous " + "operating state [D%d]\n", ioc->name, pdev, + pci_name(pdev), device_state); + + pci_set_power_state(pdev, PCI_D0); + pci_enable_wake(pdev, PCI_D0, 0); + pci_restore_state(pdev); + ioc->pdev = pdev; + r = mpt2sas_base_map_resources(ioc); + if (r) + return r; + + mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, SOFT_RESET); + scsi_unblock_requests(shost); + return 0; +} +#endif /* CONFIG_PM */ + + +static struct pci_driver scsih_driver = { + .name = MPT2SAS_DRIVER_NAME, + .id_table = scsih_pci_table, + .probe = scsih_probe, + .remove = __devexit_p(scsih_remove), +#ifdef CONFIG_PM + .suspend = scsih_suspend, + .resume = scsih_resume, +#endif +}; + + +/** + * scsih_init - main entry point for this driver. + * + * Returns 0 success, anything else error. + */ +static int __init +scsih_init(void) +{ + int error; + + mpt_ids = 0; + printk(KERN_INFO "%s version %s loaded\n", MPT2SAS_DRIVER_NAME, + MPT2SAS_DRIVER_VERSION); + + mpt2sas_transport_template = + sas_attach_transport(&mpt2sas_transport_functions); + if (!mpt2sas_transport_template) + return -ENODEV; + + mpt2sas_base_initialize_callback_handler(); + + /* queuecommand callback hander */ + scsi_io_cb_idx = mpt2sas_base_register_callback_handler(scsih_io_done); + + /* task managment callback handler */ + tm_cb_idx = mpt2sas_base_register_callback_handler(scsih_tm_done); + + /* base internal commands callback handler */ + base_cb_idx = mpt2sas_base_register_callback_handler(mpt2sas_base_done); + + /* transport internal commands callback handler */ + transport_cb_idx = mpt2sas_base_register_callback_handler( + mpt2sas_transport_done); + + /* configuration page API internal commands callback handler */ + config_cb_idx = mpt2sas_base_register_callback_handler( + mpt2sas_config_done); + + /* ctl module callback handler */ + ctl_cb_idx = mpt2sas_base_register_callback_handler(mpt2sas_ctl_done); + + mpt2sas_ctl_init(); + + error = pci_register_driver(&scsih_driver); + if (error) + sas_release_transport(mpt2sas_transport_template); + + return error; +} + +/** + * scsih_exit - exit point for this driver (when it is a module). + * + * Returns 0 success, anything else error. + */ +static void __exit +scsih_exit(void) +{ + printk(KERN_INFO "mpt2sas version %s unloading\n", + MPT2SAS_DRIVER_VERSION); + + pci_unregister_driver(&scsih_driver); + + sas_release_transport(mpt2sas_transport_template); + mpt2sas_base_release_callback_handler(scsi_io_cb_idx); + mpt2sas_base_release_callback_handler(tm_cb_idx); + mpt2sas_base_release_callback_handler(base_cb_idx); + mpt2sas_base_release_callback_handler(transport_cb_idx); + mpt2sas_base_release_callback_handler(config_cb_idx); + mpt2sas_base_release_callback_handler(ctl_cb_idx); + + mpt2sas_ctl_exit(); +} + +module_init(scsih_init); +module_exit(scsih_exit); diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c new file mode 100644 index 00000000000..e03dc0b1e1a --- /dev/null +++ b/drivers/scsi/mpt2sas/mpt2sas_transport.c @@ -0,0 +1,1211 @@ +/* + * SAS Transport Layer for MPT (Message Passing Technology) based controllers + * + * This code is based on drivers/scsi/mpt2sas/mpt2_transport.c + * Copyright (C) 2007-2008 LSI Corporation + * (mailto:DL-MPTFusionLinux@lsi.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. + * + * NO WARRANTY + * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT + * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is + * solely responsible for determining the appropriateness of using and + * distributing the Program and assumes all risks associated with its + * exercise of rights under this Agreement, including but not limited to + * the risks and costs of program errors, damage to or loss of data, + * programs or equipment, and unavailability or interruption of operations. + + * DISCLAIMER OF LIABILITY + * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED + * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES + + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/sched.h> +#include <linux/workqueue.h> +#include <linux/delay.h> +#include <linux/pci.h> + +#include <scsi/scsi.h> +#include <scsi/scsi_cmnd.h> +#include <scsi/scsi_device.h> +#include <scsi/scsi_host.h> +#include <scsi/scsi_transport_sas.h> +#include <scsi/scsi_dbg.h> + +#include "mpt2sas_base.h" +/** + * _transport_sas_node_find_by_handle - sas node search + * @ioc: per adapter object + * @handle: expander or hba handle (assigned by firmware) + * Context: Calling function should acquire ioc->sas_node_lock. + * + * Search for either hba phys or expander device based on handle, then returns + * the sas_node object. + */ +static struct _sas_node * +_transport_sas_node_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle) +{ + int i; + + for (i = 0; i < ioc->sas_hba.num_phys; i++) + if (ioc->sas_hba.phy[i].handle == handle) + return &ioc->sas_hba; + + return mpt2sas_scsih_expander_find_by_handle(ioc, handle); +} + +/** + * _transport_convert_phy_link_rate - + * @link_rate: link rate returned from mpt firmware + * + * Convert link_rate from mpi fusion into sas_transport form. + */ +static enum sas_linkrate +_transport_convert_phy_link_rate(u8 link_rate) +{ + enum sas_linkrate rc; + + switch (link_rate) { + case MPI2_SAS_NEG_LINK_RATE_1_5: + rc = SAS_LINK_RATE_1_5_GBPS; + break; + case MPI2_SAS_NEG_LINK_RATE_3_0: + rc = SAS_LINK_RATE_3_0_GBPS; + break; + case MPI2_SAS_NEG_LINK_RATE_6_0: + rc = SAS_LINK_RATE_6_0_GBPS; + break; + case MPI2_SAS_NEG_LINK_RATE_PHY_DISABLED: + rc = SAS_PHY_DISABLED; + break; + case MPI2_SAS_NEG_LINK_RATE_NEGOTIATION_FAILED: + rc = SAS_LINK_RATE_FAILED; + break; + case MPI2_SAS_NEG_LINK_RATE_PORT_SELECTOR: + rc = SAS_SATA_PORT_SELECTOR; + break; + case MPI2_SAS_NEG_LINK_RATE_SMP_RESET_IN_PROGRESS: + rc = SAS_PHY_RESET_IN_PROGRESS; + break; + default: + case MPI2_SAS_NEG_LINK_RATE_SATA_OOB_COMPLETE: + case MPI2_SAS_NEG_LINK_RATE_UNKNOWN_LINK_RATE: + rc = SAS_LINK_RATE_UNKNOWN; + break; + } + return rc; +} + +/** + * _transport_set_identify - set identify for phys and end devices + * @ioc: per adapter object + * @handle: device handle + * @identify: sas identify info + * + * Populates sas identify info. + * + * Returns 0 for success, non-zero for failure. + */ +static int +_transport_set_identify(struct MPT2SAS_ADAPTER *ioc, u16 handle, + struct sas_identify *identify) +{ + Mpi2SasDevicePage0_t sas_device_pg0; + Mpi2ConfigReply_t mpi_reply; + u32 device_info; + u32 ioc_status; + + if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, + MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + return -1; + } + + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + printk(MPT2SAS_ERR_FMT "handle(0x%04x), ioc_status(0x%04x)" + "\nfailure at %s:%d/%s()!\n", ioc->name, handle, ioc_status, + __FILE__, __LINE__, __func__); + return -1; + } + + memset(identify, 0, sizeof(identify)); + device_info = le32_to_cpu(sas_device_pg0.DeviceInfo); + + /* sas_address */ + identify->sas_address = le64_to_cpu(sas_device_pg0.SASAddress); + + /* device_type */ + switch (device_info & MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) { + case MPI2_SAS_DEVICE_INFO_NO_DEVICE: + identify->device_type = SAS_PHY_UNUSED; + break; + case MPI2_SAS_DEVICE_INFO_END_DEVICE: + identify->device_type = SAS_END_DEVICE; + break; + case MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER: + identify->device_type = SAS_EDGE_EXPANDER_DEVICE; + break; + case MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER: + identify->device_type = SAS_FANOUT_EXPANDER_DEVICE; + break; + } + + /* initiator_port_protocols */ + if (device_info & MPI2_SAS_DEVICE_INFO_SSP_INITIATOR) + identify->initiator_port_protocols |= SAS_PROTOCOL_SSP; + if (device_info & MPI2_SAS_DEVICE_INFO_STP_INITIATOR) + identify->initiator_port_protocols |= SAS_PROTOCOL_STP; + if (device_info & MPI2_SAS_DEVICE_INFO_SMP_INITIATOR) + identify->initiator_port_protocols |= SAS_PROTOCOL_SMP; + if (device_info & MPI2_SAS_DEVICE_INFO_SATA_HOST) + identify->initiator_port_protocols |= SAS_PROTOCOL_SATA; + + /* target_port_protocols */ + if (device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) + identify->target_port_protocols |= SAS_PROTOCOL_SSP; + if (device_info & MPI2_SAS_DEVICE_INFO_STP_TARGET) + identify->target_port_protocols |= SAS_PROTOCOL_STP; + if (device_info & MPI2_SAS_DEVICE_INFO_SMP_TARGET) + identify->target_port_protocols |= SAS_PROTOCOL_SMP; + if (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE) + identify->target_port_protocols |= SAS_PROTOCOL_SATA; + + return 0; +} + +/** + * mpt2sas_transport_done - internal transport layer callback handler. + * @ioc: per adapter object + * @smid: system request message index + * @VF_ID: virtual function id + * @reply: reply message frame(lower 32bit addr) + * + * Callback handler when sending internal generated transport cmds. + * The callback index passed is `ioc->transport_cb_idx` + * + * Return nothing. + */ +void +mpt2sas_transport_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, + u32 reply) +{ + MPI2DefaultReply_t *mpi_reply; + + mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); + if (ioc->transport_cmds.status == MPT2_CMD_NOT_USED) + return; + if (ioc->transport_cmds.smid != smid) + return; + ioc->transport_cmds.status |= MPT2_CMD_COMPLETE; + if (mpi_reply) { + memcpy(ioc->transport_cmds.reply, mpi_reply, + mpi_reply->MsgLength*4); + ioc->transport_cmds.status |= MPT2_CMD_REPLY_VALID; + } + ioc->transport_cmds.status &= ~MPT2_CMD_PENDING; + complete(&ioc->transport_cmds.done); +} + +/* report manufacture request structure */ +struct rep_manu_request{ + u8 smp_frame_type; + u8 function; + u8 reserved; + u8 request_length; +}; + +/* report manufacture reply structure */ +struct rep_manu_reply{ + u8 smp_frame_type; /* 0x41 */ + u8 function; /* 0x01 */ + u8 function_result; + u8 response_length; + u16 expander_change_count; + u8 reserved0[2]; + u8 sas_format:1; + u8 reserved1:7; + u8 reserved2[3]; + u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN]; + u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN]; + u8 product_rev[SAS_EXPANDER_PRODUCT_REV_LEN]; + u8 component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN]; + u16 component_id; + u8 component_revision_id; + u8 reserved3; + u8 vendor_specific[8]; +}; + +/** + * transport_expander_report_manufacture - obtain SMP report_manufacture + * @ioc: per adapter object + * @sas_address: expander sas address + * @edev: the sas_expander_device object + * + * Fills in the sas_expander_device object when SMP port is created. + * + * Returns 0 for success, non-zero for failure. + */ +static int +transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc, + u64 sas_address, struct sas_expander_device *edev) +{ + Mpi2SmpPassthroughRequest_t *mpi_request; + Mpi2SmpPassthroughReply_t *mpi_reply; + struct rep_manu_reply *manufacture_reply; + struct rep_manu_request *manufacture_request; + int rc; + u16 smid; + u32 ioc_state; + unsigned long timeleft; + void *psge; + u32 sgl_flags; + u8 issue_reset = 0; + unsigned long flags; + void *data_out = NULL; + dma_addr_t data_out_dma; + u32 sz; + u64 *sas_address_le; + u16 wait_state_count; + + spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); + if (ioc->ioc_reset_in_progress) { + spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); + printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n", + __func__, ioc->name); + return -EFAULT; + } + spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); + + mutex_lock(&ioc->transport_cmds.mutex); + + if (ioc->transport_cmds.status != MPT2_CMD_NOT_USED) { + printk(MPT2SAS_ERR_FMT "%s: transport_cmds in use\n", + ioc->name, __func__); + rc = -EAGAIN; + goto out; + } + ioc->transport_cmds.status = MPT2_CMD_PENDING; + + wait_state_count = 0; + ioc_state = mpt2sas_base_get_iocstate(ioc, 1); + while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { + if (wait_state_count++ == 10) { + printk(MPT2SAS_ERR_FMT + "%s: failed due to ioc not operational\n", + ioc->name, __func__); + rc = -EFAULT; + goto out; + } + ssleep(1); + ioc_state = mpt2sas_base_get_iocstate(ioc, 1); + printk(MPT2SAS_INFO_FMT "%s: waiting for " + "operational state(count=%d)\n", ioc->name, + __func__, wait_state_count); + } + if (wait_state_count) + printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n", + ioc->name, __func__); + + smid = mpt2sas_base_get_smid(ioc, ioc->transport_cb_idx); + if (!smid) { + printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", + ioc->name, __func__); + rc = -EAGAIN; + goto out; + } + + rc = 0; + mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); + ioc->transport_cmds.smid = smid; + + sz = sizeof(struct rep_manu_request) + sizeof(struct rep_manu_reply); + data_out = pci_alloc_consistent(ioc->pdev, sz, &data_out_dma); + + if (!data_out) { + printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, + __LINE__, __func__); + rc = -ENOMEM; + mpt2sas_base_free_smid(ioc, smid); + goto out; + } + + manufacture_request = data_out; + manufacture_request->smp_frame_type = 0x40; + manufacture_request->function = 1; + manufacture_request->reserved = 0; + manufacture_request->request_length = 0; + + memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t)); + mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH; + mpi_request->PhysicalPort = 0xFF; + sas_address_le = (u64 *)&mpi_request->SASAddress; + *sas_address_le = cpu_to_le64(sas_address); + mpi_request->RequestDataLength = sizeof(struct rep_manu_request); + psge = &mpi_request->SGL; + + /* WRITE sgel first */ + sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | + MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC); + sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; + ioc->base_add_sg_single(psge, sgl_flags | + sizeof(struct rep_manu_request), data_out_dma); + + /* incr sgel */ + psge += ioc->sge_size; + + /* READ sgel last */ + sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | + MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER | + MPI2_SGE_FLAGS_END_OF_LIST); + sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; + ioc->base_add_sg_single(psge, sgl_flags | + sizeof(struct rep_manu_reply), data_out_dma + + sizeof(struct rep_manu_request)); + + dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "report_manufacture - " + "send to sas_addr(0x%016llx)\n", ioc->name, + (unsigned long long)sas_address)); + mpt2sas_base_put_smid_default(ioc, smid, 0 /* VF_ID */); + timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done, + 10*HZ); + + if (!(ioc->transport_cmds.status & MPT2_CMD_COMPLETE)) { + printk(MPT2SAS_ERR_FMT "%s: timeout\n", + ioc->name, __func__); + _debug_dump_mf(mpi_request, + sizeof(Mpi2SmpPassthroughRequest_t)/4); + if (!(ioc->transport_cmds.status & MPT2_CMD_RESET)) + issue_reset = 1; + goto issue_host_reset; + } + + dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "report_manufacture - " + "complete\n", ioc->name)); + + if (ioc->transport_cmds.status & MPT2_CMD_REPLY_VALID) { + u8 *tmp; + + mpi_reply = ioc->transport_cmds.reply; + + dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT + "report_manufacture - reply data transfer size(%d)\n", + ioc->name, le16_to_cpu(mpi_reply->ResponseDataLength))); + + if (le16_to_cpu(mpi_reply->ResponseDataLength) != + sizeof(struct rep_manu_reply)) + goto out; + + manufacture_reply = data_out + sizeof(struct rep_manu_request); + strncpy(edev->vendor_id, manufacture_reply->vendor_id, + SAS_EXPANDER_VENDOR_ID_LEN); + strncpy(edev->product_id, manufacture_reply->product_id, + SAS_EXPANDER_PRODUCT_ID_LEN); + strncpy(edev->product_rev, manufacture_reply->product_rev, + SAS_EXPANDER_PRODUCT_REV_LEN); + edev->level = manufacture_reply->sas_format; + if (manufacture_reply->sas_format) { + strncpy(edev->component_vendor_id, + manufacture_reply->component_vendor_id, + SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN); + tmp = (u8 *)&manufacture_reply->component_id; + edev->component_id = tmp[0] << 8 | tmp[1]; + edev->component_revision_id = + manufacture_reply->component_revision_id; + } + } else + dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT + "report_manufacture - no reply\n", ioc->name)); + + issue_host_reset: + if (issue_reset) + mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, + FORCE_BIG_HAMMER); + out: + ioc->transport_cmds.status = MPT2_CMD_NOT_USED; + if (data_out) + pci_free_consistent(ioc->pdev, sz, data_out, data_out_dma); + + mutex_unlock(&ioc->transport_cmds.mutex); + return rc; +} + +/** + * mpt2sas_transport_port_add - insert port to the list + * @ioc: per adapter object + * @handle: handle of attached device + * @parent_handle: parent handle(either hba or expander) + * Context: This function will acquire ioc->sas_node_lock. + * + * Adding new port object to the sas_node->sas_port_list. + * + * Returns mpt2sas_port. + */ +struct _sas_port * +mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle, + u16 parent_handle) +{ + struct _sas_phy *mpt2sas_phy, *next; + struct _sas_port *mpt2sas_port; + unsigned long flags; + struct _sas_node *sas_node; + struct sas_rphy *rphy; + int i; + struct sas_port *port; + + if (!parent_handle) + return NULL; + + mpt2sas_port = kzalloc(sizeof(struct _sas_port), + GFP_KERNEL); + if (!mpt2sas_port) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + return NULL; + } + + INIT_LIST_HEAD(&mpt2sas_port->port_list); + INIT_LIST_HEAD(&mpt2sas_port->phy_list); + spin_lock_irqsave(&ioc->sas_node_lock, flags); + sas_node = _transport_sas_node_find_by_handle(ioc, parent_handle); + spin_unlock_irqrestore(&ioc->sas_node_lock, flags); + + if (!sas_node) { + printk(MPT2SAS_ERR_FMT "%s: Could not find parent(0x%04x)!\n", + ioc->name, __func__, parent_handle); + goto out_fail; + } + + mpt2sas_port->handle = parent_handle; + mpt2sas_port->sas_address = sas_node->sas_address; + if ((_transport_set_identify(ioc, handle, + &mpt2sas_port->remote_identify))) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + goto out_fail; + } + + if (mpt2sas_port->remote_identify.device_type == SAS_PHY_UNUSED) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + goto out_fail; + } + + for (i = 0; i < sas_node->num_phys; i++) { + if (sas_node->phy[i].remote_identify.sas_address != + mpt2sas_port->remote_identify.sas_address) + continue; + list_add_tail(&sas_node->phy[i].port_siblings, + &mpt2sas_port->phy_list); + mpt2sas_port->num_phys++; + } + + if (!mpt2sas_port->num_phys) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + goto out_fail; + } + + port = sas_port_alloc_num(sas_node->parent_dev); + if ((sas_port_add(port))) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + goto out_fail; + } + + list_for_each_entry(mpt2sas_phy, &mpt2sas_port->phy_list, + port_siblings) { + if ((ioc->logging_level & MPT_DEBUG_TRANSPORT)) + dev_printk(KERN_INFO, &port->dev, "add: handle(0x%04x)" + ", sas_addr(0x%016llx), phy(%d)\n", handle, + (unsigned long long) + mpt2sas_port->remote_identify.sas_address, + mpt2sas_phy->phy_id); + sas_port_add_phy(port, mpt2sas_phy->phy); + } + + mpt2sas_port->port = port; + if (mpt2sas_port->remote_identify.device_type == SAS_END_DEVICE) + rphy = sas_end_device_alloc(port); + else + rphy = sas_expander_alloc(port, + mpt2sas_port->remote_identify.device_type); + + rphy->identify = mpt2sas_port->remote_identify; + if ((sas_rphy_add(rphy))) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + } + if ((ioc->logging_level & MPT_DEBUG_TRANSPORT)) + dev_printk(KERN_INFO, &rphy->dev, "add: handle(0x%04x), " + "sas_addr(0x%016llx)\n", handle, + (unsigned long long) + mpt2sas_port->remote_identify.sas_address); + mpt2sas_port->rphy = rphy; + spin_lock_irqsave(&ioc->sas_node_lock, flags); + list_add_tail(&mpt2sas_port->port_list, &sas_node->sas_port_list); + spin_unlock_irqrestore(&ioc->sas_node_lock, flags); + + /* fill in report manufacture */ + if (mpt2sas_port->remote_identify.device_type == + MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER || + mpt2sas_port->remote_identify.device_type == + MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER) + transport_expander_report_manufacture(ioc, + mpt2sas_port->remote_identify.sas_address, + rphy_to_expander_device(rphy)); + + return mpt2sas_port; + + out_fail: + list_for_each_entry_safe(mpt2sas_phy, next, &mpt2sas_port->phy_list, + port_siblings) + list_del(&mpt2sas_phy->port_siblings); + kfree(mpt2sas_port); + return NULL; +} + +/** + * mpt2sas_transport_port_remove - remove port from the list + * @ioc: per adapter object + * @sas_address: sas address of attached device + * @parent_handle: handle to the upstream parent(either hba or expander) + * Context: This function will acquire ioc->sas_node_lock. + * + * Removing object and freeing associated memory from the + * ioc->sas_port_list. + * + * Return nothing. + */ +void +mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address, + u16 parent_handle) +{ + int i; + unsigned long flags; + struct _sas_port *mpt2sas_port, *next; + struct _sas_node *sas_node; + u8 found = 0; + struct _sas_phy *mpt2sas_phy, *next_phy; + + spin_lock_irqsave(&ioc->sas_node_lock, flags); + sas_node = _transport_sas_node_find_by_handle(ioc, parent_handle); + spin_unlock_irqrestore(&ioc->sas_node_lock, flags); + if (!sas_node) + return; + list_for_each_entry_safe(mpt2sas_port, next, &sas_node->sas_port_list, + port_list) { + if (mpt2sas_port->remote_identify.sas_address != sas_address) + continue; + found = 1; + list_del(&mpt2sas_port->port_list); + goto out; + } + out: + if (!found) + return; + + for (i = 0; i < sas_node->num_phys; i++) { + if (sas_node->phy[i].remote_identify.sas_address == sas_address) + memset(&sas_node->phy[i].remote_identify, 0 , + sizeof(struct sas_identify)); + } + + list_for_each_entry_safe(mpt2sas_phy, next_phy, + &mpt2sas_port->phy_list, port_siblings) { + if ((ioc->logging_level & MPT_DEBUG_TRANSPORT)) + dev_printk(KERN_INFO, &mpt2sas_port->port->dev, + "remove: parent_handle(0x%04x), " + "sas_addr(0x%016llx), phy(%d)\n", parent_handle, + (unsigned long long) + mpt2sas_port->remote_identify.sas_address, + mpt2sas_phy->phy_id); + sas_port_delete_phy(mpt2sas_port->port, mpt2sas_phy->phy); + list_del(&mpt2sas_phy->port_siblings); + } + sas_port_delete(mpt2sas_port->port); + kfree(mpt2sas_port); +} + +/** + * mpt2sas_transport_add_host_phy - report sas_host phy to transport + * @ioc: per adapter object + * @mpt2sas_phy: mpt2sas per phy object + * @phy_pg0: sas phy page 0 + * @parent_dev: parent device class object + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt2sas_transport_add_host_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy + *mpt2sas_phy, Mpi2SasPhyPage0_t phy_pg0, struct device *parent_dev) +{ + struct sas_phy *phy; + int phy_index = mpt2sas_phy->phy_id; + + + INIT_LIST_HEAD(&mpt2sas_phy->port_siblings); + phy = sas_phy_alloc(parent_dev, phy_index); + if (!phy) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + return -1; + } + if ((_transport_set_identify(ioc, mpt2sas_phy->handle, + &mpt2sas_phy->identify))) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + return -1; + } + phy->identify = mpt2sas_phy->identify; + mpt2sas_phy->attached_handle = le16_to_cpu(phy_pg0.AttachedDevHandle); + if (mpt2sas_phy->attached_handle) + _transport_set_identify(ioc, mpt2sas_phy->attached_handle, + &mpt2sas_phy->remote_identify); + phy->identify.phy_identifier = mpt2sas_phy->phy_id; + phy->negotiated_linkrate = _transport_convert_phy_link_rate( + phy_pg0.NegotiatedLinkRate & MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL); + phy->minimum_linkrate_hw = _transport_convert_phy_link_rate( + phy_pg0.HwLinkRate & MPI2_SAS_HWRATE_MIN_RATE_MASK); + phy->maximum_linkrate_hw = _transport_convert_phy_link_rate( + phy_pg0.HwLinkRate >> 4); + phy->minimum_linkrate = _transport_convert_phy_link_rate( + phy_pg0.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK); + phy->maximum_linkrate = _transport_convert_phy_link_rate( + phy_pg0.ProgrammedLinkRate >> 4); + + if ((sas_phy_add(phy))) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + sas_phy_free(phy); + return -1; + } + if ((ioc->logging_level & MPT_DEBUG_TRANSPORT)) + dev_printk(KERN_INFO, &phy->dev, + "add: handle(0x%04x), sas_addr(0x%016llx)\n" + "\tattached_handle(0x%04x), sas_addr(0x%016llx)\n", + mpt2sas_phy->handle, (unsigned long long) + mpt2sas_phy->identify.sas_address, + mpt2sas_phy->attached_handle, + (unsigned long long) + mpt2sas_phy->remote_identify.sas_address); + mpt2sas_phy->phy = phy; + return 0; +} + + +/** + * mpt2sas_transport_add_expander_phy - report expander phy to transport + * @ioc: per adapter object + * @mpt2sas_phy: mpt2sas per phy object + * @expander_pg1: expander page 1 + * @parent_dev: parent device class object + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt2sas_transport_add_expander_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy + *mpt2sas_phy, Mpi2ExpanderPage1_t expander_pg1, struct device *parent_dev) +{ + struct sas_phy *phy; + int phy_index = mpt2sas_phy->phy_id; + + INIT_LIST_HEAD(&mpt2sas_phy->port_siblings); + phy = sas_phy_alloc(parent_dev, phy_index); + if (!phy) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + return -1; + } + if ((_transport_set_identify(ioc, mpt2sas_phy->handle, + &mpt2sas_phy->identify))) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + return -1; + } + phy->identify = mpt2sas_phy->identify; + mpt2sas_phy->attached_handle = + le16_to_cpu(expander_pg1.AttachedDevHandle); + if (mpt2sas_phy->attached_handle) + _transport_set_identify(ioc, mpt2sas_phy->attached_handle, + &mpt2sas_phy->remote_identify); + phy->identify.phy_identifier = mpt2sas_phy->phy_id; + phy->negotiated_linkrate = _transport_convert_phy_link_rate( + expander_pg1.NegotiatedLinkRate & + MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL); + phy->minimum_linkrate_hw = _transport_convert_phy_link_rate( + expander_pg1.HwLinkRate & MPI2_SAS_HWRATE_MIN_RATE_MASK); + phy->maximum_linkrate_hw = _transport_convert_phy_link_rate( + expander_pg1.HwLinkRate >> 4); + phy->minimum_linkrate = _transport_convert_phy_link_rate( + expander_pg1.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK); + phy->maximum_linkrate = _transport_convert_phy_link_rate( + expander_pg1.ProgrammedLinkRate >> 4); + + if ((sas_phy_add(phy))) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + sas_phy_free(phy); + return -1; + } + if ((ioc->logging_level & MPT_DEBUG_TRANSPORT)) + dev_printk(KERN_INFO, &phy->dev, + "add: handle(0x%04x), sas_addr(0x%016llx)\n" + "\tattached_handle(0x%04x), sas_addr(0x%016llx)\n", + mpt2sas_phy->handle, (unsigned long long) + mpt2sas_phy->identify.sas_address, + mpt2sas_phy->attached_handle, + (unsigned long long) + mpt2sas_phy->remote_identify.sas_address); + mpt2sas_phy->phy = phy; + return 0; +} + +/** + * mpt2sas_transport_update_phy_link_change - refreshing phy link changes and attached devices + * @ioc: per adapter object + * @handle: handle to sas_host or expander + * @attached_handle: attached device handle + * @phy_numberv: phy number + * @link_rate: new link rate + * + * Returns nothing. + */ +void +mpt2sas_transport_update_phy_link_change(struct MPT2SAS_ADAPTER *ioc, + u16 handle, u16 attached_handle, u8 phy_number, u8 link_rate) +{ + unsigned long flags; + struct _sas_node *sas_node; + struct _sas_phy *mpt2sas_phy; + + spin_lock_irqsave(&ioc->sas_node_lock, flags); + sas_node = _transport_sas_node_find_by_handle(ioc, handle); + spin_unlock_irqrestore(&ioc->sas_node_lock, flags); + if (!sas_node) + return; + + mpt2sas_phy = &sas_node->phy[phy_number]; + mpt2sas_phy->attached_handle = attached_handle; + if (attached_handle && (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5)) + _transport_set_identify(ioc, mpt2sas_phy->attached_handle, + &mpt2sas_phy->remote_identify); + else + memset(&mpt2sas_phy->remote_identify, 0 , sizeof(struct + sas_identify)); + + if (mpt2sas_phy->phy) + mpt2sas_phy->phy->negotiated_linkrate = + _transport_convert_phy_link_rate(link_rate); + + if ((ioc->logging_level & MPT_DEBUG_TRANSPORT)) + dev_printk(KERN_INFO, &mpt2sas_phy->phy->dev, + "refresh: handle(0x%04x), sas_addr(0x%016llx),\n" + "\tlink_rate(0x%02x), phy(%d)\n" + "\tattached_handle(0x%04x), sas_addr(0x%016llx)\n", + handle, (unsigned long long) + mpt2sas_phy->identify.sas_address, link_rate, + phy_number, attached_handle, + (unsigned long long) + mpt2sas_phy->remote_identify.sas_address); +} + +static inline void * +phy_to_ioc(struct sas_phy *phy) +{ + struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); + return shost_priv(shost); +} + +static inline void * +rphy_to_ioc(struct sas_rphy *rphy) +{ + struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent); + return shost_priv(shost); +} + +/** + * transport_get_linkerrors - + * @phy: The sas phy object + * + * Only support sas_host direct attached phys. + * Returns 0 for success, non-zero for failure. + * + */ +static int +transport_get_linkerrors(struct sas_phy *phy) +{ + struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy); + struct _sas_phy *mpt2sas_phy; + Mpi2ConfigReply_t mpi_reply; + Mpi2SasPhyPage1_t phy_pg1; + int i; + + for (i = 0, mpt2sas_phy = NULL; i < ioc->sas_hba.num_phys && + !mpt2sas_phy; i++) { + if (ioc->sas_hba.phy[i].phy != phy) + continue; + mpt2sas_phy = &ioc->sas_hba.phy[i]; + } + + if (!mpt2sas_phy) /* this phy not on sas_host */ + return -EINVAL; + + if ((mpt2sas_config_get_phy_pg1(ioc, &mpi_reply, &phy_pg1, + mpt2sas_phy->phy_id))) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + return -ENXIO; + } + + if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo) + printk(MPT2SAS_INFO_FMT "phy(%d), ioc_status" + "(0x%04x), loginfo(0x%08x)\n", ioc->name, + mpt2sas_phy->phy_id, + le16_to_cpu(mpi_reply.IOCStatus), + le32_to_cpu(mpi_reply.IOCLogInfo)); + + phy->invalid_dword_count = le32_to_cpu(phy_pg1.InvalidDwordCount); + phy->running_disparity_error_count = + le32_to_cpu(phy_pg1.RunningDisparityErrorCount); + phy->loss_of_dword_sync_count = + le32_to_cpu(phy_pg1.LossDwordSynchCount); + phy->phy_reset_problem_count = + le32_to_cpu(phy_pg1.PhyResetProblemCount); + return 0; +} + +/** + * transport_get_enclosure_identifier - + * @phy: The sas phy object + * + * Obtain the enclosure logical id for an expander. + * Returns 0 for success, non-zero for failure. + */ +static int +transport_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier) +{ + struct MPT2SAS_ADAPTER *ioc = rphy_to_ioc(rphy); + struct _sas_node *sas_expander; + unsigned long flags; + + spin_lock_irqsave(&ioc->sas_node_lock, flags); + sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc, + rphy->identify.sas_address); + spin_unlock_irqrestore(&ioc->sas_node_lock, flags); + + if (!sas_expander) + return -ENXIO; + + *identifier = sas_expander->enclosure_logical_id; + return 0; +} + +/** + * transport_get_bay_identifier - + * @phy: The sas phy object + * + * Returns the slot id for a device that resides inside an enclosure. + */ +static int +transport_get_bay_identifier(struct sas_rphy *rphy) +{ + struct MPT2SAS_ADAPTER *ioc = rphy_to_ioc(rphy); + struct _sas_device *sas_device; + unsigned long flags; + + spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, + rphy->identify.sas_address); + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + + if (!sas_device) + return -ENXIO; + + return sas_device->slot; +} + +/** + * transport_phy_reset - + * @phy: The sas phy object + * @hard_reset: + * + * Only support sas_host direct attached phys. + * Returns 0 for success, non-zero for failure. + */ +static int +transport_phy_reset(struct sas_phy *phy, int hard_reset) +{ + struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy); + struct _sas_phy *mpt2sas_phy; + Mpi2SasIoUnitControlReply_t mpi_reply; + Mpi2SasIoUnitControlRequest_t mpi_request; + int i; + + for (i = 0, mpt2sas_phy = NULL; i < ioc->sas_hba.num_phys && + !mpt2sas_phy; i++) { + if (ioc->sas_hba.phy[i].phy != phy) + continue; + mpt2sas_phy = &ioc->sas_hba.phy[i]; + } + + if (!mpt2sas_phy) /* this phy not on sas_host */ + return -EINVAL; + + memset(&mpi_request, 0, sizeof(Mpi2SasIoUnitControlReply_t)); + mpi_request.Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL; + mpi_request.Operation = hard_reset ? + MPI2_SAS_OP_PHY_HARD_RESET : MPI2_SAS_OP_PHY_LINK_RESET; + mpi_request.PhyNum = mpt2sas_phy->phy_id; + + if ((mpt2sas_base_sas_iounit_control(ioc, &mpi_reply, &mpi_request))) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + return -ENXIO; + } + + if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo) + printk(MPT2SAS_INFO_FMT "phy(%d), ioc_status" + "(0x%04x), loginfo(0x%08x)\n", ioc->name, + mpt2sas_phy->phy_id, + le16_to_cpu(mpi_reply.IOCStatus), + le32_to_cpu(mpi_reply.IOCLogInfo)); + + return 0; +} + +/** + * transport_smp_handler - transport portal for smp passthru + * @shost: shost object + * @rphy: sas transport rphy object + * @req: + * + * This used primarily for smp_utils. + * Example: + * smp_rep_general /sys/class/bsg/expander-5:0 + */ +static int +transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, + struct request *req) +{ + struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + Mpi2SmpPassthroughRequest_t *mpi_request; + Mpi2SmpPassthroughReply_t *mpi_reply; + int rc; + u16 smid; + u32 ioc_state; + unsigned long timeleft; + void *psge; + u32 sgl_flags; + u8 issue_reset = 0; + unsigned long flags; + dma_addr_t dma_addr_in = 0; + dma_addr_t dma_addr_out = 0; + u16 wait_state_count; + struct request *rsp = req->next_rq; + + if (!rsp) { + printk(MPT2SAS_ERR_FMT "%s: the smp response space is " + "missing\n", ioc->name, __func__); + return -EINVAL; + } + + /* do we need to support multiple segments? */ + if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) { + printk(MPT2SAS_ERR_FMT "%s: multiple segments req %u %u, " + "rsp %u %u\n", ioc->name, __func__, req->bio->bi_vcnt, + req->data_len, rsp->bio->bi_vcnt, rsp->data_len); + return -EINVAL; + } + + spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); + if (ioc->ioc_reset_in_progress) { + spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); + printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n", + __func__, ioc->name); + return -EFAULT; + } + spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); + + rc = mutex_lock_interruptible(&ioc->transport_cmds.mutex); + if (rc) + return rc; + + if (ioc->transport_cmds.status != MPT2_CMD_NOT_USED) { + printk(MPT2SAS_ERR_FMT "%s: transport_cmds in use\n", ioc->name, + __func__); + rc = -EAGAIN; + goto out; + } + ioc->transport_cmds.status = MPT2_CMD_PENDING; + + wait_state_count = 0; + ioc_state = mpt2sas_base_get_iocstate(ioc, 1); + while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { + if (wait_state_count++ == 10) { + printk(MPT2SAS_ERR_FMT + "%s: failed due to ioc not operational\n", + ioc->name, __func__); + rc = -EFAULT; + goto out; + } + ssleep(1); + ioc_state = mpt2sas_base_get_iocstate(ioc, 1); + printk(MPT2SAS_INFO_FMT "%s: waiting for " + "operational state(count=%d)\n", ioc->name, + __func__, wait_state_count); + } + if (wait_state_count) + printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n", + ioc->name, __func__); + + smid = mpt2sas_base_get_smid(ioc, ioc->transport_cb_idx); + if (!smid) { + printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", + ioc->name, __func__); + rc = -EAGAIN; + goto out; + } + + rc = 0; + mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); + ioc->transport_cmds.smid = smid; + + memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t)); + mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH; + mpi_request->PhysicalPort = 0xFF; + *((u64 *)&mpi_request->SASAddress) = (rphy) ? + cpu_to_le64(rphy->identify.sas_address) : + cpu_to_le64(ioc->sas_hba.sas_address); + mpi_request->RequestDataLength = cpu_to_le16(req->data_len - 4); + psge = &mpi_request->SGL; + + /* WRITE sgel first */ + sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | + MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC); + sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; + dma_addr_out = pci_map_single(ioc->pdev, bio_data(req->bio), + req->data_len, PCI_DMA_BIDIRECTIONAL); + if (!dma_addr_out) { + mpt2sas_base_free_smid(ioc, le16_to_cpu(smid)); + goto unmap; + } + + ioc->base_add_sg_single(psge, sgl_flags | (req->data_len - 4), + dma_addr_out); + + /* incr sgel */ + psge += ioc->sge_size; + + /* READ sgel last */ + sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | + MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER | + MPI2_SGE_FLAGS_END_OF_LIST); + sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; + dma_addr_in = pci_map_single(ioc->pdev, bio_data(rsp->bio), + rsp->data_len, PCI_DMA_BIDIRECTIONAL); + if (!dma_addr_in) { + mpt2sas_base_free_smid(ioc, le16_to_cpu(smid)); + goto unmap; + } + + ioc->base_add_sg_single(psge, sgl_flags | (rsp->data_len + 4), + dma_addr_in); + + dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s - " + "sending smp request\n", ioc->name, __func__)); + + mpt2sas_base_put_smid_default(ioc, smid, 0 /* VF_ID */); + timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done, + 10*HZ); + + if (!(ioc->transport_cmds.status & MPT2_CMD_COMPLETE)) { + printk(MPT2SAS_ERR_FMT "%s : timeout\n", + __func__, ioc->name); + _debug_dump_mf(mpi_request, + sizeof(Mpi2SmpPassthroughRequest_t)/4); + if (!(ioc->transport_cmds.status & MPT2_CMD_RESET)) + issue_reset = 1; + goto issue_host_reset; + } + + dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s - " + "complete\n", ioc->name, __func__)); + + if (ioc->transport_cmds.status & MPT2_CMD_REPLY_VALID) { + + mpi_reply = ioc->transport_cmds.reply; + + dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT + "%s - reply data transfer size(%d)\n", + ioc->name, __func__, + le16_to_cpu(mpi_reply->ResponseDataLength))); + + memcpy(req->sense, mpi_reply, sizeof(*mpi_reply)); + req->sense_len = sizeof(*mpi_reply); + req->data_len = 0; + rsp->data_len -= mpi_reply->ResponseDataLength; + + } else { + dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT + "%s - no reply\n", ioc->name, __func__)); + rc = -ENXIO; + } + + issue_host_reset: + if (issue_reset) { + mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, + FORCE_BIG_HAMMER); + rc = -ETIMEDOUT; + } + + unmap: + if (dma_addr_out) + pci_unmap_single(ioc->pdev, dma_addr_out, req->data_len, + PCI_DMA_BIDIRECTIONAL); + if (dma_addr_in) + pci_unmap_single(ioc->pdev, dma_addr_in, rsp->data_len, + PCI_DMA_BIDIRECTIONAL); + + out: + ioc->transport_cmds.status = MPT2_CMD_NOT_USED; + mutex_unlock(&ioc->transport_cmds.mutex); + return rc; +} + +struct sas_function_template mpt2sas_transport_functions = { + .get_linkerrors = transport_get_linkerrors, + .get_enclosure_identifier = transport_get_enclosure_identifier, + .get_bay_identifier = transport_get_bay_identifier, + .phy_reset = transport_phy_reset, + .smp_handler = transport_smp_handler, +}; + +struct scsi_transport_template *mpt2sas_transport_template; diff --git a/drivers/scsi/mvme16x_scsi.c b/drivers/scsi/mvme16x_scsi.c index b264b499d98..b5fbfd6ce87 100644 --- a/drivers/scsi/mvme16x_scsi.c +++ b/drivers/scsi/mvme16x_scsi.c @@ -34,7 +34,7 @@ static struct scsi_host_template mvme16x_scsi_driver_template = { static struct platform_device *mvme16x_scsi_device; static __devinit int -mvme16x_probe(struct device *dev) +mvme16x_probe(struct platform_device *dev) { struct Scsi_Host * host = NULL; struct NCR_700_Host_Parameters *hostdata; @@ -64,7 +64,8 @@ mvme16x_probe(struct device *dev) hostdata->ctest7_extra = CTEST7_TT1; /* and register the chip */ - host = NCR_700_detect(&mvme16x_scsi_driver_template, hostdata, dev); + host = NCR_700_detect(&mvme16x_scsi_driver_template, hostdata, + &dev->dev); if (!host) { printk(KERN_ERR "mvme16x-scsi: No host detected; " "board configuration problem?\n"); @@ -88,7 +89,7 @@ mvme16x_probe(struct device *dev) out_be32(0xfff4202c, v); } - dev_set_drvdata(dev, host); + platform_set_drvdata(dev, host); scsi_scan_host(host); return 0; @@ -102,9 +103,9 @@ mvme16x_probe(struct device *dev) } static __devexit int -mvme16x_device_remove(struct device *dev) +mvme16x_device_remove(struct platform_device *dev) { - struct Scsi_Host *host = dev_get_drvdata(dev); + struct Scsi_Host *host = platform_get_drvdata(dev); struct NCR_700_Host_Parameters *hostdata = shost_priv(host); /* Disable scsi chip ints */ @@ -123,25 +124,27 @@ mvme16x_device_remove(struct device *dev) return 0; } -static struct device_driver mvme16x_scsi_driver = { - .name = "mvme16x-scsi", - .bus = &platform_bus_type, - .probe = mvme16x_probe, - .remove = __devexit_p(mvme16x_device_remove), +static struct platform_driver mvme16x_scsi_driver = { + .driver = { + .name = "mvme16x-scsi", + .owner = THIS_MODULE, + }, + .probe = mvme16x_probe, + .remove = __devexit_p(mvme16x_device_remove), }; static int __init mvme16x_scsi_init(void) { int err; - err = driver_register(&mvme16x_scsi_driver); + err = platform_driver_register(&mvme16x_scsi_driver); if (err) return err; mvme16x_scsi_device = platform_device_register_simple("mvme16x-scsi", -1, NULL, 0); if (IS_ERR(mvme16x_scsi_device)) { - driver_unregister(&mvme16x_scsi_driver); + platform_driver_unregister(&mvme16x_scsi_driver); return PTR_ERR(mvme16x_scsi_device); } @@ -151,7 +154,7 @@ static int __init mvme16x_scsi_init(void) static void __exit mvme16x_scsi_exit(void) { platform_device_unregister(mvme16x_scsi_device); - driver_unregister(&mvme16x_scsi_driver); + platform_driver_unregister(&mvme16x_scsi_driver); } module_init(mvme16x_scsi_init); diff --git a/drivers/scsi/osd/Kbuild b/drivers/scsi/osd/Kbuild new file mode 100644 index 00000000000..0e207aa67d1 --- /dev/null +++ b/drivers/scsi/osd/Kbuild @@ -0,0 +1,45 @@ +# +# Kbuild for the OSD modules +# +# Copyright (C) 2008 Panasas Inc. All rights reserved. +# +# Authors: +# Boaz Harrosh <bharrosh@panasas.com> +# Benny Halevy <bhalevy@panasas.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 +# + +ifneq ($(OSD_INC),) +# we are built out-of-tree Kconfigure everything as on + +CONFIG_SCSI_OSD_INITIATOR=m +ccflags-y += -DCONFIG_SCSI_OSD_INITIATOR -DCONFIG_SCSI_OSD_INITIATOR_MODULE + +CONFIG_SCSI_OSD_ULD=m +ccflags-y += -DCONFIG_SCSI_OSD_ULD -DCONFIG_SCSI_OSD_ULD_MODULE + +# CONFIG_SCSI_OSD_DPRINT_SENSE = +# 0 - no print of errors +# 1 - print errors +# 2 - errors + warrnings +ccflags-y += -DCONFIG_SCSI_OSD_DPRINT_SENSE=1 + +# Uncomment to turn debug on +# ccflags-y += -DCONFIG_SCSI_OSD_DEBUG + +# if we are built out-of-tree and the hosting kernel has OSD headers +# then "ccflags-y +=" will not pick the out-off-tree headers. Only by doing +# this it will work. This might break in future kernels +LINUXINCLUDE := -I$(OSD_INC) $(LINUXINCLUDE) + +endif + +# libosd.ko - osd-initiator library +libosd-y := osd_initiator.o +obj-$(CONFIG_SCSI_OSD_INITIATOR) += libosd.o + +# osd.ko - SCSI ULD and char-device +osd-y := osd_uld.o +obj-$(CONFIG_SCSI_OSD_ULD) += osd.o diff --git a/drivers/scsi/osd/Kconfig b/drivers/scsi/osd/Kconfig new file mode 100644 index 00000000000..861b5cebaea --- /dev/null +++ b/drivers/scsi/osd/Kconfig @@ -0,0 +1,53 @@ +# +# Kernel configuration file for the OSD scsi protocol +# +# Copyright (C) 2008 Panasas Inc. All rights reserved. +# +# Authors: +# Boaz Harrosh <bharrosh@panasas.com> +# Benny Halevy <bhalevy@panasas.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public version 2 License as +# published by the Free Software Foundation +# +# FIXME: SCSI_OSD_INITIATOR should select CONFIG (HMAC) SHA1 somehow. +# How is it done properly? +# + +config SCSI_OSD_INITIATOR + tristate "OSD-Initiator library" + depends on SCSI + help + Enable the OSD-Initiator library (libosd.ko). + NOTE: You must also select CRYPTO_SHA1 + CRYPTO_HMAC and their + dependencies + +config SCSI_OSD_ULD + tristate "OSD Upper Level driver" + depends on SCSI_OSD_INITIATOR + help + Build a SCSI upper layer driver that exports /dev/osdX devices + to user-mode for testing and controlling OSD devices. It is also + needed by exofs, for mounting an OSD based file system. + +config SCSI_OSD_DPRINT_SENSE + int "(0-2) When sense is returned, DEBUG print all sense descriptors" + default 1 + depends on SCSI_OSD_INITIATOR + help + When a CHECK_CONDITION status is returned from a target, and a + sense-buffer is retrieved, turning this on will dump a full + sense-decoding message. Setting to 2 will also print recoverable + errors that might be regularly returned for some filesystem + operations. + +config SCSI_OSD_DEBUG + bool "Compile All OSD modules with lots of DEBUG prints" + default n + depends on SCSI_OSD_INITIATOR + help + OSD Code is populated with lots of OSD_DEBUG(..) printouts to + dmesg. Enable this if you found a bug and you want to help us + track the problem (see also MAINTAINERS). Setting this will also + force SCSI_OSD_DPRINT_SENSE=2. diff --git a/drivers/scsi/osd/Makefile b/drivers/scsi/osd/Makefile new file mode 100755 index 00000000000..d905344f83b --- /dev/null +++ b/drivers/scsi/osd/Makefile @@ -0,0 +1,37 @@ +# +# Makefile for the OSD modules (out of tree) +# +# Copyright (C) 2008 Panasas Inc. All rights reserved. +# +# Authors: +# Boaz Harrosh <bharrosh@panasas.com> +# Benny Halevy <bhalevy@panasas.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 +# +# This Makefile is used to call the kernel Makefile in case of an out-of-tree +# build. +# $KSRC should point to a Kernel source tree otherwise host's default is +# used. (eg. /lib/modules/`uname -r`/build) + +# include path for out-of-tree Headers +OSD_INC ?= `pwd`/../../../include + +# allow users to override these +# e.g. to compile for a kernel that you aren't currently running +KSRC ?= /lib/modules/$(shell uname -r)/build +KBUILD_OUTPUT ?= +ARCH ?= +V ?= 0 + +# this is the basic Kbuild out-of-tree invocation, with the M= option +KBUILD_BASE = +$(MAKE) -C $(KSRC) M=`pwd` KBUILD_OUTPUT=$(KBUILD_OUTPUT) ARCH=$(ARCH) V=$(V) + +all: libosd + +libosd: ; + $(KBUILD_BASE) OSD_INC=$(OSD_INC) modules + +clean: + $(KBUILD_BASE) clean diff --git a/drivers/scsi/osd/osd_debug.h b/drivers/scsi/osd/osd_debug.h new file mode 100644 index 00000000000..579e491f11d --- /dev/null +++ b/drivers/scsi/osd/osd_debug.h @@ -0,0 +1,30 @@ +/* + * osd_debug.h - Some kprintf macros + * + * Copyright (C) 2008 Panasas Inc. All rights reserved. + * + * Authors: + * Boaz Harrosh <bharrosh@panasas.com> + * Benny Halevy <bhalevy@panasas.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * + */ +#ifndef __OSD_DEBUG_H__ +#define __OSD_DEBUG_H__ + +#define OSD_ERR(fmt, a...) printk(KERN_ERR "osd: " fmt, ##a) +#define OSD_INFO(fmt, a...) printk(KERN_NOTICE "osd: " fmt, ##a) + +#ifdef CONFIG_SCSI_OSD_DEBUG +#define OSD_DEBUG(fmt, a...) \ + printk(KERN_NOTICE "osd @%s:%d: " fmt, __func__, __LINE__, ##a) +#else +#define OSD_DEBUG(fmt, a...) do {} while (0) +#endif + +/* u64 has problems with printk this will cast it to unsigned long long */ +#define _LLU(x) (unsigned long long)(x) + +#endif /* ndef __OSD_DEBUG_H__ */ diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c new file mode 100644 index 00000000000..2a5f0777148 --- /dev/null +++ b/drivers/scsi/osd/osd_initiator.c @@ -0,0 +1,1663 @@ +/* + * osd_initiator - Main body of the osd initiator library. + * + * Note: The file does not contain the advanced security functionality which + * is only needed by the security_manager's initiators. + * + * Copyright (C) 2008 Panasas Inc. All rights reserved. + * + * Authors: + * Boaz Harrosh <bharrosh@panasas.com> + * Benny Halevy <bhalevy@panasas.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Panasas company nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <scsi/osd_initiator.h> +#include <scsi/osd_sec.h> +#include <scsi/osd_attributes.h> +#include <scsi/osd_sense.h> + +#include <scsi/scsi_device.h> + +#include "osd_debug.h" + +#ifndef __unused +# define __unused __attribute__((unused)) +#endif + +enum { OSD_REQ_RETRIES = 1 }; + +MODULE_AUTHOR("Boaz Harrosh <bharrosh@panasas.com>"); +MODULE_DESCRIPTION("open-osd initiator library libosd.ko"); +MODULE_LICENSE("GPL"); + +static inline void build_test(void) +{ + /* structures were not packed */ + BUILD_BUG_ON(sizeof(struct osd_capability) != OSD_CAP_LEN); + BUILD_BUG_ON(sizeof(struct osdv2_cdb) != OSD_TOTAL_CDB_LEN); + BUILD_BUG_ON(sizeof(struct osdv1_cdb) != OSDv1_TOTAL_CDB_LEN); +} + +static const char *_osd_ver_desc(struct osd_request *or) +{ + return osd_req_is_ver1(or) ? "OSD1" : "OSD2"; +} + +#define ATTR_DEF_RI(id, len) ATTR_DEF(OSD_APAGE_ROOT_INFORMATION, id, len) + +static int _osd_print_system_info(struct osd_dev *od, void *caps) +{ + struct osd_request *or; + struct osd_attr get_attrs[] = { + ATTR_DEF_RI(OSD_ATTR_RI_VENDOR_IDENTIFICATION, 8), + ATTR_DEF_RI(OSD_ATTR_RI_PRODUCT_IDENTIFICATION, 16), + ATTR_DEF_RI(OSD_ATTR_RI_PRODUCT_MODEL, 32), + ATTR_DEF_RI(OSD_ATTR_RI_PRODUCT_REVISION_LEVEL, 4), + ATTR_DEF_RI(OSD_ATTR_RI_PRODUCT_SERIAL_NUMBER, 64 /*variable*/), + ATTR_DEF_RI(OSD_ATTR_RI_OSD_NAME, 64 /*variable*/), + ATTR_DEF_RI(OSD_ATTR_RI_TOTAL_CAPACITY, 8), + ATTR_DEF_RI(OSD_ATTR_RI_USED_CAPACITY, 8), + ATTR_DEF_RI(OSD_ATTR_RI_NUMBER_OF_PARTITIONS, 8), + ATTR_DEF_RI(OSD_ATTR_RI_CLOCK, 6), + /* IBM-OSD-SIM Has a bug with this one put it last */ + ATTR_DEF_RI(OSD_ATTR_RI_OSD_SYSTEM_ID, 20), + }; + void *iter = NULL, *pFirst; + int nelem = ARRAY_SIZE(get_attrs), a = 0; + int ret; + + or = osd_start_request(od, GFP_KERNEL); + if (!or) + return -ENOMEM; + + /* get attrs */ + osd_req_get_attributes(or, &osd_root_object); + osd_req_add_get_attr_list(or, get_attrs, ARRAY_SIZE(get_attrs)); + + ret = osd_finalize_request(or, 0, caps, NULL); + if (ret) + goto out; + + ret = osd_execute_request(or); + if (ret) { + OSD_ERR("Failed to detect %s => %d\n", _osd_ver_desc(or), ret); + goto out; + } + + osd_req_decode_get_attr_list(or, get_attrs, &nelem, &iter); + + OSD_INFO("Detected %s device\n", + _osd_ver_desc(or)); + + pFirst = get_attrs[a++].val_ptr; + OSD_INFO("OSD_ATTR_RI_VENDOR_IDENTIFICATION [%s]\n", + (char *)pFirst); + + pFirst = get_attrs[a++].val_ptr; + OSD_INFO("OSD_ATTR_RI_PRODUCT_IDENTIFICATION [%s]\n", + (char *)pFirst); + + pFirst = get_attrs[a++].val_ptr; + OSD_INFO("OSD_ATTR_RI_PRODUCT_MODEL [%s]\n", + (char *)pFirst); + + pFirst = get_attrs[a++].val_ptr; + OSD_INFO("OSD_ATTR_RI_PRODUCT_REVISION_LEVEL [%u]\n", + pFirst ? get_unaligned_be32(pFirst) : ~0U); + + pFirst = get_attrs[a++].val_ptr; + OSD_INFO("OSD_ATTR_RI_PRODUCT_SERIAL_NUMBER [%s]\n", + (char *)pFirst); + + pFirst = get_attrs[a].val_ptr; + OSD_INFO("OSD_ATTR_RI_OSD_NAME [%s]\n", (char *)pFirst); + a++; + + pFirst = get_attrs[a++].val_ptr; + OSD_INFO("OSD_ATTR_RI_TOTAL_CAPACITY [0x%llx]\n", + pFirst ? _LLU(get_unaligned_be64(pFirst)) : ~0ULL); + + pFirst = get_attrs[a++].val_ptr; + OSD_INFO("OSD_ATTR_RI_USED_CAPACITY [0x%llx]\n", + pFirst ? _LLU(get_unaligned_be64(pFirst)) : ~0ULL); + + pFirst = get_attrs[a++].val_ptr; + OSD_INFO("OSD_ATTR_RI_NUMBER_OF_PARTITIONS [%llu]\n", + pFirst ? _LLU(get_unaligned_be64(pFirst)) : ~0ULL); + + if (a >= nelem) + goto out; + + /* FIXME: Where are the time utilities */ + pFirst = get_attrs[a++].val_ptr; + OSD_INFO("OSD_ATTR_RI_CLOCK [0x%02x%02x%02x%02x%02x%02x]\n", + ((char *)pFirst)[0], ((char *)pFirst)[1], + ((char *)pFirst)[2], ((char *)pFirst)[3], + ((char *)pFirst)[4], ((char *)pFirst)[5]); + + if (a < nelem) { /* IBM-OSD-SIM bug, Might not have it */ + unsigned len = get_attrs[a].len; + char sid_dump[32*4 + 2]; /* 2nibbles+space+ASCII */ + + hex_dump_to_buffer(get_attrs[a].val_ptr, len, 32, 1, + sid_dump, sizeof(sid_dump), true); + OSD_INFO("OSD_ATTR_RI_OSD_SYSTEM_ID(%d) [%s]\n", len, sid_dump); + a++; + } +out: + osd_end_request(or); + return ret; +} + +int osd_auto_detect_ver(struct osd_dev *od, void *caps) +{ + int ret; + + /* Auto-detect the osd version */ + ret = _osd_print_system_info(od, caps); + if (ret) { + osd_dev_set_ver(od, OSD_VER1); + OSD_DEBUG("converting to OSD1\n"); + ret = _osd_print_system_info(od, caps); + } + + return ret; +} +EXPORT_SYMBOL(osd_auto_detect_ver); + +static unsigned _osd_req_cdb_len(struct osd_request *or) +{ + return osd_req_is_ver1(or) ? OSDv1_TOTAL_CDB_LEN : OSD_TOTAL_CDB_LEN; +} + +static unsigned _osd_req_alist_elem_size(struct osd_request *or, unsigned len) +{ + return osd_req_is_ver1(or) ? + osdv1_attr_list_elem_size(len) : + osdv2_attr_list_elem_size(len); +} + +static unsigned _osd_req_alist_size(struct osd_request *or, void *list_head) +{ + return osd_req_is_ver1(or) ? + osdv1_list_size(list_head) : + osdv2_list_size(list_head); +} + +static unsigned _osd_req_sizeof_alist_header(struct osd_request *or) +{ + return osd_req_is_ver1(or) ? + sizeof(struct osdv1_attributes_list_header) : + sizeof(struct osdv2_attributes_list_header); +} + +static void _osd_req_set_alist_type(struct osd_request *or, + void *list, int list_type) +{ + if (osd_req_is_ver1(or)) { + struct osdv1_attributes_list_header *attr_list = list; + + memset(attr_list, 0, sizeof(*attr_list)); + attr_list->type = list_type; + } else { + struct osdv2_attributes_list_header *attr_list = list; + + memset(attr_list, 0, sizeof(*attr_list)); + attr_list->type = list_type; + } +} + +static bool _osd_req_is_alist_type(struct osd_request *or, + void *list, int list_type) +{ + if (!list) + return false; + + if (osd_req_is_ver1(or)) { + struct osdv1_attributes_list_header *attr_list = list; + + return attr_list->type == list_type; + } else { + struct osdv2_attributes_list_header *attr_list = list; + + return attr_list->type == list_type; + } +} + +/* This is for List-objects not Attributes-Lists */ +static void _osd_req_encode_olist(struct osd_request *or, + struct osd_obj_id_list *list) +{ + struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb); + + if (osd_req_is_ver1(or)) { + cdbh->v1.list_identifier = list->list_identifier; + cdbh->v1.start_address = list->continuation_id; + } else { + cdbh->v2.list_identifier = list->list_identifier; + cdbh->v2.start_address = list->continuation_id; + } +} + +static osd_cdb_offset osd_req_encode_offset(struct osd_request *or, + u64 offset, unsigned *padding) +{ + return __osd_encode_offset(offset, padding, + osd_req_is_ver1(or) ? + OSDv1_OFFSET_MIN_SHIFT : OSD_OFFSET_MIN_SHIFT, + OSD_OFFSET_MAX_SHIFT); +} + +static struct osd_security_parameters * +_osd_req_sec_params(struct osd_request *or) +{ + struct osd_cdb *ocdb = &or->cdb; + + if (osd_req_is_ver1(or)) + return &ocdb->v1.sec_params; + else + return &ocdb->v2.sec_params; +} + +void osd_dev_init(struct osd_dev *osdd, struct scsi_device *scsi_device) +{ + memset(osdd, 0, sizeof(*osdd)); + osdd->scsi_device = scsi_device; + osdd->def_timeout = BLK_DEFAULT_SG_TIMEOUT; +#ifdef OSD_VER1_SUPPORT + osdd->version = OSD_VER2; +#endif + /* TODO: Allocate pools for osd_request attributes ... */ +} +EXPORT_SYMBOL(osd_dev_init); + +void osd_dev_fini(struct osd_dev *osdd) +{ + /* TODO: De-allocate pools */ + + osdd->scsi_device = NULL; +} +EXPORT_SYMBOL(osd_dev_fini); + +static struct osd_request *_osd_request_alloc(gfp_t gfp) +{ + struct osd_request *or; + + /* TODO: Use mempool with one saved request */ + or = kzalloc(sizeof(*or), gfp); + return or; +} + +static void _osd_request_free(struct osd_request *or) +{ + kfree(or); +} + +struct osd_request *osd_start_request(struct osd_dev *dev, gfp_t gfp) +{ + struct osd_request *or; + + or = _osd_request_alloc(gfp); + if (!or) + return NULL; + + or->osd_dev = dev; + or->alloc_flags = gfp; + or->timeout = dev->def_timeout; + or->retries = OSD_REQ_RETRIES; + + return or; +} +EXPORT_SYMBOL(osd_start_request); + +static void _osd_free_seg(struct osd_request *or __unused, + struct _osd_req_data_segment *seg) +{ + if (!seg->buff || !seg->alloc_size) + return; + + kfree(seg->buff); + seg->buff = NULL; + seg->alloc_size = 0; +} + +static void _put_request(struct request *rq , bool is_async) +{ + if (is_async) { + WARN_ON(rq->bio); + __blk_put_request(rq->q, rq); + } else { + /* + * If osd_finalize_request() was called but the request was not + * executed through the block layer, then we must release BIOs. + * TODO: Keep error code in or->async_error. Need to audit all + * code paths. + */ + if (unlikely(rq->bio)) + blk_end_request(rq, -ENOMEM, blk_rq_bytes(rq)); + else + blk_put_request(rq); + } +} + +void osd_end_request(struct osd_request *or) +{ + struct request *rq = or->request; + /* IMPORTANT: make sure this agrees with osd_execute_request_async */ + bool is_async = (or->request->end_io_data == or); + + _osd_free_seg(or, &or->set_attr); + _osd_free_seg(or, &or->enc_get_attr); + _osd_free_seg(or, &or->get_attr); + + if (rq) { + if (rq->next_rq) { + _put_request(rq->next_rq, is_async); + rq->next_rq = NULL; + } + + _put_request(rq, is_async); + } + _osd_request_free(or); +} +EXPORT_SYMBOL(osd_end_request); + +int osd_execute_request(struct osd_request *or) +{ + return blk_execute_rq(or->request->q, NULL, or->request, 0); +} +EXPORT_SYMBOL(osd_execute_request); + +static void osd_request_async_done(struct request *req, int error) +{ + struct osd_request *or = req->end_io_data; + + or->async_error = error; + + if (error) + OSD_DEBUG("osd_request_async_done error recieved %d\n", error); + + if (or->async_done) + or->async_done(or, or->async_private); + else + osd_end_request(or); +} + +int osd_execute_request_async(struct osd_request *or, + osd_req_done_fn *done, void *private) +{ + or->request->end_io_data = or; + or->async_private = private; + or->async_done = done; + + blk_execute_rq_nowait(or->request->q, NULL, or->request, 0, + osd_request_async_done); + return 0; +} +EXPORT_SYMBOL(osd_execute_request_async); + +u8 sg_out_pad_buffer[1 << OSDv1_OFFSET_MIN_SHIFT]; +u8 sg_in_pad_buffer[1 << OSDv1_OFFSET_MIN_SHIFT]; + +static int _osd_realloc_seg(struct osd_request *or, + struct _osd_req_data_segment *seg, unsigned max_bytes) +{ + void *buff; + + if (seg->alloc_size >= max_bytes) + return 0; + + buff = krealloc(seg->buff, max_bytes, or->alloc_flags); + if (!buff) { + OSD_ERR("Failed to Realloc %d-bytes was-%d\n", max_bytes, + seg->alloc_size); + return -ENOMEM; + } + + memset(buff + seg->alloc_size, 0, max_bytes - seg->alloc_size); + seg->buff = buff; + seg->alloc_size = max_bytes; + return 0; +} + +static int _alloc_set_attr_list(struct osd_request *or, + const struct osd_attr *oa, unsigned nelem, unsigned add_bytes) +{ + unsigned total_bytes = add_bytes; + + for (; nelem; --nelem, ++oa) + total_bytes += _osd_req_alist_elem_size(or, oa->len); + + OSD_DEBUG("total_bytes=%d\n", total_bytes); + return _osd_realloc_seg(or, &or->set_attr, total_bytes); +} + +static int _alloc_get_attr_desc(struct osd_request *or, unsigned max_bytes) +{ + OSD_DEBUG("total_bytes=%d\n", max_bytes); + return _osd_realloc_seg(or, &or->enc_get_attr, max_bytes); +} + +static int _alloc_get_attr_list(struct osd_request *or) +{ + OSD_DEBUG("total_bytes=%d\n", or->get_attr.total_bytes); + return _osd_realloc_seg(or, &or->get_attr, or->get_attr.total_bytes); +} + +/* + * Common to all OSD commands + */ + +static void _osdv1_req_encode_common(struct osd_request *or, + __be16 act, const struct osd_obj_id *obj, u64 offset, u64 len) +{ + struct osdv1_cdb *ocdb = &or->cdb.v1; + + /* + * For speed, the commands + * OSD_ACT_PERFORM_SCSI_COMMAND , V1 0x8F7E, V2 0x8F7C + * OSD_ACT_SCSI_TASK_MANAGEMENT , V1 0x8F7F, V2 0x8F7D + * are not supported here. Should pass zero and set after the call + */ + act &= cpu_to_be16(~0x0080); /* V1 action code */ + + OSD_DEBUG("OSDv1 execute opcode 0x%x\n", be16_to_cpu(act)); + + ocdb->h.varlen_cdb.opcode = VARIABLE_LENGTH_CMD; + ocdb->h.varlen_cdb.additional_cdb_length = OSD_ADDITIONAL_CDB_LENGTH; + ocdb->h.varlen_cdb.service_action = act; + + ocdb->h.partition = cpu_to_be64(obj->partition); + ocdb->h.object = cpu_to_be64(obj->id); + ocdb->h.v1.length = cpu_to_be64(len); + ocdb->h.v1.start_address = cpu_to_be64(offset); +} + +static void _osdv2_req_encode_common(struct osd_request *or, + __be16 act, const struct osd_obj_id *obj, u64 offset, u64 len) +{ + struct osdv2_cdb *ocdb = &or->cdb.v2; + + OSD_DEBUG("OSDv2 execute opcode 0x%x\n", be16_to_cpu(act)); + + ocdb->h.varlen_cdb.opcode = VARIABLE_LENGTH_CMD; + ocdb->h.varlen_cdb.additional_cdb_length = OSD_ADDITIONAL_CDB_LENGTH; + ocdb->h.varlen_cdb.service_action = act; + + ocdb->h.partition = cpu_to_be64(obj->partition); + ocdb->h.object = cpu_to_be64(obj->id); + ocdb->h.v2.length = cpu_to_be64(len); + ocdb->h.v2.start_address = cpu_to_be64(offset); +} + +static void _osd_req_encode_common(struct osd_request *or, + __be16 act, const struct osd_obj_id *obj, u64 offset, u64 len) +{ + if (osd_req_is_ver1(or)) + _osdv1_req_encode_common(or, act, obj, offset, len); + else + _osdv2_req_encode_common(or, act, obj, offset, len); +} + +/* + * Device commands + */ +/*TODO: void osd_req_set_master_seed_xchg(struct osd_request *, ...); */ +/*TODO: void osd_req_set_master_key(struct osd_request *, ...); */ + +void osd_req_format(struct osd_request *or, u64 tot_capacity) +{ + _osd_req_encode_common(or, OSD_ACT_FORMAT_OSD, &osd_root_object, 0, + tot_capacity); +} +EXPORT_SYMBOL(osd_req_format); + +int osd_req_list_dev_partitions(struct osd_request *or, + osd_id initial_id, struct osd_obj_id_list *list, unsigned nelem) +{ + return osd_req_list_partition_objects(or, 0, initial_id, list, nelem); +} +EXPORT_SYMBOL(osd_req_list_dev_partitions); + +static void _osd_req_encode_flush(struct osd_request *or, + enum osd_options_flush_scope_values op) +{ + struct osd_cdb_head *ocdb = osd_cdb_head(&or->cdb); + + ocdb->command_specific_options = op; +} + +void osd_req_flush_obsd(struct osd_request *or, + enum osd_options_flush_scope_values op) +{ + _osd_req_encode_common(or, OSD_ACT_FLUSH_OSD, &osd_root_object, 0, 0); + _osd_req_encode_flush(or, op); +} +EXPORT_SYMBOL(osd_req_flush_obsd); + +/*TODO: void osd_req_perform_scsi_command(struct osd_request *, + const u8 *cdb, ...); */ +/*TODO: void osd_req_task_management(struct osd_request *, ...); */ + +/* + * Partition commands + */ +static void _osd_req_encode_partition(struct osd_request *or, + __be16 act, osd_id partition) +{ + struct osd_obj_id par = { + .partition = partition, + .id = 0, + }; + + _osd_req_encode_common(or, act, &par, 0, 0); +} + +void osd_req_create_partition(struct osd_request *or, osd_id partition) +{ + _osd_req_encode_partition(or, OSD_ACT_CREATE_PARTITION, partition); +} +EXPORT_SYMBOL(osd_req_create_partition); + +void osd_req_remove_partition(struct osd_request *or, osd_id partition) +{ + _osd_req_encode_partition(or, OSD_ACT_REMOVE_PARTITION, partition); +} +EXPORT_SYMBOL(osd_req_remove_partition); + +/*TODO: void osd_req_set_partition_key(struct osd_request *, + osd_id partition, u8 new_key_id[OSD_CRYPTO_KEYID_SIZE], + u8 seed[OSD_CRYPTO_SEED_SIZE]); */ + +static int _osd_req_list_objects(struct osd_request *or, + __be16 action, const struct osd_obj_id *obj, osd_id initial_id, + struct osd_obj_id_list *list, unsigned nelem) +{ + struct request_queue *q = or->osd_dev->scsi_device->request_queue; + u64 len = nelem * sizeof(osd_id) + sizeof(*list); + struct bio *bio; + + _osd_req_encode_common(or, action, obj, (u64)initial_id, len); + + if (list->list_identifier) + _osd_req_encode_olist(or, list); + + WARN_ON(or->in.bio); + bio = bio_map_kern(q, list, len, or->alloc_flags); + if (!bio) { + OSD_ERR("!!! Failed to allocate list_objects BIO\n"); + return -ENOMEM; + } + + bio->bi_rw &= ~(1 << BIO_RW); + or->in.bio = bio; + or->in.total_bytes = bio->bi_size; + return 0; +} + +int osd_req_list_partition_collections(struct osd_request *or, + osd_id partition, osd_id initial_id, struct osd_obj_id_list *list, + unsigned nelem) +{ + struct osd_obj_id par = { + .partition = partition, + .id = 0, + }; + + return osd_req_list_collection_objects(or, &par, initial_id, list, + nelem); +} +EXPORT_SYMBOL(osd_req_list_partition_collections); + +int osd_req_list_partition_objects(struct osd_request *or, + osd_id partition, osd_id initial_id, struct osd_obj_id_list *list, + unsigned nelem) +{ + struct osd_obj_id par = { + .partition = partition, + .id = 0, + }; + + return _osd_req_list_objects(or, OSD_ACT_LIST, &par, initial_id, list, + nelem); +} +EXPORT_SYMBOL(osd_req_list_partition_objects); + +void osd_req_flush_partition(struct osd_request *or, + osd_id partition, enum osd_options_flush_scope_values op) +{ + _osd_req_encode_partition(or, OSD_ACT_FLUSH_PARTITION, partition); + _osd_req_encode_flush(or, op); +} +EXPORT_SYMBOL(osd_req_flush_partition); + +/* + * Collection commands + */ +/*TODO: void osd_req_create_collection(struct osd_request *, + const struct osd_obj_id *); */ +/*TODO: void osd_req_remove_collection(struct osd_request *, + const struct osd_obj_id *); */ + +int osd_req_list_collection_objects(struct osd_request *or, + const struct osd_obj_id *obj, osd_id initial_id, + struct osd_obj_id_list *list, unsigned nelem) +{ + return _osd_req_list_objects(or, OSD_ACT_LIST_COLLECTION, obj, + initial_id, list, nelem); +} +EXPORT_SYMBOL(osd_req_list_collection_objects); + +/*TODO: void query(struct osd_request *, ...); V2 */ + +void osd_req_flush_collection(struct osd_request *or, + const struct osd_obj_id *obj, enum osd_options_flush_scope_values op) +{ + _osd_req_encode_common(or, OSD_ACT_FLUSH_PARTITION, obj, 0, 0); + _osd_req_encode_flush(or, op); +} +EXPORT_SYMBOL(osd_req_flush_collection); + +/*TODO: void get_member_attrs(struct osd_request *, ...); V2 */ +/*TODO: void set_member_attrs(struct osd_request *, ...); V2 */ + +/* + * Object commands + */ +void osd_req_create_object(struct osd_request *or, struct osd_obj_id *obj) +{ + _osd_req_encode_common(or, OSD_ACT_CREATE, obj, 0, 0); +} +EXPORT_SYMBOL(osd_req_create_object); + +void osd_req_remove_object(struct osd_request *or, struct osd_obj_id *obj) +{ + _osd_req_encode_common(or, OSD_ACT_REMOVE, obj, 0, 0); +} +EXPORT_SYMBOL(osd_req_remove_object); + + +/*TODO: void osd_req_create_multi(struct osd_request *or, + struct osd_obj_id *first, struct osd_obj_id_list *list, unsigned nelem); +*/ + +void osd_req_write(struct osd_request *or, + const struct osd_obj_id *obj, struct bio *bio, u64 offset) +{ + _osd_req_encode_common(or, OSD_ACT_WRITE, obj, offset, bio->bi_size); + WARN_ON(or->out.bio || or->out.total_bytes); + bio->bi_rw |= (1 << BIO_RW); + or->out.bio = bio; + or->out.total_bytes = bio->bi_size; +} +EXPORT_SYMBOL(osd_req_write); + +/*TODO: void osd_req_append(struct osd_request *, + const struct osd_obj_id *, struct bio *data_out); */ +/*TODO: void osd_req_create_write(struct osd_request *, + const struct osd_obj_id *, struct bio *data_out, u64 offset); */ +/*TODO: void osd_req_clear(struct osd_request *, + const struct osd_obj_id *, u64 offset, u64 len); */ +/*TODO: void osd_req_punch(struct osd_request *, + const struct osd_obj_id *, u64 offset, u64 len); V2 */ + +void osd_req_flush_object(struct osd_request *or, + const struct osd_obj_id *obj, enum osd_options_flush_scope_values op, + /*V2*/ u64 offset, /*V2*/ u64 len) +{ + if (unlikely(osd_req_is_ver1(or) && (offset || len))) { + OSD_DEBUG("OSD Ver1 flush on specific range ignored\n"); + offset = 0; + len = 0; + } + + _osd_req_encode_common(or, OSD_ACT_FLUSH, obj, offset, len); + _osd_req_encode_flush(or, op); +} +EXPORT_SYMBOL(osd_req_flush_object); + +void osd_req_read(struct osd_request *or, + const struct osd_obj_id *obj, struct bio *bio, u64 offset) +{ + _osd_req_encode_common(or, OSD_ACT_READ, obj, offset, bio->bi_size); + WARN_ON(or->in.bio || or->in.total_bytes); + bio->bi_rw &= ~(1 << BIO_RW); + or->in.bio = bio; + or->in.total_bytes = bio->bi_size; +} +EXPORT_SYMBOL(osd_req_read); + +void osd_req_get_attributes(struct osd_request *or, + const struct osd_obj_id *obj) +{ + _osd_req_encode_common(or, OSD_ACT_GET_ATTRIBUTES, obj, 0, 0); +} +EXPORT_SYMBOL(osd_req_get_attributes); + +void osd_req_set_attributes(struct osd_request *or, + const struct osd_obj_id *obj) +{ + _osd_req_encode_common(or, OSD_ACT_SET_ATTRIBUTES, obj, 0, 0); +} +EXPORT_SYMBOL(osd_req_set_attributes); + +/* + * Attributes List-mode + */ + +int osd_req_add_set_attr_list(struct osd_request *or, + const struct osd_attr *oa, unsigned nelem) +{ + unsigned total_bytes = or->set_attr.total_bytes; + void *attr_last; + int ret; + + if (or->attributes_mode && + or->attributes_mode != OSD_CDB_GET_SET_ATTR_LISTS) { + WARN_ON(1); + return -EINVAL; + } + or->attributes_mode = OSD_CDB_GET_SET_ATTR_LISTS; + + if (!total_bytes) { /* first-time: allocate and put list header */ + total_bytes = _osd_req_sizeof_alist_header(or); + ret = _alloc_set_attr_list(or, oa, nelem, total_bytes); + if (ret) + return ret; + _osd_req_set_alist_type(or, or->set_attr.buff, + OSD_ATTR_LIST_SET_RETRIEVE); + } + attr_last = or->set_attr.buff + total_bytes; + + for (; nelem; --nelem) { + struct osd_attributes_list_element *attr; + unsigned elem_size = _osd_req_alist_elem_size(or, oa->len); + + total_bytes += elem_size; + if (unlikely(or->set_attr.alloc_size < total_bytes)) { + or->set_attr.total_bytes = total_bytes - elem_size; + ret = _alloc_set_attr_list(or, oa, nelem, total_bytes); + if (ret) + return ret; + attr_last = + or->set_attr.buff + or->set_attr.total_bytes; + } + + attr = attr_last; + attr->attr_page = cpu_to_be32(oa->attr_page); + attr->attr_id = cpu_to_be32(oa->attr_id); + attr->attr_bytes = cpu_to_be16(oa->len); + memcpy(attr->attr_val, oa->val_ptr, oa->len); + + attr_last += elem_size; + ++oa; + } + + or->set_attr.total_bytes = total_bytes; + return 0; +} +EXPORT_SYMBOL(osd_req_add_set_attr_list); + +static int _append_map_kern(struct request *req, + void *buff, unsigned len, gfp_t flags) +{ + struct bio *bio; + int ret; + + bio = bio_map_kern(req->q, buff, len, flags); + if (IS_ERR(bio)) { + OSD_ERR("Failed bio_map_kern(%p, %d) => %ld\n", buff, len, + PTR_ERR(bio)); + return PTR_ERR(bio); + } + ret = blk_rq_append_bio(req->q, req, bio); + if (ret) { + OSD_ERR("Failed blk_rq_append_bio(%p) => %d\n", bio, ret); + bio_put(bio); + } + return ret; +} + +static int _req_append_segment(struct osd_request *or, + unsigned padding, struct _osd_req_data_segment *seg, + struct _osd_req_data_segment *last_seg, struct _osd_io_info *io) +{ + void *pad_buff; + int ret; + + if (padding) { + /* check if we can just add it to last buffer */ + if (last_seg && + (padding <= last_seg->alloc_size - last_seg->total_bytes)) + pad_buff = last_seg->buff + last_seg->total_bytes; + else + pad_buff = io->pad_buff; + + ret = _append_map_kern(io->req, pad_buff, padding, + or->alloc_flags); + if (ret) + return ret; + io->total_bytes += padding; + } + + ret = _append_map_kern(io->req, seg->buff, seg->total_bytes, + or->alloc_flags); + if (ret) + return ret; + + io->total_bytes += seg->total_bytes; + OSD_DEBUG("padding=%d buff=%p total_bytes=%d\n", padding, seg->buff, + seg->total_bytes); + return 0; +} + +static int _osd_req_finalize_set_attr_list(struct osd_request *or) +{ + struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb); + unsigned padding; + int ret; + + if (!or->set_attr.total_bytes) { + cdbh->attrs_list.set_attr_offset = OSD_OFFSET_UNUSED; + return 0; + } + + cdbh->attrs_list.set_attr_bytes = cpu_to_be32(or->set_attr.total_bytes); + cdbh->attrs_list.set_attr_offset = + osd_req_encode_offset(or, or->out.total_bytes, &padding); + + ret = _req_append_segment(or, padding, &or->set_attr, + or->out.last_seg, &or->out); + if (ret) + return ret; + + or->out.last_seg = &or->set_attr; + return 0; +} + +int osd_req_add_get_attr_list(struct osd_request *or, + const struct osd_attr *oa, unsigned nelem) +{ + unsigned total_bytes = or->enc_get_attr.total_bytes; + void *attr_last; + int ret; + + if (or->attributes_mode && + or->attributes_mode != OSD_CDB_GET_SET_ATTR_LISTS) { + WARN_ON(1); + return -EINVAL; + } + or->attributes_mode = OSD_CDB_GET_SET_ATTR_LISTS; + + /* first time calc data-in list header size */ + if (!or->get_attr.total_bytes) + or->get_attr.total_bytes = _osd_req_sizeof_alist_header(or); + + /* calc data-out info */ + if (!total_bytes) { /* first-time: allocate and put list header */ + unsigned max_bytes; + + total_bytes = _osd_req_sizeof_alist_header(or); + max_bytes = total_bytes + + nelem * sizeof(struct osd_attributes_list_attrid); + ret = _alloc_get_attr_desc(or, max_bytes); + if (ret) + return ret; + + _osd_req_set_alist_type(or, or->enc_get_attr.buff, + OSD_ATTR_LIST_GET); + } + attr_last = or->enc_get_attr.buff + total_bytes; + + for (; nelem; --nelem) { + struct osd_attributes_list_attrid *attrid; + const unsigned cur_size = sizeof(*attrid); + + total_bytes += cur_size; + if (unlikely(or->enc_get_attr.alloc_size < total_bytes)) { + or->enc_get_attr.total_bytes = total_bytes - cur_size; + ret = _alloc_get_attr_desc(or, + total_bytes + nelem * sizeof(*attrid)); + if (ret) + return ret; + attr_last = or->enc_get_attr.buff + + or->enc_get_attr.total_bytes; + } + + attrid = attr_last; + attrid->attr_page = cpu_to_be32(oa->attr_page); + attrid->attr_id = cpu_to_be32(oa->attr_id); + + attr_last += cur_size; + + /* calc data-in size */ + or->get_attr.total_bytes += + _osd_req_alist_elem_size(or, oa->len); + ++oa; + } + + or->enc_get_attr.total_bytes = total_bytes; + + OSD_DEBUG( + "get_attr.total_bytes=%u(%u) enc_get_attr.total_bytes=%u(%Zu)\n", + or->get_attr.total_bytes, + or->get_attr.total_bytes - _osd_req_sizeof_alist_header(or), + or->enc_get_attr.total_bytes, + (or->enc_get_attr.total_bytes - _osd_req_sizeof_alist_header(or)) + / sizeof(struct osd_attributes_list_attrid)); + + return 0; +} +EXPORT_SYMBOL(osd_req_add_get_attr_list); + +static int _osd_req_finalize_get_attr_list(struct osd_request *or) +{ + struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb); + unsigned out_padding; + unsigned in_padding; + int ret; + + if (!or->enc_get_attr.total_bytes) { + cdbh->attrs_list.get_attr_desc_offset = OSD_OFFSET_UNUSED; + cdbh->attrs_list.get_attr_offset = OSD_OFFSET_UNUSED; + return 0; + } + + ret = _alloc_get_attr_list(or); + if (ret) + return ret; + + /* The out-going buffer info update */ + OSD_DEBUG("out-going\n"); + cdbh->attrs_list.get_attr_desc_bytes = + cpu_to_be32(or->enc_get_attr.total_bytes); + + cdbh->attrs_list.get_attr_desc_offset = + osd_req_encode_offset(or, or->out.total_bytes, &out_padding); + + ret = _req_append_segment(or, out_padding, &or->enc_get_attr, + or->out.last_seg, &or->out); + if (ret) + return ret; + or->out.last_seg = &or->enc_get_attr; + + /* The incoming buffer info update */ + OSD_DEBUG("in-coming\n"); + cdbh->attrs_list.get_attr_alloc_length = + cpu_to_be32(or->get_attr.total_bytes); + + cdbh->attrs_list.get_attr_offset = + osd_req_encode_offset(or, or->in.total_bytes, &in_padding); + + ret = _req_append_segment(or, in_padding, &or->get_attr, NULL, + &or->in); + if (ret) + return ret; + or->in.last_seg = &or->get_attr; + + return 0; +} + +int osd_req_decode_get_attr_list(struct osd_request *or, + struct osd_attr *oa, int *nelem, void **iterator) +{ + unsigned cur_bytes, returned_bytes; + int n; + const unsigned sizeof_attr_list = _osd_req_sizeof_alist_header(or); + void *cur_p; + + if (!_osd_req_is_alist_type(or, or->get_attr.buff, + OSD_ATTR_LIST_SET_RETRIEVE)) { + oa->attr_page = 0; + oa->attr_id = 0; + oa->val_ptr = NULL; + oa->len = 0; + *iterator = NULL; + return 0; + } + + if (*iterator) { + BUG_ON((*iterator < or->get_attr.buff) || + (or->get_attr.buff + or->get_attr.alloc_size < *iterator)); + cur_p = *iterator; + cur_bytes = (*iterator - or->get_attr.buff) - sizeof_attr_list; + returned_bytes = or->get_attr.total_bytes; + } else { /* first time decode the list header */ + cur_bytes = sizeof_attr_list; + returned_bytes = _osd_req_alist_size(or, or->get_attr.buff) + + sizeof_attr_list; + + cur_p = or->get_attr.buff + sizeof_attr_list; + + if (returned_bytes > or->get_attr.alloc_size) { + OSD_DEBUG("target report: space was not big enough! " + "Allocate=%u Needed=%u\n", + or->get_attr.alloc_size, + returned_bytes + sizeof_attr_list); + + returned_bytes = + or->get_attr.alloc_size - sizeof_attr_list; + } + or->get_attr.total_bytes = returned_bytes; + } + + for (n = 0; (n < *nelem) && (cur_bytes < returned_bytes); ++n) { + struct osd_attributes_list_element *attr = cur_p; + unsigned inc; + + oa->len = be16_to_cpu(attr->attr_bytes); + inc = _osd_req_alist_elem_size(or, oa->len); + OSD_DEBUG("oa->len=%d inc=%d cur_bytes=%d\n", + oa->len, inc, cur_bytes); + cur_bytes += inc; + if (cur_bytes > returned_bytes) { + OSD_ERR("BAD FOOD from target. list not valid!" + "c=%d r=%d n=%d\n", + cur_bytes, returned_bytes, n); + oa->val_ptr = NULL; + break; + } + + oa->attr_page = be32_to_cpu(attr->attr_page); + oa->attr_id = be32_to_cpu(attr->attr_id); + oa->val_ptr = attr->attr_val; + + cur_p += inc; + ++oa; + } + + *iterator = (returned_bytes - cur_bytes) ? cur_p : NULL; + *nelem = n; + return returned_bytes - cur_bytes; +} +EXPORT_SYMBOL(osd_req_decode_get_attr_list); + +/* + * Attributes Page-mode + */ + +int osd_req_add_get_attr_page(struct osd_request *or, + u32 page_id, void *attar_page, unsigned max_page_len, + const struct osd_attr *set_one_attr) +{ + struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb); + + if (or->attributes_mode && + or->attributes_mode != OSD_CDB_GET_ATTR_PAGE_SET_ONE) { + WARN_ON(1); + return -EINVAL; + } + or->attributes_mode = OSD_CDB_GET_ATTR_PAGE_SET_ONE; + + or->get_attr.buff = attar_page; + or->get_attr.total_bytes = max_page_len; + + or->set_attr.buff = set_one_attr->val_ptr; + or->set_attr.total_bytes = set_one_attr->len; + + cdbh->attrs_page.get_attr_page = cpu_to_be32(page_id); + cdbh->attrs_page.get_attr_alloc_length = cpu_to_be32(max_page_len); + /* ocdb->attrs_page.get_attr_offset; */ + + cdbh->attrs_page.set_attr_page = cpu_to_be32(set_one_attr->attr_page); + cdbh->attrs_page.set_attr_id = cpu_to_be32(set_one_attr->attr_id); + cdbh->attrs_page.set_attr_length = cpu_to_be32(set_one_attr->len); + /* ocdb->attrs_page.set_attr_offset; */ + return 0; +} +EXPORT_SYMBOL(osd_req_add_get_attr_page); + +static int _osd_req_finalize_attr_page(struct osd_request *or) +{ + struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb); + unsigned in_padding, out_padding; + int ret; + + /* returned page */ + cdbh->attrs_page.get_attr_offset = + osd_req_encode_offset(or, or->in.total_bytes, &in_padding); + + ret = _req_append_segment(or, in_padding, &or->get_attr, NULL, + &or->in); + if (ret) + return ret; + + /* set one value */ + cdbh->attrs_page.set_attr_offset = + osd_req_encode_offset(or, or->out.total_bytes, &out_padding); + + ret = _req_append_segment(or, out_padding, &or->enc_get_attr, NULL, + &or->out); + return ret; +} + +static int _osd_req_finalize_data_integrity(struct osd_request *or, + bool has_in, bool has_out, const u8 *cap_key) +{ + struct osd_security_parameters *sec_parms = _osd_req_sec_params(or); + int ret; + + if (!osd_is_sec_alldata(sec_parms)) + return 0; + + if (has_out) { + struct _osd_req_data_segment seg = { + .buff = &or->out_data_integ, + .total_bytes = sizeof(or->out_data_integ), + }; + unsigned pad; + + or->out_data_integ.data_bytes = cpu_to_be64( + or->out.bio ? or->out.bio->bi_size : 0); + or->out_data_integ.set_attributes_bytes = cpu_to_be64( + or->set_attr.total_bytes); + or->out_data_integ.get_attributes_bytes = cpu_to_be64( + or->enc_get_attr.total_bytes); + + sec_parms->data_out_integrity_check_offset = + osd_req_encode_offset(or, or->out.total_bytes, &pad); + + ret = _req_append_segment(or, pad, &seg, or->out.last_seg, + &or->out); + if (ret) + return ret; + or->out.last_seg = NULL; + + /* they are now all chained to request sign them all together */ + osd_sec_sign_data(&or->out_data_integ, or->out.req->bio, + cap_key); + } + + if (has_in) { + struct _osd_req_data_segment seg = { + .buff = &or->in_data_integ, + .total_bytes = sizeof(or->in_data_integ), + }; + unsigned pad; + + sec_parms->data_in_integrity_check_offset = + osd_req_encode_offset(or, or->in.total_bytes, &pad); + + ret = _req_append_segment(or, pad, &seg, or->in.last_seg, + &or->in); + if (ret) + return ret; + + or->in.last_seg = NULL; + } + + return 0; +} + +/* + * osd_finalize_request and helpers + */ + +static int _init_blk_request(struct osd_request *or, + bool has_in, bool has_out) +{ + gfp_t flags = or->alloc_flags; + struct scsi_device *scsi_device = or->osd_dev->scsi_device; + struct request_queue *q = scsi_device->request_queue; + struct request *req; + int ret = -ENOMEM; + + req = blk_get_request(q, has_out, flags); + if (!req) + goto out; + + or->request = req; + req->cmd_type = REQ_TYPE_BLOCK_PC; + req->timeout = or->timeout; + req->retries = or->retries; + req->sense = or->sense; + req->sense_len = 0; + + if (has_out) { + or->out.req = req; + if (has_in) { + /* allocate bidi request */ + req = blk_get_request(q, READ, flags); + if (!req) { + OSD_DEBUG("blk_get_request for bidi failed\n"); + goto out; + } + req->cmd_type = REQ_TYPE_BLOCK_PC; + or->in.req = or->request->next_rq = req; + } + } else if (has_in) + or->in.req = req; + + ret = 0; +out: + OSD_DEBUG("or=%p has_in=%d has_out=%d => %d, %p\n", + or, has_in, has_out, ret, or->request); + return ret; +} + +int osd_finalize_request(struct osd_request *or, + u8 options, const void *cap, const u8 *cap_key) +{ + struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb); + bool has_in, has_out; + int ret; + + if (options & OSD_REQ_FUA) + cdbh->options |= OSD_CDB_FUA; + + if (options & OSD_REQ_DPO) + cdbh->options |= OSD_CDB_DPO; + + if (options & OSD_REQ_BYPASS_TIMESTAMPS) + cdbh->timestamp_control = OSD_CDB_BYPASS_TIMESTAMPS; + + osd_set_caps(&or->cdb, cap); + + has_in = or->in.bio || or->get_attr.total_bytes; + has_out = or->out.bio || or->set_attr.total_bytes || + or->enc_get_attr.total_bytes; + + ret = _init_blk_request(or, has_in, has_out); + if (ret) { + OSD_DEBUG("_init_blk_request failed\n"); + return ret; + } + + if (or->out.bio) { + ret = blk_rq_append_bio(or->request->q, or->out.req, + or->out.bio); + if (ret) { + OSD_DEBUG("blk_rq_append_bio out failed\n"); + return ret; + } + OSD_DEBUG("out bytes=%llu (bytes_req=%u)\n", + _LLU(or->out.total_bytes), or->out.req->data_len); + } + if (or->in.bio) { + ret = blk_rq_append_bio(or->request->q, or->in.req, or->in.bio); + if (ret) { + OSD_DEBUG("blk_rq_append_bio in failed\n"); + return ret; + } + OSD_DEBUG("in bytes=%llu (bytes_req=%u)\n", + _LLU(or->in.total_bytes), or->in.req->data_len); + } + + or->out.pad_buff = sg_out_pad_buffer; + or->in.pad_buff = sg_in_pad_buffer; + + if (!or->attributes_mode) + or->attributes_mode = OSD_CDB_GET_SET_ATTR_LISTS; + cdbh->command_specific_options |= or->attributes_mode; + if (or->attributes_mode == OSD_CDB_GET_ATTR_PAGE_SET_ONE) { + ret = _osd_req_finalize_attr_page(or); + } else { + /* TODO: I think that for the GET_ATTR command these 2 should + * be reversed to keep them in execution order (for embeded + * targets with low memory footprint) + */ + ret = _osd_req_finalize_set_attr_list(or); + if (ret) { + OSD_DEBUG("_osd_req_finalize_set_attr_list failed\n"); + return ret; + } + + ret = _osd_req_finalize_get_attr_list(or); + if (ret) { + OSD_DEBUG("_osd_req_finalize_get_attr_list failed\n"); + return ret; + } + } + + ret = _osd_req_finalize_data_integrity(or, has_in, has_out, cap_key); + if (ret) + return ret; + + osd_sec_sign_cdb(&or->cdb, cap_key); + + or->request->cmd = or->cdb.buff; + or->request->cmd_len = _osd_req_cdb_len(or); + + return 0; +} +EXPORT_SYMBOL(osd_finalize_request); + +#define OSD_SENSE_PRINT1(fmt, a...) \ + do { \ + if (__cur_sense_need_output) \ + OSD_ERR(fmt, ##a); \ + } while (0) + +#define OSD_SENSE_PRINT2(fmt, a...) OSD_SENSE_PRINT1(" " fmt, ##a) + +int osd_req_decode_sense_full(struct osd_request *or, + struct osd_sense_info *osi, bool silent, + struct osd_obj_id *bad_obj_list __unused, int max_obj __unused, + struct osd_attr *bad_attr_list, int max_attr) +{ + int sense_len, original_sense_len; + struct osd_sense_info local_osi; + struct scsi_sense_descriptor_based *ssdb; + void *cur_descriptor; +#if (CONFIG_SCSI_OSD_DPRINT_SENSE == 0) + const bool __cur_sense_need_output = false; +#else + bool __cur_sense_need_output = !silent; +#endif + + if (!or->request->errors) + return 0; + + ssdb = or->request->sense; + sense_len = or->request->sense_len; + if ((sense_len < (int)sizeof(*ssdb) || !ssdb->sense_key)) { + OSD_ERR("Block-layer returned error(0x%x) but " + "sense_len(%u) || key(%d) is empty\n", + or->request->errors, sense_len, ssdb->sense_key); + return -EIO; + } + + if ((ssdb->response_code != 0x72) && (ssdb->response_code != 0x73)) { + OSD_ERR("Unrecognized scsi sense: rcode=%x length=%d\n", + ssdb->response_code, sense_len); + return -EIO; + } + + osi = osi ? : &local_osi; + memset(osi, 0, sizeof(*osi)); + osi->key = ssdb->sense_key; + osi->additional_code = be16_to_cpu(ssdb->additional_sense_code); + original_sense_len = ssdb->additional_sense_length + 8; + +#if (CONFIG_SCSI_OSD_DPRINT_SENSE == 1) + if (__cur_sense_need_output) + __cur_sense_need_output = (osi->key > scsi_sk_recovered_error); +#endif + OSD_SENSE_PRINT1("Main Sense information key=0x%x length(%d, %d) " + "additional_code=0x%x\n", + osi->key, original_sense_len, sense_len, + osi->additional_code); + + if (original_sense_len < sense_len) + sense_len = original_sense_len; + + cur_descriptor = ssdb->ssd; + sense_len -= sizeof(*ssdb); + while (sense_len > 0) { + struct scsi_sense_descriptor *ssd = cur_descriptor; + int cur_len = ssd->additional_length + 2; + + sense_len -= cur_len; + + if (sense_len < 0) + break; /* sense was truncated */ + + switch (ssd->descriptor_type) { + case scsi_sense_information: + case scsi_sense_command_specific_information: + { + struct scsi_sense_command_specific_data_descriptor + *sscd = cur_descriptor; + + osi->command_info = + get_unaligned_be64(&sscd->information) ; + OSD_SENSE_PRINT2( + "command_specific_information 0x%llx \n", + _LLU(osi->command_info)); + break; + } + case scsi_sense_key_specific: + { + struct scsi_sense_key_specific_data_descriptor + *ssks = cur_descriptor; + + osi->sense_info = get_unaligned_be16(&ssks->value); + OSD_SENSE_PRINT2( + "sense_key_specific_information %u" + "sksv_cd_bpv_bp (0x%x)\n", + osi->sense_info, ssks->sksv_cd_bpv_bp); + break; + } + case osd_sense_object_identification: + { /*FIXME: Keep first not last, Store in array*/ + struct osd_sense_identification_data_descriptor + *osidd = cur_descriptor; + + osi->not_initiated_command_functions = + le32_to_cpu(osidd->not_initiated_functions); + osi->completed_command_functions = + le32_to_cpu(osidd->completed_functions); + osi->obj.partition = be64_to_cpu(osidd->partition_id); + osi->obj.id = be64_to_cpu(osidd->object_id); + OSD_SENSE_PRINT2( + "object_identification pid=0x%llx oid=0x%llx\n", + _LLU(osi->obj.partition), _LLU(osi->obj.id)); + OSD_SENSE_PRINT2( + "not_initiated_bits(%x) " + "completed_command_bits(%x)\n", + osi->not_initiated_command_functions, + osi->completed_command_functions); + break; + } + case osd_sense_response_integrity_check: + { + struct osd_sense_response_integrity_check_descriptor + *osricd = cur_descriptor; + const unsigned len = + sizeof(osricd->integrity_check_value); + char key_dump[len*4 + 2]; /* 2nibbles+space+ASCII */ + + hex_dump_to_buffer(osricd->integrity_check_value, len, + 32, 1, key_dump, sizeof(key_dump), true); + OSD_SENSE_PRINT2("response_integrity [%s]\n", key_dump); + } + case osd_sense_attribute_identification: + { + struct osd_sense_attributes_data_descriptor + *osadd = cur_descriptor; + int len = min(cur_len, sense_len); + int i = 0; + struct osd_sense_attr *pattr = osadd->sense_attrs; + + while (len < 0) { + u32 attr_page = be32_to_cpu(pattr->attr_page); + u32 attr_id = be32_to_cpu(pattr->attr_id); + + if (i++ == 0) { + osi->attr.attr_page = attr_page; + osi->attr.attr_id = attr_id; + } + + if (bad_attr_list && max_attr) { + bad_attr_list->attr_page = attr_page; + bad_attr_list->attr_id = attr_id; + bad_attr_list++; + max_attr--; + } + OSD_SENSE_PRINT2( + "osd_sense_attribute_identification" + "attr_page=0x%x attr_id=0x%x\n", + attr_page, attr_id); + } + } + /*These are not legal for OSD*/ + case scsi_sense_field_replaceable_unit: + OSD_SENSE_PRINT2("scsi_sense_field_replaceable_unit\n"); + break; + case scsi_sense_stream_commands: + OSD_SENSE_PRINT2("scsi_sense_stream_commands\n"); + break; + case scsi_sense_block_commands: + OSD_SENSE_PRINT2("scsi_sense_block_commands\n"); + break; + case scsi_sense_ata_return: + OSD_SENSE_PRINT2("scsi_sense_ata_return\n"); + break; + default: + if (ssd->descriptor_type <= scsi_sense_Reserved_last) + OSD_SENSE_PRINT2( + "scsi_sense Reserved descriptor (0x%x)", + ssd->descriptor_type); + else + OSD_SENSE_PRINT2( + "scsi_sense Vendor descriptor (0x%x)", + ssd->descriptor_type); + } + + cur_descriptor += cur_len; + } + + return (osi->key > scsi_sk_recovered_error) ? -EIO : 0; +} +EXPORT_SYMBOL(osd_req_decode_sense_full); + +/* + * Implementation of osd_sec.h API + * TODO: Move to a separate osd_sec.c file at a later stage. + */ + +enum { OSD_SEC_CAP_V1_ALL_CAPS = + OSD_SEC_CAP_APPEND | OSD_SEC_CAP_OBJ_MGMT | OSD_SEC_CAP_REMOVE | + OSD_SEC_CAP_CREATE | OSD_SEC_CAP_SET_ATTR | OSD_SEC_CAP_GET_ATTR | + OSD_SEC_CAP_WRITE | OSD_SEC_CAP_READ | OSD_SEC_CAP_POL_SEC | + OSD_SEC_CAP_GLOBAL | OSD_SEC_CAP_DEV_MGMT +}; + +enum { OSD_SEC_CAP_V2_ALL_CAPS = + OSD_SEC_CAP_V1_ALL_CAPS | OSD_SEC_CAP_QUERY | OSD_SEC_CAP_M_OBJECT +}; + +void osd_sec_init_nosec_doall_caps(void *caps, + const struct osd_obj_id *obj, bool is_collection, const bool is_v1) +{ + struct osd_capability *cap = caps; + u8 type; + u8 descriptor_type; + + if (likely(obj->id)) { + if (unlikely(is_collection)) { + type = OSD_SEC_OBJ_COLLECTION; + descriptor_type = is_v1 ? OSD_SEC_OBJ_DESC_OBJ : + OSD_SEC_OBJ_DESC_COL; + } else { + type = OSD_SEC_OBJ_USER; + descriptor_type = OSD_SEC_OBJ_DESC_OBJ; + } + WARN_ON(!obj->partition); + } else { + type = obj->partition ? OSD_SEC_OBJ_PARTITION : + OSD_SEC_OBJ_ROOT; + descriptor_type = OSD_SEC_OBJ_DESC_PAR; + } + + memset(cap, 0, sizeof(*cap)); + + cap->h.format = OSD_SEC_CAP_FORMAT_VER1; + cap->h.integrity_algorithm__key_version = 0; /* MAKE_BYTE(0, 0); */ + cap->h.security_method = OSD_SEC_NOSEC; +/* cap->expiration_time; + cap->AUDIT[30-10]; + cap->discriminator[42-30]; + cap->object_created_time; */ + cap->h.object_type = type; + osd_sec_set_caps(&cap->h, OSD_SEC_CAP_V1_ALL_CAPS); + cap->h.object_descriptor_type = descriptor_type; + cap->od.obj_desc.policy_access_tag = 0; + cap->od.obj_desc.allowed_partition_id = cpu_to_be64(obj->partition); + cap->od.obj_desc.allowed_object_id = cpu_to_be64(obj->id); +} +EXPORT_SYMBOL(osd_sec_init_nosec_doall_caps); + +/* FIXME: Extract version from caps pointer. + * Also Pete's target only supports caps from OSDv1 for now + */ +void osd_set_caps(struct osd_cdb *cdb, const void *caps) +{ + bool is_ver1 = true; + /* NOTE: They start at same address */ + memcpy(&cdb->v1.caps, caps, is_ver1 ? OSDv1_CAP_LEN : OSD_CAP_LEN); +} + +bool osd_is_sec_alldata(struct osd_security_parameters *sec_parms __unused) +{ + return false; +} + +void osd_sec_sign_cdb(struct osd_cdb *ocdb __unused, const u8 *cap_key __unused) +{ +} + +void osd_sec_sign_data(void *data_integ __unused, + struct bio *bio __unused, const u8 *cap_key __unused) +{ +} + +/* + * Declared in osd_protocol.h + * 4.12.5 Data-In and Data-Out buffer offsets + * byte offset = mantissa * (2^(exponent+8)) + * Returns the smallest allowed encoded offset that contains given @offset + * The actual encoded offset returned is @offset + *@padding. + */ +osd_cdb_offset __osd_encode_offset( + u64 offset, unsigned *padding, int min_shift, int max_shift) +{ + u64 try_offset = -1, mod, align; + osd_cdb_offset be32_offset; + int shift; + + *padding = 0; + if (!offset) + return 0; + + for (shift = min_shift; shift < max_shift; ++shift) { + try_offset = offset >> shift; + if (try_offset < (1 << OSD_OFFSET_MAX_BITS)) + break; + } + + BUG_ON(shift == max_shift); + + align = 1 << shift; + mod = offset & (align - 1); + if (mod) { + *padding = align - mod; + try_offset += 1; + } + + try_offset |= ((shift - 8) & 0xf) << 28; + be32_offset = cpu_to_be32((u32)try_offset); + + OSD_DEBUG("offset=%llu mantissa=%llu exp=%d encoded=%x pad=%d\n", + _LLU(offset), _LLU(try_offset & 0x0FFFFFFF), shift, + be32_offset, *padding); + return be32_offset; +} diff --git a/drivers/scsi/osd/osd_uld.c b/drivers/scsi/osd/osd_uld.c new file mode 100644 index 00000000000..f644c9571ea --- /dev/null +++ b/drivers/scsi/osd/osd_uld.c @@ -0,0 +1,481 @@ +/* + * osd_uld.c - OSD Upper Layer Driver + * + * A Linux driver module that registers as a SCSI ULD and probes + * for OSD type SCSI devices. + * It's main function is to export osd devices to in-kernel users like + * osdfs and pNFS-objects-LD. It also provides one ioctl for running + * in Kernel tests. + * + * Copyright (C) 2008 Panasas Inc. All rights reserved. + * + * Authors: + * Boaz Harrosh <bharrosh@panasas.com> + * Benny Halevy <bhalevy@panasas.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Panasas company nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <linux/namei.h> +#include <linux/cdev.h> +#include <linux/fs.h> +#include <linux/module.h> +#include <linux/device.h> +#include <linux/idr.h> +#include <linux/major.h> + +#include <scsi/scsi.h> +#include <scsi/scsi_driver.h> +#include <scsi/scsi_device.h> +#include <scsi/scsi_ioctl.h> + +#include <scsi/osd_initiator.h> +#include <scsi/osd_sec.h> + +#include "osd_debug.h" + +#ifndef TYPE_OSD +# define TYPE_OSD 0x11 +#endif + +#ifndef SCSI_OSD_MAJOR +# define SCSI_OSD_MAJOR 260 +#endif +#define SCSI_OSD_MAX_MINOR 64 + +static const char osd_name[] = "osd"; +static const char *osd_version_string = "open-osd 0.1.0"; +const char osd_symlink[] = "scsi_osd"; + +MODULE_AUTHOR("Boaz Harrosh <bharrosh@panasas.com>"); +MODULE_DESCRIPTION("open-osd Upper-Layer-Driver osd.ko"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_CHARDEV_MAJOR(SCSI_OSD_MAJOR); +MODULE_ALIAS_SCSI_DEVICE(TYPE_OSD); + +struct osd_uld_device { + int minor; + struct kref kref; + struct cdev cdev; + struct osd_dev od; + struct gendisk *disk; + struct device *class_member; +}; + +static void __uld_get(struct osd_uld_device *oud); +static void __uld_put(struct osd_uld_device *oud); + +/* + * Char Device operations + */ + +static int osd_uld_open(struct inode *inode, struct file *file) +{ + struct osd_uld_device *oud = container_of(inode->i_cdev, + struct osd_uld_device, cdev); + + __uld_get(oud); + /* cache osd_uld_device on file handle */ + file->private_data = oud; + OSD_DEBUG("osd_uld_open %p\n", oud); + return 0; +} + +static int osd_uld_release(struct inode *inode, struct file *file) +{ + struct osd_uld_device *oud = file->private_data; + + OSD_DEBUG("osd_uld_release %p\n", file->private_data); + file->private_data = NULL; + __uld_put(oud); + return 0; +} + +/* FIXME: Only one vector for now */ +unsigned g_test_ioctl; +do_test_fn *g_do_test; + +int osduld_register_test(unsigned ioctl, do_test_fn *do_test) +{ + if (g_test_ioctl) + return -EINVAL; + + g_test_ioctl = ioctl; + g_do_test = do_test; + return 0; +} +EXPORT_SYMBOL(osduld_register_test); + +void osduld_unregister_test(unsigned ioctl) +{ + if (ioctl == g_test_ioctl) { + g_test_ioctl = 0; + g_do_test = NULL; + } +} +EXPORT_SYMBOL(osduld_unregister_test); + +static do_test_fn *_find_ioctl(unsigned cmd) +{ + if (g_test_ioctl == cmd) + return g_do_test; + else + return NULL; +} + +static long osd_uld_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct osd_uld_device *oud = file->private_data; + int ret; + do_test_fn *do_test; + + do_test = _find_ioctl(cmd); + if (do_test) + ret = do_test(&oud->od, cmd, arg); + else { + OSD_ERR("Unknown ioctl %d: osd_uld_device=%p\n", cmd, oud); + ret = -ENOIOCTLCMD; + } + return ret; +} + +static const struct file_operations osd_fops = { + .owner = THIS_MODULE, + .open = osd_uld_open, + .release = osd_uld_release, + .unlocked_ioctl = osd_uld_ioctl, +}; + +struct osd_dev *osduld_path_lookup(const char *path) +{ + struct nameidata nd; + struct inode *inode; + struct cdev *cdev; + struct osd_uld_device *uninitialized_var(oud); + int error; + + if (!path || !*path) { + OSD_ERR("Mount with !path || !*path\n"); + return ERR_PTR(-EINVAL); + } + + error = path_lookup(path, LOOKUP_FOLLOW, &nd); + if (error) { + OSD_ERR("path_lookup of %s faild=>%d\n", path, error); + return ERR_PTR(error); + } + + inode = nd.path.dentry->d_inode; + error = -EINVAL; /* Not the right device e.g osd_uld_device */ + if (!S_ISCHR(inode->i_mode)) { + OSD_DEBUG("!S_ISCHR()\n"); + goto out; + } + + cdev = inode->i_cdev; + if (!cdev) { + OSD_ERR("Before mounting an OSD Based filesystem\n"); + OSD_ERR(" user-mode must open+close the %s device\n", path); + OSD_ERR(" Example: bash: echo < %s\n", path); + goto out; + } + + /* The Magic wand. Is it our char-dev */ + /* TODO: Support sg devices */ + if (cdev->owner != THIS_MODULE) { + OSD_ERR("Error mounting %s - is not an OSD device\n", path); + goto out; + } + + oud = container_of(cdev, struct osd_uld_device, cdev); + + __uld_get(oud); + error = 0; + +out: + path_put(&nd.path); + return error ? ERR_PTR(error) : &oud->od; +} +EXPORT_SYMBOL(osduld_path_lookup); + +void osduld_put_device(struct osd_dev *od) +{ + if (od) { + struct osd_uld_device *oud = container_of(od, + struct osd_uld_device, od); + + __uld_put(oud); + } +} +EXPORT_SYMBOL(osduld_put_device); + +/* + * Scsi Device operations + */ + +static int __detect_osd(struct osd_uld_device *oud) +{ + struct scsi_device *scsi_device = oud->od.scsi_device; + char caps[OSD_CAP_LEN]; + int error; + + /* sending a test_unit_ready as first command seems to be needed + * by some targets + */ + OSD_DEBUG("start scsi_test_unit_ready %p %p %p\n", + oud, scsi_device, scsi_device->request_queue); + error = scsi_test_unit_ready(scsi_device, 10*HZ, 5, NULL); + if (error) + OSD_ERR("warning: scsi_test_unit_ready failed\n"); + + osd_sec_init_nosec_doall_caps(caps, &osd_root_object, false, true); + if (osd_auto_detect_ver(&oud->od, caps)) + return -ENODEV; + + return 0; +} + +static struct class *osd_sysfs_class; +static DEFINE_IDA(osd_minor_ida); + +static int osd_probe(struct device *dev) +{ + struct scsi_device *scsi_device = to_scsi_device(dev); + struct gendisk *disk; + struct osd_uld_device *oud; + int minor; + int error; + + if (scsi_device->type != TYPE_OSD) + return -ENODEV; + + do { + if (!ida_pre_get(&osd_minor_ida, GFP_KERNEL)) + return -ENODEV; + + error = ida_get_new(&osd_minor_ida, &minor); + } while (error == -EAGAIN); + + if (error) + return error; + if (minor >= SCSI_OSD_MAX_MINOR) { + error = -EBUSY; + goto err_retract_minor; + } + + error = -ENOMEM; + oud = kzalloc(sizeof(*oud), GFP_KERNEL); + if (NULL == oud) + goto err_retract_minor; + + kref_init(&oud->kref); + dev_set_drvdata(dev, oud); + oud->minor = minor; + + /* allocate a disk and set it up */ + /* FIXME: do we need this since sg has already done that */ + disk = alloc_disk(1); + if (!disk) { + OSD_ERR("alloc_disk failed\n"); + goto err_free_osd; + } + disk->major = SCSI_OSD_MAJOR; + disk->first_minor = oud->minor; + sprintf(disk->disk_name, "osd%d", oud->minor); + oud->disk = disk; + + /* hold one more reference to the scsi_device that will get released + * in __release, in case a logout is happening while fs is mounted + */ + scsi_device_get(scsi_device); + osd_dev_init(&oud->od, scsi_device); + + /* Detect the OSD Version */ + error = __detect_osd(oud); + if (error) { + OSD_ERR("osd detection failed, non-compatible OSD device\n"); + goto err_put_disk; + } + + /* init the char-device for communication with user-mode */ + cdev_init(&oud->cdev, &osd_fops); + oud->cdev.owner = THIS_MODULE; + error = cdev_add(&oud->cdev, + MKDEV(SCSI_OSD_MAJOR, oud->minor), 1); + if (error) { + OSD_ERR("cdev_add failed\n"); + goto err_put_disk; + } + kobject_get(&oud->cdev.kobj); /* 2nd ref see osd_remove() */ + + /* class_member */ + oud->class_member = device_create(osd_sysfs_class, dev, + MKDEV(SCSI_OSD_MAJOR, oud->minor), "%s", disk->disk_name); + if (IS_ERR(oud->class_member)) { + OSD_ERR("class_device_create failed\n"); + error = PTR_ERR(oud->class_member); + goto err_put_cdev; + } + + dev_set_drvdata(oud->class_member, oud); + + OSD_INFO("osd_probe %s\n", disk->disk_name); + return 0; + +err_put_cdev: + cdev_del(&oud->cdev); +err_put_disk: + scsi_device_put(scsi_device); + put_disk(disk); +err_free_osd: + dev_set_drvdata(dev, NULL); + kfree(oud); +err_retract_minor: + ida_remove(&osd_minor_ida, minor); + return error; +} + +static int osd_remove(struct device *dev) +{ + struct scsi_device *scsi_device = to_scsi_device(dev); + struct osd_uld_device *oud = dev_get_drvdata(dev); + + if (!oud || (oud->od.scsi_device != scsi_device)) { + OSD_ERR("Half cooked osd-device %p,%p || %p!=%p", + dev, oud, oud ? oud->od.scsi_device : NULL, + scsi_device); + } + + if (oud->class_member) + device_destroy(osd_sysfs_class, + MKDEV(SCSI_OSD_MAJOR, oud->minor)); + + /* We have 2 references to the cdev. One is released here + * and also takes down the /dev/osdX mapping. The second + * Will be released in __remove() after all users have released + * the osd_uld_device. + */ + if (oud->cdev.owner) + cdev_del(&oud->cdev); + + __uld_put(oud); + return 0; +} + +static void __remove(struct kref *kref) +{ + struct osd_uld_device *oud = container_of(kref, + struct osd_uld_device, kref); + struct scsi_device *scsi_device = oud->od.scsi_device; + + /* now let delete the char_dev */ + kobject_put(&oud->cdev.kobj); + + osd_dev_fini(&oud->od); + scsi_device_put(scsi_device); + + OSD_INFO("osd_remove %s\n", + oud->disk ? oud->disk->disk_name : NULL); + + if (oud->disk) + put_disk(oud->disk); + + ida_remove(&osd_minor_ida, oud->minor); + kfree(oud); +} + +static void __uld_get(struct osd_uld_device *oud) +{ + kref_get(&oud->kref); +} + +static void __uld_put(struct osd_uld_device *oud) +{ + kref_put(&oud->kref, __remove); +} + +/* + * Global driver and scsi registration + */ + +static struct scsi_driver osd_driver = { + .owner = THIS_MODULE, + .gendrv = { + .name = osd_name, + .probe = osd_probe, + .remove = osd_remove, + } +}; + +static int __init osd_uld_init(void) +{ + int err; + + osd_sysfs_class = class_create(THIS_MODULE, osd_symlink); + if (IS_ERR(osd_sysfs_class)) { + OSD_ERR("Unable to register sysfs class => %ld\n", + PTR_ERR(osd_sysfs_class)); + return PTR_ERR(osd_sysfs_class); + } + + err = register_chrdev_region(MKDEV(SCSI_OSD_MAJOR, 0), + SCSI_OSD_MAX_MINOR, osd_name); + if (err) { + OSD_ERR("Unable to register major %d for osd ULD => %d\n", + SCSI_OSD_MAJOR, err); + goto err_out; + } + + err = scsi_register_driver(&osd_driver.gendrv); + if (err) { + OSD_ERR("scsi_register_driver failed => %d\n", err); + goto err_out_chrdev; + } + + OSD_INFO("LOADED %s\n", osd_version_string); + return 0; + +err_out_chrdev: + unregister_chrdev_region(MKDEV(SCSI_OSD_MAJOR, 0), SCSI_OSD_MAX_MINOR); +err_out: + class_destroy(osd_sysfs_class); + return err; +} + +static void __exit osd_uld_exit(void) +{ + scsi_unregister_driver(&osd_driver.gendrv); + unregister_chrdev_region(MKDEV(SCSI_OSD_MAJOR, 0), SCSI_OSD_MAX_MINOR); + class_destroy(osd_sysfs_class); + OSD_INFO("UNLOADED %s\n", osd_version_string); +} + +module_init(osd_uld_init); +module_exit(osd_uld_exit); diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c index 0ea78d9a37d..acb835837ee 100644 --- a/drivers/scsi/osst.c +++ b/drivers/scsi/osst.c @@ -280,8 +280,8 @@ static int osst_chk_result(struct osst_tape * STp, struct osst_request * SRpnt) static int notyetprinted = 1; printk(KERN_WARNING - "%s:W: Warning %x (sugg. bt 0x%x, driver bt 0x%x, host bt 0x%x).\n", - name, result, suggestion(result), driver_byte(result) & DRIVER_MASK, + "%s:W: Warning %x (driver bt 0x%x, host bt 0x%x).\n", + name, result, driver_byte(result), host_byte(result)); if (notyetprinted) { notyetprinted = 0; @@ -317,18 +317,25 @@ static int osst_chk_result(struct osst_tape * STp, struct osst_request * SRpnt) /* Wakeup from interrupt */ -static void osst_sleep_done(void *data, char *sense, int result, int resid) +static void osst_end_async(struct request *req, int update) { - struct osst_request *SRpnt = data; + struct osst_request *SRpnt = req->end_io_data; struct osst_tape *STp = SRpnt->stp; + struct rq_map_data *mdata = &SRpnt->stp->buffer->map_data; - memcpy(SRpnt->sense, sense, SCSI_SENSE_BUFFERSIZE); - STp->buffer->cmdstat.midlevel_result = SRpnt->result = result; + STp->buffer->cmdstat.midlevel_result = SRpnt->result = req->errors; #if DEBUG STp->write_pending = 0; #endif if (SRpnt->waiting) complete(SRpnt->waiting); + + if (SRpnt->bio) { + kfree(mdata->pages); + blk_rq_unmap_user(SRpnt->bio); + } + + __blk_put_request(req->q, req); } /* osst_request memory management */ @@ -342,6 +349,74 @@ static void osst_release_request(struct osst_request *streq) kfree(streq); } +static int osst_execute(struct osst_request *SRpnt, const unsigned char *cmd, + int cmd_len, int data_direction, void *buffer, unsigned bufflen, + int use_sg, int timeout, int retries) +{ + struct request *req; + struct page **pages = NULL; + struct rq_map_data *mdata = &SRpnt->stp->buffer->map_data; + + int err = 0; + int write = (data_direction == DMA_TO_DEVICE); + + req = blk_get_request(SRpnt->stp->device->request_queue, write, GFP_KERNEL); + if (!req) + return DRIVER_ERROR << 24; + + req->cmd_type = REQ_TYPE_BLOCK_PC; + req->cmd_flags |= REQ_QUIET; + + SRpnt->bio = NULL; + + if (use_sg) { + struct scatterlist *sg, *sgl = (struct scatterlist *)buffer; + int i; + + pages = kzalloc(use_sg * sizeof(struct page *), GFP_KERNEL); + if (!pages) + goto free_req; + + for_each_sg(sgl, sg, use_sg, i) + pages[i] = sg_page(sg); + + mdata->null_mapped = 1; + + mdata->page_order = get_order(sgl[0].length); + mdata->nr_entries = + DIV_ROUND_UP(bufflen, PAGE_SIZE << mdata->page_order); + mdata->offset = 0; + + err = blk_rq_map_user(req->q, req, mdata, NULL, bufflen, GFP_KERNEL); + if (err) { + kfree(pages); + goto free_req; + } + SRpnt->bio = req->bio; + mdata->pages = pages; + + } else if (bufflen) { + err = blk_rq_map_kern(req->q, req, buffer, bufflen, GFP_KERNEL); + if (err) + goto free_req; + } + + req->cmd_len = cmd_len; + memset(req->cmd, 0, BLK_MAX_CDB); /* ATAPI hates garbage after CDB */ + memcpy(req->cmd, cmd, req->cmd_len); + req->sense = SRpnt->sense; + req->sense_len = 0; + req->timeout = timeout; + req->retries = retries; + req->end_io_data = SRpnt; + + blk_execute_rq_nowait(req->q, NULL, req, 1, osst_end_async); + return 0; +free_req: + blk_put_request(req); + return DRIVER_ERROR << 24; +} + /* Do the scsi command. Waits until command performed if do_wait is true. Otherwise osst_write_behind_check() is used to check that the command has finished. */ @@ -403,8 +478,8 @@ static struct osst_request * osst_do_scsi(struct osst_request *SRpnt, struct oss STp->buffer->cmdstat.have_sense = 0; STp->buffer->syscall_result = 0; - if (scsi_execute_async(STp->device, cmd, COMMAND_SIZE(cmd[0]), direction, bp, bytes, - use_sg, timeout, retries, SRpnt, osst_sleep_done, GFP_KERNEL)) + if (osst_execute(SRpnt, cmd, COMMAND_SIZE(cmd[0]), direction, bp, bytes, + use_sg, timeout, retries)) /* could not allocate the buffer or request was too large */ (STp->buffer)->syscall_result = (-EBUSY); else if (do_wait) { @@ -5286,11 +5361,6 @@ static int enlarge_buffer(struct osst_buffer *STbuffer, int need_dma) struct page *page = alloc_pages(priority, (OS_FRAME_SIZE - got <= PAGE_SIZE) ? 0 : order); STbuffer->sg[segs].offset = 0; if (page == NULL) { - if (OS_FRAME_SIZE - got <= (max_segs - segs) * b_size / 2 && order) { - b_size /= 2; /* Large enough for the rest of the buffers */ - order--; - continue; - } printk(KERN_WARNING "osst :W: Failed to enlarge buffer to %d bytes.\n", OS_FRAME_SIZE); #if DEBUG diff --git a/drivers/scsi/osst.h b/drivers/scsi/osst.h index 5aa22740b5d..11d26c57f3f 100644 --- a/drivers/scsi/osst.h +++ b/drivers/scsi/osst.h @@ -520,6 +520,7 @@ struct osst_buffer { int syscall_result; struct osst_request *last_SRpnt; struct st_cmdstatus cmdstat; + struct rq_map_data map_data; unsigned char *b_data; os_aux_t *aux; /* onstream AUX structure at end of each block */ unsigned short use_sg; /* zero or number of s/g segments for this adapter */ @@ -634,6 +635,7 @@ struct osst_request { int result; struct osst_tape *stp; struct completion *waiting; + struct bio *bio; }; /* Values of write_type */ diff --git a/drivers/scsi/ql1040_fw.h b/drivers/scsi/ql1040_fw.h deleted file mode 100644 index aaf9284a8b7..00000000000 --- a/drivers/scsi/ql1040_fw.h +++ /dev/null @@ -1,2130 +0,0 @@ -/************************************************************************** - * QLOGIC LINUX SOFTWARE - * - * Copyright (C) 2004 QLogic Corporation - * (www.qlogic.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, 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. - * - *************************************************************************/ - -/************************************************************************ - * * - * --- ISP1040 Initiator/Target Firmware --- * - * 32 LUN Support * - * * - ************************************************************************ - */ - -/* - * Firmware Version 7.65.06 (14:38 Jan 07, 2002) - */ - -static unsigned char firmware_version[] = {7,65,6}; - -#define FW_VERSION_STRING "7.65.06" - -static unsigned short risc_code_addr01 = 0x1000 ; - -static unsigned short risc_code01[] = { - 0x0078, 0x103a, 0x0000, 0x4158, 0x0000, 0x2043, 0x4f50, 0x5952, - 0x4947, 0x4854, 0x2031, 0x3939, 0x3520, 0x514c, 0x4f47, 0x4943, - 0x2043, 0x4f52, 0x504f, 0x5241, 0x5449, 0x4f4e, 0x2049, 0x5350, - 0x3130, 0x3230, 0x2049, 0x2f54, 0x2046, 0x6972, 0x6d77, 0x6172, - 0x6520, 0x2056, 0x6572, 0x7369, 0x6f6e, 0x2030, 0x372e, 0x3635, - 0x2020, 0x2043, 0x7573, 0x746f, 0x6d65, 0x7220, 0x4e6f, 0x2e20, - 0x3030, 0x2050, 0x726f, 0x6475, 0x6374, 0x204e, 0x6f2e, 0x2020, - 0x3031, 0x2024, 0x2001, 0x04fd, 0x2004, 0xa082, 0x0005, 0x0048, - 0x1045, 0x0038, 0x104b, 0x0078, 0x1047, 0x0028, 0x104b, 0x20b9, - 0x1212, 0x0078, 0x104d, 0x20b9, 0x2222, 0x20c1, 0x0008, 0x2071, - 0x0010, 0x70c3, 0x0004, 0x20c9, 0x78ff, 0x2089, 0x1186, 0x70c7, - 0x4953, 0x70cb, 0x5020, 0x70cf, 0x2020, 0x70d3, 0x0007, 0x3f00, - 0x70d6, 0x20c1, 0x0008, 0x2019, 0x0000, 0x2009, 0xfeff, 0x2100, - 0x200b, 0xa5a5, 0xa1ec, 0x7fff, 0x2d64, 0x206b, 0x0a0a, 0xaddc, - 0x3fff, 0x2b54, 0x205b, 0x5050, 0x2114, 0xa286, 0xa5a5, 0x0040, - 0x10bf, 0xa386, 0x000f, 0x0040, 0x1085, 0x2c6a, 0x2a5a, 0x20c1, - 0x0000, 0x2019, 0x000f, 0x0078, 0x1065, 0x2c6a, 0x2a5a, 0x20c1, - 0x0008, 0x2009, 0x7fff, 0x2148, 0x2944, 0x204b, 0x0a0a, 0xa9bc, - 0x3fff, 0x2734, 0x203b, 0x5050, 0x2114, 0xa286, 0x0a0a, 0x0040, - 0x10a9, 0x284a, 0x263a, 0x20c1, 0x0004, 0x2009, 0x3fff, 0x2134, - 0x200b, 0x5050, 0x2114, 0xa286, 0x5050, 0x0040, 0x10aa, 0x0078, - 0x118e, 0x284a, 0x263a, 0x98c0, 0xa188, 0x1000, 0x212c, 0x200b, - 0xa5a5, 0x2114, 0xa286, 0xa5a5, 0x0040, 0x10bc, 0x250a, 0xa18a, - 0x1000, 0x98c1, 0x0078, 0x10c1, 0x250a, 0x0078, 0x10c1, 0x2c6a, - 0x2a5a, 0x2130, 0xa18a, 0x0040, 0x2128, 0xa1a2, 0x5200, 0x8424, - 0x8424, 0x8424, 0x8424, 0x8424, 0x8424, 0xa192, 0x7900, 0x2009, - 0x0000, 0x2001, 0x0031, 0x1078, 0x1d26, 0x2218, 0x2079, 0x5200, - 0x2fa0, 0x2408, 0x2011, 0x0000, 0x20a9, 0x0040, 0x42a4, 0x8109, - 0x00c0, 0x10dc, 0x7ef2, 0x8528, 0x7de6, 0x7cea, 0x7bee, 0x7883, - 0x0000, 0x2031, 0x0030, 0x78cf, 0x0101, 0x780b, 0x0002, 0x780f, - 0x0002, 0x784f, 0x0003, 0x2069, 0x5240, 0x2001, 0x04fd, 0x2004, - 0xa082, 0x0005, 0x0048, 0x1104, 0x0038, 0x1100, 0x0078, 0x1108, - 0x681b, 0x003c, 0x0078, 0x110a, 0x00a8, 0x1108, 0x681b, 0x003c, - 0x681b, 0x0028, 0x6807, 0x0007, 0x680b, 0x00fa, 0x680f, 0x0008, - 0x6813, 0x0005, 0x6823, 0x0000, 0x6827, 0x0006, 0x6817, 0x0008, - 0x682b, 0x0000, 0x681f, 0x0019, 0x2069, 0x5480, 0x2011, 0x0020, - 0x2009, 0x0010, 0x680b, 0x080c, 0x680f, 0x0019, 0x6803, 0xfd00, - 0x6807, 0x0018, 0x6a1a, 0x2d00, 0xa0e8, 0x0008, 0xa290, 0x0004, - 0x8109, 0x00c0, 0x1122, 0x2069, 0x5500, 0x2009, 0x0002, 0x20a9, - 0x0100, 0x6837, 0x0000, 0x680b, 0x0040, 0x7bf0, 0xa386, 0xfeff, - 0x00c0, 0x1148, 0x6817, 0x0100, 0x681f, 0x0064, 0x0078, 0x114c, - 0x6817, 0x0064, 0x681f, 0x0002, 0xade8, 0x0010, 0x0070, 0x1152, - 0x0078, 0x1139, 0x8109, 0x00c0, 0x1137, 0x1078, 0x22a7, 0x1078, - 0x493d, 0x1078, 0x19b5, 0x1078, 0x4e33, 0x3200, 0xa085, 0x000d, - 0x2090, 0x70c3, 0x0000, 0x0090, 0x116c, 0x70c0, 0xa086, 0x0002, - 0x00c0, 0x116c, 0x1078, 0x1284, 0x1078, 0x1196, 0x78cc, 0xa005, - 0x00c0, 0x117a, 0x1078, 0x1d4f, 0x0010, 0x1180, 0x0068, 0x1180, - 0x1078, 0x2186, 0x0010, 0x1180, 0x0068, 0x1180, 0x1078, 0x1ab9, - 0x00e0, 0x116c, 0x1078, 0x4cba, 0x0078, 0x116c, 0x118e, 0x1190, - 0x24ac, 0x24ac, 0x49be, 0x49be, 0x24ac, 0x24ac, 0x0078, 0x118e, - 0x0078, 0x1190, 0x0078, 0x1192, 0x0078, 0x1194, 0x0068, 0x1201, - 0x2061, 0x0000, 0x6018, 0xa084, 0x0001, 0x00c0, 0x1201, 0x7814, - 0xa005, 0x00c0, 0x11a7, 0x0010, 0x1202, 0x0078, 0x1201, 0x2009, - 0x525b, 0x2104, 0xa005, 0x00c0, 0x1201, 0x2009, 0x5264, 0x200b, - 0x0000, 0x7914, 0xa186, 0x0042, 0x00c0, 0x11cc, 0x7816, 0x2009, - 0x5262, 0x2164, 0x200b, 0x0000, 0x6018, 0x70c6, 0x6014, 0x70ca, - 0x611c, 0xa18c, 0xff00, 0x6020, 0xa084, 0x00ff, 0xa105, 0x70ce, - 0x1078, 0x199a, 0x0078, 0x11ff, 0x7814, 0xa086, 0x0018, 0x00c0, - 0x11d3, 0x1078, 0x1678, 0x7817, 0x0000, 0x2009, 0x5262, 0x2104, - 0xa065, 0x0040, 0x11ef, 0x0c7e, 0x609c, 0x2060, 0x1078, 0x1a17, - 0x0c7f, 0x609f, 0x0000, 0x1078, 0x174e, 0x2009, 0x000c, 0x6007, - 0x0103, 0x1078, 0x1976, 0x00c0, 0x11fb, 0x1078, 0x199a, 0x2009, - 0x5262, 0x200b, 0x0000, 0x2009, 0x525c, 0x2104, 0x200b, 0x0000, - 0xa005, 0x0040, 0x11ff, 0x2001, 0x4005, 0x0078, 0x1286, 0x0078, - 0x1284, 0x007c, 0x70c3, 0x0000, 0x70c7, 0x0000, 0x70cb, 0x0000, - 0x70cf, 0x0000, 0x70c0, 0xa0bc, 0xffc0, 0x00c0, 0x1252, 0x2038, - 0x0079, 0x1212, 0x1284, 0x12e5, 0x12a9, 0x12fe, 0x130d, 0x1313, - 0x12a0, 0x1766, 0x1317, 0x1298, 0x12ad, 0x12af, 0x12b1, 0x12b3, - 0x176b, 0x1298, 0x1329, 0x1365, 0x1690, 0x1760, 0x12b5, 0x15af, - 0x15cb, 0x15e7, 0x1612, 0x1568, 0x1576, 0x158a, 0x159e, 0x13e9, - 0x1298, 0x1397, 0x139d, 0x13a2, 0x13a7, 0x13ad, 0x13b2, 0x13b7, - 0x13bc, 0x13c1, 0x13c5, 0x13da, 0x13e6, 0x1298, 0x1298, 0x1298, - 0x1298, 0x13f5, 0x13fe, 0x140d, 0x1451, 0x145b, 0x1462, 0x14a8, - 0x14b7, 0x14c6, 0x14d8, 0x1548, 0x1558, 0x1298, 0x1298, 0x1298, - 0x1298, 0x155d, 0xa0bc, 0xffa0, 0x00c0, 0x1298, 0x2038, 0xa084, - 0x001f, 0x0079, 0x125b, 0x17a4, 0x17a7, 0x17b7, 0x1298, 0x1298, - 0x1931, 0x194e, 0x1298, 0x1298, 0x1298, 0x1952, 0x195a, 0x1298, - 0x1298, 0x1298, 0x1298, 0x12db, 0x12f4, 0x131f, 0x135b, 0x1686, - 0x1782, 0x1796, 0x1298, 0x1847, 0x1960, 0x190d, 0x1917, 0x191b, - 0x1929, 0x1298, 0x1298, 0x72ca, 0x71c6, 0x2001, 0x4006, 0x0078, - 0x1286, 0x73ce, 0x72ca, 0x71c6, 0x2001, 0x4000, 0x70c2, 0x0068, - 0x1287, 0x2061, 0x0000, 0x601b, 0x0001, 0x2091, 0x5000, 0x00e0, - 0x128f, 0x00e0, 0x1291, 0x0068, 0x1291, 0x2091, 0x4080, 0x007c, - 0x70c3, 0x4001, 0x0078, 0x1287, 0x70c3, 0x4006, 0x0078, 0x1287, - 0x2099, 0x0041, 0x20a1, 0x0041, 0x20a9, 0x0005, 0x53a3, 0x0078, - 0x1284, 0x70c4, 0x70c3, 0x0004, 0x007a, 0x0078, 0x1284, 0x0078, - 0x1284, 0x0078, 0x1284, 0x0078, 0x1284, 0x2091, 0x8000, 0x70c3, - 0x0000, 0x70c7, 0x4953, 0x70cb, 0x5020, 0x70cf, 0x2020, 0x70d3, - 0x0007, 0x3f00, 0x70d6, 0x2079, 0x0000, 0x781b, 0x0001, 0x2031, - 0x0030, 0x2059, 0x1000, 0x2029, 0x0457, 0x2051, 0x0470, 0x2061, - 0x0472, 0x20b9, 0xffff, 0x20c1, 0x0000, 0x2091, 0x5000, 0x2091, - 0x4080, 0x0078, 0x0455, 0x1078, 0x1bc4, 0x00c0, 0x129c, 0x75d8, - 0x74dc, 0x75da, 0x74de, 0x0078, 0x12e8, 0x2029, 0x0000, 0x2520, - 0x71d0, 0x73c8, 0x72cc, 0x70c4, 0x1078, 0x1afe, 0x0040, 0x1284, - 0x70c3, 0x4002, 0x0078, 0x1284, 0x1078, 0x1bc4, 0x00c0, 0x129c, - 0x75d8, 0x74dc, 0x75da, 0x74de, 0x0078, 0x1301, 0x2029, 0x0000, - 0x2520, 0x71d0, 0x73c8, 0x72cc, 0x70c4, 0x1078, 0x1b5e, 0x0040, - 0x1284, 0x70c3, 0x4002, 0x0078, 0x1284, 0x71c4, 0x70c8, 0x2114, - 0x200a, 0x0078, 0x1282, 0x71c4, 0x2114, 0x0078, 0x1282, 0x70c7, - 0x0007, 0x70cb, 0x0041, 0x70cf, 0x0006, 0x0078, 0x1284, 0x1078, - 0x1bc4, 0x00c0, 0x129c, 0x75d8, 0x76dc, 0x75da, 0x76de, 0x0078, - 0x132c, 0x2029, 0x0000, 0x2530, 0x70c4, 0x72c8, 0x73cc, 0x74d0, - 0x70c6, 0x72ca, 0x73ce, 0x74d2, 0xa005, 0x0040, 0x1355, 0xa40a, - 0x0040, 0x133c, 0x00c8, 0x1346, 0x8001, 0x7892, 0xa084, 0xfc00, - 0x0040, 0x134a, 0x78cc, 0xa085, 0x0001, 0x78ce, 0x2001, 0x4005, - 0x0078, 0x1286, 0x7a9a, 0x7b9e, 0x7da2, 0x7ea6, 0x7c96, 0x78cc, - 0xa084, 0xfffc, 0x78ce, 0x0078, 0x1359, 0x78cc, 0xa085, 0x0001, - 0x78ce, 0x0078, 0x1284, 0x1078, 0x1bc4, 0x00c0, 0x129c, 0x75d8, - 0x76dc, 0x75da, 0x76de, 0x0078, 0x1368, 0x2029, 0x0000, 0x2530, - 0x70c4, 0x72c8, 0x73cc, 0x74d4, 0x70c6, 0x72ca, 0x73ce, 0x74d6, - 0xa005, 0x0040, 0x1391, 0xa40a, 0x0040, 0x1378, 0x00c8, 0x1382, - 0x8001, 0x78ae, 0xa084, 0xfc00, 0x0040, 0x1386, 0x78cc, 0xa085, - 0x0100, 0x78ce, 0x2001, 0x4005, 0x0078, 0x1286, 0x7ab6, 0x7bba, - 0x7dbe, 0x7ec2, 0x7cb2, 0x78cc, 0xa084, 0xfcff, 0x78ce, 0x0078, - 0x1395, 0x78cc, 0xa085, 0x0100, 0x78ce, 0x0078, 0x1284, 0x2009, - 0x5261, 0x210c, 0x7aec, 0x0078, 0x1282, 0x2009, 0x5241, 0x210c, - 0x0078, 0x1283, 0x2009, 0x5242, 0x210c, 0x0078, 0x1283, 0x2061, - 0x5240, 0x610c, 0x6210, 0x0078, 0x1282, 0x2009, 0x5245, 0x210c, - 0x0078, 0x1283, 0x2009, 0x5246, 0x210c, 0x0078, 0x1283, 0x2009, - 0x5248, 0x210c, 0x0078, 0x1283, 0x2009, 0x5249, 0x210c, 0x0078, - 0x1283, 0x7908, 0x7a0c, 0x0078, 0x1282, 0x71c4, 0x8107, 0xa084, - 0x000f, 0x8003, 0x8003, 0x8003, 0xa0e8, 0x5480, 0x6a00, 0x6804, - 0xa084, 0x0008, 0x0040, 0x13d7, 0x6b08, 0x0078, 0x13d8, 0x6b0c, - 0x0078, 0x1281, 0x77c4, 0x1078, 0x19c5, 0x2091, 0x8000, 0x6b1c, - 0x6a14, 0x2091, 0x8001, 0x2708, 0x0078, 0x1281, 0x794c, 0x0078, - 0x1283, 0x77c4, 0x1078, 0x19c5, 0x2091, 0x8000, 0x6908, 0x6a18, - 0x6b10, 0x2091, 0x8001, 0x0078, 0x1281, 0x71c4, 0xa182, 0x0010, - 0x00c8, 0x127c, 0x1078, 0x237f, 0x0078, 0x1281, 0x71c4, 0xa182, - 0x0010, 0x00c8, 0x127c, 0x2011, 0x5241, 0x2204, 0x007e, 0x2112, - 0x1078, 0x2338, 0x017f, 0x0078, 0x1283, 0x71c4, 0x2019, 0x0100, - 0x2304, 0xa082, 0x0006, 0x0048, 0x141b, 0x2011, 0x1449, 0x20a9, - 0x0008, 0x0078, 0x141f, 0x2011, 0x1441, 0x20a9, 0x0008, 0x2204, - 0xa106, 0x0040, 0x142a, 0x8210, 0x0070, 0x1428, 0x0078, 0x141f, - 0x0078, 0x127c, 0x2304, 0xa082, 0x0006, 0x0048, 0x1433, 0xa292, - 0x1449, 0x0078, 0x1435, 0xa292, 0x1441, 0x027e, 0x2011, 0x5242, - 0x2204, 0x2112, 0x017f, 0x007e, 0x1078, 0x2344, 0x017f, 0x0078, - 0x1283, 0x03e8, 0x00fa, 0x01f4, 0x02ee, 0x0064, 0x0019, 0x0032, - 0x004b, 0x03e8, 0x00fa, 0x01f4, 0x02ee, 0x0004, 0x0001, 0x0002, - 0x0003, 0x2061, 0x5240, 0x610c, 0x6210, 0x70c4, 0x600e, 0x70c8, - 0x6012, 0x0078, 0x1282, 0x2061, 0x5240, 0x6114, 0x70c4, 0x6016, - 0x0078, 0x1283, 0x2061, 0x5240, 0x71c4, 0x2011, 0x0004, 0x601f, - 0x0019, 0x2019, 0x1212, 0xa186, 0x0028, 0x0040, 0x1483, 0x2011, - 0x0005, 0x601f, 0x0019, 0x2019, 0x1212, 0xa186, 0x0032, 0x0040, - 0x1483, 0x2011, 0x0006, 0x601f, 0x000c, 0x2019, 0x2222, 0xa186, - 0x003c, 0x00c0, 0x127c, 0x6018, 0x007e, 0x611a, 0x7800, 0xa084, - 0x0001, 0x00c0, 0x149e, 0x2001, 0x04fd, 0x2004, 0xa082, 0x0005, - 0x0048, 0x1496, 0x0038, 0x149a, 0x0078, 0x149e, 0x0028, 0x149a, - 0x0078, 0x149e, 0x2019, 0x2222, 0x0078, 0x14a0, 0x2019, 0x1212, - 0x23b8, 0x1078, 0x2355, 0x1078, 0x4e33, 0x017f, 0x0078, 0x1283, - 0x71c4, 0xa184, 0xffcf, 0x00c0, 0x127c, 0x2011, 0x5248, 0x2204, - 0x2112, 0x007e, 0x1078, 0x2377, 0x017f, 0x0078, 0x1283, 0x71c4, - 0xa182, 0x0010, 0x00c8, 0x127c, 0x2011, 0x5249, 0x2204, 0x007e, - 0x2112, 0x1078, 0x2366, 0x017f, 0x0078, 0x1283, 0x71c4, 0x72c8, - 0xa184, 0xfffd, 0x00c0, 0x127b, 0xa284, 0xfffd, 0x00c0, 0x127b, - 0x2100, 0x7908, 0x780a, 0x2200, 0x7a0c, 0x780e, 0x0078, 0x1282, - 0x71c4, 0x8107, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa0e8, - 0x5480, 0x2019, 0x0000, 0x72c8, 0xd2bc, 0x0040, 0x14e9, 0xa39d, - 0x0010, 0xd2b4, 0x0040, 0x14ee, 0xa39d, 0x0008, 0x6800, 0x007e, - 0xa226, 0x0040, 0x1511, 0x6a02, 0xa484, 0x2000, 0x0040, 0x14fa, - 0xa39d, 0x0010, 0xa484, 0x1000, 0x0040, 0x1500, 0xa39d, 0x0008, - 0xa484, 0x4000, 0x0040, 0x1511, 0x810f, 0xa284, 0x4000, 0x0040, - 0x150d, 0x1078, 0x2399, 0x0078, 0x1511, 0x1078, 0x238b, 0x0078, - 0x1511, 0x72cc, 0x6808, 0xa206, 0x0040, 0x1540, 0xa2a4, 0x00ff, - 0x2061, 0x5240, 0x6118, 0xa186, 0x0028, 0x0040, 0x1527, 0xa186, - 0x0032, 0x0040, 0x152d, 0xa186, 0x003c, 0x0040, 0x1533, 0xa482, - 0x0064, 0x0048, 0x153d, 0x0078, 0x1537, 0xa482, 0x0050, 0x0048, - 0x153d, 0x0078, 0x1537, 0xa482, 0x0043, 0x0048, 0x153d, 0x71c4, - 0x71c6, 0x027f, 0x72ca, 0x0078, 0x127d, 0x6a0a, 0xa39d, 0x000a, - 0x6804, 0xa305, 0x6806, 0x027f, 0x6b0c, 0x71c4, 0x0078, 0x1281, - 0x77c4, 0x1078, 0x19c5, 0x2091, 0x8000, 0x6a14, 0x6b1c, 0x2091, - 0x8001, 0x70c8, 0x6816, 0x70cc, 0x681e, 0x2708, 0x0078, 0x1281, - 0x70c4, 0x794c, 0x784e, 0x0078, 0x1283, 0x71c4, 0x72c8, 0x73cc, - 0xa182, 0x0010, 0x00c8, 0x127c, 0x1078, 0x23a7, 0x0078, 0x1281, - 0x77c4, 0x1078, 0x19c5, 0x2091, 0x8000, 0x6a08, 0xa295, 0x0002, - 0x6a0a, 0x2091, 0x8001, 0x2708, 0x0078, 0x1282, 0x77c4, 0x1078, - 0x19c5, 0x2091, 0x8000, 0x6a08, 0xa294, 0xfff9, 0x6a0a, 0x6804, - 0xa005, 0x0040, 0x1585, 0x1078, 0x226f, 0x2091, 0x8001, 0x2708, - 0x0078, 0x1282, 0x77c4, 0x1078, 0x19c5, 0x2091, 0x8000, 0x6a08, - 0xa295, 0x0004, 0x6a0a, 0x6804, 0xa005, 0x0040, 0x1599, 0x1078, - 0x226f, 0x2091, 0x8001, 0x2708, 0x0078, 0x1282, 0x77c4, 0x2041, - 0x0001, 0x2049, 0x0005, 0x2051, 0x0020, 0x2091, 0x8000, 0x1078, - 0x19d2, 0x2091, 0x8001, 0x2708, 0x6a08, 0x0078, 0x1282, 0x77c4, - 0x72c8, 0x73cc, 0x77c6, 0x72ca, 0x73ce, 0x1078, 0x1a52, 0x00c0, - 0x15c7, 0x6818, 0xa005, 0x0040, 0x15c7, 0x2708, 0x1078, 0x23b7, - 0x00c0, 0x15c7, 0x7817, 0x0015, 0x2091, 0x8001, 0x007c, 0x2091, - 0x8001, 0x0078, 0x1284, 0x77c4, 0x77c6, 0x2041, 0x0021, 0x2049, - 0x0005, 0x2051, 0x0020, 0x2091, 0x8000, 0x1078, 0x19d2, 0x2061, - 0x5240, 0x606f, 0x0003, 0x6782, 0x6093, 0x000f, 0x6073, 0x0000, - 0x7817, 0x0016, 0x1078, 0x226f, 0x2091, 0x8001, 0x007c, 0x77c8, - 0x77ca, 0x77c4, 0x77c6, 0xa7bc, 0xff00, 0x2091, 0x8000, 0x2061, - 0x5240, 0x606f, 0x0002, 0x6073, 0x0000, 0x6782, 0x6093, 0x000f, - 0x7817, 0x0017, 0x1078, 0x226f, 0x2091, 0x8001, 0x2041, 0x0021, - 0x2049, 0x0004, 0x2051, 0x0010, 0x2091, 0x8000, 0x1078, 0x19d2, - 0x70c8, 0x6836, 0x8738, 0xa784, 0x001f, 0x00c0, 0x1606, 0x2091, - 0x8001, 0x007c, 0x78cc, 0xa084, 0x0003, 0x00c0, 0x1636, 0x2039, - 0x0000, 0x2041, 0x0021, 0x2049, 0x0004, 0x2051, 0x0008, 0x1078, - 0x19c5, 0x2091, 0x8000, 0x6808, 0xa80d, 0x690a, 0x2091, 0x8001, - 0x8738, 0xa784, 0x001f, 0x00c0, 0x161f, 0xa7bc, 0xff00, 0x873f, - 0x8738, 0x873f, 0xa784, 0x0f00, 0x00c0, 0x161f, 0x2091, 0x8000, - 0x2069, 0x0100, 0x6830, 0xa084, 0x0040, 0x0040, 0x165f, 0x684b, - 0x0004, 0x20a9, 0x0014, 0x6848, 0xa084, 0x0004, 0x0040, 0x164c, - 0x0070, 0x164c, 0x0078, 0x1643, 0x684b, 0x0009, 0x20a9, 0x0014, - 0x6848, 0xa084, 0x0001, 0x0040, 0x1659, 0x0070, 0x1659, 0x0078, - 0x1650, 0x20a9, 0x00fa, 0x0070, 0x165f, 0x0078, 0x165b, 0x2079, - 0x5200, 0x7817, 0x0018, 0x2061, 0x5240, 0x606f, 0x0001, 0x6073, - 0x0000, 0x6093, 0x000f, 0x78cc, 0xa085, 0x0002, 0x78ce, 0x6808, - 0xa084, 0xfffd, 0x680a, 0x681b, 0x0048, 0x2091, 0x8001, 0x007c, - 0x78cc, 0xa084, 0xfffd, 0x78ce, 0xa084, 0x0001, 0x00c0, 0x1682, - 0x1078, 0x1a9c, 0x71c4, 0x71c6, 0x794a, 0x007c, 0x1078, 0x1bc4, - 0x00c0, 0x129c, 0x75d8, 0x74dc, 0x75da, 0x74de, 0x0078, 0x1693, - 0x2029, 0x0000, 0x2520, 0x71c4, 0x73c8, 0x72cc, 0x71c6, 0x73ca, - 0x72ce, 0x2079, 0x5200, 0x2091, 0x8000, 0x1078, 0x1980, 0x2091, - 0x8001, 0x0040, 0x174a, 0x20a9, 0x0005, 0x20a1, 0x5218, 0x2091, - 0x8000, 0x41a1, 0x2091, 0x8001, 0x2009, 0x0020, 0x1078, 0x197b, - 0x0040, 0x16b6, 0x1078, 0x199a, 0x0078, 0x174a, 0x6004, 0xa084, - 0xff00, 0x8007, 0x8009, 0x0040, 0x1719, 0x0c7e, 0x2c68, 0x2091, - 0x8000, 0x1078, 0x1980, 0x2091, 0x8001, 0x0040, 0x16ea, 0x2c00, - 0x689e, 0x8109, 0x00c0, 0x16be, 0x609f, 0x0000, 0x0c7f, 0x0c7e, - 0x7218, 0x731c, 0x7420, 0x7524, 0x2c68, 0x689c, 0xa065, 0x0040, - 0x1718, 0x2009, 0x0020, 0x1078, 0x197b, 0x00c0, 0x1701, 0x6004, - 0xa084, 0x00ff, 0xa086, 0x0002, 0x00c0, 0x16ea, 0x2d00, 0x6002, - 0x0078, 0x16d0, 0x0c7f, 0x0c7e, 0x609c, 0x2060, 0x1078, 0x1a17, - 0x0c7f, 0x609f, 0x0000, 0x1078, 0x174e, 0x2009, 0x000c, 0x6008, - 0xa085, 0x0200, 0x600a, 0x1078, 0x1976, 0x1078, 0x199a, 0x0078, - 0x174a, 0x0c7f, 0x0c7e, 0x609c, 0x2060, 0x1078, 0x1a17, 0x0c7f, - 0x609f, 0x0000, 0x1078, 0x174e, 0x2009, 0x000c, 0x6007, 0x0103, - 0x601b, 0x0003, 0x1078, 0x1976, 0x1078, 0x199a, 0x0078, 0x174a, - 0x0c7f, 0x74c4, 0x73c8, 0x72cc, 0x6014, 0x2091, 0x8000, 0x7817, - 0x0012, 0x0e7e, 0x2071, 0x5240, 0x706f, 0x0005, 0x7073, 0x0000, - 0x7376, 0x727a, 0x747e, 0x7082, 0x7087, 0x0000, 0x2c00, 0x708a, - 0x708f, 0x0000, 0xa02e, 0x2530, 0x611c, 0x61a2, 0xa184, 0x0060, - 0x0040, 0x173c, 0x1078, 0x48d3, 0x0e7f, 0x6596, 0x65a6, 0x669a, - 0x66aa, 0x60af, 0x0000, 0x60b3, 0x0000, 0x1078, 0x226f, 0x2091, - 0x8001, 0x007c, 0x70c3, 0x4005, 0x0078, 0x1287, 0x20a9, 0x0005, - 0x2099, 0x5218, 0x2091, 0x8000, 0x530a, 0x2091, 0x8001, 0x2100, - 0xa210, 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x007c, - 0x71c4, 0x70c7, 0x0000, 0x7906, 0x0078, 0x1284, 0x71c4, 0x71c6, - 0x2168, 0x0078, 0x176d, 0x2069, 0x1000, 0x690c, 0xa016, 0x2d04, - 0xa210, 0x8d68, 0x8109, 0x00c0, 0x176f, 0xa285, 0x0000, 0x00c0, - 0x177d, 0x70c3, 0x4000, 0x0078, 0x177f, 0x70c3, 0x4003, 0x70ca, - 0x0078, 0x1287, 0x2011, 0x5267, 0x220c, 0x70c4, 0x8003, 0x0048, - 0x178f, 0x1078, 0x3c51, 0xa184, 0x7fff, 0x0078, 0x1793, 0x1078, - 0x3c44, 0xa185, 0x8000, 0x2012, 0x0078, 0x1283, 0x71c4, 0x1078, - 0x3c3b, 0x6100, 0x2001, 0x5267, 0x2004, 0xa084, 0x8000, 0xa10d, - 0x6204, 0x6308, 0x0078, 0x1281, 0x79e4, 0x0078, 0x1283, 0x71c4, - 0x71c6, 0x2198, 0x20a1, 0x0042, 0x20a9, 0x0004, 0x53a3, 0x21a0, - 0x2099, 0x0042, 0x20a9, 0x0004, 0x53a3, 0x0078, 0x1284, 0x70c4, - 0x2068, 0x2079, 0x5200, 0x2091, 0x8000, 0x1078, 0x1980, 0x2091, - 0x8001, 0x0040, 0x1843, 0x6007, 0x0001, 0x600b, 0x0000, 0x602b, - 0x0000, 0x601b, 0x0006, 0x6a10, 0xa28c, 0x000f, 0xa284, 0x00f0, - 0x8003, 0x8003, 0x8003, 0x8003, 0xa105, 0x6016, 0xa284, 0x0800, - 0x0040, 0x17de, 0x601b, 0x000a, 0x0078, 0x17e4, 0xa284, 0x1000, - 0x0040, 0x17e4, 0x601b, 0x000c, 0xa284, 0x0300, 0x0040, 0x17ed, - 0x602b, 0x0001, 0x8004, 0x8004, 0x8004, 0xa085, 0x0001, 0x601e, - 0x6023, 0x0000, 0x6027, 0x0000, 0xa284, 0x0400, 0x0040, 0x17fa, - 0x602b, 0x0000, 0x20a9, 0x0006, 0xac80, 0x000b, 0x20a0, 0xad80, - 0x0005, 0x2098, 0x53a3, 0xa284, 0x0300, 0x00c0, 0x180f, 0x6046, - 0x604a, 0x604e, 0x6052, 0x6096, 0x609a, 0x0078, 0x1819, 0x6800, - 0x6046, 0x6804, 0x604a, 0x6e08, 0x664e, 0x6d0c, 0x6552, 0x6596, - 0x669a, 0x6014, 0x2091, 0x8000, 0x7817, 0x0042, 0x2c08, 0x2061, - 0x5240, 0x606f, 0x0005, 0x6073, 0x0000, 0x6077, 0x0000, 0x607b, - 0x0000, 0x607f, 0x0000, 0x6082, 0x618a, 0xa284, 0x0400, 0x608e, - 0x2091, 0x8001, 0x0e7e, 0x2071, 0x0020, 0x7007, 0x000a, 0x7007, - 0x0002, 0x7003, 0x0000, 0x0e7f, 0x2091, 0x8000, 0x1078, 0x226f, - 0x2091, 0x8001, 0x007c, 0x70c3, 0x4005, 0x0078, 0x1287, 0x0c7e, - 0x0d7e, 0x0e7e, 0x0f7e, 0x2091, 0x8000, 0x2071, 0x5240, 0x2079, - 0x0100, 0x2061, 0x0010, 0x70a0, 0xa06d, 0x0040, 0x1903, 0x6a04, - 0xa294, 0x00ff, 0xa286, 0x0007, 0x0040, 0x1862, 0xa286, 0x000f, - 0x00c0, 0x1903, 0x691c, 0xa184, 0x00c0, 0x0040, 0x1903, 0xa184, - 0x0080, 0x00c0, 0x18d3, 0x6824, 0xa084, 0xff00, 0xa085, 0x0019, - 0x6826, 0x71b0, 0x81ff, 0x0040, 0x1889, 0x0d7e, 0x2069, 0x0020, - 0x6807, 0x0010, 0x6908, 0x6808, 0xa106, 0x00c0, 0x187a, 0x690c, - 0x680c, 0xa106, 0x00c0, 0x187f, 0xa184, 0x00ff, 0x00c0, 0x187f, - 0x0d7f, 0x78b8, 0xa084, 0x801f, 0x00c0, 0x1889, 0x7848, 0xa085, - 0x000c, 0x784a, 0x71b0, 0x81ff, 0x0040, 0x18ac, 0x70b3, 0x0000, - 0x0d7e, 0x2069, 0x0020, 0x6807, 0x0018, 0x6804, 0xa084, 0x0008, - 0x00c0, 0x189d, 0x6807, 0x0008, 0x6804, 0xa084, 0x0008, 0x00c0, - 0x18a4, 0x6807, 0x0002, 0x0d7f, 0x61c4, 0x62c8, 0x63cc, 0x61c6, - 0x62ca, 0x63ce, 0x0e7e, 0x2071, 0x5200, 0x7266, 0x736a, 0xae80, - 0x0019, 0x0e7f, 0x7848, 0xa084, 0x000c, 0x00c0, 0x18ba, 0x1078, - 0x47e1, 0x78a3, 0x0000, 0x7858, 0xa084, 0xedff, 0x785a, 0x70b4, - 0xa080, 0x00da, 0x781a, 0x0f7f, 0x0e7f, 0x0d7f, 0x0c7f, 0x2091, - 0x8001, 0x0078, 0x1284, 0x6824, 0xa084, 0xff00, 0xa085, 0x0019, - 0x6826, 0x78b8, 0xa084, 0x801f, 0x00c0, 0x18d9, 0x7848, 0xa085, - 0x000c, 0x784a, 0x7848, 0xa084, 0x000c, 0x00c0, 0x18e2, 0x71b0, - 0x81ff, 0x0040, 0x1901, 0x70b3, 0x0000, 0x0d7e, 0x2069, 0x0020, - 0x6807, 0x0018, 0x6804, 0xa084, 0x0008, 0x00c0, 0x18f2, 0x6807, - 0x0008, 0x6804, 0xa084, 0x0008, 0x00c0, 0x18f9, 0x6807, 0x0002, - 0x0d7f, 0x0078, 0x18cb, 0x0f7f, 0x0e7f, 0x0d7f, 0x0c7f, 0x2091, - 0x8001, 0x2001, 0x4005, 0x0078, 0x1286, 0x7980, 0x71c6, 0x71c4, - 0xa182, 0x0003, 0x00c8, 0x127c, 0x7982, 0x0078, 0x1284, 0x7980, - 0x71c6, 0x0078, 0x1284, 0x7974, 0x71c6, 0x71c4, 0x7976, 0x7978, - 0x71ca, 0x71c8, 0x797a, 0x797c, 0x71ce, 0x71cc, 0x797e, 0x0078, - 0x1284, 0x7974, 0x71c6, 0x7978, 0x71ca, 0x797c, 0x71ce, 0x0078, - 0x1284, 0x7900, 0x71c6, 0x71c4, 0x7902, 0x2001, 0x04fd, 0x2004, - 0xa082, 0x0005, 0x0048, 0x1940, 0x0038, 0x1942, 0x0078, 0x194c, - 0x00a8, 0x194c, 0xa18c, 0x0001, 0x00c0, 0x194a, 0x20b9, 0x2222, - 0x0078, 0x194c, 0x20b9, 0x1212, 0x0078, 0x1284, 0x7900, 0x71c6, - 0x0078, 0x1284, 0x2009, 0x5274, 0x2104, 0x70c6, 0x70c4, 0x200a, - 0x0078, 0x1284, 0x2009, 0x5274, 0x2104, 0x70c6, 0x0078, 0x1284, - 0x71c4, 0x8107, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa0e8, - 0x5480, 0x6a14, 0xd2b4, 0x0040, 0x1971, 0x2011, 0x0001, 0x0078, - 0x1973, 0x2011, 0x0000, 0x6b0c, 0x0078, 0x1281, 0xac80, 0x0001, - 0x1078, 0x1b80, 0x007c, 0xac80, 0x0001, 0x1078, 0x1b20, 0x007c, - 0x7850, 0xa065, 0x0040, 0x1988, 0x2c04, 0x7852, 0x2063, 0x0000, - 0x007c, 0x0f7e, 0x2079, 0x5200, 0x7850, 0xa06d, 0x0040, 0x1998, - 0x2d04, 0x7852, 0x6803, 0x0000, 0x6807, 0x0000, 0x680b, 0x0000, - 0x0f7f, 0x007c, 0x2091, 0x8000, 0x0f7e, 0x2079, 0x5200, 0x7850, - 0x2062, 0x2c00, 0xa005, 0x00c0, 0x19a7, 0x1078, 0x248c, 0x7852, - 0x0f7f, 0x2091, 0x8001, 0x007c, 0x0f7e, 0x2079, 0x5200, 0x7850, - 0x206a, 0x2d00, 0x7852, 0x0f7f, 0x007c, 0x2011, 0x7900, 0x7a52, - 0x7bec, 0x8319, 0x0040, 0x19c2, 0xa280, 0x0031, 0x2012, 0x2010, - 0x0078, 0x19b9, 0x2013, 0x0000, 0x007c, 0xa784, 0x0f00, 0x800b, - 0xa784, 0x001f, 0x8003, 0x8003, 0x8003, 0x8003, 0xa105, 0xa0e8, - 0x5500, 0x007c, 0x1078, 0x19c5, 0x2900, 0x682a, 0x2a00, 0x682e, - 0x6808, 0xa084, 0xffef, 0xa80d, 0x690a, 0x2009, 0x5252, 0x210c, - 0x6804, 0xa005, 0x0040, 0x1a04, 0xa116, 0x00c0, 0x19ef, 0x2060, - 0x6000, 0x6806, 0x017e, 0x200b, 0x0000, 0x0078, 0x19f2, 0x2009, - 0x0000, 0x017e, 0x6804, 0xa065, 0x0040, 0x1a01, 0x6000, 0x6806, - 0x1078, 0x1a31, 0x1078, 0x1ccb, 0x6810, 0x8001, 0x6812, 0x00c0, - 0x19f2, 0x017f, 0x6902, 0x6906, 0x007c, 0xa065, 0x0040, 0x1a16, - 0x2008, 0x609c, 0xa005, 0x0040, 0x1a13, 0x2062, 0x609f, 0x0000, - 0xa065, 0x0078, 0x1a09, 0x7850, 0x7952, 0x2062, 0x007c, 0xa065, - 0x0040, 0x1a30, 0x2008, 0x609c, 0xa005, 0x0040, 0x1a25, 0x2062, - 0x609f, 0x0000, 0xa065, 0x0078, 0x1a1b, 0x0f7e, 0x2079, 0x5200, - 0x2091, 0x8000, 0x7850, 0x7952, 0x0f7f, 0x2062, 0x2091, 0x8001, - 0x007c, 0x6007, 0x0103, 0x608f, 0x0000, 0x20a9, 0x001c, 0xac80, - 0x0005, 0x20a0, 0x2001, 0x0000, 0x40a4, 0x6828, 0x601a, 0x682c, - 0x6022, 0x007c, 0x0e7e, 0x2071, 0x5240, 0x704c, 0xa08c, 0x0200, - 0x00c0, 0x1a50, 0xa088, 0x5280, 0x2d0a, 0x8000, 0x704e, 0xa006, - 0x0e7f, 0x007c, 0x1078, 0x19c5, 0x2091, 0x8000, 0x6804, 0x781e, - 0xa065, 0x0040, 0x1a9b, 0x0078, 0x1a63, 0x2c00, 0x781e, 0x6000, - 0xa065, 0x0040, 0x1a9b, 0x600c, 0xa306, 0x00c0, 0x1a5d, 0x6010, - 0xa206, 0x00c0, 0x1a5d, 0x2c28, 0x2001, 0x5252, 0x2004, 0xac06, - 0x00c0, 0x1a74, 0x0078, 0x1a99, 0x6804, 0xac06, 0x00c0, 0x1a81, - 0x6000, 0xa065, 0x6806, 0x00c0, 0x1a8b, 0x6803, 0x0000, 0x0078, - 0x1a8b, 0x6400, 0x781c, 0x2060, 0x6402, 0xa486, 0x0000, 0x00c0, - 0x1a8b, 0x2c00, 0x6802, 0x2560, 0x1078, 0x1a31, 0x601b, 0x0005, - 0x6023, 0x0020, 0x1078, 0x1ccb, 0x6810, 0x8001, 0x1050, 0x248c, - 0x6812, 0xa085, 0xffff, 0x007c, 0x2039, 0x0000, 0x2041, 0x0021, - 0x2049, 0x0004, 0x2051, 0x0008, 0x2091, 0x8000, 0x1078, 0x19d2, - 0x8738, 0xa784, 0x001f, 0x00c0, 0x1aa6, 0xa7bc, 0xff00, 0x873f, - 0x8738, 0x873f, 0xa784, 0x0f00, 0x00c0, 0x1aa6, 0x2091, 0x8001, - 0x007c, 0x2061, 0x0000, 0x6018, 0xa084, 0x0001, 0x00c0, 0x1aca, - 0x2091, 0x8000, 0x78e0, 0x78e3, 0x0000, 0x2091, 0x8001, 0xa005, - 0x00c0, 0x1acb, 0x007c, 0xa08c, 0xfff0, 0x0040, 0x1ad1, 0x1078, - 0x248c, 0x0079, 0x1ad3, 0x1ae3, 0x1ae6, 0x1aec, 0x1af0, 0x1ae4, - 0x1af4, 0x1afa, 0x1ae4, 0x1ae4, 0x1c95, 0x1cb9, 0x1cbd, 0x1ae4, - 0x1ae4, 0x1ae4, 0x1ae4, 0x007c, 0x1078, 0x248c, 0x1078, 0x1a9c, - 0x2001, 0x8001, 0x0078, 0x1cc3, 0x2001, 0x8003, 0x0078, 0x1cc3, - 0x2001, 0x8004, 0x0078, 0x1cc3, 0x1078, 0x1a9c, 0x2001, 0x8006, - 0x0078, 0x1cc3, 0x2001, 0x8007, 0x0078, 0x1cc3, 0x2030, 0x2138, - 0xa782, 0x0021, 0x0048, 0x1b06, 0x2009, 0x0020, 0x2600, 0x1078, - 0x1b20, 0x00c0, 0x1b1f, 0xa7ba, 0x0020, 0x0048, 0x1b1e, 0x0040, - 0x1b1e, 0x2708, 0xa6b0, 0x0020, 0xa290, 0x0040, 0xa399, 0x0000, - 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x0078, 0x1b00, 0xa006, 0x007c, - 0x81ff, 0x0040, 0x1b5b, 0x2099, 0x0030, 0x20a0, 0x700c, 0xa084, - 0x00ff, 0x0040, 0x1b32, 0x7007, 0x0004, 0x7004, 0xa084, 0x0004, - 0x00c0, 0x1b2d, 0x21a8, 0x7017, 0x0000, 0x810b, 0x7112, 0x721a, - 0x731e, 0x7422, 0x7526, 0x780c, 0xa085, 0x0001, 0x7002, 0x7007, - 0x0001, 0x2001, 0x04fd, 0x2004, 0xa082, 0x0005, 0x00c8, 0x1b4f, - 0x2009, 0x0022, 0x2104, 0xa084, 0x4000, 0x00c0, 0x1b41, 0x7008, - 0x800b, 0x00c8, 0x1b41, 0x7007, 0x0002, 0xa08c, 0x01e0, 0x00c0, - 0x1b5b, 0x53a5, 0xa006, 0x7003, 0x0000, 0x007c, 0x2030, 0x2138, - 0xa782, 0x0021, 0x0048, 0x1b66, 0x2009, 0x0020, 0x2600, 0x1078, - 0x1b80, 0x00c0, 0x1b7f, 0xa7ba, 0x0020, 0x0048, 0x1b7e, 0x0040, - 0x1b7e, 0x2708, 0xa6b0, 0x0020, 0xa290, 0x0040, 0xa399, 0x0000, - 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x0078, 0x1b60, 0xa006, 0x007c, - 0x81ff, 0x0040, 0x1bc1, 0x2098, 0x20a1, 0x0030, 0x700c, 0xa084, - 0x00ff, 0x0040, 0x1b92, 0x7007, 0x0004, 0x7004, 0xa084, 0x0004, - 0x00c0, 0x1b8d, 0x21a8, 0x7017, 0x0000, 0x810b, 0x7112, 0x721a, - 0x731e, 0x7422, 0x7526, 0x780c, 0xa085, 0x0000, 0x7002, 0x53a6, - 0x7007, 0x0001, 0x2001, 0x04fd, 0x2004, 0xa082, 0x0005, 0x00c8, - 0x1bb0, 0x2009, 0x0022, 0x2104, 0xa084, 0x4000, 0x00c0, 0x1ba2, - 0x7010, 0xa084, 0xf000, 0x0040, 0x1bb9, 0x7007, 0x0008, 0x0078, - 0x1bbd, 0x7108, 0x8103, 0x00c8, 0x1ba2, 0x7007, 0x0002, 0xa184, - 0x01e0, 0x7003, 0x0000, 0x007c, 0x2001, 0x04fd, 0x2004, 0xa082, - 0x0004, 0x00c8, 0x1bcd, 0x0078, 0x1bd0, 0xa006, 0x0078, 0x1bd2, - 0xa085, 0x0001, 0x007c, 0x0e7e, 0x2071, 0x5200, 0x2d08, 0x7058, - 0x6802, 0xa005, 0x00c0, 0x1bdd, 0x715e, 0x715a, 0x0e7f, 0x007c, - 0x2c08, 0x7858, 0x6002, 0xa005, 0x00c0, 0x1be7, 0x795e, 0x795a, - 0x007c, 0x2091, 0x8000, 0x6114, 0x1078, 0x2180, 0x6900, 0xa184, - 0x0100, 0x00c0, 0x2035, 0xa184, 0x0200, 0x00c0, 0x2031, 0x681c, - 0xa005, 0x00c0, 0x203d, 0x6003, 0x0000, 0x2c08, 0x785c, 0xa065, - 0x00c0, 0x1c05, 0x795a, 0x0078, 0x1c06, 0x6102, 0x795e, 0x2091, - 0x8001, 0x1078, 0x228c, 0x007c, 0x0e7e, 0x2071, 0x5200, 0x7058, - 0xa06d, 0x0040, 0x1c1a, 0x6800, 0x705a, 0xa005, 0x00c0, 0x1c19, - 0x705e, 0x8dff, 0x0e7f, 0x007c, 0x0d7e, 0x0c7e, 0x0f7e, 0x2079, - 0x5200, 0xaf80, 0x0016, 0x2060, 0x6000, 0xa005, 0x0040, 0x1c43, - 0x2068, 0x6814, 0xa306, 0x00c0, 0x1c33, 0x6828, 0xa084, 0x00ff, - 0xa406, 0x0040, 0x1c36, 0x2d60, 0x0078, 0x1c24, 0x6800, 0xa005, - 0x6002, 0x00c0, 0x1c42, 0xaf80, 0x0016, 0xac06, 0x0040, 0x1c41, - 0x2c00, 0x785e, 0x2d00, 0x0f7f, 0x0c7f, 0x0d7f, 0xa005, 0x007c, - 0x0d7e, 0x0c7e, 0x0f7e, 0x2079, 0x5200, 0xaf80, 0x0016, 0x2060, - 0x6000, 0xa005, 0x0040, 0x1c6b, 0x2068, 0x6814, 0xa084, 0x00ff, - 0xa306, 0x0040, 0x1c5e, 0x2d60, 0x0078, 0x1c50, 0x6800, 0xa005, - 0x6002, 0x00c0, 0x1c6a, 0xaf80, 0x0016, 0xac06, 0x0040, 0x1c69, - 0x2c00, 0x785e, 0x2d00, 0x0f7f, 0x0c7f, 0x0d7f, 0xa005, 0x007c, - 0x0d7e, 0x0c7e, 0x0f7e, 0x2079, 0x5200, 0xaf80, 0x0016, 0x2060, - 0x6000, 0xa06d, 0x0040, 0x1c90, 0x6814, 0xa306, 0x0040, 0x1c83, - 0x2d60, 0x0078, 0x1c78, 0x6800, 0xa005, 0x6002, 0x00c0, 0x1c8f, - 0xaf80, 0x0016, 0xac06, 0x0040, 0x1c8e, 0x2c00, 0x785e, 0x2d00, - 0x0f7f, 0x0c7f, 0x0d7f, 0xa005, 0x007c, 0x2091, 0x8000, 0x2069, - 0x5240, 0x6800, 0xa086, 0x0000, 0x0040, 0x1ca3, 0x2091, 0x8001, - 0x78e3, 0x0009, 0x007c, 0x6880, 0xa0bc, 0xff00, 0x2041, 0x0021, - 0x2049, 0x0004, 0x2051, 0x0010, 0x1078, 0x19d2, 0x8738, 0xa784, - 0x001f, 0x00c0, 0x1cac, 0x2091, 0x8001, 0x2001, 0x800a, 0x0078, - 0x1cc3, 0x2001, 0x800c, 0x0078, 0x1cc3, 0x1078, 0x1a9c, 0x2001, - 0x800d, 0x0078, 0x1cc3, 0x70c2, 0x2061, 0x0000, 0x601b, 0x0001, - 0x2091, 0x4080, 0x007c, 0x6004, 0x2c08, 0x2063, 0x0000, 0x7884, - 0x8000, 0x7886, 0x7888, 0xa005, 0x798a, 0x0040, 0x1cda, 0x2c02, - 0x0078, 0x1cdb, 0x798e, 0x007c, 0x6807, 0x0103, 0x0c7e, 0x2061, - 0x5200, 0x2d08, 0x206b, 0x0000, 0x6084, 0x8000, 0x6086, 0x6088, - 0xa005, 0x618a, 0x0040, 0x1cef, 0x2d02, 0x0078, 0x1cf0, 0x618e, - 0x0c7f, 0x007c, 0x1078, 0x1d03, 0x0040, 0x1d02, 0x0c7e, 0x609c, - 0xa065, 0x0040, 0x1cfd, 0x1078, 0x1a17, 0x0c7f, 0x609f, 0x0000, - 0x1078, 0x199a, 0x007c, 0x788c, 0xa065, 0x0040, 0x1d15, 0x2091, - 0x8000, 0x7884, 0x8001, 0x7886, 0x2c04, 0x788e, 0xa005, 0x00c0, - 0x1d13, 0x788a, 0x8000, 0x2091, 0x8001, 0x007c, 0x20a9, 0x0010, - 0xa006, 0x8004, 0x8086, 0x818e, 0x00c8, 0x1d1f, 0xa200, 0x0070, - 0x1d23, 0x0078, 0x1d1a, 0x8086, 0x818e, 0x007c, 0x157e, 0x20a9, - 0x0010, 0xa005, 0x0040, 0x1d49, 0xa11a, 0x00c8, 0x1d49, 0x8213, - 0x818d, 0x0048, 0x1d3a, 0xa11a, 0x00c8, 0x1d3b, 0x0070, 0x1d41, - 0x0078, 0x1d2f, 0xa11a, 0x2308, 0x8210, 0x0070, 0x1d41, 0x0078, - 0x1d2f, 0x007e, 0x3200, 0xa084, 0xf7ff, 0x2080, 0x007f, 0x157f, - 0x007c, 0x007e, 0x3200, 0xa085, 0x0800, 0x0078, 0x1d45, 0x7994, - 0x70d0, 0xa106, 0x0040, 0x1dbd, 0x2091, 0x8000, 0x2071, 0x0020, - 0x7004, 0xa005, 0x00c0, 0x1dbd, 0x7008, 0x7208, 0xa206, 0x00c0, - 0x1dbd, 0xa286, 0x0008, 0x00c0, 0x1dbd, 0x2071, 0x0010, 0x1078, - 0x1980, 0x0040, 0x1dbd, 0x7a9c, 0x7b98, 0x7ca4, 0x7da0, 0xa184, - 0xff00, 0x0040, 0x1d8b, 0x2031, 0x0000, 0x810b, 0x86b5, 0x810b, - 0x86b5, 0x810b, 0x86b5, 0x810b, 0x86b5, 0x810b, 0x86b5, 0x810b, - 0x86b5, 0x2100, 0xa210, 0x2600, 0xa319, 0xa4a1, 0x0000, 0xa5a9, - 0x0000, 0x0078, 0x1d95, 0x8107, 0x8004, 0x8004, 0xa210, 0xa399, - 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x2009, 0x0020, 0x1078, - 0x197b, 0x2091, 0x8001, 0x0040, 0x1db4, 0x1078, 0x199a, 0x78a8, - 0x8000, 0x78aa, 0xa086, 0x0002, 0x00c0, 0x1dbd, 0x2091, 0x8000, - 0x78e3, 0x0002, 0x78ab, 0x0000, 0x78cc, 0xa085, 0x0003, 0x78ce, - 0x2091, 0x8001, 0x0078, 0x1dbd, 0x78ab, 0x0000, 0x1078, 0x2149, - 0x6004, 0xa084, 0x000f, 0x0079, 0x1dc2, 0x2071, 0x0010, 0x2091, - 0x8001, 0x007c, 0x1dd2, 0x1df4, 0x1e1a, 0x1dd2, 0x1e37, 0x1de1, - 0x1fc9, 0x1fe4, 0x1dd2, 0x1dee, 0x1e14, 0x1e7f, 0x1eee, 0x1f57, - 0x1f69, 0x1fe0, 0x2039, 0x0400, 0x78dc, 0xa705, 0x78de, 0x6008, - 0xa705, 0x600a, 0x1078, 0x2064, 0x609c, 0x78da, 0x1078, 0x2131, - 0x007c, 0x78dc, 0xa084, 0x0100, 0x0040, 0x1de8, 0x0078, 0x1dd2, - 0x601c, 0xa085, 0x0080, 0x601e, 0x0078, 0x1dfb, 0x1078, 0x1bc4, - 0x00c0, 0x1dd2, 0x1078, 0x2163, 0x78dc, 0xa084, 0x0100, 0x0040, - 0x1dfb, 0x0078, 0x1dd2, 0x78df, 0x0000, 0x6004, 0x8007, 0xa084, - 0x00ff, 0x78d2, 0x8001, 0x609f, 0x0000, 0x0040, 0x1e11, 0x1078, - 0x2064, 0x0040, 0x1e11, 0x78dc, 0xa085, 0x0100, 0x78de, 0x0078, - 0x1e13, 0x1078, 0x2088, 0x007c, 0x1078, 0x1bc4, 0x00c0, 0x1dd2, - 0x1078, 0x215f, 0x78dc, 0xa08c, 0x0e00, 0x00c0, 0x1e23, 0xa084, - 0x0100, 0x00c0, 0x1e25, 0x0078, 0x1dd2, 0x1078, 0x2064, 0x00c0, - 0x1e36, 0x6104, 0xa18c, 0x00ff, 0xa186, 0x0007, 0x0040, 0x2021, - 0xa186, 0x000f, 0x0040, 0x2021, 0x1078, 0x2088, 0x007c, 0x78dc, - 0xa084, 0x0100, 0x0040, 0x1e3e, 0x0078, 0x1dd2, 0x78df, 0x0000, - 0x6714, 0x2011, 0x0001, 0x20a9, 0x0001, 0x6018, 0xa084, 0x00ff, - 0xa005, 0x0040, 0x1e61, 0x2011, 0x0001, 0xa7bc, 0xff00, 0x20a9, - 0x0020, 0xa08e, 0x0001, 0x0040, 0x1e61, 0x2039, 0x0000, 0x2011, - 0x0002, 0x20a9, 0x0100, 0xa08e, 0x0002, 0x0040, 0x1e61, 0x0078, - 0x1e7c, 0x1078, 0x19c5, 0x2091, 0x8000, 0x682b, 0x0000, 0x682f, - 0x0000, 0x6808, 0xa084, 0xffde, 0x680a, 0xade8, 0x0010, 0x2091, - 0x8001, 0x0070, 0x1e75, 0x0078, 0x1e63, 0x8211, 0x0040, 0x1e7c, - 0x20a9, 0x0100, 0x0078, 0x1e63, 0x1078, 0x199a, 0x007c, 0x2001, - 0x5267, 0x2004, 0xa084, 0x8000, 0x0040, 0x2049, 0x6114, 0x1078, - 0x2180, 0x6900, 0xa184, 0x0001, 0x0040, 0x1ea0, 0x6028, 0xa084, - 0x00ff, 0x00c0, 0x2041, 0x6800, 0xa084, 0x0001, 0x0040, 0x2049, - 0x6803, 0x0000, 0x680b, 0x0000, 0x6807, 0x0000, 0x0078, 0x2051, - 0x2011, 0x0001, 0x6020, 0xd0f4, 0x0040, 0x1ea8, 0xa295, 0x0002, - 0xd0c4, 0x0040, 0x1ead, 0xa295, 0x0008, 0xd0cc, 0x0040, 0x1eb2, - 0xa295, 0x0400, 0x601c, 0xa084, 0x0002, 0x0040, 0x1eb9, 0xa295, - 0x0004, 0x602c, 0xa08c, 0x00ff, 0xa182, 0x0002, 0x0048, 0x204d, - 0xa182, 0x001b, 0x00c8, 0x204d, 0x0040, 0x204d, 0x690e, 0x602c, - 0x8007, 0xa08c, 0x00ff, 0xa182, 0x0002, 0x0048, 0x204d, 0xa182, - 0x001b, 0x00c8, 0x204d, 0x0040, 0x204d, 0x6912, 0x6030, 0xa005, - 0x00c0, 0x1edc, 0x2001, 0x001e, 0x8000, 0x6816, 0x6028, 0xa084, - 0x00ff, 0x0040, 0x2049, 0x6806, 0x6028, 0x8007, 0xa084, 0x00ff, - 0x0040, 0x2049, 0x680a, 0x6a02, 0x0078, 0x2051, 0x2001, 0x5240, - 0x2004, 0xa086, 0x0007, 0x00c0, 0x1f53, 0x2001, 0x5267, 0x2004, - 0xa084, 0x8000, 0x0040, 0x2049, 0x6114, 0x1078, 0x2180, 0x2001, - 0x5252, 0x2004, 0x2010, 0x82ff, 0x0040, 0x1f0e, 0xa080, 0x0005, - 0x2004, 0xa084, 0x00ff, 0xa106, 0x00c0, 0x1f53, 0x2091, 0x8000, - 0x6a04, 0x6b08, 0x6418, 0xa484, 0x0003, 0x0040, 0x1f2d, 0x6128, - 0xa18c, 0x00ff, 0x8001, 0x00c0, 0x1f23, 0x2100, 0xa210, 0x0048, - 0x1f53, 0x0078, 0x1f2d, 0x8001, 0x00c0, 0x1f53, 0x2100, 0xa212, - 0x0048, 0x1f53, 0x82ff, 0x0040, 0x1f53, 0xa484, 0x000c, 0x0040, - 0x1f47, 0x6128, 0x810f, 0xa18c, 0x00ff, 0xa082, 0x0004, 0x00c0, - 0x1f3f, 0x2100, 0xa318, 0x0048, 0x1f53, 0x0078, 0x1f47, 0xa082, - 0x0004, 0x00c0, 0x1f53, 0x2100, 0xa31a, 0x0048, 0x1f53, 0x6030, - 0xa005, 0x0040, 0x1f4d, 0x8000, 0x6816, 0x6a06, 0x6b0a, 0x2091, - 0x8001, 0x0078, 0x2051, 0x2091, 0x8001, 0x0078, 0x204d, 0x6114, - 0x1078, 0x2180, 0x2091, 0x8000, 0x6b08, 0x8318, 0x0048, 0x1f65, - 0x6b0a, 0x2091, 0x8001, 0x0078, 0x2060, 0x2091, 0x8001, 0x0078, - 0x204d, 0x6024, 0x8007, 0xa084, 0x00ff, 0x0040, 0x1f87, 0xa086, - 0x0080, 0x00c0, 0x1fc7, 0x20a9, 0x0008, 0x2069, 0x7610, 0x2091, - 0x8000, 0x6800, 0xa084, 0xfcff, 0x6802, 0xade8, 0x0008, 0x0070, - 0x1f83, 0x0078, 0x1f79, 0x2091, 0x8001, 0x0078, 0x2051, 0x6028, - 0xa015, 0x0040, 0x1fc7, 0x6114, 0x1078, 0x2180, 0x0c7e, 0x0d7e, - 0xade8, 0x0007, 0x2091, 0x8000, 0x6800, 0xa00d, 0x0040, 0x1fc3, - 0xa206, 0x0040, 0x1f9e, 0x2168, 0x0078, 0x1f94, 0x2160, 0x6000, - 0x6802, 0x2c68, 0x1078, 0x19ac, 0x0d7f, 0x6818, 0xa00d, 0x0040, - 0x1fbb, 0x2060, 0x6200, 0x6a1a, 0x6a1c, 0x6202, 0x681e, 0x1078, - 0x1989, 0x2da0, 0x2198, 0x20a9, 0x0031, 0x53a3, 0x2d60, 0x1078, - 0x1ccb, 0x0078, 0x1fbe, 0x6808, 0x8000, 0x680a, 0x2091, 0x8001, - 0x0c7f, 0x0078, 0x2060, 0x2091, 0x8001, 0x0d7f, 0x0c7f, 0x0078, - 0x2049, 0x6114, 0x1078, 0x2180, 0x6800, 0xa084, 0x0001, 0x0040, - 0x2039, 0x2091, 0x8000, 0x6a04, 0x8210, 0x0048, 0x1fdc, 0x6a06, - 0x2091, 0x8001, 0x0078, 0x2060, 0x2091, 0x8001, 0x0078, 0x204d, - 0x1078, 0x1bc4, 0x00c0, 0x1dd2, 0x6114, 0x1078, 0x2180, 0x60be, - 0x60bb, 0x0000, 0x6900, 0xa184, 0x0008, 0x0040, 0x1ff3, 0x6020, - 0xa085, 0x0100, 0x6022, 0xa184, 0x0001, 0x0040, 0x2049, 0xa184, - 0x0100, 0x00c0, 0x2035, 0xa184, 0x0200, 0x00c0, 0x2031, 0x681c, - 0xa005, 0x00c0, 0x203d, 0x6004, 0xa084, 0x00ff, 0xa086, 0x000f, - 0x00c0, 0x200c, 0x1078, 0x2163, 0x78df, 0x0000, 0x6004, 0x8007, - 0xa084, 0x00ff, 0x78d2, 0x8001, 0x609f, 0x0000, 0x0040, 0x2021, - 0x1078, 0x2064, 0x0040, 0x2021, 0x78dc, 0xa085, 0x0100, 0x78de, - 0x007c, 0x78d7, 0x0000, 0x78db, 0x0000, 0x6024, 0xa084, 0xff00, - 0x6026, 0x1078, 0x3aac, 0x0040, 0x1d4f, 0x1078, 0x1be9, 0x0078, - 0x1d4f, 0x2009, 0x0017, 0x0078, 0x2053, 0x2009, 0x000e, 0x0078, - 0x2053, 0x2009, 0x0007, 0x0078, 0x2053, 0x2009, 0x0035, 0x0078, - 0x2053, 0x2009, 0x003e, 0x0078, 0x2053, 0x2009, 0x0004, 0x0078, - 0x2053, 0x2009, 0x0006, 0x0078, 0x2053, 0x2009, 0x0016, 0x0078, - 0x2053, 0x2009, 0x0001, 0x6024, 0xa084, 0xff00, 0xa105, 0x6026, - 0x2091, 0x8000, 0x1078, 0x1ccb, 0x2091, 0x8001, 0x0078, 0x1d4f, - 0x1078, 0x199a, 0x0078, 0x1d4f, 0x78d4, 0xa06d, 0x00c0, 0x206f, - 0x2c00, 0x78d6, 0x78da, 0x609f, 0x0000, 0x0078, 0x207b, 0x2c00, - 0x689e, 0x609f, 0x0000, 0x78d6, 0x2d00, 0x6002, 0x78d8, 0xad06, - 0x00c0, 0x207b, 0x6002, 0x78d0, 0x8001, 0x78d2, 0x00c0, 0x2087, - 0x78dc, 0xa084, 0xfeff, 0x78de, 0x78d8, 0x2060, 0xa006, 0x007c, - 0xa02e, 0x2530, 0x611c, 0x61a2, 0xa184, 0xe1ff, 0x601e, 0xa184, - 0x0060, 0x0040, 0x2097, 0x0e7e, 0x1078, 0x48d3, 0x0e7f, 0x6596, - 0x65a6, 0x669a, 0x66aa, 0x60af, 0x0000, 0x60b3, 0x0000, 0x6714, - 0x1078, 0x19c5, 0x2091, 0x8000, 0x60a0, 0xa084, 0x8000, 0x00c0, - 0x20be, 0x6808, 0xa084, 0x0001, 0x0040, 0x20be, 0x2091, 0x8001, - 0x1078, 0x1a31, 0x2091, 0x8000, 0x1078, 0x1ccb, 0x2091, 0x8001, - 0x78d7, 0x0000, 0x78db, 0x0000, 0x0078, 0x2130, 0x6024, 0xa096, - 0x0001, 0x00c0, 0x20c5, 0x8000, 0x6026, 0x6a10, 0x6814, 0x2091, - 0x8001, 0xa202, 0x0048, 0x20d4, 0x0040, 0x20d4, 0x2039, 0x0200, - 0x1078, 0x2131, 0x0078, 0x2130, 0x2c08, 0x2091, 0x8000, 0x60a0, - 0xa084, 0x8000, 0x0040, 0x2101, 0x6800, 0xa065, 0x0040, 0x2106, - 0x6a04, 0x0e7e, 0x2071, 0x5240, 0x7000, 0xa084, 0x0001, 0x0040, - 0x20fb, 0x7048, 0xa206, 0x00c0, 0x20fb, 0x6b04, 0x231c, 0x2160, - 0x6302, 0x2300, 0xa005, 0x00c0, 0x20f6, 0x6902, 0x2260, 0x6102, - 0x0e7f, 0x0078, 0x210d, 0x2160, 0x6202, 0x6906, 0x0e7f, 0x0078, - 0x210d, 0x6800, 0xa065, 0x0040, 0x2106, 0x6102, 0x6902, 0x00c0, - 0x210a, 0x6906, 0x2160, 0x6003, 0x0000, 0x2160, 0x60a0, 0xa084, - 0x8000, 0x0040, 0x2117, 0x6808, 0xa084, 0xfffc, 0x680a, 0x6810, - 0x8000, 0x6812, 0x2091, 0x8001, 0x6808, 0xa08c, 0x0040, 0x0040, - 0x2126, 0xa086, 0x0040, 0x680a, 0x1078, 0x1a42, 0x2091, 0x8000, - 0x1078, 0x226f, 0x2091, 0x8001, 0x78db, 0x0000, 0x78d7, 0x0000, - 0x007c, 0x6008, 0xa705, 0x600a, 0x2091, 0x8000, 0x1078, 0x1ccb, - 0x2091, 0x8001, 0x78d8, 0xa065, 0x0040, 0x2144, 0x609c, 0x78da, - 0x609f, 0x0000, 0x0078, 0x2134, 0x78d7, 0x0000, 0x78db, 0x0000, - 0x007c, 0x7990, 0x7894, 0x8000, 0xa10a, 0x00c8, 0x2150, 0xa006, - 0x7896, 0x70d2, 0x7804, 0xa005, 0x0040, 0x215e, 0x8001, 0x7806, - 0x00c0, 0x215e, 0x0068, 0x215e, 0x2091, 0x4080, 0x007c, 0x2039, - 0x2177, 0x0078, 0x2165, 0x2039, 0x217d, 0x2704, 0xa005, 0x0040, - 0x2176, 0xac00, 0x2068, 0x6b08, 0x6c0c, 0x6910, 0x6a14, 0x690a, - 0x6a0e, 0x6b12, 0x6c16, 0x8738, 0x0078, 0x2165, 0x007c, 0x0003, - 0x0009, 0x000f, 0x0015, 0x001b, 0x0000, 0x0015, 0x001b, 0x0000, - 0x0c7e, 0x1078, 0x3c3b, 0x2c68, 0x0c7f, 0x007c, 0x0010, 0x21f7, - 0x0068, 0x21f7, 0x2029, 0x0000, 0x78cb, 0x0000, 0x788c, 0xa065, - 0x0040, 0x21f0, 0x2009, 0x5274, 0x2104, 0xa084, 0x0001, 0x0040, - 0x21be, 0x6004, 0xa086, 0x0103, 0x00c0, 0x21be, 0x6018, 0xa005, - 0x00c0, 0x21be, 0x6014, 0xa005, 0x00c0, 0x21be, 0x0d7e, 0x2069, - 0x0000, 0x6818, 0xa084, 0x0001, 0x00c0, 0x21bd, 0x600c, 0x70c6, - 0x6010, 0x70ca, 0x70c3, 0x8020, 0x681b, 0x0001, 0x2091, 0x4080, - 0x0d7f, 0x1078, 0x1cf2, 0x0078, 0x21f5, 0x0d7f, 0x1078, 0x21f8, - 0x0040, 0x21f0, 0x6204, 0xa294, 0x00ff, 0xa296, 0x0003, 0x0040, - 0x21d0, 0x6204, 0xa296, 0x0110, 0x00c0, 0x21de, 0x78cb, 0x0001, - 0x6204, 0xa294, 0xff00, 0x8217, 0x8211, 0x0040, 0x21de, 0x85ff, - 0x00c0, 0x21f0, 0x8210, 0xa202, 0x00c8, 0x21f0, 0x057e, 0x1078, - 0x2207, 0x057f, 0x0040, 0x21eb, 0x78e0, 0xa086, 0x0003, 0x0040, - 0x21f0, 0x0078, 0x21de, 0x8528, 0x78c8, 0xa005, 0x0040, 0x218e, - 0x85ff, 0x0040, 0x21f7, 0x2091, 0x4080, 0x78b0, 0x70d6, 0x007c, - 0x7bac, 0x79b0, 0x70d4, 0xa102, 0x00c0, 0x2201, 0x2300, 0xa005, - 0x007c, 0x0048, 0x2205, 0xa302, 0x007c, 0x8002, 0x007c, 0x2001, - 0x04fd, 0x2004, 0xa082, 0x0005, 0x00c8, 0x2221, 0x2091, 0x8000, - 0x2071, 0x0020, 0x7004, 0xa005, 0x00c0, 0x2256, 0x7008, 0x7208, - 0xa206, 0x00c0, 0x2256, 0xa286, 0x0008, 0x00c0, 0x2256, 0x2071, - 0x0010, 0x1078, 0x225b, 0x2009, 0x0020, 0x6004, 0xa086, 0x0103, - 0x00c0, 0x2230, 0x6028, 0xa005, 0x00c0, 0x2230, 0x2009, 0x000c, - 0x1078, 0x1976, 0x0040, 0x2249, 0x78c4, 0x8000, 0x78c6, 0xa086, - 0x0002, 0x00c0, 0x2256, 0x2091, 0x8000, 0x78e3, 0x0003, 0x78c7, - 0x0000, 0x78cc, 0xa085, 0x0300, 0x78ce, 0x2091, 0x8001, 0x0078, - 0x2256, 0x78c7, 0x0000, 0x1078, 0x1cf2, 0x79ac, 0x78b0, 0x8000, - 0xa10a, 0x00c8, 0x2254, 0xa006, 0x78b2, 0xa006, 0x2071, 0x0010, - 0x2091, 0x8001, 0x007c, 0x8107, 0x8004, 0x8004, 0x7ab8, 0x7bb4, - 0x7cc0, 0x7dbc, 0xa210, 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, - 0x0000, 0x007c, 0x2009, 0x525b, 0x2091, 0x8000, 0x200a, 0x0f7e, - 0x0e7e, 0x2071, 0x5240, 0x7000, 0xa086, 0x0000, 0x00c0, 0x2289, - 0x2009, 0x5212, 0x2104, 0xa005, 0x00c0, 0x2289, 0x2079, 0x0100, - 0x7830, 0xa084, 0x00c0, 0x00c0, 0x2289, 0x0018, 0x2289, 0x781b, - 0x004b, 0x0e7f, 0x0f7f, 0x007c, 0x0f7e, 0x0e7e, 0x2071, 0x5240, - 0x2091, 0x8000, 0x7000, 0xa086, 0x0000, 0x00c0, 0x22a2, 0x2079, - 0x0100, 0x7830, 0xa084, 0x00c0, 0x00c0, 0x22a2, 0x0018, 0x22a2, - 0x781b, 0x004d, 0x2091, 0x8001, 0x0e7f, 0x0f7f, 0x007c, 0x127e, - 0x2091, 0x2300, 0x2071, 0x5240, 0x2079, 0x0100, 0x784b, 0x000f, - 0x0098, 0x22b5, 0x7838, 0x0078, 0x22ae, 0x20a9, 0x0040, 0x7800, - 0xa082, 0x0004, 0x0048, 0x22be, 0x20a9, 0x0060, 0x789b, 0x0000, - 0x78af, 0x0000, 0x78af, 0x0000, 0x0070, 0x22c8, 0x0078, 0x22c0, - 0x7800, 0xa082, 0x0004, 0x0048, 0x22d7, 0x70b7, 0x0093, 0x2019, - 0x4ff0, 0x1078, 0x2313, 0x702f, 0x8001, 0x0078, 0x22e3, 0x70b7, - 0x0000, 0x2019, 0x4e70, 0x1078, 0x2313, 0x2019, 0x4eaf, 0x1078, - 0x2313, 0x702f, 0x8000, 0x7003, 0x0000, 0x1078, 0x2420, 0x7004, - 0xa084, 0x000f, 0x017e, 0x2009, 0x04fd, 0x210c, 0xa18a, 0x0005, - 0x0048, 0x22f8, 0x0038, 0x22fe, 0xa085, 0x6280, 0x0078, 0x2300, - 0x0028, 0x22fe, 0xa085, 0x6280, 0x0078, 0x2300, 0xa085, 0x62c0, - 0x017f, 0x7806, 0x780f, 0xb204, 0x7843, 0x00d8, 0x7853, 0x0080, - 0x780b, 0x0008, 0x7047, 0x0008, 0x7053, 0x527f, 0x704f, 0x0000, - 0x127f, 0x2000, 0x007c, 0x137e, 0x147e, 0x157e, 0x047e, 0x20a1, - 0x012b, 0x2304, 0xa005, 0x789a, 0x0040, 0x2333, 0x8318, 0x2324, - 0x8318, 0x2398, 0x24a8, 0xa484, 0xff00, 0x0040, 0x232b, 0xa482, - 0x0100, 0x20a9, 0x0100, 0x2020, 0x53a6, 0xa005, 0x00c0, 0x2322, - 0x3318, 0x0078, 0x2319, 0x047f, 0x157f, 0x147f, 0x137f, 0x007c, - 0xa18c, 0x000f, 0x2011, 0x0101, 0x2204, 0xa084, 0xfff0, 0xa105, - 0x2012, 0x1078, 0x2420, 0x007c, 0x2011, 0x0101, 0x20a9, 0x0009, - 0x810b, 0x0070, 0x234d, 0x0078, 0x2348, 0xa18c, 0x0e00, 0x2204, - 0xa084, 0xf1ff, 0xa105, 0x2012, 0x007c, 0x2009, 0x0101, 0x20a9, - 0x0005, 0x8213, 0x0070, 0x235e, 0x0078, 0x2359, 0xa294, 0x00e0, - 0x2104, 0xa084, 0xff1f, 0xa205, 0x200a, 0x007c, 0x2011, 0x0101, - 0x20a9, 0x000c, 0x810b, 0x0070, 0x236f, 0x0078, 0x236a, 0xa18c, - 0xf000, 0x2204, 0xa084, 0x0fff, 0xa105, 0x2012, 0x007c, 0x2011, - 0x0102, 0x2204, 0xa084, 0xffcf, 0xa105, 0x2012, 0x007c, 0x8103, - 0x8003, 0xa080, 0x0020, 0x0c7e, 0x2061, 0x0100, 0x609a, 0x62ac, - 0x63ac, 0x0c7f, 0x007c, 0x8103, 0x8003, 0xa080, 0x0022, 0x0c7e, - 0x2061, 0x0100, 0x609a, 0x60a4, 0xa084, 0xffdf, 0x60ae, 0x0c7f, - 0x007c, 0x8103, 0x8003, 0xa080, 0x0022, 0x0c7e, 0x2061, 0x0100, - 0x609a, 0x60a4, 0xa085, 0x0020, 0x60ae, 0x0c7f, 0x007c, 0x8103, - 0x8003, 0xa080, 0x0020, 0x0c7e, 0x2061, 0x0100, 0x609a, 0x60a4, - 0x62ae, 0x2010, 0x60a4, 0x63ae, 0x2018, 0x0c7f, 0x007c, 0x2091, - 0x8000, 0x0c7e, 0x0e7e, 0x6818, 0xa005, 0x0040, 0x23fe, 0x2061, - 0x7600, 0x1078, 0x2406, 0x0040, 0x23e8, 0x20a9, 0x0000, 0x2061, - 0x7500, 0x0c7e, 0x1078, 0x2406, 0x0040, 0x23d6, 0x0c7f, 0x8c60, - 0x0070, 0x23d4, 0x0078, 0x23c9, 0x0078, 0x23fe, 0x007f, 0xa082, - 0x7500, 0x2071, 0x5240, 0x7086, 0x7182, 0x2001, 0x0004, 0x706e, - 0x7093, 0x000f, 0x7073, 0x0000, 0x1078, 0x226a, 0x0078, 0x23fa, - 0x60c0, 0xa005, 0x00c0, 0x23fe, 0x2071, 0x5240, 0x7182, 0x2c00, - 0x708a, 0x2001, 0x0006, 0x706e, 0x7093, 0x000f, 0x7073, 0x0000, - 0x1078, 0x226a, 0x2001, 0x0000, 0x0078, 0x2400, 0x2001, 0x0001, - 0x2091, 0x8001, 0xa005, 0x0e7f, 0x0c7f, 0x007c, 0x2c04, 0xa005, - 0x0040, 0x241d, 0x2060, 0x600c, 0xa306, 0x00c0, 0x241a, 0x6010, - 0xa206, 0x00c0, 0x241a, 0x6014, 0xa106, 0x00c0, 0x241a, 0xa006, - 0x0078, 0x241f, 0x6000, 0x0078, 0x2407, 0xa085, 0x0001, 0x007c, - 0x2011, 0x5241, 0x220c, 0xa18c, 0x000f, 0x2011, 0x013b, 0x2204, - 0xa084, 0x0100, 0x0040, 0x2436, 0x2021, 0xff04, 0x2122, 0x810b, - 0x810b, 0x810b, 0x810b, 0xa18d, 0x0f00, 0x2104, 0x007c, 0x0e7e, - 0x68e4, 0xa08c, 0x0020, 0x0040, 0x248a, 0xa084, 0x0006, 0x00c0, - 0x248a, 0x6014, 0x8007, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, - 0xa0f0, 0x5480, 0x7004, 0xa084, 0x000a, 0x00c0, 0x248a, 0x7108, - 0xa194, 0xff00, 0x0040, 0x248a, 0xa18c, 0x00ff, 0x2001, 0x000c, - 0xa106, 0x0040, 0x2471, 0x2001, 0x0012, 0xa106, 0x0040, 0x2475, - 0x2001, 0x0014, 0xa106, 0x0040, 0x2479, 0x2001, 0x0019, 0xa106, - 0x0040, 0x247d, 0x2001, 0x0032, 0xa106, 0x0040, 0x2481, 0x0078, - 0x2485, 0x2009, 0x0012, 0x0078, 0x2487, 0x2009, 0x0014, 0x0078, - 0x2487, 0x2009, 0x0019, 0x0078, 0x2487, 0x2009, 0x0020, 0x0078, - 0x2487, 0x2009, 0x003f, 0x0078, 0x2487, 0x2011, 0x0000, 0x2100, - 0xa205, 0x700a, 0x0e7f, 0x007c, 0x0068, 0x248c, 0x2091, 0x8000, - 0x2071, 0x0000, 0x007e, 0x7018, 0xa084, 0x0001, 0x00c0, 0x2493, - 0x007f, 0x2071, 0x0010, 0x70ca, 0x007f, 0x70c6, 0x70c3, 0x8002, - 0x70db, 0x0741, 0x70df, 0x0006, 0x2071, 0x0000, 0x701b, 0x0001, - 0x2091, 0x4080, 0x0078, 0x24aa, 0x107e, 0x007e, 0x127e, 0x2091, - 0x2300, 0x7f3c, 0x7e58, 0x7c30, 0x7d38, 0x77c2, 0x74c6, 0x76ca, - 0x75ce, 0xa594, 0x003f, 0xa49c, 0x0003, 0xa484, 0x000f, 0x0079, - 0x24c1, 0x24d3, 0x24d3, 0x24d3, 0x280d, 0x3a09, 0x24d1, 0x2502, - 0x250c, 0x24d1, 0x24d1, 0x24d1, 0x24d1, 0x24d1, 0x24d1, 0x24d1, - 0x24d1, 0x1078, 0x248c, 0x8507, 0xa084, 0x001f, 0x0079, 0x24d8, - 0x2516, 0x280d, 0x29c7, 0x2ac4, 0x2aec, 0x2d8c, 0x3037, 0x309a, - 0x30fb, 0x3180, 0x3238, 0x32d6, 0x2502, 0x28e9, 0x300c, 0x24f8, - 0x3dac, 0x3dcc, 0x3f8f, 0x3f9b, 0x4074, 0x24f8, 0x24f8, 0x4149, - 0x414d, 0x3daa, 0x24f8, 0x3efa, 0x24f8, 0x3c5e, 0x250c, 0x24f8, - 0x1078, 0x248c, 0x0018, 0x24b1, 0x127f, 0x2091, 0x8001, 0x007f, - 0x107f, 0x007c, 0x2019, 0x4f49, 0x1078, 0x2313, 0x702f, 0x0001, - 0x781b, 0x004f, 0x0078, 0x24fa, 0x2019, 0x4eaf, 0x1078, 0x2313, - 0x702f, 0x8000, 0x781b, 0x00cd, 0x0078, 0x24fa, 0x7242, 0x2009, - 0x520f, 0x200b, 0x0000, 0xa584, 0x0001, 0x00c0, 0x3c72, 0x0040, - 0x2533, 0x1078, 0x248c, 0x7003, 0x0000, 0x704b, 0x0000, 0x7043, - 0x0000, 0x7037, 0x0000, 0x1078, 0x39e0, 0x0018, 0x24b1, 0x2009, - 0x520f, 0x200b, 0x0000, 0x7068, 0xa005, 0x00c0, 0x25fe, 0x706c, - 0xa084, 0x0007, 0x0079, 0x253c, 0x2635, 0x2544, 0x2550, 0x256d, - 0x258f, 0x25dc, 0x25b5, 0x2544, 0x1078, 0x39c8, 0x2009, 0x0048, - 0x1078, 0x2ed8, 0x00c0, 0x254e, 0x7003, 0x0004, 0x0078, 0x24fa, - 0x1078, 0x39c8, 0x00c0, 0x256b, 0x7080, 0x8007, 0x7882, 0x789b, - 0x0010, 0x78ab, 0x000c, 0x789b, 0x0060, 0x78ab, 0x0001, 0x785b, - 0x0004, 0x2009, 0x00dd, 0x1078, 0x2ecc, 0x00c0, 0x256b, 0x7003, - 0x0004, 0x7093, 0x000f, 0x0078, 0x24fa, 0x1078, 0x39c8, 0x00c0, - 0x258d, 0x7180, 0x8107, 0x7882, 0x789b, 0x0010, 0xa18c, 0x001f, - 0xa18d, 0x00c0, 0x79aa, 0x78ab, 0x0006, 0x789b, 0x0060, 0x78ab, - 0x0002, 0x785b, 0x0004, 0x2009, 0x00dd, 0x1078, 0x2ecc, 0x00c0, - 0x258d, 0x7003, 0x0004, 0x7093, 0x000f, 0x0078, 0x24fa, 0x1078, - 0x39c8, 0x00c0, 0x25b3, 0x7180, 0x8107, 0x7882, 0x789b, 0x0010, - 0xa18c, 0x001f, 0xa18d, 0x00c0, 0x79aa, 0x78ab, 0x0020, 0x7184, - 0x79aa, 0x78ab, 0x000d, 0x789b, 0x0060, 0x78ab, 0x0004, 0x785b, - 0x0004, 0x2009, 0x00dd, 0x1078, 0x2ecc, 0x00c0, 0x25b3, 0x7003, - 0x0004, 0x7093, 0x000f, 0x0078, 0x24fa, 0x1078, 0x39c8, 0x00c0, - 0x25da, 0x7180, 0x8107, 0x7882, 0x789b, 0x0010, 0xa18c, 0x001f, - 0xa18d, 0x00c0, 0x79aa, 0x78ab, 0x0006, 0x789b, 0x0060, 0x78ab, - 0x0002, 0x785b, 0x0004, 0x2009, 0x00dd, 0x1078, 0x2ecc, 0x00c0, - 0x25da, 0x7088, 0x708b, 0x0000, 0x2068, 0x704a, 0x7003, 0x0002, - 0x7093, 0x000f, 0x0078, 0x24fa, 0x1078, 0x39c8, 0x00c0, 0x24fa, - 0x7088, 0x2068, 0x6f14, 0x1078, 0x38bd, 0x2c50, 0x1078, 0x3a7a, - 0x789b, 0x0010, 0x6814, 0xa084, 0x001f, 0xa085, 0x0080, 0x78aa, - 0x6e1c, 0x2041, 0x0001, 0x708c, 0xa084, 0x0400, 0x2001, 0x0004, - 0x0040, 0x25fc, 0x2001, 0x0006, 0x0078, 0x271d, 0x1078, 0x39c8, - 0x00c0, 0x24fa, 0x789b, 0x0010, 0x7068, 0x2068, 0x6f14, 0x1078, - 0x38bd, 0x2c50, 0x1078, 0x3a7a, 0x6008, 0xa085, 0x0010, 0x600a, - 0x6824, 0xa005, 0x0040, 0x261c, 0xa082, 0x0006, 0x0048, 0x261a, - 0x0078, 0x261c, 0x6827, 0x0005, 0x6b14, 0xa39c, 0x001f, 0xa39d, - 0x00c0, 0x7058, 0xa084, 0x8000, 0x0040, 0x262a, 0xa684, 0x0001, - 0x0040, 0x262c, 0xa39c, 0xffbf, 0x7baa, 0x2031, 0x0020, 0x2041, - 0x0001, 0x2001, 0x0003, 0x0078, 0x271d, 0x0018, 0x24b1, 0x744c, - 0xa485, 0x0000, 0x0040, 0x264f, 0xa080, 0x5280, 0x2030, 0x7150, - 0x8108, 0xa12a, 0x0048, 0x2646, 0x2009, 0x5280, 0x2164, 0x6504, - 0x85ff, 0x00c0, 0x2660, 0x8421, 0x00c0, 0x2640, 0x7152, 0x7003, - 0x0000, 0x704b, 0x0000, 0x7040, 0xa005, 0x0040, 0x3c72, 0x0078, - 0x24fa, 0x764c, 0xa6b0, 0x5280, 0x7150, 0x2600, 0x0078, 0x264b, - 0x7152, 0x2568, 0x2558, 0x754a, 0x2c50, 0x6034, 0xa085, 0x0000, - 0x00c0, 0x265d, 0x6708, 0x773a, 0xa784, 0x033f, 0x0040, 0x2696, - 0xa784, 0x0021, 0x00c0, 0x265d, 0xa784, 0x0002, 0x0040, 0x267f, - 0xa784, 0x0004, 0x0040, 0x265d, 0xa7bc, 0xfffb, 0x670a, 0xa784, - 0x0008, 0x00c0, 0x265d, 0xa784, 0x0010, 0x00c0, 0x265d, 0xa784, - 0x0200, 0x00c0, 0x265d, 0xa784, 0x0100, 0x0040, 0x2696, 0x6018, - 0xa005, 0x00c0, 0x265d, 0xa7bc, 0xfeff, 0x670a, 0x6823, 0x0000, - 0x6e1c, 0xa684, 0x000e, 0x6118, 0x0040, 0x26a6, 0x601c, 0xa102, - 0x0048, 0x26a9, 0x0040, 0x26a9, 0x0078, 0x2659, 0x81ff, 0x00c0, - 0x2659, 0x68c3, 0x0000, 0xa784, 0x0080, 0x00c0, 0x26b1, 0x700c, - 0x6022, 0xa7bc, 0xff7f, 0x670a, 0x1078, 0x3a7a, 0x0018, 0x24b1, - 0x789b, 0x0010, 0xa046, 0x1078, 0x39c8, 0x00c0, 0x24fa, 0x6b14, - 0xa39c, 0x001f, 0xa39d, 0x00c0, 0x7058, 0xa084, 0x8000, 0x0040, - 0x26cd, 0xa684, 0x0001, 0x0040, 0x26cf, 0xa39c, 0xffbf, 0xa684, - 0x0010, 0x0040, 0x26d5, 0xa39d, 0x0020, 0x7baa, 0x8840, 0xa684, - 0x000e, 0x00c0, 0x26e0, 0xa7bd, 0x0010, 0x670a, 0x0078, 0x271b, - 0x7158, 0xa18c, 0x0800, 0x0040, 0x34cb, 0x2011, 0x0020, 0xa684, - 0x0008, 0x00c0, 0x26f1, 0x8210, 0xa684, 0x0002, 0x00c0, 0x26f1, - 0x8210, 0x7aaa, 0x8840, 0x1078, 0x39e0, 0x6a14, 0x610c, 0x8108, - 0xa18c, 0x00ff, 0xa1e0, 0x7500, 0x2c64, 0x8cff, 0x0040, 0x2712, - 0x6014, 0xa206, 0x00c0, 0x26fc, 0x60b8, 0x8001, 0x60ba, 0x00c0, - 0x26f7, 0x0c7e, 0x2a60, 0x6008, 0xa085, 0x0100, 0x600a, 0x0c7f, - 0x0078, 0x2635, 0x1078, 0x39c8, 0x00c0, 0x24fa, 0x2a60, 0x610e, - 0x79aa, 0x8840, 0x7132, 0x2001, 0x0001, 0x007e, 0x715c, 0xa184, - 0x0018, 0x0040, 0x2738, 0xa184, 0x0010, 0x0040, 0x272b, 0x1078, - 0x36d0, 0x00c0, 0x275b, 0xa184, 0x0008, 0x0040, 0x2738, 0x69a0, - 0xa184, 0x0600, 0x00c0, 0x2738, 0x1078, 0x35bb, 0x0078, 0x275b, - 0x69a0, 0xa184, 0x0800, 0x0040, 0x274f, 0x0c7e, 0x027e, 0x2960, - 0x6000, 0xa085, 0x2000, 0x6002, 0x6104, 0xa18d, 0x0010, 0x6106, - 0x027f, 0x0c7f, 0x1078, 0x36d0, 0x00c0, 0x275b, 0x69a0, 0xa184, - 0x0200, 0x0040, 0x2757, 0x1078, 0x360c, 0x0078, 0x275b, 0xa184, - 0x0400, 0x00c0, 0x2734, 0x69a0, 0xa184, 0x1000, 0x0040, 0x2766, - 0x6914, 0xa18c, 0xff00, 0x810f, 0x1078, 0x238b, 0x007f, 0x7002, - 0xa68c, 0x00e0, 0xa684, 0x0060, 0x0040, 0x2774, 0xa086, 0x0060, - 0x00c0, 0x2774, 0xa18d, 0x4000, 0x88ff, 0x0040, 0x2779, 0xa18d, - 0x0004, 0x795a, 0x69b6, 0x789b, 0x0060, 0x2800, 0x78aa, 0x789b, - 0x0061, 0x6818, 0xa08d, 0x8000, 0xa084, 0x7fff, 0x691a, 0xa68c, - 0x0080, 0x0040, 0x2798, 0x7097, 0x0000, 0xa08a, 0x000d, 0x0050, - 0x2796, 0xa08a, 0x000c, 0x7196, 0x2001, 0x000c, 0x800c, 0x719a, - 0x78aa, 0x8008, 0x810c, 0x0040, 0x34d1, 0xa18c, 0x00f8, 0x00c0, - 0x34d1, 0x157e, 0x137e, 0x147e, 0x20a1, 0x012b, 0x789b, 0x0000, - 0x8000, 0x80ac, 0xad80, 0x000b, 0x2098, 0x53a6, 0x147f, 0x137f, - 0x157f, 0x6814, 0x8007, 0x7882, 0x6d94, 0x7dd6, 0x7dde, 0x6e98, - 0x7ed2, 0x7eda, 0x1078, 0x39c8, 0x00c0, 0x27cf, 0x702c, 0x8003, - 0x0048, 0x27c8, 0x2019, 0x4eaf, 0x1078, 0x2313, 0x702f, 0x8000, - 0x7830, 0xa084, 0x00c0, 0x00c0, 0x27cf, 0x0098, 0x27d7, 0x6008, - 0xa084, 0xffef, 0x600a, 0x1078, 0x39e0, 0x0078, 0x2523, 0x7200, - 0xa284, 0x0007, 0xa086, 0x0001, 0x00c0, 0x27e4, 0x781b, 0x004f, - 0x1078, 0x39e0, 0x0078, 0x27f5, 0x6ab4, 0xa295, 0x2000, 0x7a5a, - 0x781b, 0x004f, 0x1078, 0x39e0, 0x7200, 0x2500, 0xa605, 0x0040, - 0x27f5, 0xa284, 0x0007, 0x1079, 0x2803, 0xad80, 0x0009, 0x7036, - 0xa284, 0x0007, 0xa086, 0x0001, 0x00c0, 0x24fa, 0x6018, 0x8000, - 0x601a, 0x0078, 0x24fa, 0x280b, 0x4b4b, 0x4b4b, 0x4b3a, 0x4b4b, - 0x280b, 0x4b3a, 0x280b, 0x1078, 0x248c, 0x1078, 0x39c8, 0x0f7e, - 0x2079, 0x5200, 0x78cc, 0x0f7f, 0xa084, 0x0001, 0x0040, 0x2831, - 0x706c, 0xa086, 0x0001, 0x00c0, 0x2820, 0x706e, 0x0078, 0x28c4, - 0x706c, 0xa086, 0x0005, 0x00c0, 0x282f, 0x7088, 0x2068, 0x681b, - 0x0004, 0x6817, 0x0000, 0x6820, 0xa085, 0x0008, 0x6822, 0x706f, - 0x0000, 0x2011, 0x0004, 0x716c, 0xa186, 0x0001, 0x0040, 0x2852, - 0xa186, 0x0007, 0x00c0, 0x2842, 0x2009, 0x5238, 0x200b, 0x0005, - 0x0078, 0x2852, 0x2009, 0x5213, 0x2104, 0x2009, 0x5212, 0x200a, - 0x2009, 0x5238, 0x200b, 0x0001, 0x706f, 0x0000, 0x7073, 0x0001, - 0x0078, 0x2854, 0x706f, 0x0000, 0x1078, 0x4887, 0x157e, 0x20a9, - 0x0010, 0x2039, 0x0000, 0x1078, 0x37b0, 0xa7b8, 0x0100, 0x0070, - 0x2863, 0x0078, 0x285b, 0x157f, 0x7000, 0x0079, 0x2867, 0x2895, - 0x287c, 0x287c, 0x286f, 0x2895, 0x2895, 0x2895, 0x2895, 0x2021, - 0x525a, 0x2404, 0xa005, 0x0040, 0x2895, 0xad06, 0x00c0, 0x287c, - 0x6800, 0x2022, 0x0078, 0x288c, 0x6820, 0xa084, 0x0001, 0x00c0, - 0x2888, 0x6f14, 0x1078, 0x38bd, 0x1078, 0x34a2, 0x0078, 0x288c, - 0x7060, 0x2060, 0x6800, 0x6002, 0x6a1a, 0x6817, 0x0000, 0x6820, - 0xa085, 0x0008, 0x6822, 0x1078, 0x1cdc, 0x2021, 0x7600, 0x1078, - 0x28d1, 0x2021, 0x525a, 0x1078, 0x28d1, 0x157e, 0x20a9, 0x0000, - 0x2021, 0x7500, 0x1078, 0x28d1, 0x8420, 0x0070, 0x28a9, 0x0078, - 0x28a2, 0x2061, 0x5500, 0x2021, 0x0002, 0x20a9, 0x0100, 0x6018, - 0x6110, 0x81ff, 0x0040, 0x28b8, 0xa102, 0x0050, 0x28b8, 0x6012, - 0x601b, 0x0000, 0xace0, 0x0010, 0x0070, 0x28c0, 0x0078, 0x28af, - 0x8421, 0x00c0, 0x28ad, 0x157f, 0x709c, 0xa084, 0x8000, 0x0040, - 0x28cb, 0x1078, 0x3ace, 0x7003, 0x0000, 0x704b, 0x0000, 0x0078, - 0x24fa, 0x047e, 0x2404, 0xa005, 0x0040, 0x28e5, 0x2068, 0x6800, - 0x007e, 0x6a1a, 0x6817, 0x0000, 0x6820, 0xa085, 0x0008, 0x6822, - 0x1078, 0x1cdc, 0x007f, 0x0078, 0x28d3, 0x047f, 0x2023, 0x0000, - 0x007c, 0xa282, 0x0003, 0x0050, 0x28ef, 0x1078, 0x248c, 0x2300, - 0x0079, 0x28f2, 0x28f5, 0x2968, 0x2985, 0xa282, 0x0002, 0x0040, - 0x28fb, 0x1078, 0x248c, 0x706c, 0x706f, 0x0000, 0x7093, 0x0000, - 0x0079, 0x2902, 0x290a, 0x290a, 0x290c, 0x2940, 0x34d7, 0x290a, - 0x2940, 0x290a, 0x1078, 0x248c, 0x7780, 0x1078, 0x37b0, 0x7780, - 0xa7bc, 0x0f00, 0x1078, 0x38bd, 0x6018, 0xa005, 0x0040, 0x2937, - 0x2021, 0x7600, 0x2009, 0x0004, 0x2011, 0x0010, 0x1078, 0x29a0, - 0x0040, 0x2937, 0x157e, 0x20a9, 0x0000, 0x2021, 0x7500, 0x047e, - 0x2009, 0x0004, 0x2011, 0x0010, 0x1078, 0x29a0, 0x047f, 0x0040, - 0x2936, 0x8420, 0x0070, 0x2936, 0x0078, 0x2927, 0x157f, 0x8738, - 0xa784, 0x001f, 0x00c0, 0x2912, 0x0078, 0x2523, 0x0078, 0x2523, - 0x7780, 0x1078, 0x38bd, 0x6018, 0xa005, 0x0040, 0x2966, 0x2021, - 0x7600, 0x2009, 0x0005, 0x2011, 0x0020, 0x1078, 0x29a0, 0x0040, - 0x2966, 0x157e, 0x20a9, 0x0000, 0x2021, 0x7500, 0x047e, 0x2009, - 0x0005, 0x2011, 0x0020, 0x1078, 0x29a0, 0x047f, 0x0040, 0x2965, - 0x8420, 0x0070, 0x2965, 0x0078, 0x2956, 0x157f, 0x0078, 0x2523, - 0x2200, 0x0079, 0x296b, 0x296e, 0x2970, 0x2970, 0x1078, 0x248c, - 0x2009, 0x0012, 0x706c, 0xa086, 0x0002, 0x0040, 0x2979, 0x2009, - 0x000e, 0x6818, 0xa084, 0x8000, 0x0040, 0x297f, 0x691a, 0x706f, - 0x0000, 0x7073, 0x0001, 0x0078, 0x3956, 0x2200, 0x0079, 0x2988, - 0x298d, 0x2970, 0x298b, 0x1078, 0x248c, 0x1078, 0x4887, 0x7000, - 0xa086, 0x0001, 0x00c0, 0x3467, 0x1078, 0x34b8, 0x6008, 0xa084, - 0xffef, 0x600a, 0x1078, 0x345a, 0x0040, 0x3467, 0x0078, 0x2635, - 0x2404, 0xa005, 0x0040, 0x29c3, 0x2068, 0x2d04, 0x007e, 0x6814, - 0xa706, 0x0040, 0x29af, 0x2d20, 0x007f, 0x0078, 0x29a1, 0x007f, - 0x2022, 0x691a, 0x6817, 0x0000, 0x6820, 0xa205, 0x6822, 0x1078, - 0x1cdc, 0x6010, 0x8001, 0x6012, 0x6008, 0xa084, 0xffef, 0x600a, - 0x1078, 0x34b8, 0x007c, 0xa085, 0x0001, 0x0078, 0x29c2, 0x2300, - 0x0079, 0x29ca, 0x29cf, 0x29cd, 0x2a68, 0x1078, 0x248c, 0x78ec, - 0xa084, 0x0001, 0x00c0, 0x29e3, 0x7000, 0xa086, 0x0004, 0x00c0, - 0x29db, 0x0078, 0x2a06, 0x1078, 0x34b8, 0x6008, 0xa084, 0xffef, - 0x600a, 0x0078, 0x3467, 0x78e4, 0xa005, 0x00d0, 0x2a06, 0x0018, - 0x24fa, 0x2008, 0xa084, 0x0030, 0x00c0, 0x29f2, 0x781b, 0x004f, - 0x0078, 0x24fa, 0x78ec, 0xa084, 0x0003, 0x0040, 0x29ee, 0x2100, - 0xa084, 0x0007, 0x0079, 0x29fc, 0x2a3f, 0x2a4a, 0x2a30, 0x2a04, - 0x39bb, 0x39bb, 0x2a04, 0x2a59, 0x1078, 0x248c, 0x7000, 0xa086, - 0x0004, 0x00c0, 0x2a20, 0x706c, 0xa086, 0x0002, 0x00c0, 0x2a16, - 0x2011, 0x0002, 0x2019, 0x0000, 0x0078, 0x28e9, 0x706c, 0xa086, - 0x0006, 0x0040, 0x2a10, 0x706c, 0xa086, 0x0004, 0x0040, 0x2a10, - 0x79e4, 0xa184, 0x0030, 0x0040, 0x2a2a, 0x78ec, 0xa084, 0x0003, - 0x00c0, 0x2a2c, 0x0078, 0x300c, 0x2001, 0x0003, 0x0078, 0x2da0, - 0x6818, 0xa084, 0x8000, 0x0040, 0x2a37, 0x681b, 0x001d, 0x1078, - 0x378f, 0x782b, 0x3008, 0x781b, 0x0056, 0x0078, 0x24fa, 0x6818, - 0xa084, 0x8000, 0x0040, 0x2a46, 0x681b, 0x001d, 0x1078, 0x378f, - 0x0078, 0x3986, 0x6818, 0xa084, 0x8000, 0x0040, 0x2a51, 0x681b, - 0x001d, 0x1078, 0x378f, 0x782b, 0x3008, 0x781b, 0x00ca, 0x0078, - 0x24fa, 0x6818, 0xa084, 0x8000, 0x0040, 0x2a60, 0x681b, 0x001d, - 0x1078, 0x378f, 0x782b, 0x3008, 0x781b, 0x008f, 0x0078, 0x24fa, - 0xa584, 0x000f, 0x00c0, 0x2a85, 0x7000, 0x0079, 0x2a6f, 0x2523, - 0x2a79, 0x2a77, 0x3467, 0x3467, 0x3467, 0x3467, 0x2a77, 0x1078, - 0x248c, 0x1078, 0x34b8, 0x6008, 0xa084, 0xffef, 0x600a, 0x1078, - 0x345a, 0x0040, 0x3467, 0x0078, 0x2635, 0x78e4, 0xa005, 0x00d0, - 0x2a06, 0x0018, 0x2a06, 0x2008, 0xa084, 0x0030, 0x00c0, 0x2a94, - 0x781b, 0x004f, 0x0078, 0x24fa, 0x78ec, 0xa084, 0x0003, 0x0040, - 0x2a90, 0x2100, 0xa184, 0x0007, 0x0079, 0x2a9e, 0x2ab0, 0x2ab4, - 0x2aa8, 0x2aa6, 0x39bb, 0x39bb, 0x2aa6, 0x39b1, 0x1078, 0x248c, - 0x1078, 0x3797, 0x782b, 0x3008, 0x781b, 0x0056, 0x0078, 0x24fa, - 0x1078, 0x3797, 0x0078, 0x3986, 0x1078, 0x3797, 0x782b, 0x3008, - 0x781b, 0x00ca, 0x0078, 0x24fa, 0x1078, 0x3797, 0x782b, 0x3008, - 0x781b, 0x008f, 0x0078, 0x24fa, 0x2300, 0x0079, 0x2ac7, 0x2acc, - 0x2aca, 0x2ace, 0x1078, 0x248c, 0x0078, 0x3180, 0x681b, 0x0008, - 0x78a3, 0x0000, 0x79e4, 0xa184, 0x0030, 0x0040, 0x3180, 0x78ec, - 0xa084, 0x0003, 0x0040, 0x3180, 0xa184, 0x0007, 0x0079, 0x2ae0, - 0x2ae8, 0x2ab4, 0x2a30, 0x3956, 0x39bb, 0x39bb, 0x2ae8, 0x39b1, - 0x1078, 0x396a, 0x0078, 0x24fa, 0xa282, 0x0005, 0x0050, 0x2af2, - 0x1078, 0x248c, 0x2300, 0x0079, 0x2af5, 0x2af8, 0x2d4d, 0x2d5b, - 0x2200, 0x0079, 0x2afb, 0x2b15, 0x2b02, 0x2b15, 0x2b00, 0x2d32, - 0x1078, 0x248c, 0x789b, 0x0018, 0x78a8, 0xa084, 0x00ff, 0xa082, - 0x0020, 0x0048, 0x376b, 0xa08a, 0x0004, 0x00c8, 0x376b, 0x0079, - 0x2b11, 0x376b, 0x376b, 0x376b, 0x3719, 0x789b, 0x0018, 0x79a8, - 0xa184, 0x0080, 0x0040, 0x2b26, 0x0078, 0x376b, 0x7000, 0xa005, - 0x00c0, 0x2b1c, 0x2011, 0x0004, 0x0078, 0x32e9, 0xa184, 0x00ff, - 0xa08a, 0x0010, 0x00c8, 0x376b, 0x0079, 0x2b2e, 0x2b40, 0x2b3e, - 0x2b58, 0x2b5c, 0x2c17, 0x376b, 0x376b, 0x2c19, 0x376b, 0x376b, - 0x2d2e, 0x2d2e, 0x376b, 0x376b, 0x376b, 0x2d30, 0x1078, 0x248c, - 0xa684, 0x1000, 0x0040, 0x2b4d, 0x2001, 0x0500, 0x8000, 0x8000, - 0x783a, 0x781b, 0x008d, 0x0078, 0x24fa, 0x6818, 0xa084, 0x8000, - 0x0040, 0x2b56, 0x681b, 0x001d, 0x0078, 0x2b44, 0x0078, 0x3956, - 0x681b, 0x001d, 0x0078, 0x377b, 0x6920, 0x6922, 0xa684, 0x1800, - 0x00c0, 0x2b9d, 0x6820, 0xa084, 0x0001, 0x00c0, 0x2ba5, 0x6818, - 0xa086, 0x0008, 0x00c0, 0x2b6e, 0x681b, 0x0000, 0xa684, 0x0400, - 0x0040, 0x2c13, 0xa684, 0x0080, 0x0040, 0x2b99, 0x7097, 0x0000, - 0x6818, 0xa084, 0x003f, 0xa08a, 0x000d, 0x0050, 0x2b99, 0xa08a, - 0x000c, 0x7196, 0x2001, 0x000c, 0x800c, 0x719a, 0x789b, 0x0061, - 0x78aa, 0x157e, 0x137e, 0x147e, 0x20a1, 0x012b, 0x789b, 0x0000, - 0x8000, 0x80ac, 0xad80, 0x000b, 0x2098, 0x53a6, 0x147f, 0x137f, - 0x157f, 0x781b, 0x0058, 0x0078, 0x24fa, 0xa684, 0x1000, 0x0040, - 0x2ba5, 0x781b, 0x0065, 0x0078, 0x24fa, 0xa684, 0x0060, 0x0040, - 0x2c0f, 0xa684, 0x0800, 0x0040, 0x2c0f, 0xa684, 0x8000, 0x00c0, - 0x2bb3, 0x0078, 0x2bcb, 0xa6b4, 0x7fff, 0x7e5a, 0x6eb6, 0x7adc, - 0x79d8, 0x78d0, 0x801b, 0x00c8, 0x2bbe, 0x8000, 0xa084, 0x003f, - 0xa108, 0xa291, 0x0000, 0x6b98, 0x2100, 0xa302, 0x68b2, 0x6b94, - 0x2200, 0xa303, 0x68ae, 0xa684, 0x4000, 0x0040, 0x2bd3, 0xa6b4, - 0xbfff, 0x7e5a, 0x6eb6, 0x7000, 0xa086, 0x0003, 0x00c0, 0x2be0, - 0x1078, 0x493d, 0x1078, 0x4b3a, 0x781b, 0x0064, 0x0078, 0x24fa, - 0xa006, 0x1078, 0x4c41, 0x6ab0, 0x69ac, 0x6c98, 0x6b94, 0x2200, - 0xa105, 0x0040, 0x2bef, 0x2200, 0xa422, 0x2100, 0xa31b, 0x6caa, - 0x7cd2, 0x7cda, 0x6ba6, 0x7bd6, 0x7bde, 0x2300, 0xa405, 0x00c0, - 0x2c01, 0xa6b5, 0x4000, 0x7e5a, 0x6eb6, 0x781b, 0x0064, 0x0078, - 0x24fa, 0x781b, 0x0064, 0x2200, 0xa115, 0x00c0, 0x2c0b, 0x1078, - 0x4b4b, 0x0078, 0x24fa, 0x1078, 0x4b96, 0x0078, 0x24fa, 0x781b, - 0x0065, 0x0078, 0x24fa, 0x781b, 0x0058, 0x0078, 0x24fa, 0x1078, - 0x248c, 0x0078, 0x2c7a, 0x6920, 0xa184, 0x0100, 0x0040, 0x2c31, - 0xa18c, 0xfeff, 0x6922, 0x0c7e, 0x7054, 0x2060, 0x6000, 0xa084, - 0xefff, 0x6002, 0x6004, 0xa084, 0xfff5, 0x6006, 0x0c7f, 0x0078, - 0x2c69, 0xa184, 0x0200, 0x0040, 0x2c69, 0xa18c, 0xfdff, 0x6922, - 0x0c7e, 0x7054, 0x2060, 0x6000, 0xa084, 0xdfff, 0x6002, 0x6004, - 0xa084, 0xffef, 0x6006, 0x2008, 0x2c48, 0x0c7f, 0xa184, 0x0008, - 0x0040, 0x2c69, 0x1078, 0x38b9, 0x1078, 0x35bb, 0x88ff, 0x0040, - 0x2c69, 0x789b, 0x0060, 0x2800, 0x78aa, 0x7e58, 0xa6b5, 0x0004, - 0x7e5a, 0xa684, 0x0400, 0x00c0, 0x2c63, 0x782b, 0x3008, 0x781b, - 0x0056, 0x0078, 0x24fa, 0x782b, 0x3008, 0x781b, 0x0065, 0x0078, - 0x24fa, 0x7e58, 0xa684, 0x0400, 0x00c0, 0x2c72, 0x781b, 0x0058, - 0x0078, 0x24fa, 0x781b, 0x0065, 0x0078, 0x24fa, 0x0078, 0x3773, - 0x0078, 0x3773, 0x2019, 0x0000, 0x7990, 0xa18c, 0x0007, 0x00c0, - 0x2c88, 0x6820, 0xa084, 0x0100, 0x0040, 0x2c78, 0x2009, 0x0008, - 0x789b, 0x0010, 0x78a8, 0xa094, 0x00ff, 0xa286, 0x0001, 0x00c0, - 0x2cbf, 0x2300, 0x7ca8, 0xa400, 0x2018, 0xa102, 0x0040, 0x2cb7, - 0x0048, 0x2c9c, 0x0078, 0x2cb9, 0xa380, 0x0002, 0xa102, 0x00c8, - 0x2cb7, 0x6920, 0xa18c, 0xfcff, 0x6922, 0x0c7e, 0x7054, 0x2060, - 0x6000, 0xa084, 0xefef, 0x6002, 0x6004, 0xa084, 0xffe5, 0x6006, - 0x0c7f, 0x7e58, 0xa6b4, 0xfffb, 0x7e5a, 0x0078, 0x2c6a, 0x0078, - 0x2c1b, 0x24a8, 0x7aa8, 0x00f0, 0x2cb9, 0x0078, 0x2c8a, 0xa284, - 0x00f0, 0xa086, 0x0020, 0x00c0, 0x2d1f, 0x8318, 0x8318, 0x2300, - 0xa102, 0x0040, 0x2ccf, 0x0048, 0x2ccf, 0x0078, 0x2d1c, 0xa286, - 0x0023, 0x0040, 0x2c78, 0x681c, 0xa084, 0xfff1, 0x681e, 0x7e58, - 0xa684, 0xfff1, 0xa085, 0x0010, 0x2030, 0x7e5a, 0x6008, 0xa085, - 0x0010, 0x600a, 0x0c7e, 0x7054, 0x2060, 0x6004, 0x2008, 0x2c48, - 0x0c7f, 0xa184, 0x0010, 0x0040, 0x2cf3, 0x1078, 0x38b9, 0x1078, - 0x36d0, 0x0078, 0x2d02, 0x0c7e, 0x7054, 0x2060, 0x6004, 0x2008, - 0x2c48, 0x0c7f, 0xa184, 0x0008, 0x0040, 0x2c69, 0x1078, 0x38b9, - 0x1078, 0x35bb, 0x88ff, 0x0040, 0x2c69, 0x789b, 0x0060, 0x2800, - 0x78aa, 0xa6b5, 0x0004, 0x7e5a, 0xa684, 0x0400, 0x00c0, 0x2d16, - 0x782b, 0x3008, 0x781b, 0x0056, 0x0078, 0x24fa, 0x782b, 0x3008, - 0x781b, 0x0065, 0x0078, 0x24fa, 0x7aa8, 0x0078, 0x2c8a, 0x8318, - 0x2300, 0xa102, 0x0040, 0x2d28, 0x0048, 0x2d28, 0x0078, 0x2c8a, - 0xa284, 0x0080, 0x00c0, 0x377b, 0x0078, 0x3773, 0x0078, 0x377b, - 0x0078, 0x376b, 0x789b, 0x0018, 0x78a8, 0xa084, 0x00ff, 0xa08e, - 0x0001, 0x0040, 0x2d3d, 0x1078, 0x248c, 0x7aa8, 0xa294, 0x00ff, - 0x78a8, 0xa084, 0x00ff, 0xa08a, 0x0004, 0x00c8, 0x376b, 0x0079, - 0x2d49, 0x376b, 0x3508, 0x376b, 0x3665, 0xa282, 0x0000, 0x00c0, - 0x2d53, 0x1078, 0x248c, 0x1078, 0x378f, 0x782b, 0x3008, 0x781b, - 0x0065, 0x0078, 0x24fa, 0xa282, 0x0003, 0x00c0, 0x2d61, 0x1078, - 0x248c, 0xa484, 0x8000, 0x00c0, 0x2d84, 0x706c, 0xa005, 0x0040, - 0x2d6b, 0x1078, 0x248c, 0x6f14, 0x7782, 0xa7bc, 0x0f00, 0x1078, - 0x38bd, 0x6008, 0xa085, 0x0021, 0x600a, 0x8738, 0xa784, 0x001f, - 0x00c0, 0x2d6f, 0x1078, 0x3793, 0x706f, 0x0002, 0x2009, 0x5238, - 0x200b, 0x0009, 0x0078, 0x2d86, 0x1078, 0x379f, 0x782b, 0x3008, - 0x781b, 0x0065, 0x0078, 0x24fa, 0xa282, 0x0004, 0x0050, 0x2d92, - 0x1078, 0x248c, 0x2300, 0x0079, 0x2d95, 0x2d98, 0x2e81, 0x2eb4, - 0xa286, 0x0003, 0x0040, 0x2d9e, 0x1078, 0x248c, 0x2001, 0x0000, - 0x007e, 0x68c0, 0xa005, 0x0040, 0x2da7, 0x7003, 0x0003, 0x68a0, - 0xa084, 0x2000, 0x0040, 0x2db0, 0x6008, 0xa085, 0x0002, 0x600a, - 0x007f, 0x703e, 0x7000, 0xa084, 0x0007, 0x0079, 0x2db7, 0x2523, - 0x2dc1, 0x2dc1, 0x2fb6, 0x2ff2, 0x2523, 0x2ff2, 0x2dbf, 0x1078, - 0x248c, 0xa684, 0x1000, 0x00c0, 0x2dc9, 0x1078, 0x4887, 0x0040, - 0x2e5b, 0x7868, 0xa08c, 0x00ff, 0x0040, 0x2e11, 0xa186, 0x0008, - 0x00c0, 0x2de0, 0x1078, 0x34b8, 0x6008, 0xa084, 0xffef, 0x600a, - 0x1078, 0x345a, 0x0040, 0x2e11, 0x1078, 0x4887, 0x0078, 0x2df8, - 0xa186, 0x0028, 0x00c0, 0x2e11, 0x1078, 0x4887, 0x6008, 0xa084, - 0xffef, 0x600a, 0x6018, 0xa005, 0x0040, 0x2df8, 0x8001, 0x601a, - 0xa005, 0x0040, 0x2df8, 0x8001, 0xa005, 0x0040, 0x2df8, 0x601e, - 0x6820, 0xa084, 0x0001, 0x0040, 0x2523, 0x6820, 0xa084, 0xfffe, - 0x6822, 0x7060, 0x0c7e, 0x2060, 0x6800, 0x6002, 0x0c7f, 0x6004, - 0x6802, 0xa005, 0x2d00, 0x00c0, 0x2e0e, 0x6002, 0x6006, 0x0078, - 0x2523, 0x017e, 0x1078, 0x2ee5, 0x017f, 0xa684, 0xdf00, 0x681e, - 0x682b, 0x0000, 0x6f14, 0x81ff, 0x0040, 0x2e5b, 0xa186, 0x0002, - 0x00c0, 0x2e5b, 0xa684, 0x0800, 0x00c0, 0x2e2e, 0xa684, 0x0060, - 0x0040, 0x2e2e, 0x78d8, 0x7adc, 0x682e, 0x6a32, 0x6820, 0xa084, - 0x0800, 0x00c0, 0x2e5b, 0x8717, 0xa294, 0x000f, 0x8213, 0x8213, - 0x8213, 0xa290, 0x5480, 0xa290, 0x0000, 0x221c, 0xa384, 0x0100, - 0x00c0, 0x2e44, 0x0078, 0x2e4a, 0x8210, 0x2204, 0xa085, 0x0018, - 0x2012, 0x8211, 0xa384, 0x0400, 0x0040, 0x2e57, 0x68a0, 0xa084, - 0x0100, 0x00c0, 0x2e57, 0x1078, 0x2f69, 0x0078, 0x2523, 0x6008, - 0xa085, 0x0002, 0x600a, 0x6916, 0x6818, 0xa084, 0x8000, 0x0040, - 0x2e63, 0x703c, 0x681a, 0xa68c, 0xdf00, 0x691e, 0x1078, 0x34a9, - 0x1078, 0x34b8, 0x00c0, 0x2e70, 0x6008, 0xa084, 0xffef, 0x600a, - 0x6820, 0xa084, 0x0001, 0x00c0, 0x2e79, 0x1078, 0x34a2, 0x0078, - 0x2e7d, 0x7060, 0x2060, 0x6800, 0x6002, 0x1078, 0x1cdc, 0x0078, - 0x2523, 0xa282, 0x0004, 0x0048, 0x2e87, 0x1078, 0x248c, 0x2200, - 0x0079, 0x2e8a, 0x2e85, 0x2e8e, 0x2e9b, 0x2e8e, 0x7000, 0xa086, - 0x0005, 0x0040, 0x2e97, 0x1078, 0x378f, 0x782b, 0x3008, 0x781b, - 0x0065, 0x0078, 0x24fa, 0x7890, 0x8007, 0x8001, 0xa084, 0x0007, - 0xa080, 0x0018, 0x789a, 0x79a8, 0xa18c, 0x00ff, 0xa186, 0x0003, - 0x0040, 0x2eb0, 0xa186, 0x0000, 0x0040, 0x2eb0, 0x0078, 0x376b, - 0x781b, 0x0065, 0x0078, 0x24fa, 0x6820, 0xa085, 0x0004, 0x6822, - 0x82ff, 0x00c0, 0x2ebf, 0x1078, 0x378f, 0x0078, 0x2ec6, 0x8211, - 0x0040, 0x2ec4, 0x1078, 0x248c, 0x1078, 0x379f, 0x782b, 0x3008, - 0x781b, 0x0065, 0x0078, 0x24fa, 0x702c, 0x8003, 0x0048, 0x2ed6, - 0x2019, 0x4eaf, 0x1078, 0x2313, 0x702f, 0x8000, 0x1078, 0x39e0, - 0x7830, 0xa084, 0x00c0, 0x00c0, 0x2ee2, 0x0018, 0x2ee2, 0x791a, - 0xa006, 0x007c, 0xa085, 0x0001, 0x007c, 0xa684, 0x0060, 0x00c0, - 0x2eef, 0x682f, 0x0000, 0x6833, 0x0000, 0x0078, 0x2f68, 0xa684, - 0x0800, 0x00c0, 0x2f11, 0x68b4, 0xa084, 0x4800, 0xa635, 0xa684, - 0x0800, 0x00c0, 0x2f11, 0x6998, 0x6a94, 0x692e, 0x6a32, 0x703c, - 0xa005, 0x00c0, 0x2f09, 0x2200, 0xa105, 0x0040, 0x2f10, 0x703f, - 0x0015, 0x7000, 0xa086, 0x0006, 0x0040, 0x2f10, 0x1078, 0x4887, - 0x007c, 0xa684, 0x0020, 0x0040, 0x2f33, 0xa684, 0x4000, 0x0040, - 0x2f1f, 0x682f, 0x0000, 0x6833, 0x0000, 0x0078, 0x2f09, 0x68b4, - 0xa084, 0x4800, 0xa635, 0xa684, 0x4000, 0x00c0, 0x2f19, 0x703c, - 0xa005, 0x00c0, 0x2f2d, 0x703f, 0x0015, 0x79d8, 0x7adc, 0x692e, - 0x6a32, 0x0078, 0x2f09, 0xa684, 0x4000, 0x0040, 0x2f3d, 0x682f, - 0x0000, 0x6833, 0x0000, 0x0078, 0x2f09, 0x68b4, 0xa084, 0x4800, - 0xa635, 0xa684, 0x4000, 0x00c0, 0x2f37, 0x703c, 0xa005, 0x00c0, - 0x2f4b, 0x703f, 0x0015, 0x79d8, 0x7adc, 0x78d0, 0x80fb, 0x00c8, - 0x2f52, 0x8000, 0xa084, 0x003f, 0xa108, 0xa291, 0x0000, 0x692e, - 0x6a32, 0x2100, 0xa205, 0x00c0, 0x2f5f, 0x0078, 0x2f09, 0x7000, - 0xa086, 0x0006, 0x0040, 0x2f68, 0x1078, 0x4c41, 0x0078, 0x2f09, - 0x007c, 0x6008, 0xa085, 0x0200, 0x600a, 0xa384, 0x0200, 0x0040, - 0x2f75, 0x6008, 0xa085, 0x0002, 0x600a, 0x681b, 0x0006, 0x688f, - 0x0000, 0x6893, 0x0000, 0x6a30, 0x692c, 0x6a3e, 0x6942, 0x682f, - 0x0003, 0x6833, 0x0000, 0x6837, 0x0020, 0x6897, 0x0000, 0x689b, - 0x0020, 0x68b3, 0x0000, 0x68af, 0x0000, 0x7000, 0x0079, 0x2f90, - 0x2523, 0x2f9a, 0x2fa3, 0x2f98, 0x2f98, 0x2f98, 0x2f98, 0x2f98, - 0x1078, 0x248c, 0x6820, 0xa084, 0x0001, 0x00c0, 0x2fa3, 0x1078, - 0x34a2, 0x0078, 0x2fa9, 0x7060, 0x2c50, 0x2060, 0x6800, 0x6002, - 0x2a60, 0x2021, 0x525a, 0x2404, 0xa005, 0x0040, 0x2fb2, 0x2020, - 0x0078, 0x2fab, 0x2d22, 0x206b, 0x0000, 0x007c, 0x1078, 0x34a9, - 0x1078, 0x34b8, 0x6008, 0xa084, 0xfdff, 0x600a, 0x682b, 0x0000, - 0x789b, 0x000e, 0x6f14, 0x6817, 0x0002, 0x1078, 0x4c89, 0xa684, - 0x0800, 0x0040, 0x2fcf, 0x691c, 0xa18d, 0x2000, 0x691e, 0x6818, - 0xa084, 0x8000, 0x0040, 0x2fdf, 0x7868, 0xa08c, 0x00ff, 0x0040, - 0x2fdd, 0x681b, 0x001e, 0x0078, 0x2fdf, 0x681b, 0x0000, 0x2021, - 0x525a, 0x2404, 0xad06, 0x0040, 0x2fe6, 0x7460, 0x6800, 0x2022, - 0x68c3, 0x0000, 0x6a3c, 0x6940, 0x6a32, 0x692e, 0x1078, 0x1cdc, - 0x0078, 0x2523, 0x1078, 0x2ee5, 0x682b, 0x0000, 0x2001, 0x000e, - 0x6f14, 0x1078, 0x39e6, 0xa08c, 0x00ff, 0x6916, 0x6818, 0xa084, - 0x8000, 0x0040, 0x3005, 0x703c, 0x681a, 0xa68c, 0xdf00, 0x691e, - 0x706f, 0x0000, 0x0078, 0x2523, 0x7000, 0xa005, 0x00c0, 0x3012, - 0x0078, 0x2523, 0xa006, 0x1078, 0x4887, 0x6817, 0x0000, 0x681b, - 0x0014, 0xa68c, 0xdf00, 0x691e, 0x682b, 0x0000, 0x6820, 0xa085, - 0x00ff, 0x6822, 0x7000, 0x0079, 0x3025, 0x2523, 0x302f, 0x302f, - 0x3031, 0x3031, 0x3031, 0x3031, 0x302d, 0x1078, 0x248c, 0x1078, - 0x34b8, 0x6008, 0xa084, 0xffef, 0x600a, 0x0078, 0x3472, 0x2300, - 0x0079, 0x303a, 0x303d, 0x303f, 0x3098, 0x1078, 0x248c, 0xa684, - 0x8000, 0x00c0, 0x307d, 0x7000, 0x0079, 0x3046, 0x2523, 0x3050, - 0x3050, 0x306c, 0x3050, 0x3079, 0x306c, 0x304e, 0x1078, 0x248c, - 0xa684, 0x0060, 0xa086, 0x0060, 0x00c0, 0x3068, 0xa6b4, 0xffdf, - 0xa6b4, 0xbfff, 0xa6b5, 0x2000, 0x7e5a, 0x6eb6, 0x681c, 0xa084, - 0xffdf, 0x681e, 0x1078, 0x4887, 0x1078, 0x4b4b, 0x0078, 0x3956, - 0xa684, 0x2000, 0x0040, 0x305a, 0x6818, 0xa084, 0x8000, 0x0040, - 0x3079, 0x681b, 0x0015, 0xa684, 0x4000, 0x0040, 0x3079, 0x681b, - 0x0007, 0x1078, 0x396a, 0x0078, 0x24fa, 0xa6b4, 0x7fff, 0x7e5a, - 0x7adc, 0x79d8, 0x78d0, 0x79d2, 0x801b, 0x00c8, 0x3088, 0x8000, - 0xa084, 0x003f, 0xa108, 0xa291, 0x0000, 0x6b98, 0x2100, 0xa302, - 0x68b2, 0x6b94, 0x2200, 0xa303, 0x68ae, 0x781b, 0x0065, 0x007c, - 0x1078, 0x248c, 0x2300, 0x0079, 0x309d, 0x30a0, 0x30a2, 0x30eb, - 0x1078, 0x248c, 0xa684, 0x8000, 0x00c0, 0x30da, 0x7000, 0x0079, - 0x30a9, 0x2523, 0x30b3, 0x30b3, 0x30cf, 0x30b3, 0x30d6, 0x30cf, - 0x30b1, 0x1078, 0x248c, 0xa684, 0x0060, 0xa086, 0x0060, 0x00c0, - 0x30cb, 0xa6b4, 0xffbf, 0xa6b4, 0xbfff, 0xa6b5, 0x2000, 0x7e5a, - 0x6eb6, 0x681c, 0xa084, 0xffbf, 0x681e, 0x1078, 0x4887, 0x1078, - 0x4b4b, 0x0078, 0x3956, 0xa684, 0x2000, 0x0040, 0x30bd, 0x6818, - 0xa084, 0x8000, 0x0040, 0x30d6, 0x681b, 0x0007, 0x781b, 0x00ca, - 0x0078, 0x24fa, 0xa6b4, 0x7fff, 0x7e5a, 0x7adc, 0x79d8, 0x6b98, - 0x2100, 0xa302, 0x68b2, 0x6b94, 0x2200, 0xa303, 0x68ae, 0x79d2, - 0x781b, 0x0065, 0x007c, 0x6820, 0xa085, 0x0004, 0x6822, 0x1078, - 0x3921, 0xa6b5, 0x0800, 0x1078, 0x378f, 0x782b, 0x3008, 0x781b, - 0x0065, 0x0078, 0x24fa, 0x2300, 0x0079, 0x30fe, 0x3101, 0x3103, - 0x3105, 0x1078, 0x248c, 0x0078, 0x377b, 0xa684, 0x0400, 0x00c0, - 0x312e, 0x79e4, 0xa184, 0x0020, 0x0040, 0x3115, 0x78ec, 0xa084, - 0x0003, 0x0040, 0x3115, 0x782b, 0x3009, 0x789b, 0x0060, 0x78ab, - 0x0000, 0xa684, 0xfffb, 0x785a, 0x79e4, 0xa184, 0x0020, 0x0040, - 0x3126, 0x78ec, 0xa084, 0x0003, 0x00c0, 0x312a, 0x2001, 0x0014, - 0x0078, 0x2da0, 0xa184, 0x0007, 0x0079, 0x3166, 0x7a90, 0xa294, - 0x0007, 0x789b, 0x0060, 0x79a8, 0x81ff, 0x0040, 0x3164, 0x789b, - 0x0010, 0x7ba8, 0xa384, 0x0001, 0x00c0, 0x3155, 0x7ba8, 0x7ba8, - 0xa386, 0x0001, 0x00c0, 0x3148, 0x2009, 0xfff7, 0x0078, 0x314e, - 0xa386, 0x0003, 0x00c0, 0x3155, 0x2009, 0xffef, 0x0c7e, 0x7054, - 0x2060, 0x6004, 0xa104, 0x6006, 0x0c7f, 0x789b, 0x0060, 0x78ab, - 0x0000, 0xa684, 0xfffb, 0x785a, 0x782b, 0x3009, 0x6920, 0xa18c, - 0xfdff, 0xa18c, 0xfeff, 0x6922, 0x0078, 0x3956, 0x2a3f, 0x2a4a, - 0x3170, 0x3178, 0x316e, 0x316e, 0x3956, 0x3956, 0x1078, 0x248c, - 0x6920, 0xa18c, 0xfdff, 0xa18c, 0xfeff, 0x6922, 0x0078, 0x3960, - 0x6920, 0xa18c, 0xfdff, 0xa18c, 0xfeff, 0x6922, 0x0078, 0x3956, - 0x79e4, 0xa184, 0x0030, 0x0040, 0x318a, 0x78ec, 0xa084, 0x0003, - 0x00c0, 0x31b1, 0x7000, 0xa086, 0x0004, 0x00c0, 0x31a4, 0x706c, - 0xa086, 0x0002, 0x00c0, 0x319a, 0x2011, 0x0002, 0x2019, 0x0000, - 0x0078, 0x28e9, 0x706c, 0xa086, 0x0006, 0x0040, 0x3194, 0x706c, - 0xa086, 0x0004, 0x0040, 0x3194, 0x7000, 0xa086, 0x0000, 0x0040, - 0x24fa, 0x6818, 0xa085, 0x8000, 0x681a, 0x2001, 0x0014, 0x0078, - 0x2da0, 0xa184, 0x0007, 0x0079, 0x31b5, 0x3956, 0x3956, 0x31bd, - 0x3956, 0x39bb, 0x39bb, 0x3956, 0x3956, 0xa684, 0x0080, 0x0040, - 0x31ec, 0x7194, 0x81ff, 0x0040, 0x31ec, 0xa182, 0x000d, 0x00d0, - 0x31cd, 0x7097, 0x0000, 0x0078, 0x31d2, 0xa182, 0x000c, 0x7096, - 0x2009, 0x000c, 0x789b, 0x0061, 0x79aa, 0x157e, 0x137e, 0x147e, - 0x7098, 0x8114, 0xa210, 0x729a, 0xa080, 0x000b, 0xad00, 0x2098, - 0x20a1, 0x012b, 0x789b, 0x0000, 0x8108, 0x81ac, 0x53a6, 0x147f, - 0x137f, 0x157f, 0x0078, 0x3960, 0xa684, 0x0400, 0x00c0, 0x322d, - 0x6820, 0xa084, 0x0001, 0x0040, 0x3960, 0xa68c, 0x0060, 0xa684, - 0x0060, 0x0040, 0x3201, 0xa086, 0x0060, 0x00c0, 0x3201, 0xa18d, - 0x4000, 0xa18c, 0xfffb, 0x795a, 0x69b6, 0x789b, 0x0060, 0x78ab, - 0x0000, 0x789b, 0x0061, 0x6818, 0xa085, 0x8000, 0x681a, 0x78aa, - 0x8008, 0x810c, 0x0040, 0x34d1, 0xa18c, 0x00f8, 0x00c0, 0x34d1, - 0x157e, 0x137e, 0x147e, 0x20a1, 0x012b, 0x789b, 0x0000, 0x8000, - 0x80ac, 0xad80, 0x000b, 0x2098, 0x53a6, 0x147f, 0x137f, 0x157f, - 0x6814, 0x8007, 0x7882, 0x0078, 0x3960, 0x6818, 0xa084, 0x8000, - 0x0040, 0x3234, 0x681b, 0x0008, 0x781b, 0x00c0, 0x0078, 0x24fa, - 0x2300, 0x0079, 0x323b, 0x3240, 0x32d4, 0x323e, 0x1078, 0x248c, - 0x7000, 0xa084, 0x0007, 0x0079, 0x3245, 0x2523, 0x324f, 0x3284, - 0x325a, 0x324d, 0x2523, 0x324d, 0x324d, 0x1078, 0x248c, 0x681c, - 0xa084, 0x2000, 0x0040, 0x3268, 0x6008, 0xa085, 0x0002, 0x600a, - 0x0078, 0x3268, 0x68c0, 0xa005, 0x00c0, 0x3284, 0x6920, 0xa18d, - 0x0001, 0x6922, 0x68c3, 0x0001, 0x6800, 0x706a, 0x0078, 0x327e, - 0x6920, 0xa18d, 0x0001, 0x6922, 0x6800, 0x6006, 0xa005, 0x00c0, - 0x3272, 0x6002, 0x681c, 0xa084, 0x000e, 0x0040, 0x327e, 0x7014, - 0x68ba, 0x7130, 0xa188, 0x7500, 0x0078, 0x3280, 0x2009, 0x7600, - 0x2104, 0x6802, 0x2d0a, 0x7162, 0x6eb6, 0xa684, 0x0060, 0x0040, - 0x32d2, 0xa684, 0x0800, 0x00c0, 0x3298, 0xa684, 0x7fff, 0x68b6, - 0x6894, 0x68a6, 0x6898, 0x68aa, 0x1078, 0x4887, 0x0078, 0x32d2, - 0xa684, 0x0020, 0x0040, 0x32ad, 0x68c0, 0xa005, 0x0040, 0x32a4, - 0x1078, 0x4c89, 0x0078, 0x32a7, 0xa006, 0x1078, 0x4c41, 0x79d8, - 0x7adc, 0x69aa, 0x6aa6, 0x0078, 0x32b3, 0x1078, 0x38ca, 0x69aa, - 0x6aa6, 0x1078, 0x4c41, 0xa684, 0x8000, 0x0040, 0x32d2, 0xa684, - 0x7fff, 0x68b6, 0x7adc, 0x79d8, 0xa684, 0x0020, 0x00c0, 0x32ca, - 0x78d0, 0x801b, 0x00c8, 0x32c5, 0x8000, 0xa084, 0x003f, 0xa108, - 0xa291, 0x0000, 0x6b98, 0x2100, 0xa302, 0x68b2, 0x6b94, 0x2200, - 0xa303, 0x68ae, 0x0078, 0x2523, 0x0078, 0x377b, 0x7037, 0x0000, - 0xa282, 0x0006, 0x0050, 0x32de, 0x1078, 0x248c, 0x7000, 0xa084, - 0x0007, 0x10c0, 0x3a8c, 0x2300, 0x0079, 0x32e6, 0x32e9, 0x3312, - 0x3326, 0x2200, 0x0079, 0x32ec, 0x3310, 0x377b, 0x32f2, 0x3310, - 0x3342, 0x3384, 0x7003, 0x0005, 0x2001, 0x7710, 0x2068, 0x704a, - 0x157e, 0x20a9, 0x0031, 0x2003, 0x0000, 0x8000, 0x0070, 0x3302, - 0x0078, 0x32fb, 0x157f, 0xad80, 0x0009, 0x7036, 0x6817, 0x0000, - 0x68b7, 0x0700, 0x6823, 0x0800, 0x6827, 0x0003, 0x0078, 0x376b, - 0x1078, 0x248c, 0x7003, 0x0005, 0x2001, 0x7710, 0x2068, 0x704a, - 0xad80, 0x0009, 0x7036, 0x2200, 0x0079, 0x331e, 0x377b, 0x3324, - 0x3324, 0x3342, 0x3324, 0x377b, 0x1078, 0x248c, 0x7003, 0x0005, - 0x2001, 0x7710, 0x2068, 0x704a, 0xad80, 0x0009, 0x7036, 0x2200, - 0x0079, 0x3332, 0x333a, 0x3338, 0x3338, 0x333a, 0x3338, 0x333a, - 0x1078, 0x248c, 0x1078, 0x379f, 0x782b, 0x3008, 0x781b, 0x0065, - 0x0078, 0x24fa, 0x7003, 0x0002, 0x7a80, 0xa294, 0x0f00, 0x789b, - 0x0018, 0x7ca8, 0xa484, 0x001f, 0xa215, 0x2069, 0x7600, 0x2d04, - 0x2d08, 0x7162, 0x2068, 0xa005, 0x0040, 0x335d, 0x6814, 0xa206, - 0x0040, 0x3379, 0x6800, 0x0078, 0x3350, 0x7003, 0x0005, 0x2001, - 0x7710, 0x2068, 0x704a, 0x7036, 0x157e, 0x20a9, 0x0031, 0x2003, - 0x0000, 0x8000, 0x0070, 0x336e, 0x0078, 0x3367, 0x157f, 0xad80, - 0x0009, 0x7036, 0x6a16, 0x68b7, 0x0700, 0x6823, 0x0800, 0x6827, - 0x0003, 0x6eb4, 0x7e5a, 0x6820, 0xa084, 0x0c00, 0x0040, 0x33d3, - 0x1078, 0x3797, 0x0078, 0x33d3, 0x7003, 0x0002, 0x7a80, 0xa294, - 0x0f00, 0x789b, 0x0018, 0x7ca8, 0xa484, 0x001f, 0xa215, 0x79a8, - 0x79a8, 0xa18c, 0x00ff, 0xa1e8, 0x7500, 0x2d04, 0x2d08, 0x7162, - 0x2068, 0xa005, 0x0040, 0x33a3, 0x6814, 0xa206, 0x0040, 0x33be, - 0x6800, 0x0078, 0x3396, 0x7003, 0x0005, 0x2001, 0x7710, 0x2068, - 0x704a, 0x157e, 0x20a9, 0x0031, 0x2003, 0x0000, 0x8000, 0x0070, - 0x33b3, 0x0078, 0x33ac, 0x157f, 0xad80, 0x0009, 0x7036, 0x6a16, - 0x68b7, 0x0700, 0x6823, 0x0800, 0x6827, 0x0003, 0x6eb4, 0x7e5a, - 0x6820, 0xa084, 0x0c00, 0x0040, 0x33d3, 0xa084, 0x0800, 0x0040, - 0x33cd, 0x1078, 0x379b, 0x0078, 0x33d3, 0x1078, 0x3797, 0x708b, - 0x0000, 0x0078, 0x33d3, 0x027e, 0x8207, 0xa084, 0x000f, 0x8003, - 0x8003, 0x8003, 0xa080, 0x5480, 0x2060, 0x7056, 0x6000, 0x705a, - 0x6004, 0x705e, 0xa684, 0x0060, 0x0040, 0x342b, 0x6b98, 0x6c94, - 0x69ac, 0x68b0, 0xa105, 0x00c0, 0x340d, 0x7bd2, 0x7bda, 0x7cd6, - 0x7cde, 0xa6b4, 0xb7ff, 0x7e5a, 0xa684, 0x0060, 0xa086, 0x0060, - 0x0040, 0x342b, 0x68c0, 0xa005, 0x0040, 0x3406, 0x7003, 0x0003, - 0x682b, 0x0000, 0x1078, 0x4b3a, 0x0078, 0x3408, 0x1078, 0x4b4b, - 0xa6b5, 0x2000, 0x7e5a, 0x0078, 0x342b, 0x68b0, 0xa31a, 0x2100, - 0xa423, 0x2400, 0xa305, 0x0040, 0x342b, 0x7bd2, 0x7bda, 0x7cd6, - 0x7cde, 0x68b0, 0xa6b4, 0xbfff, 0x7e5a, 0x007e, 0x68c0, 0xa005, - 0x007f, 0x0040, 0x3429, 0x7003, 0x0003, 0x1078, 0x4b3a, 0x0078, - 0x342b, 0x1078, 0x4b96, 0x077f, 0x1078, 0x38bd, 0x2009, 0x0065, - 0xa684, 0x0004, 0x0040, 0x344c, 0x78e4, 0xa084, 0x0030, 0x0040, - 0x3444, 0x78ec, 0xa084, 0x0003, 0x0040, 0x3444, 0x782b, 0x3008, - 0x2009, 0x0065, 0x0078, 0x344c, 0x0f7e, 0x2079, 0x5200, 0x1078, - 0x4887, 0x0f7f, 0x0040, 0x2523, 0x791a, 0x2d00, 0x704a, 0x8207, - 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa080, 0x5480, 0x2048, - 0x0078, 0x24fa, 0x6020, 0xa005, 0x0040, 0x3466, 0x8001, 0x6022, - 0x6008, 0xa085, 0x0008, 0x600a, 0x7010, 0x6026, 0x007c, 0xa006, - 0x1078, 0x4887, 0x6817, 0x0000, 0x681b, 0x0001, 0x6823, 0x0040, - 0x681f, 0x0100, 0x7000, 0xa084, 0x0007, 0x0079, 0x3477, 0x2523, - 0x3481, 0x3481, 0x349e, 0x3489, 0x3487, 0x3489, 0x347f, 0x1078, - 0x248c, 0x1078, 0x34a9, 0x1078, 0x34a2, 0x1078, 0x1cdc, 0x0078, - 0x2523, 0x706c, 0x706f, 0x0000, 0x7093, 0x0000, 0x0079, 0x3490, - 0x349a, 0x349a, 0x3498, 0x3498, 0x3498, 0x349a, 0x3498, 0x349a, - 0x0079, 0x2902, 0x706f, 0x0000, 0x0078, 0x2523, 0x681b, 0x0000, - 0x0078, 0x2fb6, 0x6800, 0xa005, 0x00c0, 0x34a7, 0x6002, 0x6006, - 0x007c, 0x6010, 0xa005, 0x0040, 0x34b2, 0x8001, 0x00d0, 0x34b2, - 0x1078, 0x248c, 0x6012, 0x6008, 0xa084, 0xffef, 0x600a, 0x007c, - 0x6018, 0xa005, 0x0040, 0x34be, 0x8001, 0x601a, 0x007c, 0x1078, - 0x39e0, 0x681b, 0x0018, 0x0078, 0x34f5, 0x1078, 0x39e0, 0x681b, - 0x0019, 0x0078, 0x34f5, 0x1078, 0x39e0, 0x681b, 0x001a, 0x0078, - 0x34f5, 0x1078, 0x39e0, 0x681b, 0x0003, 0x0078, 0x34f5, 0x7780, - 0x1078, 0x38bd, 0x7184, 0xa18c, 0x00ff, 0xa1e8, 0x7500, 0x2d04, - 0x2d08, 0x2068, 0xa005, 0x00c0, 0x34e7, 0x0078, 0x2523, 0x6814, - 0x7280, 0xa206, 0x0040, 0x34ef, 0x6800, 0x0078, 0x34e0, 0x6800, - 0x200a, 0x681b, 0x0005, 0x708b, 0x0000, 0x1078, 0x34a9, 0x6820, - 0xa084, 0x0001, 0x00c0, 0x34fe, 0x1078, 0x34a2, 0x1078, 0x34b8, - 0x681f, 0x0000, 0x6823, 0x0020, 0x1078, 0x1cdc, 0x0078, 0x2523, - 0xa282, 0x0003, 0x00c0, 0x376b, 0x7da8, 0xa5ac, 0x00ff, 0x7ca8, - 0xa4a4, 0x00ff, 0x6920, 0xa18d, 0x0080, 0x6922, 0xa184, 0x0100, - 0x0040, 0x356c, 0xa18c, 0xfeff, 0x6922, 0xa4a4, 0x00ff, 0x0040, - 0x3556, 0xa482, 0x000c, 0x0048, 0x3529, 0x0040, 0x3529, 0x2021, - 0x000c, 0x852b, 0x852b, 0x1078, 0x382e, 0x0040, 0x3533, 0x1078, - 0x3627, 0x0078, 0x355f, 0x1078, 0x37e9, 0x0c7e, 0x2960, 0x6004, - 0xa084, 0xfff5, 0x6006, 0x1078, 0x3652, 0x0c7f, 0x6920, 0xa18d, - 0x0100, 0x6922, 0x7e58, 0xa6b5, 0x0004, 0x7e5a, 0xa684, 0x0400, - 0x00c0, 0x3550, 0x782b, 0x3008, 0x781b, 0x0056, 0x0078, 0x24fa, - 0x782b, 0x3008, 0x781b, 0x0065, 0x0078, 0x24fa, 0x0c7e, 0x2960, - 0x6004, 0xa084, 0xfff5, 0x6006, 0x1078, 0x3652, 0x0c7f, 0x7e58, - 0xa684, 0x0400, 0x00c0, 0x3568, 0x781b, 0x0058, 0x0078, 0x24fa, - 0x781b, 0x0065, 0x0078, 0x24fa, 0x0c7e, 0x7054, 0x2060, 0x6100, - 0xa18c, 0x1000, 0x0040, 0x35ac, 0x6208, 0x8217, 0xa294, 0x00ff, - 0xa282, 0x000c, 0x0048, 0x3580, 0x0040, 0x3580, 0x2011, 0x000c, - 0x2400, 0xa202, 0x00c8, 0x3585, 0x2220, 0x6208, 0xa294, 0x00ff, - 0x7018, 0xa086, 0x0028, 0x00c0, 0x3595, 0xa282, 0x0019, 0x00c8, - 0x359b, 0x2011, 0x0019, 0x0078, 0x359b, 0xa282, 0x000c, 0x00c8, - 0x359b, 0x2011, 0x000c, 0x2200, 0xa502, 0x00c8, 0x35a0, 0x2228, - 0x1078, 0x37ed, 0x852b, 0x852b, 0x1078, 0x382e, 0x0040, 0x35ac, - 0x1078, 0x3627, 0x0078, 0x35b0, 0x1078, 0x37e9, 0x1078, 0x3652, - 0x7858, 0xa085, 0x0004, 0x785a, 0x0c7f, 0x782b, 0x3008, 0x781b, - 0x0065, 0x0078, 0x24fa, 0x0c7e, 0x2960, 0x6000, 0xd0e4, 0x00c0, - 0x35d5, 0xd0b4, 0x00c0, 0x35cf, 0x6010, 0xa084, 0x000f, 0x00c0, - 0x35cf, 0x6104, 0xa18c, 0xfff5, 0x6106, 0x0c7f, 0x007c, 0x2011, - 0x0032, 0x2019, 0x0000, 0x0078, 0x35fc, 0x68a0, 0xa084, 0x0200, - 0x00c0, 0x35cf, 0x6208, 0xa294, 0x00ff, 0x7018, 0xa086, 0x0028, - 0x00c0, 0x35ea, 0xa282, 0x0019, 0x00c8, 0x35f0, 0x2011, 0x0019, - 0x0078, 0x35f0, 0xa282, 0x000c, 0x00c8, 0x35f0, 0x2011, 0x000c, - 0x6308, 0x831f, 0xa39c, 0x00ff, 0xa382, 0x000c, 0x0048, 0x35fc, - 0x0040, 0x35fc, 0x2019, 0x000c, 0x78ab, 0x0001, 0x78ab, 0x0003, - 0x78ab, 0x0001, 0x7aaa, 0x7baa, 0xa8c0, 0x0005, 0x6820, 0xa085, - 0x0100, 0x6822, 0x0c7f, 0x007c, 0x0c7e, 0x2960, 0xa18c, 0xfff5, - 0x6106, 0x2011, 0x0032, 0x2019, 0x0000, 0x0078, 0x3617, 0x78ab, - 0x0001, 0x78ab, 0x0003, 0x78ab, 0x0001, 0x7aaa, 0x7baa, 0xa8c0, - 0x0005, 0x6820, 0xa085, 0x0100, 0x6822, 0x0c7f, 0x007c, 0x0c7e, - 0x7154, 0x2160, 0x1078, 0x362e, 0x0c7f, 0x007c, 0x2008, 0xa084, - 0xfff0, 0xa425, 0x7c86, 0x6018, 0x789a, 0x7cae, 0x6412, 0x78a4, - 0xa084, 0xfff8, 0xa18c, 0x0007, 0xa105, 0x78a6, 0x6016, 0x788a, - 0xa4a4, 0x000f, 0x8427, 0x8204, 0x8004, 0xa084, 0x00ff, 0xa405, - 0x600e, 0x78ec, 0xd08c, 0x00c0, 0x3651, 0x6004, 0xa084, 0xfff5, - 0x6006, 0x007c, 0x0c7e, 0x7054, 0x2060, 0x1078, 0x3659, 0x0c7f, - 0x007c, 0x6018, 0x789a, 0x78a4, 0xa084, 0xfff0, 0x78a6, 0x6012, - 0x7884, 0xa084, 0xfff0, 0x7886, 0x007c, 0xa282, 0x0002, 0x00c0, - 0x376b, 0x7aa8, 0x6920, 0xa18d, 0x0080, 0x6922, 0xa184, 0x0200, - 0x0040, 0x36ae, 0xa18c, 0xfdff, 0x6922, 0xa294, 0x00ff, 0xa282, - 0x0002, 0x00c8, 0x376b, 0x1078, 0x36f9, 0x1078, 0x3652, 0xa980, - 0x0001, 0x200c, 0x1078, 0x38b9, 0x1078, 0x35bb, 0x88ff, 0x0040, - 0x36a1, 0x789b, 0x0060, 0x2800, 0x78aa, 0x7e58, 0xa6b5, 0x0004, - 0x7e5a, 0xa684, 0x0400, 0x00c0, 0x369b, 0x782b, 0x3008, 0x781b, - 0x0056, 0x0078, 0x24fa, 0x782b, 0x3008, 0x781b, 0x0065, 0x0078, - 0x24fa, 0x7e58, 0xa684, 0x0400, 0x00c0, 0x36aa, 0x781b, 0x0058, - 0x0078, 0x24fa, 0x781b, 0x0065, 0x0078, 0x24fa, 0xa282, 0x0002, - 0x00c8, 0x36b6, 0xa284, 0x0001, 0x0040, 0x36c0, 0x7154, 0xa188, - 0x0000, 0x210c, 0xa18c, 0x2000, 0x00c0, 0x36c0, 0x2011, 0x0000, - 0x1078, 0x37db, 0x1078, 0x36f9, 0x1078, 0x3652, 0x7858, 0xa085, - 0x0004, 0x785a, 0x782b, 0x3008, 0x781b, 0x0065, 0x0078, 0x24fa, - 0x0c7e, 0x027e, 0x2960, 0x6000, 0x2011, 0x0001, 0xd0ec, 0x00c0, - 0x36e9, 0xd0bc, 0x00c0, 0x36e7, 0x6014, 0xa084, 0x0040, 0x00c0, - 0x36e7, 0xa18c, 0xffef, 0x6106, 0xa006, 0x0078, 0x36f6, 0x2011, - 0x0000, 0x78ab, 0x0001, 0x78ab, 0x0002, 0x78ab, 0x0003, 0x7aaa, - 0xa8c0, 0x0004, 0x6820, 0xa085, 0x0200, 0x6822, 0x027f, 0x0c7f, - 0x007c, 0x0c7e, 0x7054, 0x2060, 0x1078, 0x3700, 0x0c7f, 0x007c, - 0x82ff, 0x0040, 0x3705, 0x2011, 0x0040, 0x6018, 0xa080, 0x0002, - 0x789a, 0x78a4, 0xa084, 0xffbf, 0xa205, 0x78a6, 0x788a, 0x6016, - 0x78ec, 0xd08c, 0x00c0, 0x3718, 0x6004, 0xa084, 0xffef, 0x6006, - 0x007c, 0x007e, 0x7000, 0xa086, 0x0003, 0x0040, 0x3722, 0x007f, - 0x0078, 0x3725, 0x007f, 0x0078, 0x3767, 0xa684, 0x0020, 0x0040, - 0x3767, 0x7888, 0xa084, 0x0040, 0x0040, 0x3767, 0x7bb8, 0xa384, - 0x003f, 0x831b, 0x00c8, 0x3735, 0x8000, 0xa005, 0x0040, 0x374b, - 0x831b, 0x00c8, 0x373e, 0x8001, 0x0040, 0x3763, 0xa684, 0x4000, - 0x0040, 0x374b, 0x78b8, 0x801b, 0x00c8, 0x3747, 0x8000, 0xa084, - 0x003f, 0x00c0, 0x3763, 0xa6b4, 0xbfff, 0x7e5a, 0x79d8, 0x7adc, - 0x2001, 0x0001, 0xa108, 0x00c8, 0x3757, 0xa291, 0x0000, 0x79d2, - 0x79da, 0x7ad6, 0x7ade, 0x1078, 0x4c41, 0x781b, 0x0064, 0x1078, - 0x4ac6, 0x0078, 0x24fa, 0x781b, 0x0064, 0x0078, 0x24fa, 0x781b, - 0x0065, 0x0078, 0x24fa, 0x1078, 0x37a3, 0x782b, 0x3008, 0x781b, - 0x0065, 0x0078, 0x24fa, 0x1078, 0x378f, 0x782b, 0x3008, 0x781b, - 0x0065, 0x0078, 0x24fa, 0x6827, 0x0002, 0x1078, 0x3797, 0x78e4, - 0xa084, 0x0030, 0x0040, 0x2523, 0x78ec, 0xa084, 0x0003, 0x0040, - 0x2523, 0x782b, 0x3008, 0x781b, 0x0065, 0x0078, 0x24fa, 0x2001, - 0x0005, 0x0078, 0x37a5, 0x2001, 0x000c, 0x0078, 0x37a5, 0x2001, - 0x0006, 0x0078, 0x37a5, 0x2001, 0x000d, 0x0078, 0x37a5, 0x2001, - 0x0009, 0x0078, 0x37a5, 0x2001, 0x0007, 0x789b, 0x0010, 0x78aa, - 0x789b, 0x0060, 0x78ab, 0x0001, 0xa6b5, 0x0004, 0x7e5a, 0x007c, - 0x077e, 0x873f, 0xa7bc, 0x000f, 0x873b, 0x873b, 0x8703, 0xa0e0, - 0x5480, 0xa7b8, 0x0020, 0x7f9a, 0x79a4, 0xa184, 0x000f, 0x0040, - 0x37c9, 0xa184, 0xfff0, 0x78a6, 0x6012, 0x6004, 0xa085, 0x0008, - 0x6006, 0x8738, 0x8738, 0x7f9a, 0x79a4, 0xa184, 0x0040, 0x0040, - 0x37d9, 0xa184, 0xffbf, 0x78a6, 0x6016, 0x6004, 0xa085, 0x0010, - 0x6006, 0x077f, 0x007c, 0x789b, 0x0010, 0x78ab, 0x0001, 0x78ab, - 0x0002, 0x78ab, 0x0003, 0x7aaa, 0x789b, 0x0060, 0x78ab, 0x0004, - 0x007c, 0x2021, 0x0000, 0x2029, 0x0032, 0x789b, 0x0010, 0x78ab, - 0x0001, 0x78ab, 0x0003, 0x78ab, 0x0001, 0x7daa, 0x7caa, 0x789b, - 0x0060, 0x78ab, 0x0005, 0x007c, 0x157e, 0x8007, 0xa084, 0x00ff, - 0x8003, 0x8003, 0xa080, 0x0020, 0x789a, 0x79a4, 0xa18c, 0xfff0, - 0x2001, 0x5246, 0x2004, 0xa082, 0x0028, 0x0040, 0x3817, 0x2021, - 0x38a0, 0x2019, 0x0014, 0x20a9, 0x000c, 0x0078, 0x381d, 0x2021, - 0x38ac, 0x2019, 0x0019, 0x20a9, 0x000d, 0x2011, 0x0064, 0x2404, - 0xa084, 0xfff0, 0xa106, 0x0040, 0x382c, 0x8420, 0x2300, 0xa210, - 0x0070, 0x382c, 0x0078, 0x381f, 0x157f, 0x007c, 0x157e, 0x2009, - 0x5246, 0x210c, 0xa182, 0x0032, 0x0048, 0x3842, 0x0040, 0x3846, - 0x2009, 0x3892, 0x2019, 0x0011, 0x20a9, 0x000e, 0x2011, 0x0032, - 0x0078, 0x3858, 0xa182, 0x0028, 0x0040, 0x3850, 0x2009, 0x38a0, - 0x2019, 0x0014, 0x20a9, 0x000c, 0x2011, 0x0064, 0x0078, 0x3858, - 0x2009, 0x38ac, 0x2019, 0x0019, 0x20a9, 0x000d, 0x2011, 0x0064, - 0x2200, 0xa502, 0x0040, 0x3868, 0x0048, 0x3868, 0x8108, 0x2300, - 0xa210, 0x0070, 0x3865, 0x0078, 0x3858, 0x157f, 0xa006, 0x007c, - 0x157f, 0xa582, 0x0064, 0x00c8, 0x3877, 0x7808, 0xa085, 0x0070, - 0x780a, 0x7044, 0xa085, 0x0070, 0x7046, 0x0078, 0x3877, 0x78ec, - 0xa084, 0x0300, 0x0040, 0x387f, 0x2104, 0x0078, 0x3890, 0x2104, - 0xa09e, 0x1102, 0x00c0, 0x3890, 0x2001, 0x04fd, 0x2004, 0xa082, - 0x0005, 0x0048, 0x388f, 0x2001, 0x1201, 0x0078, 0x3890, 0x2104, - 0xa005, 0x007c, 0x1102, 0x3002, 0x3202, 0x4203, 0x4403, 0x5404, - 0x5604, 0x6605, 0x6805, 0x7806, 0x7a06, 0x0c07, 0x0c07, 0x0e07, - 0x3202, 0x4202, 0x5202, 0x6202, 0x7202, 0x6605, 0x7605, 0x7805, - 0x7a05, 0x7c05, 0x7e05, 0x7f05, 0x2202, 0x3202, 0x4202, 0x5202, - 0x5404, 0x6404, 0x7404, 0x7604, 0x7804, 0x7a04, 0x7c04, 0x7e04, - 0x7f04, 0x789b, 0x0010, 0xa046, 0x007c, 0xa784, 0x0f00, 0x800b, - 0xa784, 0x001f, 0x8003, 0x8003, 0x8003, 0x8003, 0xa105, 0xa0e0, - 0x5500, 0x007c, 0x79d8, 0x7adc, 0x78d0, 0x801b, 0x00c8, 0x38d1, - 0x8000, 0xa084, 0x003f, 0xa108, 0xa291, 0x0000, 0x007c, 0x0f7e, - 0x2079, 0x0100, 0x2009, 0x5240, 0x2091, 0x8000, 0x2104, 0x0079, - 0x38e1, 0x3917, 0x38eb, 0x38eb, 0x38eb, 0x38eb, 0x38eb, 0x38eb, - 0x391b, 0x1078, 0x248c, 0x784b, 0x0004, 0x7848, 0xa084, 0x0004, - 0x00c0, 0x38ed, 0x784b, 0x0008, 0x7848, 0xa084, 0x0008, 0x00c0, - 0x38f4, 0x68b4, 0xa085, 0x4000, 0x68b6, 0x7858, 0xa085, 0x4000, - 0x785a, 0x7830, 0xa084, 0x0080, 0x00c0, 0x3917, 0x0018, 0x3917, - 0x681c, 0xa084, 0x0020, 0x00c0, 0x3915, 0x0e7e, 0x2071, 0x5240, - 0x1078, 0x396a, 0x0e7f, 0x0078, 0x3917, 0x781b, 0x00ca, 0x2091, - 0x8001, 0x0f7f, 0x007c, 0x70b3, 0x0000, 0x1078, 0x3b44, 0x0078, - 0x3917, 0x0c7e, 0x6814, 0x8007, 0xa084, 0x000f, 0x8003, 0x8003, - 0x8003, 0xa0e0, 0x5480, 0x6004, 0xa084, 0x000a, 0x00c0, 0x3954, - 0x6108, 0xa194, 0xff00, 0x0040, 0x3954, 0xa18c, 0x00ff, 0x2001, - 0x0019, 0xa106, 0x0040, 0x3943, 0x2001, 0x0032, 0xa106, 0x0040, - 0x3947, 0x0078, 0x394b, 0x2009, 0x0020, 0x0078, 0x394d, 0x2009, - 0x003f, 0x0078, 0x394d, 0x2011, 0x0000, 0x2100, 0xa205, 0x600a, - 0x6004, 0xa085, 0x0002, 0x6006, 0x0c7f, 0x007c, 0x781b, 0x0065, - 0x0078, 0x24fa, 0x782b, 0x3008, 0x781b, 0x0065, 0x0078, 0x24fa, - 0x781b, 0x0058, 0x0078, 0x24fa, 0x782b, 0x3008, 0x781b, 0x0056, - 0x0078, 0x24fa, 0x2009, 0x5220, 0x210c, 0xa186, 0x0000, 0x0040, - 0x397e, 0xa186, 0x0001, 0x0040, 0x3981, 0x2009, 0x5238, 0x200b, - 0x000b, 0x706f, 0x0001, 0x781b, 0x0048, 0x007c, 0x781b, 0x00c4, - 0x007c, 0x2009, 0x5238, 0x200b, 0x000a, 0x007c, 0x2009, 0x5220, - 0x210c, 0xa186, 0x0000, 0x0040, 0x39a1, 0xa186, 0x0001, 0x0040, - 0x399b, 0x2009, 0x5238, 0x200b, 0x000b, 0x706f, 0x0001, 0x781b, - 0x0048, 0x0078, 0x24fa, 0x2009, 0x5238, 0x200b, 0x000a, 0x0078, - 0x24fa, 0x782b, 0x3008, 0x781b, 0x00c4, 0x0078, 0x24fa, 0x781b, - 0x00ca, 0x0078, 0x24fa, 0x782b, 0x3008, 0x781b, 0x00ca, 0x0078, - 0x24fa, 0x781b, 0x008f, 0x0078, 0x24fa, 0x782b, 0x3008, 0x781b, - 0x008f, 0x0078, 0x24fa, 0x6818, 0xa084, 0x8000, 0x0040, 0x39c2, - 0x681b, 0x001d, 0x706f, 0x0001, 0x781b, 0x0048, 0x0078, 0x24fa, - 0x007e, 0x7830, 0xa084, 0x00c0, 0x00c0, 0x39de, 0x7808, 0xa084, - 0xfffc, 0x780a, 0x0005, 0x0005, 0x0005, 0x0005, 0x78ec, 0xa084, - 0x0021, 0x0040, 0x39de, 0x7044, 0x780a, 0xa005, 0x007f, 0x007c, - 0x7044, 0xa085, 0x0002, 0x7046, 0x780a, 0x007c, 0x007e, 0x7830, - 0xa084, 0x0040, 0x00c0, 0x39e7, 0x0098, 0x39f2, 0x007f, 0x789a, - 0x78ac, 0x007c, 0x7808, 0xa084, 0xfffd, 0x780a, 0x0005, 0x0005, - 0x0005, 0x0005, 0x78ec, 0xa084, 0x0021, 0x0040, 0x3a01, 0x0098, - 0x39ff, 0x007f, 0x789a, 0x78ac, 0x007e, 0x7044, 0x780a, 0x007f, - 0x007c, 0x78ec, 0xa084, 0x0002, 0x00c0, 0x4871, 0xa784, 0x007d, - 0x00c0, 0x3a15, 0x2700, 0x1078, 0x248c, 0xa784, 0x0001, 0x00c0, - 0x300c, 0xa784, 0x0070, 0x0040, 0x3a25, 0x0c7e, 0x2d60, 0x2f68, - 0x1078, 0x2437, 0x2d78, 0x2c68, 0x0c7f, 0xa784, 0x0008, 0x0040, - 0x3a32, 0x784b, 0x0008, 0x78ec, 0xa084, 0x0003, 0x0040, 0x2523, - 0x0078, 0x3956, 0xa784, 0x0004, 0x0040, 0x3a65, 0x78b8, 0xa084, - 0x4001, 0x0040, 0x3a65, 0x784b, 0x0008, 0x78ec, 0xa084, 0x0003, - 0x0040, 0x2523, 0x78e4, 0xa084, 0x0007, 0xa086, 0x0001, 0x00c0, - 0x3a65, 0x78c0, 0xa085, 0x4800, 0x2030, 0x7e5a, 0x781b, 0x00ca, - 0x0078, 0x24fa, 0x784b, 0x0008, 0x6818, 0xa084, 0x8000, 0x0040, - 0x3a61, 0x681b, 0x0015, 0xa684, 0x4000, 0x0040, 0x3a61, 0x681b, - 0x0007, 0x1078, 0x396a, 0x0078, 0x24fa, 0x681b, 0x0003, 0x7858, - 0xa084, 0x3f00, 0x681e, 0x682f, 0x0000, 0x6833, 0x0000, 0x784b, - 0x0008, 0x78ec, 0xa084, 0x0003, 0x0040, 0x2a06, 0x0018, 0x24fa, - 0x0078, 0x3773, 0x6b14, 0x8307, 0xa084, 0x000f, 0x8003, 0x8003, - 0x8003, 0xa080, 0x5480, 0x2060, 0x2048, 0x7056, 0x6000, 0x705a, - 0x6004, 0x705e, 0x2a60, 0x007c, 0x0079, 0x3a8e, 0x3a96, 0x3a97, - 0x3a96, 0x3a99, 0x3a96, 0x3a96, 0x3a96, 0x3a9e, 0x007c, 0x1078, - 0x34b8, 0x1078, 0x4887, 0x7038, 0x600a, 0x007c, 0x70a0, 0xa005, - 0x0040, 0x3aab, 0x2068, 0x1078, 0x1bd3, 0x1078, 0x47fe, 0x1078, - 0x4805, 0x70a3, 0x0000, 0x007c, 0x0e7e, 0x2091, 0x8000, 0x2071, - 0x5240, 0x7000, 0xa086, 0x0007, 0x00c0, 0x3ac2, 0x6110, 0x70bc, - 0xa106, 0x00c0, 0x3ac2, 0x0e7f, 0x1078, 0x1be0, 0x1078, 0x3ac8, - 0xa006, 0x007c, 0x2091, 0x8001, 0x0e7f, 0xa085, 0x0001, 0x007c, - 0x0f7e, 0x0e7e, 0x2071, 0x5240, 0x0078, 0x2297, 0x785b, 0x0000, - 0x70af, 0x000e, 0x2009, 0x0100, 0x017e, 0x70a0, 0xa06d, 0x0040, - 0x3add, 0x70a3, 0x0000, 0x0078, 0x3ae3, 0x70b3, 0x0000, 0x1078, - 0x1c0c, 0x0040, 0x3ae9, 0x70ac, 0x6826, 0x1078, 0x3bc6, 0x0078, - 0x3add, 0x017f, 0x157e, 0x0c7e, 0x0d7e, 0x20a9, 0x0008, 0x2061, - 0x7610, 0x6000, 0xa105, 0x6002, 0x601c, 0xa06d, 0x0040, 0x3b01, - 0x6800, 0x601e, 0x1078, 0x19ac, 0x6008, 0x8000, 0x600a, 0x0078, - 0x3af4, 0x6018, 0xa06d, 0x0040, 0x3b0b, 0x6800, 0x601a, 0x1078, - 0x19ac, 0x0078, 0x3b01, 0xace0, 0x0008, 0x0070, 0x3b11, 0x0078, - 0x3af1, 0x709c, 0xa084, 0x8000, 0x0040, 0x3b18, 0x1078, 0x3c44, - 0x0d7f, 0x0c7f, 0x157f, 0x007c, 0x127e, 0x2091, 0x2300, 0x6804, - 0xa084, 0x000f, 0x0079, 0x3b24, 0x3b34, 0x3b34, 0x3b34, 0x3b34, - 0x3b34, 0x3b34, 0x3b36, 0x3b3c, 0x3b34, 0x3b34, 0x3b34, 0x3b34, - 0x3b34, 0x3b3e, 0x3b34, 0x3b36, 0x1078, 0x248c, 0x1078, 0x45d3, - 0x1078, 0x19ac, 0x0078, 0x3b42, 0x6827, 0x000b, 0x1078, 0x45d3, - 0x1078, 0x3bc6, 0x127f, 0x007c, 0x127e, 0x2091, 0x2300, 0x0098, - 0x3b60, 0x7830, 0xa084, 0x00c0, 0x00c0, 0x3b60, 0x0d7e, 0x1078, - 0x4812, 0x2d00, 0x682e, 0x2009, 0x0004, 0x2001, 0x0000, 0x6827, - 0x0084, 0x1078, 0x47c7, 0x1078, 0x3bc6, 0x0d7f, 0x0078, 0x3b94, - 0x7948, 0xa185, 0x4000, 0x784a, 0x0098, 0x3b69, 0x794a, 0x0078, - 0x3b4e, 0x7828, 0xa086, 0x1834, 0x00c0, 0x3b72, 0xa185, 0x0004, - 0x0078, 0x3b79, 0x7828, 0xa086, 0x1814, 0x00c0, 0x3b66, 0xa185, - 0x000c, 0x784a, 0x789b, 0x000e, 0x78ab, 0x0002, 0x7858, 0xa084, - 0x00ff, 0xa085, 0x0400, 0x785a, 0x70b4, 0xa080, 0x0091, 0x781a, - 0x6827, 0x0284, 0x682c, 0x6836, 0x6830, 0x683a, 0x2009, 0x0004, - 0x2001, 0x0000, 0x1078, 0x47c7, 0x127f, 0x007c, 0x0d7e, 0x6b14, - 0x1078, 0x1c70, 0x0040, 0x3ba3, 0x2068, 0x6827, 0x0002, 0x1078, - 0x3bc6, 0x0078, 0x3b98, 0x0d7f, 0x007c, 0x0d7e, 0x6b14, 0x6c28, - 0xa4a4, 0x00ff, 0x1078, 0x1c1c, 0x0040, 0x3bb3, 0x2068, 0x6827, - 0x0002, 0x1078, 0x3bc6, 0x0d7f, 0x007c, 0x0d7e, 0x6b14, 0xa39c, - 0x00ff, 0x1078, 0x1c48, 0x0040, 0x3bc4, 0x2068, 0x6827, 0x0002, - 0x1078, 0x3bc6, 0x0078, 0x3bb9, 0x0d7f, 0x007c, 0x0c7e, 0x6914, - 0x1078, 0x3c3b, 0x6904, 0xa18c, 0x00ff, 0xa186, 0x0006, 0x0040, - 0x3be1, 0xa186, 0x000d, 0x0040, 0x3c00, 0xa186, 0x0017, 0x00c0, - 0x3bdd, 0x1078, 0x19ac, 0x0078, 0x3bdf, 0x1078, 0x1cde, 0x0c7f, - 0x007c, 0x6004, 0x8001, 0x0048, 0x3bfe, 0x6006, 0x2009, 0x0000, - 0xa684, 0x0001, 0x00c0, 0x3bee, 0xa18d, 0x8000, 0xa684, 0x0004, - 0x0040, 0x3bf4, 0xa18d, 0x0002, 0x691e, 0x6823, 0x0000, 0x7104, - 0x810f, 0x6818, 0xa105, 0x681a, 0x0078, 0x3bdd, 0x1078, 0x248c, - 0x6018, 0xa005, 0x00c0, 0x3c0f, 0x6008, 0x8001, 0x0048, 0x3c0f, - 0x600a, 0x601c, 0x6802, 0x2d00, 0x601e, 0x0078, 0x3c25, 0xac88, - 0x0006, 0x2104, 0xa005, 0x0040, 0x3c18, 0x2008, 0x0078, 0x3c11, - 0x6802, 0x2d0a, 0x6008, 0x8001, 0x0048, 0x3bdf, 0x600a, 0x6018, - 0x2068, 0x6800, 0x601a, 0x0078, 0x3c09, 0x157e, 0x137e, 0x147e, - 0x0c7e, 0x0d7e, 0x1078, 0x1989, 0x00c0, 0x3c30, 0x1078, 0x248c, - 0x2da0, 0x137f, 0x20a9, 0x0031, 0x53a3, 0x0c7f, 0x147f, 0x137f, - 0x157f, 0x0078, 0x3bdd, 0xa184, 0x001f, 0x8003, 0x8003, 0x8003, - 0xa080, 0x7610, 0x2060, 0x007c, 0x2019, 0x5251, 0x2304, 0xa085, - 0x0001, 0x201a, 0x2019, 0x0102, 0x2304, 0xa085, 0x0001, 0x201a, - 0x007c, 0x2019, 0x5251, 0x2304, 0xa084, 0xfffe, 0x201a, 0x2019, - 0x0102, 0x2304, 0xa084, 0xfffe, 0x201a, 0x007c, 0x7990, 0xa18c, - 0xfff8, 0x7992, 0x70b4, 0xa080, 0x00d8, 0x781a, 0x0078, 0x24fa, - 0x70a3, 0x0000, 0x7003, 0x0000, 0x7043, 0x0001, 0x7037, 0x0000, - 0x0018, 0x24b1, 0x1078, 0x1c0c, 0x0040, 0x3c99, 0x2009, 0x520f, - 0x200b, 0x0000, 0x68bc, 0x2060, 0x6100, 0xa184, 0x0300, 0x0040, - 0x3c8d, 0x6827, 0x000e, 0xa084, 0x0200, 0x0040, 0x3c89, 0x6827, - 0x0017, 0x1078, 0x3bc6, 0x0078, 0x3c68, 0x7000, 0xa086, 0x0007, - 0x00c0, 0x3d0d, 0x2d00, 0x70a2, 0xad80, 0x000f, 0x7036, 0x0078, - 0x3ca0, 0x7040, 0xa086, 0x0001, 0x0040, 0x2533, 0x0078, 0x24fa, - 0x2031, 0x0000, 0x691c, 0xa184, 0x0002, 0x0040, 0x3ca9, 0xa6b5, - 0x0004, 0xa184, 0x00c0, 0x8003, 0x8003, 0x8007, 0xa080, 0x3da6, - 0x2004, 0xa635, 0x6820, 0xa084, 0x0400, 0x0040, 0x3cc1, 0x789b, - 0x0018, 0x78ab, 0x0003, 0x789b, 0x0081, 0x78ab, 0x0001, 0xa6b5, - 0x5000, 0x6820, 0xa084, 0x8000, 0x0040, 0x3ccf, 0xa6b5, 0x0400, - 0x789b, 0x000e, 0x6824, 0x8007, 0x78aa, 0x0078, 0x3cef, 0x681c, - 0xd0fc, 0x00c0, 0x3cdd, 0xa6b5, 0x0800, 0x6820, 0xd0c4, 0x0040, - 0x3cef, 0xa6b5, 0x4000, 0x0078, 0x3cef, 0x6820, 0xd0c4, 0x0040, - 0x3ce5, 0xa6b5, 0x4000, 0x0078, 0x3cef, 0x789b, 0x0018, 0x78ab, - 0x0002, 0x789b, 0x0081, 0x78ab, 0x0001, 0xa6b5, 0x1000, 0xa684, - 0x0200, 0x0040, 0x3d09, 0x682c, 0x78d2, 0x6830, 0x78d6, 0xa684, - 0x0100, 0x0040, 0x3d07, 0x682c, 0xa084, 0x0001, 0x0040, 0x3d07, - 0x7888, 0xa084, 0x0040, 0x0040, 0x3d07, 0xa6b5, 0x8000, 0x1078, - 0x47f6, 0x7e5a, 0x6eb6, 0x0078, 0x4835, 0x1078, 0x39c8, 0x00c0, - 0x3da0, 0x702c, 0x8004, 0x0048, 0x3d1b, 0x2019, 0x4f49, 0x1078, - 0x2313, 0x702f, 0x0001, 0x2041, 0x0001, 0x2031, 0x1000, 0x789b, - 0x0018, 0x6814, 0xa084, 0x001f, 0xa085, 0x0080, 0x78aa, 0x691c, - 0xa184, 0x0002, 0x0040, 0x3d34, 0xa6b5, 0x0004, 0x78ab, 0x0020, - 0x6828, 0x78aa, 0xa8c0, 0x0002, 0x681c, 0xd0f4, 0x0040, 0x3d3d, - 0x2c50, 0x1078, 0x3a7a, 0x1078, 0x4702, 0x6820, 0xa084, 0x8000, - 0x0040, 0x3d4b, 0xa6b5, 0x0400, 0x789b, 0x000e, 0x6824, 0x8007, - 0x78aa, 0x0078, 0x3d52, 0x681c, 0xa084, 0x8000, 0x00c0, 0x3d52, - 0xa6b5, 0x0800, 0x6820, 0xa084, 0x0100, 0x0040, 0x3d59, 0xa6b5, - 0x4000, 0x681c, 0xa084, 0x00c0, 0x8003, 0x8003, 0x8007, 0xa080, - 0x3da6, 0x2004, 0xa635, 0xa684, 0x0100, 0x0040, 0x3d73, 0x682c, - 0xa084, 0x0001, 0x0040, 0x3d73, 0x7888, 0xa084, 0x0040, 0x0040, - 0x3d73, 0xa6b5, 0x8000, 0x789b, 0x007e, 0x7eae, 0x6eb6, 0x6814, - 0x8007, 0x78aa, 0x7882, 0x2810, 0x7aaa, 0x7830, 0xa084, 0x00c0, - 0x00c0, 0x3da0, 0x0018, 0x3da0, 0x70b4, 0xa080, 0x00dd, 0x781a, - 0x1078, 0x39e0, 0xa684, 0x0200, 0x0040, 0x3d94, 0x682c, 0x78d2, - 0x6830, 0x78d6, 0x1078, 0x47f6, 0x2d00, 0x70a2, 0x704a, 0x6810, - 0x70be, 0x7003, 0x0007, 0xad80, 0x000f, 0x7036, 0x0078, 0x24fa, - 0x1078, 0x1bd3, 0x1078, 0x39e0, 0x0078, 0x24fa, 0x0000, 0x0300, - 0x0200, 0x0000, 0x1078, 0x248c, 0x2300, 0x0079, 0x3daf, 0x3db2, - 0x3db2, 0x3db4, 0x1078, 0x248c, 0x1078, 0x4805, 0x6924, 0xa184, - 0x00ff, 0xa086, 0x000a, 0x0040, 0x3dc6, 0xa184, 0xff00, 0xa085, - 0x000a, 0x6826, 0x1078, 0x1bd3, 0x0078, 0x3c68, 0x2001, 0x000a, - 0x1078, 0x4797, 0x0078, 0x3c68, 0xa282, 0x0005, 0x0050, 0x3dd2, - 0x1078, 0x248c, 0x7000, 0xa084, 0x0007, 0x10c0, 0x3a8c, 0x1078, - 0x1989, 0x00c0, 0x3df4, 0x2069, 0xffff, 0xa684, 0x0004, 0x0040, - 0x3de5, 0x2001, 0x2800, 0x0078, 0x3de7, 0x2001, 0x0800, 0x71b4, - 0xa188, 0x0091, 0x789b, 0x000e, 0x8007, 0x78aa, 0x2031, 0x0400, - 0x7e5a, 0x791a, 0x0078, 0x24fa, 0x6807, 0x0106, 0x680b, 0x0000, - 0x689f, 0x0000, 0x6827, 0x0000, 0xa386, 0x0002, 0x00c0, 0x3e15, - 0xa286, 0x0002, 0x00c0, 0x3e15, 0x78a0, 0xa005, 0x00c0, 0x3e15, - 0xa484, 0x8000, 0x00c0, 0x3e15, 0x78e4, 0xa084, 0x0008, 0x0040, - 0x3e15, 0xa6b5, 0x0008, 0x2019, 0x0000, 0x1078, 0x4217, 0x2d00, - 0x70a2, 0x704a, 0x7003, 0x0007, 0x7037, 0x0000, 0x6824, 0xa084, - 0x0080, 0x0040, 0x3e27, 0x1078, 0x42cd, 0x0078, 0x24fa, 0x2300, - 0x0079, 0x3e2a, 0x3e2d, 0x3eae, 0x3ec7, 0x2200, 0x0079, 0x3e30, - 0x3e35, 0x3e45, 0x3e6b, 0x3e77, 0x3e9a, 0x2029, 0x0001, 0xa026, - 0x2011, 0x0000, 0x1078, 0x43f3, 0x0079, 0x3e3e, 0x3e43, 0x24fa, - 0x3c68, 0x3e43, 0x3e43, 0x1078, 0x248c, 0x7990, 0xa18c, 0x0007, - 0x00c0, 0x3e4c, 0x2009, 0x0008, 0x2011, 0x0001, 0xa684, 0x0004, - 0x0040, 0x3e54, 0x2011, 0x0003, 0x2220, 0xa12a, 0x2011, 0x0001, - 0x1078, 0x43f3, 0x0079, 0x3e5c, 0x3e61, 0x24fa, 0x3c68, 0x3e69, - 0x3e63, 0x0078, 0x483b, 0x70ab, 0x3e67, 0x0078, 0x24fa, 0x0078, - 0x3e61, 0x1078, 0x248c, 0xa684, 0x0010, 0x0040, 0x3e75, 0x1078, - 0x429c, 0x0040, 0x3e75, 0x0078, 0x24fa, 0x0078, 0x430d, 0x6000, - 0xa084, 0x0002, 0x0040, 0x3e94, 0x70b4, 0xa080, 0x00cd, 0x781a, - 0x0d7e, 0x1078, 0x4812, 0x2d00, 0x682e, 0x6827, 0x0000, 0x1078, - 0x3bc6, 0x0d7f, 0x1078, 0x19ac, 0x7003, 0x0000, 0x7037, 0x0000, - 0x704b, 0x0000, 0x0078, 0x3c68, 0xa684, 0x0004, 0x00c0, 0x3e9a, - 0x0078, 0x483b, 0x6000, 0xa084, 0x0004, 0x00c0, 0x3eac, 0x6000, - 0xa084, 0x0001, 0x0040, 0x3eac, 0x70ab, 0x3eac, 0x2001, 0x0007, - 0x1078, 0x478f, 0x0078, 0x4841, 0x0078, 0x483b, 0x2200, 0x0079, - 0x3eb1, 0x3eb6, 0x3eb8, 0x3eb6, 0x3eb6, 0x3eb6, 0x1078, 0x248c, - 0x70a7, 0x3ebc, 0x0078, 0x4847, 0x78e4, 0xa084, 0x0008, 0x00c0, - 0x3eb8, 0x1078, 0x4781, 0x70ab, 0x3ec5, 0x0078, 0x483b, 0x2200, - 0x0079, 0x3eca, 0x3ecf, 0x3ed1, 0x3ed1, 0x3ecf, 0x3ecf, 0x1078, - 0x248c, 0x78e4, 0xa084, 0x0008, 0x0040, 0x3ee6, 0x70a7, 0x3eda, - 0x0078, 0x4847, 0x2011, 0x0004, 0x1078, 0x43ed, 0x0079, 0x3ee0, - 0x3ee6, 0x24fa, 0x3c68, 0x3ee6, 0x3ef0, 0x3ef4, 0x70ab, 0x3eee, - 0x2001, 0x0003, 0x1078, 0x478f, 0x0078, 0x4841, 0x0078, 0x483b, - 0x70ab, 0x3ee6, 0x0078, 0x24fa, 0x70ab, 0x3ef8, 0x0078, 0x24fa, - 0x0078, 0x3eee, 0xa282, 0x0003, 0x0050, 0x3f00, 0x1078, 0x248c, - 0xa386, 0x0002, 0x00c0, 0x3f19, 0xa286, 0x0002, 0x00c0, 0x3f1f, - 0x78a0, 0xa005, 0x00c0, 0x3f1f, 0xa484, 0x8000, 0x00c0, 0x3f1f, - 0x78e4, 0xa084, 0x0008, 0x0040, 0x3f19, 0xa6b5, 0x0008, 0x2019, - 0x0000, 0xa684, 0x0008, 0x0040, 0x3f1f, 0x1078, 0x4279, 0x6810, - 0x70be, 0x7003, 0x0007, 0x2300, 0x0079, 0x3f26, 0x3f29, 0x3f56, - 0x3f5e, 0x2200, 0x0079, 0x3f2c, 0x3f31, 0x3f2f, 0x3f4a, 0x1078, - 0x248c, 0x7990, 0xa1ac, 0x0007, 0xa026, 0x2011, 0x0001, 0x1078, - 0x43f3, 0x0079, 0x3f3b, 0x3f40, 0x24fa, 0x3c68, 0x3f48, 0x3f42, - 0x0078, 0x483b, 0x70ab, 0x3f46, 0x0078, 0x24fa, 0x0078, 0x3f40, - 0x1078, 0x248c, 0xa684, 0x0010, 0x0040, 0x3f54, 0x1078, 0x429c, - 0x0040, 0x3f54, 0x0078, 0x24fa, 0x0078, 0x430d, 0x2200, 0x0079, - 0x3f59, 0x3f5c, 0x3f5c, 0x3f5c, 0x1078, 0x248c, 0x2200, 0x0079, - 0x3f61, 0x3f64, 0x3f66, 0x3f66, 0x1078, 0x248c, 0x78e4, 0xa084, - 0x0008, 0x0040, 0x3f7b, 0x70a7, 0x3f6f, 0x0078, 0x4847, 0x2011, - 0x0004, 0x1078, 0x43ed, 0x0079, 0x3f75, 0x3f7b, 0x24fa, 0x3c68, - 0x3f7b, 0x3f85, 0x3f89, 0x70ab, 0x3f83, 0x2001, 0x0003, 0x1078, - 0x478f, 0x0078, 0x4841, 0x0078, 0x483b, 0x70ab, 0x3f7b, 0x0078, - 0x24fa, 0x70ab, 0x3f8d, 0x0078, 0x24fa, 0x0078, 0x3f83, 0x2300, - 0x0079, 0x3f92, 0x3f97, 0x3f99, 0x3f95, 0x1078, 0x248c, 0x70a4, - 0x007a, 0x70a4, 0x007a, 0xa282, 0x0002, 0x0050, 0x3fa1, 0x1078, - 0x248c, 0xa684, 0x0200, 0x0040, 0x3fab, 0x1078, 0x47fe, 0x1078, - 0x43d5, 0x1078, 0x4805, 0x2300, 0x0079, 0x3fae, 0x3fb1, 0x3fd9, - 0x403f, 0xad86, 0xffff, 0x0040, 0x3c68, 0xa286, 0x0001, 0x0040, - 0x3fbb, 0x1078, 0x248c, 0xa684, 0x0200, 0x0040, 0x3fc3, 0x1078, - 0x47fe, 0x1078, 0x4805, 0x2001, 0x0001, 0x1078, 0x4797, 0x78b8, - 0xa084, 0xc001, 0x0040, 0x3fd5, 0x7848, 0xa085, 0x0008, 0x784a, - 0x7848, 0xa084, 0x0008, 0x00c0, 0x3fd0, 0x7003, 0x0000, 0x0078, - 0x3c68, 0x2200, 0x0079, 0x3fdc, 0x3fde, 0x400f, 0x70a7, 0x3fe2, - 0x0078, 0x4847, 0x2011, 0x000d, 0x1078, 0x43ed, 0x0079, 0x3fe8, - 0x3fef, 0x24fa, 0x3c68, 0x3ff7, 0x3fff, 0x4005, 0x4007, 0xa6b4, - 0x00ff, 0xa6b5, 0x0400, 0x6eb6, 0x7e5a, 0x0078, 0x4835, 0xa6b4, - 0x00ff, 0xa6b5, 0x0400, 0x6eb6, 0x7e5a, 0x0078, 0x4835, 0x70ab, - 0x4003, 0x0078, 0x24fa, 0x0078, 0x3fef, 0x1078, 0x248c, 0x70ab, - 0x400b, 0x0078, 0x24fa, 0x1078, 0x484d, 0x0078, 0x24fa, 0x70a7, - 0x4013, 0x0078, 0x4847, 0x2011, 0x0012, 0x1078, 0x43ed, 0x0079, - 0x4019, 0x401f, 0x24fa, 0x3c68, 0x402b, 0x4033, 0x4039, 0xa6b4, - 0x00ff, 0xa6b5, 0x0400, 0x6eb6, 0x7e5a, 0x70b4, 0xa080, 0x00aa, - 0x781a, 0x0078, 0x24fa, 0xa6b4, 0x00ff, 0xa6b5, 0x0400, 0x6eb6, - 0x7e5a, 0x0078, 0x4835, 0x70ab, 0x4037, 0x0078, 0x24fa, 0x0078, - 0x401f, 0x70ab, 0x403d, 0x0078, 0x24fa, 0x0078, 0x402b, 0xa286, - 0x0001, 0x0040, 0x4045, 0x1078, 0x248c, 0x70a7, 0x4049, 0x0078, - 0x4847, 0x2011, 0x0015, 0x1078, 0x43ed, 0x0079, 0x404f, 0x4054, - 0x24fa, 0x3c68, 0x4062, 0x406e, 0xa6b4, 0x00ff, 0xa6b5, 0x0400, - 0x6eb6, 0x7e5a, 0x783b, 0x1301, 0x70b4, 0xa080, 0x00b5, 0x781a, - 0x0078, 0x24fa, 0xa6b4, 0x00ff, 0xa6b5, 0x0400, 0x6eb6, 0x7e5a, - 0x70b4, 0xa080, 0x00aa, 0x781a, 0x0078, 0x24fa, 0x70ab, 0x4072, - 0x0078, 0x24fa, 0x0078, 0x4054, 0xa282, 0x0003, 0x0050, 0x407a, - 0x1078, 0x248c, 0x2300, 0x0079, 0x407d, 0x4080, 0x40b7, 0x4114, - 0xa286, 0x0001, 0x0040, 0x4086, 0x1078, 0x248c, 0x6804, 0xa084, - 0x00ff, 0xa086, 0x0006, 0x00c0, 0x4093, 0x1078, 0x3bc6, 0x7003, - 0x0000, 0x0078, 0x3c68, 0x683b, 0x0000, 0x6837, 0x0000, 0xa684, - 0x0200, 0x0040, 0x40a1, 0x1078, 0x47fe, 0x1078, 0x43d5, 0x1078, - 0x4805, 0x2001, 0x0001, 0x1078, 0x4797, 0x78b8, 0xa084, 0xc001, - 0x0040, 0x40b3, 0x7848, 0xa085, 0x0008, 0x784a, 0x7848, 0xa084, - 0x0008, 0x00c0, 0x40ae, 0x7003, 0x0000, 0x0078, 0x3c68, 0x2200, - 0x0079, 0x40ba, 0x40bc, 0x40ef, 0x70a7, 0x40c0, 0x0078, 0x4847, - 0x2011, 0x000d, 0x1078, 0x43ed, 0x0079, 0x40c6, 0x40cd, 0x24fa, - 0x3c68, 0x40d5, 0x40dd, 0x40e3, 0x40e5, 0xa6b4, 0x00ff, 0xa6b5, - 0x0800, 0x6eb6, 0x7e5a, 0x0078, 0x4835, 0xa6b4, 0x00ff, 0xa6b5, - 0x0800, 0x6eb6, 0x7e5a, 0x0078, 0x4835, 0x70ab, 0x40e1, 0x0078, - 0x24fa, 0x0078, 0x40cd, 0x1078, 0x248c, 0x70ab, 0x40eb, 0x1078, - 0x4805, 0x0078, 0x24fa, 0x1078, 0x484d, 0x0078, 0x24fa, 0x70a7, - 0x40f3, 0x0078, 0x4847, 0x2011, 0x0005, 0x1078, 0x43ed, 0x0079, - 0x40f9, 0x40fe, 0x24fa, 0x3c68, 0x4106, 0x410e, 0xa6b4, 0x00ff, - 0xa6b5, 0x0800, 0x6eb6, 0x7e5a, 0x0078, 0x4835, 0xa6b4, 0x00ff, - 0xa6b5, 0x0800, 0x6eb6, 0x7e5a, 0x0078, 0x4835, 0x70ab, 0x4112, - 0x0078, 0x24fa, 0x0078, 0x40fe, 0xa286, 0x0001, 0x0040, 0x411a, - 0x1078, 0x248c, 0x70a7, 0x411e, 0x0078, 0x4847, 0x2011, 0x0006, - 0x1078, 0x43ed, 0x0079, 0x4124, 0x4129, 0x24fa, 0x3c68, 0x412f, - 0x4139, 0xa6b5, 0x0800, 0x6eb6, 0x7e5a, 0x0078, 0x4835, 0xa6b4, - 0x00ff, 0xa6b5, 0x0800, 0x6eb6, 0xa6b5, 0x4000, 0x7e5a, 0x0078, - 0x4835, 0x70ab, 0x413d, 0x0078, 0x24fa, 0x0078, 0x4129, 0x2300, - 0x0079, 0x4142, 0x4147, 0x4145, 0x4145, 0x1078, 0x248c, 0x1078, - 0x248c, 0x2300, 0x71a8, 0xa005, 0x017a, 0x6810, 0x70be, 0xa282, - 0x0003, 0x0050, 0x4155, 0x1078, 0x248c, 0x2300, 0x0079, 0x4158, - 0x415b, 0x4169, 0x418b, 0xa684, 0x0200, 0x0040, 0x4163, 0x1078, - 0x47fe, 0x1078, 0x4805, 0x2001, 0x0001, 0x1078, 0x4797, 0x0078, - 0x24fa, 0xa296, 0x0002, 0x0040, 0x4172, 0x82ff, 0x0040, 0x4172, - 0x1078, 0x248c, 0x70a7, 0x4176, 0x0078, 0x4847, 0x2011, 0x0018, - 0x1078, 0x43ed, 0x0079, 0x417c, 0x4181, 0x24fa, 0x3c68, 0x4183, - 0x4185, 0x0078, 0x4835, 0x0078, 0x4835, 0x70ab, 0x4189, 0x0078, - 0x24fa, 0x0078, 0x4181, 0x2200, 0x0079, 0x418e, 0x4190, 0x41a9, - 0x70a7, 0x4194, 0x0078, 0x4847, 0x2011, 0x0017, 0x1078, 0x43ed, - 0x0079, 0x419a, 0x419f, 0x24fa, 0x3c68, 0x41a1, 0x41a3, 0x0078, - 0x4835, 0x0078, 0x4835, 0x70ab, 0x41a7, 0x0078, 0x24fa, 0x0078, - 0x419f, 0xa484, 0x8000, 0x00c0, 0x4205, 0xa684, 0x0100, 0x0040, - 0x41b5, 0x1078, 0x47fe, 0x1078, 0x43d5, 0x78d8, 0x78d2, 0x78dc, - 0x78d6, 0xa6b4, 0xefff, 0x7e5a, 0x70a7, 0x41c0, 0x0078, 0x4847, - 0x2011, 0x000d, 0x1078, 0x43ed, 0x0079, 0x41c6, 0x41cd, 0x24fa, - 0x3c68, 0x41cd, 0x41f3, 0x41f9, 0x41fb, 0x78d8, 0x79dc, 0xa105, - 0x00c0, 0x41df, 0x78b8, 0xa084, 0x001f, 0x00c0, 0x41df, 0x70b3, - 0x0000, 0x7858, 0xa084, 0xfdff, 0x785a, 0x0078, 0x4835, 0xa684, - 0x0100, 0x0040, 0x41f1, 0x7848, 0xa085, 0x0008, 0x784a, 0x1078, - 0x47bc, 0x682c, 0x78d2, 0x6830, 0x78d6, 0x70b3, 0x0000, 0x1078, - 0x47f6, 0x0078, 0x4835, 0x70ab, 0x41f7, 0x0078, 0x24fa, 0x0078, - 0x41cd, 0x1078, 0x248c, 0x70ab, 0x4201, 0x1078, 0x4805, 0x0078, - 0x24fa, 0x1078, 0x484d, 0x0078, 0x24fa, 0x1078, 0x4805, 0x70ab, - 0x420f, 0x2001, 0x0003, 0x1078, 0x478f, 0x0078, 0x4841, 0x1078, - 0x47f6, 0x682c, 0x78d2, 0x6830, 0x78d6, 0x0078, 0x4835, 0x70b8, - 0x6812, 0x70be, 0x8000, 0x70ba, 0x681b, 0x0000, 0xa684, 0x0008, - 0x0040, 0x423a, 0x157e, 0x137e, 0x147e, 0x7890, 0x8004, 0x8004, - 0x8004, 0x8004, 0xa084, 0x000f, 0x681a, 0x80ac, 0x789b, 0x0000, - 0xaf80, 0x002b, 0x2098, 0xad80, 0x000b, 0x20a0, 0x53a5, 0x147f, - 0x137f, 0x157f, 0xa6c4, 0x0f00, 0xa684, 0x0002, 0x00c0, 0x4249, - 0x692c, 0x810d, 0x810d, 0x810d, 0xa184, 0x0007, 0x2008, 0x0078, - 0x425c, 0x789b, 0x0010, 0x79ac, 0xa184, 0x0020, 0x0040, 0x425c, - 0x017e, 0x2009, 0x0005, 0x2001, 0x3d00, 0x1078, 0x47c7, 0x6824, - 0xa085, 0x003b, 0x6826, 0x017f, 0xa184, 0x001f, 0xa805, 0x6816, - 0x1078, 0x3c3b, 0x68be, 0xa684, 0x0004, 0x0040, 0x426d, 0xa18c, - 0xff00, 0x78a8, 0xa084, 0x00ff, 0xa105, 0x682a, 0xa6b4, 0x00ff, - 0x6000, 0xa084, 0x0008, 0x0040, 0x4277, 0xa6b5, 0x4000, 0x6eb6, - 0x007c, 0x157e, 0x137e, 0x147e, 0x6918, 0x7890, 0x8004, 0x8004, - 0x8004, 0x8004, 0xa084, 0x000f, 0x007e, 0xa100, 0x681a, 0x007f, - 0x8000, 0x8004, 0x0040, 0x4298, 0x20a8, 0x8104, 0xa080, 0x000b, - 0xad00, 0x20a0, 0x789b, 0x0000, 0xaf80, 0x002b, 0x2098, 0x53a5, - 0x147f, 0x137f, 0x157f, 0x007c, 0x682c, 0xa084, 0x0020, 0x00c0, - 0x42a4, 0x620c, 0x0078, 0x42a5, 0x6210, 0x6b18, 0x2300, 0xa202, - 0x0040, 0x42c5, 0x2018, 0xa382, 0x000e, 0x0048, 0x42b5, 0x0040, - 0x42b5, 0x2019, 0x000e, 0x0078, 0x42b9, 0x7858, 0xa084, 0xffef, - 0x785a, 0x783b, 0x1b01, 0x7893, 0x0000, 0x7ba2, 0x70b4, 0xa080, - 0x008e, 0x781a, 0xa085, 0x0001, 0x007c, 0x7858, 0xa084, 0xffef, - 0x785a, 0x7893, 0x0000, 0xa006, 0x007c, 0x6904, 0xa18c, 0x00ff, - 0xa196, 0x0007, 0x0040, 0x42da, 0xa196, 0x000f, 0x0040, 0x42da, - 0x6807, 0x0117, 0x6914, 0x1078, 0x3c3b, 0x6100, 0x8104, 0x00c8, - 0x42f5, 0x601c, 0xa005, 0x0040, 0x42e9, 0x2001, 0x0800, 0x0078, - 0x42f7, 0x0d7e, 0x6824, 0x007e, 0x1078, 0x4812, 0x007f, 0x6826, - 0x2d00, 0x682e, 0x1078, 0x3bc6, 0x0d7f, 0x2001, 0x0200, 0x6924, - 0xa18c, 0x00ff, 0xa10d, 0x6926, 0x8007, 0x789b, 0x000e, 0x78aa, - 0x6820, 0xa085, 0x8000, 0x6822, 0x2031, 0x0400, 0x6eb6, 0x7e5a, - 0x71b4, 0xa188, 0x0091, 0x791a, 0x007c, 0xa6c4, 0x0f00, 0xa684, - 0x0002, 0x00c0, 0x4321, 0x692c, 0x810d, 0x810d, 0x810d, 0xa184, - 0x0007, 0x2008, 0xa805, 0x6816, 0x1078, 0x3c3b, 0x68be, 0x0078, - 0x4324, 0x6914, 0x1078, 0x3c3b, 0x6100, 0x8104, 0x00c8, 0x4382, - 0xa184, 0x0300, 0x0040, 0x4330, 0x6807, 0x0117, 0x0078, 0x434e, - 0x6004, 0xa005, 0x00c0, 0x4357, 0x6807, 0x0117, 0x601c, 0xa005, - 0x00c0, 0x4344, 0x0d7e, 0x1078, 0x4812, 0x6827, 0x0034, 0x2d00, - 0x682e, 0x1078, 0x3bc6, 0x0d7f, 0xa684, 0x0004, 0x0040, 0x434e, - 0x2031, 0x0400, 0x2001, 0x2800, 0x0078, 0x4352, 0x2031, 0x0400, - 0x2001, 0x0800, 0x71b4, 0xa188, 0x0091, 0x0078, 0x43b0, 0x6018, - 0xa005, 0x00c0, 0x4344, 0x601c, 0xa005, 0x00c0, 0x4344, 0x689f, - 0x0000, 0x6827, 0x003d, 0xa684, 0x0001, 0x0040, 0x43be, 0xd694, - 0x00c0, 0x437b, 0x6100, 0xd1d4, 0x0040, 0x437b, 0x692c, 0xa18c, - 0x00ff, 0x0040, 0x43be, 0xa186, 0x0003, 0x0040, 0x43be, 0xa186, - 0x0012, 0x0040, 0x43be, 0xa6b5, 0x0800, 0x71b4, 0xa188, 0x00ae, - 0x0078, 0x43b9, 0x6807, 0x0117, 0x2031, 0x0400, 0x692c, 0xa18c, - 0x00ff, 0xa186, 0x0012, 0x00c0, 0x4393, 0x2001, 0x43cb, 0x2009, - 0x0001, 0x0078, 0x43a4, 0xa186, 0x0003, 0x00c0, 0x439d, 0x2001, - 0x43cc, 0x2009, 0x0012, 0x0078, 0x43a4, 0x2001, 0x0200, 0x71b4, - 0xa188, 0x0091, 0x0078, 0x43b0, 0x1078, 0x47e1, 0x78a3, 0x0000, - 0x681c, 0xa085, 0x0040, 0x681e, 0x71b4, 0xa188, 0x00da, 0xa006, - 0x6826, 0x8007, 0x789b, 0x000e, 0x78aa, 0x6820, 0xa085, 0x8000, - 0x6822, 0x6eb6, 0x7e5a, 0x791a, 0x0078, 0x24fa, 0x6eb6, 0x1078, - 0x3bc6, 0x6810, 0x70be, 0x7003, 0x0007, 0x70a3, 0x0000, 0x704b, - 0x0000, 0x0078, 0x24fa, 0x0023, 0x0070, 0x0005, 0x0000, 0x0a00, - 0x0000, 0x0000, 0x0025, 0x0000, 0x0000, 0x683b, 0x0000, 0x6837, - 0x0000, 0xa684, 0x0200, 0x0040, 0x43ec, 0x78b8, 0xa08c, 0x001f, - 0xa084, 0x8000, 0x0040, 0x43e5, 0x8108, 0x78d8, 0xa100, 0x6836, - 0x78dc, 0xa081, 0x0000, 0x683a, 0x007c, 0x7990, 0x810f, 0xa5ac, - 0x0007, 0x2021, 0x0000, 0xa480, 0x0010, 0x789a, 0x79a8, 0xa18c, - 0x00ff, 0xa184, 0x0080, 0x00c0, 0x441b, 0xa182, 0x0020, 0x00c8, - 0x4439, 0xa182, 0x0012, 0x00c8, 0x4781, 0x2100, 0x1079, 0x4409, - 0x007c, 0x4781, 0x45eb, 0x4781, 0x4781, 0x4446, 0x4449, 0x4483, - 0x44b9, 0x44ed, 0x44f0, 0x4781, 0x4781, 0x44a4, 0x4514, 0x454e, - 0x4781, 0x4781, 0x4574, 0xa184, 0x0020, 0x00c0, 0x45a8, 0xa18c, - 0x001f, 0x6814, 0xa084, 0x001f, 0xa106, 0x0040, 0x4436, 0x70b4, - 0xa080, 0x00cd, 0x781a, 0x2001, 0x0014, 0x1078, 0x4797, 0x1078, - 0x4805, 0x7003, 0x0000, 0x2001, 0x0002, 0x007c, 0x2001, 0x0000, - 0x007c, 0xa182, 0x0024, 0x00c8, 0x4781, 0xa184, 0x0003, 0x1079, - 0x4409, 0x007c, 0x4781, 0x4781, 0x4781, 0x4781, 0x1078, 0x4781, - 0x007c, 0x2200, 0x0079, 0x444c, 0x4577, 0x4577, 0x4470, 0x4470, - 0x4470, 0x4470, 0x4470, 0x4470, 0x4470, 0x4470, 0x446e, 0x4470, - 0x4465, 0x4470, 0x4470, 0x4470, 0x4470, 0x4470, 0x4478, 0x447b, - 0x4577, 0x447b, 0x4470, 0x4470, 0x4470, 0x0c7e, 0x077e, 0x6f14, - 0x1078, 0x37b0, 0x077f, 0x0c7f, 0x0078, 0x4470, 0x1078, 0x468e, - 0x6827, 0x02b3, 0x2009, 0x000b, 0x2001, 0x4800, 0x0078, 0x45ab, - 0x1078, 0x4773, 0x007c, 0x6827, 0x0093, 0x2009, 0x000b, 0x2001, - 0x4800, 0x0078, 0x4593, 0x2d58, 0x6804, 0xa084, 0x00ff, 0xa086, - 0x0006, 0x00c0, 0x448d, 0x6807, 0x0117, 0x6827, 0x0002, 0x1078, - 0x4812, 0x6827, 0x0036, 0x6932, 0x2d00, 0x682e, 0x0d7e, 0x1078, - 0x3b96, 0x1078, 0x45d3, 0x2b68, 0x1078, 0x3bc6, 0x0d7f, 0x1078, - 0x3bc6, 0x2001, 0x0002, 0x007c, 0x1078, 0x45d3, 0x2001, 0x0017, - 0x1078, 0x4797, 0x70a3, 0x0000, 0x2009, 0x5238, 0x200b, 0x0006, - 0x70af, 0x0017, 0x2009, 0x0200, 0x1078, 0x3ad4, 0x2001, 0x0001, - 0x007c, 0x2200, 0x0079, 0x44bc, 0x4577, 0x45a8, 0x45a8, 0x45a8, - 0x44dd, 0x45ba, 0x44e5, 0x45ba, 0x45ba, 0x45bd, 0x45bd, 0x45c2, - 0x45c2, 0x44d5, 0x44d5, 0x45a8, 0x45a8, 0x45ba, 0x45a8, 0x44e5, - 0x4577, 0x44e5, 0x44e5, 0x44e5, 0x44e5, 0x6827, 0x0084, 0x2009, - 0x000b, 0x2001, 0x4300, 0x0078, 0x45cc, 0x6827, 0x000d, 0x2009, - 0x000b, 0x2001, 0x4300, 0x0078, 0x45ab, 0x6827, 0x0093, 0x2009, - 0x000b, 0x2001, 0x4300, 0x0078, 0x4593, 0x2001, 0x0000, 0x007c, - 0x2200, 0x0079, 0x44f3, 0x4577, 0x450c, 0x450c, 0x450c, 0x450c, - 0x45ba, 0x45ba, 0x45ba, 0x45ba, 0x45ba, 0x45ba, 0x45ba, 0x45ba, - 0x450c, 0x450c, 0x450c, 0x450c, 0x45ba, 0x450c, 0x450c, 0x45ba, - 0x45ba, 0x45ba, 0x45ba, 0x4577, 0x6827, 0x0093, 0x2009, 0x000b, - 0x2001, 0x4300, 0x0078, 0x4593, 0xa684, 0x0004, 0x00c0, 0x4528, - 0x6804, 0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0, 0x4781, 0x1078, - 0x45d3, 0x6807, 0x0117, 0x1078, 0x3bc6, 0x2001, 0x0002, 0x007c, - 0x6000, 0xa084, 0x0004, 0x0040, 0x4781, 0x2d58, 0x6804, 0xa084, - 0x00ff, 0xa086, 0x0006, 0x00c0, 0x4537, 0x6807, 0x0117, 0x6827, - 0x0002, 0x1078, 0x4812, 0x6827, 0x0036, 0x6932, 0x2d00, 0x682e, - 0x0d7e, 0x1078, 0x3ba5, 0x1078, 0x45d3, 0x2b68, 0x1078, 0x3bc6, - 0x0d7f, 0x1078, 0x3bc6, 0x2001, 0x0002, 0x007c, 0x6000, 0xa084, - 0x0004, 0x0040, 0x4781, 0x6a04, 0xa294, 0x00ff, 0xa286, 0x0006, - 0x00c0, 0x455c, 0x6807, 0x0117, 0x6827, 0x0002, 0x2d58, 0x1078, - 0x4812, 0x6827, 0x0036, 0x6932, 0x2d00, 0x682e, 0x0d7e, 0x1078, - 0x3bb5, 0x1078, 0x45d3, 0x2b68, 0x1078, 0x3bc6, 0x0d7f, 0x1078, - 0x3bc6, 0x2001, 0x0002, 0x007c, 0x1078, 0x4781, 0x007c, 0x70b4, - 0xa080, 0x00cd, 0x781a, 0x2001, 0x0001, 0x1078, 0x4797, 0x1078, - 0x4805, 0x7003, 0x0000, 0x2001, 0x0002, 0x007c, 0x1078, 0x47c7, - 0x1078, 0x47fe, 0x1078, 0x43d5, 0x1078, 0x42cd, 0x1078, 0x4805, - 0x2001, 0x0001, 0x007c, 0x1078, 0x47c7, 0x1078, 0x47fe, 0x1078, - 0x43d5, 0x70b4, 0xa080, 0x00cd, 0x781a, 0x2001, 0x0013, 0x1078, - 0x4797, 0x1078, 0x4805, 0x7003, 0x0000, 0x2001, 0x0002, 0x007c, - 0x1078, 0x4781, 0x007c, 0x1078, 0x47c7, 0x1078, 0x47fe, 0x1078, - 0x43d5, 0x1078, 0x42cd, 0x1078, 0x4805, 0x1078, 0x484d, 0x2001, - 0x0001, 0x007c, 0x2001, 0x0003, 0x007c, 0x1078, 0x468e, 0x2001, - 0x0000, 0x007c, 0x0c7e, 0x077e, 0x6f14, 0x1078, 0x37b0, 0x077f, - 0x0c7f, 0x2001, 0x0000, 0x007c, 0x1078, 0x47c7, 0x1078, 0x4781, - 0x2001, 0x0006, 0x007c, 0x6904, 0xa18c, 0x00ff, 0xa186, 0x0007, - 0x0040, 0x45de, 0xa186, 0x000f, 0x00c0, 0x45e2, 0x1078, 0x47fe, - 0x1078, 0x43d5, 0x70b4, 0xa080, 0x00cd, 0x781a, 0x1078, 0x4805, - 0x7003, 0x0000, 0x007c, 0x7aa8, 0xa294, 0x00ff, 0x78a8, 0xa084, - 0x00ff, 0xa08a, 0x0004, 0x00c8, 0x4781, 0x1079, 0x45f8, 0x007c, - 0x4781, 0x45fc, 0x4781, 0x4695, 0xa282, 0x0003, 0x0040, 0x4603, - 0x1078, 0x4781, 0x007c, 0x7da8, 0xa5ac, 0x00ff, 0x7ca8, 0xa4a4, - 0x00ff, 0x69b8, 0xa184, 0x0100, 0x0040, 0x4642, 0xa18c, 0xfeff, - 0x69ba, 0x78a0, 0xa005, 0x00c0, 0x4642, 0xa4a4, 0x00ff, 0x0040, - 0x4636, 0xa482, 0x000c, 0x0040, 0x461f, 0x00c8, 0x4629, 0x852b, - 0x852b, 0x1078, 0x382e, 0x0040, 0x4629, 0x1078, 0x3627, 0x0078, - 0x4638, 0x1078, 0x4760, 0x1078, 0x3652, 0x69b8, 0xa18d, 0x0100, - 0x69ba, 0xa6b5, 0x1000, 0x7e5a, 0x0078, 0x463b, 0x1078, 0x3652, - 0xa6b4, 0xefff, 0x7e5a, 0x70b4, 0xa080, 0x0091, 0x781a, 0x2001, - 0x0001, 0x007c, 0x0c7e, 0x1078, 0x4682, 0x6200, 0xd2e4, 0x0040, - 0x4673, 0x6208, 0x8217, 0xa294, 0x00ff, 0xa282, 0x000c, 0x0048, - 0x4655, 0x0040, 0x4655, 0x2011, 0x000c, 0x2400, 0xa202, 0x00c8, - 0x465a, 0x2220, 0x6208, 0xa294, 0x00ff, 0x701c, 0xa202, 0x00c8, - 0x4662, 0x721c, 0x2200, 0xa502, 0x00c8, 0x4667, 0x2228, 0x1078, - 0x4764, 0x852b, 0x852b, 0x1078, 0x382e, 0x0040, 0x4673, 0x1078, - 0x362e, 0x0078, 0x4677, 0x1078, 0x4760, 0x1078, 0x3659, 0xa6b5, - 0x1000, 0x7e5a, 0x70b4, 0xa080, 0x00b9, 0x781a, 0x2001, 0x0004, - 0x0c7f, 0x007c, 0x007e, 0x6814, 0x8007, 0xa084, 0x000f, 0x8003, - 0x8003, 0x8003, 0xa0e0, 0x5480, 0x007f, 0x007c, 0x0c7e, 0x1078, - 0x4682, 0x1078, 0x3659, 0x0c7f, 0x007c, 0xa282, 0x0002, 0x00c0, - 0x4781, 0x7aa8, 0xa294, 0x00ff, 0x69b8, 0xa184, 0x0200, 0x0040, - 0x46cc, 0xa18c, 0xfdff, 0x69ba, 0x78a0, 0xa005, 0x00c0, 0x46cc, - 0xa282, 0x0002, 0x00c8, 0x376b, 0x1078, 0x472a, 0x1078, 0x36f9, - 0x1078, 0x3652, 0xa684, 0x0100, 0x0040, 0x46c2, 0x682c, 0xa084, - 0x0001, 0x0040, 0x46c2, 0xc6fc, 0x7888, 0xa084, 0x0040, 0x0040, - 0x46c2, 0xc6fd, 0xa6b5, 0x1000, 0x7e5a, 0x70b4, 0xa080, 0x0091, - 0x781a, 0x2001, 0x0001, 0x007c, 0x0c7e, 0x1078, 0x4682, 0xa284, - 0xfffe, 0x0040, 0x46d7, 0x2011, 0x0001, 0x0078, 0x46db, 0xa284, - 0x0001, 0x0040, 0x46e1, 0x6100, 0xd1ec, 0x00c0, 0x46e1, 0x2011, - 0x0000, 0x1078, 0x471c, 0x1078, 0x3700, 0x1078, 0x3659, 0xa684, - 0x0100, 0x0040, 0x46f7, 0x682c, 0xa084, 0x0001, 0x0040, 0x46f7, - 0xc6fc, 0x7888, 0xa084, 0x0040, 0x0040, 0x46f7, 0xc6fd, 0xa6b5, - 0x1000, 0x7e5a, 0x70b4, 0xa080, 0x00b9, 0x781a, 0x2001, 0x0004, - 0x0c7f, 0x007c, 0x0c7e, 0x2960, 0x6000, 0x2011, 0x0001, 0xa084, - 0x2000, 0x00c0, 0x470d, 0x2011, 0x0000, 0x78ab, 0x0001, 0x78ab, - 0x0002, 0x78ab, 0x0003, 0x7aaa, 0xa8c0, 0x0004, 0x68b8, 0xa085, - 0x0200, 0x68ba, 0x0c7f, 0x007c, 0x789b, 0x0018, 0x78ab, 0x0001, - 0x78ab, 0x0002, 0x78ab, 0x0003, 0x7aaa, 0x789b, 0x0081, 0x78ab, - 0x0004, 0x007c, 0x0c7e, 0x7054, 0x2060, 0x6000, 0xa084, 0x1000, - 0x00c0, 0x4738, 0x2029, 0x0032, 0x2021, 0x0000, 0x0078, 0x4758, - 0x6508, 0xa5ac, 0x00ff, 0x7018, 0xa086, 0x0028, 0x00c0, 0x4748, - 0xa582, 0x0019, 0x00c8, 0x474e, 0x2029, 0x0019, 0x0078, 0x474e, - 0xa582, 0x000c, 0x00c8, 0x474e, 0x2029, 0x000c, 0x6408, 0x8427, - 0xa4a4, 0x00ff, 0xa482, 0x000c, 0x0048, 0x4758, 0x2021, 0x000c, - 0x1078, 0x4764, 0x68b8, 0xa085, 0x0100, 0x68ba, 0x0c7f, 0x007c, - 0x2021, 0x0000, 0x2029, 0x0032, 0x789b, 0x0018, 0x78ab, 0x0001, - 0x78ab, 0x0003, 0x78ab, 0x0001, 0x7daa, 0x7caa, 0x789b, 0x0081, - 0x78ab, 0x0005, 0x007c, 0x2001, 0x0003, 0x1078, 0x478f, 0xa6b5, - 0x1000, 0x7e5a, 0x70b4, 0xa080, 0x00b9, 0x781a, 0x2001, 0x0005, - 0x007c, 0x2001, 0x0007, 0x1078, 0x478f, 0xa6b5, 0x1000, 0x7e5a, - 0x70b4, 0xa080, 0x00b9, 0x781a, 0x2001, 0x0004, 0x007c, 0x789b, - 0x0018, 0x78aa, 0x789b, 0x0081, 0x78ab, 0x0001, 0x007c, 0x6904, - 0xa18c, 0x00ff, 0xa196, 0x0007, 0x0040, 0x47a5, 0xa196, 0x000f, - 0x0040, 0x47a5, 0x1078, 0x19ac, 0x007c, 0x6924, 0xa194, 0x003f, - 0x00c0, 0x47ae, 0xa18c, 0xffc0, 0xa105, 0x6826, 0x1078, 0x3bc6, - 0x691c, 0xa184, 0x0100, 0x0040, 0x47bb, 0x6914, 0x1078, 0x3c3b, - 0x6204, 0x8210, 0x6206, 0x007c, 0x692c, 0x6834, 0x682e, 0xa112, - 0x6930, 0x6838, 0x6832, 0xa11b, 0xa200, 0xa301, 0x007c, 0x0c7e, - 0xade0, 0x0018, 0x6003, 0x0070, 0x6106, 0x600b, 0x0000, 0x600f, - 0x0a00, 0x6013, 0x0000, 0x6017, 0x0000, 0x8007, 0x601a, 0x601f, - 0x0000, 0x6023, 0x0000, 0x0c7f, 0x6824, 0xa085, 0x0080, 0x6826, - 0x007c, 0x157e, 0x137e, 0x147e, 0x2098, 0xaf80, 0x002d, 0x20a0, - 0x81ac, 0x0040, 0x47ec, 0x53a6, 0xa184, 0x0001, 0x0040, 0x47f2, - 0x3304, 0x78be, 0x147f, 0x137f, 0x157f, 0x007c, 0x70b0, 0xa005, - 0x10c0, 0x248c, 0x70b3, 0x8000, 0x0078, 0x4b4b, 0x71b0, 0x81ff, - 0x0040, 0x4804, 0x1078, 0x4c41, 0x007c, 0x71b0, 0x81ff, 0x0040, - 0x4811, 0x7848, 0xa085, 0x0008, 0x784a, 0x70b3, 0x0000, 0x1078, - 0x4887, 0x007c, 0x0c7e, 0x0d7e, 0x1078, 0x1989, 0x00c0, 0x481a, - 0x1078, 0x248c, 0x0c7f, 0x157e, 0x137e, 0x147e, 0x2da0, 0x2c98, - 0x20a9, 0x0031, 0x53a3, 0x147f, 0x137f, 0x157f, 0x6807, 0x010d, - 0x680b, 0x0000, 0x7004, 0x8007, 0x681a, 0x6823, 0x0000, 0x681f, - 0x0000, 0x689f, 0x0000, 0x0c7f, 0x007c, 0x70b4, 0xa080, 0x0091, - 0x781a, 0x0078, 0x24fa, 0x70b4, 0xa080, 0x0081, 0x781a, 0x0078, - 0x24fa, 0x70b4, 0xa080, 0x00b9, 0x781a, 0x0078, 0x24fa, 0x70b4, - 0xa080, 0x00c3, 0x781a, 0x0078, 0x24fa, 0x6904, 0xa18c, 0x00ff, - 0xa196, 0x0007, 0x0040, 0x485a, 0xa196, 0x000f, 0x0040, 0x485a, - 0x6807, 0x0117, 0x6824, 0xa084, 0x00ff, 0xa085, 0x0200, 0x6826, - 0x8007, 0x789b, 0x000e, 0x78aa, 0x6820, 0xa085, 0x8000, 0x6822, - 0x2031, 0x0400, 0x6eb6, 0x7e5a, 0x71b4, 0xa188, 0x0091, 0x791a, - 0x007c, 0x1078, 0x4805, 0x7848, 0xa085, 0x000c, 0x784a, 0x70b4, - 0xa080, 0x00cd, 0x781a, 0x2009, 0x000b, 0x2001, 0x4400, 0x1078, - 0x47c7, 0x2001, 0x0013, 0x1078, 0x4797, 0x0078, 0x3c68, 0x127e, - 0x2091, 0x2200, 0x2049, 0x4887, 0x7000, 0x7204, 0xa205, 0x720c, - 0xa215, 0x7008, 0xa084, 0xfff7, 0xa205, 0x0040, 0x4899, 0x0078, - 0x489e, 0x7003, 0x0000, 0x127f, 0x2000, 0x007c, 0x7000, 0xa084, - 0x0001, 0x00c0, 0x48cc, 0x7108, 0x8103, 0x00c8, 0x48ab, 0x1078, - 0x49ce, 0x0078, 0x48a3, 0x700c, 0xa08c, 0x00ff, 0x0040, 0x48cc, - 0x7004, 0x8004, 0x00c8, 0x48c3, 0x7014, 0xa005, 0x00c0, 0x48bf, - 0x7010, 0xa005, 0x0040, 0x48c3, 0xa102, 0x00c8, 0x48a3, 0x7007, - 0x0010, 0x0078, 0x48cc, 0x8aff, 0x0040, 0x48cc, 0x1078, 0x4c18, - 0x00c0, 0x48c6, 0x0040, 0x48a3, 0x1078, 0x4957, 0x7003, 0x0000, - 0x127f, 0x2000, 0x007c, 0x017e, 0x6104, 0xa18c, 0x00ff, 0xa186, - 0x0007, 0x0040, 0x48df, 0xa18e, 0x000f, 0x00c0, 0x48e2, 0x6040, - 0x0078, 0x48e3, 0x6428, 0x017f, 0x84ff, 0x0040, 0x490d, 0x2c70, - 0x7004, 0xa0bc, 0x000f, 0xa7b8, 0x491d, 0x273c, 0x87fb, 0x00c0, - 0x48fb, 0x0048, 0x48f5, 0x1078, 0x248c, 0x609c, 0xa075, 0x0040, - 0x490d, 0x0078, 0x48e8, 0x2704, 0xae68, 0x6808, 0xa630, 0x680c, - 0xa529, 0x8421, 0x0040, 0x490d, 0x8738, 0x2704, 0xa005, 0x00c0, - 0x48fc, 0x709c, 0xa075, 0x00c0, 0x48e8, 0x007c, 0x0000, 0x0005, - 0x0009, 0x000d, 0x0011, 0x0015, 0x0019, 0x001d, 0x0000, 0x0003, - 0x0009, 0x000f, 0x0015, 0x001b, 0x0000, 0x0000, 0x4912, 0x490f, - 0x0000, 0x0000, 0x8000, 0x0000, 0x4912, 0x0000, 0x491a, 0x4917, - 0x0000, 0x0000, 0x0000, 0x0000, 0x491a, 0x0000, 0x4915, 0x4915, - 0x0000, 0x0000, 0x8000, 0x0000, 0x4915, 0x0000, 0x491b, 0x491b, - 0x0000, 0x0000, 0x0000, 0x0000, 0x491b, 0x127e, 0x2091, 0x2200, - 0x2079, 0x5200, 0x2071, 0x0010, 0x7007, 0x000a, 0x7007, 0x0002, - 0x7003, 0x0000, 0x2071, 0x0020, 0x7007, 0x000a, 0x7007, 0x0002, - 0x7003, 0x0000, 0x2049, 0x0000, 0x127f, 0x2000, 0x007c, 0x2049, - 0x4957, 0x2019, 0x0000, 0x7004, 0x8004, 0x00c8, 0x49aa, 0x7007, - 0x0012, 0x7108, 0x7008, 0xa106, 0x00c0, 0x4961, 0xa184, 0x01e0, - 0x0040, 0x496c, 0x1078, 0x248c, 0x2001, 0x04fd, 0x2004, 0xa082, - 0x0005, 0x00c8, 0x4977, 0xa184, 0x4000, 0x00c0, 0x4961, 0xa19c, - 0x300c, 0xa386, 0x2004, 0x0040, 0x4985, 0xa386, 0x0008, 0x0040, - 0x4990, 0xa386, 0x200c, 0x00c0, 0x4961, 0x7200, 0x8204, 0x0048, - 0x4990, 0x730c, 0xa384, 0x00ff, 0x0040, 0x4990, 0x1078, 0x248c, - 0x7007, 0x0012, 0x7000, 0xa084, 0x0001, 0x00c0, 0x49aa, 0x7008, - 0xa084, 0x01e0, 0x00c0, 0x49aa, 0x7310, 0x7014, 0xa305, 0x0040, - 0x49aa, 0x710c, 0xa184, 0x0300, 0x00c0, 0x49aa, 0xa184, 0x00ff, - 0x00c0, 0x4957, 0x7007, 0x0012, 0x7007, 0x0008, 0x7004, 0xa084, - 0x0008, 0x00c0, 0x49ae, 0x7007, 0x0012, 0x7108, 0x8103, 0x0048, - 0x49b3, 0x7003, 0x0000, 0x2049, 0x0000, 0x007c, 0x107e, 0x007e, - 0x127e, 0x157e, 0x2091, 0x2200, 0x7108, 0x1078, 0x49ce, 0x157f, - 0x127f, 0x2091, 0x8001, 0x007f, 0x107f, 0x007c, 0x7204, 0x7500, - 0x730c, 0xa384, 0x0300, 0x00c0, 0x49f5, 0xa184, 0x01e0, 0x00c0, - 0x4a19, 0x7108, 0xa184, 0x01e0, 0x00c0, 0x4a19, 0x2001, 0x04fd, - 0x2004, 0xa082, 0x0005, 0x00c8, 0x49e9, 0xa184, 0x4000, 0x00c0, - 0x49d9, 0xa184, 0x0007, 0x0079, 0x49ed, 0x49f7, 0x4a09, 0x49f5, - 0x4a09, 0x49f5, 0x4a55, 0x49f5, 0x4a53, 0x1078, 0x248c, 0x7004, - 0xa084, 0x0010, 0xa085, 0x0002, 0x7006, 0x8aff, 0x00c0, 0x4a04, - 0x2049, 0x0000, 0x0078, 0x4a08, 0x1078, 0x4c18, 0x00c0, 0x4a04, - 0x007c, 0x7004, 0xa084, 0x0010, 0xa085, 0x0002, 0x7006, 0x8aff, - 0x00c0, 0x4a14, 0x0078, 0x4a18, 0x1078, 0x4c18, 0x00c0, 0x4a14, - 0x007c, 0x7007, 0x0012, 0x7108, 0x00e0, 0x4a1c, 0x2091, 0x6000, - 0x00e0, 0x4a20, 0x2091, 0x6000, 0x7007, 0x0012, 0x7007, 0x0008, - 0x7004, 0xa084, 0x0008, 0x00c0, 0x4a28, 0x7007, 0x0012, 0x7108, - 0x8103, 0x0048, 0x4a2d, 0x7003, 0x0000, 0x7000, 0xa005, 0x00c0, - 0x4a41, 0x7004, 0xa005, 0x00c0, 0x4a41, 0x700c, 0xa005, 0x0040, - 0x4a43, 0x0078, 0x4a24, 0x2049, 0x0000, 0x1078, 0x38d7, 0x6818, - 0xa084, 0x8000, 0x0040, 0x4a4e, 0x681b, 0x0002, 0x007c, 0x1078, - 0x248c, 0x1078, 0x248c, 0x1078, 0x4ab1, 0x7210, 0x7114, 0x700c, - 0xa09c, 0x00ff, 0x2800, 0xa300, 0xa211, 0xa189, 0x0000, 0x1078, - 0x4ab1, 0x2704, 0x2c58, 0xac60, 0x6308, 0x2200, 0xa322, 0x630c, - 0x2100, 0xa31b, 0x2400, 0xa305, 0x0040, 0x4a78, 0x00c8, 0x4a78, - 0x8412, 0x8210, 0x830a, 0xa189, 0x0000, 0x2b60, 0x0078, 0x4a5f, - 0x2b60, 0x8a07, 0x007e, 0x6004, 0xa084, 0x0008, 0x0040, 0x4a84, - 0xa7ba, 0x4917, 0x0078, 0x4a86, 0xa7ba, 0x490f, 0x007f, 0xa73d, - 0x2c00, 0x6886, 0x6f8a, 0x6c92, 0x6b8e, 0x7007, 0x0012, 0x1078, - 0x4957, 0x007c, 0x8738, 0x2704, 0xa005, 0x00c0, 0x4aa5, 0x609c, - 0xa005, 0x0040, 0x4aae, 0x2060, 0x6004, 0xa084, 0x000f, 0xa080, - 0x491d, 0x203c, 0x87fb, 0x1040, 0x248c, 0x8a51, 0x0040, 0x4aad, - 0x7008, 0xa084, 0x0003, 0xa086, 0x0003, 0x007c, 0x2051, 0x0000, - 0x007c, 0x8a50, 0x8739, 0x2704, 0xa004, 0x00c0, 0x4ac5, 0x6000, - 0xa064, 0x00c0, 0x4abc, 0x2d60, 0x6004, 0xa084, 0x000f, 0xa080, - 0x492d, 0x203c, 0x87fb, 0x1040, 0x248c, 0x007c, 0x127e, 0x0d7e, - 0x2091, 0x2200, 0x0d7f, 0x6884, 0x2060, 0x6888, 0x6b8c, 0x6c90, - 0x8057, 0xaad4, 0x00ff, 0xa084, 0x00ff, 0x007e, 0x6804, 0xa084, - 0x0008, 0x007f, 0x0040, 0x4ae0, 0xa0b8, 0x4917, 0x0078, 0x4ae2, - 0xa0b8, 0x490f, 0x7e08, 0xa6b5, 0x000c, 0x6904, 0xa18c, 0x00ff, - 0xa186, 0x0007, 0x0040, 0x4af0, 0xa18e, 0x000f, 0x00c0, 0x4af9, - 0x681c, 0xa084, 0x0040, 0x0040, 0x4b00, 0xa6b5, 0x0001, 0x0078, - 0x4b00, 0x681c, 0xa084, 0x0040, 0x0040, 0x4b00, 0xa6b5, 0x0001, - 0x7007, 0x0004, 0x7004, 0xa084, 0x0004, 0x00c0, 0x4b02, 0x2400, - 0xa305, 0x00c0, 0x4b0d, 0x0078, 0x4b33, 0x2c58, 0x2704, 0x6104, - 0xac60, 0x6000, 0xa400, 0x701a, 0x6004, 0xa301, 0x701e, 0xa184, - 0x0008, 0x0040, 0x4b23, 0x6010, 0xa081, 0x0000, 0x7022, 0x6014, - 0xa081, 0x0000, 0x7026, 0x6208, 0x2400, 0xa202, 0x7012, 0x620c, - 0x2300, 0xa203, 0x7016, 0x7602, 0x7007, 0x0001, 0x2b60, 0x1078, - 0x4a92, 0x0078, 0x4b35, 0x1078, 0x4c18, 0x00c0, 0x4b33, 0x127f, - 0x2000, 0x007c, 0x127e, 0x0d7e, 0x2091, 0x2200, 0x0d7f, 0x7007, - 0x0004, 0x7004, 0xa084, 0x0004, 0x00c0, 0x4b41, 0x7003, 0x0008, - 0x127f, 0x2000, 0x007c, 0x127e, 0x0d7e, 0x2091, 0x2200, 0x0d7f, - 0x2049, 0x4b4b, 0x7007, 0x0004, 0x7004, 0xa084, 0x0004, 0x00c0, - 0x4b54, 0x7e08, 0xa6b5, 0x000c, 0x6904, 0xa18c, 0x00ff, 0xa186, - 0x0007, 0x0040, 0x4b67, 0xa18e, 0x000f, 0x00c0, 0x4b72, 0x681c, - 0xa084, 0x0040, 0x0040, 0x4b6e, 0xa6b5, 0x0001, 0x6840, 0x2050, - 0x0078, 0x4b7b, 0x681c, 0xa084, 0x0020, 0x00c0, 0x4b79, 0xa6b5, - 0x0001, 0x6828, 0x2050, 0x2d60, 0x6004, 0xa0bc, 0x000f, 0xa7b8, - 0x491d, 0x273c, 0x87fb, 0x00c0, 0x4b8f, 0x0048, 0x4b89, 0x1078, - 0x248c, 0x689c, 0xa065, 0x0040, 0x4b93, 0x0078, 0x4b7c, 0x1078, - 0x4c18, 0x00c0, 0x4b8f, 0x127f, 0x2000, 0x007c, 0x127e, 0x007e, - 0x017e, 0x0d7e, 0x2091, 0x2200, 0x0d7f, 0x037f, 0x047f, 0x7e08, - 0xa6b5, 0x000c, 0x6904, 0xa18c, 0x00ff, 0xa186, 0x0007, 0x0040, - 0x4bad, 0xa18e, 0x000f, 0x00c0, 0x4bb6, 0x681c, 0xa084, 0x0040, - 0x0040, 0x4bbd, 0xa6b5, 0x0001, 0x0078, 0x4bbd, 0x681c, 0xa084, - 0x0040, 0x0040, 0x4bbd, 0xa6b5, 0x0001, 0x2049, 0x4b96, 0x017e, - 0x6904, 0xa18c, 0x00ff, 0xa186, 0x0007, 0x0040, 0x4bcb, 0xa18e, - 0x000f, 0x00c0, 0x4bce, 0x6840, 0x0078, 0x4bcf, 0x6828, 0x017f, - 0xa055, 0x0040, 0x4c15, 0x2d70, 0x2e60, 0x7004, 0xa0bc, 0x000f, - 0xa7b8, 0x491d, 0x273c, 0x87fb, 0x00c0, 0x4be9, 0x0048, 0x4be2, - 0x1078, 0x248c, 0x709c, 0xa075, 0x2060, 0x0040, 0x4c15, 0x0078, - 0x4bd5, 0x2704, 0xae68, 0x6808, 0xa422, 0x680c, 0xa31b, 0x0048, - 0x4c02, 0x8a51, 0x00c0, 0x4bf6, 0x1078, 0x248c, 0x8738, 0x2704, - 0xa005, 0x00c0, 0x4bea, 0x709c, 0xa075, 0x2060, 0x0040, 0x4c15, - 0x0078, 0x4bd5, 0x8422, 0x8420, 0x831a, 0xa399, 0x0000, 0x6908, - 0x2400, 0xa122, 0x690c, 0x2300, 0xa11b, 0x00c8, 0x4c11, 0x1078, - 0x248c, 0x2071, 0x0020, 0x0078, 0x4b00, 0x127f, 0x2000, 0x007c, - 0x7008, 0xa084, 0x0003, 0xa086, 0x0003, 0x0040, 0x4c40, 0x2704, - 0xac08, 0x2104, 0x701a, 0x8108, 0x2104, 0x701e, 0x8108, 0x2104, - 0x7012, 0x8108, 0x2104, 0x7016, 0x6004, 0xa084, 0x0008, 0x0040, - 0x4c37, 0x8108, 0x2104, 0x7022, 0x8108, 0x2104, 0x7026, 0x7602, - 0x7004, 0xa084, 0x0010, 0xa085, 0x0001, 0x7006, 0x1078, 0x4a92, - 0x007c, 0x127e, 0x007e, 0x0d7e, 0x2091, 0x2200, 0x2049, 0x4c41, - 0x0d7f, 0x087f, 0x7108, 0xa184, 0x0003, 0x00c0, 0x4c6b, 0x017e, - 0x6904, 0xa18c, 0x00ff, 0xa186, 0x0007, 0x0040, 0x4c5b, 0xa18e, - 0x000f, 0x00c0, 0x4c5e, 0x6840, 0x0078, 0x4c5f, 0x6828, 0x017f, - 0xa005, 0x0040, 0x4c79, 0x0078, 0x489e, 0x0020, 0x4c6b, 0x1078, - 0x4a55, 0x0078, 0x4c79, 0x00a0, 0x4c72, 0x7108, 0x1078, 0x49ce, - 0x0078, 0x4c4a, 0x7007, 0x0010, 0x00a0, 0x4c74, 0x7108, 0x1078, - 0x49ce, 0x7008, 0xa086, 0x0008, 0x00c0, 0x4c4a, 0x7000, 0xa005, - 0x00c0, 0x4c4a, 0x7003, 0x0000, 0x2049, 0x0000, 0x127f, 0x2000, - 0x007c, 0x127e, 0x147e, 0x137e, 0x157e, 0x0c7e, 0x0d7e, 0x2091, - 0x2200, 0x0d7f, 0x2049, 0x4c89, 0xad80, 0x0011, 0x20a0, 0x2099, - 0x0031, 0x700c, 0xa084, 0x00ff, 0x682a, 0x7007, 0x0008, 0x7007, - 0x0002, 0x7003, 0x0001, 0x0040, 0x4ca8, 0x8000, 0x80ac, 0x53a5, - 0x7007, 0x0004, 0x7004, 0xa084, 0x0004, 0x00c0, 0x4caa, 0x0c7f, - 0x2049, 0x0000, 0x7003, 0x0000, 0x157f, 0x137f, 0x147f, 0x127f, - 0x2000, 0x007c, 0x2091, 0x6000, 0x2091, 0x8000, 0x78cc, 0xa005, - 0x0040, 0x4cd1, 0x7994, 0x70d0, 0xa106, 0x00c0, 0x4cd1, 0x7804, - 0xa005, 0x0040, 0x4cd1, 0x7807, 0x0000, 0x0068, 0x4cd1, 0x2091, - 0x4080, 0x7820, 0x8001, 0x7822, 0x00c0, 0x4d2c, 0x7824, 0x7822, - 0x2069, 0x5240, 0x6800, 0xa084, 0x0007, 0x0040, 0x4cef, 0xa086, - 0x0002, 0x0040, 0x4cef, 0x6834, 0xa00d, 0x0040, 0x4cef, 0x2104, - 0xa005, 0x0040, 0x4cef, 0x8001, 0x200a, 0x0040, 0x4dd4, 0x7848, - 0xa005, 0x0040, 0x4cfd, 0x8001, 0x784a, 0x00c0, 0x4cfd, 0x2009, - 0x0102, 0x6844, 0x200a, 0x1078, 0x226f, 0x6890, 0xa005, 0x0040, - 0x4d09, 0x8001, 0x6892, 0x00c0, 0x4d09, 0x686f, 0x0000, 0x6873, - 0x0001, 0x2061, 0x5500, 0x20a9, 0x0100, 0x2009, 0x0002, 0x6034, - 0xa005, 0x0040, 0x4d1f, 0x8001, 0x6036, 0x00c0, 0x4d1f, 0x6010, - 0xa005, 0x0040, 0x4d1f, 0x017e, 0x1078, 0x226f, 0x017f, 0xace0, - 0x0010, 0x0070, 0x4d25, 0x0078, 0x4d0f, 0x8109, 0x0040, 0x4d2c, - 0x20a9, 0x0100, 0x0078, 0x4d0f, 0x1078, 0x4d39, 0x1078, 0x4d5e, - 0x2009, 0x5251, 0x2104, 0x2009, 0x0102, 0x200a, 0x2091, 0x8001, - 0x007c, 0x7834, 0x8001, 0x7836, 0x00c0, 0x4d5d, 0x7838, 0x7836, - 0x2091, 0x8000, 0x7844, 0xa005, 0x00c0, 0x4d48, 0x2001, 0x0101, - 0x8001, 0x7846, 0xa080, 0x7500, 0x2040, 0x2004, 0xa065, 0x0040, - 0x4d5d, 0x6024, 0xa005, 0x0040, 0x4d59, 0x8001, 0x6026, 0x0040, - 0x4d8d, 0x6000, 0x2c40, 0x0078, 0x4d4e, 0x007c, 0x7828, 0x8001, - 0x782a, 0x00c0, 0x4d8c, 0x782c, 0x782a, 0x7830, 0xa005, 0x00c0, - 0x4d6b, 0x2001, 0x0200, 0x8001, 0x7832, 0x8003, 0x8003, 0x8003, - 0x8003, 0xa090, 0x5500, 0xa298, 0x0002, 0x2304, 0xa084, 0x0008, - 0x0040, 0x4d8c, 0xa290, 0x0009, 0x2204, 0xa005, 0x0040, 0x4d84, - 0x8001, 0x2012, 0x00c0, 0x4d8c, 0x2304, 0xa084, 0xfff7, 0xa085, - 0x0080, 0x201a, 0x1078, 0x226f, 0x007c, 0x2069, 0x5240, 0x6800, - 0xa005, 0x0040, 0x4d97, 0x6848, 0xac06, 0x0040, 0x4dd4, 0x601b, - 0x0006, 0x60b4, 0xa084, 0x3f00, 0x601e, 0x6020, 0xa084, 0x00ff, - 0xa085, 0x0060, 0x6022, 0x6000, 0x2042, 0x6714, 0x6f82, 0x1078, - 0x19c5, 0x6818, 0xa005, 0x0040, 0x4daf, 0x8001, 0x681a, 0x6808, - 0xa084, 0xffef, 0x680a, 0x6810, 0x8001, 0x00d0, 0x4db9, 0x1078, - 0x248c, 0x6812, 0x602f, 0x0000, 0x6033, 0x0000, 0x2c68, 0x1078, - 0x1cdc, 0x2069, 0x5240, 0x7944, 0xa184, 0x0100, 0x2001, 0x0006, - 0x686e, 0x00c0, 0x4dcf, 0x6986, 0x2001, 0x0004, 0x686e, 0x1078, - 0x226a, 0x2091, 0x8001, 0x007c, 0x2069, 0x0100, 0x2009, 0x5240, - 0x2104, 0xa084, 0x0007, 0x0040, 0x4e30, 0xa086, 0x0007, 0x00c0, - 0x4dea, 0x0d7e, 0x2009, 0x5252, 0x216c, 0x1078, 0x3b1c, 0x0d7f, - 0x0078, 0x4e30, 0x2009, 0x5252, 0x2164, 0x1078, 0x2437, 0x601b, - 0x0006, 0x6858, 0xa084, 0x3f00, 0x601e, 0x6020, 0xa084, 0x00ff, - 0xa085, 0x0048, 0x6022, 0x602f, 0x0000, 0x6033, 0x0000, 0x6830, - 0xa084, 0x0040, 0x0040, 0x4e24, 0x684b, 0x0004, 0x20a9, 0x0014, - 0x6848, 0xa084, 0x0004, 0x0040, 0x4e11, 0x0070, 0x4e11, 0x0078, - 0x4e08, 0x684b, 0x0009, 0x20a9, 0x0014, 0x6848, 0xa084, 0x0001, - 0x0040, 0x4e1e, 0x0070, 0x4e1e, 0x0078, 0x4e15, 0x20a9, 0x00fa, - 0x0070, 0x4e24, 0x0078, 0x4e20, 0x6808, 0xa084, 0xfffd, 0x680a, - 0x681b, 0x0048, 0x2009, 0x525b, 0x200b, 0x0007, 0x784c, 0x784a, - 0x2091, 0x8001, 0x007c, 0x2079, 0x5200, 0x1078, 0x4e5e, 0x1078, - 0x4e42, 0x1078, 0x4e50, 0x7833, 0x0000, 0x7847, 0x0000, 0x784b, - 0x0000, 0x007c, 0x2019, 0x0003, 0x2011, 0x5246, 0x2204, 0xa086, - 0x003c, 0x0040, 0x4e4d, 0x2019, 0x0002, 0x7b2a, 0x7b2e, 0x007c, - 0x2019, 0x0039, 0x2011, 0x5246, 0x2204, 0xa086, 0x003c, 0x0040, - 0x4e5b, 0x2019, 0x0027, 0x7b36, 0x7b3a, 0x007c, 0x2019, 0x3971, - 0x2011, 0x5246, 0x2204, 0xa086, 0x003c, 0x0040, 0x4e69, 0x2019, - 0x2626, 0x7b22, 0x7b26, 0x783f, 0x0000, 0x7843, 0x000a, 0x007c, - 0x0020, 0x002b, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, - 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, - 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, - 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, - 0x0000, 0x0020, 0x0000, 0x0014, 0x0014, 0x9849, 0x0014, 0x0014, - 0x0014, 0x0014, 0x0014, 0x0014, 0x0014, 0x0080, 0x000f, 0x0000, - 0x0201, 0x0604, 0x0c08, 0x2120, 0x4022, 0xf880, 0x0018, 0x300b, - 0xa201, 0x0014, 0xa200, 0x0014, 0xa200, 0x0214, 0x0000, 0x006c, - 0x0002, 0x0014, 0x98cd, 0x009e, 0x0093, 0xa202, 0x8838, 0x3806, - 0x8839, 0x20c3, 0x0864, 0x9885, 0x28c1, 0x9cae, 0xa203, 0x300c, - 0x2846, 0x8161, 0x846a, 0x8300, 0x1856, 0x883a, 0x9865, 0x28f2, - 0x9c91, 0x9858, 0x300c, 0x28e1, 0x9c91, 0x2802, 0xa206, 0x64c3, - 0x282e, 0xa207, 0x64a0, 0x6de0, 0x67a0, 0x6fc0, 0x1814, 0x883b, - 0x7824, 0x68c1, 0x7864, 0x883e, 0x9879, 0x8576, 0x8677, 0x206b, - 0x28c1, 0x9cae, 0x2044, 0x2103, 0x20a2, 0x2081, 0x9865, 0xa209, - 0x2901, 0x988d, 0x0014, 0xa205, 0xa300, 0x1872, 0x879a, 0x883c, - 0x1fe2, 0xc601, 0xa20a, 0x856e, 0x0704, 0x9c91, 0x0014, 0xa204, - 0xa300, 0x3009, 0x19e2, 0xf864, 0x856e, 0x883f, 0x08e6, 0x9891, - 0xf881, 0x988c, 0xc801, 0x0014, 0xf8c1, 0x0016, 0x85b2, 0x80f0, - 0x9532, 0xfb02, 0x1de2, 0x0014, 0x8532, 0xf241, 0x0014, 0x1de2, - 0x84a8, 0xd7a0, 0x1fe6, 0x0014, 0xa208, 0x6043, 0x8008, 0x1dc1, - 0x0016, 0x8300, 0x8160, 0x842a, 0xf041, 0x3008, 0x84a8, 0x11d6, - 0x7042, 0x20dd, 0x0011, 0x20d5, 0x8822, 0x0016, 0x8000, 0x2847, - 0x1011, 0x98c0, 0x8000, 0xa000, 0x2802, 0x1011, 0x98c6, 0x9865, - 0x283e, 0x1011, 0x98ca, 0xa20b, 0x0017, 0x300c, 0xa300, 0x1de2, - 0xdb81, 0x0014, 0x0210, 0x98d7, 0x0014, 0x26e0, 0x873a, 0xfb02, - 0x19f2, 0x1fe2, 0x0014, 0xa20d, 0x3806, 0x0210, 0x9cb3, 0x0704, - 0x0000, 0x006c, 0x0002, 0x984f, 0x0014, 0x009e, 0x00a0, 0x0017, - 0x60ff, 0x300c, 0x8720, 0xa211, 0x9cd0, 0x8772, 0x8837, 0x2101, - 0x987a, 0x10d2, 0x78e2, 0x9cd3, 0x9859, 0xd984, 0xf0e2, 0xf0a1, - 0x98cd, 0x0014, 0x8831, 0xd166, 0x8830, 0x800f, 0x9401, 0xb520, - 0xc802, 0x8820, 0x987a, 0x2301, 0x987a, 0x10d2, 0x78e4, 0x9cd3, - 0x8821, 0x8820, 0x9859, 0xf123, 0xf142, 0xf101, 0x98c6, 0x10d2, - 0x70f6, 0x8832, 0x8203, 0x870c, 0xd99e, 0x6001, 0x0014, 0x6845, - 0x0214, 0xa21b, 0x9cd0, 0x2001, 0x98c5, 0x8201, 0x1852, 0xd184, - 0xd163, 0x8834, 0x8001, 0x988d, 0x3027, 0x84a8, 0x1a56, 0x8833, - 0x0014, 0xa218, 0x6981, 0x9cbc, 0x6926, 0x6902, 0x1a34, 0x9899, - 0x1a14, 0x7021, 0x0014, 0xa300, 0x6141, 0x6964, 0x8010, 0x8592, - 0x8026, 0x84b9, 0x69e4, 0x8023, 0x16e1, 0x8001, 0x10f1, 0x6946, - 0xa213, 0x1462, 0xa213, 0x8000, 0x16e1, 0x98b5, 0x6969, 0xa214, - 0x61c2, 0x8002, 0x14e1, 0x8004, 0x16e1, 0x0101, 0x300a, 0x8827, - 0x0014, 0xa217, 0x9cbc, 0x0014, 0xa300, 0x8181, 0x842a, 0x84a8, - 0x1ce6, 0x882c, 0x0016, 0xa212, 0x9cd0, 0x10d2, 0x70e4, 0x0004, - 0x8007, 0x9424, 0xcc1a, 0x9cd3, 0x98c5, 0x8827, 0x300a, 0x0013, - 0x8000, 0x84a4, 0x0016, 0x11c2, 0x211e, 0x870e, 0xa21d, 0x0014, - 0x878e, 0x0016, 0xa21c, 0x1035, 0x9891, 0xa210, 0xa000, 0x8010, - 0x8592, 0x853b, 0xd044, 0x8022, 0x3807, 0x84bb, 0x98ea, 0x8021, - 0x3807, 0x84b9, 0x300c, 0x817e, 0x872b, 0x8772, 0x9891, 0x0000, - 0x0020, 0x002b, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, - 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, - 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, - 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, - 0x0000, 0x0020, 0x0000, 0x0014, 0x0014, 0x9849, 0x0014, 0x0014, - 0x98e2, 0x98cd, 0x0014, 0x0014, 0x0014, 0x0080, 0x0137, 0x0000, - 0x0201, 0x0604, 0x0c08, 0x2120, 0x4022, 0xf880, 0x0018, 0x300b, - 0xa201, 0x0014, 0xa200, 0x0014, 0xa200, 0x0214, 0xa202, 0x8838, - 0x3806, 0x8839, 0x20c3, 0x0864, 0xa82f, 0x28c1, 0x9cae, 0xa203, - 0x300c, 0x2846, 0x8161, 0x846a, 0x8300, 0x1856, 0x883a, 0xa804, - 0x28f2, 0x9c91, 0xa8f4, 0x300c, 0x28e1, 0x9c91, 0x2802, 0xa206, - 0x64c3, 0x282e, 0xa207, 0x64a0, 0x6de0, 0x67a0, 0x6fc0, 0x1814, - 0x883b, 0x7824, 0x68c1, 0x7864, 0x883e, 0xa802, 0x8576, 0x8677, - 0x206b, 0x28c1, 0x9cae, 0x2044, 0x2103, 0x20a2, 0x2081, 0xa8e4, - 0xa209, 0x2901, 0xa809, 0x0014, 0xa205, 0xa300, 0x1872, 0x879a, - 0x883c, 0x1fe2, 0xc601, 0xa20a, 0x856e, 0x0704, 0x9c91, 0x0014, - 0xa204, 0xa300, 0x3009, 0x19e2, 0xf864, 0x856e, 0x883f, 0x08e6, - 0xa8f7, 0xf881, 0xa8f0, 0xc801, 0x0014, 0xf8c1, 0x0016, 0x85b2, - 0x80f0, 0x9532, 0xfb02, 0x1de2, 0x0014, 0x8532, 0xf241, 0x0014, - 0x1de2, 0x84a8, 0xd7a0, 0x1fe6, 0x0014, 0xa208, 0x6043, 0x8008, - 0x1dc1, 0x0016, 0x8300, 0x8160, 0x842a, 0xf041, 0x3008, 0x84a8, - 0x11d6, 0x7042, 0x20dd, 0x0011, 0x20d5, 0x8822, 0x0016, 0x8000, - 0x2847, 0x1011, 0xa8fc, 0x8000, 0xa000, 0x2802, 0x1011, 0xa8fd, - 0xa89b, 0x283e, 0x1011, 0xa8fd, 0xa20b, 0x0017, 0x300c, 0xa300, - 0x1de2, 0xdb81, 0x0014, 0x0210, 0xa801, 0x0014, 0x26e0, 0x873a, - 0xfb02, 0x19f2, 0x1fe2, 0x0014, 0xa20d, 0x3806, 0x0210, 0x9cb3, - 0x0704, 0x0017, 0x60ff, 0x300c, 0x8720, 0xa211, 0x9d63, 0x8772, - 0x8837, 0x2101, 0xa821, 0x10d2, 0x78e2, 0x9d66, 0xa8fc, 0xd984, - 0xf0e2, 0xf0a1, 0xa86c, 0x0014, 0x8831, 0xd166, 0x8830, 0x800f, - 0x9401, 0xb520, 0xc802, 0x8820, 0xa80f, 0x2301, 0xa80d, 0x10d2, - 0x78e4, 0x9d66, 0x8821, 0x8820, 0xa8e6, 0xf123, 0xf142, 0xf101, - 0xa84f, 0x10d2, 0x70f6, 0x8832, 0x8203, 0x870c, 0xd99e, 0x6001, - 0x0014, 0x6845, 0x0214, 0xa21b, 0x9d63, 0x2001, 0xa840, 0x8201, - 0x1852, 0xd184, 0xd163, 0x8834, 0x8001, 0xa801, 0x3027, 0x84a8, - 0x1a56, 0x8833, 0x0014, 0xa218, 0x6981, 0x9d4f, 0x6926, 0x6902, - 0x1a34, 0xa801, 0x1a14, 0x7021, 0x0014, 0xa300, 0x6141, 0x6964, - 0x8010, 0x8592, 0x8026, 0x84b9, 0x69e4, 0x8023, 0x16e1, 0x8001, - 0x10f1, 0x6946, 0xa213, 0x1462, 0xa213, 0x8000, 0x16e1, 0xa807, - 0x6969, 0xa214, 0x61c2, 0x8002, 0x14e1, 0x8004, 0x16e1, 0x0101, - 0x300a, 0x8827, 0x0014, 0xa217, 0x9d4f, 0x0014, 0xa300, 0x8181, - 0x842a, 0x84a8, 0x1ce6, 0x882c, 0x0016, 0xa212, 0x9d63, 0x10d2, - 0x70e4, 0x0004, 0x8007, 0x9424, 0xcc1a, 0x9d66, 0xa8f8, 0x8827, - 0x300a, 0x0013, 0x8000, 0x84a4, 0x0016, 0x11c2, 0x211e, 0x870e, - 0xa21d, 0x0014, 0x878e, 0x0016, 0xa21c, 0x1035, 0xa8b4, 0xa210, - 0x3807, 0x300c, 0x817e, 0x872b, 0x8772, 0xa8ad, 0x0000, 0x0d0c -}; -static unsigned short risc_code_length01 = 0x4158; diff --git a/drivers/scsi/ql12160_fw.h b/drivers/scsi/ql12160_fw.h deleted file mode 100644 index d89dac0cc9d..00000000000 --- a/drivers/scsi/ql12160_fw.h +++ /dev/null @@ -1,1811 +0,0 @@ -/***************************************************************************** - * QLOGIC LINUX SOFTWARE - * - * QLogic ISP12160 device driver for Linux 2.2.x and 2.4.x - * Copyright (C) 2002 Qlogic Corporation (www.qlogic.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, 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. - * - *****************************************************************************/ - -/************************************************************************ - * --- ISP12160A Initiator Firmware --- * - * 32 LUN Support * - ************************************************************************/ - -/* - * Firmware Version 10.04.42 (15:44 Apr 18, 2003) - */ - -#ifdef UNIQUE_FW_NAME -static unsigned char fw12160i_version_str[] = {10,4,42}; -#else -static unsigned char firmware_version[] = {10,4,42}; -#endif - -#ifdef UNIQUE_FW_NAME -#define fw12160i_VERSION_STRING "10.04.42" -#else -#define FW_VERSION_STRING "10.04.42" -#endif - -#ifdef UNIQUE_FW_NAME -static unsigned short fw12160i_addr01 = 0x1000; -#else -static unsigned short risc_code_addr01 = 0x1000; -#endif - -#ifdef UNIQUE_FW_NAME -static unsigned short fw12160i_code01[] = { -#else -static unsigned short risc_code01[] = { -#endif - 0x0804, 0x1041, 0x0000, 0x36c9, 0x0000, 0x2043, 0x4f50, 0x5952, - 0x4947, 0x4854, 0x2031, 0x3939, 0x312c, 0x3139, 0x3932, 0x2c31, - 0x3939, 0x332c, 0x3139, 0x3934, 0x2051, 0x4c4f, 0x4749, 0x4320, - 0x434f, 0x5250, 0x4f52, 0x4154, 0x494f, 0x4e00, 0x2049, 0x5350, - 0x3132, 0x3136, 0x2046, 0x6972, 0x6d77, 0x6172, 0x6520, 0x2056, - 0x6572, 0x7369, 0x6f6e, 0x2031, 0x302e, 0x3034, 0x2020, 0x2043, - 0x7573, 0x746f, 0x6d65, 0x7220, 0x4e6f, 0x2e20, 0x3030, 0x2050, - 0x726f, 0x6475, 0x6374, 0x204e, 0x6f2e, 0x2020, 0x3030, 0x2020, - 0x2400, 0x20c9, 0x90ff, 0x2071, 0x0200, 0x70a0, 0x70a2, 0x2001, - 0x01ff, 0x2004, 0xd0fc, 0x1120, 0x2071, 0x0100, 0x70a0, 0x70a2, - 0x20c1, 0x0020, 0x2089, 0x1221, 0x2071, 0x0010, 0x70c3, 0x0004, - 0x70c7, 0x4953, 0x70cb, 0x5020, 0x70cf, 0x2020, 0x70d3, 0x000a, - 0x2001, 0x04fd, 0x2004, 0x70d6, 0x2009, 0xfeff, 0x2130, 0x2128, - 0xa1a2, 0x4700, 0x8424, 0x8424, 0x8424, 0x8424, 0x8424, 0x8424, - 0xa192, 0x9100, 0x2009, 0x0000, 0x2001, 0x0032, 0x080c, 0x1e05, - 0x2218, 0x2079, 0x4700, 0x2fa0, 0x2408, 0x2011, 0x0000, 0x20a9, - 0x0040, 0x42a4, 0x8109, 0x1dd8, 0x2009, 0xff00, 0x3400, 0xa102, - 0x0218, 0x0110, 0x20a8, 0x42a4, 0x781b, 0x0064, 0x7814, 0xc0cd, - 0xc0d5, 0x7816, 0x2071, 0x0200, 0x00d6, 0x2069, 0x4740, 0x080c, - 0x465c, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1130, 0x2069, 0x4780, - 0x2071, 0x0100, 0x080c, 0x465c, 0x7814, 0xc0d4, 0x7816, 0x00de, - 0x7eca, 0x7cc2, 0x7bc6, 0x7867, 0x0000, 0x7800, 0xc08d, 0x7802, - 0x2031, 0x0030, 0x78af, 0x0101, 0x7823, 0x0002, 0x7827, 0x0002, - 0x2009, 0x0002, 0x2069, 0x4740, 0x681b, 0x0003, 0x6823, 0x0007, - 0x6827, 0x00fa, 0x682b, 0x0008, 0x682f, 0x0028, 0x6837, 0x0006, - 0x6833, 0x0008, 0x683b, 0x0000, 0x8109, 0x0500, 0x68cf, 0x000a, - 0x68bf, 0x47c0, 0x2079, 0x4700, 0x68d3, 0x762d, 0x68c3, 0x4cc0, - 0x68c7, 0x4bc0, 0x68cb, 0x8cc0, 0x68a7, 0x8f44, 0x68ab, 0x8f49, - 0x68af, 0x8f44, 0x68b3, 0x8f44, 0x68a3, 0x0001, 0x2001, 0x01ff, - 0x2004, 0xd0fc, 0x11c8, 0x2069, 0x4780, 0x0870, 0x68cf, 0x000a, - 0x68bf, 0x49c0, 0x68d3, 0x7839, 0x68c3, 0x6cc0, 0x68c7, 0x4c40, - 0x68cb, 0x8dd0, 0x68a7, 0x8f49, 0x68ab, 0x8f4e, 0x68af, 0x8f49, - 0x68b3, 0x8f49, 0x68a3, 0x0001, 0x00e6, 0x2069, 0x4bc0, 0x2071, - 0x0200, 0x70ec, 0xd0e4, 0x2019, 0x1809, 0x2021, 0x0009, 0x1120, - 0x2019, 0x180c, 0x2021, 0x000c, 0x080c, 0x1d75, 0x2001, 0x01ff, - 0x2004, 0xd0fc, 0x1188, 0x2069, 0x4c40, 0x2071, 0x0100, 0x70ec, - 0xd0e4, 0x2019, 0x1809, 0x2021, 0x0009, 0x1120, 0x2019, 0x180c, - 0x2021, 0x000c, 0x080c, 0x1d75, 0x00ee, 0x2011, 0x0002, 0x2069, - 0x4cc0, 0x2009, 0x0002, 0x20a9, 0x0100, 0x6837, 0x0000, 0x680b, - 0x0040, 0x7bc8, 0xa386, 0xfeff, 0x1128, 0x6817, 0x0100, 0x681f, - 0x0064, 0x0020, 0x6817, 0x0064, 0x681f, 0x0002, 0xade8, 0x0010, - 0x1f04, 0x1135, 0x8109, 0x1d38, 0x2001, 0x01ff, 0x2004, 0xd0fc, - 0x1128, 0x8211, 0x0118, 0x2069, 0x6cc0, 0x08d8, 0x080c, 0x22f6, - 0x080c, 0x403d, 0x080c, 0x1b8c, 0x080c, 0x4615, 0x2091, 0x2200, - 0x2079, 0x4700, 0x2071, 0x0050, 0x2091, 0x2400, 0x2079, 0x4700, - 0x2071, 0x0020, 0x2091, 0x2600, 0x2079, 0x0200, 0x2071, 0x4740, - 0x2091, 0x2800, 0x2079, 0x0100, 0x2071, 0x4780, 0x2091, 0x2000, - 0x2079, 0x4700, 0x2071, 0x0010, 0x3200, 0xa085, 0x303d, 0x2090, - 0x2071, 0x0010, 0x70c3, 0x0000, 0x1004, 0x118c, 0x70c0, 0xa086, - 0x0002, 0x1110, 0x080c, 0x13ba, 0x2039, 0x0000, 0x080c, 0x12ab, - 0x78ac, 0xa005, 0x1180, 0x0e04, 0x119a, 0x786c, 0xa065, 0x0110, - 0x080c, 0x20a1, 0x080c, 0x1e26, 0x0e04, 0x11af, 0x786c, 0xa065, - 0x0110, 0x080c, 0x20a1, 0x0e04, 0x11af, 0x2009, 0x4747, 0x2011, - 0x4787, 0x2104, 0x220c, 0xa105, 0x0110, 0x080c, 0x1c9b, 0x2071, - 0x4740, 0x70a0, 0xa005, 0x01e8, 0x744c, 0xa485, 0x0000, 0x01c8, - 0x2079, 0x0200, 0x2091, 0x8000, 0x72d0, 0xa28c, 0x303d, 0x2190, - 0x080c, 0x274c, 0x2091, 0x8000, 0x2091, 0x303d, 0x0e04, 0x11d1, - 0x2079, 0x4700, 0x786c, 0xa065, 0x0120, 0x2071, 0x0010, 0x080c, - 0x20a1, 0x1d04, 0x11d9, 0x2079, 0x4700, 0x2071, 0x0010, 0x080c, - 0x4429, 0x2071, 0x4780, 0x70a0, 0xa005, 0x0188, 0x704c, 0xa025, - 0x0170, 0x2079, 0x0100, 0x2091, 0x8000, 0x72d0, 0xa28c, 0x303d, - 0x2190, 0x080c, 0x274c, 0x2091, 0x8000, 0x2091, 0x303d, 0x2079, - 0x4700, 0x2071, 0x0010, 0x0e04, 0x11fa, 0x786c, 0xa065, 0x0110, - 0x080c, 0x20a1, 0x1d04, 0x118e, 0x080c, 0x4429, 0x0804, 0x118e, - 0x3c00, 0xa084, 0x0007, 0x0002, 0x120c, 0x120c, 0x120e, 0x120e, - 0x1213, 0x1213, 0x1218, 0x1218, 0x080c, 0x2575, 0x2091, 0x2400, - 0x080c, 0x40d5, 0x0005, 0x2091, 0x2200, 0x080c, 0x40d5, 0x0005, - 0x2091, 0x2200, 0x080c, 0x40d5, 0x2091, 0x2400, 0x080c, 0x40d5, - 0x0005, 0x1241, 0x1241, 0x1242, 0x1242, 0x124d, 0x124d, 0x124d, - 0x124d, 0x1256, 0x1256, 0x1261, 0x1261, 0x124d, 0x124d, 0x124d, - 0x124d, 0x1270, 0x1270, 0x1270, 0x1270, 0x1270, 0x1270, 0x1270, - 0x1270, 0x1270, 0x1270, 0x1270, 0x1270, 0x1270, 0x1270, 0x1270, - 0x1270, 0x0cf8, 0x0006, 0x0106, 0x0126, 0x2091, 0x2800, 0x080c, - 0x2592, 0x012e, 0x010e, 0x000e, 0x000d, 0x0006, 0x0106, 0x0126, - 0x080c, 0x1200, 0x012e, 0x010e, 0x000e, 0x000d, 0x0006, 0x0106, - 0x0126, 0x2091, 0x2600, 0x080c, 0x2592, 0x012e, 0x010e, 0x000e, - 0x000d, 0x0006, 0x0106, 0x0126, 0x2091, 0x2600, 0x080c, 0x2592, - 0x2091, 0x2800, 0x080c, 0x2592, 0x012e, 0x010e, 0x000e, 0x000d, - 0x0006, 0x0106, 0x0126, 0x00d6, 0x00e6, 0x00f6, 0x2079, 0x4700, - 0x2071, 0x0200, 0x2069, 0x4740, 0x3d00, 0xd08c, 0x0130, 0x70ec, - 0xa084, 0x1c00, 0x78e2, 0x080c, 0x465c, 0x3d00, 0xd084, 0x0150, - 0x2069, 0x4780, 0x2071, 0x0100, 0x70ec, 0xa084, 0x1c00, 0x78e6, - 0x080c, 0x465c, 0x080c, 0x2526, 0x00fe, 0x00ee, 0x00de, 0x012e, - 0x010e, 0x000e, 0x000d, 0x7008, 0x800b, 0x1240, 0x7007, 0x0002, - 0xa08c, 0x01e0, 0x1120, 0xd09c, 0x0108, 0x0887, 0x0897, 0x70c3, - 0x4002, 0x0804, 0x13bd, 0x0e04, 0x131e, 0x2061, 0x0000, 0x6018, - 0xd084, 0x1904, 0x131e, 0x7828, 0xa005, 0x1120, 0x0004, 0x131f, - 0x0804, 0x131e, 0xd0fc, 0x0130, 0x0006, 0x080c, 0x1b29, 0x000e, - 0x0150, 0x0028, 0x0006, 0x080c, 0x1b1e, 0x000e, 0x0120, 0x2001, - 0x4007, 0x0804, 0x13bc, 0x7910, 0xd0fc, 0x1128, 0x2061, 0x4740, - 0xc19c, 0xc7fc, 0x0020, 0x2061, 0x4780, 0xc19d, 0xc7fd, 0x6060, - 0xa005, 0x1904, 0x131e, 0x7912, 0x607e, 0x7828, 0xc0fc, 0xa086, - 0x0018, 0x1120, 0x00c6, 0x080c, 0x1926, 0x00ce, 0x782b, 0x0000, - 0x6078, 0xa065, 0x01e0, 0x00c6, 0x609c, 0x080c, 0x1bf3, 0x00ce, - 0x609f, 0x0000, 0x080c, 0x1a60, 0x2009, 0x0018, 0x6087, 0x0103, - 0x7810, 0x0006, 0x84ff, 0x1110, 0x85ff, 0x0110, 0xc0c5, 0x7812, - 0x080c, 0x1b34, 0x000e, 0x7812, 0x1198, 0x080c, 0x1b7f, 0x7810, - 0xd09c, 0x1118, 0x2061, 0x4740, 0x0020, 0x2061, 0x4780, 0xc09c, - 0x7812, 0x607b, 0x0000, 0x60d0, 0xd0c4, 0x0130, 0xc0c4, 0x60d2, - 0x2001, 0x4005, 0x0804, 0x13bc, 0x0804, 0x13ba, 0x0005, 0xa006, - 0x70c2, 0x70c6, 0x70ca, 0x70ce, 0x70da, 0x70c0, 0xa03d, 0xa08a, - 0x0040, 0x1a04, 0x136c, 0x0002, 0x13ba, 0x1408, 0x13d6, 0x143c, - 0x1470, 0x1470, 0x13ce, 0x1a78, 0x147a, 0x13c8, 0x13da, 0x13db, - 0x13dc, 0x13dd, 0x1a7c, 0x13c8, 0x1487, 0x14db, 0x1941, 0x1a72, - 0x13de, 0x17c8, 0x17fe, 0x1830, 0x1876, 0x1785, 0x1792, 0x17a5, - 0x17b7, 0x15bf, 0x13c8, 0x150d, 0x1518, 0x1526, 0x1534, 0x154b, - 0x1559, 0x155c, 0x156e, 0x157c, 0x1586, 0x15a5, 0x15b1, 0x13c8, - 0x13c8, 0x13c8, 0x13c8, 0x15cc, 0x15dd, 0x15f7, 0x162b, 0x1654, - 0x1666, 0x1669, 0x1693, 0x16cc, 0x16de, 0x1753, 0x1763, 0x13c8, - 0x13c8, 0x13c8, 0x13c8, 0x1775, 0x2100, 0xa08a, 0x0040, 0x1a04, - 0x13c8, 0x0002, 0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x1a9e, - 0x1aa4, 0x13c8, 0x13c8, 0x13c8, 0x1aa8, 0x1ae8, 0x13c8, 0x13c8, - 0x13c8, 0x13c8, 0x1403, 0x146b, 0x1482, 0x14d6, 0x193c, 0x13c8, - 0x13c8, 0x190b, 0x13c8, 0x1aec, 0x1a90, 0x1a9a, 0x13c8, 0x13c8, - 0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x13c8, - 0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x13c8, - 0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x13c8, - 0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x13c8, - 0x13c8, 0x13c8, 0x72ca, 0x71c6, 0x2001, 0x4006, 0x0028, 0x73ce, - 0x72ca, 0x71c6, 0x2001, 0x4000, 0x70c2, 0x0e04, 0x13bd, 0x2061, - 0x0000, 0x601b, 0x0001, 0x2091, 0x5000, 0x2091, 0x4080, 0x0005, - 0x70c3, 0x4001, 0x0c90, 0x70c3, 0x4006, 0x0c78, 0x2099, 0x0041, - 0x20a1, 0x0041, 0x20a9, 0x0005, 0x53a3, 0x0c20, 0x70c4, 0x70c3, - 0x0004, 0x0807, 0x08f8, 0x08f0, 0x08e8, 0x08e0, 0x2091, 0x8000, - 0x70c3, 0x0004, 0x70c7, 0x4953, 0x70cb, 0x5020, 0x70cf, 0x2020, - 0x70d3, 0x000a, 0x2001, 0x0004, 0x70d6, 0x2079, 0x0000, 0x781b, - 0x0001, 0x2031, 0x0030, 0x2059, 0x1000, 0x2029, 0x041a, 0x2051, - 0x0445, 0x2061, 0x0447, 0x20c1, 0x0020, 0x2091, 0x5000, 0x2091, - 0x4080, 0x0804, 0x0418, 0x75d8, 0x74dc, 0x75da, 0x74de, 0x0018, - 0x2029, 0x0000, 0x2520, 0x71d0, 0x72c8, 0x73cc, 0x70c4, 0x20a0, - 0x2099, 0x0030, 0x7003, 0x0001, 0x7007, 0x0006, 0x731a, 0x721e, - 0x7422, 0x7526, 0x2021, 0x0040, 0x81ff, 0x0904, 0x13ba, 0xa182, - 0x0040, 0x1210, 0x2120, 0xa006, 0x2008, 0x8403, 0x7012, 0x7007, - 0x0004, 0x7007, 0x0001, 0x7008, 0xd0fc, 0x0de8, 0x7007, 0x0002, - 0xa084, 0x01e0, 0x0120, 0x70c3, 0x4002, 0x0804, 0x13bd, 0x24a8, - 0x53a5, 0x0c10, 0x0804, 0x13ba, 0x2029, 0x0000, 0x2520, 0x71d0, - 0x72c8, 0x73cc, 0x70c4, 0x2098, 0x20a1, 0x0030, 0x7003, 0x0000, - 0x7007, 0x0006, 0x731a, 0x721e, 0x7422, 0x7526, 0x2021, 0x0040, - 0x7007, 0x0006, 0x81ff, 0x0904, 0x13ba, 0xa182, 0x0040, 0x1210, - 0x2120, 0xa006, 0x2008, 0x8403, 0x7012, 0x24a8, 0x53a6, 0x7007, - 0x0001, 0x7008, 0xd0fc, 0x0de8, 0xa084, 0x01e0, 0x0d48, 0x70c3, - 0x4002, 0x0804, 0x13bd, 0x75d8, 0x74dc, 0x75da, 0x74de, 0x0878, - 0x71c4, 0x70c8, 0x2114, 0xa79e, 0x0004, 0x1108, 0x200a, 0x72ca, - 0x0804, 0x13b9, 0x70c7, 0x000a, 0x70cb, 0x0004, 0x70cf, 0x002a, - 0x0804, 0x13ba, 0x75d8, 0x76dc, 0x75da, 0x76de, 0x0018, 0x2029, - 0x0000, 0x2530, 0x70c4, 0x72c8, 0x73cc, 0x74d0, 0x70c6, 0x72ca, - 0x73ce, 0x74d2, 0xa005, 0x05e8, 0xa40a, 0x0108, 0x1240, 0x8001, - 0x7872, 0xa084, 0xfc00, 0x0138, 0x78ac, 0xc085, 0x78ae, 0x2001, - 0x4005, 0x0804, 0x13bc, 0x7b7e, 0x7a7a, 0x7e86, 0x7d82, 0x7c76, - 0xa48c, 0xff00, 0x0170, 0x8407, 0x8004, 0x8004, 0x810c, 0x810c, - 0x810f, 0xa118, 0xa291, 0x0000, 0xa6b1, 0x0000, 0xa581, 0x0000, - 0x0050, 0x8407, 0x8004, 0x8004, 0xa318, 0xa291, 0x0000, 0xa6b1, - 0x0000, 0xa581, 0x0000, 0x731a, 0x721e, 0x7622, 0x7026, 0xa605, - 0x0118, 0x7a10, 0xc2c5, 0x7a12, 0x78ac, 0xa084, 0xfffc, 0x78ae, - 0x0018, 0x78ac, 0xc085, 0x78ae, 0x0804, 0x13ba, 0x75d8, 0x76dc, - 0x75da, 0x76de, 0x0018, 0x2029, 0x0000, 0x2530, 0x70c4, 0x72c8, - 0x73cc, 0x74d4, 0x70c6, 0x72ca, 0x73ce, 0x74d6, 0xa005, 0x0500, - 0xa40a, 0x0110, 0x1a04, 0x13bc, 0x8001, 0x7892, 0xa084, 0xfc00, - 0x0138, 0x78ac, 0xc0c5, 0x78ae, 0x2001, 0x4005, 0x0804, 0x13bc, - 0x7a9a, 0x7b9e, 0x7da2, 0x7ea6, 0x2600, 0xa505, 0x0118, 0x7a10, - 0xc2c5, 0x7a12, 0x7c96, 0x78ac, 0xa084, 0xfcff, 0x78ae, 0x0018, - 0x78ac, 0xc0c5, 0x78ae, 0x0804, 0x13ba, 0x2009, 0x0000, 0x786c, - 0xa065, 0x0118, 0x8108, 0x6000, 0x0cd8, 0x7ac4, 0x0804, 0x13b8, - 0x2009, 0x4748, 0x210c, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1904, - 0x13b9, 0x2011, 0x4788, 0x2214, 0x0804, 0x13b8, 0x2009, 0x4749, - 0x210c, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1904, 0x13b9, 0x2011, - 0x4789, 0x2214, 0x0804, 0x13b8, 0x2061, 0x4740, 0x6128, 0x622c, - 0x8214, 0x8214, 0x8214, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1148, - 0x2061, 0x4780, 0x6328, 0x73da, 0x632c, 0x831c, 0x831c, 0x831c, - 0x73de, 0x0804, 0x13b8, 0x2009, 0x474c, 0x210c, 0x2001, 0x01ff, - 0x2004, 0xd0fc, 0x1904, 0x13b9, 0x2011, 0x478c, 0x2214, 0x0804, - 0x13b8, 0x7918, 0x0804, 0x13b9, 0x2009, 0x0202, 0x210c, 0xa18c, - 0x0f30, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1904, 0x13b9, 0x2011, - 0x0102, 0x2214, 0xa294, 0x0f30, 0x0804, 0x13b8, 0x2009, 0x474d, - 0x210c, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1904, 0x13b9, 0x2011, - 0x478d, 0x2214, 0x0804, 0x13b8, 0x7920, 0x2001, 0x01ff, 0x2004, - 0xd0fc, 0x1904, 0x13b9, 0x7a24, 0x0804, 0x13b8, 0x2011, 0x4c40, - 0x71c4, 0xd1fc, 0x1110, 0x2011, 0x4bc0, 0x8107, 0xa084, 0x000f, - 0x8003, 0x8003, 0x8003, 0xa268, 0x6a00, 0x6b08, 0x6c1c, 0x74da, - 0xd1fc, 0x1118, 0x2021, 0x023b, 0x0010, 0x2021, 0x013b, 0x2424, - 0xa4a4, 0x1c00, 0x74de, 0x0804, 0x13b7, 0x77c4, 0x080c, 0x1b9a, - 0x2091, 0x8000, 0x6b1c, 0x6a14, 0x2091, 0x8001, 0x2708, 0x0804, - 0x13b7, 0x2061, 0x4740, 0x6118, 0x2001, 0x01ff, 0x2004, 0xd0fc, - 0x1904, 0x13b9, 0x2061, 0x4780, 0x6218, 0x0804, 0x13b8, 0x77c4, - 0x080c, 0x1b9a, 0x2091, 0x8000, 0x6908, 0x6a18, 0x6b10, 0x77da, - 0x2091, 0x8001, 0x0804, 0x13b7, 0x71c4, 0x2110, 0xa294, 0x000f, - 0xa282, 0x0010, 0x1a04, 0x13b3, 0x080c, 0x23b4, 0xa384, 0x4000, - 0x0110, 0xa295, 0x0020, 0x0804, 0x13b7, 0x71c4, 0x2100, 0xc0bc, - 0xa082, 0x0010, 0x1a04, 0x13b3, 0xd1bc, 0x1120, 0x2011, 0x4748, - 0x2204, 0x0020, 0x2011, 0x4788, 0x2204, 0xc0bd, 0x0006, 0x2100, - 0xc0bc, 0x2012, 0x080c, 0x2358, 0x001e, 0x0804, 0x13b9, 0x71c4, - 0x2021, 0x4749, 0x2404, 0x70c6, 0x2019, 0x0000, 0x0030, 0x71c8, - 0x2021, 0x4789, 0x2404, 0x70ca, 0xc3fd, 0x2011, 0x1623, 0x20a9, - 0x0008, 0x2204, 0xa106, 0x0138, 0x8210, 0x1f04, 0x1609, 0x71c4, - 0x72c8, 0x0804, 0x13b2, 0xa292, 0x1623, 0x0026, 0x2122, 0x001e, - 0x080c, 0x236a, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1110, 0xd3fc, - 0x09f0, 0x0804, 0x13ba, 0x03e8, 0x00fa, 0x01f4, 0x02ee, 0x0004, - 0x0001, 0x0002, 0x0003, 0x2061, 0x4740, 0x6128, 0x622c, 0x8214, - 0x8214, 0x8214, 0x70c4, 0x602a, 0x70c8, 0x8003, 0x8003, 0x8003, - 0x602e, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x11a0, 0x0026, 0x0016, - 0x2061, 0x4780, 0x6128, 0x622c, 0x8214, 0x8214, 0x8214, 0x70d8, - 0x602a, 0x70dc, 0x8003, 0x8003, 0x8003, 0x602e, 0x71da, 0x72de, - 0x001e, 0x002e, 0x0804, 0x13b8, 0x2061, 0x4740, 0x6130, 0x70c4, - 0x6032, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1904, 0x13b9, 0x2061, - 0x4780, 0x6230, 0x70c8, 0x6032, 0x0804, 0x13b8, 0x7918, 0x0804, - 0x13b9, 0x71c4, 0xa184, 0xf0cf, 0x0148, 0x2001, 0x01ff, 0x2004, - 0xd0fc, 0x1904, 0x13b3, 0x72c8, 0x0804, 0x13b2, 0x2019, 0x0000, - 0x080c, 0x23a6, 0x0036, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x0118, - 0x001e, 0x0804, 0x13b9, 0x71c8, 0xa184, 0xf0cf, 0x0128, 0x000e, - 0x2110, 0x71c4, 0x0804, 0x13b2, 0xc3fd, 0x080c, 0x23a6, 0x2310, - 0x001e, 0x0804, 0x13b8, 0x71c4, 0xa182, 0x0010, 0x0248, 0x2001, - 0x01ff, 0x2004, 0xd0fc, 0x1904, 0x13b3, 0x72c8, 0x0804, 0x13b2, - 0x2011, 0x474d, 0x2204, 0x0006, 0x8104, 0x1208, 0x8108, 0x2112, - 0x2019, 0x0000, 0x080c, 0x2393, 0x2001, 0x01ff, 0x2004, 0xd0fc, - 0x0118, 0x001e, 0x0804, 0x13b9, 0x71c8, 0xa182, 0x0010, 0x0228, - 0x0006, 0x2110, 0x71c4, 0x0804, 0x13b2, 0x2011, 0x478d, 0x2204, - 0x0006, 0x8104, 0x1208, 0x8108, 0x2112, 0xc3fd, 0x080c, 0x2393, - 0x002e, 0x001e, 0x0804, 0x13b8, 0x71c4, 0x72c8, 0xa184, 0xfffd, - 0x1904, 0x13b2, 0xa284, 0xfffd, 0x1904, 0x13b2, 0x2100, 0x7920, - 0x7822, 0x2200, 0x7a24, 0x7826, 0x0804, 0x13b8, 0x2011, 0x4c40, - 0x71c4, 0xd1fc, 0x1110, 0x2011, 0x4bc0, 0x8107, 0xa084, 0x000f, - 0x8003, 0x8003, 0x8003, 0xa268, 0x72c8, 0x73cc, 0x74d8, 0x71c6, - 0x6800, 0x70ca, 0x73ce, 0x74da, 0x2091, 0x8000, 0x6a02, 0xd2ac, - 0x1118, 0x2021, 0x0000, 0x0090, 0xa484, 0x00ff, 0xa082, 0x0002, - 0x1a04, 0x174f, 0x843f, 0xa7bc, 0x00ff, 0x0140, 0xa786, 0x0002, - 0x1904, 0x174f, 0xa484, 0x00ff, 0x0904, 0x174f, 0x2061, 0x0200, - 0xd1fc, 0x0110, 0x2061, 0x0100, 0x2029, 0x0009, 0x2031, 0x0062, - 0x843f, 0xa7bc, 0x00ff, 0x0130, 0x8307, 0xa084, 0x00ff, 0x1110, - 0xa73d, 0x1138, 0x2041, 0x0019, 0xa384, 0x00ff, 0xa082, 0x001a, - 0x0210, 0xa4a4, 0x00ff, 0x8307, 0xa084, 0x00ff, 0x0188, 0xa842, - 0x02f0, 0xa086, 0x0010, 0x1120, 0xa39c, 0x00ff, 0xa39d, 0x0f00, - 0xa3bc, 0x00ff, 0x2500, 0xa702, 0x0290, 0x2600, 0xa702, 0x1278, - 0x2039, 0x003a, 0x6804, 0xa705, 0x6806, 0x6b0a, 0x6b0c, 0x73ce, - 0x681c, 0x70da, 0x6c1e, 0x2091, 0x8001, 0x0804, 0x13ba, 0x2091, - 0x8001, 0x0804, 0x13b4, 0x77c4, 0x080c, 0x1b9a, 0x2091, 0x8000, - 0x6a14, 0x6b1c, 0x2091, 0x8001, 0x70c8, 0x6816, 0x70cc, 0x681e, - 0x2708, 0x0804, 0x13b7, 0x70c4, 0x2061, 0x4740, 0x6118, 0x601a, - 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1904, 0x13b9, 0x70c8, 0x2061, - 0x4780, 0x6218, 0x601a, 0x0804, 0x13b8, 0x71c4, 0x72c8, 0x73cc, - 0xa182, 0x0010, 0x1a04, 0x13b3, 0x080c, 0x23d8, 0xa384, 0x4000, - 0x0110, 0xa295, 0x0020, 0x0804, 0x13b7, 0x77c4, 0x080c, 0x1b9a, - 0x2091, 0x8000, 0x6a08, 0xc28d, 0x6a0a, 0x2091, 0x8001, 0x2708, - 0x0804, 0x13b8, 0x77c4, 0x080c, 0x1b9a, 0x2091, 0x8000, 0x6a08, - 0xa294, 0xfff9, 0x6a0a, 0x6804, 0xa005, 0x0110, 0x080c, 0x22d5, - 0x2091, 0x8001, 0x2708, 0x0804, 0x13b8, 0x77c4, 0x080c, 0x1b9a, - 0x2091, 0x8000, 0x6a08, 0xc295, 0x6a0a, 0x6804, 0xa005, 0x0110, - 0x080c, 0x22d5, 0x2091, 0x8001, 0x2708, 0x0804, 0x13b8, 0x77c4, - 0x2041, 0x0001, 0x2049, 0x0005, 0x2051, 0x0020, 0x2091, 0x8000, - 0x080c, 0x1bb2, 0x2091, 0x8001, 0x2708, 0x6a08, 0x0804, 0x13b8, - 0x77c4, 0xd7fc, 0x0128, 0x080c, 0x1b29, 0x0138, 0x0804, 0x13bc, - 0x080c, 0x1b1e, 0x0110, 0x0804, 0x13bc, 0x73c8, 0x72cc, 0x77c6, - 0x73ca, 0x72ce, 0x080c, 0x1c2a, 0x11e8, 0x6818, 0xa005, 0x01a0, - 0x2708, 0x0076, 0x080c, 0x23f7, 0x007e, 0x1170, 0x2001, 0x0015, - 0xd7fc, 0x1118, 0x2061, 0x4740, 0x0018, 0xc0fd, 0x2061, 0x4780, - 0x782a, 0x2091, 0x8001, 0x0005, 0x2091, 0x8001, 0x2001, 0x4005, - 0x0804, 0x13bc, 0x2091, 0x8001, 0x0804, 0x13ba, 0x77c4, 0xd7fc, - 0x0128, 0x080c, 0x1b29, 0x0138, 0x0804, 0x13bc, 0x080c, 0x1b1e, - 0x0110, 0x0804, 0x13bc, 0x77c6, 0x2041, 0x0021, 0x2049, 0x0005, - 0x2051, 0x0020, 0x2091, 0x8000, 0x080c, 0x1bb2, 0x2009, 0x0016, - 0xd7fc, 0x1118, 0x2061, 0x4740, 0x0018, 0x2061, 0x4780, 0xc1fd, - 0x6063, 0x0003, 0x607b, 0x0000, 0x6772, 0x607f, 0x000f, 0x792a, - 0x61d0, 0xc1c4, 0x61d2, 0x080c, 0x22d5, 0x2091, 0x8001, 0x0005, - 0x77c8, 0x77ca, 0x77c4, 0x77c6, 0xd7fc, 0x0128, 0x080c, 0x1b29, - 0x0138, 0x0804, 0x13bc, 0x080c, 0x1b1e, 0x0110, 0x0804, 0x13bc, - 0xa7bc, 0xff00, 0x2091, 0x8000, 0x2009, 0x0017, 0xd7fc, 0x1118, - 0x2061, 0x4740, 0x0018, 0x2061, 0x4780, 0xc1fd, 0x607b, 0x0000, - 0x6063, 0x0002, 0x6772, 0x607f, 0x000f, 0x792a, 0x61d0, 0xc1c4, - 0x61d2, 0x080c, 0x22d5, 0x2091, 0x8001, 0x2041, 0x0021, 0x2049, - 0x0005, 0x2051, 0x0010, 0x2091, 0x8000, 0x70c8, 0xa005, 0x0118, - 0x60d0, 0xc0fd, 0x60d2, 0x080c, 0x1bb2, 0x70c8, 0x6836, 0x8738, - 0xa784, 0x001f, 0x1dc0, 0x2091, 0x8001, 0x0005, 0x2019, 0x0000, - 0x72c8, 0xd284, 0x0128, 0x080c, 0x1b29, 0x0138, 0x0804, 0x13bc, - 0x080c, 0x1b1e, 0x0110, 0x0804, 0x13bc, 0x72c8, 0x72ca, 0x78ac, - 0xa084, 0x0003, 0x1518, 0x2039, 0x0000, 0xd284, 0x0108, 0xc7fd, - 0x2041, 0x0021, 0x2049, 0x0004, 0x2051, 0x0008, 0x080c, 0x1b9a, - 0x2091, 0x8000, 0x6808, 0xc0d4, 0xa80d, 0x690a, 0x6837, 0x0000, - 0x2091, 0x8001, 0x8738, 0xa784, 0x001f, 0x1d80, 0xa7bc, 0xff00, - 0x873f, 0x8738, 0x873f, 0xa784, 0x0f00, 0x1d40, 0x2091, 0x8000, - 0x72c8, 0x2069, 0x0100, 0xd284, 0x1110, 0x2069, 0x0200, 0x6808, - 0xa084, 0xfffd, 0x680a, 0x6830, 0xd0b4, 0x01b0, 0x684b, 0x0004, - 0x20a9, 0x0014, 0x6848, 0xd094, 0x0110, 0x1f04, 0x18c2, 0x684b, - 0x0009, 0x20a9, 0x0014, 0x6848, 0xd084, 0x0110, 0x1f04, 0x18cb, - 0x20a9, 0x00fa, 0x1f04, 0x18d2, 0x2079, 0x4700, 0x2009, 0x0018, - 0x72c8, 0xd284, 0x1118, 0x2061, 0x4740, 0x0018, 0x2061, 0x4780, - 0xc1fd, 0x607b, 0x0000, 0x792a, 0x6063, 0x0001, 0x607f, 0x000f, - 0x60a3, 0x0000, 0x60a4, 0x60ae, 0x60b2, 0x60d0, 0xd0b4, 0x0160, - 0xc0b4, 0x60d2, 0x00c6, 0x60b4, 0xa065, 0x6008, 0xc0d4, 0x600a, - 0x6018, 0x8001, 0x601a, 0x00ce, 0x60d0, 0xa084, 0x7eff, 0x60d2, - 0x78ac, 0xc08d, 0x78ae, 0x83ff, 0x0108, 0x0005, 0x681b, 0x0054, - 0x2091, 0x8001, 0x0005, 0x73cc, 0x080c, 0x1878, 0x69ec, 0x6a48, - 0xa185, 0x1800, 0x684a, 0xa185, 0x0040, 0x68ee, 0x73cc, 0x2021, - 0x0004, 0x20a9, 0x09ff, 0x1f04, 0x191b, 0x8421, 0x1dd0, 0x8319, - 0x1db0, 0x69ee, 0x6a4a, 0x2091, 0x8001, 0x0005, 0xd7fc, 0x1118, - 0x2069, 0x4740, 0x0010, 0x2069, 0x4780, 0x71c4, 0x71c6, 0x6916, - 0x81ff, 0x1110, 0x68a3, 0x0001, 0x78ac, 0xc08c, 0x78ae, 0xd084, - 0x1110, 0x080c, 0x1c7a, 0x0005, 0x75d8, 0x74dc, 0x75da, 0x74de, - 0x0010, 0xa02e, 0x2520, 0x71c4, 0x73c8, 0x72cc, 0x71c6, 0x73ca, - 0x72ce, 0x2079, 0x4700, 0x7dde, 0x7cda, 0x7bd6, 0x7ad2, 0x080c, - 0x1b77, 0x0904, 0x1a5c, 0x20a9, 0x0005, 0x20a1, 0x4714, 0x2091, - 0x8000, 0x41a1, 0x2091, 0x8001, 0x2009, 0x0040, 0x080c, 0x1d41, - 0x0120, 0x080c, 0x1b7f, 0x0804, 0x1a5c, 0x6004, 0xa08c, 0x00ff, - 0xa18e, 0x0009, 0x1120, 0x0006, 0x080c, 0x2086, 0x000e, 0xa084, - 0xff00, 0x8007, 0x8009, 0x0904, 0x19f1, 0x00c6, 0x2c68, 0x080c, - 0x1b77, 0x05a8, 0x2c00, 0x689e, 0x8109, 0x1dc0, 0x609f, 0x0000, - 0x00ce, 0x00c6, 0x7ddc, 0x7cd8, 0x7bd4, 0x7ad0, 0xa290, 0x0040, - 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x7dde, 0x7cda, - 0x7bd6, 0x7ad2, 0x2c68, 0x689c, 0xa065, 0x0904, 0x19f0, 0x2009, - 0x0040, 0x080c, 0x1d41, 0x15a0, 0x6004, 0xa084, 0x00ff, 0xa086, - 0x0002, 0x0150, 0x6004, 0xa084, 0x00ff, 0xa086, 0x000a, 0x1138, - 0x0016, 0x080c, 0x2083, 0x001e, 0x2d00, 0x6002, 0x0898, 0x00ce, - 0x00c6, 0x609c, 0x080c, 0x1bf3, 0x00ce, 0x609f, 0x0000, 0x080c, - 0x1a60, 0x2009, 0x0018, 0x6008, 0xc0cd, 0x600a, 0x6004, 0x6086, - 0x7810, 0x0006, 0x84ff, 0x1110, 0x85ff, 0x0110, 0xc0c5, 0x7812, - 0x080c, 0x1b34, 0x000e, 0x7812, 0x080c, 0x1b7f, 0x0804, 0x1a5c, - 0x00ce, 0x00c6, 0x609c, 0x080c, 0x1bf3, 0x00ce, 0x609f, 0x0000, - 0x080c, 0x1a60, 0x2009, 0x0018, 0x6087, 0x0103, 0x601b, 0x0003, - 0x7810, 0x0006, 0x84ff, 0x1110, 0x85ff, 0x0110, 0xc0c5, 0x7812, - 0x080c, 0x1b34, 0x000e, 0x7812, 0x080c, 0x1b7f, 0x0804, 0x1a5c, - 0x00ce, 0x6114, 0xd1fc, 0x0120, 0x080c, 0x1b29, 0x01f0, 0x0018, - 0x080c, 0x1b1e, 0x01d0, 0x080c, 0x1a60, 0x2009, 0x0018, 0x6087, - 0x0103, 0x601b, 0x0021, 0x7810, 0x0006, 0x84ff, 0x1110, 0x85ff, - 0x0110, 0xc0c5, 0x7812, 0x080c, 0x1b34, 0x000e, 0x7812, 0x080c, - 0x1b7f, 0x2001, 0x4007, 0x0804, 0x13bc, 0x6104, 0xa18c, 0x00ff, - 0xa186, 0x0005, 0x1118, 0x601c, 0xc0bd, 0x601e, 0x74c4, 0x73c8, - 0x72cc, 0x6014, 0x2091, 0x8000, 0x00e6, 0x2009, 0x0012, 0xd0fc, - 0x1118, 0x2071, 0x4740, 0x0018, 0x2071, 0x4780, 0xc1fd, 0x792a, - 0x7063, 0x0005, 0x71d0, 0xc1c4, 0x71d2, 0x7366, 0x726a, 0x746e, - 0x7072, 0x7077, 0x0000, 0x2c00, 0x707a, 0xa02e, 0x2530, 0x611c, - 0xa184, 0x0060, 0x0110, 0x080c, 0x3fe9, 0x00ee, 0x6596, 0x65a6, - 0x669a, 0x66aa, 0x60af, 0x0000, 0x60b3, 0x0000, 0x6714, 0x6023, - 0x0000, 0x6024, 0xa096, 0x0001, 0x1110, 0x8000, 0x6026, 0x080c, - 0x22d5, 0x2091, 0x8001, 0x0005, 0x70c3, 0x4005, 0x0804, 0x13bd, - 0x20a9, 0x0005, 0x2099, 0x4714, 0x2091, 0x8000, 0x530a, 0x2091, - 0x8001, 0x2100, 0xa210, 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, - 0x0000, 0x0005, 0x71c4, 0x70c7, 0x0000, 0x791e, 0x0804, 0x13ba, - 0x71c4, 0x71c6, 0x2168, 0x0010, 0x2069, 0x1000, 0x690c, 0xa016, - 0x2d04, 0xa210, 0x8d68, 0x8109, 0x1dd8, 0xa285, 0x0000, 0x1118, - 0x70c3, 0x4000, 0x0010, 0x70c3, 0x4003, 0x70ca, 0x0804, 0x13bd, - 0x7964, 0x71c6, 0x71c4, 0xa182, 0x0003, 0x1a04, 0x13b3, 0x7966, - 0x0804, 0x13ba, 0x7964, 0x71c6, 0x0804, 0x13ba, 0x7900, 0x71c6, - 0x71c4, 0x7902, 0x0804, 0x13ba, 0x7900, 0x71c6, 0x0804, 0x13ba, - 0x70c4, 0x2011, 0x0000, 0xa08c, 0x000d, 0x0160, 0x810c, 0x0230, - 0x8210, 0x810c, 0x810c, 0x0210, 0x8210, 0x810c, 0x81ff, 0x1904, - 0x13b4, 0x8210, 0x7a0e, 0xd28c, 0x0538, 0x7910, 0xc1cd, 0x7912, - 0x2009, 0x0021, 0x2019, 0x0003, 0xd284, 0x01c0, 0x8108, 0x2019, - 0x0041, 0x2011, 0x8f4e, 0x2312, 0x2019, 0x0042, 0x8210, 0x2312, - 0x2019, 0x0043, 0x8210, 0x2312, 0x2019, 0x0046, 0x8210, 0x2312, - 0x2019, 0x0047, 0x8210, 0x2312, 0x2019, 0x0006, 0x2011, 0x8f53, - 0x2112, 0x2011, 0x8f73, 0x2312, 0x7904, 0x7806, 0x0804, 0x13b9, - 0x7804, 0x70c6, 0x0804, 0x13ba, 0x71c4, 0xd1fc, 0x1118, 0x2011, - 0x4bc0, 0x0010, 0x2011, 0x4c40, 0x8107, 0xa084, 0x000f, 0x8003, - 0x8003, 0x8003, 0xa268, 0x2011, 0x0000, 0x6814, 0xd0fc, 0x0110, - 0xa295, 0x0200, 0xd0b4, 0x0110, 0xa295, 0x0001, 0x6b0c, 0x6800, - 0x70da, 0x0804, 0x13b7, 0x7814, 0xd0f4, 0x0130, 0x2001, 0x4007, - 0x70db, 0x0000, 0xa005, 0x0048, 0xd0fc, 0x0130, 0x2001, 0x4007, - 0x70db, 0x0001, 0xa005, 0x0008, 0xa006, 0x0005, 0x7814, 0xd0f4, - 0x0130, 0x2001, 0x4007, 0x70db, 0x0000, 0xa005, 0x0008, 0xa006, - 0x0005, 0x7814, 0xd0fc, 0x0130, 0x2001, 0x4007, 0x70db, 0x0001, - 0xa005, 0x0008, 0xa006, 0x0005, 0x7112, 0x721a, 0x731e, 0x7810, - 0xd0c4, 0x0110, 0x7422, 0x7526, 0xac80, 0x0001, 0x8108, 0x810c, - 0x81a9, 0x8098, 0x20a1, 0x0030, 0x7003, 0x0000, 0x6084, 0x20a2, - 0x53a6, 0x7007, 0x0001, 0x7974, 0xa184, 0xff00, 0x0140, 0x810f, - 0x810c, 0x810c, 0x8004, 0x8004, 0x8007, 0xa100, 0x0018, 0x8107, - 0x8004, 0x8004, 0x797c, 0xa108, 0x7a78, 0xa006, 0xa211, 0x7d10, - 0xd5c4, 0x0120, 0x7b84, 0xa319, 0x7c80, 0xa421, 0x7008, 0xd0fc, - 0x0de8, 0x7003, 0x0001, 0x7007, 0x0006, 0x711a, 0x721e, 0x7d10, - 0xd5c4, 0x0110, 0x7322, 0x7426, 0xa084, 0x01e0, 0x0005, 0x7848, - 0xa065, 0x0120, 0x2c04, 0x784a, 0x2063, 0x0000, 0x0005, 0x00f6, - 0x2079, 0x4700, 0x7848, 0x2062, 0x2c00, 0xa005, 0x1110, 0x080c, - 0x2575, 0x784a, 0x00fe, 0x0005, 0x2011, 0x9100, 0x7a4a, 0x7bc4, - 0x8319, 0x0128, 0xa280, 0x0032, 0x2012, 0x2010, 0x0cc8, 0x2013, - 0x0000, 0x0005, 0x0016, 0x0026, 0xd7fc, 0x1118, 0x2011, 0x4cc0, - 0x0010, 0x2011, 0x6cc0, 0xa784, 0x0f00, 0x800b, 0xa784, 0x001f, - 0x0120, 0x8003, 0x8003, 0x8003, 0x8003, 0xa105, 0xa268, 0x002e, - 0x001e, 0x0005, 0x0c39, 0x2900, 0x682a, 0x2a00, 0x682e, 0x6808, - 0xa084, 0xf9ef, 0xa80d, 0x690a, 0x00e6, 0xd7fc, 0x1128, 0x2009, - 0x4752, 0x2071, 0x4740, 0x0020, 0x2009, 0x4792, 0x2071, 0x4780, - 0x210c, 0x6804, 0xa005, 0x0148, 0xa116, 0x1138, 0x2060, 0x6000, - 0x6806, 0x0016, 0x200b, 0x0000, 0x0018, 0x2009, 0x0000, 0x0016, - 0x6804, 0xa065, 0x0178, 0x6000, 0x6806, 0x0421, 0x080c, 0x1db2, - 0x6810, 0x7908, 0x8109, 0x790a, 0x8001, 0x6812, 0x1d88, 0x7910, - 0xc1a5, 0x7912, 0x001e, 0x6902, 0x6906, 0x2d00, 0x2060, 0x080c, - 0x26bf, 0x00ee, 0x0005, 0xa065, 0x0160, 0x2008, 0x609c, 0xa005, - 0x0128, 0x2062, 0x609f, 0x0000, 0xa065, 0x0cc0, 0x7848, 0x794a, - 0x2062, 0x0005, 0x6007, 0x0103, 0x608f, 0x0000, 0x20a9, 0x001c, - 0xac80, 0x0005, 0x20a0, 0x2001, 0x0000, 0x40a4, 0x6828, 0x601a, - 0x682c, 0x6022, 0x0005, 0x00e6, 0xd7fc, 0x1128, 0x2071, 0x4740, - 0x2031, 0x47c0, 0x0020, 0x2071, 0x4780, 0x2031, 0x49c0, 0x704c, - 0xa08c, 0x0200, 0x1128, 0xa608, 0x2d0a, 0x8000, 0x704e, 0xa006, - 0x00ee, 0x0005, 0x00f6, 0xd7fc, 0x1118, 0x2079, 0x4740, 0x0010, - 0x2079, 0x4780, 0x080c, 0x1b9a, 0x2091, 0x8000, 0x6804, 0x780a, - 0xa065, 0x05f0, 0x0030, 0x2c00, 0x780a, 0x2060, 0x6000, 0xa065, - 0x05b8, 0x6010, 0xa306, 0x1db8, 0x600c, 0xa206, 0x1da0, 0x2c28, - 0x7848, 0xac06, 0x1108, 0x0448, 0x6804, 0xac06, 0x1140, 0x6000, - 0x2060, 0x6806, 0xa005, 0x1118, 0x6803, 0x0000, 0x0048, 0x6400, - 0x7808, 0x2060, 0x6402, 0xa486, 0x0000, 0x1110, 0x2c00, 0x6802, - 0x2560, 0x080c, 0x1c02, 0x601b, 0x0005, 0x6023, 0x0020, 0x00fe, - 0x080c, 0x1db2, 0x00f6, 0x7908, 0x8109, 0x790a, 0x6810, 0x8001, - 0x6812, 0x1118, 0x7810, 0xc0a5, 0x7812, 0x2001, 0xffff, 0xa005, - 0x00fe, 0x0005, 0x0076, 0x2700, 0x2039, 0x0000, 0xd0fc, 0x0108, - 0xc7fd, 0x2041, 0x0021, 0x2049, 0x0004, 0x2051, 0x0008, 0x2091, - 0x8000, 0x080c, 0x1bb2, 0x8738, 0xa784, 0x001f, 0x1dd0, 0xa7bc, - 0xff00, 0x873f, 0x8738, 0x873f, 0xa784, 0x0f00, 0x1d90, 0x2091, - 0x8001, 0x007e, 0x0005, 0x786c, 0x2009, 0x8f74, 0x210c, 0xa10d, - 0x0118, 0xa065, 0x0804, 0x20a1, 0x2061, 0x0000, 0x6018, 0xd084, - 0x11b8, 0x7810, 0xd08c, 0x0130, 0xc08c, 0x7812, 0xc7fc, 0x2069, - 0x4740, 0x0028, 0xc08d, 0x7812, 0x2069, 0x4780, 0xc7fd, 0x2091, - 0x8000, 0x681c, 0x681f, 0x0000, 0x2091, 0x8001, 0xa005, 0x1108, - 0x0005, 0xa08c, 0xfff0, 0x0110, 0x080c, 0x2575, 0x0002, 0x1cd7, - 0x1cda, 0x1ce0, 0x1ce4, 0x1cd8, 0x1ce8, 0x1cd8, 0x1cd8, 0x1cd8, - 0x1cee, 0x1d18, 0x1d1b, 0x1d20, 0x1d29, 0x1cd8, 0x1cd8, 0x0005, - 0x080c, 0x2575, 0x080c, 0x1c7a, 0x2001, 0x8001, 0x0804, 0x1d32, - 0x2001, 0x8003, 0x0804, 0x1d32, 0x2001, 0x8004, 0x0804, 0x1d32, - 0x080c, 0x1c7a, 0x2001, 0x8006, 0x0804, 0x1d32, 0x2011, 0x800a, - 0x2091, 0x8000, 0xd7fc, 0x1118, 0x2069, 0x4740, 0x0010, 0x2069, - 0x4780, 0x2038, 0x6800, 0xa086, 0x0000, 0x0120, 0x6f1e, 0x2091, - 0x8001, 0x0005, 0x0026, 0x6870, 0xa0bc, 0xff00, 0x2041, 0x0021, - 0x2049, 0x0004, 0x2051, 0x0010, 0x080c, 0x1bb2, 0x8738, 0xa784, - 0x001f, 0x1dd0, 0x2091, 0x8001, 0x000e, 0x6970, 0x71c6, 0x00d0, - 0x2001, 0x800c, 0x00b8, 0x080c, 0x1c7a, 0x2001, 0x800d, 0x0090, - 0xd7fc, 0x0110, 0x78e4, 0x0008, 0x78e0, 0x70c6, 0x2001, 0x800e, - 0x0048, 0xd7fc, 0x0110, 0x78ec, 0x0008, 0x78e8, 0x70c6, 0x2001, - 0x800f, 0x0000, 0x70c2, 0xd7fc, 0x1118, 0x70db, 0x0000, 0x0010, - 0x70db, 0x0001, 0x2061, 0x0000, 0x601b, 0x0001, 0x2091, 0x4080, - 0x0005, 0xac80, 0x0001, 0x81ff, 0x0518, 0x2099, 0x0030, 0x20a0, - 0x700c, 0xa084, 0x07ff, 0x0100, 0x7018, 0x0006, 0x701c, 0x0006, - 0x7020, 0x0006, 0x7024, 0x0006, 0x7112, 0x81ac, 0x721a, 0x731e, - 0x7422, 0x7526, 0x7003, 0x0001, 0x7007, 0x0001, 0x7008, 0x800b, - 0x1ee8, 0x7007, 0x0002, 0xa08c, 0x01e0, 0x1110, 0x53a5, 0xa006, - 0x7003, 0x0000, 0x7007, 0x0004, 0x000e, 0x7026, 0x000e, 0x7022, - 0x000e, 0x701e, 0x000e, 0x701a, 0x0005, 0x2011, 0x0020, 0x2009, - 0x0010, 0x6b0a, 0x6c0e, 0x681f, 0x0201, 0x6803, 0xfd20, 0x6807, - 0x0038, 0x6a1a, 0x2d00, 0xa0e8, 0x0008, 0xa290, 0x0004, 0x8109, - 0x1d80, 0x0005, 0x70ec, 0xd0dc, 0x1520, 0x2029, 0x0001, 0x7814, - 0xd0cc, 0x1160, 0x70ec, 0xd0e4, 0x2019, 0x0c0a, 0x2021, 0x000a, - 0x1120, 0x2019, 0x0c0c, 0x2021, 0x000c, 0x0070, 0x70ec, 0xd0e4, - 0x1128, 0x2019, 0x180c, 0x2021, 0x000c, 0x0030, 0x2019, 0x1809, - 0x2021, 0x0009, 0xa5ad, 0x0200, 0x6b0a, 0x6c0e, 0x6d1e, 0x6807, - 0x0038, 0x0005, 0x6004, 0x6086, 0x2c08, 0x2063, 0x0000, 0x7868, - 0xa005, 0x796a, 0x0110, 0x2c02, 0x0008, 0x796e, 0x0005, 0x00c6, - 0x2061, 0x4700, 0x6887, 0x0103, 0x2d08, 0x206b, 0x0000, 0x6068, - 0xa005, 0x616a, 0x0110, 0x2d02, 0x0008, 0x616e, 0x00ce, 0x0005, - 0x2091, 0x8000, 0x2c04, 0x786e, 0xa005, 0x1108, 0x786a, 0x2091, - 0x8001, 0x609c, 0xa005, 0x0188, 0x00c6, 0x2060, 0x2008, 0x609c, - 0xa005, 0x0138, 0x2062, 0x609f, 0x0000, 0xa065, 0x609c, 0xa005, - 0x1dc8, 0x7848, 0x794a, 0x2062, 0x00ce, 0x7848, 0x2062, 0x609f, - 0x0000, 0xac85, 0x0000, 0x1110, 0x080c, 0x2575, 0x784a, 0x0005, - 0x20a9, 0x0010, 0xa006, 0x8004, 0x8086, 0x818e, 0x1208, 0xa200, - 0x1f04, 0x1dfc, 0x8086, 0x818e, 0x0005, 0x0156, 0x20a9, 0x0010, - 0xa005, 0x01b8, 0xa11a, 0x12a8, 0x8213, 0x818d, 0x0228, 0xa11a, - 0x1220, 0x1f04, 0x1e0c, 0x0028, 0xa11a, 0x2308, 0x8210, 0x1f04, - 0x1e0c, 0x0006, 0x3200, 0xa084, 0xefff, 0x2080, 0x000e, 0x015e, - 0x0005, 0x0006, 0x3200, 0xa085, 0x1000, 0x0cb8, 0x7d74, 0x70d0, - 0xa506, 0x0904, 0x1eda, 0x7810, 0x2050, 0x080c, 0x1b77, 0x0904, - 0x1eda, 0xa046, 0x7970, 0x2500, 0x8000, 0xa112, 0x2009, 0x0040, - 0x1208, 0x0030, 0x72d0, 0xa206, 0x0118, 0x8840, 0x2009, 0x0080, - 0x00c6, 0x7112, 0x7007, 0x0001, 0x2099, 0x0030, 0x20a9, 0x0020, - 0xac80, 0x0001, 0x20a0, 0x2061, 0x0000, 0x88ff, 0x0110, 0x080c, - 0x1b77, 0x7008, 0xd0fc, 0x0de8, 0x7007, 0x0002, 0x2091, 0x8001, - 0xa08c, 0x01e0, 0x1538, 0x53a5, 0x8cff, 0x1120, 0x88ff, 0x0904, - 0x1ec7, 0x0050, 0x2c00, 0x788e, 0x20a9, 0x0020, 0xac80, 0x0001, - 0x20a0, 0x53a5, 0x0804, 0x1ec7, 0xa046, 0x7218, 0x731c, 0xdac4, - 0x0110, 0x7420, 0x7524, 0xa292, 0x0040, 0xa39b, 0x0000, 0xa4a3, - 0x0000, 0xa5ab, 0x0000, 0x721a, 0x731e, 0xdac4, 0x0118, 0x7422, - 0x7526, 0xa006, 0x7007, 0x0004, 0x0904, 0x1ec7, 0x8cff, 0x0110, - 0x080c, 0x1b7f, 0x00ce, 0x080c, 0x1b7f, 0xa046, 0x7888, 0x8000, - 0x788a, 0xa086, 0x0002, 0x01c0, 0x7a7c, 0x7b78, 0xdac4, 0x0110, - 0x7c84, 0x7d80, 0x7974, 0x8107, 0x8004, 0x8004, 0xa210, 0xa399, - 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x721a, 0x731e, 0xdac4, - 0x0588, 0x7422, 0x7526, 0x0470, 0x6014, 0xd0fc, 0x1118, 0x2069, - 0x4740, 0x0010, 0x2069, 0x4780, 0x2091, 0x8000, 0x681f, 0x0002, - 0x88ff, 0x0120, 0xa046, 0x788c, 0x2060, 0x0c70, 0x788b, 0x0000, - 0x78ac, 0xa085, 0x0003, 0x78ae, 0x2091, 0x8001, 0x0098, 0x00ce, - 0x788b, 0x0000, 0x080c, 0x205c, 0x6004, 0xa084, 0x000f, 0x0059, - 0x88ff, 0x0130, 0x788c, 0x2060, 0x6004, 0xa084, 0x000f, 0x0019, - 0x0804, 0x1e26, 0x0005, 0x0002, 0x1eec, 0x1f07, 0x1f20, 0x1eec, - 0x1f2d, 0x1efd, 0x1eec, 0x1eec, 0x1eec, 0x1f05, 0x1f1e, 0x1eec, - 0x1eec, 0x1eec, 0x1eec, 0x1eec, 0x2039, 0x0400, 0x78bc, 0xa705, - 0x78be, 0x6008, 0xa705, 0x600a, 0x080c, 0x1f69, 0x609c, 0x78ba, - 0x609f, 0x0000, 0x080c, 0x2048, 0x0005, 0x78bc, 0xd0c4, 0x0108, - 0x0c58, 0x601c, 0xc0bd, 0x601e, 0x0030, 0x080c, 0x2086, 0x78bc, - 0xd0c4, 0x0108, 0x0c08, 0x78bf, 0x0000, 0x6004, 0x8007, 0xa084, - 0x00ff, 0x78b2, 0x8001, 0x0138, 0x080c, 0x1f69, 0x0120, 0x78bc, - 0xc0c5, 0x78be, 0x0010, 0x0804, 0x1f84, 0x0005, 0x080c, 0x2083, - 0x78bc, 0xa08c, 0x0e00, 0x1110, 0xd0c4, 0x1108, 0x0828, 0x080c, - 0x1f69, 0x1110, 0x0804, 0x1f84, 0x0005, 0x78bc, 0xd0c4, 0x0110, - 0x0804, 0x1eec, 0x78bf, 0x0000, 0x6714, 0x2011, 0x0001, 0x22a8, - 0x6018, 0xa084, 0x00ff, 0xa005, 0x0188, 0xa7bc, 0xff00, 0x20a9, - 0x0020, 0xa08e, 0x0001, 0x0150, 0xa7bc, 0x8000, 0x2011, 0x0002, - 0x20a9, 0x0100, 0xa08e, 0x0002, 0x0108, 0x00c0, 0x080c, 0x1b9a, - 0x2d00, 0x2091, 0x8000, 0x682b, 0x0000, 0x682f, 0x0000, 0x6808, - 0xa084, 0xffde, 0x680a, 0xade8, 0x0010, 0x2091, 0x8001, 0x1f04, - 0x1f51, 0x8211, 0x0118, 0x20a9, 0x0100, 0x0c58, 0x080c, 0x1b7f, - 0x0005, 0x609f, 0x0000, 0x78b4, 0xa06d, 0x2c00, 0x78b6, 0x1110, - 0x78ba, 0x0038, 0x689e, 0x2d00, 0x6002, 0x78b8, 0xad06, 0x1108, - 0x6002, 0x78b0, 0x8001, 0x78b2, 0x1130, 0x78bc, 0xc0c4, 0x78be, - 0x78b8, 0x2060, 0xa006, 0x0005, 0x00e6, 0xa02e, 0x2530, 0x7dba, - 0x7db6, 0x65ae, 0x65b2, 0x601c, 0x60a2, 0x2048, 0xa984, 0xe1ff, - 0x601e, 0xa984, 0x0060, 0x0160, 0x080c, 0x3fe9, 0x86ff, 0x1140, - 0x85ff, 0x1130, 0x2039, 0x0800, 0x080c, 0x2048, 0x0804, 0x2046, - 0x6596, 0x65a6, 0x669a, 0x66aa, 0x6714, 0x2071, 0x4780, 0xd7fc, - 0x1110, 0x2071, 0x4740, 0xa784, 0x0f00, 0x800b, 0xa784, 0x001f, - 0x0120, 0x8003, 0x8003, 0x8003, 0x8003, 0xa105, 0x71c0, 0xa168, - 0x2700, 0x8007, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0x71c4, - 0xa100, 0x60c2, 0x2091, 0x8000, 0x7814, 0xd0c4, 0x0138, 0xd7fc, - 0x1118, 0xd0f4, 0x1140, 0x0010, 0xd0fc, 0x1128, 0x6e08, 0xd684, - 0x01f0, 0xd9fc, 0x11e0, 0x2091, 0x8001, 0x080c, 0x1c02, 0x2091, - 0x8000, 0x080c, 0x1db2, 0x2091, 0x8001, 0x7814, 0xd0c4, 0x0904, - 0x2046, 0xd7fc, 0x1120, 0xd0f4, 0x1130, 0x0804, 0x2046, 0xd0fc, - 0x1110, 0x0804, 0x2046, 0x601b, 0x0021, 0x0804, 0x2046, 0x6024, - 0xa096, 0x0001, 0x1110, 0x8000, 0x6026, 0x6a10, 0x6814, 0xa202, - 0x0268, 0x0160, 0x2091, 0x8001, 0x2039, 0x0200, 0x609c, 0x78ba, - 0x609f, 0x0000, 0x080c, 0x2048, 0x0804, 0x2046, 0x2c08, 0xd9fc, - 0x01f0, 0x6800, 0xa065, 0x01d8, 0x6a04, 0x7000, 0xa084, 0x0002, - 0x0168, 0x7048, 0xa206, 0x1150, 0x6b04, 0x2160, 0x2304, 0x6002, - 0xa005, 0x1108, 0x6902, 0x2260, 0x6102, 0x0098, 0x2d00, 0x2060, - 0x080c, 0x26bf, 0x6e08, 0x2160, 0x6202, 0x6906, 0x0050, 0x6800, - 0x6902, 0xa065, 0x0110, 0x6102, 0x0008, 0x6906, 0x2160, 0x6003, - 0x0000, 0x2160, 0xd9fc, 0x0118, 0xa6b4, 0xfffc, 0x6e0a, 0x6810, - 0x7d08, 0x8528, 0x7d0a, 0x8000, 0x6812, 0x2091, 0x8001, 0xd6b4, - 0x0128, 0xa6b6, 0x0040, 0x6e0a, 0x080c, 0x1c13, 0x00ee, 0x0005, - 0x6008, 0xa705, 0x600a, 0x2091, 0x8000, 0x080c, 0x1db2, 0x2091, - 0x8001, 0x78b8, 0xa065, 0x0128, 0x609c, 0x78ba, 0x609f, 0x0000, - 0x0c78, 0x78b6, 0x78ba, 0x0005, 0x7970, 0x7874, 0x2818, 0xd384, - 0x0118, 0x8000, 0xa112, 0x0220, 0x8000, 0xa112, 0x1278, 0xc384, - 0x7a7c, 0x721a, 0x7a78, 0x721e, 0xdac4, 0x0120, 0x7a84, 0x7222, - 0x7a80, 0x7226, 0xa006, 0xd384, 0x0108, 0x8000, 0x7876, 0x70d2, - 0x781c, 0xa005, 0x0138, 0x8001, 0x781e, 0x1120, 0x0e04, 0x2082, - 0x2091, 0x4080, 0x0005, 0x2039, 0x2098, 0x0010, 0x2039, 0x209e, - 0x2704, 0xa005, 0x0160, 0xac00, 0x2068, 0x6908, 0x6810, 0x6912, - 0x680a, 0x690c, 0x6814, 0x6916, 0x680e, 0x8738, 0x0c88, 0x0005, - 0x0003, 0x0009, 0x000f, 0x0015, 0x001b, 0x0000, 0x0015, 0x001b, - 0x0000, 0x2041, 0x0000, 0x780c, 0x0002, 0x224a, 0x2225, 0x20a9, - 0x2119, 0x2039, 0x8f74, 0x2734, 0x7d10, 0x00c0, 0x6084, 0xa086, - 0x0103, 0x1904, 0x2103, 0x6114, 0x6018, 0xa105, 0x0120, 0x86ff, - 0x11d8, 0x0804, 0x2103, 0x8603, 0xa080, 0x8f55, 0x620c, 0x2202, - 0x8000, 0x6210, 0x2202, 0x080c, 0x1dd0, 0x8630, 0xa68e, 0x000f, - 0x0904, 0x2184, 0x786c, 0xa065, 0x1d08, 0x7808, 0xa602, 0x1220, - 0xd5ac, 0x1110, 0x263a, 0x0005, 0xa682, 0x0003, 0x1a04, 0x2184, - 0x2091, 0x8000, 0x2069, 0x0000, 0x6818, 0xd084, 0x11f8, 0x2011, - 0x8f55, 0x2204, 0x70c6, 0x8210, 0x2204, 0x70ca, 0xd684, 0x1130, - 0x8210, 0x2204, 0x70da, 0x8210, 0x2204, 0x70de, 0xa685, 0x8020, - 0x70c2, 0x681b, 0x0001, 0x2091, 0x4080, 0x7810, 0xa084, 0xffcf, - 0x7812, 0x2091, 0x8001, 0x203b, 0x0000, 0x0005, 0x7810, 0xc0ad, - 0x7812, 0x0804, 0x2184, 0x263a, 0x080c, 0x2250, 0x1904, 0x226c, - 0x786c, 0xa065, 0x1904, 0x20ae, 0x2091, 0x8000, 0x7810, 0xa084, - 0xffcf, 0x86ff, 0x0108, 0xc0ad, 0x7812, 0x2091, 0x8001, 0x0804, - 0x226c, 0x2039, 0x8f74, 0x2734, 0x7d10, 0x00a0, 0x6084, 0xa086, - 0x0103, 0x1904, 0x216e, 0x6114, 0x6018, 0xa105, 0x0120, 0x86ff, - 0x11b8, 0x0804, 0x216e, 0xa680, 0x8f55, 0x620c, 0x2202, 0x080c, - 0x1dd0, 0x8630, 0xa68e, 0x001e, 0x0904, 0x2184, 0x786c, 0xa065, - 0x1d28, 0x7808, 0xa602, 0x1220, 0xd5ac, 0x1110, 0x263a, 0x0005, - 0xa682, 0x0006, 0x1a04, 0x2184, 0x2091, 0x8000, 0x2069, 0x0000, - 0x6818, 0xd084, 0x11f8, 0x2011, 0x8f55, 0x2009, 0x8f4e, 0x26a8, - 0x211c, 0x2204, 0x201a, 0x8108, 0x8210, 0x1f04, 0x2150, 0xa685, - 0x8030, 0x70c2, 0x681b, 0x0001, 0x2091, 0x4080, 0x7810, 0xa084, - 0xffcf, 0x7812, 0x2091, 0x8001, 0xa006, 0x2009, 0x8f75, 0x200a, - 0x203a, 0x0005, 0x7810, 0xc0ad, 0x7812, 0x00b0, 0x263a, 0x080c, - 0x2250, 0x1904, 0x226c, 0x786c, 0xa065, 0x1904, 0x211e, 0x2091, - 0x8000, 0x7810, 0xa084, 0xffcf, 0x86ff, 0x0108, 0xc0ad, 0x7812, - 0x2091, 0x8001, 0x0804, 0x226c, 0x2091, 0x8000, 0x7007, 0x0004, - 0x7994, 0x70d4, 0xa102, 0x0228, 0x0168, 0x7b90, 0xa302, 0x1150, - 0x0010, 0x8002, 0x1138, 0x263a, 0x7810, 0xc0ad, 0x7812, 0x2091, - 0x8001, 0x0005, 0xa184, 0xff00, 0x0140, 0x810f, 0x810c, 0x810c, - 0x8004, 0x8004, 0x8007, 0xa100, 0x0018, 0x8107, 0x8004, 0x8004, - 0x7a9c, 0xa210, 0x721a, 0x7a98, 0xa006, 0xa211, 0x721e, 0xd4c4, - 0x0130, 0x7aa4, 0xa211, 0x7222, 0x7aa0, 0xa211, 0x7226, 0x20a1, - 0x0030, 0x7003, 0x0000, 0x2009, 0x8f54, 0x260a, 0x8109, 0x2198, - 0x2104, 0xd084, 0x0108, 0x8633, 0xa6b0, 0x0002, 0x26a8, 0x53a6, - 0x8603, 0x7012, 0x7007, 0x0001, 0x7990, 0x7894, 0x8000, 0xa10a, - 0x1208, 0xa006, 0x2028, 0x7974, 0xa184, 0xff00, 0x0140, 0x810f, - 0x810c, 0x810c, 0x8004, 0x8004, 0x8007, 0xa100, 0x0018, 0x8107, - 0x8004, 0x8004, 0x797c, 0xa108, 0x7a78, 0xa006, 0xa211, 0xd4c4, - 0x0120, 0x7b84, 0xa319, 0x7c80, 0xa421, 0x7008, 0xd0fc, 0x0de8, - 0xa084, 0x01e0, 0x01d0, 0x7d10, 0x2031, 0x8f54, 0x2634, 0x78a8, - 0x8000, 0x78aa, 0xd08c, 0x1138, 0x7007, 0x0006, 0x7004, 0xd094, - 0x1de8, 0x0804, 0x2186, 0x2069, 0x4747, 0x206b, 0x0003, 0x78ac, - 0xa085, 0x0300, 0x78ae, 0xa006, 0x0048, 0x2030, 0x75d6, 0x2091, - 0x4080, 0x7d96, 0x7d10, 0xa5ac, 0xffcf, 0x7d12, 0x2091, 0x8001, - 0x78aa, 0x7007, 0x0006, 0x263a, 0x7003, 0x0001, 0x711a, 0x721e, - 0xd5c4, 0x0110, 0x7322, 0x7426, 0x0005, 0x6084, 0xa086, 0x0103, - 0x11d8, 0x6114, 0x6018, 0xa105, 0x11b8, 0x2069, 0x0000, 0x6818, - 0xd084, 0x1190, 0x600c, 0x70c6, 0x6010, 0x70ca, 0x70c3, 0x8020, - 0x681b, 0x0001, 0x2091, 0x4080, 0x080c, 0x1dd0, 0x0e04, 0x2243, - 0x786c, 0xa065, 0x1d10, 0x0005, 0x0059, 0x1530, 0x786c, 0xa065, - 0x19e0, 0x0410, 0x0029, 0x1500, 0x786c, 0xa065, 0x1dd8, 0x00e0, - 0x6084, 0xa086, 0x0103, 0x1168, 0x6018, 0xc0fc, 0x601a, 0xa086, - 0x0004, 0x1138, 0x7804, 0xd0a4, 0x0120, 0x080c, 0x1dd0, 0xa006, - 0x0005, 0x0079, 0x1118, 0xa085, 0x0001, 0x0005, 0x00b9, 0x1110, - 0x2041, 0x0001, 0x7d10, 0x0005, 0x88ff, 0x0110, 0x2091, 0x4080, - 0x0005, 0x7b90, 0x7994, 0x70d4, 0xa102, 0x1118, 0xa385, 0x0000, - 0x0005, 0x0210, 0xa302, 0x0005, 0x8002, 0x0005, 0xa184, 0xff00, - 0x0140, 0x810f, 0x810c, 0x810c, 0x8004, 0x8004, 0x8007, 0xa100, - 0x0018, 0x8107, 0x8004, 0x8004, 0x7a9c, 0x7b98, 0x7ca4, 0x7da0, - 0xa210, 0xa006, 0xa319, 0xa421, 0xa529, 0x2009, 0x0018, 0x6028, - 0xa005, 0x0110, 0x2009, 0x0040, 0x080c, 0x1b34, 0x01d0, 0x78a8, - 0x8000, 0x78aa, 0xd08c, 0x1510, 0x6014, 0xd0fc, 0x1118, 0x2069, - 0x4740, 0x0010, 0x2069, 0x4780, 0x2091, 0x8000, 0x681f, 0x0003, - 0x78ab, 0x0000, 0x78ac, 0xa085, 0x0300, 0x78ae, 0x2091, 0x8001, - 0x0068, 0x78ab, 0x0000, 0x080c, 0x1dd0, 0x7990, 0x7894, 0x8000, - 0xa10a, 0x1208, 0xa006, 0x7896, 0x70d6, 0xa006, 0x2071, 0x0010, - 0x2091, 0x8001, 0x0005, 0xd7fc, 0x1118, 0x2009, 0x4758, 0x0010, - 0x2009, 0x4798, 0x2091, 0x8000, 0x200a, 0x00f6, 0x2009, 0x4780, - 0x2079, 0x0100, 0xd7fc, 0x1120, 0x2009, 0x4740, 0x2079, 0x0200, - 0x2104, 0xa086, 0x0000, 0x1180, 0xd7fc, 0x1118, 0x2009, 0x4745, - 0x0010, 0x2009, 0x4785, 0x2104, 0xa005, 0x1130, 0x7830, 0xa084, - 0x00c0, 0x1110, 0x781b, 0x0052, 0x00fe, 0x0005, 0x2009, 0x0002, - 0x2069, 0x4700, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1904, 0x234b, - 0x2071, 0x4780, 0x2079, 0x0100, 0x2021, 0x49bf, 0x784b, 0x000f, - 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x0118, 0x2019, 0x3e37, 0x0030, - 0x20a1, 0x012b, 0x2019, 0x3e37, 0xd184, 0x0110, 0x20a1, 0x022b, - 0x2304, 0xa005, 0x0140, 0x789a, 0x8318, 0x23ac, 0x8318, 0x2398, - 0x53a6, 0x3318, 0x0ca8, 0x789b, 0x0000, 0x789b, 0x0020, 0x20a9, - 0x0010, 0x78af, 0x0000, 0x78af, 0x2020, 0x1f04, 0x2329, 0x7003, - 0x0000, 0x0016, 0xd18c, 0x2009, 0x0000, 0x0108, 0xc1bd, 0x080c, - 0x246c, 0x001e, 0x7020, 0xa084, 0x000f, 0xa085, 0x6300, 0x7806, - 0x780f, 0x9000, 0x7843, 0x00d8, 0x7853, 0x0090, 0x780b, 0x2f08, - 0x7452, 0x704f, 0x0000, 0x8109, 0x0140, 0x2071, 0x4740, 0x2079, - 0x0200, 0x2021, 0x47bf, 0x0804, 0x2306, 0x080c, 0x2526, 0x0005, - 0x0016, 0x2011, 0x0101, 0xd1bc, 0x1110, 0x2011, 0x0201, 0xa18c, - 0x000f, 0x2204, 0xa084, 0xfff0, 0xa105, 0x2012, 0x001e, 0x080c, - 0x246c, 0x0005, 0x2011, 0x0101, 0xd3fc, 0x1110, 0x2011, 0x0201, - 0x20a9, 0x0009, 0x810b, 0x1f04, 0x2372, 0xa18c, 0x0e00, 0x2204, - 0xa084, 0xf1ff, 0xa105, 0x2012, 0x0005, 0x2019, 0x0002, 0x2009, - 0x0101, 0x20a9, 0x0005, 0x8213, 0x1f04, 0x2383, 0xa294, 0x00e0, - 0x2104, 0xa084, 0xff1f, 0xa205, 0x200a, 0x8319, 0x0118, 0x2009, - 0x0201, 0x0c78, 0x0005, 0x2011, 0x0101, 0xd3fc, 0x1110, 0x2011, - 0x0201, 0x20a9, 0x000c, 0x810b, 0x1f04, 0x239b, 0xa18c, 0xf000, - 0x2204, 0xa084, 0x0fff, 0xa105, 0x2012, 0x0005, 0x2011, 0x0102, - 0xd3fc, 0x1110, 0x2011, 0x0202, 0x2204, 0xa09c, 0x0f30, 0xa084, - 0xf0cf, 0xa105, 0x2012, 0x0005, 0x00c6, 0x2061, 0x0100, 0xd1bc, - 0x1110, 0x2061, 0x0200, 0xc1bc, 0x8103, 0x8003, 0xa080, 0x0020, - 0x609a, 0x62ac, 0x63ac, 0x00ce, 0x0005, 0x00c6, 0x2061, 0x0100, - 0xd1bc, 0x1110, 0x2061, 0x0200, 0xc1bc, 0x8103, 0x8003, 0xa080, - 0x0022, 0x609a, 0x60a4, 0xa084, 0xffdf, 0x60ae, 0x00ce, 0x0005, - 0x00c6, 0x2061, 0x0100, 0xd1bc, 0x1110, 0x2061, 0x0200, 0xc1bc, - 0x8103, 0x8003, 0xa080, 0x0020, 0x609a, 0x60a4, 0xa28c, 0x0020, - 0x0118, 0xc2ac, 0xa39d, 0x4000, 0xc3ec, 0xd3b4, 0x1108, 0xc3ed, - 0x62ae, 0x2010, 0x60a4, 0x63ae, 0x2018, 0x00ce, 0x0005, 0x2091, - 0x8000, 0x00c6, 0x00e6, 0x6818, 0xa005, 0x0904, 0x2450, 0xd1fc, - 0x0118, 0x2061, 0x8ed0, 0x0010, 0x2061, 0x8dc0, 0x080c, 0x2458, - 0x0560, 0x20a9, 0x0101, 0xd1fc, 0x0118, 0x2061, 0x8dd0, 0x0010, - 0x2061, 0x8cc0, 0x00c6, 0x080c, 0x2458, 0x0128, 0x00ce, 0x8c60, - 0x1f04, 0x2412, 0x04a8, 0x000e, 0xd1fc, 0x0128, 0xa082, 0x8dd0, - 0x2071, 0x4780, 0x0020, 0xa082, 0x8cc0, 0x2071, 0x4740, 0x7076, - 0x7172, 0x2138, 0x2001, 0x0004, 0x7062, 0x707f, 0x000f, 0x71d0, - 0xc1c4, 0x71d2, 0x080c, 0x22cb, 0x00c0, 0xd1fc, 0x1118, 0x2071, - 0x4740, 0x0010, 0x2071, 0x4780, 0x6020, 0xc0dd, 0x6022, 0x7172, - 0x2138, 0x2c00, 0x707a, 0x2001, 0x0006, 0x7062, 0x707f, 0x000f, - 0x71d0, 0xc1c4, 0x71d2, 0x080c, 0x22cb, 0x2001, 0x0000, 0x0010, - 0x2001, 0x0001, 0x2091, 0x8001, 0xa005, 0x00ee, 0x00ce, 0x0005, - 0x2c04, 0xa005, 0x0170, 0x2060, 0x6010, 0xa306, 0x1140, 0x600c, - 0xa206, 0x1128, 0x6014, 0xa106, 0x1110, 0xa006, 0x0020, 0x6000, - 0x0c80, 0xa085, 0x0001, 0x0005, 0x00f6, 0x00e6, 0x0016, 0x2079, - 0x4780, 0x2071, 0x0100, 0xd1bc, 0x1120, 0x2079, 0x4740, 0x2071, - 0x0200, 0x7920, 0xa18c, 0x000f, 0x70ec, 0xd0c4, 0x1110, 0x001e, - 0x0060, 0x810b, 0x810b, 0x810b, 0x810b, 0x000e, 0xa18d, 0x0800, - 0xd0bc, 0x1110, 0xa18d, 0x0f00, 0x2104, 0x00ee, 0x00fe, 0x0005, - 0x2001, 0x4701, 0x2004, 0xd0ac, 0x1138, 0x68e4, 0xd0ac, 0x0120, - 0xa084, 0x0006, 0x1108, 0x0009, 0x0005, 0x6014, 0x00e6, 0x0036, - 0x2018, 0x2071, 0x4c40, 0xd0fc, 0x1110, 0x2071, 0x4bc0, 0x8007, - 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xae70, 0x7004, 0xa084, - 0x000a, 0x1904, 0x2523, 0x7108, 0xa194, 0xff00, 0x0904, 0x2523, - 0xa18c, 0x00ff, 0x701c, 0xa084, 0xff00, 0x01c0, 0x7004, 0xa085, - 0x003a, 0x7006, 0x2001, 0x0009, 0xa102, 0x16d8, 0x2001, 0x000a, - 0xa102, 0x16d0, 0x2001, 0x000c, 0xa102, 0x16c8, 0x701c, 0xa084, - 0x00ff, 0x701e, 0x7004, 0xa084, 0xffdf, 0x7006, 0x2001, 0x000a, - 0xa106, 0x01a8, 0x2001, 0x000c, 0xa106, 0x01a0, 0x2001, 0x0012, - 0xa106, 0x0198, 0x2001, 0x0014, 0xa106, 0x0190, 0x2001, 0x0019, - 0xa106, 0x0188, 0x2001, 0x0032, 0xa106, 0x0180, 0x00d8, 0x2009, - 0x000c, 0x00d0, 0x2009, 0x0012, 0x00b8, 0x2009, 0x0014, 0x00a0, - 0x2009, 0x0019, 0x0088, 0x2009, 0x0020, 0x0070, 0x2009, 0x003f, - 0x0058, 0x2009, 0x000a, 0x0040, 0x2009, 0x000c, 0x0028, 0x2009, - 0x0019, 0x0010, 0x2011, 0x0000, 0x2100, 0xa205, 0x700a, 0x7004, - 0xa085, 0x000a, 0x7006, 0x2071, 0x4700, 0x7004, 0xd0bc, 0x0158, - 0xd3fc, 0x1120, 0x73ea, 0x2071, 0x4740, 0x0018, 0x73ee, 0x2071, - 0x4780, 0x701f, 0x000d, 0x003e, 0x00ee, 0x0005, 0x2001, 0x01ff, - 0x2004, 0xd0fc, 0x11d0, 0x2001, 0x04fd, 0x2004, 0xa082, 0x0005, - 0x12a0, 0x2071, 0x0200, 0x71ec, 0xa18c, 0x1c00, 0x810f, 0x810c, - 0x810c, 0x2079, 0x0100, 0x78ec, 0xa084, 0x1c00, 0x8007, 0x8004, - 0x8004, 0xa105, 0xa08a, 0x0007, 0x0208, 0x0005, 0x0002, 0x2574, - 0x255b, 0x2574, 0x255b, 0x254e, 0x2568, 0x254e, 0x7008, 0xa084, - 0xc3ff, 0xa085, 0x3000, 0x700a, 0x7808, 0xa084, 0xc3ff, 0xa085, - 0x3000, 0x780a, 0x0005, 0x7008, 0xa084, 0xc3ff, 0xa085, 0x2000, - 0x700a, 0x7808, 0xa084, 0xc3ff, 0xa085, 0x2000, 0x780a, 0x0005, - 0x7008, 0xa084, 0xc3ff, 0xa085, 0x0c00, 0x700a, 0x7808, 0xa084, - 0xc3ff, 0xa085, 0x0c00, 0x780a, 0x0005, 0x0e04, 0x2575, 0x2091, - 0x8000, 0x2071, 0x0000, 0x0006, 0x7018, 0xd084, 0x1de8, 0x000e, - 0x2071, 0x0010, 0x70ca, 0x000e, 0x70c6, 0x70c3, 0x8002, 0x70db, - 0x0a04, 0x70df, 0x002a, 0x2071, 0x0000, 0x701b, 0x0001, 0x2091, - 0x4080, 0x0cf8, 0x7f3c, 0x7e58, 0x7c30, 0x7d38, 0x78a0, 0x708a, - 0x758e, 0x7492, 0x7696, 0x779a, 0xa594, 0x003f, 0xd4f4, 0x0138, - 0xd7bc, 0x1128, 0xa784, 0x007d, 0x1904, 0x3c9c, 0x0871, 0xa49c, - 0x000f, 0xa382, 0x0004, 0x0320, 0xa3a6, 0x0007, 0x1930, 0x2418, - 0x8507, 0xa084, 0x000f, 0x0002, 0x2b6c, 0x2c57, 0x2c95, 0x2efb, - 0x3279, 0x32d0, 0x3376, 0x3405, 0x34d9, 0x35ab, 0x25c7, 0x25c4, - 0x299e, 0x2a85, 0x324d, 0x25c4, 0x080c, 0x2575, 0x0005, 0xa006, - 0x0038, 0x7808, 0xc08d, 0x780a, 0xa006, 0x7002, 0x704a, 0x7042, - 0x70ce, 0x705c, 0xa005, 0x1904, 0x2718, 0x7060, 0xa084, 0x0007, - 0x0002, 0x25e1, 0x2652, 0x265a, 0x2663, 0x266c, 0x26fe, 0x2675, - 0x2652, 0x7830, 0xd0bc, 0x1d10, 0x71d0, 0xd1bc, 0x19f8, 0xd1b4, - 0x1904, 0x262f, 0x70a0, 0xa086, 0x0001, 0x09c0, 0x7014, 0xa005, - 0x19a8, 0x70b0, 0xa06d, 0x6800, 0xa065, 0xa055, 0x789b, 0x0080, - 0x6b0c, 0x7baa, 0x6808, 0xa045, 0x6d10, 0x6804, 0xa06d, 0xa05d, - 0xa886, 0x0001, 0x0118, 0x69bc, 0x7daa, 0x79aa, 0x68c0, 0xa04d, - 0x6e1c, 0x2001, 0x0010, 0x0804, 0x284b, 0x705c, 0xa005, 0x1904, - 0x25c6, 0x00c6, 0x00d6, 0x70b0, 0xa06d, 0x6800, 0xa065, 0xa055, - 0x789b, 0x0080, 0x6b0c, 0x7baa, 0x6808, 0xa045, 0x6d10, 0x6804, - 0xa06d, 0xa05d, 0xa886, 0x0001, 0x0118, 0x69bc, 0x7daa, 0x79aa, - 0x68c0, 0xa04d, 0x6e1c, 0x2001, 0x0020, 0x0804, 0x284b, 0x080c, - 0x3c5b, 0x1904, 0x25c6, 0x781b, 0x0068, 0x70b8, 0xa06d, 0x68b4, - 0x785a, 0x6894, 0x78d6, 0x78de, 0x6898, 0x78d2, 0x78da, 0x7808, - 0xc08d, 0x780a, 0x68bc, 0x703e, 0xc1b4, 0x71d2, 0x70b4, 0xa065, - 0x68c0, 0x7056, 0x7003, 0x0002, 0x2d00, 0x704a, 0xad80, 0x0009, - 0x7042, 0x0005, 0x080c, 0x3c5b, 0x1120, 0x781b, 0x0054, 0x7003, - 0x0004, 0x0005, 0x080c, 0x3c5b, 0x1128, 0x2011, 0x000c, 0x0419, - 0x7003, 0x0004, 0x0005, 0x080c, 0x3c5b, 0x1128, 0x2011, 0x0006, - 0x00d1, 0x7003, 0x0004, 0x0005, 0x080c, 0x3c5b, 0x1128, 0x2011, - 0x000d, 0x0089, 0x7003, 0x0004, 0x0005, 0x080c, 0x3c5b, 0x1150, - 0x2011, 0x0006, 0x0041, 0x7078, 0x707b, 0x0000, 0x2068, 0x704a, - 0x7003, 0x0004, 0x0005, 0x7170, 0xc1fc, 0x8107, 0x7882, 0x789b, - 0x0080, 0xa286, 0x000c, 0x1120, 0x7aaa, 0x2001, 0x0001, 0x0098, - 0xa18c, 0x001f, 0xa18d, 0x00c0, 0x79aa, 0xa286, 0x000d, 0x0120, - 0x7aaa, 0x2001, 0x0002, 0x0038, 0x78ab, 0x0020, 0x7174, 0x79aa, - 0x7aaa, 0x2001, 0x0004, 0x789b, 0x0060, 0x78aa, 0x785b, 0x0004, - 0x781b, 0x0113, 0x080c, 0x3c6e, 0x707f, 0x000f, 0x70d0, 0xd0b4, - 0x0168, 0xc0b4, 0x70d2, 0x00c6, 0x70b4, 0xa065, 0x6008, 0xa084, - 0xfbef, 0x600a, 0x6018, 0x8001, 0x601a, 0x00ce, 0x0005, 0x7014, - 0xa005, 0x1138, 0x70d0, 0xd0b4, 0x0128, 0x70b4, 0xac06, 0x1110, - 0x0c29, 0x0005, 0x0016, 0x71a0, 0xa186, 0x0001, 0x0528, 0x00d6, - 0x0026, 0x2100, 0x2011, 0x0001, 0xa212, 0x70b0, 0x2068, 0x6800, - 0xac06, 0x0120, 0x8211, 0x01b0, 0x00c9, 0x0cc8, 0x00c6, 0x2100, - 0x2011, 0x0001, 0xa212, 0x70b0, 0x2068, 0x6800, 0x2060, 0x6008, - 0xa084, 0xfbef, 0x600a, 0x8211, 0x0110, 0x0041, 0x0cb0, 0x70a3, - 0x0001, 0x00ce, 0x002e, 0x00de, 0x001e, 0x0005, 0xade8, 0x0005, - 0x70a8, 0xad06, 0x1110, 0x70a4, 0x2068, 0x0005, 0x080c, 0x3c5b, - 0x1904, 0x25c6, 0x7078, 0x2068, 0x7770, 0x080c, 0x3b95, 0x2c50, - 0x080c, 0x3cf6, 0x789b, 0x0080, 0x6814, 0xa084, 0x001f, 0xc0bd, - 0x78aa, 0x6e1c, 0x2041, 0x0001, 0x2001, 0x0004, 0x0804, 0x2850, - 0x080c, 0x3c5b, 0x1904, 0x25c6, 0x789b, 0x0080, 0x705c, 0x2068, - 0x6f14, 0x70d0, 0xd0b4, 0x0168, 0xc0b4, 0x70d2, 0x00c6, 0x70b4, - 0xa065, 0x6008, 0xa084, 0xfbef, 0x600a, 0x6018, 0x8001, 0x601a, - 0x00ce, 0x080c, 0x3b95, 0x2c50, 0x080c, 0x3cf6, 0x6824, 0xa005, - 0x0130, 0xa082, 0x0006, 0x0208, 0x0010, 0x6827, 0x0005, 0x6814, - 0xa084, 0x001f, 0xc0bd, 0x78aa, 0x2031, 0x0020, 0x2041, 0x0001, - 0x2001, 0x0003, 0x0804, 0x2850, 0xc28d, 0x72d2, 0x72bc, 0xa200, - 0xa015, 0x7150, 0x8108, 0xa12a, 0x0208, 0x71bc, 0x2164, 0x6504, - 0x85ff, 0x1170, 0x7152, 0x8421, 0x1da8, 0x70d0, 0xd08c, 0x0128, - 0x70cc, 0xa005, 0x1110, 0x70cf, 0x000a, 0x0005, 0x2200, 0x0c90, - 0x70d0, 0xc08c, 0x70d2, 0x70cf, 0x0000, 0x6034, 0xa005, 0x1db0, - 0x6708, 0xa784, 0x073f, 0x01d0, 0xd7d4, 0x1d80, 0xa784, 0x0021, - 0x1d68, 0xa784, 0x0002, 0x0130, 0xa784, 0x0004, 0x0d38, 0xa7bc, - 0xfffb, 0x670a, 0xa784, 0x0218, 0x1d08, 0xa784, 0x0100, 0x0130, - 0x6018, 0xa005, 0x19d8, 0xa7bc, 0xfeff, 0x670a, 0x2568, 0x6823, - 0x0000, 0x6e1c, 0xa684, 0x000e, 0x6318, 0x0128, 0x601c, 0xa302, - 0x0220, 0x0118, 0x0858, 0x83ff, 0x1948, 0x2d58, 0x2c50, 0x7152, - 0xd7bc, 0x1120, 0x7028, 0x6022, 0x603a, 0x0010, 0xc7bc, 0x670a, - 0x68c0, 0xa065, 0xa04d, 0x6100, 0x2a60, 0x2041, 0x0001, 0x6b14, - 0xa39c, 0x001f, 0xa39d, 0x00c0, 0xd1fc, 0x0110, 0xd684, 0x0110, - 0xa39c, 0xffbf, 0xd6a4, 0x0110, 0xa39d, 0x0020, 0xa684, 0x000e, - 0x1904, 0x2802, 0xc7a5, 0x670a, 0x2c00, 0x68c6, 0x77a0, 0xa786, - 0x0001, 0x1178, 0x70d0, 0xd0b4, 0x1160, 0x7000, 0xa082, 0x0002, - 0x1240, 0x7830, 0xd0bc, 0x1128, 0x789b, 0x0080, 0x7baa, 0x0804, - 0x2849, 0x8739, 0x77a2, 0x2750, 0x77ac, 0xa7b0, 0x0005, 0x70a8, - 0xa606, 0x1108, 0x76a4, 0x76ae, 0x2c3a, 0x8738, 0x2d3a, 0x8738, - 0x283a, 0x8738, 0x233a, 0x8738, 0x253a, 0x7830, 0xd0bc, 0x0150, - 0x2091, 0x8000, 0x2091, 0x303d, 0x70d0, 0xa084, 0x303d, 0x2091, - 0x8000, 0x2090, 0xaad5, 0x0000, 0x0120, 0x8421, 0x2200, 0x1904, - 0x2751, 0x0005, 0xd1dc, 0x0904, 0x37f1, 0x2029, 0x0020, 0xd69c, - 0x1120, 0x8528, 0xd68c, 0x1108, 0x8528, 0x8840, 0x6f14, 0x610c, - 0x8108, 0xa18c, 0x00ff, 0x70c8, 0xa160, 0x2c64, 0x8cff, 0x0188, - 0x6014, 0xa706, 0x1dd0, 0x60b8, 0x8001, 0x60ba, 0x1d88, 0x2a60, - 0x6008, 0xa085, 0x0100, 0x600a, 0x2200, 0x8421, 0x1904, 0x2751, - 0x0005, 0x2a60, 0x610e, 0x69be, 0x2c00, 0x68c6, 0x8840, 0x6008, - 0xc0d5, 0x600a, 0x77a0, 0xa786, 0x0001, 0x1904, 0x27d9, 0x70d0, - 0xd0b4, 0x1904, 0x27d9, 0x7000, 0xa082, 0x0002, 0x1a04, 0x27d9, - 0x7830, 0xd0bc, 0x1904, 0x27d9, 0x789b, 0x0080, 0x7baa, 0x7daa, - 0x79aa, 0x2001, 0x0002, 0x0006, 0x6018, 0x8000, 0x601a, 0x0008, - 0x0006, 0x2960, 0x6104, 0x2a60, 0x080c, 0x3d09, 0x1590, 0xa184, - 0x0018, 0x0180, 0xa184, 0x0010, 0x0118, 0x080c, 0x399a, 0x1548, - 0xa184, 0x0008, 0x0138, 0x69a0, 0xa184, 0x0600, 0x1118, 0x080c, - 0x38b8, 0x00f8, 0x69a0, 0xa184, 0x1e00, 0x0528, 0xa184, 0x0800, - 0x0178, 0x00c6, 0x2960, 0x6000, 0xa085, 0x2000, 0x6002, 0x6104, - 0xa18d, 0x0010, 0x6106, 0x00ce, 0x080c, 0x399a, 0x1150, 0x69a0, - 0xa184, 0x0200, 0x0118, 0x080c, 0x38fd, 0x0018, 0xa184, 0x0400, - 0x19f0, 0x69a0, 0xa184, 0x1000, 0x0130, 0x6914, 0xa18c, 0xff00, - 0x810f, 0x080c, 0x23c5, 0x002e, 0xa68c, 0x00e0, 0xa684, 0x0060, - 0x0128, 0xa086, 0x0060, 0x1110, 0xa18d, 0x4000, 0xa18d, 0x0104, - 0x69b6, 0x789b, 0x0060, 0x2800, 0x78aa, 0x6818, 0xc0fd, 0x681a, - 0xd6bc, 0x0168, 0xc0fc, 0x7083, 0x0000, 0xa08a, 0x000d, 0x0328, - 0xa08a, 0x000c, 0x7182, 0x2001, 0x000c, 0x800c, 0x7186, 0x78aa, - 0x3518, 0x3340, 0x3428, 0x8000, 0x80ac, 0xaf80, 0x002b, 0x20a0, - 0x789b, 0x0000, 0xad80, 0x000b, 0x2098, 0x53a6, 0x23a8, 0x2898, - 0x25a0, 0xa286, 0x0020, 0x1508, 0x70d0, 0xc0b5, 0x70d2, 0x2c00, - 0x70b6, 0x2d00, 0x70ba, 0x6814, 0xc0fc, 0x8007, 0x7882, 0xa286, - 0x0002, 0x0904, 0x2921, 0x70a0, 0x8000, 0x70a2, 0x74b0, 0xa498, - 0x0005, 0x70a8, 0xa306, 0x1108, 0x73a4, 0x73b2, 0xa286, 0x0010, - 0x0904, 0x25c6, 0x00de, 0x00ce, 0x0005, 0x7000, 0xa005, 0x19e0, - 0xa286, 0x0002, 0x1904, 0x2938, 0x080c, 0x3c5b, 0x19a8, 0x6814, - 0xc0fc, 0x8007, 0x7882, 0x2091, 0x8000, 0x781b, 0x0068, 0x68b4, - 0x785a, 0x6894, 0x78d6, 0x78de, 0x6898, 0x78d2, 0x78da, 0x2091, - 0x8001, 0x7808, 0xc08d, 0x780a, 0x0126, 0x00d6, 0x00c6, 0x70d0, - 0xa084, 0x2e00, 0x2090, 0x00ce, 0x00de, 0x012e, 0x2900, 0x7056, - 0x68bc, 0x703e, 0x7003, 0x0002, 0x2d00, 0x704a, 0xad80, 0x0009, - 0x7042, 0x7830, 0xd0bc, 0x0140, 0x2091, 0x303d, 0x70d0, 0xa084, - 0x303d, 0x2091, 0x8000, 0x2090, 0x70a0, 0xa005, 0x1108, 0x0005, - 0x8421, 0x0de8, 0x724c, 0x70bc, 0xa200, 0xa015, 0x0804, 0x2751, - 0xa286, 0x0010, 0x1560, 0x080c, 0x3c5b, 0x1904, 0x28cc, 0x6814, - 0xc0fc, 0x8007, 0x7882, 0x781b, 0x0068, 0x68b4, 0x785a, 0x6894, - 0x78d6, 0x78de, 0x6898, 0x78d2, 0x78da, 0x7808, 0xc08d, 0x780a, - 0x70a0, 0x8000, 0x70a2, 0x74b0, 0xa490, 0x0005, 0x70a8, 0xa206, - 0x1108, 0x72a4, 0x72b2, 0x2900, 0x7056, 0x68bc, 0x703e, 0x7003, - 0x0002, 0x2d00, 0x704a, 0xad80, 0x0009, 0x7042, 0x0005, 0x6bb4, - 0xa39d, 0x2000, 0x7b5a, 0x6814, 0xc0fc, 0x8007, 0x7882, 0x6b94, - 0x7bd6, 0x7bde, 0x6e98, 0x7ed2, 0x7eda, 0x781b, 0x0068, 0x2900, - 0x7056, 0x7202, 0x7808, 0xc08d, 0x780a, 0x2300, 0xa605, 0x0170, - 0x70d0, 0xa084, 0x2e00, 0xa086, 0x2600, 0x1118, 0x2009, 0x0000, - 0x0010, 0x2009, 0x0001, 0xa284, 0x000f, 0x0033, 0xad80, 0x0009, - 0x7042, 0x2d00, 0x704a, 0x0005, 0x299c, 0x4208, 0x4208, 0x41f6, - 0x4208, 0x299c, 0x299c, 0x299c, 0x080c, 0x2575, 0x7808, 0xa084, - 0xfffd, 0x780a, 0x00f6, 0x2079, 0x4700, 0x78ac, 0x00fe, 0xd084, - 0x01c0, 0x7160, 0xa186, 0x0001, 0x0904, 0x2a61, 0xa186, 0x0007, - 0x0170, 0xa186, 0x0005, 0x1158, 0x7078, 0x2068, 0x681b, 0x0004, - 0x6817, 0x0000, 0x6820, 0xa084, 0x00ff, 0xc09d, 0x6822, 0x7063, - 0x0000, 0x70a3, 0x0000, 0x70a4, 0x70ae, 0x70b2, 0x080c, 0x26ae, - 0x0156, 0x2011, 0x0004, 0x7160, 0xa186, 0x0001, 0x0158, 0xa186, - 0x0007, 0x1118, 0x701f, 0x0005, 0x0010, 0x701f, 0x0001, 0x70d0, - 0xc0c5, 0x70d2, 0x2001, 0x470a, 0x2004, 0xa084, 0x00ff, 0xa086, - 0x0018, 0x0130, 0x7018, 0x7016, 0xa005, 0x1110, 0x70a3, 0x0001, - 0x0066, 0x080c, 0x3f4e, 0x20a9, 0x0010, 0x2039, 0x0000, 0x080c, - 0x3a8b, 0xa7b8, 0x0100, 0x1f04, 0x29ef, 0x006e, 0x7000, 0x0002, - 0x2a2c, 0x2a0a, 0x2a0a, 0x2a02, 0x2a2c, 0x2a2c, 0x2a2c, 0x2a00, - 0x080c, 0x2575, 0x705c, 0xa005, 0x0538, 0xad06, 0x1118, 0x6800, - 0x705e, 0x0080, 0x6820, 0xd084, 0x1148, 0x6f14, 0x080c, 0x3b95, - 0x6008, 0xc0d4, 0x600a, 0x080c, 0x37c7, 0x0020, 0x7058, 0x2060, - 0x6800, 0x6002, 0xa684, 0x5f00, 0x681e, 0x6818, 0xd0fc, 0x0108, - 0x6a1a, 0x6817, 0x0000, 0x682b, 0x0000, 0x6820, 0xa084, 0x00ff, - 0xc09d, 0x6822, 0x080c, 0x1dbf, 0x2011, 0x0004, 0x74c8, 0xa4a0, - 0x0100, 0x04b1, 0xaea0, 0x0017, 0x0499, 0x20a9, 0x0101, 0x74c8, - 0x0479, 0x8420, 0x1f04, 0x2a38, 0x70c0, 0x2060, 0x2021, 0x0002, - 0x20a9, 0x0100, 0x6110, 0x81ff, 0x0198, 0x6018, 0x0016, 0x0006, - 0x2011, 0x4702, 0x220c, 0xa102, 0x2012, 0x000e, 0x001e, 0xa102, - 0x0338, 0x6012, 0x1128, 0x2011, 0x4704, 0x2204, 0xc0a5, 0x2012, - 0x601b, 0x0000, 0xace0, 0x0010, 0x1f04, 0x2a42, 0x8421, 0x1d00, - 0x015e, 0x7063, 0x0000, 0x7003, 0x0000, 0x704b, 0x0000, 0x0005, - 0x0046, 0x2404, 0xa005, 0x01a8, 0x2068, 0x6800, 0x0006, 0x6a1a, - 0x6817, 0x0000, 0x682b, 0x0000, 0x68b4, 0xa084, 0x5f00, 0x681e, - 0x6820, 0xa084, 0x00ff, 0xc09d, 0x6822, 0x080c, 0x1dbf, 0x000e, - 0x0c48, 0x004e, 0x2023, 0x0000, 0x0005, 0xa282, 0x0003, 0x0310, - 0x080c, 0x2575, 0x2300, 0x0002, 0x2a8f, 0x2b0c, 0x2b1a, 0xa282, - 0x0002, 0x0110, 0x080c, 0x2575, 0x7060, 0x7063, 0x0000, 0x707f, - 0x0000, 0x0022, 0x77d0, 0xc7c5, 0x77d2, 0x0002, 0x2aa6, 0x2aa6, - 0x2aa8, 0x2ae0, 0x37fb, 0x2aa6, 0x2ae0, 0x2aa6, 0x080c, 0x2575, - 0x7770, 0x080c, 0x3a8b, 0x7770, 0xa7bc, 0x8f00, 0x080c, 0x3b95, - 0x6018, 0xa005, 0x0528, 0xd7fc, 0x1118, 0x2021, 0x8dc0, 0x0010, - 0x2021, 0x8ed0, 0x2009, 0x0005, 0x2011, 0x0010, 0x080c, 0x2b34, - 0x01b8, 0x0156, 0x20a9, 0x0101, 0xd7fc, 0x1118, 0x2021, 0x8cc0, - 0x0010, 0x2021, 0x8dd0, 0x0046, 0x2009, 0x0005, 0x2011, 0x0010, - 0x080c, 0x2b34, 0x004e, 0x0118, 0x8420, 0x1f04, 0x2acb, 0x015e, - 0x8738, 0xa784, 0x001f, 0x1990, 0x0804, 0x25c9, 0x0804, 0x25c9, - 0x7770, 0x080c, 0x3b95, 0x6018, 0xa005, 0x0520, 0xd7fc, 0x1118, - 0x2021, 0x8dc0, 0x0010, 0x2021, 0x8ed0, 0x2009, 0x0005, 0x2011, - 0x0020, 0x080c, 0x2b34, 0x01b0, 0x0156, 0x20a9, 0x0101, 0xd7fc, - 0x1118, 0x2021, 0x8cc0, 0x0010, 0x2021, 0x8dd0, 0x0046, 0x2009, - 0x0005, 0x2011, 0x0020, 0x0481, 0x004e, 0x0118, 0x8420, 0x1f04, - 0x2afe, 0x015e, 0x0804, 0x25c9, 0x2200, 0x0002, 0x2b11, 0x2b13, - 0x2b13, 0x080c, 0x2575, 0x7063, 0x0000, 0x70d0, 0xc0c5, 0x70d2, - 0x0804, 0x25c9, 0x2200, 0x0002, 0x2b21, 0x2b13, 0x2b1f, 0x080c, - 0x2575, 0x080c, 0x3f4e, 0x7000, 0xa086, 0x0002, 0x1904, 0x3780, - 0x080c, 0x37e1, 0x6008, 0xa084, 0xfbef, 0x600a, 0x080c, 0x3772, - 0x0904, 0x3780, 0x0804, 0x25c9, 0x2404, 0xa005, 0x0590, 0x2068, - 0x2d04, 0x0006, 0x6814, 0xa706, 0x0118, 0x2d20, 0x000e, 0x0ca8, - 0x000e, 0x2022, 0x691a, 0x6817, 0x0000, 0x682b, 0x0000, 0x68b4, - 0xa084, 0x5f00, 0x681e, 0x6820, 0xa084, 0x00ff, 0xa205, 0x6822, - 0x080c, 0x1dbf, 0x2021, 0x4702, 0x241c, 0x8319, 0x2322, 0x6010, - 0x8001, 0x6012, 0x1128, 0x2021, 0x4704, 0x2404, 0xc0a5, 0x2022, - 0x6008, 0xa084, 0xf9ef, 0x600a, 0x080c, 0x26ca, 0x080c, 0x37e1, - 0x0005, 0xa085, 0x0001, 0x0ce0, 0x2300, 0x0002, 0x2b73, 0x2b71, - 0x2bee, 0x080c, 0x2575, 0x78e4, 0xa005, 0x17b0, 0x3208, 0xa18c, - 0x0800, 0x0118, 0x0104, 0x25c6, 0x0010, 0x0304, 0x25c6, 0x2008, - 0xa084, 0x0030, 0x1110, 0x0804, 0x324d, 0x78ec, 0xa084, 0x0003, - 0x0dd0, 0x7884, 0xd0fc, 0x1118, 0xa184, 0x0007, 0x0090, 0xa184, - 0x0007, 0xa086, 0x0004, 0x1118, 0x2001, 0x0000, 0x0050, 0xa184, - 0x0007, 0xa086, 0x0005, 0x0118, 0xa184, 0x0007, 0x0010, 0x2001, - 0x0001, 0x0002, 0x2bd1, 0x2bda, 0x2bc7, 0x2baa, 0x3c4f, 0x3c4f, - 0x2baa, 0x2be4, 0x080c, 0x2575, 0x7000, 0xa086, 0x0004, 0x1190, - 0x7060, 0xa086, 0x0002, 0x1130, 0x2011, 0x0002, 0x2019, 0x0000, - 0x0804, 0x2a85, 0x7060, 0xa086, 0x0006, 0x0db0, 0x7060, 0xa086, - 0x0004, 0x0d90, 0x79e4, 0x2001, 0x0003, 0x0804, 0x2f3b, 0x6818, - 0xd0fc, 0x0110, 0x681b, 0x001d, 0x080c, 0x3a61, 0x781b, 0x006e, - 0x0005, 0x6818, 0xd0fc, 0x0110, 0x681b, 0x001d, 0x080c, 0x3a61, - 0x0804, 0x3c2d, 0x6818, 0xd0fc, 0x0110, 0x681b, 0x001d, 0x080c, - 0x3a61, 0x781b, 0x00fa, 0x0005, 0x6818, 0xd0fc, 0x0110, 0x681b, - 0x001d, 0x080c, 0x3a61, 0x781b, 0x00cb, 0x0005, 0xa584, 0x000f, - 0x11c0, 0x7000, 0x0002, 0x25c9, 0x2bfb, 0x2bfd, 0x3780, 0x3780, - 0x3780, 0x2bfb, 0x2bfb, 0x080c, 0x2575, 0x080c, 0x37e1, 0x6008, - 0xa084, 0xfbef, 0x600a, 0x080c, 0x3772, 0x0904, 0x3780, 0x0804, - 0x25c9, 0x78e4, 0xa005, 0x1b04, 0x2bac, 0x3208, 0xa18c, 0x0800, - 0x0118, 0x0104, 0x2bac, 0x0010, 0x0304, 0x2bac, 0x2008, 0xa084, - 0x0030, 0x1118, 0x781b, 0x0068, 0x0005, 0x78ec, 0xa084, 0x0003, - 0x0dc8, 0x7884, 0xd0fc, 0x1118, 0xa184, 0x0007, 0x0090, 0xa184, - 0x0007, 0xa086, 0x0004, 0x1118, 0x2001, 0x0000, 0x0050, 0xa184, - 0x0007, 0xa086, 0x0005, 0x0118, 0xa184, 0x0007, 0x0010, 0x2001, - 0x0001, 0x0002, 0x2c49, 0x2c4d, 0x2c44, 0x2c42, 0x3c4f, 0x3c4f, - 0x2c42, 0x3c49, 0x080c, 0x2575, 0x080c, 0x3a67, 0x781b, 0x006e, - 0x0005, 0x080c, 0x3a67, 0x0804, 0x3c2d, 0x080c, 0x3a67, 0x781b, - 0x00fa, 0x0005, 0x080c, 0x3a67, 0x781b, 0x00cb, 0x0005, 0x2300, - 0x0002, 0x2c5e, 0x2c5c, 0x2c60, 0x080c, 0x2575, 0x0804, 0x3405, - 0x681b, 0x0016, 0x78a3, 0x0000, 0x79e4, 0xa184, 0x0030, 0x0904, - 0x3405, 0x78ec, 0xa084, 0x0003, 0x0904, 0x3405, 0xa184, 0x0100, - 0x0d98, 0x7884, 0xd0fc, 0x1118, 0xa184, 0x0007, 0x0090, 0xa184, - 0x0007, 0xa086, 0x0004, 0x1118, 0x2001, 0x0000, 0x0050, 0xa184, - 0x0007, 0xa086, 0x0005, 0x0118, 0xa184, 0x0007, 0x0010, 0x2001, - 0x0001, 0x0002, 0x2c92, 0x2c4d, 0x2bc7, 0x3c0b, 0x3c4f, 0x3c4f, - 0x3c0b, 0x3c49, 0x080c, 0x3c17, 0x0005, 0xa282, 0x0005, 0x0310, - 0x080c, 0x2575, 0x7898, 0x2040, 0x2300, 0x0002, 0x2ca1, 0x2ecb, - 0x2ed5, 0x2200, 0x0002, 0x2cbd, 0x2caa, 0x2cbd, 0x2ca8, 0x2ead, - 0x080c, 0x2575, 0x789b, 0x0018, 0x78a8, 0x2010, 0xa084, 0x00ff, - 0xa082, 0x0020, 0x0a04, 0x3a30, 0xa08a, 0x0004, 0x1a04, 0x3a30, - 0x0002, 0x3a30, 0x3a30, 0x3a30, 0x39e4, 0x789b, 0x0018, 0x79a8, - 0xa184, 0x0080, 0x0148, 0x0804, 0x3a30, 0x7000, 0xa005, 0x1dd8, - 0x2011, 0x0004, 0x0804, 0x35b7, 0xa184, 0x00ff, 0xa08a, 0x0010, - 0x1a04, 0x3a30, 0x0002, 0x2ce5, 0x2ce3, 0x2cf7, 0x2cfb, 0x2da9, - 0x3a30, 0x3a30, 0x2dab, 0x3a30, 0x3a30, 0x2ea9, 0x2ea9, 0x3a30, - 0x3a30, 0x3a30, 0x2eab, 0x080c, 0x2575, 0xd6e4, 0x0140, 0x2001, - 0x0300, 0x8000, 0x8000, 0x783a, 0x781b, 0x00c7, 0x0005, 0x6818, - 0xd0fc, 0x0118, 0x681b, 0x001d, 0x0c90, 0x0804, 0x3c0b, 0x681b, - 0x001d, 0x0804, 0x3a5b, 0x6920, 0x6922, 0xa684, 0x1800, 0x1904, - 0x2d4c, 0x6820, 0xd084, 0x1904, 0x2d54, 0x6818, 0xa086, 0x0008, - 0x1110, 0x681b, 0x0000, 0xd6d4, 0x0568, 0xd6bc, 0x0558, 0x7083, - 0x0000, 0x6818, 0xa084, 0x003f, 0xa08a, 0x000d, 0x0718, 0xa08a, - 0x000c, 0x7182, 0x2001, 0x000c, 0x800c, 0x7186, 0x789b, 0x0061, - 0x78aa, 0x0156, 0x0136, 0x0146, 0x0016, 0x3208, 0xa18c, 0x0600, - 0x0118, 0x20a1, 0x022b, 0x0010, 0x20a1, 0x012b, 0x001e, 0x789b, - 0x0000, 0x8000, 0x80ac, 0xad80, 0x000b, 0x2098, 0x53a6, 0x014e, - 0x013e, 0x015e, 0x6038, 0xa005, 0x1150, 0x681c, 0xa084, 0x000e, - 0x0904, 0x3a5b, 0x080c, 0x3a6d, 0x782b, 0x3008, 0x0010, 0x8001, - 0x603a, 0x781b, 0x0071, 0x0005, 0xd6e4, 0x0130, 0x781b, 0x0083, - 0x0005, 0x781b, 0x0083, 0x0005, 0xa684, 0x0060, 0x0dd0, 0xd6dc, - 0x0dc0, 0xd6fc, 0x01a0, 0xc6fc, 0x7e5a, 0x6eb6, 0x7adc, 0x79d8, - 0x78d0, 0x8007, 0xa084, 0x007f, 0xa108, 0xa291, 0x0000, 0x6b98, - 0x2100, 0xa302, 0x68b2, 0x6b94, 0x2200, 0xa303, 0x68ae, 0xd6f4, - 0x0118, 0xc6f4, 0x7e5a, 0x6eb6, 0x7000, 0xa086, 0x0003, 0x1148, - 0x0006, 0x080c, 0x3f4e, 0x080c, 0x4208, 0x000e, 0x781b, 0x0080, - 0x0005, 0xa006, 0x080c, 0x42e8, 0x6ab0, 0x69ac, 0x6c98, 0x6b94, - 0x2200, 0xa105, 0x0120, 0x2200, 0xa422, 0x2100, 0xa31b, 0x6caa, - 0x7cd2, 0x7cda, 0x6ba6, 0x7bd6, 0x7bde, 0x2300, 0xa405, 0x1130, - 0xc6f5, 0x7e5a, 0x6eb6, 0x781b, 0x0080, 0x0005, 0x781b, 0x0080, - 0x2200, 0xa115, 0x1118, 0x080c, 0x4208, 0x0005, 0x080c, 0x4235, - 0x0005, 0x080c, 0x2575, 0x0804, 0x2e3f, 0x00c6, 0x7054, 0x2060, - 0x6920, 0xa18c, 0xecff, 0x6922, 0x6000, 0xa084, 0xcfdf, 0x6002, - 0x080c, 0x3917, 0xa006, 0x2040, 0x2038, 0x080c, 0x39bf, 0x0804, - 0x2e33, 0x00c6, 0x7054, 0x2060, 0x2c48, 0x7aa8, 0xa294, 0x00ff, - 0xa286, 0x0004, 0x11d8, 0x6920, 0xd1e4, 0x1170, 0x2039, 0x0000, - 0x2041, 0x0000, 0x2031, 0x0000, 0xa006, 0x2010, 0x080c, 0x391a, - 0x080c, 0x39bf, 0x0804, 0x2e33, 0xa18c, 0xecff, 0x6922, 0x6104, - 0xa18c, 0xffdd, 0x6106, 0x6000, 0xc0ac, 0x6002, 0xa286, 0x0003, - 0x01d0, 0x6104, 0xa184, 0x0010, 0x0548, 0x080c, 0x3b91, 0x080c, - 0x399a, 0x88ff, 0x0518, 0x00ce, 0x789b, 0x0060, 0x2800, 0x78aa, - 0x7e58, 0xc695, 0x7e5a, 0xd6d4, 0x1118, 0x781b, 0x006e, 0x0005, - 0x781b, 0x0082, 0x0005, 0x6920, 0xd1cc, 0x0130, 0xa18c, 0xfdff, - 0x6922, 0x6000, 0xc0ec, 0x6002, 0x2039, 0x0000, 0x2041, 0x0000, - 0x2031, 0x0000, 0xa006, 0x2010, 0x080c, 0x39bf, 0xa286, 0x0001, - 0x0158, 0x6104, 0xa184, 0x0008, 0x01b0, 0x080c, 0x3b91, 0x080c, - 0x38b8, 0x88ff, 0x1980, 0x0078, 0x6920, 0xd1c4, 0x0130, 0xa18c, - 0xfeff, 0x6922, 0x6000, 0xc0e4, 0x6002, 0x2031, 0x0000, 0xa006, - 0x2010, 0x080c, 0x391a, 0x00ce, 0x7e58, 0xd6d4, 0x1118, 0x781b, - 0x0071, 0x0005, 0x781b, 0x0083, 0x0005, 0x0804, 0x3a57, 0x2808, - 0x789b, 0x0080, 0x2019, 0x0080, 0x78a8, 0xa094, 0x00ff, 0xa286, - 0x0001, 0x11b8, 0x2300, 0xa102, 0xa086, 0x0001, 0x0904, 0x2dad, - 0x7ca8, 0xa4a4, 0x00ff, 0xa480, 0x0002, 0xa300, 0x2018, 0xa102, - 0x0a04, 0x2dc1, 0x0904, 0x2dc1, 0x24a8, 0x7aa8, 0x1f04, 0x2e5d, - 0x0c18, 0xa284, 0x00f0, 0xa082, 0x0020, 0x06b8, 0x2200, 0xa082, - 0x0021, 0x1698, 0x7aa8, 0x8318, 0x8318, 0x2100, 0xa302, 0x0aa0, - 0xa286, 0x0023, 0x0950, 0x681c, 0xa084, 0xfff1, 0x681e, 0x7e58, - 0xa684, 0xfff1, 0xc0a5, 0x2030, 0x7e5a, 0x6008, 0xc0a5, 0x600a, - 0x78a0, 0xa005, 0x0904, 0x2e34, 0x20a8, 0x7998, 0x789b, 0x0060, - 0x78aa, 0x2011, 0x0080, 0x799a, 0x78a8, 0x7998, 0x7a9a, 0x78aa, - 0x7a98, 0x1f04, 0x2e8b, 0xc695, 0x7e5a, 0xd6d4, 0x1118, 0x781b, - 0x006e, 0x0005, 0x781b, 0x0082, 0x0005, 0x8318, 0x2100, 0xa302, - 0x0a04, 0x2e44, 0xa284, 0x0080, 0x1904, 0x3a5b, 0x78a0, 0xa005, - 0x08c8, 0x0804, 0x3a5b, 0x0804, 0x3a30, 0x7054, 0xa04d, 0x789b, - 0x0018, 0x78a8, 0xa084, 0x00ff, 0xa08e, 0x0001, 0x0110, 0x080c, - 0x2575, 0x7aa8, 0xa294, 0x00ff, 0x784b, 0x0008, 0x78a8, 0xa084, - 0x00ff, 0xa08a, 0x0005, 0x1a04, 0x3a30, 0x0002, 0x3a30, 0x382f, - 0x3a30, 0x394a, 0x3d59, 0xa282, 0x0000, 0x1110, 0x080c, 0x2575, - 0x080c, 0x3a61, 0x781b, 0x0082, 0x0005, 0xa282, 0x0003, 0x1110, - 0x080c, 0x2575, 0xd4fc, 0x11d0, 0x7060, 0xa005, 0x0110, 0x080c, - 0x2575, 0x6f14, 0x7772, 0xa7bc, 0x8f00, 0x080c, 0x3b95, 0x6008, - 0xa085, 0x0021, 0x600a, 0x8738, 0xa784, 0x001f, 0x1db0, 0x080c, - 0x3a64, 0x7063, 0x0002, 0x701f, 0x0009, 0x0010, 0x080c, 0x3a70, - 0x781b, 0x0082, 0x0005, 0xa282, 0x0004, 0x0310, 0x080c, 0x2575, - 0x2300, 0x0002, 0x2f05, 0x309b, 0x30d7, 0xa286, 0x0003, 0x0598, - 0x7200, 0x7cd8, 0x7ddc, 0x7fd0, 0x71d0, 0xd1b4, 0x0528, 0xd1bc, - 0x1518, 0x2001, 0x4701, 0x2004, 0xd0c4, 0x11f0, 0x7868, 0xa084, - 0x00ff, 0x11d0, 0xa282, 0x0002, 0x12b8, 0x00d6, 0x783b, 0x8300, - 0x781b, 0x0059, 0x70b8, 0xa06d, 0x68b4, 0x785a, 0x6894, 0x78d6, - 0x78de, 0x6898, 0x78d2, 0x78da, 0xc1b4, 0x71d2, 0x7003, 0x0030, - 0x00de, 0x2001, 0x0000, 0x0058, 0x783b, 0x1300, 0x781b, 0x0057, - 0x2001, 0x0000, 0x0020, 0x7200, 0x7cd8, 0x7ddc, 0x7fd0, 0x7046, - 0x68a0, 0xd0ec, 0x0118, 0x6008, 0xc08d, 0x600a, 0xa284, 0x000f, - 0x0002, 0x307c, 0x2f56, 0x2f53, 0x31a7, 0x3232, 0x25c9, 0x2f51, - 0x2f51, 0x080c, 0x2575, 0x6008, 0xc0d4, 0x600a, 0xd6e4, 0x0120, - 0x7044, 0xa086, 0x0014, 0x11e8, 0x080c, 0x3f4e, 0x2009, 0x0000, - 0x6818, 0xd0fc, 0x0108, 0x7044, 0xa086, 0x0014, 0x0168, 0x6818, - 0xa086, 0x0008, 0x1904, 0x303e, 0x7858, 0xd09c, 0x0904, 0x303e, - 0x6820, 0xd0ac, 0x0904, 0x303e, 0x681b, 0x0014, 0x2009, 0x0002, - 0x04a8, 0x7868, 0xa08c, 0x00ff, 0x0588, 0xa186, 0x0008, 0x1158, - 0x6008, 0xc0a4, 0x600a, 0x080c, 0x3772, 0x0540, 0x080c, 0x37e1, - 0x080c, 0x3f4e, 0x0060, 0xa186, 0x0028, 0x1500, 0x6018, 0xa005, - 0x0d78, 0x8001, 0x0d68, 0x8001, 0x0d58, 0x601e, 0x0c48, 0x6820, - 0xd084, 0x0904, 0x25c9, 0xc084, 0x6822, 0x080c, 0x26bf, 0x7058, - 0x00c6, 0x2060, 0x6800, 0x6002, 0x00ce, 0x6004, 0x6802, 0xa005, - 0x2d00, 0x1108, 0x6002, 0x6006, 0x0804, 0x25c9, 0x0016, 0x81ff, - 0x15f0, 0x7000, 0xa086, 0x0030, 0x05d0, 0x71d0, 0xd1bc, 0x15b8, - 0xd1b4, 0x11e8, 0x705c, 0xa005, 0x1590, 0x70a0, 0xa086, 0x0001, - 0x0570, 0x7003, 0x0000, 0x0046, 0x0056, 0x0076, 0x0066, 0x00c6, - 0x00d6, 0x080c, 0x25f1, 0x00de, 0x00ce, 0x006e, 0x007e, 0x005e, - 0x004e, 0x71d0, 0xd1b4, 0x11d8, 0x7003, 0x0040, 0x00c0, 0x080c, - 0x3c5b, 0x11a8, 0x781b, 0x0068, 0x00d6, 0x70b8, 0xa06d, 0x68b4, - 0x785a, 0x6894, 0x78d6, 0x78de, 0x6898, 0x78d2, 0x78da, 0xc1b4, - 0x71d2, 0x7003, 0x0030, 0x7808, 0xc08d, 0x780a, 0x00de, 0x080c, - 0x30ff, 0x001e, 0x81ff, 0x0904, 0x303e, 0xa684, 0xdf00, 0x681e, - 0x682b, 0x0000, 0x6f14, 0xa186, 0x0002, 0x1904, 0x303f, 0x6818, - 0xa086, 0x0014, 0x1130, 0x2008, 0xd6e4, 0x0118, 0x7868, 0xa08c, - 0x00ff, 0x080c, 0x3a7a, 0x080c, 0x26ca, 0x6820, 0xd0dc, 0x1578, - 0x8717, 0xa294, 0x000f, 0x8213, 0x8213, 0x8213, 0xb284, 0x0600, - 0x0118, 0xa290, 0x4bc0, 0x0010, 0xa290, 0x4c40, 0xa290, 0x0000, - 0x221c, 0xd3c4, 0x0170, 0x6820, 0xd0e4, 0x0128, 0xa084, 0xefff, - 0x6822, 0xc3ac, 0x2312, 0x8210, 0x2204, 0xa085, 0x0038, 0x2012, - 0x8211, 0xd3d4, 0x0138, 0x68a0, 0xd0c4, 0x1120, 0x080c, 0x3167, - 0x0804, 0x25c9, 0x6008, 0xc08d, 0x600a, 0x0008, 0x692a, 0x6916, - 0x6818, 0xd0fc, 0x0110, 0x7044, 0x681a, 0xa68c, 0xdf00, 0x691e, - 0x6410, 0x84ff, 0x0168, 0x2009, 0x4702, 0x2104, 0x8001, 0x200a, - 0x8421, 0x6412, 0x1128, 0x2021, 0x4704, 0x2404, 0xc0a5, 0x2022, - 0x6018, 0xa005, 0x0118, 0x8001, 0x601a, 0x1118, 0x6008, 0xc0a4, - 0x600a, 0x6820, 0xd084, 0x1130, 0x6800, 0xa005, 0x1108, 0x6002, - 0x6006, 0x0020, 0x7058, 0x2060, 0x6800, 0x6002, 0x2061, 0x4700, - 0x6887, 0x0103, 0x2d08, 0x206b, 0x0000, 0x6068, 0xa005, 0x616a, - 0x0110, 0x2d02, 0x0008, 0x616e, 0x7200, 0xa286, 0x0030, 0x0158, - 0xa286, 0x0040, 0x1904, 0x25c9, 0x7003, 0x0002, 0x7048, 0x2068, - 0x68c4, 0x2060, 0x0005, 0x7003, 0x0002, 0x70b8, 0xa06d, 0x68bc, - 0x703e, 0x70b4, 0xa065, 0x68c0, 0x7056, 0x2d00, 0x704a, 0xad80, - 0x0009, 0x7042, 0x0005, 0xa282, 0x0004, 0x0210, 0x080c, 0x2575, - 0x2200, 0x0002, 0x30a6, 0x30b5, 0x30c1, 0x30b5, 0xa586, 0x1300, - 0x0160, 0xa586, 0x8300, 0x1d90, 0x7003, 0x0000, 0x6018, 0x8001, - 0x601a, 0x6008, 0xa084, 0xfbef, 0x600a, 0x7000, 0xa086, 0x0005, - 0x0128, 0x080c, 0x3a61, 0x781b, 0x0082, 0x0005, 0x781b, 0x0083, - 0x0005, 0x7890, 0x8007, 0x8001, 0xa084, 0x0007, 0xa080, 0x0018, - 0x789a, 0x79a8, 0xa18c, 0x00ff, 0xa186, 0x0003, 0x0128, 0xa186, - 0x0000, 0x0110, 0x0804, 0x3a30, 0x781b, 0x0083, 0x0005, 0x6820, - 0xc095, 0x6822, 0x82ff, 0x1118, 0x080c, 0x3a61, 0x0030, 0x8211, - 0x0110, 0x080c, 0x2575, 0x080c, 0x3a70, 0x781b, 0x0082, 0x0005, - 0x080c, 0x3c6e, 0x7830, 0xa084, 0x00c0, 0x1170, 0x0016, 0x3208, - 0xa18c, 0x0800, 0x001e, 0x0118, 0x0104, 0x30fc, 0x0010, 0x0304, - 0x30fc, 0x791a, 0xa006, 0x0005, 0xa085, 0x0001, 0x0005, 0xa684, - 0x0060, 0x1130, 0x682f, 0x0000, 0x6833, 0x0000, 0x0804, 0x3166, - 0xd6dc, 0x1198, 0x68b4, 0xd0dc, 0x1180, 0x6998, 0x6a94, 0x692e, - 0x6a32, 0x7044, 0xa005, 0x1130, 0x2200, 0xa105, 0x0904, 0x3f4e, - 0x7047, 0x0015, 0x0804, 0x3f4e, 0x0005, 0xd6ac, 0x01f0, 0xd6f4, - 0x0130, 0x682f, 0x0000, 0x6833, 0x0000, 0x0804, 0x3f4e, 0x68b4, - 0xa084, 0x4000, 0xa635, 0xd6f4, 0x1da0, 0x7044, 0xa005, 0x1110, - 0x7047, 0x0015, 0xd6dc, 0x1128, 0x68b4, 0xd0dc, 0x0110, 0x6ca8, - 0x6da4, 0x6c2e, 0x6d32, 0x0804, 0x3f4e, 0xd6f4, 0x0130, 0x682f, - 0x0000, 0x6833, 0x0000, 0x0804, 0x3f4e, 0x68b4, 0xa084, 0x4800, - 0xa635, 0xd6f4, 0x1da0, 0x7044, 0xa005, 0x1110, 0x7047, 0x0015, - 0x2408, 0x2510, 0x2700, 0x8007, 0xa084, 0x007f, 0xa108, 0xa291, - 0x0000, 0x692e, 0x6a32, 0x2100, 0xa205, 0x1110, 0x0804, 0x3f4e, - 0x7000, 0xa086, 0x0006, 0x0110, 0x0804, 0x3f4e, 0x0005, 0x6946, - 0x6008, 0xc0cd, 0xd3cc, 0x0108, 0xc08d, 0x600a, 0x6818, 0x683a, - 0x681b, 0x0006, 0x688f, 0x0000, 0x6893, 0x0000, 0x6a30, 0x692c, - 0x6a3e, 0x6942, 0x682f, 0x0003, 0x6833, 0x0000, 0x6837, 0x0020, - 0x6897, 0x0000, 0x689b, 0x0020, 0x7000, 0x0002, 0x25c9, 0x3196, - 0x3190, 0x318e, 0x318e, 0x318e, 0x318e, 0x318e, 0x080c, 0x2575, - 0x6820, 0xd084, 0x1118, 0x080c, 0x37c7, 0x0030, 0x7058, 0x2c50, - 0x2060, 0x6800, 0x6002, 0x2a60, 0xaea0, 0x0017, 0x2404, 0xa005, - 0x0110, 0x2020, 0x0cd8, 0x2d22, 0x206b, 0x0000, 0x0005, 0x080c, - 0x37cd, 0x080c, 0x37e1, 0x6008, 0xc0cc, 0x600a, 0x682b, 0x0000, - 0x789b, 0x000e, 0x6f14, 0x6938, 0x691a, 0x6944, 0x6916, 0x2009, - 0x0000, 0xae86, 0x4740, 0x0110, 0x2009, 0x0001, 0x080c, 0x431f, - 0xd6dc, 0x01c8, 0x691c, 0xc1ed, 0x691e, 0x6828, 0xa082, 0x000e, - 0x0290, 0x6848, 0xa084, 0x000f, 0xa086, 0x000b, 0x1160, 0x685c, - 0xa086, 0x0047, 0x1140, 0x2001, 0x4701, 0x2004, 0xd0ac, 0x1118, - 0x2700, 0x080c, 0x249e, 0x6818, 0xd0fc, 0x0140, 0x681b, 0x0000, - 0x7868, 0xa08c, 0x00ff, 0x0110, 0x681b, 0x001e, 0xaea0, 0x0017, - 0x6800, 0x2022, 0x6a3c, 0x6940, 0x6a32, 0x692e, 0x68c0, 0x2060, - 0x6000, 0xd0a4, 0x0580, 0x2041, 0x0021, 0x2049, 0x0005, 0x2051, - 0x0020, 0x00d6, 0x00f6, 0x0156, 0x0146, 0x2079, 0x4700, 0x080c, - 0x1bb2, 0x014e, 0x015e, 0x00fe, 0x70c8, 0x2010, 0x2009, 0x0101, - 0x0026, 0x2204, 0xa06d, 0x0140, 0x6814, 0xa706, 0x0110, 0x6800, - 0x0cc8, 0x6820, 0xc0d5, 0x6822, 0x002e, 0x8210, 0x8109, 0x1d80, - 0x00de, 0x7063, 0x0003, 0x707b, 0x0000, 0x7772, 0x707f, 0x000f, - 0x71d0, 0xc1c4, 0x71d2, 0x6818, 0xa086, 0x0002, 0x1138, 0x6817, - 0x0000, 0x682b, 0x0000, 0x681c, 0xc0ec, 0x681e, 0x080c, 0x1dbf, - 0x0804, 0x25c9, 0x7cd8, 0x7ddc, 0x7fd0, 0x080c, 0x30ff, 0x682b, - 0x0000, 0x789b, 0x000e, 0x6f14, 0x080c, 0x3c72, 0xa08c, 0x00ff, - 0x6916, 0x6818, 0xd0fc, 0x0110, 0x7044, 0x681a, 0xa68c, 0xdf00, - 0x691e, 0x7063, 0x0000, 0x0804, 0x25c9, 0x7000, 0xa005, 0x1110, - 0x0804, 0x25c9, 0xa006, 0x080c, 0x3f4e, 0x6920, 0xd1ac, 0x1110, - 0x681b, 0x0014, 0xa68c, 0xdf00, 0x691e, 0x682b, 0x0000, 0x6820, - 0xa084, 0x00ff, 0x6822, 0x7000, 0x0002, 0x25c9, 0x326f, 0x326f, - 0x3272, 0x3272, 0x3272, 0x326d, 0x326d, 0x080c, 0x2575, 0x6818, - 0x0804, 0x2f3b, 0x6008, 0xc0a4, 0x600a, 0x6817, 0x0000, 0x0804, - 0x3795, 0x2300, 0x0002, 0x327e, 0x3280, 0x32ce, 0x080c, 0x2575, - 0xd6fc, 0x1904, 0x2d5b, 0x7000, 0xa00d, 0x0002, 0x25c9, 0x3290, - 0x3290, 0x32ba, 0x3290, 0x32cb, 0x328e, 0x328e, 0x080c, 0x2575, - 0xa684, 0x0060, 0x0538, 0xa086, 0x0060, 0x1510, 0xc6ac, 0xc6f4, - 0xc6ed, 0x7e5a, 0x6eb6, 0x681c, 0xc0ac, 0x681e, 0xa186, 0x0002, - 0x0148, 0x080c, 0x3f4e, 0x69ac, 0x68b0, 0xa115, 0x0118, 0x080c, - 0x4235, 0x0010, 0x080c, 0x4208, 0x781b, 0x0083, 0x71d0, 0xd1b4, - 0x1904, 0x25c6, 0x70a0, 0xa086, 0x0001, 0x1904, 0x260d, 0x0005, - 0xd6ec, 0x09f0, 0x6818, 0xd0fc, 0x0170, 0xd6f4, 0x1130, 0x681b, - 0x0015, 0x781b, 0x0083, 0x0804, 0x25c6, 0x681b, 0x0007, 0x682f, - 0x0000, 0x6833, 0x0000, 0x080c, 0x3c17, 0x0005, 0x080c, 0x2575, - 0x2300, 0x0002, 0x32d7, 0x32f9, 0x3351, 0x080c, 0x2575, 0x7000, - 0x0002, 0x32e1, 0x32e3, 0x32ea, 0x32e1, 0x32e1, 0x32e1, 0x32e1, - 0x32e1, 0x080c, 0x2575, 0x69ac, 0x68b0, 0xa115, 0x0118, 0x080c, - 0x4235, 0x0010, 0x080c, 0x4208, 0x681c, 0xc0b4, 0x681e, 0x70d0, - 0xd0b4, 0x1904, 0x25c6, 0x70a0, 0xa086, 0x0001, 0x1904, 0x260d, - 0x0005, 0xd6fc, 0x1904, 0x3341, 0x7000, 0xa00d, 0x0002, 0x25c9, - 0x330f, 0x3309, 0x3339, 0x330f, 0x333e, 0x3307, 0x3307, 0x080c, - 0x2575, 0x6894, 0x78d6, 0x78de, 0x6898, 0x78d2, 0x78da, 0xa684, - 0x0060, 0x0538, 0xa086, 0x0060, 0x1510, 0xa6b4, 0xbfbf, 0xc6ed, - 0x7e5a, 0x6eb6, 0xa186, 0x0002, 0x0148, 0x080c, 0x3f4e, 0x69ac, - 0x68b0, 0xa115, 0x0118, 0x080c, 0x4235, 0x0010, 0x080c, 0x4208, - 0x781b, 0x0083, 0x681c, 0xc0b4, 0x681e, 0x71d0, 0xd1b4, 0x1904, - 0x25c6, 0x70a0, 0xa086, 0x0001, 0x1904, 0x260d, 0x0005, 0xd6ec, - 0x09f0, 0x6818, 0xd0fc, 0x0110, 0x681b, 0x0007, 0x781b, 0x00fb, - 0x0005, 0xc6fc, 0x7e5a, 0x7adc, 0x79d8, 0x6b98, 0x2100, 0xa302, - 0x68b2, 0x6b94, 0x2200, 0xa303, 0x68ae, 0x79d2, 0x781b, 0x0083, - 0x0005, 0xd6dc, 0x0130, 0x782b, 0x3009, 0x781b, 0x0083, 0x0804, - 0x25c6, 0x7884, 0xc0ac, 0x7886, 0x78e4, 0xa084, 0x0008, 0x1150, - 0xa484, 0x0200, 0x0108, 0xc6f5, 0xc6dd, 0x7e5a, 0x781b, 0x0083, - 0x0804, 0x25c6, 0x6820, 0xc095, 0x6822, 0x080c, 0x3c02, 0xc6dd, - 0x080c, 0x3a61, 0x781b, 0x0082, 0x0804, 0x25c6, 0x2300, 0x0002, - 0x337b, 0x337d, 0x337f, 0x080c, 0x2575, 0x0804, 0x3a5b, 0x7d98, - 0xd6d4, 0x15a8, 0x79e4, 0xd1ac, 0x0130, 0x78ec, 0xa084, 0x0003, - 0x0110, 0x782b, 0x3009, 0x789b, 0x0060, 0x78ab, 0x0000, 0xa684, - 0xfffb, 0x785a, 0x7d9a, 0x79e4, 0xd1ac, 0x0120, 0x78ec, 0xa084, - 0x0003, 0x1120, 0x2001, 0x0014, 0x0804, 0x2f3b, 0x7884, 0xd0fc, - 0x1118, 0xa184, 0x0007, 0x0090, 0xa184, 0x0007, 0xa086, 0x0004, - 0x1118, 0x2001, 0x0000, 0x0050, 0xa184, 0x0007, 0xa086, 0x0005, - 0x0118, 0xa184, 0x0007, 0x0010, 0x2001, 0x0001, 0x04c2, 0x7a90, - 0xa294, 0x0007, 0x789b, 0x0060, 0x79a8, 0x81ff, 0x0568, 0x789b, - 0x0080, 0x7ba8, 0xa384, 0x0001, 0x11d0, 0x7ba8, 0x7ba8, 0xa386, - 0x0004, 0x1118, 0x2009, 0xffdf, 0x0058, 0xa386, 0x0001, 0x1118, - 0x2009, 0xfff7, 0x0028, 0xa386, 0x0003, 0x1148, 0x2009, 0xffef, - 0x00c6, 0x7054, 0x2060, 0x6004, 0xa104, 0x6006, 0x00ce, 0x789b, - 0x0060, 0x78ab, 0x0000, 0xa684, 0xfffb, 0x785a, 0x782b, 0x3009, - 0x6920, 0xa18c, 0xecff, 0x6922, 0x7d9a, 0x0804, 0x3c0b, 0x2bd1, - 0x2bda, 0x33f9, 0x33ff, 0x33f7, 0x33f7, 0x3c0b, 0x3c0b, 0x080c, - 0x2575, 0x6920, 0xa18c, 0xfcff, 0x6922, 0x0804, 0x3c11, 0x6920, - 0xa18c, 0xfcff, 0x6922, 0x0804, 0x3c0b, 0x79e4, 0xa184, 0x0030, - 0x0120, 0x78ec, 0xa084, 0x0003, 0x1570, 0x7000, 0xa086, 0x0004, - 0x1190, 0x7060, 0xa086, 0x0002, 0x1130, 0x2011, 0x0002, 0x2019, - 0x0000, 0x0804, 0x2a85, 0x7060, 0xa086, 0x0006, 0x0db0, 0x7060, - 0xa086, 0x0004, 0x0d90, 0x7000, 0xa086, 0x0000, 0x0904, 0x25c6, - 0x6920, 0xa184, 0x0420, 0x0128, 0xc1d4, 0x6922, 0x6818, 0x0804, - 0x2f3b, 0x6818, 0xa08e, 0x0002, 0x0120, 0xc0fd, 0x681a, 0x2001, - 0x0014, 0x0804, 0x2f3b, 0x7884, 0xd0fc, 0x1118, 0xa184, 0x0007, - 0x0090, 0xa184, 0x0007, 0xa086, 0x0004, 0x1118, 0x2001, 0x0000, - 0x0050, 0xa184, 0x0007, 0xa086, 0x0005, 0x0118, 0xa184, 0x0007, - 0x0010, 0x2001, 0x0001, 0x0002, 0x3c0b, 0x3c0b, 0x345c, 0x3c0b, - 0x3c4f, 0x3c4f, 0x3c0b, 0x3c0b, 0xd6bc, 0x0570, 0x7180, 0x81ff, - 0x0558, 0xa182, 0x000d, 0x1318, 0x7083, 0x0000, 0x0028, 0xa182, - 0x000c, 0x7082, 0x2009, 0x000c, 0x789b, 0x0061, 0x79aa, 0x0156, - 0x0136, 0x0146, 0x7084, 0x8114, 0xa210, 0x7286, 0xa080, 0x000b, - 0xad00, 0x2098, 0xb284, 0x0600, 0x0118, 0x20a1, 0x022b, 0x0010, - 0x20a1, 0x012b, 0x789b, 0x0000, 0x8108, 0x81ac, 0x53a6, 0x014e, - 0x013e, 0x015e, 0x0804, 0x3c11, 0xd6d4, 0x1904, 0x34cf, 0x6820, - 0xd084, 0x0904, 0x3c11, 0xa68c, 0x0060, 0xa684, 0x0060, 0x0120, - 0xa086, 0x0060, 0x1108, 0xc1f5, 0xc194, 0x795a, 0x69b6, 0x789b, - 0x0060, 0x78ab, 0x0000, 0x789b, 0x0061, 0x6818, 0xc0fd, 0x681a, - 0x78aa, 0x8008, 0x810c, 0x0904, 0x37f6, 0xa18c, 0x00f8, 0x1904, - 0x37f6, 0x0156, 0x0136, 0x0146, 0x0016, 0x20a1, 0x012b, 0x3208, - 0xa18c, 0x0600, 0x0110, 0x20a1, 0x022b, 0x001e, 0x789b, 0x0000, - 0x8000, 0x80ac, 0xad80, 0x000b, 0x2098, 0x53a6, 0x014e, 0x013e, - 0x015e, 0x6814, 0xc0fc, 0x8007, 0x7882, 0x0804, 0x3c11, 0x6818, - 0xd0fc, 0x0110, 0x681b, 0x0008, 0x080c, 0x3a61, 0x781b, 0x00ed, - 0x0005, 0x2300, 0x0002, 0x34e0, 0x359d, 0x34de, 0x080c, 0x2575, - 0x7cd8, 0x7ddc, 0x7fd0, 0x82ff, 0x1528, 0x7200, 0xa286, 0x0003, - 0x0904, 0x2f09, 0x71d0, 0xd1bc, 0x11f8, 0xd1b4, 0x01e8, 0x2001, - 0x4701, 0x2004, 0xd0c4, 0x11c0, 0x00d6, 0x783b, 0x8800, 0x781b, - 0x0059, 0x70b8, 0xa06d, 0x68b4, 0xc0a5, 0x785a, 0x6894, 0x78d6, - 0x78de, 0x6898, 0x78d2, 0x78da, 0xc1b4, 0x71d2, 0x7003, 0x0030, - 0x00de, 0x0030, 0x7200, 0x0020, 0x783b, 0x1800, 0x781b, 0x0057, - 0xa284, 0x000f, 0x0002, 0x3588, 0x3545, 0x351d, 0x2f38, 0x351b, - 0x3588, 0x351b, 0x351b, 0x080c, 0x2575, 0x681c, 0xd0ec, 0x0118, - 0x6008, 0xc08d, 0x600a, 0x6920, 0xc185, 0x6922, 0x6800, 0x6006, - 0xa005, 0x1108, 0x6002, 0x6008, 0xc0d4, 0x600a, 0x681c, 0xa084, - 0x000e, 0x1120, 0x71c8, 0xa188, 0x0100, 0x0028, 0x7030, 0x68ba, - 0x713c, 0x70c8, 0xa108, 0x2104, 0x6802, 0x2d0a, 0x715a, 0xd6dc, - 0x1120, 0xc6fc, 0x6eb6, 0x0804, 0x3588, 0x6eb6, 0xa684, 0x0060, - 0x1120, 0xa684, 0x7fff, 0x68b6, 0x04d8, 0xd6dc, 0x1150, 0xa684, - 0x7fff, 0x68b6, 0x6894, 0x68a6, 0x6898, 0x68aa, 0x080c, 0x3f4e, - 0x0478, 0xd6ac, 0x0140, 0xa006, 0x080c, 0x3f4e, 0x2408, 0x2510, - 0x69aa, 0x6aa6, 0x0068, 0x2408, 0x2510, 0x2700, 0x8007, 0xa084, - 0x007f, 0xa108, 0xa291, 0x0000, 0x69aa, 0x6aa6, 0x080c, 0x3f4e, - 0xd6fc, 0x01b0, 0xa684, 0x7fff, 0x68b6, 0x2510, 0x2408, 0xd6ac, - 0x1138, 0x2700, 0x8007, 0xa084, 0x007f, 0xa108, 0xa291, 0x0000, - 0x6b98, 0x2100, 0xa302, 0x68b2, 0x6b94, 0x2200, 0xa303, 0x68ae, - 0x7000, 0xa086, 0x0030, 0x1904, 0x25c9, 0x7003, 0x0002, 0x70b8, - 0xa06d, 0x68bc, 0x703e, 0x70b4, 0xa065, 0x68c0, 0x7056, 0x2d00, - 0x704a, 0xad80, 0x0009, 0x7042, 0x0005, 0xa586, 0x8800, 0x1148, - 0x7003, 0x0000, 0x6018, 0x8001, 0x601a, 0x6008, 0xa084, 0xfbef, - 0x600a, 0x0804, 0x3a5b, 0x7043, 0x0000, 0xa282, 0x0006, 0x0310, - 0x080c, 0x2575, 0x2300, 0x0002, 0x35b7, 0x35c8, 0x35d2, 0x2200, - 0x0002, 0x35bf, 0x3a5b, 0x35c1, 0x35bf, 0x3603, 0x3651, 0x080c, - 0x2575, 0x7a80, 0xa294, 0x0f00, 0x080c, 0x36a5, 0x0804, 0x3a30, - 0x00c1, 0x0002, 0x3a5b, 0x35d0, 0x35d0, 0x3603, 0x35d0, 0x3a5b, - 0x080c, 0x2575, 0x0071, 0x0002, 0x35dc, 0x35da, 0x35da, 0x35dc, - 0x35da, 0x35dc, 0x080c, 0x2575, 0x080c, 0x3a70, 0x781b, 0x0082, - 0x0005, 0x7000, 0xa086, 0x0002, 0x1150, 0x080c, 0x37e1, 0x0010, - 0x080c, 0x3f4e, 0x6008, 0xa084, 0xfbef, 0x600a, 0x0020, 0x7000, - 0xa086, 0x0003, 0x0da8, 0x7003, 0x0005, 0x2001, 0x8ee0, 0xae8e, - 0x4740, 0x0110, 0x2001, 0x8f12, 0x2068, 0x704a, 0xad80, 0x0009, - 0x7042, 0x2200, 0x0005, 0x7000, 0xa086, 0x0002, 0x1158, 0x70d0, - 0xc0b5, 0x70d2, 0x2c00, 0x70b6, 0x2d00, 0x70ba, 0x0038, 0x080c, - 0x3f4e, 0x0020, 0x7000, 0xa086, 0x0003, 0x0dc8, 0x7003, 0x0001, - 0x7a80, 0xa294, 0x0f00, 0x789b, 0x0018, 0x7ca8, 0xa484, 0x001f, - 0xa215, 0x2069, 0x8dc0, 0xb284, 0x0600, 0x1118, 0xc2fd, 0x2069, - 0x8ed0, 0x2d04, 0x2d08, 0x715a, 0xa06d, 0x0128, 0x6814, 0xa206, - 0x0120, 0x6800, 0x0cb8, 0x080c, 0x36a5, 0x6eb4, 0x7e5a, 0x6920, - 0xa184, 0x0c00, 0x0904, 0x36cb, 0x7060, 0xa086, 0x0006, 0x1128, - 0x7070, 0xa206, 0x1110, 0x7062, 0x707a, 0x681b, 0x0005, 0xc1ad, - 0x681b, 0x0005, 0xc1ad, 0xc1d4, 0x6922, 0x080c, 0x3a67, 0x0804, - 0x36cb, 0x7200, 0xa286, 0x0002, 0x1158, 0x70d0, 0xc0b5, 0x70d2, - 0x2c00, 0x70b6, 0x2d00, 0x70ba, 0x0030, 0x080c, 0x3f4e, 0x0018, - 0xa286, 0x0003, 0x0dd0, 0x7003, 0x0001, 0x7a80, 0xa294, 0x0f00, - 0x789b, 0x0018, 0x7ca8, 0xa484, 0x001f, 0xa215, 0xae86, 0x4740, - 0x0108, 0xc2fd, 0x79a8, 0x79a8, 0xa18c, 0x00ff, 0x2118, 0x70c8, - 0xa168, 0x2d04, 0x2d08, 0x715a, 0xa06d, 0x0128, 0x6814, 0xa206, - 0x0118, 0x6800, 0x0cb8, 0x0409, 0x6eb4, 0x6920, 0xa184, 0x0c00, - 0x0904, 0x36cb, 0xd0dc, 0x0178, 0x7060, 0xa086, 0x0004, 0x1140, - 0x7070, 0xa206, 0x1128, 0x7074, 0xa306, 0x1110, 0x7062, 0x707a, - 0x080c, 0x3a6d, 0x0480, 0x681b, 0x0005, 0xc1ad, 0xc1d4, 0x6922, - 0x080c, 0x3a67, 0x707b, 0x0000, 0x0430, 0x7003, 0x0005, 0xb284, - 0x0600, 0x0118, 0x2001, 0x8ee0, 0x0010, 0x2001, 0x8f12, 0x2068, - 0x704a, 0x0156, 0x20a9, 0x0032, 0x2003, 0x0000, 0x8000, 0x1f04, - 0x36b4, 0x015e, 0xb284, 0x0600, 0x0110, 0xc2fc, 0x0008, 0xc2fd, - 0x6a16, 0xad80, 0x0009, 0x7042, 0x68b7, 0x0700, 0x6823, 0x0800, - 0x6827, 0x0003, 0x0005, 0xc6ec, 0xa6ac, 0x0060, 0x0904, 0x3712, - 0x6b98, 0x6c94, 0x69ac, 0x68b0, 0xa105, 0x11e0, 0x7bd2, 0x7bda, - 0x7cd6, 0x7cde, 0xa586, 0x0060, 0x05c8, 0xd6f4, 0x1108, 0xc6ed, - 0xa6b4, 0xb7ff, 0x7e5a, 0x2009, 0x0083, 0xd69c, 0x0128, 0x2009, - 0x0082, 0x2019, 0x0000, 0x2320, 0x791a, 0xd6ec, 0x0588, 0x080c, - 0x4208, 0x0470, 0x68b0, 0xa31a, 0x2100, 0xa423, 0x2400, 0xa305, - 0x01f8, 0x7bd2, 0x7bda, 0x7cd6, 0x7cde, 0x68b0, 0xd6f4, 0x1108, - 0xc6ed, 0xc6f4, 0x7e5a, 0x2011, 0x0083, 0xd69c, 0x0128, 0x2011, - 0x0082, 0x2019, 0x0000, 0x2320, 0x7a1a, 0xd6ec, 0x0188, 0x080c, - 0x4235, 0x0070, 0x2019, 0x0000, 0x2320, 0x0010, 0xa6b4, 0xb7ff, - 0x7e5a, 0x2009, 0x0083, 0xd69c, 0x0110, 0x2009, 0x0082, 0x791a, - 0x68c0, 0x7056, 0x2d00, 0x704a, 0x68c4, 0x2060, 0x71d0, 0x2001, - 0x4701, 0x2004, 0xd0c4, 0x15c8, 0x70d4, 0xa02d, 0x01b8, 0xd1bc, - 0x0548, 0x7a80, 0xa294, 0x0f00, 0x70d8, 0xa206, 0x0118, 0x78e0, - 0xa504, 0x1558, 0x70d6, 0xc1bc, 0x71d2, 0x0438, 0x2031, 0x0001, - 0x852c, 0x0218, 0x8633, 0x8210, 0x0cd8, 0x0005, 0x7de0, 0xa594, - 0xff00, 0x0130, 0x2011, 0x0008, 0x852f, 0x0c81, 0x8637, 0x0008, - 0x0c69, 0x8217, 0x7880, 0xa084, 0x0f00, 0xa206, 0x0170, 0x72da, - 0x76d6, 0x0058, 0x7a80, 0xa294, 0x0f00, 0x70d8, 0xa236, 0x0dc0, - 0x78e0, 0xa534, 0x0da8, 0xc1bd, 0x71d2, 0xd1b4, 0x1904, 0x25c6, - 0x2300, 0xa405, 0x0904, 0x25c6, 0x70a0, 0xa086, 0x0001, 0x1904, - 0x260d, 0x0005, 0x6020, 0xa005, 0x0150, 0x8001, 0x6022, 0x6008, - 0xa085, 0x0008, 0x600a, 0x700f, 0x0100, 0x702c, 0x6026, 0x0005, - 0xa006, 0x080c, 0x3f4e, 0x7000, 0xa086, 0x0002, 0x0120, 0x7060, - 0xa086, 0x0005, 0x1150, 0x682b, 0x0000, 0x6817, 0x0000, 0x681b, - 0x0001, 0x6823, 0x0040, 0x681f, 0x0100, 0x7000, 0xa084, 0x000f, - 0x0002, 0x25c9, 0x37a6, 0x37a3, 0x37c3, 0x37af, 0x25c9, 0x37a1, - 0x37a1, 0x080c, 0x2575, 0x0449, 0x0411, 0x0028, 0x0431, 0x7058, - 0x2060, 0x6800, 0x6002, 0x080c, 0x1dbf, 0x0804, 0x25c9, 0x7060, - 0x7063, 0x0000, 0x707f, 0x0000, 0x0002, 0x37bf, 0x37bf, 0x37bd, - 0x37bd, 0x37bd, 0x37bf, 0x37bd, 0x37bf, 0x0804, 0x2a9a, 0x7063, - 0x0000, 0x0804, 0x25c9, 0x681b, 0x0000, 0x0804, 0x31a7, 0x6800, - 0xa005, 0x1108, 0x6002, 0x6006, 0x0005, 0x6410, 0x84ff, 0x0168, - 0x2009, 0x4702, 0x2104, 0x8001, 0x200a, 0x8421, 0x6412, 0x1128, - 0x2021, 0x4704, 0x2404, 0xc0a5, 0x2022, 0x6008, 0xc0a4, 0x600a, - 0x0005, 0x6018, 0xa005, 0x0110, 0x8001, 0x601a, 0x0005, 0x080c, - 0x3c6e, 0x681b, 0x0018, 0x0490, 0x080c, 0x3c6e, 0x681b, 0x0019, - 0x0468, 0x080c, 0x3c6e, 0x681b, 0x001a, 0x0440, 0x080c, 0x3c6e, - 0x681b, 0x0003, 0x0418, 0x7770, 0x080c, 0x3b95, 0x7174, 0xa18c, - 0x00ff, 0x3210, 0xa294, 0x0600, 0x0118, 0xa1e8, 0x8cc0, 0x0010, - 0xa1e8, 0x8dd0, 0x2d04, 0x2d08, 0x2068, 0xa005, 0x1118, 0x707a, - 0x0804, 0x25c9, 0x6814, 0x7270, 0xa206, 0x0110, 0x6800, 0x0c98, - 0x6800, 0x200a, 0x681b, 0x0005, 0x707b, 0x0000, 0x080c, 0x37cd, - 0x6820, 0xd084, 0x1110, 0x080c, 0x37c7, 0x080c, 0x37e1, 0x681f, - 0x0000, 0x6823, 0x0020, 0x080c, 0x1dbf, 0x0804, 0x25c9, 0xa282, - 0x0003, 0x1904, 0x3a35, 0x7da8, 0xa5ac, 0x00ff, 0x7ea8, 0xa6b4, - 0x00ff, 0x6920, 0xc1bd, 0x6922, 0xd1c4, 0x05b0, 0xc1c4, 0x6922, - 0xa6b4, 0x00ff, 0x0530, 0xa682, 0x0018, 0x0218, 0x0110, 0x2031, - 0x0018, 0xa686, 0x0010, 0x1108, 0x8630, 0x852b, 0x852b, 0x2041, - 0x0000, 0x080c, 0x3aee, 0x0118, 0x080c, 0x391a, 0x00a0, 0x080c, - 0x3aba, 0x080c, 0x3917, 0x6920, 0xc1c5, 0x6922, 0x7e58, 0xc695, - 0x7e5a, 0xd6d4, 0x1118, 0x781b, 0x006e, 0x0005, 0x781b, 0x0082, - 0x0005, 0x080c, 0x3917, 0x7e58, 0xd6d4, 0x1118, 0x781b, 0x0071, - 0x0005, 0x781b, 0x0083, 0x0005, 0x00c6, 0x7054, 0x2060, 0x6100, - 0xd1e4, 0x0598, 0x6208, 0x8217, 0xa294, 0x00ff, 0xa282, 0x0018, - 0x0218, 0x0110, 0x2011, 0x0018, 0x2600, 0xa202, 0x1208, 0x2230, - 0xa686, 0x0010, 0x1108, 0x8630, 0x6208, 0xa294, 0x00ff, 0x78ec, - 0xd0e4, 0x0130, 0xa282, 0x000a, 0x1240, 0x2011, 0x000a, 0x0028, - 0xa282, 0x000c, 0x1210, 0x2011, 0x000c, 0x2200, 0xa502, 0x1208, - 0x2228, 0x080c, 0x3abe, 0x852b, 0x852b, 0x2041, 0x0000, 0x080c, - 0x3aee, 0x0118, 0x080c, 0x391a, 0x0020, 0x080c, 0x3aba, 0x080c, - 0x3917, 0x7858, 0xc095, 0x785a, 0x00ce, 0x781b, 0x0082, 0x0005, - 0x00c6, 0x2960, 0x6000, 0xd0e4, 0x1188, 0xd0b4, 0x1150, 0x6010, - 0xa084, 0x000f, 0x1130, 0x6104, 0xa18c, 0xfff5, 0x6106, 0x00ce, - 0x0005, 0x2011, 0x0032, 0x2019, 0x0000, 0x00f0, 0x68a0, 0xd0cc, - 0x1dc0, 0x6208, 0xa294, 0x00ff, 0x78ec, 0xd0e4, 0x0130, 0xa282, - 0x000b, 0x1218, 0x2011, 0x000a, 0x0028, 0xa282, 0x000c, 0x1210, - 0x2011, 0x000c, 0x6308, 0x831f, 0xa39c, 0x00ff, 0xa382, 0x0018, - 0x0218, 0x0110, 0x2019, 0x0018, 0x78ab, 0x0001, 0x78ab, 0x0003, - 0x78ab, 0x0001, 0x7aaa, 0x7baa, 0xa8c0, 0x0005, 0x6820, 0xc0c5, - 0x6822, 0x080c, 0x3a7a, 0x00ce, 0x0005, 0x00c6, 0x2960, 0x6104, - 0xa18c, 0xfff5, 0x6106, 0x2011, 0x0032, 0x2019, 0x0000, 0x0000, - 0x78ab, 0x0001, 0x78ab, 0x0003, 0x78ab, 0x0001, 0x7aaa, 0x7baa, - 0xa8c0, 0x0005, 0x6820, 0xc0c5, 0x6822, 0x00ce, 0x0005, 0xa006, - 0x2030, 0x2010, 0x00c6, 0x7154, 0x2160, 0x2018, 0x2008, 0xa084, - 0xffe0, 0xa635, 0x7e86, 0x6018, 0x789a, 0x7eae, 0x6612, 0x78a4, - 0xa084, 0x7770, 0xa18c, 0x000f, 0xa105, 0x2029, 0x4705, 0x252c, - 0xd5cc, 0x0140, 0xd3a4, 0x0110, 0xa085, 0x0800, 0xd3fc, 0x0110, - 0xa085, 0x8080, 0x78a6, 0x6016, 0x788a, 0xa6b4, 0x001f, 0x8637, - 0x8204, 0x8004, 0xa605, 0x600e, 0x6004, 0xa084, 0xffd5, 0x6006, - 0x00ce, 0x0005, 0xa282, 0x0002, 0x1904, 0x3a3f, 0x7aa8, 0x6920, - 0xc1bd, 0x6922, 0xd1cc, 0x0568, 0xc1cc, 0x6922, 0xa294, 0x00ff, - 0xa282, 0x0002, 0x1a04, 0x3a30, 0x080c, 0x39c1, 0x080c, 0x3917, - 0xa980, 0x0001, 0x200c, 0x080c, 0x3b91, 0x080c, 0x38b8, 0x88ff, - 0x0178, 0x789b, 0x0060, 0x2800, 0x78aa, 0x7e58, 0xc695, 0x7e5a, - 0xd6d4, 0x1118, 0x781b, 0x006e, 0x0005, 0x781b, 0x0082, 0x0005, - 0x7e58, 0xd6d4, 0x1118, 0x781b, 0x0071, 0x0005, 0x781b, 0x0083, - 0x0005, 0xa282, 0x0002, 0x1218, 0xa284, 0x0001, 0x0140, 0x7154, - 0xa188, 0x0000, 0x210c, 0xd1ec, 0x1110, 0x2011, 0x0000, 0x080c, - 0x3aac, 0x0479, 0x080c, 0x3917, 0x7858, 0xc095, 0x785a, 0x781b, - 0x0082, 0x0005, 0x00c6, 0x0026, 0x2960, 0x6000, 0x2011, 0x0001, - 0xd0ec, 0x1158, 0xd0bc, 0x1138, 0x6014, 0xd0b4, 0x1120, 0xc1a4, - 0x6106, 0xa006, 0x0088, 0x2011, 0x0000, 0x78ab, 0x0001, 0x78ab, - 0x0002, 0x78ab, 0x0003, 0x7aaa, 0xa8c0, 0x0004, 0x080c, 0x3a7a, - 0x6820, 0xa085, 0x0200, 0x6822, 0x002e, 0x00ce, 0x0005, 0x8807, - 0xa715, 0x00c6, 0x2009, 0x0000, 0x7054, 0x2060, 0x82ff, 0x0110, - 0x2009, 0x0040, 0x6018, 0xa080, 0x0002, 0x789a, 0x78a4, 0xa084, - 0xff9f, 0xa105, 0xc0ec, 0xd0b4, 0x1108, 0xc0ed, 0x6100, 0xd1f4, - 0x0110, 0xa085, 0x0020, 0x78a6, 0x6016, 0x788a, 0x6004, 0xa084, - 0xffef, 0x6006, 0x00ce, 0x0005, 0x0006, 0x7000, 0xa086, 0x0003, - 0x0110, 0x000e, 0x0010, 0x000e, 0x0498, 0xd6ac, 0x0588, 0x7888, - 0xa084, 0x0040, 0x0568, 0x7bb8, 0x8307, 0xa084, 0x007f, 0x1518, - 0x8207, 0xa084, 0x00ff, 0x0904, 0x3a57, 0xa09a, 0x0004, 0x1a04, - 0x3a57, 0xd6f4, 0x11d0, 0x79d8, 0x7adc, 0xa108, 0xa291, 0x0000, - 0x79d2, 0x79da, 0x7ad6, 0x7ade, 0x080c, 0x42e8, 0x781b, 0x0080, - 0xb284, 0x0600, 0x0118, 0x2001, 0x0000, 0x0010, 0x2001, 0x0001, - 0x080c, 0x419a, 0x0005, 0x080c, 0x2575, 0x781b, 0x0080, 0x0005, - 0x781b, 0x0083, 0x0005, 0x2039, 0x0000, 0x2041, 0x0000, 0x2031, - 0x0000, 0xa006, 0x2010, 0x080c, 0x391a, 0x080c, 0x39bf, 0x7e58, - 0x080c, 0x3a73, 0x781b, 0x0082, 0x0005, 0x0cd1, 0x6820, 0xc0c4, - 0x6822, 0x00c6, 0x7054, 0x2060, 0x080c, 0x3944, 0x00b0, 0x0c81, - 0x6820, 0xc0cc, 0x6822, 0x00c6, 0x7054, 0x2060, 0x080c, 0x39de, - 0x0060, 0x0c31, 0x6820, 0xa084, 0xecff, 0x6822, 0x00c6, 0x7054, - 0x2060, 0x6004, 0xa084, 0xffc5, 0x6006, 0x00ce, 0x0005, 0x0049, - 0x781b, 0x0082, 0x0005, 0x6827, 0x0002, 0x0049, 0x781b, 0x0082, - 0x0005, 0x2001, 0x0005, 0x0088, 0x2001, 0x000c, 0x0070, 0x6820, - 0xc0d5, 0x6822, 0x2001, 0x0006, 0x0040, 0x2001, 0x000d, 0x0028, - 0x2001, 0x0009, 0x0010, 0x2001, 0x0007, 0x789b, 0x007e, 0x78aa, - 0xc69d, 0x7e5a, 0x70d0, 0xd0b4, 0x0168, 0xc0b4, 0x70d2, 0x00c6, - 0x70b4, 0xa065, 0x6008, 0xa084, 0xfbef, 0x600a, 0x6018, 0x8001, - 0x601a, 0x00ce, 0x0005, 0x0076, 0x873f, 0xa7bc, 0x000f, 0x873b, - 0x873b, 0x8703, 0xa0e0, 0x4bc0, 0xae8e, 0x4740, 0x0110, 0xa0e0, - 0x4c40, 0xa7b8, 0x0020, 0x7f9a, 0x79a4, 0xa184, 0x7fe0, 0x78ae, - 0x6012, 0x79a4, 0xa184, 0x773f, 0x78a6, 0x6016, 0x6004, 0xa085, - 0x0038, 0x6006, 0x007e, 0x0005, 0x789b, 0x0080, 0x78ab, 0x0001, - 0x78ab, 0x0002, 0x78ab, 0x0003, 0x7aaa, 0x789b, 0x0060, 0x78ab, - 0x0004, 0x0800, 0x2031, 0x0000, 0x2029, 0x0032, 0x789b, 0x0080, - 0x78ab, 0x0001, 0x78ab, 0x0003, 0x78ab, 0x0001, 0x7daa, 0x7eaa, - 0x789b, 0x0060, 0x78ab, 0x0005, 0x0804, 0x3a7a, 0x0156, 0x8007, - 0xa084, 0x00ff, 0x8003, 0x8003, 0xa080, 0x0020, 0x789a, 0x79a4, - 0xa18c, 0xffe0, 0x2021, 0x3b7a, 0x2019, 0x0011, 0x20a9, 0x000e, - 0x2011, 0x0032, 0x2404, 0xa084, 0xffe0, 0xa106, 0x0128, 0x8420, - 0x2300, 0xa210, 0x1f04, 0x3ae2, 0x015e, 0x0005, 0x0156, 0x0804, - 0x3b30, 0x2021, 0x3b88, 0x20a9, 0x0009, 0x2011, 0x0029, 0xa582, - 0x0028, 0x0550, 0x8420, 0x95a9, 0x2011, 0x0033, 0xa582, 0x0033, - 0x0618, 0x8420, 0x95a9, 0x2019, 0x000a, 0x2011, 0x0065, 0x2200, - 0xa502, 0x02d0, 0x8420, 0x2300, 0xa210, 0x1f04, 0x3b07, 0x015e, - 0x0088, 0x2021, 0x3b7a, 0x2019, 0x0011, 0x20a9, 0x000e, 0x2011, - 0x0033, 0x2200, 0xa502, 0x0240, 0x8420, 0x2300, 0xa210, 0x1f04, - 0x3b19, 0x015e, 0xa006, 0x0005, 0x8211, 0x015e, 0xa582, 0x0064, - 0x1220, 0x7808, 0xa085, 0x0070, 0x780a, 0x2404, 0xa005, 0x0005, - 0xa886, 0x0002, 0x01e8, 0x2021, 0x3b66, 0x20a9, 0x000d, 0x2011, - 0x0028, 0xa582, 0x0028, 0x0d48, 0x8420, 0x2019, 0x0019, 0x2011, - 0x0033, 0x2200, 0xa502, 0x0e00, 0x8420, 0x2300, 0xa210, 0x1f04, - 0x3b41, 0x015e, 0x2011, 0x0184, 0xa582, 0x0185, 0x0ab0, 0x0890, - 0x2021, 0x3b75, 0x20a9, 0x0003, 0x2011, 0x0024, 0xa586, 0x0024, - 0x0960, 0x8420, 0x2011, 0x0028, 0xa586, 0x0028, 0x0930, 0x8420, - 0x2019, 0x0019, 0x2011, 0x0033, 0x0804, 0x3b19, 0x1021, 0x2202, - 0x3403, 0x4604, 0x5805, 0x6a06, 0x7c07, 0x4610, 0x4612, 0x5812, - 0x5a12, 0x6a14, 0x6c14, 0x6e14, 0x7e17, 0x9021, 0xb002, 0xe204, - 0xe210, 0xe210, 0x1209, 0x3002, 0x3202, 0x4203, 0x4403, 0x5404, - 0x5604, 0x6605, 0x6805, 0x7806, 0x7a06, 0x0c07, 0x0c07, 0x0e07, - 0x10e1, 0x330a, 0x5805, 0x5a05, 0x6a06, 0x6c06, 0x7c07, 0x7e07, - 0x0e00, 0x789b, 0x0080, 0xa046, 0x0005, 0xa784, 0x0f00, 0x800b, - 0xa784, 0x001f, 0x8003, 0x8003, 0x8003, 0x8003, 0xa105, 0xd7fc, - 0x0118, 0xa0e0, 0x6cc0, 0x0010, 0xa0e0, 0x4cc0, 0x0005, 0x00e6, - 0x00f6, 0xd084, 0x0138, 0x2079, 0x0100, 0x2009, 0x4780, 0x2071, - 0x4780, 0x0030, 0x2009, 0x4740, 0x2079, 0x0200, 0x2071, 0x4740, - 0x2091, 0x8000, 0x2104, 0xa084, 0x000f, 0x0002, 0x3bc8, 0x3bc8, - 0x3bc8, 0x3bc8, 0x3bc8, 0x3bc8, 0x3bc6, 0x3bc6, 0x080c, 0x2575, - 0x69b4, 0xc1f5, 0xa18c, 0xff9f, 0x69b6, 0xa005, 0x0580, 0x7858, - 0xa084, 0xff9f, 0xa085, 0x6000, 0x785a, 0x7828, 0xa086, 0x1814, - 0x1530, 0x784b, 0x0004, 0x7848, 0xa084, 0x0004, 0x1de0, 0x784b, - 0x0008, 0x7848, 0xa084, 0x0008, 0x1de0, 0x7830, 0xd0bc, 0x11b8, - 0xb284, 0x0800, 0x0118, 0x0104, 0x3bff, 0x0010, 0x0304, 0x3bff, - 0x79e4, 0xa184, 0x0030, 0x0158, 0x78ec, 0xa084, 0x0003, 0x0138, - 0x681c, 0xd0ac, 0x1110, 0x00d9, 0x0010, 0x781b, 0x00fb, 0x00fe, - 0x00ee, 0x0005, 0x2001, 0x4701, 0x2004, 0xd0ac, 0x1118, 0x6814, - 0x080c, 0x249e, 0x0005, 0x781b, 0x0083, 0x0005, 0x781b, 0x0082, - 0x0005, 0x781b, 0x0071, 0x0005, 0x781b, 0x006e, 0x0005, 0x2009, - 0x4719, 0x210c, 0xa186, 0x0000, 0x0150, 0xa186, 0x0001, 0x0150, - 0x701f, 0x000b, 0x7063, 0x0001, 0x781b, 0x0054, 0x0005, 0x781b, - 0x00f3, 0x0005, 0x701f, 0x000a, 0x0005, 0x2009, 0x4719, 0x210c, - 0xa186, 0x0000, 0x0168, 0xa186, 0x0001, 0x0138, 0x701f, 0x000b, - 0x7063, 0x0001, 0x781b, 0x0054, 0x0005, 0x701f, 0x000a, 0x0005, - 0x781b, 0x00f2, 0x0005, 0x781b, 0x00fb, 0x0005, 0x781b, 0x00fa, - 0x0005, 0x781b, 0x00cc, 0x0005, 0x781b, 0x00cb, 0x0005, 0x6818, - 0xd0fc, 0x0110, 0x681b, 0x001d, 0x701f, 0x000b, 0x7063, 0x0001, - 0x781b, 0x0054, 0x0005, 0x7830, 0xa084, 0x00c0, 0x1170, 0x7808, - 0xc08c, 0x780a, 0xe000, 0xe000, 0xe000, 0xe000, 0x78ec, 0xa084, - 0x0021, 0x0118, 0x7808, 0xc08d, 0x780a, 0x0005, 0x7808, 0xc08d, - 0x780a, 0x0005, 0x7830, 0xa084, 0x0040, 0x1de0, 0xb284, 0x0800, - 0x0118, 0x1104, 0x3c80, 0x0010, 0x1304, 0x3c80, 0x78ac, 0x0005, - 0x7808, 0xa084, 0xfffd, 0x780a, 0xe000, 0xe000, 0xe000, 0xe000, - 0x78ec, 0xa084, 0x0021, 0x0140, 0xb284, 0x0800, 0x0118, 0x1104, - 0x3c8f, 0x0010, 0x1304, 0x3c92, 0x78ac, 0x0006, 0x7808, 0xa085, - 0x0002, 0x780a, 0x000e, 0x0005, 0xa784, 0x0001, 0x1904, 0x324d, - 0xa784, 0x0070, 0x0140, 0x00c6, 0x2d60, 0x2f68, 0x080c, 0x2490, - 0x2d78, 0x2c68, 0x00ce, 0xa784, 0x0008, 0x0148, 0x784b, 0x0008, - 0x78ec, 0xa084, 0x0003, 0x0904, 0x324d, 0x0804, 0x3c0b, 0xa784, - 0x0004, 0x01c8, 0x78b8, 0xa084, 0x8000, 0x01a8, 0x784b, 0x0008, - 0x78ec, 0xa084, 0x0003, 0x0904, 0x324d, 0x78e4, 0xa084, 0x0007, - 0xa086, 0x0001, 0x1140, 0x78c0, 0xa685, 0x4800, 0x2030, 0x7e5a, - 0x781b, 0x00fb, 0x0005, 0xa784, 0x0080, 0x0140, 0x7884, 0xd0fc, - 0x0128, 0x080c, 0x3a57, 0x681b, 0x0022, 0x0005, 0x681b, 0x0003, - 0x7858, 0xa084, 0x5f00, 0x681e, 0x682f, 0x0000, 0x6833, 0x0000, - 0x784b, 0x0008, 0x78ec, 0xa084, 0x0003, 0x0904, 0x2bac, 0xb284, - 0x0800, 0x0110, 0x0104, 0x25c6, 0x0304, 0x25c6, 0x6b14, 0x8307, - 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xd3fc, 0x0118, 0xa080, - 0x4c40, 0x0010, 0xa080, 0x4bc0, 0x2060, 0x2048, 0x7056, 0x2a60, - 0x0005, 0x00c6, 0x2960, 0x6000, 0xd0ac, 0x0904, 0x3d57, 0x68a0, - 0xd1ac, 0x1120, 0xa084, 0x0e00, 0x0904, 0x3d55, 0x6108, 0x8117, - 0xa18c, 0x00ff, 0x631c, 0x832f, 0xd0dc, 0x0110, 0xa39d, 0x0001, - 0xd0cc, 0x11c8, 0xa584, 0x00ff, 0x0138, 0x78ec, 0xd0e4, 0x0110, - 0x8213, 0x00b8, 0x2029, 0x0000, 0xa182, 0x000c, 0x1290, 0x78ec, - 0xd0e4, 0x1118, 0x2009, 0x000c, 0x0060, 0xa182, 0x000b, 0x1248, - 0x2009, 0x000a, 0x0030, 0x2009, 0x0032, 0x2011, 0x0000, 0x2029, - 0x0000, 0x78ab, 0x0001, 0x78ab, 0x0006, 0x78ab, 0x0004, 0x79aa, - 0x78ab, 0x0000, 0x7aaa, 0x7baa, 0x7daa, 0xa8c0, 0x0008, 0x6820, - 0xa085, 0x1000, 0x6822, 0x080c, 0x3a7a, 0xa085, 0x0001, 0x00ce, - 0x0005, 0xa282, 0x0006, 0x1904, 0x3a49, 0x7da8, 0x7eac, 0x8637, - 0xa5ac, 0x00ff, 0xa6b4, 0x00ff, 0x7fac, 0x8747, 0xa7bc, 0x00ff, - 0xa8c4, 0x00ff, 0x6920, 0xc1bd, 0x6922, 0xd1e4, 0x0904, 0x3dcb, - 0xa18c, 0xecff, 0x6922, 0xa782, 0x0002, 0x1a04, 0x3a23, 0xa6b4, - 0x00ff, 0x0904, 0x3dc8, 0xa682, 0x0031, 0x1a04, 0x3a23, 0xa582, - 0x0009, 0x0a04, 0x3a23, 0xa882, 0x0003, 0x1a04, 0x3a23, 0xa886, - 0x0002, 0x01d0, 0xa886, 0x0000, 0x1904, 0x3a23, 0x2001, 0x000c, - 0x79ec, 0xd1e4, 0x0110, 0x2001, 0x000a, 0xa502, 0x1290, 0x080c, - 0x3a23, 0x00c6, 0x2960, 0x6004, 0xa085, 0x001a, 0x6006, 0x6000, - 0xc0ac, 0x6002, 0x00ce, 0x0005, 0xa786, 0x0000, 0x0904, 0x3a23, - 0x8634, 0xa682, 0x0018, 0x0228, 0x0120, 0x2031, 0x0018, 0x0804, - 0x3e19, 0xa686, 0x0010, 0x1108, 0x8630, 0x852b, 0x852b, 0x080c, - 0x3aee, 0x0904, 0x3a23, 0x080c, 0x391a, 0x080c, 0x39bf, 0x7e58, - 0xd6d4, 0x1118, 0x781b, 0x0071, 0x0005, 0x781b, 0x0083, 0x0005, - 0x080c, 0x3917, 0x0c90, 0xa886, 0x0002, 0x1108, 0x8634, 0x7154, - 0xa188, 0x0000, 0x210c, 0xd1ac, 0x0904, 0x3a23, 0xd1ec, 0x1120, - 0x2039, 0x0000, 0x2041, 0x0000, 0xd1e4, 0x1120, 0x2031, 0x0000, - 0x2041, 0x0000, 0xa782, 0x0002, 0x12c8, 0x621c, 0xa284, 0x00ff, - 0xa706, 0x0110, 0x2039, 0x0000, 0xa605, 0x0190, 0x6108, 0x811f, - 0xa39c, 0x00ff, 0x0168, 0xa302, 0x1208, 0x2330, 0x8807, 0xa705, - 0xa086, 0x0201, 0x0160, 0xa886, 0x0000, 0x0168, 0x2039, 0x0000, - 0x2041, 0x0000, 0x2031, 0x0000, 0xa006, 0x2010, 0x0070, 0xa284, - 0xff00, 0x1108, 0x2040, 0xa184, 0x00ff, 0xa502, 0x0108, 0x2128, - 0x852b, 0x852b, 0x080c, 0x3aee, 0x0d58, 0x080c, 0x391a, 0x080c, - 0x39bf, 0x789b, 0x0080, 0x78ab, 0x0001, 0x78ab, 0x0006, 0x78ab, - 0x0004, 0x7daa, 0x78ab, 0x0000, 0x7eaa, 0x7faa, 0x2800, 0x78aa, - 0x789b, 0x0060, 0x78ab, 0x0008, 0x6820, 0xc0e5, 0x6822, 0x080c, - 0x3a7a, 0x7858, 0xc095, 0x785a, 0x781b, 0x0082, 0x0005, 0x0020, - 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, - 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, - 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, - 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, - 0x0020, 0x0062, 0x0009, 0x0014, 0x0014, 0x9855, 0x984d, 0x0014, - 0x9911, 0x98ff, 0x0014, 0x0014, 0x0090, 0x00e7, 0x0100, 0x0402, - 0x2008, 0xf880, 0x0018, 0x0017, 0x840f, 0xd8c1, 0x0014, 0x0016, - 0xa20a, 0x0014, 0x300b, 0xa20c, 0x0014, 0x2500, 0x0013, 0x2500, - 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, - 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0xa200, 0x3806, - 0x8839, 0x20c4, 0x0864, 0xa850, 0x3008, 0x28c1, 0x9d18, 0xa201, - 0x300c, 0x2847, 0x8161, 0x846a, 0x8000, 0x84a4, 0x1856, 0x883a, - 0xa808, 0x28e2, 0x9cce, 0xa8f3, 0x0864, 0xa83e, 0x300c, 0xa801, - 0x3008, 0x28e1, 0x9cce, 0x28a2, 0x7163, 0xa831, 0x2021, 0xa818, - 0xa205, 0x870c, 0xd8de, 0x64a0, 0x6de0, 0x6fc0, 0x67a4, 0x6c80, - 0x0212, 0xa205, 0x883d, 0x882b, 0x1814, 0x883b, 0x7027, 0x85f2, - 0xa737, 0xa532, 0xf003, 0x8576, 0x8677, 0xa813, 0x883e, 0xa811, - 0x2882, 0x7162, 0xa814, 0x280a, 0xa204, 0x64c0, 0x6de0, 0x67a0, - 0x6fc0, 0x1814, 0x883b, 0x7023, 0x8576, 0x8677, 0xa802, 0x7861, - 0x883e, 0x206a, 0x28c1, 0x9d18, 0x2042, 0x2101, 0xa8ca, 0x2902, - 0xa20e, 0xa80b, 0xa207, 0x0014, 0xa203, 0x8000, 0x85a4, 0x1872, - 0x879a, 0x883c, 0x1fe2, 0xf601, 0xa208, 0x856e, 0x7121, 0x0014, - 0x0704, 0x3008, 0x9cce, 0x0014, 0xa202, 0x8000, 0x85a4, 0x3009, - 0x84a8, 0x19e2, 0xf844, 0x856e, 0x883f, 0x08e6, 0xa8f5, 0xf861, - 0xa8eb, 0xf801, 0x0014, 0xf881, 0x0016, 0x85b2, 0x80f0, 0x9532, - 0xfaa2, 0x1de2, 0x0014, 0x8532, 0xf221, 0x0014, 0x1de2, 0x84a8, - 0xd6e0, 0x1fe6, 0x0014, 0x3008, 0x8000, 0x2849, 0x1011, 0xa8fc, - 0x3008, 0x8000, 0xa000, 0x2081, 0x2802, 0x1011, 0xa8fc, 0xa889, - 0x3008, 0x20a1, 0x283c, 0x1011, 0xa8fc, 0xa209, 0x0017, 0x300c, - 0x8000, 0x85a4, 0x1de2, 0xdac1, 0x0014, 0x0210, 0xa801, 0x0014, - 0x26e0, 0x873a, 0xfaa3, 0x19f2, 0x26e0, 0x18f2, 0x0014, 0xa20b, - 0x0014, 0xa20d, 0x3806, 0x0210, 0x9d22, 0x0704, 0xa206, 0x6865, - 0x817e, 0x842a, 0x1dc1, 0x8823, 0x0016, 0x6042, 0x8008, 0xa8fa, - 0x8160, 0x842a, 0x8180, 0xf021, 0x3008, 0x84a8, 0x11d7, 0x7042, - 0x20dd, 0x0011, 0x20d5, 0x8822, 0x0016, 0x0000, 0x0126, 0x70d0, - 0xa084, 0x4c00, 0x8004, 0x2090, 0x7204, 0x7008, 0xc09c, 0xa205, - 0x11a0, 0x720c, 0x82ff, 0x0128, 0x8aff, 0x1178, 0x7200, 0xd284, - 0x1160, 0x7804, 0xd0cc, 0x0110, 0x080c, 0x435b, 0x7007, 0x0008, - 0x7003, 0x0008, 0x012e, 0x2000, 0x0005, 0x7000, 0xa084, 0x0003, - 0x7002, 0xc69c, 0xd084, 0x0588, 0x7108, 0xe000, 0x7008, 0xa106, - 0x1dd8, 0xa184, 0x0003, 0x0904, 0x3fca, 0xa184, 0x01e0, 0x1904, - 0x3fca, 0xd1f4, 0x1d88, 0xa184, 0x3000, 0xa086, 0x1000, 0x0d60, - 0x2011, 0x0180, 0x710c, 0x8211, 0x0130, 0x7008, 0xd0f4, 0x1d20, - 0x700c, 0xa106, 0x0dc0, 0x7007, 0x0012, 0x7108, 0xe000, 0x7008, - 0xa106, 0x1dd8, 0xa184, 0x0003, 0x0568, 0xd194, 0x0db0, 0xd1f4, - 0x0548, 0x7007, 0x0002, 0x0880, 0x0428, 0x7108, 0xd1fc, 0x0130, - 0x080c, 0x40d6, 0x8aff, 0x0904, 0x3f54, 0x0cb8, 0x700c, 0xa08c, - 0x07ff, 0x01e8, 0x7004, 0xd084, 0x0178, 0x7014, 0xa005, 0x1148, - 0x7010, 0x7310, 0xa306, 0x1de0, 0x2300, 0xa005, 0x0128, 0xa102, - 0x1e20, 0x7007, 0x0010, 0x0030, 0x8aff, 0x0148, 0x080c, 0x429a, - 0x1de8, 0x09d8, 0x080c, 0x405c, 0x012e, 0x2000, 0x0005, 0x7204, - 0x7108, 0xc19c, 0x8103, 0x1218, 0x7007, 0x0002, 0x0cc0, 0xa205, - 0x1d88, 0x7007, 0x0008, 0x7003, 0x0008, 0x0006, 0x2001, 0x4701, - 0x2004, 0xd0cc, 0x0110, 0x080c, 0x435b, 0x000e, 0x012e, 0x2000, - 0x0005, 0x6428, 0x84ff, 0x0508, 0x2c70, 0x7004, 0xa0bc, 0x000f, - 0xa7b8, 0x401d, 0x273c, 0x87fb, 0x1148, 0x0210, 0x080c, 0x2575, - 0x609c, 0xa075, 0x0190, 0x0c88, 0x2039, 0x4012, 0x2704, 0xae68, - 0x6808, 0xa630, 0x680c, 0xa529, 0x8421, 0x0138, 0x8738, 0x2704, - 0xa005, 0x1da8, 0x709c, 0xa075, 0x1d00, 0x0005, 0x0000, 0x0005, - 0x0009, 0x000d, 0x0011, 0x0015, 0x0019, 0x001d, 0x0000, 0x0003, - 0x0009, 0x000f, 0x0015, 0x001b, 0x0000, 0x0000, 0x4012, 0x400f, - 0x0000, 0x0000, 0x8000, 0x0000, 0x4012, 0x0000, 0x401a, 0x4017, - 0x0000, 0x0000, 0x0000, 0x0000, 0x401a, 0x0000, 0x4015, 0x4015, - 0x0000, 0x0000, 0x8000, 0x0000, 0x4015, 0x0000, 0x401b, 0x401b, - 0x0000, 0x0000, 0x0000, 0x0000, 0x401b, 0x2079, 0x4700, 0x2071, - 0x0010, 0x7007, 0x000a, 0x7007, 0x0002, 0x7003, 0x0001, 0x2009, - 0x0002, 0x2071, 0x0050, 0x7007, 0x000a, 0x7007, 0x0002, 0x7003, - 0x0000, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1128, 0x8109, 0x0118, - 0x2071, 0x0020, 0x0c80, 0x0005, 0x7004, 0x8004, 0x1a04, 0x40b2, - 0x7108, 0x7008, 0xa106, 0x1de0, 0xa184, 0x01e0, 0x0120, 0x080c, - 0x410e, 0x0804, 0x40d2, 0x7007, 0x0012, 0x2019, 0x0000, 0x7108, - 0x7008, 0xa106, 0x1de0, 0xa184, 0x01e0, 0x0120, 0x080c, 0x410e, - 0x0804, 0x40d2, 0xa19c, 0x300c, 0xa386, 0x2004, 0x0190, 0xa386, - 0x0008, 0x01c0, 0x7004, 0xd084, 0x1148, 0x7108, 0x7008, 0xa106, - 0x1de0, 0xa184, 0x0003, 0x0110, 0x0804, 0x410e, 0xa386, 0x200c, - 0x19f0, 0x7200, 0x8204, 0x0230, 0x730c, 0xa384, 0x07ff, 0x0110, - 0x080c, 0x2575, 0x7108, 0x7008, 0xa106, 0x1de0, 0xa184, 0x01e0, - 0x0118, 0x080c, 0x410e, 0x0470, 0x7007, 0x0012, 0x7000, 0xd084, - 0x1148, 0x7310, 0x7014, 0xa305, 0x0128, 0x710c, 0xa184, 0x07ff, - 0x1904, 0x405c, 0x7108, 0x7008, 0xa106, 0x1de0, 0xa184, 0x01e0, - 0x0118, 0x080c, 0x410e, 0x00b0, 0x7007, 0x0012, 0x7007, 0x0008, - 0x7004, 0xd09c, 0x1de8, 0x7108, 0x7008, 0xa106, 0x1de0, 0xa184, - 0x01e0, 0x0118, 0x080c, 0x410e, 0x0028, 0x7007, 0x0012, 0x7108, - 0x8103, 0x0e88, 0x7003, 0x0008, 0x0005, 0x7108, 0xa184, 0x01e0, - 0x15a8, 0x7108, 0xa184, 0x01e0, 0x1588, 0xa184, 0x0007, 0x0002, - 0x40ea, 0x40f8, 0x40e8, 0x40f8, 0x40e8, 0x4148, 0x40e8, 0x4146, - 0x080c, 0x2575, 0x7004, 0xa084, 0x0010, 0xc08d, 0x7006, 0x8aff, - 0x1118, 0x2049, 0x0000, 0x0005, 0x080c, 0x429a, 0x1de8, 0x0005, - 0x7004, 0xa084, 0x0010, 0xc08d, 0x7006, 0x7004, 0xd084, 0x1140, - 0x7108, 0x7008, 0xa106, 0x1de0, 0xa184, 0x0003, 0x0108, 0x0030, - 0x8aff, 0x0118, 0x080c, 0x429a, 0x1de8, 0x0005, 0x7007, 0x0012, - 0x7108, 0x1d04, 0x4111, 0x2091, 0x6000, 0x1d04, 0x4115, 0x2091, - 0x6000, 0x7007, 0x0012, 0x7007, 0x0008, 0x7004, 0xd09c, 0x1de8, - 0x7007, 0x0012, 0x7108, 0xd1fc, 0x1dd8, 0x7003, 0x0000, 0x7000, - 0xa005, 0x1130, 0x7004, 0xa005, 0x1118, 0x700c, 0xa005, 0x0108, - 0x0c40, 0x2049, 0x0000, 0xb284, 0x0200, 0x0118, 0x2001, 0x0000, - 0x0010, 0x2001, 0x0001, 0x080c, 0x3ba7, 0x681b, 0x0002, 0x2051, - 0x0000, 0x0005, 0x080c, 0x2575, 0x080c, 0x2575, 0x080c, 0x4187, - 0x7210, 0x7114, 0x700c, 0xa09c, 0x07ff, 0x2800, 0xa300, 0xa211, - 0xa189, 0x0000, 0x04a1, 0x2704, 0x2c58, 0xac60, 0x6308, 0x2200, - 0xa322, 0x630c, 0x2100, 0xa31b, 0x2400, 0xa305, 0x0140, 0x1238, - 0x8412, 0x8210, 0x830a, 0xa189, 0x0000, 0x2b60, 0x0c58, 0x2b60, - 0x8a07, 0x0006, 0x6004, 0xd09c, 0x0118, 0xa7ba, 0x4017, 0x0010, - 0xa7ba, 0x400f, 0x000e, 0xa73d, 0x2c00, 0x6886, 0x6f8a, 0x6c92, - 0x6b8e, 0x7108, 0x7008, 0xa106, 0x1de0, 0xa184, 0x01e0, 0x0110, - 0x080c, 0x410e, 0x7007, 0x0012, 0x080c, 0x405c, 0x0005, 0x8a50, - 0x8739, 0x2704, 0xa004, 0x1168, 0x6000, 0xa064, 0x1108, 0x2d60, - 0x6004, 0xa084, 0x000f, 0xa080, 0x402d, 0x203c, 0x87fb, 0x090c, - 0x2575, 0x0005, 0x0126, 0x00d6, 0x70d0, 0xa084, 0x4c00, 0x8004, - 0x2090, 0x00de, 0x6884, 0x2060, 0x6888, 0x6b8c, 0x6c90, 0x8057, - 0xaad4, 0x00ff, 0xa084, 0x00ff, 0x0006, 0x6804, 0xa084, 0x0008, - 0x000e, 0x0118, 0xa0b8, 0x4017, 0x0010, 0xa0b8, 0x400f, 0xb284, - 0x0200, 0x0110, 0x7e20, 0x0008, 0x7e24, 0xa6b5, 0x000c, 0x681c, - 0xd0b4, 0x0108, 0xc685, 0x2400, 0xa305, 0x0550, 0x2c58, 0x2704, - 0x6104, 0xac60, 0x6000, 0xa400, 0x2048, 0xa9cc, 0x0004, 0x0118, - 0x080c, 0x43a3, 0x0400, 0x701a, 0x6004, 0xa301, 0x701e, 0xd19c, - 0x0140, 0x6010, 0xa081, 0x0000, 0x7022, 0x6014, 0xa081, 0x0000, - 0x7026, 0x6208, 0x2400, 0xa202, 0x7012, 0x620c, 0x2300, 0xa203, - 0x7016, 0x7602, 0x7007, 0x0001, 0x2b60, 0x080c, 0x42c5, 0x0010, - 0x080c, 0x429a, 0x1de8, 0x012e, 0x2000, 0x0005, 0x0126, 0x00d6, - 0x70d0, 0xa084, 0x4c00, 0x8004, 0x2090, 0x00de, 0x7007, 0x0004, - 0x7004, 0xd094, 0x1de8, 0x7003, 0x0008, 0x012e, 0x2000, 0x0005, - 0x0126, 0x00d6, 0x70d0, 0xa084, 0x4c00, 0x8004, 0x2090, 0x00de, - 0x7e20, 0xb284, 0x0200, 0x1108, 0x7e24, 0xa6b5, 0x000c, 0x681c, - 0xd0ac, 0x1118, 0xc685, 0x7003, 0x0000, 0x6828, 0x2050, 0x2d60, - 0x6004, 0xa0bc, 0x000f, 0xa7b8, 0x401d, 0x273c, 0x87fb, 0x1138, - 0x0210, 0x080c, 0x2575, 0x689c, 0xa065, 0x0120, 0x0c88, 0x080c, - 0x429a, 0x1de8, 0x012e, 0x2000, 0x0005, 0x0126, 0x0006, 0x0016, - 0x00d6, 0x70d0, 0xa084, 0x4c00, 0x8004, 0x2090, 0x7e20, 0xb284, - 0x0200, 0x1108, 0x7e24, 0x00de, 0x003e, 0x004e, 0xa6b5, 0x000c, - 0x681c, 0xd0b4, 0x0128, 0xc685, 0x7003, 0x0000, 0x7007, 0x0004, - 0x2049, 0x4235, 0x6828, 0xa055, 0x00d6, 0x0904, 0x4296, 0x2d70, - 0x2e60, 0x7004, 0xa0bc, 0x000f, 0xa7b8, 0x401d, 0x273c, 0x87fb, - 0x1140, 0x0210, 0x080c, 0x2575, 0x709c, 0xa075, 0x2060, 0x0570, - 0x0c80, 0x2704, 0xae68, 0x6808, 0xa422, 0x680c, 0xa31b, 0x0268, - 0x8a51, 0x1110, 0x080c, 0x2575, 0x8738, 0x2704, 0xa005, 0x1d90, - 0x709c, 0xa075, 0x2060, 0x01d0, 0x08e0, 0x8422, 0x8420, 0x831a, - 0xa399, 0x0000, 0x6908, 0x2400, 0xa122, 0x690c, 0x2300, 0xa11b, - 0x1210, 0x080c, 0x2575, 0xb284, 0x0200, 0x0118, 0x2071, 0x0050, - 0x0010, 0x2071, 0x0020, 0x00de, 0x0804, 0x41c3, 0x00de, 0x012e, - 0x2000, 0x0005, 0x7008, 0x0006, 0xa084, 0x01e0, 0x000e, 0x0110, - 0xa006, 0x0005, 0xa084, 0x0003, 0xa086, 0x0003, 0x1108, 0x0005, - 0x2704, 0xac78, 0x7800, 0x2f08, 0xd094, 0x1904, 0x43a6, 0x701a, - 0x7804, 0x701e, 0x7808, 0x7012, 0x780c, 0x7016, 0x6004, 0xd09c, - 0x0120, 0x7810, 0x7022, 0x7814, 0x7026, 0x7602, 0x7004, 0xa084, - 0x0010, 0xc085, 0x7006, 0x2079, 0x4700, 0x8a51, 0x01e8, 0x8738, - 0x2704, 0xa005, 0x1168, 0x609c, 0xa005, 0x01b8, 0x2060, 0x6004, - 0xa084, 0x000f, 0xa080, 0x401d, 0x203c, 0x87fb, 0x090c, 0x2575, - 0x7008, 0x0006, 0xa084, 0x01e0, 0x000e, 0x0110, 0xa006, 0x0028, - 0xa084, 0x0003, 0xa086, 0x0003, 0x0005, 0x2051, 0x0000, 0x0005, - 0x0126, 0x0006, 0x00d6, 0x70d0, 0xa084, 0x4c00, 0x8004, 0x2090, - 0x00de, 0x008e, 0x7108, 0xa184, 0x0003, 0x1128, 0x6828, 0xa005, - 0x0178, 0x0804, 0x3f6d, 0x7108, 0xd1fc, 0x0118, 0x080c, 0x40d6, - 0x0c88, 0x7007, 0x0010, 0x7108, 0xd1fc, 0x0de8, 0x080c, 0x40d6, - 0x7008, 0xa086, 0x0008, 0x1d30, 0x7000, 0xa005, 0x1d18, 0x7003, - 0x0000, 0x2049, 0x0000, 0x0006, 0x2001, 0x4701, 0x2004, 0xd0cc, - 0x0110, 0x080c, 0x435b, 0x000e, 0x012e, 0x2000, 0x0005, 0x0126, - 0x0146, 0x0136, 0x0156, 0x00c6, 0x00d6, 0x70d0, 0xa084, 0x4c00, - 0x8004, 0x2090, 0x00de, 0x2049, 0x431f, 0xad80, 0x0011, 0x20a0, - 0xb284, 0x0200, 0x0118, 0x2099, 0x0032, 0x0010, 0x2099, 0x0031, - 0x700c, 0xa084, 0x07ff, 0x682a, 0x7007, 0x0008, 0x7007, 0x0002, - 0x7003, 0x0001, 0x0118, 0x8000, 0x80ac, 0x53a5, 0x700c, 0xa084, - 0x07ff, 0x0130, 0x7007, 0x0004, 0x7004, 0xa084, 0x0004, 0x1de0, - 0x00ce, 0x2049, 0x0000, 0x7003, 0x0000, 0x015e, 0x013e, 0x014e, - 0x012e, 0x2000, 0x0005, 0x6814, 0xd0fc, 0x0904, 0x439e, 0x7000, - 0xd084, 0x05e0, 0x7e24, 0xa6b5, 0x0004, 0x7007, 0x0004, 0x7004, - 0xa084, 0x0004, 0x1de0, 0x7118, 0x0016, 0x711c, 0x0016, 0x7120, - 0x0016, 0x7124, 0x0016, 0x701b, 0x0000, 0x701f, 0x3fff, 0x7023, - 0x0000, 0x7027, 0x0000, 0x7013, 0x0004, 0x7017, 0x0000, 0x7602, - 0x7007, 0x0001, 0x2001, 0xffff, 0x2009, 0x0031, 0x200a, 0x200a, - 0x7108, 0x7008, 0xa106, 0x1de0, 0xd1fc, 0x0dd0, 0x002e, 0x7226, - 0x002e, 0x7222, 0x002e, 0x721e, 0x002e, 0x721a, 0x7007, 0x0002, - 0x7008, 0xa086, 0x0008, 0x0110, 0x0804, 0x410e, 0x7007, 0x0004, - 0x7003, 0x0000, 0x0005, 0x2049, 0x41c3, 0x0068, 0x7008, 0xa084, - 0x0003, 0x0110, 0xa006, 0x0005, 0xa006, 0x2020, 0x2018, 0x2c58, - 0x2160, 0x2049, 0x0000, 0x8b58, 0x6100, 0x2100, 0xa408, 0x711a, - 0x6004, 0xa301, 0x701e, 0x0006, 0x2b04, 0xa084, 0x0008, 0x0150, - 0x6010, 0xa081, 0x0000, 0x7022, 0x0006, 0x6014, 0xa081, 0x0000, - 0x7026, 0x0006, 0xa184, 0x0007, 0x2011, 0x0008, 0xa22a, 0x6208, - 0x2400, 0xa212, 0x0026, 0x620c, 0x2240, 0x2300, 0xa843, 0x002e, - 0x88ff, 0x1170, 0x2500, 0xa202, 0x0108, 0x1250, 0x2220, 0x2041, - 0x0000, 0x2b04, 0xd09c, 0x0110, 0x000e, 0x000e, 0x000e, 0x0450, - 0x7512, 0x7017, 0x0000, 0x7602, 0xa986, 0x41c3, 0x1118, 0x7007, - 0x0001, 0x0028, 0x7004, 0xa084, 0x0010, 0xc085, 0x7006, 0x2500, - 0xa100, 0x701a, 0x2b04, 0xa084, 0x0008, 0x0110, 0x000e, 0x004e, - 0x001e, 0xa189, 0x0000, 0x711e, 0x2b0c, 0xa18c, 0x0008, 0x0130, - 0xa4a1, 0x0000, 0x7422, 0xa081, 0x0000, 0x7026, 0x2500, 0xa222, - 0xa8c3, 0x0000, 0x7412, 0x2820, 0x7416, 0x7602, 0xa986, 0x41c3, - 0x1118, 0x7007, 0x0001, 0x0028, 0x7004, 0xa084, 0x0010, 0xc085, - 0x7006, 0x8b59, 0x2b60, 0x2079, 0x4700, 0x080c, 0x42c5, 0xa006, - 0x0005, 0x2091, 0x8000, 0x2091, 0x6000, 0x78ac, 0xa005, 0x1168, - 0x7974, 0x70d0, 0xa106, 0x1148, 0x781c, 0xa005, 0x0130, 0x781f, - 0x0000, 0x0e04, 0x443d, 0x2091, 0x4080, 0x2069, 0x4780, 0xc7fd, - 0x6800, 0xa084, 0x000f, 0x1198, 0x68d0, 0xd0b4, 0x0180, 0xd0bc, - 0x1170, 0x00f6, 0x2079, 0x0100, 0xd7fc, 0x1110, 0x2079, 0x0200, - 0x7830, 0xa084, 0x00c0, 0x1110, 0x080c, 0x22d5, 0x00fe, 0xd7fc, - 0x0120, 0x2069, 0x4740, 0xc7fc, 0x0c18, 0x7830, 0x8001, 0x7832, - 0x1904, 0x44c7, 0x7834, 0x7832, 0x2061, 0x6cc0, 0x2069, 0x4780, - 0xc7fd, 0x68cc, 0xa005, 0x0128, 0x8001, 0x68ce, 0x1110, 0x080c, - 0x4639, 0x6800, 0xa084, 0x000f, 0x0168, 0xa086, 0x0001, 0x0150, - 0x6840, 0xa00d, 0x0138, 0x2104, 0xa005, 0x0120, 0x8001, 0x200a, - 0x0904, 0x45d6, 0x6814, 0xa005, 0x01a8, 0x8001, 0x6816, 0x1190, - 0x68a3, 0x0001, 0x00f6, 0xd7fc, 0x1118, 0x2079, 0x0200, 0x0010, - 0x2079, 0x0100, 0x080c, 0x3c6e, 0x00fe, 0x6860, 0xa005, 0x0110, - 0x080c, 0x22d5, 0x687c, 0xa005, 0x0140, 0x8001, 0x687e, 0x1128, - 0x6863, 0x0000, 0x68d0, 0xc0c5, 0x68d2, 0x68d0, 0xd0fc, 0x01b0, - 0xc0fc, 0x68d2, 0x20a9, 0x0200, 0x6034, 0xa005, 0x0158, 0x8001, - 0x6036, 0x68d0, 0xc0fd, 0x68d2, 0x1128, 0x6010, 0xa005, 0x0110, - 0x080c, 0x22d5, 0xace0, 0x0010, 0x1f04, 0x44ac, 0xd7fc, 0x0138, - 0x2061, 0x4cc0, 0x2069, 0x4740, 0xc7fc, 0x0804, 0x4469, 0x0459, - 0x7838, 0x8001, 0x783a, 0x11a0, 0x783c, 0x783a, 0x2061, 0x4cc0, - 0x2069, 0x4740, 0xc7fc, 0x680c, 0xa005, 0x0110, 0x080c, 0x4543, - 0xd7fc, 0x1130, 0x2061, 0x6cc0, 0x2069, 0x4780, 0xc7fd, 0x0c98, - 0x7810, 0xd0cc, 0x0168, 0xd0ac, 0x1120, 0xd0a4, 0x0148, 0xc0ad, - 0x7812, 0x2091, 0x8001, 0x0e04, 0x44ef, 0x080c, 0x20a1, 0x0005, - 0x2091, 0x8001, 0x0005, 0x7840, 0x8001, 0x7842, 0x1904, 0x4542, - 0x7844, 0x7842, 0x2069, 0x4740, 0xc7fc, 0x2079, 0x0200, 0x68d4, - 0xa005, 0x0138, 0x7de0, 0xa504, 0x1120, 0x68d6, 0x68d0, 0xc0bc, - 0x68d2, 0x2079, 0x4700, 0x6810, 0xa005, 0x1110, 0x2001, 0x0101, - 0x8001, 0x6812, 0xd7fc, 0x0118, 0xa080, 0x8dd0, 0x0010, 0xa080, - 0x8cc0, 0x2040, 0x2004, 0xa065, 0x01e0, 0x6024, 0xa005, 0x01b0, - 0x8001, 0x6026, 0x1198, 0x6800, 0xa005, 0x0130, 0x6848, 0xac06, - 0x1118, 0x080c, 0x45d6, 0x0068, 0x6860, 0xa005, 0x0118, 0x6027, - 0x0001, 0x0020, 0x080c, 0x4584, 0x2804, 0x0c28, 0x6000, 0x2c40, - 0x0c10, 0xd7fc, 0x1138, 0x2069, 0x4780, 0xc7fd, 0x2079, 0x0100, - 0x0804, 0x44ff, 0x0005, 0x2009, 0x0000, 0x20a9, 0x0200, 0x6008, - 0xd09c, 0x0558, 0x6024, 0xa005, 0x0118, 0x8001, 0x6026, 0x0418, - 0x6008, 0xc09c, 0xd084, 0x1110, 0xd0ac, 0x01c0, 0x600a, 0x6004, - 0xa005, 0x01d8, 0x00d6, 0x00c6, 0x0016, 0x2068, 0x6010, 0x8001, - 0x6012, 0x080c, 0x37c7, 0x2d00, 0x2c68, 0x2060, 0x080c, 0x1c02, - 0x080c, 0x1db2, 0x001e, 0x00ce, 0x00de, 0x0038, 0xc0bd, 0x600a, - 0xa18d, 0x0001, 0x0010, 0xa18d, 0x0100, 0xace0, 0x0010, 0x1f04, - 0x4547, 0xa184, 0x0001, 0x0130, 0xa18c, 0xfffe, 0x690e, 0x080c, - 0x22d5, 0x0008, 0x690e, 0x0005, 0x2c00, 0x687a, 0x6714, 0x6f72, - 0x6017, 0x0000, 0x602b, 0x0000, 0x601b, 0x0006, 0x60b4, 0xa084, - 0x5f00, 0x601e, 0x6020, 0xa084, 0x00ff, 0xa085, 0x0060, 0x6022, - 0x6000, 0x2042, 0x2069, 0x4780, 0xd7fc, 0x1110, 0x2069, 0x4740, - 0x6858, 0xac06, 0x1110, 0x2800, 0x685a, 0x080c, 0x1b9a, 0x6818, - 0xa005, 0x0110, 0x8001, 0x681a, 0x6808, 0xc0a4, 0x680a, 0x6810, - 0x7908, 0x8109, 0x790a, 0x8001, 0x1310, 0x080c, 0x2575, 0x6812, - 0x1118, 0x7910, 0xc1a5, 0x7912, 0x602f, 0x0000, 0x6033, 0x0000, - 0x2c68, 0x080c, 0x1dbf, 0xd7fc, 0x1118, 0x2069, 0x4740, 0x0010, - 0x2069, 0x4780, 0x6910, 0xa184, 0x0100, 0x2001, 0x0006, 0x1118, - 0x6976, 0x2001, 0x0004, 0x080c, 0x22cb, 0x0005, 0x00d6, 0x6948, - 0x2160, 0xd7fc, 0x1118, 0x2069, 0x0200, 0x0010, 0x2069, 0x0100, - 0x080c, 0x2490, 0x601b, 0x0006, 0x6858, 0xa084, 0x5f00, 0x601e, - 0x6020, 0xa084, 0x00ff, 0xa085, 0x0048, 0x6022, 0x602f, 0x0000, - 0x6033, 0x0000, 0x6808, 0xa084, 0xfffd, 0x680a, 0x6830, 0xd0b4, - 0x01b0, 0x684b, 0x0004, 0x20a9, 0x0014, 0x6848, 0xd094, 0x0110, - 0x1f04, 0x45fd, 0x684b, 0x0009, 0x20a9, 0x0014, 0x6848, 0xd084, - 0x0110, 0x1f04, 0x4606, 0x20a9, 0x00fa, 0x1f04, 0x460d, 0x681b, - 0x0054, 0x00de, 0x6863, 0x0007, 0x0005, 0x2079, 0x4700, 0x00e1, - 0x0089, 0x00a9, 0x2009, 0x0002, 0x2069, 0x4780, 0x680f, 0x0000, - 0x6813, 0x0000, 0x6817, 0x0000, 0x8109, 0x0118, 0x2069, 0x4740, - 0x0ca8, 0x0005, 0x2019, 0x00a3, 0x7b3a, 0x7b3e, 0x0005, 0x2019, - 0x0033, 0x7b42, 0x7b46, 0x0005, 0x2019, 0x32dd, 0x7b32, 0x7b36, - 0x0005, 0x6a4c, 0xa285, 0x0000, 0x01f0, 0x6950, 0x6bbc, 0xa300, - 0x00c6, 0x2164, 0x6304, 0x83ff, 0x1138, 0x8211, 0x0148, 0x8108, - 0xa11a, 0x0eb8, 0x69bc, 0x0ca8, 0x68cf, 0x000a, 0x00ce, 0x0005, - 0x694c, 0x6abc, 0x2264, 0x6008, 0xc0b5, 0x600a, 0x8210, 0x8109, - 0x1dc8, 0x694e, 0x00ce, 0x0005, 0x0016, 0x1d04, 0x465d, 0x2091, - 0x6000, 0x1d04, 0x4661, 0x2091, 0x6000, 0x70ec, 0xd0dc, 0x1118, - 0xd0d4, 0x0190, 0x00a0, 0xae8e, 0x0100, 0x0138, 0x7814, 0xc0f5, - 0xc0c5, 0x7816, 0xd0d4, 0x1580, 0x0460, 0x7814, 0xc0fd, 0xc0c5, - 0x7816, 0xd0d4, 0x1548, 0x0428, 0xd0e4, 0x0904, 0x46c4, 0x1d04, - 0x467f, 0x2091, 0x6000, 0x2009, 0x000c, 0x1d04, 0x4685, 0x2091, - 0x6000, 0x8109, 0x1dd0, 0x70e4, 0xa084, 0x01ff, 0xa086, 0x01ff, - 0x1110, 0x70ec, 0x08c0, 0xae8e, 0x0100, 0x0128, 0x7814, 0xc0f4, - 0xd0fc, 0x1130, 0x0020, 0x7814, 0xc0fc, 0xd0f4, 0x1108, 0xc0c4, - 0x7816, 0x7804, 0xd08c, 0x0500, 0x00c6, 0x2061, 0x0000, 0x6018, - 0xd084, 0x11b8, 0xae86, 0x0200, 0x00e6, 0x2071, 0x0010, 0x0120, - 0x70db, 0x0001, 0x78e4, 0x0018, 0x70db, 0x0000, 0x78e0, 0x70c6, - 0x70c3, 0x800e, 0x601b, 0x0001, 0x2091, 0x4080, 0x00ee, 0x00ce, - 0x0018, 0x00ce, 0x681f, 0x000c, 0x001e, 0x70a0, 0x70a2, 0x0005, - 0x0c26 -}; -#ifdef UNIQUE_FW_NAME -static unsigned short fw12160i_length01 = 0x36c9; -#else -static unsigned short risc_code_length01 = 0x36c9; -#endif - diff --git a/drivers/scsi/ql1280_fw.h b/drivers/scsi/ql1280_fw.h deleted file mode 100644 index 784f2a04bf2..00000000000 --- a/drivers/scsi/ql1280_fw.h +++ /dev/null @@ -1,2048 +0,0 @@ -/***************************************************************************** - * QLOGIC LINUX SOFTWARE - * - * QLogic ISP1280/ device driver for Linux 2.2.x and 2.4.x - * Copyright (C) 2001 Qlogic Corporation (www.qlogic.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, 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. - * - *****************************************************************************/ - -/************************************************************************ - * --- ISP1240/1080/1280 Initiator Firmware --- * - * 32 LUN Support * - ************************************************************************/ - - -/* - * Firmware Version 8.15.11 (10:20 Jan 02, 2002) - */ - -#ifdef UNIQUE_FW_NAME -static unsigned char fw1280ei_version_str[] = {8,15,11}; -#else -static unsigned char firmware_version[] = {8,15,11}; -#endif - -#ifdef UNIQUE_FW_NAME -#define fw1280ei_VERSION_STRING "8.15.11" -#else -#define FW_VERSION_STRING "8.15.11" -#endif - -#ifdef UNIQUE_FW_NAME -static unsigned short fw1280ei_addr01 = 0x1000 ; -#else -static unsigned short risc_code_addr01 = 0x1000 ; -#endif - -#ifdef UNIQUE_FW_NAME -static unsigned short fw1280ei_code01[] = { -#else -static unsigned short risc_code01[] = { -#endif - 0x0078, 0x1041, 0x0000, 0x3e2e, 0x0000, 0x2043, 0x4f50, 0x5952, - 0x4947, 0x4854, 0x2031, 0x3939, 0x312c, 0x3139, 0x3932, 0x2c31, - 0x3939, 0x332c, 0x3139, 0x3934, 0x2051, 0x4c4f, 0x4749, 0x4320, - 0x434f, 0x5250, 0x4f52, 0x4154, 0x494f, 0x4e00, 0x2049, 0x5350, - 0x3132, 0x3430, 0x2046, 0x6972, 0x6d77, 0x6172, 0x6520, 0x2056, - 0x6572, 0x7369, 0x6f6e, 0x2030, 0x382e, 0x3135, 0x2020, 0x2043, - 0x7573, 0x746f, 0x6d65, 0x7220, 0x4e6f, 0x2e20, 0x3030, 0x2050, - 0x726f, 0x6475, 0x6374, 0x204e, 0x6f2e, 0x2020, 0x3030, 0x2020, - 0x2400, 0x20c9, 0x98ff, 0x2001, 0x04fc, 0x2004, 0xa086, 0x1080, - 0x00c0, 0x1054, 0x2071, 0x0100, 0x70a0, 0x70a2, 0x20c1, 0x0010, - 0x2089, 0x1374, 0x0078, 0x106d, 0x2001, 0x04fc, 0x2004, 0xa086, - 0x1280, 0x00c0, 0x1069, 0x2071, 0x0200, 0x70a0, 0x70a2, 0x2071, - 0x0100, 0x70a0, 0x70a2, 0x20c1, 0x0010, 0x2089, 0x13f8, 0x0078, - 0x106d, 0x20c1, 0x0020, 0x2089, 0x131c, 0x2071, 0x0010, 0x70c3, - 0x0004, 0x70c7, 0x4953, 0x70cb, 0x5020, 0x70cf, 0x2020, 0x70d3, - 0x0008, 0x2001, 0x04fe, 0x70d6, 0x20c1, 0x0021, 0x2019, 0x0000, - 0x2009, 0xfeff, 0x2100, 0x200b, 0xa5a5, 0xa1ec, 0x7fff, 0x2d64, - 0x206b, 0x0a0a, 0xaddc, 0x3fff, 0x2b54, 0x205b, 0x5050, 0x2114, - 0xa286, 0xa5a5, 0x0040, 0x10a4, 0xa386, 0x000f, 0x0040, 0x10a0, - 0x2c6a, 0x2a5a, 0x20c1, 0x0020, 0x2019, 0x000f, 0x0078, 0x1080, - 0x2c6a, 0x2a5a, 0x0078, 0x10a2, 0x2c6a, 0x2a5a, 0x2130, 0x2128, - 0xa1a2, 0x4f00, 0x8424, 0x8424, 0x8424, 0x8424, 0x8424, 0x8424, - 0xa192, 0x9900, 0x2009, 0x0000, 0x2001, 0x0032, 0x1078, 0x20c1, - 0x2218, 0x2079, 0x4f00, 0x2fa0, 0x2408, 0x2011, 0x0000, 0x20a9, - 0x0040, 0x42a4, 0x8109, 0x00c0, 0x10bf, 0x2009, 0xff00, 0x3400, - 0xa102, 0x0048, 0x10cf, 0x0040, 0x10cf, 0x20a8, 0x42a4, 0x2001, - 0x04fc, 0x2004, 0xa086, 0x1080, 0x00c0, 0x10e5, 0x2071, 0x0100, - 0x0d7e, 0x2069, 0x4f40, 0x1078, 0x4db0, 0x0d7f, 0x7810, 0xc0ed, - 0x7812, 0x781b, 0x0064, 0x0078, 0x110a, 0x2001, 0x04fc, 0x2004, - 0xa086, 0x1280, 0x00c0, 0x1105, 0x7814, 0xc0ed, 0xc0d5, 0x7816, - 0x781b, 0x0064, 0x2071, 0x0200, 0x0d7e, 0x2069, 0x4f40, 0x1078, - 0x4db0, 0x2069, 0x4f80, 0x2071, 0x0100, 0x1078, 0x4db0, 0x7814, - 0xc0d4, 0x7816, 0x0d7f, 0x0078, 0x110a, 0x7814, 0xc0e5, 0x7816, - 0x781b, 0x003c, 0x7eca, 0x7cc2, 0x7bc6, 0x7867, 0x0000, 0x7800, - 0xc08d, 0x7802, 0x2031, 0x0030, 0x78af, 0x0101, 0x7823, 0x0002, - 0x7827, 0x0002, 0x2009, 0x0002, 0x2069, 0x4f40, 0x681b, 0x0003, - 0x6823, 0x0007, 0x6827, 0x00fa, 0x682b, 0x0008, 0x682f, 0x0028, - 0x6837, 0x0000, 0x683b, 0x0006, 0x6833, 0x0008, 0x683f, 0x0000, - 0x8109, 0x0040, 0x115e, 0x68d3, 0x000a, 0x68c3, 0x4fc0, 0x2079, - 0x4f00, 0x7814, 0xd0e4, 0x00c0, 0x1144, 0xd0ec, 0x00c0, 0x1148, - 0x68d7, 0x7329, 0x0078, 0x114a, 0x68d7, 0x730d, 0x0078, 0x114a, - 0x68d7, 0x732d, 0x68c7, 0x54c0, 0x68cb, 0x53c0, 0x68cf, 0x94c0, - 0x68ab, 0x9744, 0x68af, 0x9749, 0x68b3, 0x9744, 0x68b7, 0x9744, - 0x68a7, 0x0001, 0x2069, 0x4f80, 0x0078, 0x111e, 0x68d3, 0x000a, - 0x68c3, 0x51c0, 0x7814, 0xd0e4, 0x00c0, 0x116a, 0x68d7, 0x7439, - 0x0078, 0x116c, 0x68d7, 0x7419, 0x68c7, 0x74c0, 0x68cb, 0x5440, - 0x68cf, 0x95d0, 0x68ab, 0x9749, 0x68af, 0x974e, 0x68b3, 0x9749, - 0x68b7, 0x9749, 0x68a7, 0x0001, 0x7810, 0xd0ec, 0x00c0, 0x11c2, - 0x7814, 0xd0e4, 0x00c0, 0x11b4, 0x0e7e, 0x2069, 0x53c0, 0x2071, - 0x0200, 0x70ec, 0xd0e4, 0x00c0, 0x1195, 0x2019, 0x0c0c, 0x2021, - 0x000c, 0x1078, 0x2050, 0x0078, 0x119b, 0x2019, 0x0c0a, 0x2021, - 0x000a, 0x1078, 0x2050, 0x2069, 0x5440, 0x2071, 0x0100, 0x70ec, - 0xd0e4, 0x00c0, 0x11ab, 0x2019, 0x0c0c, 0x2021, 0x000c, 0x1078, - 0x2050, 0x0078, 0x11b1, 0x2019, 0x0c0a, 0x2021, 0x000a, 0x1078, - 0x2050, 0x0e7f, 0x0078, 0x11db, 0x2019, 0x0c0c, 0x2021, 0x000c, - 0x2069, 0x53c0, 0x1078, 0x2050, 0x2069, 0x5440, 0x1078, 0x2050, - 0x0078, 0x11db, 0x2069, 0x53c0, 0x0e7e, 0x2071, 0x0100, 0x70ec, - 0xd0e4, 0x00c0, 0x11d4, 0x2019, 0x0c0c, 0x2021, 0x000c, 0x1078, - 0x2050, 0x0e7f, 0x0078, 0x11db, 0x2019, 0x0c0a, 0x2021, 0x000a, - 0x1078, 0x2050, 0x0e7f, 0x2011, 0x0002, 0x2069, 0x54c0, 0x2009, - 0x0002, 0x20a9, 0x0100, 0x6837, 0x0000, 0x680b, 0x0040, 0x7bc8, - 0xa386, 0xfeff, 0x00c0, 0x11f2, 0x6817, 0x0100, 0x681f, 0x0064, - 0x0078, 0x11f6, 0x6817, 0x0064, 0x681f, 0x0002, 0xade8, 0x0010, - 0x00f0, 0x11e3, 0x8109, 0x00c0, 0x11e1, 0x8211, 0x0040, 0x1204, - 0x2069, 0x74c0, 0x0078, 0x11df, 0x1078, 0x26a2, 0x1078, 0x4712, - 0x1078, 0x1e1b, 0x1078, 0x4d42, 0x2091, 0x2100, 0x2079, 0x4f00, - 0x7810, 0xd0ec, 0x0040, 0x1218, 0x2071, 0x0020, 0x0078, 0x121a, - 0x2071, 0x0050, 0x2091, 0x2200, 0x2079, 0x4f00, 0x2071, 0x0020, - 0x2091, 0x2300, 0x2079, 0x4f00, 0x7810, 0xd0ec, 0x0040, 0x122c, - 0x2079, 0x0100, 0x0078, 0x122e, 0x2079, 0x0200, 0x2071, 0x4f40, - 0x2091, 0x2400, 0x2079, 0x0100, 0x2071, 0x4f80, 0x2091, 0x2000, - 0x2079, 0x4f00, 0x2071, 0x0010, 0x3200, 0xa085, 0x303d, 0x2090, - 0x2071, 0x0010, 0x70c3, 0x0000, 0x0090, 0x124d, 0x70c0, 0xa086, - 0x0002, 0x00c0, 0x124d, 0x1078, 0x15c1, 0x2039, 0x0000, 0x7810, - 0xd0ec, 0x00c0, 0x12cf, 0x1078, 0x148e, 0x78ac, 0xa005, 0x00c0, - 0x126b, 0x0068, 0x1261, 0x786c, 0xa065, 0x0040, 0x1261, 0x1078, - 0x23dc, 0x1078, 0x20e8, 0x0068, 0x1278, 0x786c, 0xa065, 0x0040, - 0x126b, 0x1078, 0x23dc, 0x0068, 0x1278, 0x2009, 0x4f47, 0x2011, - 0x4f87, 0x2104, 0x220c, 0xa105, 0x0040, 0x1278, 0x1078, 0x1f51, - 0x2071, 0x4f40, 0x70a4, 0xa005, 0x0040, 0x129d, 0x7450, 0xa485, - 0x0000, 0x0040, 0x129d, 0x2079, 0x0200, 0x2091, 0x8000, 0x72d4, - 0xa28c, 0x303d, 0x2190, 0x1078, 0x2bb1, 0x2091, 0x8000, 0x2091, - 0x303d, 0x0068, 0x129d, 0x2079, 0x4f00, 0x786c, 0xa065, 0x0040, - 0x129d, 0x2071, 0x0010, 0x1078, 0x23dc, 0x00e0, 0x12a5, 0x2079, - 0x4f00, 0x2071, 0x0010, 0x1078, 0x4b16, 0x2071, 0x4f80, 0x70a4, - 0xa005, 0x0040, 0x12bd, 0x7050, 0xa025, 0x0040, 0x12bd, 0x2079, - 0x0100, 0x2091, 0x8000, 0x72d4, 0xa28c, 0x303d, 0x2190, 0x1078, - 0x2bb1, 0x2091, 0x8000, 0x2091, 0x303d, 0x2079, 0x4f00, 0x2071, - 0x0010, 0x0068, 0x12c9, 0x786c, 0xa065, 0x0040, 0x12c9, 0x1078, - 0x23dc, 0x00e0, 0x1253, 0x1078, 0x4b16, 0x0078, 0x1253, 0x1078, - 0x148e, 0x78ac, 0xa005, 0x00c0, 0x12e7, 0x0068, 0x12dd, 0x786c, - 0xa065, 0x0040, 0x12dd, 0x1078, 0x23dc, 0x1078, 0x20e8, 0x0068, - 0x12f1, 0x786c, 0xa065, 0x0040, 0x12e7, 0x1078, 0x23dc, 0x0068, - 0x12f1, 0x2009, 0x4f47, 0x2104, 0xa005, 0x0040, 0x12f1, 0x1078, - 0x1f51, 0x2071, 0x4f40, 0x70a4, 0xa005, 0x0040, 0x130c, 0x7450, - 0xa485, 0x0000, 0x0040, 0x130c, 0x2079, 0x0100, 0x2091, 0x8000, - 0x72d4, 0xa28c, 0x303d, 0x2190, 0x1078, 0x2bb1, 0x2091, 0x8000, - 0x2091, 0x303d, 0x2079, 0x4f00, 0x2071, 0x0010, 0x0068, 0x1316, - 0x786c, 0xa065, 0x0040, 0x1316, 0x1078, 0x23dc, 0x00e0, 0x12cf, - 0x1078, 0x4b16, 0x0078, 0x12cf, 0x133c, 0x133c, 0x133e, 0x133e, - 0x134b, 0x134b, 0x134b, 0x134b, 0x1356, 0x1356, 0x1363, 0x1363, - 0x134b, 0x134b, 0x134b, 0x134b, 0x133c, 0x133c, 0x133e, 0x133e, - 0x134b, 0x134b, 0x134b, 0x134b, 0x1356, 0x1356, 0x1363, 0x1363, - 0x134b, 0x134b, 0x134b, 0x134b, 0x0078, 0x133c, 0x007e, 0x107e, - 0x127e, 0x2091, 0x2400, 0x1078, 0x29d1, 0x127f, 0x107f, 0x007f, - 0x2091, 0x8001, 0x007c, 0x007e, 0x107e, 0x127e, 0x1078, 0x13c8, - 0x127f, 0x107f, 0x007f, 0x2091, 0x8001, 0x007c, 0x007e, 0x107e, - 0x127e, 0x2091, 0x2300, 0x1078, 0x29d1, 0x127f, 0x107f, 0x007f, - 0x2091, 0x8001, 0x007c, 0x007e, 0x107e, 0x127e, 0x2091, 0x2300, - 0x1078, 0x29d1, 0x2091, 0x2400, 0x1078, 0x29d1, 0x127f, 0x107f, - 0x007f, 0x2091, 0x8001, 0x007c, 0x1394, 0x1394, 0x1396, 0x1396, - 0x13a3, 0x13a3, 0x13a3, 0x13a3, 0x13ae, 0x13ae, 0x1396, 0x1396, - 0x13a3, 0x13a3, 0x13a3, 0x13a3, 0x13af, 0x13af, 0x13af, 0x13af, - 0x13af, 0x13af, 0x13af, 0x13af, 0x13af, 0x13af, 0x13af, 0x13af, - 0x13af, 0x13af, 0x13af, 0x13af, 0x0078, 0x1394, 0x007e, 0x107e, - 0x127e, 0x2091, 0x2300, 0x1078, 0x29d1, 0x127f, 0x107f, 0x007f, - 0x2091, 0x8001, 0x007c, 0x007e, 0x107e, 0x127e, 0x1078, 0x13d5, - 0x127f, 0x107f, 0x007f, 0x2091, 0x8001, 0x007c, 0x007c, 0x107e, - 0x127e, 0x0d7e, 0x0e7e, 0x0f7e, 0x007e, 0x2071, 0x0100, 0x2069, - 0x4f40, 0x2079, 0x4f00, 0x70ec, 0xa084, 0x1c00, 0x78e2, 0x1078, - 0x4db0, 0x007f, 0x0f7f, 0x0e7f, 0x0d7f, 0x127f, 0x107f, 0x007c, - 0x3c00, 0xa084, 0x0007, 0x0079, 0x13cd, 0x13de, 0x13de, 0x13e0, - 0x13e0, 0x13e5, 0x13e5, 0x13ea, 0x13ea, 0x3c00, 0xa084, 0x0003, - 0x0079, 0x13da, 0x13de, 0x13de, 0x13f3, 0x13f3, 0x1078, 0x29b2, - 0x2091, 0x2200, 0x1078, 0x47ec, 0x007c, 0x2091, 0x2100, 0x1078, - 0x47ec, 0x007c, 0x2091, 0x2100, 0x1078, 0x47ec, 0x2091, 0x2200, - 0x1078, 0x47ec, 0x007c, 0x2091, 0x2100, 0x1078, 0x47ec, 0x007c, - 0x1418, 0x1418, 0x141a, 0x141a, 0x1427, 0x1427, 0x1427, 0x1427, - 0x1432, 0x1432, 0x143f, 0x143f, 0x1427, 0x1427, 0x1427, 0x1427, - 0x1450, 0x1450, 0x1450, 0x1450, 0x1450, 0x1450, 0x1450, 0x1450, - 0x1450, 0x1450, 0x1450, 0x1450, 0x1450, 0x1450, 0x1450, 0x1450, - 0x0078, 0x1418, 0x007e, 0x107e, 0x127e, 0x2091, 0x2400, 0x1078, - 0x29d1, 0x127f, 0x107f, 0x007f, 0x2091, 0x8001, 0x007c, 0x007e, - 0x107e, 0x127e, 0x1078, 0x13c8, 0x127f, 0x107f, 0x007f, 0x2091, - 0x8001, 0x007c, 0x007e, 0x107e, 0x127e, 0x2091, 0x2300, 0x1078, - 0x29d1, 0x127f, 0x107f, 0x007f, 0x2091, 0x8001, 0x007c, 0x007e, - 0x107e, 0x127e, 0x2091, 0x2300, 0x1078, 0x29d1, 0x2091, 0x2400, - 0x1078, 0x29d1, 0x127f, 0x107f, 0x007f, 0x2091, 0x8001, 0x007c, - 0x007e, 0x107e, 0x127e, 0x0d7e, 0x0e7e, 0x0f7e, 0x2079, 0x4f00, - 0x2071, 0x0200, 0x2069, 0x4f40, 0x3d00, 0xd08c, 0x0040, 0x1466, - 0x70ec, 0xa084, 0x1c00, 0x78e2, 0x1078, 0x4db0, 0x3d00, 0xd084, - 0x0040, 0x1474, 0x2069, 0x4f80, 0x2071, 0x0100, 0x70ec, 0xa084, - 0x1c00, 0x78e6, 0x1078, 0x4db0, 0x0f7f, 0x0e7f, 0x0d7f, 0x127f, - 0x107f, 0x007f, 0x007c, 0x7008, 0x800b, 0x00c8, 0x1489, 0x7007, - 0x0002, 0xa08c, 0x01e0, 0x00c0, 0x148a, 0xd09c, 0x0040, 0x1489, - 0x087a, 0x097a, 0x70c3, 0x4002, 0x0078, 0x15c4, 0x0068, 0x151a, - 0x2061, 0x0000, 0x6018, 0xd084, 0x00c0, 0x151a, 0x7828, 0xa005, - 0x00c0, 0x149e, 0x0010, 0x151b, 0x0078, 0x151a, 0x7910, 0xd1f4, - 0x0040, 0x14a4, 0x0078, 0x14b9, 0x7914, 0xd1ec, 0x0040, 0x14bd, - 0xd0fc, 0x0040, 0x14b3, 0x007e, 0x1078, 0x1dae, 0x007f, 0x0040, - 0x14bd, 0x0078, 0x14b9, 0x007e, 0x1078, 0x1da1, 0x007f, 0x0040, - 0x14bd, 0x2001, 0x4007, 0x0078, 0x15c3, 0x7910, 0xd0fc, 0x00c0, - 0x14c7, 0x2061, 0x4f40, 0xc19c, 0xc7fc, 0x0078, 0x14cb, 0x2061, - 0x4f80, 0xc19d, 0xc7fd, 0x6064, 0xa005, 0x00c0, 0x151a, 0x7912, - 0x6082, 0x7828, 0xc0fc, 0xa086, 0x0018, 0x00c0, 0x14db, 0x0c7e, - 0x1078, 0x1b85, 0x0c7f, 0x782b, 0x0000, 0x607c, 0xa065, 0x0040, - 0x1500, 0x0c7e, 0x609c, 0x1078, 0x1e90, 0x0c7f, 0x609f, 0x0000, - 0x1078, 0x1cd5, 0x2009, 0x0018, 0x6087, 0x0103, 0x7810, 0x007e, - 0x84ff, 0x00c0, 0x14f6, 0x85ff, 0x0040, 0x14f8, 0xc0c5, 0x7812, - 0x1078, 0x1dbb, 0x007f, 0x7812, 0x00c0, 0x1514, 0x1078, 0x1e0d, - 0x7810, 0xd09c, 0x00c0, 0x1508, 0x2061, 0x4f40, 0x0078, 0x150c, - 0x2061, 0x4f80, 0xc09c, 0x7812, 0x607f, 0x0000, 0x60d4, 0xd0dc, - 0x0040, 0x1518, 0xc0dc, 0x60d6, 0x2001, 0x4005, 0x0078, 0x15c3, - 0x0078, 0x15c1, 0x007c, 0x7810, 0xd0f4, 0x0040, 0x1523, 0x2001, - 0x4007, 0x0078, 0x15c3, 0xa006, 0x70c2, 0x70c6, 0x70ca, 0x70ce, - 0x70da, 0x70c0, 0xa03d, 0xa08a, 0x0040, 0x00c8, 0x1531, 0x0079, - 0x1538, 0x2100, 0xa08a, 0x0040, 0x00c8, 0x15cf, 0x0079, 0x1578, - 0x15c1, 0x1617, 0x15e0, 0x164f, 0x1687, 0x1687, 0x15d7, 0x1ced, - 0x1692, 0x15cf, 0x15e4, 0x15e6, 0x15e8, 0x15ea, 0x1cf2, 0x15cf, - 0x16a0, 0x16fd, 0x1ba5, 0x1ce7, 0x15ec, 0x19ea, 0x1a2c, 0x1a67, - 0x1ab8, 0x19a5, 0x19b2, 0x19c6, 0x19d9, 0x17eb, 0x15cf, 0x1734, - 0x1741, 0x174d, 0x1759, 0x176f, 0x177b, 0x177e, 0x178a, 0x1796, - 0x179e, 0x17d3, 0x17df, 0x15cf, 0x15cf, 0x15cf, 0x15cf, 0x17f8, - 0x180a, 0x1826, 0x185c, 0x1884, 0x1894, 0x1897, 0x18c8, 0x18f9, - 0x190b, 0x1974, 0x1984, 0x15cf, 0x15cf, 0x15cf, 0x15cf, 0x1994, - 0x15cf, 0x15cf, 0x15cf, 0x15cf, 0x15cf, 0x1d17, 0x1d1d, 0x15cf, - 0x15cf, 0x15cf, 0x1d21, 0x1d66, 0x15cf, 0x15cf, 0x15cf, 0x15cf, - 0x1611, 0x1681, 0x169a, 0x16f7, 0x1b9f, 0x15cf, 0x15cf, 0x1b68, - 0x15cf, 0x1d6a, 0x1d09, 0x1d13, 0x15cf, 0x15cf, 0x15cf, 0x15cf, - 0x15cf, 0x15cf, 0x15cf, 0x15cf, 0x15cf, 0x15cf, 0x15cf, 0x15cf, - 0x15cf, 0x15cf, 0x15cf, 0x15cf, 0x15cf, 0x15cf, 0x15cf, 0x15cf, - 0x15cf, 0x15cf, 0x15cf, 0x15cf, 0x15cf, 0x15cf, 0x15cf, 0x15cf, - 0x15cf, 0x15cf, 0x15cf, 0x15cf, 0x15cf, 0x15cf, 0x15cf, 0x15cf, - 0x72ca, 0x71c6, 0x2001, 0x4006, 0x0078, 0x15c3, 0x73ce, 0x72ca, - 0x71c6, 0x2001, 0x4000, 0x70c2, 0x0068, 0x15c4, 0x2061, 0x0000, - 0x601b, 0x0001, 0x2091, 0x5000, 0x2091, 0x4080, 0x007c, 0x70c3, - 0x4001, 0x0078, 0x15c4, 0x70c3, 0x4006, 0x0078, 0x15c4, 0x2099, - 0x0041, 0x20a1, 0x0041, 0x20a9, 0x0005, 0x53a3, 0x0078, 0x15c1, - 0x70c4, 0x70c3, 0x0004, 0x007a, 0x0078, 0x15c1, 0x0078, 0x15c1, - 0x0078, 0x15c1, 0x0078, 0x15c1, 0x2091, 0x8000, 0x70c3, 0x0004, - 0x70c7, 0x4953, 0x70cb, 0x5020, 0x70cf, 0x2020, 0x70d3, 0x0008, - 0x2001, 0x000f, 0x70d6, 0x2079, 0x0000, 0x781b, 0x0001, 0x2031, - 0x0030, 0x2059, 0x1000, 0x2029, 0x041a, 0x2051, 0x0445, 0x2061, - 0x0447, 0x20c1, 0x0020, 0x2091, 0x5000, 0x2091, 0x4080, 0x0078, - 0x0418, 0x75d8, 0x74dc, 0x75da, 0x74de, 0x0078, 0x161a, 0x2029, - 0x0000, 0x2520, 0x71d0, 0x72c8, 0x73cc, 0x70c4, 0x20a0, 0x2099, - 0x0030, 0x7003, 0x0001, 0x7007, 0x0006, 0x731a, 0x721e, 0x7422, - 0x7526, 0x2021, 0x0040, 0x81ff, 0x0040, 0x15c1, 0xa182, 0x0040, - 0x00c8, 0x1634, 0x2120, 0xa006, 0x2008, 0x8403, 0x7012, 0x7007, - 0x0004, 0x7007, 0x0001, 0x7008, 0xd0fc, 0x0040, 0x163b, 0x7007, - 0x0002, 0xa084, 0x01e0, 0x0040, 0x1649, 0x70c3, 0x4002, 0x0078, - 0x15c4, 0x24a8, 0x53a5, 0x0078, 0x162b, 0x0078, 0x15c1, 0x2029, - 0x0000, 0x2520, 0x71d0, 0x72c8, 0x73cc, 0x70c4, 0x2098, 0x20a1, - 0x0030, 0x7003, 0x0000, 0x7007, 0x0006, 0x731a, 0x721e, 0x7422, - 0x7526, 0x2021, 0x0040, 0x7007, 0x0006, 0x81ff, 0x0040, 0x15c1, - 0xa182, 0x0040, 0x00c8, 0x166e, 0x2120, 0xa006, 0x2008, 0x8403, - 0x7012, 0x24a8, 0x53a6, 0x7007, 0x0001, 0x7008, 0xd0fc, 0x0040, - 0x1675, 0xa084, 0x01e0, 0x0040, 0x1663, 0x70c3, 0x4002, 0x0078, - 0x15c4, 0x75d8, 0x74dc, 0x75da, 0x74de, 0x0078, 0x1652, 0x71c4, - 0x70c8, 0x2114, 0xa79e, 0x0004, 0x00c0, 0x168f, 0x200a, 0x72ca, - 0x0078, 0x15c0, 0x70c7, 0x0008, 0x70cb, 0x000f, 0x70cf, 0x000b, - 0x0078, 0x15c1, 0x75d8, 0x76dc, 0x75da, 0x76de, 0x0078, 0x16a3, - 0x2029, 0x0000, 0x2530, 0x70c4, 0x72c8, 0x73cc, 0x74d0, 0x70c6, - 0x72ca, 0x73ce, 0x74d2, 0xa005, 0x0040, 0x16f2, 0xa40a, 0x0040, - 0x16b3, 0x00c8, 0x16bc, 0x8001, 0x7872, 0xa084, 0xfc00, 0x0040, - 0x16c0, 0x78ac, 0xc085, 0x78ae, 0x2001, 0x4005, 0x0078, 0x15c3, - 0x7b7e, 0x7a7a, 0x7e86, 0x7d82, 0x7c76, 0xa48c, 0xff00, 0x0040, - 0x16d8, 0x8407, 0x8004, 0x8004, 0x810c, 0x810c, 0x810f, 0xa118, - 0xa291, 0x0000, 0xa6b1, 0x0000, 0xa581, 0x0000, 0x0078, 0x16e2, - 0x8407, 0x8004, 0x8004, 0xa318, 0xa291, 0x0000, 0xa6b1, 0x0000, - 0xa581, 0x0000, 0x731a, 0x721e, 0x7622, 0x7026, 0xa605, 0x0040, - 0x16ec, 0x7a10, 0xc2c5, 0x7a12, 0x78ac, 0xa084, 0xfffc, 0x78ae, - 0x0078, 0x16f5, 0x78ac, 0xc085, 0x78ae, 0x0078, 0x15c1, 0x75d8, - 0x76dc, 0x75da, 0x76de, 0x0078, 0x1700, 0x2029, 0x0000, 0x2530, - 0x70c4, 0x72c8, 0x73cc, 0x74d4, 0x70c6, 0x72ca, 0x73ce, 0x74d6, - 0xa005, 0x0040, 0x172f, 0xa40a, 0x0040, 0x1710, 0x00c8, 0x1719, - 0x8001, 0x7892, 0xa084, 0xfc00, 0x0040, 0x171d, 0x78ac, 0xc0c5, - 0x78ae, 0x2001, 0x4005, 0x0078, 0x15c3, 0x7a9a, 0x7b9e, 0x7da2, - 0x7ea6, 0x2600, 0xa505, 0x0040, 0x1728, 0x7a10, 0xc2c5, 0x7a12, - 0x7c96, 0x78ac, 0xa084, 0xfcff, 0x78ae, 0x0078, 0x1732, 0x78ac, - 0xc0c5, 0x78ae, 0x0078, 0x15c1, 0x2009, 0x0000, 0x786c, 0xa065, - 0x0040, 0x173e, 0x8108, 0x6000, 0x0078, 0x1737, 0x7ac4, 0x0078, - 0x15bf, 0x2009, 0x4f48, 0x210c, 0x7810, 0xd0ec, 0x00c0, 0x15c0, - 0x2011, 0x4f88, 0x2214, 0x0078, 0x15bf, 0x2009, 0x4f49, 0x210c, - 0x7810, 0xd0ec, 0x00c0, 0x15c0, 0x2011, 0x4f89, 0x2214, 0x0078, - 0x15bf, 0x2061, 0x4f40, 0x6128, 0x622c, 0x8214, 0x8214, 0x8214, - 0x7810, 0xd0ec, 0x00c0, 0x176d, 0x2061, 0x4f80, 0x6328, 0x73da, - 0x632c, 0x831c, 0x831c, 0x831c, 0x73de, 0x0078, 0x15bf, 0x2009, - 0x4f4c, 0x210c, 0x7810, 0xd0ec, 0x00c0, 0x15c0, 0x2011, 0x4f8c, - 0x2214, 0x0078, 0x15bf, 0x7918, 0x0078, 0x15c0, 0x2009, 0x4f4d, - 0x210c, 0x7810, 0xd0ec, 0x00c0, 0x15c0, 0x2011, 0x4f8d, 0x2214, - 0x0078, 0x15bf, 0x2009, 0x4f4e, 0x210c, 0x7810, 0xd0ec, 0x00c0, - 0x15c0, 0x2011, 0x4f8e, 0x2214, 0x0078, 0x15bf, 0x7920, 0x7810, - 0xd0ec, 0x00c0, 0x15c0, 0x7a24, 0x0078, 0x15bf, 0x71c4, 0xd1fc, - 0x00c0, 0x17a6, 0x2011, 0x53c0, 0x0078, 0x17a8, 0x2011, 0x5440, - 0x8107, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa268, 0x6a00, - 0x6804, 0xd09c, 0x0040, 0x17b7, 0x6b08, 0x0078, 0x17b8, 0x6b0c, - 0xd1fc, 0x00c0, 0x17bf, 0x2021, 0x023b, 0x0078, 0x17c1, 0x2021, - 0x013b, 0x2424, 0x7914, 0xd1e4, 0x0040, 0x17cd, 0xd4c4, 0x00c0, - 0x17cc, 0xc4d5, 0x0078, 0x17cd, 0xc4dd, 0xa4a4, 0x1c00, 0x74de, - 0x71c4, 0x0078, 0x15be, 0x77c4, 0x1078, 0x1e2b, 0x2091, 0x8000, - 0x6b1c, 0x6a14, 0x2091, 0x8001, 0x2708, 0x0078, 0x15be, 0x2061, - 0x4f40, 0x6118, 0x7810, 0xd0ec, 0x00c0, 0x15c0, 0x2061, 0x4f80, - 0x6218, 0x0078, 0x15bf, 0x77c4, 0x1078, 0x1e2b, 0x2091, 0x8000, - 0x6908, 0x6a18, 0x6b10, 0x77da, 0x2091, 0x8001, 0x0078, 0x15be, - 0x71c4, 0x2110, 0xa294, 0x000f, 0xa282, 0x0010, 0x00c8, 0x15b9, - 0x1078, 0x27c6, 0xa384, 0x4000, 0x0040, 0x1808, 0xa295, 0x0020, - 0x0078, 0x15be, 0x71c4, 0x2100, 0xc0bc, 0xa082, 0x0010, 0x00c8, - 0x15b9, 0xd1bc, 0x00c0, 0x1819, 0x2011, 0x4f48, 0x2204, 0x0078, - 0x181d, 0x2011, 0x4f88, 0x2204, 0xc0bd, 0x007e, 0x2100, 0xc0bc, - 0x2012, 0x1078, 0x2723, 0x017f, 0x0078, 0x15c0, 0x71c4, 0x2021, - 0x4f49, 0x2404, 0x70c6, 0x2019, 0x0000, 0x0078, 0x1835, 0x71c8, - 0x2021, 0x4f89, 0x2404, 0x70ca, 0xc3fd, 0x2011, 0x1854, 0x20a9, - 0x0008, 0x2204, 0xa106, 0x0040, 0x1844, 0x8210, 0x00f0, 0x1839, - 0x71c4, 0x72c8, 0x0078, 0x15b8, 0xa292, 0x1854, 0x027e, 0x2122, - 0x017f, 0x1078, 0x2744, 0x7810, 0xd0ec, 0x00c0, 0x1852, 0xd3fc, - 0x0040, 0x182f, 0x0078, 0x15c1, 0x03e8, 0x00fa, 0x01f4, 0x02ee, - 0x0004, 0x0001, 0x0002, 0x0003, 0x2061, 0x4f40, 0x6128, 0x622c, - 0x8214, 0x8214, 0x8214, 0x70c4, 0x602a, 0x70c8, 0x8003, 0x8003, - 0x8003, 0x602e, 0x7810, 0xd0ec, 0x00c0, 0x1882, 0x027e, 0x017e, - 0x2061, 0x4f80, 0x6128, 0x622c, 0x8214, 0x8214, 0x8214, 0x70d8, - 0x602a, 0x70dc, 0x8003, 0x8003, 0x8003, 0x602e, 0x71da, 0x72de, - 0x017f, 0x027f, 0x0078, 0x15bf, 0x2061, 0x4f40, 0x6130, 0x70c4, - 0x6032, 0x7810, 0xd0ec, 0x00c0, 0x15c0, 0x2061, 0x4f80, 0x6230, - 0x70c8, 0x6032, 0x0078, 0x15bf, 0x7918, 0x0078, 0x15c0, 0x71c4, - 0xa184, 0xffcf, 0x0040, 0x18a3, 0x7810, 0xd0ec, 0x00c0, 0x15b9, - 0x72c8, 0x0078, 0x15b8, 0x2011, 0x4f4d, 0x2204, 0x2112, 0x007e, - 0x2019, 0x0000, 0x1078, 0x27ab, 0x7810, 0xd0ec, 0x0040, 0x18b3, - 0x017f, 0x0078, 0x15c0, 0x71c8, 0xa184, 0xffcf, 0x0040, 0x18bc, - 0x2110, 0x71c4, 0x0078, 0x15b8, 0x2011, 0x4f8d, 0x2204, 0x2112, - 0x007e, 0xc3fd, 0x1078, 0x27ab, 0x027f, 0x017f, 0x0078, 0x15bf, - 0x71c4, 0xa182, 0x0010, 0x0048, 0x18d4, 0x7810, 0xd0ec, 0x00c0, - 0x15b9, 0x72c8, 0x0078, 0x15b8, 0x2011, 0x4f4e, 0x2204, 0x007e, - 0x2112, 0x2019, 0x0000, 0x1078, 0x2789, 0x7810, 0xd0ec, 0x0040, - 0x18e4, 0x017f, 0x0078, 0x15c0, 0x71c8, 0xa182, 0x0010, 0x0048, - 0x18ed, 0x2110, 0x71c4, 0x0078, 0x15b8, 0x2011, 0x4f8e, 0x2204, - 0x007e, 0x2112, 0xc3fd, 0x1078, 0x2789, 0x027f, 0x017f, 0x0078, - 0x15bf, 0x71c4, 0x72c8, 0xa184, 0xfffd, 0x00c0, 0x15b8, 0xa284, - 0xfffd, 0x00c0, 0x15b8, 0x2100, 0x7920, 0x7822, 0x2200, 0x7a24, - 0x7826, 0x0078, 0x15bf, 0x71c4, 0xd1fc, 0x00c0, 0x1913, 0x2011, - 0x53c0, 0x0078, 0x1915, 0x2011, 0x5440, 0x8107, 0xa084, 0x000f, - 0x8003, 0x8003, 0x8003, 0xa268, 0x2019, 0x0000, 0x72c8, 0xd2bc, - 0x0040, 0x1924, 0xa39d, 0x0010, 0xd2b4, 0x0040, 0x1929, 0xa39d, - 0x0008, 0x2091, 0x8000, 0x6800, 0x007e, 0xa226, 0x0040, 0x1948, - 0x6a02, 0xd4ec, 0x0040, 0x1935, 0xc3a5, 0xd4e4, 0x0040, 0x1939, - 0xc39d, 0xd4f4, 0x0040, 0x1948, 0x810f, 0xd2f4, 0x0040, 0x1944, - 0x1078, 0x2808, 0x0078, 0x1948, 0x1078, 0x27e6, 0x0078, 0x1948, - 0x72cc, 0x6808, 0xa206, 0x0040, 0x196a, 0xa2a4, 0x00ff, 0x7814, - 0xd0e4, 0x00c0, 0x195b, 0xa482, 0x0028, 0x0048, 0x1967, 0x0040, - 0x1967, 0x0078, 0x195f, 0xa482, 0x0043, 0x0048, 0x1967, 0x71c4, - 0x71c6, 0x027f, 0x72ca, 0x2091, 0x8001, 0x0078, 0x15ba, 0x6a0a, - 0xa39d, 0x000a, 0x6804, 0xa305, 0x6806, 0x027f, 0x6b0c, 0x71c4, - 0x2091, 0x8001, 0x0078, 0x15be, 0x77c4, 0x1078, 0x1e2b, 0x2091, - 0x8000, 0x6a14, 0x6b1c, 0x2091, 0x8001, 0x70c8, 0x6816, 0x70cc, - 0x681e, 0x2708, 0x0078, 0x15be, 0x70c4, 0x2061, 0x4f40, 0x6118, - 0x601a, 0x7810, 0xd0ec, 0x00c0, 0x15c0, 0x70c8, 0x2061, 0x4f80, - 0x6218, 0x601a, 0x0078, 0x15bf, 0x71c4, 0x72c8, 0x73cc, 0xa182, - 0x0010, 0x00c8, 0x15b9, 0x1078, 0x282a, 0xa384, 0x4000, 0x0040, - 0x19a3, 0xa295, 0x0020, 0x0078, 0x15be, 0x77c4, 0x1078, 0x1e2b, - 0x2091, 0x8000, 0x6a08, 0xc28d, 0x6a0a, 0x2091, 0x8001, 0x2708, - 0x0078, 0x15bf, 0x77c4, 0x1078, 0x1e2b, 0x2091, 0x8000, 0x6a08, - 0xa294, 0xfff9, 0x6a0a, 0x6804, 0xa005, 0x0040, 0x19c1, 0x1078, - 0x266f, 0x2091, 0x8001, 0x2708, 0x0078, 0x15bf, 0x77c4, 0x1078, - 0x1e2b, 0x2091, 0x8000, 0x6a08, 0xc295, 0x6a0a, 0x6804, 0xa005, - 0x0040, 0x19d4, 0x1078, 0x266f, 0x2091, 0x8001, 0x2708, 0x0078, - 0x15bf, 0x77c4, 0x2041, 0x0001, 0x2049, 0x0005, 0x2051, 0x0020, - 0x2091, 0x8000, 0x1078, 0x1e46, 0x2091, 0x8001, 0x2708, 0x6a08, - 0x0078, 0x15bf, 0x77c4, 0x7814, 0xd0e4, 0x00c0, 0x19fe, 0xd7fc, - 0x0040, 0x19f8, 0x1078, 0x1dae, 0x0040, 0x19fe, 0x0078, 0x15c3, - 0x1078, 0x1da1, 0x0040, 0x19fe, 0x0078, 0x15c3, 0x73c8, 0x72cc, - 0x77c6, 0x73ca, 0x72ce, 0x1078, 0x1ecd, 0x00c0, 0x1a28, 0x6818, - 0xa005, 0x0040, 0x1a22, 0x2708, 0x077e, 0x1078, 0x285a, 0x077f, - 0x00c0, 0x1a22, 0x2001, 0x0015, 0xd7fc, 0x00c0, 0x1a1b, 0x2061, - 0x4f40, 0x0078, 0x1a1e, 0xc0fd, 0x2061, 0x4f80, 0x782a, 0x2091, - 0x8001, 0x007c, 0x2091, 0x8001, 0x2001, 0x4005, 0x0078, 0x15c3, - 0x2091, 0x8001, 0x0078, 0x15c1, 0x77c4, 0x7814, 0xd0e4, 0x00c0, - 0x1a40, 0xd7fc, 0x0040, 0x1a3a, 0x1078, 0x1dae, 0x0040, 0x1a40, - 0x0078, 0x15c3, 0x1078, 0x1da1, 0x0040, 0x1a40, 0x0078, 0x15c3, - 0x77c6, 0x2041, 0x0021, 0x2049, 0x0005, 0x2051, 0x0020, 0x2091, - 0x8000, 0x1078, 0x1e46, 0x2009, 0x0016, 0xd7fc, 0x00c0, 0x1a54, - 0x2061, 0x4f40, 0x0078, 0x1a57, 0x2061, 0x4f80, 0xc1fd, 0x6067, - 0x0003, 0x607f, 0x0000, 0x6776, 0x6083, 0x000f, 0x792a, 0x61d4, - 0xc1dc, 0x61d6, 0x1078, 0x266f, 0x2091, 0x8001, 0x007c, 0x77c8, - 0x77ca, 0x77c4, 0x77c6, 0x7814, 0xd0e4, 0x00c0, 0x1a7e, 0xd7fc, - 0x0040, 0x1a78, 0x1078, 0x1dae, 0x0040, 0x1a7e, 0x0078, 0x15c3, - 0x1078, 0x1da1, 0x0040, 0x1a7e, 0x0078, 0x15c3, 0xa7bc, 0xff00, - 0x2091, 0x8000, 0x2009, 0x0017, 0xd7fc, 0x00c0, 0x1a8b, 0x2061, - 0x4f40, 0x0078, 0x1a8e, 0x2061, 0x4f80, 0xc1fd, 0x607f, 0x0000, - 0x6067, 0x0002, 0x6776, 0x6083, 0x000f, 0x792a, 0x61d4, 0xc1dc, - 0x61d6, 0x1078, 0x266f, 0x2091, 0x8001, 0x2041, 0x0021, 0x2049, - 0x0005, 0x2051, 0x0010, 0x2091, 0x8000, 0x70c8, 0xa005, 0x0040, - 0x1aac, 0x60d4, 0xc0fd, 0x60d6, 0x1078, 0x1e46, 0x70c8, 0x6836, - 0x8738, 0xa784, 0x001f, 0x00c0, 0x1aac, 0x2091, 0x8001, 0x007c, - 0x2019, 0x0000, 0x7814, 0xd0e4, 0x00c0, 0x1ace, 0x72c8, 0xd284, - 0x0040, 0x1ac8, 0x1078, 0x1dae, 0x0040, 0x1ace, 0x0078, 0x15c3, - 0x1078, 0x1da1, 0x0040, 0x1ace, 0x0078, 0x15c3, 0x72c8, 0x72ca, - 0x78ac, 0xa084, 0x0003, 0x00c0, 0x1af9, 0x2039, 0x0000, 0xd284, - 0x0040, 0x1adb, 0xc7fd, 0x2041, 0x0021, 0x2049, 0x0004, 0x2051, - 0x0008, 0x1078, 0x1e2b, 0x2091, 0x8000, 0x6808, 0xc0d4, 0xa80d, - 0x690a, 0x2091, 0x8001, 0x8738, 0xa784, 0x001f, 0x00c0, 0x1ae1, - 0xa7bc, 0xff00, 0x873f, 0x8738, 0x873f, 0xa784, 0x0f00, 0x00c0, - 0x1ae1, 0x2091, 0x8000, 0x72c8, 0xd284, 0x00c0, 0x1b0b, 0x7810, - 0xd0ec, 0x0040, 0x1b07, 0x2069, 0x0100, 0x0078, 0x1b0d, 0x2069, - 0x0200, 0x0078, 0x1b0d, 0x2069, 0x0100, 0x6808, 0xa084, 0xfffd, - 0x680a, 0x6830, 0xd0b4, 0x0040, 0x1b2d, 0x684b, 0x0004, 0x20a9, - 0x0014, 0x6848, 0xd094, 0x0040, 0x1b1f, 0x00f0, 0x1b19, 0x684b, - 0x0009, 0x20a9, 0x0014, 0x6848, 0xd084, 0x0040, 0x1b29, 0x00f0, - 0x1b23, 0x20a9, 0x00fa, 0x00f0, 0x1b2b, 0x2079, 0x4f00, 0x2009, - 0x0018, 0x72c8, 0xd284, 0x00c0, 0x1b39, 0x2061, 0x4f40, 0x0078, - 0x1b3c, 0x2061, 0x4f80, 0xc1fd, 0x607f, 0x0000, 0x792a, 0x6067, - 0x0001, 0x6083, 0x000f, 0x60a7, 0x0000, 0x60a8, 0x60b2, 0x60b6, - 0x60d4, 0xd0b4, 0x0040, 0x1b58, 0xc0b4, 0x60d6, 0x0c7e, 0x60b8, - 0xa065, 0x6008, 0xc0d4, 0x600a, 0x6018, 0x8001, 0x601a, 0x0c7f, - 0x60d4, 0xa084, 0x77ff, 0x60d6, 0x78ac, 0xc08d, 0x78ae, 0x83ff, - 0x0040, 0x1b63, 0x007c, 0x681b, 0x0047, 0x2091, 0x8001, 0x007c, - 0x73cc, 0x1078, 0x1aba, 0x69ec, 0x6a48, 0xa185, 0x1800, 0x684a, - 0xa185, 0x0040, 0x68ee, 0x73cc, 0x2021, 0x0004, 0x20a9, 0x09ff, - 0x00f0, 0x1b78, 0x8421, 0x00c0, 0x1b76, 0x8319, 0x00c0, 0x1b74, - 0x69ee, 0x6a4a, 0x2091, 0x8001, 0x007c, 0xd7fc, 0x00c0, 0x1b8c, - 0x2069, 0x4f40, 0x0078, 0x1b8e, 0x2069, 0x4f80, 0x71c4, 0x71c6, - 0x6916, 0x81ff, 0x00c0, 0x1b96, 0x68a7, 0x0001, 0x78ac, 0xc08c, - 0x78ae, 0xd084, 0x00c0, 0x1b9e, 0x1078, 0x1f2d, 0x007c, 0x75d8, - 0x74dc, 0x75da, 0x74de, 0x0078, 0x1ba7, 0xa02e, 0x2520, 0x71c4, - 0x73c8, 0x72cc, 0x71c6, 0x73ca, 0x72ce, 0x2079, 0x4f00, 0x7dde, - 0x7cda, 0x7bd6, 0x7ad2, 0x1078, 0x1e04, 0x0040, 0x1cd1, 0x20a9, - 0x0005, 0x20a1, 0x4f14, 0x2091, 0x8000, 0x41a1, 0x2091, 0x8001, - 0x2009, 0x0040, 0x1078, 0x2018, 0x0040, 0x1bca, 0x1078, 0x1e0d, - 0x0078, 0x1cd1, 0x6004, 0xa08c, 0x00ff, 0xa18e, 0x0009, 0x00c0, - 0x1bd5, 0x007e, 0x1078, 0x23bf, 0x007f, 0xa084, 0xff00, 0x8007, - 0x8009, 0x0040, 0x1c61, 0x0c7e, 0x2c68, 0x1078, 0x1e04, 0x0040, - 0x1c1b, 0x2c00, 0x689e, 0x8109, 0x00c0, 0x1bdc, 0x609f, 0x0000, - 0x0c7f, 0x0c7e, 0x7ddc, 0x7cd8, 0x7bd4, 0x7ad0, 0xa290, 0x0040, - 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x7dde, 0x7cda, - 0x7bd6, 0x7ad2, 0x2c68, 0x689c, 0xa065, 0x0040, 0x1c60, 0x2009, - 0x0040, 0x1078, 0x2018, 0x00c0, 0x1c3e, 0x6004, 0xa084, 0x00ff, - 0xa086, 0x0002, 0x00c0, 0x1c1b, 0x6004, 0xa084, 0x00ff, 0xa086, - 0x000a, 0x00c0, 0x1c17, 0x017e, 0x1078, 0x23bb, 0x017f, 0x2d00, - 0x6002, 0x0078, 0x1bea, 0x0c7f, 0x0c7e, 0x609c, 0x1078, 0x1e90, - 0x0c7f, 0x609f, 0x0000, 0x1078, 0x1cd5, 0x2009, 0x0018, 0x6008, - 0xc0cd, 0x600a, 0x6004, 0x6086, 0x7810, 0x007e, 0x84ff, 0x00c0, - 0x1c34, 0x85ff, 0x0040, 0x1c36, 0xc0c5, 0x7812, 0x1078, 0x1dbb, - 0x007f, 0x7812, 0x1078, 0x1e0d, 0x0078, 0x1cd1, 0x0c7f, 0x0c7e, - 0x609c, 0x1078, 0x1e90, 0x0c7f, 0x609f, 0x0000, 0x1078, 0x1cd5, - 0x2009, 0x0018, 0x6087, 0x0103, 0x601b, 0x0003, 0x7810, 0x007e, - 0x84ff, 0x00c0, 0x1c56, 0x85ff, 0x0040, 0x1c58, 0xc0c5, 0x7812, - 0x1078, 0x1dbb, 0x007f, 0x7812, 0x1078, 0x1e0d, 0x0078, 0x1cd1, - 0x0c7f, 0x7814, 0xd0e4, 0x00c0, 0x1c8f, 0x6114, 0xd1fc, 0x0040, - 0x1c6f, 0x1078, 0x1dae, 0x0040, 0x1c8f, 0x0078, 0x1c73, 0x1078, - 0x1da1, 0x0040, 0x1c8f, 0x1078, 0x1cd5, 0x2009, 0x0018, 0x6087, - 0x0103, 0x601b, 0x0021, 0x7810, 0x007e, 0x84ff, 0x00c0, 0x1c83, - 0x85ff, 0x0040, 0x1c85, 0xc0c5, 0x7812, 0x1078, 0x1dbb, 0x007f, - 0x7812, 0x1078, 0x1e0d, 0x2001, 0x4007, 0x0078, 0x15c3, 0x74c4, - 0x73c8, 0x72cc, 0x6014, 0x2091, 0x8000, 0x0e7e, 0x2009, 0x0012, - 0xd0fc, 0x00c0, 0x1c9f, 0x2071, 0x4f40, 0x0078, 0x1ca2, 0x2071, - 0x4f80, 0xc1fd, 0x792a, 0x7067, 0x0005, 0x71d4, 0xc1dc, 0x71d6, - 0x736a, 0x726e, 0x7472, 0x7076, 0x707b, 0x0000, 0x2c00, 0x707e, - 0xa02e, 0x2530, 0x611c, 0xa184, 0x0060, 0x0040, 0x1cb9, 0x1078, - 0x46b6, 0x0e7f, 0x6596, 0x65a6, 0x669a, 0x66aa, 0x60af, 0x0000, - 0x60b3, 0x0000, 0x6714, 0x6023, 0x0000, 0x6024, 0xa096, 0x0001, - 0x00c0, 0x1ccc, 0x8000, 0x6026, 0x1078, 0x266f, 0x2091, 0x8001, - 0x007c, 0x70c3, 0x4005, 0x0078, 0x15c4, 0x20a9, 0x0005, 0x2099, - 0x4f14, 0x2091, 0x8000, 0x530a, 0x2091, 0x8001, 0x2100, 0xa210, - 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x007c, 0x71c4, - 0x70c7, 0x0000, 0x791e, 0x0078, 0x15c1, 0x71c4, 0x71c6, 0x2168, - 0x0078, 0x1cf4, 0x2069, 0x1000, 0x690c, 0xa016, 0x2d04, 0xa210, - 0x8d68, 0x8109, 0x00c0, 0x1cf6, 0xa285, 0x0000, 0x00c0, 0x1d04, - 0x70c3, 0x4000, 0x0078, 0x1d06, 0x70c3, 0x4003, 0x70ca, 0x0078, - 0x15c4, 0x7964, 0x71c6, 0x71c4, 0xa182, 0x0003, 0x00c8, 0x15b9, - 0x7966, 0x0078, 0x15c1, 0x7964, 0x71c6, 0x0078, 0x15c1, 0x7900, - 0x71c6, 0x71c4, 0x7902, 0x0078, 0x15c1, 0x7900, 0x71c6, 0x0078, - 0x15c1, 0x70c4, 0x2011, 0x0000, 0xa08c, 0x000d, 0x0040, 0x1d36, - 0x810c, 0x0048, 0x1d32, 0x8210, 0x810c, 0x810c, 0x0048, 0x1d32, - 0x8210, 0x810c, 0x81ff, 0x00c0, 0x15ba, 0x8210, 0x7a0e, 0xd28c, - 0x0040, 0x1d62, 0x7910, 0xc1cd, 0x7912, 0x2009, 0x0021, 0x2019, - 0x0003, 0xd284, 0x0040, 0x1d5c, 0x8108, 0x2019, 0x0041, 0x2011, - 0x974e, 0x2312, 0x2019, 0x0042, 0x8210, 0x2312, 0x2019, 0x0043, - 0x8210, 0x2312, 0x2019, 0x0046, 0x8210, 0x2312, 0x2019, 0x0047, - 0x8210, 0x2312, 0x2019, 0x0006, 0x2011, 0x9753, 0x2112, 0x2011, - 0x9773, 0x2312, 0x7904, 0x7806, 0x0078, 0x15c0, 0x7804, 0x70c6, - 0x0078, 0x15c1, 0x71c4, 0xd1fc, 0x00c0, 0x1d72, 0x2011, 0x53c0, - 0x0078, 0x1d74, 0x2011, 0x5440, 0x8107, 0xa084, 0x000f, 0x8003, - 0x8003, 0x8003, 0xa268, 0x6a14, 0xd2b4, 0x0040, 0x1d83, 0x2011, - 0x0001, 0x0078, 0x1d85, 0x2011, 0x0000, 0x6b0c, 0x6800, 0x70da, - 0x0078, 0x15be, 0x7814, 0xd0f4, 0x0040, 0x1d95, 0x2001, 0x4007, - 0x70db, 0x0000, 0xa005, 0x0078, 0x1da0, 0xd0fc, 0x0040, 0x1d9f, - 0x2001, 0x4007, 0x70db, 0x0001, 0xa005, 0x0078, 0x1da0, 0xa006, - 0x007c, 0x7814, 0xd0f4, 0x0040, 0x1dac, 0x2001, 0x4007, 0x70db, - 0x0000, 0xa005, 0x0078, 0x1dad, 0xa006, 0x007c, 0x7814, 0xd0fc, - 0x0040, 0x1db9, 0x2001, 0x4007, 0x70db, 0x0001, 0xa005, 0x0078, - 0x1dba, 0xa006, 0x007c, 0x7112, 0x721a, 0x731e, 0x7810, 0xd0c4, - 0x0040, 0x1dc4, 0x7422, 0x7526, 0xac80, 0x0001, 0x8108, 0x810c, - 0x81a9, 0x8098, 0x20a1, 0x0030, 0x7003, 0x0000, 0x6084, 0x20a2, - 0x53a6, 0x7007, 0x0001, 0x7974, 0xa184, 0xff00, 0x0040, 0x1de1, - 0x810f, 0x810c, 0x810c, 0x8004, 0x8004, 0x8007, 0xa100, 0x0078, - 0x1de4, 0x8107, 0x8004, 0x8004, 0x797c, 0xa108, 0x7a78, 0xa006, - 0xa211, 0x7d10, 0xd5c4, 0x0040, 0x1df1, 0x7b84, 0xa319, 0x7c80, - 0xa421, 0x7008, 0xd0fc, 0x0040, 0x1df1, 0x7003, 0x0001, 0x7007, - 0x0006, 0x711a, 0x721e, 0x7d10, 0xd5c4, 0x0040, 0x1e01, 0x7322, - 0x7426, 0xa084, 0x01e0, 0x007c, 0x7848, 0xa065, 0x0040, 0x1e0c, - 0x2c04, 0x784a, 0x2063, 0x0000, 0x007c, 0x0f7e, 0x2079, 0x4f00, - 0x7848, 0x2062, 0x2c00, 0xa005, 0x00c0, 0x1e18, 0x1078, 0x29b2, - 0x784a, 0x0f7f, 0x007c, 0x2011, 0x9900, 0x7a4a, 0x7bc4, 0x8319, - 0x0040, 0x1e28, 0xa280, 0x0032, 0x2012, 0x2010, 0x0078, 0x1e1f, - 0x2013, 0x0000, 0x007c, 0x017e, 0x027e, 0xd7fc, 0x00c0, 0x1e34, - 0x2011, 0x54c0, 0x0078, 0x1e36, 0x2011, 0x74c0, 0xa784, 0x0f00, - 0x800b, 0xa784, 0x001f, 0x0040, 0x1e41, 0x8003, 0x8003, 0x8003, - 0x8003, 0xa105, 0xa268, 0x027f, 0x017f, 0x007c, 0x1078, 0x1e2b, - 0x2900, 0x682a, 0x2a00, 0x682e, 0x6808, 0xa084, 0xf9ef, 0xa80d, - 0x690a, 0x0e7e, 0xd7fc, 0x00c0, 0x1e5b, 0x2009, 0x4f53, 0x2071, - 0x4f40, 0x0078, 0x1e5f, 0x2009, 0x4f93, 0x2071, 0x4f80, 0x210c, - 0x6804, 0xa005, 0x0040, 0x1e6f, 0xa116, 0x00c0, 0x1e6f, 0x2060, - 0x6000, 0x6806, 0x017e, 0x200b, 0x0000, 0x0078, 0x1e72, 0x2009, - 0x0000, 0x017e, 0x6804, 0xa065, 0x0040, 0x1e87, 0x6000, 0x6806, - 0x1078, 0x1ea2, 0x1078, 0x2064, 0x6810, 0x7908, 0x8109, 0x790a, - 0x8001, 0x6812, 0x00c0, 0x1e72, 0x7910, 0xc1a5, 0x7912, 0x017f, - 0x6902, 0x6906, 0x2d00, 0x2060, 0x1078, 0x2b13, 0x0e7f, 0x007c, - 0xa065, 0x0040, 0x1ea1, 0x2008, 0x609c, 0xa005, 0x0040, 0x1e9e, - 0x2062, 0x609f, 0x0000, 0xa065, 0x0078, 0x1e94, 0x7848, 0x794a, - 0x2062, 0x007c, 0x6007, 0x0103, 0x608f, 0x0000, 0x20a9, 0x001c, - 0xac80, 0x0005, 0x20a0, 0x2001, 0x0000, 0x40a4, 0x6828, 0x601a, - 0x682c, 0x6022, 0x007c, 0x0e7e, 0xd7fc, 0x00c0, 0x1ebd, 0x2071, - 0x4f40, 0x2031, 0x4fc0, 0x0078, 0x1ec1, 0x2071, 0x4f80, 0x2031, - 0x51c0, 0x7050, 0xa08c, 0x0200, 0x00c0, 0x1ecb, 0xa608, 0x2d0a, - 0x8000, 0x7052, 0xa006, 0x0e7f, 0x007c, 0x0f7e, 0xd7fc, 0x00c0, - 0x1ed5, 0x2079, 0x4f40, 0x0078, 0x1ed7, 0x2079, 0x4f80, 0x1078, - 0x1e2b, 0x2091, 0x8000, 0x6804, 0x780a, 0xa065, 0x0040, 0x1f2b, - 0x0078, 0x1ee9, 0x2c00, 0x780a, 0x2060, 0x6000, 0xa065, 0x0040, - 0x1f2b, 0x6010, 0xa306, 0x00c0, 0x1ee2, 0x600c, 0xa206, 0x00c0, - 0x1ee2, 0x2c28, 0x784c, 0xac06, 0x00c0, 0x1ef8, 0x0078, 0x1f28, - 0x6804, 0xac06, 0x00c0, 0x1f06, 0x6000, 0x2060, 0x6806, 0xa005, - 0x00c0, 0x1f06, 0x6803, 0x0000, 0x0078, 0x1f10, 0x6400, 0x7808, - 0x2060, 0x6402, 0xa486, 0x0000, 0x00c0, 0x1f10, 0x2c00, 0x6802, - 0x2560, 0x0f7f, 0x1078, 0x1ea2, 0x0f7e, 0x601b, 0x0005, 0x6023, - 0x0020, 0x0f7f, 0x1078, 0x2064, 0x0f7e, 0x7908, 0x8109, 0x790a, - 0x6810, 0x8001, 0x6812, 0x00c0, 0x1f28, 0x7810, 0xc0a5, 0x7812, - 0x2001, 0xffff, 0xa005, 0x0f7f, 0x007c, 0x077e, 0x2700, 0x2039, - 0x0000, 0xd0fc, 0x0040, 0x1f35, 0xc7fd, 0x2041, 0x0021, 0x2049, - 0x0004, 0x2051, 0x0008, 0x2091, 0x8000, 0x1078, 0x1e46, 0x8738, - 0xa784, 0x001f, 0x00c0, 0x1f3d, 0xa7bc, 0xff00, 0x873f, 0x8738, - 0x873f, 0xa784, 0x0f00, 0x00c0, 0x1f3d, 0x2091, 0x8001, 0x077f, - 0x007c, 0x786c, 0x2009, 0x9774, 0x210c, 0xa10d, 0x0040, 0x1f5b, - 0xa065, 0x0078, 0x23dc, 0x2061, 0x0000, 0x6018, 0xd084, 0x00c0, - 0x1f7b, 0x7810, 0xd08c, 0x0040, 0x1f6c, 0xc08c, 0x7812, 0xc7fc, - 0x2069, 0x4f40, 0x0078, 0x1f71, 0xc08d, 0x7812, 0x2069, 0x4f80, - 0xc7fd, 0x2091, 0x8000, 0x681c, 0x681f, 0x0000, 0x2091, 0x8001, - 0xa005, 0x00c0, 0x1f7c, 0x007c, 0xa08c, 0xfff0, 0x0040, 0x1f82, - 0x1078, 0x29b2, 0x0079, 0x1f84, 0x1f94, 0x1f97, 0x1f9d, 0x1fa1, - 0x1f95, 0x1fa5, 0x1f95, 0x1f95, 0x1f95, 0x1fab, 0x1fdc, 0x1fe0, - 0x1fe6, 0x1ffb, 0x1f95, 0x1f95, 0x007c, 0x1078, 0x29b2, 0x1078, - 0x1f2d, 0x2001, 0x8001, 0x0078, 0x2007, 0x2001, 0x8003, 0x0078, - 0x2007, 0x2001, 0x8004, 0x0078, 0x2007, 0x1078, 0x1f2d, 0x2001, - 0x8006, 0x0078, 0x2007, 0x2091, 0x8000, 0x077e, 0xd7fc, 0x00c0, - 0x1fb7, 0x2069, 0x4f40, 0x2039, 0x0009, 0x0078, 0x1fbb, 0x2069, - 0x4f80, 0x2039, 0x0009, 0x6800, 0xa086, 0x0000, 0x0040, 0x1fc5, - 0x007f, 0x6f1e, 0x2091, 0x8001, 0x007c, 0x6874, 0x077f, 0xa0bc, - 0xff00, 0x2041, 0x0021, 0x2049, 0x0004, 0x2051, 0x0010, 0x1078, - 0x1e46, 0x8738, 0xa784, 0x001f, 0x00c0, 0x1fcf, 0x2091, 0x8001, - 0x2001, 0x800a, 0x0078, 0x2007, 0x2001, 0x800c, 0x0078, 0x2007, - 0x1078, 0x1f2d, 0x2001, 0x800d, 0x0078, 0x2007, 0x7814, 0xd0e4, - 0x00c0, 0x1ff9, 0xd0ec, 0x0040, 0x1ff3, 0xd7fc, 0x0040, 0x1ff3, - 0x78e4, 0x0078, 0x1ff4, 0x78e0, 0x70c6, 0x2001, 0x800e, 0x0078, - 0x2007, 0x0078, 0x1f95, 0xd7fc, 0x0040, 0x2001, 0x78ec, 0x0078, - 0x2002, 0x78e8, 0x70c6, 0x2001, 0x800f, 0x0078, 0x2007, 0x70c2, - 0xd7fc, 0x00c0, 0x200f, 0x70db, 0x0000, 0x0078, 0x2011, 0x70db, - 0x0001, 0x2061, 0x0000, 0x601b, 0x0001, 0x2091, 0x4080, 0x007c, - 0xac80, 0x0001, 0x81ff, 0x0040, 0x2043, 0x2099, 0x0030, 0x20a0, - 0x700c, 0xa084, 0x03ff, 0x0040, 0x2025, 0x7018, 0x007e, 0x701c, - 0x007e, 0x7020, 0x007e, 0x7024, 0x007e, 0x7112, 0x81ac, 0x721a, - 0x731e, 0x7422, 0x7526, 0x7003, 0x0001, 0x7007, 0x0001, 0x7008, - 0x800b, 0x00c8, 0x2037, 0x7007, 0x0002, 0xa08c, 0x01e0, 0x00c0, - 0x2043, 0x53a5, 0xa006, 0x7003, 0x0000, 0x7007, 0x0004, 0x007f, - 0x7026, 0x007f, 0x7022, 0x007f, 0x701e, 0x007f, 0x701a, 0x007c, - 0x2011, 0x0020, 0x2009, 0x0010, 0x6b0a, 0x6c0e, 0x6803, 0xfd00, - 0x6807, 0x0018, 0x6a1a, 0x2d00, 0xa0e8, 0x0008, 0xa290, 0x0004, - 0x8109, 0x00c0, 0x2054, 0x007c, 0x6004, 0x6086, 0x2c08, 0x2063, - 0x0000, 0x7868, 0xa005, 0x796a, 0x0040, 0x2071, 0x2c02, 0x0078, - 0x2072, 0x796e, 0x007c, 0x0c7e, 0x2061, 0x4f00, 0x6887, 0x0103, - 0x2d08, 0x206b, 0x0000, 0x6068, 0xa005, 0x616a, 0x0040, 0x2083, - 0x2d02, 0x0078, 0x2084, 0x616e, 0x0c7f, 0x007c, 0x2091, 0x8000, - 0x2c04, 0x786e, 0xa005, 0x00c0, 0x208e, 0x786a, 0x2091, 0x8001, - 0x609c, 0xa005, 0x0040, 0x20a7, 0x0c7e, 0x2060, 0x2008, 0x609c, - 0xa005, 0x0040, 0x20a3, 0x2062, 0x609f, 0x0000, 0xa065, 0x609c, - 0xa005, 0x00c0, 0x209b, 0x7848, 0x794a, 0x2062, 0x0c7f, 0x7848, - 0x2062, 0x609f, 0x0000, 0xac85, 0x0000, 0x00c0, 0x20b1, 0x1078, - 0x29b2, 0x784a, 0x007c, 0x20a9, 0x0010, 0xa006, 0x8004, 0x8086, - 0x818e, 0x00c8, 0x20bc, 0xa200, 0x00f0, 0x20b7, 0x8086, 0x818e, - 0x007c, 0x157e, 0x20a9, 0x0010, 0xa005, 0x0040, 0x20e2, 0xa11a, - 0x00c8, 0x20e2, 0x8213, 0x818d, 0x0048, 0x20d5, 0xa11a, 0x00c8, - 0x20d6, 0x00f0, 0x20ca, 0x0078, 0x20da, 0xa11a, 0x2308, 0x8210, - 0x00f0, 0x20ca, 0x007e, 0x3200, 0xa084, 0xf7ff, 0x2080, 0x007f, - 0x157f, 0x007c, 0x007e, 0x3200, 0xa085, 0x0800, 0x0078, 0x20de, - 0x7d74, 0x70d0, 0xa506, 0x0040, 0x21ce, 0x7810, 0x2050, 0x7800, - 0xd08c, 0x0040, 0x210a, 0xdaec, 0x0040, 0x210a, 0x0e7e, 0x2091, - 0x8000, 0x2071, 0x0020, 0x7004, 0xa005, 0x00c0, 0x2107, 0x7008, - 0x0e7f, 0xa086, 0x0008, 0x0040, 0x210a, 0x0078, 0x21ce, 0x0e7f, - 0x0078, 0x21ce, 0x1078, 0x1e04, 0x0040, 0x21ce, 0xa046, 0x7970, - 0x2500, 0x8000, 0xa112, 0x2009, 0x0040, 0x00c8, 0x2119, 0x0078, - 0x2120, 0x72d0, 0xa206, 0x0040, 0x2120, 0x8840, 0x2009, 0x0080, - 0x0c7e, 0x7112, 0x7007, 0x0001, 0x2099, 0x0030, 0x20a9, 0x0020, - 0xac80, 0x0001, 0x20a0, 0x2061, 0x0000, 0x88ff, 0x0040, 0x2132, - 0x1078, 0x1e04, 0x7008, 0xd0fc, 0x0040, 0x2132, 0x7007, 0x0002, - 0x2091, 0x8001, 0xa08c, 0x01e0, 0x00c0, 0x2169, 0x53a5, 0x8cff, - 0x00c0, 0x2147, 0x88ff, 0x0040, 0x21b8, 0x0078, 0x2151, 0x2c00, - 0x788e, 0x20a9, 0x0020, 0xac80, 0x0001, 0x20a0, 0x53a5, 0x0078, - 0x21b8, 0xa046, 0x7218, 0x731c, 0xdac4, 0x0040, 0x2159, 0x7420, - 0x7524, 0xa292, 0x0040, 0xa39b, 0x0000, 0xa4a3, 0x0000, 0xa5ab, - 0x0000, 0x721a, 0x731e, 0xdac4, 0x0040, 0x2169, 0x7422, 0x7526, - 0xa006, 0x7007, 0x0004, 0x0040, 0x21b8, 0x8cff, 0x0040, 0x2172, - 0x1078, 0x1e0d, 0x0c7f, 0x1078, 0x1e0d, 0xa046, 0x7888, 0x8000, - 0x788a, 0xa086, 0x0002, 0x0040, 0x2198, 0x7a7c, 0x7b78, 0xdac4, - 0x0040, 0x2184, 0x7c84, 0x7d80, 0x7974, 0x8107, 0x8004, 0x8004, - 0xa210, 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x721a, - 0x731e, 0xdac4, 0x0040, 0x21ce, 0x7422, 0x7526, 0x0078, 0x21ce, - 0x6014, 0xd0fc, 0x00c0, 0x21a0, 0x2069, 0x4f40, 0x0078, 0x21a2, - 0x2069, 0x4f80, 0x2091, 0x8000, 0x681f, 0x0002, 0x88ff, 0x0040, - 0x21ae, 0xa046, 0x788c, 0x2060, 0x0078, 0x2198, 0x788b, 0x0000, - 0x78ac, 0xa085, 0x0003, 0x78ae, 0x2091, 0x8001, 0x0078, 0x21ce, - 0x0c7f, 0x788b, 0x0000, 0x1078, 0x238d, 0x6004, 0xa084, 0x000f, - 0x1078, 0x21cf, 0x88ff, 0x0040, 0x21cc, 0x788c, 0x2060, 0x6004, - 0xa084, 0x000f, 0x1078, 0x21cf, 0x0078, 0x20e8, 0x007c, 0x0079, - 0x21d1, 0x21e1, 0x21ff, 0x221d, 0x21e1, 0x222e, 0x21f2, 0x21e1, - 0x21e1, 0x21e1, 0x21fd, 0x221b, 0x21e1, 0x21e1, 0x21e1, 0x21e1, - 0x21e1, 0x2039, 0x0400, 0x78bc, 0xa705, 0x78be, 0x6008, 0xa705, - 0x600a, 0x1078, 0x2271, 0x609c, 0x78ba, 0x609f, 0x0000, 0x1078, - 0x2377, 0x007c, 0x78bc, 0xd0c4, 0x0040, 0x21f8, 0x0078, 0x21e1, - 0x601c, 0xc0bd, 0x601e, 0x0078, 0x2205, 0x1078, 0x23bf, 0x78bc, - 0xd0c4, 0x0040, 0x2205, 0x0078, 0x21e1, 0x78bf, 0x0000, 0x6004, - 0x8007, 0xa084, 0x00ff, 0x78b2, 0x8001, 0x0040, 0x2218, 0x1078, - 0x2271, 0x0040, 0x2218, 0x78bc, 0xc0c5, 0x78be, 0x0078, 0x221a, - 0x0078, 0x2290, 0x007c, 0x1078, 0x23bb, 0x78bc, 0xa08c, 0x0e00, - 0x00c0, 0x2225, 0xd0c4, 0x00c0, 0x2227, 0x0078, 0x21e1, 0x1078, - 0x2271, 0x00c0, 0x222d, 0x0078, 0x2290, 0x007c, 0x78bc, 0xd0c4, - 0x0040, 0x2234, 0x0078, 0x21e1, 0x78bf, 0x0000, 0x6714, 0x2011, - 0x0001, 0x22a8, 0x6018, 0xa084, 0x00ff, 0xa005, 0x0040, 0x2254, - 0xa7bc, 0xff00, 0x20a9, 0x0020, 0xa08e, 0x0001, 0x0040, 0x2254, - 0xa7bc, 0x8000, 0x2011, 0x0002, 0x20a9, 0x0100, 0xa08e, 0x0002, - 0x0040, 0x2254, 0x0078, 0x226e, 0x1078, 0x1e2b, 0x2d00, 0x2091, - 0x8000, 0x682b, 0x0000, 0x682f, 0x0000, 0x6808, 0xa084, 0xffde, - 0x680a, 0xade8, 0x0010, 0x2091, 0x8001, 0x00f0, 0x2257, 0x8211, - 0x0040, 0x226e, 0x20a9, 0x0100, 0x0078, 0x2257, 0x1078, 0x1e0d, - 0x007c, 0x609f, 0x0000, 0x78b4, 0xa06d, 0x2c00, 0x78b6, 0x00c0, - 0x227c, 0x78ba, 0x0078, 0x2284, 0x689e, 0x2d00, 0x6002, 0x78b8, - 0xad06, 0x00c0, 0x2284, 0x6002, 0x78b0, 0x8001, 0x78b2, 0x00c0, - 0x228f, 0x78bc, 0xc0c4, 0x78be, 0x78b8, 0x2060, 0xa006, 0x007c, - 0x0e7e, 0xa02e, 0x2530, 0x7dba, 0x7db6, 0x65ae, 0x65b2, 0x601c, - 0x60a2, 0x2048, 0xa984, 0xe1ff, 0x601e, 0xa984, 0x0060, 0x0040, - 0x22a3, 0x1078, 0x46b6, 0x6596, 0x65a6, 0x669a, 0x66aa, 0x6714, - 0x2071, 0x4f80, 0xd7fc, 0x00c0, 0x22af, 0x2071, 0x4f40, 0xa784, - 0x0f00, 0x800b, 0xa784, 0x001f, 0x0040, 0x22ba, 0x8003, 0x8003, - 0x8003, 0x8003, 0xa105, 0x71c4, 0xa168, 0x2700, 0x8007, 0xa084, - 0x000f, 0x8003, 0x8003, 0x8003, 0x71c8, 0xa100, 0x60c2, 0x2091, - 0x8000, 0x7814, 0xd0c4, 0x0040, 0x22df, 0xd0ec, 0x0040, 0x22db, - 0xd7fc, 0x00c0, 0x22d8, 0xd0f4, 0x00c0, 0x22e6, 0x0078, 0x22df, - 0xd0fc, 0x00c0, 0x22e6, 0x7810, 0xd0f4, 0x00c0, 0x22e6, 0x6e08, - 0xd684, 0x0040, 0x2310, 0xd9fc, 0x00c0, 0x2310, 0x2091, 0x8001, - 0x1078, 0x1ea2, 0x2091, 0x8000, 0x1078, 0x2064, 0x2091, 0x8001, - 0x7814, 0xd0e4, 0x00c0, 0x2375, 0x7814, 0xd0c4, 0x0040, 0x2375, - 0xd0ec, 0x0040, 0x2308, 0xd7fc, 0x00c0, 0x2303, 0xd0f4, 0x00c0, - 0x230c, 0x0078, 0x2375, 0xd0fc, 0x00c0, 0x230c, 0x0078, 0x2375, - 0x7810, 0xd0f4, 0x0040, 0x2375, 0x601b, 0x0021, 0x0078, 0x2375, - 0x6024, 0xa096, 0x0001, 0x00c0, 0x2317, 0x8000, 0x6026, 0x6a10, - 0x6814, 0xa202, 0x0048, 0x232a, 0x0040, 0x232a, 0x2091, 0x8001, - 0x2039, 0x0200, 0x609c, 0x78ba, 0x609f, 0x0000, 0x1078, 0x2377, - 0x0078, 0x2375, 0x2c08, 0xd9fc, 0x0040, 0x2352, 0x6800, 0xa065, - 0x0040, 0x2352, 0x6a04, 0x7000, 0xa084, 0x0002, 0x0040, 0x2348, - 0x704c, 0xa206, 0x00c0, 0x2348, 0x6b04, 0x2160, 0x2304, 0x6002, - 0xa005, 0x00c0, 0x2344, 0x6902, 0x2260, 0x6102, 0x0078, 0x235e, - 0x2d00, 0x2060, 0x1078, 0x2b13, 0x6e08, 0x2160, 0x6202, 0x6906, - 0x0078, 0x235e, 0x6800, 0x6902, 0xa065, 0x0040, 0x235a, 0x6102, - 0x0078, 0x235b, 0x6906, 0x2160, 0x6003, 0x0000, 0x2160, 0xd9fc, - 0x0040, 0x2365, 0xa6b4, 0xfffc, 0x6e0a, 0x6810, 0x7d08, 0x8528, - 0x7d0a, 0x8000, 0x6812, 0x2091, 0x8001, 0xd6b4, 0x0040, 0x2375, - 0xa6b6, 0x0040, 0x6e0a, 0x1078, 0x1eb3, 0x0e7f, 0x007c, 0x6008, - 0xa705, 0x600a, 0x2091, 0x8000, 0x1078, 0x2064, 0x2091, 0x8001, - 0x78b8, 0xa065, 0x0040, 0x238a, 0x609c, 0x78ba, 0x609f, 0x0000, - 0x0078, 0x2377, 0x78b6, 0x78ba, 0x007c, 0x7970, 0x7874, 0x2818, - 0xd384, 0x0040, 0x2397, 0x8000, 0xa112, 0x0048, 0x239c, 0x8000, - 0xa112, 0x00c8, 0x23ac, 0xc384, 0x7a7c, 0x721a, 0x7a78, 0x721e, - 0xdac4, 0x0040, 0x23a7, 0x7a84, 0x7222, 0x7a80, 0x7226, 0xa006, - 0xd384, 0x0040, 0x23ac, 0x8000, 0x7876, 0x70d2, 0x781c, 0xa005, - 0x0040, 0x23ba, 0x8001, 0x781e, 0x00c0, 0x23ba, 0x0068, 0x23ba, - 0x2091, 0x4080, 0x007c, 0x2039, 0x23d3, 0x0078, 0x23c1, 0x2039, - 0x23d9, 0x2704, 0xa005, 0x0040, 0x23d2, 0xac00, 0x2068, 0x6908, - 0x6810, 0x6912, 0x680a, 0x690c, 0x6814, 0x6916, 0x680e, 0x8738, - 0x0078, 0x23c1, 0x007c, 0x0003, 0x0009, 0x000f, 0x0015, 0x001b, - 0x0000, 0x0015, 0x001b, 0x0000, 0x2041, 0x0000, 0x780c, 0x0079, - 0x23e1, 0x25b3, 0x2586, 0x23e5, 0x245e, 0x2039, 0x9774, 0x2734, - 0x7d10, 0x0078, 0x2405, 0x6084, 0xa086, 0x0103, 0x00c0, 0x2447, - 0x6114, 0x6018, 0xa105, 0x0040, 0x23fa, 0x86ff, 0x00c0, 0x2416, - 0x0078, 0x2447, 0x8603, 0xa080, 0x9755, 0x620c, 0x2202, 0x8000, - 0x6210, 0x2202, 0x1078, 0x2086, 0x8630, 0xa68e, 0x000f, 0x0040, - 0x24d2, 0x786c, 0xa065, 0x00c0, 0x23eb, 0x7808, 0xa602, 0x00c8, - 0x2416, 0xd5ac, 0x00c0, 0x2416, 0x263a, 0x007c, 0xa682, 0x0003, - 0x00c8, 0x24d2, 0x2091, 0x8000, 0x2069, 0x0000, 0x6818, 0xd084, - 0x00c0, 0x2442, 0x2011, 0x9755, 0x2204, 0x70c6, 0x8210, 0x2204, - 0x70ca, 0xd684, 0x00c0, 0x2432, 0x8210, 0x2204, 0x70da, 0x8210, - 0x2204, 0x70de, 0xa685, 0x8020, 0x70c2, 0x681b, 0x0001, 0x2091, - 0x4080, 0x7810, 0xa084, 0xffcf, 0x7812, 0x2091, 0x8001, 0x203b, - 0x0000, 0x007c, 0x7810, 0xc0ad, 0x7812, 0x0078, 0x24d2, 0x263a, - 0x1078, 0x25bd, 0x00c0, 0x25e0, 0x786c, 0xa065, 0x00c0, 0x23eb, - 0x2091, 0x8000, 0x7810, 0xa084, 0xffcf, 0x86ff, 0x0040, 0x2459, - 0xc0ad, 0x7812, 0x2091, 0x8001, 0x0078, 0x25e0, 0x2039, 0x9774, - 0x2734, 0x7d10, 0x0078, 0x247a, 0x6084, 0xa086, 0x0103, 0x00c0, - 0x24bb, 0x6114, 0x6018, 0xa105, 0x0040, 0x2473, 0x86ff, 0x00c0, - 0x248b, 0x0078, 0x24bb, 0xa680, 0x9755, 0x620c, 0x2202, 0x1078, - 0x2086, 0x8630, 0xa68e, 0x001e, 0x0040, 0x24d2, 0x786c, 0xa065, - 0x00c0, 0x2464, 0x7808, 0xa602, 0x00c8, 0x248b, 0xd5ac, 0x00c0, - 0x248b, 0x263a, 0x007c, 0xa682, 0x0006, 0x00c8, 0x24d2, 0x2091, - 0x8000, 0x2069, 0x0000, 0x6818, 0xd084, 0x00c0, 0x24b6, 0x2011, - 0x9755, 0x2009, 0x974e, 0x26a8, 0x211c, 0x2204, 0x201a, 0x8108, - 0x8210, 0x00f0, 0x249c, 0xa685, 0x8030, 0x70c2, 0x681b, 0x0001, - 0x2091, 0x4080, 0x7810, 0xa084, 0xffcf, 0x7812, 0x2091, 0x8001, - 0xa006, 0x2009, 0x9775, 0x200a, 0x203a, 0x007c, 0x7810, 0xc0ad, - 0x7812, 0x0078, 0x24d2, 0x263a, 0x1078, 0x25bd, 0x00c0, 0x25e0, - 0x786c, 0xa065, 0x00c0, 0x2464, 0x2091, 0x8000, 0x7810, 0xa084, - 0xffcf, 0x86ff, 0x0040, 0x24cd, 0xc0ad, 0x7812, 0x2091, 0x8001, - 0x0078, 0x25e0, 0x2091, 0x8000, 0x7007, 0x0004, 0x7994, 0x70d4, - 0xa102, 0x0048, 0x24e3, 0x0040, 0x24ed, 0x7b90, 0xa302, 0x00c0, - 0x24ed, 0x0078, 0x24e6, 0x8002, 0x00c0, 0x24ed, 0x263a, 0x7810, - 0xc0ad, 0x7812, 0x2091, 0x8001, 0x007c, 0xa184, 0xff00, 0x0040, - 0x24fa, 0x810f, 0x810c, 0x810c, 0x8004, 0x8004, 0x8007, 0xa100, - 0x0078, 0x24fd, 0x8107, 0x8004, 0x8004, 0x7a9c, 0xa210, 0x721a, - 0x7a98, 0xa006, 0xa211, 0x721e, 0xd4c4, 0x0040, 0x250d, 0x7aa4, - 0xa211, 0x7222, 0x7aa0, 0xa211, 0x7226, 0x20a1, 0x0030, 0x7003, - 0x0000, 0x2009, 0x9754, 0x260a, 0x8109, 0x2198, 0x2104, 0xd084, - 0x0040, 0x251b, 0x8633, 0xa6b0, 0x0002, 0x26a8, 0x53a6, 0x8603, - 0x7012, 0x7007, 0x0001, 0x7990, 0x7894, 0x8000, 0xa10a, 0x00c8, - 0x252a, 0xa006, 0x2028, 0x7974, 0xa184, 0xff00, 0x0040, 0x2539, - 0x810f, 0x810c, 0x810c, 0x8004, 0x8004, 0x8007, 0xa100, 0x0078, - 0x253c, 0x8107, 0x8004, 0x8004, 0x797c, 0xa108, 0x7a78, 0xa006, - 0xa211, 0xd4c4, 0x0040, 0x2548, 0x7b84, 0xa319, 0x7c80, 0xa421, - 0x7008, 0xd0fc, 0x0040, 0x2548, 0xa084, 0x01e0, 0x0040, 0x256d, - 0x7d10, 0x2031, 0x9754, 0x2634, 0x78a8, 0x8000, 0x78aa, 0xd08c, - 0x00c0, 0x2562, 0x7007, 0x0006, 0x7004, 0xd094, 0x00c0, 0x255c, - 0x0078, 0x24d4, 0x2069, 0x4f47, 0x206b, 0x0003, 0x78ac, 0xa085, - 0x0300, 0x78ae, 0xa006, 0x0078, 0x2576, 0x2030, 0x75d6, 0x2091, - 0x4080, 0x7d96, 0x7d10, 0xa5ac, 0xffcf, 0x7d12, 0x2091, 0x8001, - 0x78aa, 0x7007, 0x0006, 0x263a, 0x7003, 0x0001, 0x711a, 0x721e, - 0xd5c4, 0x0040, 0x2585, 0x7322, 0x7426, 0x007c, 0x6084, 0xa086, - 0x0103, 0x00c0, 0x25a9, 0x6114, 0x6018, 0xa105, 0x00c0, 0x25a9, - 0x2069, 0x0000, 0x6818, 0xd084, 0x00c0, 0x25a9, 0x600c, 0x70c6, - 0x6010, 0x70ca, 0x70c3, 0x8020, 0x681b, 0x0001, 0x2091, 0x4080, - 0x1078, 0x2086, 0x0068, 0x25a8, 0x786c, 0xa065, 0x00c0, 0x2586, - 0x007c, 0x1078, 0x25bd, 0x00c0, 0x25e0, 0x786c, 0xa065, 0x00c0, - 0x2586, 0x0078, 0x25e0, 0x1078, 0x25bd, 0x00c0, 0x25e0, 0x786c, - 0xa065, 0x00c0, 0x25b3, 0x0078, 0x25e0, 0x6084, 0xa086, 0x0103, - 0x00c0, 0x25d1, 0x6018, 0xc0fc, 0x601a, 0xa086, 0x0004, 0x00c0, - 0x25d1, 0x7804, 0xd0a4, 0x0040, 0x25d1, 0x1078, 0x2086, 0xa006, - 0x007c, 0x1078, 0x25e6, 0x00c0, 0x25d8, 0xa085, 0x0001, 0x007c, - 0x1078, 0x25f5, 0x00c0, 0x25de, 0x2041, 0x0001, 0x7d10, 0x007c, - 0x88ff, 0x0040, 0x25e5, 0x2091, 0x4080, 0x007c, 0x7b90, 0x7994, - 0x70d4, 0xa102, 0x00c0, 0x25ef, 0xa385, 0x0000, 0x007c, 0x0048, - 0x25f3, 0xa302, 0x007c, 0x8002, 0x007c, 0x7810, 0xd0ec, 0x0040, - 0x260d, 0x0e7e, 0x2091, 0x8000, 0x2071, 0x0020, 0x7004, 0xa005, - 0x00c0, 0x260a, 0x7008, 0x0e7f, 0xa086, 0x0008, 0x0040, 0x260d, - 0x0078, 0x265e, 0x0e7f, 0x0078, 0x265e, 0xa184, 0xff00, 0x0040, - 0x261a, 0x810f, 0x810c, 0x810c, 0x8004, 0x8004, 0x8007, 0xa100, - 0x0078, 0x261d, 0x8107, 0x8004, 0x8004, 0x7a9c, 0x7b98, 0x7ca4, - 0x7da0, 0xa210, 0xa006, 0xa319, 0xa421, 0xa529, 0x2009, 0x0018, - 0x6028, 0xa005, 0x0040, 0x262e, 0x2009, 0x0040, 0x1078, 0x1dbb, - 0x0040, 0x2650, 0x78a8, 0x8000, 0x78aa, 0xd08c, 0x00c0, 0x265e, - 0x6014, 0xd0fc, 0x00c0, 0x2640, 0x2069, 0x4f40, 0x0078, 0x2642, - 0x2069, 0x4f80, 0x2091, 0x8000, 0x681f, 0x0003, 0x78ab, 0x0000, - 0x78ac, 0xa085, 0x0300, 0x78ae, 0x2091, 0x8001, 0x0078, 0x265e, - 0x78ab, 0x0000, 0x1078, 0x2086, 0x7990, 0x7894, 0x8000, 0xa10a, - 0x00c8, 0x265b, 0xa006, 0x7896, 0x70d6, 0xa006, 0x2071, 0x0010, - 0x2091, 0x8001, 0x007c, 0xd7fc, 0x00c0, 0x266a, 0x2009, 0x4f59, - 0x0078, 0x266c, 0x2009, 0x4f99, 0x2091, 0x8000, 0x200a, 0x0f7e, - 0xd7fc, 0x00c0, 0x2683, 0x2009, 0x4f40, 0x2001, 0x4f04, 0x2004, - 0xd0ec, 0x0040, 0x267f, 0x2079, 0x0100, 0x0078, 0x2687, 0x2079, - 0x0200, 0x0078, 0x2687, 0x2009, 0x4f80, 0x2079, 0x0100, 0x2104, - 0xa086, 0x0000, 0x00c0, 0x26a0, 0xd7fc, 0x00c0, 0x2693, 0x2009, - 0x4f45, 0x0078, 0x2695, 0x2009, 0x4f85, 0x2104, 0xa005, 0x00c0, - 0x26a0, 0x7830, 0xa084, 0x00c0, 0x00c0, 0x26a0, 0x781b, 0x0045, - 0x0f7f, 0x007c, 0x2009, 0x0002, 0x2069, 0x4f00, 0x6810, 0xd0ec, - 0x00c0, 0x270f, 0x2071, 0x4f80, 0x2079, 0x0100, 0x2021, 0x51bf, - 0x784b, 0x000f, 0x2019, 0x44a7, 0xd184, 0x0040, 0x26c3, 0x6810, - 0xd0ec, 0x0040, 0x26bf, 0x20a1, 0x012b, 0x0078, 0x26c5, 0x20a1, - 0x022b, 0x0078, 0x26c5, 0x20a1, 0x012b, 0x2304, 0xa005, 0x0040, - 0x26d2, 0x789a, 0x8318, 0x23ac, 0x8318, 0x2398, 0x53a6, 0x3318, - 0x0078, 0x26c5, 0x789b, 0x0020, 0x20a9, 0x0010, 0x6814, 0xd0e4, - 0x0040, 0x26e2, 0x78af, 0x0000, 0x78af, 0x9020, 0x00f0, 0x26da, - 0x0078, 0x26e8, 0x78af, 0x0000, 0x78af, 0x8020, 0x00f0, 0x26e2, - 0x7003, 0x0000, 0x017e, 0xd18c, 0x2009, 0x0000, 0x0040, 0x26f1, - 0xc1bd, 0x1078, 0x28e2, 0x017f, 0x7020, 0xa084, 0x000f, 0x007e, - 0x6814, 0xd0e4, 0x007f, 0x00c0, 0x2701, 0xa085, 0x6340, 0x0078, - 0x2703, 0xa085, 0x62c0, 0x7806, 0x780f, 0x9200, 0x7843, 0x00d8, - 0x7853, 0x0080, 0x780b, 0x0008, 0x7456, 0x7053, 0x0000, 0x8109, - 0x0040, 0x2722, 0x2071, 0x4f40, 0x6810, 0xd0ec, 0x0040, 0x271c, - 0x2079, 0x0100, 0x0078, 0x271e, 0x2079, 0x0200, 0x2021, 0x4fbf, - 0x0078, 0x26b0, 0x007c, 0x017e, 0xd1bc, 0x00c0, 0x2737, 0x007e, - 0x2001, 0x4f04, 0x2004, 0xd0ec, 0x007f, 0x0040, 0x2733, 0x2011, - 0x0101, 0x0078, 0x2739, 0x2011, 0x0201, 0x0078, 0x2739, 0x2011, - 0x0101, 0xa18c, 0x000f, 0x2204, 0xa084, 0xfff0, 0xa105, 0x2012, - 0x017f, 0x1078, 0x28e2, 0x007c, 0xd3fc, 0x00c0, 0x2757, 0x007e, - 0x2001, 0x4f04, 0x2004, 0xd0ec, 0x007f, 0x0040, 0x2753, 0x2011, - 0x0101, 0x0078, 0x2759, 0x2011, 0x0201, 0x0078, 0x2759, 0x2011, - 0x0101, 0x20a9, 0x0009, 0x810b, 0x00f0, 0x275b, 0xa18c, 0x0e00, - 0x2204, 0xa084, 0xf1ff, 0xa105, 0x2012, 0x007c, 0x2019, 0x0002, - 0x2001, 0x4f04, 0x2004, 0xd0ec, 0x0040, 0x2773, 0x8319, 0x2009, - 0x0101, 0x0078, 0x2775, 0x2009, 0x0101, 0x20a9, 0x0005, 0x8213, - 0x00f0, 0x2777, 0xa294, 0x00e0, 0x2104, 0xa084, 0xff1f, 0xa205, - 0x200a, 0x8319, 0x0040, 0x2788, 0x2009, 0x0201, 0x0078, 0x2775, - 0x007c, 0xd3fc, 0x00c0, 0x279c, 0x007e, 0x2001, 0x4f04, 0x2004, - 0xd0ec, 0x007f, 0x0040, 0x2798, 0x2011, 0x0101, 0x0078, 0x279e, - 0x2011, 0x0201, 0x0078, 0x279e, 0x2011, 0x0101, 0x20a9, 0x000c, - 0x810b, 0x00f0, 0x27a0, 0xa18c, 0xf000, 0x2204, 0xa084, 0x0fff, - 0xa105, 0x2012, 0x007c, 0xd3fc, 0x00c0, 0x27be, 0x007e, 0x2001, - 0x4f04, 0x2004, 0xd0ec, 0x007f, 0x0040, 0x27ba, 0x2011, 0x0102, - 0x0078, 0x27c0, 0x2011, 0x0202, 0x0078, 0x27c0, 0x2011, 0x0102, - 0x2204, 0xa084, 0xffcf, 0xa105, 0x2012, 0x007c, 0x0c7e, 0xd1bc, - 0x00c0, 0x27da, 0x007e, 0x2001, 0x4f04, 0x2004, 0xd0ec, 0x007f, - 0x0040, 0x27d6, 0x2061, 0x0100, 0x0078, 0x27dc, 0x2061, 0x0200, - 0x0078, 0x27dc, 0x2061, 0x0100, 0xc1bc, 0x8103, 0x8003, 0xa080, - 0x0020, 0x609a, 0x62ac, 0x63ac, 0x0c7f, 0x007c, 0x0c7e, 0xd1bc, - 0x00c0, 0x27fa, 0x007e, 0x2001, 0x4f04, 0x2004, 0xd0ec, 0x007f, - 0x0040, 0x27f6, 0x2061, 0x0100, 0x0078, 0x27fc, 0x2061, 0x0200, - 0x0078, 0x27fc, 0x2061, 0x0100, 0xc1bc, 0x8103, 0x8003, 0xa080, - 0x0022, 0x609a, 0x60a4, 0xa084, 0xffdf, 0x60ae, 0x0c7f, 0x007c, - 0x0c7e, 0xd1bc, 0x00c0, 0x281c, 0x007e, 0x2001, 0x4f04, 0x2004, - 0xd0ec, 0x007f, 0x0040, 0x2818, 0x2061, 0x0100, 0x0078, 0x281e, - 0x2061, 0x0200, 0x0078, 0x281e, 0x2061, 0x0100, 0xc1bc, 0x8103, - 0x8003, 0xa080, 0x0022, 0x609a, 0x60a4, 0xa085, 0x0020, 0x60ae, - 0x0c7f, 0x007c, 0x0c7e, 0xd1bc, 0x00c0, 0x283e, 0x007e, 0x2001, - 0x4f04, 0x2004, 0xd0ec, 0x007f, 0x0040, 0x283a, 0x2061, 0x0100, - 0x0078, 0x2840, 0x2061, 0x0200, 0x0078, 0x2840, 0x2061, 0x0100, - 0xc1bc, 0x8103, 0x8003, 0xa080, 0x0020, 0x609a, 0x60a4, 0xa28c, - 0x0020, 0x0040, 0x284e, 0xc2ac, 0xa39d, 0x4000, 0xc3fc, 0xd3b4, - 0x00c0, 0x2853, 0xc3fd, 0x62ae, 0x2010, 0x60a4, 0x63ae, 0x2018, - 0x0c7f, 0x007c, 0x2091, 0x8000, 0x0c7e, 0x0e7e, 0x6818, 0xa005, - 0x0040, 0x28c0, 0xd1fc, 0x0040, 0x2869, 0x2061, 0x96d0, 0x0078, - 0x286b, 0x2061, 0x95c0, 0x1078, 0x28c8, 0x0040, 0x28a2, 0x20a9, - 0x0101, 0xd1fc, 0x0040, 0x2878, 0x2061, 0x95d0, 0x0078, 0x287a, - 0x2061, 0x94c0, 0x0c7e, 0x1078, 0x28c8, 0x0040, 0x2885, 0x0c7f, - 0x8c60, 0x00f0, 0x287a, 0x0078, 0x28c0, 0x007f, 0xd1fc, 0x0040, - 0x288f, 0xa082, 0x95d0, 0x2071, 0x4f80, 0x0078, 0x2893, 0xa082, - 0x94c0, 0x2071, 0x4f40, 0x707a, 0x7176, 0x2138, 0x2001, 0x0004, - 0x7066, 0x7083, 0x000f, 0x71d4, 0xc1dc, 0x71d6, 0x1078, 0x2663, - 0x0078, 0x28bc, 0xd1fc, 0x00c0, 0x28a9, 0x2071, 0x4f40, 0x0078, - 0x28ab, 0x2071, 0x4f80, 0x6020, 0xc0dd, 0x6022, 0x7176, 0x2138, - 0x2c00, 0x707e, 0x2001, 0x0006, 0x7066, 0x7083, 0x000f, 0x71d4, - 0xc1dc, 0x71d6, 0x1078, 0x2663, 0x2001, 0x0000, 0x0078, 0x28c2, - 0x2001, 0x0001, 0x2091, 0x8001, 0xa005, 0x0e7f, 0x0c7f, 0x007c, - 0x2c04, 0xa005, 0x0040, 0x28df, 0x2060, 0x6010, 0xa306, 0x00c0, - 0x28dc, 0x600c, 0xa206, 0x00c0, 0x28dc, 0x6014, 0xa106, 0x00c0, - 0x28dc, 0xa006, 0x0078, 0x28e1, 0x6000, 0x0078, 0x28c9, 0xa085, - 0x0001, 0x007c, 0x0f7e, 0x0e7e, 0x017e, 0xd1bc, 0x00c0, 0x28fa, - 0x2079, 0x4f40, 0x007e, 0x2001, 0x4f04, 0x2004, 0xd0ec, 0x007f, - 0x0040, 0x28f6, 0x2071, 0x0100, 0x0078, 0x28fe, 0x2071, 0x0200, - 0x0078, 0x28fe, 0x2079, 0x4f80, 0x2071, 0x0100, 0x7920, 0xa18c, - 0x000f, 0x70ec, 0xd0c4, 0x00c0, 0x2908, 0x017f, 0x0078, 0x2923, - 0x810b, 0x810b, 0x810b, 0x810b, 0x007f, 0xd0bc, 0x00c0, 0x2920, - 0x007e, 0x2001, 0x4f04, 0x2004, 0xd0ec, 0x007f, 0x0040, 0x291c, - 0xa18d, 0x0f00, 0x0078, 0x2922, 0xa18d, 0x0f00, 0x0078, 0x2922, - 0xa18d, 0x0800, 0x2104, 0x0e7f, 0x0f7f, 0x007c, 0x0e7e, 0x2001, - 0x4f01, 0x2004, 0xd0ac, 0x00c0, 0x29a3, 0x68e4, 0xd0ac, 0x0040, - 0x29a3, 0xa084, 0x0006, 0x00c0, 0x29a3, 0x6014, 0xd0fc, 0x00c0, - 0x293d, 0x2071, 0x53c0, 0x0078, 0x293f, 0x2071, 0x5440, 0x8007, - 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xae70, 0x7004, 0xa084, - 0x000a, 0x00c0, 0x29a3, 0x7108, 0xa194, 0xff00, 0x0040, 0x29a3, - 0xa18c, 0x00ff, 0x2001, 0x000a, 0xa106, 0x0040, 0x2972, 0x2001, - 0x000c, 0xa106, 0x0040, 0x2976, 0x2001, 0x0012, 0xa106, 0x0040, - 0x297a, 0x2001, 0x0014, 0xa106, 0x0040, 0x297e, 0x2001, 0x0019, - 0xa106, 0x0040, 0x2982, 0x2001, 0x0032, 0xa106, 0x0040, 0x2986, - 0x0078, 0x298a, 0x2009, 0x000c, 0x0078, 0x298c, 0x2009, 0x0012, - 0x0078, 0x298c, 0x2009, 0x0014, 0x0078, 0x298c, 0x2009, 0x0019, - 0x0078, 0x298c, 0x2009, 0x0020, 0x0078, 0x298c, 0x2009, 0x003f, - 0x0078, 0x298c, 0x2011, 0x0000, 0x2100, 0xa205, 0x700a, 0x2071, - 0x4f00, 0x7004, 0xd0bc, 0x0040, 0x29a3, 0x6014, 0xd0fc, 0x00c0, - 0x299e, 0x70ea, 0x2071, 0x4f40, 0x0078, 0x29a1, 0x70ee, 0x2071, - 0x4f80, 0x701f, 0x000d, 0x0e7f, 0x007c, 0x2001, 0x4f05, 0x2004, - 0xd0e4, 0x00c0, 0x29b1, 0x7804, 0xa084, 0xff1f, 0xa085, 0x6340, - 0x7806, 0x007c, 0x0068, 0x29b2, 0x2091, 0x8000, 0x2071, 0x0000, - 0x007e, 0x7018, 0xd084, 0x00c0, 0x29b9, 0x007f, 0x2071, 0x0010, - 0x70ca, 0x007f, 0x70c6, 0x70c3, 0x8002, 0x70db, 0x080f, 0x70df, - 0x000b, 0x2071, 0x0000, 0x701b, 0x0001, 0x2091, 0x4080, 0x0078, - 0x29cf, 0x7f3c, 0x7e58, 0x7c30, 0x7d38, 0x78a0, 0x708e, 0x7592, - 0x7496, 0x769a, 0x779e, 0xa594, 0x003f, 0xd4f4, 0x0040, 0x29e6, - 0xa784, 0x007d, 0x00c0, 0x441d, 0x1078, 0x29b2, 0xa49c, 0x000f, - 0xa382, 0x0004, 0x0050, 0x29f1, 0xa3a6, 0x0007, 0x00c0, 0x29b2, - 0x2418, 0x8507, 0xa084, 0x000f, 0x0079, 0x29f6, 0x3071, 0x3162, - 0x318d, 0x33ff, 0x37e8, 0x3862, 0x3917, 0x39a8, 0x3a96, 0x3b85, - 0x2a09, 0x2a06, 0x2e42, 0x2f65, 0x37b9, 0x2a06, 0x1078, 0x29b2, - 0x007c, 0xa006, 0x0078, 0x2a13, 0x7808, 0xc08d, 0x780a, 0xa006, - 0x7002, 0x704e, 0x7046, 0x70d2, 0x7060, 0xa005, 0x00c0, 0x2b79, - 0x7064, 0xa084, 0x0007, 0x0079, 0x2a1d, 0x2a25, 0x2a98, 0x2aa1, - 0x2aac, 0x2ab7, 0x2b5f, 0x2ac2, 0x2a98, 0x7830, 0xd0bc, 0x00c0, - 0x2a08, 0x71d4, 0xd1bc, 0x00c0, 0x2a08, 0xd1b4, 0x00c0, 0x2a75, - 0x70a4, 0xa086, 0x0001, 0x0040, 0x2a08, 0x70b4, 0xa06d, 0x6800, - 0xa065, 0xa055, 0x789b, 0x0010, 0x6b0c, 0x7baa, 0x6808, 0xa045, - 0x6d10, 0x6804, 0xa06d, 0xa05d, 0xa886, 0x0001, 0x0040, 0x2a4b, - 0x69bc, 0x7daa, 0x79aa, 0x68c0, 0xa04d, 0x6e1c, 0x2001, 0x0010, - 0x0078, 0x2cd3, 0x7060, 0xa005, 0x00c0, 0x2a08, 0x0c7e, 0x0d7e, - 0x70b4, 0xa06d, 0x6800, 0xa065, 0xa055, 0x789b, 0x0010, 0x6b0c, - 0x7baa, 0x6808, 0xa045, 0x6d10, 0x6804, 0xa06d, 0xa05d, 0xa886, - 0x0001, 0x0040, 0x2a6e, 0x69bc, 0x7daa, 0x79aa, 0x68c0, 0xa04d, - 0x6e1c, 0x2001, 0x0020, 0x0078, 0x2cd3, 0x1078, 0x43b0, 0x00c0, - 0x2a08, 0x781b, 0x005b, 0x70bc, 0xa06d, 0x68b4, 0x785a, 0x6894, - 0x78d6, 0x78de, 0x6898, 0x78d2, 0x78da, 0x7808, 0xc08d, 0x780a, - 0x68bc, 0x7042, 0xc1b4, 0x71d6, 0x70b8, 0xa065, 0x68c0, 0x705a, - 0x7003, 0x0002, 0x2d00, 0x704e, 0xad80, 0x0009, 0x7046, 0x007c, - 0x1078, 0x43b0, 0x00c0, 0x2aa0, 0x781b, 0x0047, 0x7003, 0x0004, - 0x007c, 0x1078, 0x43b0, 0x00c0, 0x2aab, 0x2011, 0x000c, 0x1078, - 0x2ad2, 0x7003, 0x0004, 0x007c, 0x1078, 0x43b0, 0x00c0, 0x2ab6, - 0x2011, 0x0006, 0x1078, 0x2ad2, 0x7003, 0x0004, 0x007c, 0x1078, - 0x43b0, 0x00c0, 0x2ac1, 0x2011, 0x000d, 0x1078, 0x2ad2, 0x7003, - 0x0004, 0x007c, 0x1078, 0x43b0, 0x00c0, 0x2ad1, 0x2011, 0x0006, - 0x1078, 0x2ad2, 0x707c, 0x707f, 0x0000, 0x2068, 0x704e, 0x7003, - 0x0001, 0x007c, 0x7174, 0xc1fc, 0x8107, 0x7882, 0x789b, 0x0010, - 0xa286, 0x000c, 0x00c0, 0x2ae1, 0x7aaa, 0x2001, 0x0001, 0x0078, - 0x2af6, 0xa18c, 0x001f, 0xa18d, 0x00c0, 0x79aa, 0xa286, 0x000d, - 0x0040, 0x2aef, 0x7aaa, 0x2001, 0x0002, 0x0078, 0x2af6, 0x78ab, - 0x0020, 0x7178, 0x79aa, 0x7aaa, 0x2001, 0x0004, 0x789b, 0x0060, - 0x78aa, 0x785b, 0x0004, 0x781b, 0x0116, 0x1078, 0x43d3, 0x7083, - 0x000f, 0x70d4, 0xd0b4, 0x0040, 0x2b12, 0xc0b4, 0x70d6, 0x0c7e, - 0x70b8, 0xa065, 0x6008, 0xa084, 0xfbef, 0x600a, 0x6018, 0x8001, - 0x601a, 0x0c7f, 0x007c, 0x7014, 0xa005, 0x00c0, 0x2b21, 0x70d4, - 0xd0b4, 0x0040, 0x2b22, 0x70b8, 0xac06, 0x00c0, 0x2b22, 0x1078, - 0x2b01, 0x007c, 0x017e, 0x71a4, 0xa186, 0x0001, 0x0040, 0x2b54, - 0x0d7e, 0x027e, 0x2100, 0x2011, 0x0001, 0xa212, 0x70b4, 0x2068, - 0x6800, 0xac06, 0x0040, 0x2b3b, 0x8211, 0x0040, 0x2b52, 0x1078, - 0x2b56, 0x0078, 0x2b30, 0x0c7e, 0x2100, 0x2011, 0x0001, 0xa212, - 0x70b4, 0x2068, 0x6800, 0x2060, 0x6008, 0xa084, 0xfbef, 0x600a, - 0x8211, 0x0040, 0x2b4f, 0x1078, 0x2b56, 0x0078, 0x2b42, 0x70a7, - 0x0001, 0x0c7f, 0x027f, 0x0d7f, 0x017f, 0x007c, 0xade8, 0x0005, - 0x70ac, 0xad06, 0x00c0, 0x2b5e, 0x70a8, 0x2068, 0x007c, 0x1078, - 0x43b0, 0x00c0, 0x2a08, 0x707c, 0x2068, 0x7774, 0x1078, 0x424e, - 0x2c50, 0x1078, 0x4492, 0x789b, 0x0010, 0x6814, 0xa084, 0x001f, - 0xc0bd, 0x78aa, 0x6e1c, 0x2041, 0x0001, 0x2001, 0x0004, 0x0078, - 0x2cd9, 0x1078, 0x43b0, 0x00c0, 0x2a08, 0x789b, 0x0010, 0x7060, - 0x2068, 0x6f14, 0x70d4, 0xd0b4, 0x0040, 0x2b93, 0xc0b4, 0x70d6, - 0x0c7e, 0x70b8, 0xa065, 0x6008, 0xa084, 0xfbef, 0x600a, 0x6018, - 0x8001, 0x601a, 0x0c7f, 0x1078, 0x424e, 0x2c50, 0x1078, 0x4492, - 0x6824, 0xa005, 0x0040, 0x2ba4, 0xa082, 0x0006, 0x0048, 0x2ba2, - 0x0078, 0x2ba4, 0x6827, 0x0005, 0x6814, 0xa084, 0x001f, 0xc0bd, - 0x78aa, 0x2031, 0x0020, 0x2041, 0x0001, 0x2001, 0x0003, 0x0078, - 0x2cd9, 0xc28d, 0x72d6, 0x72c0, 0xa200, 0xa015, 0x7154, 0x8108, - 0xa12a, 0x0048, 0x2bbc, 0x71c0, 0x2164, 0x6504, 0x85ff, 0x00c0, - 0x2bd3, 0x7156, 0x8421, 0x00c0, 0x2bb7, 0x70d4, 0xd08c, 0x0040, - 0x2bcf, 0x70d0, 0xa005, 0x00c0, 0x2bcf, 0x70d3, 0x000a, 0x007c, - 0x2200, 0x0078, 0x2bc1, 0x70d4, 0xc08c, 0x70d6, 0x70d3, 0x0000, - 0x6034, 0xa005, 0x00c0, 0x2bd0, 0x6708, 0xa784, 0x073f, 0x0040, - 0x2c02, 0xd7d4, 0x00c0, 0x2bd0, 0xa784, 0x0021, 0x00c0, 0x2bd0, - 0xa784, 0x0002, 0x0040, 0x2bf3, 0xa784, 0x0004, 0x0040, 0x2bd0, - 0xa7bc, 0xfffb, 0x670a, 0xa784, 0x0218, 0x00c0, 0x2bd0, 0xa784, - 0x0100, 0x0040, 0x2c02, 0x6018, 0xa005, 0x00c0, 0x2bd0, 0xa7bc, - 0xfeff, 0x670a, 0x2568, 0x6823, 0x0000, 0x6e1c, 0xa684, 0x000e, - 0x6318, 0x0040, 0x2c13, 0x601c, 0xa302, 0x0048, 0x2c16, 0x0040, - 0x2c16, 0x0078, 0x2bd0, 0x83ff, 0x00c0, 0x2bd0, 0x2d58, 0x2c50, - 0x7156, 0xd7bc, 0x00c0, 0x2c1f, 0x7028, 0x6022, 0x603a, 0xc7bc, - 0x670a, 0x68c0, 0xa065, 0xa04d, 0x6100, 0x2a60, 0x2041, 0x0001, - 0x6b14, 0xa39c, 0x001f, 0xa39d, 0x00c0, 0xd1fc, 0x0040, 0x2c33, - 0xd684, 0x0040, 0x2c35, 0xa39c, 0xffbf, 0xd6a4, 0x0040, 0x2c3a, - 0xa39d, 0x0020, 0xa684, 0x000e, 0x00c0, 0x2c85, 0xc7a5, 0x670a, - 0x2c00, 0x68c6, 0x77a4, 0xa786, 0x0001, 0x00c0, 0x2c59, 0x70d4, - 0xd0b4, 0x00c0, 0x2c59, 0x7000, 0xa082, 0x0002, 0x00c8, 0x2c59, - 0x7830, 0xd0bc, 0x00c0, 0x2c59, 0x789b, 0x0010, 0x7baa, 0x0078, - 0x2cd1, 0x8739, 0x77a6, 0x2750, 0x77b0, 0xa7b0, 0x0005, 0x70ac, - 0xa606, 0x00c0, 0x2c64, 0x76a8, 0x76b2, 0x2c3a, 0x8738, 0x2d3a, - 0x8738, 0x283a, 0x8738, 0x233a, 0x8738, 0x253a, 0x7830, 0xd0bc, - 0x0040, 0x2c7c, 0x2091, 0x8000, 0x2091, 0x303d, 0x70d4, 0xa084, - 0x303d, 0x2091, 0x8000, 0x2090, 0xaad5, 0x0000, 0x0040, 0x2c84, - 0x8421, 0x2200, 0x00c0, 0x2bb6, 0x007c, 0xd1dc, 0x0040, 0x3e49, - 0x2029, 0x0020, 0xd69c, 0x00c0, 0x2c92, 0x8528, 0xd68c, 0x00c0, - 0x2c92, 0x8528, 0x8840, 0x6f14, 0x610c, 0x8108, 0xa18c, 0x00ff, - 0x70cc, 0xa160, 0x2c64, 0x8cff, 0x0040, 0x2cb1, 0x6014, 0xa706, - 0x00c0, 0x2c9a, 0x60b8, 0x8001, 0x60ba, 0x00c0, 0x2c95, 0x2a60, - 0x6008, 0xa085, 0x0100, 0x600a, 0x2200, 0x8421, 0x00c0, 0x2bb6, - 0x007c, 0x2a60, 0x610e, 0x69be, 0x2c00, 0x68c6, 0x8840, 0x6008, - 0xc0d5, 0x600a, 0x77a4, 0xa786, 0x0001, 0x00c0, 0x2c59, 0x70d4, - 0xd0b4, 0x00c0, 0x2c59, 0x7000, 0xa082, 0x0002, 0x00c8, 0x2c59, - 0x7830, 0xd0bc, 0x00c0, 0x2c59, 0x789b, 0x0010, 0x7baa, 0x7daa, - 0x79aa, 0x2001, 0x0002, 0x007e, 0x6018, 0x8000, 0x601a, 0x0078, - 0x2cda, 0x007e, 0x2960, 0x6104, 0x2a60, 0xa184, 0x0018, 0x0040, - 0x2cf6, 0xa184, 0x0010, 0x0040, 0x2ce9, 0x1078, 0x405e, 0x00c0, - 0x2d1b, 0xa184, 0x0008, 0x0040, 0x2cf6, 0x69a0, 0xa184, 0x0600, - 0x00c0, 0x2cf6, 0x1078, 0x3f3e, 0x0078, 0x2d1b, 0x69a0, 0xa184, - 0x1e00, 0x0040, 0x2d26, 0xa184, 0x0800, 0x0040, 0x2d0f, 0x0c7e, - 0x2960, 0x6000, 0xa085, 0x2000, 0x6002, 0x6104, 0xa18d, 0x0010, - 0x6106, 0x0c7f, 0x1078, 0x405e, 0x00c0, 0x2d1b, 0x69a0, 0xa184, - 0x0200, 0x0040, 0x2d17, 0x1078, 0x3fa1, 0x0078, 0x2d1b, 0xa184, - 0x0400, 0x00c0, 0x2cf2, 0x69a0, 0xa184, 0x1000, 0x0040, 0x2d26, - 0x6914, 0xa18c, 0xff00, 0x810f, 0x1078, 0x27e6, 0x027f, 0xa68c, - 0x00e0, 0xa684, 0x0060, 0x0040, 0x2d33, 0xa086, 0x0060, 0x00c0, - 0x2d33, 0xa18d, 0x4000, 0xa18d, 0x0104, 0x69b6, 0x789b, 0x0060, - 0x2800, 0x78aa, 0x6818, 0xc0fd, 0x681a, 0xd6bc, 0x0040, 0x2d4e, - 0xc0fc, 0x7087, 0x0000, 0xa08a, 0x000d, 0x0050, 0x2d4c, 0xa08a, - 0x000c, 0x7186, 0x2001, 0x000c, 0x800c, 0x718a, 0x78aa, 0x3518, - 0x3340, 0x3428, 0x8000, 0x80ac, 0xaf80, 0x002b, 0x20a0, 0x789b, - 0x0000, 0xad80, 0x000b, 0x2098, 0x53a6, 0x23a8, 0x2898, 0x25a0, - 0xa286, 0x0020, 0x00c0, 0x2d86, 0x70d4, 0xc0b5, 0x70d6, 0x2c00, - 0x70ba, 0x2d00, 0x70be, 0x6814, 0xc0fc, 0x8007, 0x7882, 0xa286, - 0x0002, 0x0040, 0x2dbc, 0x70a4, 0x8000, 0x70a6, 0x74b4, 0xa498, - 0x0005, 0x70ac, 0xa306, 0x00c0, 0x2d7e, 0x73a8, 0x73b6, 0xa286, - 0x0010, 0x0040, 0x2a08, 0x0d7f, 0x0c7f, 0x007c, 0x7000, 0xa005, - 0x00c0, 0x2d64, 0xa286, 0x0002, 0x00c0, 0x2dd6, 0x1078, 0x43b0, - 0x00c0, 0x2d64, 0x6814, 0xc0fc, 0x8007, 0x7882, 0x2091, 0x8000, - 0x781b, 0x005b, 0x68b4, 0x785a, 0x6894, 0x78d6, 0x78de, 0x6898, - 0x78d2, 0x78da, 0x2091, 0x8001, 0x7808, 0xc08d, 0x780a, 0x127e, - 0x0d7e, 0x0c7e, 0x70d4, 0xa084, 0x2700, 0x2090, 0x0c7f, 0x0d7f, - 0x127f, 0x2900, 0x705a, 0x68bc, 0x7042, 0x7003, 0x0002, 0x2d00, - 0x704e, 0xad80, 0x0009, 0x7046, 0x7830, 0xd0bc, 0x0040, 0x2dc8, - 0x2091, 0x303d, 0x70d4, 0xa084, 0x303d, 0x2091, 0x8000, 0x2090, - 0x70a4, 0xa005, 0x00c0, 0x2dcd, 0x007c, 0x8421, 0x0040, 0x2dcc, - 0x7250, 0x70c0, 0xa200, 0xa015, 0x0078, 0x2bb6, 0xa286, 0x0010, - 0x00c0, 0x2e07, 0x1078, 0x43b0, 0x00c0, 0x2d64, 0x6814, 0xc0fc, - 0x8007, 0x7882, 0x781b, 0x005b, 0x68b4, 0x785a, 0x6894, 0x78d6, - 0x78de, 0x6898, 0x78d2, 0x78da, 0x7808, 0xc08d, 0x780a, 0x70a4, - 0x8000, 0x70a6, 0x74b4, 0xa490, 0x0005, 0x70ac, 0xa206, 0x00c0, - 0x2dfa, 0x72a8, 0x72b6, 0x2900, 0x705a, 0x68bc, 0x7042, 0x7003, - 0x0002, 0x2d00, 0x704e, 0xad80, 0x0009, 0x7046, 0x007c, 0x6bb4, - 0xa39d, 0x2000, 0x7b5a, 0x6814, 0xc0fc, 0x8007, 0x7882, 0x6b94, - 0x7bd6, 0x7bde, 0x6e98, 0x7ed2, 0x7eda, 0x781b, 0x005b, 0x2900, - 0x705a, 0x7202, 0x7808, 0xc08d, 0x780a, 0x2300, 0xa605, 0x0040, - 0x2e32, 0x70d4, 0xa084, 0x2700, 0xa086, 0x2300, 0x00c0, 0x2e2c, - 0x2009, 0x0000, 0x0078, 0x2e2e, 0x2009, 0x0001, 0xa284, 0x000f, - 0x1079, 0x2e38, 0xad80, 0x0009, 0x7046, 0x2d00, 0x704e, 0x007c, - 0x2e40, 0x493f, 0x493f, 0x492c, 0x493f, 0x2e40, 0x2e40, 0x2e40, - 0x1078, 0x29b2, 0x7808, 0xa084, 0xfffd, 0x780a, 0x1078, 0x29a5, - 0x0f7e, 0x2079, 0x4f00, 0x78ac, 0x0f7f, 0xd084, 0x0040, 0x2e6a, - 0x7064, 0xa086, 0x0001, 0x00c0, 0x2e58, 0x7066, 0x0078, 0x2f41, - 0x7064, 0xa086, 0x0005, 0x00c0, 0x2e68, 0x707c, 0x2068, 0x681b, - 0x0004, 0x6817, 0x0000, 0x6820, 0xa084, 0x00ff, 0xc09d, 0x6822, - 0x7067, 0x0000, 0x70a7, 0x0000, 0x70a8, 0x70b2, 0x70b6, 0x1078, - 0x2b01, 0x157e, 0x2011, 0x0004, 0x7164, 0xa186, 0x0001, 0x0040, - 0x2e8a, 0xa186, 0x0007, 0x00c0, 0x2e81, 0x701f, 0x0005, 0x0078, - 0x2e8a, 0x701f, 0x0001, 0x7067, 0x0000, 0x70d4, 0xc0dd, 0x70d6, - 0x0078, 0x2e8c, 0x7067, 0x0000, 0x2001, 0x4f0a, 0x2004, 0xa084, - 0x00ff, 0xa086, 0x0018, 0x0040, 0x2e9c, 0x7018, 0x7016, 0xa005, - 0x00c0, 0x2e9c, 0x70a7, 0x0001, 0x067e, 0x1078, 0x45d6, 0x20a9, - 0x0010, 0x2039, 0x0000, 0x1078, 0x4148, 0xa7b8, 0x0100, 0x00f0, - 0x2ea3, 0x067f, 0x7000, 0x0079, 0x2ead, 0x2ee7, 0x2ec2, 0x2ec2, - 0x2eb7, 0x2ee7, 0x2ee7, 0x2ee7, 0x2eb5, 0x1078, 0x29b2, 0x7060, - 0xa005, 0x0040, 0x2ee7, 0xad06, 0x00c0, 0x2ec2, 0x6800, 0x7062, - 0x0078, 0x2ed4, 0x6820, 0xd084, 0x00c0, 0x2ed0, 0x6f14, 0x1078, - 0x424e, 0x6008, 0xc0d4, 0x600a, 0x1078, 0x3e19, 0x0078, 0x2ed4, - 0x705c, 0x2060, 0x6800, 0x6002, 0xa684, 0x5f00, 0x681e, 0x6818, - 0xd0fc, 0x0040, 0x2edc, 0x6a1a, 0x6817, 0x0000, 0x682b, 0x0000, - 0x6820, 0xa084, 0x00ff, 0xc09d, 0x6822, 0x1078, 0x2073, 0xb284, - 0x0400, 0x0040, 0x2eef, 0x2021, 0x96d0, 0x0078, 0x2ef1, 0x2021, - 0x95c0, 0x1078, 0x2f46, 0xb284, 0x0400, 0x0040, 0x2efb, 0x2021, - 0x4f98, 0x0078, 0x2efd, 0x2021, 0x4f58, 0x1078, 0x2f46, 0x20a9, - 0x0101, 0xb284, 0x0400, 0x0040, 0x2f09, 0x2021, 0x95d0, 0x0078, - 0x2f0b, 0x2021, 0x94c0, 0x1078, 0x2f46, 0x8420, 0x00f0, 0x2f0b, - 0xb284, 0x0300, 0x0040, 0x2f18, 0x2061, 0x54c0, 0x0078, 0x2f1a, - 0x2061, 0x74c0, 0x2021, 0x0002, 0x20a9, 0x0100, 0x6110, 0x81ff, - 0x0040, 0x2f37, 0x6018, 0x017e, 0x007e, 0x2011, 0x4f02, 0x220c, - 0xa102, 0x2012, 0x007f, 0x017f, 0xa102, 0x0050, 0x2f37, 0x6012, - 0x00c0, 0x2f37, 0x2011, 0x4f04, 0x2204, 0xc0a5, 0x2012, 0x601b, - 0x0000, 0xace0, 0x0010, 0x00f0, 0x2f1e, 0x8421, 0x00c0, 0x2f1c, - 0x157f, 0x7003, 0x0000, 0x704f, 0x0000, 0x007c, 0x047e, 0x2404, - 0xa005, 0x0040, 0x2f61, 0x2068, 0x6800, 0x007e, 0x6a1a, 0x6817, - 0x0000, 0x682b, 0x0000, 0x68b4, 0xa084, 0x5f00, 0x681e, 0x6820, - 0xa084, 0x00ff, 0xc09d, 0x6822, 0x1078, 0x2073, 0x007f, 0x0078, - 0x2f48, 0x047f, 0x2023, 0x0000, 0x007c, 0xa282, 0x0003, 0x0050, - 0x2f6b, 0x1078, 0x29b2, 0x2300, 0x0079, 0x2f6e, 0x2f71, 0x2ffc, - 0x3019, 0xa282, 0x0002, 0x0040, 0x2f77, 0x1078, 0x29b2, 0x7064, - 0x7067, 0x0000, 0x7083, 0x0000, 0x0079, 0x2f7e, 0x2f86, 0x2f86, - 0x2f88, 0x2fc8, 0x3e55, 0x2f86, 0x2fc8, 0x2f86, 0x1078, 0x29b2, - 0x7774, 0x1078, 0x4148, 0x7774, 0xa7bc, 0x8f00, 0x1078, 0x424e, - 0x6018, 0xa005, 0x0040, 0x2fbf, 0xd7fc, 0x00c0, 0x2f9b, 0x2021, - 0x95c0, 0x0078, 0x2f9d, 0x2021, 0x96d0, 0x2009, 0x0005, 0x2011, - 0x0010, 0x1078, 0x3034, 0x0040, 0x2fbf, 0x157e, 0x20a9, 0x0101, - 0xd7fc, 0x00c0, 0x2faf, 0x2021, 0x94c0, 0x0078, 0x2fb1, 0x2021, - 0x95d0, 0x047e, 0x2009, 0x0005, 0x2011, 0x0010, 0x1078, 0x3034, - 0x047f, 0x0040, 0x2fbe, 0x8420, 0x00f0, 0x2fb1, 0x157f, 0x8738, - 0xa784, 0x001f, 0x00c0, 0x2f8e, 0x0078, 0x2a0c, 0x0078, 0x2a0c, - 0x7774, 0x1078, 0x424e, 0x6018, 0xa005, 0x0040, 0x2ffa, 0xd7fc, - 0x00c0, 0x2fd6, 0x2021, 0x95c0, 0x0078, 0x2fd8, 0x2021, 0x96d0, - 0x2009, 0x0005, 0x2011, 0x0020, 0x1078, 0x3034, 0x0040, 0x2ffa, - 0x157e, 0x20a9, 0x0101, 0xd7fc, 0x00c0, 0x2fea, 0x2021, 0x94c0, - 0x0078, 0x2fec, 0x2021, 0x95d0, 0x047e, 0x2009, 0x0005, 0x2011, - 0x0020, 0x1078, 0x3034, 0x047f, 0x0040, 0x2ff9, 0x8420, 0x00f0, - 0x2fec, 0x157f, 0x0078, 0x2a0c, 0x2200, 0x0079, 0x2fff, 0x3002, - 0x3004, 0x3004, 0x1078, 0x29b2, 0x2009, 0x0012, 0x7064, 0xa086, - 0x0002, 0x0040, 0x300d, 0x2009, 0x000e, 0x6818, 0xd0fc, 0x0040, - 0x3012, 0x691a, 0x7067, 0x0000, 0x70d4, 0xc0dd, 0x70d6, 0x0078, - 0x435d, 0x2200, 0x0079, 0x301c, 0x3021, 0x3004, 0x301f, 0x1078, - 0x29b2, 0x1078, 0x45d6, 0x7000, 0xa086, 0x0002, 0x00c0, 0x3dc7, - 0x1078, 0x3e36, 0x6008, 0xa084, 0xfbef, 0x600a, 0x1078, 0x3db8, - 0x0040, 0x3dc7, 0x0078, 0x2a0c, 0x2404, 0xa005, 0x0040, 0x306d, - 0x2068, 0x2d04, 0x007e, 0x6814, 0xa706, 0x0040, 0x3043, 0x2d20, - 0x007f, 0x0078, 0x3035, 0x007f, 0x2022, 0x691a, 0x6817, 0x0000, - 0x682b, 0x0000, 0x68b4, 0xa084, 0x5f00, 0x681e, 0x6820, 0xa084, - 0x00ff, 0xa205, 0x6822, 0x1078, 0x2073, 0x2021, 0x4f02, 0x241c, - 0x8319, 0x2322, 0x6010, 0x8001, 0x6012, 0x00c0, 0x3064, 0x2021, - 0x4f04, 0x2404, 0xc0a5, 0x2022, 0x6008, 0xa084, 0xf9ef, 0x600a, - 0x1078, 0x2b22, 0x1078, 0x3e36, 0x007c, 0xa085, 0x0001, 0x0078, - 0x306c, 0x2300, 0x0079, 0x3074, 0x3079, 0x3077, 0x30f9, 0x1078, - 0x29b2, 0x78e4, 0xa005, 0x00d0, 0x30af, 0x3208, 0x007e, 0x2001, - 0x4f04, 0x2004, 0xd0ec, 0x007f, 0x0040, 0x308a, 0xa18c, 0x0300, - 0x0078, 0x308c, 0xa18c, 0x0400, 0x0040, 0x3092, 0x0018, 0x2a08, - 0x0078, 0x3094, 0x0028, 0x2a08, 0x2008, 0xa084, 0x0030, 0x00c0, - 0x309b, 0x0078, 0x37b9, 0x78ec, 0xa084, 0x0003, 0x0040, 0x3099, - 0x2100, 0xa084, 0x0007, 0x0079, 0x30a5, 0x30d9, 0x30e3, 0x30ce, - 0x30ad, 0x43a5, 0x43a5, 0x30ad, 0x30ee, 0x1078, 0x29b2, 0x7000, - 0xa086, 0x0004, 0x00c0, 0x30c9, 0x7064, 0xa086, 0x0002, 0x00c0, - 0x30bf, 0x2011, 0x0002, 0x2019, 0x0000, 0x0078, 0x2f65, 0x7064, - 0xa086, 0x0006, 0x0040, 0x30b9, 0x7064, 0xa086, 0x0004, 0x0040, - 0x30b9, 0x79e4, 0x2001, 0x0003, 0x0078, 0x3443, 0x6818, 0xd0fc, - 0x0040, 0x30d4, 0x681b, 0x001d, 0x1078, 0x4118, 0x781b, 0x0064, - 0x007c, 0x6818, 0xd0fc, 0x0040, 0x30df, 0x681b, 0x001d, 0x1078, - 0x4118, 0x0078, 0x4381, 0x6818, 0xd0fc, 0x0040, 0x30e9, 0x681b, - 0x001d, 0x1078, 0x4118, 0x781b, 0x00f8, 0x007c, 0x6818, 0xd0fc, - 0x0040, 0x30f4, 0x681b, 0x001d, 0x1078, 0x4118, 0x781b, 0x00c8, - 0x007c, 0xa584, 0x000f, 0x00c0, 0x3118, 0x1078, 0x29a5, 0x7000, - 0x0079, 0x3102, 0x2a0c, 0x310a, 0x310c, 0x3dc7, 0x3dc7, 0x3dc7, - 0x310a, 0x310a, 0x1078, 0x29b2, 0x1078, 0x3e36, 0x6008, 0xa084, - 0xfbef, 0x600a, 0x1078, 0x3db8, 0x0040, 0x3dc7, 0x0078, 0x2a0c, - 0x78e4, 0xa005, 0x00d0, 0x30af, 0x3208, 0x007e, 0x2001, 0x4f04, - 0x2004, 0xd0ec, 0x007f, 0x0040, 0x3129, 0xa18c, 0x0300, 0x0078, - 0x312b, 0xa18c, 0x0400, 0x0040, 0x3131, 0x0018, 0x30af, 0x0078, - 0x3133, 0x0028, 0x30af, 0x2008, 0xa084, 0x0030, 0x00c0, 0x313b, - 0x781b, 0x005b, 0x007c, 0x78ec, 0xa084, 0x0003, 0x0040, 0x3138, - 0x2100, 0xa184, 0x0007, 0x0079, 0x3145, 0x3154, 0x3158, 0x314f, - 0x314d, 0x43a5, 0x43a5, 0x314d, 0x439f, 0x1078, 0x29b2, 0x1078, - 0x4120, 0x781b, 0x0064, 0x007c, 0x1078, 0x4120, 0x0078, 0x4381, - 0x1078, 0x4120, 0x781b, 0x00f8, 0x007c, 0x1078, 0x4120, 0x781b, - 0x00c8, 0x007c, 0x2300, 0x0079, 0x3165, 0x316a, 0x3168, 0x316c, - 0x1078, 0x29b2, 0x0078, 0x39a8, 0x681b, 0x0016, 0x78a3, 0x0000, - 0x79e4, 0xa184, 0x0030, 0x0040, 0x39a8, 0x78ec, 0xa084, 0x0003, - 0x0040, 0x39a8, 0xa184, 0x0100, 0x0040, 0x3170, 0xa184, 0x0007, - 0x0079, 0x3182, 0x318a, 0x3158, 0x30ce, 0x435d, 0x43a5, 0x43a5, - 0x435d, 0x439f, 0x1078, 0x4369, 0x007c, 0xa282, 0x0005, 0x0050, - 0x3193, 0x1078, 0x29b2, 0x2300, 0x0079, 0x3196, 0x3199, 0x33c9, - 0x33d4, 0x2200, 0x0079, 0x319c, 0x31b6, 0x31a3, 0x31b6, 0x31a1, - 0x33ac, 0x1078, 0x29b2, 0x789b, 0x0018, 0x78a8, 0xa084, 0x00ff, - 0xa082, 0x0020, 0x0048, 0x4107, 0xa08a, 0x0004, 0x00c8, 0x4107, - 0x0079, 0x31b2, 0x4107, 0x4107, 0x4107, 0x40b1, 0x789b, 0x0018, - 0x79a8, 0xa184, 0x0080, 0x0040, 0x31c7, 0x0078, 0x4107, 0x7000, - 0xa005, 0x00c0, 0x31bd, 0x2011, 0x0004, 0x0078, 0x3b93, 0xa184, - 0x00ff, 0xa08a, 0x0010, 0x00c8, 0x4107, 0x0079, 0x31cf, 0x31e1, - 0x31df, 0x31f6, 0x31fa, 0x32cd, 0x4107, 0x4107, 0x32cf, 0x4107, - 0x4107, 0x33a8, 0x33a8, 0x4107, 0x4107, 0x4107, 0x33aa, 0x1078, - 0x29b2, 0xd6e4, 0x0040, 0x31ec, 0x2001, 0x0300, 0x8000, 0x8000, - 0x783a, 0x781b, 0x00c3, 0x007c, 0x6818, 0xd0fc, 0x0040, 0x31f4, - 0x681b, 0x001d, 0x0078, 0x31e4, 0x0078, 0x435d, 0x681b, 0x001d, - 0x0078, 0x4111, 0x6920, 0x6922, 0xa684, 0x1800, 0x00c0, 0x325f, - 0x6820, 0xd084, 0x00c0, 0x3265, 0x6818, 0xa086, 0x0008, 0x00c0, - 0x320b, 0x681b, 0x0000, 0xd6d4, 0x0040, 0x32ca, 0xd6bc, 0x0040, - 0x324b, 0x7087, 0x0000, 0x6818, 0xa084, 0x003f, 0xa08a, 0x000d, - 0x0050, 0x324b, 0xa08a, 0x000c, 0x7186, 0x2001, 0x000c, 0x800c, - 0x718a, 0x789b, 0x0061, 0x78aa, 0x157e, 0x137e, 0x147e, 0x017e, - 0x3208, 0xa18c, 0x0300, 0x0040, 0x323d, 0x007e, 0x2001, 0x4f04, - 0x2004, 0xd0ec, 0x007f, 0x0040, 0x3239, 0x20a1, 0x012b, 0x0078, - 0x323f, 0x20a1, 0x022b, 0x0078, 0x323f, 0x20a1, 0x012b, 0x017f, - 0x789b, 0x0000, 0x8000, 0x80ac, 0xad80, 0x000b, 0x2098, 0x53a6, - 0x147f, 0x137f, 0x157f, 0x6038, 0xa005, 0x00c0, 0x325a, 0x681c, - 0xa084, 0x000e, 0x0040, 0x4111, 0x1078, 0x4127, 0x782b, 0x3008, - 0x0078, 0x325c, 0x8001, 0x603a, 0x781b, 0x0067, 0x007c, 0xd6e4, - 0x0040, 0x3265, 0x781b, 0x0079, 0x007c, 0xa684, 0x0060, 0x0040, - 0x32c7, 0xd6dc, 0x0040, 0x32c7, 0xd6fc, 0x00c0, 0x3271, 0x0078, - 0x3288, 0xc6fc, 0x7e5a, 0x6eb6, 0x7adc, 0x79d8, 0x78d0, 0x801b, - 0x00c8, 0x327b, 0x8000, 0xa084, 0x003f, 0xa108, 0xa291, 0x0000, - 0x6b98, 0x2100, 0xa302, 0x68b2, 0x6b94, 0x2200, 0xa303, 0x68ae, - 0xd6f4, 0x0040, 0x328e, 0xc6f4, 0x7e5a, 0x6eb6, 0x7000, 0xa086, - 0x0003, 0x00c0, 0x329c, 0x007e, 0x1078, 0x45d6, 0x1078, 0x493f, - 0x007f, 0x781b, 0x0076, 0x007c, 0xa006, 0x1078, 0x4a44, 0x6ab0, - 0x69ac, 0x6c98, 0x6b94, 0x2200, 0xa105, 0x0040, 0x32ab, 0x2200, - 0xa422, 0x2100, 0xa31b, 0x6caa, 0x7cd2, 0x7cda, 0x6ba6, 0x7bd6, - 0x7bde, 0x2300, 0xa405, 0x00c0, 0x32bb, 0xc6f5, 0x7e5a, 0x6eb6, - 0x781b, 0x0076, 0x007c, 0x781b, 0x0076, 0x2200, 0xa115, 0x00c0, - 0x32c4, 0x1078, 0x493f, 0x007c, 0x1078, 0x4977, 0x007c, 0x781b, - 0x0079, 0x007c, 0x781b, 0x0067, 0x007c, 0x1078, 0x29b2, 0x0078, - 0x331b, 0x6920, 0xd1c4, 0x0040, 0x32e4, 0xc1c4, 0x6922, 0x0c7e, - 0x7058, 0x2060, 0x6000, 0xc0e4, 0x6002, 0x6004, 0xa084, 0xfff5, - 0x6006, 0x0c7f, 0x0078, 0x330f, 0xd1cc, 0x0040, 0x330f, 0xc1cc, - 0x6922, 0x0c7e, 0x7058, 0x2060, 0x6000, 0xc0ec, 0x6002, 0x6004, - 0xc0a4, 0x6006, 0x2008, 0x2c48, 0x0c7f, 0xd19c, 0x0040, 0x330f, - 0x1078, 0x424a, 0x1078, 0x3f3e, 0x88ff, 0x0040, 0x330f, 0x789b, - 0x0060, 0x2800, 0x78aa, 0x7e58, 0xc695, 0x7e5a, 0xd6d4, 0x00c0, - 0x330c, 0x781b, 0x0064, 0x007c, 0x781b, 0x0078, 0x007c, 0x7e58, - 0xd6d4, 0x00c0, 0x3316, 0x781b, 0x0067, 0x007c, 0x781b, 0x0079, - 0x007c, 0x0078, 0x410c, 0x2019, 0x0000, 0x7990, 0xa18c, 0x0007, - 0x00c0, 0x3329, 0x6820, 0xa084, 0x0100, 0x0040, 0x3319, 0x2009, - 0x0008, 0x789b, 0x0010, 0x78a8, 0xa094, 0x00ff, 0xa286, 0x0001, - 0x00c0, 0x3345, 0x2300, 0x7ca8, 0xa400, 0x2018, 0xa102, 0x0040, - 0x333d, 0x0048, 0x333d, 0x0078, 0x333f, 0x0078, 0x32d1, 0x24a8, - 0x7aa8, 0x00f0, 0x333f, 0x0078, 0x332b, 0xa284, 0x00f0, 0xa086, - 0x0020, 0x00c0, 0x3399, 0x8318, 0x8318, 0x2300, 0xa102, 0x0040, - 0x3355, 0x0048, 0x3355, 0x0078, 0x3396, 0xa286, 0x0023, 0x0040, - 0x3319, 0x681c, 0xa084, 0xfff1, 0x681e, 0x7e58, 0xa684, 0xfff1, - 0xc0a5, 0x2030, 0x7e5a, 0x6008, 0xc0a5, 0x600a, 0x0c7e, 0x7058, - 0x2060, 0x6004, 0x2008, 0x2c48, 0x0c7f, 0xd1a4, 0x0040, 0x3376, - 0x1078, 0x424a, 0x1078, 0x405e, 0x0078, 0x3384, 0x0c7e, 0x7058, - 0x2060, 0x6004, 0x2008, 0x2c48, 0x0c7f, 0xd19c, 0x0040, 0x330f, - 0x1078, 0x424a, 0x1078, 0x3f3e, 0x88ff, 0x0040, 0x330f, 0x789b, - 0x0060, 0x2800, 0x78aa, 0xc695, 0x7e5a, 0xd6d4, 0x00c0, 0x3393, - 0x781b, 0x0064, 0x007c, 0x781b, 0x0078, 0x007c, 0x7aa8, 0x0078, - 0x332b, 0x8318, 0x2300, 0xa102, 0x0040, 0x33a2, 0x0048, 0x33a2, - 0x0078, 0x332b, 0xa284, 0x0080, 0x00c0, 0x4111, 0x0078, 0x410c, - 0x0078, 0x4111, 0x0078, 0x4107, 0x7058, 0xa04d, 0x789b, 0x0018, - 0x78a8, 0xa084, 0x00ff, 0xa08e, 0x0001, 0x0040, 0x33b9, 0x1078, - 0x29b2, 0x7aa8, 0xa294, 0x00ff, 0x78a8, 0xa084, 0x00ff, 0xa08a, - 0x0004, 0x00c8, 0x4107, 0x0079, 0x33c5, 0x4107, 0x3e8f, 0x4107, - 0x4006, 0xa282, 0x0000, 0x00c0, 0x33cf, 0x1078, 0x29b2, 0x1078, - 0x4118, 0x781b, 0x0078, 0x007c, 0xa282, 0x0003, 0x00c0, 0x33da, - 0x1078, 0x29b2, 0xd4fc, 0x00c0, 0x33fa, 0x7064, 0xa005, 0x0040, - 0x33e3, 0x1078, 0x29b2, 0x6f14, 0x7776, 0xa7bc, 0x8f00, 0x1078, - 0x424e, 0x6008, 0xa085, 0x0021, 0x600a, 0x8738, 0xa784, 0x001f, - 0x00c0, 0x33e7, 0x1078, 0x411c, 0x7067, 0x0002, 0x701f, 0x0009, - 0x0078, 0x33fc, 0x1078, 0x412b, 0x781b, 0x0078, 0x007c, 0xa282, - 0x0004, 0x0050, 0x3405, 0x1078, 0x29b2, 0x2300, 0x0079, 0x3408, - 0x340b, 0x35cb, 0x360e, 0xa286, 0x0003, 0x0040, 0x3443, 0x7200, - 0x7cd8, 0x7ddc, 0x7fd0, 0x71d4, 0xd1bc, 0x00c0, 0x343b, 0xd1b4, - 0x0040, 0x343b, 0x7868, 0xa084, 0x00ff, 0x00c0, 0x343b, 0xa282, - 0x0002, 0x00c8, 0x343b, 0x0d7e, 0x783b, 0x8300, 0x781b, 0x004c, - 0x70bc, 0xa06d, 0x68b4, 0x785a, 0x6894, 0x78d6, 0x78de, 0x6898, - 0x78d2, 0x78da, 0xc1b4, 0x71d6, 0x7003, 0x0030, 0x0d7f, 0x2001, - 0x0000, 0x0078, 0x3447, 0x783b, 0x1300, 0x781b, 0x004a, 0x2001, - 0x0000, 0x0078, 0x3447, 0x7200, 0x7cd8, 0x7ddc, 0x7fd0, 0x704a, - 0x68a0, 0xd0ec, 0x0040, 0x344f, 0x6008, 0xc08d, 0x600a, 0xa284, - 0x000f, 0x0079, 0x3453, 0x35ab, 0x3460, 0x345d, 0x3711, 0x379d, - 0x2a0c, 0x345b, 0x345b, 0x1078, 0x29b2, 0x6008, 0xc0d4, 0x600a, - 0xd6e4, 0x0040, 0x3468, 0x7048, 0xa086, 0x0014, 0x00c0, 0x3488, - 0x1078, 0x45d6, 0x2009, 0x0000, 0x6818, 0xd0fc, 0x0040, 0x3471, - 0x7048, 0xa086, 0x0014, 0x0040, 0x3482, 0x6818, 0xa086, 0x0008, - 0x00c0, 0x3563, 0x7858, 0xd09c, 0x0040, 0x3563, 0x6820, 0xd0ac, - 0x0040, 0x3563, 0x681b, 0x0014, 0x2009, 0x0002, 0x0078, 0x34c7, - 0x7868, 0xa08c, 0x00ff, 0x0040, 0x34c7, 0xa186, 0x0008, 0x00c0, - 0x349e, 0x6008, 0xc0a4, 0x600a, 0x1078, 0x3db8, 0x0040, 0x34c7, - 0x1078, 0x3e36, 0x1078, 0x45d6, 0x0078, 0x34af, 0xa186, 0x0028, - 0x00c0, 0x34c7, 0x6018, 0xa005, 0x0040, 0x3491, 0x8001, 0x0040, - 0x3491, 0x8001, 0x0040, 0x3491, 0x601e, 0x0078, 0x3491, 0x6820, - 0xd084, 0x0040, 0x2a0c, 0xc084, 0x6822, 0x1078, 0x2b13, 0x705c, - 0x0c7e, 0x2060, 0x6800, 0x6002, 0x0c7f, 0x6004, 0x6802, 0xa005, - 0x2d00, 0x00c0, 0x34c4, 0x6002, 0x6006, 0x0078, 0x2a0c, 0x017e, - 0x81ff, 0x00c0, 0x3511, 0x7000, 0xa086, 0x0030, 0x0040, 0x3511, - 0x71d4, 0xd1bc, 0x00c0, 0x3511, 0xd1b4, 0x00c0, 0x34f8, 0x7060, - 0xa005, 0x00c0, 0x3511, 0x70a4, 0xa086, 0x0001, 0x0040, 0x3511, - 0x7003, 0x0000, 0x047e, 0x057e, 0x077e, 0x067e, 0x0c7e, 0x0d7e, - 0x1078, 0x2a35, 0x0d7f, 0x0c7f, 0x067f, 0x077f, 0x057f, 0x047f, - 0x71d4, 0xd1b4, 0x00c0, 0x3511, 0x7003, 0x0040, 0x0078, 0x3511, - 0x1078, 0x43b0, 0x00c0, 0x3511, 0x781b, 0x005b, 0x0d7e, 0x70bc, - 0xa06d, 0x68b4, 0x785a, 0x6894, 0x78d6, 0x78de, 0x6898, 0x78d2, - 0x78da, 0xc1b4, 0x71d6, 0x7003, 0x0030, 0x7808, 0xc08d, 0x780a, - 0x0d7f, 0x1078, 0x3648, 0x017f, 0x81ff, 0x0040, 0x3563, 0xa684, - 0xdf00, 0x681e, 0x682b, 0x0000, 0x6f14, 0xa186, 0x0002, 0x00c0, - 0x3564, 0x6818, 0xa086, 0x0014, 0x00c0, 0x352d, 0x2008, 0xd6e4, - 0x0040, 0x352d, 0x7868, 0xa08c, 0x00ff, 0x1078, 0x2b01, 0x1078, - 0x2b22, 0x6820, 0xd0dc, 0x00c0, 0x3564, 0x8717, 0xa294, 0x000f, - 0x8213, 0x8213, 0x8213, 0xb284, 0x0300, 0x0040, 0x3543, 0xa290, - 0x53c0, 0x0078, 0x3545, 0xa290, 0x5440, 0xa290, 0x0000, 0x221c, - 0xd3c4, 0x00c0, 0x354d, 0x0078, 0x3553, 0x8210, 0x2204, 0xa085, - 0x0018, 0x2012, 0x8211, 0xd3d4, 0x0040, 0x355e, 0x68a0, 0xd0c4, - 0x00c0, 0x355e, 0x1078, 0x36c2, 0x0078, 0x2a0c, 0x6008, 0xc08d, - 0x600a, 0x0078, 0x3564, 0x692a, 0x6916, 0x6818, 0xd0fc, 0x0040, - 0x356b, 0x7048, 0x681a, 0xa68c, 0xdf00, 0x691e, 0x6410, 0x84ff, - 0x0040, 0x3580, 0x2009, 0x4f02, 0x2104, 0x8001, 0x200a, 0x8421, - 0x6412, 0x00c0, 0x3580, 0x2021, 0x4f04, 0x2404, 0xc0a5, 0x2022, - 0x6018, 0xa005, 0x0040, 0x3588, 0x8001, 0x601a, 0x00c0, 0x358b, - 0x6008, 0xc0a4, 0x600a, 0x6820, 0xd084, 0x00c0, 0x3597, 0x6800, - 0xa005, 0x00c0, 0x3594, 0x6002, 0x6006, 0x0078, 0x359b, 0x705c, - 0x2060, 0x6800, 0x6002, 0x2061, 0x4f00, 0x6887, 0x0103, 0x2d08, - 0x206b, 0x0000, 0x6068, 0xa005, 0x616a, 0x0040, 0x35aa, 0x2d02, - 0x0078, 0x35ab, 0x616e, 0x7200, 0xa286, 0x0030, 0x0040, 0x35bb, - 0xa286, 0x0040, 0x00c0, 0x2a0c, 0x7003, 0x0002, 0x704c, 0x2068, - 0x68c4, 0x2060, 0x007c, 0x7003, 0x0002, 0x70bc, 0xa06d, 0x68bc, - 0x7042, 0x70b8, 0xa065, 0x68c0, 0x705a, 0x2d00, 0x704e, 0xad80, - 0x0009, 0x7046, 0x007c, 0xa282, 0x0004, 0x0048, 0x35d1, 0x1078, - 0x29b2, 0x2200, 0x0079, 0x35d4, 0x35d8, 0x35e9, 0x35f6, 0x35e9, - 0xa586, 0x1300, 0x0040, 0x35e9, 0xa586, 0x8300, 0x00c0, 0x35cf, - 0x7003, 0x0000, 0x6018, 0x8001, 0x601a, 0x6008, 0xa084, 0xfbef, - 0x600a, 0x7000, 0xa086, 0x0005, 0x0040, 0x35f3, 0x1078, 0x4118, - 0x781b, 0x0078, 0x007c, 0x781b, 0x0079, 0x007c, 0x7890, 0x8007, - 0x8001, 0xa084, 0x0007, 0xa080, 0x0018, 0x789a, 0x79a8, 0xa18c, - 0x00ff, 0xa186, 0x0003, 0x0040, 0x360b, 0xa186, 0x0000, 0x0040, - 0x360b, 0x0078, 0x4107, 0x781b, 0x0079, 0x007c, 0x6820, 0xc095, - 0x6822, 0x82ff, 0x00c0, 0x3618, 0x1078, 0x4118, 0x0078, 0x361f, - 0x8211, 0x0040, 0x361d, 0x1078, 0x29b2, 0x1078, 0x412b, 0x781b, - 0x0078, 0x007c, 0x1078, 0x43d3, 0x7830, 0xa084, 0x00c0, 0x00c0, - 0x3645, 0x017e, 0x3208, 0x007e, 0x2001, 0x4f04, 0x2004, 0xd0ec, - 0x007f, 0x0040, 0x3637, 0xa18c, 0x0300, 0x0078, 0x3639, 0xa18c, - 0x0400, 0x017f, 0x0040, 0x3640, 0x0018, 0x3645, 0x0078, 0x3642, - 0x0028, 0x3645, 0x791a, 0xa006, 0x007c, 0xa085, 0x0001, 0x007c, - 0xa684, 0x0060, 0x00c0, 0x3652, 0x682f, 0x0000, 0x6833, 0x0000, - 0x0078, 0x36c1, 0xd6dc, 0x00c0, 0x366a, 0x68b4, 0xd0dc, 0x00c0, - 0x366a, 0x6998, 0x6a94, 0x692e, 0x6a32, 0x7048, 0xa005, 0x00c0, - 0x3667, 0x2200, 0xa105, 0x0040, 0x45d6, 0x704b, 0x0015, 0x0078, - 0x45d6, 0x007c, 0xd6ac, 0x0040, 0x3690, 0xd6f4, 0x0040, 0x3676, - 0x682f, 0x0000, 0x6833, 0x0000, 0x0078, 0x45d6, 0x68b4, 0xa084, - 0x4000, 0xa635, 0xd6f4, 0x00c0, 0x3670, 0x7048, 0xa005, 0x00c0, - 0x3683, 0x704b, 0x0015, 0xd6dc, 0x00c0, 0x368c, 0x68b4, 0xd0dc, - 0x0040, 0x368c, 0x6ca8, 0x6da4, 0x6c2e, 0x6d32, 0x0078, 0x45d6, - 0xd6f4, 0x0040, 0x3699, 0x682f, 0x0000, 0x6833, 0x0000, 0x0078, - 0x45d6, 0x68b4, 0xa084, 0x4800, 0xa635, 0xd6f4, 0x00c0, 0x3693, - 0x7048, 0xa005, 0x00c0, 0x36a6, 0x704b, 0x0015, 0x2408, 0x2510, - 0x2700, 0x80fb, 0x00c8, 0x36ad, 0x8000, 0xa084, 0x003f, 0xa108, - 0xa291, 0x0000, 0x692e, 0x6a32, 0x2100, 0xa205, 0x00c0, 0x36ba, - 0x0078, 0x45d6, 0x7000, 0xa086, 0x0006, 0x0040, 0x36c1, 0x0078, - 0x45d6, 0x007c, 0x6946, 0x6008, 0xc0cd, 0xd3cc, 0x0040, 0x36c9, - 0xc08d, 0x600a, 0x6818, 0x683a, 0x681b, 0x0006, 0x688f, 0x0000, - 0x6893, 0x0000, 0x6a30, 0x692c, 0x6a3e, 0x6942, 0x682f, 0x0003, - 0x6833, 0x0000, 0x6837, 0x0020, 0x6897, 0x0000, 0x689b, 0x0020, - 0x7000, 0x0079, 0x36e3, 0x2a0c, 0x36f5, 0x36ed, 0x36eb, 0x36eb, - 0x36eb, 0x36eb, 0x36eb, 0x1078, 0x29b2, 0x6820, 0xd084, 0x00c0, - 0x36f5, 0x1078, 0x3e19, 0x0078, 0x36fb, 0x705c, 0x2c50, 0x2060, - 0x6800, 0x6002, 0x2a60, 0x3208, 0xa18c, 0x0300, 0x0040, 0x3704, - 0x2021, 0x4f58, 0x0078, 0x3706, 0x2021, 0x4f98, 0x2404, 0xa005, - 0x0040, 0x370d, 0x2020, 0x0078, 0x3706, 0x2d22, 0x206b, 0x0000, - 0x007c, 0x1078, 0x3e20, 0x1078, 0x3e36, 0x6008, 0xc0cc, 0x600a, - 0x682b, 0x0000, 0x789b, 0x000e, 0x6f14, 0x6938, 0x691a, 0x6944, - 0x6916, 0x3208, 0xa18c, 0x0300, 0x0040, 0x372a, 0x2009, 0x0000, - 0x0078, 0x372c, 0x2009, 0x0001, 0x1078, 0x4a81, 0xd6dc, 0x0040, - 0x3734, 0x691c, 0xc1ed, 0x691e, 0x6818, 0xd0fc, 0x0040, 0x3743, - 0x7868, 0xa08c, 0x00ff, 0x0040, 0x3741, 0x681b, 0x001e, 0x0078, - 0x3743, 0x681b, 0x0000, 0xb284, 0x0300, 0x00c0, 0x374b, 0x2021, - 0x4f98, 0x0078, 0x374d, 0x2021, 0x4f58, 0x6800, 0x2022, 0x6a3c, - 0x6940, 0x6a32, 0x692e, 0x68c0, 0x2060, 0x6000, 0xd0a4, 0x0040, - 0x378d, 0x2041, 0x0021, 0x2049, 0x0005, 0x2051, 0x0020, 0x0d7e, - 0x0f7e, 0x157e, 0x147e, 0x2079, 0x4f00, 0x1078, 0x1e46, 0x147f, - 0x157f, 0x0f7f, 0x70cc, 0x2010, 0x2009, 0x0101, 0x027e, 0x2204, - 0xa06d, 0x0040, 0x377d, 0x6814, 0xa706, 0x0040, 0x377a, 0x6800, - 0x0078, 0x3770, 0x6820, 0xc0d5, 0x6822, 0x027f, 0x8210, 0x8109, - 0x00c0, 0x376e, 0x0d7f, 0x7067, 0x0003, 0x707f, 0x0000, 0x7776, - 0x7083, 0x000f, 0x71d4, 0xc1dc, 0x71d6, 0x6818, 0xa086, 0x0002, - 0x00c0, 0x3799, 0x6817, 0x0000, 0x682b, 0x0000, 0x681c, 0xc0ec, - 0x681e, 0x1078, 0x2073, 0x0078, 0x2a0c, 0x7cd8, 0x7ddc, 0x7fd0, - 0x1078, 0x3648, 0x682b, 0x0000, 0x789b, 0x000e, 0x6f14, 0x1078, - 0x43d7, 0xa08c, 0x00ff, 0x6916, 0x6818, 0xd0fc, 0x0040, 0x37b2, - 0x7048, 0x681a, 0xa68c, 0xdf00, 0x691e, 0x7067, 0x0000, 0x0078, - 0x2a0c, 0x7000, 0xa005, 0x00c0, 0x37bf, 0x0078, 0x2a0c, 0xa006, - 0x1078, 0x45d6, 0x6920, 0xd1ac, 0x00c0, 0x37c8, 0x681b, 0x0014, - 0xa68c, 0xdf00, 0x691e, 0x682b, 0x0000, 0x6820, 0xa084, 0x00ff, - 0x6822, 0x7000, 0x0079, 0x37d4, 0x2a0c, 0x37de, 0x37de, 0x37e1, - 0x37e1, 0x37e1, 0x37dc, 0x37dc, 0x1078, 0x29b2, 0x6818, 0x0078, - 0x3443, 0x6008, 0xc0a4, 0x600a, 0x6817, 0x0000, 0x0078, 0x3dde, - 0x2300, 0x0079, 0x37eb, 0x37ee, 0x37f0, 0x3860, 0x1078, 0x29b2, - 0xd6fc, 0x00c0, 0x3847, 0x7000, 0xa00d, 0x0079, 0x37f7, 0x2a0c, - 0x3801, 0x3801, 0x3831, 0x3801, 0x3844, 0x37ff, 0x37ff, 0x1078, - 0x29b2, 0xa684, 0x0060, 0x0040, 0x3831, 0xa086, 0x0060, 0x00c0, - 0x382e, 0xc6ac, 0xc6f4, 0xc6ed, 0x7e5a, 0x6eb6, 0x681c, 0xc0ac, - 0x681e, 0xa186, 0x0002, 0x0040, 0x3820, 0x1078, 0x45d6, 0x69ac, - 0x68b0, 0xa115, 0x0040, 0x3820, 0x1078, 0x4977, 0x0078, 0x3822, - 0x1078, 0x493f, 0x781b, 0x0079, 0x71d4, 0xd1b4, 0x00c0, 0x2a08, - 0x70a4, 0xa086, 0x0001, 0x00c0, 0x2a52, 0x007c, 0xd6ec, 0x0040, - 0x380b, 0x6818, 0xd0fc, 0x0040, 0x3844, 0xd6f4, 0x00c0, 0x383e, - 0x681b, 0x0015, 0x781b, 0x0079, 0x0078, 0x2a08, 0x681b, 0x0007, - 0x682f, 0x0000, 0x6833, 0x0000, 0x1078, 0x4369, 0x007c, 0xc6fc, - 0x7e5a, 0x7adc, 0x79d8, 0x78d0, 0x801b, 0x00c8, 0x3850, 0x8000, - 0xa084, 0x003f, 0xa108, 0xa291, 0x0000, 0x6b98, 0x2100, 0xa302, - 0x68b2, 0x6b94, 0x2200, 0xa303, 0x68ae, 0x781b, 0x0079, 0x007c, - 0x1078, 0x29b2, 0x2300, 0x0079, 0x3865, 0x386a, 0x388f, 0x38ef, - 0x1078, 0x29b2, 0x7000, 0x0079, 0x386d, 0x3875, 0x3877, 0x3880, - 0x3875, 0x3875, 0x3875, 0x3875, 0x3875, 0x1078, 0x29b2, 0x69ac, - 0x68b0, 0xa115, 0x0040, 0x3880, 0x1078, 0x4977, 0x0078, 0x3882, - 0x1078, 0x493f, 0x681c, 0xc0b4, 0x681e, 0x70d4, 0xd0b4, 0x00c0, - 0x2a08, 0x70a4, 0xa086, 0x0001, 0x00c0, 0x2a52, 0x007c, 0xd6fc, - 0x00c0, 0x38df, 0x7000, 0xa00d, 0x0079, 0x3896, 0x2a0c, 0x38a6, - 0x38a0, 0x38d6, 0x38a6, 0x38dc, 0x389e, 0x389e, 0x1078, 0x29b2, - 0x6894, 0x78d6, 0x78de, 0x6898, 0x78d2, 0x78da, 0xa684, 0x0060, - 0x0040, 0x38d6, 0xa086, 0x0060, 0x00c0, 0x38d3, 0xa6b4, 0xbfbf, - 0xc6ed, 0x7e5a, 0x6eb6, 0xa186, 0x0002, 0x0040, 0x38c2, 0x1078, - 0x45d6, 0x69ac, 0x68b0, 0xa115, 0x0040, 0x38c2, 0x1078, 0x4977, - 0x0078, 0x38c4, 0x1078, 0x493f, 0x781b, 0x0079, 0x681c, 0xc0b4, - 0x681e, 0x71d4, 0xd1b4, 0x00c0, 0x2a08, 0x70a4, 0xa086, 0x0001, - 0x00c0, 0x2a52, 0x007c, 0xd6ec, 0x0040, 0x38b0, 0x6818, 0xd0fc, - 0x0040, 0x38dc, 0x681b, 0x0007, 0x781b, 0x00f9, 0x007c, 0xc6fc, - 0x7e5a, 0x7adc, 0x79d8, 0x6b98, 0x2100, 0xa302, 0x68b2, 0x6b94, - 0x2200, 0xa303, 0x68ae, 0x79d2, 0x781b, 0x0079, 0x007c, 0xd6dc, - 0x0040, 0x38f8, 0x782b, 0x3009, 0x781b, 0x0079, 0x0078, 0x2a08, - 0x7884, 0xc0ac, 0x7886, 0x78e4, 0xa084, 0x0008, 0x00c0, 0x390b, - 0xa484, 0x0200, 0x0040, 0x3905, 0xc6f5, 0xc6dd, 0x7e5a, 0x781b, - 0x0079, 0x0078, 0x2a08, 0x6820, 0xc095, 0x6822, 0x1078, 0x42e2, - 0xc6dd, 0x1078, 0x4118, 0x781b, 0x0078, 0x0078, 0x2a08, 0x2300, - 0x0079, 0x391a, 0x391d, 0x391f, 0x3921, 0x1078, 0x29b2, 0x0078, - 0x4111, 0xd6d4, 0x00c0, 0x395c, 0x79e4, 0xd1ac, 0x0040, 0x392f, - 0x78ec, 0xa084, 0x0003, 0x0040, 0x392f, 0x782b, 0x3009, 0x789b, - 0x0060, 0x78ab, 0x0000, 0xa684, 0xfffb, 0x785a, 0x79e4, 0xd1ac, - 0x0040, 0x393f, 0x78ec, 0xa084, 0x0003, 0x00c0, 0x3958, 0x2001, - 0x4f04, 0x2004, 0xd0e4, 0x00c0, 0x3954, 0x6820, 0xd0c4, 0x0040, - 0x3954, 0x0c7e, 0x7058, 0x2060, 0x6004, 0xc09d, 0x6006, 0x6008, - 0xa084, 0x00ff, 0x600a, 0x0c7f, 0x2001, 0x0014, 0x0078, 0x3443, - 0xa184, 0x0007, 0x0079, 0x3992, 0x7a90, 0xa294, 0x0007, 0x789b, - 0x0060, 0x79a8, 0x81ff, 0x0040, 0x3990, 0x789b, 0x0010, 0x7ba8, - 0xa384, 0x0001, 0x00c0, 0x3983, 0x7ba8, 0x7ba8, 0xa386, 0x0001, - 0x00c0, 0x3976, 0x2009, 0xfff7, 0x0078, 0x397c, 0xa386, 0x0003, - 0x00c0, 0x3983, 0x2009, 0xffef, 0x0c7e, 0x7058, 0x2060, 0x6004, - 0xa104, 0x6006, 0x0c7f, 0x789b, 0x0060, 0x78ab, 0x0000, 0xa684, - 0xfffb, 0x785a, 0x782b, 0x3009, 0x6920, 0xa18c, 0xfcff, 0x6922, - 0x0078, 0x435d, 0x30d9, 0x30e3, 0x399c, 0x39a2, 0x399a, 0x399a, - 0x435d, 0x435d, 0x1078, 0x29b2, 0x6920, 0xa18c, 0xfcff, 0x6922, - 0x0078, 0x4363, 0x6920, 0xa18c, 0xfcff, 0x6922, 0x0078, 0x435d, - 0x79e4, 0xa184, 0x0030, 0x0040, 0x39b2, 0x78ec, 0xa084, 0x0003, - 0x00c0, 0x39e6, 0x7000, 0xa086, 0x0004, 0x00c0, 0x39cc, 0x7064, - 0xa086, 0x0002, 0x00c0, 0x39c2, 0x2011, 0x0002, 0x2019, 0x0000, - 0x0078, 0x2f65, 0x7064, 0xa086, 0x0006, 0x0040, 0x39bc, 0x7064, - 0xa086, 0x0004, 0x0040, 0x39bc, 0x7000, 0xa086, 0x0000, 0x0040, - 0x2a08, 0x6920, 0xa184, 0x0420, 0x0040, 0x39db, 0xc1d4, 0x6922, - 0x6818, 0x0078, 0x3443, 0x6818, 0xa08e, 0x0002, 0x0040, 0x39e4, - 0xc0fd, 0x681a, 0x2001, 0x0014, 0x0078, 0x3443, 0xa184, 0x0007, - 0x0079, 0x39ea, 0x435d, 0x435d, 0x39f2, 0x435d, 0x43a5, 0x43a5, - 0x435d, 0x435d, 0xd6bc, 0x0040, 0x3a34, 0x7184, 0x81ff, 0x0040, - 0x3a34, 0xa182, 0x000d, 0x00d0, 0x3a01, 0x7087, 0x0000, 0x0078, - 0x3a06, 0xa182, 0x000c, 0x7086, 0x2009, 0x000c, 0x789b, 0x0061, - 0x79aa, 0x157e, 0x137e, 0x147e, 0x7088, 0x8114, 0xa210, 0x728a, - 0xa080, 0x000b, 0xad00, 0x2098, 0xb284, 0x0300, 0x0040, 0x3a28, - 0x007e, 0x2001, 0x4f04, 0x2004, 0xd0ec, 0x007f, 0x0040, 0x3a24, - 0x20a1, 0x012b, 0x0078, 0x3a2a, 0x20a1, 0x022b, 0x0078, 0x3a2a, - 0x20a1, 0x012b, 0x789b, 0x0000, 0x8108, 0x81ac, 0x53a6, 0x147f, - 0x137f, 0x157f, 0x0078, 0x4363, 0xd6d4, 0x00c0, 0x3a88, 0x6820, - 0xd084, 0x0040, 0x4363, 0xa68c, 0x0060, 0xa684, 0x0060, 0x0040, - 0x3a46, 0xa086, 0x0060, 0x00c0, 0x3a46, 0xc1f5, 0xc194, 0x795a, - 0x69b6, 0x789b, 0x0060, 0x78ab, 0x0000, 0x789b, 0x0061, 0x6818, - 0xc0fd, 0x681a, 0x78aa, 0x8008, 0x810c, 0x0040, 0x3e4f, 0xa18c, - 0x00f8, 0x00c0, 0x3e4f, 0x157e, 0x137e, 0x147e, 0x017e, 0x3208, - 0xa18c, 0x0300, 0x0040, 0x3a74, 0x007e, 0x2001, 0x4f04, 0x2004, - 0xd0ec, 0x007f, 0x0040, 0x3a70, 0x20a1, 0x012b, 0x0078, 0x3a76, - 0x20a1, 0x022b, 0x0078, 0x3a76, 0x20a1, 0x012b, 0x017f, 0x789b, - 0x0000, 0x8000, 0x80ac, 0xad80, 0x000b, 0x2098, 0x53a6, 0x147f, - 0x137f, 0x157f, 0x6814, 0xc0fc, 0x8007, 0x7882, 0x0078, 0x4363, - 0x6818, 0xd0fc, 0x0040, 0x3a8e, 0x681b, 0x0008, 0x6820, 0xc0ad, - 0x6822, 0x1078, 0x4120, 0x781b, 0x00ea, 0x007c, 0x2300, 0x0079, - 0x3a99, 0x3a9e, 0x3b76, 0x3a9c, 0x1078, 0x29b2, 0x7cd8, 0x7ddc, - 0x7fd0, 0x82ff, 0x00c0, 0x3ac7, 0x7200, 0xa286, 0x0003, 0x0040, - 0x3410, 0x71d4, 0xd1bc, 0x00c0, 0x3aca, 0xd1b4, 0x0040, 0x3aca, - 0x0d7e, 0x783b, 0x8800, 0x781b, 0x004c, 0x70bc, 0xa06d, 0x68b4, - 0xc0a5, 0x785a, 0x6894, 0x78d6, 0x78de, 0x6898, 0x78d2, 0x78da, - 0xc1b4, 0x71d6, 0x7003, 0x0030, 0x0d7f, 0x0078, 0x3ace, 0x7200, - 0x0078, 0x3ace, 0x783b, 0x1800, 0x781b, 0x004a, 0xa284, 0x000f, - 0x0079, 0x3ad2, 0x3b61, 0x3b10, 0x3adc, 0x343f, 0x3ada, 0x3b61, - 0x3ada, 0x3ada, 0x1078, 0x29b2, 0x681c, 0xd0ec, 0x0040, 0x3ae3, - 0x6008, 0xc08d, 0x600a, 0x6920, 0xc185, 0x6922, 0x6800, 0x6006, - 0xa005, 0x00c0, 0x3aec, 0x6002, 0x6008, 0xc0d4, 0x600a, 0x681c, - 0xa084, 0x000e, 0x00c0, 0x3b00, 0xb284, 0x0300, 0x0040, 0x3afc, - 0x2009, 0x95c0, 0x0078, 0x3b05, 0x2009, 0x96d0, 0x0078, 0x3b05, - 0x7030, 0x68ba, 0x7140, 0x70cc, 0xa108, 0x2104, 0x6802, 0x2d0a, - 0x715e, 0xd6dc, 0x00c0, 0x3b10, 0xc6fc, 0x6eb6, 0x0078, 0x3b61, - 0x6eb6, 0xa684, 0x0060, 0x00c0, 0x3b1a, 0xa684, 0x7fff, 0x68b6, - 0x0078, 0x3b61, 0xd6dc, 0x00c0, 0x3b28, 0xa684, 0x7fff, 0x68b6, - 0x6894, 0x68a6, 0x6898, 0x68aa, 0x1078, 0x45d6, 0x0078, 0x3b61, - 0xd6ac, 0x0040, 0x3b34, 0xa006, 0x1078, 0x45d6, 0x2408, 0x2510, - 0x69aa, 0x6aa6, 0x0078, 0x3b44, 0x2408, 0x2510, 0x2700, 0x801b, - 0x00c8, 0x3b3b, 0x8000, 0xa084, 0x003f, 0xa108, 0xa291, 0x0000, - 0x69aa, 0x6aa6, 0x1078, 0x45d6, 0xd6fc, 0x0040, 0x3b61, 0xa684, - 0x7fff, 0x68b6, 0x2510, 0x2408, 0xd6ac, 0x00c0, 0x3b59, 0x2700, - 0x801b, 0x00c8, 0x3b54, 0x8000, 0xa084, 0x003f, 0xa108, 0xa291, - 0x0000, 0x6b98, 0x2100, 0xa302, 0x68b2, 0x6b94, 0x2200, 0xa303, - 0x68ae, 0x7000, 0xa086, 0x0030, 0x00c0, 0x2a0c, 0x7003, 0x0002, - 0x70bc, 0xa06d, 0x68bc, 0x7042, 0x70b8, 0xa065, 0x68c0, 0x705a, - 0x2d00, 0x704e, 0xad80, 0x0009, 0x7046, 0x007c, 0xa586, 0x8800, - 0x00c0, 0x3b83, 0x7003, 0x0000, 0x6018, 0x8001, 0x601a, 0x6008, - 0xa084, 0xfbef, 0x600a, 0x0078, 0x4111, 0x7047, 0x0000, 0xa282, - 0x0006, 0x0050, 0x3b8d, 0x1078, 0x29b2, 0x2300, 0x0079, 0x3b90, - 0x3b93, 0x3ba5, 0x3bb1, 0x2200, 0x0079, 0x3b96, 0x3b9c, 0x4111, - 0x3b9e, 0x3b9c, 0x3beb, 0x3c40, 0x1078, 0x29b2, 0x7a80, 0xa294, - 0x0f00, 0x1078, 0x3cca, 0x0078, 0x4107, 0x1078, 0x3bc2, 0x0079, - 0x3ba9, 0x4111, 0x3baf, 0x3baf, 0x3beb, 0x3baf, 0x4111, 0x1078, - 0x29b2, 0x1078, 0x3bc2, 0x0079, 0x3bb5, 0x3bbd, 0x3bbb, 0x3bbb, - 0x3bbd, 0x3bbb, 0x3bbd, 0x1078, 0x29b2, 0x1078, 0x412b, 0x781b, - 0x0078, 0x007c, 0x7000, 0xa086, 0x0002, 0x00c0, 0x3bd3, 0x1078, - 0x3e36, 0x0078, 0x3bcd, 0x1078, 0x45d6, 0x6008, 0xa084, 0xfbef, - 0x600a, 0x0078, 0x3bd8, 0x7000, 0xa086, 0x0003, 0x0040, 0x3bcb, - 0x7003, 0x0005, 0xb284, 0x0300, 0x0040, 0x3be2, 0x2001, 0x96e0, - 0x0078, 0x3be4, 0x2001, 0x9712, 0x2068, 0x704e, 0xad80, 0x0009, - 0x7046, 0x2200, 0x007c, 0x7000, 0xa086, 0x0002, 0x00c0, 0x3bfd, - 0x70d4, 0xc0b5, 0x70d6, 0x2c00, 0x70ba, 0x2d00, 0x70be, 0x0078, - 0x3c02, 0x1078, 0x45d6, 0x0078, 0x3c02, 0x7000, 0xa086, 0x0003, - 0x0040, 0x3bf9, 0x7003, 0x0001, 0x7a80, 0xa294, 0x0f00, 0x789b, - 0x0018, 0x7ca8, 0xa484, 0x001f, 0xa215, 0x2069, 0x95c0, 0xb284, - 0x0300, 0x00c0, 0x3c16, 0xc2fd, 0x2069, 0x96d0, 0x2d04, 0x2d08, - 0x715e, 0xa06d, 0x0040, 0x3c23, 0x6814, 0xa206, 0x0040, 0x3c25, - 0x6800, 0x0078, 0x3c17, 0x1078, 0x3cca, 0x6eb4, 0x7e5a, 0x6920, - 0xa184, 0x0c00, 0x0040, 0x3cf4, 0x7064, 0xa086, 0x0006, 0x00c0, - 0x3c37, 0x7074, 0xa206, 0x00c0, 0x3c37, 0x7066, 0x707e, 0x681b, - 0x0005, 0xc1ad, 0xc1d4, 0x6922, 0x1078, 0x4120, 0x0078, 0x3cf4, - 0x7200, 0xa286, 0x0002, 0x00c0, 0x3c52, 0x70d4, 0xc0b5, 0x70d6, - 0x2c00, 0x70ba, 0x2d00, 0x70be, 0x0078, 0x3c56, 0x1078, 0x45d6, - 0x0078, 0x3c56, 0xa286, 0x0003, 0x0040, 0x3c4e, 0x7003, 0x0001, - 0x7a80, 0xa294, 0x0f00, 0x789b, 0x0018, 0x7ca8, 0xa484, 0x001f, - 0xa215, 0xb284, 0x0300, 0x00c0, 0x3c66, 0xc2fd, 0x79a8, 0x79a8, - 0xa18c, 0x00ff, 0x2118, 0x70cc, 0xa168, 0x2d04, 0x2d08, 0x715e, - 0xa06d, 0x0040, 0x3c7a, 0x6814, 0xa206, 0x0040, 0x3ca3, 0x6800, - 0x0078, 0x3c6e, 0x7003, 0x0005, 0xb284, 0x0300, 0x0040, 0x3c84, - 0x2001, 0x96e0, 0x0078, 0x3c86, 0x2001, 0x9712, 0x2068, 0x704e, - 0x157e, 0x20a9, 0x0032, 0x2003, 0x0000, 0x8000, 0x00f0, 0x3c8b, - 0x157f, 0xb284, 0x0300, 0x0040, 0x3c98, 0xc2fc, 0x0078, 0x3c99, - 0xc2fd, 0x6a16, 0xad80, 0x0009, 0x7046, 0x68b7, 0x0700, 0x6823, - 0x0800, 0x6827, 0x0003, 0x6eb4, 0x6920, 0xa184, 0x0c00, 0x0040, - 0x3cf4, 0xd0dc, 0x0040, 0x3cbf, 0x7064, 0xa086, 0x0004, 0x00c0, - 0x3cbb, 0x7074, 0xa206, 0x00c0, 0x3cbb, 0x7078, 0xa306, 0x00c0, - 0x3cbb, 0x7066, 0x707e, 0x1078, 0x4127, 0x0078, 0x3cf4, 0x681b, - 0x0005, 0xc1ad, 0xc1d4, 0x6922, 0x1078, 0x4120, 0x707f, 0x0000, - 0x0078, 0x3cf4, 0x7003, 0x0005, 0xb284, 0x0300, 0x0040, 0x3cd4, - 0x2001, 0x96e0, 0x0078, 0x3cd6, 0x2001, 0x9712, 0x2068, 0x704e, - 0x157e, 0x20a9, 0x0032, 0x2003, 0x0000, 0x8000, 0x00f0, 0x3cdb, - 0x157f, 0xb284, 0x0300, 0x0040, 0x3ce8, 0xc2fc, 0x0078, 0x3ce9, - 0xc2fd, 0x6a16, 0xad80, 0x0009, 0x7046, 0x68b7, 0x0700, 0x6823, - 0x0800, 0x6827, 0x0003, 0x007c, 0xc6ec, 0xa6ac, 0x0060, 0x0040, - 0x3d46, 0x6b98, 0x6c94, 0x69ac, 0x68b0, 0xa105, 0x00c0, 0x3d21, - 0x7bd2, 0x7bda, 0x7cd6, 0x7cde, 0xa586, 0x0060, 0x0040, 0x3d4b, - 0xd6f4, 0x00c0, 0x3d0c, 0xc6ed, 0xa6b4, 0xb7ff, 0x7e5a, 0x2009, - 0x0079, 0xd69c, 0x0040, 0x3d19, 0x2009, 0x0078, 0x2019, 0x0000, - 0x2320, 0x791a, 0xd6ec, 0x0040, 0x3d56, 0x1078, 0x493f, 0x0078, - 0x3d56, 0x68b0, 0xa31a, 0x2100, 0xa423, 0x2400, 0xa305, 0x0040, - 0x3d4d, 0x7bd2, 0x7bda, 0x7cd6, 0x7cde, 0x68b0, 0xd6f4, 0x00c0, - 0x3d32, 0xc6ed, 0xc6f4, 0x7e5a, 0x2011, 0x0079, 0xd69c, 0x0040, - 0x3d3e, 0x2011, 0x0078, 0x2019, 0x0000, 0x2320, 0x7a1a, 0xd6ec, - 0x0040, 0x3d56, 0x1078, 0x4977, 0x0078, 0x3d56, 0x2019, 0x0000, - 0x2320, 0x0078, 0x3d4d, 0xa6b4, 0xb7ff, 0x7e5a, 0x2009, 0x0079, - 0xd69c, 0x0040, 0x3d55, 0x2009, 0x0078, 0x791a, 0x68c0, 0x705a, - 0x2d00, 0x704e, 0x68c4, 0x2060, 0x71d4, 0x2001, 0x4f01, 0x2004, - 0xd0c4, 0x00c0, 0x3dab, 0x70d8, 0xa02d, 0x0040, 0x3d84, 0xd1bc, - 0x0040, 0x3d9e, 0x7a80, 0xa294, 0x0f00, 0x70dc, 0xa206, 0x0040, - 0x3d75, 0x78e0, 0xa504, 0x00c0, 0x3dab, 0x70da, 0xc1bc, 0x71d6, - 0x0078, 0x3dab, 0x2031, 0x0001, 0x852c, 0x0048, 0x3d83, 0x8633, - 0x8210, 0x0078, 0x3d7c, 0x007c, 0x7de0, 0xa594, 0xff00, 0x0040, - 0x3d91, 0x2011, 0x0008, 0x852f, 0x1078, 0x3d7a, 0x8637, 0x0078, - 0x3d93, 0x1078, 0x3d7a, 0x8217, 0x7880, 0xa084, 0x0f00, 0xa206, - 0x0040, 0x3dab, 0x72de, 0x76da, 0x0078, 0x3dab, 0x7a80, 0xa294, - 0x0f00, 0x70dc, 0xa236, 0x0040, 0x3d9b, 0x78e0, 0xa534, 0x0040, - 0x3d9b, 0xc1bd, 0x71d6, 0xd1b4, 0x00c0, 0x2a08, 0x2300, 0xa405, - 0x0040, 0x2a08, 0x70a4, 0xa086, 0x0001, 0x00c0, 0x2a52, 0x007c, - 0x6020, 0xa005, 0x0040, 0x3dc6, 0x8001, 0x6022, 0x6008, 0xa085, - 0x0008, 0x600a, 0x700f, 0x0100, 0x702c, 0x6026, 0x007c, 0xa006, - 0x1078, 0x45d6, 0x7000, 0xa086, 0x0002, 0x0040, 0x3dd4, 0x7064, - 0xa086, 0x0005, 0x00c0, 0x3dde, 0x682b, 0x0000, 0x6817, 0x0000, - 0x681b, 0x0001, 0x6823, 0x0040, 0x681f, 0x0100, 0x7000, 0xa084, - 0x000f, 0x0079, 0x3de3, 0x2a0c, 0x3df3, 0x3ded, 0x3e15, 0x3dfd, - 0x2a0c, 0x3deb, 0x3deb, 0x1078, 0x29b2, 0x1078, 0x3e20, 0x1078, - 0x3e19, 0x0078, 0x3df9, 0x1078, 0x3e20, 0x705c, 0x2060, 0x6800, - 0x6002, 0x1078, 0x2073, 0x0078, 0x2a0c, 0x7064, 0x7067, 0x0000, - 0x7083, 0x0000, 0x0079, 0x3e04, 0x3e11, 0x3e11, 0x3e0c, 0x3e0c, - 0x3e0c, 0x3e11, 0x3e0c, 0x3e11, 0x77d4, 0xc7dd, 0x77d6, 0x0079, - 0x2f7e, 0x7067, 0x0000, 0x0078, 0x2a0c, 0x681b, 0x0000, 0x0078, - 0x3711, 0x6800, 0xa005, 0x00c0, 0x3e1e, 0x6002, 0x6006, 0x007c, - 0x6410, 0x84ff, 0x0040, 0x3e32, 0x2009, 0x4f02, 0x2104, 0x8001, - 0x200a, 0x8421, 0x6412, 0x00c0, 0x3e32, 0x2021, 0x4f04, 0x2404, - 0xc0a5, 0x2022, 0x6008, 0xc0a4, 0x600a, 0x007c, 0x6018, 0xa005, - 0x0040, 0x3e3c, 0x8001, 0x601a, 0x007c, 0x1078, 0x43d3, 0x681b, - 0x0018, 0x0078, 0x3e7d, 0x1078, 0x43d3, 0x681b, 0x0019, 0x0078, - 0x3e7d, 0x1078, 0x43d3, 0x681b, 0x001a, 0x0078, 0x3e7d, 0x1078, - 0x43d3, 0x681b, 0x0003, 0x0078, 0x3e7d, 0x7774, 0x1078, 0x424e, - 0x7178, 0xa18c, 0x00ff, 0x3210, 0xa294, 0x0300, 0x0040, 0x3e64, - 0xa1e8, 0x94c0, 0x0078, 0x3e66, 0xa1e8, 0x95d0, 0x2d04, 0x2d08, - 0x2068, 0xa005, 0x00c0, 0x3e6f, 0x707e, 0x0078, 0x2a0c, 0x6814, - 0x7274, 0xa206, 0x0040, 0x3e77, 0x6800, 0x0078, 0x3e67, 0x6800, - 0x200a, 0x681b, 0x0005, 0x707f, 0x0000, 0x1078, 0x3e20, 0x6820, - 0xd084, 0x00c0, 0x3e85, 0x1078, 0x3e19, 0x1078, 0x3e36, 0x681f, - 0x0000, 0x6823, 0x0020, 0x1078, 0x2073, 0x0078, 0x2a0c, 0xa282, - 0x0003, 0x00c0, 0x4107, 0x7da8, 0xa5ac, 0x00ff, 0x7e5a, 0x7ea8, - 0xa6b4, 0x00ff, 0x6920, 0xc1bd, 0x6922, 0xd1c4, 0x0040, 0x3eea, - 0xc1c4, 0x6922, 0xa6b4, 0x00ff, 0x0040, 0x3ed7, 0xa682, 0x000c, - 0x0048, 0x3eae, 0x0040, 0x3eae, 0x2031, 0x000c, 0x2500, 0xa086, - 0x000a, 0x0040, 0x3eb5, 0x852b, 0x852b, 0x1078, 0x41e0, 0x0040, - 0x3ebd, 0x1078, 0x3fbc, 0x0078, 0x3ee0, 0x1078, 0x419b, 0x0c7e, - 0x2960, 0x6004, 0xa084, 0xfff5, 0x6006, 0x1078, 0x3ff2, 0x0c7f, - 0x6920, 0xc1c5, 0x6922, 0x7e58, 0xc695, 0x7e5a, 0xd6d4, 0x00c0, - 0x3ed4, 0x781b, 0x0064, 0x007c, 0x781b, 0x0078, 0x007c, 0x0c7e, - 0x2960, 0x6004, 0xa084, 0xfff5, 0x6006, 0x1078, 0x3ff2, 0x0c7f, - 0x7e58, 0xd6d4, 0x00c0, 0x3ee7, 0x781b, 0x0067, 0x007c, 0x781b, - 0x0079, 0x007c, 0x0c7e, 0x7058, 0x2060, 0x6100, 0xd1e4, 0x0040, - 0x3f33, 0x6208, 0x8217, 0xa294, 0x00ff, 0xa282, 0x000c, 0x0048, - 0x3efd, 0x0040, 0x3efd, 0x2011, 0x000c, 0x2600, 0xa202, 0x00c8, - 0x3f02, 0x2230, 0x6208, 0xa294, 0x00ff, 0x2001, 0x4f05, 0x2004, - 0xd0e4, 0x00c0, 0x3f17, 0x78ec, 0xd0e4, 0x0040, 0x3f17, 0xa282, - 0x000a, 0x00c8, 0x3f1d, 0x2011, 0x000a, 0x0078, 0x3f1d, 0xa282, - 0x000c, 0x00c8, 0x3f1d, 0x2011, 0x000c, 0x2200, 0xa502, 0x00c8, - 0x3f22, 0x2228, 0x1078, 0x419f, 0x2500, 0xa086, 0x000a, 0x0040, - 0x3f2b, 0x852b, 0x852b, 0x1078, 0x41e0, 0x0040, 0x3f33, 0x1078, - 0x3fbc, 0x0078, 0x3f37, 0x1078, 0x419b, 0x1078, 0x3ff2, 0x7858, - 0xc095, 0x785a, 0x0c7f, 0x781b, 0x0078, 0x007c, 0x0c7e, 0x2960, - 0x6000, 0xd0e4, 0x00c0, 0x3f58, 0xd0b4, 0x00c0, 0x3f52, 0x6010, - 0xa084, 0x000f, 0x00c0, 0x3f52, 0x6104, 0xa18c, 0xfff5, 0x6106, - 0x0c7f, 0x007c, 0x2011, 0x0032, 0x2019, 0x0000, 0x0078, 0x3f83, - 0x68a0, 0xd0cc, 0x00c0, 0x3f52, 0x6208, 0xa294, 0x00ff, 0x2001, - 0x4f05, 0x2004, 0xd0e4, 0x00c0, 0x3f71, 0x78ec, 0xd0e4, 0x0040, - 0x3f71, 0xa282, 0x000b, 0x00c8, 0x3f71, 0x2011, 0x000a, 0x0078, - 0x3f77, 0xa282, 0x000c, 0x00c8, 0x3f77, 0x2011, 0x000c, 0x6308, - 0x831f, 0xa39c, 0x00ff, 0xa382, 0x000c, 0x0048, 0x3f83, 0x0040, - 0x3f83, 0x2019, 0x000c, 0x78ab, 0x0001, 0x78ab, 0x0003, 0x78ab, - 0x0001, 0x7aaa, 0x7baa, 0xa8c0, 0x0005, 0x6820, 0xc0c5, 0x6822, - 0x70d4, 0xd0b4, 0x0040, 0x3f9f, 0xc0b4, 0x70d6, 0x70b8, 0xa065, - 0x6008, 0xa084, 0xfbef, 0x600a, 0x6018, 0x8001, 0x601a, 0x0c7f, - 0x007c, 0x0c7e, 0x2960, 0x6104, 0xa18c, 0xfff5, 0x6106, 0x2011, - 0x0032, 0x2019, 0x0000, 0x0078, 0x3fad, 0x78ab, 0x0001, 0x78ab, - 0x0003, 0x78ab, 0x0001, 0x7aaa, 0x7baa, 0xa8c0, 0x0005, 0x6820, - 0xc0c5, 0x6822, 0x0c7f, 0x007c, 0x0c7e, 0x7158, 0x2160, 0x2018, - 0xa08c, 0x0020, 0x0040, 0x3fc5, 0xc0ac, 0x2008, 0xa084, 0xfff0, - 0xa635, 0x7e86, 0x6018, 0x789a, 0x7eae, 0x6612, 0x78a4, 0xa084, - 0xfff0, 0xa18c, 0x000f, 0xa105, 0xc0f4, 0xa39c, 0x0020, 0x0040, - 0x3fdb, 0xa085, 0x4000, 0xc0fc, 0xd0b4, 0x00c0, 0x3fe0, 0xc0fd, - 0x78a6, 0x6016, 0x788a, 0xa6b4, 0x000f, 0x8637, 0x8204, 0x8004, - 0xa084, 0x00ff, 0xa605, 0x600e, 0x6004, 0xa084, 0xfff5, 0x6006, - 0x0c7f, 0x007c, 0x0c7e, 0x7058, 0x2060, 0x6018, 0x789a, 0x78a4, - 0xa084, 0xfff0, 0x78a6, 0x6012, 0x7884, 0xa084, 0xfff0, 0x7886, - 0x600c, 0xa084, 0x00ff, 0x600e, 0x0c7f, 0x007c, 0xa282, 0x0002, - 0x00c0, 0x4107, 0x7aa8, 0x6920, 0xc1bd, 0x6922, 0xd1cc, 0x0040, - 0x4041, 0xc1cc, 0x6922, 0xa294, 0x00ff, 0xa282, 0x0002, 0x00c8, - 0x4107, 0x1078, 0x4094, 0x1078, 0x3ff2, 0xa980, 0x0001, 0x200c, - 0x1078, 0x424a, 0x1078, 0x3f3e, 0x88ff, 0x0040, 0x4037, 0x789b, - 0x0060, 0x2800, 0x78aa, 0x7e58, 0xc695, 0x7e5a, 0xd6d4, 0x00c0, - 0x4034, 0x781b, 0x0064, 0x007c, 0x781b, 0x0078, 0x007c, 0x7e58, - 0xd6d4, 0x00c0, 0x403e, 0x781b, 0x0067, 0x007c, 0x781b, 0x0079, - 0x007c, 0xa282, 0x0002, 0x00c8, 0x4049, 0xa284, 0x0001, 0x0040, - 0x4052, 0x7158, 0xa188, 0x0000, 0x210c, 0xd1ec, 0x00c0, 0x4052, - 0x2011, 0x0000, 0x1078, 0x417c, 0x1078, 0x4094, 0x1078, 0x3ff2, - 0x7858, 0xc095, 0x785a, 0x781b, 0x0078, 0x007c, 0x0c7e, 0x027e, - 0x2960, 0x6000, 0x2011, 0x0001, 0xd0ec, 0x00c0, 0x4075, 0xd0bc, - 0x00c0, 0x4073, 0x6014, 0xd0b4, 0x00c0, 0x4073, 0xc1a4, 0x6106, - 0xa006, 0x0078, 0x4091, 0x2011, 0x0000, 0x78ab, 0x0001, 0x78ab, - 0x0002, 0x78ab, 0x0003, 0x7aaa, 0xa8c0, 0x0004, 0x70d4, 0xd0b4, - 0x0040, 0x408d, 0xc0b4, 0x70d6, 0x70b8, 0xa065, 0x6008, 0xa084, - 0xfbef, 0x600a, 0x6018, 0x8001, 0x601a, 0x6820, 0xa085, 0x0200, - 0x6822, 0x027f, 0x0c7f, 0x007c, 0x0c7e, 0x7058, 0x2060, 0x82ff, - 0x0040, 0x409c, 0x2011, 0x0040, 0x6018, 0xa080, 0x0002, 0x789a, - 0x78a4, 0xa084, 0xffbf, 0xa205, 0xc0fc, 0xd0b4, 0x00c0, 0x40a9, - 0xc0fd, 0x78a6, 0x6016, 0x788a, 0x6004, 0xc0a4, 0x6006, 0x0c7f, - 0x007c, 0x007e, 0x7000, 0xa086, 0x0003, 0x0040, 0x40ba, 0x007f, - 0x0078, 0x40bd, 0x007f, 0x0078, 0x4104, 0xd6ac, 0x0040, 0x4104, - 0x7888, 0xa084, 0x0040, 0x0040, 0x4104, 0x7bb8, 0xa384, 0x003f, - 0x831b, 0x00c8, 0x40cc, 0x8000, 0xa005, 0x0040, 0x40e1, 0x831b, - 0x00c8, 0x40d5, 0x8001, 0x0040, 0x4101, 0xd6f4, 0x0040, 0x40e1, - 0x78b8, 0x801b, 0x00c8, 0x40dd, 0x8000, 0xa084, 0x003f, 0x00c0, - 0x4101, 0xc6f4, 0x7e5a, 0x79d8, 0x7adc, 0x2001, 0x0001, 0xa108, - 0x00c8, 0x40ec, 0xa291, 0x0000, 0x79d2, 0x79da, 0x7ad6, 0x7ade, - 0x1078, 0x4a44, 0x781b, 0x0076, 0xb284, 0x0300, 0x0040, 0x40fc, - 0x2001, 0x0000, 0x0078, 0x40fe, 0x2001, 0x0001, 0x1078, 0x48ce, - 0x007c, 0x781b, 0x0076, 0x007c, 0x781b, 0x0079, 0x007c, 0x1078, - 0x412f, 0x781b, 0x0078, 0x007c, 0x1078, 0x4118, 0x781b, 0x0078, - 0x007c, 0x6827, 0x0002, 0x1078, 0x4120, 0x781b, 0x0078, 0x007c, - 0x2001, 0x0005, 0x0078, 0x4131, 0x2001, 0x000c, 0x0078, 0x4131, - 0x6820, 0xc0d5, 0x6822, 0x2001, 0x0006, 0x0078, 0x4131, 0x2001, - 0x000d, 0x0078, 0x4131, 0x2001, 0x0009, 0x0078, 0x4131, 0x2001, - 0x0007, 0x789b, 0x007e, 0x78aa, 0xc69d, 0x7e5a, 0x70d4, 0xd0b4, - 0x0040, 0x4147, 0xc0b4, 0x70d6, 0x0c7e, 0x70b8, 0xa065, 0x6008, - 0xa084, 0xfbef, 0x600a, 0x6018, 0x8001, 0x601a, 0x0c7f, 0x007c, - 0x077e, 0x873f, 0xa7bc, 0x000f, 0x873b, 0x873b, 0x8703, 0x017e, - 0xb28c, 0x0300, 0x0040, 0x4158, 0xa0e0, 0x53c0, 0x0078, 0x415a, - 0xa0e0, 0x5440, 0x017f, 0xa7b8, 0x0020, 0x7f9a, 0x79a4, 0xa184, - 0x000f, 0x0040, 0x416a, 0xa184, 0xfff0, 0x78a6, 0x6012, 0x6004, - 0xc09d, 0x6006, 0x8738, 0x8738, 0x7f9a, 0x79a4, 0xa184, 0x0040, - 0x0040, 0x417a, 0xa184, 0xffbf, 0xc0fd, 0x78a6, 0x6016, 0x6004, - 0xc0a5, 0x6006, 0x077f, 0x007c, 0x789b, 0x0010, 0x78ab, 0x0001, - 0x78ab, 0x0002, 0x78ab, 0x0003, 0x7aaa, 0x789b, 0x0060, 0x78ab, - 0x0004, 0x70d4, 0xd0b4, 0x0040, 0x419a, 0xc0b4, 0x70d6, 0x0c7e, - 0x70b8, 0xa065, 0x6008, 0xa084, 0xfbef, 0x600a, 0x6018, 0x8001, - 0x601a, 0x0c7f, 0x007c, 0x2031, 0x0000, 0x2029, 0x0032, 0x789b, - 0x0010, 0x78ab, 0x0001, 0x78ab, 0x0003, 0x78ab, 0x0001, 0x7daa, - 0x7eaa, 0x789b, 0x0060, 0x78ab, 0x0005, 0x70d4, 0xd0b4, 0x0040, - 0x41be, 0xc0b4, 0x70d6, 0x0c7e, 0x70b8, 0xa065, 0x6008, 0xa084, - 0xfbef, 0x600a, 0x6018, 0x8001, 0x601a, 0x0c7f, 0x007c, 0x157e, - 0x8007, 0xa084, 0x00ff, 0x8003, 0x8003, 0xa080, 0x0020, 0x789a, - 0x79a4, 0xa18c, 0xfff0, 0x2021, 0x4233, 0x2019, 0x0011, 0x20a9, - 0x000e, 0x2011, 0x0032, 0x2404, 0xa084, 0xfff0, 0xa106, 0x0040, - 0x41de, 0x8420, 0x2300, 0xa210, 0x00f0, 0x41d3, 0x157f, 0x007c, - 0x157e, 0x2001, 0x4f05, 0x2004, 0xd0e4, 0x00c0, 0x4211, 0x2021, - 0x4241, 0x20a9, 0x0009, 0x2011, 0x0028, 0xa582, 0x0019, 0x0040, - 0x4227, 0x0048, 0x4227, 0x8420, 0x95a9, 0x2011, 0x0032, 0xa582, - 0x0032, 0x0040, 0x4227, 0x0048, 0x4227, 0x8420, 0x95a9, 0x2019, - 0x000a, 0x2011, 0x0064, 0x2200, 0xa502, 0x0040, 0x4227, 0x0048, - 0x4227, 0x8420, 0x2300, 0xa210, 0x00f0, 0x4203, 0x157f, 0x0078, - 0x4225, 0x2021, 0x4233, 0x2019, 0x0011, 0x20a9, 0x000e, 0x2011, - 0x0032, 0x2200, 0xa502, 0x0040, 0x4227, 0x0048, 0x4227, 0x8420, - 0x2300, 0xa210, 0x00f0, 0x4219, 0x157f, 0xa006, 0x007c, 0x157f, - 0xa582, 0x0064, 0x00c8, 0x4230, 0x7808, 0xa085, 0x0070, 0x780a, - 0x2404, 0xa005, 0x007c, 0x1209, 0x3002, 0x3202, 0x4203, 0x4403, - 0x5404, 0x5604, 0x6605, 0x6805, 0x7806, 0x7a06, 0x0c07, 0x0c07, - 0x0e07, 0x10e1, 0x330a, 0x5805, 0x5a05, 0x6a06, 0x6c06, 0x7c07, - 0x7e07, 0x0e00, 0x789b, 0x0010, 0xa046, 0x007c, 0xa784, 0x0f00, - 0x800b, 0xa784, 0x001f, 0x8003, 0x8003, 0x8003, 0x8003, 0xa105, - 0xd7fc, 0x0040, 0x425f, 0xa0e0, 0x74c0, 0x0078, 0x4261, 0xa0e0, - 0x54c0, 0x007c, 0x0e7e, 0x0f7e, 0xd084, 0x0040, 0x426f, 0x2079, - 0x0100, 0x2009, 0x4f80, 0x2071, 0x4f80, 0x0078, 0x427f, 0x2009, - 0x4f40, 0x2071, 0x4f40, 0x2001, 0x4f04, 0x2004, 0xd0ec, 0x0040, - 0x427d, 0x2079, 0x0100, 0x0078, 0x427f, 0x2079, 0x0200, 0x2091, - 0x8000, 0x2104, 0xa084, 0x000f, 0x0079, 0x4286, 0x4290, 0x4290, - 0x4290, 0x4290, 0x4290, 0x4290, 0x428e, 0x428e, 0x1078, 0x29b2, - 0x69b4, 0xc1f5, 0xa18c, 0xff9f, 0x69b6, 0xa005, 0x0040, 0x42df, - 0x7858, 0xa084, 0xff9f, 0xa085, 0x6000, 0x785a, 0x7828, 0xa086, - 0x1814, 0x00c0, 0x42df, 0x784b, 0x0004, 0x7848, 0xa084, 0x0004, - 0x00c0, 0x42a5, 0x784b, 0x0008, 0x7848, 0xa084, 0x0008, 0x00c0, - 0x42ac, 0x7830, 0xd0bc, 0x00c0, 0x42df, 0x007e, 0x2001, 0x4f04, - 0x2004, 0xd0ec, 0x007f, 0x0040, 0x42c1, 0xb284, 0x0300, 0x0078, - 0x42c3, 0xb284, 0x0400, 0x0040, 0x42c9, 0x0018, 0x42df, 0x0078, - 0x42cb, 0x0028, 0x42df, 0x79e4, 0xa184, 0x0030, 0x0040, 0x42df, - 0x78ec, 0xa084, 0x0003, 0x0040, 0x42df, 0x681c, 0xd0ac, 0x00c0, - 0x42dd, 0x1078, 0x4369, 0x0078, 0x42df, 0x781b, 0x00f9, 0x0f7f, - 0x0e7f, 0x007c, 0x0c7e, 0x2001, 0x4f01, 0x2004, 0xd0ac, 0x00c0, - 0x435b, 0x6814, 0x8007, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, - 0xb28c, 0x0300, 0x0040, 0x42f8, 0xa0e0, 0x53c0, 0x0078, 0x42fa, - 0xa0e0, 0x5440, 0x6004, 0xa084, 0x000a, 0x00c0, 0x435b, 0x6108, - 0xa194, 0xff00, 0x0040, 0x435b, 0xa18c, 0x00ff, 0x2001, 0x000a, - 0xa106, 0x0040, 0x4326, 0x2001, 0x000c, 0xa106, 0x0040, 0x432a, - 0x2001, 0x0012, 0xa106, 0x0040, 0x432e, 0x2001, 0x0014, 0xa106, - 0x0040, 0x4332, 0x2001, 0x0019, 0xa106, 0x0040, 0x4336, 0x2001, - 0x0032, 0xa106, 0x0040, 0x433a, 0x0078, 0x433e, 0x2009, 0x000c, - 0x0078, 0x4340, 0x2009, 0x0012, 0x0078, 0x4340, 0x2009, 0x0014, - 0x0078, 0x4340, 0x2009, 0x0019, 0x0078, 0x4340, 0x2009, 0x0020, - 0x0078, 0x4340, 0x2009, 0x003f, 0x0078, 0x4340, 0x2011, 0x0000, - 0x2100, 0xa205, 0x600a, 0x6004, 0xa085, 0x0002, 0x6006, 0x2061, - 0x4f00, 0x6004, 0xd0bc, 0x0040, 0x435b, 0x6814, 0xd0fc, 0x00c0, - 0x4356, 0x60ea, 0x2061, 0x4f40, 0x0078, 0x4359, 0x60ee, 0x2061, - 0x4f80, 0x601f, 0x800f, 0x0c7f, 0x007c, 0x781b, 0x0079, 0x007c, - 0x781b, 0x0078, 0x007c, 0x781b, 0x0067, 0x007c, 0x781b, 0x0064, - 0x007c, 0x2009, 0x4f19, 0x210c, 0xa186, 0x0000, 0x0040, 0x437b, - 0xa186, 0x0001, 0x0040, 0x437e, 0x701f, 0x000b, 0x7067, 0x0001, - 0x781b, 0x0047, 0x007c, 0x781b, 0x00f0, 0x007c, 0x701f, 0x000a, - 0x007c, 0x2009, 0x4f19, 0x210c, 0xa186, 0x0000, 0x0040, 0x4396, - 0xa186, 0x0001, 0x0040, 0x4393, 0x701f, 0x000b, 0x7067, 0x0001, - 0x781b, 0x0047, 0x007c, 0x701f, 0x000a, 0x007c, 0x781b, 0x00ef, - 0x007c, 0x781b, 0x00f9, 0x007c, 0x781b, 0x00f8, 0x007c, 0x781b, - 0x00c9, 0x007c, 0x781b, 0x00c8, 0x007c, 0x6818, 0xd0fc, 0x0040, - 0x43ab, 0x681b, 0x001d, 0x7067, 0x0001, 0x781b, 0x0047, 0x007c, - 0x7830, 0xa084, 0x00c0, 0x00c0, 0x43d2, 0x7808, 0xc08c, 0x780a, - 0x0005, 0x0005, 0x0005, 0x0005, 0x78ec, 0xa084, 0x0021, 0x00c0, - 0x43cf, 0x2001, 0x4f05, 0x2004, 0xd0e4, 0x00c0, 0x43cd, 0x7804, - 0xa084, 0xff1f, 0xa085, 0x00e0, 0x7806, 0xa006, 0x007c, 0x7808, - 0xc08d, 0x780a, 0x007c, 0x7808, 0xc08d, 0x780a, 0x007c, 0x7830, - 0xa084, 0x0040, 0x00c0, 0x43d7, 0x2001, 0x4f04, 0x2004, 0xd0ec, - 0x0040, 0x43e6, 0xb284, 0x0300, 0x0078, 0x43e8, 0xb284, 0x0400, - 0x0040, 0x43ee, 0x0098, 0x43f2, 0x0078, 0x43f0, 0x00a8, 0x43f2, - 0x78ac, 0x007c, 0x7808, 0xa084, 0xfffd, 0x780a, 0x0005, 0x0005, - 0x0005, 0x0005, 0x78ec, 0xa084, 0x0021, 0x0040, 0x4415, 0x007e, - 0x2001, 0x4f04, 0x2004, 0xd0ec, 0x007f, 0x0040, 0x440b, 0xb284, - 0x0300, 0x0078, 0x440d, 0xb284, 0x0400, 0x0040, 0x4413, 0x0098, - 0x440f, 0x0078, 0x4415, 0x00a8, 0x4413, 0x78ac, 0x007e, 0x7808, - 0xa085, 0x0002, 0x780a, 0x007f, 0x007c, 0xa784, 0x0001, 0x00c0, - 0x37b9, 0xa784, 0x0070, 0x0040, 0x442d, 0x0c7e, 0x2d60, 0x2f68, - 0x1078, 0x2926, 0x2d78, 0x2c68, 0x0c7f, 0xa784, 0x0008, 0x0040, - 0x443a, 0x784b, 0x0008, 0x78ec, 0xa084, 0x0003, 0x0040, 0x37b9, - 0x0078, 0x435d, 0xa784, 0x0004, 0x0040, 0x4469, 0x78b8, 0xa084, - 0x4001, 0x0040, 0x4469, 0x784b, 0x0008, 0x78ec, 0xa084, 0x0003, - 0x0040, 0x37b9, 0x78e4, 0xa084, 0x0007, 0xa086, 0x0001, 0x00c0, - 0x4469, 0x78c0, 0xa685, 0x4800, 0x2030, 0x7e5a, 0x781b, 0x00f9, - 0x007c, 0x784b, 0x0008, 0x6818, 0xd0fc, 0x0040, 0x4466, 0x681b, - 0x0015, 0xd6f4, 0x0040, 0x4466, 0x681b, 0x0007, 0x1078, 0x4369, - 0x007c, 0x681b, 0x0003, 0x7858, 0xa084, 0x3f00, 0x681e, 0x682f, - 0x0000, 0x6833, 0x0000, 0x784b, 0x0008, 0x78ec, 0xa084, 0x0003, - 0x0040, 0x30af, 0x007e, 0x2001, 0x4f04, 0x2004, 0xd0ec, 0x007f, - 0x0040, 0x4486, 0xb284, 0x0300, 0x0078, 0x4488, 0xb284, 0x0400, - 0x0040, 0x448e, 0x0018, 0x2a08, 0x0078, 0x4490, 0x0028, 0x2a08, - 0x0078, 0x410c, 0x6b14, 0x8307, 0xa084, 0x000f, 0x8003, 0x8003, - 0x8003, 0xd3fc, 0x0040, 0x44a0, 0xa080, 0x5440, 0x0078, 0x44a2, - 0xa080, 0x53c0, 0x2060, 0x2048, 0x705a, 0x2a60, 0x007c, 0x0020, - 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, - 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, - 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, - 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, - 0x0020, 0x0062, 0x0009, 0x0014, 0x0014, 0x9848, 0x0014, 0x0014, - 0x9914, 0x98fd, 0x0014, 0x0014, 0x0080, 0x00ff, 0x0100, 0x0402, - 0x2008, 0xf880, 0x0018, 0xa20a, 0x0014, 0x300b, 0xa20c, 0x0014, - 0x2500, 0x0013, 0x2500, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, - 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, - 0x0010, 0xa200, 0x3806, 0x7102, 0x805f, 0x9481, 0x8839, 0x20c4, - 0x0864, 0xa856, 0x3008, 0x28c1, 0x9d1b, 0xa201, 0x300c, 0x2847, - 0x8161, 0x846a, 0x8000, 0x84a4, 0x1856, 0x883a, 0xa808, 0x28e2, - 0x9ccb, 0xa8f3, 0x0864, 0xa844, 0x300c, 0xa801, 0x3008, 0x28e1, - 0x9ccb, 0x2021, 0xa81d, 0xa205, 0x870c, 0xd8de, 0x64a0, 0x6de0, - 0x6fc0, 0x63a4, 0x6c80, 0x0212, 0xa205, 0x883d, 0x7942, 0x8020, - 0xa4a1, 0x882b, 0x1814, 0x883b, 0x80df, 0x94a1, 0x7027, 0x85f2, - 0xa737, 0xa532, 0xf003, 0x8576, 0x8677, 0xa816, 0x883e, 0xa814, - 0x2001, 0xa812, 0xa204, 0x64c0, 0x6de0, 0x67a0, 0x6fc0, 0x7942, - 0x8020, 0xa4a1, 0x1814, 0x80df, 0x94a1, 0x883b, 0x7023, 0x8576, - 0x8677, 0xa802, 0x7861, 0x883e, 0x206b, 0x28c1, 0x9d1b, 0x2044, - 0x2103, 0x20a2, 0x2081, 0xa8c3, 0xa207, 0x0904, 0xa20e, 0xa809, - 0xa203, 0x8000, 0x85a4, 0x1872, 0x879a, 0x883c, 0x1fe2, 0xf601, - 0xa208, 0x856e, 0x866f, 0x7161, 0x0014, 0x0704, 0x3008, 0x9ccb, - 0x0014, 0xa202, 0x8000, 0x85a4, 0x3009, 0x84a8, 0x19e2, 0xf844, - 0x856e, 0x883f, 0x08e6, 0xa8f5, 0xf861, 0xa8ea, 0xf801, 0x0014, - 0xf881, 0x0016, 0x85b2, 0x80f0, 0x9532, 0xfaa2, 0x1de2, 0x0014, - 0x8532, 0xf221, 0x0014, 0x1de2, 0x84a8, 0xd6e0, 0x1fe6, 0x0014, - 0x3008, 0x8000, 0x284a, 0x1011, 0xa8fc, 0x3008, 0x9d33, 0x8000, - 0xa000, 0x2802, 0x1011, 0xa8fd, 0x9d39, 0xa8bd, 0x3008, 0x9d33, - 0x283b, 0x1011, 0xa8fd, 0xa209, 0x7102, 0x805f, 0x9481, 0x0017, - 0x300c, 0xa209, 0x8000, 0x85a4, 0x1de2, 0xa209, 0xdac1, 0x0014, - 0x0210, 0xa801, 0x0014, 0x26e0, 0x873a, 0xfaa3, 0x19f2, 0x26e0, - 0x18f2, 0x0014, 0xa20b, 0x0014, 0xa20d, 0x3806, 0x0210, 0x9d25, - 0x0704, 0xa206, 0x6865, 0x817e, 0x842a, 0x1dc1, 0x8823, 0x0016, - 0x6042, 0x8008, 0xa8fa, 0x8000, 0x84a4, 0x8160, 0x842a, 0xf021, - 0x3008, 0x84a8, 0x11d6, 0x7042, 0x20dd, 0x0011, 0x20d4, 0x8822, - 0x0016, 0x7944, 0x8421, 0xa020, 0xa532, 0x84a1, 0x0016, 0x7944, - 0x8421, 0xa0df, 0x9532, 0x84a1, 0x0016, 0x0000, 0x127e, 0x70d4, - 0xa084, 0x4600, 0x8004, 0x2090, 0x7204, 0x7008, 0xc09c, 0xa205, - 0x00c0, 0x4602, 0x720c, 0x82ff, 0x0040, 0x45ed, 0x8aff, 0x00c0, - 0x4602, 0x7200, 0xd284, 0x00c0, 0x4602, 0x7804, 0xd0cc, 0x0040, - 0x45f3, 0x1078, 0x4acc, 0x7023, 0x0000, 0x7027, 0x0000, 0x7000, - 0xd084, 0x0040, 0x45fd, 0x7007, 0x0004, 0x7003, 0x0008, 0x127f, - 0x2000, 0x007c, 0x7000, 0xa084, 0x0003, 0x7002, 0xc69c, 0xd084, - 0x0040, 0x465b, 0x7108, 0x0005, 0x7008, 0xa106, 0x00c0, 0x460a, - 0xa184, 0x0003, 0x0040, 0x468c, 0xa184, 0x01e0, 0x00c0, 0x468c, - 0xd1f4, 0x00c0, 0x460a, 0xa184, 0x3000, 0xa086, 0x1000, 0x0040, - 0x460a, 0x2001, 0x4f05, 0x2004, 0xd0e4, 0x0040, 0x4637, 0x2011, - 0x0180, 0x710c, 0x8211, 0x0040, 0x4645, 0x7008, 0xd0f4, 0x00c0, - 0x460a, 0x700c, 0xa106, 0x0040, 0x462a, 0x0078, 0x4627, 0x2011, - 0x0180, 0x710c, 0x8211, 0x0040, 0x4645, 0x7008, 0xd0f4, 0x00c0, - 0x460a, 0x700c, 0xa106, 0x0040, 0x463a, 0x7007, 0x0012, 0x7108, - 0x0005, 0x7008, 0xa106, 0x00c0, 0x4647, 0xa184, 0x0003, 0x0040, - 0x468c, 0xd194, 0x0040, 0x4647, 0xd1f4, 0x0040, 0x468c, 0x7007, - 0x0002, 0x0078, 0x460a, 0x7108, 0xd1fc, 0x0040, 0x4666, 0x1078, - 0x47ed, 0x8aff, 0x0040, 0x45dc, 0x0078, 0x465b, 0x700c, 0xa08c, - 0x03ff, 0x0040, 0x4691, 0x7004, 0xd084, 0x0040, 0x4683, 0x7014, - 0xa005, 0x00c0, 0x467f, 0x7010, 0x7310, 0xa306, 0x00c0, 0x4673, - 0x2300, 0xa005, 0x0040, 0x4683, 0xa102, 0x00c8, 0x465b, 0x7007, - 0x0010, 0x0078, 0x468c, 0x8aff, 0x0040, 0x4691, 0x1078, 0x49f2, - 0x00c0, 0x4686, 0x0040, 0x465b, 0x1078, 0x4738, 0x127f, 0x2000, - 0x007c, 0x7204, 0x7108, 0xc19c, 0x8103, 0x00c8, 0x46a0, 0x7007, - 0x0002, 0x0078, 0x4691, 0x7003, 0x0008, 0x127f, 0x2000, 0x007c, - 0xa205, 0x00c0, 0x468c, 0x7023, 0x0000, 0x7027, 0x0000, 0x7003, - 0x0008, 0x007e, 0x2001, 0x4f01, 0x2004, 0xd0cc, 0x0040, 0x46b2, - 0x1078, 0x4acc, 0x007f, 0x127f, 0x2000, 0x007c, 0x6428, 0x84ff, - 0x0040, 0x46e2, 0x2c70, 0x7004, 0xa0bc, 0x000f, 0xa7b8, 0x46f2, - 0x273c, 0x87fb, 0x00c0, 0x46d0, 0x0048, 0x46c8, 0x1078, 0x29b2, - 0x609c, 0xa075, 0x0040, 0x46e2, 0x0078, 0x46bb, 0x2039, 0x46e7, - 0x2704, 0xae68, 0x6808, 0xa630, 0x680c, 0xa529, 0x8421, 0x0040, - 0x46e2, 0x8738, 0x2704, 0xa005, 0x00c0, 0x46d1, 0x709c, 0xa075, - 0x00c0, 0x46bb, 0x007c, 0x0000, 0x0005, 0x0009, 0x000d, 0x0011, - 0x0015, 0x0019, 0x001d, 0x0000, 0x0003, 0x0009, 0x000f, 0x0015, - 0x001b, 0x0000, 0x0000, 0x46e7, 0x46e4, 0x0000, 0x0000, 0x8000, - 0x0000, 0x46e7, 0x0000, 0x46ef, 0x46ec, 0x0000, 0x0000, 0x0000, - 0x0000, 0x46ef, 0x0000, 0x46ea, 0x46ea, 0x0000, 0x0000, 0x8000, - 0x0000, 0x46ea, 0x0000, 0x46f0, 0x46f0, 0x0000, 0x0000, 0x0000, - 0x0000, 0x46f0, 0x2079, 0x4f00, 0x2071, 0x0010, 0x7007, 0x000a, - 0x7007, 0x0002, 0x7003, 0x0001, 0x7810, 0xd0ec, 0x0040, 0x4726, - 0x2009, 0x0001, 0x2071, 0x0020, 0x0078, 0x472a, 0x2009, 0x0002, - 0x2071, 0x0050, 0x7007, 0x000a, 0x7007, 0x0002, 0x7003, 0x0000, - 0x8109, 0x0040, 0x4737, 0x2071, 0x0020, 0x0078, 0x472a, 0x007c, - 0x7004, 0x8004, 0x00c8, 0x47c1, 0x7108, 0x7008, 0xa106, 0x00c0, - 0x473c, 0xa184, 0x01e0, 0x0040, 0x4749, 0x1078, 0x4830, 0x0078, - 0x47e9, 0x7007, 0x0012, 0x2019, 0x0000, 0x7108, 0x7008, 0xa106, - 0x00c0, 0x474d, 0xa184, 0x01e0, 0x0040, 0x475a, 0x1078, 0x4830, - 0x0078, 0x47e9, 0x7810, 0xd0ec, 0x0040, 0x4774, 0x2001, 0x04fd, - 0x2004, 0xa086, 0x0003, 0x00c0, 0x4778, 0xa184, 0x4000, 0x0040, - 0x477c, 0xa382, 0x0003, 0x00c8, 0x477c, 0xa184, 0x0004, 0x0040, - 0x474d, 0x8318, 0x0078, 0x474d, 0x7814, 0xd0ec, 0x00c0, 0x477c, - 0xa184, 0x4000, 0x00c0, 0x474d, 0xa19c, 0x300c, 0xa386, 0x2004, - 0x0040, 0x4799, 0xa386, 0x0008, 0x0040, 0x47a4, 0x7004, 0xd084, - 0x00c0, 0x4795, 0x7108, 0x7008, 0xa106, 0x00c0, 0x478a, 0xa184, - 0x0003, 0x0040, 0x4795, 0x0078, 0x4830, 0xa386, 0x200c, 0x00c0, - 0x474d, 0x7200, 0x8204, 0x0048, 0x47a4, 0x730c, 0xa384, 0x03ff, - 0x0040, 0x47a4, 0x1078, 0x29b2, 0x7108, 0x7008, 0xa106, 0x00c0, - 0x47a4, 0xa184, 0x01e0, 0x0040, 0x47b1, 0x1078, 0x4830, 0x0078, - 0x47e9, 0x7007, 0x0012, 0x7000, 0xd084, 0x00c0, 0x47c1, 0x7310, - 0x7014, 0xa305, 0x0040, 0x47c1, 0x710c, 0xa184, 0x03ff, 0x00c0, - 0x4738, 0x7108, 0x7008, 0xa106, 0x00c0, 0x47c1, 0xa184, 0x01e0, - 0x0040, 0x47ce, 0x1078, 0x4830, 0x0078, 0x47e9, 0x7007, 0x0012, - 0x7007, 0x0008, 0x7004, 0xd09c, 0x00c0, 0x47d2, 0x7108, 0x7008, - 0xa106, 0x00c0, 0x47d6, 0xa184, 0x01e0, 0x0040, 0x47e3, 0x1078, - 0x4830, 0x0078, 0x47e9, 0x7007, 0x0012, 0x7108, 0x8103, 0x0048, - 0x47d6, 0x7003, 0x0008, 0x007c, 0x7108, 0xa184, 0x01e0, 0x00c0, - 0x4830, 0x7108, 0xa184, 0x01e0, 0x00c0, 0x4830, 0xa184, 0x0007, - 0x0079, 0x47fa, 0x4804, 0x4814, 0x4802, 0x4814, 0x4802, 0x4872, - 0x4802, 0x4870, 0x1078, 0x29b2, 0x7004, 0xa084, 0x0010, 0xc08d, - 0x7006, 0x8aff, 0x00c0, 0x480f, 0x2049, 0x0000, 0x007c, 0x1078, - 0x49f2, 0x00c0, 0x480f, 0x007c, 0x7004, 0xa084, 0x0010, 0xc08d, - 0x7006, 0x7004, 0xd084, 0x00c0, 0x4828, 0x7108, 0x7008, 0xa106, - 0x00c0, 0x481d, 0xa184, 0x0003, 0x0040, 0x4828, 0x0078, 0x4830, - 0x8aff, 0x0040, 0x482f, 0x1078, 0x49f2, 0x00c0, 0x482b, 0x007c, - 0x7007, 0x0012, 0x7108, 0x00e0, 0x4833, 0x2091, 0x6000, 0x00e0, - 0x4837, 0x2091, 0x6000, 0x7007, 0x0012, 0x7007, 0x0008, 0x7004, - 0xd09c, 0x00c0, 0x483f, 0x7007, 0x0012, 0x7108, 0xd1fc, 0x00c0, - 0x4843, 0x7003, 0x0000, 0x7000, 0xa005, 0x00c0, 0x4857, 0x7004, - 0xa005, 0x00c0, 0x4857, 0x700c, 0xa005, 0x0040, 0x4859, 0x0078, - 0x483b, 0x2049, 0x0000, 0xb284, 0x0100, 0x0040, 0x4863, 0x2001, - 0x0000, 0x0078, 0x4865, 0x2001, 0x0001, 0x1078, 0x4262, 0x681b, - 0x0002, 0x2051, 0x0000, 0x007c, 0x1078, 0x29b2, 0x1078, 0x29b2, - 0x1078, 0x48b9, 0x7210, 0x7114, 0x700c, 0xa09c, 0x03ff, 0x2800, - 0xa300, 0xa211, 0xa189, 0x0000, 0x1078, 0x48b9, 0x2704, 0x2c58, - 0xac60, 0x6308, 0x2200, 0xa322, 0x630c, 0x2100, 0xa31b, 0x2400, - 0xa305, 0x0040, 0x4895, 0x00c8, 0x4895, 0x8412, 0x8210, 0x830a, - 0xa189, 0x0000, 0x2b60, 0x0078, 0x487c, 0x2b60, 0x8a07, 0x007e, - 0x6004, 0xd09c, 0x0040, 0x48a0, 0xa7ba, 0x46ec, 0x0078, 0x48a2, - 0xa7ba, 0x46e4, 0x007f, 0xa73d, 0x2c00, 0x6886, 0x6f8a, 0x6c92, - 0x6b8e, 0x7108, 0x7008, 0xa106, 0x00c0, 0x48a9, 0xa184, 0x01e0, - 0x0040, 0x48b4, 0x1078, 0x4830, 0x7007, 0x0012, 0x1078, 0x4738, - 0x007c, 0x8a50, 0x8739, 0x2704, 0xa004, 0x00c0, 0x48cd, 0x6000, - 0xa064, 0x00c0, 0x48c4, 0x2d60, 0x6004, 0xa084, 0x000f, 0xa080, - 0x4702, 0x203c, 0x87fb, 0x1040, 0x29b2, 0x007c, 0x127e, 0x0d7e, - 0x70d4, 0xa084, 0x4600, 0x8004, 0x2090, 0x0d7f, 0x6884, 0x2060, - 0x6888, 0x6b8c, 0x6c90, 0x8057, 0xaad4, 0x00ff, 0xa084, 0x00ff, - 0x007e, 0x6804, 0xa084, 0x0008, 0x007f, 0x0040, 0x48eb, 0xa0b8, - 0x46ec, 0x0078, 0x48ed, 0xa0b8, 0x46e4, 0xb284, 0x0100, 0x0040, - 0x48f4, 0x7e20, 0x0078, 0x48f5, 0x7e24, 0xa6b5, 0x000c, 0x681c, - 0xd0b4, 0x0040, 0x48fc, 0xc685, 0x2400, 0xa305, 0x0040, 0x4925, - 0x2c58, 0x2704, 0x6104, 0xac60, 0x6000, 0xa400, 0x701a, 0x6004, - 0xa301, 0x701e, 0xd19c, 0x0040, 0x4915, 0x6010, 0xa081, 0x0000, - 0x7022, 0x6014, 0xa081, 0x0000, 0x7026, 0x6208, 0x2400, 0xa202, - 0x7012, 0x620c, 0x2300, 0xa203, 0x7016, 0x7602, 0x7007, 0x0001, - 0x2b60, 0x1078, 0x4a1c, 0x0078, 0x4927, 0x1078, 0x49f2, 0x00c0, - 0x4925, 0x127f, 0x2000, 0x007c, 0x127e, 0x0d7e, 0x70d4, 0xa084, - 0x4600, 0x8004, 0x2090, 0x0d7f, 0x7007, 0x0004, 0x7004, 0xd094, - 0x00c0, 0x4936, 0x7003, 0x0008, 0x127f, 0x2000, 0x007c, 0x127e, - 0x0d7e, 0x70d4, 0xa084, 0x4600, 0x8004, 0x007e, 0x2090, 0x007f, - 0x0d7f, 0x7e20, 0xb284, 0x0100, 0x00c0, 0x494f, 0x7e24, 0xa6b5, - 0x000c, 0x681c, 0xd0ac, 0x00c0, 0x495a, 0xc685, 0x7003, 0x0000, - 0x7007, 0x0004, 0x6828, 0x2050, 0x2d60, 0x6004, 0xa0bc, 0x000f, - 0xa7b8, 0x46f2, 0x273c, 0x87fb, 0x00c0, 0x4970, 0x0048, 0x496a, - 0x1078, 0x29b2, 0x689c, 0xa065, 0x0040, 0x4974, 0x0078, 0x495d, - 0x1078, 0x49f2, 0x00c0, 0x4970, 0x127f, 0x2000, 0x007c, 0x127e, - 0x007e, 0x017e, 0x0d7e, 0x70d4, 0xa084, 0x4600, 0x8004, 0x007e, - 0x2090, 0x007f, 0x7e20, 0xb284, 0x0100, 0x00c0, 0x4988, 0x7e24, - 0x0d7f, 0x037f, 0x047f, 0xa6b5, 0x000c, 0x681c, 0xd0b4, 0x0040, - 0x4996, 0xc685, 0x7003, 0x0000, 0x7007, 0x0004, 0x2049, 0x4977, - 0x6828, 0xa055, 0x0d7e, 0x0040, 0x49ee, 0x2d70, 0x2e60, 0x7004, - 0xa0bc, 0x000f, 0xa7b8, 0x46f2, 0x273c, 0x87fb, 0x00c0, 0x49b3, - 0x0048, 0x49ac, 0x1078, 0x29b2, 0x709c, 0xa075, 0x2060, 0x0040, - 0x49ee, 0x0078, 0x499f, 0x2704, 0xae68, 0x6808, 0xa422, 0x680c, - 0xa31b, 0x0048, 0x49cc, 0x8a51, 0x00c0, 0x49c0, 0x1078, 0x29b2, - 0x8738, 0x2704, 0xa005, 0x00c0, 0x49b4, 0x709c, 0xa075, 0x2060, - 0x0040, 0x49ee, 0x0078, 0x499f, 0x8422, 0x8420, 0x831a, 0xa399, - 0x0000, 0x6908, 0x2400, 0xa122, 0x690c, 0x2300, 0xa11b, 0x00c8, - 0x49db, 0x1078, 0x29b2, 0xb284, 0x0100, 0x0040, 0x49e9, 0x2001, - 0x4f04, 0x2004, 0xd0ec, 0x00c0, 0x49e9, 0x2071, 0x0050, 0x0078, - 0x49eb, 0x2071, 0x0020, 0x0d7f, 0x0078, 0x48fc, 0x0d7f, 0x127f, - 0x2000, 0x007c, 0x7008, 0x007e, 0xa084, 0x01e0, 0x007f, 0x0040, - 0x49fb, 0xa006, 0x007c, 0xa084, 0x0003, 0xa086, 0x0003, 0x00c0, - 0x4a02, 0x007c, 0x2704, 0xac78, 0x7800, 0x701a, 0x7804, 0x701e, - 0x7808, 0x7012, 0x780c, 0x7016, 0x6004, 0xd09c, 0x0040, 0x4a14, - 0x7810, 0x7022, 0x7814, 0x7026, 0x7602, 0x7004, 0xa084, 0x0010, - 0xc085, 0x7006, 0x2079, 0x4f00, 0x8738, 0x8a51, 0x0040, 0x4a40, - 0x2704, 0xa005, 0x00c0, 0x4a32, 0x609c, 0xa005, 0x0040, 0x4a41, - 0x2060, 0x6004, 0xa084, 0x000f, 0xa080, 0x46f2, 0x203c, 0x87fb, - 0x1040, 0x29b2, 0x7008, 0x007e, 0xa084, 0x01e0, 0x007f, 0x0040, - 0x4a3c, 0xa006, 0x0078, 0x4a41, 0xa084, 0x0003, 0xa086, 0x0003, - 0x007c, 0x2051, 0x0000, 0x007c, 0x127e, 0x007e, 0x0d7e, 0x70d4, - 0xa084, 0x4600, 0x8004, 0x2090, 0x0d7f, 0x087f, 0x7108, 0xa184, - 0x0003, 0x00c0, 0x4a59, 0x6828, 0xa005, 0x0040, 0x4a69, 0x0078, - 0x4602, 0x7108, 0xd1fc, 0x0040, 0x4a61, 0x1078, 0x47ed, 0x0078, - 0x4a4e, 0x7007, 0x0010, 0x7108, 0xd1fc, 0x0040, 0x4a63, 0x1078, - 0x47ed, 0x7008, 0xa086, 0x0008, 0x00c0, 0x4a4e, 0x7000, 0xa005, - 0x00c0, 0x4a4e, 0x7003, 0x0000, 0x2049, 0x0000, 0x007e, 0x7804, - 0xd0cc, 0x0040, 0x4a7d, 0x1078, 0x4acc, 0x007f, 0x127f, 0x2000, - 0x007c, 0x127e, 0x147e, 0x137e, 0x157e, 0x0c7e, 0x0d7e, 0x70d4, - 0xa084, 0x4600, 0x8004, 0x2090, 0x0d7f, 0x2049, 0x4a81, 0xad80, - 0x0011, 0x20a0, 0xb284, 0x0100, 0x0040, 0x4aa4, 0x2001, 0x4f04, - 0x2004, 0xd0ec, 0x0040, 0x4aa0, 0x2099, 0x0031, 0x0078, 0x4aa6, - 0x2099, 0x0032, 0x0078, 0x4aa6, 0x2099, 0x0031, 0x700c, 0xa084, - 0x03ff, 0x682a, 0x7007, 0x0008, 0x7007, 0x0002, 0x7003, 0x0001, - 0x0040, 0x4ab5, 0x8000, 0x80ac, 0x53a5, 0x700c, 0xa084, 0x03ff, - 0x0040, 0x4ac1, 0x7007, 0x0004, 0x7004, 0xa084, 0x0004, 0x00c0, - 0x4abc, 0x0c7f, 0x2049, 0x0000, 0x7003, 0x0000, 0x157f, 0x137f, - 0x147f, 0x127f, 0x2000, 0x007c, 0x6814, 0xd0fc, 0x0040, 0x4b11, - 0x7000, 0xd084, 0x0040, 0x4b11, 0x7e24, 0xa6b5, 0x0004, 0x7007, - 0x0004, 0x7004, 0xa084, 0x0004, 0x00c0, 0x4ad9, 0x7118, 0x017e, - 0x711c, 0x017e, 0x7120, 0x017e, 0x7124, 0x017e, 0xa00e, 0x711a, - 0x701f, 0x3fff, 0x7122, 0x7126, 0x7013, 0x0004, 0x7116, 0x7602, - 0x7007, 0x0001, 0x2001, 0xffff, 0x2009, 0x0031, 0x200a, 0x200a, - 0x7108, 0x7008, 0xa106, 0x00c0, 0x4af8, 0xd1fc, 0x0040, 0x4af8, - 0x027f, 0x7226, 0x027f, 0x7222, 0x027f, 0x721e, 0x027f, 0x721a, - 0x7007, 0x0002, 0x7008, 0xa086, 0x0008, 0x0040, 0x4b11, 0x0078, - 0x4830, 0x7007, 0x0004, 0x7003, 0x0000, 0x007c, 0x2091, 0x8000, - 0x2091, 0x6000, 0x78ac, 0xa005, 0x00c0, 0x4b2d, 0x7974, 0x70d0, - 0xa106, 0x00c0, 0x4b2d, 0x781c, 0xa005, 0x0040, 0x4b2d, 0x781f, - 0x0000, 0x0068, 0x4b2d, 0x2091, 0x4080, 0x7830, 0x8001, 0x7832, - 0x00c0, 0x4bb5, 0x7834, 0x7832, 0x7810, 0xd0ec, 0x00c0, 0x4bae, - 0x2061, 0x74c0, 0x2069, 0x4f80, 0xc7fd, 0x68d0, 0xa005, 0x0040, - 0x4b47, 0x8001, 0x68d2, 0x00c0, 0x4b47, 0x1078, 0x4d83, 0x6800, - 0xa084, 0x000f, 0x0040, 0x4b5c, 0xa086, 0x0001, 0x0040, 0x4b5c, - 0x6844, 0xa00d, 0x0040, 0x4b5c, 0x2104, 0xa005, 0x0040, 0x4b5c, - 0x8001, 0x200a, 0x0040, 0x4cf6, 0x6814, 0xa005, 0x0040, 0x4b81, - 0x8001, 0x6816, 0x00c0, 0x4b81, 0x68a7, 0x0001, 0x0f7e, 0xd7fc, - 0x00c0, 0x4b76, 0x7810, 0xd0ec, 0x0040, 0x4b72, 0x2079, 0x0100, - 0x0078, 0x4b78, 0x2079, 0x0200, 0x0078, 0x4b78, 0x2079, 0x0100, - 0x1078, 0x43d3, 0x0f7f, 0x6864, 0xa005, 0x0040, 0x4b81, 0x1078, - 0x266f, 0x6880, 0xa005, 0x0040, 0x4b8e, 0x8001, 0x6882, 0x00c0, - 0x4b8e, 0x6867, 0x0000, 0x68d4, 0xc0dd, 0x68d6, 0x68d4, 0xd0fc, - 0x0040, 0x4bab, 0xc0fc, 0x68d6, 0x20a9, 0x0200, 0x6034, 0xa005, - 0x0040, 0x4ba7, 0x8001, 0x6036, 0x68d4, 0xc0fd, 0x68d6, 0x00c0, - 0x4ba7, 0x6010, 0xa005, 0x0040, 0x4ba7, 0x1078, 0x266f, 0xace0, - 0x0010, 0x00f0, 0x4b96, 0xd7fc, 0x0040, 0x4bb5, 0x2061, 0x54c0, - 0x2069, 0x4f40, 0xc7fc, 0x0078, 0x4b3d, 0x1078, 0x4bf1, 0x7838, - 0x8001, 0x783a, 0x00c0, 0x4bd7, 0x783c, 0x783a, 0x2061, 0x54c0, - 0x2069, 0x4f40, 0xc7fc, 0x680c, 0xa005, 0x0040, 0x4bc9, 0x1078, - 0x4c5b, 0xd7fc, 0x00c0, 0x4bd7, 0x7810, 0xd0ec, 0x00c0, 0x4bd7, - 0x2061, 0x74c0, 0x2069, 0x4f80, 0xc7fd, 0x0078, 0x4bc3, 0x7814, - 0xd0e4, 0x00c0, 0x4bdb, 0x7810, 0xd0cc, 0x0040, 0x4bee, 0xd0ac, - 0x00c0, 0x4be7, 0xd0a4, 0x0040, 0x4bee, 0xc0ad, 0x7812, 0x2091, - 0x8001, 0x0068, 0x4bed, 0x1078, 0x23dc, 0x007c, 0x2091, 0x8001, - 0x007c, 0x7840, 0x8001, 0x7842, 0x00c0, 0x4c5a, 0x7844, 0x7842, - 0x2069, 0x4f40, 0xc7fc, 0x7810, 0x2079, 0x0200, 0xd0ec, 0x0040, - 0x4c03, 0x2079, 0x0100, 0x68d8, 0xa005, 0x0040, 0x4c0f, 0x7de0, - 0xa504, 0x00c0, 0x4c0f, 0x68da, 0x68d4, 0xc0bc, 0x68d6, 0x2079, - 0x4f00, 0x6810, 0xa005, 0x00c0, 0x4c17, 0x2001, 0x0101, 0x8001, - 0x6812, 0xd7fc, 0x0040, 0x4c20, 0xa080, 0x95d0, 0x0078, 0x4c22, - 0xa080, 0x94c0, 0x2040, 0x2004, 0xa065, 0x0040, 0x4c4c, 0x6024, - 0xa005, 0x0040, 0x4c48, 0x8001, 0x6026, 0x00c0, 0x4c48, 0x6800, - 0xa005, 0x0040, 0x4c3b, 0x684c, 0xac06, 0x00c0, 0x4c3b, 0x1078, - 0x4cf6, 0x0078, 0x4c4c, 0x6864, 0xa005, 0x0040, 0x4c43, 0x6027, - 0x0001, 0x0078, 0x4c48, 0x1078, 0x4ca9, 0x2804, 0x0078, 0x4c24, - 0x6000, 0x2c40, 0x0078, 0x4c24, 0xd7fc, 0x00c0, 0x4c5a, 0x7810, - 0xd0ec, 0x00c0, 0x4c5a, 0x2069, 0x4f80, 0xc7fd, 0x2079, 0x0100, - 0x0078, 0x4c03, 0x007c, 0x2009, 0x0000, 0x20a9, 0x0200, 0x6008, - 0xd09c, 0x0040, 0x4c95, 0x6024, 0xa005, 0x0040, 0x4c6b, 0x8001, - 0x6026, 0x0078, 0x4c93, 0x6008, 0xc09c, 0xd084, 0x00c0, 0x4c73, - 0xd0ac, 0x0040, 0x4c8d, 0x600a, 0x6004, 0xa005, 0x0040, 0x4c95, - 0x0d7e, 0x0c7e, 0x017e, 0x2068, 0x6010, 0x8001, 0x6012, 0x1078, - 0x3e19, 0x2d00, 0x2c68, 0x2060, 0x1078, 0x1ea2, 0x1078, 0x2064, - 0x017f, 0x0c7f, 0x0d7f, 0x0078, 0x4c95, 0xc0bd, 0x600a, 0xa18d, - 0x0001, 0x0078, 0x4c95, 0xa18d, 0x0100, 0xace0, 0x0010, 0x00f0, - 0x4c5f, 0xa184, 0x0001, 0x0040, 0x4ca4, 0xa18c, 0xfffe, 0x690e, - 0x1078, 0x266f, 0x0078, 0x4ca5, 0x690e, 0x007c, 0x00c0, 0x4ca5, - 0x786c, 0x2c00, 0x687e, 0x6714, 0x6f76, 0x6017, 0x0000, 0x602b, - 0x0000, 0x601b, 0x0006, 0x60b4, 0xa084, 0x3f00, 0x601e, 0x6020, - 0xa084, 0x00ff, 0xa085, 0x0060, 0x6022, 0x6000, 0x2042, 0x1078, - 0x1e2b, 0x6818, 0xa005, 0x0040, 0x4cc7, 0x8001, 0x681a, 0x6808, - 0xc0a4, 0x680a, 0x6810, 0x7908, 0x8109, 0x790a, 0x8001, 0x00d0, - 0x4cd3, 0x1078, 0x29b2, 0x6812, 0x00c0, 0x4cd9, 0x7910, 0xc1a5, - 0x7912, 0x602f, 0x0000, 0x6033, 0x0000, 0x2c68, 0x1078, 0x2073, - 0xd7fc, 0x00c0, 0x4ce7, 0x2069, 0x4f40, 0x0078, 0x4ce9, 0x2069, - 0x4f80, 0x6910, 0xa184, 0x0100, 0x2001, 0x0006, 0x00c0, 0x4cf3, - 0x697a, 0x2001, 0x0004, 0x1078, 0x2663, 0x007c, 0x0d7e, 0x694c, - 0x2160, 0xd7fc, 0x00c0, 0x4d08, 0x7810, 0xd0ec, 0x0040, 0x4d04, - 0x2069, 0x0100, 0x0078, 0x4d0a, 0x2069, 0x0200, 0x0078, 0x4d0a, - 0x2069, 0x0100, 0x1078, 0x2926, 0x601b, 0x0006, 0x6858, 0xa084, - 0x3f00, 0x601e, 0x6020, 0xa084, 0x00ff, 0xa085, 0x0048, 0x6022, - 0x602f, 0x0000, 0x6033, 0x0000, 0x6808, 0xa084, 0xfffd, 0x680a, - 0x6830, 0xd0b4, 0x0040, 0x4d3c, 0x684b, 0x0004, 0x20a9, 0x0014, - 0x6848, 0xd094, 0x0040, 0x4d2e, 0x00f0, 0x4d28, 0x684b, 0x0009, - 0x20a9, 0x0014, 0x6848, 0xd084, 0x0040, 0x4d38, 0x00f0, 0x4d32, - 0x20a9, 0x00fa, 0x00f0, 0x4d3a, 0x681b, 0x0047, 0x0d7f, 0x6867, - 0x0007, 0x007c, 0x2079, 0x4f00, 0x1078, 0x4d76, 0x1078, 0x4d5c, - 0x1078, 0x4d69, 0x2009, 0x0002, 0x2069, 0x4f80, 0x680f, 0x0000, - 0x6813, 0x0000, 0x6817, 0x0000, 0x8109, 0x0040, 0x4d5b, 0x2069, - 0x4f40, 0x0078, 0x4d4e, 0x007c, 0x7810, 0xd0ec, 0x0040, 0x4d64, - 0x2019, 0x00cc, 0x0078, 0x4d66, 0x2019, 0x007b, 0x7b3a, 0x7b3e, - 0x007c, 0x7814, 0xd0e4, 0x00c0, 0x4d71, 0x2019, 0x0040, 0x0078, - 0x4d73, 0x2019, 0x0026, 0x7b42, 0x7b46, 0x007c, 0x7814, 0xd0e4, - 0x00c0, 0x4d7e, 0x2019, 0x3f94, 0x0078, 0x4d80, 0x2019, 0x2624, - 0x7b32, 0x7b36, 0x007c, 0x6a50, 0xa285, 0x0000, 0x0040, 0x4daf, - 0x6954, 0x6bc0, 0xa300, 0x0c7e, 0x2164, 0x6304, 0x83ff, 0x00c0, - 0x4d9b, 0x8211, 0x0040, 0x4d9f, 0x8108, 0xa11a, 0x0048, 0x4d8c, - 0x69c0, 0x0078, 0x4d8c, 0x68d3, 0x000a, 0x0c7f, 0x007c, 0x6950, - 0x6ac0, 0x2264, 0x602b, 0x0000, 0x602f, 0x0000, 0x6008, 0xc0b5, - 0x600a, 0x8210, 0x8109, 0x00c0, 0x4da1, 0x6952, 0x0c7f, 0x007c, - 0x00e0, 0x4db0, 0x2091, 0x6000, 0x00e0, 0x4db4, 0x2091, 0x6000, - 0x70ec, 0xd0dc, 0x00c0, 0x4dc1, 0xd0d4, 0x0040, 0x4dea, 0x0078, - 0x4ded, 0x2008, 0x7810, 0xd0ec, 0x0040, 0x4dd4, 0xd1c4, 0x00c0, - 0x4e0e, 0x7814, 0xc0c5, 0x7816, 0x7810, 0xc0f5, 0x7812, 0xd0ec, - 0x0040, 0x4e0a, 0x0078, 0x4e06, 0xae8e, 0x0100, 0x0040, 0x4de1, - 0x7814, 0xc0f5, 0xc0c5, 0x7816, 0xd0d4, 0x00c0, 0x4e0a, 0x0078, - 0x4e06, 0x7814, 0xc0fd, 0xc0c5, 0x7816, 0xd0d4, 0x00c0, 0x4e0a, - 0x0078, 0x4e06, 0xd0e4, 0x0040, 0x4e0c, 0x00e0, 0x4ded, 0x2091, - 0x6000, 0x2009, 0x000c, 0x00e0, 0x4df3, 0x2091, 0x6000, 0x8109, - 0x00c0, 0x4df3, 0x70e4, 0xa084, 0x01ff, 0xa086, 0x01ff, 0x00c0, - 0x4e04, 0x70ec, 0x0078, 0x4dc1, 0x1078, 0x4e0f, 0x7804, 0xd08c, - 0x0040, 0x4e0c, 0x681f, 0x000c, 0x70a0, 0x70a2, 0x007c, 0x7910, - 0xd1ec, 0x0040, 0x4e19, 0x7814, 0xc0c4, 0xc1f4, 0x7912, 0x0078, - 0x4e2b, 0xae8e, 0x0100, 0x0040, 0x4e25, 0x7814, 0xc0f4, 0xd0fc, - 0x00c0, 0x4e2b, 0xc0c4, 0x0078, 0x4e2b, 0x7814, 0xc0fc, 0xd0f4, - 0x00c0, 0x4e2b, 0xc0c4, 0x7816, 0x007c, 0x14e3 -}; -#ifdef UNIQUE_FW_NAME -static unsigned short fw1280ei_length01 = 0x3e2e; -#else -static unsigned short risc_code_length01 = 0x3e2e; -#endif - diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index df09820e891..351b56ced92 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -348,6 +348,7 @@ #include <linux/interrupt.h> #include <linux/init.h> #include <linux/dma-mapping.h> +#include <linux/firmware.h> #include <asm/io.h> #include <asm/irq.h> @@ -384,11 +385,7 @@ #define MEMORY_MAPPED_IO 1 #endif -#define UNIQUE_FW_NAME #include "qla1280.h" -#include "ql12160_fw.h" /* ISP RISC codes */ -#include "ql1280_fw.h" -#include "ql1040_fw.h" #ifndef BITS_PER_LONG #error "BITS_PER_LONG not defined!" @@ -541,10 +538,7 @@ __setup("qla1280=", qla1280_setup); struct qla_boards { unsigned char name[9]; /* Board ID String */ int numPorts; /* Number of SCSI ports */ - unsigned short *fwcode; /* pointer to FW array */ - unsigned short *fwlen; /* number of words in array */ - unsigned short *fwstart; /* start address for F/W */ - unsigned char *fwver; /* Ptr to F/W version array */ + char *fwname; /* firmware name */ }; /* NOTE: the last argument in each entry is used to index ql1280_board_tbl */ @@ -567,19 +561,13 @@ MODULE_DEVICE_TABLE(pci, qla1280_pci_tbl); static struct qla_boards ql1280_board_tbl[] = { /* Name , Number of ports, FW details */ - {"QLA12160", 2, &fw12160i_code01[0], &fw12160i_length01, - &fw12160i_addr01, &fw12160i_version_str[0]}, - {"QLA1040", 1, &risc_code01[0], &risc_code_length01, - &risc_code_addr01, &firmware_version[0]}, - {"QLA1080", 1, &fw1280ei_code01[0], &fw1280ei_length01, - &fw1280ei_addr01, &fw1280ei_version_str[0]}, - {"QLA1240", 2, &fw1280ei_code01[0], &fw1280ei_length01, - &fw1280ei_addr01, &fw1280ei_version_str[0]}, - {"QLA1280", 2, &fw1280ei_code01[0], &fw1280ei_length01, - &fw1280ei_addr01, &fw1280ei_version_str[0]}, - {"QLA10160", 1, &fw12160i_code01[0], &fw12160i_length01, - &fw12160i_addr01, &fw12160i_version_str[0]}, - {" ", 0} + {"QLA12160", 2, "qlogic/12160.bin"}, + {"QLA1040", 1, "qlogic/1040.bin"}, + {"QLA1080", 1, "qlogic/1280.bin"}, + {"QLA1240", 2, "qlogic/1280.bin"}, + {"QLA1280", 2, "qlogic/1280.bin"}, + {"QLA10160", 1, "qlogic/12160.bin"}, + {" ", 0, " "}, }; static int qla1280_verbose = 1; @@ -704,7 +692,7 @@ qla1280_info(struct Scsi_Host *host) sprintf (bp, "QLogic %s PCI to SCSI Host Adapter\n" " Firmware version: %2d.%02d.%02d, Driver version %s", - &bdp->name[0], bdp->fwver[0], bdp->fwver[1], bdp->fwver[2], + &bdp->name[0], ha->fwver1, ha->fwver2, ha->fwver3, QLA1280_VERSION); return bp; } @@ -1648,36 +1636,60 @@ qla1280_chip_diag(struct scsi_qla_host *ha) static int qla1280_load_firmware_pio(struct scsi_qla_host *ha) { - uint16_t risc_address, *risc_code_address, risc_code_size; + const struct firmware *fw; + const __le16 *fw_data; + uint16_t risc_address, risc_code_size; uint16_t mb[MAILBOX_REGISTER_COUNT], i; int err; + err = request_firmware(&fw, ql1280_board_tbl[ha->devnum].fwname, + &ha->pdev->dev); + if (err) { + printk(KERN_ERR "Failed to load image \"%s\" err %d\n", + ql1280_board_tbl[ha->devnum].fwname, err); + return err; + } + if ((fw->size % 2) || (fw->size < 6)) { + printk(KERN_ERR "Bogus length %zu in image \"%s\"\n", + fw->size, ql1280_board_tbl[ha->devnum].fwname); + err = -EINVAL; + goto out; + } + ha->fwver1 = fw->data[0]; + ha->fwver2 = fw->data[1]; + ha->fwver3 = fw->data[2]; + fw_data = (const __le16 *)&fw->data[0]; + ha->fwstart = __le16_to_cpu(fw_data[2]); + /* Load RISC code. */ - risc_address = *ql1280_board_tbl[ha->devnum].fwstart; - risc_code_address = ql1280_board_tbl[ha->devnum].fwcode; - risc_code_size = *ql1280_board_tbl[ha->devnum].fwlen; + risc_address = ha->fwstart; + fw_data = (const __le16 *)&fw->data[4]; + risc_code_size = (fw->size - 6) / 2; for (i = 0; i < risc_code_size; i++) { mb[0] = MBC_WRITE_RAM_WORD; mb[1] = risc_address + i; - mb[2] = risc_code_address[i]; + mb[2] = __le16_to_cpu(fw_data[i]); err = qla1280_mailbox_command(ha, BIT_0 | BIT_1 | BIT_2, mb); if (err) { printk(KERN_ERR "scsi(%li): Failed to load firmware\n", ha->host_no); - return err; + goto out; } } - - return 0; +out: + release_firmware(fw); + return err; } #define DUMP_IT_BACK 0 /* for debug of RISC loading */ static int qla1280_load_firmware_dma(struct scsi_qla_host *ha) { - uint16_t risc_address, *risc_code_address, risc_code_size; + const struct firmware *fw; + const __le16 *fw_data; + uint16_t risc_address, risc_code_size; uint16_t mb[MAILBOX_REGISTER_COUNT], cnt; int err = 0, num, i; #if DUMP_IT_BACK @@ -1689,10 +1701,29 @@ qla1280_load_firmware_dma(struct scsi_qla_host *ha) return -ENOMEM; #endif + err = request_firmware(&fw, ql1280_board_tbl[ha->devnum].fwname, + &ha->pdev->dev); + if (err) { + printk(KERN_ERR "Failed to load image \"%s\" err %d\n", + ql1280_board_tbl[ha->devnum].fwname, err); + return err; + } + if ((fw->size % 2) || (fw->size < 6)) { + printk(KERN_ERR "Bogus length %zu in image \"%s\"\n", + fw->size, ql1280_board_tbl[ha->devnum].fwname); + err = -EINVAL; + goto out; + } + ha->fwver1 = fw->data[0]; + ha->fwver2 = fw->data[1]; + ha->fwver3 = fw->data[2]; + fw_data = (const __le16 *)&fw->data[0]; + ha->fwstart = __le16_to_cpu(fw_data[2]); + /* Load RISC code. */ - risc_address = *ql1280_board_tbl[ha->devnum].fwstart; - risc_code_address = ql1280_board_tbl[ha->devnum].fwcode; - risc_code_size = *ql1280_board_tbl[ha->devnum].fwlen; + risc_address = ha->fwstart; + fw_data = (const __le16 *)&fw->data[4]; + risc_code_size = (fw->size - 6) / 2; dprintk(1, "%s: DMA RISC code (%i) words\n", __func__, risc_code_size); @@ -1708,10 +1739,9 @@ qla1280_load_firmware_dma(struct scsi_qla_host *ha) dprintk(2, "qla1280_setup_chip: loading risc @ =(0x%p)," "%d,%d(0x%x)\n", - risc_code_address, cnt, num, risc_address); + fw_data, cnt, num, risc_address); for(i = 0; i < cnt; i++) - ((__le16 *)ha->request_ring)[i] = - cpu_to_le16(risc_code_address[i]); + ((__le16 *)ha->request_ring)[i] = fw_data[i]; mb[0] = MBC_LOAD_RAM; mb[1] = risc_address; @@ -1763,7 +1793,7 @@ qla1280_load_firmware_dma(struct scsi_qla_host *ha) #endif risc_address += cnt; risc_code_size = risc_code_size - cnt; - risc_code_address = risc_code_address + cnt; + fw_data = fw_data + cnt; num++; } @@ -1771,6 +1801,7 @@ qla1280_load_firmware_dma(struct scsi_qla_host *ha) #if DUMP_IT_BACK pci_free_consistent(ha->pdev, 8000, tbuf, p_tbuf); #endif + release_firmware(fw); return err; } @@ -1786,7 +1817,7 @@ qla1280_start_firmware(struct scsi_qla_host *ha) /* Verify checksum of loaded RISC code. */ mb[0] = MBC_VERIFY_CHECKSUM; /* mb[1] = ql12_risc_code_addr01; */ - mb[1] = *ql1280_board_tbl[ha->devnum].fwstart; + mb[1] = ha->fwstart; err = qla1280_mailbox_command(ha, BIT_1 | BIT_0, mb); if (err) { printk(KERN_ERR "scsi(%li): RISC checksum failed.\n", ha->host_no); @@ -1796,7 +1827,7 @@ qla1280_start_firmware(struct scsi_qla_host *ha) /* Start firmware execution. */ dprintk(1, "%s: start firmware running.\n", __func__); mb[0] = MBC_EXECUTE_FIRMWARE; - mb[1] = *ql1280_board_tbl[ha->devnum].fwstart; + mb[1] = ha->fwstart; err = qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]); if (err) { printk(KERN_ERR "scsi(%li): Failed to start firmware\n", @@ -4450,6 +4481,9 @@ module_exit(qla1280_exit); MODULE_AUTHOR("Qlogic & Jes Sorensen"); MODULE_DESCRIPTION("Qlogic ISP SCSI (qla1x80/qla1x160) driver"); MODULE_LICENSE("GPL"); +MODULE_FIRMWARE("qlogic/1040.bin"); +MODULE_FIRMWARE("qlogic/1280.bin"); +MODULE_FIRMWARE("qlogic/12160.bin"); MODULE_VERSION(QLA1280_VERSION); /* diff --git a/drivers/scsi/qla1280.h b/drivers/scsi/qla1280.h index ff2c363ead2..d7c44b8d2b4 100644 --- a/drivers/scsi/qla1280.h +++ b/drivers/scsi/qla1280.h @@ -1069,6 +1069,12 @@ struct scsi_qla_host { struct nvram nvram; int nvram_valid; + + /* Firmware Info */ + unsigned short fwstart; /* start address for F/W */ + unsigned char fwver1; /* F/W version first char */ + unsigned char fwver2; /* F/W version second char */ + unsigned char fwver3; /* F/W version third char */ }; #endif /* _QLA1280_H */ diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 33a3c13fd89..b09993a0657 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -96,7 +96,9 @@ qla2x00_sysfs_read_nvram(struct kobject *kobj, if (!capable(CAP_SYS_ADMIN)) return 0; - /* Read NVRAM data from cache. */ + if (IS_NOCACHE_VPD_TYPE(ha)) + ha->isp_ops->read_optrom(vha, ha->vpd, ha->flt_region_nvram << 2, + ha->nvram_size); return memory_read_from_buffer(buf, count, &off, ha->nvram, ha->nvram_size); } @@ -111,7 +113,8 @@ qla2x00_sysfs_write_nvram(struct kobject *kobj, struct qla_hw_data *ha = vha->hw; uint16_t cnt; - if (!capable(CAP_SYS_ADMIN) || off != 0 || count != ha->nvram_size) + if (!capable(CAP_SYS_ADMIN) || off != 0 || count != ha->nvram_size || + !ha->isp_ops->write_nvram) return 0; /* Checksum NVRAM. */ @@ -137,12 +140,21 @@ qla2x00_sysfs_write_nvram(struct kobject *kobj, *iter = chksum; } + if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) { + qla_printk(KERN_WARNING, ha, + "HBA not online, failing NVRAM update.\n"); + return -EAGAIN; + } + /* Write NVRAM. */ ha->isp_ops->write_nvram(vha, (uint8_t *)buf, ha->nvram_base, count); ha->isp_ops->read_nvram(vha, (uint8_t *)ha->nvram, ha->nvram_base, count); + /* NVRAM settings take effect immediately. */ set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); + qla2xxx_wake_dpc(vha); + qla2x00_wait_for_chip_reset(vha); return (count); } @@ -244,12 +256,6 @@ qla2x00_sysfs_write_optrom_ctl(struct kobject *kobj, if (ha->optrom_state != QLA_SWAITING) break; - if (start & 0xfff) { - qla_printk(KERN_WARNING, ha, - "Invalid start region 0x%x/0x%x.\n", start, size); - return -EINVAL; - } - ha->optrom_region_start = start; ha->optrom_region_size = start + size > ha->optrom_size ? ha->optrom_size - start : size; @@ -303,8 +309,7 @@ qla2x00_sysfs_write_optrom_ctl(struct kobject *kobj, else if (start == (ha->flt_region_boot * 4) || start == (ha->flt_region_fw * 4)) valid = 1; - else if ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && - start == (ha->flt_region_vpd_nvram * 4)) + else if (IS_QLA25XX(ha) || IS_QLA81XX(ha)) valid = 1; if (!valid) { qla_printk(KERN_WARNING, ha, @@ -337,6 +342,12 @@ qla2x00_sysfs_write_optrom_ctl(struct kobject *kobj, if (ha->optrom_state != QLA_SWRITING) break; + if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) { + qla_printk(KERN_WARNING, ha, + "HBA not online, failing flash update.\n"); + return -EAGAIN; + } + DEBUG2(qla_printk(KERN_INFO, ha, "Writing flash region -- 0x%x/0x%x.\n", ha->optrom_region_start, ha->optrom_region_size)); @@ -371,7 +382,9 @@ qla2x00_sysfs_read_vpd(struct kobject *kobj, if (!capable(CAP_SYS_ADMIN)) return 0; - /* Read NVRAM data from cache. */ + if (IS_NOCACHE_VPD_TYPE(ha)) + ha->isp_ops->read_optrom(vha, ha->vpd, ha->flt_region_vpd << 2, + ha->vpd_size); return memory_read_from_buffer(buf, count, &off, ha->vpd, ha->vpd_size); } @@ -383,14 +396,35 @@ qla2x00_sysfs_write_vpd(struct kobject *kobj, struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj, struct device, kobj))); struct qla_hw_data *ha = vha->hw; + uint8_t *tmp_data; - if (!capable(CAP_SYS_ADMIN) || off != 0 || count != ha->vpd_size) + if (!capable(CAP_SYS_ADMIN) || off != 0 || count != ha->vpd_size || + !ha->isp_ops->write_nvram) return 0; + if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) { + qla_printk(KERN_WARNING, ha, + "HBA not online, failing VPD update.\n"); + return -EAGAIN; + } + /* Write NVRAM. */ ha->isp_ops->write_nvram(vha, (uint8_t *)buf, ha->vpd_base, count); ha->isp_ops->read_nvram(vha, (uint8_t *)ha->vpd, ha->vpd_base, count); + /* Update flash version information for 4Gb & above. */ + if (!IS_FWI2_CAPABLE(ha)) + goto done; + + tmp_data = vmalloc(256); + if (!tmp_data) { + qla_printk(KERN_WARNING, ha, + "Unable to allocate memory for VPD information update.\n"); + goto done; + } + ha->isp_ops->get_flash_version(vha, tmp_data); + vfree(tmp_data); +done: return count; } @@ -465,6 +499,199 @@ static struct bin_attribute sysfs_sfp_attr = { .read = qla2x00_sysfs_read_sfp, }; +static ssize_t +qla2x00_sysfs_write_reset(struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t off, size_t count) +{ + struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj, + struct device, kobj))); + struct qla_hw_data *ha = vha->hw; + int type; + + if (off != 0) + return 0; + + type = simple_strtol(buf, NULL, 10); + switch (type) { + case 0x2025c: + qla_printk(KERN_INFO, ha, + "Issuing ISP reset on (%ld).\n", vha->host_no); + + scsi_block_requests(vha->host); + set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); + qla2xxx_wake_dpc(vha); + qla2x00_wait_for_chip_reset(vha); + scsi_unblock_requests(vha->host); + break; + case 0x2025d: + if (!IS_QLA81XX(ha)) + break; + + qla_printk(KERN_INFO, ha, + "Issuing MPI reset on (%ld).\n", vha->host_no); + + /* Make sure FC side is not in reset */ + qla2x00_wait_for_hba_online(vha); + + /* Issue MPI reset */ + scsi_block_requests(vha->host); + if (qla81xx_restart_mpi_firmware(vha) != QLA_SUCCESS) + qla_printk(KERN_WARNING, ha, + "MPI reset failed on (%ld).\n", vha->host_no); + scsi_unblock_requests(vha->host); + break; + } + return count; +} + +static struct bin_attribute sysfs_reset_attr = { + .attr = { + .name = "reset", + .mode = S_IWUSR, + }, + .size = 0, + .write = qla2x00_sysfs_write_reset, +}; + +static ssize_t +qla2x00_sysfs_write_edc(struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t off, size_t count) +{ + struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj, + struct device, kobj))); + struct qla_hw_data *ha = vha->hw; + uint16_t dev, adr, opt, len; + int rval; + + ha->edc_data_len = 0; + + if (!capable(CAP_SYS_ADMIN) || off != 0 || count < 8) + return 0; + + if (!ha->edc_data) { + ha->edc_data = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, + &ha->edc_data_dma); + if (!ha->edc_data) { + DEBUG2(qla_printk(KERN_INFO, ha, + "Unable to allocate memory for EDC write.\n")); + return 0; + } + } + + dev = le16_to_cpup((void *)&buf[0]); + adr = le16_to_cpup((void *)&buf[2]); + opt = le16_to_cpup((void *)&buf[4]); + len = le16_to_cpup((void *)&buf[6]); + + if (!(opt & BIT_0)) + if (len == 0 || len > DMA_POOL_SIZE || len > count - 8) + return -EINVAL; + + memcpy(ha->edc_data, &buf[8], len); + + rval = qla2x00_write_edc(vha, dev, adr, ha->edc_data_dma, + ha->edc_data, len, opt); + if (rval != QLA_SUCCESS) { + DEBUG2(qla_printk(KERN_INFO, ha, + "Unable to write EDC (%x) %02x:%02x:%04x:%02x:%02x.\n", + rval, dev, adr, opt, len, *buf)); + return 0; + } + + return count; +} + +static struct bin_attribute sysfs_edc_attr = { + .attr = { + .name = "edc", + .mode = S_IWUSR, + }, + .size = 0, + .write = qla2x00_sysfs_write_edc, +}; + +static ssize_t +qla2x00_sysfs_write_edc_status(struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t off, size_t count) +{ + struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj, + struct device, kobj))); + struct qla_hw_data *ha = vha->hw; + uint16_t dev, adr, opt, len; + int rval; + + ha->edc_data_len = 0; + + if (!capable(CAP_SYS_ADMIN) || off != 0 || count < 8) + return 0; + + if (!ha->edc_data) { + ha->edc_data = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, + &ha->edc_data_dma); + if (!ha->edc_data) { + DEBUG2(qla_printk(KERN_INFO, ha, + "Unable to allocate memory for EDC status.\n")); + return 0; + } + } + + dev = le16_to_cpup((void *)&buf[0]); + adr = le16_to_cpup((void *)&buf[2]); + opt = le16_to_cpup((void *)&buf[4]); + len = le16_to_cpup((void *)&buf[6]); + + if (!(opt & BIT_0)) + if (len == 0 || len > DMA_POOL_SIZE) + return -EINVAL; + + memset(ha->edc_data, 0, len); + rval = qla2x00_read_edc(vha, dev, adr, ha->edc_data_dma, + ha->edc_data, len, opt); + if (rval != QLA_SUCCESS) { + DEBUG2(qla_printk(KERN_INFO, ha, + "Unable to write EDC status (%x) %02x:%02x:%04x:%02x.\n", + rval, dev, adr, opt, len)); + return 0; + } + + ha->edc_data_len = len; + + return count; +} + +static ssize_t +qla2x00_sysfs_read_edc_status(struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t off, size_t count) +{ + struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj, + struct device, kobj))); + struct qla_hw_data *ha = vha->hw; + + if (!capable(CAP_SYS_ADMIN) || off != 0 || count == 0) + return 0; + + if (!ha->edc_data || ha->edc_data_len == 0 || ha->edc_data_len > count) + return -EINVAL; + + memcpy(buf, ha->edc_data, ha->edc_data_len); + + return ha->edc_data_len; +} + +static struct bin_attribute sysfs_edc_status_attr = { + .attr = { + .name = "edc_status", + .mode = S_IRUSR | S_IWUSR, + }, + .size = 0, + .write = qla2x00_sysfs_write_edc_status, + .read = qla2x00_sysfs_read_edc_status, +}; + static struct sysfs_entry { char *name; struct bin_attribute *attr; @@ -476,6 +703,9 @@ static struct sysfs_entry { { "optrom_ctl", &sysfs_optrom_ctl_attr, }, { "vpd", &sysfs_vpd_attr, 1 }, { "sfp", &sysfs_sfp_attr, 1 }, + { "reset", &sysfs_reset_attr, }, + { "edc", &sysfs_edc_attr, 2 }, + { "edc_status", &sysfs_edc_status_attr, 2 }, { NULL }, }; @@ -489,6 +719,8 @@ qla2x00_alloc_sysfs_attr(scsi_qla_host_t *vha) for (iter = bin_file_entries; iter->name; iter++) { if (iter->is4GBp_only && !IS_FWI2_CAPABLE(vha->hw)) continue; + if (iter->is4GBp_only == 2 && !IS_QLA25XX(vha->hw)) + continue; ret = sysfs_create_bin_file(&host->shost_gendev.kobj, iter->attr); @@ -509,6 +741,8 @@ qla2x00_free_sysfs_attr(scsi_qla_host_t *vha) for (iter = bin_file_entries; iter->name; iter++) { if (iter->is4GBp_only && !IS_FWI2_CAPABLE(ha)) continue; + if (iter->is4GBp_only == 2 && !IS_QLA25XX(ha)) + continue; sysfs_remove_bin_file(&host->shost_gendev.kobj, iter->attr); @@ -825,9 +1059,33 @@ qla2x00_mpi_version_show(struct device *dev, struct device_attribute *attr, if (!IS_QLA81XX(ha)) return snprintf(buf, PAGE_SIZE, "\n"); - return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x (%x)\n", + return snprintf(buf, PAGE_SIZE, "%d.%02d.%02d (%x)\n", ha->mpi_version[0], ha->mpi_version[1], ha->mpi_version[2], - ha->mpi_version[3], ha->mpi_capabilities); + ha->mpi_capabilities); +} + +static ssize_t +qla2x00_phy_version_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); + struct qla_hw_data *ha = vha->hw; + + if (!IS_QLA81XX(ha)) + return snprintf(buf, PAGE_SIZE, "\n"); + + return snprintf(buf, PAGE_SIZE, "%d.%02d.%02d\n", + ha->phy_version[0], ha->phy_version[1], ha->phy_version[2]); +} + +static ssize_t +qla2x00_flash_block_size_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); + struct qla_hw_data *ha = vha->hw; + + return snprintf(buf, PAGE_SIZE, "0x%x\n", ha->fdt_block_size); } static DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_drvr_version_show, NULL); @@ -855,6 +1113,9 @@ static DEVICE_ATTR(optrom_fw_version, S_IRUGO, qla2x00_optrom_fw_version_show, static DEVICE_ATTR(total_isp_aborts, S_IRUGO, qla2x00_total_isp_aborts_show, NULL); static DEVICE_ATTR(mpi_version, S_IRUGO, qla2x00_mpi_version_show, NULL); +static DEVICE_ATTR(phy_version, S_IRUGO, qla2x00_phy_version_show, NULL); +static DEVICE_ATTR(flash_block_size, S_IRUGO, qla2x00_flash_block_size_show, + NULL); struct device_attribute *qla2x00_host_attrs[] = { &dev_attr_driver_version, @@ -875,6 +1136,8 @@ struct device_attribute *qla2x00_host_attrs[] = { &dev_attr_optrom_fw_version, &dev_attr_total_isp_aborts, &dev_attr_mpi_version, + &dev_attr_phy_version, + &dev_attr_flash_block_size, NULL, }; @@ -1019,7 +1282,10 @@ qla2x00_dev_loss_tmo_callbk(struct fc_rport *rport) if (!fcport) return; - qla2x00_abort_fcport_cmds(fcport); + if (unlikely(pci_channel_offline(fcport->vha->hw->pdev))) + qla2x00_abort_all_cmds(fcport->vha, DID_NO_CONNECT << 16); + else + qla2x00_abort_fcport_cmds(fcport); /* * Transport has effectively 'deleted' the rport, clear @@ -1039,16 +1305,18 @@ qla2x00_terminate_rport_io(struct fc_rport *rport) if (!fcport) return; + if (unlikely(pci_channel_offline(fcport->vha->hw->pdev))) { + qla2x00_abort_all_cmds(fcport->vha, DID_NO_CONNECT << 16); + return; + } /* * At this point all fcport's software-states are cleared. Perform any * final cleanup of firmware resources (PCBs and XCBs). */ - if (fcport->loop_id != FC_NO_LOOP_ID) { + if (fcport->loop_id != FC_NO_LOOP_ID) fcport->vha->hw->isp_ops->fabric_logout(fcport->vha, fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa); - fcport->loop_id = FC_NO_LOOP_ID; - } qla2x00_abort_fcport_cmds(fcport); } @@ -1265,13 +1533,6 @@ qla24xx_vport_delete(struct fc_vport *fc_vport) test_bit(FCPORT_UPDATE_NEEDED, &vha->dpc_flags)) msleep(1000); - if (ha->mqenable) { - if (qla25xx_delete_queues(vha, 0) != QLA_SUCCESS) - qla_printk(KERN_WARNING, ha, - "Queue delete failed.\n"); - vha->req_ques[0] = ha->req_q_map[0]->id; - } - qla24xx_disable_vp(vha); fc_remove_host(vha->host); @@ -1293,6 +1554,12 @@ qla24xx_vport_delete(struct fc_vport *fc_vport) vha->host_no, vha->vp_idx, vha)); } + if (ha->mqenable) { + if (qla25xx_delete_queues(vha, 0) != QLA_SUCCESS) + qla_printk(KERN_WARNING, ha, + "Queue delete failed.\n"); + } + scsi_host_put(vha->host); qla_printk(KERN_INFO, ha, "vport %d deleted\n", id); return 0; diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 023ee77fb02..714ee67567e 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -176,8 +176,7 @@ /* ISP request and response entry counts (37-65535) */ #define REQUEST_ENTRY_CNT_2100 128 /* Number of request entries. */ #define REQUEST_ENTRY_CNT_2200 2048 /* Number of request entries. */ -#define REQUEST_ENTRY_CNT_2XXX_EXT_MEM 4096 /* Number of request entries. */ -#define REQUEST_ENTRY_CNT_24XX 4096 /* Number of request entries. */ +#define REQUEST_ENTRY_CNT_24XX 2048 /* Number of request entries. */ #define RESPONSE_ENTRY_CNT_2100 64 /* Number of response entries.*/ #define RESPONSE_ENTRY_CNT_2300 512 /* Number of response entries.*/ @@ -201,20 +200,7 @@ typedef struct srb { /* * SRB flag definitions */ -#define SRB_TIMEOUT BIT_0 /* Command timed out */ -#define SRB_DMA_VALID BIT_1 /* Command sent to ISP */ -#define SRB_WATCHDOG BIT_2 /* Command on watchdog list */ -#define SRB_ABORT_PENDING BIT_3 /* Command abort sent to device */ - -#define SRB_ABORTED BIT_4 /* Command aborted command already */ -#define SRB_RETRY BIT_5 /* Command needs retrying */ -#define SRB_GOT_SENSE BIT_6 /* Command has sense data */ -#define SRB_FAILOVER BIT_7 /* Command in failover state */ - -#define SRB_BUSY BIT_8 /* Command is in busy retry state */ -#define SRB_FO_CANCEL BIT_9 /* Command don't need to do failover */ -#define SRB_IOCTL BIT_10 /* IOCTL command. */ -#define SRB_TAPE BIT_11 /* FCP2 (Tape) command. */ +#define SRB_DMA_VALID BIT_0 /* Command sent to ISP */ /* * ISP I/O Register Set structure definitions. @@ -372,10 +358,10 @@ struct device_reg_2xxx { }; struct device_reg_25xxmq { - volatile uint32_t req_q_in; - volatile uint32_t req_q_out; - volatile uint32_t rsp_q_in; - volatile uint32_t rsp_q_out; + uint32_t req_q_in; + uint32_t req_q_out; + uint32_t rsp_q_in; + uint32_t rsp_q_out; }; typedef union { @@ -620,6 +606,7 @@ typedef struct { #define MBC_GET_TIMEOUT_PARAMS 0x22 /* Get FW timeouts. */ #define MBC_TRACE_CONTROL 0x27 /* Trace control command. */ #define MBC_GEN_SYSTEM_ERROR 0x2a /* Generate System Error. */ +#define MBC_WRITE_SFP 0x30 /* Write SFP Data. */ #define MBC_READ_SFP 0x31 /* Read SFP Data. */ #define MBC_SET_TIMEOUT_PARAMS 0x32 /* Set FW timeouts. */ #define MBC_MID_INITIALIZE_FIRMWARE 0x48 /* MID Initialize firmware. */ @@ -1570,39 +1557,13 @@ typedef struct fc_port { #define FCS_DEVICE_DEAD 2 #define FCS_DEVICE_LOST 3 #define FCS_ONLINE 4 -#define FCS_NOT_SUPPORTED 5 -#define FCS_FAILOVER 6 -#define FCS_FAILOVER_FAILED 7 /* * FC port flags. */ #define FCF_FABRIC_DEVICE BIT_0 #define FCF_LOGIN_NEEDED BIT_1 -#define FCF_FO_MASKED BIT_2 -#define FCF_FAILOVER_NEEDED BIT_3 -#define FCF_RESET_NEEDED BIT_4 -#define FCF_PERSISTENT_BOUND BIT_5 -#define FCF_TAPE_PRESENT BIT_6 -#define FCF_FARP_DONE BIT_7 -#define FCF_FARP_FAILED BIT_8 -#define FCF_FARP_REPLY_NEEDED BIT_9 -#define FCF_AUTH_REQ BIT_10 -#define FCF_SEND_AUTH_REQ BIT_11 -#define FCF_RECEIVE_AUTH_REQ BIT_12 -#define FCF_AUTH_SUCCESS BIT_13 -#define FCF_RLC_SUPPORT BIT_14 -#define FCF_CONFIG BIT_15 /* Needed? */ -#define FCF_RESCAN_NEEDED BIT_16 -#define FCF_XP_DEVICE BIT_17 -#define FCF_MSA_DEVICE BIT_18 -#define FCF_EVA_DEVICE BIT_19 -#define FCF_MSA_PORT_ACTIVE BIT_20 -#define FCF_FAILBACK_DISABLE BIT_21 -#define FCF_FAILOVER_DISABLE BIT_22 -#define FCF_DSXXX_DEVICE BIT_23 -#define FCF_AA_EVA_DEVICE BIT_24 -#define FCF_AA_MSA_DEVICE BIT_25 +#define FCF_TAPE_PRESENT BIT_2 /* No loop ID flag. */ #define FC_NO_LOOP_ID 0x1000 @@ -2102,9 +2063,6 @@ struct isp_operations { int (*get_flash_version) (struct scsi_qla_host *, void *); int (*start_scsi) (srb_t *); - void (*wrt_req_reg) (struct qla_hw_data *, uint16_t, uint16_t); - void (*wrt_rsp_reg) (struct qla_hw_data *, uint16_t, uint16_t); - uint16_t (*rd_req_reg) (struct qla_hw_data *, uint16_t); }; /* MSI-X Support *************************************************************/ @@ -2135,6 +2093,7 @@ struct qla_msix_entry { /* Work events. */ enum qla_work_type { QLA_EVT_AEN, + QLA_EVT_IDC_ACK, }; @@ -2149,6 +2108,10 @@ struct qla_work_evt { enum fc_host_event_code code; u32 data; } aen; + struct { +#define QLA_IDC_ACK_REGS 7 + uint16_t mb[QLA_IDC_ACK_REGS]; + } idc_ack; } u; }; @@ -2195,6 +2158,8 @@ struct rsp_que { dma_addr_t dma; response_t *ring; response_t *ring_ptr; + uint32_t __iomem *rsp_q_in; /* FWI2-capable only. */ + uint32_t __iomem *rsp_q_out; uint16_t ring_index; uint16_t out_ptr; uint16_t length; @@ -2212,6 +2177,8 @@ struct req_que { dma_addr_t dma; request_t *ring; request_t *ring_ptr; + uint32_t __iomem *req_q_in; /* FWI2-capable only. */ + uint32_t __iomem *req_q_out; uint16_t ring_index; uint16_t in_ptr; uint16_t cnt; @@ -2251,10 +2218,10 @@ struct qla_hw_data { uint32_t msix_enabled :1; uint32_t disable_serdes :1; uint32_t gpsc_supported :1; - uint32_t vsan_enabled :1; uint32_t npiv_supported :1; uint32_t fce_enabled :1; - uint32_t hw_event_marker_found:1; + uint32_t fac_supported :1; + uint32_t chip_reset_done :1; } flags; /* This spinlock is used to protect "io transactions", you must @@ -2272,7 +2239,7 @@ struct qla_hw_data { #define MIN_IOBASE_LEN 0x100 /* Multi queue data structs */ - device_reg_t *mqiobase; + device_reg_t __iomem *mqiobase; uint16_t msix_count; uint8_t mqenable; struct req_que **req_q_map; @@ -2295,7 +2262,6 @@ struct qla_hw_data { uint16_t max_loop_id; uint16_t fb_rev; - uint16_t max_public_loop_ids; uint16_t min_external_loopid; /* First external loop Id */ #define PORT_SPEED_UNKNOWN 0xFFFF @@ -2376,6 +2342,8 @@ struct qla_hw_data { IS_QLA25XX(ha) || IS_QLA81XX(ha)) #define IS_NOPOLLING_TYPE(ha) ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && \ (ha)->flags.msix_enabled) +#define IS_FAC_REQUIRED(ha) (IS_QLA81XX(ha)) +#define IS_NOCACHE_VPD_TYPE(ha) (IS_QLA81XX(ha)) #define IS_IIDMA_CAPABLE(ha) ((ha)->device_type & DT_IIDMA) #define IS_FWI2_CAPABLE(ha) ((ha)->device_type & DT_FWI2) @@ -2420,6 +2388,10 @@ struct qla_hw_data { void *sfp_data; dma_addr_t sfp_data_dma; + uint8_t *edc_data; + dma_addr_t edc_data_dma; + uint16_t edc_data_len; + struct task_struct *dpc_thread; uint8_t dpc_active; /* DPC routine is active */ @@ -2434,6 +2406,8 @@ struct qla_hw_data { dma_addr_t init_cb_dma; init_cb_t *init_cb; int init_cb_size; + dma_addr_t ex_init_cb_dma; + struct ex_init_cb_81xx *ex_init_cb; /* These are used by mailbox operations. */ volatile uint16_t mailbox_out[MAILBOX_REGISTER_COUNT]; @@ -2448,15 +2422,6 @@ struct qla_hw_data { struct completion mbx_cmd_comp; /* Serialize mbx access */ struct completion mbx_intr_comp; /* Used for completion notification */ - uint32_t mbx_flags; -#define MBX_IN_PROGRESS BIT_0 -#define MBX_BUSY BIT_1 /* Got the Access */ -#define MBX_SLEEPING_ON_SEM BIT_2 -#define MBX_POLLING_FOR_COMP BIT_3 -#define MBX_COMPLETED BIT_4 -#define MBX_TIMEDOUT BIT_5 -#define MBX_ACCESS_TIMEDOUT BIT_6 - /* Basic firmware related information. */ uint16_t fw_major_version; uint16_t fw_minor_version; @@ -2468,13 +2433,15 @@ struct qla_hw_data { #define RISC_START_ADDRESS_2100 0x1000 #define RISC_START_ADDRESS_2300 0x800 #define RISC_START_ADDRESS_2400 0x100000 + uint16_t fw_xcb_count; uint16_t fw_options[16]; /* slots: 1,2,3,10,11 */ uint8_t fw_seriallink_options[4]; uint16_t fw_seriallink_options24[4]; - uint8_t mpi_version[4]; + uint8_t mpi_version[3]; uint32_t mpi_capabilities; + uint8_t phy_version[3]; /* Firmware dump information. */ struct qla2xxx_fw_dump *fw_dump; @@ -2540,6 +2507,8 @@ struct qla_hw_data { uint32_t flt_region_boot; uint32_t flt_region_fw; uint32_t flt_region_vpd_nvram; + uint32_t flt_region_vpd; + uint32_t flt_region_nvram; uint32_t flt_region_npiv_conf; /* Needed for BEACON */ @@ -2608,36 +2577,19 @@ typedef struct scsi_qla_host { #define LOOP_RESYNC_ACTIVE 5 #define LOCAL_LOOP_UPDATE 6 /* Perform a local loop update. */ #define RSCN_UPDATE 7 /* Perform an RSCN update. */ -#define MAILBOX_RETRY 8 -#define ISP_RESET_NEEDED 9 /* Initiate a ISP reset. */ -#define FAILOVER_EVENT_NEEDED 10 -#define FAILOVER_EVENT 11 -#define FAILOVER_NEEDED 12 -#define SCSI_RESTART_NEEDED 13 /* Processes SCSI retry queue. */ -#define PORT_RESTART_NEEDED 14 /* Processes Retry queue. */ -#define RESTART_QUEUES_NEEDED 15 /* Restarts the Lun queue. */ -#define ABORT_QUEUES_NEEDED 16 -#define RELOGIN_NEEDED 17 -#define LOGIN_RETRY_NEEDED 18 /* Initiate required fabric logins. */ -#define REGISTER_FC4_NEEDED 19 /* SNS FC4 registration required. */ -#define ISP_ABORT_RETRY 20 /* ISP aborted. */ -#define FCPORT_RESCAN_NEEDED 21 /* IO descriptor processing needed */ -#define IODESC_PROCESS_NEEDED 22 /* IO descriptor processing needed */ -#define IOCTL_ERROR_RECOVERY 23 -#define LOOP_RESET_NEEDED 24 -#define BEACON_BLINK_NEEDED 25 -#define REGISTER_FDMI_NEEDED 26 -#define FCPORT_UPDATE_NEEDED 27 -#define VP_DPC_NEEDED 28 /* wake up for VP dpc handling */ -#define UNLOADING 29 -#define NPIV_CONFIG_NEEDED 30 +#define RELOGIN_NEEDED 8 +#define REGISTER_FC4_NEEDED 9 /* SNS FC4 registration required. */ +#define ISP_ABORT_RETRY 10 /* ISP aborted. */ +#define BEACON_BLINK_NEEDED 11 +#define REGISTER_FDMI_NEEDED 12 +#define FCPORT_UPDATE_NEEDED 13 +#define VP_DPC_NEEDED 14 /* wake up for VP dpc handling */ +#define UNLOADING 15 +#define NPIV_CONFIG_NEEDED 16 uint32_t device_flags; -#define DFLG_LOCAL_DEVICES BIT_0 -#define DFLG_RETRY_LOCAL_DEVICES BIT_1 -#define DFLG_FABRIC_DEVICES BIT_2 -#define SWITCH_FOUND BIT_3 -#define DFLG_NO_CABLE BIT_4 +#define SWITCH_FOUND BIT_0 +#define DFLG_NO_CABLE BIT_1 srb_t *status_srb; /* Status continuation entry. */ @@ -2750,10 +2702,5 @@ typedef struct scsi_qla_host { #include "qla_inline.h" #define CMD_SP(Cmnd) ((Cmnd)->SCp.ptr) -#define CMD_COMPL_STATUS(Cmnd) ((Cmnd)->SCp.this_residual) -#define CMD_RESID_LEN(Cmnd) ((Cmnd)->SCp.buffers_residual) -#define CMD_SCSI_STATUS(Cmnd) ((Cmnd)->SCp.Status) -#define CMD_ACTUAL_SNSLEN(Cmnd) ((Cmnd)->SCp.Message) -#define CMD_ENTRY_STATUS(Cmnd) ((Cmnd)->SCp.have_data_in) #endif diff --git a/drivers/scsi/qla2xxx/qla_devtbl.h b/drivers/scsi/qla2xxx/qla_devtbl.h index d78d35e681a..d6ea69df7c5 100644 --- a/drivers/scsi/qla2xxx/qla_devtbl.h +++ b/drivers/scsi/qla2xxx/qla_devtbl.h @@ -72,7 +72,7 @@ static char *qla2x00_model_name[QLA_MODEL_NAMES*2] = { "QLA2462", "Sun PCI-X 2.0 to 4Gb FC, Dual Channel", /* 0x141 */ "QLE2460", "Sun PCI-Express to 2Gb FC, Single Channel", /* 0x142 */ "QLE2462", "Sun PCI-Express to 4Gb FC, Single Channel", /* 0x143 */ - "QEM2462" "Server I/O Module 4Gb FC, Dual Channel", /* 0x144 */ + "QEM2462", "Server I/O Module 4Gb FC, Dual Channel", /* 0x144 */ "QLE2440", "PCI-Express to 4Gb FC, Single Channel", /* 0x145 */ "QLE2464", "PCI-Express to 4Gb FC, Quad Channel", /* 0x146 */ "QLA2440", "PCI-X 2.0 to 4Gb FC, Single Channel", /* 0x147 */ diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c index c66036da7d2..3a9a6ca4226 100644 --- a/drivers/scsi/qla2xxx/qla_dfs.c +++ b/drivers/scsi/qla2xxx/qla_dfs.c @@ -71,7 +71,7 @@ qla2x00_dfs_fce_open(struct inode *inode, struct file *file) mutex_unlock(&ha->fce_mutex); out: - return single_open(file, qla2x00_dfs_fce_show, ha); + return single_open(file, qla2x00_dfs_fce_show, vha); } static int @@ -145,7 +145,7 @@ create_dir: atomic_inc(&qla2x00_dfs_root_count); create_nodes: - ha->dfs_fce = debugfs_create_file("fce", S_IRUSR, ha->dfs_dir, ha, + ha->dfs_fce = debugfs_create_file("fce", S_IRUSR, ha->dfs_dir, vha, &dfs_fce_ops); if (!ha->dfs_fce) { qla_printk(KERN_NOTICE, ha, diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h index 7abb045a041..96ccb9642ba 100644 --- a/drivers/scsi/qla2xxx/qla_fw.h +++ b/drivers/scsi/qla2xxx/qla_fw.h @@ -1402,6 +1402,23 @@ struct access_chip_rsp_84xx { #define MBA_IDC_NOTIFY 0x8101 #define MBA_IDC_TIME_EXT 0x8102 +#define MBC_IDC_ACK 0x101 +#define MBC_RESTART_MPI_FW 0x3d +#define MBC_FLASH_ACCESS_CTRL 0x3e /* Control flash access. */ + +/* Flash access control option field bit definitions */ +#define FAC_OPT_FORCE_SEMAPHORE BIT_15 +#define FAC_OPT_REQUESTOR_ID BIT_14 +#define FAC_OPT_CMD_SUBCODE 0xff + +/* Flash access control command subcodes */ +#define FAC_OPT_CMD_WRITE_PROTECT 0x00 +#define FAC_OPT_CMD_WRITE_ENABLE 0x01 +#define FAC_OPT_CMD_ERASE_SECTOR 0x02 +#define FAC_OPT_CMD_LOCK_SEMAPHORE 0x03 +#define FAC_OPT_CMD_UNLOCK_SEMAPHORE 0x04 +#define FAC_OPT_CMD_GET_SECTOR_SIZE 0x05 + struct nvram_81xx { /* NVRAM header. */ uint8_t id[4]; @@ -1438,7 +1455,17 @@ struct nvram_81xx { uint16_t reserved_6[24]; /* Offset 128. */ - uint16_t reserved_7[64]; + uint16_t ex_version; + uint8_t prio_fcf_matching_flags; + uint8_t reserved_6_1[3]; + uint16_t pri_fcf_vlan_id; + uint8_t pri_fcf_fabric_name[8]; + uint16_t reserved_6_2[7]; + uint8_t spma_mac_addr[6]; + uint16_t reserved_6_3[14]; + + /* Offset 192. */ + uint16_t reserved_7[32]; /* * BIT 0 = Enable spinup delay @@ -1662,6 +1689,17 @@ struct mid_init_cb_81xx { struct mid_conf_entry_24xx entries[MAX_MULTI_ID_FABRIC]; }; +struct ex_init_cb_81xx { + uint16_t ex_version; + uint8_t prio_fcf_matching_flags; + uint8_t reserved_1[3]; + uint16_t pri_fcf_vlan_id; + uint8_t pri_fcf_fabric_name[8]; + uint16_t reserved_2[7]; + uint8_t spma_mac_addr[6]; + uint16_t reserved_3[14]; +}; + #define FARX_ACCESS_FLASH_CONF_81XX 0x7FFD0000 #define FARX_ACCESS_FLASH_DATA_81XX 0x7F800000 @@ -1670,6 +1708,10 @@ struct mid_init_cb_81xx { #define FA_RISC_CODE_ADDR_81 0xA0000 #define FA_FW_AREA_ADDR_81 0xC0000 #define FA_VPD_NVRAM_ADDR_81 0xD0000 +#define FA_VPD0_ADDR_81 0xD0000 +#define FA_VPD1_ADDR_81 0xD0400 +#define FA_NVRAM0_ADDR_81 0xD0080 +#define FA_NVRAM1_ADDR_81 0xD0480 #define FA_FEATURE_ADDR_81 0xD4000 #define FA_FLASH_DESCR_ADDR_81 0xD8000 #define FA_FLASH_LAYOUT_ADDR_81 0xD8400 diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index a336b4bc81a..528913f6bed 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -72,6 +72,8 @@ extern int qla2x00_loop_reset(scsi_qla_host_t *); extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int); extern int qla2x00_post_aen_work(struct scsi_qla_host *, enum fc_host_event_code, u32); +extern int qla2x00_post_idc_ack_work(struct scsi_qla_host *, uint16_t *); +extern int qla81xx_restart_mpi_firmware(scsi_qla_host_t *); extern void qla2x00_abort_fcport_cmds(fc_port_t *); extern struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *, @@ -81,7 +83,7 @@ extern void qla2x00_relogin(struct scsi_qla_host *); /* * Global Functions in qla_mid.c source file. */ -extern struct scsi_host_template qla24xx_driver_template; +extern struct scsi_host_template qla2xxx_driver_template; extern struct scsi_transport_template *qla2xxx_transport_vport_template; extern void qla2x00_timer(scsi_qla_host_t *); extern void qla2x00_start_timer(scsi_qla_host_t *, void *, unsigned long); @@ -109,6 +111,7 @@ extern void qla2x00_mark_all_devices_lost(scsi_qla_host_t *, int); extern struct fw_blob *qla2x00_request_firmware(scsi_qla_host_t *); extern int qla2x00_wait_for_hba_online(scsi_qla_host_t *); +extern int qla2x00_wait_for_chip_reset(scsi_qla_host_t *); extern void qla2xxx_wake_dpc(struct scsi_qla_host *); extern void qla2x00_alert_all_vps(struct rsp_que *, uint16_t *); @@ -143,8 +146,8 @@ extern int qla2x00_execute_fw(scsi_qla_host_t *, uint32_t); extern void -qla2x00_get_fw_version(scsi_qla_host_t *, uint16_t *, - uint16_t *, uint16_t *, uint16_t *, uint32_t *, uint8_t *, uint32_t *); +qla2x00_get_fw_version(scsi_qla_host_t *, uint16_t *, uint16_t *, uint16_t *, + uint16_t *, uint32_t *, uint8_t *, uint32_t *, uint8_t *); extern int qla2x00_get_fw_options(scsi_qla_host_t *, uint16_t *); @@ -262,10 +265,29 @@ extern int qla2x00_read_sfp(scsi_qla_host_t *, dma_addr_t, uint16_t, uint16_t, uint16_t); extern int +qla2x00_read_edc(scsi_qla_host_t *, uint16_t, uint16_t, dma_addr_t, + uint8_t *, uint16_t, uint16_t); + +extern int +qla2x00_write_edc(scsi_qla_host_t *, uint16_t, uint16_t, dma_addr_t, + uint8_t *, uint16_t, uint16_t); + +extern int qla2x00_set_idma_speed(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t *); extern int qla84xx_verify_chip(struct scsi_qla_host *, uint16_t *); +extern int qla81xx_idc_ack(scsi_qla_host_t *, uint16_t *); + +extern int +qla81xx_fac_get_sector_size(scsi_qla_host_t *, uint32_t *); + +extern int +qla81xx_fac_do_write_enable(scsi_qla_host_t *, int); + +extern int +qla81xx_fac_erase_sector(scsi_qla_host_t *, uint32_t, uint32_t); + /* * Global Function Prototypes in qla_isr.c source file. */ @@ -376,10 +398,8 @@ extern int qla2x00_dfs_remove(scsi_qla_host_t *); /* Globa function prototypes for multi-q */ extern int qla25xx_request_irq(struct rsp_que *); -extern int qla25xx_init_req_que(struct scsi_qla_host *, struct req_que *, - uint8_t); -extern int qla25xx_init_rsp_que(struct scsi_qla_host *, struct rsp_que *, - uint8_t); +extern int qla25xx_init_req_que(struct scsi_qla_host *, struct req_que *); +extern int qla25xx_init_rsp_que(struct scsi_qla_host *, struct rsp_que *); extern int qla25xx_create_req_que(struct qla_hw_data *, uint16_t, uint8_t, uint16_t, uint8_t, uint8_t); extern int qla25xx_create_rsp_que(struct qla_hw_data *, uint16_t, uint8_t, diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index f6368a1d302..bd7dd84c064 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -20,7 +20,6 @@ * QLogic ISP2x00 Hardware Support Function Prototypes. */ static int qla2x00_isp_firmware(scsi_qla_host_t *); -static void qla2x00_resize_request_q(scsi_qla_host_t *); static int qla2x00_setup_chip(scsi_qla_host_t *); static int qla2x00_init_rings(scsi_qla_host_t *); static int qla2x00_fw_ready(scsi_qla_host_t *); @@ -61,8 +60,10 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha) int rval; struct qla_hw_data *ha = vha->hw; struct req_que *req = ha->req_q_map[0]; + /* Clear adapter flags. */ vha->flags.online = 0; + ha->flags.chip_reset_done = 0; vha->flags.reset_active = 0; atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME); atomic_set(&vha->loop_state, LOOP_DOWN); @@ -70,7 +71,6 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha) vha->dpc_flags = 0; vha->flags.management_server_logged_in = 0; vha->marker_needed = 0; - ha->mbx_flags = 0; ha->isp_abort_cnt = 0; ha->beacon_blink_led = 0; set_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags); @@ -131,6 +131,7 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha) } } rval = qla2x00_init_rings(vha); + ha->flags.chip_reset_done = 1; return (rval); } @@ -512,7 +513,6 @@ qla2x00_reset_chip(scsi_qla_host_t *vha) static inline void qla24xx_reset_risc(scsi_qla_host_t *vha) { - int hw_evt = 0; unsigned long flags = 0; struct qla_hw_data *ha = vha->hw; struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; @@ -542,8 +542,6 @@ qla24xx_reset_risc(scsi_qla_host_t *vha) d2 = (uint32_t) RD_REG_WORD(®->mailbox0); barrier(); } - if (cnt == 0) - hw_evt = 1; /* Wait for soft-reset to complete. */ d2 = RD_REG_DWORD(®->ctrl_status); @@ -816,7 +814,7 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha) qla_printk(KERN_INFO, ha, "Allocated (%d KB) for FCE...\n", FCE_SIZE / 1024); - fce_size = sizeof(struct qla2xxx_fce_chain) + EFT_SIZE; + fce_size = sizeof(struct qla2xxx_fce_chain) + FCE_SIZE; ha->flags.fce_enabled = 1; ha->fce_dma = tc_dma; ha->fce = tc; @@ -894,62 +892,6 @@ cont_alloc: } /** - * qla2x00_resize_request_q() - Resize request queue given available ISP memory. - * @ha: HA context - * - * Returns 0 on success. - */ -static void -qla2x00_resize_request_q(scsi_qla_host_t *vha) -{ - int rval; - uint16_t fw_iocb_cnt = 0; - uint16_t request_q_length = REQUEST_ENTRY_CNT_2XXX_EXT_MEM; - dma_addr_t request_dma; - request_t *request_ring; - struct qla_hw_data *ha = vha->hw; - struct req_que *req = ha->req_q_map[0]; - - /* Valid only on recent ISPs. */ - if (IS_QLA2100(ha) || IS_QLA2200(ha)) - return; - - /* Retrieve IOCB counts available to the firmware. */ - rval = qla2x00_get_resource_cnts(vha, NULL, NULL, NULL, &fw_iocb_cnt, - &ha->max_npiv_vports); - if (rval) - return; - /* No point in continuing if current settings are sufficient. */ - if (fw_iocb_cnt < 1024) - return; - if (req->length >= request_q_length) - return; - - /* Attempt to claim larger area for request queue. */ - request_ring = dma_alloc_coherent(&ha->pdev->dev, - (request_q_length + 1) * sizeof(request_t), &request_dma, - GFP_KERNEL); - if (request_ring == NULL) - return; - - /* Resize successful, report extensions. */ - qla_printk(KERN_INFO, ha, "Extended memory detected (%d KB)...\n", - (ha->fw_memory_size + 1) / 1024); - qla_printk(KERN_INFO, ha, "Resizing request queue depth " - "(%d -> %d)...\n", req->length, request_q_length); - - /* Clear old allocations. */ - dma_free_coherent(&ha->pdev->dev, - (req->length + 1) * sizeof(request_t), req->ring, - req->dma); - - /* Begin using larger queue. */ - req->length = request_q_length; - req->ring = request_ring; - req->dma = request_dma; -} - -/** * qla2x00_setup_chip() - Load and start RISC firmware. * @ha: HA context * @@ -963,6 +905,7 @@ qla2x00_setup_chip(scsi_qla_host_t *vha) struct qla_hw_data *ha = vha->hw; struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; unsigned long flags; + uint16_t fw_major_version; if (!IS_FWI2_CAPABLE(ha) && !IS_QLA2100(ha) && !IS_QLA2200(ha)) { /* Disable SRAM, Instruction RAM and GP RAM parity. */ @@ -986,13 +929,15 @@ qla2x00_setup_chip(scsi_qla_host_t *vha) rval = qla2x00_execute_fw(vha, srisc_address); /* Retrieve firmware information. */ - if (rval == QLA_SUCCESS && ha->fw_major_version == 0) { + if (rval == QLA_SUCCESS) { + fw_major_version = ha->fw_major_version; qla2x00_get_fw_version(vha, &ha->fw_major_version, &ha->fw_minor_version, &ha->fw_subminor_version, &ha->fw_attributes, &ha->fw_memory_size, - ha->mpi_version, &ha->mpi_capabilities); + ha->mpi_version, &ha->mpi_capabilities, + ha->phy_version); ha->flags.npiv_supported = 0; if (IS_QLA2XXX_MIDTYPE(ha) && (ha->fw_attributes & BIT_2)) { @@ -1003,9 +948,11 @@ qla2x00_setup_chip(scsi_qla_host_t *vha) ha->max_npiv_vports = MIN_MULTI_ID_FABRIC - 1; } - qla2x00_resize_request_q(vha); + qla2x00_get_resource_cnts(vha, NULL, + &ha->fw_xcb_count, NULL, NULL, + &ha->max_npiv_vports); - if (ql2xallocfwdump) + if (!fw_major_version && ql2xallocfwdump) qla2x00_alloc_fw_dump(vha); } } else { @@ -1028,6 +975,21 @@ qla2x00_setup_chip(scsi_qla_host_t *vha) spin_unlock_irqrestore(&ha->hardware_lock, flags); } + if (rval == QLA_SUCCESS && IS_FAC_REQUIRED(ha)) { + uint32_t size; + + rval = qla81xx_fac_get_sector_size(vha, &size); + if (rval == QLA_SUCCESS) { + ha->flags.fac_supported = 1; + ha->fdt_block_size = size << 2; + } else { + qla_printk(KERN_ERR, ha, + "Unsupported FAC firmware (%d.%02d.%02d).\n", + ha->fw_major_version, ha->fw_minor_version, + ha->fw_subminor_version); + } + } + if (rval) { DEBUG2_3(printk("scsi(%ld): Setup chip **** FAILED ****.\n", vha->host_no)); @@ -1226,9 +1188,8 @@ qla24xx_config_rings(struct scsi_qla_host *vha) icb->firmware_options_2 |= __constant_cpu_to_le32(BIT_18); - icb->firmware_options_2 |= __constant_cpu_to_le32(BIT_22); + icb->firmware_options_2 &= __constant_cpu_to_le32(~BIT_22); icb->firmware_options_2 |= __constant_cpu_to_le32(BIT_23); - ha->rsp_q_map[0]->options = icb->firmware_options_2; WRT_REG_DWORD(®->isp25mq.req_q_in, 0); WRT_REG_DWORD(®->isp25mq.req_q_out, 0); @@ -1309,10 +1270,17 @@ qla2x00_init_rings(scsi_qla_host_t *vha) DEBUG(printk("scsi(%ld): Issue init firmware.\n", vha->host_no)); - if (ha->flags.npiv_supported) + if (ha->flags.npiv_supported) { + if (ha->operating_mode == LOOP) + ha->max_npiv_vports = MIN_MULTI_ID_FABRIC - 1; mid_init_cb->count = cpu_to_le16(ha->max_npiv_vports); + } - mid_init_cb->options = __constant_cpu_to_le16(BIT_1); + if (IS_FWI2_CAPABLE(ha)) { + mid_init_cb->options = __constant_cpu_to_le16(BIT_1); + mid_init_cb->init_cb.execution_throttle = + cpu_to_le16(ha->fw_xcb_count); + } rval = qla2x00_init_firmware(vha, ha->init_cb_size); if (rval) { @@ -1986,7 +1954,6 @@ qla2x00_alloc_fcport(scsi_qla_host_t *vha, gfp_t flags) fcport->port_type = FCT_UNKNOWN; fcport->loop_id = FC_NO_LOOP_ID; atomic_set(&fcport->state, FCS_UNCONFIGURED); - fcport->flags = FCF_RLC_SUPPORT; fcport->supported_classes = FC_COS_UNSPECIFIED; return fcport; @@ -2168,7 +2135,6 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha) vha->host_no, fcport->loop_id)); atomic_set(&fcport->state, FCS_DEVICE_LOST); - fcport->flags &= ~FCF_FARP_DONE; } } @@ -2225,8 +2191,7 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha) WWN_SIZE)) continue; - fcport->flags &= ~(FCF_FABRIC_DEVICE | - FCF_PERSISTENT_BOUND); + fcport->flags &= ~FCF_FABRIC_DEVICE; fcport->loop_id = new_fcport->loop_id; fcport->port_type = new_fcport->port_type; fcport->d_id.b24 = new_fcport->d_id.b24; @@ -2239,7 +2204,6 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha) if (!found) { /* New device, add to fcports list. */ - new_fcport->flags &= ~FCF_PERSISTENT_BOUND; if (vha->vp_idx) { new_fcport->vha = vha; new_fcport->vp_idx = vha->vp_idx; @@ -2272,11 +2236,6 @@ cleanup_allocation: "rval=%x\n", vha->host_no, rval)); } - if (found_devs) { - vha->device_flags |= DFLG_LOCAL_DEVICES; - vha->device_flags &= ~DFLG_RETRY_LOCAL_DEVICES; - } - return (rval); } @@ -2611,6 +2570,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha, port_id_t wrap, nxt_d_id; struct qla_hw_data *ha = vha->hw; struct scsi_qla_host *vp, *base_vha = pci_get_drvdata(ha->pdev); + struct scsi_qla_host *tvp; rval = QLA_SUCCESS; @@ -2710,7 +2670,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha, /* Bypass virtual ports of the same host. */ found = 0; if (ha->num_vhosts) { - list_for_each_entry(vp, &ha->vp_list, list) { + list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) { if (new_fcport->d_id.b24 == vp->d_id.b24) { found = 1; break; @@ -2761,7 +2721,6 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha, fcport->loop_id = FC_NO_LOOP_ID; fcport->flags |= (FCF_FABRIC_DEVICE | FCF_LOGIN_NEEDED); - fcport->flags &= ~FCF_PERSISTENT_BOUND; break; } @@ -2804,9 +2763,6 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha, kfree(swl); kfree(new_fcport); - if (!list_empty(new_fcports)) - vha->device_flags |= DFLG_FABRIC_DEVICES; - return (rval); } @@ -2833,6 +2789,7 @@ qla2x00_find_new_loop_id(scsi_qla_host_t *vha, fc_port_t *dev) uint16_t first_loop_id; struct qla_hw_data *ha = vha->hw; struct scsi_qla_host *vp; + struct scsi_qla_host *tvp; rval = QLA_SUCCESS; @@ -2857,7 +2814,7 @@ qla2x00_find_new_loop_id(scsi_qla_host_t *vha, fc_port_t *dev) /* Check for loop ID being already in use. */ found = 0; fcport = NULL; - list_for_each_entry(vp, &ha->vp_list, list) { + list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) { list_for_each_entry(fcport, &vp->vp_fcports, list) { if (fcport->loop_id == dev->loop_id && fcport != dev) { @@ -2988,7 +2945,6 @@ qla2x00_device_resync(scsi_qla_host_t *vha) 0, 0); } } - fcport->flags &= ~FCF_FARP_DONE; } } return (rval); @@ -3292,10 +3248,12 @@ qla2x00_abort_isp(scsi_qla_host_t *vha) uint8_t status = 0; struct qla_hw_data *ha = vha->hw; struct scsi_qla_host *vp; + struct scsi_qla_host *tvp; struct req_que *req = ha->req_q_map[0]; if (vha->flags.online) { vha->flags.online = 0; + ha->flags.chip_reset_done = 0; clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); ha->qla_stats.total_isp_aborts++; @@ -3307,7 +3265,7 @@ qla2x00_abort_isp(scsi_qla_host_t *vha) if (atomic_read(&vha->loop_state) != LOOP_DOWN) { atomic_set(&vha->loop_state, LOOP_DOWN); qla2x00_mark_all_devices_lost(vha, 0); - list_for_each_entry(vp, &ha->vp_list, list) + list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) qla2x00_mark_all_devices_lost(vp, 0); } else { if (!atomic_read(&vha->loop_down_timer)) @@ -3404,7 +3362,7 @@ qla2x00_abort_isp(scsi_qla_host_t *vha) DEBUG(printk(KERN_INFO "qla2x00_abort_isp(%ld): succeeded.\n", vha->host_no)); - list_for_each_entry(vp, &ha->vp_list, list) { + list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) { if (vp->vp_idx) qla2x00_vp_abort_isp(vp); } @@ -3429,7 +3387,7 @@ qla2x00_abort_isp(scsi_qla_host_t *vha) static int qla2x00_restart_isp(scsi_qla_host_t *vha) { - uint8_t status = 0; + int status = 0; uint32_t wait_time; struct qla_hw_data *ha = vha->hw; struct req_que *req = ha->req_q_map[0]; @@ -3445,6 +3403,7 @@ qla2x00_restart_isp(scsi_qla_host_t *vha) if (!status && !(status = qla2x00_init_rings(vha))) { clear_bit(RESET_MARKER_NEEDED, &vha->dpc_flags); + ha->flags.chip_reset_done = 1; /* Initialize the queues in use */ qla25xx_init_queues(ha); @@ -3493,7 +3452,7 @@ qla25xx_init_queues(struct qla_hw_data *ha) rsp = ha->rsp_q_map[i]; if (rsp) { rsp->options &= ~BIT_0; - ret = qla25xx_init_rsp_que(base_vha, rsp, rsp->options); + ret = qla25xx_init_rsp_que(base_vha, rsp); if (ret != QLA_SUCCESS) DEBUG2_17(printk(KERN_WARNING "%s Rsp que:%d init failed\n", __func__, @@ -3507,7 +3466,7 @@ qla25xx_init_queues(struct qla_hw_data *ha) if (req) { /* Clear outstanding commands array. */ req->options &= ~BIT_0; - ret = qla25xx_init_req_que(base_vha, req, req->options); + ret = qla25xx_init_req_que(base_vha, req); if (ret != QLA_SUCCESS) DEBUG2_17(printk(KERN_WARNING "%s Req que:%d init failed\n", __func__, @@ -4332,23 +4291,17 @@ qla81xx_nvram_config(scsi_qla_host_t *vha) /* Determine NVRAM starting address. */ ha->nvram_size = sizeof(struct nvram_81xx); - ha->nvram_base = FA_NVRAM_FUNC0_ADDR; ha->vpd_size = FA_NVRAM_VPD_SIZE; - ha->vpd_base = FA_NVRAM_VPD0_ADDR; - if (PCI_FUNC(ha->pdev->devfn) & 1) { - ha->nvram_base = FA_NVRAM_FUNC1_ADDR; - ha->vpd_base = FA_NVRAM_VPD1_ADDR; - } /* Get VPD data into cache */ ha->vpd = ha->nvram + VPD_OFFSET; - ha->isp_ops->read_nvram(vha, (uint8_t *)ha->vpd, - ha->nvram_base - FA_NVRAM_FUNC0_ADDR, FA_NVRAM_VPD_SIZE * 4); + ha->isp_ops->read_optrom(vha, ha->vpd, ha->flt_region_vpd << 2, + ha->vpd_size); /* Get NVRAM data into cache and calculate checksum. */ - dptr = (uint32_t *)nv; - ha->isp_ops->read_nvram(vha, (uint8_t *)dptr, ha->nvram_base, + ha->isp_ops->read_optrom(vha, ha->nvram, ha->flt_region_nvram << 2, ha->nvram_size); + dptr = (uint32_t *)nv; for (cnt = 0, chksum = 0; cnt < ha->nvram_size >> 2; cnt++) chksum += le32_to_cpu(*dptr++); @@ -4446,6 +4399,9 @@ qla81xx_nvram_config(scsi_qla_host_t *vha) icb->enode_mac[5] = 0x06 + PCI_FUNC(ha->pdev->devfn); } + /* Use extended-initialization control block. */ + memcpy(ha->ex_init_cb, &nv->ex_version, sizeof(*ha->ex_init_cb)); + /* * Setup driver NVRAM options. */ diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 2258152b1f4..a8abbb95730 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -776,7 +776,7 @@ qla24xx_start_scsi(srb_t *sp) req_cnt = qla24xx_calc_iocbs(tot_dsds); if (req->cnt < (req_cnt + 2)) { - cnt = ha->isp_ops->rd_req_reg(ha, req->id); + cnt = RD_REG_DWORD_RELAXED(req->req_q_out); if (req->ring_index < cnt) req->cnt = cnt - req->ring_index; @@ -836,7 +836,8 @@ qla24xx_start_scsi(srb_t *sp) sp->flags |= SRB_DMA_VALID; /* Set chip new ring index. */ - ha->isp_ops->wrt_req_reg(ha, req->id, req->ring_index); + WRT_REG_DWORD(req->req_q_in, req->ring_index); + RD_REG_DWORD_RELAXED(&ha->iobase->isp24.hccr); /* Manage unprocessed RIO/ZIO commands in response queue. */ if (vha->flags.process_response_queue && @@ -854,35 +855,3 @@ queuing_error: return QLA_FUNCTION_FAILED; } - -uint16_t -qla24xx_rd_req_reg(struct qla_hw_data *ha, uint16_t id) -{ - device_reg_t __iomem *reg = (void *) ha->iobase; - return RD_REG_DWORD_RELAXED(®->isp24.req_q_out); -} - -uint16_t -qla25xx_rd_req_reg(struct qla_hw_data *ha, uint16_t id) -{ - device_reg_t __iomem *reg = (void *) ha->mqiobase + QLA_QUE_PAGE * id; - return RD_REG_DWORD_RELAXED(®->isp25mq.req_q_out); -} - -void -qla24xx_wrt_req_reg(struct qla_hw_data *ha, uint16_t id, uint16_t index) -{ - device_reg_t __iomem *reg = (void *) ha->iobase; - WRT_REG_DWORD(®->isp24.req_q_in, index); - RD_REG_DWORD_RELAXED(®->isp24.req_q_in); -} - -void -qla25xx_wrt_req_reg(struct qla_hw_data *ha, uint16_t id, uint16_t index) -{ - device_reg_t __iomem *reg = (void *) ha->mqiobase + QLA_QUE_PAGE * id; - struct device_reg_2xxx __iomem *ioreg = &ha->iobase->isp; - WRT_REG_DWORD(®->isp25mq.req_q_in, index); - RD_REG_DWORD(&ioreg->hccr); /* PCI posting */ -} - diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index e28ad81baf1..d04981848e5 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -266,6 +266,40 @@ qla2x00_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0) } } +static void +qla81xx_idc_event(scsi_qla_host_t *vha, uint16_t aen, uint16_t descr) +{ + static char *event[] = + { "Complete", "Request Notification", "Time Extension" }; + int rval; + struct device_reg_24xx __iomem *reg24 = &vha->hw->iobase->isp24; + uint16_t __iomem *wptr; + uint16_t cnt, timeout, mb[QLA_IDC_ACK_REGS]; + + /* Seed data -- mailbox1 -> mailbox7. */ + wptr = (uint16_t __iomem *)®24->mailbox1; + for (cnt = 0; cnt < QLA_IDC_ACK_REGS; cnt++, wptr++) + mb[cnt] = RD_REG_WORD(wptr); + + DEBUG2(printk("scsi(%ld): Inter-Driver Commucation %s -- " + "%04x %04x %04x %04x %04x %04x %04x.\n", vha->host_no, + event[aen & 0xff], + mb[0], mb[1], mb[2], mb[3], mb[4], mb[5], mb[6])); + + /* Acknowledgement needed? [Notify && non-zero timeout]. */ + timeout = (descr >> 8) & 0xf; + if (aen != MBA_IDC_NOTIFY || !timeout) + return; + + DEBUG2(printk("scsi(%ld): Inter-Driver Commucation %s -- " + "ACK timeout=%d.\n", vha->host_no, event[aen & 0xff], timeout)); + + rval = qla2x00_post_idc_ack_work(vha, mb); + if (rval != QLA_SUCCESS) + qla_printk(KERN_WARNING, vha->hw, + "IDC failed to post ACK.\n"); +} + /** * qla2x00_async_event() - Process aynchronous events. * @ha: SCSI driver HA context @@ -714,21 +748,9 @@ skip_rio: "%04x %04x %04x\n", vha->host_no, mb[1], mb[2], mb[3])); break; case MBA_IDC_COMPLETE: - DEBUG2(printk("scsi(%ld): Inter-Driver Commucation " - "Complete -- %04x %04x %04x\n", vha->host_no, mb[1], mb[2], - mb[3])); - break; case MBA_IDC_NOTIFY: - DEBUG2(printk("scsi(%ld): Inter-Driver Commucation " - "Request Notification -- %04x %04x %04x\n", vha->host_no, - mb[1], mb[2], mb[3])); - /**** Mailbox registers 4 - 7 valid!!! */ - break; case MBA_IDC_TIME_EXT: - DEBUG2(printk("scsi(%ld): Inter-Driver Commucation " - "Time Extension -- %04x %04x %04x\n", vha->host_no, mb[1], - mb[2], mb[3])); - /**** Mailbox registers 4 - 7 valid!!! */ + qla81xx_idc_event(vha, mb[0], mb[1]); break; } @@ -830,9 +852,6 @@ qla2x00_process_completed_request(struct scsi_qla_host *vha, /* Free outstanding command slot. */ req->outstanding_cmds[index] = NULL; - CMD_COMPL_STATUS(sp->cmd) = 0L; - CMD_SCSI_STATUS(sp->cmd) = 0L; - /* Save ISP completion status */ sp->cmd->result = DID_OK << 16; @@ -933,7 +952,6 @@ qla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t sense_len) if (sense_len >= SCSI_SENSE_BUFFERSIZE) sense_len = SCSI_SENSE_BUFFERSIZE; - CMD_ACTUAL_SNSLEN(cp) = sense_len; sp->request_sense_length = sense_len; sp->request_sense_ptr = cp->sense_buffer; if (sp->request_sense_length > 32) @@ -951,8 +969,7 @@ qla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t sense_len) cp->device->channel, cp->device->id, cp->device->lun, cp, cp->serial_number)); if (sense_len) - DEBUG5(qla2x00_dump_buffer(cp->sense_buffer, - CMD_ACTUAL_SNSLEN(cp))); + DEBUG5(qla2x00_dump_buffer(cp->sense_buffer, sense_len)); } /** @@ -1021,9 +1038,6 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) } lscsi_status = scsi_status & STATUS_MASK; - CMD_ENTRY_STATUS(cp) = sts->entry_status; - CMD_COMPL_STATUS(cp) = comp_status; - CMD_SCSI_STATUS(cp) = scsi_status; fcport = sp->fcport; @@ -1082,7 +1096,6 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) if (scsi_status & (SS_RESIDUAL_UNDER | SS_RESIDUAL_OVER)) { resid = resid_len; scsi_set_resid(cp, resid); - CMD_RESID_LEN(cp) = resid; if (!lscsi_status && ((unsigned)(scsi_bufflen(cp) - resid) < @@ -1138,7 +1151,6 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) if (scsi_status & SS_RESIDUAL_UNDER) { scsi_set_resid(cp, resid); - CMD_RESID_LEN(cp) = resid; } else { DEBUG2(printk(KERN_INFO "scsi(%ld:%d:%d) UNDERRUN status detected " @@ -1477,7 +1489,6 @@ qla24xx_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0) void qla24xx_process_response_queue(struct rsp_que *rsp) { - struct qla_hw_data *ha = rsp->hw; struct sts_entry_24xx *pkt; struct scsi_qla_host *vha; @@ -1531,7 +1542,7 @@ qla24xx_process_response_queue(struct rsp_que *rsp) } /* Adjust ring index */ - ha->isp_ops->wrt_rsp_reg(ha, rsp->id, rsp->ring_index); + WRT_REG_DWORD(rsp->rsp_q_out, rsp->ring_index); } static void @@ -1707,7 +1718,6 @@ qla25xx_msix_rsp_q(int irq, void *dev_id) struct qla_hw_data *ha; struct rsp_que *rsp; struct device_reg_24xx __iomem *reg; - uint16_t msix_disabled_hccr = 0; rsp = (struct rsp_que *) dev_id; if (!rsp) { @@ -1720,17 +1730,8 @@ qla25xx_msix_rsp_q(int irq, void *dev_id) spin_lock_irq(&ha->hardware_lock); - msix_disabled_hccr = rsp->options; - if (!rsp->id) - msix_disabled_hccr &= __constant_cpu_to_le32(BIT_22); - else - msix_disabled_hccr &= __constant_cpu_to_le32(BIT_6); - qla24xx_process_response_queue(rsp); - if (!msix_disabled_hccr) - WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT); - spin_unlock_irq(&ha->hardware_lock); return IRQ_HANDLED; @@ -2017,7 +2018,7 @@ skip_msix: skip_msi: ret = request_irq(ha->pdev->irq, ha->isp_ops->intr_handler, - IRQF_DISABLED|IRQF_SHARED, QLA2XXX_DRIVER_NAME, rsp); + IRQF_SHARED, QLA2XXX_DRIVER_NAME, rsp); if (ret) { qla_printk(KERN_WARNING, ha, "Failed to reserve interrupt %d already in use.\n", @@ -2105,18 +2106,3 @@ int qla25xx_request_irq(struct rsp_que *rsp) msix->rsp = rsp; return ret; } - -void -qla25xx_wrt_rsp_reg(struct qla_hw_data *ha, uint16_t id, uint16_t index) -{ - device_reg_t __iomem *reg = (void *) ha->mqiobase + QLA_QUE_PAGE * id; - WRT_REG_DWORD(®->isp25mq.rsp_q_out, index); -} - -void -qla24xx_wrt_rsp_reg(struct qla_hw_data *ha, uint16_t id, uint16_t index) -{ - device_reg_t __iomem *reg = (void *) ha->iobase; - WRT_REG_DWORD(®->isp24.rsp_q_out, index); -} - diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index f94ffbb98e9..e67c1660bf4 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -45,6 +45,9 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) struct qla_hw_data *ha = vha->hw; scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); + if (ha->pdev->error_state > pci_channel_io_frozen) + return QLA_FUNCTION_TIMEOUT; + reg = ha->iobase; io_lock_on = base_vha->flags.init_done; @@ -408,7 +411,7 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr) void qla2x00_get_fw_version(scsi_qla_host_t *vha, uint16_t *major, uint16_t *minor, uint16_t *subminor, uint16_t *attributes, uint32_t *memory, uint8_t *mpi, - uint32_t *mpi_caps) + uint32_t *mpi_caps, uint8_t *phy) { int rval; mbx_cmd_t mc; @@ -420,7 +423,7 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha, uint16_t *major, uint16_t *minor, mcp->out_mb = MBX_0; mcp->in_mb = MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; if (IS_QLA81XX(vha->hw)) - mcp->in_mb |= MBX_13|MBX_12|MBX_11|MBX_10; + mcp->in_mb |= MBX_13|MBX_12|MBX_11|MBX_10|MBX_9|MBX_8; mcp->flags = 0; mcp->tov = MBX_TOV_SECONDS; rval = qla2x00_mailbox_command(vha, mcp); @@ -435,11 +438,13 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha, uint16_t *major, uint16_t *minor, else *memory = (mcp->mb[5] << 16) | mcp->mb[4]; if (IS_QLA81XX(vha->hw)) { - mpi[0] = mcp->mb[10] >> 8; - mpi[1] = mcp->mb[10] & 0xff; - mpi[2] = mcp->mb[11] >> 8; - mpi[3] = mcp->mb[11] & 0xff; + mpi[0] = mcp->mb[10] & 0xff; + mpi[1] = mcp->mb[11] >> 8; + mpi[2] = mcp->mb[11] & 0xff; *mpi_caps = (mcp->mb[12] << 16) | mcp->mb[13]; + phy[0] = mcp->mb[8] & 0xff; + phy[1] = mcp->mb[9] >> 8; + phy[2] = mcp->mb[9] & 0xff; } if (rval != QLA_SUCCESS) { @@ -1043,14 +1048,22 @@ qla2x00_init_firmware(scsi_qla_host_t *vha, uint16_t size) else mcp->mb[0] = MBC_INITIALIZE_FIRMWARE; + mcp->mb[1] = 0; mcp->mb[2] = MSW(ha->init_cb_dma); mcp->mb[3] = LSW(ha->init_cb_dma); - mcp->mb[4] = 0; - mcp->mb[5] = 0; mcp->mb[6] = MSW(MSD(ha->init_cb_dma)); mcp->mb[7] = LSW(MSD(ha->init_cb_dma)); - mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_0; - mcp->in_mb = MBX_5|MBX_4|MBX_0; + mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; + if (IS_QLA81XX(ha) && ha->ex_init_cb->ex_version) { + mcp->mb[1] = BIT_0; + mcp->mb[10] = MSW(ha->ex_init_cb_dma); + mcp->mb[11] = LSW(ha->ex_init_cb_dma); + mcp->mb[12] = MSW(MSD(ha->ex_init_cb_dma)); + mcp->mb[13] = LSW(MSD(ha->ex_init_cb_dma)); + mcp->mb[14] = sizeof(*ha->ex_init_cb); + mcp->out_mb |= MBX_14|MBX_13|MBX_12|MBX_11|MBX_10; + } + mcp->in_mb = MBX_0; mcp->buf_size = size; mcp->flags = MBX_DMA_OUT; mcp->tov = MBX_TOV_SECONDS; @@ -1187,10 +1200,6 @@ qla2x00_get_port_database(scsi_qla_host_t *vha, fc_port_t *fcport, uint8_t opt) fcport->d_id.b.al_pa = pd->port_id[2]; fcport->d_id.b.rsvd_1 = 0; - /* Check for device require authentication. */ - pd->common_features & BIT_5 ? (fcport->flags |= FCF_AUTH_REQ) : - (fcport->flags &= ~FCF_AUTH_REQ); - /* If not target must be initiator or unknown type. */ if ((pd->prli_svc_param_word_3[0] & BIT_4) == 0) fcport->port_type = FCT_INITIATOR; @@ -2685,6 +2694,7 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha, uint16_t stat = le16_to_cpu(rptid_entry->vp_idx); struct qla_hw_data *ha = vha->hw; scsi_qla_host_t *vp; + scsi_qla_host_t *tvp; if (rptid_entry->entry_status != 0) return; @@ -2710,7 +2720,7 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha, if (MSB(stat) == 1) return; - list_for_each_entry(vp, &ha->vp_list, list) + list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) if (vp_idx == vp->vp_idx) break; if (!vp) @@ -3090,8 +3100,7 @@ verify_done: } int -qla25xx_init_req_que(struct scsi_qla_host *vha, struct req_que *req, - uint8_t options) +qla25xx_init_req_que(struct scsi_qla_host *vha, struct req_que *req) { int rval; unsigned long flags; @@ -3101,7 +3110,7 @@ qla25xx_init_req_que(struct scsi_qla_host *vha, struct req_que *req, struct qla_hw_data *ha = vha->hw; mcp->mb[0] = MBC_INITIALIZE_MULTIQ; - mcp->mb[1] = options; + mcp->mb[1] = req->options; mcp->mb[2] = MSW(LSD(req->dma)); mcp->mb[3] = LSW(LSD(req->dma)); mcp->mb[6] = MSW(MSD(req->dma)); @@ -3128,7 +3137,7 @@ qla25xx_init_req_que(struct scsi_qla_host *vha, struct req_que *req, mcp->tov = 60; spin_lock_irqsave(&ha->hardware_lock, flags); - if (!(options & BIT_0)) { + if (!(req->options & BIT_0)) { WRT_REG_DWORD(®->req_q_in, 0); WRT_REG_DWORD(®->req_q_out, 0); } @@ -3142,8 +3151,7 @@ qla25xx_init_req_que(struct scsi_qla_host *vha, struct req_que *req, } int -qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp, - uint8_t options) +qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp) { int rval; unsigned long flags; @@ -3153,7 +3161,7 @@ qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp, struct qla_hw_data *ha = vha->hw; mcp->mb[0] = MBC_INITIALIZE_MULTIQ; - mcp->mb[1] = options; + mcp->mb[1] = rsp->options; mcp->mb[2] = MSW(LSD(rsp->dma)); mcp->mb[3] = LSW(LSD(rsp->dma)); mcp->mb[6] = MSW(MSD(rsp->dma)); @@ -3178,7 +3186,7 @@ qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp, mcp->tov = 60; spin_lock_irqsave(&ha->hardware_lock, flags); - if (!(options & BIT_0)) { + if (!(rsp->options & BIT_0)) { WRT_REG_DWORD(®->rsp_q_out, 0); WRT_REG_DWORD(®->rsp_q_in, 0); } @@ -3193,3 +3201,230 @@ qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp, return rval; } +int +qla81xx_idc_ack(scsi_qla_host_t *vha, uint16_t *mb) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no)); + + mcp->mb[0] = MBC_IDC_ACK; + memcpy(&mcp->mb[1], mb, QLA_IDC_ACK_REGS * sizeof(uint16_t)); + mcp->out_mb = MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; + mcp->in_mb = MBX_0; + mcp->tov = MBX_TOV_SECONDS; + mcp->flags = 0; + rval = qla2x00_mailbox_command(vha, mcp); + + if (rval != QLA_SUCCESS) { + DEBUG2_3_11(printk("%s(%ld): failed=%x (%x).\n", __func__, + vha->host_no, rval, mcp->mb[0])); + } else { + DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no)); + } + + return rval; +} + +int +qla81xx_fac_get_sector_size(scsi_qla_host_t *vha, uint32_t *sector_size) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + if (!IS_QLA81XX(vha->hw)) + return QLA_FUNCTION_FAILED; + + DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no)); + + mcp->mb[0] = MBC_FLASH_ACCESS_CTRL; + mcp->mb[1] = FAC_OPT_CMD_GET_SECTOR_SIZE; + mcp->out_mb = MBX_1|MBX_0; + mcp->in_mb = MBX_1|MBX_0; + mcp->tov = MBX_TOV_SECONDS; + mcp->flags = 0; + rval = qla2x00_mailbox_command(vha, mcp); + + if (rval != QLA_SUCCESS) { + DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x.\n", + __func__, vha->host_no, rval, mcp->mb[0], mcp->mb[1])); + } else { + DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no)); + *sector_size = mcp->mb[1]; + } + + return rval; +} + +int +qla81xx_fac_do_write_enable(scsi_qla_host_t *vha, int enable) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + if (!IS_QLA81XX(vha->hw)) + return QLA_FUNCTION_FAILED; + + DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no)); + + mcp->mb[0] = MBC_FLASH_ACCESS_CTRL; + mcp->mb[1] = enable ? FAC_OPT_CMD_WRITE_ENABLE : + FAC_OPT_CMD_WRITE_PROTECT; + mcp->out_mb = MBX_1|MBX_0; + mcp->in_mb = MBX_1|MBX_0; + mcp->tov = MBX_TOV_SECONDS; + mcp->flags = 0; + rval = qla2x00_mailbox_command(vha, mcp); + + if (rval != QLA_SUCCESS) { + DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x.\n", + __func__, vha->host_no, rval, mcp->mb[0], mcp->mb[1])); + } else { + DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no)); + } + + return rval; +} + +int +qla81xx_fac_erase_sector(scsi_qla_host_t *vha, uint32_t start, uint32_t finish) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + if (!IS_QLA81XX(vha->hw)) + return QLA_FUNCTION_FAILED; + + DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no)); + + mcp->mb[0] = MBC_FLASH_ACCESS_CTRL; + mcp->mb[1] = FAC_OPT_CMD_ERASE_SECTOR; + mcp->mb[2] = LSW(start); + mcp->mb[3] = MSW(start); + mcp->mb[4] = LSW(finish); + mcp->mb[5] = MSW(finish); + mcp->out_mb = MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; + mcp->in_mb = MBX_2|MBX_1|MBX_0; + mcp->tov = MBX_TOV_SECONDS; + mcp->flags = 0; + rval = qla2x00_mailbox_command(vha, mcp); + + if (rval != QLA_SUCCESS) { + DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x " + "mb[2]=%x.\n", __func__, vha->host_no, rval, mcp->mb[0], + mcp->mb[1], mcp->mb[2])); + } else { + DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no)); + } + + return rval; +} + +int +qla81xx_restart_mpi_firmware(scsi_qla_host_t *vha) +{ + int rval = 0; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no)); + + mcp->mb[0] = MBC_RESTART_MPI_FW; + mcp->out_mb = MBX_0; + mcp->in_mb = MBX_0|MBX_1; + mcp->tov = MBX_TOV_SECONDS; + mcp->flags = 0; + rval = qla2x00_mailbox_command(vha, mcp); + + if (rval != QLA_SUCCESS) { + DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=0x%x mb[1]=0x%x.\n", + __func__, vha->host_no, rval, mcp->mb[0], mcp->mb[1])); + } else { + DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no)); + } + + return rval; +} + +int +qla2x00_read_edc(scsi_qla_host_t *vha, uint16_t dev, uint16_t adr, + dma_addr_t sfp_dma, uint8_t *sfp, uint16_t len, uint16_t opt) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no)); + + mcp->mb[0] = MBC_READ_SFP; + mcp->mb[1] = dev; + mcp->mb[2] = MSW(sfp_dma); + mcp->mb[3] = LSW(sfp_dma); + mcp->mb[6] = MSW(MSD(sfp_dma)); + mcp->mb[7] = LSW(MSD(sfp_dma)); + mcp->mb[8] = len; + mcp->mb[9] = adr; + mcp->mb[10] = opt; + mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; + mcp->in_mb = MBX_0; + mcp->tov = MBX_TOV_SECONDS; + mcp->flags = 0; + rval = qla2x00_mailbox_command(vha, mcp); + + if (opt & BIT_0) + if (sfp) + *sfp = mcp->mb[8]; + + if (rval != QLA_SUCCESS) { + DEBUG2_3_11(printk("%s(%ld): failed=%x (%x).\n", __func__, + vha->host_no, rval, mcp->mb[0])); + } else { + DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); + } + + return rval; +} + +int +qla2x00_write_edc(scsi_qla_host_t *vha, uint16_t dev, uint16_t adr, + dma_addr_t sfp_dma, uint8_t *sfp, uint16_t len, uint16_t opt) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no)); + + if (opt & BIT_0) + if (sfp) + len = *sfp; + + mcp->mb[0] = MBC_WRITE_SFP; + mcp->mb[1] = dev; + mcp->mb[2] = MSW(sfp_dma); + mcp->mb[3] = LSW(sfp_dma); + mcp->mb[6] = MSW(MSD(sfp_dma)); + mcp->mb[7] = LSW(MSD(sfp_dma)); + mcp->mb[8] = len; + mcp->mb[9] = adr; + mcp->mb[10] = opt; + mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; + mcp->in_mb = MBX_0; + mcp->tov = MBX_TOV_SECONDS; + mcp->flags = 0; + rval = qla2x00_mailbox_command(vha, mcp); + + if (rval != QLA_SUCCESS) { + DEBUG2_3_11(printk("%s(%ld): failed=%x (%x).\n", __func__, + vha->host_no, rval, mcp->mb[0])); + } else { + DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no)); + } + + return rval; +} diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c index f53179c4642..51716c7e300 100644 --- a/drivers/scsi/qla2xxx/qla_mid.c +++ b/drivers/scsi/qla2xxx/qla_mid.c @@ -69,9 +69,10 @@ static scsi_qla_host_t * qla24xx_find_vhost_by_name(struct qla_hw_data *ha, uint8_t *port_name) { scsi_qla_host_t *vha; + struct scsi_qla_host *tvha; /* Locate matching device in database. */ - list_for_each_entry(vha, &ha->vp_list, list) { + list_for_each_entry_safe(vha, tvha, &ha->vp_list, list) { if (!memcmp(port_name, vha->port_name, WWN_SIZE)) return vha; } @@ -194,11 +195,11 @@ qla24xx_configure_vp(scsi_qla_host_t *vha) void qla2x00_alert_all_vps(struct rsp_que *rsp, uint16_t *mb) { - scsi_qla_host_t *vha; + scsi_qla_host_t *vha, *tvha; struct qla_hw_data *ha = rsp->hw; int i = 0; - list_for_each_entry(vha, &ha->vp_list, list) { + list_for_each_entry_safe(vha, tvha, &ha->vp_list, list) { if (vha->vp_idx) { switch (mb[0]) { case MBA_LIP_OCCURRED: @@ -300,6 +301,7 @@ qla2x00_do_dpc_all_vps(scsi_qla_host_t *vha) int ret; struct qla_hw_data *ha = vha->hw; scsi_qla_host_t *vp; + struct scsi_qla_host *tvp; if (vha->vp_idx) return; @@ -308,7 +310,7 @@ qla2x00_do_dpc_all_vps(scsi_qla_host_t *vha) clear_bit(VP_DPC_NEEDED, &vha->dpc_flags); - list_for_each_entry(vp, &ha->vp_list, list) { + list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) { if (vp->vp_idx) ret = qla2x00_do_dpc_vp(vp); } @@ -357,7 +359,7 @@ qla24xx_create_vhost(struct fc_vport *fc_vport) scsi_qla_host_t *base_vha = shost_priv(fc_vport->shost); struct qla_hw_data *ha = base_vha->hw; scsi_qla_host_t *vha; - struct scsi_host_template *sht = &qla24xx_driver_template; + struct scsi_host_template *sht = &qla2xxx_driver_template; struct Scsi_Host *host; vha = qla2x00_create_host(sht, ha); @@ -396,7 +398,7 @@ qla24xx_create_vhost(struct fc_vport *fc_vport) qla2x00_start_timer(vha, qla2x00_timer, WATCH_INTERVAL); - memset(vha->req_ques, 0, sizeof(vha->req_ques) * QLA_MAX_HOST_QUES); + memset(vha->req_ques, 0, sizeof(vha->req_ques)); vha->req_ques[0] = ha->req_q_map[0]->id; host->can_queue = ha->req_q_map[0]->length + 128; host->this_id = 255; @@ -471,7 +473,7 @@ qla25xx_delete_req_que(struct scsi_qla_host *vha, struct req_que *req) if (req) { req->options |= BIT_0; - ret = qla25xx_init_req_que(vha, req, req->options); + ret = qla25xx_init_req_que(vha, req); } if (ret == QLA_SUCCESS) qla25xx_free_req_que(vha, req); @@ -486,7 +488,7 @@ qla25xx_delete_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp) if (rsp) { rsp->options |= BIT_0; - ret = qla25xx_init_rsp_que(vha, rsp, rsp->options); + ret = qla25xx_init_rsp_que(vha, rsp); } if (ret == QLA_SUCCESS) qla25xx_free_rsp_que(vha, rsp); @@ -502,7 +504,7 @@ int qla25xx_update_req_que(struct scsi_qla_host *vha, uint8_t que, uint8_t qos) req->options |= BIT_3; req->qos = qos; - ret = qla25xx_init_req_que(vha, req, req->options); + ret = qla25xx_init_req_que(vha, req); if (ret != QLA_SUCCESS) DEBUG2_17(printk(KERN_WARNING "%s failed\n", __func__)); /* restore options bit */ @@ -582,6 +584,7 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options, struct req_que *req = NULL; struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); uint16_t que_id = 0; + device_reg_t __iomem *reg; req = kzalloc(sizeof(struct req_que), GFP_KERNEL); if (req == NULL) { @@ -629,10 +632,13 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options, req->ring_index = 0; req->cnt = req->length; req->id = que_id; + reg = ISP_QUE_REG(ha, que_id); + req->req_q_in = ®->isp25mq.req_q_in; + req->req_q_out = ®->isp25mq.req_q_out; req->max_q_depth = ha->req_q_map[0]->max_q_depth; mutex_unlock(&ha->vport_lock); - ret = qla25xx_init_req_que(base_vha, req, options); + ret = qla25xx_init_req_que(base_vha, req); if (ret != QLA_SUCCESS) { qla_printk(KERN_WARNING, ha, "%s failed\n", __func__); mutex_lock(&ha->vport_lock); @@ -656,7 +662,8 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options, int ret = 0; struct rsp_que *rsp = NULL; struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); - uint16_t que_id = 0;; + uint16_t que_id = 0; + device_reg_t __iomem *reg; rsp = kzalloc(sizeof(struct rsp_que), GFP_KERNEL); if (rsp == NULL) { @@ -704,13 +711,16 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options, rsp->ring_ptr = rsp->ring; rsp->ring_index = 0; rsp->id = que_id; + reg = ISP_QUE_REG(ha, que_id); + rsp->rsp_q_in = ®->isp25mq.rsp_q_in; + rsp->rsp_q_out = ®->isp25mq.rsp_q_out; mutex_unlock(&ha->vport_lock); ret = qla25xx_request_irq(rsp); if (ret) goto que_failed; - ret = qla25xx_init_rsp_que(base_vha, rsp, options); + ret = qla25xx_init_rsp_que(base_vha, rsp); if (ret != QLA_SUCCESS) { qla_printk(KERN_WARNING, ha, "%s failed\n", __func__); mutex_lock(&ha->vport_lock); diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index c11f872d3e1..efe29924e05 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -104,9 +104,7 @@ static int qla2xxx_slave_alloc(struct scsi_device *); static int qla2xxx_scan_finished(struct Scsi_Host *, unsigned long time); static void qla2xxx_scan_start(struct Scsi_Host *); static void qla2xxx_slave_destroy(struct scsi_device *); -static int qla2x00_queuecommand(struct scsi_cmnd *cmd, - void (*fn)(struct scsi_cmnd *)); -static int qla24xx_queuecommand(struct scsi_cmnd *cmd, +static int qla2xxx_queuecommand(struct scsi_cmnd *cmd, void (*fn)(struct scsi_cmnd *)); static int qla2xxx_eh_abort(struct scsi_cmnd *); static int qla2xxx_eh_device_reset(struct scsi_cmnd *); @@ -117,42 +115,10 @@ static int qla2xxx_eh_host_reset(struct scsi_cmnd *); static int qla2x00_change_queue_depth(struct scsi_device *, int); static int qla2x00_change_queue_type(struct scsi_device *, int); -static struct scsi_host_template qla2x00_driver_template = { +struct scsi_host_template qla2xxx_driver_template = { .module = THIS_MODULE, .name = QLA2XXX_DRIVER_NAME, - .queuecommand = qla2x00_queuecommand, - - .eh_abort_handler = qla2xxx_eh_abort, - .eh_device_reset_handler = qla2xxx_eh_device_reset, - .eh_target_reset_handler = qla2xxx_eh_target_reset, - .eh_bus_reset_handler = qla2xxx_eh_bus_reset, - .eh_host_reset_handler = qla2xxx_eh_host_reset, - - .slave_configure = qla2xxx_slave_configure, - - .slave_alloc = qla2xxx_slave_alloc, - .slave_destroy = qla2xxx_slave_destroy, - .scan_finished = qla2xxx_scan_finished, - .scan_start = qla2xxx_scan_start, - .change_queue_depth = qla2x00_change_queue_depth, - .change_queue_type = qla2x00_change_queue_type, - .this_id = -1, - .cmd_per_lun = 3, - .use_clustering = ENABLE_CLUSTERING, - .sg_tablesize = SG_ALL, - - /* - * The RISC allows for each command to transfer (2^32-1) bytes of data, - * which equates to 0x800000 sectors. - */ - .max_sectors = 0xFFFF, - .shost_attrs = qla2x00_host_attrs, -}; - -struct scsi_host_template qla24xx_driver_template = { - .module = THIS_MODULE, - .name = QLA2XXX_DRIVER_NAME, - .queuecommand = qla24xx_queuecommand, + .queuecommand = qla2xxx_queuecommand, .eh_abort_handler = qla2xxx_eh_abort, .eh_device_reset_handler = qla2xxx_eh_device_reset, @@ -430,73 +396,7 @@ qla2x00_get_new_sp(scsi_qla_host_t *vha, fc_port_t *fcport, } static int -qla2x00_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) -{ - scsi_qla_host_t *vha = shost_priv(cmd->device->host); - fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata; - struct fc_rport *rport = starget_to_rport(scsi_target(cmd->device)); - struct qla_hw_data *ha = vha->hw; - srb_t *sp; - int rval; - - if (unlikely(pci_channel_offline(ha->pdev))) { - cmd->result = DID_REQUEUE << 16; - goto qc_fail_command; - } - - rval = fc_remote_port_chkready(rport); - if (rval) { - cmd->result = rval; - goto qc_fail_command; - } - - /* Close window on fcport/rport state-transitioning. */ - if (fcport->drport) - goto qc_target_busy; - - if (atomic_read(&fcport->state) != FCS_ONLINE) { - if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD || - atomic_read(&vha->loop_state) == LOOP_DEAD) { - cmd->result = DID_NO_CONNECT << 16; - goto qc_fail_command; - } - goto qc_target_busy; - } - - spin_unlock_irq(vha->host->host_lock); - - sp = qla2x00_get_new_sp(vha, fcport, cmd, done); - if (!sp) - goto qc_host_busy_lock; - - rval = ha->isp_ops->start_scsi(sp); - if (rval != QLA_SUCCESS) - goto qc_host_busy_free_sp; - - spin_lock_irq(vha->host->host_lock); - - return 0; - -qc_host_busy_free_sp: - qla2x00_sp_free_dma(sp); - mempool_free(sp, ha->srb_mempool); - -qc_host_busy_lock: - spin_lock_irq(vha->host->host_lock); - return SCSI_MLQUEUE_HOST_BUSY; - -qc_target_busy: - return SCSI_MLQUEUE_TARGET_BUSY; - -qc_fail_command: - done(cmd); - - return 0; -} - - -static int -qla24xx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) +qla2xxx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) { scsi_qla_host_t *vha = shost_priv(cmd->device->host); fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata; @@ -507,7 +407,10 @@ qla24xx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) int rval; if (unlikely(pci_channel_offline(ha->pdev))) { - cmd->result = DID_REQUEUE << 16; + if (ha->pdev->error_state == pci_channel_io_frozen) + cmd->result = DID_REQUEUE << 16; + else + cmd->result = DID_NO_CONNECT << 16; goto qc24_fail_command; } @@ -635,6 +538,34 @@ qla2x00_wait_for_hba_online(scsi_qla_host_t *vha) return (return_status); } +int +qla2x00_wait_for_chip_reset(scsi_qla_host_t *vha) +{ + int return_status; + unsigned long wait_reset; + struct qla_hw_data *ha = vha->hw; + scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); + + wait_reset = jiffies + (MAX_LOOP_TIMEOUT * HZ); + while (((test_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags)) || + test_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags) || + test_bit(ISP_ABORT_RETRY, &base_vha->dpc_flags) || + ha->dpc_active) && time_before(jiffies, wait_reset)) { + + msleep(1000); + + if (!test_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags) && + ha->flags.chip_reset_done) + break; + } + if (ha->flags.chip_reset_done) + return_status = QLA_SUCCESS; + else + return_status = QLA_FUNCTION_FAILED; + + return return_status; +} + /* * qla2x00_wait_for_loop_ready * Wait for MAX_LOOP_TIMEOUT(5 min) value for loop @@ -1163,7 +1094,7 @@ qla2x00_abort_all_cmds(scsi_qla_host_t *vha, int res) continue; for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { sp = req->outstanding_cmds[cnt]; - if (sp && sp->fcport->vha == vha) { + if (sp) { req->outstanding_cmds[cnt] = NULL; sp->cmd->result = res; qla2x00_sp_compl(ha, sp); @@ -1351,9 +1282,6 @@ static struct isp_operations qla2100_isp_ops = { .write_optrom = qla2x00_write_optrom_data, .get_flash_version = qla2x00_get_flash_version, .start_scsi = qla2x00_start_scsi, - .wrt_req_reg = NULL, - .wrt_rsp_reg = NULL, - .rd_req_reg = NULL, }; static struct isp_operations qla2300_isp_ops = { @@ -1389,9 +1317,6 @@ static struct isp_operations qla2300_isp_ops = { .write_optrom = qla2x00_write_optrom_data, .get_flash_version = qla2x00_get_flash_version, .start_scsi = qla2x00_start_scsi, - .wrt_req_reg = NULL, - .wrt_rsp_reg = NULL, - .rd_req_reg = NULL, }; static struct isp_operations qla24xx_isp_ops = { @@ -1427,9 +1352,6 @@ static struct isp_operations qla24xx_isp_ops = { .write_optrom = qla24xx_write_optrom_data, .get_flash_version = qla24xx_get_flash_version, .start_scsi = qla24xx_start_scsi, - .wrt_req_reg = qla24xx_wrt_req_reg, - .wrt_rsp_reg = qla24xx_wrt_rsp_reg, - .rd_req_reg = qla24xx_rd_req_reg, }; static struct isp_operations qla25xx_isp_ops = { @@ -1465,9 +1387,6 @@ static struct isp_operations qla25xx_isp_ops = { .write_optrom = qla24xx_write_optrom_data, .get_flash_version = qla24xx_get_flash_version, .start_scsi = qla24xx_start_scsi, - .wrt_req_reg = qla24xx_wrt_req_reg, - .wrt_rsp_reg = qla24xx_wrt_rsp_reg, - .rd_req_reg = qla24xx_rd_req_reg, }; static struct isp_operations qla81xx_isp_ops = { @@ -1493,8 +1412,8 @@ static struct isp_operations qla81xx_isp_ops = { .build_iocbs = NULL, .prep_ms_iocb = qla24xx_prep_ms_iocb, .prep_ms_fdmi_iocb = qla24xx_prep_ms_fdmi_iocb, - .read_nvram = qla25xx_read_nvram_data, - .write_nvram = qla25xx_write_nvram_data, + .read_nvram = NULL, + .write_nvram = NULL, .fw_dump = qla81xx_fw_dump, .beacon_on = qla24xx_beacon_on, .beacon_off = qla24xx_beacon_off, @@ -1503,9 +1422,6 @@ static struct isp_operations qla81xx_isp_ops = { .write_optrom = qla24xx_write_optrom_data, .get_flash_version = qla24xx_get_flash_version, .start_scsi = qla24xx_start_scsi, - .wrt_req_reg = qla24xx_wrt_req_reg, - .wrt_rsp_reg = qla24xx_wrt_rsp_reg, - .rd_req_reg = qla24xx_rd_req_reg, }; static inline void @@ -1727,7 +1643,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) struct rsp_que *rsp = NULL; bars = pci_select_bars(pdev, IORESOURCE_MEM | IORESOURCE_IO); - sht = &qla2x00_driver_template; + sht = &qla2xxx_driver_template; if (pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2422 || pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2432 || pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8432 || @@ -1736,7 +1652,6 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2532 || pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8001) { bars = pci_select_bars(pdev, IORESOURCE_MEM); - sht = &qla24xx_driver_template; mem_only = 1; } @@ -1927,10 +1842,16 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) ha->rsp_q_map[0] = rsp; ha->req_q_map[0] = req; + /* FWI2-capable only. */ + req->req_q_in = &ha->iobase->isp24.req_q_in; + req->req_q_out = &ha->iobase->isp24.req_q_out; + rsp->rsp_q_in = &ha->iobase->isp24.rsp_q_in; + rsp->rsp_q_out = &ha->iobase->isp24.rsp_q_out; if (ha->mqenable) { - ha->isp_ops->wrt_req_reg = qla25xx_wrt_req_reg; - ha->isp_ops->wrt_rsp_reg = qla25xx_wrt_rsp_reg; - ha->isp_ops->rd_req_reg = qla25xx_rd_req_reg; + req->req_q_in = &ha->mqiobase->isp25mq.req_q_in; + req->req_q_out = &ha->mqiobase->isp25mq.req_q_out; + rsp->rsp_q_in = &ha->mqiobase->isp25mq.rsp_q_in; + rsp->rsp_q_out = &ha->mqiobase->isp25mq.rsp_q_out; } if (qla2x00_initialize_adapter(base_vha)) { @@ -2000,6 +1921,16 @@ probe_init_failed: ha->max_queues = 0; probe_failed: + if (base_vha->timer_active) + qla2x00_stop_timer(base_vha); + base_vha->flags.online = 0; + if (ha->dpc_thread) { + struct task_struct *t = ha->dpc_thread; + + ha->dpc_thread = NULL; + kthread_stop(t); + } + qla2x00_free_device(base_vha); scsi_host_put(base_vha->host); @@ -2033,10 +1964,30 @@ qla2x00_remove_one(struct pci_dev *pdev) set_bit(UNLOADING, &base_vha->dpc_flags); + qla2x00_abort_all_cmds(base_vha, DID_NO_CONNECT << 16); + qla2x00_dfs_remove(base_vha); qla84xx_put_chip(base_vha); + /* Disable timer */ + if (base_vha->timer_active) + qla2x00_stop_timer(base_vha); + + base_vha->flags.online = 0; + + /* Kill the kernel thread for this host */ + if (ha->dpc_thread) { + struct task_struct *t = ha->dpc_thread; + + /* + * qla2xxx_wake_dpc checks for ->dpc_thread + * so we need to zero it out. + */ + ha->dpc_thread = NULL; + kthread_stop(t); + } + qla2x00_free_sysfs_attr(base_vha); fc_remove_host(base_vha->host); @@ -2065,25 +2016,6 @@ static void qla2x00_free_device(scsi_qla_host_t *vha) { struct qla_hw_data *ha = vha->hw; - qla2x00_abort_all_cmds(vha, DID_NO_CONNECT << 16); - - /* Disable timer */ - if (vha->timer_active) - qla2x00_stop_timer(vha); - - vha->flags.online = 0; - - /* Kill the kernel thread for this host */ - if (ha->dpc_thread) { - struct task_struct *t = ha->dpc_thread; - - /* - * qla2xxx_wake_dpc checks for ->dpc_thread - * so we need to zero it out. - */ - ha->dpc_thread = NULL; - kthread_stop(t); - } if (ha->flags.fce_enabled) qla2x00_disable_fce_trace(vha, NULL, NULL); @@ -2222,10 +2154,6 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len, { char name[16]; - ha->init_cb_size = sizeof(init_cb_t); - if (IS_QLA2XXX_MIDTYPE(ha)) - ha->init_cb_size = sizeof(struct mid_init_cb_24xx); - ha->init_cb = dma_alloc_coherent(&ha->pdev->dev, ha->init_cb_size, &ha->init_cb_dma, GFP_KERNEL); if (!ha->init_cb) @@ -2317,9 +2245,19 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len, } else ha->npiv_info = NULL; + /* Get consistent memory allocated for EX-INIT-CB. */ + if (IS_QLA81XX(ha)) { + ha->ex_init_cb = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, + &ha->ex_init_cb_dma); + if (!ha->ex_init_cb) + goto fail_ex_init_cb; + } + INIT_LIST_HEAD(&ha->vp_list); return 1; +fail_ex_init_cb: + kfree(ha->npiv_info); fail_npiv_info: dma_free_coherent(&ha->pdev->dev, ((*rsp)->length + 1) * sizeof(response_t), (*rsp)->ring, (*rsp)->dma); @@ -2402,18 +2340,22 @@ qla2x00_mem_free(struct qla_hw_data *ha) if (ha->sfp_data) dma_pool_free(ha->s_dma_pool, ha->sfp_data, ha->sfp_data_dma); + if (ha->edc_data) + dma_pool_free(ha->s_dma_pool, ha->edc_data, ha->edc_data_dma); + if (ha->ms_iocb) dma_pool_free(ha->s_dma_pool, ha->ms_iocb, ha->ms_iocb_dma); + if (ha->ex_init_cb) + dma_pool_free(ha->s_dma_pool, ha->ex_init_cb, ha->ex_init_cb_dma); + if (ha->s_dma_pool) dma_pool_destroy(ha->s_dma_pool); - if (ha->gid_list) dma_free_coherent(&ha->pdev->dev, GID_LIST_SIZE, ha->gid_list, ha->gid_list_dma); - if (ha->init_cb) dma_free_coherent(&ha->pdev->dev, ha->init_cb_size, ha->init_cb, ha->init_cb_dma); @@ -2432,6 +2374,8 @@ qla2x00_mem_free(struct qla_hw_data *ha) ha->ms_iocb_dma = 0; ha->init_cb = NULL; ha->init_cb_dma = 0; + ha->ex_init_cb = NULL; + ha->ex_init_cb_dma = 0; ha->s_dma_pool = NULL; @@ -2522,6 +2466,19 @@ qla2x00_post_aen_work(struct scsi_qla_host *vha, enum fc_host_event_code code, return qla2x00_post_work(vha, e, 1); } +int +qla2x00_post_idc_ack_work(struct scsi_qla_host *vha, uint16_t *mb) +{ + struct qla_work_evt *e; + + e = qla2x00_alloc_work(vha, QLA_EVT_IDC_ACK, 1); + if (!e) + return QLA_FUNCTION_FAILED; + + memcpy(e->u.idc_ack.mb, mb, QLA_IDC_ACK_REGS * sizeof(uint16_t)); + return qla2x00_post_work(vha, e, 1); +} + static void qla2x00_do_work(struct scsi_qla_host *vha) { @@ -2539,6 +2496,9 @@ qla2x00_do_work(struct scsi_qla_host *vha) fc_host_post_event(vha->host, fc_get_event_number(), e->u.aen.code, e->u.aen.data); break; + case QLA_EVT_IDC_ACK: + qla81xx_idc_ack(vha, e->u.idc_ack.mb); + break; } if (e->flags & QLA_EVT_FLAG_FREE) kfree(e); @@ -2552,7 +2512,7 @@ qla2x00_do_work(struct scsi_qla_host *vha) void qla2x00_relogin(struct scsi_qla_host *vha) { fc_port_t *fcport; - uint8_t status; + int status; uint16_t next_loopid = 0; struct qla_hw_data *ha = vha->hw; @@ -2902,19 +2862,11 @@ qla2x00_timer(scsi_qla_host_t *vha) spin_unlock_irqrestore(&ha->hardware_lock, cpu_flags); } - set_bit(ABORT_QUEUES_NEEDED, &vha->dpc_flags); start_dpc++; } /* if the loop has been down for 4 minutes, reinit adapter */ if (atomic_dec_and_test(&vha->loop_down_timer) != 0) { - DEBUG(printk("scsi(%ld): Loop down exceed 4 mins - " - "restarting queues.\n", - vha->host_no)); - - set_bit(RESTART_QUEUES_NEEDED, &vha->dpc_flags); - start_dpc++; - if (!(vha->device_flags & DFLG_NO_CABLE) && !vha->vp_idx) { DEBUG(printk("scsi(%ld): Loop down - " @@ -3041,6 +2993,8 @@ qla2x00_release_firmware(void) static pci_ers_result_t qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) { + scsi_qla_host_t *base_vha = pci_get_drvdata(pdev); + switch (state) { case pci_channel_io_normal: return PCI_ERS_RESULT_CAN_RECOVER; @@ -3048,7 +3002,7 @@ qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) pci_disable_device(pdev); return PCI_ERS_RESULT_NEED_RESET; case pci_channel_io_perm_failure: - qla2x00_remove_one(pdev); + qla2x00_abort_all_cmds(base_vha, DID_NO_CONNECT << 16); return PCI_ERS_RESULT_DISCONNECT; } return PCI_ERS_RESULT_NEED_RESET; diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c index 9c3b694c049..152ecfc26cd 100644 --- a/drivers/scsi/qla2xxx/qla_sup.c +++ b/drivers/scsi/qla2xxx/qla_sup.c @@ -612,8 +612,8 @@ qla2xxx_find_flt_start(scsi_qla_host_t *vha, uint32_t *start) /* Good data. Use specified location. */ loc = locations[1]; - *start = le16_to_cpu(fltl->start_hi) << 16 | - le16_to_cpu(fltl->start_lo); + *start = (le16_to_cpu(fltl->start_hi) << 16 | + le16_to_cpu(fltl->start_lo)) >> 2; end: DEBUG2(qla_printk(KERN_DEBUG, ha, "FLTL[%s] = 0x%x.\n", loc, *start)); return QLA_SUCCESS; @@ -629,6 +629,14 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr) { FA_BOOT_CODE_ADDR, FA_BOOT_CODE_ADDR, FA_BOOT_CODE_ADDR_81 }; const uint32_t def_vpd_nvram[] = { FA_VPD_NVRAM_ADDR, FA_VPD_NVRAM_ADDR, FA_VPD_NVRAM_ADDR_81 }; + const uint32_t def_vpd0[] = + { 0, 0, FA_VPD0_ADDR_81 }; + const uint32_t def_vpd1[] = + { 0, 0, FA_VPD1_ADDR_81 }; + const uint32_t def_nvram0[] = + { 0, 0, FA_NVRAM0_ADDR_81 }; + const uint32_t def_nvram1[] = + { 0, 0, FA_NVRAM1_ADDR_81 }; const uint32_t def_fdt[] = { FA_FLASH_DESCR_ADDR_24, FA_FLASH_DESCR_ADDR, FA_FLASH_DESCR_ADDR_81 }; @@ -684,7 +692,7 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr) "end=0x%x size=0x%x.\n", le32_to_cpu(region->code), start, le32_to_cpu(region->end) >> 2, le32_to_cpu(region->size))); - switch (le32_to_cpu(region->code)) { + switch (le32_to_cpu(region->code) & 0xff) { case FLT_REG_FW: ha->flt_region_fw = start; break; @@ -693,6 +701,20 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr) break; case FLT_REG_VPD_0: ha->flt_region_vpd_nvram = start; + if (!(PCI_FUNC(ha->pdev->devfn) & 1)) + ha->flt_region_vpd = start; + break; + case FLT_REG_VPD_1: + if (PCI_FUNC(ha->pdev->devfn) & 1) + ha->flt_region_vpd = start; + break; + case FLT_REG_NVRAM_0: + if (!(PCI_FUNC(ha->pdev->devfn) & 1)) + ha->flt_region_nvram = start; + break; + case FLT_REG_NVRAM_1: + if (PCI_FUNC(ha->pdev->devfn) & 1) + ha->flt_region_nvram = start; break; case FLT_REG_FDT: ha->flt_region_fdt = start; @@ -722,13 +744,18 @@ no_flash_data: ha->flt_region_fw = def_fw[def]; ha->flt_region_boot = def_boot[def]; ha->flt_region_vpd_nvram = def_vpd_nvram[def]; + ha->flt_region_vpd = !(PCI_FUNC(ha->pdev->devfn) & 1) ? + def_vpd0[def]: def_vpd1[def]; + ha->flt_region_nvram = !(PCI_FUNC(ha->pdev->devfn) & 1) ? + def_nvram0[def]: def_nvram1[def]; ha->flt_region_fdt = def_fdt[def]; ha->flt_region_npiv_conf = !(PCI_FUNC(ha->pdev->devfn) & 1) ? def_npiv_conf0[def]: def_npiv_conf1[def]; done: DEBUG2(qla_printk(KERN_DEBUG, ha, "FLT[%s]: boot=0x%x fw=0x%x " - "vpd_nvram=0x%x fdt=0x%x flt=0x%x npiv=0x%x.\n", loc, - ha->flt_region_boot, ha->flt_region_fw, ha->flt_region_vpd_nvram, + "vpd_nvram=0x%x vpd=0x%x nvram=0x%x fdt=0x%x flt=0x%x " + "npiv=0x%x.\n", loc, ha->flt_region_boot, ha->flt_region_fw, + ha->flt_region_vpd_nvram, ha->flt_region_vpd, ha->flt_region_nvram, ha->flt_region_fdt, ha->flt_region_flt, ha->flt_region_npiv_conf)); } @@ -931,31 +958,41 @@ done: ha->npiv_info = NULL; } -static void -qla24xx_unprotect_flash(struct qla_hw_data *ha) +static int +qla24xx_unprotect_flash(scsi_qla_host_t *vha) { + struct qla_hw_data *ha = vha->hw; struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; + if (ha->flags.fac_supported) + return qla81xx_fac_do_write_enable(vha, 1); + /* Enable flash write. */ WRT_REG_DWORD(®->ctrl_status, RD_REG_DWORD(®->ctrl_status) | CSRX_FLASH_ENABLE); RD_REG_DWORD(®->ctrl_status); /* PCI Posting. */ if (!ha->fdt_wrt_disable) - return; + goto done; /* Disable flash write-protection, first clear SR protection bit */ qla24xx_write_flash_dword(ha, flash_conf_addr(ha, 0x101), 0); /* Then write zero again to clear remaining SR bits.*/ qla24xx_write_flash_dword(ha, flash_conf_addr(ha, 0x101), 0); +done: + return QLA_SUCCESS; } -static void -qla24xx_protect_flash(struct qla_hw_data *ha) +static int +qla24xx_protect_flash(scsi_qla_host_t *vha) { uint32_t cnt; + struct qla_hw_data *ha = vha->hw; struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; + if (ha->flags.fac_supported) + return qla81xx_fac_do_write_enable(vha, 0); + if (!ha->fdt_wrt_disable) goto skip_wrt_protect; @@ -973,6 +1010,26 @@ skip_wrt_protect: WRT_REG_DWORD(®->ctrl_status, RD_REG_DWORD(®->ctrl_status) & ~CSRX_FLASH_ENABLE); RD_REG_DWORD(®->ctrl_status); /* PCI Posting. */ + + return QLA_SUCCESS; +} + +static int +qla24xx_erase_sector(scsi_qla_host_t *vha, uint32_t fdata) +{ + struct qla_hw_data *ha = vha->hw; + uint32_t start, finish; + + if (ha->flags.fac_supported) { + start = fdata >> 2; + finish = start + (ha->fdt_block_size >> 2) - 1; + return qla81xx_fac_erase_sector(vha, flash_data_addr(ha, + start), flash_data_addr(ha, finish)); + } + + return qla24xx_write_flash_dword(ha, ha->fdt_erase_cmd, + (fdata & 0xff00) | ((fdata << 16) & 0xff0000) | + ((fdata >> 16) & 0xff)); } static int @@ -987,8 +1044,6 @@ qla24xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr, void *optrom = NULL; struct qla_hw_data *ha = vha->hw; - ret = QLA_SUCCESS; - /* Prepare burst-capable write on supported ISPs. */ if ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && !(faddr & 0xfff) && dwords > OPTROM_BURST_DWORDS) { @@ -1004,7 +1059,12 @@ qla24xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr, rest_addr = (ha->fdt_block_size >> 2) - 1; sec_mask = ~rest_addr; - qla24xx_unprotect_flash(ha); + ret = qla24xx_unprotect_flash(vha); + if (ret != QLA_SUCCESS) { + qla_printk(KERN_WARNING, ha, + "Unable to unprotect flash for update.\n"); + goto done; + } for (liter = 0; liter < dwords; liter++, faddr++, dwptr++) { fdata = (faddr & sec_mask) << 2; @@ -1017,9 +1077,7 @@ qla24xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr, ha->fdt_unprotect_sec_cmd, (fdata & 0xff00) | ((fdata << 16) & 0xff0000) | ((fdata >> 16) & 0xff)); - ret = qla24xx_write_flash_dword(ha, ha->fdt_erase_cmd, - (fdata & 0xff00) |((fdata << 16) & - 0xff0000) | ((fdata >> 16) & 0xff)); + ret = qla24xx_erase_sector(vha, fdata); if (ret != QLA_SUCCESS) { DEBUG9(qla_printk("Unable to erase sector: " "address=%x.\n", faddr)); @@ -1073,8 +1131,11 @@ qla24xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr, 0xff0000) | ((fdata >> 16) & 0xff)); } - qla24xx_protect_flash(ha); - + ret = qla24xx_protect_flash(vha); + if (ret != QLA_SUCCESS) + qla_printk(KERN_WARNING, ha, + "Unable to protect flash after update.\n"); +done: if (optrom) dma_free_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE, optrom, optrom_dma); @@ -1915,7 +1976,7 @@ qla2x00_resume_hba(struct scsi_qla_host *vha) clear_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags); set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); qla2xxx_wake_dpc(vha); - qla2x00_wait_for_hba_online(vha); + qla2x00_wait_for_chip_reset(vha); scsi_unblock_requests(vha->host); } @@ -2206,11 +2267,7 @@ qla24xx_write_optrom_data(struct scsi_qla_host *vha, uint8_t *buf, rval = qla24xx_write_flash_data(vha, (uint32_t *)buf, offset >> 2, length >> 2); - /* Resume HBA -- RISC reset needed. */ clear_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags); - set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); - qla2xxx_wake_dpc(vha); - qla2x00_wait_for_hba_online(vha); scsi_unblock_requests(vha->host); return rval; @@ -2518,7 +2575,7 @@ qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf) dcode = mbuf; /* Begin with first PCI expansion ROM header. */ - pcihdr = ha->flt_region_boot; + pcihdr = ha->flt_region_boot << 2; last_image = 1; do { /* Verify PCI expansion ROM header. */ diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index cfa4c11a479..19d1afc3a34 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -7,9 +7,9 @@ /* * Driver version */ -#define QLA2XXX_VERSION "8.03.00-k2" +#define QLA2XXX_VERSION "8.03.01-k1" #define QLA_DRIVER_MAJOR_VER 8 #define QLA_DRIVER_MINOR_VER 3 -#define QLA_DRIVER_PATCH_VER 0 +#define QLA_DRIVER_PATCH_VER 1 #define QLA_DRIVER_BETA_VER 0 diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c index 69d6ad862b6..fa34b92850a 100644 --- a/drivers/scsi/qlogicpti.c +++ b/drivers/scsi/qlogicpti.c @@ -28,6 +28,7 @@ #include <linux/dma-mapping.h> #include <linux/of.h> #include <linux/of_device.h> +#include <linux/firmware.h> #include <asm/byteorder.h> @@ -53,8 +54,6 @@ #define DEFAULT_LOOP_COUNT 10000 -#include "qlogicpti_asm.c" - static struct qlogicpti *qptichain = NULL; static DEFINE_SPINLOCK(qptichain_lock); @@ -465,16 +464,32 @@ static int qlogicpti_reset_hardware(struct Scsi_Host *host) static int __devinit qlogicpti_load_firmware(struct qlogicpti *qpti) { + const struct firmware *fw; + const char fwname[] = "qlogic/isp1000.bin"; + const __le16 *fw_data; struct Scsi_Host *host = qpti->qhost; unsigned short csum = 0; unsigned short param[6]; - unsigned short *risc_code, risc_code_addr, risc_code_length; + unsigned short risc_code_addr, risc_code_length; + int err; unsigned long flags; int i, timeout; - risc_code = &sbus_risc_code01[0]; + err = request_firmware(&fw, fwname, &qpti->op->dev); + if (err) { + printk(KERN_ERR "Failed to load image \"%s\" err %d\n", + fwname, err); + return err; + } + if (fw->size % 2) { + printk(KERN_ERR "Bogus length %zu in image \"%s\"\n", + fw->size, fwname); + err = -EINVAL; + goto outfirm; + } + fw_data = (const __le16 *)&fw->data[0]; risc_code_addr = 0x1000; /* all f/w modules load at 0x1000 */ - risc_code_length = sbus_risc_code_length01; + risc_code_length = fw->size / 2; spin_lock_irqsave(host->host_lock, flags); @@ -482,12 +497,12 @@ static int __devinit qlogicpti_load_firmware(struct qlogicpti *qpti) * afterwards via the mailbox commands. */ for (i = 0; i < risc_code_length; i++) - csum += risc_code[i]; + csum += __le16_to_cpu(fw_data[i]); if (csum) { - spin_unlock_irqrestore(host->host_lock, flags); printk(KERN_EMERG "qlogicpti%d: Aieee, firmware checksum failed!", qpti->qpti_id); - return 1; + err = 1; + goto out; } sbus_writew(SBUS_CTRL_RESET, qpti->qregs + SBUS_CTRL); sbus_writew((DMA_CTRL_CCLEAR | DMA_CTRL_CIRQ), qpti->qregs + CMD_DMA_CTRL); @@ -496,9 +511,9 @@ static int __devinit qlogicpti_load_firmware(struct qlogicpti *qpti) while (--timeout && (sbus_readw(qpti->qregs + SBUS_CTRL) & SBUS_CTRL_RESET)) udelay(20); if (!timeout) { - spin_unlock_irqrestore(host->host_lock, flags); printk(KERN_EMERG "qlogicpti%d: Cannot reset the ISP.", qpti->qpti_id); - return 1; + err = 1; + goto out; } sbus_writew(HCCTRL_RESET, qpti->qregs + HCCTRL); @@ -536,21 +551,21 @@ static int __devinit qlogicpti_load_firmware(struct qlogicpti *qpti) if (qlogicpti_mbox_command(qpti, param, 1)) { printk(KERN_EMERG "qlogicpti%d: Cannot stop firmware for reload.\n", qpti->qpti_id); - spin_unlock_irqrestore(host->host_lock, flags); - return 1; + err = 1; + goto out; } /* Load it up.. */ for (i = 0; i < risc_code_length; i++) { param[0] = MBOX_WRITE_RAM_WORD; param[1] = risc_code_addr + i; - param[2] = risc_code[i]; + param[2] = __le16_to_cpu(fw_data[i]); if (qlogicpti_mbox_command(qpti, param, 1) || param[0] != MBOX_COMMAND_COMPLETE) { printk("qlogicpti%d: Firmware dload failed, I'm bolixed!\n", qpti->qpti_id); - spin_unlock_irqrestore(host->host_lock, flags); - return 1; + err = 1; + goto out; } } @@ -569,8 +584,8 @@ static int __devinit qlogicpti_load_firmware(struct qlogicpti *qpti) (param[0] != MBOX_COMMAND_COMPLETE)) { printk(KERN_EMERG "qlogicpti%d: New firmware csum failure!\n", qpti->qpti_id); - spin_unlock_irqrestore(host->host_lock, flags); - return 1; + err = 1; + goto out; } /* Start using newly downloaded firmware. */ @@ -583,8 +598,8 @@ static int __devinit qlogicpti_load_firmware(struct qlogicpti *qpti) (param[0] != MBOX_COMMAND_COMPLETE)) { printk(KERN_EMERG "qlogicpti%d: AboutFirmware cmd fails.\n", qpti->qpti_id); - spin_unlock_irqrestore(host->host_lock, flags); - return 1; + err = 1; + goto out; } /* Snag the major and minor revisions from the result. */ @@ -599,8 +614,8 @@ static int __devinit qlogicpti_load_firmware(struct qlogicpti *qpti) (param[0] != MBOX_COMMAND_COMPLETE)) { printk(KERN_EMERG "qlogicpti%d: could not set clock rate.\n", qpti->qpti_id); - spin_unlock_irqrestore(host->host_lock, flags); - return 1; + err = 1; + goto out; } if (qpti->is_pti != 0) { @@ -616,8 +631,11 @@ static int __devinit qlogicpti_load_firmware(struct qlogicpti *qpti) qlogicpti_mbox_command(qpti, param, 1); } +out: spin_unlock_irqrestore(host->host_lock, flags); - return 0; +outfirm: + release_firmware(fw); + return err; } static int qlogicpti_verify_tmon(struct qlogicpti *qpti) @@ -1458,6 +1476,7 @@ MODULE_DESCRIPTION("QlogicISP SBUS driver"); MODULE_AUTHOR("David S. Miller (davem@davemloft.net)"); MODULE_LICENSE("GPL"); MODULE_VERSION("2.1"); +MODULE_FIRMWARE("qlogic/isp1000.bin"); module_init(qpti_init); module_exit(qpti_exit); diff --git a/drivers/scsi/qlogicpti_asm.c b/drivers/scsi/qlogicpti_asm.c deleted file mode 100644 index 19aa84f4601..00000000000 --- a/drivers/scsi/qlogicpti_asm.c +++ /dev/null @@ -1,1160 +0,0 @@ -/* Version 1.31.00 ISP1000 Initiator RISC firmware */ -unsigned short sbus_risc_code01[] __devinitdata = { - 0x0078, 0x1030, 0x0000, 0x2419, 0x0000, 0x12ff, 0x2043, 0x4f50, - 0x5952, 0x4947, 0x4854, 0x2031, 0x3939, 0x312c, 0x3139, 0x3932, - 0x2c31, 0x3939, 0x332c, 0x3139, 0x3934, 0x2051, 0x4c4f, 0x4749, - 0x4320, 0x434f, 0x5250, 0x4f52, 0x4154, 0x494f, 0x4e00, 0x2049, - 0x5350, 0x3130, 0x3030, 0x2046, 0x6972, 0x6d77, 0x6172, 0x6520, - 0x2056, 0x6572, 0x7369, 0x6f6e, 0x2030, 0x312e, 0x3331, 0x2020, - 0x20b9, 0x1212, 0x20c1, 0x0008, 0x2071, 0x0010, 0x70c3, 0x0004, - 0x20c9, 0x3fff, 0x2089, 0x10c8, 0x70c7, 0x4953, 0x70cb, 0x5020, - 0x70cf, 0x2020, 0x70d3, 0x0001, 0x3f00, 0x70d6, 0x2031, 0x0030, - 0x2079, 0x3500, 0x7863, 0x0000, 0x2fa0, 0x2009, 0x0327, 0x2011, - 0x0000, 0x20a9, 0x0040, 0x42a4, 0x8109, 0x00c0, 0x1051, 0x789b, - 0x0101, 0x780b, 0x0002, 0x780f, 0x0002, 0x784f, 0x0bb8, 0x2069, - 0x3540, 0x00a8, 0x106a, 0x681b, 0x003c, 0x2009, 0x1313, 0x21b8, - 0x0078, 0x106c, 0x681b, 0x0028, 0x6807, 0x0007, 0x680b, 0x00fa, - 0x680f, 0x0008, 0x6813, 0x0005, 0x681f, 0x0000, 0x6823, 0x0006, - 0x6817, 0x0008, 0x6827, 0x0000, 0x2069, 0x3600, 0x2011, 0x0020, - 0x2009, 0x0010, 0x680b, 0x0c19, 0x680f, 0x0019, 0x6803, 0xdd00, - 0x6807, 0x001a, 0x6a1a, 0x2d00, 0xa0e8, 0x0008, 0xa290, 0x0004, - 0x8109, 0x00c0, 0x1082, 0x2069, 0x3680, 0x20a9, 0x0080, 0x6837, - 0x0000, 0x680b, 0x0040, 0x6817, 0x0100, 0x681f, 0x0064, 0xade8, - 0x0010, 0x0070, 0x10a5, 0x0078, 0x1097, 0x1078, 0x1a38, 0x1078, - 0x2f3a, 0x1078, 0x1681, 0x1078, 0x33ba, 0x3200, 0xa085, 0x000d, - 0x2090, 0x70c3, 0x0000, 0x0090, 0x10bc, 0x70c0, 0xa086, 0x0002, - 0x00c0, 0x10bc, 0x1078, 0x11ba, 0x1078, 0x10ec, 0x1078, 0x1817, - 0x1078, 0x19a8, 0x1078, 0x327d, 0x1078, 0x177d, 0x0078, 0x10bc, - 0x10d0, 0x10d2, 0x1bc3, 0x1bc3, 0x2f98, 0x2f98, 0x1bc3, 0x1bc3, - 0x0078, 0x10d0, 0x0078, 0x10d2, 0x0078, 0x10d4, 0x0078, 0x10d6, - 0x7008, 0x800c, 0x00c8, 0x10e7, 0x7007, 0x0002, 0xa08c, 0x000c, - 0x00c0, 0x10e8, 0x8004, 0x8004, 0x00c8, 0x10e7, 0x087a, 0x097a, - 0x70c3, 0x4002, 0x0078, 0x11bd, 0x7814, 0xa005, 0x00c0, 0x10f4, - 0x0010, 0x1130, 0x0078, 0x112f, 0x2009, 0x3568, 0x2104, 0xa005, - 0x00c0, 0x112f, 0x7814, 0xa086, 0x0001, 0x00c0, 0x1101, 0x1078, - 0x1536, 0x7817, 0x0000, 0x2009, 0x356f, 0x2104, 0xa065, 0x0040, - 0x111d, 0x2009, 0x356a, 0x211c, 0x8108, 0x2114, 0x8108, 0x2104, - 0xa210, 0xa399, 0x0000, 0x2009, 0x001c, 0x6083, 0x0103, 0x1078, - 0x1611, 0x00c0, 0x1129, 0x1078, 0x1678, 0x2009, 0x356f, 0x200b, - 0x0000, 0x2009, 0x3569, 0x2104, 0x200b, 0x0000, 0xa005, 0x0040, - 0x112d, 0x2001, 0x4005, 0x0078, 0x11bc, 0x0078, 0x11ba, 0x007c, - 0x2061, 0x0000, 0x6018, 0xa084, 0x0001, 0x0040, 0x1138, 0x007c, - 0x70c3, 0x0000, 0x70c7, 0x0000, 0x70cb, 0x0000, 0x70cf, 0x0000, - 0x70c0, 0xa0bc, 0xffc0, 0x00c0, 0x1188, 0x2038, 0x0079, 0x1148, - 0x11ba, 0x1205, 0x11d3, 0x1205, 0x1256, 0x1256, 0x11ca, 0x1590, - 0x1261, 0x11c6, 0x11d7, 0x11d9, 0x11db, 0x11dd, 0x1595, 0x11c6, - 0x1267, 0x1283, 0x1544, 0x158a, 0x11df, 0x146b, 0x148d, 0x14a7, - 0x14d0, 0x1424, 0x1432, 0x1446, 0x145a, 0x12ef, 0x11c6, 0x129f, - 0x12a6, 0x12ab, 0x12b0, 0x12b6, 0x12bb, 0x12c0, 0x12c5, 0x12ca, - 0x12ce, 0x12e3, 0x11c6, 0x11c6, 0x11c6, 0x11c6, 0x11c6, 0x12fb, - 0x1304, 0x1313, 0x1339, 0x1343, 0x134a, 0x1370, 0x137f, 0x138e, - 0x13a0, 0x1409, 0x11c6, 0x11c6, 0x11c6, 0x11c6, 0x11c6, 0x1419, - 0xa0bc, 0xffa0, 0x00c0, 0x11c6, 0x2038, 0xa084, 0x001f, 0x0079, - 0x1191, 0x11c6, 0x11c6, 0x11c6, 0x11c6, 0x11c6, 0x11c6, 0x11c6, - 0x11c6, 0x11c6, 0x11c6, 0x11c6, 0x11c6, 0x11c6, 0x11c6, 0x11c6, - 0x11c6, 0x11c6, 0x11c6, 0x11c6, 0x11c6, 0x11c6, 0x11c6, 0x11c6, - 0x11c6, 0x11c6, 0x11c6, 0x15ed, 0x15f7, 0x15fb, 0x1609, 0x11c6, - 0x11c6, 0x72ca, 0x71c6, 0x2001, 0x4006, 0x0078, 0x11bc, 0x73ce, - 0x72ca, 0x71c6, 0x2001, 0x4000, 0x70c2, 0x2061, 0x0000, 0x601b, - 0x0001, 0x2091, 0x5000, 0x2091, 0x4080, 0x007c, 0x70c3, 0x4001, - 0x0078, 0x11bd, 0x2099, 0x0041, 0x20a1, 0x0041, 0x20a9, 0x0005, - 0x53a3, 0x0078, 0x11ba, 0x70c4, 0x70c3, 0x0004, 0x007a, 0x0078, - 0x11ba, 0x0078, 0x11ba, 0x0078, 0x11ba, 0x0078, 0x11ba, 0x2091, - 0x8000, 0x70c3, 0x0000, 0x70c7, 0x4953, 0x70cb, 0x5020, 0x70cf, - 0x2020, 0x70d3, 0x0001, 0x3f00, 0x70d6, 0x2079, 0x0000, 0x781b, - 0x0001, 0x2031, 0x0030, 0x2059, 0x1000, 0x2029, 0x0457, 0x2051, - 0x0470, 0x2061, 0x0472, 0x20b9, 0xffff, 0x20c1, 0x0000, 0x2091, - 0x5000, 0x2091, 0x4080, 0x0078, 0x0455, 0x71d0, 0x72c8, 0x73cc, - 0x70c4, 0x20a0, 0x2098, 0x2031, 0x0030, 0x81ff, 0x0040, 0x11ba, - 0x7007, 0x0004, 0x731a, 0x721e, 0x2051, 0x0012, 0x2049, 0x1234, - 0x2041, 0x11ba, 0x7003, 0x0002, 0xa786, 0x0001, 0x00c0, 0x1226, - 0x2049, 0x1242, 0x2041, 0x124e, 0x7003, 0x0003, 0x7017, 0x0000, - 0x810b, 0x7112, 0x00c8, 0x122e, 0x7017, 0x0001, 0x7007, 0x0001, - 0xa786, 0x0001, 0x0040, 0x1242, 0x700c, 0xa084, 0x007f, 0x8004, - 0x2009, 0x0020, 0xa102, 0x0942, 0x094a, 0x20a8, 0x26a0, 0x53a6, - 0x0078, 0x10d8, 0x700c, 0xa084, 0x007f, 0x0040, 0x1242, 0x80ac, - 0x0048, 0x1242, 0x2698, 0x53a5, 0x0078, 0x10d8, 0x700c, 0xa084, - 0x007f, 0x80ac, 0x2698, 0x53a5, 0x0078, 0x11ba, 0x71c4, 0x70c8, - 0x2114, 0xa79e, 0x0004, 0x00c0, 0x125e, 0x200a, 0x72ca, 0x0078, - 0x11b9, 0x70c7, 0x0001, 0x70cb, 0x001f, 0x0078, 0x11ba, 0x70c4, - 0x72c8, 0x73cc, 0x74d0, 0x70c6, 0x72ca, 0x73ce, 0x74d2, 0xa005, - 0x0040, 0x127d, 0x8001, 0x7872, 0x7a7a, 0x7b7e, 0x7c76, 0x7898, - 0xa084, 0xfffc, 0x789a, 0x0078, 0x1281, 0x7898, 0xa085, 0x0001, - 0x789a, 0x0078, 0x11ba, 0x70c4, 0x72c8, 0x73cc, 0x74d4, 0x70c6, - 0x72ca, 0x73ce, 0x74d6, 0xa005, 0x0040, 0x1299, 0x8001, 0x7886, - 0x7a8e, 0x7b92, 0x7c8a, 0x7898, 0xa084, 0xfcff, 0x789a, 0x0078, - 0x129d, 0x7898, 0xa085, 0x0100, 0x789a, 0x0078, 0x11ba, 0x2009, - 0x3559, 0x210c, 0x2011, 0x0410, 0x0078, 0x11b8, 0x2009, 0x3541, - 0x210c, 0x0078, 0x11b9, 0x2009, 0x3542, 0x210c, 0x0078, 0x11b9, - 0x2061, 0x3540, 0x610c, 0x6210, 0x0078, 0x11b8, 0x2009, 0x3545, - 0x210c, 0x0078, 0x11b9, 0x2009, 0x3546, 0x210c, 0x0078, 0x11b9, - 0x2009, 0x3547, 0x210c, 0x0078, 0x11b9, 0x2009, 0x3548, 0x210c, - 0x0078, 0x11b9, 0x7908, 0x7a0c, 0x0078, 0x11b8, 0x71c4, 0x8107, - 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa0e8, 0x3600, 0x6a00, - 0x6804, 0xa084, 0x0008, 0x0040, 0x12e0, 0x6b08, 0x0078, 0x12e1, - 0x6b0c, 0x0078, 0x11b7, 0x77c4, 0x1078, 0x1692, 0x2091, 0x8000, - 0x6b1c, 0x6a14, 0x2091, 0x8001, 0x2708, 0x0078, 0x11b7, 0x77c4, - 0x1078, 0x1692, 0x2091, 0x8000, 0x6908, 0x6a18, 0x6b10, 0x2091, - 0x8001, 0x0078, 0x11b7, 0x71c4, 0xa182, 0x0010, 0x00c8, 0x11b2, - 0x1078, 0x1abc, 0x0078, 0x11b7, 0x71c4, 0xa182, 0x0010, 0x00c8, - 0x11b2, 0x2011, 0x3541, 0x2204, 0x007e, 0x2112, 0x1078, 0x1a75, - 0x017f, 0x0078, 0x11b9, 0x71c4, 0x2011, 0x1331, 0x20a9, 0x0008, - 0x2204, 0xa106, 0x0040, 0x1323, 0x8210, 0x0070, 0x1321, 0x0078, - 0x1318, 0x0078, 0x11b2, 0xa292, 0x1331, 0x027e, 0x2011, 0x3542, - 0x2204, 0x2112, 0x017f, 0x007e, 0x1078, 0x1a81, 0x017f, 0x0078, - 0x11b9, 0x03e8, 0x00fa, 0x01f4, 0x02ee, 0x0064, 0x0019, 0x0032, - 0x004b, 0x2061, 0x3540, 0x610c, 0x6210, 0x70c4, 0x600e, 0x70c8, - 0x6012, 0x0078, 0x11b8, 0x2061, 0x3540, 0x6114, 0x70c4, 0x6016, - 0x0078, 0x11b9, 0x71c4, 0x2011, 0x0004, 0x2019, 0x1212, 0xa186, - 0x0028, 0x0040, 0x1363, 0x2011, 0x0005, 0x2019, 0x1212, 0xa186, - 0x0032, 0x0040, 0x1363, 0x2011, 0x0006, 0x2019, 0x1313, 0xa186, - 0x003c, 0x00c0, 0x11b2, 0x2061, 0x3540, 0x6018, 0x007e, 0x611a, - 0x23b8, 0x1078, 0x1a92, 0x1078, 0x33ba, 0x017f, 0x0078, 0x11b9, - 0x71c4, 0xa184, 0xffcf, 0x00c0, 0x11b2, 0x2011, 0x3547, 0x2204, - 0x2112, 0x007e, 0x1078, 0x1ab4, 0x017f, 0x0078, 0x11b9, 0x71c4, - 0xa182, 0x0010, 0x00c8, 0x11b2, 0x2011, 0x3548, 0x2204, 0x007e, - 0x2112, 0x1078, 0x1aa3, 0x017f, 0x0078, 0x11b9, 0x71c4, 0x72c8, - 0xa184, 0xfffd, 0x00c0, 0x11b1, 0xa284, 0xfffd, 0x00c0, 0x11b1, - 0x2100, 0x7908, 0x780a, 0x2200, 0x7a0c, 0x780e, 0x0078, 0x11b8, - 0x71c4, 0x8107, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa0e8, - 0x3600, 0x2019, 0x0000, 0x72c8, 0x6800, 0x007e, 0xa226, 0x0040, - 0x13cf, 0x6a02, 0xa484, 0x2000, 0x0040, 0x13b8, 0xa39d, 0x0010, - 0xa484, 0x1000, 0x0040, 0x13be, 0xa39d, 0x0008, 0xa484, 0x4000, - 0x0040, 0x13cf, 0x810f, 0xa284, 0x4000, 0x0040, 0x13cb, 0x1078, - 0x1ad6, 0x0078, 0x13cf, 0x1078, 0x1ac8, 0x0078, 0x13cf, 0x72cc, - 0x82ff, 0x0040, 0x1401, 0x6808, 0xa206, 0x0040, 0x1401, 0xa2a4, - 0x00ff, 0x2061, 0x3540, 0x6118, 0xa186, 0x0028, 0x0040, 0x13e8, - 0xa186, 0x0032, 0x0040, 0x13ee, 0xa186, 0x003c, 0x0040, 0x13f4, - 0xa482, 0x0064, 0x0048, 0x13fe, 0x0078, 0x13f8, 0xa482, 0x0050, - 0x0048, 0x13fe, 0x0078, 0x13f8, 0xa482, 0x0043, 0x0048, 0x13fe, - 0x71c4, 0x71c6, 0x027f, 0x72ca, 0x0078, 0x11b3, 0x6a0a, 0xa39d, - 0x000a, 0x6804, 0xa305, 0x6806, 0x027f, 0x6b0c, 0x71c4, 0x0078, - 0x11b7, 0x77c4, 0x1078, 0x1692, 0x2091, 0x8000, 0x6a14, 0x6b1c, - 0x2091, 0x8001, 0x70c8, 0x6816, 0x70cc, 0x681e, 0x2708, 0x0078, - 0x11b7, 0x71c4, 0x72c8, 0x73cc, 0xa182, 0x0010, 0x00c8, 0x11b2, - 0x1078, 0x1ae4, 0x0078, 0x11b7, 0x77c4, 0x1078, 0x1692, 0x2091, - 0x8000, 0x6a08, 0xa295, 0x0002, 0x6a0a, 0x2091, 0x8001, 0x2708, - 0x0078, 0x11b8, 0x77c4, 0x1078, 0x1692, 0x2091, 0x8000, 0x6a08, - 0xa294, 0xfff9, 0x6a0a, 0x6804, 0xa005, 0x0040, 0x1441, 0x1078, - 0x1a19, 0x2091, 0x8001, 0x2708, 0x0078, 0x11b8, 0x77c4, 0x1078, - 0x1692, 0x2091, 0x8000, 0x6a08, 0xa295, 0x0004, 0x6a0a, 0x6804, - 0xa005, 0x0040, 0x1455, 0x1078, 0x1a19, 0x2091, 0x8001, 0x2708, - 0x0078, 0x11b8, 0x77c4, 0x2041, 0x0001, 0x2049, 0x0005, 0x2051, - 0x0020, 0x2091, 0x8000, 0x1078, 0x169f, 0x2091, 0x8001, 0x2708, - 0x6a08, 0x0078, 0x11b8, 0x77c4, 0x72c8, 0x73cc, 0x77c6, 0x72ca, - 0x73ce, 0x1078, 0x1718, 0x00c0, 0x1489, 0x6818, 0xa005, 0x0040, - 0x1483, 0x2708, 0x1078, 0x1af4, 0x00c0, 0x1483, 0x7817, 0xffff, - 0x2091, 0x8001, 0x007c, 0x2091, 0x8001, 0x2001, 0x4005, 0x0078, - 0x11bc, 0x2091, 0x8001, 0x0078, 0x11ba, 0x77c4, 0x77c6, 0x2041, - 0x0021, 0x2049, 0x0005, 0x2051, 0x0020, 0x2091, 0x8000, 0x1078, - 0x169f, 0x2061, 0x3540, 0x60a3, 0x0003, 0x67b6, 0x60a7, 0x0000, - 0x7817, 0xffff, 0x2091, 0x8001, 0x1078, 0x1a19, 0x007c, 0x77c8, - 0x77ca, 0x77c4, 0x77c6, 0xa7bc, 0xff00, 0x2091, 0x8000, 0x2061, - 0x3540, 0x60a3, 0x0002, 0x60a7, 0x0000, 0x67b6, 0x7817, 0xffff, - 0x1078, 0x1a19, 0x2091, 0x8001, 0x2041, 0x0021, 0x2049, 0x0004, - 0x2051, 0x0010, 0x2091, 0x8000, 0x1078, 0x169f, 0x70c8, 0x6836, - 0x8738, 0xa784, 0x0007, 0x00c0, 0x14c4, 0x2091, 0x8001, 0x007c, - 0x7898, 0xa084, 0x0003, 0x00c0, 0x14f4, 0x2039, 0x0000, 0x2041, - 0x0021, 0x2049, 0x0004, 0x2051, 0x0008, 0x1078, 0x1692, 0x2091, - 0x8000, 0x6808, 0xa80d, 0x690a, 0x2091, 0x8001, 0x8738, 0xa784, - 0x0007, 0x00c0, 0x14dd, 0xa7bc, 0xff00, 0x873f, 0x8738, 0x873f, - 0xa784, 0x0f00, 0x00c0, 0x14dd, 0x2091, 0x8000, 0x2069, 0x0100, - 0x6830, 0xa084, 0x0040, 0x0040, 0x151d, 0x684b, 0x0004, 0x20a9, - 0x0014, 0x6848, 0xa084, 0x0004, 0x0040, 0x150a, 0x0070, 0x150a, - 0x0078, 0x1501, 0x684b, 0x0009, 0x20a9, 0x0014, 0x6848, 0xa084, - 0x0001, 0x0040, 0x1517, 0x0070, 0x1517, 0x0078, 0x150e, 0x20a9, - 0x00fa, 0x0070, 0x151d, 0x0078, 0x1519, 0x2079, 0x3500, 0x7817, - 0x0001, 0x2061, 0x3540, 0x60a3, 0x0001, 0x60a7, 0x0000, 0x60c3, - 0x000f, 0x7898, 0xa085, 0x0002, 0x789a, 0x6808, 0xa084, 0xfffd, - 0x680a, 0x681b, 0x0046, 0x2091, 0x8001, 0x007c, 0x7898, 0xa084, - 0xfffd, 0x789a, 0xa084, 0x0001, 0x00c0, 0x1540, 0x1078, 0x1760, - 0x71c4, 0x71c6, 0x794a, 0x007c, 0x74c4, 0x73c8, 0x72cc, 0x74c6, - 0x73ca, 0x72ce, 0x2079, 0x3500, 0x2009, 0x0040, 0x1078, 0x166f, - 0x0040, 0x1586, 0x1078, 0x163f, 0x0040, 0x155a, 0x1078, 0x1678, - 0x0078, 0x1586, 0x6010, 0x2091, 0x8001, 0x7817, 0xffff, 0x2009, - 0x3568, 0x200b, 0x0005, 0x8108, 0x200b, 0x0000, 0x8108, 0x230a, - 0x8108, 0x220a, 0x8108, 0x240a, 0x8108, 0x200a, 0x8108, 0x200b, - 0x0000, 0x8108, 0x2c0a, 0xa02e, 0x2530, 0x0e7e, 0x1078, 0x2f13, - 0x0e7f, 0x6592, 0x65a2, 0x6696, 0x66a6, 0x60ab, 0x0000, 0x60af, - 0x0000, 0x2091, 0x8001, 0x1078, 0x1a19, 0x007c, 0x70c3, 0x4005, - 0x0078, 0x11bd, 0x71c4, 0x70c7, 0x0000, 0x7906, 0x0078, 0x11ba, - 0x71c4, 0x71c6, 0x2168, 0x0078, 0x1597, 0x2069, 0x1000, 0x690c, - 0xa016, 0x2d04, 0xa210, 0x8d68, 0x8109, 0x00c0, 0x1599, 0xa285, - 0x0000, 0x00c0, 0x15a7, 0x70c3, 0x4000, 0x0078, 0x15a9, 0x70c3, - 0x4003, 0x70ca, 0x0078, 0x11bd, 0x71c4, 0x72c8, 0x73cc, 0x2100, - 0xa184, 0xfffc, 0x00c0, 0x11c6, 0x2100, 0x0079, 0x15b7, 0x15ce, - 0x15e3, 0x15e5, 0x15e7, 0x70c3, 0x4003, 0x71ce, 0x72d2, 0x73d6, - 0x0078, 0x15ca, 0x70c3, 0x4000, 0x70cf, 0x0000, 0x70d3, 0x0000, - 0x70d7, 0x0000, 0x77c6, 0x71ca, 0x0078, 0x11ba, 0x2031, 0x15e9, - 0x2624, 0x8630, 0x2412, 0x2204, 0xa446, 0x00c0, 0x15bb, 0xa484, - 0xffff, 0x00c0, 0x15d0, 0x2031, 0x15e9, 0x8210, 0x8319, 0xa384, - 0xffff, 0x00c0, 0x15d0, 0x0078, 0x15c2, 0x0078, 0x15c2, 0x0078, - 0x15c2, 0x5555, 0xaaaa, 0xffff, 0x0000, 0x7960, 0x71c6, 0x71c4, - 0xa182, 0x0003, 0x00c8, 0x11b2, 0x7962, 0x0078, 0x11ba, 0x7960, - 0x71c6, 0x0078, 0x11ba, 0x7954, 0x71c6, 0x71c4, 0x7956, 0x7958, - 0x71ca, 0x71c8, 0x795a, 0x795c, 0x71ce, 0x71cc, 0x795e, 0x0078, - 0x11ba, 0x7954, 0x71c6, 0x7958, 0x71ca, 0x795c, 0x71ce, 0x0078, - 0x11ba, 0x700c, 0xa084, 0x007f, 0x0040, 0x161d, 0x7007, 0x0004, - 0x7004, 0xa084, 0x0004, 0x00c0, 0x1618, 0x7017, 0x0000, 0x7112, - 0x721a, 0x731e, 0x8108, 0x810c, 0x81a9, 0x8c98, 0x20a1, 0x0030, - 0x6080, 0x20a2, 0x53a6, 0x780c, 0xa085, 0x0000, 0x7002, 0x7007, - 0x0001, 0x7108, 0x8104, 0x00c8, 0x1631, 0x7007, 0x0002, 0xa184, - 0x000c, 0x710c, 0xa184, 0x0300, 0x7003, 0x0000, 0x007c, 0x700c, - 0xa084, 0x007f, 0x0040, 0x164b, 0x7007, 0x0004, 0x7004, 0xa084, - 0x0004, 0x00c0, 0x1646, 0x7017, 0x0000, 0x7112, 0x721a, 0x731e, - 0x2099, 0x0030, 0x8108, 0x81ac, 0x780c, 0xa085, 0x0001, 0x7002, - 0x7007, 0x0001, 0x7008, 0x800c, 0x00c8, 0x165a, 0x7007, 0x0002, - 0xa08c, 0x000c, 0x00c0, 0x166c, 0x710c, 0xa184, 0x0300, 0x00c0, - 0x166c, 0x2ca0, 0x53a5, 0xa006, 0x7003, 0x0000, 0x007c, 0x7850, - 0xa065, 0x0040, 0x1677, 0x2c04, 0x7852, 0x2063, 0x0000, 0x007c, - 0x0f7e, 0x2079, 0x3500, 0x7850, 0x2062, 0x2c00, 0x7852, 0x0f7f, - 0x007c, 0x2011, 0x4000, 0x7a52, 0x2019, 0x0410, 0x8319, 0x0040, - 0x168f, 0xa280, 0x002f, 0x2012, 0x2010, 0x0078, 0x1686, 0x2013, - 0x0000, 0x007c, 0xa784, 0x0f00, 0x800c, 0xa784, 0x0007, 0x8003, - 0x8003, 0x8003, 0x8003, 0xa105, 0xa0e8, 0x3680, 0x007c, 0x1078, - 0x1692, 0x2900, 0x682a, 0x2a00, 0x682e, 0x6808, 0xa084, 0xffef, - 0xa80d, 0x690a, 0x2009, 0x354f, 0x210c, 0x6804, 0xa005, 0x0040, - 0x16bc, 0xa116, 0x00c0, 0x16bc, 0x2060, 0x6000, 0x6806, 0x017e, - 0x200b, 0x0000, 0x0078, 0x16bf, 0x2009, 0x0000, 0x017e, 0x6804, - 0xa065, 0x0040, 0x16ce, 0x6000, 0x6806, 0x1078, 0x16df, 0x1078, - 0x17cb, 0x6810, 0x8001, 0x6812, 0x00c0, 0x16bf, 0x017f, 0x6902, - 0x6906, 0x007c, 0xa065, 0x0040, 0x16de, 0x6098, 0x609b, 0x0000, - 0x2008, 0x1078, 0x1678, 0x2100, 0x0078, 0x16d2, 0x007c, 0x6003, - 0x0103, 0x20a9, 0x001c, 0xac80, 0x0004, 0x20a0, 0x2001, 0x0000, - 0x40a4, 0x6828, 0x6016, 0x682c, 0x601e, 0x007c, 0x0e7e, 0x2071, - 0x3540, 0x7040, 0xa08c, 0x0080, 0x00c0, 0x16fc, 0xa088, 0x3580, - 0x2d0a, 0x8000, 0x7042, 0xa006, 0x0e7f, 0x007c, 0x0e7e, 0x2071, - 0x3540, 0x2009, 0x3580, 0x7240, 0x8221, 0x8211, 0x0048, 0x1716, - 0x2104, 0x8108, 0xad06, 0x00c0, 0x1705, 0x8119, 0x211e, 0x8108, - 0x8318, 0x8211, 0x00c8, 0x170e, 0x7442, 0xa006, 0x0e7f, 0x007c, - 0x1078, 0x1692, 0x2091, 0x8000, 0x6804, 0x781e, 0xa065, 0x0040, - 0x175f, 0x0078, 0x1729, 0x2c00, 0x781e, 0x6000, 0xa065, 0x0040, - 0x175f, 0x600c, 0xa306, 0x00c0, 0x1723, 0x6008, 0xa206, 0x00c0, - 0x1723, 0x2c28, 0x2001, 0x354f, 0x2004, 0xac06, 0x0040, 0x175f, - 0x6804, 0xac06, 0x00c0, 0x1746, 0x6000, 0x2060, 0x6806, 0xa005, - 0x00c0, 0x1746, 0x6803, 0x0000, 0x0078, 0x1750, 0x6400, 0x781c, - 0x2060, 0x6402, 0xa486, 0x0000, 0x00c0, 0x1750, 0x2c00, 0x6802, - 0x2560, 0x1078, 0x16df, 0x6017, 0x0005, 0x601f, 0x0020, 0x1078, - 0x17cb, 0x6810, 0x8001, 0x6812, 0x2001, 0xffff, 0xa005, 0x007c, - 0x2039, 0x0000, 0x2041, 0x0021, 0x2049, 0x0004, 0x2051, 0x0008, - 0x2091, 0x8000, 0x1078, 0x169f, 0x8738, 0xa784, 0x0007, 0x00c0, - 0x176a, 0xa7bc, 0xff00, 0x873f, 0x8738, 0x873f, 0xa784, 0x0f00, - 0x00c0, 0x176a, 0x2091, 0x8001, 0x007c, 0x2061, 0x0000, 0x6018, - 0xa084, 0x0001, 0x00c0, 0x178a, 0x78ac, 0x78af, 0x0000, 0xa005, - 0x00c0, 0x178b, 0x007c, 0xa08c, 0xfff0, 0x0040, 0x1791, 0x1078, - 0x1ba5, 0x0079, 0x1793, 0x17a3, 0x17a5, 0x17ab, 0x17af, 0x17a3, - 0x17b3, 0x17a3, 0x17a3, 0x17a3, 0x17a3, 0x17b9, 0x17bd, 0x17a3, - 0x17a3, 0x17a3, 0x17a3, 0x1078, 0x1ba5, 0x1078, 0x1760, 0x2001, - 0x8001, 0x0078, 0x17c3, 0x2001, 0x8003, 0x0078, 0x17c3, 0x2001, - 0x8004, 0x0078, 0x17c3, 0x1078, 0x1760, 0x2001, 0x8006, 0x0078, - 0x17c3, 0x2001, 0x800c, 0x0078, 0x17c3, 0x1078, 0x1760, 0x2001, - 0x800d, 0x0078, 0x17c3, 0x70c2, 0x2061, 0x0000, 0x601b, 0x0001, - 0x2091, 0x4080, 0x007c, 0x2c04, 0x6082, 0x2c08, 0x2063, 0x0000, - 0x7864, 0x8000, 0x7866, 0x7868, 0xa005, 0x796a, 0x0040, 0x17db, - 0x2c02, 0x0078, 0x17dc, 0x796e, 0x007c, 0x0c7e, 0x2061, 0x3500, - 0x6883, 0x0103, 0x2d08, 0x206b, 0x0000, 0x6064, 0x8000, 0x6066, - 0x6068, 0xa005, 0x616a, 0x0040, 0x17f0, 0x2d02, 0x0078, 0x17f1, - 0x616e, 0x0c7f, 0x007c, 0x1078, 0x1804, 0x0040, 0x1803, 0x0c7e, - 0x6098, 0xa065, 0x0040, 0x17fe, 0x1078, 0x16d2, 0x0c7f, 0x609b, - 0x0000, 0x1078, 0x1678, 0x007c, 0x786c, 0xa065, 0x0040, 0x1816, - 0x2091, 0x8000, 0x7864, 0x8001, 0x7866, 0x2c04, 0x786e, 0xa005, - 0x00c0, 0x1814, 0x786a, 0x8000, 0x2091, 0x8001, 0x007c, 0x7898, - 0xa005, 0x00c0, 0x1865, 0x7974, 0x70d0, 0x0005, 0x0005, 0x72d0, - 0xa206, 0x00c0, 0x181c, 0x2200, 0xa106, 0x00c0, 0x1833, 0x7804, - 0xa005, 0x0040, 0x1865, 0x7807, 0x0000, 0x0068, 0x1865, 0x2091, - 0x4080, 0x0078, 0x1865, 0x1078, 0x166f, 0x0040, 0x1865, 0x7a7c, - 0x7b78, 0x8107, 0x8004, 0x8004, 0xa210, 0xa399, 0x0000, 0x2009, - 0x0040, 0x1078, 0x163f, 0x0040, 0x185c, 0x1078, 0x1678, 0x7880, - 0x8000, 0x7882, 0xa086, 0x0002, 0x00c0, 0x1865, 0x2091, 0x8000, - 0x78af, 0x0002, 0x7883, 0x0000, 0x7898, 0xa085, 0x0003, 0x789a, - 0x2091, 0x8001, 0x0078, 0x1865, 0x7883, 0x0000, 0x1078, 0x1992, - 0x6000, 0xa084, 0x0007, 0x0079, 0x1866, 0x007c, 0x186e, 0x187d, - 0x189d, 0x186e, 0x18af, 0x186e, 0x186e, 0x186e, 0x2039, 0x0400, - 0x78a8, 0xa705, 0x78aa, 0x6004, 0xa705, 0x6006, 0x1078, 0x18ed, - 0x6018, 0x78a6, 0x1078, 0x197a, 0x007c, 0x78a8, 0xa084, 0x0100, - 0x0040, 0x1884, 0x0078, 0x186e, 0x78ab, 0x0000, 0x6000, 0x8007, - 0xa084, 0x00ff, 0x789e, 0x8001, 0x609b, 0x0000, 0x0040, 0x189a, - 0x1078, 0x18ed, 0x0040, 0x189a, 0x78a8, 0xa085, 0x0100, 0x78aa, - 0x0078, 0x189c, 0x1078, 0x1911, 0x007c, 0x78a8, 0xa08c, 0x0e00, - 0x00c0, 0x18a6, 0xa084, 0x0100, 0x00c0, 0x18a8, 0x0078, 0x186e, - 0x1078, 0x18ed, 0x00c0, 0x18ae, 0x1078, 0x1911, 0x007c, 0x78a8, - 0xa084, 0x0100, 0x0040, 0x18b6, 0x0078, 0x186e, 0x78ab, 0x0000, - 0x6710, 0x20a9, 0x0001, 0x6014, 0xa084, 0x00ff, 0xa005, 0x0040, - 0x18d3, 0xa7bc, 0xff00, 0x20a9, 0x0008, 0xa08e, 0x0001, 0x0040, - 0x18d3, 0x2039, 0x0000, 0x20a9, 0x0080, 0xa08e, 0x0002, 0x0040, - 0x18d3, 0x0078, 0x18ea, 0x1078, 0x1692, 0x2d00, 0x2091, 0x8000, - 0x682b, 0x0000, 0x682f, 0x0000, 0x6808, 0xa084, 0xffde, 0x680a, - 0x2d00, 0xa080, 0x0010, 0x2068, 0x2091, 0x8001, 0x0070, 0x18ea, - 0x0078, 0x18d6, 0x1078, 0x1678, 0x007c, 0x78a0, 0xa06d, 0x00c0, - 0x18f8, 0x2c00, 0x78a2, 0x78a6, 0x609b, 0x0000, 0x0078, 0x1904, - 0x2c00, 0x689a, 0x609b, 0x0000, 0x78a2, 0x2d00, 0x6002, 0x78a4, - 0xad06, 0x00c0, 0x1904, 0x6002, 0x789c, 0x8001, 0x789e, 0x00c0, - 0x1910, 0x78a8, 0xa084, 0x0000, 0x78aa, 0x78a4, 0x2060, 0xa006, - 0x007c, 0xa02e, 0x2530, 0x6118, 0xa184, 0x0060, 0x619e, 0x0040, - 0x191d, 0x0e7e, 0x1078, 0x2f13, 0x0e7f, 0x6592, 0x65a2, 0x6696, - 0x66a6, 0x60ab, 0x0000, 0x60af, 0x0000, 0x6710, 0x1078, 0x1692, - 0x2091, 0x8000, 0x6808, 0xa084, 0x0001, 0x0040, 0x193f, 0x2091, - 0x8001, 0x1078, 0x16df, 0x2091, 0x8000, 0x1078, 0x17cb, 0x2091, - 0x8001, 0x78a3, 0x0000, 0x78a7, 0x0000, 0x0078, 0x1979, 0x6020, - 0xa096, 0x0001, 0x00c0, 0x1946, 0x8000, 0x6022, 0x6a10, 0x6814, - 0x2091, 0x8001, 0xa202, 0x0048, 0x1955, 0x0040, 0x1955, 0x2039, - 0x0200, 0x1078, 0x197a, 0x0078, 0x1979, 0x2c08, 0x2091, 0x8000, - 0x6800, 0xa065, 0x0040, 0x195d, 0x6102, 0x6902, 0x00c0, 0x1961, - 0x6906, 0x2160, 0x6003, 0x0000, 0x6810, 0x8000, 0x6812, 0x2091, - 0x8001, 0x6808, 0xa08c, 0x0040, 0x0040, 0x1973, 0xa086, 0x0040, - 0x680a, 0x1078, 0x16ee, 0x1078, 0x1a19, 0x78a7, 0x0000, 0x78a3, - 0x0000, 0x007c, 0x6004, 0xa705, 0x6006, 0x2091, 0x8000, 0x1078, - 0x17cb, 0x2091, 0x8001, 0x78a4, 0xa065, 0x0040, 0x198d, 0x6098, - 0x78a6, 0x609b, 0x0000, 0x0078, 0x197d, 0x78a3, 0x0000, 0x78a7, - 0x0000, 0x007c, 0x7970, 0x7874, 0x8000, 0xa10a, 0x00c8, 0x1999, - 0xa006, 0x7876, 0x70d2, 0x7804, 0xa005, 0x0040, 0x19a7, 0x8001, - 0x7806, 0x00c0, 0x19a7, 0x0068, 0x19a7, 0x2091, 0x4080, 0x007c, - 0x0068, 0x19c2, 0x2029, 0x0000, 0x786c, 0xa065, 0x0040, 0x19bd, - 0x1078, 0x19c3, 0x0040, 0x19bd, 0x057e, 0x1078, 0x19d9, 0x057f, - 0x00c0, 0x19bd, 0x8528, 0x0078, 0x19ac, 0x85ff, 0x0040, 0x19c2, - 0x2091, 0x4080, 0x007c, 0x7b84, 0x7988, 0x72d4, 0x0005, 0x0005, - 0x70d4, 0xa206, 0x00c0, 0x19c5, 0x2200, 0xa102, 0x00c0, 0x19d3, - 0x2300, 0xa005, 0x007c, 0x0048, 0x19d7, 0xa302, 0x007c, 0x8002, - 0x007c, 0x1078, 0x1a0b, 0x2009, 0x001c, 0x6024, 0xa005, 0x0040, - 0x19e3, 0x2009, 0x0040, 0x1078, 0x1611, 0x0040, 0x19fc, 0x7894, - 0x8000, 0x7896, 0xa086, 0x0002, 0x00c0, 0x1a0a, 0x2091, 0x8000, - 0x78af, 0x0003, 0x7897, 0x0000, 0x7898, 0xa085, 0x0300, 0x789a, - 0x2091, 0x8001, 0x0078, 0x1a0a, 0x7897, 0x0000, 0x1078, 0x17f3, - 0x7984, 0x7888, 0x8000, 0xa10a, 0x00c8, 0x1a07, 0xa006, 0x788a, - 0x70d6, 0xa006, 0x007c, 0x8107, 0x8004, 0x8004, 0x7a90, 0x7b8c, - 0xa210, 0xa399, 0x0000, 0x007c, 0x2009, 0x3568, 0x2091, 0x8000, - 0x200a, 0x0f7e, 0x2079, 0x0100, 0x2009, 0x3540, 0x2091, 0x8000, - 0x2104, 0xa086, 0x0000, 0x00c0, 0x1a34, 0x2009, 0x3512, 0x2104, - 0xa005, 0x00c0, 0x1a34, 0x7830, 0xa084, 0x00c0, 0x00c0, 0x1a34, - 0x0018, 0x1a34, 0x781b, 0x0044, 0x2091, 0x8001, 0x0f7f, 0x007c, - 0x127e, 0x2091, 0x2300, 0x2071, 0x3540, 0x2079, 0x0100, 0x2019, - 0x2dd8, 0x20a1, 0x012b, 0x2304, 0xa005, 0x0040, 0x1a50, 0x789a, - 0x8318, 0x23ac, 0x8318, 0x2398, 0x53a6, 0x3318, 0x0078, 0x1a43, - 0x789b, 0x0020, 0x20a9, 0x0010, 0x78af, 0x0000, 0x78af, 0x0220, - 0x0070, 0x1a5c, 0x0078, 0x1a54, 0x7003, 0x0000, 0x1078, 0x1b5b, - 0x7004, 0xa084, 0x000f, 0xa085, 0x6280, 0x7806, 0x780f, 0x9200, - 0x7843, 0x00d8, 0x7853, 0x0080, 0x780b, 0x0038, 0x7047, 0x357f, - 0x7043, 0x0000, 0x127f, 0x2000, 0x007c, 0xa18c, 0x000f, 0x2011, - 0x0101, 0x2204, 0xa084, 0xfff0, 0xa105, 0x2012, 0x1078, 0x1b5b, - 0x007c, 0x2011, 0x0101, 0x20a9, 0x0009, 0x810b, 0x0070, 0x1a8a, - 0x0078, 0x1a85, 0xa18c, 0x0e00, 0x2204, 0xa084, 0xf1ff, 0xa105, - 0x2012, 0x007c, 0x2009, 0x0101, 0x20a9, 0x0005, 0x8213, 0x0070, - 0x1a9b, 0x0078, 0x1a96, 0xa294, 0x00e0, 0x2104, 0xa084, 0xff1f, - 0xa205, 0x200a, 0x007c, 0x2011, 0x0101, 0x20a9, 0x000c, 0x810b, - 0x0070, 0x1aac, 0x0078, 0x1aa7, 0xa18c, 0xf000, 0x2204, 0xa084, - 0x0fff, 0xa105, 0x2012, 0x007c, 0x2011, 0x0102, 0x2204, 0xa084, - 0xffcf, 0xa105, 0x2012, 0x007c, 0x8103, 0x8003, 0xa080, 0x0020, - 0x0c7e, 0x2061, 0x0100, 0x609a, 0x62ac, 0x63ac, 0x0c7f, 0x007c, - 0x8103, 0x8003, 0xa080, 0x0022, 0x0c7e, 0x2061, 0x0100, 0x609a, - 0x60a4, 0xa084, 0xffdf, 0x60ae, 0x0c7f, 0x007c, 0x8103, 0x8003, - 0xa080, 0x0022, 0x0c7e, 0x2061, 0x0100, 0x609a, 0x60a4, 0xa085, - 0x0020, 0x60ae, 0x0c7f, 0x007c, 0x8103, 0x8003, 0xa080, 0x0020, - 0x0c7e, 0x2061, 0x0100, 0x609a, 0x60a4, 0x62ae, 0x2010, 0x60a4, - 0x63ae, 0x2018, 0x0c7f, 0x007c, 0x2091, 0x8000, 0x0c7e, 0x0e7e, - 0x6818, 0xa005, 0x0040, 0x1b39, 0x2061, 0x3f80, 0x1078, 0x1b41, - 0x0040, 0x1b27, 0x20a9, 0x0000, 0x2061, 0x3e80, 0x0c7e, 0x1078, - 0x1b41, 0x0040, 0x1b13, 0x0c7f, 0x8c60, 0x0070, 0x1b11, 0x0078, - 0x1b06, 0x0078, 0x1b39, 0x007f, 0xa082, 0x3e80, 0x2071, 0x3540, - 0x70ba, 0x601c, 0xa085, 0x0800, 0x601e, 0x71b6, 0x60a7, 0x0000, - 0x2001, 0x0004, 0x70a2, 0x1078, 0x1a14, 0x0078, 0x1b35, 0x2071, - 0x3540, 0x601c, 0xa085, 0x0800, 0x601e, 0x71b6, 0x60a7, 0x0000, - 0x2001, 0x0006, 0x70a2, 0x1078, 0x1a14, 0x2001, 0x0000, 0x0078, - 0x1b3b, 0x2001, 0x0001, 0x2091, 0x8001, 0xa005, 0x0e7f, 0x0c7f, - 0x007c, 0x2c04, 0xa005, 0x0040, 0x1b58, 0x2060, 0x600c, 0xa306, - 0x00c0, 0x1b55, 0x6008, 0xa206, 0x00c0, 0x1b55, 0x6010, 0xa106, - 0x00c0, 0x1b55, 0xa006, 0x0078, 0x1b5a, 0x6000, 0x0078, 0x1b42, - 0xa085, 0x0001, 0x007c, 0x2011, 0x3541, 0x220c, 0xa18c, 0x000f, - 0x2011, 0x013b, 0x2204, 0xa084, 0x0100, 0x0040, 0x1b6a, 0x2021, - 0xff80, 0x2122, 0x007c, 0x0e7e, 0x68e4, 0xa08c, 0x0020, 0x0040, - 0x1ba3, 0xa084, 0x0006, 0x00c0, 0x1ba3, 0x6010, 0x8007, 0xa084, - 0x000f, 0x8003, 0x8003, 0x8003, 0xa0f0, 0x3600, 0x7004, 0xa084, - 0x000a, 0x00c0, 0x1ba3, 0x7108, 0xa194, 0xff00, 0x0040, 0x1ba3, - 0xa18c, 0x00ff, 0x2001, 0x0019, 0xa106, 0x0040, 0x1b96, 0x2001, - 0x0032, 0xa106, 0x0040, 0x1b9a, 0x0078, 0x1b9e, 0x2009, 0x0020, - 0x0078, 0x1ba0, 0x2009, 0x003f, 0x0078, 0x1ba0, 0x2011, 0x0000, - 0x2100, 0xa205, 0x700a, 0x0e7f, 0x007c, 0x0068, 0x1ba5, 0x007e, - 0x2071, 0x0000, 0x7018, 0xa084, 0x0001, 0x00c0, 0x1baa, 0x007f, - 0x2e08, 0x2071, 0x0010, 0x70ca, 0x007f, 0x70c6, 0x70c3, 0x8002, - 0x2071, 0x0000, 0x701b, 0x0001, 0x2091, 0x4080, 0x007f, 0x2070, - 0x007f, 0x0078, 0x1bc1, 0x107e, 0x007e, 0x127e, 0x2091, 0x2300, - 0x7f3c, 0x7e58, 0x7c30, 0x7d38, 0xa594, 0x003f, 0xa484, 0x4000, - 0x0040, 0x1bd8, 0xa784, 0x007c, 0x00c0, 0x2d9c, 0x1078, 0x1ba5, - 0xa49c, 0x000f, 0xa382, 0x0004, 0x0050, 0x1be0, 0x1078, 0x1ba5, - 0x8507, 0xa084, 0x000f, 0x0079, 0x1be5, 0x1fea, 0x209a, 0x20c0, - 0x22e6, 0x256b, 0x25b3, 0x25ea, 0x2665, 0x26bf, 0x2744, 0x1c0b, - 0x1bf5, 0x1e53, 0x1f1d, 0x254a, 0x1bf5, 0x1078, 0x1ba5, 0x0018, - 0x1bc8, 0x127f, 0x2091, 0x8001, 0x007f, 0x107f, 0x007c, 0x7003, - 0x0000, 0x703f, 0x0000, 0x7030, 0xa005, 0x0040, 0x1c09, 0x7033, - 0x0000, 0x0018, 0x1bc8, 0x705c, 0xa005, 0x00c0, 0x1cb6, 0x70a0, - 0xa084, 0x0007, 0x0079, 0x1c14, 0x1cd6, 0x1c1c, 0x1c2a, 0x1c4b, - 0x1c71, 0x1c9d, 0x1c9b, 0x1c1c, 0x7808, 0xa084, 0xfffd, 0x780a, - 0x2009, 0x0046, 0x1078, 0x2412, 0x00c0, 0x1c28, 0x7003, 0x0004, - 0x0078, 0x1bf7, 0x1078, 0x2d5e, 0x00c0, 0x1c49, 0x70b4, 0x8007, - 0x789b, 0x007e, 0x78aa, 0x789b, 0x0010, 0x78ab, 0x000c, 0x789b, - 0x0060, 0x78ab, 0x0001, 0x785b, 0x0004, 0x2009, 0x00f7, 0x1078, - 0x2410, 0x00c0, 0x1c49, 0x7003, 0x0004, 0x70c3, 0x000f, 0x7033, - 0x3570, 0x0078, 0x1bf7, 0x1078, 0x2d5e, 0x00c0, 0x1c6f, 0x71b4, - 0x8107, 0x789b, 0x007e, 0x78aa, 0x789b, 0x0010, 0xa18c, 0x0007, - 0xa18d, 0x00c0, 0x79aa, 0x78ab, 0x0006, 0x789b, 0x0060, 0x78ab, - 0x0002, 0x785b, 0x0004, 0x2009, 0x00f7, 0x1078, 0x2410, 0x00c0, - 0x1c6f, 0x7003, 0x0004, 0x70c3, 0x000f, 0x7033, 0x3570, 0x0078, - 0x1bf7, 0x1078, 0x2d5e, 0x00c0, 0x1c99, 0x71b4, 0x8107, 0x789b, - 0x007e, 0x78aa, 0x789b, 0x0010, 0xa18c, 0x0007, 0xa18d, 0x00c0, - 0x79aa, 0x78ab, 0x0020, 0x71b8, 0x79aa, 0x78ab, 0x000d, 0x789b, - 0x0060, 0x78ab, 0x0004, 0x785b, 0x0004, 0x2009, 0x00f7, 0x1078, - 0x2410, 0x00c0, 0x1c99, 0x7003, 0x0004, 0x70c3, 0x000f, 0x7033, - 0x3570, 0x0078, 0x1bf7, 0x0078, 0x1c4b, 0x1078, 0x2d5e, 0x00c0, - 0x1bf7, 0x70bc, 0x2068, 0x789b, 0x0010, 0x6f10, 0x1078, 0x2ca1, - 0x2c50, 0x6810, 0xa084, 0x0007, 0xa085, 0x0080, 0x78aa, 0x6e18, - 0x2041, 0x0001, 0x2001, 0x0004, 0x0078, 0x1dde, 0x1078, 0x2d5e, - 0x00c0, 0x1bf7, 0x789b, 0x0010, 0x705c, 0x2068, 0x6f10, 0x1078, - 0x2ca1, 0x2c50, 0x6008, 0xa085, 0x0010, 0x600a, 0x6810, 0xa084, - 0x0007, 0xa085, 0x0080, 0x78aa, 0x2031, 0x0020, 0x2041, 0x0001, - 0x1078, 0x2dc5, 0x2001, 0x0003, 0x0078, 0x1dc9, 0x0018, 0x1bc8, - 0x7440, 0xa485, 0x0000, 0x0040, 0x1cf0, 0xa080, 0x3580, 0x2030, - 0x7144, 0x8108, 0xa12a, 0x0048, 0x1ce7, 0x2009, 0x3580, 0x2164, - 0x6504, 0x85ff, 0x00c0, 0x1cfd, 0x8421, 0x00c0, 0x1ce1, 0x7146, - 0x7003, 0x0000, 0x703f, 0x0000, 0x0078, 0x1bf7, 0x7640, 0xa6b0, - 0x3580, 0x7144, 0x2600, 0x0078, 0x1cec, 0x7146, 0x2568, 0x2558, - 0x753e, 0x2c50, 0x6034, 0xa085, 0x0000, 0x00c0, 0x1cfa, 0x6708, - 0x7736, 0xa784, 0x013f, 0x0040, 0x1d2f, 0xa784, 0x0021, 0x00c0, - 0x1cfa, 0xa784, 0x0002, 0x0040, 0x1d1c, 0xa784, 0x0004, 0x0040, - 0x1cfa, 0xa7bc, 0xfffb, 0x670a, 0xa784, 0x0008, 0x00c0, 0x1cfa, - 0xa784, 0x0010, 0x00c0, 0x1cfa, 0xa784, 0x0100, 0x0040, 0x1d2f, - 0x6018, 0xa005, 0x00c0, 0x1cfa, 0xa7bc, 0xfeff, 0x670a, 0x681f, - 0x0000, 0x6e18, 0xa684, 0x000e, 0x6118, 0x0040, 0x1d3f, 0x601c, - 0xa102, 0x0048, 0x1d42, 0x0040, 0x1d42, 0x0078, 0x1cf6, 0x81ff, - 0x00c0, 0x1cf6, 0xa784, 0x0080, 0x00c0, 0x1d48, 0x700c, 0x6022, - 0xa7bc, 0xff7f, 0x670a, 0x6b10, 0x8307, 0xa084, 0x000f, 0x8003, - 0x8003, 0x8003, 0xa080, 0x3600, 0x2060, 0x2048, 0x704a, 0x6000, - 0x704e, 0x6004, 0x7052, 0x2a60, 0x0018, 0x1bc8, 0x789b, 0x0010, - 0xa046, 0x1078, 0x2d5e, 0x00c0, 0x1bf7, 0x6b10, 0xa39c, 0x0007, - 0xa39d, 0x00c0, 0x704c, 0xa084, 0x8000, 0x0040, 0x1d73, 0xa684, - 0x0001, 0x0040, 0x1d75, 0xa39c, 0xffbf, 0xa684, 0x0010, 0x0040, - 0x1d7b, 0xa39d, 0x0020, 0x7baa, 0x8840, 0xa684, 0x000e, 0x00c0, - 0x1d86, 0xa7bd, 0x0010, 0x670a, 0x0078, 0x1dc7, 0x714c, 0xa18c, - 0x0800, 0x0040, 0x2902, 0x2011, 0x0021, 0x8004, 0x8004, 0x0048, - 0x1d9d, 0x2011, 0x0022, 0x8004, 0x0048, 0x1d9d, 0x2011, 0x0020, - 0x8004, 0x0048, 0x1d9d, 0x0040, 0x1dc7, 0x7aaa, 0x8840, 0x1078, - 0x2d77, 0x6a10, 0x610c, 0x8108, 0xa18c, 0x00ff, 0xa1e0, 0x3e80, - 0x2c64, 0x8cff, 0x0040, 0x1dbe, 0x6010, 0xa206, 0x00c0, 0x1da8, - 0x60b4, 0x8001, 0x60b6, 0x00c0, 0x1da3, 0x0c7e, 0x2a60, 0x6008, - 0xa085, 0x0100, 0x600a, 0x0c7f, 0x0078, 0x1cd6, 0x1078, 0x2d5e, - 0x00c0, 0x1bf7, 0x2a60, 0x610e, 0x79aa, 0x8840, 0x712e, 0x2001, - 0x0001, 0x007e, 0x7150, 0xa184, 0x0018, 0x0040, 0x1ddd, 0xa184, - 0x0010, 0x0040, 0x1dd7, 0x1078, 0x2acc, 0x00c0, 0x1ddd, 0xa184, - 0x0008, 0x0040, 0x1ddd, 0x1078, 0x29e6, 0x007f, 0x7002, 0xa68c, - 0x0060, 0x88ff, 0x0040, 0x1de6, 0xa18d, 0x0004, 0x795a, 0x69b2, - 0x789b, 0x0060, 0x2800, 0x78aa, 0x789b, 0x0061, 0x6814, 0xa085, - 0x8000, 0x6816, 0x78aa, 0x157e, 0x137e, 0x147e, 0x20a1, 0x012c, - 0x789b, 0x0000, 0x8000, 0x80ac, 0xad80, 0x000a, 0x2098, 0x53a6, - 0x147f, 0x137f, 0x157f, 0x6810, 0x8007, 0x789b, 0x007e, 0x78aa, - 0x6d90, 0x7dd6, 0x7dde, 0x6e94, 0x7ed2, 0x7eda, 0x7830, 0xa084, - 0x00c0, 0x00c0, 0x1e15, 0x0098, 0x1e1d, 0x6008, 0xa084, 0xffef, - 0x600a, 0x1078, 0x2d77, 0x0078, 0x1bff, 0x7200, 0xa284, 0x0007, - 0xa086, 0x0001, 0x00c0, 0x1e2a, 0x781b, 0x0049, 0x1078, 0x2d77, - 0x0078, 0x1e3b, 0x6ab0, 0xa295, 0x2000, 0x7a5a, 0x781b, 0x0049, - 0x1078, 0x2d77, 0x7200, 0x2500, 0xa605, 0x0040, 0x1e3b, 0xa284, - 0x0007, 0x1079, 0x1e49, 0xad80, 0x0008, 0x7032, 0xa284, 0x0007, - 0xa086, 0x0001, 0x00c0, 0x1e47, 0x6018, 0x8000, 0x601a, 0x0078, - 0x1bf7, 0x1e51, 0x30f0, 0x30f0, 0x30df, 0x30f0, 0x1e51, 0x1e51, - 0x1e51, 0x1078, 0x1ba5, 0x7808, 0xa084, 0xfffd, 0x780a, 0x0f7e, - 0x2079, 0x3500, 0x7898, 0x0f7f, 0xa084, 0x0001, 0x0040, 0x1e79, - 0x70a0, 0xa086, 0x0001, 0x00c0, 0x1e68, 0x70a2, 0x0078, 0x1f01, - 0x70a0, 0xa086, 0x0005, 0x00c0, 0x1e77, 0x70bc, 0x2068, 0x6817, - 0x0004, 0x6813, 0x0000, 0x681c, 0xa085, 0x0008, 0x681e, 0x70a3, - 0x0000, 0x157e, 0x2011, 0x0004, 0x71a0, 0xa186, 0x0001, 0x0040, - 0x1e9b, 0xa186, 0x0007, 0x00c0, 0x1e8b, 0x2009, 0x352b, 0x200b, - 0x0005, 0x0078, 0x1e9b, 0x2009, 0x3513, 0x2104, 0x2009, 0x3512, - 0x200a, 0x2009, 0x352b, 0x200b, 0x0001, 0x70a3, 0x0000, 0x70a7, - 0x0001, 0x0078, 0x1e9d, 0x70a3, 0x0000, 0x1078, 0x2ec7, 0x20a9, - 0x0010, 0x2039, 0x0000, 0x1078, 0x2ba6, 0xa7b8, 0x0100, 0x0070, - 0x1eab, 0x0078, 0x1ea3, 0x7000, 0x2020, 0x0079, 0x1eaf, 0x1edd, - 0x1ec6, 0x1ec6, 0x1eb9, 0x1edd, 0x1edd, 0x1eb7, 0x1eb7, 0x1078, - 0x1ba5, 0x2021, 0x3557, 0x2404, 0xa005, 0x0040, 0x1ec6, 0xad06, - 0x00c0, 0x1ec6, 0x6800, 0x2022, 0x0078, 0x1ed6, 0x681c, 0xa084, - 0x0001, 0x00c0, 0x1ed2, 0x6f10, 0x1078, 0x2ca1, 0x1078, 0x28d9, - 0x0078, 0x1ed6, 0x7054, 0x2060, 0x6800, 0x6002, 0x6a16, 0x681c, - 0xa085, 0x0008, 0x681e, 0x1078, 0x17dd, 0x2021, 0x3f80, 0x1078, - 0x1f07, 0x2021, 0x3557, 0x1078, 0x1f07, 0x20a9, 0x0000, 0x2021, - 0x3e80, 0x1078, 0x1f07, 0x8420, 0x0070, 0x1ef0, 0x0078, 0x1ee9, - 0x20a9, 0x0080, 0x2061, 0x3680, 0x6018, 0x6110, 0xa102, 0x6012, - 0x601b, 0x0000, 0xace0, 0x0010, 0x0070, 0x1f00, 0x0078, 0x1ef4, - 0x157f, 0x7003, 0x0000, 0x703f, 0x0000, 0x0078, 0x1bf7, 0x047e, - 0x2404, 0xa005, 0x0040, 0x1f19, 0x2068, 0x6800, 0x007e, 0x6a16, - 0x681c, 0xa085, 0x0008, 0x681e, 0x1078, 0x17dd, 0x007f, 0x0078, - 0x1f09, 0x047f, 0x2023, 0x0000, 0x007c, 0xa282, 0x0003, 0x0050, - 0x1f23, 0x1078, 0x1ba5, 0x2300, 0x0079, 0x1f26, 0x1f29, 0x1f9c, - 0x1faa, 0xa282, 0x0002, 0x0040, 0x1f2f, 0x1078, 0x1ba5, 0x70a0, - 0x70a3, 0x0000, 0x70c3, 0x0000, 0x0079, 0x1f36, 0x1f3e, 0x1f3e, - 0x1f40, 0x1f74, 0x2908, 0x1f3e, 0x1f74, 0x1f3e, 0x1078, 0x1ba5, - 0x77b4, 0x1078, 0x2ba6, 0x77b4, 0xa7bc, 0x0f00, 0x1078, 0x2ca1, - 0x6018, 0xa005, 0x0040, 0x1f6b, 0x2021, 0x3f80, 0x2009, 0x0004, - 0x2011, 0x0010, 0x1078, 0x1fc5, 0x0040, 0x1f6b, 0x157e, 0x20a9, - 0x0000, 0x2021, 0x3e80, 0x047e, 0x2009, 0x0004, 0x2011, 0x0010, - 0x1078, 0x1fc5, 0x047f, 0x0040, 0x1f6a, 0x8420, 0x0070, 0x1f6a, - 0x0078, 0x1f5b, 0x157f, 0x8738, 0xa784, 0x0007, 0x00c0, 0x1f46, - 0x0078, 0x1bff, 0x0078, 0x1bff, 0x77b4, 0x1078, 0x2ca1, 0x6018, - 0xa005, 0x0040, 0x1f9a, 0x2021, 0x3f80, 0x2009, 0x0005, 0x2011, - 0x0020, 0x1078, 0x1fc5, 0x0040, 0x1f9a, 0x157e, 0x20a9, 0x0000, - 0x2021, 0x3e80, 0x047e, 0x2009, 0x0005, 0x2011, 0x0020, 0x1078, - 0x1fc5, 0x047f, 0x0040, 0x1f99, 0x8420, 0x0070, 0x1f99, 0x0078, - 0x1f8a, 0x157f, 0x0078, 0x1bff, 0x2200, 0x0079, 0x1f9f, 0x1fa2, - 0x1fa4, 0x1fa4, 0x1078, 0x1ba5, 0x70a3, 0x0000, 0x70a7, 0x0001, - 0x0078, 0x1bf7, 0x2200, 0x0079, 0x1fad, 0x1fb2, 0x1fa4, 0x1fb0, - 0x1078, 0x1ba5, 0x1078, 0x241f, 0x7000, 0xa086, 0x0001, 0x00c0, - 0x28af, 0x1078, 0x28ef, 0x6008, 0xa084, 0xffef, 0x600a, 0x1078, - 0x28a2, 0x0040, 0x28af, 0x0078, 0x1cd6, 0x2404, 0xa005, 0x0040, - 0x1fe6, 0x2068, 0x2d04, 0x007e, 0x6810, 0xa706, 0x0040, 0x1fd4, - 0x2d20, 0x007f, 0x0078, 0x1fc6, 0x007f, 0x2022, 0x6916, 0x681c, - 0xa205, 0x681e, 0x1078, 0x17dd, 0x6010, 0x8001, 0x6012, 0x6008, - 0xa084, 0xffef, 0x600a, 0x1078, 0x28ef, 0x007c, 0xa085, 0x0001, - 0x0078, 0x1fe5, 0x2300, 0x0079, 0x1fed, 0x1ff2, 0x1ff0, 0x2035, - 0x1078, 0x1ba5, 0x78e4, 0xa005, 0x00d0, 0x2015, 0x0018, 0x2015, - 0x2008, 0xa084, 0x0030, 0x00c0, 0x2001, 0x781b, 0x0049, 0x0078, - 0x1bf7, 0x78ec, 0xa084, 0x0003, 0x0040, 0x1ffd, 0x2100, 0xa084, - 0x0007, 0x0079, 0x200b, 0x2023, 0x2029, 0x201d, 0x2013, 0x2d58, - 0x2d58, 0x2013, 0x202f, 0x1078, 0x1ba5, 0x7000, 0xa005, 0x0040, - 0x1bff, 0x2001, 0x0003, 0x0078, 0x22fa, 0x1078, 0x2b89, 0x781b, - 0x0055, 0x0078, 0x1bf7, 0x1078, 0x2b89, 0x781b, 0x00dc, 0x0078, - 0x1bf7, 0x1078, 0x2b89, 0x781b, 0x00e3, 0x0078, 0x1bf7, 0x1078, - 0x2b89, 0x781b, 0x009d, 0x0078, 0x1bf7, 0xa584, 0x000f, 0x00c0, - 0x205f, 0x1078, 0x241f, 0x7000, 0x0079, 0x203e, 0x2046, 0x2053, - 0x2046, 0x28af, 0x2048, 0x28af, 0x2046, 0x2046, 0x1078, 0x1ba5, - 0x71a0, 0x70a3, 0x0000, 0xa186, 0x0004, 0x00c0, 0x2051, 0x0078, - 0x2908, 0x0078, 0x28af, 0x1078, 0x28ef, 0x6008, 0xa084, 0xffef, - 0x600a, 0x1078, 0x28a2, 0x0040, 0x28af, 0x0078, 0x1cd6, 0x78e4, - 0xa005, 0x00d0, 0x2015, 0x0018, 0x2015, 0x2008, 0xa084, 0x0030, - 0x00c0, 0x206e, 0x781b, 0x0049, 0x0078, 0x1bf7, 0x78ec, 0xa084, - 0x0003, 0x0040, 0x206a, 0x2100, 0xa184, 0x0007, 0x0079, 0x2078, - 0x2088, 0x208e, 0x2082, 0x2080, 0x2d58, 0x2d58, 0x2080, 0x2d50, - 0x1078, 0x1ba5, 0x1078, 0x2b91, 0x781b, 0x0055, 0x0078, 0x1bf7, - 0x1078, 0x2b91, 0x781b, 0x00dc, 0x0078, 0x1bf7, 0x1078, 0x2b91, - 0x781b, 0x00e3, 0x0078, 0x1bf7, 0x1078, 0x2b91, 0x781b, 0x009d, - 0x0078, 0x1bf7, 0x2300, 0x0079, 0x209d, 0x20a2, 0x20a0, 0x20a4, - 0x1078, 0x1ba5, 0x0078, 0x2665, 0x6817, 0x0008, 0x78a3, 0x0000, - 0x79e4, 0xa184, 0x0030, 0x0040, 0x2665, 0x78ec, 0xa084, 0x0003, - 0x0040, 0x2665, 0xa184, 0x0007, 0x0079, 0x20b6, 0x2023, 0x2029, - 0x201d, 0x2d30, 0x2d58, 0x2d58, 0x20be, 0x2d50, 0x1078, 0x1ba5, - 0xa282, 0x0005, 0x0050, 0x20c6, 0x1078, 0x1ba5, 0x2300, 0x0079, - 0x20c9, 0x20cc, 0x22ce, 0x22da, 0x2200, 0x0079, 0x20cf, 0x20d4, - 0x20d6, 0x20e9, 0x20d4, 0x22b3, 0x1078, 0x1ba5, 0x789b, 0x0018, - 0x78a8, 0xa084, 0x00ff, 0xa082, 0x0020, 0x0048, 0x2b6a, 0xa08a, - 0x0004, 0x00c8, 0x2b6a, 0x0079, 0x20e5, 0x2b6a, 0x2b6a, 0x2b6a, - 0x2b0c, 0x789b, 0x0018, 0x79a8, 0xa184, 0x0080, 0x0040, 0x20fe, - 0xa184, 0x0018, 0x0040, 0x20fa, 0x0078, 0x2b6a, 0x7000, 0xa005, - 0x00c0, 0x20f4, 0x2011, 0x0003, 0x0078, 0x2752, 0xa184, 0x00ff, - 0xa08a, 0x0010, 0x00c8, 0x2b6a, 0x0079, 0x2106, 0x2118, 0x2116, - 0x212e, 0x2130, 0x21c2, 0x2b6a, 0x2b6a, 0x21c4, 0x2b6a, 0x2b6a, - 0x22af, 0x22af, 0x2b6a, 0x2b6a, 0x2b6a, 0x22b1, 0x1078, 0x1ba5, - 0xa684, 0x1000, 0x0040, 0x2125, 0x2001, 0x0300, 0x8000, 0x8000, - 0x783a, 0x781b, 0x009a, 0x0078, 0x1bf7, 0x6814, 0xa084, 0x8000, - 0x0040, 0x212c, 0x6817, 0x0003, 0x0078, 0x2d30, 0x1078, 0x1ba5, - 0x691c, 0x691e, 0xa684, 0x1800, 0x00c0, 0x214a, 0x681c, 0xa084, - 0x0001, 0x00c0, 0x2152, 0x6814, 0xa086, 0x0008, 0x00c0, 0x2142, - 0x6817, 0x0000, 0xa684, 0x0400, 0x0040, 0x21be, 0x781b, 0x0058, - 0x0078, 0x1bf7, 0xa684, 0x1000, 0x0040, 0x2152, 0x781b, 0x0058, - 0x0078, 0x1bf7, 0xa684, 0x0060, 0x0040, 0x21ba, 0xa684, 0x0800, - 0x0040, 0x21ba, 0xa684, 0x8000, 0x00c0, 0x2160, 0x0078, 0x217a, - 0xa6b4, 0x7fff, 0x7e5a, 0x6eb2, 0x789b, 0x0074, 0x7aac, 0x79ac, - 0x78ac, 0x801b, 0x00c8, 0x216d, 0x8000, 0xa084, 0x003f, 0xa108, - 0xa291, 0x0000, 0x6b94, 0x2100, 0xa302, 0x68ae, 0x6b90, 0x2200, - 0xa303, 0x68aa, 0xa684, 0x4000, 0x0040, 0x2182, 0xa6b4, 0xbfff, - 0x7e5a, 0x6eb2, 0x7000, 0xa086, 0x0003, 0x00c0, 0x218f, 0x1078, - 0x2f3a, 0x1078, 0x30df, 0x781b, 0x0067, 0x0078, 0x1bf7, 0xa006, - 0x1078, 0x3194, 0x6aac, 0x69a8, 0x6c94, 0x6b90, 0x2200, 0xa105, - 0x0040, 0x219e, 0x2200, 0xa422, 0x2100, 0xa31b, 0x7cd2, 0x7bd6, - 0x2300, 0xa405, 0x00c0, 0x21ac, 0xa6b5, 0x4000, 0x7e5a, 0x6eb2, - 0x781b, 0x0067, 0x0078, 0x1bf7, 0x781b, 0x0067, 0x2200, 0xa115, - 0x00c0, 0x21b6, 0x1078, 0x30f0, 0x0078, 0x1bf7, 0x1078, 0x311d, - 0x0078, 0x1bf7, 0x781b, 0x006a, 0x0078, 0x1bf7, 0x781b, 0x0058, - 0x0078, 0x1bf7, 0x1078, 0x1ba5, 0x0078, 0x2221, 0x691c, 0xa184, - 0x0100, 0x0040, 0x21dc, 0xa18c, 0xfeff, 0x691e, 0x0c7e, 0x7048, - 0x2060, 0x6000, 0xa084, 0xefff, 0x6002, 0x6004, 0xa084, 0xfff5, - 0x6006, 0x0c7f, 0x0078, 0x2210, 0xa184, 0x0200, 0x0040, 0x2210, - 0xa18c, 0xfdff, 0x691e, 0x0c7e, 0x7048, 0x2060, 0x6000, 0xa084, - 0xdfff, 0x6002, 0x6004, 0xa084, 0xffef, 0x6006, 0x2008, 0x2c48, - 0x0c7f, 0xa184, 0x0008, 0x0040, 0x2210, 0x1078, 0x2c9d, 0x1078, - 0x29e6, 0x88ff, 0x0040, 0x2210, 0x789b, 0x0060, 0x2800, 0x78aa, - 0x7e58, 0xa6b5, 0x0004, 0x7e5a, 0xa684, 0x0400, 0x00c0, 0x220c, - 0x781b, 0x0055, 0x0078, 0x1bf7, 0x781b, 0x0069, 0x0078, 0x1bf7, - 0x7e58, 0xa684, 0x0400, 0x00c0, 0x2219, 0x781b, 0x0058, 0x0078, - 0x1bf7, 0x781b, 0x006a, 0x0078, 0x1bf7, 0x0078, 0x2b70, 0x0078, - 0x2b70, 0x2019, 0x0000, 0x7990, 0xa18c, 0x0007, 0x0040, 0x221f, - 0x789b, 0x0010, 0x78a8, 0xa094, 0x00ff, 0xa286, 0x0001, 0x00c0, - 0x2244, 0x2300, 0x7ca8, 0xa400, 0x2018, 0xa102, 0x0040, 0x223c, - 0x0048, 0x223c, 0x0078, 0x223e, 0x0078, 0x21c6, 0x24a8, 0x7aa8, - 0x00f0, 0x223e, 0x0078, 0x222a, 0xa284, 0x00f0, 0xa086, 0x0020, - 0x00c0, 0x22a0, 0x8318, 0x8318, 0x2300, 0xa102, 0x0040, 0x2254, - 0x0048, 0x2254, 0x0078, 0x229d, 0xa286, 0x0023, 0x0040, 0x221f, - 0x6818, 0xa084, 0xfff1, 0x681a, 0x7e58, 0xa684, 0xfff1, 0xa085, - 0x0010, 0x2030, 0x7e5a, 0x6008, 0xa085, 0x0010, 0x600a, 0x0c7e, - 0x7048, 0x2060, 0x6004, 0x2008, 0x2c48, 0x0c7f, 0xa184, 0x0010, - 0x0040, 0x2278, 0x1078, 0x2c9d, 0x1078, 0x2acc, 0x0078, 0x2287, - 0x0c7e, 0x7048, 0x2060, 0x6004, 0x2008, 0x2c48, 0x0c7f, 0xa184, - 0x0008, 0x0040, 0x2210, 0x1078, 0x2c9d, 0x1078, 0x29e6, 0x88ff, - 0x0040, 0x2210, 0x789b, 0x0060, 0x2800, 0x78aa, 0xa6b5, 0x0004, - 0x7e5a, 0xa684, 0x0400, 0x00c0, 0x2299, 0x781b, 0x0055, 0x0078, - 0x1bf7, 0x781b, 0x0069, 0x0078, 0x1bf7, 0x7aa8, 0x0078, 0x222a, - 0x8318, 0x2300, 0xa102, 0x0040, 0x22a9, 0x0048, 0x22a9, 0x0078, - 0x222a, 0xa284, 0x0080, 0x00c0, 0x2b76, 0x0078, 0x2b70, 0x0078, - 0x2b76, 0x0078, 0x2b6a, 0x789b, 0x0018, 0x78a8, 0xa084, 0x00ff, - 0xa08e, 0x0001, 0x0040, 0x22be, 0x1078, 0x1ba5, 0x7aa8, 0xa294, - 0x00ff, 0x78a8, 0xa084, 0x00ff, 0xa08a, 0x0004, 0x00c8, 0x2b6a, - 0x0079, 0x22ca, 0x2b6a, 0x2939, 0x2b6a, 0x2a67, 0xa282, 0x0000, - 0x00c0, 0x22d4, 0x1078, 0x1ba5, 0x1078, 0x2b89, 0x781b, 0x0069, - 0x0078, 0x1bf7, 0xa282, 0x0003, 0x00c0, 0x22e0, 0x1078, 0x1ba5, - 0x1078, 0x2b99, 0x781b, 0x0069, 0x0078, 0x1bf7, 0xa282, 0x0004, - 0x0050, 0x22ec, 0x1078, 0x1ba5, 0x2300, 0x0079, 0x22ef, 0x22f2, - 0x23c9, 0x23fa, 0xa286, 0x0003, 0x0040, 0x22f8, 0x1078, 0x1ba5, - 0x2001, 0x0000, 0x703a, 0x7000, 0xa084, 0x0007, 0x0079, 0x2300, - 0x2308, 0x230a, 0x230a, 0x2508, 0x2530, 0x24d2, 0x2308, 0x2308, - 0x1078, 0x1ba5, 0xa684, 0x1000, 0x00c0, 0x2312, 0x1078, 0x2ec7, - 0x0040, 0x23a3, 0x7868, 0xa08c, 0x00ff, 0x0040, 0x235a, 0xa186, - 0x0008, 0x00c0, 0x2329, 0x1078, 0x28ef, 0x6008, 0xa084, 0xffef, - 0x600a, 0x1078, 0x28a2, 0x0040, 0x235a, 0x1078, 0x2ec7, 0x0078, - 0x2341, 0xa186, 0x0028, 0x00c0, 0x235a, 0x1078, 0x2ec7, 0x6008, - 0xa084, 0xffef, 0x600a, 0x6018, 0xa005, 0x0040, 0x2341, 0x8001, - 0x601a, 0xa005, 0x0040, 0x2341, 0x8001, 0xa005, 0x0040, 0x2341, - 0x601e, 0x681c, 0xa084, 0x0001, 0x0040, 0x1bff, 0x681c, 0xa084, - 0xfffe, 0x681e, 0x7054, 0x0c7e, 0x2060, 0x6800, 0x6002, 0x0c7f, - 0x6004, 0x6802, 0xa005, 0x2d00, 0x00c0, 0x2357, 0x6002, 0x6006, - 0x0078, 0x1bff, 0x017e, 0x1078, 0x241f, 0x017f, 0xa684, 0xdf00, - 0x681a, 0x6827, 0x0000, 0x6f10, 0x81ff, 0x0040, 0x23a3, 0xa186, - 0x0002, 0x00c0, 0x239b, 0xa684, 0x0800, 0x00c0, 0x2377, 0xa684, - 0x0060, 0x0040, 0x2377, 0x78d8, 0x7adc, 0x682e, 0x6a2a, 0x8717, - 0xa294, 0x000f, 0x8213, 0x8213, 0x8213, 0xa290, 0x3600, 0xa290, - 0x0000, 0x221c, 0xa384, 0x0100, 0x00c0, 0x2388, 0x0078, 0x238e, - 0x8210, 0x2204, 0xa085, 0x0018, 0x2012, 0x8211, 0xa384, 0x0400, - 0x0040, 0x239b, 0x689c, 0xa084, 0x0100, 0x00c0, 0x239b, 0x1078, - 0x2491, 0x0078, 0x1bff, 0xa186, 0x0018, 0x0040, 0x23a3, 0xa186, - 0x0014, 0x0040, 0x1bff, 0x6912, 0x6814, 0xa084, 0x8000, 0x0040, - 0x23ab, 0x7038, 0x6816, 0xa68c, 0xdf00, 0x691a, 0x1078, 0x28e0, - 0x1078, 0x28ef, 0x00c0, 0x23b8, 0x6008, 0xa084, 0xffef, 0x600a, - 0x681c, 0xa084, 0x0001, 0x00c0, 0x23c1, 0x1078, 0x28d9, 0x0078, - 0x23c5, 0x7054, 0x2060, 0x6800, 0x6002, 0x1078, 0x17dd, 0x0078, - 0x1bff, 0xa282, 0x0004, 0x0048, 0x23cf, 0x1078, 0x1ba5, 0x2200, - 0x0079, 0x23d2, 0x23d6, 0x23d8, 0x23e5, 0x23d8, 0x1078, 0x1ba5, - 0x7000, 0xa086, 0x0005, 0x0040, 0x23e1, 0x1078, 0x2b89, 0x781b, - 0x0069, 0x781b, 0x006a, 0x0078, 0x1bf7, 0x7890, 0x8007, 0x8001, - 0xa084, 0x0007, 0xa080, 0x0018, 0x789a, 0x79a8, 0xa18c, 0x00ff, - 0xa186, 0x0003, 0x0040, 0x23f6, 0x0078, 0x2b6a, 0x781b, 0x006a, - 0x0078, 0x1bf7, 0x681c, 0xa085, 0x0004, 0x681e, 0x82ff, 0x00c0, - 0x2405, 0x1078, 0x2b89, 0x0078, 0x240c, 0x8211, 0x0040, 0x240a, - 0x1078, 0x1ba5, 0x1078, 0x2b99, 0x781b, 0x0069, 0x0078, 0x1bf7, - 0x1078, 0x2d77, 0x7830, 0xa084, 0x00c0, 0x00c0, 0x241c, 0x0018, - 0x241c, 0x791a, 0xa006, 0x007c, 0xa085, 0x0001, 0x007c, 0xa684, - 0x0060, 0x00c0, 0x2429, 0x682f, 0x0000, 0x682b, 0x0000, 0x0078, - 0x2490, 0xa684, 0x0800, 0x00c0, 0x2438, 0x68b0, 0xa084, 0x4800, - 0xa635, 0xa684, 0x0800, 0x00c0, 0x2438, 0x1078, 0x2ec7, 0x007c, - 0xa684, 0x0020, 0x0040, 0x2462, 0x78d0, 0x8003, 0x00c8, 0x2446, - 0xa006, 0x1078, 0x3194, 0x78d4, 0x1078, 0x31f9, 0xa684, 0x4000, - 0x0040, 0x2450, 0x682f, 0x0000, 0x682b, 0x0000, 0x0078, 0x2435, - 0x68b0, 0xa084, 0x4800, 0xa635, 0xa684, 0x4000, 0x00c0, 0x244a, - 0x7038, 0xa005, 0x00c0, 0x245c, 0x79d8, 0x7adc, 0x692e, 0x6a2a, - 0x0078, 0x2435, 0xa684, 0x4000, 0x0040, 0x246c, 0x682f, 0x0000, - 0x682b, 0x0000, 0x0078, 0x2435, 0x68b0, 0xa084, 0x4800, 0xa635, - 0xa684, 0x4000, 0x00c0, 0x2466, 0x7038, 0xa005, 0x00c0, 0x247a, - 0x703b, 0x0007, 0x79d8, 0x7adc, 0x78d0, 0x80f3, 0x00c8, 0x2481, - 0x8000, 0xa084, 0x003f, 0xa108, 0xa291, 0x0000, 0x692e, 0x6a2a, - 0x2100, 0xa205, 0x00c0, 0x248e, 0x0078, 0x2435, 0x1078, 0x3194, - 0x007c, 0xa384, 0x0200, 0x0040, 0x2499, 0x6008, 0xa085, 0x0002, - 0x600a, 0x6817, 0x0006, 0x6a28, 0x692c, 0x6a3a, 0x693e, 0x682b, - 0x0300, 0x682f, 0x0000, 0x6833, 0x2000, 0x6893, 0x0000, 0x6897, - 0x0020, 0x7000, 0x0079, 0x24ac, 0x24b4, 0x24b6, 0x24bf, 0x24b4, - 0x24b4, 0x24b4, 0x24b4, 0x24b4, 0x1078, 0x1ba5, 0x681c, 0xa084, - 0x0001, 0x00c0, 0x24bf, 0x1078, 0x28d9, 0x0078, 0x24c5, 0x7054, - 0x2c50, 0x2060, 0x6800, 0x6002, 0x2a60, 0x2021, 0x3557, 0x2404, - 0xa005, 0x0040, 0x24ce, 0x2020, 0x0078, 0x24c7, 0x2d22, 0x206b, - 0x0000, 0x007c, 0x77b4, 0x1078, 0x2ba6, 0xa7bc, 0x0f00, 0x1078, - 0x2ca1, 0x6018, 0xa005, 0x0040, 0x2501, 0x0d7e, 0x2001, 0x3f90, - 0x2068, 0x0d7f, 0x2021, 0x3f80, 0x2009, 0x0004, 0x2011, 0x0010, - 0x1078, 0x1fc5, 0x0040, 0x2501, 0x157e, 0x20a9, 0x0000, 0x2021, - 0x3e80, 0x047e, 0x2009, 0x0004, 0x2011, 0x0010, 0x1078, 0x1fc5, - 0x047f, 0x0040, 0x2500, 0x8420, 0x0070, 0x2500, 0x0078, 0x24f1, - 0x157f, 0x8738, 0xa784, 0x0007, 0x00c0, 0x24d7, 0x0078, 0x1bff, - 0x1078, 0x28e0, 0x1078, 0x28ef, 0x6827, 0x0000, 0x789b, 0x000e, - 0x6f10, 0x6813, 0x0002, 0x1078, 0x31ca, 0xa684, 0x0800, 0x0040, - 0x251d, 0x6918, 0xa18d, 0x2000, 0x691a, 0x6814, 0xa084, 0x8000, - 0x0040, 0x2524, 0x6817, 0x0000, 0x2021, 0x3557, 0x6800, 0x2022, - 0x6a38, 0x693c, 0x6a2a, 0x692e, 0x1078, 0x17dd, 0x0078, 0x1bff, - 0x1078, 0x241f, 0x6827, 0x0000, 0x789b, 0x000e, 0x6f10, 0x1078, - 0x2d7c, 0xa08c, 0x00ff, 0x6912, 0x6814, 0xa084, 0x8000, 0x0040, - 0x2543, 0x7038, 0x6816, 0xa68c, 0xdf00, 0x691a, 0x70a3, 0x0000, - 0x0078, 0x1bff, 0xa006, 0x1078, 0x2ec7, 0x6813, 0x0000, 0x6817, - 0x0001, 0xa68c, 0xdf00, 0x691a, 0x6827, 0x0000, 0x7000, 0x0079, - 0x2559, 0x2561, 0x2563, 0x2563, 0x2565, 0x2565, 0x2565, 0x2561, - 0x2561, 0x1078, 0x1ba5, 0x1078, 0x28ef, 0x6008, 0xa084, 0xffef, - 0x600a, 0x0078, 0x28ba, 0x2300, 0x0079, 0x256e, 0x2571, 0x2573, - 0x25b1, 0x1078, 0x1ba5, 0x7000, 0x0079, 0x2576, 0x257e, 0x2580, - 0x2580, 0x258b, 0x2580, 0x2592, 0x257e, 0x257e, 0x1078, 0x1ba5, - 0xa684, 0x2000, 0x00c0, 0x258b, 0xa6b5, 0x2000, 0x7e5a, 0x1078, - 0x30f0, 0x0078, 0x2d30, 0x6814, 0xa084, 0x8000, 0x0040, 0x2592, - 0x6817, 0x0007, 0x2009, 0x3518, 0x210c, 0xa186, 0x0000, 0x0040, - 0x25a7, 0xa186, 0x0001, 0x0040, 0x25ab, 0x2009, 0x352b, 0x200b, - 0x000b, 0x70a3, 0x0001, 0x781b, 0x0046, 0x0078, 0x1bf7, 0x781b, - 0x00dd, 0x0078, 0x1bf7, 0x2009, 0x352b, 0x200b, 0x000a, 0x0078, - 0x1bf7, 0x1078, 0x1ba5, 0x2300, 0x0079, 0x25b6, 0x25b9, 0x25bb, - 0x25de, 0x1078, 0x1ba5, 0x7000, 0x0079, 0x25be, 0x25c6, 0x25c8, - 0x25c8, 0x25d3, 0x25c8, 0x25da, 0x25c6, 0x25c6, 0x1078, 0x1ba5, - 0xa684, 0x2000, 0x00c0, 0x25d3, 0xa6b5, 0x2000, 0x7e5a, 0x1078, - 0x30f0, 0x0078, 0x2d30, 0x6814, 0xa084, 0x8000, 0x0040, 0x25da, - 0x6817, 0x0007, 0x781b, 0x00e4, 0x0078, 0x1bf7, 0x681c, 0xa085, - 0x0004, 0x681e, 0xa6b5, 0x0800, 0x1078, 0x2b89, 0x781b, 0x0069, - 0x0078, 0x1bf7, 0x2300, 0x0079, 0x25ed, 0x25f0, 0x25f2, 0x25f4, - 0x1078, 0x1ba5, 0x1078, 0x1ba5, 0xa684, 0x0400, 0x00c0, 0x2613, - 0x782b, 0x3009, 0x789b, 0x0060, 0x78ab, 0x0000, 0xa684, 0xfffb, - 0x785a, 0x79e4, 0xa184, 0x0020, 0x0040, 0x260b, 0x78ec, 0xa084, - 0x0003, 0x00c0, 0x260f, 0x2001, 0x0014, 0x0078, 0x22fa, 0xa184, - 0x0007, 0x0079, 0x264b, 0x7a90, 0xa294, 0x0007, 0x789b, 0x0060, - 0x79a8, 0x81ff, 0x0040, 0x2649, 0x789b, 0x0010, 0x7ba8, 0xa384, - 0x0001, 0x00c0, 0x263a, 0x7ba8, 0x7ba8, 0xa386, 0x0001, 0x00c0, - 0x262d, 0x2009, 0xfff7, 0x0078, 0x2633, 0xa386, 0x0003, 0x00c0, - 0x263a, 0x2009, 0xffef, 0x0c7e, 0x7048, 0x2060, 0x6004, 0xa104, - 0x6006, 0x0c7f, 0x789b, 0x0060, 0x78ab, 0x0000, 0xa684, 0xfffb, - 0x785a, 0x782b, 0x3009, 0x691c, 0xa18c, 0xfdff, 0xa18c, 0xfeff, - 0x691e, 0x0078, 0x2d30, 0x2023, 0x2029, 0x2655, 0x265d, 0x2653, - 0x2653, 0x2653, 0x2d30, 0x1078, 0x1ba5, 0x691c, 0xa18c, 0xfdff, - 0xa18c, 0xfeff, 0x691e, 0x0078, 0x2d38, 0x691c, 0xa18c, 0xfdff, - 0xa18c, 0xfeff, 0x691e, 0x0078, 0x2d30, 0x79e4, 0xa184, 0x0030, - 0x0040, 0x266f, 0x78ec, 0xa084, 0x0003, 0x00c0, 0x2677, 0x6814, - 0xa085, 0x8000, 0x6816, 0x2001, 0x0014, 0x0078, 0x22fa, 0xa184, - 0x0007, 0x0079, 0x267b, 0x2d30, 0x2d30, 0x2683, 0x2d30, 0x2d58, - 0x2d58, 0x2d30, 0x2d30, 0xa684, 0x0400, 0x00c0, 0x26b4, 0x681c, - 0xa084, 0x0001, 0x0040, 0x2d38, 0xa68c, 0x2060, 0xa18c, 0xfffb, - 0x795a, 0x69b2, 0x789b, 0x0060, 0x78ab, 0x0000, 0x789b, 0x0061, - 0x6814, 0xa085, 0x8000, 0x6816, 0x78aa, 0x157e, 0x137e, 0x147e, - 0x20a1, 0x012c, 0x789b, 0x0000, 0x8000, 0x80ac, 0xad80, 0x000a, - 0x2098, 0x53a6, 0x147f, 0x137f, 0x157f, 0x6810, 0x8007, 0x789b, - 0x007e, 0x78aa, 0x0078, 0x2d38, 0x6814, 0xa084, 0x8000, 0x0040, - 0x26bb, 0x6817, 0x0008, 0x781b, 0x00d8, 0x0078, 0x1bf7, 0x2300, - 0x0079, 0x26c2, 0x26c7, 0x2742, 0x26c5, 0x1078, 0x1ba5, 0x7000, - 0xa084, 0x0007, 0x0079, 0x26cc, 0x26d4, 0x26d6, 0x26f2, 0x26d4, - 0x26d4, 0x24d2, 0x26d4, 0x26d4, 0x1078, 0x1ba5, 0x691c, 0xa18d, - 0x0001, 0x691e, 0x6800, 0x6006, 0xa005, 0x00c0, 0x26e0, 0x6002, - 0x6818, 0xa084, 0x000e, 0x0040, 0x26ec, 0x7014, 0x68b6, 0x712c, - 0xa188, 0x3e80, 0x0078, 0x26ee, 0x2009, 0x3f80, 0x2104, 0x6802, - 0x2d0a, 0x7156, 0x6eb2, 0xa684, 0x0060, 0x0040, 0x2740, 0xa684, - 0x0800, 0x00c0, 0x2704, 0xa684, 0x7fff, 0x68b2, 0x6890, 0x6894, - 0x1078, 0x2ec7, 0x0078, 0x2740, 0xa684, 0x0020, 0x0040, 0x2716, - 0xa006, 0x1078, 0x3194, 0x78d0, 0x8003, 0x00c8, 0x2712, 0x78d4, - 0x1078, 0x31f9, 0x79d8, 0x7adc, 0x0078, 0x271a, 0x1078, 0x2cae, - 0x1078, 0x3194, 0xa684, 0x8000, 0x0040, 0x2740, 0xa684, 0x7fff, - 0x68b2, 0x789b, 0x0074, 0x1078, 0x2d7c, 0x2010, 0x1078, 0x2d7c, - 0x2008, 0xa684, 0x0020, 0x00c0, 0x2738, 0x1078, 0x2d7c, 0x801b, - 0x00c8, 0x2733, 0x8000, 0xa084, 0x003f, 0xa108, 0xa291, 0x0000, - 0x6b94, 0x2100, 0xa302, 0x68ae, 0x6b90, 0x2200, 0xa303, 0x68aa, - 0x0078, 0x1bff, 0x0078, 0x2b76, 0x7033, 0x0000, 0xa282, 0x0005, - 0x0050, 0x274c, 0x1078, 0x1ba5, 0x2300, 0x0079, 0x274f, 0x2752, - 0x275c, 0x277f, 0x2200, 0x0079, 0x2755, 0x275a, 0x2b76, 0x275a, - 0x27a8, 0x27f9, 0x1078, 0x1ba5, 0x7000, 0xa086, 0x0001, 0x00c0, - 0x2769, 0x1078, 0x28ef, 0x1078, 0x2ec7, 0x7034, 0x600a, 0x0078, - 0x276e, 0x7000, 0xa086, 0x0003, 0x0040, 0x2763, 0x7003, 0x0005, - 0x2001, 0x3f90, 0x2068, 0x703e, 0x7032, 0x2200, 0x0079, 0x2778, - 0x2b76, 0x277d, 0x27a8, 0x277d, 0x2b76, 0x1078, 0x1ba5, 0x7000, - 0xa086, 0x0001, 0x00c0, 0x278c, 0x1078, 0x28ef, 0x1078, 0x2ec7, - 0x7034, 0x600a, 0x0078, 0x2791, 0x7000, 0xa086, 0x0003, 0x0040, - 0x2786, 0x7003, 0x0005, 0x2001, 0x3f90, 0x2068, 0x703e, 0x7032, - 0x2200, 0x0079, 0x279b, 0x27a2, 0x27a0, 0x27a2, 0x27a0, 0x27a2, - 0x1078, 0x1ba5, 0x1078, 0x2b99, 0x781b, 0x0069, 0x0078, 0x1bf7, - 0x7000, 0xa086, 0x0001, 0x00c0, 0x27b5, 0x1078, 0x28ef, 0x1078, - 0x2ec7, 0x7034, 0x600a, 0x0078, 0x27ba, 0x7000, 0xa086, 0x0003, - 0x0040, 0x27af, 0x7003, 0x0002, 0x7a80, 0xa294, 0x0f00, 0x789b, - 0x0018, 0x7ca8, 0xa484, 0x0007, 0xa215, 0x2069, 0x3f80, 0x2d04, - 0x2d08, 0x7156, 0x2068, 0xa005, 0x0040, 0x27d5, 0x6810, 0xa206, - 0x0040, 0x27ee, 0x6800, 0x0078, 0x27c8, 0x7003, 0x0005, 0x2001, - 0x3f90, 0x2068, 0x703e, 0x7032, 0x157e, 0x20a9, 0x002f, 0x2003, - 0x0000, 0x8000, 0x0070, 0x27e6, 0x0078, 0x27df, 0x157f, 0x6a12, - 0x68b3, 0x0700, 0x681f, 0x0800, 0x6823, 0x0003, 0x6eb0, 0x7e5a, - 0x681c, 0xa084, 0x0c00, 0x0040, 0x284f, 0x1078, 0x2b91, 0x0078, - 0x284f, 0x7000, 0xa086, 0x0001, 0x00c0, 0x2806, 0x1078, 0x28ef, - 0x1078, 0x2ec7, 0x7034, 0x600a, 0x0078, 0x280b, 0x7000, 0xa086, - 0x0003, 0x0040, 0x2800, 0x7003, 0x0002, 0x7a80, 0xa294, 0x0f00, - 0x789b, 0x0018, 0x7ca8, 0xa484, 0x0007, 0xa215, 0x79a8, 0x79a8, - 0xa18c, 0x00ff, 0xa1e8, 0x3e80, 0x2d04, 0x2d08, 0x7156, 0x2068, - 0xa005, 0x0040, 0x282a, 0x6810, 0xa206, 0x0040, 0x2843, 0x6800, - 0x0078, 0x281d, 0x7003, 0x0005, 0x2001, 0x3f90, 0x2068, 0x703e, - 0x7032, 0x157e, 0x20a9, 0x002f, 0x2003, 0x0000, 0x8000, 0x0070, - 0x283b, 0x0078, 0x2834, 0x157f, 0x6a12, 0x68b3, 0x0700, 0x681f, - 0x0800, 0x6823, 0x0003, 0x6eb0, 0x7e5a, 0x681c, 0xa084, 0x0c00, - 0x0040, 0x284f, 0x1078, 0x2b8d, 0x7e58, 0x0078, 0x284f, 0x027e, - 0x8207, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa080, 0x3600, - 0x2060, 0x704a, 0x6000, 0x704e, 0x6004, 0x7052, 0xa684, 0x0060, - 0x0040, 0x2886, 0x6b94, 0x6c90, 0x69a8, 0x68ac, 0xa105, 0x00c0, - 0x2874, 0x7bd2, 0x7bda, 0x7cd6, 0x7cde, 0xa6b4, 0xb7ff, 0x7e5a, - 0x1078, 0x30f0, 0x0078, 0x2886, 0x68ac, 0xa31a, 0x2100, 0xa423, - 0x2400, 0xa305, 0x0040, 0x2886, 0x7bd2, 0x7bda, 0x7cd6, 0x7cde, - 0x68ac, 0xa6b4, 0xbfff, 0x7e5a, 0x1078, 0x311d, 0x077f, 0x1078, - 0x2ca1, 0x2009, 0x006a, 0xa684, 0x0008, 0x0040, 0x2891, 0x2009, - 0x0069, 0xa6b5, 0x2000, 0x7e5a, 0x791a, 0x2d00, 0x703e, 0x8207, - 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa080, 0x3600, 0x2048, - 0x0078, 0x1bf7, 0x6020, 0xa005, 0x0040, 0x28ae, 0x8001, 0x6022, - 0x6008, 0xa085, 0x0008, 0x600a, 0x7010, 0x6026, 0x007c, 0xa006, - 0x1078, 0x2ec7, 0x6813, 0x0000, 0x6817, 0x0001, 0x681f, 0x0040, - 0x681b, 0x0100, 0x7000, 0xa084, 0x0007, 0x0079, 0x28bf, 0x28c7, - 0x28c9, 0x28c9, 0x28d5, 0x28d1, 0x28c7, 0x28c7, 0x28c7, 0x1078, - 0x1ba5, 0x1078, 0x28e0, 0x1078, 0x28d9, 0x1078, 0x17dd, 0x0078, - 0x1bff, 0x70a3, 0x0000, 0x0078, 0x1bff, 0x6817, 0x0000, 0x0078, - 0x2508, 0x6800, 0xa005, 0x00c0, 0x28de, 0x6002, 0x6006, 0x007c, - 0x6010, 0xa005, 0x0040, 0x28e9, 0x8001, 0x00d0, 0x28e9, 0x1078, - 0x1ba5, 0x6012, 0x6008, 0xa084, 0xffef, 0x600a, 0x007c, 0x6018, - 0xa005, 0x0040, 0x28f5, 0x8001, 0x601a, 0x007c, 0x1078, 0x2d77, - 0x6817, 0x0018, 0x0078, 0x2926, 0x1078, 0x2d77, 0x6817, 0x0019, - 0x0078, 0x2926, 0x1078, 0x2d77, 0x6817, 0x001a, 0x0078, 0x2926, - 0x77b4, 0x1078, 0x2ca1, 0x71b8, 0xa18c, 0x00ff, 0xa1e8, 0x3e80, - 0x2d04, 0x2d08, 0x2068, 0xa005, 0x00c0, 0x2918, 0x0078, 0x1bff, - 0x6810, 0x72b4, 0xa206, 0x0040, 0x2920, 0x6800, 0x0078, 0x2911, - 0x6800, 0x200a, 0x6817, 0x0005, 0x70bf, 0x0000, 0x1078, 0x28e0, - 0x681c, 0xa084, 0x0001, 0x00c0, 0x292f, 0x1078, 0x28d9, 0x1078, - 0x28ef, 0x681b, 0x0000, 0x681f, 0x0020, 0x1078, 0x17dd, 0x0078, - 0x1bff, 0xa282, 0x0003, 0x00c0, 0x2b6a, 0x7da8, 0xa5ac, 0x00ff, - 0x7ea8, 0xa6b4, 0x00ff, 0x691c, 0xa18d, 0x0080, 0x691e, 0xa184, - 0x0100, 0x0040, 0x2999, 0xa18c, 0xfeff, 0x691e, 0xa6b4, 0x00ff, - 0x0040, 0x2983, 0xa682, 0x000f, 0x0048, 0x295a, 0x0040, 0x295a, - 0x2031, 0x000f, 0x852b, 0x852b, 0x1078, 0x2c24, 0x0040, 0x2964, - 0x1078, 0x2a33, 0x0078, 0x298c, 0x1078, 0x2bdf, 0x0c7e, 0x2960, - 0x6004, 0xa084, 0xfff5, 0x6006, 0x1078, 0x2a57, 0x0c7f, 0x691c, - 0xa18d, 0x0100, 0x691e, 0x7e58, 0xa6b5, 0x0004, 0x7e5a, 0xa684, - 0x0400, 0x00c0, 0x297f, 0x781b, 0x0055, 0x0078, 0x1bf7, 0x781b, - 0x0069, 0x0078, 0x1bf7, 0x0c7e, 0x2960, 0x6004, 0xa084, 0xfff5, - 0x6006, 0x1078, 0x2a57, 0x0c7f, 0x7e58, 0xa684, 0x0400, 0x00c0, - 0x2995, 0x781b, 0x0058, 0x0078, 0x1bf7, 0x781b, 0x006a, 0x0078, - 0x1bf7, 0x0c7e, 0x7048, 0x2060, 0x6100, 0xa18c, 0x1000, 0x0040, - 0x29d9, 0x6208, 0x8217, 0xa294, 0x00ff, 0xa282, 0x000f, 0x0048, - 0x29ad, 0x0040, 0x29ad, 0x2011, 0x000f, 0x2600, 0xa202, 0x00c8, - 0x29b2, 0x2230, 0x6208, 0xa294, 0x00ff, 0x7018, 0xa086, 0x0028, - 0x00c0, 0x29c2, 0xa282, 0x0019, 0x00c8, 0x29c8, 0x2011, 0x0019, - 0x0078, 0x29c8, 0xa282, 0x000c, 0x00c8, 0x29c8, 0x2011, 0x000c, - 0x2200, 0xa502, 0x00c8, 0x29cd, 0x2228, 0x1078, 0x2be3, 0x852b, - 0x852b, 0x1078, 0x2c24, 0x0040, 0x29d9, 0x1078, 0x2a33, 0x0078, - 0x29dd, 0x1078, 0x2bdf, 0x1078, 0x2a57, 0x7858, 0xa085, 0x0004, - 0x785a, 0x0c7f, 0x781b, 0x0069, 0x0078, 0x1bf7, 0x0c7e, 0x2960, - 0x6000, 0xa084, 0x1000, 0x00c0, 0x2a01, 0x6010, 0xa084, 0x000f, - 0x00c0, 0x29fb, 0xa18c, 0x0002, 0x00c0, 0x29fb, 0xa18c, 0xfff5, - 0x6106, 0x0c7f, 0x007c, 0x2011, 0x0032, 0x2019, 0x0000, 0x0078, - 0x2a23, 0x6208, 0xa294, 0x00ff, 0x7018, 0xa086, 0x0028, 0x00c0, - 0x2a11, 0xa282, 0x0019, 0x00c8, 0x2a17, 0x2011, 0x0019, 0x0078, - 0x2a17, 0xa282, 0x000c, 0x00c8, 0x2a17, 0x2011, 0x000c, 0x6308, - 0x831f, 0xa39c, 0x00ff, 0xa382, 0x000f, 0x0048, 0x2a23, 0x0040, - 0x2a23, 0x2019, 0x000f, 0x78ab, 0x0001, 0x78ab, 0x0003, 0x78ab, - 0x0001, 0x7aaa, 0x7baa, 0xa8c0, 0x0005, 0x681c, 0xa085, 0x0100, - 0x681e, 0x0c7f, 0x007c, 0x0c7e, 0x7148, 0x2160, 0x2008, 0xa084, - 0xfff0, 0xa635, 0x7e86, 0x6018, 0x789a, 0x7eae, 0x6612, 0x78a4, - 0xa084, 0xfff8, 0xa18c, 0x0007, 0xa105, 0x78a6, 0x6016, 0x788a, - 0xa6b4, 0x000f, 0x8637, 0x8204, 0x8004, 0xa084, 0x00ff, 0xa605, - 0x600e, 0x6004, 0xa084, 0xfff5, 0x6006, 0x0c7f, 0x007c, 0x0c7e, - 0x7048, 0x2060, 0x6018, 0x789a, 0x78a4, 0xa084, 0xfff0, 0x78a6, - 0x6012, 0x7884, 0xa084, 0xfff0, 0x7886, 0x0c7f, 0x007c, 0xa282, - 0x0002, 0x00c0, 0x2b6a, 0x7aa8, 0x691c, 0xa18d, 0x0080, 0x691e, - 0xa184, 0x0200, 0x0040, 0x2aac, 0xa18c, 0xfdff, 0x691e, 0xa294, - 0x00ff, 0xa282, 0x0002, 0x00c8, 0x2b6a, 0x1078, 0x2af3, 0x1078, - 0x2a57, 0xa980, 0x0001, 0x200c, 0x1078, 0x2c9d, 0x1078, 0x29e6, - 0x88ff, 0x0040, 0x2a9f, 0x789b, 0x0060, 0x2800, 0x78aa, 0x7e58, - 0xa6b5, 0x0004, 0x7e5a, 0xa684, 0x0400, 0x00c0, 0x2a9b, 0x781b, - 0x0055, 0x0078, 0x1bf7, 0x781b, 0x0069, 0x0078, 0x1bf7, 0x7e58, - 0xa684, 0x0400, 0x00c0, 0x2aa8, 0x781b, 0x0058, 0x0078, 0x1bf7, - 0x781b, 0x006a, 0x0078, 0x1bf7, 0xa282, 0x0002, 0x00c8, 0x2ab4, - 0xa284, 0x0001, 0x0040, 0x2abe, 0x7148, 0xa188, 0x0000, 0x210c, - 0xa18c, 0x2000, 0x00c0, 0x2abe, 0x2011, 0x0000, 0x1078, 0x2bd1, - 0x1078, 0x2af3, 0x1078, 0x2a57, 0x7858, 0xa085, 0x0004, 0x785a, - 0x781b, 0x0069, 0x0078, 0x1bf7, 0x0c7e, 0x027e, 0x2960, 0x6000, - 0x2011, 0x0001, 0xa084, 0x2000, 0x00c0, 0x2ae3, 0x6014, 0xa084, - 0x0040, 0x00c0, 0x2ae1, 0xa18c, 0xffef, 0x6106, 0xa006, 0x0078, - 0x2af0, 0x2011, 0x0000, 0x78ab, 0x0001, 0x78ab, 0x0002, 0x78ab, - 0x0003, 0x7aaa, 0xa8c0, 0x0004, 0x681c, 0xa085, 0x0200, 0x681e, - 0x027f, 0x0c7f, 0x007c, 0x0c7e, 0x7048, 0x2060, 0x82ff, 0x0040, - 0x2afb, 0x2011, 0x0040, 0x6018, 0xa080, 0x0002, 0x789a, 0x78a4, - 0xa084, 0xffbf, 0xa205, 0x78a6, 0x6016, 0x788a, 0x6004, 0xa084, - 0xffef, 0x6006, 0x0c7f, 0x007c, 0x007e, 0x7000, 0xa086, 0x0003, - 0x0040, 0x2b15, 0x007f, 0x0078, 0x2b18, 0x007f, 0x0078, 0x2b66, - 0xa684, 0x0020, 0x0040, 0x2b66, 0x7888, 0xa084, 0x0040, 0x0040, - 0x2b66, 0x78a8, 0x8001, 0x0040, 0x2b25, 0x7bb8, 0xa384, 0x003f, - 0x831b, 0x00c8, 0x2b2c, 0x8000, 0xa005, 0x0040, 0x2b4d, 0x831b, - 0x00c8, 0x2b35, 0x8001, 0x0040, 0x2b62, 0xa006, 0x1078, 0x3194, - 0x78b4, 0x1078, 0x31f9, 0x0078, 0x2b66, 0xa684, 0x4000, 0x0040, - 0x2b4d, 0x78b8, 0x801b, 0x00c8, 0x2b46, 0x8000, 0xa084, 0x003f, - 0x00c0, 0x2b62, 0xa6b4, 0xbfff, 0x7e5a, 0x79d8, 0x7adc, 0x2001, - 0x0001, 0xa108, 0x00c8, 0x2b56, 0xa291, 0x0000, 0x79d2, 0x79da, - 0x7ad6, 0x7ade, 0x1078, 0x3194, 0x781b, 0x0067, 0x1078, 0x305e, - 0x0078, 0x1bf7, 0x781b, 0x0067, 0x0078, 0x1bf7, 0x781b, 0x006a, - 0x0078, 0x1bf7, 0x1078, 0x2b9d, 0x781b, 0x0069, 0x0078, 0x1bf7, - 0x1078, 0x2b89, 0x781b, 0x0069, 0x0078, 0x1bf7, 0x6823, 0x0002, - 0x1078, 0x2b91, 0x691c, 0xa18d, 0x0020, 0x691e, 0x6814, 0xa084, - 0x8000, 0x0040, 0x2b85, 0x6817, 0x0005, 0x781b, 0x0069, 0x0078, - 0x1bf7, 0x2001, 0x0005, 0x0078, 0x2b9f, 0x2001, 0x000c, 0x0078, - 0x2b9f, 0x2001, 0x0006, 0x0078, 0x2b9f, 0x2001, 0x000d, 0x0078, - 0x2b9f, 0x2001, 0x0009, 0x0078, 0x2b9f, 0x2001, 0x0007, 0x789b, - 0x007f, 0x78aa, 0xa6b5, 0x0008, 0x7e5a, 0x007c, 0x077e, 0x873f, - 0xa7bc, 0x000f, 0x873b, 0x873b, 0x8703, 0xa0e0, 0x3600, 0xa7b8, - 0x0020, 0x7f9a, 0x79a4, 0xa184, 0x000f, 0x0040, 0x2bbf, 0xa184, - 0xfff0, 0x78a6, 0x6012, 0x6004, 0xa085, 0x0008, 0x6006, 0x8738, - 0x8738, 0x7f9a, 0x79a4, 0xa184, 0x0040, 0x0040, 0x2bcf, 0xa184, - 0xffbf, 0x78a6, 0x6016, 0x6004, 0xa085, 0x0010, 0x6006, 0x077f, - 0x007c, 0x789b, 0x0010, 0x78ab, 0x0001, 0x78ab, 0x0002, 0x78ab, - 0x0003, 0x7aaa, 0x789b, 0x0060, 0x78ab, 0x0004, 0x007c, 0x2031, - 0x0000, 0x2029, 0x0032, 0x789b, 0x0010, 0x78ab, 0x0001, 0x78ab, - 0x0003, 0x78ab, 0x0001, 0x7daa, 0x7eaa, 0x789b, 0x0060, 0x78ab, - 0x0005, 0x007c, 0x157e, 0x8007, 0xa084, 0x00ff, 0x8003, 0x8003, - 0xa080, 0x0020, 0x789a, 0x79a4, 0xa18c, 0xfff0, 0x2001, 0x3546, - 0x2004, 0xa082, 0x0028, 0x0040, 0x2c0d, 0x2021, 0x2c84, 0x2019, - 0x0014, 0x20a9, 0x000c, 0x0078, 0x2c13, 0x2021, 0x2c90, 0x2019, - 0x0019, 0x20a9, 0x000d, 0x2011, 0x0064, 0x2404, 0xa084, 0xfff0, - 0xa106, 0x0040, 0x2c22, 0x8420, 0x2300, 0xa210, 0x0070, 0x2c22, - 0x0078, 0x2c15, 0x157f, 0x007c, 0x157e, 0x2011, 0x3546, 0x2214, - 0xa282, 0x0032, 0x0048, 0x2c38, 0x0040, 0x2c3c, 0x2021, 0x2c76, - 0x2019, 0x0011, 0x20a9, 0x000e, 0x2011, 0x0032, 0x0078, 0x2c4c, - 0xa282, 0x0028, 0x0040, 0x2c44, 0x2021, 0x2c84, 0x2019, 0x0014, - 0x20a9, 0x000c, 0x0078, 0x2c4a, 0x2021, 0x2c90, 0x2019, 0x0019, - 0x20a9, 0x000d, 0x2011, 0x0064, 0x2200, 0xa502, 0x0040, 0x2c5c, - 0x0048, 0x2c5c, 0x8420, 0x2300, 0xa210, 0x0070, 0x2c59, 0x0078, - 0x2c4c, 0x157f, 0xa006, 0x007c, 0x157f, 0xa582, 0x0064, 0x00c8, - 0x2c65, 0x7808, 0xa085, 0x0070, 0x780a, 0x78ec, 0xa084, 0x0300, - 0x0040, 0x2c73, 0x2404, 0xa09e, 0x1201, 0x00c0, 0x2c73, 0x2001, - 0x2101, 0x0078, 0x2c74, 0x2404, 0xa005, 0x007c, 0x1201, 0x3002, - 0x3202, 0x4203, 0x4403, 0x5404, 0x5604, 0x6605, 0x6805, 0x7806, - 0x7a06, 0x0a07, 0x0c07, 0x0e07, 0x3202, 0x4202, 0x5202, 0x6202, - 0x7202, 0x6605, 0x7605, 0x7805, 0x7a05, 0x7c05, 0x7e05, 0x7f05, - 0x2202, 0x3202, 0x4202, 0x5202, 0x5404, 0x6404, 0x7404, 0x7604, - 0x7804, 0x7a04, 0x7c04, 0x7e04, 0x7f04, 0x789b, 0x0010, 0xa046, - 0x007c, 0xa784, 0x0f00, 0x800c, 0xa784, 0x0007, 0x8003, 0x8003, - 0x8003, 0x8003, 0xa105, 0xa0e0, 0x3680, 0x007c, 0x79d8, 0x7adc, - 0x78d0, 0x801b, 0x00c8, 0x2cb5, 0x8000, 0xa084, 0x003f, 0xa108, - 0xa291, 0x0000, 0x007c, 0x0f7e, 0x2079, 0x0100, 0x2009, 0x3540, - 0x2091, 0x8000, 0x2104, 0x0079, 0x2cc5, 0x2cf7, 0x2ccf, 0x2ccf, - 0x2ccf, 0x2ccf, 0x2ccf, 0x2ccd, 0x2ccd, 0x1078, 0x1ba5, 0x784b, - 0x0004, 0x7848, 0xa084, 0x0004, 0x00c0, 0x2cd1, 0x784b, 0x0008, - 0x7848, 0xa084, 0x0008, 0x00c0, 0x2cd8, 0x68b0, 0xa085, 0x4000, - 0x68b2, 0x7858, 0xa085, 0x4000, 0x785a, 0x7830, 0xa084, 0x0080, - 0x00c0, 0x2cf7, 0x0018, 0x2cf7, 0x6818, 0xa084, 0x0020, 0x00c0, - 0x2cf5, 0x781b, 0x00dd, 0x0078, 0x2cf7, 0x781b, 0x00e4, 0x2091, - 0x8001, 0x0f7f, 0x007c, 0x0c7e, 0x6810, 0x8007, 0xa084, 0x000f, - 0x8003, 0x8003, 0x8003, 0xa0e0, 0x3600, 0x6004, 0xa084, 0x000a, - 0x00c0, 0x2d2e, 0x6108, 0xa194, 0xff00, 0x0040, 0x2d2e, 0xa18c, - 0x00ff, 0x2001, 0x0019, 0xa106, 0x0040, 0x2d1d, 0x2001, 0x0032, - 0xa106, 0x0040, 0x2d21, 0x0078, 0x2d25, 0x2009, 0x0020, 0x0078, - 0x2d27, 0x2009, 0x003f, 0x0078, 0x2d27, 0x2011, 0x0000, 0x2100, - 0xa205, 0x600a, 0x6004, 0xa085, 0x0002, 0x6006, 0x0c7f, 0x007c, - 0x781b, 0x006a, 0x0078, 0x1bf7, 0x781b, 0x0069, 0x0078, 0x1bf7, - 0x781b, 0x0058, 0x0078, 0x1bf7, 0x781b, 0x0055, 0x0078, 0x1bf7, - 0x781b, 0x00dd, 0x0078, 0x1bf7, 0x781b, 0x00dc, 0x0078, 0x1bf7, - 0x781b, 0x00e4, 0x0078, 0x1bf7, 0x781b, 0x00e3, 0x0078, 0x1bf7, - 0x781b, 0x009e, 0x0078, 0x1bf7, 0x781b, 0x009d, 0x0078, 0x1bf7, - 0x70a3, 0x0001, 0x781b, 0x0046, 0x0078, 0x1bf7, 0x007e, 0x7830, - 0xa084, 0x00c0, 0x00c0, 0x2d75, 0x7808, 0xa084, 0xfffd, 0x780a, - 0x0005, 0x0005, 0x0005, 0x0005, 0x78ec, 0xa084, 0x0021, 0x0040, - 0x2d75, 0x7808, 0xa085, 0x0002, 0x780a, 0x007f, 0x007c, 0x7808, - 0xa085, 0x0002, 0x780a, 0x007c, 0x7830, 0xa084, 0x0040, 0x00c0, - 0x2d7c, 0x0098, 0x2d85, 0x78ac, 0x007c, 0x7808, 0xa084, 0xfffd, - 0x780a, 0x0005, 0x0005, 0x0005, 0x0005, 0x78ec, 0xa084, 0x0021, - 0x0040, 0x2d94, 0x0098, 0x2d92, 0x78ac, 0x007e, 0x7808, 0xa085, - 0x0002, 0x780a, 0x007f, 0x007c, 0xa784, 0x0070, 0x0040, 0x2da8, - 0x0c7e, 0x2d60, 0x2f68, 0x1078, 0x1b6b, 0x2d78, 0x2c68, 0x0c7f, - 0x6817, 0x0003, 0x7858, 0xa084, 0x3f00, 0x681a, 0x682f, 0x0000, - 0x682b, 0x0000, 0x784b, 0x0008, 0x78e4, 0xa005, 0x00d0, 0x2015, - 0xa084, 0x0020, 0x0040, 0x2015, 0x78ec, 0xa084, 0x0003, 0x0040, - 0x2015, 0x0018, 0x2015, 0x0078, 0x2b70, 0x0c7e, 0x6810, 0x8007, - 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa080, 0x3600, 0x2060, - 0x2048, 0x704a, 0x6000, 0x704e, 0x6004, 0x7052, 0x0c7f, 0x007c, - 0x0020, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, - 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, - 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, - 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, - 0x0000, 0x0020, 0x0062, 0x0009, 0x0014, 0x0014, 0x9847, 0x0014, - 0x0014, 0x98f5, 0x98e7, 0x0014, 0x0014, 0x0080, 0x00bf, 0x0100, - 0x0402, 0x2008, 0xf880, 0xa20a, 0x0014, 0x300b, 0xa20c, 0x0014, - 0xa200, 0x8838, 0x817e, 0x842a, 0x84a0, 0x3806, 0x8839, 0x28c2, - 0x9cc3, 0xa805, 0x0864, 0xa83b, 0x3008, 0x28c1, 0x9cc3, 0xa201, - 0x300c, 0x2847, 0x8161, 0x846a, 0x8000, 0x84a4, 0x1856, 0x883a, - 0xa808, 0x28e2, 0x9ca0, 0xa8f3, 0x0864, 0xa829, 0x300c, 0xa801, - 0x3008, 0x28e1, 0x9ca0, 0x280d, 0xa204, 0x64c0, 0x67a0, 0x6fc0, - 0x1814, 0x883b, 0x7023, 0x8576, 0x8677, 0xa80f, 0x786e, 0x883e, - 0xa80c, 0x282b, 0xa205, 0x64a0, 0x67a0, 0x6fc0, 0x1814, 0x883b, - 0x7023, 0x8576, 0x8677, 0xa801, 0x883e, 0x2069, 0x28c1, 0x9cc3, - 0x2044, 0x2103, 0x20a2, 0x2081, 0xa8dc, 0xa207, 0x0014, 0xa203, - 0x8000, 0x84a8, 0x85a4, 0x1872, 0x849a, 0x883c, 0x1fe2, 0xf601, - 0xa208, 0x856e, 0x866f, 0x0704, 0x3008, 0x9ca0, 0x0014, 0xa202, - 0x8000, 0x85a4, 0x3009, 0x84a8, 0x19e2, 0xf848, 0x8174, 0x86eb, - 0x85eb, 0x872e, 0x87a9, 0x883f, 0x08e6, 0xa8f1, 0xf861, 0xa8e8, - 0xf801, 0x0014, 0xf881, 0x0016, 0x85b2, 0x80f0, 0x9532, 0xfaa2, - 0x1de2, 0x0014, 0x8532, 0xf221, 0x0014, 0x1de2, 0x84a8, 0xd6e0, - 0x1fe6, 0x0014, 0xa206, 0x6865, 0x817f, 0x842a, 0x1dc1, 0x8823, - 0x0016, 0x6042, 0x8008, 0xa8fa, 0x8000, 0x84a4, 0x8160, 0x842a, - 0xf021, 0x3008, 0x84a8, 0x1dc6, 0x20d7, 0x8822, 0x0016, 0x8000, - 0x2848, 0x1011, 0xa8fc, 0x3008, 0x8000, 0xa000, 0x2802, 0x1011, - 0xa8fd, 0xa887, 0x3008, 0x283d, 0x1011, 0xa8fd, 0xa209, 0x0017, - 0x300c, 0x8000, 0x85a4, 0x1de2, 0xdac1, 0x0014, 0x26e0, 0x873a, - 0xfaa2, 0x19f2, 0x1fe2, 0x0014, 0xa20b, 0x0014, 0xa20d, 0x817e, - 0x842a, 0x84a0, 0x3806, 0x0210, 0x9ccd, 0x0704, 0x0000, 0x127e, - 0x2091, 0x2200, 0x2049, 0x2ec7, 0x7000, 0x7204, 0xa205, 0x720c, - 0xa215, 0x7008, 0xa084, 0xfffd, 0xa205, 0x0040, 0x2ed9, 0x0078, - 0x2ede, 0x7003, 0x0000, 0x127f, 0x2000, 0x007c, 0x7000, 0xa084, - 0x0001, 0x00c0, 0x2f0c, 0x7108, 0x8104, 0x00c8, 0x2eeb, 0x1078, - 0x2fa8, 0x0078, 0x2ee3, 0x700c, 0xa08c, 0x007f, 0x0040, 0x2f0c, - 0x7004, 0x8004, 0x00c8, 0x2f03, 0x7014, 0xa005, 0x00c0, 0x2eff, - 0x7010, 0xa005, 0x0040, 0x2f03, 0xa102, 0x00c8, 0x2ee3, 0x7007, - 0x0010, 0x0078, 0x2f0c, 0x8aff, 0x0040, 0x2f0c, 0x1078, 0x316b, - 0x00c0, 0x2f06, 0x0040, 0x2ee3, 0x1078, 0x2f56, 0x7003, 0x0000, - 0x127f, 0x2000, 0x007c, 0x6424, 0x84ff, 0x0040, 0x2f30, 0x2c70, - 0x2039, 0x2f35, 0x2704, 0xae68, 0x680c, 0xa630, 0x6808, 0xa529, - 0x8421, 0x0040, 0x2f30, 0x8738, 0x2704, 0xa005, 0x00c0, 0x2f1b, - 0x7098, 0xa075, 0x0040, 0x2f30, 0x2039, 0x2f32, 0x0078, 0x2f1a, - 0x007c, 0x0000, 0x0004, 0x0008, 0x000c, 0x0010, 0x0014, 0x0018, - 0x001c, 0x0000, 0x127e, 0x2091, 0x2200, 0x2079, 0x3500, 0x2071, - 0x0010, 0x7007, 0x000a, 0x7007, 0x0002, 0x7003, 0x0000, 0x2071, - 0x0020, 0x7007, 0x000a, 0x7007, 0x0002, 0x7003, 0x0000, 0x2049, - 0x0000, 0x78b3, 0x0000, 0x127f, 0x2000, 0x007c, 0x2049, 0x2f56, - 0x7004, 0x8004, 0x00c8, 0x2f82, 0x7007, 0x0012, 0x7108, 0x7008, - 0xa106, 0x00c0, 0x2f5e, 0xa184, 0x0030, 0x0040, 0x2f6b, 0xa086, - 0x0030, 0x00c0, 0x2f5e, 0x7000, 0xa084, 0x0001, 0x00c0, 0x2f82, - 0x7008, 0xa084, 0x000c, 0x00c0, 0x2f80, 0x710c, 0xa184, 0x0300, - 0x00c0, 0x2f80, 0xa184, 0x007f, 0x00c0, 0x2f56, 0x0078, 0x2f82, - 0x6817, 0x0003, 0x7007, 0x0012, 0x7007, 0x0008, 0x7004, 0xa084, - 0x0008, 0x00c0, 0x2f86, 0x7007, 0x0012, 0x7108, 0x8104, 0x0048, - 0x2f8b, 0x78b3, 0x0000, 0x7003, 0x0000, 0x2049, 0x0000, 0x007c, - 0x107e, 0x007e, 0x127e, 0x157e, 0x2091, 0x2200, 0x7108, 0x1078, - 0x2fa8, 0x157f, 0x127f, 0x2091, 0x8001, 0x007f, 0x107f, 0x007c, - 0x7204, 0x2118, 0x7108, 0x700c, 0xa084, 0x0300, 0x00c0, 0x2fea, - 0xa184, 0x000c, 0x00c0, 0x2fea, 0x8213, 0x8213, 0x8213, 0x8213, - 0xa284, 0x0100, 0xa10d, 0x810b, 0x810b, 0x810f, 0xa184, 0x0007, - 0x0079, 0x2fc2, 0x2fcc, 0x2fdc, 0x2fea, 0x2fdc, 0x2ffe, 0x2ffe, - 0x2fea, 0x2ffc, 0x1078, 0x1ba5, 0x7007, 0x0002, 0x8aff, 0x00c0, - 0x2fd5, 0x2049, 0x0000, 0x0078, 0x2fd9, 0x1078, 0x316b, 0x00c0, - 0x2fd5, 0x78b3, 0x0000, 0x007c, 0x7007, 0x0002, 0x8aff, 0x00c0, - 0x2fe3, 0x0078, 0x2fe7, 0x1078, 0x316b, 0x00c0, 0x2fe3, 0x78b3, - 0x0000, 0x007c, 0x7007, 0x0002, 0x1078, 0x2f56, 0x1078, 0x2cbb, - 0x6814, 0xa084, 0x8000, 0x0040, 0x2ff7, 0x6817, 0x0002, 0x007c, - 0x1078, 0x1ba5, 0x1078, 0x1ba5, 0x1078, 0x3050, 0x7210, 0x7114, - 0x700c, 0xa09c, 0x007f, 0x2800, 0xa300, 0xa211, 0xa189, 0x0000, - 0x78b0, 0xa005, 0x0040, 0x3010, 0x78b3, 0x0000, 0x0078, 0x3033, - 0x1078, 0x3050, 0x2704, 0x2c58, 0xac60, 0x630c, 0x2200, 0xa322, - 0x6308, 0x2100, 0xa31b, 0x2400, 0xa305, 0x0040, 0x3029, 0x00c8, - 0x3029, 0x8412, 0x8210, 0x830a, 0xa189, 0x0000, 0x2b60, 0x0078, - 0x3010, 0x2b60, 0x8a07, 0xa7ba, 0x2f32, 0xa73d, 0x2c00, 0x6882, - 0x6f86, 0x6c8e, 0x6b8a, 0x7007, 0x0012, 0x1078, 0x2f56, 0x007c, - 0x8738, 0x2704, 0xa005, 0x00c0, 0x3044, 0x6098, 0xa005, 0x0040, - 0x304d, 0x2060, 0x2039, 0x2f32, 0x8a51, 0x0040, 0x304c, 0x7008, - 0xa084, 0x00c0, 0xa086, 0x00c0, 0x007c, 0x2051, 0x0000, 0x007c, - 0x8a50, 0x8739, 0x2704, 0xa004, 0x00c0, 0x305d, 0x2039, 0x2f38, - 0x6000, 0xa064, 0x00c0, 0x305d, 0x2d60, 0x007c, 0x127e, 0x0d7e, - 0x2091, 0x2200, 0x0d7f, 0x6880, 0x2060, 0x6884, 0x6b88, 0x6c8c, - 0x8057, 0xaad4, 0x00ff, 0xa084, 0x00ff, 0xa0b8, 0x2f32, 0x7e08, - 0xa6b5, 0x000c, 0x6818, 0xa084, 0x0040, 0x0040, 0x3079, 0xa6b5, - 0x0001, 0x0f7e, 0x2079, 0x0100, 0x7858, 0x0f7f, 0xa084, 0x0040, - 0x0040, 0x3088, 0xa684, 0x0001, 0x00c0, 0x3088, 0xa6b5, 0x0001, - 0x7007, 0x0004, 0x7004, 0xa084, 0x0004, 0x00c0, 0x308a, 0x7000, - 0xa005, 0x0040, 0x3095, 0x1078, 0x1ba5, 0x2400, 0xa305, 0x00c0, - 0x309b, 0x0078, 0x30d8, 0x2c58, 0x2704, 0xac60, 0x6004, 0xa400, - 0x007e, 0x701a, 0x6000, 0xa301, 0x701e, 0x2009, 0x04fd, 0x2104, - 0xa086, 0x04fd, 0x007f, 0x00c0, 0x30c8, 0xa084, 0x0001, 0x0040, - 0x30c8, 0xa684, 0x0001, 0x00c0, 0x30c8, 0x7013, 0x0001, 0x7017, - 0x0000, 0x7602, 0x7007, 0x0001, 0x78b3, 0x0001, 0xa4a0, 0x0001, - 0xa399, 0x0000, 0x6004, 0xa400, 0x701a, 0x6000, 0xa301, 0x701e, - 0x620c, 0x2400, 0xa202, 0x7012, 0x6208, 0x2300, 0xa203, 0x7016, - 0x7602, 0x7007, 0x0001, 0x2b60, 0x1078, 0x3038, 0x0078, 0x30da, - 0x1078, 0x316b, 0x00c0, 0x30d8, 0x127f, 0x2000, 0x007c, 0x127e, - 0x0d7e, 0x2091, 0x2200, 0x0d7f, 0x7007, 0x0004, 0x7004, 0xa084, - 0x0004, 0x00c0, 0x30e6, 0x7003, 0x0008, 0x127f, 0x2000, 0x007c, - 0x127e, 0x0d7e, 0x2091, 0x2200, 0x0d7f, 0x2049, 0x30f0, 0x7007, - 0x0004, 0x7004, 0xa084, 0x0004, 0x00c0, 0x30f9, 0x7000, 0xa005, - 0x0040, 0x3104, 0x1078, 0x1ba5, 0x7e08, 0xa6b5, 0x000c, 0x6818, - 0xa084, 0x0040, 0x0040, 0x310e, 0xa6b5, 0x0001, 0x6824, 0xa005, - 0x0040, 0x311a, 0x2050, 0x2039, 0x2f35, 0x2d60, 0x1078, 0x316b, - 0x00c0, 0x3116, 0x127f, 0x2000, 0x007c, 0x127e, 0x007e, 0x017e, - 0x0d7e, 0x2091, 0x2200, 0x0d7f, 0x037f, 0x047f, 0x7e08, 0xa6b5, - 0x000c, 0x6818, 0xa084, 0x0040, 0x0040, 0x3130, 0xa6b5, 0x0001, - 0x2049, 0x311d, 0x6824, 0xa055, 0x0040, 0x3168, 0x2d70, 0x2e60, - 0x2039, 0x2f35, 0x2704, 0xae68, 0x680c, 0xa422, 0x6808, 0xa31b, - 0x0048, 0x3155, 0x8a51, 0x00c0, 0x3147, 0x1078, 0x1ba5, 0x8738, - 0x2704, 0xa005, 0x00c0, 0x313b, 0x7098, 0xa075, 0x2060, 0x0040, - 0x3168, 0x2039, 0x2f32, 0x0078, 0x313a, 0x8422, 0x8420, 0x831a, - 0xa399, 0x0000, 0x690c, 0x2400, 0xa122, 0x6908, 0x2300, 0xa11b, - 0x00c8, 0x3164, 0x1078, 0x1ba5, 0x2071, 0x0020, 0x0078, 0x3088, - 0x127f, 0x2000, 0x007c, 0x7008, 0xa084, 0x00c0, 0xa086, 0x00c0, - 0x0040, 0x3193, 0x2704, 0xac08, 0x2104, 0x701e, 0x8108, 0x2104, - 0x701a, 0x8108, 0x2104, 0x7016, 0x8108, 0x2104, 0x7012, 0x0f7e, - 0x2079, 0x0100, 0x7858, 0x0f7f, 0xa084, 0x0040, 0x0040, 0x318e, - 0xa684, 0x0001, 0x00c0, 0x318e, 0xa6b5, 0x0001, 0x7602, 0x7007, - 0x0001, 0x1078, 0x3038, 0x007c, 0x127e, 0x007e, 0x0d7e, 0x2091, - 0x2200, 0x2049, 0x3194, 0x0d7f, 0x087f, 0x7108, 0xa184, 0x00c0, - 0x00c0, 0x31aa, 0x6824, 0xa005, 0x0040, 0x31ba, 0x0078, 0x2ede, - 0x0078, 0x31ba, 0x7108, 0x8104, 0x00c8, 0x31b2, 0x1078, 0x2fa8, - 0x0078, 0x319d, 0x7007, 0x0010, 0x7108, 0x8104, 0x00c8, 0x31b4, - 0x1078, 0x2fa8, 0x7008, 0xa086, 0x0002, 0x00c0, 0x319d, 0x7000, - 0xa005, 0x00c0, 0x319d, 0x7003, 0x0000, 0x2049, 0x0000, 0x127f, - 0x2000, 0x007c, 0x127e, 0x147e, 0x137e, 0x157e, 0x0d7e, 0x2091, - 0x2200, 0x0d7f, 0x2049, 0x31ca, 0xad80, 0x0010, 0x20a0, 0x2099, - 0x0031, 0x700c, 0xa084, 0x007f, 0x6826, 0x7007, 0x0008, 0x7007, - 0x0002, 0x7003, 0x0001, 0x0040, 0x31e8, 0x8000, 0x80ac, 0x53a5, - 0x7007, 0x0004, 0x7004, 0xa084, 0x0004, 0x00c0, 0x31ea, 0x2049, - 0x0000, 0x7003, 0x0000, 0x157f, 0x137f, 0x147f, 0x127f, 0x2000, - 0x007c, 0x127e, 0x007e, 0x0d7e, 0x2091, 0x2200, 0x0d7f, 0x2049, - 0x31f9, 0x6880, 0x2060, 0x6884, 0x6b88, 0x6c8c, 0x8057, 0xaad4, - 0x00ff, 0xa084, 0x00ff, 0xa0b8, 0x2f32, 0x7e08, 0xa6b5, 0x0004, - 0x7007, 0x0004, 0x7004, 0xa084, 0x0004, 0x00c0, 0x3212, 0x2c58, - 0x2704, 0xac60, 0x6004, 0xa400, 0x701a, 0x6000, 0xa301, 0x701e, - 0x7013, 0x0001, 0x7017, 0x0000, 0x7602, 0x7007, 0x0001, 0x007f, - 0x8007, 0x2009, 0x0031, 0x200a, 0x00a0, 0x322c, 0x7108, 0x7007, - 0x0002, 0x810c, 0x00c8, 0x322c, 0x810c, 0x0048, 0x3239, 0x0078, - 0x2fea, 0xa4a0, 0x0001, 0xa399, 0x0000, 0x6b8a, 0x6c8e, 0x7007, - 0x0004, 0x2049, 0x0000, 0x7003, 0x0000, 0x127f, 0x2000, 0x007c, - 0x20a9, 0x0010, 0xa006, 0x8004, 0x8086, 0x818e, 0x00c8, 0x3251, - 0xa200, 0x00f0, 0x324c, 0x8086, 0x818e, 0x007c, 0x157e, 0x20a9, - 0x0010, 0xa005, 0x0040, 0x3277, 0xa11a, 0x00c8, 0x3277, 0x8213, - 0x818d, 0x0048, 0x326a, 0xa11a, 0x00c8, 0x326b, 0x00f0, 0x325f, - 0x0078, 0x326f, 0xa11a, 0x2308, 0x8210, 0x00f0, 0x325f, 0x007e, - 0x3200, 0xa084, 0xf7ff, 0x2080, 0x007f, 0x157f, 0x007c, 0x007e, - 0x3200, 0xa085, 0x0800, 0x0078, 0x3273, 0x00e0, 0x32bf, 0x2091, - 0x6000, 0x7820, 0x8001, 0x7822, 0x00c0, 0x32b9, 0x7824, 0x7822, - 0x2091, 0x8000, 0x2069, 0x3540, 0x6800, 0xa084, 0x0007, 0x0040, - 0x32a1, 0xa086, 0x0002, 0x0040, 0x32a1, 0x6830, 0xa00d, 0x0040, - 0x32a1, 0x2104, 0xa005, 0x0040, 0x32a1, 0x8001, 0x200a, 0x0040, - 0x336f, 0x2061, 0x3680, 0x20a9, 0x0080, 0x6034, 0xa005, 0x0040, - 0x32b3, 0x8001, 0x6036, 0x00c0, 0x32b3, 0x6010, 0xa005, 0x0040, - 0x32b3, 0x1078, 0x1a19, 0xace0, 0x0010, 0x0070, 0x32b9, 0x0078, - 0x32a5, 0x1078, 0x32d4, 0x1078, 0x32c2, 0x1078, 0x32f9, 0x2091, - 0x8001, 0x007c, 0x783c, 0x8001, 0x783e, 0x00c0, 0x32d3, 0x7840, - 0x783e, 0x7848, 0xa005, 0x0040, 0x32d3, 0x8001, 0x784a, 0x00c0, - 0x32d3, 0x1078, 0x1a19, 0x007c, 0x7834, 0x8001, 0x7836, 0x00c0, - 0x32f8, 0x7838, 0x7836, 0x2091, 0x8000, 0x7844, 0xa005, 0x00c0, - 0x32e3, 0x2001, 0x0101, 0x8001, 0x7846, 0xa080, 0x3e80, 0x2040, - 0x2004, 0xa065, 0x0040, 0x32f8, 0x6020, 0xa005, 0x0040, 0x32f4, - 0x8001, 0x6022, 0x0040, 0x3328, 0x6000, 0x2c40, 0x0078, 0x32e9, - 0x007c, 0x7828, 0x8001, 0x782a, 0x00c0, 0x3327, 0x782c, 0x782a, - 0x7830, 0xa005, 0x00c0, 0x3306, 0x2001, 0x0080, 0x8001, 0x7832, - 0x8003, 0x8003, 0x8003, 0x8003, 0xa090, 0x3680, 0xa298, 0x0002, - 0x2304, 0xa084, 0x0008, 0x0040, 0x3327, 0xa290, 0x0009, 0x2204, - 0xa005, 0x0040, 0x331f, 0x8001, 0x2012, 0x00c0, 0x3327, 0x2304, - 0xa084, 0xfff7, 0xa085, 0x0080, 0x201a, 0x1078, 0x1a19, 0x007c, - 0x2069, 0x3540, 0x6800, 0xa005, 0x0040, 0x3332, 0x683c, 0xac06, - 0x0040, 0x336f, 0x6017, 0x0006, 0x60b0, 0xa084, 0x3f00, 0x601a, - 0x601c, 0xa084, 0x00ff, 0xa085, 0x0060, 0x601e, 0x6000, 0x2042, - 0x6710, 0x6fb6, 0x1078, 0x1692, 0x6818, 0xa005, 0x0040, 0x334a, - 0x8001, 0x681a, 0x6808, 0xa084, 0xffef, 0x680a, 0x6810, 0x8001, - 0x00d0, 0x3354, 0x1078, 0x1ba5, 0x6812, 0x602f, 0x0000, 0x602b, - 0x0000, 0x2c68, 0x1078, 0x17dd, 0x2069, 0x3540, 0x2001, 0x0006, - 0x68a2, 0x7944, 0xa184, 0x0100, 0x00c0, 0x336a, 0x69ba, 0x2001, - 0x0004, 0x68a2, 0x1078, 0x1a14, 0x2091, 0x8001, 0x007c, 0x2009, - 0x354f, 0x2164, 0x2069, 0x0100, 0x1078, 0x1b6b, 0x6017, 0x0006, - 0x6858, 0xa084, 0x3f00, 0x601a, 0x601c, 0xa084, 0x00ff, 0xa085, - 0x0048, 0x601e, 0x602f, 0x0000, 0x602b, 0x0000, 0x6830, 0xa084, - 0x0040, 0x0040, 0x33ab, 0x684b, 0x0004, 0x20a9, 0x0014, 0x6848, - 0xa084, 0x0004, 0x0040, 0x3398, 0x0070, 0x3398, 0x0078, 0x338f, - 0x684b, 0x0009, 0x20a9, 0x0014, 0x6848, 0xa084, 0x0001, 0x0040, - 0x33a5, 0x0070, 0x33a5, 0x0078, 0x339c, 0x20a9, 0x00fa, 0x0070, - 0x33ab, 0x0078, 0x33a7, 0x6808, 0xa084, 0xfffd, 0x680a, 0x681b, - 0x0046, 0x2009, 0x3568, 0x200b, 0x0007, 0x784c, 0x784a, 0x2091, - 0x8001, 0x007c, 0x2079, 0x3500, 0x1078, 0x3403, 0x1078, 0x33cb, - 0x1078, 0x33e0, 0x1078, 0x33f5, 0x7833, 0x0000, 0x7847, 0x0000, - 0x784b, 0x0000, 0x007c, 0x2019, 0x000a, 0x2011, 0x3546, 0x2204, - 0xa086, 0x0032, 0x0040, 0x33dd, 0x2019, 0x000c, 0x2204, 0xa086, - 0x003c, 0x0040, 0x33dd, 0x2019, 0x0008, 0x7b2a, 0x7b2e, 0x007c, - 0x2019, 0x0030, 0x2011, 0x3546, 0x2204, 0xa086, 0x0032, 0x0040, - 0x33f2, 0x2019, 0x0039, 0x2204, 0xa086, 0x003c, 0x0040, 0x33f2, - 0x2019, 0x0027, 0x7b36, 0x7b3a, 0x007c, 0x2019, 0x000d, 0x2011, - 0x3546, 0x2204, 0xa086, 0x003c, 0x0040, 0x3400, 0x2019, 0x000a, - 0x7b3e, 0x7b42, 0x007c, 0x2019, 0x2faf, 0x2011, 0x3546, 0x2204, - 0xa086, 0x0032, 0x0040, 0x3415, 0x2019, 0x3971, 0x2204, 0xa086, - 0x003c, 0x0040, 0x3415, 0x2019, 0x2626, 0x7b22, 0x7b26, 0x007c, - 0x92a7 -}; -unsigned short __devinitdata sbus_risc_code_length01 = 0x2419; diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index cbcd3f681b6..166417a6afb 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -169,12 +169,10 @@ scsi_pool_alloc_command(struct scsi_host_cmd_pool *pool, gfp_t gfp_mask) { struct scsi_cmnd *cmd; - cmd = kmem_cache_alloc(pool->cmd_slab, gfp_mask | pool->gfp_mask); + cmd = kmem_cache_zalloc(pool->cmd_slab, gfp_mask | pool->gfp_mask); if (!cmd) return NULL; - memset(cmd, 0, sizeof(*cmd)); - cmd->sense_buffer = kmem_cache_alloc(pool->sense_slab, gfp_mask | pool->gfp_mask); if (!cmd->sense_buffer) { @@ -967,6 +965,110 @@ int scsi_track_queue_full(struct scsi_device *sdev, int depth) EXPORT_SYMBOL(scsi_track_queue_full); /** + * scsi_vpd_inquiry - Request a device provide us with a VPD page + * @sdev: The device to ask + * @buffer: Where to put the result + * @page: Which Vital Product Data to return + * @len: The length of the buffer + * + * This is an internal helper function. You probably want to use + * scsi_get_vpd_page instead. + * + * Returns 0 on success or a negative error number. + */ +static int scsi_vpd_inquiry(struct scsi_device *sdev, unsigned char *buffer, + u8 page, unsigned len) +{ + int result; + unsigned char cmd[16]; + + cmd[0] = INQUIRY; + cmd[1] = 1; /* EVPD */ + cmd[2] = page; + cmd[3] = len >> 8; + cmd[4] = len & 0xff; + cmd[5] = 0; /* Control byte */ + + /* + * I'm not convinced we need to try quite this hard to get VPD, but + * all the existing users tried this hard. + */ + result = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buffer, + len + 4, NULL, 30 * HZ, 3, NULL); + if (result) + return result; + + /* Sanity check that we got the page back that we asked for */ + if (buffer[1] != page) + return -EIO; + + return 0; +} + +/** + * scsi_get_vpd_page - Get Vital Product Data from a SCSI device + * @sdev: The device to ask + * @page: Which Vital Product Data to return + * + * SCSI devices may optionally supply Vital Product Data. Each 'page' + * of VPD is defined in the appropriate SCSI document (eg SPC, SBC). + * If the device supports this VPD page, this routine returns a pointer + * to a buffer containing the data from that page. The caller is + * responsible for calling kfree() on this pointer when it is no longer + * needed. If we cannot retrieve the VPD page this routine returns %NULL. + */ +unsigned char *scsi_get_vpd_page(struct scsi_device *sdev, u8 page) +{ + int i, result; + unsigned int len; + unsigned char *buf = kmalloc(259, GFP_KERNEL); + + if (!buf) + return NULL; + + /* Ask for all the pages supported by this device */ + result = scsi_vpd_inquiry(sdev, buf, 0, 255); + if (result) + goto fail; + + /* If the user actually wanted this page, we can skip the rest */ + if (page == 0) + return buf; + + for (i = 0; i < buf[3]; i++) + if (buf[i + 4] == page) + goto found; + /* The device claims it doesn't support the requested page */ + goto fail; + + found: + result = scsi_vpd_inquiry(sdev, buf, page, 255); + if (result) + goto fail; + + /* + * Some pages are longer than 255 bytes. The actual length of + * the page is returned in the header. + */ + len = (buf[2] << 8) | buf[3]; + if (len <= 255) + return buf; + + kfree(buf); + buf = kmalloc(len + 4, GFP_KERNEL); + result = scsi_vpd_inquiry(sdev, buf, page, len); + if (result) + goto fail; + + return buf; + + fail: + kfree(buf); + return NULL; +} +EXPORT_SYMBOL_GPL(scsi_get_vpd_page); + +/** * scsi_device_get - get an additional reference to a scsi_device * @sdev: device to get a reference to * diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 6eebd0bbe8a..213123b0486 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -40,6 +40,9 @@ #include <linux/moduleparam.h> #include <linux/scatterlist.h> #include <linux/blkdev.h> +#include <linux/crc-t10dif.h> + +#include <net/checksum.h> #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> @@ -48,8 +51,7 @@ #include <scsi/scsicam.h> #include <scsi/scsi_eh.h> -#include <linux/stat.h> - +#include "sd.h" #include "scsi_logging.h" #define SCSI_DEBUG_VERSION "1.81" @@ -95,6 +97,10 @@ static const char * scsi_debug_version_date = "20070104"; #define DEF_FAKE_RW 0 #define DEF_VPD_USE_HOSTNO 1 #define DEF_SECTOR_SIZE 512 +#define DEF_DIX 0 +#define DEF_DIF 0 +#define DEF_GUARD 0 +#define DEF_ATO 1 /* bit mask values for scsi_debug_opts */ #define SCSI_DEBUG_OPT_NOISE 1 @@ -102,6 +108,8 @@ static const char * scsi_debug_version_date = "20070104"; #define SCSI_DEBUG_OPT_TIMEOUT 4 #define SCSI_DEBUG_OPT_RECOVERED_ERR 8 #define SCSI_DEBUG_OPT_TRANSPORT_ERR 16 +#define SCSI_DEBUG_OPT_DIF_ERR 32 +#define SCSI_DEBUG_OPT_DIX_ERR 64 /* When "every_nth" > 0 then modulo "every_nth" commands: * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set * - a RECOVERED_ERROR is simulated on successful read and write @@ -144,6 +152,10 @@ static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB; static int scsi_debug_fake_rw = DEF_FAKE_RW; static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO; static int scsi_debug_sector_size = DEF_SECTOR_SIZE; +static int scsi_debug_dix = DEF_DIX; +static int scsi_debug_dif = DEF_DIF; +static int scsi_debug_guard = DEF_GUARD; +static int scsi_debug_ato = DEF_ATO; static int scsi_debug_cmnd_count = 0; @@ -204,11 +216,15 @@ struct sdebug_queued_cmd { static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE]; static unsigned char * fake_storep; /* ramdisk storage */ +static unsigned char *dif_storep; /* protection info */ static int num_aborts = 0; static int num_dev_resets = 0; static int num_bus_resets = 0; static int num_host_resets = 0; +static int dix_writes; +static int dix_reads; +static int dif_errors; static DEFINE_SPINLOCK(queued_arr_lock); static DEFINE_RWLOCK(atomic_rw); @@ -217,6 +233,11 @@ static char sdebug_proc_name[] = "scsi_debug"; static struct bus_type pseudo_lld_bus; +static inline sector_t dif_offset(sector_t sector) +{ + return sector << 3; +} + static struct device_driver sdebug_driverfs_driver = { .name = sdebug_proc_name, .bus = &pseudo_lld_bus, @@ -225,6 +246,9 @@ static struct device_driver sdebug_driverfs_driver = { static const int check_condition_result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; +static const int illegal_condition_result = + (DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION; + static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 0, 0, 0x2, 0x4b}; static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, @@ -726,7 +750,12 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target, } else if (0x86 == cmd[2]) { /* extended inquiry */ arr[1] = cmd[2]; /*sanity */ arr[3] = 0x3c; /* number of following entries */ - arr[4] = 0x0; /* no protection stuff */ + if (scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) + arr[4] = 0x4; /* SPT: GRD_CHK:1 */ + else if (scsi_debug_dif) + arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */ + else + arr[4] = 0x0; /* no protection stuff */ arr[5] = 0x7; /* head of q, ordered + simple q's */ } else if (0x87 == cmd[2]) { /* mode page policy */ arr[1] = cmd[2]; /*sanity */ @@ -767,6 +796,7 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target, arr[2] = scsi_debug_scsi_level; arr[3] = 2; /* response_data_format==2 */ arr[4] = SDEBUG_LONG_INQ_SZ - 5; + arr[5] = scsi_debug_dif ? 1 : 0; /* PROTECT bit */ if (0 == scsi_debug_vpd_use_hostno) arr[5] = 0x10; /* claim: implicit TGPS */ arr[6] = 0x10; /* claim: MultiP */ @@ -915,6 +945,12 @@ static int resp_readcap16(struct scsi_cmnd * scp, arr[9] = (scsi_debug_sector_size >> 16) & 0xff; arr[10] = (scsi_debug_sector_size >> 8) & 0xff; arr[11] = scsi_debug_sector_size & 0xff; + + if (scsi_debug_dif) { + arr[12] = (scsi_debug_dif - 1) << 1; /* P_TYPE */ + arr[12] |= 1; /* PROT_EN */ + } + return fill_from_dev_buffer(scp, arr, min(alloc_len, SDEBUG_READCAP16_ARR_SZ)); } @@ -1066,6 +1102,10 @@ static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target) ctrl_m_pg[2] |= 0x4; else ctrl_m_pg[2] &= ~0x4; + + if (scsi_debug_ato) + ctrl_m_pg[5] |= 0x80; /* ATO=1 */ + memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg)); if (1 == pcontrol) memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg)); @@ -1536,6 +1576,87 @@ static int do_device_access(struct scsi_cmnd *scmd, return ret; } +static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec, + unsigned int sectors) +{ + unsigned int i, resid; + struct scatterlist *psgl; + struct sd_dif_tuple *sdt; + sector_t sector; + sector_t tmp_sec = start_sec; + void *paddr; + + start_sec = do_div(tmp_sec, sdebug_store_sectors); + + sdt = (struct sd_dif_tuple *)(dif_storep + dif_offset(start_sec)); + + for (i = 0 ; i < sectors ; i++) { + u16 csum; + + if (sdt[i].app_tag == 0xffff) + continue; + + sector = start_sec + i; + + switch (scsi_debug_guard) { + case 1: + csum = ip_compute_csum(fake_storep + + sector * scsi_debug_sector_size, + scsi_debug_sector_size); + break; + case 0: + csum = crc_t10dif(fake_storep + + sector * scsi_debug_sector_size, + scsi_debug_sector_size); + csum = cpu_to_be16(csum); + break; + default: + BUG(); + } + + if (sdt[i].guard_tag != csum) { + printk(KERN_ERR "%s: GUARD check failed on sector %lu" \ + " rcvd 0x%04x, data 0x%04x\n", __func__, + (unsigned long)sector, + be16_to_cpu(sdt[i].guard_tag), + be16_to_cpu(csum)); + dif_errors++; + return 0x01; + } + + if (scsi_debug_dif != SD_DIF_TYPE3_PROTECTION && + be32_to_cpu(sdt[i].ref_tag) != (sector & 0xffffffff)) { + printk(KERN_ERR "%s: REF check failed on sector %lu\n", + __func__, (unsigned long)sector); + dif_errors++; + return 0x03; + } + } + + resid = sectors * 8; /* Bytes of protection data to copy into sgl */ + sector = start_sec; + + scsi_for_each_prot_sg(SCpnt, psgl, scsi_prot_sg_count(SCpnt), i) { + int len = min(psgl->length, resid); + + paddr = kmap_atomic(sg_page(psgl), KM_IRQ0) + psgl->offset; + memcpy(paddr, dif_storep + dif_offset(sector), len); + + sector += len >> 3; + if (sector >= sdebug_store_sectors) { + /* Force wrap */ + tmp_sec = sector; + sector = do_div(tmp_sec, sdebug_store_sectors); + } + resid -= len; + kunmap_atomic(paddr, KM_IRQ0); + } + + dix_reads++; + + return 0; +} + static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba, unsigned int num, struct sdebug_dev_info *devip) { @@ -1563,12 +1684,162 @@ static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba, } return check_condition_result; } + + /* DIX + T10 DIF */ + if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) { + int prot_ret = prot_verify_read(SCpnt, lba, num); + + if (prot_ret) { + mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, prot_ret); + return illegal_condition_result; + } + } + read_lock_irqsave(&atomic_rw, iflags); ret = do_device_access(SCpnt, devip, lba, num, 0); read_unlock_irqrestore(&atomic_rw, iflags); return ret; } +void dump_sector(unsigned char *buf, int len) +{ + int i, j; + + printk(KERN_ERR ">>> Sector Dump <<<\n"); + + for (i = 0 ; i < len ; i += 16) { + printk(KERN_ERR "%04d: ", i); + + for (j = 0 ; j < 16 ; j++) { + unsigned char c = buf[i+j]; + if (c >= 0x20 && c < 0x7e) + printk(" %c ", buf[i+j]); + else + printk("%02x ", buf[i+j]); + } + + printk("\n"); + } +} + +static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec, + unsigned int sectors) +{ + int i, j, ret; + struct sd_dif_tuple *sdt; + struct scatterlist *dsgl = scsi_sglist(SCpnt); + struct scatterlist *psgl = scsi_prot_sglist(SCpnt); + void *daddr, *paddr; + sector_t tmp_sec = start_sec; + sector_t sector; + int ppage_offset; + unsigned short csum; + + sector = do_div(tmp_sec, sdebug_store_sectors); + + if (((SCpnt->cmnd[1] >> 5) & 7) != 1) { + printk(KERN_WARNING "scsi_debug: WRPROTECT != 1\n"); + return 0; + } + + BUG_ON(scsi_sg_count(SCpnt) == 0); + BUG_ON(scsi_prot_sg_count(SCpnt) == 0); + + paddr = kmap_atomic(sg_page(psgl), KM_IRQ1) + psgl->offset; + ppage_offset = 0; + + /* For each data page */ + scsi_for_each_sg(SCpnt, dsgl, scsi_sg_count(SCpnt), i) { + daddr = kmap_atomic(sg_page(dsgl), KM_IRQ0) + dsgl->offset; + + /* For each sector-sized chunk in data page */ + for (j = 0 ; j < dsgl->length ; j += scsi_debug_sector_size) { + + /* If we're at the end of the current + * protection page advance to the next one + */ + if (ppage_offset >= psgl->length) { + kunmap_atomic(paddr, KM_IRQ1); + psgl = sg_next(psgl); + BUG_ON(psgl == NULL); + paddr = kmap_atomic(sg_page(psgl), KM_IRQ1) + + psgl->offset; + ppage_offset = 0; + } + + sdt = paddr + ppage_offset; + + switch (scsi_debug_guard) { + case 1: + csum = ip_compute_csum(daddr, + scsi_debug_sector_size); + break; + case 0: + csum = cpu_to_be16(crc_t10dif(daddr, + scsi_debug_sector_size)); + break; + default: + BUG(); + ret = 0; + goto out; + } + + if (sdt->guard_tag != csum) { + printk(KERN_ERR + "%s: GUARD check failed on sector %lu " \ + "rcvd 0x%04x, calculated 0x%04x\n", + __func__, (unsigned long)sector, + be16_to_cpu(sdt->guard_tag), + be16_to_cpu(csum)); + ret = 0x01; + dump_sector(daddr, scsi_debug_sector_size); + goto out; + } + + if (scsi_debug_dif != SD_DIF_TYPE3_PROTECTION && + be32_to_cpu(sdt->ref_tag) + != (start_sec & 0xffffffff)) { + printk(KERN_ERR + "%s: REF check failed on sector %lu\n", + __func__, (unsigned long)sector); + ret = 0x03; + dump_sector(daddr, scsi_debug_sector_size); + goto out; + } + + /* Would be great to copy this in bigger + * chunks. However, for the sake of + * correctness we need to verify each sector + * before writing it to "stable" storage + */ + memcpy(dif_storep + dif_offset(sector), sdt, 8); + + sector++; + + if (sector == sdebug_store_sectors) + sector = 0; /* Force wrap */ + + start_sec++; + daddr += scsi_debug_sector_size; + ppage_offset += sizeof(struct sd_dif_tuple); + } + + kunmap_atomic(daddr, KM_IRQ0); + } + + kunmap_atomic(paddr, KM_IRQ1); + + dix_writes++; + + return 0; + +out: + dif_errors++; + kunmap_atomic(daddr, KM_IRQ0); + kunmap_atomic(paddr, KM_IRQ1); + return ret; +} + static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba, unsigned int num, struct sdebug_dev_info *devip) { @@ -1579,6 +1850,16 @@ static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba, if (ret) return ret; + /* DIX + T10 DIF */ + if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) { + int prot_ret = prot_verify_write(SCpnt, lba, num); + + if (prot_ret) { + mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, prot_ret); + return illegal_condition_result; + } + } + write_lock_irqsave(&atomic_rw, iflags); ret = do_device_access(SCpnt, devip, lba, num, 1); write_unlock_irqrestore(&atomic_rw, iflags); @@ -2095,6 +2376,10 @@ module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR); module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int, S_IRUGO | S_IWUSR); module_param_named(sector_size, scsi_debug_sector_size, int, S_IRUGO); +module_param_named(dix, scsi_debug_dix, int, S_IRUGO); +module_param_named(dif, scsi_debug_dif, int, S_IRUGO); +module_param_named(guard, scsi_debug_guard, int, S_IRUGO); +module_param_named(ato, scsi_debug_ato, int, S_IRUGO); MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); MODULE_DESCRIPTION("SCSI debug adapter driver"); @@ -2117,7 +2402,10 @@ MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])"); MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)"); MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)"); MODULE_PARM_DESC(sector_size, "hardware sector size in bytes (def=512)"); - +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)"); static char sdebug_info[256]; @@ -2164,14 +2452,14 @@ static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **sta "delay=%d, max_luns=%d, scsi_level=%d\n" "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n" "number of aborts=%d, device_reset=%d, bus_resets=%d, " - "host_resets=%d\n", + "host_resets=%d\ndix_reads=%d dix_writes=%d dif_errors=%d\n", SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts, scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth, scsi_debug_cmnd_count, scsi_debug_delay, scsi_debug_max_luns, scsi_debug_scsi_level, scsi_debug_sector_size, sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per, num_aborts, num_dev_resets, num_bus_resets, - num_host_resets); + num_host_resets, dix_reads, dix_writes, dif_errors); if (pos < offset) { len = 0; begin = pos; @@ -2452,6 +2740,31 @@ static ssize_t sdebug_sector_size_show(struct device_driver * ddp, char * buf) } DRIVER_ATTR(sector_size, S_IRUGO, sdebug_sector_size_show, NULL); +static ssize_t sdebug_dix_show(struct device_driver *ddp, char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dix); +} +DRIVER_ATTR(dix, S_IRUGO, sdebug_dix_show, NULL); + +static ssize_t sdebug_dif_show(struct device_driver *ddp, char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dif); +} +DRIVER_ATTR(dif, S_IRUGO, sdebug_dif_show, NULL); + +static ssize_t sdebug_guard_show(struct device_driver *ddp, char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_guard); +} +DRIVER_ATTR(guard, S_IRUGO, sdebug_guard_show, NULL); + +static ssize_t sdebug_ato_show(struct device_driver *ddp, char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ato); +} +DRIVER_ATTR(ato, S_IRUGO, sdebug_ato_show, NULL); + + /* Note: The following function creates attribute files in the /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these files (over those found in the /sys/module/scsi_debug/parameters @@ -2478,11 +2791,19 @@ static int do_create_driverfs_files(void) ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb); ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno); ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_sector_size); + ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dix); + ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dif); + ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_guard); + ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ato); return ret; } static void do_remove_driverfs_files(void) { + driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ato); + driver_remove_file(&sdebug_driverfs_driver, &driver_attr_guard); + driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dif); + driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dix); driver_remove_file(&sdebug_driverfs_driver, &driver_attr_sector_size); driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno); driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb); @@ -2526,11 +2847,33 @@ static int __init scsi_debug_init(void) case 4096: break; default: - printk(KERN_ERR "scsi_debug_init: invalid sector_size %u\n", + printk(KERN_ERR "scsi_debug_init: invalid sector_size %d\n", scsi_debug_sector_size); return -EINVAL; } + switch (scsi_debug_dif) { + + case SD_DIF_TYPE0_PROTECTION: + case SD_DIF_TYPE1_PROTECTION: + case SD_DIF_TYPE3_PROTECTION: + break; + + default: + printk(KERN_ERR "scsi_debug_init: dif must be 0, 1 or 3\n"); + return -EINVAL; + } + + if (scsi_debug_guard > 1) { + printk(KERN_ERR "scsi_debug_init: guard must be 0 or 1\n"); + return -EINVAL; + } + + if (scsi_debug_ato > 1) { + printk(KERN_ERR "scsi_debug_init: ato must be 0 or 1\n"); + return -EINVAL; + } + if (scsi_debug_dev_size_mb < 1) scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */ sz = (unsigned long)scsi_debug_dev_size_mb * 1048576; @@ -2563,6 +2906,24 @@ static int __init scsi_debug_init(void) if (scsi_debug_num_parts > 0) sdebug_build_parts(fake_storep, sz); + if (scsi_debug_dif) { + int dif_size; + + dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple); + dif_storep = vmalloc(dif_size); + + printk(KERN_ERR "scsi_debug_init: dif_storep %u bytes @ %p\n", + dif_size, dif_storep); + + if (dif_storep == NULL) { + printk(KERN_ERR "scsi_debug_init: out of mem. (DIX)\n"); + ret = -ENOMEM; + goto free_vm; + } + + memset(dif_storep, 0xff, dif_size); + } + ret = device_register(&pseudo_primary); if (ret < 0) { printk(KERN_WARNING "scsi_debug: device_register error: %d\n", @@ -2615,6 +2976,8 @@ bus_unreg: dev_unreg: device_unregister(&pseudo_primary); free_vm: + if (dif_storep) + vfree(dif_storep); vfree(fake_storep); return ret; @@ -2632,6 +2995,9 @@ static void __exit scsi_debug_exit(void) bus_unregister(&pseudo_lld_bus); device_unregister(&pseudo_primary); + if (dif_storep) + vfree(dif_storep); + vfree(fake_storep); } @@ -2732,6 +3098,8 @@ int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done) struct sdebug_dev_info *devip = NULL; int inj_recovered = 0; int inj_transport = 0; + int inj_dif = 0; + int inj_dix = 0; int delay_override = 0; scsi_set_resid(SCpnt, 0); @@ -2769,6 +3137,10 @@ int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done) inj_recovered = 1; /* to reads and writes below */ else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts) inj_transport = 1; /* to reads and writes below */ + else if (SCSI_DEBUG_OPT_DIF_ERR & scsi_debug_opts) + inj_dif = 1; /* to reads and writes below */ + else if (SCSI_DEBUG_OPT_DIX_ERR & scsi_debug_opts) + inj_dix = 1; /* to reads and writes below */ } if (devip->wlun) { @@ -2870,6 +3242,12 @@ int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done) mk_sense_buffer(devip, ABORTED_COMMAND, TRANSPORT_PROBLEM, ACK_NAK_TO); errsts = check_condition_result; + } else if (inj_dif && (0 == errsts)) { + mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, 1); + errsts = illegal_condition_result; + } else if (inj_dix && (0 == errsts)) { + mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, 1); + errsts = illegal_condition_result; } break; case REPORT_LUNS: /* mandatory, ignore unit attention */ @@ -2894,6 +3272,12 @@ int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done) mk_sense_buffer(devip, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0); errsts = check_condition_result; + } else if (inj_dif && (0 == errsts)) { + mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, 1); + errsts = illegal_condition_result; + } else if (inj_dix && (0 == errsts)) { + mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, 1); + errsts = illegal_condition_result; } break; case MODE_SENSE: @@ -2982,6 +3366,7 @@ static int sdebug_driver_probe(struct device * dev) int error = 0; struct sdebug_host_info *sdbg_host; struct Scsi_Host *hpnt; + int host_prot; sdbg_host = to_sdebug_host(dev); @@ -3000,6 +3385,50 @@ static int sdebug_driver_probe(struct device * dev) hpnt->max_id = scsi_debug_num_tgts; hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */ + host_prot = 0; + + switch (scsi_debug_dif) { + + case SD_DIF_TYPE1_PROTECTION: + host_prot = SHOST_DIF_TYPE1_PROTECTION; + if (scsi_debug_dix) + host_prot |= SHOST_DIX_TYPE1_PROTECTION; + break; + + case SD_DIF_TYPE2_PROTECTION: + host_prot = SHOST_DIF_TYPE2_PROTECTION; + if (scsi_debug_dix) + host_prot |= SHOST_DIX_TYPE2_PROTECTION; + break; + + case SD_DIF_TYPE3_PROTECTION: + host_prot = SHOST_DIF_TYPE3_PROTECTION; + if (scsi_debug_dix) + host_prot |= SHOST_DIX_TYPE3_PROTECTION; + break; + + default: + if (scsi_debug_dix) + host_prot |= SHOST_DIX_TYPE0_PROTECTION; + break; + } + + scsi_host_set_prot(hpnt, host_prot); + + printk(KERN_INFO "scsi_debug: host protection%s%s%s%s%s%s%s\n", + (host_prot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "", + (host_prot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "", + (host_prot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "", + (host_prot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "", + (host_prot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "", + (host_prot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "", + (host_prot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : ""); + + if (scsi_debug_guard == 1) + scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP); + else + scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC); + error = scsi_add_host(hpnt, &sdbg_host->dev); if (error) { printk(KERN_ERR "%s: scsi_add_host failed\n", __func__); diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index 099b5455bbc..b1348136964 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -596,8 +596,6 @@ int __init scsi_init_devinfo(void) error = -ENOMEM; goto out; } - - p->owner = THIS_MODULE; #endif /* CONFIG_SCSI_PROC_FS */ out: diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index ad6a1370761..0c2c73be197 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -1441,6 +1441,11 @@ int scsi_decide_disposition(struct scsi_cmnd *scmd) } } +static void eh_lock_door_done(struct request *req, int uptodate) +{ + __blk_put_request(req->q, req); +} + /** * scsi_eh_lock_door - Prevent medium removal for the specified device * @sdev: SCSI device to prevent medium removal @@ -1463,19 +1468,28 @@ int scsi_decide_disposition(struct scsi_cmnd *scmd) */ static void scsi_eh_lock_door(struct scsi_device *sdev) { - unsigned char cmnd[MAX_COMMAND_SIZE]; + struct request *req; - cmnd[0] = ALLOW_MEDIUM_REMOVAL; - cmnd[1] = 0; - cmnd[2] = 0; - cmnd[3] = 0; - cmnd[4] = SCSI_REMOVAL_PREVENT; - cmnd[5] = 0; + req = blk_get_request(sdev->request_queue, READ, GFP_KERNEL); + if (!req) + return; - scsi_execute_async(sdev, cmnd, 6, DMA_NONE, NULL, 0, 0, 10 * HZ, - 5, NULL, NULL, GFP_KERNEL); -} + req->cmd[0] = ALLOW_MEDIUM_REMOVAL; + req->cmd[1] = 0; + req->cmd[2] = 0; + req->cmd[3] = 0; + req->cmd[4] = SCSI_REMOVAL_PREVENT; + req->cmd[5] = 0; + req->cmd_len = COMMAND_SIZE(req->cmd[0]); + + req->cmd_type = REQ_TYPE_BLOCK_PC; + req->cmd_flags |= REQ_QUIET; + req->timeout = 10 * HZ; + req->retries = 5; + + blk_execute_rq_nowait(req->q, NULL, req, 1, eh_lock_door_done); +} /** * scsi_restart_operations - restart io operations to the specified host. diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 940dc32ff0d..d1cb64ad1a3 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -277,196 +277,6 @@ int scsi_execute_req(struct scsi_device *sdev, const unsigned char *cmd, } EXPORT_SYMBOL(scsi_execute_req); -struct scsi_io_context { - void *data; - void (*done)(void *data, char *sense, int result, int resid); - char sense[SCSI_SENSE_BUFFERSIZE]; -}; - -static struct kmem_cache *scsi_io_context_cache; - -static void scsi_end_async(struct request *req, int uptodate) -{ - struct scsi_io_context *sioc = req->end_io_data; - - if (sioc->done) - sioc->done(sioc->data, sioc->sense, req->errors, req->data_len); - - kmem_cache_free(scsi_io_context_cache, sioc); - __blk_put_request(req->q, req); -} - -static int scsi_merge_bio(struct request *rq, struct bio *bio) -{ - struct request_queue *q = rq->q; - - bio->bi_flags &= ~(1 << BIO_SEG_VALID); - if (rq_data_dir(rq) == WRITE) - bio->bi_rw |= (1 << BIO_RW); - blk_queue_bounce(q, &bio); - - return blk_rq_append_bio(q, rq, bio); -} - -static void scsi_bi_endio(struct bio *bio, int error) -{ - bio_put(bio); -} - -/** - * scsi_req_map_sg - map a scatterlist into a request - * @rq: request to fill - * @sgl: scatterlist - * @nsegs: number of elements - * @bufflen: len of buffer - * @gfp: memory allocation flags - * - * scsi_req_map_sg maps a scatterlist into a request so that the - * request can be sent to the block layer. We do not trust the scatterlist - * sent to use, as some ULDs use that struct to only organize the pages. - */ -static int scsi_req_map_sg(struct request *rq, struct scatterlist *sgl, - int nsegs, unsigned bufflen, gfp_t gfp) -{ - struct request_queue *q = rq->q; - int nr_pages = (bufflen + sgl[0].offset + PAGE_SIZE - 1) >> PAGE_SHIFT; - unsigned int data_len = bufflen, len, bytes, off; - struct scatterlist *sg; - struct page *page; - struct bio *bio = NULL; - int i, err, nr_vecs = 0; - - for_each_sg(sgl, sg, nsegs, i) { - page = sg_page(sg); - off = sg->offset; - len = sg->length; - - while (len > 0 && data_len > 0) { - /* - * sg sends a scatterlist that is larger than - * the data_len it wants transferred for certain - * IO sizes - */ - bytes = min_t(unsigned int, len, PAGE_SIZE - off); - bytes = min(bytes, data_len); - - if (!bio) { - nr_vecs = min_t(int, BIO_MAX_PAGES, nr_pages); - nr_pages -= nr_vecs; - - bio = bio_alloc(gfp, nr_vecs); - if (!bio) { - err = -ENOMEM; - goto free_bios; - } - bio->bi_end_io = scsi_bi_endio; - } - - if (bio_add_pc_page(q, bio, page, bytes, off) != - bytes) { - bio_put(bio); - err = -EINVAL; - goto free_bios; - } - - if (bio->bi_vcnt >= nr_vecs) { - err = scsi_merge_bio(rq, bio); - if (err) { - bio_endio(bio, 0); - goto free_bios; - } - bio = NULL; - } - - page++; - len -= bytes; - data_len -=bytes; - off = 0; - } - } - - rq->buffer = rq->data = NULL; - rq->data_len = bufflen; - return 0; - -free_bios: - while ((bio = rq->bio) != NULL) { - rq->bio = bio->bi_next; - /* - * call endio instead of bio_put incase it was bounced - */ - bio_endio(bio, 0); - } - - return err; -} - -/** - * scsi_execute_async - insert request - * @sdev: scsi device - * @cmd: scsi command - * @cmd_len: length of scsi cdb - * @data_direction: DMA_TO_DEVICE, DMA_FROM_DEVICE, or DMA_NONE - * @buffer: data buffer (this can be a kernel buffer or scatterlist) - * @bufflen: len of buffer - * @use_sg: if buffer is a scatterlist this is the number of elements - * @timeout: request timeout in seconds - * @retries: number of times to retry request - * @privdata: data passed to done() - * @done: callback function when done - * @gfp: memory allocation flags - */ -int scsi_execute_async(struct scsi_device *sdev, const unsigned char *cmd, - int cmd_len, int data_direction, void *buffer, unsigned bufflen, - int use_sg, int timeout, int retries, void *privdata, - void (*done)(void *, char *, int, int), gfp_t gfp) -{ - struct request *req; - struct scsi_io_context *sioc; - int err = 0; - int write = (data_direction == DMA_TO_DEVICE); - - sioc = kmem_cache_zalloc(scsi_io_context_cache, gfp); - if (!sioc) - return DRIVER_ERROR << 24; - - req = blk_get_request(sdev->request_queue, write, gfp); - if (!req) - goto free_sense; - req->cmd_type = REQ_TYPE_BLOCK_PC; - req->cmd_flags |= REQ_QUIET; - - if (use_sg) - err = scsi_req_map_sg(req, buffer, use_sg, bufflen, gfp); - else if (bufflen) - err = blk_rq_map_kern(req->q, req, buffer, bufflen, gfp); - - if (err) - goto free_req; - - req->cmd_len = cmd_len; - memset(req->cmd, 0, BLK_MAX_CDB); /* ATAPI hates garbage after CDB */ - memcpy(req->cmd, cmd, req->cmd_len); - req->sense = sioc->sense; - req->sense_len = 0; - req->timeout = timeout; - req->retries = retries; - req->end_io_data = sioc; - - sioc->data = privdata; - sioc->done = done; - - blk_execute_rq_nowait(req->q, NULL, req, 1, scsi_end_async); - return 0; - -free_req: - blk_put_request(req); -free_sense: - kmem_cache_free(scsi_io_context_cache, sioc); - return DRIVER_ERROR << 24; -} -EXPORT_SYMBOL_GPL(scsi_execute_async); - /* * Function: scsi_init_cmd_errh() * @@ -981,7 +791,22 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) "%d bytes done.\n", req->nr_sectors, good_bytes)); - /* A number of bytes were successfully read. If there + /* + * Recovered errors need reporting, but they're always treated + * as success, so fiddle the result code here. For BLOCK_PC + * we already took a copy of the original into rq->errors which + * is what gets returned to the user + */ + if (sense_valid && sshdr.sense_key == RECOVERED_ERROR) { + if (!(req->cmd_flags & REQ_QUIET)) + scsi_print_sense("", cmd); + result = 0; + /* BLOCK_PC may have set error */ + error = 0; + } + + /* + * A number of bytes were successfully read. If there * are leftovers and there is some kind of error * (result != 0), retry the rest. */ @@ -1040,12 +865,11 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) action = ACTION_FAIL; break; case ABORTED_COMMAND: + action = ACTION_FAIL; if (sshdr.asc == 0x10) { /* DIF */ description = "Target Data Integrity Failure"; - action = ACTION_FAIL; error = -EILSEQ; - } else - action = ACTION_RETRY; + } break; case NOT_READY: /* If the device is in the process of becoming @@ -1921,20 +1745,12 @@ int __init scsi_init_queue(void) { int i; - scsi_io_context_cache = kmem_cache_create("scsi_io_context", - sizeof(struct scsi_io_context), - 0, 0, NULL); - if (!scsi_io_context_cache) { - printk(KERN_ERR "SCSI: can't init scsi io context cache\n"); - return -ENOMEM; - } - scsi_sdb_cache = kmem_cache_create("scsi_data_buffer", sizeof(struct scsi_data_buffer), 0, 0, NULL); if (!scsi_sdb_cache) { printk(KERN_ERR "SCSI: can't init scsi sdb cache\n"); - goto cleanup_io_context; + return -ENOMEM; } for (i = 0; i < SG_MEMPOOL_NR; i++) { @@ -1969,8 +1785,6 @@ cleanup_sdb: kmem_cache_destroy(sgp->slab); } kmem_cache_destroy(scsi_sdb_cache); -cleanup_io_context: - kmem_cache_destroy(scsi_io_context_cache); return -ENOMEM; } @@ -1979,7 +1793,6 @@ void scsi_exit_queue(void) { int i; - kmem_cache_destroy(scsi_io_context_cache); kmem_cache_destroy(scsi_sdb_cache); for (i = 0; i < SG_MEMPOOL_NR; i++) { diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c index 82f7b2dd08a..77fbddb507f 100644 --- a/drivers/scsi/scsi_proc.c +++ b/drivers/scsi/scsi_proc.c @@ -115,8 +115,6 @@ void scsi_proc_hostdir_add(struct scsi_host_template *sht) if (!sht->proc_dir) printk(KERN_ERR "%s: proc_mkdir failed for %s\n", __func__, sht->proc_name); - else - sht->proc_dir->owner = sht->module; } mutex_unlock(&global_host_template_mutex); } @@ -163,7 +161,6 @@ void scsi_proc_host_add(struct Scsi_Host *shost) } p->write_proc = proc_scsi_write_proc; - p->owner = sht->module; } /** diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 66505bb7941..a14d245a66b 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -317,6 +317,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget, return sdev; out_device_destroy: + scsi_device_set_state(sdev, SDEV_DEL); transport_destroy_device(&sdev->sdev_gendev); put_device(&sdev->sdev_gendev); out: @@ -796,6 +797,7 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result, case TYPE_ENCLOSURE: case TYPE_COMM: case TYPE_RAID: + case TYPE_OSD: sdev->writeable = 1; break; case TYPE_ROM: diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index da63802cbf9..fa4711d1274 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -1043,7 +1043,6 @@ EXPORT_SYMBOL(scsi_register_interface); /** * scsi_sysfs_add_host - add scsi host to subsystem * @shost: scsi host struct to add to subsystem - * @dev: parent struct device pointer **/ int scsi_sysfs_add_host(struct Scsi_Host *shost) { diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 5f77417ed58..a152f89ae51 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -95,7 +95,7 @@ static struct { { FC_PORTTYPE_NPORT, "NPort (fabric via point-to-point)" }, { FC_PORTTYPE_NLPORT, "NLPort (fabric via loop)" }, { FC_PORTTYPE_LPORT, "LPort (private loop)" }, - { FC_PORTTYPE_PTP, "Point-To-Point (direct nport connection" }, + { FC_PORTTYPE_PTP, "Point-To-Point (direct nport connection)" }, { FC_PORTTYPE_NPIV, "NPIV VPORT" }, }; fc_enum_name_search(port_type, fc_port_type, fc_port_type_names) @@ -533,12 +533,8 @@ fc_host_post_event(struct Scsi_Host *shost, u32 event_number, event->event_code = event_code; event->event_data = event_data; - err = nlmsg_multicast(scsi_nl_sock, skb, 0, SCSI_NL_GRP_FC_EVENTS, - GFP_KERNEL); - if (err && (err != -ESRCH)) /* filter no recipient errors */ - /* nlmsg_multicast already kfree_skb'd */ - goto send_fail; - + nlmsg_multicast(scsi_nl_sock, skb, 0, SCSI_NL_GRP_FC_EVENTS, + GFP_KERNEL); return; send_fail_skb: @@ -607,12 +603,8 @@ fc_host_post_vendor_event(struct Scsi_Host *shost, u32 event_number, event->event_code = FCH_EVT_VENDOR_UNIQUE; memcpy(&event->event_data, data_buf, data_len); - err = nlmsg_multicast(scsi_nl_sock, skb, 0, SCSI_NL_GRP_FC_EVENTS, - GFP_KERNEL); - if (err && (err != -ESRCH)) /* filter no recipient errors */ - /* nlmsg_multicast already kfree_skb'd */ - goto send_vendor_fail; - + nlmsg_multicast(scsi_nl_sock, skb, 0, SCSI_NL_GRP_FC_EVENTS, + GFP_KERNEL); return; send_vendor_fail_skb: diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 75c9297694c..09479545529 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -246,30 +246,13 @@ static int iscsi_setup_host(struct transport_container *tc, struct device *dev, memset(ihost, 0, sizeof(*ihost)); atomic_set(&ihost->nr_scans, 0); mutex_init(&ihost->mutex); - - snprintf(ihost->scan_workq_name, sizeof(ihost->scan_workq_name), - "iscsi_scan_%d", shost->host_no); - ihost->scan_workq = create_singlethread_workqueue( - ihost->scan_workq_name); - if (!ihost->scan_workq) - return -ENOMEM; - return 0; -} - -static int iscsi_remove_host(struct transport_container *tc, struct device *dev, - struct device *cdev) -{ - struct Scsi_Host *shost = dev_to_shost(dev); - struct iscsi_cls_host *ihost = shost->shost_data; - - destroy_workqueue(ihost->scan_workq); return 0; } static DECLARE_TRANSPORT_CLASS(iscsi_host_class, "iscsi_host", iscsi_setup_host, - iscsi_remove_host, + NULL, NULL); static DECLARE_TRANSPORT_CLASS(iscsi_session_class, @@ -568,7 +551,7 @@ static void __iscsi_unblock_session(struct work_struct *work) * scanning from userspace). */ if (shost->hostt->scan_finished) { - if (queue_work(ihost->scan_workq, &session->scan_work)) + if (scsi_queue_work(shost, &session->scan_work)) atomic_inc(&ihost->nr_scans); } } @@ -636,14 +619,6 @@ static void __iscsi_unbind_session(struct work_struct *work) iscsi_session_event(session, ISCSI_KEVENT_UNBIND_SESSION); } -static int iscsi_unbind_session(struct iscsi_cls_session *session) -{ - struct Scsi_Host *shost = iscsi_session_to_shost(session); - struct iscsi_cls_host *ihost = shost->shost_data; - - return queue_work(ihost->scan_workq, &session->unbind_work); -} - struct iscsi_cls_session * iscsi_alloc_session(struct Scsi_Host *shost, struct iscsi_transport *transport, int dd_size) @@ -796,7 +771,6 @@ static int iscsi_iter_destroy_conn_fn(struct device *dev, void *data) void iscsi_remove_session(struct iscsi_cls_session *session) { struct Scsi_Host *shost = iscsi_session_to_shost(session); - struct iscsi_cls_host *ihost = shost->shost_data; unsigned long flags; int err; @@ -821,7 +795,7 @@ void iscsi_remove_session(struct iscsi_cls_session *session) scsi_target_unblock(&session->dev); /* flush running scans then delete devices */ - flush_workqueue(ihost->scan_workq); + scsi_flush_work(shost); __iscsi_unbind_session(&session->unbind_work); /* hw iscsi may not have removed all connections from session */ @@ -966,15 +940,7 @@ iscsi_if_transport_lookup(struct iscsi_transport *tt) static int iscsi_broadcast_skb(struct sk_buff *skb, gfp_t gfp) { - int rc; - - rc = netlink_broadcast(nls, skb, 0, 1, gfp); - if (rc < 0) { - printk(KERN_ERR "iscsi: can not broadcast skb (%d)\n", rc); - return rc; - } - - return 0; + return netlink_broadcast(nls, skb, 0, 1, gfp); } static int @@ -1207,7 +1173,7 @@ int iscsi_session_event(struct iscsi_cls_session *session, * the user and when the daemon is restarted it will handle it */ rc = iscsi_broadcast_skb(skb, GFP_KERNEL); - if (rc < 0) + if (rc == -ESRCH) iscsi_cls_session_printk(KERN_ERR, session, "Cannot notify userspace of session " "event %u. Check iscsi daemon\n", @@ -1223,14 +1189,15 @@ iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_endpoint *ep, { struct iscsi_transport *transport = priv->iscsi_transport; struct iscsi_cls_session *session; - uint32_t host_no; + struct Scsi_Host *shost; session = transport->create_session(ep, cmds_max, queue_depth, - initial_cmdsn, &host_no); + initial_cmdsn); if (!session) return -ENOMEM; - ev->r.c_session_ret.host_no = host_no; + shost = iscsi_session_to_shost(session); + ev->r.c_session_ret.host_no = shost->host_no; ev->r.c_session_ret.sid = session->sid; return 0; } @@ -1447,7 +1414,8 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) case ISCSI_UEVENT_UNBIND_SESSION: session = iscsi_session_lookup(ev->u.d_session.sid); if (session) - iscsi_unbind_session(session); + scsi_queue_work(iscsi_session_to_shost(session), + &session->unbind_work); else err = -EINVAL; break; @@ -1809,8 +1777,7 @@ iscsi_register_transport(struct iscsi_transport *tt) priv->daemon_pid = -1; priv->iscsi_transport = tt; priv->t.user_scan = iscsi_user_scan; - if (!(tt->caps & CAP_DATA_PATH_OFFLOAD)) - priv->t.create_work_queue = 1; + priv->t.create_work_queue = 1; priv->dev.class = &iscsi_transport_class; dev_set_name(&priv->dev, "%s", tt->name); diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index d57566b8be0..3fcb64b91c4 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -107,6 +107,7 @@ static void scsi_disk_release(struct device *cdev); static void sd_print_sense_hdr(struct scsi_disk *, struct scsi_sense_hdr *); static void sd_print_result(struct scsi_disk *, int); +static DEFINE_SPINLOCK(sd_index_lock); static DEFINE_IDA(sd_index_ida); /* This semaphore is used to mediate the 0->1 reference get in the @@ -1050,12 +1051,6 @@ static int sd_done(struct scsi_cmnd *SCpnt) good_bytes = sd_completed_bytes(SCpnt); break; case RECOVERED_ERROR: - /* Inform the user, but make sure that it's not treated - * as a hard error. - */ - scsi_print_sense("sd", SCpnt); - SCpnt->result = 0; - memset(SCpnt->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); good_bytes = scsi_bufflen(SCpnt); break; case NO_SENSE: @@ -1166,23 +1161,19 @@ sd_spinup_disk(struct scsi_disk *sdkp) /* * The device does not want the automatic start to be issued. */ - if (sdkp->device->no_start_on_add) { + if (sdkp->device->no_start_on_add) break; - } - - /* - * If manual intervention is required, or this is an - * absent USB storage device, a spinup is meaningless. - */ - if (sense_valid && - sshdr.sense_key == NOT_READY && - sshdr.asc == 4 && sshdr.ascq == 3) { - break; /* manual intervention required */ - /* - * Issue command to spin up drive when not ready - */ - } else if (sense_valid && sshdr.sense_key == NOT_READY) { + if (sense_valid && sshdr.sense_key == NOT_READY) { + if (sshdr.asc == 4 && sshdr.ascq == 3) + break; /* manual intervention required */ + if (sshdr.asc == 4 && sshdr.ascq == 0xb) + break; /* standby */ + if (sshdr.asc == 4 && sshdr.ascq == 0xc) + break; /* unavailable */ + /* + * Issue command to spin up drive when not ready + */ if (!spintime) { sd_printk(KERN_NOTICE, sdkp, "Spinning up disk..."); cmd[0] = START_STOP; @@ -1276,42 +1267,126 @@ disable: sdkp->capacity = 0; } -/* - * read disk capacity - */ -static void -sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer) +static void read_capacity_error(struct scsi_disk *sdkp, struct scsi_device *sdp, + struct scsi_sense_hdr *sshdr, int sense_valid, + int the_result) +{ + sd_print_result(sdkp, the_result); + if (driver_byte(the_result) & DRIVER_SENSE) + sd_print_sense_hdr(sdkp, sshdr); + else + sd_printk(KERN_NOTICE, sdkp, "Sense not available.\n"); + + /* + * Set dirty bit for removable devices if not ready - + * sometimes drives will not report this properly. + */ + if (sdp->removable && + sense_valid && sshdr->sense_key == NOT_READY) + sdp->changed = 1; + + /* + * We used to set media_present to 0 here to indicate no media + * in the drive, but some drives fail read capacity even with + * media present, so we can't do that. + */ + sdkp->capacity = 0; /* unknown mapped to zero - as usual */ +} + +#define RC16_LEN 32 +#if RC16_LEN > SD_BUF_SIZE +#error RC16_LEN must not be more than SD_BUF_SIZE +#endif + +static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp, + unsigned char *buffer) { unsigned char cmd[16]; - int the_result, retries; - int sector_size = 0; - /* Force READ CAPACITY(16) when PROTECT=1 */ - int longrc = scsi_device_protection(sdkp->device) ? 1 : 0; struct scsi_sense_hdr sshdr; int sense_valid = 0; - struct scsi_device *sdp = sdkp->device; + int the_result; + int retries = 3; + unsigned long long lba; + unsigned sector_size; -repeat: - retries = 3; do { - if (longrc) { - memset((void *) cmd, 0, 16); - cmd[0] = SERVICE_ACTION_IN; - cmd[1] = SAI_READ_CAPACITY_16; - cmd[13] = 13; - memset((void *) buffer, 0, 13); - } else { - cmd[0] = READ_CAPACITY; - memset((void *) &cmd[1], 0, 9); - memset((void *) buffer, 0, 8); + memset(cmd, 0, 16); + cmd[0] = SERVICE_ACTION_IN; + cmd[1] = SAI_READ_CAPACITY_16; + cmd[13] = RC16_LEN; + memset(buffer, 0, RC16_LEN); + + the_result = scsi_execute_req(sdp, cmd, DMA_FROM_DEVICE, + buffer, RC16_LEN, &sshdr, + SD_TIMEOUT, SD_MAX_RETRIES, NULL); + + if (media_not_present(sdkp, &sshdr)) + return -ENODEV; + + if (the_result) { + sense_valid = scsi_sense_valid(&sshdr); + if (sense_valid && + sshdr.sense_key == ILLEGAL_REQUEST && + (sshdr.asc == 0x20 || sshdr.asc == 0x24) && + sshdr.ascq == 0x00) + /* Invalid Command Operation Code or + * Invalid Field in CDB, just retry + * silently with RC10 */ + return -EINVAL; } - + retries--; + + } while (the_result && retries); + + if (the_result) { + sd_printk(KERN_NOTICE, sdkp, "READ CAPACITY(16) failed\n"); + read_capacity_error(sdkp, sdp, &sshdr, sense_valid, the_result); + return -EINVAL; + } + + sector_size = (buffer[8] << 24) | (buffer[9] << 16) | + (buffer[10] << 8) | buffer[11]; + lba = (((u64)buffer[0] << 56) | ((u64)buffer[1] << 48) | + ((u64)buffer[2] << 40) | ((u64)buffer[3] << 32) | + ((u64)buffer[4] << 24) | ((u64)buffer[5] << 16) | + ((u64)buffer[6] << 8) | (u64)buffer[7]); + + sd_read_protection_type(sdkp, buffer); + + if ((sizeof(sdkp->capacity) == 4) && (lba >= 0xffffffffULL)) { + sd_printk(KERN_ERR, sdkp, "Too big for this kernel. Use a " + "kernel compiled with support for large block " + "devices.\n"); + sdkp->capacity = 0; + return -EOVERFLOW; + } + + sdkp->capacity = lba + 1; + return sector_size; +} + +static int read_capacity_10(struct scsi_disk *sdkp, struct scsi_device *sdp, + unsigned char *buffer) +{ + unsigned char cmd[16]; + struct scsi_sense_hdr sshdr; + int sense_valid = 0; + int the_result; + int retries = 3; + sector_t lba; + unsigned sector_size; + + do { + cmd[0] = READ_CAPACITY; + memset(&cmd[1], 0, 9); + memset(buffer, 0, 8); + the_result = scsi_execute_req(sdp, cmd, DMA_FROM_DEVICE, - buffer, longrc ? 13 : 8, &sshdr, - SD_TIMEOUT, SD_MAX_RETRIES, NULL); + buffer, 8, &sshdr, + SD_TIMEOUT, SD_MAX_RETRIES, NULL); if (media_not_present(sdkp, &sshdr)) - return; + return -ENODEV; if (the_result) sense_valid = scsi_sense_valid(&sshdr); @@ -1319,85 +1394,96 @@ repeat: } while (the_result && retries); - if (the_result && !longrc) { + if (the_result) { sd_printk(KERN_NOTICE, sdkp, "READ CAPACITY failed\n"); - sd_print_result(sdkp, the_result); - if (driver_byte(the_result) & DRIVER_SENSE) - sd_print_sense_hdr(sdkp, &sshdr); - else - sd_printk(KERN_NOTICE, sdkp, "Sense not available.\n"); + read_capacity_error(sdkp, sdp, &sshdr, sense_valid, the_result); + return -EINVAL; + } - /* Set dirty bit for removable devices if not ready - - * sometimes drives will not report this properly. */ - if (sdp->removable && - sense_valid && sshdr.sense_key == NOT_READY) - sdp->changed = 1; + sector_size = (buffer[4] << 24) | (buffer[5] << 16) | + (buffer[6] << 8) | buffer[7]; + lba = (buffer[0] << 24) | (buffer[1] << 16) | + (buffer[2] << 8) | buffer[3]; - /* Either no media are present but the drive didn't tell us, - or they are present but the read capacity command fails */ - /* sdkp->media_present = 0; -- not always correct */ - sdkp->capacity = 0; /* unknown mapped to zero - as usual */ + if ((sizeof(sdkp->capacity) == 4) && (lba == 0xffffffff)) { + sd_printk(KERN_ERR, sdkp, "Too big for this kernel. Use a " + "kernel compiled with support for large block " + "devices.\n"); + sdkp->capacity = 0; + return -EOVERFLOW; + } - return; - } else if (the_result && longrc) { - /* READ CAPACITY(16) has been failed */ - sd_printk(KERN_NOTICE, sdkp, "READ CAPACITY(16) failed\n"); - sd_print_result(sdkp, the_result); - sd_printk(KERN_NOTICE, sdkp, "Use 0xffffffff as device size\n"); + sdkp->capacity = lba + 1; + return sector_size; +} - sdkp->capacity = 1 + (sector_t) 0xffffffff; - goto got_data; - } - - if (!longrc) { - sector_size = (buffer[4] << 24) | - (buffer[5] << 16) | (buffer[6] << 8) | buffer[7]; - if (buffer[0] == 0xff && buffer[1] == 0xff && - buffer[2] == 0xff && buffer[3] == 0xff) { - if(sizeof(sdkp->capacity) > 4) { - sd_printk(KERN_NOTICE, sdkp, "Very big device. " - "Trying to use READ CAPACITY(16).\n"); - longrc = 1; - goto repeat; - } - sd_printk(KERN_ERR, sdkp, "Too big for this kernel. Use " - "a kernel compiled with support for large " - "block devices.\n"); - sdkp->capacity = 0; +static int sd_try_rc16_first(struct scsi_device *sdp) +{ + if (sdp->scsi_level > SCSI_SPC_2) + return 1; + if (scsi_device_protection(sdp)) + return 1; + return 0; +} + +/* + * read disk capacity + */ +static void +sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer) +{ + int sector_size; + struct scsi_device *sdp = sdkp->device; + sector_t old_capacity = sdkp->capacity; + + if (sd_try_rc16_first(sdp)) { + sector_size = read_capacity_16(sdkp, sdp, buffer); + if (sector_size == -EOVERFLOW) goto got_data; - } - sdkp->capacity = 1 + (((sector_t)buffer[0] << 24) | - (buffer[1] << 16) | - (buffer[2] << 8) | - buffer[3]); + if (sector_size == -ENODEV) + return; + if (sector_size < 0) + sector_size = read_capacity_10(sdkp, sdp, buffer); + if (sector_size < 0) + return; } else { - sdkp->capacity = 1 + (((u64)buffer[0] << 56) | - ((u64)buffer[1] << 48) | - ((u64)buffer[2] << 40) | - ((u64)buffer[3] << 32) | - ((sector_t)buffer[4] << 24) | - ((sector_t)buffer[5] << 16) | - ((sector_t)buffer[6] << 8) | - (sector_t)buffer[7]); - - sector_size = (buffer[8] << 24) | - (buffer[9] << 16) | (buffer[10] << 8) | buffer[11]; - - sd_read_protection_type(sdkp, buffer); - } - - /* Some devices return the total number of sectors, not the - * highest sector number. Make the necessary adjustment. */ - if (sdp->fix_capacity) { - --sdkp->capacity; + sector_size = read_capacity_10(sdkp, sdp, buffer); + if (sector_size == -EOVERFLOW) + goto got_data; + if (sector_size < 0) + return; + if ((sizeof(sdkp->capacity) > 4) && + (sdkp->capacity > 0xffffffffULL)) { + int old_sector_size = sector_size; + sd_printk(KERN_NOTICE, sdkp, "Very big device. " + "Trying to use READ CAPACITY(16).\n"); + sector_size = read_capacity_16(sdkp, sdp, buffer); + if (sector_size < 0) { + sd_printk(KERN_NOTICE, sdkp, + "Using 0xffffffff as device size\n"); + sdkp->capacity = 1 + (sector_t) 0xffffffff; + sector_size = old_sector_size; + goto got_data; + } + } + } - /* Some devices have version which report the correct sizes - * and others which do not. We guess size according to a heuristic - * and err on the side of lowering the capacity. */ - } else { - if (sdp->guess_capacity) - if (sdkp->capacity & 0x01) /* odd sizes are odd */ - --sdkp->capacity; + /* Some devices are known to return the total number of blocks, + * not the highest block number. Some devices have versions + * which do this and others which do not. Some devices we might + * suspect of doing this but we don't know for certain. + * + * If we know the reported capacity is wrong, decrement it. If + * we can only guess, then assume the number of blocks is even + * (usually true but not always) and err on the side of lowering + * the capacity. + */ + if (sdp->fix_capacity || + (sdp->guess_capacity && (sdkp->capacity & 0x01))) { + sd_printk(KERN_INFO, sdkp, "Adjusting the sector count " + "from its reported value: %llu\n", + (unsigned long long) sdkp->capacity); + --sdkp->capacity; } got_data: @@ -1440,10 +1526,11 @@ got_data: string_get_size(sz, STRING_UNITS_10, cap_str_10, sizeof(cap_str_10)); - sd_printk(KERN_NOTICE, sdkp, - "%llu %d-byte hardware sectors: (%s/%s)\n", - (unsigned long long)sdkp->capacity, - sector_size, cap_str_10, cap_str_2); + if (sdkp->first_scan || old_capacity != sdkp->capacity) + sd_printk(KERN_NOTICE, sdkp, + "%llu %d-byte hardware sectors: (%s/%s)\n", + (unsigned long long)sdkp->capacity, + sector_size, cap_str_10, cap_str_2); } /* Rescale capacity to 512-byte units */ @@ -1480,6 +1567,7 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, unsigned char *buffer) int res; struct scsi_device *sdp = sdkp->device; struct scsi_mode_data data; + int old_wp = sdkp->write_prot; set_disk_ro(sdkp->disk, 0); if (sdp->skip_ms_page_3f) { @@ -1520,11 +1608,13 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, unsigned char *buffer) } else { sdkp->write_prot = ((data.device_specific & 0x80) != 0); set_disk_ro(sdkp->disk, sdkp->write_prot); - sd_printk(KERN_NOTICE, sdkp, "Write Protect is %s\n", - sdkp->write_prot ? "on" : "off"); - sd_printk(KERN_DEBUG, sdkp, - "Mode Sense: %02x %02x %02x %02x\n", - buffer[0], buffer[1], buffer[2], buffer[3]); + if (sdkp->first_scan || old_wp != sdkp->write_prot) { + sd_printk(KERN_NOTICE, sdkp, "Write Protect is %s\n", + sdkp->write_prot ? "on" : "off"); + sd_printk(KERN_DEBUG, sdkp, + "Mode Sense: %02x %02x %02x %02x\n", + buffer[0], buffer[1], buffer[2], buffer[3]); + } } } @@ -1542,6 +1632,9 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer) int modepage; struct scsi_mode_data data; struct scsi_sense_hdr sshdr; + int old_wce = sdkp->WCE; + int old_rcd = sdkp->RCD; + int old_dpofua = sdkp->DPOFUA; if (sdp->skip_ms_page_8) goto defaults; @@ -1613,12 +1706,14 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer) sdkp->DPOFUA = 0; } - sd_printk(KERN_NOTICE, sdkp, - "Write cache: %s, read cache: %s, %s\n", - sdkp->WCE ? "enabled" : "disabled", - sdkp->RCD ? "disabled" : "enabled", - sdkp->DPOFUA ? "supports DPO and FUA" - : "doesn't support DPO or FUA"); + if (sdkp->first_scan || old_wce != sdkp->WCE || + old_rcd != sdkp->RCD || old_dpofua != sdkp->DPOFUA) + sd_printk(KERN_NOTICE, sdkp, + "Write cache: %s, read cache: %s, %s\n", + sdkp->WCE ? "enabled" : "disabled", + sdkp->RCD ? "disabled" : "enabled", + sdkp->DPOFUA ? "supports DPO and FUA" + : "doesn't support DPO or FUA"); return; } @@ -1714,15 +1809,6 @@ static int sd_revalidate_disk(struct gendisk *disk) goto out; } - /* defaults, until the device tells us otherwise */ - sdp->sector_size = 512; - sdkp->capacity = 0; - sdkp->media_present = 1; - sdkp->write_prot = 0; - sdkp->WCE = 0; - sdkp->RCD = 0; - sdkp->ATO = 0; - sd_spinup_disk(sdkp); /* @@ -1736,6 +1822,8 @@ static int sd_revalidate_disk(struct gendisk *disk) sd_read_app_tag_own(sdkp, buffer); } + sdkp->first_scan = 0; + /* * We now have all cache related info, determine how we deal * with ordered requests. Note that as the current SCSI @@ -1846,6 +1934,16 @@ static void sd_probe_async(void *data, async_cookie_t cookie) gd->private_data = &sdkp->driver; gd->queue = sdkp->device->request_queue; + /* defaults, until the device tells us otherwise */ + sdp->sector_size = 512; + sdkp->capacity = 0; + sdkp->media_present = 1; + sdkp->write_prot = 0; + sdkp->WCE = 0; + sdkp->RCD = 0; + sdkp->ATO = 0; + sdkp->first_scan = 1; + sd_revalidate_disk(gd); blk_queue_prep_rq(sdp->request_queue, sd_prep_fn); @@ -1914,7 +2012,9 @@ static int sd_probe(struct device *dev) if (!ida_pre_get(&sd_index_ida, GFP_KERNEL)) goto out_put; + spin_lock(&sd_index_lock); error = ida_get_new(&sd_index_ida, &index); + spin_unlock(&sd_index_lock); } while (error == -EAGAIN); if (error) @@ -1936,7 +2036,9 @@ static int sd_probe(struct device *dev) return 0; out_free_index: + spin_lock(&sd_index_lock); ida_remove(&sd_index_ida, index); + spin_unlock(&sd_index_lock); out_put: put_disk(gd); out_free: @@ -1986,7 +2088,9 @@ static void scsi_disk_release(struct device *dev) struct scsi_disk *sdkp = to_scsi_disk(dev); struct gendisk *disk = sdkp->disk; + spin_lock(&sd_index_lock); ida_remove(&sd_index_ida, sdkp->index); + spin_unlock(&sd_index_lock); disk->private_data = NULL; put_disk(disk); diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h index 75638e7d3f6..708778cf5f0 100644 --- a/drivers/scsi/sd.h +++ b/drivers/scsi/sd.h @@ -53,6 +53,7 @@ struct scsi_disk { unsigned WCE : 1; /* state of disk WCE bit */ unsigned RCD : 1; /* state of disk RCD bit, unused */ unsigned DPOFUA : 1; /* state of disk DPOFUA bit */ + unsigned first_scan : 1; }; #define to_scsi_disk(obj) container_of(obj,struct scsi_disk,dev) diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c index e946e05db7f..4f618f48735 100644 --- a/drivers/scsi/ses.c +++ b/drivers/scsi/ses.c @@ -264,6 +264,7 @@ struct ses_host_edev { struct enclosure_device *edev; }; +#if 0 int ses_match_host(struct enclosure_device *edev, void *data) { struct ses_host_edev *sed = data; @@ -280,6 +281,7 @@ int ses_match_host(struct enclosure_device *edev, void *data) sed->edev = edev; return 1; } +#endif /* 0 */ static void ses_process_descriptor(struct enclosure_component *ecomp, unsigned char *desc) @@ -345,44 +347,21 @@ static int ses_enclosure_find_by_addr(struct enclosure_device *edev, return 0; } -#define VPD_INQUIRY_SIZE 36 - static void ses_match_to_enclosure(struct enclosure_device *edev, struct scsi_device *sdev) { - unsigned char *buf = kmalloc(VPD_INQUIRY_SIZE, GFP_KERNEL); + unsigned char *buf; unsigned char *desc; - u16 vpd_len; + unsigned int vpd_len; struct efd efd = { .addr = 0, }; - unsigned char cmd[] = { - INQUIRY, - 1, - 0x83, - VPD_INQUIRY_SIZE >> 8, - VPD_INQUIRY_SIZE & 0xff, - 0 - }; + buf = scsi_get_vpd_page(sdev, 0x83); if (!buf) return; - if (scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buf, - VPD_INQUIRY_SIZE, NULL, SES_TIMEOUT, SES_RETRIES, - NULL)) - goto free; - - vpd_len = (buf[2] << 8) + buf[3]; - kfree(buf); - buf = kmalloc(vpd_len, GFP_KERNEL); - if (!buf) - return; - cmd[3] = vpd_len >> 8; - cmd[4] = vpd_len & 0xff; - if (scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buf, - vpd_len, NULL, SES_TIMEOUT, SES_RETRIES, NULL)) - goto free; + vpd_len = ((buf[2] << 8) | buf[3]) + 4; desc = buf + 4; while (desc < buf + vpd_len) { @@ -393,7 +372,7 @@ static void ses_match_to_enclosure(struct enclosure_device *edev, u8 type = desc[1] & 0x0f; u8 len = desc[3]; - if (piv && code_set == 1 && assoc == 1 && code_set == 1 + if (piv && code_set == 1 && assoc == 1 && proto == SCSI_PROTOCOL_SAS && type == 3 && len == 8) efd.addr = (u64)desc[4] << 56 | (u64)desc[5] << 48 | diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 8f0bd3f7a59..82312df9b0b 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -98,7 +98,6 @@ static int scatter_elem_sz = SG_SCATTER_SZ; static int scatter_elem_sz_prev = SG_SCATTER_SZ; #define SG_SECTOR_SZ 512 -#define SG_SECTOR_MSK (SG_SECTOR_SZ - 1) static int sg_add(struct device *, struct class_interface *); static void sg_remove(struct device *, struct class_interface *); @@ -137,10 +136,11 @@ typedef struct sg_request { /* SG_MAX_QUEUE requests outstanding per file */ volatile char done; /* 0->before bh, 1->before read, 2->read */ struct request *rq; struct bio *bio; + struct execute_work ew; } Sg_request; typedef struct sg_fd { /* holds the state of a file descriptor */ - struct sg_fd *nextfp; /* NULL when last opened fd on this device */ + struct list_head sfd_siblings; struct sg_device *parentdp; /* owning device */ wait_queue_head_t read_wait; /* queue read until command done */ rwlock_t rq_list_lock; /* protect access to list in req_arr */ @@ -158,6 +158,8 @@ typedef struct sg_fd { /* holds the state of a file descriptor */ char next_cmd_len; /* 0 -> automatic (def), >0 -> use on next write() */ char keep_orphan; /* 0 -> drop orphan (def), 1 -> keep for read() */ char mmap_called; /* 0 -> mmap() never called on this fd */ + struct kref f_ref; + struct execute_work ew; } Sg_fd; typedef struct sg_device { /* holds the state of each scsi generic device */ @@ -165,27 +167,25 @@ typedef struct sg_device { /* holds the state of each scsi generic device */ wait_queue_head_t o_excl_wait; /* queue open() when O_EXCL in use */ int sg_tablesize; /* adapter's max scatter-gather table size */ u32 index; /* device index number */ - Sg_fd *headfp; /* first open fd belonging to this device */ + struct list_head sfds; volatile char detached; /* 0->attached, 1->detached pending removal */ volatile char exclude; /* opened for exclusive access */ char sgdebug; /* 0->off, 1->sense, 9->dump dev, 10-> all devs */ struct gendisk *disk; struct cdev * cdev; /* char_dev [sysfs: /sys/cdev/major/sg<n>] */ + struct kref d_ref; } Sg_device; -static int sg_fasync(int fd, struct file *filp, int mode); /* tasklet or soft irq callback */ static void sg_rq_end_io(struct request *rq, int uptodate); static int sg_start_req(Sg_request *srp, unsigned char *cmd); static void sg_finish_rem_req(Sg_request * srp); static int sg_build_indirect(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size); -static int sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp, - int tablesize); static ssize_t sg_new_read(Sg_fd * sfp, char __user *buf, size_t count, Sg_request * srp); static ssize_t sg_new_write(Sg_fd *sfp, struct file *file, const char __user *buf, size_t count, int blocking, - int read_only, Sg_request **o_srp); + int read_only, int sg_io_owned, Sg_request **o_srp); static int sg_common_write(Sg_fd * sfp, Sg_request * srp, unsigned char *cmnd, int timeout, int blocking); static int sg_read_oxfer(Sg_request * srp, char __user *outp, int num_read_xfer); @@ -194,16 +194,13 @@ static void sg_build_reserve(Sg_fd * sfp, int req_size); static void sg_link_reserve(Sg_fd * sfp, Sg_request * srp, int size); static void sg_unlink_reserve(Sg_fd * sfp, Sg_request * srp); static Sg_fd *sg_add_sfp(Sg_device * sdp, int dev); -static int sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp); -static void __sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp); +static void sg_remove_sfp(struct kref *); static Sg_request *sg_get_rq_mark(Sg_fd * sfp, int pack_id); static Sg_request *sg_add_request(Sg_fd * sfp); static int sg_remove_request(Sg_fd * sfp, Sg_request * srp); static int sg_res_in_use(Sg_fd * sfp); static Sg_device *sg_get_dev(int dev); -#ifdef CONFIG_SCSI_PROC_FS -static int sg_last_dev(void); -#endif +static void sg_put_dev(Sg_device *sdp); #define SZ_SG_HEADER sizeof(struct sg_header) #define SZ_SG_IO_HDR sizeof(sg_io_hdr_t) @@ -237,22 +234,17 @@ sg_open(struct inode *inode, struct file *filp) nonseekable_open(inode, filp); SCSI_LOG_TIMEOUT(3, printk("sg_open: dev=%d, flags=0x%x\n", dev, flags)); sdp = sg_get_dev(dev); - if ((!sdp) || (!sdp->device)) { - unlock_kernel(); - return -ENXIO; - } - if (sdp->detached) { - unlock_kernel(); - return -ENODEV; + if (IS_ERR(sdp)) { + retval = PTR_ERR(sdp); + sdp = NULL; + goto sg_put; } /* This driver's module count bumped by fops_get in <linux/fs.h> */ /* Prevent the device driver from vanishing while we sleep */ retval = scsi_device_get(sdp->device); - if (retval) { - unlock_kernel(); - return retval; - } + if (retval) + goto sg_put; if (!((flags & O_NONBLOCK) || scsi_block_when_processing_errors(sdp->device))) { @@ -266,13 +258,13 @@ sg_open(struct inode *inode, struct file *filp) retval = -EPERM; /* Can't lock it with read only access */ goto error_out; } - if (sdp->headfp && (flags & O_NONBLOCK)) { + if (!list_empty(&sdp->sfds) && (flags & O_NONBLOCK)) { retval = -EBUSY; goto error_out; } res = 0; __wait_event_interruptible(sdp->o_excl_wait, - ((sdp->headfp || sdp->exclude) ? 0 : (sdp->exclude = 1)), res); + ((!list_empty(&sdp->sfds) || sdp->exclude) ? 0 : (sdp->exclude = 1)), res); if (res) { retval = res; /* -ERESTARTSYS because signal hit process */ goto error_out; @@ -294,7 +286,7 @@ sg_open(struct inode *inode, struct file *filp) retval = -ENODEV; goto error_out; } - if (!sdp->headfp) { /* no existing opens on this device */ + if (list_empty(&sdp->sfds)) { /* no existing opens on this device */ sdp->sgdebug = 0; q = sdp->device->request_queue; sdp->sg_tablesize = min(q->max_hw_segments, @@ -303,16 +295,20 @@ sg_open(struct inode *inode, struct file *filp) if ((sfp = sg_add_sfp(sdp, dev))) filp->private_data = sfp; else { - if (flags & O_EXCL) + if (flags & O_EXCL) { sdp->exclude = 0; /* undo if error */ + wake_up_interruptible(&sdp->o_excl_wait); + } retval = -ENOMEM; goto error_out; } - unlock_kernel(); - return 0; - - error_out: - scsi_device_put(sdp->device); + retval = 0; +error_out: + if (retval) + scsi_device_put(sdp->device); +sg_put: + if (sdp) + sg_put_dev(sdp); unlock_kernel(); return retval; } @@ -327,13 +323,13 @@ sg_release(struct inode *inode, struct file *filp) if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp))) return -ENXIO; SCSI_LOG_TIMEOUT(3, printk("sg_release: %s\n", sdp->disk->disk_name)); - if (0 == sg_remove_sfp(sdp, sfp)) { /* Returns 1 when sdp gone */ - if (!sdp->detached) { - scsi_device_put(sdp->device); - } - sdp->exclude = 0; - wake_up_interruptible(&sdp->o_excl_wait); - } + + sfp->closed = 1; + + sdp->exclude = 0; + wake_up_interruptible(&sdp->o_excl_wait); + + kref_put(&sfp->f_ref, sg_remove_sfp); return 0; } @@ -557,7 +553,8 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos) return -EFAULT; blocking = !(filp->f_flags & O_NONBLOCK); if (old_hdr.reply_len < 0) - return sg_new_write(sfp, filp, buf, count, blocking, 0, NULL); + return sg_new_write(sfp, filp, buf, count, + blocking, 0, 0, NULL); if (count < (SZ_SG_HEADER + 6)) return -EIO; /* The minimum scsi command length is 6 bytes. */ @@ -638,7 +635,7 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos) static ssize_t sg_new_write(Sg_fd *sfp, struct file *file, const char __user *buf, - size_t count, int blocking, int read_only, + size_t count, int blocking, int read_only, int sg_io_owned, Sg_request **o_srp) { int k; @@ -658,6 +655,7 @@ sg_new_write(Sg_fd *sfp, struct file *file, const char __user *buf, SCSI_LOG_TIMEOUT(1, printk("sg_new_write: queue full\n")); return -EDOM; } + srp->sg_io_owned = sg_io_owned; hp = &srp->header; if (__copy_from_user(hp, buf, SZ_SG_IO_HDR)) { sg_remove_request(sfp, srp); @@ -755,24 +753,13 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp, hp->duration = jiffies_to_msecs(jiffies); srp->rq->timeout = timeout; + kref_get(&sfp->f_ref); /* sg_rq_end_io() does kref_put(). */ blk_execute_rq_nowait(sdp->device->request_queue, sdp->disk, srp->rq, 1, sg_rq_end_io); return 0; } static int -sg_srp_done(Sg_request *srp, Sg_fd *sfp) -{ - unsigned long iflags; - int done; - - read_lock_irqsave(&sfp->rq_list_lock, iflags); - done = srp->done; - read_unlock_irqrestore(&sfp->rq_list_lock, iflags); - return done; -} - -static int sg_ioctl(struct inode *inode, struct file *filp, unsigned int cmd_in, unsigned long arg) { @@ -804,27 +791,26 @@ sg_ioctl(struct inode *inode, struct file *filp, return -EFAULT; result = sg_new_write(sfp, filp, p, SZ_SG_IO_HDR, - blocking, read_only, &srp); + blocking, read_only, 1, &srp); if (result < 0) return result; - srp->sg_io_owned = 1; while (1) { result = 0; /* following macro to beat race condition */ __wait_event_interruptible(sfp->read_wait, - (sdp->detached || sfp->closed || sg_srp_done(srp, sfp)), - result); + (srp->done || sdp->detached), + result); if (sdp->detached) return -ENODEV; - if (sfp->closed) - return 0; /* request packet dropped already */ - if (0 == result) + write_lock_irq(&sfp->rq_list_lock); + if (srp->done) { + srp->done = 2; + write_unlock_irq(&sfp->rq_list_lock); break; + } srp->orphan = 1; + write_unlock_irq(&sfp->rq_list_lock); return result; /* -ERESTARTSYS because signal hit process */ } - write_lock_irqsave(&sfp->rq_list_lock, iflags); - srp->done = 2; - write_unlock_irqrestore(&sfp->rq_list_lock, iflags); result = sg_new_read(sfp, p, SZ_SG_IO_HDR, srp); return (result < 0) ? result : 0; } @@ -1078,7 +1064,7 @@ sg_ioctl(struct inode *inode, struct file *filp, case BLKTRACESETUP: return blk_trace_setup(sdp->device->request_queue, sdp->disk->disk_name, - sdp->device->sdev_gendev.devt, + MKDEV(SCSI_GENERIC_MAJOR, sdp->index), (char *)arg); case BLKTRACESTART: return blk_trace_startstop(sdp->device->request_queue, 1); @@ -1154,7 +1140,6 @@ sg_poll(struct file *filp, poll_table * wait) static int sg_fasync(int fd, struct file *filp, int mode) { - int retval; Sg_device *sdp; Sg_fd *sfp; @@ -1163,8 +1148,7 @@ sg_fasync(int fd, struct file *filp, int mode) SCSI_LOG_TIMEOUT(3, printk("sg_fasync: %s, mode=%d\n", sdp->disk->disk_name, mode)); - retval = fasync_helper(fd, filp, mode, &sfp->async_qp); - return (retval < 0) ? retval : 0; + return fasync_helper(fd, filp, mode, &sfp->async_qp); } static int @@ -1240,6 +1224,15 @@ sg_mmap(struct file *filp, struct vm_area_struct *vma) return 0; } +static void sg_rq_end_io_usercontext(struct work_struct *work) +{ + struct sg_request *srp = container_of(work, struct sg_request, ew.work); + struct sg_fd *sfp = srp->parentfp; + + sg_finish_rem_req(srp); + kref_put(&sfp->f_ref, sg_remove_sfp); +} + /* * This function is a "bottom half" handler that is called by the mid * level when a command is completed (or has failed). @@ -1247,24 +1240,23 @@ sg_mmap(struct file *filp, struct vm_area_struct *vma) static void sg_rq_end_io(struct request *rq, int uptodate) { struct sg_request *srp = rq->end_io_data; - Sg_device *sdp = NULL; + Sg_device *sdp; Sg_fd *sfp; unsigned long iflags; unsigned int ms; char *sense; - int result, resid; + int result, resid, done = 1; - if (NULL == srp) { - printk(KERN_ERR "sg_cmd_done: NULL request\n"); + if (WARN_ON(srp->done != 0)) return; - } + sfp = srp->parentfp; - if (sfp) - sdp = sfp->parentdp; - if ((NULL == sdp) || sdp->detached) { - printk(KERN_INFO "sg_cmd_done: device detached\n"); + if (WARN_ON(sfp == NULL)) return; - } + + sdp = sfp->parentdp; + if (unlikely(sdp->detached)) + printk(KERN_INFO "sg_rq_end_io: device detached\n"); sense = rq->sense; result = rq->errors; @@ -1303,32 +1295,26 @@ static void sg_rq_end_io(struct request *rq, int uptodate) } /* Rely on write phase to clean out srp status values, so no "else" */ - if (sfp->closed) { /* whoops this fd already released, cleanup */ - SCSI_LOG_TIMEOUT(1, printk("sg_cmd_done: already closed, freeing ...\n")); - sg_finish_rem_req(srp); - srp = NULL; - if (NULL == sfp->headrp) { - SCSI_LOG_TIMEOUT(1, printk("sg_cmd_done: already closed, final cleanup\n")); - if (0 == sg_remove_sfp(sdp, sfp)) { /* device still present */ - scsi_device_put(sdp->device); - } - sfp = NULL; - } - } else if (srp && srp->orphan) { + write_lock_irqsave(&sfp->rq_list_lock, iflags); + if (unlikely(srp->orphan)) { if (sfp->keep_orphan) srp->sg_io_owned = 0; - else { - sg_finish_rem_req(srp); - srp = NULL; - } + else + done = 0; } - if (sfp && srp) { - /* Now wake up any sg_read() that is waiting for this packet. */ - kill_fasync(&sfp->async_qp, SIGPOLL, POLL_IN); - write_lock_irqsave(&sfp->rq_list_lock, iflags); - srp->done = 1; + srp->done = done; + write_unlock_irqrestore(&sfp->rq_list_lock, iflags); + + if (likely(done)) { + /* Now wake up any sg_read() that is waiting for this + * packet. + */ wake_up_interruptible(&sfp->read_wait); - write_unlock_irqrestore(&sfp->rq_list_lock, iflags); + kill_fasync(&sfp->async_qp, SIGPOLL, POLL_IN); + kref_put(&sfp->f_ref, sg_remove_sfp); + } else { + INIT_WORK(&srp->ew.work, sg_rq_end_io_usercontext); + schedule_work(&srp->ew.work); } } @@ -1364,17 +1350,18 @@ static Sg_device *sg_alloc(struct gendisk *disk, struct scsi_device *scsidp) printk(KERN_WARNING "kmalloc Sg_device failure\n"); return ERR_PTR(-ENOMEM); } - error = -ENOMEM; + if (!idr_pre_get(&sg_index_idr, GFP_KERNEL)) { printk(KERN_WARNING "idr expansion Sg_device failure\n"); + error = -ENOMEM; goto out; } write_lock_irqsave(&sg_index_lock, iflags); - error = idr_get_new(&sg_index_idr, sdp, &k); - write_unlock_irqrestore(&sg_index_lock, iflags); + error = idr_get_new(&sg_index_idr, sdp, &k); if (error) { + write_unlock_irqrestore(&sg_index_lock, iflags); printk(KERN_WARNING "idr allocation Sg_device failure: %d\n", error); goto out; @@ -1388,9 +1375,13 @@ static Sg_device *sg_alloc(struct gendisk *disk, struct scsi_device *scsidp) disk->first_minor = k; sdp->disk = disk; sdp->device = scsidp; + INIT_LIST_HEAD(&sdp->sfds); init_waitqueue_head(&sdp->o_excl_wait); sdp->sg_tablesize = min(q->max_hw_segments, q->max_phys_segments); sdp->index = k; + kref_init(&sdp->d_ref); + + write_unlock_irqrestore(&sg_index_lock, iflags); error = 0; out: @@ -1401,6 +1392,8 @@ static Sg_device *sg_alloc(struct gendisk *disk, struct scsi_device *scsidp) return sdp; overflow: + idr_remove(&sg_index_idr, k); + write_unlock_irqrestore(&sg_index_lock, iflags); sdev_printk(KERN_WARNING, scsidp, "Unable to attach sg device type=%d, minor " "number exceeds %d\n", scsidp->type, SG_MAX_DEVS - 1); @@ -1488,49 +1481,46 @@ out: return error; } -static void -sg_remove(struct device *cl_dev, struct class_interface *cl_intf) +static void sg_device_destroy(struct kref *kref) +{ + struct sg_device *sdp = container_of(kref, struct sg_device, d_ref); + unsigned long flags; + + /* CAUTION! Note that the device can still be found via idr_find() + * even though the refcount is 0. Therefore, do idr_remove() BEFORE + * any other cleanup. + */ + + write_lock_irqsave(&sg_index_lock, flags); + idr_remove(&sg_index_idr, sdp->index); + write_unlock_irqrestore(&sg_index_lock, flags); + + SCSI_LOG_TIMEOUT(3, + printk("sg_device_destroy: %s\n", + sdp->disk->disk_name)); + + put_disk(sdp->disk); + kfree(sdp); +} + +static void sg_remove(struct device *cl_dev, struct class_interface *cl_intf) { struct scsi_device *scsidp = to_scsi_device(cl_dev->parent); Sg_device *sdp = dev_get_drvdata(cl_dev); unsigned long iflags; Sg_fd *sfp; - Sg_fd *tsfp; - Sg_request *srp; - Sg_request *tsrp; - int delay; - if (!sdp) + if (!sdp || sdp->detached) return; - delay = 0; + SCSI_LOG_TIMEOUT(3, printk("sg_remove: %s\n", sdp->disk->disk_name)); + + /* Need a write lock to set sdp->detached. */ write_lock_irqsave(&sg_index_lock, iflags); - if (sdp->headfp) { - sdp->detached = 1; - for (sfp = sdp->headfp; sfp; sfp = tsfp) { - tsfp = sfp->nextfp; - for (srp = sfp->headrp; srp; srp = tsrp) { - tsrp = srp->nextrp; - if (sfp->closed || (0 == sg_srp_done(srp, sfp))) - sg_finish_rem_req(srp); - } - if (sfp->closed) { - scsi_device_put(sdp->device); - __sg_remove_sfp(sdp, sfp); - } else { - delay = 1; - wake_up_interruptible(&sfp->read_wait); - kill_fasync(&sfp->async_qp, SIGPOLL, - POLL_HUP); - } - } - SCSI_LOG_TIMEOUT(3, printk("sg_remove: dev=%d, dirty\n", sdp->index)); - if (NULL == sdp->headfp) { - idr_remove(&sg_index_idr, sdp->index); - } - } else { /* nothing active, simple case */ - SCSI_LOG_TIMEOUT(3, printk("sg_remove: dev=%d\n", sdp->index)); - idr_remove(&sg_index_idr, sdp->index); + sdp->detached = 1; + list_for_each_entry(sfp, &sdp->sfds, sfd_siblings) { + wake_up_interruptible(&sfp->read_wait); + kill_fasync(&sfp->async_qp, SIGPOLL, POLL_HUP); } write_unlock_irqrestore(&sg_index_lock, iflags); @@ -1538,13 +1528,8 @@ sg_remove(struct device *cl_dev, struct class_interface *cl_intf) device_destroy(sg_sysfs_class, MKDEV(SCSI_GENERIC_MAJOR, sdp->index)); cdev_del(sdp->cdev); sdp->cdev = NULL; - put_disk(sdp->disk); - sdp->disk = NULL; - if (NULL == sdp->headfp) - kfree(sdp); - if (delay) - msleep(10); /* dirty detach so delay device destruction */ + sg_put_dev(sdp); } module_param_named(scatter_elem_sz, scatter_elem_sz, int, S_IRUGO | S_IWUSR); @@ -1673,10 +1658,30 @@ static int sg_start_req(Sg_request *srp, unsigned char *cmd) md->null_mapped = hp->dxferp ? 0 : 1; } - if (iov_count) - res = blk_rq_map_user_iov(q, rq, md, hp->dxferp, iov_count, - hp->dxfer_len, GFP_ATOMIC); - else + if (iov_count) { + int len, size = sizeof(struct sg_iovec) * iov_count; + struct iovec *iov; + + iov = kmalloc(size, GFP_ATOMIC); + if (!iov) + return -ENOMEM; + + if (copy_from_user(iov, hp->dxferp, size)) { + kfree(iov); + return -EFAULT; + } + + len = iov_length(iov, iov_count); + if (hp->dxfer_len < len) { + iov_count = iov_shorten(iov, iov_count, hp->dxfer_len); + len = hp->dxfer_len; + } + + res = blk_rq_map_user_iov(q, rq, md, (struct sg_iovec *)iov, + iov_count, + len, GFP_ATOMIC); + kfree(iov); + } else res = blk_rq_map_user(q, rq, md, hp->dxferp, hp->dxfer_len, GFP_ATOMIC); @@ -1738,8 +1743,8 @@ sg_build_indirect(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size) return -EFAULT; if (0 == blk_size) ++blk_size; /* don't know why */ -/* round request up to next highest SG_SECTOR_SZ byte boundary */ - blk_size = (blk_size + SG_SECTOR_MSK) & (~SG_SECTOR_MSK); + /* round request up to next highest SG_SECTOR_SZ byte boundary */ + blk_size = ALIGN(blk_size, SG_SECTOR_SZ); SCSI_LOG_TIMEOUT(4, printk("sg_build_indirect: buff_size=%d, blk_size=%d\n", buff_size, blk_size)); @@ -1941,22 +1946,6 @@ sg_get_rq_mark(Sg_fd * sfp, int pack_id) return resp; } -#ifdef CONFIG_SCSI_PROC_FS -static Sg_request * -sg_get_nth_request(Sg_fd * sfp, int nth) -{ - Sg_request *resp; - unsigned long iflags; - int k; - - read_lock_irqsave(&sfp->rq_list_lock, iflags); - for (k = 0, resp = sfp->headrp; resp && (k < nth); - ++k, resp = resp->nextrp) ; - read_unlock_irqrestore(&sfp->rq_list_lock, iflags); - return resp; -} -#endif - /* always adds to end of list */ static Sg_request * sg_add_request(Sg_fd * sfp) @@ -2032,22 +2021,6 @@ sg_remove_request(Sg_fd * sfp, Sg_request * srp) return res; } -#ifdef CONFIG_SCSI_PROC_FS -static Sg_fd * -sg_get_nth_sfp(Sg_device * sdp, int nth) -{ - Sg_fd *resp; - unsigned long iflags; - int k; - - read_lock_irqsave(&sg_index_lock, iflags); - for (k = 0, resp = sdp->headfp; resp && (k < nth); - ++k, resp = resp->nextfp) ; - read_unlock_irqrestore(&sg_index_lock, iflags); - return resp; -} -#endif - static Sg_fd * sg_add_sfp(Sg_device * sdp, int dev) { @@ -2062,6 +2035,7 @@ sg_add_sfp(Sg_device * sdp, int dev) init_waitqueue_head(&sfp->read_wait); rwlock_init(&sfp->rq_list_lock); + kref_init(&sfp->f_ref); sfp->timeout = SG_DEFAULT_TIMEOUT; sfp->timeout_user = SG_DEFAULT_TIMEOUT_USER; sfp->force_packid = SG_DEF_FORCE_PACK_ID; @@ -2071,14 +2045,7 @@ sg_add_sfp(Sg_device * sdp, int dev) sfp->keep_orphan = SG_DEF_KEEP_ORPHAN; sfp->parentdp = sdp; write_lock_irqsave(&sg_index_lock, iflags); - if (!sdp->headfp) - sdp->headfp = sfp; - else { /* add to tail of existing list */ - Sg_fd *pfp = sdp->headfp; - while (pfp->nextfp) - pfp = pfp->nextfp; - pfp->nextfp = sfp; - } + list_add_tail(&sfp->sfd_siblings, &sdp->sfds); write_unlock_irqrestore(&sg_index_lock, iflags); SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: sfp=0x%p\n", sfp)); if (unlikely(sg_big_buff != def_reserved_size)) @@ -2089,75 +2056,53 @@ sg_add_sfp(Sg_device * sdp, int dev) sg_build_reserve(sfp, bufflen); SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: bufflen=%d, k_use_sg=%d\n", sfp->reserve.bufflen, sfp->reserve.k_use_sg)); + + kref_get(&sdp->d_ref); + __module_get(THIS_MODULE); return sfp; } -static void -__sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp) +static void sg_remove_sfp_usercontext(struct work_struct *work) { - Sg_fd *fp; - Sg_fd *prev_fp; + struct sg_fd *sfp = container_of(work, struct sg_fd, ew.work); + struct sg_device *sdp = sfp->parentdp; + + /* Cleanup any responses which were never read(). */ + while (sfp->headrp) + sg_finish_rem_req(sfp->headrp); - prev_fp = sdp->headfp; - if (sfp == prev_fp) - sdp->headfp = prev_fp->nextfp; - else { - while ((fp = prev_fp->nextfp)) { - if (sfp == fp) { - prev_fp->nextfp = fp->nextfp; - break; - } - prev_fp = fp; - } - } if (sfp->reserve.bufflen > 0) { - SCSI_LOG_TIMEOUT(6, - printk("__sg_remove_sfp: bufflen=%d, k_use_sg=%d\n", - (int) sfp->reserve.bufflen, (int) sfp->reserve.k_use_sg)); + SCSI_LOG_TIMEOUT(6, + printk("sg_remove_sfp: bufflen=%d, k_use_sg=%d\n", + (int) sfp->reserve.bufflen, + (int) sfp->reserve.k_use_sg)); sg_remove_scat(&sfp->reserve); } - sfp->parentdp = NULL; - SCSI_LOG_TIMEOUT(6, printk("__sg_remove_sfp: sfp=0x%p\n", sfp)); + + SCSI_LOG_TIMEOUT(6, + printk("sg_remove_sfp: %s, sfp=0x%p\n", + sdp->disk->disk_name, + sfp)); kfree(sfp); + + scsi_device_put(sdp->device); + sg_put_dev(sdp); + module_put(THIS_MODULE); } -/* Returns 0 in normal case, 1 when detached and sdp object removed */ -static int -sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp) +static void sg_remove_sfp(struct kref *kref) { - Sg_request *srp; - Sg_request *tsrp; - int dirty = 0; - int res = 0; + struct sg_fd *sfp = container_of(kref, struct sg_fd, f_ref); + struct sg_device *sdp = sfp->parentdp; + unsigned long iflags; - for (srp = sfp->headrp; srp; srp = tsrp) { - tsrp = srp->nextrp; - if (sg_srp_done(srp, sfp)) - sg_finish_rem_req(srp); - else - ++dirty; - } - if (0 == dirty) { - unsigned long iflags; + write_lock_irqsave(&sg_index_lock, iflags); + list_del(&sfp->sfd_siblings); + write_unlock_irqrestore(&sg_index_lock, iflags); + wake_up_interruptible(&sdp->o_excl_wait); - write_lock_irqsave(&sg_index_lock, iflags); - __sg_remove_sfp(sdp, sfp); - if (sdp->detached && (NULL == sdp->headfp)) { - idr_remove(&sg_index_idr, sdp->index); - kfree(sdp); - res = 1; - } - write_unlock_irqrestore(&sg_index_lock, iflags); - } else { - /* MOD_INC's to inhibit unloading sg and associated adapter driver */ - /* only bump the access_count if we actually succeeded in - * throwing another counter on the host module */ - scsi_device_get(sdp->device); /* XXX: retval ignored? */ - sfp->closed = 1; /* flag dirty state on this fd */ - SCSI_LOG_TIMEOUT(1, printk("sg_remove_sfp: worrisome, %d writes pending\n", - dirty)); - } - return res; + INIT_WORK(&sfp->ew.work, sg_remove_sfp_usercontext); + schedule_work(&sfp->ew.work); } static int @@ -2199,19 +2144,38 @@ sg_last_dev(void) } #endif -static Sg_device * -sg_get_dev(int dev) +/* must be called with sg_index_lock held */ +static Sg_device *sg_lookup_dev(int dev) { - Sg_device *sdp; - unsigned long iflags; + return idr_find(&sg_index_idr, dev); +} - read_lock_irqsave(&sg_index_lock, iflags); - sdp = idr_find(&sg_index_idr, dev); - read_unlock_irqrestore(&sg_index_lock, iflags); +static Sg_device *sg_get_dev(int dev) +{ + struct sg_device *sdp; + unsigned long flags; + + read_lock_irqsave(&sg_index_lock, flags); + sdp = sg_lookup_dev(dev); + if (!sdp) + sdp = ERR_PTR(-ENXIO); + else if (sdp->detached) { + /* If sdp->detached, then the refcount may already be 0, in + * which case it would be a bug to do kref_get(). + */ + sdp = ERR_PTR(-ENODEV); + } else + kref_get(&sdp->d_ref); + read_unlock_irqrestore(&sg_index_lock, flags); return sdp; } +static void sg_put_dev(struct sg_device *sdp) +{ + kref_put(&sdp->d_ref, sg_device_destroy); +} + #ifdef CONFIG_SCSI_PROC_FS static struct proc_dir_entry *sg_proc_sgp = NULL; @@ -2468,8 +2432,10 @@ static int sg_proc_seq_show_dev(struct seq_file *s, void *v) struct sg_proc_deviter * it = (struct sg_proc_deviter *) v; Sg_device *sdp; struct scsi_device *scsidp; + unsigned long iflags; - sdp = it ? sg_get_dev(it->index) : NULL; + read_lock_irqsave(&sg_index_lock, iflags); + sdp = it ? sg_lookup_dev(it->index) : NULL; if (sdp && (scsidp = sdp->device) && (!sdp->detached)) seq_printf(s, "%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n", scsidp->host->host_no, scsidp->channel, @@ -2480,6 +2446,7 @@ static int sg_proc_seq_show_dev(struct seq_file *s, void *v) (int) scsi_device_online(scsidp)); else seq_printf(s, "-1\t-1\t-1\t-1\t-1\t-1\t-1\t-1\t-1\n"); + read_unlock_irqrestore(&sg_index_lock, iflags); return 0; } @@ -2493,16 +2460,20 @@ static int sg_proc_seq_show_devstrs(struct seq_file *s, void *v) struct sg_proc_deviter * it = (struct sg_proc_deviter *) v; Sg_device *sdp; struct scsi_device *scsidp; + unsigned long iflags; - sdp = it ? sg_get_dev(it->index) : NULL; + read_lock_irqsave(&sg_index_lock, iflags); + sdp = it ? sg_lookup_dev(it->index) : NULL; if (sdp && (scsidp = sdp->device) && (!sdp->detached)) seq_printf(s, "%8.8s\t%16.16s\t%4.4s\n", scsidp->vendor, scsidp->model, scsidp->rev); else seq_printf(s, "<no active device>\n"); + read_unlock_irqrestore(&sg_index_lock, iflags); return 0; } +/* must be called while holding sg_index_lock */ static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp) { int k, m, new_interface, blen, usg; @@ -2512,9 +2483,12 @@ static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp) const char * cp; unsigned int ms; - for (k = 0; (fp = sg_get_nth_sfp(sdp, k)); ++k) { + k = 0; + list_for_each_entry(fp, &sdp->sfds, sfd_siblings) { + k++; + read_lock(&fp->rq_list_lock); /* irqs already disabled */ seq_printf(s, " FD(%d): timeout=%dms bufflen=%d " - "(res)sgat=%d low_dma=%d\n", k + 1, + "(res)sgat=%d low_dma=%d\n", k, jiffies_to_msecs(fp->timeout), fp->reserve.bufflen, (int) fp->reserve.k_use_sg, @@ -2522,7 +2496,9 @@ static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp) seq_printf(s, " cmd_q=%d f_packid=%d k_orphan=%d closed=%d\n", (int) fp->cmd_q, (int) fp->force_packid, (int) fp->keep_orphan, (int) fp->closed); - for (m = 0; (srp = sg_get_nth_request(fp, m)); ++m) { + for (m = 0, srp = fp->headrp; + srp != NULL; + ++m, srp = srp->nextrp) { hp = &srp->header; new_interface = (hp->interface_id == '\0') ? 0 : 1; if (srp->res_used) { @@ -2559,6 +2535,7 @@ static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp) } if (0 == m) seq_printf(s, " No requests active\n"); + read_unlock(&fp->rq_list_lock); } } @@ -2571,39 +2548,34 @@ static int sg_proc_seq_show_debug(struct seq_file *s, void *v) { struct sg_proc_deviter * it = (struct sg_proc_deviter *) v; Sg_device *sdp; + unsigned long iflags; if (it && (0 == it->index)) { seq_printf(s, "max_active_device=%d(origin 1)\n", (int)it->max); seq_printf(s, " def_reserved_size=%d\n", sg_big_buff); } - sdp = it ? sg_get_dev(it->index) : NULL; - if (sdp) { - struct scsi_device *scsidp = sdp->device; - if (NULL == scsidp) { - seq_printf(s, "device %d detached ??\n", - (int)it->index); - return 0; - } + read_lock_irqsave(&sg_index_lock, iflags); + sdp = it ? sg_lookup_dev(it->index) : NULL; + if (sdp && !list_empty(&sdp->sfds)) { + struct scsi_device *scsidp = sdp->device; - if (sg_get_nth_sfp(sdp, 0)) { - seq_printf(s, " >>> device=%s ", - sdp->disk->disk_name); - if (sdp->detached) - seq_printf(s, "detached pending close "); - else - seq_printf - (s, "scsi%d chan=%d id=%d lun=%d em=%d", - scsidp->host->host_no, - scsidp->channel, scsidp->id, - scsidp->lun, - scsidp->host->hostt->emulated); - seq_printf(s, " sg_tablesize=%d excl=%d\n", - sdp->sg_tablesize, sdp->exclude); - } + seq_printf(s, " >>> device=%s ", sdp->disk->disk_name); + if (sdp->detached) + seq_printf(s, "detached pending close "); + else + seq_printf + (s, "scsi%d chan=%d id=%d lun=%d em=%d", + scsidp->host->host_no, + scsidp->channel, scsidp->id, + scsidp->lun, + scsidp->host->hostt->emulated); + seq_printf(s, " sg_tablesize=%d excl=%d\n", + sdp->sg_tablesize, sdp->exclude); sg_proc_debug_helper(s, sdp); } + read_unlock_irqrestore(&sg_index_lock, iflags); return 0; } diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index e7fa3caead7..0e1a0f2d2ad 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -309,15 +309,6 @@ static int sr_done(struct scsi_cmnd *SCpnt) break; case RECOVERED_ERROR: - - /* - * An error occured, but it recovered. Inform the - * user, but make sure that it's not treated as a - * hard error. - */ - scsi_print_sense("sr", SCpnt); - SCpnt->result = 0; - SCpnt->sense_buffer[0] = 0x0; good_bytes = this_count; break; diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index c6f19ee8f2c..eb24efea8f1 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -374,9 +374,9 @@ static int st_chk_result(struct scsi_tape *STp, struct st_request * SRpnt) if (!debugging) { /* Abnormal conditions for tape */ if (!cmdstatp->have_sense) printk(KERN_WARNING - "%s: Error %x (sugg. bt 0x%x, driver bt 0x%x, host bt 0x%x).\n", - name, result, suggestion(result), - driver_byte(result) & DRIVER_MASK, host_byte(result)); + "%s: Error %x (driver bt 0x%x, host bt 0x%x).\n", + name, result, driver_byte(result), + host_byte(result)); else if (cmdstatp->have_sense && scode != NO_SENSE && scode != RECOVERED_ERROR && diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c index a3a18ad7312..df7f96caa1c 100644 --- a/drivers/scsi/stex.c +++ b/drivers/scsi/stex.c @@ -1,7 +1,7 @@ /* * SuperTrak EX Series Storage Controller driver for Linux * - * Copyright (C) 2005, 2006 Promise Technology Inc. + * Copyright (C) 2005-2009 Promise Technology Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -36,11 +36,11 @@ #include <scsi/scsi_eh.h> #define DRV_NAME "stex" -#define ST_DRIVER_VERSION "3.6.0000.1" -#define ST_VER_MAJOR 3 -#define ST_VER_MINOR 6 -#define ST_OEM 0 -#define ST_BUILD_VER 1 +#define ST_DRIVER_VERSION "4.6.0000.3" +#define ST_VER_MAJOR 4 +#define ST_VER_MINOR 6 +#define ST_OEM 0 +#define ST_BUILD_VER 3 enum { /* MU register offset */ @@ -55,6 +55,13 @@ enum { OIS = 0x30, /* MU_OUTBOUND_INTERRUPT_STATUS */ OIM = 0x3c, /* MU_OUTBOUND_INTERRUPT_MASK */ + YH2I_INT = 0x20, + YINT_EN = 0x34, + YI2H_INT = 0x9c, + YI2H_INT_C = 0xa0, + YH2I_REQ = 0xc0, + YH2I_REQ_HI = 0xc4, + /* MU register value */ MU_INBOUND_DOORBELL_HANDSHAKE = 1, MU_INBOUND_DOORBELL_REQHEADCHANGED = 2, @@ -95,34 +102,32 @@ enum { TASK_ATTRIBUTE_ORDERED = 0x2, TASK_ATTRIBUTE_ACA = 0x4, - /* request count, etc. */ - MU_MAX_REQUEST = 32, + SS_STS_NORMAL = 0x80000000, + SS_STS_DONE = 0x40000000, + SS_STS_HANDSHAKE = 0x20000000, - /* one message wasted, use MU_MAX_REQUEST+1 - to handle MU_MAX_REQUEST messages */ - MU_REQ_COUNT = (MU_MAX_REQUEST + 1), - MU_STATUS_COUNT = (MU_MAX_REQUEST + 1), + SS_HEAD_HANDSHAKE = 0x80, - STEX_CDB_LENGTH = MAX_COMMAND_SIZE, - REQ_VARIABLE_LEN = 1024, + STEX_CDB_LENGTH = 16, STATUS_VAR_LEN = 128, - ST_CAN_QUEUE = MU_MAX_REQUEST, - ST_CMD_PER_LUN = MU_MAX_REQUEST, - ST_MAX_SG = 32, /* sg flags */ SG_CF_EOT = 0x80, /* end of table */ SG_CF_64B = 0x40, /* 64 bit item */ SG_CF_HOST = 0x20, /* sg in host memory */ + MSG_DATA_DIR_ND = 0, + MSG_DATA_DIR_IN = 1, + MSG_DATA_DIR_OUT = 2, st_shasta = 0, st_vsc = 1, - st_vsc1 = 2, - st_yosemite = 3, + st_yosemite = 2, + st_seq = 3, + st_yel = 4, PASSTHRU_REQ_TYPE = 0x00000001, PASSTHRU_REQ_NO_WAKEUP = 0x00000100, - ST_INTERNAL_TIMEOUT = 30, + ST_INTERNAL_TIMEOUT = 180, ST_TO_CMD = 0, ST_FROM_CMD = 1, @@ -152,59 +157,40 @@ enum { ST_ADDITIONAL_MEM = 0x200000, }; -/* SCSI inquiry data */ -typedef struct st_inq { - u8 DeviceType :5; - u8 DeviceTypeQualifier :3; - u8 DeviceTypeModifier :7; - u8 RemovableMedia :1; - u8 Versions; - u8 ResponseDataFormat :4; - u8 HiSupport :1; - u8 NormACA :1; - u8 ReservedBit :1; - u8 AERC :1; - u8 AdditionalLength; - u8 Reserved[2]; - u8 SoftReset :1; - u8 CommandQueue :1; - u8 Reserved2 :1; - u8 LinkedCommands :1; - u8 Synchronous :1; - u8 Wide16Bit :1; - u8 Wide32Bit :1; - u8 RelativeAddressing :1; - u8 VendorId[8]; - u8 ProductId[16]; - u8 ProductRevisionLevel[4]; - u8 VendorSpecific[20]; - u8 Reserved3[40]; -} ST_INQ; - struct st_sgitem { u8 ctrl; /* SG_CF_xxx */ u8 reserved[3]; __le32 count; + __le64 addr; +}; + +struct st_ss_sgitem { __le32 addr; __le32 addr_hi; + __le32 count; }; struct st_sgtable { __le16 sg_count; __le16 max_sg_count; __le32 sz_in_byte; - struct st_sgitem table[ST_MAX_SG]; +}; + +struct st_msg_header { + __le64 handle; + u8 flag; + u8 channel; + __le16 timeout; + u32 reserved; }; struct handshake_frame { - __le32 rb_phy; /* request payload queue physical address */ - __le32 rb_phy_hi; + __le64 rb_phy; /* request payload queue physical address */ __le16 req_sz; /* size of each request payload */ __le16 req_cnt; /* count of reqs the buffer can hold */ __le16 status_sz; /* size of each status payload */ __le16 status_cnt; /* count of status the buffer can hold */ - __le32 hosttime; /* seconds from Jan 1, 1970 (GMT) */ - __le32 hosttime_hi; + __le64 hosttime; /* seconds from Jan 1, 1970 (GMT) */ u8 partner_type; /* who sends this frame */ u8 reserved0[7]; __le32 partner_ver_major; @@ -213,7 +199,8 @@ struct handshake_frame { __le32 partner_ver_build; __le32 extra_offset; /* NEW */ __le32 extra_size; /* NEW */ - u32 reserved1[2]; + __le32 scratch_size; + u32 reserved1; }; struct req_msg { @@ -222,10 +209,10 @@ struct req_msg { u8 target; u8 task_attr; u8 task_manage; - u8 prd_entry; + u8 data_dir; u8 payload_sz; /* payload size in 4-byte, not used */ u8 cdb[STEX_CDB_LENGTH]; - u8 variable[REQ_VARIABLE_LEN]; + u32 variable[0]; }; struct status_msg { @@ -281,12 +268,6 @@ struct st_drvver { u32 reserved[3]; }; -#define MU_REQ_BUFFER_SIZE (MU_REQ_COUNT * sizeof(struct req_msg)) -#define MU_STATUS_BUFFER_SIZE (MU_STATUS_COUNT * sizeof(struct status_msg)) -#define MU_BUFFER_SIZE (MU_REQ_BUFFER_SIZE + MU_STATUS_BUFFER_SIZE) -#define STEX_EXTRA_SIZE max(sizeof(struct st_frame), sizeof(ST_INQ)) -#define STEX_BUFFER_SIZE (MU_BUFFER_SIZE + STEX_EXTRA_SIZE) - struct st_ccb { struct req_msg *req; struct scsi_cmnd *cmd; @@ -298,6 +279,7 @@ struct st_ccb { u32 req_type; u8 srb_status; u8 scsi_status; + u8 reserved[2]; }; struct st_hba { @@ -309,6 +291,10 @@ struct st_hba { struct Scsi_Host *host; struct pci_dev *pdev; + struct req_msg * (*alloc_rq) (struct st_hba *); + int (*map_sg)(struct st_hba *, struct req_msg *, struct st_ccb *); + void (*send) (struct st_hba *, struct req_msg *, u16); + u32 req_head; u32 req_tail; u32 status_head; @@ -316,16 +302,36 @@ struct st_hba { struct status_msg *status_buffer; void *copy_buffer; /* temp buffer for driver-handled commands */ - struct st_ccb ccb[MU_MAX_REQUEST]; + struct st_ccb *ccb; struct st_ccb *wait_ccb; - wait_queue_head_t waitq; + __le32 *scratch; unsigned int mu_status; + unsigned int cardtype; + int msi_enabled; int out_req_cnt; + u32 extra_offset; + u16 rq_count; + u16 rq_size; + u16 sts_count; +}; - unsigned int cardtype; +struct st_card_info { + struct req_msg * (*alloc_rq) (struct st_hba *); + int (*map_sg)(struct st_hba *, struct req_msg *, struct st_ccb *); + void (*send) (struct st_hba *, struct req_msg *, u16); + unsigned int max_id; + unsigned int max_lun; + unsigned int max_channel; + u16 rq_count; + u16 rq_size; + u16 sts_count; }; +static int msi; +module_param(msi, int, 0); +MODULE_PARM_DESC(msi, "Enable Message Signaled Interrupts(0=off, 1=on)"); + static const char console_inq_page[] = { 0x03,0x00,0x03,0x03,0xFA,0x00,0x00,0x30, @@ -343,22 +349,20 @@ MODULE_DESCRIPTION("Promise Technology SuperTrak EX Controllers"); MODULE_LICENSE("GPL"); MODULE_VERSION(ST_DRIVER_VERSION); -static void stex_gettime(__le32 *time) +static void stex_gettime(__le64 *time) { struct timeval tv; - do_gettimeofday(&tv); - *time = cpu_to_le32(tv.tv_sec & 0xffffffff); - *(time + 1) = cpu_to_le32((tv.tv_sec >> 16) >> 16); + do_gettimeofday(&tv); + *time = cpu_to_le64(tv.tv_sec); } static struct status_msg *stex_get_status(struct st_hba *hba) { - struct status_msg *status = - hba->status_buffer + hba->status_tail; + struct status_msg *status = hba->status_buffer + hba->status_tail; ++hba->status_tail; - hba->status_tail %= MU_STATUS_COUNT; + hba->status_tail %= hba->sts_count+1; return status; } @@ -368,7 +372,7 @@ static void stex_invalid_field(struct scsi_cmnd *cmd, { cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; - /* "Invalid field in cbd" */ + /* "Invalid field in cdb" */ scsi_build_sense_buffer(0, cmd->sense_buffer, ILLEGAL_REQUEST, 0x24, 0x0); done(cmd); @@ -376,47 +380,83 @@ static void stex_invalid_field(struct scsi_cmnd *cmd, static struct req_msg *stex_alloc_req(struct st_hba *hba) { - struct req_msg *req = ((struct req_msg *)hba->dma_mem) + - hba->req_head; + struct req_msg *req = hba->dma_mem + hba->req_head * hba->rq_size; ++hba->req_head; - hba->req_head %= MU_REQ_COUNT; + hba->req_head %= hba->rq_count+1; return req; } +static struct req_msg *stex_ss_alloc_req(struct st_hba *hba) +{ + return (struct req_msg *)(hba->dma_mem + + hba->req_head * hba->rq_size + sizeof(struct st_msg_header)); +} + static int stex_map_sg(struct st_hba *hba, struct req_msg *req, struct st_ccb *ccb) { struct scsi_cmnd *cmd; struct scatterlist *sg; struct st_sgtable *dst; + struct st_sgitem *table; int i, nseg; cmd = ccb->cmd; - dst = (struct st_sgtable *)req->variable; - dst->max_sg_count = cpu_to_le16(ST_MAX_SG); - dst->sz_in_byte = cpu_to_le32(scsi_bufflen(cmd)); + nseg = scsi_dma_map(cmd); + BUG_ON(nseg < 0); + if (nseg) { + dst = (struct st_sgtable *)req->variable; + + ccb->sg_count = nseg; + dst->sg_count = cpu_to_le16((u16)nseg); + dst->max_sg_count = cpu_to_le16(hba->host->sg_tablesize); + dst->sz_in_byte = cpu_to_le32(scsi_bufflen(cmd)); + + table = (struct st_sgitem *)(dst + 1); + scsi_for_each_sg(cmd, sg, nseg, i) { + table[i].count = cpu_to_le32((u32)sg_dma_len(sg)); + table[i].addr = cpu_to_le64(sg_dma_address(sg)); + table[i].ctrl = SG_CF_64B | SG_CF_HOST; + } + table[--i].ctrl |= SG_CF_EOT; + } + + return nseg; +} + +static int stex_ss_map_sg(struct st_hba *hba, + struct req_msg *req, struct st_ccb *ccb) +{ + struct scsi_cmnd *cmd; + struct scatterlist *sg; + struct st_sgtable *dst; + struct st_ss_sgitem *table; + int i, nseg; + cmd = ccb->cmd; nseg = scsi_dma_map(cmd); - if (nseg < 0) - return -EIO; + BUG_ON(nseg < 0); if (nseg) { + dst = (struct st_sgtable *)req->variable; + ccb->sg_count = nseg; dst->sg_count = cpu_to_le16((u16)nseg); + dst->max_sg_count = cpu_to_le16(hba->host->sg_tablesize); + dst->sz_in_byte = cpu_to_le32(scsi_bufflen(cmd)); + table = (struct st_ss_sgitem *)(dst + 1); scsi_for_each_sg(cmd, sg, nseg, i) { - dst->table[i].count = cpu_to_le32((u32)sg_dma_len(sg)); - dst->table[i].addr = + table[i].count = cpu_to_le32((u32)sg_dma_len(sg)); + table[i].addr = cpu_to_le32(sg_dma_address(sg) & 0xffffffff); - dst->table[i].addr_hi = + table[i].addr_hi = cpu_to_le32((sg_dma_address(sg) >> 16) >> 16); - dst->table[i].ctrl = SG_CF_64B | SG_CF_HOST; } - dst->table[--i].ctrl |= SG_CF_EOT; } - return 0; + return nseg; } static void stex_controller_info(struct st_hba *hba, struct st_ccb *ccb) @@ -425,7 +465,7 @@ static void stex_controller_info(struct st_hba *hba, struct st_ccb *ccb) size_t count = sizeof(struct st_frame); p = hba->copy_buffer; - count = scsi_sg_copy_to_buffer(ccb->cmd, p, count); + scsi_sg_copy_to_buffer(ccb->cmd, p, count); memset(p->base, 0, sizeof(u32)*6); *(unsigned long *)(p->base) = pci_resource_start(hba->pdev, 0); p->rom_addr = 0; @@ -443,15 +483,13 @@ static void stex_controller_info(struct st_hba *hba, struct st_ccb *ccb) p->subid = hba->pdev->subsystem_vendor << 16 | hba->pdev->subsystem_device; - count = scsi_sg_copy_from_buffer(ccb->cmd, p, count); + scsi_sg_copy_from_buffer(ccb->cmd, p, count); } static void stex_send_cmd(struct st_hba *hba, struct req_msg *req, u16 tag) { req->tag = cpu_to_le16(tag); - req->task_attr = TASK_ATTRIBUTE_SIMPLE; - req->task_manage = 0; /* not supported yet */ hba->ccb[tag].req = req; hba->out_req_cnt++; @@ -461,13 +499,44 @@ stex_send_cmd(struct st_hba *hba, struct req_msg *req, u16 tag) readl(hba->mmio_base + IDBL); /* flush */ } +static void +stex_ss_send_cmd(struct st_hba *hba, struct req_msg *req, u16 tag) +{ + struct scsi_cmnd *cmd; + struct st_msg_header *msg_h; + dma_addr_t addr; + + req->tag = cpu_to_le16(tag); + + hba->ccb[tag].req = req; + hba->out_req_cnt++; + + cmd = hba->ccb[tag].cmd; + msg_h = (struct st_msg_header *)req - 1; + if (likely(cmd)) { + msg_h->channel = (u8)cmd->device->channel; + msg_h->timeout = cpu_to_le16(cmd->request->timeout/HZ); + } + addr = hba->dma_handle + hba->req_head * hba->rq_size; + addr += (hba->ccb[tag].sg_count+4)/11; + msg_h->handle = cpu_to_le64(addr); + + ++hba->req_head; + hba->req_head %= hba->rq_count+1; + + writel((addr >> 16) >> 16, hba->mmio_base + YH2I_REQ_HI); + readl(hba->mmio_base + YH2I_REQ_HI); /* flush */ + writel(addr, hba->mmio_base + YH2I_REQ); + readl(hba->mmio_base + YH2I_REQ); /* flush */ +} + static int stex_slave_alloc(struct scsi_device *sdev) { /* Cheat: usually extracted from Inquiry data */ sdev->tagged_supported = 1; - scsi_activate_tcq(sdev, ST_CMD_PER_LUN); + scsi_activate_tcq(sdev, sdev->host->can_queue); return 0; } @@ -494,9 +563,10 @@ stex_queuecommand(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *)) { struct st_hba *hba; struct Scsi_Host *host; - unsigned int id,lun; + unsigned int id, lun; struct req_msg *req; u16 tag; + host = cmd->device->host; id = cmd->device->id; lun = cmd->device->lun; @@ -508,6 +578,7 @@ stex_queuecommand(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *)) static char ms10_caching_page[12] = { 0, 0x12, 0, 0, 0, 0, 0, 0, 0x8, 0xa, 0x4, 0 }; unsigned char page; + page = cmd->cmnd[2] & 0x3f; if (page == 0x8 || page == 0x3f) { scsi_sg_copy_from_buffer(cmd, ms10_caching_page, @@ -539,7 +610,8 @@ stex_queuecommand(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *)) case INQUIRY: if (id != host->max_id - 1) break; - if (lun == 0 && (cmd->cmnd[1] & INQUIRY_EVPD) == 0) { + if (!lun && !cmd->device->channel && + (cmd->cmnd[1] & INQUIRY_EVPD) == 0) { scsi_sg_copy_from_buffer(cmd, (void *)console_inq_page, sizeof(console_inq_page)); cmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8; @@ -551,6 +623,7 @@ stex_queuecommand(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *)) if (cmd->cmnd[1] == PASSTHRU_GET_DRVVER) { struct st_drvver ver; size_t cp_len = sizeof(ver); + ver.major = ST_VER_MAJOR; ver.minor = ST_VER_MINOR; ver.oem = ST_OEM; @@ -576,7 +649,7 @@ stex_queuecommand(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *)) if (unlikely(tag >= host->can_queue)) return SCSI_MLQUEUE_HOST_BUSY; - req = stex_alloc_req(hba); + req = hba->alloc_rq(hba); req->lun = lun; req->target = id; @@ -584,15 +657,23 @@ stex_queuecommand(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *)) /* cdb */ memcpy(req->cdb, cmd->cmnd, STEX_CDB_LENGTH); + if (cmd->sc_data_direction == DMA_FROM_DEVICE) + req->data_dir = MSG_DATA_DIR_IN; + else if (cmd->sc_data_direction == DMA_TO_DEVICE) + req->data_dir = MSG_DATA_DIR_OUT; + else + req->data_dir = MSG_DATA_DIR_ND; + hba->ccb[tag].cmd = cmd; hba->ccb[tag].sense_bufflen = SCSI_SENSE_BUFFERSIZE; hba->ccb[tag].sense_buffer = cmd->sense_buffer; - hba->ccb[tag].req_type = 0; - if (cmd->sc_data_direction != DMA_NONE) - stex_map_sg(hba, req, &hba->ccb[tag]); + if (!hba->map_sg(hba, req, &hba->ccb[tag])) { + hba->ccb[tag].sg_count = 0; + memset(&req->variable[0], 0, 8); + } - stex_send_cmd(hba, req, tag); + hba->send(hba, req, tag); return 0; } @@ -601,7 +682,7 @@ static void stex_scsi_done(struct st_ccb *ccb) struct scsi_cmnd *cmd = ccb->cmd; int result; - if (ccb->srb_status == SRB_STATUS_SUCCESS || ccb->srb_status == 0) { + if (ccb->srb_status == SRB_STATUS_SUCCESS || ccb->srb_status == 0) { result = ccb->scsi_status; switch (ccb->scsi_status) { case SAM_STAT_GOOD: @@ -641,7 +722,6 @@ static void stex_scsi_done(struct st_ccb *ccb) static void stex_copy_data(struct st_ccb *ccb, struct status_msg *resp, unsigned int variable) { - size_t count = variable; if (resp->scsi_status != SAM_STAT_GOOD) { if (ccb->sense_buffer != NULL) memcpy(ccb->sense_buffer, resp->variable, @@ -651,35 +731,16 @@ static void stex_copy_data(struct st_ccb *ccb, if (ccb->cmd == NULL) return; - count = scsi_sg_copy_from_buffer(ccb->cmd, resp->variable, count); + scsi_sg_copy_from_buffer(ccb->cmd, resp->variable, variable); } -static void stex_ys_commands(struct st_hba *hba, +static void stex_check_cmd(struct st_hba *hba, struct st_ccb *ccb, struct status_msg *resp) { if (ccb->cmd->cmnd[0] == MGT_CMD && - resp->scsi_status != SAM_STAT_CHECK_CONDITION) { + resp->scsi_status != SAM_STAT_CHECK_CONDITION) scsi_set_resid(ccb->cmd, scsi_bufflen(ccb->cmd) - le32_to_cpu(*(__le32 *)&resp->variable[0])); - return; - } - - if (resp->srb_status != 0) - return; - - /* determine inquiry command status by DeviceTypeQualifier */ - if (ccb->cmd->cmnd[0] == INQUIRY && - resp->scsi_status == SAM_STAT_GOOD) { - ST_INQ *inq_data; - - scsi_sg_copy_to_buffer(ccb->cmd, hba->copy_buffer, - STEX_EXTRA_SIZE); - inq_data = (ST_INQ *)hba->copy_buffer; - if (inq_data->DeviceTypeQualifier != 0) - ccb->srb_status = SRB_STATUS_SELECTION_TIMEOUT; - else - ccb->srb_status = SRB_STATUS_SUCCESS; - } } static void stex_mu_intr(struct st_hba *hba, u32 doorbell) @@ -690,12 +751,12 @@ static void stex_mu_intr(struct st_hba *hba, u32 doorbell) unsigned int size; u16 tag; - if (!(doorbell & MU_OUTBOUND_DOORBELL_STATUSHEADCHANGED)) + if (unlikely(!(doorbell & MU_OUTBOUND_DOORBELL_STATUSHEADCHANGED))) return; /* status payloads */ hba->status_head = readl(base + OMR1); - if (unlikely(hba->status_head >= MU_STATUS_COUNT)) { + if (unlikely(hba->status_head > hba->sts_count)) { printk(KERN_WARNING DRV_NAME "(%s): invalid status head\n", pci_name(hba->pdev)); return; @@ -725,13 +786,13 @@ static void stex_mu_intr(struct st_hba *hba, u32 doorbell) continue; } + hba->out_req_cnt--; ccb = &hba->ccb[tag]; - if (hba->wait_ccb == ccb) + if (unlikely(hba->wait_ccb == ccb)) hba->wait_ccb = NULL; if (unlikely(ccb->req == NULL)) { printk(KERN_WARNING DRV_NAME "(%s): lagging req\n", pci_name(hba->pdev)); - hba->out_req_cnt--; continue; } @@ -746,12 +807,13 @@ static void stex_mu_intr(struct st_hba *hba, u32 doorbell) stex_copy_data(ccb, resp, size); } + ccb->req = NULL; ccb->srb_status = resp->srb_status; ccb->scsi_status = resp->scsi_status; if (likely(ccb->cmd != NULL)) { if (hba->cardtype == st_yosemite) - stex_ys_commands(hba, ccb, resp); + stex_check_cmd(hba, ccb, resp); if (unlikely(ccb->cmd->cmnd[0] == PASSTHRU_CMD && ccb->cmd->cmnd[1] == PASSTHRU_GET_ADAPTER)) @@ -759,17 +821,8 @@ static void stex_mu_intr(struct st_hba *hba, u32 doorbell) scsi_dma_unmap(ccb->cmd); stex_scsi_done(ccb); - hba->out_req_cnt--; - } else if (ccb->req_type & PASSTHRU_REQ_TYPE) { - hba->out_req_cnt--; - if (ccb->req_type & PASSTHRU_REQ_NO_WAKEUP) { - ccb->req_type = 0; - continue; - } + } else ccb->req_type = 0; - if (waitqueue_active(&hba->waitq)) - wake_up(&hba->waitq); - } } update_status: @@ -802,7 +855,103 @@ static irqreturn_t stex_intr(int irq, void *__hba) return IRQ_RETVAL(handled); } -static int stex_handshake(struct st_hba *hba) +static void stex_ss_mu_intr(struct st_hba *hba) +{ + struct status_msg *resp; + struct st_ccb *ccb; + __le32 *scratch; + unsigned int size; + int count = 0; + u32 value; + u16 tag; + + if (unlikely(hba->out_req_cnt <= 0 || + hba->mu_status == MU_STATE_RESETTING)) + return; + + while (count < hba->sts_count) { + scratch = hba->scratch + hba->status_tail; + value = le32_to_cpu(*scratch); + if (unlikely(!(value & SS_STS_NORMAL))) + return; + + resp = hba->status_buffer + hba->status_tail; + *scratch = 0; + ++count; + ++hba->status_tail; + hba->status_tail %= hba->sts_count+1; + + tag = (u16)value; + if (unlikely(tag >= hba->host->can_queue)) { + printk(KERN_WARNING DRV_NAME + "(%s): invalid tag\n", pci_name(hba->pdev)); + continue; + } + + hba->out_req_cnt--; + ccb = &hba->ccb[tag]; + if (unlikely(hba->wait_ccb == ccb)) + hba->wait_ccb = NULL; + if (unlikely(ccb->req == NULL)) { + printk(KERN_WARNING DRV_NAME + "(%s): lagging req\n", pci_name(hba->pdev)); + continue; + } + + ccb->req = NULL; + if (likely(value & SS_STS_DONE)) { /* normal case */ + ccb->srb_status = SRB_STATUS_SUCCESS; + ccb->scsi_status = SAM_STAT_GOOD; + } else { + ccb->srb_status = resp->srb_status; + ccb->scsi_status = resp->scsi_status; + size = resp->payload_sz * sizeof(u32); + if (unlikely(size < sizeof(*resp) - STATUS_VAR_LEN || + size > sizeof(*resp))) { + printk(KERN_WARNING DRV_NAME + "(%s): bad status size\n", + pci_name(hba->pdev)); + } else { + size -= sizeof(*resp) - STATUS_VAR_LEN; + if (size) + stex_copy_data(ccb, resp, size); + } + if (likely(ccb->cmd != NULL)) + stex_check_cmd(hba, ccb, resp); + } + + if (likely(ccb->cmd != NULL)) { + scsi_dma_unmap(ccb->cmd); + stex_scsi_done(ccb); + } else + ccb->req_type = 0; + } +} + +static irqreturn_t stex_ss_intr(int irq, void *__hba) +{ + struct st_hba *hba = __hba; + void __iomem *base = hba->mmio_base; + u32 data; + unsigned long flags; + int handled = 0; + + spin_lock_irqsave(hba->host->host_lock, flags); + + data = readl(base + YI2H_INT); + if (data && data != 0xffffffff) { + /* clear the interrupt */ + writel(data, base + YI2H_INT_C); + stex_ss_mu_intr(hba); + handled = 1; + } + + spin_unlock_irqrestore(hba->host->host_lock, flags); + + return IRQ_RETVAL(handled); +} + +static int stex_common_handshake(struct st_hba *hba) { void __iomem *base = hba->mmio_base; struct handshake_frame *h; @@ -831,26 +980,27 @@ static int stex_handshake(struct st_hba *hba) data = readl(base + OMR1); if ((data & 0xffff0000) == MU_HANDSHAKE_SIGNATURE_HALF) { data &= 0x0000ffff; - if (hba->host->can_queue > data) + if (hba->host->can_queue > data) { hba->host->can_queue = data; + hba->host->cmd_per_lun = data; + } } - h = (struct handshake_frame *)(hba->dma_mem + MU_REQ_BUFFER_SIZE); - h->rb_phy = cpu_to_le32(hba->dma_handle); - h->rb_phy_hi = cpu_to_le32((hba->dma_handle >> 16) >> 16); - h->req_sz = cpu_to_le16(sizeof(struct req_msg)); - h->req_cnt = cpu_to_le16(MU_REQ_COUNT); + h = (struct handshake_frame *)hba->status_buffer; + h->rb_phy = cpu_to_le64(hba->dma_handle); + h->req_sz = cpu_to_le16(hba->rq_size); + h->req_cnt = cpu_to_le16(hba->rq_count+1); h->status_sz = cpu_to_le16(sizeof(struct status_msg)); - h->status_cnt = cpu_to_le16(MU_STATUS_COUNT); + h->status_cnt = cpu_to_le16(hba->sts_count+1); stex_gettime(&h->hosttime); h->partner_type = HMU_PARTNER_TYPE; - if (hba->dma_size > STEX_BUFFER_SIZE) { - h->extra_offset = cpu_to_le32(STEX_BUFFER_SIZE); + if (hba->extra_offset) { + h->extra_offset = cpu_to_le32(hba->extra_offset); h->extra_size = cpu_to_le32(ST_ADDITIONAL_MEM); } else h->extra_offset = h->extra_size = 0; - status_phys = hba->dma_handle + MU_REQ_BUFFER_SIZE; + status_phys = hba->dma_handle + (hba->rq_count+1) * hba->rq_size; writel(status_phys, base + IMR0); readl(base + IMR0); writel((status_phys >> 16) >> 16, base + IMR1); @@ -882,10 +1032,79 @@ static int stex_handshake(struct st_hba *hba) readl(base + IMR1); writel(0, base + OMR1); readl(base + OMR1); /* flush */ - hba->mu_status = MU_STATE_STARTED; return 0; } +static int stex_ss_handshake(struct st_hba *hba) +{ + void __iomem *base = hba->mmio_base; + struct st_msg_header *msg_h; + struct handshake_frame *h; + __le32 *scratch = hba->scratch; + u32 data; + unsigned long before; + int ret = 0; + + h = (struct handshake_frame *)(hba->alloc_rq(hba)); + msg_h = (struct st_msg_header *)h - 1; + msg_h->handle = cpu_to_le64(hba->dma_handle); + msg_h->flag = SS_HEAD_HANDSHAKE; + + h->rb_phy = cpu_to_le64(hba->dma_handle); + h->req_sz = cpu_to_le16(hba->rq_size); + h->req_cnt = cpu_to_le16(hba->rq_count+1); + h->status_sz = cpu_to_le16(sizeof(struct status_msg)); + h->status_cnt = cpu_to_le16(hba->sts_count+1); + stex_gettime(&h->hosttime); + h->partner_type = HMU_PARTNER_TYPE; + h->extra_offset = h->extra_size = 0; + h->scratch_size = cpu_to_le32((hba->sts_count+1)*sizeof(u32)); + + data = readl(base + YINT_EN); + data &= ~4; + writel(data, base + YINT_EN); + writel((hba->dma_handle >> 16) >> 16, base + YH2I_REQ_HI); + writel(hba->dma_handle, base + YH2I_REQ); + + scratch = hba->scratch; + before = jiffies; + while (!(le32_to_cpu(*scratch) & SS_STS_HANDSHAKE)) { + if (time_after(jiffies, before + MU_MAX_DELAY * HZ)) { + printk(KERN_ERR DRV_NAME + "(%s): no signature after handshake frame\n", + pci_name(hba->pdev)); + ret = -1; + break; + } + rmb(); + msleep(1); + } + + *scratch = 0; + msg_h->flag = 0; + return ret; +} + +static int stex_handshake(struct st_hba *hba) +{ + int err; + unsigned long flags; + + err = (hba->cardtype == st_yel) ? + stex_ss_handshake(hba) : stex_common_handshake(hba); + if (err == 0) { + spin_lock_irqsave(hba->host->host_lock, flags); + hba->req_head = 0; + hba->req_tail = 0; + hba->status_head = 0; + hba->status_tail = 0; + hba->out_req_cnt = 0; + hba->mu_status = MU_STATE_STARTED; + spin_unlock_irqrestore(hba->host->host_lock, flags); + } + return err; +} + static int stex_abort(struct scsi_cmnd *cmd) { struct Scsi_Host *host = cmd->device->host; @@ -914,15 +1133,23 @@ static int stex_abort(struct scsi_cmnd *cmd) goto out; } - data = readl(base + ODBL); - if (data == 0 || data == 0xffffffff) - goto fail_out; + if (hba->cardtype == st_yel) { + data = readl(base + YI2H_INT); + if (data == 0 || data == 0xffffffff) + goto fail_out; - writel(data, base + ODBL); - readl(base + ODBL); /* flush */ + writel(data, base + YI2H_INT_C); + stex_ss_mu_intr(hba); + } else { + data = readl(base + ODBL); + if (data == 0 || data == 0xffffffff) + goto fail_out; - stex_mu_intr(hba, data); + writel(data, base + ODBL); + readl(base + ODBL); /* flush */ + stex_mu_intr(hba, data); + } if (hba->wait_ccb == NULL) { printk(KERN_WARNING DRV_NAME "(%s): lost interrupt\n", pci_name(hba->pdev)); @@ -981,8 +1208,9 @@ static void stex_hard_reset(struct st_hba *hba) static int stex_reset(struct scsi_cmnd *cmd) { struct st_hba *hba; - unsigned long flags; - unsigned long before; + void __iomem *base; + unsigned long flags, before; + hba = (struct st_hba *) &cmd->device->host->hostdata[0]; printk(KERN_INFO DRV_NAME @@ -1001,13 +1229,6 @@ static int stex_reset(struct scsi_cmnd *cmd) pci_name(hba->pdev)); return FAILED; } - spin_lock_irqsave(hba->host->host_lock, flags); - hba->req_head = 0; - hba->req_tail = 0; - hba->status_head = 0; - hba->status_tail = 0; - hba->out_req_cnt = 0; - spin_unlock_irqrestore(hba->host->host_lock, flags); return SUCCESS; } @@ -1024,7 +1245,23 @@ static int stex_reset(struct scsi_cmnd *cmd) msleep(1); } + base = hba->mmio_base; + writel(0, base + IMR0); + readl(base + IMR0); + writel(0, base + OMR0); + readl(base + OMR0); + writel(0, base + IMR1); + readl(base + IMR1); + writel(0, base + OMR1); + readl(base + OMR1); /* flush */ + spin_lock_irqsave(hba->host->host_lock, flags); + hba->req_head = 0; + hba->req_tail = 0; + hba->status_head = 0; + hba->status_tail = 0; + hba->out_req_cnt = 0; hba->mu_status = MU_STATE_STARTED; + spin_unlock_irqrestore(hba->host->host_lock, flags); return SUCCESS; } @@ -1058,15 +1295,106 @@ static struct scsi_host_template driver_template = { .slave_destroy = stex_slave_destroy, .eh_abort_handler = stex_abort, .eh_host_reset_handler = stex_reset, - .can_queue = ST_CAN_QUEUE, .this_id = -1, - .sg_tablesize = ST_MAX_SG, - .cmd_per_lun = ST_CMD_PER_LUN, +}; + +static struct pci_device_id stex_pci_tbl[] = { + /* st_shasta */ + { 0x105a, 0x8350, PCI_ANY_ID, PCI_ANY_ID, 0, 0, + st_shasta }, /* SuperTrak EX8350/8300/16350/16300 */ + { 0x105a, 0xc350, PCI_ANY_ID, PCI_ANY_ID, 0, 0, + st_shasta }, /* SuperTrak EX12350 */ + { 0x105a, 0x4302, PCI_ANY_ID, PCI_ANY_ID, 0, 0, + st_shasta }, /* SuperTrak EX4350 */ + { 0x105a, 0xe350, PCI_ANY_ID, PCI_ANY_ID, 0, 0, + st_shasta }, /* SuperTrak EX24350 */ + + /* st_vsc */ + { 0x105a, 0x7250, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_vsc }, + + /* st_yosemite */ + { 0x105a, 0x8650, 0x105a, PCI_ANY_ID, 0, 0, st_yosemite }, + + /* st_seq */ + { 0x105a, 0x3360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_seq }, + + /* st_yel */ + { 0x105a, 0x8650, 0x1033, PCI_ANY_ID, 0, 0, st_yel }, + { 0x105a, 0x8760, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_yel }, + { } /* terminate list */ +}; + +static struct st_card_info stex_card_info[] = { + /* st_shasta */ + { + .max_id = 17, + .max_lun = 8, + .max_channel = 0, + .rq_count = 32, + .rq_size = 1048, + .sts_count = 32, + .alloc_rq = stex_alloc_req, + .map_sg = stex_map_sg, + .send = stex_send_cmd, + }, + + /* st_vsc */ + { + .max_id = 129, + .max_lun = 1, + .max_channel = 0, + .rq_count = 32, + .rq_size = 1048, + .sts_count = 32, + .alloc_rq = stex_alloc_req, + .map_sg = stex_map_sg, + .send = stex_send_cmd, + }, + + /* st_yosemite */ + { + .max_id = 2, + .max_lun = 256, + .max_channel = 0, + .rq_count = 256, + .rq_size = 1048, + .sts_count = 256, + .alloc_rq = stex_alloc_req, + .map_sg = stex_map_sg, + .send = stex_send_cmd, + }, + + /* st_seq */ + { + .max_id = 129, + .max_lun = 1, + .max_channel = 0, + .rq_count = 32, + .rq_size = 1048, + .sts_count = 32, + .alloc_rq = stex_alloc_req, + .map_sg = stex_map_sg, + .send = stex_send_cmd, + }, + + /* st_yel */ + { + .max_id = 129, + .max_lun = 256, + .max_channel = 3, + .rq_count = 801, + .rq_size = 512, + .sts_count = 801, + .alloc_rq = stex_ss_alloc_req, + .map_sg = stex_ss_map_sg, + .send = stex_ss_send_cmd, + }, }; static int stex_set_dma_mask(struct pci_dev * pdev) { int ret; + if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK) && !pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) return 0; @@ -1076,11 +1404,48 @@ static int stex_set_dma_mask(struct pci_dev * pdev) return ret; } +static int stex_request_irq(struct st_hba *hba) +{ + struct pci_dev *pdev = hba->pdev; + int status; + + if (msi) { + status = pci_enable_msi(pdev); + if (status != 0) + printk(KERN_ERR DRV_NAME + "(%s): error %d setting up MSI\n", + pci_name(pdev), status); + else + hba->msi_enabled = 1; + } else + hba->msi_enabled = 0; + + status = request_irq(pdev->irq, hba->cardtype == st_yel ? + stex_ss_intr : stex_intr, IRQF_SHARED, DRV_NAME, hba); + + if (status != 0) { + if (hba->msi_enabled) + pci_disable_msi(pdev); + } + return status; +} + +static void stex_free_irq(struct st_hba *hba) +{ + struct pci_dev *pdev = hba->pdev; + + free_irq(pdev->irq, hba); + if (hba->msi_enabled) + pci_disable_msi(pdev); +} + static int __devinit stex_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct st_hba *hba; struct Scsi_Host *host; + const struct st_card_info *ci = NULL; + u32 sts_offset, cp_offset, scratch_offset; int err; err = pci_enable_device(pdev); @@ -1124,10 +1489,17 @@ stex_probe(struct pci_dev *pdev, const struct pci_device_id *id) } hba->cardtype = (unsigned int) id->driver_data; - if (hba->cardtype == st_vsc && (pdev->subsystem_device & 0xf) == 0x1) - hba->cardtype = st_vsc1; - hba->dma_size = (hba->cardtype == st_vsc1) ? - (STEX_BUFFER_SIZE + ST_ADDITIONAL_MEM) : (STEX_BUFFER_SIZE); + ci = &stex_card_info[hba->cardtype]; + sts_offset = scratch_offset = (ci->rq_count+1) * ci->rq_size; + if (hba->cardtype == st_yel) + sts_offset += (ci->sts_count+1) * sizeof(u32); + cp_offset = sts_offset + (ci->sts_count+1) * sizeof(struct status_msg); + hba->dma_size = cp_offset + sizeof(struct st_frame); + if (hba->cardtype == st_seq || + (hba->cardtype == st_vsc && (pdev->subsystem_device & 1))) { + hba->extra_offset = hba->dma_size; + hba->dma_size += ST_ADDITIONAL_MEM; + } hba->dma_mem = dma_alloc_coherent(&pdev->dev, hba->dma_size, &hba->dma_handle, GFP_KERNEL); if (!hba->dma_mem) { @@ -1137,35 +1509,46 @@ stex_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto out_iounmap; } - hba->status_buffer = - (struct status_msg *)(hba->dma_mem + MU_REQ_BUFFER_SIZE); - hba->copy_buffer = hba->dma_mem + MU_BUFFER_SIZE; + hba->ccb = kcalloc(ci->rq_count, sizeof(struct st_ccb), GFP_KERNEL); + if (!hba->ccb) { + err = -ENOMEM; + printk(KERN_ERR DRV_NAME "(%s): ccb alloc failed\n", + pci_name(pdev)); + goto out_pci_free; + } + + if (hba->cardtype == st_yel) + hba->scratch = (__le32 *)(hba->dma_mem + scratch_offset); + hba->status_buffer = (struct status_msg *)(hba->dma_mem + sts_offset); + hba->copy_buffer = hba->dma_mem + cp_offset; + hba->rq_count = ci->rq_count; + hba->rq_size = ci->rq_size; + hba->sts_count = ci->sts_count; + hba->alloc_rq = ci->alloc_rq; + hba->map_sg = ci->map_sg; + hba->send = ci->send; hba->mu_status = MU_STATE_STARTING; - if (hba->cardtype == st_shasta) { - host->max_lun = 8; - host->max_id = 16 + 1; - } else if (hba->cardtype == st_yosemite) { - host->max_lun = 128; - host->max_id = 1 + 1; - } else { - /* st_vsc and st_vsc1 */ - host->max_lun = 1; - host->max_id = 128 + 1; - } - host->max_channel = 0; + if (hba->cardtype == st_yel) + host->sg_tablesize = 38; + else + host->sg_tablesize = 32; + host->can_queue = ci->rq_count; + host->cmd_per_lun = ci->rq_count; + host->max_id = ci->max_id; + host->max_lun = ci->max_lun; + host->max_channel = ci->max_channel; host->unique_id = host->host_no; host->max_cmd_len = STEX_CDB_LENGTH; hba->host = host; hba->pdev = pdev; - init_waitqueue_head(&hba->waitq); - err = request_irq(pdev->irq, stex_intr, IRQF_SHARED, DRV_NAME, hba); + err = stex_request_irq(hba); if (err) { printk(KERN_ERR DRV_NAME "(%s): request irq failed\n", pci_name(pdev)); - goto out_pci_free; + goto out_ccb_free; } err = stex_handshake(hba); @@ -1193,7 +1576,9 @@ stex_probe(struct pci_dev *pdev, const struct pci_device_id *id) return 0; out_free_irq: - free_irq(pdev->irq, hba); + stex_free_irq(hba); +out_ccb_free: + kfree(hba->ccb); out_pci_free: dma_free_coherent(&pdev->dev, hba->dma_size, hba->dma_mem, hba->dma_handle); @@ -1212,15 +1597,20 @@ out_disable: static void stex_hba_stop(struct st_hba *hba) { struct req_msg *req; + struct st_msg_header *msg_h; unsigned long flags; unsigned long before; u16 tag = 0; spin_lock_irqsave(hba->host->host_lock, flags); - req = stex_alloc_req(hba); - memset(req->cdb, 0, STEX_CDB_LENGTH); + req = hba->alloc_rq(hba); + if (hba->cardtype == st_yel) { + msg_h = (struct st_msg_header *)req - 1; + memset(msg_h, 0, hba->rq_size); + } else + memset(req, 0, hba->rq_size); - if (hba->cardtype == st_yosemite) { + if (hba->cardtype == st_yosemite || hba->cardtype == st_yel) { req->cdb[0] = MGT_CMD; req->cdb[1] = MGT_CMD_SIGNATURE; req->cdb[2] = CTLR_CONFIG_CMD; @@ -1235,27 +1625,31 @@ static void stex_hba_stop(struct st_hba *hba) hba->ccb[tag].sg_count = 0; hba->ccb[tag].sense_bufflen = 0; hba->ccb[tag].sense_buffer = NULL; - hba->ccb[tag].req_type |= PASSTHRU_REQ_TYPE; + hba->ccb[tag].req_type = PASSTHRU_REQ_TYPE; - stex_send_cmd(hba, req, tag); + hba->send(hba, req, tag); spin_unlock_irqrestore(hba->host->host_lock, flags); before = jiffies; while (hba->ccb[tag].req_type & PASSTHRU_REQ_TYPE) { - if (time_after(jiffies, before + ST_INTERNAL_TIMEOUT * HZ)) + if (time_after(jiffies, before + ST_INTERNAL_TIMEOUT * HZ)) { + hba->ccb[tag].req_type = 0; return; - msleep(10); + } + msleep(1); } } static void stex_hba_free(struct st_hba *hba) { - free_irq(hba->pdev->irq, hba); + stex_free_irq(hba); iounmap(hba->mmio_base); pci_release_regions(hba->pdev); + kfree(hba->ccb); + dma_free_coherent(&hba->pdev->dev, hba->dma_size, hba->dma_mem, hba->dma_handle); } @@ -1284,35 +1678,6 @@ static void stex_shutdown(struct pci_dev *pdev) stex_hba_stop(hba); } -static struct pci_device_id stex_pci_tbl[] = { - /* st_shasta */ - { 0x105a, 0x8350, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - st_shasta }, /* SuperTrak EX8350/8300/16350/16300 */ - { 0x105a, 0xc350, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - st_shasta }, /* SuperTrak EX12350 */ - { 0x105a, 0x4302, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - st_shasta }, /* SuperTrak EX4350 */ - { 0x105a, 0xe350, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - st_shasta }, /* SuperTrak EX24350 */ - - /* st_vsc */ - { 0x105a, 0x7250, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_vsc }, - - /* st_yosemite */ - { 0x105a, 0x8650, PCI_ANY_ID, 0x4600, 0, 0, - st_yosemite }, /* SuperTrak EX4650 */ - { 0x105a, 0x8650, PCI_ANY_ID, 0x4610, 0, 0, - st_yosemite }, /* SuperTrak EX4650o */ - { 0x105a, 0x8650, PCI_ANY_ID, 0x8600, 0, 0, - st_yosemite }, /* SuperTrak EX8650EL */ - { 0x105a, 0x8650, PCI_ANY_ID, 0x8601, 0, 0, - st_yosemite }, /* SuperTrak EX8650 */ - { 0x105a, 0x8650, PCI_ANY_ID, 0x8602, 0, 0, - st_yosemite }, /* SuperTrak EX8654 */ - { 0x105a, 0x8650, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - st_yosemite }, /* generic st_yosemite */ - { } /* terminate list */ -}; MODULE_DEVICE_TABLE(pci, stex_pci_tbl); static struct pci_driver stex_pci_driver = { diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c index f4e6cde1fd0..23e78201588 100644 --- a/drivers/scsi/sym53c8xx_2/sym_glue.c +++ b/drivers/scsi/sym53c8xx_2/sym_glue.c @@ -792,9 +792,9 @@ static int sym53c8xx_slave_configure(struct scsi_device *sdev) /* * Select queue depth from driver setup. - * Donnot use more than configured by user. - * Use at least 2. - * Donnot use more than our maximum. + * Do not use more than configured by user. + * Use at least 1. + * Do not use more than our maximum. */ reqtags = sym_driver_setup.max_tag; if (reqtags > tp->usrtags) @@ -803,7 +803,7 @@ static int sym53c8xx_slave_configure(struct scsi_device *sdev) reqtags = 0; if (reqtags > SYM_CONF_MAX_TAG) reqtags = SYM_CONF_MAX_TAG; - depth_to_use = reqtags ? reqtags : 2; + depth_to_use = reqtags ? reqtags : 1; scsi_adjust_queue_depth(sdev, sdev->tagged_supported ? MSG_SIMPLE_TAG : 0, depth_to_use); @@ -1236,14 +1236,29 @@ static int sym53c8xx_proc_info(struct Scsi_Host *shost, char *buffer, #endif /* SYM_LINUX_PROC_INFO_SUPPORT */ /* + * Free resources claimed by sym_iomap_device(). Note that + * sym_free_resources() should be used instead of this function after calling + * sym_attach(). + */ +static void __devinit +sym_iounmap_device(struct sym_device *device) +{ + if (device->s.ioaddr) + pci_iounmap(device->pdev, device->s.ioaddr); + if (device->s.ramaddr) + pci_iounmap(device->pdev, device->s.ramaddr); +} + +/* * Free controller resources. */ -static void sym_free_resources(struct sym_hcb *np, struct pci_dev *pdev) +static void sym_free_resources(struct sym_hcb *np, struct pci_dev *pdev, + int do_free_irq) { /* * Free O/S specific resources. */ - if (pdev->irq) + if (do_free_irq) free_irq(pdev->irq, np->s.host); if (np->s.ioaddr) pci_iounmap(pdev, np->s.ioaddr); @@ -1271,10 +1286,11 @@ static struct Scsi_Host * __devinit sym_attach(struct scsi_host_template *tpnt, { struct sym_data *sym_data; struct sym_hcb *np = NULL; - struct Scsi_Host *shost; + struct Scsi_Host *shost = NULL; struct pci_dev *pdev = dev->pdev; unsigned long flags; struct sym_fw *fw; + int do_free_irq = 0; printk(KERN_INFO "sym%d: <%s> rev 0x%x at pci %s irq %u\n", unit, dev->chip.name, pdev->revision, pci_name(pdev), @@ -1285,11 +1301,11 @@ static struct Scsi_Host * __devinit sym_attach(struct scsi_host_template *tpnt, */ fw = sym_find_firmware(&dev->chip); if (!fw) - return NULL; + goto attach_failed; shost = scsi_host_alloc(tpnt, sizeof(*sym_data)); if (!shost) - return NULL; + goto attach_failed; sym_data = shost_priv(shost); /* @@ -1319,6 +1335,10 @@ static struct Scsi_Host * __devinit sym_attach(struct scsi_host_template *tpnt, np->maxoffs = dev->chip.offset_max; np->maxburst = dev->chip.burst_max; np->myaddr = dev->host_id; + np->mmio_ba = (u32)dev->mmio_base; + np->ram_ba = (u32)dev->ram_base; + np->s.ioaddr = dev->s.ioaddr; + np->s.ramaddr = dev->s.ramaddr; /* * Edit its name. @@ -1334,22 +1354,6 @@ static struct Scsi_Host * __devinit sym_attach(struct scsi_host_template *tpnt, goto attach_failed; } - /* - * Try to map the controller chip to - * virtual and physical memory. - */ - np->mmio_ba = (u32)dev->mmio_base; - np->s.ioaddr = dev->s.ioaddr; - np->s.ramaddr = dev->s.ramaddr; - - /* - * Map on-chip RAM if present and supported. - */ - if (!(np->features & FE_RAM)) - dev->ram_base = 0; - if (dev->ram_base) - np->ram_ba = (u32)dev->ram_base; - if (sym_hcb_attach(shost, fw, dev->nvram)) goto attach_failed; @@ -1364,6 +1368,7 @@ static struct Scsi_Host * __devinit sym_attach(struct scsi_host_template *tpnt, sym_name(np), pdev->irq); goto attach_failed; } + do_free_irq = 1; /* * After SCSI devices have been opened, we cannot @@ -1416,12 +1421,13 @@ static struct Scsi_Host * __devinit sym_attach(struct scsi_host_template *tpnt, "TERMINATION, DEVICE POWER etc.!\n", sym_name(np)); spin_unlock_irqrestore(shost->host_lock, flags); attach_failed: - if (!shost) - return NULL; - printf_info("%s: giving up ...\n", sym_name(np)); + printf_info("sym%d: giving up ...\n", unit); if (np) - sym_free_resources(np, pdev); - scsi_host_put(shost); + sym_free_resources(np, pdev, do_free_irq); + else + sym_iounmap_device(dev); + if (shost) + scsi_host_put(shost); return NULL; } @@ -1550,30 +1556,28 @@ static int __devinit sym_set_workarounds(struct sym_device *device) } /* - * Read and check the PCI configuration for any detected NCR - * boards and save data for attaching after all boards have - * been detected. + * Map HBA registers and on-chip SRAM (if present). */ -static void __devinit -sym_init_device(struct pci_dev *pdev, struct sym_device *device) +static int __devinit +sym_iomap_device(struct sym_device *device) { - int i = 2; + struct pci_dev *pdev = device->pdev; struct pci_bus_region bus_addr; - - device->host_id = SYM_SETUP_HOST_ID; - device->pdev = pdev; + int i = 2; pcibios_resource_to_bus(pdev, &bus_addr, &pdev->resource[1]); device->mmio_base = bus_addr.start; - /* - * If the BAR is 64-bit, resource 2 will be occupied by the - * upper 32 bits - */ - if (!pdev->resource[i].flags) - i++; - pcibios_resource_to_bus(pdev, &bus_addr, &pdev->resource[i]); - device->ram_base = bus_addr.start; + if (device->chip.features & FE_RAM) { + /* + * If the BAR is 64-bit, resource 2 will be occupied by the + * upper 32 bits + */ + if (!pdev->resource[i].flags) + i++; + pcibios_resource_to_bus(pdev, &bus_addr, &pdev->resource[i]); + device->ram_base = bus_addr.start; + } #ifdef CONFIG_SCSI_SYM53C8XX_MMIO if (device->mmio_base) @@ -1583,9 +1587,21 @@ sym_init_device(struct pci_dev *pdev, struct sym_device *device) if (!device->s.ioaddr) device->s.ioaddr = pci_iomap(pdev, 0, pci_resource_len(pdev, 0)); - if (device->ram_base) + if (!device->s.ioaddr) { + dev_err(&pdev->dev, "could not map registers; giving up.\n"); + return -EIO; + } + if (device->ram_base) { device->s.ramaddr = pci_iomap(pdev, i, pci_resource_len(pdev, i)); + if (!device->s.ramaddr) { + dev_warn(&pdev->dev, + "could not map SRAM; continuing anyway.\n"); + device->ram_base = 0; + } + } + + return 0; } /* @@ -1659,7 +1675,8 @@ static int sym_detach(struct Scsi_Host *shost, struct pci_dev *pdev) udelay(10); OUTB(np, nc_istat, 0); - sym_free_resources(np, pdev); + sym_free_resources(np, pdev, 1); + scsi_host_put(shost); return 1; } @@ -1696,9 +1713,13 @@ static int __devinit sym2_probe(struct pci_dev *pdev, struct sym_device sym_dev; struct sym_nvram nvram; struct Scsi_Host *shost; + int do_iounmap = 0; + int do_disable_device = 1; memset(&sym_dev, 0, sizeof(sym_dev)); memset(&nvram, 0, sizeof(nvram)); + sym_dev.pdev = pdev; + sym_dev.host_id = SYM_SETUP_HOST_ID; if (pci_enable_device(pdev)) goto leave; @@ -1708,12 +1729,17 @@ static int __devinit sym2_probe(struct pci_dev *pdev, if (pci_request_regions(pdev, NAME53C8XX)) goto disable; - sym_init_device(pdev, &sym_dev); if (sym_check_supported(&sym_dev)) goto free; - if (sym_check_raid(&sym_dev)) - goto leave; /* Don't disable the device */ + if (sym_iomap_device(&sym_dev)) + goto free; + do_iounmap = 1; + + if (sym_check_raid(&sym_dev)) { + do_disable_device = 0; /* Don't disable the device */ + goto free; + } if (sym_set_workarounds(&sym_dev)) goto free; @@ -1722,6 +1748,7 @@ static int __devinit sym2_probe(struct pci_dev *pdev, sym_get_nvram(&sym_dev, &nvram); + do_iounmap = 0; /* Don't sym_iounmap_device() after sym_attach(). */ shost = sym_attach(&sym2_template, attach_count, &sym_dev); if (!shost) goto free; @@ -1737,9 +1764,12 @@ static int __devinit sym2_probe(struct pci_dev *pdev, detach: sym_detach(pci_get_drvdata(pdev), pdev); free: + if (do_iounmap) + sym_iounmap_device(&sym_dev); pci_release_regions(pdev); disable: - pci_disable_device(pdev); + if (do_disable_device) + pci_disable_device(pdev); leave: return -ENODEV; } @@ -1749,7 +1779,6 @@ static void sym2_remove(struct pci_dev *pdev) struct Scsi_Host *shost = pci_get_drvdata(pdev); scsi_remove_host(shost); - scsi_host_put(shost); sym_detach(shost, pdev); pci_release_regions(pdev); pci_disable_device(pdev); diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.h b/drivers/scsi/sym53c8xx_2/sym_glue.h index 567fbe0b4f0..b80bf709f10 100644 --- a/drivers/scsi/sym53c8xx_2/sym_glue.h +++ b/drivers/scsi/sym53c8xx_2/sym_glue.h @@ -234,7 +234,7 @@ static inline struct sym_hcb * sym_get_hcb(struct Scsi_Host *host) /* * Set the status field of a CAM CCB. */ -static __inline void +static inline void sym_set_cam_status(struct scsi_cmnd *cmd, int status) { cmd->result &= ~(0xff << 16); @@ -244,7 +244,7 @@ sym_set_cam_status(struct scsi_cmnd *cmd, int status) /* * Get the status field of a CAM CCB. */ -static __inline int +static inline int sym_get_cam_status(struct scsi_cmnd *cmd) { return host_byte(cmd->result); @@ -253,7 +253,7 @@ sym_get_cam_status(struct scsi_cmnd *cmd) /* * Build CAM result for a successful IO and for a failed IO. */ -static __inline void sym_set_cam_result_ok(struct sym_ccb *cp, struct scsi_cmnd *cmd, int resid) +static inline void sym_set_cam_result_ok(struct sym_ccb *cp, struct scsi_cmnd *cmd, int resid) { scsi_set_resid(cmd, resid); cmd->result = (((DID_OK) << 16) + ((cp->ssss_status) & 0x7f)); diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.c b/drivers/scsi/sym53c8xx_2/sym_hipd.c index 98df1651404..ffa70d1ed18 100644 --- a/drivers/scsi/sym53c8xx_2/sym_hipd.c +++ b/drivers/scsi/sym53c8xx_2/sym_hipd.c @@ -602,7 +602,7 @@ sym_getsync(struct sym_hcb *np, u_char dt, u_char sfac, u_char *divp, u_char *fa /* * Set initial io register bits from burst code. */ -static __inline void sym_init_burst(struct sym_hcb *np, u_char bc) +static inline void sym_init_burst(struct sym_hcb *np, u_char bc) { np->rv_ctest4 &= ~0x80; np->rv_dmode &= ~(0x3 << 6); @@ -1433,13 +1433,12 @@ static int sym_prepare_nego(struct sym_hcb *np, struct sym_ccb *cp, u_char *msgp * Many devices implement PPR in a buggy way, so only use it if we * really want to. */ - if (goal->offset && - (goal->iu || goal->dt || goal->qas || (goal->period < 0xa))) { + if (goal->renego == NS_PPR || (goal->offset && + (goal->iu || goal->dt || goal->qas || (goal->period < 0xa)))) { nego = NS_PPR; - } else if (spi_width(starget) != goal->width) { + } else if (goal->renego == NS_WIDE || goal->width) { nego = NS_WIDE; - } else if (spi_period(starget) != goal->period || - spi_offset(starget) != goal->offset) { + } else if (goal->renego == NS_SYNC || goal->offset) { nego = NS_SYNC; } else { goal->check_nego = 0; @@ -2040,6 +2039,29 @@ static void sym_settrans(struct sym_hcb *np, int target, u_char opts, u_char ofs } } +static void sym_announce_transfer_rate(struct sym_tcb *tp) +{ + struct scsi_target *starget = tp->starget; + + if (tp->tprint.period != spi_period(starget) || + tp->tprint.offset != spi_offset(starget) || + tp->tprint.width != spi_width(starget) || + tp->tprint.iu != spi_iu(starget) || + tp->tprint.dt != spi_dt(starget) || + tp->tprint.qas != spi_qas(starget) || + !tp->tprint.check_nego) { + tp->tprint.period = spi_period(starget); + tp->tprint.offset = spi_offset(starget); + tp->tprint.width = spi_width(starget); + tp->tprint.iu = spi_iu(starget); + tp->tprint.dt = spi_dt(starget); + tp->tprint.qas = spi_qas(starget); + tp->tprint.check_nego = 1; + + spi_display_xfer_agreement(starget); + } +} + /* * We received a WDTR. * Let everything be aware of the changes. @@ -2049,11 +2071,13 @@ static void sym_setwide(struct sym_hcb *np, int target, u_char wide) struct sym_tcb *tp = &np->target[target]; struct scsi_target *starget = tp->starget; - if (spi_width(starget) == wide) - return; - sym_settrans(np, target, 0, 0, 0, wide, 0, 0); + if (wide) + tp->tgoal.renego = NS_WIDE; + else + tp->tgoal.renego = 0; + tp->tgoal.check_nego = 0; tp->tgoal.width = wide; spi_offset(starget) = 0; spi_period(starget) = 0; @@ -2063,7 +2087,7 @@ static void sym_setwide(struct sym_hcb *np, int target, u_char wide) spi_qas(starget) = 0; if (sym_verbose >= 3) - spi_display_xfer_agreement(starget); + sym_announce_transfer_rate(tp); } /* @@ -2080,6 +2104,12 @@ sym_setsync(struct sym_hcb *np, int target, sym_settrans(np, target, 0, ofs, per, wide, div, fak); + if (wide) + tp->tgoal.renego = NS_WIDE; + else if (ofs) + tp->tgoal.renego = NS_SYNC; + else + tp->tgoal.renego = 0; spi_period(starget) = per; spi_offset(starget) = ofs; spi_iu(starget) = spi_dt(starget) = spi_qas(starget) = 0; @@ -2090,7 +2120,7 @@ sym_setsync(struct sym_hcb *np, int target, tp->tgoal.check_nego = 0; } - spi_display_xfer_agreement(starget); + sym_announce_transfer_rate(tp); } /* @@ -2106,6 +2136,10 @@ sym_setpprot(struct sym_hcb *np, int target, u_char opts, u_char ofs, sym_settrans(np, target, opts, ofs, per, wide, div, fak); + if (wide || ofs) + tp->tgoal.renego = NS_PPR; + else + tp->tgoal.renego = 0; spi_width(starget) = tp->tgoal.width = wide; spi_period(starget) = tp->tgoal.period = per; spi_offset(starget) = tp->tgoal.offset = ofs; @@ -2114,7 +2148,7 @@ sym_setpprot(struct sym_hcb *np, int target, u_char opts, u_char ofs, spi_qas(starget) = tp->tgoal.qas = !!(opts & PPR_OPT_QAS); tp->tgoal.check_nego = 0; - spi_display_xfer_agreement(starget); + sym_announce_transfer_rate(tp); } /* @@ -3516,6 +3550,7 @@ static void sym_sir_task_recovery(struct sym_hcb *np, int num) spi_dt(starget) = 0; spi_qas(starget) = 0; tp->tgoal.check_nego = 1; + tp->tgoal.renego = 0; } /* @@ -5135,9 +5170,14 @@ int sym_queue_scsiio(struct sym_hcb *np, struct scsi_cmnd *cmd, struct sym_ccb * /* * Build a negotiation message if needed. * (nego_status is filled by sym_prepare_nego()) + * + * Always negotiate on INQUIRY and REQUEST SENSE. + * */ cp->nego_status = 0; - if (tp->tgoal.check_nego && !tp->nego_cp && lp) { + if ((tp->tgoal.check_nego || + cmd->cmnd[0] == INQUIRY || cmd->cmnd[0] == REQUEST_SENSE) && + !tp->nego_cp && lp) { msglen += sym_prepare_nego(np, cp, msgptr + msglen); } diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.h b/drivers/scsi/sym53c8xx_2/sym_hipd.h index ad078805e62..1588c90518d 100644 --- a/drivers/scsi/sym53c8xx_2/sym_hipd.h +++ b/drivers/scsi/sym53c8xx_2/sym_hipd.h @@ -354,6 +354,7 @@ struct sym_trans { unsigned int dt:1; unsigned int qas:1; unsigned int check_nego:1; + unsigned int renego:2; }; /* @@ -419,6 +420,9 @@ struct sym_tcb { /* Transfer goal */ struct sym_trans tgoal; + /* Last printed transfer speed */ + struct sym_trans tprint; + /* * Keep track of the CCB used for the negotiation in order * to ensure that only 1 negotiation is queued at a time. @@ -1092,7 +1096,7 @@ do { \ #elif SYM_CONF_DMA_ADDRESSING_MODE == 2 #define DMA_DAC_MASK DMA_64BIT_MASK int sym_lookup_dmap(struct sym_hcb *np, u32 h, int s); -static __inline void +static inline void sym_build_sge(struct sym_hcb *np, struct sym_tblmove *data, u64 badd, int len) { u32 h = (badd>>32); @@ -1197,7 +1201,7 @@ dma_addr_t __vtobus(m_pool_ident_t dev_dmat, void *m); #define sym_m_pool_match(mp_id1, mp_id2) (mp_id1 == mp_id2) -static __inline void *sym_m_get_dma_mem_cluster(m_pool_p mp, m_vtob_p vbp) +static inline void *sym_m_get_dma_mem_cluster(m_pool_p mp, m_vtob_p vbp) { void *vaddr = NULL; dma_addr_t baddr = 0; @@ -1211,7 +1215,7 @@ static __inline void *sym_m_get_dma_mem_cluster(m_pool_p mp, m_vtob_p vbp) return vaddr; } -static __inline void sym_m_free_dma_mem_cluster(m_pool_p mp, m_vtob_p vbp) +static inline void sym_m_free_dma_mem_cluster(m_pool_p mp, m_vtob_p vbp) { dma_free_coherent(mp->dev_dmat, SYM_MEM_CLUSTER_SIZE, vbp->vaddr, vbp->baddr); diff --git a/drivers/scsi/sym53c8xx_2/sym_malloc.c b/drivers/scsi/sym53c8xx_2/sym_malloc.c index 92bf9b14a7a..883cac10daf 100644 --- a/drivers/scsi/sym53c8xx_2/sym_malloc.c +++ b/drivers/scsi/sym53c8xx_2/sym_malloc.c @@ -262,7 +262,7 @@ static void ___free_dma_mem_cluster(m_pool_p mp, void *m) #endif /* Fetch the memory pool for a given pool id (i.e. DMA constraints) */ -static __inline m_pool_p ___get_dma_pool(m_pool_ident_t dev_dmat) +static inline m_pool_p ___get_dma_pool(m_pool_ident_t dev_dmat) { m_pool_p mp; for (mp = mp0.next; diff --git a/drivers/scsi/sym53c8xx_2/sym_misc.h b/drivers/scsi/sym53c8xx_2/sym_misc.h index 430537183c1..96c15145902 100644 --- a/drivers/scsi/sym53c8xx_2/sym_misc.h +++ b/drivers/scsi/sym53c8xx_2/sym_misc.h @@ -52,17 +52,17 @@ typedef struct sym_quehead { (ptr)->flink = (ptr); (ptr)->blink = (ptr); \ } while (0) -static __inline struct sym_quehead *sym_que_first(struct sym_quehead *head) +static inline struct sym_quehead *sym_que_first(struct sym_quehead *head) { return (head->flink == head) ? 0 : head->flink; } -static __inline struct sym_quehead *sym_que_last(struct sym_quehead *head) +static inline struct sym_quehead *sym_que_last(struct sym_quehead *head) { return (head->blink == head) ? 0 : head->blink; } -static __inline void __sym_que_add(struct sym_quehead * new, +static inline void __sym_que_add(struct sym_quehead * new, struct sym_quehead * blink, struct sym_quehead * flink) { @@ -72,19 +72,19 @@ static __inline void __sym_que_add(struct sym_quehead * new, blink->flink = new; } -static __inline void __sym_que_del(struct sym_quehead * blink, +static inline void __sym_que_del(struct sym_quehead * blink, struct sym_quehead * flink) { flink->blink = blink; blink->flink = flink; } -static __inline int sym_que_empty(struct sym_quehead *head) +static inline int sym_que_empty(struct sym_quehead *head) { return head->flink == head; } -static __inline void sym_que_splice(struct sym_quehead *list, +static inline void sym_que_splice(struct sym_quehead *list, struct sym_quehead *head) { struct sym_quehead *first = list->flink; @@ -101,7 +101,7 @@ static __inline void sym_que_splice(struct sym_quehead *list, } } -static __inline void sym_que_move(struct sym_quehead *orig, +static inline void sym_que_move(struct sym_quehead *orig, struct sym_quehead *dest) { struct sym_quehead *first, *last; @@ -129,7 +129,7 @@ static __inline void sym_que_move(struct sym_quehead *orig, #define sym_insque_head(new, head) __sym_que_add(new, head, (head)->flink) -static __inline struct sym_quehead *sym_remque_head(struct sym_quehead *head) +static inline struct sym_quehead *sym_remque_head(struct sym_quehead *head) { struct sym_quehead *elem = head->flink; @@ -142,7 +142,7 @@ static __inline struct sym_quehead *sym_remque_head(struct sym_quehead *head) #define sym_insque_tail(new, head) __sym_que_add(new, (head)->blink, head) -static __inline struct sym_quehead *sym_remque_tail(struct sym_quehead *head) +static inline struct sym_quehead *sym_remque_tail(struct sym_quehead *head) { struct sym_quehead *elem = head->blink; diff --git a/drivers/scsi/zalon.c b/drivers/scsi/zalon.c index a8d61a62522..97f3158fa7b 100644 --- a/drivers/scsi/zalon.c +++ b/drivers/scsi/zalon.c @@ -137,7 +137,7 @@ zalon_probe(struct parisc_device *dev) goto fail; if (request_irq(dev->irq, ncr53c8xx_intr, IRQF_SHARED, "zalon", host)) { - dev_printk(KERN_ERR, dev, "irq problem with %d, detaching\n ", + dev_printk(KERN_ERR, &dev->dev, "irq problem with %d, detaching\n ", dev->irq); goto fail; } |