diff options
Diffstat (limited to 'drivers')
509 files changed, 16278 insertions, 42731 deletions
diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c index 06a67d5f2846..296b7a14893a 100644 --- a/drivers/acpi/acpi_platform.c +++ b/drivers/acpi/acpi_platform.c @@ -103,7 +103,12 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev) pdevinfo.res = resources; pdevinfo.num_res = count; pdevinfo.fwnode = acpi_fwnode_handle(adev); - pdevinfo.dma_mask = acpi_check_dma(adev, NULL) ? DMA_BIT_MASK(32) : 0; + + if (acpi_dma_supported(adev)) + pdevinfo.dma_mask = DMA_BIT_MASK(32); + else + pdevinfo.dma_mask = 0; + pdev = platform_device_register_full(&pdevinfo); if (IS_ERR(pdev)) dev_err(&adev->dev, "platform device creation failed: %ld\n", diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c index 5778e8e4313a..3405f7a41e25 100644 --- a/drivers/acpi/acpi_video.c +++ b/drivers/acpi/acpi_video.c @@ -77,6 +77,12 @@ module_param(allow_duplicates, bool, 0644); static int disable_backlight_sysfs_if = -1; module_param(disable_backlight_sysfs_if, int, 0444); +static bool device_id_scheme = false; +module_param(device_id_scheme, bool, 0444); + +static bool only_lcd = false; +module_param(only_lcd, bool, 0444); + static int register_count; static DEFINE_MUTEX(register_count_mutex); static struct mutex video_list_lock; @@ -394,6 +400,18 @@ static int video_disable_backlight_sysfs_if( return 0; } +static int video_set_device_id_scheme(const struct dmi_system_id *d) +{ + device_id_scheme = true; + return 0; +} + +static int video_enable_only_lcd(const struct dmi_system_id *d) +{ + only_lcd = true; + return 0; +} + static struct dmi_system_id video_dmi_table[] = { /* * Broken _BQC workaround http://bugzilla.kernel.org/show_bug.cgi?id=13121 @@ -455,6 +473,33 @@ static struct dmi_system_id video_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE R830"), }, }, + /* + * Some machine's _DOD IDs don't have bit 31(Device ID Scheme) set + * but the IDs actually follow the Device ID Scheme. + */ + { + /* https://bugzilla.kernel.org/show_bug.cgi?id=104121 */ + .callback = video_set_device_id_scheme, + .ident = "ESPRIMO Mobile M9410", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), + DMI_MATCH(DMI_PRODUCT_NAME, "ESPRIMO Mobile M9410"), + }, + }, + /* + * Some machines have multiple video output devices, but only the one + * that is the type of LCD can do the backlight control so we should not + * register backlight interface for other video output devices. + */ + { + /* https://bugzilla.kernel.org/show_bug.cgi?id=104121 */ + .callback = video_enable_only_lcd, + .ident = "ESPRIMO Mobile M9410", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), + DMI_MATCH(DMI_PRODUCT_NAME, "ESPRIMO Mobile M9410"), + }, + }, {} }; @@ -1003,7 +1048,7 @@ acpi_video_bus_get_one_device(struct acpi_device *device, attribute = acpi_video_get_device_attr(video, device_id); - if (attribute && attribute->device_id_scheme) { + if (attribute && (attribute->device_id_scheme || device_id_scheme)) { switch (attribute->display_type) { case ACPI_VIDEO_DISPLAY_CRT: data->flags.crt = 1; @@ -1568,15 +1613,6 @@ static void acpi_video_dev_register_backlight(struct acpi_video_device *device) static int count; char *name; - /* - * Do not create backlight device for video output - * device that is not in the enumerated list. - */ - if (!acpi_video_device_in_dod(device)) { - dev_dbg(&device->dev->dev, "not in _DOD list, ignore\n"); - return; - } - result = acpi_video_init_brightness(device); if (result) return; @@ -1657,6 +1693,22 @@ static void acpi_video_run_bcl_for_osi(struct acpi_video_bus *video) mutex_unlock(&video->device_list_lock); } +static bool acpi_video_should_register_backlight(struct acpi_video_device *dev) +{ + /* + * Do not create backlight device for video output + * device that is not in the enumerated list. + */ + if (!acpi_video_device_in_dod(dev)) { + dev_dbg(&dev->dev->dev, "not in _DOD list, ignore\n"); + return false; + } + + if (only_lcd) + return dev->flags.lcd; + return true; +} + static int acpi_video_bus_register_backlight(struct acpi_video_bus *video) { struct acpi_video_device *dev; @@ -1670,8 +1722,10 @@ static int acpi_video_bus_register_backlight(struct acpi_video_bus *video) return 0; mutex_lock(&video->device_list_lock); - list_for_each_entry(dev, &video->video_device_list, entry) - acpi_video_dev_register_backlight(dev); + list_for_each_entry(dev, &video->video_device_list, entry) { + if (acpi_video_should_register_backlight(dev)) + acpi_video_dev_register_backlight(dev); + } mutex_unlock(&video->device_list_lock); video->backlight_registered = true; diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c index 3c083d2cc434..6730f965b379 100644 --- a/drivers/acpi/cppc_acpi.c +++ b/drivers/acpi/cppc_acpi.c @@ -304,7 +304,7 @@ EXPORT_SYMBOL_GPL(acpi_get_psd_map); static int register_pcc_channel(int pcc_subspace_idx) { - struct acpi_pcct_subspace *cppc_ss; + struct acpi_pcct_hw_reduced *cppc_ss; unsigned int len; if (pcc_subspace_idx >= 0) { diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index f61a7c834540..b420fb46669d 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -1103,7 +1103,7 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 *data) } err_exit: - if (result && q) + if (result) acpi_ec_delete_query(q); if (data) *data = value; diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 1470ae4f98c0..5ea5dc219f56 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -168,7 +168,7 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev) struct list_head *physnode_list; unsigned int node_id; int retval = -EINVAL; - bool coherent; + enum dev_dma_attr attr; if (has_acpi_companion(dev)) { if (acpi_dev) { @@ -225,8 +225,10 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev) if (!has_acpi_companion(dev)) ACPI_COMPANION_SET(dev, acpi_dev); - if (acpi_check_dma(acpi_dev, &coherent)) - arch_setup_dma_ops(dev, 0, 0, NULL, coherent); + attr = acpi_get_dma_attr(acpi_dev); + if (attr != DEV_DMA_NOT_SUPPORTED) + arch_setup_dma_ops(dev, 0, 0, NULL, + attr == DEV_DMA_COHERENT); acpi_physnode_link_name(physical_node_name, node_id); retval = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj, diff --git a/drivers/acpi/sbshc.c b/drivers/acpi/sbshc.c index bf034f8b7c1a..2fa8304171e0 100644 --- a/drivers/acpi/sbshc.c +++ b/drivers/acpi/sbshc.c @@ -14,7 +14,6 @@ #include <linux/delay.h> #include <linux/module.h> #include <linux/interrupt.h> -#include <linux/dmi.h> #include "sbshc.h" #define PREFIX "ACPI: " @@ -30,6 +29,7 @@ struct acpi_smb_hc { u8 query_bit; smbus_alarm_callback callback; void *context; + bool done; }; static int acpi_smbus_hc_add(struct acpi_device *device); @@ -88,8 +88,6 @@ enum acpi_smb_offset { ACPI_SMB_ALARM_DATA = 0x26, /* 2 bytes alarm data */ }; -static bool macbook; - static inline int smb_hc_read(struct acpi_smb_hc *hc, u8 address, u8 *data) { return ec_read(hc->offset + address, data); @@ -100,27 +98,11 @@ static inline int smb_hc_write(struct acpi_smb_hc *hc, u8 address, u8 data) return ec_write(hc->offset + address, data); } -static inline int smb_check_done(struct acpi_smb_hc *hc) -{ - union acpi_smb_status status = {.raw = 0}; - smb_hc_read(hc, ACPI_SMB_STATUS, &status.raw); - return status.fields.done && (status.fields.status == SMBUS_OK); -} - static int wait_transaction_complete(struct acpi_smb_hc *hc, int timeout) { - if (wait_event_timeout(hc->wait, smb_check_done(hc), - msecs_to_jiffies(timeout))) + if (wait_event_timeout(hc->wait, hc->done, msecs_to_jiffies(timeout))) return 0; - /* - * After the timeout happens, OS will try to check the status of SMbus. - * If the status is what OS expected, it will be regarded as the bogus - * timeout. - */ - if (smb_check_done(hc)) - return 0; - else - return -ETIME; + return -ETIME; } static int acpi_smbus_transaction(struct acpi_smb_hc *hc, u8 protocol, @@ -135,8 +117,7 @@ static int acpi_smbus_transaction(struct acpi_smb_hc *hc, u8 protocol, } mutex_lock(&hc->lock); - if (macbook) - udelay(5); + hc->done = false; if (smb_hc_read(hc, ACPI_SMB_PROTOCOL, &temp)) goto end; if (temp) { @@ -235,8 +216,10 @@ static int smbus_alarm(void *context) if (smb_hc_read(hc, ACPI_SMB_STATUS, &status.raw)) return 0; /* Check if it is only a completion notify */ - if (status.fields.done) + if (status.fields.done && status.fields.status == SMBUS_OK) { + hc->done = true; wake_up(&hc->wait); + } if (!status.fields.alarm) return 0; mutex_lock(&hc->lock); @@ -262,29 +245,12 @@ extern int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit, acpi_handle handle, acpi_ec_query_func func, void *data); -static int macbook_dmi_match(const struct dmi_system_id *d) -{ - pr_debug("Detected MacBook, enabling workaround\n"); - macbook = true; - return 0; -} - -static struct dmi_system_id acpi_smbus_dmi_table[] = { - { macbook_dmi_match, "Apple MacBook", { - DMI_MATCH(DMI_BOARD_VENDOR, "Apple"), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBook") }, - }, - { }, -}; - static int acpi_smbus_hc_add(struct acpi_device *device) { int status; unsigned long long val; struct acpi_smb_hc *hc; - dmi_check_system(acpi_smbus_dmi_table); - if (!device) return -EINVAL; diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index daf9fc8329e6..78d5f02a073b 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1308,6 +1308,48 @@ void acpi_free_pnp_ids(struct acpi_device_pnp *pnp) kfree(pnp->unique_id); } +/** + * acpi_dma_supported - Check DMA support for the specified device. + * @adev: The pointer to acpi device + * + * Return false if DMA is not supported. Otherwise, return true + */ +bool acpi_dma_supported(struct acpi_device *adev) +{ + if (!adev) + return false; + + if (adev->flags.cca_seen) + return true; + + /* + * Per ACPI 6.0 sec 6.2.17, assume devices can do cache-coherent + * DMA on "Intel platforms". Presumably that includes all x86 and + * ia64, and other arches will set CONFIG_ACPI_CCA_REQUIRED=y. + */ + if (!IS_ENABLED(CONFIG_ACPI_CCA_REQUIRED)) + return true; + + return false; +} + +/** + * acpi_get_dma_attr - Check the supported DMA attr for the specified device. + * @adev: The pointer to acpi device + * + * Return enum dev_dma_attr. + */ +enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev) +{ + if (!acpi_dma_supported(adev)) + return DEV_DMA_NOT_SUPPORTED; + + if (adev->flags.coherent_dma) + return DEV_DMA_COHERENT; + else + return DEV_DMA_NON_COHERENT; +} + static void acpi_init_coherency(struct acpi_device *adev) { unsigned long long cca = 0; diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 30d8518b25fb..82707f9824ca 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -315,7 +315,7 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) if (crt == -1) { tz->trips.critical.flags.valid = 0; } else if (crt > 0) { - unsigned long crt_k = CELSIUS_TO_KELVIN(crt); + unsigned long crt_k = CELSIUS_TO_DECI_KELVIN(crt); /* * Allow override critical threshold */ @@ -351,7 +351,7 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) if (psv == -1) { status = AE_SUPPORT; } else if (psv > 0) { - tmp = CELSIUS_TO_KELVIN(psv); + tmp = CELSIUS_TO_DECI_KELVIN(psv); status = AE_OK; } else { status = acpi_evaluate_integer(tz->device->handle, @@ -431,7 +431,7 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) break; if (i == 1) tz->trips.active[0].temperature = - CELSIUS_TO_KELVIN(act); + CELSIUS_TO_DECI_KELVIN(act); else /* * Don't allow override higher than @@ -439,9 +439,9 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) */ tz->trips.active[i - 1].temperature = (tz->trips.active[i - 2].temperature < - CELSIUS_TO_KELVIN(act) ? + CELSIUS_TO_DECI_KELVIN(act) ? tz->trips.active[i - 2].temperature : - CELSIUS_TO_KELVIN(act)); + CELSIUS_TO_DECI_KELVIN(act)); break; } else { tz->trips.active[i].temperature = tmp; @@ -1105,7 +1105,7 @@ static int acpi_thermal_add(struct acpi_device *device) INIT_WORK(&tz->thermal_check_work, acpi_thermal_check_fn); pr_info(PREFIX "%s [%s] (%ld C)\n", acpi_device_name(device), - acpi_device_bid(device), KELVIN_TO_CELSIUS(tz->temperature)); + acpi_device_bid(device), DECI_KELVIN_TO_CELSIUS(tz->temperature)); goto end; free_memory: diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index 0d3a384b508a..daaf1c4e1e0f 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -233,6 +233,15 @@ static const struct dmi_system_id video_detect_dmi_table[] = { }, }, { + /* https://bugzilla.redhat.com/show_bug.cgi?id=1272633 */ + .callback = video_detect_force_video, + .ident = "Dell XPS14 L421X", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "XPS L421X"), + }, + }, + { /* https://bugzilla.redhat.com/show_bug.cgi?id=1163574 */ .callback = video_detect_force_video, .ident = "Dell XPS15 L521X", diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 8b3a7861fa44..7e959f90c020 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -3696,9 +3696,6 @@ int ata_scsi_add_hosts(struct ata_host *host, struct scsi_host_template *sht) */ shost->max_host_blocked = 1; - if (scsi_init_shared_tag_map(shost, host->n_tags)) - goto err_add; - rc = scsi_add_host_with_dma(ap->scsi_host, &ap->tdev, ap->host->dev); if (rc) diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 80e298870388..e03b1ad25a90 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -321,8 +321,7 @@ static int genpd_poweroff(struct generic_pm_domain *genpd, bool is_async) if (stat > PM_QOS_FLAGS_NONE) return -EBUSY; - if (pdd->dev->driver && (!pm_runtime_suspended(pdd->dev) - || pdd->dev->power.irq_safe)) + if (!pm_runtime_suspended(pdd->dev) || pdd->dev->power.irq_safe) not_suspended++; } @@ -1312,13 +1311,17 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd, int pm_genpd_add_subdomain(struct generic_pm_domain *genpd, struct generic_pm_domain *subdomain) { - struct gpd_link *link; + struct gpd_link *link, *itr; int ret = 0; if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(subdomain) || genpd == subdomain) return -EINVAL; + link = kzalloc(sizeof(*link), GFP_KERNEL); + if (!link) + return -ENOMEM; + mutex_lock(&genpd->lock); mutex_lock_nested(&subdomain->lock, SINGLE_DEPTH_NESTING); @@ -1328,18 +1331,13 @@ int pm_genpd_add_subdomain(struct generic_pm_domain *genpd, goto out; } - list_for_each_entry(link, &genpd->master_links, master_node) { - if (link->slave == subdomain && link->master == genpd) { + list_for_each_entry(itr, &genpd->master_links, master_node) { + if (itr->slave == subdomain && itr->master == genpd) { ret = -EINVAL; goto out; } } - link = kzalloc(sizeof(*link), GFP_KERNEL); - if (!link) { - ret = -ENOMEM; - goto out; - } link->master = genpd; list_add_tail(&link->master_node, &genpd->master_links); link->slave = subdomain; @@ -1350,7 +1348,8 @@ int pm_genpd_add_subdomain(struct generic_pm_domain *genpd, out: mutex_unlock(&subdomain->lock); mutex_unlock(&genpd->lock); - + if (ret) + kfree(link); return ret; } EXPORT_SYMBOL_GPL(pm_genpd_add_subdomain); diff --git a/drivers/base/power/opp/core.c b/drivers/base/power/opp/core.c index d5c1149ff123..b8e76f75073b 100644 --- a/drivers/base/power/opp/core.c +++ b/drivers/base/power/opp/core.c @@ -11,6 +11,8 @@ * published by the Free Software Foundation. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/errno.h> #include <linux/err.h> #include <linux/slab.h> @@ -27,7 +29,7 @@ */ static LIST_HEAD(dev_opp_list); /* Lock to allow exclusive modification to the device and opp lists */ -static DEFINE_MUTEX(dev_opp_list_lock); +DEFINE_MUTEX(dev_opp_list_lock); #define opp_rcu_lockdep_assert() \ do { \ @@ -79,14 +81,18 @@ static struct device_opp *_managed_opp(const struct device_node *np) * Return: pointer to 'struct device_opp' if found, otherwise -ENODEV or * -EINVAL based on type of error. * - * Locking: This function must be called under rcu_read_lock(). device_opp - * is a RCU protected pointer. This means that device_opp is valid as long - * as we are under RCU lock. + * Locking: For readers, this function must be called under rcu_read_lock(). + * device_opp is a RCU protected pointer, which means that device_opp is valid + * as long as we are under RCU lock. + * + * For Writers, this function must be called with dev_opp_list_lock held. */ struct device_opp *_find_device_opp(struct device *dev) { struct device_opp *dev_opp; + opp_rcu_lockdep_assert(); + if (IS_ERR_OR_NULL(dev)) { pr_err("%s: Invalid parameters\n", __func__); return ERR_PTR(-EINVAL); @@ -100,7 +106,7 @@ struct device_opp *_find_device_opp(struct device *dev) } /** - * dev_pm_opp_get_voltage() - Gets the voltage corresponding to an available opp + * dev_pm_opp_get_voltage() - Gets the voltage corresponding to an opp * @opp: opp for which voltage has to be returned for * * Return: voltage in micro volt corresponding to the opp, else @@ -122,7 +128,7 @@ unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp) opp_rcu_lockdep_assert(); tmp_opp = rcu_dereference(opp); - if (IS_ERR_OR_NULL(tmp_opp) || !tmp_opp->available) + if (IS_ERR_OR_NULL(tmp_opp)) pr_err("%s: Invalid parameters\n", __func__); else v = tmp_opp->u_volt; @@ -701,7 +707,7 @@ static int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, } /** - * _opp_add_dynamic() - Allocate a dynamic OPP. + * _opp_add_v1() - Allocate a OPP based on v1 bindings. * @dev: device for which we do this operation * @freq: Frequency in Hz for this OPP * @u_volt: Voltage in uVolts for this OPP @@ -727,8 +733,8 @@ static int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, * Duplicate OPPs (both freq and volt are same) and !opp->available * -ENOMEM Memory allocation failure */ -static int _opp_add_dynamic(struct device *dev, unsigned long freq, - long u_volt, bool dynamic) +static int _opp_add_v1(struct device *dev, unsigned long freq, long u_volt, + bool dynamic) { struct device_opp *dev_opp; struct dev_pm_opp *new_opp; @@ -770,9 +776,10 @@ unlock: } /* TODO: Support multiple regulators */ -static int opp_get_microvolt(struct dev_pm_opp *opp, struct device *dev) +static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev) { u32 microvolt[3] = {0}; + u32 val; int count, ret; /* Missing property isn't a problem, but an invalid entry is */ @@ -805,6 +812,9 @@ static int opp_get_microvolt(struct dev_pm_opp *opp, struct device *dev) opp->u_volt_min = microvolt[1]; opp->u_volt_max = microvolt[2]; + if (!of_property_read_u32(opp->np, "opp-microamp", &val)) + opp->u_amp = val; + return 0; } @@ -869,13 +879,10 @@ static int _opp_add_static_v2(struct device *dev, struct device_node *np) if (!of_property_read_u32(np, "clock-latency-ns", &val)) new_opp->clock_latency_ns = val; - ret = opp_get_microvolt(new_opp, dev); + ret = opp_parse_supplies(new_opp, dev); if (ret) goto free_opp; - if (!of_property_read_u32(new_opp->np, "opp-microamp", &val)) - new_opp->u_amp = val; - ret = _opp_add(dev, new_opp, dev_opp); if (ret) goto free_opp; @@ -939,7 +946,7 @@ unlock: */ int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt) { - return _opp_add_dynamic(dev, freq, u_volt, true); + return _opp_add_v1(dev, freq, u_volt, true); } EXPORT_SYMBOL_GPL(dev_pm_opp_add); @@ -1172,13 +1179,17 @@ static int _of_add_opp_table_v2(struct device *dev, struct device_node *opp_np) struct device_opp *dev_opp; int ret = 0, count = 0; + mutex_lock(&dev_opp_list_lock); + dev_opp = _managed_opp(opp_np); if (dev_opp) { /* OPPs are already managed */ if (!_add_list_dev(dev, dev_opp)) ret = -ENOMEM; + mutex_unlock(&dev_opp_list_lock); return ret; } + mutex_unlock(&dev_opp_list_lock); /* We have opp-list node now, iterate over it and add OPPs */ for_each_available_child_of_node(opp_np, np) { @@ -1196,15 +1207,20 @@ static int _of_add_opp_table_v2(struct device *dev, struct device_node *opp_np) if (WARN_ON(!count)) return -ENOENT; + mutex_lock(&dev_opp_list_lock); + dev_opp = _find_device_opp(dev); if (WARN_ON(IS_ERR(dev_opp))) { ret = PTR_ERR(dev_opp); + mutex_unlock(&dev_opp_list_lock); goto free_table; } dev_opp->np = opp_np; dev_opp->shared_opp = of_property_read_bool(opp_np, "opp-shared"); + mutex_unlock(&dev_opp_list_lock); + return 0; free_table: @@ -1241,7 +1257,7 @@ static int _of_add_opp_table_v1(struct device *dev) unsigned long freq = be32_to_cpup(val++) * 1000; unsigned long volt = be32_to_cpup(val++); - if (_opp_add_dynamic(dev, freq, volt, false)) + if (_opp_add_v1(dev, freq, volt, false)) dev_warn(dev, "%s: Failed to add OPP %ld\n", __func__, freq); nr -= 2; diff --git a/drivers/base/power/opp/cpu.c b/drivers/base/power/opp/cpu.c index 7654c5606307..7b445e88a0d5 100644 --- a/drivers/base/power/opp/cpu.c +++ b/drivers/base/power/opp/cpu.c @@ -10,6 +10,9 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/cpu.h> #include <linux/cpufreq.h> #include <linux/err.h> @@ -124,12 +127,12 @@ int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev, cpumask_var_t cpumask) struct device *dev; int cpu, ret = 0; - rcu_read_lock(); + mutex_lock(&dev_opp_list_lock); dev_opp = _find_device_opp(cpu_dev); if (IS_ERR(dev_opp)) { ret = -EINVAL; - goto out_rcu_read_unlock; + goto unlock; } for_each_cpu(cpu, cpumask) { @@ -150,10 +153,10 @@ int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev, cpumask_var_t cpumask) continue; } } -out_rcu_read_unlock: - rcu_read_unlock(); +unlock: + mutex_unlock(&dev_opp_list_lock); - return 0; + return ret; } EXPORT_SYMBOL_GPL(dev_pm_opp_set_sharing_cpus); diff --git a/drivers/base/power/opp/opp.h b/drivers/base/power/opp/opp.h index dcb38f78dae4..7366b2aa8997 100644 --- a/drivers/base/power/opp/opp.h +++ b/drivers/base/power/opp/opp.h @@ -21,6 +21,9 @@ #include <linux/rculist.h> #include <linux/rcupdate.h> +/* Lock to allow exclusive modification to the device and opp lists */ +extern struct mutex dev_opp_list_lock; + /* * Internal data structure organization with the OPP layer library is as * follows: diff --git a/drivers/base/power/wakeirq.c b/drivers/base/power/wakeirq.c index eb6e67451dec..0d77cd6fd8d1 100644 --- a/drivers/base/power/wakeirq.c +++ b/drivers/base/power/wakeirq.c @@ -68,6 +68,9 @@ int dev_pm_set_wake_irq(struct device *dev, int irq) struct wake_irq *wirq; int err; + if (irq < 0) + return -EINVAL; + wirq = kzalloc(sizeof(*wirq), GFP_KERNEL); if (!wirq) return -ENOMEM; @@ -167,6 +170,9 @@ int dev_pm_set_dedicated_wake_irq(struct device *dev, int irq) struct wake_irq *wirq; int err; + if (irq < 0) + return -EINVAL; + wirq = kzalloc(sizeof(*wirq), GFP_KERNEL); if (!wirq) return -ENOMEM; diff --git a/drivers/base/property.c b/drivers/base/property.c index de40623bbd8a..1325ff225cc4 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -598,18 +598,34 @@ unsigned int device_get_child_node_count(struct device *dev) } EXPORT_SYMBOL_GPL(device_get_child_node_count); -bool device_dma_is_coherent(struct device *dev) +bool device_dma_supported(struct device *dev) { - bool coherent = false; - + /* For DT, this is always supported. + * For ACPI, this depends on CCA, which + * is determined by the acpi_dma_supported(). + */ if (IS_ENABLED(CONFIG_OF) && dev->of_node) - coherent = of_dma_is_coherent(dev->of_node); - else - acpi_check_dma(ACPI_COMPANION(dev), &coherent); + return true; + + return acpi_dma_supported(ACPI_COMPANION(dev)); +} +EXPORT_SYMBOL_GPL(device_dma_supported); - return coherent; +enum dev_dma_attr device_get_dma_attr(struct device *dev) +{ + enum dev_dma_attr attr = DEV_DMA_NOT_SUPPORTED; + + if (IS_ENABLED(CONFIG_OF) && dev->of_node) { + if (of_dma_is_coherent(dev->of_node)) + attr = DEV_DMA_COHERENT; + else + attr = DEV_DMA_NON_COHERENT; + } else + attr = acpi_get_dma_attr(ACPI_COMPANION(dev)); + + return attr; } -EXPORT_SYMBOL_GPL(device_dma_is_coherent); +EXPORT_SYMBOL_GPL(device_get_dma_attr); /** * device_get_phy_mode - Get phy mode for given device diff --git a/drivers/block/brd.c b/drivers/block/brd.c index b9794aeeb878..a5880f4ab40e 100644 --- a/drivers/block/brd.c +++ b/drivers/block/brd.c @@ -323,7 +323,7 @@ out: return err; } -static void brd_make_request(struct request_queue *q, struct bio *bio) +static blk_qc_t brd_make_request(struct request_queue *q, struct bio *bio) { struct block_device *bdev = bio->bi_bdev; struct brd_device *brd = bdev->bd_disk->private_data; @@ -337,6 +337,9 @@ static void brd_make_request(struct request_queue *q, struct bio *bio) goto io_error; if (unlikely(bio->bi_rw & REQ_DISCARD)) { + if (sector & ((PAGE_SIZE >> SECTOR_SHIFT) - 1) || + bio->bi_iter.bi_size & PAGE_MASK) + goto io_error; discard_from_brd(brd, sector, bio->bi_iter.bi_size); goto out; } @@ -358,9 +361,10 @@ static void brd_make_request(struct request_queue *q, struct bio *bio) out: bio_endio(bio); - return; + return BLK_QC_T_NONE; io_error: bio_io_error(bio); + return BLK_QC_T_NONE; } static int brd_rw_page(struct block_device *bdev, sector_t sector, diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 015c6e91b756..e66d453a5f2b 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1448,7 +1448,7 @@ extern int proc_details; /* drbd_req */ extern void do_submit(struct work_struct *ws); extern void __drbd_make_request(struct drbd_device *, struct bio *, unsigned long); -extern void drbd_make_request(struct request_queue *q, struct bio *bio); +extern blk_qc_t drbd_make_request(struct request_queue *q, struct bio *bio); extern int drbd_read_remote(struct drbd_device *device, struct drbd_request *req); extern int is_valid_ar_handle(struct drbd_request *, sector_t); diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 211592682169..3ae2c0086563 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -1494,7 +1494,7 @@ void do_submit(struct work_struct *ws) } } -void drbd_make_request(struct request_queue *q, struct bio *bio) +blk_qc_t drbd_make_request(struct request_queue *q, struct bio *bio) { struct drbd_device *device = (struct drbd_device *) q->queuedata; unsigned long start_jif; @@ -1510,6 +1510,7 @@ void drbd_make_request(struct request_queue *q, struct bio *bio) inc_ap_bio(device); __drbd_make_request(device, bio, start_jif); + return BLK_QC_T_NONE; } void request_timer_fn(unsigned long data) diff --git a/drivers/block/null_blk.c b/drivers/block/null_blk.c index 1c9e4fe5aa44..6255d1c4bba4 100644 --- a/drivers/block/null_blk.c +++ b/drivers/block/null_blk.c @@ -321,7 +321,7 @@ static struct nullb_queue *nullb_to_queue(struct nullb *nullb) return &nullb->queues[index]; } -static void null_queue_bio(struct request_queue *q, struct bio *bio) +static blk_qc_t null_queue_bio(struct request_queue *q, struct bio *bio) { struct nullb *nullb = q->queuedata; struct nullb_queue *nq = nullb_to_queue(nullb); @@ -331,6 +331,7 @@ static void null_queue_bio(struct request_queue *q, struct bio *bio) cmd->bio = bio; null_handle_cmd(cmd); + return BLK_QC_T_NONE; } static int null_rq_prep_fn(struct request_queue *q, struct request *req) diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 2f477d45d6cf..d06c62eccdf0 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -2441,7 +2441,7 @@ static void pkt_make_request_write(struct request_queue *q, struct bio *bio) } } -static void pkt_make_request(struct request_queue *q, struct bio *bio) +static blk_qc_t pkt_make_request(struct request_queue *q, struct bio *bio) { struct pktcdvd_device *pd; char b[BDEVNAME_SIZE]; @@ -2467,7 +2467,7 @@ static void pkt_make_request(struct request_queue *q, struct bio *bio) */ if (bio_data_dir(bio) == READ) { pkt_make_request_read(pd, bio); - return; + return BLK_QC_T_NONE; } if (!test_bit(PACKET_WRITABLE, &pd->flags)) { @@ -2499,13 +2499,12 @@ static void pkt_make_request(struct request_queue *q, struct bio *bio) pkt_make_request_write(q, split); } while (split != bio); - return; + return BLK_QC_T_NONE; end_io: bio_io_error(bio); + return BLK_QC_T_NONE; } - - static void pkt_init_queue(struct pktcdvd_device *pd) { struct request_queue *q = pd->disk->queue; diff --git a/drivers/block/ps3vram.c b/drivers/block/ps3vram.c index d89fcac59515..56847fcda086 100644 --- a/drivers/block/ps3vram.c +++ b/drivers/block/ps3vram.c @@ -598,7 +598,7 @@ out: return next; } -static void ps3vram_make_request(struct request_queue *q, struct bio *bio) +static blk_qc_t ps3vram_make_request(struct request_queue *q, struct bio *bio) { struct ps3_system_bus_device *dev = q->queuedata; struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); @@ -614,11 +614,13 @@ static void ps3vram_make_request(struct request_queue *q, struct bio *bio) spin_unlock_irq(&priv->lock); if (busy) - return; + return BLK_QC_T_NONE; do { bio = ps3vram_do_bio(dev, bio); } while (bio); + + return BLK_QC_T_NONE; } static int ps3vram_probe(struct ps3_system_bus_device *dev) diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 128e7df5b807..235708c7c46e 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -418,8 +418,6 @@ MODULE_PARM_DESC(single_major, "Use a single major number for all rbd devices (d static int rbd_img_request_submit(struct rbd_img_request *img_request); -static void rbd_dev_device_release(struct device *dev); - static ssize_t rbd_add(struct bus_type *bus, const char *buf, size_t count); static ssize_t rbd_remove(struct bus_type *bus, const char *buf, @@ -3991,14 +3989,12 @@ static const struct attribute_group *rbd_attr_groups[] = { NULL }; -static void rbd_sysfs_dev_release(struct device *dev) -{ -} +static void rbd_dev_release(struct device *dev); static struct device_type rbd_device_type = { .name = "rbd", .groups = rbd_attr_groups, - .release = rbd_sysfs_dev_release, + .release = rbd_dev_release, }; static struct rbd_spec *rbd_spec_get(struct rbd_spec *spec) @@ -4041,6 +4037,25 @@ static void rbd_spec_free(struct kref *kref) kfree(spec); } +static void rbd_dev_release(struct device *dev) +{ + struct rbd_device *rbd_dev = dev_to_rbd_dev(dev); + bool need_put = !!rbd_dev->opts; + + rbd_put_client(rbd_dev->rbd_client); + rbd_spec_put(rbd_dev->spec); + kfree(rbd_dev->opts); + kfree(rbd_dev); + + /* + * This is racy, but way better than putting module outside of + * the release callback. The race window is pretty small, so + * doing something similar to dm (dm-builtin.c) is overkill. + */ + if (need_put) + module_put(THIS_MODULE); +} + static struct rbd_device *rbd_dev_create(struct rbd_client *rbdc, struct rbd_spec *spec, struct rbd_options *opts) @@ -4057,6 +4072,11 @@ static struct rbd_device *rbd_dev_create(struct rbd_client *rbdc, INIT_LIST_HEAD(&rbd_dev->node); init_rwsem(&rbd_dev->header_rwsem); + rbd_dev->dev.bus = &rbd_bus_type; + rbd_dev->dev.type = &rbd_device_type; + rbd_dev->dev.parent = &rbd_root_dev; + device_initialize(&rbd_dev->dev); + rbd_dev->rbd_client = rbdc; rbd_dev->spec = spec; rbd_dev->opts = opts; @@ -4068,15 +4088,21 @@ static struct rbd_device *rbd_dev_create(struct rbd_client *rbdc, rbd_dev->layout.fl_object_size = cpu_to_le32(1 << RBD_MAX_OBJ_ORDER); rbd_dev->layout.fl_pg_pool = cpu_to_le32((u32) spec->pool_id); + /* + * If this is a mapping rbd_dev (as opposed to a parent one), + * pin our module. We have a ref from do_rbd_add(), so use + * __module_get(). + */ + if (rbd_dev->opts) + __module_get(THIS_MODULE); + return rbd_dev; } static void rbd_dev_destroy(struct rbd_device *rbd_dev) { - rbd_put_client(rbd_dev->rbd_client); - rbd_spec_put(rbd_dev->spec); - kfree(rbd_dev->opts); - kfree(rbd_dev); + if (rbd_dev) + put_device(&rbd_dev->dev); } /* @@ -4702,27 +4728,6 @@ static int rbd_dev_header_info(struct rbd_device *rbd_dev) return rbd_dev_v2_header_info(rbd_dev); } -static int rbd_bus_add_dev(struct rbd_device *rbd_dev) -{ - struct device *dev; - int ret; - - dev = &rbd_dev->dev; - dev->bus = &rbd_bus_type; - dev->type = &rbd_device_type; - dev->parent = &rbd_root_dev; - dev->release = rbd_dev_device_release; - dev_set_name(dev, "%d", rbd_dev->dev_id); - ret = device_register(dev); - - return ret; -} - -static void rbd_bus_del_dev(struct rbd_device *rbd_dev) -{ - device_unregister(&rbd_dev->dev); -} - /* * Get a unique rbd identifier for the given new rbd_dev, and add * the rbd_dev to the global list. @@ -5225,7 +5230,8 @@ static int rbd_dev_device_setup(struct rbd_device *rbd_dev) set_capacity(rbd_dev->disk, rbd_dev->mapping.size / SECTOR_SIZE); set_disk_ro(rbd_dev->disk, rbd_dev->mapping.read_only); - ret = rbd_bus_add_dev(rbd_dev); + dev_set_name(&rbd_dev->dev, "%d", rbd_dev->dev_id); + ret = device_add(&rbd_dev->dev); if (ret) goto err_out_mapping; @@ -5248,8 +5254,6 @@ err_out_blkdev: unregister_blkdev(rbd_dev->major, rbd_dev->name); err_out_id: rbd_dev_id_put(rbd_dev); - rbd_dev_mapping_clear(rbd_dev); - return ret; } @@ -5397,7 +5401,7 @@ static ssize_t do_rbd_add(struct bus_type *bus, struct rbd_spec *spec = NULL; struct rbd_client *rbdc; bool read_only; - int rc = -ENOMEM; + int rc; if (!try_module_get(THIS_MODULE)) return -ENODEV; @@ -5405,7 +5409,7 @@ static ssize_t do_rbd_add(struct bus_type *bus, /* parse add command */ rc = rbd_add_parse_args(buf, &ceph_opts, &rbd_opts, &spec); if (rc < 0) - goto err_out_module; + goto out; rbdc = rbd_get_client(ceph_opts); if (IS_ERR(rbdc)) { @@ -5432,8 +5436,10 @@ static ssize_t do_rbd_add(struct bus_type *bus, } rbd_dev = rbd_dev_create(rbdc, spec, rbd_opts); - if (!rbd_dev) + if (!rbd_dev) { + rc = -ENOMEM; goto err_out_client; + } rbdc = NULL; /* rbd_dev now owns this */ spec = NULL; /* rbd_dev now owns this */ rbd_opts = NULL; /* rbd_dev now owns this */ @@ -5458,10 +5464,13 @@ static ssize_t do_rbd_add(struct bus_type *bus, */ rbd_dev_header_unwatch_sync(rbd_dev); rbd_dev_image_release(rbd_dev); - goto err_out_module; + goto out; } - return count; + rc = count; +out: + module_put(THIS_MODULE); + return rc; err_out_rbd_dev: rbd_dev_destroy(rbd_dev); @@ -5470,12 +5479,7 @@ err_out_client: err_out_args: rbd_spec_put(spec); kfree(rbd_opts); -err_out_module: - module_put(THIS_MODULE); - - dout("Error adding device %s\n", buf); - - return (ssize_t)rc; + goto out; } static ssize_t rbd_add(struct bus_type *bus, @@ -5495,17 +5499,15 @@ static ssize_t rbd_add_single_major(struct bus_type *bus, return do_rbd_add(bus, buf, count); } -static void rbd_dev_device_release(struct device *dev) +static void rbd_dev_device_release(struct rbd_device *rbd_dev) { - struct rbd_device *rbd_dev = dev_to_rbd_dev(dev); - rbd_free_disk(rbd_dev); clear_bit(RBD_DEV_FLAG_EXISTS, &rbd_dev->flags); + device_del(&rbd_dev->dev); rbd_dev_mapping_clear(rbd_dev); if (!single_major) unregister_blkdev(rbd_dev->major, rbd_dev->name); rbd_dev_id_put(rbd_dev); - rbd_dev_mapping_clear(rbd_dev); } static void rbd_dev_remove_parent(struct rbd_device *rbd_dev) @@ -5590,9 +5592,8 @@ static ssize_t do_rbd_remove(struct bus_type *bus, * rbd_bus_del_dev() will race with rbd_watch_cb(), resulting * in a potential use after free of rbd_dev->disk or rbd_dev. */ - rbd_bus_del_dev(rbd_dev); + rbd_dev_device_release(rbd_dev); rbd_dev_image_release(rbd_dev); - module_put(THIS_MODULE); return count; } @@ -5663,10 +5664,8 @@ static int rbd_slab_init(void) if (rbd_segment_name_cache) return 0; out_err: - if (rbd_obj_request_cache) { - kmem_cache_destroy(rbd_obj_request_cache); - rbd_obj_request_cache = NULL; - } + kmem_cache_destroy(rbd_obj_request_cache); + rbd_obj_request_cache = NULL; kmem_cache_destroy(rbd_img_request_cache); rbd_img_request_cache = NULL; diff --git a/drivers/block/rsxx/dev.c b/drivers/block/rsxx/dev.c index 3163e4cdc2cc..e1b8b7061d2f 100644 --- a/drivers/block/rsxx/dev.c +++ b/drivers/block/rsxx/dev.c @@ -145,7 +145,7 @@ static void bio_dma_done_cb(struct rsxx_cardinfo *card, } } -static void rsxx_make_request(struct request_queue *q, struct bio *bio) +static blk_qc_t rsxx_make_request(struct request_queue *q, struct bio *bio) { struct rsxx_cardinfo *card = q->queuedata; struct rsxx_bio_meta *bio_meta; @@ -199,7 +199,7 @@ static void rsxx_make_request(struct request_queue *q, struct bio *bio) if (st) goto queue_err; - return; + return BLK_QC_T_NONE; queue_err: kmem_cache_free(bio_meta_pool, bio_meta); @@ -207,6 +207,7 @@ req_err: if (st) bio->bi_error = st; bio_endio(bio); + return BLK_QC_T_NONE; } /*----------------- Device Setup -------------------*/ diff --git a/drivers/block/umem.c b/drivers/block/umem.c index 04d65790a886..7939b9f87441 100644 --- a/drivers/block/umem.c +++ b/drivers/block/umem.c @@ -524,7 +524,7 @@ static int mm_check_plugged(struct cardinfo *card) return !!blk_check_plugged(mm_unplug, card, sizeof(struct blk_plug_cb)); } -static void mm_make_request(struct request_queue *q, struct bio *bio) +static blk_qc_t mm_make_request(struct request_queue *q, struct bio *bio) { struct cardinfo *card = q->queuedata; pr_debug("mm_make_request %llu %u\n", @@ -541,7 +541,7 @@ static void mm_make_request(struct request_queue *q, struct bio *bio) activate(card); spin_unlock_irq(&card->lock); - return; + return BLK_QC_T_NONE; } static irqreturn_t mm_interrupt(int irq, void *__card) diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index 81a557c33a1f..47915d736f8d 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -894,7 +894,7 @@ out: /* * Handler function for all zram I/O requests. */ -static void zram_make_request(struct request_queue *queue, struct bio *bio) +static blk_qc_t zram_make_request(struct request_queue *queue, struct bio *bio) { struct zram *zram = queue->queuedata; @@ -911,11 +911,12 @@ static void zram_make_request(struct request_queue *queue, struct bio *bio) __zram_make_request(zram, bio); zram_meta_put(zram); - return; + return BLK_QC_T_NONE; put_zram: zram_meta_put(zram); error: bio_io_error(bio); + return BLK_QC_T_NONE; } static void zram_slot_free_notify(struct block_device *bdev, diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index e33dacf5bd98..92f0ee388f9e 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -1372,6 +1372,8 @@ static void btusb_work(struct work_struct *work) } if (data->isoc_altsetting != new_alts) { + unsigned long flags; + clear_bit(BTUSB_ISOC_RUNNING, &data->flags); usb_kill_anchored_urbs(&data->isoc_anchor); @@ -1384,10 +1386,10 @@ static void btusb_work(struct work_struct *work) * Clear outstanding fragment when selecting a new * alternate setting. */ - spin_lock(&data->rxlock); + spin_lock_irqsave(&data->rxlock, flags); kfree_skb(data->sco_skb); data->sco_skb = NULL; - spin_unlock(&data->rxlock); + spin_unlock_irqrestore(&data->rxlock, flags); if (__set_isoc_interface(hdev, new_alts) < 0) return; diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 654f6f36a071..55fe9020459f 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -412,18 +412,42 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info) return rv; } -static void start_check_enables(struct smi_info *smi_info) +static void smi_mod_timer(struct smi_info *smi_info, unsigned long new_val) +{ + smi_info->last_timeout_jiffies = jiffies; + mod_timer(&smi_info->si_timer, new_val); + smi_info->timer_running = true; +} + +/* + * Start a new message and (re)start the timer and thread. + */ +static void start_new_msg(struct smi_info *smi_info, unsigned char *msg, + unsigned int size) +{ + smi_mod_timer(smi_info, jiffies + SI_TIMEOUT_JIFFIES); + + if (smi_info->thread) + wake_up_process(smi_info->thread); + + smi_info->handlers->start_transaction(smi_info->si_sm, msg, size); +} + +static void start_check_enables(struct smi_info *smi_info, bool start_timer) { unsigned char msg[2]; msg[0] = (IPMI_NETFN_APP_REQUEST << 2); msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD; - smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2); + if (start_timer) + start_new_msg(smi_info, msg, 2); + else + smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2); smi_info->si_state = SI_CHECKING_ENABLES; } -static void start_clear_flags(struct smi_info *smi_info) +static void start_clear_flags(struct smi_info *smi_info, bool start_timer) { unsigned char msg[3]; @@ -432,7 +456,10 @@ static void start_clear_flags(struct smi_info *smi_info) msg[1] = IPMI_CLEAR_MSG_FLAGS_CMD; msg[2] = WDT_PRE_TIMEOUT_INT; - smi_info->handlers->start_transaction(smi_info->si_sm, msg, 3); + if (start_timer) + start_new_msg(smi_info, msg, 3); + else + smi_info->handlers->start_transaction(smi_info->si_sm, msg, 3); smi_info->si_state = SI_CLEARING_FLAGS; } @@ -442,10 +469,8 @@ static void start_getting_msg_queue(struct smi_info *smi_info) smi_info->curr_msg->data[1] = IPMI_GET_MSG_CMD; smi_info->curr_msg->data_size = 2; - smi_info->handlers->start_transaction( - smi_info->si_sm, - smi_info->curr_msg->data, - smi_info->curr_msg->data_size); + start_new_msg(smi_info, smi_info->curr_msg->data, + smi_info->curr_msg->data_size); smi_info->si_state = SI_GETTING_MESSAGES; } @@ -455,20 +480,11 @@ static void start_getting_events(struct smi_info *smi_info) smi_info->curr_msg->data[1] = IPMI_READ_EVENT_MSG_BUFFER_CMD; smi_info->curr_msg->data_size = 2; - smi_info->handlers->start_transaction( - smi_info->si_sm, - smi_info->curr_msg->data, - smi_info->curr_msg->data_size); + start_new_msg(smi_info, smi_info->curr_msg->data, + smi_info->curr_msg->data_size); smi_info->si_state = SI_GETTING_EVENTS; } -static void smi_mod_timer(struct smi_info *smi_info, unsigned long new_val) -{ - smi_info->last_timeout_jiffies = jiffies; - mod_timer(&smi_info->si_timer, new_val); - smi_info->timer_running = true; -} - /* * When we have a situtaion where we run out of memory and cannot * allocate messages, we just leave them in the BMC and run the system @@ -478,11 +494,11 @@ static void smi_mod_timer(struct smi_info *smi_info, unsigned long new_val) * Note that we cannot just use disable_irq(), since the interrupt may * be shared. */ -static inline bool disable_si_irq(struct smi_info *smi_info) +static inline bool disable_si_irq(struct smi_info *smi_info, bool start_timer) { if ((smi_info->irq) && (!smi_info->interrupt_disabled)) { smi_info->interrupt_disabled = true; - start_check_enables(smi_info); + start_check_enables(smi_info, start_timer); return true; } return false; @@ -492,7 +508,7 @@ static inline bool enable_si_irq(struct smi_info *smi_info) { if ((smi_info->irq) && (smi_info->interrupt_disabled)) { smi_info->interrupt_disabled = false; - start_check_enables(smi_info); + start_check_enables(smi_info, true); return true; } return false; @@ -510,7 +526,7 @@ static struct ipmi_smi_msg *alloc_msg_handle_irq(struct smi_info *smi_info) msg = ipmi_alloc_smi_msg(); if (!msg) { - if (!disable_si_irq(smi_info)) + if (!disable_si_irq(smi_info, true)) smi_info->si_state = SI_NORMAL; } else if (enable_si_irq(smi_info)) { ipmi_free_smi_msg(msg); @@ -526,7 +542,7 @@ static void handle_flags(struct smi_info *smi_info) /* Watchdog pre-timeout */ smi_inc_stat(smi_info, watchdog_pretimeouts); - start_clear_flags(smi_info); + start_clear_flags(smi_info, true); smi_info->msg_flags &= ~WDT_PRE_TIMEOUT_INT; if (smi_info->intf) ipmi_smi_watchdog_pretimeout(smi_info->intf); @@ -879,8 +895,7 @@ static enum si_sm_result smi_event_handler(struct smi_info *smi_info, msg[0] = (IPMI_NETFN_APP_REQUEST << 2); msg[1] = IPMI_GET_MSG_FLAGS_CMD; - smi_info->handlers->start_transaction( - smi_info->si_sm, msg, 2); + start_new_msg(smi_info, msg, 2); smi_info->si_state = SI_GETTING_FLAGS; goto restart; } @@ -910,7 +925,7 @@ static enum si_sm_result smi_event_handler(struct smi_info *smi_info, * disable and messages disabled. */ if (smi_info->supports_event_msg_buff || smi_info->irq) { - start_check_enables(smi_info); + start_check_enables(smi_info, true); } else { smi_info->curr_msg = alloc_msg_handle_irq(smi_info); if (!smi_info->curr_msg) @@ -920,6 +935,13 @@ static enum si_sm_result smi_event_handler(struct smi_info *smi_info, } goto restart; } + + if (si_sm_result == SI_SM_IDLE && smi_info->timer_running) { + /* Ok it if fails, the timer will just go off. */ + if (del_timer(&smi_info->si_timer)) + smi_info->timer_running = false; + } + out: return si_sm_result; } @@ -2560,6 +2582,7 @@ static const struct of_device_id of_ipmi_match[] = { .data = (void *)(unsigned long) SI_BT }, {}, }; +MODULE_DEVICE_TABLE(of, of_ipmi_match); static int of_ipmi_probe(struct platform_device *dev) { @@ -2646,7 +2669,6 @@ static int of_ipmi_probe(struct platform_device *dev) } return 0; } -MODULE_DEVICE_TABLE(of, of_ipmi_match); #else #define of_ipmi_match NULL static int of_ipmi_probe(struct platform_device *dev) @@ -3613,7 +3635,7 @@ static int try_smi_init(struct smi_info *new_smi) * Start clearing the flags before we enable interrupts or the * timer to avoid racing with the timer. */ - start_clear_flags(new_smi); + start_clear_flags(new_smi, false); /* * IRQ is defined to be set when non-zero. req_events will @@ -3908,7 +3930,7 @@ static void cleanup_one_si(struct smi_info *to_clean) poll(to_clean); schedule_timeout_uninterruptible(1); } - disable_si_irq(to_clean); + disable_si_irq(to_clean, false); while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) { poll(to_clean); schedule_timeout_uninterruptible(1); diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c index 0ac3bd1a5497..096f0cef4da1 100644 --- a/drivers/char/ipmi/ipmi_watchdog.c +++ b/drivers/char/ipmi/ipmi_watchdog.c @@ -153,6 +153,9 @@ static int timeout = 10; /* The pre-timeout is disabled by default. */ static int pretimeout; +/* Default timeout to set on panic */ +static int panic_wdt_timeout = 255; + /* Default action is to reset the board on a timeout. */ static unsigned char action_val = WDOG_TIMEOUT_RESET; @@ -293,6 +296,9 @@ MODULE_PARM_DESC(timeout, "Timeout value in seconds."); module_param(pretimeout, timeout, 0644); MODULE_PARM_DESC(pretimeout, "Pretimeout value in seconds."); +module_param(panic_wdt_timeout, timeout, 0644); +MODULE_PARM_DESC(timeout, "Timeout value on kernel panic in seconds."); + module_param_cb(action, ¶m_ops_str, action_op, 0644); MODULE_PARM_DESC(action, "Timeout action. One of: " "reset, none, power_cycle, power_off."); @@ -1189,7 +1195,7 @@ static int wdog_panic_handler(struct notifier_block *this, /* Make sure we do this only once. */ panic_event_handled = 1; - timeout = 255; + timeout = panic_wdt_timeout; pretimeout = 0; panic_halt_ipmi_set_timeout(); } diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index f26b0ae23bea..45cc39aabeee 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -226,21 +226,23 @@ int tpm_chip_register(struct tpm_chip *chip) if (rc) goto out_err; - if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) { - rc = __compat_only_sysfs_link_entry_to_kobj(&chip->pdev->kobj, - &chip->dev.kobj, - "ppi"); - if (rc) - goto out_err; - } - /* Make the chip available. */ spin_lock(&driver_lock); - list_add_rcu(&chip->list, &tpm_chip_list); + list_add_tail_rcu(&chip->list, &tpm_chip_list); spin_unlock(&driver_lock); chip->flags |= TPM_CHIP_FLAG_REGISTERED; + if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) { + rc = __compat_only_sysfs_link_entry_to_kobj(&chip->pdev->kobj, + &chip->dev.kobj, + "ppi"); + if (rc && rc != -ENOENT) { + tpm_chip_unregister(chip); + return rc; + } + } + return 0; out_err: tpm1_chip_unregister(chip); diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c index bd7039fafa8a..c12130485fc1 100644 --- a/drivers/char/tpm/tpm2-cmd.c +++ b/drivers/char/tpm/tpm2-cmd.c @@ -443,12 +443,13 @@ int tpm2_seal_trusted(struct tpm_chip *chip, TPM_DIGEST_SIZE); /* sensitive */ - tpm_buf_append_u16(&buf, 4 + TPM_DIGEST_SIZE + payload->key_len); + tpm_buf_append_u16(&buf, 4 + TPM_DIGEST_SIZE + payload->key_len + 1); tpm_buf_append_u16(&buf, TPM_DIGEST_SIZE); tpm_buf_append(&buf, options->blobauth, TPM_DIGEST_SIZE); - tpm_buf_append_u16(&buf, payload->key_len); + tpm_buf_append_u16(&buf, payload->key_len + 1); tpm_buf_append(&buf, payload->key, payload->key_len); + tpm_buf_append_u8(&buf, payload->migratable); /* public */ tpm_buf_append_u16(&buf, 14); @@ -573,6 +574,8 @@ static int tpm2_unseal(struct tpm_chip *chip, u32 blob_handle) { struct tpm_buf buf; + u16 data_len; + u8 *data; int rc; rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_UNSEAL); @@ -591,11 +594,13 @@ static int tpm2_unseal(struct tpm_chip *chip, rc = -EPERM; if (!rc) { - payload->key_len = be16_to_cpup( + data_len = be16_to_cpup( (__be16 *) &buf.data[TPM_HEADER_SIZE + 4]); + data = &buf.data[TPM_HEADER_SIZE + 6]; - memcpy(payload->key, &buf.data[TPM_HEADER_SIZE + 6], - payload->key_len); + memcpy(payload->key, data, data_len - 1); + payload->key_len = data_len - 1; + payload->migratable = data[data_len - 1]; } tpm_buf_destroy(&buf); diff --git a/drivers/char/tpm/tpm_of.c b/drivers/char/tpm/tpm_of.c index 1141456a4b1f..570f30c5c5f4 100644 --- a/drivers/char/tpm/tpm_of.c +++ b/drivers/char/tpm/tpm_of.c @@ -53,17 +53,18 @@ int read_log(struct tpm_bios_log *log) goto cleanup_eio; } - of_node_put(np); log->bios_event_log = kmalloc(*sizep, GFP_KERNEL); if (!log->bios_event_log) { pr_err("%s: ERROR - Not enough memory for BIOS measurements\n", __func__); + of_node_put(np); return -ENOMEM; } log->bios_event_log_end = log->bios_event_log + *sizep; memcpy(log->bios_event_log, __va(*basep), *sizep); + of_node_put(np); return 0; diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 696ef1d56b4f..65f7eecc45b0 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -645,6 +645,7 @@ static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info, { u32 vendor, intfcaps, intmask; int rc, i, irq_s, irq_e, probe; + int irq_r = -1; struct tpm_chip *chip; struct priv_data *priv; @@ -751,6 +752,7 @@ static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info, irq_s = ioread8(chip->vendor.iobase + TPM_INT_VECTOR(chip->vendor.locality)); + irq_r = irq_s; if (irq_s) { irq_e = irq_s; } else { @@ -805,6 +807,8 @@ static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info, iowrite32(intmask, chip->vendor.iobase + TPM_INT_ENABLE(chip->vendor.locality)); + + devm_free_irq(dev, i, chip); } } if (chip->vendor.irq) { @@ -831,7 +835,9 @@ static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info, chip->vendor.iobase + TPM_INT_ENABLE(chip->vendor.locality)); } - } + } else if (irq_r != -1) + iowrite8(irq_r, chip->vendor.iobase + + TPM_INT_VECTOR(chip->vendor.locality)); if (chip->flags & TPM_CHIP_FLAG_TPM2) { chip->vendor.timeout_a = msecs_to_jiffies(TPM2_TIMEOUT_A); diff --git a/drivers/clk/h8300/clk-div.c b/drivers/clk/h8300/clk-div.c index 1dd5d14d5dbe..d71d01157dbb 100644 --- a/drivers/clk/h8300/clk-div.c +++ b/drivers/clk/h8300/clk-div.c @@ -19,6 +19,7 @@ static void __init h8300_div_clk_setup(struct device_node *node) const char *parent_name; void __iomem *divcr = NULL; int width; + int offset; num_parents = of_clk_get_parent_count(node); if (num_parents < 1) { @@ -31,11 +32,14 @@ static void __init h8300_div_clk_setup(struct device_node *node) pr_err("%s: failed to map divide register", clk_name); goto error; } + offset = (unsigned long)divcr & 3; + offset = (3 - offset) * 8; + divcr = (void *)((unsigned long)divcr & ~3); parent_name = of_clk_get_parent_name(node, 0); of_property_read_u32(node, "renesas,width", &width); clk = clk_register_divider(NULL, clk_name, parent_name, - CLK_SET_RATE_GATE, divcr, 0, width, + CLK_SET_RATE_GATE, divcr, offset, width, CLK_DIVIDER_POWER_OF_TWO, &clklock); if (!IS_ERR(clk)) { of_clk_add_provider(node, of_clk_src_simple_get, clk); diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 71cfdf7c9708..2eb5f0efae90 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -1,4 +1,5 @@ menu "Clock Source drivers" + depends on !ARCH_USES_GETTIMEOFFSET config CLKSRC_OF bool diff --git a/drivers/clocksource/fsl_ftm_timer.c b/drivers/clocksource/fsl_ftm_timer.c index 10202f1fdfd7..517e1c7624d4 100644 --- a/drivers/clocksource/fsl_ftm_timer.c +++ b/drivers/clocksource/fsl_ftm_timer.c @@ -203,7 +203,7 @@ static int __init ftm_clockevent_init(unsigned long freq, int irq) int err; ftm_writel(0x00, priv->clkevt_base + FTM_CNTIN); - ftm_writel(~0UL, priv->clkevt_base + FTM_MOD); + ftm_writel(~0u, priv->clkevt_base + FTM_MOD); ftm_reset_counter(priv->clkevt_base); @@ -230,7 +230,7 @@ static int __init ftm_clocksource_init(unsigned long freq) int err; ftm_writel(0x00, priv->clksrc_base + FTM_CNTIN); - ftm_writel(~0UL, priv->clksrc_base + FTM_MOD); + ftm_writel(~0u, priv->clksrc_base + FTM_MOD); ftm_reset_counter(priv->clksrc_base); diff --git a/drivers/clocksource/mips-gic-timer.c b/drivers/clocksource/mips-gic-timer.c index 02a1945e5093..89d3e4d7900c 100644 --- a/drivers/clocksource/mips-gic-timer.c +++ b/drivers/clocksource/mips-gic-timer.c @@ -140,9 +140,10 @@ static cycle_t gic_hpt_read(struct clocksource *cs) } static struct clocksource gic_clocksource = { - .name = "GIC", - .read = gic_hpt_read, - .flags = CLOCK_SOURCE_IS_CONTINUOUS, + .name = "GIC", + .read = gic_hpt_read, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, + .archdata = { .vdso_clock_mode = VDSO_CLOCK_GIC }, }; static void __init __gic_clocksource_init(void) diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index 1582c1c016b0..8014c2307332 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -84,6 +84,7 @@ config ARM_KIRKWOOD_CPUFREQ config ARM_MT8173_CPUFREQ bool "Mediatek MT8173 CPUFreq support" depends on ARCH_MEDIATEK && REGULATOR + depends on ARM64 || (ARM_CPU_TOPOLOGY && COMPILE_TEST) depends on !CPU_THERMAL || THERMAL=y select PM_OPP help diff --git a/drivers/cpufreq/Kconfig.x86 b/drivers/cpufreq/Kconfig.x86 index adbd1de1cea5..c59bdcb83217 100644 --- a/drivers/cpufreq/Kconfig.x86 +++ b/drivers/cpufreq/Kconfig.x86 @@ -5,7 +5,6 @@ config X86_INTEL_PSTATE bool "Intel P state control" depends on X86 - select ACPI_PROCESSOR if ACPI help This driver provides a P state for Intel core processors. The driver implements an internal governor and will become diff --git a/drivers/cpufreq/arm_big_little.c b/drivers/cpufreq/arm_big_little.c index f1e42f8ce0fc..c5d256caa664 100644 --- a/drivers/cpufreq/arm_big_little.c +++ b/drivers/cpufreq/arm_big_little.c @@ -149,6 +149,19 @@ bL_cpufreq_set_rate(u32 cpu, u32 old_cluster, u32 new_cluster, u32 rate) __func__, cpu, old_cluster, new_cluster, new_rate); ret = clk_set_rate(clk[new_cluster], new_rate * 1000); + if (!ret) { + /* + * FIXME: clk_set_rate hasn't returned an error here however it + * may be that clk_change_rate failed due to hardware or + * firmware issues and wasn't able to report that due to the + * current design of the clk core layer. To work around this + * problem we will read back the clock rate and check it is + * correct. This needs to be removed once clk core is fixed. + */ + if (clk_get_rate(clk[new_cluster]) != new_rate * 1000) + ret = -EIO; + } + if (WARN_ON(ret)) { pr_err("clk_set_rate failed: %d, new cluster: %d\n", ret, new_cluster); @@ -189,15 +202,6 @@ bL_cpufreq_set_rate(u32 cpu, u32 old_cluster, u32 new_cluster, u32 rate) mutex_unlock(&cluster_lock[old_cluster]); } - /* - * FIXME: clk_set_rate has to handle the case where clk_change_rate - * can fail due to hardware or firmware issues. Until the clk core - * layer is fixed, we can check here. In most of the cases we will - * be reading only the cached value anyway. This needs to be removed - * once clk core is fixed. - */ - if (bL_cpufreq_get_rate(cpu) != new_rate) - return -EIO; return 0; } diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c index 93c219fab850..e8cb334094b0 100644 --- a/drivers/cpufreq/cppc_cpufreq.c +++ b/drivers/cpufreq/cppc_cpufreq.c @@ -166,8 +166,7 @@ static int __init cppc_cpufreq_init(void) out: for_each_possible_cpu(i) - if (all_cpu_data[i]) - kfree(all_cpu_data[i]); + kfree(all_cpu_data[i]); kfree(all_cpu_data); return -ENODEV; diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index 11258c4c1b17..b260576ddb12 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -171,10 +171,6 @@ void gov_queue_work(struct dbs_data *dbs_data, struct cpufreq_policy *policy, { int i; - mutex_lock(&cpufreq_governor_lock); - if (!policy->governor_enabled) - goto out_unlock; - if (!all_cpus) { /* * Use raw_smp_processor_id() to avoid preemptible warnings. @@ -188,9 +184,6 @@ void gov_queue_work(struct dbs_data *dbs_data, struct cpufreq_policy *policy, for_each_cpu(i, policy->cpus) __gov_queue_work(i, dbs_data, delay); } - -out_unlock: - mutex_unlock(&cpufreq_governor_lock); } EXPORT_SYMBOL_GPL(gov_queue_work); @@ -229,13 +222,24 @@ static void dbs_timer(struct work_struct *work) struct cpu_dbs_info *cdbs = container_of(work, struct cpu_dbs_info, dwork.work); struct cpu_common_dbs_info *shared = cdbs->shared; - struct cpufreq_policy *policy = shared->policy; - struct dbs_data *dbs_data = policy->governor_data; + struct cpufreq_policy *policy; + struct dbs_data *dbs_data; unsigned int sampling_rate, delay; bool modify_all = true; mutex_lock(&shared->timer_mutex); + policy = shared->policy; + + /* + * Governor might already be disabled and there is no point continuing + * with the work-handler. + */ + if (!policy) + goto unlock; + + dbs_data = policy->governor_data; + if (dbs_data->cdata->governor == GOV_CONSERVATIVE) { struct cs_dbs_tuners *cs_tuners = dbs_data->tuners; @@ -252,6 +256,7 @@ static void dbs_timer(struct work_struct *work) delay = dbs_data->cdata->gov_dbs_timer(cdbs, dbs_data, modify_all); gov_queue_work(dbs_data, policy, delay, modify_all); +unlock: mutex_unlock(&shared->timer_mutex); } @@ -478,9 +483,17 @@ static int cpufreq_governor_stop(struct cpufreq_policy *policy, if (!shared || !shared->policy) return -EBUSY; + /* + * Work-handler must see this updated, as it should not proceed any + * further after governor is disabled. And so timer_mutex is taken while + * updating this value. + */ + mutex_lock(&shared->timer_mutex); + shared->policy = NULL; + mutex_unlock(&shared->timer_mutex); + gov_cancel_work(dbs_data, policy); - shared->policy = NULL; mutex_destroy(&shared->timer_mutex); return 0; } diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 93a3c635ea27..001a532e342e 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -34,14 +34,10 @@ #include <asm/cpu_device_id.h> #include <asm/cpufeature.h> -#if IS_ENABLED(CONFIG_ACPI) -#include <acpi/processor.h> -#endif - -#define BYT_RATIOS 0x66a -#define BYT_VIDS 0x66b -#define BYT_TURBO_RATIOS 0x66c -#define BYT_TURBO_VIDS 0x66d +#define ATOM_RATIOS 0x66a +#define ATOM_VIDS 0x66b +#define ATOM_TURBO_RATIOS 0x66c +#define ATOM_TURBO_VIDS 0x66d #define FRAC_BITS 8 #define int_tofp(X) ((int64_t)(X) << FRAC_BITS) @@ -117,9 +113,6 @@ struct cpudata { u64 prev_mperf; u64 prev_tsc; struct sample sample; -#if IS_ENABLED(CONFIG_ACPI) - struct acpi_processor_performance acpi_perf_data; -#endif }; static struct cpudata **all_cpu_data; @@ -150,7 +143,6 @@ struct cpu_defaults { static struct pstate_adjust_policy pid_params; static struct pstate_funcs pstate_funcs; static int hwp_active; -static int no_acpi_perf; struct perf_limits { int no_turbo; @@ -163,8 +155,6 @@ struct perf_limits { int max_sysfs_pct; int min_policy_pct; int min_sysfs_pct; - int max_perf_ctl; - int min_perf_ctl; }; static struct perf_limits performance_limits = { @@ -191,8 +181,6 @@ static struct perf_limits powersave_limits = { .max_sysfs_pct = 100, .min_policy_pct = 0, .min_sysfs_pct = 0, - .max_perf_ctl = 0, - .min_perf_ctl = 0, }; #ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE @@ -201,153 +189,6 @@ static struct perf_limits *limits = &performance_limits; static struct perf_limits *limits = &powersave_limits; #endif -#if IS_ENABLED(CONFIG_ACPI) -/* - * The max target pstate ratio is a 8 bit value in both PLATFORM_INFO MSR and - * in TURBO_RATIO_LIMIT MSR, which pstate driver stores in max_pstate and - * max_turbo_pstate fields. The PERF_CTL MSR contains 16 bit value for P state - * ratio, out of it only high 8 bits are used. For example 0x1700 is setting - * target ratio 0x17. The _PSS control value stores in a format which can be - * directly written to PERF_CTL MSR. But in intel_pstate driver this shift - * occurs during write to PERF_CTL (E.g. for cores core_set_pstate()). - * This function converts the _PSS control value to intel pstate driver format - * for comparison and assignment. - */ -static int convert_to_native_pstate_format(struct cpudata *cpu, int index) -{ - return cpu->acpi_perf_data.states[index].control >> 8; -} - -static int intel_pstate_init_perf_limits(struct cpufreq_policy *policy) -{ - struct cpudata *cpu; - int ret; - bool turbo_absent = false; - int max_pstate_index; - int min_pss_ctl, max_pss_ctl, turbo_pss_ctl; - int i; - - cpu = all_cpu_data[policy->cpu]; - - pr_debug("intel_pstate: default limits 0x%x 0x%x 0x%x\n", - cpu->pstate.min_pstate, cpu->pstate.max_pstate, - cpu->pstate.turbo_pstate); - - if (!cpu->acpi_perf_data.shared_cpu_map && - zalloc_cpumask_var_node(&cpu->acpi_perf_data.shared_cpu_map, - GFP_KERNEL, cpu_to_node(policy->cpu))) { - return -ENOMEM; - } - - ret = acpi_processor_register_performance(&cpu->acpi_perf_data, - policy->cpu); - if (ret) - return ret; - - /* - * Check if the control value in _PSS is for PERF_CTL MSR, which should - * guarantee that the states returned by it map to the states in our - * list directly. - */ - if (cpu->acpi_perf_data.control_register.space_id != - ACPI_ADR_SPACE_FIXED_HARDWARE) - return -EIO; - - pr_debug("intel_pstate: CPU%u - ACPI _PSS perf data\n", policy->cpu); - for (i = 0; i < cpu->acpi_perf_data.state_count; i++) - pr_debug(" %cP%d: %u MHz, %u mW, 0x%x\n", - (i == cpu->acpi_perf_data.state ? '*' : ' '), i, - (u32) cpu->acpi_perf_data.states[i].core_frequency, - (u32) cpu->acpi_perf_data.states[i].power, - (u32) cpu->acpi_perf_data.states[i].control); - - /* - * If there is only one entry _PSS, simply ignore _PSS and continue as - * usual without taking _PSS into account - */ - if (cpu->acpi_perf_data.state_count < 2) - return 0; - - turbo_pss_ctl = convert_to_native_pstate_format(cpu, 0); - min_pss_ctl = convert_to_native_pstate_format(cpu, - cpu->acpi_perf_data.state_count - 1); - /* Check if there is a turbo freq in _PSS */ - if (turbo_pss_ctl <= cpu->pstate.max_pstate && - turbo_pss_ctl > cpu->pstate.min_pstate) { - pr_debug("intel_pstate: no turbo range exists in _PSS\n"); - limits->no_turbo = limits->turbo_disabled = 1; - cpu->pstate.turbo_pstate = cpu->pstate.max_pstate; - turbo_absent = true; - } - - /* Check if the max non turbo p state < Intel P state max */ - max_pstate_index = turbo_absent ? 0 : 1; - max_pss_ctl = convert_to_native_pstate_format(cpu, max_pstate_index); - if (max_pss_ctl < cpu->pstate.max_pstate && - max_pss_ctl > cpu->pstate.min_pstate) - cpu->pstate.max_pstate = max_pss_ctl; - - /* check If min perf > Intel P State min */ - if (min_pss_ctl > cpu->pstate.min_pstate && - min_pss_ctl < cpu->pstate.max_pstate) { - cpu->pstate.min_pstate = min_pss_ctl; - policy->cpuinfo.min_freq = min_pss_ctl * cpu->pstate.scaling; - } - - if (turbo_absent) - policy->cpuinfo.max_freq = cpu->pstate.max_pstate * - cpu->pstate.scaling; - else { - policy->cpuinfo.max_freq = cpu->pstate.turbo_pstate * - cpu->pstate.scaling; - /* - * The _PSS table doesn't contain whole turbo frequency range. - * This just contains +1 MHZ above the max non turbo frequency, - * with control value corresponding to max turbo ratio. But - * when cpufreq set policy is called, it will call with this - * max frequency, which will cause a reduced performance as - * this driver uses real max turbo frequency as the max - * frequeny. So correct this frequency in _PSS table to - * correct max turbo frequency based on the turbo ratio. - * Also need to convert to MHz as _PSS freq is in MHz. - */ - cpu->acpi_perf_data.states[0].core_frequency = - turbo_pss_ctl * 100; - } - - pr_debug("intel_pstate: Updated limits using _PSS 0x%x 0x%x 0x%x\n", - cpu->pstate.min_pstate, cpu->pstate.max_pstate, - cpu->pstate.turbo_pstate); - pr_debug("intel_pstate: policy max_freq=%d Khz min_freq = %d KHz\n", - policy->cpuinfo.max_freq, policy->cpuinfo.min_freq); - - return 0; -} - -static int intel_pstate_exit_perf_limits(struct cpufreq_policy *policy) -{ - struct cpudata *cpu; - - if (!no_acpi_perf) - return 0; - - cpu = all_cpu_data[policy->cpu]; - acpi_processor_unregister_performance(policy->cpu); - return 0; -} - -#else -static int intel_pstate_init_perf_limits(struct cpufreq_policy *policy) -{ - return 0; -} - -static int intel_pstate_exit_perf_limits(struct cpufreq_policy *policy) -{ - return 0; -} -#endif - static inline void pid_reset(struct _pid *pid, int setpoint, int busy, int deadband, int integral) { pid->setpoint = setpoint; @@ -684,36 +525,34 @@ static void __init intel_pstate_sysfs_expose_params(void) static void intel_pstate_hwp_enable(struct cpudata *cpudata) { - pr_info("intel_pstate: HWP enabled\n"); - wrmsrl_on_cpu(cpudata->cpu, MSR_PM_ENABLE, 0x1); } -static int byt_get_min_pstate(void) +static int atom_get_min_pstate(void) { u64 value; - rdmsrl(BYT_RATIOS, value); + rdmsrl(ATOM_RATIOS, value); return (value >> 8) & 0x7F; } -static int byt_get_max_pstate(void) +static int atom_get_max_pstate(void) { u64 value; - rdmsrl(BYT_RATIOS, value); + rdmsrl(ATOM_RATIOS, value); return (value >> 16) & 0x7F; } -static int byt_get_turbo_pstate(void) +static int atom_get_turbo_pstate(void) { u64 value; - rdmsrl(BYT_TURBO_RATIOS, value); + rdmsrl(ATOM_TURBO_RATIOS, value); return value & 0x7F; } -static void byt_set_pstate(struct cpudata *cpudata, int pstate) +static void atom_set_pstate(struct cpudata *cpudata, int pstate) { u64 val; int32_t vid_fp; @@ -738,27 +577,42 @@ static void byt_set_pstate(struct cpudata *cpudata, int pstate) wrmsrl_on_cpu(cpudata->cpu, MSR_IA32_PERF_CTL, val); } -#define BYT_BCLK_FREQS 5 -static int byt_freq_table[BYT_BCLK_FREQS] = { 833, 1000, 1333, 1167, 800}; - -static int byt_get_scaling(void) +static int silvermont_get_scaling(void) { u64 value; int i; + /* Defined in Table 35-6 from SDM (Sept 2015) */ + static int silvermont_freq_table[] = { + 83300, 100000, 133300, 116700, 80000}; rdmsrl(MSR_FSB_FREQ, value); - i = value & 0x3; + i = value & 0x7; + WARN_ON(i > 4); + + return silvermont_freq_table[i]; +} - BUG_ON(i > BYT_BCLK_FREQS); +static int airmont_get_scaling(void) +{ + u64 value; + int i; + /* Defined in Table 35-10 from SDM (Sept 2015) */ + static int airmont_freq_table[] = { + 83300, 100000, 133300, 116700, 80000, + 93300, 90000, 88900, 87500}; - return byt_freq_table[i] * 100; + rdmsrl(MSR_FSB_FREQ, value); + i = value & 0xF; + WARN_ON(i > 8); + + return airmont_freq_table[i]; } -static void byt_get_vid(struct cpudata *cpudata) +static void atom_get_vid(struct cpudata *cpudata) { u64 value; - rdmsrl(BYT_VIDS, value); + rdmsrl(ATOM_VIDS, value); cpudata->vid.min = int_tofp((value >> 8) & 0x7f); cpudata->vid.max = int_tofp((value >> 16) & 0x7f); cpudata->vid.ratio = div_fp( @@ -766,7 +620,7 @@ static void byt_get_vid(struct cpudata *cpudata) int_tofp(cpudata->pstate.max_pstate - cpudata->pstate.min_pstate)); - rdmsrl(BYT_TURBO_VIDS, value); + rdmsrl(ATOM_TURBO_VIDS, value); cpudata->vid.turbo = value & 0x7f; } @@ -887,7 +741,7 @@ static struct cpu_defaults core_params = { }, }; -static struct cpu_defaults byt_params = { +static struct cpu_defaults silvermont_params = { .pid_policy = { .sample_rate_ms = 10, .deadband = 0, @@ -897,13 +751,33 @@ static struct cpu_defaults byt_params = { .i_gain_pct = 4, }, .funcs = { - .get_max = byt_get_max_pstate, - .get_max_physical = byt_get_max_pstate, - .get_min = byt_get_min_pstate, - .get_turbo = byt_get_turbo_pstate, - .set = byt_set_pstate, - .get_scaling = byt_get_scaling, - .get_vid = byt_get_vid, + .get_max = atom_get_max_pstate, + .get_max_physical = atom_get_max_pstate, + .get_min = atom_get_min_pstate, + .get_turbo = atom_get_turbo_pstate, + .set = atom_set_pstate, + .get_scaling = silvermont_get_scaling, + .get_vid = atom_get_vid, + }, +}; + +static struct cpu_defaults airmont_params = { + .pid_policy = { + .sample_rate_ms = 10, + .deadband = 0, + .setpoint = 60, + .p_gain_pct = 14, + .d_gain_pct = 0, + .i_gain_pct = 4, + }, + .funcs = { + .get_max = atom_get_max_pstate, + .get_max_physical = atom_get_max_pstate, + .get_min = atom_get_min_pstate, + .get_turbo = atom_get_turbo_pstate, + .set = atom_set_pstate, + .get_scaling = airmont_get_scaling, + .get_vid = atom_get_vid, }, }; @@ -940,23 +814,12 @@ static void intel_pstate_get_min_max(struct cpudata *cpu, int *min, int *max) * policy, or by cpu specific default values determined through * experimentation. */ - if (limits->max_perf_ctl && limits->max_sysfs_pct >= - limits->max_policy_pct) { - *max = limits->max_perf_ctl; - } else { - max_perf_adj = fp_toint(mul_fp(int_tofp(max_perf), - limits->max_perf)); - *max = clamp_t(int, max_perf_adj, cpu->pstate.min_pstate, - cpu->pstate.turbo_pstate); - } + max_perf_adj = fp_toint(mul_fp(int_tofp(max_perf), limits->max_perf)); + *max = clamp_t(int, max_perf_adj, + cpu->pstate.min_pstate, cpu->pstate.turbo_pstate); - if (limits->min_perf_ctl) { - *min = limits->min_perf_ctl; - } else { - min_perf = fp_toint(mul_fp(int_tofp(max_perf), - limits->min_perf)); - *min = clamp_t(int, min_perf, cpu->pstate.min_pstate, max_perf); - } + min_perf = fp_toint(mul_fp(int_tofp(max_perf), limits->min_perf)); + *min = clamp_t(int, min_perf, cpu->pstate.min_pstate, max_perf); } static void intel_pstate_set_pstate(struct cpudata *cpu, int pstate, bool force) @@ -1155,7 +1018,7 @@ static void intel_pstate_timer_func(unsigned long __data) static const struct x86_cpu_id intel_pstate_cpu_ids[] = { ICPU(0x2a, core_params), ICPU(0x2d, core_params), - ICPU(0x37, byt_params), + ICPU(0x37, silvermont_params), ICPU(0x3a, core_params), ICPU(0x3c, core_params), ICPU(0x3d, core_params), @@ -1164,7 +1027,7 @@ static const struct x86_cpu_id intel_pstate_cpu_ids[] = { ICPU(0x45, core_params), ICPU(0x46, core_params), ICPU(0x47, core_params), - ICPU(0x4c, byt_params), + ICPU(0x4c, airmont_params), ICPU(0x4e, core_params), ICPU(0x4f, core_params), ICPU(0x5e, core_params), @@ -1231,12 +1094,6 @@ static unsigned int intel_pstate_get(unsigned int cpu_num) static int intel_pstate_set_policy(struct cpufreq_policy *policy) { -#if IS_ENABLED(CONFIG_ACPI) - struct cpudata *cpu; - int i; -#endif - pr_debug("intel_pstate: %s max %u policy->max %u\n", __func__, - policy->cpuinfo.max_freq, policy->max); if (!policy->cpuinfo.max_freq) return -ENODEV; @@ -1272,23 +1129,6 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy) limits->max_perf = div_fp(int_tofp(limits->max_perf_pct), int_tofp(100)); -#if IS_ENABLED(CONFIG_ACPI) - cpu = all_cpu_data[policy->cpu]; - for (i = 0; i < cpu->acpi_perf_data.state_count; i++) { - int control; - - control = convert_to_native_pstate_format(cpu, i); - if (control * cpu->pstate.scaling == policy->max) - limits->max_perf_ctl = control; - if (control * cpu->pstate.scaling == policy->min) - limits->min_perf_ctl = control; - } - - pr_debug("intel_pstate: max %u policy_max %u perf_ctl [0x%x-0x%x]\n", - policy->cpuinfo.max_freq, policy->max, limits->min_perf_ctl, - limits->max_perf_ctl); -#endif - if (hwp_active) intel_pstate_hwp_set(); @@ -1343,30 +1183,18 @@ static int intel_pstate_cpu_init(struct cpufreq_policy *policy) policy->cpuinfo.min_freq = cpu->pstate.min_pstate * cpu->pstate.scaling; policy->cpuinfo.max_freq = cpu->pstate.turbo_pstate * cpu->pstate.scaling; - if (!no_acpi_perf) - intel_pstate_init_perf_limits(policy); - /* - * If there is no acpi perf data or error, we ignore and use Intel P - * state calculated limits, So this is not fatal error. - */ policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; cpumask_set_cpu(policy->cpu, policy->cpus); return 0; } -static int intel_pstate_cpu_exit(struct cpufreq_policy *policy) -{ - return intel_pstate_exit_perf_limits(policy); -} - static struct cpufreq_driver intel_pstate_driver = { .flags = CPUFREQ_CONST_LOOPS, .verify = intel_pstate_verify_policy, .setpolicy = intel_pstate_set_policy, .get = intel_pstate_get, .init = intel_pstate_cpu_init, - .exit = intel_pstate_cpu_exit, .stop_cpu = intel_pstate_stop_cpu, .name = "intel_pstate", }; @@ -1408,6 +1236,7 @@ static void copy_cpu_funcs(struct pstate_funcs *funcs) } #if IS_ENABLED(CONFIG_ACPI) +#include <acpi/processor.h> static bool intel_pstate_no_acpi_pss(void) { @@ -1557,8 +1386,10 @@ static int __init intel_pstate_init(void) if (!all_cpu_data) return -ENOMEM; - if (static_cpu_has_safe(X86_FEATURE_HWP) && !no_hwp) + if (static_cpu_has_safe(X86_FEATURE_HWP) && !no_hwp) { + pr_info("intel_pstate: HWP enabled\n"); hwp_active++; + } if (!hwp_active && hwp_only) goto out; @@ -1593,15 +1424,14 @@ static int __init intel_pstate_setup(char *str) if (!strcmp(str, "disable")) no_load = 1; - if (!strcmp(str, "no_hwp")) + if (!strcmp(str, "no_hwp")) { + pr_info("intel_pstate: HWP disabled\n"); no_hwp = 1; + } if (!strcmp(str, "force")) force_load = 1; if (!strcmp(str, "hwp_only")) hwp_only = 1; - if (!strcmp(str, "no_acpi")) - no_acpi_perf = 1; - return 0; } early_param("intel_pstate", intel_pstate_setup); diff --git a/drivers/cpufreq/s5pv210-cpufreq.c b/drivers/cpufreq/s5pv210-cpufreq.c index 9e231f52150c..051a8a8224cd 100644 --- a/drivers/cpufreq/s5pv210-cpufreq.c +++ b/drivers/cpufreq/s5pv210-cpufreq.c @@ -212,11 +212,11 @@ static void s5pv210_set_refresh(enum s5pv210_dmc_port ch, unsigned long freq) /* Find current DRAM frequency */ tmp = s5pv210_dram_conf[ch].freq; - do_div(tmp, freq); + tmp /= freq; tmp1 = s5pv210_dram_conf[ch].refresh; - do_div(tmp1, tmp); + tmp1 /= tmp; __raw_writel(tmp1, reg); } diff --git a/drivers/crypto/ccp/ccp-platform.c b/drivers/crypto/ccp/ccp-platform.c index 8b923b7e9389..01b50cb4c982 100644 --- a/drivers/crypto/ccp/ccp-platform.c +++ b/drivers/crypto/ccp/ccp-platform.c @@ -94,6 +94,7 @@ static int ccp_platform_probe(struct platform_device *pdev) struct ccp_device *ccp; struct ccp_platform *ccp_platform; struct device *dev = &pdev->dev; + enum dev_dma_attr attr; struct resource *ior; int ret; @@ -118,18 +119,24 @@ static int ccp_platform_probe(struct platform_device *pdev) } ccp->io_regs = ccp->io_map; - ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48)); - if (ret) { - dev_err(dev, "dma_set_mask_and_coherent failed (%d)\n", ret); + attr = device_get_dma_attr(dev); + if (attr == DEV_DMA_NOT_SUPPORTED) { + dev_err(dev, "DMA is not supported"); goto e_err; } - ccp_platform->coherent = device_dma_is_coherent(ccp->dev); + ccp_platform->coherent = (attr == DEV_DMA_COHERENT); if (ccp_platform->coherent) ccp->axcache = CACHE_WB_NO_ALLOC; else ccp->axcache = CACHE_NONE; + ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48)); + if (ret) { + dev_err(dev, "dma_set_mask_and_coherent failed (%d)\n", ret); + goto e_err; + } + dev_set_drvdata(dev, ccp); ret = ccp_init(ccp); diff --git a/drivers/crypto/qat/qat_common/adf_ctl_drv.c b/drivers/crypto/qat/qat_common/adf_ctl_drv.c index 03856ad280b9..473d36d91644 100644 --- a/drivers/crypto/qat/qat_common/adf_ctl_drv.c +++ b/drivers/crypto/qat/qat_common/adf_ctl_drv.c @@ -198,7 +198,7 @@ static int adf_copy_key_value_data(struct adf_accel_dev *accel_dev, goto out_err; } - params_head = section_head->params; + params_head = section.params; while (params_head) { if (copy_from_user(&key_val, (void __user *)params_head, diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index 4e55239c7a30..53d22eb73b56 100644 --- a/drivers/dma/at_hdmac.c +++ b/drivers/dma/at_hdmac.c @@ -729,8 +729,8 @@ atc_prep_dma_interleaved(struct dma_chan *chan, return NULL; dev_info(chan2dev(chan), - "%s: src=0x%08x, dest=0x%08x, numf=%d, frame_size=%d, flags=0x%lx\n", - __func__, xt->src_start, xt->dst_start, xt->numf, + "%s: src=%pad, dest=%pad, numf=%d, frame_size=%d, flags=0x%lx\n", + __func__, &xt->src_start, &xt->dst_start, xt->numf, xt->frame_size, flags); /* @@ -824,8 +824,8 @@ atc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, u32 ctrla; u32 ctrlb; - dev_vdbg(chan2dev(chan), "prep_dma_memcpy: d0x%x s0x%x l0x%zx f0x%lx\n", - dest, src, len, flags); + dev_vdbg(chan2dev(chan), "prep_dma_memcpy: d%pad s%pad l0x%zx f0x%lx\n", + &dest, &src, len, flags); if (unlikely(!len)) { dev_dbg(chan2dev(chan), "prep_dma_memcpy: length is zero!\n"); @@ -938,8 +938,8 @@ atc_prep_dma_memset(struct dma_chan *chan, dma_addr_t dest, int value, void __iomem *vaddr; dma_addr_t paddr; - dev_vdbg(chan2dev(chan), "%s: d0x%x v0x%x l0x%zx f0x%lx\n", __func__, - dest, value, len, flags); + dev_vdbg(chan2dev(chan), "%s: d%pad v0x%x l0x%zx f0x%lx\n", __func__, + &dest, value, len, flags); if (unlikely(!len)) { dev_dbg(chan2dev(chan), "%s: length is zero!\n", __func__); @@ -1022,8 +1022,8 @@ atc_prep_dma_memset_sg(struct dma_chan *chan, dma_addr_t dest = sg_dma_address(sg); size_t len = sg_dma_len(sg); - dev_vdbg(chan2dev(chan), "%s: d0x%08x, l0x%zx\n", - __func__, dest, len); + dev_vdbg(chan2dev(chan), "%s: d%pad, l0x%zx\n", + __func__, &dest, len); if (!is_dma_fill_aligned(chan->device, dest, 0, len)) { dev_err(chan2dev(chan), "%s: buffer is not aligned\n", @@ -1439,9 +1439,9 @@ atc_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, unsigned int periods = buf_len / period_len; unsigned int i; - dev_vdbg(chan2dev(chan), "prep_dma_cyclic: %s buf@0x%08x - %d (%d/%d)\n", + dev_vdbg(chan2dev(chan), "prep_dma_cyclic: %s buf@%pad - %d (%d/%d)\n", direction == DMA_MEM_TO_DEV ? "TO DEVICE" : "FROM DEVICE", - buf_addr, + &buf_addr, periods, buf_len, period_len); if (unlikely(!atslave || !buf_len || !period_len)) { diff --git a/drivers/dma/at_hdmac_regs.h b/drivers/dma/at_hdmac_regs.h index d1cfc8c876f9..7f58f06157f6 100644 --- a/drivers/dma/at_hdmac_regs.h +++ b/drivers/dma/at_hdmac_regs.h @@ -385,9 +385,9 @@ static void vdbg_dump_regs(struct at_dma_chan *atchan) {} static void atc_dump_lli(struct at_dma_chan *atchan, struct at_lli *lli) { dev_crit(chan2dev(&atchan->chan_common), - " desc: s0x%x d0x%x ctrl0x%x:0x%x l0x%x\n", - lli->saddr, lli->daddr, - lli->ctrla, lli->ctrlb, lli->dscr); + " desc: s%pad d%pad ctrl0x%x:0x%x l0x%pad\n", + &lli->saddr, &lli->daddr, + lli->ctrla, lli->ctrlb, &lli->dscr); } diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c index b5e132d4bae5..7f039de143f0 100644 --- a/drivers/dma/at_xdmac.c +++ b/drivers/dma/at_xdmac.c @@ -920,8 +920,8 @@ at_xdmac_interleaved_queue_desc(struct dma_chan *chan, desc->lld.mbr_cfg = chan_cc; dev_dbg(chan2dev(chan), - "%s: lld: mbr_sa=0x%08x, mbr_da=0x%08x, mbr_ubc=0x%08x, mbr_cfg=0x%08x\n", - __func__, desc->lld.mbr_sa, desc->lld.mbr_da, + "%s: lld: mbr_sa=%pad, mbr_da=%pad, mbr_ubc=0x%08x, mbr_cfg=0x%08x\n", + __func__, &desc->lld.mbr_sa, &desc->lld.mbr_da, desc->lld.mbr_ubc, desc->lld.mbr_cfg); /* Chain lld. */ @@ -953,8 +953,8 @@ at_xdmac_prep_interleaved(struct dma_chan *chan, if ((xt->numf > 1) && (xt->frame_size > 1)) return NULL; - dev_dbg(chan2dev(chan), "%s: src=0x%08x, dest=0x%08x, numf=%d, frame_size=%d, flags=0x%lx\n", - __func__, xt->src_start, xt->dst_start, xt->numf, + dev_dbg(chan2dev(chan), "%s: src=%pad, dest=%pad, numf=%d, frame_size=%d, flags=0x%lx\n", + __func__, &xt->src_start, &xt->dst_start, xt->numf, xt->frame_size, flags); src_addr = xt->src_start; @@ -1179,8 +1179,8 @@ static struct at_xdmac_desc *at_xdmac_memset_create_desc(struct dma_chan *chan, desc->lld.mbr_cfg = chan_cc; dev_dbg(chan2dev(chan), - "%s: lld: mbr_da=0x%08x, mbr_ds=0x%08x, mbr_ubc=0x%08x, mbr_cfg=0x%08x\n", - __func__, desc->lld.mbr_da, desc->lld.mbr_ds, desc->lld.mbr_ubc, + "%s: lld: mbr_da=%pad, mbr_ds=%pad, mbr_ubc=0x%08x, mbr_cfg=0x%08x\n", + __func__, &desc->lld.mbr_da, &desc->lld.mbr_ds, desc->lld.mbr_ubc, desc->lld.mbr_cfg); return desc; @@ -1193,8 +1193,8 @@ at_xdmac_prep_dma_memset(struct dma_chan *chan, dma_addr_t dest, int value, struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan); struct at_xdmac_desc *desc; - dev_dbg(chan2dev(chan), "%s: dest=0x%08x, len=%d, pattern=0x%x, flags=0x%lx\n", - __func__, dest, len, value, flags); + dev_dbg(chan2dev(chan), "%s: dest=%pad, len=%d, pattern=0x%x, flags=0x%lx\n", + __func__, &dest, len, value, flags); if (unlikely(!len)) return NULL; @@ -1229,8 +1229,8 @@ at_xdmac_prep_dma_memset_sg(struct dma_chan *chan, struct scatterlist *sgl, /* Prepare descriptors. */ for_each_sg(sgl, sg, sg_len, i) { - dev_dbg(chan2dev(chan), "%s: dest=0x%08x, len=%d, pattern=0x%x, flags=0x%lx\n", - __func__, sg_dma_address(sg), sg_dma_len(sg), + dev_dbg(chan2dev(chan), "%s: dest=%pad, len=%d, pattern=0x%x, flags=0x%lx\n", + __func__, &sg_dma_address(sg), sg_dma_len(sg), value, flags); desc = at_xdmac_memset_create_desc(chan, atchan, sg_dma_address(sg), diff --git a/drivers/dma/edma.c b/drivers/dma/edma.c index 6b03e4e84e6b..0675e268d577 100644 --- a/drivers/dma/edma.c +++ b/drivers/dma/edma.c @@ -107,7 +107,7 @@ /* CCCFG register */ #define GET_NUM_DMACH(x) (x & 0x7) /* bits 0-2 */ -#define GET_NUM_QDMACH(x) (x & 0x70 >> 4) /* bits 4-6 */ +#define GET_NUM_QDMACH(x) ((x & 0x70) >> 4) /* bits 4-6 */ #define GET_NUM_PAENTRY(x) ((x & 0x7000) >> 12) /* bits 12-14 */ #define GET_NUM_EVQUE(x) ((x & 0x70000) >> 16) /* bits 16-18 */ #define GET_NUM_REGN(x) ((x & 0x300000) >> 20) /* bits 20-21 */ @@ -1565,7 +1565,7 @@ static void edma_tc_set_pm_state(struct edma_tc *tc, bool enable) struct platform_device *tc_pdev; int ret; - if (!tc) + if (!IS_ENABLED(CONFIG_OF) || !tc) return; tc_pdev = of_find_device_by_node(tc->node); diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index 7058d58ba588..0f6fd42f55ca 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -1462,7 +1462,7 @@ err_firmware: #define EVENT_REMAP_CELLS 3 -static int __init sdma_event_remap(struct sdma_engine *sdma) +static int sdma_event_remap(struct sdma_engine *sdma) { struct device_node *np = sdma->dev->of_node; struct device_node *gpr_np = of_parse_phandle(np, "gpr", 0); diff --git a/drivers/dma/sh/usb-dmac.c b/drivers/dma/sh/usb-dmac.c index ebd8a5f398b0..f1bcc2a163b3 100644 --- a/drivers/dma/sh/usb-dmac.c +++ b/drivers/dma/sh/usb-dmac.c @@ -679,8 +679,11 @@ static int usb_dmac_runtime_suspend(struct device *dev) struct usb_dmac *dmac = dev_get_drvdata(dev); int i; - for (i = 0; i < dmac->n_channels; ++i) + for (i = 0; i < dmac->n_channels; ++i) { + if (!dmac->channels[i].iomem) + break; usb_dmac_chan_halt(&dmac->channels[i]); + } return 0; } @@ -799,11 +802,10 @@ static int usb_dmac_probe(struct platform_device *pdev) ret = pm_runtime_get_sync(&pdev->dev); if (ret < 0) { dev_err(&pdev->dev, "runtime PM get sync failed (%d)\n", ret); - return ret; + goto error_pm; } ret = usb_dmac_init(dmac); - pm_runtime_put(&pdev->dev); if (ret) { dev_err(&pdev->dev, "failed to reset device\n"); @@ -851,10 +853,13 @@ static int usb_dmac_probe(struct platform_device *pdev) if (ret < 0) goto error; + pm_runtime_put(&pdev->dev); return 0; error: of_dma_controller_free(pdev->dev.of_node); + pm_runtime_put(&pdev->dev); +error_pm: pm_runtime_disable(&pdev->dev); return ret; } diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index f51d376d10ba..c2f5117fd8cb 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -3675,6 +3675,11 @@ static int pci_probe(struct pci_dev *dev, reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, ~0); ohci->it_context_support = reg_read(ohci, OHCI1394_IsoXmitIntMaskSet); + /* JMicron JMB38x often shows 0 at first read, just ignore it */ + if (!ohci->it_context_support) { + ohci_notice(ohci, "overriding IsoXmitIntMask\n"); + ohci->it_context_support = 0xf; + } reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, ~0); ohci->it_context_mask = ohci->it_context_support; ohci->n_it = hweight32(ohci->it_context_mask); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 615ce6d464fb..306f75700bf8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -389,7 +389,6 @@ struct amdgpu_clock { * Fences. */ struct amdgpu_fence_driver { - struct amdgpu_ring *ring; uint64_t gpu_addr; volatile uint32_t *cpu_addr; /* sync_seq is protected by ring emission lock */ @@ -398,7 +397,7 @@ struct amdgpu_fence_driver { bool initialized; struct amdgpu_irq_src *irq_src; unsigned irq_type; - struct delayed_work lockup_work; + struct timer_list fallback_timer; wait_queue_head_t fence_queue; }; @@ -917,8 +916,8 @@ struct amdgpu_ring { #define AMDGPU_VM_FAULT_STOP_ALWAYS 2 struct amdgpu_vm_pt { - struct amdgpu_bo *bo; - uint64_t addr; + struct amdgpu_bo *bo; + uint64_t addr; }; struct amdgpu_vm_id { @@ -926,8 +925,6 @@ struct amdgpu_vm_id { uint64_t pd_gpu_addr; /* last flushed PD/PT update */ struct fence *flushed_updates; - /* last use of vmid */ - struct fence *last_id_use; }; struct amdgpu_vm { @@ -957,24 +954,70 @@ struct amdgpu_vm { /* for id and flush management per ring */ struct amdgpu_vm_id ids[AMDGPU_MAX_RINGS]; + /* for interval tree */ + spinlock_t it_lock; }; struct amdgpu_vm_manager { - struct fence *active[AMDGPU_NUM_VM]; - uint32_t max_pfn; + struct { + struct fence *active; + atomic_long_t owner; + } ids[AMDGPU_NUM_VM]; + + uint32_t max_pfn; /* number of VMIDs */ - unsigned nvm; + unsigned nvm; /* vram base address for page table entry */ - u64 vram_base_offset; + u64 vram_base_offset; /* is vm enabled? */ - bool enabled; - /* for hw to save the PD addr on suspend/resume */ - uint32_t saved_table_addr[AMDGPU_NUM_VM]; + bool enabled; /* vm pte handling */ const struct amdgpu_vm_pte_funcs *vm_pte_funcs; struct amdgpu_ring *vm_pte_funcs_ring; }; +void amdgpu_vm_manager_fini(struct amdgpu_device *adev); +int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm); +void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm); +struct amdgpu_bo_list_entry *amdgpu_vm_get_bos(struct amdgpu_device *adev, + struct amdgpu_vm *vm, + struct list_head *head); +int amdgpu_vm_grab_id(struct amdgpu_vm *vm, struct amdgpu_ring *ring, + struct amdgpu_sync *sync); +void amdgpu_vm_flush(struct amdgpu_ring *ring, + struct amdgpu_vm *vm, + struct fence *updates); +void amdgpu_vm_fence(struct amdgpu_device *adev, + struct amdgpu_vm *vm, + struct fence *fence); +uint64_t amdgpu_vm_map_gart(struct amdgpu_device *adev, uint64_t addr); +int amdgpu_vm_update_page_directory(struct amdgpu_device *adev, + struct amdgpu_vm *vm); +int amdgpu_vm_clear_freed(struct amdgpu_device *adev, + struct amdgpu_vm *vm); +int amdgpu_vm_clear_invalids(struct amdgpu_device *adev, struct amdgpu_vm *vm, + struct amdgpu_sync *sync); +int amdgpu_vm_bo_update(struct amdgpu_device *adev, + struct amdgpu_bo_va *bo_va, + struct ttm_mem_reg *mem); +void amdgpu_vm_bo_invalidate(struct amdgpu_device *adev, + struct amdgpu_bo *bo); +struct amdgpu_bo_va *amdgpu_vm_bo_find(struct amdgpu_vm *vm, + struct amdgpu_bo *bo); +struct amdgpu_bo_va *amdgpu_vm_bo_add(struct amdgpu_device *adev, + struct amdgpu_vm *vm, + struct amdgpu_bo *bo); +int amdgpu_vm_bo_map(struct amdgpu_device *adev, + struct amdgpu_bo_va *bo_va, + uint64_t addr, uint64_t offset, + uint64_t size, uint32_t flags); +int amdgpu_vm_bo_unmap(struct amdgpu_device *adev, + struct amdgpu_bo_va *bo_va, + uint64_t addr); +void amdgpu_vm_bo_rmv(struct amdgpu_device *adev, + struct amdgpu_bo_va *bo_va); +int amdgpu_vm_free_job(struct amdgpu_job *job); + /* * context related structures */ @@ -1211,6 +1254,7 @@ struct amdgpu_cs_parser { /* relocations */ struct amdgpu_bo_list_entry *vm_bos; struct list_head validated; + struct fence *fence; struct amdgpu_ib *ibs; uint32_t num_ibs; @@ -1226,7 +1270,7 @@ struct amdgpu_job { struct amdgpu_device *adev; struct amdgpu_ib *ibs; uint32_t num_ibs; - struct mutex job_lock; + void *owner; struct amdgpu_user_fence uf; int (*free_job)(struct amdgpu_job *job); }; @@ -2257,11 +2301,6 @@ void amdgpu_pci_config_reset(struct amdgpu_device *adev); bool amdgpu_card_posted(struct amdgpu_device *adev); void amdgpu_update_display_priority(struct amdgpu_device *adev); bool amdgpu_boot_test_post_card(struct amdgpu_device *adev); -struct amdgpu_cs_parser *amdgpu_cs_parser_create(struct amdgpu_device *adev, - struct drm_file *filp, - struct amdgpu_ctx *ctx, - struct amdgpu_ib *ibs, - uint32_t num_ibs); int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data); int amdgpu_cs_get_ring(struct amdgpu_device *adev, u32 ip_type, @@ -2319,49 +2358,6 @@ long amdgpu_kms_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); /* - * vm - */ -int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm); -void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm); -struct amdgpu_bo_list_entry *amdgpu_vm_get_bos(struct amdgpu_device *adev, - struct amdgpu_vm *vm, - struct list_head *head); -int amdgpu_vm_grab_id(struct amdgpu_vm *vm, struct amdgpu_ring *ring, - struct amdgpu_sync *sync); -void amdgpu_vm_flush(struct amdgpu_ring *ring, - struct amdgpu_vm *vm, - struct fence *updates); -void amdgpu_vm_fence(struct amdgpu_device *adev, - struct amdgpu_vm *vm, - struct amdgpu_fence *fence); -uint64_t amdgpu_vm_map_gart(struct amdgpu_device *adev, uint64_t addr); -int amdgpu_vm_update_page_directory(struct amdgpu_device *adev, - struct amdgpu_vm *vm); -int amdgpu_vm_clear_freed(struct amdgpu_device *adev, - struct amdgpu_vm *vm); -int amdgpu_vm_clear_invalids(struct amdgpu_device *adev, - struct amdgpu_vm *vm, struct amdgpu_sync *sync); -int amdgpu_vm_bo_update(struct amdgpu_device *adev, - struct amdgpu_bo_va *bo_va, - struct ttm_mem_reg *mem); -void amdgpu_vm_bo_invalidate(struct amdgpu_device *adev, - struct amdgpu_bo *bo); -struct amdgpu_bo_va *amdgpu_vm_bo_find(struct amdgpu_vm *vm, - struct amdgpu_bo *bo); -struct amdgpu_bo_va *amdgpu_vm_bo_add(struct amdgpu_device *adev, - struct amdgpu_vm *vm, - struct amdgpu_bo *bo); -int amdgpu_vm_bo_map(struct amdgpu_device *adev, - struct amdgpu_bo_va *bo_va, - uint64_t addr, uint64_t offset, - uint64_t size, uint32_t flags); -int amdgpu_vm_bo_unmap(struct amdgpu_device *adev, - struct amdgpu_bo_va *bo_va, - uint64_t addr); -void amdgpu_vm_bo_rmv(struct amdgpu_device *adev, - struct amdgpu_bo_va *bo_va); -int amdgpu_vm_free_job(struct amdgpu_job *job); -/* * functions used by amdgpu_encoder.c */ struct amdgpu_afmt_acr { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index dfc4d02c7a38..3afcf0237c25 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -127,30 +127,6 @@ int amdgpu_cs_get_ring(struct amdgpu_device *adev, u32 ip_type, return 0; } -struct amdgpu_cs_parser *amdgpu_cs_parser_create(struct amdgpu_device *adev, - struct drm_file *filp, - struct amdgpu_ctx *ctx, - struct amdgpu_ib *ibs, - uint32_t num_ibs) -{ - struct amdgpu_cs_parser *parser; - int i; - - parser = kzalloc(sizeof(struct amdgpu_cs_parser), GFP_KERNEL); - if (!parser) - return NULL; - - parser->adev = adev; - parser->filp = filp; - parser->ctx = ctx; - parser->ibs = ibs; - parser->num_ibs = num_ibs; - for (i = 0; i < num_ibs; i++) - ibs[i].ctx = ctx; - - return parser; -} - int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data) { union drm_amdgpu_cs *cs = data; @@ -463,8 +439,18 @@ static int cmp_size_smaller_first(void *priv, struct list_head *a, return (int)la->robj->tbo.num_pages - (int)lb->robj->tbo.num_pages; } -static void amdgpu_cs_parser_fini_early(struct amdgpu_cs_parser *parser, int error, bool backoff) +/** + * cs_parser_fini() - clean parser states + * @parser: parser structure holding parsing context. + * @error: error number + * + * If error is set than unvalidate buffer, otherwise just free memory + * used by parsing context. + **/ +static void amdgpu_cs_parser_fini(struct amdgpu_cs_parser *parser, int error, bool backoff) { + unsigned i; + if (!error) { /* Sort the buffer list from the smallest to largest buffer, * which affects the order of buffers in the LRU list. @@ -479,17 +465,14 @@ static void amdgpu_cs_parser_fini_early(struct amdgpu_cs_parser *parser, int err list_sort(NULL, &parser->validated, cmp_size_smaller_first); ttm_eu_fence_buffer_objects(&parser->ticket, - &parser->validated, - &parser->ibs[parser->num_ibs-1].fence->base); + &parser->validated, + parser->fence); } else if (backoff) { ttm_eu_backoff_reservation(&parser->ticket, &parser->validated); } -} + fence_put(parser->fence); -static void amdgpu_cs_parser_fini_late(struct amdgpu_cs_parser *parser) -{ - unsigned i; if (parser->ctx) amdgpu_ctx_put(parser->ctx); if (parser->bo_list) @@ -499,31 +482,12 @@ static void amdgpu_cs_parser_fini_late(struct amdgpu_cs_parser *parser) for (i = 0; i < parser->nchunks; i++) drm_free_large(parser->chunks[i].kdata); kfree(parser->chunks); - if (!amdgpu_enable_scheduler) - { - if (parser->ibs) - for (i = 0; i < parser->num_ibs; i++) - amdgpu_ib_free(parser->adev, &parser->ibs[i]); - kfree(parser->ibs); - if (parser->uf.bo) - drm_gem_object_unreference_unlocked(&parser->uf.bo->gem_base); - } - - kfree(parser); -} - -/** - * cs_parser_fini() - clean parser states - * @parser: parser structure holding parsing context. - * @error: error number - * - * If error is set than unvalidate buffer, otherwise just free memory - * used by parsing context. - **/ -static void amdgpu_cs_parser_fini(struct amdgpu_cs_parser *parser, int error, bool backoff) -{ - amdgpu_cs_parser_fini_early(parser, error, backoff); - amdgpu_cs_parser_fini_late(parser); + if (parser->ibs) + for (i = 0; i < parser->num_ibs; i++) + amdgpu_ib_free(parser->adev, &parser->ibs[i]); + kfree(parser->ibs); + if (parser->uf.bo) + drm_gem_object_unreference_unlocked(&parser->uf.bo->gem_base); } static int amdgpu_bo_vm_update_pte(struct amdgpu_cs_parser *p, @@ -610,15 +574,9 @@ static int amdgpu_cs_ib_vm_chunk(struct amdgpu_device *adev, } r = amdgpu_bo_vm_update_pte(parser, vm); - if (r) { - goto out; - } - amdgpu_cs_sync_rings(parser); - if (!amdgpu_enable_scheduler) - r = amdgpu_ib_schedule(adev, parser->num_ibs, parser->ibs, - parser->filp); + if (!r) + amdgpu_cs_sync_rings(parser); -out: return r; } @@ -828,36 +786,36 @@ int amdgpu_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) union drm_amdgpu_cs *cs = data; struct amdgpu_fpriv *fpriv = filp->driver_priv; struct amdgpu_vm *vm = &fpriv->vm; - struct amdgpu_cs_parser *parser; + struct amdgpu_cs_parser parser = {}; bool reserved_buffers = false; int i, r; if (!adev->accel_working) return -EBUSY; - parser = amdgpu_cs_parser_create(adev, filp, NULL, NULL, 0); - if (!parser) - return -ENOMEM; - r = amdgpu_cs_parser_init(parser, data); + parser.adev = adev; + parser.filp = filp; + + r = amdgpu_cs_parser_init(&parser, data); if (r) { DRM_ERROR("Failed to initialize parser !\n"); - amdgpu_cs_parser_fini(parser, r, false); + amdgpu_cs_parser_fini(&parser, r, false); r = amdgpu_cs_handle_lockup(adev, r); return r; } mutex_lock(&vm->mutex); - r = amdgpu_cs_parser_relocs(parser); + r = amdgpu_cs_parser_relocs(&parser); if (r == -ENOMEM) DRM_ERROR("Not enough memory for command submission!\n"); else if (r && r != -ERESTARTSYS) DRM_ERROR("Failed to process the buffer list %d!\n", r); else if (!r) { reserved_buffers = true; - r = amdgpu_cs_ib_fill(adev, parser); + r = amdgpu_cs_ib_fill(adev, &parser); } if (!r) { - r = amdgpu_cs_dependencies(adev, parser); + r = amdgpu_cs_dependencies(adev, &parser); if (r) DRM_ERROR("Failed in the dependencies handling %d!\n", r); } @@ -865,62 +823,71 @@ int amdgpu_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) if (r) goto out; - for (i = 0; i < parser->num_ibs; i++) - trace_amdgpu_cs(parser, i); + for (i = 0; i < parser.num_ibs; i++) + trace_amdgpu_cs(&parser, i); - r = amdgpu_cs_ib_vm_chunk(adev, parser); + r = amdgpu_cs_ib_vm_chunk(adev, &parser); if (r) goto out; - if (amdgpu_enable_scheduler && parser->num_ibs) { + if (amdgpu_enable_scheduler && parser.num_ibs) { + struct amdgpu_ring * ring = parser.ibs->ring; + struct amd_sched_fence *fence; struct amdgpu_job *job; - struct amdgpu_ring * ring = parser->ibs->ring; + job = kzalloc(sizeof(struct amdgpu_job), GFP_KERNEL); if (!job) { r = -ENOMEM; goto out; } + job->base.sched = &ring->sched; - job->base.s_entity = &parser->ctx->rings[ring->idx].entity; - job->adev = parser->adev; - job->ibs = parser->ibs; - job->num_ibs = parser->num_ibs; - job->base.owner = parser->filp; - mutex_init(&job->job_lock); + job->base.s_entity = &parser.ctx->rings[ring->idx].entity; + job->adev = parser.adev; + job->owner = parser.filp; + job->free_job = amdgpu_cs_free_job; + + job->ibs = parser.ibs; + job->num_ibs = parser.num_ibs; + parser.ibs = NULL; + parser.num_ibs = 0; + if (job->ibs[job->num_ibs - 1].user) { - memcpy(&job->uf, &parser->uf, - sizeof(struct amdgpu_user_fence)); + job->uf = parser.uf; job->ibs[job->num_ibs - 1].user = &job->uf; + parser.uf.bo = NULL; } - job->free_job = amdgpu_cs_free_job; - mutex_lock(&job->job_lock); - r = amd_sched_entity_push_job(&job->base); - if (r) { - mutex_unlock(&job->job_lock); + fence = amd_sched_fence_create(job->base.s_entity, + parser.filp); + if (!fence) { + r = -ENOMEM; amdgpu_cs_free_job(job); kfree(job); goto out; } - cs->out.handle = - amdgpu_ctx_add_fence(parser->ctx, ring, - &job->base.s_fence->base); - parser->ibs[parser->num_ibs - 1].sequence = cs->out.handle; + job->base.s_fence = fence; + parser.fence = fence_get(&fence->base); - list_sort(NULL, &parser->validated, cmp_size_smaller_first); - ttm_eu_fence_buffer_objects(&parser->ticket, - &parser->validated, - &job->base.s_fence->base); + cs->out.handle = amdgpu_ctx_add_fence(parser.ctx, ring, + &fence->base); + job->ibs[job->num_ibs - 1].sequence = cs->out.handle; - mutex_unlock(&job->job_lock); - amdgpu_cs_parser_fini_late(parser); - mutex_unlock(&vm->mutex); - return 0; + trace_amdgpu_cs_ioctl(job); + amd_sched_entity_push_job(&job->base); + + } else { + struct amdgpu_fence *fence; + + r = amdgpu_ib_schedule(adev, parser.num_ibs, parser.ibs, + parser.filp); + fence = parser.ibs[parser.num_ibs - 1].fence; + parser.fence = fence_get(&fence->base); + cs->out.handle = parser.ibs[parser.num_ibs - 1].sequence; } - cs->out.handle = parser->ibs[parser->num_ibs - 1].sequence; out: - amdgpu_cs_parser_fini(parser, r, reserved_buffers); + amdgpu_cs_parser_fini(&parser, r, reserved_buffers); mutex_unlock(&vm->mutex); r = amdgpu_cs_handle_lockup(adev, r); return r; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c index 257d72205bb5..3671f9f220bd 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c @@ -47,6 +47,9 @@ * that the the relevant GPU caches have been flushed. */ +static struct kmem_cache *amdgpu_fence_slab; +static atomic_t amdgpu_fence_slab_ref = ATOMIC_INIT(0); + /** * amdgpu_fence_write - write a fence value * @@ -85,24 +88,6 @@ static u32 amdgpu_fence_read(struct amdgpu_ring *ring) } /** - * amdgpu_fence_schedule_check - schedule lockup check - * - * @ring: pointer to struct amdgpu_ring - * - * Queues a delayed work item to check for lockups. - */ -static void amdgpu_fence_schedule_check(struct amdgpu_ring *ring) -{ - /* - * Do not reset the timer here with mod_delayed_work, - * this can livelock in an interaction with TTM delayed destroy. - */ - queue_delayed_work(system_power_efficient_wq, - &ring->fence_drv.lockup_work, - AMDGPU_FENCE_JIFFIES_TIMEOUT); -} - -/** * amdgpu_fence_emit - emit a fence on the requested ring * * @ring: ring the fence is associated with @@ -118,7 +103,7 @@ int amdgpu_fence_emit(struct amdgpu_ring *ring, void *owner, struct amdgpu_device *adev = ring->adev; /* we are protected by the ring emission mutex */ - *fence = kmalloc(sizeof(struct amdgpu_fence), GFP_KERNEL); + *fence = kmem_cache_alloc(amdgpu_fence_slab, GFP_KERNEL); if ((*fence) == NULL) { return -ENOMEM; } @@ -132,11 +117,23 @@ int amdgpu_fence_emit(struct amdgpu_ring *ring, void *owner, amdgpu_ring_emit_fence(ring, ring->fence_drv.gpu_addr, (*fence)->seq, AMDGPU_FENCE_FLAG_INT); - trace_amdgpu_fence_emit(ring->adev->ddev, ring->idx, (*fence)->seq); return 0; } /** + * amdgpu_fence_schedule_fallback - schedule fallback check + * + * @ring: pointer to struct amdgpu_ring + * + * Start a timer as fallback to our interrupts. + */ +static void amdgpu_fence_schedule_fallback(struct amdgpu_ring *ring) +{ + mod_timer(&ring->fence_drv.fallback_timer, + jiffies + AMDGPU_FENCE_JIFFIES_TIMEOUT); +} + +/** * amdgpu_fence_activity - check for fence activity * * @ring: pointer to struct amdgpu_ring @@ -202,45 +199,38 @@ static bool amdgpu_fence_activity(struct amdgpu_ring *ring) } while (atomic64_xchg(&ring->fence_drv.last_seq, seq) > seq); if (seq < last_emitted) - amdgpu_fence_schedule_check(ring); + amdgpu_fence_schedule_fallback(ring); return wake; } /** - * amdgpu_fence_check_lockup - check for hardware lockup + * amdgpu_fence_process - process a fence * - * @work: delayed work item + * @adev: amdgpu_device pointer + * @ring: ring index the fence is associated with * - * Checks for fence activity and if there is none probe - * the hardware if a lockup occured. + * Checks the current fence value and wakes the fence queue + * if the sequence number has increased (all asics). */ -static void amdgpu_fence_check_lockup(struct work_struct *work) +void amdgpu_fence_process(struct amdgpu_ring *ring) { - struct amdgpu_fence_driver *fence_drv; - struct amdgpu_ring *ring; - - fence_drv = container_of(work, struct amdgpu_fence_driver, - lockup_work.work); - ring = fence_drv->ring; - if (amdgpu_fence_activity(ring)) wake_up_all(&ring->fence_drv.fence_queue); } /** - * amdgpu_fence_process - process a fence + * amdgpu_fence_fallback - fallback for hardware interrupts * - * @adev: amdgpu_device pointer - * @ring: ring index the fence is associated with + * @work: delayed work item * - * Checks the current fence value and wakes the fence queue - * if the sequence number has increased (all asics). + * Checks for fence activity. */ -void amdgpu_fence_process(struct amdgpu_ring *ring) +static void amdgpu_fence_fallback(unsigned long arg) { - if (amdgpu_fence_activity(ring)) - wake_up_all(&ring->fence_drv.fence_queue); + struct amdgpu_ring *ring = (void *)arg; + + amdgpu_fence_process(ring); } /** @@ -290,7 +280,7 @@ static int amdgpu_fence_ring_wait_seq(struct amdgpu_ring *ring, uint64_t seq) if (atomic64_read(&ring->fence_drv.last_seq) >= seq) return 0; - amdgpu_fence_schedule_check(ring); + amdgpu_fence_schedule_fallback(ring); wait_event(ring->fence_drv.fence_queue, ( (signaled = amdgpu_fence_seq_signaled(ring, seq)))); @@ -491,9 +481,8 @@ int amdgpu_fence_driver_init_ring(struct amdgpu_ring *ring) atomic64_set(&ring->fence_drv.last_seq, 0); ring->fence_drv.initialized = false; - INIT_DELAYED_WORK(&ring->fence_drv.lockup_work, - amdgpu_fence_check_lockup); - ring->fence_drv.ring = ring; + setup_timer(&ring->fence_drv.fallback_timer, amdgpu_fence_fallback, + (unsigned long)ring); init_waitqueue_head(&ring->fence_drv.fence_queue); @@ -536,6 +525,13 @@ int amdgpu_fence_driver_init_ring(struct amdgpu_ring *ring) */ int amdgpu_fence_driver_init(struct amdgpu_device *adev) { + if (atomic_inc_return(&amdgpu_fence_slab_ref) == 1) { + amdgpu_fence_slab = kmem_cache_create( + "amdgpu_fence", sizeof(struct amdgpu_fence), 0, + SLAB_HWCACHE_ALIGN, NULL); + if (!amdgpu_fence_slab) + return -ENOMEM; + } if (amdgpu_debugfs_fence_init(adev)) dev_err(adev->dev, "fence debugfs file creation failed\n"); @@ -554,9 +550,12 @@ void amdgpu_fence_driver_fini(struct amdgpu_device *adev) { int i, r; + if (atomic_dec_and_test(&amdgpu_fence_slab_ref)) + kmem_cache_destroy(amdgpu_fence_slab); mutex_lock(&adev->ring_lock); for (i = 0; i < AMDGPU_MAX_RINGS; i++) { struct amdgpu_ring *ring = adev->rings[i]; + if (!ring || !ring->fence_drv.initialized) continue; r = amdgpu_fence_wait_empty(ring); @@ -568,6 +567,7 @@ void amdgpu_fence_driver_fini(struct amdgpu_device *adev) amdgpu_irq_put(adev, ring->fence_drv.irq_src, ring->fence_drv.irq_type); amd_sched_fini(&ring->sched); + del_timer_sync(&ring->fence_drv.fallback_timer); ring->fence_drv.initialized = false; } mutex_unlock(&adev->ring_lock); @@ -751,18 +751,25 @@ static bool amdgpu_fence_enable_signaling(struct fence *f) fence->fence_wake.func = amdgpu_fence_check_signaled; __add_wait_queue(&ring->fence_drv.fence_queue, &fence->fence_wake); fence_get(f); - amdgpu_fence_schedule_check(ring); + if (!timer_pending(&ring->fence_drv.fallback_timer)) + amdgpu_fence_schedule_fallback(ring); FENCE_TRACE(&fence->base, "armed on ring %i!\n", ring->idx); return true; } +static void amdgpu_fence_release(struct fence *f) +{ + struct amdgpu_fence *fence = to_amdgpu_fence(f); + kmem_cache_free(amdgpu_fence_slab, fence); +} + const struct fence_ops amdgpu_fence_ops = { .get_driver_name = amdgpu_fence_get_driver_name, .get_timeline_name = amdgpu_fence_get_timeline_name, .enable_signaling = amdgpu_fence_enable_signaling, .signaled = amdgpu_fence_is_signaled, .wait = fence_default_wait, - .release = NULL, + .release = amdgpu_fence_release, }; /* diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c index 087332858853..00c5b580f56c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c @@ -483,6 +483,9 @@ static void amdgpu_gem_va_update_vm(struct amdgpu_device *adev, if (domain == AMDGPU_GEM_DOMAIN_CPU) goto error_unreserve; } + r = amdgpu_vm_update_page_directory(adev, bo_va->vm); + if (r) + goto error_unreserve; r = amdgpu_vm_clear_freed(adev, bo_va->vm); if (r) @@ -512,6 +515,9 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data, struct amdgpu_fpriv *fpriv = filp->driver_priv; struct amdgpu_bo *rbo; struct amdgpu_bo_va *bo_va; + struct ttm_validate_buffer tv, tv_pd; + struct ww_acquire_ctx ticket; + struct list_head list, duplicates; uint32_t invalid_flags, va_flags = 0; int r = 0; @@ -549,7 +555,18 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data, return -ENOENT; mutex_lock(&fpriv->vm.mutex); rbo = gem_to_amdgpu_bo(gobj); - r = amdgpu_bo_reserve(rbo, false); + INIT_LIST_HEAD(&list); + INIT_LIST_HEAD(&duplicates); + tv.bo = &rbo->tbo; + tv.shared = true; + list_add(&tv.head, &list); + + if (args->operation == AMDGPU_VA_OP_MAP) { + tv_pd.bo = &fpriv->vm.page_directory->tbo; + tv_pd.shared = true; + list_add(&tv_pd.head, &list); + } + r = ttm_eu_reserve_buffers(&ticket, &list, true, &duplicates); if (r) { mutex_unlock(&fpriv->vm.mutex); drm_gem_object_unreference_unlocked(gobj); @@ -558,7 +575,8 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data, bo_va = amdgpu_vm_bo_find(&fpriv->vm, rbo); if (!bo_va) { - amdgpu_bo_unreserve(rbo); + ttm_eu_backoff_reservation(&ticket, &list); + drm_gem_object_unreference_unlocked(gobj); mutex_unlock(&fpriv->vm.mutex); return -ENOENT; } @@ -581,7 +599,7 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data, default: break; } - + ttm_eu_backoff_reservation(&ticket, &list); if (!r && !(args->flags & AMDGPU_VM_DELAY_UPDATE)) amdgpu_gem_va_update_vm(adev, bo_va, args->operation); mutex_unlock(&fpriv->vm.mutex); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c index e65987743871..9e25edafa721 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c @@ -62,7 +62,7 @@ int amdgpu_ib_get(struct amdgpu_ring *ring, struct amdgpu_vm *vm, int r; if (size) { - r = amdgpu_sa_bo_new(adev, &adev->ring_tmp_bo, + r = amdgpu_sa_bo_new(&adev->ring_tmp_bo, &ib->sa_bo, size, 256); if (r) { dev_err(adev->dev, "failed to get a new IB (%d)\n", r); @@ -216,7 +216,7 @@ int amdgpu_ib_schedule(struct amdgpu_device *adev, unsigned num_ibs, } if (ib->vm) - amdgpu_vm_fence(adev, ib->vm, ib->fence); + amdgpu_vm_fence(adev, ib->vm, &ib->fence->base); amdgpu_ring_unlock_commit(ring); return 0; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h index 3c2ff4567798..ea756e77b023 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h @@ -189,10 +189,9 @@ int amdgpu_sa_bo_manager_start(struct amdgpu_device *adev, struct amdgpu_sa_manager *sa_manager); int amdgpu_sa_bo_manager_suspend(struct amdgpu_device *adev, struct amdgpu_sa_manager *sa_manager); -int amdgpu_sa_bo_new(struct amdgpu_device *adev, - struct amdgpu_sa_manager *sa_manager, - struct amdgpu_sa_bo **sa_bo, - unsigned size, unsigned align); +int amdgpu_sa_bo_new(struct amdgpu_sa_manager *sa_manager, + struct amdgpu_sa_bo **sa_bo, + unsigned size, unsigned align); void amdgpu_sa_bo_free(struct amdgpu_device *adev, struct amdgpu_sa_bo **sa_bo, struct fence *fence); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c index 0212b31dc194..8b88edb0434b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c @@ -311,8 +311,7 @@ static bool amdgpu_sa_bo_next_hole(struct amdgpu_sa_manager *sa_manager, return false; } -int amdgpu_sa_bo_new(struct amdgpu_device *adev, - struct amdgpu_sa_manager *sa_manager, +int amdgpu_sa_bo_new(struct amdgpu_sa_manager *sa_manager, struct amdgpu_sa_bo **sa_bo, unsigned size, unsigned align) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c index dcf4a8aca680..438c05254695 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c @@ -26,6 +26,7 @@ #include <linux/sched.h> #include <drm/drmP.h> #include "amdgpu.h" +#include "amdgpu_trace.h" static struct fence *amdgpu_sched_dependency(struct amd_sched_job *sched_job) { @@ -44,11 +45,8 @@ static struct fence *amdgpu_sched_run_job(struct amd_sched_job *sched_job) return NULL; } job = to_amdgpu_job(sched_job); - mutex_lock(&job->job_lock); - r = amdgpu_ib_schedule(job->adev, - job->num_ibs, - job->ibs, - job->base.owner); + trace_amdgpu_sched_run_job(job); + r = amdgpu_ib_schedule(job->adev, job->num_ibs, job->ibs, job->owner); if (r) { DRM_ERROR("Error scheduling IBs (%d)\n", r); goto err; @@ -61,8 +59,6 @@ err: if (job->free_job) job->free_job(job); - mutex_unlock(&job->job_lock); - fence_put(&job->base.s_fence->base); kfree(job); return fence ? &fence->base : NULL; } @@ -88,21 +84,19 @@ int amdgpu_sched_ib_submit_kernel_helper(struct amdgpu_device *adev, return -ENOMEM; job->base.sched = &ring->sched; job->base.s_entity = &adev->kernel_ctx.rings[ring->idx].entity; + job->base.s_fence = amd_sched_fence_create(job->base.s_entity, owner); + if (!job->base.s_fence) { + kfree(job); + return -ENOMEM; + } + *f = fence_get(&job->base.s_fence->base); + job->adev = adev; job->ibs = ibs; job->num_ibs = num_ibs; - job->base.owner = owner; - mutex_init(&job->job_lock); + job->owner = owner; job->free_job = free_job; - mutex_lock(&job->job_lock); - r = amd_sched_entity_push_job(&job->base); - if (r) { - mutex_unlock(&job->job_lock); - kfree(job); - return r; - } - *f = fence_get(&job->base.s_fence->base); - mutex_unlock(&job->job_lock); + amd_sched_entity_push_job(&job->base); } else { r = amdgpu_ib_schedule(adev, num_ibs, ibs, owner); if (r) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_semaphore.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_semaphore.c index ff3ca52ec6fe..1caaf201b708 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_semaphore.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_semaphore.c @@ -40,7 +40,7 @@ int amdgpu_semaphore_create(struct amdgpu_device *adev, if (*semaphore == NULL) { return -ENOMEM; } - r = amdgpu_sa_bo_new(adev, &adev->ring_tmp_bo, + r = amdgpu_sa_bo_new(&adev->ring_tmp_bo, &(*semaphore)->sa_bo, 8, 8); if (r) { kfree(*semaphore); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c index a6697fd05217..dd005c336c97 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c @@ -302,8 +302,14 @@ int amdgpu_sync_rings(struct amdgpu_sync *sync, return -EINVAL; } - if (amdgpu_enable_scheduler || !amdgpu_enable_semaphores || - (count >= AMDGPU_NUM_SYNCS)) { + if (amdgpu_enable_scheduler || !amdgpu_enable_semaphores) { + r = fence_wait(&fence->base, true); + if (r) + return r; + continue; + } + + if (count >= AMDGPU_NUM_SYNCS) { /* not enough room, wait manually */ r = fence_wait(&fence->base, false); if (r) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h index 76ecbaf72a2e..8f9834ab1bd5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h @@ -48,6 +48,57 @@ TRACE_EVENT(amdgpu_cs, __entry->fences) ); +TRACE_EVENT(amdgpu_cs_ioctl, + TP_PROTO(struct amdgpu_job *job), + TP_ARGS(job), + TP_STRUCT__entry( + __field(struct amdgpu_device *, adev) + __field(struct amd_sched_job *, sched_job) + __field(struct amdgpu_ib *, ib) + __field(struct fence *, fence) + __field(char *, ring_name) + __field(u32, num_ibs) + ), + + TP_fast_assign( + __entry->adev = job->adev; + __entry->sched_job = &job->base; + __entry->ib = job->ibs; + __entry->fence = &job->base.s_fence->base; + __entry->ring_name = job->ibs[0].ring->name; + __entry->num_ibs = job->num_ibs; + ), + TP_printk("adev=%p, sched_job=%p, first ib=%p, sched fence=%p, ring name:%s, num_ibs:%u", + __entry->adev, __entry->sched_job, __entry->ib, + __entry->fence, __entry->ring_name, __entry->num_ibs) +); + +TRACE_EVENT(amdgpu_sched_run_job, + TP_PROTO(struct amdgpu_job *job), + TP_ARGS(job), + TP_STRUCT__entry( + __field(struct amdgpu_device *, adev) + __field(struct amd_sched_job *, sched_job) + __field(struct amdgpu_ib *, ib) + __field(struct fence *, fence) + __field(char *, ring_name) + __field(u32, num_ibs) + ), + + TP_fast_assign( + __entry->adev = job->adev; + __entry->sched_job = &job->base; + __entry->ib = job->ibs; + __entry->fence = &job->base.s_fence->base; + __entry->ring_name = job->ibs[0].ring->name; + __entry->num_ibs = job->num_ibs; + ), + TP_printk("adev=%p, sched_job=%p, first ib=%p, sched fence=%p, ring name:%s, num_ibs:%u", + __entry->adev, __entry->sched_job, __entry->ib, + __entry->fence, __entry->ring_name, __entry->num_ibs) +); + + TRACE_EVENT(amdgpu_vm_grab_id, TP_PROTO(unsigned vmid, int ring), TP_ARGS(vmid, ring), @@ -196,49 +247,6 @@ TRACE_EVENT(amdgpu_bo_list_set, TP_printk("list=%p, bo=%p", __entry->list, __entry->bo) ); -DECLARE_EVENT_CLASS(amdgpu_fence_request, - - TP_PROTO(struct drm_device *dev, int ring, u32 seqno), - - TP_ARGS(dev, ring, seqno), - - TP_STRUCT__entry( - __field(u32, dev) - __field(int, ring) - __field(u32, seqno) - ), - - TP_fast_assign( - __entry->dev = dev->primary->index; - __entry->ring = ring; - __entry->seqno = seqno; - ), - - TP_printk("dev=%u, ring=%d, seqno=%u", - __entry->dev, __entry->ring, __entry->seqno) -); - -DEFINE_EVENT(amdgpu_fence_request, amdgpu_fence_emit, - - TP_PROTO(struct drm_device *dev, int ring, u32 seqno), - - TP_ARGS(dev, ring, seqno) -); - -DEFINE_EVENT(amdgpu_fence_request, amdgpu_fence_wait_begin, - - TP_PROTO(struct drm_device *dev, int ring, u32 seqno), - - TP_ARGS(dev, ring, seqno) -); - -DEFINE_EVENT(amdgpu_fence_request, amdgpu_fence_wait_end, - - TP_PROTO(struct drm_device *dev, int ring, u32 seqno), - - TP_ARGS(dev, ring, seqno) -); - DECLARE_EVENT_CLASS(amdgpu_semaphore_request, TP_PROTO(int ring, struct amdgpu_semaphore *sem), diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 81bb8e9fc26d..d4bac5f49939 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -1073,10 +1073,10 @@ static int amdgpu_mm_dump_table(struct seq_file *m, void *data) ret = drm_mm_dump_table(m, mm); spin_unlock(&glob->lru_lock); if (ttm_pl == TTM_PL_VRAM) - seq_printf(m, "man size:%llu pages, ram usage:%luMB, vis usage:%luMB\n", + seq_printf(m, "man size:%llu pages, ram usage:%lluMB, vis usage:%lluMB\n", adev->mman.bdev.man[ttm_pl].size, - atomic64_read(&adev->vram_usage) >> 20, - atomic64_read(&adev->vram_vis_usage) >> 20); + (u64)atomic64_read(&adev->vram_usage) >> 20, + (u64)atomic64_read(&adev->vram_vis_usage) >> 20); return ret; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 633a32a48560..159ce54bbd8d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -143,10 +143,15 @@ int amdgpu_vm_grab_id(struct amdgpu_vm *vm, struct amdgpu_ring *ring, unsigned i; /* check if the id is still valid */ - if (vm_id->id && vm_id->last_id_use && - vm_id->last_id_use == adev->vm_manager.active[vm_id->id]) { - trace_amdgpu_vm_grab_id(vm_id->id, ring->idx); - return 0; + if (vm_id->id) { + unsigned id = vm_id->id; + long owner; + + owner = atomic_long_read(&adev->vm_manager.ids[id].owner); + if (owner == (long)vm) { + trace_amdgpu_vm_grab_id(vm_id->id, ring->idx); + return 0; + } } /* we definately need to flush */ @@ -154,7 +159,7 @@ int amdgpu_vm_grab_id(struct amdgpu_vm *vm, struct amdgpu_ring *ring, /* skip over VMID 0, since it is the system VM */ for (i = 1; i < adev->vm_manager.nvm; ++i) { - struct fence *fence = adev->vm_manager.active[i]; + struct fence *fence = adev->vm_manager.ids[i].active; struct amdgpu_ring *fring; if (fence == NULL) { @@ -176,7 +181,7 @@ int amdgpu_vm_grab_id(struct amdgpu_vm *vm, struct amdgpu_ring *ring, if (choices[i]) { struct fence *fence; - fence = adev->vm_manager.active[choices[i]]; + fence = adev->vm_manager.ids[choices[i]].active; vm_id->id = choices[i]; trace_amdgpu_vm_grab_id(choices[i], ring->idx); @@ -207,24 +212,21 @@ void amdgpu_vm_flush(struct amdgpu_ring *ring, uint64_t pd_addr = amdgpu_bo_gpu_offset(vm->page_directory); struct amdgpu_vm_id *vm_id = &vm->ids[ring->idx]; struct fence *flushed_updates = vm_id->flushed_updates; - bool is_earlier = false; - - if (flushed_updates && updates) { - BUG_ON(flushed_updates->context != updates->context); - is_earlier = (updates->seqno - flushed_updates->seqno <= - INT_MAX) ? true : false; - } + bool is_later; - if (pd_addr != vm_id->pd_gpu_addr || !flushed_updates || - is_earlier) { + if (!flushed_updates) + is_later = true; + else if (!updates) + is_later = false; + else + is_later = fence_is_later(updates, flushed_updates); + if (pd_addr != vm_id->pd_gpu_addr || is_later) { trace_amdgpu_vm_flush(pd_addr, ring->idx, vm_id->id); - if (is_earlier) { + if (is_later) { vm_id->flushed_updates = fence_get(updates); fence_put(flushed_updates); } - if (!flushed_updates) - vm_id->flushed_updates = fence_get(updates); vm_id->pd_gpu_addr = pd_addr; amdgpu_ring_emit_vm_flush(ring, vm_id->id, vm_id->pd_gpu_addr); } @@ -244,16 +246,14 @@ void amdgpu_vm_flush(struct amdgpu_ring *ring, */ void amdgpu_vm_fence(struct amdgpu_device *adev, struct amdgpu_vm *vm, - struct amdgpu_fence *fence) + struct fence *fence) { - unsigned ridx = fence->ring->idx; - unsigned vm_id = vm->ids[ridx].id; - - fence_put(adev->vm_manager.active[vm_id]); - adev->vm_manager.active[vm_id] = fence_get(&fence->base); + struct amdgpu_ring *ring = amdgpu_ring_from_fence(fence); + unsigned vm_id = vm->ids[ring->idx].id; - fence_put(vm->ids[ridx].last_id_use); - vm->ids[ridx].last_id_use = fence_get(&fence->base); + fence_put(adev->vm_manager.ids[vm_id].active); + adev->vm_manager.ids[vm_id].active = fence_get(fence); + atomic_long_set(&adev->vm_manager.ids[vm_id].owner, (long)vm); } /** @@ -332,6 +332,8 @@ int amdgpu_vm_free_job(struct amdgpu_job *job) * * @adev: amdgpu_device pointer * @bo: bo to clear + * + * need to reserve bo first before calling it. */ static int amdgpu_vm_clear_bo(struct amdgpu_device *adev, struct amdgpu_bo *bo) @@ -343,24 +345,20 @@ static int amdgpu_vm_clear_bo(struct amdgpu_device *adev, uint64_t addr; int r; - r = amdgpu_bo_reserve(bo, false); - if (r) - return r; - r = reservation_object_reserve_shared(bo->tbo.resv); if (r) return r; r = ttm_bo_validate(&bo->tbo, &bo->placement, true, false); if (r) - goto error_unreserve; + goto error; addr = amdgpu_bo_gpu_offset(bo); entries = amdgpu_bo_size(bo) / 8; ib = kzalloc(sizeof(struct amdgpu_ib), GFP_KERNEL); if (!ib) - goto error_unreserve; + goto error; r = amdgpu_ib_get(ring, NULL, entries * 2 + 64, ib); if (r) @@ -378,16 +376,14 @@ static int amdgpu_vm_clear_bo(struct amdgpu_device *adev, if (!r) amdgpu_bo_fence(bo, fence, true); fence_put(fence); - if (amdgpu_enable_scheduler) { - amdgpu_bo_unreserve(bo); + if (amdgpu_enable_scheduler) return 0; - } + error_free: amdgpu_ib_free(adev, ib); kfree(ib); -error_unreserve: - amdgpu_bo_unreserve(bo); +error: return r; } @@ -989,7 +985,7 @@ struct amdgpu_bo_va *amdgpu_vm_bo_add(struct amdgpu_device *adev, * Add a mapping of the BO at the specefied addr into the VM. * Returns 0 for success, error for failure. * - * Object has to be reserved and gets unreserved by this function! + * Object has to be reserved and unreserved outside! */ int amdgpu_vm_bo_map(struct amdgpu_device *adev, struct amdgpu_bo_va *bo_va, @@ -1005,30 +1001,27 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev, /* validate the parameters */ if (saddr & AMDGPU_GPU_PAGE_MASK || offset & AMDGPU_GPU_PAGE_MASK || - size == 0 || size & AMDGPU_GPU_PAGE_MASK) { - amdgpu_bo_unreserve(bo_va->bo); + size == 0 || size & AMDGPU_GPU_PAGE_MASK) return -EINVAL; - } /* make sure object fit at this offset */ eaddr = saddr + size; - if ((saddr >= eaddr) || (offset + size > amdgpu_bo_size(bo_va->bo))) { - amdgpu_bo_unreserve(bo_va->bo); + if ((saddr >= eaddr) || (offset + size > amdgpu_bo_size(bo_va->bo))) return -EINVAL; - } last_pfn = eaddr / AMDGPU_GPU_PAGE_SIZE; if (last_pfn > adev->vm_manager.max_pfn) { dev_err(adev->dev, "va above limit (0x%08X > 0x%08X)\n", last_pfn, adev->vm_manager.max_pfn); - amdgpu_bo_unreserve(bo_va->bo); return -EINVAL; } saddr /= AMDGPU_GPU_PAGE_SIZE; eaddr /= AMDGPU_GPU_PAGE_SIZE; + spin_lock(&vm->it_lock); it = interval_tree_iter_first(&vm->va, saddr, eaddr - 1); + spin_unlock(&vm->it_lock); if (it) { struct amdgpu_bo_va_mapping *tmp; tmp = container_of(it, struct amdgpu_bo_va_mapping, it); @@ -1036,14 +1029,12 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev, dev_err(adev->dev, "bo %p va 0x%010Lx-0x%010Lx conflict with " "0x%010lx-0x%010lx\n", bo_va->bo, saddr, eaddr, tmp->it.start, tmp->it.last + 1); - amdgpu_bo_unreserve(bo_va->bo); r = -EINVAL; goto error; } mapping = kmalloc(sizeof(*mapping), GFP_KERNEL); if (!mapping) { - amdgpu_bo_unreserve(bo_va->bo); r = -ENOMEM; goto error; } @@ -1055,7 +1046,9 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev, mapping->flags = flags; list_add(&mapping->list, &bo_va->invalids); + spin_lock(&vm->it_lock); interval_tree_insert(&mapping->it, &vm->va); + spin_unlock(&vm->it_lock); trace_amdgpu_vm_bo_map(bo_va, mapping); /* Make sure the page tables are allocated */ @@ -1067,8 +1060,6 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev, if (eaddr > vm->max_pde_used) vm->max_pde_used = eaddr; - amdgpu_bo_unreserve(bo_va->bo); - /* walk over the address space and allocate the page tables */ for (pt_idx = saddr; pt_idx <= eaddr; ++pt_idx) { struct reservation_object *resv = vm->page_directory->tbo.resv; @@ -1077,13 +1068,11 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev, if (vm->page_tables[pt_idx].bo) continue; - ww_mutex_lock(&resv->lock, NULL); r = amdgpu_bo_create(adev, AMDGPU_VM_PTE_COUNT * 8, AMDGPU_GPU_PAGE_SIZE, true, AMDGPU_GEM_DOMAIN_VRAM, AMDGPU_GEM_CREATE_NO_CPU_ACCESS, NULL, resv, &pt); - ww_mutex_unlock(&resv->lock); if (r) goto error_free; @@ -1101,7 +1090,9 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev, error_free: list_del(&mapping->list); + spin_lock(&vm->it_lock); interval_tree_remove(&mapping->it, &vm->va); + spin_unlock(&vm->it_lock); trace_amdgpu_vm_bo_unmap(bo_va, mapping); kfree(mapping); @@ -1119,7 +1110,7 @@ error: * Remove a mapping of the BO at the specefied addr from the VM. * Returns 0 for success, error for failure. * - * Object has to be reserved and gets unreserved by this function! + * Object has to be reserved and unreserved outside! */ int amdgpu_vm_bo_unmap(struct amdgpu_device *adev, struct amdgpu_bo_va *bo_va, @@ -1144,21 +1135,20 @@ int amdgpu_vm_bo_unmap(struct amdgpu_device *adev, break; } - if (&mapping->list == &bo_va->invalids) { - amdgpu_bo_unreserve(bo_va->bo); + if (&mapping->list == &bo_va->invalids) return -ENOENT; - } } list_del(&mapping->list); + spin_lock(&vm->it_lock); interval_tree_remove(&mapping->it, &vm->va); + spin_unlock(&vm->it_lock); trace_amdgpu_vm_bo_unmap(bo_va, mapping); if (valid) list_add(&mapping->list, &vm->freed); else kfree(mapping); - amdgpu_bo_unreserve(bo_va->bo); return 0; } @@ -1187,13 +1177,17 @@ void amdgpu_vm_bo_rmv(struct amdgpu_device *adev, list_for_each_entry_safe(mapping, next, &bo_va->valids, list) { list_del(&mapping->list); + spin_lock(&vm->it_lock); interval_tree_remove(&mapping->it, &vm->va); + spin_unlock(&vm->it_lock); trace_amdgpu_vm_bo_unmap(bo_va, mapping); list_add(&mapping->list, &vm->freed); } list_for_each_entry_safe(mapping, next, &bo_va->invalids, list) { list_del(&mapping->list); + spin_lock(&vm->it_lock); interval_tree_remove(&mapping->it, &vm->va); + spin_unlock(&vm->it_lock); kfree(mapping); } @@ -1241,7 +1235,6 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm) for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { vm->ids[i].id = 0; vm->ids[i].flushed_updates = NULL; - vm->ids[i].last_id_use = NULL; } mutex_init(&vm->mutex); vm->va = RB_ROOT; @@ -1249,7 +1242,7 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm) INIT_LIST_HEAD(&vm->invalidated); INIT_LIST_HEAD(&vm->cleared); INIT_LIST_HEAD(&vm->freed); - + spin_lock_init(&vm->it_lock); pd_size = amdgpu_vm_directory_size(adev); pd_entries = amdgpu_vm_num_pdes(adev); @@ -1269,8 +1262,14 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm) NULL, NULL, &vm->page_directory); if (r) return r; - + r = amdgpu_bo_reserve(vm->page_directory, false); + if (r) { + amdgpu_bo_unref(&vm->page_directory); + vm->page_directory = NULL; + return r; + } r = amdgpu_vm_clear_bo(adev, vm->page_directory); + amdgpu_bo_unreserve(vm->page_directory); if (r) { amdgpu_bo_unref(&vm->page_directory); vm->page_directory = NULL; @@ -1313,11 +1312,28 @@ void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm) amdgpu_bo_unref(&vm->page_directory); fence_put(vm->page_directory_fence); - for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { + unsigned id = vm->ids[i].id; + + atomic_long_cmpxchg(&adev->vm_manager.ids[id].owner, + (long)vm, 0); fence_put(vm->ids[i].flushed_updates); - fence_put(vm->ids[i].last_id_use); } mutex_destroy(&vm->mutex); } + +/** + * amdgpu_vm_manager_fini - cleanup VM manager + * + * @adev: amdgpu_device pointer + * + * Cleanup the VM manager and free resources. + */ +void amdgpu_vm_manager_fini(struct amdgpu_device *adev) +{ + unsigned i; + + for (i = 0; i < AMDGPU_NUM_VM; ++i) + fence_put(adev->vm_manager.ids[i].active); +} diff --git a/drivers/gpu/drm/amd/amdgpu/ci_dpm.c b/drivers/gpu/drm/amd/amdgpu/ci_dpm.c index a1a35a5df8e7..57a2e347f04d 100644 --- a/drivers/gpu/drm/amd/amdgpu/ci_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/ci_dpm.c @@ -6569,12 +6569,12 @@ static int ci_dpm_set_interrupt_state(struct amdgpu_device *adev, switch (state) { case AMDGPU_IRQ_STATE_DISABLE: cg_thermal_int = RREG32_SMC(ixCG_THERMAL_INT); - cg_thermal_int &= ~CG_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK; + cg_thermal_int |= CG_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK; WREG32_SMC(ixCG_THERMAL_INT, cg_thermal_int); break; case AMDGPU_IRQ_STATE_ENABLE: cg_thermal_int = RREG32_SMC(ixCG_THERMAL_INT); - cg_thermal_int |= CG_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK; + cg_thermal_int &= ~CG_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK; WREG32_SMC(ixCG_THERMAL_INT, cg_thermal_int); break; default: @@ -6586,12 +6586,12 @@ static int ci_dpm_set_interrupt_state(struct amdgpu_device *adev, switch (state) { case AMDGPU_IRQ_STATE_DISABLE: cg_thermal_int = RREG32_SMC(ixCG_THERMAL_INT); - cg_thermal_int &= ~CG_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK; + cg_thermal_int |= CG_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK; WREG32_SMC(ixCG_THERMAL_INT, cg_thermal_int); break; case AMDGPU_IRQ_STATE_ENABLE: cg_thermal_int = RREG32_SMC(ixCG_THERMAL_INT); - cg_thermal_int |= CG_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK; + cg_thermal_int &= ~CG_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK; WREG32_SMC(ixCG_THERMAL_INT, cg_thermal_int); break; default: diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index 6776cf756d40..e1dcab98e249 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -268,7 +268,6 @@ static const u32 fiji_mgcg_cgcg_init[] = mmCGTT_CP_CLK_CTRL, 0xffffffff, 0x00000100, mmCGTT_CPC_CLK_CTRL, 0xffffffff, 0x00000100, mmCGTT_CPF_CLK_CTRL, 0xffffffff, 0x40000100, - mmCGTT_DRM_CLK_CTRL0, 0xffffffff, 0x00600100, mmCGTT_GDS_CLK_CTRL, 0xffffffff, 0x00000100, mmCGTT_IA_CLK_CTRL, 0xffffffff, 0x06000100, mmCGTT_PA_CLK_CTRL, 0xffffffff, 0x00000100, @@ -296,10 +295,6 @@ static const u32 fiji_mgcg_cgcg_init[] = mmCGTS_SM_CTRL_REG, 0xffffffff, 0x96e00200, mmCP_RB_WPTR_POLL_CNTL, 0xffffffff, 0x00900100, mmRLC_CGCG_CGLS_CTRL, 0xffffffff, 0x0020003c, - mmPCIE_INDEX, 0xffffffff, 0x0140001c, - mmPCIE_DATA, 0x000f0000, 0x00000000, - mmCGTT_DRM_CLK_CTRL0, 0xff000fff, 0x00000100, - mmHDP_XDP_CGTT_BLK_CTRL, 0xc0000fff, 0x00000104, mmCP_MEM_SLP_CNTL, 0x00000001, 0x00000001, }; @@ -1000,7 +995,7 @@ static void gfx_v8_0_gpu_early_init(struct amdgpu_device *adev) adev->gfx.config.max_cu_per_sh = 16; adev->gfx.config.max_sh_per_se = 1; adev->gfx.config.max_backends_per_se = 4; - adev->gfx.config.max_texture_channel_caches = 8; + adev->gfx.config.max_texture_channel_caches = 16; adev->gfx.config.max_gprs = 256; adev->gfx.config.max_gs_threads = 32; adev->gfx.config.max_hw_contexts = 8; @@ -1613,6 +1608,296 @@ static void gfx_v8_0_tiling_mode_table_init(struct amdgpu_device *adev) WREG32(mmGB_MACROTILE_MODE0 + reg_offset, gb_tile_moden); } case CHIP_FIJI: + for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++) { + switch (reg_offset) { + case 0: + gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING)); + break; + case 1: + gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING)); + break; + case 2: + gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING)); + break; + case 3: + gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING)); + break; + case 4: + gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_2KB) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING)); + break; + case 5: + gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_2KB) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING)); + break; + case 6: + gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_2KB) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING)); + break; + case 7: + gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_16x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_2KB) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING)); + break; + case 8: + gb_tile_moden = (ARRAY_MODE(ARRAY_LINEAR_ALIGNED) | + PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16)); + break; + case 9: + gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); + break; + case 10: + gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); + break; + case 11: + gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8)); + break; + case 12: + gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_16x16) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8)); + break; + case 13: + gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | + MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); + break; + case 14: + gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | + MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); + break; + case 15: + gb_tile_moden = (ARRAY_MODE(ARRAY_3D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | + MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); + break; + case 16: + gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | + MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8)); + break; + case 17: + gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_16x16) | + MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8)); + break; + case 18: + gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THICK) | + PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | + MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1)); + break; + case 19: + gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THICK) | + PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | + MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1)); + break; + case 20: + gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THICK) | + PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | + MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1)); + break; + case 21: + gb_tile_moden = (ARRAY_MODE(ARRAY_3D_TILED_THICK) | + PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | + MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1)); + break; + case 22: + gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THICK) | + PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | + MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1)); + break; + case 23: + gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THICK) | + PIPE_CONFIG(ADDR_SURF_P4_16x16) | + MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1)); + break; + case 24: + gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THICK) | + PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | + MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1)); + break; + case 25: + gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_XTHICK) | + PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | + MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1)); + break; + case 26: + gb_tile_moden = (ARRAY_MODE(ARRAY_3D_TILED_XTHICK) | + PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | + MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1)); + break; + case 27: + gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | + MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); + break; + case 28: + gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | + MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); + break; + case 29: + gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | + MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8)); + break; + case 30: + gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_16x16) | + MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8)); + break; + default: + gb_tile_moden = 0; + break; + } + adev->gfx.config.tile_mode_array[reg_offset] = gb_tile_moden; + WREG32(mmGB_TILE_MODE0 + reg_offset, gb_tile_moden); + } + for (reg_offset = 0; reg_offset < num_secondary_tile_mode_states; reg_offset++) { + switch (reg_offset) { + case 0: + gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | + NUM_BANKS(ADDR_SURF_8_BANK)); + break; + case 1: + gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | + NUM_BANKS(ADDR_SURF_8_BANK)); + break; + case 2: + gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | + NUM_BANKS(ADDR_SURF_8_BANK)); + break; + case 3: + gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | + NUM_BANKS(ADDR_SURF_8_BANK)); + break; + case 4: + gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_8_BANK)); + break; + case 5: + gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_8_BANK)); + break; + case 6: + gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_8_BANK)); + break; + case 8: + gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_8) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | + NUM_BANKS(ADDR_SURF_8_BANK)); + break; + case 9: + gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | + NUM_BANKS(ADDR_SURF_8_BANK)); + break; + case 10: + gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_8_BANK)); + break; + case 11: + gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_8_BANK)); + break; + case 12: + gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | + NUM_BANKS(ADDR_SURF_8_BANK)); + break; + case 13: + gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | + NUM_BANKS(ADDR_SURF_8_BANK)); + break; + case 14: + gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_4_BANK)); + break; + case 7: + /* unused idx */ + continue; + default: + gb_tile_moden = 0; + break; + } + adev->gfx.config.macrotile_mode_array[reg_offset] = gb_tile_moden; + WREG32(mmGB_MACROTILE_MODE0 + reg_offset, gb_tile_moden); + } + break; case CHIP_TONGA: for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++) { switch (reg_offset) { @@ -2971,10 +3256,13 @@ static int gfx_v8_0_cp_gfx_start(struct amdgpu_device *adev) amdgpu_ring_write(ring, mmPA_SC_RASTER_CONFIG - PACKET3_SET_CONTEXT_REG_START); switch (adev->asic_type) { case CHIP_TONGA: - case CHIP_FIJI: amdgpu_ring_write(ring, 0x16000012); amdgpu_ring_write(ring, 0x0000002A); break; + case CHIP_FIJI: + amdgpu_ring_write(ring, 0x3a00161a); + amdgpu_ring_write(ring, 0x0000002e); + break; case CHIP_TOPAZ: case CHIP_CARRIZO: amdgpu_ring_write(ring, 0x00000002); diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c index 85bbcdc73fff..7427d8cd4c43 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c @@ -40,7 +40,7 @@ static void gmc_v7_0_set_gart_funcs(struct amdgpu_device *adev); static void gmc_v7_0_set_irq_funcs(struct amdgpu_device *adev); -MODULE_FIRMWARE("radeon/boniare_mc.bin"); +MODULE_FIRMWARE("radeon/bonaire_mc.bin"); MODULE_FIRMWARE("radeon/hawaii_mc.bin"); /** @@ -501,6 +501,7 @@ static int gmc_v7_0_gart_enable(struct amdgpu_device *adev) tmp = REG_SET_FIELD(tmp, VM_L2_CNTL, ENABLE_L2_PDE0_CACHE_LRU_UPDATE_BY_WRITE, 1); tmp = REG_SET_FIELD(tmp, VM_L2_CNTL, EFFECTIVE_L2_QUEUE_SIZE, 7); tmp = REG_SET_FIELD(tmp, VM_L2_CNTL, CONTEXT1_IDENTITY_ACCESS_MODE, 1); + tmp = REG_SET_FIELD(tmp, VM_L2_CNTL, ENABLE_DEFAULT_PAGE_OUT_TO_SYSTEM_MEMORY, 1); WREG32(mmVM_L2_CNTL, tmp); tmp = REG_SET_FIELD(0, VM_L2_CNTL2, INVALIDATE_ALL_L1_TLBS, 1); tmp = REG_SET_FIELD(tmp, VM_L2_CNTL2, INVALIDATE_L2_CACHE, 1); @@ -960,12 +961,10 @@ static int gmc_v7_0_sw_init(void *handle) static int gmc_v7_0_sw_fini(void *handle) { - int i; struct amdgpu_device *adev = (struct amdgpu_device *)handle; if (adev->vm_manager.enabled) { - for (i = 0; i < AMDGPU_NUM_VM; ++i) - fence_put(adev->vm_manager.active[i]); + amdgpu_vm_manager_fini(adev); gmc_v7_0_vm_fini(adev); adev->vm_manager.enabled = false; } @@ -1010,12 +1009,10 @@ static int gmc_v7_0_hw_fini(void *handle) static int gmc_v7_0_suspend(void *handle) { - int i; struct amdgpu_device *adev = (struct amdgpu_device *)handle; if (adev->vm_manager.enabled) { - for (i = 0; i < AMDGPU_NUM_VM; ++i) - fence_put(adev->vm_manager.active[i]); + amdgpu_vm_manager_fini(adev); gmc_v7_0_vm_fini(adev); adev->vm_manager.enabled = false; } diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c index 1bcc4e74e3b4..cb0e50ebb528 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c @@ -629,6 +629,7 @@ static int gmc_v8_0_gart_enable(struct amdgpu_device *adev) tmp = REG_SET_FIELD(tmp, VM_L2_CNTL, ENABLE_L2_PDE0_CACHE_LRU_UPDATE_BY_WRITE, 1); tmp = REG_SET_FIELD(tmp, VM_L2_CNTL, EFFECTIVE_L2_QUEUE_SIZE, 7); tmp = REG_SET_FIELD(tmp, VM_L2_CNTL, CONTEXT1_IDENTITY_ACCESS_MODE, 1); + tmp = REG_SET_FIELD(tmp, VM_L2_CNTL, ENABLE_DEFAULT_PAGE_OUT_TO_SYSTEM_MEMORY, 1); WREG32(mmVM_L2_CNTL, tmp); tmp = RREG32(mmVM_L2_CNTL2); tmp = REG_SET_FIELD(tmp, VM_L2_CNTL2, INVALIDATE_ALL_L1_TLBS, 1); @@ -979,12 +980,10 @@ static int gmc_v8_0_sw_init(void *handle) static int gmc_v8_0_sw_fini(void *handle) { - int i; struct amdgpu_device *adev = (struct amdgpu_device *)handle; if (adev->vm_manager.enabled) { - for (i = 0; i < AMDGPU_NUM_VM; ++i) - fence_put(adev->vm_manager.active[i]); + amdgpu_vm_manager_fini(adev); gmc_v8_0_vm_fini(adev); adev->vm_manager.enabled = false; } @@ -1031,12 +1030,10 @@ static int gmc_v8_0_hw_fini(void *handle) static int gmc_v8_0_suspend(void *handle) { - int i; struct amdgpu_device *adev = (struct amdgpu_device *)handle; if (adev->vm_manager.enabled) { - for (i = 0; i < AMDGPU_NUM_VM; ++i) - fence_put(adev->vm_manager.active[i]); + amdgpu_vm_manager_fini(adev); gmc_v8_0_vm_fini(adev); adev->vm_manager.enabled = false; } diff --git a/drivers/gpu/drm/amd/scheduler/gpu_sched_trace.h b/drivers/gpu/drm/amd/scheduler/gpu_sched_trace.h index 144f50acc971..c89dc777768f 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_sched_trace.h +++ b/drivers/gpu/drm/amd/scheduler/gpu_sched_trace.h @@ -16,6 +16,8 @@ TRACE_EVENT(amd_sched_job, TP_ARGS(sched_job), TP_STRUCT__entry( __field(struct amd_sched_entity *, entity) + __field(struct amd_sched_job *, sched_job) + __field(struct fence *, fence) __field(const char *, name) __field(u32, job_count) __field(int, hw_job_count) @@ -23,16 +25,32 @@ TRACE_EVENT(amd_sched_job, TP_fast_assign( __entry->entity = sched_job->s_entity; + __entry->sched_job = sched_job; + __entry->fence = &sched_job->s_fence->base; __entry->name = sched_job->sched->name; __entry->job_count = kfifo_len( &sched_job->s_entity->job_queue) / sizeof(sched_job); __entry->hw_job_count = atomic_read( &sched_job->sched->hw_rq_count); ), - TP_printk("entity=%p, ring=%s, job count:%u, hw job count:%d", - __entry->entity, __entry->name, __entry->job_count, - __entry->hw_job_count) + TP_printk("entity=%p, sched job=%p, fence=%p, ring=%s, job count:%u, hw job count:%d", + __entry->entity, __entry->sched_job, __entry->fence, __entry->name, + __entry->job_count, __entry->hw_job_count) ); + +TRACE_EVENT(amd_sched_process_job, + TP_PROTO(struct amd_sched_fence *fence), + TP_ARGS(fence), + TP_STRUCT__entry( + __field(struct fence *, fence) + ), + + TP_fast_assign( + __entry->fence = &fence->base; + ), + TP_printk("fence=%p signaled", __entry->fence) +); + #endif /* This part must be outside protection */ diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c index 89619a5a4289..ea30d6ad4c13 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c @@ -34,6 +34,9 @@ static struct amd_sched_job * amd_sched_entity_pop_job(struct amd_sched_entity *entity); static void amd_sched_wakeup(struct amd_gpu_scheduler *sched); +struct kmem_cache *sched_fence_slab; +atomic_t sched_fence_slab_ref = ATOMIC_INIT(0); + /* Initialize a given run queue struct */ static void amd_sched_rq_init(struct amd_sched_rq *rq) { @@ -273,22 +276,13 @@ static bool amd_sched_entity_in(struct amd_sched_job *sched_job) * * Returns 0 for success, negative error code otherwise. */ -int amd_sched_entity_push_job(struct amd_sched_job *sched_job) +void amd_sched_entity_push_job(struct amd_sched_job *sched_job) { struct amd_sched_entity *entity = sched_job->s_entity; - struct amd_sched_fence *fence = amd_sched_fence_create( - entity, sched_job->owner); - - if (!fence) - return -ENOMEM; - - fence_get(&fence->base); - sched_job->s_fence = fence; wait_event(entity->sched->job_scheduled, amd_sched_entity_in(sched_job)); trace_amd_sched_job(sched_job); - return 0; } /** @@ -343,6 +337,7 @@ static void amd_sched_process_job(struct fence *f, struct fence_cb *cb) list_del_init(&s_fence->list); spin_unlock_irqrestore(&sched->fence_list_lock, flags); } + trace_amd_sched_process_job(s_fence); fence_put(&s_fence->base); wake_up_interruptible(&sched->wake_up_worker); } @@ -450,6 +445,13 @@ int amd_sched_init(struct amd_gpu_scheduler *sched, init_waitqueue_head(&sched->wake_up_worker); init_waitqueue_head(&sched->job_scheduled); atomic_set(&sched->hw_rq_count, 0); + if (atomic_inc_return(&sched_fence_slab_ref) == 1) { + sched_fence_slab = kmem_cache_create( + "amd_sched_fence", sizeof(struct amd_sched_fence), 0, + SLAB_HWCACHE_ALIGN, NULL); + if (!sched_fence_slab) + return -ENOMEM; + } /* Each scheduler will run on a seperate kernel thread */ sched->thread = kthread_run(amd_sched_main, sched, sched->name); @@ -470,4 +472,6 @@ void amd_sched_fini(struct amd_gpu_scheduler *sched) { if (sched->thread) kthread_stop(sched->thread); + if (atomic_dec_and_test(&sched_fence_slab_ref)) + kmem_cache_destroy(sched_fence_slab); } diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h index 929e9aced041..939692b14f4b 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h @@ -30,6 +30,9 @@ struct amd_gpu_scheduler; struct amd_sched_rq; +extern struct kmem_cache *sched_fence_slab; +extern atomic_t sched_fence_slab_ref; + /** * A scheduler entity is a wrapper around a job queue or a group * of other entities. Entities take turns emitting jobs from their @@ -76,7 +79,6 @@ struct amd_sched_job { struct amd_gpu_scheduler *sched; struct amd_sched_entity *s_entity; struct amd_sched_fence *s_fence; - void *owner; }; extern const struct fence_ops amd_sched_fence_ops; @@ -128,7 +130,7 @@ int amd_sched_entity_init(struct amd_gpu_scheduler *sched, uint32_t jobs); void amd_sched_entity_fini(struct amd_gpu_scheduler *sched, struct amd_sched_entity *entity); -int amd_sched_entity_push_job(struct amd_sched_job *sched_job); +void amd_sched_entity_push_job(struct amd_sched_job *sched_job); struct amd_sched_fence *amd_sched_fence_create( struct amd_sched_entity *s_entity, void *owner); diff --git a/drivers/gpu/drm/amd/scheduler/sched_fence.c b/drivers/gpu/drm/amd/scheduler/sched_fence.c index d802638094f4..8d2130b9ff05 100644 --- a/drivers/gpu/drm/amd/scheduler/sched_fence.c +++ b/drivers/gpu/drm/amd/scheduler/sched_fence.c @@ -32,7 +32,7 @@ struct amd_sched_fence *amd_sched_fence_create(struct amd_sched_entity *s_entity struct amd_sched_fence *fence = NULL; unsigned seq; - fence = kzalloc(sizeof(struct amd_sched_fence), GFP_KERNEL); + fence = kmem_cache_zalloc(sched_fence_slab, GFP_KERNEL); if (fence == NULL) return NULL; fence->owner = owner; @@ -71,11 +71,17 @@ static bool amd_sched_fence_enable_signaling(struct fence *f) return true; } +static void amd_sched_fence_release(struct fence *f) +{ + struct amd_sched_fence *fence = to_amd_sched_fence(f); + kmem_cache_free(sched_fence_slab, fence); +} + const struct fence_ops amd_sched_fence_ops = { .get_driver_name = amd_sched_fence_get_driver_name, .get_timeline_name = amd_sched_fence_get_timeline_name, .enable_signaling = amd_sched_fence_enable_signaling, .signaled = NULL, .wait = fence_default_wait, - .release = NULL, + .release = amd_sched_fence_release, }; diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h index 86205a28e56b..05f6522c0457 100644 --- a/drivers/gpu/drm/ast/ast_drv.h +++ b/drivers/gpu/drm/ast/ast_drv.h @@ -315,6 +315,7 @@ int ast_framebuffer_init(struct drm_device *dev, int ast_fbdev_init(struct drm_device *dev); void ast_fbdev_fini(struct drm_device *dev); void ast_fbdev_set_suspend(struct drm_device *dev, int state); +void ast_fbdev_set_base(struct ast_private *ast, unsigned long gpu_addr); struct ast_bo { struct ttm_buffer_object bo; diff --git a/drivers/gpu/drm/ast/ast_fb.c b/drivers/gpu/drm/ast/ast_fb.c index f31db28a684b..a37e7ea4a00c 100644 --- a/drivers/gpu/drm/ast/ast_fb.c +++ b/drivers/gpu/drm/ast/ast_fb.c @@ -365,3 +365,10 @@ void ast_fbdev_set_suspend(struct drm_device *dev, int state) drm_fb_helper_set_suspend(&ast->fbdev->helper, state); } + +void ast_fbdev_set_base(struct ast_private *ast, unsigned long gpu_addr) +{ + ast->fbdev->helper.fbdev->fix.smem_start = + ast->fbdev->helper.fbdev->apertures->ranges[0].base + gpu_addr; + ast->fbdev->helper.fbdev->fix.smem_len = ast->vram_size - gpu_addr; +} diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c index 838217f8ce7d..541a610667ad 100644 --- a/drivers/gpu/drm/ast/ast_main.c +++ b/drivers/gpu/drm/ast/ast_main.c @@ -448,6 +448,7 @@ int ast_driver_load(struct drm_device *dev, unsigned long flags) dev->mode_config.min_height = 0; dev->mode_config.preferred_depth = 24; dev->mode_config.prefer_shadow = 1; + dev->mode_config.fb_base = pci_resource_start(ast->dev->pdev, 0); if (ast->chip == AST2100 || ast->chip == AST2200 || diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index b7ee2634e47c..69d19f3304a5 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -547,6 +547,8 @@ static int ast_crtc_do_set_base(struct drm_crtc *crtc, ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap); if (ret) DRM_ERROR("failed to kmap fbcon\n"); + else + ast_fbdev_set_base(ast, gpu_addr); } ast_bo_unreserve(bo); diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 7bb3845d9974..aeee083c7f95 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1432,6 +1432,45 @@ static int atomic_set_prop(struct drm_atomic_state *state, return ret; } +/** + * drm_atomic_update_old_fb -- Unset old_fb pointers and set plane->fb pointers. + * + * @dev: drm device to check. + * @plane_mask: plane mask for planes that were updated. + * @ret: return value, can be -EDEADLK for a retry. + * + * Before doing an update plane->old_fb is set to plane->fb, + * but before dropping the locks old_fb needs to be set to NULL + * and plane->fb updated. This is a common operation for each + * atomic update, so this call is split off as a helper. + */ +void drm_atomic_clean_old_fb(struct drm_device *dev, + unsigned plane_mask, + int ret) +{ + struct drm_plane *plane; + + /* if succeeded, fixup legacy plane crtc/fb ptrs before dropping + * locks (ie. while it is still safe to deref plane->state). We + * need to do this here because the driver entry points cannot + * distinguish between legacy and atomic ioctls. + */ + drm_for_each_plane_mask(plane, dev, plane_mask) { + if (ret == 0) { + struct drm_framebuffer *new_fb = plane->state->fb; + if (new_fb) + drm_framebuffer_reference(new_fb); + plane->fb = new_fb; + plane->crtc = plane->state->crtc; + + if (plane->old_fb) + drm_framebuffer_unreference(plane->old_fb); + } + plane->old_fb = NULL; + } +} +EXPORT_SYMBOL(drm_atomic_clean_old_fb); + int drm_mode_atomic_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -1446,7 +1485,7 @@ int drm_mode_atomic_ioctl(struct drm_device *dev, struct drm_plane *plane; struct drm_crtc *crtc; struct drm_crtc_state *crtc_state; - unsigned plane_mask = 0; + unsigned plane_mask; int ret = 0; unsigned int i, j; @@ -1486,6 +1525,7 @@ int drm_mode_atomic_ioctl(struct drm_device *dev, state->allow_modeset = !!(arg->flags & DRM_MODE_ATOMIC_ALLOW_MODESET); retry: + plane_mask = 0; copied_objs = 0; copied_props = 0; @@ -1576,24 +1616,7 @@ retry: } out: - /* if succeeded, fixup legacy plane crtc/fb ptrs before dropping - * locks (ie. while it is still safe to deref plane->state). We - * need to do this here because the driver entry points cannot - * distinguish between legacy and atomic ioctls. - */ - drm_for_each_plane_mask(plane, dev, plane_mask) { - if (ret == 0) { - struct drm_framebuffer *new_fb = plane->state->fb; - if (new_fb) - drm_framebuffer_reference(new_fb); - plane->fb = new_fb; - plane->crtc = plane->state->crtc; - - if (plane->old_fb) - drm_framebuffer_unreference(plane->old_fb); - } - plane->old_fb = NULL; - } + drm_atomic_clean_old_fb(dev, plane_mask, ret); if (ret && arg->flags & DRM_MODE_PAGE_FLIP_EVENT) { /* diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 0c6f62168776..e5aec45bf985 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -210,6 +210,14 @@ update_connector_routing(struct drm_atomic_state *state, int conn_idx) return -EINVAL; } + if (!drm_encoder_crtc_ok(new_encoder, connector_state->crtc)) { + DRM_DEBUG_ATOMIC("[ENCODER:%d:%s] incompatible with [CRTC:%d]\n", + new_encoder->base.id, + new_encoder->name, + connector_state->crtc->base.id); + return -EINVAL; + } + if (new_encoder == connector_state->best_encoder) { DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] keeps [ENCODER:%d:%s], now on [CRTC:%d]\n", connector->base.id, @@ -1553,6 +1561,9 @@ retry: goto fail; } + if (plane_state->crtc && (plane == plane->crtc->cursor)) + plane_state->state->legacy_cursor_update = true; + ret = __drm_atomic_helper_disable_plane(plane, plane_state); if (ret != 0) goto fail; @@ -1605,9 +1616,6 @@ int __drm_atomic_helper_disable_plane(struct drm_plane *plane, plane_state->src_h = 0; plane_state->src_w = 0; - if (plane->crtc && (plane == plane->crtc->cursor)) - plane_state->state->legacy_cursor_update = true; - return 0; } @@ -1741,6 +1749,7 @@ int __drm_atomic_helper_set_config(struct drm_mode_set *set, struct drm_crtc_state *crtc_state; struct drm_plane_state *primary_state; struct drm_crtc *crtc = set->crtc; + int hdisplay, vdisplay; int ret; crtc_state = drm_atomic_get_crtc_state(state, crtc); @@ -1783,19 +1792,21 @@ int __drm_atomic_helper_set_config(struct drm_mode_set *set, if (ret != 0) return ret; + drm_crtc_get_hv_timing(set->mode, &hdisplay, &vdisplay); + drm_atomic_set_fb_for_plane(primary_state, set->fb); primary_state->crtc_x = 0; primary_state->crtc_y = 0; - primary_state->crtc_h = set->mode->vdisplay; - primary_state->crtc_w = set->mode->hdisplay; + primary_state->crtc_h = vdisplay; + primary_state->crtc_w = hdisplay; primary_state->src_x = set->x << 16; primary_state->src_y = set->y << 16; if (primary_state->rotation & (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270))) { - primary_state->src_h = set->mode->hdisplay << 16; - primary_state->src_w = set->mode->vdisplay << 16; + primary_state->src_h = hdisplay << 16; + primary_state->src_w = vdisplay << 16; } else { - primary_state->src_h = set->mode->vdisplay << 16; - primary_state->src_w = set->mode->hdisplay << 16; + primary_state->src_h = vdisplay << 16; + primary_state->src_w = hdisplay << 16; } commit: diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index e673c13c7391..69cbab5e5c81 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -342,6 +342,7 @@ static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper) struct drm_plane *plane; struct drm_atomic_state *state; int i, ret; + unsigned plane_mask; state = drm_atomic_state_alloc(dev); if (!state) @@ -349,11 +350,10 @@ static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper) state->acquire_ctx = dev->mode_config.acquire_ctx; retry: + plane_mask = 0; drm_for_each_plane(plane, dev) { struct drm_plane_state *plane_state; - plane->old_fb = plane->fb; - plane_state = drm_atomic_get_plane_state(state, plane); if (IS_ERR(plane_state)) { ret = PTR_ERR(plane_state); @@ -362,6 +362,9 @@ retry: plane_state->rotation = BIT(DRM_ROTATE_0); + plane->old_fb = plane->fb; + plane_mask |= 1 << drm_plane_index(plane); + /* disable non-primary: */ if (plane->type == DRM_PLANE_TYPE_PRIMARY) continue; @@ -382,19 +385,7 @@ retry: ret = drm_atomic_commit(state); fail: - drm_for_each_plane(plane, dev) { - if (ret == 0) { - struct drm_framebuffer *new_fb = plane->state->fb; - if (new_fb) - drm_framebuffer_reference(new_fb); - plane->fb = new_fb; - plane->crtc = plane->state->crtc; - - if (plane->old_fb) - drm_framebuffer_unreference(plane->old_fb); - } - plane->old_fb = NULL; - } + drm_atomic_clean_old_fb(dev, plane_mask, ret); if (ret == -EDEADLK) goto backoff; @@ -1236,7 +1227,9 @@ static int pan_display_atomic(struct fb_var_screeninfo *var, struct drm_fb_helper *fb_helper = info->par; struct drm_device *dev = fb_helper->dev; struct drm_atomic_state *state; + struct drm_plane *plane; int i, ret; + unsigned plane_mask; state = drm_atomic_state_alloc(dev); if (!state) @@ -1244,19 +1237,22 @@ static int pan_display_atomic(struct fb_var_screeninfo *var, state->acquire_ctx = dev->mode_config.acquire_ctx; retry: + plane_mask = 0; for(i = 0; i < fb_helper->crtc_count; i++) { struct drm_mode_set *mode_set; mode_set = &fb_helper->crtc_info[i].mode_set; - mode_set->crtc->primary->old_fb = mode_set->crtc->primary->fb; - mode_set->x = var->xoffset; mode_set->y = var->yoffset; ret = __drm_atomic_helper_set_config(mode_set, state); if (ret != 0) goto fail; + + plane = mode_set->crtc->primary; + plane_mask |= drm_plane_index(plane); + plane->old_fb = plane->fb; } ret = drm_atomic_commit(state); @@ -1268,26 +1264,7 @@ retry: fail: - for(i = 0; i < fb_helper->crtc_count; i++) { - struct drm_mode_set *mode_set; - struct drm_plane *plane; - - mode_set = &fb_helper->crtc_info[i].mode_set; - plane = mode_set->crtc->primary; - - if (ret == 0) { - struct drm_framebuffer *new_fb = plane->state->fb; - - if (new_fb) - drm_framebuffer_reference(new_fb); - plane->fb = new_fb; - plane->crtc = plane->state->crtc; - - if (plane->old_fb) - drm_framebuffer_unreference(plane->old_fb); - } - plane->old_fb = NULL; - } + drm_atomic_clean_old_fb(dev, plane_mask, ret); if (ret == -EDEADLK) goto backoff; diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index eba6337f5860..2151ea551d3b 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -616,10 +616,18 @@ int drm_control(struct drm_device *dev, void *data, void drm_calc_timestamping_constants(struct drm_crtc *crtc, const struct drm_display_mode *mode) { - struct drm_vblank_crtc *vblank = &crtc->dev->vblank[drm_crtc_index(crtc)]; + struct drm_device *dev = crtc->dev; + unsigned int pipe = drm_crtc_index(crtc); + struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; int linedur_ns = 0, framedur_ns = 0; int dotclock = mode->crtc_clock; + if (!dev->num_crtcs) + return; + + if (WARN_ON(pipe >= dev->num_crtcs)) + return; + /* Valid dotclock? */ if (dotclock > 0) { int frame_size = mode->crtc_htotal * mode->crtc_vtotal; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 8afda459a26e..95bb27de774f 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -351,6 +351,8 @@ enum intel_dpll_id { /* hsw/bdw */ DPLL_ID_WRPLL1 = 0, DPLL_ID_WRPLL2 = 1, + DPLL_ID_SPLL = 2, + /* skl */ DPLL_ID_SKL_DPLL1 = 0, DPLL_ID_SKL_DPLL2 = 1, @@ -367,6 +369,7 @@ struct intel_dpll_hw_state { /* hsw, bdw */ uint32_t wrpll; + uint32_t spll; /* skl */ /* @@ -2648,6 +2651,7 @@ struct i915_params { int enable_cmd_parser; /* leave bools at the end to not create holes */ bool enable_hangcheck; + bool fastboot; bool prefault_disable; bool load_detect_test; bool reset; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 5cf4a1998273..91bb1fc27420 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3809,6 +3809,7 @@ int i915_gem_get_caching_ioctl(struct drm_device *dev, void *data, int i915_gem_set_caching_ioctl(struct drm_device *dev, void *data, struct drm_file *file) { + struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_caching *args = data; struct drm_i915_gem_object *obj; enum i915_cache_level level; @@ -3837,9 +3838,11 @@ int i915_gem_set_caching_ioctl(struct drm_device *dev, void *data, return -EINVAL; } + intel_runtime_pm_get(dev_priv); + ret = i915_mutex_lock_interruptible(dev); if (ret) - return ret; + goto rpm_put; obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle)); if (&obj->base == NULL) { @@ -3852,6 +3855,9 @@ int i915_gem_set_caching_ioctl(struct drm_device *dev, void *data, drm_gem_object_unreference(&obj->base); unlock: mutex_unlock(&dev->struct_mutex); +rpm_put: + intel_runtime_pm_put(dev_priv); + return ret; } diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index 96bb23865eac..4be13a5eb932 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -40,6 +40,7 @@ struct i915_params i915 __read_mostly = { .preliminary_hw_support = IS_ENABLED(CONFIG_DRM_I915_PRELIMINARY_HW_SUPPORT), .disable_power_well = -1, .enable_ips = 1, + .fastboot = 0, .prefault_disable = 0, .load_detect_test = 0, .reset = true, @@ -133,6 +134,10 @@ MODULE_PARM_DESC(disable_power_well, module_param_named_unsafe(enable_ips, i915.enable_ips, int, 0600); MODULE_PARM_DESC(enable_ips, "Enable IPS (default: true)"); +module_param_named(fastboot, i915.fastboot, bool, 0600); +MODULE_PARM_DESC(fastboot, + "Try to skip unnecessary mode sets at boot time (default: false)"); + module_param_named_unsafe(prefault_disable, i915.prefault_disable, bool, 0600); MODULE_PARM_DESC(prefault_disable, "Disable page prefaulting for pread/pwrite/reloc (default:false). " diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index b84aaa0bb48a..6a2c76e367a5 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -138,18 +138,6 @@ static void hsw_crt_get_config(struct intel_encoder *encoder, pipe_config->base.adjusted_mode.flags |= intel_crt_get_flags(encoder); } -static void hsw_crt_pre_enable(struct intel_encoder *encoder) -{ - struct drm_device *dev = encoder->base.dev; - struct drm_i915_private *dev_priv = dev->dev_private; - - WARN(I915_READ(SPLL_CTL) & SPLL_PLL_ENABLE, "SPLL already enabled\n"); - I915_WRITE(SPLL_CTL, - SPLL_PLL_ENABLE | SPLL_PLL_FREQ_1350MHz | SPLL_PLL_SSC); - POSTING_READ(SPLL_CTL); - udelay(20); -} - /* Note: The caller is required to filter out dpms modes not supported by the * platform. */ static void intel_crt_set_dpms(struct intel_encoder *encoder, int mode) @@ -216,19 +204,6 @@ static void pch_post_disable_crt(struct intel_encoder *encoder) intel_disable_crt(encoder); } -static void hsw_crt_post_disable(struct intel_encoder *encoder) -{ - struct drm_device *dev = encoder->base.dev; - struct drm_i915_private *dev_priv = dev->dev_private; - uint32_t val; - - DRM_DEBUG_KMS("Disabling SPLL\n"); - val = I915_READ(SPLL_CTL); - WARN_ON(!(val & SPLL_PLL_ENABLE)); - I915_WRITE(SPLL_CTL, val & ~SPLL_PLL_ENABLE); - POSTING_READ(SPLL_CTL); -} - static void intel_enable_crt(struct intel_encoder *encoder) { struct intel_crt *crt = intel_encoder_to_crt(encoder); @@ -280,6 +255,10 @@ static bool intel_crt_compute_config(struct intel_encoder *encoder, if (HAS_DDI(dev)) { pipe_config->ddi_pll_sel = PORT_CLK_SEL_SPLL; pipe_config->port_clock = 135000 * 2; + + pipe_config->dpll_hw_state.wrpll = 0; + pipe_config->dpll_hw_state.spll = + SPLL_PLL_ENABLE | SPLL_PLL_FREQ_1350MHz | SPLL_PLL_SSC; } return true; @@ -860,8 +839,6 @@ void intel_crt_init(struct drm_device *dev) if (HAS_DDI(dev)) { crt->base.get_config = hsw_crt_get_config; crt->base.get_hw_state = intel_ddi_get_hw_state; - crt->base.pre_enable = hsw_crt_pre_enable; - crt->base.post_disable = hsw_crt_post_disable; } else { crt->base.get_config = intel_crt_get_config; crt->base.get_hw_state = intel_crt_get_hw_state; diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index b25e99a432fb..a6752a61d99f 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1286,6 +1286,18 @@ hsw_ddi_pll_select(struct intel_crtc *intel_crtc, } crtc_state->ddi_pll_sel = PORT_CLK_SEL_WRPLL(pll->id); + } else if (crtc_state->ddi_pll_sel == PORT_CLK_SEL_SPLL) { + struct drm_atomic_state *state = crtc_state->base.state; + struct intel_shared_dpll_config *spll = + &intel_atomic_get_shared_dpll_state(state)[DPLL_ID_SPLL]; + + if (spll->crtc_mask && + WARN_ON(spll->hw_state.spll != crtc_state->dpll_hw_state.spll)) + return false; + + crtc_state->shared_dpll = DPLL_ID_SPLL; + spll->hw_state.spll = crtc_state->dpll_hw_state.spll; + spll->crtc_mask |= 1 << intel_crtc->pipe; } return true; @@ -2437,7 +2449,7 @@ static void intel_disable_ddi(struct intel_encoder *intel_encoder) } } -static void hsw_ddi_pll_enable(struct drm_i915_private *dev_priv, +static void hsw_ddi_wrpll_enable(struct drm_i915_private *dev_priv, struct intel_shared_dpll *pll) { I915_WRITE(WRPLL_CTL(pll->id), pll->config.hw_state.wrpll); @@ -2445,9 +2457,17 @@ static void hsw_ddi_pll_enable(struct drm_i915_private *dev_priv, udelay(20); } -static void hsw_ddi_pll_disable(struct drm_i915_private *dev_priv, +static void hsw_ddi_spll_enable(struct drm_i915_private *dev_priv, struct intel_shared_dpll *pll) { + I915_WRITE(SPLL_CTL, pll->config.hw_state.spll); + POSTING_READ(SPLL_CTL); + udelay(20); +} + +static void hsw_ddi_wrpll_disable(struct drm_i915_private *dev_priv, + struct intel_shared_dpll *pll) +{ uint32_t val; val = I915_READ(WRPLL_CTL(pll->id)); @@ -2455,9 +2475,19 @@ static void hsw_ddi_pll_disable(struct drm_i915_private *dev_priv, POSTING_READ(WRPLL_CTL(pll->id)); } -static bool hsw_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv, - struct intel_shared_dpll *pll, - struct intel_dpll_hw_state *hw_state) +static void hsw_ddi_spll_disable(struct drm_i915_private *dev_priv, + struct intel_shared_dpll *pll) +{ + uint32_t val; + + val = I915_READ(SPLL_CTL); + I915_WRITE(SPLL_CTL, val & ~SPLL_PLL_ENABLE); + POSTING_READ(SPLL_CTL); +} + +static bool hsw_ddi_wrpll_get_hw_state(struct drm_i915_private *dev_priv, + struct intel_shared_dpll *pll, + struct intel_dpll_hw_state *hw_state) { uint32_t val; @@ -2470,25 +2500,50 @@ static bool hsw_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv, return val & WRPLL_PLL_ENABLE; } +static bool hsw_ddi_spll_get_hw_state(struct drm_i915_private *dev_priv, + struct intel_shared_dpll *pll, + struct intel_dpll_hw_state *hw_state) +{ + uint32_t val; + + if (!intel_display_power_is_enabled(dev_priv, POWER_DOMAIN_PLLS)) + return false; + + val = I915_READ(SPLL_CTL); + hw_state->spll = val; + + return val & SPLL_PLL_ENABLE; +} + + static const char * const hsw_ddi_pll_names[] = { "WRPLL 1", "WRPLL 2", + "SPLL" }; static void hsw_shared_dplls_init(struct drm_i915_private *dev_priv) { int i; - dev_priv->num_shared_dpll = 2; + dev_priv->num_shared_dpll = 3; - for (i = 0; i < dev_priv->num_shared_dpll; i++) { + for (i = 0; i < 2; i++) { dev_priv->shared_dplls[i].id = i; dev_priv->shared_dplls[i].name = hsw_ddi_pll_names[i]; - dev_priv->shared_dplls[i].disable = hsw_ddi_pll_disable; - dev_priv->shared_dplls[i].enable = hsw_ddi_pll_enable; + dev_priv->shared_dplls[i].disable = hsw_ddi_wrpll_disable; + dev_priv->shared_dplls[i].enable = hsw_ddi_wrpll_enable; dev_priv->shared_dplls[i].get_hw_state = - hsw_ddi_pll_get_hw_state; + hsw_ddi_wrpll_get_hw_state; } + + /* SPLL is special, but needs to be initialized anyway.. */ + dev_priv->shared_dplls[i].id = i; + dev_priv->shared_dplls[i].name = hsw_ddi_pll_names[i]; + dev_priv->shared_dplls[i].disable = hsw_ddi_spll_disable; + dev_priv->shared_dplls[i].enable = hsw_ddi_spll_enable; + dev_priv->shared_dplls[i].get_hw_state = hsw_ddi_spll_get_hw_state; + } static const char * const skl_ddi_pll_names[] = { diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f62ffc04c21d..71860f8680f9 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2646,11 +2646,13 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc, return; valid_fb: - plane_state->src_x = plane_state->src_y = 0; + plane_state->src_x = 0; + plane_state->src_y = 0; plane_state->src_w = fb->width << 16; plane_state->src_h = fb->height << 16; - plane_state->crtc_x = plane_state->src_y = 0; + plane_state->crtc_x = 0; + plane_state->crtc_y = 0; plane_state->crtc_w = fb->width; plane_state->crtc_h = fb->height; @@ -4237,6 +4239,7 @@ struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc, struct intel_shared_dpll *pll; struct intel_shared_dpll_config *shared_dpll; enum intel_dpll_id i; + int max = dev_priv->num_shared_dpll; shared_dpll = intel_atomic_get_shared_dpll_state(crtc_state->base.state); @@ -4271,9 +4274,11 @@ struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc, WARN_ON(shared_dpll[i].crtc_mask); goto found; - } + } else if (INTEL_INFO(dev_priv)->gen < 9 && HAS_DDI(dev_priv)) + /* Do not consider SPLL */ + max = 2; - for (i = 0; i < dev_priv->num_shared_dpll; i++) { + for (i = 0; i < max; i++) { pll = &dev_priv->shared_dplls[i]; /* Only want to check enabled timings first */ @@ -9723,6 +9728,8 @@ static void haswell_get_ddi_pll(struct drm_i915_private *dev_priv, case PORT_CLK_SEL_WRPLL2: pipe_config->shared_dpll = DPLL_ID_WRPLL2; break; + case PORT_CLK_SEL_SPLL: + pipe_config->shared_dpll = DPLL_ID_SPLL; } } @@ -12003,9 +12010,10 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc, pipe_config->dpll_hw_state.cfgcr1, pipe_config->dpll_hw_state.cfgcr2); } else if (HAS_DDI(dev)) { - DRM_DEBUG_KMS("ddi_pll_sel: %u; dpll_hw_state: wrpll: 0x%x\n", + DRM_DEBUG_KMS("ddi_pll_sel: %u; dpll_hw_state: wrpll: 0x%x spll: 0x%x\n", pipe_config->ddi_pll_sel, - pipe_config->dpll_hw_state.wrpll); + pipe_config->dpll_hw_state.wrpll, + pipe_config->dpll_hw_state.spll); } else { DRM_DEBUG_KMS("dpll_hw_state: dpll: 0x%x, dpll_md: 0x%x, " "fp0: 0x%x, fp1: 0x%x\n", @@ -12528,6 +12536,7 @@ intel_pipe_config_compare(struct drm_device *dev, PIPE_CONF_CHECK_X(dpll_hw_state.fp0); PIPE_CONF_CHECK_X(dpll_hw_state.fp1); PIPE_CONF_CHECK_X(dpll_hw_state.wrpll); + PIPE_CONF_CHECK_X(dpll_hw_state.spll); PIPE_CONF_CHECK_X(dpll_hw_state.ctrl1); PIPE_CONF_CHECK_X(dpll_hw_state.cfgcr1); PIPE_CONF_CHECK_X(dpll_hw_state.cfgcr2); @@ -13032,6 +13041,9 @@ static int intel_atomic_check(struct drm_device *dev, struct intel_crtc_state *pipe_config = to_intel_crtc_state(crtc_state); + memset(&to_intel_crtc(crtc)->atomic, 0, + sizeof(struct intel_crtc_atomic_commit)); + /* Catch I915_MODE_FLAG_INHERITED */ if (crtc_state->mode.private_flags != crtc->state->mode.private_flags) crtc_state->mode_changed = true; @@ -13056,7 +13068,8 @@ static int intel_atomic_check(struct drm_device *dev, if (ret) return ret; - if (intel_pipe_config_compare(state->dev, + if (i915.fastboot && + intel_pipe_config_compare(state->dev, to_intel_crtc_state(crtc->state), pipe_config, true)) { crtc_state->mode_changed = false; @@ -14364,16 +14377,17 @@ static int intel_framebuffer_init(struct drm_device *dev, static struct drm_framebuffer * intel_user_framebuffer_create(struct drm_device *dev, struct drm_file *filp, - struct drm_mode_fb_cmd2 *mode_cmd) + struct drm_mode_fb_cmd2 *user_mode_cmd) { struct drm_i915_gem_object *obj; + struct drm_mode_fb_cmd2 mode_cmd = *user_mode_cmd; obj = to_intel_bo(drm_gem_object_lookup(dev, filp, - mode_cmd->handles[0])); + mode_cmd.handles[0])); if (&obj->base == NULL) return ERR_PTR(-ENOENT); - return intel_framebuffer_create(dev, mode_cmd, obj); + return intel_framebuffer_create(dev, &mode_cmd, obj); } #ifndef CONFIG_DRM_FBDEV_EMULATION @@ -14705,6 +14719,9 @@ static struct intel_quirk intel_quirks[] = { /* Apple Macbook 2,1 (Core 2 T7400) */ { 0x27a2, 0x8086, 0x7270, quirk_backlight_present }, + /* Apple Macbook 4,1 */ + { 0x2a02, 0x106b, 0x00a1, quirk_backlight_present }, + /* Toshiba CB35 Chromebook (Celeron 2955U) */ { 0x0a06, 0x1179, 0x0a88, quirk_backlight_present }, diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index d52a15df6917..071a76b9ac52 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4449,7 +4449,7 @@ static void gen6_set_rps(struct drm_device *dev, u8 val) POSTING_READ(GEN6_RPNSWREQ); dev_priv->rps.cur_freq = val; - trace_intel_gpu_freq_change(val * 50); + trace_intel_gpu_freq_change(intel_gpu_freq(dev_priv, val)); } static void valleyview_set_rps(struct drm_device *dev, u8 val) @@ -7255,7 +7255,8 @@ static int chv_freq_opcode(struct drm_i915_private *dev_priv, int val) int intel_gpu_freq(struct drm_i915_private *dev_priv, int val) { if (IS_GEN9(dev_priv->dev)) - return (val * GT_FREQUENCY_MULTIPLIER) / GEN9_FREQ_SCALER; + return DIV_ROUND_CLOSEST(val * GT_FREQUENCY_MULTIPLIER, + GEN9_FREQ_SCALER); else if (IS_CHERRYVIEW(dev_priv->dev)) return chv_gpu_freq(dev_priv, val); else if (IS_VALLEYVIEW(dev_priv->dev)) @@ -7267,13 +7268,14 @@ int intel_gpu_freq(struct drm_i915_private *dev_priv, int val) int intel_freq_opcode(struct drm_i915_private *dev_priv, int val) { if (IS_GEN9(dev_priv->dev)) - return (val * GEN9_FREQ_SCALER) / GT_FREQUENCY_MULTIPLIER; + return DIV_ROUND_CLOSEST(val * GEN9_FREQ_SCALER, + GT_FREQUENCY_MULTIPLIER); else if (IS_CHERRYVIEW(dev_priv->dev)) return chv_freq_opcode(dev_priv, val); else if (IS_VALLEYVIEW(dev_priv->dev)) return byt_freq_opcode(dev_priv, val); else - return val / GT_FREQUENCY_MULTIPLIER; + return DIV_ROUND_CLOSEST(val, GT_FREQUENCY_MULTIPLIER); } struct request_boost { diff --git a/drivers/gpu/drm/mgag200/mgag200_cursor.c b/drivers/gpu/drm/mgag200/mgag200_cursor.c index 4f2068fe5d88..a7bf6a90eae5 100644 --- a/drivers/gpu/drm/mgag200/mgag200_cursor.c +++ b/drivers/gpu/drm/mgag200/mgag200_cursor.c @@ -70,6 +70,11 @@ int mga_crtc_cursor_set(struct drm_crtc *crtc, BUG_ON(pixels_2 != pixels_current && pixels_2 != pixels_prev); BUG_ON(pixels_current == pixels_prev); + if (!handle || !file_priv) { + mga_hide_cursor(mdev); + return 0; + } + obj = drm_gem_object_lookup(dev, file_priv, handle); if (!obj) return -ENOENT; @@ -88,12 +93,6 @@ int mga_crtc_cursor_set(struct drm_crtc *crtc, goto out_unreserve1; } - if (!handle) { - mga_hide_cursor(mdev); - ret = 0; - goto out1; - } - /* Move cursor buffers into VRAM if they aren't already */ if (!pixels_1->pin_count) { ret = mgag200_bo_pin(pixels_1, TTM_PL_FLAG_VRAM, diff --git a/drivers/gpu/drm/nouveau/nouveau_ttm.c b/drivers/gpu/drm/nouveau/nouveau_ttm.c index 3f713c1b5dc1..d2e7d209f651 100644 --- a/drivers/gpu/drm/nouveau/nouveau_ttm.c +++ b/drivers/gpu/drm/nouveau/nouveau_ttm.c @@ -353,8 +353,7 @@ nouveau_ttm_init(struct nouveau_drm *drm) bits = nvxx_mmu(&drm->device)->dma_bits; if (nvxx_device(&drm->device)->func->pci) { - if (drm->agp.bridge || - !dma_supported(dev->dev, DMA_BIT_MASK(bits))) + if (drm->agp.bridge) bits = 32; } else if (device->func->tegra) { struct nvkm_device_tegra *tegra = device->func->tegra(device); @@ -369,6 +368,10 @@ nouveau_ttm_init(struct nouveau_drm *drm) } ret = dma_set_mask(dev->dev, DMA_BIT_MASK(bits)); + if (ret && bits != 32) { + bits = 32; + ret = dma_set_mask(dev->dev, DMA_BIT_MASK(bits)); + } if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c index fc419bb8eab7..14107b5b7811 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c @@ -133,18 +133,24 @@ gk20a_instobj_size(struct nvkm_memory *memory) static void __iomem * gk20a_instobj_cpu_map_dma(struct nvkm_memory *memory) { +#if defined(CONFIG_ARM) || defined(CONFIG_ARM64) struct gk20a_instobj_dma *node = gk20a_instobj_dma(memory); struct device *dev = node->base.imem->base.subdev.device->dev; int npages = nvkm_memory_size(memory) >> 12; struct page *pages[npages]; int i; + /* we shouldn't see a gk20a on anything but arm/arm64 anyways */ /* phys_to_page does not exist on all platforms... */ pages[0] = pfn_to_page(dma_to_phys(dev, node->handle) >> PAGE_SHIFT); for (i = 1; i < npages; i++) pages[i] = pages[0] + i; return vmap(pages, npages, VM_MAP, pgprot_writecombine(PAGE_KERNEL)); +#else + BUG(); + return NULL; +#endif } static void __iomem * diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index d3024883b844..84d45633d28c 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -221,11 +221,17 @@ int radeon_bo_create(struct radeon_device *rdev, if (!(rdev->flags & RADEON_IS_PCIE)) bo->flags &= ~(RADEON_GEM_GTT_WC | RADEON_GEM_GTT_UC); + /* Write-combined CPU mappings of GTT cause GPU hangs with RV6xx + * See https://bugs.freedesktop.org/show_bug.cgi?id=91268 + */ + if (rdev->family >= CHIP_RV610 && rdev->family <= CHIP_RV635) + bo->flags &= ~(RADEON_GEM_GTT_WC | RADEON_GEM_GTT_UC); + #ifdef CONFIG_X86_32 /* XXX: Write-combined CPU mappings of GTT seem broken on 32-bit * See https://bugs.freedesktop.org/show_bug.cgi?id=84627 */ - bo->flags &= ~RADEON_GEM_GTT_WC; + bo->flags &= ~(RADEON_GEM_GTT_WC | RADEON_GEM_GTT_UC); #elif defined(CONFIG_X86) && !defined(CONFIG_X86_PAT) /* Don't try to enable write-combining when it can't work, or things * may be slow @@ -235,9 +241,10 @@ int radeon_bo_create(struct radeon_device *rdev, #warning Please enable CONFIG_MTRR and CONFIG_X86_PAT for better performance \ thanks to write-combining - DRM_INFO_ONCE("Please enable CONFIG_MTRR and CONFIG_X86_PAT for " - "better performance thanks to write-combining\n"); - bo->flags &= ~RADEON_GEM_GTT_WC; + if (bo->flags & RADEON_GEM_GTT_WC) + DRM_INFO_ONCE("Please enable CONFIG_MTRR and CONFIG_X86_PAT for " + "better performance thanks to write-combining\n"); + bo->flags &= ~(RADEON_GEM_GTT_WC | RADEON_GEM_GTT_UC); #endif radeon_ttm_placement_from_domain(bo, domain); diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 6d80dde23400..f4f03dcc1530 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -1542,8 +1542,7 @@ int radeon_pm_late_init(struct radeon_device *rdev) ret = device_create_file(rdev->dev, &dev_attr_power_method); if (ret) DRM_ERROR("failed to create device file for power method\n"); - if (!ret) - rdev->pm.sysfs_initialized = true; + rdev->pm.sysfs_initialized = true; } mutex_lock(&rdev->pm.mutex); diff --git a/drivers/gpu/drm/radeon/si_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c index e72bf46042e0..a82b891ae1fe 100644 --- a/drivers/gpu/drm/radeon/si_dpm.c +++ b/drivers/gpu/drm/radeon/si_dpm.c @@ -2927,7 +2927,7 @@ static struct si_dpm_quirk si_dpm_quirk_list[] = { { PCI_VENDOR_ID_ATI, 0x6810, 0x1462, 0x3036, 0, 120000 }, { PCI_VENDOR_ID_ATI, 0x6811, 0x174b, 0xe271, 0, 120000 }, { PCI_VENDOR_ID_ATI, 0x6810, 0x174b, 0xe271, 85000, 90000 }, - { PCI_VENDOR_ID_ATI, 0x6811, 0x1762, 0x2015, 0, 120000 }, + { PCI_VENDOR_ID_ATI, 0x6811, 0x1462, 0x2015, 0, 120000 }, { PCI_VENDOR_ID_ATI, 0x6811, 0x1043, 0x2015, 0, 120000 }, { 0, 0, 0, 0 }, }; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index d26e0cc7dc4b..f22e1e1ee64a 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -19,7 +19,6 @@ #include <drm/drmP.h> #include <drm/drm_crtc_helper.h> #include <drm/drm_fb_helper.h> -#include <drm/drm_of.h> #include <linux/dma-mapping.h> #include <linux/pm_runtime.h> #include <linux/module.h> @@ -419,6 +418,29 @@ static int compare_of(struct device *dev, void *data) return dev->of_node == np; } +static void rockchip_add_endpoints(struct device *dev, + struct component_match **match, + struct device_node *port) +{ + struct device_node *ep, *remote; + + for_each_child_of_node(port, ep) { + remote = of_graph_get_remote_port_parent(ep); + if (!remote || !of_device_is_available(remote)) { + of_node_put(remote); + continue; + } else if (!of_device_is_available(remote->parent)) { + dev_warn(dev, "parent device of %s is not available\n", + remote->full_name); + of_node_put(remote); + continue; + } + + component_match_add(dev, match, compare_of, remote); + of_node_put(remote); + } +} + static int rockchip_drm_bind(struct device *dev) { struct drm_device *drm; @@ -461,14 +483,61 @@ static const struct component_master_ops rockchip_drm_ops = { static int rockchip_drm_platform_probe(struct platform_device *pdev) { - int ret = drm_of_component_probe(&pdev->dev, compare_of, - &rockchip_drm_ops); + struct device *dev = &pdev->dev; + struct component_match *match = NULL; + struct device_node *np = dev->of_node; + struct device_node *port; + int i; - /* keep compatibility with old code that was returning -ENODEV */ - if (ret == -EINVAL) + if (!np) return -ENODEV; + /* + * Bind the crtc ports first, so that + * drm_of_find_possible_crtcs called from encoder .bind callbacks + * works as expected. + */ + for (i = 0;; i++) { + port = of_parse_phandle(np, "ports", i); + if (!port) + break; + + if (!of_device_is_available(port->parent)) { + of_node_put(port); + continue; + } - return ret; + component_match_add(dev, &match, compare_of, port->parent); + of_node_put(port); + } + + if (i == 0) { + dev_err(dev, "missing 'ports' property\n"); + return -ENODEV; + } + + if (!match) { + dev_err(dev, "No available vop found for display-subsystem.\n"); + return -ENODEV; + } + /* + * For each bound crtc, bind the encoders attached to its + * remote endpoint. + */ + for (i = 0;; i++) { + port = of_parse_phandle(np, "ports", i); + if (!port) + break; + + if (!of_device_is_available(port->parent)) { + of_node_put(port); + continue; + } + + rockchip_add_endpoints(dev, &match, port); + of_node_put(port); + } + + return component_master_add_with_match(dev, &rockchip_drm_ops, match); } static int rockchip_drm_platform_remove(struct platform_device *pdev) diff --git a/drivers/gpu/drm/sti/Kconfig b/drivers/gpu/drm/sti/Kconfig index fbccc105819b..10c1b1926e6f 100644 --- a/drivers/gpu/drm/sti/Kconfig +++ b/drivers/gpu/drm/sti/Kconfig @@ -6,12 +6,6 @@ config DRM_STI select DRM_GEM_CMA_HELPER select DRM_KMS_CMA_HELPER select DRM_PANEL - select FW_LOADER_USER_HELPER_FALLBACK + select FW_LOADER help Choose this option to enable DRM on STM stiH41x chipset - -config DRM_STI_FBDEV - bool "DRM frame buffer device for STMicroelectronics SoC stiH41x Serie" - depends on DRM_STI - help - Choose this option to enable FBDEV on top of DRM for STM stiH41x chipset diff --git a/drivers/gpu/drm/sti/Makefile b/drivers/gpu/drm/sti/Makefile index e27490b492a5..b8057620b3b3 100644 --- a/drivers/gpu/drm/sti/Makefile +++ b/drivers/gpu/drm/sti/Makefile @@ -1,26 +1,23 @@ -sticompositor-y := \ +sti-drm-y := \ sti_mixer.o \ sti_gdp.o \ sti_vid.o \ sti_cursor.o \ sti_compositor.o \ sti_crtc.o \ - sti_plane.o - -stihdmi-y := sti_hdmi.o \ + sti_plane.o \ + sti_crtc.o \ + sti_plane.o \ + sti_hdmi.o \ sti_hdmi_tx3g0c55phy.o \ sti_hdmi_tx3g4c28phy.o \ - -stidvo-y := sti_dvo.o \ - sti_awg_utils.o - -obj-$(CONFIG_DRM_STI) = \ + sti_dvo.o \ + sti_awg_utils.o \ sti_vtg.o \ sti_vtac.o \ - stihdmi.o \ sti_hda.o \ sti_tvout.o \ - sticompositor.o \ sti_hqvdp.o \ - stidvo.o \ sti_drv.o + +obj-$(CONFIG_DRM_STI) = sti-drm.o diff --git a/drivers/gpu/drm/sti/sti_awg_utils.c b/drivers/gpu/drm/sti/sti_awg_utils.c index 6029a2e3db1d..00d0698be9d3 100644 --- a/drivers/gpu/drm/sti/sti_awg_utils.c +++ b/drivers/gpu/drm/sti/sti_awg_utils.c @@ -65,7 +65,6 @@ static int awg_generate_instr(enum opcode opcode, mux = 0; data_enable = 0; - arg = (arg << 22) >> 22; arg &= (0x3ff); break; case REPEAT: @@ -77,14 +76,12 @@ static int awg_generate_instr(enum opcode opcode, mux = 0; data_enable = 0; - arg = (arg << 22) >> 22; arg &= (0x3ff); break; case JUMP: mux = 0; data_enable = 0; arg |= 0x40; /* for jump instruction 7th bit is 1 */ - arg = (arg << 22) >> 22; arg &= 0x3ff; break; case STOP: @@ -94,7 +91,6 @@ static int awg_generate_instr(enum opcode opcode, case RPTSET: case RPLSET: case HOLD: - arg = (arg << 24) >> 24; arg &= (0x0ff); break; default: diff --git a/drivers/gpu/drm/sti/sti_compositor.c b/drivers/gpu/drm/sti/sti_compositor.c index c652627b1bca..afed2171beb9 100644 --- a/drivers/gpu/drm/sti/sti_compositor.c +++ b/drivers/gpu/drm/sti/sti_compositor.c @@ -263,7 +263,7 @@ static int sti_compositor_remove(struct platform_device *pdev) return 0; } -static struct platform_driver sti_compositor_driver = { +struct platform_driver sti_compositor_driver = { .driver = { .name = "sti-compositor", .of_match_table = compositor_of_match, @@ -272,8 +272,6 @@ static struct platform_driver sti_compositor_driver = { .remove = sti_compositor_remove, }; -module_platform_driver(sti_compositor_driver); - MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>"); MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/sti/sti_crtc.c b/drivers/gpu/drm/sti/sti_crtc.c index 493c4a3006ad..3ae09dcd4fd8 100644 --- a/drivers/gpu/drm/sti/sti_crtc.c +++ b/drivers/gpu/drm/sti/sti_crtc.c @@ -226,7 +226,7 @@ static void sti_crtc_atomic_flush(struct drm_crtc *crtc, } } -static struct drm_crtc_helper_funcs sti_crtc_helper_funcs = { +static const struct drm_crtc_helper_funcs sti_crtc_helper_funcs = { .enable = sti_crtc_enable, .disable = sti_crtc_disabling, .mode_fixup = sti_crtc_mode_fixup, @@ -254,15 +254,17 @@ static int sti_crtc_set_property(struct drm_crtc *crtc, int sti_crtc_vblank_cb(struct notifier_block *nb, unsigned long event, void *data) { - struct drm_device *drm_dev; struct sti_compositor *compo = container_of(nb, struct sti_compositor, vtg_vblank_nb); - int *crtc = data; + struct drm_crtc *crtc = data; + struct sti_mixer *mixer; unsigned long flags; struct sti_private *priv; + unsigned int pipe; - drm_dev = compo->mixer[*crtc]->drm_crtc.dev; - priv = drm_dev->dev_private; + priv = crtc->dev->dev_private; + pipe = drm_crtc_index(crtc); + mixer = compo->mixer[pipe]; if ((event != VTG_TOP_FIELD_EVENT) && (event != VTG_BOTTOM_FIELD_EVENT)) { @@ -270,30 +272,30 @@ int sti_crtc_vblank_cb(struct notifier_block *nb, return -EINVAL; } - drm_handle_vblank(drm_dev, *crtc); + drm_crtc_handle_vblank(crtc); - spin_lock_irqsave(&drm_dev->event_lock, flags); - if (compo->mixer[*crtc]->pending_event) { - drm_send_vblank_event(drm_dev, -1, - compo->mixer[*crtc]->pending_event); - drm_vblank_put(drm_dev, *crtc); - compo->mixer[*crtc]->pending_event = NULL; + spin_lock_irqsave(&crtc->dev->event_lock, flags); + if (mixer->pending_event) { + drm_crtc_send_vblank_event(crtc, mixer->pending_event); + drm_crtc_vblank_put(crtc); + mixer->pending_event = NULL; } - spin_unlock_irqrestore(&drm_dev->event_lock, flags); + spin_unlock_irqrestore(&crtc->dev->event_lock, flags); - if (compo->mixer[*crtc]->status == STI_MIXER_DISABLING) { + if (mixer->status == STI_MIXER_DISABLING) { struct drm_plane *p; /* Disable mixer only if all overlay planes (GDP and VDP) * are disabled */ - list_for_each_entry(p, &drm_dev->mode_config.plane_list, head) { + list_for_each_entry(p, &crtc->dev->mode_config.plane_list, + head) { struct sti_plane *plane = to_sti_plane(p); if ((plane->desc & STI_PLANE_TYPE_MASK) <= STI_VDP) if (plane->status != STI_PLANE_DISABLED) return 0; } - sti_crtc_disable(&compo->mixer[*crtc]->drm_crtc); + sti_crtc_disable(crtc); } return 0; @@ -304,25 +306,26 @@ int sti_crtc_enable_vblank(struct drm_device *dev, unsigned int pipe) struct sti_private *dev_priv = dev->dev_private; struct sti_compositor *compo = dev_priv->compo; struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb; + struct drm_crtc *crtc = &compo->mixer[pipe]->drm_crtc; DRM_DEBUG_DRIVER("\n"); if (sti_vtg_register_client(pipe == STI_MIXER_MAIN ? compo->vtg_main : compo->vtg_aux, - vtg_vblank_nb, pipe)) { + vtg_vblank_nb, crtc)) { DRM_ERROR("Cannot register VTG notifier\n"); return -EINVAL; } return 0; } -EXPORT_SYMBOL(sti_crtc_enable_vblank); void sti_crtc_disable_vblank(struct drm_device *drm_dev, unsigned int pipe) { struct sti_private *priv = drm_dev->dev_private; struct sti_compositor *compo = priv->compo; struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb; + struct drm_crtc *crtc = &compo->mixer[pipe]->drm_crtc; DRM_DEBUG_DRIVER("\n"); @@ -332,13 +335,12 @@ void sti_crtc_disable_vblank(struct drm_device *drm_dev, unsigned int pipe) /* free the resources of the pending requests */ if (compo->mixer[pipe]->pending_event) { - drm_vblank_put(drm_dev, pipe); + drm_crtc_vblank_put(crtc); compo->mixer[pipe]->pending_event = NULL; } } -EXPORT_SYMBOL(sti_crtc_disable_vblank); -static struct drm_crtc_funcs sti_crtc_funcs = { +static const struct drm_crtc_funcs sti_crtc_funcs = { .set_config = drm_atomic_helper_set_config, .page_flip = drm_atomic_helper_page_flip, .destroy = sti_crtc_destroy, @@ -357,7 +359,6 @@ bool sti_crtc_is_main(struct drm_crtc *crtc) return false; } -EXPORT_SYMBOL(sti_crtc_is_main); int sti_crtc_init(struct drm_device *drm_dev, struct sti_mixer *mixer, struct drm_plane *primary, struct drm_plane *cursor) diff --git a/drivers/gpu/drm/sti/sti_drv.c b/drivers/gpu/drm/sti/sti_drv.c index f8469967a0bf..1469987949d8 100644 --- a/drivers/gpu/drm/sti/sti_drv.c +++ b/drivers/gpu/drm/sti/sti_drv.c @@ -107,7 +107,7 @@ static int sti_atomic_commit(struct drm_device *drm, return 0; } -static struct drm_mode_config_funcs sti_mode_config_funcs = { +static const struct drm_mode_config_funcs sti_mode_config_funcs = { .fb_create = drm_fb_cma_create, .atomic_check = drm_atomic_helper_check, .atomic_commit = sti_atomic_commit, @@ -123,8 +123,8 @@ static void sti_mode_config_init(struct drm_device *dev) * this value would be used to check framebuffer size limitation * at drm_mode_addfb(). */ - dev->mode_config.max_width = STI_MAX_FB_HEIGHT; - dev->mode_config.max_height = STI_MAX_FB_WIDTH; + dev->mode_config.max_width = STI_MAX_FB_WIDTH; + dev->mode_config.max_height = STI_MAX_FB_HEIGHT; dev->mode_config.funcs = &sti_mode_config_funcs; } @@ -160,11 +160,10 @@ static int sti_load(struct drm_device *dev, unsigned long flags) drm_mode_config_reset(dev); -#ifdef CONFIG_DRM_STI_FBDEV drm_fbdev_cma_init(dev, 32, dev->mode_config.num_crtc, dev->mode_config.num_connector); -#endif + return 0; } @@ -287,7 +286,29 @@ static struct platform_driver sti_platform_driver = { }, }; -module_platform_driver(sti_platform_driver); +static struct platform_driver * const drivers[] = { + &sti_tvout_driver, + &sti_vtac_driver, + &sti_hqvdp_driver, + &sti_hdmi_driver, + &sti_hda_driver, + &sti_dvo_driver, + &sti_vtg_driver, + &sti_compositor_driver, + &sti_platform_driver, +}; + +static int sti_drm_init(void) +{ + return platform_register_drivers(drivers, ARRAY_SIZE(drivers)); +} +module_init(sti_drm_init); + +static void sti_drm_exit(void) +{ + platform_unregister_drivers(drivers, ARRAY_SIZE(drivers)); +} +module_exit(sti_drm_exit); MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>"); MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver"); diff --git a/drivers/gpu/drm/sti/sti_drv.h b/drivers/gpu/drm/sti/sti_drv.h index 9372f69e1859..30ddc20841c3 100644 --- a/drivers/gpu/drm/sti/sti_drv.h +++ b/drivers/gpu/drm/sti/sti_drv.h @@ -32,4 +32,13 @@ struct sti_private { } commit; }; +extern struct platform_driver sti_tvout_driver; +extern struct platform_driver sti_vtac_driver; +extern struct platform_driver sti_hqvdp_driver; +extern struct platform_driver sti_hdmi_driver; +extern struct platform_driver sti_hda_driver; +extern struct platform_driver sti_dvo_driver; +extern struct platform_driver sti_vtg_driver; +extern struct platform_driver sti_compositor_driver; + #endif diff --git a/drivers/gpu/drm/sti/sti_dvo.c b/drivers/gpu/drm/sti/sti_dvo.c index d141d645bd13..45cbe2bf7dd6 100644 --- a/drivers/gpu/drm/sti/sti_dvo.c +++ b/drivers/gpu/drm/sti/sti_dvo.c @@ -329,7 +329,8 @@ struct drm_encoder *sti_dvo_best_encoder(struct drm_connector *connector) return dvo_connector->encoder; } -static struct drm_connector_helper_funcs sti_dvo_connector_helper_funcs = { +static const +struct drm_connector_helper_funcs sti_dvo_connector_helper_funcs = { .get_modes = sti_dvo_connector_get_modes, .mode_valid = sti_dvo_connector_mode_valid, .best_encoder = sti_dvo_best_encoder, @@ -364,7 +365,7 @@ static void sti_dvo_connector_destroy(struct drm_connector *connector) kfree(dvo_connector); } -static struct drm_connector_funcs sti_dvo_connector_funcs = { +static const struct drm_connector_funcs sti_dvo_connector_funcs = { .dpms = drm_atomic_helper_connector_dpms, .fill_modes = drm_helper_probe_single_connector_modes, .detect = sti_dvo_connector_detect, @@ -557,8 +558,6 @@ struct platform_driver sti_dvo_driver = { .remove = sti_dvo_remove, }; -module_platform_driver(sti_dvo_driver); - MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>"); MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/sti/sti_gdp.c b/drivers/gpu/drm/sti/sti_gdp.c index 9365670427ad..c85dc7d6b005 100644 --- a/drivers/gpu/drm/sti/sti_gdp.c +++ b/drivers/gpu/drm/sti/sti_gdp.c @@ -492,7 +492,7 @@ static void sti_gdp_atomic_update(struct drm_plane *drm_plane, /* Register gdp callback */ if (sti_vtg_register_client(mixer->id == STI_MIXER_MAIN ? compo->vtg_main : compo->vtg_aux, - &gdp->vtg_field_nb, mixer->id)) { + &gdp->vtg_field_nb, crtc)) { DRM_ERROR("Cannot register VTG notifier\n"); return; } diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c index 598cd78b0b16..d735daccd458 100644 --- a/drivers/gpu/drm/sti/sti_hda.c +++ b/drivers/gpu/drm/sti/sti_hda.c @@ -589,7 +589,8 @@ struct drm_encoder *sti_hda_best_encoder(struct drm_connector *connector) return hda_connector->encoder; } -static struct drm_connector_helper_funcs sti_hda_connector_helper_funcs = { +static const +struct drm_connector_helper_funcs sti_hda_connector_helper_funcs = { .get_modes = sti_hda_connector_get_modes, .mode_valid = sti_hda_connector_mode_valid, .best_encoder = sti_hda_best_encoder, @@ -611,7 +612,7 @@ static void sti_hda_connector_destroy(struct drm_connector *connector) kfree(hda_connector); } -static struct drm_connector_funcs sti_hda_connector_funcs = { +static const struct drm_connector_funcs sti_hda_connector_funcs = { .dpms = drm_atomic_helper_connector_dpms, .fill_modes = drm_helper_probe_single_connector_modes, .detect = sti_hda_connector_detect, @@ -784,8 +785,6 @@ struct platform_driver sti_hda_driver = { .remove = sti_hda_remove, }; -module_platform_driver(sti_hda_driver); - MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>"); MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c index 09e29e43423e..cd501563c0cc 100644 --- a/drivers/gpu/drm/sti/sti_hdmi.c +++ b/drivers/gpu/drm/sti/sti_hdmi.c @@ -628,7 +628,8 @@ struct drm_encoder *sti_hdmi_best_encoder(struct drm_connector *connector) return hdmi_connector->encoder; } -static struct drm_connector_helper_funcs sti_hdmi_connector_helper_funcs = { +static const +struct drm_connector_helper_funcs sti_hdmi_connector_helper_funcs = { .get_modes = sti_hdmi_connector_get_modes, .mode_valid = sti_hdmi_connector_mode_valid, .best_encoder = sti_hdmi_best_encoder, @@ -663,7 +664,7 @@ static void sti_hdmi_connector_destroy(struct drm_connector *connector) kfree(hdmi_connector); } -static struct drm_connector_funcs sti_hdmi_connector_funcs = { +static const struct drm_connector_funcs sti_hdmi_connector_funcs = { .dpms = drm_atomic_helper_connector_dpms, .fill_modes = drm_helper_probe_single_connector_modes, .detect = sti_hdmi_connector_detect, @@ -700,18 +701,17 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data) encoder = sti_hdmi_find_encoder(drm_dev); if (!encoder) - goto err_adapt; + return -EINVAL; connector = devm_kzalloc(dev, sizeof(*connector), GFP_KERNEL); if (!connector) - goto err_adapt; - + return -EINVAL; connector->hdmi = hdmi; bridge = devm_kzalloc(dev, sizeof(*bridge), GFP_KERNEL); if (!bridge) - goto err_adapt; + return -EINVAL; bridge->driver_private = hdmi; bridge->funcs = &sti_hdmi_bridge_funcs; @@ -748,8 +748,7 @@ err_sysfs: drm_connector_unregister(drm_connector); err_connector: drm_connector_cleanup(drm_connector); -err_adapt: - put_device(&hdmi->ddc_adapt->dev); + return -EINVAL; } @@ -794,13 +793,10 @@ static int sti_hdmi_probe(struct platform_device *pdev) ddc = of_parse_phandle(pdev->dev.of_node, "ddc", 0); if (ddc) { - hdmi->ddc_adapt = of_find_i2c_adapter_by_node(ddc); - if (!hdmi->ddc_adapt) { - of_node_put(ddc); - return -EPROBE_DEFER; - } - + hdmi->ddc_adapt = of_get_i2c_adapter_by_node(ddc); of_node_put(ddc); + if (!hdmi->ddc_adapt) + return -EPROBE_DEFER; } hdmi->dev = pdev->dev; @@ -809,24 +805,29 @@ static int sti_hdmi_probe(struct platform_device *pdev) res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hdmi-reg"); if (!res) { DRM_ERROR("Invalid hdmi resource\n"); - return -ENOMEM; + ret = -ENOMEM; + goto release_adapter; } hdmi->regs = devm_ioremap_nocache(dev, res->start, resource_size(res)); - if (!hdmi->regs) - return -ENOMEM; + if (!hdmi->regs) { + ret = -ENOMEM; + goto release_adapter; + } if (of_device_is_compatible(np, "st,stih416-hdmi")) { res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "syscfg"); if (!res) { DRM_ERROR("Invalid syscfg resource\n"); - return -ENOMEM; + ret = -ENOMEM; + goto release_adapter; } hdmi->syscfg = devm_ioremap_nocache(dev, res->start, resource_size(res)); - if (!hdmi->syscfg) - return -ENOMEM; - + if (!hdmi->syscfg) { + ret = -ENOMEM; + goto release_adapter; + } } hdmi->phy_ops = (struct hdmi_phy_ops *) @@ -836,25 +837,29 @@ static int sti_hdmi_probe(struct platform_device *pdev) hdmi->clk_pix = devm_clk_get(dev, "pix"); if (IS_ERR(hdmi->clk_pix)) { DRM_ERROR("Cannot get hdmi_pix clock\n"); - return PTR_ERR(hdmi->clk_pix); + ret = PTR_ERR(hdmi->clk_pix); + goto release_adapter; } hdmi->clk_tmds = devm_clk_get(dev, "tmds"); if (IS_ERR(hdmi->clk_tmds)) { DRM_ERROR("Cannot get hdmi_tmds clock\n"); - return PTR_ERR(hdmi->clk_tmds); + ret = PTR_ERR(hdmi->clk_tmds); + goto release_adapter; } hdmi->clk_phy = devm_clk_get(dev, "phy"); if (IS_ERR(hdmi->clk_phy)) { DRM_ERROR("Cannot get hdmi_phy clock\n"); - return PTR_ERR(hdmi->clk_phy); + ret = PTR_ERR(hdmi->clk_phy); + goto release_adapter; } hdmi->clk_audio = devm_clk_get(dev, "audio"); if (IS_ERR(hdmi->clk_audio)) { DRM_ERROR("Cannot get hdmi_audio clock\n"); - return PTR_ERR(hdmi->clk_audio); + ret = PTR_ERR(hdmi->clk_audio); + goto release_adapter; } hdmi->hpd = readl(hdmi->regs + HDMI_STA) & HDMI_STA_HOT_PLUG; @@ -867,7 +872,7 @@ static int sti_hdmi_probe(struct platform_device *pdev) hdmi_irq_thread, IRQF_ONESHOT, dev_name(dev), hdmi); if (ret) { DRM_ERROR("Failed to register HDMI interrupt\n"); - return ret; + goto release_adapter; } hdmi->reset = devm_reset_control_get(dev, "hdmi"); @@ -878,16 +883,20 @@ static int sti_hdmi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, hdmi); return component_add(&pdev->dev, &sti_hdmi_ops); + + release_adapter: + i2c_put_adapter(hdmi->ddc_adapt); + + return ret; } static int sti_hdmi_remove(struct platform_device *pdev) { struct sti_hdmi *hdmi = dev_get_drvdata(&pdev->dev); - if (hdmi->ddc_adapt) - put_device(&hdmi->ddc_adapt->dev); - + i2c_put_adapter(hdmi->ddc_adapt); component_del(&pdev->dev, &sti_hdmi_ops); + return 0; } @@ -901,8 +910,6 @@ struct platform_driver sti_hdmi_driver = { .remove = sti_hdmi_remove, }; -module_platform_driver(sti_hdmi_driver); - MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>"); MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/sti/sti_hqvdp.c b/drivers/gpu/drm/sti/sti_hqvdp.c index 7c8f9b8bfae1..ea0690bc77d5 100644 --- a/drivers/gpu/drm/sti/sti_hqvdp.c +++ b/drivers/gpu/drm/sti/sti_hqvdp.c @@ -628,6 +628,153 @@ static void sti_hqvdp_init(struct sti_hqvdp *hqvdp) memset(hqvdp->hqvdp_cmd, 0, size); } +static void sti_hqvdp_init_plugs(struct sti_hqvdp *hqvdp) +{ + /* Configure Plugs (same for RD & WR) */ + writel(PLUG_PAGE_SIZE_256, hqvdp->regs + HQVDP_RD_PLUG_PAGE_SIZE); + writel(PLUG_MIN_OPC_8, hqvdp->regs + HQVDP_RD_PLUG_MIN_OPC); + writel(PLUG_MAX_OPC_64, hqvdp->regs + HQVDP_RD_PLUG_MAX_OPC); + writel(PLUG_MAX_CHK_2X, hqvdp->regs + HQVDP_RD_PLUG_MAX_CHK); + writel(PLUG_MAX_MSG_1X, hqvdp->regs + HQVDP_RD_PLUG_MAX_MSG); + writel(PLUG_MIN_SPACE_1, hqvdp->regs + HQVDP_RD_PLUG_MIN_SPACE); + writel(PLUG_CONTROL_ENABLE, hqvdp->regs + HQVDP_RD_PLUG_CONTROL); + + writel(PLUG_PAGE_SIZE_256, hqvdp->regs + HQVDP_WR_PLUG_PAGE_SIZE); + writel(PLUG_MIN_OPC_8, hqvdp->regs + HQVDP_WR_PLUG_MIN_OPC); + writel(PLUG_MAX_OPC_64, hqvdp->regs + HQVDP_WR_PLUG_MAX_OPC); + writel(PLUG_MAX_CHK_2X, hqvdp->regs + HQVDP_WR_PLUG_MAX_CHK); + writel(PLUG_MAX_MSG_1X, hqvdp->regs + HQVDP_WR_PLUG_MAX_MSG); + writel(PLUG_MIN_SPACE_1, hqvdp->regs + HQVDP_WR_PLUG_MIN_SPACE); + writel(PLUG_CONTROL_ENABLE, hqvdp->regs + HQVDP_WR_PLUG_CONTROL); +} + +/** + * sti_hqvdp_start_xp70 + * @hqvdp: hqvdp pointer + * + * Run the xP70 initialization sequence + */ +static void sti_hqvdp_start_xp70(struct sti_hqvdp *hqvdp) +{ + const struct firmware *firmware; + u32 *fw_rd_plug, *fw_wr_plug, *fw_pmem, *fw_dmem; + u8 *data; + int i; + struct fw_header { + int rd_size; + int wr_size; + int pmem_size; + int dmem_size; + } *header; + + DRM_DEBUG_DRIVER("\n"); + + if (hqvdp->xp70_initialized) { + DRM_INFO("HQVDP XP70 already initialized\n"); + return; + } + + /* Request firmware */ + if (request_firmware(&firmware, HQVDP_FMW_NAME, hqvdp->dev)) { + DRM_ERROR("Can't get HQVDP firmware\n"); + return; + } + + /* Check firmware parts */ + if (!firmware) { + DRM_ERROR("Firmware not available\n"); + return; + } + + header = (struct fw_header *)firmware->data; + if (firmware->size < sizeof(*header)) { + DRM_ERROR("Invalid firmware size (%d)\n", firmware->size); + goto out; + } + if ((sizeof(*header) + header->rd_size + header->wr_size + + header->pmem_size + header->dmem_size) != firmware->size) { + DRM_ERROR("Invalid fmw structure (%d+%d+%d+%d+%d != %d)\n", + sizeof(*header), header->rd_size, header->wr_size, + header->pmem_size, header->dmem_size, + firmware->size); + goto out; + } + + data = (u8 *)firmware->data; + data += sizeof(*header); + fw_rd_plug = (void *)data; + data += header->rd_size; + fw_wr_plug = (void *)data; + data += header->wr_size; + fw_pmem = (void *)data; + data += header->pmem_size; + fw_dmem = (void *)data; + + /* Enable clock */ + if (clk_prepare_enable(hqvdp->clk)) + DRM_ERROR("Failed to prepare/enable HQVDP clk\n"); + + /* Reset */ + writel(SW_RESET_CTRL_FULL, hqvdp->regs + HQVDP_MBX_SW_RESET_CTRL); + + for (i = 0; i < POLL_MAX_ATTEMPT; i++) { + if (readl(hqvdp->regs + HQVDP_MBX_STARTUP_CTRL1) + & STARTUP_CTRL1_RST_DONE) + break; + msleep(POLL_DELAY_MS); + } + if (i == POLL_MAX_ATTEMPT) { + DRM_ERROR("Could not reset\n"); + goto out; + } + + /* Init Read & Write plugs */ + for (i = 0; i < header->rd_size / 4; i++) + writel(fw_rd_plug[i], hqvdp->regs + HQVDP_RD_PLUG + i * 4); + for (i = 0; i < header->wr_size / 4; i++) + writel(fw_wr_plug[i], hqvdp->regs + HQVDP_WR_PLUG + i * 4); + + sti_hqvdp_init_plugs(hqvdp); + + /* Authorize Idle Mode */ + writel(STARTUP_CTRL1_AUTH_IDLE, hqvdp->regs + HQVDP_MBX_STARTUP_CTRL1); + + /* Prevent VTG interruption during the boot */ + writel(SOFT_VSYNC_SW_CTRL_IRQ, hqvdp->regs + HQVDP_MBX_SOFT_VSYNC); + writel(0, hqvdp->regs + HQVDP_MBX_NEXT_CMD); + + /* Download PMEM & DMEM */ + for (i = 0; i < header->pmem_size / 4; i++) + writel(fw_pmem[i], hqvdp->regs + HQVDP_PMEM + i * 4); + for (i = 0; i < header->dmem_size / 4; i++) + writel(fw_dmem[i], hqvdp->regs + HQVDP_DMEM + i * 4); + + /* Enable fetch */ + writel(STARTUP_CTRL2_FETCH_EN, hqvdp->regs + HQVDP_MBX_STARTUP_CTRL2); + + /* Wait end of boot */ + for (i = 0; i < POLL_MAX_ATTEMPT; i++) { + if (readl(hqvdp->regs + HQVDP_MBX_INFO_XP70) + & INFO_XP70_FW_READY) + break; + msleep(POLL_DELAY_MS); + } + if (i == POLL_MAX_ATTEMPT) { + DRM_ERROR("Could not boot\n"); + goto out; + } + + /* Launch Vsync */ + writel(SOFT_VSYNC_HW, hqvdp->regs + HQVDP_MBX_SOFT_VSYNC); + + DRM_INFO("HQVDP XP70 initialized\n"); + + hqvdp->xp70_initialized = true; + +out: + release_firmware(firmware); +} + static void sti_hqvdp_atomic_update(struct drm_plane *drm_plane, struct drm_plane_state *oldstate) { @@ -754,6 +901,9 @@ static void sti_hqvdp_atomic_update(struct drm_plane *drm_plane, sti_hqvdp_update_hvsrc(HVSRC_VERT, scale_v, &cmd->hvsrc); if (first_prepare) { + /* Start HQVDP XP70 coprocessor */ + sti_hqvdp_start_xp70(hqvdp); + /* Prevent VTG shutdown */ if (clk_prepare_enable(hqvdp->clk_pix_main)) { DRM_ERROR("Failed to prepare/enable pix main clk\n"); @@ -763,7 +913,7 @@ static void sti_hqvdp_atomic_update(struct drm_plane *drm_plane, /* Register VTG Vsync callback to handle bottom fields */ if (sti_vtg_register_client(hqvdp->vtg, &hqvdp->vtg_nb, - mixer->id)) { + crtc)) { DRM_ERROR("Cannot register VTG notifier\n"); return; } @@ -836,168 +986,16 @@ static struct drm_plane *sti_hqvdp_create(struct drm_device *drm_dev, return &hqvdp->plane.drm_plane; } -static void sti_hqvdp_init_plugs(struct sti_hqvdp *hqvdp) -{ - /* Configure Plugs (same for RD & WR) */ - writel(PLUG_PAGE_SIZE_256, hqvdp->regs + HQVDP_RD_PLUG_PAGE_SIZE); - writel(PLUG_MIN_OPC_8, hqvdp->regs + HQVDP_RD_PLUG_MIN_OPC); - writel(PLUG_MAX_OPC_64, hqvdp->regs + HQVDP_RD_PLUG_MAX_OPC); - writel(PLUG_MAX_CHK_2X, hqvdp->regs + HQVDP_RD_PLUG_MAX_CHK); - writel(PLUG_MAX_MSG_1X, hqvdp->regs + HQVDP_RD_PLUG_MAX_MSG); - writel(PLUG_MIN_SPACE_1, hqvdp->regs + HQVDP_RD_PLUG_MIN_SPACE); - writel(PLUG_CONTROL_ENABLE, hqvdp->regs + HQVDP_RD_PLUG_CONTROL); - - writel(PLUG_PAGE_SIZE_256, hqvdp->regs + HQVDP_WR_PLUG_PAGE_SIZE); - writel(PLUG_MIN_OPC_8, hqvdp->regs + HQVDP_WR_PLUG_MIN_OPC); - writel(PLUG_MAX_OPC_64, hqvdp->regs + HQVDP_WR_PLUG_MAX_OPC); - writel(PLUG_MAX_CHK_2X, hqvdp->regs + HQVDP_WR_PLUG_MAX_CHK); - writel(PLUG_MAX_MSG_1X, hqvdp->regs + HQVDP_WR_PLUG_MAX_MSG); - writel(PLUG_MIN_SPACE_1, hqvdp->regs + HQVDP_WR_PLUG_MIN_SPACE); - writel(PLUG_CONTROL_ENABLE, hqvdp->regs + HQVDP_WR_PLUG_CONTROL); -} - -/** - * sti_hqvdp_start_xp70 - * @firmware: firmware found - * @ctxt: hqvdp structure - * - * Run the xP70 initialization sequence - */ -static void sti_hqvdp_start_xp70(const struct firmware *firmware, void *ctxt) -{ - struct sti_hqvdp *hqvdp = ctxt; - u32 *fw_rd_plug, *fw_wr_plug, *fw_pmem, *fw_dmem; - u8 *data; - int i; - struct fw_header { - int rd_size; - int wr_size; - int pmem_size; - int dmem_size; - } *header; - - DRM_DEBUG_DRIVER("\n"); - - if (hqvdp->xp70_initialized) { - DRM_INFO("HQVDP XP70 already initialized\n"); - return; - } - - /* Check firmware parts */ - if (!firmware) { - DRM_ERROR("Firmware not available\n"); - return; - } - - header = (struct fw_header *) firmware->data; - if (firmware->size < sizeof(*header)) { - DRM_ERROR("Invalid firmware size (%d)\n", firmware->size); - goto out; - } - if ((sizeof(*header) + header->rd_size + header->wr_size + - header->pmem_size + header->dmem_size) != firmware->size) { - DRM_ERROR("Invalid fmw structure (%d+%d+%d+%d+%d != %d)\n", - sizeof(*header), header->rd_size, header->wr_size, - header->pmem_size, header->dmem_size, - firmware->size); - goto out; - } - - data = (u8 *) firmware->data; - data += sizeof(*header); - fw_rd_plug = (void *) data; - data += header->rd_size; - fw_wr_plug = (void *) data; - data += header->wr_size; - fw_pmem = (void *) data; - data += header->pmem_size; - fw_dmem = (void *) data; - - /* Enable clock */ - if (clk_prepare_enable(hqvdp->clk)) - DRM_ERROR("Failed to prepare/enable HQVDP clk\n"); - - /* Reset */ - writel(SW_RESET_CTRL_FULL, hqvdp->regs + HQVDP_MBX_SW_RESET_CTRL); - - for (i = 0; i < POLL_MAX_ATTEMPT; i++) { - if (readl(hqvdp->regs + HQVDP_MBX_STARTUP_CTRL1) - & STARTUP_CTRL1_RST_DONE) - break; - msleep(POLL_DELAY_MS); - } - if (i == POLL_MAX_ATTEMPT) { - DRM_ERROR("Could not reset\n"); - goto out; - } - - /* Init Read & Write plugs */ - for (i = 0; i < header->rd_size / 4; i++) - writel(fw_rd_plug[i], hqvdp->regs + HQVDP_RD_PLUG + i * 4); - for (i = 0; i < header->wr_size / 4; i++) - writel(fw_wr_plug[i], hqvdp->regs + HQVDP_WR_PLUG + i * 4); - - sti_hqvdp_init_plugs(hqvdp); - - /* Authorize Idle Mode */ - writel(STARTUP_CTRL1_AUTH_IDLE, hqvdp->regs + HQVDP_MBX_STARTUP_CTRL1); - - /* Prevent VTG interruption during the boot */ - writel(SOFT_VSYNC_SW_CTRL_IRQ, hqvdp->regs + HQVDP_MBX_SOFT_VSYNC); - writel(0, hqvdp->regs + HQVDP_MBX_NEXT_CMD); - - /* Download PMEM & DMEM */ - for (i = 0; i < header->pmem_size / 4; i++) - writel(fw_pmem[i], hqvdp->regs + HQVDP_PMEM + i * 4); - for (i = 0; i < header->dmem_size / 4; i++) - writel(fw_dmem[i], hqvdp->regs + HQVDP_DMEM + i * 4); - - /* Enable fetch */ - writel(STARTUP_CTRL2_FETCH_EN, hqvdp->regs + HQVDP_MBX_STARTUP_CTRL2); - - /* Wait end of boot */ - for (i = 0; i < POLL_MAX_ATTEMPT; i++) { - if (readl(hqvdp->regs + HQVDP_MBX_INFO_XP70) - & INFO_XP70_FW_READY) - break; - msleep(POLL_DELAY_MS); - } - if (i == POLL_MAX_ATTEMPT) { - DRM_ERROR("Could not boot\n"); - goto out; - } - - /* Launch Vsync */ - writel(SOFT_VSYNC_HW, hqvdp->regs + HQVDP_MBX_SOFT_VSYNC); - - DRM_INFO("HQVDP XP70 initialized\n"); - - hqvdp->xp70_initialized = true; - -out: - release_firmware(firmware); -} - int sti_hqvdp_bind(struct device *dev, struct device *master, void *data) { struct sti_hqvdp *hqvdp = dev_get_drvdata(dev); struct drm_device *drm_dev = data; struct drm_plane *plane; - int err; DRM_DEBUG_DRIVER("\n"); hqvdp->drm_dev = drm_dev; - /* Request for firmware */ - err = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, - HQVDP_FMW_NAME, hqvdp->dev, - GFP_KERNEL, hqvdp, sti_hqvdp_start_xp70); - if (err) { - DRM_ERROR("Can't get HQVDP firmware\n"); - return err; - } - /* Create HQVDP plane once xp70 is initialized */ plane = sti_hqvdp_create(drm_dev, hqvdp->dev, STI_HQVDP_0); if (!plane) @@ -1090,8 +1088,6 @@ struct platform_driver sti_hqvdp_driver = { .remove = sti_hqvdp_remove, }; -module_platform_driver(sti_hqvdp_driver); - MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>"); MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/sti/sti_mixer.c b/drivers/gpu/drm/sti/sti_mixer.c index 0182e9365004..49db835dce03 100644 --- a/drivers/gpu/drm/sti/sti_mixer.c +++ b/drivers/gpu/drm/sti/sti_mixer.c @@ -10,6 +10,11 @@ #include "sti_mixer.h" #include "sti_vtg.h" +/* Module parameter to set the background color of the mixer */ +static unsigned int bkg_color = 0x000000; +MODULE_PARM_DESC(bkgcolor, "Value of the background color 0xRRGGBB"); +module_param_named(bkgcolor, bkg_color, int, 0644); + /* Identity: G=Y , B=Cb , R=Cr */ static const u32 mixerColorSpaceMatIdentity[] = { 0x10000000, 0x00000000, 0x10000000, 0x00001000, @@ -58,7 +63,6 @@ const char *sti_mixer_to_str(struct sti_mixer *mixer) return "<UNKNOWN MIXER>"; } } -EXPORT_SYMBOL(sti_mixer_to_str); static inline u32 sti_mixer_reg_read(struct sti_mixer *mixer, u32 reg_id) { @@ -81,11 +85,9 @@ void sti_mixer_set_background_status(struct sti_mixer *mixer, bool enable) } static void sti_mixer_set_background_color(struct sti_mixer *mixer, - u8 red, u8 green, u8 blue) + unsigned int rgb) { - u32 val = (red << 16) | (green << 8) | blue; - - sti_mixer_reg_write(mixer, GAM_MIXER_BKC, val); + sti_mixer_reg_write(mixer, GAM_MIXER_BKC, rgb); } static void sti_mixer_set_background_area(struct sti_mixer *mixer, @@ -175,7 +177,7 @@ int sti_mixer_active_video_area(struct sti_mixer *mixer, sti_mixer_reg_write(mixer, GAM_MIXER_AVO, ydo << 16 | xdo); sti_mixer_reg_write(mixer, GAM_MIXER_AVS, yds << 16 | xds); - sti_mixer_set_background_color(mixer, 0xFF, 0, 0); + sti_mixer_set_background_color(mixer, bkg_color); sti_mixer_set_background_area(mixer, mode); sti_mixer_set_background_status(mixer, true); diff --git a/drivers/gpu/drm/sti/sti_plane.c b/drivers/gpu/drm/sti/sti_plane.c index d5c5e91f2956..2e5c751910c5 100644 --- a/drivers/gpu/drm/sti/sti_plane.c +++ b/drivers/gpu/drm/sti/sti_plane.c @@ -42,7 +42,6 @@ const char *sti_plane_to_str(struct sti_plane *plane) return "<UNKNOWN PLANE>"; } } -EXPORT_SYMBOL(sti_plane_to_str); static void sti_plane_destroy(struct drm_plane *drm_plane) { @@ -108,7 +107,6 @@ void sti_plane_init_property(struct sti_plane *plane, plane->drm_plane.base.id, sti_plane_to_str(plane), plane->zorder); } -EXPORT_SYMBOL(sti_plane_init_property); struct drm_plane_funcs sti_plane_helpers_funcs = { .update_plane = drm_atomic_helper_update_plane, @@ -119,4 +117,3 @@ struct drm_plane_funcs sti_plane_helpers_funcs = { .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, }; -EXPORT_SYMBOL(sti_plane_helpers_funcs); diff --git a/drivers/gpu/drm/sti/sti_tvout.c b/drivers/gpu/drm/sti/sti_tvout.c index c1aac8e66fb5..c8a4c5dae2b6 100644 --- a/drivers/gpu/drm/sti/sti_tvout.c +++ b/drivers/gpu/drm/sti/sti_tvout.c @@ -735,8 +735,6 @@ struct platform_driver sti_tvout_driver = { .remove = sti_tvout_remove, }; -module_platform_driver(sti_tvout_driver); - MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>"); MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/sti/sti_vtac.c b/drivers/gpu/drm/sti/sti_vtac.c index 97bcdac23ae1..b1eb0d77630d 100644 --- a/drivers/gpu/drm/sti/sti_vtac.c +++ b/drivers/gpu/drm/sti/sti_vtac.c @@ -216,8 +216,6 @@ struct platform_driver sti_vtac_driver = { .remove = sti_vtac_remove, }; -module_platform_driver(sti_vtac_driver); - MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>"); MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/sti/sti_vtg.c b/drivers/gpu/drm/sti/sti_vtg.c index aa8097137701..d56630c60039 100644 --- a/drivers/gpu/drm/sti/sti_vtg.c +++ b/drivers/gpu/drm/sti/sti_vtg.c @@ -79,7 +79,7 @@ LIST_HEAD(vtg_lookup); * @irq: VTG irq * @type: VTG type (main or aux) * @notifier_list: notifier callback - * @crtc_id: the crtc id for vblank event + * @crtc: the CRTC for vblank event * @slave: slave vtg * @link: List node to link the structure in lookup list */ @@ -90,7 +90,7 @@ struct sti_vtg { int irq; u32 irq_status; struct raw_notifier_head notifier_list; - int crtc_id; + struct drm_crtc *crtc; struct sti_vtg *slave; struct list_head link; }; @@ -110,7 +110,6 @@ struct sti_vtg *of_vtg_find(struct device_node *np) } return NULL; } -EXPORT_SYMBOL(of_vtg_find); static void vtg_reset(struct sti_vtg *vtg) { @@ -242,7 +241,6 @@ void sti_vtg_set_config(struct sti_vtg *vtg, else vtg_enable_irq(vtg); } -EXPORT_SYMBOL(sti_vtg_set_config); /** * sti_vtg_get_line_number @@ -265,7 +263,6 @@ u32 sti_vtg_get_line_number(struct drm_display_mode mode, int y) return start_line + y; } -EXPORT_SYMBOL(sti_vtg_get_line_number); /** * sti_vtg_get_pixel_number @@ -281,18 +278,16 @@ u32 sti_vtg_get_pixel_number(struct drm_display_mode mode, int x) { return mode.htotal - mode.hsync_start + x; } -EXPORT_SYMBOL(sti_vtg_get_pixel_number); -int sti_vtg_register_client(struct sti_vtg *vtg, - struct notifier_block *nb, int crtc_id) +int sti_vtg_register_client(struct sti_vtg *vtg, struct notifier_block *nb, + struct drm_crtc *crtc) { if (vtg->slave) - return sti_vtg_register_client(vtg->slave, nb, crtc_id); + return sti_vtg_register_client(vtg->slave, nb, crtc); - vtg->crtc_id = crtc_id; + vtg->crtc = crtc; return raw_notifier_chain_register(&vtg->notifier_list, nb); } -EXPORT_SYMBOL(sti_vtg_register_client); int sti_vtg_unregister_client(struct sti_vtg *vtg, struct notifier_block *nb) { @@ -301,7 +296,6 @@ int sti_vtg_unregister_client(struct sti_vtg *vtg, struct notifier_block *nb) return raw_notifier_chain_unregister(&vtg->notifier_list, nb); } -EXPORT_SYMBOL(sti_vtg_unregister_client); static irqreturn_t vtg_irq_thread(int irq, void *arg) { @@ -311,7 +305,7 @@ static irqreturn_t vtg_irq_thread(int irq, void *arg) event = (vtg->irq_status & VTG_IRQ_TOP) ? VTG_TOP_FIELD_EVENT : VTG_BOTTOM_FIELD_EVENT; - raw_notifier_call_chain(&vtg->notifier_list, event, &vtg->crtc_id); + raw_notifier_call_chain(&vtg->notifier_list, event, vtg->crtc); return IRQ_HANDLED; } @@ -406,8 +400,6 @@ struct platform_driver sti_vtg_driver = { .remove = vtg_remove, }; -module_platform_driver(sti_vtg_driver); - MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>"); MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/sti/sti_vtg.h b/drivers/gpu/drm/sti/sti_vtg.h index e84d23f1f57f..cd2439f89d05 100644 --- a/drivers/gpu/drm/sti/sti_vtg.h +++ b/drivers/gpu/drm/sti/sti_vtg.h @@ -17,8 +17,8 @@ struct notifier_block; struct sti_vtg *of_vtg_find(struct device_node *np); void sti_vtg_set_config(struct sti_vtg *vtg, const struct drm_display_mode *mode); -int sti_vtg_register_client(struct sti_vtg *vtg, - struct notifier_block *nb, int crtc_id); +int sti_vtg_register_client(struct sti_vtg *vtg, struct notifier_block *nb, + struct drm_crtc *crtc); int sti_vtg_unregister_client(struct sti_vtg *vtg, struct notifier_block *nb); diff --git a/drivers/gpu/drm/vc4/Kconfig b/drivers/gpu/drm/vc4/Kconfig index e502802d74b6..2d7d115ddf3f 100644 --- a/drivers/gpu/drm/vc4/Kconfig +++ b/drivers/gpu/drm/vc4/Kconfig @@ -1,9 +1,10 @@ config DRM_VC4 tristate "Broadcom VC4 Graphics" depends on ARCH_BCM2835 || COMPILE_TEST - depends on DRM + depends on DRM && HAVE_DMA_ATTRS select DRM_KMS_HELPER select DRM_KMS_CMA_HELPER + select DRM_GEM_CMA_HELPER help Choose this option if you have a system that has a Broadcom VC4 GPU, such as the Raspberry Pi or other BCM2708/BCM2835. diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c index 7a9f4768591e..265064c62d49 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c @@ -168,7 +168,7 @@ static int vc4_get_clock_select(struct drm_crtc *crtc) struct drm_connector *connector; drm_for_each_connector(connector, crtc->dev) { - if (connector && connector->state->crtc == crtc) { + if (connector->state->crtc == crtc) { struct drm_encoder *encoder = connector->encoder; struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder); @@ -401,7 +401,8 @@ static void vc4_crtc_atomic_flush(struct drm_crtc *crtc, dlist_next++; HVS_WRITE(SCALER_DISPLISTX(vc4_crtc->channel), - (u32 *)vc4_crtc->dlist - (u32 *)vc4->hvs->dlist); + (u32 __iomem *)vc4_crtc->dlist - + (u32 __iomem *)vc4->hvs->dlist); /* Make the next display list start after ours. */ vc4_crtc->dlist_size -= (dlist_next - vc4_crtc->dlist); @@ -591,14 +592,14 @@ static int vc4_crtc_bind(struct device *dev, struct device *master, void *data) * that will take too much. */ primary_plane = vc4_plane_init(drm, DRM_PLANE_TYPE_PRIMARY); - if (!primary_plane) { + if (IS_ERR(primary_plane)) { dev_err(dev, "failed to construct primary plane\n"); ret = PTR_ERR(primary_plane); goto err; } cursor_plane = vc4_plane_init(drm, DRM_PLANE_TYPE_CURSOR); - if (!cursor_plane) { + if (IS_ERR(cursor_plane)) { dev_err(dev, "failed to construct cursor plane\n"); ret = PTR_ERR(cursor_plane); goto err_primary; diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c index 6e730605edcc..d5db9e0f3b73 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.c +++ b/drivers/gpu/drm/vc4/vc4_drv.c @@ -259,7 +259,6 @@ static struct platform_driver vc4_platform_driver = { .remove = vc4_platform_drm_remove, .driver = { .name = "vc4-drm", - .owner = THIS_MODULE, .of_match_table = vc4_of_match, }, }; diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c index ab1673f672a4..8098c5b21ba4 100644 --- a/drivers/gpu/drm/vc4/vc4_hvs.c +++ b/drivers/gpu/drm/vc4/vc4_hvs.c @@ -75,10 +75,10 @@ void vc4_hvs_dump_state(struct drm_device *dev) for (i = 0; i < 64; i += 4) { DRM_INFO("0x%08x (%s): 0x%08x 0x%08x 0x%08x 0x%08x\n", i * 4, i < HVS_BOOTLOADER_DLIST_END ? "B" : "D", - ((uint32_t *)vc4->hvs->dlist)[i + 0], - ((uint32_t *)vc4->hvs->dlist)[i + 1], - ((uint32_t *)vc4->hvs->dlist)[i + 2], - ((uint32_t *)vc4->hvs->dlist)[i + 3]); + readl((u32 __iomem *)vc4->hvs->dlist + i + 0), + readl((u32 __iomem *)vc4->hvs->dlist + i + 1), + readl((u32 __iomem *)vc4->hvs->dlist + i + 2), + readl((u32 __iomem *)vc4->hvs->dlist + i + 3)); } } diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index cdd8b10c0147..887f3caad0be 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c @@ -70,7 +70,7 @@ static bool plane_enabled(struct drm_plane_state *state) return state->fb && state->crtc; } -struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane) +static struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane) { struct vc4_plane_state *vc4_state; @@ -97,8 +97,8 @@ struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane) return &vc4_state->base; } -void vc4_plane_destroy_state(struct drm_plane *plane, - struct drm_plane_state *state) +static void vc4_plane_destroy_state(struct drm_plane *plane, + struct drm_plane_state *state) { struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); @@ -108,7 +108,7 @@ void vc4_plane_destroy_state(struct drm_plane *plane, } /* Called during init to allocate the plane's atomic state. */ -void vc4_plane_reset(struct drm_plane *plane) +static void vc4_plane_reset(struct drm_plane *plane) { struct vc4_plane_state *vc4_state; @@ -157,6 +157,16 @@ static int vc4_plane_mode_set(struct drm_plane *plane, int crtc_w = state->crtc_w; int crtc_h = state->crtc_h; + if (state->crtc_w << 16 != state->src_w || + state->crtc_h << 16 != state->src_h) { + /* We don't support scaling yet, which involves + * allocating the LBM memory for scaling temporary + * storage, and putting filter kernels in the HVS + * context. + */ + return -EINVAL; + } + if (crtc_x < 0) { offset += drm_format_plane_cpp(fb->pixel_format, 0) * -crtc_x; crtc_w += crtc_x; diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index 8b29949507d1..01a4f05c1642 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -2481,7 +2481,7 @@ void wacom_setup_device_quirks(struct wacom *wacom) if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) { if (features->touch_max) features->device_type |= WACOM_DEVICETYPE_TOUCH; - if (features->type >= INTUOSHT || features->type <= BAMBOO_PT) + if (features->type >= INTUOSHT && features->type <= BAMBOO_PT) features->device_type |= WACOM_DEVICETYPE_PAD; features->x_max = 4096; @@ -3213,7 +3213,8 @@ static const struct wacom_features wacom_features_0x32F = WACOM_DTU_OFFSET, WACOM_DTU_OFFSET }; static const struct wacom_features wacom_features_0x336 = { "Wacom DTU1141", 23472, 13203, 1023, 0, - DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4 }; + DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4, + WACOM_DTU_OFFSET, WACOM_DTU_OFFSET }; static const struct wacom_features wacom_features_0x57 = { "Wacom DTK2241", 95640, 54060, 2047, 63, DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 6, diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 842b0043ad94..8f59f057cdf4 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -324,6 +324,7 @@ config SENSORS_APPLESMC config SENSORS_ARM_SCPI tristate "ARM SCPI Sensors" depends on ARM_SCPI_PROTOCOL + depends on THERMAL || !THERMAL_OF help This driver provides support for temperature, voltage, current and power sensors available on ARM Ltd's SCP based platforms. The @@ -1471,6 +1472,7 @@ config SENSORS_INA209 config SENSORS_INA2XX tristate "Texas Instruments INA219 and compatibles" depends on I2C + select REGMAP_I2C help If you say yes here you get support for INA219, INA220, INA226, INA230, and INA231 power monitor chips. diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c index 1f5e956941b1..0af7fd311979 100644 --- a/drivers/hwmon/applesmc.c +++ b/drivers/hwmon/applesmc.c @@ -537,7 +537,7 @@ static int applesmc_init_index(struct applesmc_registers *s) static int applesmc_init_smcreg_try(void) { struct applesmc_registers *s = &smcreg; - bool left_light_sensor, right_light_sensor; + bool left_light_sensor = 0, right_light_sensor = 0; unsigned int count; u8 tmp[1]; int ret; diff --git a/drivers/hwmon/scpi-hwmon.c b/drivers/hwmon/scpi-hwmon.c index 2c1241bbf9af..7e20567bc369 100644 --- a/drivers/hwmon/scpi-hwmon.c +++ b/drivers/hwmon/scpi-hwmon.c @@ -117,7 +117,7 @@ static int scpi_hwmon_probe(struct platform_device *pdev) struct scpi_ops *scpi_ops; struct device *hwdev, *dev = &pdev->dev; struct scpi_sensors *scpi_sensors; - int ret; + int ret, idx; scpi_ops = get_scpi_ops(); if (!scpi_ops) @@ -146,8 +146,8 @@ static int scpi_hwmon_probe(struct platform_device *pdev) scpi_sensors->scpi_ops = scpi_ops; - for (i = 0; i < nr_sensors; i++) { - struct sensor_data *sensor = &scpi_sensors->data[i]; + for (i = 0, idx = 0; i < nr_sensors; i++) { + struct sensor_data *sensor = &scpi_sensors->data[idx]; ret = scpi_ops->sensor_get_info(i, &sensor->info); if (ret) @@ -183,7 +183,7 @@ static int scpi_hwmon_probe(struct platform_device *pdev) num_power++; break; default: - break; + continue; } sensor->dev_attr_input.attr.mode = S_IRUGO; @@ -194,11 +194,12 @@ static int scpi_hwmon_probe(struct platform_device *pdev) sensor->dev_attr_label.show = scpi_show_label; sensor->dev_attr_label.attr.name = sensor->label; - scpi_sensors->attrs[i << 1] = &sensor->dev_attr_input.attr; - scpi_sensors->attrs[(i << 1) + 1] = &sensor->dev_attr_label.attr; + scpi_sensors->attrs[idx << 1] = &sensor->dev_attr_input.attr; + scpi_sensors->attrs[(idx << 1) + 1] = &sensor->dev_attr_label.attr; - sysfs_attr_init(scpi_sensors->attrs[i << 1]); - sysfs_attr_init(scpi_sensors->attrs[(i << 1) + 1]); + sysfs_attr_init(scpi_sensors->attrs[idx << 1]); + sysfs_attr_init(scpi_sensors->attrs[(idx << 1) + 1]); + idx++; } scpi_sensors->group.attrs = scpi_sensors->attrs; @@ -236,8 +237,8 @@ static int scpi_hwmon_probe(struct platform_device *pdev) zone->sensor_id = i; zone->scpi_sensors = scpi_sensors; - zone->tzd = thermal_zone_of_sensor_register(dev, i, zone, - &scpi_sensor_ops); + zone->tzd = thermal_zone_of_sensor_register(dev, + sensor->info.sensor_id, zone, &scpi_sensor_ops); /* * The call to thermal_zone_of_sensor_register returns * an error for sensors that are not associated with diff --git a/drivers/hwtracing/stm/policy.c b/drivers/hwtracing/stm/policy.c index 6498a9dbb7bd..11ab6d01adf6 100644 --- a/drivers/hwtracing/stm/policy.c +++ b/drivers/hwtracing/stm/policy.c @@ -76,9 +76,10 @@ to_stp_policy_node(struct config_item *item) NULL; } -static ssize_t stp_policy_node_masters_show(struct stp_policy_node *policy_node, - char *page) +static ssize_t +stp_policy_node_masters_show(struct config_item *item, char *page) { + struct stp_policy_node *policy_node = to_stp_policy_node(item); ssize_t count; count = sprintf(page, "%u %u\n", policy_node->first_master, @@ -88,9 +89,10 @@ static ssize_t stp_policy_node_masters_show(struct stp_policy_node *policy_node, } static ssize_t -stp_policy_node_masters_store(struct stp_policy_node *policy_node, - const char *page, size_t count) +stp_policy_node_masters_store(struct config_item *item, const char *page, + size_t count) { + struct stp_policy_node *policy_node = to_stp_policy_node(item); unsigned int first, last; struct stm_device *stm; char *p = (char *)page; @@ -123,8 +125,9 @@ unlock: } static ssize_t -stp_policy_node_channels_show(struct stp_policy_node *policy_node, char *page) +stp_policy_node_channels_show(struct config_item *item, char *page) { + struct stp_policy_node *policy_node = to_stp_policy_node(item); ssize_t count; count = sprintf(page, "%u %u\n", policy_node->first_channel, @@ -134,9 +137,10 @@ stp_policy_node_channels_show(struct stp_policy_node *policy_node, char *page) } static ssize_t -stp_policy_node_channels_store(struct stp_policy_node *policy_node, - const char *page, size_t count) +stp_policy_node_channels_store(struct config_item *item, const char *page, + size_t count) { + struct stp_policy_node *policy_node = to_stp_policy_node(item); unsigned int first, last; struct stm_device *stm; char *p = (char *)page; @@ -171,71 +175,16 @@ static void stp_policy_node_release(struct config_item *item) kfree(to_stp_policy_node(item)); } -struct stp_policy_node_attribute { - struct configfs_attribute attr; - ssize_t (*show)(struct stp_policy_node *, char *); - ssize_t (*store)(struct stp_policy_node *, const char *, size_t); -}; - -static ssize_t stp_policy_node_attr_show(struct config_item *item, - struct configfs_attribute *attr, - char *page) -{ - struct stp_policy_node *policy_node = to_stp_policy_node(item); - struct stp_policy_node_attribute *pn_attr = - container_of(attr, struct stp_policy_node_attribute, attr); - ssize_t count = 0; - - if (pn_attr->show) - count = pn_attr->show(policy_node, page); - - return count; -} - -static ssize_t stp_policy_node_attr_store(struct config_item *item, - struct configfs_attribute *attr, - const char *page, size_t len) -{ - struct stp_policy_node *policy_node = to_stp_policy_node(item); - struct stp_policy_node_attribute *pn_attr = - container_of(attr, struct stp_policy_node_attribute, attr); - ssize_t count = -EINVAL; - - if (pn_attr->store) - count = pn_attr->store(policy_node, page, len); - - return count; -} - static struct configfs_item_operations stp_policy_node_item_ops = { .release = stp_policy_node_release, - .show_attribute = stp_policy_node_attr_show, - .store_attribute = stp_policy_node_attr_store, }; -static struct stp_policy_node_attribute stp_policy_node_attr_range = { - .attr = { - .ca_owner = THIS_MODULE, - .ca_name = "masters", - .ca_mode = S_IRUGO | S_IWUSR, - }, - .show = stp_policy_node_masters_show, - .store = stp_policy_node_masters_store, -}; - -static struct stp_policy_node_attribute stp_policy_node_attr_channels = { - .attr = { - .ca_owner = THIS_MODULE, - .ca_name = "channels", - .ca_mode = S_IRUGO | S_IWUSR, - }, - .show = stp_policy_node_channels_show, - .store = stp_policy_node_channels_store, -}; +CONFIGFS_ATTR(stp_policy_node_, masters); +CONFIGFS_ATTR(stp_policy_node_, channels); static struct configfs_attribute *stp_policy_node_attrs[] = { - &stp_policy_node_attr_range.attr, - &stp_policy_node_attr_channels.attr, + &stp_policy_node_attr_masters, + &stp_policy_node_attr_channels, NULL, }; @@ -298,20 +247,8 @@ static struct config_item_type stp_policy_node_type = { /* * Root group: policies. */ -static struct configfs_attribute stp_policy_attr_device = { - .ca_owner = THIS_MODULE, - .ca_name = "device", - .ca_mode = S_IRUGO, -}; - -static struct configfs_attribute *stp_policy_attrs[] = { - &stp_policy_attr_device, - NULL, -}; - -static ssize_t stp_policy_attr_show(struct config_item *item, - struct configfs_attribute *attr, - char *page) +static ssize_t stp_policy_device_show(struct config_item *item, + char *page) { struct stp_policy *policy = to_stp_policy(item); ssize_t count; @@ -324,6 +261,13 @@ static ssize_t stp_policy_attr_show(struct config_item *item, return count; } +CONFIGFS_ATTR_RO(stp_policy_, device); + +static struct configfs_attribute *stp_policy_attrs[] = { + &stp_policy_attr_device, + NULL, +}; + void stp_policy_unbind(struct stp_policy *policy) { struct stm_device *stm = policy->stm; @@ -350,7 +294,6 @@ static void stp_policy_release(struct config_item *item) static struct configfs_item_operations stp_policy_item_ops = { .release = stp_policy_release, - .show_attribute = stp_policy_attr_show, }; static struct configfs_group_operations stp_policy_group_ops = { diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index e24c2b680b47..7b0aa82ea38b 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -126,6 +126,7 @@ config I2C_I801 Sunrise Point-LP (PCH) DNV (SOC) Broxton (SOC) + Lewisburg (PCH) This driver can also be built as a module. If so, the module will be called i2c-i801. diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index c306751ceadb..f62d69799a9c 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -62,6 +62,8 @@ * Sunrise Point-LP (PCH) 0x9d23 32 hard yes yes yes * DNV (SOC) 0x19df 32 hard yes yes yes * Broxton (SOC) 0x5ad4 32 hard yes yes yes + * Lewisburg (PCH) 0xa1a3 32 hard yes yes yes + * Lewisburg Supersku (PCH) 0xa223 32 hard yes yes yes * * Features supported by this driver: * Software PEC no @@ -206,6 +208,8 @@ #define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS 0x9d23 #define PCI_DEVICE_ID_INTEL_DNV_SMBUS 0x19df #define PCI_DEVICE_ID_INTEL_BROXTON_SMBUS 0x5ad4 +#define PCI_DEVICE_ID_INTEL_LEWISBURG_SMBUS 0xa1a3 +#define PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS 0xa223 struct i801_mux_config { char *gpio_chip; @@ -869,6 +873,8 @@ static const struct pci_device_id i801_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_DNV_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BROXTON_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LEWISBURG_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS) }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index 1e4d99da4164..9bb0b056b25f 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -50,6 +50,7 @@ #include <linux/of_device.h> #include <linux/of_dma.h> #include <linux/of_gpio.h> +#include <linux/pinctrl/consumer.h> #include <linux/platform_data/i2c-imx.h> #include <linux/platform_device.h> #include <linux/sched.h> diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index e23a7b068c60..0b20449e48cf 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -662,8 +662,10 @@ static void __xiic_start_xfer(struct xiic_i2c *i2c) static void xiic_start_xfer(struct xiic_i2c *i2c) { - + spin_lock(&i2c->lock); + xiic_reinit(i2c); __xiic_start_xfer(i2c); + spin_unlock(&i2c->lock); } static int xiic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 040af5cc8143..ba8eb087f224 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -715,7 +715,7 @@ static int i2c_device_probe(struct device *dev) if (wakeirq > 0 && wakeirq != client->irq) status = dev_pm_set_dedicated_wake_irq(dev, wakeirq); else if (client->irq > 0) - status = dev_pm_set_wake_irq(dev, wakeirq); + status = dev_pm_set_wake_irq(dev, client->irq); else status = 0; diff --git a/drivers/iio/adc/ad7793.c b/drivers/iio/adc/ad7793.c index eea0c79111e7..4d960d3b93c0 100644 --- a/drivers/iio/adc/ad7793.c +++ b/drivers/iio/adc/ad7793.c @@ -101,7 +101,7 @@ #define AD7795_CH_AIN1M_AIN1M 8 /* AIN1(-) - AIN1(-) */ /* ID Register Bit Designations (AD7793_REG_ID) */ -#define AD7785_ID 0xB +#define AD7785_ID 0x3 #define AD7792_ID 0xA #define AD7793_ID 0xB #define AD7794_ID 0xF diff --git a/drivers/iio/adc/vf610_adc.c b/drivers/iio/adc/vf610_adc.c index 599cde3d03a1..b10f629cc44b 100644 --- a/drivers/iio/adc/vf610_adc.c +++ b/drivers/iio/adc/vf610_adc.c @@ -106,6 +106,13 @@ #define DEFAULT_SAMPLE_TIME 1000 +/* V at 25°C of 696 mV */ +#define VF610_VTEMP25_3V0 950 +/* V at 25°C of 699 mV */ +#define VF610_VTEMP25_3V3 867 +/* Typical sensor slope coefficient at all temperatures */ +#define VF610_TEMP_SLOPE_COEFF 1840 + enum clk_sel { VF610_ADCIOC_BUSCLK_SET, VF610_ADCIOC_ALTCLK_SET, @@ -197,6 +204,8 @@ static inline void vf610_adc_calculate_rates(struct vf610_adc *info) adc_feature->clk_div = 8; } + adck_rate = ipg_rate / adc_feature->clk_div; + /* * Determine the long sample time adder value to be used based * on the default minimum sample time provided. @@ -221,7 +230,6 @@ static inline void vf610_adc_calculate_rates(struct vf610_adc *info) * BCT (Base Conversion Time): fixed to 25 ADCK cycles for 12 bit mode * LSTAdder(Long Sample Time): 3, 5, 7, 9, 13, 17, 21, 25 ADCK cycles */ - adck_rate = ipg_rate / info->adc_feature.clk_div; for (i = 0; i < ARRAY_SIZE(vf610_hw_avgs); i++) info->sample_freq_avail[i] = adck_rate / (6 + vf610_hw_avgs[i] * @@ -663,11 +671,13 @@ static int vf610_read_raw(struct iio_dev *indio_dev, break; case IIO_TEMP: /* - * Calculate in degree Celsius times 1000 - * Using sensor slope of 1.84 mV/°C and - * V at 25°C of 696 mV - */ - *val = 25000 - ((int)info->value - 864) * 1000000 / 1840; + * Calculate in degree Celsius times 1000 + * Using the typical sensor slope of 1.84 mV/°C + * and VREFH_ADC at 3.3V, V at 25°C of 699 mV + */ + *val = 25000 - ((int)info->value - VF610_VTEMP25_3V3) * + 1000000 / VF610_TEMP_SLOPE_COEFF; + break; default: mutex_unlock(&indio_dev->mlock); diff --git a/drivers/iio/adc/xilinx-xadc-core.c b/drivers/iio/adc/xilinx-xadc-core.c index 0370624a35db..02e636a1c49a 100644 --- a/drivers/iio/adc/xilinx-xadc-core.c +++ b/drivers/iio/adc/xilinx-xadc-core.c @@ -841,6 +841,7 @@ static int xadc_read_raw(struct iio_dev *indio_dev, case XADC_REG_VCCINT: case XADC_REG_VCCAUX: case XADC_REG_VREFP: + case XADC_REG_VREFN: case XADC_REG_VCCBRAM: case XADC_REG_VCCPINT: case XADC_REG_VCCPAUX: diff --git a/drivers/iio/dac/ad5064.c b/drivers/iio/dac/ad5064.c index 9e4d2c18b554..81ca0081a019 100644 --- a/drivers/iio/dac/ad5064.c +++ b/drivers/iio/dac/ad5064.c @@ -113,12 +113,16 @@ enum ad5064_type { ID_AD5065, ID_AD5628_1, ID_AD5628_2, + ID_AD5629_1, + ID_AD5629_2, ID_AD5648_1, ID_AD5648_2, ID_AD5666_1, ID_AD5666_2, ID_AD5668_1, ID_AD5668_2, + ID_AD5669_1, + ID_AD5669_2, }; static int ad5064_write(struct ad5064_state *st, unsigned int cmd, @@ -291,7 +295,7 @@ static const struct iio_chan_spec_ext_info ad5064_ext_info[] = { { }, }; -#define AD5064_CHANNEL(chan, addr, bits) { \ +#define AD5064_CHANNEL(chan, addr, bits, _shift) { \ .type = IIO_VOLTAGE, \ .indexed = 1, \ .output = 1, \ @@ -303,36 +307,39 @@ static const struct iio_chan_spec_ext_info ad5064_ext_info[] = { .sign = 'u', \ .realbits = (bits), \ .storagebits = 16, \ - .shift = 20 - bits, \ + .shift = (_shift), \ }, \ .ext_info = ad5064_ext_info, \ } -#define DECLARE_AD5064_CHANNELS(name, bits) \ +#define DECLARE_AD5064_CHANNELS(name, bits, shift) \ const struct iio_chan_spec name[] = { \ - AD5064_CHANNEL(0, 0, bits), \ - AD5064_CHANNEL(1, 1, bits), \ - AD5064_CHANNEL(2, 2, bits), \ - AD5064_CHANNEL(3, 3, bits), \ - AD5064_CHANNEL(4, 4, bits), \ - AD5064_CHANNEL(5, 5, bits), \ - AD5064_CHANNEL(6, 6, bits), \ - AD5064_CHANNEL(7, 7, bits), \ + AD5064_CHANNEL(0, 0, bits, shift), \ + AD5064_CHANNEL(1, 1, bits, shift), \ + AD5064_CHANNEL(2, 2, bits, shift), \ + AD5064_CHANNEL(3, 3, bits, shift), \ + AD5064_CHANNEL(4, 4, bits, shift), \ + AD5064_CHANNEL(5, 5, bits, shift), \ + AD5064_CHANNEL(6, 6, bits, shift), \ + AD5064_CHANNEL(7, 7, bits, shift), \ } -#define DECLARE_AD5065_CHANNELS(name, bits) \ +#define DECLARE_AD5065_CHANNELS(name, bits, shift) \ const struct iio_chan_spec name[] = { \ - AD5064_CHANNEL(0, 0, bits), \ - AD5064_CHANNEL(1, 3, bits), \ + AD5064_CHANNEL(0, 0, bits, shift), \ + AD5064_CHANNEL(1, 3, bits, shift), \ } -static DECLARE_AD5064_CHANNELS(ad5024_channels, 12); -static DECLARE_AD5064_CHANNELS(ad5044_channels, 14); -static DECLARE_AD5064_CHANNELS(ad5064_channels, 16); +static DECLARE_AD5064_CHANNELS(ad5024_channels, 12, 8); +static DECLARE_AD5064_CHANNELS(ad5044_channels, 14, 6); +static DECLARE_AD5064_CHANNELS(ad5064_channels, 16, 4); -static DECLARE_AD5065_CHANNELS(ad5025_channels, 12); -static DECLARE_AD5065_CHANNELS(ad5045_channels, 14); -static DECLARE_AD5065_CHANNELS(ad5065_channels, 16); +static DECLARE_AD5065_CHANNELS(ad5025_channels, 12, 8); +static DECLARE_AD5065_CHANNELS(ad5045_channels, 14, 6); +static DECLARE_AD5065_CHANNELS(ad5065_channels, 16, 4); + +static DECLARE_AD5064_CHANNELS(ad5629_channels, 12, 4); +static DECLARE_AD5064_CHANNELS(ad5669_channels, 16, 0); static const struct ad5064_chip_info ad5064_chip_info_tbl[] = { [ID_AD5024] = { @@ -382,6 +389,18 @@ static const struct ad5064_chip_info ad5064_chip_info_tbl[] = { .channels = ad5024_channels, .num_channels = 8, }, + [ID_AD5629_1] = { + .shared_vref = true, + .internal_vref = 2500000, + .channels = ad5629_channels, + .num_channels = 8, + }, + [ID_AD5629_2] = { + .shared_vref = true, + .internal_vref = 5000000, + .channels = ad5629_channels, + .num_channels = 8, + }, [ID_AD5648_1] = { .shared_vref = true, .internal_vref = 2500000, @@ -418,6 +437,18 @@ static const struct ad5064_chip_info ad5064_chip_info_tbl[] = { .channels = ad5064_channels, .num_channels = 8, }, + [ID_AD5669_1] = { + .shared_vref = true, + .internal_vref = 2500000, + .channels = ad5669_channels, + .num_channels = 8, + }, + [ID_AD5669_2] = { + .shared_vref = true, + .internal_vref = 5000000, + .channels = ad5669_channels, + .num_channels = 8, + }, }; static inline unsigned int ad5064_num_vref(struct ad5064_state *st) @@ -597,10 +628,16 @@ static int ad5064_i2c_write(struct ad5064_state *st, unsigned int cmd, unsigned int addr, unsigned int val) { struct i2c_client *i2c = to_i2c_client(st->dev); + int ret; st->data.i2c[0] = (cmd << 4) | addr; put_unaligned_be16(val, &st->data.i2c[1]); - return i2c_master_send(i2c, st->data.i2c, 3); + + ret = i2c_master_send(i2c, st->data.i2c, 3); + if (ret < 0) + return ret; + + return 0; } static int ad5064_i2c_probe(struct i2c_client *i2c, @@ -616,12 +653,12 @@ static int ad5064_i2c_remove(struct i2c_client *i2c) } static const struct i2c_device_id ad5064_i2c_ids[] = { - {"ad5629-1", ID_AD5628_1}, - {"ad5629-2", ID_AD5628_2}, - {"ad5629-3", ID_AD5628_2}, /* similar enough to ad5629-2 */ - {"ad5669-1", ID_AD5668_1}, - {"ad5669-2", ID_AD5668_2}, - {"ad5669-3", ID_AD5668_2}, /* similar enough to ad5669-2 */ + {"ad5629-1", ID_AD5629_1}, + {"ad5629-2", ID_AD5629_2}, + {"ad5629-3", ID_AD5629_2}, /* similar enough to ad5629-2 */ + {"ad5669-1", ID_AD5669_1}, + {"ad5669-2", ID_AD5669_2}, + {"ad5669-3", ID_AD5669_2}, /* similar enough to ad5669-2 */ {} }; MODULE_DEVICE_TABLE(i2c, ad5064_i2c_ids); diff --git a/drivers/iio/humidity/si7020.c b/drivers/iio/humidity/si7020.c index 12128d1ca570..71991b5c0658 100644 --- a/drivers/iio/humidity/si7020.c +++ b/drivers/iio/humidity/si7020.c @@ -50,10 +50,10 @@ static int si7020_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: - ret = i2c_smbus_read_word_data(*client, - chan->type == IIO_TEMP ? - SI7020CMD_TEMP_HOLD : - SI7020CMD_RH_HOLD); + ret = i2c_smbus_read_word_swapped(*client, + chan->type == IIO_TEMP ? + SI7020CMD_TEMP_HOLD : + SI7020CMD_RH_HOLD); if (ret < 0) return ret; *val = ret >> 2; diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 32f79624dd28..9909022dc6c3 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -2798,7 +2798,6 @@ static struct scsi_host_template srp_template = { .cmd_per_lun = SRP_DEFAULT_CMD_SQ_SIZE, .use_clustering = ENABLE_CLUSTERING, .shost_attrs = srp_host_attrs, - .use_blk_tags = 1, .track_queue_depth = 1, }; @@ -3229,10 +3228,6 @@ static ssize_t srp_create_target(struct device *dev, if (ret) goto out; - ret = scsi_init_shared_tag_map(target_host, target_host->can_queue); - if (ret) - goto out; - target->req_ring_size = target->queue_size - SRP_TSK_MGMT_SQ_SIZE; if (!srp_conn_unique(target->srp_host, target)) { diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 47c4022fda76..2e2fe818ca9f 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -43,9 +43,7 @@ #include <linux/atomic.h> #include <scsi/scsi_proto.h> #include <scsi/scsi_tcq.h> -#include <target/configfs_macros.h> #include <target/target_core_base.h> -#include <target/target_core_fabric_configfs.h> #include <target/target_core_fabric.h> #include "ib_srpt.h" @@ -3546,20 +3544,19 @@ static void srpt_cleanup_nodeacl(struct se_node_acl *se_nacl) spin_unlock_irq(&sport->port_acl_lock); } -static ssize_t srpt_tpg_attrib_show_srp_max_rdma_size( - struct se_portal_group *se_tpg, - char *page) +static ssize_t srpt_tpg_attrib_srp_max_rdma_size_show(struct config_item *item, + char *page) { + struct se_portal_group *se_tpg = attrib_to_tpg(item); struct srpt_port *sport = container_of(se_tpg, struct srpt_port, port_tpg_1); return sprintf(page, "%u\n", sport->port_attrib.srp_max_rdma_size); } -static ssize_t srpt_tpg_attrib_store_srp_max_rdma_size( - struct se_portal_group *se_tpg, - const char *page, - size_t count) +static ssize_t srpt_tpg_attrib_srp_max_rdma_size_store(struct config_item *item, + const char *page, size_t count) { + struct se_portal_group *se_tpg = attrib_to_tpg(item); struct srpt_port *sport = container_of(se_tpg, struct srpt_port, port_tpg_1); unsigned long val; int ret; @@ -3584,22 +3581,19 @@ static ssize_t srpt_tpg_attrib_store_srp_max_rdma_size( return count; } -TF_TPG_ATTRIB_ATTR(srpt, srp_max_rdma_size, S_IRUGO | S_IWUSR); - -static ssize_t srpt_tpg_attrib_show_srp_max_rsp_size( - struct se_portal_group *se_tpg, - char *page) +static ssize_t srpt_tpg_attrib_srp_max_rsp_size_show(struct config_item *item, + char *page) { + struct se_portal_group *se_tpg = attrib_to_tpg(item); struct srpt_port *sport = container_of(se_tpg, struct srpt_port, port_tpg_1); return sprintf(page, "%u\n", sport->port_attrib.srp_max_rsp_size); } -static ssize_t srpt_tpg_attrib_store_srp_max_rsp_size( - struct se_portal_group *se_tpg, - const char *page, - size_t count) +static ssize_t srpt_tpg_attrib_srp_max_rsp_size_store(struct config_item *item, + const char *page, size_t count) { + struct se_portal_group *se_tpg = attrib_to_tpg(item); struct srpt_port *sport = container_of(se_tpg, struct srpt_port, port_tpg_1); unsigned long val; int ret; @@ -3624,22 +3618,19 @@ static ssize_t srpt_tpg_attrib_store_srp_max_rsp_size( return count; } -TF_TPG_ATTRIB_ATTR(srpt, srp_max_rsp_size, S_IRUGO | S_IWUSR); - -static ssize_t srpt_tpg_attrib_show_srp_sq_size( - struct se_portal_group *se_tpg, - char *page) +static ssize_t srpt_tpg_attrib_srp_sq_size_show(struct config_item *item, + char *page) { + struct se_portal_group *se_tpg = attrib_to_tpg(item); struct srpt_port *sport = container_of(se_tpg, struct srpt_port, port_tpg_1); return sprintf(page, "%u\n", sport->port_attrib.srp_sq_size); } -static ssize_t srpt_tpg_attrib_store_srp_sq_size( - struct se_portal_group *se_tpg, - const char *page, - size_t count) +static ssize_t srpt_tpg_attrib_srp_sq_size_store(struct config_item *item, + const char *page, size_t count) { + struct se_portal_group *se_tpg = attrib_to_tpg(item); struct srpt_port *sport = container_of(se_tpg, struct srpt_port, port_tpg_1); unsigned long val; int ret; @@ -3664,29 +3655,29 @@ static ssize_t srpt_tpg_attrib_store_srp_sq_size( return count; } -TF_TPG_ATTRIB_ATTR(srpt, srp_sq_size, S_IRUGO | S_IWUSR); +CONFIGFS_ATTR(srpt_tpg_attrib_, srp_max_rdma_size); +CONFIGFS_ATTR(srpt_tpg_attrib_, srp_max_rsp_size); +CONFIGFS_ATTR(srpt_tpg_attrib_, srp_sq_size); static struct configfs_attribute *srpt_tpg_attrib_attrs[] = { - &srpt_tpg_attrib_srp_max_rdma_size.attr, - &srpt_tpg_attrib_srp_max_rsp_size.attr, - &srpt_tpg_attrib_srp_sq_size.attr, + &srpt_tpg_attrib_attr_srp_max_rdma_size, + &srpt_tpg_attrib_attr_srp_max_rsp_size, + &srpt_tpg_attrib_attr_srp_sq_size, NULL, }; -static ssize_t srpt_tpg_show_enable( - struct se_portal_group *se_tpg, - char *page) +static ssize_t srpt_tpg_enable_show(struct config_item *item, char *page) { + struct se_portal_group *se_tpg = to_tpg(item); struct srpt_port *sport = container_of(se_tpg, struct srpt_port, port_tpg_1); return snprintf(page, PAGE_SIZE, "%d\n", (sport->enabled) ? 1: 0); } -static ssize_t srpt_tpg_store_enable( - struct se_portal_group *se_tpg, - const char *page, - size_t count) +static ssize_t srpt_tpg_enable_store(struct config_item *item, + const char *page, size_t count) { + struct se_portal_group *se_tpg = to_tpg(item); struct srpt_port *sport = container_of(se_tpg, struct srpt_port, port_tpg_1); unsigned long tmp; int ret; @@ -3709,10 +3700,10 @@ static ssize_t srpt_tpg_store_enable( return count; } -TF_TPG_BASE_ATTR(srpt, enable, S_IRUGO | S_IWUSR); +CONFIGFS_ATTR(srpt_tpg_, enable); static struct configfs_attribute *srpt_tpg_attrs[] = { - &srpt_tpg_enable.attr, + &srpt_tpg_attr_enable, NULL, }; @@ -3782,16 +3773,15 @@ static void srpt_drop_tport(struct se_wwn *wwn) pr_debug("drop_tport(%s\n", config_item_name(&sport->port_wwn.wwn_group.cg_item)); } -static ssize_t srpt_wwn_show_attr_version(struct target_fabric_configfs *tf, - char *buf) +static ssize_t srpt_wwn_version_show(struct config_item *item, char *buf) { return scnprintf(buf, PAGE_SIZE, "%s\n", DRV_VERSION); } -TF_WWN_ATTR_RO(srpt, version); +CONFIGFS_ATTR_RO(srpt_wwn_, version); static struct configfs_attribute *srpt_wwn_attrs[] = { - &srpt_wwn_version.attr, + &srpt_wwn_attr_version, NULL, }; diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index 2955f1d0ca6c..537ebb0e193a 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -1520,6 +1520,13 @@ static const struct dmi_system_id elantech_dmi_force_crc_enabled[] = { DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E544"), }, }, + { + /* Fujitsu LIFEBOOK U745 does not work with crc_enabled == 0 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), + DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK U745"), + }, + }, #endif { } }; diff --git a/drivers/input/serio/parkbd.c b/drivers/input/serio/parkbd.c index 74bb17270255..92c31b8f8fb4 100644 --- a/drivers/input/serio/parkbd.c +++ b/drivers/input/serio/parkbd.c @@ -164,7 +164,7 @@ static int parkbd_getport(struct parport *pp) return 0; } -static struct serio * __init parkbd_allocate_serio(void) +static struct serio *parkbd_allocate_serio(void) { struct serio *serio; diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 80cc69897a43..ae33da7ab51f 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -939,10 +939,27 @@ config TOUCHSCREEN_TSC_SERIO To compile this driver as a module, choose M here: the module will be called tsc40. +config TOUCHSCREEN_TSC200X_CORE + tristate + +config TOUCHSCREEN_TSC2004 + tristate "TSC2004 based touchscreens" + depends on I2C + select REGMAP_I2C + select TOUCHSCREEN_TSC200X_CORE + help + Say Y here if you have a TSC2004 based touchscreen. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called tsc2004. + config TOUCHSCREEN_TSC2005 tristate "TSC2005 based touchscreens" depends on SPI_MASTER select REGMAP_SPI + select TOUCHSCREEN_TSC200X_CORE help Say Y here if you have a TSC2005 based touchscreen. diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 17435c7e97e3..cbaa6abb08da 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -69,6 +69,8 @@ obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o obj-$(CONFIG_TOUCHSCREEN_TSC_SERIO) += tsc40.o +obj-$(CONFIG_TOUCHSCREEN_TSC200X_CORE) += tsc200x-core.o +obj-$(CONFIG_TOUCHSCREEN_TSC2004) += tsc2004.o obj-$(CONFIG_TOUCHSCREEN_TSC2005) += tsc2005.o obj-$(CONFIG_TOUCHSCREEN_TSC2007) += tsc2007.o obj-$(CONFIG_TOUCHSCREEN_UCB1400) += ucb1400_ts.o diff --git a/drivers/input/touchscreen/tsc2004.c b/drivers/input/touchscreen/tsc2004.c new file mode 100644 index 000000000000..7295c198aa08 --- /dev/null +++ b/drivers/input/touchscreen/tsc2004.c @@ -0,0 +1,83 @@ +/* + * TSC2004 touchscreen driver + * + * Copyright (C) 2015 QWERTY Embedded Design + * Copyright (C) 2015 EMAC Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/module.h> +#include <linux/input.h> +#include <linux/of.h> +#include <linux/i2c.h> +#include <linux/regmap.h> +#include "tsc200x-core.h" + +static int tsc2004_cmd(struct device *dev, u8 cmd) +{ + u8 tx = TSC200X_CMD | TSC200X_CMD_12BIT | cmd; + s32 data; + struct i2c_client *i2c = to_i2c_client(dev); + + data = i2c_smbus_write_byte(i2c, tx); + if (data < 0) { + dev_err(dev, "%s: failed, command: %x i2c error: %d\n", + __func__, cmd, data); + return data; + } + + return 0; +} + +static int tsc2004_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) + +{ + return tsc200x_probe(&i2c->dev, i2c->irq, BUS_I2C, + devm_regmap_init_i2c(i2c, &tsc200x_regmap_config), + tsc2004_cmd); +} + +static int tsc2004_remove(struct i2c_client *i2c) +{ + return tsc200x_remove(&i2c->dev); +} + +static const struct i2c_device_id tsc2004_idtable[] = { + { "tsc2004", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tsc2004_idtable); + +#ifdef CONFIG_OF +static const struct of_device_id tsc2004_of_match[] = { + { .compatible = "ti,tsc2004" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, tsc2004_of_match); +#endif + +static struct i2c_driver tsc2004_driver = { + .driver = { + .name = "tsc2004", + .of_match_table = of_match_ptr(tsc2004_of_match), + .pm = &tsc200x_pm_ops, + }, + .id_table = tsc2004_idtable, + .probe = tsc2004_probe, + .remove = tsc2004_remove, +}; +module_i2c_driver(tsc2004_driver); + +MODULE_AUTHOR("Michael Welling <mwelling@ieee.org>"); +MODULE_DESCRIPTION("TSC2004 Touchscreen Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index f41f23318484..b9f593dfd2ef 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -2,9 +2,10 @@ * TSC2005 touchscreen driver * * Copyright (C) 2006-2010 Nokia Corporation + * Copyright (C) 2015 QWERTY Embedded Design + * Copyright (C) 2015 EMAC Inc. * - * Author: Lauri Leukkunen <lauri.leukkunen@nokia.com> - * based on TSC2301 driver by Klaus K. Pedersen <klaus.k.pedersen@nokia.com> + * Based on original tsc2005.c by Lauri Leukkunen <lauri.leukkunen@nokia.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 @@ -15,192 +16,32 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * */ -#include <linux/kernel.h> #include <linux/module.h> #include <linux/input.h> -#include <linux/input/touchscreen.h> -#include <linux/interrupt.h> -#include <linux/delay.h> -#include <linux/pm.h> -#include <linux/of.h> #include <linux/spi/spi.h> -#include <linux/spi/tsc2005.h> -#include <linux/regulator/consumer.h> #include <linux/regmap.h> -#include <linux/gpio/consumer.h> - -/* - * The touchscreen interface operates as follows: - * - * 1) Pen is pressed against the touchscreen. - * 2) TSC2005 performs AD conversion. - * 3) After the conversion is done TSC2005 drives DAV line down. - * 4) GPIO IRQ is received and tsc2005_irq_thread() is scheduled. - * 5) tsc2005_irq_thread() queues up an spi transfer to fetch the x, y, z1, z2 - * values. - * 6) tsc2005_irq_thread() reports coordinates to input layer and sets up - * tsc2005_penup_timer() to be called after TSC2005_PENUP_TIME_MS (40ms). - * 7) When the penup timer expires, there have not been touch or DAV interrupts - * during the last 40ms which means the pen has been lifted. - * - * ESD recovery via a hardware reset is done if the TSC2005 doesn't respond - * after a configurable period (in ms) of activity. If esd_timeout is 0, the - * watchdog is disabled. - */ - -/* control byte 1 */ -#define TSC2005_CMD 0x80 -#define TSC2005_CMD_NORMAL 0x00 -#define TSC2005_CMD_STOP 0x01 -#define TSC2005_CMD_12BIT 0x04 - -/* control byte 0 */ -#define TSC2005_REG_READ 0x01 /* R/W access */ -#define TSC2005_REG_PND0 0x02 /* Power Not Down Control */ -#define TSC2005_REG_X (0x0 << 3) -#define TSC2005_REG_Y (0x1 << 3) -#define TSC2005_REG_Z1 (0x2 << 3) -#define TSC2005_REG_Z2 (0x3 << 3) -#define TSC2005_REG_AUX (0x4 << 3) -#define TSC2005_REG_TEMP1 (0x5 << 3) -#define TSC2005_REG_TEMP2 (0x6 << 3) -#define TSC2005_REG_STATUS (0x7 << 3) -#define TSC2005_REG_AUX_HIGH (0x8 << 3) -#define TSC2005_REG_AUX_LOW (0x9 << 3) -#define TSC2005_REG_TEMP_HIGH (0xA << 3) -#define TSC2005_REG_TEMP_LOW (0xB << 3) -#define TSC2005_REG_CFR0 (0xC << 3) -#define TSC2005_REG_CFR1 (0xD << 3) -#define TSC2005_REG_CFR2 (0xE << 3) -#define TSC2005_REG_CONV_FUNC (0xF << 3) - -/* configuration register 0 */ -#define TSC2005_CFR0_PRECHARGE_276US 0x0040 -#define TSC2005_CFR0_STABTIME_1MS 0x0300 -#define TSC2005_CFR0_CLOCK_1MHZ 0x1000 -#define TSC2005_CFR0_RESOLUTION12 0x2000 -#define TSC2005_CFR0_PENMODE 0x8000 -#define TSC2005_CFR0_INITVALUE (TSC2005_CFR0_STABTIME_1MS | \ - TSC2005_CFR0_CLOCK_1MHZ | \ - TSC2005_CFR0_RESOLUTION12 | \ - TSC2005_CFR0_PRECHARGE_276US | \ - TSC2005_CFR0_PENMODE) - -/* bits common to both read and write of configuration register 0 */ -#define TSC2005_CFR0_RW_MASK 0x3fff - -/* configuration register 1 */ -#define TSC2005_CFR1_BATCHDELAY_4MS 0x0003 -#define TSC2005_CFR1_INITVALUE TSC2005_CFR1_BATCHDELAY_4MS - -/* configuration register 2 */ -#define TSC2005_CFR2_MAVE_Z 0x0004 -#define TSC2005_CFR2_MAVE_Y 0x0008 -#define TSC2005_CFR2_MAVE_X 0x0010 -#define TSC2005_CFR2_AVG_7 0x0800 -#define TSC2005_CFR2_MEDIUM_15 0x3000 -#define TSC2005_CFR2_INITVALUE (TSC2005_CFR2_MAVE_X | \ - TSC2005_CFR2_MAVE_Y | \ - TSC2005_CFR2_MAVE_Z | \ - TSC2005_CFR2_MEDIUM_15 | \ - TSC2005_CFR2_AVG_7) - -#define MAX_12BIT 0xfff -#define TSC2005_DEF_X_FUZZ 4 -#define TSC2005_DEF_Y_FUZZ 8 -#define TSC2005_DEF_P_FUZZ 2 -#define TSC2005_DEF_RESISTOR 280 - -#define TSC2005_SPI_MAX_SPEED_HZ 10000000 -#define TSC2005_PENUP_TIME_MS 40 - -static const struct regmap_range tsc2005_writable_ranges[] = { - regmap_reg_range(TSC2005_REG_AUX_HIGH, TSC2005_REG_CFR2), -}; - -static const struct regmap_access_table tsc2005_writable_table = { - .yes_ranges = tsc2005_writable_ranges, - .n_yes_ranges = ARRAY_SIZE(tsc2005_writable_ranges), -}; - -static struct regmap_config tsc2005_regmap_config = { - .reg_bits = 8, - .val_bits = 16, - .reg_stride = 0x08, - .max_register = 0x78, - .read_flag_mask = TSC2005_REG_READ, - .write_flag_mask = TSC2005_REG_PND0, - .wr_table = &tsc2005_writable_table, - .use_single_rw = true, -}; - -struct tsc2005_data { - u16 x; - u16 y; - u16 z1; - u16 z2; -} __packed; -#define TSC2005_DATA_REGS 4 - -struct tsc2005 { - struct spi_device *spi; - struct regmap *regmap; - - struct input_dev *idev; - char phys[32]; - - struct mutex mutex; - - /* raw copy of previous x,y,z */ - int in_x; - int in_y; - int in_z1; - int in_z2; - - spinlock_t lock; - struct timer_list penup_timer; +#include "tsc200x-core.h" - unsigned int esd_timeout; - struct delayed_work esd_work; - unsigned long last_valid_interrupt; - - unsigned int x_plate_ohm; - - bool opened; - bool suspended; - - bool pen_down; - - struct regulator *vio; - - struct gpio_desc *reset_gpio; - void (*set_reset)(bool enable); -}; - -static int tsc2005_cmd(struct tsc2005 *ts, u8 cmd) +static int tsc2005_cmd(struct device *dev, u8 cmd) { - u8 tx = TSC2005_CMD | TSC2005_CMD_12BIT | cmd; + u8 tx = TSC200X_CMD | TSC200X_CMD_12BIT | cmd; struct spi_transfer xfer = { - .tx_buf = &tx, - .len = 1, - .bits_per_word = 8, + .tx_buf = &tx, + .len = 1, + .bits_per_word = 8, }; struct spi_message msg; + struct spi_device *spi = to_spi_device(dev); int error; spi_message_init(&msg); spi_message_add_tail(&xfer, &msg); - error = spi_sync(ts->spi, &msg); + error = spi_sync(spi, &msg); if (error) { - dev_err(&ts->spi->dev, "%s: failed, command: %x, error: %d\n", + dev_err(dev, "%s: failed, command: %x, spi error: %d\n", __func__, cmd, error); return error; } @@ -208,382 +49,10 @@ static int tsc2005_cmd(struct tsc2005 *ts, u8 cmd) return 0; } -static void tsc2005_update_pen_state(struct tsc2005 *ts, - int x, int y, int pressure) -{ - if (pressure) { - input_report_abs(ts->idev, ABS_X, x); - input_report_abs(ts->idev, ABS_Y, y); - input_report_abs(ts->idev, ABS_PRESSURE, pressure); - if (!ts->pen_down) { - input_report_key(ts->idev, BTN_TOUCH, !!pressure); - ts->pen_down = true; - } - } else { - input_report_abs(ts->idev, ABS_PRESSURE, 0); - if (ts->pen_down) { - input_report_key(ts->idev, BTN_TOUCH, 0); - ts->pen_down = false; - } - } - input_sync(ts->idev); - dev_dbg(&ts->spi->dev, "point(%4d,%4d), pressure (%4d)\n", x, y, - pressure); -} - -static irqreturn_t tsc2005_irq_thread(int irq, void *_ts) -{ - struct tsc2005 *ts = _ts; - unsigned long flags; - unsigned int pressure; - struct tsc2005_data tsdata; - int error; - - /* read the coordinates */ - error = regmap_bulk_read(ts->regmap, TSC2005_REG_X, &tsdata, - TSC2005_DATA_REGS); - if (unlikely(error)) - goto out; - - /* validate position */ - if (unlikely(tsdata.x > MAX_12BIT || tsdata.y > MAX_12BIT)) - goto out; - - /* Skip reading if the pressure components are out of range */ - if (unlikely(tsdata.z1 == 0 || tsdata.z2 > MAX_12BIT)) - goto out; - if (unlikely(tsdata.z1 >= tsdata.z2)) - goto out; - - /* - * Skip point if this is a pen down with the exact same values as - * the value before pen-up - that implies SPI fed us stale data - */ - if (!ts->pen_down && - ts->in_x == tsdata.x && ts->in_y == tsdata.y && - ts->in_z1 == tsdata.z1 && ts->in_z2 == tsdata.z2) { - goto out; - } - - /* - * At this point we are happy we have a valid and useful reading. - * Remember it for later comparisons. We may now begin downsampling. - */ - ts->in_x = tsdata.x; - ts->in_y = tsdata.y; - ts->in_z1 = tsdata.z1; - ts->in_z2 = tsdata.z2; - - /* Compute touch pressure resistance using equation #1 */ - pressure = tsdata.x * (tsdata.z2 - tsdata.z1) / tsdata.z1; - pressure = pressure * ts->x_plate_ohm / 4096; - if (unlikely(pressure > MAX_12BIT)) - goto out; - - spin_lock_irqsave(&ts->lock, flags); - - tsc2005_update_pen_state(ts, tsdata.x, tsdata.y, pressure); - mod_timer(&ts->penup_timer, - jiffies + msecs_to_jiffies(TSC2005_PENUP_TIME_MS)); - - spin_unlock_irqrestore(&ts->lock, flags); - - ts->last_valid_interrupt = jiffies; -out: - return IRQ_HANDLED; -} - -static void tsc2005_penup_timer(unsigned long data) -{ - struct tsc2005 *ts = (struct tsc2005 *)data; - unsigned long flags; - - spin_lock_irqsave(&ts->lock, flags); - tsc2005_update_pen_state(ts, 0, 0, 0); - spin_unlock_irqrestore(&ts->lock, flags); -} - -static void tsc2005_start_scan(struct tsc2005 *ts) -{ - regmap_write(ts->regmap, TSC2005_REG_CFR0, TSC2005_CFR0_INITVALUE); - regmap_write(ts->regmap, TSC2005_REG_CFR1, TSC2005_CFR1_INITVALUE); - regmap_write(ts->regmap, TSC2005_REG_CFR2, TSC2005_CFR2_INITVALUE); - tsc2005_cmd(ts, TSC2005_CMD_NORMAL); -} - -static void tsc2005_stop_scan(struct tsc2005 *ts) -{ - tsc2005_cmd(ts, TSC2005_CMD_STOP); -} - -static void tsc2005_set_reset(struct tsc2005 *ts, bool enable) -{ - if (ts->reset_gpio) - gpiod_set_value_cansleep(ts->reset_gpio, enable); - else if (ts->set_reset) - ts->set_reset(enable); -} - -/* must be called with ts->mutex held */ -static void __tsc2005_disable(struct tsc2005 *ts) -{ - tsc2005_stop_scan(ts); - - disable_irq(ts->spi->irq); - del_timer_sync(&ts->penup_timer); - - cancel_delayed_work_sync(&ts->esd_work); - - enable_irq(ts->spi->irq); -} - -/* must be called with ts->mutex held */ -static void __tsc2005_enable(struct tsc2005 *ts) -{ - tsc2005_start_scan(ts); - - if (ts->esd_timeout && (ts->set_reset || ts->reset_gpio)) { - ts->last_valid_interrupt = jiffies; - schedule_delayed_work(&ts->esd_work, - round_jiffies_relative( - msecs_to_jiffies(ts->esd_timeout))); - } - -} - -static ssize_t tsc2005_selftest_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct tsc2005 *ts = dev_get_drvdata(dev); - unsigned int temp_high; - unsigned int temp_high_orig; - unsigned int temp_high_test; - bool success = true; - int error; - - mutex_lock(&ts->mutex); - - /* - * Test TSC2005 communications via temp high register. - */ - __tsc2005_disable(ts); - - error = regmap_read(ts->regmap, TSC2005_REG_TEMP_HIGH, &temp_high_orig); - if (error) { - dev_warn(dev, "selftest failed: read error %d\n", error); - success = false; - goto out; - } - - temp_high_test = (temp_high_orig - 1) & MAX_12BIT; - - error = regmap_write(ts->regmap, TSC2005_REG_TEMP_HIGH, temp_high_test); - if (error) { - dev_warn(dev, "selftest failed: write error %d\n", error); - success = false; - goto out; - } - - error = regmap_read(ts->regmap, TSC2005_REG_TEMP_HIGH, &temp_high); - if (error) { - dev_warn(dev, "selftest failed: read error %d after write\n", - error); - success = false; - goto out; - } - - if (temp_high != temp_high_test) { - dev_warn(dev, "selftest failed: %d != %d\n", - temp_high, temp_high_test); - success = false; - } - - /* hardware reset */ - tsc2005_set_reset(ts, false); - usleep_range(100, 500); /* only 10us required */ - tsc2005_set_reset(ts, true); - - if (!success) - goto out; - - /* test that the reset really happened */ - error = regmap_read(ts->regmap, TSC2005_REG_TEMP_HIGH, &temp_high); - if (error) { - dev_warn(dev, "selftest failed: read error %d after reset\n", - error); - success = false; - goto out; - } - - if (temp_high != temp_high_orig) { - dev_warn(dev, "selftest failed after reset: %d != %d\n", - temp_high, temp_high_orig); - success = false; - } - -out: - __tsc2005_enable(ts); - mutex_unlock(&ts->mutex); - - return sprintf(buf, "%d\n", success); -} - -static DEVICE_ATTR(selftest, S_IRUGO, tsc2005_selftest_show, NULL); - -static struct attribute *tsc2005_attrs[] = { - &dev_attr_selftest.attr, - NULL -}; - -static umode_t tsc2005_attr_is_visible(struct kobject *kobj, - struct attribute *attr, int n) -{ - struct device *dev = container_of(kobj, struct device, kobj); - struct tsc2005 *ts = dev_get_drvdata(dev); - umode_t mode = attr->mode; - - if (attr == &dev_attr_selftest.attr) { - if (!ts->set_reset && !ts->reset_gpio) - mode = 0; - } - - return mode; -} - -static const struct attribute_group tsc2005_attr_group = { - .is_visible = tsc2005_attr_is_visible, - .attrs = tsc2005_attrs, -}; - -static void tsc2005_esd_work(struct work_struct *work) -{ - struct tsc2005 *ts = container_of(work, struct tsc2005, esd_work.work); - int error; - unsigned int r; - - if (!mutex_trylock(&ts->mutex)) { - /* - * If the mutex is taken, it means that disable or enable is in - * progress. In that case just reschedule the work. If the work - * is not needed, it will be canceled by disable. - */ - goto reschedule; - } - - if (time_is_after_jiffies(ts->last_valid_interrupt + - msecs_to_jiffies(ts->esd_timeout))) - goto out; - - /* We should be able to read register without disabling interrupts. */ - error = regmap_read(ts->regmap, TSC2005_REG_CFR0, &r); - if (!error && - !((r ^ TSC2005_CFR0_INITVALUE) & TSC2005_CFR0_RW_MASK)) { - goto out; - } - - /* - * If we could not read our known value from configuration register 0 - * then we should reset the controller as if from power-up and start - * scanning again. - */ - dev_info(&ts->spi->dev, "TSC2005 not responding - resetting\n"); - - disable_irq(ts->spi->irq); - del_timer_sync(&ts->penup_timer); - - tsc2005_update_pen_state(ts, 0, 0, 0); - - tsc2005_set_reset(ts, false); - usleep_range(100, 500); /* only 10us required */ - tsc2005_set_reset(ts, true); - - enable_irq(ts->spi->irq); - tsc2005_start_scan(ts); - -out: - mutex_unlock(&ts->mutex); -reschedule: - /* re-arm the watchdog */ - schedule_delayed_work(&ts->esd_work, - round_jiffies_relative( - msecs_to_jiffies(ts->esd_timeout))); -} - -static int tsc2005_open(struct input_dev *input) -{ - struct tsc2005 *ts = input_get_drvdata(input); - - mutex_lock(&ts->mutex); - - if (!ts->suspended) - __tsc2005_enable(ts); - - ts->opened = true; - - mutex_unlock(&ts->mutex); - - return 0; -} - -static void tsc2005_close(struct input_dev *input) -{ - struct tsc2005 *ts = input_get_drvdata(input); - - mutex_lock(&ts->mutex); - - if (!ts->suspended) - __tsc2005_disable(ts); - - ts->opened = false; - - mutex_unlock(&ts->mutex); -} - static int tsc2005_probe(struct spi_device *spi) { - const struct tsc2005_platform_data *pdata = dev_get_platdata(&spi->dev); - struct device_node *np = spi->dev.of_node; - - struct tsc2005 *ts; - struct input_dev *input_dev; - unsigned int max_x = MAX_12BIT; - unsigned int max_y = MAX_12BIT; - unsigned int max_p = MAX_12BIT; - unsigned int fudge_x = TSC2005_DEF_X_FUZZ; - unsigned int fudge_y = TSC2005_DEF_Y_FUZZ; - unsigned int fudge_p = TSC2005_DEF_P_FUZZ; - unsigned int x_plate_ohm = TSC2005_DEF_RESISTOR; - unsigned int esd_timeout; int error; - if (!np && !pdata) { - dev_err(&spi->dev, "no platform data\n"); - return -ENODEV; - } - - if (spi->irq <= 0) { - dev_err(&spi->dev, "no irq\n"); - return -ENODEV; - } - - if (pdata) { - fudge_x = pdata->ts_x_fudge; - fudge_y = pdata->ts_y_fudge; - fudge_p = pdata->ts_pressure_fudge; - max_x = pdata->ts_x_max; - max_y = pdata->ts_y_max; - max_p = pdata->ts_pressure_max; - x_plate_ohm = pdata->ts_x_plate_ohm; - esd_timeout = pdata->esd_timeout_ms; - } else { - x_plate_ohm = TSC2005_DEF_RESISTOR; - of_property_read_u32(np, "ti,x-plate-ohms", &x_plate_ohm); - esd_timeout = 0; - of_property_read_u32(np, "ti,esd-recovery-timeout-ms", - &esd_timeout); - } - spi->mode = SPI_MODE_0; spi->bits_per_word = 8; if (!spi->max_speed_hz) @@ -593,174 +62,27 @@ static int tsc2005_probe(struct spi_device *spi) if (error) return error; - ts = devm_kzalloc(&spi->dev, sizeof(*ts), GFP_KERNEL); - if (!ts) - return -ENOMEM; - - input_dev = devm_input_allocate_device(&spi->dev); - if (!input_dev) - return -ENOMEM; - - ts->spi = spi; - ts->idev = input_dev; - - ts->regmap = devm_regmap_init_spi(spi, &tsc2005_regmap_config); - if (IS_ERR(ts->regmap)) - return PTR_ERR(ts->regmap); - - ts->x_plate_ohm = x_plate_ohm; - ts->esd_timeout = esd_timeout; - - ts->reset_gpio = devm_gpiod_get_optional(&spi->dev, "reset", - GPIOD_OUT_HIGH); - if (IS_ERR(ts->reset_gpio)) { - error = PTR_ERR(ts->reset_gpio); - dev_err(&spi->dev, "error acquiring reset gpio: %d\n", error); - return error; - } - - ts->vio = devm_regulator_get_optional(&spi->dev, "vio"); - if (IS_ERR(ts->vio)) { - error = PTR_ERR(ts->vio); - dev_err(&spi->dev, "vio regulator missing (%d)", error); - return error; - } - - if (!ts->reset_gpio && pdata) - ts->set_reset = pdata->set_reset; - - mutex_init(&ts->mutex); - - spin_lock_init(&ts->lock); - setup_timer(&ts->penup_timer, tsc2005_penup_timer, (unsigned long)ts); - - INIT_DELAYED_WORK(&ts->esd_work, tsc2005_esd_work); - - snprintf(ts->phys, sizeof(ts->phys), - "%s/input-ts", dev_name(&spi->dev)); - - input_dev->name = "TSC2005 touchscreen"; - input_dev->phys = ts->phys; - input_dev->id.bustype = BUS_SPI; - input_dev->dev.parent = &spi->dev; - input_dev->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY); - input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); - - input_set_abs_params(input_dev, ABS_X, 0, max_x, fudge_x, 0); - input_set_abs_params(input_dev, ABS_Y, 0, max_y, fudge_y, 0); - input_set_abs_params(input_dev, ABS_PRESSURE, 0, max_p, fudge_p, 0); - - if (np) - touchscreen_parse_properties(input_dev, false); - - input_dev->open = tsc2005_open; - input_dev->close = tsc2005_close; - - input_set_drvdata(input_dev, ts); - - /* Ensure the touchscreen is off */ - tsc2005_stop_scan(ts); - - error = devm_request_threaded_irq(&spi->dev, spi->irq, NULL, - tsc2005_irq_thread, - IRQF_TRIGGER_RISING | IRQF_ONESHOT, - "tsc2005", ts); - if (error) { - dev_err(&spi->dev, "Failed to request irq, err: %d\n", error); - return error; - } - - /* enable regulator for DT */ - if (ts->vio) { - error = regulator_enable(ts->vio); - if (error) - return error; - } - - dev_set_drvdata(&spi->dev, ts); - error = sysfs_create_group(&spi->dev.kobj, &tsc2005_attr_group); - if (error) { - dev_err(&spi->dev, - "Failed to create sysfs attributes, err: %d\n", error); - goto disable_regulator; - } - - error = input_register_device(ts->idev); - if (error) { - dev_err(&spi->dev, - "Failed to register input device, err: %d\n", error); - goto err_remove_sysfs; - } - - irq_set_irq_wake(spi->irq, 1); - return 0; - -err_remove_sysfs: - sysfs_remove_group(&spi->dev.kobj, &tsc2005_attr_group); -disable_regulator: - if (ts->vio) - regulator_disable(ts->vio); - return error; + return tsc200x_probe(&spi->dev, spi->irq, BUS_SPI, + devm_regmap_init_spi(spi, &tsc200x_regmap_config), + tsc2005_cmd); } static int tsc2005_remove(struct spi_device *spi) { - struct tsc2005 *ts = dev_get_drvdata(&spi->dev); - - sysfs_remove_group(&spi->dev.kobj, &tsc2005_attr_group); - - if (ts->vio) - regulator_disable(ts->vio); - - return 0; -} - -static int __maybe_unused tsc2005_suspend(struct device *dev) -{ - struct tsc2005 *ts = dev_get_drvdata(dev); - - mutex_lock(&ts->mutex); - - if (!ts->suspended && ts->opened) - __tsc2005_disable(ts); - - ts->suspended = true; - - mutex_unlock(&ts->mutex); - - return 0; -} - -static int __maybe_unused tsc2005_resume(struct device *dev) -{ - struct tsc2005 *ts = dev_get_drvdata(dev); - - mutex_lock(&ts->mutex); - - if (ts->suspended && ts->opened) - __tsc2005_enable(ts); - - ts->suspended = false; - - mutex_unlock(&ts->mutex); - - return 0; + return tsc200x_remove(&spi->dev); } -static SIMPLE_DEV_PM_OPS(tsc2005_pm_ops, tsc2005_suspend, tsc2005_resume); - static struct spi_driver tsc2005_driver = { .driver = { .name = "tsc2005", - .pm = &tsc2005_pm_ops, + .pm = &tsc200x_pm_ops, }, .probe = tsc2005_probe, .remove = tsc2005_remove, }; - module_spi_driver(tsc2005_driver); -MODULE_AUTHOR("Lauri Leukkunen <lauri.leukkunen@nokia.com>"); +MODULE_AUTHOR("Michael Welling <mwelling@ieee.org>"); MODULE_DESCRIPTION("TSC2005 Touchscreen Driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("spi:tsc2005"); diff --git a/drivers/input/touchscreen/tsc200x-core.c b/drivers/input/touchscreen/tsc200x-core.c new file mode 100644 index 000000000000..15240c1ee850 --- /dev/null +++ b/drivers/input/touchscreen/tsc200x-core.c @@ -0,0 +1,665 @@ +/* + * TSC2004/TSC2005 touchscreen driver core + * + * Copyright (C) 2006-2010 Nokia Corporation + * Copyright (C) 2015 QWERTY Embedded Design + * Copyright (C) 2015 EMAC Inc. + * + * Author: Lauri Leukkunen <lauri.leukkunen@nokia.com> + * based on TSC2301 driver by Klaus K. Pedersen <klaus.k.pedersen@nokia.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. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/input.h> +#include <linux/input/touchscreen.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/of.h> +#include <linux/spi/tsc2005.h> +#include <linux/regulator/consumer.h> +#include <linux/regmap.h> +#include <linux/gpio/consumer.h> +#include "tsc200x-core.h" + +/* + * The touchscreen interface operates as follows: + * + * 1) Pen is pressed against the touchscreen. + * 2) TSC200X performs AD conversion. + * 3) After the conversion is done TSC200X drives DAV line down. + * 4) GPIO IRQ is received and tsc200x_irq_thread() is scheduled. + * 5) tsc200x_irq_thread() queues up a transfer to fetch the x, y, z1, z2 + * values. + * 6) tsc200x_irq_thread() reports coordinates to input layer and sets up + * tsc200x_penup_timer() to be called after TSC200X_PENUP_TIME_MS (40ms). + * 7) When the penup timer expires, there have not been touch or DAV interrupts + * during the last 40ms which means the pen has been lifted. + * + * ESD recovery via a hardware reset is done if the TSC200X doesn't respond + * after a configurable period (in ms) of activity. If esd_timeout is 0, the + * watchdog is disabled. + */ + +static const struct regmap_range tsc200x_writable_ranges[] = { + regmap_reg_range(TSC200X_REG_AUX_HIGH, TSC200X_REG_CFR2), +}; + +static const struct regmap_access_table tsc200x_writable_table = { + .yes_ranges = tsc200x_writable_ranges, + .n_yes_ranges = ARRAY_SIZE(tsc200x_writable_ranges), +}; + +const struct regmap_config tsc200x_regmap_config = { + .reg_bits = 8, + .val_bits = 16, + .reg_stride = 0x08, + .max_register = 0x78, + .read_flag_mask = TSC200X_REG_READ, + .write_flag_mask = TSC200X_REG_PND0, + .wr_table = &tsc200x_writable_table, + .use_single_rw = true, +}; +EXPORT_SYMBOL_GPL(tsc200x_regmap_config); + +struct tsc200x_data { + u16 x; + u16 y; + u16 z1; + u16 z2; +} __packed; +#define TSC200X_DATA_REGS 4 + +struct tsc200x { + struct device *dev; + struct regmap *regmap; + __u16 bustype; + + struct input_dev *idev; + char phys[32]; + + struct mutex mutex; + + /* raw copy of previous x,y,z */ + int in_x; + int in_y; + int in_z1; + int in_z2; + + spinlock_t lock; + struct timer_list penup_timer; + + unsigned int esd_timeout; + struct delayed_work esd_work; + unsigned long last_valid_interrupt; + + unsigned int x_plate_ohm; + + bool opened; + bool suspended; + + bool pen_down; + + struct regulator *vio; + + struct gpio_desc *reset_gpio; + void (*set_reset)(bool enable); + int (*tsc200x_cmd)(struct device *dev, u8 cmd); + int irq; +}; + +static void tsc200x_update_pen_state(struct tsc200x *ts, + int x, int y, int pressure) +{ + if (pressure) { + input_report_abs(ts->idev, ABS_X, x); + input_report_abs(ts->idev, ABS_Y, y); + input_report_abs(ts->idev, ABS_PRESSURE, pressure); + if (!ts->pen_down) { + input_report_key(ts->idev, BTN_TOUCH, !!pressure); + ts->pen_down = true; + } + } else { + input_report_abs(ts->idev, ABS_PRESSURE, 0); + if (ts->pen_down) { + input_report_key(ts->idev, BTN_TOUCH, 0); + ts->pen_down = false; + } + } + input_sync(ts->idev); + dev_dbg(ts->dev, "point(%4d,%4d), pressure (%4d)\n", x, y, + pressure); +} + +static irqreturn_t tsc200x_irq_thread(int irq, void *_ts) +{ + struct tsc200x *ts = _ts; + unsigned long flags; + unsigned int pressure; + struct tsc200x_data tsdata; + int error; + + /* read the coordinates */ + error = regmap_bulk_read(ts->regmap, TSC200X_REG_X, &tsdata, + TSC200X_DATA_REGS); + if (unlikely(error)) + goto out; + + /* validate position */ + if (unlikely(tsdata.x > MAX_12BIT || tsdata.y > MAX_12BIT)) + goto out; + + /* Skip reading if the pressure components are out of range */ + if (unlikely(tsdata.z1 == 0 || tsdata.z2 > MAX_12BIT)) + goto out; + if (unlikely(tsdata.z1 >= tsdata.z2)) + goto out; + + /* + * Skip point if this is a pen down with the exact same values as + * the value before pen-up - that implies SPI fed us stale data + */ + if (!ts->pen_down && + ts->in_x == tsdata.x && ts->in_y == tsdata.y && + ts->in_z1 == tsdata.z1 && ts->in_z2 == tsdata.z2) { + goto out; + } + + /* + * At this point we are happy we have a valid and useful reading. + * Remember it for later comparisons. We may now begin downsampling. + */ + ts->in_x = tsdata.x; + ts->in_y = tsdata.y; + ts->in_z1 = tsdata.z1; + ts->in_z2 = tsdata.z2; + + /* Compute touch pressure resistance using equation #1 */ + pressure = tsdata.x * (tsdata.z2 - tsdata.z1) / tsdata.z1; + pressure = pressure * ts->x_plate_ohm / 4096; + if (unlikely(pressure > MAX_12BIT)) + goto out; + + spin_lock_irqsave(&ts->lock, flags); + + tsc200x_update_pen_state(ts, tsdata.x, tsdata.y, pressure); + mod_timer(&ts->penup_timer, + jiffies + msecs_to_jiffies(TSC200X_PENUP_TIME_MS)); + + spin_unlock_irqrestore(&ts->lock, flags); + + ts->last_valid_interrupt = jiffies; +out: + return IRQ_HANDLED; +} + +static void tsc200x_penup_timer(unsigned long data) +{ + struct tsc200x *ts = (struct tsc200x *)data; + unsigned long flags; + + spin_lock_irqsave(&ts->lock, flags); + tsc200x_update_pen_state(ts, 0, 0, 0); + spin_unlock_irqrestore(&ts->lock, flags); +} + +static void tsc200x_start_scan(struct tsc200x *ts) +{ + regmap_write(ts->regmap, TSC200X_REG_CFR0, TSC200X_CFR0_INITVALUE); + regmap_write(ts->regmap, TSC200X_REG_CFR1, TSC200X_CFR1_INITVALUE); + regmap_write(ts->regmap, TSC200X_REG_CFR2, TSC200X_CFR2_INITVALUE); + ts->tsc200x_cmd(ts->dev, TSC200X_CMD_NORMAL); +} + +static void tsc200x_stop_scan(struct tsc200x *ts) +{ + ts->tsc200x_cmd(ts->dev, TSC200X_CMD_STOP); +} + +static void tsc200x_set_reset(struct tsc200x *ts, bool enable) +{ + if (ts->reset_gpio) + gpiod_set_value_cansleep(ts->reset_gpio, enable); + else if (ts->set_reset) + ts->set_reset(enable); +} + +/* must be called with ts->mutex held */ +static void __tsc200x_disable(struct tsc200x *ts) +{ + tsc200x_stop_scan(ts); + + disable_irq(ts->irq); + del_timer_sync(&ts->penup_timer); + + cancel_delayed_work_sync(&ts->esd_work); + + enable_irq(ts->irq); +} + +/* must be called with ts->mutex held */ +static void __tsc200x_enable(struct tsc200x *ts) +{ + tsc200x_start_scan(ts); + + if (ts->esd_timeout && (ts->set_reset || ts->reset_gpio)) { + ts->last_valid_interrupt = jiffies; + schedule_delayed_work(&ts->esd_work, + round_jiffies_relative( + msecs_to_jiffies(ts->esd_timeout))); + } +} + +static ssize_t tsc200x_selftest_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tsc200x *ts = dev_get_drvdata(dev); + unsigned int temp_high; + unsigned int temp_high_orig; + unsigned int temp_high_test; + bool success = true; + int error; + + mutex_lock(&ts->mutex); + + /* + * Test TSC200X communications via temp high register. + */ + __tsc200x_disable(ts); + + error = regmap_read(ts->regmap, TSC200X_REG_TEMP_HIGH, &temp_high_orig); + if (error) { + dev_warn(dev, "selftest failed: read error %d\n", error); + success = false; + goto out; + } + + temp_high_test = (temp_high_orig - 1) & MAX_12BIT; + + error = regmap_write(ts->regmap, TSC200X_REG_TEMP_HIGH, temp_high_test); + if (error) { + dev_warn(dev, "selftest failed: write error %d\n", error); + success = false; + goto out; + } + + error = regmap_read(ts->regmap, TSC200X_REG_TEMP_HIGH, &temp_high); + if (error) { + dev_warn(dev, "selftest failed: read error %d after write\n", + error); + success = false; + goto out; + } + + if (temp_high != temp_high_test) { + dev_warn(dev, "selftest failed: %d != %d\n", + temp_high, temp_high_test); + success = false; + } + + /* hardware reset */ + tsc200x_set_reset(ts, false); + usleep_range(100, 500); /* only 10us required */ + tsc200x_set_reset(ts, true); + + if (!success) + goto out; + + /* test that the reset really happened */ + error = regmap_read(ts->regmap, TSC200X_REG_TEMP_HIGH, &temp_high); + if (error) { + dev_warn(dev, "selftest failed: read error %d after reset\n", + error); + success = false; + goto out; + } + + if (temp_high != temp_high_orig) { + dev_warn(dev, "selftest failed after reset: %d != %d\n", + temp_high, temp_high_orig); + success = false; + } + +out: + __tsc200x_enable(ts); + mutex_unlock(&ts->mutex); + + return sprintf(buf, "%d\n", success); +} + +static DEVICE_ATTR(selftest, S_IRUGO, tsc200x_selftest_show, NULL); + +static struct attribute *tsc200x_attrs[] = { + &dev_attr_selftest.attr, + NULL +}; + +static umode_t tsc200x_attr_is_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct tsc200x *ts = dev_get_drvdata(dev); + umode_t mode = attr->mode; + + if (attr == &dev_attr_selftest.attr) { + if (!ts->set_reset && !ts->reset_gpio) + mode = 0; + } + + return mode; +} + +static const struct attribute_group tsc200x_attr_group = { + .is_visible = tsc200x_attr_is_visible, + .attrs = tsc200x_attrs, +}; + +static void tsc200x_esd_work(struct work_struct *work) +{ + struct tsc200x *ts = container_of(work, struct tsc200x, esd_work.work); + int error; + unsigned int r; + + if (!mutex_trylock(&ts->mutex)) { + /* + * If the mutex is taken, it means that disable or enable is in + * progress. In that case just reschedule the work. If the work + * is not needed, it will be canceled by disable. + */ + goto reschedule; + } + + if (time_is_after_jiffies(ts->last_valid_interrupt + + msecs_to_jiffies(ts->esd_timeout))) + goto out; + + /* We should be able to read register without disabling interrupts. */ + error = regmap_read(ts->regmap, TSC200X_REG_CFR0, &r); + if (!error && + !((r ^ TSC200X_CFR0_INITVALUE) & TSC200X_CFR0_RW_MASK)) { + goto out; + } + + /* + * If we could not read our known value from configuration register 0 + * then we should reset the controller as if from power-up and start + * scanning again. + */ + dev_info(ts->dev, "TSC200X not responding - resetting\n"); + + disable_irq(ts->irq); + del_timer_sync(&ts->penup_timer); + + tsc200x_update_pen_state(ts, 0, 0, 0); + + tsc200x_set_reset(ts, false); + usleep_range(100, 500); /* only 10us required */ + tsc200x_set_reset(ts, true); + + enable_irq(ts->irq); + tsc200x_start_scan(ts); + +out: + mutex_unlock(&ts->mutex); +reschedule: + /* re-arm the watchdog */ + schedule_delayed_work(&ts->esd_work, + round_jiffies_relative( + msecs_to_jiffies(ts->esd_timeout))); +} + +static int tsc200x_open(struct input_dev *input) +{ + struct tsc200x *ts = input_get_drvdata(input); + + mutex_lock(&ts->mutex); + + if (!ts->suspended) + __tsc200x_enable(ts); + + ts->opened = true; + + mutex_unlock(&ts->mutex); + + return 0; +} + +static void tsc200x_close(struct input_dev *input) +{ + struct tsc200x *ts = input_get_drvdata(input); + + mutex_lock(&ts->mutex); + + if (!ts->suspended) + __tsc200x_disable(ts); + + ts->opened = false; + + mutex_unlock(&ts->mutex); +} + +int tsc200x_probe(struct device *dev, int irq, __u16 bustype, + struct regmap *regmap, + int (*tsc200x_cmd)(struct device *dev, u8 cmd)) +{ + const struct tsc2005_platform_data *pdata = dev_get_platdata(dev); + struct device_node *np = dev->of_node; + + struct tsc200x *ts; + struct input_dev *input_dev; + unsigned int max_x = MAX_12BIT; + unsigned int max_y = MAX_12BIT; + unsigned int max_p = MAX_12BIT; + unsigned int fudge_x = TSC200X_DEF_X_FUZZ; + unsigned int fudge_y = TSC200X_DEF_Y_FUZZ; + unsigned int fudge_p = TSC200X_DEF_P_FUZZ; + unsigned int x_plate_ohm = TSC200X_DEF_RESISTOR; + unsigned int esd_timeout; + int error; + + if (!np && !pdata) { + dev_err(dev, "no platform data\n"); + return -ENODEV; + } + + if (irq <= 0) { + dev_err(dev, "no irq\n"); + return -ENODEV; + } + + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + if (!tsc200x_cmd) { + dev_err(dev, "no cmd function\n"); + return -ENODEV; + } + + if (pdata) { + fudge_x = pdata->ts_x_fudge; + fudge_y = pdata->ts_y_fudge; + fudge_p = pdata->ts_pressure_fudge; + max_x = pdata->ts_x_max; + max_y = pdata->ts_y_max; + max_p = pdata->ts_pressure_max; + x_plate_ohm = pdata->ts_x_plate_ohm; + esd_timeout = pdata->esd_timeout_ms; + } else { + x_plate_ohm = TSC200X_DEF_RESISTOR; + of_property_read_u32(np, "ti,x-plate-ohms", &x_plate_ohm); + esd_timeout = 0; + of_property_read_u32(np, "ti,esd-recovery-timeout-ms", + &esd_timeout); + } + + ts = devm_kzalloc(dev, sizeof(*ts), GFP_KERNEL); + if (!ts) + return -ENOMEM; + + input_dev = devm_input_allocate_device(dev); + if (!input_dev) + return -ENOMEM; + + ts->irq = irq; + ts->dev = dev; + ts->idev = input_dev; + ts->regmap = regmap; + ts->tsc200x_cmd = tsc200x_cmd; + ts->x_plate_ohm = x_plate_ohm; + ts->esd_timeout = esd_timeout; + + ts->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(ts->reset_gpio)) { + error = PTR_ERR(ts->reset_gpio); + dev_err(dev, "error acquiring reset gpio: %d\n", error); + return error; + } + + ts->vio = devm_regulator_get_optional(dev, "vio"); + if (IS_ERR(ts->vio)) { + error = PTR_ERR(ts->vio); + dev_err(dev, "vio regulator missing (%d)", error); + return error; + } + + if (!ts->reset_gpio && pdata) + ts->set_reset = pdata->set_reset; + + mutex_init(&ts->mutex); + + spin_lock_init(&ts->lock); + setup_timer(&ts->penup_timer, tsc200x_penup_timer, (unsigned long)ts); + + INIT_DELAYED_WORK(&ts->esd_work, tsc200x_esd_work); + + snprintf(ts->phys, sizeof(ts->phys), + "%s/input-ts", dev_name(dev)); + + input_dev->name = "TSC200X touchscreen"; + input_dev->phys = ts->phys; + input_dev->id.bustype = bustype; + input_dev->dev.parent = dev; + input_dev->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY); + input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); + + input_set_abs_params(input_dev, ABS_X, 0, max_x, fudge_x, 0); + input_set_abs_params(input_dev, ABS_Y, 0, max_y, fudge_y, 0); + input_set_abs_params(input_dev, ABS_PRESSURE, 0, max_p, fudge_p, 0); + + if (np) + touchscreen_parse_properties(input_dev, false); + + input_dev->open = tsc200x_open; + input_dev->close = tsc200x_close; + + input_set_drvdata(input_dev, ts); + + /* Ensure the touchscreen is off */ + tsc200x_stop_scan(ts); + + error = devm_request_threaded_irq(dev, irq, NULL, + tsc200x_irq_thread, + IRQF_TRIGGER_RISING | IRQF_ONESHOT, + "tsc200x", ts); + if (error) { + dev_err(dev, "Failed to request irq, err: %d\n", error); + return error; + } + + /* enable regulator for DT */ + if (ts->vio) { + error = regulator_enable(ts->vio); + if (error) + return error; + } + + dev_set_drvdata(dev, ts); + error = sysfs_create_group(&dev->kobj, &tsc200x_attr_group); + if (error) { + dev_err(dev, + "Failed to create sysfs attributes, err: %d\n", error); + goto disable_regulator; + } + + error = input_register_device(ts->idev); + if (error) { + dev_err(dev, + "Failed to register input device, err: %d\n", error); + goto err_remove_sysfs; + } + + irq_set_irq_wake(irq, 1); + return 0; + +err_remove_sysfs: + sysfs_remove_group(&dev->kobj, &tsc200x_attr_group); +disable_regulator: + if (ts->vio) + regulator_disable(ts->vio); + return error; +} +EXPORT_SYMBOL_GPL(tsc200x_probe); + +int tsc200x_remove(struct device *dev) +{ + struct tsc200x *ts = dev_get_drvdata(dev); + + sysfs_remove_group(&dev->kobj, &tsc200x_attr_group); + + if (ts->vio) + regulator_disable(ts->vio); + + return 0; +} +EXPORT_SYMBOL_GPL(tsc200x_remove); + +static int __maybe_unused tsc200x_suspend(struct device *dev) +{ + struct tsc200x *ts = dev_get_drvdata(dev); + + mutex_lock(&ts->mutex); + + if (!ts->suspended && ts->opened) + __tsc200x_disable(ts); + + ts->suspended = true; + + mutex_unlock(&ts->mutex); + + return 0; +} + +static int __maybe_unused tsc200x_resume(struct device *dev) +{ + struct tsc200x *ts = dev_get_drvdata(dev); + + mutex_lock(&ts->mutex); + + if (ts->suspended && ts->opened) + __tsc200x_enable(ts); + + ts->suspended = false; + + mutex_unlock(&ts->mutex); + + return 0; +} + +SIMPLE_DEV_PM_OPS(tsc200x_pm_ops, tsc200x_suspend, tsc200x_resume); +EXPORT_SYMBOL_GPL(tsc200x_pm_ops); + +MODULE_AUTHOR("Lauri Leukkunen <lauri.leukkunen@nokia.com>"); +MODULE_DESCRIPTION("TSC200x Touchscreen Driver Core"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/tsc200x-core.h b/drivers/input/touchscreen/tsc200x-core.h new file mode 100644 index 000000000000..7a482d102614 --- /dev/null +++ b/drivers/input/touchscreen/tsc200x-core.h @@ -0,0 +1,78 @@ +#ifndef _TSC200X_CORE_H +#define _TSC200X_CORE_H + +/* control byte 1 */ +#define TSC200X_CMD 0x80 +#define TSC200X_CMD_NORMAL 0x00 +#define TSC200X_CMD_STOP 0x01 +#define TSC200X_CMD_12BIT 0x04 + +/* control byte 0 */ +#define TSC200X_REG_READ 0x01 /* R/W access */ +#define TSC200X_REG_PND0 0x02 /* Power Not Down Control */ +#define TSC200X_REG_X (0x0 << 3) +#define TSC200X_REG_Y (0x1 << 3) +#define TSC200X_REG_Z1 (0x2 << 3) +#define TSC200X_REG_Z2 (0x3 << 3) +#define TSC200X_REG_AUX (0x4 << 3) +#define TSC200X_REG_TEMP1 (0x5 << 3) +#define TSC200X_REG_TEMP2 (0x6 << 3) +#define TSC200X_REG_STATUS (0x7 << 3) +#define TSC200X_REG_AUX_HIGH (0x8 << 3) +#define TSC200X_REG_AUX_LOW (0x9 << 3) +#define TSC200X_REG_TEMP_HIGH (0xA << 3) +#define TSC200X_REG_TEMP_LOW (0xB << 3) +#define TSC200X_REG_CFR0 (0xC << 3) +#define TSC200X_REG_CFR1 (0xD << 3) +#define TSC200X_REG_CFR2 (0xE << 3) +#define TSC200X_REG_CONV_FUNC (0xF << 3) + +/* configuration register 0 */ +#define TSC200X_CFR0_PRECHARGE_276US 0x0040 +#define TSC200X_CFR0_STABTIME_1MS 0x0300 +#define TSC200X_CFR0_CLOCK_1MHZ 0x1000 +#define TSC200X_CFR0_RESOLUTION12 0x2000 +#define TSC200X_CFR0_PENMODE 0x8000 +#define TSC200X_CFR0_INITVALUE (TSC200X_CFR0_STABTIME_1MS | \ + TSC200X_CFR0_CLOCK_1MHZ | \ + TSC200X_CFR0_RESOLUTION12 | \ + TSC200X_CFR0_PRECHARGE_276US | \ + TSC200X_CFR0_PENMODE) + +/* bits common to both read and write of configuration register 0 */ +#define TSC200X_CFR0_RW_MASK 0x3fff + +/* configuration register 1 */ +#define TSC200X_CFR1_BATCHDELAY_4MS 0x0003 +#define TSC200X_CFR1_INITVALUE TSC200X_CFR1_BATCHDELAY_4MS + +/* configuration register 2 */ +#define TSC200X_CFR2_MAVE_Z 0x0004 +#define TSC200X_CFR2_MAVE_Y 0x0008 +#define TSC200X_CFR2_MAVE_X 0x0010 +#define TSC200X_CFR2_AVG_7 0x0800 +#define TSC200X_CFR2_MEDIUM_15 0x3000 +#define TSC200X_CFR2_INITVALUE (TSC200X_CFR2_MAVE_X | \ + TSC200X_CFR2_MAVE_Y | \ + TSC200X_CFR2_MAVE_Z | \ + TSC200X_CFR2_MEDIUM_15 | \ + TSC200X_CFR2_AVG_7) + +#define MAX_12BIT 0xfff +#define TSC200X_DEF_X_FUZZ 4 +#define TSC200X_DEF_Y_FUZZ 8 +#define TSC200X_DEF_P_FUZZ 2 +#define TSC200X_DEF_RESISTOR 280 + +#define TSC2005_SPI_MAX_SPEED_HZ 10000000 +#define TSC200X_PENUP_TIME_MS 40 + +extern const struct regmap_config tsc200x_regmap_config; +extern const struct dev_pm_ops tsc200x_pm_ops; + +int tsc200x_probe(struct device *dev, int irq, __u16 bustype, + struct regmap *regmap, + int (*tsc200x_cmd)(struct device *dev, u8 cmd)); +int tsc200x_remove(struct device *dev); + +#endif diff --git a/drivers/iommu/s390-iommu.c b/drivers/iommu/s390-iommu.c index cbe198cb3699..471ee36b9c6e 100644 --- a/drivers/iommu/s390-iommu.c +++ b/drivers/iommu/s390-iommu.c @@ -216,6 +216,7 @@ static int s390_iommu_update_trans(struct s390_domain *s390_domain, u8 *page_addr = (u8 *) (pa & PAGE_MASK); dma_addr_t start_dma_addr = dma_addr; unsigned long irq_flags, nr_pages, i; + unsigned long *entry; int rc = 0; if (dma_addr < s390_domain->domain.geometry.aperture_start || @@ -228,8 +229,12 @@ static int s390_iommu_update_trans(struct s390_domain *s390_domain, spin_lock_irqsave(&s390_domain->dma_table_lock, irq_flags); for (i = 0; i < nr_pages; i++) { - dma_update_cpu_trans(s390_domain->dma_table, page_addr, - dma_addr, flags); + entry = dma_walk_cpu_trans(s390_domain->dma_table, dma_addr); + if (!entry) { + rc = -ENOMEM; + goto undo_cpu_trans; + } + dma_update_cpu_trans(entry, page_addr, flags); page_addr += PAGE_SIZE; dma_addr += PAGE_SIZE; } @@ -242,6 +247,20 @@ static int s390_iommu_update_trans(struct s390_domain *s390_domain, break; } spin_unlock(&s390_domain->list_lock); + +undo_cpu_trans: + if (rc && ((flags & ZPCI_PTE_VALID_MASK) == ZPCI_PTE_VALID)) { + flags = ZPCI_PTE_INVALID; + while (i-- > 0) { + page_addr -= PAGE_SIZE; + dma_addr -= PAGE_SIZE; + entry = dma_walk_cpu_trans(s390_domain->dma_table, + dma_addr); + if (!entry) + break; + dma_update_cpu_trans(entry, page_addr, flags); + } + } spin_unlock_irqrestore(&s390_domain->dma_table_lock, irq_flags); return rc; diff --git a/drivers/irqchip/irq-gic-common.c b/drivers/irqchip/irq-gic-common.c index 44a077f3a4a2..f174ce0ca361 100644 --- a/drivers/irqchip/irq-gic-common.c +++ b/drivers/irqchip/irq-gic-common.c @@ -84,12 +84,15 @@ void __init gic_dist_config(void __iomem *base, int gic_irqs, writel_relaxed(GICD_INT_DEF_PRI_X4, base + GIC_DIST_PRI + i); /* - * Disable all interrupts. Leave the PPI and SGIs alone - * as they are enabled by redistributor registers. + * Deactivate and disable all SPIs. Leave the PPI and SGIs + * alone as they are in the redistributor registers on GICv3. */ - for (i = 32; i < gic_irqs; i += 32) + for (i = 32; i < gic_irqs; i += 32) { writel_relaxed(GICD_INT_EN_CLR_X32, - base + GIC_DIST_ENABLE_CLEAR + i / 8); + base + GIC_DIST_ACTIVE_CLEAR + i / 8); + writel_relaxed(GICD_INT_EN_CLR_X32, + base + GIC_DIST_ENABLE_CLEAR + i / 8); + } if (sync_access) sync_access(); @@ -102,7 +105,9 @@ void gic_cpu_config(void __iomem *base, void (*sync_access)(void)) /* * Deal with the banked PPI and SGI interrupts - disable all * PPI interrupts, ensure all SGI interrupts are enabled. + * Make sure everything is deactivated. */ + writel_relaxed(GICD_INT_EN_CLR_X32, base + GIC_DIST_ACTIVE_CLEAR); writel_relaxed(GICD_INT_EN_CLR_PPI, base + GIC_DIST_ENABLE_CLEAR); writel_relaxed(GICD_INT_EN_SET_SGI, base + GIC_DIST_ENABLE_SET); diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 515c823c1c95..abf2ffaed392 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -73,9 +73,11 @@ struct gic_chip_data { union gic_base cpu_base; #ifdef CONFIG_CPU_PM u32 saved_spi_enable[DIV_ROUND_UP(1020, 32)]; + u32 saved_spi_active[DIV_ROUND_UP(1020, 32)]; u32 saved_spi_conf[DIV_ROUND_UP(1020, 16)]; u32 saved_spi_target[DIV_ROUND_UP(1020, 4)]; u32 __percpu *saved_ppi_enable; + u32 __percpu *saved_ppi_active; u32 __percpu *saved_ppi_conf; #endif struct irq_domain *domain; @@ -566,6 +568,10 @@ static void gic_dist_save(unsigned int gic_nr) for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++) gic_data[gic_nr].saved_spi_enable[i] = readl_relaxed(dist_base + GIC_DIST_ENABLE_SET + i * 4); + + for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++) + gic_data[gic_nr].saved_spi_active[i] = + readl_relaxed(dist_base + GIC_DIST_ACTIVE_SET + i * 4); } /* @@ -604,9 +610,19 @@ static void gic_dist_restore(unsigned int gic_nr) writel_relaxed(gic_data[gic_nr].saved_spi_target[i], dist_base + GIC_DIST_TARGET + i * 4); - for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++) + for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++) { + writel_relaxed(GICD_INT_EN_CLR_X32, + dist_base + GIC_DIST_ENABLE_CLEAR + i * 4); writel_relaxed(gic_data[gic_nr].saved_spi_enable[i], dist_base + GIC_DIST_ENABLE_SET + i * 4); + } + + for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++) { + writel_relaxed(GICD_INT_EN_CLR_X32, + dist_base + GIC_DIST_ACTIVE_CLEAR + i * 4); + writel_relaxed(gic_data[gic_nr].saved_spi_active[i], + dist_base + GIC_DIST_ACTIVE_SET + i * 4); + } writel_relaxed(GICD_ENABLE, dist_base + GIC_DIST_CTRL); } @@ -631,6 +647,10 @@ static void gic_cpu_save(unsigned int gic_nr) for (i = 0; i < DIV_ROUND_UP(32, 32); i++) ptr[i] = readl_relaxed(dist_base + GIC_DIST_ENABLE_SET + i * 4); + ptr = raw_cpu_ptr(gic_data[gic_nr].saved_ppi_active); + for (i = 0; i < DIV_ROUND_UP(32, 32); i++) + ptr[i] = readl_relaxed(dist_base + GIC_DIST_ACTIVE_SET + i * 4); + ptr = raw_cpu_ptr(gic_data[gic_nr].saved_ppi_conf); for (i = 0; i < DIV_ROUND_UP(32, 16); i++) ptr[i] = readl_relaxed(dist_base + GIC_DIST_CONFIG + i * 4); @@ -654,8 +674,18 @@ static void gic_cpu_restore(unsigned int gic_nr) return; ptr = raw_cpu_ptr(gic_data[gic_nr].saved_ppi_enable); - for (i = 0; i < DIV_ROUND_UP(32, 32); i++) + for (i = 0; i < DIV_ROUND_UP(32, 32); i++) { + writel_relaxed(GICD_INT_EN_CLR_X32, + dist_base + GIC_DIST_ENABLE_CLEAR + i * 4); writel_relaxed(ptr[i], dist_base + GIC_DIST_ENABLE_SET + i * 4); + } + + ptr = raw_cpu_ptr(gic_data[gic_nr].saved_ppi_active); + for (i = 0; i < DIV_ROUND_UP(32, 32); i++) { + writel_relaxed(GICD_INT_EN_CLR_X32, + dist_base + GIC_DIST_ACTIVE_CLEAR + i * 4); + writel_relaxed(ptr[i], dist_base + GIC_DIST_ACTIVE_SET + i * 4); + } ptr = raw_cpu_ptr(gic_data[gic_nr].saved_ppi_conf); for (i = 0; i < DIV_ROUND_UP(32, 16); i++) @@ -710,6 +740,10 @@ static void __init gic_pm_init(struct gic_chip_data *gic) sizeof(u32)); BUG_ON(!gic->saved_ppi_enable); + gic->saved_ppi_active = __alloc_percpu(DIV_ROUND_UP(32, 32) * 4, + sizeof(u32)); + BUG_ON(!gic->saved_ppi_active); + gic->saved_ppi_conf = __alloc_percpu(DIV_ROUND_UP(32, 16) * 4, sizeof(u32)); BUG_ON(!gic->saved_ppi_conf); diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index aeaa061f0dbf..9e17ef27a183 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -29,6 +29,7 @@ struct gic_pcpu_mask { DECLARE_BITMAP(pcpu_mask, GIC_MAX_INTRS); }; +static unsigned long __gic_base_addr; static void __iomem *gic_base; static struct gic_pcpu_mask pcpu_masks[NR_CPUS]; static DEFINE_SPINLOCK(gic_lock); @@ -301,6 +302,17 @@ int gic_get_c0_fdc_int(void) GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_FDC)); } +int gic_get_usm_range(struct resource *gic_usm_res) +{ + if (!gic_present) + return -1; + + gic_usm_res->start = __gic_base_addr + USM_VISIBLE_SECTION_OFS; + gic_usm_res->end = gic_usm_res->start + (USM_VISIBLE_SECTION_SIZE - 1); + + return 0; +} + static void gic_handle_shared_int(bool chained) { unsigned int i, intr, virq, gic_reg_step = mips_cm_is64 ? 8 : 4; @@ -798,6 +810,8 @@ static void __init __gic_init(unsigned long gic_base_addr, { unsigned int gicconfig; + __gic_base_addr = gic_base_addr; + gic_base = ioremap_nocache(gic_base_addr, gic_addrspace_size); gicconfig = gic_read(GIC_REG(SHARED, GIC_SH_CONFIG)); diff --git a/drivers/lightnvm/rrpc.c b/drivers/lightnvm/rrpc.c index 64a888a5e9b3..7ba64c87ba1c 100644 --- a/drivers/lightnvm/rrpc.c +++ b/drivers/lightnvm/rrpc.c @@ -803,7 +803,7 @@ static int rrpc_submit_io(struct rrpc *rrpc, struct bio *bio, return NVM_IO_OK; } -static void rrpc_make_rq(struct request_queue *q, struct bio *bio) +static blk_qc_t rrpc_make_rq(struct request_queue *q, struct bio *bio) { struct rrpc *rrpc = q->queuedata; struct nvm_rq *rqd; @@ -811,21 +811,21 @@ static void rrpc_make_rq(struct request_queue *q, struct bio *bio) if (bio->bi_rw & REQ_DISCARD) { rrpc_discard(rrpc, bio); - return; + return BLK_QC_T_NONE; } rqd = mempool_alloc(rrpc->rq_pool, GFP_KERNEL); if (!rqd) { pr_err_ratelimited("rrpc: not able to queue bio."); bio_io_error(bio); - return; + return BLK_QC_T_NONE; } memset(rqd, 0, sizeof(struct nvm_rq)); err = rrpc_submit_io(rrpc, bio, rqd, NVM_IOTYPE_NONE); switch (err) { case NVM_IO_OK: - return; + return BLK_QC_T_NONE; case NVM_IO_ERR: bio_io_error(bio); break; @@ -841,6 +841,7 @@ static void rrpc_make_rq(struct request_queue *q, struct bio *bio) } mempool_free(rqd, rrpc->rq_pool); + return BLK_QC_T_NONE; } static void rrpc_requeue(struct work_struct *work) diff --git a/drivers/md/bcache/request.c b/drivers/md/bcache/request.c index 8e9877b04637..25fa8445bb24 100644 --- a/drivers/md/bcache/request.c +++ b/drivers/md/bcache/request.c @@ -958,7 +958,8 @@ static void cached_dev_nodata(struct closure *cl) /* Cached devices - read & write stuff */ -static void cached_dev_make_request(struct request_queue *q, struct bio *bio) +static blk_qc_t cached_dev_make_request(struct request_queue *q, + struct bio *bio) { struct search *s; struct bcache_device *d = bio->bi_bdev->bd_disk->private_data; @@ -997,6 +998,8 @@ static void cached_dev_make_request(struct request_queue *q, struct bio *bio) else generic_make_request(bio); } + + return BLK_QC_T_NONE; } static int cached_dev_ioctl(struct bcache_device *d, fmode_t mode, @@ -1070,7 +1073,8 @@ static void flash_dev_nodata(struct closure *cl) continue_at(cl, search_free, NULL); } -static void flash_dev_make_request(struct request_queue *q, struct bio *bio) +static blk_qc_t flash_dev_make_request(struct request_queue *q, + struct bio *bio) { struct search *s; struct closure *cl; @@ -1093,7 +1097,7 @@ static void flash_dev_make_request(struct request_queue *q, struct bio *bio) continue_at_nobarrier(&s->cl, flash_dev_nodata, bcache_wq); - return; + return BLK_QC_T_NONE; } else if (rw) { bch_keybuf_check_overlapping(&s->iop.c->moving_gc_keys, &KEY(d->id, bio->bi_iter.bi_sector, 0), @@ -1109,6 +1113,7 @@ static void flash_dev_make_request(struct request_queue *q, struct bio *bio) } continue_at(cl, search_free, NULL); + return BLK_QC_T_NONE; } static int flash_dev_ioctl(struct bcache_device *d, fmode_t mode, diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 32440ad5f684..6e15f3565892 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -1755,7 +1755,7 @@ static void __split_and_process_bio(struct mapped_device *md, * The request function that just remaps the bio built up by * dm_merge_bvec. */ -static void dm_make_request(struct request_queue *q, struct bio *bio) +static blk_qc_t dm_make_request(struct request_queue *q, struct bio *bio) { int rw = bio_data_dir(bio); struct mapped_device *md = q->queuedata; @@ -1774,12 +1774,12 @@ static void dm_make_request(struct request_queue *q, struct bio *bio) queue_io(md, bio); else bio_io_error(bio); - return; + return BLK_QC_T_NONE; } __split_and_process_bio(md, map, bio); dm_put_live_table(md, srcu_idx); - return; + return BLK_QC_T_NONE; } int dm_request_based(struct mapped_device *md) diff --git a/drivers/md/md.c b/drivers/md/md.c index 3f9a514b5b9d..807095f4c793 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -250,7 +250,7 @@ static DEFINE_SPINLOCK(all_mddevs_lock); * call has finished, the bio has been linked into some internal structure * and so is visible to ->quiesce(), so we don't need the refcount any more. */ -static void md_make_request(struct request_queue *q, struct bio *bio) +static blk_qc_t md_make_request(struct request_queue *q, struct bio *bio) { const int rw = bio_data_dir(bio); struct mddev *mddev = q->queuedata; @@ -262,13 +262,13 @@ static void md_make_request(struct request_queue *q, struct bio *bio) if (mddev == NULL || mddev->pers == NULL || !mddev->ready) { bio_io_error(bio); - return; + return BLK_QC_T_NONE; } if (mddev->ro == 1 && unlikely(rw == WRITE)) { if (bio_sectors(bio) != 0) bio->bi_error = -EROFS; bio_endio(bio); - return; + return BLK_QC_T_NONE; } smp_rmb(); /* Ensure implications of 'active' are visible */ rcu_read_lock(); @@ -302,6 +302,8 @@ static void md_make_request(struct request_queue *q, struct bio *bio) if (atomic_dec_and_test(&mddev->active_io) && mddev->suspended) wake_up(&mddev->sb_wait); + + return BLK_QC_T_NONE; } /* mddev_suspend makes sure no new requests are submitted diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c index bc1c9602f435..e8f847226a19 100644 --- a/drivers/media/pci/cx23885/cx23885-core.c +++ b/drivers/media/pci/cx23885/cx23885-core.c @@ -1992,9 +1992,9 @@ static int cx23885_initdev(struct pci_dev *pci_dev, (unsigned long long)pci_resource_start(pci_dev, 0)); pci_set_master(pci_dev); - if (!pci_dma_supported(pci_dev, 0xffffffff)) { + err = pci_set_dma_mask(pci_dev, 0xffffffff); + if (err) { printk("%s/0: Oops: no 32bit PCI DMA ???\n", dev->name); - err = -EIO; goto fail_context; } diff --git a/drivers/media/pci/cx25821/cx25821-core.c b/drivers/media/pci/cx25821/cx25821-core.c index 559f8293c53a..0042803a9de7 100644 --- a/drivers/media/pci/cx25821/cx25821-core.c +++ b/drivers/media/pci/cx25821/cx25821-core.c @@ -1319,7 +1319,8 @@ static int cx25821_initdev(struct pci_dev *pci_dev, dev->pci_lat, (unsigned long long)dev->base_io_addr); pci_set_master(pci_dev); - if (!pci_dma_supported(pci_dev, 0xffffffff)) { + err = pci_set_dma_mask(pci_dev, 0xffffffff); + if (err) { pr_err("%s/0: Oops: no 32bit PCI DMA ???\n", dev->name); err = -EIO; goto fail_irq; diff --git a/drivers/media/pci/cx88/cx88-alsa.c b/drivers/media/pci/cx88/cx88-alsa.c index 57ddf8a34178..1b5268f9bb24 100644 --- a/drivers/media/pci/cx88/cx88-alsa.c +++ b/drivers/media/pci/cx88/cx88-alsa.c @@ -890,9 +890,9 @@ static int snd_cx88_create(struct snd_card *card, struct pci_dev *pci, return err; } - if (!pci_dma_supported(pci,DMA_BIT_MASK(32))) { + err = pci_set_dma_mask(pci,DMA_BIT_MASK(32)); + if (err) { dprintk(0, "%s/1: Oops: no 32bit PCI DMA ???\n",core->name); - err = -EIO; cx88_core_put(core, pci); return err; } diff --git a/drivers/media/pci/cx88/cx88-mpeg.c b/drivers/media/pci/cx88/cx88-mpeg.c index 9961b2232b97..f34c229f9b37 100644 --- a/drivers/media/pci/cx88/cx88-mpeg.c +++ b/drivers/media/pci/cx88/cx88-mpeg.c @@ -393,7 +393,8 @@ static int cx8802_init_common(struct cx8802_dev *dev) if (pci_enable_device(dev->pci)) return -EIO; pci_set_master(dev->pci); - if (!pci_dma_supported(dev->pci,DMA_BIT_MASK(32))) { + err = pci_set_dma_mask(dev->pci,DMA_BIT_MASK(32)); + if (err) { printk("%s/2: Oops: no 32bit PCI DMA ???\n",dev->core->name); return -EIO; } diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c index f3b12dbbe9a1..aef9acf351f6 100644 --- a/drivers/media/pci/cx88/cx88-video.c +++ b/drivers/media/pci/cx88/cx88-video.c @@ -1314,9 +1314,9 @@ static int cx8800_initdev(struct pci_dev *pci_dev, dev->pci_lat,(unsigned long long)pci_resource_start(pci_dev,0)); pci_set_master(pci_dev); - if (!pci_dma_supported(pci_dev,DMA_BIT_MASK(32))) { + err = pci_set_dma_mask(pci_dev,DMA_BIT_MASK(32)); + if (err) { printk("%s/0: Oops: no 32bit PCI DMA ???\n",core->name); - err = -EIO; goto fail_core; } dev->alloc_ctx = vb2_dma_sg_init_ctx(&pci_dev->dev); diff --git a/drivers/media/pci/netup_unidvb/netup_unidvb_core.c b/drivers/media/pci/netup_unidvb/netup_unidvb_core.c index 83c90d3462e9..3fdbd81b5580 100644 --- a/drivers/media/pci/netup_unidvb/netup_unidvb_core.c +++ b/drivers/media/pci/netup_unidvb/netup_unidvb_core.c @@ -810,7 +810,7 @@ static int netup_unidvb_initdev(struct pci_dev *pci_dev, "%s(): board vendor 0x%x, revision 0x%x\n", __func__, board_vendor, board_revision); pci_set_master(pci_dev); - if (!pci_dma_supported(pci_dev, 0xffffffff)) { + if (pci_set_dma_mask(pci_dev, 0xffffffff) < 0) { dev_err(&pci_dev->dev, "%s(): 32bit PCI DMA is not supported\n", __func__); goto pci_detect_err; diff --git a/drivers/media/pci/saa7134/saa7134-core.c b/drivers/media/pci/saa7134/saa7134-core.c index 87f39f97a79f..f720cea80e28 100644 --- a/drivers/media/pci/saa7134/saa7134-core.c +++ b/drivers/media/pci/saa7134/saa7134-core.c @@ -951,9 +951,9 @@ static int saa7134_initdev(struct pci_dev *pci_dev, pci_name(pci_dev), dev->pci_rev, pci_dev->irq, dev->pci_lat,(unsigned long long)pci_resource_start(pci_dev,0)); pci_set_master(pci_dev); - if (!pci_dma_supported(pci_dev, DMA_BIT_MASK(32))) { + err = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32)); + if (err) { pr_warn("%s: Oops: no 32bit PCI DMA ???\n", dev->name); - err = -EIO; goto fail1; } diff --git a/drivers/media/pci/saa7164/saa7164-core.c b/drivers/media/pci/saa7164/saa7164-core.c index 3206a826b80d..8bbd092fbe1d 100644 --- a/drivers/media/pci/saa7164/saa7164-core.c +++ b/drivers/media/pci/saa7164/saa7164-core.c @@ -1264,9 +1264,9 @@ static int saa7164_initdev(struct pci_dev *pci_dev, pci_set_master(pci_dev); /* TODO */ - if (!pci_dma_supported(pci_dev, 0xffffffff)) { + err = pci_set_dma_mask(pci_dev, 0xffffffff); + if (err) { printk("%s/0: Oops: no 32bit PCI DMA ???\n", dev->name); - err = -EIO; goto fail_irq; } diff --git a/drivers/media/pci/tw68/tw68-core.c b/drivers/media/pci/tw68/tw68-core.c index 04706cc9b818..4e77618fbb2b 100644 --- a/drivers/media/pci/tw68/tw68-core.c +++ b/drivers/media/pci/tw68/tw68-core.c @@ -257,9 +257,9 @@ static int tw68_initdev(struct pci_dev *pci_dev, dev->name, pci_name(pci_dev), dev->pci_rev, pci_dev->irq, dev->pci_lat, (u64)pci_resource_start(pci_dev, 0)); pci_set_master(pci_dev); - if (!pci_dma_supported(pci_dev, DMA_BIT_MASK(32))) { + err = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32)); + if (err) { pr_info("%s: Oops: no 32bit PCI DMA ???\n", dev->name); - err = -EIO; goto fail1; } diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c index fc7393729081..02b5f69e1a42 100644 --- a/drivers/message/fusion/mptctl.c +++ b/drivers/message/fusion/mptctl.c @@ -1038,6 +1038,10 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, int sge_offset, int *frags, int i, buflist_ent; int sg_spill = MAX_FRAGS_SPILL1; int dir; + + if (bytes < 0) + return NULL; + /* initialization */ *frags = 0; *blp = NULL; diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 005a88b9f440..7ebccfa8072a 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -1994,7 +1994,6 @@ static struct scsi_host_template mptsas_driver_template = { .cmd_per_lun = 7, .use_clustering = ENABLE_CLUSTERING, .shost_attrs = mptscsih_host_attrs, - .use_blk_tags = 1, }; static int mptsas_get_linkerrors(struct sas_phy *phy) diff --git a/drivers/misc/spear13xx_pcie_gadget.c b/drivers/misc/spear13xx_pcie_gadget.c index b8374cdaf9c9..ee120dcbb3e6 100644 --- a/drivers/misc/spear13xx_pcie_gadget.c +++ b/drivers/misc/spear13xx_pcie_gadget.c @@ -220,11 +220,17 @@ static irqreturn_t spear_pcie_gadget_irq(int irq, void *dev_id) /* * configfs interfaces show/store functions */ -static ssize_t pcie_gadget_show_link( - struct spear_pcie_gadget_config *config, - char *buf) + +static struct pcie_gadget_target *to_target(struct config_item *item) { - struct pcie_app_reg __iomem *app_reg = config->va_app_base; + return item ? + container_of(to_configfs_subsystem(to_config_group(item)), + struct pcie_gadget_target, subsys) : NULL; +} + +static ssize_t pcie_gadget_link_show(struct config_item *item, char *buf) +{ + struct pcie_app_reg __iomem *app_reg = to_target(item)->va_app_base; if (readl(&app_reg->app_status_1) & ((u32)1 << XMLH_LINK_UP_ID)) return sprintf(buf, "UP"); @@ -232,11 +238,10 @@ static ssize_t pcie_gadget_show_link( return sprintf(buf, "DOWN"); } -static ssize_t pcie_gadget_store_link( - struct spear_pcie_gadget_config *config, +static ssize_t pcie_gadget_link_store(struct config_item *item, const char *buf, size_t count) { - struct pcie_app_reg __iomem *app_reg = config->va_app_base; + struct pcie_app_reg __iomem *app_reg = to_target(item)->va_app_base; if (sysfs_streq(buf, "UP")) writel(readl(&app_reg->app_ctrl_0) | (1 << APP_LTSSM_ENABLE_ID), @@ -250,17 +255,15 @@ static ssize_t pcie_gadget_store_link( return count; } -static ssize_t pcie_gadget_show_int_type( - struct spear_pcie_gadget_config *config, - char *buf) +static ssize_t pcie_gadget_int_type_show(struct config_item *item, char *buf) { - return sprintf(buf, "%s", config->int_type); + return sprintf(buf, "%s", to_target(item)->int_type); } -static ssize_t pcie_gadget_store_int_type( - struct spear_pcie_gadget_config *config, +static ssize_t pcie_gadget_int_type_store(struct config_item *item, const char *buf, size_t count) { + struct spear_pcie_gadget_config *config = to_target(item) u32 cap, vec, flags; ulong vector; @@ -288,11 +291,10 @@ static ssize_t pcie_gadget_store_int_type( return count; } -static ssize_t pcie_gadget_show_no_of_msi( - struct spear_pcie_gadget_config *config, - char *buf) +static ssize_t pcie_gadget_no_of_msi_show(struct config_item *item, char *buf) { - struct pcie_app_reg __iomem *app_reg = config->va_app_base; + struct spear_pcie_gadget_config *config = to_target(item) + struct pcie_app_reg __iomem *app_reg = to_target(item)->va_app_base; u32 cap, vec, flags; ulong vector; @@ -313,13 +315,12 @@ static ssize_t pcie_gadget_show_no_of_msi( return sprintf(buf, "%lu", vector); } -static ssize_t pcie_gadget_store_no_of_msi( - struct spear_pcie_gadget_config *config, +static ssize_t pcie_gadget_no_of_msi_store(struct config_item *item, const char *buf, size_t count) { int ret; - ret = kstrtoul(buf, 0, &config->requested_msi); + ret = kstrtoul(buf, 0, &to_target(item)->requested_msi); if (ret) return ret; @@ -329,11 +330,10 @@ static ssize_t pcie_gadget_store_no_of_msi( return count; } -static ssize_t pcie_gadget_store_inta( - struct spear_pcie_gadget_config *config, +static ssize_t pcie_gadget_inta_store(struct config_item *item, const char *buf, size_t count) { - struct pcie_app_reg __iomem *app_reg = config->va_app_base; + struct pcie_app_reg __iomem *app_reg = to_target(item)->va_app_base; ulong en; int ret; @@ -351,10 +351,10 @@ static ssize_t pcie_gadget_store_inta( return count; } -static ssize_t pcie_gadget_store_send_msi( - struct spear_pcie_gadget_config *config, +static ssize_t pcie_gadget_send_msi_store(struct config_item *item, const char *buf, size_t count) { + struct spear_pcie_gadget_config *config = to_target(item) struct pcie_app_reg __iomem *app_reg = config->va_app_base; ulong vector; u32 ven_msi; @@ -388,19 +388,16 @@ static ssize_t pcie_gadget_store_send_msi( return count; } -static ssize_t pcie_gadget_show_vendor_id( - struct spear_pcie_gadget_config *config, - char *buf) +static ssize_t pcie_gadget_vendor_id_show(struct config_item *item, char *buf) { u32 id; - spear_dbi_read_reg(config, PCI_VENDOR_ID, 2, &id); + spear_dbi_read_reg(to_target(item), PCI_VENDOR_ID, 2, &id); return sprintf(buf, "%x", id); } -static ssize_t pcie_gadget_store_vendor_id( - struct spear_pcie_gadget_config *config, +static ssize_t pcie_gadget_vendor_id_store(struct config_item *item, const char *buf, size_t count) { ulong id; @@ -410,24 +407,21 @@ static ssize_t pcie_gadget_store_vendor_id( if (ret) return ret; - spear_dbi_write_reg(config, PCI_VENDOR_ID, 2, id); + spear_dbi_write_reg(to_target(item), PCI_VENDOR_ID, 2, id); return count; } -static ssize_t pcie_gadget_show_device_id( - struct spear_pcie_gadget_config *config, - char *buf) +static ssize_t pcie_gadget_device_id_show(struct config_item *item, char *buf) { u32 id; - spear_dbi_read_reg(config, PCI_DEVICE_ID, 2, &id); + spear_dbi_read_reg(to_target(item), PCI_DEVICE_ID, 2, &id); return sprintf(buf, "%x", id); } -static ssize_t pcie_gadget_store_device_id( - struct spear_pcie_gadget_config *config, +static ssize_t pcie_gadget_device_id_store(struct config_item *item, const char *buf, size_t count) { ulong id; @@ -437,22 +431,20 @@ static ssize_t pcie_gadget_store_device_id( if (ret) return ret; - spear_dbi_write_reg(config, PCI_DEVICE_ID, 2, id); + spear_dbi_write_reg(to_target(item), PCI_DEVICE_ID, 2, id); return count; } -static ssize_t pcie_gadget_show_bar0_size( - struct spear_pcie_gadget_config *config, - char *buf) +static ssize_t pcie_gadget_bar0_size_show(struct config_item *item, char *buf) { - return sprintf(buf, "%lx", config->bar0_size); + return sprintf(buf, "%lx", to_target(item)->bar0_size); } -static ssize_t pcie_gadget_store_bar0_size( - struct spear_pcie_gadget_config *config, +static ssize_t pcie_gadget_bar0_size_store(struct config_item *item, const char *buf, size_t count) { + struct spear_pcie_gadget_config *config = to_target(item) ulong size; u32 pos, pos1; u32 no_of_bit = 0; @@ -489,21 +481,20 @@ static ssize_t pcie_gadget_store_bar0_size( return count; } -static ssize_t pcie_gadget_show_bar0_address( - struct spear_pcie_gadget_config *config, +static ssize_t pcie_gadget_bar0_address_show(struct config_item *item, char *buf) { - struct pcie_app_reg __iomem *app_reg = config->va_app_base; + struct pcie_app_reg __iomem *app_reg = to_target(item)->va_app_base; u32 address = readl(&app_reg->pim0_mem_addr_start); return sprintf(buf, "%x", address); } -static ssize_t pcie_gadget_store_bar0_address( - struct spear_pcie_gadget_config *config, +static ssize_t pcie_gadget_bar0_address_store(struct config_item *item, const char *buf, size_t count) { + struct spear_pcie_gadget_config *config = to_target(item) struct pcie_app_reg __iomem *app_reg = config->va_app_base; ulong address; int ret; @@ -524,15 +515,13 @@ static ssize_t pcie_gadget_store_bar0_address( return count; } -static ssize_t pcie_gadget_show_bar0_rw_offset( - struct spear_pcie_gadget_config *config, +static ssize_t pcie_gadget_bar0_rw_offset_show(struct config_item *item, char *buf) { - return sprintf(buf, "%lx", config->bar0_rw_offset); + return sprintf(buf, "%lx", to_target(item)->bar0_rw_offset); } -static ssize_t pcie_gadget_store_bar0_rw_offset( - struct spear_pcie_gadget_config *config, +static ssize_t pcie_gadget_bar0_rw_offset_store(struct config_item *item, const char *buf, size_t count) { ulong offset; @@ -545,15 +534,14 @@ static ssize_t pcie_gadget_store_bar0_rw_offset( if (offset % 4) return -EINVAL; - config->bar0_rw_offset = offset; + to_target(item)->bar0_rw_offset = offset; return count; } -static ssize_t pcie_gadget_show_bar0_data( - struct spear_pcie_gadget_config *config, - char *buf) +static ssize_t pcie_gadget_bar0_data_show(struct config_item *item, char *buf) { + struct spear_pcie_gadget_config *config = to_target(item) ulong data; if (!config->va_bar0_address) @@ -564,10 +552,10 @@ static ssize_t pcie_gadget_show_bar0_data( return sprintf(buf, "%lx", data); } -static ssize_t pcie_gadget_store_bar0_data( - struct spear_pcie_gadget_config *config, +static ssize_t pcie_gadget_bar0_data_store(struct config_item *item, const char *buf, size_t count) { + struct spear_pcie_gadget_config *config = to_target(item) ulong data; int ret; @@ -583,97 +571,35 @@ static ssize_t pcie_gadget_store_bar0_data( return count; } -/* - * Attribute definitions. - */ - -#define PCIE_GADGET_TARGET_ATTR_RO(_name) \ -static struct pcie_gadget_target_attr pcie_gadget_target_##_name = \ - __CONFIGFS_ATTR(_name, S_IRUGO, pcie_gadget_show_##_name, NULL) - -#define PCIE_GADGET_TARGET_ATTR_WO(_name) \ -static struct pcie_gadget_target_attr pcie_gadget_target_##_name = \ - __CONFIGFS_ATTR(_name, S_IWUSR, NULL, pcie_gadget_store_##_name) - -#define PCIE_GADGET_TARGET_ATTR_RW(_name) \ -static struct pcie_gadget_target_attr pcie_gadget_target_##_name = \ - __CONFIGFS_ATTR(_name, S_IRUGO | S_IWUSR, pcie_gadget_show_##_name, \ - pcie_gadget_store_##_name) -PCIE_GADGET_TARGET_ATTR_RW(link); -PCIE_GADGET_TARGET_ATTR_RW(int_type); -PCIE_GADGET_TARGET_ATTR_RW(no_of_msi); -PCIE_GADGET_TARGET_ATTR_WO(inta); -PCIE_GADGET_TARGET_ATTR_WO(send_msi); -PCIE_GADGET_TARGET_ATTR_RW(vendor_id); -PCIE_GADGET_TARGET_ATTR_RW(device_id); -PCIE_GADGET_TARGET_ATTR_RW(bar0_size); -PCIE_GADGET_TARGET_ATTR_RW(bar0_address); -PCIE_GADGET_TARGET_ATTR_RW(bar0_rw_offset); -PCIE_GADGET_TARGET_ATTR_RW(bar0_data); +CONFIGFS_ATTR(pcie_gadget_, link); +CONFIGFS_ATTR(pcie_gadget_, int_type); +CONFIGFS_ATTR(pcie_gadget_, no_of_msi); +CONFIGFS_ATTR_WO(pcie_gadget_, inta); +CONFIGFS_ATTR_WO(pcie_gadget_, send_msi); +CONFIGFS_ATTR(pcie_gadget_, vendor_id); +CONFIGFS_ATTR(pcie_gadget_, device_id); +CONFIGFS_ATTR(pcie_gadget_, bar0_size); +CONFIGFS_ATTR(pcie_gadget_, bar0_address); +CONFIGFS_ATTR(pcie_gadget_, bar0_rw_offset); +CONFIGFS_ATTR(pcie_gadget_, bar0_data); static struct configfs_attribute *pcie_gadget_target_attrs[] = { - &pcie_gadget_target_link.attr, - &pcie_gadget_target_int_type.attr, - &pcie_gadget_target_no_of_msi.attr, - &pcie_gadget_target_inta.attr, - &pcie_gadget_target_send_msi.attr, - &pcie_gadget_target_vendor_id.attr, - &pcie_gadget_target_device_id.attr, - &pcie_gadget_target_bar0_size.attr, - &pcie_gadget_target_bar0_address.attr, - &pcie_gadget_target_bar0_rw_offset.attr, - &pcie_gadget_target_bar0_data.attr, + &pcie_gadget_attr_link, + &pcie_gadget_attr_int_type, + &pcie_gadget_attr_no_of_msi, + &pcie_gadget_attr_inta, + &pcie_gadget_attr_send_msi, + &pcie_gadget_attr_vendor_id, + &pcie_gadget_attr_device_id, + &pcie_gadget_attr_bar0_size, + &pcie_gadget_attr_bar0_address, + &pcie_gadget_attr_bar0_rw_offset, + &pcie_gadget_attr_bar0_data, NULL, }; -static struct pcie_gadget_target *to_target(struct config_item *item) -{ - return item ? - container_of(to_configfs_subsystem(to_config_group(item)), - struct pcie_gadget_target, subsys) : NULL; -} - -/* - * Item operations and type for pcie_gadget_target. - */ - -static ssize_t pcie_gadget_target_attr_show(struct config_item *item, - struct configfs_attribute *attr, - char *buf) -{ - ssize_t ret = -EINVAL; - struct pcie_gadget_target *target = to_target(item); - struct pcie_gadget_target_attr *t_attr = - container_of(attr, struct pcie_gadget_target_attr, attr); - - if (t_attr->show) - ret = t_attr->show(&target->config, buf); - return ret; -} - -static ssize_t pcie_gadget_target_attr_store(struct config_item *item, - struct configfs_attribute *attr, - const char *buf, - size_t count) -{ - ssize_t ret = -EINVAL; - struct pcie_gadget_target *target = to_target(item); - struct pcie_gadget_target_attr *t_attr = - container_of(attr, struct pcie_gadget_target_attr, attr); - - if (t_attr->store) - ret = t_attr->store(&target->config, buf, count); - return ret; -} - -static struct configfs_item_operations pcie_gadget_target_item_ops = { - .show_attribute = pcie_gadget_target_attr_show, - .store_attribute = pcie_gadget_target_attr_store, -}; - static struct config_item_type pcie_gadget_target_type = { .ct_attrs = pcie_gadget_target_attrs, - .ct_item_ops = &pcie_gadget_target_item_ops, .ct_owner = THIS_MODULE, }; diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 23b6c8e8701c..d8486168415a 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -65,8 +65,7 @@ MODULE_ALIAS("mmc:block"); #define MMC_SANITIZE_REQ_TIMEOUT 240000 #define MMC_EXTRACT_INDEX_FROM_ARG(x) ((x & 0x00FF0000) >> 16) -#define mmc_req_rel_wr(req) (((req->cmd_flags & REQ_FUA) || \ - (req->cmd_flags & REQ_META)) && \ +#define mmc_req_rel_wr(req) ((req->cmd_flags & REQ_FUA) && \ (rq_data_dir(req) == WRITE)) #define PACKED_CMD_VER 0x01 #define PACKED_CMD_WR 0x02 @@ -1467,13 +1466,9 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq, /* * Reliable writes are used to implement Forced Unit Access and - * REQ_META accesses, and are supported only on MMCs. - * - * XXX: this really needs a good explanation of why REQ_META - * is treated special. + * are supported only on MMCs. */ - bool do_rel_wr = ((req->cmd_flags & REQ_FUA) || - (req->cmd_flags & REQ_META)) && + bool do_rel_wr = (req->cmd_flags & REQ_FUA) && (rq_data_dir(req) == WRITE) && (md->flags & MMC_BLK_REL_WR); diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index c793fda27321..3a9a79ec4343 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1040,9 +1040,24 @@ static int mmc_select_hs_ddr(struct mmc_card *card) return err; } +/* Caller must hold re-tuning */ +static int mmc_switch_status(struct mmc_card *card) +{ + u32 status; + int err; + + err = mmc_send_status(card, &status); + if (err) + return err; + + return mmc_switch_status_error(card->host, status); +} + static int mmc_select_hs400(struct mmc_card *card) { struct mmc_host *host = card->host; + bool send_status = true; + unsigned int max_dtr; int err = 0; u8 val; @@ -1053,25 +1068,36 @@ static int mmc_select_hs400(struct mmc_card *card) host->ios.bus_width == MMC_BUS_WIDTH_8)) return 0; - /* - * Before switching to dual data rate operation for HS400, - * it is required to convert from HS200 mode to HS mode. - */ - mmc_set_timing(card->host, MMC_TIMING_MMC_HS); - mmc_set_bus_speed(card); + if (host->caps & MMC_CAP_WAIT_WHILE_BUSY) + send_status = false; + /* Reduce frequency to HS frequency */ + max_dtr = card->ext_csd.hs_max_dtr; + mmc_set_clock(host, max_dtr); + + /* Switch card to HS mode */ val = EXT_CSD_TIMING_HS | card->drive_strength << EXT_CSD_DRV_STR_SHIFT; err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, val, card->ext_csd.generic_cmd6_time, - true, true, true); + true, send_status, true); if (err) { pr_err("%s: switch to high-speed from hs200 failed, err:%d\n", mmc_hostname(host), err); return err; } + /* Set host controller to HS timing */ + mmc_set_timing(card->host, MMC_TIMING_MMC_HS); + + if (!send_status) { + err = mmc_switch_status(card); + if (err) + goto out_err; + } + + /* Switch card to DDR */ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, EXT_CSD_DDR_BUS_WIDTH_8, @@ -1082,22 +1108,35 @@ static int mmc_select_hs400(struct mmc_card *card) return err; } + /* Switch card to HS400 */ val = EXT_CSD_TIMING_HS400 | card->drive_strength << EXT_CSD_DRV_STR_SHIFT; err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, val, card->ext_csd.generic_cmd6_time, - true, true, true); + true, send_status, true); if (err) { pr_err("%s: switch to hs400 failed, err:%d\n", mmc_hostname(host), err); return err; } + /* Set host controller to HS400 timing and frequency */ mmc_set_timing(host, MMC_TIMING_MMC_HS400); mmc_set_bus_speed(card); + if (!send_status) { + err = mmc_switch_status(card); + if (err) + goto out_err; + } + return 0; + +out_err: + pr_err("%s: %s failed, error %d\n", mmc_hostname(card->host), + __func__, err); + return err; } int mmc_hs200_to_hs400(struct mmc_card *card) @@ -1105,19 +1144,6 @@ int mmc_hs200_to_hs400(struct mmc_card *card) return mmc_select_hs400(card); } -/* Caller must hold re-tuning */ -static int mmc_switch_status(struct mmc_card *card) -{ - u32 status; - int err; - - err = mmc_send_status(card, &status); - if (err) - return err; - - return mmc_switch_status_error(card->host, status); -} - int mmc_hs400_to_hs200(struct mmc_card *card) { struct mmc_host *host = card->host; @@ -1219,6 +1245,8 @@ static void mmc_select_driver_type(struct mmc_card *card) static int mmc_select_hs200(struct mmc_card *card) { struct mmc_host *host = card->host; + bool send_status = true; + unsigned int old_timing; int err = -EINVAL; u8 val; @@ -1234,6 +1262,9 @@ static int mmc_select_hs200(struct mmc_card *card) mmc_select_driver_type(card); + if (host->caps & MMC_CAP_WAIT_WHILE_BUSY) + send_status = false; + /* * Set the bus width(4 or 8) with host's support and * switch to HS200 mode if bus width is set successfully. @@ -1245,11 +1276,25 @@ static int mmc_select_hs200(struct mmc_card *card) err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, val, card->ext_csd.generic_cmd6_time, - true, true, true); - if (!err) - mmc_set_timing(host, MMC_TIMING_MMC_HS200); + true, send_status, true); + if (err) + goto err; + old_timing = host->ios.timing; + mmc_set_timing(host, MMC_TIMING_MMC_HS200); + if (!send_status) { + err = mmc_switch_status(card); + /* + * mmc_select_timing() assumes timing has not changed if + * it is a switch error. + */ + if (err == -EBADMSG) + mmc_set_timing(host, old_timing); + } } err: + if (err) + pr_err("%s: %s failed, error %d\n", mmc_hostname(card->host), + __func__, err); return err; } diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index af71de5fda3b..1dee533634c9 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -473,6 +473,7 @@ config MMC_DAVINCI config MMC_GOLDFISH tristate "goldfish qemu Multimedia Card Interface support" + depends on HAS_DMA depends on GOLDFISH || COMPILE_TEST help This selects the Goldfish Multimedia card Interface emulation diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index 39568cc29a2a..33dfd7e72516 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -1276,7 +1276,7 @@ static struct msdc_delay_phase get_best_delay(struct msdc_host *host, u32 delay) int start = 0, len = 0; int start_final = 0, len_final = 0; u8 final_phase = 0xff; - struct msdc_delay_phase delay_phase; + struct msdc_delay_phase delay_phase = { 0, }; if (delay == 0) { dev_err(host->dev, "phase error: [map:%x]\n", delay); diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index 8cadd74e8407..ce08896b9d69 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c @@ -805,7 +805,7 @@ static int pxamci_probe(struct platform_device *pdev) goto out; } else { mmc->caps |= host->pdata->gpio_card_ro_invert ? - MMC_CAP2_RO_ACTIVE_HIGH : 0; + 0 : MMC_CAP2_RO_ACTIVE_HIGH; } if (gpio_is_valid(gpio_cd)) diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c index dc4e8446f1ff..5a99a93ed025 100644 --- a/drivers/mtd/nand/jz4740_nand.c +++ b/drivers/mtd/nand/jz4740_nand.c @@ -25,6 +25,7 @@ #include <linux/gpio.h> +#include <asm/mach-jz4740/gpio.h> #include <asm/mach-jz4740/jz4740_nand.h> #define JZ_REG_NAND_CTRL 0x50 diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index cc74142938b0..ece544efccc3 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -3110,7 +3110,7 @@ static void nand_resume(struct mtd_info *mtd) */ static void nand_shutdown(struct mtd_info *mtd) { - nand_get_device(mtd, FL_SHUTDOWN); + nand_get_device(mtd, FL_PM_SUSPENDED); } /* Set default functions */ diff --git a/drivers/mtd/ubi/attach.c b/drivers/mtd/ubi/attach.c index 68eea5befaf1..c1aaf0336cf2 100644 --- a/drivers/mtd/ubi/attach.c +++ b/drivers/mtd/ubi/attach.c @@ -1209,9 +1209,7 @@ static void destroy_ai(struct ubi_attach_info *ai) } } - if (ai->aeb_slab_cache) - kmem_cache_destroy(ai->aeb_slab_cache); - + kmem_cache_destroy(ai->aeb_slab_cache); kfree(ai); } diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c index d16fccf79179..54e056d3be02 100644 --- a/drivers/mtd/ubi/cdev.c +++ b/drivers/mtd/ubi/cdev.c @@ -949,7 +949,7 @@ static long ubi_cdev_ioctl(struct file *file, unsigned int cmd, if (!req) { err = -ENOMEM; break; - }; + } err = copy_from_user(req, argp, sizeof(struct ubi_rnvol_req)); if (err) { diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index 51bca035cd83..5b9834cf2820 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c @@ -1358,7 +1358,7 @@ int self_check_eba(struct ubi_device *ubi, struct ubi_attach_info *ai_fastmap, continue; ubi_err(ubi, "LEB:%i:%i is PEB:%i instead of %i!", - vol->vol_id, i, fm_eba[i][j], + vol->vol_id, j, fm_eba[i][j], scan_eba[i][j]); ubi_assert(0); } diff --git a/drivers/mtd/ubi/fastmap-wl.c b/drivers/mtd/ubi/fastmap-wl.c index b2a665398bca..30d3999dddba 100644 --- a/drivers/mtd/ubi/fastmap-wl.c +++ b/drivers/mtd/ubi/fastmap-wl.c @@ -172,6 +172,30 @@ void ubi_refill_pools(struct ubi_device *ubi) } /** + * produce_free_peb - produce a free physical eraseblock. + * @ubi: UBI device description object + * + * This function tries to make a free PEB by means of synchronous execution of + * pending works. This may be needed if, for example the background thread is + * disabled. Returns zero in case of success and a negative error code in case + * of failure. + */ +static int produce_free_peb(struct ubi_device *ubi) +{ + int err; + + while (!ubi->free.rb_node && ubi->works_count) { + dbg_wl("do one work synchronously"); + err = do_work(ubi); + + if (err) + return err; + } + + return 0; +} + +/** * ubi_wl_get_peb - get a physical eraseblock. * @ubi: UBI device description object * @@ -213,6 +237,11 @@ again: } retried = 1; up_read(&ubi->fm_eba_sem); + ret = produce_free_peb(ubi); + if (ret < 0) { + down_read(&ubi->fm_eba_sem); + goto out; + } goto again; } diff --git a/drivers/mtd/ubi/fastmap.c b/drivers/mtd/ubi/fastmap.c index 4aa2fd8633e7..263b439e21a8 100644 --- a/drivers/mtd/ubi/fastmap.c +++ b/drivers/mtd/ubi/fastmap.c @@ -450,7 +450,7 @@ static void unmap_peb(struct ubi_attach_info *ai, int pnum) * < 0 indicates an internal error. */ static int scan_pool(struct ubi_device *ubi, struct ubi_attach_info *ai, - int *pebs, int pool_size, unsigned long long *max_sqnum, + __be32 *pebs, int pool_size, unsigned long long *max_sqnum, struct list_head *free) { struct ubi_vid_hdr *vh; @@ -775,7 +775,7 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, for (j = 0; j < be32_to_cpu(fm_eba->reserved_pebs); j++) { int pnum = be32_to_cpu(fm_eba->pnum[j]); - if ((int)be32_to_cpu(fm_eba->pnum[j]) < 0) + if (pnum < 0) continue; aeb = NULL; diff --git a/drivers/mtd/ubi/ubi-media.h b/drivers/mtd/ubi/ubi-media.h index d0d072e7ccd2..22ed3f627506 100644 --- a/drivers/mtd/ubi/ubi-media.h +++ b/drivers/mtd/ubi/ubi-media.h @@ -500,7 +500,7 @@ struct ubi_fm_volhdr { /* struct ubi_fm_volhdr is followed by one struct ubi_fm_eba records */ /** - * struct ubi_fm_eba - denotes an association beween a PEB and LEB + * struct ubi_fm_eba - denotes an association between a PEB and LEB * @magic: EBA table magic number * @reserved_pebs: number of table entries * @pnum: PEB number of LEB (LEB is the index) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index b4351caf8e01..9e0f8a7ef8b1 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1749,6 +1749,7 @@ err_undo_flags: slave_dev->dev_addr)) eth_hw_addr_random(bond_dev); if (bond_dev->type != ARPHRD_ETHER) { + dev_close(bond_dev); ether_setup(bond_dev); bond_dev->flags |= IFF_MASTER; bond_dev->priv_flags &= ~IFF_TX_SKB_SHARING; diff --git a/drivers/net/caif/caif_spi.c b/drivers/net/caif/caif_spi.c index de3962014af7..4721948a92f6 100644 --- a/drivers/net/caif/caif_spi.c +++ b/drivers/net/caif/caif_spi.c @@ -730,11 +730,14 @@ int cfspi_spi_probe(struct platform_device *pdev) int res; dev = (struct cfspi_dev *)pdev->dev.platform_data; - ndev = alloc_netdev(sizeof(struct cfspi), "cfspi%d", - NET_NAME_UNKNOWN, cfspi_setup); if (!dev) return -ENODEV; + ndev = alloc_netdev(sizeof(struct cfspi), "cfspi%d", + NET_NAME_UNKNOWN, cfspi_setup); + if (!ndev) + return -ENOMEM; + cfspi = netdev_priv(ndev); netif_stop_queue(ndev); cfspi->ndev = ndev; diff --git a/drivers/net/dsa/mv88e6060.c b/drivers/net/dsa/mv88e6060.c index 9093577755f6..0527f485c3dc 100644 --- a/drivers/net/dsa/mv88e6060.c +++ b/drivers/net/dsa/mv88e6060.c @@ -15,9 +15,7 @@ #include <linux/netdevice.h> #include <linux/phy.h> #include <net/dsa.h> - -#define REG_PORT(p) (8 + (p)) -#define REG_GLOBAL 0x0f +#include "mv88e6060.h" static int reg_read(struct dsa_switch *ds, int addr, int reg) { @@ -67,13 +65,14 @@ static char *mv88e6060_probe(struct device *host_dev, int sw_addr) if (bus == NULL) return NULL; - ret = mdiobus_read(bus, sw_addr + REG_PORT(0), 0x03); + ret = mdiobus_read(bus, sw_addr + REG_PORT(0), PORT_SWITCH_ID); if (ret >= 0) { - if (ret == 0x0600) + if (ret == PORT_SWITCH_ID_6060) return "Marvell 88E6060 (A0)"; - if (ret == 0x0601 || ret == 0x0602) + if (ret == PORT_SWITCH_ID_6060_R1 || + ret == PORT_SWITCH_ID_6060_R2) return "Marvell 88E6060 (B0)"; - if ((ret & 0xfff0) == 0x0600) + if ((ret & PORT_SWITCH_ID_6060_MASK) == PORT_SWITCH_ID_6060) return "Marvell 88E6060"; } @@ -87,22 +86,26 @@ static int mv88e6060_switch_reset(struct dsa_switch *ds) unsigned long timeout; /* Set all ports to the disabled state. */ - for (i = 0; i < 6; i++) { - ret = REG_READ(REG_PORT(i), 0x04); - REG_WRITE(REG_PORT(i), 0x04, ret & 0xfffc); + for (i = 0; i < MV88E6060_PORTS; i++) { + ret = REG_READ(REG_PORT(i), PORT_CONTROL); + REG_WRITE(REG_PORT(i), PORT_CONTROL, + ret & ~PORT_CONTROL_STATE_MASK); } /* Wait for transmit queues to drain. */ usleep_range(2000, 4000); /* Reset the switch. */ - REG_WRITE(REG_GLOBAL, 0x0a, 0xa130); + REG_WRITE(REG_GLOBAL, GLOBAL_ATU_CONTROL, + GLOBAL_ATU_CONTROL_SWRESET | + GLOBAL_ATU_CONTROL_ATUSIZE_1024 | + GLOBAL_ATU_CONTROL_ATE_AGE_5MIN); /* Wait up to one second for reset to complete. */ timeout = jiffies + 1 * HZ; while (time_before(jiffies, timeout)) { - ret = REG_READ(REG_GLOBAL, 0x00); - if ((ret & 0x8000) == 0x0000) + ret = REG_READ(REG_GLOBAL, GLOBAL_STATUS); + if (ret & GLOBAL_STATUS_INIT_READY) break; usleep_range(1000, 2000); @@ -119,13 +122,15 @@ static int mv88e6060_setup_global(struct dsa_switch *ds) * set the maximum frame size to 1536 bytes, and mask all * interrupt sources. */ - REG_WRITE(REG_GLOBAL, 0x04, 0x0800); + REG_WRITE(REG_GLOBAL, GLOBAL_CONTROL, GLOBAL_CONTROL_MAX_FRAME_1536); /* Enable automatic address learning, set the address * database size to 1024 entries, and set the default aging * time to 5 minutes. */ - REG_WRITE(REG_GLOBAL, 0x0a, 0x2130); + REG_WRITE(REG_GLOBAL, GLOBAL_ATU_CONTROL, + GLOBAL_ATU_CONTROL_ATUSIZE_1024 | + GLOBAL_ATU_CONTROL_ATE_AGE_5MIN); return 0; } @@ -139,25 +144,30 @@ static int mv88e6060_setup_port(struct dsa_switch *ds, int p) * state to Forwarding. Additionally, if this is the CPU * port, enable Ingress and Egress Trailer tagging mode. */ - REG_WRITE(addr, 0x04, dsa_is_cpu_port(ds, p) ? 0x4103 : 0x0003); + REG_WRITE(addr, PORT_CONTROL, + dsa_is_cpu_port(ds, p) ? + PORT_CONTROL_TRAILER | + PORT_CONTROL_INGRESS_MODE | + PORT_CONTROL_STATE_FORWARDING : + PORT_CONTROL_STATE_FORWARDING); /* Port based VLAN map: give each port its own address * database, allow the CPU port to talk to each of the 'real' * ports, and allow each of the 'real' ports to only talk to * the CPU port. */ - REG_WRITE(addr, 0x06, - ((p & 0xf) << 12) | - (dsa_is_cpu_port(ds, p) ? - ds->phys_port_mask : - (1 << ds->dst->cpu_port))); + REG_WRITE(addr, PORT_VLAN_MAP, + ((p & 0xf) << PORT_VLAN_MAP_DBNUM_SHIFT) | + (dsa_is_cpu_port(ds, p) ? + ds->phys_port_mask : + BIT(ds->dst->cpu_port))); /* Port Association Vector: when learning source addresses * of packets, add the address to the address database using * a port bitmap that has only the bit for this port set and * the other bits clear. */ - REG_WRITE(addr, 0x0b, 1 << p); + REG_WRITE(addr, PORT_ASSOC_VECTOR, BIT(p)); return 0; } @@ -177,7 +187,7 @@ static int mv88e6060_setup(struct dsa_switch *ds) if (ret < 0) return ret; - for (i = 0; i < 6; i++) { + for (i = 0; i < MV88E6060_PORTS; i++) { ret = mv88e6060_setup_port(ds, i); if (ret < 0) return ret; @@ -188,16 +198,17 @@ static int mv88e6060_setup(struct dsa_switch *ds) static int mv88e6060_set_addr(struct dsa_switch *ds, u8 *addr) { - REG_WRITE(REG_GLOBAL, 0x01, (addr[0] << 8) | addr[1]); - REG_WRITE(REG_GLOBAL, 0x02, (addr[2] << 8) | addr[3]); - REG_WRITE(REG_GLOBAL, 0x03, (addr[4] << 8) | addr[5]); + /* Use the same MAC Address as FD Pause frames for all ports */ + REG_WRITE(REG_GLOBAL, GLOBAL_MAC_01, (addr[0] << 9) | addr[1]); + REG_WRITE(REG_GLOBAL, GLOBAL_MAC_23, (addr[2] << 8) | addr[3]); + REG_WRITE(REG_GLOBAL, GLOBAL_MAC_45, (addr[4] << 8) | addr[5]); return 0; } static int mv88e6060_port_to_phy_addr(int port) { - if (port >= 0 && port <= 5) + if (port >= 0 && port < MV88E6060_PORTS) return port; return -1; } @@ -225,54 +236,6 @@ mv88e6060_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val) return reg_write(ds, addr, regnum, val); } -static void mv88e6060_poll_link(struct dsa_switch *ds) -{ - int i; - - for (i = 0; i < DSA_MAX_PORTS; i++) { - struct net_device *dev; - int uninitialized_var(port_status); - int link; - int speed; - int duplex; - int fc; - - dev = ds->ports[i]; - if (dev == NULL) - continue; - - link = 0; - if (dev->flags & IFF_UP) { - port_status = reg_read(ds, REG_PORT(i), 0x00); - if (port_status < 0) - continue; - - link = !!(port_status & 0x1000); - } - - if (!link) { - if (netif_carrier_ok(dev)) { - netdev_info(dev, "link down\n"); - netif_carrier_off(dev); - } - continue; - } - - speed = (port_status & 0x0100) ? 100 : 10; - duplex = (port_status & 0x0200) ? 1 : 0; - fc = ((port_status & 0xc000) == 0xc000) ? 1 : 0; - - if (!netif_carrier_ok(dev)) { - netdev_info(dev, - "link up, %d Mb/s, %s duplex, flow control %sabled\n", - speed, - duplex ? "full" : "half", - fc ? "en" : "dis"); - netif_carrier_on(dev); - } - } -} - static struct dsa_switch_driver mv88e6060_switch_driver = { .tag_protocol = DSA_TAG_PROTO_TRAILER, .probe = mv88e6060_probe, @@ -280,7 +243,6 @@ static struct dsa_switch_driver mv88e6060_switch_driver = { .set_addr = mv88e6060_set_addr, .phy_read = mv88e6060_phy_read, .phy_write = mv88e6060_phy_write, - .poll_link = mv88e6060_poll_link, }; static int __init mv88e6060_init(void) diff --git a/drivers/net/dsa/mv88e6060.h b/drivers/net/dsa/mv88e6060.h new file mode 100644 index 000000000000..cc9b2ed4aff4 --- /dev/null +++ b/drivers/net/dsa/mv88e6060.h @@ -0,0 +1,111 @@ +/* + * drivers/net/dsa/mv88e6060.h - Marvell 88e6060 switch chip support + * Copyright (c) 2015 Neil Armstrong + * + * Based on mv88e6xxx.h + * Copyright (c) 2008 Marvell Semiconductor + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef __MV88E6060_H +#define __MV88E6060_H + +#define MV88E6060_PORTS 6 + +#define REG_PORT(p) (0x8 + (p)) +#define PORT_STATUS 0x00 +#define PORT_STATUS_PAUSE_EN BIT(15) +#define PORT_STATUS_MY_PAUSE BIT(14) +#define PORT_STATUS_FC (PORT_STATUS_MY_PAUSE | PORT_STATUS_PAUSE_EN) +#define PORT_STATUS_RESOLVED BIT(13) +#define PORT_STATUS_LINK BIT(12) +#define PORT_STATUS_PORTMODE BIT(11) +#define PORT_STATUS_PHYMODE BIT(10) +#define PORT_STATUS_DUPLEX BIT(9) +#define PORT_STATUS_SPEED BIT(8) +#define PORT_SWITCH_ID 0x03 +#define PORT_SWITCH_ID_6060 0x0600 +#define PORT_SWITCH_ID_6060_MASK 0xfff0 +#define PORT_SWITCH_ID_6060_R1 0x0601 +#define PORT_SWITCH_ID_6060_R2 0x0602 +#define PORT_CONTROL 0x04 +#define PORT_CONTROL_FORCE_FLOW_CTRL BIT(15) +#define PORT_CONTROL_TRAILER BIT(14) +#define PORT_CONTROL_HEADER BIT(11) +#define PORT_CONTROL_INGRESS_MODE BIT(8) +#define PORT_CONTROL_VLAN_TUNNEL BIT(7) +#define PORT_CONTROL_STATE_MASK 0x03 +#define PORT_CONTROL_STATE_DISABLED 0x00 +#define PORT_CONTROL_STATE_BLOCKING 0x01 +#define PORT_CONTROL_STATE_LEARNING 0x02 +#define PORT_CONTROL_STATE_FORWARDING 0x03 +#define PORT_VLAN_MAP 0x06 +#define PORT_VLAN_MAP_DBNUM_SHIFT 12 +#define PORT_VLAN_MAP_TABLE_MASK 0x1f +#define PORT_ASSOC_VECTOR 0x0b +#define PORT_ASSOC_VECTOR_MONITOR BIT(15) +#define PORT_ASSOC_VECTOR_PAV_MASK 0x1f +#define PORT_RX_CNTR 0x10 +#define PORT_TX_CNTR 0x11 + +#define REG_GLOBAL 0x0f +#define GLOBAL_STATUS 0x00 +#define GLOBAL_STATUS_SW_MODE_MASK (0x3 << 12) +#define GLOBAL_STATUS_SW_MODE_0 (0x0 << 12) +#define GLOBAL_STATUS_SW_MODE_1 (0x1 << 12) +#define GLOBAL_STATUS_SW_MODE_2 (0x2 << 12) +#define GLOBAL_STATUS_SW_MODE_3 (0x3 << 12) +#define GLOBAL_STATUS_INIT_READY BIT(11) +#define GLOBAL_STATUS_ATU_FULL BIT(3) +#define GLOBAL_STATUS_ATU_DONE BIT(2) +#define GLOBAL_STATUS_PHY_INT BIT(1) +#define GLOBAL_STATUS_EEINT BIT(0) +#define GLOBAL_MAC_01 0x01 +#define GLOBAL_MAC_01_DIFF_ADDR BIT(8) +#define GLOBAL_MAC_23 0x02 +#define GLOBAL_MAC_45 0x03 +#define GLOBAL_CONTROL 0x04 +#define GLOBAL_CONTROL_DISCARD_EXCESS BIT(13) +#define GLOBAL_CONTROL_MAX_FRAME_1536 BIT(10) +#define GLOBAL_CONTROL_RELOAD_EEPROM BIT(9) +#define GLOBAL_CONTROL_CTRMODE BIT(8) +#define GLOBAL_CONTROL_ATU_FULL_EN BIT(3) +#define GLOBAL_CONTROL_ATU_DONE_EN BIT(2) +#define GLOBAL_CONTROL_PHYINT_EN BIT(1) +#define GLOBAL_CONTROL_EEPROM_DONE_EN BIT(0) +#define GLOBAL_ATU_CONTROL 0x0a +#define GLOBAL_ATU_CONTROL_SWRESET BIT(15) +#define GLOBAL_ATU_CONTROL_LEARNDIS BIT(14) +#define GLOBAL_ATU_CONTROL_ATUSIZE_256 (0x0 << 12) +#define GLOBAL_ATU_CONTROL_ATUSIZE_512 (0x1 << 12) +#define GLOBAL_ATU_CONTROL_ATUSIZE_1024 (0x2 << 12) +#define GLOBAL_ATU_CONTROL_ATE_AGE_SHIFT 4 +#define GLOBAL_ATU_CONTROL_ATE_AGE_MASK (0xff << 4) +#define GLOBAL_ATU_CONTROL_ATE_AGE_5MIN (0x13 << 4) +#define GLOBAL_ATU_OP 0x0b +#define GLOBAL_ATU_OP_BUSY BIT(15) +#define GLOBAL_ATU_OP_NOP (0 << 12) +#define GLOBAL_ATU_OP_FLUSH_ALL ((1 << 12) | GLOBAL_ATU_OP_BUSY) +#define GLOBAL_ATU_OP_FLUSH_UNLOCKED ((2 << 12) | GLOBAL_ATU_OP_BUSY) +#define GLOBAL_ATU_OP_LOAD_DB ((3 << 12) | GLOBAL_ATU_OP_BUSY) +#define GLOBAL_ATU_OP_GET_NEXT_DB ((4 << 12) | GLOBAL_ATU_OP_BUSY) +#define GLOBAL_ATU_OP_FLUSH_DB ((5 << 12) | GLOBAL_ATU_OP_BUSY) +#define GLOBAL_ATU_OP_FLUSH_UNLOCKED_DB ((6 << 12) | GLOBAL_ATU_OP_BUSY) +#define GLOBAL_ATU_DATA 0x0c +#define GLOBAL_ATU_DATA_PORT_VECTOR_MASK 0x3f0 +#define GLOBAL_ATU_DATA_PORT_VECTOR_SHIFT 4 +#define GLOBAL_ATU_DATA_STATE_MASK 0x0f +#define GLOBAL_ATU_DATA_STATE_UNUSED 0x00 +#define GLOBAL_ATU_DATA_STATE_UC_STATIC 0x0e +#define GLOBAL_ATU_DATA_STATE_UC_LOCKED 0x0f +#define GLOBAL_ATU_DATA_STATE_MC_STATIC 0x07 +#define GLOBAL_ATU_DATA_STATE_MC_LOCKED 0x0e +#define GLOBAL_ATU_MAC_01 0x0d +#define GLOBAL_ATU_MAC_23 0x0e +#define GLOBAL_ATU_MAC_45 0x0f + +#endif diff --git a/drivers/net/dsa/mv88e6171.c b/drivers/net/dsa/mv88e6171.c index 54aa00012dd0..6e18213b9c04 100644 --- a/drivers/net/dsa/mv88e6171.c +++ b/drivers/net/dsa/mv88e6171.c @@ -103,6 +103,8 @@ struct dsa_switch_driver mv88e6171_switch_driver = { #endif .get_regs_len = mv88e6xxx_get_regs_len, .get_regs = mv88e6xxx_get_regs, + .port_join_bridge = mv88e6xxx_port_bridge_join, + .port_leave_bridge = mv88e6xxx_port_bridge_leave, .port_stp_update = mv88e6xxx_port_stp_update, .port_pvid_get = mv88e6xxx_port_pvid_get, .port_vlan_prepare = mv88e6xxx_port_vlan_prepare, diff --git a/drivers/net/dsa/mv88e6352.c b/drivers/net/dsa/mv88e6352.c index ff846d0cfceb..cc6c54553418 100644 --- a/drivers/net/dsa/mv88e6352.c +++ b/drivers/net/dsa/mv88e6352.c @@ -323,6 +323,8 @@ struct dsa_switch_driver mv88e6352_switch_driver = { .set_eeprom = mv88e6352_set_eeprom, .get_regs_len = mv88e6xxx_get_regs_len, .get_regs = mv88e6xxx_get_regs, + .port_join_bridge = mv88e6xxx_port_bridge_join, + .port_leave_bridge = mv88e6xxx_port_bridge_leave, .port_stp_update = mv88e6xxx_port_stp_update, .port_pvid_get = mv88e6xxx_port_pvid_get, .port_vlan_prepare = mv88e6xxx_port_vlan_prepare, diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index 04cff58d771b..b06dba05594a 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -1462,6 +1462,10 @@ int mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port, const struct switchdev_obj_port_vlan *vlan, struct switchdev_trans *trans) { + /* We reserve a few VLANs to isolate unbridged ports */ + if (vlan->vid_end >= 4000) + return -EOPNOTSUPP; + /* We don't need any dynamic resource from the kernel (yet), * so skip the prepare phase. */ @@ -1870,6 +1874,36 @@ unlock: return err; } +int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port, u32 members) +{ + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); + const u16 pvid = 4000 + ds->index * DSA_MAX_PORTS + port; + int err; + + /* The port joined a bridge, so leave its reserved VLAN */ + mutex_lock(&ps->smi_mutex); + err = _mv88e6xxx_port_vlan_del(ds, port, pvid); + if (!err) + err = _mv88e6xxx_port_pvid_set(ds, port, 0); + mutex_unlock(&ps->smi_mutex); + return err; +} + +int mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port, u32 members) +{ + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); + const u16 pvid = 4000 + ds->index * DSA_MAX_PORTS + port; + int err; + + /* The port left the bridge, so join its reserved VLAN */ + mutex_lock(&ps->smi_mutex); + err = _mv88e6xxx_port_vlan_add(ds, port, pvid, true); + if (!err) + err = _mv88e6xxx_port_pvid_set(ds, port, pvid); + mutex_unlock(&ps->smi_mutex); + return err; +} + static void mv88e6xxx_bridge_work(struct work_struct *work) { struct mv88e6xxx_priv_state *ps; @@ -2140,6 +2174,14 @@ int mv88e6xxx_setup_ports(struct dsa_switch *ds) ret = mv88e6xxx_setup_port(ds, i); if (ret < 0) return ret; + + if (dsa_is_cpu_port(ds, i) || dsa_is_dsa_port(ds, i)) + continue; + + /* setup the unbridged state */ + ret = mv88e6xxx_port_bridge_leave(ds, i, 0); + if (ret < 0) + return ret; } return 0; } diff --git a/drivers/net/dsa/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx.h index fb9a8739712f..21c8daa03f78 100644 --- a/drivers/net/dsa/mv88e6xxx.h +++ b/drivers/net/dsa/mv88e6xxx.h @@ -468,6 +468,8 @@ int mv88e6xxx_phy_write_indirect(struct dsa_switch *ds, int addr, int regnum, int mv88e6xxx_get_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e); int mv88e6xxx_set_eee(struct dsa_switch *ds, int port, struct phy_device *phydev, struct ethtool_eee *e); +int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port, u32 members); +int mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port, u32 members); int mv88e6xxx_port_stp_update(struct dsa_switch *ds, int port, u8 state); int mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port, const struct switchdev_obj_port_vlan *vlan, diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig index 05aa7597dab9..955d06b9cdba 100644 --- a/drivers/net/ethernet/Kconfig +++ b/drivers/net/ethernet/Kconfig @@ -78,7 +78,6 @@ source "drivers/net/ethernet/ibm/Kconfig" source "drivers/net/ethernet/intel/Kconfig" source "drivers/net/ethernet/i825xx/Kconfig" source "drivers/net/ethernet/xscale/Kconfig" -source "drivers/net/ethernet/icplus/Kconfig" config JME tristate "JMicron(R) PCI-Express Gigabit Ethernet support" diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile index ddfc808110a1..4a2ee98738f0 100644 --- a/drivers/net/ethernet/Makefile +++ b/drivers/net/ethernet/Makefile @@ -41,7 +41,6 @@ obj-$(CONFIG_NET_VENDOR_IBM) += ibm/ obj-$(CONFIG_NET_VENDOR_INTEL) += intel/ obj-$(CONFIG_NET_VENDOR_I825XX) += i825xx/ obj-$(CONFIG_NET_VENDOR_XSCALE) += xscale/ -obj-$(CONFIG_IP1000) += icplus/ obj-$(CONFIG_JME) += jme.o obj-$(CONFIG_KORINA) += korina.o obj-$(CONFIG_LANTIQ_ETOP) += lantiq_etop.o diff --git a/drivers/net/ethernet/amd/pcnet32.c b/drivers/net/ethernet/amd/pcnet32.c index bc8b04f42882..7ccebae9cb48 100644 --- a/drivers/net/ethernet/amd/pcnet32.c +++ b/drivers/net/ethernet/amd/pcnet32.c @@ -1500,10 +1500,11 @@ pcnet32_probe_pci(struct pci_dev *pdev, const struct pci_device_id *ent) return -ENODEV; } - if (!pci_dma_supported(pdev, PCNET32_DMA_MASK)) { + err = pci_set_dma_mask(pdev, PCNET32_DMA_MASK); + if (err) { if (pcnet32_debug & NETIF_MSG_PROBE) pr_err("architecture does not support 32bit PCI busmaster DMA\n"); - return -ENODEV; + return err; } if (!request_region(ioaddr, PCNET32_TOTAL_SIZE, "pcnet32_probe_pci")) { if (pcnet32_debug & NETIF_MSG_PROBE) diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-main.c b/drivers/net/ethernet/amd/xgbe/xgbe-main.c index 7dd893331785..618d952c2984 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-main.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-main.c @@ -342,6 +342,7 @@ static int xgbe_probe(struct platform_device *pdev) struct resource *res; const char *phy_mode; unsigned int i, phy_memnum, phy_irqnum; + enum dev_dma_attr attr; int ret; DBGPR("--> xgbe_probe\n"); @@ -609,7 +610,12 @@ static int xgbe_probe(struct platform_device *pdev) goto err_io; /* Set the DMA coherency values */ - pdata->coherent = device_dma_is_coherent(pdata->dev); + attr = device_get_dma_attr(dev); + if (attr == DEV_DMA_NOT_SUPPORTED) { + dev_err(dev, "DMA is not supported"); + goto err_io; + } + pdata->coherent = (attr == DEV_DMA_COHERENT); if (pdata->coherent) { pdata->axdomain = XGBE_DMA_OS_AXDOMAIN; pdata->arcache = XGBE_DMA_OS_ARCACHE; diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c index 33850a0f7e82..c31e691d11fc 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c @@ -459,6 +459,45 @@ static void xgene_gmac_reset(struct xgene_enet_pdata *pdata) xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, 0); } +static void xgene_enet_configure_clock(struct xgene_enet_pdata *pdata) +{ + struct device *dev = &pdata->pdev->dev; + + if (dev->of_node) { + struct clk *parent = clk_get_parent(pdata->clk); + + switch (pdata->phy_speed) { + case SPEED_10: + clk_set_rate(parent, 2500000); + break; + case SPEED_100: + clk_set_rate(parent, 25000000); + break; + default: + clk_set_rate(parent, 125000000); + break; + } + } +#ifdef CONFIG_ACPI + else { + switch (pdata->phy_speed) { + case SPEED_10: + acpi_evaluate_object(ACPI_HANDLE(dev), + "S10", NULL, NULL); + break; + case SPEED_100: + acpi_evaluate_object(ACPI_HANDLE(dev), + "S100", NULL, NULL); + break; + default: + acpi_evaluate_object(ACPI_HANDLE(dev), + "S1G", NULL, NULL); + break; + } + } +#endif +} + static void xgene_gmac_init(struct xgene_enet_pdata *pdata) { struct device *dev = &pdata->pdev->dev; @@ -477,12 +516,14 @@ static void xgene_gmac_init(struct xgene_enet_pdata *pdata) switch (pdata->phy_speed) { case SPEED_10: ENET_INTERFACE_MODE2_SET(&mc2, 1); + intf_ctl &= ~(ENET_LHD_MODE | ENET_GHD_MODE); CFG_MACMODE_SET(&icm0, 0); CFG_WAITASYNCRD_SET(&icm2, 500); rgmii &= ~CFG_SPEED_1250; break; case SPEED_100: ENET_INTERFACE_MODE2_SET(&mc2, 1); + intf_ctl &= ~ENET_GHD_MODE; intf_ctl |= ENET_LHD_MODE; CFG_MACMODE_SET(&icm0, 1); CFG_WAITASYNCRD_SET(&icm2, 80); @@ -490,12 +531,15 @@ static void xgene_gmac_init(struct xgene_enet_pdata *pdata) break; default: ENET_INTERFACE_MODE2_SET(&mc2, 2); + intf_ctl &= ~ENET_LHD_MODE; intf_ctl |= ENET_GHD_MODE; - + CFG_MACMODE_SET(&icm0, 2); + CFG_WAITASYNCRD_SET(&icm2, 0); if (dev->of_node) { CFG_TXCLK_MUXSEL0_SET(&rgmii, pdata->tx_delay); CFG_RXCLK_MUXSEL0_SET(&rgmii, pdata->rx_delay); } + rgmii |= CFG_SPEED_1250; xgene_enet_rd_csr(pdata, DEBUG_REG_ADDR, &value); value |= CFG_BYPASS_UNISEC_TX | CFG_BYPASS_UNISEC_RX; @@ -503,7 +547,7 @@ static void xgene_gmac_init(struct xgene_enet_pdata *pdata) break; } - mc2 |= FULL_DUPLEX2; + mc2 |= FULL_DUPLEX2 | PAD_CRC; xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_2_ADDR, mc2); xgene_enet_wr_mcx_mac(pdata, INTERFACE_CONTROL_ADDR, intf_ctl); @@ -522,6 +566,7 @@ static void xgene_gmac_init(struct xgene_enet_pdata *pdata) /* Rtype should be copied from FP */ xgene_enet_wr_csr(pdata, RSIF_RAM_DBG_REG0_ADDR, 0); xgene_enet_wr_csr(pdata, RGMII_REG_0_ADDR, rgmii); + xgene_enet_configure_clock(pdata); /* Rx-Tx traffic resume */ xgene_enet_wr_csr(pdata, CFG_LINK_AGGR_RESUME_0_ADDR, TX_PORT0); diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h index 6dee73c3c1e1..c153a1dc5ff7 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h @@ -181,6 +181,7 @@ enum xgene_enet_rm { #define ENET_LHD_MODE BIT(25) #define ENET_GHD_MODE BIT(26) #define FULL_DUPLEX2 BIT(0) +#define PAD_CRC BIT(2) #define SCAN_AUTO_INCR BIT(5) #define TBYT_ADDR 0x38 #define TPKT_ADDR 0x39 diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c index ce1068771b32..991412ce6f48 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c @@ -698,7 +698,6 @@ static int xgene_enet_open(struct net_device *ndev) else schedule_delayed_work(&pdata->link_work, PHY_POLL_LINK_OFF); - netif_carrier_off(ndev); netif_start_queue(ndev); return ret; diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/broadcom/Kconfig index 67a7d520d9f5..8550df189ceb 100644 --- a/drivers/net/ethernet/broadcom/Kconfig +++ b/drivers/net/ethernet/broadcom/Kconfig @@ -173,6 +173,7 @@ config SYSTEMPORT config BNXT tristate "Broadcom NetXtreme-C/E support" depends on PCI + depends on VXLAN || VXLAN=n select FW_LOADER select LIBCRC32C ---help--- diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index f1d62d5dbaff..c9b036789184 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -13207,7 +13207,7 @@ static int bnx2x_init_dev(struct bnx2x *bp, struct pci_dev *pdev, /* VF with OLD Hypervisor or old PF do not support filtering */ if (IS_PF(bp)) { - if (CHIP_IS_E1x(bp)) + if (chip_is_e1x) bp->accept_any_vlan = true; else dev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 6c2e0c622831..db15c5ee09c5 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -1292,8 +1292,6 @@ static inline int bnxt_has_work(struct bnxt *bp, struct bnxt_cp_ring_info *cpr) return TX_CMP_VALID(txcmp, raw_cons); } -#define CAG_LEGACY_INT_STATUS 0x2014 - static irqreturn_t bnxt_inta(int irq, void *dev_instance) { struct bnxt_napi *bnapi = dev_instance; @@ -1305,7 +1303,7 @@ static irqreturn_t bnxt_inta(int irq, void *dev_instance) prefetch(&cpr->cp_desc_ring[CP_RING(cons)][CP_IDX(cons)]); if (!bnxt_has_work(bp, cpr)) { - int_status = readl(bp->bar0 + CAG_LEGACY_INT_STATUS); + int_status = readl(bp->bar0 + BNXT_CAG_REG_LEGACY_INT_STATUS); /* return if erroneous interrupt */ if (!(int_status & (0x10000 << cpr->cp_ring_struct.fw_ring_id))) return IRQ_NONE; @@ -4527,10 +4525,25 @@ static int bnxt_update_phy_setting(struct bnxt *bp) return rc; } +/* Common routine to pre-map certain register block to different GRC window. + * A PF has 16 4K windows and a VF has 4 4K windows. However, only 15 windows + * in PF and 3 windows in VF that can be customized to map in different + * register blocks. + */ +static void bnxt_preset_reg_win(struct bnxt *bp) +{ + if (BNXT_PF(bp)) { + /* CAG registers map to GRC window #4 */ + writel(BNXT_CAG_REG_BASE, + bp->bar0 + BNXT_GRCPF_REG_WINDOW_BASE_OUT + 12); + } +} + static int __bnxt_open_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init) { int rc = 0; + bnxt_preset_reg_win(bp); netif_carrier_off(bp->dev); if (irq_re_init) { rc = bnxt_setup_int_mode(bp); @@ -5294,7 +5307,7 @@ static int bnxt_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb, struct bnxt_ntuple_filter *fltr, *new_fltr; struct flow_keys *fkeys; struct ethhdr *eth = (struct ethhdr *)skb_mac_header(skb); - int rc = 0, idx; + int rc = 0, idx, bit_id; struct hlist_head *head; if (skb->encapsulation) @@ -5332,14 +5345,15 @@ static int bnxt_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb, rcu_read_unlock(); spin_lock_bh(&bp->ntp_fltr_lock); - new_fltr->sw_id = bitmap_find_free_region(bp->ntp_fltr_bmap, - BNXT_NTP_FLTR_MAX_FLTR, 0); - if (new_fltr->sw_id < 0) { + bit_id = bitmap_find_free_region(bp->ntp_fltr_bmap, + BNXT_NTP_FLTR_MAX_FLTR, 0); + if (bit_id < 0) { spin_unlock_bh(&bp->ntp_fltr_lock); rc = -ENOMEM; goto err_free; } + new_fltr->sw_id = (u16)bit_id; new_fltr->flow_id = flow_id; new_fltr->rxq = rxq_index; hlist_add_head_rcu(&new_fltr->hash, head); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 4f2267ca482d..674bc5159b91 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -166,9 +166,11 @@ struct rx_cmp { #define RX_CMP_HASH_VALID(rxcmp) \ ((rxcmp)->rx_cmp_len_flags_type & cpu_to_le32(RX_CMP_FLAGS_RSS_VALID)) +#define RSS_PROFILE_ID_MASK 0x1f + #define RX_CMP_HASH_TYPE(rxcmp) \ - ((le32_to_cpu((rxcmp)->rx_cmp_misc_v1) & RX_CMP_RSS_HASH_TYPE) >>\ - RX_CMP_RSS_HASH_TYPE_SHIFT) + (((le32_to_cpu((rxcmp)->rx_cmp_misc_v1) & RX_CMP_RSS_HASH_TYPE) >>\ + RX_CMP_RSS_HASH_TYPE_SHIFT) & RSS_PROFILE_ID_MASK) struct rx_cmp_ext { __le32 rx_cmp_flags2; @@ -282,9 +284,9 @@ struct rx_tpa_start_cmp { cpu_to_le32(RX_TPA_START_CMP_FLAGS_RSS_VALID)) #define TPA_START_HASH_TYPE(rx_tpa_start) \ - ((le32_to_cpu((rx_tpa_start)->rx_tpa_start_cmp_misc_v1) & \ - RX_TPA_START_CMP_RSS_HASH_TYPE) >> \ - RX_TPA_START_CMP_RSS_HASH_TYPE_SHIFT) + (((le32_to_cpu((rx_tpa_start)->rx_tpa_start_cmp_misc_v1) & \ + RX_TPA_START_CMP_RSS_HASH_TYPE) >> \ + RX_TPA_START_CMP_RSS_HASH_TYPE_SHIFT) & RSS_PROFILE_ID_MASK) #define TPA_START_AGG_ID(rx_tpa_start) \ ((le32_to_cpu((rx_tpa_start)->rx_tpa_start_cmp_misc_v1) & \ @@ -839,6 +841,10 @@ struct bnxt_queue_info { u8 queue_profile; }; +#define BNXT_GRCPF_REG_WINDOW_BASE_OUT 0x400 +#define BNXT_CAG_REG_LEGACY_INT_STATUS 0x4014 +#define BNXT_CAG_REG_BASE 0x300000 + struct bnxt { void __iomem *bar0; void __iomem *bar1; @@ -959,11 +965,11 @@ struct bnxt { #define BNXT_RX_MASK_SP_EVENT 0 #define BNXT_RX_NTP_FLTR_SP_EVENT 1 #define BNXT_LINK_CHNG_SP_EVENT 2 -#define BNXT_HWRM_EXEC_FWD_REQ_SP_EVENT 4 -#define BNXT_VXLAN_ADD_PORT_SP_EVENT 8 -#define BNXT_VXLAN_DEL_PORT_SP_EVENT 16 -#define BNXT_RESET_TASK_SP_EVENT 32 -#define BNXT_RST_RING_SP_EVENT 64 +#define BNXT_HWRM_EXEC_FWD_REQ_SP_EVENT 3 +#define BNXT_VXLAN_ADD_PORT_SP_EVENT 4 +#define BNXT_VXLAN_DEL_PORT_SP_EVENT 5 +#define BNXT_RESET_TASK_SP_EVENT 6 +#define BNXT_RST_RING_SP_EVENT 7 struct bnxt_pf_info pf; #ifdef CONFIG_BNXT_SRIOV diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c index 60989e7e266a..f4cf68861069 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c @@ -258,7 +258,7 @@ static int bnxt_set_vf_attr(struct bnxt *bp, int num_vfs) return 0; } -static int bnxt_hwrm_func_vf_resource_free(struct bnxt *bp) +static int bnxt_hwrm_func_vf_resource_free(struct bnxt *bp, int num_vfs) { int i, rc = 0; struct bnxt_pf_info *pf = &bp->pf; @@ -267,7 +267,7 @@ static int bnxt_hwrm_func_vf_resource_free(struct bnxt *bp) bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_VF_RESC_FREE, -1, -1); mutex_lock(&bp->hwrm_cmd_lock); - for (i = pf->first_vf_id; i < pf->first_vf_id + pf->active_vfs; i++) { + for (i = pf->first_vf_id; i < pf->first_vf_id + num_vfs; i++) { req.vf_id = cpu_to_le16(i); rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); @@ -509,7 +509,7 @@ static int bnxt_sriov_enable(struct bnxt *bp, int *num_vfs) err_out2: /* Free the resources reserved for various VF's */ - bnxt_hwrm_func_vf_resource_free(bp); + bnxt_hwrm_func_vf_resource_free(bp, *num_vfs); err_out1: bnxt_free_vf_resources(bp); @@ -519,13 +519,19 @@ err_out1: void bnxt_sriov_disable(struct bnxt *bp) { - if (!bp->pf.active_vfs) - return; + u16 num_vfs = pci_num_vf(bp->pdev); - pci_disable_sriov(bp->pdev); + if (!num_vfs) + return; - /* Free the resources reserved for various VF's */ - bnxt_hwrm_func_vf_resource_free(bp); + if (pci_vfs_assigned(bp->pdev)) { + netdev_warn(bp->dev, "Unable to free %d VFs because some are assigned to VMs.\n", + num_vfs); + } else { + pci_disable_sriov(bp->pdev); + /* Free the HW resources reserved for various VF's */ + bnxt_hwrm_func_vf_resource_free(bp, num_vfs); + } bnxt_free_vf_resources(bp); @@ -552,17 +558,25 @@ int bnxt_sriov_configure(struct pci_dev *pdev, int num_vfs) } bp->sriov_cfg = true; rtnl_unlock(); - if (!num_vfs) { - bnxt_sriov_disable(bp); - return 0; + + if (pci_vfs_assigned(bp->pdev)) { + netdev_warn(dev, "Unable to configure SRIOV since some VFs are assigned to VMs.\n"); + num_vfs = 0; + goto sriov_cfg_exit; } /* Check if enabled VFs is same as requested */ - if (num_vfs == bp->pf.active_vfs) - return 0; + if (num_vfs && num_vfs == bp->pf.active_vfs) + goto sriov_cfg_exit; + + /* if there are previous existing VFs, clean them up */ + bnxt_sriov_disable(bp); + if (!num_vfs) + goto sriov_cfg_exit; bnxt_sriov_enable(bp, &num_vfs); +sriov_cfg_exit: bp->sriov_cfg = false; wake_up(&bp->sriov_cfg_wait); diff --git a/drivers/net/ethernet/cavium/liquidio/lio_main.c b/drivers/net/ethernet/cavium/liquidio/lio_main.c index f683d97d7614..b89504405b72 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_main.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_main.c @@ -560,7 +560,7 @@ static int liquidio_resume(struct pci_dev *pdev) #endif /* For PCI-E Advanced Error Recovery (AER) Interface */ -static struct pci_error_handlers liquidio_err_handler = { +static const struct pci_error_handlers liquidio_err_handler = { .error_detected = liquidio_pcie_error_detected, .mmio_enabled = liquidio_pcie_mmio_enabled, .slot_reset = liquidio_pcie_slot_reset, diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_main.c b/drivers/net/ethernet/cavium/thunder/nicvf_main.c index a9377727c11c..7f709cbdcd87 100644 --- a/drivers/net/ethernet/cavium/thunder/nicvf_main.c +++ b/drivers/net/ethernet/cavium/thunder/nicvf_main.c @@ -1583,8 +1583,14 @@ err_disable_device: static void nicvf_remove(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); - struct nicvf *nic = netdev_priv(netdev); - struct net_device *pnetdev = nic->pnicvf->netdev; + struct nicvf *nic; + struct net_device *pnetdev; + + if (!netdev) + return; + + nic = netdev_priv(netdev); + pnetdev = nic->pnicvf->netdev; /* Check if this Qset is assigned to different VF. * If yes, clean primary and all secondary Qsets. diff --git a/drivers/net/ethernet/dlink/Kconfig b/drivers/net/ethernet/dlink/Kconfig index f6e858d0b9d4..ebdc83247bb6 100644 --- a/drivers/net/ethernet/dlink/Kconfig +++ b/drivers/net/ethernet/dlink/Kconfig @@ -17,15 +17,16 @@ config NET_VENDOR_DLINK if NET_VENDOR_DLINK config DL2K - tristate "DL2000/TC902x-based Gigabit Ethernet support" + tristate "DL2000/TC902x/IP1000A-based Gigabit Ethernet support" depends on PCI select CRC32 ---help--- - This driver supports DL2000/TC902x-based Gigabit ethernet cards, + This driver supports DL2000/TC902x/IP1000A-based Gigabit ethernet cards, which includes D-Link DGE-550T Gigabit Ethernet Adapter. D-Link DL2000-based Gigabit Ethernet Adapter. Sundance/Tamarack TC902x Gigabit Ethernet Adapter. + ICPlus IP1000A-based cards To compile this driver as a module, choose M here: the module will be called dl2k. diff --git a/drivers/net/ethernet/dlink/dl2k.c b/drivers/net/ethernet/dlink/dl2k.c index cf0a5fcdaaaf..ccca4799c27b 100644 --- a/drivers/net/ethernet/dlink/dl2k.c +++ b/drivers/net/ethernet/dlink/dl2k.c @@ -253,6 +253,19 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent) if (err) goto err_out_unmap_rx; + if (np->chip_id == CHIP_IP1000A && + (np->pdev->revision == 0x40 || np->pdev->revision == 0x41)) { + /* PHY magic taken from ipg driver, undocumented registers */ + mii_write(dev, np->phy_addr, 31, 0x0001); + mii_write(dev, np->phy_addr, 27, 0x01e0); + mii_write(dev, np->phy_addr, 31, 0x0002); + mii_write(dev, np->phy_addr, 27, 0xeb8e); + mii_write(dev, np->phy_addr, 31, 0x0000); + mii_write(dev, np->phy_addr, 30, 0x005e); + /* advertise 1000BASE-T half & full duplex, prefer MASTER */ + mii_write(dev, np->phy_addr, MII_CTRL1000, 0x0700); + } + /* Fiber device? */ np->phy_media = (dr16(ASICCtrl) & PhyMedia) ? 1 : 0; np->link_status = 0; @@ -361,6 +374,11 @@ parse_eeprom (struct net_device *dev) for (i = 0; i < 6; i++) dev->dev_addr[i] = psrom->mac_addr[i]; + if (np->chip_id == CHIP_IP1000A) { + np->led_mode = psrom->led_mode; + return 0; + } + if (np->pdev->vendor != PCI_VENDOR_ID_DLINK) { return 0; } @@ -406,6 +424,28 @@ parse_eeprom (struct net_device *dev) return 0; } +static void rio_set_led_mode(struct net_device *dev) +{ + struct netdev_private *np = netdev_priv(dev); + void __iomem *ioaddr = np->ioaddr; + u32 mode; + + if (np->chip_id != CHIP_IP1000A) + return; + + mode = dr32(ASICCtrl); + mode &= ~(IPG_AC_LED_MODE_BIT_1 | IPG_AC_LED_MODE | IPG_AC_LED_SPEED); + + if (np->led_mode & 0x01) + mode |= IPG_AC_LED_MODE; + if (np->led_mode & 0x02) + mode |= IPG_AC_LED_MODE_BIT_1; + if (np->led_mode & 0x08) + mode |= IPG_AC_LED_SPEED; + + dw32(ASICCtrl, mode); +} + static int rio_open (struct net_device *dev) { @@ -424,6 +464,8 @@ rio_open (struct net_device *dev) GlobalReset | DMAReset | FIFOReset | NetworkReset | HostReset); mdelay(10); + rio_set_led_mode(dev); + /* DebugCtrl bit 4, 5, 9 must set */ dw32(DebugCtrl, dr32(DebugCtrl) | 0x0230); @@ -433,9 +475,13 @@ rio_open (struct net_device *dev) alloc_list (dev); - /* Get station address */ - for (i = 0; i < 6; i++) - dw8(StationAddr0 + i, dev->dev_addr[i]); + /* Set station address */ + /* 16 or 32-bit access is required by TC9020 datasheet but 8-bit works + * too. However, it doesn't work on IP1000A so we use 16-bit access. + */ + for (i = 0; i < 3; i++) + dw16(StationAddr0 + 2 * i, + cpu_to_le16(((u16 *)dev->dev_addr)[i])); set_multicast (dev); if (np->coalesce) { @@ -780,6 +826,7 @@ tx_error (struct net_device *dev, int tx_status) break; mdelay (1); } + rio_set_led_mode(dev); rio_free_tx (dev, 1); /* Reset TFDListPtr */ dw32(TFDListPtr0, np->tx_ring_dma + @@ -799,6 +846,7 @@ tx_error (struct net_device *dev, int tx_status) break; mdelay (1); } + rio_set_led_mode(dev); /* Let TxStartThresh stay default value */ } /* Maximum Collisions */ @@ -965,6 +1013,7 @@ rio_error (struct net_device *dev, int int_status) dev->name, int_status); dw16(ASICCtrl + 2, GlobalReset | HostReset); mdelay (500); + rio_set_led_mode(dev); } } diff --git a/drivers/net/ethernet/dlink/dl2k.h b/drivers/net/ethernet/dlink/dl2k.h index 23c07b007069..8f4f61262d5c 100644 --- a/drivers/net/ethernet/dlink/dl2k.h +++ b/drivers/net/ethernet/dlink/dl2k.h @@ -211,6 +211,10 @@ enum ASICCtrl_HiWord_bits { ResetBusy = 0x0400, }; +#define IPG_AC_LED_MODE BIT(14) +#define IPG_AC_LED_SPEED BIT(27) +#define IPG_AC_LED_MODE_BIT_1 BIT(29) + /* Transmit Frame Control bits */ enum TFC_bits { DwordAlign = 0x00000000, @@ -332,7 +336,10 @@ typedef struct t_SROM { u16 asic_ctrl; /* 0x02 */ u16 sub_vendor_id; /* 0x04 */ u16 sub_system_id; /* 0x06 */ - u16 reserved1[12]; /* 0x08-0x1f */ + u16 pci_base_1; /* 0x08 (IP1000A only) */ + u16 pci_base_2; /* 0x0a (IP1000A only) */ + u16 led_mode; /* 0x0c (IP1000A only) */ + u16 reserved1[9]; /* 0x0e-0x1f */ u8 mac_addr[6]; /* 0x20-0x25 */ u8 reserved2[10]; /* 0x26-0x2f */ u8 sib[204]; /* 0x30-0xfb */ @@ -397,6 +404,7 @@ struct netdev_private { u16 advertising; /* NWay media advertisement */ u16 negotiate; /* Negotiated media */ int phy_addr; /* PHY addresses. */ + u16 led_mode; /* LED mode read from EEPROM (IP1000A only) */ }; /* The station address location in the EEPROM. */ @@ -407,10 +415,15 @@ struct netdev_private { class_mask of the class are honored during the comparison. driver_data Data private to the driver. */ +#define CHIP_IP1000A 1 static const struct pci_device_id rio_pci_tbl[] = { {0x1186, 0x4000, PCI_ANY_ID, PCI_ANY_ID, }, {0x13f0, 0x1021, PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VDEVICE(SUNDANCE, 0x1023), CHIP_IP1000A }, + { PCI_VDEVICE(SUNDANCE, 0x2021), CHIP_IP1000A }, + { PCI_VDEVICE(DLINK, 0x9021), CHIP_IP1000A }, + { PCI_VDEVICE(DLINK, 0x4020), CHIP_IP1000A }, { } }; MODULE_DEVICE_TABLE (pci, rio_pci_tbl); diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c index f4cb8e425853..734f655c99c1 100644 --- a/drivers/net/ethernet/emulex/benet/be_ethtool.c +++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c @@ -1062,9 +1062,7 @@ static int be_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd, static int be_set_rss_hash_opts(struct be_adapter *adapter, struct ethtool_rxnfc *cmd) { - struct be_rx_obj *rxo; - int status = 0, i, j; - u8 rsstable[128]; + int status; u32 rss_flags = adapter->rss_info.rss_flags; if (cmd->data != L3_RSS_FLAGS && @@ -1113,20 +1111,11 @@ static int be_set_rss_hash_opts(struct be_adapter *adapter, } if (rss_flags == adapter->rss_info.rss_flags) - return status; - - if (be_multi_rxq(adapter)) { - for (j = 0; j < 128; j += adapter->num_rss_qs) { - for_all_rss_queues(adapter, rxo, i) { - if ((j + i) >= 128) - break; - rsstable[j + i] = rxo->rss_id; - } - } - } + return 0; status = be_cmd_rss_config(adapter, adapter->rss_info.rsstable, - rss_flags, 128, adapter->rss_info.rss_hkey); + rss_flags, RSS_INDIR_TABLE_LEN, + adapter->rss_info.rss_hkey); if (!status) adapter->rss_info.rss_flags = rss_flags; diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index eb48a977f8da..b6ad02909d6b 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -3518,7 +3518,7 @@ static int be_rx_qs_create(struct be_adapter *adapter) netdev_rss_key_fill(rss_key, RSS_HASH_KEY_LEN); rc = be_cmd_rss_config(adapter, rss->rsstable, rss->rss_flags, - 128, rss_key); + RSS_INDIR_TABLE_LEN, rss_key); if (rc) { rss->rss_flags = RSS_ENABLE_NONE; return rc; diff --git a/drivers/net/ethernet/hisilicon/Kconfig b/drivers/net/ethernet/hisilicon/Kconfig index f250dec488fd..74beb1867230 100644 --- a/drivers/net/ethernet/hisilicon/Kconfig +++ b/drivers/net/ethernet/hisilicon/Kconfig @@ -5,7 +5,8 @@ config NET_VENDOR_HISILICON bool "Hisilicon devices" default y - depends on OF && (ARM || ARM64 || COMPILE_TEST) + depends on OF && HAS_DMA + depends on ARM || ARM64 || COMPILE_TEST ---help--- If you have a network (Ethernet) card belonging to this class, say Y. diff --git a/drivers/net/ethernet/icplus/Kconfig b/drivers/net/ethernet/icplus/Kconfig deleted file mode 100644 index 14a66e9d2e26..000000000000 --- a/drivers/net/ethernet/icplus/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -# -# IC Plus device configuration -# - -config IP1000 - tristate "IP1000 Gigabit Ethernet support" - depends on PCI - select MII - ---help--- - This driver supports IP1000 gigabit Ethernet cards. - - To compile this driver as a module, choose M here: the module - will be called ipg. This is recommended. diff --git a/drivers/net/ethernet/icplus/Makefile b/drivers/net/ethernet/icplus/Makefile deleted file mode 100644 index 5bc87c1f36aa..000000000000 --- a/drivers/net/ethernet/icplus/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -# -# Makefile for the IC Plus device drivers -# - -obj-$(CONFIG_IP1000) += ipg.o diff --git a/drivers/net/ethernet/icplus/ipg.c b/drivers/net/ethernet/icplus/ipg.c deleted file mode 100644 index c3b6af83f070..000000000000 --- a/drivers/net/ethernet/icplus/ipg.c +++ /dev/null @@ -1,2300 +0,0 @@ -/* - * ipg.c: Device Driver for the IP1000 Gigabit Ethernet Adapter - * - * Copyright (C) 2003, 2007 IC Plus Corp - * - * Original Author: - * - * Craig Rich - * Sundance Technology, Inc. - * www.sundanceti.com - * craig_rich@sundanceti.com - * - * Current Maintainer: - * - * Sorbica Shieh. - * http://www.icplus.com.tw - * sorbica@icplus.com.tw - * - * Jesse Huang - * http://www.icplus.com.tw - * jesse@icplus.com.tw - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/crc32.h> -#include <linux/ethtool.h> -#include <linux/interrupt.h> -#include <linux/gfp.h> -#include <linux/mii.h> -#include <linux/mutex.h> - -#include <asm/div64.h> - -#define IPG_RX_RING_BYTES (sizeof(struct ipg_rx) * IPG_RFDLIST_LENGTH) -#define IPG_TX_RING_BYTES (sizeof(struct ipg_tx) * IPG_TFDLIST_LENGTH) -#define IPG_RESET_MASK \ - (IPG_AC_GLOBAL_RESET | IPG_AC_RX_RESET | IPG_AC_TX_RESET | \ - IPG_AC_DMA | IPG_AC_FIFO | IPG_AC_NETWORK | IPG_AC_HOST | \ - IPG_AC_AUTO_INIT) - -#define ipg_w32(val32, reg) iowrite32((val32), ioaddr + (reg)) -#define ipg_w16(val16, reg) iowrite16((val16), ioaddr + (reg)) -#define ipg_w8(val8, reg) iowrite8((val8), ioaddr + (reg)) - -#define ipg_r32(reg) ioread32(ioaddr + (reg)) -#define ipg_r16(reg) ioread16(ioaddr + (reg)) -#define ipg_r8(reg) ioread8(ioaddr + (reg)) - -enum { - netdev_io_size = 128 -}; - -#include "ipg.h" -#define DRV_NAME "ipg" - -MODULE_AUTHOR("IC Plus Corp. 2003"); -MODULE_DESCRIPTION("IC Plus IP1000 Gigabit Ethernet Adapter Linux Driver"); -MODULE_LICENSE("GPL"); - -/* - * Defaults - */ -#define IPG_MAX_RXFRAME_SIZE 0x0600 -#define IPG_RXFRAG_SIZE 0x0600 -#define IPG_RXSUPPORT_SIZE 0x0600 -#define IPG_IS_JUMBO false - -/* - * Variable record -- index by leading revision/length - * Revision/Length(=N*4), Address1, Data1, Address2, Data2,...,AddressN,DataN - */ -static const unsigned short DefaultPhyParam[] = { - /* 11/12/03 IP1000A v1-3 rev=0x40 */ - /*-------------------------------------------------------------------------- - (0x4000|(15*4)), 31, 0x0001, 27, 0x01e0, 31, 0x0002, 22, 0x85bd, 24, 0xfff2, - 27, 0x0c10, 28, 0x0c10, 29, 0x2c10, 31, 0x0003, 23, 0x92f6, - 31, 0x0000, 23, 0x003d, 30, 0x00de, 20, 0x20e7, 9, 0x0700, - --------------------------------------------------------------------------*/ - /* 12/17/03 IP1000A v1-4 rev=0x40 */ - (0x4000 | (07 * 4)), 31, 0x0001, 27, 0x01e0, 31, 0x0002, 27, 0xeb8e, 31, - 0x0000, - 30, 0x005e, 9, 0x0700, - /* 01/09/04 IP1000A v1-5 rev=0x41 */ - (0x4100 | (07 * 4)), 31, 0x0001, 27, 0x01e0, 31, 0x0002, 27, 0xeb8e, 31, - 0x0000, - 30, 0x005e, 9, 0x0700, - 0x0000 -}; - -static const char * const ipg_brand_name[] = { - "IC PLUS IP1000 1000/100/10 based NIC", - "Sundance Technology ST2021 based NIC", - "Tamarack Microelectronics TC9020/9021 based NIC", - "D-Link NIC IP1000A" -}; - -static const struct pci_device_id ipg_pci_tbl[] = { - { PCI_VDEVICE(SUNDANCE, 0x1023), 0 }, - { PCI_VDEVICE(SUNDANCE, 0x2021), 1 }, - { PCI_VDEVICE(DLINK, 0x9021), 2 }, - { PCI_VDEVICE(DLINK, 0x4020), 3 }, - { 0, } -}; - -MODULE_DEVICE_TABLE(pci, ipg_pci_tbl); - -static inline void __iomem *ipg_ioaddr(struct net_device *dev) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - return sp->ioaddr; -} - -#ifdef IPG_DEBUG -static void ipg_dump_rfdlist(struct net_device *dev) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->ioaddr; - unsigned int i; - u32 offset; - - IPG_DEBUG_MSG("_dump_rfdlist\n"); - - netdev_info(dev, "rx_current = %02x\n", sp->rx_current); - netdev_info(dev, "rx_dirty = %02x\n", sp->rx_dirty); - netdev_info(dev, "RFDList start address = %016lx\n", - (unsigned long)sp->rxd_map); - netdev_info(dev, "RFDListPtr register = %08x%08x\n", - ipg_r32(IPG_RFDLISTPTR1), ipg_r32(IPG_RFDLISTPTR0)); - - for (i = 0; i < IPG_RFDLIST_LENGTH; i++) { - offset = (u32) &sp->rxd[i].next_desc - (u32) sp->rxd; - netdev_info(dev, "%02x %04x RFDNextPtr = %016lx\n", - i, offset, (unsigned long)sp->rxd[i].next_desc); - offset = (u32) &sp->rxd[i].rfs - (u32) sp->rxd; - netdev_info(dev, "%02x %04x RFS = %016lx\n", - i, offset, (unsigned long)sp->rxd[i].rfs); - offset = (u32) &sp->rxd[i].frag_info - (u32) sp->rxd; - netdev_info(dev, "%02x %04x frag_info = %016lx\n", - i, offset, (unsigned long)sp->rxd[i].frag_info); - } -} - -static void ipg_dump_tfdlist(struct net_device *dev) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->ioaddr; - unsigned int i; - u32 offset; - - IPG_DEBUG_MSG("_dump_tfdlist\n"); - - netdev_info(dev, "tx_current = %02x\n", sp->tx_current); - netdev_info(dev, "tx_dirty = %02x\n", sp->tx_dirty); - netdev_info(dev, "TFDList start address = %016lx\n", - (unsigned long) sp->txd_map); - netdev_info(dev, "TFDListPtr register = %08x%08x\n", - ipg_r32(IPG_TFDLISTPTR1), ipg_r32(IPG_TFDLISTPTR0)); - - for (i = 0; i < IPG_TFDLIST_LENGTH; i++) { - offset = (u32) &sp->txd[i].next_desc - (u32) sp->txd; - netdev_info(dev, "%02x %04x TFDNextPtr = %016lx\n", - i, offset, (unsigned long)sp->txd[i].next_desc); - - offset = (u32) &sp->txd[i].tfc - (u32) sp->txd; - netdev_info(dev, "%02x %04x TFC = %016lx\n", - i, offset, (unsigned long) sp->txd[i].tfc); - offset = (u32) &sp->txd[i].frag_info - (u32) sp->txd; - netdev_info(dev, "%02x %04x frag_info = %016lx\n", - i, offset, (unsigned long) sp->txd[i].frag_info); - } -} -#endif - -static void ipg_write_phy_ctl(void __iomem *ioaddr, u8 data) -{ - ipg_w8(IPG_PC_RSVD_MASK & data, PHY_CTRL); - ndelay(IPG_PC_PHYCTRLWAIT_NS); -} - -static void ipg_drive_phy_ctl_low_high(void __iomem *ioaddr, u8 data) -{ - ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_LO | data); - ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_HI | data); -} - -static void send_three_state(void __iomem *ioaddr, u8 phyctrlpolarity) -{ - phyctrlpolarity |= (IPG_PC_MGMTDATA & 0) | IPG_PC_MGMTDIR; - - ipg_drive_phy_ctl_low_high(ioaddr, phyctrlpolarity); -} - -static void send_end(void __iomem *ioaddr, u8 phyctrlpolarity) -{ - ipg_w8((IPG_PC_MGMTCLK_LO | (IPG_PC_MGMTDATA & 0) | IPG_PC_MGMTDIR | - phyctrlpolarity) & IPG_PC_RSVD_MASK, PHY_CTRL); -} - -static u16 read_phy_bit(void __iomem *ioaddr, u8 phyctrlpolarity) -{ - u16 bit_data; - - ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_LO | phyctrlpolarity); - - bit_data = ((ipg_r8(PHY_CTRL) & IPG_PC_MGMTDATA) >> 1) & 1; - - ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_HI | phyctrlpolarity); - - return bit_data; -} - -/* - * Read a register from the Physical Layer device located - * on the IPG NIC, using the IPG PHYCTRL register. - */ -static int mdio_read(struct net_device *dev, int phy_id, int phy_reg) -{ - void __iomem *ioaddr = ipg_ioaddr(dev); - /* - * The GMII mangement frame structure for a read is as follows: - * - * |Preamble|st|op|phyad|regad|ta| data |idle| - * |< 32 1s>|01|10|AAAAA|RRRRR|z0|DDDDDDDDDDDDDDDD|z | - * - * <32 1s> = 32 consecutive logic 1 values - * A = bit of Physical Layer device address (MSB first) - * R = bit of register address (MSB first) - * z = High impedance state - * D = bit of read data (MSB first) - * - * Transmission order is 'Preamble' field first, bits transmitted - * left to right (first to last). - */ - struct { - u32 field; - unsigned int len; - } p[] = { - { GMII_PREAMBLE, 32 }, /* Preamble */ - { GMII_ST, 2 }, /* ST */ - { GMII_READ, 2 }, /* OP */ - { phy_id, 5 }, /* PHYAD */ - { phy_reg, 5 }, /* REGAD */ - { 0x0000, 2 }, /* TA */ - { 0x0000, 16 }, /* DATA */ - { 0x0000, 1 } /* IDLE */ - }; - unsigned int i, j; - u8 polarity, data; - - polarity = ipg_r8(PHY_CTRL); - polarity &= (IPG_PC_DUPLEX_POLARITY | IPG_PC_LINK_POLARITY); - - /* Create the Preamble, ST, OP, PHYAD, and REGAD field. */ - for (j = 0; j < 5; j++) { - for (i = 0; i < p[j].len; i++) { - /* For each variable length field, the MSB must be - * transmitted first. Rotate through the field bits, - * starting with the MSB, and move each bit into the - * the 1st (2^1) bit position (this is the bit position - * corresponding to the MgmtData bit of the PhyCtrl - * register for the IPG). - * - * Example: ST = 01; - * - * First write a '0' to bit 1 of the PhyCtrl - * register, then write a '1' to bit 1 of the - * PhyCtrl register. - * - * To do this, right shift the MSB of ST by the value: - * [field length - 1 - #ST bits already written] - * then left shift this result by 1. - */ - data = (p[j].field >> (p[j].len - 1 - i)) << 1; - data &= IPG_PC_MGMTDATA; - data |= polarity | IPG_PC_MGMTDIR; - - ipg_drive_phy_ctl_low_high(ioaddr, data); - } - } - - send_three_state(ioaddr, polarity); - - read_phy_bit(ioaddr, polarity); - - /* - * For a read cycle, the bits for the next two fields (TA and - * DATA) are driven by the PHY (the IPG reads these bits). - */ - for (i = 0; i < p[6].len; i++) { - p[6].field |= - (read_phy_bit(ioaddr, polarity) << (p[6].len - 1 - i)); - } - - send_three_state(ioaddr, polarity); - send_three_state(ioaddr, polarity); - send_three_state(ioaddr, polarity); - send_end(ioaddr, polarity); - - /* Return the value of the DATA field. */ - return p[6].field; -} - -/* - * Write to a register from the Physical Layer device located - * on the IPG NIC, using the IPG PHYCTRL register. - */ -static void mdio_write(struct net_device *dev, int phy_id, int phy_reg, int val) -{ - void __iomem *ioaddr = ipg_ioaddr(dev); - /* - * The GMII mangement frame structure for a read is as follows: - * - * |Preamble|st|op|phyad|regad|ta| data |idle| - * |< 32 1s>|01|10|AAAAA|RRRRR|z0|DDDDDDDDDDDDDDDD|z | - * - * <32 1s> = 32 consecutive logic 1 values - * A = bit of Physical Layer device address (MSB first) - * R = bit of register address (MSB first) - * z = High impedance state - * D = bit of write data (MSB first) - * - * Transmission order is 'Preamble' field first, bits transmitted - * left to right (first to last). - */ - struct { - u32 field; - unsigned int len; - } p[] = { - { GMII_PREAMBLE, 32 }, /* Preamble */ - { GMII_ST, 2 }, /* ST */ - { GMII_WRITE, 2 }, /* OP */ - { phy_id, 5 }, /* PHYAD */ - { phy_reg, 5 }, /* REGAD */ - { 0x0002, 2 }, /* TA */ - { val & 0xffff, 16 }, /* DATA */ - { 0x0000, 1 } /* IDLE */ - }; - unsigned int i, j; - u8 polarity, data; - - polarity = ipg_r8(PHY_CTRL); - polarity &= (IPG_PC_DUPLEX_POLARITY | IPG_PC_LINK_POLARITY); - - /* Create the Preamble, ST, OP, PHYAD, and REGAD field. */ - for (j = 0; j < 7; j++) { - for (i = 0; i < p[j].len; i++) { - /* For each variable length field, the MSB must be - * transmitted first. Rotate through the field bits, - * starting with the MSB, and move each bit into the - * the 1st (2^1) bit position (this is the bit position - * corresponding to the MgmtData bit of the PhyCtrl - * register for the IPG). - * - * Example: ST = 01; - * - * First write a '0' to bit 1 of the PhyCtrl - * register, then write a '1' to bit 1 of the - * PhyCtrl register. - * - * To do this, right shift the MSB of ST by the value: - * [field length - 1 - #ST bits already written] - * then left shift this result by 1. - */ - data = (p[j].field >> (p[j].len - 1 - i)) << 1; - data &= IPG_PC_MGMTDATA; - data |= polarity | IPG_PC_MGMTDIR; - - ipg_drive_phy_ctl_low_high(ioaddr, data); - } - } - - /* The last cycle is a tri-state, so read from the PHY. */ - ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_LO | polarity); - ipg_r8(PHY_CTRL); - ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_HI | polarity); -} - -static void ipg_set_led_mode(struct net_device *dev) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->ioaddr; - u32 mode; - - mode = ipg_r32(ASIC_CTRL); - mode &= ~(IPG_AC_LED_MODE_BIT_1 | IPG_AC_LED_MODE | IPG_AC_LED_SPEED); - - if ((sp->led_mode & 0x03) > 1) - mode |= IPG_AC_LED_MODE_BIT_1; /* Write Asic Control Bit 29 */ - - if ((sp->led_mode & 0x01) == 1) - mode |= IPG_AC_LED_MODE; /* Write Asic Control Bit 14 */ - - if ((sp->led_mode & 0x08) == 8) - mode |= IPG_AC_LED_SPEED; /* Write Asic Control Bit 27 */ - - ipg_w32(mode, ASIC_CTRL); -} - -static void ipg_set_phy_set(struct net_device *dev) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->ioaddr; - int physet; - - physet = ipg_r8(PHY_SET); - physet &= ~(IPG_PS_MEM_LENB9B | IPG_PS_MEM_LEN9 | IPG_PS_NON_COMPDET); - physet |= ((sp->led_mode & 0x70) >> 4); - ipg_w8(physet, PHY_SET); -} - -static int ipg_reset(struct net_device *dev, u32 resetflags) -{ - /* Assert functional resets via the IPG AsicCtrl - * register as specified by the 'resetflags' input - * parameter. - */ - void __iomem *ioaddr = ipg_ioaddr(dev); - unsigned int timeout_count = 0; - - IPG_DEBUG_MSG("_reset\n"); - - ipg_w32(ipg_r32(ASIC_CTRL) | resetflags, ASIC_CTRL); - - /* Delay added to account for problem with 10Mbps reset. */ - mdelay(IPG_AC_RESETWAIT); - - while (IPG_AC_RESET_BUSY & ipg_r32(ASIC_CTRL)) { - mdelay(IPG_AC_RESETWAIT); - if (++timeout_count > IPG_AC_RESET_TIMEOUT) - return -ETIME; - } - /* Set LED Mode in Asic Control */ - ipg_set_led_mode(dev); - - /* Set PHYSet Register Value */ - ipg_set_phy_set(dev); - return 0; -} - -/* Find the GMII PHY address. */ -static int ipg_find_phyaddr(struct net_device *dev) -{ - unsigned int phyaddr, i; - - for (i = 0; i < 32; i++) { - u32 status; - - /* Search for the correct PHY address among 32 possible. */ - phyaddr = (IPG_NIC_PHY_ADDRESS + i) % 32; - - /* 10/22/03 Grace change verify from GMII_PHY_STATUS to - GMII_PHY_ID1 - */ - - status = mdio_read(dev, phyaddr, MII_BMSR); - - if ((status != 0xFFFF) && (status != 0)) - return phyaddr; - } - - return 0x1f; -} - -/* - * Configure IPG based on result of IEEE 802.3 PHY - * auto-negotiation. - */ -static int ipg_config_autoneg(struct net_device *dev) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->ioaddr; - unsigned int txflowcontrol; - unsigned int rxflowcontrol; - unsigned int fullduplex; - u32 mac_ctrl_val; - u32 asicctrl; - u8 phyctrl; - const char *speed; - const char *duplex; - const char *tx_desc; - const char *rx_desc; - - IPG_DEBUG_MSG("_config_autoneg\n"); - - asicctrl = ipg_r32(ASIC_CTRL); - phyctrl = ipg_r8(PHY_CTRL); - mac_ctrl_val = ipg_r32(MAC_CTRL); - - /* Set flags for use in resolving auto-negotiation, assuming - * non-1000Mbps, half duplex, no flow control. - */ - fullduplex = 0; - txflowcontrol = 0; - rxflowcontrol = 0; - - /* To accommodate a problem in 10Mbps operation, - * set a global flag if PHY running in 10Mbps mode. - */ - sp->tenmbpsmode = 0; - - /* Determine actual speed of operation. */ - switch (phyctrl & IPG_PC_LINK_SPEED) { - case IPG_PC_LINK_SPEED_10MBPS: - speed = "10Mbps"; - sp->tenmbpsmode = 1; - break; - case IPG_PC_LINK_SPEED_100MBPS: - speed = "100Mbps"; - break; - case IPG_PC_LINK_SPEED_1000MBPS: - speed = "1000Mbps"; - break; - default: - speed = "undefined!"; - return 0; - } - - netdev_info(dev, "Link speed = %s\n", speed); - if (sp->tenmbpsmode == 1) - netdev_info(dev, "10Mbps operational mode enabled\n"); - - if (phyctrl & IPG_PC_DUPLEX_STATUS) { - fullduplex = 1; - txflowcontrol = 1; - rxflowcontrol = 1; - } - - /* Configure full duplex, and flow control. */ - if (fullduplex == 1) { - - /* Configure IPG for full duplex operation. */ - - duplex = "full"; - - mac_ctrl_val |= IPG_MC_DUPLEX_SELECT_FD; - - if (txflowcontrol == 1) { - tx_desc = ""; - mac_ctrl_val |= IPG_MC_TX_FLOW_CONTROL_ENABLE; - } else { - tx_desc = "no "; - mac_ctrl_val &= ~IPG_MC_TX_FLOW_CONTROL_ENABLE; - } - - if (rxflowcontrol == 1) { - rx_desc = ""; - mac_ctrl_val |= IPG_MC_RX_FLOW_CONTROL_ENABLE; - } else { - rx_desc = "no "; - mac_ctrl_val &= ~IPG_MC_RX_FLOW_CONTROL_ENABLE; - } - } else { - duplex = "half"; - tx_desc = "no "; - rx_desc = "no "; - mac_ctrl_val &= (~IPG_MC_DUPLEX_SELECT_FD & - ~IPG_MC_TX_FLOW_CONTROL_ENABLE & - ~IPG_MC_RX_FLOW_CONTROL_ENABLE); - } - - netdev_info(dev, "setting %s duplex, %sTX, %sRX flow control\n", - duplex, tx_desc, rx_desc); - ipg_w32(mac_ctrl_val, MAC_CTRL); - - return 0; -} - -/* Determine and configure multicast operation and set - * receive mode for IPG. - */ -static void ipg_nic_set_multicast_list(struct net_device *dev) -{ - void __iomem *ioaddr = ipg_ioaddr(dev); - struct netdev_hw_addr *ha; - unsigned int hashindex; - u32 hashtable[2]; - u8 receivemode; - - IPG_DEBUG_MSG("_nic_set_multicast_list\n"); - - receivemode = IPG_RM_RECEIVEUNICAST | IPG_RM_RECEIVEBROADCAST; - - if (dev->flags & IFF_PROMISC) { - /* NIC to be configured in promiscuous mode. */ - receivemode = IPG_RM_RECEIVEALLFRAMES; - } else if ((dev->flags & IFF_ALLMULTI) || - ((dev->flags & IFF_MULTICAST) && - (netdev_mc_count(dev) > IPG_MULTICAST_HASHTABLE_SIZE))) { - /* NIC to be configured to receive all multicast - * frames. */ - receivemode |= IPG_RM_RECEIVEMULTICAST; - } else if ((dev->flags & IFF_MULTICAST) && !netdev_mc_empty(dev)) { - /* NIC to be configured to receive selected - * multicast addresses. */ - receivemode |= IPG_RM_RECEIVEMULTICASTHASH; - } - - /* Calculate the bits to set for the 64 bit, IPG HASHTABLE. - * The IPG applies a cyclic-redundancy-check (the same CRC - * used to calculate the frame data FCS) to the destination - * address all incoming multicast frames whose destination - * address has the multicast bit set. The least significant - * 6 bits of the CRC result are used as an addressing index - * into the hash table. If the value of the bit addressed by - * this index is a 1, the frame is passed to the host system. - */ - - /* Clear hashtable. */ - hashtable[0] = 0x00000000; - hashtable[1] = 0x00000000; - - /* Cycle through all multicast addresses to filter. */ - netdev_for_each_mc_addr(ha, dev) { - /* Calculate CRC result for each multicast address. */ - hashindex = crc32_le(0xffffffff, ha->addr, - ETH_ALEN); - - /* Use only the least significant 6 bits. */ - hashindex = hashindex & 0x3F; - - /* Within "hashtable", set bit number "hashindex" - * to a logic 1. - */ - set_bit(hashindex, (void *)hashtable); - } - - /* Write the value of the hashtable, to the 4, 16 bit - * HASHTABLE IPG registers. - */ - ipg_w32(hashtable[0], HASHTABLE_0); - ipg_w32(hashtable[1], HASHTABLE_1); - - ipg_w8(IPG_RM_RSVD_MASK & receivemode, RECEIVE_MODE); - - IPG_DEBUG_MSG("ReceiveMode = %x\n", ipg_r8(RECEIVE_MODE)); -} - -static int ipg_io_config(struct net_device *dev) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - void __iomem *ioaddr = ipg_ioaddr(dev); - u32 origmacctrl; - u32 restoremacctrl; - - IPG_DEBUG_MSG("_io_config\n"); - - origmacctrl = ipg_r32(MAC_CTRL); - - restoremacctrl = origmacctrl | IPG_MC_STATISTICS_ENABLE; - - /* Based on compilation option, determine if FCS is to be - * stripped on receive frames by IPG. - */ - if (!IPG_STRIP_FCS_ON_RX) - restoremacctrl |= IPG_MC_RCV_FCS; - - /* Determine if transmitter and/or receiver are - * enabled so we may restore MACCTRL correctly. - */ - if (origmacctrl & IPG_MC_TX_ENABLED) - restoremacctrl |= IPG_MC_TX_ENABLE; - - if (origmacctrl & IPG_MC_RX_ENABLED) - restoremacctrl |= IPG_MC_RX_ENABLE; - - /* Transmitter and receiver must be disabled before setting - * IFSSelect. - */ - ipg_w32((origmacctrl & (IPG_MC_RX_DISABLE | IPG_MC_TX_DISABLE)) & - IPG_MC_RSVD_MASK, MAC_CTRL); - - /* Now that transmitter and receiver are disabled, write - * to IFSSelect. - */ - ipg_w32((origmacctrl & IPG_MC_IFS_96BIT) & IPG_MC_RSVD_MASK, MAC_CTRL); - - /* Set RECEIVEMODE register. */ - ipg_nic_set_multicast_list(dev); - - ipg_w16(sp->max_rxframe_size, MAX_FRAME_SIZE); - - ipg_w8(IPG_RXDMAPOLLPERIOD_VALUE, RX_DMA_POLL_PERIOD); - ipg_w8(IPG_RXDMAURGENTTHRESH_VALUE, RX_DMA_URGENT_THRESH); - ipg_w8(IPG_RXDMABURSTTHRESH_VALUE, RX_DMA_BURST_THRESH); - ipg_w8(IPG_TXDMAPOLLPERIOD_VALUE, TX_DMA_POLL_PERIOD); - ipg_w8(IPG_TXDMAURGENTTHRESH_VALUE, TX_DMA_URGENT_THRESH); - ipg_w8(IPG_TXDMABURSTTHRESH_VALUE, TX_DMA_BURST_THRESH); - ipg_w16((IPG_IE_HOST_ERROR | IPG_IE_TX_DMA_COMPLETE | - IPG_IE_TX_COMPLETE | IPG_IE_INT_REQUESTED | - IPG_IE_UPDATE_STATS | IPG_IE_LINK_EVENT | - IPG_IE_RX_DMA_COMPLETE | IPG_IE_RX_DMA_PRIORITY), INT_ENABLE); - ipg_w16(IPG_FLOWONTHRESH_VALUE, FLOW_ON_THRESH); - ipg_w16(IPG_FLOWOFFTHRESH_VALUE, FLOW_OFF_THRESH); - - /* IPG multi-frag frame bug workaround. - * Per silicon revision B3 eratta. - */ - ipg_w16(ipg_r16(DEBUG_CTRL) | 0x0200, DEBUG_CTRL); - - /* IPG TX poll now bug workaround. - * Per silicon revision B3 eratta. - */ - ipg_w16(ipg_r16(DEBUG_CTRL) | 0x0010, DEBUG_CTRL); - - /* IPG RX poll now bug workaround. - * Per silicon revision B3 eratta. - */ - ipg_w16(ipg_r16(DEBUG_CTRL) | 0x0020, DEBUG_CTRL); - - /* Now restore MACCTRL to original setting. */ - ipg_w32(IPG_MC_RSVD_MASK & restoremacctrl, MAC_CTRL); - - /* Disable unused RMON statistics. */ - ipg_w32(IPG_RZ_ALL, RMON_STATISTICS_MASK); - - /* Disable unused MIB statistics. */ - ipg_w32(IPG_SM_MACCONTROLFRAMESXMTD | IPG_SM_MACCONTROLFRAMESRCVD | - IPG_SM_BCSTOCTETXMTOK_BCSTFRAMESXMTDOK | IPG_SM_TXJUMBOFRAMES | - IPG_SM_MCSTOCTETXMTOK_MCSTFRAMESXMTDOK | IPG_SM_RXJUMBOFRAMES | - IPG_SM_BCSTOCTETRCVDOK_BCSTFRAMESRCVDOK | - IPG_SM_UDPCHECKSUMERRORS | IPG_SM_TCPCHECKSUMERRORS | - IPG_SM_IPCHECKSUMERRORS, STATISTICS_MASK); - - return 0; -} - -/* - * Create a receive buffer within system memory and update - * NIC private structure appropriately. - */ -static int ipg_get_rxbuff(struct net_device *dev, int entry) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - struct ipg_rx *rxfd = sp->rxd + entry; - struct sk_buff *skb; - u64 rxfragsize; - - IPG_DEBUG_MSG("_get_rxbuff\n"); - - skb = netdev_alloc_skb_ip_align(dev, sp->rxsupport_size); - if (!skb) { - sp->rx_buff[entry] = NULL; - return -ENOMEM; - } - - /* Save the address of the sk_buff structure. */ - sp->rx_buff[entry] = skb; - - rxfd->frag_info = cpu_to_le64(pci_map_single(sp->pdev, skb->data, - sp->rx_buf_sz, PCI_DMA_FROMDEVICE)); - - /* Set the RFD fragment length. */ - rxfragsize = sp->rxfrag_size; - rxfd->frag_info |= cpu_to_le64((rxfragsize << 48) & IPG_RFI_FRAGLEN); - - return 0; -} - -static int init_rfdlist(struct net_device *dev) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->ioaddr; - unsigned int i; - - IPG_DEBUG_MSG("_init_rfdlist\n"); - - for (i = 0; i < IPG_RFDLIST_LENGTH; i++) { - struct ipg_rx *rxfd = sp->rxd + i; - - if (sp->rx_buff[i]) { - pci_unmap_single(sp->pdev, - le64_to_cpu(rxfd->frag_info) & ~IPG_RFI_FRAGLEN, - sp->rx_buf_sz, PCI_DMA_FROMDEVICE); - dev_kfree_skb_irq(sp->rx_buff[i]); - sp->rx_buff[i] = NULL; - } - - /* Clear out the RFS field. */ - rxfd->rfs = 0x0000000000000000; - - if (ipg_get_rxbuff(dev, i) < 0) { - /* - * A receive buffer was not ready, break the - * RFD list here. - */ - IPG_DEBUG_MSG("Cannot allocate Rx buffer\n"); - - /* Just in case we cannot allocate a single RFD. - * Should not occur. - */ - if (i == 0) { - netdev_err(dev, "No memory available for RFD list\n"); - return -ENOMEM; - } - } - - rxfd->next_desc = cpu_to_le64(sp->rxd_map + - sizeof(struct ipg_rx)*(i + 1)); - } - sp->rxd[i - 1].next_desc = cpu_to_le64(sp->rxd_map); - - sp->rx_current = 0; - sp->rx_dirty = 0; - - /* Write the location of the RFDList to the IPG. */ - ipg_w32((u32) sp->rxd_map, RFD_LIST_PTR_0); - ipg_w32(0x00000000, RFD_LIST_PTR_1); - - return 0; -} - -static void init_tfdlist(struct net_device *dev) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->ioaddr; - unsigned int i; - - IPG_DEBUG_MSG("_init_tfdlist\n"); - - for (i = 0; i < IPG_TFDLIST_LENGTH; i++) { - struct ipg_tx *txfd = sp->txd + i; - - txfd->tfc = cpu_to_le64(IPG_TFC_TFDDONE); - - if (sp->tx_buff[i]) { - dev_kfree_skb_irq(sp->tx_buff[i]); - sp->tx_buff[i] = NULL; - } - - txfd->next_desc = cpu_to_le64(sp->txd_map + - sizeof(struct ipg_tx)*(i + 1)); - } - sp->txd[i - 1].next_desc = cpu_to_le64(sp->txd_map); - - sp->tx_current = 0; - sp->tx_dirty = 0; - - /* Write the location of the TFDList to the IPG. */ - IPG_DDEBUG_MSG("Starting TFDListPtr = %08x\n", - (u32) sp->txd_map); - ipg_w32((u32) sp->txd_map, TFD_LIST_PTR_0); - ipg_w32(0x00000000, TFD_LIST_PTR_1); - - sp->reset_current_tfd = 1; -} - -/* - * Free all transmit buffers which have already been transferred - * via DMA to the IPG. - */ -static void ipg_nic_txfree(struct net_device *dev) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - unsigned int released, pending, dirty; - - IPG_DEBUG_MSG("_nic_txfree\n"); - - pending = sp->tx_current - sp->tx_dirty; - dirty = sp->tx_dirty % IPG_TFDLIST_LENGTH; - - for (released = 0; released < pending; released++) { - struct sk_buff *skb = sp->tx_buff[dirty]; - struct ipg_tx *txfd = sp->txd + dirty; - - IPG_DEBUG_MSG("TFC = %016lx\n", (unsigned long) txfd->tfc); - - /* Look at each TFD's TFC field beginning - * at the last freed TFD up to the current TFD. - * If the TFDDone bit is set, free the associated - * buffer. - */ - if (!(txfd->tfc & cpu_to_le64(IPG_TFC_TFDDONE))) - break; - - /* Free the transmit buffer. */ - if (skb) { - pci_unmap_single(sp->pdev, - le64_to_cpu(txfd->frag_info) & ~IPG_TFI_FRAGLEN, - skb->len, PCI_DMA_TODEVICE); - - dev_kfree_skb_irq(skb); - - sp->tx_buff[dirty] = NULL; - } - dirty = (dirty + 1) % IPG_TFDLIST_LENGTH; - } - - sp->tx_dirty += released; - - if (netif_queue_stopped(dev) && - (sp->tx_current != (sp->tx_dirty + IPG_TFDLIST_LENGTH))) { - netif_wake_queue(dev); - } -} - -static void ipg_tx_timeout(struct net_device *dev) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->ioaddr; - - ipg_reset(dev, IPG_AC_TX_RESET | IPG_AC_DMA | IPG_AC_NETWORK | - IPG_AC_FIFO); - - spin_lock_irq(&sp->lock); - - /* Re-configure after DMA reset. */ - if (ipg_io_config(dev) < 0) - netdev_info(dev, "Error during re-configuration\n"); - - init_tfdlist(dev); - - spin_unlock_irq(&sp->lock); - - ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_TX_ENABLE) & IPG_MC_RSVD_MASK, - MAC_CTRL); -} - -/* - * For TxComplete interrupts, free all transmit - * buffers which have already been transferred via DMA - * to the IPG. - */ -static void ipg_nic_txcleanup(struct net_device *dev) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->ioaddr; - unsigned int i; - - IPG_DEBUG_MSG("_nic_txcleanup\n"); - - for (i = 0; i < IPG_TFDLIST_LENGTH; i++) { - /* Reading the TXSTATUS register clears the - * TX_COMPLETE interrupt. - */ - u32 txstatusdword = ipg_r32(TX_STATUS); - - IPG_DEBUG_MSG("TxStatus = %08x\n", txstatusdword); - - /* Check for Transmit errors. Error bits only valid if - * TX_COMPLETE bit in the TXSTATUS register is a 1. - */ - if (!(txstatusdword & IPG_TS_TX_COMPLETE)) - break; - - /* If in 10Mbps mode, indicate transmit is ready. */ - if (sp->tenmbpsmode) { - netif_wake_queue(dev); - } - - /* Transmit error, increment stat counters. */ - if (txstatusdword & IPG_TS_TX_ERROR) { - IPG_DEBUG_MSG("Transmit error\n"); - sp->stats.tx_errors++; - } - - /* Late collision, re-enable transmitter. */ - if (txstatusdword & IPG_TS_LATE_COLLISION) { - IPG_DEBUG_MSG("Late collision on transmit\n"); - ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_TX_ENABLE) & - IPG_MC_RSVD_MASK, MAC_CTRL); - } - - /* Maximum collisions, re-enable transmitter. */ - if (txstatusdword & IPG_TS_TX_MAX_COLL) { - IPG_DEBUG_MSG("Maximum collisions on transmit\n"); - ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_TX_ENABLE) & - IPG_MC_RSVD_MASK, MAC_CTRL); - } - - /* Transmit underrun, reset and re-enable - * transmitter. - */ - if (txstatusdword & IPG_TS_TX_UNDERRUN) { - IPG_DEBUG_MSG("Transmitter underrun\n"); - sp->stats.tx_fifo_errors++; - ipg_reset(dev, IPG_AC_TX_RESET | IPG_AC_DMA | - IPG_AC_NETWORK | IPG_AC_FIFO); - - /* Re-configure after DMA reset. */ - if (ipg_io_config(dev) < 0) { - netdev_info(dev, "Error during re-configuration\n"); - } - init_tfdlist(dev); - - ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_TX_ENABLE) & - IPG_MC_RSVD_MASK, MAC_CTRL); - } - } - - ipg_nic_txfree(dev); -} - -/* Provides statistical information about the IPG NIC. */ -static struct net_device_stats *ipg_nic_get_stats(struct net_device *dev) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->ioaddr; - u16 temp1; - u16 temp2; - - IPG_DEBUG_MSG("_nic_get_stats\n"); - - /* Check to see if the NIC has been initialized via nic_open, - * before trying to read statistic registers. - */ - if (!netif_running(dev)) - return &sp->stats; - - sp->stats.rx_packets += ipg_r32(IPG_FRAMESRCVDOK); - sp->stats.tx_packets += ipg_r32(IPG_FRAMESXMTDOK); - sp->stats.rx_bytes += ipg_r32(IPG_OCTETRCVOK); - sp->stats.tx_bytes += ipg_r32(IPG_OCTETXMTOK); - temp1 = ipg_r16(IPG_FRAMESLOSTRXERRORS); - sp->stats.rx_errors += temp1; - sp->stats.rx_missed_errors += temp1; - temp1 = ipg_r32(IPG_SINGLECOLFRAMES) + ipg_r32(IPG_MULTICOLFRAMES) + - ipg_r32(IPG_LATECOLLISIONS); - temp2 = ipg_r16(IPG_CARRIERSENSEERRORS); - sp->stats.collisions += temp1; - sp->stats.tx_dropped += ipg_r16(IPG_FRAMESABORTXSCOLLS); - sp->stats.tx_errors += ipg_r16(IPG_FRAMESWEXDEFERRAL) + - ipg_r32(IPG_FRAMESWDEFERREDXMT) + temp1 + temp2; - sp->stats.multicast += ipg_r32(IPG_MCSTOCTETRCVDOK); - - /* detailed tx_errors */ - sp->stats.tx_carrier_errors += temp2; - - /* detailed rx_errors */ - sp->stats.rx_length_errors += ipg_r16(IPG_INRANGELENGTHERRORS) + - ipg_r16(IPG_FRAMETOOLONGERRORS); - sp->stats.rx_crc_errors += ipg_r16(IPG_FRAMECHECKSEQERRORS); - - /* Unutilized IPG statistic registers. */ - ipg_r32(IPG_MCSTFRAMESRCVDOK); - - return &sp->stats; -} - -/* Restore used receive buffers. */ -static int ipg_nic_rxrestore(struct net_device *dev) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - const unsigned int curr = sp->rx_current; - unsigned int dirty = sp->rx_dirty; - - IPG_DEBUG_MSG("_nic_rxrestore\n"); - - for (dirty = sp->rx_dirty; curr - dirty > 0; dirty++) { - unsigned int entry = dirty % IPG_RFDLIST_LENGTH; - - /* rx_copybreak may poke hole here and there. */ - if (sp->rx_buff[entry]) - continue; - - /* Generate a new receive buffer to replace the - * current buffer (which will be released by the - * Linux system). - */ - if (ipg_get_rxbuff(dev, entry) < 0) { - IPG_DEBUG_MSG("Cannot allocate new Rx buffer\n"); - - break; - } - - /* Reset the RFS field. */ - sp->rxd[entry].rfs = 0x0000000000000000; - } - sp->rx_dirty = dirty; - - return 0; -} - -/* use jumboindex and jumbosize to control jumbo frame status - * initial status is jumboindex=-1 and jumbosize=0 - * 1. jumboindex = -1 and jumbosize=0 : previous jumbo frame has been done. - * 2. jumboindex != -1 and jumbosize != 0 : jumbo frame is not over size and receiving - * 3. jumboindex = -1 and jumbosize != 0 : jumbo frame is over size, already dump - * previous receiving and need to continue dumping the current one - */ -enum { - NORMAL_PACKET, - ERROR_PACKET -}; - -enum { - FRAME_NO_START_NO_END = 0, - FRAME_WITH_START = 1, - FRAME_WITH_END = 10, - FRAME_WITH_START_WITH_END = 11 -}; - -static void ipg_nic_rx_free_skb(struct net_device *dev) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - unsigned int entry = sp->rx_current % IPG_RFDLIST_LENGTH; - - if (sp->rx_buff[entry]) { - struct ipg_rx *rxfd = sp->rxd + entry; - - pci_unmap_single(sp->pdev, - le64_to_cpu(rxfd->frag_info) & ~IPG_RFI_FRAGLEN, - sp->rx_buf_sz, PCI_DMA_FROMDEVICE); - dev_kfree_skb_irq(sp->rx_buff[entry]); - sp->rx_buff[entry] = NULL; - } -} - -static int ipg_nic_rx_check_frame_type(struct net_device *dev) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - struct ipg_rx *rxfd = sp->rxd + (sp->rx_current % IPG_RFDLIST_LENGTH); - int type = FRAME_NO_START_NO_END; - - if (le64_to_cpu(rxfd->rfs) & IPG_RFS_FRAMESTART) - type += FRAME_WITH_START; - if (le64_to_cpu(rxfd->rfs) & IPG_RFS_FRAMEEND) - type += FRAME_WITH_END; - return type; -} - -static int ipg_nic_rx_check_error(struct net_device *dev) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - unsigned int entry = sp->rx_current % IPG_RFDLIST_LENGTH; - struct ipg_rx *rxfd = sp->rxd + entry; - - if (IPG_DROP_ON_RX_ETH_ERRORS && (le64_to_cpu(rxfd->rfs) & - (IPG_RFS_RXFIFOOVERRUN | IPG_RFS_RXRUNTFRAME | - IPG_RFS_RXALIGNMENTERROR | IPG_RFS_RXFCSERROR | - IPG_RFS_RXOVERSIZEDFRAME | IPG_RFS_RXLENGTHERROR))) { - IPG_DEBUG_MSG("Rx error, RFS = %016lx\n", - (unsigned long) rxfd->rfs); - - /* Increment general receive error statistic. */ - sp->stats.rx_errors++; - - /* Increment detailed receive error statistics. */ - if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFIFOOVERRUN) { - IPG_DEBUG_MSG("RX FIFO overrun occurred\n"); - - sp->stats.rx_fifo_errors++; - } - - if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXRUNTFRAME) { - IPG_DEBUG_MSG("RX runt occurred\n"); - sp->stats.rx_length_errors++; - } - - /* Do nothing for IPG_RFS_RXOVERSIZEDFRAME, - * error count handled by a IPG statistic register. - */ - - if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXALIGNMENTERROR) { - IPG_DEBUG_MSG("RX alignment error occurred\n"); - sp->stats.rx_frame_errors++; - } - - /* Do nothing for IPG_RFS_RXFCSERROR, error count - * handled by a IPG statistic register. - */ - - /* Free the memory associated with the RX - * buffer since it is erroneous and we will - * not pass it to higher layer processes. - */ - if (sp->rx_buff[entry]) { - pci_unmap_single(sp->pdev, - le64_to_cpu(rxfd->frag_info) & ~IPG_RFI_FRAGLEN, - sp->rx_buf_sz, PCI_DMA_FROMDEVICE); - - dev_kfree_skb_irq(sp->rx_buff[entry]); - sp->rx_buff[entry] = NULL; - } - return ERROR_PACKET; - } - return NORMAL_PACKET; -} - -static void ipg_nic_rx_with_start_and_end(struct net_device *dev, - struct ipg_nic_private *sp, - struct ipg_rx *rxfd, unsigned entry) -{ - struct ipg_jumbo *jumbo = &sp->jumbo; - struct sk_buff *skb; - int framelen; - - if (jumbo->found_start) { - dev_kfree_skb_irq(jumbo->skb); - jumbo->found_start = 0; - jumbo->current_size = 0; - jumbo->skb = NULL; - } - - /* 1: found error, 0 no error */ - if (ipg_nic_rx_check_error(dev) != NORMAL_PACKET) - return; - - skb = sp->rx_buff[entry]; - if (!skb) - return; - - /* accept this frame and send to upper layer */ - framelen = le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFRAMELEN; - if (framelen > sp->rxfrag_size) - framelen = sp->rxfrag_size; - - skb_put(skb, framelen); - skb->protocol = eth_type_trans(skb, dev); - skb_checksum_none_assert(skb); - netif_rx(skb); - sp->rx_buff[entry] = NULL; -} - -static void ipg_nic_rx_with_start(struct net_device *dev, - struct ipg_nic_private *sp, - struct ipg_rx *rxfd, unsigned entry) -{ - struct ipg_jumbo *jumbo = &sp->jumbo; - struct pci_dev *pdev = sp->pdev; - struct sk_buff *skb; - - /* 1: found error, 0 no error */ - if (ipg_nic_rx_check_error(dev) != NORMAL_PACKET) - return; - - /* accept this frame and send to upper layer */ - skb = sp->rx_buff[entry]; - if (!skb) - return; - - if (jumbo->found_start) - dev_kfree_skb_irq(jumbo->skb); - - pci_unmap_single(pdev, le64_to_cpu(rxfd->frag_info) & ~IPG_RFI_FRAGLEN, - sp->rx_buf_sz, PCI_DMA_FROMDEVICE); - - skb_put(skb, sp->rxfrag_size); - - jumbo->found_start = 1; - jumbo->current_size = sp->rxfrag_size; - jumbo->skb = skb; - - sp->rx_buff[entry] = NULL; -} - -static void ipg_nic_rx_with_end(struct net_device *dev, - struct ipg_nic_private *sp, - struct ipg_rx *rxfd, unsigned entry) -{ - struct ipg_jumbo *jumbo = &sp->jumbo; - - /* 1: found error, 0 no error */ - if (ipg_nic_rx_check_error(dev) == NORMAL_PACKET) { - struct sk_buff *skb = sp->rx_buff[entry]; - - if (!skb) - return; - - if (jumbo->found_start) { - int framelen, endframelen; - - framelen = le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFRAMELEN; - - endframelen = framelen - jumbo->current_size; - if (framelen > sp->rxsupport_size) - dev_kfree_skb_irq(jumbo->skb); - else { - memcpy(skb_put(jumbo->skb, endframelen), - skb->data, endframelen); - - jumbo->skb->protocol = - eth_type_trans(jumbo->skb, dev); - - skb_checksum_none_assert(jumbo->skb); - netif_rx(jumbo->skb); - } - } - - jumbo->found_start = 0; - jumbo->current_size = 0; - jumbo->skb = NULL; - - ipg_nic_rx_free_skb(dev); - } else { - dev_kfree_skb_irq(jumbo->skb); - jumbo->found_start = 0; - jumbo->current_size = 0; - jumbo->skb = NULL; - } -} - -static void ipg_nic_rx_no_start_no_end(struct net_device *dev, - struct ipg_nic_private *sp, - struct ipg_rx *rxfd, unsigned entry) -{ - struct ipg_jumbo *jumbo = &sp->jumbo; - - /* 1: found error, 0 no error */ - if (ipg_nic_rx_check_error(dev) == NORMAL_PACKET) { - struct sk_buff *skb = sp->rx_buff[entry]; - - if (skb) { - if (jumbo->found_start) { - jumbo->current_size += sp->rxfrag_size; - if (jumbo->current_size <= sp->rxsupport_size) { - memcpy(skb_put(jumbo->skb, - sp->rxfrag_size), - skb->data, sp->rxfrag_size); - } - } - ipg_nic_rx_free_skb(dev); - } - } else { - dev_kfree_skb_irq(jumbo->skb); - jumbo->found_start = 0; - jumbo->current_size = 0; - jumbo->skb = NULL; - } -} - -static int ipg_nic_rx_jumbo(struct net_device *dev) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - unsigned int curr = sp->rx_current; - void __iomem *ioaddr = sp->ioaddr; - unsigned int i; - - IPG_DEBUG_MSG("_nic_rx\n"); - - for (i = 0; i < IPG_MAXRFDPROCESS_COUNT; i++, curr++) { - unsigned int entry = curr % IPG_RFDLIST_LENGTH; - struct ipg_rx *rxfd = sp->rxd + entry; - - if (!(rxfd->rfs & cpu_to_le64(IPG_RFS_RFDDONE))) - break; - - switch (ipg_nic_rx_check_frame_type(dev)) { - case FRAME_WITH_START_WITH_END: - ipg_nic_rx_with_start_and_end(dev, sp, rxfd, entry); - break; - case FRAME_WITH_START: - ipg_nic_rx_with_start(dev, sp, rxfd, entry); - break; - case FRAME_WITH_END: - ipg_nic_rx_with_end(dev, sp, rxfd, entry); - break; - case FRAME_NO_START_NO_END: - ipg_nic_rx_no_start_no_end(dev, sp, rxfd, entry); - break; - } - } - - sp->rx_current = curr; - - if (i == IPG_MAXRFDPROCESS_COUNT) { - /* There are more RFDs to process, however the - * allocated amount of RFD processing time has - * expired. Assert Interrupt Requested to make - * sure we come back to process the remaining RFDs. - */ - ipg_w32(ipg_r32(ASIC_CTRL) | IPG_AC_INT_REQUEST, ASIC_CTRL); - } - - ipg_nic_rxrestore(dev); - - return 0; -} - -static int ipg_nic_rx(struct net_device *dev) -{ - /* Transfer received Ethernet frames to higher network layers. */ - struct ipg_nic_private *sp = netdev_priv(dev); - unsigned int curr = sp->rx_current; - void __iomem *ioaddr = sp->ioaddr; - struct ipg_rx *rxfd; - unsigned int i; - - IPG_DEBUG_MSG("_nic_rx\n"); - -#define __RFS_MASK \ - cpu_to_le64(IPG_RFS_RFDDONE | IPG_RFS_FRAMESTART | IPG_RFS_FRAMEEND) - - for (i = 0; i < IPG_MAXRFDPROCESS_COUNT; i++, curr++) { - unsigned int entry = curr % IPG_RFDLIST_LENGTH; - struct sk_buff *skb = sp->rx_buff[entry]; - unsigned int framelen; - - rxfd = sp->rxd + entry; - - if (((rxfd->rfs & __RFS_MASK) != __RFS_MASK) || !skb) - break; - - /* Get received frame length. */ - framelen = le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFRAMELEN; - - /* Check for jumbo frame arrival with too small - * RXFRAG_SIZE. - */ - if (framelen > sp->rxfrag_size) { - IPG_DEBUG_MSG - ("RFS FrameLen > allocated fragment size\n"); - - framelen = sp->rxfrag_size; - } - - if ((IPG_DROP_ON_RX_ETH_ERRORS && (le64_to_cpu(rxfd->rfs) & - (IPG_RFS_RXFIFOOVERRUN | IPG_RFS_RXRUNTFRAME | - IPG_RFS_RXALIGNMENTERROR | IPG_RFS_RXFCSERROR | - IPG_RFS_RXOVERSIZEDFRAME | IPG_RFS_RXLENGTHERROR)))) { - - IPG_DEBUG_MSG("Rx error, RFS = %016lx\n", - (unsigned long int) rxfd->rfs); - - /* Increment general receive error statistic. */ - sp->stats.rx_errors++; - - /* Increment detailed receive error statistics. */ - if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFIFOOVERRUN) { - IPG_DEBUG_MSG("RX FIFO overrun occurred\n"); - sp->stats.rx_fifo_errors++; - } - - if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXRUNTFRAME) { - IPG_DEBUG_MSG("RX runt occurred\n"); - sp->stats.rx_length_errors++; - } - - if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXOVERSIZEDFRAME) ; - /* Do nothing, error count handled by a IPG - * statistic register. - */ - - if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXALIGNMENTERROR) { - IPG_DEBUG_MSG("RX alignment error occurred\n"); - sp->stats.rx_frame_errors++; - } - - if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFCSERROR) ; - /* Do nothing, error count handled by a IPG - * statistic register. - */ - - /* Free the memory associated with the RX - * buffer since it is erroneous and we will - * not pass it to higher layer processes. - */ - if (skb) { - __le64 info = rxfd->frag_info; - - pci_unmap_single(sp->pdev, - le64_to_cpu(info) & ~IPG_RFI_FRAGLEN, - sp->rx_buf_sz, PCI_DMA_FROMDEVICE); - - dev_kfree_skb_irq(skb); - } - } else { - - /* Adjust the new buffer length to accommodate the size - * of the received frame. - */ - skb_put(skb, framelen); - - /* Set the buffer's protocol field to Ethernet. */ - skb->protocol = eth_type_trans(skb, dev); - - /* The IPG encountered an error with (or - * there were no) IP/TCP/UDP checksums. - * This may or may not indicate an invalid - * IP/TCP/UDP frame was received. Let the - * upper layer decide. - */ - skb_checksum_none_assert(skb); - - /* Hand off frame for higher layer processing. - * The function netif_rx() releases the sk_buff - * when processing completes. - */ - netif_rx(skb); - } - - /* Assure RX buffer is not reused by IPG. */ - sp->rx_buff[entry] = NULL; - } - - /* - * If there are more RFDs to process and the allocated amount of RFD - * processing time has expired, assert Interrupt Requested to make - * sure we come back to process the remaining RFDs. - */ - if (i == IPG_MAXRFDPROCESS_COUNT) - ipg_w32(ipg_r32(ASIC_CTRL) | IPG_AC_INT_REQUEST, ASIC_CTRL); - -#ifdef IPG_DEBUG - /* Check if the RFD list contained no receive frame data. */ - if (!i) - sp->EmptyRFDListCount++; -#endif - while ((le64_to_cpu(rxfd->rfs) & IPG_RFS_RFDDONE) && - !((le64_to_cpu(rxfd->rfs) & IPG_RFS_FRAMESTART) && - (le64_to_cpu(rxfd->rfs) & IPG_RFS_FRAMEEND))) { - unsigned int entry = curr++ % IPG_RFDLIST_LENGTH; - - rxfd = sp->rxd + entry; - - IPG_DEBUG_MSG("Frame requires multiple RFDs\n"); - - /* An unexpected event, additional code needed to handle - * properly. So for the time being, just disregard the - * frame. - */ - - /* Free the memory associated with the RX - * buffer since it is erroneous and we will - * not pass it to higher layer processes. - */ - if (sp->rx_buff[entry]) { - pci_unmap_single(sp->pdev, - le64_to_cpu(rxfd->frag_info) & ~IPG_RFI_FRAGLEN, - sp->rx_buf_sz, PCI_DMA_FROMDEVICE); - dev_kfree_skb_irq(sp->rx_buff[entry]); - } - - /* Assure RX buffer is not reused by IPG. */ - sp->rx_buff[entry] = NULL; - } - - sp->rx_current = curr; - - /* Check to see if there are a minimum number of used - * RFDs before restoring any (should improve performance.) - */ - if ((curr - sp->rx_dirty) >= IPG_MINUSEDRFDSTOFREE) - ipg_nic_rxrestore(dev); - - return 0; -} - -static void ipg_reset_after_host_error(struct work_struct *work) -{ - struct ipg_nic_private *sp = - container_of(work, struct ipg_nic_private, task.work); - struct net_device *dev = sp->dev; - - /* - * Acknowledge HostError interrupt by resetting - * IPG DMA and HOST. - */ - ipg_reset(dev, IPG_AC_GLOBAL_RESET | IPG_AC_HOST | IPG_AC_DMA); - - init_rfdlist(dev); - init_tfdlist(dev); - - if (ipg_io_config(dev) < 0) { - netdev_info(dev, "Cannot recover from PCI error\n"); - schedule_delayed_work(&sp->task, HZ); - } -} - -static irqreturn_t ipg_interrupt_handler(int irq, void *dev_inst) -{ - struct net_device *dev = dev_inst; - struct ipg_nic_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->ioaddr; - unsigned int handled = 0; - u16 status; - - IPG_DEBUG_MSG("_interrupt_handler\n"); - - if (sp->is_jumbo) - ipg_nic_rxrestore(dev); - - spin_lock(&sp->lock); - - /* Get interrupt source information, and acknowledge - * some (i.e. TxDMAComplete, RxDMAComplete, RxEarly, - * IntRequested, MacControlFrame, LinkEvent) interrupts - * if issued. Also, all IPG interrupts are disabled by - * reading IntStatusAck. - */ - status = ipg_r16(INT_STATUS_ACK); - - IPG_DEBUG_MSG("IntStatusAck = %04x\n", status); - - /* Shared IRQ of remove event. */ - if (!(status & IPG_IS_RSVD_MASK)) - goto out_enable; - - handled = 1; - - if (unlikely(!netif_running(dev))) - goto out_unlock; - - /* If RFDListEnd interrupt, restore all used RFDs. */ - if (status & IPG_IS_RFD_LIST_END) { - IPG_DEBUG_MSG("RFDListEnd Interrupt\n"); - - /* The RFD list end indicates an RFD was encountered - * with a 0 NextPtr, or with an RFDDone bit set to 1 - * (indicating the RFD is not read for use by the - * IPG.) Try to restore all RFDs. - */ - ipg_nic_rxrestore(dev); - -#ifdef IPG_DEBUG - /* Increment the RFDlistendCount counter. */ - sp->RFDlistendCount++; -#endif - } - - /* If RFDListEnd, RxDMAPriority, RxDMAComplete, or - * IntRequested interrupt, process received frames. */ - if ((status & IPG_IS_RX_DMA_PRIORITY) || - (status & IPG_IS_RFD_LIST_END) || - (status & IPG_IS_RX_DMA_COMPLETE) || - (status & IPG_IS_INT_REQUESTED)) { -#ifdef IPG_DEBUG - /* Increment the RFD list checked counter if interrupted - * only to check the RFD list. */ - if (status & (~(IPG_IS_RX_DMA_PRIORITY | IPG_IS_RFD_LIST_END | - IPG_IS_RX_DMA_COMPLETE | IPG_IS_INT_REQUESTED) & - (IPG_IS_HOST_ERROR | IPG_IS_TX_DMA_COMPLETE | - IPG_IS_LINK_EVENT | IPG_IS_TX_COMPLETE | - IPG_IS_UPDATE_STATS))) - sp->RFDListCheckedCount++; -#endif - - if (sp->is_jumbo) - ipg_nic_rx_jumbo(dev); - else - ipg_nic_rx(dev); - } - - /* If TxDMAComplete interrupt, free used TFDs. */ - if (status & IPG_IS_TX_DMA_COMPLETE) - ipg_nic_txfree(dev); - - /* TxComplete interrupts indicate one of numerous actions. - * Determine what action to take based on TXSTATUS register. - */ - if (status & IPG_IS_TX_COMPLETE) - ipg_nic_txcleanup(dev); - - /* If UpdateStats interrupt, update Linux Ethernet statistics */ - if (status & IPG_IS_UPDATE_STATS) - ipg_nic_get_stats(dev); - - /* If HostError interrupt, reset IPG. */ - if (status & IPG_IS_HOST_ERROR) { - IPG_DDEBUG_MSG("HostError Interrupt\n"); - - schedule_delayed_work(&sp->task, 0); - } - - /* If LinkEvent interrupt, resolve autonegotiation. */ - if (status & IPG_IS_LINK_EVENT) { - if (ipg_config_autoneg(dev) < 0) - netdev_info(dev, "Auto-negotiation error\n"); - } - - /* If MACCtrlFrame interrupt, do nothing. */ - if (status & IPG_IS_MAC_CTRL_FRAME) - IPG_DEBUG_MSG("MACCtrlFrame interrupt\n"); - - /* If RxComplete interrupt, do nothing. */ - if (status & IPG_IS_RX_COMPLETE) - IPG_DEBUG_MSG("RxComplete interrupt\n"); - - /* If RxEarly interrupt, do nothing. */ - if (status & IPG_IS_RX_EARLY) - IPG_DEBUG_MSG("RxEarly interrupt\n"); - -out_enable: - /* Re-enable IPG interrupts. */ - ipg_w16(IPG_IE_TX_DMA_COMPLETE | IPG_IE_RX_DMA_COMPLETE | - IPG_IE_HOST_ERROR | IPG_IE_INT_REQUESTED | IPG_IE_TX_COMPLETE | - IPG_IE_LINK_EVENT | IPG_IE_UPDATE_STATS, INT_ENABLE); -out_unlock: - spin_unlock(&sp->lock); - - return IRQ_RETVAL(handled); -} - -static void ipg_rx_clear(struct ipg_nic_private *sp) -{ - unsigned int i; - - for (i = 0; i < IPG_RFDLIST_LENGTH; i++) { - if (sp->rx_buff[i]) { - struct ipg_rx *rxfd = sp->rxd + i; - - dev_kfree_skb_irq(sp->rx_buff[i]); - sp->rx_buff[i] = NULL; - pci_unmap_single(sp->pdev, - le64_to_cpu(rxfd->frag_info) & ~IPG_RFI_FRAGLEN, - sp->rx_buf_sz, PCI_DMA_FROMDEVICE); - } - } -} - -static void ipg_tx_clear(struct ipg_nic_private *sp) -{ - unsigned int i; - - for (i = 0; i < IPG_TFDLIST_LENGTH; i++) { - if (sp->tx_buff[i]) { - struct ipg_tx *txfd = sp->txd + i; - - pci_unmap_single(sp->pdev, - le64_to_cpu(txfd->frag_info) & ~IPG_TFI_FRAGLEN, - sp->tx_buff[i]->len, PCI_DMA_TODEVICE); - - dev_kfree_skb_irq(sp->tx_buff[i]); - - sp->tx_buff[i] = NULL; - } - } -} - -static int ipg_nic_open(struct net_device *dev) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->ioaddr; - struct pci_dev *pdev = sp->pdev; - int rc; - - IPG_DEBUG_MSG("_nic_open\n"); - - sp->rx_buf_sz = sp->rxsupport_size; - - /* Check for interrupt line conflicts, and request interrupt - * line for IPG. - * - * IMPORTANT: Disable IPG interrupts prior to registering - * IRQ. - */ - ipg_w16(0x0000, INT_ENABLE); - - /* Register the interrupt line to be used by the IPG within - * the Linux system. - */ - rc = request_irq(pdev->irq, ipg_interrupt_handler, IRQF_SHARED, - dev->name, dev); - if (rc < 0) { - netdev_info(dev, "Error when requesting interrupt\n"); - goto out; - } - - dev->irq = pdev->irq; - - rc = -ENOMEM; - - sp->rxd = dma_alloc_coherent(&pdev->dev, IPG_RX_RING_BYTES, - &sp->rxd_map, GFP_KERNEL); - if (!sp->rxd) - goto err_free_irq_0; - - sp->txd = dma_alloc_coherent(&pdev->dev, IPG_TX_RING_BYTES, - &sp->txd_map, GFP_KERNEL); - if (!sp->txd) - goto err_free_rx_1; - - rc = init_rfdlist(dev); - if (rc < 0) { - netdev_info(dev, "Error during configuration\n"); - goto err_free_tx_2; - } - - init_tfdlist(dev); - - rc = ipg_io_config(dev); - if (rc < 0) { - netdev_info(dev, "Error during configuration\n"); - goto err_release_tfdlist_3; - } - - /* Resolve autonegotiation. */ - if (ipg_config_autoneg(dev) < 0) - netdev_info(dev, "Auto-negotiation error\n"); - - /* initialize JUMBO Frame control variable */ - sp->jumbo.found_start = 0; - sp->jumbo.current_size = 0; - sp->jumbo.skb = NULL; - - /* Enable transmit and receive operation of the IPG. */ - ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_RX_ENABLE | IPG_MC_TX_ENABLE) & - IPG_MC_RSVD_MASK, MAC_CTRL); - - netif_start_queue(dev); -out: - return rc; - -err_release_tfdlist_3: - ipg_tx_clear(sp); - ipg_rx_clear(sp); -err_free_tx_2: - dma_free_coherent(&pdev->dev, IPG_TX_RING_BYTES, sp->txd, sp->txd_map); -err_free_rx_1: - dma_free_coherent(&pdev->dev, IPG_RX_RING_BYTES, sp->rxd, sp->rxd_map); -err_free_irq_0: - free_irq(pdev->irq, dev); - goto out; -} - -static int ipg_nic_stop(struct net_device *dev) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->ioaddr; - struct pci_dev *pdev = sp->pdev; - - IPG_DEBUG_MSG("_nic_stop\n"); - - netif_stop_queue(dev); - - IPG_DUMPTFDLIST(dev); - - do { - (void) ipg_r16(INT_STATUS_ACK); - - ipg_reset(dev, IPG_AC_GLOBAL_RESET | IPG_AC_HOST | IPG_AC_DMA); - - synchronize_irq(pdev->irq); - } while (ipg_r16(INT_ENABLE) & IPG_IE_RSVD_MASK); - - ipg_rx_clear(sp); - - ipg_tx_clear(sp); - - pci_free_consistent(pdev, IPG_RX_RING_BYTES, sp->rxd, sp->rxd_map); - pci_free_consistent(pdev, IPG_TX_RING_BYTES, sp->txd, sp->txd_map); - - free_irq(pdev->irq, dev); - - return 0; -} - -static netdev_tx_t ipg_nic_hard_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->ioaddr; - unsigned int entry = sp->tx_current % IPG_TFDLIST_LENGTH; - unsigned long flags; - struct ipg_tx *txfd; - - IPG_DDEBUG_MSG("_nic_hard_start_xmit\n"); - - /* If in 10Mbps mode, stop the transmit queue so - * no more transmit frames are accepted. - */ - if (sp->tenmbpsmode) - netif_stop_queue(dev); - - if (sp->reset_current_tfd) { - sp->reset_current_tfd = 0; - entry = 0; - } - - txfd = sp->txd + entry; - - sp->tx_buff[entry] = skb; - - /* Clear all TFC fields, except TFDDONE. */ - txfd->tfc = cpu_to_le64(IPG_TFC_TFDDONE); - - /* Specify the TFC field within the TFD. */ - txfd->tfc |= cpu_to_le64(IPG_TFC_WORDALIGNDISABLED | - (IPG_TFC_FRAMEID & sp->tx_current) | - (IPG_TFC_FRAGCOUNT & (1 << 24))); - /* - * 16--17 (WordAlign) <- 3 (disable), - * 0--15 (FrameId) <- sp->tx_current, - * 24--27 (FragCount) <- 1 - */ - - /* Request TxComplete interrupts at an interval defined - * by the constant IPG_FRAMESBETWEENTXCOMPLETES. - * Request TxComplete interrupt for every frame - * if in 10Mbps mode to accommodate problem with 10Mbps - * processing. - */ - if (sp->tenmbpsmode) - txfd->tfc |= cpu_to_le64(IPG_TFC_TXINDICATE); - txfd->tfc |= cpu_to_le64(IPG_TFC_TXDMAINDICATE); - /* Based on compilation option, determine if FCS is to be - * appended to transmit frame by IPG. - */ - if (!(IPG_APPEND_FCS_ON_TX)) - txfd->tfc |= cpu_to_le64(IPG_TFC_FCSAPPENDDISABLE); - - /* Based on compilation option, determine if IP, TCP and/or - * UDP checksums are to be added to transmit frame by IPG. - */ - if (IPG_ADD_IPCHECKSUM_ON_TX) - txfd->tfc |= cpu_to_le64(IPG_TFC_IPCHECKSUMENABLE); - - if (IPG_ADD_TCPCHECKSUM_ON_TX) - txfd->tfc |= cpu_to_le64(IPG_TFC_TCPCHECKSUMENABLE); - - if (IPG_ADD_UDPCHECKSUM_ON_TX) - txfd->tfc |= cpu_to_le64(IPG_TFC_UDPCHECKSUMENABLE); - - /* Based on compilation option, determine if VLAN tag info is to be - * inserted into transmit frame by IPG. - */ - if (IPG_INSERT_MANUAL_VLAN_TAG) { - txfd->tfc |= cpu_to_le64(IPG_TFC_VLANTAGINSERT | - ((u64) IPG_MANUAL_VLAN_VID << 32) | - ((u64) IPG_MANUAL_VLAN_CFI << 44) | - ((u64) IPG_MANUAL_VLAN_USERPRIORITY << 45)); - } - - /* The fragment start location within system memory is defined - * by the sk_buff structure's data field. The physical address - * of this location within the system's virtual memory space - * is determined using the IPG_HOST2BUS_MAP function. - */ - txfd->frag_info = cpu_to_le64(pci_map_single(sp->pdev, skb->data, - skb->len, PCI_DMA_TODEVICE)); - - /* The length of the fragment within system memory is defined by - * the sk_buff structure's len field. - */ - txfd->frag_info |= cpu_to_le64(IPG_TFI_FRAGLEN & - ((u64) (skb->len & 0xffff) << 48)); - - /* Clear the TFDDone bit last to indicate the TFD is ready - * for transfer to the IPG. - */ - txfd->tfc &= cpu_to_le64(~IPG_TFC_TFDDONE); - - spin_lock_irqsave(&sp->lock, flags); - - sp->tx_current++; - - mmiowb(); - - ipg_w32(IPG_DC_TX_DMA_POLL_NOW, DMA_CTRL); - - if (sp->tx_current == (sp->tx_dirty + IPG_TFDLIST_LENGTH)) - netif_stop_queue(dev); - - spin_unlock_irqrestore(&sp->lock, flags); - - return NETDEV_TX_OK; -} - -static void ipg_set_phy_default_param(unsigned char rev, - struct net_device *dev, int phy_address) -{ - unsigned short length; - unsigned char revision; - const unsigned short *phy_param; - unsigned short address, value; - - phy_param = &DefaultPhyParam[0]; - length = *phy_param & 0x00FF; - revision = (unsigned char)((*phy_param) >> 8); - phy_param++; - while (length != 0) { - if (rev == revision) { - while (length > 1) { - address = *phy_param; - value = *(phy_param + 1); - phy_param += 2; - mdio_write(dev, phy_address, address, value); - length -= 4; - } - break; - } else { - phy_param += length / 2; - length = *phy_param & 0x00FF; - revision = (unsigned char)((*phy_param) >> 8); - phy_param++; - } - } -} - -static int read_eeprom(struct net_device *dev, int eep_addr) -{ - void __iomem *ioaddr = ipg_ioaddr(dev); - unsigned int i; - int ret = 0; - u16 value; - - value = IPG_EC_EEPROM_READOPCODE | (eep_addr & 0xff); - ipg_w16(value, EEPROM_CTRL); - - for (i = 0; i < 1000; i++) { - u16 data; - - mdelay(10); - data = ipg_r16(EEPROM_CTRL); - if (!(data & IPG_EC_EEPROM_BUSY)) { - ret = ipg_r16(EEPROM_DATA); - break; - } - } - return ret; -} - -static void ipg_init_mii(struct net_device *dev) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - struct mii_if_info *mii_if = &sp->mii_if; - int phyaddr; - - mii_if->dev = dev; - mii_if->mdio_read = mdio_read; - mii_if->mdio_write = mdio_write; - mii_if->phy_id_mask = 0x1f; - mii_if->reg_num_mask = 0x1f; - - mii_if->phy_id = phyaddr = ipg_find_phyaddr(dev); - - if (phyaddr != 0x1f) { - u16 mii_phyctrl, mii_1000cr; - - mii_1000cr = mdio_read(dev, phyaddr, MII_CTRL1000); - mii_1000cr |= ADVERTISE_1000FULL | ADVERTISE_1000HALF | - GMII_PHY_1000BASETCONTROL_PreferMaster; - mdio_write(dev, phyaddr, MII_CTRL1000, mii_1000cr); - - mii_phyctrl = mdio_read(dev, phyaddr, MII_BMCR); - - /* Set default phyparam */ - ipg_set_phy_default_param(sp->pdev->revision, dev, phyaddr); - - /* Reset PHY */ - mii_phyctrl |= BMCR_RESET | BMCR_ANRESTART; - mdio_write(dev, phyaddr, MII_BMCR, mii_phyctrl); - - } -} - -static int ipg_hw_init(struct net_device *dev) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->ioaddr; - unsigned int i; - int rc; - - /* Read/Write and Reset EEPROM Value */ - /* Read LED Mode Configuration from EEPROM */ - sp->led_mode = read_eeprom(dev, 6); - - /* Reset all functions within the IPG. Do not assert - * RST_OUT as not compatible with some PHYs. - */ - rc = ipg_reset(dev, IPG_RESET_MASK); - if (rc < 0) - goto out; - - ipg_init_mii(dev); - - /* Read MAC Address from EEPROM */ - for (i = 0; i < 3; i++) - sp->station_addr[i] = read_eeprom(dev, 16 + i); - - for (i = 0; i < 3; i++) - ipg_w16(sp->station_addr[i], STATION_ADDRESS_0 + 2*i); - - /* Set station address in ethernet_device structure. */ - dev->dev_addr[0] = ipg_r16(STATION_ADDRESS_0) & 0x00ff; - dev->dev_addr[1] = (ipg_r16(STATION_ADDRESS_0) & 0xff00) >> 8; - dev->dev_addr[2] = ipg_r16(STATION_ADDRESS_1) & 0x00ff; - dev->dev_addr[3] = (ipg_r16(STATION_ADDRESS_1) & 0xff00) >> 8; - dev->dev_addr[4] = ipg_r16(STATION_ADDRESS_2) & 0x00ff; - dev->dev_addr[5] = (ipg_r16(STATION_ADDRESS_2) & 0xff00) >> 8; -out: - return rc; -} - -static int ipg_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - int rc; - - mutex_lock(&sp->mii_mutex); - rc = generic_mii_ioctl(&sp->mii_if, if_mii(ifr), cmd, NULL); - mutex_unlock(&sp->mii_mutex); - - return rc; -} - -static int ipg_nic_change_mtu(struct net_device *dev, int new_mtu) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - int err; - - /* Function to accommodate changes to Maximum Transfer Unit - * (or MTU) of IPG NIC. Cannot use default function since - * the default will not allow for MTU > 1500 bytes. - */ - - IPG_DEBUG_MSG("_nic_change_mtu\n"); - - /* - * Check that the new MTU value is between 68 (14 byte header, 46 byte - * payload, 4 byte FCS) and 10 KB, which is the largest supported MTU. - */ - if (new_mtu < 68 || new_mtu > 10240) - return -EINVAL; - - err = ipg_nic_stop(dev); - if (err) - return err; - - dev->mtu = new_mtu; - - sp->max_rxframe_size = new_mtu; - - sp->rxfrag_size = new_mtu; - if (sp->rxfrag_size > 4088) - sp->rxfrag_size = 4088; - - sp->rxsupport_size = sp->max_rxframe_size; - - if (new_mtu > 0x0600) - sp->is_jumbo = true; - else - sp->is_jumbo = false; - - return ipg_nic_open(dev); -} - -static int ipg_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - int rc; - - mutex_lock(&sp->mii_mutex); - rc = mii_ethtool_gset(&sp->mii_if, cmd); - mutex_unlock(&sp->mii_mutex); - - return rc; -} - -static int ipg_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - int rc; - - mutex_lock(&sp->mii_mutex); - rc = mii_ethtool_sset(&sp->mii_if, cmd); - mutex_unlock(&sp->mii_mutex); - - return rc; -} - -static int ipg_nway_reset(struct net_device *dev) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - int rc; - - mutex_lock(&sp->mii_mutex); - rc = mii_nway_restart(&sp->mii_if); - mutex_unlock(&sp->mii_mutex); - - return rc; -} - -static const struct ethtool_ops ipg_ethtool_ops = { - .get_settings = ipg_get_settings, - .set_settings = ipg_set_settings, - .nway_reset = ipg_nway_reset, -}; - -static void ipg_remove(struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata(pdev); - struct ipg_nic_private *sp = netdev_priv(dev); - - IPG_DEBUG_MSG("_remove\n"); - - /* Un-register Ethernet device. */ - unregister_netdev(dev); - - pci_iounmap(pdev, sp->ioaddr); - - pci_release_regions(pdev); - - free_netdev(dev); - pci_disable_device(pdev); -} - -static const struct net_device_ops ipg_netdev_ops = { - .ndo_open = ipg_nic_open, - .ndo_stop = ipg_nic_stop, - .ndo_start_xmit = ipg_nic_hard_start_xmit, - .ndo_get_stats = ipg_nic_get_stats, - .ndo_set_rx_mode = ipg_nic_set_multicast_list, - .ndo_do_ioctl = ipg_ioctl, - .ndo_tx_timeout = ipg_tx_timeout, - .ndo_change_mtu = ipg_nic_change_mtu, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, -}; - -static int ipg_probe(struct pci_dev *pdev, const struct pci_device_id *id) -{ - unsigned int i = id->driver_data; - struct ipg_nic_private *sp; - struct net_device *dev; - void __iomem *ioaddr; - int rc; - - rc = pci_enable_device(pdev); - if (rc < 0) - goto out; - - pr_info("%s: %s\n", pci_name(pdev), ipg_brand_name[i]); - - pci_set_master(pdev); - - rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(40)); - if (rc < 0) { - rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (rc < 0) { - pr_err("%s: DMA config failed\n", pci_name(pdev)); - goto err_disable_0; - } - } - - /* - * Initialize net device. - */ - dev = alloc_etherdev(sizeof(struct ipg_nic_private)); - if (!dev) { - rc = -ENOMEM; - goto err_disable_0; - } - - sp = netdev_priv(dev); - spin_lock_init(&sp->lock); - mutex_init(&sp->mii_mutex); - - sp->is_jumbo = IPG_IS_JUMBO; - sp->rxfrag_size = IPG_RXFRAG_SIZE; - sp->rxsupport_size = IPG_RXSUPPORT_SIZE; - sp->max_rxframe_size = IPG_MAX_RXFRAME_SIZE; - - /* Declare IPG NIC functions for Ethernet device methods. - */ - dev->netdev_ops = &ipg_netdev_ops; - SET_NETDEV_DEV(dev, &pdev->dev); - dev->ethtool_ops = &ipg_ethtool_ops; - - rc = pci_request_regions(pdev, DRV_NAME); - if (rc) - goto err_free_dev_1; - - ioaddr = pci_iomap(pdev, 1, pci_resource_len(pdev, 1)); - if (!ioaddr) { - pr_err("%s: cannot map MMIO\n", pci_name(pdev)); - rc = -EIO; - goto err_release_regions_2; - } - - /* Save the pointer to the PCI device information. */ - sp->ioaddr = ioaddr; - sp->pdev = pdev; - sp->dev = dev; - - INIT_DELAYED_WORK(&sp->task, ipg_reset_after_host_error); - - pci_set_drvdata(pdev, dev); - - rc = ipg_hw_init(dev); - if (rc < 0) - goto err_unmap_3; - - rc = register_netdev(dev); - if (rc < 0) - goto err_unmap_3; - - netdev_info(dev, "Ethernet device registered\n"); -out: - return rc; - -err_unmap_3: - pci_iounmap(pdev, ioaddr); -err_release_regions_2: - pci_release_regions(pdev); -err_free_dev_1: - free_netdev(dev); -err_disable_0: - pci_disable_device(pdev); - goto out; -} - -static struct pci_driver ipg_pci_driver = { - .name = IPG_DRIVER_NAME, - .id_table = ipg_pci_tbl, - .probe = ipg_probe, - .remove = ipg_remove, -}; - -module_pci_driver(ipg_pci_driver); diff --git a/drivers/net/ethernet/icplus/ipg.h b/drivers/net/ethernet/icplus/ipg.h deleted file mode 100644 index de606281f97b..000000000000 --- a/drivers/net/ethernet/icplus/ipg.h +++ /dev/null @@ -1,748 +0,0 @@ -/* - * Include file for Gigabit Ethernet device driver for Network - * Interface Cards (NICs) utilizing the Tamarack Microelectronics - * Inc. IPG Gigabit or Triple Speed Ethernet Media Access - * Controller. - */ -#ifndef __LINUX_IPG_H -#define __LINUX_IPG_H - -#include <linux/module.h> - -#include <linux/kernel.h> -#include <linux/pci.h> -#include <linux/ioport.h> -#include <linux/errno.h> -#include <asm/io.h> -#include <linux/delay.h> -#include <linux/types.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/skbuff.h> -#include <asm/bitops.h> - -/* - * Constants - */ - -/* GMII based PHY IDs */ -#define NS 0x2000 -#define MARVELL 0x0141 -#define ICPLUS_PHY 0x243 - -/* NIC Physical Layer Device MII register fields. */ -#define MII_PHY_SELECTOR_IEEE8023 0x0001 -#define MII_PHY_TECHABILITYFIELD 0x1FE0 - -/* GMII_PHY_1000 need to set to prefer master */ -#define GMII_PHY_1000BASETCONTROL_PreferMaster 0x0400 - -/* NIC Physical Layer Device GMII constants. */ -#define GMII_PREAMBLE 0xFFFFFFFF -#define GMII_ST 0x1 -#define GMII_READ 0x2 -#define GMII_WRITE 0x1 -#define GMII_TA_READ_MASK 0x1 -#define GMII_TA_WRITE 0x2 - -/* I/O register offsets. */ -enum ipg_regs { - DMA_CTRL = 0x00, - RX_DMA_STATUS = 0x08, /* Unused + reserved */ - TFD_LIST_PTR_0 = 0x10, - TFD_LIST_PTR_1 = 0x14, - TX_DMA_BURST_THRESH = 0x18, - TX_DMA_URGENT_THRESH = 0x19, - TX_DMA_POLL_PERIOD = 0x1a, - RFD_LIST_PTR_0 = 0x1c, - RFD_LIST_PTR_1 = 0x20, - RX_DMA_BURST_THRESH = 0x24, - RX_DMA_URGENT_THRESH = 0x25, - RX_DMA_POLL_PERIOD = 0x26, - DEBUG_CTRL = 0x2c, - ASIC_CTRL = 0x30, - FIFO_CTRL = 0x38, /* Unused */ - FLOW_OFF_THRESH = 0x3c, - FLOW_ON_THRESH = 0x3e, - EEPROM_DATA = 0x48, - EEPROM_CTRL = 0x4a, - EXPROM_ADDR = 0x4c, /* Unused */ - EXPROM_DATA = 0x50, /* Unused */ - WAKE_EVENT = 0x51, /* Unused */ - COUNTDOWN = 0x54, /* Unused */ - INT_STATUS_ACK = 0x5a, - INT_ENABLE = 0x5c, - INT_STATUS = 0x5e, /* Unused */ - TX_STATUS = 0x60, - MAC_CTRL = 0x6c, - VLAN_TAG = 0x70, /* Unused */ - PHY_SET = 0x75, - PHY_CTRL = 0x76, - STATION_ADDRESS_0 = 0x78, - STATION_ADDRESS_1 = 0x7a, - STATION_ADDRESS_2 = 0x7c, - MAX_FRAME_SIZE = 0x86, - RECEIVE_MODE = 0x88, - HASHTABLE_0 = 0x8c, - HASHTABLE_1 = 0x90, - RMON_STATISTICS_MASK = 0x98, - STATISTICS_MASK = 0x9c, - RX_JUMBO_FRAMES = 0xbc, /* Unused */ - TCP_CHECKSUM_ERRORS = 0xc0, /* Unused */ - IP_CHECKSUM_ERRORS = 0xc2, /* Unused */ - UDP_CHECKSUM_ERRORS = 0xc4, /* Unused */ - TX_JUMBO_FRAMES = 0xf4 /* Unused */ -}; - -/* Ethernet MIB statistic register offsets. */ -#define IPG_OCTETRCVOK 0xA8 -#define IPG_MCSTOCTETRCVDOK 0xAC -#define IPG_BCSTOCTETRCVOK 0xB0 -#define IPG_FRAMESRCVDOK 0xB4 -#define IPG_MCSTFRAMESRCVDOK 0xB8 -#define IPG_BCSTFRAMESRCVDOK 0xBE -#define IPG_MACCONTROLFRAMESRCVD 0xC6 -#define IPG_FRAMETOOLONGERRORS 0xC8 -#define IPG_INRANGELENGTHERRORS 0xCA -#define IPG_FRAMECHECKSEQERRORS 0xCC -#define IPG_FRAMESLOSTRXERRORS 0xCE -#define IPG_OCTETXMTOK 0xD0 -#define IPG_MCSTOCTETXMTOK 0xD4 -#define IPG_BCSTOCTETXMTOK 0xD8 -#define IPG_FRAMESXMTDOK 0xDC -#define IPG_MCSTFRAMESXMTDOK 0xE0 -#define IPG_FRAMESWDEFERREDXMT 0xE4 -#define IPG_LATECOLLISIONS 0xE8 -#define IPG_MULTICOLFRAMES 0xEC -#define IPG_SINGLECOLFRAMES 0xF0 -#define IPG_BCSTFRAMESXMTDOK 0xF6 -#define IPG_CARRIERSENSEERRORS 0xF8 -#define IPG_MACCONTROLFRAMESXMTDOK 0xFA -#define IPG_FRAMESABORTXSCOLLS 0xFC -#define IPG_FRAMESWEXDEFERRAL 0xFE - -/* RMON statistic register offsets. */ -#define IPG_ETHERSTATSCOLLISIONS 0x100 -#define IPG_ETHERSTATSOCTETSTRANSMIT 0x104 -#define IPG_ETHERSTATSPKTSTRANSMIT 0x108 -#define IPG_ETHERSTATSPKTS64OCTESTSTRANSMIT 0x10C -#define IPG_ETHERSTATSPKTS65TO127OCTESTSTRANSMIT 0x110 -#define IPG_ETHERSTATSPKTS128TO255OCTESTSTRANSMIT 0x114 -#define IPG_ETHERSTATSPKTS256TO511OCTESTSTRANSMIT 0x118 -#define IPG_ETHERSTATSPKTS512TO1023OCTESTSTRANSMIT 0x11C -#define IPG_ETHERSTATSPKTS1024TO1518OCTESTSTRANSMIT 0x120 -#define IPG_ETHERSTATSCRCALIGNERRORS 0x124 -#define IPG_ETHERSTATSUNDERSIZEPKTS 0x128 -#define IPG_ETHERSTATSFRAGMENTS 0x12C -#define IPG_ETHERSTATSJABBERS 0x130 -#define IPG_ETHERSTATSOCTETS 0x134 -#define IPG_ETHERSTATSPKTS 0x138 -#define IPG_ETHERSTATSPKTS64OCTESTS 0x13C -#define IPG_ETHERSTATSPKTS65TO127OCTESTS 0x140 -#define IPG_ETHERSTATSPKTS128TO255OCTESTS 0x144 -#define IPG_ETHERSTATSPKTS256TO511OCTESTS 0x148 -#define IPG_ETHERSTATSPKTS512TO1023OCTESTS 0x14C -#define IPG_ETHERSTATSPKTS1024TO1518OCTESTS 0x150 - -/* RMON statistic register equivalents. */ -#define IPG_ETHERSTATSMULTICASTPKTSTRANSMIT 0xE0 -#define IPG_ETHERSTATSBROADCASTPKTSTRANSMIT 0xF6 -#define IPG_ETHERSTATSMULTICASTPKTS 0xB8 -#define IPG_ETHERSTATSBROADCASTPKTS 0xBE -#define IPG_ETHERSTATSOVERSIZEPKTS 0xC8 -#define IPG_ETHERSTATSDROPEVENTS 0xCE - -/* Serial EEPROM offsets */ -#define IPG_EEPROM_CONFIGPARAM 0x00 -#define IPG_EEPROM_ASICCTRL 0x01 -#define IPG_EEPROM_SUBSYSTEMVENDORID 0x02 -#define IPG_EEPROM_SUBSYSTEMID 0x03 -#define IPG_EEPROM_STATIONADDRESS0 0x10 -#define IPG_EEPROM_STATIONADDRESS1 0x11 -#define IPG_EEPROM_STATIONADDRESS2 0x12 - -/* Register & data structure bit masks */ - -/* PCI register masks. */ - -/* IOBaseAddress */ -#define IPG_PIB_RSVD_MASK 0xFFFFFE01 -#define IPG_PIB_IOBASEADDRESS 0xFFFFFF00 -#define IPG_PIB_IOBASEADDRIND 0x00000001 - -/* MemBaseAddress */ -#define IPG_PMB_RSVD_MASK 0xFFFFFE07 -#define IPG_PMB_MEMBASEADDRIND 0x00000001 -#define IPG_PMB_MEMMAPTYPE 0x00000006 -#define IPG_PMB_MEMMAPTYPE0 0x00000002 -#define IPG_PMB_MEMMAPTYPE1 0x00000004 -#define IPG_PMB_MEMBASEADDRESS 0xFFFFFE00 - -/* ConfigStatus */ -#define IPG_CS_RSVD_MASK 0xFFB0 -#define IPG_CS_CAPABILITIES 0x0010 -#define IPG_CS_66MHZCAPABLE 0x0020 -#define IPG_CS_FASTBACK2BACK 0x0080 -#define IPG_CS_DATAPARITYREPORTED 0x0100 -#define IPG_CS_DEVSELTIMING 0x0600 -#define IPG_CS_SIGNALEDTARGETABORT 0x0800 -#define IPG_CS_RECEIVEDTARGETABORT 0x1000 -#define IPG_CS_RECEIVEDMASTERABORT 0x2000 -#define IPG_CS_SIGNALEDSYSTEMERROR 0x4000 -#define IPG_CS_DETECTEDPARITYERROR 0x8000 - -/* TFD data structure masks. */ - -/* TFDList, TFC */ -#define IPG_TFC_RSVD_MASK 0x0000FFFF9FFFFFFFULL -#define IPG_TFC_FRAMEID 0x000000000000FFFFULL -#define IPG_TFC_WORDALIGN 0x0000000000030000ULL -#define IPG_TFC_WORDALIGNTODWORD 0x0000000000000000ULL -#define IPG_TFC_WORDALIGNTOWORD 0x0000000000020000ULL -#define IPG_TFC_WORDALIGNDISABLED 0x0000000000030000ULL -#define IPG_TFC_TCPCHECKSUMENABLE 0x0000000000040000ULL -#define IPG_TFC_UDPCHECKSUMENABLE 0x0000000000080000ULL -#define IPG_TFC_IPCHECKSUMENABLE 0x0000000000100000ULL -#define IPG_TFC_FCSAPPENDDISABLE 0x0000000000200000ULL -#define IPG_TFC_TXINDICATE 0x0000000000400000ULL -#define IPG_TFC_TXDMAINDICATE 0x0000000000800000ULL -#define IPG_TFC_FRAGCOUNT 0x000000000F000000ULL -#define IPG_TFC_VLANTAGINSERT 0x0000000010000000ULL -#define IPG_TFC_TFDDONE 0x0000000080000000ULL -#define IPG_TFC_VID 0x00000FFF00000000ULL -#define IPG_TFC_CFI 0x0000100000000000ULL -#define IPG_TFC_USERPRIORITY 0x0000E00000000000ULL - -/* TFDList, FragInfo */ -#define IPG_TFI_RSVD_MASK 0xFFFF00FFFFFFFFFFULL -#define IPG_TFI_FRAGADDR 0x000000FFFFFFFFFFULL -#define IPG_TFI_FRAGLEN 0xFFFF000000000000ULL - -/* RFD data structure masks. */ - -/* RFDList, RFS */ -#define IPG_RFS_RSVD_MASK 0x0000FFFFFFFFFFFFULL -#define IPG_RFS_RXFRAMELEN 0x000000000000FFFFULL -#define IPG_RFS_RXFIFOOVERRUN 0x0000000000010000ULL -#define IPG_RFS_RXRUNTFRAME 0x0000000000020000ULL -#define IPG_RFS_RXALIGNMENTERROR 0x0000000000040000ULL -#define IPG_RFS_RXFCSERROR 0x0000000000080000ULL -#define IPG_RFS_RXOVERSIZEDFRAME 0x0000000000100000ULL -#define IPG_RFS_RXLENGTHERROR 0x0000000000200000ULL -#define IPG_RFS_VLANDETECTED 0x0000000000400000ULL -#define IPG_RFS_TCPDETECTED 0x0000000000800000ULL -#define IPG_RFS_TCPERROR 0x0000000001000000ULL -#define IPG_RFS_UDPDETECTED 0x0000000002000000ULL -#define IPG_RFS_UDPERROR 0x0000000004000000ULL -#define IPG_RFS_IPDETECTED 0x0000000008000000ULL -#define IPG_RFS_IPERROR 0x0000000010000000ULL -#define IPG_RFS_FRAMESTART 0x0000000020000000ULL -#define IPG_RFS_FRAMEEND 0x0000000040000000ULL -#define IPG_RFS_RFDDONE 0x0000000080000000ULL -#define IPG_RFS_TCI 0x0000FFFF00000000ULL - -/* RFDList, FragInfo */ -#define IPG_RFI_RSVD_MASK 0xFFFF00FFFFFFFFFFULL -#define IPG_RFI_FRAGADDR 0x000000FFFFFFFFFFULL -#define IPG_RFI_FRAGLEN 0xFFFF000000000000ULL - -/* I/O Register masks. */ - -/* RMON Statistics Mask */ -#define IPG_RZ_ALL 0x0FFFFFFF - -/* Statistics Mask */ -#define IPG_SM_ALL 0x0FFFFFFF -#define IPG_SM_OCTETRCVOK_FRAMESRCVDOK 0x00000001 -#define IPG_SM_MCSTOCTETRCVDOK_MCSTFRAMESRCVDOK 0x00000002 -#define IPG_SM_BCSTOCTETRCVDOK_BCSTFRAMESRCVDOK 0x00000004 -#define IPG_SM_RXJUMBOFRAMES 0x00000008 -#define IPG_SM_TCPCHECKSUMERRORS 0x00000010 -#define IPG_SM_IPCHECKSUMERRORS 0x00000020 -#define IPG_SM_UDPCHECKSUMERRORS 0x00000040 -#define IPG_SM_MACCONTROLFRAMESRCVD 0x00000080 -#define IPG_SM_FRAMESTOOLONGERRORS 0x00000100 -#define IPG_SM_INRANGELENGTHERRORS 0x00000200 -#define IPG_SM_FRAMECHECKSEQERRORS 0x00000400 -#define IPG_SM_FRAMESLOSTRXERRORS 0x00000800 -#define IPG_SM_OCTETXMTOK_FRAMESXMTOK 0x00001000 -#define IPG_SM_MCSTOCTETXMTOK_MCSTFRAMESXMTDOK 0x00002000 -#define IPG_SM_BCSTOCTETXMTOK_BCSTFRAMESXMTDOK 0x00004000 -#define IPG_SM_FRAMESWDEFERREDXMT 0x00008000 -#define IPG_SM_LATECOLLISIONS 0x00010000 -#define IPG_SM_MULTICOLFRAMES 0x00020000 -#define IPG_SM_SINGLECOLFRAMES 0x00040000 -#define IPG_SM_TXJUMBOFRAMES 0x00080000 -#define IPG_SM_CARRIERSENSEERRORS 0x00100000 -#define IPG_SM_MACCONTROLFRAMESXMTD 0x00200000 -#define IPG_SM_FRAMESABORTXSCOLLS 0x00400000 -#define IPG_SM_FRAMESWEXDEFERAL 0x00800000 - -/* Countdown */ -#define IPG_CD_RSVD_MASK 0x0700FFFF -#define IPG_CD_COUNT 0x0000FFFF -#define IPG_CD_COUNTDOWNSPEED 0x01000000 -#define IPG_CD_COUNTDOWNMODE 0x02000000 -#define IPG_CD_COUNTINTENABLED 0x04000000 - -/* TxDMABurstThresh */ -#define IPG_TB_RSVD_MASK 0xFF - -/* TxDMAUrgentThresh */ -#define IPG_TU_RSVD_MASK 0xFF - -/* TxDMAPollPeriod */ -#define IPG_TP_RSVD_MASK 0xFF - -/* RxDMAUrgentThresh */ -#define IPG_RU_RSVD_MASK 0xFF - -/* RxDMAPollPeriod */ -#define IPG_RP_RSVD_MASK 0xFF - -/* ReceiveMode */ -#define IPG_RM_RSVD_MASK 0x3F -#define IPG_RM_RECEIVEUNICAST 0x01 -#define IPG_RM_RECEIVEMULTICAST 0x02 -#define IPG_RM_RECEIVEBROADCAST 0x04 -#define IPG_RM_RECEIVEALLFRAMES 0x08 -#define IPG_RM_RECEIVEMULTICASTHASH 0x10 -#define IPG_RM_RECEIVEIPMULTICAST 0x20 - -/* PhySet */ -#define IPG_PS_MEM_LENB9B 0x01 -#define IPG_PS_MEM_LEN9 0x02 -#define IPG_PS_NON_COMPDET 0x04 - -/* PhyCtrl */ -#define IPG_PC_RSVD_MASK 0xFF -#define IPG_PC_MGMTCLK_LO 0x00 -#define IPG_PC_MGMTCLK_HI 0x01 -#define IPG_PC_MGMTCLK 0x01 -#define IPG_PC_MGMTDATA 0x02 -#define IPG_PC_MGMTDIR 0x04 -#define IPG_PC_DUPLEX_POLARITY 0x08 -#define IPG_PC_DUPLEX_STATUS 0x10 -#define IPG_PC_LINK_POLARITY 0x20 -#define IPG_PC_LINK_SPEED 0xC0 -#define IPG_PC_LINK_SPEED_10MBPS 0x40 -#define IPG_PC_LINK_SPEED_100MBPS 0x80 -#define IPG_PC_LINK_SPEED_1000MBPS 0xC0 - -/* DMACtrl */ -#define IPG_DC_RSVD_MASK 0xC07D9818 -#define IPG_DC_RX_DMA_COMPLETE 0x00000008 -#define IPG_DC_RX_DMA_POLL_NOW 0x00000010 -#define IPG_DC_TX_DMA_COMPLETE 0x00000800 -#define IPG_DC_TX_DMA_POLL_NOW 0x00001000 -#define IPG_DC_TX_DMA_IN_PROG 0x00008000 -#define IPG_DC_RX_EARLY_DISABLE 0x00010000 -#define IPG_DC_MWI_DISABLE 0x00040000 -#define IPG_DC_TX_WRITE_BACK_DISABLE 0x00080000 -#define IPG_DC_TX_BURST_LIMIT 0x00700000 -#define IPG_DC_TARGET_ABORT 0x40000000 -#define IPG_DC_MASTER_ABORT 0x80000000 - -/* ASICCtrl */ -#define IPG_AC_RSVD_MASK 0x07FFEFF2 -#define IPG_AC_EXP_ROM_SIZE 0x00000002 -#define IPG_AC_PHY_SPEED10 0x00000010 -#define IPG_AC_PHY_SPEED100 0x00000020 -#define IPG_AC_PHY_SPEED1000 0x00000040 -#define IPG_AC_PHY_MEDIA 0x00000080 -#define IPG_AC_FORCED_CFG 0x00000700 -#define IPG_AC_D3RESETDISABLE 0x00000800 -#define IPG_AC_SPEED_UP_MODE 0x00002000 -#define IPG_AC_LED_MODE 0x00004000 -#define IPG_AC_RST_OUT_POLARITY 0x00008000 -#define IPG_AC_GLOBAL_RESET 0x00010000 -#define IPG_AC_RX_RESET 0x00020000 -#define IPG_AC_TX_RESET 0x00040000 -#define IPG_AC_DMA 0x00080000 -#define IPG_AC_FIFO 0x00100000 -#define IPG_AC_NETWORK 0x00200000 -#define IPG_AC_HOST 0x00400000 -#define IPG_AC_AUTO_INIT 0x00800000 -#define IPG_AC_RST_OUT 0x01000000 -#define IPG_AC_INT_REQUEST 0x02000000 -#define IPG_AC_RESET_BUSY 0x04000000 -#define IPG_AC_LED_SPEED 0x08000000 -#define IPG_AC_LED_MODE_BIT_1 0x20000000 - -/* EepromCtrl */ -#define IPG_EC_RSVD_MASK 0x83FF -#define IPG_EC_EEPROM_ADDR 0x00FF -#define IPG_EC_EEPROM_OPCODE 0x0300 -#define IPG_EC_EEPROM_SUBCOMMAD 0x0000 -#define IPG_EC_EEPROM_WRITEOPCODE 0x0100 -#define IPG_EC_EEPROM_READOPCODE 0x0200 -#define IPG_EC_EEPROM_ERASEOPCODE 0x0300 -#define IPG_EC_EEPROM_BUSY 0x8000 - -/* FIFOCtrl */ -#define IPG_FC_RSVD_MASK 0xC001 -#define IPG_FC_RAM_TEST_MODE 0x0001 -#define IPG_FC_TRANSMITTING 0x4000 -#define IPG_FC_RECEIVING 0x8000 - -/* TxStatus */ -#define IPG_TS_RSVD_MASK 0xFFFF00DD -#define IPG_TS_TX_ERROR 0x00000001 -#define IPG_TS_LATE_COLLISION 0x00000004 -#define IPG_TS_TX_MAX_COLL 0x00000008 -#define IPG_TS_TX_UNDERRUN 0x00000010 -#define IPG_TS_TX_IND_REQD 0x00000040 -#define IPG_TS_TX_COMPLETE 0x00000080 -#define IPG_TS_TX_FRAMEID 0xFFFF0000 - -/* WakeEvent */ -#define IPG_WE_WAKE_PKT_ENABLE 0x01 -#define IPG_WE_MAGIC_PKT_ENABLE 0x02 -#define IPG_WE_LINK_EVT_ENABLE 0x04 -#define IPG_WE_WAKE_POLARITY 0x08 -#define IPG_WE_WAKE_PKT_EVT 0x10 -#define IPG_WE_MAGIC_PKT_EVT 0x20 -#define IPG_WE_LINK_EVT 0x40 -#define IPG_WE_WOL_ENABLE 0x80 - -/* IntEnable */ -#define IPG_IE_RSVD_MASK 0x1FFE -#define IPG_IE_HOST_ERROR 0x0002 -#define IPG_IE_TX_COMPLETE 0x0004 -#define IPG_IE_MAC_CTRL_FRAME 0x0008 -#define IPG_IE_RX_COMPLETE 0x0010 -#define IPG_IE_RX_EARLY 0x0020 -#define IPG_IE_INT_REQUESTED 0x0040 -#define IPG_IE_UPDATE_STATS 0x0080 -#define IPG_IE_LINK_EVENT 0x0100 -#define IPG_IE_TX_DMA_COMPLETE 0x0200 -#define IPG_IE_RX_DMA_COMPLETE 0x0400 -#define IPG_IE_RFD_LIST_END 0x0800 -#define IPG_IE_RX_DMA_PRIORITY 0x1000 - -/* IntStatus */ -#define IPG_IS_RSVD_MASK 0x1FFF -#define IPG_IS_INTERRUPT_STATUS 0x0001 -#define IPG_IS_HOST_ERROR 0x0002 -#define IPG_IS_TX_COMPLETE 0x0004 -#define IPG_IS_MAC_CTRL_FRAME 0x0008 -#define IPG_IS_RX_COMPLETE 0x0010 -#define IPG_IS_RX_EARLY 0x0020 -#define IPG_IS_INT_REQUESTED 0x0040 -#define IPG_IS_UPDATE_STATS 0x0080 -#define IPG_IS_LINK_EVENT 0x0100 -#define IPG_IS_TX_DMA_COMPLETE 0x0200 -#define IPG_IS_RX_DMA_COMPLETE 0x0400 -#define IPG_IS_RFD_LIST_END 0x0800 -#define IPG_IS_RX_DMA_PRIORITY 0x1000 - -/* MACCtrl */ -#define IPG_MC_RSVD_MASK 0x7FE33FA3 -#define IPG_MC_IFS_SELECT 0x00000003 -#define IPG_MC_IFS_4352BIT 0x00000003 -#define IPG_MC_IFS_1792BIT 0x00000002 -#define IPG_MC_IFS_1024BIT 0x00000001 -#define IPG_MC_IFS_96BIT 0x00000000 -#define IPG_MC_DUPLEX_SELECT 0x00000020 -#define IPG_MC_DUPLEX_SELECT_FD 0x00000020 -#define IPG_MC_DUPLEX_SELECT_HD 0x00000000 -#define IPG_MC_TX_FLOW_CONTROL_ENABLE 0x00000080 -#define IPG_MC_RX_FLOW_CONTROL_ENABLE 0x00000100 -#define IPG_MC_RCV_FCS 0x00000200 -#define IPG_MC_FIFO_LOOPBACK 0x00000400 -#define IPG_MC_MAC_LOOPBACK 0x00000800 -#define IPG_MC_AUTO_VLAN_TAGGING 0x00001000 -#define IPG_MC_AUTO_VLAN_UNTAGGING 0x00002000 -#define IPG_MC_COLLISION_DETECT 0x00010000 -#define IPG_MC_CARRIER_SENSE 0x00020000 -#define IPG_MC_STATISTICS_ENABLE 0x00200000 -#define IPG_MC_STATISTICS_DISABLE 0x00400000 -#define IPG_MC_STATISTICS_ENABLED 0x00800000 -#define IPG_MC_TX_ENABLE 0x01000000 -#define IPG_MC_TX_DISABLE 0x02000000 -#define IPG_MC_TX_ENABLED 0x04000000 -#define IPG_MC_RX_ENABLE 0x08000000 -#define IPG_MC_RX_DISABLE 0x10000000 -#define IPG_MC_RX_ENABLED 0x20000000 -#define IPG_MC_PAUSED 0x40000000 - -/* - * Tune - */ - -/* Assign IPG_APPEND_FCS_ON_TX > 0 for auto FCS append on TX. */ -#define IPG_APPEND_FCS_ON_TX 1 - -/* Assign IPG_APPEND_FCS_ON_TX > 0 for auto FCS strip on RX. */ -#define IPG_STRIP_FCS_ON_RX 1 - -/* Assign IPG_DROP_ON_RX_ETH_ERRORS > 0 to drop RX frames with - * Ethernet errors. - */ -#define IPG_DROP_ON_RX_ETH_ERRORS 1 - -/* Assign IPG_INSERT_MANUAL_VLAN_TAG > 0 to insert VLAN tags manually - * (via TFC). - */ -#define IPG_INSERT_MANUAL_VLAN_TAG 0 - -/* Assign IPG_ADD_IPCHECKSUM_ON_TX > 0 for auto IP checksum on TX. */ -#define IPG_ADD_IPCHECKSUM_ON_TX 0 - -/* Assign IPG_ADD_TCPCHECKSUM_ON_TX > 0 for auto TCP checksum on TX. - * DO NOT USE FOR SILICON REVISIONS B3 AND EARLIER. - */ -#define IPG_ADD_TCPCHECKSUM_ON_TX 0 - -/* Assign IPG_ADD_UDPCHECKSUM_ON_TX > 0 for auto UDP checksum on TX. - * DO NOT USE FOR SILICON REVISIONS B3 AND EARLIER. - */ -#define IPG_ADD_UDPCHECKSUM_ON_TX 0 - -/* If inserting VLAN tags manually, assign the IPG_MANUAL_VLAN_xx - * constants as desired. - */ -#define IPG_MANUAL_VLAN_VID 0xABC -#define IPG_MANUAL_VLAN_CFI 0x1 -#define IPG_MANUAL_VLAN_USERPRIORITY 0x5 - -#define IPG_IO_REG_RANGE 0xFF -#define IPG_MEM_REG_RANGE 0x154 -#define IPG_DRIVER_NAME "Sundance Technology IPG Triple-Speed Ethernet" -#define IPG_NIC_PHY_ADDRESS 0x01 -#define IPG_DMALIST_ALIGN_PAD 0x07 -#define IPG_MULTICAST_HASHTABLE_SIZE 0x40 - -/* Number of milliseconds to wait after issuing a software reset. - * 0x05 <= IPG_AC_RESETWAIT to account for proper 10Mbps operation. - */ -#define IPG_AC_RESETWAIT 0x05 - -/* Number of IPG_AC_RESETWAIT timeperiods before declaring timeout. */ -#define IPG_AC_RESET_TIMEOUT 0x0A - -/* Minimum number of nanoseconds used to toggle MDC clock during - * MII/GMII register access. - */ -#define IPG_PC_PHYCTRLWAIT_NS 200 - -#define IPG_TFDLIST_LENGTH 0x100 - -/* Number of frames between TxDMAComplete interrupt. - * 0 < IPG_FRAMESBETWEENTXDMACOMPLETES <= IPG_TFDLIST_LENGTH - */ -#define IPG_FRAMESBETWEENTXDMACOMPLETES 0x1 - -#define IPG_RFDLIST_LENGTH 0x100 - -/* Maximum number of RFDs to process per interrupt. - * 1 < IPG_MAXRFDPROCESS_COUNT < IPG_RFDLIST_LENGTH - */ -#define IPG_MAXRFDPROCESS_COUNT 0x80 - -/* Minimum margin between last freed RFD, and current RFD. - * 1 < IPG_MINUSEDRFDSTOFREE < IPG_RFDLIST_LENGTH - */ -#define IPG_MINUSEDRFDSTOFREE 0x80 - -/* specify the jumbo frame maximum size - * per unit is 0x600 (the rx_buffer size that one RFD can carry) - */ -#define MAX_JUMBOSIZE 0x8 /* max is 12K */ - -/* Key register values loaded at driver start up. */ - -/* TXDMAPollPeriod is specified in 320ns increments. - * - * Value Time - * --------------------- - * 0x00-0x01 320ns - * 0x03 ~1us - * 0x1F ~10us - * 0xFF ~82us - */ -#define IPG_TXDMAPOLLPERIOD_VALUE 0x26 - -/* TxDMAUrgentThresh specifies the minimum amount of - * data in the transmit FIFO before asserting an - * urgent transmit DMA request. - * - * Value Min TxFIFO occupied space before urgent TX request - * --------------------------------------------------------------- - * 0x00-0x04 128 bytes (1024 bits) - * 0x27 1248 bytes (~10000 bits) - * 0x30 1536 bytes (12288 bits) - * 0xFF 8192 bytes (65535 bits) - */ -#define IPG_TXDMAURGENTTHRESH_VALUE 0x04 - -/* TxDMABurstThresh specifies the minimum amount of - * free space in the transmit FIFO before asserting an - * transmit DMA request. - * - * Value Min TxFIFO free space before TX request - * ---------------------------------------------------- - * 0x00-0x08 256 bytes - * 0x30 1536 bytes - * 0xFF 8192 bytes - */ -#define IPG_TXDMABURSTTHRESH_VALUE 0x30 - -/* RXDMAPollPeriod is specified in 320ns increments. - * - * Value Time - * --------------------- - * 0x00-0x01 320ns - * 0x03 ~1us - * 0x1F ~10us - * 0xFF ~82us - */ -#define IPG_RXDMAPOLLPERIOD_VALUE 0x01 - -/* RxDMAUrgentThresh specifies the minimum amount of - * free space within the receive FIFO before asserting - * a urgent receive DMA request. - * - * Value Min RxFIFO free space before urgent RX request - * --------------------------------------------------------------- - * 0x00-0x04 128 bytes (1024 bits) - * 0x27 1248 bytes (~10000 bits) - * 0x30 1536 bytes (12288 bits) - * 0xFF 8192 bytes (65535 bits) - */ -#define IPG_RXDMAURGENTTHRESH_VALUE 0x30 - -/* RxDMABurstThresh specifies the minimum amount of - * occupied space within the receive FIFO before asserting - * a receive DMA request. - * - * Value Min TxFIFO free space before TX request - * ---------------------------------------------------- - * 0x00-0x08 256 bytes - * 0x30 1536 bytes - * 0xFF 8192 bytes - */ -#define IPG_RXDMABURSTTHRESH_VALUE 0x30 - -/* FlowOnThresh specifies the maximum amount of occupied - * space in the receive FIFO before a PAUSE frame with - * maximum pause time transmitted. - * - * Value Max RxFIFO occupied space before PAUSE - * --------------------------------------------------- - * 0x0000 0 bytes - * 0x0740 29,696 bytes - * 0x07FF 32,752 bytes - */ -#define IPG_FLOWONTHRESH_VALUE 0x0740 - -/* FlowOffThresh specifies the minimum amount of occupied - * space in the receive FIFO before a PAUSE frame with - * zero pause time is transmitted. - * - * Value Max RxFIFO occupied space before PAUSE - * --------------------------------------------------- - * 0x0000 0 bytes - * 0x00BF 3056 bytes - * 0x07FF 32,752 bytes - */ -#define IPG_FLOWOFFTHRESH_VALUE 0x00BF - -/* - * Miscellaneous macros. - */ - -/* Macros for printing debug statements. */ -#ifdef IPG_DEBUG -# define IPG_DEBUG_MSG(fmt, args...) \ -do { \ - if (0) \ - printk(KERN_DEBUG "IPG: " fmt, ##args); \ -} while (0) -# define IPG_DDEBUG_MSG(fmt, args...) \ - printk(KERN_DEBUG "IPG: " fmt, ##args) -# define IPG_DUMPRFDLIST(args) ipg_dump_rfdlist(args) -# define IPG_DUMPTFDLIST(args) ipg_dump_tfdlist(args) -#else -# define IPG_DEBUG_MSG(fmt, args...) \ -do { \ - if (0) \ - printk(KERN_DEBUG "IPG: " fmt, ##args); \ -} while (0) -# define IPG_DDEBUG_MSG(fmt, args...) \ -do { \ - if (0) \ - printk(KERN_DEBUG "IPG: " fmt, ##args); \ -} while (0) -# define IPG_DUMPRFDLIST(args) -# define IPG_DUMPTFDLIST(args) -#endif - -/* - * End miscellaneous macros. - */ - -/* Transmit Frame Descriptor. The IPG supports 15 fragments, - * however Linux requires only a single fragment. Note, each - * TFD field is 64 bits wide. - */ -struct ipg_tx { - __le64 next_desc; - __le64 tfc; - __le64 frag_info; -}; - -/* Receive Frame Descriptor. Note, each RFD field is 64 bits wide. - */ -struct ipg_rx { - __le64 next_desc; - __le64 rfs; - __le64 frag_info; -}; - -struct ipg_jumbo { - int found_start; - int current_size; - struct sk_buff *skb; -}; - -/* Structure of IPG NIC specific data. */ -struct ipg_nic_private { - void __iomem *ioaddr; - struct ipg_tx *txd; - struct ipg_rx *rxd; - dma_addr_t txd_map; - dma_addr_t rxd_map; - struct sk_buff *tx_buff[IPG_TFDLIST_LENGTH]; - struct sk_buff *rx_buff[IPG_RFDLIST_LENGTH]; - unsigned int tx_current; - unsigned int tx_dirty; - unsigned int rx_current; - unsigned int rx_dirty; - bool is_jumbo; - struct ipg_jumbo jumbo; - unsigned long rxfrag_size; - unsigned long rxsupport_size; - unsigned long max_rxframe_size; - unsigned int rx_buf_sz; - struct pci_dev *pdev; - struct net_device *dev; - struct net_device_stats stats; - spinlock_t lock; - int tenmbpsmode; - - u16 led_mode; - u16 station_addr[3]; /* Station Address in EEPROM Reg 0x10..0x12 */ - - struct mutex mii_mutex; - struct mii_if_info mii_if; - int reset_current_tfd; -#ifdef IPG_DEBUG - int RFDlistendCount; - int RFDListCheckedCount; - int EmptyRFDListCount; -#endif - struct delayed_work task; -}; - -#endif /* __LINUX_IPG_H */ diff --git a/drivers/net/ethernet/marvell/Kconfig b/drivers/net/ethernet/marvell/Kconfig index 80af9ffce5ea..a1c862b4664d 100644 --- a/drivers/net/ethernet/marvell/Kconfig +++ b/drivers/net/ethernet/marvell/Kconfig @@ -44,6 +44,7 @@ config MVNETA tristate "Marvell Armada 370/38x/XP network interface support" depends on PLAT_ORION select MVMDIO + select FIXED_PHY ---help--- This driver supports the network interface units in the Marvell ARMADA XP, ARMADA 370 and ARMADA 38x SoC family. diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index a47496a020d9..e84c7f2634d3 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -1493,9 +1493,9 @@ static void mvneta_rxq_drop_pkts(struct mvneta_port *pp, struct mvneta_rx_desc *rx_desc = rxq->descs + i; void *data = (void *)rx_desc->buf_cookie; - mvneta_frag_free(pp, data); dma_unmap_single(pp->dev->dev.parent, rx_desc->buf_phys_addr, MVNETA_RX_BUF_SIZE(pp->pkt_size), DMA_FROM_DEVICE); + mvneta_frag_free(pp, data); } if (rx_done) diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index 85f1b1e7e505..31c491e02e69 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -892,9 +892,10 @@ static int mlx4_slave_cap(struct mlx4_dev *dev) dev->caps.qp1_proxy[i - 1] = func_cap.qp1_proxy_qpn; dev->caps.port_mask[i] = dev->caps.port_type[i]; dev->caps.phys_port_id[i] = func_cap.phys_port_id; - if (mlx4_get_slave_pkey_gid_tbl_len(dev, i, - &dev->caps.gid_table_len[i], - &dev->caps.pkey_table_len[i])) + err = mlx4_get_slave_pkey_gid_tbl_len(dev, i, + &dev->caps.gid_table_len[i], + &dev->caps.pkey_table_len[i]); + if (err) goto err_mem; } @@ -906,6 +907,7 @@ static int mlx4_slave_cap(struct mlx4_dev *dev) dev->caps.uar_page_size * dev->caps.num_uars, (unsigned long long) pci_resource_len(dev->persist->pdev, 2)); + err = -ENOMEM; goto err_mem; } diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c index 9813d34f3e5b..6fec3e993d02 100644 --- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c +++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c @@ -4952,26 +4952,41 @@ static void rem_slave_counters(struct mlx4_dev *dev, int slave) struct res_counter *counter; struct res_counter *tmp; int err; - int index; + int *counters_arr = NULL; + int i, j; err = move_all_busy(dev, slave, RES_COUNTER); if (err) mlx4_warn(dev, "rem_slave_counters: Could not move all counters - too busy for slave %d\n", slave); - spin_lock_irq(mlx4_tlock(dev)); - list_for_each_entry_safe(counter, tmp, counter_list, com.list) { - if (counter->com.owner == slave) { - index = counter->com.res_id; - rb_erase(&counter->com.node, - &tracker->res_tree[RES_COUNTER]); - list_del(&counter->com.list); - kfree(counter); - __mlx4_counter_free(dev, index); + counters_arr = kmalloc_array(dev->caps.max_counters, + sizeof(*counters_arr), GFP_KERNEL); + if (!counters_arr) + return; + + do { + i = 0; + j = 0; + spin_lock_irq(mlx4_tlock(dev)); + list_for_each_entry_safe(counter, tmp, counter_list, com.list) { + if (counter->com.owner == slave) { + counters_arr[i++] = counter->com.res_id; + rb_erase(&counter->com.node, + &tracker->res_tree[RES_COUNTER]); + list_del(&counter->com.list); + kfree(counter); + } + } + spin_unlock_irq(mlx4_tlock(dev)); + + while (j < i) { + __mlx4_counter_free(dev, counters_arr[j++]); mlx4_release_resource(dev, slave, RES_COUNTER, 1, 0); } - } - spin_unlock_irq(mlx4_tlock(dev)); + } while (i); + + kfree(counters_arr); } static void rem_slave_xrcdns(struct mlx4_dev *dev, int slave) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index f2ae62dd8c09..22e72bf1ae48 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -334,9 +334,15 @@ struct mlx5e_tx_skb_cb { #define MLX5E_TX_SKB_CB(__skb) ((struct mlx5e_tx_skb_cb *)__skb->cb) +enum mlx5e_dma_map_type { + MLX5E_DMA_MAP_SINGLE, + MLX5E_DMA_MAP_PAGE +}; + struct mlx5e_sq_dma { - dma_addr_t addr; - u32 size; + dma_addr_t addr; + u32 size; + enum mlx5e_dma_map_type type; }; enum { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 5fc4d2d78cdf..1e52db32c73d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -1332,6 +1332,42 @@ static int mlx5e_modify_tir_lro(struct mlx5e_priv *priv, int tt) return err; } +static int mlx5e_refresh_tir_self_loopback_enable(struct mlx5_core_dev *mdev, + u32 tirn) +{ + void *in; + int inlen; + int err; + + inlen = MLX5_ST_SZ_BYTES(modify_tir_in); + in = mlx5_vzalloc(inlen); + if (!in) + return -ENOMEM; + + MLX5_SET(modify_tir_in, in, bitmask.self_lb_en, 1); + + err = mlx5_core_modify_tir(mdev, tirn, in, inlen); + + kvfree(in); + + return err; +} + +static int mlx5e_refresh_tirs_self_loopback_enable(struct mlx5e_priv *priv) +{ + int err; + int i; + + for (i = 0; i < MLX5E_NUM_TT; i++) { + err = mlx5e_refresh_tir_self_loopback_enable(priv->mdev, + priv->tirn[i]); + if (err) + return err; + } + + return 0; +} + static int mlx5e_set_dev_port_mtu(struct net_device *netdev) { struct mlx5e_priv *priv = netdev_priv(netdev); @@ -1376,6 +1412,13 @@ int mlx5e_open_locked(struct net_device *netdev) goto err_clear_state_opened_flag; } + err = mlx5e_refresh_tirs_self_loopback_enable(priv); + if (err) { + netdev_err(netdev, "%s: mlx5e_refresh_tirs_self_loopback_enable failed, %d\n", + __func__, err); + goto err_close_channels; + } + mlx5e_update_carrier(priv); mlx5e_redirect_rqts(priv); @@ -1383,6 +1426,8 @@ int mlx5e_open_locked(struct net_device *netdev) return 0; +err_close_channels: + mlx5e_close_channels(priv); err_clear_state_opened_flag: clear_bit(MLX5E_STATE_OPENED, &priv->state); return err; @@ -1856,6 +1901,8 @@ static int mlx5e_change_mtu(struct net_device *netdev, int new_mtu) mlx5_query_port_max_mtu(mdev, &max_mtu, 1); + max_mtu = MLX5E_HW2SW_MTU(max_mtu); + if (new_mtu > max_mtu) { netdev_err(netdev, "%s: Bad MTU (%d) > (%d) Max\n", @@ -1909,6 +1956,9 @@ static int mlx5e_check_required_hca_cap(struct mlx5_core_dev *mdev) "Not creating net device, some required device capabilities are missing\n"); return -ENOTSUPP; } + if (!MLX5_CAP_ETH(mdev, self_lb_en_modifiable)) + mlx5_core_warn(mdev, "Self loop back prevention is not supported\n"); + return 0; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c index cd8f85a251d7..1341b1d3c421 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c @@ -61,39 +61,47 @@ void mlx5e_send_nop(struct mlx5e_sq *sq, bool notify_hw) } } -static void mlx5e_dma_pop_last_pushed(struct mlx5e_sq *sq, dma_addr_t *addr, - u32 *size) +static inline void mlx5e_tx_dma_unmap(struct device *pdev, + struct mlx5e_sq_dma *dma) { - sq->dma_fifo_pc--; - *addr = sq->dma_fifo[sq->dma_fifo_pc & sq->dma_fifo_mask].addr; - *size = sq->dma_fifo[sq->dma_fifo_pc & sq->dma_fifo_mask].size; -} - -static void mlx5e_dma_unmap_wqe_err(struct mlx5e_sq *sq, struct sk_buff *skb) -{ - dma_addr_t addr; - u32 size; - int i; - - for (i = 0; i < MLX5E_TX_SKB_CB(skb)->num_dma; i++) { - mlx5e_dma_pop_last_pushed(sq, &addr, &size); - dma_unmap_single(sq->pdev, addr, size, DMA_TO_DEVICE); + switch (dma->type) { + case MLX5E_DMA_MAP_SINGLE: + dma_unmap_single(pdev, dma->addr, dma->size, DMA_TO_DEVICE); + break; + case MLX5E_DMA_MAP_PAGE: + dma_unmap_page(pdev, dma->addr, dma->size, DMA_TO_DEVICE); + break; + default: + WARN_ONCE(true, "mlx5e_tx_dma_unmap unknown DMA type!\n"); } } -static inline void mlx5e_dma_push(struct mlx5e_sq *sq, dma_addr_t addr, - u32 size) +static inline void mlx5e_dma_push(struct mlx5e_sq *sq, + dma_addr_t addr, + u32 size, + enum mlx5e_dma_map_type map_type) { sq->dma_fifo[sq->dma_fifo_pc & sq->dma_fifo_mask].addr = addr; sq->dma_fifo[sq->dma_fifo_pc & sq->dma_fifo_mask].size = size; + sq->dma_fifo[sq->dma_fifo_pc & sq->dma_fifo_mask].type = map_type; sq->dma_fifo_pc++; } -static inline void mlx5e_dma_get(struct mlx5e_sq *sq, u32 i, dma_addr_t *addr, - u32 *size) +static inline struct mlx5e_sq_dma *mlx5e_dma_get(struct mlx5e_sq *sq, u32 i) { - *addr = sq->dma_fifo[i & sq->dma_fifo_mask].addr; - *size = sq->dma_fifo[i & sq->dma_fifo_mask].size; + return &sq->dma_fifo[i & sq->dma_fifo_mask]; +} + +static void mlx5e_dma_unmap_wqe_err(struct mlx5e_sq *sq, struct sk_buff *skb) +{ + int i; + + for (i = 0; i < MLX5E_TX_SKB_CB(skb)->num_dma; i++) { + struct mlx5e_sq_dma *last_pushed_dma = + mlx5e_dma_get(sq, --sq->dma_fifo_pc); + + mlx5e_tx_dma_unmap(sq->pdev, last_pushed_dma); + } } u16 mlx5e_select_queue(struct net_device *dev, struct sk_buff *skb, @@ -118,8 +126,15 @@ static inline u16 mlx5e_get_inline_hdr_size(struct mlx5e_sq *sq, */ #define MLX5E_MIN_INLINE ETH_HLEN - if (bf && (skb_headlen(skb) <= sq->max_inline)) - return skb_headlen(skb); + if (bf) { + u16 ihs = skb_headlen(skb); + + if (skb_vlan_tag_present(skb)) + ihs += VLAN_HLEN; + + if (ihs <= sq->max_inline) + return skb_headlen(skb); + } return MLX5E_MIN_INLINE; } @@ -218,7 +233,7 @@ static netdev_tx_t mlx5e_sq_xmit(struct mlx5e_sq *sq, struct sk_buff *skb) dseg->lkey = sq->mkey_be; dseg->byte_count = cpu_to_be32(headlen); - mlx5e_dma_push(sq, dma_addr, headlen); + mlx5e_dma_push(sq, dma_addr, headlen, MLX5E_DMA_MAP_SINGLE); MLX5E_TX_SKB_CB(skb)->num_dma++; dseg++; @@ -237,7 +252,7 @@ static netdev_tx_t mlx5e_sq_xmit(struct mlx5e_sq *sq, struct sk_buff *skb) dseg->lkey = sq->mkey_be; dseg->byte_count = cpu_to_be32(fsz); - mlx5e_dma_push(sq, dma_addr, fsz); + mlx5e_dma_push(sq, dma_addr, fsz, MLX5E_DMA_MAP_PAGE); MLX5E_TX_SKB_CB(skb)->num_dma++; dseg++; @@ -353,13 +368,10 @@ bool mlx5e_poll_tx_cq(struct mlx5e_cq *cq) } for (j = 0; j < MLX5E_TX_SKB_CB(skb)->num_dma; j++) { - dma_addr_t addr; - u32 size; + struct mlx5e_sq_dma *dma = + mlx5e_dma_get(sq, dma_fifo_cc++); - mlx5e_dma_get(sq, dma_fifo_cc, &addr, &size); - dma_fifo_cc++; - dma_unmap_single(sq->pdev, addr, size, - DMA_TO_DEVICE); + mlx5e_tx_dma_unmap(sq->pdev, dma); } npkts++; diff --git a/drivers/net/ethernet/qlogic/Kconfig b/drivers/net/ethernet/qlogic/Kconfig index 30a6f246dfc9..ddcfcab034c2 100644 --- a/drivers/net/ethernet/qlogic/Kconfig +++ b/drivers/net/ethernet/qlogic/Kconfig @@ -94,6 +94,7 @@ config NETXEN_NIC config QED tristate "QLogic QED 25/40/100Gb core driver" depends on PCI + select ZLIB_INFLATE ---help--- This enables the support for ... diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c index b9b7b7e6fa53..803b190ccada 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c @@ -223,6 +223,7 @@ int qed_resc_alloc(struct qed_dev *cdev) if (!p_hwfn->p_tx_cids) { DP_NOTICE(p_hwfn, "Failed to allocate memory for Tx Cids\n"); + rc = -ENOMEM; goto alloc_err; } @@ -230,6 +231,7 @@ int qed_resc_alloc(struct qed_dev *cdev) if (!p_hwfn->p_rx_cids) { DP_NOTICE(p_hwfn, "Failed to allocate memory for Rx Cids\n"); + rc = -ENOMEM; goto alloc_err; } } @@ -281,14 +283,17 @@ int qed_resc_alloc(struct qed_dev *cdev) /* EQ */ p_eq = qed_eq_alloc(p_hwfn, 256); - - if (!p_eq) + if (!p_eq) { + rc = -ENOMEM; goto alloc_err; + } p_hwfn->p_eq = p_eq; p_consq = qed_consq_alloc(p_hwfn); - if (!p_consq) + if (!p_consq) { + rc = -ENOMEM; goto alloc_err; + } p_hwfn->p_consq = p_consq; /* DMA info initialization */ @@ -303,6 +308,7 @@ int qed_resc_alloc(struct qed_dev *cdev) cdev->reset_stats = kzalloc(sizeof(*cdev->reset_stats), GFP_KERNEL); if (!cdev->reset_stats) { DP_NOTICE(cdev, "Failed to allocate reset statistics\n"); + rc = -ENOMEM; goto alloc_err; } @@ -562,7 +568,7 @@ static int qed_hw_init_pf(struct qed_hwfn *p_hwfn, } /* Enable classification by MAC if needed */ - if (hw_mode & MODE_MF_SI) { + if (hw_mode & (1 << MODE_MF_SI)) { DP_VERBOSE(p_hwfn, NETIF_MSG_HW, "Configuring TAGMAC_CLS_TYPE\n"); STORE_RT_REG(p_hwfn, diff --git a/drivers/net/ethernet/qlogic/qed/qed_int.c b/drivers/net/ethernet/qlogic/qed/qed_int.c index 2e399b6137a2..de50e84902af 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_int.c +++ b/drivers/net/ethernet/qlogic/qed/qed_int.c @@ -251,11 +251,6 @@ void qed_int_sp_dpc(unsigned long hwfn_cookie) int arr_size; u16 rc = 0; - if (!p_hwfn) { - DP_ERR(p_hwfn->cdev, "DPC called - no hwfn!\n"); - return; - } - if (!p_hwfn->p_sp_sb) { DP_ERR(p_hwfn->cdev, "DPC called - no p_sp_sb\n"); return; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c index d4481454b5f8..1205f6f9c941 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c @@ -353,7 +353,8 @@ static int qlcnic_set_mac(struct net_device *netdev, void *p) if (!is_valid_ether_addr(addr->sa_data)) return -EINVAL; - if (ether_addr_equal_unaligned(adapter->mac_addr, addr->sa_data)) + if (ether_addr_equal_unaligned(adapter->mac_addr, addr->sa_data) && + ether_addr_equal_unaligned(netdev->dev_addr, addr->sa_data)) return 0; if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) { diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index b4f21232019a..79ef799f88ab 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -7429,15 +7429,15 @@ process_pkt: rtl8169_rx_vlan_tag(desc, skb); + if (skb->pkt_type == PACKET_MULTICAST) + dev->stats.multicast++; + napi_gro_receive(&tp->napi, skb); u64_stats_update_begin(&tp->rx_stats.syncp); tp->rx_stats.packets++; tp->rx_stats.bytes += pkt_size; u64_stats_update_end(&tp->rx_stats.syncp); - - if (skb->pkt_type == PACKET_MULTICAST) - dev->stats.multicast++; } release_descriptor: desc->opts2 = 0; diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index aa7b2083cb53..ee8d1ec61fab 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -408,8 +408,6 @@ static int ravb_dmac_init(struct net_device *ndev) /* Interrupt enable: */ /* Frame receive */ ravb_write(ndev, RIC0_FRE0 | RIC0_FRE1, RIC0); - /* Receive FIFO full warning */ - ravb_write(ndev, RIC1_RFWE, RIC1); /* Receive FIFO full error, descriptor empty */ ravb_write(ndev, RIC2_QFE0 | RIC2_QFE1 | RIC2_RFFE, RIC2); /* Frame transmitted, timestamp FIFO updated */ @@ -733,8 +731,10 @@ static irqreturn_t ravb_interrupt(int irq, void *dev_id) ((tis & tic) & BIT(q))) { if (napi_schedule_prep(&priv->napi[q])) { /* Mask RX and TX interrupts */ - ravb_write(ndev, ric0 & ~BIT(q), RIC0); - ravb_write(ndev, tic & ~BIT(q), TIC); + ric0 &= ~BIT(q); + tic &= ~BIT(q); + ravb_write(ndev, ric0, RIC0); + ravb_write(ndev, tic, TIC); __napi_schedule(&priv->napi[q]); } else { netdev_warn(ndev, diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index 6150a235b72c..e7bab7909ed9 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -1098,7 +1098,7 @@ static struct mdiobb_ops bb_ops = { static void sh_eth_ring_free(struct net_device *ndev) { struct sh_eth_private *mdp = netdev_priv(ndev); - int i; + int ringsize, i; /* Free Rx skb ringbuffer */ if (mdp->rx_skbuff) { @@ -1115,6 +1115,20 @@ static void sh_eth_ring_free(struct net_device *ndev) } kfree(mdp->tx_skbuff); mdp->tx_skbuff = NULL; + + if (mdp->rx_ring) { + ringsize = sizeof(struct sh_eth_rxdesc) * mdp->num_rx_ring; + dma_free_coherent(NULL, ringsize, mdp->rx_ring, + mdp->rx_desc_dma); + mdp->rx_ring = NULL; + } + + if (mdp->tx_ring) { + ringsize = sizeof(struct sh_eth_txdesc) * mdp->num_tx_ring; + dma_free_coherent(NULL, ringsize, mdp->tx_ring, + mdp->tx_desc_dma); + mdp->tx_ring = NULL; + } } /* format skb and descriptor buffer */ @@ -1199,7 +1213,7 @@ static void sh_eth_ring_format(struct net_device *ndev) static int sh_eth_ring_init(struct net_device *ndev) { struct sh_eth_private *mdp = netdev_priv(ndev); - int rx_ringsize, tx_ringsize, ret = 0; + int rx_ringsize, tx_ringsize; /* +26 gets the maximum ethernet encapsulation, +7 & ~7 because the * card needs room to do 8 byte alignment, +2 so we can reserve @@ -1214,26 +1228,20 @@ static int sh_eth_ring_init(struct net_device *ndev) /* Allocate RX and TX skb rings */ mdp->rx_skbuff = kcalloc(mdp->num_rx_ring, sizeof(*mdp->rx_skbuff), GFP_KERNEL); - if (!mdp->rx_skbuff) { - ret = -ENOMEM; - return ret; - } + if (!mdp->rx_skbuff) + return -ENOMEM; mdp->tx_skbuff = kcalloc(mdp->num_tx_ring, sizeof(*mdp->tx_skbuff), GFP_KERNEL); - if (!mdp->tx_skbuff) { - ret = -ENOMEM; - goto skb_ring_free; - } + if (!mdp->tx_skbuff) + goto ring_free; /* Allocate all Rx descriptors. */ rx_ringsize = sizeof(struct sh_eth_rxdesc) * mdp->num_rx_ring; mdp->rx_ring = dma_alloc_coherent(NULL, rx_ringsize, &mdp->rx_desc_dma, GFP_KERNEL); - if (!mdp->rx_ring) { - ret = -ENOMEM; - goto skb_ring_free; - } + if (!mdp->rx_ring) + goto ring_free; mdp->dirty_rx = 0; @@ -1241,42 +1249,15 @@ static int sh_eth_ring_init(struct net_device *ndev) tx_ringsize = sizeof(struct sh_eth_txdesc) * mdp->num_tx_ring; mdp->tx_ring = dma_alloc_coherent(NULL, tx_ringsize, &mdp->tx_desc_dma, GFP_KERNEL); - if (!mdp->tx_ring) { - ret = -ENOMEM; - goto desc_ring_free; - } - return ret; - -desc_ring_free: - /* free DMA buffer */ - dma_free_coherent(NULL, rx_ringsize, mdp->rx_ring, mdp->rx_desc_dma); + if (!mdp->tx_ring) + goto ring_free; + return 0; -skb_ring_free: - /* Free Rx and Tx skb ring buffer */ +ring_free: + /* Free Rx and Tx skb ring buffer and DMA buffer */ sh_eth_ring_free(ndev); - mdp->tx_ring = NULL; - mdp->rx_ring = NULL; - - return ret; -} - -static void sh_eth_free_dma_buffer(struct sh_eth_private *mdp) -{ - int ringsize; - - if (mdp->rx_ring) { - ringsize = sizeof(struct sh_eth_rxdesc) * mdp->num_rx_ring; - dma_free_coherent(NULL, ringsize, mdp->rx_ring, - mdp->rx_desc_dma); - mdp->rx_ring = NULL; - } - if (mdp->tx_ring) { - ringsize = sizeof(struct sh_eth_txdesc) * mdp->num_tx_ring; - dma_free_coherent(NULL, ringsize, mdp->tx_ring, - mdp->tx_desc_dma); - mdp->tx_ring = NULL; - } + return -ENOMEM; } static int sh_eth_dev_init(struct net_device *ndev, bool start) @@ -2239,10 +2220,8 @@ static int sh_eth_set_ringparam(struct net_device *ndev, sh_eth_dev_exit(ndev); - /* Free all the skbuffs in the Rx queue. */ + /* Free all the skbuffs in the Rx queue and the DMA buffers. */ sh_eth_ring_free(ndev); - /* Free DMA buffer */ - sh_eth_free_dma_buffer(mdp); } /* Set new parameters */ @@ -2487,12 +2466,9 @@ static int sh_eth_close(struct net_device *ndev) free_irq(ndev->irq, ndev); - /* Free all the skbuffs in the Rx queue. */ + /* Free all the skbuffs in the Rx queue and the DMA buffer. */ sh_eth_ring_free(ndev); - /* free DMA buffer */ - sh_eth_free_dma_buffer(mdp); - pm_runtime_put_sync(&mdp->pdev->dev); mdp->is_opened = 0; diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index 6e11ee6173ce..a3c42a376741 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -1247,11 +1247,9 @@ static int efx_init_io(struct efx_nic *efx) * masks event though they reject 46 bit masks. */ while (dma_mask > 0x7fffffffUL) { - if (dma_supported(&pci_dev->dev, dma_mask)) { - rc = dma_set_mask_and_coherent(&pci_dev->dev, dma_mask); - if (rc == 0) - break; - } + rc = dma_set_mask_and_coherent(&pci_dev->dev, dma_mask); + if (rc == 0) + break; dma_mask >>= 1; } if (rc) { @@ -3424,7 +3422,7 @@ out: * with our request for slot reset the mmio_enabled callback will never be * called, and the link_reset callback is not used by AER or EEH mechanisms. */ -static struct pci_error_handlers efx_err_handlers = { +static const struct pci_error_handlers efx_err_handlers = { .error_detected = efx_io_error_detected, .slot_reset = efx_io_slot_reset, .resume = efx_io_resume, diff --git a/drivers/net/ethernet/smsc/smsc911x.c b/drivers/net/ethernet/smsc/smsc911x.c index c860c9007e49..219a99b7a631 100644 --- a/drivers/net/ethernet/smsc/smsc911x.c +++ b/drivers/net/ethernet/smsc/smsc911x.c @@ -809,22 +809,17 @@ static int smsc911x_phy_check_loopbackpkt(struct smsc911x_data *pdata) static int smsc911x_phy_reset(struct smsc911x_data *pdata) { - struct phy_device *phy_dev = pdata->phy_dev; unsigned int temp; unsigned int i = 100000; - BUG_ON(!phy_dev); - BUG_ON(!phy_dev->bus); - - SMSC_TRACE(pdata, hw, "Performing PHY BCR Reset"); - smsc911x_mii_write(phy_dev->bus, phy_dev->addr, MII_BMCR, BMCR_RESET); + temp = smsc911x_reg_read(pdata, PMT_CTRL); + smsc911x_reg_write(pdata, PMT_CTRL, temp | PMT_CTRL_PHY_RST_); do { msleep(1); - temp = smsc911x_mii_read(phy_dev->bus, phy_dev->addr, - MII_BMCR); - } while ((i--) && (temp & BMCR_RESET)); + temp = smsc911x_reg_read(pdata, PMT_CTRL); + } while ((i--) && (temp & PMT_CTRL_PHY_RST_)); - if (temp & BMCR_RESET) { + if (unlikely(temp & PMT_CTRL_PHY_RST_)) { SMSC_WARN(pdata, hw, "PHY reset failed to complete"); return -EIO; } @@ -2296,7 +2291,7 @@ static int smsc911x_init(struct net_device *dev) } /* Reset the LAN911x */ - if (smsc911x_soft_reset(pdata)) + if (smsc911x_phy_reset(pdata) || smsc911x_soft_reset(pdata)) return -ENODEV; dev->flags |= IFF_MULTICAST; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c index 9d89bdbf029f..82de68b1a452 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c @@ -337,11 +337,11 @@ static int ipq806x_gmac_probe(struct platform_device *pdev) QSGMII_PHY_RX_SIGNAL_DETECT_EN | QSGMII_PHY_TX_DRIVER_EN | QSGMII_PHY_QSGMII_EN | - 0x4 << QSGMII_PHY_PHASE_LOOP_GAIN_OFFSET | - 0x3 << QSGMII_PHY_RX_DC_BIAS_OFFSET | - 0x1 << QSGMII_PHY_RX_INPUT_EQU_OFFSET | - 0x2 << QSGMII_PHY_CDR_PI_SLEW_OFFSET | - 0xC << QSGMII_PHY_TX_DRV_AMP_OFFSET); + 0x4ul << QSGMII_PHY_PHASE_LOOP_GAIN_OFFSET | + 0x3ul << QSGMII_PHY_RX_DC_BIAS_OFFSET | + 0x1ul << QSGMII_PHY_RX_INPUT_EQU_OFFSET | + 0x2ul << QSGMII_PHY_CDR_PI_SLEW_OFFSET | + 0xCul << QSGMII_PHY_TX_DRV_AMP_OFFSET); } plat_dat->has_gmac = true; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c index 11baa4b19779..0cd3ecff768b 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c @@ -354,7 +354,7 @@ static int gmac_clk_init(struct rk_priv_data *bsp_priv) static int gmac_clk_enable(struct rk_priv_data *bsp_priv, bool enable) { - int phy_iface = phy_iface = bsp_priv->phy_iface; + int phy_iface = bsp_priv->phy_iface; if (enable) { if (!bsp_priv->clk_enabled) { diff --git a/drivers/net/ethernet/synopsys/dwc_eth_qos.c b/drivers/net/ethernet/synopsys/dwc_eth_qos.c index 85b3326775b8..9066d7a8483c 100644 --- a/drivers/net/ethernet/synopsys/dwc_eth_qos.c +++ b/drivers/net/ethernet/synopsys/dwc_eth_qos.c @@ -2970,8 +2970,7 @@ err_out_unregister_netdev: err_out_clk_dis_aper: clk_disable_unprepare(lp->apb_pclk); err_out_free_netdev: - if (lp->phy_node) - of_node_put(lp->phy_node); + of_node_put(lp->phy_node); free_netdev(ndev); platform_set_drvdata(pdev, NULL); return ret; diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 040fbc1e5508..48b92c9de12a 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -2037,6 +2037,19 @@ static int cpsw_probe_dt(struct cpsw_priv *priv, continue; priv->phy_node = of_parse_phandle(slave_node, "phy-handle", 0); + if (of_phy_is_fixed_link(slave_node)) { + struct phy_device *pd; + + ret = of_phy_register_fixed_link(slave_node); + if (ret) + return ret; + pd = of_phy_find_device(slave_node); + if (!pd) + return -ENODEV; + snprintf(slave_data->phy_id, sizeof(slave_data->phy_id), + PHY_ID_FMT, pd->bus->id, pd->phy_id); + goto no_phy_slave; + } parp = of_get_property(slave_node, "phy_id", &lenp); if ((parp == NULL) || (lenp != (sizeof(void *) * 2))) { dev_err(&pdev->dev, "Missing slave[%d] phy_id property\n", i); diff --git a/drivers/net/ethernet/via/via-velocity.c b/drivers/net/ethernet/via/via-velocity.c index ae68afd50a15..f38696ceee74 100644 --- a/drivers/net/ethernet/via/via-velocity.c +++ b/drivers/net/ethernet/via/via-velocity.c @@ -345,13 +345,6 @@ VELOCITY_PARAM(flow_control, "Enable flow control ability"); */ VELOCITY_PARAM(speed_duplex, "Setting the speed and duplex mode"); -#define VAL_PKT_LEN_DEF 0 -/* ValPktLen[] is used for setting the checksum offload ability of NIC. - 0: Receive frame with invalid layer 2 length (Default) - 1: Drop frame with invalid layer 2 length -*/ -VELOCITY_PARAM(ValPktLen, "Receiving or Drop invalid 802.3 frame"); - #define WOL_OPT_DEF 0 #define WOL_OPT_MIN 0 #define WOL_OPT_MAX 7 @@ -494,7 +487,6 @@ static void velocity_get_options(struct velocity_opt *opts, int index, velocity_set_int_opt(&opts->flow_cntl, flow_control[index], FLOW_CNTL_MIN, FLOW_CNTL_MAX, FLOW_CNTL_DEF, "flow_control", devname); velocity_set_bool_opt(&opts->flags, IP_byte_align[index], IP_ALIG_DEF, VELOCITY_FLAGS_IP_ALIGN, "IP_byte_align", devname); - velocity_set_bool_opt(&opts->flags, ValPktLen[index], VAL_PKT_LEN_DEF, VELOCITY_FLAGS_VAL_PKT_LEN, "ValPktLen", devname); velocity_set_int_opt((int *) &opts->spd_dpx, speed_duplex[index], MED_LNK_MIN, MED_LNK_MAX, MED_LNK_DEF, "Media link mode", devname); velocity_set_int_opt(&opts->wol_opts, wol_opts[index], WOL_OPT_MIN, WOL_OPT_MAX, WOL_OPT_DEF, "Wake On Lan options", devname); opts->numrx = (opts->numrx & ~3); @@ -2055,8 +2047,9 @@ static int velocity_receive_frame(struct velocity_info *vptr, int idx) int pkt_len = le16_to_cpu(rd->rdesc0.len) & 0x3fff; struct sk_buff *skb; - if (rd->rdesc0.RSR & (RSR_STP | RSR_EDP)) { - VELOCITY_PRT(MSG_LEVEL_VERBOSE, KERN_ERR " %s : the received frame spans multiple RDs.\n", vptr->netdev->name); + if (unlikely(rd->rdesc0.RSR & (RSR_STP | RSR_EDP | RSR_RL))) { + if (rd->rdesc0.RSR & (RSR_STP | RSR_EDP)) + VELOCITY_PRT(MSG_LEVEL_VERBOSE, KERN_ERR " %s : the received frame spans multiple RDs.\n", vptr->netdev->name); stats->rx_length_errors++; return -EINVAL; } @@ -2069,17 +2062,6 @@ static int velocity_receive_frame(struct velocity_info *vptr, int idx) dma_sync_single_for_cpu(vptr->dev, rd_info->skb_dma, vptr->rx.buf_sz, DMA_FROM_DEVICE); - /* - * Drop frame not meeting IEEE 802.3 - */ - - if (vptr->flags & VELOCITY_FLAGS_VAL_PKT_LEN) { - if (rd->rdesc0.RSR & RSR_RL) { - stats->rx_length_errors++; - return -EINVAL; - } - } - velocity_rx_csum(rd, skb); if (velocity_rx_copy(&skb, pkt_len, vptr) < 0) { diff --git a/drivers/net/fjes/fjes_hw.c b/drivers/net/fjes/fjes_hw.c index 2d3848c9dc35..b103adb8d62e 100644 --- a/drivers/net/fjes/fjes_hw.c +++ b/drivers/net/fjes/fjes_hw.c @@ -143,9 +143,7 @@ static int fjes_hw_alloc_epbuf(struct epbuf_handler *epbh) static void fjes_hw_free_epbuf(struct epbuf_handler *epbh) { - if (epbh->buffer) - vfree(epbh->buffer); - + vfree(epbh->buffer); epbh->buffer = NULL; epbh->size = 0; @@ -601,7 +599,7 @@ int fjes_hw_unregister_buff_addr(struct fjes_hw *hw, int dest_epid) FJES_CMD_REQ_RES_CODE_BUSY) && (timeout > 0)) { msleep(200 + hw->my_epid * 20); - timeout -= (200 + hw->my_epid * 20); + timeout -= (200 + hw->my_epid * 20); res_buf->unshare_buffer.length = 0; res_buf->unshare_buffer.code = 0; diff --git a/drivers/net/ipvlan/ipvlan_core.c b/drivers/net/ipvlan/ipvlan_core.c index d50887e3df6d..8c48bb2a94ea 100644 --- a/drivers/net/ipvlan/ipvlan_core.c +++ b/drivers/net/ipvlan/ipvlan_core.c @@ -254,7 +254,7 @@ acct: } } -static int ipvlan_rcv_frame(struct ipvl_addr *addr, struct sk_buff *skb, +static int ipvlan_rcv_frame(struct ipvl_addr *addr, struct sk_buff **pskb, bool local) { struct ipvl_dev *ipvlan = addr->master; @@ -262,6 +262,7 @@ static int ipvlan_rcv_frame(struct ipvl_addr *addr, struct sk_buff *skb, unsigned int len; rx_handler_result_t ret = RX_HANDLER_CONSUMED; bool success = false; + struct sk_buff *skb = *pskb; len = skb->len + ETH_HLEN; if (unlikely(!(dev->flags & IFF_UP))) { @@ -273,6 +274,7 @@ static int ipvlan_rcv_frame(struct ipvl_addr *addr, struct sk_buff *skb, if (!skb) goto out; + *pskb = skb; skb->dev = dev; skb->pkt_type = PACKET_HOST; @@ -486,7 +488,7 @@ static int ipvlan_xmit_mode_l3(struct sk_buff *skb, struct net_device *dev) addr = ipvlan_addr_lookup(ipvlan->port, lyr3h, addr_type, true); if (addr) - return ipvlan_rcv_frame(addr, skb, true); + return ipvlan_rcv_frame(addr, &skb, true); out: skb->dev = ipvlan->phy_dev; @@ -506,7 +508,7 @@ static int ipvlan_xmit_mode_l2(struct sk_buff *skb, struct net_device *dev) if (lyr3h) { addr = ipvlan_addr_lookup(ipvlan->port, lyr3h, addr_type, true); if (addr) - return ipvlan_rcv_frame(addr, skb, true); + return ipvlan_rcv_frame(addr, &skb, true); } skb = skb_share_check(skb, GFP_ATOMIC); if (!skb) @@ -589,7 +591,7 @@ static rx_handler_result_t ipvlan_handle_mode_l3(struct sk_buff **pskb, addr = ipvlan_addr_lookup(port, lyr3h, addr_type, true); if (addr) - ret = ipvlan_rcv_frame(addr, skb, false); + ret = ipvlan_rcv_frame(addr, pskb, false); out: return ret; @@ -626,7 +628,7 @@ static rx_handler_result_t ipvlan_handle_mode_l2(struct sk_buff **pskb, addr = ipvlan_addr_lookup(port, lyr3h, addr_type, true); if (addr) - ret = ipvlan_rcv_frame(addr, skb, false); + ret = ipvlan_rcv_frame(addr, pskb, false); } return ret; @@ -651,5 +653,5 @@ rx_handler_result_t ipvlan_handle_frame(struct sk_buff **pskb) WARN_ONCE(true, "ipvlan_handle_frame() called for mode = [%hx]\n", port->mode); kfree_skb(skb); - return NET_RX_DROP; + return RX_HANDLER_CONSUMED; } diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 86f6c6292c27..06c8bfeaccd6 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -415,6 +415,7 @@ static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb) skb = ip_check_defrag(dev_net(skb->dev), skb, IP_DEFRAG_MACVLAN); if (!skb) return RX_HANDLER_CONSUMED; + *pskb = skb; eth = eth_hdr(skb); macvlan_forward_source(skb, port, eth->h_source); src = macvlan_hash_lookup(port, eth->h_source); @@ -456,6 +457,7 @@ static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb) goto out; } + *pskb = skb; skb->dev = dev; skb->pkt_type = PACKET_HOST; diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index 197c93937c2d..54036ae0a388 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -935,6 +935,9 @@ static ssize_t macvtap_do_read(struct macvtap_queue *q, /* Nothing to read, let's sleep */ schedule(); } + if (!noblock) + finish_wait(sk_sleep(&q->sk), &wait); + if (skb) { ret = macvtap_put_user(q, skb, to); if (unlikely(ret < 0)) @@ -942,8 +945,6 @@ static ssize_t macvtap_do_read(struct macvtap_queue *q, else consume_skb(skb); } - if (!noblock) - finish_wait(sk_sleep(&q->sk), &wait); return ret; } diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index 97f3acd44798..06ee6395117f 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -244,15 +244,6 @@ static void free_param_target(struct netconsole_target *nt) * <target>/... */ -struct netconsole_target_attr { - struct configfs_attribute attr; - ssize_t (*show)(struct netconsole_target *nt, - char *buf); - ssize_t (*store)(struct netconsole_target *nt, - const char *buf, - size_t count); -}; - static struct netconsole_target *to_target(struct config_item *item) { return item ? @@ -264,58 +255,62 @@ static struct netconsole_target *to_target(struct config_item *item) * Attribute operations for netconsole_target. */ -static ssize_t show_enabled(struct netconsole_target *nt, char *buf) +static ssize_t enabled_show(struct config_item *item, char *buf) { - return snprintf(buf, PAGE_SIZE, "%d\n", nt->enabled); + return snprintf(buf, PAGE_SIZE, "%d\n", to_target(item)->enabled); } -static ssize_t show_extended(struct netconsole_target *nt, char *buf) +static ssize_t extended_show(struct config_item *item, char *buf) { - return snprintf(buf, PAGE_SIZE, "%d\n", nt->extended); + return snprintf(buf, PAGE_SIZE, "%d\n", to_target(item)->extended); } -static ssize_t show_dev_name(struct netconsole_target *nt, char *buf) +static ssize_t dev_name_show(struct config_item *item, char *buf) { - return snprintf(buf, PAGE_SIZE, "%s\n", nt->np.dev_name); + return snprintf(buf, PAGE_SIZE, "%s\n", to_target(item)->np.dev_name); } -static ssize_t show_local_port(struct netconsole_target *nt, char *buf) +static ssize_t local_port_show(struct config_item *item, char *buf) { - return snprintf(buf, PAGE_SIZE, "%d\n", nt->np.local_port); + return snprintf(buf, PAGE_SIZE, "%d\n", to_target(item)->np.local_port); } -static ssize_t show_remote_port(struct netconsole_target *nt, char *buf) +static ssize_t remote_port_show(struct config_item *item, char *buf) { - return snprintf(buf, PAGE_SIZE, "%d\n", nt->np.remote_port); + return snprintf(buf, PAGE_SIZE, "%d\n", to_target(item)->np.remote_port); } -static ssize_t show_local_ip(struct netconsole_target *nt, char *buf) +static ssize_t local_ip_show(struct config_item *item, char *buf) { + struct netconsole_target *nt = to_target(item); + if (nt->np.ipv6) return snprintf(buf, PAGE_SIZE, "%pI6c\n", &nt->np.local_ip.in6); else return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.local_ip); } -static ssize_t show_remote_ip(struct netconsole_target *nt, char *buf) +static ssize_t remote_ip_show(struct config_item *item, char *buf) { + struct netconsole_target *nt = to_target(item); + if (nt->np.ipv6) return snprintf(buf, PAGE_SIZE, "%pI6c\n", &nt->np.remote_ip.in6); else return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.remote_ip); } -static ssize_t show_local_mac(struct netconsole_target *nt, char *buf) +static ssize_t local_mac_show(struct config_item *item, char *buf) { - struct net_device *dev = nt->np.dev; + struct net_device *dev = to_target(item)->np.dev; static const u8 bcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; return snprintf(buf, PAGE_SIZE, "%pM\n", dev ? dev->dev_addr : bcast); } -static ssize_t show_remote_mac(struct netconsole_target *nt, char *buf) +static ssize_t remote_mac_show(struct config_item *item, char *buf) { - return snprintf(buf, PAGE_SIZE, "%pM\n", nt->np.remote_mac); + return snprintf(buf, PAGE_SIZE, "%pM\n", to_target(item)->np.remote_mac); } /* @@ -325,23 +320,26 @@ static ssize_t show_remote_mac(struct netconsole_target *nt, char *buf) * would enable him to dynamically add new netpoll targets for new * network interfaces as and when they come up). */ -static ssize_t store_enabled(struct netconsole_target *nt, - const char *buf, - size_t count) +static ssize_t enabled_store(struct config_item *item, + const char *buf, size_t count) { + struct netconsole_target *nt = to_target(item); unsigned long flags; int enabled; int err; + mutex_lock(&dynamic_netconsole_mutex); err = kstrtoint(buf, 10, &enabled); if (err < 0) - return err; + goto out_unlock; + + err = -EINVAL; if (enabled < 0 || enabled > 1) - return -EINVAL; + goto out_unlock; if ((bool)enabled == nt->enabled) { pr_info("network logging has already %s\n", nt->enabled ? "started" : "stopped"); - return -EINVAL; + goto out_unlock; } if (enabled) { /* true */ @@ -358,7 +356,7 @@ static ssize_t store_enabled(struct netconsole_target *nt, err = netpoll_setup(&nt->np); if (err) - return err; + goto out_unlock; pr_info("netconsole: network logging started\n"); } else { /* false */ @@ -374,42 +372,56 @@ static ssize_t store_enabled(struct netconsole_target *nt, nt->enabled = enabled; + mutex_unlock(&dynamic_netconsole_mutex); return strnlen(buf, count); +out_unlock: + mutex_unlock(&dynamic_netconsole_mutex); + return err; } -static ssize_t store_extended(struct netconsole_target *nt, - const char *buf, - size_t count) +static ssize_t extended_store(struct config_item *item, const char *buf, + size_t count) { + struct netconsole_target *nt = to_target(item); int extended; int err; + mutex_lock(&dynamic_netconsole_mutex); if (nt->enabled) { pr_err("target (%s) is enabled, disable to update parameters\n", config_item_name(&nt->item)); - return -EINVAL; + err = -EINVAL; + goto out_unlock; } err = kstrtoint(buf, 10, &extended); if (err < 0) - return err; - if (extended < 0 || extended > 1) - return -EINVAL; + goto out_unlock; + if (extended < 0 || extended > 1) { + err = -EINVAL; + goto out_unlock; + } nt->extended = extended; + mutex_unlock(&dynamic_netconsole_mutex); return strnlen(buf, count); +out_unlock: + mutex_unlock(&dynamic_netconsole_mutex); + return err; } -static ssize_t store_dev_name(struct netconsole_target *nt, - const char *buf, - size_t count) +static ssize_t dev_name_store(struct config_item *item, const char *buf, + size_t count) { + struct netconsole_target *nt = to_target(item); size_t len; + mutex_lock(&dynamic_netconsole_mutex); if (nt->enabled) { pr_err("target (%s) is enabled, disable to update parameters\n", config_item_name(&nt->item)); + mutex_unlock(&dynamic_netconsole_mutex); return -EINVAL; } @@ -420,53 +432,66 @@ static ssize_t store_dev_name(struct netconsole_target *nt, if (nt->np.dev_name[len - 1] == '\n') nt->np.dev_name[len - 1] = '\0'; + mutex_unlock(&dynamic_netconsole_mutex); return strnlen(buf, count); } -static ssize_t store_local_port(struct netconsole_target *nt, - const char *buf, - size_t count) +static ssize_t local_port_store(struct config_item *item, const char *buf, + size_t count) { - int rv; + struct netconsole_target *nt = to_target(item); + int rv = -EINVAL; + mutex_lock(&dynamic_netconsole_mutex); if (nt->enabled) { pr_err("target (%s) is enabled, disable to update parameters\n", config_item_name(&nt->item)); - return -EINVAL; + goto out_unlock; } rv = kstrtou16(buf, 10, &nt->np.local_port); if (rv < 0) - return rv; + goto out_unlock; + mutex_unlock(&dynamic_netconsole_mutex); return strnlen(buf, count); +out_unlock: + mutex_unlock(&dynamic_netconsole_mutex); + return rv; } -static ssize_t store_remote_port(struct netconsole_target *nt, - const char *buf, - size_t count) +static ssize_t remote_port_store(struct config_item *item, + const char *buf, size_t count) { - int rv; + struct netconsole_target *nt = to_target(item); + int rv = -EINVAL; + mutex_lock(&dynamic_netconsole_mutex); if (nt->enabled) { pr_err("target (%s) is enabled, disable to update parameters\n", config_item_name(&nt->item)); - return -EINVAL; + goto out_unlock; } rv = kstrtou16(buf, 10, &nt->np.remote_port); if (rv < 0) - return rv; + goto out_unlock; + mutex_unlock(&dynamic_netconsole_mutex); return strnlen(buf, count); +out_unlock: + mutex_unlock(&dynamic_netconsole_mutex); + return rv; } -static ssize_t store_local_ip(struct netconsole_target *nt, - const char *buf, - size_t count) +static ssize_t local_ip_store(struct config_item *item, const char *buf, + size_t count) { + struct netconsole_target *nt = to_target(item); + + mutex_lock(&dynamic_netconsole_mutex); if (nt->enabled) { pr_err("target (%s) is enabled, disable to update parameters\n", config_item_name(&nt->item)); - return -EINVAL; + goto out_unlock; } if (strnchr(buf, count, ':')) { @@ -474,29 +499,35 @@ static ssize_t store_local_ip(struct netconsole_target *nt, if (in6_pton(buf, count, nt->np.local_ip.in6.s6_addr, -1, &end) > 0) { if (*end && *end != '\n') { pr_err("invalid IPv6 address at: <%c>\n", *end); - return -EINVAL; + goto out_unlock; } nt->np.ipv6 = true; } else - return -EINVAL; + goto out_unlock; } else { if (!nt->np.ipv6) { nt->np.local_ip.ip = in_aton(buf); } else - return -EINVAL; + goto out_unlock; } + mutex_unlock(&dynamic_netconsole_mutex); return strnlen(buf, count); +out_unlock: + mutex_unlock(&dynamic_netconsole_mutex); + return -EINVAL; } -static ssize_t store_remote_ip(struct netconsole_target *nt, - const char *buf, - size_t count) +static ssize_t remote_ip_store(struct config_item *item, const char *buf, + size_t count) { + struct netconsole_target *nt = to_target(item); + + mutex_lock(&dynamic_netconsole_mutex); if (nt->enabled) { pr_err("target (%s) is enabled, disable to update parameters\n", config_item_name(&nt->item)); - return -EINVAL; + goto out_unlock; } if (strnchr(buf, count, ':')) { @@ -504,74 +535,71 @@ static ssize_t store_remote_ip(struct netconsole_target *nt, if (in6_pton(buf, count, nt->np.remote_ip.in6.s6_addr, -1, &end) > 0) { if (*end && *end != '\n') { pr_err("invalid IPv6 address at: <%c>\n", *end); - return -EINVAL; + goto out_unlock; } nt->np.ipv6 = true; } else - return -EINVAL; + goto out_unlock; } else { if (!nt->np.ipv6) { nt->np.remote_ip.ip = in_aton(buf); } else - return -EINVAL; + goto out_unlock; } + mutex_unlock(&dynamic_netconsole_mutex); return strnlen(buf, count); +out_unlock: + mutex_unlock(&dynamic_netconsole_mutex); + return -EINVAL; } -static ssize_t store_remote_mac(struct netconsole_target *nt, - const char *buf, - size_t count) +static ssize_t remote_mac_store(struct config_item *item, const char *buf, + size_t count) { + struct netconsole_target *nt = to_target(item); u8 remote_mac[ETH_ALEN]; + mutex_lock(&dynamic_netconsole_mutex); if (nt->enabled) { pr_err("target (%s) is enabled, disable to update parameters\n", config_item_name(&nt->item)); - return -EINVAL; + goto out_unlock; } if (!mac_pton(buf, remote_mac)) - return -EINVAL; + goto out_unlock; if (buf[3 * ETH_ALEN - 1] && buf[3 * ETH_ALEN - 1] != '\n') - return -EINVAL; + goto out_unlock; memcpy(nt->np.remote_mac, remote_mac, ETH_ALEN); + mutex_unlock(&dynamic_netconsole_mutex); return strnlen(buf, count); +out_unlock: + mutex_unlock(&dynamic_netconsole_mutex); + return -EINVAL; } -/* - * Attribute definitions for netconsole_target. - */ - -#define NETCONSOLE_TARGET_ATTR_RO(_name) \ -static struct netconsole_target_attr netconsole_target_##_name = \ - __CONFIGFS_ATTR(_name, S_IRUGO, show_##_name, NULL) - -#define NETCONSOLE_TARGET_ATTR_RW(_name) \ -static struct netconsole_target_attr netconsole_target_##_name = \ - __CONFIGFS_ATTR(_name, S_IRUGO | S_IWUSR, show_##_name, store_##_name) - -NETCONSOLE_TARGET_ATTR_RW(enabled); -NETCONSOLE_TARGET_ATTR_RW(extended); -NETCONSOLE_TARGET_ATTR_RW(dev_name); -NETCONSOLE_TARGET_ATTR_RW(local_port); -NETCONSOLE_TARGET_ATTR_RW(remote_port); -NETCONSOLE_TARGET_ATTR_RW(local_ip); -NETCONSOLE_TARGET_ATTR_RW(remote_ip); -NETCONSOLE_TARGET_ATTR_RO(local_mac); -NETCONSOLE_TARGET_ATTR_RW(remote_mac); +CONFIGFS_ATTR(, enabled); +CONFIGFS_ATTR(, extended); +CONFIGFS_ATTR(, dev_name); +CONFIGFS_ATTR(, local_port); +CONFIGFS_ATTR(, remote_port); +CONFIGFS_ATTR(, local_ip); +CONFIGFS_ATTR(, remote_ip); +CONFIGFS_ATTR_RO(, local_mac); +CONFIGFS_ATTR(, remote_mac); static struct configfs_attribute *netconsole_target_attrs[] = { - &netconsole_target_enabled.attr, - &netconsole_target_extended.attr, - &netconsole_target_dev_name.attr, - &netconsole_target_local_port.attr, - &netconsole_target_remote_port.attr, - &netconsole_target_local_ip.attr, - &netconsole_target_remote_ip.attr, - &netconsole_target_local_mac.attr, - &netconsole_target_remote_mac.attr, + &attr_enabled, + &attr_extended, + &attr_dev_name, + &attr_local_port, + &attr_remote_port, + &attr_local_ip, + &attr_remote_ip, + &attr_local_mac, + &attr_remote_mac, NULL, }; @@ -584,43 +612,8 @@ static void netconsole_target_release(struct config_item *item) kfree(to_target(item)); } -static ssize_t netconsole_target_attr_show(struct config_item *item, - struct configfs_attribute *attr, - char *buf) -{ - ssize_t ret = -EINVAL; - struct netconsole_target *nt = to_target(item); - struct netconsole_target_attr *na = - container_of(attr, struct netconsole_target_attr, attr); - - if (na->show) - ret = na->show(nt, buf); - - return ret; -} - -static ssize_t netconsole_target_attr_store(struct config_item *item, - struct configfs_attribute *attr, - const char *buf, - size_t count) -{ - ssize_t ret = -EINVAL; - struct netconsole_target *nt = to_target(item); - struct netconsole_target_attr *na = - container_of(attr, struct netconsole_target_attr, attr); - - mutex_lock(&dynamic_netconsole_mutex); - if (na->store) - ret = na->store(nt, buf, count); - mutex_unlock(&dynamic_netconsole_mutex); - - return ret; -} - static struct configfs_item_operations netconsole_target_item_ops = { .release = netconsole_target_release, - .show_attribute = netconsole_target_attr_show, - .store_attribute = netconsole_target_attr_store, }; static struct config_item_type netconsole_target_type = { diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c index fabf11d32d27..2d020a3ec0b5 100644 --- a/drivers/net/phy/at803x.c +++ b/drivers/net/phy/at803x.c @@ -308,6 +308,8 @@ static struct phy_driver at803x_driver[] = { .flags = PHY_HAS_INTERRUPT, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, + .ack_interrupt = at803x_ack_interrupt, + .config_intr = at803x_config_intr, .driver = { .owner = THIS_MODULE, }, @@ -327,6 +329,8 @@ static struct phy_driver at803x_driver[] = { .flags = PHY_HAS_INTERRUPT, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, + .ack_interrupt = at803x_ack_interrupt, + .config_intr = at803x_config_intr, .driver = { .owner = THIS_MODULE, }, diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 5de8d5827536..0240552b50f3 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -1154,6 +1154,21 @@ static struct phy_driver marvell_drivers[] = { .driver = { .owner = THIS_MODULE }, }, { + .phy_id = MARVELL_PHY_ID_88E1540, + .phy_id_mask = MARVELL_PHY_ID_MASK, + .name = "Marvell 88E1540", + .features = PHY_GBIT_FEATURES, + .flags = PHY_HAS_INTERRUPT, + .config_aneg = &m88e1510_config_aneg, + .read_status = &marvell_read_status, + .ack_interrupt = &marvell_ack_interrupt, + .config_intr = &marvell_config_intr, + .did_interrupt = &m88e1121_did_interrupt, + .resume = &genphy_resume, + .suspend = &genphy_suspend, + .driver = { .owner = THIS_MODULE }, + }, + { .phy_id = MARVELL_PHY_ID_88E3016, .phy_id_mask = MARVELL_PHY_ID_MASK, .name = "Marvell 88E3016", @@ -1186,6 +1201,7 @@ static struct mdio_device_id __maybe_unused marvell_tbl[] = { { MARVELL_PHY_ID_88E1318S, MARVELL_PHY_ID_MASK }, { MARVELL_PHY_ID_88E1116R, MARVELL_PHY_ID_MASK }, { MARVELL_PHY_ID_88E1510, MARVELL_PHY_ID_MASK }, + { MARVELL_PHY_ID_88E1540, MARVELL_PHY_ID_MASK }, { MARVELL_PHY_ID_88E3016, MARVELL_PHY_ID_MASK }, { } }; diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index adb48abafc87..48ce6ef400fe 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -863,6 +863,9 @@ void phy_state_machine(struct work_struct *work) needs_aneg = true; break; case PHY_NOLINK: + if (phy_interrupt_is_valid(phydev)) + break; + err = phy_read_status(phydev); if (err) break; diff --git a/drivers/net/phy/vitesse.c b/drivers/net/phy/vitesse.c index 76cad712ddb2..dd295dbaa074 100644 --- a/drivers/net/phy/vitesse.c +++ b/drivers/net/phy/vitesse.c @@ -66,6 +66,7 @@ #define PHY_ID_VSC8244 0x000fc6c0 #define PHY_ID_VSC8514 0x00070670 #define PHY_ID_VSC8574 0x000704a0 +#define PHY_ID_VSC8601 0x00070420 #define PHY_ID_VSC8662 0x00070660 #define PHY_ID_VSC8221 0x000fc550 #define PHY_ID_VSC8211 0x000fc4b0 @@ -133,7 +134,8 @@ static int vsc82xx_config_intr(struct phy_device *phydev) (phydev->drv->phy_id == PHY_ID_VSC8234 || phydev->drv->phy_id == PHY_ID_VSC8244 || phydev->drv->phy_id == PHY_ID_VSC8514 || - phydev->drv->phy_id == PHY_ID_VSC8574) ? + phydev->drv->phy_id == PHY_ID_VSC8574 || + phydev->drv->phy_id == PHY_ID_VSC8601) ? MII_VSC8244_IMASK_MASK : MII_VSC8221_IMASK_MASK); else { @@ -272,6 +274,18 @@ static struct phy_driver vsc82xx_driver[] = { .config_intr = &vsc82xx_config_intr, .driver = { .owner = THIS_MODULE,}, }, { + .phy_id = PHY_ID_VSC8601, + .name = "Vitesse VSC8601", + .phy_id_mask = 0x000ffff0, + .features = PHY_GBIT_FEATURES, + .flags = PHY_HAS_INTERRUPT, + .config_init = &genphy_config_init, + .config_aneg = &genphy_config_aneg, + .read_status = &genphy_read_status, + .ack_interrupt = &vsc824x_ack_interrupt, + .config_intr = &vsc82xx_config_intr, + .driver = { .owner = THIS_MODULE,}, +}, { .phy_id = PHY_ID_VSC8662, .name = "Vitesse VSC8662", .phy_id_mask = 0x000ffff0, diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c index c78d3cb1b464..3da70bf9936a 100644 --- a/drivers/net/usb/cdc_ether.c +++ b/drivers/net/usb/cdc_ether.c @@ -696,6 +696,11 @@ static const struct usb_device_id products[] = { USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE), .driver_info = (kernel_ulong_t) &wwan_info, }, { + /* Dell DW5580 modules */ + USB_DEVICE_AND_INTERFACE_INFO(DELL_VENDOR_ID, 0x81ba, USB_CLASS_COMM, + USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE), + .driver_info = (kernel_ulong_t)&wwan_info, +}, { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE), .driver_info = (unsigned long) &cdc_info, diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c index 1e9cdca37014..f64b25c221e8 100644 --- a/drivers/net/usb/kaweth.c +++ b/drivers/net/usb/kaweth.c @@ -1177,12 +1177,6 @@ err_fw: INIT_DELAYED_WORK(&kaweth->lowmem_work, kaweth_resubmit_tl); usb_set_intfdata(intf, kaweth); -#if 0 -// dma_supported() is deeply broken on almost all architectures - if (dma_supported (dev, 0xffffffffffffffffULL)) - kaweth->net->features |= NETIF_F_HIGHDMA; -#endif - SET_NETDEV_DEV(netdev, dev); if (register_netdev(netdev) != 0) { dev_err(dev, "Error registering netdev.\n"); diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index c54719984c4b..34799eaace41 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -771,6 +771,7 @@ static const struct usb_device_id products[] = { {QMI_GOBI_DEVICE(0x05c6, 0x9245)}, /* Samsung Gobi 2000 Modem device (VL176) */ {QMI_GOBI_DEVICE(0x03f0, 0x251d)}, /* HP Gobi 2000 Modem device (VP412) */ {QMI_GOBI_DEVICE(0x05c6, 0x9215)}, /* Acer Gobi 2000 Modem device (VP413) */ + {QMI_FIXED_INTF(0x05c6, 0x9215, 4)}, /* Quectel EC20 Mini PCIe */ {QMI_GOBI_DEVICE(0x05c6, 0x9265)}, /* Asus Gobi 2000 Modem device (VR305) */ {QMI_GOBI_DEVICE(0x05c6, 0x9235)}, /* Top Global Gobi 2000 Modem device (VR306) */ {QMI_GOBI_DEVICE(0x05c6, 0x9275)}, /* iRex Technologies Gobi 2000 Modem device (VR307) */ @@ -802,10 +803,24 @@ static const struct usb_device_id products[] = { }; MODULE_DEVICE_TABLE(usb, products); +static bool quectel_ec20_detected(struct usb_interface *intf) +{ + struct usb_device *dev = interface_to_usbdev(intf); + + if (dev->actconfig && + le16_to_cpu(dev->descriptor.idVendor) == 0x05c6 && + le16_to_cpu(dev->descriptor.idProduct) == 0x9215 && + dev->actconfig->desc.bNumInterfaces == 5) + return true; + + return false; +} + static int qmi_wwan_probe(struct usb_interface *intf, const struct usb_device_id *prod) { struct usb_device_id *id = (struct usb_device_id *)prod; + struct usb_interface_descriptor *desc = &intf->cur_altsetting->desc; /* Workaround to enable dynamic IDs. This disables usbnet * blacklisting functionality. Which, if required, can be @@ -817,6 +832,12 @@ static int qmi_wwan_probe(struct usb_interface *intf, id->driver_info = (unsigned long)&qmi_wwan_info; } + /* Quectel EC20 quirk where we've QMI on interface 4 instead of 0 */ + if (quectel_ec20_detected(intf) && desc->bInterfaceNumber == 0) { + dev_dbg(&intf->dev, "Quectel EC20 quirk, skipping interface 0\n"); + return -ENODEV; + } + return usbnet_probe(intf, id); } diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 060918f49fea..0744bf2ef2d6 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -1662,12 +1662,6 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) * bind() should set rx_urb_size in that case. */ dev->hard_mtu = net->mtu + net->hard_header_len; -#if 0 -// dma_supported() is deeply broken on almost all architectures - // possible with some EHCI controllers - if (dma_supported (&udev->dev, DMA_BIT_MASK(64))) - net->features |= NETIF_F_HIGHDMA; -#endif net->netdev_ops = &usbnet_netdev_ops; net->watchdog_timeo = TX_TIMEOUT_JIFFIES; diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c index 46f4caddccbe..899ea4288197 100644 --- a/drivers/net/vmxnet3/vmxnet3_drv.c +++ b/drivers/net/vmxnet3/vmxnet3_drv.c @@ -2157,12 +2157,13 @@ vmxnet3_set_mc(struct net_device *netdev) if (!netdev_mc_empty(netdev)) { new_table = vmxnet3_copy_mc(netdev); if (new_table) { - rxConf->mfTableLen = cpu_to_le16( - netdev_mc_count(netdev) * ETH_ALEN); + size_t sz = netdev_mc_count(netdev) * ETH_ALEN; + + rxConf->mfTableLen = cpu_to_le16(sz); new_table_pa = dma_map_single( &adapter->pdev->dev, new_table, - rxConf->mfTableLen, + sz, PCI_DMA_TODEVICE); } diff --git a/drivers/net/vmxnet3/vmxnet3_int.h b/drivers/net/vmxnet3/vmxnet3_int.h index 3f859a55c035..4c58c83dc225 100644 --- a/drivers/net/vmxnet3/vmxnet3_int.h +++ b/drivers/net/vmxnet3/vmxnet3_int.h @@ -69,10 +69,10 @@ /* * Version numbers */ -#define VMXNET3_DRIVER_VERSION_STRING "1.4.3.0-k" +#define VMXNET3_DRIVER_VERSION_STRING "1.4.4.0-k" /* a 32-bit int, each byte encode a verion number in VMXNET3_DRIVER_VERSION */ -#define VMXNET3_DRIVER_VERSION_NUM 0x01040300 +#define VMXNET3_DRIVER_VERSION_NUM 0x01040400 #if defined(CONFIG_PCI_MSI) /* RSS only makes sense if MSI-X is supported. */ diff --git a/drivers/nfc/nfcmrvl/Kconfig b/drivers/nfc/nfcmrvl/Kconfig index 444ca94697d9..670af76922e0 100644 --- a/drivers/nfc/nfcmrvl/Kconfig +++ b/drivers/nfc/nfcmrvl/Kconfig @@ -44,7 +44,7 @@ config NFC_MRVL_I2C config NFC_MRVL_SPI tristate "Marvell NFC-over-SPI driver" - depends on NFC_MRVL && SPI + depends on NFC_MRVL && NFC_NCI_SPI help Marvell NFC-over-SPI driver. diff --git a/drivers/nfc/nfcmrvl/fw_dnld.c b/drivers/nfc/nfcmrvl/fw_dnld.c index bfa771392b1f..f8dcdf4b24f6 100644 --- a/drivers/nfc/nfcmrvl/fw_dnld.c +++ b/drivers/nfc/nfcmrvl/fw_dnld.c @@ -113,9 +113,12 @@ static void fw_dnld_over(struct nfcmrvl_private *priv, u32 error) } atomic_set(&priv->ndev->cmd_cnt, 0); - del_timer_sync(&priv->ndev->cmd_timer); - del_timer_sync(&priv->fw_dnld.timer); + if (timer_pending(&priv->ndev->cmd_timer)) + del_timer_sync(&priv->ndev->cmd_timer); + + if (timer_pending(&priv->fw_dnld.timer)) + del_timer_sync(&priv->fw_dnld.timer); nfc_info(priv->dev, "FW loading over (%d)]\n", error); @@ -472,9 +475,12 @@ void nfcmrvl_fw_dnld_deinit(struct nfcmrvl_private *priv) void nfcmrvl_fw_dnld_recv_frame(struct nfcmrvl_private *priv, struct sk_buff *skb) { + /* Discard command timer */ + if (timer_pending(&priv->ndev->cmd_timer)) + del_timer_sync(&priv->ndev->cmd_timer); + /* Allow next command */ atomic_set(&priv->ndev->cmd_cnt, 1); - del_timer_sync(&priv->ndev->cmd_timer); /* Queue and trigger rx work */ skb_queue_tail(&priv->fw_dnld.rx_q, skb); diff --git a/drivers/nfc/nfcmrvl/main.c b/drivers/nfc/nfcmrvl/main.c index 8079ae0de21e..51c8240a1672 100644 --- a/drivers/nfc/nfcmrvl/main.c +++ b/drivers/nfc/nfcmrvl/main.c @@ -194,6 +194,9 @@ void nfcmrvl_nci_unregister_dev(struct nfcmrvl_private *priv) nfcmrvl_fw_dnld_deinit(priv); + if (priv->config.reset_n_io) + devm_gpio_free(priv->dev, priv->config.reset_n_io); + nci_unregister_device(ndev); nci_free_device(ndev); kfree(priv); @@ -251,8 +254,6 @@ void nfcmrvl_chip_halt(struct nfcmrvl_private *priv) gpio_set_value(priv->config.reset_n_io, 0); } -#ifdef CONFIG_OF - int nfcmrvl_parse_dt(struct device_node *node, struct nfcmrvl_platform_data *pdata) { @@ -275,16 +276,6 @@ int nfcmrvl_parse_dt(struct device_node *node, return 0; } - -#else - -int nfcmrvl_parse_dt(struct device_node *node, - struct nfcmrvl_platform_data *pdata) -{ - return -ENODEV; -} - -#endif EXPORT_SYMBOL_GPL(nfcmrvl_parse_dt); MODULE_AUTHOR("Marvell International Ltd."); diff --git a/drivers/nfc/nfcmrvl/uart.c b/drivers/nfc/nfcmrvl/uart.c index f3d041c4f249..83a99e38e7bd 100644 --- a/drivers/nfc/nfcmrvl/uart.c +++ b/drivers/nfc/nfcmrvl/uart.c @@ -67,8 +67,6 @@ static struct nfcmrvl_if_ops uart_ops = { .nci_update_config = nfcmrvl_uart_nci_update_config }; -#ifdef CONFIG_OF - static int nfcmrvl_uart_parse_dt(struct device_node *node, struct nfcmrvl_platform_data *pdata) { @@ -102,16 +100,6 @@ static int nfcmrvl_uart_parse_dt(struct device_node *node, return 0; } -#else - -static int nfcmrvl_uart_parse_dt(struct device_node *node, - struct nfcmrvl_platform_data *pdata) -{ - return -ENODEV; -} - -#endif - /* ** NCI UART OPS */ @@ -152,10 +140,6 @@ static int nfcmrvl_nci_uart_open(struct nci_uart *nu) nu->drv_data = priv; nu->ndev = priv->ndev; - /* Set BREAK */ - if (priv->config.break_control && nu->tty->ops->break_ctl) - nu->tty->ops->break_ctl(nu->tty, -1); - return 0; } @@ -174,6 +158,9 @@ static void nfcmrvl_nci_uart_tx_start(struct nci_uart *nu) { struct nfcmrvl_private *priv = (struct nfcmrvl_private *)nu->drv_data; + if (priv->ndev->nfc_dev->fw_download_in_progress) + return; + /* Remove BREAK to wake up the NFCC */ if (priv->config.break_control && nu->tty->ops->break_ctl) { nu->tty->ops->break_ctl(nu->tty, 0); @@ -185,13 +172,18 @@ static void nfcmrvl_nci_uart_tx_done(struct nci_uart *nu) { struct nfcmrvl_private *priv = (struct nfcmrvl_private *)nu->drv_data; + if (priv->ndev->nfc_dev->fw_download_in_progress) + return; + /* ** To ensure that if the NFCC goes in DEEP SLEEP sate we can wake him ** up. we set BREAK. Once we will be ready to send again we will remove ** it. */ - if (priv->config.break_control && nu->tty->ops->break_ctl) + if (priv->config.break_control && nu->tty->ops->break_ctl) { nu->tty->ops->break_ctl(nu->tty, -1); + usleep_range(1000, 3000); + } } static struct nci_uart nfcmrvl_nci_uart = { diff --git a/drivers/nvdimm/blk.c b/drivers/nvdimm/blk.c index 0df77cb07df6..91a336ea8c4f 100644 --- a/drivers/nvdimm/blk.c +++ b/drivers/nvdimm/blk.c @@ -161,7 +161,7 @@ static int nd_blk_do_bvec(struct nd_blk_device *blk_dev, return err; } -static void nd_blk_make_request(struct request_queue *q, struct bio *bio) +static blk_qc_t nd_blk_make_request(struct request_queue *q, struct bio *bio) { struct block_device *bdev = bio->bi_bdev; struct gendisk *disk = bdev->bd_disk; @@ -208,6 +208,7 @@ static void nd_blk_make_request(struct request_queue *q, struct bio *bio) out: bio_endio(bio); + return BLK_QC_T_NONE; } static int nd_blk_rw_bytes(struct nd_namespace_common *ndns, diff --git a/drivers/nvdimm/btt.c b/drivers/nvdimm/btt.c index eae93ab8ffcd..efb2c1ceef98 100644 --- a/drivers/nvdimm/btt.c +++ b/drivers/nvdimm/btt.c @@ -1150,7 +1150,7 @@ static int btt_do_bvec(struct btt *btt, struct bio_integrity_payload *bip, return ret; } -static void btt_make_request(struct request_queue *q, struct bio *bio) +static blk_qc_t btt_make_request(struct request_queue *q, struct bio *bio) { struct bio_integrity_payload *bip = bio_integrity(bio); struct btt *btt = q->queuedata; @@ -1198,6 +1198,7 @@ static void btt_make_request(struct request_queue *q, struct bio *bio) out: bio_endio(bio); + return BLK_QC_T_NONE; } static int btt_rw_page(struct block_device *bdev, sector_t sector, diff --git a/drivers/nvdimm/e820.c b/drivers/nvdimm/e820.c index 8282db2ef99e..b0045a505dc8 100644 --- a/drivers/nvdimm/e820.c +++ b/drivers/nvdimm/e820.c @@ -3,6 +3,7 @@ * Copyright (c) 2015, Intel Corporation. */ #include <linux/platform_device.h> +#include <linux/memory_hotplug.h> #include <linux/libnvdimm.h> #include <linux/module.h> @@ -25,6 +26,18 @@ static int e820_pmem_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_MEMORY_HOTPLUG +static int e820_range_to_nid(resource_size_t addr) +{ + return memory_add_physaddr_to_nid(addr); +} +#else +static int e820_range_to_nid(resource_size_t addr) +{ + return NUMA_NO_NODE; +} +#endif + static int e820_pmem_probe(struct platform_device *pdev) { static struct nvdimm_bus_descriptor nd_desc; @@ -48,7 +61,7 @@ static int e820_pmem_probe(struct platform_device *pdev) memset(&ndr_desc, 0, sizeof(ndr_desc)); ndr_desc.res = p; ndr_desc.attr_groups = e820_pmem_region_attribute_groups; - ndr_desc.numa_node = NUMA_NO_NODE; + ndr_desc.numa_node = e820_range_to_nid(p->start); set_bit(ND_REGION_PAGEMAP, &ndr_desc.flags); if (!nvdimm_pmem_region_create(nvdimm_bus, &ndr_desc)) goto err; diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c index 349f03e7ed06..8ee79893d2f5 100644 --- a/drivers/nvdimm/pmem.c +++ b/drivers/nvdimm/pmem.c @@ -64,7 +64,7 @@ static void pmem_do_bvec(struct pmem_device *pmem, struct page *page, kunmap_atomic(mem); } -static void pmem_make_request(struct request_queue *q, struct bio *bio) +static blk_qc_t pmem_make_request(struct request_queue *q, struct bio *bio) { bool do_acct; unsigned long start; @@ -84,6 +84,7 @@ static void pmem_make_request(struct request_queue *q, struct bio *bio) wmb_pmem(); bio_endio(bio); + return BLK_QC_T_NONE; } static int pmem_rw_page(struct block_device *bdev, sector_t sector, @@ -104,22 +105,11 @@ static long pmem_direct_access(struct block_device *bdev, sector_t sector, { struct pmem_device *pmem = bdev->bd_disk->private_data; resource_size_t offset = sector * 512 + pmem->data_offset; - resource_size_t size; - - if (pmem->data_offset) { - /* - * Limit the direct_access() size to what is covered by - * the memmap - */ - size = (pmem->size - offset) & ~ND_PFN_MASK; - } else - size = pmem->size - offset; - - /* FIXME convert DAX to comprehend that this mapping has a lifetime */ + *kaddr = pmem->virt_addr + offset; *pfn = (pmem->phys_addr + offset) >> PAGE_SHIFT; - return size; + return pmem->size - offset; } static const struct block_device_operations pmem_fops = { diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index 97b6640a3745..8187df204695 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -90,7 +90,7 @@ static struct class *nvme_class; static int __nvme_reset(struct nvme_dev *dev); static int nvme_reset(struct nvme_dev *dev); -static int nvme_process_cq(struct nvme_queue *nvmeq); +static void nvme_process_cq(struct nvme_queue *nvmeq); static void nvme_dead_ctrl(struct nvme_dev *dev); struct async_cmd_info { @@ -935,7 +935,7 @@ static int nvme_queue_rq(struct blk_mq_hw_ctx *hctx, return BLK_MQ_RQ_QUEUE_BUSY; } -static int nvme_process_cq(struct nvme_queue *nvmeq) +static void __nvme_process_cq(struct nvme_queue *nvmeq, unsigned int *tag) { u16 head, phase; @@ -953,6 +953,8 @@ static int nvme_process_cq(struct nvme_queue *nvmeq) head = 0; phase = !phase; } + if (tag && *tag == cqe.command_id) + *tag = -1; ctx = nvme_finish_cmd(nvmeq, cqe.command_id, &fn); fn(nvmeq, ctx, &cqe); } @@ -964,14 +966,18 @@ static int nvme_process_cq(struct nvme_queue *nvmeq) * a big problem. */ if (head == nvmeq->cq_head && phase == nvmeq->cq_phase) - return 0; + return; writel(head, nvmeq->q_db + nvmeq->dev->db_stride); nvmeq->cq_head = head; nvmeq->cq_phase = phase; nvmeq->cqe_seen = 1; - return 1; +} + +static void nvme_process_cq(struct nvme_queue *nvmeq) +{ + __nvme_process_cq(nvmeq, NULL); } static irqreturn_t nvme_irq(int irq, void *data) @@ -995,6 +1001,23 @@ static irqreturn_t nvme_irq_check(int irq, void *data) return IRQ_WAKE_THREAD; } +static int nvme_poll(struct blk_mq_hw_ctx *hctx, unsigned int tag) +{ + struct nvme_queue *nvmeq = hctx->driver_data; + + if ((le16_to_cpu(nvmeq->cqes[nvmeq->cq_head].status) & 1) == + nvmeq->cq_phase) { + spin_lock_irq(&nvmeq->q_lock); + __nvme_process_cq(nvmeq, &tag); + spin_unlock_irq(&nvmeq->q_lock); + + if (tag == -1) + return 1; + } + + return 0; +} + /* * Returns 0 on success. If the result is negative, it's a Linux error code; * if the result is positive, it's an NVM Express status code @@ -1656,6 +1679,7 @@ static struct blk_mq_ops nvme_mq_ops = { .init_hctx = nvme_init_hctx, .init_request = nvme_init_request, .timeout = nvme_timeout, + .poll = nvme_poll, }; static void nvme_dev_remove_admin(struct nvme_dev *dev) @@ -1701,7 +1725,7 @@ static int nvme_configure_admin_queue(struct nvme_dev *dev) { int result; u32 aqa; - u64 cap = readq(&dev->bar->cap); + u64 cap = lo_hi_readq(&dev->bar->cap); struct nvme_queue *nvmeq; unsigned page_shift = PAGE_SHIFT; unsigned dev_page_min = NVME_CAP_MPSMIN(cap) + 12; @@ -1750,8 +1774,8 @@ static int nvme_configure_admin_queue(struct nvme_dev *dev) dev->ctrl_config |= NVME_CC_IOSQES | NVME_CC_IOCQES; writel(aqa, &dev->bar->aqa); - writeq(nvmeq->sq_dma_addr, &dev->bar->asq); - writeq(nvmeq->cq_dma_addr, &dev->bar->acq); + lo_hi_writeq(nvmeq->sq_dma_addr, &dev->bar->asq); + lo_hi_writeq(nvmeq->cq_dma_addr, &dev->bar->acq); result = nvme_enable_ctrl(dev, cap); if (result) @@ -2582,7 +2606,7 @@ static int nvme_dev_add(struct nvme_dev *dev) struct pci_dev *pdev = to_pci_dev(dev->dev); int res; struct nvme_id_ctrl *ctrl; - int shift = NVME_CAP_MPSMIN(readq(&dev->bar->cap)) + 12; + int shift = NVME_CAP_MPSMIN(lo_hi_readq(&dev->bar->cap)) + 12; res = nvme_identify_ctrl(dev, &ctrl); if (res) { @@ -2598,6 +2622,8 @@ static int nvme_dev_add(struct nvme_dev *dev) memcpy(dev->firmware_rev, ctrl->fr, sizeof(ctrl->fr)); if (ctrl->mdts) dev->max_hw_sectors = 1 << (ctrl->mdts + shift - 9); + else + dev->max_hw_sectors = UINT_MAX; if ((pdev->vendor == PCI_VENDOR_ID_INTEL) && (pdev->device == 0x0953) && ctrl->vs[3]) { unsigned int max_hw_sectors; @@ -2671,7 +2697,7 @@ static int nvme_dev_map(struct nvme_dev *dev) goto unmap; } - cap = readq(&dev->bar->cap); + cap = lo_hi_readq(&dev->bar->cap); dev->q_depth = min_t(int, NVME_CAP_MQES(cap) + 1, NVME_Q_DEPTH); dev->db_stride = 1 << NVME_CAP_STRIDE(cap); dev->dbs = ((void __iomem *)dev->bar) + 4096; @@ -2734,7 +2760,7 @@ static void nvme_wait_dq(struct nvme_delq_ctx *dq, struct nvme_dev *dev) * queues than admin tags. */ set_current_state(TASK_RUNNING); - nvme_disable_ctrl(dev, readq(&dev->bar->cap)); + nvme_disable_ctrl(dev, lo_hi_readq(&dev->bar->cap)); nvme_clear_queue(dev->queues[0]); flush_kthread_worker(dq->worker); nvme_disable_queue(dev, 0); @@ -3377,6 +3403,7 @@ static const struct pci_error_handlers nvme_err_handler = { static const struct pci_device_id nvme_id_table[] = { { PCI_DEVICE_CLASS(PCI_CLASS_STORAGE_EXPRESS, 0xffffff) }, + { PCI_DEVICE(PCI_VENDOR_ID_APPLE, 0x2001) }, { 0, } }; MODULE_DEVICE_TABLE(pci, nvme_id_table); diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c index ff27177f49ed..b1449f71601c 100644 --- a/drivers/of/of_pci.c +++ b/drivers/of/of_pci.c @@ -143,26 +143,6 @@ void of_pci_check_probe_only(void) } EXPORT_SYMBOL_GPL(of_pci_check_probe_only); -/** - * of_pci_dma_configure - Setup DMA configuration - * @dev: ptr to pci_dev struct of the PCI device - * - * Function to update PCI devices's DMA configuration using the same - * info from the OF node of host bridge's parent (if any). - */ -void of_pci_dma_configure(struct pci_dev *pci_dev) -{ - struct device *dev = &pci_dev->dev; - struct device *bridge = pci_get_host_bridge_device(pci_dev); - - if (!bridge->parent) - return; - - of_dma_configure(dev, bridge->parent->of_node); - pci_put_host_bridge_device(bridge); -} -EXPORT_SYMBOL_GPL(of_pci_dma_configure); - #if defined(CONFIG_OF_ADDRESS) /** * of_pci_get_host_bridge_resources - Parse PCI host bridge resources from DT diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c index 62f467b8ccae..be77e75c587d 100644 --- a/drivers/of/of_reserved_mem.c +++ b/drivers/of/of_reserved_mem.c @@ -124,6 +124,10 @@ static int __init __reserved_mem_alloc_size(unsigned long node, align = dt_mem_next_cell(dt_root_addr_cells, &prop); } + /* Need adjust the alignment to satisfy the CMA requirement */ + if (IS_ENABLED(CONFIG_CMA) && of_flat_dt_is_compatible(node, "shared-dma-pool")) + align = max(align, (phys_addr_t)PAGE_SIZE << max(MAX_ORDER - 1, pageblock_order)); + prop = of_get_flat_dt_prop(node, "alloc-ranges", &len); if (prop) { @@ -226,10 +230,9 @@ static void __init __rmem_check_for_overlap(void) this_end = this->base + this->size; next_end = next->base + next->size; - WARN(1, - "Reserved memory: OVERLAP DETECTED!\n%s (%pa--%pa) overlaps with %s (%pa--%pa)\n", - this->name, &this->base, &this_end, - next->name, &next->base, &next_end); + pr_err("Reserved memory: OVERLAP DETECTED!\n%s (%pa--%pa) overlaps with %s (%pa--%pa)\n", + this->name, &this->base, &this_end, + next->name, &next->base, &next_end); } } } diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c index 957b42198328..8e11fb2831cd 100644 --- a/drivers/parisc/ccio-dma.c +++ b/drivers/parisc/ccio-dma.c @@ -704,8 +704,6 @@ ccio_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt) * ccio_dma_supported - Verify the IOMMU supports the DMA address range. * @dev: The PCI device. * @mask: A bit mask describing the DMA address range of the device. - * - * This function implements the pci_dma_supported function. */ static int ccio_dma_supported(struct device *dev, u64 mask) diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index f53b8e85f137..edb1984201e9 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -6,6 +6,7 @@ #include <linux/delay.h> #include <linux/init.h> #include <linux/pci.h> +#include <linux/of_device.h> #include <linux/of_pci.h> #include <linux/pci_hotplug.h> #include <linux/slab.h> @@ -13,6 +14,7 @@ #include <linux/cpumask.h> #include <linux/pci-aspm.h> #include <linux/aer.h> +#include <linux/acpi.h> #include <asm-generic/pci-bridge.h> #include "pci.h" @@ -1672,6 +1674,34 @@ static void pci_set_msi_domain(struct pci_dev *dev) dev_set_msi_domain(&dev->dev, d); } +/** + * pci_dma_configure - Setup DMA configuration + * @dev: ptr to pci_dev struct of the PCI device + * + * Function to update PCI devices's DMA configuration using the same + * info from the OF node or ACPI node of host bridge's parent (if any). + */ +static void pci_dma_configure(struct pci_dev *dev) +{ + struct device *bridge = pci_get_host_bridge_device(dev); + + if (IS_ENABLED(CONFIG_OF) && + bridge->parent && bridge->parent->of_node) { + of_dma_configure(&dev->dev, bridge->parent->of_node); + } else if (has_acpi_companion(bridge)) { + struct acpi_device *adev = to_acpi_device_node(bridge->fwnode); + enum dev_dma_attr attr = acpi_get_dma_attr(adev); + + if (attr == DEV_DMA_NOT_SUPPORTED) + dev_warn(&dev->dev, "DMA not supported.\n"); + else + arch_setup_dma_ops(&dev->dev, 0, 0, NULL, + attr == DEV_DMA_COHERENT); + } + + pci_put_host_bridge_device(bridge); +} + void pci_device_add(struct pci_dev *dev, struct pci_bus *bus) { int ret; @@ -1685,7 +1715,7 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus) dev->dev.dma_mask = &dev->dma_mask; dev->dev.dma_parms = &dev->dma_parms; dev->dev.coherent_dma_mask = 0xffffffffull; - of_pci_dma_configure(dev); + pci_dma_configure(dev); pci_set_dma_max_seg_size(dev, 65536); pci_set_dma_seg_boundary(dev, 0xffffffff); diff --git a/drivers/platform/chrome/Kconfig b/drivers/platform/chrome/Kconfig index 3271cd1abe7c..d03df4a60d05 100644 --- a/drivers/platform/chrome/Kconfig +++ b/drivers/platform/chrome/Kconfig @@ -4,6 +4,7 @@ menuconfig CHROME_PLATFORMS bool "Platform support for Chrome hardware" + depends on X86 || ARM || ARM64 || COMPILE_TEST ---help--- Say Y here to get to see options for platform support for various Chromebooks and Chromeboxes. This option alone does @@ -39,7 +40,7 @@ config CHROMEOS_PSTORE config CROS_EC_CHARDEV tristate "Chrome OS Embedded Controller userspace device interface" - depends on CROS_EC_PROTO + depends on MFD_CROS_EC ---help--- This driver adds support to talk with the ChromeOS EC from userspace. @@ -48,7 +49,7 @@ config CROS_EC_CHARDEV config CROS_EC_LPC tristate "ChromeOS Embedded Controller (LPC)" - depends on MFD_CROS_EC && CROS_EC_PROTO && (X86 || COMPILE_TEST) + depends on MFD_CROS_EC && (X86 || COMPILE_TEST) help If you say Y here, you get support for talking to the ChromeOS EC over an LPC bus. This uses a simple byte-level protocol with a diff --git a/drivers/platform/chrome/Makefile b/drivers/platform/chrome/Makefile index 4a11b010f5d8..bc498bda8211 100644 --- a/drivers/platform/chrome/Makefile +++ b/drivers/platform/chrome/Makefile @@ -1,7 +1,8 @@ obj-$(CONFIG_CHROMEOS_LAPTOP) += chromeos_laptop.o obj-$(CONFIG_CHROMEOS_PSTORE) += chromeos_pstore.o -cros_ec_devs-objs := cros_ec_dev.o cros_ec_sysfs.o cros_ec_lightbar.o +cros_ec_devs-objs := cros_ec_dev.o cros_ec_sysfs.o \ + cros_ec_lightbar.o cros_ec_vbc.o obj-$(CONFIG_CROS_EC_CHARDEV) += cros_ec_devs.o obj-$(CONFIG_CROS_EC_LPC) += cros_ec_lpc.o obj-$(CONFIG_CROS_EC_PROTO) += cros_ec_proto.o diff --git a/drivers/platform/chrome/chromeos_laptop.c b/drivers/platform/chrome/chromeos_laptop.c index 02072749fff3..2b441e9ae593 100644 --- a/drivers/platform/chrome/chromeos_laptop.c +++ b/drivers/platform/chrome/chromeos_laptop.c @@ -47,8 +47,8 @@ static const char *i2c_adapter_names[] = { "SMBus I801 adapter", "i915 gmbus vga", "i915 gmbus panel", - "i2c-designware-pci", - "i2c-designware-pci", + "Synopsys DesignWare I2C adapter", + "Synopsys DesignWare I2C adapter", }; /* Keep this enum consistent with i2c_adapter_names */ diff --git a/drivers/platform/chrome/cros_ec_dev.c b/drivers/platform/chrome/cros_ec_dev.c index e8fcdc237029..d45cd254ed1c 100644 --- a/drivers/platform/chrome/cros_ec_dev.c +++ b/drivers/platform/chrome/cros_ec_dev.c @@ -32,6 +32,7 @@ static int ec_major; static const struct attribute_group *cros_ec_groups[] = { &cros_ec_attr_group, &cros_ec_lightbar_attr_group, + &cros_ec_vbc_attr_group, NULL, }; @@ -287,6 +288,12 @@ static int ec_device_remove(struct platform_device *pdev) return 0; } +static const struct platform_device_id cros_ec_id[] = { + { "cros-ec-ctl", 0 }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(platform, cros_ec_id); + static struct platform_driver cros_ec_dev_driver = { .driver = { .name = "cros-ec-ctl", diff --git a/drivers/platform/chrome/cros_ec_lightbar.c b/drivers/platform/chrome/cros_ec_lightbar.c index 144e09df9b84..ff7640575c75 100644 --- a/drivers/platform/chrome/cros_ec_lightbar.c +++ b/drivers/platform/chrome/cros_ec_lightbar.c @@ -252,7 +252,7 @@ static ssize_t led_rgb_store(struct device *dev, struct device_attribute *attr, ret = sscanf(buf, "%i", &val[i++]); if (ret == 0) - return -EINVAL; + goto exit; if (i == 4) { param = (struct ec_params_lightbar *)msg->data; @@ -268,17 +268,15 @@ static ssize_t led_rgb_store(struct device *dev, struct device_attribute *attr, if ((j++ % 4) == 0) { ret = lb_throttle(); if (ret) - return ret; + goto exit; } ret = cros_ec_cmd_xfer(ec->ec_dev, msg); if (ret < 0) goto exit; - if (msg->result != EC_RES_SUCCESS) { - ret = -EINVAL; + if (msg->result != EC_RES_SUCCESS) goto exit; - } i = 0; ok = 1; @@ -352,10 +350,6 @@ static ssize_t sequence_store(struct device *dev, struct device_attribute *attr, struct cros_ec_dev *ec = container_of(dev, struct cros_ec_dev, class_dev); - msg = alloc_lightbar_cmd_msg(ec); - if (!msg) - return -ENOMEM; - for (len = 0; len < count; len++) if (!isalnum(buf[len])) break; @@ -370,21 +364,30 @@ static ssize_t sequence_store(struct device *dev, struct device_attribute *attr, return ret; } + msg = alloc_lightbar_cmd_msg(ec); + if (!msg) + return -ENOMEM; + param = (struct ec_params_lightbar *)msg->data; param->cmd = LIGHTBAR_CMD_SEQ; param->seq.num = num; ret = lb_throttle(); if (ret) - return ret; + goto exit; ret = cros_ec_cmd_xfer(ec->ec_dev, msg); if (ret < 0) - return ret; + goto exit; - if (msg->result != EC_RES_SUCCESS) - return -EINVAL; + if (msg->result != EC_RES_SUCCESS) { + ret = -EINVAL; + goto exit; + } - return count; + ret = count; +exit: + kfree(msg); + return ret; } /* Module initialization */ diff --git a/drivers/platform/chrome/cros_ec_lpc.c b/drivers/platform/chrome/cros_ec_lpc.c index bdd77ce45f05..f9a245465fd0 100644 --- a/drivers/platform/chrome/cros_ec_lpc.c +++ b/drivers/platform/chrome/cros_ec_lpc.c @@ -166,19 +166,9 @@ static int cros_ec_cmd_xfer_lpc(struct cros_ec_device *ec, /* Check result */ msg->result = inb(EC_LPC_ADDR_HOST_DATA); - - switch (msg->result) { - case EC_RES_SUCCESS: - break; - case EC_RES_IN_PROGRESS: - ret = -EAGAIN; - dev_dbg(ec->dev, "command 0x%02x in progress\n", - msg->command); + ret = cros_ec_check_result(ec, msg); + if (ret) goto done; - default: - dev_dbg(ec->dev, "command 0x%02x returned %d\n", - msg->command, msg->result); - } /* Read back args */ args.flags = inb(EC_LPC_ADDR_HOST_ARGS); @@ -330,6 +320,13 @@ static struct dmi_system_id cros_ec_lpc_dmi_table[] __initdata = { }, }, { + /* x86-samus, the Chromebook Pixel 2. */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"), + DMI_MATCH(DMI_PRODUCT_NAME, "Samus"), + }, + }, + { /* x86-peppy, the Acer C720 Chromebook. */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), diff --git a/drivers/platform/chrome/cros_ec_vbc.c b/drivers/platform/chrome/cros_ec_vbc.c new file mode 100644 index 000000000000..564a0d08c8bf --- /dev/null +++ b/drivers/platform/chrome/cros_ec_vbc.c @@ -0,0 +1,137 @@ +/* + * cros_ec_vbc - Expose the vboot context nvram to userspace + * + * Copyright (C) 2015 Collabora Ltd. + * + * based on vendor driver, + * + * Copyright (C) 2012 The Chromium OS Authors + * + * 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. + */ + +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/mfd/cros_ec.h> +#include <linux/mfd/cros_ec_commands.h> +#include <linux/slab.h> + +static ssize_t vboot_context_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *att, char *buf, + loff_t pos, size_t count) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct cros_ec_dev *ec = container_of(dev, struct cros_ec_dev, + class_dev); + struct cros_ec_device *ecdev = ec->ec_dev; + struct ec_params_vbnvcontext *params; + struct cros_ec_command *msg; + int err; + const size_t para_sz = sizeof(params->op); + const size_t resp_sz = sizeof(struct ec_response_vbnvcontext); + const size_t payload = max(para_sz, resp_sz); + + msg = kmalloc(sizeof(*msg) + payload, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + /* NB: we only kmalloc()ated enough space for the op field */ + params = (struct ec_params_vbnvcontext *)msg->data; + params->op = EC_VBNV_CONTEXT_OP_READ; + + msg->version = EC_VER_VBNV_CONTEXT; + msg->command = EC_CMD_VBNV_CONTEXT; + msg->outsize = para_sz; + msg->insize = resp_sz; + + err = cros_ec_cmd_xfer(ecdev, msg); + if (err < 0) { + dev_err(dev, "Error sending read request: %d\n", err); + kfree(msg); + return err; + } + + memcpy(buf, msg->data, resp_sz); + + kfree(msg); + return resp_sz; +} + +static ssize_t vboot_context_write(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, char *buf, + loff_t pos, size_t count) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct cros_ec_dev *ec = container_of(dev, struct cros_ec_dev, + class_dev); + struct cros_ec_device *ecdev = ec->ec_dev; + struct ec_params_vbnvcontext *params; + struct cros_ec_command *msg; + int err; + const size_t para_sz = sizeof(*params); + const size_t data_sz = sizeof(params->block); + + /* Only write full values */ + if (count != data_sz) + return -EINVAL; + + msg = kmalloc(sizeof(*msg) + para_sz, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + params = (struct ec_params_vbnvcontext *)msg->data; + params->op = EC_VBNV_CONTEXT_OP_WRITE; + memcpy(params->block, buf, data_sz); + + msg->version = EC_VER_VBNV_CONTEXT; + msg->command = EC_CMD_VBNV_CONTEXT; + msg->outsize = para_sz; + msg->insize = 0; + + err = cros_ec_cmd_xfer(ecdev, msg); + if (err < 0) { + dev_err(dev, "Error sending write request: %d\n", err); + kfree(msg); + return err; + } + + kfree(msg); + return data_sz; +} + +static umode_t cros_ec_vbc_is_visible(struct kobject *kobj, + struct bin_attribute *a, int n) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct cros_ec_dev *ec = container_of(dev, struct cros_ec_dev, + class_dev); + struct device_node *np = ec->ec_dev->dev->of_node; + + if (IS_ENABLED(CONFIG_OF) && np) { + if (of_property_read_bool(np, "google,has-vbc-nvram")) + return a->attr.mode; + } + + return 0; +} + +static BIN_ATTR_RW(vboot_context, 16); + +static struct bin_attribute *cros_ec_vbc_bin_attrs[] = { + &bin_attr_vboot_context, + NULL +}; + +struct attribute_group cros_ec_vbc_attr_group = { + .name = "vbc", + .bin_attrs = cros_ec_vbc_bin_attrs, + .is_bin_visible = cros_ec_vbc_is_visible, +}; diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 02bbc70c332d..1089eaa02b00 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -345,6 +345,7 @@ config IDEAPAD_LAPTOP depends on SERIO_I8042 depends on BACKLIGHT_CLASS_DEVICE depends on ACPI_VIDEO || ACPI_VIDEO = n + depends on ACPI_WMI || ACPI_WMI = n select INPUT_SPARSEKMAP help This is a driver for Lenovo IdeaPad netbooks contains drivers for diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 1f7d80ff8cb4..f96f7b865267 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -1320,7 +1320,7 @@ static ssize_t asus_hwmon_temp1(struct device *dev, if (err < 0) return err; - value = KELVIN_TO_CELSIUS((value & 0xFFFF)) * 1000; + value = DECI_KELVIN_TO_CELSIUS((value & 0xFFFF)) * 1000; return sprintf(buf, "%d\n", value); } @@ -1682,7 +1682,7 @@ static ssize_t store_sys_wmi(struct asus_wmi *asus, int devid, int rv, err, value; value = asus_wmi_get_devstate_simple(asus, devid); - if (value == -ENODEV) /* Check device presence */ + if (value < 0) return value; rv = parse_arg(buf, count, &value); diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index fce49f3c6ed6..a313dfc0245f 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -47,6 +47,10 @@ #define CFG_WIFI_BIT (18) #define CFG_CAMERA_BIT (19) +#if IS_ENABLED(CONFIG_ACPI_WMI) +static const char ideapad_wmi_fnesc_event[] = "26CAB2E5-5CF1-46AE-AAC3-4A12B6BA50E6"; +#endif + enum { VPCCMD_R_VPC1 = 0x10, VPCCMD_R_BL_MAX, @@ -567,6 +571,8 @@ static const struct key_entry ideapad_keymap[] = { { KE_KEY, 65, { KEY_PROG4 } }, { KE_KEY, 66, { KEY_TOUCHPAD_OFF } }, { KE_KEY, 67, { KEY_TOUCHPAD_ON } }, + { KE_KEY, 128, { KEY_ESC } }, + { KE_END, 0 }, }; @@ -825,6 +831,19 @@ static void ideapad_acpi_notify(acpi_handle handle, u32 event, void *data) } } +#if IS_ENABLED(CONFIG_ACPI_WMI) +static void ideapad_wmi_notify(u32 value, void *context) +{ + switch (value) { + case 128: + ideapad_input_report(context, value); + break; + default: + pr_info("Unknown WMI event %u\n", value); + } +} +#endif + /* * Some ideapads don't have a hardware rfkill switch, reading VPCCMD_R_RF * always results in 0 on these models, causing ideapad_laptop to wrongly @@ -853,24 +872,31 @@ static const struct dmi_system_id no_hw_rfkill_list[] = { }, }, { - .ident = "Lenovo Yoga 3 14", + .ident = "Lenovo Yoga 2 11 / 13 / Pro", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Yoga 3 14"), + DMI_MATCH(DMI_BOARD_NAME, "Yoga2"), }, }, { - .ident = "Lenovo Yoga 2 11 / 13 / Pro", + .ident = "Lenovo Yoga 3 1170 / 1470", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), - DMI_MATCH(DMI_BOARD_NAME, "Yoga2"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Yoga 3"), }, }, { .ident = "Lenovo Yoga 3 Pro 1370", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo YOGA 3 Pro-1370"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo YOGA 3"), + }, + }, + { + .ident = "Lenovo Yoga 900", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo YOGA 900"), }, }, {} @@ -935,8 +961,18 @@ static int ideapad_acpi_add(struct platform_device *pdev) ACPI_DEVICE_NOTIFY, ideapad_acpi_notify, priv); if (ret) goto notification_failed; +#if IS_ENABLED(CONFIG_ACPI_WMI) + ret = wmi_install_notify_handler(ideapad_wmi_fnesc_event, ideapad_wmi_notify, priv); + if (ret != AE_OK && ret != AE_NOT_EXIST) + goto notification_failed_wmi; +#endif return 0; +#if IS_ENABLED(CONFIG_ACPI_WMI) +notification_failed_wmi: + acpi_remove_notify_handler(priv->adev->handle, + ACPI_DEVICE_NOTIFY, ideapad_acpi_notify); +#endif notification_failed: ideapad_backlight_exit(priv); backlight_failed: @@ -955,6 +991,9 @@ static int ideapad_acpi_remove(struct platform_device *pdev) struct ideapad_private *priv = dev_get_drvdata(&pdev->dev); int i; +#if IS_ENABLED(CONFIG_ACPI_WMI) + wmi_remove_notify_handler(ideapad_wmi_fnesc_event); +#endif acpi_remove_notify_handler(priv->adev->handle, ACPI_DEVICE_NOTIFY, ideapad_acpi_notify); ideapad_backlight_exit(priv); diff --git a/drivers/platform/x86/intel_menlow.c b/drivers/platform/x86/intel_menlow.c index e8b46d2c468c..0a919d81662c 100644 --- a/drivers/platform/x86/intel_menlow.c +++ b/drivers/platform/x86/intel_menlow.c @@ -315,7 +315,7 @@ static ssize_t aux0_show(struct device *dev, result = sensor_get_auxtrip(attr->handle, 0, &value); - return result ? result : sprintf(buf, "%lu", KELVIN_TO_CELSIUS(value)); + return result ? result : sprintf(buf, "%lu", DECI_KELVIN_TO_CELSIUS(value)); } static ssize_t aux1_show(struct device *dev, @@ -327,7 +327,7 @@ static ssize_t aux1_show(struct device *dev, result = sensor_get_auxtrip(attr->handle, 1, &value); - return result ? result : sprintf(buf, "%lu", KELVIN_TO_CELSIUS(value)); + return result ? result : sprintf(buf, "%lu", DECI_KELVIN_TO_CELSIUS(value)); } static ssize_t aux0_store(struct device *dev, @@ -345,7 +345,7 @@ static ssize_t aux0_store(struct device *dev, if (value < 0) return -EINVAL; - result = sensor_set_auxtrip(attr->handle, 0, CELSIUS_TO_KELVIN(value)); + result = sensor_set_auxtrip(attr->handle, 0, CELSIUS_TO_DECI_KELVIN(value)); return result ? result : count; } @@ -364,7 +364,7 @@ static ssize_t aux1_store(struct device *dev, if (value < 0) return -EINVAL; - result = sensor_set_auxtrip(attr->handle, 1, CELSIUS_TO_KELVIN(value)); + result = sensor_set_auxtrip(attr->handle, 1, CELSIUS_TO_DECI_KELVIN(value)); return result ? result : count; } diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 131dd7464183..0bed4733c4f0 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -6459,8 +6459,7 @@ static void __init tpacpi_detect_brightness_capabilities(void) pr_info("detected a 8-level brightness capable ThinkPad\n"); break; default: - pr_err("Unsupported brightness interface, " - "please contact %s\n", TPACPI_MAIL); + pr_info("Unsupported brightness interface\n"); tp_features.bright_unkfw = 1; bright_maxlvl = b - 1; } diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 062630ab7424..2f4641a0e88b 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -92,6 +92,15 @@ config PWM_BCM2835 To compile this driver as a module, choose M here: the module will be called pwm-bcm2835. +config PWM_BERLIN + tristate "Marvell Berlin PWM support" + depends on ARCH_BERLIN + help + PWM framework driver for Marvell Berlin SoCs. + + To compile this driver as a module, choose M here: the module + will be called pwm-berlin. + config PWM_BFIN tristate "Blackfin PWM support" depends on BFIN_GPTIMERS @@ -101,6 +110,16 @@ config PWM_BFIN To compile this driver as a module, choose M here: the module will be called pwm-bfin. +config PWM_BRCMSTB + tristate "Broadcom STB PWM support" + depends on ARCH_BRCMSTB || BMIPS_GENERIC + help + Generic PWM framework driver for the Broadcom Set-top-Box + SoCs (BCM7xxx). + + To compile this driver as a module, choose M Here: the module + will be called pwm-brcmstb.c. + config PWM_CLPS711X tristate "CLPS711X PWM support" depends on ARCH_CLPS711X || COMPILE_TEST @@ -230,6 +249,17 @@ config PWM_LPSS_PLATFORM To compile this driver as a module, choose M here: the module will be called pwm-lpss-platform. +config PWM_MTK_DISP + tristate "MediaTek display PWM driver" + depends on ARCH_MEDIATEK || COMPILE_TEST + depends on HAS_IOMEM + help + Generic PWM framework driver for MediaTek disp-pwm device. + The PWM is used to control the backlight brightness for display. + + To compile this driver as a module, choose M here: the module + will be called pwm-mtk-disp. + config PWM_MXS tristate "Freescale MXS PWM support" depends on ARCH_MXS && OF @@ -242,7 +272,7 @@ config PWM_MXS config PWM_PCA9685 tristate "NXP PCA9685 PWM driver" - depends on OF && I2C + depends on I2C select REGMAP_I2C help Generic PWM framework driver for NXP PCA9685 LED controller. @@ -268,6 +298,17 @@ config PWM_PXA To compile this driver as a module, choose M here: the module will be called pwm-pxa. +config PWM_RCAR + tristate "Renesas R-Car PWM support" + depends on ARCH_RCAR_GEN1 || ARCH_RCAR_GEN2 || COMPILE_TEST + depends on HAS_IOMEM + help + This driver exposes the PWM Timer controller found in Renesas + R-Car chips through the PWM API. + + To compile this driver as a module, choose M here: the module + will be called pwm-rcar. + config PWM_RENESAS_TPU tristate "Renesas TPU PWM support" depends on ARCH_SHMOBILE || COMPILE_TEST @@ -338,7 +379,7 @@ config PWM_TEGRA config PWM_TIECAP tristate "ECAP PWM support" - depends on SOC_AM33XX || ARCH_DAVINCI_DA8XX + depends on ARCH_OMAP2PLUS || ARCH_DAVINCI_DA8XX help PWM driver support for the ECAP APWM controller found on AM33XX TI SOC @@ -348,7 +389,7 @@ config PWM_TIECAP config PWM_TIEHRPWM tristate "EHRPWM PWM support" - depends on SOC_AM33XX || ARCH_DAVINCI_DA8XX + depends on ARCH_OMAP2PLUS || ARCH_DAVINCI_DA8XX help PWM driver support for the EHRPWM controller found on AM33XX TI SOC @@ -358,7 +399,7 @@ config PWM_TIEHRPWM config PWM_TIPWMSS bool - default y if SOC_AM33XX && (PWM_TIECAP || PWM_TIEHRPWM) + default y if (ARCH_OMAP2PLUS) && (PWM_TIECAP || PWM_TIEHRPWM) help PWM Subsystem driver support for AM33xx SOC. diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index a0e00c09ead3..69b8275f3c08 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -6,7 +6,9 @@ obj-$(CONFIG_PWM_ATMEL_HLCDC_PWM) += pwm-atmel-hlcdc.o obj-$(CONFIG_PWM_ATMEL_TCB) += pwm-atmel-tcb.o obj-$(CONFIG_PWM_BCM_KONA) += pwm-bcm-kona.o obj-$(CONFIG_PWM_BCM2835) += pwm-bcm2835.o +obj-$(CONFIG_PWM_BERLIN) += pwm-berlin.o obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o +obj-$(CONFIG_PWM_BRCMSTB) += pwm-brcmstb.o obj-$(CONFIG_PWM_CLPS711X) += pwm-clps711x.o obj-$(CONFIG_PWM_CRC) += pwm-crc.o obj-$(CONFIG_PWM_EP93XX) += pwm-ep93xx.o @@ -20,10 +22,12 @@ obj-$(CONFIG_PWM_LPC32XX) += pwm-lpc32xx.o obj-$(CONFIG_PWM_LPSS) += pwm-lpss.o obj-$(CONFIG_PWM_LPSS_PCI) += pwm-lpss-pci.o obj-$(CONFIG_PWM_LPSS_PLATFORM) += pwm-lpss-platform.o +obj-$(CONFIG_PWM_MTK_DISP) += pwm-mtk-disp.o obj-$(CONFIG_PWM_MXS) += pwm-mxs.o obj-$(CONFIG_PWM_PCA9685) += pwm-pca9685.o obj-$(CONFIG_PWM_PUV3) += pwm-puv3.o obj-$(CONFIG_PWM_PXA) += pwm-pxa.o +obj-$(CONFIG_PWM_RCAR) += pwm-rcar.o obj-$(CONFIG_PWM_RENESAS_TPU) += pwm-renesas-tpu.o obj-$(CONFIG_PWM_ROCKCHIP) += pwm-rockchip.o obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index 3f9df3ea3350..d24ca5f281b4 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -269,6 +269,7 @@ int pwmchip_add_with_polarity(struct pwm_chip *chip, pwm->pwm = chip->base + i; pwm->hwpwm = i; pwm->polarity = polarity; + mutex_init(&pwm->lock); radix_tree_insert(&pwm_tree, pwm->pwm, pwm); } @@ -473,16 +474,22 @@ int pwm_set_polarity(struct pwm_device *pwm, enum pwm_polarity polarity) if (!pwm->chip->ops->set_polarity) return -ENOSYS; - if (pwm_is_enabled(pwm)) - return -EBUSY; + mutex_lock(&pwm->lock); + + if (pwm_is_enabled(pwm)) { + err = -EBUSY; + goto unlock; + } err = pwm->chip->ops->set_polarity(pwm->chip, pwm, polarity); if (err) - return err; + goto unlock; pwm->polarity = polarity; - return 0; +unlock: + mutex_unlock(&pwm->lock); + return err; } EXPORT_SYMBOL_GPL(pwm_set_polarity); @@ -494,10 +501,22 @@ EXPORT_SYMBOL_GPL(pwm_set_polarity); */ int pwm_enable(struct pwm_device *pwm) { - if (pwm && !test_and_set_bit(PWMF_ENABLED, &pwm->flags)) - return pwm->chip->ops->enable(pwm->chip, pwm); + int err = 0; - return pwm ? 0 : -EINVAL; + if (!pwm) + return -EINVAL; + + mutex_lock(&pwm->lock); + + if (!test_and_set_bit(PWMF_ENABLED, &pwm->flags)) { + err = pwm->chip->ops->enable(pwm->chip, pwm); + if (err) + clear_bit(PWMF_ENABLED, &pwm->flags); + } + + mutex_unlock(&pwm->lock); + + return err; } EXPORT_SYMBOL_GPL(pwm_enable); @@ -719,8 +738,10 @@ struct pwm_device *pwm_get(struct device *dev, const char *con_id) } } - if (!chosen) + if (!chosen) { + pwm = ERR_PTR(-ENODEV); goto out; + } chip = pwmchip_find_by_name(chosen->provider); if (!chip) diff --git a/drivers/pwm/pwm-atmel-hlcdc.c b/drivers/pwm/pwm-atmel-hlcdc.c index 5df1db40fc07..f994c7eaf41c 100644 --- a/drivers/pwm/pwm-atmel-hlcdc.c +++ b/drivers/pwm/pwm-atmel-hlcdc.c @@ -227,6 +227,9 @@ static const struct of_device_id atmel_hlcdc_dt_ids[] = { .data = &atmel_hlcdc_pwm_at91sam9x5_errata, }, { + .compatible = "atmel,sama5d2-hlcdc", + }, + { .compatible = "atmel,sama5d3-hlcdc", .data = &atmel_hlcdc_pwm_sama5d3_errata, }, @@ -236,6 +239,7 @@ static const struct of_device_id atmel_hlcdc_dt_ids[] = { }, { /* sentinel */ }, }; +MODULE_DEVICE_TABLE(of, atmel_hlcdc_dt_ids); static int atmel_hlcdc_pwm_probe(struct platform_device *pdev) { diff --git a/drivers/pwm/pwm-berlin.c b/drivers/pwm/pwm-berlin.c new file mode 100644 index 000000000000..65108129d505 --- /dev/null +++ b/drivers/pwm/pwm-berlin.c @@ -0,0 +1,219 @@ +/* + * Marvell Berlin PWM driver + * + * Copyright (C) 2015 Marvell Technology Group Ltd. + * + * Author: Antoine Tenart <antoine.tenart@free-electrons.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/pwm.h> + +#define BERLIN_PWM_EN 0x0 +#define BERLIN_PWM_ENABLE BIT(0) +#define BERLIN_PWM_CONTROL 0x4 +#define BERLIN_PWM_PRESCALE_MASK 0x7 +#define BERLIN_PWM_PRESCALE_MAX 4096 +#define BERLIN_PWM_INVERT_POLARITY BIT(3) +#define BERLIN_PWM_DUTY 0x8 +#define BERLIN_PWM_TCNT 0xc +#define BERLIN_PWM_MAX_TCNT 65535 + +struct berlin_pwm_chip { + struct pwm_chip chip; + struct clk *clk; + void __iomem *base; +}; + +static inline struct berlin_pwm_chip *to_berlin_pwm_chip(struct pwm_chip *chip) +{ + return container_of(chip, struct berlin_pwm_chip, chip); +} + +static const u32 prescaler_table[] = { + 1, 4, 8, 16, 64, 256, 1024, 4096 +}; + +static inline u32 berlin_pwm_readl(struct berlin_pwm_chip *chip, + unsigned int channel, unsigned long offset) +{ + return readl_relaxed(chip->base + channel * 0x10 + offset); +} + +static inline void berlin_pwm_writel(struct berlin_pwm_chip *chip, + unsigned int channel, u32 value, + unsigned long offset) +{ + writel_relaxed(value, chip->base + channel * 0x10 + offset); +} + +static int berlin_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm_dev, + int duty_ns, int period_ns) +{ + struct berlin_pwm_chip *pwm = to_berlin_pwm_chip(chip); + unsigned int prescale; + u32 value, duty, period; + u64 cycles, tmp; + + cycles = clk_get_rate(pwm->clk); + cycles *= period_ns; + do_div(cycles, NSEC_PER_SEC); + + for (prescale = 0; prescale < ARRAY_SIZE(prescaler_table); prescale++) { + tmp = cycles; + do_div(tmp, prescaler_table[prescale]); + + if (tmp <= BERLIN_PWM_MAX_TCNT) + break; + } + + if (tmp > BERLIN_PWM_MAX_TCNT) + return -ERANGE; + + period = tmp; + cycles = tmp * duty_ns; + do_div(cycles, period_ns); + duty = cycles; + + value = berlin_pwm_readl(pwm, pwm_dev->hwpwm, BERLIN_PWM_CONTROL); + value &= ~BERLIN_PWM_PRESCALE_MASK; + value |= prescale; + berlin_pwm_writel(pwm, pwm_dev->hwpwm, value, BERLIN_PWM_CONTROL); + + berlin_pwm_writel(pwm, pwm_dev->hwpwm, duty, BERLIN_PWM_DUTY); + berlin_pwm_writel(pwm, pwm_dev->hwpwm, period, BERLIN_PWM_TCNT); + + return 0; +} + +static int berlin_pwm_set_polarity(struct pwm_chip *chip, + struct pwm_device *pwm_dev, + enum pwm_polarity polarity) +{ + struct berlin_pwm_chip *pwm = to_berlin_pwm_chip(chip); + u32 value; + + value = berlin_pwm_readl(pwm, pwm_dev->hwpwm, BERLIN_PWM_CONTROL); + + if (polarity == PWM_POLARITY_NORMAL) + value &= ~BERLIN_PWM_INVERT_POLARITY; + else + value |= BERLIN_PWM_INVERT_POLARITY; + + berlin_pwm_writel(pwm, pwm_dev->hwpwm, value, BERLIN_PWM_CONTROL); + + return 0; +} + +static int berlin_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm_dev) +{ + struct berlin_pwm_chip *pwm = to_berlin_pwm_chip(chip); + u32 value; + + value = berlin_pwm_readl(pwm, pwm_dev->hwpwm, BERLIN_PWM_EN); + value |= BERLIN_PWM_ENABLE; + berlin_pwm_writel(pwm, pwm_dev->hwpwm, value, BERLIN_PWM_EN); + + return 0; +} + +static void berlin_pwm_disable(struct pwm_chip *chip, + struct pwm_device *pwm_dev) +{ + struct berlin_pwm_chip *pwm = to_berlin_pwm_chip(chip); + u32 value; + + value = berlin_pwm_readl(pwm, pwm_dev->hwpwm, BERLIN_PWM_EN); + value &= ~BERLIN_PWM_ENABLE; + berlin_pwm_writel(pwm, pwm_dev->hwpwm, value, BERLIN_PWM_EN); +} + +static const struct pwm_ops berlin_pwm_ops = { + .config = berlin_pwm_config, + .set_polarity = berlin_pwm_set_polarity, + .enable = berlin_pwm_enable, + .disable = berlin_pwm_disable, + .owner = THIS_MODULE, +}; + +static const struct of_device_id berlin_pwm_match[] = { + { .compatible = "marvell,berlin-pwm" }, + { }, +}; +MODULE_DEVICE_TABLE(of, berlin_pwm_match); + +static int berlin_pwm_probe(struct platform_device *pdev) +{ + struct berlin_pwm_chip *pwm; + struct resource *res; + int ret; + + pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL); + if (!pwm) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + pwm->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(pwm->base)) + return PTR_ERR(pwm->base); + + pwm->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(pwm->clk)) + return PTR_ERR(pwm->clk); + + ret = clk_prepare_enable(pwm->clk); + if (ret) + return ret; + + pwm->chip.dev = &pdev->dev; + pwm->chip.ops = &berlin_pwm_ops; + pwm->chip.base = -1; + pwm->chip.npwm = 4; + pwm->chip.can_sleep = true; + pwm->chip.of_xlate = of_pwm_xlate_with_flags; + pwm->chip.of_pwm_n_cells = 3; + + ret = pwmchip_add(&pwm->chip); + if (ret < 0) { + dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret); + clk_disable_unprepare(pwm->clk); + return ret; + } + + platform_set_drvdata(pdev, pwm); + + return 0; +} + +static int berlin_pwm_remove(struct platform_device *pdev) +{ + struct berlin_pwm_chip *pwm = platform_get_drvdata(pdev); + int ret; + + ret = pwmchip_remove(&pwm->chip); + clk_disable_unprepare(pwm->clk); + + return ret; +} + +static struct platform_driver berlin_pwm_driver = { + .probe = berlin_pwm_probe, + .remove = berlin_pwm_remove, + .driver = { + .name = "berlin-pwm", + .of_match_table = berlin_pwm_match, + }, +}; +module_platform_driver(berlin_pwm_driver); + +MODULE_AUTHOR("Antoine Tenart <antoine.tenart@free-electrons.com>"); +MODULE_DESCRIPTION("Marvell Berlin PWM driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/pwm/pwm-brcmstb.c b/drivers/pwm/pwm-brcmstb.c new file mode 100644 index 000000000000..423ce087cd9c --- /dev/null +++ b/drivers/pwm/pwm-brcmstb.c @@ -0,0 +1,343 @@ +/* + * Broadcom BCM7038 PWM driver + * Author: Florian Fainelli + * + * Copyright (C) 2015 Broadcom 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 + * 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. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/clk.h> +#include <linux/export.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pwm.h> +#include <linux/spinlock.h> + +#define PWM_CTRL 0x00 +#define CTRL_START BIT(0) +#define CTRL_OEB BIT(1) +#define CTRL_FORCE_HIGH BIT(2) +#define CTRL_OPENDRAIN BIT(3) +#define CTRL_CHAN_OFFS 4 + +#define PWM_CTRL2 0x04 +#define CTRL2_OUT_SELECT BIT(0) + +#define PWM_CH_SIZE 0x8 + +#define PWM_CWORD_MSB(ch) (0x08 + ((ch) * PWM_CH_SIZE)) +#define PWM_CWORD_LSB(ch) (0x0c + ((ch) * PWM_CH_SIZE)) + +/* Number of bits for the CWORD value */ +#define CWORD_BIT_SIZE 16 + +/* + * Maximum control word value allowed when variable-frequency PWM is used as a + * clock for the constant-frequency PMW. + */ +#define CONST_VAR_F_MAX 32768 +#define CONST_VAR_F_MIN 1 + +#define PWM_ON(ch) (0x18 + ((ch) * PWM_CH_SIZE)) +#define PWM_ON_MIN 1 +#define PWM_PERIOD(ch) (0x1c + ((ch) * PWM_CH_SIZE)) +#define PWM_PERIOD_MIN 0 + +#define PWM_ON_PERIOD_MAX 0xff + +struct brcmstb_pwm { + void __iomem *base; + spinlock_t lock; + struct clk *clk; + struct pwm_chip chip; +}; + +static inline u32 brcmstb_pwm_readl(struct brcmstb_pwm *p, + unsigned int offset) +{ + if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) + return __raw_readl(p->base + offset); + else + return readl_relaxed(p->base + offset); +} + +static inline void brcmstb_pwm_writel(struct brcmstb_pwm *p, u32 value, + unsigned int offset) +{ + if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) + __raw_writel(value, p->base + offset); + else + writel_relaxed(value, p->base + offset); +} + +static inline struct brcmstb_pwm *to_brcmstb_pwm(struct pwm_chip *chip) +{ + return container_of(chip, struct brcmstb_pwm, chip); +} + +/* + * Fv is derived from the variable frequency output. The variable frequency + * output is configured using this formula: + * + * W = cword, if cword < 2 ^ 15 else 16-bit 2's complement of cword + * + * Fv = W x 2 ^ -16 x 27Mhz (reference clock) + * + * The period is: (period + 1) / Fv and "on" time is on / (period + 1) + * + * The PWM core framework specifies that the "duty_ns" parameter is in fact the + * "on" time, so this translates directly into our HW programming here. + */ +static int brcmstb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, + int duty_ns, int period_ns) +{ + struct brcmstb_pwm *p = to_brcmstb_pwm(chip); + unsigned long pc, dc, cword = CONST_VAR_F_MAX; + unsigned int channel = pwm->hwpwm; + u32 value; + + /* + * If asking for a duty_ns equal to period_ns, we need to substract + * the period value by 1 to make it shorter than the "on" time and + * produce a flat 100% duty cycle signal, and max out the "on" time + */ + if (duty_ns == period_ns) { + dc = PWM_ON_PERIOD_MAX; + pc = PWM_ON_PERIOD_MAX - 1; + goto done; + } + + while (1) { + u64 rate, tmp; + + /* + * Calculate the base rate from base frequency and current + * cword + */ + rate = (u64)clk_get_rate(p->clk) * (u64)cword; + do_div(rate, 1 << CWORD_BIT_SIZE); + + tmp = period_ns * rate; + do_div(tmp, NSEC_PER_SEC); + pc = tmp; + + tmp = (duty_ns + 1) * rate; + do_div(tmp, NSEC_PER_SEC); + dc = tmp; + + /* + * We can be called with separate duty and period updates, + * so do not reject dc == 0 right away + */ + if (pc == PWM_PERIOD_MIN || (dc < PWM_ON_MIN && duty_ns)) + return -EINVAL; + + /* We converged on a calculation */ + if (pc <= PWM_ON_PERIOD_MAX && dc <= PWM_ON_PERIOD_MAX) + break; + + /* + * The cword needs to be a power of 2 for the variable + * frequency generator to output a 50% duty cycle variable + * frequency which is used as input clock to the fixed + * frequency generator. + */ + cword >>= 1; + + /* + * Desired periods are too large, we do not have a divider + * for them + */ + if (cword < CONST_VAR_F_MIN) + return -EINVAL; + } + +done: + /* + * Configure the defined "cword" value to have the variable frequency + * generator output a base frequency for the constant frequency + * generator to derive from. + */ + spin_lock(&p->lock); + brcmstb_pwm_writel(p, cword >> 8, PWM_CWORD_MSB(channel)); + brcmstb_pwm_writel(p, cword & 0xff, PWM_CWORD_LSB(channel)); + + /* Select constant frequency signal output */ + value = brcmstb_pwm_readl(p, PWM_CTRL2); + value |= CTRL2_OUT_SELECT << (channel * CTRL_CHAN_OFFS); + brcmstb_pwm_writel(p, value, PWM_CTRL2); + + /* Configure on and period value */ + brcmstb_pwm_writel(p, pc, PWM_PERIOD(channel)); + brcmstb_pwm_writel(p, dc, PWM_ON(channel)); + spin_unlock(&p->lock); + + return 0; +} + +static inline void brcmstb_pwm_enable_set(struct brcmstb_pwm *p, + unsigned int channel, bool enable) +{ + unsigned int shift = channel * CTRL_CHAN_OFFS; + u32 value; + + spin_lock(&p->lock); + value = brcmstb_pwm_readl(p, PWM_CTRL); + + if (enable) { + value &= ~(CTRL_OEB << shift); + value |= (CTRL_START | CTRL_OPENDRAIN) << shift; + } else { + value &= ~((CTRL_START | CTRL_OPENDRAIN) << shift); + value |= CTRL_OEB << shift; + } + + brcmstb_pwm_writel(p, value, PWM_CTRL); + spin_unlock(&p->lock); +} + +static int brcmstb_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct brcmstb_pwm *p = to_brcmstb_pwm(chip); + + brcmstb_pwm_enable_set(p, pwm->hwpwm, true); + + return 0; +} + +static void brcmstb_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct brcmstb_pwm *p = to_brcmstb_pwm(chip); + + brcmstb_pwm_enable_set(p, pwm->hwpwm, false); +} + +static const struct pwm_ops brcmstb_pwm_ops = { + .config = brcmstb_pwm_config, + .enable = brcmstb_pwm_enable, + .disable = brcmstb_pwm_disable, + .owner = THIS_MODULE, +}; + +static const struct of_device_id brcmstb_pwm_of_match[] = { + { .compatible = "brcm,bcm7038-pwm", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, brcmstb_pwm_of_match); + +static int brcmstb_pwm_probe(struct platform_device *pdev) +{ + struct brcmstb_pwm *p; + struct resource *res; + int ret; + + p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL); + if (!p) + return -ENOMEM; + + spin_lock_init(&p->lock); + + p->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(p->clk)) { + dev_err(&pdev->dev, "failed to obtain clock\n"); + return PTR_ERR(p->clk); + } + + ret = clk_prepare_enable(p->clk); + if (ret < 0) { + dev_err(&pdev->dev, "failed to enable clock: %d\n", ret); + return ret; + } + + platform_set_drvdata(pdev, p); + + p->chip.dev = &pdev->dev; + p->chip.ops = &brcmstb_pwm_ops; + p->chip.base = -1; + p->chip.npwm = 2; + p->chip.can_sleep = true; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + p->base = devm_ioremap_resource(&pdev->dev, res); + if (!p->base) { + ret = -ENOMEM; + goto out_clk; + } + + ret = pwmchip_add(&p->chip); + if (ret) { + dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret); + goto out_clk; + } + + return 0; + +out_clk: + clk_disable_unprepare(p->clk); + return ret; +} + +static int brcmstb_pwm_remove(struct platform_device *pdev) +{ + struct brcmstb_pwm *p = platform_get_drvdata(pdev); + int ret; + + ret = pwmchip_remove(&p->chip); + clk_disable_unprepare(p->clk); + + return ret; +} + +#ifdef CONFIG_PM_SLEEP +static int brcmstb_pwm_suspend(struct device *dev) +{ + struct brcmstb_pwm *p = dev_get_drvdata(dev); + + clk_disable(p->clk); + + return 0; +} + +static int brcmstb_pwm_resume(struct device *dev) +{ + struct brcmstb_pwm *p = dev_get_drvdata(dev); + + clk_enable(p->clk); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(brcmstb_pwm_pm_ops, brcmstb_pwm_suspend, + brcmstb_pwm_resume); + +static struct platform_driver brcmstb_pwm_driver = { + .probe = brcmstb_pwm_probe, + .remove = brcmstb_pwm_remove, + .driver = { + .name = "pwm-brcmstb", + .of_match_table = brcmstb_pwm_of_match, + .pm = &brcmstb_pwm_pm_ops, + }, +}; +module_platform_driver(brcmstb_pwm_driver); + +MODULE_AUTHOR("Florian Fainelli <f.fainelli@gmail.com>"); +MODULE_DESCRIPTION("Broadcom STB PWM driver"); +MODULE_ALIAS("platform:pwm-brcmstb"); +MODULE_LICENSE("GPL"); diff --git a/drivers/pwm/pwm-lpss-pci.c b/drivers/pwm/pwm-lpss-pci.c index 45042c1b2046..7160e8ab38a4 100644 --- a/drivers/pwm/pwm-lpss-pci.c +++ b/drivers/pwm/pwm-lpss-pci.c @@ -13,6 +13,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> +#include <linux/pm_runtime.h> #include "pwm-lpss.h" @@ -33,6 +34,10 @@ static int pwm_lpss_probe_pci(struct pci_dev *pdev, return PTR_ERR(lpwm); pci_set_drvdata(pdev, lpwm); + + pm_runtime_put(&pdev->dev); + pm_runtime_allow(&pdev->dev); + return 0; } @@ -40,16 +45,41 @@ static void pwm_lpss_remove_pci(struct pci_dev *pdev) { struct pwm_lpss_chip *lpwm = pci_get_drvdata(pdev); + pm_runtime_forbid(&pdev->dev); + pm_runtime_get_sync(&pdev->dev); + pwm_lpss_remove(lpwm); } +#ifdef CONFIG_PM +static int pwm_lpss_runtime_suspend_pci(struct device *dev) +{ + /* + * The PCI core will handle transition to D3 automatically. We only + * need to provide runtime PM hooks for that to happen. + */ + return 0; +} + +static int pwm_lpss_runtime_resume_pci(struct device *dev) +{ + return 0; +} +#endif + +static const struct dev_pm_ops pwm_lpss_pci_pm = { + SET_RUNTIME_PM_OPS(pwm_lpss_runtime_suspend_pci, + pwm_lpss_runtime_resume_pci, NULL) +}; + static const struct pci_device_id pwm_lpss_pci_ids[] = { - { PCI_VDEVICE(INTEL, 0x0ac8), (unsigned long)&pwm_lpss_bsw_info}, + { PCI_VDEVICE(INTEL, 0x0ac8), (unsigned long)&pwm_lpss_bxt_info}, { PCI_VDEVICE(INTEL, 0x0f08), (unsigned long)&pwm_lpss_byt_info}, { PCI_VDEVICE(INTEL, 0x0f09), (unsigned long)&pwm_lpss_byt_info}, - { PCI_VDEVICE(INTEL, 0x1ac8), (unsigned long)&pwm_lpss_bsw_info}, + { PCI_VDEVICE(INTEL, 0x1ac8), (unsigned long)&pwm_lpss_bxt_info}, { PCI_VDEVICE(INTEL, 0x2288), (unsigned long)&pwm_lpss_bsw_info}, { PCI_VDEVICE(INTEL, 0x2289), (unsigned long)&pwm_lpss_bsw_info}, + { PCI_VDEVICE(INTEL, 0x5ac8), (unsigned long)&pwm_lpss_bxt_info}, { }, }; MODULE_DEVICE_TABLE(pci, pwm_lpss_pci_ids); @@ -59,6 +89,9 @@ static struct pci_driver pwm_lpss_driver_pci = { .id_table = pwm_lpss_pci_ids, .probe = pwm_lpss_probe_pci, .remove = pwm_lpss_remove_pci, + .driver = { + .pm = &pwm_lpss_pci_pm, + }, }; module_pci_driver(pwm_lpss_driver_pci); diff --git a/drivers/pwm/pwm-lpss-platform.c b/drivers/pwm/pwm-lpss-platform.c index 18a9c880a76d..54433fc6d1a4 100644 --- a/drivers/pwm/pwm-lpss-platform.c +++ b/drivers/pwm/pwm-lpss-platform.c @@ -14,6 +14,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include "pwm-lpss.h" @@ -36,6 +37,10 @@ static int pwm_lpss_probe_platform(struct platform_device *pdev) return PTR_ERR(lpwm); platform_set_drvdata(pdev, lpwm); + + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + return 0; } @@ -43,12 +48,14 @@ static int pwm_lpss_remove_platform(struct platform_device *pdev) { struct pwm_lpss_chip *lpwm = platform_get_drvdata(pdev); + pm_runtime_disable(&pdev->dev); return pwm_lpss_remove(lpwm); } static const struct acpi_device_id pwm_lpss_acpi_match[] = { { "80860F09", (unsigned long)&pwm_lpss_byt_info }, { "80862288", (unsigned long)&pwm_lpss_bsw_info }, + { "80865AC8", (unsigned long)&pwm_lpss_bxt_info }, { }, }; MODULE_DEVICE_TABLE(acpi, pwm_lpss_acpi_match); diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c index e9798253a16f..25044104003b 100644 --- a/drivers/pwm/pwm-lpss.c +++ b/drivers/pwm/pwm-lpss.c @@ -16,6 +16,7 @@ #include <linux/io.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/pm_runtime.h> #include "pwm-lpss.h" @@ -29,6 +30,9 @@ #define PWM_LIMIT (0x8000 + PWM_DIVISION_CORRECTION) #define NSECS_PER_SEC 1000000000UL +/* Size of each PWM register space if multiple */ +#define PWM_SIZE 0x400 + struct pwm_lpss_chip { struct pwm_chip chip; void __iomem *regs; @@ -37,21 +41,44 @@ struct pwm_lpss_chip { /* BayTrail */ const struct pwm_lpss_boardinfo pwm_lpss_byt_info = { - .clk_rate = 25000000 + .clk_rate = 25000000, + .npwm = 1, }; EXPORT_SYMBOL_GPL(pwm_lpss_byt_info); /* Braswell */ const struct pwm_lpss_boardinfo pwm_lpss_bsw_info = { - .clk_rate = 19200000 + .clk_rate = 19200000, + .npwm = 1, }; EXPORT_SYMBOL_GPL(pwm_lpss_bsw_info); +/* Broxton */ +const struct pwm_lpss_boardinfo pwm_lpss_bxt_info = { + .clk_rate = 19200000, + .npwm = 4, +}; +EXPORT_SYMBOL_GPL(pwm_lpss_bxt_info); + static inline struct pwm_lpss_chip *to_lpwm(struct pwm_chip *chip) { return container_of(chip, struct pwm_lpss_chip, chip); } +static inline u32 pwm_lpss_read(const struct pwm_device *pwm) +{ + struct pwm_lpss_chip *lpwm = to_lpwm(pwm->chip); + + return readl(lpwm->regs + pwm->hwpwm * PWM_SIZE + PWM); +} + +static inline void pwm_lpss_write(const struct pwm_device *pwm, u32 value) +{ + struct pwm_lpss_chip *lpwm = to_lpwm(pwm->chip); + + writel(value, lpwm->regs + pwm->hwpwm * PWM_SIZE + PWM); +} + static int pwm_lpss_config(struct pwm_chip *chip, struct pwm_device *pwm, int duty_ns, int period_ns) { @@ -79,38 +106,36 @@ static int pwm_lpss_config(struct pwm_chip *chip, struct pwm_device *pwm, duty_ns = 1; on_time_div = 255 - (255 * duty_ns / period_ns); - ctrl = readl(lpwm->regs + PWM); + pm_runtime_get_sync(chip->dev); + + ctrl = pwm_lpss_read(pwm); ctrl &= ~(PWM_BASE_UNIT_MASK | PWM_ON_TIME_DIV_MASK); ctrl |= (u16) base_unit << PWM_BASE_UNIT_SHIFT; ctrl |= on_time_div; /* request PWM to update on next cycle */ ctrl |= PWM_SW_UPDATE; - writel(ctrl, lpwm->regs + PWM); + pwm_lpss_write(pwm, ctrl); + + pm_runtime_put(chip->dev); return 0; } static int pwm_lpss_enable(struct pwm_chip *chip, struct pwm_device *pwm) { - struct pwm_lpss_chip *lpwm = to_lpwm(chip); - u32 ctrl; - - ctrl = readl(lpwm->regs + PWM); - writel(ctrl | PWM_ENABLE, lpwm->regs + PWM); - + pm_runtime_get_sync(chip->dev); + pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_ENABLE); return 0; } static void pwm_lpss_disable(struct pwm_chip *chip, struct pwm_device *pwm) { - struct pwm_lpss_chip *lpwm = to_lpwm(chip); - u32 ctrl; - - ctrl = readl(lpwm->regs + PWM); - writel(ctrl & ~PWM_ENABLE, lpwm->regs + PWM); + pwm_lpss_write(pwm, pwm_lpss_read(pwm) & ~PWM_ENABLE); + pm_runtime_put(chip->dev); } static const struct pwm_ops pwm_lpss_ops = { + .free = pwm_lpss_disable, .config = pwm_lpss_config, .enable = pwm_lpss_enable, .disable = pwm_lpss_disable, @@ -135,7 +160,7 @@ struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, struct resource *r, lpwm->chip.dev = dev; lpwm->chip.ops = &pwm_lpss_ops; lpwm->chip.base = -1; - lpwm->chip.npwm = 1; + lpwm->chip.npwm = info->npwm; ret = pwmchip_add(&lpwm->chip); if (ret) { @@ -149,11 +174,6 @@ EXPORT_SYMBOL_GPL(pwm_lpss_probe); int pwm_lpss_remove(struct pwm_lpss_chip *lpwm) { - u32 ctrl; - - ctrl = readl(lpwm->regs + PWM); - writel(ctrl & ~PWM_ENABLE, lpwm->regs + PWM); - return pwmchip_remove(&lpwm->chip); } EXPORT_SYMBOL_GPL(pwm_lpss_remove); diff --git a/drivers/pwm/pwm-lpss.h b/drivers/pwm/pwm-lpss.h index aa041bb1b67d..e8cf337ae1d1 100644 --- a/drivers/pwm/pwm-lpss.h +++ b/drivers/pwm/pwm-lpss.h @@ -20,10 +20,12 @@ struct pwm_lpss_chip; struct pwm_lpss_boardinfo { unsigned long clk_rate; + unsigned int npwm; }; extern const struct pwm_lpss_boardinfo pwm_lpss_byt_info; extern const struct pwm_lpss_boardinfo pwm_lpss_bsw_info; +extern const struct pwm_lpss_boardinfo pwm_lpss_bxt_info; struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, struct resource *r, const struct pwm_lpss_boardinfo *info); diff --git a/drivers/pwm/pwm-mtk-disp.c b/drivers/pwm/pwm-mtk-disp.c new file mode 100644 index 000000000000..0ad3385298c0 --- /dev/null +++ b/drivers/pwm/pwm-mtk-disp.c @@ -0,0 +1,243 @@ +/* + * MediaTek display pulse-width-modulation controller driver. + * Copyright (c) 2015 MediaTek Inc. + * Author: YH Huang <yh.huang@mediatek.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 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pwm.h> +#include <linux/slab.h> + +#define DISP_PWM_EN 0x00 +#define PWM_ENABLE_MASK BIT(0) + +#define DISP_PWM_COMMIT 0x08 +#define PWM_COMMIT_MASK BIT(0) + +#define DISP_PWM_CON_0 0x10 +#define PWM_CLKDIV_SHIFT 16 +#define PWM_CLKDIV_MAX 0x3ff +#define PWM_CLKDIV_MASK (PWM_CLKDIV_MAX << PWM_CLKDIV_SHIFT) + +#define DISP_PWM_CON_1 0x14 +#define PWM_PERIOD_BIT_WIDTH 12 +#define PWM_PERIOD_MASK ((1 << PWM_PERIOD_BIT_WIDTH) - 1) + +#define PWM_HIGH_WIDTH_SHIFT 16 +#define PWM_HIGH_WIDTH_MASK (0x1fff << PWM_HIGH_WIDTH_SHIFT) + +struct mtk_disp_pwm { + struct pwm_chip chip; + struct clk *clk_main; + struct clk *clk_mm; + void __iomem *base; +}; + +static inline struct mtk_disp_pwm *to_mtk_disp_pwm(struct pwm_chip *chip) +{ + return container_of(chip, struct mtk_disp_pwm, chip); +} + +static void mtk_disp_pwm_update_bits(struct mtk_disp_pwm *mdp, u32 offset, + u32 mask, u32 data) +{ + void __iomem *address = mdp->base + offset; + u32 value; + + value = readl(address); + value &= ~mask; + value |= data; + writel(value, address); +} + +static int mtk_disp_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, + int duty_ns, int period_ns) +{ + struct mtk_disp_pwm *mdp = to_mtk_disp_pwm(chip); + u32 clk_div, period, high_width, value; + u64 div, rate; + int err; + + /* + * Find period, high_width and clk_div to suit duty_ns and period_ns. + * Calculate proper div value to keep period value in the bound. + * + * period_ns = 10^9 * (clk_div + 1) * (period + 1) / PWM_CLK_RATE + * duty_ns = 10^9 * (clk_div + 1) * high_width / PWM_CLK_RATE + * + * period = (PWM_CLK_RATE * period_ns) / (10^9 * (clk_div + 1)) - 1 + * high_width = (PWM_CLK_RATE * duty_ns) / (10^9 * (clk_div + 1)) + */ + rate = clk_get_rate(mdp->clk_main); + clk_div = div_u64(rate * period_ns, NSEC_PER_SEC) >> + PWM_PERIOD_BIT_WIDTH; + if (clk_div > PWM_CLKDIV_MAX) + return -EINVAL; + + div = NSEC_PER_SEC * (clk_div + 1); + period = div64_u64(rate * period_ns, div); + if (period > 0) + period--; + + high_width = div64_u64(rate * duty_ns, div); + value = period | (high_width << PWM_HIGH_WIDTH_SHIFT); + + err = clk_enable(mdp->clk_main); + if (err < 0) + return err; + + err = clk_enable(mdp->clk_mm); + if (err < 0) { + clk_disable(mdp->clk_main); + return err; + } + + mtk_disp_pwm_update_bits(mdp, DISP_PWM_CON_0, PWM_CLKDIV_MASK, + clk_div << PWM_CLKDIV_SHIFT); + mtk_disp_pwm_update_bits(mdp, DISP_PWM_CON_1, + PWM_PERIOD_MASK | PWM_HIGH_WIDTH_MASK, value); + mtk_disp_pwm_update_bits(mdp, DISP_PWM_COMMIT, PWM_COMMIT_MASK, 1); + mtk_disp_pwm_update_bits(mdp, DISP_PWM_COMMIT, PWM_COMMIT_MASK, 0); + + clk_disable(mdp->clk_mm); + clk_disable(mdp->clk_main); + + return 0; +} + +static int mtk_disp_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct mtk_disp_pwm *mdp = to_mtk_disp_pwm(chip); + int err; + + err = clk_enable(mdp->clk_main); + if (err < 0) + return err; + + err = clk_enable(mdp->clk_mm); + if (err < 0) { + clk_disable(mdp->clk_main); + return err; + } + + mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, PWM_ENABLE_MASK, 1); + + return 0; +} + +static void mtk_disp_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct mtk_disp_pwm *mdp = to_mtk_disp_pwm(chip); + + mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, PWM_ENABLE_MASK, 0); + + clk_disable(mdp->clk_mm); + clk_disable(mdp->clk_main); +} + +static const struct pwm_ops mtk_disp_pwm_ops = { + .config = mtk_disp_pwm_config, + .enable = mtk_disp_pwm_enable, + .disable = mtk_disp_pwm_disable, + .owner = THIS_MODULE, +}; + +static int mtk_disp_pwm_probe(struct platform_device *pdev) +{ + struct mtk_disp_pwm *mdp; + struct resource *r; + int ret; + + mdp = devm_kzalloc(&pdev->dev, sizeof(*mdp), GFP_KERNEL); + if (!mdp) + return -ENOMEM; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + mdp->base = devm_ioremap_resource(&pdev->dev, r); + if (IS_ERR(mdp->base)) + return PTR_ERR(mdp->base); + + mdp->clk_main = devm_clk_get(&pdev->dev, "main"); + if (IS_ERR(mdp->clk_main)) + return PTR_ERR(mdp->clk_main); + + mdp->clk_mm = devm_clk_get(&pdev->dev, "mm"); + if (IS_ERR(mdp->clk_mm)) + return PTR_ERR(mdp->clk_mm); + + ret = clk_prepare(mdp->clk_main); + if (ret < 0) + return ret; + + ret = clk_prepare(mdp->clk_mm); + if (ret < 0) + goto disable_clk_main; + + mdp->chip.dev = &pdev->dev; + mdp->chip.ops = &mtk_disp_pwm_ops; + mdp->chip.base = -1; + mdp->chip.npwm = 1; + + ret = pwmchip_add(&mdp->chip); + if (ret < 0) { + dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret); + goto disable_clk_mm; + } + + platform_set_drvdata(pdev, mdp); + + return 0; + +disable_clk_mm: + clk_unprepare(mdp->clk_mm); +disable_clk_main: + clk_unprepare(mdp->clk_main); + return ret; +} + +static int mtk_disp_pwm_remove(struct platform_device *pdev) +{ + struct mtk_disp_pwm *mdp = platform_get_drvdata(pdev); + int ret; + + ret = pwmchip_remove(&mdp->chip); + clk_unprepare(mdp->clk_mm); + clk_unprepare(mdp->clk_main); + + return ret; +} + +static const struct of_device_id mtk_disp_pwm_of_match[] = { + { .compatible = "mediatek,mt8173-disp-pwm" }, + { .compatible = "mediatek,mt6595-disp-pwm" }, + { } +}; +MODULE_DEVICE_TABLE(of, mtk_disp_pwm_of_match); + +static struct platform_driver mtk_disp_pwm_driver = { + .driver = { + .name = "mediatek-disp-pwm", + .of_match_table = mtk_disp_pwm_of_match, + }, + .probe = mtk_disp_pwm_probe, + .remove = mtk_disp_pwm_remove, +}; +module_platform_driver(mtk_disp_pwm_driver); + +MODULE_AUTHOR("YH Huang <yh.huang@mediatek.com>"); +MODULE_DESCRIPTION("MediaTek SoC display PWM driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c index 70448a6079b0..117fccf7934a 100644 --- a/drivers/pwm/pwm-pca9685.c +++ b/drivers/pwm/pwm-pca9685.c @@ -19,9 +19,11 @@ * this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <linux/acpi.h> #include <linux/i2c.h> #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/property.h> #include <linux/pwm.h> #include <linux/regmap.h> #include <linux/slab.h> @@ -297,7 +299,6 @@ static const struct regmap_config pca9685_regmap_i2c_config = { static int pca9685_pwm_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct device_node *np = client->dev.of_node; struct pca9685 *pca; int ret; int mode2; @@ -320,12 +321,12 @@ static int pca9685_pwm_probe(struct i2c_client *client, regmap_read(pca->regmap, PCA9685_MODE2, &mode2); - if (of_property_read_bool(np, "invert")) + if (device_property_read_bool(&client->dev, "invert")) mode2 |= MODE2_INVRT; else mode2 &= ~MODE2_INVRT; - if (of_property_read_bool(np, "open-drain")) + if (device_property_read_bool(&client->dev, "open-drain")) mode2 &= ~MODE2_OUTDRV; else mode2 |= MODE2_OUTDRV; @@ -363,16 +364,27 @@ static const struct i2c_device_id pca9685_id[] = { }; MODULE_DEVICE_TABLE(i2c, pca9685_id); +#ifdef CONFIG_ACPI +static const struct acpi_device_id pca9685_acpi_ids[] = { + { "INT3492", 0 }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(acpi, pca9685_acpi_ids); +#endif + +#ifdef CONFIG_OF static const struct of_device_id pca9685_dt_ids[] = { { .compatible = "nxp,pca9685-pwm", }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, pca9685_dt_ids); +#endif static struct i2c_driver pca9685_i2c_driver = { .driver = { .name = "pca9685-pwm", - .of_match_table = pca9685_dt_ids, + .acpi_match_table = ACPI_PTR(pca9685_acpi_ids), + .of_match_table = of_match_ptr(pca9685_dt_ids), }, .probe = pca9685_pwm_probe, .remove = pca9685_pwm_remove, diff --git a/drivers/pwm/pwm-rcar.c b/drivers/pwm/pwm-rcar.c new file mode 100644 index 000000000000..6e99a63ffa29 --- /dev/null +++ b/drivers/pwm/pwm-rcar.c @@ -0,0 +1,274 @@ +/* + * R-Car PWM Timer driver + * + * Copyright (C) 2015 Renesas Electronics Corporation + * + * This is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + */ + +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/pwm.h> +#include <linux/slab.h> + +#define RCAR_PWM_MAX_DIVISION 24 +#define RCAR_PWM_MAX_CYCLE 1023 + +#define RCAR_PWMCR 0x00 +#define RCAR_PWMCR_CC0_MASK 0x000f0000 +#define RCAR_PWMCR_CC0_SHIFT 16 +#define RCAR_PWMCR_CCMD BIT(15) +#define RCAR_PWMCR_SYNC BIT(11) +#define RCAR_PWMCR_SS0 BIT(4) +#define RCAR_PWMCR_EN0 BIT(0) + +#define RCAR_PWMCNT 0x04 +#define RCAR_PWMCNT_CYC0_MASK 0x03ff0000 +#define RCAR_PWMCNT_CYC0_SHIFT 16 +#define RCAR_PWMCNT_PH0_MASK 0x000003ff +#define RCAR_PWMCNT_PH0_SHIFT 0 + +struct rcar_pwm_chip { + struct pwm_chip chip; + void __iomem *base; + struct clk *clk; +}; + +static inline struct rcar_pwm_chip *to_rcar_pwm_chip(struct pwm_chip *chip) +{ + return container_of(chip, struct rcar_pwm_chip, chip); +} + +static void rcar_pwm_write(struct rcar_pwm_chip *rp, u32 data, + unsigned int offset) +{ + writel(data, rp->base + offset); +} + +static u32 rcar_pwm_read(struct rcar_pwm_chip *rp, unsigned int offset) +{ + return readl(rp->base + offset); +} + +static void rcar_pwm_update(struct rcar_pwm_chip *rp, u32 mask, u32 data, + unsigned int offset) +{ + u32 value; + + value = rcar_pwm_read(rp, offset); + value &= ~mask; + value |= data & mask; + rcar_pwm_write(rp, value, offset); +} + +static int rcar_pwm_get_clock_division(struct rcar_pwm_chip *rp, int period_ns) +{ + unsigned long clk_rate = clk_get_rate(rp->clk); + unsigned long long max; /* max cycle / nanoseconds */ + unsigned int div; + + if (clk_rate == 0) + return -EINVAL; + + for (div = 0; div <= RCAR_PWM_MAX_DIVISION; div++) { + max = (unsigned long long)NSEC_PER_SEC * RCAR_PWM_MAX_CYCLE * + (1 << div); + do_div(max, clk_rate); + if (period_ns < max) + break; + } + + return (div <= RCAR_PWM_MAX_DIVISION) ? div : -ERANGE; +} + +static void rcar_pwm_set_clock_control(struct rcar_pwm_chip *rp, + unsigned int div) +{ + u32 value; + + value = rcar_pwm_read(rp, RCAR_PWMCR); + value &= ~(RCAR_PWMCR_CCMD | RCAR_PWMCR_CC0_MASK); + + if (div & 1) + value |= RCAR_PWMCR_CCMD; + + div >>= 1; + + value |= div << RCAR_PWMCR_CC0_SHIFT; + rcar_pwm_write(rp, value, RCAR_PWMCR); +} + +static int rcar_pwm_set_counter(struct rcar_pwm_chip *rp, int div, int duty_ns, + int period_ns) +{ + unsigned long long one_cycle, tmp; /* 0.01 nanoseconds */ + unsigned long clk_rate = clk_get_rate(rp->clk); + u32 cyc, ph; + + one_cycle = (unsigned long long)NSEC_PER_SEC * 100ULL * (1 << div); + do_div(one_cycle, clk_rate); + + tmp = period_ns * 100ULL; + do_div(tmp, one_cycle); + cyc = (tmp << RCAR_PWMCNT_CYC0_SHIFT) & RCAR_PWMCNT_CYC0_MASK; + + tmp = duty_ns * 100ULL; + do_div(tmp, one_cycle); + ph = tmp & RCAR_PWMCNT_PH0_MASK; + + /* Avoid prohibited setting */ + if (cyc == 0 || ph == 0) + return -EINVAL; + + rcar_pwm_write(rp, cyc | ph, RCAR_PWMCNT); + + return 0; +} + +static int rcar_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct rcar_pwm_chip *rp = to_rcar_pwm_chip(chip); + + return clk_prepare_enable(rp->clk); +} + +static void rcar_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct rcar_pwm_chip *rp = to_rcar_pwm_chip(chip); + + clk_disable_unprepare(rp->clk); +} + +static int rcar_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, + int duty_ns, int period_ns) +{ + struct rcar_pwm_chip *rp = to_rcar_pwm_chip(chip); + int div, ret; + + div = rcar_pwm_get_clock_division(rp, period_ns); + if (div < 0) + return div; + + /* Let the core driver set pwm->period if disabled and duty_ns == 0 */ + if (!test_bit(PWMF_ENABLED, &pwm->flags) && !duty_ns) + return 0; + + rcar_pwm_update(rp, RCAR_PWMCR_SYNC, RCAR_PWMCR_SYNC, RCAR_PWMCR); + + ret = rcar_pwm_set_counter(rp, div, duty_ns, period_ns); + if (!ret) + rcar_pwm_set_clock_control(rp, div); + + /* The SYNC should be set to 0 even if rcar_pwm_set_counter failed */ + rcar_pwm_update(rp, RCAR_PWMCR_SYNC, 0, RCAR_PWMCR); + + return ret; +} + +static int rcar_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct rcar_pwm_chip *rp = to_rcar_pwm_chip(chip); + u32 value; + + /* Don't enable the PWM device if CYC0 or PH0 is 0 */ + value = rcar_pwm_read(rp, RCAR_PWMCNT); + if ((value & RCAR_PWMCNT_CYC0_MASK) == 0 || + (value & RCAR_PWMCNT_PH0_MASK) == 0) + return -EINVAL; + + rcar_pwm_update(rp, RCAR_PWMCR_EN0, RCAR_PWMCR_EN0, RCAR_PWMCR); + + return 0; +} + +static void rcar_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct rcar_pwm_chip *rp = to_rcar_pwm_chip(chip); + + rcar_pwm_update(rp, RCAR_PWMCR_EN0, 0, RCAR_PWMCR); +} + +static const struct pwm_ops rcar_pwm_ops = { + .request = rcar_pwm_request, + .free = rcar_pwm_free, + .config = rcar_pwm_config, + .enable = rcar_pwm_enable, + .disable = rcar_pwm_disable, + .owner = THIS_MODULE, +}; + +static int rcar_pwm_probe(struct platform_device *pdev) +{ + struct rcar_pwm_chip *rcar_pwm; + struct resource *res; + int ret; + + rcar_pwm = devm_kzalloc(&pdev->dev, sizeof(*rcar_pwm), GFP_KERNEL); + if (rcar_pwm == NULL) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + rcar_pwm->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(rcar_pwm->base)) + return PTR_ERR(rcar_pwm->base); + + rcar_pwm->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(rcar_pwm->clk)) { + dev_err(&pdev->dev, "cannot get clock\n"); + return PTR_ERR(rcar_pwm->clk); + } + + platform_set_drvdata(pdev, rcar_pwm); + + rcar_pwm->chip.dev = &pdev->dev; + rcar_pwm->chip.ops = &rcar_pwm_ops; + rcar_pwm->chip.base = -1; + rcar_pwm->chip.npwm = 1; + + ret = pwmchip_add(&rcar_pwm->chip); + if (ret < 0) { + dev_err(&pdev->dev, "failed to register PWM chip: %d\n", ret); + return ret; + } + + pm_runtime_enable(&pdev->dev); + + return 0; +} + +static int rcar_pwm_remove(struct platform_device *pdev) +{ + struct rcar_pwm_chip *rcar_pwm = platform_get_drvdata(pdev); + + pm_runtime_disable(&pdev->dev); + + return pwmchip_remove(&rcar_pwm->chip); +} + +static const struct of_device_id rcar_pwm_of_table[] = { + { .compatible = "renesas,pwm-rcar", }, + { }, +}; +MODULE_DEVICE_TABLE(of, rcar_pwm_of_table); + +static struct platform_driver rcar_pwm_driver = { + .probe = rcar_pwm_probe, + .remove = rcar_pwm_remove, + .driver = { + .name = "pwm-rcar", + .of_match_table = of_match_ptr(rcar_pwm_of_table), + } +}; +module_platform_driver(rcar_pwm_driver); + +MODULE_AUTHOR("Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>"); +MODULE_DESCRIPTION("Renesas PWM Timer Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:pwm-rcar"); diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c index cd9dde563018..67af9f62361f 100644 --- a/drivers/pwm/pwm-sun4i.c +++ b/drivers/pwm/pwm-sun4i.c @@ -68,6 +68,7 @@ static const u32 prescaler_table[] = { struct sun4i_pwm_data { bool has_prescaler_bypass; bool has_rdy; + unsigned int npwm; }; struct sun4i_pwm_chip { @@ -114,7 +115,7 @@ static int sun4i_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, * is not an integer so round it half up instead of * truncating to get less surprising values. */ - div = clk_rate * period_ns + NSEC_PER_SEC/2; + div = clk_rate * period_ns + NSEC_PER_SEC / 2; do_div(div, NSEC_PER_SEC); if (div - 1 > PWM_PRD_MASK) prescaler = 0; @@ -262,11 +263,25 @@ static const struct pwm_ops sun4i_pwm_ops = { static const struct sun4i_pwm_data sun4i_pwm_data_a10 = { .has_prescaler_bypass = false, .has_rdy = false, + .npwm = 2, +}; + +static const struct sun4i_pwm_data sun4i_pwm_data_a10s = { + .has_prescaler_bypass = true, + .has_rdy = true, + .npwm = 2, +}; + +static const struct sun4i_pwm_data sun4i_pwm_data_a13 = { + .has_prescaler_bypass = true, + .has_rdy = true, + .npwm = 1, }; static const struct sun4i_pwm_data sun4i_pwm_data_a20 = { .has_prescaler_bypass = true, .has_rdy = true, + .npwm = 2, }; static const struct of_device_id sun4i_pwm_dt_ids[] = { @@ -274,6 +289,12 @@ static const struct of_device_id sun4i_pwm_dt_ids[] = { .compatible = "allwinner,sun4i-a10-pwm", .data = &sun4i_pwm_data_a10, }, { + .compatible = "allwinner,sun5i-a10s-pwm", + .data = &sun4i_pwm_data_a10s, + }, { + .compatible = "allwinner,sun5i-a13-pwm", + .data = &sun4i_pwm_data_a13, + }, { .compatible = "allwinner,sun7i-a20-pwm", .data = &sun4i_pwm_data_a20, }, { @@ -305,14 +326,14 @@ static int sun4i_pwm_probe(struct platform_device *pdev) if (IS_ERR(pwm->clk)) return PTR_ERR(pwm->clk); + pwm->data = match->data; pwm->chip.dev = &pdev->dev; pwm->chip.ops = &sun4i_pwm_ops; pwm->chip.base = -1; - pwm->chip.npwm = 2; + pwm->chip.npwm = pwm->data->npwm; pwm->chip.can_sleep = true; pwm->chip.of_xlate = of_pwm_xlate_with_flags; pwm->chip.of_pwm_n_cells = 3; - pwm->data = match->data; spin_lock_init(&pwm->ctrl_lock); diff --git a/drivers/pwm/sysfs.c b/drivers/pwm/sysfs.c index c472772f00a7..9c90886f4123 100644 --- a/drivers/pwm/sysfs.c +++ b/drivers/pwm/sysfs.c @@ -40,18 +40,18 @@ static struct pwm_device *child_to_pwm_device(struct device *child) return export->pwm; } -static ssize_t pwm_period_show(struct device *child, - struct device_attribute *attr, - char *buf) +static ssize_t period_show(struct device *child, + struct device_attribute *attr, + char *buf) { const struct pwm_device *pwm = child_to_pwm_device(child); return sprintf(buf, "%u\n", pwm_get_period(pwm)); } -static ssize_t pwm_period_store(struct device *child, - struct device_attribute *attr, - const char *buf, size_t size) +static ssize_t period_store(struct device *child, + struct device_attribute *attr, + const char *buf, size_t size) { struct pwm_device *pwm = child_to_pwm_device(child); unsigned int val; @@ -66,18 +66,18 @@ static ssize_t pwm_period_store(struct device *child, return ret ? : size; } -static ssize_t pwm_duty_cycle_show(struct device *child, - struct device_attribute *attr, - char *buf) +static ssize_t duty_cycle_show(struct device *child, + struct device_attribute *attr, + char *buf) { const struct pwm_device *pwm = child_to_pwm_device(child); return sprintf(buf, "%u\n", pwm_get_duty_cycle(pwm)); } -static ssize_t pwm_duty_cycle_store(struct device *child, - struct device_attribute *attr, - const char *buf, size_t size) +static ssize_t duty_cycle_store(struct device *child, + struct device_attribute *attr, + const char *buf, size_t size) { struct pwm_device *pwm = child_to_pwm_device(child); unsigned int val; @@ -92,19 +92,18 @@ static ssize_t pwm_duty_cycle_store(struct device *child, return ret ? : size; } -static ssize_t pwm_enable_show(struct device *child, - struct device_attribute *attr, - char *buf) +static ssize_t enable_show(struct device *child, + struct device_attribute *attr, + char *buf) { const struct pwm_device *pwm = child_to_pwm_device(child); - int enabled = pwm_is_enabled(pwm); - return sprintf(buf, "%d\n", enabled); + return sprintf(buf, "%d\n", pwm_is_enabled(pwm)); } -static ssize_t pwm_enable_store(struct device *child, - struct device_attribute *attr, - const char *buf, size_t size) +static ssize_t enable_store(struct device *child, + struct device_attribute *attr, + const char *buf, size_t size) { struct pwm_device *pwm = child_to_pwm_device(child); int val, ret; @@ -128,9 +127,9 @@ static ssize_t pwm_enable_store(struct device *child, return ret ? : size; } -static ssize_t pwm_polarity_show(struct device *child, - struct device_attribute *attr, - char *buf) +static ssize_t polarity_show(struct device *child, + struct device_attribute *attr, + char *buf) { const struct pwm_device *pwm = child_to_pwm_device(child); const char *polarity = "unknown"; @@ -148,9 +147,9 @@ static ssize_t pwm_polarity_show(struct device *child, return sprintf(buf, "%s\n", polarity); } -static ssize_t pwm_polarity_store(struct device *child, - struct device_attribute *attr, - const char *buf, size_t size) +static ssize_t polarity_store(struct device *child, + struct device_attribute *attr, + const char *buf, size_t size) { struct pwm_device *pwm = child_to_pwm_device(child); enum pwm_polarity polarity; @@ -168,10 +167,10 @@ static ssize_t pwm_polarity_store(struct device *child, return ret ? : size; } -static DEVICE_ATTR(period, 0644, pwm_period_show, pwm_period_store); -static DEVICE_ATTR(duty_cycle, 0644, pwm_duty_cycle_show, pwm_duty_cycle_store); -static DEVICE_ATTR(enable, 0644, pwm_enable_show, pwm_enable_store); -static DEVICE_ATTR(polarity, 0644, pwm_polarity_show, pwm_polarity_store); +static DEVICE_ATTR_RW(period); +static DEVICE_ATTR_RW(duty_cycle); +static DEVICE_ATTR_RW(enable); +static DEVICE_ATTR_RW(polarity); static struct attribute *pwm_attrs[] = { &dev_attr_period.attr, @@ -245,9 +244,9 @@ static int pwm_unexport_child(struct device *parent, struct pwm_device *pwm) return 0; } -static ssize_t pwm_export_store(struct device *parent, - struct device_attribute *attr, - const char *buf, size_t len) +static ssize_t export_store(struct device *parent, + struct device_attribute *attr, + const char *buf, size_t len) { struct pwm_chip *chip = dev_get_drvdata(parent); struct pwm_device *pwm; @@ -271,11 +270,11 @@ static ssize_t pwm_export_store(struct device *parent, return ret ? : len; } -static DEVICE_ATTR(export, 0200, NULL, pwm_export_store); +static DEVICE_ATTR_WO(export); -static ssize_t pwm_unexport_store(struct device *parent, - struct device_attribute *attr, - const char *buf, size_t len) +static ssize_t unexport_store(struct device *parent, + struct device_attribute *attr, + const char *buf, size_t len) { struct pwm_chip *chip = dev_get_drvdata(parent); unsigned int hwpwm; @@ -292,7 +291,7 @@ static ssize_t pwm_unexport_store(struct device *parent, return ret ? : len; } -static DEVICE_ATTR(unexport, 0200, NULL, pwm_unexport_store); +static DEVICE_ATTR_WO(unexport); static ssize_t npwm_show(struct device *parent, struct device_attribute *attr, char *buf) diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index 5ed44fe21380..94a8f4ab57bc 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c @@ -27,7 +27,8 @@ static int dcssblk_open(struct block_device *bdev, fmode_t mode); static void dcssblk_release(struct gendisk *disk, fmode_t mode); -static void dcssblk_make_request(struct request_queue *q, struct bio *bio); +static blk_qc_t dcssblk_make_request(struct request_queue *q, + struct bio *bio); static long dcssblk_direct_access(struct block_device *bdev, sector_t secnum, void __pmem **kaddr, unsigned long *pfn); @@ -815,7 +816,7 @@ dcssblk_release(struct gendisk *disk, fmode_t mode) up_write(&dcssblk_devices_sem); } -static void +static blk_qc_t dcssblk_make_request(struct request_queue *q, struct bio *bio) { struct dcssblk_dev_info *dev_info; @@ -874,9 +875,10 @@ dcssblk_make_request(struct request_queue *q, struct bio *bio) bytes_done += bvec.bv_len; } bio_endio(bio); - return; + return BLK_QC_T_NONE; fail: bio_io_error(bio); + return BLK_QC_T_NONE; } static long diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c index 02871f1db562..288f59a4147b 100644 --- a/drivers/s390/block/xpram.c +++ b/drivers/s390/block/xpram.c @@ -181,7 +181,7 @@ static unsigned long xpram_highest_page_index(void) /* * Block device make request function. */ -static void xpram_make_request(struct request_queue *q, struct bio *bio) +static blk_qc_t xpram_make_request(struct request_queue *q, struct bio *bio) { xpram_device_t *xdev = bio->bi_bdev->bd_disk->private_data; struct bio_vec bvec; @@ -223,9 +223,10 @@ static void xpram_make_request(struct request_queue *q, struct bio *bio) } } bio_endio(bio); - return; + return BLK_QC_T_NONE; fail: bio_io_error(bio); + return BLK_QC_T_NONE; } static int xpram_getgeo(struct block_device *bdev, struct hd_geometry *geo) diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 548a18916a31..a831d18596a5 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -1080,28 +1080,10 @@ void __init chsc_init_cleanup(void) free_page((unsigned long)sei_page); } -int chsc_enable_facility(int operation_code) +int __chsc_enable_facility(struct chsc_sda_area *sda_area, int operation_code) { - unsigned long flags; int ret; - struct { - struct chsc_header request; - u8 reserved1:4; - u8 format:4; - u8 reserved2; - u16 operation_code; - u32 reserved3; - u32 reserved4; - u32 operation_data_area[252]; - struct chsc_header response; - u32 reserved5:4; - u32 format2:4; - u32 reserved6:24; - } __attribute__ ((packed)) *sda_area; - spin_lock_irqsave(&chsc_page_lock, flags); - memset(chsc_page, 0, PAGE_SIZE); - sda_area = chsc_page; sda_area->request.length = 0x0400; sda_area->request.code = 0x0031; sda_area->operation_code = operation_code; @@ -1119,10 +1101,25 @@ int chsc_enable_facility(int operation_code) default: ret = chsc_error_from_response(sda_area->response.code); } +out: + return ret; +} + +int chsc_enable_facility(int operation_code) +{ + struct chsc_sda_area *sda_area; + unsigned long flags; + int ret; + + spin_lock_irqsave(&chsc_page_lock, flags); + memset(chsc_page, 0, PAGE_SIZE); + sda_area = chsc_page; + + ret = __chsc_enable_facility(sda_area, operation_code); if (ret != 0) CIO_CRW_EVENT(2, "chsc: sda (oc=%x) failed (rc=%04x)\n", operation_code, sda_area->response.code); -out: + spin_unlock_irqrestore(&chsc_page_lock, flags); return ret; } diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h index 76c9b50700b2..0de134c3a204 100644 --- a/drivers/s390/cio/chsc.h +++ b/drivers/s390/cio/chsc.h @@ -115,6 +115,20 @@ struct chsc_scpd { u8 data[PAGE_SIZE - 20]; } __attribute__ ((packed)); +struct chsc_sda_area { + struct chsc_header request; + u8 :4; + u8 format:4; + u8 :8; + u16 operation_code; + u32 :32; + u32 :32; + u32 operation_data_area[252]; + struct chsc_header response; + u32 :4; + u32 format2:4; + u32 :24; +} __packed __aligned(PAGE_SIZE); extern int chsc_get_ssd_info(struct subchannel_id schid, struct chsc_ssd_info *ssd); @@ -122,6 +136,7 @@ extern int chsc_determine_css_characteristics(void); extern int chsc_init(void); extern void chsc_init_cleanup(void); +int __chsc_enable_facility(struct chsc_sda_area *sda_area, int operation_code); extern int chsc_enable_facility(int); struct channel_subsystem; extern int chsc_secm(struct channel_subsystem *, int); diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index b5620e818d6b..690b8547e828 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -925,18 +925,32 @@ void reipl_ccw_dev(struct ccw_dev_id *devid) int __init cio_get_iplinfo(struct cio_iplinfo *iplinfo) { + static struct chsc_sda_area sda_area __initdata; struct subchannel_id schid; struct schib schib; schid = *(struct subchannel_id *)&S390_lowcore.subchannel_id; if (!schid.one) return -ENODEV; + + if (schid.ssid) { + /* + * Firmware should have already enabled MSS but whoever started + * the kernel might have initiated a channel subsystem reset. + * Ensure that MSS is enabled. + */ + memset(&sda_area, 0, sizeof(sda_area)); + if (__chsc_enable_facility(&sda_area, CHSC_SDA_OC_MSS)) + return -ENODEV; + } if (stsch_err(schid, &schib)) return -ENODEV; if (schib.pmcw.st != SUBCHANNEL_TYPE_IO) return -ENODEV; if (!schib.pmcw.dnv) return -ENODEV; + + iplinfo->ssid = schid.ssid; iplinfo->devno = schib.pmcw.dev; iplinfo->is_qdio = schib.pmcw.qf; return 0; diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 2ee3053bdc12..489e703dc82d 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -702,17 +702,12 @@ css_generate_pgid(struct channel_subsystem *css, u32 tod_high) css->global_pgid.pgid_high.ext_cssid.version = 0x80; css->global_pgid.pgid_high.ext_cssid.cssid = css->cssid; } else { -#ifdef CONFIG_SMP css->global_pgid.pgid_high.cpu_addr = stap(); -#else - css->global_pgid.pgid_high.cpu_addr = 0; -#endif } get_cpu_id(&cpu_id); css->global_pgid.cpu_id = cpu_id.ident; css->global_pgid.cpu_model = cpu_id.machine; css->global_pgid.tod_high = tod_high; - } static void diff --git a/drivers/s390/crypto/Makefile b/drivers/s390/crypto/Makefile index 57f710b3c8a4..b8ab18676e69 100644 --- a/drivers/s390/crypto/Makefile +++ b/drivers/s390/crypto/Makefile @@ -3,6 +3,9 @@ # ap-objs := ap_bus.o -obj-$(CONFIG_ZCRYPT) += ap.o zcrypt_api.o zcrypt_pcixcc.o -obj-$(CONFIG_ZCRYPT) += zcrypt_cex2a.o zcrypt_cex4.o +# zcrypt_api depends on ap +obj-$(CONFIG_ZCRYPT) += ap.o zcrypt_api.o +# msgtype* depend on zcrypt_api obj-$(CONFIG_ZCRYPT) += zcrypt_msgtype6.o zcrypt_msgtype50.o +# adapter drivers depend on ap, zcrypt_api and msgtype* +obj-$(CONFIG_ZCRYPT) += zcrypt_pcixcc.o zcrypt_cex2a.o zcrypt_cex4.o diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 9cb3dfbcaddb..61f768518a34 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -74,6 +74,7 @@ static struct device *ap_root_device = NULL; static struct ap_config_info *ap_configuration; static DEFINE_SPINLOCK(ap_device_list_lock); static LIST_HEAD(ap_device_list); +static bool initialised; /* * Workqueue timer for bus rescan. @@ -1384,6 +1385,9 @@ int ap_driver_register(struct ap_driver *ap_drv, struct module *owner, { struct device_driver *drv = &ap_drv->driver; + if (!initialised) + return -ENODEV; + drv->bus = &ap_bus_type; drv->probe = ap_device_probe; drv->remove = ap_device_remove; @@ -1808,6 +1812,7 @@ int __init ap_module_init(void) goto out_pm; queue_work(system_long_wq, &ap_scan_work); + initialised = true; return 0; @@ -1837,6 +1842,7 @@ void ap_module_exit(void) { int i; + initialised = false; ap_reset_domain(); ap_poll_thread_stop(); del_timer_sync(&ap_config_timer); diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index a9603ebbc1f8..9f8fa42c062c 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -317,11 +317,9 @@ EXPORT_SYMBOL(zcrypt_device_unregister); void zcrypt_msgtype_register(struct zcrypt_ops *zops) { - if (zops->owner) { - spin_lock_bh(&zcrypt_ops_list_lock); - list_add_tail(&zops->list, &zcrypt_ops_list); - spin_unlock_bh(&zcrypt_ops_list_lock); - } + spin_lock_bh(&zcrypt_ops_list_lock); + list_add_tail(&zops->list, &zcrypt_ops_list); + spin_unlock_bh(&zcrypt_ops_list_lock); } EXPORT_SYMBOL(zcrypt_msgtype_register); @@ -342,7 +340,7 @@ struct zcrypt_ops *__ops_lookup(unsigned char *name, int variant) spin_lock_bh(&zcrypt_ops_list_lock); list_for_each_entry(zops, &zcrypt_ops_list, list) { if ((zops->variant == variant) && - (!strncmp(zops->owner->name, name, MODULE_NAME_LEN))) { + (!strncmp(zops->name, name, sizeof(zops->name)))) { found = 1; break; } diff --git a/drivers/s390/crypto/zcrypt_api.h b/drivers/s390/crypto/zcrypt_api.h index 750876891931..38618f05ad92 100644 --- a/drivers/s390/crypto/zcrypt_api.h +++ b/drivers/s390/crypto/zcrypt_api.h @@ -96,6 +96,7 @@ struct zcrypt_ops { struct list_head list; /* zcrypt ops list. */ struct module *owner; int variant; + char name[128]; }; struct zcrypt_device { diff --git a/drivers/s390/crypto/zcrypt_msgtype50.c b/drivers/s390/crypto/zcrypt_msgtype50.c index 71ceee9137a8..74edf2934e7c 100644 --- a/drivers/s390/crypto/zcrypt_msgtype50.c +++ b/drivers/s390/crypto/zcrypt_msgtype50.c @@ -513,6 +513,7 @@ static struct zcrypt_ops zcrypt_msgtype50_ops = { .rsa_modexpo = zcrypt_cex2a_modexpo, .rsa_modexpo_crt = zcrypt_cex2a_modexpo_crt, .owner = THIS_MODULE, + .name = MSGTYPE50_NAME, .variant = MSGTYPE50_VARIANT_DEFAULT, }; diff --git a/drivers/s390/crypto/zcrypt_msgtype6.c b/drivers/s390/crypto/zcrypt_msgtype6.c index 74762214193b..9a2dd472c1cc 100644 --- a/drivers/s390/crypto/zcrypt_msgtype6.c +++ b/drivers/s390/crypto/zcrypt_msgtype6.c @@ -1119,6 +1119,7 @@ static long zcrypt_msgtype6_rng(struct zcrypt_device *zdev, */ static struct zcrypt_ops zcrypt_msgtype6_norng_ops = { .owner = THIS_MODULE, + .name = MSGTYPE06_NAME, .variant = MSGTYPE06_VARIANT_NORNG, .rsa_modexpo = zcrypt_msgtype6_modexpo, .rsa_modexpo_crt = zcrypt_msgtype6_modexpo_crt, @@ -1127,6 +1128,7 @@ static struct zcrypt_ops zcrypt_msgtype6_norng_ops = { static struct zcrypt_ops zcrypt_msgtype6_ops = { .owner = THIS_MODULE, + .name = MSGTYPE06_NAME, .variant = MSGTYPE06_VARIANT_DEFAULT, .rsa_modexpo = zcrypt_msgtype6_modexpo, .rsa_modexpo_crt = zcrypt_msgtype6_modexpo_crt, @@ -1136,6 +1138,7 @@ static struct zcrypt_ops zcrypt_msgtype6_ops = { static struct zcrypt_ops zcrypt_msgtype6_ep11_ops = { .owner = THIS_MODULE, + .name = MSGTYPE06_NAME, .variant = MSGTYPE06_VARIANT_EP11, .rsa_modexpo = NULL, .rsa_modexpo_crt = NULL, diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c index a209c3418898..d4c285688ce9 100644 --- a/drivers/scsi/53c700.c +++ b/drivers/scsi/53c700.c @@ -325,7 +325,6 @@ NCR_700_detect(struct scsi_host_template *tpnt, tpnt->slave_destroy = NCR_700_slave_destroy; tpnt->slave_alloc = NCR_700_slave_alloc; tpnt->change_queue_depth = NCR_700_change_queue_depth; - tpnt->use_blk_tags = 1; if(tpnt->name == NULL) tpnt->name = "53c700"; @@ -1107,7 +1106,9 @@ process_script_interrupt(__u32 dsps, __u32 dsp, struct scsi_cmnd *SCp, BUG(); } if(hostdata->msgin[1] == A_SIMPLE_TAG_MSG) { - struct scsi_cmnd *SCp = scsi_find_tag(SDp, hostdata->msgin[2]); + struct scsi_cmnd *SCp; + + SCp = scsi_host_find_tag(SDp->host, hostdata->msgin[2]); if(unlikely(SCp == NULL)) { printk(KERN_ERR "scsi%d: (%d:%d) no saved request for tag %d\n", host->host_no, reselection_id, lun, hostdata->msgin[2]); @@ -1119,7 +1120,9 @@ process_script_interrupt(__u32 dsps, __u32 dsp, struct scsi_cmnd *SCp, "reselection is tag %d, slot %p(%d)\n", hostdata->msgin[2], slot, slot->tag); } else { - struct scsi_cmnd *SCp = scsi_find_tag(SDp, SCSI_NO_TAG); + struct scsi_cmnd *SCp; + + SCp = scsi_host_find_tag(SDp->host, SCSI_NO_TAG); if(unlikely(SCp == NULL)) { sdev_printk(KERN_ERR, SDp, "no saved request for untagged cmd\n"); @@ -1823,7 +1826,7 @@ NCR_700_queuecommand_lck(struct scsi_cmnd *SCp, void (*done)(struct scsi_cmnd *) slot->tag, slot); } else { slot->tag = SCSI_NO_TAG; - /* must populate current_cmnd for scsi_find_tag to work */ + /* must populate current_cmnd for scsi_host_find_tag to work */ SCp->device->current_cmnd = SCp; } /* sanity check: some of the commands generated by the mid-layer diff --git a/drivers/scsi/FlashPoint.c b/drivers/scsi/FlashPoint.c index 5c74e4c52fe4..867b864f5047 100644 --- a/drivers/scsi/FlashPoint.c +++ b/drivers/scsi/FlashPoint.c @@ -2136,7 +2136,7 @@ static unsigned char FPT_SccbMgr_bad_isr(u32 p_port, unsigned char p_card, * *---------------------------------------------------------------------*/ -static void FPT_SccbMgrTableInitAll() +static void FPT_SccbMgrTableInitAll(void) { unsigned char thisCard; diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index d2f480b04a52..5f692ae40749 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -534,7 +534,6 @@ config SCSI_ARCMSR source "drivers/scsi/esas2r/Kconfig" source "drivers/scsi/megaraid/Kconfig.megaraid" -source "drivers/scsi/mpt2sas/Kconfig" source "drivers/scsi/mpt3sas/Kconfig" source "drivers/scsi/ufs/Kconfig" diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 1a8c9b53fafa..c14bca4a9675 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -106,7 +106,6 @@ obj-$(CONFIG_CXLFLASH) += cxlflash/ obj-$(CONFIG_MEGARAID_LEGACY) += megaraid.o obj-$(CONFIG_MEGARAID_NEWGEN) += megaraid/ obj-$(CONFIG_MEGARAID_SAS) += megaraid/ -obj-$(CONFIG_SCSI_MPT2SAS) += mpt2sas/ obj-$(CONFIG_SCSI_MPT3SAS) += mpt3sas/ obj-$(CONFIG_SCSI_UFSHCD) += ufs/ obj-$(CONFIG_SCSI_ACARD) += atp870u.o diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index 9b3dd6ef6a0b..e4c243748a97 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c @@ -259,7 +259,7 @@ MODULE_PARM_DESC(commit, "Control whether a COMMIT_CONFIG is issued to the" " 0=off, 1=on"); module_param_named(msi, aac_msi, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(msi, "IRQ handling." - " 0=PIC(default), 1=MSI, 2=MSI-X(unsupported, uses MSI)"); + " 0=PIC(default), 1=MSI, 2=MSI-X)"); module_param(startup_timeout, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(startup_timeout, "The duration of time in seconds to wait for" " adapter to have it's kernel up and\n" @@ -570,7 +570,7 @@ static int aac_get_container_name(struct scsi_cmnd * scsicmd) status = aac_fib_send(ContainerCommand, cmd_fibcontext, - sizeof (struct aac_get_name), + sizeof(struct aac_get_name_resp), FsaNormal, 0, 1, (fib_callback)get_container_name_callback, @@ -1052,7 +1052,7 @@ static int aac_get_container_serial(struct scsi_cmnd * scsicmd) status = aac_fib_send(ContainerCommand, cmd_fibcontext, - sizeof (struct aac_get_serial), + sizeof(struct aac_get_serial_resp), FsaNormal, 0, 1, (fib_callback) get_container_serial_callback, @@ -2977,11 +2977,16 @@ static void aac_srb_callback(void *context, struct fib * fibptr) return; BUG_ON(fibptr == NULL); - dev = fibptr->dev; - srbreply = (struct aac_srb_reply *) fib_data(fibptr); + scsi_dma_unmap(scsicmd); + /* expose physical device if expose_physicald flag is on */ + if (scsicmd->cmnd[0] == INQUIRY && !(scsicmd->cmnd[1] & 0x01) + && expose_physicals > 0) + aac_expose_phy_device(scsicmd); + + srbreply = (struct aac_srb_reply *) fib_data(fibptr); scsicmd->sense_buffer[0] = '\0'; /* Initialize sense valid flag to false */ if (fibptr->flags & FIB_CONTEXT_FLAG_FASTRESP) { @@ -2994,147 +2999,157 @@ static void aac_srb_callback(void *context, struct fib * fibptr) */ scsi_set_resid(scsicmd, scsi_bufflen(scsicmd) - le32_to_cpu(srbreply->data_xfer_length)); - } - - scsi_dma_unmap(scsicmd); - - /* expose physical device if expose_physicald flag is on */ - if (scsicmd->cmnd[0] == INQUIRY && !(scsicmd->cmnd[1] & 0x01) - && expose_physicals > 0) - aac_expose_phy_device(scsicmd); + /* + * First check the fib status + */ - /* - * First check the fib status - */ + if (le32_to_cpu(srbreply->status) != ST_OK) { + int len; - if (le32_to_cpu(srbreply->status) != ST_OK){ - int len; - printk(KERN_WARNING "aac_srb_callback: srb failed, status = %d\n", le32_to_cpu(srbreply->status)); - len = min_t(u32, le32_to_cpu(srbreply->sense_data_size), - SCSI_SENSE_BUFFERSIZE); - scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION; - memcpy(scsicmd->sense_buffer, srbreply->sense_data, len); - } + printk(KERN_WARNING "aac_srb_callback: srb failed, status = %d\n", le32_to_cpu(srbreply->status)); + len = min_t(u32, le32_to_cpu(srbreply->sense_data_size), + SCSI_SENSE_BUFFERSIZE); + scsicmd->result = DID_ERROR << 16 + | COMMAND_COMPLETE << 8 + | SAM_STAT_CHECK_CONDITION; + memcpy(scsicmd->sense_buffer, + srbreply->sense_data, len); + } - /* - * Next check the srb status - */ - switch( (le32_to_cpu(srbreply->srb_status))&0x3f){ - case SRB_STATUS_ERROR_RECOVERY: - case SRB_STATUS_PENDING: - case SRB_STATUS_SUCCESS: - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8; - break; - case SRB_STATUS_DATA_OVERRUN: - switch(scsicmd->cmnd[0]){ - case READ_6: - case WRITE_6: - case READ_10: - case WRITE_10: - case READ_12: - case WRITE_12: - case READ_16: - case WRITE_16: - if (le32_to_cpu(srbreply->data_xfer_length) < scsicmd->underflow) { - printk(KERN_WARNING"aacraid: SCSI CMD underflow\n"); - } else { - printk(KERN_WARNING"aacraid: SCSI CMD Data Overrun\n"); + /* + * Next check the srb status + */ + switch ((le32_to_cpu(srbreply->srb_status))&0x3f) { + case SRB_STATUS_ERROR_RECOVERY: + case SRB_STATUS_PENDING: + case SRB_STATUS_SUCCESS: + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8; + break; + case SRB_STATUS_DATA_OVERRUN: + switch (scsicmd->cmnd[0]) { + case READ_6: + case WRITE_6: + case READ_10: + case WRITE_10: + case READ_12: + case WRITE_12: + case READ_16: + case WRITE_16: + if (le32_to_cpu(srbreply->data_xfer_length) + < scsicmd->underflow) + printk(KERN_WARNING"aacraid: SCSI CMD underflow\n"); + else + printk(KERN_WARNING"aacraid: SCSI CMD Data Overrun\n"); + scsicmd->result = DID_ERROR << 16 + | COMMAND_COMPLETE << 8; + break; + case INQUIRY: { + scsicmd->result = DID_OK << 16 + | COMMAND_COMPLETE << 8; + break; + } + default: + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8; + break; } - scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8; break; - case INQUIRY: { - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8; + case SRB_STATUS_ABORTED: + scsicmd->result = DID_ABORT << 16 | ABORT << 8; break; - } - default: - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8; + case SRB_STATUS_ABORT_FAILED: + /* + * Not sure about this one - but assuming the + * hba was trying to abort for some reason + */ + scsicmd->result = DID_ERROR << 16 | ABORT << 8; + break; + case SRB_STATUS_PARITY_ERROR: + scsicmd->result = DID_PARITY << 16 + | MSG_PARITY_ERROR << 8; + break; + case SRB_STATUS_NO_DEVICE: + case SRB_STATUS_INVALID_PATH_ID: + case SRB_STATUS_INVALID_TARGET_ID: + case SRB_STATUS_INVALID_LUN: + case SRB_STATUS_SELECTION_TIMEOUT: + scsicmd->result = DID_NO_CONNECT << 16 + | COMMAND_COMPLETE << 8; break; - } - break; - case SRB_STATUS_ABORTED: - scsicmd->result = DID_ABORT << 16 | ABORT << 8; - break; - case SRB_STATUS_ABORT_FAILED: - // Not sure about this one - but assuming the hba was trying to abort for some reason - scsicmd->result = DID_ERROR << 16 | ABORT << 8; - break; - case SRB_STATUS_PARITY_ERROR: - scsicmd->result = DID_PARITY << 16 | MSG_PARITY_ERROR << 8; - break; - case SRB_STATUS_NO_DEVICE: - case SRB_STATUS_INVALID_PATH_ID: - case SRB_STATUS_INVALID_TARGET_ID: - case SRB_STATUS_INVALID_LUN: - case SRB_STATUS_SELECTION_TIMEOUT: - scsicmd->result = DID_NO_CONNECT << 16 | COMMAND_COMPLETE << 8; - break; - case SRB_STATUS_COMMAND_TIMEOUT: - case SRB_STATUS_TIMEOUT: - scsicmd->result = DID_TIME_OUT << 16 | COMMAND_COMPLETE << 8; - break; + case SRB_STATUS_COMMAND_TIMEOUT: + case SRB_STATUS_TIMEOUT: + scsicmd->result = DID_TIME_OUT << 16 + | COMMAND_COMPLETE << 8; + break; - case SRB_STATUS_BUSY: - scsicmd->result = DID_BUS_BUSY << 16 | COMMAND_COMPLETE << 8; - break; + case SRB_STATUS_BUSY: + scsicmd->result = DID_BUS_BUSY << 16 + | COMMAND_COMPLETE << 8; + break; - case SRB_STATUS_BUS_RESET: - scsicmd->result = DID_RESET << 16 | COMMAND_COMPLETE << 8; - break; + case SRB_STATUS_BUS_RESET: + scsicmd->result = DID_RESET << 16 + | COMMAND_COMPLETE << 8; + break; - case SRB_STATUS_MESSAGE_REJECTED: - scsicmd->result = DID_ERROR << 16 | MESSAGE_REJECT << 8; - break; - case SRB_STATUS_REQUEST_FLUSHED: - case SRB_STATUS_ERROR: - case SRB_STATUS_INVALID_REQUEST: - case SRB_STATUS_REQUEST_SENSE_FAILED: - case SRB_STATUS_NO_HBA: - case SRB_STATUS_UNEXPECTED_BUS_FREE: - case SRB_STATUS_PHASE_SEQUENCE_FAILURE: - case SRB_STATUS_BAD_SRB_BLOCK_LENGTH: - case SRB_STATUS_DELAYED_RETRY: - case SRB_STATUS_BAD_FUNCTION: - case SRB_STATUS_NOT_STARTED: - case SRB_STATUS_NOT_IN_USE: - case SRB_STATUS_FORCE_ABORT: - case SRB_STATUS_DOMAIN_VALIDATION_FAIL: - default: + case SRB_STATUS_MESSAGE_REJECTED: + scsicmd->result = DID_ERROR << 16 + | MESSAGE_REJECT << 8; + break; + case SRB_STATUS_REQUEST_FLUSHED: + case SRB_STATUS_ERROR: + case SRB_STATUS_INVALID_REQUEST: + case SRB_STATUS_REQUEST_SENSE_FAILED: + case SRB_STATUS_NO_HBA: + case SRB_STATUS_UNEXPECTED_BUS_FREE: + case SRB_STATUS_PHASE_SEQUENCE_FAILURE: + case SRB_STATUS_BAD_SRB_BLOCK_LENGTH: + case SRB_STATUS_DELAYED_RETRY: + case SRB_STATUS_BAD_FUNCTION: + case SRB_STATUS_NOT_STARTED: + case SRB_STATUS_NOT_IN_USE: + case SRB_STATUS_FORCE_ABORT: + case SRB_STATUS_DOMAIN_VALIDATION_FAIL: + default: #ifdef AAC_DETAILED_STATUS_INFO - printk("aacraid: SRB ERROR(%u) %s scsi cmd 0x%x - scsi status 0x%x\n", - le32_to_cpu(srbreply->srb_status) & 0x3F, - aac_get_status_string( - le32_to_cpu(srbreply->srb_status) & 0x3F), - scsicmd->cmnd[0], - le32_to_cpu(srbreply->scsi_status)); + printk(KERN_INFO "aacraid: SRB ERROR(%u) %s scsi cmd 0x%x - scsi status 0x%x\n", + le32_to_cpu(srbreply->srb_status) & 0x3F, + aac_get_status_string( + le32_to_cpu(srbreply->srb_status) & 0x3F), + scsicmd->cmnd[0], + le32_to_cpu(srbreply->scsi_status)); #endif - if ((scsicmd->cmnd[0] == ATA_12) - || (scsicmd->cmnd[0] == ATA_16)) { - if (scsicmd->cmnd[2] & (0x01 << 5)) { - scsicmd->result = DID_OK << 16 - | COMMAND_COMPLETE << 8; + if ((scsicmd->cmnd[0] == ATA_12) + || (scsicmd->cmnd[0] == ATA_16)) { + if (scsicmd->cmnd[2] & (0x01 << 5)) { + scsicmd->result = DID_OK << 16 + | COMMAND_COMPLETE << 8; break; + } else { + scsicmd->result = DID_ERROR << 16 + | COMMAND_COMPLETE << 8; + break; + } } else { scsicmd->result = DID_ERROR << 16 - | COMMAND_COMPLETE << 8; + | COMMAND_COMPLETE << 8; break; } - } else { - scsicmd->result = DID_ERROR << 16 - | COMMAND_COMPLETE << 8; - break; } - } - if (le32_to_cpu(srbreply->scsi_status) == SAM_STAT_CHECK_CONDITION) { - int len; - scsicmd->result |= SAM_STAT_CHECK_CONDITION; - len = min_t(u32, le32_to_cpu(srbreply->sense_data_size), - SCSI_SENSE_BUFFERSIZE); + if (le32_to_cpu(srbreply->scsi_status) + == SAM_STAT_CHECK_CONDITION) { + int len; + + scsicmd->result |= SAM_STAT_CHECK_CONDITION; + len = min_t(u32, le32_to_cpu(srbreply->sense_data_size), + SCSI_SENSE_BUFFERSIZE); #ifdef AAC_DETAILED_STATUS_INFO - printk(KERN_WARNING "aac_srb_callback: check condition, status = %d len=%d\n", - le32_to_cpu(srbreply->status), len); + printk(KERN_WARNING "aac_srb_callback: check condition, status = %d len=%d\n", + le32_to_cpu(srbreply->status), len); #endif - memcpy(scsicmd->sense_buffer, srbreply->sense_data, len); + memcpy(scsicmd->sense_buffer, + srbreply->sense_data, len); + } } /* * OR in the scsi status (already shifted up a bit) diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h index 40fe65c91b41..074878b55a0b 100644 --- a/drivers/scsi/aacraid/aacraid.h +++ b/drivers/scsi/aacraid/aacraid.h @@ -12,7 +12,7 @@ * D E F I N E S *----------------------------------------------------------------------------*/ -#define AAC_MAX_MSIX 8 /* vectors */ +#define AAC_MAX_MSIX 32 /* vectors */ #define AAC_PCI_MSI_ENABLE 0x8000 enum { @@ -62,7 +62,7 @@ enum { #define PMC_GLOBAL_INT_BIT0 0x00000001 #ifndef AAC_DRIVER_BUILD -# define AAC_DRIVER_BUILD 40709 +# define AAC_DRIVER_BUILD 41010 # define AAC_DRIVER_BRANCH "-ms" #endif #define MAXIMUM_NUM_CONTAINERS 32 @@ -547,6 +547,7 @@ struct adapter_ops int (*adapter_sync_cmd)(struct aac_dev *dev, u32 command, u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6, u32 *status, u32 *r1, u32 *r2, u32 *r3, u32 *r4); int (*adapter_check_health)(struct aac_dev *dev); int (*adapter_restart)(struct aac_dev *dev, int bled); + void (*adapter_start)(struct aac_dev *dev); /* Transport operations */ int (*adapter_ioremap)(struct aac_dev * dev, u32 size); irq_handler_t adapter_intr; @@ -843,6 +844,10 @@ struct src_registers { &((AEP)->regs.src.bar0->CSR)) #define src_writel(AEP, CSR, value) writel(value, \ &((AEP)->regs.src.bar0->CSR)) +#if defined(writeq) +#define src_writeq(AEP, CSR, value) writeq(value, \ + &((AEP)->regs.src.bar0->CSR)) +#endif #define SRC_ODR_SHIFT 12 #define SRC_IDR_SHIFT 9 @@ -1162,6 +1167,11 @@ struct aac_dev struct fsa_dev_info *fsa_dev; struct task_struct *thread; int cardtype; + /* + *This lock will protect the two 32-bit + *writes to the Inbound Queue + */ + spinlock_t iq_lock; /* * The following is the device specific extension. @@ -1247,6 +1257,9 @@ struct aac_dev #define aac_adapter_restart(dev,bled) \ (dev)->a_ops.adapter_restart(dev,bled) +#define aac_adapter_start(dev) \ + ((dev)->a_ops.adapter_start(dev)) + #define aac_adapter_ioremap(dev, size) \ (dev)->a_ops.adapter_ioremap(dev, size) @@ -2097,6 +2110,8 @@ static inline unsigned int cap_to_cyls(sector_t capacity, unsigned divisor) #define AAC_OWNER_ERROR_HANDLER 0x103 #define AAC_OWNER_FIRMWARE 0x106 +int aac_acquire_irq(struct aac_dev *dev); +void aac_free_irq(struct aac_dev *dev); const char *aac_driverinfo(struct Scsi_Host *); struct fib *aac_fib_alloc(struct aac_dev *dev); int aac_fib_setup(struct aac_dev *dev); @@ -2127,6 +2142,7 @@ int aac_sa_init(struct aac_dev *dev); int aac_src_init(struct aac_dev *dev); int aac_srcv_init(struct aac_dev *dev); int aac_queue_get(struct aac_dev * dev, u32 * index, u32 qid, struct hw_fib * hw_fib, int wait, struct fib * fibptr, unsigned long *nonotify); +void aac_define_int_mode(struct aac_dev *dev); unsigned int aac_response_normal(struct aac_queue * q); unsigned int aac_command_normal(struct aac_queue * q); unsigned int aac_intr_normal(struct aac_dev *dev, u32 Index, diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c index 45db84ad322f..0e954e37f0b5 100644 --- a/drivers/scsi/aacraid/comminit.c +++ b/drivers/scsi/aacraid/comminit.c @@ -43,8 +43,6 @@ #include "aacraid.h" -static void aac_define_int_mode(struct aac_dev *dev); - struct aac_common aac_config = { .irq_mod = 1 }; @@ -338,6 +336,74 @@ static int aac_comm_init(struct aac_dev * dev) return 0; } +void aac_define_int_mode(struct aac_dev *dev) +{ + int i, msi_count, min_msix; + + msi_count = i = 0; + /* max. vectors from GET_COMM_PREFERRED_SETTINGS */ + if (dev->max_msix == 0 || + dev->pdev->device == PMC_DEVICE_S6 || + dev->sync_mode) { + dev->max_msix = 1; + dev->vector_cap = + dev->scsi_host_ptr->can_queue + + AAC_NUM_MGT_FIB; + return; + } + + /* Don't bother allocating more MSI-X vectors than cpus */ + msi_count = min(dev->max_msix, + (unsigned int)num_online_cpus()); + + dev->max_msix = msi_count; + + if (msi_count > AAC_MAX_MSIX) + msi_count = AAC_MAX_MSIX; + + for (i = 0; i < msi_count; i++) + dev->msixentry[i].entry = i; + + if (msi_count > 1 && + pci_find_capability(dev->pdev, PCI_CAP_ID_MSIX)) { + min_msix = 2; + i = pci_enable_msix_range(dev->pdev, + dev->msixentry, + min_msix, + msi_count); + if (i > 0) { + dev->msi_enabled = 1; + msi_count = i; + } else { + dev->msi_enabled = 0; + printk(KERN_ERR "%s%d: MSIX not supported!! Will try MSI 0x%x.\n", + dev->name, dev->id, i); + } + } + + if (!dev->msi_enabled) { + msi_count = 1; + i = pci_enable_msi(dev->pdev); + + if (!i) { + dev->msi_enabled = 1; + dev->msi = 1; + } else { + printk(KERN_ERR "%s%d: MSI not supported!! Will try INTx 0x%x.\n", + dev->name, dev->id, i); + } + } + + if (!dev->msi_enabled) + dev->max_msix = msi_count = 1; + else { + if (dev->max_msix > msi_count) + dev->max_msix = msi_count; + } + dev->vector_cap = + (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB) / + msi_count; +} struct aac_dev *aac_init_adapter(struct aac_dev *dev) { u32 status[5]; @@ -350,6 +416,7 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev) dev->management_fib_count = 0; spin_lock_init(&dev->manage_lock); spin_lock_init(&dev->sync_lock); + spin_lock_init(&dev->iq_lock); dev->max_fib_size = sizeof(struct hw_fib); dev->sg_tablesize = host->sg_tablesize = (dev->max_fib_size - sizeof(struct aac_fibhdr) @@ -508,79 +575,3 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev) return dev; } -static void aac_define_int_mode(struct aac_dev *dev) -{ - - int i, msi_count; - - msi_count = i = 0; - /* max. vectors from GET_COMM_PREFERRED_SETTINGS */ - if (dev->max_msix == 0 || - dev->pdev->device == PMC_DEVICE_S6 || - dev->sync_mode) { - dev->max_msix = 1; - dev->vector_cap = - dev->scsi_host_ptr->can_queue + - AAC_NUM_MGT_FIB; - return; - } - - msi_count = min(dev->max_msix, - (unsigned int)num_online_cpus()); - - dev->max_msix = msi_count; - - if (msi_count > AAC_MAX_MSIX) - msi_count = AAC_MAX_MSIX; - - for (i = 0; i < msi_count; i++) - dev->msixentry[i].entry = i; - - if (msi_count > 1 && - pci_find_capability(dev->pdev, PCI_CAP_ID_MSIX)) { - i = pci_enable_msix(dev->pdev, - dev->msixentry, - msi_count); - /* Check how many MSIX vectors are allocated */ - if (i >= 0) { - dev->msi_enabled = 1; - if (i) { - msi_count = i; - if (pci_enable_msix(dev->pdev, - dev->msixentry, - msi_count)) { - dev->msi_enabled = 0; - printk(KERN_ERR "%s%d: MSIX not supported!! Will try MSI 0x%x.\n", - dev->name, dev->id, i); - } - } - } else { - dev->msi_enabled = 0; - printk(KERN_ERR "%s%d: MSIX not supported!! Will try MSI 0x%x.\n", - dev->name, dev->id, i); - } - } - - if (!dev->msi_enabled) { - msi_count = 1; - i = pci_enable_msi(dev->pdev); - - if (!i) { - dev->msi_enabled = 1; - dev->msi = 1; - } else { - printk(KERN_ERR "%s%d: MSI not supported!! Will try INTx 0x%x.\n", - dev->name, dev->id, i); - } - } - - if (!dev->msi_enabled) - dev->max_msix = msi_count = 1; - else { - if (dev->max_msix > msi_count) - dev->max_msix = msi_count; - } - dev->vector_cap = - (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB) / - msi_count; -} diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c index 4da574925284..a1f90fe849c9 100644 --- a/drivers/scsi/aacraid/commsup.c +++ b/drivers/scsi/aacraid/commsup.c @@ -1270,13 +1270,12 @@ retry_next: static int _aac_reset_adapter(struct aac_dev *aac, int forced) { int index, quirks; - int retval, i; + int retval; struct Scsi_Host *host; struct scsi_device *dev; struct scsi_cmnd *command; struct scsi_cmnd *command_list; int jafo = 0; - int cpu; /* * Assumptions: @@ -1339,35 +1338,7 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced) aac->comm_phys = 0; kfree(aac->queues); aac->queues = NULL; - cpu = cpumask_first(cpu_online_mask); - if (aac->pdev->device == PMC_DEVICE_S6 || - aac->pdev->device == PMC_DEVICE_S7 || - aac->pdev->device == PMC_DEVICE_S8 || - aac->pdev->device == PMC_DEVICE_S9) { - if (aac->max_msix > 1) { - for (i = 0; i < aac->max_msix; i++) { - if (irq_set_affinity_hint( - aac->msixentry[i].vector, - NULL)) { - printk(KERN_ERR "%s%d: Failed to reset IRQ affinity for cpu %d\n", - aac->name, - aac->id, - cpu); - } - cpu = cpumask_next(cpu, - cpu_online_mask); - free_irq(aac->msixentry[i].vector, - &(aac->aac_msix[i])); - } - pci_disable_msix(aac->pdev); - } else { - free_irq(aac->pdev->irq, &(aac->aac_msix[0])); - } - } else { - free_irq(aac->pdev->irq, aac); - } - if (aac->msi) - pci_disable_msi(aac->pdev); + aac_free_irq(aac); kfree(aac->fsa_dev); aac->fsa_dev = NULL; quirks = aac_get_driver_ident(index)->quirks; @@ -1978,3 +1949,83 @@ int aac_command_thread(void *data) dev->aif_thread = 0; return 0; } + +int aac_acquire_irq(struct aac_dev *dev) +{ + int i; + int j; + int ret = 0; + int cpu; + + cpu = cpumask_first(cpu_online_mask); + if (!dev->sync_mode && dev->msi_enabled && dev->max_msix > 1) { + for (i = 0; i < dev->max_msix; i++) { + dev->aac_msix[i].vector_no = i; + dev->aac_msix[i].dev = dev; + if (request_irq(dev->msixentry[i].vector, + dev->a_ops.adapter_intr, + 0, "aacraid", &(dev->aac_msix[i]))) { + printk(KERN_ERR "%s%d: Failed to register IRQ for vector %d.\n", + dev->name, dev->id, i); + for (j = 0 ; j < i ; j++) + free_irq(dev->msixentry[j].vector, + &(dev->aac_msix[j])); + pci_disable_msix(dev->pdev); + ret = -1; + } + if (irq_set_affinity_hint(dev->msixentry[i].vector, + get_cpu_mask(cpu))) { + printk(KERN_ERR "%s%d: Failed to set IRQ affinity for cpu %d\n", + dev->name, dev->id, cpu); + } + cpu = cpumask_next(cpu, cpu_online_mask); + } + } else { + dev->aac_msix[0].vector_no = 0; + dev->aac_msix[0].dev = dev; + + if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr, + IRQF_SHARED, "aacraid", + &(dev->aac_msix[0])) < 0) { + if (dev->msi) + pci_disable_msi(dev->pdev); + printk(KERN_ERR "%s%d: Interrupt unavailable.\n", + dev->name, dev->id); + ret = -1; + } + } + return ret; +} + +void aac_free_irq(struct aac_dev *dev) +{ + int i; + int cpu; + + cpu = cpumask_first(cpu_online_mask); + if (dev->pdev->device == PMC_DEVICE_S6 || + dev->pdev->device == PMC_DEVICE_S7 || + dev->pdev->device == PMC_DEVICE_S8 || + dev->pdev->device == PMC_DEVICE_S9) { + if (dev->max_msix > 1) { + for (i = 0; i < dev->max_msix; i++) { + if (irq_set_affinity_hint( + dev->msixentry[i].vector, NULL)) { + printk(KERN_ERR "%s%d: Failed to reset IRQ affinity for cpu %d\n", + dev->name, dev->id, cpu); + } + cpu = cpumask_next(cpu, cpu_online_mask); + free_irq(dev->msixentry[i].vector, + &(dev->aac_msix[i])); + } + } else { + free_irq(dev->pdev->irq, &(dev->aac_msix[0])); + } + } else { + free_irq(dev->pdev->irq, dev); + } + if (dev->msi) + pci_disable_msi(dev->pdev); + else if (dev->max_msix > 1) + pci_disable_msix(dev->pdev); +} diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index 9eec02733c86..3b6e5c67e853 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -1317,6 +1317,154 @@ static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) return error; } +#if (defined(CONFIG_PM)) +void aac_release_resources(struct aac_dev *aac) +{ + int i; + + aac_adapter_disable_int(aac); + if (aac->pdev->device == PMC_DEVICE_S6 || + aac->pdev->device == PMC_DEVICE_S7 || + aac->pdev->device == PMC_DEVICE_S8 || + aac->pdev->device == PMC_DEVICE_S9) { + if (aac->max_msix > 1) { + for (i = 0; i < aac->max_msix; i++) + free_irq(aac->msixentry[i].vector, + &(aac->aac_msix[i])); + } else { + free_irq(aac->pdev->irq, &(aac->aac_msix[0])); + } + } else { + free_irq(aac->pdev->irq, aac); + } + if (aac->msi) + pci_disable_msi(aac->pdev); + else if (aac->max_msix > 1) + pci_disable_msix(aac->pdev); + +} + +static int aac_acquire_resources(struct aac_dev *dev) +{ + int i, j; + int instance = dev->id; + const char *name = dev->name; + unsigned long status; + /* + * First clear out all interrupts. Then enable the one's that we + * can handle. + */ + while (!((status = src_readl(dev, MUnit.OMR)) & KERNEL_UP_AND_RUNNING) + || status == 0xffffffff) + msleep(20); + + aac_adapter_disable_int(dev); + aac_adapter_enable_int(dev); + + + if ((dev->pdev->device == PMC_DEVICE_S7 || + dev->pdev->device == PMC_DEVICE_S8 || + dev->pdev->device == PMC_DEVICE_S9)) + aac_define_int_mode(dev); + + if (dev->msi_enabled) + aac_src_access_devreg(dev, AAC_ENABLE_MSIX); + + if (!dev->sync_mode && dev->msi_enabled && dev->max_msix > 1) { + for (i = 0; i < dev->max_msix; i++) { + dev->aac_msix[i].vector_no = i; + dev->aac_msix[i].dev = dev; + + if (request_irq(dev->msixentry[i].vector, + dev->a_ops.adapter_intr, + 0, "aacraid", &(dev->aac_msix[i]))) { + printk(KERN_ERR "%s%d: Failed to register IRQ for vector %d.\n", + name, instance, i); + for (j = 0 ; j < i ; j++) + free_irq(dev->msixentry[j].vector, + &(dev->aac_msix[j])); + pci_disable_msix(dev->pdev); + goto error_iounmap; + } + } + } else { + dev->aac_msix[0].vector_no = 0; + dev->aac_msix[0].dev = dev; + + if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr, + IRQF_SHARED, "aacraid", + &(dev->aac_msix[0])) < 0) { + if (dev->msi) + pci_disable_msi(dev->pdev); + printk(KERN_ERR "%s%d: Interrupt unavailable.\n", + name, instance); + goto error_iounmap; + } + } + + aac_adapter_enable_int(dev); + + if (!dev->sync_mode) + aac_adapter_start(dev); + return 0; + +error_iounmap: + return -1; + +} +static int aac_suspend(struct pci_dev *pdev, pm_message_t state) +{ + + struct Scsi_Host *shost = pci_get_drvdata(pdev); + struct aac_dev *aac = (struct aac_dev *)shost->hostdata; + + scsi_block_requests(shost); + aac_send_shutdown(aac); + + aac_release_resources(aac); + + pci_set_drvdata(pdev, shost); + pci_save_state(pdev); + pci_disable_device(pdev); + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + + return 0; +} + +static int aac_resume(struct pci_dev *pdev) +{ + struct Scsi_Host *shost = pci_get_drvdata(pdev); + struct aac_dev *aac = (struct aac_dev *)shost->hostdata; + int r; + + pci_set_power_state(pdev, PCI_D0); + pci_enable_wake(pdev, PCI_D0, 0); + pci_restore_state(pdev); + r = pci_enable_device(pdev); + + if (r) + goto fail_device; + + pci_set_master(pdev); + if (aac_acquire_resources(aac)) + goto fail_device; + /* + * reset this flag to unblock ioctl() as it was set at + * aac_send_shutdown() to block ioctls from upperlayer + */ + aac->adapter_shutdown = 0; + scsi_unblock_requests(shost); + + return 0; + +fail_device: + printk(KERN_INFO "%s%d: resume failed.\n", aac->name, aac->id); + scsi_host_put(shost); + pci_disable_device(pdev); + return -ENODEV; +} +#endif + static void aac_shutdown(struct pci_dev *dev) { struct Scsi_Host *shost = pci_get_drvdata(dev); @@ -1356,6 +1504,10 @@ static struct pci_driver aac_pci_driver = { .id_table = aac_pci_tbl, .probe = aac_probe_one, .remove = aac_remove_one, +#if (defined(CONFIG_PM)) + .suspend = aac_suspend, + .resume = aac_resume, +#endif .shutdown = aac_shutdown, }; diff --git a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c index 9570612b80ce..ac1638069335 100644 --- a/drivers/scsi/aacraid/rx.c +++ b/drivers/scsi/aacraid/rx.c @@ -623,6 +623,7 @@ int _aac_rx_init(struct aac_dev *dev) dev->a_ops.adapter_sync_cmd = rx_sync_cmd; dev->a_ops.adapter_check_health = aac_rx_check_health; dev->a_ops.adapter_restart = aac_rx_restart_adapter; + dev->a_ops.adapter_start = aac_rx_start_adapter; /* * First clear out all interrupts. Then enable the one's that we diff --git a/drivers/scsi/aacraid/sa.c b/drivers/scsi/aacraid/sa.c index e66477c98240..869aea23c041 100644 --- a/drivers/scsi/aacraid/sa.c +++ b/drivers/scsi/aacraid/sa.c @@ -372,6 +372,7 @@ int aac_sa_init(struct aac_dev *dev) dev->a_ops.adapter_sync_cmd = sa_sync_cmd; dev->a_ops.adapter_check_health = aac_sa_check_health; dev->a_ops.adapter_restart = aac_sa_restart_adapter; + dev->a_ops.adapter_start = aac_sa_start_adapter; dev->a_ops.adapter_intr = aac_sa_intr; dev->a_ops.adapter_deliver = aac_rx_deliver_producer; dev->a_ops.adapter_ioremap = aac_sa_ioremap; diff --git a/drivers/scsi/aacraid/src.c b/drivers/scsi/aacraid/src.c index e63cf9f22f36..2aa34ea8ceb1 100644 --- a/drivers/scsi/aacraid/src.c +++ b/drivers/scsi/aacraid/src.c @@ -447,6 +447,10 @@ static int aac_src_deliver_message(struct fib *fib) u32 fibsize; dma_addr_t address; struct aac_fib_xporthdr *pFibX; +#if !defined(writeq) + unsigned long flags; +#endif + u16 hdr_size = le16_to_cpu(fib->hw_fib_va->header.Size); atomic_inc(&q->numpending); @@ -511,10 +515,14 @@ static int aac_src_deliver_message(struct fib *fib) return -EINVAL; address |= fibsize; } - +#if defined(writeq) + src_writeq(dev, MUnit.IQ_L, (u64)address); +#else + spin_lock_irqsave(&fib->dev->iq_lock, flags); src_writel(dev, MUnit.IQ_H, upper_32_bits(address) & 0xffffffff); src_writel(dev, MUnit.IQ_L, address & 0xffffffff); - + spin_unlock_irqrestore(&fib->dev->iq_lock, flags); +#endif return 0; } @@ -726,6 +734,7 @@ int aac_src_init(struct aac_dev *dev) dev->a_ops.adapter_sync_cmd = src_sync_cmd; dev->a_ops.adapter_check_health = aac_src_check_health; dev->a_ops.adapter_restart = aac_src_restart_adapter; + dev->a_ops.adapter_start = aac_src_start_adapter; /* * First clear out all interrupts. Then enable the one's that we @@ -741,7 +750,7 @@ int aac_src_init(struct aac_dev *dev) if (dev->comm_interface != AAC_COMM_MESSAGE_TYPE1) goto error_iounmap; - dev->msi = aac_msi && !pci_enable_msi(dev->pdev); + dev->msi = !pci_enable_msi(dev->pdev); dev->aac_msix[0].vector_no = 0; dev->aac_msix[0].dev = dev; @@ -789,9 +798,7 @@ int aac_srcv_init(struct aac_dev *dev) unsigned long status; int restart = 0; int instance = dev->id; - int i, j; const char *name = dev->name; - int cpu; dev->a_ops.adapter_ioremap = aac_srcv_ioremap; dev->a_ops.adapter_comm = aac_src_select_comm; @@ -892,6 +899,7 @@ int aac_srcv_init(struct aac_dev *dev) dev->a_ops.adapter_sync_cmd = src_sync_cmd; dev->a_ops.adapter_check_health = aac_src_check_health; dev->a_ops.adapter_restart = aac_src_restart_adapter; + dev->a_ops.adapter_start = aac_src_start_adapter; /* * First clear out all interrupts. Then enable the one's that we @@ -908,48 +916,10 @@ int aac_srcv_init(struct aac_dev *dev) goto error_iounmap; if (dev->msi_enabled) aac_src_access_devreg(dev, AAC_ENABLE_MSIX); - if (!dev->sync_mode && dev->msi_enabled && dev->max_msix > 1) { - cpu = cpumask_first(cpu_online_mask); - for (i = 0; i < dev->max_msix; i++) { - dev->aac_msix[i].vector_no = i; - dev->aac_msix[i].dev = dev; - - if (request_irq(dev->msixentry[i].vector, - dev->a_ops.adapter_intr, - 0, - "aacraid", - &(dev->aac_msix[i]))) { - printk(KERN_ERR "%s%d: Failed to register IRQ for vector %d.\n", - name, instance, i); - for (j = 0 ; j < i ; j++) - free_irq(dev->msixentry[j].vector, - &(dev->aac_msix[j])); - pci_disable_msix(dev->pdev); - goto error_iounmap; - } - if (irq_set_affinity_hint( - dev->msixentry[i].vector, - get_cpu_mask(cpu))) { - printk(KERN_ERR "%s%d: Failed to set IRQ affinity for cpu %d\n", - name, instance, cpu); - } - cpu = cpumask_next(cpu, cpu_online_mask); - } - } else { - dev->aac_msix[0].vector_no = 0; - dev->aac_msix[0].dev = dev; - - if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr, - IRQF_SHARED, - "aacraid", - &(dev->aac_msix[0])) < 0) { - if (dev->msi) - pci_disable_msi(dev->pdev); - printk(KERN_ERR "%s%d: Interrupt unavailable.\n", - name, instance); - goto error_iounmap; - } - } + + if (aac_acquire_irq(dev)) + goto error_iounmap; + dev->dbg_base = dev->base_start; dev->dbg_base_mapped = dev->base; dev->dbg_size = dev->base_size; diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index 4305178e4e01..519f9a4b3dad 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c @@ -10819,7 +10819,6 @@ static struct scsi_host_template advansys_template = { * by enabling clustering, I/O throughput increases as well. */ .use_clustering = ENABLE_CLUSTERING, - .use_blk_tags = 1, }; static int advansys_wide_init_chip(struct Scsi_Host *shost) @@ -11211,11 +11210,6 @@ static int advansys_board_found(struct Scsi_Host *shost, unsigned int iop, /* Set maximum number of queues the adapter can handle. */ shost->can_queue = adv_dvc_varp->max_host_qng; } - ret = scsi_init_shared_tag_map(shost, shost->can_queue); - if (ret) { - shost_printk(KERN_ERR, shost, "init tag map failed\n"); - goto err_free_dma; - } /* * Set the maximum number of scatter-gather elements the diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index ce96a0be3282..2588b8f84ba0 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -925,7 +925,6 @@ struct scsi_host_template aic79xx_driver_template = { .slave_configure = ahd_linux_slave_configure, .target_alloc = ahd_linux_target_alloc, .target_destroy = ahd_linux_target_destroy, - .use_blk_tags = 1, }; /******************************** Bus DMA *************************************/ diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c index a2f2c774cd6b..b846a4683562 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c @@ -812,7 +812,6 @@ struct scsi_host_template aic7xxx_driver_template = { .slave_configure = ahc_linux_slave_configure, .target_alloc = ahc_linux_target_alloc, .target_destroy = ahc_linux_target_destroy, - .use_blk_tags = 1, }; /**************************** Tasklet Handler *********************************/ diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c index f6c336b05d5b..662b2321d1b0 100644 --- a/drivers/scsi/aic94xx/aic94xx_init.c +++ b/drivers/scsi/aic94xx/aic94xx_init.c @@ -73,7 +73,6 @@ static struct scsi_host_template aic94xx_sht = { .eh_bus_reset_handler = sas_eh_bus_reset_handler, .target_destroy = sas_target_destroy, .ioctl = sas_ioctl, - .use_blk_tags = 1, .track_queue_depth = 1, }; @@ -704,10 +703,10 @@ static int asd_unregister_sas_ha(struct asd_ha_struct *asd_ha) { int err; + scsi_remove_host(asd_ha->sas_ha.core.shost); err = sas_unregister_ha(&asd_ha->sas_ha); sas_remove_host(asd_ha->sas_ha.core.shost); - scsi_remove_host(asd_ha->sas_ha.core.shost); scsi_host_put(asd_ha->sas_ha.core.shost); kfree(asd_ha->sas_ha.sas_phy); diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 2e6abe7b7324..fe0c5143f8e6 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -1198,14 +1198,16 @@ free_io_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle) * alloc_wrb_handle - To allocate a wrb handle * @phba: The hba pointer * @cid: The cid to use for allocation + * @pwrb_context: ptr to ptr to wrb context * * This happens under session_lock until submission to chip */ -struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid) +struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid, + struct hwi_wrb_context **pcontext) { struct hwi_wrb_context *pwrb_context; struct hwi_controller *phwi_ctrlr; - struct wrb_handle *pwrb_handle, *pwrb_handle_tmp; + struct wrb_handle *pwrb_handle; uint16_t cri_index = BE_GET_CRI_FROM_CID(cid); phwi_ctrlr = phba->phwi_ctrlr; @@ -1219,9 +1221,9 @@ struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid) pwrb_context->alloc_index = 0; else pwrb_context->alloc_index++; - pwrb_handle_tmp = pwrb_context->pwrb_handle_base[ - pwrb_context->alloc_index]; - pwrb_handle->nxt_wrb_index = pwrb_handle_tmp->wrb_index; + + /* Return the context address */ + *pcontext = pwrb_context; } else pwrb_handle = NULL; return pwrb_handle; @@ -3184,7 +3186,7 @@ be_sgl_create_contiguous(void *virtual_address, { WARN_ON(!virtual_address); WARN_ON(!physical_address); - WARN_ON(!length > 0); + WARN_ON(!length); WARN_ON(!sgl); sgl->va = virtual_address; @@ -4678,6 +4680,7 @@ beiscsi_offload_connection(struct beiscsi_conn *beiscsi_conn, struct beiscsi_offload_params *params) { struct wrb_handle *pwrb_handle; + struct hwi_wrb_context *pwrb_context = NULL; struct beiscsi_hba *phba = beiscsi_conn->phba; struct iscsi_task *task = beiscsi_conn->task; struct iscsi_session *session = task->conn->session; @@ -4692,14 +4695,17 @@ beiscsi_offload_connection(struct beiscsi_conn *beiscsi_conn, beiscsi_cleanup_task(task); spin_unlock_bh(&session->back_lock); - pwrb_handle = alloc_wrb_handle(phba, beiscsi_conn->beiscsi_conn_cid); + pwrb_handle = alloc_wrb_handle(phba, beiscsi_conn->beiscsi_conn_cid, + &pwrb_context); /* Check for the adapter family */ if (is_chip_be2_be3r(phba)) beiscsi_offload_cxn_v0(params, pwrb_handle, - phba->init_mem); + phba->init_mem, + pwrb_context); else - beiscsi_offload_cxn_v2(params, pwrb_handle); + beiscsi_offload_cxn_v2(params, pwrb_handle, + pwrb_context); be_dws_le_to_cpu(pwrb_handle->pwrb, sizeof(struct iscsi_target_context_update_wrb)); @@ -4769,7 +4775,8 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode) goto free_hndls; } io_task->pwrb_handle = alloc_wrb_handle(phba, - beiscsi_conn->beiscsi_conn_cid); + beiscsi_conn->beiscsi_conn_cid, + &io_task->pwrb_context); if (!io_task->pwrb_handle) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG, @@ -4803,7 +4810,8 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode) io_task->psgl_handle; io_task->pwrb_handle = alloc_wrb_handle(phba, - beiscsi_conn->beiscsi_conn_cid); + beiscsi_conn->beiscsi_conn_cid, + &io_task->pwrb_context); if (!io_task->pwrb_handle) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_IO | @@ -4839,7 +4847,8 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode) } io_task->pwrb_handle = alloc_wrb_handle(phba, - beiscsi_conn->beiscsi_conn_cid); + beiscsi_conn->beiscsi_conn_cid, + &io_task->pwrb_context); if (!io_task->pwrb_handle) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG, @@ -4925,7 +4934,12 @@ int beiscsi_iotask_v2(struct iscsi_task *task, struct scatterlist *sg, hwi_write_sgl_v2(pwrb, sg, num_sg, io_task); AMAP_SET_BITS(struct amap_iscsi_wrb_v2, ptr2nextwrb, pwrb, - io_task->pwrb_handle->nxt_wrb_index); + io_task->pwrb_handle->wrb_index); + if (io_task->pwrb_context->plast_wrb) + AMAP_SET_BITS(struct amap_iscsi_wrb_v2, ptr2nextwrb, + io_task->pwrb_context->plast_wrb, + io_task->pwrb_handle->wrb_index); + io_task->pwrb_context->plast_wrb = pwrb; be_dws_le_to_cpu(pwrb, sizeof(struct iscsi_wrb)); @@ -4982,7 +4996,13 @@ static int beiscsi_iotask(struct iscsi_task *task, struct scatterlist *sg, hwi_write_sgl(pwrb, sg, num_sg, io_task); AMAP_SET_BITS(struct amap_iscsi_wrb, ptr2nextwrb, pwrb, - io_task->pwrb_handle->nxt_wrb_index); + io_task->pwrb_handle->wrb_index); + if (io_task->pwrb_context->plast_wrb) + AMAP_SET_BITS(struct amap_iscsi_wrb, ptr2nextwrb, + io_task->pwrb_context->plast_wrb, + io_task->pwrb_handle->wrb_index); + io_task->pwrb_context->plast_wrb = pwrb; + be_dws_le_to_cpu(pwrb, sizeof(struct iscsi_wrb)); doorbell |= beiscsi_conn->beiscsi_conn_cid & DB_WRB_POST_CID_MASK; @@ -5020,7 +5040,13 @@ static int beiscsi_mtask(struct iscsi_task *task) AMAP_SET_BITS(struct amap_iscsi_wrb, r2t_exp_dtl, pwrb, task->data_count); AMAP_SET_BITS(struct amap_iscsi_wrb, ptr2nextwrb, pwrb, - io_task->pwrb_handle->nxt_wrb_index); + io_task->pwrb_handle->wrb_index); + if (io_task->pwrb_context->plast_wrb) + AMAP_SET_BITS(struct amap_iscsi_wrb, ptr2nextwrb, + io_task->pwrb_context->plast_wrb, + io_task->pwrb_handle->wrb_index); + io_task->pwrb_context->plast_wrb = pwrb; + pwrb_typeoffset = BE_WRB_TYPE_OFFSET; } else { AMAP_SET_BITS(struct amap_iscsi_wrb_v2, cmdsn_itt, pwrb, @@ -5032,7 +5058,13 @@ static int beiscsi_mtask(struct iscsi_task *task) AMAP_SET_BITS(struct amap_iscsi_wrb_v2, r2t_exp_dtl, pwrb, task->data_count); AMAP_SET_BITS(struct amap_iscsi_wrb_v2, ptr2nextwrb, pwrb, - io_task->pwrb_handle->nxt_wrb_index); + io_task->pwrb_handle->wrb_index); + if (io_task->pwrb_context->plast_wrb) + AMAP_SET_BITS(struct amap_iscsi_wrb_v2, ptr2nextwrb, + io_task->pwrb_context->plast_wrb, + io_task->pwrb_handle->wrb_index); + io_task->pwrb_context->plast_wrb = pwrb; + pwrb_typeoffset = SKH_WRB_TYPE_OFFSET; } diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h index 51366de5ef70..5c67c0732241 100644 --- a/drivers/scsi/be2iscsi/be_main.h +++ b/drivers/scsi/be2iscsi/be_main.h @@ -36,7 +36,7 @@ #include <scsi/scsi_transport_iscsi.h> #define DRV_NAME "be2iscsi" -#define BUILD_STR "10.6.0.0" +#define BUILD_STR "10.6.0.1" #define BE_NAME "Emulex OneConnect" \ "Open-iSCSI Driver version" BUILD_STR #define DRV_DESC BE_NAME " " "Driver" @@ -502,6 +502,7 @@ struct beiscsi_io_task { struct sgl_handle *psgl_handle; struct beiscsi_conn *conn; struct scsi_cmnd *scsi_cmnd; + struct hwi_wrb_context *pwrb_context; unsigned int cmd_sn; unsigned int flags; unsigned short cid; @@ -833,7 +834,8 @@ struct amap_iscsi_wrb_v2 { } __packed; -struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid); +struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid, + struct hwi_wrb_context **pcontext); void free_mgmt_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle); @@ -1044,7 +1046,6 @@ enum hwh_type_enum { struct wrb_handle { enum hwh_type_enum type; unsigned short wrb_index; - unsigned short nxt_wrb_index; struct iscsi_task *pio_handle; struct iscsi_wrb *pwrb; diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c index 1b2bd044dad6..aea3e6b9477d 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.c +++ b/drivers/scsi/be2iscsi/be_mgmt.c @@ -1573,7 +1573,8 @@ beiscsi_phys_port_disp(struct device *dev, struct device_attribute *attr, void beiscsi_offload_cxn_v0(struct beiscsi_offload_params *params, struct wrb_handle *pwrb_handle, - struct be_mem_descriptor *mem_descr) + struct be_mem_descriptor *mem_descr, + struct hwi_wrb_context *pwrb_context) { struct iscsi_wrb *pwrb = pwrb_handle->pwrb; @@ -1617,7 +1618,14 @@ void beiscsi_offload_cxn_v0(struct beiscsi_offload_params *params, max_burst_length) / 32]); AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, ptr2nextwrb, - pwrb, pwrb_handle->nxt_wrb_index); + pwrb, pwrb_handle->wrb_index); + if (pwrb_context->plast_wrb) + AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, + ptr2nextwrb, + pwrb_context->plast_wrb, + pwrb_handle->wrb_index); + pwrb_context->plast_wrb = pwrb; + AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, session_state, pwrb, 0); AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, compltonack, @@ -1637,7 +1645,8 @@ void beiscsi_offload_cxn_v0(struct beiscsi_offload_params *params, } void beiscsi_offload_cxn_v2(struct beiscsi_offload_params *params, - struct wrb_handle *pwrb_handle) + struct wrb_handle *pwrb_handle, + struct hwi_wrb_context *pwrb_context) { struct iscsi_wrb *pwrb = pwrb_handle->pwrb; @@ -1652,7 +1661,14 @@ void beiscsi_offload_cxn_v2(struct beiscsi_offload_params *params, BE_TGT_CTX_UPDT_CMD); AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, ptr2nextwrb, - pwrb, pwrb_handle->nxt_wrb_index); + pwrb, pwrb_handle->wrb_index); + if (pwrb_context->plast_wrb) + AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, + ptr2nextwrb, + pwrb_context->plast_wrb, + pwrb_handle->wrb_index); + pwrb_context->plast_wrb = pwrb; + AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, wrb_idx, pwrb, pwrb_handle->wrb_index); AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, diff --git a/drivers/scsi/be2iscsi/be_mgmt.h b/drivers/scsi/be2iscsi/be_mgmt.h index afa326da75c6..c1dbb690ee27 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.h +++ b/drivers/scsi/be2iscsi/be_mgmt.h @@ -330,10 +330,13 @@ ssize_t beiscsi_phys_port_disp(struct device *dev, void beiscsi_offload_cxn_v0(struct beiscsi_offload_params *params, struct wrb_handle *pwrb_handle, - struct be_mem_descriptor *mem_descr); + struct be_mem_descriptor *mem_descr, + struct hwi_wrb_context *pwrb_context); void beiscsi_offload_cxn_v2(struct beiscsi_offload_params *params, - struct wrb_handle *pwrb_handle); + struct wrb_handle *pwrb_handle, + struct hwi_wrb_context *pwrb_context); + void beiscsi_ue_detect(struct beiscsi_hba *phba); int be_cmd_modify_eq_delay(struct beiscsi_hba *phba, struct be_set_eqd *, int num); diff --git a/drivers/scsi/bfa/bfad_im.c b/drivers/scsi/bfa/bfad_im.c index 8367c11d554b..299c6f80d460 100644 --- a/drivers/scsi/bfa/bfad_im.c +++ b/drivers/scsi/bfa/bfad_im.c @@ -800,7 +800,6 @@ struct scsi_host_template bfad_im_scsi_host_template = { .shost_attrs = bfad_im_host_attrs, .max_sectors = BFAD_MAX_SECTORS, .vendor_id = BFA_PCI_VENDOR_ID_BROCADE, - .use_blk_tags = 1, }; struct scsi_host_template bfad_im_vport_template = { @@ -822,7 +821,6 @@ struct scsi_host_template bfad_im_vport_template = { .use_clustering = ENABLE_CLUSTERING, .shost_attrs = bfad_im_vport_attrs, .max_sectors = BFAD_MAX_SECTORS, - .use_blk_tags = 1, }; bfa_status_t diff --git a/drivers/scsi/bnx2fc/57xx_hsi_bnx2fc.h b/drivers/scsi/bnx2fc/57xx_hsi_bnx2fc.h index fe2106c91c08..ac1c0b631aca 100644 --- a/drivers/scsi/bnx2fc/57xx_hsi_bnx2fc.h +++ b/drivers/scsi/bnx2fc/57xx_hsi_bnx2fc.h @@ -1,9 +1,9 @@ -/* 57xx_hsi_bnx2fc.h: QLogic NetXtreme II Linux FCoE offload driver. +/* 57xx_hsi_bnx2fc.h: QLogic Linux FCoE offload driver. * Handles operations such as session offload/upload etc, and manages * session resources such as connection id and qp resources. * - * Copyright (c) 2008 - 2013 Broadcom Corporation - * Copyright (c) 2014, QLogic Corporation + * Copyright (c) 2008-2013 Broadcom Corporation + * Copyright (c) 2014-2015 QLogic 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/bnx2fc/Kconfig b/drivers/scsi/bnx2fc/Kconfig index 097882882649..d401a096dfc7 100644 --- a/drivers/scsi/bnx2fc/Kconfig +++ b/drivers/scsi/bnx2fc/Kconfig @@ -1,5 +1,5 @@ config SCSI_BNX2X_FCOE - tristate "QLogic NetXtreme II FCoE support" + tristate "QLogic FCoE offload support" depends on PCI depends on (IPV6 || IPV6=n) depends on LIBFC @@ -9,5 +9,4 @@ config SCSI_BNX2X_FCOE select NET_VENDOR_BROADCOM select CNIC ---help--- - This driver supports FCoE offload for the QLogic NetXtreme II - devices. + This driver supports FCoE offload for the QLogic devices. diff --git a/drivers/scsi/bnx2fc/bnx2fc.h b/drivers/scsi/bnx2fc/bnx2fc.h index 1346e052e03c..499e369eabf0 100644 --- a/drivers/scsi/bnx2fc/bnx2fc.h +++ b/drivers/scsi/bnx2fc/bnx2fc.h @@ -1,7 +1,7 @@ -/* bnx2fc.h: QLogic NetXtreme II Linux FCoE offload driver. +/* bnx2fc.h: QLogic Linux FCoE offload driver. * - * Copyright (c) 2008 - 2013 Broadcom Corporation - * Copyright (c) 2014, QLogic Corporation + * Copyright (c) 2008-2013 Broadcom Corporation + * Copyright (c) 2014-2015 QLogic 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 @@ -65,7 +65,7 @@ #include "bnx2fc_constants.h" #define BNX2FC_NAME "bnx2fc" -#define BNX2FC_VERSION "2.4.2" +#define BNX2FC_VERSION "2.9.6" #define PFX "bnx2fc: " @@ -303,7 +303,6 @@ struct bnx2fc_rport { #define BNX2FC_FLAG_OFLD_REQ_CMPL 0x5 #define BNX2FC_FLAG_CTX_ALLOC_FAILURE 0x6 #define BNX2FC_FLAG_UPLD_REQ_COMPL 0x7 -#define BNX2FC_FLAG_EXPL_LOGO 0x8 #define BNX2FC_FLAG_DISABLE_FAILED 0x9 #define BNX2FC_FLAG_ENABLED 0xa diff --git a/drivers/scsi/bnx2fc/bnx2fc_constants.h b/drivers/scsi/bnx2fc/bnx2fc_constants.h index e147cc7ee36c..5b20efb661a5 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_constants.h +++ b/drivers/scsi/bnx2fc/bnx2fc_constants.h @@ -1,9 +1,9 @@ -/* bnx2fc_constants.h: QLogic NetXtreme II Linux FCoE offload driver. +/* bnx2fc_constants.h: QLogic Linux FCoE offload driver. * Handles operations such as session offload/upload etc, and manages * session resources such as connection id and qp resources. * - * Copyright (c) 2008 - 2013 Broadcom Corporation - * Copyright (c) 2014, QLogic Corporation + * Copyright (c) 2008-2013 Broadcom Corporation + * Copyright (c) 2014-2015 QLogic 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/bnx2fc/bnx2fc_debug.c b/drivers/scsi/bnx2fc/bnx2fc_debug.c index d055df01faa5..c9e0bc7fad3b 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_debug.c +++ b/drivers/scsi/bnx2fc/bnx2fc_debug.c @@ -1,9 +1,9 @@ -/* bnx2fc_debug.c: QLogic NetXtreme II Linux FCoE offload driver. +/* bnx2fc_debug.c: QLogic Linux FCoE offload driver. * Handles operations such as session offload/upload etc, and manages * session resources such as connection id and qp resources. * - * Copyright (c) 2008 - 2013 Broadcom Corporation - * Copyright (c) 2014, QLogic Corporation + * Copyright (c) 2008-2013 Broadcom Corporation + * Copyright (c) 2014-2015 QLogic 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/bnx2fc/bnx2fc_debug.h b/drivers/scsi/bnx2fc/bnx2fc_debug.h index 2b9006774f37..34fda3e04d27 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_debug.h +++ b/drivers/scsi/bnx2fc/bnx2fc_debug.h @@ -1,9 +1,9 @@ -/* bnx2fc_debug.h: QLogic NetXtreme II Linux FCoE offload driver. +/* bnx2fc_debug.h: QLogic Linux FCoE offload driver. * Handles operations such as session offload/upload etc, and manages * session resources such as connection id and qp resources. * - * Copyright (c) 2008 - 2013 Broadcom Corporation - * Copyright (c) 2014, QLogic Corporation + * Copyright (c) 2008-2013 Broadcom Corporation + * Copyright (c) 2014-2015 QLogic 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/bnx2fc/bnx2fc_els.c b/drivers/scsi/bnx2fc/bnx2fc_els.c index ef355c13ccc4..5beea776b9f5 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_els.c +++ b/drivers/scsi/bnx2fc/bnx2fc_els.c @@ -1,10 +1,10 @@ /* - * bnx2fc_els.c: QLogic NetXtreme II Linux FCoE offload driver. + * bnx2fc_els.c: QLogic Linux FCoE offload driver. * This file contains helper routines that handle ELS requests * and responses. * - * Copyright (c) 2008 - 2013 Broadcom Corporation - * Copyright (c) 2014, QLogic Corporation + * Copyright (c) 2008-2013 Broadcom Corporation + * Copyright (c) 2014-2015 QLogic 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 @@ -689,8 +689,7 @@ static int bnx2fc_initiate_els(struct bnx2fc_rport *tgt, unsigned int op, rc = -EINVAL; goto els_err; } - if (!(test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags)) || - (test_bit(BNX2FC_FLAG_EXPL_LOGO, &tgt->flags))) { + if (!(test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags))) { printk(KERN_ERR PFX "els 0x%x: tgt not ready\n", op); rc = -EINVAL; goto els_err; @@ -707,6 +706,7 @@ static int bnx2fc_initiate_els(struct bnx2fc_rport *tgt, unsigned int op, els_req->cb_func = cb_func; cb_arg->io_req = els_req; els_req->cb_arg = cb_arg; + els_req->data_xfer_len = data_len; mp_req = (struct bnx2fc_mp_req *)&(els_req->mp_req); rc = bnx2fc_init_mp_req(els_req); diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c index b0bc5ffee903..67405c628864 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c @@ -1,10 +1,10 @@ -/* bnx2fc_fcoe.c: QLogic NetXtreme II Linux FCoE offload driver. +/* bnx2fc_fcoe.c: QLogic Linux FCoE offload driver. * This file contains the code that interacts with libfc, libfcoe, * cnic modules to create FCoE instances, send/receive non-offloaded * FIP/FCoE packets, listen to link events etc. * - * Copyright (c) 2008 - 2013 Broadcom Corporation - * Copyright (c) 2014, QLogic Corporation + * Copyright (c) 2008-2013 Broadcom Corporation + * Copyright (c) 2014-2015 QLogic 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 @@ -23,16 +23,16 @@ DEFINE_PER_CPU(struct bnx2fc_percpu_s, bnx2fc_percpu); #define DRV_MODULE_NAME "bnx2fc" #define DRV_MODULE_VERSION BNX2FC_VERSION -#define DRV_MODULE_RELDATE "Dec 11, 2013" +#define DRV_MODULE_RELDATE "October 15, 2015" static char version[] = - "QLogic NetXtreme II FCoE Driver " DRV_MODULE_NAME \ + "QLogic FCoE Driver " DRV_MODULE_NAME \ " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; MODULE_AUTHOR("Bhanu Prakash Gollapudi <bprakash@broadcom.com>"); -MODULE_DESCRIPTION("QLogic NetXtreme II BCM57710 FCoE Driver"); +MODULE_DESCRIPTION("QLogic FCoE Driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_MODULE_VERSION); @@ -2091,7 +2091,7 @@ static int __bnx2fc_enable(struct fcoe_ctlr *ctlr) { struct bnx2fc_interface *interface = fcoe_ctlr_priv(ctlr); struct bnx2fc_hba *hba; - struct cnic_fc_npiv_tbl npiv_tbl; + struct cnic_fc_npiv_tbl *npiv_tbl; struct fc_lport *lport; if (interface->enabled == false) { @@ -2123,11 +2123,16 @@ static int __bnx2fc_enable(struct fcoe_ctlr *ctlr) if (!hba->cnic->get_fc_npiv_tbl) goto done; - memset(&npiv_tbl, 0, sizeof(npiv_tbl)); - if (hba->cnic->get_fc_npiv_tbl(hba->cnic, &npiv_tbl)) + npiv_tbl = kzalloc(sizeof(struct cnic_fc_npiv_tbl), GFP_KERNEL); + if (!npiv_tbl) goto done; - bnx2fc_npiv_create_vports(lport, &npiv_tbl); + if (hba->cnic->get_fc_npiv_tbl(hba->cnic, npiv_tbl)) + goto done_free; + + bnx2fc_npiv_create_vports(lport, npiv_tbl); +done_free: + kfree(npiv_tbl); done: return 0; } @@ -2862,7 +2867,6 @@ static struct scsi_host_template bnx2fc_shost_template = { .use_clustering = ENABLE_CLUSTERING, .sg_tablesize = BNX2FC_MAX_BDS_PER_CMD, .max_sectors = 1024, - .use_blk_tags = 1, .track_queue_depth = 1, }; diff --git a/drivers/scsi/bnx2fc/bnx2fc_hwi.c b/drivers/scsi/bnx2fc/bnx2fc_hwi.c index c6688d72a846..28c671b609b2 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_hwi.c +++ b/drivers/scsi/bnx2fc/bnx2fc_hwi.c @@ -1,9 +1,9 @@ -/* bnx2fc_hwi.c: QLogic NetXtreme II Linux FCoE offload driver. +/* bnx2fc_hwi.c: QLogic Linux FCoE offload driver. * This file contains the code that low level functions that interact * with 57712 FCoE firmware. * - * Copyright (c) 2008 - 2013 Broadcom Corporation - * Copyright (c) 2014, QLogic Corporation + * Copyright (c) 2008-2013 Broadcom Corporation + * Copyright (c) 2014-2015 QLogic 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/bnx2fc/bnx2fc_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c index 9ecca8504f60..0002caf687dd 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_io.c +++ b/drivers/scsi/bnx2fc/bnx2fc_io.c @@ -1,8 +1,8 @@ -/* bnx2fc_io.c: QLogic NetXtreme II Linux FCoE offload driver. +/* bnx2fc_io.c: QLogic Linux FCoE offload driver. * IO manager and SCSI IO processing. * - * Copyright (c) 2008 - 2013 Broadcom Corporation - * Copyright (c) 2014, QLogic Corporation + * Copyright (c) 2008-2013 Broadcom Corporation + * Copyright (c) 2014-2015 QLogic 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 @@ -40,11 +40,8 @@ static void bnx2fc_cmd_timeout(struct work_struct *work) { struct bnx2fc_cmd *io_req = container_of(work, struct bnx2fc_cmd, timeout_work.work); - struct fc_lport *lport; - struct fc_rport_priv *rdata; u8 cmd_type = io_req->cmd_type; struct bnx2fc_rport *tgt = io_req->tgt; - int logo_issued; int rc; BNX2FC_IO_DBG(io_req, "cmd_timeout, cmd_type = %d," @@ -80,25 +77,14 @@ static void bnx2fc_cmd_timeout(struct work_struct *work) io_req->refcount.refcount.counter); if (!(test_and_set_bit(BNX2FC_FLAG_ABTS_DONE, &io_req->req_flags))) { - - lport = io_req->port->lport; - rdata = io_req->tgt->rdata; - logo_issued = test_and_set_bit( - BNX2FC_FLAG_EXPL_LOGO, - &tgt->flags); + /* + * Cleanup and return original command to + * mid-layer. + */ + bnx2fc_initiate_cleanup(io_req); kref_put(&io_req->refcount, bnx2fc_cmd_release); spin_unlock_bh(&tgt->tgt_lock); - /* Explicitly logo the target */ - if (!logo_issued) { - BNX2FC_IO_DBG(io_req, "Explicit " - "logo - tgt flags = 0x%lx\n", - tgt->flags); - - mutex_lock(&lport->disc.disc_mutex); - lport->tt.rport_logoff(rdata); - mutex_unlock(&lport->disc.disc_mutex); - } return; } } else { @@ -116,28 +102,10 @@ static void bnx2fc_cmd_timeout(struct work_struct *work) rc = bnx2fc_initiate_abts(io_req); if (rc == SUCCESS) goto done; - /* - * Explicitly logo the target if - * abts initiation fails - */ - lport = io_req->port->lport; - rdata = io_req->tgt->rdata; - logo_issued = test_and_set_bit( - BNX2FC_FLAG_EXPL_LOGO, - &tgt->flags); + kref_put(&io_req->refcount, bnx2fc_cmd_release); spin_unlock_bh(&tgt->tgt_lock); - if (!logo_issued) { - BNX2FC_IO_DBG(io_req, "Explicit " - "logo - tgt flags = 0x%lx\n", - tgt->flags); - - - mutex_lock(&lport->disc.disc_mutex); - lport->tt.rport_logoff(rdata); - mutex_unlock(&lport->disc.disc_mutex); - } return; } else { BNX2FC_IO_DBG(io_req, "IO already in " @@ -152,22 +120,9 @@ static void bnx2fc_cmd_timeout(struct work_struct *work) if (!test_and_set_bit(BNX2FC_FLAG_ABTS_DONE, &io_req->req_flags)) { - lport = io_req->port->lport; - rdata = io_req->tgt->rdata; - logo_issued = test_and_set_bit( - BNX2FC_FLAG_EXPL_LOGO, - &tgt->flags); kref_put(&io_req->refcount, bnx2fc_cmd_release); spin_unlock_bh(&tgt->tgt_lock); - /* Explicitly logo the target */ - if (!logo_issued) { - BNX2FC_IO_DBG(io_req, "Explicitly logo" - "(els)\n"); - mutex_lock(&lport->disc.disc_mutex); - lport->tt.rport_logoff(rdata); - mutex_unlock(&lport->disc.disc_mutex); - } return; } } else { @@ -623,8 +578,12 @@ int bnx2fc_init_mp_req(struct bnx2fc_cmd *io_req) mp_req = (struct bnx2fc_mp_req *)&(io_req->mp_req); memset(mp_req, 0, sizeof(struct bnx2fc_mp_req)); - mp_req->req_len = sizeof(struct fcp_cmnd); - io_req->data_xfer_len = mp_req->req_len; + if (io_req->cmd_type != BNX2FC_ELS) { + mp_req->req_len = sizeof(struct fcp_cmnd); + io_req->data_xfer_len = mp_req->req_len; + } else + mp_req->req_len = io_req->data_xfer_len; + mp_req->req_buf = dma_alloc_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE, &mp_req->req_buf_dma, GFP_ATOMIC); @@ -1108,18 +1067,11 @@ int bnx2fc_eh_device_reset(struct scsi_cmnd *sc_cmd) return bnx2fc_initiate_tmf(sc_cmd, FCP_TMF_LUN_RESET); } -int bnx2fc_expl_logo(struct fc_lport *lport, struct bnx2fc_cmd *io_req) +int bnx2fc_abts_cleanup(struct bnx2fc_cmd *io_req) { struct bnx2fc_rport *tgt = io_req->tgt; - struct fc_rport_priv *rdata = tgt->rdata; - int logo_issued; int rc = SUCCESS; - int wait_cnt = 0; - BNX2FC_IO_DBG(io_req, "Expl logo - tgt flags = 0x%lx\n", - tgt->flags); - logo_issued = test_and_set_bit(BNX2FC_FLAG_EXPL_LOGO, - &tgt->flags); io_req->wait_for_comp = 1; bnx2fc_initiate_cleanup(io_req); @@ -1132,21 +1084,8 @@ int bnx2fc_expl_logo(struct fc_lport *lport, struct bnx2fc_cmd *io_req) * release the reference taken in eh_abort to allow the * target to re-login after flushing IOs */ - kref_put(&io_req->refcount, bnx2fc_cmd_release); - - if (!logo_issued) { - clear_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags); - mutex_lock(&lport->disc.disc_mutex); - lport->tt.rport_logoff(rdata); - mutex_unlock(&lport->disc.disc_mutex); - do { - msleep(BNX2FC_RELOGIN_WAIT_TIME); - if (wait_cnt++ > BNX2FC_RELOGIN_WAIT_CNT) { - rc = FAILED; - break; - } - } while (!test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags)); - } + kref_put(&io_req->refcount, bnx2fc_cmd_release); + spin_lock_bh(&tgt->tgt_lock); return rc; } @@ -1248,7 +1187,7 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd) if (cancel_delayed_work(&io_req->timeout_work)) kref_put(&io_req->refcount, bnx2fc_cmd_release); /* drop timer hold */ - rc = bnx2fc_expl_logo(lport, io_req); + rc = bnx2fc_abts_cleanup(io_req); /* This only occurs when an task abort was requested while ABTS is in progress. Setting the IO_CLEANUP flag will skip the RRQ process in the case when the fw generated SCSI_CMD cmpl @@ -1287,7 +1226,7 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd) /* Let the scsi-ml try to recover this command */ printk(KERN_ERR PFX "abort failed, xid = 0x%x\n", io_req->xid); - rc = bnx2fc_expl_logo(lport, io_req); + rc = bnx2fc_abts_cleanup(io_req); goto out; } else { /* @@ -1755,7 +1694,10 @@ static void bnx2fc_parse_fcp_rsp(struct bnx2fc_cmd *io_req, int fcp_rsp_len = 0; io_req->fcp_status = FC_GOOD; - io_req->fcp_resid = fcp_rsp->fcp_resid; + io_req->fcp_resid = 0; + if (rsp_flags & (FCOE_FCP_RSP_FLAGS_FCP_RESID_OVER | + FCOE_FCP_RSP_FLAGS_FCP_RESID_UNDER)) + io_req->fcp_resid = fcp_rsp->fcp_resid; io_req->scsi_comp_flags = rsp_flags; CMD_SCSI_STATUS(sc_cmd) = io_req->cdb_status = diff --git a/drivers/scsi/bnx2fc/bnx2fc_tgt.c b/drivers/scsi/bnx2fc/bnx2fc_tgt.c index c66c708412a6..08ec318afb99 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_tgt.c +++ b/drivers/scsi/bnx2fc/bnx2fc_tgt.c @@ -1,9 +1,9 @@ -/* bnx2fc_tgt.c: QLogic NetXtreme II Linux FCoE offload driver. +/* bnx2fc_tgt.c: QLogic Linux FCoE offload driver. * Handles operations such as session offload/upload etc, and manages * session resources such as connection id and qp resources. * - * Copyright (c) 2008 - 2013 Broadcom Corporation - * Copyright (c) 2014, QLogic Corporation + * Copyright (c) 2008-2013 Broadcom Corporation + * Copyright (c) 2014-2015 QLogic 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 @@ -560,12 +560,6 @@ void bnx2fc_rport_event_handler(struct fc_lport *lport, (hba->num_ofld_sess == 0)) { wake_up_interruptible(&hba->shutdown_wait); } - if (test_bit(BNX2FC_FLAG_EXPL_LOGO, &tgt->flags)) { - printk(KERN_ERR PFX "Relogin to the tgt\n"); - mutex_lock(&lport->disc.disc_mutex); - lport->tt.rport_login(rdata); - mutex_unlock(&lport->disc.disc_mutex); - } mutex_unlock(&hba->hba_mutex); break; diff --git a/drivers/scsi/csiostor/csio_scsi.c b/drivers/scsi/csiostor/csio_scsi.c index 2c4562d82dc0..c2a6f9f29427 100644 --- a/drivers/scsi/csiostor/csio_scsi.c +++ b/drivers/scsi/csiostor/csio_scsi.c @@ -2283,7 +2283,6 @@ struct scsi_host_template csio_fcoe_shost_template = { .use_clustering = ENABLE_CLUSTERING, .shost_attrs = csio_fcoe_lport_attrs, .max_sectors = CSIO_MAX_SECTOR_SIZE, - .use_blk_tags = 1, }; struct scsi_host_template csio_fcoe_shost_vport_template = { @@ -2303,7 +2302,6 @@ struct scsi_host_template csio_fcoe_shost_vport_template = { .use_clustering = ENABLE_CLUSTERING, .shost_attrs = csio_fcoe_vport_attrs, .max_sectors = CSIO_MAX_SECTOR_SIZE, - .use_blk_tags = 1, }; /* diff --git a/drivers/scsi/esas2r/esas2r_main.c b/drivers/scsi/esas2r/esas2r_main.c index 31f8966b2e03..33581ba4386e 100644 --- a/drivers/scsi/esas2r/esas2r_main.c +++ b/drivers/scsi/esas2r/esas2r_main.c @@ -256,7 +256,6 @@ static struct scsi_host_template driver_template = { .proc_name = ESAS2R_DRVR_NAME, .change_queue_depth = scsi_change_queue_depth, .max_sectors = 0xFFFF, - .use_blk_tags = 1, }; int sgl_page_size = 512; diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c index 065b25df741b..71cb05b1c3eb 100644 --- a/drivers/scsi/esp_scsi.c +++ b/drivers/scsi/esp_scsi.c @@ -2694,7 +2694,6 @@ struct scsi_host_template scsi_esp_template = { .use_clustering = ENABLE_CLUSTERING, .max_sectors = 0xffff, .skip_settle_delay = 1, - .use_blk_tags = 1, }; EXPORT_SYMBOL(scsi_esp_template); diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index d3eb80c46bbe..f4424063b860 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -287,7 +287,6 @@ static struct scsi_host_template fcoe_shost_template = { .use_clustering = ENABLE_CLUSTERING, .sg_tablesize = SG_ALL, .max_sectors = 0xffff, - .use_blk_tags = 1, .track_queue_depth = 1, }; @@ -1873,7 +1872,6 @@ static int fcoe_percpu_receive_thread(void *arg) set_user_nice(current, MIN_NICE); -retry: while (!kthread_should_stop()) { spin_lock_bh(&p->fcoe_rx_list.lock); @@ -1883,7 +1881,7 @@ retry: set_current_state(TASK_INTERRUPTIBLE); spin_unlock_bh(&p->fcoe_rx_list.lock); schedule(); - goto retry; + continue; } spin_unlock_bh(&p->fcoe_rx_list.lock); diff --git a/drivers/scsi/fnic/fnic_main.c b/drivers/scsi/fnic/fnic_main.c index 8a0d4d7b3254..58ce9020d69c 100644 --- a/drivers/scsi/fnic/fnic_main.c +++ b/drivers/scsi/fnic/fnic_main.c @@ -118,7 +118,6 @@ static struct scsi_host_template fnic_host_template = { .sg_tablesize = FNIC_MAX_SG_DESC_CNT, .max_sectors = 0xffff, .shost_attrs = fnic_attrs, - .use_blk_tags = 1, .track_queue_depth = 1, }; @@ -697,13 +696,6 @@ static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } fnic->fnic_max_tag_id = host->can_queue; - err = scsi_init_shared_tag_map(host, fnic->fnic_max_tag_id); - if (err) { - shost_printk(KERN_ERR, fnic->lport->host, - "Unable to alloc shared tag map\n"); - goto err_out_dev_close; - } - host->max_lun = fnic->config.luns_per_tgt; host->max_id = FNIC_MAX_FCP_TARGET; host->max_cmd_len = FCOE_MAX_CMD_LEN; diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 8bb173e01084..323982fd00c3 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -217,6 +217,13 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev, error = scsi_mq_setup_tags(shost); if (error) goto fail; + } else { + shost->bqt = blk_init_tags(shost->can_queue, + shost->hostt->tag_alloc_policy); + if (!shost->bqt) { + error = -ENOMEM; + goto fail; + } } /* diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 40669f8dd0df..6a8f95808ee0 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -41,6 +41,7 @@ #include <scsi/scsi_host.h> #include <scsi/scsi_tcq.h> #include <scsi/scsi_eh.h> +#include <scsi/scsi_transport_sas.h> #include <scsi/scsi_dbg.h> #include <linux/cciss_ioctl.h> #include <linux/string.h> @@ -54,8 +55,11 @@ #include "hpsa_cmd.h" #include "hpsa.h" -/* HPSA_DRIVER_VERSION must be 3 byte values (0-255) separated by '.' */ -#define HPSA_DRIVER_VERSION "3.4.10-0" +/* + * HPSA_DRIVER_VERSION must be 3 byte values (0-255) separated by '.' + * with an optional trailing '-' followed by a byte value (0-255). + */ +#define HPSA_DRIVER_VERSION "3.4.14-0" #define DRIVER_NAME "HP HPSA Driver (v " HPSA_DRIVER_VERSION ")" #define HPSA "hpsa" @@ -205,6 +209,16 @@ static struct board_type products[] = { {0xFFFF103C, "Unknown Smart Array", &SA5_access}, }; +static struct scsi_transport_template *hpsa_sas_transport_template; +static int hpsa_add_sas_host(struct ctlr_info *h); +static void hpsa_delete_sas_host(struct ctlr_info *h); +static int hpsa_add_sas_device(struct hpsa_sas_node *hpsa_sas_node, + struct hpsa_scsi_dev_t *device); +static void hpsa_remove_sas_device(struct hpsa_scsi_dev_t *device); +static struct hpsa_scsi_dev_t + *hpsa_find_device_by_sas_rphy(struct ctlr_info *h, + struct sas_rphy *rphy); + #define SCSI_CMD_BUSY ((struct scsi_cmnd *)&hpsa_cmd_busy) static const struct scsi_cmnd hpsa_cmd_busy; #define SCSI_CMD_IDLE ((struct scsi_cmnd *)&hpsa_cmd_idle) @@ -230,6 +244,7 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, int cmd_type); static void hpsa_free_cmd_pool(struct ctlr_info *h); #define VPD_PAGE (1 << 8) +#define HPSA_SIMPLE_ERROR_BITS 0x03 static int hpsa_scsi_queue_command(struct Scsi_Host *h, struct scsi_cmnd *cmd); static void hpsa_scan_start(struct Scsi_Host *); @@ -243,7 +258,7 @@ static int hpsa_slave_alloc(struct scsi_device *sdev); static int hpsa_slave_configure(struct scsi_device *sdev); static void hpsa_slave_destroy(struct scsi_device *sdev); -static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno); +static void hpsa_update_scsi_devices(struct ctlr_info *h); static int check_for_unit_attention(struct ctlr_info *h, struct CommandList *c); static void check_ioctl_unit_attention(struct ctlr_info *h, @@ -274,7 +289,10 @@ static int hpsa_scsi_ioaccel_queue_command(struct ctlr_info *h, static void hpsa_command_resubmit_worker(struct work_struct *work); static u32 lockup_detected(struct ctlr_info *h); static int detect_controller_lockup(struct ctlr_info *h); -static int is_ext_target(struct ctlr_info *h, struct hpsa_scsi_dev_t *device); +static void hpsa_disable_rld_caching(struct ctlr_info *h); +static inline int hpsa_scsi_do_report_phys_luns(struct ctlr_info *h, + struct ReportExtendedLUNdata *buf, int bufsize); +static int hpsa_luns_changed(struct ctlr_info *h); static inline struct ctlr_info *sdev_to_hba(struct scsi_device *sdev) { @@ -606,7 +624,7 @@ static inline int is_logical_dev_addr_mode(unsigned char scsi3addr[]) } static const char * const raid_label[] = { "0", "4", "1(+0)", "5", "5+1", "6", - "1(+0)ADM", "UNKNOWN" + "1(+0)ADM", "UNKNOWN", "PHYS DRV" }; #define HPSA_RAID_0 0 #define HPSA_RAID_4 1 @@ -615,7 +633,13 @@ static const char * const raid_label[] = { "0", "4", "1(+0)", "5", "5+1", "6", #define HPSA_RAID_51 4 #define HPSA_RAID_6 5 /* also used for RAID 60 */ #define HPSA_RAID_ADM 6 /* also used for RAID 1+0 ADM */ -#define RAID_UNKNOWN (ARRAY_SIZE(raid_label) - 1) +#define RAID_UNKNOWN (ARRAY_SIZE(raid_label) - 2) +#define PHYSICAL_DRIVE (ARRAY_SIZE(raid_label) - 1) + +static inline bool is_logical_device(struct hpsa_scsi_dev_t *device) +{ + return !device->physical_device; +} static ssize_t raid_level_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -637,7 +661,7 @@ static ssize_t raid_level_show(struct device *dev, } /* Is this even a logical drive? */ - if (!is_logical_dev_addr_mode(hdev->scsi3addr)) { + if (!is_logical_device(hdev)) { spin_unlock_irqrestore(&h->lock, flags); l = snprintf(buf, PAGE_SIZE, "N/A\n"); return l; @@ -726,7 +750,6 @@ static ssize_t host_show_hp_ssd_smart_path_enabled(struct device *dev, } #define MAX_PATHS 8 -#define PATH_STRING_LEN 50 static ssize_t path_info_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -742,9 +765,7 @@ static ssize_t path_info_show(struct device *dev, u8 path_map_index = 0; char *active; unsigned char phys_connector[2]; - unsigned char path[MAX_PATHS][PATH_STRING_LEN]; - memset(path, 0, MAX_PATHS * PATH_STRING_LEN); sdev = to_scsi_device(dev); h = sdev_to_hba(sdev); spin_lock_irqsave(&h->devlock, flags); @@ -764,18 +785,19 @@ static ssize_t path_info_show(struct device *dev, else continue; - output_len = snprintf(path[i], - PATH_STRING_LEN, "[%d:%d:%d:%d] %20.20s ", + output_len += scnprintf(buf + output_len, + PAGE_SIZE - output_len, + "[%d:%d:%d:%d] %20.20s ", h->scsi_host->host_no, hdev->bus, hdev->target, hdev->lun, scsi_device_type(hdev->devtype)); - if (is_ext_target(h, hdev) || - (hdev->devtype == TYPE_RAID) || - is_logical_dev_addr_mode(hdev->scsi3addr)) { - output_len += snprintf(path[i] + output_len, - PATH_STRING_LEN, "%s\n", - active); + if (hdev->external || + hdev->devtype == TYPE_RAID || + is_logical_device(hdev)) { + output_len += snprintf(buf + output_len, + PAGE_SIZE - output_len, + "%s\n", active); continue; } @@ -787,36 +809,33 @@ static ssize_t path_info_show(struct device *dev, if (phys_connector[1] < '0') phys_connector[1] = '0'; if (hdev->phys_connector[i] > 0) - output_len += snprintf(path[i] + output_len, - PATH_STRING_LEN, + output_len += snprintf(buf + output_len, + PAGE_SIZE - output_len, "PORT: %.2s ", phys_connector); - if (hdev->devtype == TYPE_DISK && - hdev->expose_state != HPSA_DO_NOT_EXPOSE) { + if (hdev->devtype == TYPE_DISK && hdev->expose_device) { if (box == 0 || box == 0xFF) { - output_len += snprintf(path[i] + output_len, - PATH_STRING_LEN, + output_len += snprintf(buf + output_len, + PAGE_SIZE - output_len, "BAY: %hhu %s\n", bay, active); } else { - output_len += snprintf(path[i] + output_len, - PATH_STRING_LEN, + output_len += snprintf(buf + output_len, + PAGE_SIZE - output_len, "BOX: %hhu BAY: %hhu %s\n", box, bay, active); } } else if (box != 0 && box != 0xFF) { - output_len += snprintf(path[i] + output_len, - PATH_STRING_LEN, "BOX: %hhu %s\n", + output_len += snprintf(buf + output_len, + PAGE_SIZE - output_len, "BOX: %hhu %s\n", box, active); } else - output_len += snprintf(path[i] + output_len, - PATH_STRING_LEN, "%s\n", active); + output_len += snprintf(buf + output_len, + PAGE_SIZE - output_len, "%s\n", active); } spin_unlock_irqrestore(&h->devlock, flags); - return snprintf(buf, output_len+1, "%s%s%s%s%s%s%s%s", - path[0], path[1], path[2], path[3], - path[4], path[5], path[6], path[7]); + return output_len; } static DEVICE_ATTR(raid_level, S_IRUGO, raid_level_show, NULL); @@ -848,7 +867,6 @@ static struct device_attribute *hpsa_sdev_attrs[] = { &dev_attr_unique_id, &dev_attr_hp_ssd_smart_path_enabled, &dev_attr_path_info, - &dev_attr_lockup_detected, NULL, }; @@ -860,6 +878,7 @@ static struct device_attribute *hpsa_shost_attrs[] = { &dev_attr_resettable, &dev_attr_hp_ssd_smart_path_status, &dev_attr_raid_offload_debug, + &dev_attr_lockup_detected, NULL, }; @@ -1134,25 +1153,62 @@ static int hpsa_find_target_lun(struct ctlr_info *h, return !found; } -static inline void hpsa_show_dev_msg(const char *level, struct ctlr_info *h, +static void hpsa_show_dev_msg(const char *level, struct ctlr_info *h, struct hpsa_scsi_dev_t *dev, char *description) { +#define LABEL_SIZE 25 + char label[LABEL_SIZE]; + + if (h == NULL || h->pdev == NULL || h->scsi_host == NULL) + return; + + switch (dev->devtype) { + case TYPE_RAID: + snprintf(label, LABEL_SIZE, "controller"); + break; + case TYPE_ENCLOSURE: + snprintf(label, LABEL_SIZE, "enclosure"); + break; + case TYPE_DISK: + if (dev->external) + snprintf(label, LABEL_SIZE, "external"); + else if (!is_logical_dev_addr_mode(dev->scsi3addr)) + snprintf(label, LABEL_SIZE, "%s", + raid_label[PHYSICAL_DRIVE]); + else + snprintf(label, LABEL_SIZE, "RAID-%s", + dev->raid_level > RAID_UNKNOWN ? "?" : + raid_label[dev->raid_level]); + break; + case TYPE_ROM: + snprintf(label, LABEL_SIZE, "rom"); + break; + case TYPE_TAPE: + snprintf(label, LABEL_SIZE, "tape"); + break; + case TYPE_MEDIUM_CHANGER: + snprintf(label, LABEL_SIZE, "changer"); + break; + default: + snprintf(label, LABEL_SIZE, "UNKNOWN"); + break; + } + dev_printk(level, &h->pdev->dev, - "scsi %d:%d:%d:%d: %s %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d\n", + "scsi %d:%d:%d:%d: %s %s %.8s %.16s %s SSDSmartPathCap%c En%c Exp=%d\n", h->scsi_host->host_no, dev->bus, dev->target, dev->lun, description, scsi_device_type(dev->devtype), dev->vendor, dev->model, - dev->raid_level > RAID_UNKNOWN ? - "RAID-?" : raid_label[dev->raid_level], + label, dev->offload_config ? '+' : '-', dev->offload_enabled ? '+' : '-', - dev->expose_state); + dev->expose_device); } /* Add an entry into h->dev[] array. */ -static int hpsa_scsi_add_entry(struct ctlr_info *h, int hostno, +static int hpsa_scsi_add_entry(struct ctlr_info *h, struct hpsa_scsi_dev_t *device, struct hpsa_scsi_dev_t *added[], int *nadded) { @@ -1221,14 +1277,14 @@ lun_assigned: added[*nadded] = device; (*nadded)++; hpsa_show_dev_msg(KERN_INFO, h, device, - device->expose_state & HPSA_SCSI_ADD ? "added" : "masked"); + device->expose_device ? "added" : "masked"); device->offload_to_be_enabled = device->offload_enabled; device->offload_enabled = 0; return 0; } /* Update an entry in h->dev[] array. */ -static void hpsa_scsi_update_entry(struct ctlr_info *h, int hostno, +static void hpsa_scsi_update_entry(struct ctlr_info *h, int entry, struct hpsa_scsi_dev_t *new_entry) { int offload_enabled; @@ -1276,7 +1332,7 @@ static void hpsa_scsi_update_entry(struct ctlr_info *h, int hostno, } /* Replace an entry from h->dev[] array. */ -static void hpsa_scsi_replace_entry(struct ctlr_info *h, int hostno, +static void hpsa_scsi_replace_entry(struct ctlr_info *h, int entry, struct hpsa_scsi_dev_t *new_entry, struct hpsa_scsi_dev_t *added[], int *nadded, struct hpsa_scsi_dev_t *removed[], int *nremoved) @@ -1304,7 +1360,7 @@ static void hpsa_scsi_replace_entry(struct ctlr_info *h, int hostno, } /* Remove an entry from h->dev[] array. */ -static void hpsa_scsi_remove_entry(struct ctlr_info *h, int hostno, int entry, +static void hpsa_scsi_remove_entry(struct ctlr_info *h, int entry, struct hpsa_scsi_dev_t *removed[], int *nremoved) { /* assumes h->devlock is held */ @@ -1415,6 +1471,9 @@ static int hpsa_scsi_find_entry(struct hpsa_scsi_dev_t *needle, #define DEVICE_CHANGED 1 #define DEVICE_SAME 2 #define DEVICE_UPDATED 3 + if (needle == NULL) + return DEVICE_NOT_FOUND; + for (i = 0; i < haystack_size; i++) { if (haystack[i] == NULL) /* previously removed. */ continue; @@ -1577,9 +1636,11 @@ static void hpsa_figure_phys_disk_ptrs(struct ctlr_info *h, if (!logical_drive->offload_config) continue; for (j = 0; j < ndevices; j++) { + if (dev[j] == NULL) + continue; if (dev[j]->devtype != TYPE_DISK) continue; - if (is_logical_dev_addr_mode(dev[j]->scsi3addr)) + if (is_logical_device(dev[j])) continue; if (dev[j]->ioaccel_handle != dd[i].ioaccel_handle) continue; @@ -1620,9 +1681,11 @@ static void hpsa_update_log_drive_phys_drive_ptrs(struct ctlr_info *h, int i; for (i = 0; i < ndevices; i++) { + if (dev[i] == NULL) + continue; if (dev[i]->devtype != TYPE_DISK) continue; - if (!is_logical_dev_addr_mode(dev[i]->scsi3addr)) + if (!is_logical_device(dev[i])) continue; /* @@ -1638,7 +1701,50 @@ static void hpsa_update_log_drive_phys_drive_ptrs(struct ctlr_info *h, } } -static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno, +static int hpsa_add_device(struct ctlr_info *h, struct hpsa_scsi_dev_t *device) +{ + int rc = 0; + + if (!h->scsi_host) + return 1; + + if (is_logical_device(device)) /* RAID */ + rc = scsi_add_device(h->scsi_host, device->bus, + device->target, device->lun); + else /* HBA */ + rc = hpsa_add_sas_device(h->sas_host, device); + + return rc; +} + +static void hpsa_remove_device(struct ctlr_info *h, + struct hpsa_scsi_dev_t *device) +{ + struct scsi_device *sdev = NULL; + + if (!h->scsi_host) + return; + + if (is_logical_device(device)) { /* RAID */ + sdev = scsi_device_lookup(h->scsi_host, device->bus, + device->target, device->lun); + if (sdev) { + scsi_remove_device(sdev); + scsi_device_put(sdev); + } else { + /* + * We don't expect to get here. Future commands + * to this device will get a selection timeout as + * if the device were gone. + */ + hpsa_show_dev_msg(KERN_WARNING, h, device, + "didn't find device for removal."); + } + } else /* HBA */ + hpsa_remove_sas_device(device); +} + +static void adjust_hpsa_scsi_table(struct ctlr_info *h, struct hpsa_scsi_dev_t *sd[], int nsds) { /* sd contains scsi3 addresses and devtypes, and inquiry @@ -1650,7 +1756,15 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno, unsigned long flags; struct hpsa_scsi_dev_t **added, **removed; int nadded, nremoved; - struct Scsi_Host *sh = NULL; + + /* + * A reset can cause a device status to change + * re-schedule the scan to see what happened. + */ + if (h->reset_in_progress) { + h->drv_req_rescan = 1; + return; + } added = kzalloc(sizeof(*added) * HPSA_MAX_DEVICES, GFP_KERNEL); removed = kzalloc(sizeof(*removed) * HPSA_MAX_DEVICES, GFP_KERNEL); @@ -1678,19 +1792,18 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno, device_change = hpsa_scsi_find_entry(csd, sd, nsds, &entry); if (device_change == DEVICE_NOT_FOUND) { changes++; - hpsa_scsi_remove_entry(h, hostno, i, - removed, &nremoved); + hpsa_scsi_remove_entry(h, i, removed, &nremoved); continue; /* remove ^^^, hence i not incremented */ } else if (device_change == DEVICE_CHANGED) { changes++; - hpsa_scsi_replace_entry(h, hostno, i, sd[entry], + hpsa_scsi_replace_entry(h, i, sd[entry], added, &nadded, removed, &nremoved); /* Set it to NULL to prevent it from being freed * at the bottom of hpsa_update_scsi_devices() */ sd[entry] = NULL; } else if (device_change == DEVICE_UPDATED) { - hpsa_scsi_update_entry(h, hostno, i, sd[entry]); + hpsa_scsi_update_entry(h, i, sd[entry]); } i++; } @@ -1718,8 +1831,7 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno, h->ndevices, &entry); if (device_change == DEVICE_NOT_FOUND) { changes++; - if (hpsa_scsi_add_entry(h, hostno, sd[i], - added, &nadded) != 0) + if (hpsa_scsi_add_entry(h, sd[i], added, &nadded) != 0) break; sd[i] = NULL; /* prevent from being freed later. */ } else if (device_change == DEVICE_CHANGED) { @@ -1735,8 +1847,11 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno, /* Now that h->dev[]->phys_disk[] is coherent, we can enable * any logical drives that need it enabled. */ - for (i = 0; i < h->ndevices; i++) + for (i = 0; i < h->ndevices; i++) { + if (h->dev[i] == NULL) + continue; h->dev[i]->offload_enabled = h->dev[i]->offload_to_be_enabled; + } spin_unlock_irqrestore(&h->devlock, flags); @@ -1755,47 +1870,37 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno, * (or if there are no changes) scsi_scan_host will do it later the * first time through. */ - if (hostno == -1 || !changes) + if (!changes) goto free_and_out; - sh = h->scsi_host; /* Notify scsi mid layer of any removed devices */ for (i = 0; i < nremoved; i++) { - if (removed[i]->expose_state & HPSA_SCSI_ADD) { - struct scsi_device *sdev = - scsi_device_lookup(sh, removed[i]->bus, - removed[i]->target, removed[i]->lun); - if (sdev != NULL) { - scsi_remove_device(sdev); - scsi_device_put(sdev); - } else { - /* - * We don't expect to get here. - * future cmds to this device will get selection - * timeout as if the device was gone. - */ - hpsa_show_dev_msg(KERN_WARNING, h, removed[i], - "didn't find device for removal."); - } - } + if (removed[i] == NULL) + continue; + if (removed[i]->expose_device) + hpsa_remove_device(h, removed[i]); kfree(removed[i]); removed[i] = NULL; } /* Notify scsi mid layer of any added devices */ for (i = 0; i < nadded; i++) { - if (!(added[i]->expose_state & HPSA_SCSI_ADD)) + int rc = 0; + + if (added[i] == NULL) + continue; + if (!(added[i]->expose_device)) continue; - if (scsi_add_device(sh, added[i]->bus, - added[i]->target, added[i]->lun) == 0) + rc = hpsa_add_device(h, added[i]); + if (!rc) continue; - hpsa_show_dev_msg(KERN_WARNING, h, added[i], - "addition failed, device not added."); + dev_warn(&h->pdev->dev, + "addition failed %d, device not added.", rc); /* now we have to remove it from h->dev, * since it didn't get added to scsi mid layer */ fixup_botched_add(h, added[i]); - added[i] = NULL; + h->drv_req_rescan = 1; } free_and_out: @@ -1829,11 +1934,24 @@ static int hpsa_slave_alloc(struct scsi_device *sdev) h = sdev_to_hba(sdev); spin_lock_irqsave(&h->devlock, flags); - sd = lookup_hpsa_scsi_dev(h, sdev_channel(sdev), - sdev_id(sdev), sdev->lun); - if (likely(sd)) { + if (sdev_channel(sdev) == HPSA_PHYSICAL_DEVICE_BUS) { + struct scsi_target *starget; + struct sas_rphy *rphy; + + starget = scsi_target(sdev); + rphy = target_to_rphy(starget); + sd = hpsa_find_device_by_sas_rphy(h, rphy); + if (sd) { + sd->target = sdev_id(sdev); + sd->lun = sdev->lun; + } + } else + sd = lookup_hpsa_scsi_dev(h, sdev_channel(sdev), + sdev_id(sdev), sdev->lun); + + if (sd && sd->expose_device) { atomic_set(&sd->ioaccel_cmds_out, 0); - sdev->hostdata = (sd->expose_state & HPSA_SCSI_ADD) ? sd : NULL; + sdev->hostdata = sd; } else sdev->hostdata = NULL; spin_unlock_irqrestore(&h->devlock, flags); @@ -1847,7 +1965,7 @@ static int hpsa_slave_configure(struct scsi_device *sdev) int queue_depth; sd = sdev->hostdata; - sdev->no_uld_attach = !sd || !(sd->expose_state & HPSA_ULD_ATTACH); + sdev->no_uld_attach = !sd || !sd->expose_device; if (sd) queue_depth = sd->queue_depth != 0 ? @@ -1955,7 +2073,7 @@ static int hpsa_map_ioaccel2_sg_chain_block(struct ctlr_info *h, u32 chain_size; chain_block = h->ioaccel2_cmd_sg_list[c->cmdindex]; - chain_size = le32_to_cpu(cp->data_len); + chain_size = le32_to_cpu(cp->sg[0].length); temp64 = pci_map_single(h->pdev, chain_block, chain_size, PCI_DMA_TODEVICE); if (dma_mapping_error(&h->pdev->dev, temp64)) { @@ -1976,7 +2094,7 @@ static void hpsa_unmap_ioaccel2_sg_chain_block(struct ctlr_info *h, chain_sg = cp->sg; temp64 = le64_to_cpu(chain_sg->address); - chain_size = le32_to_cpu(cp->data_len); + chain_size = le32_to_cpu(cp->sg[0].length); pci_unmap_single(h->pdev, temp64, chain_size, PCI_DMA_TODEVICE); } @@ -2210,7 +2328,7 @@ static void process_ioaccel2_completion(struct ctlr_info *h, * the normal I/O path so the controller can handle whatever's * wrong. */ - if (is_logical_dev_addr_mode(dev->scsi3addr) && + if (is_logical_device(dev) && c2->error_data.serv_response == IOACCEL2_SERV_RESPONSE_FAILURE) { if (c2->error_data.status == @@ -2330,7 +2448,7 @@ static void complete_scsi_command(struct CommandList *cp) * the normal I/O path so the controller can handle whatever's * wrong. */ - if (is_logical_dev_addr_mode(dev->scsi3addr)) { + if (is_logical_device(dev)) { if (ei->CommandStatus == CMD_IOACCEL_DISABLED) dev->offload_enabled = 0; return hpsa_retry_cmd(h, cp); @@ -2709,9 +2827,8 @@ static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr, /* fill_cmd can't fail here, no data buffer to map. */ - (void) fill_cmd(c, HPSA_DEVICE_RESET_MSG, h, NULL, 0, 0, + (void) fill_cmd(c, reset_type, h, NULL, 0, 0, scsi3addr, TYPE_MSG); - c->Request.CDB[1] = reset_type; /* fill_cmd defaults to LUN reset */ rc = hpsa_scsi_do_simple_cmd(h, c, reply_queue, NO_TIMEOUT); if (rc) { dev_warn(&h->pdev->dev, "Failed to send reset command\n"); @@ -2984,6 +3101,66 @@ out: return rc; } +static int hpsa_bmic_sense_subsystem_information(struct ctlr_info *h, + unsigned char scsi3addr[], u16 bmic_device_index, + struct bmic_sense_subsystem_info *buf, size_t bufsize) +{ + int rc = IO_OK; + struct CommandList *c; + struct ErrorInfo *ei; + + c = cmd_alloc(h); + + rc = fill_cmd(c, BMIC_SENSE_SUBSYSTEM_INFORMATION, h, buf, bufsize, + 0, RAID_CTLR_LUNID, TYPE_CMD); + if (rc) + goto out; + + c->Request.CDB[2] = bmic_device_index & 0xff; + c->Request.CDB[9] = (bmic_device_index >> 8) & 0xff; + + rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, + PCI_DMA_FROMDEVICE, NO_TIMEOUT); + if (rc) + goto out; + ei = c->err_info; + if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) { + hpsa_scsi_interpret_error(h, c); + rc = -1; + } +out: + cmd_free(h, c); + return rc; +} + +static int hpsa_bmic_id_controller(struct ctlr_info *h, + struct bmic_identify_controller *buf, size_t bufsize) +{ + int rc = IO_OK; + struct CommandList *c; + struct ErrorInfo *ei; + + c = cmd_alloc(h); + + rc = fill_cmd(c, BMIC_IDENTIFY_CONTROLLER, h, buf, bufsize, + 0, RAID_CTLR_LUNID, TYPE_CMD); + if (rc) + goto out; + + rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, + PCI_DMA_FROMDEVICE, NO_TIMEOUT); + if (rc) + goto out; + ei = c->err_info; + if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) { + hpsa_scsi_interpret_error(h, c); + rc = -1; + } +out: + cmd_free(h, c); + return rc; +} + static int hpsa_bmic_id_physical_device(struct ctlr_info *h, unsigned char scsi3addr[], u16 bmic_device_index, struct bmic_identify_physical_device *buf, size_t bufsize) @@ -3010,9 +3187,71 @@ static int hpsa_bmic_id_physical_device(struct ctlr_info *h, } out: cmd_free(h, c); + return rc; } +static u64 hpsa_get_sas_address_from_report_physical(struct ctlr_info *h, + unsigned char *scsi3addr) +{ + struct ReportExtendedLUNdata *physdev; + u32 nphysicals; + u64 sa = 0; + int i; + + physdev = kzalloc(sizeof(*physdev), GFP_KERNEL); + if (!physdev) + return 0; + + if (hpsa_scsi_do_report_phys_luns(h, physdev, sizeof(*physdev))) { + dev_err(&h->pdev->dev, "report physical LUNs failed.\n"); + kfree(physdev); + return 0; + } + nphysicals = get_unaligned_be32(physdev->LUNListLength) / 24; + + for (i = 0; i < nphysicals; i++) + if (!memcmp(&physdev->LUN[i].lunid[0], scsi3addr, 8)) { + sa = get_unaligned_be64(&physdev->LUN[i].wwid[0]); + break; + } + + kfree(physdev); + + return sa; +} + +static void hpsa_get_sas_address(struct ctlr_info *h, unsigned char *scsi3addr, + struct hpsa_scsi_dev_t *dev) +{ + int rc; + u64 sa = 0; + + if (is_hba_lunid(scsi3addr)) { + struct bmic_sense_subsystem_info *ssi; + + ssi = kzalloc(sizeof(*ssi), GFP_KERNEL); + if (ssi == NULL) { + dev_warn(&h->pdev->dev, + "%s: out of memory\n", __func__); + return; + } + + rc = hpsa_bmic_sense_subsystem_information(h, + scsi3addr, 0, ssi, sizeof(*ssi)); + if (rc == 0) { + sa = get_unaligned_be64(ssi->primary_world_wide_id); + h->sas_address = sa; + } + + kfree(ssi); + } else + sa = hpsa_get_sas_address_from_report_physical(h, scsi3addr); + + dev->sas_address = sa; +} + +/* Get a device id from inquiry page 0x83 */ static int hpsa_vpd_page_supported(struct ctlr_info *h, unsigned char scsi3addr[], u8 page) { @@ -3097,7 +3336,7 @@ out: /* Get the device id from inquiry page 0x83 */ static int hpsa_get_device_id(struct ctlr_info *h, unsigned char *scsi3addr, - unsigned char *device_id, int buflen) + unsigned char *device_id, int index, int buflen) { int rc; unsigned char *buf; @@ -3109,8 +3348,10 @@ static int hpsa_get_device_id(struct ctlr_info *h, unsigned char *scsi3addr, return -ENOMEM; rc = hpsa_scsi_do_inquiry(h, scsi3addr, VPD_PAGE | 0x83, buf, 64); if (rc == 0) - memcpy(device_id, &buf[8], buflen); + memcpy(device_id, &buf[index], buflen); + kfree(buf); + return rc != 0; } @@ -3339,6 +3580,18 @@ static int hpsa_device_supports_aborts(struct ctlr_info *h, return rc; } +static void sanitize_inquiry_string(unsigned char *s, int len) +{ + bool terminated = false; + + for (; len > 0; (--len, ++s)) { + if (*s == 0) + terminated = true; + if (terminated || *s < 0x20 || *s > 0x7e) + *s = ' '; + } +} + static int hpsa_update_device_info(struct ctlr_info *h, unsigned char scsi3addr[], struct hpsa_scsi_dev_t *this_device, unsigned char *is_OBDR_device) @@ -3351,10 +3604,13 @@ static int hpsa_update_device_info(struct ctlr_info *h, unsigned char *inq_buff; unsigned char *obdr_sig; + int rc = 0; inq_buff = kzalloc(OBDR_TAPE_INQ_SIZE, GFP_KERNEL); - if (!inq_buff) + if (!inq_buff) { + rc = -ENOMEM; goto bail_out; + } /* Do an inquiry to the device to see what it is. */ if (hpsa_scsi_do_inquiry(h, scsi3addr, 0, inq_buff, @@ -3362,9 +3618,13 @@ static int hpsa_update_device_info(struct ctlr_info *h, /* Inquiry failed (msg printed already) */ dev_err(&h->pdev->dev, "hpsa_update_device_info: inquiry failed\n"); + rc = -EIO; goto bail_out; } + sanitize_inquiry_string(&inq_buff[8], 8); + sanitize_inquiry_string(&inq_buff[16], 16); + this_device->devtype = (inq_buff[0] & 0x1f); memcpy(this_device->scsi3addr, scsi3addr, 8); memcpy(this_device->vendor, &inq_buff[8], @@ -3373,7 +3633,7 @@ static int hpsa_update_device_info(struct ctlr_info *h, sizeof(this_device->model)); memset(this_device->device_id, 0, sizeof(this_device->device_id)); - hpsa_get_device_id(h, scsi3addr, this_device->device_id, + hpsa_get_device_id(h, scsi3addr, this_device->device_id, 8, sizeof(this_device->device_id)); if (this_device->devtype == TYPE_DISK && @@ -3411,7 +3671,7 @@ static int hpsa_update_device_info(struct ctlr_info *h, bail_out: kfree(inq_buff); - return 1; + return rc; } static void hpsa_update_device_supports_aborts(struct ctlr_info *h, @@ -3439,115 +3699,39 @@ static void hpsa_update_device_supports_aborts(struct ctlr_info *h, } } -static unsigned char *ext_target_model[] = { - "MSA2012", - "MSA2024", - "MSA2312", - "MSA2324", - "P2000 G3 SAS", - "MSA 2040 SAS", - NULL, -}; - -static int is_ext_target(struct ctlr_info *h, struct hpsa_scsi_dev_t *device) -{ - int i; - - for (i = 0; ext_target_model[i]; i++) - if (strncmp(device->model, ext_target_model[i], - strlen(ext_target_model[i])) == 0) - return 1; - return 0; -} - -/* Helper function to assign bus, target, lun mapping of devices. - * Puts non-external target logical volumes on bus 0, external target logical - * volumes on bus 1, physical devices on bus 2. and the hba on bus 3. +/* + * Helper function to assign bus, target, lun mapping of devices. * Logical drive target and lun are assigned at this time, but * physical device lun and target assignment are deferred (assigned * in hpsa_find_target_lun, called by hpsa_scsi_add_entry.) - */ +*/ static void figure_bus_target_lun(struct ctlr_info *h, u8 *lunaddrbytes, struct hpsa_scsi_dev_t *device) { - u32 lunid = le32_to_cpu(*((__le32 *) lunaddrbytes)); + u32 lunid = get_unaligned_le32(lunaddrbytes); if (!is_logical_dev_addr_mode(lunaddrbytes)) { /* physical device, target and lun filled in later */ if (is_hba_lunid(lunaddrbytes)) - hpsa_set_bus_target_lun(device, 3, 0, lunid & 0x3fff); + hpsa_set_bus_target_lun(device, + HPSA_HBA_BUS, 0, lunid & 0x3fff); else /* defer target, lun assignment for physical devices */ - hpsa_set_bus_target_lun(device, 2, -1, -1); + hpsa_set_bus_target_lun(device, + HPSA_PHYSICAL_DEVICE_BUS, -1, -1); return; } /* It's a logical device */ - if (is_ext_target(h, device)) { - /* external target way, put logicals on bus 1 - * and match target/lun numbers box - * reports, other smart array, bus 0, target 0, match lunid - */ + if (device->external) { hpsa_set_bus_target_lun(device, - 1, (lunid >> 16) & 0x3fff, lunid & 0x00ff); + HPSA_EXTERNAL_RAID_VOLUME_BUS, (lunid >> 16) & 0x3fff, + lunid & 0x00ff); return; } - hpsa_set_bus_target_lun(device, 0, 0, lunid & 0x3fff); + hpsa_set_bus_target_lun(device, HPSA_RAID_VOLUME_BUS, + 0, lunid & 0x3fff); } -/* - * If there is no lun 0 on a target, linux won't find any devices. - * For the external targets (arrays), we have to manually detect the enclosure - * which is at lun zero, as CCISS_REPORT_PHYSICAL_LUNS doesn't report - * it for some reason. *tmpdevice is the target we're adding, - * this_device is a pointer into the current element of currentsd[] - * that we're building up in update_scsi_devices(), below. - * lunzerobits is a bitmap that tracks which targets already have a - * lun 0 assigned. - * Returns 1 if an enclosure was added, 0 if not. - */ -static int add_ext_target_dev(struct ctlr_info *h, - struct hpsa_scsi_dev_t *tmpdevice, - struct hpsa_scsi_dev_t *this_device, u8 *lunaddrbytes, - unsigned long lunzerobits[], int *n_ext_target_devs) -{ - unsigned char scsi3addr[8]; - - if (test_bit(tmpdevice->target, lunzerobits)) - return 0; /* There is already a lun 0 on this target. */ - - if (!is_logical_dev_addr_mode(lunaddrbytes)) - return 0; /* It's the logical targets that may lack lun 0. */ - - if (!is_ext_target(h, tmpdevice)) - return 0; /* Only external target devices have this problem. */ - - if (tmpdevice->lun == 0) /* if lun is 0, then we have a lun 0. */ - return 0; - - memset(scsi3addr, 0, 8); - scsi3addr[3] = tmpdevice->target; - if (is_hba_lunid(scsi3addr)) - return 0; /* Don't add the RAID controller here. */ - - if (is_scsi_rev_5(h)) - return 0; /* p1210m doesn't need to do this. */ - - if (*n_ext_target_devs >= MAX_EXT_TARGETS) { - dev_warn(&h->pdev->dev, "Maximum number of external " - "target devices exceeded. Check your hardware " - "configuration."); - return 0; - } - - if (hpsa_update_device_info(h, scsi3addr, this_device, NULL)) - return 0; - (*n_ext_target_devs)++; - hpsa_set_bus_target_lun(this_device, - tmpdevice->bus, tmpdevice->target, 0); - hpsa_update_device_supports_aborts(h, this_device, scsi3addr); - set_bit(tmpdevice->target, lunzerobits); - return 1; -} /* * Get address of physical disk used for an ioaccel2 mode command: @@ -3577,6 +3761,27 @@ static int hpsa_get_pdisk_of_ioaccel2(struct ctlr_info *h, return 0; } +static int figure_external_status(struct ctlr_info *h, int raid_ctlr_position, + int i, int nphysicals, int nlocal_logicals) +{ + /* In report logicals, local logicals are listed first, + * then any externals. + */ + int logicals_start = nphysicals + (raid_ctlr_position == 0); + + if (i == raid_ctlr_position) + return 0; + + if (i < logicals_start) + return 0; + + /* i is in logicals range, but still within local logicals */ + if ((i - nphysicals - (raid_ctlr_position == 0)) < nlocal_logicals) + return 0; + + return 1; /* it's an external lun */ +} + /* * Do CISS_REPORT_PHYS and CISS_REPORT_LOG. Data is returned in physdev, * logdev. The number of luns in physdev and logdev are returned in @@ -3650,19 +3855,18 @@ static u8 *figure_lunaddrbytes(struct ctlr_info *h, int raid_ctlr_position, /* get physical drive ioaccel handle and queue depth */ static void hpsa_get_ioaccel_drive_info(struct ctlr_info *h, struct hpsa_scsi_dev_t *dev, - u8 *lunaddrbytes, + struct ReportExtendedLUNdata *rlep, int rle_index, struct bmic_identify_physical_device *id_phys) { int rc; - struct ext_report_lun_entry *rle = - (struct ext_report_lun_entry *) lunaddrbytes; + struct ext_report_lun_entry *rle = &rlep->LUN[rle_index]; dev->ioaccel_handle = rle->ioaccel_handle; - if (PHYS_IOACCEL(lunaddrbytes) && dev->ioaccel_handle) + if ((rle->device_flags & 0x08) && dev->ioaccel_handle) dev->hba_ioaccel_enabled = 1; memset(id_phys, 0, sizeof(*id_phys)); - rc = hpsa_bmic_id_physical_device(h, lunaddrbytes, - GET_BMIC_DRIVE_NUMBER(lunaddrbytes), id_phys, + rc = hpsa_bmic_id_physical_device(h, &rle->lunid[0], + GET_BMIC_DRIVE_NUMBER(&rle->lunid[0]), id_phys, sizeof(*id_phys)); if (!rc) /* Reserve space for FW operations */ @@ -3673,16 +3877,15 @@ static void hpsa_get_ioaccel_drive_info(struct ctlr_info *h, DRIVE_CMDS_RESERVED_FOR_FW; else dev->queue_depth = DRIVE_QUEUE_DEPTH; /* conservative */ - atomic_set(&dev->ioaccel_cmds_out, 0); - atomic_set(&dev->reset_cmds_out, 0); } static void hpsa_get_path_info(struct hpsa_scsi_dev_t *this_device, - u8 *lunaddrbytes, + struct ReportExtendedLUNdata *rlep, int rle_index, struct bmic_identify_physical_device *id_phys) { - if (PHYS_IOACCEL(lunaddrbytes) - && this_device->ioaccel_handle) + struct ext_report_lun_entry *rle = &rlep->LUN[rle_index]; + + if ((rle->device_flags & 0x08) && this_device->ioaccel_handle) this_device->hba_ioaccel_enabled = 1; memcpy(&this_device->active_path_index, @@ -3702,7 +3905,33 @@ static void hpsa_get_path_info(struct hpsa_scsi_dev_t *this_device, sizeof(this_device->bay)); } -static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) +/* get number of local logical disks. */ +static int hpsa_set_local_logical_count(struct ctlr_info *h, + struct bmic_identify_controller *id_ctlr, + u32 *nlocals) +{ + int rc; + + if (!id_ctlr) { + dev_warn(&h->pdev->dev, "%s: id_ctlr buffer is NULL.\n", + __func__); + return -ENOMEM; + } + memset(id_ctlr, 0, sizeof(*id_ctlr)); + rc = hpsa_bmic_id_controller(h, id_ctlr, sizeof(*id_ctlr)); + if (!rc) + if (id_ctlr->configured_logical_drive_count < 256) + *nlocals = id_ctlr->configured_logical_drive_count; + else + *nlocals = le16_to_cpu( + id_ctlr->extended_logical_unit_count); + else + *nlocals = -1; + return rc; +} + + +static void hpsa_update_scsi_devices(struct ctlr_info *h) { /* the idea here is we could get notified * that some devices have changed, so we do a report @@ -3717,13 +3946,16 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) struct ReportExtendedLUNdata *physdev_list = NULL; struct ReportLUNdata *logdev_list = NULL; struct bmic_identify_physical_device *id_phys = NULL; + struct bmic_identify_controller *id_ctlr = NULL; u32 nphysicals = 0; u32 nlogicals = 0; + u32 nlocal_logicals = 0; u32 ndev_allocated = 0; struct hpsa_scsi_dev_t **currentsd, *this_device, *tmpdevice; int ncurrent = 0; int i, n_ext_target_devs, ndevs_to_allocate; int raid_ctlr_position; + bool physical_device; DECLARE_BITMAP(lunzerobits, MAX_EXT_TARGETS); currentsd = kzalloc(sizeof(*currentsd) * HPSA_MAX_DEVICES, GFP_KERNEL); @@ -3731,17 +3963,29 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) logdev_list = kzalloc(sizeof(*logdev_list), GFP_KERNEL); tmpdevice = kzalloc(sizeof(*tmpdevice), GFP_KERNEL); id_phys = kzalloc(sizeof(*id_phys), GFP_KERNEL); + id_ctlr = kzalloc(sizeof(*id_ctlr), GFP_KERNEL); if (!currentsd || !physdev_list || !logdev_list || - !tmpdevice || !id_phys) { + !tmpdevice || !id_phys || !id_ctlr) { dev_err(&h->pdev->dev, "out of memory\n"); goto out; } memset(lunzerobits, 0, sizeof(lunzerobits)); + h->drv_req_rescan = 0; /* cancel scheduled rescan - we're doing it. */ + if (hpsa_gather_lun_info(h, physdev_list, &nphysicals, - logdev_list, &nlogicals)) + logdev_list, &nlogicals)) { + h->drv_req_rescan = 1; goto out; + } + + /* Set number of local logicals (non PTRAID) */ + if (hpsa_set_local_logical_count(h, id_ctlr, &nlocal_logicals)) { + dev_warn(&h->pdev->dev, + "%s: Can't determine number of local logical devices.\n", + __func__); + } /* We might see up to the maximum number of logical and physical disks * plus external target devices, and a device for the local RAID @@ -3762,6 +4006,7 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) if (!currentsd[i]) { dev_warn(&h->pdev->dev, "out of memory at %s:%d\n", __FILE__, __LINE__); + h->drv_req_rescan = 1; goto out; } ndev_allocated++; @@ -3776,49 +4021,74 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) n_ext_target_devs = 0; for (i = 0; i < nphysicals + nlogicals + 1; i++) { u8 *lunaddrbytes, is_OBDR = 0; + int rc = 0; + int phys_dev_index = i - (raid_ctlr_position == 0); + + physical_device = i < nphysicals + (raid_ctlr_position == 0); /* Figure out where the LUN ID info is coming from */ lunaddrbytes = figure_lunaddrbytes(h, raid_ctlr_position, i, nphysicals, nlogicals, physdev_list, logdev_list); /* skip masked non-disk devices */ - if (MASKED_DEVICE(lunaddrbytes)) - if (i < nphysicals + (raid_ctlr_position == 0) && - NON_DISK_PHYS_DEV(lunaddrbytes)) - continue; + if (MASKED_DEVICE(lunaddrbytes) && physical_device && + (physdev_list->LUN[phys_dev_index].device_flags & 0x01)) + continue; /* Get device type, vendor, model, device id */ - if (hpsa_update_device_info(h, lunaddrbytes, tmpdevice, - &is_OBDR)) - continue; /* skip it if we can't talk to it. */ + rc = hpsa_update_device_info(h, lunaddrbytes, tmpdevice, + &is_OBDR); + if (rc == -ENOMEM) { + dev_warn(&h->pdev->dev, + "Out of memory, rescan deferred.\n"); + h->drv_req_rescan = 1; + goto out; + } + if (rc) { + dev_warn(&h->pdev->dev, + "Inquiry failed, skipping device.\n"); + continue; + } + + /* Determine if this is a lun from an external target array */ + tmpdevice->external = + figure_external_status(h, raid_ctlr_position, i, + nphysicals, nlocal_logicals); + figure_bus_target_lun(h, lunaddrbytes, tmpdevice); hpsa_update_device_supports_aborts(h, tmpdevice, lunaddrbytes); this_device = currentsd[ncurrent]; - /* - * For external target devices, we have to insert a LUN 0 which - * doesn't show up in CCISS_REPORT_PHYSICAL data, but there - * is nonetheless an enclosure device there. We have to - * present that otherwise linux won't find anything if - * there is no lun 0. + /* Turn on discovery_polling if there are ext target devices. + * Event-based change notification is unreliable for those. */ - if (add_ext_target_dev(h, tmpdevice, this_device, - lunaddrbytes, lunzerobits, - &n_ext_target_devs)) { - ncurrent++; - this_device = currentsd[ncurrent]; + if (!h->discovery_polling) { + if (tmpdevice->external) { + h->discovery_polling = 1; + dev_info(&h->pdev->dev, + "External target, activate discovery polling.\n"); + } } + *this_device = *tmpdevice; + this_device->physical_device = physical_device; + + /* + * Expose all devices except for physical devices that + * are masked. + */ + if (MASKED_DEVICE(lunaddrbytes) && this_device->physical_device) + this_device->expose_device = 0; + else + this_device->expose_device = 1; - /* do not expose masked devices */ - if (MASKED_DEVICE(lunaddrbytes) && - i < nphysicals + (raid_ctlr_position == 0)) { - this_device->expose_state = HPSA_DO_NOT_EXPOSE; - } else { - this_device->expose_state = - HPSA_SG_ATTACH | HPSA_ULD_ATTACH; - } + + /* + * Get the SAS address for physical devices that are exposed. + */ + if (this_device->physical_device && this_device->expose_device) + hpsa_get_sas_address(h, lunaddrbytes, this_device); switch (this_device->devtype) { case TYPE_ROM: @@ -3833,14 +4103,14 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) ncurrent++; break; case TYPE_DISK: - if (i < nphysicals + (raid_ctlr_position == 0)) { + if (this_device->physical_device) { /* The disk is in HBA mode. */ /* Never use RAID mapper in HBA mode. */ this_device->offload_enabled = 0; hpsa_get_ioaccel_drive_info(h, this_device, - lunaddrbytes, id_phys); - hpsa_get_path_info(this_device, lunaddrbytes, - id_phys); + physdev_list, phys_dev_index, id_phys); + hpsa_get_path_info(this_device, + physdev_list, phys_dev_index, id_phys); } ncurrent++; break; @@ -3865,7 +4135,19 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) if (ncurrent >= HPSA_MAX_DEVICES) break; } - adjust_hpsa_scsi_table(h, hostno, currentsd, ncurrent); + + if (h->sas_host == NULL) { + int rc = 0; + + rc = hpsa_add_sas_host(h); + if (rc) { + dev_warn(&h->pdev->dev, + "Could not add sas host %d\n", rc); + goto out; + } + } + + adjust_hpsa_scsi_table(h, currentsd, ncurrent); out: kfree(tmpdevice); for (i = 0; i < ndev_allocated; i++) @@ -3873,6 +4155,7 @@ out: kfree(currentsd); kfree(physdev_list); kfree(logdev_list); + kfree(id_ctlr); kfree(id_phys); } @@ -3978,19 +4261,14 @@ static int fixup_ioaccel_cdb(u8 *cdb, int *cdb_len) case READ_6: case READ_12: if (*cdb_len == 6) { - block = (((u32) cdb[2]) << 8) | cdb[3]; + block = get_unaligned_be16(&cdb[2]); block_cnt = cdb[4]; + if (block_cnt == 0) + block_cnt = 256; } else { BUG_ON(*cdb_len != 12); - block = (((u32) cdb[2]) << 24) | - (((u32) cdb[3]) << 16) | - (((u32) cdb[4]) << 8) | - cdb[5]; - block_cnt = - (((u32) cdb[6]) << 24) | - (((u32) cdb[7]) << 16) | - (((u32) cdb[8]) << 8) | - cdb[9]; + block = get_unaligned_be32(&cdb[2]); + block_cnt = get_unaligned_be32(&cdb[6]); } if (block_cnt > 0xffff) return IO_ACCEL_INELIGIBLE; @@ -4272,6 +4550,7 @@ static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h, /* fill in sg elements */ if (use_sg > h->ioaccel_maxsg) { cp->sg_count = 1; + cp->sg[0].length = cpu_to_le32(use_sg * sizeof(cp->sg[0])); if (hpsa_map_ioaccel2_sg_chain_block(h, cp, c)) { atomic_dec(&phys_disk->ioaccel_cmds_out); scsi_dma_unmap(cmd); @@ -4376,9 +4655,7 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h, case WRITE_6: is_write = 1; case READ_6: - first_block = - (((u64) cmd->cmnd[2]) << 8) | - cmd->cmnd[3]; + first_block = get_unaligned_be16(&cmd->cmnd[2]); block_cnt = cmd->cmnd[4]; if (block_cnt == 0) block_cnt = 256; @@ -4947,7 +5224,7 @@ static void hpsa_scan_start(struct Scsi_Host *sh) if (unlikely(lockup_detected(h))) return hpsa_scan_complete(h); - hpsa_update_scsi_devices(h, h->scsi_host->host_no); + hpsa_update_scsi_devices(h); hpsa_scan_complete(h); } @@ -4983,7 +5260,6 @@ static int hpsa_scan_finished(struct Scsi_Host *sh, static int hpsa_scsi_host_alloc(struct ctlr_info *h) { struct Scsi_Host *sh; - int error; sh = scsi_host_alloc(&hpsa_driver_template, sizeof(h)); if (sh == NULL) { @@ -5001,17 +5277,11 @@ static int hpsa_scsi_host_alloc(struct ctlr_info *h) sh->can_queue = h->nr_cmds - HPSA_NRESERVED_CMDS; sh->cmd_per_lun = sh->can_queue; sh->sg_tablesize = h->maxsgentries; + sh->transportt = hpsa_sas_transport_template; sh->hostdata[0] = (unsigned long) h; sh->irq = h->intr[h->intr_mode]; sh->unique_id = sh->irq; - error = scsi_init_shared_tag_map(sh, sh->can_queue); - if (error) { - dev_err(&h->pdev->dev, - "%s: scsi_init_shared_tag_map failed for controller %d\n", - __func__, h->ctlr); - scsi_host_put(sh); - return error; - } + h->scsi_host = sh; return 0; } @@ -5167,6 +5437,7 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd) int rc; struct ctlr_info *h; struct hpsa_scsi_dev_t *dev; + u8 reset_type; char msg[48]; /* find the controller to which the command to be aborted was sent */ @@ -5205,14 +5476,25 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd) if (is_hba_lunid(dev->scsi3addr)) return SUCCESS; - hpsa_show_dev_msg(KERN_WARNING, h, dev, "resetting"); + if (is_logical_dev_addr_mode(dev->scsi3addr)) + reset_type = HPSA_DEVICE_RESET_MSG; + else + reset_type = HPSA_PHYS_TARGET_RESET; + + sprintf(msg, "resetting %s", + reset_type == HPSA_DEVICE_RESET_MSG ? "logical " : "physical "); + hpsa_show_dev_msg(KERN_WARNING, h, dev, msg); + + h->reset_in_progress = 1; /* send a reset to the SCSI LUN which the command was sent to */ - rc = hpsa_do_reset(h, dev, dev->scsi3addr, HPSA_RESET_TYPE_LUN, + rc = hpsa_do_reset(h, dev, dev->scsi3addr, reset_type, DEFAULT_REPLY_QUEUE); - snprintf(msg, sizeof(msg), "reset %s", - rc == 0 ? "completed successfully" : "failed"); + sprintf(msg, "reset %s %s", + reset_type == HPSA_DEVICE_RESET_MSG ? "logical " : "physical ", + rc == 0 ? "completed successfully" : "failed"); hpsa_show_dev_msg(KERN_WARNING, h, dev, msg); + h->reset_in_progress = 0; return rc == 0 ? SUCCESS : FAILED; } @@ -6270,6 +6552,24 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, c->Request.CDB[8] = (size >> 8) & 0xFF; c->Request.CDB[9] = size & 0xFF; break; + case BMIC_SENSE_DIAG_OPTIONS: + c->Request.CDBLen = 16; + c->Request.type_attr_dir = + TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_READ); + c->Request.Timeout = 0; + /* Spec says this should be BMIC_WRITE */ + c->Request.CDB[0] = BMIC_READ; + c->Request.CDB[6] = BMIC_SENSE_DIAG_OPTIONS; + break; + case BMIC_SET_DIAG_OPTIONS: + c->Request.CDBLen = 16; + c->Request.type_attr_dir = + TYPE_ATTR_DIR(cmd_type, + ATTR_SIMPLE, XFER_WRITE); + c->Request.Timeout = 0; + c->Request.CDB[0] = BMIC_WRITE; + c->Request.CDB[6] = BMIC_SET_DIAG_OPTIONS; + break; case HPSA_CACHE_FLUSH: c->Request.CDBLen = 12; c->Request.type_attr_dir = @@ -6319,6 +6619,32 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, c->Request.CDB[7] = (size >> 16) & 0xFF; c->Request.CDB[8] = (size >> 8) & 0XFF; break; + case BMIC_SENSE_SUBSYSTEM_INFORMATION: + c->Request.CDBLen = 10; + c->Request.type_attr_dir = + TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_READ); + c->Request.Timeout = 0; + c->Request.CDB[0] = BMIC_READ; + c->Request.CDB[6] = BMIC_SENSE_SUBSYSTEM_INFORMATION; + c->Request.CDB[7] = (size >> 16) & 0xFF; + c->Request.CDB[8] = (size >> 8) & 0XFF; + break; + case BMIC_IDENTIFY_CONTROLLER: + c->Request.CDBLen = 10; + c->Request.type_attr_dir = + TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_READ); + c->Request.Timeout = 0; + c->Request.CDB[0] = BMIC_READ; + c->Request.CDB[1] = 0; + c->Request.CDB[2] = 0; + c->Request.CDB[3] = 0; + c->Request.CDB[4] = 0; + c->Request.CDB[5] = 0; + c->Request.CDB[6] = BMIC_IDENTIFY_CONTROLLER; + c->Request.CDB[7] = (size >> 16) & 0xFF; + c->Request.CDB[8] = (size >> 8) & 0XFF; + c->Request.CDB[9] = 0; + break; default: dev_warn(&h->pdev->dev, "unknown command 0x%c\n", cmd); BUG(); @@ -6327,6 +6653,20 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, } else if (cmd_type == TYPE_MSG) { switch (cmd) { + case HPSA_PHYS_TARGET_RESET: + c->Request.CDBLen = 16; + c->Request.type_attr_dir = + TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_NONE); + c->Request.Timeout = 0; /* Don't time out */ + memset(&c->Request.CDB[0], 0, sizeof(c->Request.CDB)); + c->Request.CDB[0] = HPSA_RESET; + c->Request.CDB[1] = HPSA_TARGET_RESET_TYPE; + /* Physical target reset needs no control bytes 4-7*/ + c->Request.CDB[4] = 0x00; + c->Request.CDB[5] = 0x00; + c->Request.CDB[6] = 0x00; + c->Request.CDB[7] = 0x00; + break; case HPSA_DEVICE_RESET_MSG: c->Request.CDBLen = 16; c->Request.type_attr_dir = @@ -6440,16 +6780,6 @@ static inline void finish_cmd(struct CommandList *c) complete(c->waiting); } - -static inline u32 hpsa_tag_discard_error_bits(struct ctlr_info *h, u32 tag) -{ -#define HPSA_PERF_ERROR_BITS ((1 << DIRECT_LOOKUP_SHIFT) - 1) -#define HPSA_SIMPLE_ERROR_BITS 0x03 - if (unlikely(!(h->transMethod & CFGTBL_Trans_Performant))) - return tag & ~HPSA_SIMPLE_ERROR_BITS; - return tag & ~HPSA_PERF_ERROR_BITS; -} - /* process completion of an indexed ("direct lookup") command */ static inline void process_indexed_cmd(struct ctlr_info *h, u32 raw_tag) @@ -7860,6 +8190,11 @@ static void hpsa_ack_ctlr_events(struct ctlr_info *h) */ static int hpsa_ctlr_needs_rescan(struct ctlr_info *h) { + if (h->drv_req_rescan) { + h->drv_req_rescan = 0; + return 1; + } + if (!(h->fw_support & MISC_FW_EVENT_NOTIFY)) return 0; @@ -7893,6 +8228,41 @@ static int hpsa_offline_devices_ready(struct ctlr_info *h) return 0; } +static int hpsa_luns_changed(struct ctlr_info *h) +{ + int rc = 1; /* assume there are changes */ + struct ReportLUNdata *logdev = NULL; + + /* if we can't find out if lun data has changed, + * assume that it has. + */ + + if (!h->lastlogicals) + goto out; + + logdev = kzalloc(sizeof(*logdev), GFP_KERNEL); + if (!logdev) { + dev_warn(&h->pdev->dev, + "Out of memory, can't track lun changes.\n"); + goto out; + } + if (hpsa_scsi_do_report_luns(h, 1, logdev, sizeof(*logdev), 0)) { + dev_warn(&h->pdev->dev, + "report luns failed, can't track lun changes.\n"); + goto out; + } + if (memcmp(logdev, h->lastlogicals, sizeof(*logdev))) { + dev_info(&h->pdev->dev, + "Lun changes detected.\n"); + memcpy(h->lastlogicals, logdev, sizeof(*logdev)); + goto out; + } else + rc = 0; /* no changes detected. */ +out: + kfree(logdev); + return rc; +} + static void hpsa_rescan_ctlr_worker(struct work_struct *work) { unsigned long flags; @@ -7908,6 +8278,19 @@ static void hpsa_rescan_ctlr_worker(struct work_struct *work) hpsa_ack_ctlr_events(h); hpsa_scan_start(h->scsi_host); scsi_host_put(h->scsi_host); + } else if (h->discovery_polling) { + hpsa_disable_rld_caching(h); + if (hpsa_luns_changed(h)) { + struct Scsi_Host *sh = NULL; + + dev_info(&h->pdev->dev, + "driver discovery polling rescan.\n"); + sh = scsi_host_get(h->scsi_host); + if (sh != NULL) { + hpsa_scan_start(sh); + scsi_host_put(sh); + } + } } spin_lock_irqsave(&h->lock, flags); if (!h->remove_in_progress) @@ -8148,6 +8531,8 @@ reinit_after_soft_reset: /* Enable Accelerated IO path at driver layer */ h->acciopath_status = 1; + /* Disable discovery polling.*/ + h->discovery_polling = 0; /* Turn the interrupts on so we can service requests */ @@ -8155,6 +8540,11 @@ reinit_after_soft_reset: hpsa_hba_inquiry(h); + h->lastlogicals = kzalloc(sizeof(*(h->lastlogicals)), GFP_KERNEL); + if (!h->lastlogicals) + dev_info(&h->pdev->dev, + "Can't track change to report lun data\n"); + /* Monitor the controller for firmware lockups */ h->heartbeat_sample_interval = HEARTBEAT_SAMPLE_INTERVAL; INIT_DELAYED_WORK(&h->monitor_ctlr_work, hpsa_monitor_ctlr_worker); @@ -8227,6 +8617,71 @@ out: kfree(flush_buf); } +/* Make controller gather fresh report lun data each time we + * send down a report luns request + */ +static void hpsa_disable_rld_caching(struct ctlr_info *h) +{ + u32 *options; + struct CommandList *c; + int rc; + + /* Don't bother trying to set diag options if locked up */ + if (unlikely(h->lockup_detected)) + return; + + options = kzalloc(sizeof(*options), GFP_KERNEL); + if (!options) { + dev_err(&h->pdev->dev, + "Error: failed to disable rld caching, during alloc.\n"); + return; + } + + c = cmd_alloc(h); + + /* first, get the current diag options settings */ + if (fill_cmd(c, BMIC_SENSE_DIAG_OPTIONS, h, options, 4, 0, + RAID_CTLR_LUNID, TYPE_CMD)) + goto errout; + + rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, + PCI_DMA_FROMDEVICE, NO_TIMEOUT); + if ((rc != 0) || (c->err_info->CommandStatus != 0)) + goto errout; + + /* Now, set the bit for disabling the RLD caching */ + *options |= HPSA_DIAG_OPTS_DISABLE_RLD_CACHING; + + if (fill_cmd(c, BMIC_SET_DIAG_OPTIONS, h, options, 4, 0, + RAID_CTLR_LUNID, TYPE_CMD)) + goto errout; + + rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, + PCI_DMA_TODEVICE, NO_TIMEOUT); + if ((rc != 0) || (c->err_info->CommandStatus != 0)) + goto errout; + + /* Now verify that it got set: */ + if (fill_cmd(c, BMIC_SENSE_DIAG_OPTIONS, h, options, 4, 0, + RAID_CTLR_LUNID, TYPE_CMD)) + goto errout; + + rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, + PCI_DMA_FROMDEVICE, NO_TIMEOUT); + if ((rc != 0) || (c->err_info->CommandStatus != 0)) + goto errout; + + if (*options && HPSA_DIAG_OPTS_DISABLE_RLD_CACHING) + goto out; + +errout: + dev_err(&h->pdev->dev, + "Error: failed to disable report lun data caching.\n"); +out: + cmd_free(h, c); + kfree(options); +} + static void hpsa_shutdown(struct pci_dev *pdev) { struct ctlr_info *h; @@ -8292,6 +8747,7 @@ static void hpsa_remove_one(struct pci_dev *pdev) hpsa_free_performant_mode(h); /* init_one 7 */ hpsa_free_sg_chain_blocks(h); /* init_one 6 */ hpsa_free_cmd_pool(h); /* init_one 5 */ + kfree(h->lastlogicals); /* hpsa_free_irqs already called via hpsa_shutdown init_one 4 */ @@ -8304,6 +8760,9 @@ static void hpsa_remove_one(struct pci_dev *pdev) free_percpu(h->lockup_detected); /* init_one 2 */ h->lockup_detected = NULL; /* init_one 2 */ /* (void) pci_disable_pcie_error_reporting(pdev); */ /* init_one 1 */ + + hpsa_delete_sas_host(h); + kfree(h); /* init_one 1 */ } @@ -8766,18 +9225,369 @@ static void hpsa_drain_accel_commands(struct ctlr_info *h) } while (1); } +static struct hpsa_sas_phy *hpsa_alloc_sas_phy( + struct hpsa_sas_port *hpsa_sas_port) +{ + struct hpsa_sas_phy *hpsa_sas_phy; + struct sas_phy *phy; + + hpsa_sas_phy = kzalloc(sizeof(*hpsa_sas_phy), GFP_KERNEL); + if (!hpsa_sas_phy) + return NULL; + + phy = sas_phy_alloc(hpsa_sas_port->parent_node->parent_dev, + hpsa_sas_port->next_phy_index); + if (!phy) { + kfree(hpsa_sas_phy); + return NULL; + } + + hpsa_sas_port->next_phy_index++; + hpsa_sas_phy->phy = phy; + hpsa_sas_phy->parent_port = hpsa_sas_port; + + return hpsa_sas_phy; +} + +static void hpsa_free_sas_phy(struct hpsa_sas_phy *hpsa_sas_phy) +{ + struct sas_phy *phy = hpsa_sas_phy->phy; + + sas_port_delete_phy(hpsa_sas_phy->parent_port->port, phy); + sas_phy_free(phy); + if (hpsa_sas_phy->added_to_port) + list_del(&hpsa_sas_phy->phy_list_entry); + kfree(hpsa_sas_phy); +} + +static int hpsa_sas_port_add_phy(struct hpsa_sas_phy *hpsa_sas_phy) +{ + int rc; + struct hpsa_sas_port *hpsa_sas_port; + struct sas_phy *phy; + struct sas_identify *identify; + + hpsa_sas_port = hpsa_sas_phy->parent_port; + phy = hpsa_sas_phy->phy; + + identify = &phy->identify; + memset(identify, 0, sizeof(*identify)); + identify->sas_address = hpsa_sas_port->sas_address; + identify->device_type = SAS_END_DEVICE; + identify->initiator_port_protocols = SAS_PROTOCOL_STP; + identify->target_port_protocols = SAS_PROTOCOL_STP; + phy->minimum_linkrate_hw = SAS_LINK_RATE_UNKNOWN; + phy->maximum_linkrate_hw = SAS_LINK_RATE_UNKNOWN; + phy->minimum_linkrate = SAS_LINK_RATE_UNKNOWN; + phy->maximum_linkrate = SAS_LINK_RATE_UNKNOWN; + phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN; + + rc = sas_phy_add(hpsa_sas_phy->phy); + if (rc) + return rc; + + sas_port_add_phy(hpsa_sas_port->port, hpsa_sas_phy->phy); + list_add_tail(&hpsa_sas_phy->phy_list_entry, + &hpsa_sas_port->phy_list_head); + hpsa_sas_phy->added_to_port = true; + + return 0; +} + +static int + hpsa_sas_port_add_rphy(struct hpsa_sas_port *hpsa_sas_port, + struct sas_rphy *rphy) +{ + struct sas_identify *identify; + + identify = &rphy->identify; + identify->sas_address = hpsa_sas_port->sas_address; + identify->initiator_port_protocols = SAS_PROTOCOL_STP; + identify->target_port_protocols = SAS_PROTOCOL_STP; + + return sas_rphy_add(rphy); +} + +static struct hpsa_sas_port + *hpsa_alloc_sas_port(struct hpsa_sas_node *hpsa_sas_node, + u64 sas_address) +{ + int rc; + struct hpsa_sas_port *hpsa_sas_port; + struct sas_port *port; + + hpsa_sas_port = kzalloc(sizeof(*hpsa_sas_port), GFP_KERNEL); + if (!hpsa_sas_port) + return NULL; + + INIT_LIST_HEAD(&hpsa_sas_port->phy_list_head); + hpsa_sas_port->parent_node = hpsa_sas_node; + + port = sas_port_alloc_num(hpsa_sas_node->parent_dev); + if (!port) + goto free_hpsa_port; + + rc = sas_port_add(port); + if (rc) + goto free_sas_port; + + hpsa_sas_port->port = port; + hpsa_sas_port->sas_address = sas_address; + list_add_tail(&hpsa_sas_port->port_list_entry, + &hpsa_sas_node->port_list_head); + + return hpsa_sas_port; + +free_sas_port: + sas_port_free(port); +free_hpsa_port: + kfree(hpsa_sas_port); + + return NULL; +} + +static void hpsa_free_sas_port(struct hpsa_sas_port *hpsa_sas_port) +{ + struct hpsa_sas_phy *hpsa_sas_phy; + struct hpsa_sas_phy *next; + + list_for_each_entry_safe(hpsa_sas_phy, next, + &hpsa_sas_port->phy_list_head, phy_list_entry) + hpsa_free_sas_phy(hpsa_sas_phy); + + sas_port_delete(hpsa_sas_port->port); + list_del(&hpsa_sas_port->port_list_entry); + kfree(hpsa_sas_port); +} + +static struct hpsa_sas_node *hpsa_alloc_sas_node(struct device *parent_dev) +{ + struct hpsa_sas_node *hpsa_sas_node; + + hpsa_sas_node = kzalloc(sizeof(*hpsa_sas_node), GFP_KERNEL); + if (hpsa_sas_node) { + hpsa_sas_node->parent_dev = parent_dev; + INIT_LIST_HEAD(&hpsa_sas_node->port_list_head); + } + + return hpsa_sas_node; +} + +static void hpsa_free_sas_node(struct hpsa_sas_node *hpsa_sas_node) +{ + struct hpsa_sas_port *hpsa_sas_port; + struct hpsa_sas_port *next; + + if (!hpsa_sas_node) + return; + + list_for_each_entry_safe(hpsa_sas_port, next, + &hpsa_sas_node->port_list_head, port_list_entry) + hpsa_free_sas_port(hpsa_sas_port); + + kfree(hpsa_sas_node); +} + +static struct hpsa_scsi_dev_t + *hpsa_find_device_by_sas_rphy(struct ctlr_info *h, + struct sas_rphy *rphy) +{ + int i; + struct hpsa_scsi_dev_t *device; + + for (i = 0; i < h->ndevices; i++) { + device = h->dev[i]; + if (!device->sas_port) + continue; + if (device->sas_port->rphy == rphy) + return device; + } + + return NULL; +} + +static int hpsa_add_sas_host(struct ctlr_info *h) +{ + int rc; + struct device *parent_dev; + struct hpsa_sas_node *hpsa_sas_node; + struct hpsa_sas_port *hpsa_sas_port; + struct hpsa_sas_phy *hpsa_sas_phy; + + parent_dev = &h->scsi_host->shost_gendev; + + hpsa_sas_node = hpsa_alloc_sas_node(parent_dev); + if (!hpsa_sas_node) + return -ENOMEM; + + hpsa_sas_port = hpsa_alloc_sas_port(hpsa_sas_node, h->sas_address); + if (!hpsa_sas_port) { + rc = -ENODEV; + goto free_sas_node; + } + + hpsa_sas_phy = hpsa_alloc_sas_phy(hpsa_sas_port); + if (!hpsa_sas_phy) { + rc = -ENODEV; + goto free_sas_port; + } + + rc = hpsa_sas_port_add_phy(hpsa_sas_phy); + if (rc) + goto free_sas_phy; + + h->sas_host = hpsa_sas_node; + + return 0; + +free_sas_phy: + hpsa_free_sas_phy(hpsa_sas_phy); +free_sas_port: + hpsa_free_sas_port(hpsa_sas_port); +free_sas_node: + hpsa_free_sas_node(hpsa_sas_node); + + return rc; +} + +static void hpsa_delete_sas_host(struct ctlr_info *h) +{ + hpsa_free_sas_node(h->sas_host); +} + +static int hpsa_add_sas_device(struct hpsa_sas_node *hpsa_sas_node, + struct hpsa_scsi_dev_t *device) +{ + int rc; + struct hpsa_sas_port *hpsa_sas_port; + struct sas_rphy *rphy; + + hpsa_sas_port = hpsa_alloc_sas_port(hpsa_sas_node, device->sas_address); + if (!hpsa_sas_port) + return -ENOMEM; + + rphy = sas_end_device_alloc(hpsa_sas_port->port); + if (!rphy) { + rc = -ENODEV; + goto free_sas_port; + } + + hpsa_sas_port->rphy = rphy; + device->sas_port = hpsa_sas_port; + + rc = hpsa_sas_port_add_rphy(hpsa_sas_port, rphy); + if (rc) + goto free_sas_port; + + return 0; + +free_sas_port: + hpsa_free_sas_port(hpsa_sas_port); + device->sas_port = NULL; + + return rc; +} + +static void hpsa_remove_sas_device(struct hpsa_scsi_dev_t *device) +{ + if (device->sas_port) { + hpsa_free_sas_port(device->sas_port); + device->sas_port = NULL; + } +} + +static int +hpsa_sas_get_linkerrors(struct sas_phy *phy) +{ + return 0; +} + +static int +hpsa_sas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier) +{ + return 0; +} + +static int +hpsa_sas_get_bay_identifier(struct sas_rphy *rphy) +{ + return -ENXIO; +} + +static int +hpsa_sas_phy_reset(struct sas_phy *phy, int hard_reset) +{ + return 0; +} + +static int +hpsa_sas_phy_enable(struct sas_phy *phy, int enable) +{ + return 0; +} + +static int +hpsa_sas_phy_setup(struct sas_phy *phy) +{ + return 0; +} + +static void +hpsa_sas_phy_release(struct sas_phy *phy) +{ +} + +static int +hpsa_sas_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates) +{ + return -EINVAL; +} + +/* SMP = Serial Management Protocol */ +static int +hpsa_sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, +struct request *req) +{ + return -EINVAL; +} + +static struct sas_function_template hpsa_sas_transport_functions = { + .get_linkerrors = hpsa_sas_get_linkerrors, + .get_enclosure_identifier = hpsa_sas_get_enclosure_identifier, + .get_bay_identifier = hpsa_sas_get_bay_identifier, + .phy_reset = hpsa_sas_phy_reset, + .phy_enable = hpsa_sas_phy_enable, + .phy_setup = hpsa_sas_phy_setup, + .phy_release = hpsa_sas_phy_release, + .set_phy_speed = hpsa_sas_phy_speed, + .smp_handler = hpsa_sas_smp_handler, +}; + /* * This is it. Register the PCI driver information for the cards we control * the OS will call our registered routines when it finds one of our cards. */ static int __init hpsa_init(void) { - return pci_register_driver(&hpsa_pci_driver); + int rc; + + hpsa_sas_transport_template = + sas_attach_transport(&hpsa_sas_transport_functions); + if (!hpsa_sas_transport_template) + return -ENODEV; + + rc = pci_register_driver(&hpsa_pci_driver); + + if (rc) + sas_release_transport(hpsa_sas_transport_template); + + return rc; } static void __exit hpsa_cleanup(void) { pci_unregister_driver(&hpsa_pci_driver); + sas_release_transport(hpsa_sas_transport_template); } static void __attribute__((unused)) verify_offsets(void) diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 27debb363529..ae5beda1bdb5 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -33,12 +33,38 @@ struct access_method { unsigned long (*command_completed)(struct ctlr_info *h, u8 q); }; +/* for SAS hosts and SAS expanders */ +struct hpsa_sas_node { + struct device *parent_dev; + struct list_head port_list_head; +}; + +struct hpsa_sas_port { + struct list_head port_list_entry; + u64 sas_address; + struct sas_port *port; + int next_phy_index; + struct list_head phy_list_head; + struct hpsa_sas_node *parent_node; + struct sas_rphy *rphy; +}; + +struct hpsa_sas_phy { + struct list_head phy_list_entry; + struct sas_phy *phy; + struct hpsa_sas_port *parent_port; + bool added_to_port; +}; + struct hpsa_scsi_dev_t { - int devtype; + unsigned int devtype; int bus, target, lun; /* as presented to the OS */ unsigned char scsi3addr[8]; /* as presented to the HW */ + u8 physical_device : 1; + u8 expose_device; #define RAID_CTLR_LUNID "\0\0\0\0\0\0\0\0" unsigned char device_id[16]; /* from inquiry pg. 0x83 */ + u64 sas_address; unsigned char vendor[8]; /* bytes 8-15 of inquiry data */ unsigned char model[16]; /* bytes 16-31 of inquiry data */ unsigned char raid_level; /* from inquiry page 0xC1 */ @@ -75,11 +101,8 @@ struct hpsa_scsi_dev_t { struct hpsa_scsi_dev_t *phys_disk[RAID_MAP_MAX_ENTRIES]; int nphysical_disks; int supports_aborts; -#define HPSA_DO_NOT_EXPOSE 0x0 -#define HPSA_SG_ATTACH 0x1 -#define HPSA_ULD_ATTACH 0x2 -#define HPSA_SCSI_ADD (HPSA_SG_ATTACH | HPSA_ULD_ATTACH) - u8 expose_state; + struct hpsa_sas_port *sas_port; + int external; /* 1-from external array 0-not <0-unknown */ }; struct reply_queue_buffer { @@ -136,6 +159,7 @@ struct ctlr_info { char *product_name; struct pci_dev *pdev; u32 board_id; + u64 sas_address; void __iomem *vaddr; unsigned long paddr; int nr_cmds; /* Number of commands allowed on this controller */ @@ -262,7 +286,10 @@ struct ctlr_info { spinlock_t offline_device_lock; struct list_head offline_device_list; int acciopath_status; + int drv_req_rescan; int raid_offload_debug; + int discovery_polling; + struct ReportLUNdata *lastlogicals; int needs_abort_tags_swizzled; struct workqueue_struct *resubmit_wq; struct workqueue_struct *rescan_ctlr_wq; @@ -270,6 +297,8 @@ struct ctlr_info { wait_queue_head_t abort_cmd_wait_queue; wait_queue_head_t event_sync_wait_queue; struct mutex reset_mutex; + u8 reset_in_progress; + struct hpsa_sas_node *sas_host; }; struct offline_device_entry { @@ -283,6 +312,7 @@ struct offline_device_entry { #define HPSA_RESET_TYPE_BUS 0x01 #define HPSA_RESET_TYPE_TARGET 0x03 #define HPSA_RESET_TYPE_LUN 0x04 +#define HPSA_PHYS_TARGET_RESET 0x99 /* not defined by cciss spec */ #define HPSA_MSG_SEND_RETRY_LIMIT 10 #define HPSA_MSG_SEND_RETRY_INTERVAL_MSECS (10000) @@ -367,6 +397,11 @@ struct offline_device_entry { #define IOACCEL2_INBOUND_POSTQ_64_LOW 0xd0 #define IOACCEL2_INBOUND_POSTQ_64_HI 0xd4 +#define HPSA_PHYSICAL_DEVICE_BUS 0 +#define HPSA_RAID_VOLUME_BUS 1 +#define HPSA_EXTERNAL_RAID_VOLUME_BUS 2 +#define HPSA_HBA_BUS 3 + /* Send the command to the hardware */ diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index 47c756ba8dce..d92ef0d352b5 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -260,8 +260,6 @@ struct ext_report_lun_entry { u8 wwid[8]; u8 device_type; u8 device_flags; -#define NON_DISK_PHYS_DEV(x) ((x)[17] & 0x01) -#define PHYS_IOACCEL(x) ((x)[17] & 0x08) u8 lun_count; /* multi-lun device, how many luns */ u8 redundant_paths; u32 ioaccel_handle; /* ioaccel1 only uses lower 16 bits */ @@ -288,6 +286,11 @@ struct SenseSubsystem_info { #define BMIC_FLASH_FIRMWARE 0xF7 #define BMIC_SENSE_CONTROLLER_PARAMETERS 0x64 #define BMIC_IDENTIFY_PHYSICAL_DEVICE 0x15 +#define BMIC_IDENTIFY_CONTROLLER 0x11 +#define BMIC_SET_DIAG_OPTIONS 0xF4 +#define BMIC_SENSE_DIAG_OPTIONS 0xF5 +#define HPSA_DIAG_OPTS_DISABLE_RLD_CACHING 0x40000000 +#define BMIC_SENSE_SUBSYSTEM_INFORMATION 0x66 /* Command List Structure */ union SCSI3Addr { @@ -684,6 +687,16 @@ struct hpsa_pci_info { u32 board_id; }; +struct bmic_identify_controller { + u8 configured_logical_drive_count; /* offset 0 */ + u8 pad1[153]; + __le16 extended_logical_unit_count; /* offset 154 */ + u8 pad2[136]; + u8 controller_mode; /* offset 292 */ + u8 pad3[32]; +}; + + struct bmic_identify_physical_device { u8 scsi_bus; /* SCSI Bus number on controller */ u8 scsi_id; /* SCSI ID on this bus */ @@ -816,5 +829,18 @@ struct bmic_identify_physical_device { u8 padding[112]; }; +struct bmic_sense_subsystem_info { + u8 primary_slot_number; + u8 reserved[3]; + u8 chasis_serial_number[32]; + u8 primary_world_wide_id[8]; + u8 primary_array_serial_number[32]; /* NULL terminated */ + u8 primary_cache_serial_number[32]; /* NULL terminated */ + u8 reserved_2[8]; + u8 secondary_array_serial_number[32]; + u8 secondary_cache_serial_number[32]; + u8 pad[332]; +}; + #pragma pack() #endif /* HPSA_CMD_H */ diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index 057d27721d5b..6aa317c303e2 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c @@ -3095,7 +3095,6 @@ static struct scsi_host_template driver_template = { .max_sectors = IBMVFC_MAX_SECTORS, .use_clustering = ENABLE_CLUSTERING, .shost_attrs = ibmvfc_attrs, - .use_blk_tags = 1, .track_queue_depth = 1, }; diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index 6a41c36b16b0..adfef9db6f1e 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -106,9 +106,9 @@ MODULE_LICENSE("GPL"); MODULE_VERSION(IBMVSCSI_VERSION); module_param_named(max_id, max_id, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(max_id, "Largest ID value for each channel"); +MODULE_PARM_DESC(max_id, "Largest ID value for each channel [Default=64]"); module_param_named(max_channel, max_channel, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(max_channel, "Largest channel value"); +MODULE_PARM_DESC(max_channel, "Largest channel value [Default=3]"); module_param_named(init_timeout, init_timeout, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(init_timeout, "Initialization timeout in seconds"); module_param_named(max_requests, max_requests, int, S_IRUGO); @@ -2289,11 +2289,15 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id) goto init_pool_failed; } - host->max_lun = 8; + host->max_lun = IBMVSCSI_MAX_LUN; host->max_id = max_id; host->max_channel = max_channel; host->max_cmd_len = 16; + dev_info(dev, + "Maximum ID: %d Maximum LUN: %llu Maximum Channel: %d\n", + host->max_id, host->max_lun, host->max_channel); + if (scsi_add_host(hostdata->host, hostdata->dev)) goto add_host_failed; diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.h b/drivers/scsi/ibmvscsi/ibmvscsi.h index 7d64867c5dd1..1067367395cd 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.h +++ b/drivers/scsi/ibmvscsi/ibmvscsi.h @@ -48,6 +48,7 @@ struct Scsi_Host; #define IBMVSCSI_CMDS_PER_LUN_DEFAULT 16 #define IBMVSCSI_MAX_SECTORS_DEFAULT 256 /* 32 * 8 = default max I/O 32 pages */ #define IBMVSCSI_MAX_CMDS_PER_LUN 64 +#define IBMVSCSI_MAX_LUN 32 /* ------------------------------------------------------------ * Data Structures diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index b62836ddbbee..536cd5a80422 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -6363,15 +6363,19 @@ static int ipr_queuecommand(struct Scsi_Host *shost, ipr_cmd->scsi_cmd = scsi_cmd; ipr_cmd->done = ipr_scsi_eh_done; - if (ipr_is_gscsi(res) || ipr_is_vset_device(res)) { + if (ipr_is_gscsi(res)) { if (scsi_cmd->underflow == 0) ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_ULEN_CHK; - ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_LINK_DESC; - if (ipr_is_gscsi(res) && res->reset_occurred) { + if (res->reset_occurred) { res->reset_occurred = 0; ioarcb->cmd_pkt.flags_lo |= IPR_FLAGS_LO_DELAY_AFTER_RST; } + } + + if (ipr_is_gscsi(res) || ipr_is_vset_device(res)) { + ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_LINK_DESC; + ioarcb->cmd_pkt.flags_lo |= IPR_FLAGS_LO_ALIGNED_BFR; if (scsi_cmd->flags & SCMD_TAGGED) ioarcb->cmd_pkt.flags_lo |= IPR_FLAGS_LO_SIMPLE_TASK; @@ -6502,7 +6506,6 @@ static struct scsi_host_template driver_template = { .shost_attrs = ipr_ioa_attrs, .sdev_attrs = ipr_dev_attrs, .proc_name = IPR_NAME, - .use_blk_tags = 1, }; /** @@ -7671,6 +7674,63 @@ static int ipr_ioafp_query_ioa_cfg(struct ipr_cmnd *ipr_cmd) return IPR_RC_JOB_RETURN; } +static int ipr_ioa_service_action_failed(struct ipr_cmnd *ipr_cmd) +{ + u32 ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc); + + if (ioasc == IPR_IOASC_IR_INVALID_REQ_TYPE_OR_PKT) + return IPR_RC_JOB_CONTINUE; + + return ipr_reset_cmd_failed(ipr_cmd); +} + +static void ipr_build_ioa_service_action(struct ipr_cmnd *ipr_cmd, + __be32 res_handle, u8 sa_code) +{ + struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; + + ioarcb->res_handle = res_handle; + ioarcb->cmd_pkt.cdb[0] = IPR_IOA_SERVICE_ACTION; + ioarcb->cmd_pkt.cdb[1] = sa_code; + ioarcb->cmd_pkt.request_type = IPR_RQTYPE_IOACMD; +} + +/** + * ipr_ioafp_set_caching_parameters - Issue Set Cache parameters service + * action + * + * Return value: + * none + **/ +static int ipr_ioafp_set_caching_parameters(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + struct ipr_inquiry_pageC4 *pageC4 = &ioa_cfg->vpd_cbs->pageC4_data; + + ENTER; + + ipr_cmd->job_step = ipr_ioafp_query_ioa_cfg; + + if (pageC4->cache_cap[0] & IPR_CAP_SYNC_CACHE) { + ipr_build_ioa_service_action(ipr_cmd, + cpu_to_be32(IPR_IOA_RES_HANDLE), + IPR_IOA_SA_CHANGE_CACHE_PARAMS); + + ioarcb->cmd_pkt.cdb[2] = 0x40; + + ipr_cmd->job_step_failed = ipr_ioa_service_action_failed; + ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, + IPR_SET_SUP_DEVICE_TIMEOUT); + + LEAVE; + return IPR_RC_JOB_RETURN; + } + + LEAVE; + return IPR_RC_JOB_CONTINUE; +} + /** * ipr_ioafp_inquiry - Send an Inquiry to the adapter. * @ipr_cmd: ipr command struct @@ -7722,6 +7782,39 @@ static int ipr_inquiry_page_supported(struct ipr_inquiry_page0 *page0, u8 page) } /** + * ipr_ioafp_pageC4_inquiry - Send a Page 0xC4 Inquiry to the adapter. + * @ipr_cmd: ipr command struct + * + * This function sends a Page 0xC4 inquiry to the adapter + * to retrieve software VPD information. + * + * Return value: + * IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN + **/ +static int ipr_ioafp_pageC4_inquiry(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + struct ipr_inquiry_page0 *page0 = &ioa_cfg->vpd_cbs->page0_data; + struct ipr_inquiry_pageC4 *pageC4 = &ioa_cfg->vpd_cbs->pageC4_data; + + ENTER; + ipr_cmd->job_step = ipr_ioafp_set_caching_parameters; + memset(pageC4, 0, sizeof(*pageC4)); + + if (ipr_inquiry_page_supported(page0, 0xC4)) { + ipr_ioafp_inquiry(ipr_cmd, 1, 0xC4, + (ioa_cfg->vpd_cbs_dma + + offsetof(struct ipr_misc_cbs, + pageC4_data)), + sizeof(struct ipr_inquiry_pageC4)); + return IPR_RC_JOB_RETURN; + } + + LEAVE; + return IPR_RC_JOB_CONTINUE; +} + +/** * ipr_ioafp_cap_inquiry - Send a Page 0xD0 Inquiry to the adapter. * @ipr_cmd: ipr command struct * @@ -7738,7 +7831,7 @@ static int ipr_ioafp_cap_inquiry(struct ipr_cmnd *ipr_cmd) struct ipr_inquiry_cap *cap = &ioa_cfg->vpd_cbs->cap; ENTER; - ipr_cmd->job_step = ipr_ioafp_query_ioa_cfg; + ipr_cmd->job_step = ipr_ioafp_pageC4_inquiry; memset(cap, 0, sizeof(*cap)); if (ipr_inquiry_page_supported(page0, 0xD0)) { @@ -8277,6 +8370,42 @@ static int ipr_reset_get_unit_check_job(struct ipr_cmnd *ipr_cmd) return IPR_RC_JOB_RETURN; } +static int ipr_dump_mailbox_wait(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + + ENTER; + + if (ioa_cfg->sdt_state != GET_DUMP) + return IPR_RC_JOB_RETURN; + + if (!ioa_cfg->sis64 || !ipr_cmd->u.time_left || + (readl(ioa_cfg->regs.sense_interrupt_reg) & + IPR_PCII_MAILBOX_STABLE)) { + + if (!ipr_cmd->u.time_left) + dev_err(&ioa_cfg->pdev->dev, + "Timed out waiting for Mailbox register.\n"); + + ioa_cfg->sdt_state = READ_DUMP; + ioa_cfg->dump_timeout = 0; + if (ioa_cfg->sis64) + ipr_reset_start_timer(ipr_cmd, IPR_SIS64_DUMP_TIMEOUT); + else + ipr_reset_start_timer(ipr_cmd, IPR_SIS32_DUMP_TIMEOUT); + ipr_cmd->job_step = ipr_reset_wait_for_dump; + schedule_work(&ioa_cfg->work_q); + + } else { + ipr_cmd->u.time_left -= IPR_CHECK_FOR_RESET_TIMEOUT; + ipr_reset_start_timer(ipr_cmd, + IPR_CHECK_FOR_RESET_TIMEOUT); + } + + LEAVE; + return IPR_RC_JOB_RETURN; +} + /** * ipr_reset_restore_cfg_space - Restore PCI config space. * @ipr_cmd: ipr command struct @@ -8326,20 +8455,11 @@ static int ipr_reset_restore_cfg_space(struct ipr_cmnd *ipr_cmd) if (ioa_cfg->in_ioa_bringdown) { ipr_cmd->job_step = ipr_ioa_bringdown_done; + } else if (ioa_cfg->sdt_state == GET_DUMP) { + ipr_cmd->job_step = ipr_dump_mailbox_wait; + ipr_cmd->u.time_left = IPR_WAIT_FOR_MAILBOX; } else { ipr_cmd->job_step = ipr_reset_enable_ioa; - - if (GET_DUMP == ioa_cfg->sdt_state) { - ioa_cfg->sdt_state = READ_DUMP; - ioa_cfg->dump_timeout = 0; - if (ioa_cfg->sis64) - ipr_reset_start_timer(ipr_cmd, IPR_SIS64_DUMP_TIMEOUT); - else - ipr_reset_start_timer(ipr_cmd, IPR_SIS32_DUMP_TIMEOUT); - ipr_cmd->job_step = ipr_reset_wait_for_dump; - schedule_work(&ioa_cfg->work_q); - return IPR_RC_JOB_RETURN; - } } LEAVE; diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h index e4fb17a58649..a34c7a5a995e 100644 --- a/drivers/scsi/ipr.h +++ b/drivers/scsi/ipr.h @@ -39,8 +39,8 @@ /* * Literals */ -#define IPR_DRIVER_VERSION "2.6.2" -#define IPR_DRIVER_DATE "(June 11, 2015)" +#define IPR_DRIVER_VERSION "2.6.3" +#define IPR_DRIVER_DATE "(October 17, 2015)" /* * IPR_MAX_CMD_PER_LUN: This defines the maximum number of outstanding @@ -216,6 +216,10 @@ #define IPR_SET_ALL_SUPPORTED_DEVICES 0x80 #define IPR_IOA_SHUTDOWN 0xF7 #define IPR_WR_BUF_DOWNLOAD_AND_SAVE 0x05 +#define IPR_IOA_SERVICE_ACTION 0xD2 + +/* IOA Service Actions */ +#define IPR_IOA_SA_CHANGE_CACHE_PARAMS 0x14 /* * Timeouts @@ -279,6 +283,9 @@ #define IPR_IPL_INIT_STAGE_TIME_MASK 0x0000ffff #define IPR_PCII_IPL_STAGE_CHANGE (0x80000000 >> 0) +#define IPR_PCII_MAILBOX_STABLE (0x80000000 >> 4) +#define IPR_WAIT_FOR_MAILBOX (2 * HZ) + #define IPR_PCII_IOA_TRANS_TO_OPER (0x80000000 >> 0) #define IPR_PCII_IOARCB_XFER_FAILED (0x80000000 >> 3) #define IPR_PCII_IOA_UNIT_CHECKED (0x80000000 >> 4) @@ -846,6 +853,16 @@ struct ipr_inquiry_page0 { u8 page[IPR_INQUIRY_PAGE0_ENTRIES]; }__attribute__((packed)); +struct ipr_inquiry_pageC4 { + u8 peri_qual_dev_type; + u8 page_code; + u8 reserved1; + u8 len; + u8 cache_cap[4]; +#define IPR_CAP_SYNC_CACHE 0x08 + u8 reserved2[20]; +} __packed; + struct ipr_hostrcb_device_data_entry { struct ipr_vpd vpd; struct ipr_res_addr dev_res_addr; @@ -1319,6 +1336,7 @@ struct ipr_misc_cbs { struct ipr_inquiry_page0 page0_data; struct ipr_inquiry_page3 page3_data; struct ipr_inquiry_cap cap; + struct ipr_inquiry_pageC4 pageC4_data; struct ipr_mode_pages mode_pages; struct ipr_supported_device supp_dev; }; diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c index 0dfcabe3ca7c..77128d680e3b 100644 --- a/drivers/scsi/isci/init.c +++ b/drivers/scsi/isci/init.c @@ -170,7 +170,6 @@ static struct scsi_host_template isci_sht = { .target_destroy = sas_target_destroy, .ioctl = sas_ioctl, .shost_attrs = isci_host_attrs, - .use_blk_tags = 1, .track_queue_depth = 1, }; @@ -272,11 +271,11 @@ static void isci_unregister(struct isci_host *isci_host) if (!isci_host) return; + shost = to_shost(isci_host); + scsi_remove_host(shost); sas_unregister_ha(&isci_host->sas_ha); - shost = to_shost(isci_host); sas_remove_host(shost); - scsi_remove_host(shost); scsi_host_put(shost); } diff --git a/drivers/scsi/libfc/fc_npiv.c b/drivers/scsi/libfc/fc_npiv.c index 9fbf78ed821b..c168321b560e 100644 --- a/drivers/scsi/libfc/fc_npiv.c +++ b/drivers/scsi/libfc/fc_npiv.c @@ -25,7 +25,7 @@ #include <linux/export.h> /** - * fc_vport_create() - Create a new NPIV vport instance + * libfc_vport_create() - Create a new NPIV vport instance * @vport: fc_vport structure from scsi_transport_fc * @privsize: driver private data size to allocate along with the Scsi_Host */ diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 3feeb447b740..b6fa257ea3e0 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -5173,7 +5173,6 @@ lpfc_els_rcv_lcb(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, rjt_err = LSRJT_CMD_UNSUPPORTED; goto rjt; } - lcb_context = kmalloc(sizeof(struct lpfc_lcb_context), GFP_KERNEL); if (phba->hba_flag & HBA_FCOE_MODE) { rjt_err = LSRJT_CMD_UNSUPPORTED; @@ -5204,6 +5203,12 @@ lpfc_els_rcv_lcb(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, goto rjt; } + lcb_context = kmalloc(sizeof(*lcb_context), GFP_KERNEL); + if (!lcb_context) { + rjt_err = LSRJT_UNABLE_TPC; + goto rjt; + } + state = (beacon->lcb_sub_command == LPFC_LCB_ON) ? 1 : 0; lcb_context->sub_command = beacon->lcb_sub_command; lcb_context->type = beacon->lcb_type; @@ -5214,6 +5219,7 @@ lpfc_els_rcv_lcb(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, if (lpfc_sli4_set_beacon(vport, lcb_context, state)) { lpfc_printf_vlog(ndlp->vport, KERN_ERR, LOG_ELS, "0193 failed to send mail box"); + kfree(lcb_context); lpfc_nlp_put(ndlp); rjt_err = LSRJT_UNABLE_TPC; goto rjt; diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 051b3b3bd625..4679ed4444a7 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -5914,7 +5914,6 @@ struct scsi_host_template lpfc_template_s3 = { .max_sectors = 0xFFFF, .vendor_id = LPFC_NL_VENDOR_ID, .change_queue_depth = scsi_change_queue_depth, - .use_blk_tags = 1, .track_queue_depth = 1, }; @@ -5940,7 +5939,6 @@ struct scsi_host_template lpfc_template = { .max_sectors = 0xFFFF, .vendor_id = LPFC_NL_VENDOR_ID, .change_queue_depth = scsi_change_queue_depth, - .use_blk_tags = 1, .track_queue_depth = 1, }; @@ -5964,6 +5962,5 @@ struct scsi_host_template lpfc_vport_template = { .shost_attrs = lpfc_vport_attrs, .max_sectors = 0xFFFF, .change_queue_depth = scsi_change_queue_depth, - .use_blk_tags = 1, .track_queue_depth = 1, }; diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 20c37541963f..c0f7c8ce54aa 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -35,8 +35,8 @@ /* * MegaRAID SAS Driver meta data */ -#define MEGASAS_VERSION "06.807.10.00-rc1" -#define MEGASAS_RELDATE "March 6, 2015" +#define MEGASAS_VERSION "06.808.16.00-rc1" +#define MEGASAS_RELDATE "Oct. 8, 2015" /* * Device IDs @@ -52,6 +52,10 @@ #define PCI_DEVICE_ID_LSI_PLASMA 0x002f #define PCI_DEVICE_ID_LSI_INVADER 0x005d #define PCI_DEVICE_ID_LSI_FURY 0x005f +#define PCI_DEVICE_ID_LSI_INTRUDER 0x00ce +#define PCI_DEVICE_ID_LSI_INTRUDER_24 0x00cf +#define PCI_DEVICE_ID_LSI_CUTLASS_52 0x0052 +#define PCI_DEVICE_ID_LSI_CUTLASS_53 0x0053 /* * Intel HBA SSDIDs @@ -62,6 +66,14 @@ #define MEGARAID_INTEL_RS3MC044_SSDID 0x9381 #define MEGARAID_INTEL_RS3WC080_SSDID 0x9341 #define MEGARAID_INTEL_RS3WC040_SSDID 0x9343 +#define MEGARAID_INTEL_RMS3BC160_SSDID 0x352B + +/* + * Intruder HBA SSDIDs + */ +#define MEGARAID_INTRUDER_SSDID1 0x9371 +#define MEGARAID_INTRUDER_SSDID2 0x9390 +#define MEGARAID_INTRUDER_SSDID3 0x9370 /* * Intel HBA branding @@ -78,6 +90,8 @@ "Intel(R) RAID Controller RS3WC080" #define MEGARAID_INTEL_RS3WC040_BRANDING \ "Intel(R) RAID Controller RS3WC040" +#define MEGARAID_INTEL_RMS3BC160_BRANDING \ + "Intel(R) Integrated RAID Module RMS3BC160" /* * ===================================== @@ -273,6 +287,16 @@ enum MFI_STAT { MFI_STAT_INVALID_STATUS = 0xFF }; +enum mfi_evt_class { + MFI_EVT_CLASS_DEBUG = -2, + MFI_EVT_CLASS_PROGRESS = -1, + MFI_EVT_CLASS_INFO = 0, + MFI_EVT_CLASS_WARNING = 1, + MFI_EVT_CLASS_CRITICAL = 2, + MFI_EVT_CLASS_FATAL = 3, + MFI_EVT_CLASS_DEAD = 4 +}; + /* * Crash dump related defines */ @@ -364,6 +388,8 @@ enum MR_EVT_ARGS { MR_EVT_ARGS_GENERIC, }; + +#define SGE_BUFFER_SIZE 4096 /* * define constants for device list query options */ @@ -394,6 +420,7 @@ enum MR_LD_QUERY_TYPE { #define MR_EVT_FOREIGN_CFG_IMPORTED 0x00db #define MR_EVT_LD_OFFLINE 0x00fc #define MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED 0x0152 +#define MR_EVT_CTRL_PROP_CHANGED 0x012f enum MR_PD_STATE { MR_PD_STATE_UNCONFIGURED_GOOD = 0x00, @@ -973,7 +1000,12 @@ struct megasas_ctrl_info { struct { #if defined(__BIG_ENDIAN_BITFIELD) - u32 reserved:12; + u32 reserved:7; + u32 useSeqNumJbodFP:1; + u32 supportExtendedSSCSize:1; + u32 supportDiskCacheSettingForSysPDs:1; + u32 supportCPLDUpdate:1; + u32 supportTTYLogCompression:1; u32 discardCacheDuringLDDelete:1; u32 supportSecurityonJBOD:1; u32 supportCacheBypassModes:1; @@ -1013,7 +1045,12 @@ struct megasas_ctrl_info { u32 supportCacheBypassModes:1; u32 supportSecurityonJBOD:1; u32 discardCacheDuringLDDelete:1; - u32 reserved:12; + u32 supportTTYLogCompression:1; + u32 supportCPLDUpdate:1; + u32 supportDiskCacheSettingForSysPDs:1; + u32 supportExtendedSSCSize:1; + u32 useSeqNumJbodFP:1; + u32 reserved:7; #endif } adapterOperations3; @@ -1229,7 +1266,9 @@ union megasas_sgl_frame { typedef union _MFI_CAPABILITIES { struct { #if defined(__BIG_ENDIAN_BITFIELD) - u32 reserved:25; + u32 reserved:23; + u32 support_ext_io_size:1; + u32 support_ext_queue_depth:1; u32 security_protocol_cmds_fw:1; u32 support_core_affinity:1; u32 support_ndrive_r1_lb:1; @@ -1245,7 +1284,9 @@ typedef union _MFI_CAPABILITIES { u32 support_ndrive_r1_lb:1; u32 support_core_affinity:1; u32 security_protocol_cmds_fw:1; - u32 reserved:25; + u32 support_ext_queue_depth:1; + u32 support_ext_io_size:1; + u32 reserved:23; #endif } mfi_capabilities; __le32 reg; @@ -1690,6 +1731,7 @@ struct megasas_instance { u32 crash_dump_drv_support; u32 crash_dump_app_support; u32 secure_jbod_support; + bool use_seqnum_jbod_fp; /* Added for PD sequence */ spinlock_t crashdump_lock; struct megasas_register_set __iomem *reg_set; @@ -1748,6 +1790,7 @@ struct megasas_instance { u8 UnevenSpanSupport; u8 supportmax256vd; + u8 allow_fw_scan; u16 fw_supported_vd_count; u16 fw_supported_pd_count; @@ -1769,7 +1812,9 @@ struct megasas_instance { struct msix_entry msixentry[MEGASAS_MAX_MSIX_QUEUES]; struct megasas_irq_context irq_context[MEGASAS_MAX_MSIX_QUEUES]; u64 map_id; + u64 pd_seq_map_id; struct megasas_cmd *map_update_cmd; + struct megasas_cmd *jbod_seq_cmd; unsigned long bar; long reset_flags; struct mutex reset_mutex; @@ -1780,6 +1825,7 @@ struct megasas_instance { char mpio; u16 throttlequeuedepth; u8 mask_interrupts; + u16 max_chain_frame_sz; u8 is_imr; bool dev_handle; }; @@ -1985,6 +2031,9 @@ __le16 get_updated_dev_handle(struct megasas_instance *instance, void mr_update_load_balance_params(struct MR_DRV_RAID_MAP_ALL *map, struct LD_LOAD_BALANCE_INFO *lbInfo); int megasas_get_ctrl_info(struct megasas_instance *instance); +/* PD sequence */ +int +megasas_sync_pd_seq_num(struct megasas_instance *instance, bool pend); int megasas_set_crash_dump_params(struct megasas_instance *instance, u8 crash_buf_state); void megasas_free_host_crash_buffer(struct megasas_instance *instance); @@ -2000,5 +2049,6 @@ void __megasas_return_cmd(struct megasas_instance *instance, void megasas_return_mfi_mpt_pthr(struct megasas_instance *instance, struct megasas_cmd *cmd_mfi, struct megasas_cmd_fusion *cmd_fusion); int megasas_cmd_type(struct scsi_cmnd *cmd); +void megasas_setup_jbod_map(struct megasas_instance *instance); #endif /*LSI_MEGARAID_SAS_H */ diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index eaa81e552fd2..97a1c1c33b05 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -135,6 +135,12 @@ static struct pci_device_id megasas_pci_table[] = { /* Invader */ {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FURY)}, /* Fury */ + {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_INTRUDER)}, + /* Intruder */ + {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_INTRUDER_24)}, + /* Intruder 24 port*/ + {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_CUTLASS_52)}, + {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_CUTLASS_53)}, {} }; @@ -260,6 +266,66 @@ megasas_return_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd) } +static const char * +format_timestamp(uint32_t timestamp) +{ + static char buffer[32]; + + if ((timestamp & 0xff000000) == 0xff000000) + snprintf(buffer, sizeof(buffer), "boot + %us", timestamp & + 0x00ffffff); + else + snprintf(buffer, sizeof(buffer), "%us", timestamp); + return buffer; +} + +static const char * +format_class(int8_t class) +{ + static char buffer[6]; + + switch (class) { + case MFI_EVT_CLASS_DEBUG: + return "debug"; + case MFI_EVT_CLASS_PROGRESS: + return "progress"; + case MFI_EVT_CLASS_INFO: + return "info"; + case MFI_EVT_CLASS_WARNING: + return "WARN"; + case MFI_EVT_CLASS_CRITICAL: + return "CRIT"; + case MFI_EVT_CLASS_FATAL: + return "FATAL"; + case MFI_EVT_CLASS_DEAD: + return "DEAD"; + default: + snprintf(buffer, sizeof(buffer), "%d", class); + return buffer; + } +} + +/** + * megasas_decode_evt: Decode FW AEN event and print critical event + * for information. + * @instance: Adapter soft state + */ +static void +megasas_decode_evt(struct megasas_instance *instance) +{ + struct megasas_evt_detail *evt_detail = instance->evt_detail; + union megasas_evt_class_locale class_locale; + class_locale.word = le32_to_cpu(evt_detail->cl.word); + + if (class_locale.members.class >= MFI_EVT_CLASS_CRITICAL) + dev_info(&instance->pdev->dev, "%d (%s/0x%04x/%s) - %s\n", + le32_to_cpu(evt_detail->seq_num), + format_timestamp(le32_to_cpu(evt_detail->time_stamp)), + (class_locale.members.locale), + format_class(class_locale.members.class), + evt_detail->description); +} + /** * The following functions are defined for xscale * (deviceid : 1064R, PERC5) controllers @@ -1659,8 +1725,56 @@ static struct megasas_instance *megasas_lookup_instance(u16 host_no) return NULL; } +/* +* megasas_set_dma_alignment - Set DMA alignment for PI enabled VD +* +* @sdev: OS provided scsi device +* +* Returns void +*/ +static void megasas_set_dma_alignment(struct scsi_device *sdev) +{ + u32 device_id, ld; + struct megasas_instance *instance; + struct fusion_context *fusion; + struct MR_LD_RAID *raid; + struct MR_DRV_RAID_MAP_ALL *local_map_ptr; + + instance = megasas_lookup_instance(sdev->host->host_no); + fusion = instance->ctrl_context; + + if (!fusion) + return; + + if (sdev->channel >= MEGASAS_MAX_PD_CHANNELS) { + device_id = ((sdev->channel % 2) * MEGASAS_MAX_DEV_PER_CHANNEL) + + sdev->id; + local_map_ptr = fusion->ld_drv_map[(instance->map_id & 1)]; + ld = MR_TargetIdToLdGet(device_id, local_map_ptr); + raid = MR_LdRaidGet(ld, local_map_ptr); + + if (raid->capability.ldPiMode == MR_PROT_INFO_TYPE_CONTROLLER) + blk_queue_update_dma_alignment(sdev->request_queue, 0x7); + } +} + static int megasas_slave_configure(struct scsi_device *sdev) { + u16 pd_index = 0; + struct megasas_instance *instance; + + instance = megasas_lookup_instance(sdev->host->host_no); + if (instance->allow_fw_scan) { + if (sdev->channel < MEGASAS_MAX_PD_CHANNELS && + sdev->type == TYPE_DISK) { + pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) + + sdev->id; + if (instance->pd_list[pd_index].driveState != + MR_PD_STATE_SYSTEM) + return -ENXIO; + } + } + megasas_set_dma_alignment(sdev); /* * The RAID firmware may require extended timeouts. */ @@ -1683,8 +1797,8 @@ static int megasas_slave_alloc(struct scsi_device *sdev) pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) + sdev->id; - if (instance->pd_list[pd_index].driveState == - MR_PD_STATE_SYSTEM) { + if ((instance->allow_fw_scan || instance->pd_list[pd_index].driveState == + MR_PD_STATE_SYSTEM)) { return 0; } return -ENXIO; @@ -1736,10 +1850,7 @@ void megaraid_sas_kill_hba(struct megasas_instance *instance) msleep(1000); if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) || (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) { + (instance->ctrl_context)) { writel(MFI_STOP_ADP, &instance->reg_set->doorbell); /* Flush */ readl(&instance->reg_set->doorbell); @@ -2506,10 +2617,7 @@ static int megasas_reset_bus_host(struct scsi_cmnd *scmd) /* * First wait for all commands to complete */ - if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) + if (instance->ctrl_context) ret = megasas_reset_fusion(scmd->device->host, 1); else ret = megasas_generic_reset(scmd); @@ -2837,7 +2945,7 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd, struct megasas_header *hdr = &cmd->frame->hdr; unsigned long flags; struct fusion_context *fusion = instance->ctrl_context; - u32 opcode; + u32 opcode, status; /* flag for the retry reset */ cmd->retry_for_fw_reset = 0; @@ -2945,6 +3053,7 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd, && (cmd->frame->dcmd.mbox.b[1] == 1)) { fusion->fast_path_io = 0; spin_lock_irqsave(instance->host->host_lock, flags); + instance->map_update_cmd = NULL; if (cmd->frame->hdr.cmd_status != 0) { if (cmd->frame->hdr.cmd_status != MFI_STAT_NOT_FOUND) @@ -2982,6 +3091,27 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd, spin_unlock_irqrestore(&poll_aen_lock, flags); } + /* FW has an updated PD sequence */ + if ((opcode == MR_DCMD_SYSTEM_PD_MAP_GET_INFO) && + (cmd->frame->dcmd.mbox.b[0] == 1)) { + + spin_lock_irqsave(instance->host->host_lock, flags); + status = cmd->frame->hdr.cmd_status; + instance->jbod_seq_cmd = NULL; + megasas_return_cmd(instance, cmd); + + if (status == MFI_STAT_OK) { + instance->pd_seq_map_id++; + /* Re-register a pd sync seq num cmd */ + if (megasas_sync_pd_seq_num(instance, true)) + instance->use_seqnum_jbod_fp = false; + } else + instance->use_seqnum_jbod_fp = false; + + spin_unlock_irqrestore(instance->host->host_lock, flags); + break; + } + /* * See if got an event notification */ @@ -3348,22 +3478,14 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr) PCI_DEVICE_ID_LSI_SAS0073SKINNY) || (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY) || - (instance->pdev->device == - PCI_DEVICE_ID_LSI_FUSION) || - (instance->pdev->device == - PCI_DEVICE_ID_LSI_PLASMA) || - (instance->pdev->device == - PCI_DEVICE_ID_LSI_INVADER) || - (instance->pdev->device == - PCI_DEVICE_ID_LSI_FURY)) { + (instance->ctrl_context)) writel( MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG, &instance->reg_set->doorbell); - } else { + else writel( MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG, &instance->reg_set->inbound_doorbell); - } max_wait = MEGASAS_RESET_WAIT_TIME; cur_state = MFI_STATE_WAIT_HANDSHAKE; @@ -3374,17 +3496,10 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr) PCI_DEVICE_ID_LSI_SAS0073SKINNY) || (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY) || - (instance->pdev->device == - PCI_DEVICE_ID_LSI_FUSION) || - (instance->pdev->device == - PCI_DEVICE_ID_LSI_PLASMA) || - (instance->pdev->device == - PCI_DEVICE_ID_LSI_INVADER) || - (instance->pdev->device == - PCI_DEVICE_ID_LSI_FURY)) { + (instance->ctrl_context)) writel(MFI_INIT_HOTPLUG, &instance->reg_set->doorbell); - } else + else writel(MFI_INIT_HOTPLUG, &instance->reg_set->inbound_doorbell); @@ -3401,24 +3516,11 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr) PCI_DEVICE_ID_LSI_SAS0073SKINNY) || (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY) || - (instance->pdev->device - == PCI_DEVICE_ID_LSI_FUSION) || - (instance->pdev->device - == PCI_DEVICE_ID_LSI_PLASMA) || - (instance->pdev->device - == PCI_DEVICE_ID_LSI_INVADER) || - (instance->pdev->device - == PCI_DEVICE_ID_LSI_FURY)) { + (instance->ctrl_context)) { writel(MFI_RESET_FLAGS, &instance->reg_set->doorbell); - if ((instance->pdev->device == - PCI_DEVICE_ID_LSI_FUSION) || - (instance->pdev->device == - PCI_DEVICE_ID_LSI_PLASMA) || - (instance->pdev->device == - PCI_DEVICE_ID_LSI_INVADER) || - (instance->pdev->device == - PCI_DEVICE_ID_LSI_FURY)) { + + if (instance->ctrl_context) { for (i = 0; i < (10 * 1000); i += 20) { if (readl( &instance-> @@ -3639,11 +3741,7 @@ static int megasas_create_frame_pool(struct megasas_instance *instance) memset(cmd->frame, 0, total_sz); cmd->frame->io.context = cpu_to_le32(cmd->index); cmd->frame->io.pad_0 = 0; - if ((instance->pdev->device != PCI_DEVICE_ID_LSI_FUSION) && - (instance->pdev->device != PCI_DEVICE_ID_LSI_PLASMA) && - (instance->pdev->device != PCI_DEVICE_ID_LSI_INVADER) && - (instance->pdev->device != PCI_DEVICE_ID_LSI_FURY) && - (reset_devices)) + if (!instance->ctrl_context && reset_devices) cmd->frame->hdr.cmd = MFI_CMD_INVALID; } @@ -4136,11 +4234,21 @@ megasas_get_ctrl_info(struct megasas_instance *instance) le32_to_cpus((u32 *)&ctrl_info->adapterOperations2); le32_to_cpus((u32 *)&ctrl_info->adapterOperations3); megasas_update_ext_vd_details(instance); + instance->use_seqnum_jbod_fp = + ctrl_info->adapterOperations3.useSeqNumJbodFP; instance->is_imr = (ctrl_info->memory_size ? 0 : 1); dev_info(&instance->pdev->dev, "controller type\t: %s(%dMB)\n", instance->is_imr ? "iMR" : "MR", le16_to_cpu(ctrl_info->memory_size)); + instance->disableOnlineCtrlReset = + ctrl_info->properties.OnOffProperties.disableOnlineCtrlReset; + dev_info(&instance->pdev->dev, "Online Controller Reset(OCR)\t: %s\n", + instance->disableOnlineCtrlReset ? "Disabled" : "Enabled"); + instance->secure_jbod_support = + ctrl_info->adapterOperations3.supportSecurityonJBOD; + dev_info(&instance->pdev->dev, "Secure JBOD support\t: %s\n", + instance->secure_jbod_support ? "Yes" : "No"); } pci_free_consistent(instance->pdev, sizeof(struct megasas_ctrl_info), @@ -4481,6 +4589,62 @@ megasas_destroy_irqs(struct megasas_instance *instance) { } /** + * megasas_setup_jbod_map - setup jbod map for FP seq_number. + * @instance: Adapter soft state + * @is_probe: Driver probe check + * + * Return 0 on success. + */ +void +megasas_setup_jbod_map(struct megasas_instance *instance) +{ + int i; + struct fusion_context *fusion = instance->ctrl_context; + u32 pd_seq_map_sz; + + pd_seq_map_sz = sizeof(struct MR_PD_CFG_SEQ_NUM_SYNC) + + (sizeof(struct MR_PD_CFG_SEQ) * (MAX_PHYSICAL_DEVICES - 1)); + + if (reset_devices || !fusion || + !instance->ctrl_info->adapterOperations3.useSeqNumJbodFP) { + dev_info(&instance->pdev->dev, + "Jbod map is not supported %s %d\n", + __func__, __LINE__); + instance->use_seqnum_jbod_fp = false; + return; + } + + if (fusion->pd_seq_sync[0]) + goto skip_alloc; + + for (i = 0; i < JBOD_MAPS_COUNT; i++) { + fusion->pd_seq_sync[i] = dma_alloc_coherent + (&instance->pdev->dev, pd_seq_map_sz, + &fusion->pd_seq_phys[i], GFP_KERNEL); + if (!fusion->pd_seq_sync[i]) { + dev_err(&instance->pdev->dev, + "Failed to allocate memory from %s %d\n", + __func__, __LINE__); + if (i == 1) { + dma_free_coherent(&instance->pdev->dev, + pd_seq_map_sz, fusion->pd_seq_sync[0], + fusion->pd_seq_phys[0]); + fusion->pd_seq_sync[0] = NULL; + } + instance->use_seqnum_jbod_fp = false; + return; + } + } + +skip_alloc: + if (!megasas_sync_pd_seq_num(instance, false) && + !megasas_sync_pd_seq_num(instance, true)) + instance->use_seqnum_jbod_fp = true; + else + instance->use_seqnum_jbod_fp = false; +} + +/** * megasas_init_fw - Initializes the FW * @instance: Adapter soft state * @@ -4498,6 +4662,9 @@ static int megasas_init_fw(struct megasas_instance *instance) unsigned long bar_list; int i, loop, fw_msix_count = 0; struct IOV_111 *iovPtr; + struct fusion_context *fusion; + + fusion = instance->ctrl_context; /* Find first memory bar */ bar_list = pci_select_bars(instance->pdev, IORESOURCE_MEM); @@ -4523,6 +4690,10 @@ static int megasas_init_fw(struct megasas_instance *instance) case PCI_DEVICE_ID_LSI_PLASMA: case PCI_DEVICE_ID_LSI_INVADER: case PCI_DEVICE_ID_LSI_FURY: + case PCI_DEVICE_ID_LSI_INTRUDER: + case PCI_DEVICE_ID_LSI_INTRUDER_24: + case PCI_DEVICE_ID_LSI_CUTLASS_52: + case PCI_DEVICE_ID_LSI_CUTLASS_53: instance->instancet = &megasas_instance_template_fusion; break; case PCI_DEVICE_ID_LSI_SAS1078R: @@ -4541,6 +4712,7 @@ static int megasas_init_fw(struct megasas_instance *instance) case PCI_DEVICE_ID_DELL_PERC5: default: instance->instancet = &megasas_instance_template_xscale; + instance->allow_fw_scan = 1; break; } @@ -4575,37 +4747,32 @@ static int megasas_init_fw(struct megasas_instance *instance) scratch_pad_2 = readl (&instance->reg_set->outbound_scratch_pad_2); /* Check max MSI-X vectors */ - if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA)) { - instance->msix_vectors = (scratch_pad_2 - & MR_MAX_REPLY_QUEUES_OFFSET) + 1; - fw_msix_count = instance->msix_vectors; - if (msix_vectors) - instance->msix_vectors = - min(msix_vectors, - instance->msix_vectors); - } else if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) - || (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) { - /* Invader/Fury supports more than 8 MSI-X */ - instance->msix_vectors = ((scratch_pad_2 - & MR_MAX_REPLY_QUEUES_EXT_OFFSET) - >> MR_MAX_REPLY_QUEUES_EXT_OFFSET_SHIFT) + 1; - fw_msix_count = instance->msix_vectors; - /* Save 1-15 reply post index address to local memory - * Index 0 is already saved from reg offset - * MPI2_REPLY_POST_HOST_INDEX_OFFSET - */ - for (loop = 1; loop < MR_MAX_MSIX_REG_ARRAY; loop++) { - instance->reply_post_host_index_addr[loop] = - (u32 __iomem *) - ((u8 __iomem *)instance->reg_set + - MPI2_SUP_REPLY_POST_HOST_INDEX_OFFSET - + (loop * 0x10)); + if (fusion) { + if (fusion->adapter_type == THUNDERBOLT_SERIES) { /* Thunderbolt Series*/ + instance->msix_vectors = (scratch_pad_2 + & MR_MAX_REPLY_QUEUES_OFFSET) + 1; + fw_msix_count = instance->msix_vectors; + } else { /* Invader series supports more than 8 MSI-x vectors*/ + instance->msix_vectors = ((scratch_pad_2 + & MR_MAX_REPLY_QUEUES_EXT_OFFSET) + >> MR_MAX_REPLY_QUEUES_EXT_OFFSET_SHIFT) + 1; + fw_msix_count = instance->msix_vectors; + /* Save 1-15 reply post index address to local memory + * Index 0 is already saved from reg offset + * MPI2_REPLY_POST_HOST_INDEX_OFFSET + */ + for (loop = 1; loop < MR_MAX_MSIX_REG_ARRAY; loop++) { + instance->reply_post_host_index_addr[loop] = + (u32 __iomem *) + ((u8 __iomem *)instance->reg_set + + MPI2_SUP_REPLY_POST_HOST_INDEX_OFFSET + + (loop * 0x10)); + } } if (msix_vectors) instance->msix_vectors = min(msix_vectors, instance->msix_vectors); - } else + } else /* MFI adapters */ instance->msix_vectors = 1; /* Don't bother allocating more MSI-X vectors than cpus */ instance->msix_vectors = min(instance->msix_vectors, @@ -4626,6 +4793,9 @@ static int megasas_init_fw(struct megasas_instance *instance) "current msix/online cpus\t: (%d/%d)\n", instance->msix_vectors, (unsigned int)num_online_cpus()); + tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet, + (unsigned long)instance); + if (instance->msix_vectors ? megasas_setup_irqs_msix(instance, 1) : megasas_setup_irqs_ioapic(instance)) @@ -4646,13 +4816,13 @@ static int megasas_init_fw(struct megasas_instance *instance) if (instance->instancet->init_adapter(instance)) goto fail_init_adapter; - tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet, - (unsigned long)instance); instance->instancet->enable_intr(instance); dev_err(&instance->pdev->dev, "INIT adapter done\n"); + megasas_setup_jbod_map(instance); + /** for passthrough * the following function will get the PD LIST. */ @@ -4686,8 +4856,6 @@ static int megasas_init_fw(struct megasas_instance *instance) tmp_sectors = min_t(u32, max_sectors_1, max_sectors_2); - instance->disableOnlineCtrlReset = - ctrl_info->properties.OnOffProperties.disableOnlineCtrlReset; instance->mpio = ctrl_info->adapterOperations2.mpio; instance->UnevenSpanSupport = ctrl_info->adapterOperations2.supportUnevenSpans; @@ -4700,18 +4868,22 @@ static int megasas_init_fw(struct megasas_instance *instance) } if (ctrl_info->host_interface.SRIOV) { - if (!ctrl_info->adapterOperations2.activePassive) - instance->PlasmaFW111 = 1; - - if (!instance->PlasmaFW111) - instance->requestorId = - ctrl_info->iov.requestorId; - else { - iovPtr = (struct IOV_111 *)((unsigned char *)ctrl_info + IOV_111_OFFSET); - instance->requestorId = iovPtr->requestorId; + instance->requestorId = ctrl_info->iov.requestorId; + if (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) { + if (!ctrl_info->adapterOperations2.activePassive) + instance->PlasmaFW111 = 1; + + dev_info(&instance->pdev->dev, "SR-IOV: firmware type: %s\n", + instance->PlasmaFW111 ? "1.11" : "new"); + + if (instance->PlasmaFW111) { + iovPtr = (struct IOV_111 *) + ((unsigned char *)ctrl_info + IOV_111_OFFSET); + instance->requestorId = iovPtr->requestorId; + } } - dev_warn(&instance->pdev->dev, "I am VF " - "requestorId %d\n", instance->requestorId); + dev_info(&instance->pdev->dev, "SRIOV: VF requestorId %d\n", + instance->requestorId); } instance->crash_dump_fw_support = @@ -4732,8 +4904,6 @@ static int megasas_init_fw(struct megasas_instance *instance) instance->crash_dump_buf = NULL; } - instance->secure_jbod_support = - ctrl_info->adapterOperations3.supportSecurityonJBOD; dev_info(&instance->pdev->dev, "pci id\t\t: (0x%04x)/(0x%04x)/(0x%04x)/(0x%04x)\n", @@ -4743,16 +4913,14 @@ static int megasas_init_fw(struct megasas_instance *instance) le16_to_cpu(ctrl_info->pci.sub_device_id)); dev_info(&instance->pdev->dev, "unevenspan support : %s\n", instance->UnevenSpanSupport ? "yes" : "no"); - dev_info(&instance->pdev->dev, "disable ocr : %s\n", - instance->disableOnlineCtrlReset ? "yes" : "no"); dev_info(&instance->pdev->dev, "firmware crash dump : %s\n", instance->crash_dump_drv_support ? "yes" : "no"); - dev_info(&instance->pdev->dev, "secure jbod : %s\n", - instance->secure_jbod_support ? "yes" : "no"); + dev_info(&instance->pdev->dev, "jbod sync map : %s\n", + instance->use_seqnum_jbod_fp ? "yes" : "no"); instance->max_sectors_per_req = instance->max_num_sge * - PAGE_SIZE / 512; + SGE_BUFFER_SIZE / 512; if (tmp_sectors && (instance->max_sectors_per_req > tmp_sectors)) instance->max_sectors_per_req = tmp_sectors; @@ -5049,7 +5217,6 @@ static int megasas_start_aen(struct megasas_instance *instance) static int megasas_io_attach(struct megasas_instance *instance) { struct Scsi_Host *host = instance->host; - u32 error; /* * Export parameters required by SCSI mid-layer @@ -5092,20 +5259,10 @@ static int megasas_io_attach(struct megasas_instance *instance) host->max_cmd_len = 16; /* Fusion only supports host reset */ - if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) { + if (instance->ctrl_context) { host->hostt->eh_device_reset_handler = NULL; host->hostt->eh_bus_reset_handler = NULL; } - error = scsi_init_shared_tag_map(host, host->can_queue); - if (error) { - dev_err(&instance->pdev->dev, - "Failed to shared tag from %s %d\n", - __func__, __LINE__); - return -ENODEV; - } /* * Notify the mid-layer about the new controller @@ -5218,6 +5375,10 @@ static int megasas_probe_one(struct pci_dev *pdev, case PCI_DEVICE_ID_LSI_PLASMA: case PCI_DEVICE_ID_LSI_INVADER: case PCI_DEVICE_ID_LSI_FURY: + case PCI_DEVICE_ID_LSI_INTRUDER: + case PCI_DEVICE_ID_LSI_INTRUDER_24: + case PCI_DEVICE_ID_LSI_CUTLASS_52: + case PCI_DEVICE_ID_LSI_CUTLASS_53: { instance->ctrl_context_pages = get_order(sizeof(struct fusion_context)); @@ -5231,6 +5392,11 @@ static int megasas_probe_one(struct pci_dev *pdev, fusion = instance->ctrl_context; memset(fusion, 0, ((1 << PAGE_SHIFT) << instance->ctrl_context_pages)); + if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) || + (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA)) + fusion->adapter_type = THUNDERBOLT_SERIES; + else + fusion->adapter_type = INVADER_SERIES; } break; default: /* For all other supported controllers */ @@ -5333,10 +5499,7 @@ static int megasas_probe_one(struct pci_dev *pdev, instance->disableOnlineCtrlReset = 1; instance->UnevenSpanSupport = 0; - if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) { + if (instance->ctrl_context) { INIT_WORK(&instance->work_init, megasas_fusion_ocr_wq); INIT_WORK(&instance->crash_init, megasas_fusion_crash_dump_wq); } else @@ -5416,10 +5579,7 @@ fail_io_attach: instance->instancet->disable_intr(instance); megasas_destroy_irqs(instance); - if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) + if (instance->ctrl_context) megasas_release_fusion(instance); else megasas_release_mfi(instance); @@ -5506,10 +5666,14 @@ static void megasas_shutdown_controller(struct megasas_instance *instance, if (instance->aen_cmd) megasas_issue_blocked_abort_cmd(instance, - instance->aen_cmd, 30); + instance->aen_cmd, MEGASAS_BLOCKED_CMD_TIMEOUT); if (instance->map_update_cmd) megasas_issue_blocked_abort_cmd(instance, - instance->map_update_cmd, 30); + instance->map_update_cmd, MEGASAS_BLOCKED_CMD_TIMEOUT); + if (instance->jbod_seq_cmd) + megasas_issue_blocked_abort_cmd(instance, + instance->jbod_seq_cmd, MEGASAS_BLOCKED_CMD_TIMEOUT); + dcmd = &cmd->frame->dcmd; memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE); @@ -5628,12 +5792,7 @@ megasas_resume(struct pci_dev *pdev) instance->msix_vectors)) goto fail_reenable_msix; - switch (instance->pdev->device) { - case PCI_DEVICE_ID_LSI_FUSION: - case PCI_DEVICE_ID_LSI_PLASMA: - case PCI_DEVICE_ID_LSI_INVADER: - case PCI_DEVICE_ID_LSI_FURY: - { + if (instance->ctrl_context) { megasas_reset_reply_desc(instance); if (megasas_ioc_init_fusion(instance)) { megasas_free_cmds(instance); @@ -5642,14 +5801,11 @@ megasas_resume(struct pci_dev *pdev) } if (!megasas_get_map_info(instance)) megasas_sync_map_info(instance); - } - break; - default: + } else { *instance->producer = 0; *instance->consumer = 0; if (megasas_issue_init_mfi(instance)) goto fail_init_mfi; - break; } tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet, @@ -5674,6 +5830,7 @@ megasas_resume(struct pci_dev *pdev) } instance->instancet->enable_intr(instance); + megasas_setup_jbod_map(instance); instance->unload = 0; /* @@ -5721,6 +5878,7 @@ static void megasas_detach_one(struct pci_dev *pdev) struct Scsi_Host *host; struct megasas_instance *instance; struct fusion_context *fusion; + u32 pd_seq_map_sz; instance = pci_get_drvdata(pdev); instance->unload = 1; @@ -5769,12 +5927,11 @@ static void megasas_detach_one(struct pci_dev *pdev) if (instance->msix_vectors) pci_disable_msix(instance->pdev); - switch (instance->pdev->device) { - case PCI_DEVICE_ID_LSI_FUSION: - case PCI_DEVICE_ID_LSI_PLASMA: - case PCI_DEVICE_ID_LSI_INVADER: - case PCI_DEVICE_ID_LSI_FURY: + if (instance->ctrl_context) { megasas_release_fusion(instance); + pd_seq_map_sz = sizeof(struct MR_PD_CFG_SEQ_NUM_SYNC) + + (sizeof(struct MR_PD_CFG_SEQ) * + (MAX_PHYSICAL_DEVICES - 1)); for (i = 0; i < 2 ; i++) { if (fusion->ld_map[i]) dma_free_coherent(&instance->pdev->dev, @@ -5784,11 +5941,15 @@ static void megasas_detach_one(struct pci_dev *pdev) if (fusion->ld_drv_map[i]) free_pages((ulong)fusion->ld_drv_map[i], fusion->drv_map_pages); + if (fusion->pd_seq_sync) + dma_free_coherent(&instance->pdev->dev, + pd_seq_map_sz, + fusion->pd_seq_sync[i], + fusion->pd_seq_phys[i]); } free_pages((ulong)instance->ctrl_context, instance->ctrl_context_pages); - break; - default: + } else { megasas_release_mfi(instance); pci_free_consistent(pdev, sizeof(u32), instance->producer, @@ -5796,7 +5957,6 @@ static void megasas_detach_one(struct pci_dev *pdev) pci_free_consistent(pdev, sizeof(u32), instance->consumer, instance->consumer_h); - break; } kfree(instance->ctrl_info); @@ -6316,6 +6476,9 @@ static int megasas_mgmt_compat_ioctl_fw(struct file *file, unsigned long arg) int i; int error = 0; compat_uptr_t ptr; + unsigned long local_raw_ptr; + u32 local_sense_off; + u32 local_sense_len; if (clear_user(ioc, sizeof(*ioc))) return -EFAULT; @@ -6333,9 +6496,15 @@ static int megasas_mgmt_compat_ioctl_fw(struct file *file, unsigned long arg) * sense_len is not null, so prepare the 64bit value under * the same condition. */ - if (ioc->sense_len) { + if (get_user(local_raw_ptr, ioc->frame.raw) || + get_user(local_sense_off, &ioc->sense_off) || + get_user(local_sense_len, &ioc->sense_len)) + return -EFAULT; + + + if (local_sense_len) { void __user **sense_ioc_ptr = - (void __user **)(ioc->frame.raw + ioc->sense_off); + (void __user **)((u8*)local_raw_ptr + local_sense_off); compat_uptr_t *sense_cioc_ptr = (compat_uptr_t *)(cioc->frame.raw + cioc->sense_off); if (get_user(ptr, sense_cioc_ptr) || @@ -6504,6 +6673,7 @@ megasas_aen_polling(struct work_struct *work) instance->ev = NULL; host = instance->host; if (instance->evt_detail) { + megasas_decode_evt(instance); switch (le32_to_cpu(instance->evt_detail->code)) { case MR_EVT_PD_INSERTED: @@ -6564,8 +6734,7 @@ megasas_aen_polling(struct work_struct *work) case MR_EVT_CFG_CLEARED: case MR_EVT_LD_DELETED: if (!instance->requestorId || - (instance->requestorId && - megasas_get_ld_vf_affiliation(instance, 0))) { + megasas_get_ld_vf_affiliation(instance, 0)) { if (megasas_ld_list_query(instance, MR_LD_QUERY_TYPE_EXPOSED_TO_HOST)) megasas_get_ld_list(instance); @@ -6596,8 +6765,7 @@ megasas_aen_polling(struct work_struct *work) break; case MR_EVT_LD_CREATED: if (!instance->requestorId || - (instance->requestorId && - megasas_get_ld_vf_affiliation(instance, 0))) { + megasas_get_ld_vf_affiliation(instance, 0)) { if (megasas_ld_list_query(instance, MR_LD_QUERY_TYPE_EXPOSED_TO_HOST)) megasas_get_ld_list(instance); @@ -6627,6 +6795,9 @@ megasas_aen_polling(struct work_struct *work) case MR_EVT_LD_STATE_CHANGE: doscan = 1; break; + case MR_EVT_CTRL_PROP_CHANGED: + megasas_get_ctrl_info(instance); + break; default: doscan = 0; break; @@ -6663,8 +6834,7 @@ megasas_aen_polling(struct work_struct *work) } if (!instance->requestorId || - (instance->requestorId && - megasas_get_ld_vf_affiliation(instance, 0))) { + megasas_get_ld_vf_affiliation(instance, 0)) { if (megasas_ld_list_query(instance, MR_LD_QUERY_TYPE_EXPOSED_TO_HOST)) megasas_get_ld_list(instance); diff --git a/drivers/scsi/megaraid/megaraid_sas_fp.c b/drivers/scsi/megaraid/megaraid_sas_fp.c index be57b18675a4..741509b35617 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fp.c +++ b/drivers/scsi/megaraid/megaraid_sas_fp.c @@ -741,14 +741,12 @@ static u8 mr_spanset_get_phy_params(struct megasas_instance *instance, u32 ld, u8 physArm, span; u64 row; u8 retval = TRUE; - u8 do_invader = 0; u64 *pdBlock = &io_info->pdBlock; __le16 *pDevHandle = &io_info->devHandle; u32 logArm, rowMod, armQ, arm; + struct fusion_context *fusion; - if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER || - instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) - do_invader = 1; + fusion = instance->ctrl_context; /*Get row and span from io_info for Uneven Span IO.*/ row = io_info->start_row; @@ -779,7 +777,8 @@ static u8 mr_spanset_get_phy_params(struct megasas_instance *instance, u32 ld, else { *pDevHandle = cpu_to_le16(MR_PD_INVALID); if ((raid->level >= 5) && - (!do_invader || (do_invader && + ((fusion->adapter_type == THUNDERBOLT_SERIES) || + ((fusion->adapter_type == INVADER_SERIES) && (raid->regTypeReqOnRead != REGION_TYPE_UNUSED)))) pRAID_Context->regLockFlags = REGION_TYPE_EXCLUSIVE; else if (raid->level == 1) { @@ -823,13 +822,12 @@ u8 MR_GetPhyParams(struct megasas_instance *instance, u32 ld, u64 stripRow, u8 physArm, span; u64 row; u8 retval = TRUE; - u8 do_invader = 0; u64 *pdBlock = &io_info->pdBlock; __le16 *pDevHandle = &io_info->devHandle; + struct fusion_context *fusion; + + fusion = instance->ctrl_context; - if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER || - instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) - do_invader = 1; row = mega_div64_32(stripRow, raid->rowDataSize); @@ -875,7 +873,8 @@ u8 MR_GetPhyParams(struct megasas_instance *instance, u32 ld, u64 stripRow, /* set dev handle as invalid. */ *pDevHandle = cpu_to_le16(MR_PD_INVALID); if ((raid->level >= 5) && - (!do_invader || (do_invader && + ((fusion->adapter_type == THUNDERBOLT_SERIES) || + ((fusion->adapter_type == INVADER_SERIES) && (raid->regTypeReqOnRead != REGION_TYPE_UNUSED)))) pRAID_Context->regLockFlags = REGION_TYPE_EXCLUSIVE; else if (raid->level == 1) { @@ -909,6 +908,7 @@ MR_BuildRaidContext(struct megasas_instance *instance, struct RAID_CONTEXT *pRAID_Context, struct MR_DRV_RAID_MAP_ALL *map, u8 **raidLUN) { + struct fusion_context *fusion; struct MR_LD_RAID *raid; u32 ld, stripSize, stripe_mask; u64 endLba, endStrip, endRow, start_row, start_strip; @@ -929,6 +929,7 @@ MR_BuildRaidContext(struct megasas_instance *instance, isRead = io_info->isRead; io_info->IoforUnevenSpan = 0; io_info->start_span = SPAN_INVALID; + fusion = instance->ctrl_context; ld = MR_TargetIdToLdGet(ldTgtId, map); raid = MR_LdRaidGet(ld, map); @@ -1092,8 +1093,7 @@ MR_BuildRaidContext(struct megasas_instance *instance, cpu_to_le16(raid->fpIoTimeoutForLd ? raid->fpIoTimeoutForLd : map->raidMap.fpPdIoTimeoutSec); - if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) + if (fusion->adapter_type == INVADER_SERIES) pRAID_Context->regLockFlags = (isRead) ? raid->regTypeReqOnRead : raid->regTypeReqOnWrite; else @@ -1198,10 +1198,6 @@ void mr_update_span_set(struct MR_DRV_RAID_MAP_ALL *map, span_row_width += MR_LdSpanPtrGet (ld, count, map)->spanRowDataSize; - printk(KERN_INFO "megasas:" - "span %x rowDataSize %x\n", - count, MR_LdSpanPtrGet - (ld, count, map)->spanRowDataSize); } } diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index f0837cc3b163..8d630a552b07 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -316,26 +316,23 @@ static int megasas_create_frame_pool_fusion(struct megasas_instance *instance) u32 max_cmd; struct fusion_context *fusion; struct megasas_cmd_fusion *cmd; - u32 total_sz_chain_frame; fusion = instance->ctrl_context; max_cmd = instance->max_fw_cmds; - total_sz_chain_frame = MEGASAS_MAX_SZ_CHAIN_FRAME; /* * Use DMA pool facility provided by PCI layer */ - fusion->sg_dma_pool = pci_pool_create("megasas sg pool fusion", - instance->pdev, - total_sz_chain_frame, 4, - 0); + fusion->sg_dma_pool = pci_pool_create("sg_pool_fusion", instance->pdev, + instance->max_chain_frame_sz, + 4, 0); if (!fusion->sg_dma_pool) { dev_printk(KERN_DEBUG, &instance->pdev->dev, "failed to setup request pool fusion\n"); return -ENOMEM; } - fusion->sense_dma_pool = pci_pool_create("megasas sense pool fusion", + fusion->sense_dma_pool = pci_pool_create("sense pool fusion", instance->pdev, SCSI_SENSE_BUFFERSIZE, 64, 0); @@ -605,6 +602,7 @@ megasas_ioc_init_fusion(struct megasas_instance *instance) int i; struct megasas_header *frame_hdr; const char *sys_info; + MFI_CAPABILITIES *drv_ops; fusion = instance->ctrl_context; @@ -652,20 +650,21 @@ megasas_ioc_init_fusion(struct megasas_instance *instance) init_frame->cmd = MFI_CMD_INIT; init_frame->cmd_status = 0xFF; + drv_ops = (MFI_CAPABILITIES *) &(init_frame->driver_operations); + /* driver support Extended MSIX */ - if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) - init_frame->driver_operations. - mfi_capabilities.support_additional_msix = 1; + if (fusion->adapter_type == INVADER_SERIES) + drv_ops->mfi_capabilities.support_additional_msix = 1; /* driver supports HA / Remote LUN over Fast Path interface */ - init_frame->driver_operations.mfi_capabilities.support_fp_remote_lun - = 1; - init_frame->driver_operations.mfi_capabilities.support_max_255lds - = 1; - init_frame->driver_operations.mfi_capabilities.support_ndrive_r1_lb - = 1; - init_frame->driver_operations.mfi_capabilities.security_protocol_cmds_fw - = 1; + drv_ops->mfi_capabilities.support_fp_remote_lun = 1; + + drv_ops->mfi_capabilities.support_max_255lds = 1; + drv_ops->mfi_capabilities.support_ndrive_r1_lb = 1; + drv_ops->mfi_capabilities.security_protocol_cmds_fw = 1; + + if (instance->max_chain_frame_sz > MEGASAS_CHAIN_FRAME_SZ_MIN) + drv_ops->mfi_capabilities.support_ext_io_size = 1; + /* Convert capability to LE32 */ cpu_to_le32s((u32 *)&init_frame->driver_operations.mfi_capabilities); @@ -726,6 +725,83 @@ fail_get_cmd: return ret; } +/** + * megasas_sync_pd_seq_num - JBOD SEQ MAP + * @instance: Adapter soft state + * @pend: set to 1, if it is pended jbod map. + * + * Issue Jbod map to the firmware. If it is pended command, + * issue command and return. If it is first instance of jbod map + * issue and receive command. + */ +int +megasas_sync_pd_seq_num(struct megasas_instance *instance, bool pend) { + int ret = 0; + u32 pd_seq_map_sz; + struct megasas_cmd *cmd; + struct megasas_dcmd_frame *dcmd; + struct fusion_context *fusion = instance->ctrl_context; + struct MR_PD_CFG_SEQ_NUM_SYNC *pd_sync; + dma_addr_t pd_seq_h; + + pd_sync = (void *)fusion->pd_seq_sync[(instance->pd_seq_map_id & 1)]; + pd_seq_h = fusion->pd_seq_phys[(instance->pd_seq_map_id & 1)]; + pd_seq_map_sz = sizeof(struct MR_PD_CFG_SEQ_NUM_SYNC) + + (sizeof(struct MR_PD_CFG_SEQ) * + (MAX_PHYSICAL_DEVICES - 1)); + + cmd = megasas_get_cmd(instance); + if (!cmd) { + dev_err(&instance->pdev->dev, + "Could not get mfi cmd. Fail from %s %d\n", + __func__, __LINE__); + return -ENOMEM; + } + + dcmd = &cmd->frame->dcmd; + + memset(pd_sync, 0, pd_seq_map_sz); + memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE); + dcmd->cmd = MFI_CMD_DCMD; + dcmd->cmd_status = 0xFF; + dcmd->sge_count = 1; + dcmd->timeout = 0; + dcmd->pad_0 = 0; + dcmd->data_xfer_len = cpu_to_le32(pd_seq_map_sz); + dcmd->opcode = cpu_to_le32(MR_DCMD_SYSTEM_PD_MAP_GET_INFO); + dcmd->sgl.sge32[0].phys_addr = cpu_to_le32(pd_seq_h); + dcmd->sgl.sge32[0].length = cpu_to_le32(pd_seq_map_sz); + + if (pend) { + dcmd->mbox.b[0] = MEGASAS_DCMD_MBOX_PEND_FLAG; + dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_WRITE); + instance->jbod_seq_cmd = cmd; + instance->instancet->issue_dcmd(instance, cmd); + return 0; + } + + dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_READ); + + /* Below code is only for non pended DCMD */ + if (instance->ctrl_context && !instance->mask_interrupts) + ret = megasas_issue_blocked_cmd(instance, cmd, 60); + else + ret = megasas_issue_polled(instance, cmd); + + if (le32_to_cpu(pd_sync->count) > MAX_PHYSICAL_DEVICES) { + dev_warn(&instance->pdev->dev, + "driver supports max %d JBOD, but FW reports %d\n", + MAX_PHYSICAL_DEVICES, le32_to_cpu(pd_sync->count)); + ret = -EINVAL; + } + + if (!ret) + instance->pd_seq_map_id++; + + megasas_return_cmd(instance, cmd); + return ret; +} + /* * megasas_get_ld_map_info - Returns FW's ld_map structure * @instance: Adapter soft state @@ -961,6 +1037,18 @@ megasas_display_intel_branding(struct megasas_instance *instance) break; } break; + case PCI_DEVICE_ID_LSI_CUTLASS_52: + case PCI_DEVICE_ID_LSI_CUTLASS_53: + switch (instance->pdev->subsystem_device) { + case MEGARAID_INTEL_RMS3BC160_SSDID: + dev_info(&instance->pdev->dev, "scsi host %d: %s\n", + instance->host->host_no, + MEGARAID_INTEL_RMS3BC160_BRANDING); + break; + default: + break; + } + break; default: break; } @@ -977,7 +1065,7 @@ megasas_init_adapter_fusion(struct megasas_instance *instance) { struct megasas_register_set __iomem *reg_set; struct fusion_context *fusion; - u32 max_cmd; + u32 max_cmd, scratch_pad_2; int i = 0, count; fusion = instance->ctrl_context; @@ -1016,15 +1104,40 @@ megasas_init_adapter_fusion(struct megasas_instance *instance) (MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE * (max_cmd + 1)); /* Extra 1 for SMID 0 */ + scratch_pad_2 = readl(&instance->reg_set->outbound_scratch_pad_2); + /* If scratch_pad_2 & MEGASAS_MAX_CHAIN_SIZE_UNITS_MASK is set, + * Firmware support extended IO chain frame which is 4 times more than + * legacy Firmware. + * Legacy Firmware - Frame size is (8 * 128) = 1K + * 1M IO Firmware - Frame size is (8 * 128 * 4) = 4K + */ + if (scratch_pad_2 & MEGASAS_MAX_CHAIN_SIZE_UNITS_MASK) + instance->max_chain_frame_sz = + ((scratch_pad_2 & MEGASAS_MAX_CHAIN_SIZE_MASK) >> + MEGASAS_MAX_CHAIN_SHIFT) * MEGASAS_1MB_IO; + else + instance->max_chain_frame_sz = + ((scratch_pad_2 & MEGASAS_MAX_CHAIN_SIZE_MASK) >> + MEGASAS_MAX_CHAIN_SHIFT) * MEGASAS_256K_IO; + + if (instance->max_chain_frame_sz < MEGASAS_CHAIN_FRAME_SZ_MIN) { + dev_warn(&instance->pdev->dev, "frame size %d invalid, fall back to legacy max frame size %d\n", + instance->max_chain_frame_sz, + MEGASAS_CHAIN_FRAME_SZ_MIN); + instance->max_chain_frame_sz = MEGASAS_CHAIN_FRAME_SZ_MIN; + } + fusion->max_sge_in_main_msg = - (MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE - - offsetof(struct MPI2_RAID_SCSI_IO_REQUEST, SGL))/16; + (MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE + - offsetof(struct MPI2_RAID_SCSI_IO_REQUEST, SGL))/16; fusion->max_sge_in_chain = - MEGASAS_MAX_SZ_CHAIN_FRAME / sizeof(union MPI2_SGE_IO_UNION); + instance->max_chain_frame_sz + / sizeof(union MPI2_SGE_IO_UNION); - instance->max_num_sge = rounddown_pow_of_two( - fusion->max_sge_in_main_msg + fusion->max_sge_in_chain - 2); + instance->max_num_sge = + rounddown_pow_of_two(fusion->max_sge_in_main_msg + + fusion->max_sge_in_chain - 2); /* Used for pass thru MFI frame (DCMD) */ fusion->chain_offset_mfi_pthru = @@ -1186,8 +1299,7 @@ megasas_make_sgl_fusion(struct megasas_instance *instance, fusion = instance->ctrl_context; - if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) { + if (fusion->adapter_type == INVADER_SERIES) { struct MPI25_IEEE_SGE_CHAIN64 *sgl_ptr_end = sgl_ptr; sgl_ptr_end += fusion->max_sge_in_main_msg - 1; sgl_ptr_end->Flags = 0; @@ -1204,11 +1316,9 @@ megasas_make_sgl_fusion(struct megasas_instance *instance, sgl_ptr->Length = cpu_to_le32(sg_dma_len(os_sgl)); sgl_ptr->Address = cpu_to_le64(sg_dma_address(os_sgl)); sgl_ptr->Flags = 0; - if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) { + if (fusion->adapter_type == INVADER_SERIES) if (i == sge_count - 1) sgl_ptr->Flags = IEEE_SGE_FLAGS_END_OF_LIST; - } sgl_ptr++; sg_processed = i + 1; @@ -1217,10 +1327,7 @@ megasas_make_sgl_fusion(struct megasas_instance *instance, (sge_count > fusion->max_sge_in_main_msg)) { struct MPI25_IEEE_SGE_CHAIN64 *sg_chain; - if ((instance->pdev->device == - PCI_DEVICE_ID_LSI_INVADER) || - (instance->pdev->device == - PCI_DEVICE_ID_LSI_FURY)) { + if (fusion->adapter_type == INVADER_SERIES) { if ((le16_to_cpu(cmd->io_request->IoFlags) & MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH) != MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH) @@ -1236,10 +1343,7 @@ megasas_make_sgl_fusion(struct megasas_instance *instance, sg_chain = sgl_ptr; /* Prepare chain element */ sg_chain->NextChainOffset = 0; - if ((instance->pdev->device == - PCI_DEVICE_ID_LSI_INVADER) || - (instance->pdev->device == - PCI_DEVICE_ID_LSI_FURY)) + if (fusion->adapter_type == INVADER_SERIES) sg_chain->Flags = IEEE_SGE_FLAGS_CHAIN_ELEMENT; else sg_chain->Flags = @@ -1250,7 +1354,7 @@ megasas_make_sgl_fusion(struct megasas_instance *instance, sgl_ptr = (struct MPI25_IEEE_SGE_CHAIN64 *)cmd->sg_frame; - memset(sgl_ptr, 0, MEGASAS_MAX_SZ_CHAIN_FRAME); + memset(sgl_ptr, 0, instance->max_chain_frame_sz); } } @@ -1556,8 +1660,7 @@ megasas_build_ldio_fusion(struct megasas_instance *instance, cmd->request_desc->SCSIIO.RequestFlags = (MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); - if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) { + if (fusion->adapter_type == INVADER_SERIES) { if (io_request->RaidContext.regLockFlags == REGION_TYPE_UNUSED) cmd->request_desc->SCSIIO.RequestFlags = @@ -1582,7 +1685,7 @@ megasas_build_ldio_fusion(struct megasas_instance *instance, scp->SCp.Status &= ~MEGASAS_LOAD_BALANCE_FLAG; if ((raidLUN[0] == 1) && - (local_map_ptr->raidMap.devHndlInfo[io_info.pd_after_lb].validHandles > 2)) { + (local_map_ptr->raidMap.devHndlInfo[io_info.pd_after_lb].validHandles > 1)) { instance->dev_handle = !(instance->dev_handle); io_info.devHandle = local_map_ptr->raidMap.devHndlInfo[io_info.pd_after_lb].devHandle[instance->dev_handle]; @@ -1598,8 +1701,7 @@ megasas_build_ldio_fusion(struct megasas_instance *instance, cmd->request_desc->SCSIIO.RequestFlags = (MEGASAS_REQ_DESCRIPT_FLAGS_LD_IO << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); - if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) { + if (fusion->adapter_type == INVADER_SERIES) { if (io_request->RaidContext.regLockFlags == REGION_TYPE_UNUSED) cmd->request_desc->SCSIIO.RequestFlags = @@ -1722,7 +1824,9 @@ megasas_build_syspd_fusion(struct megasas_instance *instance, u16 timeout_limit; struct MR_DRV_RAID_MAP_ALL *local_map_ptr; struct RAID_CONTEXT *pRAID_Context; + struct MR_PD_CFG_SEQ_NUM_SYNC *pd_sync; struct fusion_context *fusion = instance->ctrl_context; + pd_sync = (void *)fusion->pd_seq_sync[(instance->pd_seq_map_id - 1) & 1]; device_id = MEGASAS_DEV_INDEX(scmd); pd_index = MEGASAS_PD_INDEX(scmd); @@ -1731,16 +1835,38 @@ megasas_build_syspd_fusion(struct megasas_instance *instance, io_request = cmd->io_request; /* get RAID_Context pointer */ pRAID_Context = &io_request->RaidContext; + pRAID_Context->regLockFlags = 0; + pRAID_Context->regLockRowLBA = 0; + pRAID_Context->regLockLength = 0; io_request->DataLength = cpu_to_le32(scsi_bufflen(scmd)); io_request->LUN[1] = scmd->device->lun; pRAID_Context->RAIDFlags = MR_RAID_FLAGS_IO_SUB_TYPE_SYSTEM_PD << MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT; - pRAID_Context->VirtualDiskTgtId = cpu_to_le16(device_id); - pRAID_Context->configSeqNum = 0; - local_map_ptr = fusion->ld_drv_map[(instance->map_id & 1)]; - io_request->DevHandle = - local_map_ptr->raidMap.devHndlInfo[device_id].curDevHdl; + /* If FW supports PD sequence number */ + if (instance->use_seqnum_jbod_fp && + instance->pd_list[pd_index].driveType == TYPE_DISK) { + /* TgtId must be incremented by 255 as jbod seq number is index + * below raid map + */ + pRAID_Context->VirtualDiskTgtId = + cpu_to_le16(device_id + (MAX_PHYSICAL_DEVICES - 1)); + pRAID_Context->configSeqNum = pd_sync->seq[pd_index].seqNum; + io_request->DevHandle = pd_sync->seq[pd_index].devHandle; + pRAID_Context->regLockFlags |= + (MR_RL_FLAGS_SEQ_NUM_ENABLE|MR_RL_FLAGS_GRANT_DESTINATION_CUDA); + } else if (fusion->fast_path_io) { + pRAID_Context->VirtualDiskTgtId = cpu_to_le16(device_id); + pRAID_Context->configSeqNum = 0; + local_map_ptr = fusion->ld_drv_map[(instance->map_id & 1)]; + io_request->DevHandle = + local_map_ptr->raidMap.devHndlInfo[device_id].curDevHdl; + } else { + /* Want to send all IO via FW path */ + pRAID_Context->VirtualDiskTgtId = cpu_to_le16(device_id); + pRAID_Context->configSeqNum = 0; + io_request->DevHandle = cpu_to_le16(0xFFFF); + } cmd->request_desc->SCSIIO.DevHandle = io_request->DevHandle; cmd->request_desc->SCSIIO.MSIxIndex = @@ -1755,22 +1881,16 @@ megasas_build_syspd_fusion(struct megasas_instance *instance, (MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); pRAID_Context->timeoutValue = cpu_to_le16(os_timeout_value); + pRAID_Context->VirtualDiskTgtId = cpu_to_le16(device_id); } else { /* system pd Fast Path */ io_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST; - pRAID_Context->regLockFlags = 0; - pRAID_Context->regLockRowLBA = 0; - pRAID_Context->regLockLength = 0; timeout_limit = (scmd->device->type == TYPE_DISK) ? 255 : 0xFFFF; pRAID_Context->timeoutValue = cpu_to_le16((os_timeout_value > timeout_limit) ? timeout_limit : os_timeout_value); - if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) { - cmd->request_desc->SCSIIO.RequestFlags |= - (MEGASAS_REQ_DESCRIPT_FLAGS_NO_LOCK << - MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); + if (fusion->adapter_type == INVADER_SERIES) { pRAID_Context->Type = MPI2_TYPE_CUDA; pRAID_Context->nseg = 0x1; io_request->IoFlags |= @@ -1796,7 +1916,7 @@ megasas_build_io_fusion(struct megasas_instance *instance, struct scsi_cmnd *scp, struct megasas_cmd_fusion *cmd) { - u32 sge_count; + u16 sge_count; u8 cmd_type; struct MPI2_RAID_SCSI_IO_REQUEST *io_request = cmd->io_request; @@ -1854,7 +1974,11 @@ megasas_build_io_fusion(struct megasas_instance *instance, return 1; } + /* numSGE store lower 8 bit of sge_count. + * numSGEExt store higher 8 bit of sge_count + */ io_request->RaidContext.numSGE = sge_count; + io_request->RaidContext.numSGEExt = (u8)(sge_count >> 8); io_request->SGLFlags = cpu_to_le16(MPI2_SGE_FLAGS_64_BIT_ADDRESSING); @@ -2084,10 +2208,7 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex) * pending to be completed */ if (threshold_reply_count >= THRESHOLD_REPLY_COUNT) { - if ((instance->pdev->device == - PCI_DEVICE_ID_LSI_INVADER) || - (instance->pdev->device == - PCI_DEVICE_ID_LSI_FURY)) + if (fusion->adapter_type == INVADER_SERIES) writel(((MSIxIndex & 0x7) << 24) | fusion->last_reply_idx[MSIxIndex], instance->reply_post_host_index_addr[MSIxIndex/8]); @@ -2103,8 +2224,7 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex) return IRQ_NONE; wmb(); - if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) + if (fusion->adapter_type == INVADER_SERIES) writel(((MSIxIndex & 0x7) << 24) | fusion->last_reply_idx[MSIxIndex], instance->reply_post_host_index_addr[MSIxIndex/8]); @@ -2227,8 +2347,7 @@ build_mpt_mfi_pass_thru(struct megasas_instance *instance, io_req = cmd->io_request; - if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) { + if (fusion->adapter_type == INVADER_SERIES) { struct MPI25_IEEE_SGE_CHAIN64 *sgl_ptr_end = (struct MPI25_IEEE_SGE_CHAIN64 *)&io_req->SGL; sgl_ptr_end += fusion->max_sge_in_main_msg - 1; @@ -2248,7 +2367,7 @@ build_mpt_mfi_pass_thru(struct megasas_instance *instance, mpi25_ieee_chain->Flags = IEEE_SGE_FLAGS_CHAIN_ELEMENT | MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR; - mpi25_ieee_chain->Length = cpu_to_le32(MEGASAS_MAX_SZ_CHAIN_FRAME); + mpi25_ieee_chain->Length = cpu_to_le32(instance->max_chain_frame_sz); return 0; } @@ -2384,6 +2503,70 @@ static int megasas_adp_reset_fusion(struct megasas_instance *instance, struct megasas_register_set __iomem *regs) { + u32 host_diag, abs_state, retry; + + /* Now try to reset the chip */ + writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &instance->reg_set->fusion_seq_offset); + writel(MPI2_WRSEQ_1ST_KEY_VALUE, &instance->reg_set->fusion_seq_offset); + writel(MPI2_WRSEQ_2ND_KEY_VALUE, &instance->reg_set->fusion_seq_offset); + writel(MPI2_WRSEQ_3RD_KEY_VALUE, &instance->reg_set->fusion_seq_offset); + writel(MPI2_WRSEQ_4TH_KEY_VALUE, &instance->reg_set->fusion_seq_offset); + writel(MPI2_WRSEQ_5TH_KEY_VALUE, &instance->reg_set->fusion_seq_offset); + writel(MPI2_WRSEQ_6TH_KEY_VALUE, &instance->reg_set->fusion_seq_offset); + + /* Check that the diag write enable (DRWE) bit is on */ + host_diag = readl(&instance->reg_set->fusion_host_diag); + retry = 0; + while (!(host_diag & HOST_DIAG_WRITE_ENABLE)) { + msleep(100); + host_diag = readl(&instance->reg_set->fusion_host_diag); + if (retry++ == 100) { + dev_warn(&instance->pdev->dev, + "Host diag unlock failed from %s %d\n", + __func__, __LINE__); + break; + } + } + if (!(host_diag & HOST_DIAG_WRITE_ENABLE)) + return -1; + + /* Send chip reset command */ + writel(host_diag | HOST_DIAG_RESET_ADAPTER, + &instance->reg_set->fusion_host_diag); + msleep(3000); + + /* Make sure reset adapter bit is cleared */ + host_diag = readl(&instance->reg_set->fusion_host_diag); + retry = 0; + while (host_diag & HOST_DIAG_RESET_ADAPTER) { + msleep(100); + host_diag = readl(&instance->reg_set->fusion_host_diag); + if (retry++ == 1000) { + dev_warn(&instance->pdev->dev, + "Diag reset adapter never cleared %s %d\n", + __func__, __LINE__); + break; + } + } + if (host_diag & HOST_DIAG_RESET_ADAPTER) + return -1; + + abs_state = instance->instancet->read_fw_status_reg(instance->reg_set) + & MFI_STATE_MASK; + retry = 0; + + while ((abs_state <= MFI_STATE_FW_INIT) && (retry++ < 1000)) { + msleep(100); + abs_state = instance->instancet-> + read_fw_status_reg(instance->reg_set) & MFI_STATE_MASK; + } + if (abs_state <= MFI_STATE_FW_INIT) { + dev_warn(&instance->pdev->dev, + "fw state < MFI_STATE_FW_INIT, state = 0x%x %s %d\n", + abs_state, __func__, __LINE__); + return -1; + } + return 0; } @@ -2512,8 +2695,10 @@ void megasas_refire_mgmt_cmd(struct megasas_instance *instance) continue; req_desc = megasas_get_request_descriptor (instance, smid - 1); - if (req_desc && (cmd_mfi->frame->dcmd.opcode != - cpu_to_le32(MR_DCMD_LD_MAP_GET_INFO))) + if (req_desc && ((cmd_mfi->frame->dcmd.opcode != + cpu_to_le32(MR_DCMD_LD_MAP_GET_INFO)) && + (cmd_mfi->frame->dcmd.opcode != + cpu_to_le32(MR_DCMD_SYSTEM_PD_MAP_GET_INFO)))) megasas_fire_cmd_fusion(instance, req_desc); else megasas_return_cmd(instance, cmd_mfi); @@ -2547,11 +2732,11 @@ out: /* Core fusion reset function */ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout) { - int retval = SUCCESS, i, retry = 0, convert = 0; + int retval = SUCCESS, i, convert = 0; struct megasas_instance *instance; struct megasas_cmd_fusion *cmd_fusion; struct fusion_context *fusion; - u32 host_diag, abs_state, status_reg, reset_adapter; + u32 abs_state, status_reg, reset_adapter; u32 io_timeout_in_crash_mode = 0; struct scsi_cmnd *scmd_local = NULL; @@ -2705,82 +2890,11 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout) /* Now try to reset the chip */ for (i = 0; i < MEGASAS_FUSION_MAX_RESET_TRIES; i++) { - writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, - &instance->reg_set->fusion_seq_offset); - writel(MPI2_WRSEQ_1ST_KEY_VALUE, - &instance->reg_set->fusion_seq_offset); - writel(MPI2_WRSEQ_2ND_KEY_VALUE, - &instance->reg_set->fusion_seq_offset); - writel(MPI2_WRSEQ_3RD_KEY_VALUE, - &instance->reg_set->fusion_seq_offset); - writel(MPI2_WRSEQ_4TH_KEY_VALUE, - &instance->reg_set->fusion_seq_offset); - writel(MPI2_WRSEQ_5TH_KEY_VALUE, - &instance->reg_set->fusion_seq_offset); - writel(MPI2_WRSEQ_6TH_KEY_VALUE, - &instance->reg_set->fusion_seq_offset); - - /* Check that the diag write enable (DRWE) bit is on */ - host_diag = readl(&instance->reg_set->fusion_host_diag); - retry = 0; - while (!(host_diag & HOST_DIAG_WRITE_ENABLE)) { - msleep(100); - host_diag = - readl(&instance->reg_set->fusion_host_diag); - if (retry++ == 100) { - dev_warn(&instance->pdev->dev, - "Host diag unlock failed! " - "for scsi%d\n", - instance->host->host_no); - break; - } - } - if (!(host_diag & HOST_DIAG_WRITE_ENABLE)) - continue; - /* Send chip reset command */ - writel(host_diag | HOST_DIAG_RESET_ADAPTER, - &instance->reg_set->fusion_host_diag); - msleep(3000); - - /* Make sure reset adapter bit is cleared */ - host_diag = readl(&instance->reg_set->fusion_host_diag); - retry = 0; - while (host_diag & HOST_DIAG_RESET_ADAPTER) { - msleep(100); - host_diag = - readl(&instance->reg_set->fusion_host_diag); - if (retry++ == 1000) { - dev_warn(&instance->pdev->dev, - "Diag reset adapter never " - "cleared for scsi%d!\n", - instance->host->host_no); - break; - } - } - if (host_diag & HOST_DIAG_RESET_ADAPTER) + if (instance->instancet->adp_reset + (instance, instance->reg_set)) continue; - abs_state = - instance->instancet->read_fw_status_reg( - instance->reg_set) & MFI_STATE_MASK; - retry = 0; - - while ((abs_state <= MFI_STATE_FW_INIT) && - (retry++ < 1000)) { - msleep(100); - abs_state = - instance->instancet->read_fw_status_reg( - instance->reg_set) & MFI_STATE_MASK; - } - if (abs_state <= MFI_STATE_FW_INIT) { - dev_warn(&instance->pdev->dev, "firmware " - "state < MFI_STATE_FW_INIT, state = " - "0x%x for scsi%d\n", abs_state, - instance->host->host_no); - continue; - } - /* Wait for FW to become ready */ if (megasas_transition_to_ready(instance, 1)) { dev_warn(&instance->pdev->dev, "Failed to " @@ -2816,6 +2930,8 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout) if (!megasas_get_map_info(instance)) megasas_sync_map_info(instance); + megasas_setup_jbod_map(instance); + clear_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags); instance->instancet->enable_intr(instance); diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h index ced6dc0cf8e8..473005c99b44 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.h +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h @@ -35,8 +35,13 @@ #define _MEGARAID_SAS_FUSION_H_ /* Fusion defines */ -#define MEGASAS_MAX_SZ_CHAIN_FRAME 1024 +#define MEGASAS_CHAIN_FRAME_SZ_MIN 1024 #define MFI_FUSION_ENABLE_INTERRUPT_MASK (0x00000009) +#define MEGASAS_MAX_CHAIN_SHIFT 5 +#define MEGASAS_MAX_CHAIN_SIZE_UNITS_MASK 0x400000 +#define MEGASAS_MAX_CHAIN_SIZE_MASK 0x3E0 +#define MEGASAS_256K_IO 128 +#define MEGASAS_1MB_IO (MEGASAS_256K_IO * 4) #define MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE 256 #define MEGASAS_MPI2_FUNCTION_PASSTHRU_IO_REQUEST 0xF0 #define MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST 0xF1 @@ -89,6 +94,12 @@ enum MR_RAID_FLAGS_IO_SUB_TYPE { #define MEGASAS_FP_CMD_LEN 16 #define MEGASAS_FUSION_IN_RESET 0 #define THRESHOLD_REPLY_COUNT 50 +#define JBOD_MAPS_COUNT 2 + +enum MR_FUSION_ADAPTER_TYPE { + THUNDERBOLT_SERIES = 0, + INVADER_SERIES = 1, +}; /* * Raid Context structure which describes MegaRAID specific IO Parameters @@ -117,7 +128,9 @@ struct RAID_CONTEXT { u8 numSGE; __le16 configSeqNum; u8 spanArm; - u8 resvd2[3]; + u8 priority; + u8 numSGEExt; + u8 resvd2; }; #define RAID_CTX_SPANARM_ARM_SHIFT (0) @@ -486,6 +499,7 @@ struct MPI2_IOC_INIT_REQUEST { #define MAX_PHYSICAL_DEVICES 256 #define MAX_RAIDMAP_PHYSICAL_DEVICES (MAX_PHYSICAL_DEVICES) #define MR_DCMD_LD_MAP_GET_INFO 0x0300e101 +#define MR_DCMD_SYSTEM_PD_MAP_GET_INFO 0x0200e102 #define MR_DCMD_CTRL_SHARED_HOST_MEM_ALLOC 0x010e8485 /* SR-IOV HB alloc*/ #define MR_DCMD_LD_VF_MAP_GET_ALL_LDS_111 0x03200200 #define MR_DCMD_LD_VF_MAP_GET_ALL_LDS 0x03150200 @@ -789,6 +803,21 @@ struct MR_FW_RAID_MAP_EXT { struct MR_LD_SPAN_MAP ldSpanMap[MAX_LOGICAL_DRIVES_EXT]; }; +/* + * * define MR_PD_CFG_SEQ structure for system PDs + * */ +struct MR_PD_CFG_SEQ { + __le16 seqNum; + __le16 devHandle; + u8 reserved[4]; +} __packed; + +struct MR_PD_CFG_SEQ_NUM_SYNC { + __le32 size; + __le32 count; + struct MR_PD_CFG_SEQ seq[1]; +} __packed; + struct fusion_context { struct megasas_cmd_fusion **cmd_list; dma_addr_t req_frames_desc_phys; @@ -828,9 +857,12 @@ struct fusion_context { u32 current_map_sz; u32 drv_map_sz; u32 drv_map_pages; + struct MR_PD_CFG_SEQ_NUM_SYNC *pd_seq_sync[JBOD_MAPS_COUNT]; + dma_addr_t pd_seq_phys[JBOD_MAPS_COUNT]; u8 fast_path_io; struct LD_LOAD_BALANCE_INFO load_balance_info[MAX_LOGICAL_DRIVES_EXT]; LD_SPAN_INFO log_to_span[MAX_LOGICAL_DRIVES_EXT]; + u8 adapter_type; }; union desc_value { diff --git a/drivers/scsi/mpt2sas/Kconfig b/drivers/scsi/mpt2sas/Kconfig deleted file mode 100644 index 657b45ca04c5..000000000000 --- a/drivers/scsi/mpt2sas/Kconfig +++ /dev/null @@ -1,67 +0,0 @@ -# -# Kernel configuration file for the MPT2SAS -# -# This code is based on drivers/scsi/mpt2sas/Kconfig -# Copyright (C) 2007-2014 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 - select RAID_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 deleted file mode 100644 index 728f0475711d..000000000000 --- a/drivers/scsi/mpt2sas/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# 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 deleted file mode 100644 index 7fc6f23bd9dc..000000000000 --- a/drivers/scsi/mpt2sas/mpi/mpi2.h +++ /dev/null @@ -1,1170 +0,0 @@ -/* - * Copyright (c) 2000-2014 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.35 - * - * 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. - * 05-06-09 02.00.12 Bumped MPI2_HEADER_VERSION_UNIT. - * In all request and reply descriptors, replaced VF_ID - * field with MSIxIndex field. - * Removed DevHandle field from - * MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR and made those - * bytes reserved. - * Added RAID Accelerator functionality. - * 07-30-09 02.00.13 Bumped MPI2_HEADER_VERSION_UNIT. - * 10-28-09 02.00.14 Bumped MPI2_HEADER_VERSION_UNIT. - * Added MSI-x index mask and shift for Reply Post Host - * Index register. - * Added function code for Host Based Discovery Action. - * 02-10-10 02.00.15 Bumped MPI2_HEADER_VERSION_UNIT. - * Added define for MPI2_FUNCTION_PWR_MGMT_CONTROL. - * Added defines for product-specific range of message - * function codes, 0xF0 to 0xFF. - * 05-12-10 02.00.16 Bumped MPI2_HEADER_VERSION_UNIT. - * Added alternative defines for the SGE Direction bit. - * 08-11-10 02.00.17 Bumped MPI2_HEADER_VERSION_UNIT. - * 11-10-10 02.00.18 Bumped MPI2_HEADER_VERSION_UNIT. - * Added MPI2_IEEE_SGE_FLAGS_SYSTEMPLBCPI_ADDR define. - * 02-23-11 02.00.19 Bumped MPI2_HEADER_VERSION_UNIT. - * Added MPI2_FUNCTION_SEND_HOST_MESSAGE. - * 03-09-11 02.00.20 Bumped MPI2_HEADER_VERSION_UNIT. - * 05-25-11 02.00.21 Bumped MPI2_HEADER_VERSION_UNIT. - * 08-24-11 02.00.22 Bumped MPI2_HEADER_VERSION_UNIT. - * 11-18-11 02.00.23 Bumped MPI2_HEADER_VERSION_UNIT. - * 02-06-12 02.00.24 Bumped MPI2_HEADER_VERSION_UNIT. - * 03-29-12 02.00.25 Bumped MPI2_HEADER_VERSION_UNIT. - * Added Hard Reset delay timings. - * 07-10-12 02.00.26 Bumped MPI2_HEADER_VERSION_UNIT. - * 07-26-12 02.00.27 Bumped MPI2_HEADER_VERSION_UNIT. - * 11-27-12 02.00.28 Bumped MPI2_HEADER_VERSION_UNIT. - * 12-20-12 02.00.29 Bumped MPI2_HEADER_VERSION_UNIT. - * Added MPI25_SUP_REPLY_POST_HOST_INDEX_OFFSET. - * 04-09-13 02.00.30 Bumped MPI2_HEADER_VERSION_UNIT. - * 04-17-13 02.00.31 Bumped MPI2_HEADER_VERSION_UNIT. - * 08-19-13 02.00.32 Bumped MPI2_HEADER_VERSION_UNIT. - * 12-05-13 02.00.33 Bumped MPI2_HEADER_VERSION_UNIT. - * 01-08-14 02.00.34 Bumped MPI2_HEADER_VERSION_UNIT. - * 06-13-14 02.00.35 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 (0x23) -#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) - -/* - * Defines for the Reply Descriptor Post Queue - */ -#define MPI2_REPLY_POST_HOST_INDEX_OFFSET (0x0000006C) -#define MPI2_REPLY_POST_HOST_INDEX_MASK (0x00FFFFFF) -#define MPI2_RPHI_MSIX_INDEX_MASK (0xFF000000) -#define MPI2_RPHI_MSIX_INDEX_SHIFT (24) -#define MPI25_SUP_REPLY_POST_HOST_INDEX_OFFSET (0x0000030C) /* MPI v2.5 only */ - -/* - * 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) - - -/* Hard Reset delay timings */ -#define MPI2_HARD_RESET_PCIE_FIRST_READ_DELAY_MICRO_SEC (50000) -#define MPI2_HARD_RESET_PCIE_RESET_READ_WINDOW_MICRO_SEC (255000) -#define MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC (256000) - -/***************************************************************************** -* -* Message Descriptors -* -*****************************************************************************/ - -/* Request Descriptors */ - -/* Default Request Descriptor */ -typedef struct _MPI2_DEFAULT_REQUEST_DESCRIPTOR -{ - U8 RequestFlags; /* 0x00 */ - U8 MSIxIndex; /* 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_RAID_ACCELERATOR (0x0A) - -#define MPI2_REQ_DESCRIPT_FLAGS_IOC_FIFO_MARKER (0x01) - - -/* High Priority Request Descriptor */ -typedef struct _MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR -{ - U8 RequestFlags; /* 0x00 */ - U8 MSIxIndex; /* 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 MSIxIndex; /* 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 MSIxIndex; /* 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; - - -/* RAID Accelerator Request Descriptor */ -typedef struct _MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR { - U8 RequestFlags; /* 0x00 */ - U8 MSIxIndex; /* 0x01 */ - U16 SMID; /* 0x02 */ - U16 LMID; /* 0x04 */ - U16 Reserved; /* 0x06 */ -} MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR, - MPI2_POINTER PTR_MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR, - Mpi2RAIDAcceleratorRequestDescriptor_t, - MPI2_POINTER pMpi2RAIDAcceleratorRequestDescriptor_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; - MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR RAIDAccelerator; - 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 MSIxIndex; /* 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_RAID_ACCELERATOR_SUCCESS (0x05) -#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 MSIxIndex; /* 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 MSIxIndex; /* 0x01 */ - U16 SMID; /* 0x02 */ - U16 TaskTag; /* 0x04 */ - U16 Reserved1; /* 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 MSIxIndex; /* 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 MSIxIndex; /* 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) - - -/* RAID Accelerator Success Reply Descriptor */ -typedef struct _MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR { - U8 ReplyFlags; /* 0x00 */ - U8 MSIxIndex; /* 0x01 */ - U16 SMID; /* 0x02 */ - U32 Reserved; /* 0x04 */ -} MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR, - MPI2_POINTER PTR_MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR, - Mpi2RAIDAcceleratorSuccessReplyDescriptor_t, - MPI2_POINTER pMpi2RAIDAcceleratorSuccessReplyDescriptor_t; - - -/* 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; - MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR RAIDAcceleratorSuccess; - U64 Words; -} MPI2_REPLY_DESCRIPTORS_UNION, MPI2_POINTER PTR_MPI2_REPLY_DESCRIPTORS_UNION, -Mpi2ReplyDescriptorsUnion_t, MPI2_POINTER pMpi2ReplyDescriptorsUnion_t; - - - -/***************************************************************************** -* -* Message Functions -* -*****************************************************************************/ - -#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 */ -#define MPI2_FUNCTION_RAID_ACCELERATOR (0x2C) /* RAID Accelerator*/ -/* Host Based Discovery Action */ -#define MPI2_FUNCTION_HOST_BASED_DISCOVERY_ACTION (0x2F) -/* Power Management Control */ -#define MPI2_FUNCTION_PWR_MGMT_CONTROL (0x30) -/* Send Host Message */ -#define MPI2_FUNCTION_SEND_HOST_MESSAGE (0x31) -/* beginning of product-specific range */ -#define MPI2_FUNCTION_MIN_PRODUCT_SPECIFIC (0xF0) -/* end of product-specific range */ -#define MPI2_FUNCTION_MAX_PRODUCT_SPECIFIC (0xFF) - - - - -/* Doorbell functions */ -#define MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET (0x40) -#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) - -/**************************************************************************** -* RAID Accelerator values -****************************************************************************/ - -#define MPI2_IOCSTATUS_RAID_ACCEL_ERROR (0x00B0) - -/**************************************************************************** -* 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) - -#define MPI2_SGE_FLAGS_DEST (MPI2_SGE_FLAGS_IOC_TO_HOST) -#define MPI2_SGE_FLAGS_SOURCE (MPI2_SGE_FLAGS_HOST_TO_IOC) - -/* 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) - /* IEEE Simple Element only */ -#define MPI2_IEEE_SGE_FLAGS_IOCDDR_ADDR (0x01) - /* IEEE Simple Element only */ -#define MPI2_IEEE_SGE_FLAGS_IOCPLB_ADDR (0x02) -#define MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR (0x03) - /* IEEE Simple Element only */ -#define MPI2_IEEE_SGE_FLAGS_SYSTEMPLBPCI_ADDR (0x03) - /* IEEE Chain Element only */ -#define MPI2_IEEE_SGE_FLAGS_SYSTEMPLBCPI_ADDR \ - (MPI2_IEEE_SGE_FLAGS_SYSTEMPLBPCI_ADDR) /* typo in name */ - -/**************************************************************************** -* 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 deleted file mode 100644 index ee8d2d695d55..000000000000 --- a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h +++ /dev/null @@ -1,3068 +0,0 @@ -/* - * Copyright (c) 2000-2014 LSI Corporation. - * - * - * Name: mpi2_cnfg.h - * Title: MPI Configuration messages and pages - * Creation Date: November 10, 2006 - * - * mpi2_cnfg.h Version: 02.00.29 - * - * 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. - * 05-06-09 02.00.11 Added structures and defines for IO Unit Page 5 and IO - * Unit Page 6. - * Added expander reduced functionality data to SAS - * Expander Page 0. - * Added SAS PHY Page 2 and SAS PHY Page 3. - * 07-30-09 02.00.12 Added IO Unit Page 7. - * Added new device ids. - * Added SAS IO Unit Page 5. - * Added partial and slumber power management capable flags - * to SAS Device Page 0 Flags field. - * Added PhyInfo defines for power condition. - * Added Ethernet configuration pages. - * 10-28-09 02.00.13 Added MPI2_IOUNITPAGE1_ENABLE_HOST_BASED_DISCOVERY. - * Added SAS PHY Page 4 structure and defines. - * 02-10-10 02.00.14 Modified the comments for the configuration page - * structures that contain an array of data. The host - * should use the "count" field in the page data (e.g. the - * NumPhys field) to determine the number of valid elements - * in the array. - * Added/modified some MPI2_MFGPAGE_DEVID_SAS defines. - * Added PowerManagementCapabilities to IO Unit Page 7. - * Added PortWidthModGroup field to - * MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS. - * Added MPI2_CONFIG_PAGE_SASIOUNIT_6 and related defines. - * Added MPI2_CONFIG_PAGE_SASIOUNIT_7 and related defines. - * Added MPI2_CONFIG_PAGE_SASIOUNIT_8 and related defines. - * 05-12-10 02.00.15 Added MPI2_RAIDVOL0_STATUS_FLAG_VOL_NOT_CONSISTENT - * define. - * Added MPI2_PHYSDISK0_INCOMPATIBLE_MEDIA_TYPE define. - * Added MPI2_SAS_NEG_LINK_RATE_UNSUPPORTED_PHY define. - * 08-11-10 02.00.16 Removed IO Unit Page 1 device path (multi-pathing) - * defines. - * 11-10-10 02.00.17 Added ReceptacleID field (replacing Reserved1) to - * MPI2_MANPAGE7_CONNECTOR_INFO and reworked defines for - * the Pinout field. - * Added BoardTemperature and BoardTemperatureUnits fields - * to MPI2_CONFIG_PAGE_IO_UNIT_7. - * Added MPI2_CONFIG_EXTPAGETYPE_EXT_MANUFACTURING define - * and MPI2_CONFIG_PAGE_EXT_MAN_PS structure. - * 02-23-11 02.00.18 Added ProxyVF_ID field to MPI2_CONFIG_REQUEST. - * Added IO Unit Page 8, IO Unit Page 9, - * and IO Unit Page 10. - * Added SASNotifyPrimitiveMasks field to - * MPI2_CONFIG_PAGE_IOC_7. - * 03-09-11 02.00.19 Fixed IO Unit Page 10 (to match the spec). - * 05-25-11 02.00.20 Cleaned up a few comments. - * 08-24-11 02.00.21 Marked the IO Unit Page 7 PowerManagementCapabilities - * for PCIe link as obsolete. - * Added SpinupFlags field containing a Disable Spin-up - * bit to the MPI2_SAS_IOUNIT4_SPINUP_GROUP fields of - * SAS IO Unit Page 4. - * 11-18-11 02.00.22 Added define MPI2_IOCPAGE6_CAP_FLAGS_4K_SECTORS_SUPPORT. - * Added UEFIVersion field to BIOS Page 1 and defined new - * BiosOptions bits. - * 11-27-12 02.00.23 Added MPI2_MANPAGE7_FLAG_EVENTREPLAY_SLOT_ORDER. - * Added MPI2_BIOSPAGE1_OPTIONS_MASK_OEM_ID. - * 12-20-12 02.00.24 Marked MPI2_SASIOUNIT1_CONTROL_CLEAR_AFFILIATION as - * obsolete for MPI v2.5 and later. - * Added some defines for 12G SAS speeds. - * 04-09-13 02.00.25 Added MPI2_IOUNITPAGE1_ATA_SECURITY_FREEZE_LOCK. - * Fixed MPI2_IOUNITPAGE5_DMA_CAP_MASK_MAX_REQUESTS to - * match the specification. - * 12-05-13 02.00.27 Added MPI2_MANPAGE7_FLAG_BASE_ENCLOSURE_LEVEL for - * MPI2_CONFIG_PAGE_MAN_7. - * Added EnclosureLevel and ConnectorName fields to - * MPI2_CONFIG_PAGE_SAS_DEV_0. - * Added MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID for - * MPI2_CONFIG_PAGE_SAS_DEV_0. - * Added EnclosureLevel field to - * MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0. - * Added MPI2_SAS_ENCLS0_FLAGS_ENCL_LEVEL_VALID for - * MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0. - * 01-08-14 02.00.28 Added more defines for the BiosOptions field of - * MPI2_CONFIG_PAGE_BIOS_1. - * 06-13-14 02.00.29 Added SSUTimeout field to MPI2_CONFIG_PAGE_BIOS_1, and - * more defines for the BiosOptions field. - * -------------------------------------------------------------------------- - */ - -#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) -#define MPI2_CONFIG_EXTPAGETYPE_ETHERNET (0x19) -#define MPI2_CONFIG_EXTPAGETYPE_EXT_MANUFACTURING (0x1A) - - -/***************************************************************************** -* 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) - - -/* Ethernet PageAddress format */ -#define MPI2_ETHERNET_PGAD_FORM_MASK (0xF0000000) -#define MPI2_ETHERNET_PGAD_FORM_IF_NUM (0x00000000) - -#define MPI2_ETHERNET_PGAD_IF_NUMBER_MASK (0x000000FF) - - - -/**************************************************************************** -* 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 */ - U8 Reserved2; /* 0x0C */ - U8 ProxyVF_ID; /* 0x0D */ - U16 Reserved4; /* 0x0E */ - 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) - -/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */ - - -/* 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) - -#define MPI2_MFGPAGE_DEVID_SSS6200 (0x007E) - -#define MPI2_MFGPAGE_DEVID_SAS2208_1 (0x0080) -#define MPI2_MFGPAGE_DEVID_SAS2208_2 (0x0081) -#define MPI2_MFGPAGE_DEVID_SAS2208_3 (0x0082) -#define MPI2_MFGPAGE_DEVID_SAS2208_4 (0x0083) -#define MPI2_MFGPAGE_DEVID_SAS2208_5 (0x0084) -#define MPI2_MFGPAGE_DEVID_SAS2208_6 (0x0085) -#define MPI2_MFGPAGE_DEVID_SAS2308_1 (0x0086) -#define MPI2_MFGPAGE_DEVID_SAS2308_2 (0x0087) -#define MPI2_MFGPAGE_DEVID_SAS2308_3 (0x006E) - - - - -/* 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 the value returned for 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 ReceptacleID; /* 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_LANE_MASK (0x0000FF00) -#define MPI2_MANPAGE7_PINOUT_LANE_SHIFT (8) - -#define MPI2_MANPAGE7_PINOUT_TYPE_MASK (0x000000FF) -#define MPI2_MANPAGE7_PINOUT_TYPE_UNKNOWN (0x00) -#define MPI2_MANPAGE7_PINOUT_SATA_SINGLE (0x01) -#define MPI2_MANPAGE7_PINOUT_SFF_8482 (0x02) -#define MPI2_MANPAGE7_PINOUT_SFF_8486 (0x03) -#define MPI2_MANPAGE7_PINOUT_SFF_8484 (0x04) -#define MPI2_MANPAGE7_PINOUT_SFF_8087 (0x05) -#define MPI2_MANPAGE7_PINOUT_SFF_8643_4I (0x06) -#define MPI2_MANPAGE7_PINOUT_SFF_8643_8I (0x07) -#define MPI2_MANPAGE7_PINOUT_SFF_8470 (0x08) -#define MPI2_MANPAGE7_PINOUT_SFF_8088 (0x09) -#define MPI2_MANPAGE7_PINOUT_SFF_8644_4X (0x0A) -#define MPI2_MANPAGE7_PINOUT_SFF_8644_8X (0x0B) -#define MPI2_MANPAGE7_PINOUT_SFF_8644_16X (0x0C) -#define MPI2_MANPAGE7_PINOUT_SFF_8436 (0x0D) - -/* 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 the value returned for 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 (0x01) - -/* defines for the Flags field */ -#define MPI2_MANPAGE7_FLAG_BASE_ENCLOSURE_LEVEL (0x00000008) -#define MPI2_MANPAGE7_FLAG_EVENTREPLAY_SLOT_ORDER (0x00000002) -#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_ATA_SECURITY_FREEZE_LOCK (0x00004000) -#define MPI2_IOUNITPAGE1_ENABLE_HOST_BASED_DISCOVERY (0x00000800) -#define MPI2_IOUNITPAGE1_MASK_SATA_WRITE_CACHE (0x00000600) -#define MPI2_IOUNITPAGE1_SATA_WRITE_CACHE_SHIFT (9) -#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) - - -/* IO Unit Page 3 */ - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check the value returned for GPIOCount at runtime. - */ -#ifndef MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX -#define MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX (1) -#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) - - -/* IO Unit Page 5 */ - -/* - * Upper layer code (drivers, utilities, etc.) should leave this define set to - * one and check the value returned for NumDmaEngines at runtime. - */ -#ifndef MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES -#define MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES (1) -#endif - -typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_5 { - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U64 RaidAcceleratorBufferBaseAddress; /* 0x04 */ - U64 RaidAcceleratorBufferSize; /* 0x0C */ - U64 RaidAcceleratorControlBaseAddress; /* 0x14 */ - U8 RAControlSize; /* 0x1C */ - U8 NumDmaEngines; /* 0x1D */ - U8 RAMinControlSize; /* 0x1E */ - U8 RAMaxControlSize; /* 0x1F */ - U32 Reserved1; /* 0x20 */ - U32 Reserved2; /* 0x24 */ - U32 Reserved3; /* 0x28 */ - U32 DmaEngineCapabilities - [MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES]; /* 0x2C */ -} MPI2_CONFIG_PAGE_IO_UNIT_5, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_5, - Mpi2IOUnitPage5_t, MPI2_POINTER pMpi2IOUnitPage5_t; - -#define MPI2_IOUNITPAGE5_PAGEVERSION (0x00) - -/* defines for IO Unit Page 5 DmaEngineCapabilities field */ -#define MPI2_IOUNITPAGE5_DMA_CAP_MASK_MAX_REQUESTS (0xFFFF0000) -#define MPI2_IOUNITPAGE5_DMA_CAP_SHIFT_MAX_REQUESTS (16) - -#define MPI2_IOUNITPAGE5_DMA_CAP_EEDP (0x0008) -#define MPI2_IOUNITPAGE5_DMA_CAP_PARITY_GENERATION (0x0004) -#define MPI2_IOUNITPAGE5_DMA_CAP_HASHING (0x0002) -#define MPI2_IOUNITPAGE5_DMA_CAP_ENCRYPTION (0x0001) - - -/* IO Unit Page 6 */ - -typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_6 { - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U16 Flags; /* 0x04 */ - U8 RAHostControlSize; /* 0x06 */ - U8 Reserved0; /* 0x07 */ - U64 RaidAcceleratorHostControlBaseAddress; /* 0x08 */ - U32 Reserved1; /* 0x10 */ - U32 Reserved2; /* 0x14 */ - U32 Reserved3; /* 0x18 */ -} MPI2_CONFIG_PAGE_IO_UNIT_6, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_6, - Mpi2IOUnitPage6_t, MPI2_POINTER pMpi2IOUnitPage6_t; - -#define MPI2_IOUNITPAGE6_PAGEVERSION (0x00) - -/* defines for IO Unit Page 6 Flags field */ -#define MPI2_IOUNITPAGE6_FLAGS_ENABLE_RAID_ACCELERATOR (0x0001) - - -/* IO Unit Page 7 */ - -typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_7 { - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U16 Reserved1; /* 0x04 */ - U8 PCIeWidth; /* 0x06 */ - U8 PCIeSpeed; /* 0x07 */ - U32 ProcessorState; /* 0x08 */ - U32 PowerManagementCapabilities; /* 0x0C */ - U16 IOCTemperature; /* 0x10 */ - U8 IOCTemperatureUnits; /* 0x12 */ - U8 IOCSpeed; /* 0x13 */ - U16 BoardTemperature; /* 0x14 */ - U8 BoardTemperatureUnits; /* 0x16 */ - U8 Reserved3; /* 0x17 */ - U32 Reserved4; /* 0x18 */ - U32 Reserved5; /* 0x1C */ - U32 Reserved6; /* 0x20 */ - U32 Reserved7; /* 0x24 */ -} MPI2_CONFIG_PAGE_IO_UNIT_7, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_7, - Mpi2IOUnitPage7_t, MPI2_POINTER pMpi2IOUnitPage7_t; - -#define MPI2_IOUNITPAGE7_PAGEVERSION (0x04) - -/* defines for IO Unit Page 7 PCIeWidth field */ -#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X1 (0x01) -#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X2 (0x02) -#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X4 (0x04) -#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X8 (0x08) - -/* defines for IO Unit Page 7 PCIeSpeed field */ -#define MPI2_IOUNITPAGE7_PCIE_SPEED_2_5_GBPS (0x00) -#define MPI2_IOUNITPAGE7_PCIE_SPEED_5_0_GBPS (0x01) -#define MPI2_IOUNITPAGE7_PCIE_SPEED_8_0_GBPS (0x02) - -/* defines for IO Unit Page 7 ProcessorState field */ -#define MPI2_IOUNITPAGE7_PSTATE_MASK_SECOND (0x0000000F) -#define MPI2_IOUNITPAGE7_PSTATE_SHIFT_SECOND (0) - -#define MPI2_IOUNITPAGE7_PSTATE_NOT_PRESENT (0x00) -#define MPI2_IOUNITPAGE7_PSTATE_DISABLED (0x01) -#define MPI2_IOUNITPAGE7_PSTATE_ENABLED (0x02) - -/* defines for IO Unit Page 7 PowerManagementCapabilities field */ -#define MPI2_IOUNITPAGE7_PMCAP_12_5_PCT_IOCSPEED (0x00000400) -#define MPI2_IOUNITPAGE7_PMCAP_25_0_PCT_IOCSPEED (0x00000200) -#define MPI2_IOUNITPAGE7_PMCAP_50_0_PCT_IOCSPEED (0x00000100) -#define MPI2_IOUNITPAGE7_PMCAP_PCIE_WIDTH_CHANGE (0x00000008) /* obsolete */ -#define MPI2_IOUNITPAGE7_PMCAP_PCIE_SPEED_CHANGE (0x00000004) /* obsolete */ - -/* defines for IO Unit Page 7 IOCTemperatureUnits field */ -#define MPI2_IOUNITPAGE7_IOC_TEMP_NOT_PRESENT (0x00) -#define MPI2_IOUNITPAGE7_IOC_TEMP_FAHRENHEIT (0x01) -#define MPI2_IOUNITPAGE7_IOC_TEMP_CELSIUS (0x02) - -/* defines for IO Unit Page 7 IOCSpeed field */ -#define MPI2_IOUNITPAGE7_IOC_SPEED_FULL (0x01) -#define MPI2_IOUNITPAGE7_IOC_SPEED_HALF (0x02) -#define MPI2_IOUNITPAGE7_IOC_SPEED_QUARTER (0x04) -#define MPI2_IOUNITPAGE7_IOC_SPEED_EIGHTH (0x08) - -/* defines for IO Unit Page 7 BoardTemperatureUnits field */ -#define MPI2_IOUNITPAGE7_BOARD_TEMP_NOT_PRESENT (0x00) -#define MPI2_IOUNITPAGE7_BOARD_TEMP_FAHRENHEIT (0x01) -#define MPI2_IOUNITPAGE7_BOARD_TEMP_CELSIUS (0x02) - -/* IO Unit Page 8 */ - -#define MPI2_IOUNIT8_NUM_THRESHOLDS (4) - -typedef struct _MPI2_IOUNIT8_SENSOR { - U16 Flags; /* 0x00 */ - U16 Reserved1; /* 0x02 */ - U16 - Threshold[MPI2_IOUNIT8_NUM_THRESHOLDS]; /* 0x04 */ - U32 Reserved2; /* 0x0C */ - U32 Reserved3; /* 0x10 */ - U32 Reserved4; /* 0x14 */ -} MPI2_IOUNIT8_SENSOR, MPI2_POINTER PTR_MPI2_IOUNIT8_SENSOR, -Mpi2IOUnit8Sensor_t, MPI2_POINTER pMpi2IOUnit8Sensor_t; - -/* defines for IO Unit Page 8 Sensor Flags field */ -#define MPI2_IOUNIT8_SENSOR_FLAGS_T3_ENABLE (0x0008) -#define MPI2_IOUNIT8_SENSOR_FLAGS_T2_ENABLE (0x0004) -#define MPI2_IOUNIT8_SENSOR_FLAGS_T1_ENABLE (0x0002) -#define MPI2_IOUNIT8_SENSOR_FLAGS_T0_ENABLE (0x0001) - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check the value returned for NumSensors at runtime. - */ -#ifndef MPI2_IOUNITPAGE8_SENSOR_ENTRIES -#define MPI2_IOUNITPAGE8_SENSOR_ENTRIES (1) -#endif - -typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_8 { - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U32 Reserved1; /* 0x04 */ - U32 Reserved2; /* 0x08 */ - U8 NumSensors; /* 0x0C */ - U8 PollingInterval; /* 0x0D */ - U16 Reserved3; /* 0x0E */ - MPI2_IOUNIT8_SENSOR - Sensor[MPI2_IOUNITPAGE8_SENSOR_ENTRIES];/* 0x10 */ -} MPI2_CONFIG_PAGE_IO_UNIT_8, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_8, -Mpi2IOUnitPage8_t, MPI2_POINTER pMpi2IOUnitPage8_t; - -#define MPI2_IOUNITPAGE8_PAGEVERSION (0x00) - - -/* IO Unit Page 9 */ - -typedef struct _MPI2_IOUNIT9_SENSOR { - U16 CurrentTemperature; /* 0x00 */ - U16 Reserved1; /* 0x02 */ - U8 Flags; /* 0x04 */ - U8 Reserved2; /* 0x05 */ - U16 Reserved3; /* 0x06 */ - U32 Reserved4; /* 0x08 */ - U32 Reserved5; /* 0x0C */ -} MPI2_IOUNIT9_SENSOR, MPI2_POINTER PTR_MPI2_IOUNIT9_SENSOR, -Mpi2IOUnit9Sensor_t, MPI2_POINTER pMpi2IOUnit9Sensor_t; - -/* defines for IO Unit Page 9 Sensor Flags field */ -#define MPI2_IOUNIT9_SENSOR_FLAGS_TEMP_VALID (0x01) - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check the value returned for NumSensors at runtime. - */ -#ifndef MPI2_IOUNITPAGE9_SENSOR_ENTRIES -#define MPI2_IOUNITPAGE9_SENSOR_ENTRIES (1) -#endif - -typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_9 { - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U32 Reserved1; /* 0x04 */ - U32 Reserved2; /* 0x08 */ - U8 NumSensors; /* 0x0C */ - U8 Reserved4; /* 0x0D */ - U16 Reserved3; /* 0x0E */ - MPI2_IOUNIT9_SENSOR - Sensor[MPI2_IOUNITPAGE9_SENSOR_ENTRIES];/* 0x10 */ -} MPI2_CONFIG_PAGE_IO_UNIT_9, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_9, -Mpi2IOUnitPage9_t, MPI2_POINTER pMpi2IOUnitPage9_t; - -#define MPI2_IOUNITPAGE9_PAGEVERSION (0x00) - - -/* IO Unit Page 10 */ - -typedef struct _MPI2_IOUNIT10_FUNCTION { - U8 CreditPercent; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U16 Reserved2; /* 0x02 */ -} MPI2_IOUNIT10_FUNCTION, MPI2_POINTER PTR_MPI2_IOUNIT10_FUNCTION, -Mpi2IOUnit10Function_t, MPI2_POINTER pMpi2IOUnit10Function_t; - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check the value returned for NumFunctions at runtime. - */ -#ifndef MPI2_IOUNITPAGE10_FUNCTION_ENTRIES -#define MPI2_IOUNITPAGE10_FUNCTION_ENTRIES (1) -#endif - -typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_10 { - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U8 NumFunctions; /* 0x04 */ - U8 Reserved1; /* 0x05 */ - U16 Reserved2; /* 0x06 */ - U32 Reserved3; /* 0x08 */ - U32 Reserved4; /* 0x0C */ - MPI2_IOUNIT10_FUNCTION - Function[MPI2_IOUNITPAGE10_FUNCTION_ENTRIES];/* 0x10 */ -} MPI2_CONFIG_PAGE_IO_UNIT_10, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_10, -Mpi2IOUnitPage10_t, MPI2_POINTER pMpi2IOUnitPage10_t; - -#define MPI2_IOUNITPAGE10_PAGEVERSION (0x01) - - - -/**************************************************************************** -* 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 (0x05) - -/* defines for IOC Page 6 CapabilitiesFlags */ -#define MPI2_IOCPAGE6_CAP_FLAGS_4K_SECTORS_SUPPORT (0x00000020) -#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 SASNotifyPrimitiveMasks; /* 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 (0x02) - - -/* 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 */ - U8 SSUTimeout; /* 0x0C */ - U8 Reserved1; /* 0x0D */ - U16 Reserved2; /* 0x0E */ - U32 DeviceSettings; /* 0x10 */ - U16 NumberOfDevices; /* 0x14 */ - U16 UEFIVersion; /* 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 (0x07) - -/* values for BIOS Page 1 BiosOptions field */ -#define MPI2_BIOSPAGE1_OPTIONS_PNS_MASK (0x00003800) -#define MPI2_BIOSPAGE1_OPTIONS_PNS_PBDHL (0x00000000) -#define MPI2_BIOSPAGE1_OPTIONS_PNS_ENCSLOSURE (0x00000800) -#define MPI2_BIOSPAGE1_OPTIONS_PNS_LWWID (0x00001000) -#define MPI2_BIOSPAGE1_OPTIONS_PNS_PSENS (0x00001800) -#define MPI2_BIOSPAGE1_OPTIONS_PNS_ESPHY (0x00002000) - -#define MPI2_BIOSPAGE1_OPTIONS_X86_DISABLE_BIOS (0x00000400) - -#define MPI2_BIOSPAGE1_OPTIONS_MASK_REGISTRATION_UEFI_BSD (0x00000300) -#define MPI2_BIOSPAGE1_OPTIONS_USE_BIT0_REGISTRATION_UEFI_BSD (0x00000000) -#define MPI2_BIOSPAGE1_OPTIONS_FULL_REGISTRATION_UEFI_BSD (0x00000100) -#define MPI2_BIOSPAGE1_OPTIONS_ADAPTER_REGISTRATION_UEFI_BSD (0x00000200) -#define MPI2_BIOSPAGE1_OPTIONS_DISABLE_REGISTRATION_UEFI_BSD (0x00000300) - -#define MPI2_BIOSPAGE1_OPTIONS_MASK_OEM_ID (0x000000F0) -#define MPI2_BIOSPAGE1_OPTIONS_LSI_OEM_ID (0x00000000) - -#define MPI2_BIOSPAGE1_OPTIONS_MASK_UEFI_HII_REGISTRATION (0x00000006) -#define MPI2_BIOSPAGE1_OPTIONS_ENABLE_UEFI_HII (0x00000000) -#define MPI2_BIOSPAGE1_OPTIONS_DISABLE_UEFI_HII (0x00000002) -#define MPI2_BIOSPAGE1_OPTIONS_VERSION_CHECK_UEFI_HII (0x00000004) - -#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) - -/* defines for BIOS Page 1 UEFIVersion field */ -#define MPI2_BIOSPAGE1_UEFI_VER_MAJOR_MASK (0xFF00) -#define MPI2_BIOSPAGE1_UEFI_VER_MAJOR_SHIFT (8) -#define MPI2_BIOSPAGE1_UEFI_VER_MINOR_MASK (0x00FF) -#define MPI2_BIOSPAGE1_UEFI_VER_MINOR_SHIFT (0) - - - -/* 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 the value returned for 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 the value returned for NumPhysDisks 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_VOL_NOT_CONSISTENT (0x00000080) -#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_MEDIA_TYPE (0x06) -#define MPI2_PHYSDISK0_INCOMPATIBLE_UNKNOWN (0xFF) - -/* PhysDiskAttributes defines */ -#define MPI2_PHYSDISK0_ATTRIB_MEDIA_MASK (0x0C) -#define MPI2_PHYSDISK0_ATTRIB_SOLID_STATE_DRIVE (0x08) -#define MPI2_PHYSDISK0_ATTRIB_HARD_DISK_DRIVE (0x04) - -#define MPI2_PHYSDISK0_ATTRIB_PROTOCOL_MASK (0x03) -#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 the value returned for 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_UNSUPPORTED_PHY (0x06) -#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_PHY_POWER_CONDITION_MASK (0x18000000) -#define MPI2_SAS_PHYINFO_SHIFT_PHY_POWER_CONDITION (27) -#define MPI2_SAS_PHYINFO_PHY_POWER_ACTIVE (0x00000000) -#define MPI2_SAS_PHYINFO_PHY_POWER_PARTIAL (0x08000000) -#define MPI2_SAS_PHYINFO_PHY_POWER_SLUMBER (0x10000000) - -#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 MPI25_SAS_PRATE_MAX_RATE_12_0 (0xB0) -#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 MPI25_SAS_HWRATE_MAX_RATE_12_0 (0xB0) -#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 the value returned for 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 the value returned for 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 1 PhyFlags */ -#define MPI2_SASIOUNIT1_PHYFLAGS_ZONING_ENABLE (0x10) -#define MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE (0x08) - -/* values for SAS IO Unit Page 1 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 */ - U8 SpinupFlags; /* 0x02 */ - U8 Reserved1; /* 0x03 */ -} MPI2_SAS_IOUNIT4_SPINUP_GROUP, MPI2_POINTER PTR_MPI2_SAS_IOUNIT4_SPINUP_GROUP, - Mpi2SasIOUnit4SpinupGroup_t, MPI2_POINTER pMpi2SasIOUnit4SpinupGroup_t; - -/* defines for SAS IO Unit Page 4 SpinupFlags */ -#define MPI2_SASIOUNIT4_SPINUP_DISABLE_FLAG (0x01) - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check the value returned for 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 IO Unit Page 5 */ - -typedef struct _MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS { - U8 ControlFlags; /* 0x00 */ - U8 PortWidthModGroup; /* 0x01 */ - U16 InactivityTimerExponent; /* 0x02 */ - U8 SATAPartialTimeout; /* 0x04 */ - U8 Reserved2; /* 0x05 */ - U8 SATASlumberTimeout; /* 0x06 */ - U8 Reserved3; /* 0x07 */ - U8 SASPartialTimeout; /* 0x08 */ - U8 Reserved4; /* 0x09 */ - U8 SASSlumberTimeout; /* 0x0A */ - U8 Reserved5; /* 0x0B */ -} MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS, - MPI2_POINTER PTR_MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS, - Mpi2SasIOUnit5PhyPmSettings_t, MPI2_POINTER pMpi2SasIOUnit5PhyPmSettings_t; - -/* defines for ControlFlags field */ -#define MPI2_SASIOUNIT5_CONTROL_SAS_SLUMBER_ENABLE (0x08) -#define MPI2_SASIOUNIT5_CONTROL_SAS_PARTIAL_ENABLE (0x04) -#define MPI2_SASIOUNIT5_CONTROL_SATA_SLUMBER_ENABLE (0x02) -#define MPI2_SASIOUNIT5_CONTROL_SATA_PARTIAL_ENABLE (0x01) - -/* defines for PortWidthModeGroup field */ -#define MPI2_SASIOUNIT5_PWMG_DISABLE (0xFF) - -/* defines for InactivityTimerExponent field */ -#define MPI2_SASIOUNIT5_ITE_MASK_SAS_SLUMBER (0x7000) -#define MPI2_SASIOUNIT5_ITE_SHIFT_SAS_SLUMBER (12) -#define MPI2_SASIOUNIT5_ITE_MASK_SAS_PARTIAL (0x0700) -#define MPI2_SASIOUNIT5_ITE_SHIFT_SAS_PARTIAL (8) -#define MPI2_SASIOUNIT5_ITE_MASK_SATA_SLUMBER (0x0070) -#define MPI2_SASIOUNIT5_ITE_SHIFT_SATA_SLUMBER (4) -#define MPI2_SASIOUNIT5_ITE_MASK_SATA_PARTIAL (0x0007) -#define MPI2_SASIOUNIT5_ITE_SHIFT_SATA_PARTIAL (0) - -#define MPI2_SASIOUNIT5_ITE_TEN_SECONDS (7) -#define MPI2_SASIOUNIT5_ITE_ONE_SECOND (6) -#define MPI2_SASIOUNIT5_ITE_HUNDRED_MILLISECONDS (5) -#define MPI2_SASIOUNIT5_ITE_TEN_MILLISECONDS (4) -#define MPI2_SASIOUNIT5_ITE_ONE_MILLISECOND (3) -#define MPI2_SASIOUNIT5_ITE_HUNDRED_MICROSECONDS (2) -#define MPI2_SASIOUNIT5_ITE_TEN_MICROSECONDS (1) -#define MPI2_SASIOUNIT5_ITE_ONE_MICROSECOND (0) - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check the value returned for NumPhys at runtime. - */ -#ifndef MPI2_SAS_IOUNIT5_PHY_MAX -#define MPI2_SAS_IOUNIT5_PHY_MAX (1) -#endif - -typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_5 { - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U8 NumPhys; /* 0x08 */ - U8 Reserved1; /* 0x09 */ - U16 Reserved2; /* 0x0A */ - U32 Reserved3; /* 0x0C */ - MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS SASPhyPowerManagementSettings - [MPI2_SAS_IOUNIT5_PHY_MAX]; /* 0x10 */ -} MPI2_CONFIG_PAGE_SASIOUNIT_5, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_5, - Mpi2SasIOUnitPage5_t, MPI2_POINTER pMpi2SasIOUnitPage5_t; - -#define MPI2_SASIOUNITPAGE5_PAGEVERSION (0x01) - - -/* SAS IO Unit Page 6 */ - -typedef struct _MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS { - U8 CurrentStatus; /* 0x00 */ - U8 CurrentModulation; /* 0x01 */ - U8 CurrentUtilization; /* 0x02 */ - U8 Reserved1; /* 0x03 */ - U32 Reserved2; /* 0x04 */ -} MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS, - MPI2_POINTER PTR_MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS, - Mpi2SasIOUnit6PortWidthModGroupStatus_t, - MPI2_POINTER pMpi2SasIOUnit6PortWidthModGroupStatus_t; - -/* defines for CurrentStatus field */ -#define MPI2_SASIOUNIT6_STATUS_UNAVAILABLE (0x00) -#define MPI2_SASIOUNIT6_STATUS_UNCONFIGURED (0x01) -#define MPI2_SASIOUNIT6_STATUS_INVALID_CONFIG (0x02) -#define MPI2_SASIOUNIT6_STATUS_LINK_DOWN (0x03) -#define MPI2_SASIOUNIT6_STATUS_OBSERVATION_ONLY (0x04) -#define MPI2_SASIOUNIT6_STATUS_INACTIVE (0x05) -#define MPI2_SASIOUNIT6_STATUS_ACTIVE_IOUNIT (0x06) -#define MPI2_SASIOUNIT6_STATUS_ACTIVE_HOST (0x07) - -/* defines for CurrentModulation field */ -#define MPI2_SASIOUNIT6_MODULATION_25_PERCENT (0x00) -#define MPI2_SASIOUNIT6_MODULATION_50_PERCENT (0x01) -#define MPI2_SASIOUNIT6_MODULATION_75_PERCENT (0x02) -#define MPI2_SASIOUNIT6_MODULATION_100_PERCENT (0x03) - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check the value returned for NumGroups at runtime. - */ -#ifndef MPI2_SAS_IOUNIT6_GROUP_MAX -#define MPI2_SAS_IOUNIT6_GROUP_MAX (1) -#endif - -typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_6 { - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U32 Reserved1; /* 0x08 */ - U32 Reserved2; /* 0x0C */ - U8 NumGroups; /* 0x10 */ - U8 Reserved3; /* 0x11 */ - U16 Reserved4; /* 0x12 */ - MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS - PortWidthModulationGroupStatus[MPI2_SAS_IOUNIT6_GROUP_MAX]; /* 0x14 */ -} MPI2_CONFIG_PAGE_SASIOUNIT_6, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_6, - Mpi2SasIOUnitPage6_t, MPI2_POINTER pMpi2SasIOUnitPage6_t; - -#define MPI2_SASIOUNITPAGE6_PAGEVERSION (0x00) - - -/* SAS IO Unit Page 7 */ - -typedef struct _MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS { - U8 Flags; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U16 Reserved2; /* 0x02 */ - U8 Threshold75Pct; /* 0x04 */ - U8 Threshold50Pct; /* 0x05 */ - U8 Threshold25Pct; /* 0x06 */ - U8 Reserved3; /* 0x07 */ -} MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS, - MPI2_POINTER PTR_MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS, - Mpi2SasIOUnit7PortWidthModGroupSettings_t, - MPI2_POINTER pMpi2SasIOUnit7PortWidthModGroupSettings_t; - -/* defines for Flags field */ -#define MPI2_SASIOUNIT7_FLAGS_ENABLE_PORT_WIDTH_MODULATION (0x01) - - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check the value returned for NumGroups at runtime. - */ -#ifndef MPI2_SAS_IOUNIT7_GROUP_MAX -#define MPI2_SAS_IOUNIT7_GROUP_MAX (1) -#endif - -typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_7 { - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U8 SamplingInterval; /* 0x08 */ - U8 WindowLength; /* 0x09 */ - U16 Reserved1; /* 0x0A */ - U32 Reserved2; /* 0x0C */ - U32 Reserved3; /* 0x10 */ - U8 NumGroups; /* 0x14 */ - U8 Reserved4; /* 0x15 */ - U16 Reserved5; /* 0x16 */ - MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS - PortWidthModulationGroupSettings[MPI2_SAS_IOUNIT7_GROUP_MAX]; /* 0x18 */ -} MPI2_CONFIG_PAGE_SASIOUNIT_7, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_7, - Mpi2SasIOUnitPage7_t, MPI2_POINTER pMpi2SasIOUnitPage7_t; - -#define MPI2_SASIOUNITPAGE7_PAGEVERSION (0x00) - - -/* SAS IO Unit Page 8 */ - -typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_8 { - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U32 Reserved1; /* 0x08 */ - U32 PowerManagementCapabilities;/* 0x0C */ - U32 Reserved2; /* 0x10 */ -} MPI2_CONFIG_PAGE_SASIOUNIT_8, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_8, - Mpi2SasIOUnitPage8_t, MPI2_POINTER pMpi2SasIOUnitPage8_t; - -#define MPI2_SASIOUNITPAGE8_PAGEVERSION (0x00) - -/* defines for PowerManagementCapabilities field */ -#define MPI2_SASIOUNIT8_PM_HOST_PORT_WIDTH_MOD (0x00001000) -#define MPI2_SASIOUNIT8_PM_HOST_SAS_SLUMBER_MODE (0x00000800) -#define MPI2_SASIOUNIT8_PM_HOST_SAS_PARTIAL_MODE (0x00000400) -#define MPI2_SASIOUNIT8_PM_HOST_SATA_SLUMBER_MODE (0x00000200) -#define MPI2_SASIOUNIT8_PM_HOST_SATA_PARTIAL_MODE (0x00000100) -#define MPI2_SASIOUNIT8_PM_IOUNIT_PORT_WIDTH_MOD (0x00000010) -#define MPI2_SASIOUNIT8_PM_IOUNIT_SAS_SLUMBER_MODE (0x00000008) -#define MPI2_SASIOUNIT8_PM_IOUNIT_SAS_PARTIAL_MODE (0x00000004) -#define MPI2_SASIOUNIT8_PM_IOUNIT_SATA_SLUMBER_MODE (0x00000002) -#define MPI2_SASIOUNIT8_PM_IOUNIT_SATA_PARTIAL_MODE (0x00000001) - - - -/* SAS IO Unit Page 16 */ - -typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT16 { - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U64 TimeStamp; /* 0x08 */ - U32 Reserved1; /* 0x10 */ - U32 Reserved2; /* 0x14 */ - U32 FastPathPendedRequests; /* 0x18 */ - U32 FastPathUnPendedRequests; /* 0x1C */ - U32 FastPathHostRequestStarts; /* 0x20 */ - U32 FastPathFirmwareRequestStarts; /* 0x24 */ - U32 FastPathHostCompletions; /* 0x28 */ - U32 FastPathFirmwareCompletions; /* 0x2C */ - U32 NonFastPathRequestStarts; /* 0x30 */ - U32 NonFastPathHostCompletions; /* 0x30 */ -} MPI2_CONFIG_PAGE_SASIOUNIT16, -MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT16, -Mpi2SasIOUnitPage16_t, MPI2_POINTER pMpi2SasIOUnitPage16_t; - -#define MPI2_SASIOUNITPAGE16_PAGEVERSION (0x00) - - -/**************************************************************************** -* 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 */ - U8 TimeToReducedFunc; /* 0x38 */ - U8 InitialTimeToReducedFunc; /* 0x39 */ - U8 MaxReducedFuncTime; /* 0x3A */ - U8 Reserved2; /* 0x3B */ -} MPI2_CONFIG_PAGE_EXPANDER_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_EXPANDER_0, - Mpi2ExpanderPage0_t, MPI2_POINTER pMpi2ExpanderPage0_t; - -#define MPI2_SASEXPANDER0_PAGEVERSION (0x06) - -/* 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_REDUCED_FUNCTIONALITY (0x2000) -#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 */ - -/* 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) - -/* use MPI2_SAS_APHYINFO_ defines for AttachedPhyInfo field */ - -/**************************************************************************** -* 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 EnclosureLevel; /* 0x2F */ - U8 ConnectorName[4]; /* 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 (0x09) - -/* 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_UNAUTHORIZED_DEVICE (0x8000) -#define MPI2_SAS_DEVICE0_FLAGS_SLUMBER_PM_CAPABLE (0x1000) -#define MPI2_SAS_DEVICE0_FLAGS_PARTIAL_PM_CAPABLE (0x0800) -#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_ENCL_LEVEL_VALID (0x0002) -#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_APHYINFO_ defines for AttachedPhyInfo field */ - -/* 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_PHYINFO_ for the PhyInfo field */ - -/* use MPI2_SAS_NEG_LINK_RATE_ defines for the NegotiatedLinkRate 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 PHY Page 2 */ - -typedef struct _MPI2_SASPHY2_PHY_EVENT { - U8 PhyEventCode; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U16 Reserved2; /* 0x02 */ - U32 PhyEventInfo; /* 0x04 */ -} MPI2_SASPHY2_PHY_EVENT, MPI2_POINTER PTR_MPI2_SASPHY2_PHY_EVENT, - Mpi2SasPhy2PhyEvent_t, MPI2_POINTER pMpi2SasPhy2PhyEvent_t; - -/* use MPI2_SASPHY3_EVENT_CODE_ for the PhyEventCode field */ - - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check the value returned for NumPhyEvents at runtime. - */ -#ifndef MPI2_SASPHY2_PHY_EVENT_MAX -#define MPI2_SASPHY2_PHY_EVENT_MAX (1) -#endif - -typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_2 { - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U32 Reserved1; /* 0x08 */ - U8 NumPhyEvents; /* 0x0C */ - U8 Reserved2; /* 0x0D */ - U16 Reserved3; /* 0x0E */ - MPI2_SASPHY2_PHY_EVENT PhyEvent[MPI2_SASPHY2_PHY_EVENT_MAX]; - /* 0x10 */ -} MPI2_CONFIG_PAGE_SAS_PHY_2, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_2, - Mpi2SasPhyPage2_t, MPI2_POINTER pMpi2SasPhyPage2_t; - -#define MPI2_SASPHY2_PAGEVERSION (0x00) - - -/* SAS PHY Page 3 */ - -typedef struct _MPI2_SASPHY3_PHY_EVENT_CONFIG { - U8 PhyEventCode; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U16 Reserved2; /* 0x02 */ - U8 CounterType; /* 0x04 */ - U8 ThresholdWindow; /* 0x05 */ - U8 TimeUnits; /* 0x06 */ - U8 Reserved3; /* 0x07 */ - U32 EventThreshold; /* 0x08 */ - U16 ThresholdFlags; /* 0x0C */ - U16 Reserved4; /* 0x0E */ -} MPI2_SASPHY3_PHY_EVENT_CONFIG, MPI2_POINTER PTR_MPI2_SASPHY3_PHY_EVENT_CONFIG, - Mpi2SasPhy3PhyEventConfig_t, MPI2_POINTER pMpi2SasPhy3PhyEventConfig_t; - -/* values for PhyEventCode field */ -#define MPI2_SASPHY3_EVENT_CODE_NO_EVENT (0x00) -#define MPI2_SASPHY3_EVENT_CODE_INVALID_DWORD (0x01) -#define MPI2_SASPHY3_EVENT_CODE_RUNNING_DISPARITY_ERROR (0x02) -#define MPI2_SASPHY3_EVENT_CODE_LOSS_DWORD_SYNC (0x03) -#define MPI2_SASPHY3_EVENT_CODE_PHY_RESET_PROBLEM (0x04) -#define MPI2_SASPHY3_EVENT_CODE_ELASTICITY_BUF_OVERFLOW (0x05) -#define MPI2_SASPHY3_EVENT_CODE_RX_ERROR (0x06) -#define MPI2_SASPHY3_EVENT_CODE_RX_ADDR_FRAME_ERROR (0x20) -#define MPI2_SASPHY3_EVENT_CODE_TX_AC_OPEN_REJECT (0x21) -#define MPI2_SASPHY3_EVENT_CODE_RX_AC_OPEN_REJECT (0x22) -#define MPI2_SASPHY3_EVENT_CODE_TX_RC_OPEN_REJECT (0x23) -#define MPI2_SASPHY3_EVENT_CODE_RX_RC_OPEN_REJECT (0x24) -#define MPI2_SASPHY3_EVENT_CODE_RX_AIP_PARTIAL_WAITING_ON (0x25) -#define MPI2_SASPHY3_EVENT_CODE_RX_AIP_CONNECT_WAITING_ON (0x26) -#define MPI2_SASPHY3_EVENT_CODE_TX_BREAK (0x27) -#define MPI2_SASPHY3_EVENT_CODE_RX_BREAK (0x28) -#define MPI2_SASPHY3_EVENT_CODE_BREAK_TIMEOUT (0x29) -#define MPI2_SASPHY3_EVENT_CODE_CONNECTION (0x2A) -#define MPI2_SASPHY3_EVENT_CODE_PEAKTX_PATHWAY_BLOCKED (0x2B) -#define MPI2_SASPHY3_EVENT_CODE_PEAKTX_ARB_WAIT_TIME (0x2C) -#define MPI2_SASPHY3_EVENT_CODE_PEAK_ARB_WAIT_TIME (0x2D) -#define MPI2_SASPHY3_EVENT_CODE_PEAK_CONNECT_TIME (0x2E) -#define MPI2_SASPHY3_EVENT_CODE_TX_SSP_FRAMES (0x40) -#define MPI2_SASPHY3_EVENT_CODE_RX_SSP_FRAMES (0x41) -#define MPI2_SASPHY3_EVENT_CODE_TX_SSP_ERROR_FRAMES (0x42) -#define MPI2_SASPHY3_EVENT_CODE_RX_SSP_ERROR_FRAMES (0x43) -#define MPI2_SASPHY3_EVENT_CODE_TX_CREDIT_BLOCKED (0x44) -#define MPI2_SASPHY3_EVENT_CODE_RX_CREDIT_BLOCKED (0x45) -#define MPI2_SASPHY3_EVENT_CODE_TX_SATA_FRAMES (0x50) -#define MPI2_SASPHY3_EVENT_CODE_RX_SATA_FRAMES (0x51) -#define MPI2_SASPHY3_EVENT_CODE_SATA_OVERFLOW (0x52) -#define MPI2_SASPHY3_EVENT_CODE_TX_SMP_FRAMES (0x60) -#define MPI2_SASPHY3_EVENT_CODE_RX_SMP_FRAMES (0x61) -#define MPI2_SASPHY3_EVENT_CODE_RX_SMP_ERROR_FRAMES (0x63) -#define MPI2_SASPHY3_EVENT_CODE_HOTPLUG_TIMEOUT (0xD0) -#define MPI2_SASPHY3_EVENT_CODE_MISALIGNED_MUX_PRIMITIVE (0xD1) -#define MPI2_SASPHY3_EVENT_CODE_RX_AIP (0xD2) - -/* values for the CounterType field */ -#define MPI2_SASPHY3_COUNTER_TYPE_WRAPPING (0x00) -#define MPI2_SASPHY3_COUNTER_TYPE_SATURATING (0x01) -#define MPI2_SASPHY3_COUNTER_TYPE_PEAK_VALUE (0x02) - -/* values for the TimeUnits field */ -#define MPI2_SASPHY3_TIME_UNITS_10_MICROSECONDS (0x00) -#define MPI2_SASPHY3_TIME_UNITS_100_MICROSECONDS (0x01) -#define MPI2_SASPHY3_TIME_UNITS_1_MILLISECOND (0x02) -#define MPI2_SASPHY3_TIME_UNITS_10_MILLISECONDS (0x03) - -/* values for the ThresholdFlags field */ -#define MPI2_SASPHY3_TFLAGS_PHY_RESET (0x0002) -#define MPI2_SASPHY3_TFLAGS_EVENT_NOTIFY (0x0001) - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check the value returned for NumPhyEvents at runtime. - */ -#ifndef MPI2_SASPHY3_PHY_EVENT_MAX -#define MPI2_SASPHY3_PHY_EVENT_MAX (1) -#endif - -typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_3 { - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U32 Reserved1; /* 0x08 */ - U8 NumPhyEvents; /* 0x0C */ - U8 Reserved2; /* 0x0D */ - U16 Reserved3; /* 0x0E */ - MPI2_SASPHY3_PHY_EVENT_CONFIG PhyEventConfig - [MPI2_SASPHY3_PHY_EVENT_MAX]; /* 0x10 */ -} MPI2_CONFIG_PAGE_SAS_PHY_3, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_3, - Mpi2SasPhyPage3_t, MPI2_POINTER pMpi2SasPhyPage3_t; - -#define MPI2_SASPHY3_PAGEVERSION (0x00) - - -/* SAS PHY Page 4 */ - -typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_4 { - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U16 Reserved1; /* 0x08 */ - U8 Reserved2; /* 0x0A */ - U8 Flags; /* 0x0B */ - U8 InitialFrame[28]; /* 0x0C */ -} MPI2_CONFIG_PAGE_SAS_PHY_4, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_4, - Mpi2SasPhyPage4_t, MPI2_POINTER pMpi2SasPhyPage4_t; - -#define MPI2_SASPHY4_PAGEVERSION (0x00) - -/* values for the Flags field */ -#define MPI2_SASPHY4_FLAGS_FRAME_VALID (0x02) -#define MPI2_SASPHY4_FLAGS_SATA_FRAME (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 */ - U8 Reserved2; /* 0x1C */ - U8 EnclosureLevel; /* 0x1D */ - 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 (0x04) - -/* values for SAS Enclosure Page 0 Flags field */ -#define MPI2_SAS_ENCLS0_FLAGS_ENCL_LEVEL_VALID (0x0010) -#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 the value returned for NumLogEntries 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 the value returned for NumElements 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) - - -/**************************************************************************** -* Ethernet Config Pages -****************************************************************************/ - -/* Ethernet Page 0 */ - -/* IP address (union of IPv4 and IPv6) */ -typedef union _MPI2_ETHERNET_IP_ADDR { - U32 IPv4Addr; - U32 IPv6Addr[4]; -} MPI2_ETHERNET_IP_ADDR, MPI2_POINTER PTR_MPI2_ETHERNET_IP_ADDR, - Mpi2EthernetIpAddr_t, MPI2_POINTER pMpi2EthernetIpAddr_t; - -#define MPI2_ETHERNET_HOST_NAME_LENGTH (32) - -typedef struct _MPI2_CONFIG_PAGE_ETHERNET_0 { - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U8 NumInterfaces; /* 0x08 */ - U8 Reserved0; /* 0x09 */ - U16 Reserved1; /* 0x0A */ - U32 Status; /* 0x0C */ - U8 MediaState; /* 0x10 */ - U8 Reserved2; /* 0x11 */ - U16 Reserved3; /* 0x12 */ - U8 MacAddress[6]; /* 0x14 */ - U8 Reserved4; /* 0x1A */ - U8 Reserved5; /* 0x1B */ - MPI2_ETHERNET_IP_ADDR IpAddress; /* 0x1C */ - MPI2_ETHERNET_IP_ADDR SubnetMask; /* 0x2C */ - MPI2_ETHERNET_IP_ADDR GatewayIpAddress; /* 0x3C */ - MPI2_ETHERNET_IP_ADDR DNS1IpAddress; /* 0x4C */ - MPI2_ETHERNET_IP_ADDR DNS2IpAddress; /* 0x5C */ - MPI2_ETHERNET_IP_ADDR DhcpIpAddress; /* 0x6C */ - U8 HostName - [MPI2_ETHERNET_HOST_NAME_LENGTH];/* 0x7C */ -} MPI2_CONFIG_PAGE_ETHERNET_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_ETHERNET_0, - Mpi2EthernetPage0_t, MPI2_POINTER pMpi2EthernetPage0_t; - -#define MPI2_ETHERNETPAGE0_PAGEVERSION (0x00) - -/* values for Ethernet Page 0 Status field */ -#define MPI2_ETHPG0_STATUS_IPV6_CAPABLE (0x80000000) -#define MPI2_ETHPG0_STATUS_IPV4_CAPABLE (0x40000000) -#define MPI2_ETHPG0_STATUS_CONSOLE_CONNECTED (0x20000000) -#define MPI2_ETHPG0_STATUS_DEFAULT_IF (0x00000100) -#define MPI2_ETHPG0_STATUS_FW_DWNLD_ENABLED (0x00000080) -#define MPI2_ETHPG0_STATUS_TELNET_ENABLED (0x00000040) -#define MPI2_ETHPG0_STATUS_SSH2_ENABLED (0x00000020) -#define MPI2_ETHPG0_STATUS_DHCP_CLIENT_ENABLED (0x00000010) -#define MPI2_ETHPG0_STATUS_IPV6_ENABLED (0x00000008) -#define MPI2_ETHPG0_STATUS_IPV4_ENABLED (0x00000004) -#define MPI2_ETHPG0_STATUS_IPV6_ADDRESSES (0x00000002) -#define MPI2_ETHPG0_STATUS_ETH_IF_ENABLED (0x00000001) - -/* values for Ethernet Page 0 MediaState field */ -#define MPI2_ETHPG0_MS_DUPLEX_MASK (0x80) -#define MPI2_ETHPG0_MS_HALF_DUPLEX (0x00) -#define MPI2_ETHPG0_MS_FULL_DUPLEX (0x80) - -#define MPI2_ETHPG0_MS_CONNECT_SPEED_MASK (0x07) -#define MPI2_ETHPG0_MS_NOT_CONNECTED (0x00) -#define MPI2_ETHPG0_MS_10MBIT (0x01) -#define MPI2_ETHPG0_MS_100MBIT (0x02) -#define MPI2_ETHPG0_MS_1GBIT (0x03) - - -/* Ethernet Page 1 */ - -typedef struct _MPI2_CONFIG_PAGE_ETHERNET_1 { - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U32 Reserved0; /* 0x08 */ - U32 Flags; /* 0x0C */ - U8 MediaState; /* 0x10 */ - U8 Reserved1; /* 0x11 */ - U16 Reserved2; /* 0x12 */ - U8 MacAddress[6]; /* 0x14 */ - U8 Reserved3; /* 0x1A */ - U8 Reserved4; /* 0x1B */ - MPI2_ETHERNET_IP_ADDR StaticIpAddress; /* 0x1C */ - MPI2_ETHERNET_IP_ADDR StaticSubnetMask; /* 0x2C */ - MPI2_ETHERNET_IP_ADDR StaticGatewayIpAddress; /* 0x3C */ - MPI2_ETHERNET_IP_ADDR StaticDNS1IpAddress; /* 0x4C */ - MPI2_ETHERNET_IP_ADDR StaticDNS2IpAddress; /* 0x5C */ - U32 Reserved5; /* 0x6C */ - U32 Reserved6; /* 0x70 */ - U32 Reserved7; /* 0x74 */ - U32 Reserved8; /* 0x78 */ - U8 HostName - [MPI2_ETHERNET_HOST_NAME_LENGTH];/* 0x7C */ -} MPI2_CONFIG_PAGE_ETHERNET_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_ETHERNET_1, - Mpi2EthernetPage1_t, MPI2_POINTER pMpi2EthernetPage1_t; - -#define MPI2_ETHERNETPAGE1_PAGEVERSION (0x00) - -/* values for Ethernet Page 1 Flags field */ -#define MPI2_ETHPG1_FLAG_SET_DEFAULT_IF (0x00000100) -#define MPI2_ETHPG1_FLAG_ENABLE_FW_DOWNLOAD (0x00000080) -#define MPI2_ETHPG1_FLAG_ENABLE_TELNET (0x00000040) -#define MPI2_ETHPG1_FLAG_ENABLE_SSH2 (0x00000020) -#define MPI2_ETHPG1_FLAG_ENABLE_DHCP_CLIENT (0x00000010) -#define MPI2_ETHPG1_FLAG_ENABLE_IPV6 (0x00000008) -#define MPI2_ETHPG1_FLAG_ENABLE_IPV4 (0x00000004) -#define MPI2_ETHPG1_FLAG_USE_IPV6_ADDRESSES (0x00000002) -#define MPI2_ETHPG1_FLAG_ENABLE_ETH_IF (0x00000001) - -/* values for Ethernet Page 1 MediaState field */ -#define MPI2_ETHPG1_MS_DUPLEX_MASK (0x80) -#define MPI2_ETHPG1_MS_HALF_DUPLEX (0x00) -#define MPI2_ETHPG1_MS_FULL_DUPLEX (0x80) - -#define MPI2_ETHPG1_MS_DATA_RATE_MASK (0x07) -#define MPI2_ETHPG1_MS_DATA_RATE_AUTO (0x00) -#define MPI2_ETHPG1_MS_DATA_RATE_10MBIT (0x01) -#define MPI2_ETHPG1_MS_DATA_RATE_100MBIT (0x02) -#define MPI2_ETHPG1_MS_DATA_RATE_1GBIT (0x03) - - -/**************************************************************************** -* Extended Manufacturing Config Pages -****************************************************************************/ - -/* - * Generic structure to use for product-specific extended manufacturing pages - * (currently Extended Manufacturing Page 40 through Extended Manufacturing - * Page 60). - */ - -typedef struct _MPI2_CONFIG_PAGE_EXT_MAN_PS { - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U32 ProductSpecificInfo; /* 0x08 */ -} MPI2_CONFIG_PAGE_EXT_MAN_PS, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_EXT_MAN_PS, - Mpi2ExtManufacturingPagePS_t, - MPI2_POINTER pMpi2ExtManufacturingPagePS_t; - -/* PageVersion should be provided by product-specific code */ - -#endif - diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_init.h b/drivers/scsi/mpt2sas/mpi/mpi2_init.h deleted file mode 100644 index eea1a16b13ec..000000000000 --- a/drivers/scsi/mpt2sas/mpi/mpi2_init.h +++ /dev/null @@ -1,461 +0,0 @@ -/* - * Copyright (c) 2000-2014 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.15 - * - * 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 because they are - * common to many structures. - * 05-06-09 02.00.07 Changed task management type of Query Unit Attention to - * Query Asynchronous Event. - * Defined two new bits in the SlotStatus field of the SCSI - * Enclosure Processor Request and Reply. - * 10-28-09 02.00.08 Added defines for decoding the ResponseInfo bytes for - * both SCSI IO Error Reply and SCSI Task Management Reply. - * Added ResponseInfo field to MPI2_SCSI_TASK_MANAGE_REPLY. - * Added MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG define. - * 02-10-10 02.00.09 Removed unused structure that had "#if 0" around it. - * 05-12-10 02.00.10 Added optional vendor-unique region to SCSI IO Request. - * 11-10-10 02.00.11 Added MPI2_SCSIIO_NUM_SGLOFFSETS define. - * 02-06-12 02.00.13 Added alternate defines for Task Priority / Command - * Priority to match SAM-4. - * 07-10-12 02.00.14 Added MPI2_SCSIIO_CONTROL_SHIFT_DATADIRECTION. - * 04-09-13 02.00.15 Added SCSIStatusQualifier field to MPI2_SCSI_IO_REPLY, - * replacing the Reserved4 field. - * -------------------------------------------------------------------------- - */ - -#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; - -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 */ - -#ifdef MPI2_SCSI_IO_VENDOR_UNIQUE_REGION /* typically this is left undefined */ - MPI2_SCSI_IO_VENDOR_UNIQUE VendorRegion; -#endif - - 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) - -/* number of SGLOffset fields */ -#define MPI2_SCSIIO_NUM_SGLOFFSETS (4) - -/* 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_SHIFT_DATADIRECTION (24) -#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) -/* alternate name for the previous field; called Command Priority in SAM-4 */ -#define MPI2_SCSIIO_CONTROL_CMDPRI_MASK (0x00007800) -#define MPI2_SCSIIO_CONTROL_CMDPRI_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 SCSIStatusQualifier; /* 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) - -/* masks and shifts for the ResponseInfo field */ - -#define MPI2_SCSI_RI_MASK_REASONCODE (0x000000FF) -#define MPI2_SCSI_RI_SHIFT_REASONCODE (0) - -#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_ASYNC_EVENT (0x0A) - -/* obsolete TaskType name */ -#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_UNIT_ATTENTION \ - (MPI2_SCSITASKMGMT_TASKTYPE_QRY_ASYNC_EVENT) - -/* 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 */ - U32 ResponseInfo; /* 0x18 */ -} 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_TM_OVERLAPPED_TAG (0x0A) -#define MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC (0x80) - -/* masks and shifts for the ResponseInfo field */ - -#define MPI2_SCSITASKMGMT_RI_MASK_REASONCODE (0x000000FF) -#define MPI2_SCSITASKMGMT_RI_SHIFT_REASONCODE (0) -#define MPI2_SCSITASKMGMT_RI_MASK_ARI2 (0x0000FF00) -#define MPI2_SCSITASKMGMT_RI_SHIFT_ARI2 (8) -#define MPI2_SCSITASKMGMT_RI_MASK_ARI1 (0x00FF0000) -#define MPI2_SCSITASKMGMT_RI_SHIFT_ARI1 (16) -#define MPI2_SCSITASKMGMT_RI_MASK_ARI0 (0xFF000000) -#define MPI2_SCSITASKMGMT_RI_SHIFT_ARI0 (24) - - -/**************************************************************************** -* 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_IN_CRITICAL_ARRAY (0x00000010) -#define MPI2_SEP_REQ_SLOTSTATUS_IN_FAILED_ARRAY (0x00000008) -#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_IN_CRITICAL_ARRAY (0x00000010) -#define MPI2_SEP_REPLY_SLOTSTATUS_IN_FAILED_ARRAY (0x00000008) -#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 deleted file mode 100644 index b02de48be204..000000000000 --- a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h +++ /dev/null @@ -1,1708 +0,0 @@ -/* - * Copyright (c) 2000-2014 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.24 - * - * 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. - * 05-06-09 02.00.11 Added MPI2_IOCFACTS_CAPABILITY_RAID_ACCELERATOR define. - * Added MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX define. - * Added two new reason codes for SAS Device Status Change - * Event. - * Added new event: SAS PHY Counter. - * 07-30-09 02.00.12 Added GPIO Interrupt event define and structure. - * Added MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER define. - * Added new product id family for 2208. - * 10-28-09 02.00.13 Added HostMSIxVectors field to MPI2_IOC_INIT_REQUEST. - * Added MaxMSIxVectors field to MPI2_IOC_FACTS_REPLY. - * Added MinDevHandle field to MPI2_IOC_FACTS_REPLY. - * Added MPI2_IOCFACTS_CAPABILITY_HOST_BASED_DISCOVERY. - * Added MPI2_EVENT_HOST_BASED_DISCOVERY_PHY define. - * Added MPI2_EVENT_SAS_TOPO_ES_NO_EXPANDER define. - * Added Host Based Discovery Phy Event data. - * Added defines for ProductID Product field - * (MPI2_FW_HEADER_PID_). - * Modified values for SAS ProductID Family - * (MPI2_FW_HEADER_PID_FAMILY_). - * 02-10-10 02.00.14 Added SAS Quiesce Event structure and defines. - * Added PowerManagementControl Request structures and - * defines. - * 05-12-10 02.00.15 Marked Task Set Full Event as obsolete. - * Added MPI2_EVENT_SAS_TOPO_LR_UNSUPPORTED_PHY define. - * 11-10-10 02.00.16 Added MPI2_FW_DOWNLOAD_ITYPE_MIN_PRODUCT_SPECIFIC. - * 02-23-11 02.00.17 Added SAS NOTIFY Primitive event, and added - * SASNotifyPrimitiveMasks field to - * MPI2_EVENT_NOTIFICATION_REQUEST. - * Added Temperature Threshold Event. - * Added Host Message Event. - * Added Send Host Message request and reply. - * 05-25-11 02.00.18 For Extended Image Header, added - * MPI2_EXT_IMAGE_TYPE_MIN_PRODUCT_SPECIFIC and - * MPI2_EXT_IMAGE_TYPE_MAX_PRODUCT_SPECIFIC defines. - * Deprecated MPI2_EXT_IMAGE_TYPE_MAX define. - * 08-24-11 02.00.19 Added PhysicalPort field to - * MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE structure. - * Marked MPI2_PM_CONTROL_FEATURE_PCIE_LINK as obsolete. - * 03-29-12 02.00.21 Added a product specific range to event values. - * 07-26-12 02.00.22 Added MPI2_IOCFACTS_EXCEPT_PARTIAL_MEMORY_FAILURE. - * Added ElapsedSeconds field to - * MPI2_EVENT_DATA_IR_OPERATION_STATUS. - * 08-19-13 02.00.23 For IOCInit, added MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE - * and MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY. - * Added MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE. - * Added MPI2_FW_DOWNLOAD_ITYPE_PUBLIC_KEY. - * Added Encrypted Hash Extended Image. - * 12-05-13 02.00.24 Added MPI25_HASH_IMAGE_TYPE_BIOS. - * -------------------------------------------------------------------------- - */ - -#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 */ - U16 Reserved6; /* 0x14 */ - U8 Reserved7; /* 0x16 */ - U8 HostMSIxVectors; /* 0x17 */ - U16 Reserved8; /* 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) - -/* MsgFlags */ -#define MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE (0x01) - -/* 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 a Reply Descriptor Post Queue */ -#define MPI2_RDPQ_DEPTH_MIN (16) - -/* Reply Descriptor Post Queue Array Entry */ -typedef struct _MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY { - U64 RDPQBaseAddress; /* 0x00 */ - U32 Reserved1; /* 0x08 */ - U32 Reserved2; /* 0x0C */ -} MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY, -MPI2_POINTER PTR_MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY, -Mpi2IOCInitRDPQArrayEntry, MPI2_POINTER pMpi2IOCInitRDPQArrayEntry; - -/* 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 MaxMSIxVectors; /* 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 */ - U16 MinDevHandle; /* 0x3C */ - U16 Reserved4; /* 0x3E */ -} 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_PARTIAL_MEMORY_FAILURE (0x0200) -#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_RDPQ_ARRAY_CAPABLE (0x00040000) -#define MPI2_IOCFACTS_CAPABILITY_HOST_BASED_DISCOVERY (0x00010000) -#define MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX (0x00008000) -#define MPI2_IOCFACTS_CAPABILITY_RAID_ACCELERATOR (0x00004000) -#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_EXTENDED_BUFFER (0x00000020) -#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 SASNotifyPrimitiveMasks; /* 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) /* obsolete */ -#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) -#define MPI2_EVENT_SAS_PHY_COUNTER (0x0022) -#define MPI2_EVENT_GPIO_INTERRUPT (0x0023) -#define MPI2_EVENT_HOST_BASED_DISCOVERY_PHY (0x0024) -#define MPI2_EVENT_SAS_QUIESCE (0x0025) -#define MPI2_EVENT_SAS_NOTIFY_PRIMITIVE (0x0026) -#define MPI2_EVENT_TEMP_THRESHOLD (0x0027) -#define MPI2_EVENT_HOST_MESSAGE (0x0028) -#define MPI2_EVENT_MIN_PRODUCT_SPECIFIC (0x006E) -#define MPI2_EVENT_MAX_PRODUCT_SPECIFIC (0x007F) - -/* 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; - -/* GPIO Interrupt Event data */ - -typedef struct _MPI2_EVENT_DATA_GPIO_INTERRUPT { - U8 GPIONum; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U16 Reserved2; /* 0x02 */ -} MPI2_EVENT_DATA_GPIO_INTERRUPT, - MPI2_POINTER PTR_MPI2_EVENT_DATA_GPIO_INTERRUPT, - Mpi2EventDataGpioInterrupt_t, MPI2_POINTER pMpi2EventDataGpioInterrupt_t; - -/* Temperature Threshold Event data */ - -typedef struct _MPI2_EVENT_DATA_TEMPERATURE { - U16 Status; /* 0x00 */ - U8 SensorNum; /* 0x02 */ - U8 Reserved1; /* 0x03 */ - U16 CurrentTemperature; /* 0x04 */ - U16 Reserved2; /* 0x06 */ - U32 Reserved3; /* 0x08 */ - U32 Reserved4; /* 0x0C */ -} MPI2_EVENT_DATA_TEMPERATURE, -MPI2_POINTER PTR_MPI2_EVENT_DATA_TEMPERATURE, -Mpi2EventDataTemperature_t, MPI2_POINTER pMpi2EventDataTemperature_t; - -/* Temperature Threshold Event data Status bits */ -#define MPI2_EVENT_TEMPERATURE3_EXCEEDED (0x0008) -#define MPI2_EVENT_TEMPERATURE2_EXCEEDED (0x0004) -#define MPI2_EVENT_TEMPERATURE1_EXCEEDED (0x0002) -#define MPI2_EVENT_TEMPERATURE0_EXCEEDED (0x0001) - - -/* Host Message Event data */ - -typedef struct _MPI2_EVENT_DATA_HOST_MESSAGE { - U8 SourceVF_ID; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U16 Reserved2; /* 0x02 */ - U32 Reserved3; /* 0x04 */ - U32 HostData[1]; /* 0x08 */ -} MPI2_EVENT_DATA_HOST_MESSAGE, MPI2_POINTER PTR_MPI2_EVENT_DATA_HOST_MESSAGE, -Mpi2EventDataHostMessage_t, MPI2_POINTER pMpi2EventDataHostMessage_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 */ -/* this event is obsolete */ - -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 PhysicalPort; /* 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) -#define MPI2_EVENT_SAS_DEV_STAT_RC_EXPANDER_REDUCED_FUNCTIONALITY (0x11) -#define MPI2_EVENT_SAS_DEV_STAT_RC_CMP_EXPANDER_REDUCED_FUNCTIONALITY (0x12) - - -/* 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 ElapsedSeconds; /* 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 Notify Primitive Event data */ - -typedef struct _MPI2_EVENT_DATA_SAS_NOTIFY_PRIMITIVE { - U8 PhyNum; /* 0x00 */ - U8 Port; /* 0x01 */ - U8 Reserved1; /* 0x02 */ - U8 Primitive; /* 0x03 */ -} MPI2_EVENT_DATA_SAS_NOTIFY_PRIMITIVE, -MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_NOTIFY_PRIMITIVE, -Mpi2EventDataSasNotifyPrimitive_t, -MPI2_POINTER pMpi2EventDataSasNotifyPrimitive_t; - -/* defines for the Primitive field */ -#define MPI2_EVENT_NOTIFY_ENABLE_SPINUP (0x01) -#define MPI2_EVENT_NOTIFY_POWER_LOSS_EXPECTED (0x02) -#define MPI2_EVENT_NOTIFY_RESERVED1 (0x03) -#define MPI2_EVENT_NOTIFY_RESERVED2 (0x04) - - -/* 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_NO_EXPANDER (0x00) -#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_UNSUPPORTED_PHY (0x06) -#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) - - -/* SAS PHY Counter Event data */ - -typedef struct _MPI2_EVENT_DATA_SAS_PHY_COUNTER { - U64 TimeStamp; /* 0x00 */ - U32 Reserved1; /* 0x08 */ - U8 PhyEventCode; /* 0x0C */ - U8 PhyNum; /* 0x0D */ - U16 Reserved2; /* 0x0E */ - U32 PhyEventInfo; /* 0x10 */ - U8 CounterType; /* 0x14 */ - U8 ThresholdWindow; /* 0x15 */ - U8 TimeUnits; /* 0x16 */ - U8 Reserved3; /* 0x17 */ - U32 EventThreshold; /* 0x18 */ - U16 ThresholdFlags; /* 0x1C */ - U16 Reserved4; /* 0x1E */ -} MPI2_EVENT_DATA_SAS_PHY_COUNTER, - MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_PHY_COUNTER, - Mpi2EventDataSasPhyCounter_t, MPI2_POINTER pMpi2EventDataSasPhyCounter_t; - -/* use MPI2_SASPHY3_EVENT_CODE_ values from mpi2_cnfg.h for the - * PhyEventCode field - * use MPI2_SASPHY3_COUNTER_TYPE_ values from mpi2_cnfg.h for the - * CounterType field - * use MPI2_SASPHY3_TIME_UNITS_ values from mpi2_cnfg.h for the - * TimeUnits field - * use MPI2_SASPHY3_TFLAGS_ values from mpi2_cnfg.h for the - * ThresholdFlags field - * */ - - -/* SAS Quiesce Event data */ - -typedef struct _MPI2_EVENT_DATA_SAS_QUIESCE { - U8 ReasonCode; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U16 Reserved2; /* 0x02 */ - U32 Reserved3; /* 0x04 */ -} MPI2_EVENT_DATA_SAS_QUIESCE, - MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_QUIESCE, - Mpi2EventDataSasQuiesce_t, MPI2_POINTER pMpi2EventDataSasQuiesce_t; - -/* SAS Quiesce Event data ReasonCode values */ -#define MPI2_EVENT_SAS_QUIESCE_RC_STARTED (0x01) -#define MPI2_EVENT_SAS_QUIESCE_RC_COMPLETED (0x02) - - -/* Host Based Discovery Phy Event data */ - -typedef struct _MPI2_EVENT_HBD_PHY_SAS { - U8 Flags; /* 0x00 */ - U8 NegotiatedLinkRate; /* 0x01 */ - U8 PhyNum; /* 0x02 */ - U8 PhysicalPort; /* 0x03 */ - U32 Reserved1; /* 0x04 */ - U8 InitialFrame[28]; /* 0x08 */ -} MPI2_EVENT_HBD_PHY_SAS, MPI2_POINTER PTR_MPI2_EVENT_HBD_PHY_SAS, - Mpi2EventHbdPhySas_t, MPI2_POINTER pMpi2EventHbdPhySas_t; - -/* values for the Flags field */ -#define MPI2_EVENT_HBD_SAS_FLAGS_FRAME_VALID (0x02) -#define MPI2_EVENT_HBD_SAS_FLAGS_SATA_FRAME (0x01) - -/* use MPI2_SAS_NEG_LINK_RATE_ defines from mpi2_cnfg.h for - * the NegotiatedLinkRate field */ - -typedef union _MPI2_EVENT_HBD_DESCRIPTOR { - MPI2_EVENT_HBD_PHY_SAS Sas; -} MPI2_EVENT_HBD_DESCRIPTOR, MPI2_POINTER PTR_MPI2_EVENT_HBD_DESCRIPTOR, - Mpi2EventHbdDescriptor_t, MPI2_POINTER pMpi2EventHbdDescriptor_t; - -typedef struct _MPI2_EVENT_DATA_HBD_PHY { - U8 DescriptorType; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U16 Reserved2; /* 0x02 */ - U32 Reserved3; /* 0x04 */ - MPI2_EVENT_HBD_DESCRIPTOR Descriptor; /* 0x08 */ -} MPI2_EVENT_DATA_HBD_PHY, MPI2_POINTER PTR_MPI2_EVENT_DATA_HBD_PHY, - Mpi2EventDataHbdPhy_t, MPI2_POINTER pMpi2EventDataMpi2EventDataHbdPhy_t; - -/* values for the DescriptorType field */ -#define MPI2_EVENT_HBD_DT_SAS (0x01) - - - -/**************************************************************************** -* 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; - - -/**************************************************************************** -* SendHostMessage message -****************************************************************************/ - -/* SendHostMessage Request message */ -typedef struct _MPI2_SEND_HOST_MESSAGE_REQUEST { - U16 HostDataLength; /* 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 */ - U8 Reserved4; /* 0x0C */ - U8 DestVF_ID; /* 0x0D */ - U16 Reserved5; /* 0x0E */ - U32 Reserved6; /* 0x10 */ - U32 Reserved7; /* 0x14 */ - U32 Reserved8; /* 0x18 */ - U32 Reserved9; /* 0x1C */ - U32 Reserved10; /* 0x20 */ - U32 HostData[1]; /* 0x24 */ -} MPI2_SEND_HOST_MESSAGE_REQUEST, -MPI2_POINTER PTR_MPI2_SEND_HOST_MESSAGE_REQUEST, -Mpi2SendHostMessageRequest_t, MPI2_POINTER pMpi2SendHostMessageRequest_t; - - -/* SendHostMessage Reply message */ -typedef struct _MPI2_SEND_HOST_MESSAGE_REPLY { - U16 HostDataLength; /* 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 */ - U16 Reserved4; /* 0x0C */ - U16 IOCStatus; /* 0x0E */ - U32 IOCLogInfo; /* 0x10 */ -} MPI2_SEND_HOST_MESSAGE_REPLY, MPI2_POINTER PTR_MPI2_SEND_HOST_MESSAGE_REPLY, -Mpi2SendHostMessageReply_t, MPI2_POINTER pMpi2SendHostMessageReply_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_COMPLETE (0x0A) -#define MPI2_FW_DOWNLOAD_ITYPE_COMMON_BOOT_BLOCK (0x0B) -#define MPI2_FW_DOWNLOAD_ITYPE_PUBLIC_KEY (0x0C) -#define MPI2_FW_DOWNLOAD_ITYPE_MIN_PRODUCT_SPECIFIC (0xF0) - -/* 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_PROD_TARGET_INITIATOR_SCSI (0x0200) -#define MPI2_FW_HEADER_PID_PROD_IR_SCSI (0x0700) - - -#define MPI2_FW_HEADER_PID_FAMILY_MASK (0x00FF) -/* SAS */ -#define MPI2_FW_HEADER_PID_FAMILY_2108_SAS (0x0013) -#define MPI2_FW_HEADER_PID_FAMILY_2208_SAS (0x0014) - -/* 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_ENCRYPTED_HASH (0x09) -#define MPI2_EXT_IMAGE_TYPE_MIN_PRODUCT_SPECIFIC (0x80) -#define MPI2_EXT_IMAGE_TYPE_MAX_PRODUCT_SPECIFIC (0xFF) -#define MPI2_EXT_IMAGE_TYPE_MAX \ - (MPI2_EXT_IMAGE_TYPE_MAX_PRODUCT_SPECIFIC) /* deprecated */ - - - -/* 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) - - -/* Encrypted Hash Extended Image Data */ - -typedef struct _MPI25_ENCRYPTED_HASH_ENTRY { - U8 HashImageType; /* 0x00 */ - U8 HashAlgorithm; /* 0x01 */ - U8 EncryptionAlgorithm; /* 0x02 */ - U8 Reserved1; /* 0x03 */ - U32 Reserved2; /* 0x04 */ - U32 EncryptedHash[1]; /* 0x08 */ -} MPI25_ENCRYPTED_HASH_ENTRY, MPI2_POINTER PTR_MPI25_ENCRYPTED_HASH_ENTRY, -Mpi25EncryptedHashEntry_t, MPI2_POINTER pMpi25EncryptedHashEntry_t; - -/* values for HashImageType */ -#define MPI25_HASH_IMAGE_TYPE_UNUSED (0x00) -#define MPI25_HASH_IMAGE_TYPE_FIRMWARE (0x01) -#define MPI25_HASH_IMAGE_TYPE_BIOS (0x02) - -/* values for HashAlgorithm */ -#define MPI25_HASH_ALGORITHM_UNUSED (0x00) -#define MPI25_HASH_ALGORITHM_SHA256 (0x01) - -/* values for EncryptionAlgorithm */ -#define MPI25_ENCRYPTION_ALG_UNUSED (0x00) -#define MPI25_ENCRYPTION_ALG_RSA256 (0x01) - -typedef struct _MPI25_ENCRYPTED_HASH_DATA { - U8 ImageVersion; /* 0x00 */ - U8 NumHash; /* 0x01 */ - U16 Reserved1; /* 0x02 */ - U32 Reserved2; /* 0x04 */ - MPI25_ENCRYPTED_HASH_ENTRY EncryptedHashEntry[1]; /* 0x08 */ -} MPI25_ENCRYPTED_HASH_DATA, MPI2_POINTER PTR_MPI25_ENCRYPTED_HASH_DATA, -Mpi25EncryptedHashData_t, MPI2_POINTER pMpi25EncryptedHashData_t; - -/**************************************************************************** -* PowerManagementControl message -****************************************************************************/ - -/* PowerManagementControl Request message */ -typedef struct _MPI2_PWR_MGMT_CONTROL_REQUEST { - U8 Feature; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ - U8 Parameter1; /* 0x0C */ - U8 Parameter2; /* 0x0D */ - U8 Parameter3; /* 0x0E */ - U8 Parameter4; /* 0x0F */ - U32 Reserved5; /* 0x10 */ - U32 Reserved6; /* 0x14 */ -} MPI2_PWR_MGMT_CONTROL_REQUEST, MPI2_POINTER PTR_MPI2_PWR_MGMT_CONTROL_REQUEST, - Mpi2PwrMgmtControlRequest_t, MPI2_POINTER pMpi2PwrMgmtControlRequest_t; - -/* defines for the Feature field */ -#define MPI2_PM_CONTROL_FEATURE_DA_PHY_POWER_COND (0x01) -#define MPI2_PM_CONTROL_FEATURE_PORT_WIDTH_MODULATION (0x02) -#define MPI2_PM_CONTROL_FEATURE_PCIE_LINK (0x03) /* obsolete */ -#define MPI2_PM_CONTROL_FEATURE_IOC_SPEED (0x04) -#define MPI2_PM_CONTROL_FEATURE_MIN_PRODUCT_SPECIFIC (0x80) -#define MPI2_PM_CONTROL_FEATURE_MAX_PRODUCT_SPECIFIC (0xFF) - -/* parameter usage for the MPI2_PM_CONTROL_FEATURE_DA_PHY_POWER_COND Feature */ -/* Parameter1 contains a PHY number */ -/* Parameter2 indicates power condition action using these defines */ -#define MPI2_PM_CONTROL_PARAM2_PARTIAL (0x01) -#define MPI2_PM_CONTROL_PARAM2_SLUMBER (0x02) -#define MPI2_PM_CONTROL_PARAM2_EXIT_PWR_MGMT (0x03) -/* Parameter3 and Parameter4 are reserved */ - -/* parameter usage for the MPI2_PM_CONTROL_FEATURE_PORT_WIDTH_MODULATION - * Feature */ -/* Parameter1 contains SAS port width modulation group number */ -/* Parameter2 indicates IOC action using these defines */ -#define MPI2_PM_CONTROL_PARAM2_REQUEST_OWNERSHIP (0x01) -#define MPI2_PM_CONTROL_PARAM2_CHANGE_MODULATION (0x02) -#define MPI2_PM_CONTROL_PARAM2_RELINQUISH_OWNERSHIP (0x03) -/* Parameter3 indicates desired modulation level using these defines */ -#define MPI2_PM_CONTROL_PARAM3_25_PERCENT (0x00) -#define MPI2_PM_CONTROL_PARAM3_50_PERCENT (0x01) -#define MPI2_PM_CONTROL_PARAM3_75_PERCENT (0x02) -#define MPI2_PM_CONTROL_PARAM3_100_PERCENT (0x03) -/* Parameter4 is reserved */ - -/* parameter usage for the MPI2_PM_CONTROL_FEATURE_PCIE_LINK Feature */ -/* Parameter1 indicates desired PCIe link speed using these defines */ -#define MPI2_PM_CONTROL_PARAM1_PCIE_2_5_GBPS (0x00) /* obsolete */ -#define MPI2_PM_CONTROL_PARAM1_PCIE_5_0_GBPS (0x01) /* obsolete */ -#define MPI2_PM_CONTROL_PARAM1_PCIE_8_0_GBPS (0x02) /* obsolete */ -/* Parameter2 indicates desired PCIe link width using these defines */ -#define MPI2_PM_CONTROL_PARAM2_WIDTH_X1 (0x01) /* obsolete */ -#define MPI2_PM_CONTROL_PARAM2_WIDTH_X2 (0x02) /* obsolete */ -#define MPI2_PM_CONTROL_PARAM2_WIDTH_X4 (0x04) /* obsolete */ -#define MPI2_PM_CONTROL_PARAM2_WIDTH_X8 (0x08) /* obsolete */ -/* Parameter3 and Parameter4 are reserved */ - -/* parameter usage for the MPI2_PM_CONTROL_FEATURE_IOC_SPEED Feature */ -/* Parameter1 indicates desired IOC hardware clock speed using these defines */ -#define MPI2_PM_CONTROL_PARAM1_FULL_IOC_SPEED (0x01) -#define MPI2_PM_CONTROL_PARAM1_HALF_IOC_SPEED (0x02) -#define MPI2_PM_CONTROL_PARAM1_QUARTER_IOC_SPEED (0x04) -#define MPI2_PM_CONTROL_PARAM1_EIGHTH_IOC_SPEED (0x08) -/* Parameter2, Parameter3, and Parameter4 are reserved */ - - -/* PowerManagementControl Reply message */ -typedef struct _MPI2_PWR_MGMT_CONTROL_REPLY { - U8 Feature; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 MsgLength; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ - U16 Reserved5; /* 0x0C */ - U16 IOCStatus; /* 0x0E */ - U32 IOCLogInfo; /* 0x10 */ -} MPI2_PWR_MGMT_CONTROL_REPLY, MPI2_POINTER PTR_MPI2_PWR_MGMT_CONTROL_REPLY, - Mpi2PwrMgmtControlReply_t, MPI2_POINTER pMpi2PwrMgmtControlReply_t; - - -#endif - diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_raid.h b/drivers/scsi/mpt2sas/mpi/mpi2_raid.h deleted file mode 100644 index 7efa58ff0d34..000000000000 --- a/drivers/scsi/mpt2sas/mpi/mpi2_raid.h +++ /dev/null @@ -1,366 +0,0 @@ -/* - * Copyright (c) 2000-2014 LSI Corporation. - * - * - * Name: mpi2_raid.h - * Title: MPI Integrated RAID messages and structures - * Creation Date: April 26, 2007 - * - * mpi2_raid.h Version: 02.00.10 - * - * 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. - * 07-30-09 02.00.04 Added proper define for the Use Default Settings bit of - * VolumeCreationFlags and marked the old one as obsolete. - * 05-12-10 02.00.05 Added MPI2_RAID_VOL_FLAGS_OP_MDC define. - * 08-24-10 02.00.06 Added MPI2_RAID_ACTION_COMPATIBILITY_CHECK along with - * related structures and defines. - * Added product-specific range to RAID Action values. - * 02-06-12 02.00.08 Added MPI2_RAID_ACTION_PHYSDISK_HIDDEN. - * 07-26-12 02.00.09 Added ElapsedSeconds field to MPI2_RAID_VOL_INDICATOR. - * Added MPI2_RAID_VOL_FLAGS_ELAPSED_SECONDS_VALID define. - * 04-17-13 02.00.10 Added MPI25_RAID_ACTION_ADATA_ALLOW_PI. - * -------------------------------------------------------------------------- - */ - -#ifndef MPI2_RAID_H -#define MPI2_RAID_H - -/***************************************************************************** -* -* Integrated RAID Messages -* -*****************************************************************************/ - -/**************************************************************************** -* RAID Action messages -****************************************************************************/ - -/* ActionDataWord defines for use with MPI2_RAID_ACTION_CREATE_VOLUME action */ -#define MPI25_RAID_ACTION_ADATA_ALLOW_PI (0x80000000) - -/* 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) -#define MPI2_RAID_ACTION_COMPATIBILITY_CHECK (0x23) -#define MPI2_RAID_ACTION_PHYSDISK_HIDDEN (0x24) -#define MPI2_RAID_ACTION_MIN_PRODUCT_SPECIFIC (0x80) -#define MPI2_RAID_ACTION_MAX_PRODUCT_SPECIFIC (0xFF) - -/* 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_DEFAULT_SETTINGS (0x80000000) -#define MPI2_RAID_VOL_CREATION_BACKGROUND_INIT (0x00000004) -#define MPI2_RAID_VOL_CREATION_LOW_LEVEL_INIT (0x00000002) -#define MPI2_RAID_VOL_CREATION_MIGRATE_DATA (0x00000001) -/* The following is an obsolete define. - * It must be shifted left 24 bits in order to set the proper bit. - */ -#define MPI2_RAID_VOL_CREATION_USE_DEFAULT_SETTINGS (0x80) - - -/* 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 Compatibility Input Structure */ - -typedef struct _MPI2_RAID_COMPATIBILITY_INPUT_STRUCT { - U16 SourceDevHandle; /* 0x00 */ - U16 CandidateDevHandle; /* 0x02 */ - U32 Flags; /* 0x04 */ - U32 Reserved1; /* 0x08 */ - U32 Reserved2; /* 0x0C */ -} MPI2_RAID_COMPATIBILITY_INPUT_STRUCT, -MPI2_POINTER PTR_MPI2_RAID_COMPATIBILITY_INPUT_STRUCT, -Mpi2RaidCompatibilityInputStruct_t, -MPI2_POINTER pMpi2RaidCompatibilityInputStruct_t; - -/* defines for RAID Compatibility Structure Flags field */ -#define MPI2_RAID_COMPAT_SOURCE_IS_VOLUME_FLAG (0x00000002) -#define MPI2_RAID_COMPAT_REPORT_SOURCE_INFO_FLAG (0x00000001) - - -/* RAID Volume Indicator Structure */ - -typedef struct _MPI2_RAID_VOL_INDICATOR -{ - U64 TotalBlocks; /* 0x00 */ - U64 BlocksRemaining; /* 0x08 */ - U32 Flags; /* 0x10 */ - U32 ElapsedSeconds; /* 0x14 */ -} 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_ELAPSED_SECONDS_VALID (0x80000000) - -#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) -#define MPI2_RAID_VOL_FLAGS_OP_MDC (0x00000004) - -/* RAID Compatibility Result Structure */ - -typedef struct _MPI2_RAID_COMPATIBILITY_RESULT_STRUCT { - U8 State; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U16 Reserved2; /* 0x02 */ - U32 GenericAttributes; /* 0x04 */ - U32 OEMSpecificAttributes; /* 0x08 */ - U32 Reserved3; /* 0x0C */ - U32 Reserved4; /* 0x10 */ -} MPI2_RAID_COMPATIBILITY_RESULT_STRUCT, -MPI2_POINTER PTR_MPI2_RAID_COMPATIBILITY_RESULT_STRUCT, -Mpi2RaidCompatibilityResultStruct_t, -MPI2_POINTER pMpi2RaidCompatibilityResultStruct_t; - -/* defines for RAID Compatibility Result Structure State field */ -#define MPI2_RAID_COMPAT_STATE_COMPATIBLE (0x00) -#define MPI2_RAID_COMPAT_STATE_NOT_COMPATIBLE (0x01) - -/* defines for RAID Compatibility Result Structure GenericAttributes field */ -#define MPI2_RAID_COMPAT_GENATTRIB_4K_SECTOR (0x00000010) - -#define MPI2_RAID_COMPAT_GENATTRIB_MEDIA_MASK (0x0000000C) -#define MPI2_RAID_COMPAT_GENATTRIB_SOLID_STATE_DRIVE (0x00000008) -#define MPI2_RAID_COMPAT_GENATTRIB_HARD_DISK_DRIVE (0x00000004) - -#define MPI2_RAID_COMPAT_GENATTRIB_PROTOCOL_MASK (0x00000003) -#define MPI2_RAID_COMPAT_GENATTRIB_SAS_PROTOCOL (0x00000002) -#define MPI2_RAID_COMPAT_GENATTRIB_SATA_PROTOCOL (0x00000001) - -/* RAID Action Reply ActionData union */ -typedef union _MPI2_RAID_ACTION_REPLY_DATA -{ - U32 Word[6]; - MPI2_RAID_VOL_INDICATOR RaidVolumeIndicator; - U16 VolDevHandle; - U8 VolumeState; - U8 PhysDiskNum; - MPI2_RAID_COMPATIBILITY_RESULT_STRUCT RaidCompatibilityResult; -} 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 deleted file mode 100644 index 45b6fa10b803..000000000000 --- a/drivers/scsi/mpt2sas/mpi/mpi2_sas.h +++ /dev/null @@ -1,288 +0,0 @@ -/* - * Copyright (c) 2000-2014 LSI Corporation. - * - * - * Name: mpi2_sas.h - * Title: MPI Serial Attached SCSI structures and definitions - * Creation Date: February 9, 2007 - * - * mpi2_sas.h Version: 02.00.05 - * - * 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. - * 10-28-09 02.00.03 Changed the type of SGL in MPI2_SATA_PASSTHROUGH_REQUEST - * to MPI2_SGE_IO_UNION since it supports chained SGLs. - * 05-12-10 02.00.04 Modified some comments. - * 08-11-10 02.00.05 Added NCQ operations to SAS IO Unit Control. - * -------------------------------------------------------------------------- - */ - -#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) - -/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */ - - -/* 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_SGE_IO_UNION SGL; /* 0x30 */ -} 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) - -/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */ - - -/* 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_DEV_ENABLE_NCQ (0x14) -#define MPI2_SAS_OP_DEV_DISABLE_NCQ (0x15) -#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 deleted file mode 100644 index 659b8ac83ceb..000000000000 --- a/drivers/scsi/mpt2sas/mpi/mpi2_tool.h +++ /dev/null @@ -1,481 +0,0 @@ -/* - * Copyright (c) 2000-2014 LSI Corporation. - * - * - * Name: mpi2_tool.h - * Title: MPI diagnostic tool structures and definitions - * Creation Date: March 26, 2007 - * - * mpi2_tool.h Version: 02.00.12 - * - * 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. - * 05-06-09 02.00.03 Added ISTWI Read Write Tool and Diagnostic CLI Tool. - * 07-30-09 02.00.04 Added ExtendedType field to DiagnosticBufferPost request - * and reply messages. - * Added MPI2_DIAG_BUF_TYPE_EXTENDED. - * Incremented MPI2_DIAG_BUF_TYPE_COUNT. - * 05-12-10 02.00.05 Added Diagnostic Data Upload tool. - * 08-11-10 02.00.06 Added defines that were missing for Diagnostic Buffer - * Post Request. - * 05-25-11 02.00.07 Added Flags field and related defines to - * MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST. - * 07-26-12 02.00.10 Modified MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST so that - * it uses MPI Chain SGE as well as MPI Simple SGE. - * 08-19-13 02.00.11 Added MPI2_TOOLBOX_TEXT_DISPLAY_TOOL and related info. - * 01-08-14 02.00.12 Added MPI2_TOOLBOX_CLEAN_BIT26_PRODUCT_SPECIFIC. - * -------------------------------------------------------------------------- - */ - -#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_DIAG_DATA_UPLOAD_TOOL (0x02) -#define MPI2_TOOLBOX_ISTWI_READ_WRITE_TOOL (0x03) -#define MPI2_TOOLBOX_BEACON_TOOL (0x05) -#define MPI2_TOOLBOX_DIAGNOSTIC_CLI_TOOL (0x06) -#define MPI2_TOOLBOX_TEXT_DISPLAY_TOOL (0x07) - - -/**************************************************************************** -* 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_BIT26_PRODUCT_SPECIFIC (0x04000000) -#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 Diagnostic Data Upload request -****************************************************************************/ - -typedef struct _MPI2_TOOLBOX_DIAG_DATA_UPLOAD_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 SGLFlags; /* 0x0C */ - U8 Reserved5; /* 0x0D */ - U16 Reserved6; /* 0x0E */ - U32 Flags; /* 0x10 */ - U32 DataLength; /* 0x14 */ - MPI2_SGE_SIMPLE_UNION SGL; /* 0x18 */ -} MPI2_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST, -MPI2_POINTER PTR_MPI2_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST, -Mpi2ToolboxDiagDataUploadRequest_t, -MPI2_POINTER pMpi2ToolboxDiagDataUploadRequest_t; - -/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */ - - -typedef struct _MPI2_DIAG_DATA_UPLOAD_HEADER { - U32 DiagDataLength; /* 00h */ - U8 FormatCode; /* 04h */ - U8 Reserved1; /* 05h */ - U16 Reserved2; /* 06h */ -} MPI2_DIAG_DATA_UPLOAD_HEADER, MPI2_POINTER PTR_MPI2_DIAG_DATA_UPLOAD_HEADER, -Mpi2DiagDataUploadHeader_t, MPI2_POINTER pMpi2DiagDataUploadHeader_t; - - -/**************************************************************************** -* Toolbox ISTWI Read Write Tool -****************************************************************************/ - -/* Toolbox ISTWI Read Write Tool request message */ -typedef struct _MPI2_TOOLBOX_ISTWI_READ_WRITE_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 Reserved5; /* 0x0C */ - U32 Reserved6; /* 0x10 */ - U8 DevIndex; /* 0x14 */ - U8 Action; /* 0x15 */ - U8 SGLFlags; /* 0x16 */ - U8 Flags; /* 0x17 */ - U16 TxDataLength; /* 0x18 */ - U16 RxDataLength; /* 0x1A */ - U32 Reserved8; /* 0x1C */ - U32 Reserved9; /* 0x20 */ - U32 Reserved10; /* 0x24 */ - U32 Reserved11; /* 0x28 */ - U32 Reserved12; /* 0x2C */ - MPI2_SGE_SIMPLE_UNION SGL; /* 0x30 */ -} MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST, - MPI2_POINTER PTR_MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST, - Mpi2ToolboxIstwiReadWriteRequest_t, - MPI2_POINTER pMpi2ToolboxIstwiReadWriteRequest_t; - -/* values for the Action field */ -#define MPI2_TOOL_ISTWI_ACTION_READ_DATA (0x01) -#define MPI2_TOOL_ISTWI_ACTION_WRITE_DATA (0x02) -#define MPI2_TOOL_ISTWI_ACTION_SEQUENCE (0x03) -#define MPI2_TOOL_ISTWI_ACTION_RESERVE_BUS (0x10) -#define MPI2_TOOL_ISTWI_ACTION_RELEASE_BUS (0x11) -#define MPI2_TOOL_ISTWI_ACTION_RESET (0x12) - -/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */ - -/* values for the Flags field */ -#define MPI2_TOOL_ISTWI_FLAG_AUTO_RESERVE_RELEASE (0x80) -#define MPI2_TOOL_ISTWI_FLAG_PAGE_ADDR_MASK (0x07) - -/* Toolbox ISTWI Read Write Tool reply message */ -typedef struct _MPI2_TOOLBOX_ISTWI_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 */ - U8 DevIndex; /* 0x14 */ - U8 Action; /* 0x15 */ - U8 IstwiStatus; /* 0x16 */ - U8 Reserved6; /* 0x17 */ - U16 TxDataCount; /* 0x18 */ - U16 RxDataCount; /* 0x1A */ -} MPI2_TOOLBOX_ISTWI_REPLY, MPI2_POINTER PTR_MPI2_TOOLBOX_ISTWI_REPLY, - Mpi2ToolboxIstwiReply_t, MPI2_POINTER pMpi2ToolboxIstwiReply_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) - - -/**************************************************************************** -* Toolbox Diagnostic CLI Tool -****************************************************************************/ - -#define MPI2_TOOLBOX_DIAG_CLI_CMD_LENGTH (0x5C) - -/* MPI v2.0 Toolbox Diagnostic CLI Tool request message */ -typedef struct _MPI2_TOOLBOX_DIAGNOSTIC_CLI_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 SGLFlags; /* 0x0C */ - U8 Reserved5; /* 0x0D */ - U16 Reserved6; /* 0x0E */ - U32 DataLength; /* 0x10 */ - U8 DiagnosticCliCommand - [MPI2_TOOLBOX_DIAG_CLI_CMD_LENGTH]; /* 0x14 */ - MPI2_MPI_SGE_IO_UNION SGL; /* 0x70 */ -} MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST, - MPI2_POINTER PTR_MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST, - Mpi2ToolboxDiagnosticCliRequest_t, - MPI2_POINTER pMpi2ToolboxDiagnosticCliRequest_t; - -/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */ - - -/* Toolbox Diagnostic CLI Tool reply message */ -typedef struct _MPI2_TOOLBOX_DIAGNOSTIC_CLI_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 */ - U32 ReturnedDataLength; /* 0x14 */ -} MPI2_TOOLBOX_DIAGNOSTIC_CLI_REPLY, - MPI2_POINTER PTR_MPI2_TOOLBOX_DIAG_CLI_REPLY, - Mpi2ToolboxDiagnosticCliReply_t, - MPI2_POINTER pMpi2ToolboxDiagnosticCliReply_t; - - -/**************************************************************************** -* Toolbox Console Text Display Tool -****************************************************************************/ - -/* Toolbox Console Text Display Tool request message */ -typedef struct _MPI2_TOOLBOX_TEXT_DISPLAY_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 Console; /* 0x0C */ - U8 Flags; /* 0x0D */ - U16 Reserved6; /* 0x0E */ - U8 TextToDisplay[4]; /* 0x10 */ -} MPI2_TOOLBOX_TEXT_DISPLAY_REQUEST, -MPI2_POINTER PTR_MPI2_TOOLBOX_TEXT_DISPLAY_REQUEST, -Mpi2ToolboxTextDisplayRequest_t, -MPI2_POINTER pMpi2ToolboxTextDisplayRequest_t; - -/* defines for the Console field */ -#define MPI2_TOOLBOX_CONSOLE_TYPE_MASK (0xF0) -#define MPI2_TOOLBOX_CONSOLE_TYPE_DEFAULT (0x00) -#define MPI2_TOOLBOX_CONSOLE_TYPE_UART (0x10) -#define MPI2_TOOLBOX_CONSOLE_TYPE_ETHERNET (0x20) - -#define MPI2_TOOLBOX_CONSOLE_NUMBER_MASK (0x0F) - -/* defines for the Flags field */ -#define MPI2_TOOLBOX_CONSOLE_FLAG_TIMESTAMP (0x01) - - - -/***************************************************************************** -* -* Diagnostic Buffer Messages -* -*****************************************************************************/ - - -/**************************************************************************** -* Diagnostic Buffer Post request -****************************************************************************/ - -typedef struct _MPI2_DIAG_BUFFER_POST_REQUEST -{ - U8 ExtendedType; /* 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 ExtendedType field */ -#define MPI2_DIAG_EXTENDED_TYPE_UTILIZATION (0x02) - -/* values for the BufferType field */ -#define MPI2_DIAG_BUF_TYPE_TRACE (0x00) -#define MPI2_DIAG_BUF_TYPE_SNAPSHOT (0x01) -#define MPI2_DIAG_BUF_TYPE_EXTENDED (0x02) -/* count of the number of buffer types */ -#define MPI2_DIAG_BUF_TYPE_COUNT (0x03) - -/* values for the Flags field */ -#define MPI2_DIAG_BUF_FLAG_RELEASE_ON_FULL (0x00000002) -#define MPI2_DIAG_BUF_FLAG_IMMEDIATE_RELEASE (0x00000001) - - -/**************************************************************************** -* Diagnostic Buffer Post reply -****************************************************************************/ - -typedef struct _MPI2_DIAG_BUFFER_POST_REPLY -{ - U8 ExtendedType; /* 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 deleted file mode 100644 index 6b0dcdd02f68..000000000000 --- a/drivers/scsi/mpt2sas/mpi/mpi2_type.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2000-2014 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 deleted file mode 100644 index c167911221e9..000000000000 --- a/drivers/scsi/mpt2sas/mpt2sas_base.c +++ /dev/null @@ -1,4899 +0,0 @@ -/* - * 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-2014 LSI Corporation - * Copyright (C) 20013-2014 Avago Technologies - * (mailto: MPT-FusionLinux.pdl@avagotech.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/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 <linux/time.h> -#include <linux/kthread.h> -#include <linux/aer.h> - -#include "mpt2sas_base.h" - -static MPT_CALLBACK mpt_callbacks[MPT_MAX_CALLBACKS]; - -#define FAULT_POLLING_INTERVAL 1000 /* in milliseconds */ - -#define MAX_HBA_QUEUE_DEPTH 30000 -#define MAX_CHAIN_DEPTH 100000 -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)"); - -static int max_msix_vectors = -1; -module_param(max_msix_vectors, int, 0); -MODULE_PARM_DESC(max_msix_vectors, " max msix vectors "); - -static int mpt2sas_fwfault_debug; -MODULE_PARM_DESC(mpt2sas_fwfault_debug, " enable detection of firmware fault " - "and halt firmware - (default=0)"); - -static int disable_discovery = -1; -module_param(disable_discovery, int, 0); -MODULE_PARM_DESC(disable_discovery, " disable discovery "); - -static int -_base_get_ioc_facts(struct MPT2SAS_ADAPTER *ioc, int sleep_flag); - -static int -_base_diag_reset(struct MPT2SAS_ADAPTER *ioc, int sleep_flag); - -/** - * _scsih_set_fwfault_debug - global setting of ioc->fwfault_debug. - * - */ -static int -_scsih_set_fwfault_debug(const char *val, struct kernel_param *kp) -{ - int ret = param_set_int(val, kp); - struct MPT2SAS_ADAPTER *ioc; - - if (ret) - return ret; - - /* global ioc spinlock to protect controller list on list operations */ - printk(KERN_INFO "setting fwfault_debug(%d)\n", mpt2sas_fwfault_debug); - spin_lock(&gioc_lock); - list_for_each_entry(ioc, &mpt2sas_ioc_list, list) - ioc->fwfault_debug = mpt2sas_fwfault_debug; - spin_unlock(&gioc_lock); - return 0; -} - -module_param_call(mpt2sas_fwfault_debug, _scsih_set_fwfault_debug, - param_get_int, &mpt2sas_fwfault_debug, 0644); - -/** - * mpt2sas_remove_dead_ioc_func - kthread context to remove dead ioc - * @arg: input argument, used to derive ioc - * - * Return 0 if controller is removed from pci subsystem. - * Return -1 for other case. - */ -static int mpt2sas_remove_dead_ioc_func(void *arg) -{ - struct MPT2SAS_ADAPTER *ioc = (struct MPT2SAS_ADAPTER *)arg; - struct pci_dev *pdev; - - if ((ioc == NULL)) - return -1; - - pdev = ioc->pdev; - if ((pdev == NULL)) - return -1; - pci_stop_and_remove_bus_device_locked(pdev); - return 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; - struct task_struct *p; - - spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); - if (ioc->shost_recovery || ioc->pci_error_recovery) - 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_MASK) { - printk(MPT2SAS_INFO_FMT "%s : SAS host is non-operational !!!!\n", - ioc->name, __func__); - - /* It may be possible that EEH recovery can resolve some of - * pci bus failure issues rather removing the dead ioc function - * by considering controller is in a non-operational state. So - * here priority is given to the EEH recovery. If it doesn't - * not resolve this issue, mpt2sas driver will consider this - * controller to non-operational state and remove the dead ioc - * function. - */ - if (ioc->non_operational_loop++ < 5) { - spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, - flags); - goto rearm_timer; - } - - /* - * Call _scsih_flush_pending_cmds callback so that we flush all - * pending commands back to OS. This call is required to aovid - * deadlock at block layer. Dead IOC will fail to do diag reset, - * and this call is safe since dead ioc will never return any - * command back from HW. - */ - ioc->schedule_dead_ioc_flush_running_cmds(ioc); - /* - * Set remove_host flag early since kernel thread will - * take some time to execute. - */ - ioc->remove_host = 1; - /*Remove the Dead Host */ - p = kthread_run(mpt2sas_remove_dead_ioc_func, ioc, - "mpt2sas_dead_ioc_%d", ioc->id); - if (IS_ERR(p)) { - printk(MPT2SAS_ERR_FMT - "%s: Running mpt2sas_dead_ioc thread failed !!!!\n", - ioc->name, __func__); - } else { - printk(MPT2SAS_ERR_FMT - "%s: Running mpt2sas_dead_ioc thread success !!!!\n", - ioc->name, __func__); - } - - return; /* don't rearm timer */ - } - - ioc->non_operational_loop = 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); -} - -/** - * mpt2sas_base_start_watchdog - start the fault_reset_work_q - * @ioc: per adapter object - * Context: sleep. - * - * Return nothing. - */ -void -mpt2sas_base_start_watchdog(struct MPT2SAS_ADAPTER *ioc) -{ - unsigned long flags; - - if (ioc->fault_reset_work_q) - return; - - /* 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__); - return; - } - 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); -} - -/** - * mpt2sas_base_stop_watchdog - stop the fault_reset_work_q - * @ioc: per adapter object - * Context: sleep. - * - * Return nothing. - */ -void -mpt2sas_base_stop_watchdog(struct MPT2SAS_ADAPTER *ioc) -{ - unsigned long flags; - struct workqueue_struct *wq; - - 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 (wq) { - if (!cancel_delayed_work_sync(&ioc->fault_reset_work)) - flush_workqueue(wq); - destroy_workqueue(wq); - } -} - -/** - * mpt2sas_base_fault_info - verbose translation of firmware FAULT code - * @ioc: per adapter 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); -} - -/** - * mpt2sas_halt_firmware - halt's mpt controller firmware - * @ioc: per adapter object - * - * For debugging timeout related issues. Writing 0xCOFFEE00 - * to the doorbell register will halt controller firmware. With - * the purpose to stop both driver and firmware, the enduser can - * obtain a ring buffer from controller UART. - */ -void -mpt2sas_halt_firmware(struct MPT2SAS_ADAPTER *ioc) -{ - u32 doorbell; - - if (!ioc->fwfault_debug) - return; - - dump_stack(); - - doorbell = readl(&ioc->chip->Doorbell); - if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) - mpt2sas_base_fault_info(ioc , doorbell); - else { - writel(0xC0FFEE00, &ioc->chip->Doorbell); - printk(MPT2SAS_ERR_FMT "Firmware is halted due to command " - "timeout\n", ioc->name); - } - - panic("panic in %s\n", __func__); -} - -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING -/** - * _base_sas_ioc_info - verbose translation of the ioc status - * @ioc: per adapter 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; - - if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) - 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: per adapter 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_SAS_DEVICE_STATUS_CHANGE: - desc = "Device Status Change"; - break; - case MPI2_EVENT_IR_OPERATION_STATUS: - if (!ioc->hide_ir_msg) - desc = "IR Operation Status"; - break; - case MPI2_EVENT_SAS_DISCOVERY: - { - Mpi2EventDataSasDiscovery_t *event_data = - (Mpi2EventDataSasDiscovery_t *)mpi_reply->EventData; - printk(MPT2SAS_INFO_FMT "Discovery: (%s)", ioc->name, - (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED) ? - "start" : "stop"); - if (event_data->DiscoveryStatus) - printk("discovery_status(0x%08x)", - le32_to_cpu(event_data->DiscoveryStatus)); - printk("\n"); - return; - } - 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: - if (!ioc->hide_ir_msg) - desc = "IR Volume"; - break; - case MPI2_EVENT_IR_PHYSICAL_DISK: - if (!ioc->hide_ir_msg) - desc = "IR Physical Disk"; - break; - case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST: - if (!ioc->hide_ir_msg) - desc = "IR Configuration Change List"; - break; - case MPI2_EVENT_LOG_ENTRY_ADDED: - if (!ioc->hide_ir_msg) - desc = "Log Entry Added"; - break; - case MPI2_EVENT_TEMP_THRESHOLD: - desc = "Temperature Threshold"; - 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: per adapter 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; - - /* each nexus loss loginfo */ - if (log_info == 0x31170000) - return; - - /* eat the loginfos associated with task aborts */ - if (ioc->ignore_loginfos && (log_info == 0x30050000 || 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: - if (!ioc->hide_ir_msg) - originator_str = "IR"; - else - originator_str = "WarpDrive"; - 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); -} - -/** - * _base_display_reply_info - - * @ioc: per adapter object - * @smid: system request message index - * @msix_index: MSIX table index supplied by the OS - * @reply: reply message frame(lower 32bit addr) - * - * Return nothing. - */ -static void -_base_display_reply_info(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, - u32 reply) -{ - MPI2DefaultReply_t *mpi_reply; - u16 ioc_status; - - mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); - if (unlikely(!mpi_reply)) { - printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return; - } - 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: per adapter object - * @smid: system request message index - * @msix_index: MSIX table index supplied by the OS - * @reply: reply message frame(lower 32bit addr) - * - * Return 1 meaning mf should be freed from _base_interrupt - * 0 means the mf is freed from this function. - */ -u8 -mpt2sas_base_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, - 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 1; - - if (ioc->base_cmds.status == MPT2_CMD_NOT_USED) - return 1; - - 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); - return 1; -} - -/** - * _base_async_event - main callback handler for firmware asyn events - * @ioc: per adapter object - * @msix_index: MSIX table index supplied by the OS - * @reply: reply message frame(lower 32bit addr) - * - * Returns void. - */ -static void -_base_async_event(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, 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 = 0; /* TODO */ - ack_request->VP_ID = 0; - mpt2sas_base_put_smid_default(ioc, smid); - - out: - - /* scsih callback handler */ - mpt2sas_scsih_event_callback(ioc, msix_index, reply); - - /* ctl callback handler */ - mpt2sas_ctl_event_callback(ioc, msix_index, reply); - - return; -} - -/** - * _base_get_cb_idx - obtain the callback index - * @ioc: per adapter object - * @smid: system request message index - * - * Return callback index. - */ -static u8 -_base_get_cb_idx(struct MPT2SAS_ADAPTER *ioc, u16 smid) -{ - int i; - u8 cb_idx; - - if (smid < ioc->hi_priority_smid) { - i = smid - 1; - cb_idx = ioc->scsi_lookup[i].cb_idx; - } else if (smid < ioc->internal_smid) { - i = smid - ioc->hi_priority_smid; - cb_idx = ioc->hpr_lookup[i].cb_idx; - } else if (smid <= ioc->hba_queue_depth) { - i = smid - ioc->internal_smid; - cb_idx = ioc->internal_lookup[i].cb_idx; - } else - cb_idx = 0xFF; - return cb_idx; -} - -/** - * _base_mask_interrupts - disable interrupts - * @ioc: per adapter 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: per adapter object - * - * Enabling only Reply Interrupts - * - * Return nothing. - */ -static void -_base_unmask_interrupts(struct MPT2SAS_ADAPTER *ioc) -{ - u32 him_register; - - him_register = readl(&ioc->chip->HostInterruptMask); - him_register &= ~MPI2_HIM_RIM; - writel(him_register, &ioc->chip->HostInterruptMask); - ioc->mask_interrupts = 0; -} - -union reply_descriptor { - u64 word; - struct { - u32 low; - u32 high; - } u; -}; - -/** - * _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) -{ - struct adapter_reply_queue *reply_q = bus_id; - union reply_descriptor rd; - u32 completed_cmds; - u8 request_desript_type; - u16 smid; - u8 cb_idx; - u32 reply; - u8 msix_index = reply_q->msix_index; - struct MPT2SAS_ADAPTER *ioc = reply_q->ioc; - Mpi2ReplyDescriptorsUnion_t *rpf; - u8 rc; - - if (ioc->mask_interrupts) - return IRQ_NONE; - - if (!atomic_add_unless(&reply_q->busy, 1, 1)) - return IRQ_NONE; - - rpf = &reply_q->reply_post_free[reply_q->reply_post_host_index]; - request_desript_type = rpf->Default.ReplyFlags - & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; - if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) { - atomic_dec(&reply_q->busy); - return IRQ_NONE; - } - - completed_cmds = 0; - cb_idx = 0xFF; - do { - rd.word = le64_to_cpu(rpf->Words); - if (rd.u.low == UINT_MAX || rd.u.high == UINT_MAX) - goto out; - reply = 0; - smid = le16_to_cpu(rpf->Default.DescriptorTypeDependent1); - if (request_desript_type == - MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY) { - reply = le32_to_cpu - (rpf->AddressReply.ReplyFrameAddress); - if (reply > ioc->reply_dma_max_address || - reply < ioc->reply_dma_min_address) - reply = 0; - } 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 = _base_get_cb_idx(ioc, smid); - if ((likely(cb_idx < MPT_MAX_CALLBACKS)) - && (likely(mpt_callbacks[cb_idx] != NULL))) { - rc = mpt_callbacks[cb_idx](ioc, smid, - msix_index, reply); - if (reply) - _base_display_reply_info(ioc, smid, - msix_index, reply); - if (rc) - mpt2sas_base_free_smid(ioc, smid); - } - } - if (!smid) - _base_async_event(ioc, msix_index, 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); - wmb(); - writel(ioc->reply_free_host_index, - &ioc->chip->ReplyFreeHostIndex); - } - - next: - - rpf->Words = cpu_to_le64(ULLONG_MAX); - reply_q->reply_post_host_index = - (reply_q->reply_post_host_index == - (ioc->reply_post_queue_depth - 1)) ? 0 : - reply_q->reply_post_host_index + 1; - request_desript_type = - reply_q->reply_post_free[reply_q->reply_post_host_index]. - Default.ReplyFlags & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; - completed_cmds++; - if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) - goto out; - if (!reply_q->reply_post_host_index) - rpf = reply_q->reply_post_free; - else - rpf++; - } while (1); - - out: - - if (!completed_cmds) { - atomic_dec(&reply_q->busy); - return IRQ_NONE; - } - wmb(); - if (ioc->is_warpdrive) { - writel(reply_q->reply_post_host_index, - ioc->reply_post_host_index[msix_index]); - atomic_dec(&reply_q->busy); - return IRQ_HANDLED; - } - writel(reply_q->reply_post_host_index | (msix_index << - MPI2_RPHI_MSIX_INDEX_SHIFT), &ioc->chip->ReplyPostHostIndex); - atomic_dec(&reply_q->busy); - return IRQ_HANDLED; -} - -/** - * _base_is_controller_msix_enabled - is controller support muli-reply queues - * @ioc: per adapter object - * - */ -static inline int -_base_is_controller_msix_enabled(struct MPT2SAS_ADAPTER *ioc) -{ - return (ioc->facts.IOCCapabilities & - MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX) && ioc->msix_enable; -} - -/** - * mpt2sas_base_flush_reply_queues - flushing the MSIX reply queues - * @ioc: per adapter object - * Context: ISR conext - * - * Called when a Task Management request has completed. We want - * to flush the other reply queues so all the outstanding IO has been - * completed back to OS before we process the TM completetion. - * - * Return nothing. - */ -void -mpt2sas_base_flush_reply_queues(struct MPT2SAS_ADAPTER *ioc) -{ - struct adapter_reply_queue *reply_q; - - /* If MSIX capability is turned off - * then multi-queues are not enabled - */ - if (!_base_is_controller_msix_enabled(ioc)) - return; - - list_for_each_entry(reply_q, &ioc->reply_queue_list, list) { - if (ioc->shost_recovery) - return; - /* TMs are on msix_index == 0 */ - if (reply_q->msix_index == 0) - continue; - _base_interrupt(reply_q->vector, (void *)reply_q); - } -} - -/** - * mpt2sas_base_release_callback_handler - clear interrupt 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; - u64 consistent_dma_mask; - - if (ioc->dma_mask) - consistent_dma_mask = DMA_BIT_MASK(64); - else - consistent_dma_mask = DMA_BIT_MASK(32); - - if (sizeof(dma_addr_t) > 4) { - const uint64_t required_mask = - dma_get_required_mask(&pdev->dev); - if ((required_mask > DMA_BIT_MASK(32)) && - !pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) && - !pci_set_consistent_dma_mask(pdev, consistent_dma_mask)) { - ioc->base_add_sg_single = &_base_add_sg_single_64; - ioc->sge_size = sizeof(Mpi2SGESimple64_t); - ioc->dma_mask = 64; - goto out; - } - } - - if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) - && !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) { - ioc->base_add_sg_single = &_base_add_sg_single_32; - ioc->sge_size = sizeof(Mpi2SGESimple32_t); - ioc->dma_mask = 32; - } else - return -ENODEV; - - out: - si_meminfo(&s); - printk(MPT2SAS_INFO_FMT - "%d BIT PCI BUS DMA ADDRESSING SUPPORTED, total mem (%ld kB)\n", - ioc->name, ioc->dma_mask, convert_to_kb(s.totalram)); - - return 0; -} - -static int -_base_change_consistent_dma_mask(struct MPT2SAS_ADAPTER *ioc, - struct pci_dev *pdev) -{ - if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) { - if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) - return -ENODEV; - } - return 0; -} -/** - * _base_check_enable_msix - checks MSIX capabable. - * @ioc: per adapter object - * - * Check to see if card is capable of MSIX, and set number - * of available msix vectors - */ -static int -_base_check_enable_msix(struct MPT2SAS_ADAPTER *ioc) -{ - int base; - u16 message_control; - - - /* Check whether controller SAS2008 B0 controller, - if it is SAS2008 B0 controller use IO-APIC instead of MSIX */ - if (ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2008 && - ioc->pdev->revision == 0x01) { - return -EINVAL; - } - - 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 */ - /* NUMA_IO not supported for older controllers */ - if (ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2004 || - ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2008 || - ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_1 || - ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_2 || - ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_3 || - ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2116_1 || - ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2116_2) - ioc->msix_vector_count = 1; - else { - pci_read_config_word(ioc->pdev, base + 2, &message_control); - ioc->msix_vector_count = (message_control & 0x3FF) + 1; - } - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "msix is supported, " - "vector_count(%d)\n", ioc->name, ioc->msix_vector_count)); - - return 0; -} - -/** - * _base_free_irq - free irq - * @ioc: per adapter object - * - * Freeing respective reply_queue from the list. - */ -static void -_base_free_irq(struct MPT2SAS_ADAPTER *ioc) -{ - struct adapter_reply_queue *reply_q, *next; - - if (list_empty(&ioc->reply_queue_list)) - return; - - list_for_each_entry_safe(reply_q, next, &ioc->reply_queue_list, list) { - list_del(&reply_q->list); - irq_set_affinity_hint(reply_q->vector, NULL); - free_cpumask_var(reply_q->affinity_hint); - synchronize_irq(reply_q->vector); - free_irq(reply_q->vector, reply_q); - kfree(reply_q); - } -} - -/** - * _base_request_irq - request irq - * @ioc: per adapter object - * @index: msix index into vector table - * @vector: irq vector - * - * Inserting respective reply_queue into the list. - */ -static int -_base_request_irq(struct MPT2SAS_ADAPTER *ioc, u8 index, u32 vector) -{ - struct adapter_reply_queue *reply_q; - int r; - - reply_q = kzalloc(sizeof(struct adapter_reply_queue), GFP_KERNEL); - if (!reply_q) { - printk(MPT2SAS_ERR_FMT "unable to allocate memory %d!\n", - ioc->name, (int)sizeof(struct adapter_reply_queue)); - return -ENOMEM; - } - reply_q->ioc = ioc; - reply_q->msix_index = index; - reply_q->vector = vector; - - if (!alloc_cpumask_var(&reply_q->affinity_hint, GFP_KERNEL)) - return -ENOMEM; - cpumask_clear(reply_q->affinity_hint); - - atomic_set(&reply_q->busy, 0); - if (ioc->msix_enable) - snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d-msix%d", - MPT2SAS_DRIVER_NAME, ioc->id, index); - else - snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d", - MPT2SAS_DRIVER_NAME, ioc->id); - r = request_irq(vector, _base_interrupt, IRQF_SHARED, reply_q->name, - reply_q); - if (r) { - printk(MPT2SAS_ERR_FMT "unable to allocate interrupt %d!\n", - reply_q->name, vector); - kfree(reply_q); - return -EBUSY; - } - - INIT_LIST_HEAD(&reply_q->list); - list_add_tail(&reply_q->list, &ioc->reply_queue_list); - return 0; -} - -/** - * _base_assign_reply_queues - assigning msix index for each cpu - * @ioc: per adapter object - * - * The enduser would need to set the affinity via /proc/irq/#/smp_affinity - * - * It would nice if we could call irq_set_affinity, however it is not - * an exported symbol - */ -static void -_base_assign_reply_queues(struct MPT2SAS_ADAPTER *ioc) -{ - unsigned int cpu, nr_cpus, nr_msix, index = 0; - struct adapter_reply_queue *reply_q; - - if (!_base_is_controller_msix_enabled(ioc)) - return; - - memset(ioc->cpu_msix_table, 0, ioc->cpu_msix_table_sz); - - nr_cpus = num_online_cpus(); - nr_msix = ioc->reply_queue_count = min(ioc->reply_queue_count, - ioc->facts.MaxMSIxVectors); - if (!nr_msix) - return; - - cpu = cpumask_first(cpu_online_mask); - - list_for_each_entry(reply_q, &ioc->reply_queue_list, list) { - - unsigned int i, group = nr_cpus / nr_msix; - - if (cpu >= nr_cpus) - break; - - if (index < nr_cpus % nr_msix) - group++; - - for (i = 0 ; i < group ; i++) { - ioc->cpu_msix_table[cpu] = index; - cpumask_or(reply_q->affinity_hint, - reply_q->affinity_hint, get_cpu_mask(cpu)); - cpu = cpumask_next(cpu, cpu_online_mask); - } - - if (irq_set_affinity_hint(reply_q->vector, - reply_q->affinity_hint)) - dinitprintk(ioc, pr_info(MPT2SAS_FMT - "error setting affinity hint for irq vector %d\n", - ioc->name, reply_q->vector)); - index++; - } -} - -/** - * _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); - 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, *a; - int r; - int i; - 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->reply_queue_count = min_t(int, ioc->cpu_count, - ioc->msix_vector_count); - - if (!ioc->rdpq_array_enable && max_msix_vectors == -1) - max_msix_vectors = 8; - - if (max_msix_vectors > 0) { - ioc->reply_queue_count = min_t(int, max_msix_vectors, - ioc->reply_queue_count); - ioc->msix_vector_count = ioc->reply_queue_count; - } else if (max_msix_vectors == 0) - goto try_ioapic; - - printk(MPT2SAS_INFO_FMT - "MSI-X vectors supported: %d, no of cores: %d, max_msix_vectors: %d\n", - ioc->name, ioc->msix_vector_count, ioc->cpu_count, max_msix_vectors); - - entries = kcalloc(ioc->reply_queue_count, sizeof(struct msix_entry), - GFP_KERNEL); - if (!entries) { - dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "kcalloc " - "failed @ at %s:%d/%s() !!!\n", ioc->name, __FILE__, - __LINE__, __func__)); - goto try_ioapic; - } - - for (i = 0, a = entries; i < ioc->reply_queue_count; i++, a++) - a->entry = i; - - r = pci_enable_msix_exact(ioc->pdev, entries, ioc->reply_queue_count); - if (r) { - dfailprintk(ioc, printk(MPT2SAS_INFO_FMT - "pci_enable_msix_exact failed (r=%d) !!!\n", ioc->name, r)); - kfree(entries); - goto try_ioapic; - } - - ioc->msix_enable = 1; - for (i = 0, a = entries; i < ioc->reply_queue_count; i++, a++) { - r = _base_request_irq(ioc, i, a->vector); - if (r) { - _base_free_irq(ioc); - _base_disable_msix(ioc); - kfree(entries); - goto try_ioapic; - } - } - - kfree(entries); - return 0; - -/* failback to io_apic interrupt routing */ - try_ioapic: - - ioc->reply_queue_count = 1; - r = _base_request_irq(ioc, 0, ioc->pdev->irq); - - 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; - u64 pio_chip = 0; - u64 chip_phys = 0; - struct adapter_reply_queue *reply_q; - - dinitprintk(ioc, printk(MPT2SAS_INFO_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); - ioc->bars = 0; - 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); - ioc->bars = 0; - r = -ENODEV; - goto out_fail; - } - - /* AER (Advanced Error Reporting) hooks */ - pci_enable_pcie_error_reporting(pdev); - - 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) && - (!memap_sz || !pio_sz); i++) { - if (pci_resource_flags(pdev, i) & IORESOURCE_IO) { - if (pio_sz) - continue; - pio_chip = (u64)pci_resource_start(pdev, i); - pio_sz = pci_resource_len(pdev, i); - } else { - if (memap_sz) - continue; - /* verify memory resource is valid before using */ - if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) { - ioc->chip_phys = pci_resource_start(pdev, i); - chip_phys = (u64)ioc->chip_phys; - 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! " - "or resource not found\n", ioc->name); - r = -EINVAL; - goto out_fail; - } - - _base_mask_interrupts(ioc); - - r = _base_get_ioc_facts(ioc, CAN_SLEEP); - if (r) - goto out_fail; - - if (!ioc->rdpq_array_enable_assigned) { - ioc->rdpq_array_enable = ioc->rdpq_array_capable; - ioc->rdpq_array_enable_assigned = 1; - } - - r = _base_enable_msix(ioc); - if (r) - goto out_fail; - - list_for_each_entry(reply_q, &ioc->reply_queue_list, list) - printk(MPT2SAS_INFO_FMT "%s: IRQ %d\n", - reply_q->name, ((ioc->msix_enable) ? "PCI-MSI-X enabled" : - "IO-APIC enabled"), reply_q->vector); - - printk(MPT2SAS_INFO_FMT "iomem(0x%016llx), mapped(0x%p), size(%d)\n", - ioc->name, (unsigned long long)chip_phys, ioc->chip, memap_sz); - printk(MPT2SAS_INFO_FMT "ioport(0x%016llx), size(%d)\n", - ioc->name, (unsigned long long)pio_chip, pio_sz); - - /* Save PCI configuration state for recovery from PCI AER/EEH errors */ - pci_save_state(pdev); - - return 0; - - out_fail: - if (ioc->chip_phys) - iounmap(ioc->chip); - ioc->chip_phys = 0; - pci_release_selected_regions(ioc->pdev, ioc->bars); - pci_disable_pcie_error_reporting(pdev); - pci_disable_device(pdev); - return r; -} - -/** - * 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 the low 32bit address of the sense buffer. - */ -__le32 -mpt2sas_base_get_sense_buffer_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid) -{ - return cpu_to_le32(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 from internal queue - * @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->internal_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->internal_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_get_smid_scsiio - obtain a free smid from scsiio queue - * @ioc: per adapter object - * @cb_idx: callback index - * @scmd: pointer to scsi command object - * - * Returns smid (zero is invalid) - */ -u16 -mpt2sas_base_get_smid_scsiio(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx, - struct scsi_cmnd *scmd) -{ - unsigned long flags; - struct scsiio_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 scsiio_tracker, tracker_list); - request->scmd = scmd; - 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_get_smid_hpr - obtain a free smid from hi-priority queue - * @ioc: per adapter object - * @cb_idx: callback index - * - * Returns smid (zero is invalid) - */ -u16 -mpt2sas_base_get_smid_hpr(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->hpr_free_list)) { - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - return 0; - } - - request = list_entry(ioc->hpr_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; - int i; - struct chain_tracker *chain_req, *next; - - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - if (smid < ioc->hi_priority_smid) { - /* scsiio queue */ - i = smid - 1; - if (!list_empty(&ioc->scsi_lookup[i].chain_list)) { - list_for_each_entry_safe(chain_req, next, - &ioc->scsi_lookup[i].chain_list, tracker_list) { - list_del_init(&chain_req->tracker_list); - list_add(&chain_req->tracker_list, - &ioc->free_chain_list); - } - } - ioc->scsi_lookup[i].cb_idx = 0xFF; - ioc->scsi_lookup[i].scmd = NULL; - ioc->scsi_lookup[i].direct_io = 0; - list_add(&ioc->scsi_lookup[i].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--; - } - return; - } else if (smid < ioc->internal_smid) { - /* hi-priority */ - i = smid - ioc->hi_priority_smid; - ioc->hpr_lookup[i].cb_idx = 0xFF; - list_add(&ioc->hpr_lookup[i].tracker_list, - &ioc->hpr_free_list); - } else if (smid <= ioc->hba_queue_depth) { - /* internal queue */ - i = smid - ioc->internal_smid; - ioc->internal_lookup[i].cb_idx = 0xFF; - list_add(&ioc->internal_lookup[i].tracker_list, - &ioc->internal_free_list); - } - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); -} - -/** - * _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 - -static inline u8 -_base_get_msix_index(struct MPT2SAS_ADAPTER *ioc) -{ - return ioc->cpu_msix_table[raw_smp_processor_id()]; -} - -/** - * mpt2sas_base_put_smid_scsi_io - send SCSI_IO request to firmware - * @ioc: per adapter object - * @smid: system request message index - * @handle: device handle - * - * Return nothing. - */ -void -mpt2sas_base_put_smid_scsi_io(struct MPT2SAS_ADAPTER *ioc, u16 smid, u16 handle) -{ - Mpi2RequestDescriptorUnion_t descriptor; - u64 *request = (u64 *)&descriptor; - - - descriptor.SCSIIO.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO; - descriptor.SCSIIO.MSIxIndex = _base_get_msix_index(ioc); - 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 Management request to firmware - * @ioc: per adapter object - * @smid: system request message index - * - * Return nothing. - */ -void -mpt2sas_base_put_smid_hi_priority(struct MPT2SAS_ADAPTER *ioc, u16 smid) -{ - Mpi2RequestDescriptorUnion_t descriptor; - u64 *request = (u64 *)&descriptor; - - descriptor.HighPriority.RequestFlags = - MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; - descriptor.HighPriority.MSIxIndex = 0; - 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 - * - * Return nothing. - */ -void -mpt2sas_base_put_smid_default(struct MPT2SAS_ADAPTER *ioc, u16 smid) -{ - Mpi2RequestDescriptorUnion_t descriptor; - u64 *request = (u64 *)&descriptor; - - descriptor.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; - descriptor.Default.MSIxIndex = _base_get_msix_index(ioc); - 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 - * @io_index: value used to track the IO - * - * Return nothing. - */ -void -mpt2sas_base_put_smid_target_assist(struct MPT2SAS_ADAPTER *ioc, u16 smid, - u16 io_index) -{ - Mpi2RequestDescriptorUnion_t descriptor; - u64 *request = (u64 *)&descriptor; - - descriptor.SCSITarget.RequestFlags = - MPI2_REQ_DESCRIPT_FLAGS_SCSI_TARGET; - descriptor.SCSITarget.MSIxIndex = _base_get_msix_index(ioc); - 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_dell_branding - Disply branding string - * @ioc: per adapter object - * - * Return nothing. - */ -static void -_base_display_dell_branding(struct MPT2SAS_ADAPTER *ioc) -{ - char dell_branding[MPT2SAS_DELL_BRANDING_SIZE]; - - if (ioc->pdev->subsystem_vendor != PCI_VENDOR_ID_DELL) - return; - - memset(dell_branding, 0, MPT2SAS_DELL_BRANDING_SIZE); - switch (ioc->pdev->subsystem_device) { - case MPT2SAS_DELL_6GBPS_SAS_HBA_SSDID: - strncpy(dell_branding, MPT2SAS_DELL_6GBPS_SAS_HBA_BRANDING, - MPT2SAS_DELL_BRANDING_SIZE - 1); - break; - case MPT2SAS_DELL_PERC_H200_ADAPTER_SSDID: - strncpy(dell_branding, MPT2SAS_DELL_PERC_H200_ADAPTER_BRANDING, - MPT2SAS_DELL_BRANDING_SIZE - 1); - break; - case MPT2SAS_DELL_PERC_H200_INTEGRATED_SSDID: - strncpy(dell_branding, - MPT2SAS_DELL_PERC_H200_INTEGRATED_BRANDING, - MPT2SAS_DELL_BRANDING_SIZE - 1); - break; - case MPT2SAS_DELL_PERC_H200_MODULAR_SSDID: - strncpy(dell_branding, - MPT2SAS_DELL_PERC_H200_MODULAR_BRANDING, - MPT2SAS_DELL_BRANDING_SIZE - 1); - break; - case MPT2SAS_DELL_PERC_H200_EMBEDDED_SSDID: - strncpy(dell_branding, - MPT2SAS_DELL_PERC_H200_EMBEDDED_BRANDING, - MPT2SAS_DELL_BRANDING_SIZE - 1); - break; - case MPT2SAS_DELL_PERC_H200_SSDID: - strncpy(dell_branding, MPT2SAS_DELL_PERC_H200_BRANDING, - MPT2SAS_DELL_BRANDING_SIZE - 1); - break; - case MPT2SAS_DELL_6GBPS_SAS_SSDID: - strncpy(dell_branding, MPT2SAS_DELL_6GBPS_SAS_BRANDING, - MPT2SAS_DELL_BRANDING_SIZE - 1); - break; - default: - sprintf(dell_branding, "0x%4X", ioc->pdev->subsystem_device); - break; - } - - printk(MPT2SAS_INFO_FMT "%s: Vendor(0x%04X), Device(0x%04X)," - " SSVID(0x%04X), SSDID(0x%04X)\n", ioc->name, dell_branding, - ioc->pdev->vendor, ioc->pdev->device, ioc->pdev->subsystem_vendor, - ioc->pdev->subsystem_device); -} - -/** - * _base_display_intel_branding - Display branding string - * @ioc: per adapter object - * - * Return nothing. - */ -static void -_base_display_intel_branding(struct MPT2SAS_ADAPTER *ioc) -{ - if (ioc->pdev->subsystem_vendor != PCI_VENDOR_ID_INTEL) - return; - - switch (ioc->pdev->device) { - case MPI2_MFGPAGE_DEVID_SAS2008: - switch (ioc->pdev->subsystem_device) { - case MPT2SAS_INTEL_RMS2LL080_SSDID: - printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - MPT2SAS_INTEL_RMS2LL080_BRANDING); - break; - case MPT2SAS_INTEL_RMS2LL040_SSDID: - printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - MPT2SAS_INTEL_RMS2LL040_BRANDING); - break; - case MPT2SAS_INTEL_SSD910_SSDID: - printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - MPT2SAS_INTEL_SSD910_BRANDING); - break; - default: - break; - } - case MPI2_MFGPAGE_DEVID_SAS2308_2: - switch (ioc->pdev->subsystem_device) { - case MPT2SAS_INTEL_RS25GB008_SSDID: - printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - MPT2SAS_INTEL_RS25GB008_BRANDING); - break; - case MPT2SAS_INTEL_RMS25JB080_SSDID: - printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - MPT2SAS_INTEL_RMS25JB080_BRANDING); - break; - case MPT2SAS_INTEL_RMS25JB040_SSDID: - printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - MPT2SAS_INTEL_RMS25JB040_BRANDING); - break; - case MPT2SAS_INTEL_RMS25KB080_SSDID: - printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - MPT2SAS_INTEL_RMS25KB080_BRANDING); - break; - case MPT2SAS_INTEL_RMS25KB040_SSDID: - printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - MPT2SAS_INTEL_RMS25KB040_BRANDING); - break; - case MPT2SAS_INTEL_RMS25LB040_SSDID: - printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - MPT2SAS_INTEL_RMS25LB040_BRANDING); - break; - case MPT2SAS_INTEL_RMS25LB080_SSDID: - printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - MPT2SAS_INTEL_RMS25LB080_BRANDING); - break; - default: - break; - } - default: - break; - } -} - -/** - * _base_display_hp_branding - Display branding string - * @ioc: per adapter object - * - * Return nothing. - */ -static void -_base_display_hp_branding(struct MPT2SAS_ADAPTER *ioc) -{ - if (ioc->pdev->subsystem_vendor != MPT2SAS_HP_3PAR_SSVID) - return; - - switch (ioc->pdev->device) { - case MPI2_MFGPAGE_DEVID_SAS2004: - switch (ioc->pdev->subsystem_device) { - case MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_SSDID: - printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_BRANDING); - break; - default: - break; - } - case MPI2_MFGPAGE_DEVID_SAS2308_2: - switch (ioc->pdev->subsystem_device) { - case MPT2SAS_HP_2_4_INTERNAL_SSDID: - printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - MPT2SAS_HP_2_4_INTERNAL_BRANDING); - break; - case MPT2SAS_HP_2_4_EXTERNAL_SSDID: - printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - MPT2SAS_HP_2_4_EXTERNAL_BRANDING); - break; - case MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_SSDID: - printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_BRANDING); - break; - case MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_SSDID: - printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_BRANDING); - break; - default: - break; - } - default: - break; - } -} - -/** - * _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]; - u32 iounit_pg1_flags; - u32 bios_version; - - bios_version = le32_to_cpu(ioc->bios_pg3.BiosVersion); - 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, - ioc->pdev->revision, - (bios_version & 0xFF000000) >> 24, - (bios_version & 0x00FF0000) >> 16, - (bios_version & 0x0000FF00) >> 8, - bios_version & 0x000000FF); - - _base_display_dell_branding(ioc); - _base_display_intel_branding(ioc); - _base_display_hp_branding(ioc); - - 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->hide_ir_msg) { - 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_EXTENDED_BUFFER) { - printk(KERN_INFO "%sDiag Extended 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"); -} - -/** - * mpt2sas_base_update_missing_delay - change the missing delay timers - * @ioc: per adapter object - * @device_missing_delay: amount of time till device is reported missing - * @io_missing_delay: interval IO is returned when there is a missing device - * - * Return nothing. - * - * Passed on the command line, this function will modify the device missing - * delay, as well as the io missing delay. This should be called at driver - * load time. - */ -void -mpt2sas_base_update_missing_delay(struct MPT2SAS_ADAPTER *ioc, - u16 device_missing_delay, u8 io_missing_delay) -{ - u16 dmd, dmd_new, dmd_orignal; - u8 io_missing_delay_original; - u16 sz; - Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL; - Mpi2ConfigReply_t mpi_reply; - u8 num_phys = 0; - u16 ioc_status; - - mpt2sas_config_get_number_hba_phys(ioc, &num_phys); - if (!num_phys) - return; - - sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (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; - } - - /* device missing delay */ - dmd = sas_iounit_pg1->ReportDeviceMissingDelay; - if (dmd & MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16) - dmd = (dmd & MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16; - else - dmd = dmd & MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK; - dmd_orignal = dmd; - if (device_missing_delay > 0x7F) { - dmd = (device_missing_delay > 0x7F0) ? 0x7F0 : - device_missing_delay; - dmd = dmd / 16; - dmd |= MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16; - } else - dmd = device_missing_delay; - sas_iounit_pg1->ReportDeviceMissingDelay = dmd; - - /* io missing delay */ - io_missing_delay_original = sas_iounit_pg1->IODeviceMissingDelay; - sas_iounit_pg1->IODeviceMissingDelay = io_missing_delay; - - if (!mpt2sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1, - sz)) { - if (dmd & MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16) - dmd_new = (dmd & - MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16; - else - dmd_new = - dmd & MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK; - printk(MPT2SAS_INFO_FMT "device_missing_delay: old(%d), " - "new(%d)\n", ioc->name, dmd_orignal, dmd_new); - printk(MPT2SAS_INFO_FMT "ioc_missing_delay: old(%d), " - "new(%d)\n", ioc->name, io_missing_delay_original, - io_missing_delay); - ioc->device_missing_delay = dmd_new; - ioc->io_missing_delay = io_missing_delay; - } - -out: - kfree(sas_iounit_pg1); -} - -/** - * _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); - if (ioc->ir_firmware) - mpt2sas_config_get_manufacturing_pg10(ioc, &mpi_reply, - &ioc->manu_pg10); - 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); - mpt2sas_config_get_iounit_pg8(ioc, &mpi_reply, &ioc->iounit_pg8); - _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); - - if (ioc->iounit_pg8.NumSensors) - ioc->temp_sensors_count = ioc->iounit_pg8.NumSensors; -} - -/** - * _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) -{ - int i = 0; - struct reply_post_struct *rps; - - dexitprintk(ioc, printk(MPT2SAS_INFO_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) { - do { - rps = &ioc->reply_post[i]; - if (rps->reply_post_free) { - pci_pool_free( - ioc->reply_post_free_dma_pool, - rps->reply_post_free, - rps->reply_post_free_dma); - dexitprintk(ioc, printk(MPT2SAS_INFO_FMT - "reply_post_free_pool(0x%p): free\n", - ioc->name, rps->reply_post_free)); - rps->reply_post_free = NULL; - } - } while (ioc->rdpq_array_enable && - (++i < ioc->reply_queue_count)); - - if (ioc->reply_post_free_dma_pool) - pci_pool_destroy(ioc->reply_post_free_dma_pool); - kfree(ioc->reply_post); - } - - 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); - } - - if (ioc->scsi_lookup) { - free_pages((ulong)ioc->scsi_lookup, ioc->scsi_lookup_pages); - ioc->scsi_lookup = NULL; - } - kfree(ioc->hpr_lookup); - kfree(ioc->internal_lookup); - if (ioc->chain_lookup) { - for (i = 0; i < ioc->chain_depth; i++) { - if (ioc->chain_lookup[i].chain_buffer) - pci_pool_free(ioc->chain_dma_pool, - ioc->chain_lookup[i].chain_buffer, - ioc->chain_lookup[i].chain_buffer_dma); - } - if (ioc->chain_dma_pool) - pci_pool_destroy(ioc->chain_dma_pool); - free_pages((ulong)ioc->chain_lookup, ioc->chain_pages); - ioc->chain_lookup = NULL; - } -} - - -/** - * _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) -{ - struct mpt2sas_facts *facts; - u16 max_sge_elements; - u16 chains_needed_per_io; - u32 sz, total_sz, reply_post_free_sz; - u32 retry_sz; - u16 max_request_credit; - int i; - - dinitprintk(ioc, printk(MPT2SAS_INFO_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 = min_t(unsigned short, - max_sgl_entries, SCSI_MAX_SG_CHAIN_SEGMENTS); - if (ioc->shost->sg_tablesize > MPT2SAS_SG_DEPTH) - printk(MPT2SAS_WARN_FMT - "sg_tablesize(%u) is bigger than kernel defined" - " SCSI_MAX_SG_SEGMENTS(%u)\n", ioc->name, - ioc->shost->sg_tablesize, 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_queue_depth != 0) { - max_request_credit = min_t(u16, max_queue_depth + - ioc->hi_priority_depth + ioc->internal_depth, - facts->RequestCredit); - if (max_request_credit > MAX_HBA_QUEUE_DEPTH) - max_request_credit = MAX_HBA_QUEUE_DEPTH; - } else - max_request_credit = min_t(u16, facts->RequestCredit, - MAX_HBA_QUEUE_DEPTH); - - ioc->hba_queue_depth = max_request_credit; - ioc->hi_priority_depth = facts->HighPriorityCredit; - ioc->internal_depth = ioc->hi_priority_depth + 5; - - /* 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 64 FW events */ - ioc->reply_free_queue_depth = ioc->hba_queue_depth + 64; - - /* calculate reply descriptor post queue depth */ - ioc->reply_post_queue_depth = ioc->hba_queue_depth + - ioc->reply_free_queue_depth + 1; - /* align the reply post queue on the next 16 count boundary */ - if (ioc->reply_post_queue_depth % 16) - ioc->reply_post_queue_depth += 16 - - (ioc->reply_post_queue_depth % 16); - - - if (ioc->reply_post_queue_depth > - facts->MaxReplyDescriptorPostQueueDepth) { - ioc->reply_post_queue_depth = - facts->MaxReplyDescriptorPostQueueDepth - - (facts->MaxReplyDescriptorPostQueueDepth % 16); - ioc->hba_queue_depth = - ((ioc->reply_post_queue_depth - 64) / 2) - 1; - ioc->reply_free_queue_depth = ioc->hba_queue_depth + 64; - } - - 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)); - - /* reply post queue, 16 byte align */ - reply_post_free_sz = ioc->reply_post_queue_depth * - sizeof(Mpi2DefaultReplyDescriptor_t); - - sz = reply_post_free_sz; - if (_base_is_controller_msix_enabled(ioc) && !ioc->rdpq_array_enable) - sz *= ioc->reply_queue_count; - - ioc->reply_post = kcalloc((ioc->rdpq_array_enable) ? - (ioc->reply_queue_count):1, - sizeof(struct reply_post_struct), GFP_KERNEL); - - if (!ioc->reply_post) { - printk(MPT2SAS_ERR_FMT "reply_post_free pool: kcalloc failed\n", - ioc->name); - goto out; - } - 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; - } - i = 0; - do { - ioc->reply_post[i].reply_post_free = - pci_pool_alloc(ioc->reply_post_free_dma_pool, - GFP_KERNEL, - &ioc->reply_post[i].reply_post_free_dma); - if (!ioc->reply_post[i].reply_post_free) { - printk(MPT2SAS_ERR_FMT - "reply_post_free pool: pci_pool_alloc failed\n", - ioc->name); - goto out; - } - memset(ioc->reply_post[i].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[i].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[i].reply_post_free_dma)); - total_sz += sz; - } while (ioc->rdpq_array_enable && (++i < ioc->reply_queue_count)); - - if (ioc->dma_mask == 64) { - if (_base_change_consistent_dma_mask(ioc, ioc->pdev) != 0) { - printk(MPT2SAS_WARN_FMT - "no suitable consistent DMA mask for %s\n", - ioc->name, pci_name(ioc->pdev)); - goto out; - } - } - - ioc->scsiio_depth = ioc->hba_queue_depth - - ioc->hi_priority_depth - ioc->internal_depth; - - /* set the scsi host can_queue depth - * with some internal commands that could be outstanding - */ - ioc->shost->can_queue = ioc->scsiio_depth; - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "scsi host: " - "can_queue depth (%d)\n", ioc->name, ioc->shost->can_queue)); - - /* contiguous pool for request and chains, 16 byte align, one extra " - * "frame for smid=0 - */ - ioc->chain_depth = ioc->chains_needed_per_io * ioc->scsiio_depth; - sz = ((ioc->scsiio_depth + 1) * ioc->request_sz); - - /* hi-priority queue */ - sz += (ioc->hi_priority_depth * ioc->request_sz); - - /* internal queue */ - sz += (ioc->internal_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: hba_depth(%d), chains_per_io(%d), frame_sz(%d), " - "total(%d kB)\n", ioc->name, ioc->hba_queue_depth, - ioc->chains_needed_per_io, ioc->request_sz, sz/1024); - if (ioc->scsiio_depth < MPT2SAS_SAS_QUEUE_DEPTH) - goto out; - retry_sz += 64; - ioc->hba_queue_depth = max_request_credit - retry_sz; - goto retry_allocation; - } - - if (retry_sz) - printk(MPT2SAS_ERR_FMT "request pool: pci_alloc_consistent " - "succeed: hba_depth(%d), chains_per_io(%d), frame_sz(%d), " - "total(%d kb)\n", ioc->name, ioc->hba_queue_depth, - ioc->chains_needed_per_io, ioc->request_sz, sz/1024); - - - /* hi-priority queue */ - ioc->hi_priority = ioc->request + ((ioc->scsiio_depth + 1) * - ioc->request_sz); - ioc->hi_priority_dma = ioc->request_dma + ((ioc->scsiio_depth + 1) * - ioc->request_sz); - - /* internal queue */ - ioc->internal = ioc->hi_priority + (ioc->hi_priority_depth * - ioc->request_sz); - ioc->internal_dma = ioc->hi_priority_dma + (ioc->hi_priority_depth * - 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->hba_queue_depth, ioc->request_sz, - (ioc->hba_queue_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; - - sz = ioc->scsiio_depth * sizeof(struct scsiio_tracker); - ioc->scsi_lookup_pages = get_order(sz); - ioc->scsi_lookup = (struct scsiio_tracker *)__get_free_pages( - GFP_KERNEL, ioc->scsi_lookup_pages); - if (!ioc->scsi_lookup) { - printk(MPT2SAS_ERR_FMT "scsi_lookup: get_free_pages failed, " - "sz(%d)\n", ioc->name, (int)sz); - goto out; - } - - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "scsiio(0x%p): " - "depth(%d)\n", ioc->name, ioc->request, - ioc->scsiio_depth)); - - ioc->chain_depth = min_t(u32, ioc->chain_depth, MAX_CHAIN_DEPTH); - sz = ioc->chain_depth * sizeof(struct chain_tracker); - ioc->chain_pages = get_order(sz); - - ioc->chain_lookup = (struct chain_tracker *)__get_free_pages( - GFP_KERNEL, ioc->chain_pages); - if (!ioc->chain_lookup) { - printk(MPT2SAS_ERR_FMT "chain_lookup: get_free_pages failed, " - "sz(%d)\n", ioc->name, (int)sz); - goto out; - } - ioc->chain_dma_pool = pci_pool_create("chain pool", ioc->pdev, - ioc->request_sz, 16, 0); - if (!ioc->chain_dma_pool) { - printk(MPT2SAS_ERR_FMT "chain_dma_pool: pci_pool_create " - "failed\n", ioc->name); - goto out; - } - for (i = 0; i < ioc->chain_depth; i++) { - ioc->chain_lookup[i].chain_buffer = pci_pool_alloc( - ioc->chain_dma_pool , GFP_KERNEL, - &ioc->chain_lookup[i].chain_buffer_dma); - if (!ioc->chain_lookup[i].chain_buffer) { - ioc->chain_depth = i; - goto chain_done; - } - total_sz += ioc->request_sz; - } -chain_done: - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "chain pool depth" - "(%d), frame_size(%d), pool_size(%d kB)\n", ioc->name, - ioc->chain_depth, ioc->request_sz, ((ioc->chain_depth * - ioc->request_sz))/1024)); - - /* initialize hi-priority queue smid's */ - ioc->hpr_lookup = kcalloc(ioc->hi_priority_depth, - sizeof(struct request_tracker), GFP_KERNEL); - if (!ioc->hpr_lookup) { - printk(MPT2SAS_ERR_FMT "hpr_lookup: kcalloc failed\n", - ioc->name); - goto out; - } - ioc->hi_priority_smid = ioc->scsiio_depth + 1; - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "hi_priority(0x%p): " - "depth(%d), start smid(%d)\n", ioc->name, ioc->hi_priority, - ioc->hi_priority_depth, ioc->hi_priority_smid)); - - /* initialize internal queue smid's */ - ioc->internal_lookup = kcalloc(ioc->internal_depth, - sizeof(struct request_tracker), GFP_KERNEL); - if (!ioc->internal_lookup) { - printk(MPT2SAS_ERR_FMT "internal_lookup: kcalloc failed\n", - ioc->name); - goto out; - } - ioc->internal_smid = ioc->hi_priority_smid + ioc->hi_priority_depth; - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "internal(0x%p): " - "depth(%d), start smid(%d)\n", ioc->name, ioc->internal, - ioc->internal_depth, ioc->internal_smid)); - - /* sense buffers, 4 byte align */ - sz = ioc->scsiio_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->scsiio_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; - } - ioc->reply_dma_min_address = (u32)(ioc->reply_dma); - ioc->reply_dma_max_address = (u32)(ioc->reply_dma) + sz; - 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; - - 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: - 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_INFO_FMT "%s: " - "successful 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_INFO_FMT "%s: " - "successful 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_INFO_FMT "%s: " - "successful 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; - __le32 *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, NO_SLEEP))) { - 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 = (__le32 *)reply; - printk(KERN_INFO "\toffset:data\n"); - for (i = 0; i < reply_bytes/4; i++) - printk(KERN_INFO "\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; - bool issue_reset = false; - int rc; - void *request; - u16 wait_state_count; - - dinitprintk(ioc, printk(MPT2SAS_INFO_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; - init_completion(&ioc->base_cmds.done); - mpt2sas_base_put_smid_default(ioc, smid); - 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 = true; - 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; - bool issue_reset = false; - int rc; - void *request; - u16 wait_state_count; - - dinitprintk(ioc, printk(MPT2SAS_INFO_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)); - init_completion(&ioc->base_cmds.done); - mpt2sas_base_put_smid_default(ioc, smid); - 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 = true; - 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; - struct mpt2sas_port_facts *pfacts; - int mpi_reply_sz, mpi_request_sz, r; - - dinitprintk(ioc, printk(MPT2SAS_INFO_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(struct mpt2sas_port_facts)); - 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_wait_for_iocstate - Wait until the card is in READY or OPERATIONAL - * @ioc: per adapter object - * @timeout: - * @sleep_flag: CAN_SLEEP or NO_SLEEP - * - * Returns 0 for success, non-zero for failure. - */ -static int -_base_wait_for_iocstate(struct MPT2SAS_ADAPTER *ioc, int timeout, - int sleep_flag) -{ - u32 ioc_state, doorbell; - int rc; - - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - __func__)); - - if (ioc->pci_error_recovery) - return 0; - - doorbell = mpt2sas_base_get_iocstate(ioc, 0); - ioc_state = doorbell & MPI2_IOC_STATE_MASK; - dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: ioc_state(0x%08x)\n", - ioc->name, __func__, ioc_state)); - - switch (ioc_state) { - case MPI2_IOC_STATE_READY: - case MPI2_IOC_STATE_OPERATIONAL: - return 0; - } - - if (doorbell & MPI2_DOORBELL_USED) { - dhsprintk(ioc, printk(MPT2SAS_INFO_FMT - "unexpected doorbell activ!e\n", ioc->name)); - goto issue_diag_reset; - } - - if (ioc_state == MPI2_IOC_STATE_FAULT) { - mpt2sas_base_fault_info(ioc, doorbell & - MPI2_DOORBELL_DATA_MASK); - goto issue_diag_reset; - } - - 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); - return -EFAULT; - } - - issue_diag_reset: - rc = _base_diag_reset(ioc, sleep_flag); - return rc; -} - -/** - * _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; - struct mpt2sas_facts *facts; - int mpi_reply_sz, mpi_request_sz, r; - - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - __func__)); - - r = _base_wait_for_iocstate(ioc, 10, sleep_flag); - if (r) { - printk(MPT2SAS_ERR_FMT "%s: failed getting to correct state\n", - ioc->name, __func__); - return r; - } - - 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(struct mpt2sas_facts)); - 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->MaxMSIxVectors = mpi_reply.MaxMSIxVectors; - 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; - if ((facts->IOCCapabilities & - MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE)) - ioc->rdpq_array_capable = 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 - * @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, int sleep_flag) -{ - Mpi2IOCInitRequest_t mpi_request; - Mpi2IOCInitReply_t mpi_reply; - int i, r = 0; - struct timeval current_time; - u16 ioc_status; - u32 reply_post_free_array_sz = 0; - Mpi2IOCInitRDPQArrayEntry *reply_post_free_array = NULL; - dma_addr_t reply_post_free_array_dma; - - dinitprintk(ioc, printk(MPT2SAS_INFO_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 = 0; /* TODO */ - mpi_request.VP_ID = 0; - mpi_request.MsgVersion = cpu_to_le16(MPI2_VERSION); - mpi_request.HeaderVersion = cpu_to_le16(MPI2_HEADER_VERSION); - - if (_base_is_controller_msix_enabled(ioc)) - mpi_request.HostMSIxVectors = ioc->reply_queue_count; - 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); - - mpi_request.SenseBufferAddressHigh = - cpu_to_le32((u64)ioc->sense_dma >> 32); - mpi_request.SystemReplyAddressHigh = - cpu_to_le32((u64)ioc->reply_dma >> 32); - mpi_request.SystemRequestFrameBaseAddress = - cpu_to_le64((u64)ioc->request_dma); - mpi_request.ReplyFreeQueueAddress = - cpu_to_le64((u64)ioc->reply_free_dma); - - if (ioc->rdpq_array_enable) { - reply_post_free_array_sz = ioc->reply_queue_count * - sizeof(Mpi2IOCInitRDPQArrayEntry); - reply_post_free_array = pci_alloc_consistent(ioc->pdev, - reply_post_free_array_sz, &reply_post_free_array_dma); - if (!reply_post_free_array) { - printk(MPT2SAS_ERR_FMT - "reply_post_free_array: pci_alloc_consistent failed\n", - ioc->name); - r = -ENOMEM; - goto out; - } - memset(reply_post_free_array, 0, reply_post_free_array_sz); - for (i = 0; i < ioc->reply_queue_count; i++) - reply_post_free_array[i].RDPQBaseAddress = - cpu_to_le64( - (u64)ioc->reply_post[i].reply_post_free_dma); - mpi_request.MsgFlags = MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE; - mpi_request.ReplyDescriptorPostQueueAddress = - cpu_to_le64((u64)reply_post_free_array_dma); - } else { - mpi_request.ReplyDescriptorPostQueueAddress = - cpu_to_le64((u64)ioc->reply_post[0].reply_post_free_dma); - } - - /* This time stamp specifies number of milliseconds - * since epoch ~ midnight January 1, 1970. - */ - do_gettimeofday(¤t_time); - mpi_request.TimeStamp = cpu_to_le64((u64)current_time.tv_sec * 1000 + - (current_time.tv_usec / 1000)); - - if (ioc->logging_level & MPT_DEBUG_INIT) { - __le32 *mfp; - int i; - - mfp = (__le32 *)&mpi_request; - printk(KERN_INFO "\toffset:data\n"); - for (i = 0; i < sizeof(Mpi2IOCInitRequest_t)/4; i++) - printk(KERN_INFO "\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); - goto out; - } - - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS || - mpi_reply.IOCLogInfo) { - printk(MPT2SAS_ERR_FMT "%s: failed\n", ioc->name, __func__); - r = -EIO; - } - -out: - if (reply_post_free_array) - pci_free_consistent(ioc->pdev, reply_post_free_array_sz, - reply_post_free_array, - reply_post_free_array_dma); - return r; -} - -/** - * mpt2sas_port_enable_done - command completion routine for port enable - * @ioc: per adapter object - * @smid: system request message index - * @msix_index: MSIX table index supplied by the OS - * @reply: reply message frame(lower 32bit addr) - * - * Return 1 meaning mf should be freed from _base_interrupt - * 0 means the mf is freed from this function. - */ -u8 -mpt2sas_port_enable_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, - u32 reply) -{ - MPI2DefaultReply_t *mpi_reply; - u16 ioc_status; - - mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); - if (mpi_reply && mpi_reply->Function == MPI2_FUNCTION_EVENT_ACK) - return 1; - - if (ioc->port_enable_cmds.status == MPT2_CMD_NOT_USED) - return 1; - - ioc->port_enable_cmds.status |= MPT2_CMD_COMPLETE; - if (mpi_reply) { - ioc->port_enable_cmds.status |= MPT2_CMD_REPLY_VALID; - memcpy(ioc->port_enable_cmds.reply, mpi_reply, - mpi_reply->MsgLength*4); - } - ioc->port_enable_cmds.status &= ~MPT2_CMD_PENDING; - - ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK; - - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) - ioc->port_enable_failed = 1; - - if (ioc->is_driver_loading) { - if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { - mpt2sas_port_enable_complete(ioc); - return 1; - } else { - ioc->start_scan_failed = ioc_status; - ioc->start_scan = 0; - return 1; - } - } - complete(&ioc->port_enable_cmds.done); - return 1; -} - - -/** - * _base_send_port_enable - send port_enable(discovery stuff) to firmware - * @ioc: per adapter object - * @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, int sleep_flag) -{ - Mpi2PortEnableRequest_t *mpi_request; - Mpi2PortEnableReply_t *mpi_reply; - unsigned long timeleft; - int r = 0; - u16 smid; - u16 ioc_status; - - printk(MPT2SAS_INFO_FMT "sending port enable !!\n", ioc->name); - - if (ioc->port_enable_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->port_enable_cb_idx); - if (!smid) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); - return -EAGAIN; - } - - ioc->port_enable_cmds.status = MPT2_CMD_PENDING; - mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); - ioc->port_enable_cmds.smid = smid; - memset(mpi_request, 0, sizeof(Mpi2PortEnableRequest_t)); - mpi_request->Function = MPI2_FUNCTION_PORT_ENABLE; - - init_completion(&ioc->port_enable_cmds.done); - mpt2sas_base_put_smid_default(ioc, smid); - timeleft = wait_for_completion_timeout(&ioc->port_enable_cmds.done, - 300*HZ); - if (!(ioc->port_enable_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->port_enable_cmds.status & MPT2_CMD_RESET) - r = -EFAULT; - else - r = -ETIME; - goto out; - } - mpi_reply = ioc->port_enable_cmds.reply; - - ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - printk(MPT2SAS_ERR_FMT "%s: failed with (ioc_status=0x%08x)\n", - ioc->name, __func__, ioc_status); - r = -EFAULT; - goto out; - } - out: - ioc->port_enable_cmds.status = MPT2_CMD_NOT_USED; - printk(MPT2SAS_INFO_FMT "port enable: %s\n", ioc->name, ((r == 0) ? - "SUCCESS" : "FAILED")); - return r; -} - -/** - * mpt2sas_port_enable - initiate firmware discovery (don't wait for reply) - * @ioc: per adapter object - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_port_enable(struct MPT2SAS_ADAPTER *ioc) -{ - Mpi2PortEnableRequest_t *mpi_request; - u16 smid; - - printk(MPT2SAS_INFO_FMT "sending port enable !!\n", ioc->name); - - if (ioc->port_enable_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->port_enable_cb_idx); - if (!smid) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); - return -EAGAIN; - } - - ioc->port_enable_cmds.status = MPT2_CMD_PENDING; - mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); - ioc->port_enable_cmds.smid = smid; - memset(mpi_request, 0, sizeof(Mpi2PortEnableRequest_t)); - mpi_request->Function = MPI2_FUNCTION_PORT_ENABLE; - - mpt2sas_base_put_smid_default(ioc, smid); - return 0; -} - -/** - * _base_determine_wait_on_discovery - desposition - * @ioc: per adapter object - * - * Decide whether to wait on discovery to complete. Used to either - * locate boot device, or report volumes ahead of physical devices. - * - * Returns 1 for wait, 0 for don't wait - */ -static int -_base_determine_wait_on_discovery(struct MPT2SAS_ADAPTER *ioc) -{ - /* We wait for discovery to complete if IR firmware is loaded. - * The sas topology events arrive before PD events, so we need time to - * turn on the bit in ioc->pd_handles to indicate PD - * Also, it maybe required to report Volumes ahead of physical - * devices when MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING is set. - */ - if (ioc->ir_firmware) - return 1; - - /* if no Bios, then we don't need to wait */ - if (!ioc->bios_pg3.BiosVersion) - return 0; - - /* Bios is present, then we drop down here. - * - * If there any entries in the Bios Page 2, then we wait - * for discovery to complete. - */ - - /* Current Boot Device */ - if ((ioc->bios_pg2.CurrentBootDeviceForm & - MPI2_BIOSPAGE2_FORM_MASK) == - MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED && - /* Request Boot Device */ - (ioc->bios_pg2.ReqBootDeviceForm & - MPI2_BIOSPAGE2_FORM_MASK) == - MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED && - /* Alternate Request Boot Device */ - (ioc->bios_pg2.ReqAltBootDeviceForm & - MPI2_BIOSPAGE2_FORM_MASK) == - MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED) - return 0; - - return 1; -} - - -/** - * _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 - * @sleep_flag: CAN_SLEEP or NO_SLEEP - * - * Returns 0 for success, non-zero for failure. - */ -static int -_base_event_notification(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) -{ - Mpi2EventNotificationRequest_t *mpi_request; - unsigned long timeleft; - u16 smid; - int r = 0; - int i; - - dinitprintk(ioc, printk(MPT2SAS_INFO_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 = 0; /* TODO */ - mpi_request->VP_ID = 0; - for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++) - mpi_request->EventMasks[i] = - cpu_to_le32(ioc->event_masks[i]); - init_completion(&ioc->base_cmds.done); - mpt2sas_base_put_smid_default(ioc, smid); - 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_INFO_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, 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); - drsprintk(ioc, printk(MPT2SAS_INFO_FMT "clear interrupts\n", - ioc->name)); - - count = 0; - do { - /* Write magic sequence to WriteSequence register - * Loop until in diagnostic mode - */ - drsprintk(ioc, printk(MPT2SAS_INFO_FMT "write magic " - "sequence\n", ioc->name)); - writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &ioc->chip->WriteSequence); - writel(MPI2_WRSEQ_1ST_KEY_VALUE, &ioc->chip->WriteSequence); - 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_INFO_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_INFO_FMT "diag reset: issued\n", - ioc->name)); - writel(host_diagnostic | MPI2_DIAG_RESET_ADAPTER, - &ioc->chip->HostDiagnostic); - - /* This delay allows the chip PCIe hardware time to finish reset tasks*/ - if (sleep_flag == CAN_SLEEP) - msleep(MPI2_HARD_RESET_PCIE_FIRST_READ_DELAY_MICRO_SEC/1000); - else - mdelay(MPI2_HARD_RESET_PCIE_FIRST_READ_DELAY_MICRO_SEC/1000); - - /* Approximately 300 second max wait */ - for (count = 0; count < (300000000 / - MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC); count++) { - - host_diagnostic = readl(&ioc->chip->HostDiagnostic); - - if (host_diagnostic == 0xFFFFFFFF) - goto out; - if (!(host_diagnostic & MPI2_DIAG_RESET_ADAPTER)) - break; - - /* Wait to pass the second read delay window */ - if (sleep_flag == CAN_SLEEP) - msleep(MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC - /1000); - else - mdelay(MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC - /1000); - } - - if (host_diagnostic & MPI2_DIAG_HCB_MODE) { - - drsprintk(ioc, printk(MPT2SAS_INFO_FMT "restart the adapter " - "assuming the HCB Address points to good F/W\n", - ioc->name)); - host_diagnostic &= ~MPI2_DIAG_BOOT_DEVICE_SELECT_MASK; - host_diagnostic |= MPI2_DIAG_BOOT_DEVICE_SELECT_HCDW; - writel(host_diagnostic, &ioc->chip->HostDiagnostic); - - drsprintk(ioc, printk(MPT2SAS_INFO_FMT - "re-enable the HCDW\n", ioc->name)); - writel(hcb_size | MPI2_HCB_SIZE_HCB_ENABLE, - &ioc->chip->HCBSize); - } - - drsprintk(ioc, printk(MPT2SAS_INFO_FMT "restart the adapter\n", - ioc->name)); - writel(host_diagnostic & ~MPI2_DIAG_HOLD_IOC_RESET, - &ioc->chip->HostDiagnostic); - - drsprintk(ioc, printk(MPT2SAS_INFO_FMT "disable writes to the " - "diagnostic register\n", ioc->name)); - writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &ioc->chip->WriteSequence); - - drsprintk(ioc, printk(MPT2SAS_INFO_FMT "Wait for FW to go to the " - "READY state\n", ioc->name)); - ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY, 20, - sleep_flag); - 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; - } - - 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; - int rc; - - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - __func__)); - - if (ioc->pci_error_recovery) - return 0; - - ioc_state = mpt2sas_base_get_iocstate(ioc, 0); - dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: ioc_state(0x%08x)\n", - ioc->name, __func__, ioc_state)); - - if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_READY) - return 0; - - if (ioc_state & MPI2_DOORBELL_USED) { - dhsprintk(ioc, printk(MPT2SAS_INFO_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))) { - ioc->ioc_reset_count++; - return 0; - } - - issue_diag_reset: - rc = _base_diag_reset(ioc, CAN_SLEEP); - ioc->ioc_reset_count++; - return rc; -} - -/** - * _base_make_ioc_operational - put controller in OPERATIONAL state - * @ioc: per adapter object - * @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, int sleep_flag) -{ - int r, i; - unsigned long flags; - u32 reply_address; - u16 smid; - struct _tr_list *delayed_tr, *delayed_tr_next; - u8 hide_flag; - struct adapter_reply_queue *reply_q; - long reply_post_free; - u32 reply_post_free_sz, index = 0; - - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - __func__)); - - /* clean the delayed target reset list */ - list_for_each_entry_safe(delayed_tr, delayed_tr_next, - &ioc->delayed_tr_list, list) { - list_del(&delayed_tr->list); - kfree(delayed_tr); - } - - list_for_each_entry_safe(delayed_tr, delayed_tr_next, - &ioc->delayed_tr_volume_list, list) { - list_del(&delayed_tr->list); - kfree(delayed_tr); - } - - /* initialize the scsi lookup free list */ - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - INIT_LIST_HEAD(&ioc->free_list); - smid = 1; - for (i = 0; i < ioc->scsiio_depth; i++, smid++) { - INIT_LIST_HEAD(&ioc->scsi_lookup[i].chain_list); - ioc->scsi_lookup[i].cb_idx = 0xFF; - ioc->scsi_lookup[i].smid = smid; - ioc->scsi_lookup[i].scmd = NULL; - ioc->scsi_lookup[i].direct_io = 0; - list_add_tail(&ioc->scsi_lookup[i].tracker_list, - &ioc->free_list); - } - - /* hi-priority queue */ - INIT_LIST_HEAD(&ioc->hpr_free_list); - smid = ioc->hi_priority_smid; - for (i = 0; i < ioc->hi_priority_depth; i++, smid++) { - ioc->hpr_lookup[i].cb_idx = 0xFF; - ioc->hpr_lookup[i].smid = smid; - list_add_tail(&ioc->hpr_lookup[i].tracker_list, - &ioc->hpr_free_list); - } - - /* internal queue */ - INIT_LIST_HEAD(&ioc->internal_free_list); - smid = ioc->internal_smid; - for (i = 0; i < ioc->internal_depth; i++, smid++) { - ioc->internal_lookup[i].cb_idx = 0xFF; - ioc->internal_lookup[i].smid = smid; - list_add_tail(&ioc->internal_lookup[i].tracker_list, - &ioc->internal_free_list); - } - - /* chain pool */ - INIT_LIST_HEAD(&ioc->free_chain_list); - for (i = 0; i < ioc->chain_depth; i++) - list_add_tail(&ioc->chain_lookup[i].tracker_list, - &ioc->free_chain_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 queues */ - if (ioc->is_driver_loading) - _base_assign_reply_queues(ioc); - - /* initialize Reply Post Free Queue */ - reply_post_free_sz = ioc->reply_post_queue_depth * - sizeof(Mpi2DefaultReplyDescriptor_t); - reply_post_free = (long)ioc->reply_post[index].reply_post_free; - list_for_each_entry(reply_q, &ioc->reply_queue_list, list) { - reply_q->reply_post_host_index = 0; - reply_q->reply_post_free = (Mpi2ReplyDescriptorsUnion_t *) - reply_post_free; - for (i = 0; i < ioc->reply_post_queue_depth; i++) - reply_q->reply_post_free[i].Words = - cpu_to_le64(ULLONG_MAX); - if (!_base_is_controller_msix_enabled(ioc)) - goto skip_init_reply_post_free_queue; - /* - * If RDPQ is enabled, switch to the next allocation. - * Otherwise advance within the contiguous region. - */ - if (ioc->rdpq_array_enable) - reply_post_free = (long) - ioc->reply_post[++index].reply_post_free; - else - reply_post_free += reply_post_free_sz; - } - skip_init_reply_post_free_queue: - - r = _base_send_ioc_init(ioc, sleep_flag); - if (r) - return r; - - /* initialize reply free host index */ - ioc->reply_free_host_index = ioc->reply_free_queue_depth - 1; - writel(ioc->reply_free_host_index, &ioc->chip->ReplyFreeHostIndex); - - /* initialize reply post host index */ - list_for_each_entry(reply_q, &ioc->reply_queue_list, list) { - writel(reply_q->msix_index << MPI2_RPHI_MSIX_INDEX_SHIFT, - &ioc->chip->ReplyPostHostIndex); - if (!_base_is_controller_msix_enabled(ioc)) - goto skip_init_reply_post_host_index; - } - - skip_init_reply_post_host_index: - - _base_unmask_interrupts(ioc); - - r = _base_event_notification(ioc, sleep_flag); - if (r) - return r; - - if (sleep_flag == CAN_SLEEP) - _base_static_config_pages(ioc); - - - if (ioc->is_driver_loading) { - if (ioc->is_warpdrive && ioc->manu_pg10.OEMIdentifier - == 0x80) { - hide_flag = (u8) ( - le32_to_cpu(ioc->manu_pg10.OEMSpecificFlags0) & - MFG_PAGE10_HIDE_SSDS_MASK); - if (hide_flag != MFG_PAGE10_HIDE_SSDS_MASK) - ioc->mfg_pg10_hide_flag = hide_flag; - } - ioc->wait_for_discovery_to_complete = - _base_determine_wait_on_discovery(ioc); - return r; /* scan_start and scan_finished support */ - } - r = _base_send_port_enable(ioc, 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_INFO_FMT "%s\n", ioc->name, - __func__)); - - /* synchronizing freeing resource with pci_access_mutex lock */ - mutex_lock(&ioc->pci_access_mutex); - if (ioc->chip_phys && ioc->chip) { - _base_mask_interrupts(ioc); - ioc->shost_recovery = 1; - _base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET); - ioc->shost_recovery = 0; - } - - _base_free_irq(ioc); - _base_disable_msix(ioc); - - if (ioc->chip_phys && ioc->chip) - iounmap(ioc->chip); - ioc->chip_phys = 0; - - if (pci_is_enabled(pdev)) { - pci_release_selected_regions(ioc->pdev, ioc->bars); - pci_disable_pcie_error_reporting(pdev); - pci_disable_device(pdev); - } - mutex_unlock(&ioc->pci_access_mutex); - 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; - int cpu_id, last_cpu_id = 0; - - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - __func__)); - - /* setup cpu_msix_table */ - ioc->cpu_count = num_online_cpus(); - for_each_online_cpu(cpu_id) - last_cpu_id = cpu_id; - ioc->cpu_msix_table_sz = last_cpu_id + 1; - ioc->cpu_msix_table = kzalloc(ioc->cpu_msix_table_sz, GFP_KERNEL); - ioc->reply_queue_count = 1; - if (!ioc->cpu_msix_table) { - dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "allocation for " - "cpu_msix_table failed!!!\n", ioc->name)); - r = -ENOMEM; - goto out_free_resources; - } - - if (ioc->is_warpdrive) { - ioc->reply_post_host_index = kcalloc(ioc->cpu_msix_table_sz, - sizeof(resource_size_t *), GFP_KERNEL); - if (!ioc->reply_post_host_index) { - dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "allocation " - "for cpu_msix_table failed!!!\n", ioc->name)); - r = -ENOMEM; - goto out_free_resources; - } - } - - ioc->rdpq_array_enable_assigned = 0; - ioc->dma_mask = 0; - r = mpt2sas_base_map_resources(ioc); - if (r) - goto out_free_resources; - - if (ioc->is_warpdrive) { - ioc->reply_post_host_index[0] = (resource_size_t __iomem *) - &ioc->chip->ReplyPostHostIndex; - - for (i = 1; i < ioc->cpu_msix_table_sz; i++) - ioc->reply_post_host_index[i] = - (resource_size_t __iomem *) - ((u8 __iomem *)&ioc->chip->Doorbell + (0x4000 + ((i - 1) - * 4))); - } - - pci_set_drvdata(ioc->pdev, ioc->shost); - r = _base_get_ioc_facts(ioc, CAN_SLEEP); - if (r) - goto out_free_resources; - - r = _base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET); - if (r) - goto out_free_resources; - - ioc->pfacts = kcalloc(ioc->facts.NumberOfPorts, - sizeof(struct mpt2sas_port_facts), GFP_KERNEL); - if (!ioc->pfacts) { - r = -ENOMEM; - 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_allocate_memory_pools(ioc, CAN_SLEEP); - if (r) - goto out_free_resources; - - init_waitqueue_head(&ioc->reset_wq); - /* allocate memory pd handle bitmask list */ - ioc->pd_handles_sz = (ioc->facts.MaxDevHandle / 8); - if (ioc->facts.MaxDevHandle % 8) - ioc->pd_handles_sz++; - ioc->pd_handles = kzalloc(ioc->pd_handles_sz, - GFP_KERNEL); - if (!ioc->pd_handles) { - r = -ENOMEM; - goto out_free_resources; - } - ioc->blocking_handles = kzalloc(ioc->pd_handles_sz, - GFP_KERNEL); - if (!ioc->blocking_handles) { - r = -ENOMEM; - goto out_free_resources; - } - ioc->fwfault_debug = mpt2sas_fwfault_debug; - - /* base internal command bits */ - mutex_init(&ioc->base_cmds.mutex); - ioc->base_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); - ioc->base_cmds.status = MPT2_CMD_NOT_USED; - - /* port_enable command bits */ - ioc->port_enable_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); - ioc->port_enable_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); - - /* scsih internal command bits */ - ioc->scsih_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); - ioc->scsih_cmds.status = MPT2_CMD_NOT_USED; - mutex_init(&ioc->scsih_cmds.mutex); - - /* 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); - - /* 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); - - /* ctl module internal command bits */ - ioc->ctl_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); - ioc->ctl_cmds.sense = kzalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL); - ioc->ctl_cmds.status = MPT2_CMD_NOT_USED; - mutex_init(&ioc->ctl_cmds.mutex); - - if (!ioc->base_cmds.reply || !ioc->transport_cmds.reply || - !ioc->scsih_cmds.reply || !ioc->tm_cmds.reply || - !ioc->config_cmds.reply || !ioc->ctl_cmds.reply || - !ioc->ctl_cmds.sense) { - r = -ENOMEM; - goto out_free_resources; - } - - if (!ioc->base_cmds.reply || !ioc->transport_cmds.reply || - !ioc->scsih_cmds.reply || !ioc->tm_cmds.reply || - !ioc->config_cmds.reply || !ioc->ctl_cmds.reply) { - r = -ENOMEM; - goto out_free_resources; - } - - 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_LOG_ENTRY_ADDED); - _base_unmask_events(ioc, MPI2_EVENT_TEMP_THRESHOLD); - r = _base_make_ioc_operational(ioc, CAN_SLEEP); - if (r) - goto out_free_resources; - - ioc->non_operational_loop = 0; - - return 0; - - out_free_resources: - - ioc->remove_host = 1; - mpt2sas_base_free_resources(ioc); - _base_release_memory_pools(ioc); - pci_set_drvdata(ioc->pdev, NULL); - kfree(ioc->cpu_msix_table); - if (ioc->is_warpdrive) - kfree(ioc->reply_post_host_index); - kfree(ioc->pd_handles); - kfree(ioc->blocking_handles); - kfree(ioc->tm_cmds.reply); - kfree(ioc->transport_cmds.reply); - kfree(ioc->scsih_cmds.reply); - kfree(ioc->config_cmds.reply); - kfree(ioc->base_cmds.reply); - kfree(ioc->port_enable_cmds.reply); - kfree(ioc->ctl_cmds.reply); - kfree(ioc->ctl_cmds.sense); - kfree(ioc->pfacts); - ioc->ctl_cmds.reply = NULL; - ioc->base_cmds.reply = NULL; - ioc->tm_cmds.reply = NULL; - ioc->scsih_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) -{ - - dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - __func__)); - - mpt2sas_base_stop_watchdog(ioc); - mpt2sas_base_free_resources(ioc); - _base_release_memory_pools(ioc); - pci_set_drvdata(ioc->pdev, NULL); - kfree(ioc->cpu_msix_table); - if (ioc->is_warpdrive) - kfree(ioc->reply_post_host_index); - kfree(ioc->pd_handles); - kfree(ioc->blocking_handles); - kfree(ioc->pfacts); - kfree(ioc->ctl_cmds.reply); - kfree(ioc->ctl_cmds.sense); - kfree(ioc->base_cmds.reply); - kfree(ioc->port_enable_cmds.reply); - kfree(ioc->tm_cmds.reply); - kfree(ioc->transport_cmds.reply); - kfree(ioc->scsih_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) -{ - mpt2sas_scsih_reset_handler(ioc, reset_phase); - mpt2sas_ctl_reset_handler(ioc, reset_phase); - switch (reset_phase) { - case MPT2_IOC_PRE_RESET: - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " - "MPT2_IOC_PRE_RESET\n", ioc->name, __func__)); - break; - case MPT2_IOC_AFTER_RESET: - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " - "MPT2_IOC_AFTER_RESET\n", ioc->name, __func__)); - if (ioc->transport_cmds.status & MPT2_CMD_PENDING) { - ioc->transport_cmds.status |= MPT2_CMD_RESET; - 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->port_enable_cmds.status & MPT2_CMD_PENDING) { - ioc->port_enable_failed = 1; - ioc->port_enable_cmds.status |= MPT2_CMD_RESET; - mpt2sas_base_free_smid(ioc, ioc->port_enable_cmds.smid); - if (ioc->is_driver_loading) { - ioc->start_scan_failed = - MPI2_IOCSTATUS_INTERNAL_ERROR; - ioc->start_scan = 0; - ioc->port_enable_cmds.status = - MPT2_CMD_NOT_USED; - } else - complete(&ioc->port_enable_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); - ioc->config_cmds.smid = USHRT_MAX; - complete(&ioc->config_cmds.done); - } - break; - case MPT2_IOC_DONE_RESET: - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " - "MPT2_IOC_DONE_RESET\n", ioc->name, __func__)); - break; - } -} - -/** - * _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->scsiio_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, 10 * 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; - unsigned long flags; - - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name, - __func__)); - - if (ioc->pci_error_recovery) { - printk(MPT2SAS_ERR_FMT "%s: pci error recovery reset\n", - ioc->name, __func__); - r = 0; - goto out_unlocked; - } - - if (mpt2sas_fwfault_debug) - mpt2sas_halt_firmware(ioc); - - /* TODO - What we really should be doing is pulling - * out all the code associated with NO_SLEEP; its never used. - * That is legacy code from mpt fusion driver, ported over. - * I will leave this BUG_ON here for now till its been resolved. - */ - BUG_ON(sleep_flag == NO_SLEEP); - - /* wait for an active reset in progress to complete */ - if (!mutex_trylock(&ioc->reset_in_progress_mutex)) { - do { - ssleep(1); - } while (ioc->shost_recovery == 1); - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit\n", ioc->name, - __func__)); - return ioc->ioc_reset_in_progress_status; - } - - spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); - ioc->shost_recovery = 1; - spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); - - _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); - - /* If this hard reset is called while port enable is active, then - * there is no reason to call make_ioc_operational - */ - if (ioc->is_driver_loading && ioc->port_enable_failed) { - ioc->remove_host = 1; - r = -EFAULT; - goto out; - } - - r = _base_get_ioc_facts(ioc, CAN_SLEEP); - if (r) - goto out; - - if (ioc->rdpq_array_enable && !ioc->rdpq_array_capable) - panic("%s: Issue occurred with flashing controller firmware." - "Please reboot the system and ensure that the correct" - " firmware version is running\n", ioc->name); - - r = _base_make_ioc_operational(ioc, sleep_flag); - if (!r) - _base_reset_handler(ioc, MPT2_IOC_DONE_RESET); - out: - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: %s\n", - ioc->name, __func__, ((r == 0) ? "SUCCESS" : "FAILED"))); - - spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); - ioc->ioc_reset_in_progress_status = r; - ioc->shost_recovery = 0; - spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); - mutex_unlock(&ioc->reset_in_progress_mutex); - - out_unlocked: - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit\n", ioc->name, - __func__)); - return r; -} diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h deleted file mode 100644 index 97ea360c6920..000000000000 --- a/drivers/scsi/mpt2sas/mpt2sas_base.h +++ /dev/null @@ -1,1235 +0,0 @@ -/* - * 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-2014 LSI Corporation - * Copyright (C) 20013-2014 Avago Technologies - * (mailto: MPT-FusionLinux.pdl@avagotech.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 <scsi/scsi_eh.h> - -#include "mpt2sas_debug.h" - -/* driver versioning info */ -#define MPT2SAS_DRIVER_NAME "mpt2sas" -#define MPT2SAS_AUTHOR "Avago Technologies <MPT-FusionLinux.pdl@avagotech.com>" -#define MPT2SAS_DESCRIPTION "LSI MPT Fusion SAS 2.0 Device Driver" -#define MPT2SAS_DRIVER_VERSION "20.100.00.00" -#define MPT2SAS_MAJOR_VERSION 20 -#define MPT2SAS_MINOR_VERSION 100 -#define MPT2SAS_BUILD_VERSION 00 -#define MPT2SAS_RELEASE_VERSION 00 - -/* - * 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_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 - -/* - * Dell HBA branding - */ -#define MPT2SAS_DELL_BRANDING_SIZE 32 - -#define MPT2SAS_DELL_6GBPS_SAS_HBA_BRANDING "Dell 6Gbps SAS HBA" -#define MPT2SAS_DELL_PERC_H200_ADAPTER_BRANDING "Dell PERC H200 Adapter" -#define MPT2SAS_DELL_PERC_H200_INTEGRATED_BRANDING "Dell PERC H200 Integrated" -#define MPT2SAS_DELL_PERC_H200_MODULAR_BRANDING "Dell PERC H200 Modular" -#define MPT2SAS_DELL_PERC_H200_EMBEDDED_BRANDING "Dell PERC H200 Embedded" -#define MPT2SAS_DELL_PERC_H200_BRANDING "Dell PERC H200" -#define MPT2SAS_DELL_6GBPS_SAS_BRANDING "Dell 6Gbps SAS" - -/* - * Dell HBA SSDIDs - */ -#define MPT2SAS_DELL_6GBPS_SAS_HBA_SSDID 0x1F1C -#define MPT2SAS_DELL_PERC_H200_ADAPTER_SSDID 0x1F1D -#define MPT2SAS_DELL_PERC_H200_INTEGRATED_SSDID 0x1F1E -#define MPT2SAS_DELL_PERC_H200_MODULAR_SSDID 0x1F1F -#define MPT2SAS_DELL_PERC_H200_EMBEDDED_SSDID 0x1F20 -#define MPT2SAS_DELL_PERC_H200_SSDID 0x1F21 -#define MPT2SAS_DELL_6GBPS_SAS_SSDID 0x1F22 - -/* - * Intel HBA branding - */ -#define MPT2SAS_INTEL_RMS25JB080_BRANDING \ - "Intel(R) Integrated RAID Module RMS25JB080" -#define MPT2SAS_INTEL_RMS25JB040_BRANDING \ - "Intel(R) Integrated RAID Module RMS25JB040" -#define MPT2SAS_INTEL_RMS25KB080_BRANDING \ - "Intel(R) Integrated RAID Module RMS25KB080" -#define MPT2SAS_INTEL_RMS25KB040_BRANDING \ - "Intel(R) Integrated RAID Module RMS25KB040" -#define MPT2SAS_INTEL_RMS25LB040_BRANDING \ - "Intel(R) Integrated RAID Module RMS25LB040" -#define MPT2SAS_INTEL_RMS25LB080_BRANDING \ - "Intel(R) Integrated RAID Module RMS25LB080" -#define MPT2SAS_INTEL_RMS2LL080_BRANDING \ - "Intel Integrated RAID Module RMS2LL080" -#define MPT2SAS_INTEL_RMS2LL040_BRANDING \ - "Intel Integrated RAID Module RMS2LL040" -#define MPT2SAS_INTEL_RS25GB008_BRANDING \ - "Intel(R) RAID Controller RS25GB008" -#define MPT2SAS_INTEL_SSD910_BRANDING \ - "Intel(R) SSD 910 Series" -/* - * Intel HBA SSDIDs - */ -#define MPT2SAS_INTEL_RMS25JB080_SSDID 0x3516 -#define MPT2SAS_INTEL_RMS25JB040_SSDID 0x3517 -#define MPT2SAS_INTEL_RMS25KB080_SSDID 0x3518 -#define MPT2SAS_INTEL_RMS25KB040_SSDID 0x3519 -#define MPT2SAS_INTEL_RMS25LB040_SSDID 0x351A -#define MPT2SAS_INTEL_RMS25LB080_SSDID 0x351B -#define MPT2SAS_INTEL_RMS2LL080_SSDID 0x350E -#define MPT2SAS_INTEL_RMS2LL040_SSDID 0x350F -#define MPT2SAS_INTEL_RS25GB008_SSDID 0x3000 -#define MPT2SAS_INTEL_SSD910_SSDID 0x3700 - -/* - * HP HBA branding - */ -#define MPT2SAS_HP_3PAR_SSVID 0x1590 -#define MPT2SAS_HP_2_4_INTERNAL_BRANDING "HP H220 Host Bus Adapter" -#define MPT2SAS_HP_2_4_EXTERNAL_BRANDING "HP H221 Host Bus Adapter" -#define MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_BRANDING "HP H222 Host Bus Adapter" -#define MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_BRANDING "HP H220i Host Bus Adapter" -#define MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_BRANDING "HP H210i Host Bus Adapter" - -/* - * HO HBA SSDIDs - */ -#define MPT2SAS_HP_2_4_INTERNAL_SSDID 0x0041 -#define MPT2SAS_HP_2_4_EXTERNAL_SSDID 0x0042 -#define MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_SSDID 0x0043 -#define MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_SSDID 0x0044 -#define MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_SSDID 0x0046 - -/* - * WarpDrive Specific Log codes - */ - -#define MPT2_WARPDRIVE_LOGENTRY (0x8002) -#define MPT2_WARPDRIVE_LC_SSDT (0x41) -#define MPT2_WARPDRIVE_LC_SSDLW (0x43) -#define MPT2_WARPDRIVE_LC_SSDLF (0x44) -#define MPT2_WARPDRIVE_LC_BRMF (0x4D) - -/* - * 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 - * @raid_device: raid_device pointer to access volume data - * @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. - * @sdev: The sas_device associated with this target - */ -struct MPT2SAS_TARGET { - struct scsi_target *starget; - u64 sas_address; - struct _raid_device *raid_device; - u16 handle; - int num_luns; - u32 flags; - u8 deleted; - u8 tm_busy; - struct _sas_device *sdev; -}; - - -/* - * 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 - */ - -/* OEM Identifiers */ -#define MFG10_OEM_ID_INVALID (0x00000000) -#define MFG10_OEM_ID_DELL (0x00000001) -#define MFG10_OEM_ID_FSC (0x00000002) -#define MFG10_OEM_ID_SUN (0x00000003) -#define MFG10_OEM_ID_IBM (0x00000004) - -/* GENERIC Flags 0*/ -#define MFG10_GF0_OCE_DISABLED (0x00000001) -#define MFG10_GF0_R1E_DRIVE_COUNT (0x00000002) -#define MFG10_GF0_R10_DISPLAY (0x00000004) -#define MFG10_GF0_SSD_DATA_SCRUB_DISABLE (0x00000008) -#define MFG10_GF0_SINGLE_DRIVE_R0 (0x00000010) - -/* OEM Specific Flags will come from OEM specific header files */ -typedef struct _MPI2_CONFIG_PAGE_MAN_10 { - MPI2_CONFIG_PAGE_HEADER Header; /* 00h */ - U8 OEMIdentifier; /* 04h */ - U8 Reserved1; /* 05h */ - U16 Reserved2; /* 08h */ - U32 Reserved3; /* 0Ch */ - U32 GenericFlags0; /* 10h */ - U32 GenericFlags1; /* 14h */ - U32 Reserved4; /* 18h */ - U32 OEMSpecificFlags0; /* 1Ch */ - U32 OEMSpecificFlags1; /* 20h */ - U32 Reserved5[18]; /* 24h-60h*/ -} MPI2_CONFIG_PAGE_MAN_10, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_10, - Mpi2ManufacturingPage10_t, MPI2_POINTER pMpi2ManufacturingPage10_t; - -#define MFG_PAGE10_HIDE_SSDS_MASK (0x00000003) -#define MFG_PAGE10_HIDE_ALL_DISKS (0x00) -#define MFG_PAGE10_EXPOSE_ALL_DISKS (0x01) -#define MFG_PAGE10_HIDE_IF_VOL_PRESENT (0x02) - - -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 - * @sense: sense data - * @status: MPT2_CMD_XXX status - * @smid: system message id - */ -struct _internal_cmd { - struct mutex mutex; - struct completion done; - void *reply; - void *sense; - u16 status; - u16 smid; -}; - - -/** - * 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 - * @sas_address_parent: sas address of parent expander or sas host - * @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 - * @phy: phy identifier provided in sas device page 0 - * @responding: used in _scsih_sas_device_mark_responding - * @pfa_led_on: flag for PFA LED status - */ -struct _sas_device { - struct list_head list; - struct scsi_target *starget; - u64 sas_address; - u64 device_name; - u16 handle; - u64 sas_address_parent; - u16 enclosure_handle; - u64 enclosure_logical_id; - u16 volume_handle; - u64 volume_wwid; - u32 device_info; - int id; - int channel; - u16 slot; - u8 phy; - u8 responding; - u8 pfa_led_on; - struct kref refcount; -}; - -static inline void sas_device_get(struct _sas_device *s) -{ - kref_get(&s->refcount); -} - -static inline void sas_device_free(struct kref *r) -{ - kfree(container_of(r, struct _sas_device, refcount)); -} - -static inline void sas_device_put(struct _sas_device *s) -{ - kref_put(&s->refcount, sas_device_free); -} - -/** - * 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 - * @block_size: Block size of the volume - * @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 - * @percent_complete: resync percent complete - * @direct_io_enabled: Whether direct io to PDs are allowed or not - * @stripe_exponent: X where 2powX is the stripe sz in blocks - * @block_exponent: X where 2powX is the block sz in bytes - * @max_lba: Maximum number of LBA in the volume - * @stripe_sz: Stripe Size of the volume - * @device_info: Device info of the volume member disk - * @pd_handle: Array of handles of the physical drives for direct I/O in le16 - */ -#define MPT_MAX_WARPDRIVE_PDS 8 -struct _raid_device { - struct list_head list; - struct scsi_target *starget; - struct scsi_device *sdev; - u64 wwid; - u16 handle; - u16 block_sz; - int id; - int channel; - u8 volume_type; - u8 num_pds; - u8 responding; - u8 percent_complete; - u8 direct_io_enabled; - u8 stripe_exponent; - u8 block_exponent; - u64 max_lba; - u32 stripe_sz; - u32 device_info; - u16 pd_handle[MPT_MAX_WARPDRIVE_PDS]; -}; - -/** - * 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 - * @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; - 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 - * @phy_belongs_to_port: port has been created for this phy - */ -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; - u8 phy_belongs_to_port; -}; - -/** - * 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 - * @sas_address_parent: sas address of parent expander or sas host - * @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; - u64 sas_address_parent; - 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 chain_tracker - firmware chain tracker - * @chain_buffer: chain buffer - * @chain_buffer_dma: physical address - * @tracker_list: list of free request (ioc->free_chain_list) - */ -struct chain_tracker { - void *chain_buffer; - dma_addr_t chain_buffer_dma; - struct list_head tracker_list; -}; - -/** - * struct scsiio_tracker - scsi mf request tracker - * @smid: system message id - * @scmd: scsi request pointer - * @cb_idx: callback index - * @direct_io: To indicate whether I/O is direct (WARPDRIVE) - * @chain_list: list of chains associated to this IO - * @tracker_list: list of free request (ioc->free_list) - */ -struct scsiio_tracker { - u16 smid; - struct scsi_cmnd *scmd; - u8 cb_idx; - u8 direct_io; - struct list_head chain_list; - struct list_head tracker_list; -}; - -/** - * struct request_tracker - firmware request tracker - * @smid: system message id - * @cb_idx: callback index - * @tracker_list: list of free request (ioc->free_list) - */ -struct request_tracker { - u16 smid; - u8 cb_idx; - struct list_head tracker_list; -}; - -/** - * struct _tr_list - target reset list - * @handle: device handle - * @state: state machine - */ -struct _tr_list { - struct list_head list; - u16 handle; - u16 state; -}; - -typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr); - -/** - * struct adapter_reply_queue - the reply queue struct - * @ioc: per adapter object - * @msix_index: msix index into vector table - * @vector: irq vector - * @reply_post_host_index: head index in the pool where FW completes IO - * @reply_post_free: reply post base virt address - * @name: the name registered to request_irq() - * @busy: isr is actively processing replies on another cpu - * @list: this list -*/ -struct adapter_reply_queue { - struct MPT2SAS_ADAPTER *ioc; - u8 msix_index; - unsigned int vector; - u32 reply_post_host_index; - Mpi2ReplyDescriptorsUnion_t *reply_post_free; - char name[MPT_NAME_LENGTH]; - atomic_t busy; - cpumask_var_t affinity_hint; - struct list_head list; -}; - -/* IOC Facts and Port Facts converted from little endian to cpu */ -union mpi2_version_union { - MPI2_VERSION_STRUCT Struct; - u32 Word; -}; - -struct mpt2sas_facts { - u16 MsgVersion; - u16 HeaderVersion; - u8 IOCNumber; - u8 VP_ID; - u8 VF_ID; - u16 IOCExceptions; - u16 IOCStatus; - u32 IOCLogInfo; - u8 MaxChainDepth; - u8 WhoInit; - u8 NumberOfPorts; - u8 MaxMSIxVectors; - u16 RequestCredit; - u16 ProductID; - u32 IOCCapabilities; - union mpi2_version_union FWVersion; - u16 IOCRequestFrameSize; - u16 Reserved3; - u16 MaxInitiators; - u16 MaxTargets; - u16 MaxSasExpanders; - u16 MaxEnclosures; - u16 ProtocolFlags; - u16 HighPriorityCredit; - u16 MaxReplyDescriptorPostQueueDepth; - u8 ReplyFrameSize; - u8 MaxVolumes; - u16 MaxDevHandle; - u16 MaxPersistentEntries; - u16 MinDevHandle; -}; - -struct mpt2sas_port_facts { - u8 PortNumber; - u8 VP_ID; - u8 VF_ID; - u8 PortType; - u16 MaxPostedCmdBuffers; -}; - -struct reply_post_struct { - Mpi2ReplyDescriptorsUnion_t *reply_post_free; - dma_addr_t reply_post_free_dma; -}; - -/** - * enum mutex_type - task management mutex type - * @TM_MUTEX_OFF: mutex is not required becuase calling function is acquiring it - * @TM_MUTEX_ON: mutex is required - */ -enum mutex_type { - TM_MUTEX_OFF = 0, - TM_MUTEX_ON = 1, -}; - -typedef void (*MPT2SAS_FLUSH_RUNNING_CMDS)(struct MPT2SAS_ADAPTER *ioc); -/** - * struct MPT2SAS_ADAPTER - per adapter struct - * @list: ioc_list - * @shost: shost object - * @id: unique adapter id - * @cpu_count: number online cpus - * @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 - * @logging_level: see mpt2sas_debug.h - * @fwfault_debug: debuging FW timeouts - * @ir_firmware: IR firmware present - * @bars: bitmask of BAR's that must be configured - * @mask_interrupts: ignore interrupt - * @dma_mask: used to set the consistent dma mask - * @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 - * @shost_recovery: 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 management - * @remove_host: flag for when driver unloads, to avoid sending dev resets - * @pci_error_recovery: flag to prevent ioc access until slot reset completes - * @wait_for_discovery_to_complete: flag set at driver load time when - * waiting on reporting devices - * @is_driver_loading: flag set at driver load time - * @port_enable_failed: flag set when port enable has failed - * @start_scan: flag set from scan_start callback, cleared from _mpt2sas_fw_work - * @start_scan_failed: means port enable failed, return's the ioc_status - * @msix_enable: flag indicating msix is enabled - * @msix_vector_count: number msix vectors - * @cpu_msix_table: table for mapping cpus to msix index - * @cpu_msix_table_sz: table size - * @schedule_dead_ioc_flush_running_cmds: callback to flush pending commands - * @scsi_io_cb_idx: shost generated commands - * @tm_cb_idx: task management commands - * @scsih_cb_idx: scsih internal 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 - * @tm_tr_cb_idx : device removal target reset handshake - * @tm_tr_volume_cb_idx : volume removal target reset - * @base_cmds: - * @transport_cmds: - * @scsih_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 - * @manu_pg10: static manufacturing page 10 - * @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 - * @iounit_pg8: static iounit page 8 - * @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 - * @sas_id : used for setting volume target IDs - * @blocking_handles: bitmask used to identify which devices need blocking - * @pd_handles : bitmask for PD handles - * @pd_handles_sz : size of pd_handle bitmask - * @config_page_sz: config page size - * @config_page: reserve memory for config page payload - * @config_page_dma: - * @hba_queue_depth: hba request queue depth - * @sge_size: sg element size for either 32/64 bit - * @scsiio_depth: SCSI_IO 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 - * @hi_priority_smid: - * @hi_priority: - * @hi_priority_dma: - * @hi_priority_depth: - * @hpr_lookup: - * @hpr_free_list: - * @internal_smid: - * @internal: - * @internal_dma: - * @internal_depth: - * @internal_lookup: - * @internal_free_list: - * @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_struct: struct for reply_post_free physical & virt address - * @rdpq_array_capable: FW supports multiple reply queue addresses in ioc_init - * @rdpq_array_enable: rdpq_array support is enabled in the driver - * @rdpq_array_enable_assigned: this ensures that rdpq_array_enable flag - * is assigned only ones - * @reply_queue_count: number of reply queue's - * @reply_queue_list: link list contaning the reply queue info - * @reply_post_host_index: head index in the pool where FW completes IO - * @delayed_tr_list: target reset link list - * @delayed_tr_volume_list: volume target reset link list - * @@temp_sensors_count: flag to carry the number of temperature sensors - * @pci_access_mutex: Mutex to synchronize ioctl,sysfs show path and - * pci resource handling. PCI resource freeing will lead to free - * vital hardware/memory resource, which might be in use by cli/sysfs - * path functions resulting in Null pointer reference followed by kernel - * crash. To avoid the above race condition we use mutex syncrhonization - * which ensures the syncrhonization between cli/sysfs_show path - */ -struct MPT2SAS_ADAPTER { - struct list_head list; - struct Scsi_Host *shost; - u8 id; - int cpu_count; - char name[MPT_NAME_LENGTH]; - char tmp_string[MPT_STRING_LENGTH]; - struct pci_dev *pdev; - Mpi2SystemInterfaceRegs_t __iomem *chip; - resource_size_t chip_phys; - int logging_level; - int fwfault_debug; - u8 ir_firmware; - int bars; - u8 mask_interrupts; - int dma_mask; - - /* 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; - spinlock_t fw_event_lock; - struct list_head fw_event_list; - - /* misc flags */ - int aen_event_read_flag; - u8 broadcast_aen_busy; - u16 broadcast_aen_pending; - u8 shost_recovery; - - struct mutex reset_in_progress_mutex; - spinlock_t ioc_reset_in_progress_lock; - u8 ioc_link_reset_in_progress; - u8 ioc_reset_in_progress_status; - - u8 ignore_loginfos; - u8 remove_host; - u8 pci_error_recovery; - u8 wait_for_discovery_to_complete; - struct completion port_enable_done; - u8 is_driver_loading; - u8 port_enable_failed; - - u8 start_scan; - u16 start_scan_failed; - - u8 msix_enable; - u16 msix_vector_count; - u8 *cpu_msix_table; - resource_size_t __iomem **reply_post_host_index; - u16 cpu_msix_table_sz; - u32 ioc_reset_count; - MPT2SAS_FLUSH_RUNNING_CMDS schedule_dead_ioc_flush_running_cmds; - u32 non_operational_loop; - - /* internal commands, callback index */ - u8 scsi_io_cb_idx; - u8 tm_cb_idx; - u8 transport_cb_idx; - u8 scsih_cb_idx; - u8 ctl_cb_idx; - u8 base_cb_idx; - u8 port_enable_cb_idx; - u8 config_cb_idx; - u8 tm_tr_cb_idx; - u8 tm_tr_volume_cb_idx; - u8 tm_sas_control_cb_idx; - struct _internal_cmd base_cmds; - struct _internal_cmd port_enable_cmds; - struct _internal_cmd transport_cmds; - struct _internal_cmd scsih_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 */ - struct mpt2sas_facts facts; - struct mpt2sas_port_facts *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; - Mpi2IOUnitPage8_t iounit_pg8; - - 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; - void *blocking_handles; - void *pd_handles; - u16 pd_handles_sz; - - /* config page */ - u16 config_page_sz; - void *config_page; - dma_addr_t config_page_dma; - - /* scsiio request */ - u16 hba_queue_depth; - u16 sge_size; - u16 scsiio_depth; - u16 request_sz; - u8 *request; - dma_addr_t request_dma; - u32 request_dma_sz; - struct scsiio_tracker *scsi_lookup; - ulong scsi_lookup_pages; - spinlock_t scsi_lookup_lock; - struct list_head free_list; - int pending_io_count; - wait_queue_head_t reset_wq; - - /* chain */ - struct chain_tracker *chain_lookup; - struct list_head free_chain_list; - struct dma_pool *chain_dma_pool; - ulong chain_pages; - u16 max_sges_in_main_message; - u16 max_sges_in_chain_message; - u16 chains_needed_per_io; - u16 chain_offset_value_for_main_message; - u32 chain_depth; - - /* hi-priority queue */ - u16 hi_priority_smid; - u8 *hi_priority; - dma_addr_t hi_priority_dma; - u16 hi_priority_depth; - struct request_tracker *hpr_lookup; - struct list_head hpr_free_list; - - /* internal queue */ - u16 internal_smid; - u8 *internal; - dma_addr_t internal_dma; - u16 internal_depth; - struct request_tracker *internal_lookup; - struct list_head internal_free_list; - - /* 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; - u32 reply_dma_max_address; - u32 reply_dma_min_address; - struct dma_pool *reply_dma_pool; - - /* reply free queue */ - u16 reply_free_queue_depth; - __le32 *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; - struct reply_post_struct *reply_post; - u8 rdpq_array_capable; - u8 rdpq_array_enable; - u8 rdpq_array_enable_assigned; - struct dma_pool *reply_post_free_dma_pool; - u8 reply_queue_count; - struct list_head reply_queue_list; - - struct list_head delayed_tr_list; - struct list_head delayed_tr_volume_list; - u8 temp_sensors_count; - - /* 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]; - Mpi2ManufacturingPage10_t manu_pg10; - u32 product_specific[MPI2_DIAG_BUF_TYPE_COUNT][23]; - u32 diagnostic_flags[MPI2_DIAG_BUF_TYPE_COUNT]; - u32 ring_buffer_offset; - u32 ring_buffer_sz; - u8 is_warpdrive; - u8 hide_ir_msg; - u8 mfg_pg10_hide_flag; - u8 hide_drives; - - struct mutex pci_access_mutex; -}; - -typedef u8 (*MPT_CALLBACK)(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, - u32 reply); - - -/* base shared API */ -extern struct list_head mpt2sas_ioc_list; -/* spinlock on list operations over IOCs - * Case: when multiple warpdrive cards(IOCs) are in use - * Each IOC will added to the ioc list stucture on initialization. - * Watchdog threads run at regular intervals to check IOC for any - * fault conditions which will trigger the dead_ioc thread to - * deallocate pci resource, resulting deleting the IOC netry from list, - * this deletion need to protected by spinlock to enusre that - * ioc removal is syncrhonized, if not synchronized it might lead to - * list_del corruption as the ioc list is traversed in cli path - */ -extern spinlock_t gioc_lock; -void mpt2sas_base_start_watchdog(struct MPT2SAS_ADAPTER *ioc); -void mpt2sas_base_stop_watchdog(struct MPT2SAS_ADAPTER *ioc); - -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); -__le32 mpt2sas_base_get_sense_buffer_dma(struct MPT2SAS_ADAPTER *ioc, - u16 smid); -void mpt2sas_base_flush_reply_queues(struct MPT2SAS_ADAPTER *ioc); - -/* hi-priority queue */ -u16 mpt2sas_base_get_smid_hpr(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx); -u16 mpt2sas_base_get_smid_scsiio(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx, - struct scsi_cmnd *scmd); - -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, - u16 handle); -void mpt2sas_base_put_smid_hi_priority(struct MPT2SAS_ADAPTER *ioc, u16 smid); -void mpt2sas_base_put_smid_target_assist(struct MPT2SAS_ADAPTER *ioc, u16 smid, - u16 io_index); -void mpt2sas_base_put_smid_default(struct MPT2SAS_ADAPTER *ioc, u16 smid); -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); - -u8 mpt2sas_base_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, - u32 reply); -u8 mpt2sas_port_enable_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, - u8 msix_index, 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); - -void mpt2sas_halt_firmware(struct MPT2SAS_ADAPTER *ioc); - -void mpt2sas_base_update_missing_delay(struct MPT2SAS_ADAPTER *ioc, - u16 device_missing_delay, u8 io_missing_delay); - -int mpt2sas_port_enable(struct MPT2SAS_ADAPTER *ioc); - -/* scsih shared API */ -void mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, - u32 reply); -int mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, - uint channel, uint id, uint lun, u8 type, u16 smid_task, - ulong timeout, enum mutex_type m_type); -void mpt2sas_scsih_set_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle); -void mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle); -void mpt2sas_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address); -void mpt2sas_device_remove_by_sas_address(struct MPT2SAS_ADAPTER *ioc, - u64 sas_address); -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_get_sdev_by_addr( - struct MPT2SAS_ADAPTER *ioc, u64 sas_address); -struct _sas_device *__mpt2sas_get_sdev_by_addr( - struct MPT2SAS_ADAPTER *ioc, u64 sas_address); - -void mpt2sas_port_enable_complete(struct MPT2SAS_ADAPTER *ioc); -void mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase); - -/* config shared API */ -u8 mpt2sas_config_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, - 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_manufacturing_pg10(struct MPT2SAS_ADAPTER *ioc, - Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage10_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_iounit_pg8(struct MPT2SAS_ADAPTER *ioc, - Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage8_t *config_page); -int mpt2sas_config_get_iounit_pg3(struct MPT2SAS_ADAPTER *ioc, - Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage3_t *config_page, u16 sz); -int mpt2sas_config_get_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2SasIOUnitPage1_t *config_page, u16 sz); -int mpt2sas_config_set_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); -u8 mpt2sas_ctl_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, - u32 reply); -void mpt2sas_ctl_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase); -void mpt2sas_ctl_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, - u32 reply); -void mpt2sas_ctl_add_to_event_log(struct MPT2SAS_ADAPTER *ioc, - Mpi2EventNotificationReply_t *mpi_reply); - -void mpt2sas_enable_diag_buffer(struct MPT2SAS_ADAPTER *ioc, - u8 bits_to_regsiter); - -/* transport shared API */ -u8 mpt2sas_transport_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, - u32 reply); -struct _sas_port *mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, - u16 handle, u64 sas_address); -void mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address, - u64 sas_address_parent); -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_links(struct MPT2SAS_ADAPTER *ioc, - u64 sas_address, u16 handle, u8 phy_number, u8 link_rate); -extern struct sas_function_template mpt2sas_transport_functions; -extern struct scsi_transport_template *mpt2sas_transport_template; -extern int scsi_internal_device_block(struct scsi_device *sdev); -extern u8 mpt2sas_stm_zero_smid_handler(struct MPT2SAS_ADAPTER *ioc, - u8 msix_index, u32 reply); -extern int scsi_internal_device_unblock(struct scsi_device *sdev, - enum scsi_device_state new_state); - -#endif /* MPT2SAS_BASE_H_INCLUDED */ diff --git a/drivers/scsi/mpt2sas/mpt2sas_config.c b/drivers/scsi/mpt2sas/mpt2sas_config.c deleted file mode 100644 index c43815b1a485..000000000000 --- a/drivers/scsi/mpt2sas/mpt2sas_config.c +++ /dev/null @@ -1,1527 +0,0 @@ -/* - * This module provides common API for accessing firmware configuration pages - * - * This code is based on drivers/scsi/mpt2sas/mpt2_base.c - * Copyright (C) 2007-2014 LSI Corporation - * Copyright (C) 20013-2014 Avago Technologies - * (mailto: MPT-FusionLinux.pdl@avagotech.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/blkdev.h> -#include <linux/sched.h> -#include <linux/workqueue.h> -#include <linux/delay.h> -#include <linux/pci.h> -#include <linux/slab.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 - * @sz: size - * @page: virt pointer - * @page_dma: phys pointer - * - */ -struct config_request{ - u16 sz; - void *page; - dma_addr_t 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 helpful 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_mapping"; - break; - } - break; - } - - if (!desc) - return; - - printk(MPT2SAS_INFO_FMT "%s: %s(%d), action(%d), form(0x%08x), " - "smid(%d)\n", ioc->name, calling_function_name, desc, - mpi_request->Header.PageNumber, mpi_request->Action, - le32_to_cpu(mpi_request->PageAddress), smid); - - if (!mpi_reply) - return; - - if (mpi_reply->IOCStatus || mpi_reply->IOCLogInfo) - printk(MPT2SAS_INFO_FMT - "\tiocstatus(0x%04x), loginfo(0x%08x)\n", - ioc->name, le16_to_cpu(mpi_reply->IOCStatus), - le32_to_cpu(mpi_reply->IOCLogInfo)); -} -#endif - -/** - * _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; - - if (mem->sz > ioc->config_page_sz) { - mem->page = dma_alloc_coherent(&ioc->pdev->dev, mem->sz, - &mem->page_dma, GFP_KERNEL); - if (!mem->page) { - printk(MPT2SAS_ERR_FMT "%s: dma_alloc_coherent" - " failed asking for (%d) bytes!!\n", - ioc->name, __func__, mem->sz); - r = -ENOMEM; - } - } else { /* use tmp buffer if less than 512 bytes */ - mem->page = ioc->config_page; - mem->page_dma = ioc->config_page_dma; - } - 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) -{ - if (mem->sz > ioc->config_page_sz) - dma_free_coherent(&ioc->pdev->dev, mem->sz, mem->page, - mem->page_dma); -} - -/** - * mpt2sas_config_done - config page completion routine - * @ioc: per adapter object - * @smid: system request message index - * @msix_index: MSIX table index supplied by the OS - * @reply: reply message frame(lower 32bit addr) - * Context: none. - * - * The callback handler when using _config_request. - * - * Return 1 meaning mf should be freed from _base_interrupt - * 0 means the mf is freed from this function. - */ -u8 -mpt2sas_config_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, - u32 reply) -{ - MPI2DefaultReply_t *mpi_reply; - - if (ioc->config_cmds.status == MPT2_CMD_NOT_USED) - return 1; - if (ioc->config_cmds.smid != smid) - return 1; - 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 - ioc->config_cmds.smid = USHRT_MAX; - complete(&ioc->config_cmds.done); - return 1; -} - -/** - * _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 - * @config_page: contents of the config page - * @config_page_sz: size of config page - * Context: sleep - * - * 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, - void *config_page, u16 config_page_sz) -{ - u16 smid; - u32 ioc_state; - unsigned long timeleft; - Mpi2ConfigRequest_t *config_request; - int r; - u8 retry_count, issue_host_reset = 0; - u16 wait_state_count; - struct config_request mem; - - mutex_lock(&ioc->config_cmds.mutex); - if (ioc->config_cmds.status != MPT2_CMD_NOT_USED) { - printk(MPT2SAS_ERR_FMT "%s: config_cmd in use\n", - ioc->name, __func__); - mutex_unlock(&ioc->config_cmds.mutex); - return -EAGAIN; - } - - retry_count = 0; - memset(&mem, 0, sizeof(struct config_request)); - - mpi_request->VF_ID = 0; /* TODO */ - mpi_request->VP_ID = 0; - - if (config_page) { - 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; - mpi_request->ExtPageLength = mpi_reply->ExtPageLength; - mpi_request->ExtPageType = mpi_reply->ExtPageType; - if (mpi_request->Header.PageLength) - mem.sz = mpi_request->Header.PageLength * 4; - else - mem.sz = le16_to_cpu(mpi_reply->ExtPageLength) * 4; - r = _config_alloc_config_dma_memory(ioc, &mem); - if (r != 0) - goto out; - if (mpi_request->Action == - MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT || - mpi_request->Action == - MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM) { - ioc->base_add_sg_single(&mpi_request->PageBufferSGE, - MPT2_CONFIG_COMMON_WRITE_SGLFLAGS | mem.sz, - mem.page_dma); - memcpy(mem.page, config_page, min_t(u16, mem.sz, - config_page_sz)); - } else { - memset(config_page, 0, config_page_sz); - ioc->base_add_sg_single(&mpi_request->PageBufferSGE, - MPT2_CONFIG_COMMON_SGLFLAGS | mem.sz, mem.page_dma); - } - } - - retry_config: - if (retry_count) { - if (retry_count > 2) { /* attempt only 2 retries */ - r = -EFAULT; - goto free_mem; - } - printk(MPT2SAS_INFO_FMT "%s: attempting retry (%d)\n", - ioc->name, __func__, retry_count); - } - 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; - r = -EFAULT; - goto free_mem; - } - 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; - r = -EAGAIN; - goto free_mem; - } - - 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 - init_completion(&ioc->config_cmds.done); - mpt2sas_base_put_smid_default(ioc, smid); - 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); - retry_count++; - if (ioc->config_cmds.smid == smid) - mpt2sas_base_free_smid(ioc, smid); - if ((ioc->shost_recovery) || (ioc->config_cmds.status & - MPT2_CMD_RESET) || ioc->pci_error_recovery) - goto retry_config; - issue_host_reset = 1; - r = -EFAULT; - goto free_mem; - } - - 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 (%d) completed!!\n", - ioc->name, __func__, retry_count); - if (config_page && mpi_request->Action == - MPI2_CONFIG_ACTION_PAGE_READ_CURRENT) - memcpy(config_page, mem.page, min_t(u16, mem.sz, - config_page_sz)); - free_mem: - if (config_page) - _config_free_config_dma_memory(ioc, &mem); - out: - ioc->config_cmds.status = MPT2_CMD_NOT_USED; - mutex_unlock(&ioc->config_cmds.mutex); - - if (issue_host_reset) - mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, - FORCE_BIG_HAMMER); - return r; -} - -/** - * 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; - - 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, NULL, 0); - if (r) - goto out; - - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - return r; -} - -/** - * mpt2sas_config_get_manufacturing_pg10 - obtain manufacturing page 10 - * @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_pg10(struct MPT2SAS_ADAPTER *ioc, - Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage10_t *config_page) -{ - Mpi2ConfigRequest_t mpi_request; - int r; - - 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 = 10; - 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, NULL, 0); - if (r) - goto out; - - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - 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; - - 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, NULL, 0); - if (r) - goto out; - - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - 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; - - 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, NULL, 0); - if (r) - goto out; - - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - 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; - - 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, NULL, 0); - if (r) - goto out; - - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - 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; - - 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, NULL, 0); - if (r) - goto out; - - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - 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; - - 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, NULL, 0); - if (r) - goto out; - - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - return r; -} - -/** - * mpt2sas_config_get_iounit_pg3 - obtain iounit page 3 - * @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. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_get_iounit_pg3(struct MPT2SAS_ADAPTER *ioc, - Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage3_t *config_page, u16 sz) -{ - Mpi2ConfigRequest_t mpi_request; - int r; - - 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 = 3; - mpi_request.Header.PageVersion = MPI2_IOUNITPAGE3_PAGEVERSION; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz); - out: - return r; -} - -/** - * mpt2sas_config_get_iounit_pg8 - obtain iounit 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_iounit_pg8(struct MPT2SAS_ADAPTER *ioc, - Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage8_t *config_page) -{ - Mpi2ConfigRequest_t mpi_request; - int r; - - 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 = 8; - mpi_request.Header.PageVersion = MPI2_IOUNITPAGE8_PAGEVERSION; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - 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; - - 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, NULL, 0); - if (r) - goto out; - - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - 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; - - 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, NULL, 0); - if (r) - goto out; - - mpi_request.PageAddress = cpu_to_le32(form | handle); - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - 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; - - 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, NULL, 0); - if (r) - goto out; - - mpi_request.PageAddress = cpu_to_le32(form | handle); - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - 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; - u16 ioc_status; - Mpi2ConfigReply_t mpi_reply; - Mpi2SasIOUnitPage0_t config_page; - - *num_phys = 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_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, NULL, 0); - if (r) - goto out; - - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, &mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, &config_page, - sizeof(Mpi2SasIOUnitPage0_t)); - if (!r) { - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status == MPI2_IOCSTATUS_SUCCESS) - *num_phys = config_page.NumPhys; - } - out: - 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; - - 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, NULL, 0); - if (r) - goto out; - - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz); - out: - return r; -} - -/** - * mpt2sas_config_get_sas_iounit_pg1 - obtain sas iounit page 1 - * @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; - - 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_SASIOUNITPAGE1_PAGEVERSION; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz); - out: - return r; -} - -/** - * mpt2sas_config_set_sas_iounit_pg1 - send sas iounit page 1 - * @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_set_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2SasIOUnitPage1_t *config_page, u16 sz) -{ - Mpi2ConfigRequest_t mpi_request; - int r; - - 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_SASIOUNITPAGE1_PAGEVERSION; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT; - _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz); - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz); - out: - 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; - - 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, NULL, 0); - if (r) - goto out; - - mpi_request.PageAddress = cpu_to_le32(form | handle); - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - 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; - - 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, NULL, 0); - 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; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - 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; - - 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, NULL, 0); - if (r) - goto out; - - mpi_request.PageAddress = cpu_to_le32(form | handle); - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - 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; - - 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, NULL, 0); - 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; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - 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; - - 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, NULL, 0); - 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; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - 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; - - 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, NULL, 0); - if (r) - goto out; - - mpi_request.PageAddress = cpu_to_le32(form | handle); - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - 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; - u16 ioc_status; - - 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, NULL, 0); - 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; - r = _config_request(ioc, &mpi_request, &mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, &config_page, - sizeof(Mpi2RaidVolPage0_t)); - if (!r) { - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status == MPI2_IOCSTATUS_SUCCESS) - *num_pds = config_page.NumPhysDisks; - } - - out: - 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; - - 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 = 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, NULL, 0); - if (r) - goto out; - - mpi_request.PageAddress = cpu_to_le32(form | handle); - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz); - out: - 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; - - 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_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, NULL, 0); - if (r) - goto out; - - mpi_request.PageAddress = cpu_to_le32(form | form_specific); - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - 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 = NULL; - Mpi2ConfigRequest_t mpi_request; - Mpi2ConfigReply_t mpi_reply; - int r, i, config_page_sz; - u16 ioc_status; - int config_num; - u16 element_type; - u16 phys_disk_dev_handle; - - *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, NULL, 0); - if (r) - goto out; - - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - config_page_sz = (le16_to_cpu(mpi_reply.ExtPageLength) * 4); - config_page = kmalloc(config_page_sz, GFP_KERNEL); - if (!config_page) { - r = -1; - goto out; - } - config_num = 0xff; - while (1) { - mpi_request.PageAddress = cpu_to_le32(config_num + - MPI2_RAID_PGAD_FORM_GET_NEXT_CONFIGNUM); - r = _config_request(ioc, &mpi_request, &mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - config_page_sz); - if (r) - goto out; - r = -1; - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) - goto out; - for (i = 0; i < config_page->NumElements; i++) { - element_type = le16_to_cpu(config_page-> - ConfigElement[i].ElementFlags) & - MPI2_RAIDCONFIG0_EFLAGS_MASK_ELEMENT_TYPE; - if (element_type == - MPI2_RAIDCONFIG0_EFLAGS_VOL_PHYS_DISK_ELEMENT || - element_type == - MPI2_RAIDCONFIG0_EFLAGS_OCE_ELEMENT) { - phys_disk_dev_handle = - le16_to_cpu(config_page->ConfigElement[i]. - PhysDiskDevHandle); - if (phys_disk_dev_handle == pd_handle) { - *volume_handle = - le16_to_cpu(config_page-> - ConfigElement[i].VolDevHandle); - r = 0; - goto out; - } - } else if (element_type == - MPI2_RAIDCONFIG0_EFLAGS_HOT_SPARE_ELEMENT) { - *volume_handle = 0; - r = 0; - goto out; - } - } - config_num = config_page->ConfigNum; - } - out: - kfree(config_page); - 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 deleted file mode 100644 index 3694b63bd993..000000000000 --- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c +++ /dev/null @@ -1,3101 +0,0 @@ -/* - * Management Module Support for MPT (Message Passing Technology) based - * controllers - * - * This code is based on drivers/scsi/mpt2sas/mpt2_ctl.c - * Copyright (C) 2007-2014 LSI Corporation - * Copyright (C) 20013-2014 Avago Technologies - * (mailto: MPT-FusionLinux.pdl@avagotech.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/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/mutex.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 DEFINE_MUTEX(_ctl_mutex); -static struct fasync_struct *async_queue; -static DECLARE_WAIT_QUEUE_HEAD(ctl_poll_wait); - -static int _ctl_send_release(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type, - u8 *issue_reset); - -/** - * 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_sas_device_find_by_handle - sas device search - * @ioc: per adapter object - * @handle: sas device handle (assigned by firmware) - * Context: Calling function should acquire ioc->sas_device_lock - * - * This searches for sas_device based on sas_address, then return sas_device - * object. - */ -static struct _sas_device * -_ctl_sas_device_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle) -{ - struct _sas_device *sas_device, *r; - - r = NULL; - list_for_each_entry(sas_device, &ioc->sas_device_list, list) { - if (sas_device->handle != handle) - continue; - r = sas_device; - goto out; - } - - out: - return r; -} - -/** - * _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 helpful 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_INFO_FMT "%s: %s, smid(%d)\n", - ioc->name, calling_function_name, desc, smid); - - if (!mpi_reply) - return; - - if (mpi_reply->IOCStatus || mpi_reply->IOCLogInfo) - printk(MPT2SAS_INFO_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; - struct _sas_device *sas_device = NULL; - unsigned long flags; - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = _ctl_sas_device_find_by_handle(ioc, - le16_to_cpu(scsi_reply->DevHandle)); - if (sas_device) { - printk(MPT2SAS_WARN_FMT "\tsas_address(0x%016llx), " - "phy(%d)\n", ioc->name, (unsigned long long) - sas_device->sas_address, sas_device->phy); - printk(MPT2SAS_WARN_FMT - "\tenclosure_logical_id(0x%016llx), slot(%d)\n", - ioc->name, sas_device->enclosure_logical_id, - sas_device->slot); - } - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - if (scsi_reply->SCSIState || scsi_reply->SCSIStatus) - printk(MPT2SAS_INFO_FMT - "\tscsi_state(0x%02x), scsi_status" - "(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 - * @msix_index: MSIX table index supplied by the OS - * @reply: reply message frame(lower 32bit addr) - * Context: none. - * - * The callback handler when using ioc->ctl_cb_idx. - * - * Return 1 meaning mf should be freed from _base_interrupt - * 0 means the mf is freed from this function. - */ -u8 -mpt2sas_ctl_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, - u32 reply) -{ - MPI2DefaultReply_t *mpi_reply; - Mpi2SCSIIOReply_t *scsiio_reply; - const void *sense_data; - u32 sz; - - if (ioc->ctl_cmds.status == MPT2_CMD_NOT_USED) - return 1; - if (ioc->ctl_cmds.smid != smid) - return 1; - 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; - /* get sense data */ - if (mpi_reply->Function == MPI2_FUNCTION_SCSI_IO_REQUEST || - mpi_reply->Function == - MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) { - scsiio_reply = (Mpi2SCSIIOReply_t *)mpi_reply; - if (scsiio_reply->SCSIState & - MPI2_SCSI_STATE_AUTOSENSE_VALID) { - sz = min_t(u32, SCSI_SENSE_BUFFERSIZE, - le32_to_cpu(scsiio_reply->SenseCount)); - sense_data = mpt2sas_base_get_sense_buffer(ioc, - smid); - memcpy(ioc->ctl_cmds.sense, sense_data, sz); - } - } - } -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING - _ctl_display_some_debug(ioc, smid, "ctl_done", mpi_reply); -#endif - ioc->ctl_cmds.status &= ~MPT2_CMD_PENDING; - complete(&ioc->ctl_cmds.done); - return 1; -} - -/** - * _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 - * @msix_index: MSIX table index supplied by the OS - * @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. - * - * Returns void. - */ -void -mpt2sas_ctl_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, - u32 reply) -{ - Mpi2EventNotificationReply_t *mpi_reply; - - mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); - if (unlikely(!mpi_reply)) { - printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return; - } - mpt2sas_ctl_add_to_event_log(ioc, mpi_reply); - return; -} - -/** - * _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; - /* global ioc lock to protect controller on list operations */ - spin_lock(&gioc_lock); - list_for_each_entry(ioc, &mpt2sas_ioc_list, list) { - if (ioc->id != ioc_number) - continue; - spin_unlock(&gioc_lock); - *iocpp = ioc; - return ioc_number; - } - spin_unlock(&gioc_lock); - *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) -{ - int i; - u8 issue_reset; - - switch (reset_phase) { - case MPT2_IOC_PRE_RESET: - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " - "MPT2_IOC_PRE_RESET\n", ioc->name, __func__)); - for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) { - if (!(ioc->diag_buffer_status[i] & - MPT2_DIAG_BUFFER_IS_REGISTERED)) - continue; - if ((ioc->diag_buffer_status[i] & - MPT2_DIAG_BUFFER_IS_RELEASED)) - continue; - _ctl_send_release(ioc, i, &issue_reset); - } - break; - case MPT2_IOC_AFTER_RESET: - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " - "MPT2_IOC_AFTER_RESET\n", ioc->name, __func__)); - if (ioc->ctl_cmds.status & MPT2_CMD_PENDING) { - ioc->ctl_cmds.status |= MPT2_CMD_RESET; - mpt2sas_base_free_smid(ioc, ioc->ctl_cmds.smid); - complete(&ioc->ctl_cmds.done); - } - break; - case MPT2_IOC_DONE_RESET: - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " - "MPT2_IOC_DONE_RESET\n", ioc->name, __func__)); - - for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) { - if (!(ioc->diag_buffer_status[i] & - MPT2_DIAG_BUFFER_IS_REGISTERED)) - continue; - if ((ioc->diag_buffer_status[i] & - MPT2_DIAG_BUFFER_IS_RELEASED)) - continue; - ioc->diag_buffer_status[i] |= - MPT2_DIAG_BUFFER_IS_DIAG_RESET; - } - 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_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); - - /* global ioc lock to protect controller on list operations */ - spin_lock(&gioc_lock); - list_for_each_entry(ioc, &mpt2sas_ioc_list, list) { - if (ioc->aen_event_read_flag) { - spin_unlock(&gioc_lock); - return POLLIN | POLLRDNORM; - } - } - spin_unlock(&gioc_lock); - return 0; -} - -/** - * _ctl_set_task_mid - assign an active smid to tm request - * @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_set_task_mid(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; - char *desc = NULL; - - if (tm_request->TaskType == MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK) - desc = "abort_task"; - else if (tm_request->TaskType == MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK) - desc = "query_task"; - else - return 0; - - 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->scsiio_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_INFO_FMT "%s: " - "handle(0x%04x), lun(%d), no active mid!!\n", ioc->name, - desc, le16_to_cpu(tm_request->DevHandle), lun)); - tm_reply = ioc->ctl_cmds.reply; - tm_reply->DevHandle = tm_request->DevHandle; - tm_reply->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; - tm_reply->TaskType = tm_request->TaskType; - 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_INFO_FMT "%s: " - "handle(0x%04x), lun(%d), task_mid(%d)\n", ioc->name, - desc, le16_to_cpu(tm_request->DevHandle), lun, - le16_to_cpu(tm_request->TaskMID))); - 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 - */ -static long -_ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command karg, - void __user *mf) -{ - MPI2RequestHeader_t *mpi_request = NULL, *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 *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 (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__); - - mpi_request = kzalloc(ioc->request_sz, GFP_KERNEL); - if (!mpi_request) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a memory for " - "mpi_request\n", ioc->name, __func__); - ret = -ENOMEM; - goto out; - } - - /* Check for overflow and wraparound */ - if (karg.data_sge_offset * 4 > ioc->request_sz || - karg.data_sge_offset > (UINT_MAX / 4)) { - ret = -EINVAL; - goto out; - } - - /* 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; - goto out; - } - - if (mpi_request->Function == MPI2_FUNCTION_SCSI_TASK_MGMT) { - smid = mpt2sas_base_get_smid_hpr(ioc, ioc->ctl_cb_idx); - if (!smid) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); - ret = -EAGAIN; - goto out; - } - } else { - - smid = mpt2sas_base_get_smid_scsiio(ioc, ioc->ctl_cb_idx, NULL); - if (!smid) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); - ret = -EAGAIN; - goto out; - } - } - - ret = 0; - ioc->ctl_cmds.status = MPT2_CMD_PENDING; - memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz); - request = mpt2sas_base_get_msg_frame(ioc, smid); - memcpy(request, mpi_request, karg.data_sge_offset*4); - ioc->ctl_cmds.smid = smid; - data_out_sz = karg.data_out_size; - data_in_sz = karg.data_in_size; - - if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST || - mpi_request->Function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) { - if (!le16_to_cpu(mpi_request->FunctionDependent1) || - le16_to_cpu(mpi_request->FunctionDependent1) > - 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 *)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 - - init_completion(&ioc->ctl_cmds.done); - switch (mpi_request->Function) { - case MPI2_FUNCTION_SCSI_IO_REQUEST: - case MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH: - { - Mpi2SCSIIORequest_t *scsiio_request = - (Mpi2SCSIIORequest_t *)request; - scsiio_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE; - scsiio_request->SenseBufferLowAddress = - mpt2sas_base_get_sense_buffer_dma(ioc, smid); - memset(ioc->ctl_cmds.sense, 0, SCSI_SENSE_BUFFERSIZE); - if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST) - mpt2sas_base_put_smid_scsi_io(ioc, smid, - le16_to_cpu(mpi_request->FunctionDependent1)); - else - mpt2sas_base_put_smid_default(ioc, smid); - break; - } - case MPI2_FUNCTION_SCSI_TASK_MGMT: - { - Mpi2SCSITaskManagementRequest_t *tm_request = - (Mpi2SCSITaskManagementRequest_t *)request; - - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "TASK_MGMT: " - "handle(0x%04x), task_type(0x%02x)\n", ioc->name, - le16_to_cpu(tm_request->DevHandle), tm_request->TaskType)); - - if (tm_request->TaskType == - MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK || - tm_request->TaskType == - MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK) { - if (_ctl_set_task_mid(ioc, &karg, tm_request)) { - mpt2sas_base_free_smid(ioc, smid); - goto out; - } - } - - mpt2sas_scsih_set_tm_flag(ioc, le16_to_cpu( - tm_request->DevHandle)); - mpt2sas_base_put_smid_hi_priority(ioc, smid); - 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 { - if (unlikely(data_out == NULL)) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - mpt2sas_base_free_smid(ioc, smid); - ret = -EINVAL; - goto out; - } - 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); - 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); - break; - } - default: - mpt2sas_base_put_smid_default(ioc, smid); - 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; - 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_INFO_FMT "TASK_MGMT: " - "IOCStatus(0x%04x), IOCLogInfo(0x%08x), " - "TerminationCount(0x%08x)\n", ioc->name, - le16_to_cpu(tm_reply->IOCStatus), - le32_to_cpu(tm_reply->IOCLogInfo), - le32_to_cpu(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, - ioc->ctl_cmds.sense, sz)) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, - __LINE__, __func__); - ret = -ENODATA; - goto out; - } - } - - issue_host_reset: - if (issue_reset) { - ret = -ENODATA; - if ((mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST || - mpi_request->Function == - MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH || - mpi_request->Function == MPI2_FUNCTION_SATA_PASSTHROUGH)) { - printk(MPT2SAS_INFO_FMT "issue target reset: handle " - "= (0x%04x)\n", ioc->name, - le16_to_cpu(mpi_request->FunctionDependent1)); - mpt2sas_halt_firmware(ioc); - mpt2sas_scsih_issue_tm(ioc, - le16_to_cpu(mpi_request->FunctionDependent1), 0, 0, - 0, MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 10, - TM_MUTEX_ON); - ioc->tm_cmds.status = MPT2_CMD_NOT_USED; - } 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); - - kfree(mpi_request); - ioc->ctl_cmds.status = MPT2_CMD_NOT_USED; - return ret; -} - -/** - * _ctl_getiocinfo - main handler for MPT2IOCINFO opcode - * @ioc: per adapter object - * @arg - user space buffer containing ioctl content - */ -static long -_ctl_getiocinfo(struct MPT2SAS_ADAPTER *ioc, void __user *arg) -{ - struct mpt2_ioctl_iocinfo karg; - - if (copy_from_user(&karg, arg, sizeof(karg))) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - return -EFAULT; - } - - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name, - __func__)); - - memset(&karg, 0 , sizeof(karg)); - if (ioc->is_warpdrive) - karg.adapter_type = MPT2_IOCTL_INTERFACE_SAS2_SSS6200; - else - karg.adapter_type = MPT2_IOCTL_INTERFACE_SAS2; - if (ioc->pfacts) - karg.port_number = ioc->pfacts[0].PortNumber; - karg.hw_rev = ioc->pdev->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; - strcpy(karg.driver_version, MPT2SAS_DRIVER_NAME); - strcat(karg.driver_version, "-"); - strcat(karg.driver_version, MPT2SAS_DRIVER_VERSION); - 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 - * @ioc: per adapter object - * @arg - user space buffer containing ioctl content - */ -static long -_ctl_eventquery(struct MPT2SAS_ADAPTER *ioc, void __user *arg) -{ - struct mpt2_ioctl_eventquery karg; - - if (copy_from_user(&karg, arg, sizeof(karg))) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - return -EFAULT; - } - - dctlprintk(ioc, printk(MPT2SAS_INFO_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 - * @ioc: per adapter object - * @arg - user space buffer containing ioctl content - */ -static long -_ctl_eventenable(struct MPT2SAS_ADAPTER *ioc, void __user *arg) -{ - struct mpt2_ioctl_eventenable karg; - - if (copy_from_user(&karg, arg, sizeof(karg))) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - return -EFAULT; - } - - dctlprintk(ioc, printk(MPT2SAS_INFO_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 - * @ioc: per adapter object - * @arg - user space buffer containing ioctl content - */ -static long -_ctl_eventreport(struct MPT2SAS_ADAPTER *ioc, void __user *arg) -{ - struct mpt2_ioctl_eventreport karg; - 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; - } - - dctlprintk(ioc, printk(MPT2SAS_INFO_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 - * @ioc: per adapter object - * @arg - user space buffer containing ioctl content - */ -static long -_ctl_do_reset(struct MPT2SAS_ADAPTER *ioc, void __user *arg) -{ - struct mpt2_ioctl_diag_reset karg; - 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 (ioc->shost_recovery || ioc->pci_error_recovery || - ioc->is_driver_loading) - return -EAGAIN; - dctlprintk(ioc, printk(MPT2SAS_INFO_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 - * @ioc: per adapter object - * @arg - user space buffer containing ioctl content - */ -static long -_ctl_btdh_mapping(struct MPT2SAS_ADAPTER *ioc, void __user *arg) -{ - struct mpt2_ioctl_btdh_mapping karg; - int rc; - - if (copy_from_user(&karg, arg, sizeof(karg))) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - return -EFAULT; - } - - dctlprintk(ioc, printk(MPT2SAS_INFO_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, SNAPSHOT, or EXTENDED - * - * 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; - case MPI2_DIAG_BUF_TYPE_EXTENDED: - if (ioc->facts.IOCCapabilities & - MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER) - rc = 1; - } - - return rc; -} - -/** - * _ctl_diag_register_2 - wrapper for registering diag buffer support - * @ioc: per adapter object - * @diag_register: the diag_register struct passed in from user space - * - */ -static long -_ctl_diag_register_2(struct MPT2SAS_ADAPTER *ioc, - struct mpt2_diag_register *diag_register) -{ - 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; - - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - __func__)); - - 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; - } - - buffer_type = diag_register->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 (diag_register->requested_buffer_size % 4) { - printk(MPT2SAS_ERR_FMT "%s: the requested_buffer_size " - "is not 4 byte aligned\n", ioc->name, __func__); - return -EINVAL; - } - - 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 = diag_register->requested_buffer_size; - ioc->unique_id[buffer_type] = diag_register->unique_id; - ioc->diag_buffer_status[buffer_type] = 0; - memcpy(ioc->product_specific[buffer_type], - diag_register->product_specific, MPT2_PRODUCT_SPECIFIC_DWORDS); - ioc->diagnostic_flags[buffer_type] = diag_register->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 = diag_register->buffer_type; - mpi_request->Flags = cpu_to_le32(diag_register->diagnostic_flags); - mpi_request->BufferAddress = cpu_to_le64(request_data_dma); - mpi_request->BufferLength = cpu_to_le32(request_data_sz); - mpi_request->VF_ID = 0; /* TODO */ - mpi_request->VP_ID = 0; - - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: diag_buffer(0x%p), " - "dma(0x%llx), sz(%d)\n", ioc->name, __func__, request_data, - (unsigned long long)request_data_dma, - le32_to_cpu(mpi_request->BufferLength))); - - for (i = 0; i < MPT2_PRODUCT_SPECIFIC_DWORDS; i++) - mpi_request->ProductSpecific[i] = - cpu_to_le32(ioc->product_specific[buffer_type][i]); - - init_completion(&ioc->ctl_cmds.done); - mpt2sas_base_put_smid_default(ioc, smid); - 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_INFO_FMT "%s: success\n", - ioc->name, __func__)); - } else { - printk(MPT2SAS_INFO_FMT "%s: ioc_status(0x%04x) " - "log_info(0x%08x)\n", ioc->name, __func__, - ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo)); - rc = -EFAULT; - } - - 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; - return rc; -} - -/** - * mpt2sas_enable_diag_buffer - enabling diag_buffers support driver load time - * @ioc: per adapter object - * @bits_to_register: bitwise field where trace is bit 0, and snapshot is bit 1 - * - * This is called when command line option diag_buffer_enable is enabled - * at driver load time. - */ -void -mpt2sas_enable_diag_buffer(struct MPT2SAS_ADAPTER *ioc, u8 bits_to_register) -{ - struct mpt2_diag_register diag_register; - - memset(&diag_register, 0, sizeof(struct mpt2_diag_register)); - - if (bits_to_register & 1) { - printk(MPT2SAS_INFO_FMT "registering trace buffer support\n", - ioc->name); - diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_TRACE; - /* register for 1MB buffers */ - diag_register.requested_buffer_size = (1024 * 1024); - diag_register.unique_id = 0x7075900; - _ctl_diag_register_2(ioc, &diag_register); - } - - if (bits_to_register & 2) { - printk(MPT2SAS_INFO_FMT "registering snapshot buffer support\n", - ioc->name); - diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_SNAPSHOT; - /* register for 2MB buffers */ - diag_register.requested_buffer_size = 2 * (1024 * 1024); - diag_register.unique_id = 0x7075901; - _ctl_diag_register_2(ioc, &diag_register); - } - - if (bits_to_register & 4) { - printk(MPT2SAS_INFO_FMT "registering extended buffer support\n", - ioc->name); - diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_EXTENDED; - /* register for 2MB buffers */ - diag_register.requested_buffer_size = 2 * (1024 * 1024); - diag_register.unique_id = 0x7075901; - _ctl_diag_register_2(ioc, &diag_register); - } -} - -/** - * _ctl_diag_register - application register with driver - * @ioc: per adapter object - * @arg - user space buffer containing ioctl content - * - * 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(struct MPT2SAS_ADAPTER *ioc, void __user *arg) -{ - struct mpt2_diag_register karg; - long rc; - - if (copy_from_user(&karg, arg, sizeof(karg))) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - return -EFAULT; - } - - rc = _ctl_diag_register_2(ioc, &karg); - return rc; -} - -/** - * _ctl_diag_unregister - application unregister with driver - * @ioc: per adapter object - * @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(struct MPT2SAS_ADAPTER *ioc, void __user *arg) -{ - struct mpt2_diag_unregister karg; - 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; - } - - dctlprintk(ioc, printk(MPT2SAS_INFO_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 - * @ioc: per adapter object - * @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(struct MPT2SAS_ADAPTER *ioc, void __user *arg) -{ - struct mpt2_diag_query karg; - 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; - } - - dctlprintk(ioc, printk(MPT2SAS_INFO_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_send_release - Diag Release Message - * @ioc: per adapter object - * @buffer_type - specifies either TRACE, SNAPSHOT, or EXTENDED - * @issue_reset - specifies whether host reset is required. - * - */ -static int -_ctl_send_release(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type, u8 *issue_reset) -{ - Mpi2DiagReleaseRequest_t *mpi_request; - Mpi2DiagReleaseReply_t *mpi_reply; - u16 smid; - u16 ioc_status; - u32 ioc_state; - int rc; - unsigned long timeleft; - - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - __func__)); - - rc = 0; - *issue_reset = 0; - - ioc_state = mpt2sas_base_get_iocstate(ioc, 1); - if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " - "skipping due to FAULT state\n", ioc->name, - __func__)); - rc = -EAGAIN; - goto out; - } - - 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; - } - - 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; - mpi_request->VF_ID = 0; /* TODO */ - mpi_request->VP_ID = 0; - - init_completion(&ioc->ctl_cmds.done); - mpt2sas_base_put_smid_default(ioc, smid); - 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; - rc = -EFAULT; - goto out; - } - - /* 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_INFO_FMT "%s: success\n", - ioc->name, __func__)); - } else { - printk(MPT2SAS_INFO_FMT "%s: ioc_status(0x%04x) " - "log_info(0x%08x)\n", ioc->name, __func__, - ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo)); - rc = -EFAULT; - } - - out: - ioc->ctl_cmds.status = MPT2_CMD_NOT_USED; - return rc; -} - -/** - * _ctl_diag_release - request to send Diag Release Message to firmware - * @arg - user space buffer containing ioctl content - * - * 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(struct MPT2SAS_ADAPTER *ioc, void __user *arg) -{ - struct mpt2_diag_release karg; - void *request_data; - int rc; - u8 buffer_type; - 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; - } - - dctlprintk(ioc, printk(MPT2SAS_INFO_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; - } - - /* buffers were released by due to host reset */ - if ((ioc->diag_buffer_status[buffer_type] & - MPT2_DIAG_BUFFER_IS_DIAG_RESET)) { - ioc->diag_buffer_status[buffer_type] |= - MPT2_DIAG_BUFFER_IS_RELEASED; - ioc->diag_buffer_status[buffer_type] &= - ~MPT2_DIAG_BUFFER_IS_DIAG_RESET; - printk(MPT2SAS_ERR_FMT "%s: buffer_type(0x%02x) " - "was released due to host reset\n", ioc->name, __func__, - buffer_type); - return 0; - } - - rc = _ctl_send_release(ioc, buffer_type, &issue_reset); - - if (issue_reset) - mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, - FORCE_BIG_HAMMER); - - return rc; -} - -/** - * _ctl_diag_read_buffer - request for copy of the diag buffer - * @ioc: per adapter object - * @arg - user space buffer containing ioctl content - */ -static long -_ctl_diag_read_buffer(struct MPT2SAS_ADAPTER *ioc, void __user *arg) -{ - struct mpt2_diag_read_buffer karg; - struct mpt2_diag_read_buffer __user *uarg = arg; - void *request_data, *diag_data; - Mpi2DiagBufferPostRequest_t *mpi_request; - Mpi2DiagBufferPostReply_t *mpi_reply; - int rc, i; - u8 buffer_type; - unsigned long timeleft, request_size, copy_size; - 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; - } - - dctlprintk(ioc, printk(MPT2SAS_INFO_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; - } - - request_size = ioc->diag_buffer_sz[buffer_type]; - - 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; - } - - if (karg.starting_offset > request_size) - return -EINVAL; - - diag_data = (void *)(request_data + karg.starting_offset); - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: diag_buffer(%p), " - "offset(%d), sz(%d)\n", ioc->name, __func__, - diag_data, karg.starting_offset, karg.bytes_to_read)); - - /* Truncate data on requests that are too large */ - if ((diag_data + karg.bytes_to_read < diag_data) || - (diag_data + karg.bytes_to_read > request_data + request_size)) - copy_size = request_size - karg.starting_offset; - else - copy_size = karg.bytes_to_read; - - if (copy_to_user((void __user *)uarg->diagnostic_data, - diag_data, copy_size)) { - 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_INFO_FMT "%s: Reregister " - "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type)); - if ((ioc->diag_buffer_status[buffer_type] & - MPT2_DIAG_BUFFER_IS_RELEASED) == 0) { - dctlprintk(ioc, printk(MPT2SAS_INFO_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 (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]); - mpi_request->VF_ID = 0; /* TODO */ - mpi_request->VP_ID = 0; - - init_completion(&ioc->ctl_cmds.done); - mpt2sas_base_put_smid_default(ioc, smid); - 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_INFO_FMT "%s: success\n", - ioc->name, __func__)); - } else { - printk(MPT2SAS_INFO_FMT "%s: ioc_status(0x%04x) " - "log_info(0x%08x)\n", ioc->name, __func__, - ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo)); - rc = -EFAULT; - } - - 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; - return rc; -} - - -#ifdef CONFIG_COMPAT -/** - * _ctl_compat_mpt_command - convert 32bit pointers to 64bit. - * @ioc: per adapter object - * @cmd - ioctl opcode - * @arg - (struct mpt2_ioctl_command32) - * - * MPT2COMMAND32 - Handle 32bit applications running on 64bit os. - */ -static long -_ctl_compat_mpt_command(struct MPT2SAS_ADAPTER *ioc, unsigned cmd, - void __user *arg) -{ - struct mpt2_ioctl_command32 karg32; - struct mpt2_ioctl_command32 __user *uarg; - struct mpt2_ioctl_command karg; - - 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; - } - - 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; - karg.reply_frame_buf_ptr = compat_ptr(karg32.reply_frame_buf_ptr); - karg.data_in_buf_ptr = compat_ptr(karg32.data_in_buf_ptr); - karg.data_out_buf_ptr = compat_ptr(karg32.data_out_buf_ptr); - karg.sense_data_ptr = compat_ptr(karg32.sense_data_ptr); - return _ctl_do_mpt_command(ioc, karg, &uarg->mf); -} -#endif - -/** - * _ctl_ioctl_main - main ioctl entry point - * @file - (struct file) - * @cmd - ioctl opcode - * @arg - - * compat - handles 32 bit applications in 64bit os - */ -static long -_ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg, - u8 compat) -{ - struct MPT2SAS_ADAPTER *ioc; - struct mpt2_ioctl_header ioctl_header; - enum block_state state; - long ret = -EINVAL; - - /* get IOCTL header */ - if (copy_from_user(&ioctl_header, (char __user *)arg, - sizeof(struct mpt2_ioctl_header))) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - return -EFAULT; - } - - if (_ctl_verify_adapter(ioctl_header.ioc_number, &ioc) == -1 || !ioc) - return -ENODEV; - /* pci_access_mutex lock acquired by ioctl path */ - mutex_lock(&ioc->pci_access_mutex); - if (ioc->shost_recovery || ioc->pci_error_recovery || - ioc->is_driver_loading || ioc->remove_host) { - ret = -EAGAIN; - goto out_unlock_pciaccess; - } - - state = (file->f_flags & O_NONBLOCK) ? NON_BLOCKING : BLOCKING; - if (state == NON_BLOCKING) { - if (!mutex_trylock(&ioc->ctl_cmds.mutex)) { - ret = -EAGAIN; - goto out_unlock_pciaccess; - } - } else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex)) { - ret = -ERESTARTSYS; - goto out_unlock_pciaccess; - } - - switch (cmd) { - case MPT2IOCINFO: - if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_iocinfo)) - ret = _ctl_getiocinfo(ioc, arg); - break; -#ifdef CONFIG_COMPAT - case MPT2COMMAND32: -#endif - case MPT2COMMAND: - { - struct mpt2_ioctl_command __user *uarg; - struct mpt2_ioctl_command karg; -#ifdef CONFIG_COMPAT - if (compat) { - ret = _ctl_compat_mpt_command(ioc, cmd, arg); - break; - } -#endif - if (copy_from_user(&karg, arg, sizeof(karg))) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - ret = -EFAULT; - break; - } - - if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_command)) { - uarg = arg; - ret = _ctl_do_mpt_command(ioc, karg, &uarg->mf); - } - break; - } - case MPT2EVENTQUERY: - if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_eventquery)) - ret = _ctl_eventquery(ioc, arg); - break; - case MPT2EVENTENABLE: - if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_eventenable)) - ret = _ctl_eventenable(ioc, arg); - break; - case MPT2EVENTREPORT: - ret = _ctl_eventreport(ioc, arg); - break; - case MPT2HARDRESET: - if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_diag_reset)) - ret = _ctl_do_reset(ioc, arg); - break; - case MPT2BTDHMAPPING: - if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_btdh_mapping)) - ret = _ctl_btdh_mapping(ioc, arg); - break; - case MPT2DIAGREGISTER: - if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_register)) - ret = _ctl_diag_register(ioc, arg); - break; - case MPT2DIAGUNREGISTER: - if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_unregister)) - ret = _ctl_diag_unregister(ioc, arg); - break; - case MPT2DIAGQUERY: - if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_query)) - ret = _ctl_diag_query(ioc, arg); - break; - case MPT2DIAGRELEASE: - if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_release)) - ret = _ctl_diag_release(ioc, arg); - break; - case MPT2DIAGREADBUFFER: - if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_read_buffer)) - ret = _ctl_diag_read_buffer(ioc, arg); - break; - default: - - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT - "unsupported ioctl opcode(0x%08x)\n", ioc->name, cmd)); - break; - } - - mutex_unlock(&ioc->ctl_cmds.mutex); -out_unlock_pciaccess: - mutex_unlock(&ioc->pci_access_mutex); - 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; - - ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 0); - return ret; -} -#ifdef CONFIG_COMPAT -/** - * _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; - - ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 1); - 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, "%08xh\n", - le32_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, "%08xh\n", - le32_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); - -/* device attributes */ -/* - * _ctl_fwfault_debug_show - show/store fwfault_debug - * @cdev - pointer to embedded class device - * @buf - the buffer returned - * - * mpt2sas_fwfault_debug is command line option - * A sysfs 'read/write' shost attribute. - */ -static ssize_t -_ctl_fwfault_debug_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, "%d\n", ioc->fwfault_debug); -} -static ssize_t -_ctl_fwfault_debug_store(struct device *cdev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - int val = 0; - - if (sscanf(buf, "%d", &val) != 1) - return -EINVAL; - - ioc->fwfault_debug = val; - printk(MPT2SAS_INFO_FMT "fwfault_debug=%d\n", ioc->name, - ioc->fwfault_debug); - return strlen(buf); -} -static DEVICE_ATTR(fwfault_debug, S_IRUGO | S_IWUSR, - _ctl_fwfault_debug_show, _ctl_fwfault_debug_store); - - -/** - * _ctl_ioc_reset_count_show - ioc reset count - * @cdev - pointer to embedded class device - * @buf - the buffer returned - * - * This is firmware queue depth limit - * - * A sysfs 'read-only' shost attribute. - */ -static ssize_t -_ctl_ioc_reset_count_show(struct device *cdev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - - return snprintf(buf, PAGE_SIZE, "%08d\n", ioc->ioc_reset_count); -} -static DEVICE_ATTR(ioc_reset_count, S_IRUGO, - _ctl_ioc_reset_count_show, NULL); - -/** - * _ctl_ioc_reply_queue_count_show - number of reply queues - * @cdev - pointer to embedded class device - * @buf - the buffer returned - * - * This is number of reply queues - * - * A sysfs 'read-only' shost attribute. - */ -static ssize_t -_ctl_ioc_reply_queue_count_show(struct device *cdev, - struct device_attribute *attr, char *buf) -{ - u8 reply_queue_count; - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - - if ((ioc->facts.IOCCapabilities & - MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX) && ioc->msix_enable) - reply_queue_count = ioc->reply_queue_count; - else - reply_queue_count = 1; - return snprintf(buf, PAGE_SIZE, "%d\n", reply_queue_count); -} -static DEVICE_ATTR(reply_queue_count, S_IRUGO, - _ctl_ioc_reply_queue_count_show, NULL); - -/** - * _ctl_BRM_status_show - Backup Rail Monitor Status - * @cdev - pointer to embedded class device - * @buf - the buffer returned - * - * This is number of reply queues - * - * A sysfs 'read-only' shost attribute. - */ -static ssize_t -_ctl_BRM_status_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); - Mpi2IOUnitPage3_t *io_unit_pg3 = NULL; - Mpi2ConfigReply_t mpi_reply; - u16 backup_rail_monitor_status = 0; - u16 ioc_status; - int sz; - ssize_t rc = 0; - - if (!ioc->is_warpdrive) { - printk(MPT2SAS_ERR_FMT "%s: BRM attribute is only for"\ - "warpdrive\n", ioc->name, __func__); - goto out; - } - /* pci_access_mutex lock acquired by sysfs show path */ - mutex_lock(&ioc->pci_access_mutex); - if (ioc->pci_error_recovery || ioc->remove_host) { - mutex_unlock(&ioc->pci_access_mutex); - return 0; - } - - /* allocate upto GPIOVal 36 entries */ - sz = offsetof(Mpi2IOUnitPage3_t, GPIOVal) + (sizeof(u16) * 36); - io_unit_pg3 = kzalloc(sz, GFP_KERNEL); - if (!io_unit_pg3) { - printk(MPT2SAS_ERR_FMT "%s: failed allocating memory"\ - "for iounit_pg3: (%d) bytes\n", ioc->name, __func__, sz); - goto out; - } - - if (mpt2sas_config_get_iounit_pg3(ioc, &mpi_reply, io_unit_pg3, sz) != - 0) { - printk(MPT2SAS_ERR_FMT - "%s: failed reading iounit_pg3\n", ioc->name, - __func__); - goto out; - } - - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - printk(MPT2SAS_ERR_FMT "%s: iounit_pg3 failed with"\ - "ioc_status(0x%04x)\n", ioc->name, __func__, ioc_status); - goto out; - } - - if (io_unit_pg3->GPIOCount < 25) { - printk(MPT2SAS_ERR_FMT "%s: iounit_pg3->GPIOCount less than"\ - "25 entries, detected (%d) entries\n", ioc->name, __func__, - io_unit_pg3->GPIOCount); - goto out; - } - - /* BRM status is in bit zero of GPIOVal[24] */ - backup_rail_monitor_status = le16_to_cpu(io_unit_pg3->GPIOVal[24]); - rc = snprintf(buf, PAGE_SIZE, "%d\n", (backup_rail_monitor_status & 1)); - - out: - kfree(io_unit_pg3); - mutex_unlock(&ioc->pci_access_mutex); - return rc; -} -static DEVICE_ATTR(BRM_status, S_IRUGO, _ctl_BRM_status_show, NULL); - -struct DIAG_BUFFER_START { - __le32 Size; - __le32 DiagVersion; - u8 BufferType; - u8 Reserved[3]; - __le32 Reserved1; - __le32 Reserved2; - __le32 Reserved3; -}; -/** - * _ctl_host_trace_buffer_size_show - host buffer size (trace only) - * @cdev - pointer to embedded class device - * @buf - the buffer returned - * - * A sysfs 'read-only' shost attribute. - */ -static ssize_t -_ctl_host_trace_buffer_size_show(struct device *cdev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - u32 size = 0; - struct DIAG_BUFFER_START *request_data; - - if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) { - printk(MPT2SAS_ERR_FMT "%s: host_trace_buffer is not " - "registered\n", ioc->name, __func__); - return 0; - } - - if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & - MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) { - printk(MPT2SAS_ERR_FMT "%s: host_trace_buffer is not " - "registered\n", ioc->name, __func__); - return 0; - } - - request_data = (struct DIAG_BUFFER_START *) - ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]; - if ((le32_to_cpu(request_data->DiagVersion) == 0x00000000 || - le32_to_cpu(request_data->DiagVersion) == 0x01000000) && - le32_to_cpu(request_data->Reserved3) == 0x4742444c) - size = le32_to_cpu(request_data->Size); - - ioc->ring_buffer_sz = size; - return snprintf(buf, PAGE_SIZE, "%d\n", size); -} -static DEVICE_ATTR(host_trace_buffer_size, S_IRUGO, - _ctl_host_trace_buffer_size_show, NULL); - -/** - * _ctl_host_trace_buffer_show - firmware ring buffer (trace only) - * @cdev - pointer to embedded class device - * @buf - the buffer returned - * - * A sysfs 'read/write' shost attribute. - * - * You will only be able to read 4k bytes of ring buffer at a time. - * In order to read beyond 4k bytes, you will have to write out the - * offset to the same attribute, it will move the pointer. - */ -static ssize_t -_ctl_host_trace_buffer_show(struct device *cdev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - void *request_data; - u32 size; - - if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) { - printk(MPT2SAS_ERR_FMT "%s: host_trace_buffer is not " - "registered\n", ioc->name, __func__); - return 0; - } - - if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & - MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) { - printk(MPT2SAS_ERR_FMT "%s: host_trace_buffer is not " - "registered\n", ioc->name, __func__); - return 0; - } - - if (ioc->ring_buffer_offset > ioc->ring_buffer_sz) - return 0; - - size = ioc->ring_buffer_sz - ioc->ring_buffer_offset; - size = (size > PAGE_SIZE) ? PAGE_SIZE : size; - request_data = ioc->diag_buffer[0] + ioc->ring_buffer_offset; - memcpy(buf, request_data, size); - return size; -} - -static ssize_t -_ctl_host_trace_buffer_store(struct device *cdev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - int val = 0; - - if (sscanf(buf, "%d", &val) != 1) - return -EINVAL; - - ioc->ring_buffer_offset = val; - return strlen(buf); -} -static DEVICE_ATTR(host_trace_buffer, S_IRUGO | S_IWUSR, - _ctl_host_trace_buffer_show, _ctl_host_trace_buffer_store); - -/*****************************************/ - -/** - * _ctl_host_trace_buffer_enable_show - firmware ring buffer (trace only) - * @cdev - pointer to embedded class device - * @buf - the buffer returned - * - * A sysfs 'read/write' shost attribute. - * - * This is a mechnism to post/release host_trace_buffers - */ -static ssize_t -_ctl_host_trace_buffer_enable_show(struct device *cdev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - - if ((!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) || - ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & - MPT2_DIAG_BUFFER_IS_REGISTERED) == 0)) - return snprintf(buf, PAGE_SIZE, "off\n"); - else if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & - MPT2_DIAG_BUFFER_IS_RELEASED)) - return snprintf(buf, PAGE_SIZE, "release\n"); - else - return snprintf(buf, PAGE_SIZE, "post\n"); -} - -static ssize_t -_ctl_host_trace_buffer_enable_store(struct device *cdev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - char str[10] = ""; - struct mpt2_diag_register diag_register; - u8 issue_reset = 0; - - if (sscanf(buf, "%9s", str) != 1) - return -EINVAL; - - if (!strcmp(str, "post")) { - /* exit out if host buffers are already posted */ - if ((ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) && - (ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & - MPT2_DIAG_BUFFER_IS_REGISTERED) && - ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & - MPT2_DIAG_BUFFER_IS_RELEASED) == 0)) - goto out; - memset(&diag_register, 0, sizeof(struct mpt2_diag_register)); - printk(MPT2SAS_INFO_FMT "posting host trace buffers\n", - ioc->name); - diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_TRACE; - diag_register.requested_buffer_size = (1024 * 1024); - diag_register.unique_id = 0x7075900; - ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] = 0; - _ctl_diag_register_2(ioc, &diag_register); - } else if (!strcmp(str, "release")) { - /* exit out if host buffers are already released */ - if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) - goto out; - if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & - MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) - goto out; - if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & - MPT2_DIAG_BUFFER_IS_RELEASED)) - goto out; - printk(MPT2SAS_INFO_FMT "releasing host trace buffer\n", - ioc->name); - _ctl_send_release(ioc, MPI2_DIAG_BUF_TYPE_TRACE, &issue_reset); - } - - out: - return strlen(buf); -} -static DEVICE_ATTR(host_trace_buffer_enable, S_IRUGO | S_IWUSR, - _ctl_host_trace_buffer_enable_show, _ctl_host_trace_buffer_enable_store); - -struct device_attribute *mpt2sas_host_attrs[] = { - &dev_attr_version_fw, - &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_fwfault_debug, - &dev_attr_fw_queue_depth, - &dev_attr_host_sas_address, - &dev_attr_ioc_reset_count, - &dev_attr_host_trace_buffer_size, - &dev_attr_host_trace_buffer, - &dev_attr_host_trace_buffer_enable, - &dev_attr_reply_queue_count, - &dev_attr_BRM_status, - NULL, -}; - -/** - * _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, - .poll = _ctl_poll, - .fasync = _ctl_fasync, -#ifdef CONFIG_COMPAT - .compat_ioctl = _ctl_ioctl_compat, -#endif - .llseek = noop_llseek, -}; - -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 deleted file mode 100644 index 46b2fc5b74af..000000000000 --- a/drivers/scsi/mpt2sas/mpt2sas_ctl.h +++ /dev/null @@ -1,419 +0,0 @@ -/* - * Management Module Support for MPT (Message Passing Technology) based - * controllers - * - * This code is based on drivers/scsi/mpt2sas/mpt2_ctl.h - * Copyright (C) 2007-2014 LSI Corporation - * Copyright (C) 20013-2014 Avago Technologies - * (mailto: MPT-FusionLinux.pdl@avagotech.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 'L' -#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_INTERFACE_SAS2_SSS6200 (0x05) -#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 ioctl - * @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) -#define MPT2_DIAG_BUFFER_IS_DIAG_RESET (0x04) - -/* 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, SNAPSHOT, or EXTENDED - * @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, SNAPSHOT, or EXTENDED - * @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 deleted file mode 100644 index 277120d45648..000000000000 --- a/drivers/scsi/mpt2sas/mpt2sas_debug.h +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Logging Support for MPT (Message Passing Technology) based controllers - * - * This code is based on drivers/scsi/mpt2sas/mpt2_debug.c - * Copyright (C) 2007-2014 LSI Corporation - * Copyright (C) 20013-2014 Avago Technologies - * (mailto: MPT-FusionLinux.pdl@avagotech.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; - __le32 *mfp = (__le32 *)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 deleted file mode 100644 index 0ad09b2bff9c..000000000000 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ /dev/null @@ -1,8855 +0,0 @@ -/* - * Scsi Host Layer for MPT (Message Passing Technology) based controllers - * - * This code is based on drivers/scsi/mpt2sas/mpt2_scsih.c - * Copyright (C) 2007-2014 LSI Corporation - * Copyright (C) 20013-2014 Avago Technologies - * (mailto: MPT-FusionLinux.pdl@avagotech.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/blkdev.h> -#include <linux/sched.h> -#include <linux/workqueue.h> -#include <linux/delay.h> -#include <linux/pci.h> -#include <linux/interrupt.h> -#include <linux/aer.h> -#include <linux/raid_class.h> -#include <linux/slab.h> - -#include <asm/unaligned.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); - -static u8 _scsih_check_for_pending_tm(struct MPT2SAS_ADAPTER *ioc, u16 smid); - -static void _scsih_scan_start(struct Scsi_Host *shost); -static int _scsih_scan_finished(struct Scsi_Host *shost, unsigned long time); - -/* global parameters */ -LIST_HEAD(mpt2sas_ioc_list); -/* global ioc lock for list operations */ -DEFINE_SPINLOCK(gioc_lock); -/* 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 port_enable_cb_idx = -1; -static u8 transport_cb_idx = -1; -static u8 scsih_cb_idx = -1; -static u8 config_cb_idx = -1; -static int mpt_ids; - -static u8 tm_tr_cb_idx = -1 ; -static u8 tm_tr_volume_cb_idx = -1 ; -static u8 tm_sas_control_cb_idx = -1; - -/* command line options */ -static u32 logging_level; -MODULE_PARM_DESC(logging_level, " bits for enabling additional logging info " - "(default=0)"); - -static ushort max_sectors = 0xFFFF; -module_param(max_sectors, ushort, 0); -MODULE_PARM_DESC(max_sectors, "max sectors, range 64 to 32767 default=32767"); - -static int missing_delay[2] = {-1, -1}; -module_param_array(missing_delay, int, NULL, 0); -MODULE_PARM_DESC(missing_delay, " device missing delay , io missing delay"); - -/* 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 "); - -/* diag_buffer_enable is bitwise - * bit 0 set = TRACE - * bit 1 set = SNAPSHOT - * bit 2 set = EXTENDED - * - * Either bit can be set, or both - */ -static int diag_buffer_enable = -1; -module_param(diag_buffer_enable, int, 0); -MODULE_PARM_DESC(diag_buffer_enable, " post diag buffers " - "(TRACE=1/SNAPSHOT=2/EXTENDED=4/default=0)"); - -static int disable_discovery = -1; -module_param(disable_discovery, int, 0); -MODULE_PARM_DESC(disable_discovery, " disable discovery "); - -/* permit overriding the host protection capabilities mask (EEDP/T10 PI) */ -static int prot_mask = 0; -module_param(prot_mask, int, 0); -MODULE_PARM_DESC(prot_mask, " host protection capabilities mask, def=7 "); - -/** - * 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_TURN_ON_PFA_LED (0xFFFC) -#define MPT2SAS_PORT_ENABLE_COMPLETE (0xFFFD) -#define MPT2SAS_REMOVE_UNRESPONDING_DEVICES (0xFFFF) -/** - * struct fw_event_work - firmware event struct - * @list: link list framework - * @work: work object (ioc->fault_reset_work_q) - * @cancel_pending_work: flag set during reset handling - * @ioc: per adapter object - * @device_handle: device handle - * @VF_ID: virtual function id - * @VP_ID: virtual port id - * @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; - u8 cancel_pending_work; - struct delayed_work delayed_work; - struct MPT2SAS_ADAPTER *ioc; - u16 device_handle; - u8 VF_ID; - u8 VP_ID; - u8 ignore; - u16 event; - struct kref refcount; - char event_data[0] __aligned(4); -}; - -static void fw_event_work_free(struct kref *r) -{ - kfree(container_of(r, struct fw_event_work, refcount)); -} - -static void fw_event_work_get(struct fw_event_work *fw_work) -{ - kref_get(&fw_work->refcount); -} - -static void fw_event_work_put(struct fw_event_work *fw_work) -{ - kref_put(&fw_work->refcount, fw_event_work_free); -} - -static struct fw_event_work *alloc_fw_event_work(int len) -{ - struct fw_event_work *fw_event; - - fw_event = kzalloc(sizeof(*fw_event) + len, GFP_ATOMIC); - if (!fw_event) - return NULL; - - kref_init(&fw_event->refcount); - return fw_event; -} - -/* raid transport support */ -static struct raid_template *mpt2sas_raid_template; - -/** - * 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 - * @timeout: timeout for this command - * @VF_ID: virtual function id - * @VP_ID: virtual port id - * @valid_reply: flag set for reply message - * @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 VF_ID; - u8 VP_ID; - 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 }, - /* Meteor ~ 2116 */ - { 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 }, - /* Thunderbolt ~ 2208 */ - { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_1, - PCI_ANY_ID, PCI_ANY_ID }, - { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_2, - PCI_ANY_ID, PCI_ANY_ID }, - { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_3, - PCI_ANY_ID, PCI_ANY_ID }, - { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_4, - PCI_ANY_ID, PCI_ANY_ID }, - { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_5, - PCI_ANY_ID, PCI_ANY_ID }, - { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_6, - PCI_ANY_ID, PCI_ANY_ID }, - /* Mustang ~ 2308 */ - { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_1, - PCI_ANY_ID, PCI_ANY_ID }, - { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_2, - PCI_ANY_ID, PCI_ANY_ID }, - { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_3, - PCI_ANY_ID, PCI_ANY_ID }, - /* SSS6200 */ - { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SSS6200, - 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); - spin_lock(&gioc_lock); - list_for_each_entry(ioc, &mpt2sas_ioc_list, list) - ioc->logging_level = logging_level; - spin_unlock(&gioc_lock); - 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_get_sas_address - set the sas_address for given device handle - * @handle: device handle - * @sas_address: sas address - * - * Returns 0 success, non-zero when failure - */ -static int -_scsih_get_sas_address(struct MPT2SAS_ADAPTER *ioc, u16 handle, - u64 *sas_address) -{ - Mpi2SasDevicePage0_t sas_device_pg0; - Mpi2ConfigReply_t mpi_reply; - u32 ioc_status; - *sas_address = 0; - - if (handle <= ioc->sas_hba.num_phys) { - *sas_address = ioc->sas_hba.sas_address; - return 0; - } - - 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 -ENXIO; - } - - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; - if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { - *sas_address = le64_to_cpu(sas_device_pg0.SASAddress); - return 0; - } - - /* we hit this becuase the given parent handle doesn't exist */ - if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) - return -ENXIO; - /* else error case */ - printk(MPT2SAS_ERR_FMT "handle(0x%04x), ioc_status(0x%04x), " - "failure at %s:%d/%s()!\n", ioc->name, handle, ioc_status, - __FILE__, __LINE__, __func__); - return -EIO; -} - -/** - * _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 persistent 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->is_driver_loading) - return; - - /* no Bios, return immediately */ - if (!ioc->bios_pg3.BiosVersion) - 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_INFO_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_INFO_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_INFO_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; - } - } -} - -static struct _sas_device * -__mpt2sas_get_sdev_from_target(struct MPT2SAS_ADAPTER *ioc, - struct MPT2SAS_TARGET *tgt_priv) -{ - struct _sas_device *ret; - - assert_spin_locked(&ioc->sas_device_lock); - - ret = tgt_priv->sdev; - if (ret) - sas_device_get(ret); - - return ret; -} - -static struct _sas_device * -mpt2sas_get_sdev_from_target(struct MPT2SAS_ADAPTER *ioc, - struct MPT2SAS_TARGET *tgt_priv) -{ - struct _sas_device *ret; - unsigned long flags; - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - ret = __mpt2sas_get_sdev_from_target(ioc, tgt_priv); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - - return ret; -} - - -struct _sas_device * -__mpt2sas_get_sdev_by_addr(struct MPT2SAS_ADAPTER *ioc, - u64 sas_address) -{ - struct _sas_device *sas_device; - - assert_spin_locked(&ioc->sas_device_lock); - - list_for_each_entry(sas_device, &ioc->sas_device_list, list) - if (sas_device->sas_address == sas_address) - goto found_device; - - list_for_each_entry(sas_device, &ioc->sas_device_init_list, list) - if (sas_device->sas_address == sas_address) - goto found_device; - - return NULL; - -found_device: - sas_device_get(sas_device); - return sas_device; -} - -/** - * mpt2sas_get_sdev_by_addr - 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_get_sdev_by_addr(struct MPT2SAS_ADAPTER *ioc, - u64 sas_address) -{ - struct _sas_device *sas_device; - unsigned long flags; - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = __mpt2sas_get_sdev_by_addr(ioc, - sas_address); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - - return sas_device; -} - -static struct _sas_device * -__mpt2sas_get_sdev_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle) -{ - struct _sas_device *sas_device; - - assert_spin_locked(&ioc->sas_device_lock); - - list_for_each_entry(sas_device, &ioc->sas_device_list, list) - if (sas_device->handle == handle) - goto found_device; - - list_for_each_entry(sas_device, &ioc->sas_device_init_list, list) - if (sas_device->handle == handle) - goto found_device; - - return NULL; - -found_device: - sas_device_get(sas_device); - return sas_device; -} - -/** - * mpt2sas_get_sdev_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 * -mpt2sas_get_sdev_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle) -{ - struct _sas_device *sas_device; - unsigned long flags; - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = __mpt2sas_get_sdev_by_handle(ioc, handle); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - - return sas_device; -} - -/** - * _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. - * - * If sas_device is on the list, remove it and decrement its reference count. - */ -static void -_scsih_sas_device_remove(struct MPT2SAS_ADAPTER *ioc, - struct _sas_device *sas_device) -{ - unsigned long flags; - - if (!sas_device) - return; - - /* - * The lock serializes access to the list, but we still need to verify - * that nobody removed the entry while we were waiting on the lock. - */ - spin_lock_irqsave(&ioc->sas_device_lock, flags); - if (!list_empty(&sas_device->list)) { - list_del_init(&sas_device->list); - sas_device_put(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; - - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle" - "(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__, - sas_device->handle, (unsigned long long)sas_device->sas_address)); - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device_get(sas_device); - list_add_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->sas_address_parent)) { - _scsih_sas_device_remove(ioc, sas_device); - } else if (!sas_device->starget) { - /* When asyn scanning is enabled, its not possible to remove - * devices while scanning is turned on due to an oops in - * scsi_sysfs_add_sdev()->add_device()->sysfs_addrm_start() - */ - if (!ioc->is_driver_loading) { - mpt2sas_transport_port_remove(ioc, - sas_device->sas_address, - sas_device->sas_address_parent); - _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_INFO_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); - sas_device_get(sas_device); - list_add_tail(&sas_device->list, &ioc->sas_device_init_list); - _scsih_determine_boot_device(ioc, sas_device, 0); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -} - -/** - * _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_INFO_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 - * - */ -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); - kfree(raid_device); - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); -} - -/** - * 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; -} - -/** - * 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 - * - * Returns the smid stored scmd pointer. - */ -static struct scsi_cmnd * -_scsih_scsi_lookup_get(struct MPT2SAS_ADAPTER *ioc, u16 smid) -{ - return ioc->scsi_lookup[smid - 1].scmd; -} - -/** - * _scsih_scsi_lookup_get_clear - returns scmd entry - * @ioc: per adapter object - * @smid: system request message index - * - * Returns the smid stored scmd pointer. - * Then will derefrence the stored scmd pointer. - */ -static inline struct scsi_cmnd * -_scsih_scsi_lookup_get_clear(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_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->scsiio_depth; i++) { - if (ioc->scsi_lookup[i].scmd == scmd) { - smid = ioc->scsi_lookup[i].smid; - 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->scsiio_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_scsi_lookup_find_by_lun - search for matching channel:id:lun - * @ioc: per adapter object - * @id: target id - * @lun: lun number - * @channel: channel - * Context: This function will acquire ioc->scsi_lookup_lock. - * - * This will search for a matching channel:id:lun in the scsi_lookup array, - * returning 1 if found. - */ -static u8 -_scsih_scsi_lookup_find_by_lun(struct MPT2SAS_ADAPTER *ioc, int id, - unsigned int lun, int channel) -{ - u8 found; - unsigned long flags; - int i; - - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - found = 0; - for (i = 0 ; i < ioc->scsiio_depth; i++) { - if (ioc->scsi_lookup[i].scmd && - (ioc->scsi_lookup[i].scmd->device->id == id && - ioc->scsi_lookup[i].scmd->device->channel == channel && - ioc->scsi_lookup[i].scmd->device->lun == lun)) { - found = 1; - goto out; - } - } - out: - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - return found; -} - -/** - * _scsih_get_chain_buffer_tracker - obtain chain tracker - * @ioc: per adapter object - * @smid: smid associated to an IO request - * - * Returns chain tracker(from ioc->free_chain_list) - */ -static struct chain_tracker * -_scsih_get_chain_buffer_tracker(struct MPT2SAS_ADAPTER *ioc, u16 smid) -{ - struct chain_tracker *chain_req; - unsigned long flags; - - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - if (list_empty(&ioc->free_chain_list)) { - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - dfailprintk(ioc, printk(MPT2SAS_WARN_FMT "chain buffers not " - "available\n", ioc->name)); - return NULL; - } - chain_req = list_entry(ioc->free_chain_list.next, - struct chain_tracker, tracker_list); - list_del_init(&chain_req->tracker_list); - list_add_tail(&chain_req->tracker_list, - &ioc->scsi_lookup[smid - 1].chain_list); - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - return chain_req; -} - -/** - * _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; - int sges_left; - u32 sges_in_segment; - u32 sgl_flags; - u32 sgl_flags_last_element; - u32 sgl_flags_end_buffer; - struct chain_tracker *chain_req; - - 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 < 0) { - 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_req = _scsih_get_chain_buffer_tracker(ioc, smid); - if (!chain_req) - return -1; - chain = chain_req->chain_buffer; - chain_dma = chain_req->chain_buffer_dma; - 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_req = _scsih_get_chain_buffer_tracker(ioc, smid); - if (!chain_req) - return -1; - chain = chain_req->chain_buffer; - chain_dma = chain_req->chain_buffer_dma; - } 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; - 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; - unsigned long flags; - - max_depth = shost->can_queue; - - /* limit max device queue for SATA to 32 */ - sas_device_priv_data = sdev->hostdata; - if (!sas_device_priv_data) - goto not_sata; - sas_target_priv_data = sas_device_priv_data->sas_target; - if (!sas_target_priv_data) - goto not_sata; - if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) - goto not_sata; - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = __mpt2sas_get_sdev_from_target(ioc, sas_target_priv_data); - if (sas_device) { - if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE) - max_depth = MPT2SAS_SATA_QUEUE_DEPTH; - - sas_device_put(sas_device); - } - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - - not_sata: - if (!sdev->tagged_supported) - max_depth = 1; - if (qdepth > max_depth) - qdepth = max_depth; - return scsi_change_queue_depth(sdev, qdepth); -} - -/** - * _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(*sas_target_priv_data), - 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; - if (ioc->is_warpdrive) - sas_target_priv_data->raid_device = raid_device; - 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_get_sdev_by_addr(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_target_priv_data->sdev = sas_device; - sas_device->starget = starget; - sas_device->id = starget->id; - sas_device->channel = starget->channel; - if (test_bit(sas_device->handle, ioc->pd_handles)) - 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_get_sdev_from_target(ioc, sas_target_priv_data); - if (sas_device && (sas_device->starget == starget) && - (sas_device->id == starget->id) && - (sas_device->channel == starget->channel)) - sas_device->starget = NULL; - - if (sas_device) { - /* - * Corresponding get() is in _scsih_target_alloc() - */ - sas_target_priv_data->sdev = NULL; - sas_device_put(sas_device); - - sas_device_put(sas_device); - } - 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(*sas_device_priv_data), - 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); - } - - if (!(sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) { - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = __mpt2sas_get_sdev_by_addr(ioc, - sas_target_priv_data->sas_address); - if (sas_device && (sas_device->starget == NULL)) { - sdev_printk(KERN_INFO, sdev, - "%s : sas_device->starget set to starget @ %d\n", - __func__, __LINE__); - sas_device->starget = starget; - } - - if (sas_device) - sas_device_put(sas_device); - - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - } - - 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; - struct Scsi_Host *shost; - struct MPT2SAS_ADAPTER *ioc; - struct _sas_device *sas_device; - unsigned long flags; - - if (!sdev->hostdata) - return; - - starget = scsi_target(sdev); - sas_target_priv_data = starget->hostdata; - sas_target_priv_data->num_luns--; - - shost = dev_to_shost(&starget->dev); - ioc = shost_priv(shost); - - if (!(sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) { - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = __mpt2sas_get_sdev_from_target(ioc, - sas_target_priv_data); - if (sas_device && !sas_target_priv_data->num_luns) - sas_device->starget = NULL; - - if (sas_device) - sas_device_put(sas_device); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - } - - kfree(sdev->hostdata); - sdev->hostdata = NULL; -} - -/** - * _scsih_display_sata_capabilities - sata capabilities - * @ioc: per adapter object - * @handle: device handle - * @sdev: scsi device struct - */ -static void -_scsih_display_sata_capabilities(struct MPT2SAS_ADAPTER *ioc, - u16 handle, 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, 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 = le32_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_is_raid - return boolean indicating device is raid volume - * @dev the device struct object - */ -static int -_scsih_is_raid(struct device *dev) -{ - struct scsi_device *sdev = to_scsi_device(dev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(sdev->host); - - if (ioc->is_warpdrive) - return 0; - return (sdev->channel == RAID_CHANNEL) ? 1 : 0; -} - -/** - * _scsih_get_resync - get raid volume resync percent complete - * @dev the device struct object - */ -static void -_scsih_get_resync(struct device *dev) -{ - struct scsi_device *sdev = to_scsi_device(dev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(sdev->host); - static struct _raid_device *raid_device; - unsigned long flags; - Mpi2RaidVolPage0_t vol_pg0; - Mpi2ConfigReply_t mpi_reply; - u32 volume_status_flags; - u8 percent_complete; - u16 handle; - - percent_complete = 0; - handle = 0; - if (ioc->is_warpdrive) - goto out; - - spin_lock_irqsave(&ioc->raid_device_lock, flags); - raid_device = _scsih_raid_device_find_by_id(ioc, sdev->id, - sdev->channel); - if (raid_device) { - handle = raid_device->handle; - percent_complete = raid_device->percent_complete; - } - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); - - if (!handle) - goto out; - - if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0, - MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle, - sizeof(Mpi2RaidVolPage0_t))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - percent_complete = 0; - goto out; - } - - volume_status_flags = le32_to_cpu(vol_pg0.VolumeStatusFlags); - if (!(volume_status_flags & - MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS)) - percent_complete = 0; - - out: - raid_set_resync(mpt2sas_raid_template, dev, percent_complete); -} - -/** - * _scsih_get_state - get raid volume level - * @dev the device struct object - */ -static void -_scsih_get_state(struct device *dev) -{ - struct scsi_device *sdev = to_scsi_device(dev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(sdev->host); - static struct _raid_device *raid_device; - unsigned long flags; - Mpi2RaidVolPage0_t vol_pg0; - Mpi2ConfigReply_t mpi_reply; - u32 volstate; - enum raid_state state = RAID_STATE_UNKNOWN; - u16 handle = 0; - - spin_lock_irqsave(&ioc->raid_device_lock, flags); - raid_device = _scsih_raid_device_find_by_id(ioc, sdev->id, - sdev->channel); - if (raid_device) - handle = raid_device->handle; - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); - - if (!raid_device) - goto out; - - if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0, - MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle, - sizeof(Mpi2RaidVolPage0_t))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - goto out; - } - - volstate = le32_to_cpu(vol_pg0.VolumeStatusFlags); - if (volstate & MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS) { - state = RAID_STATE_RESYNCING; - goto out; - } - - switch (vol_pg0.VolumeState) { - case MPI2_RAID_VOL_STATE_OPTIMAL: - case MPI2_RAID_VOL_STATE_ONLINE: - state = RAID_STATE_ACTIVE; - break; - case MPI2_RAID_VOL_STATE_DEGRADED: - state = RAID_STATE_DEGRADED; - break; - case MPI2_RAID_VOL_STATE_FAILED: - case MPI2_RAID_VOL_STATE_MISSING: - state = RAID_STATE_OFFLINE; - break; - } - out: - raid_set_state(mpt2sas_raid_template, dev, state); -} - -/** - * _scsih_set_level - set raid level - * @sdev: scsi device struct - * @volume_type: volume type - */ -static void -_scsih_set_level(struct scsi_device *sdev, u8 volume_type) -{ - enum raid_level level = RAID_LEVEL_UNKNOWN; - - switch (volume_type) { - case MPI2_RAID_VOL_TYPE_RAID0: - level = RAID_LEVEL_0; - break; - case MPI2_RAID_VOL_TYPE_RAID10: - level = RAID_LEVEL_10; - break; - case MPI2_RAID_VOL_TYPE_RAID1E: - level = RAID_LEVEL_1E; - break; - case MPI2_RAID_VOL_TYPE_RAID1: - level = RAID_LEVEL_1; - break; - } - - raid_set_level(mpt2sas_raid_template, &sdev->sdev_gendev, level); -} - -/** - * _scsih_get_volume_capabilities - volume capabilities - * @ioc: per adapter object - * @sas_device: the raid_device object - * - * Returns 0 for success, else 1 - */ -static int -_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) { - dfailprintk(ioc, printk(MPT2SAS_WARN_FMT - "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, - __func__)); - return 1; - } - - 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) { - dfailprintk(ioc, printk(MPT2SAS_WARN_FMT - "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, - __func__)); - return 1; - } - - if ((mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, vol_pg0, - MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, sz))) { - dfailprintk(ioc, printk(MPT2SAS_WARN_FMT - "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, - __func__)); - kfree(vol_pg0); - return 1; - } - - 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); - return 0; -} -/** - * _scsih_disable_ddio - Disable direct I/O for all the volumes - * @ioc: per adapter object - */ -static void -_scsih_disable_ddio(struct MPT2SAS_ADAPTER *ioc) -{ - Mpi2RaidVolPage1_t vol_pg1; - Mpi2ConfigReply_t mpi_reply; - struct _raid_device *raid_device; - u16 handle; - u16 ioc_status; - unsigned long flags; - - handle = 0xFFFF; - while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply, - &vol_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(vol_pg1.DevHandle); - spin_lock_irqsave(&ioc->raid_device_lock, flags); - raid_device = _scsih_raid_device_find_by_handle(ioc, handle); - if (raid_device) - raid_device->direct_io_enabled = 0; - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); - } - return; -} - - -/** - * _scsih_get_num_volumes - Get number of volumes in the ioc - * @ioc: per adapter object - */ -static u8 -_scsih_get_num_volumes(struct MPT2SAS_ADAPTER *ioc) -{ - Mpi2RaidVolPage1_t vol_pg1; - Mpi2ConfigReply_t mpi_reply; - u16 handle; - u8 vol_cnt = 0; - u16 ioc_status; - - handle = 0xFFFF; - while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply, - &vol_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; - vol_cnt++; - handle = le16_to_cpu(vol_pg1.DevHandle); - } - return vol_cnt; -} - - -/** - * _scsih_init_warpdrive_properties - Set properties for warpdrive direct I/O. - * @ioc: per adapter object - * @raid_device: the raid_device object - */ -static void -_scsih_init_warpdrive_properties(struct MPT2SAS_ADAPTER *ioc, - struct _raid_device *raid_device) -{ - Mpi2RaidVolPage0_t *vol_pg0; - Mpi2RaidPhysDiskPage0_t pd_pg0; - Mpi2ConfigReply_t mpi_reply; - u16 sz; - u8 num_pds, count; - unsigned long stripe_sz, block_sz; - u8 stripe_exp, block_exp; - u64 dev_max_lba; - - if (!ioc->is_warpdrive) - return; - - if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_EXPOSE_ALL_DISKS) { - printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled " - "globally as drives are exposed\n", ioc->name); - return; - } - if (_scsih_get_num_volumes(ioc) > 1) { - _scsih_disable_ddio(ioc); - printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled " - "globally as number of drives > 1\n", ioc->name); - return; - } - if ((mpt2sas_config_get_number_pds(ioc, raid_device->handle, - &num_pds)) || !num_pds) { - printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled " - "Failure in computing number of drives\n", ioc->name); - return; - } - - sz = offsetof(Mpi2RaidVolPage0_t, PhysDisk) + (num_pds * - sizeof(Mpi2RaidVol0PhysDisk_t)); - vol_pg0 = kzalloc(sz, GFP_KERNEL); - if (!vol_pg0) { - printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled " - "Memory allocation failure for RVPG0\n", ioc->name); - 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_INFO_FMT "WarpDrive : Direct IO is disabled " - "Failure in retrieving RVPG0\n", ioc->name); - kfree(vol_pg0); - return; - } - - /* - * WARPDRIVE:If number of physical disks in a volume exceeds the max pds - * assumed for WARPDRIVE, disable direct I/O - */ - if (num_pds > MPT_MAX_WARPDRIVE_PDS) { - printk(MPT2SAS_WARN_FMT "WarpDrive : Direct IO is disabled " - "for the drive with handle(0x%04x): num_mem=%d, " - "max_mem_allowed=%d\n", ioc->name, raid_device->handle, - num_pds, MPT_MAX_WARPDRIVE_PDS); - kfree(vol_pg0); - return; - } - for (count = 0; count < num_pds; count++) { - if (mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply, - &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM, - vol_pg0->PhysDisk[count].PhysDiskNum) || - le16_to_cpu(pd_pg0.DevHandle) == - MPT2SAS_INVALID_DEVICE_HANDLE) { - printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is " - "disabled for the drive with handle(0x%04x) member" - "handle retrieval failed for member number=%d\n", - ioc->name, raid_device->handle, - vol_pg0->PhysDisk[count].PhysDiskNum); - goto out_error; - } - /* Disable direct I/O if member drive lba exceeds 4 bytes */ - dev_max_lba = le64_to_cpu(pd_pg0.DeviceMaxLBA); - if (dev_max_lba >> 32) { - printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is " - "disabled for the drive with handle(0x%04x) member" - "handle (0x%04x) unsupported max lba 0x%016llx\n", - ioc->name, raid_device->handle, - le16_to_cpu(pd_pg0.DevHandle), - (unsigned long long)dev_max_lba); - goto out_error; - } - - raid_device->pd_handle[count] = le16_to_cpu(pd_pg0.DevHandle); - } - - /* - * Assumption for WD: Direct I/O is not supported if the volume is - * not RAID0 - */ - if (raid_device->volume_type != MPI2_RAID_VOL_TYPE_RAID0) { - printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled " - "for the drive with handle(0x%04x): type=%d, " - "s_sz=%uK, blk_size=%u\n", ioc->name, - raid_device->handle, raid_device->volume_type, - (le32_to_cpu(vol_pg0->StripeSize) * - le16_to_cpu(vol_pg0->BlockSize)) / 1024, - le16_to_cpu(vol_pg0->BlockSize)); - goto out_error; - } - - stripe_sz = le32_to_cpu(vol_pg0->StripeSize); - stripe_exp = find_first_bit(&stripe_sz, 32); - if (stripe_exp == 32) { - printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled " - "for the drive with handle(0x%04x) invalid stripe sz %uK\n", - ioc->name, raid_device->handle, - (le32_to_cpu(vol_pg0->StripeSize) * - le16_to_cpu(vol_pg0->BlockSize)) / 1024); - goto out_error; - } - raid_device->stripe_exponent = stripe_exp; - block_sz = le16_to_cpu(vol_pg0->BlockSize); - block_exp = find_first_bit(&block_sz, 16); - if (block_exp == 16) { - printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled " - "for the drive with handle(0x%04x) invalid block sz %u\n", - ioc->name, raid_device->handle, - le16_to_cpu(vol_pg0->BlockSize)); - goto out_error; - } - raid_device->block_exponent = block_exp; - raid_device->direct_io_enabled = 1; - - printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is Enabled for the drive" - " with handle(0x%04x)\n", ioc->name, raid_device->handle); - /* - * WARPDRIVE: Though the following fields are not used for direct IO, - * stored for future purpose: - */ - raid_device->max_lba = le64_to_cpu(vol_pg0->MaxLBA); - raid_device->stripe_sz = le32_to_cpu(vol_pg0->StripeSize); - raid_device->block_sz = le16_to_cpu(vol_pg0->BlockSize); - - - kfree(vol_pg0); - return; - -out_error: - raid_device->direct_io_enabled = 0; - for (count = 0; count < num_pds; count++) - raid_device->pd_handle[count] = 0; - kfree(vol_pg0); - return; -} - -/** - * _scsih_enable_tlr - setting TLR flags - * @ioc: per adapter object - * @sdev: scsi device struct - * - * Enabling Transaction Layer Retries for tape devices when - * vpd page 0x90 is present - * - */ -static void -_scsih_enable_tlr(struct MPT2SAS_ADAPTER *ioc, struct scsi_device *sdev) -{ - /* only for TAPE */ - if (sdev->type != TYPE_TAPE) - return; - - if (!(ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TLR)) - return; - - sas_enable_tlr(sdev); - sdev_printk(KERN_INFO, sdev, "TLR %s\n", - sas_is_tlr_enabled(sdev) ? "Enabled" : "Disabled"); - return; - -} - -/** - * _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 = ""; - u16 handle, volume_handle = 0; - u64 volume_wwid = 0; - - 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; - handle = sas_target_priv_data->handle; - - /* 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, handle); - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); - if (!raid_device) { - dfailprintk(ioc, printk(MPT2SAS_WARN_FMT - "failure at %s:%d/%s()!\n", ioc->name, __FILE__, - __LINE__, __func__)); - return 1; - } - - if (_scsih_get_volume_capabilities(ioc, raid_device)) { - dfailprintk(ioc, printk(MPT2SAS_WARN_FMT - "failure at %s:%d/%s()!\n", ioc->name, __FILE__, - __LINE__, __func__)); - return 1; - } - /* - * WARPDRIVE: Initialize the required data for Direct IO - */ - _scsih_init_warpdrive_properties(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; - if (ioc->manu_pg10.OEMIdentifier && - (le32_to_cpu(ioc->manu_pg10.GenericFlags0) & - MFG10_GF0_R10_DISPLAY) && - !(raid_device->num_pds % 2)) - r_level = "RAID10"; - else - 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; - } - - if (!ioc->hide_ir_msg) - 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); - /* raid transport support */ - if (!ioc->is_warpdrive) - _scsih_set_level(sdev, raid_device->volume_type); - return 0; - } - - /* non-raid handling */ - if (sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) { - if (mpt2sas_config_get_volume_handle(ioc, handle, - &volume_handle)) { - dfailprintk(ioc, printk(MPT2SAS_WARN_FMT - "failure at %s:%d/%s()!\n", ioc->name, - __FILE__, __LINE__, __func__)); - return 1; - } - if (volume_handle && mpt2sas_config_get_volume_wwid(ioc, - volume_handle, &volume_wwid)) { - dfailprintk(ioc, printk(MPT2SAS_WARN_FMT - "failure at %s:%d/%s()!\n", ioc->name, - __FILE__, __LINE__, __func__)); - return 1; - } - } - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = __mpt2sas_get_sdev_by_addr(ioc, - sas_device_priv_data->sas_target->sas_address); - if (!sas_device) { - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - dfailprintk(ioc, printk(MPT2SAS_WARN_FMT - "failure at %s:%d/%s()!\n", ioc->name, __FILE__, - __LINE__, __func__)); - return 1; - } - sas_device->volume_handle = volume_handle; - sas_device->volume_wwid = 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), phy(%d), device_name(0x%016llx)\n", - ds, sas_device->handle, - (unsigned long long)sas_device->sas_address, - sas_device->phy, - (unsigned long long)sas_device->device_name); - sdev_printk(KERN_INFO, sdev, "%s: " - "enclosure_logical_id(0x%016llx), slot(%d)\n", ds, - (unsigned long long) sas_device->enclosure_logical_id, - sas_device->slot); - - sas_device_put(sas_device); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - if (!ssp_target) - _scsih_display_sata_capabilities(ioc, handle, sdev); - - _scsih_change_queue_depth(sdev, qdepth); - - if (ssp_target) { - sas_read_port_mode_page(sdev); - _scsih_enable_tlr(ioc, 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 - * @msix_index: MSIX table index supplied by the OS - * @reply: reply message frame(lower 32bit addr) - * Context: none. - * - * The callback handler when using scsih_issue_tm. - * - * Return 1 meaning mf should be freed from _base_interrupt - * 0 means the mf is freed from this function. - */ -static u8 -_scsih_tm_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) -{ - MPI2DefaultReply_t *mpi_reply; - - if (ioc->tm_cmds.status == MPT2_CMD_NOT_USED) - return 1; - if (ioc->tm_cmds.smid != smid) - return 1; - mpt2sas_base_flush_reply_queues(ioc); - 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); - return 1; -} - -/** - * 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 - * @channel: the channel assigned by the OS - * @id: the id assigned by the OS - * @lun: lun number - * @type: MPI2_SCSITASKMGMT_TASKTYPE__XXX (defined in mpi2_init.h) - * @smid_task: smid assigned to the task - * @timeout: timeout in seconds - * @m_type: TM_MUTEX_ON or TM_MUTEX_OFF - * Context: user - * - * A generic API for sending task management requests to firmware. - * - * The callback index is set inside `ioc->tm_cb_idx`. - * - * Return SUCCESS or FAILED. - */ -int -mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint channel, - uint id, uint lun, u8 type, u16 smid_task, ulong timeout, - enum mutex_type m_type) -{ - Mpi2SCSITaskManagementRequest_t *mpi_request; - Mpi2SCSITaskManagementReply_t *mpi_reply; - u16 smid = 0; - u32 ioc_state; - unsigned long timeleft; - struct scsiio_tracker *scsi_lookup = NULL; - int rc; - - if (m_type == TM_MUTEX_ON) - mutex_lock(&ioc->tm_cmds.mutex); - if (ioc->tm_cmds.status != MPT2_CMD_NOT_USED) { - printk(MPT2SAS_INFO_FMT "%s: tm_cmd busy!!!\n", - __func__, ioc->name); - rc = FAILED; - goto err_out; - } - - if (ioc->shost_recovery || ioc->remove_host || - ioc->pci_error_recovery) { - printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n", - __func__, ioc->name); - rc = FAILED; - goto err_out; - } - - ioc_state = mpt2sas_base_get_iocstate(ioc, 0); - if (ioc_state & MPI2_DOORBELL_USED) { - dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "unexpected doorbell " - "active!\n", ioc->name)); - rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, - FORCE_BIG_HAMMER); - rc = (!rc) ? SUCCESS : FAILED; - goto err_out; - } - - if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) { - mpt2sas_base_fault_info(ioc, ioc_state & - MPI2_DOORBELL_DATA_MASK); - rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, - FORCE_BIG_HAMMER); - rc = (!rc) ? SUCCESS : FAILED; - goto err_out; - } - - smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_cb_idx); - if (!smid) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); - rc = FAILED; - goto err_out; - } - - if (type == MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK) - scsi_lookup = &ioc->scsi_lookup[smid_task - 1]; - - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "sending tm: handle(0x%04x)," - " task_type(0x%02x), smid(%d)\n", ioc->name, handle, type, - smid_task)); - 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)); - memset(ioc->tm_cmds.reply, 0, sizeof(Mpi2SCSITaskManagementReply_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); - init_completion(&ioc->tm_cmds.done); - mpt2sas_base_put_smid_hi_priority(ioc, smid); - timeleft = wait_for_completion_timeout(&ioc->tm_cmds.done, timeout*HZ); - 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)) { - rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, - FORCE_BIG_HAMMER); - rc = (!rc) ? SUCCESS : FAILED; - ioc->tm_cmds.status = MPT2_CMD_NOT_USED; - mpt2sas_scsih_clear_tm_flag(ioc, handle); - goto err_out; - } - } - - 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); - if (mpi_reply->IOCStatus) - _debug_dump_mf(mpi_request, - sizeof(Mpi2SCSITaskManagementRequest_t)/4); - } - } - - switch (type) { - case MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK: - rc = SUCCESS; - if (scsi_lookup->scmd == NULL) - break; - rc = FAILED; - break; - - case MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET: - if (_scsih_scsi_lookup_find_by_target(ioc, id, channel)) - rc = FAILED; - else - rc = SUCCESS; - break; - - case MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET: - case MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET: - if (_scsih_scsi_lookup_find_by_lun(ioc, id, lun, channel)) - rc = FAILED; - else - rc = SUCCESS; - break; - case MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK: - rc = SUCCESS; - break; - default: - rc = FAILED; - break; - } - - mpt2sas_scsih_clear_tm_flag(ioc, handle); - ioc->tm_cmds.status = MPT2_CMD_NOT_USED; - if (m_type == TM_MUTEX_ON) - mutex_unlock(&ioc->tm_cmds.mutex); - - return rc; - - err_out: - if (m_type == TM_MUTEX_ON) - mutex_unlock(&ioc->tm_cmds.mutex); - return rc; -} - -/** - * _scsih_tm_display_info - displays info about the device - * @ioc: per adapter struct - * @scmd: pointer to scsi command object - * - * Called by task management callback handlers. - */ -static void -_scsih_tm_display_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd) -{ - struct scsi_target *starget = scmd->device->sdev_target; - struct MPT2SAS_TARGET *priv_target = starget->hostdata; - struct _sas_device *sas_device = NULL; - unsigned long flags; - char *device_str = NULL; - - if (!priv_target) - return; - if (ioc->hide_ir_msg) - device_str = "WarpDrive"; - else - device_str = "volume"; - - scsi_print_command(scmd); - if (priv_target->flags & MPT_TARGET_FLAGS_VOLUME) { - starget_printk(KERN_INFO, starget, "%s handle(0x%04x), " - "%s wwid(0x%016llx)\n", device_str, priv_target->handle, - device_str, (unsigned long long)priv_target->sas_address); - } else { - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = __mpt2sas_get_sdev_from_target(ioc, priv_target); - if (sas_device) { - if (priv_target->flags & - MPT_TARGET_FLAGS_RAID_COMPONENT) { - starget_printk(KERN_INFO, starget, - "volume handle(0x%04x), " - "volume wwid(0x%016llx)\n", - sas_device->volume_handle, - (unsigned long long)sas_device->volume_wwid); - } - starget_printk(KERN_INFO, starget, - "handle(0x%04x), sas_address(0x%016llx), phy(%d)\n", - sas_device->handle, - (unsigned long long)sas_device->sas_address, - sas_device->phy); - starget_printk(KERN_INFO, starget, - "enclosure_logical_id(0x%016llx), slot(%d)\n", - (unsigned long long)sas_device->enclosure_logical_id, - sas_device->slot); - - sas_device_put(sas_device); - } - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - } -} - -/** - * _scsih_abort - eh threads main abort routine - * @scmd: pointer to scsi command object - * - * 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; - - sdev_printk(KERN_INFO, scmd->device, "attempting task abort! " - "scmd(%p)\n", scmd); - _scsih_tm_display_info(ioc, scmd); - - sas_device_priv_data = scmd->device->hostdata; - if (!sas_device_priv_data || !sas_device_priv_data->sas_target) { - sdev_printk(KERN_INFO, scmd->device, "device been deleted! " - "scmd(%p)\n", scmd); - scmd->result = DID_NO_CONNECT << 16; - scmd->scsi_done(scmd); - r = SUCCESS; - 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; - } - - mpt2sas_halt_firmware(ioc); - - handle = sas_device_priv_data->sas_target->handle; - r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel, - scmd->device->id, scmd->device->lun, - MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30, TM_MUTEX_ON); - - out: - sdev_printk(KERN_INFO, scmd->device, "task abort: %s scmd(%p)\n", - ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); - return r; -} - -/** - * _scsih_dev_reset - eh threads main device reset routine - * @scmd: pointer to scsi command object - * - * 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 = NULL; - u16 handle; - int r; - - struct scsi_target *starget = scmd->device->sdev_target; - struct MPT2SAS_TARGET *target_priv_data = starget->hostdata; - - starget_printk(KERN_INFO, starget, "attempting device reset! " - "scmd(%p)\n", scmd); - _scsih_tm_display_info(ioc, scmd); - - sas_device_priv_data = scmd->device->hostdata; - if (!sas_device_priv_data || !sas_device_priv_data->sas_target) { - starget_printk(KERN_INFO, starget, "device been deleted! " - "scmd(%p)\n", 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) { - sas_device = mpt2sas_get_sdev_from_target(ioc, - target_priv_data); - if (sas_device) - handle = sas_device->volume_handle; - } else - handle = sas_device_priv_data->sas_target->handle; - - if (!handle) { - scmd->result = DID_RESET << 16; - r = FAILED; - goto out; - } - - r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel, - scmd->device->id, scmd->device->lun, - MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, 0, 30, TM_MUTEX_ON); - - out: - sdev_printk(KERN_INFO, scmd->device, "device reset: %s scmd(%p)\n", - ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); - - if (sas_device) - sas_device_put(sas_device); - - return r; -} - -/** - * _scsih_target_reset - eh threads main target reset routine - * @scmd: pointer to scsi command object - * - * Returns SUCCESS if command aborted else FAILED - */ -static int -_scsih_target_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 = NULL; - u16 handle; - int r; - struct scsi_target *starget = scmd->device->sdev_target; - struct MPT2SAS_TARGET *target_priv_data = starget->hostdata; - - starget_printk(KERN_INFO, starget, "attempting target reset! " - "scmd(%p)\n", scmd); - _scsih_tm_display_info(ioc, scmd); - - sas_device_priv_data = scmd->device->hostdata; - if (!sas_device_priv_data || !sas_device_priv_data->sas_target) { - starget_printk(KERN_INFO, starget, "target been deleted! " - "scmd(%p)\n", 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) { - sas_device = mpt2sas_get_sdev_from_target(ioc, - target_priv_data); - if (sas_device) - handle = sas_device->volume_handle; - } else - handle = sas_device_priv_data->sas_target->handle; - - if (!handle) { - scmd->result = DID_RESET << 16; - r = FAILED; - goto out; - } - - r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel, - scmd->device->id, 0, MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, - 30, TM_MUTEX_ON); - - out: - starget_printk(KERN_INFO, starget, "target reset: %s scmd(%p)\n", - ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); - - if (sas_device) - sas_device_put(sas_device); - - return r; -} - -/** - * _scsih_host_reset - eh threads main host reset routine - * @scmd: pointer to scsi command object - * - * 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); - - if (ioc->is_driver_loading) { - printk(MPT2SAS_INFO_FMT "Blocking the host reset\n", - ioc->name); - r = FAILED; - goto out; - } - - retval = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, - FORCE_BIG_HAMMER); - r = (retval < 0) ? FAILED : SUCCESS; - - out: - 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); - fw_event_work_get(fw_event); - list_add_tail(&fw_event->list, &ioc->fw_event_list); - INIT_DELAYED_WORK(&fw_event->delayed_work, _firmware_event_work); - fw_event_work_get(fw_event); - queue_delayed_work(ioc->firmware_event_thread, - &fw_event->delayed_work, 0); - spin_unlock_irqrestore(&ioc->fw_event_lock, flags); -} - -/** - * _scsih_fw_event_del_from_list - delete fw_event from the list - * @ioc: per adapter object - * @fw_event: object describing the event - * Context: This function will acquire ioc->fw_event_lock. - * - * If the fw_event is on the fw_event_list, remove it and do a put. - * - * Return nothing. - */ -static void -_scsih_fw_event_del_from_list(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work - *fw_event) -{ - unsigned long flags; - - spin_lock_irqsave(&ioc->fw_event_lock, flags); - if (!list_empty(&fw_event->list)) { - list_del_init(&fw_event->list); - fw_event_work_put(fw_event); - } - spin_unlock_irqrestore(&ioc->fw_event_lock, flags); -} - -/** - * _scsih_error_recovery_delete_devices - remove devices not responding - * @ioc: per adapter object - * - * Return nothing. - */ -static void -_scsih_error_recovery_delete_devices(struct MPT2SAS_ADAPTER *ioc) -{ - struct fw_event_work *fw_event; - - if (ioc->is_driver_loading) - return; - - fw_event = alloc_fw_event_work(0); - if (!fw_event) - return; - - fw_event->event = MPT2SAS_REMOVE_UNRESPONDING_DEVICES; - fw_event->ioc = ioc; - _scsih_fw_event_add(ioc, fw_event); - fw_event_work_put(fw_event); -} - -/** - * mpt2sas_port_enable_complete - port enable completed (fake event) - * @ioc: per adapter object - * - * Return nothing. - */ -void -mpt2sas_port_enable_complete(struct MPT2SAS_ADAPTER *ioc) -{ - struct fw_event_work *fw_event; - - fw_event = alloc_fw_event_work(0); - if (!fw_event) - return; - fw_event->event = MPT2SAS_PORT_ENABLE_COMPLETE; - fw_event->ioc = ioc; - _scsih_fw_event_add(ioc, fw_event); - fw_event_work_put(fw_event); -} - -static struct fw_event_work *dequeue_next_fw_event(struct MPT2SAS_ADAPTER *ioc) -{ - unsigned long flags; - struct fw_event_work *fw_event = NULL; - - spin_lock_irqsave(&ioc->fw_event_lock, flags); - if (!list_empty(&ioc->fw_event_list)) { - fw_event = list_first_entry(&ioc->fw_event_list, - struct fw_event_work, list); - list_del_init(&fw_event->list); - } - spin_unlock_irqrestore(&ioc->fw_event_lock, flags); - - return fw_event; -} - -/** - * _scsih_fw_event_cleanup_queue - cleanup event queue - * @ioc: per adapter object - * - * Walk the firmware event queue, either killing timers, or waiting - * for outstanding events to complete - * - * Return nothing. - */ -static void -_scsih_fw_event_cleanup_queue(struct MPT2SAS_ADAPTER *ioc) -{ - struct fw_event_work *fw_event; - - if (list_empty(&ioc->fw_event_list) || - !ioc->firmware_event_thread || in_interrupt()) - return; - - while ((fw_event = dequeue_next_fw_event(ioc))) { - /* - * Wait on the fw_event to complete. If this returns 1, then - * the event was never executed, and we need a put for the - * reference the delayed_work had on the fw_event. - * - * If it did execute, we wait for it to finish, and the put will - * happen from _firmware_event_work() - */ - if (cancel_delayed_work_sync(&fw_event->delayed_work)) - fw_event_work_put(fw_event); - - fw_event_work_put(fw_event); - } -} - -/** - * _scsih_ublock_io_all_device - unblock every device - * @ioc: per adapter object - * - * change the device state from block to running - */ -static void -_scsih_ublock_io_all_device(struct MPT2SAS_ADAPTER *ioc) -{ - 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; - sas_device_priv_data->block = 0; - dewtprintk(ioc, sdev_printk(KERN_INFO, sdev, "device_running, " - "handle(0x%04x)\n", - sas_device_priv_data->sas_target->handle)); - scsi_internal_device_unblock(sdev, SDEV_RUNNING); - } -} -/** - * _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, u64 sas_address) -{ - 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->sas_address == - sas_address) { - dewtprintk(ioc, sdev_printk(KERN_INFO, sdev, - MPT2SAS_INFO_FMT "SDEV_RUNNING: " - "sas address(0x%016llx)\n", ioc->name, - (unsigned long long)sas_address)); - sas_device_priv_data->block = 0; - scsi_internal_device_unblock(sdev, SDEV_RUNNING); - } - } -} - -/** - * _scsih_block_io_all_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_all_device(struct MPT2SAS_ADAPTER *ioc) -{ - 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; - sas_device_priv_data->block = 1; - dewtprintk(ioc, sdev_printk(KERN_INFO, sdev, "device_blocked, " - "handle(0x%04x)\n", - sas_device_priv_data->sas_target->handle)); - scsi_internal_device_block(sdev); - } -} - - -/** - * _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_internal_device_block(sdev); - } - } -} - -/** - * _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_get_sdev_by_addr(ioc, - mpt2sas_port->remote_identify.sas_address); - if (sas_device) { - set_bit(sas_device->handle, - ioc->blocking_handles); - sas_device_put(sas_device); - } - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - } - } - - list_for_each_entry(mpt2sas_port, - &sas_expander->sas_port_list, port_list) { - - if (mpt2sas_port->remote_identify.device_type == - SAS_EDGE_EXPANDER_DEVICE || - mpt2sas_port->remote_identify.device_type == - SAS_FANOUT_EXPANDER_DEVICE) { - expander_sibling = - mpt2sas_scsih_expander_find_by_sas_address( - ioc, mpt2sas_port->remote_identify.sas_address); - _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_tm_tr_send - send task management request - * @ioc: per adapter object - * @handle: device handle - * Context: interrupt time. - * - * This code is to initiate the device removal handshake protocol - * with controller firmware. This function will issue target reset - * using high priority request queue. It will send a sas iounit - * control request (MPI2_SAS_OP_REMOVE_DEVICE) from this completion. - * - * This is designed to send muliple task management request at the same - * time to the fifo. If the fifo is full, we will append the request, - * and process it in a future completion. - */ -static void -_scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle) -{ - Mpi2SCSITaskManagementRequest_t *mpi_request; - u16 smid; - struct _sas_device *sas_device = NULL; - struct MPT2SAS_TARGET *sas_target_priv_data = NULL; - u64 sas_address = 0; - unsigned long flags; - struct _tr_list *delayed_tr; - u32 ioc_state; - - if (ioc->remove_host) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host has been " - "removed: handle(0x%04x)\n", __func__, ioc->name, handle)); - return; - } else if (ioc->pci_error_recovery) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host in pci " - "error recovery: handle(0x%04x)\n", __func__, ioc->name, - handle)); - return; - } - ioc_state = mpt2sas_base_get_iocstate(ioc, 1); - if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host is not " - "operational: handle(0x%04x)\n", __func__, ioc->name, - handle)); - return; - } - - /* if PD, then return */ - if (test_bit(handle, ioc->pd_handles)) - return; - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = __mpt2sas_get_sdev_by_handle(ioc, handle); - if (sas_device && sas_device->starget && - sas_device->starget->hostdata) { - sas_target_priv_data = sas_device->starget->hostdata; - sas_target_priv_data->deleted = 1; - sas_address = sas_device->sas_address; - } - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - - if (sas_target_priv_data) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "setting delete flag: " - "handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, handle, - (unsigned long long)sas_address)); - _scsih_ublock_io_device(ioc, sas_address); - sas_target_priv_data->handle = MPT2SAS_INVALID_DEVICE_HANDLE; - } - - smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_tr_cb_idx); - if (!smid) { - delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC); - if (!delayed_tr) - goto out; - INIT_LIST_HEAD(&delayed_tr->list); - delayed_tr->handle = handle; - list_add_tail(&delayed_tr->list, &ioc->delayed_tr_list); - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT - "DELAYED:tr:handle(0x%04x), (open)\n", - ioc->name, handle)); - goto out; - } - - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "tr_send:handle(0x%04x), " - "(open), smid(%d), cb(%d)\n", ioc->name, handle, smid, - ioc->tm_tr_cb_idx)); - mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); - memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t)); - mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; - mpi_request->DevHandle = cpu_to_le16(handle); - mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET; - mpt2sas_base_put_smid_hi_priority(ioc, smid); -out: - if (sas_device) - sas_device_put(sas_device); -} - - - -/** - * _scsih_sas_control_complete - completion routine - * @ioc: per adapter object - * @smid: system request message index - * @msix_index: MSIX table index supplied by the OS - * @reply: reply message frame(lower 32bit addr) - * Context: interrupt time. - * - * This is the sas iounit control completion routine. - * This code is part of the code to initiate the device removal - * handshake protocol with controller firmware. - * - * Return 1 meaning mf should be freed from _base_interrupt - * 0 means the mf is freed from this function. - */ -static u8 -_scsih_sas_control_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, - u8 msix_index, u32 reply) -{ - Mpi2SasIoUnitControlReply_t *mpi_reply = - mpt2sas_base_get_reply_virt_addr(ioc, reply); - if (likely(mpi_reply)) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT - "sc_complete:handle(0x%04x), (open) " - "smid(%d), ioc_status(0x%04x), loginfo(0x%08x)\n", - ioc->name, le16_to_cpu(mpi_reply->DevHandle), smid, - le16_to_cpu(mpi_reply->IOCStatus), - le32_to_cpu(mpi_reply->IOCLogInfo))); - } else { - printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - } - return 1; -} - -/** - * _scsih_tm_tr_volume_send - send target reset request for volumes - * @ioc: per adapter object - * @handle: device handle - * Context: interrupt time. - * - * This is designed to send muliple task management request at the same - * time to the fifo. If the fifo is full, we will append the request, - * and process it in a future completion. - */ -static void -_scsih_tm_tr_volume_send(struct MPT2SAS_ADAPTER *ioc, u16 handle) -{ - Mpi2SCSITaskManagementRequest_t *mpi_request; - u16 smid; - struct _tr_list *delayed_tr; - - if (ioc->shost_recovery || ioc->remove_host || - ioc->pci_error_recovery) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in " - "progress!\n", __func__, ioc->name)); - return; - } - - smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_tr_volume_cb_idx); - if (!smid) { - delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC); - if (!delayed_tr) - return; - INIT_LIST_HEAD(&delayed_tr->list); - delayed_tr->handle = handle; - list_add_tail(&delayed_tr->list, &ioc->delayed_tr_volume_list); - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT - "DELAYED:tr:handle(0x%04x), (open)\n", - ioc->name, handle)); - return; - } - - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "tr_send:handle(0x%04x), " - "(open), smid(%d), cb(%d)\n", ioc->name, handle, smid, - ioc->tm_tr_volume_cb_idx)); - mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); - memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t)); - mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; - mpi_request->DevHandle = cpu_to_le16(handle); - mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET; - mpt2sas_base_put_smid_hi_priority(ioc, smid); -} - -/** - * _scsih_tm_volume_tr_complete - target reset completion - * @ioc: per adapter object - * @smid: system request message index - * @msix_index: MSIX table index supplied by the OS - * @reply: reply message frame(lower 32bit addr) - * Context: interrupt time. - * - * Return 1 meaning mf should be freed from _base_interrupt - * 0 means the mf is freed from this function. - */ -static u8 -_scsih_tm_volume_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, - u8 msix_index, u32 reply) -{ - u16 handle; - Mpi2SCSITaskManagementRequest_t *mpi_request_tm; - Mpi2SCSITaskManagementReply_t *mpi_reply = - mpt2sas_base_get_reply_virt_addr(ioc, reply); - - if (ioc->shost_recovery || ioc->remove_host || - ioc->pci_error_recovery) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in " - "progress!\n", __func__, ioc->name)); - return 1; - } - if (unlikely(!mpi_reply)) { - printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return 1; - } - mpi_request_tm = mpt2sas_base_get_msg_frame(ioc, smid); - handle = le16_to_cpu(mpi_request_tm->DevHandle); - if (handle != le16_to_cpu(mpi_reply->DevHandle)) { - dewtprintk(ioc, printk("spurious interrupt: " - "handle(0x%04x:0x%04x), smid(%d)!!!\n", handle, - le16_to_cpu(mpi_reply->DevHandle), smid)); - return 0; - } - - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT - "tr_complete:handle(0x%04x), (open) smid(%d), ioc_status(0x%04x), " - "loginfo(0x%08x), completed(%d)\n", ioc->name, - handle, smid, le16_to_cpu(mpi_reply->IOCStatus), - le32_to_cpu(mpi_reply->IOCLogInfo), - le32_to_cpu(mpi_reply->TerminationCount))); - - return _scsih_check_for_pending_tm(ioc, smid); -} - -/** - * _scsih_tm_tr_complete - - * @ioc: per adapter object - * @smid: system request message index - * @msix_index: MSIX table index supplied by the OS - * @reply: reply message frame(lower 32bit addr) - * Context: interrupt time. - * - * This is the target reset completion routine. - * This code is part of the code to initiate the device removal - * handshake protocol with controller firmware. - * It will send a sas iounit control request (MPI2_SAS_OP_REMOVE_DEVICE) - * - * Return 1 meaning mf should be freed from _base_interrupt - * 0 means the mf is freed from this function. - */ -static u8 -_scsih_tm_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, - u32 reply) -{ - u16 handle; - Mpi2SCSITaskManagementRequest_t *mpi_request_tm; - Mpi2SCSITaskManagementReply_t *mpi_reply = - mpt2sas_base_get_reply_virt_addr(ioc, reply); - Mpi2SasIoUnitControlRequest_t *mpi_request; - u16 smid_sas_ctrl; - u32 ioc_state; - - if (ioc->remove_host) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host has been " - "removed\n", __func__, ioc->name)); - return 1; - } else if (ioc->pci_error_recovery) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host in pci " - "error recovery\n", __func__, ioc->name)); - return 1; - } - ioc_state = mpt2sas_base_get_iocstate(ioc, 1); - if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host is not " - "operational\n", __func__, ioc->name)); - return 1; - } - if (unlikely(!mpi_reply)) { - printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return 1; - } - mpi_request_tm = mpt2sas_base_get_msg_frame(ioc, smid); - handle = le16_to_cpu(mpi_request_tm->DevHandle); - if (handle != le16_to_cpu(mpi_reply->DevHandle)) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "spurious interrupt: " - "handle(0x%04x:0x%04x), smid(%d)!!!\n", ioc->name, handle, - le16_to_cpu(mpi_reply->DevHandle), smid)); - return 0; - } - - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT - "tr_complete:handle(0x%04x), (open) smid(%d), ioc_status(0x%04x), " - "loginfo(0x%08x), completed(%d)\n", ioc->name, - handle, smid, le16_to_cpu(mpi_reply->IOCStatus), - le32_to_cpu(mpi_reply->IOCLogInfo), - le32_to_cpu(mpi_reply->TerminationCount))); - - smid_sas_ctrl = mpt2sas_base_get_smid(ioc, ioc->tm_sas_control_cb_idx); - if (!smid_sas_ctrl) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); - return 1; - } - - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sc_send:handle(0x%04x), " - "(open), smid(%d), cb(%d)\n", ioc->name, handle, smid_sas_ctrl, - ioc->tm_sas_control_cb_idx)); - mpi_request = mpt2sas_base_get_msg_frame(ioc, smid_sas_ctrl); - 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 = mpi_request_tm->DevHandle; - mpt2sas_base_put_smid_default(ioc, smid_sas_ctrl); - - return _scsih_check_for_pending_tm(ioc, smid); -} - -/** - * _scsih_check_for_pending_tm - check for pending task management - * @ioc: per adapter object - * @smid: system request message index - * - * This will check delayed target reset list, and feed the - * next reqeust. - * - * Return 1 meaning mf should be freed from _base_interrupt - * 0 means the mf is freed from this function. - */ -static u8 -_scsih_check_for_pending_tm(struct MPT2SAS_ADAPTER *ioc, u16 smid) -{ - struct _tr_list *delayed_tr; - - if (!list_empty(&ioc->delayed_tr_volume_list)) { - delayed_tr = list_entry(ioc->delayed_tr_volume_list.next, - struct _tr_list, list); - mpt2sas_base_free_smid(ioc, smid); - _scsih_tm_tr_volume_send(ioc, delayed_tr->handle); - list_del(&delayed_tr->list); - kfree(delayed_tr); - return 0; - } - - if (!list_empty(&ioc->delayed_tr_list)) { - delayed_tr = list_entry(ioc->delayed_tr_list.next, - struct _tr_list, list); - mpt2sas_base_free_smid(ioc, smid); - _scsih_tm_tr_send(ioc, delayed_tr->handle); - list_del(&delayed_tr->list); - kfree(delayed_tr); - return 0; - } - - return 1; -} - -/** - * _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 receives 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; - int i, reason_code; - u16 handle; - - for (i = 0 ; i < event_data->NumEntries; i++) { - handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle); - if (!handle) - continue; - reason_code = event_data->PHY[i].PhyStatus & - MPI2_EVENT_SAS_TOPO_RC_MASK; - if (reason_code == MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING) - _scsih_tm_tr_send(ioc, handle); - } - - 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) { - /* put expander attached devices into blocking state */ - spin_lock_irqsave(&ioc->sas_node_lock, flags); - sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc, - expander_handle); - _scsih_block_io_to_children_attached_to_ex(ioc, sas_expander); - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - do { - handle = find_first_bit(ioc->blocking_handles, - ioc->facts.MaxDevHandle); - if (handle < ioc->facts.MaxDevHandle) - _scsih_block_io_device(ioc, handle); - } while (test_and_clear_bit(handle, ioc->blocking_handles)); - } 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 = (Mpi2EventDataSasTopologyChangeList_t *) - 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_INFO_FMT - "setting ignoring flag\n", ioc->name)); - fw_event->ignore = 1; - } - } - } - spin_unlock_irqrestore(&ioc->fw_event_lock, flags); -} - -/** - * _scsih_set_volume_delete_flag - setting volume delete flag - * @ioc: per adapter object - * @handle: device handle - * - * This - * Return nothing. - */ -static void -_scsih_set_volume_delete_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle) -{ - struct _raid_device *raid_device; - struct MPT2SAS_TARGET *sas_target_priv_data; - unsigned long flags; - - spin_lock_irqsave(&ioc->raid_device_lock, flags); - raid_device = _scsih_raid_device_find_by_handle(ioc, handle); - if (raid_device && raid_device->starget && - raid_device->starget->hostdata) { - sas_target_priv_data = - raid_device->starget->hostdata; - sas_target_priv_data->deleted = 1; - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT - "setting delete flag: handle(0x%04x), " - "wwid(0x%016llx)\n", ioc->name, handle, - (unsigned long long) raid_device->wwid)); - } - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); -} - -/** - * _scsih_set_volume_handle_for_tr - set handle for target reset to volume - * @handle: input handle - * @a: handle for volume a - * @b: handle for volume b - * - * IR firmware only supports two raid volumes. The purpose of this - * routine is to set the volume handle in either a or b. When the given - * input handle is non-zero, or when a and b have not been set before. - */ -static void -_scsih_set_volume_handle_for_tr(u16 handle, u16 *a, u16 *b) -{ - if (!handle || handle == *a || handle == *b) - return; - if (!*a) - *a = handle; - else if (!*b) - *b = handle; -} - -/** - * _scsih_check_ir_config_unhide_events - check for UNHIDE events - * @ioc: per adapter object - * @event_data: the event data payload - * Context: interrupt time. - * - * This routine will send target reset to volume, followed by target - * resets to the PDs. This is called when a PD has been removed, or - * volume has been deleted or removed. When the target reset is sent - * to volume, the PD target resets need to be queued to start upon - * completion of the volume target reset. - * - * Return nothing. - */ -static void -_scsih_check_ir_config_unhide_events(struct MPT2SAS_ADAPTER *ioc, - Mpi2EventDataIrConfigChangeList_t *event_data) -{ - Mpi2EventIrConfigElement_t *element; - int i; - u16 handle, volume_handle, a, b; - struct _tr_list *delayed_tr; - - a = 0; - b = 0; - - if (ioc->is_warpdrive) - return; - - /* Volume Resets for Deleted or Removed */ - element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0]; - for (i = 0; i < event_data->NumElements; i++, element++) { - if (element->ReasonCode == - MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED || - element->ReasonCode == - MPI2_EVENT_IR_CHANGE_RC_REMOVED) { - volume_handle = le16_to_cpu(element->VolDevHandle); - _scsih_set_volume_delete_flag(ioc, volume_handle); - _scsih_set_volume_handle_for_tr(volume_handle, &a, &b); - } - } - - /* Volume Resets for UNHIDE events */ - element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0]; - for (i = 0; i < event_data->NumElements; i++, element++) { - if (le32_to_cpu(event_data->Flags) & - MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) - continue; - if (element->ReasonCode == MPI2_EVENT_IR_CHANGE_RC_UNHIDE) { - volume_handle = le16_to_cpu(element->VolDevHandle); - _scsih_set_volume_handle_for_tr(volume_handle, &a, &b); - } - } - - if (a) - _scsih_tm_tr_volume_send(ioc, a); - if (b) - _scsih_tm_tr_volume_send(ioc, b); - - /* PD target resets */ - element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0]; - for (i = 0; i < event_data->NumElements; i++, element++) { - if (element->ReasonCode != MPI2_EVENT_IR_CHANGE_RC_UNHIDE) - continue; - handle = le16_to_cpu(element->PhysDiskDevHandle); - volume_handle = le16_to_cpu(element->VolDevHandle); - clear_bit(handle, ioc->pd_handles); - if (!volume_handle) - _scsih_tm_tr_send(ioc, handle); - else if (volume_handle == a || volume_handle == b) { - delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC); - BUG_ON(!delayed_tr); - INIT_LIST_HEAD(&delayed_tr->list); - delayed_tr->handle = handle; - list_add_tail(&delayed_tr->list, &ioc->delayed_tr_list); - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT - "DELAYED:tr:handle(0x%04x), (open)\n", ioc->name, - handle)); - } else - _scsih_tm_tr_send(ioc, handle); - } -} - - -/** - * _scsih_check_volume_delete_events - set delete flag for volumes - * @ioc: per adapter object - * @event_data: the event data payload - * Context: interrupt time. - * - * This will handle the case when the cable connected to entire volume is - * pulled. We will take care of setting the deleted flag so normal IO will - * not be sent. - * - * Return nothing. - */ -static void -_scsih_check_volume_delete_events(struct MPT2SAS_ADAPTER *ioc, - Mpi2EventDataIrVolume_t *event_data) -{ - u32 state; - - if (event_data->ReasonCode != MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED) - return; - state = le32_to_cpu(event_data->NewValue); - if (state == MPI2_RAID_VOL_STATE_MISSING || state == - MPI2_RAID_VOL_STATE_FAILED) - _scsih_set_volume_delete_flag(ioc, - le16_to_cpu(event_data->VolDevHandle)); -} - -/** - * _scsih_temp_threshold_events - display temperature threshold exceeded events - * @ioc: per adapter object - * @event_data: the temp threshold event data - * Context: interrupt time. - * - * Return nothing. - */ -static void -_scsih_temp_threshold_events(struct MPT2SAS_ADAPTER *ioc, - Mpi2EventDataTemperature_t *event_data) -{ - if (ioc->temp_sensors_count >= event_data->SensorNum) { - printk(MPT2SAS_ERR_FMT "Temperature Threshold flags %s%s%s%s" - " exceeded for Sensor: %d !!!\n", ioc->name, - ((le16_to_cpu(event_data->Status) & 0x1) == 1) ? "0 " : " ", - ((le16_to_cpu(event_data->Status) & 0x2) == 2) ? "1 " : " ", - ((le16_to_cpu(event_data->Status) & 0x4) == 4) ? "2 " : " ", - ((le16_to_cpu(event_data->Status) & 0x8) == 8) ? "3 " : " ", - event_data->SensorNum); - printk(MPT2SAS_ERR_FMT "Current Temp In Celsius: %d\n", - ioc->name, event_data->CurrentTemperature); - } -} - -/** - * _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->scsiio_depth; smid++) { - scmd = _scsih_scsi_lookup_get_clear(ioc, smid); - if (!scmd) - continue; - count++; - mpt2sas_base_free_smid(ioc, smid); - scsi_dma_unmap(scmd); - if (ioc->pci_error_recovery) - scmd->result = DID_NO_CONNECT << 16; - else - scmd->result = DID_RESET << 16; - scmd->scsi_done(scmd); - } - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "completing %d cmds\n", - ioc->name, count)); -} - -/** - * _scsih_setup_eedp - setup MPI request for EEDP transfer - * @scmd: pointer to scsi command object - * @mpi_request: pointer to the SCSI_IO reqest message frame - * - * Supporting protection 1 and 3. - * - * Returns nothing - */ -static void -_scsih_setup_eedp(struct scsi_cmnd *scmd, Mpi2SCSIIORequest_t *mpi_request) -{ - u16 eedp_flags; - unsigned char prot_op = scsi_get_prot_op(scmd); - unsigned char prot_type = scsi_get_prot_type(scmd); - - if (prot_type == SCSI_PROT_DIF_TYPE0 || prot_op == SCSI_PROT_NORMAL) - return; - - if (prot_op == SCSI_PROT_READ_STRIP) - eedp_flags = MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP; - else if (prot_op == SCSI_PROT_WRITE_INSERT) - eedp_flags = MPI2_SCSIIO_EEDPFLAGS_INSERT_OP; - else - return; - - switch (prot_type) { - case SCSI_PROT_DIF_TYPE1: - case SCSI_PROT_DIF_TYPE2: - - /* - * enable ref/guard checking - * auto increment ref tag - */ - eedp_flags |= MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG | - MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG | - MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD; - mpi_request->CDB.EEDP32.PrimaryReferenceTag = - cpu_to_be32(scsi_get_lba(scmd)); - break; - - case SCSI_PROT_DIF_TYPE3: - - /* - * enable guard checking - */ - eedp_flags |= MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD; - break; - } - mpi_request->EEDPBlockSize = cpu_to_le32(scmd->device->sector_size); - mpi_request->EEDPFlags = cpu_to_le16(eedp_flags); -} - -/** - * _scsih_eedp_error_handling - return sense code for EEDP errors - * @scmd: pointer to scsi command object - * @ioc_status: ioc status - * - * Returns nothing - */ -static void -_scsih_eedp_error_handling(struct scsi_cmnd *scmd, u16 ioc_status) -{ - u8 ascq; - - switch (ioc_status) { - case MPI2_IOCSTATUS_EEDP_GUARD_ERROR: - ascq = 0x01; - break; - case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR: - ascq = 0x02; - break; - case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR: - ascq = 0x03; - break; - default: - ascq = 0x00; - break; - } - - scsi_build_sense_buffer(0, scmd->sense_buffer, ILLEGAL_REQUEST, 0x10, ascq); - scmd->result = DRIVER_SENSE << 24 | (DID_ABORT << 16) | - SAM_STAT_CHECK_CONDITION; -} - -/** - * _scsih_scsi_direct_io_get - returns direct io flag - * @ioc: per adapter object - * @smid: system request message index - * - * Returns the smid stored scmd pointer. - */ -static inline u8 -_scsih_scsi_direct_io_get(struct MPT2SAS_ADAPTER *ioc, u16 smid) -{ - return ioc->scsi_lookup[smid - 1].direct_io; -} - -/** - * _scsih_scsi_direct_io_set - sets direct io flag - * @ioc: per adapter object - * @smid: system request message index - * @direct_io: Zero or non-zero value to set in the direct_io flag - * - * Returns Nothing. - */ -static inline void -_scsih_scsi_direct_io_set(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 direct_io) -{ - ioc->scsi_lookup[smid - 1].direct_io = direct_io; -} - - -/** - * _scsih_setup_direct_io - setup MPI request for WARPDRIVE Direct I/O - * @ioc: per adapter object - * @scmd: pointer to scsi command object - * @raid_device: pointer to raid device data structure - * @mpi_request: pointer to the SCSI_IO reqest message frame - * @smid: system request message index - * - * Returns nothing - */ -static void -_scsih_setup_direct_io(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, - struct _raid_device *raid_device, Mpi2SCSIIORequest_t *mpi_request, - u16 smid) -{ - sector_t v_lba, p_lba, stripe_off, column, io_size; - u32 stripe_sz, stripe_exp; - u8 num_pds, cmd = scmd->cmnd[0]; - - if (cmd != READ_10 && cmd != WRITE_10 && - cmd != READ_16 && cmd != WRITE_16) - return; - - if (cmd == READ_10 || cmd == WRITE_10) - v_lba = get_unaligned_be32(&mpi_request->CDB.CDB32[2]); - else - v_lba = get_unaligned_be64(&mpi_request->CDB.CDB32[2]); - - io_size = scsi_bufflen(scmd) >> raid_device->block_exponent; - - if (v_lba + io_size - 1 > raid_device->max_lba) - return; - - stripe_sz = raid_device->stripe_sz; - stripe_exp = raid_device->stripe_exponent; - stripe_off = v_lba & (stripe_sz - 1); - - /* Return unless IO falls within a stripe */ - if (stripe_off + io_size > stripe_sz) - return; - - num_pds = raid_device->num_pds; - p_lba = v_lba >> stripe_exp; - column = sector_div(p_lba, num_pds); - p_lba = (p_lba << stripe_exp) + stripe_off; - - mpi_request->DevHandle = cpu_to_le16(raid_device->pd_handle[column]); - - if (cmd == READ_10 || cmd == WRITE_10) - put_unaligned_be32(lower_32_bits(p_lba), - &mpi_request->CDB.CDB32[2]); - else - put_unaligned_be64(p_lba, &mpi_request->CDB.CDB32[2]); - - _scsih_scsi_direct_io_set(ioc, smid, 1); -} - -/** - * _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_Host *shost, struct scsi_cmnd *scmd) -{ - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - struct MPT2SAS_DEVICE *sas_device_priv_data; - struct MPT2SAS_TARGET *sas_target_priv_data; - struct _raid_device *raid_device; - Mpi2SCSIIORequest_t *mpi_request; - u32 mpi_control; - u16 smid; - - sas_device_priv_data = scmd->device->hostdata; - if (!sas_device_priv_data || !sas_device_priv_data->sas_target) { - scmd->result = DID_NO_CONNECT << 16; - scmd->scsi_done(scmd); - return 0; - } - - if (ioc->pci_error_recovery || ioc->remove_host) { - scmd->result = DID_NO_CONNECT << 16; - scmd->scsi_done(scmd); - return 0; - } - - sas_target_priv_data = sas_device_priv_data->sas_target; - /* invalid device handle */ - if (sas_target_priv_data->handle == MPT2SAS_INVALID_DEVICE_HANDLE) { - scmd->result = DID_NO_CONNECT << 16; - scmd->scsi_done(scmd); - return 0; - } - - /* host recovery or link resets sent via IOCTLs */ - if (ioc->shost_recovery || ioc->ioc_link_reset_in_progress) - return SCSI_MLQUEUE_HOST_BUSY; - /* device busy with task management */ - else if (sas_device_priv_data->block || sas_target_priv_data->tm_busy) - return SCSI_MLQUEUE_DEVICE_BUSY; - /* device has been deleted */ - else if (sas_target_priv_data->deleted) { - scmd->result = DID_NO_CONNECT << 16; - scmd->scsi_done(scmd); - return 0; - } - - 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 */ - mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ; - - /* Make sure Device is not raid volume. - * We do not expose raid functionality to upper layer for warpdrive. - */ - if (!ioc->is_warpdrive && !_scsih_is_raid(&scmd->device->sdev_gendev) && - sas_is_tlr_enabled(scmd->device) && scmd->cmd_len != 32) - mpi_control |= MPI2_SCSIIO_CONTROL_TLR_ON; - - smid = mpt2sas_base_get_smid_scsiio(ioc, ioc->scsi_io_cb_idx, scmd); - 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)); - _scsih_setup_eedp(scmd, mpi_request); - if (scmd->cmd_len == 32) - mpi_control |= 4 << MPI2_SCSIIO_CONTROL_ADDCDBLEN_SHIFT; - mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST; - if (sas_device_priv_data->sas_target->flags & - MPT_TARGET_FLAGS_RAID_COMPONENT) - 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 = - 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); - mpi_request->VF_ID = 0; /* TODO */ - mpi_request->VP_ID = 0; - 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; - } - } - - raid_device = sas_target_priv_data->raid_device; - if (raid_device && raid_device->direct_io_enabled) - _scsih_setup_direct_io(ioc, scmd, raid_device, mpi_request, - smid); - - if (likely(mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST)) - mpt2sas_base_put_smid_scsi_io(ioc, smid, - le16_to_cpu(mpi_request->DevHandle)); - else - mpt2sas_base_put_smid_default(ioc, smid); - 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-successful 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; - u32 log_info = le32_to_cpu(mpi_reply->IOCLogInfo); - struct _sas_device *sas_device = NULL; - struct scsi_target *starget = scmd->device->sdev_target; - struct MPT2SAS_TARGET *priv_target = starget->hostdata; - char *device_str = NULL; - - if (!priv_target) - return; - - if (ioc->hide_ir_msg) - device_str = "WarpDrive"; - else - device_str = "volume"; - - if (log_info == 0x31170000) - return; - - 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; - case MPI2_IOCSTATUS_EEDP_GUARD_ERROR: - desc_ioc_state = "eedp guard error"; - break; - case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR: - desc_ioc_state = "eedp ref tag error"; - break; - case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR: - desc_ioc_state = "eedp app tag error"; - 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); - - if (priv_target->flags & MPT_TARGET_FLAGS_VOLUME) { - printk(MPT2SAS_WARN_FMT "\t%s wwid(0x%016llx)\n", ioc->name, - device_str, (unsigned long long)priv_target->sas_address); - } else { - sas_device = mpt2sas_get_sdev_from_target(ioc, priv_target); - if (sas_device) { - printk(MPT2SAS_WARN_FMT "\tsas_address(0x%016llx), " - "phy(%d)\n", ioc->name, sas_device->sas_address, - sas_device->phy); - printk(MPT2SAS_WARN_FMT - "\tenclosure_logical_id(0x%016llx), slot(%d)\n", - ioc->name, sas_device->enclosure_logical_id, - sas_device->slot); - - sas_device_put(sas_device); - } - } - - printk(MPT2SAS_WARN_FMT "\thandle(0x%04x), ioc_status(%s)(0x%04x), " - "smid(%d)\n", ioc->name, le16_to_cpu(mpi_reply->DevHandle), - desc_ioc_state, ioc_status, smid); - printk(MPT2SAS_WARN_FMT "\trequest_len(%d), underflow(%d), " - "resid(%d)\n", ioc->name, scsi_bufflen(scmd), scmd->underflow, - scsi_get_resid(scmd)); - 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], count(%d)\n", ioc->name, data.skey, - data.asc, data.ascq, le32_to_cpu(mpi_reply->SenseCount)); - } - - 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[0]); - } -} -#endif - -/** - * _scsih_turn_on_pfa_led - illuminate PFA LED - * @ioc: per adapter object - * @handle: device handle - * Context: process - * - * Return nothing. - */ -static void -_scsih_turn_on_pfa_led(struct MPT2SAS_ADAPTER *ioc, u16 handle) -{ - Mpi2SepReply_t mpi_reply; - Mpi2SepRequest_t mpi_request; - struct _sas_device *sas_device; - - sas_device = mpt2sas_get_sdev_by_handle(ioc, handle); - if (!sas_device) - return; - - 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 = - cpu_to_le32(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__); - goto out; - } - sas_device->pfa_led_on = 1; - - - 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))); - goto out; - } -out: - sas_device_put(sas_device); -} - -/** - * _scsih_turn_off_pfa_led - turn off PFA LED - * @ioc: per adapter object - * @sas_device: sas device whose PFA LED has to turned off - * Context: process - * - * Return nothing. - */ -static void -_scsih_turn_off_pfa_led(struct MPT2SAS_ADAPTER *ioc, - struct _sas_device *sas_device) -{ - Mpi2SepReply_t mpi_reply; - Mpi2SepRequest_t mpi_request; - - 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 = 0; - mpi_request.Slot = cpu_to_le16(sas_device->slot); - mpi_request.DevHandle = 0; - mpi_request.EnclosureHandle = cpu_to_le16(sas_device->enclosure_handle); - mpi_request.Flags = MPI2_SEP_REQ_FLAGS_ENCLOSURE_SLOT_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; - } -} - -/** - * _scsih_send_event_to_turn_on_pfa_led - fire delayed event - * @ioc: per adapter object - * @handle: device handle - * Context: interrupt. - * - * Return nothing. - */ -static void -_scsih_send_event_to_turn_on_pfa_led(struct MPT2SAS_ADAPTER *ioc, u16 handle) -{ - struct fw_event_work *fw_event; - - fw_event = alloc_fw_event_work(0); - if (!fw_event) - return; - fw_event->event = MPT2SAS_TURN_ON_PFA_LED; - fw_event->device_handle = handle; - fw_event->ioc = ioc; - _scsih_fw_event_add(ioc, fw_event); - fw_event_work_put(fw_event); -} - -/** - * _scsih_smart_predicted_fault - process smart errors - * @ioc: per adapter object - * @handle: device handle - * Context: interrupt. - * - * Return nothing. - */ -static void -_scsih_smart_predicted_fault(struct MPT2SAS_ADAPTER *ioc, u16 handle) -{ - 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 = __mpt2sas_get_sdev_by_handle(ioc, handle); - if (!sas_device) { - goto out_unlock; - } - 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))) - goto out_unlock; - - 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) - _scsih_send_event_to_turn_on_pfa_led(ioc, handle); - - /* insert into event log */ - sz = offsetof(Mpi2EventNotificationReply_t, EventData) + - sizeof(Mpi2EventDataSasDeviceStatusChange_t); - event_reply = kzalloc(sz, GFP_ATOMIC); - if (!event_reply) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - goto out; - } - - 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); -out: - if (sas_device) - sas_device_put(sas_device); - return; - -out_unlock: - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - goto out; -} - -/** - * _scsih_io_done - scsi request callback - * @ioc: per adapter object - * @smid: system request message index - * @msix_index: MSIX table index supplied by the OS - * @reply: reply message frame(lower 32bit addr) - * - * Callback handler when using _scsih_qcmd. - * - * Return 1 meaning mf should be freed from _base_interrupt - * 0 means the mf is freed from this function. - */ -static u8 -_scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, 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 = 0; - unsigned long flags; - - mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); - scmd = _scsih_scsi_lookup_get_clear(ioc, smid); - if (scmd == NULL) - return 1; - - 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; - } - ioc_status = le16_to_cpu(mpi_reply->IOCStatus); - /* - * WARPDRIVE: If direct_io is set then it is directIO, - * the failed direct I/O should be redirected to volume - */ - if (_scsih_scsi_direct_io_get(ioc, smid) && - ((ioc_status & MPI2_IOCSTATUS_MASK) - != MPI2_IOCSTATUS_SCSI_TASK_TERMINATED)) { - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - ioc->scsi_lookup[smid - 1].scmd = scmd; - _scsih_scsi_direct_io_set(ioc, smid, 0); - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len); - mpi_request->DevHandle = - cpu_to_le16(sas_device_priv_data->sas_target->handle); - mpt2sas_base_put_smid_scsi_io(ioc, smid, - sas_device_priv_data->sas_target->handle); - return 0; - } - - - /* turning off TLR */ - scsi_state = mpi_reply->SCSIState; - if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) - response_code = - le32_to_cpu(mpi_reply->ResponseInfo) & 0xFF; - if (!sas_device_priv_data->tlr_snoop_check) { - sas_device_priv_data->tlr_snoop_check++; - /* Make sure Device is not raid volume. - * We do not expose raid functionality to upper layer for warpdrive. - */ - if (!ioc->is_warpdrive && !_scsih_is_raid(&scmd->device->sdev_gendev) && - sas_is_tlr_enabled(scmd->device) && - response_code == MPI2_SCSITASKMGMT_RSP_INVALID_FRAME) { - sas_disable_tlr(scmd->device); - sdev_printk(KERN_INFO, scmd->device, "TLR disabled\n"); - } - } - - xfer_cnt = le32_to_cpu(mpi_reply->TransferCount); - scsi_set_resid(scmd, scsi_bufflen(scmd) - xfer_cnt); - 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_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); - u32 sz = min_t(u32, SCSI_SENSE_BUFFERSIZE, - le32_to_cpu(mpi_reply->SenseCount)); - memcpy(scmd->sense_buffer, sense_data, sz); - _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_TRANSPORT_DISRUPTED << 16; - goto out; - } - if (log_info == 0x32010081) { - scmd->result = DID_RESET << 16; - break; - } - scmd->result = DID_SOFT_ERROR << 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 (response_code == - MPI2_SCSITASKMGMT_RSP_INVALID_FRAME || - (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_EEDP_GUARD_ERROR: - case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR: - case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR: - _scsih_eedp_error_handling(scmd, ioc_status); - 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); - return 1; -} - -/** - * _scsih_sas_host_refresh - refreshing sas host object contents - * @ioc: per adapter object - * 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) -{ - u16 sz; - u16 ioc_status; - int i; - Mpi2ConfigReply_t mpi_reply; - Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL; - u16 attached_handle; - u8 link_rate; - - 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)) != 0) - goto out; - 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++) { - link_rate = sas_iounit_pg0->PhyData[i].NegotiatedLinkRate >> 4; - if (i == 0) - ioc->sas_hba.handle = le16_to_cpu(sas_iounit_pg0-> - PhyData[0].ControllerDevHandle); - ioc->sas_hba.phy[i].handle = ioc->sas_hba.handle; - attached_handle = le16_to_cpu(sas_iounit_pg0->PhyData[i]. - AttachedDevHandle); - if (attached_handle && link_rate < MPI2_SAS_NEG_LINK_RATE_1_5) - link_rate = MPI2_SAS_NEG_LINK_RATE_1_5; - mpt2sas_transport_update_links(ioc, ioc->sas_hba.sas_address, - attached_handle, i, link_rate); - } - 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; - } - - if (i == 0) - ioc->sas_hba.handle = le16_to_cpu(sas_iounit_pg0-> - PhyData[0].ControllerDevHandle); - ioc->sas_hba.phy[i].handle = ioc->sas_hba.handle; - 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.handle))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - goto out; - } - 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; - u64 sas_address, sas_address_parent = 0; - int i; - unsigned long flags; - struct _sas_port *mpt2sas_port = NULL; - int rc = 0; - - if (!handle) - return -1; - - if (ioc->shost_recovery || ioc->pci_error_recovery) - 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 (_scsih_get_sas_address(ioc, parent_handle, &sas_address_parent) - != 0) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return -1; - } - if (sas_address_parent != ioc->sas_hba.sas_address) { - spin_lock_irqsave(&ioc->sas_node_lock, flags); - sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc, - sas_address_parent); - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - if (!sas_expander) { - rc = _scsih_expander_add(ioc, parent_handle); - if (rc != 0) - return rc; - } - } - - spin_lock_irqsave(&ioc->sas_node_lock, flags); - sas_address = le64_to_cpu(expander_pg0.SASAddress); - 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->sas_address_parent = sas_address_parent; - 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, 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_address_parent); - 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__); - rc = -1; - goto out_fail; - } - sas_expander->phy[i].handle = handle; - sas_expander->phy[i].phy_id = i; - - if ((mpt2sas_transport_add_expander_phy(ioc, - &sas_expander->phy[i], expander_pg1, - sas_expander->parent_dev))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - rc = -1; - goto out_fail; - } - } - - 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 (mpt2sas_port) - mpt2sas_transport_port_remove(ioc, sas_expander->sas_address, - sas_address_parent); - kfree(sas_expander); - return rc; -} - -/** - * _scsih_done - scsih callback handler. - * @ioc: per adapter object - * @smid: system request message index - * @msix_index: MSIX table index supplied by the OS - * @reply: reply message frame(lower 32bit addr) - * - * Callback handler when sending internal generated message frames. - * The callback index passed is `ioc->scsih_cb_idx` - * - * Return 1 meaning mf should be freed from _base_interrupt - * 0 means the mf is freed from this function. - */ -static u8 -_scsih_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) -{ - MPI2DefaultReply_t *mpi_reply; - - mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); - if (ioc->scsih_cmds.status == MPT2_CMD_NOT_USED) - return 1; - if (ioc->scsih_cmds.smid != smid) - return 1; - ioc->scsih_cmds.status |= MPT2_CMD_COMPLETE; - if (mpi_reply) { - memcpy(ioc->scsih_cmds.reply, mpi_reply, - mpi_reply->MsgLength*4); - ioc->scsih_cmds.status |= MPT2_CMD_REPLY_VALID; - } - ioc->scsih_cmds.status &= ~MPT2_CMD_PENDING; - complete(&ioc->scsih_cmds.done); - return 1; -} - -/** - * mpt2sas_expander_remove - removing expander object - * @ioc: per adapter object - * @sas_address: expander sas_address - * - * Return nothing. - */ -void -mpt2sas_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address) -{ - struct _sas_node *sas_expander; - unsigned long flags; - - if (ioc->shost_recovery) - return; - - spin_lock_irqsave(&ioc->sas_node_lock, flags); - sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc, - sas_address); - if (sas_expander) - list_del(&sas_expander->list); - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - if (sas_expander) - _scsih_expander_node_remove(ioc, sas_expander); -} - -/** - * _scsih_check_access_status - check access flags - * @ioc: per adapter object - * @sas_address: sas address - * @handle: sas device handle - * @access_flags: errors returned during discovery of the device - * - * Return 0 for success, else failure - */ -static u8 -_scsih_check_access_status(struct MPT2SAS_ADAPTER *ioc, u64 sas_address, - u16 handle, u8 access_status) -{ - u8 rc = 1; - char *desc = NULL; - - switch (access_status) { - case MPI2_SAS_DEVICE0_ASTATUS_NO_ERRORS: - case MPI2_SAS_DEVICE0_ASTATUS_SATA_NEEDS_INITIALIZATION: - rc = 0; - break; - case MPI2_SAS_DEVICE0_ASTATUS_SATA_CAPABILITY_FAILED: - desc = "sata capability failed"; - break; - case MPI2_SAS_DEVICE0_ASTATUS_SATA_AFFILIATION_CONFLICT: - desc = "sata affiliation conflict"; - break; - case MPI2_SAS_DEVICE0_ASTATUS_ROUTE_NOT_ADDRESSABLE: - desc = "route not addressable"; - break; - case MPI2_SAS_DEVICE0_ASTATUS_SMP_ERROR_NOT_ADDRESSABLE: - desc = "smp error not addressable"; - break; - case MPI2_SAS_DEVICE0_ASTATUS_DEVICE_BLOCKED: - desc = "device blocked"; - break; - case MPI2_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED: - case MPI2_SAS_DEVICE0_ASTATUS_SIF_UNKNOWN: - case MPI2_SAS_DEVICE0_ASTATUS_SIF_AFFILIATION_CONFLICT: - case MPI2_SAS_DEVICE0_ASTATUS_SIF_DIAG: - case MPI2_SAS_DEVICE0_ASTATUS_SIF_IDENTIFICATION: - case MPI2_SAS_DEVICE0_ASTATUS_SIF_CHECK_POWER: - case MPI2_SAS_DEVICE0_ASTATUS_SIF_PIO_SN: - case MPI2_SAS_DEVICE0_ASTATUS_SIF_MDMA_SN: - case MPI2_SAS_DEVICE0_ASTATUS_SIF_UDMA_SN: - case MPI2_SAS_DEVICE0_ASTATUS_SIF_ZONING_VIOLATION: - case MPI2_SAS_DEVICE0_ASTATUS_SIF_NOT_ADDRESSABLE: - case MPI2_SAS_DEVICE0_ASTATUS_SIF_MAX: - desc = "sata initialization failed"; - break; - default: - desc = "unknown"; - break; - } - - if (!rc) - return 0; - - printk(MPT2SAS_ERR_FMT "discovery errors(%s): sas_address(0x%016llx), " - "handle(0x%04x)\n", ioc->name, desc, - (unsigned long long)sas_address, handle); - return rc; -} - -static void -_scsih_check_device(struct MPT2SAS_ADAPTER *ioc, u16 handle) -{ - Mpi2ConfigReply_t mpi_reply; - Mpi2SasDevicePage0_t sas_device_pg0; - struct _sas_device *sas_device; - u32 ioc_status; - unsigned long flags; - u64 sas_address; - struct scsi_target *starget; - struct MPT2SAS_TARGET *sas_target_priv_data; - u32 device_info; - - - if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, - MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) - return; - - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) - return; - - /* check if this is end device */ - device_info = le32_to_cpu(sas_device_pg0.DeviceInfo); - if (!(_scsih_is_end_device(device_info))) - return; - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_address = le64_to_cpu(sas_device_pg0.SASAddress); - sas_device = __mpt2sas_get_sdev_by_addr(ioc, - sas_address); - - if (!sas_device) { - printk(MPT2SAS_ERR_FMT "device is not present " - "handle(0x%04x), no sas_device!!!\n", ioc->name, handle); - goto out_unlock; - } - - if (unlikely(sas_device->handle != handle)) { - starget = sas_device->starget; - sas_target_priv_data = starget->hostdata; - starget_printk(KERN_INFO, starget, "handle changed from(0x%04x)" - " to (0x%04x)!!!\n", sas_device->handle, handle); - sas_target_priv_data->handle = handle; - sas_device->handle = handle; - } - - /* check if device is present */ - if (!(le16_to_cpu(sas_device_pg0.Flags) & - MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) { - printk(MPT2SAS_ERR_FMT "device is not present " - "handle(0x%04x), flags!!!\n", ioc->name, handle); - goto out_unlock; - } - - /* check if there were any issues with discovery */ - if (_scsih_check_access_status(ioc, sas_address, handle, - sas_device_pg0.AccessStatus)) - goto out_unlock; - - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - _scsih_ublock_io_device(ioc, sas_address); - if (sas_device) - sas_device_put(sas_device); - return; - -out_unlock: - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - if (sas_device) - sas_device_put(sas_device); -} - -/** - * _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; - - 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; - } - - sas_address = le64_to_cpu(sas_device_pg0.SASAddress); - - /* 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 issues with discovery */ - if (_scsih_check_access_status(ioc, sas_address, handle, - 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_device = mpt2sas_get_sdev_by_addr(ioc, - sas_address); - - if (sas_device) { - sas_device_put(sas_device); - 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; - } - - kref_init(&sas_device->refcount); - sas_device->handle = handle; - if (_scsih_get_sas_address(ioc, le16_to_cpu - (sas_device_pg0.ParentDevHandle), - &sas_device->sas_address_parent) != 0) - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - 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->phy = sas_device_pg0.PhyNum; - - /* get enclosure_logical_id */ - if (sas_device->enclosure_handle && !(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_discovery_to_complete) - _scsih_sas_device_init_add(ioc, sas_device); - else - _scsih_sas_device_add(ioc, sas_device); - - sas_device_put(sas_device); - return 0; -} - -/** - * _scsih_remove_device - removing sas device object - * @ioc: per adapter object - * @sas_device_delete: the sas_device object - * - * Return nothing. - */ -static void -_scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, - struct _sas_device *sas_device) -{ - struct MPT2SAS_TARGET *sas_target_priv_data; - - if ((ioc->pdev->subsystem_vendor == PCI_VENDOR_ID_IBM) && - (sas_device->pfa_led_on)) { - _scsih_turn_off_pfa_led(ioc, sas_device); - sas_device->pfa_led_on = 0; - } - - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: " - "handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__, - sas_device->handle, (unsigned long long) - sas_device->sas_address)); - - if (sas_device->starget && sas_device->starget->hostdata) { - sas_target_priv_data = sas_device->starget->hostdata; - sas_target_priv_data->deleted = 1; - _scsih_ublock_io_device(ioc, sas_device->sas_address); - sas_target_priv_data->handle = - MPT2SAS_INVALID_DEVICE_HANDLE; - } - - if (!ioc->hide_drives) - mpt2sas_transport_port_remove(ioc, - sas_device->sas_address, - sas_device->sas_address_parent); - - 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); - - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit: " - "handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__, - sas_device->handle, (unsigned long long) - sas_device->sas_address)); -} -/** - * _scsih_device_remove_by_handle - removing device object by handle - * @ioc: per adapter object - * @handle: device handle - * - * Return nothing. - */ -static void -_scsih_device_remove_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle) -{ - struct _sas_device *sas_device; - unsigned long flags; - - if (ioc->shost_recovery) - return; - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = __mpt2sas_get_sdev_by_handle(ioc, handle); - if (sas_device) { - list_del_init(&sas_device->list); - sas_device_put(sas_device); - } - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - - if (sas_device) { - _scsih_remove_device(ioc, sas_device); - sas_device_put(sas_device); - } -} - -/** - * mpt2sas_device_remove_by_sas_address - removing device object by sas address - * @ioc: per adapter object - * @sas_address: device sas_address - * - * Return nothing. - */ -void -mpt2sas_device_remove_by_sas_address(struct MPT2SAS_ADAPTER *ioc, - u64 sas_address) -{ - struct _sas_device *sas_device; - unsigned long flags; - - if (ioc->shost_recovery) - return; - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = __mpt2sas_get_sdev_by_addr(ioc, sas_address); - if (sas_device) { - list_del_init(&sas_device->list); - sas_device_put(sas_device); - } - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - - if (sas_device) { - _scsih_remove_device(ioc, sas_device); - sas_device_put(sas_device); - } -} -#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; - u8 link_rate, prev_link_rate; - - 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: - case 0: - 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_INFO_FMT "sas topology change: (%s)\n", - ioc->name, status_str); - printk(KERN_INFO "\thandle(0x%04x), enclosure_handle(0x%04x) " - "start_phy(%02d), count(%d)\n", - le16_to_cpu(event_data->ExpanderDevHandle), - le16_to_cpu(event_data->EnclosureHandle), - 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: - status_str = "target add"; - break; - case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING: - status_str = "target remove"; - break; - case MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING: - status_str = "delay target remove"; - break; - case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED: - status_str = "link rate change"; - break; - case MPI2_EVENT_SAS_TOPO_RC_NO_CHANGE: - status_str = "target responding"; - break; - default: - status_str = "unknown"; - break; - } - link_rate = event_data->PHY[i].LinkRate >> 4; - prev_link_rate = event_data->PHY[i].LinkRate & 0xF; - printk(KERN_INFO "\tphy(%02d), attached_handle(0x%04x): %s:" - " link rate: new(0x%02x), old(0x%02x)\n", phy_number, - handle, status_str, link_rate, prev_link_rate); - - } -} -#endif - -/** - * _scsih_sas_topology_change_event - handle topology changes - * @ioc: per adapter object - * @fw_event: The fw_event_work object - * Context: user. - * - */ -static void -_scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc, - struct fw_event_work *fw_event) -{ - int i; - u16 parent_handle, handle; - u16 reason_code; - u8 phy_number, max_phys; - struct _sas_node *sas_expander; - u64 sas_address; - unsigned long flags; - u8 link_rate, prev_link_rate; - Mpi2EventDataSasTopologyChangeList_t *event_data = - (Mpi2EventDataSasTopologyChangeList_t *) - fw_event->event_data; - -#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->remove_host || ioc->pci_error_recovery) - return; - - if (!ioc->sas_hba.num_phys) - _scsih_sas_host_add(ioc); - else - _scsih_sas_host_refresh(ioc); - - if (fw_event->ignore) { - dewtprintk(ioc, printk(MPT2SAS_INFO_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; - - spin_lock_irqsave(&ioc->sas_node_lock, flags); - sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc, - parent_handle); - if (sas_expander) { - sas_address = sas_expander->sas_address; - max_phys = sas_expander->num_phys; - } else if (parent_handle < ioc->sas_hba.num_phys) { - sas_address = ioc->sas_hba.sas_address; - max_phys = ioc->sas_hba.num_phys; - } else { - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - return; - } - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - - /* handle siblings events */ - for (i = 0; i < event_data->NumEntries; i++) { - if (fw_event->ignore) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "ignoring " - "expander event\n", ioc->name)); - return; - } - if (ioc->shost_recovery || ioc->remove_host || - ioc->pci_error_recovery) - return; - phy_number = event_data->StartPhyNum + i; - if (phy_number >= max_phys) - continue; - reason_code = event_data->PHY[i].PhyStatus & - MPI2_EVENT_SAS_TOPO_RC_MASK; - if ((event_data->PHY[i].PhyStatus & - MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT) && (reason_code != - MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING)) - continue; - handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle); - if (!handle) - continue; - link_rate = event_data->PHY[i].LinkRate >> 4; - prev_link_rate = event_data->PHY[i].LinkRate & 0xF; - switch (reason_code) { - case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED: - - if (ioc->shost_recovery) - break; - - if (link_rate == prev_link_rate) - break; - - mpt2sas_transport_update_links(ioc, sas_address, - handle, phy_number, link_rate); - - if (link_rate < MPI2_SAS_NEG_LINK_RATE_1_5) - break; - - _scsih_check_device(ioc, handle); - break; - case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED: - - if (ioc->shost_recovery) - break; - - mpt2sas_transport_update_links(ioc, sas_address, - handle, phy_number, link_rate); - - _scsih_add_device(ioc, handle, phy_number, 0); - break; - case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING: - - _scsih_device_remove_by_handle(ioc, handle); - break; - } - } - - /* handle expander removal */ - if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING && - sas_expander) - mpt2sas_expander_remove(ioc, sas_address); - -} - -#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; - case MPI2_EVENT_SAS_DEV_STAT_RC_EXPANDER_REDUCED_FUNCTIONALITY: - reason_str = "expander reduced functionality"; - break; - case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_EXPANDER_REDUCED_FUNCTIONALITY: - reason_str = "expander reduced functionality complete"; - break; - default: - reason_str = "unknown reason"; - break; - } - printk(MPT2SAS_INFO_FMT "device status change: (%s)\n" - "\thandle(0x%04x), sas address(0x%016llx), tag(%d)", - ioc->name, reason_str, le16_to_cpu(event_data->DevHandle), - (unsigned long long)le64_to_cpu(event_data->SASAddress), - le16_to_cpu(event_data->TaskTag)); - if (event_data->ReasonCode == MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA) - printk(MPT2SAS_INFO_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 - * @fw_event: The fw_event_work object - * Context: user. - * - * Return nothing. - */ -static void -_scsih_sas_device_status_change_event(struct MPT2SAS_ADAPTER *ioc, - struct fw_event_work *fw_event) -{ - struct MPT2SAS_TARGET *target_priv_data; - struct _sas_device *sas_device; - u64 sas_address; - unsigned long flags; - Mpi2EventDataSasDeviceStatusChange_t *event_data = - (Mpi2EventDataSasDeviceStatusChange_t *) - fw_event->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 - - /* In MPI Revision K (0xC), the internal device reset complete was - * implemented, so avoid setting tm_busy flag for older firmware. - */ - if ((ioc->facts.HeaderVersion >> 8) < 0xC) - return; - - if (event_data->ReasonCode != - MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET && - event_data->ReasonCode != - MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET) - return; - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_address = le64_to_cpu(event_data->SASAddress); - sas_device = __mpt2sas_get_sdev_by_addr(ioc, - sas_address); - - if (!sas_device || !sas_device->starget) - goto out; - - target_priv_data = sas_device->starget->hostdata; - if (!target_priv_data) - goto out; - - if (event_data->ReasonCode == - MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET) - target_priv_data->tm_busy = 1; - else - target_priv_data->tm_busy = 0; - -out: - if (sas_device) - sas_device_put(sas_device); - - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - -} - -#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_INFO_FMT "enclosure status change: (%s)\n" - "\thandle(0x%04x), enclosure logical id(0x%016llx)" - " number slots(%d)\n", ioc->name, reason_str, - le16_to_cpu(event_data->EnclosureHandle), - (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 - * @fw_event: The fw_event_work object - * Context: user. - * - * Return nothing. - */ -static void -_scsih_sas_enclosure_dev_status_change_event(struct MPT2SAS_ADAPTER *ioc, - struct fw_event_work *fw_event) -{ -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING - if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) - _scsih_sas_enclosure_dev_status_change_event_debug(ioc, - (Mpi2EventDataSasEnclDevStatusChange_t *) - fw_event->event_data); -#endif -} - -/** - * _scsih_sas_broadcast_primitive_event - handle broadcast events - * @ioc: per adapter object - * @fw_event: The fw_event_work object - * Context: user. - * - * Return nothing. - */ -static void -_scsih_sas_broadcast_primitive_event(struct MPT2SAS_ADAPTER *ioc, - struct fw_event_work *fw_event) -{ - struct scsi_cmnd *scmd; - struct scsi_device *sdev; - u16 smid, handle; - u32 lun; - struct MPT2SAS_DEVICE *sas_device_priv_data; - u32 termination_count; - u32 query_count; - Mpi2SCSITaskManagementReply_t *mpi_reply; - Mpi2EventDataSasBroadcastPrimitive_t *event_data = - (Mpi2EventDataSasBroadcastPrimitive_t *) - fw_event->event_data; - u16 ioc_status; - unsigned long flags; - int r; - u8 max_retries = 0; - u8 task_abort_retries; - - mutex_lock(&ioc->tm_cmds.mutex); - pr_info(MPT2SAS_FMT - "%s: enter: phy number(%d), width(%d)\n", - ioc->name, __func__, event_data->PhyNum, - event_data->PortWidth); - - _scsih_block_io_all_device(ioc); - - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - mpi_reply = ioc->tm_cmds.reply; -broadcast_aen_retry: - - /* sanity checks for retrying this loop */ - if (max_retries++ == 5) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: giving up\n", - ioc->name, __func__)); - goto out; - } else if (max_retries > 1) - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: %d retry\n", - ioc->name, __func__, max_retries - 1)); - - termination_count = 0; - query_count = 0; - for (smid = 1; smid <= ioc->scsiio_depth; smid++) { - if (ioc->shost_recovery) - goto out; - scmd = _scsih_scsi_lookup_get(ioc, smid); - if (!scmd) - continue; - sdev = scmd->device; - sas_device_priv_data = sdev->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++; - - if (ioc->shost_recovery) - goto out; - - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - r = mpt2sas_scsih_issue_tm(ioc, handle, 0, 0, lun, - MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK, smid, 30, - TM_MUTEX_OFF); - if (r == FAILED) { - sdev_printk(KERN_WARNING, sdev, - "mpt2sas_scsih_issue_tm: FAILED when sending " - "QUERY_TASK: scmd(%p)\n", scmd); - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - goto broadcast_aen_retry; - } - ioc_status = le16_to_cpu(mpi_reply->IOCStatus) - & MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - sdev_printk(KERN_WARNING, sdev, "query task: FAILED " - "with IOCSTATUS(0x%04x), scmd(%p)\n", ioc_status, - scmd); - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - goto broadcast_aen_retry; - } - - /* see if IO is still owned by IOC and target */ - if (mpi_reply->ResponseCode == - MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED || - mpi_reply->ResponseCode == - MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC) { - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - continue; - } - task_abort_retries = 0; - tm_retry: - if (task_abort_retries++ == 60) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT - "%s: ABORT_TASK: giving up\n", ioc->name, - __func__)); - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - goto broadcast_aen_retry; - } - - if (ioc->shost_recovery) - goto out_no_lock; - - r = mpt2sas_scsih_issue_tm(ioc, handle, sdev->channel, sdev->id, - sdev->lun, MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30, - TM_MUTEX_OFF); - if (r == FAILED) { - sdev_printk(KERN_WARNING, sdev, - "mpt2sas_scsih_issue_tm: ABORT_TASK: FAILED : " - "scmd(%p)\n", scmd); - goto tm_retry; - } - - if (task_abort_retries > 1) - sdev_printk(KERN_WARNING, sdev, - "mpt2sas_scsih_issue_tm: ABORT_TASK: RETRIES (%d):" - " scmd(%p)\n", - task_abort_retries - 1, scmd); - - termination_count += le32_to_cpu(mpi_reply->TerminationCount); - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - } - - if (ioc->broadcast_aen_pending) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: loop back due to" - " pending AEN\n", ioc->name, __func__)); - ioc->broadcast_aen_pending = 0; - goto broadcast_aen_retry; - } - - out: - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - out_no_lock: - - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT - "%s - exit, query_count = %d termination_count = %d\n", - ioc->name, __func__, query_count, termination_count)); - - ioc->broadcast_aen_busy = 0; - if (!ioc->shost_recovery) - _scsih_ublock_io_all_device(ioc); - mutex_unlock(&ioc->tm_cmds.mutex); -} - -/** - * _scsih_sas_discovery_event - handle discovery events - * @ioc: per adapter object - * @fw_event: The fw_event_work object - * Context: user. - * - * Return nothing. - */ -static void -_scsih_sas_discovery_event(struct MPT2SAS_ADAPTER *ioc, - struct fw_event_work *fw_event) -{ - Mpi2EventDataSasDiscovery_t *event_data = - (Mpi2EventDataSasDiscovery_t *) - fw_event->event_data; - -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING - if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) { - printk(MPT2SAS_INFO_FMT "discovery event: (%s)", ioc->name, - (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED) ? - "start" : "stop"); - if (event_data->DiscoveryStatus) - printk("discovery_status(0x%08x)", - le32_to_cpu(event_data->DiscoveryStatus)); - printk("\n"); - } -#endif - - if (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED && - !ioc->sas_hba.num_phys) { - if (disable_discovery > 0 && ioc->shost_recovery) { - /* Wait for the reset to complete */ - while (ioc->shost_recovery) - ssleep(1); - } - _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_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; - - 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_discovery_to_complete) { - rc = scsi_add_device(ioc->shost, RAID_CHANNEL, - raid_device->id, 0); - if (rc) - _scsih_raid_device_remove(ioc, raid_device); - } else { - spin_lock_irqsave(&ioc->raid_device_lock, flags); - _scsih_determine_boot_device(ioc, raid_device, 1); - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); - } -} - -/** - * _scsih_sas_volume_delete - delete volume - * @ioc: per adapter object - * @handle: volume device handle - * Context: user. - * - * Return nothing. - */ -static void -_scsih_sas_volume_delete(struct MPT2SAS_ADAPTER *ioc, u16 handle) -{ - struct _raid_device *raid_device; - unsigned long flags; - struct MPT2SAS_TARGET *sas_target_priv_data; - struct scsi_target *starget = NULL; - - spin_lock_irqsave(&ioc->raid_device_lock, flags); - raid_device = _scsih_raid_device_find_by_handle(ioc, handle); - if (raid_device) { - if (raid_device->starget) { - starget = raid_device->starget; - sas_target_priv_data = starget->hostdata; - sas_target_priv_data->deleted = 1; - } - printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), wwid" - "(0x%016llx)\n", ioc->name, raid_device->handle, - (unsigned long long) raid_device->wwid); - list_del(&raid_device->list); - kfree(raid_device); - } - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); - if (starget) - scsi_remove_target(&starget->dev); -} - -/** - * _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; - struct scsi_target *starget = NULL; - struct MPT2SAS_TARGET *sas_target_priv_data; - unsigned long flags; - u16 handle = le16_to_cpu(element->PhysDiskDevHandle); - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = __mpt2sas_get_sdev_by_handle(ioc, handle); - if (sas_device) { - sas_device->volume_handle = 0; - sas_device->volume_wwid = 0; - clear_bit(handle, ioc->pd_handles); - if (sas_device->starget && sas_device->starget->hostdata) { - starget = sas_device->starget; - sas_target_priv_data = starget->hostdata; - sas_target_priv_data->flags &= - ~MPT_TARGET_FLAGS_RAID_COMPONENT; - } - } - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - if (!sas_device) - return; - - /* exposing raid component */ - if (starget) - starget_for_each_device(starget, NULL, _scsih_reprobe_lun); - - sas_device_put(sas_device); -} - -/** - * _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; - struct scsi_target *starget = NULL; - struct MPT2SAS_TARGET *sas_target_priv_data; - unsigned long flags; - u16 handle = le16_to_cpu(element->PhysDiskDevHandle); - u16 volume_handle = 0; - u64 volume_wwid = 0; - - mpt2sas_config_get_volume_handle(ioc, handle, &volume_handle); - if (volume_handle) - mpt2sas_config_get_volume_wwid(ioc, volume_handle, - &volume_wwid); - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = __mpt2sas_get_sdev_by_handle(ioc, handle); - if (sas_device) { - set_bit(handle, ioc->pd_handles); - if (sas_device->starget && sas_device->starget->hostdata) { - starget = sas_device->starget; - sas_target_priv_data = starget->hostdata; - sas_target_priv_data->flags |= - MPT_TARGET_FLAGS_RAID_COMPONENT; - sas_device->volume_handle = volume_handle; - sas_device->volume_wwid = volume_wwid; - } - } - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - if (!sas_device) - return; - - /* hiding raid component */ - if (starget) - starget_for_each_device(starget, (void *)1, _scsih_reprobe_lun); - - sas_device_put(sas_device); -} - -/** - * _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) -{ - u16 handle = le16_to_cpu(element->PhysDiskDevHandle); - - _scsih_device_remove_by_handle(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; - u16 handle = le16_to_cpu(element->PhysDiskDevHandle); - Mpi2ConfigReply_t mpi_reply; - Mpi2SasDevicePage0_t sas_device_pg0; - u32 ioc_status; - u64 sas_address; - u16 parent_handle; - - set_bit(handle, ioc->pd_handles); - - sas_device = mpt2sas_get_sdev_by_handle(ioc, handle); - if (sas_device) { - sas_device_put(sas_device); - return; - } - - 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; - } - - 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; - } - - parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle); - if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address)) - mpt2sas_transport_update_links(ioc, sas_address, handle, - sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5); - - _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_INFO_FMT "raid config change: (%s), elements(%d)\n", - ioc->name, (le32_to_cpu(event_data->Flags) & - MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ? - "foreign" : "native", event_data->NumElements); - 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_INFO "\t(%s:%s), vol handle(0x%04x), " - "pd handle(0x%04x), pd num(0x%02x)\n", element_str, - reason_str, le16_to_cpu(element->VolDevHandle), - le16_to_cpu(element->PhysDiskDevHandle), - element->PhysDiskNum); - } -} -#endif - -/** - * _scsih_sas_ir_config_change_event - handle ir configuration change events - * @ioc: per adapter object - * @fw_event: The fw_event_work object - * Context: user. - * - * Return nothing. - */ -static void -_scsih_sas_ir_config_change_event(struct MPT2SAS_ADAPTER *ioc, - struct fw_event_work *fw_event) -{ - Mpi2EventIrConfigElement_t *element; - int i; - u8 foreign_config; - Mpi2EventDataIrConfigChangeList_t *event_data = - (Mpi2EventDataIrConfigChangeList_t *) - fw_event->event_data; - -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING - if ((ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) - && !ioc->hide_ir_msg) - _scsih_sas_ir_config_change_event_debug(ioc, event_data); - -#endif - - if (ioc->shost_recovery) - return; - - foreign_config = (le32_to_cpu(event_data->Flags) & - MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ? 1 : 0; - - 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: - if (!foreign_config) - _scsih_sas_volume_add(ioc, element); - break; - case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED: - case MPI2_EVENT_IR_CHANGE_RC_REMOVED: - if (!foreign_config) - _scsih_sas_volume_delete(ioc, - le16_to_cpu(element->VolDevHandle)); - break; - case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED: - if (!ioc->is_warpdrive) - _scsih_sas_pd_hide(ioc, element); - break; - case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED: - if (!ioc->is_warpdrive) - _scsih_sas_pd_expose(ioc, element); - break; - case MPI2_EVENT_IR_CHANGE_RC_HIDE: - if (!ioc->is_warpdrive) - _scsih_sas_pd_add(ioc, element); - break; - case MPI2_EVENT_IR_CHANGE_RC_UNHIDE: - if (!ioc->is_warpdrive) - _scsih_sas_pd_delete(ioc, element); - break; - } - } -} - -/** - * _scsih_sas_ir_volume_event - IR volume event - * @ioc: per adapter object - * @fw_event: The fw_event_work object - * Context: user. - * - * Return nothing. - */ -static void -_scsih_sas_ir_volume_event(struct MPT2SAS_ADAPTER *ioc, - struct fw_event_work *fw_event) -{ - u64 wwid; - unsigned long flags; - struct _raid_device *raid_device; - u16 handle; - u32 state; - int rc; - Mpi2EventDataIrVolume_t *event_data = - (Mpi2EventDataIrVolume_t *) - fw_event->event_data; - - if (ioc->shost_recovery) - return; - - 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); - if (!ioc->hide_ir_msg) - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle(0x%04x), " - "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle, - le32_to_cpu(event_data->PreviousValue), state)); - - switch (state) { - case MPI2_RAID_VOL_STATE_MISSING: - case MPI2_RAID_VOL_STATE_FAILED: - _scsih_sas_volume_delete(ioc, handle); - break; - - case MPI2_RAID_VOL_STATE_ONLINE: - case MPI2_RAID_VOL_STATE_DEGRADED: - case MPI2_RAID_VOL_STATE_OPTIMAL: - - spin_lock_irqsave(&ioc->raid_device_lock, flags); - raid_device = _scsih_raid_device_find_by_handle(ioc, handle); - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); - - if (raid_device) - break; - - 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 - * @fw_event: The fw_event_work object - * Context: user. - * - * Return nothing. - */ -static void -_scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc, - struct fw_event_work *fw_event) -{ - u16 handle, parent_handle; - u32 state; - struct _sas_device *sas_device; - Mpi2ConfigReply_t mpi_reply; - Mpi2SasDevicePage0_t sas_device_pg0; - u32 ioc_status; - Mpi2EventDataIrPhysicalDisk_t *event_data = - (Mpi2EventDataIrPhysicalDisk_t *) - fw_event->event_data; - u64 sas_address; - - if (ioc->shost_recovery) - return; - - 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); - - if (!ioc->hide_ir_msg) - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle(0x%04x), " - "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle, - le32_to_cpu(event_data->PreviousValue), state)); - - switch (state) { - case MPI2_RAID_PD_STATE_ONLINE: - case MPI2_RAID_PD_STATE_DEGRADED: - case MPI2_RAID_PD_STATE_REBUILDING: - case MPI2_RAID_PD_STATE_OPTIMAL: - case MPI2_RAID_PD_STATE_HOT_SPARE: - - if (!ioc->is_warpdrive) - set_bit(handle, ioc->pd_handles); - - sas_device = mpt2sas_get_sdev_by_handle(ioc, handle); - if (sas_device) { - sas_device_put(sas_device); - return; - } - - 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; - } - - 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; - } - - parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle); - if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address)) - mpt2sas_transport_update_links(ioc, sas_address, handle, - sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5); - - _scsih_add_device(ioc, handle, 0, 1); - - break; - - case MPI2_RAID_PD_STATE_OFFLINE: - case MPI2_RAID_PD_STATE_NOT_CONFIGURED: - case MPI2_RAID_PD_STATE_NOT_COMPATIBLE: - 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; - case MPI2_EVENT_IR_RAIDOP_BACKGROUND_INIT: - reason_str = "background init"; - break; - case MPI2_EVENT_IR_RAIDOP_MAKE_DATA_CONSISTENT: - reason_str = "make data consistent"; - break; - } - - if (!reason_str) - return; - - 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 - * @fw_event: The fw_event_work object - * Context: user. - * - * Return nothing. - */ -static void -_scsih_sas_ir_operation_status_event(struct MPT2SAS_ADAPTER *ioc, - struct fw_event_work *fw_event) -{ - Mpi2EventDataIrOperationStatus_t *event_data = - (Mpi2EventDataIrOperationStatus_t *) - fw_event->event_data; - static struct _raid_device *raid_device; - unsigned long flags; - u16 handle; - -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING - if ((ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) - && !ioc->hide_ir_msg) - _scsih_sas_ir_operation_status_event_debug(ioc, - event_data); -#endif - - /* code added for raid transport support */ - if (event_data->RAIDOperation == MPI2_EVENT_IR_RAIDOP_RESYNC) { - - spin_lock_irqsave(&ioc->raid_device_lock, flags); - handle = le16_to_cpu(event_data->VolDevHandle); - raid_device = _scsih_raid_device_find_by_handle(ioc, handle); - if (raid_device) - raid_device->percent_complete = - event_data->PercentComplete; - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); - } -} - -/** - * _scsih_prep_device_scan - initialize parameters prior to device scan - * @ioc: per adapter object - * - * Set the deleted flag prior to device scan. If the device is found during - * the scan, then we clear the deleted flag. - */ -static void -_scsih_prep_device_scan(struct MPT2SAS_ADAPTER *ioc) -{ - 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 && sas_device_priv_data->sas_target) - sas_device_priv_data->sas_target->deleted = 1; - } -} - -/** - * _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 = NULL; - 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->responding = 1; - starget = sas_device->starget; - if (starget && starget->hostdata) { - sas_target_priv_data = starget->hostdata; - sas_target_priv_data->tm_busy = 0; - sas_target_priv_data->deleted = 0; - } else - sas_target_priv_data = NULL; - if (starget) - starget_printk(KERN_INFO, 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; - if (sas_target_priv_data) - 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 "search for end-devices: start\n", ioc->name); - - if (list_empty(&ioc->sas_device_list)) - goto out; - - 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_SUCCESS) - 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); - } -out: - printk(MPT2SAS_INFO_FMT "search for end-devices: complete\n", - ioc->name); -} - -/** - * _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) { - starget = raid_device->starget; - if (starget && starget->hostdata) { - sas_target_priv_data = starget->hostdata; - sas_target_priv_data->deleted = 0; - } else - sas_target_priv_data = NULL; - raid_device->responding = 1; - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); - starget_printk(KERN_INFO, raid_device->starget, - "handle(0x%04x), wwid(0x%016llx)\n", handle, - (unsigned long long)raid_device->wwid); - /* - * WARPDRIVE: The handles of the PDs might have changed - * across the host reset so re-initialize the - * required data for Direct IO - */ - _scsih_init_warpdrive_properties(ioc, raid_device); - spin_lock_irqsave(&ioc->raid_device_lock, flags); - if (raid_device->handle == handle) { - spin_unlock_irqrestore(&ioc->raid_device_lock, - flags); - return; - } - printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n", - raid_device->handle); - raid_device->handle = handle; - if (sas_target_priv_data) - sas_target_priv_data->handle = handle; - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); - return; - } - } - - 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; - Mpi2RaidVolPage0_t volume_pg0; - Mpi2RaidPhysDiskPage0_t pd_pg0; - Mpi2ConfigReply_t mpi_reply; - u16 ioc_status; - u16 handle; - u8 phys_disk_num; - - if (!ioc->ir_firmware) - return; - - printk(MPT2SAS_INFO_FMT "search for raid volumes: start\n", - ioc->name); - - if (list_empty(&ioc->raid_device_list)) - goto out; - - 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_SUCCESS) - break; - handle = le16_to_cpu(volume_pg1.DevHandle); - - if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, - &volume_pg0, MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle, - sizeof(Mpi2RaidVolPage0_t))) - continue; - - if (volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_OPTIMAL || - volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_ONLINE || - volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_DEGRADED) - _scsih_mark_responding_raid_device(ioc, - le64_to_cpu(volume_pg1.WWID), handle); - } - - /* refresh the pd_handles */ - if (!ioc->is_warpdrive) { - phys_disk_num = 0xFF; - memset(ioc->pd_handles, 0, ioc->pd_handles_sz); - while (!(mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply, - &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_GET_NEXT_PHYSDISKNUM, - phys_disk_num))) { - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) - break; - phys_disk_num = pd_pg0.PhysDiskNum; - handle = le16_to_cpu(pd_pg0.DevHandle); - set_bit(handle, ioc->pd_handles); - } - } -out: - printk(MPT2SAS_INFO_FMT "search for responding raid volumes: " - "complete\n", ioc->name); -} - -/** - * _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; - int i; - - 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) - continue; - sas_expander->responding = 1; - if (sas_expander->handle == handle) - goto out; - printk(KERN_INFO "\texpander(0x%016llx): handle changed" - " from(0x%04x) to (0x%04x)!!!\n", - (unsigned long long)sas_expander->sas_address, - sas_expander->handle, handle); - sas_expander->handle = handle; - for (i = 0 ; i < sas_expander->num_phys ; i++) - sas_expander->phy[i].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; - u64 sas_address; - u16 handle; - - printk(MPT2SAS_INFO_FMT "search for expanders: start\n", ioc->name); - - if (list_empty(&ioc->sas_expander_list)) - goto out; - - 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_SUCCESS) - 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); - } - - out: - printk(MPT2SAS_INFO_FMT "search for expanders: complete\n", ioc->name); -} - -/** - * _scsih_remove_unresponding_sas_devices - removing unresponding devices - * @ioc: per adapter object - * - * Return nothing. - */ -static void -_scsih_remove_unresponding_sas_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; - struct list_head tmp_list; - unsigned long flags; - LIST_HEAD(head); - - printk(MPT2SAS_INFO_FMT "removing unresponding devices: start\n", - ioc->name); - - /* removing unresponding end devices */ - printk(MPT2SAS_INFO_FMT "removing unresponding devices: end-devices\n", - ioc->name); - - /* - * Iterate, pulling off devices marked as non-responding. We become the - * owner for the reference the list had on any object we prune. - */ - spin_lock_irqsave(&ioc->sas_device_lock, flags); - list_for_each_entry_safe(sas_device, sas_device_next, - &ioc->sas_device_list, list) { - if (!sas_device->responding) - list_move_tail(&sas_device->list, &head); - else - sas_device->responding = 0; - } - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - - /* - * Now, uninitialize and remove the unresponding devices we pruned. - */ - list_for_each_entry_safe(sas_device, sas_device_next, &head, list) { - _scsih_remove_device(ioc, sas_device); - list_del_init(&sas_device->list); - sas_device_put(sas_device); - } - - /* removing unresponding volumes */ - if (ioc->ir_firmware) { - printk(MPT2SAS_INFO_FMT "removing unresponding devices: " - "volumes\n", ioc->name); - list_for_each_entry_safe(raid_device, raid_device_next, - &ioc->raid_device_list, list) { - if (!raid_device->responding) - _scsih_sas_volume_delete(ioc, - raid_device->handle); - else - raid_device->responding = 0; - } - } - /* removing unresponding expanders */ - printk(MPT2SAS_INFO_FMT "removing unresponding devices: expanders\n", - ioc->name); - spin_lock_irqsave(&ioc->sas_node_lock, flags); - INIT_LIST_HEAD(&tmp_list); - list_for_each_entry_safe(sas_expander, sas_expander_next, - &ioc->sas_expander_list, list) { - if (!sas_expander->responding) - list_move_tail(&sas_expander->list, &tmp_list); - else - sas_expander->responding = 0; - } - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - list_for_each_entry_safe(sas_expander, sas_expander_next, &tmp_list, - list) { - list_del(&sas_expander->list); - _scsih_expander_node_remove(ioc, sas_expander); - } - printk(MPT2SAS_INFO_FMT "removing unresponding devices: complete\n", - ioc->name); - /* unblock devices */ - _scsih_ublock_io_all_device(ioc); -} - -static void -_scsih_refresh_expander_links(struct MPT2SAS_ADAPTER *ioc, - struct _sas_node *sas_expander, u16 handle) -{ - Mpi2ExpanderPage1_t expander_pg1; - Mpi2ConfigReply_t mpi_reply; - int i; - - 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__); - return; - } - - mpt2sas_transport_update_links(ioc, sas_expander->sas_address, - le16_to_cpu(expander_pg1.AttachedDevHandle), i, - expander_pg1.NegotiatedLinkRate >> 4); - } -} - -/** - * _scsih_scan_for_devices_after_reset - scan for devices after host reset - * @ioc: per adapter object - * - * Return nothing. - */ -static void -_scsih_scan_for_devices_after_reset(struct MPT2SAS_ADAPTER *ioc) -{ - Mpi2ExpanderPage0_t expander_pg0; - Mpi2SasDevicePage0_t sas_device_pg0; - Mpi2RaidVolPage1_t volume_pg1; - Mpi2RaidVolPage0_t volume_pg0; - Mpi2RaidPhysDiskPage0_t pd_pg0; - Mpi2EventIrConfigElement_t element; - Mpi2ConfigReply_t mpi_reply; - u8 phys_disk_num; - u16 ioc_status; - u16 handle, parent_handle; - u64 sas_address; - struct _sas_device *sas_device; - struct _sas_node *expander_device; - static struct _raid_device *raid_device; - u8 retry_count; - unsigned long flags; - - printk(MPT2SAS_INFO_FMT "scan devices: start\n", ioc->name); - - _scsih_sas_host_refresh(ioc); - - printk(MPT2SAS_INFO_FMT "\tscan devices: expanders start\n", - ioc->name); - /* expanders */ - 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_SUCCESS) { - printk(MPT2SAS_INFO_FMT "\tbreak from expander scan: " - "ioc_status(0x%04x), loginfo(0x%08x)\n", - ioc->name, ioc_status, - le32_to_cpu(mpi_reply.IOCLogInfo)); - break; - } - handle = le16_to_cpu(expander_pg0.DevHandle); - spin_lock_irqsave(&ioc->sas_node_lock, flags); - expander_device = mpt2sas_scsih_expander_find_by_sas_address( - ioc, le64_to_cpu(expander_pg0.SASAddress)); - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - if (expander_device) - _scsih_refresh_expander_links(ioc, expander_device, - handle); - else { - printk(MPT2SAS_INFO_FMT "\tBEFORE adding expander: " - "handle (0x%04x), sas_addr(0x%016llx)\n", - ioc->name, handle, (unsigned long long) - le64_to_cpu(expander_pg0.SASAddress)); - _scsih_expander_add(ioc, handle); - printk(MPT2SAS_INFO_FMT "\tAFTER adding expander: " - "handle (0x%04x), sas_addr(0x%016llx)\n", - ioc->name, handle, (unsigned long long) - le64_to_cpu(expander_pg0.SASAddress)); - } - } - - printk(MPT2SAS_INFO_FMT "\tscan devices: expanders complete\n", - ioc->name); - - if (!ioc->ir_firmware) - goto skip_to_sas; - - printk(MPT2SAS_INFO_FMT "\tscan devices phys disk start\n", ioc->name); - /* phys disk */ - phys_disk_num = 0xFF; - while (!(mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply, - &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_GET_NEXT_PHYSDISKNUM, - phys_disk_num))) { - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - printk(MPT2SAS_INFO_FMT "\tbreak from phys disk scan:" - "ioc_status(0x%04x), loginfo(0x%08x)\n", - ioc->name, ioc_status, - le32_to_cpu(mpi_reply.IOCLogInfo)); - break; - } - phys_disk_num = pd_pg0.PhysDiskNum; - handle = le16_to_cpu(pd_pg0.DevHandle); - sas_device = mpt2sas_get_sdev_by_handle(ioc, handle); - if (sas_device) { - sas_device_put(sas_device); - continue; - } - if (mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, - &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, - handle) != 0) - continue; - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - printk(MPT2SAS_INFO_FMT "\tbreak from phys disk scan " - "ioc_status(0x%04x), loginfo(0x%08x)\n", - ioc->name, ioc_status, - le32_to_cpu(mpi_reply.IOCLogInfo)); - break; - } - parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle); - if (!_scsih_get_sas_address(ioc, parent_handle, - &sas_address)) { - printk(MPT2SAS_INFO_FMT "\tBEFORE adding phys disk: " - " handle (0x%04x), sas_addr(0x%016llx)\n", - ioc->name, handle, (unsigned long long) - le64_to_cpu(sas_device_pg0.SASAddress)); - mpt2sas_transport_update_links(ioc, sas_address, - handle, sas_device_pg0.PhyNum, - MPI2_SAS_NEG_LINK_RATE_1_5); - set_bit(handle, ioc->pd_handles); - retry_count = 0; - /* This will retry adding the end device. - * _scsih_add_device() will decide on retries and - * return "1" when it should be retried - */ - while (_scsih_add_device(ioc, handle, retry_count++, - 1)) { - ssleep(1); - } - printk(MPT2SAS_INFO_FMT "\tAFTER adding phys disk: " - " handle (0x%04x), sas_addr(0x%016llx)\n", - ioc->name, handle, (unsigned long long) - le64_to_cpu(sas_device_pg0.SASAddress)); - } - } - - printk(MPT2SAS_INFO_FMT "\tscan devices: phys disk complete\n", - ioc->name); - - printk(MPT2SAS_INFO_FMT "\tscan devices: volumes start\n", ioc->name); - /* volumes */ - 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_SUCCESS) { - printk(MPT2SAS_INFO_FMT "\tbreak from volume scan: " - "ioc_status(0x%04x), loginfo(0x%08x)\n", - ioc->name, ioc_status, - le32_to_cpu(mpi_reply.IOCLogInfo)); - break; - } - handle = le16_to_cpu(volume_pg1.DevHandle); - spin_lock_irqsave(&ioc->raid_device_lock, flags); - raid_device = _scsih_raid_device_find_by_wwid(ioc, - le64_to_cpu(volume_pg1.WWID)); - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); - if (raid_device) - continue; - if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, - &volume_pg0, MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle, - sizeof(Mpi2RaidVolPage0_t))) - continue; - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - printk(MPT2SAS_INFO_FMT "\tbreak from volume scan: " - "ioc_status(0x%04x), loginfo(0x%08x)\n", - ioc->name, ioc_status, - le32_to_cpu(mpi_reply.IOCLogInfo)); - break; - } - if (volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_OPTIMAL || - volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_ONLINE || - volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_DEGRADED) { - memset(&element, 0, sizeof(Mpi2EventIrConfigElement_t)); - element.ReasonCode = MPI2_EVENT_IR_CHANGE_RC_ADDED; - element.VolDevHandle = volume_pg1.DevHandle; - printk(MPT2SAS_INFO_FMT "\tBEFORE adding volume: " - " handle (0x%04x)\n", ioc->name, - volume_pg1.DevHandle); - _scsih_sas_volume_add(ioc, &element); - printk(MPT2SAS_INFO_FMT "\tAFTER adding volume: " - " handle (0x%04x)\n", ioc->name, - volume_pg1.DevHandle); - } - } - - printk(MPT2SAS_INFO_FMT "\tscan devices: volumes complete\n", - ioc->name); - - skip_to_sas: - - printk(MPT2SAS_INFO_FMT "\tscan devices: end devices start\n", - ioc->name); - /* sas devices */ - 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_SUCCESS) { - printk(MPT2SAS_INFO_FMT "\tbreak from end device scan:" - " ioc_status(0x%04x), loginfo(0x%08x)\n", - ioc->name, ioc_status, - le32_to_cpu(mpi_reply.IOCLogInfo)); - break; - } - handle = le16_to_cpu(sas_device_pg0.DevHandle); - if (!(_scsih_is_end_device( - le32_to_cpu(sas_device_pg0.DeviceInfo)))) - continue; - sas_device = mpt2sas_get_sdev_by_addr(ioc, - le64_to_cpu(sas_device_pg0.SASAddress)); - if (sas_device) { - sas_device_put(sas_device); - continue; - } - parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle); - if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address)) { - printk(MPT2SAS_INFO_FMT "\tBEFORE adding end device: " - "handle (0x%04x), sas_addr(0x%016llx)\n", - ioc->name, handle, (unsigned long long) - le64_to_cpu(sas_device_pg0.SASAddress)); - mpt2sas_transport_update_links(ioc, sas_address, handle, - sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5); - retry_count = 0; - /* This will retry adding the end device. - * _scsih_add_device() will decide on retries and - * return "1" when it should be retried - */ - while (_scsih_add_device(ioc, handle, retry_count++, - 0)) { - ssleep(1); - } - printk(MPT2SAS_INFO_FMT "\tAFTER adding end device: " - "handle (0x%04x), sas_addr(0x%016llx)\n", - ioc->name, handle, (unsigned long long) - le64_to_cpu(sas_device_pg0.SASAddress)); - } - } - - printk(MPT2SAS_INFO_FMT "\tscan devices: end devices complete\n", - ioc->name); - - printk(MPT2SAS_INFO_FMT "scan devices: complete\n", ioc->name); -} - - -/** - * 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_INFO_FMT "%s: " - "MPT2_IOC_PRE_RESET\n", ioc->name, __func__)); - break; - case MPT2_IOC_AFTER_RESET: - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " - "MPT2_IOC_AFTER_RESET\n", ioc->name, __func__)); - if (ioc->scsih_cmds.status & MPT2_CMD_PENDING) { - ioc->scsih_cmds.status |= MPT2_CMD_RESET; - mpt2sas_base_free_smid(ioc, ioc->scsih_cmds.smid); - complete(&ioc->scsih_cmds.done); - } - 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_cleanup_queue(ioc); - _scsih_flush_running_cmds(ioc); - break; - case MPT2_IOC_DONE_RESET: - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " - "MPT2_IOC_DONE_RESET\n", ioc->name, __func__)); - _scsih_sas_host_refresh(ioc); - _scsih_prep_device_scan(ioc); - _scsih_search_responding_sas_devices(ioc); - _scsih_search_responding_raid_devices(ioc); - _scsih_search_responding_expanders(ioc); - if ((!ioc->is_driver_loading) && !(disable_discovery > 0 && - !ioc->sas_hba.num_phys)) { - _scsih_prep_device_scan(ioc); - _scsih_search_responding_sas_devices(ioc); - _scsih_search_responding_raid_devices(ioc); - _scsih_search_responding_expanders(ioc); - _scsih_error_recovery_delete_devices(ioc); - } - break; - } -} - -/** - * _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, delayed_work.work); - struct MPT2SAS_ADAPTER *ioc = fw_event->ioc; - - _scsih_fw_event_del_from_list(ioc, fw_event); - - /* the queue is being flushed so ignore this event */ - if (ioc->remove_host || ioc->pci_error_recovery) { - fw_event_work_put(fw_event); - return; - } - - switch (fw_event->event) { - case MPT2SAS_REMOVE_UNRESPONDING_DEVICES: - while (scsi_host_in_recovery(ioc->shost) || - ioc->shost_recovery) { - /* - * If we're unloading, bail. Otherwise, this can become - * an infinite loop. - */ - if (ioc->remove_host) - goto out; - - ssleep(1); - } - _scsih_remove_unresponding_sas_devices(ioc); - _scsih_scan_for_devices_after_reset(ioc); - break; - case MPT2SAS_PORT_ENABLE_COMPLETE: - ioc->start_scan = 0; - - if (missing_delay[0] != -1 && missing_delay[1] != -1) - mpt2sas_base_update_missing_delay(ioc, missing_delay[0], - missing_delay[1]); - - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "port enable: complete " - "from worker thread\n", ioc->name)); - break; - case MPT2SAS_TURN_ON_PFA_LED: - _scsih_turn_on_pfa_led(ioc, fw_event->device_handle); - break; - case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST: - _scsih_sas_topology_change_event(ioc, fw_event); - break; - case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE: - _scsih_sas_device_status_change_event(ioc, - fw_event); - break; - case MPI2_EVENT_SAS_DISCOVERY: - _scsih_sas_discovery_event(ioc, - fw_event); - break; - case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE: - _scsih_sas_broadcast_primitive_event(ioc, - fw_event); - break; - case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE: - _scsih_sas_enclosure_dev_status_change_event(ioc, - fw_event); - break; - case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST: - _scsih_sas_ir_config_change_event(ioc, fw_event); - break; - case MPI2_EVENT_IR_VOLUME: - _scsih_sas_ir_volume_event(ioc, fw_event); - break; - case MPI2_EVENT_IR_PHYSICAL_DISK: - _scsih_sas_ir_physical_disk_event(ioc, fw_event); - break; - case MPI2_EVENT_IR_OPERATION_STATUS: - _scsih_sas_ir_operation_status_event(ioc, fw_event); - break; - } -out: - fw_event_work_put(fw_event); -} - -/** - * mpt2sas_scsih_event_callback - firmware event handler (called at ISR time) - * @ioc: per adapter object - * @msix_index: MSIX table index supplied by the OS - * @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. - * - * Returns void. - */ -void -mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, - u32 reply) -{ - struct fw_event_work *fw_event; - Mpi2EventNotificationReply_t *mpi_reply; - u16 event; - u16 sz; - - /* events turned off due to host reset or driver unloading */ - if (ioc->remove_host || ioc->pci_error_recovery) - return; - - mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); - - if (unlikely(!mpi_reply)) { - printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return; - } - - 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) - return; - - if (ioc->broadcast_aen_busy) { - ioc->broadcast_aen_pending++; - return; - } else - 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_IR_CONFIGURATION_CHANGE_LIST: - _scsih_check_ir_config_unhide_events(ioc, - (Mpi2EventDataIrConfigChangeList_t *) - mpi_reply->EventData); - break; - case MPI2_EVENT_IR_VOLUME: - _scsih_check_volume_delete_events(ioc, - (Mpi2EventDataIrVolume_t *) - mpi_reply->EventData); - break; - case MPI2_EVENT_LOG_ENTRY_ADDED: - { - Mpi2EventDataLogEntryAdded_t *log_entry; - __le32 *log_code; - - if (!ioc->is_warpdrive) - break; - - log_entry = (Mpi2EventDataLogEntryAdded_t *) - mpi_reply->EventData; - log_code = (__le32 *)log_entry->LogData; - - if (le16_to_cpu(log_entry->LogEntryQualifier) - != MPT2_WARPDRIVE_LOGENTRY) - break; - - switch (le32_to_cpu(*log_code)) { - case MPT2_WARPDRIVE_LC_SSDT: - printk(MPT2SAS_WARN_FMT "WarpDrive Warning: " - "IO Throttling has occurred in the WarpDrive " - "subsystem. Check WarpDrive documentation for " - "additional details.\n", ioc->name); - break; - case MPT2_WARPDRIVE_LC_SSDLW: - printk(MPT2SAS_WARN_FMT "WarpDrive Warning: " - "Program/Erase Cycles for the WarpDrive subsystem " - "in degraded range. Check WarpDrive documentation " - "for additional details.\n", ioc->name); - break; - case MPT2_WARPDRIVE_LC_SSDLF: - printk(MPT2SAS_ERR_FMT "WarpDrive Fatal Error: " - "There are no Program/Erase Cycles for the " - "WarpDrive subsystem. The storage device will be " - "in read-only mode. Check WarpDrive documentation " - "for additional details.\n", ioc->name); - break; - case MPT2_WARPDRIVE_LC_BRMF: - printk(MPT2SAS_ERR_FMT "WarpDrive Fatal Error: " - "The Backup Rail Monitor has failed on the " - "WarpDrive subsystem. Check WarpDrive " - "documentation for additional details.\n", - ioc->name); - break; - } - - 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_PHYSICAL_DISK: - break; - - case MPI2_EVENT_TEMP_THRESHOLD: - _scsih_temp_threshold_events(ioc, - (Mpi2EventDataTemperature_t *) - mpi_reply->EventData); - break; - - default: /* ignore the rest */ - return; - } - - sz = le16_to_cpu(mpi_reply->EventDataLength) * 4; - fw_event = alloc_fw_event_work(sz); - if (!fw_event) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return; - } - - memcpy(fw_event->event_data, mpi_reply->EventData, sz); - fw_event->ioc = ioc; - fw_event->VF_ID = mpi_reply->VF_ID; - fw_event->VP_ID = mpi_reply->VP_ID; - fw_event->event = event; - _scsih_fw_event_add(ioc, fw_event); - fw_event_work_put(fw_event); - return; -} - -/* 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, - .scan_finished = _scsih_scan_finished, - .scan_start = _scsih_scan_start, - .change_queue_depth = _scsih_change_queue_depth, - .eh_abort_handler = _scsih_abort, - .eh_device_reset_handler = _scsih_dev_reset, - .eh_target_reset_handler = _scsih_target_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 = 32767, - .cmd_per_lun = 7, - .use_clustering = ENABLE_CLUSTERING, - .shost_attrs = mpt2sas_host_attrs, - .sdev_attrs = mpt2sas_dev_attrs, - .track_queue_depth = 1, -}; - -/** - * _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, *next; - - /* remove sibling ports attached to this expander */ - list_for_each_entry_safe(mpt2sas_port, next, - &sas_expander->sas_port_list, port_list) { - if (ioc->shost_recovery) - return; - if (mpt2sas_port->remote_identify.device_type == - SAS_END_DEVICE) - mpt2sas_device_remove_by_sas_address(ioc, - mpt2sas_port->remote_identify.sas_address); - else if (mpt2sas_port->remote_identify.device_type == - SAS_EDGE_EXPANDER_DEVICE || - mpt2sas_port->remote_identify.device_type == - SAS_FANOUT_EXPANDER_DEVICE) - mpt2sas_expander_remove(ioc, - mpt2sas_port->remote_identify.sas_address); - } - - mpt2sas_transport_port_remove(ioc, sas_expander->sas_address, - sas_expander->sas_address_parent); - - 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); - - kfree(sas_expander->phy); - kfree(sas_expander); -} - -/** - * _scsih_ir_shutdown - IR shutdown notification - * @ioc: per adapter object - * - * Sending RAID Action to alert the Integrated RAID subsystem of the IOC that - * the host system is shutting down. - * - * Return nothing. - */ -static void -_scsih_ir_shutdown(struct MPT2SAS_ADAPTER *ioc) -{ - Mpi2RaidActionRequest_t *mpi_request; - Mpi2RaidActionReply_t *mpi_reply; - u16 smid; - - /* is IR firmware build loaded ? */ - if (!ioc->ir_firmware) - return; - - mutex_lock(&ioc->scsih_cmds.mutex); - - if (ioc->scsih_cmds.status != MPT2_CMD_NOT_USED) { - printk(MPT2SAS_ERR_FMT "%s: scsih_cmd in use\n", - ioc->name, __func__); - goto out; - } - ioc->scsih_cmds.status = MPT2_CMD_PENDING; - - smid = mpt2sas_base_get_smid(ioc, ioc->scsih_cb_idx); - if (!smid) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); - ioc->scsih_cmds.status = MPT2_CMD_NOT_USED; - goto out; - } - - mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); - ioc->scsih_cmds.smid = smid; - memset(mpi_request, 0, sizeof(Mpi2RaidActionRequest_t)); - - mpi_request->Function = MPI2_FUNCTION_RAID_ACTION; - mpi_request->Action = MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED; - - if (!ioc->hide_ir_msg) - printk(MPT2SAS_INFO_FMT "IR shutdown (sending)\n", ioc->name); - init_completion(&ioc->scsih_cmds.done); - mpt2sas_base_put_smid_default(ioc, smid); - wait_for_completion_timeout(&ioc->scsih_cmds.done, 10*HZ); - - if (!(ioc->scsih_cmds.status & MPT2_CMD_COMPLETE)) { - printk(MPT2SAS_ERR_FMT "%s: timeout\n", - ioc->name, __func__); - goto out; - } - - if (ioc->scsih_cmds.status & MPT2_CMD_REPLY_VALID) { - mpi_reply = ioc->scsih_cmds.reply; - - if (!ioc->hide_ir_msg) - printk(MPT2SAS_INFO_FMT "IR shutdown (complete): " - "ioc_status(0x%04x), loginfo(0x%08x)\n", - ioc->name, le16_to_cpu(mpi_reply->IOCStatus), - le32_to_cpu(mpi_reply->IOCLogInfo)); - } - - out: - ioc->scsih_cmds.status = MPT2_CMD_NOT_USED; - mutex_unlock(&ioc->scsih_cmds.mutex); -} - -/** - * _scsih_shutdown - routine call during system shutdown - * @pdev: PCI device struct - * - * Return nothing. - */ -static void -_scsih_shutdown(struct pci_dev *pdev) -{ - struct Scsi_Host *shost = pci_get_drvdata(pdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - struct workqueue_struct *wq; - unsigned long flags; - - ioc->remove_host = 1; - _scsih_fw_event_cleanup_queue(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); - - _scsih_ir_shutdown(ioc); - mpt2sas_base_detach(ioc); -} - -/** - * _scsih_remove - detach and remove add host - * @pdev: PCI device struct - * - * Routine called when unloading the driver. - * Return nothing. - */ -static void -_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, *next_port; - struct _raid_device *raid_device, *next; - struct MPT2SAS_TARGET *sas_target_priv_data; - struct workqueue_struct *wq; - unsigned long flags; - - ioc->remove_host = 1; - _scsih_fw_event_cleanup_queue(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); - - /* release all the volumes */ - _scsih_ir_shutdown(ioc); - list_for_each_entry_safe(raid_device, next, &ioc->raid_device_list, - list) { - 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); - } - printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), wwid" - "(0x%016llx)\n", ioc->name, raid_device->handle, - (unsigned long long) raid_device->wwid); - _scsih_raid_device_remove(ioc, raid_device); - } - - /* free ports attached to the sas_host */ - list_for_each_entry_safe(mpt2sas_port, next_port, - &ioc->sas_hba.sas_port_list, port_list) { - if (mpt2sas_port->remote_identify.device_type == - SAS_END_DEVICE) - mpt2sas_device_remove_by_sas_address(ioc, - mpt2sas_port->remote_identify.sas_address); - else if (mpt2sas_port->remote_identify.device_type == - SAS_EDGE_EXPANDER_DEVICE || - mpt2sas_port->remote_identify.device_type == - SAS_FANOUT_EXPANDER_DEVICE) - mpt2sas_expander_remove(ioc, - mpt2sas_port->remote_identify.sas_address); - } - - /* 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); - scsi_remove_host(shost); - mpt2sas_base_detach(ioc); - spin_lock(&gioc_lock); - list_del(&ioc->list); - spin_unlock(&gioc_lock); - 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; - u64 sas_address_parent; - u64 sas_address; - unsigned long flags; - int rc; - - /* no Bios, return immediately */ - if (!ioc->bios_pg3.BiosVersion) - return; - - device = NULL; - is_raid = 0; - 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 { - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = device; - handle = sas_device->handle; - sas_address_parent = sas_device->sas_address_parent; - sas_address = sas_device->sas_address; - list_move_tail(&sas_device->list, &ioc->sas_device_list); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - - if (ioc->hide_drives) - return; - if (!mpt2sas_transport_port_add(ioc, sas_device->handle, - sas_device->sas_address_parent)) { - _scsih_sas_device_remove(ioc, sas_device); - } else if (!sas_device->starget) { - if (!ioc->is_driver_loading) { - mpt2sas_transport_port_remove(ioc, - sas_address, - sas_address_parent); - _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); - } -} - -static struct _sas_device *get_next_sas_device(struct MPT2SAS_ADAPTER *ioc) -{ - struct _sas_device *sas_device = NULL; - unsigned long flags; - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - if (!list_empty(&ioc->sas_device_init_list)) { - sas_device = list_first_entry(&ioc->sas_device_init_list, - struct _sas_device, list); - sas_device_get(sas_device); - } - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - - return sas_device; -} - -static void sas_device_make_active(struct MPT2SAS_ADAPTER *ioc, - struct _sas_device *sas_device) -{ - unsigned long flags; - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - - /* - * Since we dropped the lock during the call to port_add(), we need to - * be careful here that somebody else didn't move or delete this item - * while we were busy with other things. - * - * If it was on the list, we need a put() for the reference the list - * had. Either way, we need a get() for the destination list. - */ - if (!list_empty(&sas_device->list)) { - list_del_init(&sas_device->list); - sas_device_put(sas_device); - } - - sas_device_get(sas_device); - list_add_tail(&sas_device->list, &ioc->sas_device_list); - - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -} - -/** - * _scsih_probe_sas - reporting sas devices 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; - - if (ioc->hide_drives) - return; - - while ((sas_device = get_next_sas_device(ioc))) { - if (!mpt2sas_transport_port_add(ioc, sas_device->handle, - sas_device->sas_address_parent)) { - _scsih_sas_device_remove(ioc, sas_device); - sas_device_put(sas_device); - continue; - } else if (!sas_device->starget) { - if (!ioc->is_driver_loading) { - mpt2sas_transport_port_remove(ioc, - sas_device->sas_address, - sas_device->sas_address_parent); - _scsih_sas_device_remove(ioc, sas_device); - sas_device_put(sas_device); - continue; - } - } - - sas_device_make_active(ioc, sas_device); - sas_device_put(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; - - 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) { - volume_mapping_flags = - le16_to_cpu(ioc->ioc_pg8.IRVolumeMappingFlags) & - MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE; - if (volume_mapping_flags == - MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING) { - _scsih_probe_raid(ioc); - _scsih_probe_sas(ioc); - } else { - _scsih_probe_sas(ioc); - _scsih_probe_raid(ioc); - } - } else - _scsih_probe_sas(ioc); -} - - -/** - * _scsih_scan_start - scsi lld callback for .scan_start - * @shost: SCSI host pointer - * - * The shost has the ability to discover targets on its own instead - * of scanning the entire bus. In our implemention, we will kick off - * firmware discovery. - */ -static void -_scsih_scan_start(struct Scsi_Host *shost) -{ - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - int rc; - - if (diag_buffer_enable != -1 && diag_buffer_enable != 0) - mpt2sas_enable_diag_buffer(ioc, diag_buffer_enable); - - if (disable_discovery > 0) - return; - - ioc->start_scan = 1; - rc = mpt2sas_port_enable(ioc); - - if (rc != 0) - printk(MPT2SAS_INFO_FMT "port enable: FAILED\n", ioc->name); -} - -/** - * _scsih_scan_finished - scsi lld callback for .scan_finished - * @shost: SCSI host pointer - * @time: elapsed time of the scan in jiffies - * - * This function will be called periodically until it returns 1 with the - * scsi_host and the elapsed time of the scan in jiffies. In our implemention, - * we wait for firmware discovery to complete, then return 1. - */ -static int -_scsih_scan_finished(struct Scsi_Host *shost, unsigned long time) -{ - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - - if (disable_discovery > 0) { - ioc->is_driver_loading = 0; - ioc->wait_for_discovery_to_complete = 0; - return 1; - } - - if (time >= (300 * HZ)) { - ioc->base_cmds.status = MPT2_CMD_NOT_USED; - printk(MPT2SAS_INFO_FMT "port enable: FAILED with timeout " - "(timeout=300s)\n", ioc->name); - ioc->is_driver_loading = 0; - return 1; - } - - if (ioc->start_scan) - return 0; - - if (ioc->start_scan_failed) { - printk(MPT2SAS_INFO_FMT "port enable: FAILED with " - "(ioc_status=0x%08x)\n", ioc->name, ioc->start_scan_failed); - ioc->is_driver_loading = 0; - ioc->wait_for_discovery_to_complete = 0; - ioc->remove_host = 1; - return 1; - } - - printk(MPT2SAS_INFO_FMT "port enable: SUCCESS\n", ioc->name); - ioc->base_cmds.status = MPT2_CMD_NOT_USED; - - if (ioc->wait_for_discovery_to_complete) { - ioc->wait_for_discovery_to_complete = 0; - _scsih_probe_devices(ioc); - } - mpt2sas_base_start_watchdog(ioc); - ioc->is_driver_loading = 0; - return 1; -} - - -/** - * _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; - int rv; - - 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); - spin_lock(&gioc_lock); - list_add_tail(&ioc->list, &mpt2sas_ioc_list); - spin_unlock(&gioc_lock); - ioc->shost = shost; - ioc->id = mpt_ids++; - sprintf(ioc->name, "%s%d", MPT2SAS_DRIVER_NAME, ioc->id); - ioc->pdev = pdev; - if (id->device == MPI2_MFGPAGE_DEVID_SSS6200) { - ioc->is_warpdrive = 1; - ioc->hide_ir_msg = 1; - } else - ioc->mfg_pg10_hide_flag = MFG_PAGE10_EXPOSE_ALL_DISKS; - 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->port_enable_cb_idx = port_enable_cb_idx; - ioc->transport_cb_idx = transport_cb_idx; - ioc->scsih_cb_idx = scsih_cb_idx; - ioc->config_cb_idx = config_cb_idx; - ioc->tm_tr_cb_idx = tm_tr_cb_idx; - ioc->tm_tr_volume_cb_idx = tm_tr_volume_cb_idx; - ioc->tm_sas_control_cb_idx = tm_sas_control_cb_idx; - ioc->logging_level = logging_level; - ioc->schedule_dead_ioc_flush_running_cmds = &_scsih_flush_running_cmds; - /* misc semaphores and spin locks */ - mutex_init(&ioc->reset_in_progress_mutex); - /* initializing pci_access_mutex lock */ - mutex_init(&ioc->pci_access_mutex); - 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_LIST_HEAD(&ioc->delayed_tr_list); - INIT_LIST_HEAD(&ioc->delayed_tr_volume_list); - INIT_LIST_HEAD(&ioc->reply_queue_list); - - /* init shost parameters */ - shost->max_cmd_len = 32; - shost->max_lun = max_lun; - shost->transportt = mpt2sas_transport_template; - shost->unique_id = ioc->id; - - if (max_sectors != 0xFFFF) { - if (max_sectors < 64) { - shost->max_sectors = 64; - printk(MPT2SAS_WARN_FMT "Invalid value %d passed " - "for max_sectors, range is 64 to 32767. Assigning " - "value of 64.\n", ioc->name, max_sectors); - } else if (max_sectors > 32767) { - shost->max_sectors = 32767; - printk(MPT2SAS_WARN_FMT "Invalid value %d passed " - "for max_sectors, range is 64 to 8192. Assigning " - "default value of 32767.\n", ioc->name, - max_sectors); - } else { - shost->max_sectors = max_sectors & 0xFFFE; - printk(MPT2SAS_INFO_FMT "The max_sectors value is " - "set to %d\n", ioc->name, shost->max_sectors); - } - } - - /* register EEDP capabilities with SCSI layer */ - if (prot_mask) - scsi_host_set_prot(shost, prot_mask); - else - scsi_host_set_prot(shost, SHOST_DIF_TYPE1_PROTECTION - | SHOST_DIF_TYPE2_PROTECTION - | SHOST_DIF_TYPE3_PROTECTION); - - scsi_host_set_guard(shost, SHOST_DIX_GUARD_CRC); - - /* 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__); - rv = -ENODEV; - goto out_thread_fail; - } - - ioc->is_driver_loading = 1; - if ((mpt2sas_base_attach(ioc))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - rv = -ENODEV; - goto out_attach_fail; - } - - if (ioc->is_warpdrive) { - if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_EXPOSE_ALL_DISKS) - ioc->hide_drives = 0; - else if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_HIDE_ALL_DISKS) - ioc->hide_drives = 1; - else { - if (_scsih_get_num_volumes(ioc)) - ioc->hide_drives = 1; - else - ioc->hide_drives = 0; - } - } else - ioc->hide_drives = 0; - - rv = scsi_add_host(shost, &pdev->dev); - if (rv) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - goto out_add_shost_fail; - } - - scsi_scan_host(shost); - - return 0; - - out_add_shost_fail: - mpt2sas_base_detach(ioc); - out_attach_fail: - destroy_workqueue(ioc->firmware_event_thread); - out_thread_fail: - spin_lock(&gioc_lock); - list_del(&ioc->list); - spin_unlock(&gioc_lock); - scsi_host_put(shost); - return rv; -} - -#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); - pci_power_t device_state; - - mpt2sas_base_stop_watchdog(ioc); - scsi_block_requests(shost); - _scsih_ir_shutdown(ioc); - 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_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); - pci_power_t 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); - mpt2sas_base_start_watchdog(ioc); - return 0; -} -#endif /* CONFIG_PM */ - -/** - * _scsih_pci_error_detected - Called when a PCI error is detected. - * @pdev: PCI device struct - * @state: PCI channel state - * - * Description: Called when a PCI error is detected. - * - * Return value: - * PCI_ERS_RESULT_NEED_RESET or PCI_ERS_RESULT_DISCONNECT - */ -static pci_ers_result_t -_scsih_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) -{ - struct Scsi_Host *shost = pci_get_drvdata(pdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - - printk(MPT2SAS_INFO_FMT "PCI error: detected callback, state(%d)!!\n", - ioc->name, state); - - switch (state) { - case pci_channel_io_normal: - return PCI_ERS_RESULT_CAN_RECOVER; - case pci_channel_io_frozen: - /* Fatal error, prepare for slot reset */ - ioc->pci_error_recovery = 1; - scsi_block_requests(ioc->shost); - mpt2sas_base_stop_watchdog(ioc); - mpt2sas_base_free_resources(ioc); - return PCI_ERS_RESULT_NEED_RESET; - case pci_channel_io_perm_failure: - /* Permanent error, prepare for device removal */ - ioc->pci_error_recovery = 1; - mpt2sas_base_stop_watchdog(ioc); - _scsih_flush_running_cmds(ioc); - return PCI_ERS_RESULT_DISCONNECT; - } - return PCI_ERS_RESULT_NEED_RESET; -} - -/** - * _scsih_pci_slot_reset - Called when PCI slot has been reset. - * @pdev: PCI device struct - * - * Description: This routine is called by the pci error recovery - * code after the PCI slot has been reset, just before we - * should resume normal operations. - */ -static pci_ers_result_t -_scsih_pci_slot_reset(struct pci_dev *pdev) -{ - struct Scsi_Host *shost = pci_get_drvdata(pdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - int rc; - - printk(MPT2SAS_INFO_FMT "PCI error: slot reset callback!!\n", - ioc->name); - - ioc->pci_error_recovery = 0; - ioc->pdev = pdev; - pci_restore_state(pdev); - rc = mpt2sas_base_map_resources(ioc); - if (rc) - return PCI_ERS_RESULT_DISCONNECT; - - - rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, - FORCE_BIG_HAMMER); - - printk(MPT2SAS_WARN_FMT "hard reset: %s\n", ioc->name, - (rc == 0) ? "success" : "failed"); - - if (!rc) - return PCI_ERS_RESULT_RECOVERED; - else - return PCI_ERS_RESULT_DISCONNECT; -} - -/** - * _scsih_pci_resume() - resume normal ops after PCI reset - * @pdev: pointer to PCI device - * - * Called when the error recovery driver tells us that its - * OK to resume normal operation. Use completion to allow - * halted scsi ops to resume. - */ -static void -_scsih_pci_resume(struct pci_dev *pdev) -{ - struct Scsi_Host *shost = pci_get_drvdata(pdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - - printk(MPT2SAS_INFO_FMT "PCI error: resume callback!!\n", ioc->name); - - pci_cleanup_aer_uncorrect_error_status(pdev); - mpt2sas_base_start_watchdog(ioc); - scsi_unblock_requests(ioc->shost); -} - -/** - * _scsih_pci_mmio_enabled - Enable MMIO and dump debug registers - * @pdev: pointer to PCI device - */ -static pci_ers_result_t -_scsih_pci_mmio_enabled(struct pci_dev *pdev) -{ - struct Scsi_Host *shost = pci_get_drvdata(pdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - - printk(MPT2SAS_INFO_FMT "PCI error: mmio enabled callback!!\n", - ioc->name); - - /* TODO - dump whatever for debugging purposes */ - - /* Request a slot reset. */ - return PCI_ERS_RESULT_NEED_RESET; -} - -static const struct pci_error_handlers _scsih_err_handler = { - .error_detected = _scsih_pci_error_detected, - .mmio_enabled = _scsih_pci_mmio_enabled, - .slot_reset = _scsih_pci_slot_reset, - .resume = _scsih_pci_resume, -}; - -static struct pci_driver scsih_driver = { - .name = MPT2SAS_DRIVER_NAME, - .id_table = scsih_pci_table, - .probe = _scsih_probe, - .remove = _scsih_remove, - .shutdown = _scsih_shutdown, - .err_handler = &_scsih_err_handler, -#ifdef CONFIG_PM - .suspend = _scsih_suspend, - .resume = _scsih_resume, -#endif -}; - -/* raid transport support */ -static struct raid_function_template mpt2sas_raid_functions = { - .cookie = &scsih_driver_template, - .is_raid = _scsih_is_raid, - .get_resync = _scsih_get_resync, - .get_state = _scsih_get_state, -}; - -/** - * _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; - /* raid transport support */ - mpt2sas_raid_template = raid_class_attach(&mpt2sas_raid_functions); - if (!mpt2sas_raid_template) { - sas_release_transport(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 management 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); - port_enable_cb_idx = mpt2sas_base_register_callback_handler( - mpt2sas_port_enable_done); - - /* transport internal commands callback handler */ - transport_cb_idx = mpt2sas_base_register_callback_handler( - mpt2sas_transport_done); - - /* scsih internal commands callback handler */ - scsih_cb_idx = mpt2sas_base_register_callback_handler(_scsih_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); - - tm_tr_cb_idx = mpt2sas_base_register_callback_handler( - _scsih_tm_tr_complete); - - tm_tr_volume_cb_idx = mpt2sas_base_register_callback_handler( - _scsih_tm_volume_tr_complete); - - tm_sas_control_cb_idx = mpt2sas_base_register_callback_handler( - _scsih_sas_control_complete); - - mpt2sas_ctl_init(); - - error = pci_register_driver(&scsih_driver); - if (error) { - /* raid transport support */ - raid_class_release(mpt2sas_raid_template); - 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); - - mpt2sas_ctl_exit(); - - 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(port_enable_cb_idx); - mpt2sas_base_release_callback_handler(transport_cb_idx); - mpt2sas_base_release_callback_handler(scsih_cb_idx); - mpt2sas_base_release_callback_handler(config_cb_idx); - mpt2sas_base_release_callback_handler(ctl_cb_idx); - - mpt2sas_base_release_callback_handler(tm_tr_cb_idx); - mpt2sas_base_release_callback_handler(tm_tr_volume_cb_idx); - mpt2sas_base_release_callback_handler(tm_sas_control_cb_idx); - - /* raid transport support */ - raid_class_release(mpt2sas_raid_template); - sas_release_transport(mpt2sas_transport_template); - -} - -module_init(_scsih_init); -module_exit(_scsih_exit); diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c deleted file mode 100644 index af868009395d..000000000000 --- a/drivers/scsi/mpt2sas/mpt2sas_transport.c +++ /dev/null @@ -1,2173 +0,0 @@ -/* - * SAS Transport Layer for MPT (Message Passing Technology) based controllers - * - * This code is based on drivers/scsi/mpt2sas/mpt2_transport.c - * Copyright (C) 2007-2014 LSI Corporation - * Copyright (C) 20013-2014 Avago Technologies - * (mailto: MPT-FusionLinux.pdl@avagotech.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 <linux/slab.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_sas_address - sas node search - * @ioc: per adapter object - * @sas_address: sas address of expander or sas host - * 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_sas_address(struct MPT2SAS_ADAPTER *ioc, - u64 sas_address) -{ - if (ioc->sas_hba.sas_address == sas_address) - return &ioc->sas_hba; - else - return mpt2sas_scsih_expander_find_by_sas_address(ioc, - sas_address); -} - -/** - * _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 (ioc->shost_recovery || ioc->pci_error_recovery) { - printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n", - __func__, ioc->name); - return -EFAULT; - } - - 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 -ENXIO; - } - - 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 -EIO; - } - - memset(identify, 0, sizeof(struct sas_identify)); - device_info = le32_to_cpu(sas_device_pg0.DeviceInfo); - - /* sas_address */ - identify->sas_address = le64_to_cpu(sas_device_pg0.SASAddress); - - /* phy number of the parent device this device is linked to */ - identify->phy_identifier = sas_device_pg0.PhyNum; - - /* 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 - * @msix_index: MSIX table index supplied by the OS - * @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 1 meaning mf should be freed from _base_interrupt - * 0 means the mf is freed from this function. - */ -u8 -mpt2sas_transport_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, - 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 1; - if (ioc->transport_cmds.smid != smid) - return 1; - 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); - return 1; -} - -/* 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; - 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; - void *data_out = NULL; - dma_addr_t data_out_dma; - u32 sz; - u16 wait_state_count; - - if (ioc->shost_recovery || ioc->pci_error_recovery) { - printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n", - __func__, ioc->name); - return -EFAULT; - } - - mutex_lock(&ioc->transport_cmds.mutex); - - if (ioc->transport_cmds.status != MPT2_CMD_NOT_USED) { - printk(MPT2SAS_ERR_FMT "%s: transport_cmds in use\n", - ioc->name, __func__); - rc = -EAGAIN; - goto out; - } - ioc->transport_cmds.status = MPT2_CMD_PENDING; - - wait_state_count = 0; - ioc_state = mpt2sas_base_get_iocstate(ioc, 1); - while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { - if (wait_state_count++ == 10) { - printk(MPT2SAS_ERR_FMT - "%s: failed due to ioc not operational\n", - ioc->name, __func__); - rc = -EFAULT; - goto out; - } - ssleep(1); - ioc_state = mpt2sas_base_get_iocstate(ioc, 1); - printk(MPT2SAS_INFO_FMT "%s: waiting for " - "operational state(count=%d)\n", ioc->name, - __func__, wait_state_count); - } - if (wait_state_count) - printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n", - ioc->name, __func__); - - smid = mpt2sas_base_get_smid(ioc, ioc->transport_cb_idx); - if (!smid) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); - rc = -EAGAIN; - goto out; - } - - 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; - mpi_request->VF_ID = 0; /* TODO */ - mpi_request->VP_ID = 0; - mpi_request->SASAddress = cpu_to_le64(sas_address); - mpi_request->RequestDataLength = - cpu_to_le16(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_INFO_FMT "report_manufacture - " - "send to sas_addr(0x%016llx)\n", ioc->name, - (unsigned long long)sas_address)); - init_completion(&ioc->transport_cmds.done); - mpt2sas_base_put_smid_default(ioc, smid); - timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done, - 10*HZ); - - if (!(ioc->transport_cmds.status & MPT2_CMD_COMPLETE)) { - printk(MPT2SAS_ERR_FMT "%s: timeout\n", - ioc->name, __func__); - _debug_dump_mf(mpi_request, - sizeof(Mpi2SmpPassthroughRequest_t)/4); - if (!(ioc->transport_cmds.status & MPT2_CMD_RESET)) - issue_reset = 1; - goto issue_host_reset; - } - - dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "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_INFO_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 & 1; - if (edev->level) { - 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_INFO_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; -} - -/** - * _transport_delete_port - helper function to removing a port - * @ioc: per adapter object - * @mpt2sas_port: mpt2sas per port object - * - * Returns nothing. - */ -static void -_transport_delete_port(struct MPT2SAS_ADAPTER *ioc, - struct _sas_port *mpt2sas_port) -{ - u64 sas_address = mpt2sas_port->remote_identify.sas_address; - enum sas_device_type device_type = - mpt2sas_port->remote_identify.device_type; - - dev_printk(KERN_INFO, &mpt2sas_port->port->dev, - "remove: sas_addr(0x%016llx)\n", - (unsigned long long) sas_address); - - ioc->logging_level |= MPT_DEBUG_TRANSPORT; - if (device_type == SAS_END_DEVICE) - mpt2sas_device_remove_by_sas_address(ioc, sas_address); - else if (device_type == SAS_EDGE_EXPANDER_DEVICE || - device_type == SAS_FANOUT_EXPANDER_DEVICE) - mpt2sas_expander_remove(ioc, sas_address); - ioc->logging_level &= ~MPT_DEBUG_TRANSPORT; -} - -/** - * _transport_delete_phy - helper function to removing single phy from port - * @ioc: per adapter object - * @mpt2sas_port: mpt2sas per port object - * @mpt2sas_phy: mpt2sas per phy object - * - * Returns nothing. - */ -static void -_transport_delete_phy(struct MPT2SAS_ADAPTER *ioc, - struct _sas_port *mpt2sas_port, struct _sas_phy *mpt2sas_phy) -{ - u64 sas_address = mpt2sas_port->remote_identify.sas_address; - - dev_printk(KERN_INFO, &mpt2sas_phy->phy->dev, - "remove: sas_addr(0x%016llx), phy(%d)\n", - (unsigned long long) sas_address, mpt2sas_phy->phy_id); - - list_del(&mpt2sas_phy->port_siblings); - mpt2sas_port->num_phys--; - sas_port_delete_phy(mpt2sas_port->port, mpt2sas_phy->phy); - mpt2sas_phy->phy_belongs_to_port = 0; -} - -/** - * _transport_add_phy - helper function to adding single phy to port - * @ioc: per adapter object - * @mpt2sas_port: mpt2sas per port object - * @mpt2sas_phy: mpt2sas per phy object - * - * Returns nothing. - */ -static void -_transport_add_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_port *mpt2sas_port, - struct _sas_phy *mpt2sas_phy) -{ - u64 sas_address = mpt2sas_port->remote_identify.sas_address; - - dev_printk(KERN_INFO, &mpt2sas_phy->phy->dev, - "add: sas_addr(0x%016llx), phy(%d)\n", (unsigned long long) - sas_address, mpt2sas_phy->phy_id); - - list_add_tail(&mpt2sas_phy->port_siblings, &mpt2sas_port->phy_list); - mpt2sas_port->num_phys++; - sas_port_add_phy(mpt2sas_port->port, mpt2sas_phy->phy); - mpt2sas_phy->phy_belongs_to_port = 1; -} - -/** - * _transport_add_phy_to_an_existing_port - adding new phy to existing port - * @ioc: per adapter object - * @sas_node: sas node object (either expander or sas host) - * @mpt2sas_phy: mpt2sas per phy object - * @sas_address: sas address of device/expander were phy needs to be added to - * - * Returns nothing. - */ -static void -_transport_add_phy_to_an_existing_port(struct MPT2SAS_ADAPTER *ioc, -struct _sas_node *sas_node, struct _sas_phy *mpt2sas_phy, u64 sas_address) -{ - struct _sas_port *mpt2sas_port; - struct _sas_phy *phy_srch; - - if (mpt2sas_phy->phy_belongs_to_port == 1) - return; - - list_for_each_entry(mpt2sas_port, &sas_node->sas_port_list, - port_list) { - if (mpt2sas_port->remote_identify.sas_address != - sas_address) - continue; - list_for_each_entry(phy_srch, &mpt2sas_port->phy_list, - port_siblings) { - if (phy_srch == mpt2sas_phy) - return; - } - _transport_add_phy(ioc, mpt2sas_port, mpt2sas_phy); - return; - } - -} - -/** - * _transport_del_phy_from_an_existing_port - delete phy from existing port - * @ioc: per adapter object - * @sas_node: sas node object (either expander or sas host) - * @mpt2sas_phy: mpt2sas per phy object - * - * Returns nothing. - */ -static void -_transport_del_phy_from_an_existing_port(struct MPT2SAS_ADAPTER *ioc, - struct _sas_node *sas_node, struct _sas_phy *mpt2sas_phy) -{ - struct _sas_port *mpt2sas_port, *next; - struct _sas_phy *phy_srch; - - if (mpt2sas_phy->phy_belongs_to_port == 0) - return; - - list_for_each_entry_safe(mpt2sas_port, next, &sas_node->sas_port_list, - port_list) { - list_for_each_entry(phy_srch, &mpt2sas_port->phy_list, - port_siblings) { - if (phy_srch != mpt2sas_phy) - continue; - if (mpt2sas_port->num_phys == 1) - _transport_delete_port(ioc, mpt2sas_port); - else - _transport_delete_phy(ioc, mpt2sas_port, - mpt2sas_phy); - return; - } - } -} - -/** - * _transport_sanity_check - sanity check when adding a new port - * @ioc: per adapter object - * @sas_node: sas node object (either expander or sas host) - * @sas_address: sas address of device being added - * - * See the explanation above from _transport_delete_duplicate_port - */ -static void -_transport_sanity_check(struct MPT2SAS_ADAPTER *ioc, struct _sas_node *sas_node, - u64 sas_address) -{ - int i; - - for (i = 0; i < sas_node->num_phys; i++) { - if (sas_node->phy[i].remote_identify.sas_address != sas_address) - continue; - if (sas_node->phy[i].phy_belongs_to_port == 1) - _transport_del_phy_from_an_existing_port(ioc, sas_node, - &sas_node->phy[i]); - } -} - -/** - * mpt2sas_transport_port_add - insert port to the list - * @ioc: per adapter object - * @handle: handle of attached device - * @sas_address: sas address of parent expander or sas host - * 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, - u64 sas_address) -{ - 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; - - 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_sas_address(ioc, sas_address); - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - - if (!sas_node) { - printk(MPT2SAS_ERR_FMT "%s: Could not find " - "parent sas_address(0x%016llx)!\n", ioc->name, - __func__, (unsigned long long)sas_address); - goto out_fail; - } - - 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; - } - - _transport_sanity_check(ioc, sas_node, - mpt2sas_port->remote_identify.sas_address); - - 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_phy->phy_belongs_to_port = 1; - } - - 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 - * @sas_address_parent: sas address of parent expander or sas host - * 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, - u64 sas_address_parent) -{ - 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_sas_address(ioc, - sas_address_parent); - if (!sas_node) { - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - 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) { - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - 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)); - } - - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - 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: sas_addr(0x%016llx), phy(%d)\n", - (unsigned long long) - mpt2sas_port->remote_identify.sas_address, - mpt2sas_phy->phy_id); - mpt2sas_phy->phy_belongs_to_port = 0; - 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_links - refreshing phy link changes - * @ioc: per adapter object - * @sas_address: sas address of parent expander or sas host - * @handle: attached device handle - * @phy_numberv: phy number - * @link_rate: new link rate - * - * Returns nothing. - */ -void -mpt2sas_transport_update_links(struct MPT2SAS_ADAPTER *ioc, - u64 sas_address, u16 handle, u8 phy_number, u8 link_rate) -{ - unsigned long flags; - struct _sas_node *sas_node; - struct _sas_phy *mpt2sas_phy; - - if (ioc->shost_recovery || ioc->pci_error_recovery) - return; - - spin_lock_irqsave(&ioc->sas_node_lock, flags); - sas_node = _transport_sas_node_find_by_sas_address(ioc, sas_address); - if (!sas_node) { - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - return; - } - - mpt2sas_phy = &sas_node->phy[phy_number]; - mpt2sas_phy->attached_handle = handle; - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - if (handle && (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5)) { - _transport_set_identify(ioc, handle, - &mpt2sas_phy->remote_identify); - _transport_add_phy_to_an_existing_port(ioc, sas_node, - mpt2sas_phy, mpt2sas_phy->remote_identify.sas_address); - } 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: parent sas_addr(0x%016llx),\n" - "\tlink_rate(0x%02x), phy(%d)\n" - "\tattached_handle(0x%04x), sas_addr(0x%016llx)\n", - (unsigned long long)sas_address, - link_rate, phy_number, 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); -} - - -/* report phy error log structure */ -struct phy_error_log_request{ - u8 smp_frame_type; /* 0x40 */ - u8 function; /* 0x11 */ - u8 allocated_response_length; - u8 request_length; /* 02 */ - u8 reserved_1[5]; - u8 phy_identifier; - u8 reserved_2[2]; -}; - -/* report phy error log reply structure */ -struct phy_error_log_reply{ - u8 smp_frame_type; /* 0x41 */ - u8 function; /* 0x11 */ - u8 function_result; - u8 response_length; - __be16 expander_change_count; - u8 reserved_1[3]; - u8 phy_identifier; - u8 reserved_2[2]; - __be32 invalid_dword; - __be32 running_disparity_error; - __be32 loss_of_dword_sync; - __be32 phy_reset_problem; -}; - -/** - * _transport_get_expander_phy_error_log - return expander counters - * @ioc: per adapter object - * @phy: The sas phy object - * - * Returns 0 for success, non-zero for failure. - * - */ -static int -_transport_get_expander_phy_error_log(struct MPT2SAS_ADAPTER *ioc, - struct sas_phy *phy) -{ - Mpi2SmpPassthroughRequest_t *mpi_request; - Mpi2SmpPassthroughReply_t *mpi_reply; - struct phy_error_log_request *phy_error_log_request; - struct phy_error_log_reply *phy_error_log_reply; - int rc; - u16 smid; - u32 ioc_state; - unsigned long timeleft; - void *psge; - u32 sgl_flags; - u8 issue_reset = 0; - void *data_out = NULL; - dma_addr_t data_out_dma; - u32 sz; - u16 wait_state_count; - - if (ioc->shost_recovery || ioc->pci_error_recovery) { - printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n", - __func__, ioc->name); - return -EFAULT; - } - - mutex_lock(&ioc->transport_cmds.mutex); - - if (ioc->transport_cmds.status != MPT2_CMD_NOT_USED) { - printk(MPT2SAS_ERR_FMT "%s: transport_cmds in use\n", - ioc->name, __func__); - rc = -EAGAIN; - goto out; - } - ioc->transport_cmds.status = MPT2_CMD_PENDING; - - wait_state_count = 0; - ioc_state = mpt2sas_base_get_iocstate(ioc, 1); - while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { - if (wait_state_count++ == 10) { - printk(MPT2SAS_ERR_FMT - "%s: failed due to ioc not operational\n", - ioc->name, __func__); - rc = -EFAULT; - goto out; - } - ssleep(1); - ioc_state = mpt2sas_base_get_iocstate(ioc, 1); - printk(MPT2SAS_INFO_FMT "%s: waiting for " - "operational state(count=%d)\n", ioc->name, - __func__, wait_state_count); - } - if (wait_state_count) - printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n", - ioc->name, __func__); - - smid = mpt2sas_base_get_smid(ioc, ioc->transport_cb_idx); - if (!smid) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); - rc = -EAGAIN; - goto out; - } - - mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); - ioc->transport_cmds.smid = smid; - - sz = sizeof(struct phy_error_log_request) + - sizeof(struct phy_error_log_reply); - data_out = pci_alloc_consistent(ioc->pdev, sz, &data_out_dma); - if (!data_out) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, - __LINE__, __func__); - rc = -ENOMEM; - mpt2sas_base_free_smid(ioc, smid); - goto out; - } - - rc = -EINVAL; - memset(data_out, 0, sz); - phy_error_log_request = data_out; - phy_error_log_request->smp_frame_type = 0x40; - phy_error_log_request->function = 0x11; - phy_error_log_request->request_length = 2; - phy_error_log_request->allocated_response_length = 0; - phy_error_log_request->phy_identifier = phy->number; - - memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t)); - mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH; - mpi_request->PhysicalPort = 0xFF; - mpi_request->VF_ID = 0; /* TODO */ - mpi_request->VP_ID = 0; - mpi_request->SASAddress = cpu_to_le64(phy->identify.sas_address); - mpi_request->RequestDataLength = - cpu_to_le16(sizeof(struct phy_error_log_request)); - psge = &mpi_request->SGL; - - /* WRITE sgel first */ - sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | - MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC); - sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; - ioc->base_add_sg_single(psge, sgl_flags | - sizeof(struct phy_error_log_request), data_out_dma); - - /* incr sgel */ - psge += ioc->sge_size; - - /* READ sgel last */ - sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | - MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER | - MPI2_SGE_FLAGS_END_OF_LIST); - sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; - ioc->base_add_sg_single(psge, sgl_flags | - sizeof(struct phy_error_log_reply), data_out_dma + - sizeof(struct phy_error_log_request)); - - dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "phy_error_log - " - "send to sas_addr(0x%016llx), phy(%d)\n", ioc->name, - (unsigned long long)phy->identify.sas_address, phy->number)); - init_completion(&ioc->transport_cmds.done); - mpt2sas_base_put_smid_default(ioc, smid); - timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done, - 10*HZ); - - if (!(ioc->transport_cmds.status & MPT2_CMD_COMPLETE)) { - printk(MPT2SAS_ERR_FMT "%s: timeout\n", - ioc->name, __func__); - _debug_dump_mf(mpi_request, - sizeof(Mpi2SmpPassthroughRequest_t)/4); - if (!(ioc->transport_cmds.status & MPT2_CMD_RESET)) - issue_reset = 1; - goto issue_host_reset; - } - - dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "phy_error_log - " - "complete\n", ioc->name)); - - if (ioc->transport_cmds.status & MPT2_CMD_REPLY_VALID) { - - mpi_reply = ioc->transport_cmds.reply; - - dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT - "phy_error_log - reply data transfer size(%d)\n", - ioc->name, le16_to_cpu(mpi_reply->ResponseDataLength))); - - if (le16_to_cpu(mpi_reply->ResponseDataLength) != - sizeof(struct phy_error_log_reply)) - goto out; - - phy_error_log_reply = data_out + - sizeof(struct phy_error_log_request); - - dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT - "phy_error_log - function_result(%d)\n", - ioc->name, phy_error_log_reply->function_result)); - - phy->invalid_dword_count = - be32_to_cpu(phy_error_log_reply->invalid_dword); - phy->running_disparity_error_count = - be32_to_cpu(phy_error_log_reply->running_disparity_error); - phy->loss_of_dword_sync_count = - be32_to_cpu(phy_error_log_reply->loss_of_dword_sync); - phy->phy_reset_problem_count = - be32_to_cpu(phy_error_log_reply->phy_reset_problem); - rc = 0; - } else - dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT - "phy_error_log - no reply\n", ioc->name)); - - issue_host_reset: - if (issue_reset) - mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, - FORCE_BIG_HAMMER); - out: - ioc->transport_cmds.status = MPT2_CMD_NOT_USED; - if (data_out) - pci_free_consistent(ioc->pdev, sz, data_out, data_out_dma); - - mutex_unlock(&ioc->transport_cmds.mutex); - return rc; -} - -/** - * _transport_get_linkerrors - return phy counters for both hba and expanders - * @phy: The sas phy object - * - * 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); - unsigned long flags; - Mpi2ConfigReply_t mpi_reply; - Mpi2SasPhyPage1_t phy_pg1; - - spin_lock_irqsave(&ioc->sas_node_lock, flags); - if (_transport_sas_node_find_by_sas_address(ioc, - phy->identify.sas_address) == NULL) { - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - return -EINVAL; - } - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - - if (phy->identify.sas_address != ioc->sas_hba.sas_address) - return _transport_get_expander_phy_error_log(ioc, phy); - - /* get hba phy error logs */ - if ((mpt2sas_config_get_phy_pg1(ioc, &mpi_reply, &phy_pg1, - phy->number))) { - 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, - phy->number, 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_device *sas_device; - unsigned long flags; - int rc; - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = __mpt2sas_get_sdev_by_addr(ioc, - rphy->identify.sas_address); - if (sas_device) { - *identifier = sas_device->enclosure_logical_id; - rc = 0; - sas_device_put(sas_device); - } else { - *identifier = 0; - rc = -ENXIO; - } - - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - return rc; -} - -/** - * _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; - int rc; - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = __mpt2sas_get_sdev_by_addr(ioc, - rphy->identify.sas_address); - if (sas_device) { - rc = sas_device->slot; - sas_device_put(sas_device); - } else { - rc = -ENXIO; - } - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - return rc; -} - -/* phy control request structure */ -struct phy_control_request{ - u8 smp_frame_type; /* 0x40 */ - u8 function; /* 0x91 */ - u8 allocated_response_length; - u8 request_length; /* 0x09 */ - u16 expander_change_count; - u8 reserved_1[3]; - u8 phy_identifier; - u8 phy_operation; - u8 reserved_2[13]; - u64 attached_device_name; - u8 programmed_min_physical_link_rate; - u8 programmed_max_physical_link_rate; - u8 reserved_3[6]; -}; - -/* phy control reply structure */ -struct phy_control_reply{ - u8 smp_frame_type; /* 0x41 */ - u8 function; /* 0x11 */ - u8 function_result; - u8 response_length; -}; - -#define SMP_PHY_CONTROL_LINK_RESET (0x01) -#define SMP_PHY_CONTROL_HARD_RESET (0x02) -#define SMP_PHY_CONTROL_DISABLE (0x03) - -/** - * _transport_expander_phy_control - expander phy control - * @ioc: per adapter object - * @phy: The sas phy object - * - * Returns 0 for success, non-zero for failure. - * - */ -static int -_transport_expander_phy_control(struct MPT2SAS_ADAPTER *ioc, - struct sas_phy *phy, u8 phy_operation) -{ - Mpi2SmpPassthroughRequest_t *mpi_request; - Mpi2SmpPassthroughReply_t *mpi_reply; - struct phy_control_request *phy_control_request; - struct phy_control_reply *phy_control_reply; - int rc; - u16 smid; - u32 ioc_state; - unsigned long timeleft; - void *psge; - u32 sgl_flags; - u8 issue_reset = 0; - void *data_out = NULL; - dma_addr_t data_out_dma; - u32 sz; - u16 wait_state_count; - - if (ioc->shost_recovery) { - printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n", - __func__, ioc->name); - return -EFAULT; - } - - mutex_lock(&ioc->transport_cmds.mutex); - - if (ioc->transport_cmds.status != MPT2_CMD_NOT_USED) { - printk(MPT2SAS_ERR_FMT "%s: transport_cmds in use\n", - ioc->name, __func__); - rc = -EAGAIN; - goto out; - } - ioc->transport_cmds.status = MPT2_CMD_PENDING; - - wait_state_count = 0; - ioc_state = mpt2sas_base_get_iocstate(ioc, 1); - while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { - if (wait_state_count++ == 10) { - printk(MPT2SAS_ERR_FMT - "%s: failed due to ioc not operational\n", - ioc->name, __func__); - rc = -EFAULT; - goto out; - } - ssleep(1); - ioc_state = mpt2sas_base_get_iocstate(ioc, 1); - printk(MPT2SAS_INFO_FMT "%s: waiting for " - "operational state(count=%d)\n", ioc->name, - __func__, wait_state_count); - } - if (wait_state_count) - printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n", - ioc->name, __func__); - - smid = mpt2sas_base_get_smid(ioc, ioc->transport_cb_idx); - if (!smid) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); - rc = -EAGAIN; - goto out; - } - - mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); - ioc->transport_cmds.smid = smid; - - sz = sizeof(struct phy_control_request) + - sizeof(struct phy_control_reply); - data_out = pci_alloc_consistent(ioc->pdev, sz, &data_out_dma); - if (!data_out) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, - __LINE__, __func__); - rc = -ENOMEM; - mpt2sas_base_free_smid(ioc, smid); - goto out; - } - - rc = -EINVAL; - memset(data_out, 0, sz); - phy_control_request = data_out; - phy_control_request->smp_frame_type = 0x40; - phy_control_request->function = 0x91; - phy_control_request->request_length = 9; - phy_control_request->allocated_response_length = 0; - phy_control_request->phy_identifier = phy->number; - phy_control_request->phy_operation = phy_operation; - phy_control_request->programmed_min_physical_link_rate = - phy->minimum_linkrate << 4; - phy_control_request->programmed_max_physical_link_rate = - phy->maximum_linkrate << 4; - - memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t)); - mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH; - mpi_request->PhysicalPort = 0xFF; - mpi_request->VF_ID = 0; /* TODO */ - mpi_request->VP_ID = 0; - mpi_request->SASAddress = cpu_to_le64(phy->identify.sas_address); - mpi_request->RequestDataLength = - cpu_to_le16(sizeof(struct phy_error_log_request)); - psge = &mpi_request->SGL; - - /* WRITE sgel first */ - sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | - MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC); - sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; - ioc->base_add_sg_single(psge, sgl_flags | - sizeof(struct phy_control_request), data_out_dma); - - /* incr sgel */ - psge += ioc->sge_size; - - /* READ sgel last */ - sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | - MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER | - MPI2_SGE_FLAGS_END_OF_LIST); - sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; - ioc->base_add_sg_single(psge, sgl_flags | - sizeof(struct phy_control_reply), data_out_dma + - sizeof(struct phy_control_request)); - - dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "phy_control - " - "send to sas_addr(0x%016llx), phy(%d), opcode(%d)\n", ioc->name, - (unsigned long long)phy->identify.sas_address, phy->number, - phy_operation)); - - init_completion(&ioc->transport_cmds.done); - mpt2sas_base_put_smid_default(ioc, smid); - timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done, - 10*HZ); - - if (!(ioc->transport_cmds.status & MPT2_CMD_COMPLETE)) { - printk(MPT2SAS_ERR_FMT "%s: timeout\n", - ioc->name, __func__); - _debug_dump_mf(mpi_request, - sizeof(Mpi2SmpPassthroughRequest_t)/4); - if (!(ioc->transport_cmds.status & MPT2_CMD_RESET)) - issue_reset = 1; - goto issue_host_reset; - } - - dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "phy_control - " - "complete\n", ioc->name)); - - if (ioc->transport_cmds.status & MPT2_CMD_REPLY_VALID) { - - mpi_reply = ioc->transport_cmds.reply; - - dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT - "phy_control - reply data transfer size(%d)\n", - ioc->name, le16_to_cpu(mpi_reply->ResponseDataLength))); - - if (le16_to_cpu(mpi_reply->ResponseDataLength) != - sizeof(struct phy_control_reply)) - goto out; - - phy_control_reply = data_out + - sizeof(struct phy_control_request); - - dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT - "phy_control - function_result(%d)\n", - ioc->name, phy_control_reply->function_result)); - - rc = 0; - } else - dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT - "phy_control - no reply\n", ioc->name)); - - issue_host_reset: - if (issue_reset) - mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, - FORCE_BIG_HAMMER); - out: - ioc->transport_cmds.status = MPT2_CMD_NOT_USED; - if (data_out) - pci_free_consistent(ioc->pdev, sz, data_out, data_out_dma); - - mutex_unlock(&ioc->transport_cmds.mutex); - return rc; -} - -/** - * _transport_phy_reset - - * @phy: The sas phy object - * @hard_reset: - * - * 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); - Mpi2SasIoUnitControlReply_t mpi_reply; - Mpi2SasIoUnitControlRequest_t mpi_request; - unsigned long flags; - - spin_lock_irqsave(&ioc->sas_node_lock, flags); - if (_transport_sas_node_find_by_sas_address(ioc, - phy->identify.sas_address) == NULL) { - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - return -EINVAL; - } - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - - /* handle expander phys */ - if (phy->identify.sas_address != ioc->sas_hba.sas_address) - return _transport_expander_phy_control(ioc, phy, - (hard_reset == 1) ? SMP_PHY_CONTROL_HARD_RESET : - SMP_PHY_CONTROL_LINK_RESET); - - /* handle hba phys */ - memset(&mpi_request, 0, sizeof(Mpi2SasIoUnitControlReply_t)); - mpi_request.Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL; - mpi_request.Operation = hard_reset ? - MPI2_SAS_OP_PHY_HARD_RESET : MPI2_SAS_OP_PHY_LINK_RESET; - mpi_request.PhyNum = phy->number; - - 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, - phy->number, le16_to_cpu(mpi_reply.IOCStatus), - le32_to_cpu(mpi_reply.IOCLogInfo)); - - return 0; -} - -/** - * _transport_phy_enable - enable/disable phys - * @phy: The sas phy object - * @enable: enable phy when true - * - * Only support sas_host direct attached phys. - * Returns 0 for success, non-zero for failure. - */ -static int -_transport_phy_enable(struct sas_phy *phy, int enable) -{ - struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy); - Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL; - Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL; - Mpi2ConfigReply_t mpi_reply; - u16 ioc_status; - u16 sz; - int rc = 0; - unsigned long flags; - int i, discovery_active; - - spin_lock_irqsave(&ioc->sas_node_lock, flags); - if (_transport_sas_node_find_by_sas_address(ioc, - phy->identify.sas_address) == NULL) { - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - return -EINVAL; - } - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - - /* handle expander phys */ - if (phy->identify.sas_address != ioc->sas_hba.sas_address) - return _transport_expander_phy_control(ioc, phy, - (enable == 1) ? SMP_PHY_CONTROL_LINK_RESET : - SMP_PHY_CONTROL_DISABLE); - - /* handle hba phys */ - - /* read 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__); - rc = -ENOMEM; - goto out; - } - 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__); - rc = -ENXIO; - 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__); - rc = -EIO; - goto out; - } - - /* unable to enable/disable phys when when discovery is active */ - for (i = 0, discovery_active = 0; i < ioc->sas_hba.num_phys ; i++) { - if (sas_iounit_pg0->PhyData[i].PortFlags & - MPI2_SASIOUNIT0_PORTFLAGS_DISCOVERY_IN_PROGRESS) { - printk(MPT2SAS_ERR_FMT "discovery is active on " - "port = %d, phy = %d: unable to enable/disable " - "phys, try again later!\n", ioc->name, - sas_iounit_pg0->PhyData[i].Port, i); - discovery_active = 1; - } - } - - if (discovery_active) { - rc = -EAGAIN; - goto out; - } - - /* read 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__); - rc = -ENOMEM; - 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__); - rc = -ENXIO; - 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__); - rc = -EIO; - goto out; - } - /* copy Port/PortFlags/PhyFlags from page 0 */ - for (i = 0; i < ioc->sas_hba.num_phys ; i++) { - sas_iounit_pg1->PhyData[i].Port = - sas_iounit_pg0->PhyData[i].Port; - sas_iounit_pg1->PhyData[i].PortFlags = - (sas_iounit_pg0->PhyData[i].PortFlags & - MPI2_SASIOUNIT0_PORTFLAGS_AUTO_PORT_CONFIG); - sas_iounit_pg1->PhyData[i].PhyFlags = - (sas_iounit_pg0->PhyData[i].PhyFlags & - (MPI2_SASIOUNIT0_PHYFLAGS_ZONING_ENABLED + - MPI2_SASIOUNIT0_PHYFLAGS_PHY_DISABLED)); - } - if (enable) - sas_iounit_pg1->PhyData[phy->number].PhyFlags - &= ~MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE; - else - sas_iounit_pg1->PhyData[phy->number].PhyFlags - |= MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE; - - mpt2sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1, sz); - - /* link reset */ - if (enable) - _transport_phy_reset(phy, 0); - - out: - kfree(sas_iounit_pg1); - kfree(sas_iounit_pg0); - return rc; -} - -/** - * _transport_phy_speed - set phy min/max link rates - * @phy: The sas phy object - * @rates: rates defined in sas_phy_linkrates - * - * Only support sas_host direct attached phys. - * Returns 0 for success, non-zero for failure. - */ -static int -_transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates) -{ - struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy); - Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL; - Mpi2SasPhyPage0_t phy_pg0; - Mpi2ConfigReply_t mpi_reply; - u16 ioc_status; - u16 sz; - int i; - int rc = 0; - unsigned long flags; - - spin_lock_irqsave(&ioc->sas_node_lock, flags); - if (_transport_sas_node_find_by_sas_address(ioc, - phy->identify.sas_address) == NULL) { - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - return -EINVAL; - } - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - - if (!rates->minimum_linkrate) - rates->minimum_linkrate = phy->minimum_linkrate; - else if (rates->minimum_linkrate < phy->minimum_linkrate_hw) - rates->minimum_linkrate = phy->minimum_linkrate_hw; - - if (!rates->maximum_linkrate) - rates->maximum_linkrate = phy->maximum_linkrate; - else if (rates->maximum_linkrate > phy->maximum_linkrate_hw) - rates->maximum_linkrate = phy->maximum_linkrate_hw; - - /* handle expander phys */ - if (phy->identify.sas_address != ioc->sas_hba.sas_address) { - phy->minimum_linkrate = rates->minimum_linkrate; - phy->maximum_linkrate = rates->maximum_linkrate; - return _transport_expander_phy_control(ioc, phy, - SMP_PHY_CONTROL_LINK_RESET); - } - - /* handle hba phys */ - - /* sas_iounit page 1 */ - sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys * - sizeof(Mpi2SasIOUnit1PhyData_t)); - 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__); - rc = -ENOMEM; - 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__); - rc = -ENXIO; - 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__); - rc = -EIO; - goto out; - } - - for (i = 0; i < ioc->sas_hba.num_phys; i++) { - if (phy->number != i) { - sas_iounit_pg1->PhyData[i].MaxMinLinkRate = - (ioc->sas_hba.phy[i].phy->minimum_linkrate + - (ioc->sas_hba.phy[i].phy->maximum_linkrate << 4)); - } else { - sas_iounit_pg1->PhyData[i].MaxMinLinkRate = - (rates->minimum_linkrate + - (rates->maximum_linkrate << 4)); - } - } - - if (mpt2sas_config_set_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__); - rc = -ENXIO; - goto out; - } - - /* link reset */ - _transport_phy_reset(phy, 0); - - /* read phy page 0, then update the rates in the sas transport phy */ - if (!mpt2sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0, - phy->number)) { - phy->minimum_linkrate = _transport_convert_phy_link_rate( - phy_pg0.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK); - phy->maximum_linkrate = _transport_convert_phy_link_rate( - phy_pg0.ProgrammedLinkRate >> 4); - phy->negotiated_linkrate = _transport_convert_phy_link_rate( - phy_pg0.NegotiatedLinkRate & - MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL); - } - - out: - kfree(sas_iounit_pg1); - return rc; -} - - -/** - * _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; - dma_addr_t dma_addr_in = 0; - dma_addr_t dma_addr_out = 0; - dma_addr_t pci_dma_in = 0; - dma_addr_t pci_dma_out = 0; - void *pci_addr_in = NULL; - void *pci_addr_out = NULL; - u16 wait_state_count; - struct request *rsp = req->next_rq; - struct bio_vec bvec; - struct bvec_iter iter; - - if (!rsp) { - printk(MPT2SAS_ERR_FMT "%s: the smp response space is " - "missing\n", ioc->name, __func__); - return -EINVAL; - } - if (ioc->shost_recovery || ioc->pci_error_recovery) { - printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n", - __func__, ioc->name); - return -EFAULT; - } - - 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; - - /* Check if the request is split across multiple segments */ - if (bio_multiple_segments(req->bio)) { - u32 offset = 0; - - /* Allocate memory and copy the request */ - pci_addr_out = pci_alloc_consistent(ioc->pdev, - blk_rq_bytes(req), &pci_dma_out); - if (!pci_addr_out) { - printk(MPT2SAS_INFO_FMT "%s(): PCI Addr out = NULL\n", - ioc->name, __func__); - rc = -ENOMEM; - goto out; - } - - bio_for_each_segment(bvec, req->bio, iter) { - memcpy(pci_addr_out + offset, - page_address(bvec.bv_page) + bvec.bv_offset, - bvec.bv_len); - offset += bvec.bv_len; - } - } else { - dma_addr_out = pci_map_single(ioc->pdev, bio_data(req->bio), - blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL); - if (!dma_addr_out) { - printk(MPT2SAS_INFO_FMT "%s(): DMA Addr out = NULL\n", - ioc->name, __func__); - rc = -ENOMEM; - goto free_pci; - } - } - - /* Check if the response needs to be populated across - * multiple segments */ - if (bio_multiple_segments(rsp->bio)) { - pci_addr_in = pci_alloc_consistent(ioc->pdev, blk_rq_bytes(rsp), - &pci_dma_in); - if (!pci_addr_in) { - printk(MPT2SAS_INFO_FMT "%s(): PCI Addr in = NULL\n", - ioc->name, __func__); - rc = -ENOMEM; - goto unmap; - } - } else { - dma_addr_in = pci_map_single(ioc->pdev, bio_data(rsp->bio), - blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL); - if (!dma_addr_in) { - printk(MPT2SAS_INFO_FMT "%s(): DMA Addr in = NULL\n", - ioc->name, __func__); - rc = -ENOMEM; - goto unmap; - } - } - - 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 unmap; - } - 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 unmap; - } - - 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; - mpi_request->VF_ID = 0; /* TODO */ - mpi_request->VP_ID = 0; - 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(blk_rq_bytes(req) - 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; - if (bio_multiple_segments(req->bio)) { - ioc->base_add_sg_single(psge, sgl_flags | - (blk_rq_bytes(req) - 4), pci_dma_out); - } else { - ioc->base_add_sg_single(psge, sgl_flags | - (blk_rq_bytes(req) - 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; - if (bio_multiple_segments(rsp->bio)) { - ioc->base_add_sg_single(psge, sgl_flags | - (blk_rq_bytes(rsp) + 4), pci_dma_in); - } else { - ioc->base_add_sg_single(psge, sgl_flags | - (blk_rq_bytes(rsp) + 4), dma_addr_in); - } - - dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "%s - " - "sending smp request\n", ioc->name, __func__)); - - init_completion(&ioc->transport_cmds.done); - mpt2sas_base_put_smid_default(ioc, smid); - 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_INFO_FMT "%s - " - "complete\n", ioc->name, __func__)); - - if (ioc->transport_cmds.status & MPT2_CMD_REPLY_VALID) { - - mpi_reply = ioc->transport_cmds.reply; - - dtransportprintk(ioc, printk(MPT2SAS_INFO_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->resid_len = 0; - rsp->resid_len -= - le16_to_cpu(mpi_reply->ResponseDataLength); - /* check if the resp needs to be copied from the allocated - * pci mem */ - if (bio_multiple_segments(rsp->bio)) { - u32 offset = 0; - u32 bytes_to_copy = - le16_to_cpu(mpi_reply->ResponseDataLength); - bio_for_each_segment(bvec, rsp->bio, iter) { - if (bytes_to_copy <= bvec.bv_len) { - memcpy(page_address(bvec.bv_page) + - bvec.bv_offset, pci_addr_in + - offset, bytes_to_copy); - break; - } else { - memcpy(page_address(bvec.bv_page) + - bvec.bv_offset, pci_addr_in + - offset, bvec.bv_len); - bytes_to_copy -= bvec.bv_len; - } - offset += bvec.bv_len; - } - } - } else { - dtransportprintk(ioc, printk(MPT2SAS_INFO_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, blk_rq_bytes(req), - PCI_DMA_BIDIRECTIONAL); - if (dma_addr_in) - pci_unmap_single(ioc->pdev, dma_addr_in, blk_rq_bytes(rsp), - PCI_DMA_BIDIRECTIONAL); - - free_pci: - if (pci_addr_out) - pci_free_consistent(ioc->pdev, blk_rq_bytes(req), pci_addr_out, - pci_dma_out); - - if (pci_addr_in) - pci_free_consistent(ioc->pdev, blk_rq_bytes(rsp), pci_addr_in, - pci_dma_in); - - 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, - .phy_enable = _transport_phy_enable, - .set_phy_speed = _transport_phy_speed, - .smp_handler = _transport_smp_handler, -}; - -struct scsi_transport_template *mpt2sas_transport_template; diff --git a/drivers/scsi/mpt3sas/Kconfig b/drivers/scsi/mpt3sas/Kconfig index 4d235dd741bf..29061467cc17 100644 --- a/drivers/scsi/mpt3sas/Kconfig +++ b/drivers/scsi/mpt3sas/Kconfig @@ -41,15 +41,15 @@ # USA. config SCSI_MPT3SAS - tristate "LSI MPT Fusion SAS 3.0 Device Driver" + tristate "LSI MPT Fusion SAS 3.0 & SAS 2.0 Device Driver" depends on PCI && SCSI select SCSI_SAS_ATTRS select RAID_ATTRS ---help--- This driver supports PCI-Express SAS 12Gb/s Host Adapters. -config SCSI_MPT3SAS_MAX_SGE - int "LSI MPT Fusion Max number of SG Entries (16 - 256)" +config SCSI_MPT2SAS_MAX_SGE + int "LSI MPT Fusion SAS 2.0 Max number of SG Entries (16 - 256)" depends on PCI && SCSI && SCSI_MPT3SAS default "128" range 16 256 @@ -60,8 +60,14 @@ config SCSI_MPT3SAS_MAX_SGE can be 256. However, it may decreased down to 16. Decreasing this parameter will reduce memory requirements on a per controller instance. -config SCSI_MPT3SAS_LOGGING - bool "LSI MPT Fusion logging facility" +config SCSI_MPT3SAS_MAX_SGE + int "LSI MPT Fusion SAS 3.0 Max number of SG Entries (16 - 256)" depends on PCI && SCSI && SCSI_MPT3SAS + default "128" + range 16 256 ---help--- - This turns on a logging facility. + This option allows you to specify the maximum number of scatter- + gather entries per I/O. The driver default is 128, which matches + MAX_PHYS_SEGMENTS in most kernels. However in SuSE kernels this + can be 256. However, it may decreased down to 16. Decreasing this + parameter will reduce memory requirements on a per controller instance. diff --git a/drivers/scsi/mpt3sas/Makefile b/drivers/scsi/mpt3sas/Makefile index efb0c4c2e310..b7643f596c1e 100644 --- a/drivers/scsi/mpt3sas/Makefile +++ b/drivers/scsi/mpt3sas/Makefile @@ -5,4 +5,5 @@ mpt3sas-y += mpt3sas_base.o \ mpt3sas_scsih.o \ mpt3sas_transport.o \ mpt3sas_ctl.o \ - mpt3sas_trigger_diag.o + mpt3sas_trigger_diag.o \ + mpt3sas_warpdrive.o diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index d4f1dcdb8361..11393ebf1a68 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -108,9 +108,12 @@ _scsih_set_fwfault_debug(const char *val, struct kernel_param *kp) if (ret) return ret; + /* global ioc spinlock to protect controller list on list operations */ pr_info("setting fwfault_debug(%d)\n", mpt3sas_fwfault_debug); + spin_lock(&gioc_lock); list_for_each_entry(ioc, &mpt3sas_ioc_list, list) ioc->fwfault_debug = mpt3sas_fwfault_debug; + spin_unlock(&gioc_lock); return 0; } module_param_call(mpt3sas_fwfault_debug, _scsih_set_fwfault_debug, @@ -157,7 +160,7 @@ _base_fault_reset_work(struct work_struct *work) spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); - if (ioc->shost_recovery) + if (ioc->shost_recovery || ioc->pci_error_recovery) goto rearm_timer; spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); @@ -166,6 +169,20 @@ _base_fault_reset_work(struct work_struct *work) pr_err(MPT3SAS_FMT "SAS host is non-operational !!!!\n", ioc->name); + /* It may be possible that EEH recovery can resolve some of + * pci bus failure issues rather removing the dead ioc function + * by considering controller is in a non-operational state. So + * here priority is given to the EEH recovery. If it doesn't + * not resolve this issue, mpt3sas driver will consider this + * controller to non-operational state and remove the dead ioc + * function. + */ + if (ioc->non_operational_loop++ < 5) { + spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, + flags); + goto rearm_timer; + } + /* * Call _scsih_flush_pending_cmds callback so that we flush all * pending commands back to OS. This call is required to aovid @@ -181,7 +198,7 @@ _base_fault_reset_work(struct work_struct *work) ioc->remove_host = 1; /*Remove the Dead Host */ p = kthread_run(mpt3sas_remove_dead_ioc_func, ioc, - "mpt3sas_dead_ioc_%d", ioc->id); + "%s_dead_ioc_%d", ioc->driver_name, ioc->id); if (IS_ERR(p)) pr_err(MPT3SAS_FMT "%s: Running mpt3sas_dead_ioc thread failed !!!!\n", @@ -193,6 +210,8 @@ _base_fault_reset_work(struct work_struct *work) return; /* don't rearm timer */ } + ioc->non_operational_loop = 0; + if ((doorbell & MPI2_IOC_STATE_MASK) != MPI2_IOC_STATE_OPERATIONAL) { rc = mpt3sas_base_hard_reset_handler(ioc, CAN_SLEEP, FORCE_BIG_HAMMER); @@ -235,7 +254,8 @@ mpt3sas_base_start_watchdog(struct MPT3SAS_ADAPTER *ioc) 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); + sizeof(ioc->fault_reset_work_q_name), "poll_%s%d_status", + ioc->driver_name, ioc->id); ioc->fault_reset_work_q = create_singlethread_workqueue(ioc->fault_reset_work_q_name); if (!ioc->fault_reset_work_q) { @@ -324,7 +344,6 @@ mpt3sas_halt_firmware(struct MPT3SAS_ADAPTER *ioc) panic("panic in %s\n", __func__); } -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING /** * _base_sas_ioc_info - verbose translation of the ioc status * @ioc: per adapter object @@ -578,7 +597,8 @@ _base_display_event_data(struct MPT3SAS_ADAPTER *ioc, desc = "Device Status Change"; break; case MPI2_EVENT_IR_OPERATION_STATUS: - desc = "IR Operation Status"; + if (!ioc->hide_ir_msg) + desc = "IR Operation Status"; break; case MPI2_EVENT_SAS_DISCOVERY: { @@ -609,16 +629,20 @@ _base_display_event_data(struct MPT3SAS_ADAPTER *ioc, desc = "SAS Enclosure Device Status Change"; break; case MPI2_EVENT_IR_VOLUME: - desc = "IR Volume"; + if (!ioc->hide_ir_msg) + desc = "IR Volume"; break; case MPI2_EVENT_IR_PHYSICAL_DISK: - desc = "IR Physical Disk"; + if (!ioc->hide_ir_msg) + desc = "IR Physical Disk"; break; case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST: - desc = "IR Configuration Change List"; + if (!ioc->hide_ir_msg) + desc = "IR Configuration Change List"; break; case MPI2_EVENT_LOG_ENTRY_ADDED: - desc = "Log Entry Added"; + if (!ioc->hide_ir_msg) + desc = "Log Entry Added"; break; case MPI2_EVENT_TEMP_THRESHOLD: desc = "Temperature Threshold"; @@ -630,7 +654,6 @@ _base_display_event_data(struct MPT3SAS_ADAPTER *ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, desc); } -#endif /** * _base_sas_log_info - verbose translation of firmware log info @@ -675,7 +698,10 @@ _base_sas_log_info(struct MPT3SAS_ADAPTER *ioc , u32 log_info) originator_str = "PL"; break; case 2: - originator_str = "IR"; + if (!ioc->hide_ir_msg) + originator_str = "IR"; + else + originator_str = "WarpDrive"; break; } @@ -710,13 +736,13 @@ _base_display_reply_info(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, return; } ioc_status = le16_to_cpu(mpi_reply->IOCStatus); -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING + if ((ioc_status & MPI2_IOCSTATUS_MASK) && (ioc->logging_level & MPT_DEBUG_REPLY)) { _base_sas_ioc_info(ioc , mpi_reply, mpt3sas_base_get_msg_frame(ioc, smid)); } -#endif + if (ioc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) { loginfo = le32_to_cpu(mpi_reply->IOCLogInfo); _base_sas_log_info(ioc, loginfo); @@ -783,9 +809,9 @@ _base_async_event(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, u32 reply) return 1; if (mpi_reply->Function != MPI2_FUNCTION_EVENT_NOTIFICATION) return 1; -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING + _base_display_event_data(ioc, mpi_reply); -#endif + if (!(mpi_reply->AckRequired & MPI2_EVENT_NOTIFICATION_ACK_REQUIRED)) goto out; smid = mpt3sas_base_get_smid(ioc, ioc->base_cb_idx); @@ -1009,6 +1035,12 @@ _base_interrupt(int irq, void *bus_id) } wmb(); + if (ioc->is_warpdrive) { + writel(reply_q->reply_post_host_index, + ioc->reply_post_host_index[msix_index]); + atomic_dec(&reply_q->busy); + return IRQ_HANDLED; + } /* Update Reply Post Host Index. * For those HBA's which support combined reply queue feature @@ -1320,6 +1352,149 @@ _base_build_zero_len_sge_ieee(struct MPT3SAS_ADAPTER *ioc, void *paddr) } /** + * _base_build_sg_scmd - 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 +_base_build_sg_scmd(struct MPT3SAS_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; + int sges_left; + u32 sges_in_segment; + u32 sgl_flags; + u32 sgl_flags_last_element; + u32 sgl_flags_end_buffer; + struct chain_tracker *chain_req; + + mpi_request = mpt3sas_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 < 0) { + 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_req = _base_get_chain_buffer_tracker(ioc, smid); + if (!chain_req) + return -1; + chain = chain_req->chain_buffer; + chain_dma = chain_req->chain_buffer_dma; + 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_req = _base_get_chain_buffer_tracker(ioc, smid); + if (!chain_req) + return -1; + chain = chain_req->chain_buffer; + chain_dma = chain_req->chain_buffer_dma; + } 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; +} + +/** * _base_build_sg_scmd_ieee - main sg creation routine for IEEE format * @ioc: per adapter object * @scmd: scsi command @@ -1571,6 +1746,14 @@ _base_check_enable_msix(struct MPT3SAS_ADAPTER *ioc) int base; u16 message_control; + /* Check whether controller SAS2008 B0 controller, + * if it is SAS2008 B0 controller use IO-APIC instead of MSIX + */ + if (ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2008 && + ioc->pdev->revision == SAS2_PCI_DEVICE_B0_REVISION) { + return -EINVAL; + } + base = pci_find_capability(ioc->pdev, PCI_CAP_ID_MSIX); if (!base) { dfailprintk(ioc, pr_info(MPT3SAS_FMT "msix not supported\n", @@ -1579,9 +1762,19 @@ _base_check_enable_msix(struct MPT3SAS_ADAPTER *ioc) } /* get msix vector count */ - - pci_read_config_word(ioc->pdev, base + 2, &message_control); - ioc->msix_vector_count = (message_control & 0x3FF) + 1; + /* NUMA_IO not supported for older controllers */ + if (ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2004 || + ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2008 || + ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_1 || + ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_2 || + ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_3 || + ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2116_1 || + ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2116_2) + ioc->msix_vector_count = 1; + else { + pci_read_config_word(ioc->pdev, base + 2, &message_control); + ioc->msix_vector_count = (message_control & 0x3FF) + 1; + } dinitprintk(ioc, pr_info(MPT3SAS_FMT "msix is supported, vector_count(%d)\n", ioc->name, ioc->msix_vector_count)); @@ -1643,10 +1836,10 @@ _base_request_irq(struct MPT3SAS_ADAPTER *ioc, u8 index, u32 vector) atomic_set(&reply_q->busy, 0); if (ioc->msix_enable) snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d-msix%d", - MPT3SAS_DRIVER_NAME, ioc->id, index); + ioc->driver_name, ioc->id, index); else snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d", - MPT3SAS_DRIVER_NAME, ioc->id); + ioc->driver_name, ioc->id); r = request_irq(vector, _base_interrupt, IRQF_SHARED, reply_q->name, reply_q); if (r) { @@ -1872,7 +2065,7 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc) if (pci_request_selected_regions(pdev, ioc->bars, - MPT3SAS_DRIVER_NAME)) { + ioc->driver_name)) { pr_warn(MPT3SAS_FMT "pci_request_selected_regions: failed\n", ioc->name); ioc->bars = 0; @@ -2158,6 +2351,7 @@ mpt3sas_base_free_smid(struct MPT3SAS_ADAPTER *ioc, u16 smid) } ioc->scsi_lookup[i].cb_idx = 0xFF; ioc->scsi_lookup[i].scmd = NULL; + ioc->scsi_lookup[i].direct_io = 0; list_add(&ioc->scsi_lookup[i].tracker_list, &ioc->free_list); spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); @@ -2318,143 +2512,261 @@ mpt3sas_base_put_smid_default(struct MPT3SAS_ADAPTER *ioc, u16 smid) } /** - * _base_display_intel_branding - Display branding string + * _base_display_OEMs_branding - Display branding string * @ioc: per adapter object * * Return nothing. */ static void -_base_display_intel_branding(struct MPT3SAS_ADAPTER *ioc) +_base_display_OEMs_branding(struct MPT3SAS_ADAPTER *ioc) { if (ioc->pdev->subsystem_vendor != PCI_VENDOR_ID_INTEL) return; - switch (ioc->pdev->device) { - case MPI25_MFGPAGE_DEVID_SAS3008: - switch (ioc->pdev->subsystem_device) { - case MPT3SAS_INTEL_RMS3JC080_SSDID: - pr_info(MPT3SAS_FMT "%s\n", ioc->name, - MPT3SAS_INTEL_RMS3JC080_BRANDING); - break; - - case MPT3SAS_INTEL_RS3GC008_SSDID: - pr_info(MPT3SAS_FMT "%s\n", ioc->name, - MPT3SAS_INTEL_RS3GC008_BRANDING); - break; - case MPT3SAS_INTEL_RS3FC044_SSDID: - pr_info(MPT3SAS_FMT "%s\n", ioc->name, - MPT3SAS_INTEL_RS3FC044_BRANDING); - break; - case MPT3SAS_INTEL_RS3UC080_SSDID: - pr_info(MPT3SAS_FMT "%s\n", ioc->name, - MPT3SAS_INTEL_RS3UC080_BRANDING); + switch (ioc->pdev->subsystem_vendor) { + case PCI_VENDOR_ID_INTEL: + switch (ioc->pdev->device) { + case MPI2_MFGPAGE_DEVID_SAS2008: + switch (ioc->pdev->subsystem_device) { + case MPT2SAS_INTEL_RMS2LL080_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT2SAS_INTEL_RMS2LL080_BRANDING); + break; + case MPT2SAS_INTEL_RMS2LL040_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT2SAS_INTEL_RMS2LL040_BRANDING); + break; + case MPT2SAS_INTEL_SSD910_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT2SAS_INTEL_SSD910_BRANDING); + break; + default: + pr_info(MPT3SAS_FMT + "Intel(R) Controller: Subsystem ID: 0x%X\n", + ioc->name, ioc->pdev->subsystem_device); + break; + } + case MPI2_MFGPAGE_DEVID_SAS2308_2: + switch (ioc->pdev->subsystem_device) { + case MPT2SAS_INTEL_RS25GB008_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT2SAS_INTEL_RS25GB008_BRANDING); + break; + case MPT2SAS_INTEL_RMS25JB080_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT2SAS_INTEL_RMS25JB080_BRANDING); + break; + case MPT2SAS_INTEL_RMS25JB040_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT2SAS_INTEL_RMS25JB040_BRANDING); + break; + case MPT2SAS_INTEL_RMS25KB080_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT2SAS_INTEL_RMS25KB080_BRANDING); + break; + case MPT2SAS_INTEL_RMS25KB040_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT2SAS_INTEL_RMS25KB040_BRANDING); + break; + case MPT2SAS_INTEL_RMS25LB040_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT2SAS_INTEL_RMS25LB040_BRANDING); + break; + case MPT2SAS_INTEL_RMS25LB080_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT2SAS_INTEL_RMS25LB080_BRANDING); + break; + default: + pr_info(MPT3SAS_FMT + "Intel(R) Controller: Subsystem ID: 0x%X\n", + ioc->name, ioc->pdev->subsystem_device); + break; + } + case MPI25_MFGPAGE_DEVID_SAS3008: + switch (ioc->pdev->subsystem_device) { + case MPT3SAS_INTEL_RMS3JC080_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT3SAS_INTEL_RMS3JC080_BRANDING); + break; + + case MPT3SAS_INTEL_RS3GC008_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT3SAS_INTEL_RS3GC008_BRANDING); + break; + case MPT3SAS_INTEL_RS3FC044_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT3SAS_INTEL_RS3FC044_BRANDING); + break; + case MPT3SAS_INTEL_RS3UC080_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT3SAS_INTEL_RS3UC080_BRANDING); + break; + default: + pr_info(MPT3SAS_FMT + "Intel(R) Controller: Subsystem ID: 0x%X\n", + ioc->name, ioc->pdev->subsystem_device); + break; + } break; default: pr_info(MPT3SAS_FMT - "Intel(R) Controller: Subsystem ID: 0x%X\n", - ioc->name, ioc->pdev->subsystem_device); + "Intel(R) Controller: Subsystem ID: 0x%X\n", + ioc->name, ioc->pdev->subsystem_device); break; } break; - default: - pr_info(MPT3SAS_FMT - "Intel(R) Controller: Subsystem ID: 0x%X\n", - ioc->name, ioc->pdev->subsystem_device); - break; - } -} - - - -/** - * _base_display_dell_branding - Display branding string - * @ioc: per adapter object - * - * Return nothing. - */ -static void -_base_display_dell_branding(struct MPT3SAS_ADAPTER *ioc) -{ - if (ioc->pdev->subsystem_vendor != PCI_VENDOR_ID_DELL) - return; - - switch (ioc->pdev->device) { - case MPI25_MFGPAGE_DEVID_SAS3008: - switch (ioc->pdev->subsystem_device) { - case MPT3SAS_DELL_12G_HBA_SSDID: - pr_info(MPT3SAS_FMT "%s\n", ioc->name, - MPT3SAS_DELL_12G_HBA_BRANDING); + case PCI_VENDOR_ID_DELL: + switch (ioc->pdev->device) { + case MPI2_MFGPAGE_DEVID_SAS2008: + switch (ioc->pdev->subsystem_device) { + case MPT2SAS_DELL_6GBPS_SAS_HBA_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT2SAS_DELL_6GBPS_SAS_HBA_BRANDING); + break; + case MPT2SAS_DELL_PERC_H200_ADAPTER_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT2SAS_DELL_PERC_H200_ADAPTER_BRANDING); + break; + case MPT2SAS_DELL_PERC_H200_INTEGRATED_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT2SAS_DELL_PERC_H200_INTEGRATED_BRANDING); + break; + case MPT2SAS_DELL_PERC_H200_MODULAR_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT2SAS_DELL_PERC_H200_MODULAR_BRANDING); + break; + case MPT2SAS_DELL_PERC_H200_EMBEDDED_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT2SAS_DELL_PERC_H200_EMBEDDED_BRANDING); + break; + case MPT2SAS_DELL_PERC_H200_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT2SAS_DELL_PERC_H200_BRANDING); + break; + case MPT2SAS_DELL_6GBPS_SAS_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT2SAS_DELL_6GBPS_SAS_BRANDING); + break; + default: + pr_info(MPT3SAS_FMT + "Dell 6Gbps HBA: Subsystem ID: 0x%X\n", + ioc->name, ioc->pdev->subsystem_device); + break; + } + break; + case MPI25_MFGPAGE_DEVID_SAS3008: + switch (ioc->pdev->subsystem_device) { + case MPT3SAS_DELL_12G_HBA_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT3SAS_DELL_12G_HBA_BRANDING); + break; + default: + pr_info(MPT3SAS_FMT + "Dell 12Gbps HBA: Subsystem ID: 0x%X\n", + ioc->name, ioc->pdev->subsystem_device); + break; + } break; default: pr_info(MPT3SAS_FMT - "Dell 12Gbps HBA: Subsystem ID: 0x%X\n", ioc->name, + "Dell HBA: Subsystem ID: 0x%X\n", ioc->name, ioc->pdev->subsystem_device); break; } break; - default: - pr_info(MPT3SAS_FMT - "Dell 12Gbps HBA: Subsystem ID: 0x%X\n", ioc->name, - ioc->pdev->subsystem_device); - break; - } -} - -/** - * _base_display_cisco_branding - Display branding string - * @ioc: per adapter object - * - * Return nothing. - */ -static void -_base_display_cisco_branding(struct MPT3SAS_ADAPTER *ioc) -{ - if (ioc->pdev->subsystem_vendor != PCI_VENDOR_ID_CISCO) - return; - - switch (ioc->pdev->device) { - case MPI25_MFGPAGE_DEVID_SAS3008: - switch (ioc->pdev->subsystem_device) { - case MPT3SAS_CISCO_12G_8E_HBA_SSDID: - pr_info(MPT3SAS_FMT "%s\n", ioc->name, - MPT3SAS_CISCO_12G_8E_HBA_BRANDING); - break; - case MPT3SAS_CISCO_12G_8I_HBA_SSDID: - pr_info(MPT3SAS_FMT "%s\n", ioc->name, - MPT3SAS_CISCO_12G_8I_HBA_BRANDING); + case PCI_VENDOR_ID_CISCO: + switch (ioc->pdev->device) { + case MPI25_MFGPAGE_DEVID_SAS3008: + switch (ioc->pdev->subsystem_device) { + case MPT3SAS_CISCO_12G_8E_HBA_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT3SAS_CISCO_12G_8E_HBA_BRANDING); + break; + case MPT3SAS_CISCO_12G_8I_HBA_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT3SAS_CISCO_12G_8I_HBA_BRANDING); + break; + case MPT3SAS_CISCO_12G_AVILA_HBA_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT3SAS_CISCO_12G_AVILA_HBA_BRANDING); + break; + default: + pr_info(MPT3SAS_FMT + "Cisco 12Gbps SAS HBA: Subsystem ID: 0x%X\n", + ioc->name, ioc->pdev->subsystem_device); + break; + } break; - case MPT3SAS_CISCO_12G_AVILA_HBA_SSDID: - pr_info(MPT3SAS_FMT "%s\n", ioc->name, + case MPI25_MFGPAGE_DEVID_SAS3108_1: + switch (ioc->pdev->subsystem_device) { + case MPT3SAS_CISCO_12G_AVILA_HBA_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, MPT3SAS_CISCO_12G_AVILA_HBA_BRANDING); + break; + case MPT3SAS_CISCO_12G_COLUSA_MEZZANINE_HBA_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT3SAS_CISCO_12G_COLUSA_MEZZANINE_HBA_BRANDING + ); + break; + default: + pr_info(MPT3SAS_FMT + "Cisco 12Gbps SAS HBA: Subsystem ID: 0x%X\n", + ioc->name, ioc->pdev->subsystem_device); + break; + } break; default: pr_info(MPT3SAS_FMT - "Cisco 12Gbps SAS HBA: Subsystem ID: 0x%X\n", - ioc->name, ioc->pdev->subsystem_device); + "Cisco SAS HBA: Subsystem ID: 0x%X\n", + ioc->name, ioc->pdev->subsystem_device); break; } break; - case MPI25_MFGPAGE_DEVID_SAS3108_1: - switch (ioc->pdev->subsystem_device) { - case MPT3SAS_CISCO_12G_AVILA_HBA_SSDID: - pr_info(MPT3SAS_FMT "%s\n", ioc->name, - MPT3SAS_CISCO_12G_AVILA_HBA_BRANDING); - break; - case MPT3SAS_CISCO_12G_COLUSA_MEZZANINE_HBA_SSDID: - pr_info(MPT3SAS_FMT "%s\n", ioc->name, - MPT3SAS_CISCO_12G_COLUSA_MEZZANINE_HBA_BRANDING); - break; + case MPT2SAS_HP_3PAR_SSVID: + switch (ioc->pdev->device) { + case MPI2_MFGPAGE_DEVID_SAS2004: + switch (ioc->pdev->subsystem_device) { + case MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_BRANDING); + break; + default: + pr_info(MPT3SAS_FMT + "HP 6Gbps SAS HBA: Subsystem ID: 0x%X\n", + ioc->name, ioc->pdev->subsystem_device); + break; + } + case MPI2_MFGPAGE_DEVID_SAS2308_2: + switch (ioc->pdev->subsystem_device) { + case MPT2SAS_HP_2_4_INTERNAL_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT2SAS_HP_2_4_INTERNAL_BRANDING); + break; + case MPT2SAS_HP_2_4_EXTERNAL_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT2SAS_HP_2_4_EXTERNAL_BRANDING); + break; + case MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_BRANDING); + break; + case MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_BRANDING); + break; + default: + pr_info(MPT3SAS_FMT + "HP 6Gbps SAS HBA: Subsystem ID: 0x%X\n", + ioc->name, ioc->pdev->subsystem_device); + break; + } default: pr_info(MPT3SAS_FMT - "Cisco 12Gbps SAS HBA: Subsystem ID: 0x%X\n", - ioc->name, ioc->pdev->subsystem_device); + "HP SAS HBA: Subsystem ID: 0x%X\n", + ioc->name, ioc->pdev->subsystem_device); break; } - break; default: - pr_info(MPT3SAS_FMT - "Cisco 12Gbps SAS HBA: Subsystem ID: 0x%X\n", - ioc->name, ioc->pdev->subsystem_device); break; } } @@ -2488,9 +2800,7 @@ _base_display_ioc_capabilities(struct MPT3SAS_ADAPTER *ioc) (bios_version & 0x0000FF00) >> 8, bios_version & 0x000000FF); - _base_display_intel_branding(ioc); - _base_display_dell_branding(ioc); - _base_display_cisco_branding(ioc); + _base_display_OEMs_branding(ioc); pr_info(MPT3SAS_FMT "Protocol=(", ioc->name); @@ -2508,10 +2818,12 @@ _base_display_ioc_capabilities(struct MPT3SAS_ADAPTER *ioc) pr_info("), "); pr_info("Capabilities=("); - if (ioc->facts.IOCCapabilities & + if (!ioc->hide_ir_msg) { + if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID) { pr_info("Raid"); i++; + } } if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TLR) { @@ -2852,18 +3164,22 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc, int sleep_flag) /* command line tunables for max sgl entries */ if (max_sgl_entries != -1) sg_tablesize = max_sgl_entries; - else - sg_tablesize = MPT3SAS_SG_DEPTH; + else { + if (ioc->hba_mpi_version_belonged == MPI2_VERSION) + sg_tablesize = MPT2SAS_SG_DEPTH; + else + sg_tablesize = MPT3SAS_SG_DEPTH; + } - if (sg_tablesize < MPT3SAS_MIN_PHYS_SEGMENTS) - sg_tablesize = MPT3SAS_MIN_PHYS_SEGMENTS; - else if (sg_tablesize > MPT3SAS_MAX_PHYS_SEGMENTS) { + if (sg_tablesize < MPT_MIN_PHYS_SEGMENTS) + sg_tablesize = MPT_MIN_PHYS_SEGMENTS; + else if (sg_tablesize > MPT_MAX_PHYS_SEGMENTS) { sg_tablesize = min_t(unsigned short, sg_tablesize, SCSI_MAX_SG_CHAIN_SEGMENTS); pr_warn(MPT3SAS_FMT "sg_tablesize(%u) is bigger than kernel" " defined SCSI_MAX_SG_SEGMENTS(%u)\n", ioc->name, - sg_tablesize, MPT3SAS_MAX_PHYS_SEGMENTS); + sg_tablesize, MPT_MAX_PHYS_SEGMENTS); } ioc->shost->sg_tablesize = sg_tablesize; @@ -4021,7 +4337,7 @@ _base_send_ioc_init(struct MPT3SAS_ADAPTER *ioc, int sleep_flag) mpi_request.WhoInit = MPI2_WHOINIT_HOST_DRIVER; mpi_request.VF_ID = 0; /* TODO */ mpi_request.VP_ID = 0; - mpi_request.MsgVersion = cpu_to_le16(MPI25_VERSION); + mpi_request.MsgVersion = cpu_to_le16(ioc->hba_mpi_version_belonged); mpi_request.HeaderVersion = cpu_to_le16(MPI2_HEADER_VERSION); if (_base_is_controller_msix_enabled(ioc)) @@ -4655,6 +4971,7 @@ _base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc, int sleep_flag) u32 reply_address; u16 smid; struct _tr_list *delayed_tr, *delayed_tr_next; + u8 hide_flag; struct adapter_reply_queue *reply_q; long reply_post_free; u32 reply_post_free_sz, index = 0; @@ -4685,6 +5002,7 @@ _base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc, int sleep_flag) ioc->scsi_lookup[i].cb_idx = 0xFF; ioc->scsi_lookup[i].smid = smid; ioc->scsi_lookup[i].scmd = NULL; + ioc->scsi_lookup[i].direct_io = 0; list_add_tail(&ioc->scsi_lookup[i].tracker_list, &ioc->free_list); } @@ -4787,6 +5105,16 @@ _base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc, int sleep_flag) if (ioc->is_driver_loading) { + + if (ioc->is_warpdrive && ioc->manu_pg10.OEMIdentifier + == 0x80) { + hide_flag = (u8) ( + le32_to_cpu(ioc->manu_pg10.OEMSpecificFlags0) & + MFG_PAGE10_HIDE_SSDS_MASK); + if (hide_flag != MFG_PAGE10_HIDE_SSDS_MASK) + ioc->mfg_pg10_hide_flag = hide_flag; + } + ioc->wait_for_discovery_to_complete = _base_determine_wait_on_discovery(ioc); @@ -4812,6 +5140,8 @@ mpt3sas_base_free_resources(struct MPT3SAS_ADAPTER *ioc) dexitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, __func__)); + /* synchronizing freeing resource with pci_access_mutex lock */ + mutex_lock(&ioc->pci_access_mutex); if (ioc->chip_phys && ioc->chip) { _base_mask_interrupts(ioc); ioc->shost_recovery = 1; @@ -4820,6 +5150,7 @@ mpt3sas_base_free_resources(struct MPT3SAS_ADAPTER *ioc) } mpt3sas_base_unmap_resources(ioc); + mutex_unlock(&ioc->pci_access_mutex); return; } @@ -4834,7 +5165,6 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc) { int r, i; int cpu_id, last_cpu_id = 0; - u8 revision; dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, __func__)); @@ -4854,19 +5184,16 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc) goto out_free_resources; } - /* Check whether the controller revision is C0 or above. - * only C0 and above revision controllers support 96 MSI-X vectors. - */ - revision = ioc->pdev->revision; - - if ((ioc->pdev->device == MPI25_MFGPAGE_DEVID_SAS3004 || - ioc->pdev->device == MPI25_MFGPAGE_DEVID_SAS3008 || - ioc->pdev->device == MPI25_MFGPAGE_DEVID_SAS3108_1 || - ioc->pdev->device == MPI25_MFGPAGE_DEVID_SAS3108_2 || - ioc->pdev->device == MPI25_MFGPAGE_DEVID_SAS3108_5 || - ioc->pdev->device == MPI25_MFGPAGE_DEVID_SAS3108_6) && - (revision >= 0x02)) - ioc->msix96_vector = 1; + if (ioc->is_warpdrive) { + ioc->reply_post_host_index = kcalloc(ioc->cpu_msix_table_sz, + sizeof(resource_size_t *), GFP_KERNEL); + if (!ioc->reply_post_host_index) { + dfailprintk(ioc, pr_info(MPT3SAS_FMT "allocation " + "for cpu_msix_table failed!!!\n", ioc->name)); + r = -ENOMEM; + goto out_free_resources; + } + } ioc->rdpq_array_enable_assigned = 0; ioc->dma_mask = 0; @@ -4874,23 +5201,41 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc) if (r) goto out_free_resources; + if (ioc->is_warpdrive) { + ioc->reply_post_host_index[0] = (resource_size_t __iomem *) + &ioc->chip->ReplyPostHostIndex; + + for (i = 1; i < ioc->cpu_msix_table_sz; i++) + ioc->reply_post_host_index[i] = + (resource_size_t __iomem *) + ((u8 __iomem *)&ioc->chip->Doorbell + (0x4000 + ((i - 1) + * 4))); + } pci_set_drvdata(ioc->pdev, ioc->shost); r = _base_get_ioc_facts(ioc, CAN_SLEEP); if (r) goto out_free_resources; - /* - * In SAS3.0, - * SCSI_IO, SMP_PASSTHRU, SATA_PASSTHRU, Target Assist, and - * Target Status - all require the IEEE formated scatter gather - * elements. - */ - - ioc->build_sg_scmd = &_base_build_sg_scmd_ieee; - ioc->build_sg = &_base_build_sg_ieee; - ioc->build_zero_len_sge = &_base_build_zero_len_sge_ieee; - ioc->sge_size_ieee = sizeof(Mpi2IeeeSgeSimple64_t); + switch (ioc->hba_mpi_version_belonged) { + case MPI2_VERSION: + ioc->build_sg_scmd = &_base_build_sg_scmd; + ioc->build_sg = &_base_build_sg; + ioc->build_zero_len_sge = &_base_build_zero_len_sge; + break; + case MPI25_VERSION: + /* + * In SAS3.0, + * SCSI_IO, SMP_PASSTHRU, SATA_PASSTHRU, Target Assist, and + * Target Status - all require the IEEE formated scatter gather + * elements. + */ + ioc->build_sg_scmd = &_base_build_sg_scmd_ieee; + ioc->build_sg = &_base_build_sg_ieee; + ioc->build_zero_len_sge = &_base_build_zero_len_sge_ieee; + ioc->sge_size_ieee = sizeof(Mpi2IeeeSgeSimple64_t); + break; + } /* * These function pointers for other requests that don't @@ -5006,6 +5351,7 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc) if (r) goto out_free_resources; + ioc->non_operational_loop = 0; return 0; out_free_resources: @@ -5016,6 +5362,8 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc) _base_release_memory_pools(ioc); pci_set_drvdata(ioc->pdev, NULL); kfree(ioc->cpu_msix_table); + if (ioc->is_warpdrive) + kfree(ioc->reply_post_host_index); kfree(ioc->pd_handles); kfree(ioc->blocking_handles); kfree(ioc->tm_cmds.reply); @@ -5055,6 +5403,8 @@ mpt3sas_base_detach(struct MPT3SAS_ADAPTER *ioc) _base_release_memory_pools(ioc); pci_set_drvdata(ioc->pdev, NULL); kfree(ioc->cpu_msix_table); + if (ioc->is_warpdrive) + kfree(ioc->reply_post_host_index); kfree(ioc->pd_handles); kfree(ioc->blocking_handles); kfree(ioc->pfacts); diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h index f0e462b0880d..5ad271efbd45 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.h +++ b/drivers/scsi/mpt3sas/mpt3sas_base.h @@ -63,6 +63,8 @@ #include <scsi/scsi_transport_sas.h> #include <scsi/scsi_dbg.h> #include <scsi/scsi_eh.h> +#include <linux/pci.h> +#include <linux/poll.h> #include "mpt3sas_debug.h" #include "mpt3sas_trigger_diag.h" @@ -71,23 +73,37 @@ #define MPT3SAS_DRIVER_NAME "mpt3sas" #define MPT3SAS_AUTHOR "Avago Technologies <MPT-FusionLinux.pdl@avagotech.com>" #define MPT3SAS_DESCRIPTION "LSI MPT Fusion SAS 3.0 Device Driver" -#define MPT3SAS_DRIVER_VERSION "09.100.00.00" +#define MPT3SAS_DRIVER_VERSION "09.102.00.00" #define MPT3SAS_MAJOR_VERSION 9 -#define MPT3SAS_MINOR_VERSION 100 +#define MPT3SAS_MINOR_VERSION 102 #define MPT3SAS_BUILD_VERSION 0 #define MPT3SAS_RELEASE_VERSION 00 +#define MPT2SAS_DRIVER_NAME "mpt2sas" +#define MPT2SAS_DESCRIPTION "LSI MPT Fusion SAS 2.0 Device Driver" +#define MPT2SAS_DRIVER_VERSION "20.102.00.00" +#define MPT2SAS_MAJOR_VERSION 20 +#define MPT2SAS_MINOR_VERSION 102 +#define MPT2SAS_BUILD_VERSION 0 +#define MPT2SAS_RELEASE_VERSION 00 + /* * Set MPT3SAS_SG_DEPTH value based on user input. */ -#define MPT3SAS_MAX_PHYS_SEGMENTS SCSI_MAX_SG_SEGMENTS -#define MPT3SAS_MIN_PHYS_SEGMENTS 16 +#define MPT_MAX_PHYS_SEGMENTS SCSI_MAX_SG_SEGMENTS +#define MPT_MIN_PHYS_SEGMENTS 16 + #ifdef CONFIG_SCSI_MPT3SAS_MAX_SGE #define MPT3SAS_SG_DEPTH CONFIG_SCSI_MPT3SAS_MAX_SGE #else -#define MPT3SAS_SG_DEPTH MPT3SAS_MAX_PHYS_SEGMENTS +#define MPT3SAS_SG_DEPTH MPT_MAX_PHYS_SEGMENTS #endif +#ifdef CONFIG_SCSI_MPT2SAS_MAX_SGE +#define MPT2SAS_SG_DEPTH CONFIG_SCSI_MPT2SAS_MAX_SGE +#else +#define MPT2SAS_SG_DEPTH MPT_MAX_PHYS_SEGMENTS +#endif /* * Generic Defines @@ -124,6 +140,16 @@ #define MPT3SAS_FMT "%s: " /* + * WarpDrive Specific Log codes + */ + +#define MPT2_WARPDRIVE_LOGENTRY (0x8002) +#define MPT2_WARPDRIVE_LC_SSDT (0x41) +#define MPT2_WARPDRIVE_LC_SSDLW (0x43) +#define MPT2_WARPDRIVE_LC_SSDLF (0x44) +#define MPT2_WARPDRIVE_LC_BRMF (0x4D) + +/* * per target private data */ #define MPT_TARGET_FLAGS_RAID_COMPONENT 0x01 @@ -131,9 +157,33 @@ #define MPT_TARGET_FLAGS_DELETED 0x04 #define MPT_TARGET_FASTPATH_IO 0x08 +#define SAS2_PCI_DEVICE_B0_REVISION (0x01) +#define SAS3_PCI_DEVICE_C0_REVISION (0x02) + /* * Intel HBA branding */ +#define MPT2SAS_INTEL_RMS25JB080_BRANDING \ + "Intel(R) Integrated RAID Module RMS25JB080" +#define MPT2SAS_INTEL_RMS25JB040_BRANDING \ + "Intel(R) Integrated RAID Module RMS25JB040" +#define MPT2SAS_INTEL_RMS25KB080_BRANDING \ + "Intel(R) Integrated RAID Module RMS25KB080" +#define MPT2SAS_INTEL_RMS25KB040_BRANDING \ + "Intel(R) Integrated RAID Module RMS25KB040" +#define MPT2SAS_INTEL_RMS25LB040_BRANDING \ + "Intel(R) Integrated RAID Module RMS25LB040" +#define MPT2SAS_INTEL_RMS25LB080_BRANDING \ + "Intel(R) Integrated RAID Module RMS25LB080" +#define MPT2SAS_INTEL_RMS2LL080_BRANDING \ + "Intel Integrated RAID Module RMS2LL080" +#define MPT2SAS_INTEL_RMS2LL040_BRANDING \ + "Intel Integrated RAID Module RMS2LL040" +#define MPT2SAS_INTEL_RS25GB008_BRANDING \ + "Intel(R) RAID Controller RS25GB008" +#define MPT2SAS_INTEL_SSD910_BRANDING \ + "Intel(R) SSD 910 Series" + #define MPT3SAS_INTEL_RMS3JC080_BRANDING \ "Intel(R) Integrated RAID Module RMS3JC080" #define MPT3SAS_INTEL_RS3GC008_BRANDING \ @@ -146,33 +196,62 @@ /* * Intel HBA SSDIDs */ -#define MPT3SAS_INTEL_RMS3JC080_SSDID 0x3521 -#define MPT3SAS_INTEL_RS3GC008_SSDID 0x3522 -#define MPT3SAS_INTEL_RS3FC044_SSDID 0x3523 -#define MPT3SAS_INTEL_RS3UC080_SSDID 0x3524 +#define MPT2SAS_INTEL_RMS25JB080_SSDID 0x3516 +#define MPT2SAS_INTEL_RMS25JB040_SSDID 0x3517 +#define MPT2SAS_INTEL_RMS25KB080_SSDID 0x3518 +#define MPT2SAS_INTEL_RMS25KB040_SSDID 0x3519 +#define MPT2SAS_INTEL_RMS25LB040_SSDID 0x351A +#define MPT2SAS_INTEL_RMS25LB080_SSDID 0x351B +#define MPT2SAS_INTEL_RMS2LL080_SSDID 0x350E +#define MPT2SAS_INTEL_RMS2LL040_SSDID 0x350F +#define MPT2SAS_INTEL_RS25GB008_SSDID 0x3000 +#define MPT2SAS_INTEL_SSD910_SSDID 0x3700 + +#define MPT3SAS_INTEL_RMS3JC080_SSDID 0x3521 +#define MPT3SAS_INTEL_RS3GC008_SSDID 0x3522 +#define MPT3SAS_INTEL_RS3FC044_SSDID 0x3523 +#define MPT3SAS_INTEL_RS3UC080_SSDID 0x3524 /* * Dell HBA branding */ +#define MPT2SAS_DELL_BRANDING_SIZE 32 + +#define MPT2SAS_DELL_6GBPS_SAS_HBA_BRANDING "Dell 6Gbps SAS HBA" +#define MPT2SAS_DELL_PERC_H200_ADAPTER_BRANDING "Dell PERC H200 Adapter" +#define MPT2SAS_DELL_PERC_H200_INTEGRATED_BRANDING "Dell PERC H200 Integrated" +#define MPT2SAS_DELL_PERC_H200_MODULAR_BRANDING "Dell PERC H200 Modular" +#define MPT2SAS_DELL_PERC_H200_EMBEDDED_BRANDING "Dell PERC H200 Embedded" +#define MPT2SAS_DELL_PERC_H200_BRANDING "Dell PERC H200" +#define MPT2SAS_DELL_6GBPS_SAS_BRANDING "Dell 6Gbps SAS" + #define MPT3SAS_DELL_12G_HBA_BRANDING \ "Dell 12Gbps HBA" /* * Dell HBA SSDIDs */ -#define MPT3SAS_DELL_12G_HBA_SSDID 0x1F46 +#define MPT2SAS_DELL_6GBPS_SAS_HBA_SSDID 0x1F1C +#define MPT2SAS_DELL_PERC_H200_ADAPTER_SSDID 0x1F1D +#define MPT2SAS_DELL_PERC_H200_INTEGRATED_SSDID 0x1F1E +#define MPT2SAS_DELL_PERC_H200_MODULAR_SSDID 0x1F1F +#define MPT2SAS_DELL_PERC_H200_EMBEDDED_SSDID 0x1F20 +#define MPT2SAS_DELL_PERC_H200_SSDID 0x1F21 +#define MPT2SAS_DELL_6GBPS_SAS_SSDID 0x1F22 + +#define MPT3SAS_DELL_12G_HBA_SSDID 0x1F46 /* * Cisco HBA branding */ #define MPT3SAS_CISCO_12G_8E_HBA_BRANDING \ - "Cisco 9300-8E 12G SAS HBA" + "Cisco 9300-8E 12G SAS HBA" #define MPT3SAS_CISCO_12G_8I_HBA_BRANDING \ - "Cisco 9300-8i 12G SAS HBA" + "Cisco 9300-8i 12G SAS HBA" #define MPT3SAS_CISCO_12G_AVILA_HBA_BRANDING \ - "Cisco 12G Modular SAS Pass through Controller" + "Cisco 12G Modular SAS Pass through Controller" #define MPT3SAS_CISCO_12G_COLUSA_MEZZANINE_HBA_BRANDING \ - "UCS C3X60 12G SAS Pass through Controller" + "UCS C3X60 12G SAS Pass through Controller" /* * Cisco HBA SSSDIDs */ @@ -189,6 +268,31 @@ #define MPT3_DIAG_BUFFER_IS_DIAG_RESET (0x04) /* + * HP HBA branding + */ +#define MPT2SAS_HP_3PAR_SSVID 0x1590 + +#define MPT2SAS_HP_2_4_INTERNAL_BRANDING \ + "HP H220 Host Bus Adapter" +#define MPT2SAS_HP_2_4_EXTERNAL_BRANDING \ + "HP H221 Host Bus Adapter" +#define MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_BRANDING \ + "HP H222 Host Bus Adapter" +#define MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_BRANDING \ + "HP H220i Host Bus Adapter" +#define MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_BRANDING \ + "HP H210i Host Bus Adapter" + +/* + * HO HBA SSDIDs + */ +#define MPT2SAS_HP_2_4_INTERNAL_SSDID 0x0041 +#define MPT2SAS_HP_2_4_EXTERNAL_SSDID 0x0042 +#define MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_SSDID 0x0043 +#define MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_SSDID 0x0044 +#define MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_SSDID 0x0046 + +/* * Combined Reply Queue constants, * There are twelve Supplemental Reply Post Host Index Registers * and each register is at offset 0x10 bytes from the previous one. @@ -243,20 +347,24 @@ struct Mpi2ManufacturingPage11_t { * struct MPT3SAS_TARGET - starget private hostdata * @starget: starget object * @sas_address: target sas address + * @raid_device: raid_device pointer to access volume data * @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. + * @sdev: The sas_device associated with this target */ struct MPT3SAS_TARGET { struct scsi_target *starget; u64 sas_address; + struct _raid_device *raid_device; u16 handle; int num_luns; u32 flags; u8 deleted; u8 tm_busy; + struct _sas_device *sdev; }; @@ -266,6 +374,11 @@ struct MPT3SAS_TARGET { #define MPT_DEVICE_FLAGS_INIT 0x01 #define MPT_DEVICE_TLR_ON 0x02 +#define MFG_PAGE10_HIDE_SSDS_MASK (0x00000003) +#define MFG_PAGE10_HIDE_ALL_DISKS (0x00) +#define MFG_PAGE10_EXPOSE_ALL_DISKS (0x01) +#define MFG_PAGE10_HIDE_IF_VOL_PRESENT (0x02) + /** * struct MPT3SAS_DEVICE - sdev private hostdata * @sas_target: starget private hostdata @@ -358,8 +471,24 @@ struct _sas_device { u8 pend_sas_rphy_add; u8 enclosure_level; u8 connector_name[4]; + struct kref refcount; }; +static inline void sas_device_get(struct _sas_device *s) +{ + kref_get(&s->refcount); +} + +static inline void sas_device_free(struct kref *r) +{ + kfree(container_of(r, struct _sas_device, refcount)); +} + +static inline void sas_device_put(struct _sas_device *s) +{ + kref_put(&s->refcount, sas_device_free); +} + /** * struct _raid_device - raid volume link list * @list: sas device list @@ -367,6 +496,7 @@ struct _sas_device { * @sdev: scsi device struct (volumes are single lun) * @wwid: unique identifier for the volume * @handle: device handle + * @block_size: Block size of the volume * @id: target id * @channel: target channel * @volume_type: the raid level @@ -374,6 +504,13 @@ struct _sas_device { * @num_pds: number of hidden raid components * @responding: used in _scsih_raid_device_mark_responding * @percent_complete: resync percent complete + * @direct_io_enabled: Whether direct io to PDs are allowed or not + * @stripe_exponent: X where 2powX is the stripe sz in blocks + * @block_exponent: X where 2powX is the block sz in bytes + * @max_lba: Maximum number of LBA in the volume + * @stripe_sz: Stripe Size of the volume + * @device_info: Device info of the volume member disk + * @pd_handle: Array of handles of the physical drives for direct I/O in le16 */ #define MPT_MAX_WARPDRIVE_PDS 8 struct _raid_device { @@ -382,13 +519,20 @@ struct _raid_device { struct scsi_device *sdev; u64 wwid; u16 handle; + u16 block_sz; int id; int channel; u8 volume_type; u8 num_pds; u8 responding; u8 percent_complete; + u8 direct_io_enabled; + u8 stripe_exponent; + u8 block_exponent; + u64 max_lba; + u32 stripe_sz; u32 device_info; + u16 pd_handle[MPT_MAX_WARPDRIVE_PDS]; }; /** @@ -497,12 +641,14 @@ struct chain_tracker { * @smid: system message id * @scmd: scsi request pointer * @cb_idx: callback index + * @direct_io: To indicate whether I/O is direct (WARPDRIVE) * @tracker_list: list of free request (ioc->free_list) */ struct scsiio_tracker { u16 smid; struct scsi_cmnd *scmd; u8 cb_idx; + u8 direct_io; struct list_head chain_list; struct list_head tracker_list; }; @@ -775,7 +921,13 @@ typedef void (*MPT3SAS_FLUSH_RUNNING_CMDS)(struct MPT3SAS_ADAPTER *ioc); * @replyPostRegisterIndex: index of next position in Reply Desc Post Queue * @delayed_tr_list: target reset link list * @delayed_tr_volume_list: volume target reset link list - * @@temp_sensors_count: flag to carry the number of temperature sensors + * @temp_sensors_count: flag to carry the number of temperature sensors + * @pci_access_mutex: Mutex to synchronize ioctl,sysfs show path and + * pci resource handling. PCI resource freeing will lead to free + * vital hardware/memory resource, which might be in use by cli/sysfs + * path functions resulting in Null pointer reference followed by kernel + * crash. To avoid the above race condition we use mutex syncrhonization + * which ensures the syncrhonization between cli/sysfs_show path. */ struct MPT3SAS_ADAPTER { struct list_head list; @@ -783,6 +935,7 @@ struct MPT3SAS_ADAPTER { u8 id; int cpu_count; char name[MPT_NAME_LENGTH]; + char driver_name[MPT_NAME_LENGTH]; char tmp_string[MPT_STRING_LENGTH]; struct pci_dev *pdev; Mpi2SystemInterfaceRegs_t __iomem *chip; @@ -829,8 +982,10 @@ struct MPT3SAS_ADAPTER { u16 msix_vector_count; u8 *cpu_msix_table; u16 cpu_msix_table_sz; + resource_size_t __iomem **reply_post_host_index; u32 ioc_reset_count; MPT3SAS_FLUSH_RUNNING_CMDS schedule_dead_ioc_flush_running_cmds; + u32 non_operational_loop; /* internal commands, callback index */ u8 scsi_io_cb_idx; @@ -859,6 +1014,7 @@ struct MPT3SAS_ADAPTER { MPT_BUILD_SG build_sg; MPT_BUILD_ZERO_LEN_SGE build_zero_len_sge; u16 sge_size_ieee; + u16 hba_mpi_version_belonged; /* function ptr for MPI sg elements only */ MPT_BUILD_SG build_sg_mpi; @@ -987,6 +1143,7 @@ struct MPT3SAS_ADAPTER { struct list_head delayed_tr_list; struct list_head delayed_tr_volume_list; u8 temp_sensors_count; + struct mutex pci_access_mutex; /* diag buffer support */ u8 *diag_buffer[MPI2_DIAG_BUF_TYPE_COUNT]; @@ -998,6 +1155,10 @@ struct MPT3SAS_ADAPTER { u32 diagnostic_flags[MPI2_DIAG_BUF_TYPE_COUNT]; u32 ring_buffer_offset; u32 ring_buffer_sz; + u8 is_warpdrive; + u8 hide_ir_msg; + u8 mfg_pg10_hide_flag; + u8 hide_drives; spinlock_t diag_trigger_lock; u8 diag_trigger_active; struct SL_WH_MASTER_TRIGGER_T diag_trigger_master; @@ -1012,6 +1173,19 @@ typedef u8 (*MPT_CALLBACK)(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, /* base shared API */ extern struct list_head mpt3sas_ioc_list; +extern char driver_name[MPT_NAME_LENGTH]; +/* spinlock on list operations over IOCs + * Case: when multiple warpdrive cards(IOCs) are in use + * Each IOC will added to the ioc list structure on initialization. + * Watchdog threads run at regular intervals to check IOC for any + * fault conditions which will trigger the dead_ioc thread to + * deallocate pci resource, resulting deleting the IOC netry from list, + * this deletion need to protected by spinlock to enusre that + * ioc removal is syncrhonized, if not synchronized it might lead to + * list_del corruption as the ioc list is traversed in cli path. + */ +extern spinlock_t gioc_lock; + void mpt3sas_base_start_watchdog(struct MPT3SAS_ADAPTER *ioc); void mpt3sas_base_stop_watchdog(struct MPT3SAS_ADAPTER *ioc); @@ -1090,10 +1264,14 @@ struct _sas_node *mpt3sas_scsih_expander_find_by_handle( struct MPT3SAS_ADAPTER *ioc, u16 handle); struct _sas_node *mpt3sas_scsih_expander_find_by_sas_address( struct MPT3SAS_ADAPTER *ioc, u64 sas_address); -struct _sas_device *mpt3sas_scsih_sas_device_find_by_sas_address( - struct MPT3SAS_ADAPTER *ioc, u64 sas_address); +struct _sas_device *mpt3sas_get_sdev_by_addr( + struct MPT3SAS_ADAPTER *ioc, u64 sas_address); +struct _sas_device *__mpt3sas_get_sdev_by_addr( + struct MPT3SAS_ADAPTER *ioc, u64 sas_address); void mpt3sas_port_enable_complete(struct MPT3SAS_ADAPTER *ioc); +struct _raid_device * +mpt3sas_raid_device_find_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle); /* config shared API */ u8 mpt3sas_config_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, @@ -1133,6 +1311,8 @@ int mpt3sas_config_get_sas_iounit_pg0(struct MPT3SAS_ADAPTER *ioc, u16 sz); int mpt3sas_config_get_iounit_pg1(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage1_t *config_page); +int mpt3sas_config_get_iounit_pg3(struct MPT3SAS_ADAPTER *ioc, + Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage3_t *config_page, u16 sz); int mpt3sas_config_set_iounit_pg1(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage1_t *config_page); int mpt3sas_config_get_iounit_pg8(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t @@ -1177,8 +1357,8 @@ int mpt3sas_config_get_volume_wwid(struct MPT3SAS_ADAPTER *ioc, /* ctl shared API */ extern struct device_attribute *mpt3sas_host_attrs[]; extern struct device_attribute *mpt3sas_dev_attrs[]; -void mpt3sas_ctl_init(void); -void mpt3sas_ctl_exit(void); +void mpt3sas_ctl_init(ushort hbas_to_enumerate); +void mpt3sas_ctl_exit(ushort hbas_to_enumerate); u8 mpt3sas_ctl_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply); void mpt3sas_ctl_reset_handler(struct MPT3SAS_ADAPTER *ioc, int reset_phase); @@ -1193,6 +1373,7 @@ int mpt3sas_send_diag_release(struct MPT3SAS_ADAPTER *ioc, u8 buffer_type, u8 *issue_reset); /* transport shared API */ +extern struct scsi_transport_template *mpt3sas_transport_template; u8 mpt3sas_transport_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply); struct _sas_port *mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, @@ -1224,4 +1405,18 @@ void mpt3sas_trigger_scsi(struct MPT3SAS_ADAPTER *ioc, u8 sense_key, u8 asc, u8 ascq); void mpt3sas_trigger_mpi(struct MPT3SAS_ADAPTER *ioc, u16 ioc_status, u32 loginfo); + +/* warpdrive APIs */ +u8 mpt3sas_get_num_volumes(struct MPT3SAS_ADAPTER *ioc); +void mpt3sas_init_warpdrive_properties(struct MPT3SAS_ADAPTER *ioc, + struct _raid_device *raid_device); +u8 +mpt3sas_scsi_direct_io_get(struct MPT3SAS_ADAPTER *ioc, u16 smid); +void +mpt3sas_scsi_direct_io_set(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 direct_io); +void +mpt3sas_setup_direct_io(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, + struct _raid_device *raid_device, Mpi2SCSIIORequest_t *mpi_request, + u16 smid); + #endif /* MPT3SAS_BASE_H_INCLUDED */ diff --git a/drivers/scsi/mpt3sas/mpt3sas_config.c b/drivers/scsi/mpt3sas/mpt3sas_config.c index e45c4613ef0c..a6914ec99cc0 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_config.c +++ b/drivers/scsi/mpt3sas/mpt3sas_config.c @@ -83,7 +83,6 @@ struct config_request { dma_addr_t page_dma; }; -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING /** * _config_display_some_debug - debug routine * @ioc: per adapter object @@ -173,7 +172,6 @@ _config_display_some_debug(struct MPT3SAS_ADAPTER *ioc, u16 smid, ioc->name, le16_to_cpu(mpi_reply->IOCStatus), le32_to_cpu(mpi_reply->IOCLogInfo)); } -#endif /** * _config_alloc_config_dma_memory - obtain physical memory @@ -255,9 +253,7 @@ mpt3sas_config_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, mpi_reply->MsgLength*4); } ioc->config_cmds.status &= ~MPT3_CMD_PENDING; -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING _config_display_some_debug(ioc, smid, "config_done", mpi_reply); -#endif ioc->config_cmds.smid = USHRT_MAX; complete(&ioc->config_cmds.done); return 1; @@ -387,9 +383,7 @@ _config_request(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigRequest_t config_request = mpt3sas_base_get_msg_frame(ioc, smid); ioc->config_cmds.smid = smid; memcpy(config_request, mpi_request, sizeof(Mpi2ConfigRequest_t)); -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING _config_display_some_debug(ioc, smid, "config_request", NULL); -#endif init_completion(&ioc->config_cmds.done); mpt3sas_base_put_smid_default(ioc, smid); timeleft = wait_for_completion_timeout(&ioc->config_cmds.done, @@ -872,6 +866,42 @@ mpt3sas_config_set_iounit_pg1(struct MPT3SAS_ADAPTER *ioc, } /** + * mpt3sas_config_get_iounit_pg3 - obtain iounit page 3 + * @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. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt3sas_config_get_iounit_pg3(struct MPT3SAS_ADAPTER *ioc, + Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage3_t *config_page, u16 sz) +{ + Mpi2ConfigRequest_t mpi_request; + int r; + + 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 = 3; + mpi_request.Header.PageVersion = MPI2_IOUNITPAGE3_PAGEVERSION; + ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); + if (r) + goto out; + + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz); + out: + return r; +} + +/** * mpt3sas_config_get_iounit_pg8 - obtain iounit page 8 * @ioc: per adapter object * @mpi_reply: reply mf payload returned from firmware diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.c b/drivers/scsi/mpt3sas/mpt3sas_ctl.c index 080c8a76d23d..d8366b056b70 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_ctl.c +++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.c @@ -78,7 +78,6 @@ enum block_state { BLOCKING, }; -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING /** * _ctl_sas_device_find_by_handle - sas device search * @ioc: per adapter object @@ -254,8 +253,6 @@ _ctl_display_some_debug(struct MPT3SAS_ADAPTER *ioc, u16 smid, } } -#endif - /** * mpt3sas_ctl_done - ctl module completion routine * @ioc: per adapter object @@ -302,9 +299,7 @@ mpt3sas_ctl_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, } } } -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING _ctl_display_some_debug(ioc, smid, "ctl_done", mpi_reply); -#endif ioc->ctl_cmds.status &= ~MPT3_CMD_PENDING; complete(&ioc->ctl_cmds.done); return 1; @@ -414,20 +409,31 @@ mpt3sas_ctl_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, * _ctl_verify_adapter - validates ioc_number passed from application * @ioc: per adapter object * @iocpp: The ioc pointer is returned in this. + * @mpi_version: will be MPI2_VERSION for mpt2ctl ioctl device & + * MPI25_VERSION for mpt3ctl ioctl device. * * Return (-1) means error, else ioc_number. */ static int -_ctl_verify_adapter(int ioc_number, struct MPT3SAS_ADAPTER **iocpp) +_ctl_verify_adapter(int ioc_number, struct MPT3SAS_ADAPTER **iocpp, + int mpi_version) { struct MPT3SAS_ADAPTER *ioc; - + /* global ioc lock to protect controller on list operations */ + spin_lock(&gioc_lock); list_for_each_entry(ioc, &mpt3sas_ioc_list, list) { if (ioc->id != ioc_number) continue; + /* Check whether this ioctl command is from right + * ioctl device or not, if not continue the search. + */ + if (ioc->hba_mpi_version_belonged != mpi_version) + continue; + spin_unlock(&gioc_lock); *iocpp = ioc; return ioc_number; } + spin_unlock(&gioc_lock); *iocpp = NULL; return -1; } @@ -497,7 +503,7 @@ mpt3sas_ctl_reset_handler(struct MPT3SAS_ADAPTER *ioc, int reset_phase) * * Called when application request fasyn callback handler. */ -static int +int _ctl_fasync(int fd, struct file *filep, int mode) { return fasync_helper(fd, filep, mode, &async_queue); @@ -509,17 +515,22 @@ _ctl_fasync(int fd, struct file *filep, int mode) * @wait - * */ -static unsigned int +unsigned int _ctl_poll(struct file *filep, poll_table *wait) { struct MPT3SAS_ADAPTER *ioc; poll_wait(filep, &ctl_poll_wait, wait); + /* global ioc lock to protect controller on list operations */ + spin_lock(&gioc_lock); list_for_each_entry(ioc, &mpt3sas_ioc_list, list) { - if (ioc->aen_event_read_flag) + if (ioc->aen_event_read_flag) { + spin_unlock(&gioc_lock); return POLLIN | POLLRDNORM; + } } + spin_unlock(&gioc_lock); return 0; } @@ -759,9 +770,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, psge = (void *)request + (karg.data_sge_offset*4); /* send command to firmware */ -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING _ctl_display_some_debug(ioc, smid, "ctl_request", NULL); -#endif init_completion(&ioc->ctl_cmds.done); switch (mpi_request->Function) { @@ -916,7 +925,6 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, mpi_reply = ioc->ctl_cmds.reply; ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK; -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING if (mpi_reply->Function == MPI2_FUNCTION_SCSI_TASK_MGMT && (ioc->logging_level & MPT_DEBUG_TM)) { Mpi2SCSITaskManagementReply_t *tm_reply = @@ -929,7 +937,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, le32_to_cpu(tm_reply->IOCLogInfo), le32_to_cpu(tm_reply->TerminationCount)); } -#endif + /* copy out xdata to user */ if (data_in_sz) { if (copy_to_user(karg.data_in_buf_ptr, data_in, @@ -1023,7 +1031,6 @@ _ctl_getiocinfo(struct MPT3SAS_ADAPTER *ioc, void __user *arg) __func__)); memset(&karg, 0 , sizeof(karg)); - karg.adapter_type = MPT3_IOCTL_INTERFACE_SAS3; if (ioc->pfacts) karg.port_number = ioc->pfacts[0].PortNumber; karg.hw_rev = ioc->pdev->revision; @@ -1035,9 +1042,21 @@ _ctl_getiocinfo(struct MPT3SAS_ADAPTER *ioc, void __user *arg) 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; - strcpy(karg.driver_version, MPT3SAS_DRIVER_NAME); + strcpy(karg.driver_version, ioc->driver_name); strcat(karg.driver_version, "-"); - strcat(karg.driver_version, MPT3SAS_DRIVER_VERSION); + switch (ioc->hba_mpi_version_belonged) { + case MPI2_VERSION: + if (ioc->is_warpdrive) + karg.adapter_type = MPT2_IOCTL_INTERFACE_SAS2_SSS6200; + else + karg.adapter_type = MPT2_IOCTL_INTERFACE_SAS2; + strcat(karg.driver_version, MPT2SAS_DRIVER_VERSION); + break; + case MPI25_VERSION: + karg.adapter_type = MPT3_IOCTL_INTERFACE_SAS3; + strcat(karg.driver_version, MPT3SAS_DRIVER_VERSION); + break; + } karg.bios_version = le32_to_cpu(ioc->bios_pg3.BiosVersion); if (copy_to_user(arg, &karg, sizeof(karg))) { @@ -2181,12 +2200,14 @@ _ctl_compat_mpt_command(struct MPT3SAS_ADAPTER *ioc, unsigned cmd, * _ctl_ioctl_main - main ioctl entry point * @file - (struct file) * @cmd - ioctl opcode - * @arg - - * compat - handles 32 bit applications in 64bit os + * @arg - user space data buffer + * @compat - handles 32 bit applications in 64bit os + * @mpi_version: will be MPI2_VERSION for mpt2ctl ioctl device & + * MPI25_VERSION for mpt3ctl ioctl device. */ static long _ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg, - u8 compat) + u8 compat, u16 mpi_version) { struct MPT3SAS_ADAPTER *ioc; struct mpt3_ioctl_header ioctl_header; @@ -2201,19 +2222,29 @@ _ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg, return -EFAULT; } - if (_ctl_verify_adapter(ioctl_header.ioc_number, &ioc) == -1 || !ioc) + if (_ctl_verify_adapter(ioctl_header.ioc_number, + &ioc, mpi_version) == -1 || !ioc) return -ENODEV; + /* pci_access_mutex lock acquired by ioctl path */ + mutex_lock(&ioc->pci_access_mutex); + if (ioc->shost_recovery || ioc->pci_error_recovery || - ioc->is_driver_loading) - return -EAGAIN; + ioc->is_driver_loading || ioc->remove_host) { + ret = -EAGAIN; + goto out_unlock_pciaccess; + } state = (file->f_flags & O_NONBLOCK) ? NON_BLOCKING : BLOCKING; if (state == NON_BLOCKING) { - if (!mutex_trylock(&ioc->ctl_cmds.mutex)) - return -EAGAIN; - } else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex)) - return -ERESTARTSYS; + if (!mutex_trylock(&ioc->ctl_cmds.mutex)) { + ret = -EAGAIN; + goto out_unlock_pciaccess; + } + } else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex)) { + ret = -ERESTARTSYS; + goto out_unlock_pciaccess; + } switch (cmd) { @@ -2294,39 +2325,78 @@ _ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg, } mutex_unlock(&ioc->ctl_cmds.mutex); +out_unlock_pciaccess: + mutex_unlock(&ioc->pci_access_mutex); return ret; } /** - * _ctl_ioctl - main ioctl entry point (unlocked) + * _ctl_ioctl - mpt3ctl main ioctl entry point (unlocked) * @file - (struct file) * @cmd - ioctl opcode * @arg - */ -static long +long _ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { long ret; - ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 0); + /* pass MPI25_VERSION value, to indicate that this ioctl cmd + * came from mpt3ctl ioctl device. + */ + ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 0, MPI25_VERSION); return ret; } +/** + * _ctl_mpt2_ioctl - mpt2ctl main ioctl entry point (unlocked) + * @file - (struct file) + * @cmd - ioctl opcode + * @arg - + */ +long +_ctl_mpt2_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + long ret; + + /* pass MPI2_VERSION value, to indicate that this ioctl cmd + * came from mpt2ctl ioctl device. + */ + ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 0, MPI2_VERSION); + return ret; +} #ifdef CONFIG_COMPAT /** - * _ctl_ioctl_compat - main ioctl entry point (compat) + *_ ctl_ioctl_compat - main ioctl entry point (compat) * @file - * @cmd - * @arg - * * This routine handles 32 bit applications in 64bit os. */ -static long +long _ctl_ioctl_compat(struct file *file, unsigned cmd, unsigned long arg) { long ret; - ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 1); + ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 1, MPI25_VERSION); + return ret; +} + +/** + *_ ctl_mpt2_ioctl_compat - main ioctl entry point (compat) + * @file - + * @cmd - + * @arg - + * + * This routine handles 32 bit applications in 64bit os. + */ +long +_ctl_mpt2_ioctl_compat(struct file *file, unsigned cmd, unsigned long arg) +{ + long ret; + + ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 1, MPI2_VERSION); return ret; } #endif @@ -2713,6 +2783,82 @@ _ctl_ioc_reply_queue_count_show(struct device *cdev, static DEVICE_ATTR(reply_queue_count, S_IRUGO, _ctl_ioc_reply_queue_count_show, NULL); +/** + * _ctl_BRM_status_show - Backup Rail Monitor Status + * @cdev - pointer to embedded class device + * @buf - the buffer returned + * + * This is number of reply queues + * + * A sysfs 'read-only' shost attribute. + */ +static ssize_t +_ctl_BRM_status_show(struct device *cdev, struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); + Mpi2IOUnitPage3_t *io_unit_pg3 = NULL; + Mpi2ConfigReply_t mpi_reply; + u16 backup_rail_monitor_status = 0; + u16 ioc_status; + int sz; + ssize_t rc = 0; + + if (!ioc->is_warpdrive) { + pr_err(MPT3SAS_FMT "%s: BRM attribute is only for" + " warpdrive\n", ioc->name, __func__); + goto out; + } + /* pci_access_mutex lock acquired by sysfs show path */ + mutex_lock(&ioc->pci_access_mutex); + if (ioc->pci_error_recovery || ioc->remove_host) { + mutex_unlock(&ioc->pci_access_mutex); + return 0; + } + + /* allocate upto GPIOVal 36 entries */ + sz = offsetof(Mpi2IOUnitPage3_t, GPIOVal) + (sizeof(u16) * 36); + io_unit_pg3 = kzalloc(sz, GFP_KERNEL); + if (!io_unit_pg3) { + pr_err(MPT3SAS_FMT "%s: failed allocating memory " + "for iounit_pg3: (%d) bytes\n", ioc->name, __func__, sz); + goto out; + } + + if (mpt3sas_config_get_iounit_pg3(ioc, &mpi_reply, io_unit_pg3, sz) != + 0) { + pr_err(MPT3SAS_FMT + "%s: failed reading iounit_pg3\n", ioc->name, + __func__); + goto out; + } + + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + pr_err(MPT3SAS_FMT "%s: iounit_pg3 failed with " + "ioc_status(0x%04x)\n", ioc->name, __func__, ioc_status); + goto out; + } + + if (io_unit_pg3->GPIOCount < 25) { + pr_err(MPT3SAS_FMT "%s: iounit_pg3->GPIOCount less than " + "25 entries, detected (%d) entries\n", ioc->name, __func__, + io_unit_pg3->GPIOCount); + goto out; + } + + /* BRM status is in bit zero of GPIOVal[24] */ + backup_rail_monitor_status = le16_to_cpu(io_unit_pg3->GPIOVal[24]); + rc = snprintf(buf, PAGE_SIZE, "%d\n", (backup_rail_monitor_status & 1)); + + out: + kfree(io_unit_pg3); + mutex_unlock(&ioc->pci_access_mutex); + return rc; +} +static DEVICE_ATTR(BRM_status, S_IRUGO, _ctl_BRM_status_show, NULL); + struct DIAG_BUFFER_START { __le32 Size; __le32 DiagVersion; @@ -3165,6 +3311,7 @@ struct device_attribute *mpt3sas_host_attrs[] = { &dev_attr_diag_trigger_event, &dev_attr_diag_trigger_scsi, &dev_attr_diag_trigger_mpi, + &dev_attr_BRM_status, NULL, }; @@ -3218,6 +3365,7 @@ struct device_attribute *mpt3sas_dev_attrs[] = { NULL, }; +/* file operations table for mpt3ctl device */ static const struct file_operations ctl_fops = { .owner = THIS_MODULE, .unlocked_ioctl = _ctl_ioctl, @@ -3228,23 +3376,53 @@ static const struct file_operations ctl_fops = { #endif }; +/* file operations table for mpt2ctl device */ +static const struct file_operations ctl_gen2_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = _ctl_mpt2_ioctl, + .poll = _ctl_poll, + .fasync = _ctl_fasync, +#ifdef CONFIG_COMPAT + .compat_ioctl = _ctl_mpt2_ioctl_compat, +#endif +}; + static struct miscdevice ctl_dev = { .minor = MPT3SAS_MINOR, .name = MPT3SAS_DEV_NAME, .fops = &ctl_fops, }; +static struct miscdevice gen2_ctl_dev = { + .minor = MPT2SAS_MINOR, + .name = MPT2SAS_DEV_NAME, + .fops = &ctl_gen2_fops, +}; + /** * mpt3sas_ctl_init - main entry point for ctl. * */ void -mpt3sas_ctl_init(void) +mpt3sas_ctl_init(ushort hbas_to_enumerate) { async_queue = NULL; - if (misc_register(&ctl_dev) < 0) - pr_err("%s can't register misc device [minor=%d]\n", - MPT3SAS_DRIVER_NAME, MPT3SAS_MINOR); + + /* Don't register mpt3ctl ioctl device if + * hbas_to_enumarate is one. + */ + if (hbas_to_enumerate != 1) + if (misc_register(&ctl_dev) < 0) + pr_err("%s can't register misc device [minor=%d]\n", + MPT3SAS_DRIVER_NAME, MPT3SAS_MINOR); + + /* Don't register mpt3ctl ioctl device if + * hbas_to_enumarate is two. + */ + if (hbas_to_enumerate != 2) + if (misc_register(&gen2_ctl_dev) < 0) + pr_err("%s can't register misc device [minor=%d]\n", + MPT2SAS_DRIVER_NAME, MPT2SAS_MINOR); init_waitqueue_head(&ctl_poll_wait); } @@ -3254,7 +3432,7 @@ mpt3sas_ctl_init(void) * */ void -mpt3sas_ctl_exit(void) +mpt3sas_ctl_exit(ushort hbas_to_enumerate) { struct MPT3SAS_ADAPTER *ioc; int i; @@ -3279,5 +3457,8 @@ mpt3sas_ctl_exit(void) kfree(ioc->event_log); } - misc_deregister(&ctl_dev); + if (hbas_to_enumerate != 1) + misc_deregister(&ctl_dev); + if (hbas_to_enumerate != 2) + misc_deregister(&gen2_ctl_dev); } diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.h b/drivers/scsi/mpt3sas/mpt3sas_ctl.h index aee99ce67e54..89408356d252 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_ctl.h +++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.h @@ -50,10 +50,13 @@ #include <linux/miscdevice.h> #endif - +#ifndef MPT2SAS_MINOR +#define MPT2SAS_MINOR (MPT_MINOR + 1) +#endif #ifndef MPT3SAS_MINOR #define MPT3SAS_MINOR (MPT_MINOR + 2) #endif +#define MPT2SAS_DEV_NAME "mpt2ctl" #define MPT3SAS_DEV_NAME "mpt3ctl" #define MPT3_MAGIC_NUMBER 'L' #define MPT3_IOCTL_DEFAULT_TIMEOUT (10) /* in seconds */ @@ -138,6 +141,7 @@ struct mpt3_ioctl_pci_info { #define MPT2_IOCTL_INTERFACE_FC_IP (0x02) #define MPT2_IOCTL_INTERFACE_SAS (0x03) #define MPT2_IOCTL_INTERFACE_SAS2 (0x04) +#define MPT2_IOCTL_INTERFACE_SAS2_SSS6200 (0x05) #define MPT3_IOCTL_INTERFACE_SAS3 (0x06) #define MPT2_IOCTL_VERSION_LENGTH (32) diff --git a/drivers/scsi/mpt3sas/mpt3sas_debug.h b/drivers/scsi/mpt3sas/mpt3sas_debug.h index 4e8a63fdb304..cceeb2c16e64 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_debug.h +++ b/drivers/scsi/mpt3sas/mpt3sas_debug.h @@ -68,20 +68,11 @@ #define MPT_DEBUG_TRIGGER_DIAG 0x00200000 -/* - * CONFIG_SCSI_MPT3SAS_LOGGING - enabled in Kconfig - */ - -#ifdef CONFIG_SCSI_MPT3SAS_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_MPT3SAS_LOGGING */ - /* * debug macros @@ -153,7 +144,7 @@ /* inline functions for dumping debug data*/ -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING + /** * _debug_dump_mf - print message frame contents * @mpi_request: pointer to message frame @@ -211,10 +202,5 @@ _debug_dump_config(void *mpi_request, int sz) } pr_info("\n"); } -#else -#define _debug_dump_mf(mpi_request, sz) -#define _debug_dump_reply(mpi_request, sz) -#define _debug_dump_config(mpi_request, sz) -#endif /* CONFIG_SCSI_MPT3SAS_LOGGING */ #endif /* MPT3SAS_DEBUG_H_INCLUDED */ diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index 8ccef38523fa..d95206b7e116 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -54,14 +54,10 @@ #include <linux/interrupt.h> #include <linux/aer.h> #include <linux/raid_class.h> +#include <asm/unaligned.h> #include "mpt3sas_base.h" -MODULE_AUTHOR(MPT3SAS_AUTHOR); -MODULE_DESCRIPTION(MPT3SAS_DESCRIPTION); -MODULE_LICENSE("GPL"); -MODULE_VERSION(MPT3SAS_DRIVER_VERSION); - #define RAID_CHANNEL 1 /* forward proto's */ static void _scsih_expander_node_remove(struct MPT3SAS_ADAPTER *ioc, @@ -75,11 +71,16 @@ static int _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, static u8 _scsih_check_for_pending_tm(struct MPT3SAS_ADAPTER *ioc, u16 smid); -static void _scsih_scan_start(struct Scsi_Host *shost); -static int _scsih_scan_finished(struct Scsi_Host *shost, unsigned long time); - /* global parameters */ LIST_HEAD(mpt3sas_ioc_list); +/* global ioc lock for list operations */ +DEFINE_SPINLOCK(gioc_lock); + +MODULE_AUTHOR(MPT3SAS_AUTHOR); +MODULE_DESCRIPTION(MPT3SAS_DESCRIPTION); +MODULE_LICENSE("GPL"); +MODULE_VERSION(MPT3SAS_DRIVER_VERSION); +MODULE_ALIAS("mpt2sas"); /* local parameters */ static u8 scsi_io_cb_idx = -1; @@ -90,7 +91,8 @@ static u8 port_enable_cb_idx = -1; static u8 transport_cb_idx = -1; static u8 scsih_cb_idx = -1; static u8 config_cb_idx = -1; -static int mpt_ids; +static int mpt2_ids; +static int mpt3_ids; static u8 tm_tr_cb_idx = -1 ; static u8 tm_tr_volume_cb_idx = -1 ; @@ -117,8 +119,12 @@ static u64 max_lun = MPT3SAS_MAX_LUN; module_param(max_lun, ullong, 0); MODULE_PARM_DESC(max_lun, " max lun, default=16895 "); - - +static ushort hbas_to_enumerate; +module_param(hbas_to_enumerate, ushort, 0); +MODULE_PARM_DESC(hbas_to_enumerate, + " 0 - enumerates both SAS 2.0 & SAS 3.0 generation HBAs\n \ + 1 - enumerates only SAS 2.0 generation HBAs\n \ + 2 - enumerates only SAS 3.0 generation HBAs (default=0)"); /* diag_buffer_enable is bitwise * bit 0 set = TRACE @@ -143,8 +149,8 @@ MODULE_PARM_DESC(prot_mask, " host protection capabilities mask, def=7 "); /* raid transport support */ - -static struct raid_template *mpt3sas_raid_template; +struct raid_template *mpt3sas_raid_template; +struct raid_template *mpt2sas_raid_template; /** @@ -191,11 +197,36 @@ struct fw_event_work { u8 VP_ID; u8 ignore; u16 event; + struct kref refcount; char event_data[0] __aligned(4); }; -/* raid transport support */ -static struct raid_template *mpt3sas_raid_template; +static void fw_event_work_free(struct kref *r) +{ + kfree(container_of(r, struct fw_event_work, refcount)); +} + +static void fw_event_work_get(struct fw_event_work *fw_work) +{ + kref_get(&fw_work->refcount); +} + +static void fw_event_work_put(struct fw_event_work *fw_work) +{ + kref_put(&fw_work->refcount, fw_event_work_free); +} + +static struct fw_event_work *alloc_fw_event_work(int len) +{ + struct fw_event_work *fw_event; + + fw_event = kzalloc(sizeof(*fw_event) + len, GFP_ATOMIC); + if (!fw_event) + return NULL; + + kref_init(&fw_event->refcount); + return fw_event; +} /** * struct _scsi_io_transfer - scsi io transfer @@ -245,28 +276,6 @@ struct _scsi_io_transfer { u32 transfer_length; }; -/* - * The pci device ids are defined in mpi/mpi2_cnfg.h. - */ -static const struct pci_device_id scsih_pci_table[] = { - /* Fury ~ 3004 and 3008 */ - { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3004, - PCI_ANY_ID, PCI_ANY_ID }, - { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3008, - PCI_ANY_ID, PCI_ANY_ID }, - /* Invader ~ 3108 */ - { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_1, - PCI_ANY_ID, PCI_ANY_ID }, - { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_2, - PCI_ANY_ID, PCI_ANY_ID }, - { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_5, - PCI_ANY_ID, PCI_ANY_ID }, - { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_6, - 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. * @@ -282,8 +291,10 @@ _scsih_set_debug_level(const char *val, struct kernel_param *kp) return ret; pr_info("setting logging_level(0x%08x)\n", logging_level); + spin_lock(&gioc_lock); list_for_each_entry(ioc, &mpt3sas_ioc_list, list) ioc->logging_level = logging_level; + spin_unlock(&gioc_lock); return 0; } module_param_call(logging_level, _scsih_set_debug_level, param_get_int, @@ -518,8 +529,61 @@ _scsih_determine_boot_device(struct MPT3SAS_ADAPTER *ioc, } } +static struct _sas_device * +__mpt3sas_get_sdev_from_target(struct MPT3SAS_ADAPTER *ioc, + struct MPT3SAS_TARGET *tgt_priv) +{ + struct _sas_device *ret; + + assert_spin_locked(&ioc->sas_device_lock); + + ret = tgt_priv->sdev; + if (ret) + sas_device_get(ret); + + return ret; +} + +static struct _sas_device * +mpt3sas_get_sdev_from_target(struct MPT3SAS_ADAPTER *ioc, + struct MPT3SAS_TARGET *tgt_priv) +{ + struct _sas_device *ret; + unsigned long flags; + + spin_lock_irqsave(&ioc->sas_device_lock, flags); + ret = __mpt3sas_get_sdev_from_target(ioc, tgt_priv); + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + + return ret; +} + + +struct _sas_device * +__mpt3sas_get_sdev_by_addr(struct MPT3SAS_ADAPTER *ioc, + u64 sas_address) +{ + struct _sas_device *sas_device; + + assert_spin_locked(&ioc->sas_device_lock); + + list_for_each_entry(sas_device, &ioc->sas_device_list, list) + if (sas_device->sas_address == sas_address) + goto found_device; + + list_for_each_entry(sas_device, &ioc->sas_device_init_list, list) + if (sas_device->sas_address == sas_address) + goto found_device; + + return NULL; + +found_device: + sas_device_get(sas_device); + return sas_device; +} + /** - * mpt3sas_scsih_sas_device_find_by_sas_address - sas device search + * mpt3sas_get_sdev_by_addr - sas device search * @ioc: per adapter object * @sas_address: sas address * Context: Calling function should acquire ioc->sas_device_lock @@ -528,24 +592,44 @@ _scsih_determine_boot_device(struct MPT3SAS_ADAPTER *ioc, * object. */ struct _sas_device * -mpt3sas_scsih_sas_device_find_by_sas_address(struct MPT3SAS_ADAPTER *ioc, +mpt3sas_get_sdev_by_addr(struct MPT3SAS_ADAPTER *ioc, u64 sas_address) { struct _sas_device *sas_device; + unsigned long flags; + + spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_device = __mpt3sas_get_sdev_by_addr(ioc, + sas_address); + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + + return sas_device; +} + +static struct _sas_device * +__mpt3sas_get_sdev_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle) +{ + struct _sas_device *sas_device; + + assert_spin_locked(&ioc->sas_device_lock); list_for_each_entry(sas_device, &ioc->sas_device_list, list) - if (sas_device->sas_address == sas_address) - return sas_device; + if (sas_device->handle == handle) + goto found_device; list_for_each_entry(sas_device, &ioc->sas_device_init_list, list) - if (sas_device->sas_address == sas_address) - return sas_device; + if (sas_device->handle == handle) + goto found_device; return NULL; + +found_device: + sas_device_get(sas_device); + return sas_device; } /** - * _scsih_sas_device_find_by_handle - sas device search + * mpt3sas_get_sdev_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 @@ -554,19 +638,16 @@ mpt3sas_scsih_sas_device_find_by_sas_address(struct MPT3SAS_ADAPTER *ioc, * object. */ static struct _sas_device * -_scsih_sas_device_find_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle) +mpt3sas_get_sdev_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle) { struct _sas_device *sas_device; + unsigned long flags; - list_for_each_entry(sas_device, &ioc->sas_device_list, list) - if (sas_device->handle == handle) - return sas_device; - - list_for_each_entry(sas_device, &ioc->sas_device_init_list, list) - if (sas_device->handle == handle) - return sas_device; + spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_device = __mpt3sas_get_sdev_by_handle(ioc, handle); + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - return NULL; + return sas_device; } /** @@ -575,7 +656,7 @@ _scsih_sas_device_find_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle) * @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. + * If sas_device is on the list, remove it and decrement its reference count. */ static void _scsih_sas_device_remove(struct MPT3SAS_ADAPTER *ioc, @@ -602,9 +683,15 @@ _scsih_sas_device_remove(struct MPT3SAS_ADAPTER *ioc, ioc->name, sas_device->enclosure_level, sas_device->connector_name); + /* + * The lock serializes access to the list, but we still need to verify + * that nobody removed the entry while we were waiting on the lock. + */ spin_lock_irqsave(&ioc->sas_device_lock, flags); - list_del(&sas_device->list); - kfree(sas_device); + if (!list_empty(&sas_device->list)) { + list_del_init(&sas_device->list); + sas_device_put(sas_device); + } spin_unlock_irqrestore(&ioc->sas_device_lock, flags); } @@ -625,12 +712,16 @@ _scsih_device_remove_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle) return; spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = _scsih_sas_device_find_by_handle(ioc, handle); - if (sas_device) - list_del(&sas_device->list); + sas_device = __mpt3sas_get_sdev_by_handle(ioc, handle); + if (sas_device) { + list_del_init(&sas_device->list); + sas_device_put(sas_device); + } spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - if (sas_device) + if (sas_device) { _scsih_remove_device(ioc, sas_device); + sas_device_put(sas_device); + } } /** @@ -651,13 +742,16 @@ mpt3sas_device_remove_by_sas_address(struct MPT3SAS_ADAPTER *ioc, return; spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc, - sas_address); - if (sas_device) - list_del(&sas_device->list); + sas_device = __mpt3sas_get_sdev_by_addr(ioc, sas_address); + if (sas_device) { + list_del_init(&sas_device->list); + sas_device_put(sas_device); + } spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - if (sas_device) + if (sas_device) { _scsih_remove_device(ioc, sas_device); + sas_device_put(sas_device); + } } /** @@ -692,6 +786,7 @@ _scsih_sas_device_add(struct MPT3SAS_ADAPTER *ioc, sas_device->enclosure_level, sas_device->connector_name)); spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_device_get(sas_device); list_add_tail(&sas_device->list, &ioc->sas_device_list); spin_unlock_irqrestore(&ioc->sas_device_lock, flags); @@ -745,6 +840,7 @@ _scsih_sas_device_init_add(struct MPT3SAS_ADAPTER *ioc, sas_device->connector_name)); spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_device_get(sas_device); list_add_tail(&sas_device->list, &ioc->sas_device_init_list); _scsih_determine_boot_device(ioc, sas_device, 0); spin_unlock_irqrestore(&ioc->sas_device_lock, flags); @@ -778,7 +874,7 @@ _scsih_raid_device_find_by_id(struct MPT3SAS_ADAPTER *ioc, int id, int channel) } /** - * _scsih_raid_device_find_by_handle - raid device search + * mpt3sas_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 @@ -786,8 +882,8 @@ _scsih_raid_device_find_by_id(struct MPT3SAS_ADAPTER *ioc, int id, int channel) * This searches for raid_device based on handle, then return raid_device * object. */ -static struct _raid_device * -_scsih_raid_device_find_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle) +struct _raid_device * +mpt3sas_raid_device_find_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle) { struct _raid_device *raid_device, *r; @@ -1095,14 +1191,14 @@ _scsih_scsi_lookup_find_by_lun(struct MPT3SAS_ADAPTER *ioc, int id, } /** - * _scsih_change_queue_depth - setting device queue depth + * 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) +int +scsih_change_queue_depth(struct scsi_device *sdev, int qdepth) { struct Scsi_Host *shost = sdev->host; int max_depth; @@ -1123,12 +1219,15 @@ _scsih_change_queue_depth(struct scsi_device *sdev, int qdepth) goto not_sata; if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) goto not_sata; + spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc, - sas_device_priv_data->sas_target->sas_address); - if (sas_device && sas_device->device_info & - MPI2_SAS_DEVICE_INFO_SATA_DEVICE) - max_depth = MPT3SAS_SATA_QUEUE_DEPTH; + sas_device = __mpt3sas_get_sdev_from_target(ioc, sas_target_priv_data); + if (sas_device) { + if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE) + max_depth = MPT3SAS_SATA_QUEUE_DEPTH; + + sas_device_put(sas_device); + } spin_unlock_irqrestore(&ioc->sas_device_lock, flags); not_sata: @@ -1141,14 +1240,14 @@ _scsih_change_queue_depth(struct scsi_device *sdev, int qdepth) } /** - * _scsih_target_alloc - target add routine + * 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) +int +scsih_target_alloc(struct scsi_target *starget) { struct Scsi_Host *shost = dev_to_shost(&starget->dev); struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); @@ -1176,7 +1275,9 @@ _scsih_target_alloc(struct scsi_target *starget) 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; + sas_target_priv_data->raid_device = raid_device; + if (ioc->is_warpdrive) + raid_device->starget = starget; } spin_unlock_irqrestore(&ioc->raid_device_lock, flags); return 0; @@ -1185,12 +1286,13 @@ _scsih_target_alloc(struct scsi_target *starget) /* sas/sata devices */ spin_lock_irqsave(&ioc->sas_device_lock, flags); rphy = dev_to_rphy(starget->dev.parent); - sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc, + sas_device = __mpt3sas_get_sdev_by_addr(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_target_priv_data->sdev = sas_device; sas_device->starget = starget; sas_device->id = starget->id; sas_device->channel = starget->channel; @@ -1206,13 +1308,13 @@ _scsih_target_alloc(struct scsi_target *starget) } /** - * _scsih_target_destroy - target destroy routine + * scsih_target_destroy - target destroy routine * @starget: scsi target struct * * Returns nothing. */ -static void -_scsih_target_destroy(struct scsi_target *starget) +void +scsih_target_destroy(struct scsi_target *starget) { struct Scsi_Host *shost = dev_to_shost(&starget->dev); struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); @@ -1240,13 +1342,21 @@ _scsih_target_destroy(struct scsi_target *starget) spin_lock_irqsave(&ioc->sas_device_lock, flags); rphy = dev_to_rphy(starget->dev.parent); - sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc, - rphy->identify.sas_address); + sas_device = __mpt3sas_get_sdev_from_target(ioc, sas_target_priv_data); if (sas_device && (sas_device->starget == starget) && (sas_device->id == starget->id) && (sas_device->channel == starget->channel)) sas_device->starget = NULL; + if (sas_device) { + /* + * Corresponding get() is in _scsih_target_alloc() + */ + sas_target_priv_data->sdev = NULL; + sas_device_put(sas_device); + + sas_device_put(sas_device); + } spin_unlock_irqrestore(&ioc->sas_device_lock, flags); out: @@ -1255,14 +1365,14 @@ _scsih_target_destroy(struct scsi_target *starget) } /** - * _scsih_slave_alloc - device add routine + * 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) +int +scsih_slave_alloc(struct scsi_device *sdev) { struct Scsi_Host *shost; struct MPT3SAS_ADAPTER *ioc; @@ -1302,14 +1412,18 @@ _scsih_slave_alloc(struct scsi_device *sdev) if (!(sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) { spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc, + sas_device = __mpt3sas_get_sdev_by_addr(ioc, sas_target_priv_data->sas_address); if (sas_device && (sas_device->starget == NULL)) { sdev_printk(KERN_INFO, sdev, "%s : sas_device->starget set to starget @ %d\n", - __func__, __LINE__); + __func__, __LINE__); sas_device->starget = starget; } + + if (sas_device) + sas_device_put(sas_device); + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); } @@ -1317,13 +1431,13 @@ _scsih_slave_alloc(struct scsi_device *sdev) } /** - * _scsih_slave_destroy - device destroy routine + * scsih_slave_destroy - device destroy routine * @sdev: scsi device struct * * Returns nothing. */ -static void -_scsih_slave_destroy(struct scsi_device *sdev) +void +scsih_slave_destroy(struct scsi_device *sdev) { struct MPT3SAS_TARGET *sas_target_priv_data; struct scsi_target *starget; @@ -1344,10 +1458,13 @@ _scsih_slave_destroy(struct scsi_device *sdev) if (!(sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) { spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc, - sas_target_priv_data->sas_address); + sas_device = __mpt3sas_get_sdev_from_target(ioc, + sas_target_priv_data); if (sas_device && !sas_target_priv_data->num_luns) sas_device->starget = NULL; + + if (sas_device) + sas_device_put(sas_device); spin_unlock_irqrestore(&ioc->sas_device_lock, flags); } @@ -1409,23 +1526,26 @@ _scsih_display_sata_capabilities(struct MPT3SAS_ADAPTER *ioc, */ /** - * _scsih_is_raid - return boolean indicating device is raid volume + * scsih_is_raid - return boolean indicating device is raid volume * @dev the device struct object */ -static int -_scsih_is_raid(struct device *dev) +int +scsih_is_raid(struct device *dev) { struct scsi_device *sdev = to_scsi_device(dev); + struct MPT3SAS_ADAPTER *ioc = shost_priv(sdev->host); + if (ioc->is_warpdrive) + return 0; return (sdev->channel == RAID_CHANNEL) ? 1 : 0; } /** - * _scsih_get_resync - get raid volume resync percent complete + * scsih_get_resync - get raid volume resync percent complete * @dev the device struct object */ -static void -_scsih_get_resync(struct device *dev) +void +scsih_get_resync(struct device *dev) { struct scsi_device *sdev = to_scsi_device(dev); struct MPT3SAS_ADAPTER *ioc = shost_priv(sdev->host); @@ -1439,6 +1559,9 @@ _scsih_get_resync(struct device *dev) percent_complete = 0; handle = 0; + if (ioc->is_warpdrive) + goto out; + spin_lock_irqsave(&ioc->raid_device_lock, flags); raid_device = _scsih_raid_device_find_by_id(ioc, sdev->id, sdev->channel); @@ -1466,15 +1589,18 @@ _scsih_get_resync(struct device *dev) percent_complete = 0; out: - raid_set_resync(mpt3sas_raid_template, dev, percent_complete); + if (ioc->hba_mpi_version_belonged == MPI2_VERSION) + raid_set_resync(mpt2sas_raid_template, dev, percent_complete); + if (ioc->hba_mpi_version_belonged == MPI25_VERSION) + raid_set_resync(mpt3sas_raid_template, dev, percent_complete); } /** - * _scsih_get_state - get raid volume level + * scsih_get_state - get raid volume level * @dev the device struct object */ -static void -_scsih_get_state(struct device *dev) +void +scsih_get_state(struct device *dev) { struct scsi_device *sdev = to_scsi_device(dev); struct MPT3SAS_ADAPTER *ioc = shost_priv(sdev->host); @@ -1524,7 +1650,10 @@ _scsih_get_state(struct device *dev) break; } out: - raid_set_state(mpt3sas_raid_template, dev, state); + if (ioc->hba_mpi_version_belonged == MPI2_VERSION) + raid_set_state(mpt2sas_raid_template, dev, state); + if (ioc->hba_mpi_version_belonged == MPI25_VERSION) + raid_set_state(mpt3sas_raid_template, dev, state); } /** @@ -1533,7 +1662,8 @@ _scsih_get_state(struct device *dev) * @volume_type: volume type */ static void -_scsih_set_level(struct scsi_device *sdev, u8 volume_type) +_scsih_set_level(struct MPT3SAS_ADAPTER *ioc, + struct scsi_device *sdev, u8 volume_type) { enum raid_level level = RAID_LEVEL_UNKNOWN; @@ -1552,7 +1682,12 @@ _scsih_set_level(struct scsi_device *sdev, u8 volume_type) break; } - raid_set_level(mpt3sas_raid_template, &sdev->sdev_gendev, level); + if (ioc->hba_mpi_version_belonged == MPI2_VERSION) + raid_set_level(mpt2sas_raid_template, + &sdev->sdev_gendev, level); + if (ioc->hba_mpi_version_belonged == MPI25_VERSION) + raid_set_level(mpt3sas_raid_template, + &sdev->sdev_gendev, level); } @@ -1622,8 +1757,6 @@ _scsih_get_volume_capabilities(struct MPT3SAS_ADAPTER *ioc, return 0; } - - /** * _scsih_enable_tlr - setting TLR flags * @ioc: per adapter object @@ -1652,14 +1785,14 @@ _scsih_enable_tlr(struct MPT3SAS_ADAPTER *ioc, struct scsi_device *sdev) } /** - * _scsih_slave_configure - device configure routine. + * 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) +int +scsih_slave_configure(struct scsi_device *sdev) { struct Scsi_Host *shost = sdev->host; struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); @@ -1686,7 +1819,7 @@ _scsih_slave_configure(struct scsi_device *sdev) 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, handle); + raid_device = mpt3sas_raid_device_find_by_handle(ioc, handle); spin_unlock_irqrestore(&ioc->raid_device_lock, flags); if (!raid_device) { dfailprintk(ioc, pr_warn(MPT3SAS_FMT @@ -1702,6 +1835,10 @@ _scsih_slave_configure(struct scsi_device *sdev) return 1; } + /* + * WARPDRIVE: Initialize the required data for Direct IO + */ + mpt3sas_init_warpdrive_properties(ioc, raid_device); /* RAID Queue Depth Support * IS volume = underlying qdepth of drive type, either @@ -1750,17 +1887,19 @@ _scsih_slave_configure(struct scsi_device *sdev) 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); - + if (!ioc->hide_ir_msg) + 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); + scsih_change_queue_depth(sdev, qdepth); -/* raid transport support */ - _scsih_set_level(sdev, raid_device->volume_type); + /* raid transport support */ + if (!ioc->is_warpdrive) + _scsih_set_level(ioc, sdev, raid_device->volume_type); return 0; } @@ -1783,7 +1922,7 @@ _scsih_slave_configure(struct scsi_device *sdev) } spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc, + sas_device = __mpt3sas_get_sdev_by_addr(ioc, sas_device_priv_data->sas_target->sas_address); if (!sas_device) { spin_unlock_irqrestore(&ioc->sas_device_lock, flags); @@ -1823,13 +1962,14 @@ _scsih_slave_configure(struct scsi_device *sdev) ds, sas_device->enclosure_level, sas_device->connector_name); + sas_device_put(sas_device); spin_unlock_irqrestore(&ioc->sas_device_lock, flags); if (!ssp_target) _scsih_display_sata_capabilities(ioc, handle, sdev); - _scsih_change_queue_depth(sdev, qdepth); + scsih_change_queue_depth(sdev, qdepth); if (ssp_target) { sas_read_port_mode_page(sdev); @@ -1840,7 +1980,7 @@ _scsih_slave_configure(struct scsi_device *sdev) } /** - * _scsih_bios_param - fetch head, sector, cylinder info for a disk + * 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) @@ -1851,8 +1991,8 @@ _scsih_slave_configure(struct scsi_device *sdev) * * Return nothing. */ -static int -_scsih_bios_param(struct scsi_device *sdev, struct block_device *bdev, +int +scsih_bios_param(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int params[]) { int heads; @@ -2209,7 +2349,10 @@ _scsih_tm_display_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd) if (!priv_target) return; - device_str = "volume"; + if (ioc->hide_ir_msg) + device_str = "WarpDrive"; + else + device_str = "volume"; scsi_print_command(scmd); if (priv_target->flags & MPT_TARGET_FLAGS_VOLUME) { @@ -2219,8 +2362,7 @@ _scsih_tm_display_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd) device_str, (unsigned long long)priv_target->sas_address); } else { spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc, - priv_target->sas_address); + sas_device = __mpt3sas_get_sdev_from_target(ioc, priv_target); if (sas_device) { if (priv_target->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) { @@ -2246,19 +2388,21 @@ _scsih_tm_display_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd) "enclosure level(0x%04x),connector name(%s)\n", sas_device->enclosure_level, sas_device->connector_name); + + sas_device_put(sas_device); } spin_unlock_irqrestore(&ioc->sas_device_lock, flags); } } /** - * _scsih_abort - eh threads main abort routine + * scsih_abort - eh threads main abort routine * @scmd: pointer to scsi command object * * Returns SUCCESS if command aborted else FAILED */ -static int -_scsih_abort(struct scsi_cmnd *scmd) +int +scsih_abort(struct scsi_cmnd *scmd) { struct MPT3SAS_ADAPTER *ioc = shost_priv(scmd->device->host); struct MPT3SAS_DEVICE *sas_device_priv_data; @@ -2311,21 +2455,23 @@ _scsih_abort(struct scsi_cmnd *scmd) } /** - * _scsih_dev_reset - eh threads main device reset routine + * scsih_dev_reset - eh threads main device reset routine * @scmd: pointer to scsi command object * * Returns SUCCESS if command aborted else FAILED */ -static int -_scsih_dev_reset(struct scsi_cmnd *scmd) +int +scsih_dev_reset(struct scsi_cmnd *scmd) { struct MPT3SAS_ADAPTER *ioc = shost_priv(scmd->device->host); struct MPT3SAS_DEVICE *sas_device_priv_data; - struct _sas_device *sas_device; - unsigned long flags; + struct _sas_device *sas_device = NULL; u16 handle; int r; + struct scsi_target *starget = scmd->device->sdev_target; + struct MPT3SAS_TARGET *target_priv_data = starget->hostdata; + sdev_printk(KERN_INFO, scmd->device, "attempting device reset! scmd(%p)\n", scmd); _scsih_tm_display_info(ioc, scmd); @@ -2344,12 +2490,10 @@ _scsih_dev_reset(struct scsi_cmnd *scmd) 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); + sas_device = mpt3sas_get_sdev_from_target(ioc, + target_priv_data); 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; @@ -2366,25 +2510,29 @@ _scsih_dev_reset(struct scsi_cmnd *scmd) out: sdev_printk(KERN_INFO, scmd->device, "device reset: %s scmd(%p)\n", ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); + + if (sas_device) + sas_device_put(sas_device); + return r; } /** - * _scsih_target_reset - eh threads main target reset routine + * scsih_target_reset - eh threads main target reset routine * @scmd: pointer to scsi command object * * Returns SUCCESS if command aborted else FAILED */ -static int -_scsih_target_reset(struct scsi_cmnd *scmd) +int +scsih_target_reset(struct scsi_cmnd *scmd) { struct MPT3SAS_ADAPTER *ioc = shost_priv(scmd->device->host); struct MPT3SAS_DEVICE *sas_device_priv_data; - struct _sas_device *sas_device; - unsigned long flags; + struct _sas_device *sas_device = NULL; u16 handle; int r; struct scsi_target *starget = scmd->device->sdev_target; + struct MPT3SAS_TARGET *target_priv_data = starget->hostdata; starget_printk(KERN_INFO, starget, "attempting target reset! scmd(%p)\n", scmd); @@ -2404,12 +2552,10 @@ _scsih_target_reset(struct scsi_cmnd *scmd) 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); + sas_device = mpt3sas_get_sdev_from_target(ioc, + target_priv_data); 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; @@ -2426,18 +2572,22 @@ _scsih_target_reset(struct scsi_cmnd *scmd) out: starget_printk(KERN_INFO, starget, "target reset: %s scmd(%p)\n", ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); + + if (sas_device) + sas_device_put(sas_device); + return r; } /** - * _scsih_host_reset - eh threads main host reset routine + * scsih_host_reset - eh threads main host reset routine * @scmd: pointer to scsi command object * * Returns SUCCESS if command aborted else FAILED */ -static int -_scsih_host_reset(struct scsi_cmnd *scmd) +int +scsih_host_reset(struct scsi_cmnd *scmd) { struct MPT3SAS_ADAPTER *ioc = shost_priv(scmd->device->host); int r, retval; @@ -2483,32 +2633,36 @@ _scsih_fw_event_add(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work *fw_event) return; spin_lock_irqsave(&ioc->fw_event_lock, flags); + fw_event_work_get(fw_event); INIT_LIST_HEAD(&fw_event->list); list_add_tail(&fw_event->list, &ioc->fw_event_list); INIT_WORK(&fw_event->work, _firmware_event_work); + fw_event_work_get(fw_event); queue_work(ioc->firmware_event_thread, &fw_event->work); spin_unlock_irqrestore(&ioc->fw_event_lock, flags); } /** - * _scsih_fw_event_free - delete fw_event + * _scsih_fw_event_del_from_list - delete fw_event from the list * @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. + * If the fw_event is on the fw_event_list, remove it and do a put. * * Return nothing. */ static void -_scsih_fw_event_free(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work +_scsih_fw_event_del_from_list(struct MPT3SAS_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); + if (!list_empty(&fw_event->list)) { + list_del_init(&fw_event->list); + fw_event_work_put(fw_event); + } spin_unlock_irqrestore(&ioc->fw_event_lock, flags); } @@ -2525,17 +2679,19 @@ mpt3sas_send_trigger_data_event(struct MPT3SAS_ADAPTER *ioc, struct SL_WH_TRIGGERS_EVENT_DATA_T *event_data) { struct fw_event_work *fw_event; + u16 sz; if (ioc->is_driver_loading) return; - fw_event = kzalloc(sizeof(*fw_event) + sizeof(*event_data), - GFP_ATOMIC); + sz = sizeof(*event_data); + fw_event = alloc_fw_event_work(sz); if (!fw_event) return; fw_event->event = MPT3SAS_PROCESS_TRIGGER_DIAG; fw_event->ioc = ioc; memcpy(fw_event->event_data, event_data, sizeof(*event_data)); _scsih_fw_event_add(ioc, fw_event); + fw_event_work_put(fw_event); } /** @@ -2551,12 +2707,13 @@ _scsih_error_recovery_delete_devices(struct MPT3SAS_ADAPTER *ioc) if (ioc->is_driver_loading) return; - fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC); + fw_event = alloc_fw_event_work(0); if (!fw_event) return; fw_event->event = MPT3SAS_REMOVE_UNRESPONDING_DEVICES; fw_event->ioc = ioc; _scsih_fw_event_add(ioc, fw_event); + fw_event_work_put(fw_event); } /** @@ -2570,12 +2727,29 @@ mpt3sas_port_enable_complete(struct MPT3SAS_ADAPTER *ioc) { struct fw_event_work *fw_event; - fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC); + fw_event = alloc_fw_event_work(0); if (!fw_event) return; fw_event->event = MPT3SAS_PORT_ENABLE_COMPLETE; fw_event->ioc = ioc; _scsih_fw_event_add(ioc, fw_event); + fw_event_work_put(fw_event); +} + +static struct fw_event_work *dequeue_next_fw_event(struct MPT3SAS_ADAPTER *ioc) +{ + unsigned long flags; + struct fw_event_work *fw_event = NULL; + + spin_lock_irqsave(&ioc->fw_event_lock, flags); + if (!list_empty(&ioc->fw_event_list)) { + fw_event = list_first_entry(&ioc->fw_event_list, + struct fw_event_work, list); + list_del_init(&fw_event->list); + } + spin_unlock_irqrestore(&ioc->fw_event_lock, flags); + + return fw_event; } /** @@ -2590,17 +2764,25 @@ mpt3sas_port_enable_complete(struct MPT3SAS_ADAPTER *ioc) static void _scsih_fw_event_cleanup_queue(struct MPT3SAS_ADAPTER *ioc) { - struct fw_event_work *fw_event, *next; + struct fw_event_work *fw_event; if (list_empty(&ioc->fw_event_list) || !ioc->firmware_event_thread || in_interrupt()) return; - list_for_each_entry_safe(fw_event, next, &ioc->fw_event_list, list) { - if (cancel_delayed_work_sync(&fw_event->delayed_work)) { - _scsih_fw_event_free(ioc, fw_event); - continue; - } + while ((fw_event = dequeue_next_fw_event(ioc))) { + /* + * Wait on the fw_event to complete. If this returns 1, then + * the event was never executed, and we need a put for the + * reference the delayed_work had on the fw_event. + * + * If it did execute, we wait for it to finish, and the put will + * happen from _firmware_event_work() + */ + if (cancel_delayed_work_sync(&fw_event->delayed_work)) + fw_event_work_put(fw_event); + + fw_event_work_put(fw_event); } } @@ -2763,7 +2945,7 @@ _scsih_block_io_device(struct MPT3SAS_ADAPTER *ioc, u16 handle) struct scsi_device *sdev; struct _sas_device *sas_device; - sas_device = _scsih_sas_device_find_by_handle(ioc, handle); + sas_device = mpt3sas_get_sdev_by_handle(ioc, handle); if (!sas_device) return; @@ -2779,6 +2961,8 @@ _scsih_block_io_device(struct MPT3SAS_ADAPTER *ioc, u16 handle) continue; _scsih_internal_device_block(sdev, sas_device_priv_data); } + + sas_device_put(sas_device); } /** @@ -2807,12 +2991,13 @@ _scsih_block_io_to_children_attached_to_ex(struct MPT3SAS_ADAPTER *ioc, if (mpt3sas_port->remote_identify.device_type == SAS_END_DEVICE) { spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = - mpt3sas_scsih_sas_device_find_by_sas_address(ioc, - mpt3sas_port->remote_identify.sas_address); - if (sas_device) + sas_device = __mpt3sas_get_sdev_by_addr(ioc, + mpt3sas_port->remote_identify.sas_address); + if (sas_device) { set_bit(sas_device->handle, - ioc->blocking_handles); + ioc->blocking_handles); + sas_device_put(sas_device); + } spin_unlock_irqrestore(&ioc->sas_device_lock, flags); } } @@ -2880,7 +3065,7 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle) { Mpi2SCSITaskManagementRequest_t *mpi_request; u16 smid; - struct _sas_device *sas_device; + struct _sas_device *sas_device = NULL; struct MPT3SAS_TARGET *sas_target_priv_data = NULL; u64 sas_address = 0; unsigned long flags; @@ -2913,7 +3098,7 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle) return; spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = _scsih_sas_device_find_by_handle(ioc, handle); + sas_device = __mpt3sas_get_sdev_by_handle(ioc, handle); if (sas_device && sas_device->starget && sas_device->starget->hostdata) { sas_target_priv_data = sas_device->starget->hostdata; @@ -2947,14 +3132,14 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle) if (!smid) { delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC); if (!delayed_tr) - return; + goto out; INIT_LIST_HEAD(&delayed_tr->list); delayed_tr->handle = handle; list_add_tail(&delayed_tr->list, &ioc->delayed_tr_list); dewtprintk(ioc, pr_info(MPT3SAS_FMT "DELAYED:tr:handle(0x%04x), (open)\n", ioc->name, handle)); - return; + goto out; } dewtprintk(ioc, pr_info(MPT3SAS_FMT @@ -2968,6 +3153,10 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle) mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET; mpt3sas_base_put_smid_hi_priority(ioc, smid); mpt3sas_trigger_master(ioc, MASTER_TRIGGER_DEVICE_REMOVAL); + +out: + if (sas_device) + sas_device_put(sas_device); } /** @@ -3337,7 +3526,7 @@ _scsih_set_volume_delete_flag(struct MPT3SAS_ADAPTER *ioc, u16 handle) unsigned long flags; spin_lock_irqsave(&ioc->raid_device_lock, flags); - raid_device = _scsih_raid_device_find_by_handle(ioc, handle); + raid_device = mpt3sas_raid_device_find_by_handle(ioc, handle); if (raid_device && raid_device->starget && raid_device->starget->hostdata) { sas_target_priv_data = @@ -3398,6 +3587,9 @@ _scsih_check_ir_config_unhide_events(struct MPT3SAS_ADAPTER *ioc, a = 0; b = 0; + if (ioc->is_warpdrive) + return; + /* Volume Resets for Deleted or Removed */ element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0]; for (i = 0; i < event_data->NumElements; i++, element++) { @@ -3634,8 +3826,9 @@ _scsih_eedp_error_handling(struct scsi_cmnd *scmd, u16 ioc_status) } + /** - * _scsih_qcmd - main scsi request entry point + * scsih_qcmd - main scsi request entry point * @scmd: pointer to scsi command object * @done: function pointer to be invoked on completion * @@ -3645,21 +3838,20 @@ _scsih_eedp_error_handling(struct scsi_cmnd *scmd, u16 ioc_status) * 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_Host *shost, struct scsi_cmnd *scmd) +int +scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd) { struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); struct MPT3SAS_DEVICE *sas_device_priv_data; struct MPT3SAS_TARGET *sas_target_priv_data; + struct _raid_device *raid_device; Mpi2SCSIIORequest_t *mpi_request; u32 mpi_control; u16 smid; u16 handle; -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING if (ioc->logging_level & MPT_DEBUG_SCSI) scsi_print_command(scmd); -#endif sas_device_priv_data = scmd->device->hostdata; if (!sas_device_priv_data || !sas_device_priv_data->sas_target) { @@ -3709,7 +3901,11 @@ _scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd) /* set tags */ mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ; - if ((sas_device_priv_data->flags & MPT_DEVICE_TLR_ON) && + /* Make sure Device is not raid volume. + * We do not expose raid functionality to upper layer for warpdrive. + */ + if (!ioc->is_warpdrive && !scsih_is_raid(&scmd->device->sdev_gendev) + && (sas_device_priv_data->flags & MPT_DEVICE_TLR_ON) && scmd->cmd_len != 32) mpi_control |= MPI2_SCSIIO_CONTROL_TLR_ON; @@ -3752,13 +3948,19 @@ _scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd) } else ioc->build_zero_len_sge(ioc, &mpi_request->SGL); + raid_device = sas_target_priv_data->raid_device; + if (raid_device && raid_device->direct_io_enabled) + mpt3sas_setup_direct_io(ioc, scmd, raid_device, mpi_request, + smid); + if (likely(mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST)) { if (sas_target_priv_data->flags & MPT_TARGET_FASTPATH_IO) { mpi_request->IoFlags = cpu_to_le16(scmd->cmd_len | MPI25_SCSIIO_IOFLAGS_FAST_PATH); mpt3sas_base_put_smid_fast_path(ioc, smid, handle); } else - mpt3sas_base_put_smid_scsi_io(ioc, smid, handle); + mpt3sas_base_put_smid_scsi_io(ioc, smid, + le16_to_cpu(mpi_request->DevHandle)); } else mpt3sas_base_put_smid_default(ioc, smid); return 0; @@ -3790,7 +3992,6 @@ _scsih_normalize_sense(char *sense_buffer, struct sense_info *data) } } -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING /** * _scsih_scsi_ioc_info - translated non-succesfull SCSI_IO request * @ioc: per adapter object @@ -3818,14 +4019,16 @@ _scsih_scsi_ioc_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, char *desc_scsi_state = ioc->tmp_string; u32 log_info = le32_to_cpu(mpi_reply->IOCLogInfo); struct _sas_device *sas_device = NULL; - unsigned long flags; struct scsi_target *starget = scmd->device->sdev_target; struct MPT3SAS_TARGET *priv_target = starget->hostdata; char *device_str = NULL; if (!priv_target) return; - device_str = "volume"; + if (ioc->hide_ir_msg) + device_str = "WarpDrive"; + else + device_str = "volume"; if (log_info == 0x31170000) return; @@ -3946,9 +4149,7 @@ _scsih_scsi_ioc_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, pr_warn(MPT3SAS_FMT "\t%s wwid(0x%016llx)\n", ioc->name, device_str, (unsigned long long)priv_target->sas_address); } else { - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc, - priv_target->sas_address); + sas_device = mpt3sas_get_sdev_from_target(ioc, priv_target); if (sas_device) { pr_warn(MPT3SAS_FMT "\tsas_address(0x%016llx), phy(%d)\n", @@ -3967,8 +4168,9 @@ _scsih_scsi_ioc_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, " connector name( %s)\n", ioc->name, sas_device->enclosure_level, sas_device->connector_name); + + sas_device_put(sas_device); } - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); } pr_warn(MPT3SAS_FMT @@ -4003,7 +4205,6 @@ _scsih_scsi_ioc_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, _scsih_response_code(ioc, response_bytes[0]); } } -#endif /** * _scsih_turn_on_pfa_led - illuminate PFA LED @@ -4020,7 +4221,7 @@ _scsih_turn_on_pfa_led(struct MPT3SAS_ADAPTER *ioc, u16 handle) Mpi2SepRequest_t mpi_request; struct _sas_device *sas_device; - sas_device = _scsih_sas_device_find_by_handle(ioc, handle); + sas_device = mpt3sas_get_sdev_by_handle(ioc, handle); if (!sas_device) return; @@ -4035,7 +4236,7 @@ _scsih_turn_on_pfa_led(struct MPT3SAS_ADAPTER *ioc, u16 handle) &mpi_request)) != 0) { pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); - return; + goto out; } sas_device->pfa_led_on = 1; @@ -4044,9 +4245,12 @@ _scsih_turn_on_pfa_led(struct MPT3SAS_ADAPTER *ioc, u16 handle) "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; + goto out; } +out: + sas_device_put(sas_device); } + /** * _scsih_turn_off_pfa_led - turn off Fault LED * @ioc: per adapter object @@ -4085,6 +4289,7 @@ _scsih_turn_off_pfa_led(struct MPT3SAS_ADAPTER *ioc, return; } } + /** * _scsih_send_event_to_turn_on_pfa_led - fire delayed event * @ioc: per adapter object @@ -4098,13 +4303,14 @@ _scsih_send_event_to_turn_on_pfa_led(struct MPT3SAS_ADAPTER *ioc, u16 handle) { struct fw_event_work *fw_event; - fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC); + fw_event = alloc_fw_event_work(0); if (!fw_event) return; fw_event->event = MPT3SAS_TURN_ON_PFA_LED; fw_event->device_handle = handle; fw_event->ioc = ioc; _scsih_fw_event_add(ioc, fw_event); + fw_event_work_put(fw_event); } /** @@ -4128,19 +4334,17 @@ _scsih_smart_predicted_fault(struct MPT3SAS_ADAPTER *ioc, u16 handle) /* 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; - } + sas_device = __mpt3sas_get_sdev_by_handle(ioc, handle); + if (!sas_device) + goto out_unlock; + 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; - } + ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME))) + goto out_unlock; + if (sas_device->enclosure_handle != 0) starget_printk(KERN_INFO, starget, "predicted fault, " "enclosure logical id(0x%016llx), slot(%d)\n", @@ -4163,7 +4367,7 @@ _scsih_smart_predicted_fault(struct MPT3SAS_ADAPTER *ioc, u16 handle) if (!event_reply) { pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); - return; + goto out; } event_reply->Function = MPI2_FUNCTION_EVENT_NOTIFICATION; @@ -4180,6 +4384,14 @@ _scsih_smart_predicted_fault(struct MPT3SAS_ADAPTER *ioc, u16 handle) event_data->SASAddress = cpu_to_le64(sas_target_priv_data->sas_address); mpt3sas_ctl_add_to_event_log(ioc, event_reply); kfree(event_reply); +out: + if (sas_device) + sas_device_put(sas_device); + return; + +out_unlock: + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + goto out; } /** @@ -4207,6 +4419,7 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) u32 log_info; struct MPT3SAS_DEVICE *sas_device_priv_data; u32 response_code = 0; + unsigned long flags; mpi_reply = mpt3sas_base_get_reply_virt_addr(ioc, reply); scmd = _scsih_scsi_lookup_get_clear(ioc, smid); @@ -4228,6 +4441,24 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) } ioc_status = le16_to_cpu(mpi_reply->IOCStatus); + /* + * WARPDRIVE: If direct_io is set then it is directIO, + * the failed direct I/O should be redirected to volume + */ + if (mpt3sas_scsi_direct_io_get(ioc, smid) && + ((ioc_status & MPI2_IOCSTATUS_MASK) + != MPI2_IOCSTATUS_SCSI_TASK_TERMINATED)) { + spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); + ioc->scsi_lookup[smid - 1].scmd = scmd; + spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); + mpt3sas_scsi_direct_io_set(ioc, smid, 0); + memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len); + mpi_request->DevHandle = + cpu_to_le16(sas_device_priv_data->sas_target->handle); + mpt3sas_base_put_smid_scsi_io(ioc, smid, + sas_device_priv_data->sas_target->handle); + return 0; + } /* turning off TLR */ scsi_state = mpi_reply->SCSIState; if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) @@ -4235,10 +4466,13 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) le32_to_cpu(mpi_reply->ResponseInfo) & 0xFF; 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 == MPI2_SCSITASKMGMT_RSP_INVALID_FRAME) - sas_device_priv_data->flags &= - ~MPT_DEVICE_TLR_ON; + if (!ioc->is_warpdrive && + !scsih_is_raid(&scmd->device->sdev_gendev) && + sas_is_tlr_enabled(scmd->device) && + response_code == MPI2_SCSITASKMGMT_RSP_INVALID_FRAME) { + sas_disable_tlr(scmd->device); + sdev_printk(KERN_INFO, scmd->device, "TLR disabled\n"); + } } xfer_cnt = le32_to_cpu(mpi_reply->TransferCount); @@ -4271,13 +4505,11 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) le16_to_cpu(mpi_reply->DevHandle)); mpt3sas_trigger_scsi(ioc, data.skey, data.asc, data.ascq); -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING if (!(ioc->logging_level & MPT_DEBUG_REPLY) && ((scmd->sense_buffer[2] == UNIT_ATTENTION) || (scmd->sense_buffer[2] == MEDIUM_ERROR) || (scmd->sense_buffer[2] == HARDWARE_ERROR))) _scsih_scsi_ioc_info(ioc, scmd, mpi_reply, smid); -#endif } switch (ioc_status) { case MPI2_IOCSTATUS_BUSY: @@ -4384,10 +4616,8 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) } -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING if (scmd->result && (ioc->logging_level & MPT_DEBUG_REPLY)) _scsih_scsi_ioc_info(ioc , scmd, mpi_reply, smid); -#endif out: @@ -4933,13 +5163,11 @@ _scsih_check_device(struct MPT3SAS_ADAPTER *ioc, spin_lock_irqsave(&ioc->sas_device_lock, flags); sas_address = le64_to_cpu(sas_device_pg0.SASAddress); - sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc, + sas_device = __mpt3sas_get_sdev_by_addr(ioc, sas_address); - if (!sas_device) { - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - return; - } + if (!sas_device) + goto out_unlock; if (unlikely(sas_device->handle != handle)) { starget = sas_device->starget; @@ -4967,20 +5195,25 @@ _scsih_check_device(struct MPT3SAS_ADAPTER *ioc, pr_err(MPT3SAS_FMT "device is not present handle(0x%04x), flags!!!\n", ioc->name, handle); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - return; + goto out_unlock; } /* check if there were any issues with discovery */ if (_scsih_check_access_status(ioc, sas_address, handle, - sas_device_pg0.AccessStatus)) { - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - return; - } + sas_device_pg0.AccessStatus)) + goto out_unlock; spin_unlock_irqrestore(&ioc->sas_device_lock, flags); _scsih_ublock_io_device(ioc, sas_address); + if (sas_device) + sas_device_put(sas_device); + return; + +out_unlock: + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + if (sas_device) + sas_device_put(sas_device); } /** @@ -5005,7 +5238,6 @@ _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u32 ioc_status; u64 sas_address; u32 device_info; - unsigned long flags; if ((mpt3sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) { @@ -5041,13 +5273,12 @@ _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num, sas_device_pg0.AccessStatus)) return -1; - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc, - sas_address); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - - if (sas_device) + sas_device = mpt3sas_get_sdev_by_addr(ioc, + sas_address); + if (sas_device) { + sas_device_put(sas_device); return -1; + } sas_device = kzalloc(sizeof(struct _sas_device), GFP_KERNEL); @@ -5057,6 +5288,7 @@ _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num, return 0; } + kref_init(&sas_device->refcount); sas_device->handle = handle; if (_scsih_get_sas_address(ioc, le16_to_cpu(sas_device_pg0.ParentDevHandle), @@ -5098,6 +5330,7 @@ _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num, else _scsih_sas_device_add(ioc, sas_device); + sas_device_put(sas_device); return 0; } @@ -5144,7 +5377,9 @@ _scsih_remove_device(struct MPT3SAS_ADAPTER *ioc, sas_target_priv_data->handle = MPT3SAS_INVALID_DEVICE_HANDLE; } - mpt3sas_transport_port_remove(ioc, + + if (!ioc->hide_drives) + mpt3sas_transport_port_remove(ioc, sas_device->sas_address, sas_device->sas_address_parent); @@ -5180,11 +5415,8 @@ _scsih_remove_device(struct MPT3SAS_ADAPTER *ioc, "%s: exit: enclosure level(0x%04x), connector name(%s)\n", ioc->name, __func__, sas_device->enclosure_level, sas_device->connector_name)); - - kfree(sas_device); } -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING /** * _scsih_sas_topology_change_event_debug - debug for topology event * @ioc: per adapter object @@ -5262,7 +5494,6 @@ _scsih_sas_topology_change_event_debug(struct MPT3SAS_ADAPTER *ioc, } } -#endif /** * _scsih_sas_topology_change_event - handle topology changes @@ -5287,10 +5518,8 @@ _scsih_sas_topology_change_event(struct MPT3SAS_ADAPTER *ioc, (Mpi2EventDataSasTopologyChangeList_t *) fw_event->event_data; -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) _scsih_sas_topology_change_event_debug(ioc, event_data); -#endif if (ioc->shost_recovery || ioc->remove_host || ioc->pci_error_recovery) return 0; @@ -5396,7 +5625,6 @@ _scsih_sas_topology_change_event(struct MPT3SAS_ADAPTER *ioc, return 0; } -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING /** * _scsih_sas_device_status_change_event_debug - debug for device event * @event_data: event data payload @@ -5464,7 +5692,6 @@ _scsih_sas_device_status_change_event_debug(struct MPT3SAS_ADAPTER *ioc, event_data->ASC, event_data->ASCQ); pr_info("\n"); } -#endif /** * _scsih_sas_device_status_change_event - handle device status change @@ -5486,11 +5713,9 @@ _scsih_sas_device_status_change_event(struct MPT3SAS_ADAPTER *ioc, (Mpi2EventDataSasDeviceStatusChange_t *) fw_event->event_data; -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) _scsih_sas_device_status_change_event_debug(ioc, event_data); -#endif /* In MPI Revision K (0xC), the internal device reset complete was * implemented, so avoid setting tm_busy flag for older firmware. @@ -5506,29 +5731,30 @@ _scsih_sas_device_status_change_event(struct MPT3SAS_ADAPTER *ioc, spin_lock_irqsave(&ioc->sas_device_lock, flags); sas_address = le64_to_cpu(event_data->SASAddress); - sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc, + sas_device = __mpt3sas_get_sdev_by_addr(ioc, sas_address); - if (!sas_device || !sas_device->starget) { - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - return; - } + if (!sas_device || !sas_device->starget) + goto out; target_priv_data = sas_device->starget->hostdata; - if (!target_priv_data) { - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - return; - } + if (!target_priv_data) + goto out; if (event_data->ReasonCode == MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET) target_priv_data->tm_busy = 1; else target_priv_data->tm_busy = 0; + +out: + if (sas_device) + sas_device_put(sas_device); + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + } -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING /** * _scsih_sas_enclosure_dev_status_change_event_debug - debug for enclosure * event @@ -5563,7 +5789,6 @@ _scsih_sas_enclosure_dev_status_change_event_debug(struct MPT3SAS_ADAPTER *ioc, (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 @@ -5577,12 +5802,10 @@ static void _scsih_sas_enclosure_dev_status_change_event(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work *fw_event) { -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) _scsih_sas_enclosure_dev_status_change_event_debug(ioc, (Mpi2EventDataSasEnclDevStatusChange_t *) fw_event->event_data); -#endif } /** @@ -5762,17 +5985,15 @@ _scsih_sas_discovery_event(struct MPT3SAS_ADAPTER *ioc, Mpi2EventDataSasDiscovery_t *event_data = (Mpi2EventDataSasDiscovery_t *) fw_event->event_data; -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) { pr_info(MPT3SAS_FMT "discovery event: (%s)", ioc->name, (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED) ? "start" : "stop"); - if (event_data->DiscoveryStatus) - pr_info("discovery_status(0x%08x)", - le32_to_cpu(event_data->DiscoveryStatus)); - pr_info("\n"); + if (event_data->DiscoveryStatus) + pr_info("discovery_status(0x%08x)", + le32_to_cpu(event_data->DiscoveryStatus)); + pr_info("\n"); } -#endif if (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED && !ioc->sas_hba.num_phys) { @@ -5804,6 +6025,8 @@ _scsih_ir_fastpath(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phys_disk_num) u16 ioc_status; u32 log_info; + if (ioc->hba_mpi_version_belonged == MPI2_VERSION) + return rc; mutex_lock(&ioc->scsih_cmds.mutex); @@ -5971,7 +6194,7 @@ _scsih_sas_volume_delete(struct MPT3SAS_ADAPTER *ioc, u16 handle) struct scsi_target *starget = NULL; spin_lock_irqsave(&ioc->raid_device_lock, flags); - raid_device = _scsih_raid_device_find_by_handle(ioc, handle); + raid_device = mpt3sas_raid_device_find_by_handle(ioc, handle); if (raid_device) { if (raid_device->starget) { starget = raid_device->starget; @@ -6008,7 +6231,7 @@ _scsih_sas_pd_expose(struct MPT3SAS_ADAPTER *ioc, 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); + sas_device = __mpt3sas_get_sdev_by_handle(ioc, handle); if (sas_device) { sas_device->volume_handle = 0; sas_device->volume_wwid = 0; @@ -6027,6 +6250,8 @@ _scsih_sas_pd_expose(struct MPT3SAS_ADAPTER *ioc, /* exposing raid component */ if (starget) starget_for_each_device(starget, NULL, _scsih_reprobe_lun); + + sas_device_put(sas_device); } /** @@ -6055,7 +6280,7 @@ _scsih_sas_pd_hide(struct MPT3SAS_ADAPTER *ioc, &volume_wwid); spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = _scsih_sas_device_find_by_handle(ioc, handle); + sas_device = __mpt3sas_get_sdev_by_handle(ioc, handle); if (sas_device) { set_bit(handle, ioc->pd_handles); if (sas_device->starget && sas_device->starget->hostdata) { @@ -6073,8 +6298,11 @@ _scsih_sas_pd_hide(struct MPT3SAS_ADAPTER *ioc, /* hiding raid component */ _scsih_ir_fastpath(ioc, handle, element->PhysDiskNum); + if (starget) starget_for_each_device(starget, (void *)1, _scsih_reprobe_lun); + + sas_device_put(sas_device); } /** @@ -6107,7 +6335,6 @@ _scsih_sas_pd_add(struct MPT3SAS_ADAPTER *ioc, Mpi2EventIrConfigElement_t *element) { struct _sas_device *sas_device; - unsigned long flags; u16 handle = le16_to_cpu(element->PhysDiskDevHandle); Mpi2ConfigReply_t mpi_reply; Mpi2SasDevicePage0_t sas_device_pg0; @@ -6117,11 +6344,10 @@ _scsih_sas_pd_add(struct MPT3SAS_ADAPTER *ioc, set_bit(handle, ioc->pd_handles); - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = _scsih_sas_device_find_by_handle(ioc, handle); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + sas_device = mpt3sas_get_sdev_by_handle(ioc, handle); if (sas_device) { _scsih_ir_fastpath(ioc, handle, element->PhysDiskNum); + sas_device_put(sas_device); return; } @@ -6149,7 +6375,6 @@ _scsih_sas_pd_add(struct MPT3SAS_ADAPTER *ioc, _scsih_add_device(ioc, handle, 0, 1); } -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING /** * _scsih_sas_ir_config_change_event_debug - debug for IR Config Change events * @ioc: per adapter object @@ -6229,7 +6454,6 @@ _scsih_sas_ir_config_change_event_debug(struct MPT3SAS_ADAPTER *ioc, element->PhysDiskNum); } } -#endif /** * _scsih_sas_ir_config_change_event - handle ir configuration change events @@ -6250,18 +6474,16 @@ _scsih_sas_ir_config_change_event(struct MPT3SAS_ADAPTER *ioc, (Mpi2EventDataIrConfigChangeList_t *) fw_event->event_data; -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING - if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) + if ((ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) && + (!ioc->hide_ir_msg)) _scsih_sas_ir_config_change_event_debug(ioc, event_data); -#endif - foreign_config = (le32_to_cpu(event_data->Flags) & MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ? 1 : 0; element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0]; - if (ioc->shost_recovery) { - + if (ioc->shost_recovery && + ioc->hba_mpi_version_belonged != MPI2_VERSION) { for (i = 0; i < event_data->NumElements; i++, element++) { if (element->ReasonCode == MPI2_EVENT_IR_CHANGE_RC_HIDE) _scsih_ir_fastpath(ioc, @@ -6270,6 +6492,7 @@ _scsih_sas_ir_config_change_event(struct MPT3SAS_ADAPTER *ioc, } return; } + for (i = 0; i < event_data->NumElements; i++, element++) { switch (element->ReasonCode) { @@ -6285,16 +6508,20 @@ _scsih_sas_ir_config_change_event(struct MPT3SAS_ADAPTER *ioc, le16_to_cpu(element->VolDevHandle)); break; case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED: - _scsih_sas_pd_hide(ioc, element); + if (!ioc->is_warpdrive) + _scsih_sas_pd_hide(ioc, element); break; case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED: - _scsih_sas_pd_expose(ioc, element); + if (!ioc->is_warpdrive) + _scsih_sas_pd_expose(ioc, element); break; case MPI2_EVENT_IR_CHANGE_RC_HIDE: - _scsih_sas_pd_add(ioc, element); + if (!ioc->is_warpdrive) + _scsih_sas_pd_add(ioc, element); break; case MPI2_EVENT_IR_CHANGE_RC_UNHIDE: - _scsih_sas_pd_delete(ioc, element); + if (!ioc->is_warpdrive) + _scsih_sas_pd_delete(ioc, element); break; } } @@ -6329,10 +6556,11 @@ _scsih_sas_ir_volume_event(struct MPT3SAS_ADAPTER *ioc, handle = le16_to_cpu(event_data->VolDevHandle); state = le32_to_cpu(event_data->NewValue); - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "%s: handle(0x%04x), old(0x%08x), new(0x%08x)\n", - ioc->name, __func__, handle, - le32_to_cpu(event_data->PreviousValue), state)); + if (!ioc->hide_ir_msg) + dewtprintk(ioc, pr_info(MPT3SAS_FMT + "%s: handle(0x%04x), old(0x%08x), new(0x%08x)\n", + ioc->name, __func__, handle, + le32_to_cpu(event_data->PreviousValue), state)); switch (state) { case MPI2_RAID_VOL_STATE_MISSING: case MPI2_RAID_VOL_STATE_FAILED: @@ -6344,7 +6572,7 @@ _scsih_sas_ir_volume_event(struct MPT3SAS_ADAPTER *ioc, case MPI2_RAID_VOL_STATE_OPTIMAL: spin_lock_irqsave(&ioc->raid_device_lock, flags); - raid_device = _scsih_raid_device_find_by_handle(ioc, handle); + raid_device = mpt3sas_raid_device_find_by_handle(ioc, handle); spin_unlock_irqrestore(&ioc->raid_device_lock, flags); if (raid_device) @@ -6398,7 +6626,6 @@ _scsih_sas_ir_physical_disk_event(struct MPT3SAS_ADAPTER *ioc, u16 handle, parent_handle; u32 state; struct _sas_device *sas_device; - unsigned long flags; Mpi2ConfigReply_t mpi_reply; Mpi2SasDevicePage0_t sas_device_pg0; u32 ioc_status; @@ -6415,10 +6642,12 @@ _scsih_sas_ir_physical_disk_event(struct MPT3SAS_ADAPTER *ioc, handle = le16_to_cpu(event_data->PhysDiskDevHandle); state = le32_to_cpu(event_data->NewValue); - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "%s: handle(0x%04x), old(0x%08x), new(0x%08x)\n", - ioc->name, __func__, handle, + if (!ioc->hide_ir_msg) + dewtprintk(ioc, pr_info(MPT3SAS_FMT + "%s: handle(0x%04x), old(0x%08x), new(0x%08x)\n", + ioc->name, __func__, handle, le32_to_cpu(event_data->PreviousValue), state)); + switch (state) { case MPI2_RAID_PD_STATE_ONLINE: case MPI2_RAID_PD_STATE_DEGRADED: @@ -6426,13 +6655,14 @@ _scsih_sas_ir_physical_disk_event(struct MPT3SAS_ADAPTER *ioc, case MPI2_RAID_PD_STATE_OPTIMAL: case MPI2_RAID_PD_STATE_HOT_SPARE: - set_bit(handle, ioc->pd_handles); - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = _scsih_sas_device_find_by_handle(ioc, handle); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + if (!ioc->is_warpdrive) + set_bit(handle, ioc->pd_handles); - if (sas_device) + sas_device = mpt3sas_get_sdev_by_handle(ioc, handle); + if (sas_device) { + sas_device_put(sas_device); return; + } if ((mpt3sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, @@ -6467,7 +6697,6 @@ _scsih_sas_ir_physical_disk_event(struct MPT3SAS_ADAPTER *ioc, } } -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING /** * _scsih_sas_ir_operation_status_event_debug - debug for IR op event * @ioc: per adapter object @@ -6509,7 +6738,6 @@ _scsih_sas_ir_operation_status_event_debug(struct MPT3SAS_ADAPTER *ioc, le16_to_cpu(event_data->VolDevHandle), event_data->PercentComplete); } -#endif /** * _scsih_sas_ir_operation_status_event - handle RAID operation events @@ -6530,18 +6758,17 @@ _scsih_sas_ir_operation_status_event(struct MPT3SAS_ADAPTER *ioc, unsigned long flags; u16 handle; -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING - if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) + if ((ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) && + (!ioc->hide_ir_msg)) _scsih_sas_ir_operation_status_event_debug(ioc, event_data); -#endif /* code added for raid transport support */ if (event_data->RAIDOperation == MPI2_EVENT_IR_RAIDOP_RESYNC) { spin_lock_irqsave(&ioc->raid_device_lock, flags); handle = le16_to_cpu(event_data->VolDevHandle); - raid_device = _scsih_raid_device_find_by_handle(ioc, handle); + raid_device = mpt3sas_raid_device_find_by_handle(ioc, handle); if (raid_device) raid_device->percent_complete = event_data->PercentComplete; @@ -6703,7 +6930,7 @@ static void _scsih_mark_responding_raid_device(struct MPT3SAS_ADAPTER *ioc, u64 wwid, u16 handle) { - struct MPT3SAS_TARGET *sas_target_priv_data; + struct MPT3SAS_TARGET *sas_target_priv_data = NULL; struct scsi_target *starget; struct _raid_device *raid_device; unsigned long flags; @@ -6722,6 +6949,13 @@ _scsih_mark_responding_raid_device(struct MPT3SAS_ADAPTER *ioc, u64 wwid, starget_printk(KERN_INFO, raid_device->starget, "handle(0x%04x), wwid(0x%016llx)\n", handle, (unsigned long long)raid_device->wwid); + + /* + * WARPDRIVE: The handles of the PDs might have changed + * across the host reset so re-initialize the + * required data for Direct IO + */ + mpt3sas_init_warpdrive_properties(ioc, raid_device); spin_lock_irqsave(&ioc->raid_device_lock, flags); if (raid_device->handle == handle) { spin_unlock_irqrestore(&ioc->raid_device_lock, @@ -6791,6 +7025,7 @@ _scsih_search_responding_raid_devices(struct MPT3SAS_ADAPTER *ioc) } /* refresh the pd_handles */ + if (!ioc->is_warpdrive) { phys_disk_num = 0xFF; memset(ioc->pd_handles, 0, ioc->pd_handles_sz); while (!(mpt3sas_config_get_phys_disk_pg0(ioc, &mpi_reply, @@ -6804,6 +7039,7 @@ _scsih_search_responding_raid_devices(struct MPT3SAS_ADAPTER *ioc) handle = le16_to_cpu(pd_pg0.DevHandle); set_bit(handle, ioc->pd_handles); } + } out: pr_info(MPT3SAS_FMT "search for responding raid volumes: complete\n", ioc->name); @@ -6906,6 +7142,7 @@ _scsih_remove_unresponding_sas_devices(struct MPT3SAS_ADAPTER *ioc) struct _raid_device *raid_device, *raid_device_next; struct list_head tmp_list; unsigned long flags; + LIST_HEAD(head); pr_info(MPT3SAS_FMT "removing unresponding devices: start\n", ioc->name); @@ -6913,14 +7150,28 @@ _scsih_remove_unresponding_sas_devices(struct MPT3SAS_ADAPTER *ioc) /* removing unresponding end devices */ pr_info(MPT3SAS_FMT "removing unresponding devices: end-devices\n", ioc->name); + /* + * Iterate, pulling off devices marked as non-responding. We become the + * owner for the reference the list had on any object we prune. + */ + spin_lock_irqsave(&ioc->sas_device_lock, flags); list_for_each_entry_safe(sas_device, sas_device_next, &ioc->sas_device_list, list) { if (!sas_device->responding) - mpt3sas_device_remove_by_sas_address(ioc, - sas_device->sas_address); + list_move_tail(&sas_device->list, &head); else sas_device->responding = 0; } + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + + /* + * Now, uninitialize and remove the unresponding devices we pruned. + */ + list_for_each_entry_safe(sas_device, sas_device_next, &head, list) { + _scsih_remove_device(ioc, sas_device); + list_del_init(&sas_device->list); + sas_device_put(sas_device); + } /* removing unresponding volumes */ if (ioc->ir_firmware) { @@ -7074,11 +7325,11 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc) } phys_disk_num = pd_pg0.PhysDiskNum; handle = le16_to_cpu(pd_pg0.DevHandle); - 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 = mpt3sas_get_sdev_by_handle(ioc, handle); + if (sas_device) { + sas_device_put(sas_device); continue; + } if (mpt3sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle) != 0) @@ -7199,12 +7450,12 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc) if (!(_scsih_is_end_device( le32_to_cpu(sas_device_pg0.DeviceInfo)))) continue; - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc, + sas_device = mpt3sas_get_sdev_by_addr(ioc, le64_to_cpu(sas_device_pg0.SASAddress)); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - if (sas_device) + if (sas_device) { + sas_device_put(sas_device); continue; + } parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle); if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address)) { pr_info(MPT3SAS_FMT "\tBEFORE adding end device: " \ @@ -7296,10 +7547,11 @@ mpt3sas_scsih_reset_handler(struct MPT3SAS_ADAPTER *ioc, int reset_phase) static void _mpt3sas_fw_work(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work *fw_event) { + _scsih_fw_event_del_from_list(ioc, fw_event); + /* the queue is being flushed so ignore this event */ - if (ioc->remove_host || - ioc->pci_error_recovery) { - _scsih_fw_event_free(ioc, fw_event); + if (ioc->remove_host || ioc->pci_error_recovery) { + fw_event_work_put(fw_event); return; } @@ -7310,8 +7562,16 @@ _mpt3sas_fw_work(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work *fw_event) fw_event->event_data); break; case MPT3SAS_REMOVE_UNRESPONDING_DEVICES: - while (scsi_host_in_recovery(ioc->shost) || ioc->shost_recovery) + while (scsi_host_in_recovery(ioc->shost) || + ioc->shost_recovery) { + /* + * If we're unloading, bail. Otherwise, this can become + * an infinite loop. + */ + if (ioc->remove_host) + goto out; ssleep(1); + } _scsih_remove_unresponding_sas_devices(ioc); _scsih_scan_for_devices_after_reset(ioc); break; @@ -7356,7 +7616,8 @@ _mpt3sas_fw_work(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work *fw_event) _scsih_sas_ir_operation_status_event(ioc, fw_event); break; } - _scsih_fw_event_free(ioc, fw_event); +out: + fw_event_work_put(fw_event); } /** @@ -7453,7 +7714,53 @@ mpt3sas_scsih_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, (Mpi2EventDataIrVolume_t *) mpi_reply->EventData); break; + case MPI2_EVENT_LOG_ENTRY_ADDED: + { + Mpi2EventDataLogEntryAdded_t *log_entry; + u32 *log_code; + + if (!ioc->is_warpdrive) + break; + + log_entry = (Mpi2EventDataLogEntryAdded_t *) + mpi_reply->EventData; + log_code = (u32 *)log_entry->LogData; + if (le16_to_cpu(log_entry->LogEntryQualifier) + != MPT2_WARPDRIVE_LOGENTRY) + break; + + switch (le32_to_cpu(*log_code)) { + case MPT2_WARPDRIVE_LC_SSDT: + pr_warn(MPT3SAS_FMT "WarpDrive Warning: " + "IO Throttling has occurred in the WarpDrive " + "subsystem. Check WarpDrive documentation for " + "additional details.\n", ioc->name); + break; + case MPT2_WARPDRIVE_LC_SSDLW: + pr_warn(MPT3SAS_FMT "WarpDrive Warning: " + "Program/Erase Cycles for the WarpDrive subsystem " + "in degraded range. Check WarpDrive documentation " + "for additional details.\n", ioc->name); + break; + case MPT2_WARPDRIVE_LC_SSDLF: + pr_err(MPT3SAS_FMT "WarpDrive Fatal Error: " + "There are no Program/Erase Cycles for the " + "WarpDrive subsystem. The storage device will be " + "in read-only mode. Check WarpDrive documentation " + "for additional details.\n", ioc->name); + break; + case MPT2_WARPDRIVE_LC_BRMF: + pr_err(MPT3SAS_FMT "WarpDrive Fatal Error: " + "The Backup Rail Monitor has failed on the " + "WarpDrive subsystem. Check WarpDrive " + "documentation for additional details.\n", + ioc->name); + break; + } + + break; + } case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE: case MPI2_EVENT_IR_OPERATION_STATUS: case MPI2_EVENT_SAS_DISCOVERY: @@ -7472,7 +7779,7 @@ mpt3sas_scsih_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, } sz = le16_to_cpu(mpi_reply->EventDataLength) * 4; - fw_event = kzalloc(sizeof(*fw_event) + sz, GFP_ATOMIC); + fw_event = alloc_fw_event_work(sz); if (!fw_event) { pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); @@ -7485,39 +7792,10 @@ mpt3sas_scsih_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, fw_event->VP_ID = mpi_reply->VP_ID; fw_event->event = event; _scsih_fw_event_add(ioc, fw_event); + fw_event_work_put(fw_event); return 1; } -/* shost template */ -static struct scsi_host_template scsih_driver_template = { - .module = THIS_MODULE, - .name = "Fusion MPT SAS Host", - .proc_name = MPT3SAS_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, - .scan_finished = _scsih_scan_finished, - .scan_start = _scsih_scan_start, - .change_queue_depth = _scsih_change_queue_depth, - .eh_abort_handler = _scsih_abort, - .eh_device_reset_handler = _scsih_dev_reset, - .eh_target_reset_handler = _scsih_target_reset, - .eh_host_reset_handler = _scsih_host_reset, - .bios_param = _scsih_bios_param, - .can_queue = 1, - .this_id = -1, - .sg_tablesize = MPT3SAS_SG_DEPTH, - .max_sectors = 32767, - .cmd_per_lun = 7, - .use_clustering = ENABLE_CLUSTERING, - .shost_attrs = mpt3sas_host_attrs, - .sdev_attrs = mpt3sas_dev_attrs, - .track_queue_depth = 1, -}; - /** * _scsih_expander_node_remove - removing expander device from list. * @ioc: per adapter object @@ -7613,7 +7891,8 @@ _scsih_ir_shutdown(struct MPT3SAS_ADAPTER *ioc) mpi_request->Function = MPI2_FUNCTION_RAID_ACTION; mpi_request->Action = MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED; - pr_info(MPT3SAS_FMT "IR shutdown (sending)\n", ioc->name); + if (!ioc->hide_ir_msg) + pr_info(MPT3SAS_FMT "IR shutdown (sending)\n", ioc->name); init_completion(&ioc->scsih_cmds.done); mpt3sas_base_put_smid_default(ioc, smid); wait_for_completion_timeout(&ioc->scsih_cmds.done, 10*HZ); @@ -7626,10 +7905,11 @@ _scsih_ir_shutdown(struct MPT3SAS_ADAPTER *ioc) if (ioc->scsih_cmds.status & MPT3_CMD_REPLY_VALID) { mpi_reply = ioc->scsih_cmds.reply; - pr_info(MPT3SAS_FMT - "IR shutdown (complete): ioc_status(0x%04x), loginfo(0x%08x)\n", - ioc->name, le16_to_cpu(mpi_reply->IOCStatus), - le32_to_cpu(mpi_reply->IOCLogInfo)); + if (!ioc->hide_ir_msg) + pr_info(MPT3SAS_FMT "IR shutdown " + "(complete): ioc_status(0x%04x), loginfo(0x%08x)\n", + ioc->name, le16_to_cpu(mpi_reply->IOCStatus), + le32_to_cpu(mpi_reply->IOCLogInfo)); } out: @@ -7638,13 +7918,13 @@ _scsih_ir_shutdown(struct MPT3SAS_ADAPTER *ioc) } /** - * _scsih_remove - detach and remove add host + * scsih_remove - detach and remove add host * @pdev: PCI device struct * * Routine called when unloading the driver. * Return nothing. */ -static void _scsih_remove(struct pci_dev *pdev) +void scsih_remove(struct pci_dev *pdev) { struct Scsi_Host *shost = pci_get_drvdata(pdev); struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); @@ -7705,18 +7985,20 @@ static void _scsih_remove(struct pci_dev *pdev) sas_remove_host(shost); scsi_remove_host(shost); mpt3sas_base_detach(ioc); + spin_lock(&gioc_lock); list_del(&ioc->list); + spin_unlock(&gioc_lock); scsi_host_put(shost); } /** - * _scsih_shutdown - routine call during system shutdown + * scsih_shutdown - routine call during system shutdown * @pdev: PCI device struct * * Return nothing. */ -static void -_scsih_shutdown(struct pci_dev *pdev) +void +scsih_shutdown(struct pci_dev *pdev) { struct Scsi_Host *shost = pci_get_drvdata(pdev); struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); @@ -7794,6 +8076,8 @@ _scsih_probe_boot_devices(struct MPT3SAS_ADAPTER *ioc) list_move_tail(&sas_device->list, &ioc->sas_device_list); spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + if (ioc->hide_drives) + return; if (!mpt3sas_transport_port_add(ioc, handle, sas_address_parent)) { _scsih_sas_device_remove(ioc, sas_device); @@ -7831,6 +8115,48 @@ _scsih_probe_raid(struct MPT3SAS_ADAPTER *ioc) } } +static struct _sas_device *get_next_sas_device(struct MPT3SAS_ADAPTER *ioc) +{ + struct _sas_device *sas_device = NULL; + unsigned long flags; + + spin_lock_irqsave(&ioc->sas_device_lock, flags); + if (!list_empty(&ioc->sas_device_init_list)) { + sas_device = list_first_entry(&ioc->sas_device_init_list, + struct _sas_device, list); + sas_device_get(sas_device); + } + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + + return sas_device; +} + +static void sas_device_make_active(struct MPT3SAS_ADAPTER *ioc, + struct _sas_device *sas_device) +{ + unsigned long flags; + + spin_lock_irqsave(&ioc->sas_device_lock, flags); + + /* + * Since we dropped the lock during the call to port_add(), we need to + * be careful here that somebody else didn't move or delete this item + * while we were busy with other things. + * + * If it was on the list, we need a put() for the reference the list + * had. Either way, we need a get() for the destination list. + */ + if (!list_empty(&sas_device->list)) { + list_del_init(&sas_device->list); + sas_device_put(sas_device); + } + + sas_device_get(sas_device); + list_add_tail(&sas_device->list, &ioc->sas_device_list); + + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); +} + /** * _scsih_probe_sas - reporting sas devices to sas transport * @ioc: per adapter object @@ -7840,17 +8166,16 @@ _scsih_probe_raid(struct MPT3SAS_ADAPTER *ioc) static void _scsih_probe_sas(struct MPT3SAS_ADAPTER *ioc) { - struct _sas_device *sas_device, *next; - unsigned long flags; + struct _sas_device *sas_device; - /* SAS Device List */ - list_for_each_entry_safe(sas_device, next, &ioc->sas_device_init_list, - list) { + if (ioc->hide_drives) + return; + while ((sas_device = get_next_sas_device(ioc))) { if (!mpt3sas_transport_port_add(ioc, sas_device->handle, sas_device->sas_address_parent)) { - list_del(&sas_device->list); - kfree(sas_device); + _scsih_sas_device_remove(ioc, sas_device); + sas_device_put(sas_device); continue; } else if (!sas_device->starget) { /* @@ -7863,15 +8188,13 @@ _scsih_probe_sas(struct MPT3SAS_ADAPTER *ioc) mpt3sas_transport_port_remove(ioc, sas_device->sas_address, sas_device->sas_address_parent); - list_del(&sas_device->list); - kfree(sas_device); + _scsih_sas_device_remove(ioc, sas_device); + sas_device_put(sas_device); continue; } } - - 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); + sas_device_make_active(ioc, sas_device); + sas_device_put(sas_device); } } @@ -7908,15 +8231,15 @@ _scsih_probe_devices(struct MPT3SAS_ADAPTER *ioc) } /** - * _scsih_scan_start - scsi lld callback for .scan_start + * scsih_scan_start - scsi lld callback for .scan_start * @shost: SCSI host pointer * * The shost has the ability to discover targets on its own instead * of scanning the entire bus. In our implemention, we will kick off * firmware discovery. */ -static void -_scsih_scan_start(struct Scsi_Host *shost) +void +scsih_scan_start(struct Scsi_Host *shost) { struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); int rc; @@ -7934,7 +8257,7 @@ _scsih_scan_start(struct Scsi_Host *shost) } /** - * _scsih_scan_finished - scsi lld callback for .scan_finished + * scsih_scan_finished - scsi lld callback for .scan_finished * @shost: SCSI host pointer * @time: elapsed time of the scan in jiffies * @@ -7942,8 +8265,8 @@ _scsih_scan_start(struct Scsi_Host *shost) * scsi_host and the elapsed time of the scan in jiffies. In our implemention, * we wait for firmware discovery to complete, then return 1. */ -static int -_scsih_scan_finished(struct Scsi_Host *shost, unsigned long time) +int +scsih_scan_finished(struct Scsi_Host *shost, unsigned long time) { struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); @@ -7987,6 +8310,124 @@ _scsih_scan_finished(struct Scsi_Host *shost, unsigned long time) return 1; } +/* shost template for SAS 2.0 HBA devices */ +static struct scsi_host_template mpt2sas_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, + .scan_finished = scsih_scan_finished, + .scan_start = scsih_scan_start, + .change_queue_depth = scsih_change_queue_depth, + .eh_abort_handler = scsih_abort, + .eh_device_reset_handler = scsih_dev_reset, + .eh_target_reset_handler = scsih_target_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 = 32767, + .cmd_per_lun = 7, + .use_clustering = ENABLE_CLUSTERING, + .shost_attrs = mpt3sas_host_attrs, + .sdev_attrs = mpt3sas_dev_attrs, + .track_queue_depth = 1, +}; + +/* raid transport support for SAS 2.0 HBA devices */ +static struct raid_function_template mpt2sas_raid_functions = { + .cookie = &mpt2sas_driver_template, + .is_raid = scsih_is_raid, + .get_resync = scsih_get_resync, + .get_state = scsih_get_state, +}; + +/* shost template for SAS 3.0 HBA devices */ +static struct scsi_host_template mpt3sas_driver_template = { + .module = THIS_MODULE, + .name = "Fusion MPT SAS Host", + .proc_name = MPT3SAS_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, + .scan_finished = scsih_scan_finished, + .scan_start = scsih_scan_start, + .change_queue_depth = scsih_change_queue_depth, + .eh_abort_handler = scsih_abort, + .eh_device_reset_handler = scsih_dev_reset, + .eh_target_reset_handler = scsih_target_reset, + .eh_host_reset_handler = scsih_host_reset, + .bios_param = scsih_bios_param, + .can_queue = 1, + .this_id = -1, + .sg_tablesize = MPT3SAS_SG_DEPTH, + .max_sectors = 32767, + .cmd_per_lun = 7, + .use_clustering = ENABLE_CLUSTERING, + .shost_attrs = mpt3sas_host_attrs, + .sdev_attrs = mpt3sas_dev_attrs, + .track_queue_depth = 1, +}; + +/* raid transport support for SAS 3.0 HBA devices */ +static struct raid_function_template mpt3sas_raid_functions = { + .cookie = &mpt3sas_driver_template, + .is_raid = scsih_is_raid, + .get_resync = scsih_get_resync, + .get_state = scsih_get_state, +}; + +/** + * _scsih_determine_hba_mpi_version - determine in which MPI version class + * this device belongs to. + * @pdev: PCI device struct + * + * return MPI2_VERSION for SAS 2.0 HBA devices, + * MPI25_VERSION for SAS 3.0 HBA devices. + */ +u16 +_scsih_determine_hba_mpi_version(struct pci_dev *pdev) +{ + + switch (pdev->device) { + case MPI2_MFGPAGE_DEVID_SSS6200: + case MPI2_MFGPAGE_DEVID_SAS2004: + case MPI2_MFGPAGE_DEVID_SAS2008: + case MPI2_MFGPAGE_DEVID_SAS2108_1: + case MPI2_MFGPAGE_DEVID_SAS2108_2: + case MPI2_MFGPAGE_DEVID_SAS2108_3: + case MPI2_MFGPAGE_DEVID_SAS2116_1: + case MPI2_MFGPAGE_DEVID_SAS2116_2: + case MPI2_MFGPAGE_DEVID_SAS2208_1: + case MPI2_MFGPAGE_DEVID_SAS2208_2: + case MPI2_MFGPAGE_DEVID_SAS2208_3: + case MPI2_MFGPAGE_DEVID_SAS2208_4: + case MPI2_MFGPAGE_DEVID_SAS2208_5: + case MPI2_MFGPAGE_DEVID_SAS2208_6: + case MPI2_MFGPAGE_DEVID_SAS2308_1: + case MPI2_MFGPAGE_DEVID_SAS2308_2: + case MPI2_MFGPAGE_DEVID_SAS2308_3: + return MPI2_VERSION; + case MPI25_MFGPAGE_DEVID_SAS3004: + case MPI25_MFGPAGE_DEVID_SAS3008: + case MPI25_MFGPAGE_DEVID_SAS3108_1: + case MPI25_MFGPAGE_DEVID_SAS3108_2: + case MPI25_MFGPAGE_DEVID_SAS3108_5: + case MPI25_MFGPAGE_DEVID_SAS3108_6: + return MPI25_VERSION; + } + return 0; +} + /** * _scsih_probe - attach and add scsi host * @pdev: PCI device struct @@ -7994,26 +8435,72 @@ _scsih_scan_finished(struct Scsi_Host *shost, unsigned long time) * * Returns 0 success, anything else error. */ -static int +int _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct MPT3SAS_ADAPTER *ioc; - struct Scsi_Host *shost; + struct Scsi_Host *shost = NULL; int rv; + u16 hba_mpi_version; - shost = scsi_host_alloc(&scsih_driver_template, - sizeof(struct MPT3SAS_ADAPTER)); - if (!shost) + /* Determine in which MPI version class this pci device belongs */ + hba_mpi_version = _scsih_determine_hba_mpi_version(pdev); + if (hba_mpi_version == 0) return -ENODEV; - /* init local params */ - ioc = shost_priv(shost); - memset(ioc, 0, sizeof(struct MPT3SAS_ADAPTER)); + /* Enumerate only SAS 2.0 HBA's if hbas_to_enumerate is one, + * for other generation HBA's return with -ENODEV + */ + if ((hbas_to_enumerate == 1) && (hba_mpi_version != MPI2_VERSION)) + return -ENODEV; + + /* Enumerate only SAS 3.0 HBA's if hbas_to_enumerate is two, + * for other generation HBA's return with -ENODEV + */ + if ((hbas_to_enumerate == 2) && (hba_mpi_version != MPI25_VERSION)) + return -ENODEV; + + switch (hba_mpi_version) { + case MPI2_VERSION: + /* Use mpt2sas driver host template for SAS 2.0 HBA's */ + shost = scsi_host_alloc(&mpt2sas_driver_template, + sizeof(struct MPT3SAS_ADAPTER)); + if (!shost) + return -ENODEV; + ioc = shost_priv(shost); + memset(ioc, 0, sizeof(struct MPT3SAS_ADAPTER)); + ioc->hba_mpi_version_belonged = hba_mpi_version; + ioc->id = mpt2_ids++; + sprintf(ioc->driver_name, "%s", MPT2SAS_DRIVER_NAME); + if (pdev->device == MPI2_MFGPAGE_DEVID_SSS6200) { + ioc->is_warpdrive = 1; + ioc->hide_ir_msg = 1; + } else + ioc->mfg_pg10_hide_flag = MFG_PAGE10_EXPOSE_ALL_DISKS; + break; + case MPI25_VERSION: + /* Use mpt3sas driver host template for SAS 3.0 HBA's */ + shost = scsi_host_alloc(&mpt3sas_driver_template, + sizeof(struct MPT3SAS_ADAPTER)); + if (!shost) + return -ENODEV; + ioc = shost_priv(shost); + memset(ioc, 0, sizeof(struct MPT3SAS_ADAPTER)); + ioc->hba_mpi_version_belonged = hba_mpi_version; + ioc->id = mpt3_ids++; + sprintf(ioc->driver_name, "%s", MPT3SAS_DRIVER_NAME); + if (pdev->revision >= SAS3_PCI_DEVICE_C0_REVISION) + ioc->msix96_vector = 1; + break; + default: + return -ENODEV; + } + INIT_LIST_HEAD(&ioc->list); + spin_lock(&gioc_lock); list_add_tail(&ioc->list, &mpt3sas_ioc_list); + spin_unlock(&gioc_lock); ioc->shost = shost; - ioc->id = mpt_ids++; - sprintf(ioc->name, "%s%d", MPT3SAS_DRIVER_NAME, ioc->id); ioc->pdev = pdev; ioc->scsi_io_cb_idx = scsi_io_cb_idx; ioc->tm_cb_idx = tm_cb_idx; @@ -8030,6 +8517,8 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) ioc->schedule_dead_ioc_flush_running_cmds = &_scsih_flush_running_cmds; /* misc semaphores and spin locks */ mutex_init(&ioc->reset_in_progress_mutex); + /* initializing pci_access_mutex lock */ + mutex_init(&ioc->pci_access_mutex); spin_lock_init(&ioc->ioc_reset_in_progress_lock); spin_lock_init(&ioc->scsi_lookup_lock); spin_lock_init(&ioc->sas_device_lock); @@ -8048,6 +8537,8 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) INIT_LIST_HEAD(&ioc->delayed_tr_volume_list); INIT_LIST_HEAD(&ioc->reply_queue_list); + sprintf(ioc->name, "%s_cm%d", ioc->driver_name, ioc->id); + /* init shost parameters */ shost->max_cmd_len = 32; shost->max_lun = max_lun; @@ -8086,7 +8577,7 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) /* event thread */ snprintf(ioc->firmware_event_name, sizeof(ioc->firmware_event_name), - "fw_event%d", ioc->id); + "fw_event_%s%d", ioc->driver_name, ioc->id); ioc->firmware_event_thread = alloc_ordered_workqueue( ioc->firmware_event_name, WQ_MEM_RECLAIM); if (!ioc->firmware_event_thread) { @@ -8103,6 +8594,21 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) rv = -ENODEV; goto out_attach_fail; } + + if (ioc->is_warpdrive) { + if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_EXPOSE_ALL_DISKS) + ioc->hide_drives = 0; + else if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_HIDE_ALL_DISKS) + ioc->hide_drives = 1; + else { + if (mpt3sas_get_num_volumes(ioc)) + ioc->hide_drives = 1; + else + ioc->hide_drives = 0; + } + } else + ioc->hide_drives = 0; + rv = scsi_add_host(shost, &pdev->dev); if (rv) { pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", @@ -8117,21 +8623,23 @@ out_add_shost_fail: out_attach_fail: destroy_workqueue(ioc->firmware_event_thread); out_thread_fail: + spin_lock(&gioc_lock); list_del(&ioc->list); + spin_unlock(&gioc_lock); scsi_host_put(shost); return rv; } #ifdef CONFIG_PM /** - * _scsih_suspend - power management suspend main entry point + * 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) +int +scsih_suspend(struct pci_dev *pdev, pm_message_t state) { struct Scsi_Host *shost = pci_get_drvdata(pdev); struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); @@ -8152,13 +8660,13 @@ _scsih_suspend(struct pci_dev *pdev, pm_message_t state) } /** - * _scsih_resume - power management resume main entry point + * 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) +int +scsih_resume(struct pci_dev *pdev) { struct Scsi_Host *shost = pci_get_drvdata(pdev); struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); @@ -8185,7 +8693,7 @@ _scsih_resume(struct pci_dev *pdev) #endif /* CONFIG_PM */ /** - * _scsih_pci_error_detected - Called when a PCI error is detected. + * scsih_pci_error_detected - Called when a PCI error is detected. * @pdev: PCI device struct * @state: PCI channel state * @@ -8194,8 +8702,8 @@ _scsih_resume(struct pci_dev *pdev) * Return value: * PCI_ERS_RESULT_NEED_RESET or PCI_ERS_RESULT_DISCONNECT */ -static pci_ers_result_t -_scsih_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) +pci_ers_result_t +scsih_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) { struct Scsi_Host *shost = pci_get_drvdata(pdev); struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); @@ -8224,15 +8732,15 @@ _scsih_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) } /** - * _scsih_pci_slot_reset - Called when PCI slot has been reset. + * scsih_pci_slot_reset - Called when PCI slot has been reset. * @pdev: PCI device struct * * Description: This routine is called by the pci error recovery * code after the PCI slot has been reset, just before we * should resume normal operations. */ -static pci_ers_result_t -_scsih_pci_slot_reset(struct pci_dev *pdev) +pci_ers_result_t +scsih_pci_slot_reset(struct pci_dev *pdev) { struct Scsi_Host *shost = pci_get_drvdata(pdev); struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); @@ -8261,15 +8769,15 @@ _scsih_pci_slot_reset(struct pci_dev *pdev) } /** - * _scsih_pci_resume() - resume normal ops after PCI reset + * scsih_pci_resume() - resume normal ops after PCI reset * @pdev: pointer to PCI device * * Called when the error recovery driver tells us that its * OK to resume normal operation. Use completion to allow * halted scsi ops to resume. */ -static void -_scsih_pci_resume(struct pci_dev *pdev) +void +scsih_pci_resume(struct pci_dev *pdev) { struct Scsi_Host *shost = pci_get_drvdata(pdev); struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); @@ -8282,11 +8790,11 @@ _scsih_pci_resume(struct pci_dev *pdev) } /** - * _scsih_pci_mmio_enabled - Enable MMIO and dump debug registers + * scsih_pci_mmio_enabled - Enable MMIO and dump debug registers * @pdev: pointer to PCI device */ -static pci_ers_result_t -_scsih_pci_mmio_enabled(struct pci_dev *pdev) +pci_ers_result_t +scsih_pci_mmio_enabled(struct pci_dev *pdev) { struct Scsi_Host *shost = pci_get_drvdata(pdev); struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); @@ -8300,61 +8808,99 @@ _scsih_pci_mmio_enabled(struct pci_dev *pdev) return PCI_ERS_RESULT_NEED_RESET; } -/* raid transport support */ -static struct raid_function_template mpt3sas_raid_functions = { - .cookie = &scsih_driver_template, - .is_raid = _scsih_is_raid, - .get_resync = _scsih_get_resync, - .get_state = _scsih_get_state, +/* + * The pci device ids are defined in mpi/mpi2_cnfg.h. + */ +static const struct pci_device_id mpt3sas_pci_table[] = { + /* Spitfire ~ 2004 */ + { 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 }, + /* Meteor ~ 2116 */ + { 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 }, + /* Thunderbolt ~ 2208 */ + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_1, + PCI_ANY_ID, PCI_ANY_ID }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_2, + PCI_ANY_ID, PCI_ANY_ID }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_3, + PCI_ANY_ID, PCI_ANY_ID }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_4, + PCI_ANY_ID, PCI_ANY_ID }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_5, + PCI_ANY_ID, PCI_ANY_ID }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_6, + PCI_ANY_ID, PCI_ANY_ID }, + /* Mustang ~ 2308 */ + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_1, + PCI_ANY_ID, PCI_ANY_ID }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_2, + PCI_ANY_ID, PCI_ANY_ID }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_3, + PCI_ANY_ID, PCI_ANY_ID }, + /* SSS6200 */ + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SSS6200, + PCI_ANY_ID, PCI_ANY_ID }, + /* Fury ~ 3004 and 3008 */ + { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3004, + PCI_ANY_ID, PCI_ANY_ID }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3008, + PCI_ANY_ID, PCI_ANY_ID }, + /* Invader ~ 3108 */ + { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_1, + PCI_ANY_ID, PCI_ANY_ID }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_2, + PCI_ANY_ID, PCI_ANY_ID }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_5, + PCI_ANY_ID, PCI_ANY_ID }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_6, + PCI_ANY_ID, PCI_ANY_ID }, + {0} /* Terminating entry */ }; +MODULE_DEVICE_TABLE(pci, mpt3sas_pci_table); -static struct pci_error_handlers _scsih_err_handler = { - .error_detected = _scsih_pci_error_detected, - .mmio_enabled = _scsih_pci_mmio_enabled, - .slot_reset = _scsih_pci_slot_reset, - .resume = _scsih_pci_resume, +static struct pci_error_handlers _mpt3sas_err_handler = { + .error_detected = scsih_pci_error_detected, + .mmio_enabled = scsih_pci_mmio_enabled, + .slot_reset = scsih_pci_slot_reset, + .resume = scsih_pci_resume, }; -static struct pci_driver scsih_driver = { +static struct pci_driver mpt3sas_driver = { .name = MPT3SAS_DRIVER_NAME, - .id_table = scsih_pci_table, + .id_table = mpt3sas_pci_table, .probe = _scsih_probe, - .remove = _scsih_remove, - .shutdown = _scsih_shutdown, - .err_handler = &_scsih_err_handler, + .remove = scsih_remove, + .shutdown = scsih_shutdown, + .err_handler = &_mpt3sas_err_handler, #ifdef CONFIG_PM - .suspend = _scsih_suspend, - .resume = _scsih_resume, + .suspend = scsih_suspend, + .resume = scsih_resume, #endif }; - /** - * _scsih_init - main entry point for this driver. + * scsih_init - main entry point for this driver. * * Returns 0 success, anything else error. */ -static int __init -_scsih_init(void) +int +scsih_init(void) { - int error; - - mpt_ids = 0; - - pr_info("%s version %s loaded\n", MPT3SAS_DRIVER_NAME, - MPT3SAS_DRIVER_VERSION); - - mpt3sas_transport_template = - sas_attach_transport(&mpt3sas_transport_functions); - if (!mpt3sas_transport_template) - return -ENODEV; - -/* raid transport support */ - mpt3sas_raid_template = raid_class_attach(&mpt3sas_raid_functions); - if (!mpt3sas_raid_template) { - sas_release_transport(mpt3sas_transport_template); - return -ENODEV; - } + mpt2_ids = 0; + mpt3_ids = 0; mpt3sas_base_initialize_callback_handler(); @@ -8392,33 +8938,17 @@ _scsih_init(void) tm_sas_control_cb_idx = mpt3sas_base_register_callback_handler( _scsih_sas_control_complete); - mpt3sas_ctl_init(); - - error = pci_register_driver(&scsih_driver); - if (error) { - /* raid transport support */ - raid_class_release(mpt3sas_raid_template); - sas_release_transport(mpt3sas_transport_template); - } - - return error; + return 0; } /** - * _scsih_exit - exit point for this driver (when it is a module). + * scsih_exit - exit point for this driver (when it is a module). * * Returns 0 success, anything else error. */ -static void __exit -_scsih_exit(void) +void +scsih_exit(void) { - pr_info("mpt3sas version %s unloading\n", - MPT3SAS_DRIVER_VERSION); - - mpt3sas_ctl_exit(); - - pci_unregister_driver(&scsih_driver); - mpt3sas_base_release_callback_handler(scsi_io_cb_idx); mpt3sas_base_release_callback_handler(tm_cb_idx); @@ -8434,9 +8964,86 @@ _scsih_exit(void) mpt3sas_base_release_callback_handler(tm_sas_control_cb_idx); /* raid transport support */ - raid_class_release(mpt3sas_raid_template); + if (hbas_to_enumerate != 1) + raid_class_release(mpt3sas_raid_template); + if (hbas_to_enumerate != 2) + raid_class_release(mpt2sas_raid_template); sas_release_transport(mpt3sas_transport_template); } -module_init(_scsih_init); -module_exit(_scsih_exit); +/** + * _mpt3sas_init - main entry point for this driver. + * + * Returns 0 success, anything else error. + */ +static int __init +_mpt3sas_init(void) +{ + int error; + + pr_info("%s version %s loaded\n", MPT3SAS_DRIVER_NAME, + MPT3SAS_DRIVER_VERSION); + + mpt3sas_transport_template = + sas_attach_transport(&mpt3sas_transport_functions); + if (!mpt3sas_transport_template) + return -ENODEV; + + /* No need attach mpt3sas raid functions template + * if hbas_to_enumarate value is one. + */ + if (hbas_to_enumerate != 1) { + mpt3sas_raid_template = + raid_class_attach(&mpt3sas_raid_functions); + if (!mpt3sas_raid_template) { + sas_release_transport(mpt3sas_transport_template); + return -ENODEV; + } + } + + /* No need to attach mpt2sas raid functions template + * if hbas_to_enumarate value is two + */ + if (hbas_to_enumerate != 2) { + mpt2sas_raid_template = + raid_class_attach(&mpt2sas_raid_functions); + if (!mpt2sas_raid_template) { + sas_release_transport(mpt3sas_transport_template); + return -ENODEV; + } + } + + error = scsih_init(); + if (error) { + scsih_exit(); + return error; + } + + mpt3sas_ctl_init(hbas_to_enumerate); + + error = pci_register_driver(&mpt3sas_driver); + if (error) + scsih_exit(); + + return error; +} + +/** + * _mpt3sas_exit - exit point for this driver (when it is a module). + * + */ +static void __exit +_mpt3sas_exit(void) +{ + pr_info("mpt3sas version %s unloading\n", + MPT3SAS_DRIVER_VERSION); + + pci_unregister_driver(&mpt3sas_driver); + + mpt3sas_ctl_exit(hbas_to_enumerate); + + scsih_exit(); +} + +module_init(_mpt3sas_init); +module_exit(_mpt3sas_exit); diff --git a/drivers/scsi/mpt3sas/mpt3sas_transport.c b/drivers/scsi/mpt3sas/mpt3sas_transport.c index 70fd019e7ee5..ca36d7ea0964 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_transport.c +++ b/drivers/scsi/mpt3sas/mpt3sas_transport.c @@ -734,7 +734,7 @@ mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, u16 handle, rphy->identify = mpt3sas_port->remote_identify; if (mpt3sas_port->remote_identify.device_type == SAS_END_DEVICE) { - sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc, + sas_device = mpt3sas_get_sdev_by_addr(ioc, mpt3sas_port->remote_identify.sas_address); if (!sas_device) { dfailprintk(ioc, printk(MPT3SAS_FMT @@ -750,8 +750,10 @@ mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, u16 handle, ioc->name, __FILE__, __LINE__, __func__); } - if (mpt3sas_port->remote_identify.device_type == SAS_END_DEVICE) + if (mpt3sas_port->remote_identify.device_type == SAS_END_DEVICE) { sas_device->pend_sas_rphy_add = 0; + sas_device_put(sas_device); + } if ((ioc->logging_level & MPT_DEBUG_TRANSPORT)) dev_printk(KERN_INFO, &rphy->dev, @@ -1324,15 +1326,17 @@ _transport_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier) int rc; spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc, + sas_device = __mpt3sas_get_sdev_by_addr(ioc, rphy->identify.sas_address); if (sas_device) { *identifier = sas_device->enclosure_logical_id; rc = 0; + sas_device_put(sas_device); } else { *identifier = 0; rc = -ENXIO; } + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); return rc; } @@ -1352,12 +1356,14 @@ _transport_get_bay_identifier(struct sas_rphy *rphy) int rc; spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc, + sas_device = __mpt3sas_get_sdev_by_addr(ioc, rphy->identify.sas_address); - if (sas_device) + if (sas_device) { rc = sas_device->slot; - else + sas_device_put(sas_device); + } else { rc = -ENXIO; + } spin_unlock_irqrestore(&ioc->sas_device_lock, flags); return rc; } diff --git a/drivers/scsi/mpt3sas/mpt3sas_warpdrive.c b/drivers/scsi/mpt3sas/mpt3sas_warpdrive.c new file mode 100644 index 000000000000..540bd5005149 --- /dev/null +++ b/drivers/scsi/mpt3sas/mpt3sas_warpdrive.c @@ -0,0 +1,344 @@ +/* + * Scsi Host Layer for MPT (Message Passing Technology) based controllers + * + * Copyright (C) 2012-2014 LSI Corporation + * Copyright (C) 2013-2015 Avago Technologies + * (mailto: MPT-FusionLinux.pdl@avagotech.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. + */ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/types.h> +#include <asm/unaligned.h> + +#include "mpt3sas_base.h" + +/** + * _warpdrive_disable_ddio - Disable direct I/O for all the volumes + * @ioc: per adapter object + */ +static void +_warpdrive_disable_ddio(struct MPT3SAS_ADAPTER *ioc) +{ + Mpi2RaidVolPage1_t vol_pg1; + Mpi2ConfigReply_t mpi_reply; + struct _raid_device *raid_device; + u16 handle; + u16 ioc_status; + unsigned long flags; + + handle = 0xFFFF; + while (!(mpt3sas_config_get_raid_volume_pg1(ioc, &mpi_reply, + &vol_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(vol_pg1.DevHandle); + spin_lock_irqsave(&ioc->raid_device_lock, flags); + raid_device = mpt3sas_raid_device_find_by_handle(ioc, handle); + if (raid_device) + raid_device->direct_io_enabled = 0; + spin_unlock_irqrestore(&ioc->raid_device_lock, flags); + } + return; +} + + +/** + * mpt3sas_get_num_volumes - Get number of volumes in the ioc + * @ioc: per adapter object + */ +u8 +mpt3sas_get_num_volumes(struct MPT3SAS_ADAPTER *ioc) +{ + Mpi2RaidVolPage1_t vol_pg1; + Mpi2ConfigReply_t mpi_reply; + u16 handle; + u8 vol_cnt = 0; + u16 ioc_status; + + handle = 0xFFFF; + while (!(mpt3sas_config_get_raid_volume_pg1(ioc, &mpi_reply, + &vol_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; + vol_cnt++; + handle = le16_to_cpu(vol_pg1.DevHandle); + } + return vol_cnt; +} + + +/** + * mpt3sas_init_warpdrive_properties - Set properties for warpdrive direct I/O. + * @ioc: per adapter object + * @raid_device: the raid_device object + */ +void +mpt3sas_init_warpdrive_properties(struct MPT3SAS_ADAPTER *ioc, + struct _raid_device *raid_device) +{ + Mpi2RaidVolPage0_t *vol_pg0; + Mpi2RaidPhysDiskPage0_t pd_pg0; + Mpi2ConfigReply_t mpi_reply; + u16 sz; + u8 num_pds, count; + unsigned long stripe_sz, block_sz; + u8 stripe_exp, block_exp; + u64 dev_max_lba; + + if (!ioc->is_warpdrive) + return; + + if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_EXPOSE_ALL_DISKS) { + pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled " + "globally as drives are exposed\n", ioc->name); + return; + } + if (mpt3sas_get_num_volumes(ioc) > 1) { + _warpdrive_disable_ddio(ioc); + pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled " + "globally as number of drives > 1\n", ioc->name); + return; + } + if ((mpt3sas_config_get_number_pds(ioc, raid_device->handle, + &num_pds)) || !num_pds) { + pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled " + "Failure in computing number of drives\n", ioc->name); + return; + } + + sz = offsetof(Mpi2RaidVolPage0_t, PhysDisk) + (num_pds * + sizeof(Mpi2RaidVol0PhysDisk_t)); + vol_pg0 = kzalloc(sz, GFP_KERNEL); + if (!vol_pg0) { + pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled " + "Memory allocation failure for RVPG0\n", ioc->name); + return; + } + + if ((mpt3sas_config_get_raid_volume_pg0(ioc, &mpi_reply, vol_pg0, + MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, sz))) { + pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled " + "Failure in retrieving RVPG0\n", ioc->name); + kfree(vol_pg0); + return; + } + + /* + * WARPDRIVE:If number of physical disks in a volume exceeds the max pds + * assumed for WARPDRIVE, disable direct I/O + */ + if (num_pds > MPT_MAX_WARPDRIVE_PDS) { + pr_warn(MPT3SAS_FMT "WarpDrive : Direct IO is disabled " + "for the drive with handle(0x%04x): num_mem=%d, " + "max_mem_allowed=%d\n", ioc->name, raid_device->handle, + num_pds, MPT_MAX_WARPDRIVE_PDS); + kfree(vol_pg0); + return; + } + for (count = 0; count < num_pds; count++) { + if (mpt3sas_config_get_phys_disk_pg0(ioc, &mpi_reply, + &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM, + vol_pg0->PhysDisk[count].PhysDiskNum) || + pd_pg0.DevHandle == MPT3SAS_INVALID_DEVICE_HANDLE) { + pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is " + "disabled for the drive with handle(0x%04x) member" + "handle retrieval failed for member number=%d\n", + ioc->name, raid_device->handle, + vol_pg0->PhysDisk[count].PhysDiskNum); + goto out_error; + } + /* Disable direct I/O if member drive lba exceeds 4 bytes */ + dev_max_lba = le64_to_cpu(pd_pg0.DeviceMaxLBA); + if (dev_max_lba >> 32) { + pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is " + "disabled for the drive with handle(0x%04x) member" + " handle (0x%04x) unsupported max lba 0x%016llx\n", + ioc->name, raid_device->handle, + le16_to_cpu(pd_pg0.DevHandle), + (unsigned long long)dev_max_lba); + goto out_error; + } + + raid_device->pd_handle[count] = le16_to_cpu(pd_pg0.DevHandle); + } + + /* + * Assumption for WD: Direct I/O is not supported if the volume is + * not RAID0 + */ + if (raid_device->volume_type != MPI2_RAID_VOL_TYPE_RAID0) { + pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled " + "for the drive with handle(0x%04x): type=%d, " + "s_sz=%uK, blk_size=%u\n", ioc->name, + raid_device->handle, raid_device->volume_type, + (le32_to_cpu(vol_pg0->StripeSize) * + le16_to_cpu(vol_pg0->BlockSize)) / 1024, + le16_to_cpu(vol_pg0->BlockSize)); + goto out_error; + } + + stripe_sz = le32_to_cpu(vol_pg0->StripeSize); + stripe_exp = find_first_bit(&stripe_sz, 32); + if (stripe_exp == 32) { + pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled " + "for the drive with handle(0x%04x) invalid stripe sz %uK\n", + ioc->name, raid_device->handle, + (le32_to_cpu(vol_pg0->StripeSize) * + le16_to_cpu(vol_pg0->BlockSize)) / 1024); + goto out_error; + } + raid_device->stripe_exponent = stripe_exp; + block_sz = le16_to_cpu(vol_pg0->BlockSize); + block_exp = find_first_bit(&block_sz, 16); + if (block_exp == 16) { + pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled " + "for the drive with handle(0x%04x) invalid block sz %u\n", + ioc->name, raid_device->handle, + le16_to_cpu(vol_pg0->BlockSize)); + goto out_error; + } + raid_device->block_exponent = block_exp; + raid_device->direct_io_enabled = 1; + + pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is Enabled for the drive" + " with handle(0x%04x)\n", ioc->name, raid_device->handle); + /* + * WARPDRIVE: Though the following fields are not used for direct IO, + * stored for future purpose: + */ + raid_device->max_lba = le64_to_cpu(vol_pg0->MaxLBA); + raid_device->stripe_sz = le32_to_cpu(vol_pg0->StripeSize); + raid_device->block_sz = le16_to_cpu(vol_pg0->BlockSize); + + + kfree(vol_pg0); + return; + +out_error: + raid_device->direct_io_enabled = 0; + for (count = 0; count < num_pds; count++) + raid_device->pd_handle[count] = 0; + kfree(vol_pg0); + return; +} + +/** + * mpt3sas_scsi_direct_io_get - returns direct io flag + * @ioc: per adapter object + * @smid: system request message index + * + * Returns the smid stored scmd pointer. + */ +inline u8 +mpt3sas_scsi_direct_io_get(struct MPT3SAS_ADAPTER *ioc, u16 smid) +{ + return ioc->scsi_lookup[smid - 1].direct_io; +} + +/** + * mpt3sas_scsi_direct_io_set - sets direct io flag + * @ioc: per adapter object + * @smid: system request message index + * @direct_io: Zero or non-zero value to set in the direct_io flag + * + * Returns Nothing. + */ +inline void +mpt3sas_scsi_direct_io_set(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 direct_io) +{ + ioc->scsi_lookup[smid - 1].direct_io = direct_io; +} + +/** + * mpt3sas_setup_direct_io - setup MPI request for WARPDRIVE Direct I/O + * @ioc: per adapter object + * @scmd: pointer to scsi command object + * @raid_device: pointer to raid device data structure + * @mpi_request: pointer to the SCSI_IO reqest message frame + * @smid: system request message index + * + * Returns nothing + */ +void +mpt3sas_setup_direct_io(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, + struct _raid_device *raid_device, Mpi2SCSIIORequest_t *mpi_request, + u16 smid) +{ + sector_t v_lba, p_lba, stripe_off, column, io_size; + u32 stripe_sz, stripe_exp; + u8 num_pds, cmd = scmd->cmnd[0]; + + if (cmd != READ_10 && cmd != WRITE_10 && + cmd != READ_16 && cmd != WRITE_16) + return; + + if (cmd == READ_10 || cmd == WRITE_10) + v_lba = get_unaligned_be32(&mpi_request->CDB.CDB32[2]); + else + v_lba = get_unaligned_be64(&mpi_request->CDB.CDB32[2]); + + io_size = scsi_bufflen(scmd) >> raid_device->block_exponent; + + if (v_lba + io_size - 1 > raid_device->max_lba) + return; + + stripe_sz = raid_device->stripe_sz; + stripe_exp = raid_device->stripe_exponent; + stripe_off = v_lba & (stripe_sz - 1); + + /* Return unless IO falls within a stripe */ + if (stripe_off + io_size > stripe_sz) + return; + + num_pds = raid_device->num_pds; + p_lba = v_lba >> stripe_exp; + column = sector_div(p_lba, num_pds); + p_lba = (p_lba << stripe_exp) + stripe_off; + mpi_request->DevHandle = cpu_to_le16(raid_device->pd_handle[column]); + + if (cmd == READ_10 || cmd == WRITE_10) + put_unaligned_be32(lower_32_bits(p_lba), + &mpi_request->CDB.CDB32[2]); + else + put_unaligned_be64(p_lba, &mpi_request->CDB.CDB32[2]); + + mpt3sas_scsi_direct_io_set(ioc, smid, 1); +} diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c index e2d555c1bffc..90fdf0e859e3 100644 --- a/drivers/scsi/mvsas/mv_init.c +++ b/drivers/scsi/mvsas/mv_init.c @@ -65,7 +65,6 @@ static struct scsi_host_template mvs_sht = { .target_destroy = sas_target_destroy, .ioctl = sas_ioctl, .shost_attrs = mvst_host_attrs, - .use_blk_tags = 1, .track_queue_depth = 1, }; @@ -641,9 +640,9 @@ static void mvs_pci_remove(struct pci_dev *pdev) tasklet_kill(&((struct mvs_prv_info *)sha->lldd_ha)->mv_tasklet); #endif + scsi_remove_host(mvi->shost); sas_unregister_ha(sha); sas_remove_host(mvi->shost); - scsi_remove_host(mvi->shost); MVS_CHIP_DISP->interrupt_disable(mvi); free_irq(mvi->pdev->irq, sha); diff --git a/drivers/scsi/mvumi.c b/drivers/scsi/mvumi.c index 3e6b866759fe..02360de6b7e0 100644 --- a/drivers/scsi/mvumi.c +++ b/drivers/scsi/mvumi.c @@ -31,6 +31,7 @@ #include <linux/spinlock.h> #include <linux/interrupt.h> #include <linux/delay.h> +#include <linux/ktime.h> #include <linux/blkdev.h> #include <linux/io.h> #include <scsi/scsi.h> @@ -858,8 +859,8 @@ static void mvumi_hs_build_page(struct mvumi_hba *mhba, struct mvumi_hs_page2 *hs_page2; struct mvumi_hs_page4 *hs_page4; struct mvumi_hs_page3 *hs_page3; - struct timeval time; - unsigned int local_time; + u64 time; + u64 local_time; switch (hs_header->page_code) { case HS_PAGE_HOST_INFO: @@ -877,9 +878,8 @@ static void mvumi_hs_build_page(struct mvumi_hba *mhba, hs_page2->slot_number = 0; hs_page2->intr_level = 0; hs_page2->intr_vector = 0; - do_gettimeofday(&time); - local_time = (unsigned int) (time.tv_sec - - (sys_tz.tz_minuteswest * 60)); + time = ktime_get_real_seconds(); + local_time = (time - (sys_tz.tz_minuteswest * 60)); hs_page2->seconds_since1970 = local_time; hs_header->checksum = mvumi_calculate_checksum(hs_header, hs_header->frame_length); diff --git a/drivers/scsi/pm8001/pm8001_defs.h b/drivers/scsi/pm8001/pm8001_defs.h index f14ec6e042b9..199527dbaaa1 100644 --- a/drivers/scsi/pm8001/pm8001_defs.h +++ b/drivers/scsi/pm8001/pm8001_defs.h @@ -51,6 +51,8 @@ enum chip_flavors { chip_8076, chip_8077, chip_8006, + chip_8070, + chip_8072 }; enum phy_speed { diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c index 5c0356fb6310..062ab34b86f8 100644 --- a/drivers/scsi/pm8001/pm8001_init.c +++ b/drivers/scsi/pm8001/pm8001_init.c @@ -58,6 +58,8 @@ static const struct pm8001_chip_info pm8001_chips[] = { [chip_8076] = {0, 16, &pm8001_80xx_dispatch,}, [chip_8077] = {0, 16, &pm8001_80xx_dispatch,}, [chip_8006] = {0, 16, &pm8001_80xx_dispatch,}, + [chip_8070] = {0, 8, &pm8001_80xx_dispatch,}, + [chip_8072] = {0, 16, &pm8001_80xx_dispatch,}, }; static int pm8001_id; @@ -88,7 +90,6 @@ static struct scsi_host_template pm8001_sht = { .target_destroy = sas_target_destroy, .ioctl = sas_ioctl, .shost_attrs = pm8001_host_attrs, - .use_blk_tags = 1, .track_queue_depth = 1, }; @@ -480,7 +481,8 @@ static struct pm8001_hba_info *pm8001_pci_alloc(struct pci_dev *pdev, #ifdef PM8001_USE_TASKLET /* Tasklet for non msi-x interrupt handler */ - if ((!pdev->msix_cap) || (pm8001_ha->chip_id == chip_8001)) + if ((!pdev->msix_cap || !pci_msi_enabled()) + || (pm8001_ha->chip_id == chip_8001)) tasklet_init(&pm8001_ha->tasklet[0], pm8001_tasklet, (unsigned long)&(pm8001_ha->irq_vector[0])); else @@ -634,6 +636,11 @@ static void pm8001_init_sas_add(struct pm8001_hba_info *pm8001_ha) payload.minor_function = 0; payload.length = 128; } + } else if ((pm8001_ha->chip_id == chip_8070 || + pm8001_ha->chip_id == chip_8072) && + pm8001_ha->pdev->subsystem_vendor == PCI_VENDOR_ID_ATTO) { + payload.minor_function = 4; + payload.length = 4096; } else { payload.minor_function = 1; payload.length = 4096; @@ -660,6 +667,11 @@ static void pm8001_init_sas_add(struct pm8001_hba_info *pm8001_ha) else if (deviceid == 0x0042) pm8001_ha->sas_addr[j] = payload.func_specific[0x010 + i]; + } else if ((pm8001_ha->chip_id == chip_8070 || + pm8001_ha->chip_id == chip_8072) && + pm8001_ha->pdev->subsystem_vendor == PCI_VENDOR_ID_ATTO) { + pm8001_ha->sas_addr[j] = + payload.func_specific[0x010 + i]; } else pm8001_ha->sas_addr[j] = payload.func_specific[0x804 + i]; @@ -720,6 +732,153 @@ static int pm8001_get_phy_settings_info(struct pm8001_hba_info *pm8001_ha) return 0; } +struct pm8001_mpi3_phy_pg_trx_config { + u32 LaneLosCfg; + u32 LanePgaCfg1; + u32 LanePisoCfg1; + u32 LanePisoCfg2; + u32 LanePisoCfg3; + u32 LanePisoCfg4; + u32 LanePisoCfg5; + u32 LanePisoCfg6; + u32 LaneBctCtrl; +}; + +/** + * pm8001_get_internal_phy_settings : Retrieves the internal PHY settings + * @pm8001_ha : our adapter + * @phycfg : PHY config page to populate + */ +static +void pm8001_get_internal_phy_settings(struct pm8001_hba_info *pm8001_ha, + struct pm8001_mpi3_phy_pg_trx_config *phycfg) +{ + phycfg->LaneLosCfg = 0x00000132; + phycfg->LanePgaCfg1 = 0x00203949; + phycfg->LanePisoCfg1 = 0x000000FF; + phycfg->LanePisoCfg2 = 0xFF000001; + phycfg->LanePisoCfg3 = 0xE7011300; + phycfg->LanePisoCfg4 = 0x631C40C0; + phycfg->LanePisoCfg5 = 0xF8102036; + phycfg->LanePisoCfg6 = 0xF74A1000; + phycfg->LaneBctCtrl = 0x00FB33F8; +} + +/** + * pm8001_get_external_phy_settings : Retrieves the external PHY settings + * @pm8001_ha : our adapter + * @phycfg : PHY config page to populate + */ +static +void pm8001_get_external_phy_settings(struct pm8001_hba_info *pm8001_ha, + struct pm8001_mpi3_phy_pg_trx_config *phycfg) +{ + phycfg->LaneLosCfg = 0x00000132; + phycfg->LanePgaCfg1 = 0x00203949; + phycfg->LanePisoCfg1 = 0x000000FF; + phycfg->LanePisoCfg2 = 0xFF000001; + phycfg->LanePisoCfg3 = 0xE7011300; + phycfg->LanePisoCfg4 = 0x63349140; + phycfg->LanePisoCfg5 = 0xF8102036; + phycfg->LanePisoCfg6 = 0xF80D9300; + phycfg->LaneBctCtrl = 0x00FB33F8; +} + +/** + * pm8001_get_phy_mask : Retrieves the mask that denotes if a PHY is int/ext + * @pm8001_ha : our adapter + * @phymask : The PHY mask + */ +static +void pm8001_get_phy_mask(struct pm8001_hba_info *pm8001_ha, int *phymask) +{ + switch (pm8001_ha->pdev->subsystem_device) { + case 0x0070: /* H1280 - 8 external 0 internal */ + case 0x0072: /* H12F0 - 16 external 0 internal */ + *phymask = 0x0000; + break; + + case 0x0071: /* H1208 - 0 external 8 internal */ + case 0x0073: /* H120F - 0 external 16 internal */ + *phymask = 0xFFFF; + break; + + case 0x0080: /* H1244 - 4 external 4 internal */ + *phymask = 0x00F0; + break; + + case 0x0081: /* H1248 - 4 external 8 internal */ + *phymask = 0x0FF0; + break; + + case 0x0082: /* H1288 - 8 external 8 internal */ + *phymask = 0xFF00; + break; + + default: + PM8001_INIT_DBG(pm8001_ha, + pm8001_printk("Unknown subsystem device=0x%.04x", + pm8001_ha->pdev->subsystem_device)); + } +} + +/** + * pm8001_set_phy_settings_ven_117c_12Gb : Configure ATTO 12Gb PHY settings + * @pm8001_ha : our adapter + */ +static +int pm8001_set_phy_settings_ven_117c_12G(struct pm8001_hba_info *pm8001_ha) +{ + struct pm8001_mpi3_phy_pg_trx_config phycfg_int; + struct pm8001_mpi3_phy_pg_trx_config phycfg_ext; + int phymask = 0; + int i = 0; + + memset(&phycfg_int, 0, sizeof(phycfg_int)); + memset(&phycfg_ext, 0, sizeof(phycfg_ext)); + + pm8001_get_internal_phy_settings(pm8001_ha, &phycfg_int); + pm8001_get_external_phy_settings(pm8001_ha, &phycfg_ext); + pm8001_get_phy_mask(pm8001_ha, &phymask); + + for (i = 0; i < pm8001_ha->chip->n_phy; i++) { + if (phymask & (1 << i)) {/* Internal PHY */ + pm8001_set_phy_profile_single(pm8001_ha, i, + sizeof(phycfg_int) / sizeof(u32), + (u32 *)&phycfg_int); + + } else { /* External PHY */ + pm8001_set_phy_profile_single(pm8001_ha, i, + sizeof(phycfg_ext) / sizeof(u32), + (u32 *)&phycfg_ext); + } + } + + return 0; +} + +/** + * pm8001_configure_phy_settings : Configures PHY settings based on vendor ID. + * @pm8001_ha : our hba. + */ +static int pm8001_configure_phy_settings(struct pm8001_hba_info *pm8001_ha) +{ + switch (pm8001_ha->pdev->subsystem_vendor) { + case PCI_VENDOR_ID_ATTO: + if (pm8001_ha->pdev->device == 0x0042) /* 6Gb */ + return 0; + else + return pm8001_set_phy_settings_ven_117c_12G(pm8001_ha); + + case PCI_VENDOR_ID_ADAPTEC2: + case 0: + return 0; + + default: + return pm8001_get_phy_settings_info(pm8001_ha); + } +} + #ifdef PM8001_USE_MSIX /** * pm8001_setup_msix - enable MSI-X interrupt @@ -792,7 +951,7 @@ static u32 pm8001_request_irq(struct pm8001_hba_info *pm8001_ha) pdev = pm8001_ha->pdev; #ifdef PM8001_USE_MSIX - if (pdev->msix_cap) + if (pdev->msix_cap && pci_msi_enabled()) return pm8001_setup_msix(pm8001_ha); else { PM8001_INIT_DBG(pm8001_ha, @@ -803,6 +962,8 @@ static u32 pm8001_request_irq(struct pm8001_hba_info *pm8001_ha) intx: /* initialize the INT-X interrupt */ + pm8001_ha->irq_vector[0].irq_id = 0; + pm8001_ha->irq_vector[0].drv_inst = pm8001_ha; rc = request_irq(pdev->irq, pm8001_interrupt_handler_intx, IRQF_SHARED, DRV_NAME, SHOST_TO_SAS_HA(pm8001_ha->shost)); return rc; @@ -902,12 +1063,9 @@ static int pm8001_pci_probe(struct pci_dev *pdev, pm8001_init_sas_add(pm8001_ha); /* phy setting support for motherboard controller */ - if (pdev->subsystem_vendor != PCI_VENDOR_ID_ADAPTEC2 && - pdev->subsystem_vendor != 0) { - rc = pm8001_get_phy_settings_info(pm8001_ha); - if (rc) - goto err_out_shost; - } + if (pm8001_configure_phy_settings(pm8001_ha)) + goto err_out_shost; + pm8001_post_sas_ha_init(shost, chip); rc = sas_register_ha(SHOST_TO_SAS_HA(shost)); if (rc) @@ -937,10 +1095,10 @@ static void pm8001_pci_remove(struct pci_dev *pdev) struct pm8001_hba_info *pm8001_ha; int i, j; pm8001_ha = sha->lldd_ha; + scsi_remove_host(pm8001_ha->shost); sas_unregister_ha(sha); sas_remove_host(pm8001_ha->shost); list_del(&pm8001_ha->list); - scsi_remove_host(pm8001_ha->shost); PM8001_CHIP_DISP->interrupt_disable(pm8001_ha, 0xFF); PM8001_CHIP_DISP->chip_soft_rst(pm8001_ha); @@ -956,7 +1114,8 @@ static void pm8001_pci_remove(struct pci_dev *pdev) #endif #ifdef PM8001_USE_TASKLET /* For non-msix and msix interrupts */ - if ((!pdev->msix_cap) || (pm8001_ha->chip_id == chip_8001)) + if ((!pdev->msix_cap || !pci_msi_enabled()) || + (pm8001_ha->chip_id == chip_8001)) tasklet_kill(&pm8001_ha->tasklet[0]); else for (j = 0; j < PM8001_MAX_MSIX_VEC; j++) @@ -1005,7 +1164,8 @@ static int pm8001_pci_suspend(struct pci_dev *pdev, pm_message_t state) #endif #ifdef PM8001_USE_TASKLET /* For non-msix and msix interrupts */ - if ((!pdev->msix_cap) || (pm8001_ha->chip_id == chip_8001)) + if ((!pdev->msix_cap || !pci_msi_enabled()) || + (pm8001_ha->chip_id == chip_8001)) tasklet_kill(&pm8001_ha->tasklet[0]); else for (j = 0; j < PM8001_MAX_MSIX_VEC; j++) @@ -1074,7 +1234,8 @@ static int pm8001_pci_resume(struct pci_dev *pdev) goto err_out_disable; #ifdef PM8001_USE_TASKLET /* Tasklet for non msi-x interrupt handler */ - if ((!pdev->msix_cap) || (pm8001_ha->chip_id == chip_8001)) + if ((!pdev->msix_cap || !pci_msi_enabled()) || + (pm8001_ha->chip_id == chip_8001)) tasklet_init(&pm8001_ha->tasklet[0], pm8001_tasklet, (unsigned long)&(pm8001_ha->irq_vector[0])); else @@ -1087,6 +1248,19 @@ static int pm8001_pci_resume(struct pci_dev *pdev) for (i = 1; i < pm8001_ha->number_of_intr; i++) PM8001_CHIP_DISP->interrupt_enable(pm8001_ha, i); } + + /* Chip documentation for the 8070 and 8072 SPCv */ + /* states that a 500ms minimum delay is required */ + /* before issuing commands. Otherwise, the firmare */ + /* will enter an unrecoverable state. */ + + if (pm8001_ha->chip_id == chip_8070 || + pm8001_ha->chip_id == chip_8072) { + mdelay(500); + } + + /* Spin up the PHYs */ + pm8001_ha->flags = PM8001F_RUN_TIME; for (i = 0; i < pm8001_ha->chip->n_phy; i++) { pm8001_ha->phy[i].enable_completion = &completion; @@ -1165,6 +1339,20 @@ static struct pci_device_id pm8001_pci_table[] = { PCI_VENDOR_ID_ADAPTEC2, 0x0808, 0, 0, chip_8077 }, { PCI_VENDOR_ID_ADAPTEC2, 0x8074, PCI_VENDOR_ID_ADAPTEC2, 0x0404, 0, 0, chip_8074 }, + { PCI_VENDOR_ID_ATTO, 0x8070, + PCI_VENDOR_ID_ATTO, 0x0070, 0, 0, chip_8070 }, + { PCI_VENDOR_ID_ATTO, 0x8070, + PCI_VENDOR_ID_ATTO, 0x0071, 0, 0, chip_8070 }, + { PCI_VENDOR_ID_ATTO, 0x8072, + PCI_VENDOR_ID_ATTO, 0x0072, 0, 0, chip_8072 }, + { PCI_VENDOR_ID_ATTO, 0x8072, + PCI_VENDOR_ID_ATTO, 0x0073, 0, 0, chip_8072 }, + { PCI_VENDOR_ID_ATTO, 0x8070, + PCI_VENDOR_ID_ATTO, 0x0080, 0, 0, chip_8070 }, + { PCI_VENDOR_ID_ATTO, 0x8072, + PCI_VENDOR_ID_ATTO, 0x0081, 0, 0, chip_8072 }, + { PCI_VENDOR_ID_ATTO, 0x8072, + PCI_VENDOR_ID_ATTO, 0x0082, 0, 0, chip_8072 }, {} /* terminate list */ }; @@ -1220,7 +1408,7 @@ MODULE_AUTHOR("Anand Kumar Santhanam <AnandKumar.Santhanam@pmcs.com>"); MODULE_AUTHOR("Sangeetha Gnanasekaran <Sangeetha.Gnanasekaran@pmcs.com>"); MODULE_AUTHOR("Nikith Ganigarakoppal <Nikith.Ganigarakoppal@pmcs.com>"); MODULE_DESCRIPTION( - "PMC-Sierra PM8001/8006/8081/8088/8089/8074/8076/8077 " + "PMC-Sierra PM8001/8006/8081/8088/8089/8074/8076/8077/8070/8072 " "SAS/SATA controller driver"); MODULE_VERSION(DRV_VERSION); MODULE_LICENSE("GPL"); diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h index e2e97db38ae8..6628cc38316c 100644 --- a/drivers/scsi/pm8001/pm8001_sas.h +++ b/drivers/scsi/pm8001/pm8001_sas.h @@ -106,7 +106,9 @@ do { \ #define DEV_IS_EXPANDER(type) ((type == SAS_EDGE_EXPANDER_DEVICE) || (type == SAS_FANOUT_EXPANDER_DEVICE)) #define IS_SPCV_12G(dev) ((dev->device == 0X8074) \ || (dev->device == 0X8076) \ - || (dev->device == 0X8077)) + || (dev->device == 0X8077) \ + || (dev->device == 0X8070) \ + || (dev->device == 0X8072)) #define PM8001_NAME_LENGTH 32/* generic length of strings */ extern struct list_head hba_list; @@ -708,6 +710,8 @@ int pm80xx_set_thermal_config(struct pm8001_hba_info *pm8001_ha); int pm8001_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shiftValue); void pm8001_set_phy_profile(struct pm8001_hba_info *pm8001_ha, u32 length, u8 *buf); +void pm8001_set_phy_profile_single(struct pm8001_hba_info *pm8001_ha, + u32 phy, u32 length, u32 *buf); int pm80xx_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shiftValue); ssize_t pm80xx_get_fatal_dump(struct device *cdev, struct device_attribute *attr, char *buf); diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c index 9a389f1508de..eb4fee61df72 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.c +++ b/drivers/scsi/pm8001/pm80xx_hwi.c @@ -1267,6 +1267,8 @@ pm80xx_chip_soft_rst(struct pm8001_hba_info *pm8001_ha) /* check iButton feature support for motherboard controller */ if (pm8001_ha->pdev->subsystem_vendor != PCI_VENDOR_ID_ADAPTEC2 && + pm8001_ha->pdev->subsystem_vendor != + PCI_VENDOR_ID_ATTO && pm8001_ha->pdev->subsystem_vendor != 0) { ibutton0 = pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_6); @@ -4576,6 +4578,38 @@ void pm8001_set_phy_profile(struct pm8001_hba_info *pm8001_ha, } PM8001_INIT_DBG(pm8001_ha, pm8001_printk("phy settings completed\n")); } + +void pm8001_set_phy_profile_single(struct pm8001_hba_info *pm8001_ha, + u32 phy, u32 length, u32 *buf) +{ + u32 tag, opc; + int rc, i; + struct set_phy_profile_req payload; + struct inbound_queue_table *circularQ; + + memset(&payload, 0, sizeof(payload)); + + rc = pm8001_tag_alloc(pm8001_ha, &tag); + if (rc) + PM8001_INIT_DBG(pm8001_ha, pm8001_printk("Invalid tag")); + + circularQ = &pm8001_ha->inbnd_q_tbl[0]; + opc = OPC_INB_SET_PHY_PROFILE; + + payload.tag = cpu_to_le32(tag); + payload.ppc_phyid = (((SAS_PHY_ANALOG_SETTINGS_PAGE & 0xF) << 8) + | (phy & 0xFF)); + + for (i = 0; i < length; i++) + payload.reserved[i] = cpu_to_le32(*(buf + i)); + + rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0); + if (rc) + pm8001_tag_free(pm8001_ha, tag); + + PM8001_INIT_DBG(pm8001_ha, + pm8001_printk("PHY %d settings applied", phy)); +} const struct pm8001_dispatch pm8001_80xx_dispatch = { .name = "pmc80xx", .chip_init = pm80xx_chip_init, diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c index ed31d8cc6266..b2a88200fe54 100644 --- a/drivers/scsi/pmcraid.c +++ b/drivers/scsi/pmcraid.c @@ -45,6 +45,7 @@ #include <asm/processor.h> #include <linux/libata.h> #include <linux/mutex.h> +#include <linux/ktime.h> #include <scsi/scsi.h> #include <scsi/scsi_host.h> #include <scsi/scsi_device.h> @@ -4254,7 +4255,6 @@ static struct scsi_host_template pmcraid_host_template = { .use_clustering = ENABLE_CLUSTERING, .shost_attrs = pmcraid_host_attrs, .proc_name = PMCRAID_DRIVER_NAME, - .use_blk_tags = 1, }; /* @@ -5563,11 +5563,9 @@ static void pmcraid_set_timestamp(struct pmcraid_cmd *cmd) __be32 time_stamp_len = cpu_to_be32(PMCRAID_TIMESTAMP_LEN); struct pmcraid_ioadl_desc *ioadl = ioarcb->add_data.u.ioadl; - struct timeval tv; __le64 timestamp; - do_gettimeofday(&tv); - timestamp = tv.tv_sec * 1000; + timestamp = ktime_get_real_seconds() * 1000; pinstance->timestamp_data->timestamp[0] = (__u8)(timestamp); pinstance->timestamp_data->timestamp[1] = (__u8)((timestamp) >> 8); diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index c2dd17b1d26f..bfa9a64c316b 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -267,7 +267,6 @@ struct scsi_host_template qla2xxx_driver_template = { .shost_attrs = qla2x00_host_attrs, .supported_mode = MODE_INITIATOR, - .use_blk_tags = 1, .track_queue_depth = 1, }; diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index ac65cb7b4886..3ba2e9564b9a 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -43,8 +43,6 @@ #include <scsi/scsi_cmnd.h> #include <target/target_core_base.h> #include <target/target_core_fabric.h> -#include <target/target_core_fabric_configfs.h> -#include <target/configfs_macros.h> #include "qla_def.h" #include "qla_target.h" @@ -729,23 +727,23 @@ static int tcm_qla2xxx_init_nodeacl(struct se_node_acl *se_nacl, #define DEF_QLA_TPG_ATTRIB(name) \ \ -static ssize_t tcm_qla2xxx_tpg_attrib_show_##name( \ - struct se_portal_group *se_tpg, \ - char *page) \ +static ssize_t tcm_qla2xxx_tpg_attrib_##name##_show( \ + struct config_item *item, char *page) \ { \ + struct se_portal_group *se_tpg = attrib_to_tpg(item); \ struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, \ struct tcm_qla2xxx_tpg, se_tpg); \ \ return sprintf(page, "%u\n", tpg->tpg_attrib.name); \ } \ \ -static ssize_t tcm_qla2xxx_tpg_attrib_store_##name( \ - struct se_portal_group *se_tpg, \ - const char *page, \ - size_t count) \ +static ssize_t tcm_qla2xxx_tpg_attrib_##name##_store( \ + struct config_item *item, const char *page, size_t count) \ { \ + struct se_portal_group *se_tpg = attrib_to_tpg(item); \ struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, \ struct tcm_qla2xxx_tpg, se_tpg); \ + struct tcm_qla2xxx_tpg_attrib *a = &tpg->tpg_attrib; \ unsigned long val; \ int ret; \ \ @@ -755,81 +753,39 @@ static ssize_t tcm_qla2xxx_tpg_attrib_store_##name( \ " ret: %d\n", ret); \ return -EINVAL; \ } \ - ret = tcm_qla2xxx_set_attrib_##name(tpg, val); \ - \ - return (!ret) ? count : -EINVAL; \ -} - -#define DEF_QLA_TPG_ATTR_BOOL(_name) \ - \ -static int tcm_qla2xxx_set_attrib_##_name( \ - struct tcm_qla2xxx_tpg *tpg, \ - unsigned long val) \ -{ \ - struct tcm_qla2xxx_tpg_attrib *a = &tpg->tpg_attrib; \ \ if ((val != 0) && (val != 1)) { \ pr_err("Illegal boolean value %lu\n", val); \ return -EINVAL; \ } \ \ - a->_name = val; \ - return 0; \ -} - -#define QLA_TPG_ATTR(_name, _mode) \ - TF_TPG_ATTRIB_ATTR(tcm_qla2xxx, _name, _mode); + a->name = val; \ + \ + return count; \ +} \ +CONFIGFS_ATTR(tcm_qla2xxx_tpg_attrib_, name) -/* - * Define tcm_qla2xxx_tpg_attrib_s_generate_node_acls - */ -DEF_QLA_TPG_ATTR_BOOL(generate_node_acls); DEF_QLA_TPG_ATTRIB(generate_node_acls); -QLA_TPG_ATTR(generate_node_acls, S_IRUGO | S_IWUSR); - -/* - Define tcm_qla2xxx_attrib_s_cache_dynamic_acls - */ -DEF_QLA_TPG_ATTR_BOOL(cache_dynamic_acls); DEF_QLA_TPG_ATTRIB(cache_dynamic_acls); -QLA_TPG_ATTR(cache_dynamic_acls, S_IRUGO | S_IWUSR); - -/* - * Define tcm_qla2xxx_tpg_attrib_s_demo_mode_write_protect - */ -DEF_QLA_TPG_ATTR_BOOL(demo_mode_write_protect); DEF_QLA_TPG_ATTRIB(demo_mode_write_protect); -QLA_TPG_ATTR(demo_mode_write_protect, S_IRUGO | S_IWUSR); - -/* - * Define tcm_qla2xxx_tpg_attrib_s_prod_mode_write_protect - */ -DEF_QLA_TPG_ATTR_BOOL(prod_mode_write_protect); DEF_QLA_TPG_ATTRIB(prod_mode_write_protect); -QLA_TPG_ATTR(prod_mode_write_protect, S_IRUGO | S_IWUSR); - -/* - * Define tcm_qla2xxx_tpg_attrib_s_demo_mode_login_only - */ -DEF_QLA_TPG_ATTR_BOOL(demo_mode_login_only); DEF_QLA_TPG_ATTRIB(demo_mode_login_only); -QLA_TPG_ATTR(demo_mode_login_only, S_IRUGO | S_IWUSR); static struct configfs_attribute *tcm_qla2xxx_tpg_attrib_attrs[] = { - &tcm_qla2xxx_tpg_attrib_generate_node_acls.attr, - &tcm_qla2xxx_tpg_attrib_cache_dynamic_acls.attr, - &tcm_qla2xxx_tpg_attrib_demo_mode_write_protect.attr, - &tcm_qla2xxx_tpg_attrib_prod_mode_write_protect.attr, - &tcm_qla2xxx_tpg_attrib_demo_mode_login_only.attr, + &tcm_qla2xxx_tpg_attrib_attr_generate_node_acls, + &tcm_qla2xxx_tpg_attrib_attr_cache_dynamic_acls, + &tcm_qla2xxx_tpg_attrib_attr_demo_mode_write_protect, + &tcm_qla2xxx_tpg_attrib_attr_prod_mode_write_protect, + &tcm_qla2xxx_tpg_attrib_attr_demo_mode_login_only, NULL, }; /* End items for tcm_qla2xxx_tpg_attrib_cit */ -static ssize_t tcm_qla2xxx_tpg_show_enable( - struct se_portal_group *se_tpg, - char *page) +static ssize_t tcm_qla2xxx_tpg_enable_show(struct config_item *item, + char *page) { + struct se_portal_group *se_tpg = to_tpg(item); struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, struct tcm_qla2xxx_tpg, se_tpg); @@ -865,11 +821,10 @@ static void tcm_qla2xxx_undepend_tpg(struct work_struct *work) complete(&base_tpg->tpg_base_comp); } -static ssize_t tcm_qla2xxx_tpg_store_enable( - struct se_portal_group *se_tpg, - const char *page, - size_t count) +static ssize_t tcm_qla2xxx_tpg_enable_store(struct config_item *item, + const char *page, size_t count) { + struct se_portal_group *se_tpg = to_tpg(item); struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, struct tcm_qla2xxx_tpg, se_tpg); unsigned long op; @@ -909,22 +864,16 @@ static ssize_t tcm_qla2xxx_tpg_store_enable( return count; } -TF_TPG_BASE_ATTR(tcm_qla2xxx, enable, S_IRUGO | S_IWUSR); - -static ssize_t tcm_qla2xxx_tpg_show_dynamic_sessions( - struct se_portal_group *se_tpg, - char *page) +static ssize_t tcm_qla2xxx_tpg_dynamic_sessions_show(struct config_item *item, + char *page) { - return target_show_dynamic_sessions(se_tpg, page); + return target_show_dynamic_sessions(to_tpg(item), page); } -TF_TPG_BASE_ATTR_RO(tcm_qla2xxx, dynamic_sessions); - -static ssize_t tcm_qla2xxx_tpg_store_fabric_prot_type( - struct se_portal_group *se_tpg, - const char *page, - size_t count) +static ssize_t tcm_qla2xxx_tpg_fabric_prot_type_store(struct config_item *item, + const char *page, size_t count) { + struct se_portal_group *se_tpg = to_tpg(item); struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, struct tcm_qla2xxx_tpg, se_tpg); unsigned long val; @@ -943,21 +892,24 @@ static ssize_t tcm_qla2xxx_tpg_store_fabric_prot_type( return count; } -static ssize_t tcm_qla2xxx_tpg_show_fabric_prot_type( - struct se_portal_group *se_tpg, - char *page) +static ssize_t tcm_qla2xxx_tpg_fabric_prot_type_show(struct config_item *item, + char *page) { + struct se_portal_group *se_tpg = to_tpg(item); struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, struct tcm_qla2xxx_tpg, se_tpg); return sprintf(page, "%d\n", tpg->tpg_attrib.fabric_prot_type); } -TF_TPG_BASE_ATTR(tcm_qla2xxx, fabric_prot_type, S_IRUGO | S_IWUSR); + +CONFIGFS_ATTR_WO(tcm_qla2xxx_tpg_, enable); +CONFIGFS_ATTR_RO(tcm_qla2xxx_tpg_, dynamic_sessions); +CONFIGFS_ATTR(tcm_qla2xxx_tpg_, fabric_prot_type); static struct configfs_attribute *tcm_qla2xxx_tpg_attrs[] = { - &tcm_qla2xxx_tpg_enable.attr, - &tcm_qla2xxx_tpg_dynamic_sessions.attr, - &tcm_qla2xxx_tpg_fabric_prot_type.attr, + &tcm_qla2xxx_tpg_attr_enable, + &tcm_qla2xxx_tpg_attr_dynamic_sessions, + &tcm_qla2xxx_tpg_attr_fabric_prot_type, NULL, }; @@ -1030,18 +982,16 @@ static void tcm_qla2xxx_drop_tpg(struct se_portal_group *se_tpg) kfree(tpg); } -static ssize_t tcm_qla2xxx_npiv_tpg_show_enable( - struct se_portal_group *se_tpg, - char *page) +static ssize_t tcm_qla2xxx_npiv_tpg_enable_show(struct config_item *item, + char *page) { - return tcm_qla2xxx_tpg_show_enable(se_tpg, page); + return tcm_qla2xxx_tpg_enable_show(item, page); } -static ssize_t tcm_qla2xxx_npiv_tpg_store_enable( - struct se_portal_group *se_tpg, - const char *page, - size_t count) +static ssize_t tcm_qla2xxx_npiv_tpg_enable_store(struct config_item *item, + const char *page, size_t count) { + struct se_portal_group *se_tpg = to_tpg(item); struct se_wwn *se_wwn = se_tpg->se_tpg_wwn; struct tcm_qla2xxx_lport *lport = container_of(se_wwn, struct tcm_qla2xxx_lport, lport_wwn); @@ -1077,10 +1027,10 @@ static ssize_t tcm_qla2xxx_npiv_tpg_store_enable( return count; } -TF_TPG_BASE_ATTR(tcm_qla2xxx_npiv, enable, S_IRUGO | S_IWUSR); +CONFIGFS_ATTR(tcm_qla2xxx_npiv_tpg_, enable); static struct configfs_attribute *tcm_qla2xxx_npiv_tpg_attrs[] = { - &tcm_qla2xxx_npiv_tpg_enable.attr, + &tcm_qla2xxx_npiv_tpg_attr_enable, NULL, }; @@ -1783,9 +1733,8 @@ static void tcm_qla2xxx_npiv_drop_lport(struct se_wwn *wwn) } -static ssize_t tcm_qla2xxx_wwn_show_attr_version( - struct target_fabric_configfs *tf, - char *page) +static ssize_t tcm_qla2xxx_wwn_version_show(struct config_item *item, + char *page) { return sprintf(page, "TCM QLOGIC QLA2XXX NPIV capable fabric module %s on %s/%s on " @@ -1793,10 +1742,10 @@ static ssize_t tcm_qla2xxx_wwn_show_attr_version( utsname()->machine); } -TF_WWN_ATTR_RO(tcm_qla2xxx, version); +CONFIGFS_ATTR_RO(tcm_qla2xxx_wwn_, version); static struct configfs_attribute *tcm_qla2xxx_wwn_attrs[] = { - &tcm_qla2xxx_wwn_version.attr, + &tcm_qla2xxx_wwn_attr_version, NULL, }; diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 6d25879d87c8..01c3610a60cf 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -212,7 +212,6 @@ static struct scsi_host_template qla4xxx_driver_template = { .shost_attrs = qla4xxx_host_attrs, .host_reset = qla4xxx_host_reset, .vendor_id = SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_QLOGIC, - .use_blk_tags = 1, }; static struct iscsi_transport qla4xxx_iscsi_transport = { @@ -8697,13 +8696,6 @@ static int qla4xxx_probe_adapter(struct pci_dev *pdev, host->can_queue = MAX_SRBS ; host->transportt = qla4xxx_scsi_transport; - ret = scsi_init_shared_tag_map(host, MAX_SRBS); - if (ret) { - ql4_printk(KERN_WARNING, ha, - "%s: scsi_init_shared_tag_map failed\n", __func__); - goto probe_failed; - } - pci_set_drvdata(pdev, ha); ret = scsi_add_host(host, &pdev->dev); diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 207d6a7a1bd0..d07fb653f5dc 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -616,32 +616,11 @@ void scsi_finish_command(struct scsi_cmnd *cmd) */ int scsi_change_queue_depth(struct scsi_device *sdev, int depth) { - unsigned long flags; - - if (depth <= 0) - goto out; - - spin_lock_irqsave(sdev->request_queue->queue_lock, flags); - - /* - * Check to see if the queue is managed by the block layer. - * If it is, and we fail to adjust the depth, exit. - * - * Do not resize the tag map if it is a host wide share bqt, - * because the size should be the hosts's can_queue. If there - * is more IO than the LLD's can_queue (so there are not enuogh - * tags) request_fn's host queue ready check will handle it. - */ - if (!shost_use_blk_mq(sdev->host) && !sdev->host->bqt) { - if (blk_queue_tagged(sdev->request_queue) && - blk_queue_resize_tags(sdev->request_queue, depth) != 0) - goto out_unlock; + if (depth > 0) { + sdev->queue_depth = depth; + wmb(); } - sdev->queue_depth = depth; -out_unlock: - spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); -out: return sdev->queue_depth; } EXPORT_SYMBOL(scsi_change_queue_depth); diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index f9f3f8203d42..83245391e956 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -55,6 +55,7 @@ * Default timeout */ #define SCSI_TIMEOUT (2*HZ) +#define SCSI_REPORT_LUNS_TIMEOUT (30*HZ) /* * Prefix values for the SCSI id's (stored in sysfs name field) @@ -274,8 +275,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget, WARN_ON_ONCE(!blk_get_queue(sdev->request_queue)); sdev->request_queue->queuedata = sdev; - if (!shost_use_blk_mq(sdev->host) && - (shost->bqt || shost->hostt->use_blk_tags)) { + if (!shost_use_blk_mq(sdev->host)) { blk_queue_init_tags(sdev->request_queue, sdev->host->cmd_per_lun, shost->bqt, shost->hostt->tag_alloc_policy); @@ -1383,7 +1383,7 @@ retry: result = scsi_execute_req(sdev, scsi_cmd, DMA_FROM_DEVICE, lun_data, length, &sshdr, - SCSI_TIMEOUT + 4 * HZ, 3, NULL); + SCSI_REPORT_LUNS_TIMEOUT, 3, NULL); SCSI_LOG_SCAN_BUS(3, sdev_printk (KERN_INFO, sdev, "scsi scan: REPORT LUNS" @@ -1712,8 +1712,7 @@ static struct async_scan_data *scsi_prep_async_scan(struct Scsi_Host *shost) return NULL; if (shost->async_scan) { - shost_printk(KERN_INFO, shost, "%s called twice\n", __func__); - dump_stack(); + shost_printk(KERN_DEBUG, shost, "%s called twice\n", __func__); return NULL; } diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index dff8fafb741c..8d2312239ae0 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -775,6 +775,29 @@ static struct bin_attribute dev_attr_vpd_##_page = { \ sdev_vpd_pg_attr(pg83); sdev_vpd_pg_attr(pg80); +static ssize_t show_inquiry(struct file *filep, struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t off, size_t count) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct scsi_device *sdev = to_scsi_device(dev); + + if (!sdev->inquiry) + return -EINVAL; + + return memory_read_from_buffer(buf, count, &off, sdev->inquiry, + sdev->inquiry_len); +} + +static struct bin_attribute dev_attr_inquiry = { + .attr = { + .name = "inquiry", + .mode = S_IRUGO, + }, + .size = 0, + .read = show_inquiry, +}; + static ssize_t show_iostat_counterbits(struct device *dev, struct device_attribute *attr, char *buf) @@ -900,7 +923,7 @@ sdev_store_queue_ramp_up_period(struct device *dev, return -EINVAL; sdev->queue_ramp_up_period = msecs_to_jiffies(period); - return period; + return count; } static DEVICE_ATTR(queue_ramp_up_period, S_IRUGO | S_IWUSR, @@ -959,6 +982,7 @@ static struct attribute *scsi_sdev_attrs[] = { static struct bin_attribute *scsi_sdev_bin_attrs[] = { &dev_attr_vpd_pg83, &dev_attr_vpd_pg80, + &dev_attr_inquiry, NULL }; static struct attribute_group scsi_sdev_attr_group = { @@ -1086,9 +1110,7 @@ void __scsi_remove_device(struct scsi_device *sdev) device_unregister(&sdev->sdev_dev); transport_remove_device(dev); scsi_dh_remove_device(sdev); - device_del(dev); - } else - put_device(&sdev->sdev_dev); + } /* * Stop accepting new requests and wait until all queuecommand() and @@ -1099,6 +1121,16 @@ void __scsi_remove_device(struct scsi_device *sdev) blk_cleanup_queue(sdev->request_queue); cancel_work_sync(&sdev->requeue_work); + /* + * Remove the device after blk_cleanup_queue() has been called such + * a possible bdi_register() call with the same name occurs after + * blk_cleanup_queue() has called bdi_destroy(). + */ + if (sdev->is_visible) + device_del(dev); + else + put_device(&sdev->sdev_dev); + if (sdev->host->hostt->slave_destroy) sdev->host->hostt->slave_destroy(sdev); transport_destroy_device(dev); @@ -1160,31 +1192,23 @@ static void __scsi_remove_target(struct scsi_target *starget) void scsi_remove_target(struct device *dev) { struct Scsi_Host *shost = dev_to_shost(dev->parent); - struct scsi_target *starget, *last = NULL; + struct scsi_target *starget; unsigned long flags; - /* remove targets being careful to lookup next entry before - * deleting the last - */ +restart: spin_lock_irqsave(shost->host_lock, flags); list_for_each_entry(starget, &shost->__targets, siblings) { if (starget->state == STARGET_DEL) continue; if (starget->dev.parent == dev || &starget->dev == dev) { - /* assuming new targets arrive at the end */ kref_get(&starget->reap_ref); spin_unlock_irqrestore(shost->host_lock, flags); - if (last) - scsi_target_reap(last); - last = starget; __scsi_remove_target(starget); - spin_lock_irqsave(shost->host_lock, flags); + scsi_target_reap(starget); + goto restart; } } spin_unlock_irqrestore(shost->host_lock, flags); - - if (last) - scsi_target_reap(last); } EXPORT_SYMBOL(scsi_remove_target); diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 5e170a6809fd..54519804c46a 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -205,6 +205,7 @@ cache_type_store(struct device *dev, struct device_attribute *attr, buffer_data[2] &= ~0x05; buffer_data[2] |= wce << 2 | rcd; sp = buffer_data[0] & 0x80 ? 1 : 0; + buffer_data[0] &= ~0x80; if (scsi_mode_select(sdp, 1, sp, 8, buffer_data, len, SD_TIMEOUT, SD_MAX_RETRIES, &data, &sshdr)) { diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 9d7b7db75e4b..503ab8b46c0b 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -787,8 +787,14 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp, return k; /* probably out of space --> ENOMEM */ } if (atomic_read(&sdp->detaching)) { - if (srp->bio) + if (srp->bio) { + if (srp->rq->cmd != srp->rq->__cmd) + kfree(srp->rq->cmd); + blk_end_request_all(srp->rq, -EIO); + srp->rq = NULL; + } + sg_finish_rem_req(srp); return -ENODEV; } diff --git a/drivers/scsi/snic/snic_main.c b/drivers/scsi/snic/snic_main.c index b2b87cef00fc..2b3c25371d76 100644 --- a/drivers/scsi/snic/snic_main.c +++ b/drivers/scsi/snic/snic_main.c @@ -124,7 +124,6 @@ static struct scsi_host_template snic_host_template = { .sg_tablesize = SNIC_MAX_SG_DESC_CNT, .max_sectors = 0x800, .shost_attrs = snic_attrs, - .use_blk_tags = 1, .track_queue_depth = 1, .cmd_size = sizeof(struct snic_internal_io_state), .proc_name = "snic_scsi", @@ -533,15 +532,6 @@ snic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) snic->max_tag_id = shost->can_queue; - ret = scsi_init_shared_tag_map(shost, snic->max_tag_id); - if (ret) { - SNIC_HOST_ERR(shost, - "Unable to alloc shared tag map. %d\n", - ret); - - goto err_dev_close; - } - shost->max_lun = snic->config.luns_per_tgt; shost->max_id = SNIC_MAX_TARGET; diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index b37b9b00c4b4..e0a1e52a04e7 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -4452,11 +4452,41 @@ static ssize_t version_show(struct device_driver *ddd, char *buf) } static DRIVER_ATTR_RO(version); +#if DEBUG +static ssize_t debug_flag_store(struct device_driver *ddp, + const char *buf, size_t count) +{ +/* We only care what the first byte of the data is the rest is unused. + * if it's a '1' we turn on debug and if it's a '0' we disable it. All + * other values have -EINVAL returned if they are passed in. + */ + if (count > 0) { + if (buf[0] == '0') { + debugging = NO_DEBUG; + return count; + } else if (buf[0] == '1') { + debugging = 1; + return count; + } + } + return -EINVAL; +} + +static ssize_t debug_flag_show(struct device_driver *ddp, char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "%d\n", debugging); +} +static DRIVER_ATTR_RW(debug_flag); +#endif + static struct attribute *st_drv_attrs[] = { &driver_attr_try_direct_io.attr, &driver_attr_fixed_buffer_size.attr, &driver_attr_max_sg_segs.attr, &driver_attr_version.attr, +#if DEBUG + &driver_attr_debug_flag.attr, +#endif NULL, }; ATTRIBUTE_GROUPS(st_drv); diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c index 98a62bc15069..2de28d7a0b04 100644 --- a/drivers/scsi/stex.c +++ b/drivers/scsi/stex.c @@ -25,6 +25,7 @@ #include <linux/types.h> #include <linux/module.h> #include <linux/spinlock.h> +#include <linux/ktime.h> #include <asm/io.h> #include <asm/irq.h> #include <asm/byteorder.h> @@ -362,14 +363,6 @@ MODULE_DESCRIPTION("Promise Technology SuperTrak EX Controllers"); MODULE_LICENSE("GPL"); MODULE_VERSION(ST_DRIVER_VERSION); -static void stex_gettime(__le64 *time) -{ - struct timeval tv; - - 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; @@ -1002,7 +995,7 @@ static int stex_common_handshake(struct st_hba *hba) 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->hosttime = cpu_to_le64(ktime_get_real_seconds()); h->partner_type = HMU_PARTNER_TYPE; if (hba->extra_offset) { h->extra_offset = cpu_to_le32(hba->extra_offset); @@ -1076,7 +1069,7 @@ static int stex_ss_handshake(struct st_hba *hba) 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->hosttime = cpu_to_le64(ktime_get_real_seconds()); h->partner_type = HMU_PARTNER_TYPE; h->extra_offset = h->extra_size = 0; scratch_size = (hba->sts_count+1)*sizeof(u32); @@ -1374,7 +1367,6 @@ static struct scsi_host_template driver_template = { .eh_abort_handler = stex_abort, .eh_host_reset_handler = stex_reset, .this_id = -1, - .use_blk_tags = 1, }; static struct pci_device_id stex_pci_tbl[] = { @@ -1659,13 +1651,6 @@ static int stex_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (err) goto out_free_irq; - err = scsi_init_shared_tag_map(host, host->can_queue); - if (err) { - printk(KERN_ERR DRV_NAME "(%s): init shared queue failed\n", - pci_name(pdev)); - goto out_free_irq; - } - pci_set_drvdata(pdev, hba); err = scsi_add_host(host, &pdev->dev); diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index 40c43aeb4ff3..3fba42ad9fb8 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -349,11 +349,14 @@ enum storvsc_request_type { */ #define SRB_STATUS_AUTOSENSE_VALID 0x80 +#define SRB_STATUS_QUEUE_FROZEN 0x40 #define SRB_STATUS_INVALID_LUN 0x20 #define SRB_STATUS_SUCCESS 0x01 #define SRB_STATUS_ABORTED 0x02 #define SRB_STATUS_ERROR 0x04 +#define SRB_STATUS(status) \ + (status & ~(SRB_STATUS_AUTOSENSE_VALID | SRB_STATUS_QUEUE_FROZEN)) /* * This is the end of Protocol specific defines. */ @@ -393,9 +396,6 @@ static void storvsc_on_channel_callback(void *context); struct storvsc_cmd_request { struct scsi_cmnd *cmd; - unsigned int bounce_sgl_count; - struct scatterlist *bounce_sgl; - struct hv_device *device; /* Synchronize the request/response if needed */ @@ -586,241 +586,6 @@ get_in_err: } -static void destroy_bounce_buffer(struct scatterlist *sgl, - unsigned int sg_count) -{ - int i; - struct page *page_buf; - - for (i = 0; i < sg_count; i++) { - page_buf = sg_page((&sgl[i])); - if (page_buf != NULL) - __free_page(page_buf); - } - - kfree(sgl); -} - -static int do_bounce_buffer(struct scatterlist *sgl, unsigned int sg_count) -{ - int i; - - /* No need to check */ - if (sg_count < 2) - return -1; - - /* We have at least 2 sg entries */ - for (i = 0; i < sg_count; i++) { - if (i == 0) { - /* make sure 1st one does not have hole */ - if (sgl[i].offset + sgl[i].length != PAGE_SIZE) - return i; - } else if (i == sg_count - 1) { - /* make sure last one does not have hole */ - if (sgl[i].offset != 0) - return i; - } else { - /* make sure no hole in the middle */ - if (sgl[i].length != PAGE_SIZE || sgl[i].offset != 0) - return i; - } - } - return -1; -} - -static struct scatterlist *create_bounce_buffer(struct scatterlist *sgl, - unsigned int sg_count, - unsigned int len, - int write) -{ - int i; - int num_pages; - struct scatterlist *bounce_sgl; - struct page *page_buf; - unsigned int buf_len = ((write == WRITE_TYPE) ? 0 : PAGE_SIZE); - - num_pages = ALIGN(len, PAGE_SIZE) >> PAGE_SHIFT; - - bounce_sgl = kcalloc(num_pages, sizeof(struct scatterlist), GFP_ATOMIC); - if (!bounce_sgl) - return NULL; - - sg_init_table(bounce_sgl, num_pages); - for (i = 0; i < num_pages; i++) { - page_buf = alloc_page(GFP_ATOMIC); - if (!page_buf) - goto cleanup; - sg_set_page(&bounce_sgl[i], page_buf, buf_len, 0); - } - - return bounce_sgl; - -cleanup: - destroy_bounce_buffer(bounce_sgl, num_pages); - return NULL; -} - -/* Assume the original sgl has enough room */ -static unsigned int copy_from_bounce_buffer(struct scatterlist *orig_sgl, - struct scatterlist *bounce_sgl, - unsigned int orig_sgl_count, - unsigned int bounce_sgl_count) -{ - int i; - int j = 0; - unsigned long src, dest; - unsigned int srclen, destlen, copylen; - unsigned int total_copied = 0; - unsigned long bounce_addr = 0; - unsigned long dest_addr = 0; - unsigned long flags; - struct scatterlist *cur_dest_sgl; - struct scatterlist *cur_src_sgl; - - local_irq_save(flags); - cur_dest_sgl = orig_sgl; - cur_src_sgl = bounce_sgl; - for (i = 0; i < orig_sgl_count; i++) { - dest_addr = (unsigned long) - kmap_atomic(sg_page(cur_dest_sgl)) + - cur_dest_sgl->offset; - dest = dest_addr; - destlen = cur_dest_sgl->length; - - if (bounce_addr == 0) - bounce_addr = (unsigned long)kmap_atomic( - sg_page(cur_src_sgl)); - - while (destlen) { - src = bounce_addr + cur_src_sgl->offset; - srclen = cur_src_sgl->length - cur_src_sgl->offset; - - copylen = min(srclen, destlen); - memcpy((void *)dest, (void *)src, copylen); - - total_copied += copylen; - cur_src_sgl->offset += copylen; - destlen -= copylen; - dest += copylen; - - if (cur_src_sgl->offset == cur_src_sgl->length) { - /* full */ - kunmap_atomic((void *)bounce_addr); - j++; - - /* - * It is possible that the number of elements - * in the bounce buffer may not be equal to - * the number of elements in the original - * scatter list. Handle this correctly. - */ - - if (j == bounce_sgl_count) { - /* - * We are done; cleanup and return. - */ - kunmap_atomic((void *)(dest_addr - - cur_dest_sgl->offset)); - local_irq_restore(flags); - return total_copied; - } - - /* if we need to use another bounce buffer */ - if (destlen || i != orig_sgl_count - 1) { - cur_src_sgl = sg_next(cur_src_sgl); - bounce_addr = (unsigned long) - kmap_atomic( - sg_page(cur_src_sgl)); - } - } else if (destlen == 0 && i == orig_sgl_count - 1) { - /* unmap the last bounce that is < PAGE_SIZE */ - kunmap_atomic((void *)bounce_addr); - } - } - - kunmap_atomic((void *)(dest_addr - cur_dest_sgl->offset)); - cur_dest_sgl = sg_next(cur_dest_sgl); - } - - local_irq_restore(flags); - - return total_copied; -} - -/* Assume the bounce_sgl has enough room ie using the create_bounce_buffer() */ -static unsigned int copy_to_bounce_buffer(struct scatterlist *orig_sgl, - struct scatterlist *bounce_sgl, - unsigned int orig_sgl_count) -{ - int i; - int j = 0; - unsigned long src, dest; - unsigned int srclen, destlen, copylen; - unsigned int total_copied = 0; - unsigned long bounce_addr = 0; - unsigned long src_addr = 0; - unsigned long flags; - struct scatterlist *cur_src_sgl; - struct scatterlist *cur_dest_sgl; - - local_irq_save(flags); - - cur_src_sgl = orig_sgl; - cur_dest_sgl = bounce_sgl; - - for (i = 0; i < orig_sgl_count; i++) { - src_addr = (unsigned long) - kmap_atomic(sg_page(cur_src_sgl)) + - cur_src_sgl->offset; - src = src_addr; - srclen = cur_src_sgl->length; - - if (bounce_addr == 0) - bounce_addr = (unsigned long) - kmap_atomic(sg_page(cur_dest_sgl)); - - while (srclen) { - /* assume bounce offset always == 0 */ - dest = bounce_addr + cur_dest_sgl->length; - destlen = PAGE_SIZE - cur_dest_sgl->length; - - copylen = min(srclen, destlen); - memcpy((void *)dest, (void *)src, copylen); - - total_copied += copylen; - cur_dest_sgl->length += copylen; - srclen -= copylen; - src += copylen; - - if (cur_dest_sgl->length == PAGE_SIZE) { - /* full..move to next entry */ - kunmap_atomic((void *)bounce_addr); - bounce_addr = 0; - j++; - } - - /* if we need to use another bounce buffer */ - if (srclen && bounce_addr == 0) { - cur_dest_sgl = sg_next(cur_dest_sgl); - bounce_addr = (unsigned long) - kmap_atomic( - sg_page(cur_dest_sgl)); - } - - } - - kunmap_atomic((void *)(src_addr - cur_src_sgl->offset)); - cur_src_sgl = sg_next(cur_src_sgl); - } - - if (bounce_addr) - kunmap_atomic((void *)bounce_addr); - - local_irq_restore(flags); - - return total_copied; -} - static void handle_sc_creation(struct vmbus_channel *new_sc) { struct hv_device *device = new_sc->primary_channel->device_obj; @@ -1096,7 +861,7 @@ static void storvsc_handle_error(struct vmscsi_request *vm_srb, void (*process_err_fn)(struct work_struct *work); bool do_work = false; - switch (vm_srb->srb_status) { + switch (SRB_STATUS(vm_srb->srb_status)) { case SRB_STATUS_ERROR: /* * If there is an error; offline the device since all @@ -1171,15 +936,6 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request) host = stor_dev->host; vm_srb = &cmd_request->vstor_packet.vm_srb; - if (cmd_request->bounce_sgl_count) { - if (vm_srb->data_in == READ_TYPE) - copy_from_bounce_buffer(scsi_sglist(scmnd), - cmd_request->bounce_sgl, - scsi_sg_count(scmnd), - cmd_request->bounce_sgl_count); - destroy_bounce_buffer(cmd_request->bounce_sgl, - cmd_request->bounce_sgl_count); - } scmnd->result = vm_srb->scsi_status; @@ -1474,6 +1230,9 @@ static int storvsc_device_configure(struct scsi_device *sdevice) blk_queue_rq_timeout(sdevice->request_queue, (storvsc_timeout * HZ)); + /* Ensure there are no gaps in presented sgls */ + blk_queue_virt_boundary(sdevice->request_queue, PAGE_SIZE - 1); + sdevice->no_write_same = 1; /* @@ -1647,8 +1406,7 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd) vm_srb->win8_extension.time_out_value = 60; vm_srb->win8_extension.srb_flags |= - (SRB_FLAGS_QUEUE_ACTION_ENABLE | - SRB_FLAGS_DISABLE_SYNCH_TRANSFER); + SRB_FLAGS_DISABLE_SYNCH_TRANSFER; /* Build the SRB */ switch (scmnd->sc_data_direction) { @@ -1692,40 +1450,13 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd) payload_sz = sizeof(cmd_request->mpb); if (sg_count) { - /* check if we need to bounce the sgl */ - if (do_bounce_buffer(sgl, scsi_sg_count(scmnd)) != -1) { - cmd_request->bounce_sgl = - create_bounce_buffer(sgl, sg_count, - length, - vm_srb->data_in); - if (!cmd_request->bounce_sgl) - return SCSI_MLQUEUE_HOST_BUSY; - - cmd_request->bounce_sgl_count = - ALIGN(length, PAGE_SIZE) >> PAGE_SHIFT; - - if (vm_srb->data_in == WRITE_TYPE) - copy_to_bounce_buffer(sgl, - cmd_request->bounce_sgl, sg_count); - - sgl = cmd_request->bounce_sgl; - sg_count = cmd_request->bounce_sgl_count; - } - - if (sg_count > MAX_PAGE_BUFFER_COUNT) { payload_sz = (sg_count * sizeof(void *) + sizeof(struct vmbus_packet_mpb_array)); payload = kmalloc(payload_sz, GFP_ATOMIC); - if (!payload) { - if (cmd_request->bounce_sgl_count) - destroy_bounce_buffer( - cmd_request->bounce_sgl, - cmd_request->bounce_sgl_count); - - return SCSI_MLQUEUE_DEVICE_BUSY; - } + if (!payload) + return SCSI_MLQUEUE_DEVICE_BUSY; } payload->range.len = length; @@ -1754,11 +1485,6 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd) if (ret == -EAGAIN) { /* no more space */ - - if (cmd_request->bounce_sgl_count) - destroy_bounce_buffer(cmd_request->bounce_sgl, - cmd_request->bounce_sgl_count); - return SCSI_MLQUEUE_DEVICE_BUSY; } diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig index e94538362536..5f4530744e0a 100644 --- a/drivers/scsi/ufs/Kconfig +++ b/drivers/scsi/ufs/Kconfig @@ -72,7 +72,7 @@ config SCSI_UFSHCD_PLATFORM If unsure, say N. config SCSI_UFS_QCOM - bool "QCOM specific hooks to UFS controller platform driver" + tristate "QCOM specific hooks to UFS controller platform driver" depends on SCSI_UFSHCD_PLATFORM && ARCH_QCOM select PHY_QCOM_UFS help diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index 4cdffa46d401..4f38d008bfb4 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -19,16 +19,44 @@ #include <linux/phy/phy-qcom-ufs.h> #include "ufshcd.h" +#include "ufshcd-pltfrm.h" #include "unipro.h" #include "ufs-qcom.h" #include "ufshci.h" +#define UFS_QCOM_DEFAULT_DBG_PRINT_EN \ + (UFS_QCOM_DBG_PRINT_REGS_EN | UFS_QCOM_DBG_PRINT_TEST_BUS_EN) + +enum { + TSTBUS_UAWM, + TSTBUS_UARM, + TSTBUS_TXUC, + TSTBUS_RXUC, + TSTBUS_DFC, + TSTBUS_TRLUT, + TSTBUS_TMRLUT, + TSTBUS_OCSC, + TSTBUS_UTP_HCI, + TSTBUS_COMBINED, + TSTBUS_WRAPPER, + TSTBUS_UNIPRO, + TSTBUS_MAX, +}; static struct ufs_qcom_host *ufs_qcom_hosts[MAX_UFS_QCOM_HOSTS]; -static void ufs_qcom_get_speed_mode(struct ufs_pa_layer_attr *p, char *result); -static int ufs_qcom_get_bus_vote(struct ufs_qcom_host *host, - const char *speed_mode); static int ufs_qcom_set_bus_vote(struct ufs_qcom_host *host, int vote); +static void ufs_qcom_get_default_testbus_cfg(struct ufs_qcom_host *host); +static int ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(struct ufs_hba *hba, + u32 clk_cycles); + +static void ufs_qcom_dump_regs(struct ufs_hba *hba, int offset, int len, + char *prefix) +{ + print_hex_dump(KERN_ERR, prefix, + len > 4 ? DUMP_PREFIX_OFFSET : DUMP_PREFIX_NONE, + 16, 4, (void __force *)hba->mmio_base + offset, + len * 4, false); +} static int ufs_qcom_get_connected_tx_lanes(struct ufs_hba *hba, u32 *tx_lanes) { @@ -149,13 +177,14 @@ static int ufs_qcom_init_lane_clks(struct ufs_qcom_host *host) err = ufs_qcom_host_clk_get(dev, "tx_lane1_sync_clk", &host->tx_l1_sync_clk); + out: return err; } static int ufs_qcom_link_startup_post_change(struct ufs_hba *hba) { - struct ufs_qcom_host *host = hba->priv; + struct ufs_qcom_host *host = ufshcd_get_variant(hba); struct phy *phy = host->generic_phy; u32 tx_lanes; int err = 0; @@ -181,7 +210,9 @@ static int ufs_qcom_check_hibern8(struct ufs_hba *hba) do { err = ufshcd_dme_get(hba, - UIC_ARG_MIB(MPHY_TX_FSM_STATE), &tx_fsm_val); + UIC_ARG_MIB_SEL(MPHY_TX_FSM_STATE, + UIC_ARG_MPHY_TX_GEN_SEL_INDEX(0)), + &tx_fsm_val); if (err || tx_fsm_val == TX_FSM_HIBERN8) break; @@ -195,7 +226,9 @@ static int ufs_qcom_check_hibern8(struct ufs_hba *hba) */ if (time_after(jiffies, timeout)) err = ufshcd_dme_get(hba, - UIC_ARG_MIB(MPHY_TX_FSM_STATE), &tx_fsm_val); + UIC_ARG_MIB_SEL(MPHY_TX_FSM_STATE, + UIC_ARG_MPHY_TX_GEN_SEL_INDEX(0)), + &tx_fsm_val); if (err) { dev_err(hba->dev, "%s: unable to get TX_FSM_STATE, err %d\n", @@ -209,9 +242,18 @@ static int ufs_qcom_check_hibern8(struct ufs_hba *hba) return err; } +static void ufs_qcom_select_unipro_mode(struct ufs_qcom_host *host) +{ + ufshcd_rmwl(host->hba, QUNIPRO_SEL, + ufs_qcom_cap_qunipro(host) ? QUNIPRO_SEL : 0, + REG_UFS_CFG1); + /* make sure above configuration is applied before we return */ + mb(); +} + static int ufs_qcom_power_up_sequence(struct ufs_hba *hba) { - struct ufs_qcom_host *host = hba->priv; + struct ufs_qcom_host *host = ufshcd_get_variant(hba); struct phy *phy = host->generic_phy; int ret = 0; bool is_rate_B = (UFS_QCOM_LIMIT_HS_RATE == PA_HS_MODE_B) @@ -223,9 +265,11 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba) usleep_range(1000, 1100); ret = ufs_qcom_phy_calibrate_phy(phy, is_rate_B); + if (ret) { - dev_err(hba->dev, "%s: ufs_qcom_phy_calibrate_phy() failed, ret = %d\n", - __func__, ret); + dev_err(hba->dev, + "%s: ufs_qcom_phy_calibrate_phy()failed, ret = %d\n", + __func__, ret); goto out; } @@ -246,9 +290,12 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba) ret = ufs_qcom_phy_is_pcs_ready(phy); if (ret) - dev_err(hba->dev, "%s: is_physical_coding_sublayer_ready() failed, ret = %d\n", + dev_err(hba->dev, + "%s: is_physical_coding_sublayer_ready() failed, ret = %d\n", __func__, ret); + ufs_qcom_select_unipro_mode(host); + out: return ret; } @@ -271,9 +318,10 @@ static void ufs_qcom_enable_hw_clk_gating(struct ufs_hba *hba) mb(); } -static int ufs_qcom_hce_enable_notify(struct ufs_hba *hba, bool status) +static int ufs_qcom_hce_enable_notify(struct ufs_hba *hba, + enum ufs_notify_change_status status) { - struct ufs_qcom_host *host = hba->priv; + struct ufs_qcom_host *host = ufshcd_get_variant(hba); int err = 0; switch (status) { @@ -301,13 +349,13 @@ static int ufs_qcom_hce_enable_notify(struct ufs_hba *hba, bool status) } /** - * Returns non-zero for success (which rate of core_clk) and 0 - * in case of a failure + * Returns zero for success and non-zero in case of a failure */ -static unsigned long -ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear, u32 hs, u32 rate) +static int ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear, + u32 hs, u32 rate, bool update_link_startup_timer) { - struct ufs_qcom_host *host = hba->priv; + int ret = 0; + struct ufs_qcom_host *host = ufshcd_get_variant(hba); struct ufs_clk_info *clki; u32 core_clk_period_in_ns; u32 tx_clk_cycles_per_us = 0; @@ -324,11 +372,13 @@ ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear, u32 hs, u32 rate) static u32 hs_fr_table_rA[][2] = { {UFS_HS_G1, 0x1F}, {UFS_HS_G2, 0x3e}, + {UFS_HS_G3, 0x7D}, }; static u32 hs_fr_table_rB[][2] = { {UFS_HS_G1, 0x24}, {UFS_HS_G2, 0x49}, + {UFS_HS_G3, 0x92}, }; /* @@ -356,7 +406,17 @@ ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear, u32 hs, u32 rate) core_clk_rate = DEFAULT_CLK_RATE_HZ; core_clk_cycles_per_us = core_clk_rate / USEC_PER_SEC; - ufshcd_writel(hba, core_clk_cycles_per_us, REG_UFS_SYS1CLK_1US); + if (ufshcd_readl(hba, REG_UFS_SYS1CLK_1US) != core_clk_cycles_per_us) { + ufshcd_writel(hba, core_clk_cycles_per_us, REG_UFS_SYS1CLK_1US); + /* + * make sure above write gets applied before we return from + * this function. + */ + mb(); + } + + if (ufs_qcom_cap_qunipro(host)) + goto out; core_clk_period_in_ns = NSEC_PER_SEC / core_clk_rate; core_clk_period_in_ns <<= OFFSET_CLK_NS_REG; @@ -406,35 +466,59 @@ ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear, u32 hs, u32 rate) goto out_error; } - /* this register 2 fields shall be written at once */ - ufshcd_writel(hba, core_clk_period_in_ns | tx_clk_cycles_per_us, - REG_UFS_TX_SYMBOL_CLK_NS_US); + if (ufshcd_readl(hba, REG_UFS_TX_SYMBOL_CLK_NS_US) != + (core_clk_period_in_ns | tx_clk_cycles_per_us)) { + /* this register 2 fields shall be written at once */ + ufshcd_writel(hba, core_clk_period_in_ns | tx_clk_cycles_per_us, + REG_UFS_TX_SYMBOL_CLK_NS_US); + /* + * make sure above write gets applied before we return from + * this function. + */ + mb(); + } + + if (update_link_startup_timer) { + ufshcd_writel(hba, ((core_clk_rate / MSEC_PER_SEC) * 100), + REG_UFS_PA_LINK_STARTUP_TIMER); + /* + * make sure that this configuration is applied before + * we return + */ + mb(); + } goto out; out_error: - core_clk_rate = 0; + ret = -EINVAL; out: - return core_clk_rate; + return ret; } -static int ufs_qcom_link_startup_notify(struct ufs_hba *hba, bool status) +static int ufs_qcom_link_startup_notify(struct ufs_hba *hba, + enum ufs_notify_change_status status) { - unsigned long core_clk_rate = 0; - u32 core_clk_cycles_per_100ms; + int err = 0; + struct ufs_qcom_host *host = ufshcd_get_variant(hba); switch (status) { case PRE_CHANGE: - core_clk_rate = ufs_qcom_cfg_timers(hba, UFS_PWM_G1, - SLOWAUTO_MODE, 0); - if (!core_clk_rate) { + if (ufs_qcom_cfg_timers(hba, UFS_PWM_G1, SLOWAUTO_MODE, + 0, true)) { dev_err(hba->dev, "%s: ufs_qcom_cfg_timers() failed\n", __func__); - return -EINVAL; + err = -EINVAL; + goto out; } - core_clk_cycles_per_100ms = - (core_clk_rate / MSEC_PER_SEC) * 100; - ufshcd_writel(hba, core_clk_cycles_per_100ms, - REG_UFS_PA_LINK_STARTUP_TIMER); + + if (ufs_qcom_cap_qunipro(host)) + /* + * set unipro core clock cycles to 150 & clear clock + * divider + */ + err = ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(hba, + 150); + break; case POST_CHANGE: ufs_qcom_link_startup_post_change(hba); @@ -443,12 +527,13 @@ static int ufs_qcom_link_startup_notify(struct ufs_hba *hba, bool status) break; } - return 0; +out: + return err; } static int ufs_qcom_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) { - struct ufs_qcom_host *host = hba->priv; + struct ufs_qcom_host *host = ufshcd_get_variant(hba); struct phy *phy = host->generic_phy; int ret = 0; @@ -470,8 +555,10 @@ static int ufs_qcom_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) * If UniPro link is not active, PHY ref_clk, main PHY analog power * rail and low noise analog power rail for PLL can be switched off. */ - if (!ufs_qcom_is_link_active(hba)) + if (!ufs_qcom_is_link_active(hba)) { + ufs_qcom_disable_lane_clks(host); phy_power_off(phy); + } out: return ret; @@ -479,7 +566,7 @@ out: static int ufs_qcom_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) { - struct ufs_qcom_host *host = hba->priv; + struct ufs_qcom_host *host = ufshcd_get_variant(hba); struct phy *phy = host->generic_phy; int err; @@ -490,6 +577,10 @@ static int ufs_qcom_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) goto out; } + err = ufs_qcom_enable_lane_clks(host); + if (err) + goto out; + hba->is_sys_suspended = false; out: @@ -594,6 +685,81 @@ static int ufs_qcom_get_pwr_dev_param(struct ufs_qcom_dev_params *qcom_param, return 0; } +#ifdef CONFIG_MSM_BUS_SCALING +static int ufs_qcom_get_bus_vote(struct ufs_qcom_host *host, + const char *speed_mode) +{ + struct device *dev = host->hba->dev; + struct device_node *np = dev->of_node; + int err; + const char *key = "qcom,bus-vector-names"; + + if (!speed_mode) { + err = -EINVAL; + goto out; + } + + if (host->bus_vote.is_max_bw_needed && !!strcmp(speed_mode, "MIN")) + err = of_property_match_string(np, key, "MAX"); + else + err = of_property_match_string(np, key, speed_mode); + +out: + if (err < 0) + dev_err(dev, "%s: Invalid %s mode %d\n", + __func__, speed_mode, err); + return err; +} + +static void ufs_qcom_get_speed_mode(struct ufs_pa_layer_attr *p, char *result) +{ + int gear = max_t(u32, p->gear_rx, p->gear_tx); + int lanes = max_t(u32, p->lane_rx, p->lane_tx); + int pwr; + + /* default to PWM Gear 1, Lane 1 if power mode is not initialized */ + if (!gear) + gear = 1; + + if (!lanes) + lanes = 1; + + if (!p->pwr_rx && !p->pwr_tx) { + pwr = SLOWAUTO_MODE; + snprintf(result, BUS_VECTOR_NAME_LEN, "MIN"); + } else if (p->pwr_rx == FAST_MODE || p->pwr_rx == FASTAUTO_MODE || + p->pwr_tx == FAST_MODE || p->pwr_tx == FASTAUTO_MODE) { + pwr = FAST_MODE; + snprintf(result, BUS_VECTOR_NAME_LEN, "%s_R%s_G%d_L%d", "HS", + p->hs_rate == PA_HS_MODE_B ? "B" : "A", gear, lanes); + } else { + pwr = SLOW_MODE; + snprintf(result, BUS_VECTOR_NAME_LEN, "%s_G%d_L%d", + "PWM", gear, lanes); + } +} + +static int ufs_qcom_set_bus_vote(struct ufs_qcom_host *host, int vote) +{ + int err = 0; + + if (vote != host->bus_vote.curr_vote) { + err = msm_bus_scale_client_update_request( + host->bus_vote.client_handle, vote); + if (err) { + dev_err(host->hba->dev, + "%s: msm_bus_scale_client_update_request() failed: bus_client_handle=0x%x, vote=%d, err=%d\n", + __func__, host->bus_vote.client_handle, + vote, err); + goto out; + } + + host->bus_vote.curr_vote = vote; + } +out: + return err; +} + static int ufs_qcom_update_bus_bw_vote(struct ufs_qcom_host *host) { int vote; @@ -615,13 +781,137 @@ static int ufs_qcom_update_bus_bw_vote(struct ufs_qcom_host *host) return err; } +static ssize_t +show_ufs_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + struct ufs_qcom_host *host = ufshcd_get_variant(hba); + + return snprintf(buf, PAGE_SIZE, "%u\n", + host->bus_vote.is_max_bw_needed); +} + +static ssize_t +store_ufs_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + struct ufs_qcom_host *host = ufshcd_get_variant(hba); + uint32_t value; + + if (!kstrtou32(buf, 0, &value)) { + host->bus_vote.is_max_bw_needed = !!value; + ufs_qcom_update_bus_bw_vote(host); + } + + return count; +} + +static int ufs_qcom_bus_register(struct ufs_qcom_host *host) +{ + int err; + struct msm_bus_scale_pdata *bus_pdata; + struct device *dev = host->hba->dev; + struct platform_device *pdev = to_platform_device(dev); + struct device_node *np = dev->of_node; + + bus_pdata = msm_bus_cl_get_pdata(pdev); + if (!bus_pdata) { + dev_err(dev, "%s: failed to get bus vectors\n", __func__); + err = -ENODATA; + goto out; + } + + err = of_property_count_strings(np, "qcom,bus-vector-names"); + if (err < 0 || err != bus_pdata->num_usecases) { + dev_err(dev, "%s: qcom,bus-vector-names not specified correctly %d\n", + __func__, err); + goto out; + } + + host->bus_vote.client_handle = msm_bus_scale_register_client(bus_pdata); + if (!host->bus_vote.client_handle) { + dev_err(dev, "%s: msm_bus_scale_register_client failed\n", + __func__); + err = -EFAULT; + goto out; + } + + /* cache the vote index for minimum and maximum bandwidth */ + host->bus_vote.min_bw_vote = ufs_qcom_get_bus_vote(host, "MIN"); + host->bus_vote.max_bw_vote = ufs_qcom_get_bus_vote(host, "MAX"); + + host->bus_vote.max_bus_bw.show = show_ufs_to_mem_max_bus_bw; + host->bus_vote.max_bus_bw.store = store_ufs_to_mem_max_bus_bw; + sysfs_attr_init(&host->bus_vote.max_bus_bw.attr); + host->bus_vote.max_bus_bw.attr.name = "max_bus_bw"; + host->bus_vote.max_bus_bw.attr.mode = S_IRUGO | S_IWUSR; + err = device_create_file(dev, &host->bus_vote.max_bus_bw); +out: + return err; +} +#else /* CONFIG_MSM_BUS_SCALING */ +static int ufs_qcom_update_bus_bw_vote(struct ufs_qcom_host *host) +{ + return 0; +} + +static int ufs_qcom_set_bus_vote(struct ufs_qcom_host *host, int vote) +{ + return 0; +} + +static int ufs_qcom_bus_register(struct ufs_qcom_host *host) +{ + return 0; +} +#endif /* CONFIG_MSM_BUS_SCALING */ + +static void ufs_qcom_dev_ref_clk_ctrl(struct ufs_qcom_host *host, bool enable) +{ + if (host->dev_ref_clk_ctrl_mmio && + (enable ^ host->is_dev_ref_clk_enabled)) { + u32 temp = readl_relaxed(host->dev_ref_clk_ctrl_mmio); + + if (enable) + temp |= host->dev_ref_clk_en_mask; + else + temp &= ~host->dev_ref_clk_en_mask; + + /* + * If we are here to disable this clock it might be immediately + * after entering into hibern8 in which case we need to make + * sure that device ref_clk is active at least 1us after the + * hibern8 enter. + */ + if (!enable) + udelay(1); + + writel_relaxed(temp, host->dev_ref_clk_ctrl_mmio); + + /* ensure that ref_clk is enabled/disabled before we return */ + wmb(); + + /* + * If we call hibern8 exit after this, we need to make sure that + * device ref_clk is stable for at least 1us before the hibern8 + * exit command. + */ + if (enable) + udelay(1); + + host->is_dev_ref_clk_enabled = enable; + } +} + static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, - bool status, + enum ufs_notify_change_status status, struct ufs_pa_layer_attr *dev_max_params, struct ufs_pa_layer_attr *dev_req_params) { u32 val; - struct ufs_qcom_host *host = hba->priv; + struct ufs_qcom_host *host = ufshcd_get_variant(hba); struct phy *phy = host->generic_phy; struct ufs_qcom_dev_params ufs_qcom_cap; int ret = 0; @@ -649,6 +939,20 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, ufs_qcom_cap.desired_working_mode = UFS_QCOM_LIMIT_DESIRED_MODE; + if (host->hw_ver.major == 0x1) { + /* + * HS-G3 operations may not reliably work on legacy QCOM + * UFS host controller hardware even though capability + * exchange during link startup phase may end up + * negotiating maximum supported gear as G3. + * Hence downgrade the maximum supported gear to HS-G2. + */ + if (ufs_qcom_cap.hs_tx_gear > UFS_HS_G2) + ufs_qcom_cap.hs_tx_gear = UFS_HS_G2; + if (ufs_qcom_cap.hs_rx_gear > UFS_HS_G2) + ufs_qcom_cap.hs_rx_gear = UFS_HS_G2; + } + ret = ufs_qcom_get_pwr_dev_param(&ufs_qcom_cap, dev_max_params, dev_req_params); @@ -660,9 +964,9 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, break; case POST_CHANGE: - if (!ufs_qcom_cfg_timers(hba, dev_req_params->gear_rx, + if (ufs_qcom_cfg_timers(hba, dev_req_params->gear_rx, dev_req_params->pwr_rx, - dev_req_params->hs_rate)) { + dev_req_params->hs_rate, false)) { dev_err(hba->dev, "%s: ufs_qcom_cfg_timers() failed\n", __func__); /* @@ -696,7 +1000,7 @@ out: static u32 ufs_qcom_get_ufs_hci_version(struct ufs_hba *hba) { - struct ufs_qcom_host *host = hba->priv; + struct ufs_qcom_host *host = ufshcd_get_variant(hba); if (host->hw_ver.major == 0x1) return UFSHCI_VERSION_11; @@ -715,7 +1019,7 @@ static u32 ufs_qcom_get_ufs_hci_version(struct ufs_hba *hba) */ static void ufs_qcom_advertise_quirks(struct ufs_hba *hba) { - struct ufs_qcom_host *host = hba->priv; + struct ufs_qcom_host *host = ufshcd_get_variant(hba); if (host->hw_ver.major == 0x01) { hba->quirks |= UFSHCD_QUIRK_DELAY_BEFORE_DME_CMDS @@ -724,10 +1028,11 @@ static void ufs_qcom_advertise_quirks(struct ufs_hba *hba) if (host->hw_ver.minor == 0x0001 && host->hw_ver.step == 0x0001) hba->quirks |= UFSHCD_QUIRK_BROKEN_INTR_AGGR; + + hba->quirks |= UFSHCD_QUIRK_BROKEN_LCC; } if (host->hw_ver.major >= 0x2) { - hba->quirks |= UFSHCD_QUIRK_BROKEN_LCC; hba->quirks |= UFSHCD_QUIRK_BROKEN_UFS_HCI_VERSION; if (!ufs_qcom_cap_qunipro(host)) @@ -740,79 +1045,29 @@ static void ufs_qcom_advertise_quirks(struct ufs_hba *hba) static void ufs_qcom_set_caps(struct ufs_hba *hba) { - struct ufs_qcom_host *host = hba->priv; + struct ufs_qcom_host *host = ufshcd_get_variant(hba); - if (host->hw_ver.major >= 0x2) - host->caps = UFS_QCOM_CAP_QUNIPRO; -} - -static int ufs_qcom_get_bus_vote(struct ufs_qcom_host *host, - const char *speed_mode) -{ - struct device *dev = host->hba->dev; - struct device_node *np = dev->of_node; - int err; - const char *key = "qcom,bus-vector-names"; - - if (!speed_mode) { - err = -EINVAL; - goto out; - } - - if (host->bus_vote.is_max_bw_needed && !!strcmp(speed_mode, "MIN")) - err = of_property_match_string(np, key, "MAX"); - else - err = of_property_match_string(np, key, speed_mode); - -out: - if (err < 0) - dev_err(dev, "%s: Invalid %s mode %d\n", - __func__, speed_mode, err); - return err; -} - -static int ufs_qcom_set_bus_vote(struct ufs_qcom_host *host, int vote) -{ - int err = 0; - - if (vote != host->bus_vote.curr_vote) - host->bus_vote.curr_vote = vote; - - return err; -} - -static void ufs_qcom_get_speed_mode(struct ufs_pa_layer_attr *p, char *result) -{ - int gear = max_t(u32, p->gear_rx, p->gear_tx); - int lanes = max_t(u32, p->lane_rx, p->lane_tx); - int pwr; - - /* default to PWM Gear 1, Lane 1 if power mode is not initialized */ - if (!gear) - gear = 1; - - if (!lanes) - lanes = 1; + hba->caps |= UFSHCD_CAP_CLK_GATING | UFSHCD_CAP_HIBERN8_WITH_CLK_GATING; + hba->caps |= UFSHCD_CAP_CLK_SCALING; + hba->caps |= UFSHCD_CAP_AUTO_BKOPS_SUSPEND; - if (!p->pwr_rx && !p->pwr_tx) { - pwr = SLOWAUTO_MODE; - snprintf(result, BUS_VECTOR_NAME_LEN, "MIN"); - } else if (p->pwr_rx == FAST_MODE || p->pwr_rx == FASTAUTO_MODE || - p->pwr_tx == FAST_MODE || p->pwr_tx == FASTAUTO_MODE) { - pwr = FAST_MODE; - snprintf(result, BUS_VECTOR_NAME_LEN, "%s_R%s_G%d_L%d", "HS", - p->hs_rate == PA_HS_MODE_B ? "B" : "A", gear, lanes); - } else { - pwr = SLOW_MODE; - snprintf(result, BUS_VECTOR_NAME_LEN, "%s_G%d_L%d", - "PWM", gear, lanes); + if (host->hw_ver.major >= 0x2) { + host->caps = UFS_QCOM_CAP_QUNIPRO | + UFS_QCOM_CAP_RETAIN_SEC_CFG_AFTER_PWR_COLLAPSE; } } +/** + * ufs_qcom_setup_clocks - enables/disable clocks + * @hba: host controller instance + * @on: If true, enable clocks else disable them. + * + * Returns 0 on success, non-zero on failure. + */ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on) { - struct ufs_qcom_host *host = hba->priv; - int err = 0; + struct ufs_qcom_host *host = ufshcd_get_variant(hba); + int err; int vote = 0; /* @@ -835,20 +1090,18 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on) ufs_qcom_phy_disable_iface_clk(host->generic_phy); goto out; } - /* enable the device ref clock */ - ufs_qcom_phy_enable_dev_ref_clk(host->generic_phy); vote = host->bus_vote.saved_vote; if (vote == host->bus_vote.min_bw_vote) ufs_qcom_update_bus_bw_vote(host); + } else { + /* M-PHY RMMI interface clocks can be turned off */ ufs_qcom_phy_disable_iface_clk(host->generic_phy); - if (!ufs_qcom_is_link_active(hba)) { - /* turn off UFS local PHY ref_clk */ - ufs_qcom_phy_disable_ref_clk(host->generic_phy); + if (!ufs_qcom_is_link_active(hba)) /* disable device ref_clk */ - ufs_qcom_phy_disable_dev_ref_clk(host->generic_phy); - } + ufs_qcom_dev_ref_clk_ctrl(host, false); + vote = host->bus_vote.min_bw_vote; } @@ -861,68 +1114,17 @@ out: return err; } -static ssize_t -show_ufs_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct ufs_hba *hba = dev_get_drvdata(dev); - struct ufs_qcom_host *host = hba->priv; - - return snprintf(buf, PAGE_SIZE, "%u\n", - host->bus_vote.is_max_bw_needed); -} - -static ssize_t -store_ufs_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct ufs_hba *hba = dev_get_drvdata(dev); - struct ufs_qcom_host *host = hba->priv; - uint32_t value; - - if (!kstrtou32(buf, 0, &value)) { - host->bus_vote.is_max_bw_needed = !!value; - ufs_qcom_update_bus_bw_vote(host); - } - - return count; -} - -static int ufs_qcom_bus_register(struct ufs_qcom_host *host) -{ - int err; - struct device *dev = host->hba->dev; - struct device_node *np = dev->of_node; - - err = of_property_count_strings(np, "qcom,bus-vector-names"); - if (err < 0 ) { - dev_err(dev, "%s: qcom,bus-vector-names not specified correctly %d\n", - __func__, err); - goto out; - } - - /* cache the vote index for minimum and maximum bandwidth */ - host->bus_vote.min_bw_vote = ufs_qcom_get_bus_vote(host, "MIN"); - host->bus_vote.max_bw_vote = ufs_qcom_get_bus_vote(host, "MAX"); - - host->bus_vote.max_bus_bw.show = show_ufs_to_mem_max_bus_bw; - host->bus_vote.max_bus_bw.store = store_ufs_to_mem_max_bus_bw; - sysfs_attr_init(&host->bus_vote.max_bus_bw.attr); - host->bus_vote.max_bus_bw.attr.name = "max_bus_bw"; - host->bus_vote.max_bus_bw.attr.mode = S_IRUGO | S_IWUSR; - err = device_create_file(dev, &host->bus_vote.max_bus_bw); -out: - return err; -} - #define ANDROID_BOOT_DEV_MAX 30 static char android_boot_dev[ANDROID_BOOT_DEV_MAX]; -static int get_android_boot_dev(char *str) + +#ifndef MODULE +static int __init get_android_boot_dev(char *str) { strlcpy(android_boot_dev, str, ANDROID_BOOT_DEV_MAX); return 1; } __setup("androidboot.bootdevice=", get_android_boot_dev); +#endif /** * ufs_qcom_init - bind phy with controller @@ -938,7 +1140,9 @@ static int ufs_qcom_init(struct ufs_hba *hba) { int err; struct device *dev = hba->dev; + struct platform_device *pdev = to_platform_device(dev); struct ufs_qcom_host *host; + struct resource *res; if (strlen(android_boot_dev) && strcmp(android_boot_dev, dev_name(dev))) return -ENODEV; @@ -950,9 +1154,15 @@ static int ufs_qcom_init(struct ufs_hba *hba) goto out; } + /* Make a two way bind between the qcom host and the hba */ host->hba = hba; - hba->priv = (void *)host; + ufshcd_set_variant(hba, host); + /* + * voting/devoting device ref_clk source is time consuming hence + * skip devoting it during aggressive clock gating. This clock + * will still be gated off during runtime suspend. + */ host->generic_phy = devm_phy_get(dev, "ufsphy"); if (IS_ERR(host->generic_phy)) { @@ -968,6 +1178,30 @@ static int ufs_qcom_init(struct ufs_hba *hba) ufs_qcom_get_controller_revision(hba, &host->hw_ver.major, &host->hw_ver.minor, &host->hw_ver.step); + /* + * for newer controllers, device reference clock control bit has + * moved inside UFS controller register address space itself. + */ + if (host->hw_ver.major >= 0x02) { + host->dev_ref_clk_ctrl_mmio = hba->mmio_base + REG_UFS_CFG1; + host->dev_ref_clk_en_mask = BIT(26); + } else { + /* "dev_ref_clk_ctrl_mem" is optional resource */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (res) { + host->dev_ref_clk_ctrl_mmio = + devm_ioremap_resource(dev, res); + if (IS_ERR(host->dev_ref_clk_ctrl_mmio)) { + dev_warn(dev, + "%s: could not map dev_ref_clk_ctrl_mmio, err %ld\n", + __func__, + PTR_ERR(host->dev_ref_clk_ctrl_mmio)); + host->dev_ref_clk_ctrl_mmio = NULL; + } + host->dev_ref_clk_en_mask = BIT(5); + } + } + /* update phy revision information before calling phy_init() */ ufs_qcom_phy_save_controller_version(host->generic_phy, host->hw_ver.major, host->hw_ver.minor, host->hw_ver.step); @@ -984,14 +1218,20 @@ static int ufs_qcom_init(struct ufs_hba *hba) ufs_qcom_set_caps(hba); ufs_qcom_advertise_quirks(hba); - hba->caps |= UFSHCD_CAP_CLK_GATING | UFSHCD_CAP_CLK_SCALING; - hba->caps |= UFSHCD_CAP_AUTO_BKOPS_SUSPEND; - ufs_qcom_setup_clocks(hba, true); if (hba->dev->id < MAX_UFS_QCOM_HOSTS) ufs_qcom_hosts[hba->dev->id] = host; + host->dbg_print_en |= UFS_QCOM_DEFAULT_DBG_PRINT_EN; + ufs_qcom_get_default_testbus_cfg(host); + err = ufs_qcom_testbus_config(host); + if (err) { + dev_warn(dev, "%s: failed to configure the testbus %d\n", + __func__, err); + err = 0; + } + goto out; out_disable_phy: @@ -1000,40 +1240,266 @@ out_unregister_bus: phy_exit(host->generic_phy); out_host_free: devm_kfree(dev, host); - hba->priv = NULL; + ufshcd_set_variant(hba, NULL); out: return err; } static void ufs_qcom_exit(struct ufs_hba *hba) { - struct ufs_qcom_host *host = hba->priv; + struct ufs_qcom_host *host = ufshcd_get_variant(hba); ufs_qcom_disable_lane_clks(host); phy_power_off(host->generic_phy); } -static -void ufs_qcom_clk_scale_notify(struct ufs_hba *hba) +static int ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(struct ufs_hba *hba, + u32 clk_cycles) +{ + int err; + u32 core_clk_ctrl_reg; + + if (clk_cycles > DME_VS_CORE_CLK_CTRL_MAX_CORE_CLK_1US_CYCLES_MASK) + return -EINVAL; + + err = ufshcd_dme_get(hba, + UIC_ARG_MIB(DME_VS_CORE_CLK_CTRL), + &core_clk_ctrl_reg); + if (err) + goto out; + + core_clk_ctrl_reg &= ~DME_VS_CORE_CLK_CTRL_MAX_CORE_CLK_1US_CYCLES_MASK; + core_clk_ctrl_reg |= clk_cycles; + + /* Clear CORE_CLK_DIV_EN */ + core_clk_ctrl_reg &= ~DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT; + + err = ufshcd_dme_set(hba, + UIC_ARG_MIB(DME_VS_CORE_CLK_CTRL), + core_clk_ctrl_reg); +out: + return err; +} + +static int ufs_qcom_clk_scale_up_pre_change(struct ufs_hba *hba) +{ + /* nothing to do as of now */ + return 0; +} + +static int ufs_qcom_clk_scale_up_post_change(struct ufs_hba *hba) +{ + struct ufs_qcom_host *host = ufshcd_get_variant(hba); + + if (!ufs_qcom_cap_qunipro(host)) + return 0; + + /* set unipro core clock cycles to 150 and clear clock divider */ + return ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(hba, 150); +} + +static int ufs_qcom_clk_scale_down_pre_change(struct ufs_hba *hba) +{ + struct ufs_qcom_host *host = ufshcd_get_variant(hba); + int err; + u32 core_clk_ctrl_reg; + + if (!ufs_qcom_cap_qunipro(host)) + return 0; + + err = ufshcd_dme_get(hba, + UIC_ARG_MIB(DME_VS_CORE_CLK_CTRL), + &core_clk_ctrl_reg); + + /* make sure CORE_CLK_DIV_EN is cleared */ + if (!err && + (core_clk_ctrl_reg & DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT)) { + core_clk_ctrl_reg &= ~DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT; + err = ufshcd_dme_set(hba, + UIC_ARG_MIB(DME_VS_CORE_CLK_CTRL), + core_clk_ctrl_reg); + } + + return err; +} + +static int ufs_qcom_clk_scale_down_post_change(struct ufs_hba *hba) +{ + struct ufs_qcom_host *host = ufshcd_get_variant(hba); + + if (!ufs_qcom_cap_qunipro(host)) + return 0; + + /* set unipro core clock cycles to 75 and clear clock divider */ + return ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(hba, 75); +} + +static int ufs_qcom_clk_scale_notify(struct ufs_hba *hba, + bool scale_up, enum ufs_notify_change_status status) { - struct ufs_qcom_host *host = hba->priv; + struct ufs_qcom_host *host = ufshcd_get_variant(hba); struct ufs_pa_layer_attr *dev_req_params = &host->dev_req_params; + int err = 0; - if (!dev_req_params) - return; + if (status == PRE_CHANGE) { + if (scale_up) + err = ufs_qcom_clk_scale_up_pre_change(hba); + else + err = ufs_qcom_clk_scale_down_pre_change(hba); + } else { + if (scale_up) + err = ufs_qcom_clk_scale_up_post_change(hba); + else + err = ufs_qcom_clk_scale_down_post_change(hba); - ufs_qcom_cfg_timers(hba, dev_req_params->gear_rx, - dev_req_params->pwr_rx, - dev_req_params->hs_rate); + if (err || !dev_req_params) + goto out; + + ufs_qcom_cfg_timers(hba, + dev_req_params->gear_rx, + dev_req_params->pwr_rx, + dev_req_params->hs_rate, + false); + ufs_qcom_update_bus_bw_vote(host); + } + +out: + return err; } +static void ufs_qcom_get_default_testbus_cfg(struct ufs_qcom_host *host) +{ + /* provide a legal default configuration */ + host->testbus.select_major = TSTBUS_UAWM; + host->testbus.select_minor = 1; +} + +static bool ufs_qcom_testbus_cfg_is_ok(struct ufs_qcom_host *host) +{ + if (host->testbus.select_major >= TSTBUS_MAX) { + dev_err(host->hba->dev, + "%s: UFS_CFG1[TEST_BUS_SEL} may not equal 0x%05X\n", + __func__, host->testbus.select_major); + return false; + } + + /* + * Not performing check for each individual select_major + * mappings of select_minor, since there is no harm in + * configuring a non-existent select_minor + */ + if (host->testbus.select_minor > 0x1F) { + dev_err(host->hba->dev, + "%s: 0x%05X is not a legal testbus option\n", + __func__, host->testbus.select_minor); + return false; + } + + return true; +} + +int ufs_qcom_testbus_config(struct ufs_qcom_host *host) +{ + int reg; + int offset; + u32 mask = TEST_BUS_SUB_SEL_MASK; + + if (!host) + return -EINVAL; + + if (!ufs_qcom_testbus_cfg_is_ok(host)) + return -EPERM; + + switch (host->testbus.select_major) { + case TSTBUS_UAWM: + reg = UFS_TEST_BUS_CTRL_0; + offset = 24; + break; + case TSTBUS_UARM: + reg = UFS_TEST_BUS_CTRL_0; + offset = 16; + break; + case TSTBUS_TXUC: + reg = UFS_TEST_BUS_CTRL_0; + offset = 8; + break; + case TSTBUS_RXUC: + reg = UFS_TEST_BUS_CTRL_0; + offset = 0; + break; + case TSTBUS_DFC: + reg = UFS_TEST_BUS_CTRL_1; + offset = 24; + break; + case TSTBUS_TRLUT: + reg = UFS_TEST_BUS_CTRL_1; + offset = 16; + break; + case TSTBUS_TMRLUT: + reg = UFS_TEST_BUS_CTRL_1; + offset = 8; + break; + case TSTBUS_OCSC: + reg = UFS_TEST_BUS_CTRL_1; + offset = 0; + break; + case TSTBUS_WRAPPER: + reg = UFS_TEST_BUS_CTRL_2; + offset = 16; + break; + case TSTBUS_COMBINED: + reg = UFS_TEST_BUS_CTRL_2; + offset = 8; + break; + case TSTBUS_UTP_HCI: + reg = UFS_TEST_BUS_CTRL_2; + offset = 0; + break; + case TSTBUS_UNIPRO: + reg = UFS_UNIPRO_CFG; + offset = 1; + break; + /* + * No need for a default case, since + * ufs_qcom_testbus_cfg_is_ok() checks that the configuration + * is legal + */ + } + mask <<= offset; + + pm_runtime_get_sync(host->hba->dev); + ufshcd_hold(host->hba, false); + ufshcd_rmwl(host->hba, TEST_BUS_SEL, + (u32)host->testbus.select_major << 19, + REG_UFS_CFG1); + ufshcd_rmwl(host->hba, mask, + (u32)host->testbus.select_minor << offset, + reg); + ufshcd_release(host->hba); + pm_runtime_put_sync(host->hba->dev); + + return 0; +} + +static void ufs_qcom_testbus_read(struct ufs_hba *hba) +{ + ufs_qcom_dump_regs(hba, UFS_TEST_BUS, 1, "UFS_TEST_BUS "); +} + +static void ufs_qcom_dump_dbg_regs(struct ufs_hba *hba) +{ + ufs_qcom_dump_regs(hba, REG_UFS_SYS1CLK_1US, 16, + "HCI Vendor Specific Registers "); + + ufs_qcom_testbus_read(hba); +} /** * struct ufs_hba_qcom_vops - UFS QCOM specific variant operations * * The variant operations configure the necessary controller and PHY * handshake during initialization. */ -static const struct ufs_hba_variant_ops ufs_hba_qcom_vops = { +static struct ufs_hba_variant_ops ufs_hba_qcom_vops = { .name = "qcom", .init = ufs_qcom_init, .exit = ufs_qcom_exit, @@ -1045,5 +1511,66 @@ static const struct ufs_hba_variant_ops ufs_hba_qcom_vops = { .pwr_change_notify = ufs_qcom_pwr_change_notify, .suspend = ufs_qcom_suspend, .resume = ufs_qcom_resume, + .dbg_register_dump = ufs_qcom_dump_dbg_regs, +}; + +/** + * ufs_qcom_probe - probe routine of the driver + * @pdev: pointer to Platform device handle + * + * Return zero for success and non-zero for failure + */ +static int ufs_qcom_probe(struct platform_device *pdev) +{ + int err; + struct device *dev = &pdev->dev; + + /* Perform generic probe */ + err = ufshcd_pltfrm_init(pdev, &ufs_hba_qcom_vops); + if (err) + dev_err(dev, "ufshcd_pltfrm_init() failed %d\n", err); + + return err; +} + +/** + * ufs_qcom_remove - set driver_data of the device to NULL + * @pdev: pointer to platform device handle + * + * Always return 0 + */ +static int ufs_qcom_remove(struct platform_device *pdev) +{ + struct ufs_hba *hba = platform_get_drvdata(pdev); + + pm_runtime_get_sync(&(pdev)->dev); + ufshcd_remove(hba); + return 0; +} + +static const struct of_device_id ufs_qcom_of_match[] = { + { .compatible = "qcom,ufshc"}, + {}, +}; + +static const struct dev_pm_ops ufs_qcom_pm_ops = { + .suspend = ufshcd_pltfrm_suspend, + .resume = ufshcd_pltfrm_resume, + .runtime_suspend = ufshcd_pltfrm_runtime_suspend, + .runtime_resume = ufshcd_pltfrm_runtime_resume, + .runtime_idle = ufshcd_pltfrm_runtime_idle, }; -EXPORT_SYMBOL(ufs_hba_qcom_vops); + +static struct platform_driver ufs_qcom_pltform = { + .probe = ufs_qcom_probe, + .remove = ufs_qcom_remove, + .shutdown = ufshcd_pltfrm_shutdown, + .driver = { + .name = "ufshcd-qcom", + .pm = &ufs_qcom_pm_ops, + .of_match_table = of_match_ptr(ufs_qcom_of_match), + }, +}; +module_platform_driver(ufs_qcom_pltform); + +MODULE_LICENSE("GPL v2"); diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h index db2c0a00e846..36249b35f858 100644 --- a/drivers/scsi/ufs/ufs-qcom.h +++ b/drivers/scsi/ufs/ufs-qcom.h @@ -35,8 +35,8 @@ #define UFS_QCOM_LIMIT_NUM_LANES_RX 2 #define UFS_QCOM_LIMIT_NUM_LANES_TX 2 -#define UFS_QCOM_LIMIT_HSGEAR_RX UFS_HS_G2 -#define UFS_QCOM_LIMIT_HSGEAR_TX UFS_HS_G2 +#define UFS_QCOM_LIMIT_HSGEAR_RX UFS_HS_G3 +#define UFS_QCOM_LIMIT_HSGEAR_TX UFS_HS_G3 #define UFS_QCOM_LIMIT_PWMGEAR_RX UFS_PWM_G4 #define UFS_QCOM_LIMIT_PWMGEAR_TX UFS_PWM_G4 #define UFS_QCOM_LIMIT_RX_PWR_PWM SLOW_MODE @@ -58,6 +58,21 @@ enum { REG_UFS_CFG2 = 0xE0, REG_UFS_HW_VERSION = 0xE4, + UFS_TEST_BUS = 0xE8, + UFS_TEST_BUS_CTRL_0 = 0xEC, + UFS_TEST_BUS_CTRL_1 = 0xF0, + UFS_TEST_BUS_CTRL_2 = 0xF4, + UFS_UNIPRO_CFG = 0xF8, + + /* + * QCOM UFS host controller vendor specific registers + * added in HW Version 3.0.0 + */ + UFS_AH8_CFG = 0xFC, +}; + +/* QCOM UFS host controller vendor specific debug registers */ +enum { UFS_DBG_RD_REG_UAWM = 0x100, UFS_DBG_RD_REG_UARM = 0x200, UFS_DBG_RD_REG_TXUC = 0x300, @@ -73,6 +88,14 @@ enum { UFS_UFS_DBG_RD_EDTL_RAM = 0x1900, }; +#define UFS_CNTLR_2_x_x_VEN_REGS_OFFSET(x) (0x000 + x) +#define UFS_CNTLR_3_x_x_VEN_REGS_OFFSET(x) (0x400 + x) + +/* bit definitions for REG_UFS_CFG1 register */ +#define QUNIPRO_SEL UFS_BIT(0) +#define TEST_BUS_EN BIT(18) +#define TEST_BUS_SEL GENMASK(22, 19) + /* bit definitions for REG_UFS_CFG2 register */ #define UAWM_HW_CGC_EN (1 << 0) #define UARM_HW_CGC_EN (1 << 1) @@ -83,6 +106,9 @@ enum { #define TMRLUT_HW_CGC_EN (1 << 6) #define OCSC_HW_CGC_EN (1 << 7) +/* bit definition for UFS_UFS_TEST_BUS_CTRL_n */ +#define TEST_BUS_SUB_SEL_MASK 0x1F /* All XXX_SEL fields are 5 bits wide */ + #define REG_UFS_CFG2_CGC_EN_ALL (UAWM_HW_CGC_EN | UARM_HW_CGC_EN |\ TXUC_HW_CGC_EN | RXUC_HW_CGC_EN |\ DFC_HW_CGC_EN | TRLUT_HW_CGC_EN |\ @@ -106,6 +132,21 @@ enum ufs_qcom_phy_init_type { UFS_PHY_INIT_CFG_RESTORE, }; +/* QCOM UFS debug print bit mask */ +#define UFS_QCOM_DBG_PRINT_REGS_EN BIT(0) +#define UFS_QCOM_DBG_PRINT_ICE_REGS_EN BIT(1) +#define UFS_QCOM_DBG_PRINT_TEST_BUS_EN BIT(2) + +#define UFS_QCOM_DBG_PRINT_ALL \ + (UFS_QCOM_DBG_PRINT_REGS_EN | UFS_QCOM_DBG_PRINT_ICE_REGS_EN | \ + UFS_QCOM_DBG_PRINT_TEST_BUS_EN) + +/* QUniPro Vendor specific attributes */ +#define DME_VS_CORE_CLK_CTRL 0xD002 +/* bit and mask definitions for DME_VS_CORE_CLK_CTRL attribute */ +#define DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT BIT(8) +#define DME_VS_CORE_CLK_CTRL_MAX_CORE_CLK_1US_CYCLES_MASK 0xFF + static inline void ufs_qcom_get_controller_revision(struct ufs_hba *hba, u8 *major, u16 *minor, u16 *step) @@ -157,8 +198,13 @@ struct ufs_hw_version { u16 minor; u8 major; }; -struct ufs_qcom_host { +struct ufs_qcom_testbus { + u8 select_major; + u8 select_minor; +}; + +struct ufs_qcom_host { /* * Set this capability if host controller supports the QUniPro mode * and if driver wants the Host controller to operate in QUniPro mode. @@ -166,6 +212,12 @@ struct ufs_qcom_host { * controller supports the QUniPro mode. */ #define UFS_QCOM_CAP_QUNIPRO UFS_BIT(0) + + /* + * Set this capability if host controller can retain the secure + * configuration even after UFS controller core power collapse. + */ + #define UFS_QCOM_CAP_RETAIN_SEC_CFG_AFTER_PWR_COLLAPSE UFS_BIT(1) u32 caps; struct phy *generic_phy; @@ -178,13 +230,23 @@ struct ufs_qcom_host { struct clk *tx_l1_sync_clk; bool is_lane_clks_enabled; + void __iomem *dev_ref_clk_ctrl_mmio; + bool is_dev_ref_clk_enabled; struct ufs_hw_version hw_ver; + + u32 dev_ref_clk_en_mask; + + /* Bitmask for enabling debug prints */ + u32 dbg_print_en; + struct ufs_qcom_testbus testbus; }; #define ufs_qcom_is_link_off(hba) ufshcd_is_link_off(hba) #define ufs_qcom_is_link_active(hba) ufshcd_is_link_active(hba) #define ufs_qcom_is_link_hibern8(hba) ufshcd_is_link_hibern8(hba) +int ufs_qcom_testbus_config(struct ufs_qcom_host *host); + static inline bool ufs_qcom_cap_qunipro(struct ufs_qcom_host *host) { if (host->caps & UFS_QCOM_CAP_QUNIPRO) diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c index 7db9564f507d..9714f2a8b329 100644 --- a/drivers/scsi/ufs/ufshcd-pltfrm.c +++ b/drivers/scsi/ufs/ufshcd-pltfrm.c @@ -38,20 +38,7 @@ #include <linux/of.h> #include "ufshcd.h" - -static const struct of_device_id ufs_of_match[]; -static struct ufs_hba_variant_ops *get_variant_ops(struct device *dev) -{ - if (dev->of_node) { - const struct of_device_id *match; - - match = of_match_node(ufs_of_match, dev->of_node); - if (match) - return (struct ufs_hba_variant_ops *)match->data; - } - - return NULL; -} +#include "ufshcd-pltfrm.h" static int ufshcd_parse_clock_info(struct ufs_hba *hba) { @@ -245,10 +232,11 @@ out: * Returns 0 if successful * Returns non-zero otherwise */ -static int ufshcd_pltfrm_suspend(struct device *dev) +int ufshcd_pltfrm_suspend(struct device *dev) { return ufshcd_system_suspend(dev_get_drvdata(dev)); } +EXPORT_SYMBOL_GPL(ufshcd_pltfrm_suspend); /** * ufshcd_pltfrm_resume - resume power management function @@ -257,43 +245,47 @@ static int ufshcd_pltfrm_suspend(struct device *dev) * Returns 0 if successful * Returns non-zero otherwise */ -static int ufshcd_pltfrm_resume(struct device *dev) +int ufshcd_pltfrm_resume(struct device *dev) { return ufshcd_system_resume(dev_get_drvdata(dev)); } +EXPORT_SYMBOL_GPL(ufshcd_pltfrm_resume); -static int ufshcd_pltfrm_runtime_suspend(struct device *dev) +int ufshcd_pltfrm_runtime_suspend(struct device *dev) { return ufshcd_runtime_suspend(dev_get_drvdata(dev)); } -static int ufshcd_pltfrm_runtime_resume(struct device *dev) +EXPORT_SYMBOL_GPL(ufshcd_pltfrm_runtime_suspend); + +int ufshcd_pltfrm_runtime_resume(struct device *dev) { return ufshcd_runtime_resume(dev_get_drvdata(dev)); } -static int ufshcd_pltfrm_runtime_idle(struct device *dev) +EXPORT_SYMBOL_GPL(ufshcd_pltfrm_runtime_resume); + +int ufshcd_pltfrm_runtime_idle(struct device *dev) { return ufshcd_runtime_idle(dev_get_drvdata(dev)); } -#else /* !CONFIG_PM */ -#define ufshcd_pltfrm_suspend NULL -#define ufshcd_pltfrm_resume NULL -#define ufshcd_pltfrm_runtime_suspend NULL -#define ufshcd_pltfrm_runtime_resume NULL -#define ufshcd_pltfrm_runtime_idle NULL +EXPORT_SYMBOL_GPL(ufshcd_pltfrm_runtime_idle); + #endif /* CONFIG_PM */ -static void ufshcd_pltfrm_shutdown(struct platform_device *pdev) +void ufshcd_pltfrm_shutdown(struct platform_device *pdev) { ufshcd_shutdown((struct ufs_hba *)platform_get_drvdata(pdev)); } +EXPORT_SYMBOL_GPL(ufshcd_pltfrm_shutdown); /** - * ufshcd_pltfrm_probe - probe routine of the driver + * ufshcd_pltfrm_init - probe routine of the driver * @pdev: pointer to Platform device handle + * @vops: pointer to variant ops * * Returns 0 on success, non-zero value on failure */ -static int ufshcd_pltfrm_probe(struct platform_device *pdev) +int ufshcd_pltfrm_init(struct platform_device *pdev, + struct ufs_hba_variant_ops *vops) { struct ufs_hba *hba; void __iomem *mmio_base; @@ -321,19 +313,19 @@ static int ufshcd_pltfrm_probe(struct platform_device *pdev) goto out; } - hba->vops = get_variant_ops(&pdev->dev); + hba->vops = vops; err = ufshcd_parse_clock_info(hba); if (err) { dev_err(&pdev->dev, "%s: clock parse failed %d\n", __func__, err); - goto out; + goto dealloc_host; } err = ufshcd_parse_regulator_info(hba); if (err) { dev_err(&pdev->dev, "%s: regulator init failed %d\n", __func__, err); - goto out; + goto dealloc_host; } pm_runtime_set_active(&pdev->dev); @@ -352,50 +344,12 @@ static int ufshcd_pltfrm_probe(struct platform_device *pdev) out_disable_rpm: pm_runtime_disable(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); +dealloc_host: + ufshcd_dealloc_host(hba); out: return err; } - -/** - * ufshcd_pltfrm_remove - remove platform driver routine - * @pdev: pointer to platform device handle - * - * Returns 0 on success, non-zero value on failure - */ -static int ufshcd_pltfrm_remove(struct platform_device *pdev) -{ - struct ufs_hba *hba = platform_get_drvdata(pdev); - - pm_runtime_get_sync(&(pdev)->dev); - ufshcd_remove(hba); - return 0; -} - -static const struct of_device_id ufs_of_match[] = { - { .compatible = "jedec,ufs-1.1"}, - {}, -}; - -static const struct dev_pm_ops ufshcd_dev_pm_ops = { - .suspend = ufshcd_pltfrm_suspend, - .resume = ufshcd_pltfrm_resume, - .runtime_suspend = ufshcd_pltfrm_runtime_suspend, - .runtime_resume = ufshcd_pltfrm_runtime_resume, - .runtime_idle = ufshcd_pltfrm_runtime_idle, -}; - -static struct platform_driver ufshcd_pltfrm_driver = { - .probe = ufshcd_pltfrm_probe, - .remove = ufshcd_pltfrm_remove, - .shutdown = ufshcd_pltfrm_shutdown, - .driver = { - .name = "ufshcd", - .pm = &ufshcd_dev_pm_ops, - .of_match_table = ufs_of_match, - }, -}; - -module_platform_driver(ufshcd_pltfrm_driver); +EXPORT_SYMBOL_GPL(ufshcd_pltfrm_init); MODULE_AUTHOR("Santosh Yaragnavi <santosh.sy@samsung.com>"); MODULE_AUTHOR("Vinayak Holikatti <h.vinayak@samsung.com>"); diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.h b/drivers/scsi/ufs/ufshcd-pltfrm.h new file mode 100644 index 000000000000..df64c4180340 --- /dev/null +++ b/drivers/scsi/ufs/ufshcd-pltfrm.h @@ -0,0 +1,41 @@ +/* Copyright (c) 2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef UFSHCD_PLTFRM_H_ +#define UFSHCD_PLTFRM_H_ + +#include "ufshcd.h" + +int ufshcd_pltfrm_init(struct platform_device *pdev, + struct ufs_hba_variant_ops *vops); +void ufshcd_pltfrm_shutdown(struct platform_device *pdev); + +#ifdef CONFIG_PM + +int ufshcd_pltfrm_suspend(struct device *dev); +int ufshcd_pltfrm_resume(struct device *dev); +int ufshcd_pltfrm_runtime_suspend(struct device *dev); +int ufshcd_pltfrm_runtime_resume(struct device *dev); +int ufshcd_pltfrm_runtime_idle(struct device *dev); + +#else /* !CONFIG_PM */ + +#define ufshcd_pltfrm_suspend NULL +#define ufshcd_pltfrm_resume NULL +#define ufshcd_pltfrm_runtime_suspend NULL +#define ufshcd_pltfrm_runtime_resume NULL +#define ufshcd_pltfrm_runtime_idle NULL + +#endif /* CONFIG_PM */ + +#endif /* UFSHCD_PLTFRM_H_ */ diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index b0ade73f8c6a..85cd2564c157 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -271,10 +271,8 @@ static inline u32 ufshcd_get_intr_mask(struct ufs_hba *hba) */ static inline u32 ufshcd_get_ufs_version(struct ufs_hba *hba) { - if (hba->quirks & UFSHCD_QUIRK_BROKEN_UFS_HCI_VERSION) { - if (hba->vops && hba->vops->get_ufs_hci_version) - return hba->vops->get_ufs_hci_version(hba); - } + if (hba->quirks & UFSHCD_QUIRK_BROKEN_UFS_HCI_VERSION) + return ufshcd_vops_get_ufs_hci_version(hba); return ufshcd_readl(hba, REG_UFS_VERSION); } @@ -627,6 +625,7 @@ start: out: return rc; } +EXPORT_SYMBOL_GPL(ufshcd_hold); static void ufshcd_gate_work(struct work_struct *work) { @@ -714,6 +713,7 @@ void ufshcd_release(struct ufs_hba *hba) __ufshcd_release(hba); spin_unlock_irqrestore(hba->host->host_lock, flags); } +EXPORT_SYMBOL_GPL(ufshcd_release); static ssize_t ufshcd_clkgate_delay_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -2473,9 +2473,8 @@ static int ufshcd_change_power_mode(struct ufs_hba *hba, dev_err(hba->dev, "%s: power mode change failed %d\n", __func__, ret); } else { - if (hba->vops && hba->vops->pwr_change_notify) - hba->vops->pwr_change_notify(hba, - POST_CHANGE, NULL, pwr_mode); + ufshcd_vops_pwr_change_notify(hba, POST_CHANGE, NULL, + pwr_mode); memcpy(&hba->pwr_info, pwr_mode, sizeof(struct ufs_pa_layer_attr)); @@ -2495,10 +2494,10 @@ static int ufshcd_config_pwr_mode(struct ufs_hba *hba, struct ufs_pa_layer_attr final_params = { 0 }; int ret; - if (hba->vops && hba->vops->pwr_change_notify) - hba->vops->pwr_change_notify(hba, - PRE_CHANGE, desired_pwr_mode, &final_params); - else + ret = ufshcd_vops_pwr_change_notify(hba, PRE_CHANGE, + desired_pwr_mode, &final_params); + + if (ret) memcpy(&final_params, desired_pwr_mode, sizeof(final_params)); ret = ufshcd_change_power_mode(hba, &final_params); @@ -2647,8 +2646,7 @@ static int ufshcd_hba_enable(struct ufs_hba *hba) /* UniPro link is disabled at this point */ ufshcd_set_link_off(hba); - if (hba->vops && hba->vops->hce_enable_notify) - hba->vops->hce_enable_notify(hba, PRE_CHANGE); + ufshcd_vops_hce_enable_notify(hba, PRE_CHANGE); /* start controller initialization sequence */ ufshcd_hba_start(hba); @@ -2681,8 +2679,7 @@ static int ufshcd_hba_enable(struct ufs_hba *hba) /* enable UIC related interrupts */ ufshcd_enable_intr(hba, UFSHCD_UIC_MASK); - if (hba->vops && hba->vops->hce_enable_notify) - hba->vops->hce_enable_notify(hba, POST_CHANGE); + ufshcd_vops_hce_enable_notify(hba, POST_CHANGE); return 0; } @@ -2735,8 +2732,7 @@ static int ufshcd_link_startup(struct ufs_hba *hba) int retries = DME_LINKSTARTUP_RETRIES; do { - if (hba->vops && hba->vops->link_startup_notify) - hba->vops->link_startup_notify(hba, PRE_CHANGE); + ufshcd_vops_link_startup_notify(hba, PRE_CHANGE); ret = ufshcd_dme_link_startup(hba); @@ -2767,11 +2763,9 @@ static int ufshcd_link_startup(struct ufs_hba *hba) } /* Include any host controller configuration via UIC commands */ - if (hba->vops && hba->vops->link_startup_notify) { - ret = hba->vops->link_startup_notify(hba, POST_CHANGE); - if (ret) - goto out; - } + ret = ufshcd_vops_link_startup_notify(hba, POST_CHANGE); + if (ret) + goto out; ret = ufshcd_make_hba_operational(hba); out: @@ -4355,7 +4349,6 @@ static struct scsi_host_template ufshcd_driver_template = { .cmd_per_lun = UFSHCD_CMD_PER_LUN, .can_queue = UFSHCD_CAN_QUEUE, .max_host_blocked = 1, - .use_blk_tags = 1, .track_queue_depth = 1, }; @@ -4578,8 +4571,7 @@ static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool on, } } - if (hba->vops && hba->vops->setup_clocks) - ret = hba->vops->setup_clocks(hba, on); + ret = ufshcd_vops_setup_clocks(hba, on); out: if (ret) { list_for_each_entry(clki, head, list) { @@ -4645,27 +4637,22 @@ static int ufshcd_variant_hba_init(struct ufs_hba *hba) if (!hba->vops) goto out; - if (hba->vops->init) { - err = hba->vops->init(hba); - if (err) - goto out; - } + err = ufshcd_vops_init(hba); + if (err) + goto out; - if (hba->vops->setup_regulators) { - err = hba->vops->setup_regulators(hba, true); - if (err) - goto out_exit; - } + err = ufshcd_vops_setup_regulators(hba, true); + if (err) + goto out_exit; goto out; out_exit: - if (hba->vops->exit) - hba->vops->exit(hba); + ufshcd_vops_exit(hba); out: if (err) dev_err(hba->dev, "%s: variant %s init failed err %d\n", - __func__, hba->vops ? hba->vops->name : "", err); + __func__, ufshcd_get_var_name(hba), err); return err; } @@ -4674,14 +4661,11 @@ static void ufshcd_variant_hba_exit(struct ufs_hba *hba) if (!hba->vops) return; - if (hba->vops->setup_clocks) - hba->vops->setup_clocks(hba, false); + ufshcd_vops_setup_clocks(hba, false); - if (hba->vops->setup_regulators) - hba->vops->setup_regulators(hba, false); + ufshcd_vops_setup_regulators(hba, false); - if (hba->vops->exit) - hba->vops->exit(hba); + ufshcd_vops_exit(hba); } static int ufshcd_hba_init(struct ufs_hba *hba) @@ -5058,17 +5042,13 @@ disable_clks: * vendor specific host controller register space call them before the * host clocks are ON. */ - if (hba->vops && hba->vops->suspend) { - ret = hba->vops->suspend(hba, pm_op); - if (ret) - goto set_link_active; - } + ret = ufshcd_vops_suspend(hba, pm_op); + if (ret) + goto set_link_active; - if (hba->vops && hba->vops->setup_clocks) { - ret = hba->vops->setup_clocks(hba, false); - if (ret) - goto vops_resume; - } + ret = ufshcd_vops_setup_clocks(hba, false); + if (ret) + goto vops_resume; if (!ufshcd_is_link_active(hba)) ufshcd_setup_clocks(hba, false); @@ -5079,7 +5059,7 @@ disable_clks: hba->clk_gating.state = CLKS_OFF; /* * Disable the host irq as host controller as there won't be any - * host controller trasanction expected till resume. + * host controller transaction expected till resume. */ ufshcd_disable_irq(hba); /* Put the host controller in low power mode if possible */ @@ -5087,8 +5067,7 @@ disable_clks: goto out; vops_resume: - if (hba->vops && hba->vops->resume) - hba->vops->resume(hba, pm_op); + ufshcd_vops_resume(hba, pm_op); set_link_active: ufshcd_vreg_set_hpm(hba); if (ufshcd_is_link_hibern8(hba) && !ufshcd_uic_hibern8_exit(hba)) @@ -5144,11 +5123,9 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) * vendor specific host controller register space call them when the * host clocks are ON. */ - if (hba->vops && hba->vops->resume) { - ret = hba->vops->resume(hba, pm_op); - if (ret) - goto disable_vreg; - } + ret = ufshcd_vops_resume(hba, pm_op); + if (ret) + goto disable_vreg; if (ufshcd_is_link_hibern8(hba)) { ret = ufshcd_uic_hibern8_exit(hba); @@ -5189,8 +5166,7 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) set_old_link_state: ufshcd_link_state_transition(hba, old_link_state, 0); vendor_suspend: - if (hba->vops && hba->vops->suspend) - hba->vops->suspend(hba, pm_op); + ufshcd_vops_suspend(hba, pm_op); disable_vreg: ufshcd_vreg_set_lpm(hba); disable_irq_and_vops_clks: @@ -5373,6 +5349,16 @@ void ufshcd_remove(struct ufs_hba *hba) EXPORT_SYMBOL_GPL(ufshcd_remove); /** + * ufshcd_dealloc_host - deallocate Host Bus Adapter (HBA) + * @hba: pointer to Host Bus Adapter (HBA) + */ +void ufshcd_dealloc_host(struct ufs_hba *hba) +{ + scsi_host_put(hba->host); +} +EXPORT_SYMBOL_GPL(ufshcd_dealloc_host); + +/** * ufshcd_set_dma_mask - Set dma mask based on the controller * addressing capability * @hba: per adapter instance @@ -5433,6 +5419,10 @@ static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up) if (!head || list_empty(head)) goto out; + ret = ufshcd_vops_clk_scale_notify(hba, scale_up, PRE_CHANGE); + if (ret) + return ret; + list_for_each_entry(clki, head, list) { if (!IS_ERR_OR_NULL(clki->clk)) { if (scale_up && clki->max_freq) { @@ -5463,8 +5453,9 @@ static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up) dev_dbg(hba->dev, "%s: clk: %s, rate: %lu\n", __func__, clki->name, clk_get_rate(clki->clk)); } - if (hba->vops->clk_scale_notify) - hba->vops->clk_scale_notify(hba); + + ret = ufshcd_vops_clk_scale_notify(hba, scale_up, POST_CHANGE); + out: return ret; } @@ -5619,13 +5610,6 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) hba->is_irq_enabled = true; } - /* Enable SCSI tag mapping */ - err = scsi_init_shared_tag_map(host, host->can_queue); - if (err) { - dev_err(hba->dev, "init shared queue failed\n"); - goto exit_gating; - } - err = scsi_add_host(host, hba->dev); if (err) { dev_err(hba->dev, "scsi_add_host failed\n"); diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index c40a0e78a6c4..2570d9477b37 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -223,8 +223,10 @@ struct ufs_clk_info { bool enabled; }; -#define PRE_CHANGE 0 -#define POST_CHANGE 1 +enum ufs_notify_change_status { + PRE_CHANGE, + POST_CHANGE, +}; struct ufs_pa_layer_attr { u32 gear_rx; @@ -259,22 +261,28 @@ struct ufs_pwr_mode_info { * to be set. * @suspend: called during host controller PM callback * @resume: called during host controller PM callback + * @dbg_register_dump: used to dump controller debug information */ struct ufs_hba_variant_ops { const char *name; int (*init)(struct ufs_hba *); void (*exit)(struct ufs_hba *); u32 (*get_ufs_hci_version)(struct ufs_hba *); - void (*clk_scale_notify)(struct ufs_hba *); - int (*setup_clocks)(struct ufs_hba *, bool); + int (*clk_scale_notify)(struct ufs_hba *, bool, + enum ufs_notify_change_status); + int (*setup_clocks)(struct ufs_hba *, bool); int (*setup_regulators)(struct ufs_hba *, bool); - int (*hce_enable_notify)(struct ufs_hba *, bool); - int (*link_startup_notify)(struct ufs_hba *, bool); + int (*hce_enable_notify)(struct ufs_hba *, + enum ufs_notify_change_status); + int (*link_startup_notify)(struct ufs_hba *, + enum ufs_notify_change_status); int (*pwr_change_notify)(struct ufs_hba *, - bool, struct ufs_pa_layer_attr *, + enum ufs_notify_change_status status, + struct ufs_pa_layer_attr *, struct ufs_pa_layer_attr *); int (*suspend)(struct ufs_hba *, enum ufs_pm_op); int (*resume)(struct ufs_hba *, enum ufs_pm_op); + void (*dbg_register_dump)(struct ufs_hba *hba); }; /* clock gating state */ @@ -576,6 +584,7 @@ static inline void ufshcd_rmwl(struct ufs_hba *hba, u32 mask, u32 val, u32 reg) } int ufshcd_alloc_host(struct device *, struct ufs_hba **); +void ufshcd_dealloc_host(struct ufs_hba *); int ufshcd_init(struct ufs_hba * , void __iomem * , unsigned int); void ufshcd_remove(struct ufs_hba *); @@ -594,6 +603,27 @@ static inline void check_upiu_size(void) GENERAL_UPIU_REQUEST_SIZE + QUERY_DESC_MAX_SIZE); } +/** + * ufshcd_set_variant - set variant specific data to the hba + * @hba - per adapter instance + * @variant - pointer to variant specific data + */ +static inline void ufshcd_set_variant(struct ufs_hba *hba, void *variant) +{ + BUG_ON(!hba); + hba->priv = variant; +} + +/** + * ufshcd_get_variant - get variant specific data from the hba + * @hba - per adapter instance + */ +static inline void *ufshcd_get_variant(struct ufs_hba *hba) +{ + BUG_ON(!hba); + return hba->priv; +} + extern int ufshcd_runtime_suspend(struct ufs_hba *hba); extern int ufshcd_runtime_resume(struct ufs_hba *hba); extern int ufshcd_runtime_idle(struct ufs_hba *hba); @@ -653,4 +683,109 @@ static inline int ufshcd_dme_peer_get(struct ufs_hba *hba, int ufshcd_hold(struct ufs_hba *hba, bool async); void ufshcd_release(struct ufs_hba *hba); + +/* Wrapper functions for safely calling variant operations */ +static inline const char *ufshcd_get_var_name(struct ufs_hba *hba) +{ + if (hba->vops) + return hba->vops->name; + return ""; +} + +static inline int ufshcd_vops_init(struct ufs_hba *hba) +{ + if (hba->vops && hba->vops->init) + return hba->vops->init(hba); + + return 0; +} + +static inline void ufshcd_vops_exit(struct ufs_hba *hba) +{ + if (hba->vops && hba->vops->exit) + return hba->vops->exit(hba); +} + +static inline u32 ufshcd_vops_get_ufs_hci_version(struct ufs_hba *hba) +{ + if (hba->vops && hba->vops->get_ufs_hci_version) + return hba->vops->get_ufs_hci_version(hba); + + return ufshcd_readl(hba, REG_UFS_VERSION); +} + +static inline int ufshcd_vops_clk_scale_notify(struct ufs_hba *hba, + bool up, enum ufs_notify_change_status status) +{ + if (hba->vops && hba->vops->clk_scale_notify) + return hba->vops->clk_scale_notify(hba, up, status); + return 0; +} + +static inline int ufshcd_vops_setup_clocks(struct ufs_hba *hba, bool on) +{ + if (hba->vops && hba->vops->setup_clocks) + return hba->vops->setup_clocks(hba, on); + return 0; +} + +static inline int ufshcd_vops_setup_regulators(struct ufs_hba *hba, bool status) +{ + if (hba->vops && hba->vops->setup_regulators) + return hba->vops->setup_regulators(hba, status); + + return 0; +} + +static inline int ufshcd_vops_hce_enable_notify(struct ufs_hba *hba, + bool status) +{ + if (hba->vops && hba->vops->hce_enable_notify) + return hba->vops->hce_enable_notify(hba, status); + + return 0; +} +static inline int ufshcd_vops_link_startup_notify(struct ufs_hba *hba, + bool status) +{ + if (hba->vops && hba->vops->link_startup_notify) + return hba->vops->link_startup_notify(hba, status); + + return 0; +} + +static inline int ufshcd_vops_pwr_change_notify(struct ufs_hba *hba, + bool status, + struct ufs_pa_layer_attr *dev_max_params, + struct ufs_pa_layer_attr *dev_req_params) +{ + if (hba->vops && hba->vops->pwr_change_notify) + return hba->vops->pwr_change_notify(hba, status, + dev_max_params, dev_req_params); + + return -ENOTSUPP; +} + +static inline int ufshcd_vops_suspend(struct ufs_hba *hba, enum ufs_pm_op op) +{ + if (hba->vops && hba->vops->suspend) + return hba->vops->suspend(hba, op); + + return 0; +} + +static inline int ufshcd_vops_resume(struct ufs_hba *hba, enum ufs_pm_op op) +{ + if (hba->vops && hba->vops->resume) + return hba->vops->resume(hba, op); + + return 0; +} + +static inline void ufshcd_vops_dbg_register_dump(struct ufs_hba *hba) +{ + if (hba->vops && hba->vops->dbg_register_dump) + hba->vops->dbg_register_dump(hba); +} + #endif /* End of Header */ diff --git a/drivers/sh/pm_runtime.c b/drivers/sh/pm_runtime.c index 25abd4eb7d10..91a003011acf 100644 --- a/drivers/sh/pm_runtime.c +++ b/drivers/sh/pm_runtime.c @@ -34,7 +34,7 @@ static struct pm_clk_notifier_block platform_bus_notifier = { static int __init sh_pm_runtime_init(void) { - if (IS_ENABLED(CONFIG_ARCH_SHMOBILE_MULTI)) { + if (IS_ENABLED(CONFIG_ARCH_SHMOBILE)) { if (!of_find_compatible_node(NULL, NULL, "renesas,cpg-mstp-clocks")) return 0; diff --git a/drivers/staging/iio/Kconfig b/drivers/staging/iio/Kconfig index 6d5b38d69578..9d7f0004d2d7 100644 --- a/drivers/staging/iio/Kconfig +++ b/drivers/staging/iio/Kconfig @@ -18,7 +18,8 @@ source "drivers/staging/iio/resolver/Kconfig" source "drivers/staging/iio/trigger/Kconfig" config IIO_DUMMY_EVGEN - tristate + tristate + select IRQ_WORK config IIO_SIMPLE_DUMMY tristate "An example driver with no hardware requirements" diff --git a/drivers/staging/iio/adc/lpc32xx_adc.c b/drivers/staging/iio/adc/lpc32xx_adc.c index d11c54b72186..b51f237cd817 100644 --- a/drivers/staging/iio/adc/lpc32xx_adc.c +++ b/drivers/staging/iio/adc/lpc32xx_adc.c @@ -76,7 +76,7 @@ static int lpc32xx_read_raw(struct iio_dev *indio_dev, if (mask == IIO_CHAN_INFO_RAW) { mutex_lock(&indio_dev->mlock); - clk_enable(info->clk); + clk_prepare_enable(info->clk); /* Measurement setup */ __raw_writel(AD_INTERNAL | (chan->address) | AD_REFp | AD_REFm, LPC32XX_ADC_SELECT(info->adc_base)); @@ -84,7 +84,7 @@ static int lpc32xx_read_raw(struct iio_dev *indio_dev, __raw_writel(AD_PDN_CTRL | AD_STROBE, LPC32XX_ADC_CTRL(info->adc_base)); wait_for_completion(&info->completion); /* set by ISR */ - clk_disable(info->clk); + clk_disable_unprepare(info->clk); *val = info->value; mutex_unlock(&indio_dev->mlock); diff --git a/drivers/staging/lustre/lustre/llite/lloop.c b/drivers/staging/lustre/lustre/llite/lloop.c index e6974c36276d..fed50d538a41 100644 --- a/drivers/staging/lustre/lustre/llite/lloop.c +++ b/drivers/staging/lustre/lustre/llite/lloop.c @@ -333,7 +333,7 @@ static unsigned int loop_get_bio(struct lloop_device *lo, struct bio **req) return count; } -static void loop_make_request(struct request_queue *q, struct bio *old_bio) +static blk_qc_t loop_make_request(struct request_queue *q, struct bio *old_bio) { struct lloop_device *lo = q->queuedata; int rw = bio_rw(old_bio); @@ -364,9 +364,10 @@ static void loop_make_request(struct request_queue *q, struct bio *old_bio) goto err; } loop_add_bio(lo, old_bio); - return; + return BLK_QC_T_NONE; err: bio_io_error(old_bio); + return BLK_QC_T_NONE; } static inline void loop_handle_bio(struct lloop_device *lo, struct bio *bio) diff --git a/drivers/staging/wilc1000/coreconfigurator.c b/drivers/staging/wilc1000/coreconfigurator.c index e10c6ffa698a..9568bdb6319b 100644 --- a/drivers/staging/wilc1000/coreconfigurator.c +++ b/drivers/staging/wilc1000/coreconfigurator.c @@ -13,12 +13,8 @@ #include "wilc_wlan.h" #include <linux/errno.h> #include <linux/slab.h> -#include <linux/etherdevice.h> #define TAG_PARAM_OFFSET (MAC_HDR_LEN + TIME_STAMP_LEN + \ BEACON_INTERVAL_LEN + CAP_INFO_LEN) -#define ADDR1 4 -#define ADDR2 10 -#define ADDR3 16 /* Basic Frame Type Codes (2-bit) */ enum basic_frame_type { @@ -175,32 +171,38 @@ static inline u8 get_from_ds(u8 *header) return ((header[1] & 0x02) >> 1); } +/* This function extracts the MAC Address in 'address1' field of the MAC */ +/* header and updates the MAC Address in the allocated 'addr' variable. */ +static inline void get_address1(u8 *pu8msa, u8 *addr) +{ + memcpy(addr, pu8msa + 4, 6); +} + +/* This function extracts the MAC Address in 'address2' field of the MAC */ +/* header and updates the MAC Address in the allocated 'addr' variable. */ +static inline void get_address2(u8 *pu8msa, u8 *addr) +{ + memcpy(addr, pu8msa + 10, 6); +} + +/* This function extracts the MAC Address in 'address3' field of the MAC */ +/* header and updates the MAC Address in the allocated 'addr' variable. */ +static inline void get_address3(u8 *pu8msa, u8 *addr) +{ + memcpy(addr, pu8msa + 16, 6); +} + /* This function extracts the BSSID from the incoming WLAN packet based on */ -/* the 'from ds' bit, and updates the MAC Address in the allocated 'data' */ +/* the 'from ds' bit, and updates the MAC Address in the allocated 'addr' */ /* variable. */ static inline void get_BSSID(u8 *data, u8 *bssid) { if (get_from_ds(data) == 1) - /* - * Extract the MAC Address in 'address2' field of the MAC - * header and update the MAC Address in the allocated 'data' - * variable. - */ - ether_addr_copy(data, bssid + ADDR2); + get_address2(data, bssid); else if (get_to_ds(data) == 1) - /* - * Extract the MAC Address in 'address1' field of the MAC - * header and update the MAC Address in the allocated 'data' - * variable. - */ - ether_addr_copy(data, bssid + ADDR1); + get_address1(data, bssid); else - /* - * Extract the MAC Address in 'address3' field of the MAC - * header and update the MAC Address in the allocated 'data' - * variable. - */ - ether_addr_copy(data, bssid + ADDR3); + get_address3(data, bssid); } /* This function extracts the SSID from a beacon/probe response frame */ diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index c7461d770d3a..255204cc43e6 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -23,8 +23,6 @@ #include <linux/inet.h> #include <target/target_core_base.h> #include <target/target_core_fabric.h> -#include <target/target_core_fabric_configfs.h> -#include <target/configfs_macros.h> #include <target/iscsi/iscsi_transport.h> #include <target/iscsi/iscsi_target_core.h> @@ -37,20 +35,17 @@ #include "iscsi_target.h" #include <target/iscsi/iscsi_target_stat.h> -struct lio_target_configfs_attribute { - struct configfs_attribute attr; - ssize_t (*show)(void *, char *); - ssize_t (*store)(void *, const char *, size_t); -}; /* Start items for lio_target_portal_cit */ -static ssize_t lio_target_np_show_sctp( - struct se_tpg_np *se_tpg_np, - char *page) +static inline struct iscsi_tpg_np *to_iscsi_tpg_np(struct config_item *item) +{ + return container_of(to_tpg_np(item), struct iscsi_tpg_np, se_tpg_np); +} + +static ssize_t lio_target_np_sctp_show(struct config_item *item, char *page) { - struct iscsi_tpg_np *tpg_np = container_of(se_tpg_np, - struct iscsi_tpg_np, se_tpg_np); + struct iscsi_tpg_np *tpg_np = to_iscsi_tpg_np(item); struct iscsi_tpg_np *tpg_np_sctp; ssize_t rb; @@ -63,15 +58,12 @@ static ssize_t lio_target_np_show_sctp( return rb; } -static ssize_t lio_target_np_store_sctp( - struct se_tpg_np *se_tpg_np, - const char *page, - size_t count) +static ssize_t lio_target_np_sctp_store(struct config_item *item, + const char *page, size_t count) { + struct iscsi_tpg_np *tpg_np = to_iscsi_tpg_np(item); struct iscsi_np *np; struct iscsi_portal_group *tpg; - struct iscsi_tpg_np *tpg_np = container_of(se_tpg_np, - struct iscsi_tpg_np, se_tpg_np); struct iscsi_tpg_np *tpg_np_sctp = NULL; u32 op; int ret; @@ -119,14 +111,9 @@ out: return -EINVAL; } -TF_NP_BASE_ATTR(lio_target, sctp, S_IRUGO | S_IWUSR); - -static ssize_t lio_target_np_show_iser( - struct se_tpg_np *se_tpg_np, - char *page) +static ssize_t lio_target_np_iser_show(struct config_item *item, char *page) { - struct iscsi_tpg_np *tpg_np = container_of(se_tpg_np, - struct iscsi_tpg_np, se_tpg_np); + struct iscsi_tpg_np *tpg_np = to_iscsi_tpg_np(item); struct iscsi_tpg_np *tpg_np_iser; ssize_t rb; @@ -139,15 +126,12 @@ static ssize_t lio_target_np_show_iser( return rb; } -static ssize_t lio_target_np_store_iser( - struct se_tpg_np *se_tpg_np, - const char *page, - size_t count) +static ssize_t lio_target_np_iser_store(struct config_item *item, + const char *page, size_t count) { + struct iscsi_tpg_np *tpg_np = to_iscsi_tpg_np(item); struct iscsi_np *np; struct iscsi_portal_group *tpg; - struct iscsi_tpg_np *tpg_np = container_of(se_tpg_np, - struct iscsi_tpg_np, se_tpg_np); struct iscsi_tpg_np *tpg_np_iser = NULL; char *endptr; u32 op; @@ -198,11 +182,12 @@ out: return rc; } -TF_NP_BASE_ATTR(lio_target, iser, S_IRUGO | S_IWUSR); +CONFIGFS_ATTR(lio_target_np_, sctp); +CONFIGFS_ATTR(lio_target_np_, iser); static struct configfs_attribute *lio_target_portal_attrs[] = { - &lio_target_np_sctp.attr, - &lio_target_np_iser.attr, + &lio_target_np_attr_sctp, + &lio_target_np_attr_iser, NULL, }; @@ -360,22 +345,21 @@ out: /* Start items for lio_target_nacl_attrib_cit */ -#define DEF_NACL_ATTRIB(name) \ -static ssize_t iscsi_nacl_attrib_show_##name( \ - struct se_node_acl *se_nacl, \ - char *page) \ +#define ISCSI_NACL_ATTR(name) \ +static ssize_t iscsi_nacl_attrib_##name##_show(struct config_item *item,\ + char *page) \ { \ + struct se_node_acl *se_nacl = attrib_to_nacl(item); \ struct iscsi_node_acl *nacl = container_of(se_nacl, struct iscsi_node_acl, \ se_node_acl); \ \ return sprintf(page, "%u\n", nacl->node_attrib.name); \ } \ \ -static ssize_t iscsi_nacl_attrib_store_##name( \ - struct se_node_acl *se_nacl, \ - const char *page, \ - size_t count) \ +static ssize_t iscsi_nacl_attrib_##name##_store(struct config_item *item,\ + const char *page, size_t count) \ { \ + struct se_node_acl *se_nacl = attrib_to_nacl(item); \ struct iscsi_node_acl *nacl = container_of(se_nacl, struct iscsi_node_acl, \ se_node_acl); \ u32 val; \ @@ -389,59 +373,28 @@ static ssize_t iscsi_nacl_attrib_store_##name( \ return ret; \ \ return count; \ -} +} \ + \ +CONFIGFS_ATTR(iscsi_nacl_attrib_, name) -#define NACL_ATTR(_name, _mode) TF_NACL_ATTRIB_ATTR(iscsi, _name, _mode); -/* - * Define iscsi_node_attrib_s_dataout_timeout - */ -DEF_NACL_ATTRIB(dataout_timeout); -NACL_ATTR(dataout_timeout, S_IRUGO | S_IWUSR); -/* - * Define iscsi_node_attrib_s_dataout_timeout_retries - */ -DEF_NACL_ATTRIB(dataout_timeout_retries); -NACL_ATTR(dataout_timeout_retries, S_IRUGO | S_IWUSR); -/* - * Define iscsi_node_attrib_s_default_erl - */ -DEF_NACL_ATTRIB(default_erl); -NACL_ATTR(default_erl, S_IRUGO | S_IWUSR); -/* - * Define iscsi_node_attrib_s_nopin_timeout - */ -DEF_NACL_ATTRIB(nopin_timeout); -NACL_ATTR(nopin_timeout, S_IRUGO | S_IWUSR); -/* - * Define iscsi_node_attrib_s_nopin_response_timeout - */ -DEF_NACL_ATTRIB(nopin_response_timeout); -NACL_ATTR(nopin_response_timeout, S_IRUGO | S_IWUSR); -/* - * Define iscsi_node_attrib_s_random_datain_pdu_offsets - */ -DEF_NACL_ATTRIB(random_datain_pdu_offsets); -NACL_ATTR(random_datain_pdu_offsets, S_IRUGO | S_IWUSR); -/* - * Define iscsi_node_attrib_s_random_datain_seq_offsets - */ -DEF_NACL_ATTRIB(random_datain_seq_offsets); -NACL_ATTR(random_datain_seq_offsets, S_IRUGO | S_IWUSR); -/* - * Define iscsi_node_attrib_s_random_r2t_offsets - */ -DEF_NACL_ATTRIB(random_r2t_offsets); -NACL_ATTR(random_r2t_offsets, S_IRUGO | S_IWUSR); +ISCSI_NACL_ATTR(dataout_timeout); +ISCSI_NACL_ATTR(dataout_timeout_retries); +ISCSI_NACL_ATTR(default_erl); +ISCSI_NACL_ATTR(nopin_timeout); +ISCSI_NACL_ATTR(nopin_response_timeout); +ISCSI_NACL_ATTR(random_datain_pdu_offsets); +ISCSI_NACL_ATTR(random_datain_seq_offsets); +ISCSI_NACL_ATTR(random_r2t_offsets); static struct configfs_attribute *lio_target_nacl_attrib_attrs[] = { - &iscsi_nacl_attrib_dataout_timeout.attr, - &iscsi_nacl_attrib_dataout_timeout_retries.attr, - &iscsi_nacl_attrib_default_erl.attr, - &iscsi_nacl_attrib_nopin_timeout.attr, - &iscsi_nacl_attrib_nopin_response_timeout.attr, - &iscsi_nacl_attrib_random_datain_pdu_offsets.attr, - &iscsi_nacl_attrib_random_datain_seq_offsets.attr, - &iscsi_nacl_attrib_random_r2t_offsets.attr, + &iscsi_nacl_attrib_attr_dataout_timeout, + &iscsi_nacl_attrib_attr_dataout_timeout_retries, + &iscsi_nacl_attrib_attr_default_erl, + &iscsi_nacl_attrib_attr_nopin_timeout, + &iscsi_nacl_attrib_attr_nopin_response_timeout, + &iscsi_nacl_attrib_attr_random_datain_pdu_offsets, + &iscsi_nacl_attrib_attr_random_datain_seq_offsets, + &iscsi_nacl_attrib_attr_random_r2t_offsets, NULL, }; @@ -450,7 +403,7 @@ static struct configfs_attribute *lio_target_nacl_attrib_attrs[] = { /* Start items for lio_target_nacl_auth_cit */ #define __DEF_NACL_AUTH_STR(prefix, name, flags) \ -static ssize_t __iscsi_##prefix##_show_##name( \ +static ssize_t __iscsi_##prefix##_##name##_show( \ struct iscsi_node_acl *nacl, \ char *page) \ { \ @@ -461,7 +414,7 @@ static ssize_t __iscsi_##prefix##_show_##name( \ return snprintf(page, PAGE_SIZE, "%s\n", auth->name); \ } \ \ -static ssize_t __iscsi_##prefix##_store_##name( \ +static ssize_t __iscsi_##prefix##_##name##_store( \ struct iscsi_node_acl *nacl, \ const char *page, \ size_t count) \ @@ -487,8 +440,35 @@ static ssize_t __iscsi_##prefix##_store_##name( \ return count; \ } +#define DEF_NACL_AUTH_STR(name, flags) \ + __DEF_NACL_AUTH_STR(nacl_auth, name, flags) \ +static ssize_t iscsi_nacl_auth_##name##_show(struct config_item *item, \ + char *page) \ +{ \ + struct se_node_acl *nacl = auth_to_nacl(item); \ + return __iscsi_nacl_auth_##name##_show(container_of(nacl, \ + struct iscsi_node_acl, se_node_acl), page); \ +} \ +static ssize_t iscsi_nacl_auth_##name##_store(struct config_item *item, \ + const char *page, size_t count) \ +{ \ + struct se_node_acl *nacl = auth_to_nacl(item); \ + return __iscsi_nacl_auth_##name##_store(container_of(nacl, \ + struct iscsi_node_acl, se_node_acl), page, count); \ +} \ + \ +CONFIGFS_ATTR(iscsi_nacl_auth_, name) + +/* + * One-way authentication userid + */ +DEF_NACL_AUTH_STR(userid, NAF_USERID_SET); +DEF_NACL_AUTH_STR(password, NAF_PASSWORD_SET); +DEF_NACL_AUTH_STR(userid_mutual, NAF_USERID_IN_SET); +DEF_NACL_AUTH_STR(password_mutual, NAF_PASSWORD_IN_SET); + #define __DEF_NACL_AUTH_INT(prefix, name) \ -static ssize_t __iscsi_##prefix##_show_##name( \ +static ssize_t __iscsi_##prefix##_##name##_show( \ struct iscsi_node_acl *nacl, \ char *page) \ { \ @@ -500,69 +480,26 @@ static ssize_t __iscsi_##prefix##_show_##name( \ return snprintf(page, PAGE_SIZE, "%d\n", auth->name); \ } -#define DEF_NACL_AUTH_STR(name, flags) \ - __DEF_NACL_AUTH_STR(nacl_auth, name, flags) \ -static ssize_t iscsi_nacl_auth_show_##name( \ - struct se_node_acl *nacl, \ - char *page) \ -{ \ - return __iscsi_nacl_auth_show_##name(container_of(nacl, \ - struct iscsi_node_acl, se_node_acl), page); \ -} \ -static ssize_t iscsi_nacl_auth_store_##name( \ - struct se_node_acl *nacl, \ - const char *page, \ - size_t count) \ -{ \ - return __iscsi_nacl_auth_store_##name(container_of(nacl, \ - struct iscsi_node_acl, se_node_acl), page, count); \ -} - #define DEF_NACL_AUTH_INT(name) \ __DEF_NACL_AUTH_INT(nacl_auth, name) \ -static ssize_t iscsi_nacl_auth_show_##name( \ - struct se_node_acl *nacl, \ - char *page) \ +static ssize_t iscsi_nacl_auth_##name##_show(struct config_item *item, \ + char *page) \ { \ - return __iscsi_nacl_auth_show_##name(container_of(nacl, \ - struct iscsi_node_acl, se_node_acl), page); \ -} - -#define AUTH_ATTR(_name, _mode) TF_NACL_AUTH_ATTR(iscsi, _name, _mode); -#define AUTH_ATTR_RO(_name) TF_NACL_AUTH_ATTR_RO(iscsi, _name); + struct se_node_acl *nacl = auth_to_nacl(item); \ + return __iscsi_nacl_auth_##name##_show(container_of(nacl, \ + struct iscsi_node_acl, se_node_acl), page); \ +} \ + \ +CONFIGFS_ATTR_RO(iscsi_nacl_auth_, name) -/* - * One-way authentication userid - */ -DEF_NACL_AUTH_STR(userid, NAF_USERID_SET); -AUTH_ATTR(userid, S_IRUGO | S_IWUSR); -/* - * One-way authentication password - */ -DEF_NACL_AUTH_STR(password, NAF_PASSWORD_SET); -AUTH_ATTR(password, S_IRUGO | S_IWUSR); -/* - * Enforce mutual authentication - */ DEF_NACL_AUTH_INT(authenticate_target); -AUTH_ATTR_RO(authenticate_target); -/* - * Mutual authentication userid - */ -DEF_NACL_AUTH_STR(userid_mutual, NAF_USERID_IN_SET); -AUTH_ATTR(userid_mutual, S_IRUGO | S_IWUSR); -/* - * Mutual authentication password - */ -DEF_NACL_AUTH_STR(password_mutual, NAF_PASSWORD_IN_SET); -AUTH_ATTR(password_mutual, S_IRUGO | S_IWUSR); static struct configfs_attribute *lio_target_nacl_auth_attrs[] = { - &iscsi_nacl_auth_userid.attr, - &iscsi_nacl_auth_password.attr, - &iscsi_nacl_auth_authenticate_target.attr, - &iscsi_nacl_auth_userid_mutual.attr, - &iscsi_nacl_auth_password_mutual.attr, + &iscsi_nacl_auth_attr_userid, + &iscsi_nacl_auth_attr_password, + &iscsi_nacl_auth_attr_authenticate_target, + &iscsi_nacl_auth_attr_userid_mutual, + &iscsi_nacl_auth_attr_password_mutual, NULL, }; @@ -570,11 +507,11 @@ static struct configfs_attribute *lio_target_nacl_auth_attrs[] = { /* Start items for lio_target_nacl_param_cit */ -#define DEF_NACL_PARAM(name) \ -static ssize_t iscsi_nacl_param_show_##name( \ - struct se_node_acl *se_nacl, \ - char *page) \ +#define ISCSI_NACL_PARAM(name) \ +static ssize_t iscsi_nacl_param_##name##_show(struct config_item *item, \ + char *page) \ { \ + struct se_node_acl *se_nacl = param_to_nacl(item); \ struct iscsi_session *sess; \ struct se_session *se_sess; \ ssize_t rb; \ @@ -592,55 +529,34 @@ static ssize_t iscsi_nacl_param_show_##name( \ spin_unlock_bh(&se_nacl->nacl_sess_lock); \ \ return rb; \ -} - -#define NACL_PARAM_ATTR(_name) TF_NACL_PARAM_ATTR_RO(iscsi, _name); - -DEF_NACL_PARAM(MaxConnections); -NACL_PARAM_ATTR(MaxConnections); - -DEF_NACL_PARAM(InitialR2T); -NACL_PARAM_ATTR(InitialR2T); - -DEF_NACL_PARAM(ImmediateData); -NACL_PARAM_ATTR(ImmediateData); - -DEF_NACL_PARAM(MaxBurstLength); -NACL_PARAM_ATTR(MaxBurstLength); - -DEF_NACL_PARAM(FirstBurstLength); -NACL_PARAM_ATTR(FirstBurstLength); - -DEF_NACL_PARAM(DefaultTime2Wait); -NACL_PARAM_ATTR(DefaultTime2Wait); - -DEF_NACL_PARAM(DefaultTime2Retain); -NACL_PARAM_ATTR(DefaultTime2Retain); - -DEF_NACL_PARAM(MaxOutstandingR2T); -NACL_PARAM_ATTR(MaxOutstandingR2T); - -DEF_NACL_PARAM(DataPDUInOrder); -NACL_PARAM_ATTR(DataPDUInOrder); - -DEF_NACL_PARAM(DataSequenceInOrder); -NACL_PARAM_ATTR(DataSequenceInOrder); - -DEF_NACL_PARAM(ErrorRecoveryLevel); -NACL_PARAM_ATTR(ErrorRecoveryLevel); +} \ + \ +CONFIGFS_ATTR_RO(iscsi_nacl_param_, name) + +ISCSI_NACL_PARAM(MaxConnections); +ISCSI_NACL_PARAM(InitialR2T); +ISCSI_NACL_PARAM(ImmediateData); +ISCSI_NACL_PARAM(MaxBurstLength); +ISCSI_NACL_PARAM(FirstBurstLength); +ISCSI_NACL_PARAM(DefaultTime2Wait); +ISCSI_NACL_PARAM(DefaultTime2Retain); +ISCSI_NACL_PARAM(MaxOutstandingR2T); +ISCSI_NACL_PARAM(DataPDUInOrder); +ISCSI_NACL_PARAM(DataSequenceInOrder); +ISCSI_NACL_PARAM(ErrorRecoveryLevel); static struct configfs_attribute *lio_target_nacl_param_attrs[] = { - &iscsi_nacl_param_MaxConnections.attr, - &iscsi_nacl_param_InitialR2T.attr, - &iscsi_nacl_param_ImmediateData.attr, - &iscsi_nacl_param_MaxBurstLength.attr, - &iscsi_nacl_param_FirstBurstLength.attr, - &iscsi_nacl_param_DefaultTime2Wait.attr, - &iscsi_nacl_param_DefaultTime2Retain.attr, - &iscsi_nacl_param_MaxOutstandingR2T.attr, - &iscsi_nacl_param_DataPDUInOrder.attr, - &iscsi_nacl_param_DataSequenceInOrder.attr, - &iscsi_nacl_param_ErrorRecoveryLevel.attr, + &iscsi_nacl_param_attr_MaxConnections, + &iscsi_nacl_param_attr_InitialR2T, + &iscsi_nacl_param_attr_ImmediateData, + &iscsi_nacl_param_attr_MaxBurstLength, + &iscsi_nacl_param_attr_FirstBurstLength, + &iscsi_nacl_param_attr_DefaultTime2Wait, + &iscsi_nacl_param_attr_DefaultTime2Retain, + &iscsi_nacl_param_attr_MaxOutstandingR2T, + &iscsi_nacl_param_attr_DataPDUInOrder, + &iscsi_nacl_param_attr_DataSequenceInOrder, + &iscsi_nacl_param_attr_ErrorRecoveryLevel, NULL, }; @@ -648,10 +564,9 @@ static struct configfs_attribute *lio_target_nacl_param_attrs[] = { /* Start items for lio_target_acl_cit */ -static ssize_t lio_target_nacl_show_info( - struct se_node_acl *se_nacl, - char *page) +static ssize_t lio_target_nacl_info_show(struct config_item *item, char *page) { + struct se_node_acl *se_nacl = acl_to_nacl(item); struct iscsi_session *sess; struct iscsi_conn *conn; struct se_session *se_sess; @@ -766,20 +681,16 @@ static ssize_t lio_target_nacl_show_info( return rb; } -TF_NACL_BASE_ATTR_RO(lio_target, info); - -static ssize_t lio_target_nacl_show_cmdsn_depth( - struct se_node_acl *se_nacl, - char *page) +static ssize_t lio_target_nacl_cmdsn_depth_show(struct config_item *item, + char *page) { - return sprintf(page, "%u\n", se_nacl->queue_depth); + return sprintf(page, "%u\n", acl_to_nacl(item)->queue_depth); } -static ssize_t lio_target_nacl_store_cmdsn_depth( - struct se_node_acl *se_nacl, - const char *page, - size_t count) +static ssize_t lio_target_nacl_cmdsn_depth_store(struct config_item *item, + const char *page, size_t count) { + struct se_node_acl *se_nacl = acl_to_nacl(item); struct se_portal_group *se_tpg = se_nacl->se_tpg; struct iscsi_portal_group *tpg = container_of(se_tpg, struct iscsi_portal_group, tpg_se_tpg); @@ -829,20 +740,15 @@ static ssize_t lio_target_nacl_store_cmdsn_depth( return (!ret) ? count : (ssize_t)ret; } -TF_NACL_BASE_ATTR(lio_target, cmdsn_depth, S_IRUGO | S_IWUSR); - -static ssize_t lio_target_nacl_show_tag( - struct se_node_acl *se_nacl, - char *page) +static ssize_t lio_target_nacl_tag_show(struct config_item *item, char *page) { - return snprintf(page, PAGE_SIZE, "%s", se_nacl->acl_tag); + return snprintf(page, PAGE_SIZE, "%s", acl_to_nacl(item)->acl_tag); } -static ssize_t lio_target_nacl_store_tag( - struct se_node_acl *se_nacl, - const char *page, - size_t count) +static ssize_t lio_target_nacl_tag_store(struct config_item *item, + const char *page, size_t count) { + struct se_node_acl *se_nacl = acl_to_nacl(item); int ret; ret = core_tpg_set_initiator_node_tag(se_nacl->se_tpg, se_nacl, page); @@ -852,12 +758,14 @@ static ssize_t lio_target_nacl_store_tag( return count; } -TF_NACL_BASE_ATTR(lio_target, tag, S_IRUGO | S_IWUSR); +CONFIGFS_ATTR_RO(lio_target_nacl_, info); +CONFIGFS_ATTR(lio_target_nacl_, cmdsn_depth); +CONFIGFS_ATTR(lio_target_nacl_, tag); static struct configfs_attribute *lio_target_initiator_attrs[] = { - &lio_target_nacl_info.attr, - &lio_target_nacl_cmdsn_depth.attr, - &lio_target_nacl_tag.attr, + &lio_target_nacl_attr_info, + &lio_target_nacl_attr_cmdsn_depth, + &lio_target_nacl_attr_tag, NULL, }; @@ -907,10 +815,10 @@ static void lio_target_cleanup_nodeacl( struct se_node_acl *se_nacl) #define DEF_TPG_ATTRIB(name) \ \ -static ssize_t iscsi_tpg_attrib_show_##name( \ - struct se_portal_group *se_tpg, \ - char *page) \ +static ssize_t iscsi_tpg_attrib_##name##_show(struct config_item *item, \ + char *page) \ { \ + struct se_portal_group *se_tpg = attrib_to_tpg(item); \ struct iscsi_portal_group *tpg = container_of(se_tpg, \ struct iscsi_portal_group, tpg_se_tpg); \ ssize_t rb; \ @@ -923,11 +831,10 @@ static ssize_t iscsi_tpg_attrib_show_##name( \ return rb; \ } \ \ -static ssize_t iscsi_tpg_attrib_store_##name( \ - struct se_portal_group *se_tpg, \ - const char *page, \ - size_t count) \ +static ssize_t iscsi_tpg_attrib_##name##_store(struct config_item *item,\ + const char *page, size_t count) \ { \ + struct se_portal_group *se_tpg = attrib_to_tpg(item); \ struct iscsi_portal_group *tpg = container_of(se_tpg, \ struct iscsi_portal_group, tpg_se_tpg); \ u32 val; \ @@ -948,90 +855,37 @@ static ssize_t iscsi_tpg_attrib_store_##name( \ out: \ iscsit_put_tpg(tpg); \ return ret; \ -} - -#define TPG_ATTR(_name, _mode) TF_TPG_ATTRIB_ATTR(iscsi, _name, _mode); +} \ +CONFIGFS_ATTR(iscsi_tpg_attrib_, name) -/* - * Define iscsi_tpg_attrib_s_authentication - */ DEF_TPG_ATTRIB(authentication); -TPG_ATTR(authentication, S_IRUGO | S_IWUSR); -/* - * Define iscsi_tpg_attrib_s_login_timeout - */ DEF_TPG_ATTRIB(login_timeout); -TPG_ATTR(login_timeout, S_IRUGO | S_IWUSR); -/* - * Define iscsi_tpg_attrib_s_netif_timeout - */ DEF_TPG_ATTRIB(netif_timeout); -TPG_ATTR(netif_timeout, S_IRUGO | S_IWUSR); -/* - * Define iscsi_tpg_attrib_s_generate_node_acls - */ DEF_TPG_ATTRIB(generate_node_acls); -TPG_ATTR(generate_node_acls, S_IRUGO | S_IWUSR); -/* - * Define iscsi_tpg_attrib_s_default_cmdsn_depth - */ DEF_TPG_ATTRIB(default_cmdsn_depth); -TPG_ATTR(default_cmdsn_depth, S_IRUGO | S_IWUSR); -/* - Define iscsi_tpg_attrib_s_cache_dynamic_acls - */ DEF_TPG_ATTRIB(cache_dynamic_acls); -TPG_ATTR(cache_dynamic_acls, S_IRUGO | S_IWUSR); -/* - * Define iscsi_tpg_attrib_s_demo_mode_write_protect - */ DEF_TPG_ATTRIB(demo_mode_write_protect); -TPG_ATTR(demo_mode_write_protect, S_IRUGO | S_IWUSR); -/* - * Define iscsi_tpg_attrib_s_prod_mode_write_protect - */ DEF_TPG_ATTRIB(prod_mode_write_protect); -TPG_ATTR(prod_mode_write_protect, S_IRUGO | S_IWUSR); -/* - * Define iscsi_tpg_attrib_s_demo_mode_discovery, - */ DEF_TPG_ATTRIB(demo_mode_discovery); -TPG_ATTR(demo_mode_discovery, S_IRUGO | S_IWUSR); -/* - * Define iscsi_tpg_attrib_s_default_erl - */ DEF_TPG_ATTRIB(default_erl); -TPG_ATTR(default_erl, S_IRUGO | S_IWUSR); -/* - * Define iscsi_tpg_attrib_s_t10_pi - */ DEF_TPG_ATTRIB(t10_pi); -TPG_ATTR(t10_pi, S_IRUGO | S_IWUSR); -/* - * Define iscsi_tpg_attrib_s_fabric_prot_type - */ DEF_TPG_ATTRIB(fabric_prot_type); -TPG_ATTR(fabric_prot_type, S_IRUGO | S_IWUSR); -/* - * Define iscsi_tpg_attrib_s_tpg_enabled_sendtargets - */ DEF_TPG_ATTRIB(tpg_enabled_sendtargets); -TPG_ATTR(tpg_enabled_sendtargets, S_IRUGO | S_IWUSR); static struct configfs_attribute *lio_target_tpg_attrib_attrs[] = { - &iscsi_tpg_attrib_authentication.attr, - &iscsi_tpg_attrib_login_timeout.attr, - &iscsi_tpg_attrib_netif_timeout.attr, - &iscsi_tpg_attrib_generate_node_acls.attr, - &iscsi_tpg_attrib_default_cmdsn_depth.attr, - &iscsi_tpg_attrib_cache_dynamic_acls.attr, - &iscsi_tpg_attrib_demo_mode_write_protect.attr, - &iscsi_tpg_attrib_prod_mode_write_protect.attr, - &iscsi_tpg_attrib_demo_mode_discovery.attr, - &iscsi_tpg_attrib_default_erl.attr, - &iscsi_tpg_attrib_t10_pi.attr, - &iscsi_tpg_attrib_fabric_prot_type.attr, - &iscsi_tpg_attrib_tpg_enabled_sendtargets.attr, + &iscsi_tpg_attrib_attr_authentication, + &iscsi_tpg_attrib_attr_login_timeout, + &iscsi_tpg_attrib_attr_netif_timeout, + &iscsi_tpg_attrib_attr_generate_node_acls, + &iscsi_tpg_attrib_attr_default_cmdsn_depth, + &iscsi_tpg_attrib_attr_cache_dynamic_acls, + &iscsi_tpg_attrib_attr_demo_mode_write_protect, + &iscsi_tpg_attrib_attr_prod_mode_write_protect, + &iscsi_tpg_attrib_attr_demo_mode_discovery, + &iscsi_tpg_attrib_attr_default_erl, + &iscsi_tpg_attrib_attr_t10_pi, + &iscsi_tpg_attrib_attr_fabric_prot_type, + &iscsi_tpg_attrib_attr_tpg_enabled_sendtargets, NULL, }; @@ -1040,9 +894,8 @@ static struct configfs_attribute *lio_target_tpg_attrib_attrs[] = { /* Start items for lio_target_tpg_auth_cit */ #define __DEF_TPG_AUTH_STR(prefix, name, flags) \ -static ssize_t __iscsi_##prefix##_show_##name( \ - struct se_portal_group *se_tpg, \ - char *page) \ +static ssize_t __iscsi_##prefix##_##name##_show(struct se_portal_group *se_tpg, \ + char *page) \ { \ struct iscsi_portal_group *tpg = container_of(se_tpg, \ struct iscsi_portal_group, tpg_se_tpg); \ @@ -1054,10 +907,8 @@ static ssize_t __iscsi_##prefix##_show_##name( \ return snprintf(page, PAGE_SIZE, "%s\n", auth->name); \ } \ \ -static ssize_t __iscsi_##prefix##_store_##name( \ - struct se_portal_group *se_tpg, \ - const char *page, \ - size_t count) \ +static ssize_t __iscsi_##prefix##_##name##_store(struct se_portal_group *se_tpg,\ + const char *page, size_t count) \ { \ struct iscsi_portal_group *tpg = container_of(se_tpg, \ struct iscsi_portal_group, tpg_se_tpg); \ @@ -1081,10 +932,31 @@ static ssize_t __iscsi_##prefix##_store_##name( \ return count; \ } +#define DEF_TPG_AUTH_STR(name, flags) \ + __DEF_TPG_AUTH_STR(tpg_auth, name, flags) \ +static ssize_t iscsi_tpg_auth_##name##_show(struct config_item *item, \ + char *page) \ +{ \ + return __iscsi_tpg_auth_##name##_show(auth_to_tpg(item), page); \ +} \ + \ +static ssize_t iscsi_tpg_auth_##name##_store(struct config_item *item, \ + const char *page, size_t count) \ +{ \ + return __iscsi_tpg_auth_##name##_store(auth_to_tpg(item), page, count); \ +} \ + \ +CONFIGFS_ATTR(iscsi_tpg_auth_, name); + + +DEF_TPG_AUTH_STR(userid, NAF_USERID_SET); +DEF_TPG_AUTH_STR(password, NAF_PASSWORD_SET); +DEF_TPG_AUTH_STR(userid_mutual, NAF_USERID_IN_SET); +DEF_TPG_AUTH_STR(password_mutual, NAF_PASSWORD_IN_SET); + #define __DEF_TPG_AUTH_INT(prefix, name) \ -static ssize_t __iscsi_##prefix##_show_##name( \ - struct se_portal_group *se_tpg, \ - char *page) \ +static ssize_t __iscsi_##prefix##_##name##_show(struct se_portal_group *se_tpg, \ + char *page) \ { \ struct iscsi_portal_group *tpg = container_of(se_tpg, \ struct iscsi_portal_group, tpg_se_tpg); \ @@ -1096,67 +968,23 @@ static ssize_t __iscsi_##prefix##_show_##name( \ return snprintf(page, PAGE_SIZE, "%d\n", auth->name); \ } -#define DEF_TPG_AUTH_STR(name, flags) \ - __DEF_TPG_AUTH_STR(tpg_auth, name, flags) \ -static ssize_t iscsi_tpg_auth_show_##name( \ - struct se_portal_group *se_tpg, \ - char *page) \ -{ \ - return __iscsi_tpg_auth_show_##name(se_tpg, page); \ -} \ - \ -static ssize_t iscsi_tpg_auth_store_##name( \ - struct se_portal_group *se_tpg, \ - const char *page, \ - size_t count) \ -{ \ - return __iscsi_tpg_auth_store_##name(se_tpg, page, count); \ -} - #define DEF_TPG_AUTH_INT(name) \ __DEF_TPG_AUTH_INT(tpg_auth, name) \ -static ssize_t iscsi_tpg_auth_show_##name( \ - struct se_portal_group *se_tpg, \ - char *page) \ +static ssize_t iscsi_tpg_auth_##name##_show(struct config_item *item, \ + char *page) \ { \ - return __iscsi_tpg_auth_show_##name(se_tpg, page); \ -} - -#define TPG_AUTH_ATTR(_name, _mode) TF_TPG_AUTH_ATTR(iscsi, _name, _mode); -#define TPG_AUTH_ATTR_RO(_name) TF_TPG_AUTH_ATTR_RO(iscsi, _name); + return __iscsi_tpg_auth_##name##_show(auth_to_tpg(item), page); \ +} \ +CONFIGFS_ATTR_RO(iscsi_tpg_auth_, name); -/* - * * One-way authentication userid - * */ -DEF_TPG_AUTH_STR(userid, NAF_USERID_SET); -TPG_AUTH_ATTR(userid, S_IRUGO | S_IWUSR); -/* - * * One-way authentication password - * */ -DEF_TPG_AUTH_STR(password, NAF_PASSWORD_SET); -TPG_AUTH_ATTR(password, S_IRUGO | S_IWUSR); -/* - * * Enforce mutual authentication - * */ DEF_TPG_AUTH_INT(authenticate_target); -TPG_AUTH_ATTR_RO(authenticate_target); -/* - * * Mutual authentication userid - * */ -DEF_TPG_AUTH_STR(userid_mutual, NAF_USERID_IN_SET); -TPG_AUTH_ATTR(userid_mutual, S_IRUGO | S_IWUSR); -/* - * * Mutual authentication password - * */ -DEF_TPG_AUTH_STR(password_mutual, NAF_PASSWORD_IN_SET); -TPG_AUTH_ATTR(password_mutual, S_IRUGO | S_IWUSR); static struct configfs_attribute *lio_target_tpg_auth_attrs[] = { - &iscsi_tpg_auth_userid.attr, - &iscsi_tpg_auth_password.attr, - &iscsi_tpg_auth_authenticate_target.attr, - &iscsi_tpg_auth_userid_mutual.attr, - &iscsi_tpg_auth_password_mutual.attr, + &iscsi_tpg_auth_attr_userid, + &iscsi_tpg_auth_attr_password, + &iscsi_tpg_auth_attr_authenticate_target, + &iscsi_tpg_auth_attr_userid_mutual, + &iscsi_tpg_auth_attr_password_mutual, NULL, }; @@ -1165,10 +993,10 @@ static struct configfs_attribute *lio_target_tpg_auth_attrs[] = { /* Start items for lio_target_tpg_param_cit */ #define DEF_TPG_PARAM(name) \ -static ssize_t iscsi_tpg_param_show_##name( \ - struct se_portal_group *se_tpg, \ - char *page) \ +static ssize_t iscsi_tpg_param_##name##_show(struct config_item *item, \ + char *page) \ { \ + struct se_portal_group *se_tpg = param_to_tpg(item); \ struct iscsi_portal_group *tpg = container_of(se_tpg, \ struct iscsi_portal_group, tpg_se_tpg); \ struct iscsi_param *param; \ @@ -1188,11 +1016,10 @@ static ssize_t iscsi_tpg_param_show_##name( \ iscsit_put_tpg(tpg); \ return rb; \ } \ -static ssize_t iscsi_tpg_param_store_##name( \ - struct se_portal_group *se_tpg, \ - const char *page, \ - size_t count) \ +static ssize_t iscsi_tpg_param_##name##_store(struct config_item *item, \ + const char *page, size_t count) \ { \ + struct se_portal_group *se_tpg = param_to_tpg(item); \ struct iscsi_portal_group *tpg = container_of(se_tpg, \ struct iscsi_portal_group, tpg_se_tpg); \ char *buf; \ @@ -1220,96 +1047,54 @@ static ssize_t iscsi_tpg_param_store_##name( \ out: \ kfree(buf); \ iscsit_put_tpg(tpg); \ - return -EINVAL; \ -} - -#define TPG_PARAM_ATTR(_name, _mode) TF_TPG_PARAM_ATTR(iscsi, _name, _mode); + return -EINVAL; \ +} \ +CONFIGFS_ATTR(iscsi_tpg_param_, name) DEF_TPG_PARAM(AuthMethod); -TPG_PARAM_ATTR(AuthMethod, S_IRUGO | S_IWUSR); - DEF_TPG_PARAM(HeaderDigest); -TPG_PARAM_ATTR(HeaderDigest, S_IRUGO | S_IWUSR); - DEF_TPG_PARAM(DataDigest); -TPG_PARAM_ATTR(DataDigest, S_IRUGO | S_IWUSR); - DEF_TPG_PARAM(MaxConnections); -TPG_PARAM_ATTR(MaxConnections, S_IRUGO | S_IWUSR); - DEF_TPG_PARAM(TargetAlias); -TPG_PARAM_ATTR(TargetAlias, S_IRUGO | S_IWUSR); - DEF_TPG_PARAM(InitialR2T); -TPG_PARAM_ATTR(InitialR2T, S_IRUGO | S_IWUSR); - DEF_TPG_PARAM(ImmediateData); -TPG_PARAM_ATTR(ImmediateData, S_IRUGO | S_IWUSR); - DEF_TPG_PARAM(MaxRecvDataSegmentLength); -TPG_PARAM_ATTR(MaxRecvDataSegmentLength, S_IRUGO | S_IWUSR); - DEF_TPG_PARAM(MaxXmitDataSegmentLength); -TPG_PARAM_ATTR(MaxXmitDataSegmentLength, S_IRUGO | S_IWUSR); - DEF_TPG_PARAM(MaxBurstLength); -TPG_PARAM_ATTR(MaxBurstLength, S_IRUGO | S_IWUSR); - DEF_TPG_PARAM(FirstBurstLength); -TPG_PARAM_ATTR(FirstBurstLength, S_IRUGO | S_IWUSR); - DEF_TPG_PARAM(DefaultTime2Wait); -TPG_PARAM_ATTR(DefaultTime2Wait, S_IRUGO | S_IWUSR); - DEF_TPG_PARAM(DefaultTime2Retain); -TPG_PARAM_ATTR(DefaultTime2Retain, S_IRUGO | S_IWUSR); - DEF_TPG_PARAM(MaxOutstandingR2T); -TPG_PARAM_ATTR(MaxOutstandingR2T, S_IRUGO | S_IWUSR); - DEF_TPG_PARAM(DataPDUInOrder); -TPG_PARAM_ATTR(DataPDUInOrder, S_IRUGO | S_IWUSR); - DEF_TPG_PARAM(DataSequenceInOrder); -TPG_PARAM_ATTR(DataSequenceInOrder, S_IRUGO | S_IWUSR); - DEF_TPG_PARAM(ErrorRecoveryLevel); -TPG_PARAM_ATTR(ErrorRecoveryLevel, S_IRUGO | S_IWUSR); - DEF_TPG_PARAM(IFMarker); -TPG_PARAM_ATTR(IFMarker, S_IRUGO | S_IWUSR); - DEF_TPG_PARAM(OFMarker); -TPG_PARAM_ATTR(OFMarker, S_IRUGO | S_IWUSR); - DEF_TPG_PARAM(IFMarkInt); -TPG_PARAM_ATTR(IFMarkInt, S_IRUGO | S_IWUSR); - DEF_TPG_PARAM(OFMarkInt); -TPG_PARAM_ATTR(OFMarkInt, S_IRUGO | S_IWUSR); static struct configfs_attribute *lio_target_tpg_param_attrs[] = { - &iscsi_tpg_param_AuthMethod.attr, - &iscsi_tpg_param_HeaderDigest.attr, - &iscsi_tpg_param_DataDigest.attr, - &iscsi_tpg_param_MaxConnections.attr, - &iscsi_tpg_param_TargetAlias.attr, - &iscsi_tpg_param_InitialR2T.attr, - &iscsi_tpg_param_ImmediateData.attr, - &iscsi_tpg_param_MaxRecvDataSegmentLength.attr, - &iscsi_tpg_param_MaxXmitDataSegmentLength.attr, - &iscsi_tpg_param_MaxBurstLength.attr, - &iscsi_tpg_param_FirstBurstLength.attr, - &iscsi_tpg_param_DefaultTime2Wait.attr, - &iscsi_tpg_param_DefaultTime2Retain.attr, - &iscsi_tpg_param_MaxOutstandingR2T.attr, - &iscsi_tpg_param_DataPDUInOrder.attr, - &iscsi_tpg_param_DataSequenceInOrder.attr, - &iscsi_tpg_param_ErrorRecoveryLevel.attr, - &iscsi_tpg_param_IFMarker.attr, - &iscsi_tpg_param_OFMarker.attr, - &iscsi_tpg_param_IFMarkInt.attr, - &iscsi_tpg_param_OFMarkInt.attr, + &iscsi_tpg_param_attr_AuthMethod, + &iscsi_tpg_param_attr_HeaderDigest, + &iscsi_tpg_param_attr_DataDigest, + &iscsi_tpg_param_attr_MaxConnections, + &iscsi_tpg_param_attr_TargetAlias, + &iscsi_tpg_param_attr_InitialR2T, + &iscsi_tpg_param_attr_ImmediateData, + &iscsi_tpg_param_attr_MaxRecvDataSegmentLength, + &iscsi_tpg_param_attr_MaxXmitDataSegmentLength, + &iscsi_tpg_param_attr_MaxBurstLength, + &iscsi_tpg_param_attr_FirstBurstLength, + &iscsi_tpg_param_attr_DefaultTime2Wait, + &iscsi_tpg_param_attr_DefaultTime2Retain, + &iscsi_tpg_param_attr_MaxOutstandingR2T, + &iscsi_tpg_param_attr_DataPDUInOrder, + &iscsi_tpg_param_attr_DataSequenceInOrder, + &iscsi_tpg_param_attr_ErrorRecoveryLevel, + &iscsi_tpg_param_attr_IFMarker, + &iscsi_tpg_param_attr_OFMarker, + &iscsi_tpg_param_attr_IFMarkInt, + &iscsi_tpg_param_attr_OFMarkInt, NULL, }; @@ -1317,10 +1102,9 @@ static struct configfs_attribute *lio_target_tpg_param_attrs[] = { /* Start items for lio_target_tpg_cit */ -static ssize_t lio_target_tpg_show_enable( - struct se_portal_group *se_tpg, - char *page) +static ssize_t lio_target_tpg_enable_show(struct config_item *item, char *page) { + struct se_portal_group *se_tpg = to_tpg(item); struct iscsi_portal_group *tpg = container_of(se_tpg, struct iscsi_portal_group, tpg_se_tpg); ssize_t len; @@ -1333,11 +1117,10 @@ static ssize_t lio_target_tpg_show_enable( return len; } -static ssize_t lio_target_tpg_store_enable( - struct se_portal_group *se_tpg, - const char *page, - size_t count) +static ssize_t lio_target_tpg_enable_store(struct config_item *item, + const char *page, size_t count) { + struct se_portal_group *se_tpg = to_tpg(item); struct iscsi_portal_group *tpg = container_of(se_tpg, struct iscsi_portal_group, tpg_se_tpg); u32 op; @@ -1375,20 +1158,19 @@ out: return -EINVAL; } -TF_TPG_BASE_ATTR(lio_target, enable, S_IRUGO | S_IWUSR); -static ssize_t lio_target_tpg_show_dynamic_sessions( - struct se_portal_group *se_tpg, - char *page) +static ssize_t lio_target_tpg_dynamic_sessions_show(struct config_item *item, + char *page) { - return target_show_dynamic_sessions(se_tpg, page); + return target_show_dynamic_sessions(to_tpg(item), page); } -TF_TPG_BASE_ATTR_RO(lio_target, dynamic_sessions); +CONFIGFS_ATTR(lio_target_tpg_, enable); +CONFIGFS_ATTR_RO(lio_target_tpg_, dynamic_sessions); static struct configfs_attribute *lio_target_tpg_attrs[] = { - &lio_target_tpg_enable.attr, - &lio_target_tpg_dynamic_sessions.attr, + &lio_target_tpg_attr_enable, + &lio_target_tpg_attr_dynamic_sessions, NULL, }; @@ -1463,17 +1245,16 @@ static void lio_target_tiqn_deltpg(struct se_portal_group *se_tpg) /* Start LIO-Target TIQN struct contig_item lio_target_cit */ -static ssize_t lio_target_wwn_show_attr_lio_version( - struct target_fabric_configfs *tf, - char *page) +static ssize_t lio_target_wwn_lio_version_show(struct config_item *item, + char *page) { return sprintf(page, "Datera Inc. iSCSI Target "ISCSIT_VERSION"\n"); } -TF_WWN_ATTR_RO(lio_target, lio_version); +CONFIGFS_ATTR_RO(lio_target_wwn_, lio_version); static struct configfs_attribute *lio_target_wwn_attrs[] = { - &lio_target_wwn_lio_version.attr, + &lio_target_wwn_attr_lio_version, NULL, }; @@ -1552,77 +1333,47 @@ static void lio_target_call_coredeltiqn( #define DEF_DISC_AUTH_STR(name, flags) \ __DEF_NACL_AUTH_STR(disc, name, flags) \ -static ssize_t iscsi_disc_show_##name( \ - struct target_fabric_configfs *tf, \ - char *page) \ +static ssize_t iscsi_disc_##name##_show(struct config_item *item, char *page) \ { \ - return __iscsi_disc_show_##name(&iscsit_global->discovery_acl, \ + return __iscsi_disc_##name##_show(&iscsit_global->discovery_acl,\ page); \ } \ -static ssize_t iscsi_disc_store_##name( \ - struct target_fabric_configfs *tf, \ - const char *page, \ - size_t count) \ +static ssize_t iscsi_disc_##name##_store(struct config_item *item, \ + const char *page, size_t count) \ { \ - return __iscsi_disc_store_##name(&iscsit_global->discovery_acl, \ + return __iscsi_disc_##name##_store(&iscsit_global->discovery_acl, \ page, count); \ -} + \ +} \ +CONFIGFS_ATTR(iscsi_disc_, name) + +DEF_DISC_AUTH_STR(userid, NAF_USERID_SET); +DEF_DISC_AUTH_STR(password, NAF_PASSWORD_SET); +DEF_DISC_AUTH_STR(userid_mutual, NAF_USERID_IN_SET); +DEF_DISC_AUTH_STR(password_mutual, NAF_PASSWORD_IN_SET); #define DEF_DISC_AUTH_INT(name) \ __DEF_NACL_AUTH_INT(disc, name) \ -static ssize_t iscsi_disc_show_##name( \ - struct target_fabric_configfs *tf, \ - char *page) \ +static ssize_t iscsi_disc_##name##_show(struct config_item *item, char *page) \ { \ - return __iscsi_disc_show_##name(&iscsit_global->discovery_acl, \ + return __iscsi_disc_##name##_show(&iscsit_global->discovery_acl, \ page); \ -} - -#define DISC_AUTH_ATTR(_name, _mode) TF_DISC_ATTR(iscsi, _name, _mode) -#define DISC_AUTH_ATTR_RO(_name) TF_DISC_ATTR_RO(iscsi, _name) +} \ +CONFIGFS_ATTR_RO(iscsi_disc_, name) -/* - * One-way authentication userid - */ -DEF_DISC_AUTH_STR(userid, NAF_USERID_SET); -DISC_AUTH_ATTR(userid, S_IRUGO | S_IWUSR); -/* - * One-way authentication password - */ -DEF_DISC_AUTH_STR(password, NAF_PASSWORD_SET); -DISC_AUTH_ATTR(password, S_IRUGO | S_IWUSR); -/* - * Enforce mutual authentication - */ DEF_DISC_AUTH_INT(authenticate_target); -DISC_AUTH_ATTR_RO(authenticate_target); -/* - * Mutual authentication userid - */ -DEF_DISC_AUTH_STR(userid_mutual, NAF_USERID_IN_SET); -DISC_AUTH_ATTR(userid_mutual, S_IRUGO | S_IWUSR); -/* - * Mutual authentication password - */ -DEF_DISC_AUTH_STR(password_mutual, NAF_PASSWORD_IN_SET); -DISC_AUTH_ATTR(password_mutual, S_IRUGO | S_IWUSR); -/* - * enforce_discovery_auth - */ -static ssize_t iscsi_disc_show_enforce_discovery_auth( - struct target_fabric_configfs *tf, - char *page) + +static ssize_t iscsi_disc_enforce_discovery_auth_show(struct config_item *item, + char *page) { struct iscsi_node_auth *discovery_auth = &iscsit_global->discovery_acl.node_auth; return sprintf(page, "%d\n", discovery_auth->enforce_discovery_auth); } -static ssize_t iscsi_disc_store_enforce_discovery_auth( - struct target_fabric_configfs *tf, - const char *page, - size_t count) +static ssize_t iscsi_disc_enforce_discovery_auth_store(struct config_item *item, + const char *page, size_t count) { struct iscsi_param *param; struct iscsi_portal_group *discovery_tpg = iscsit_global->discovery_tpg; @@ -1677,15 +1428,15 @@ static ssize_t iscsi_disc_store_enforce_discovery_auth( return count; } -DISC_AUTH_ATTR(enforce_discovery_auth, S_IRUGO | S_IWUSR); +CONFIGFS_ATTR(iscsi_disc_, enforce_discovery_auth); static struct configfs_attribute *lio_target_discovery_auth_attrs[] = { - &iscsi_disc_userid.attr, - &iscsi_disc_password.attr, - &iscsi_disc_authenticate_target.attr, - &iscsi_disc_userid_mutual.attr, - &iscsi_disc_password_mutual.attr, - &iscsi_disc_enforce_discovery_auth.attr, + &iscsi_disc_attr_userid, + &iscsi_disc_attr_password, + &iscsi_disc_attr_authenticate_target, + &iscsi_disc_attr_userid_mutual, + &iscsi_disc_attr_password_mutual, + &iscsi_disc_attr_enforce_discovery_auth, NULL, }; diff --git a/drivers/target/iscsi/iscsi_target_stat.c b/drivers/target/iscsi/iscsi_target_stat.c index 9dd94ff0b62c..411cb266a47d 100644 --- a/drivers/target/iscsi/iscsi_target_stat.c +++ b/drivers/target/iscsi/iscsi_target_stat.c @@ -21,7 +21,6 @@ #include <linux/export.h> #include <scsi/iscsi_proto.h> #include <target/target_core_base.h> -#include <target/configfs_macros.h> #include <target/iscsi/iscsi_target_core.h> #include "iscsi_target_parameters.h" @@ -50,76 +49,56 @@ /* * Instance Attributes Table */ -CONFIGFS_EATTR_STRUCT(iscsi_stat_instance, iscsi_wwn_stat_grps); -#define ISCSI_STAT_INSTANCE_ATTR(_name, _mode) \ -static struct iscsi_stat_instance_attribute \ - iscsi_stat_instance_##_name = \ - __CONFIGFS_EATTR(_name, _mode, \ - iscsi_stat_instance_show_attr_##_name, \ - iscsi_stat_instance_store_attr_##_name); - -#define ISCSI_STAT_INSTANCE_ATTR_RO(_name) \ -static struct iscsi_stat_instance_attribute \ - iscsi_stat_instance_##_name = \ - __CONFIGFS_EATTR_RO(_name, \ - iscsi_stat_instance_show_attr_##_name); - -static ssize_t iscsi_stat_instance_show_attr_inst( - struct iscsi_wwn_stat_grps *igrps, char *page) -{ - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); +static struct iscsi_tiqn *iscsi_instance_tiqn(struct config_item *item) +{ + struct iscsi_wwn_stat_grps *igrps = container_of(to_config_group(item), + struct iscsi_wwn_stat_grps, iscsi_instance_group); + return container_of(igrps, struct iscsi_tiqn, tiqn_stat_grps); +} - return snprintf(page, PAGE_SIZE, "%u\n", tiqn->tiqn_index); +static ssize_t iscsi_stat_instance_inst_show(struct config_item *item, + char *page) +{ + return snprintf(page, PAGE_SIZE, "%u\n", + iscsi_instance_tiqn(item)->tiqn_index); } -ISCSI_STAT_INSTANCE_ATTR_RO(inst); -static ssize_t iscsi_stat_instance_show_attr_min_ver( - struct iscsi_wwn_stat_grps *igrps, char *page) +static ssize_t iscsi_stat_instance_min_ver_show(struct config_item *item, + char *page) { return snprintf(page, PAGE_SIZE, "%u\n", ISCSI_DRAFT20_VERSION); } -ISCSI_STAT_INSTANCE_ATTR_RO(min_ver); -static ssize_t iscsi_stat_instance_show_attr_max_ver( - struct iscsi_wwn_stat_grps *igrps, char *page) +static ssize_t iscsi_stat_instance_max_ver_show(struct config_item *item, + char *page) { return snprintf(page, PAGE_SIZE, "%u\n", ISCSI_DRAFT20_VERSION); } -ISCSI_STAT_INSTANCE_ATTR_RO(max_ver); -static ssize_t iscsi_stat_instance_show_attr_portals( - struct iscsi_wwn_stat_grps *igrps, char *page) +static ssize_t iscsi_stat_instance_portals_show(struct config_item *item, + char *page) { - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); - - return snprintf(page, PAGE_SIZE, "%u\n", tiqn->tiqn_num_tpg_nps); + return snprintf(page, PAGE_SIZE, "%u\n", + iscsi_instance_tiqn(item)->tiqn_num_tpg_nps); } -ISCSI_STAT_INSTANCE_ATTR_RO(portals); -static ssize_t iscsi_stat_instance_show_attr_nodes( - struct iscsi_wwn_stat_grps *igrps, char *page) +static ssize_t iscsi_stat_instance_nodes_show(struct config_item *item, + char *page) { return snprintf(page, PAGE_SIZE, "%u\n", ISCSI_INST_NUM_NODES); } -ISCSI_STAT_INSTANCE_ATTR_RO(nodes); -static ssize_t iscsi_stat_instance_show_attr_sessions( - struct iscsi_wwn_stat_grps *igrps, char *page) +static ssize_t iscsi_stat_instance_sessions_show(struct config_item *item, + char *page) { - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); - - return snprintf(page, PAGE_SIZE, "%u\n", tiqn->tiqn_nsessions); + return snprintf(page, PAGE_SIZE, "%u\n", + iscsi_instance_tiqn(item)->tiqn_nsessions); } -ISCSI_STAT_INSTANCE_ATTR_RO(sessions); -static ssize_t iscsi_stat_instance_show_attr_fail_sess( - struct iscsi_wwn_stat_grps *igrps, char *page) +static ssize_t iscsi_stat_instance_fail_sess_show(struct config_item *item, + char *page) { - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); + struct iscsi_tiqn *tiqn = iscsi_instance_tiqn(item); struct iscsi_sess_err_stats *sess_err = &tiqn->sess_err_stats; u32 sess_err_count; @@ -131,88 +110,84 @@ static ssize_t iscsi_stat_instance_show_attr_fail_sess( return snprintf(page, PAGE_SIZE, "%u\n", sess_err_count); } -ISCSI_STAT_INSTANCE_ATTR_RO(fail_sess); -static ssize_t iscsi_stat_instance_show_attr_fail_type( - struct iscsi_wwn_stat_grps *igrps, char *page) +static ssize_t iscsi_stat_instance_fail_type_show(struct config_item *item, + char *page) { - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); + struct iscsi_tiqn *tiqn = iscsi_instance_tiqn(item); struct iscsi_sess_err_stats *sess_err = &tiqn->sess_err_stats; return snprintf(page, PAGE_SIZE, "%u\n", sess_err->last_sess_failure_type); } -ISCSI_STAT_INSTANCE_ATTR_RO(fail_type); -static ssize_t iscsi_stat_instance_show_attr_fail_rem_name( - struct iscsi_wwn_stat_grps *igrps, char *page) +static ssize_t iscsi_stat_instance_fail_rem_name_show(struct config_item *item, + char *page) { - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); + struct iscsi_tiqn *tiqn = iscsi_instance_tiqn(item); struct iscsi_sess_err_stats *sess_err = &tiqn->sess_err_stats; return snprintf(page, PAGE_SIZE, "%s\n", sess_err->last_sess_fail_rem_name[0] ? sess_err->last_sess_fail_rem_name : NONE); } -ISCSI_STAT_INSTANCE_ATTR_RO(fail_rem_name); -static ssize_t iscsi_stat_instance_show_attr_disc_time( - struct iscsi_wwn_stat_grps *igrps, char *page) +static ssize_t iscsi_stat_instance_disc_time_show(struct config_item *item, + char *page) { return snprintf(page, PAGE_SIZE, "%u\n", ISCSI_DISCONTINUITY_TIME); } -ISCSI_STAT_INSTANCE_ATTR_RO(disc_time); -static ssize_t iscsi_stat_instance_show_attr_description( - struct iscsi_wwn_stat_grps *igrps, char *page) +static ssize_t iscsi_stat_instance_description_show(struct config_item *item, + char *page) { return snprintf(page, PAGE_SIZE, "%s\n", ISCSI_INST_DESCR); } -ISCSI_STAT_INSTANCE_ATTR_RO(description); -static ssize_t iscsi_stat_instance_show_attr_vendor( - struct iscsi_wwn_stat_grps *igrps, char *page) +static ssize_t iscsi_stat_instance_vendor_show(struct config_item *item, + char *page) { return snprintf(page, PAGE_SIZE, "Datera, Inc. iSCSI-Target\n"); } -ISCSI_STAT_INSTANCE_ATTR_RO(vendor); -static ssize_t iscsi_stat_instance_show_attr_version( - struct iscsi_wwn_stat_grps *igrps, char *page) +static ssize_t iscsi_stat_instance_version_show(struct config_item *item, + char *page) { return snprintf(page, PAGE_SIZE, "%s\n", ISCSIT_VERSION); } -ISCSI_STAT_INSTANCE_ATTR_RO(version); -CONFIGFS_EATTR_OPS(iscsi_stat_instance, iscsi_wwn_stat_grps, - iscsi_instance_group); +CONFIGFS_ATTR_RO(iscsi_stat_instance_, inst); +CONFIGFS_ATTR_RO(iscsi_stat_instance_, min_ver); +CONFIGFS_ATTR_RO(iscsi_stat_instance_, max_ver); +CONFIGFS_ATTR_RO(iscsi_stat_instance_, portals); +CONFIGFS_ATTR_RO(iscsi_stat_instance_, nodes); +CONFIGFS_ATTR_RO(iscsi_stat_instance_, sessions); +CONFIGFS_ATTR_RO(iscsi_stat_instance_, fail_sess); +CONFIGFS_ATTR_RO(iscsi_stat_instance_, fail_type); +CONFIGFS_ATTR_RO(iscsi_stat_instance_, fail_rem_name); +CONFIGFS_ATTR_RO(iscsi_stat_instance_, disc_time); +CONFIGFS_ATTR_RO(iscsi_stat_instance_, description); +CONFIGFS_ATTR_RO(iscsi_stat_instance_, vendor); +CONFIGFS_ATTR_RO(iscsi_stat_instance_, version); static struct configfs_attribute *iscsi_stat_instance_attrs[] = { - &iscsi_stat_instance_inst.attr, - &iscsi_stat_instance_min_ver.attr, - &iscsi_stat_instance_max_ver.attr, - &iscsi_stat_instance_portals.attr, - &iscsi_stat_instance_nodes.attr, - &iscsi_stat_instance_sessions.attr, - &iscsi_stat_instance_fail_sess.attr, - &iscsi_stat_instance_fail_type.attr, - &iscsi_stat_instance_fail_rem_name.attr, - &iscsi_stat_instance_disc_time.attr, - &iscsi_stat_instance_description.attr, - &iscsi_stat_instance_vendor.attr, - &iscsi_stat_instance_version.attr, + &iscsi_stat_instance_attr_inst, + &iscsi_stat_instance_attr_min_ver, + &iscsi_stat_instance_attr_max_ver, + &iscsi_stat_instance_attr_portals, + &iscsi_stat_instance_attr_nodes, + &iscsi_stat_instance_attr_sessions, + &iscsi_stat_instance_attr_fail_sess, + &iscsi_stat_instance_attr_fail_type, + &iscsi_stat_instance_attr_fail_rem_name, + &iscsi_stat_instance_attr_disc_time, + &iscsi_stat_instance_attr_description, + &iscsi_stat_instance_attr_vendor, + &iscsi_stat_instance_attr_version, NULL, }; -static struct configfs_item_operations iscsi_stat_instance_item_ops = { - .show_attribute = iscsi_stat_instance_attr_show, - .store_attribute = iscsi_stat_instance_attr_store, -}; - struct config_item_type iscsi_stat_instance_cit = { - .ct_item_ops = &iscsi_stat_instance_item_ops, .ct_attrs = iscsi_stat_instance_attrs, .ct_owner = THIS_MODULE, }; @@ -220,81 +195,61 @@ struct config_item_type iscsi_stat_instance_cit = { /* * Instance Session Failure Stats Table */ -CONFIGFS_EATTR_STRUCT(iscsi_stat_sess_err, iscsi_wwn_stat_grps); -#define ISCSI_STAT_SESS_ERR_ATTR(_name, _mode) \ -static struct iscsi_stat_sess_err_attribute \ - iscsi_stat_sess_err_##_name = \ - __CONFIGFS_EATTR(_name, _mode, \ - iscsi_stat_sess_err_show_attr_##_name, \ - iscsi_stat_sess_err_store_attr_##_name); - -#define ISCSI_STAT_SESS_ERR_ATTR_RO(_name) \ -static struct iscsi_stat_sess_err_attribute \ - iscsi_stat_sess_err_##_name = \ - __CONFIGFS_EATTR_RO(_name, \ - iscsi_stat_sess_err_show_attr_##_name); - -static ssize_t iscsi_stat_sess_err_show_attr_inst( - struct iscsi_wwn_stat_grps *igrps, char *page) -{ - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); +static struct iscsi_tiqn *iscsi_sess_err_tiqn(struct config_item *item) +{ + struct iscsi_wwn_stat_grps *igrps = container_of(to_config_group(item), + struct iscsi_wwn_stat_grps, iscsi_sess_err_group); + return container_of(igrps, struct iscsi_tiqn, tiqn_stat_grps); +} - return snprintf(page, PAGE_SIZE, "%u\n", tiqn->tiqn_index); +static ssize_t iscsi_stat_sess_err_inst_show(struct config_item *item, + char *page) +{ + return snprintf(page, PAGE_SIZE, "%u\n", + iscsi_sess_err_tiqn(item)->tiqn_index); } -ISCSI_STAT_SESS_ERR_ATTR_RO(inst); -static ssize_t iscsi_stat_sess_err_show_attr_digest_errors( - struct iscsi_wwn_stat_grps *igrps, char *page) +static ssize_t iscsi_stat_sess_err_digest_errors_show(struct config_item *item, + char *page) { - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); + struct iscsi_tiqn *tiqn = iscsi_sess_err_tiqn(item); struct iscsi_sess_err_stats *sess_err = &tiqn->sess_err_stats; return snprintf(page, PAGE_SIZE, "%u\n", sess_err->digest_errors); } -ISCSI_STAT_SESS_ERR_ATTR_RO(digest_errors); -static ssize_t iscsi_stat_sess_err_show_attr_cxn_errors( - struct iscsi_wwn_stat_grps *igrps, char *page) +static ssize_t iscsi_stat_sess_err_cxn_errors_show(struct config_item *item, + char *page) { - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); + struct iscsi_tiqn *tiqn = iscsi_sess_err_tiqn(item); struct iscsi_sess_err_stats *sess_err = &tiqn->sess_err_stats; return snprintf(page, PAGE_SIZE, "%u\n", sess_err->cxn_timeout_errors); } -ISCSI_STAT_SESS_ERR_ATTR_RO(cxn_errors); -static ssize_t iscsi_stat_sess_err_show_attr_format_errors( - struct iscsi_wwn_stat_grps *igrps, char *page) +static ssize_t iscsi_stat_sess_err_format_errors_show(struct config_item *item, + char *page) { - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); + struct iscsi_tiqn *tiqn = iscsi_sess_err_tiqn(item); struct iscsi_sess_err_stats *sess_err = &tiqn->sess_err_stats; return snprintf(page, PAGE_SIZE, "%u\n", sess_err->pdu_format_errors); } -ISCSI_STAT_SESS_ERR_ATTR_RO(format_errors); -CONFIGFS_EATTR_OPS(iscsi_stat_sess_err, iscsi_wwn_stat_grps, - iscsi_sess_err_group); +CONFIGFS_ATTR_RO(iscsi_stat_sess_err_, inst); +CONFIGFS_ATTR_RO(iscsi_stat_sess_err_, digest_errors); +CONFIGFS_ATTR_RO(iscsi_stat_sess_err_, cxn_errors); +CONFIGFS_ATTR_RO(iscsi_stat_sess_err_, format_errors); static struct configfs_attribute *iscsi_stat_sess_err_attrs[] = { - &iscsi_stat_sess_err_inst.attr, - &iscsi_stat_sess_err_digest_errors.attr, - &iscsi_stat_sess_err_cxn_errors.attr, - &iscsi_stat_sess_err_format_errors.attr, + &iscsi_stat_sess_err_attr_inst, + &iscsi_stat_sess_err_attr_digest_errors, + &iscsi_stat_sess_err_attr_cxn_errors, + &iscsi_stat_sess_err_attr_format_errors, NULL, }; -static struct configfs_item_operations iscsi_stat_sess_err_item_ops = { - .show_attribute = iscsi_stat_sess_err_attr_show, - .store_attribute = iscsi_stat_sess_err_attr_store, -}; - struct config_item_type iscsi_stat_sess_err_cit = { - .ct_item_ops = &iscsi_stat_sess_err_item_ops, .ct_attrs = iscsi_stat_sess_err_attrs, .ct_owner = THIS_MODULE, }; @@ -302,42 +257,30 @@ struct config_item_type iscsi_stat_sess_err_cit = { /* * Target Attributes Table */ -CONFIGFS_EATTR_STRUCT(iscsi_stat_tgt_attr, iscsi_wwn_stat_grps); -#define ISCSI_STAT_TGT_ATTR(_name, _mode) \ -static struct iscsi_stat_tgt_attr_attribute \ - iscsi_stat_tgt_attr_##_name = \ - __CONFIGFS_EATTR(_name, _mode, \ - iscsi_stat_tgt-attr_show_attr_##_name, \ - iscsi_stat_tgt_attr_store_attr_##_name); - -#define ISCSI_STAT_TGT_ATTR_RO(_name) \ -static struct iscsi_stat_tgt_attr_attribute \ - iscsi_stat_tgt_attr_##_name = \ - __CONFIGFS_EATTR_RO(_name, \ - iscsi_stat_tgt_attr_show_attr_##_name); - -static ssize_t iscsi_stat_tgt_attr_show_attr_inst( - struct iscsi_wwn_stat_grps *igrps, char *page) -{ - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); +static struct iscsi_tiqn *iscsi_tgt_attr_tiqn(struct config_item *item) +{ + struct iscsi_wwn_stat_grps *igrps = container_of(to_config_group(item), + struct iscsi_wwn_stat_grps, iscsi_tgt_attr_group); + return container_of(igrps, struct iscsi_tiqn, tiqn_stat_grps); +} - return snprintf(page, PAGE_SIZE, "%u\n", tiqn->tiqn_index); +static ssize_t iscsi_stat_tgt_attr_inst_show(struct config_item *item, + char *page) +{ + return snprintf(page, PAGE_SIZE, "%u\n", + iscsi_tgt_attr_tiqn(item)->tiqn_index); } -ISCSI_STAT_TGT_ATTR_RO(inst); -static ssize_t iscsi_stat_tgt_attr_show_attr_indx( - struct iscsi_wwn_stat_grps *igrps, char *page) +static ssize_t iscsi_stat_tgt_attr_indx_show(struct config_item *item, + char *page) { return snprintf(page, PAGE_SIZE, "%u\n", ISCSI_NODE_INDEX); } -ISCSI_STAT_TGT_ATTR_RO(indx); -static ssize_t iscsi_stat_tgt_attr_show_attr_login_fails( - struct iscsi_wwn_stat_grps *igrps, char *page) +static ssize_t iscsi_stat_tgt_attr_login_fails_show(struct config_item *item, + char *page) { - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); + struct iscsi_tiqn *tiqn = iscsi_tgt_attr_tiqn(item); struct iscsi_login_stats *lstat = &tiqn->login_stats; u32 fail_count; @@ -349,13 +292,11 @@ static ssize_t iscsi_stat_tgt_attr_show_attr_login_fails( return snprintf(page, PAGE_SIZE, "%u\n", fail_count); } -ISCSI_STAT_TGT_ATTR_RO(login_fails); -static ssize_t iscsi_stat_tgt_attr_show_attr_last_fail_time( - struct iscsi_wwn_stat_grps *igrps, char *page) +static ssize_t iscsi_stat_tgt_attr_last_fail_time_show(struct config_item *item, + char *page) { - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); + struct iscsi_tiqn *tiqn = iscsi_tgt_attr_tiqn(item); struct iscsi_login_stats *lstat = &tiqn->login_stats; u32 last_fail_time; @@ -367,13 +308,11 @@ static ssize_t iscsi_stat_tgt_attr_show_attr_last_fail_time( return snprintf(page, PAGE_SIZE, "%u\n", last_fail_time); } -ISCSI_STAT_TGT_ATTR_RO(last_fail_time); -static ssize_t iscsi_stat_tgt_attr_show_attr_last_fail_type( - struct iscsi_wwn_stat_grps *igrps, char *page) +static ssize_t iscsi_stat_tgt_attr_last_fail_type_show(struct config_item *item, + char *page) { - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); + struct iscsi_tiqn *tiqn = iscsi_tgt_attr_tiqn(item); struct iscsi_login_stats *lstat = &tiqn->login_stats; u32 last_fail_type; @@ -383,13 +322,11 @@ static ssize_t iscsi_stat_tgt_attr_show_attr_last_fail_type( return snprintf(page, PAGE_SIZE, "%u\n", last_fail_type); } -ISCSI_STAT_TGT_ATTR_RO(last_fail_type); -static ssize_t iscsi_stat_tgt_attr_show_attr_fail_intr_name( - struct iscsi_wwn_stat_grps *igrps, char *page) +static ssize_t iscsi_stat_tgt_attr_fail_intr_name_show(struct config_item *item, + char *page) { - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); + struct iscsi_tiqn *tiqn = iscsi_tgt_attr_tiqn(item); struct iscsi_login_stats *lstat = &tiqn->login_stats; unsigned char buf[224]; @@ -400,13 +337,11 @@ static ssize_t iscsi_stat_tgt_attr_show_attr_fail_intr_name( return snprintf(page, PAGE_SIZE, "%s\n", buf); } -ISCSI_STAT_TGT_ATTR_RO(fail_intr_name); -static ssize_t iscsi_stat_tgt_attr_show_attr_fail_intr_addr_type( - struct iscsi_wwn_stat_grps *igrps, char *page) +static ssize_t iscsi_stat_tgt_attr_fail_intr_addr_type_show(struct config_item *item, + char *page) { - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); + struct iscsi_tiqn *tiqn = iscsi_tgt_attr_tiqn(item); struct iscsi_login_stats *lstat = &tiqn->login_stats; int ret; @@ -419,13 +354,11 @@ static ssize_t iscsi_stat_tgt_attr_show_attr_fail_intr_addr_type( return ret; } -ISCSI_STAT_TGT_ATTR_RO(fail_intr_addr_type); -static ssize_t iscsi_stat_tgt_attr_show_attr_fail_intr_addr( - struct iscsi_wwn_stat_grps *igrps, char *page) +static ssize_t iscsi_stat_tgt_attr_fail_intr_addr_show(struct config_item *item, + char *page) { - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); + struct iscsi_tiqn *tiqn = iscsi_tgt_attr_tiqn(item); struct iscsi_login_stats *lstat = &tiqn->login_stats; int ret; @@ -435,30 +368,29 @@ static ssize_t iscsi_stat_tgt_attr_show_attr_fail_intr_addr( return ret; } -ISCSI_STAT_TGT_ATTR_RO(fail_intr_addr); -CONFIGFS_EATTR_OPS(iscsi_stat_tgt_attr, iscsi_wwn_stat_grps, - iscsi_tgt_attr_group); +CONFIGFS_ATTR_RO(iscsi_stat_tgt_attr_, inst); +CONFIGFS_ATTR_RO(iscsi_stat_tgt_attr_, indx); +CONFIGFS_ATTR_RO(iscsi_stat_tgt_attr_, login_fails); +CONFIGFS_ATTR_RO(iscsi_stat_tgt_attr_, last_fail_time); +CONFIGFS_ATTR_RO(iscsi_stat_tgt_attr_, last_fail_type); +CONFIGFS_ATTR_RO(iscsi_stat_tgt_attr_, fail_intr_name); +CONFIGFS_ATTR_RO(iscsi_stat_tgt_attr_, fail_intr_addr_type); +CONFIGFS_ATTR_RO(iscsi_stat_tgt_attr_, fail_intr_addr); static struct configfs_attribute *iscsi_stat_tgt_attr_attrs[] = { - &iscsi_stat_tgt_attr_inst.attr, - &iscsi_stat_tgt_attr_indx.attr, - &iscsi_stat_tgt_attr_login_fails.attr, - &iscsi_stat_tgt_attr_last_fail_time.attr, - &iscsi_stat_tgt_attr_last_fail_type.attr, - &iscsi_stat_tgt_attr_fail_intr_name.attr, - &iscsi_stat_tgt_attr_fail_intr_addr_type.attr, - &iscsi_stat_tgt_attr_fail_intr_addr.attr, + &iscsi_stat_tgt_attr_attr_inst, + &iscsi_stat_tgt_attr_attr_indx, + &iscsi_stat_tgt_attr_attr_login_fails, + &iscsi_stat_tgt_attr_attr_last_fail_time, + &iscsi_stat_tgt_attr_attr_last_fail_type, + &iscsi_stat_tgt_attr_attr_fail_intr_name, + &iscsi_stat_tgt_attr_attr_fail_intr_addr_type, + &iscsi_stat_tgt_attr_attr_fail_intr_addr, NULL, }; -static struct configfs_item_operations iscsi_stat_tgt_attr_item_ops = { - .show_attribute = iscsi_stat_tgt_attr_attr_show, - .store_attribute = iscsi_stat_tgt_attr_attr_store, -}; - struct config_item_type iscsi_stat_tgt_attr_cit = { - .ct_item_ops = &iscsi_stat_tgt_attr_item_ops, .ct_attrs = iscsi_stat_tgt_attr_attrs, .ct_owner = THIS_MODULE, }; @@ -466,42 +398,29 @@ struct config_item_type iscsi_stat_tgt_attr_cit = { /* * Target Login Stats Table */ -CONFIGFS_EATTR_STRUCT(iscsi_stat_login, iscsi_wwn_stat_grps); -#define ISCSI_STAT_LOGIN(_name, _mode) \ -static struct iscsi_stat_login_attribute \ - iscsi_stat_login_##_name = \ - __CONFIGFS_EATTR(_name, _mode, \ - iscsi_stat_login_show_attr_##_name, \ - iscsi_stat_login_store_attr_##_name); - -#define ISCSI_STAT_LOGIN_RO(_name) \ -static struct iscsi_stat_login_attribute \ - iscsi_stat_login_##_name = \ - __CONFIGFS_EATTR_RO(_name, \ - iscsi_stat_login_show_attr_##_name); - -static ssize_t iscsi_stat_login_show_attr_inst( - struct iscsi_wwn_stat_grps *igrps, char *page) -{ - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); +static struct iscsi_tiqn *iscsi_login_stat_tiqn(struct config_item *item) +{ + struct iscsi_wwn_stat_grps *igrps = container_of(to_config_group(item), + struct iscsi_wwn_stat_grps, iscsi_login_stats_group); + return container_of(igrps, struct iscsi_tiqn, tiqn_stat_grps); +} - return snprintf(page, PAGE_SIZE, "%u\n", tiqn->tiqn_index); +static ssize_t iscsi_stat_login_inst_show(struct config_item *item, char *page) +{ + return snprintf(page, PAGE_SIZE, "%u\n", + iscsi_login_stat_tiqn(item)->tiqn_index); } -ISCSI_STAT_LOGIN_RO(inst); -static ssize_t iscsi_stat_login_show_attr_indx( - struct iscsi_wwn_stat_grps *igrps, char *page) +static ssize_t iscsi_stat_login_indx_show(struct config_item *item, + char *page) { return snprintf(page, PAGE_SIZE, "%u\n", ISCSI_NODE_INDEX); } -ISCSI_STAT_LOGIN_RO(indx); -static ssize_t iscsi_stat_login_show_attr_accepts( - struct iscsi_wwn_stat_grps *igrps, char *page) +static ssize_t iscsi_stat_login_accepts_show(struct config_item *item, + char *page) { - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); + struct iscsi_tiqn *tiqn = iscsi_login_stat_tiqn(item); struct iscsi_login_stats *lstat = &tiqn->login_stats; ssize_t ret; @@ -511,13 +430,11 @@ static ssize_t iscsi_stat_login_show_attr_accepts( return ret; } -ISCSI_STAT_LOGIN_RO(accepts); -static ssize_t iscsi_stat_login_show_attr_other_fails( - struct iscsi_wwn_stat_grps *igrps, char *page) +static ssize_t iscsi_stat_login_other_fails_show(struct config_item *item, + char *page) { - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); + struct iscsi_tiqn *tiqn = iscsi_login_stat_tiqn(item); struct iscsi_login_stats *lstat = &tiqn->login_stats; ssize_t ret; @@ -527,13 +444,11 @@ static ssize_t iscsi_stat_login_show_attr_other_fails( return ret; } -ISCSI_STAT_LOGIN_RO(other_fails); -static ssize_t iscsi_stat_login_show_attr_redirects( - struct iscsi_wwn_stat_grps *igrps, char *page) +static ssize_t iscsi_stat_login_redirects_show(struct config_item *item, + char *page) { - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); + struct iscsi_tiqn *tiqn = iscsi_login_stat_tiqn(item); struct iscsi_login_stats *lstat = &tiqn->login_stats; ssize_t ret; @@ -543,13 +458,11 @@ static ssize_t iscsi_stat_login_show_attr_redirects( return ret; } -ISCSI_STAT_LOGIN_RO(redirects); -static ssize_t iscsi_stat_login_show_attr_authorize_fails( - struct iscsi_wwn_stat_grps *igrps, char *page) +static ssize_t iscsi_stat_login_authorize_fails_show(struct config_item *item, + char *page) { - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); + struct iscsi_tiqn *tiqn = iscsi_login_stat_tiqn(item); struct iscsi_login_stats *lstat = &tiqn->login_stats; ssize_t ret; @@ -559,13 +472,11 @@ static ssize_t iscsi_stat_login_show_attr_authorize_fails( return ret; } -ISCSI_STAT_LOGIN_RO(authorize_fails); -static ssize_t iscsi_stat_login_show_attr_authenticate_fails( - struct iscsi_wwn_stat_grps *igrps, char *page) +static ssize_t iscsi_stat_login_authenticate_fails_show( + struct config_item *item, char *page) { - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); + struct iscsi_tiqn *tiqn = iscsi_login_stat_tiqn(item); struct iscsi_login_stats *lstat = &tiqn->login_stats; ssize_t ret; @@ -575,13 +486,11 @@ static ssize_t iscsi_stat_login_show_attr_authenticate_fails( return ret; } -ISCSI_STAT_LOGIN_RO(authenticate_fails); -static ssize_t iscsi_stat_login_show_attr_negotiate_fails( - struct iscsi_wwn_stat_grps *igrps, char *page) +static ssize_t iscsi_stat_login_negotiate_fails_show(struct config_item *item, + char *page) { - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); + struct iscsi_tiqn *tiqn = iscsi_login_stat_tiqn(item); struct iscsi_login_stats *lstat = &tiqn->login_stats; ssize_t ret; @@ -591,30 +500,29 @@ static ssize_t iscsi_stat_login_show_attr_negotiate_fails( return ret; } -ISCSI_STAT_LOGIN_RO(negotiate_fails); -CONFIGFS_EATTR_OPS(iscsi_stat_login, iscsi_wwn_stat_grps, - iscsi_login_stats_group); +CONFIGFS_ATTR_RO(iscsi_stat_login_, inst); +CONFIGFS_ATTR_RO(iscsi_stat_login_, indx); +CONFIGFS_ATTR_RO(iscsi_stat_login_, accepts); +CONFIGFS_ATTR_RO(iscsi_stat_login_, other_fails); +CONFIGFS_ATTR_RO(iscsi_stat_login_, redirects); +CONFIGFS_ATTR_RO(iscsi_stat_login_, authorize_fails); +CONFIGFS_ATTR_RO(iscsi_stat_login_, authenticate_fails); +CONFIGFS_ATTR_RO(iscsi_stat_login_, negotiate_fails); static struct configfs_attribute *iscsi_stat_login_stats_attrs[] = { - &iscsi_stat_login_inst.attr, - &iscsi_stat_login_indx.attr, - &iscsi_stat_login_accepts.attr, - &iscsi_stat_login_other_fails.attr, - &iscsi_stat_login_redirects.attr, - &iscsi_stat_login_authorize_fails.attr, - &iscsi_stat_login_authenticate_fails.attr, - &iscsi_stat_login_negotiate_fails.attr, + &iscsi_stat_login_attr_inst, + &iscsi_stat_login_attr_indx, + &iscsi_stat_login_attr_accepts, + &iscsi_stat_login_attr_other_fails, + &iscsi_stat_login_attr_redirects, + &iscsi_stat_login_attr_authorize_fails, + &iscsi_stat_login_attr_authenticate_fails, + &iscsi_stat_login_attr_negotiate_fails, NULL, }; -static struct configfs_item_operations iscsi_stat_login_stats_item_ops = { - .show_attribute = iscsi_stat_login_attr_show, - .store_attribute = iscsi_stat_login_attr_store, -}; - struct config_item_type iscsi_stat_login_cit = { - .ct_item_ops = &iscsi_stat_login_stats_item_ops, .ct_attrs = iscsi_stat_login_stats_attrs, .ct_owner = THIS_MODULE, }; @@ -622,78 +530,56 @@ struct config_item_type iscsi_stat_login_cit = { /* * Target Logout Stats Table */ - -CONFIGFS_EATTR_STRUCT(iscsi_stat_logout, iscsi_wwn_stat_grps); -#define ISCSI_STAT_LOGOUT(_name, _mode) \ -static struct iscsi_stat_logout_attribute \ - iscsi_stat_logout_##_name = \ - __CONFIGFS_EATTR(_name, _mode, \ - iscsi_stat_logout_show_attr_##_name, \ - iscsi_stat_logout_store_attr_##_name); - -#define ISCSI_STAT_LOGOUT_RO(_name) \ -static struct iscsi_stat_logout_attribute \ - iscsi_stat_logout_##_name = \ - __CONFIGFS_EATTR_RO(_name, \ - iscsi_stat_logout_show_attr_##_name); - -static ssize_t iscsi_stat_logout_show_attr_inst( - struct iscsi_wwn_stat_grps *igrps, char *page) +static struct iscsi_tiqn *iscsi_logout_stat_tiqn(struct config_item *item) { - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); + struct iscsi_wwn_stat_grps *igrps = container_of(to_config_group(item), + struct iscsi_wwn_stat_grps, iscsi_logout_stats_group); + return container_of(igrps, struct iscsi_tiqn, tiqn_stat_grps); +} - return snprintf(page, PAGE_SIZE, "%u\n", tiqn->tiqn_index); +static ssize_t iscsi_stat_logout_inst_show(struct config_item *item, char *page) +{ + return snprintf(page, PAGE_SIZE, "%u\n", + iscsi_logout_stat_tiqn(item)->tiqn_index); } -ISCSI_STAT_LOGOUT_RO(inst); -static ssize_t iscsi_stat_logout_show_attr_indx( - struct iscsi_wwn_stat_grps *igrps, char *page) +static ssize_t iscsi_stat_logout_indx_show(struct config_item *item, char *page) { return snprintf(page, PAGE_SIZE, "%u\n", ISCSI_NODE_INDEX); } -ISCSI_STAT_LOGOUT_RO(indx); -static ssize_t iscsi_stat_logout_show_attr_normal_logouts( - struct iscsi_wwn_stat_grps *igrps, char *page) +static ssize_t iscsi_stat_logout_normal_logouts_show(struct config_item *item, + char *page) { - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); + struct iscsi_tiqn *tiqn = iscsi_logout_stat_tiqn(item); struct iscsi_logout_stats *lstats = &tiqn->logout_stats; return snprintf(page, PAGE_SIZE, "%u\n", lstats->normal_logouts); } -ISCSI_STAT_LOGOUT_RO(normal_logouts); -static ssize_t iscsi_stat_logout_show_attr_abnormal_logouts( - struct iscsi_wwn_stat_grps *igrps, char *page) +static ssize_t iscsi_stat_logout_abnormal_logouts_show(struct config_item *item, + char *page) { - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); + struct iscsi_tiqn *tiqn = iscsi_logout_stat_tiqn(item); struct iscsi_logout_stats *lstats = &tiqn->logout_stats; return snprintf(page, PAGE_SIZE, "%u\n", lstats->abnormal_logouts); } -ISCSI_STAT_LOGOUT_RO(abnormal_logouts); -CONFIGFS_EATTR_OPS(iscsi_stat_logout, iscsi_wwn_stat_grps, - iscsi_logout_stats_group); +CONFIGFS_ATTR_RO(iscsi_stat_logout_, inst); +CONFIGFS_ATTR_RO(iscsi_stat_logout_, indx); +CONFIGFS_ATTR_RO(iscsi_stat_logout_, normal_logouts); +CONFIGFS_ATTR_RO(iscsi_stat_logout_, abnormal_logouts); static struct configfs_attribute *iscsi_stat_logout_stats_attrs[] = { - &iscsi_stat_logout_inst.attr, - &iscsi_stat_logout_indx.attr, - &iscsi_stat_logout_normal_logouts.attr, - &iscsi_stat_logout_abnormal_logouts.attr, + &iscsi_stat_logout_attr_inst, + &iscsi_stat_logout_attr_indx, + &iscsi_stat_logout_attr_normal_logouts, + &iscsi_stat_logout_attr_abnormal_logouts, NULL, }; -static struct configfs_item_operations iscsi_stat_logout_stats_item_ops = { - .show_attribute = iscsi_stat_logout_attr_show, - .store_attribute = iscsi_stat_logout_attr_store, -}; - struct config_item_type iscsi_stat_logout_cit = { - .ct_item_ops = &iscsi_stat_logout_stats_item_ops, .ct_attrs = iscsi_stat_logout_stats_attrs, .ct_owner = THIS_MODULE, }; @@ -701,39 +587,26 @@ struct config_item_type iscsi_stat_logout_cit = { /* * Session Stats Table */ +static struct iscsi_node_acl *iscsi_stat_nacl(struct config_item *item) +{ + struct iscsi_node_stat_grps *igrps = container_of(to_config_group(item), + struct iscsi_node_stat_grps, iscsi_sess_stats_group); + return container_of(igrps, struct iscsi_node_acl, node_stat_grps); +} -CONFIGFS_EATTR_STRUCT(iscsi_stat_sess, iscsi_node_stat_grps); -#define ISCSI_STAT_SESS(_name, _mode) \ -static struct iscsi_stat_sess_attribute \ - iscsi_stat_sess_##_name = \ - __CONFIGFS_EATTR(_name, _mode, \ - iscsi_stat_sess_show_attr_##_name, \ - iscsi_stat_sess_store_attr_##_name); - -#define ISCSI_STAT_SESS_RO(_name) \ -static struct iscsi_stat_sess_attribute \ - iscsi_stat_sess_##_name = \ - __CONFIGFS_EATTR_RO(_name, \ - iscsi_stat_sess_show_attr_##_name); - -static ssize_t iscsi_stat_sess_show_attr_inst( - struct iscsi_node_stat_grps *igrps, char *page) -{ - struct iscsi_node_acl *acl = container_of(igrps, - struct iscsi_node_acl, node_stat_grps); +static ssize_t iscsi_stat_sess_inst_show(struct config_item *item, char *page) +{ + struct iscsi_node_acl *acl = iscsi_stat_nacl(item); struct se_wwn *wwn = acl->se_node_acl.se_tpg->se_tpg_wwn; struct iscsi_tiqn *tiqn = container_of(wwn, struct iscsi_tiqn, tiqn_wwn); return snprintf(page, PAGE_SIZE, "%u\n", tiqn->tiqn_index); } -ISCSI_STAT_SESS_RO(inst); -static ssize_t iscsi_stat_sess_show_attr_node( - struct iscsi_node_stat_grps *igrps, char *page) +static ssize_t iscsi_stat_sess_node_show(struct config_item *item, char *page) { - struct iscsi_node_acl *acl = container_of(igrps, - struct iscsi_node_acl, node_stat_grps); + struct iscsi_node_acl *acl = iscsi_stat_nacl(item); struct se_node_acl *se_nacl = &acl->se_node_acl; struct iscsi_session *sess; struct se_session *se_sess; @@ -751,13 +624,10 @@ static ssize_t iscsi_stat_sess_show_attr_node( return ret; } -ISCSI_STAT_SESS_RO(node); -static ssize_t iscsi_stat_sess_show_attr_indx( - struct iscsi_node_stat_grps *igrps, char *page) +static ssize_t iscsi_stat_sess_indx_show(struct config_item *item, char *page) { - struct iscsi_node_acl *acl = container_of(igrps, - struct iscsi_node_acl, node_stat_grps); + struct iscsi_node_acl *acl = iscsi_stat_nacl(item); struct se_node_acl *se_nacl = &acl->se_node_acl; struct iscsi_session *sess; struct se_session *se_sess; @@ -775,13 +645,11 @@ static ssize_t iscsi_stat_sess_show_attr_indx( return ret; } -ISCSI_STAT_SESS_RO(indx); -static ssize_t iscsi_stat_sess_show_attr_cmd_pdus( - struct iscsi_node_stat_grps *igrps, char *page) +static ssize_t iscsi_stat_sess_cmd_pdus_show(struct config_item *item, + char *page) { - struct iscsi_node_acl *acl = container_of(igrps, - struct iscsi_node_acl, node_stat_grps); + struct iscsi_node_acl *acl = iscsi_stat_nacl(item); struct se_node_acl *se_nacl = &acl->se_node_acl; struct iscsi_session *sess; struct se_session *se_sess; @@ -799,13 +667,11 @@ static ssize_t iscsi_stat_sess_show_attr_cmd_pdus( return ret; } -ISCSI_STAT_SESS_RO(cmd_pdus); -static ssize_t iscsi_stat_sess_show_attr_rsp_pdus( - struct iscsi_node_stat_grps *igrps, char *page) +static ssize_t iscsi_stat_sess_rsp_pdus_show(struct config_item *item, + char *page) { - struct iscsi_node_acl *acl = container_of(igrps, - struct iscsi_node_acl, node_stat_grps); + struct iscsi_node_acl *acl = iscsi_stat_nacl(item); struct se_node_acl *se_nacl = &acl->se_node_acl; struct iscsi_session *sess; struct se_session *se_sess; @@ -823,13 +689,11 @@ static ssize_t iscsi_stat_sess_show_attr_rsp_pdus( return ret; } -ISCSI_STAT_SESS_RO(rsp_pdus); -static ssize_t iscsi_stat_sess_show_attr_txdata_octs( - struct iscsi_node_stat_grps *igrps, char *page) +static ssize_t iscsi_stat_sess_txdata_octs_show(struct config_item *item, + char *page) { - struct iscsi_node_acl *acl = container_of(igrps, - struct iscsi_node_acl, node_stat_grps); + struct iscsi_node_acl *acl = iscsi_stat_nacl(item); struct se_node_acl *se_nacl = &acl->se_node_acl; struct iscsi_session *sess; struct se_session *se_sess; @@ -847,13 +711,11 @@ static ssize_t iscsi_stat_sess_show_attr_txdata_octs( return ret; } -ISCSI_STAT_SESS_RO(txdata_octs); -static ssize_t iscsi_stat_sess_show_attr_rxdata_octs( - struct iscsi_node_stat_grps *igrps, char *page) +static ssize_t iscsi_stat_sess_rxdata_octs_show(struct config_item *item, + char *page) { - struct iscsi_node_acl *acl = container_of(igrps, - struct iscsi_node_acl, node_stat_grps); + struct iscsi_node_acl *acl = iscsi_stat_nacl(item); struct se_node_acl *se_nacl = &acl->se_node_acl; struct iscsi_session *sess; struct se_session *se_sess; @@ -871,13 +733,11 @@ static ssize_t iscsi_stat_sess_show_attr_rxdata_octs( return ret; } -ISCSI_STAT_SESS_RO(rxdata_octs); -static ssize_t iscsi_stat_sess_show_attr_conn_digest_errors( - struct iscsi_node_stat_grps *igrps, char *page) +static ssize_t iscsi_stat_sess_conn_digest_errors_show(struct config_item *item, + char *page) { - struct iscsi_node_acl *acl = container_of(igrps, - struct iscsi_node_acl, node_stat_grps); + struct iscsi_node_acl *acl = iscsi_stat_nacl(item); struct se_node_acl *se_nacl = &acl->se_node_acl; struct iscsi_session *sess; struct se_session *se_sess; @@ -895,13 +755,11 @@ static ssize_t iscsi_stat_sess_show_attr_conn_digest_errors( return ret; } -ISCSI_STAT_SESS_RO(conn_digest_errors); -static ssize_t iscsi_stat_sess_show_attr_conn_timeout_errors( - struct iscsi_node_stat_grps *igrps, char *page) +static ssize_t iscsi_stat_sess_conn_timeout_errors_show( + struct config_item *item, char *page) { - struct iscsi_node_acl *acl = container_of(igrps, - struct iscsi_node_acl, node_stat_grps); + struct iscsi_node_acl *acl = iscsi_stat_nacl(item); struct se_node_acl *se_nacl = &acl->se_node_acl; struct iscsi_session *sess; struct se_session *se_sess; @@ -919,31 +777,31 @@ static ssize_t iscsi_stat_sess_show_attr_conn_timeout_errors( return ret; } -ISCSI_STAT_SESS_RO(conn_timeout_errors); -CONFIGFS_EATTR_OPS(iscsi_stat_sess, iscsi_node_stat_grps, - iscsi_sess_stats_group); +CONFIGFS_ATTR_RO(iscsi_stat_sess_, inst); +CONFIGFS_ATTR_RO(iscsi_stat_sess_, node); +CONFIGFS_ATTR_RO(iscsi_stat_sess_, indx); +CONFIGFS_ATTR_RO(iscsi_stat_sess_, cmd_pdus); +CONFIGFS_ATTR_RO(iscsi_stat_sess_, rsp_pdus); +CONFIGFS_ATTR_RO(iscsi_stat_sess_, txdata_octs); +CONFIGFS_ATTR_RO(iscsi_stat_sess_, rxdata_octs); +CONFIGFS_ATTR_RO(iscsi_stat_sess_, conn_digest_errors); +CONFIGFS_ATTR_RO(iscsi_stat_sess_, conn_timeout_errors); static struct configfs_attribute *iscsi_stat_sess_stats_attrs[] = { - &iscsi_stat_sess_inst.attr, - &iscsi_stat_sess_node.attr, - &iscsi_stat_sess_indx.attr, - &iscsi_stat_sess_cmd_pdus.attr, - &iscsi_stat_sess_rsp_pdus.attr, - &iscsi_stat_sess_txdata_octs.attr, - &iscsi_stat_sess_rxdata_octs.attr, - &iscsi_stat_sess_conn_digest_errors.attr, - &iscsi_stat_sess_conn_timeout_errors.attr, + &iscsi_stat_sess_attr_inst, + &iscsi_stat_sess_attr_node, + &iscsi_stat_sess_attr_indx, + &iscsi_stat_sess_attr_cmd_pdus, + &iscsi_stat_sess_attr_rsp_pdus, + &iscsi_stat_sess_attr_txdata_octs, + &iscsi_stat_sess_attr_rxdata_octs, + &iscsi_stat_sess_attr_conn_digest_errors, + &iscsi_stat_sess_attr_conn_timeout_errors, NULL, }; -static struct configfs_item_operations iscsi_stat_sess_stats_item_ops = { - .show_attribute = iscsi_stat_sess_attr_show, - .store_attribute = iscsi_stat_sess_attr_store, -}; - struct config_item_type iscsi_stat_sess_cit = { - .ct_item_ops = &iscsi_stat_sess_stats_item_ops, .ct_attrs = iscsi_stat_sess_stats_attrs, .ct_owner = THIS_MODULE, }; diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index 5bc85ffed720..4fb0eca86857 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -34,7 +34,6 @@ #include <target/target_core_base.h> #include <target/target_core_fabric.h> -#include <target/target_core_fabric_configfs.h> #include "tcm_loop.h" @@ -377,7 +376,6 @@ static struct scsi_host_template tcm_loop_driver_template = { .use_clustering = DISABLE_CLUSTERING, .slave_alloc = tcm_loop_slave_alloc, .module = THIS_MODULE, - .use_blk_tags = 1, .track_queue_depth = 1, }; @@ -763,21 +761,20 @@ static void tcm_loop_port_unlink( /* End items for tcm_loop_port_cit */ -static ssize_t tcm_loop_tpg_attrib_show_fabric_prot_type( - struct se_portal_group *se_tpg, - char *page) +static ssize_t tcm_loop_tpg_attrib_fabric_prot_type_show( + struct config_item *item, char *page) { + struct se_portal_group *se_tpg = attrib_to_tpg(item); struct tcm_loop_tpg *tl_tpg = container_of(se_tpg, struct tcm_loop_tpg, tl_se_tpg); return sprintf(page, "%d\n", tl_tpg->tl_fabric_prot_type); } -static ssize_t tcm_loop_tpg_attrib_store_fabric_prot_type( - struct se_portal_group *se_tpg, - const char *page, - size_t count) +static ssize_t tcm_loop_tpg_attrib_fabric_prot_type_store( + struct config_item *item, const char *page, size_t count) { + struct se_portal_group *se_tpg = attrib_to_tpg(item); struct tcm_loop_tpg *tl_tpg = container_of(se_tpg, struct tcm_loop_tpg, tl_se_tpg); unsigned long val; @@ -796,10 +793,10 @@ static ssize_t tcm_loop_tpg_attrib_store_fabric_prot_type( return count; } -TF_TPG_ATTRIB_ATTR(tcm_loop, fabric_prot_type, S_IRUGO | S_IWUSR); +CONFIGFS_ATTR(tcm_loop_tpg_attrib_, fabric_prot_type); static struct configfs_attribute *tcm_loop_tpg_attrib_attrs[] = { - &tcm_loop_tpg_attrib_fabric_prot_type.attr, + &tcm_loop_tpg_attrib_attr_fabric_prot_type, NULL, }; @@ -894,10 +891,9 @@ static int tcm_loop_drop_nexus( /* End items for tcm_loop_nexus_cit */ -static ssize_t tcm_loop_tpg_show_nexus( - struct se_portal_group *se_tpg, - char *page) +static ssize_t tcm_loop_tpg_nexus_show(struct config_item *item, char *page) { + struct se_portal_group *se_tpg = to_tpg(item); struct tcm_loop_tpg *tl_tpg = container_of(se_tpg, struct tcm_loop_tpg, tl_se_tpg); struct tcm_loop_nexus *tl_nexus; @@ -913,11 +909,10 @@ static ssize_t tcm_loop_tpg_show_nexus( return ret; } -static ssize_t tcm_loop_tpg_store_nexus( - struct se_portal_group *se_tpg, - const char *page, - size_t count) +static ssize_t tcm_loop_tpg_nexus_store(struct config_item *item, + const char *page, size_t count) { + struct se_portal_group *se_tpg = to_tpg(item); struct tcm_loop_tpg *tl_tpg = container_of(se_tpg, struct tcm_loop_tpg, tl_se_tpg); struct tcm_loop_hba *tl_hba = tl_tpg->tl_hba; @@ -992,12 +987,10 @@ check_newline: return count; } -TF_TPG_BASE_ATTR(tcm_loop, nexus, S_IRUGO | S_IWUSR); - -static ssize_t tcm_loop_tpg_show_transport_status( - struct se_portal_group *se_tpg, - char *page) +static ssize_t tcm_loop_tpg_transport_status_show(struct config_item *item, + char *page) { + struct se_portal_group *se_tpg = to_tpg(item); struct tcm_loop_tpg *tl_tpg = container_of(se_tpg, struct tcm_loop_tpg, tl_se_tpg); const char *status = NULL; @@ -1020,11 +1013,10 @@ static ssize_t tcm_loop_tpg_show_transport_status( return ret; } -static ssize_t tcm_loop_tpg_store_transport_status( - struct se_portal_group *se_tpg, - const char *page, - size_t count) +static ssize_t tcm_loop_tpg_transport_status_store(struct config_item *item, + const char *page, size_t count) { + struct se_portal_group *se_tpg = to_tpg(item); struct tcm_loop_tpg *tl_tpg = container_of(se_tpg, struct tcm_loop_tpg, tl_se_tpg); @@ -1044,11 +1036,12 @@ static ssize_t tcm_loop_tpg_store_transport_status( return -EINVAL; } -TF_TPG_BASE_ATTR(tcm_loop, transport_status, S_IRUGO | S_IWUSR); +CONFIGFS_ATTR(tcm_loop_tpg_, nexus); +CONFIGFS_ATTR(tcm_loop_tpg_, transport_status); static struct configfs_attribute *tcm_loop_tpg_attrs[] = { - &tcm_loop_tpg_nexus.attr, - &tcm_loop_tpg_transport_status.attr, + &tcm_loop_tpg_attr_nexus, + &tcm_loop_tpg_attr_transport_status, NULL, }; @@ -1216,17 +1209,15 @@ static void tcm_loop_drop_scsi_hba( } /* Start items for tcm_loop_cit */ -static ssize_t tcm_loop_wwn_show_attr_version( - struct target_fabric_configfs *tf, - char *page) +static ssize_t tcm_loop_wwn_version_show(struct config_item *item, char *page) { return sprintf(page, "TCM Loopback Fabric module %s\n", TCM_LOOP_VERSION); } -TF_WWN_ATTR_RO(tcm_loop, version); +CONFIGFS_ATTR_RO(tcm_loop_wwn_, version); static struct configfs_attribute *tcm_loop_wwn_attrs[] = { - &tcm_loop_wwn_version.attr, + &tcm_loop_wwn_attr_version, NULL, }; diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c index 0edf320fb685..35f7d31b29d2 100644 --- a/drivers/target/sbp/sbp_target.c +++ b/drivers/target/sbp/sbp_target.c @@ -35,8 +35,6 @@ #include <target/target_core_base.h> #include <target/target_core_backend.h> #include <target/target_core_fabric.h> -#include <target/target_core_fabric_configfs.h> -#include <target/configfs_macros.h> #include <asm/unaligned.h> #include "sbp_target.h" @@ -2111,24 +2109,21 @@ static void sbp_drop_tport(struct se_wwn *wwn) kfree(tport); } -static ssize_t sbp_wwn_show_attr_version( - struct target_fabric_configfs *tf, - char *page) +static ssize_t sbp_wwn_version_show(struct config_item *item, char *page) { return sprintf(page, "FireWire SBP fabric module %s\n", SBP_VERSION); } -TF_WWN_ATTR_RO(sbp, version); +CONFIGFS_ATTR_RO(sbp_wwn_, version); static struct configfs_attribute *sbp_wwn_attrs[] = { - &sbp_wwn_version.attr, + &sbp_wwn_attr_version, NULL, }; -static ssize_t sbp_tpg_show_directory_id( - struct se_portal_group *se_tpg, - char *page) +static ssize_t sbp_tpg_directory_id_show(struct config_item *item, char *page) { + struct se_portal_group *se_tpg = to_tpg(item); struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg); struct sbp_tport *tport = tpg->tport; @@ -2138,11 +2133,10 @@ static ssize_t sbp_tpg_show_directory_id( return sprintf(page, "%06x\n", tport->directory_id); } -static ssize_t sbp_tpg_store_directory_id( - struct se_portal_group *se_tpg, - const char *page, - size_t count) +static ssize_t sbp_tpg_directory_id_store(struct config_item *item, + const char *page, size_t count) { + struct se_portal_group *se_tpg = to_tpg(item); struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg); struct sbp_tport *tport = tpg->tport; unsigned long val; @@ -2166,20 +2160,18 @@ static ssize_t sbp_tpg_store_directory_id( return count; } -static ssize_t sbp_tpg_show_enable( - struct se_portal_group *se_tpg, - char *page) +static ssize_t sbp_tpg_enable_show(struct config_item *item, char *page) { + struct se_portal_group *se_tpg = to_tpg(item); struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg); struct sbp_tport *tport = tpg->tport; return sprintf(page, "%d\n", tport->enable); } -static ssize_t sbp_tpg_store_enable( - struct se_portal_group *se_tpg, - const char *page, - size_t count) +static ssize_t sbp_tpg_enable_store(struct config_item *item, + const char *page, size_t count) { + struct se_portal_group *se_tpg = to_tpg(item); struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg); struct sbp_tport *tport = tpg->tport; unsigned long val; @@ -2219,29 +2211,28 @@ static ssize_t sbp_tpg_store_enable( return count; } -TF_TPG_BASE_ATTR(sbp, directory_id, S_IRUGO | S_IWUSR); -TF_TPG_BASE_ATTR(sbp, enable, S_IRUGO | S_IWUSR); +CONFIGFS_ATTR(sbp_tpg_, directory_id); +CONFIGFS_ATTR(sbp_tpg_, enable); static struct configfs_attribute *sbp_tpg_base_attrs[] = { - &sbp_tpg_directory_id.attr, - &sbp_tpg_enable.attr, + &sbp_tpg_attr_directory_id, + &sbp_tpg_attr_enable, NULL, }; -static ssize_t sbp_tpg_attrib_show_mgt_orb_timeout( - struct se_portal_group *se_tpg, +static ssize_t sbp_tpg_attrib_mgt_orb_timeout_show(struct config_item *item, char *page) { + struct se_portal_group *se_tpg = attrib_to_tpg(item); struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg); struct sbp_tport *tport = tpg->tport; return sprintf(page, "%d\n", tport->mgt_orb_timeout); } -static ssize_t sbp_tpg_attrib_store_mgt_orb_timeout( - struct se_portal_group *se_tpg, - const char *page, - size_t count) +static ssize_t sbp_tpg_attrib_mgt_orb_timeout_store(struct config_item *item, + const char *page, size_t count) { + struct se_portal_group *se_tpg = attrib_to_tpg(item); struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg); struct sbp_tport *tport = tpg->tport; unsigned long val; @@ -2264,20 +2255,19 @@ static ssize_t sbp_tpg_attrib_store_mgt_orb_timeout( return count; } -static ssize_t sbp_tpg_attrib_show_max_reconnect_timeout( - struct se_portal_group *se_tpg, +static ssize_t sbp_tpg_attrib_max_reconnect_timeout_show(struct config_item *item, char *page) { + struct se_portal_group *se_tpg = attrib_to_tpg(item); struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg); struct sbp_tport *tport = tpg->tport; return sprintf(page, "%d\n", tport->max_reconnect_timeout); } -static ssize_t sbp_tpg_attrib_store_max_reconnect_timeout( - struct se_portal_group *se_tpg, - const char *page, - size_t count) +static ssize_t sbp_tpg_attrib_max_reconnect_timeout_store(struct config_item *item, + const char *page, size_t count) { + struct se_portal_group *se_tpg = attrib_to_tpg(item); struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg); struct sbp_tport *tport = tpg->tport; unsigned long val; @@ -2300,20 +2290,19 @@ static ssize_t sbp_tpg_attrib_store_max_reconnect_timeout( return count; } -static ssize_t sbp_tpg_attrib_show_max_logins_per_lun( - struct se_portal_group *se_tpg, +static ssize_t sbp_tpg_attrib_max_logins_per_lun_show(struct config_item *item, char *page) { + struct se_portal_group *se_tpg = attrib_to_tpg(item); struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg); struct sbp_tport *tport = tpg->tport; return sprintf(page, "%d\n", tport->max_logins_per_lun); } -static ssize_t sbp_tpg_attrib_store_max_logins_per_lun( - struct se_portal_group *se_tpg, - const char *page, - size_t count) +static ssize_t sbp_tpg_attrib_max_logins_per_lun_store(struct config_item *item, + const char *page, size_t count) { + struct se_portal_group *se_tpg = attrib_to_tpg(item); struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg); struct sbp_tport *tport = tpg->tport; unsigned long val; @@ -2330,14 +2319,14 @@ static ssize_t sbp_tpg_attrib_store_max_logins_per_lun( return count; } -TF_TPG_ATTRIB_ATTR(sbp, mgt_orb_timeout, S_IRUGO | S_IWUSR); -TF_TPG_ATTRIB_ATTR(sbp, max_reconnect_timeout, S_IRUGO | S_IWUSR); -TF_TPG_ATTRIB_ATTR(sbp, max_logins_per_lun, S_IRUGO | S_IWUSR); +CONFIGFS_ATTR(sbp_tpg_attrib_, mgt_orb_timeout); +CONFIGFS_ATTR(sbp_tpg_attrib_, max_reconnect_timeout); +CONFIGFS_ATTR(sbp_tpg_attrib_, max_logins_per_lun); static struct configfs_attribute *sbp_tpg_attrib_attrs[] = { - &sbp_tpg_attrib_mgt_orb_timeout.attr, - &sbp_tpg_attrib_max_reconnect_timeout.attr, - &sbp_tpg_attrib_max_logins_per_lun.attr, + &sbp_tpg_attrib_attr_mgt_orb_timeout, + &sbp_tpg_attrib_attr_max_reconnect_timeout, + &sbp_tpg_attrib_attr_max_logins_per_lun, NULL, }; diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 860e84046177..b9b9ffde4c7a 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -40,8 +40,6 @@ #include <target/target_core_base.h> #include <target/target_core_backend.h> #include <target/target_core_fabric.h> -#include <target/target_core_fabric_configfs.h> -#include <target/configfs_macros.h> #include "target_core_internal.h" #include "target_core_alua.h" @@ -78,12 +76,6 @@ extern struct t10_alua_lu_gp *default_lu_gp; static LIST_HEAD(g_tf_list); static DEFINE_MUTEX(g_tf_lock); -struct target_core_configfs_attribute { - struct configfs_attribute attr; - ssize_t (*show)(void *, char *); - ssize_t (*store)(void *, const char *, size_t); -}; - static struct config_group target_core_hbagroup; static struct config_group alua_group; static struct config_group alua_lu_gps_group; @@ -97,24 +89,15 @@ item_to_hba(struct config_item *item) /* * Attributes for /sys/kernel/config/target/ */ -static ssize_t target_core_attr_show(struct config_item *item, - struct configfs_attribute *attr, - char *page) +static ssize_t target_core_item_version_show(struct config_item *item, + char *page) { return sprintf(page, "Target Engine Core ConfigFS Infrastructure %s" " on %s/%s on "UTS_RELEASE"\n", TARGET_CORE_VERSION, utsname()->sysname, utsname()->machine); } -static struct configfs_item_operations target_core_fabric_item_ops = { - .show_attribute = target_core_attr_show, -}; - -static struct configfs_attribute target_core_item_attr_version = { - .ca_owner = THIS_MODULE, - .ca_name = "version", - .ca_mode = S_IRUGO, -}; +CONFIGFS_ATTR_RO(target_core_item_, version); static struct target_fabric_configfs *target_core_get_fabric( const char *name) @@ -273,7 +256,6 @@ static struct configfs_attribute *target_core_fabric_item_attrs[] = { * Provides Fabrics Groups and Item Attributes for /sys/kernel/config/target/ */ static struct config_item_type target_core_fabrics_item = { - .ct_item_ops = &target_core_fabric_item_ops, .ct_group_ops = &target_core_fabric_group_ops, .ct_attrs = target_core_fabric_item_attrs, .ct_owner = THIS_MODULE, @@ -476,47 +458,54 @@ EXPORT_SYMBOL(target_unregister_template); // Stop functions called by external Target Fabrics Modules //############################################################################*/ +static inline struct se_dev_attrib *to_attrib(struct config_item *item) +{ + return container_of(to_config_group(item), struct se_dev_attrib, + da_group); +} + /* Start functions for struct config_item_type tb_dev_attrib_cit */ -#define DEF_TB_DEV_ATTRIB_SHOW(_name) \ -static ssize_t show_##_name(struct se_dev_attrib *da, char *page) \ +#define DEF_CONFIGFS_ATTRIB_SHOW(_name) \ +static ssize_t _name##_show(struct config_item *item, char *page) \ { \ - return snprintf(page, PAGE_SIZE, "%u\n", da->_name); \ -} - -DEF_TB_DEV_ATTRIB_SHOW(emulate_model_alias); -DEF_TB_DEV_ATTRIB_SHOW(emulate_dpo); -DEF_TB_DEV_ATTRIB_SHOW(emulate_fua_write); -DEF_TB_DEV_ATTRIB_SHOW(emulate_fua_read); -DEF_TB_DEV_ATTRIB_SHOW(emulate_write_cache); -DEF_TB_DEV_ATTRIB_SHOW(emulate_ua_intlck_ctrl); -DEF_TB_DEV_ATTRIB_SHOW(emulate_tas); -DEF_TB_DEV_ATTRIB_SHOW(emulate_tpu); -DEF_TB_DEV_ATTRIB_SHOW(emulate_tpws); -DEF_TB_DEV_ATTRIB_SHOW(emulate_caw); -DEF_TB_DEV_ATTRIB_SHOW(emulate_3pc); -DEF_TB_DEV_ATTRIB_SHOW(pi_prot_type); -DEF_TB_DEV_ATTRIB_SHOW(hw_pi_prot_type); -DEF_TB_DEV_ATTRIB_SHOW(pi_prot_format); -DEF_TB_DEV_ATTRIB_SHOW(enforce_pr_isids); -DEF_TB_DEV_ATTRIB_SHOW(is_nonrot); -DEF_TB_DEV_ATTRIB_SHOW(emulate_rest_reord); -DEF_TB_DEV_ATTRIB_SHOW(force_pr_aptpl); -DEF_TB_DEV_ATTRIB_SHOW(hw_block_size); -DEF_TB_DEV_ATTRIB_SHOW(block_size); -DEF_TB_DEV_ATTRIB_SHOW(hw_max_sectors); -DEF_TB_DEV_ATTRIB_SHOW(optimal_sectors); -DEF_TB_DEV_ATTRIB_SHOW(hw_queue_depth); -DEF_TB_DEV_ATTRIB_SHOW(queue_depth); -DEF_TB_DEV_ATTRIB_SHOW(max_unmap_lba_count); -DEF_TB_DEV_ATTRIB_SHOW(max_unmap_block_desc_count); -DEF_TB_DEV_ATTRIB_SHOW(unmap_granularity); -DEF_TB_DEV_ATTRIB_SHOW(unmap_granularity_alignment); -DEF_TB_DEV_ATTRIB_SHOW(max_write_same_len); - -#define DEF_TB_DEV_ATTRIB_STORE_U32(_name) \ -static ssize_t store_##_name(struct se_dev_attrib *da, const char *page,\ + return snprintf(page, PAGE_SIZE, "%u\n", to_attrib(item)->_name); \ +} + +DEF_CONFIGFS_ATTRIB_SHOW(emulate_model_alias); +DEF_CONFIGFS_ATTRIB_SHOW(emulate_dpo); +DEF_CONFIGFS_ATTRIB_SHOW(emulate_fua_write); +DEF_CONFIGFS_ATTRIB_SHOW(emulate_fua_read); +DEF_CONFIGFS_ATTRIB_SHOW(emulate_write_cache); +DEF_CONFIGFS_ATTRIB_SHOW(emulate_ua_intlck_ctrl); +DEF_CONFIGFS_ATTRIB_SHOW(emulate_tas); +DEF_CONFIGFS_ATTRIB_SHOW(emulate_tpu); +DEF_CONFIGFS_ATTRIB_SHOW(emulate_tpws); +DEF_CONFIGFS_ATTRIB_SHOW(emulate_caw); +DEF_CONFIGFS_ATTRIB_SHOW(emulate_3pc); +DEF_CONFIGFS_ATTRIB_SHOW(pi_prot_type); +DEF_CONFIGFS_ATTRIB_SHOW(hw_pi_prot_type); +DEF_CONFIGFS_ATTRIB_SHOW(pi_prot_format); +DEF_CONFIGFS_ATTRIB_SHOW(enforce_pr_isids); +DEF_CONFIGFS_ATTRIB_SHOW(is_nonrot); +DEF_CONFIGFS_ATTRIB_SHOW(emulate_rest_reord); +DEF_CONFIGFS_ATTRIB_SHOW(force_pr_aptpl); +DEF_CONFIGFS_ATTRIB_SHOW(hw_block_size); +DEF_CONFIGFS_ATTRIB_SHOW(block_size); +DEF_CONFIGFS_ATTRIB_SHOW(hw_max_sectors); +DEF_CONFIGFS_ATTRIB_SHOW(optimal_sectors); +DEF_CONFIGFS_ATTRIB_SHOW(hw_queue_depth); +DEF_CONFIGFS_ATTRIB_SHOW(queue_depth); +DEF_CONFIGFS_ATTRIB_SHOW(max_unmap_lba_count); +DEF_CONFIGFS_ATTRIB_SHOW(max_unmap_block_desc_count); +DEF_CONFIGFS_ATTRIB_SHOW(unmap_granularity); +DEF_CONFIGFS_ATTRIB_SHOW(unmap_granularity_alignment); +DEF_CONFIGFS_ATTRIB_SHOW(max_write_same_len); + +#define DEF_CONFIGFS_ATTRIB_STORE_U32(_name) \ +static ssize_t _name##_store(struct config_item *item, const char *page,\ size_t count) \ { \ + struct se_dev_attrib *da = to_attrib(item); \ u32 val; \ int ret; \ \ @@ -527,16 +516,17 @@ static ssize_t store_##_name(struct se_dev_attrib *da, const char *page,\ return count; \ } -DEF_TB_DEV_ATTRIB_STORE_U32(max_unmap_lba_count); -DEF_TB_DEV_ATTRIB_STORE_U32(max_unmap_block_desc_count); -DEF_TB_DEV_ATTRIB_STORE_U32(unmap_granularity); -DEF_TB_DEV_ATTRIB_STORE_U32(unmap_granularity_alignment); -DEF_TB_DEV_ATTRIB_STORE_U32(max_write_same_len); +DEF_CONFIGFS_ATTRIB_STORE_U32(max_unmap_lba_count); +DEF_CONFIGFS_ATTRIB_STORE_U32(max_unmap_block_desc_count); +DEF_CONFIGFS_ATTRIB_STORE_U32(unmap_granularity); +DEF_CONFIGFS_ATTRIB_STORE_U32(unmap_granularity_alignment); +DEF_CONFIGFS_ATTRIB_STORE_U32(max_write_same_len); -#define DEF_TB_DEV_ATTRIB_STORE_BOOL(_name) \ -static ssize_t store_##_name(struct se_dev_attrib *da, const char *page,\ +#define DEF_CONFIGFS_ATTRIB_STORE_BOOL(_name) \ +static ssize_t _name##_store(struct config_item *item, const char *page, \ size_t count) \ { \ + struct se_dev_attrib *da = to_attrib(item); \ bool flag; \ int ret; \ \ @@ -547,14 +537,14 @@ static ssize_t store_##_name(struct se_dev_attrib *da, const char *page,\ return count; \ } -DEF_TB_DEV_ATTRIB_STORE_BOOL(emulate_fua_write); -DEF_TB_DEV_ATTRIB_STORE_BOOL(emulate_caw); -DEF_TB_DEV_ATTRIB_STORE_BOOL(emulate_3pc); -DEF_TB_DEV_ATTRIB_STORE_BOOL(enforce_pr_isids); -DEF_TB_DEV_ATTRIB_STORE_BOOL(is_nonrot); +DEF_CONFIGFS_ATTRIB_STORE_BOOL(emulate_fua_write); +DEF_CONFIGFS_ATTRIB_STORE_BOOL(emulate_caw); +DEF_CONFIGFS_ATTRIB_STORE_BOOL(emulate_3pc); +DEF_CONFIGFS_ATTRIB_STORE_BOOL(enforce_pr_isids); +DEF_CONFIGFS_ATTRIB_STORE_BOOL(is_nonrot); -#define DEF_TB_DEV_ATTRIB_STORE_STUB(_name) \ -static ssize_t store_##_name(struct se_dev_attrib *da, const char *page,\ +#define DEF_CONFIGFS_ATTRIB_STORE_STUB(_name) \ +static ssize_t _name##_store(struct config_item *item, const char *page,\ size_t count) \ { \ printk_once(KERN_WARNING \ @@ -562,8 +552,8 @@ static ssize_t store_##_name(struct se_dev_attrib *da, const char *page,\ return count; \ } -DEF_TB_DEV_ATTRIB_STORE_STUB(emulate_dpo); -DEF_TB_DEV_ATTRIB_STORE_STUB(emulate_fua_read); +DEF_CONFIGFS_ATTRIB_STORE_STUB(emulate_dpo); +DEF_CONFIGFS_ATTRIB_STORE_STUB(emulate_fua_read); static void dev_set_t10_wwn_model_alias(struct se_device *dev) { @@ -578,9 +568,10 @@ static void dev_set_t10_wwn_model_alias(struct se_device *dev) snprintf(&dev->t10_wwn.model[0], 16, "%s", configname); } -static ssize_t store_emulate_model_alias(struct se_dev_attrib *da, +static ssize_t emulate_model_alias_store(struct config_item *item, const char *page, size_t count) { + struct se_dev_attrib *da = to_attrib(item); struct se_device *dev = da->da_dev; bool flag; int ret; @@ -606,9 +597,10 @@ static ssize_t store_emulate_model_alias(struct se_dev_attrib *da, return count; } -static ssize_t store_emulate_write_cache(struct se_dev_attrib *da, +static ssize_t emulate_write_cache_store(struct config_item *item, const char *page, size_t count) { + struct se_dev_attrib *da = to_attrib(item); bool flag; int ret; @@ -627,9 +619,10 @@ static ssize_t store_emulate_write_cache(struct se_dev_attrib *da, return count; } -static ssize_t store_emulate_ua_intlck_ctrl(struct se_dev_attrib *da, +static ssize_t emulate_ua_intlck_ctrl_store(struct config_item *item, const char *page, size_t count) { + struct se_dev_attrib *da = to_attrib(item); u32 val; int ret; @@ -654,9 +647,10 @@ static ssize_t store_emulate_ua_intlck_ctrl(struct se_dev_attrib *da, return count; } -static ssize_t store_emulate_tas(struct se_dev_attrib *da, +static ssize_t emulate_tas_store(struct config_item *item, const char *page, size_t count) { + struct se_dev_attrib *da = to_attrib(item); bool flag; int ret; @@ -677,9 +671,10 @@ static ssize_t store_emulate_tas(struct se_dev_attrib *da, return count; } -static ssize_t store_emulate_tpu(struct se_dev_attrib *da, +static ssize_t emulate_tpu_store(struct config_item *item, const char *page, size_t count) { + struct se_dev_attrib *da = to_attrib(item); bool flag; int ret; @@ -702,9 +697,10 @@ static ssize_t store_emulate_tpu(struct se_dev_attrib *da, return count; } -static ssize_t store_emulate_tpws(struct se_dev_attrib *da, +static ssize_t emulate_tpws_store(struct config_item *item, const char *page, size_t count) { + struct se_dev_attrib *da = to_attrib(item); bool flag; int ret; @@ -727,9 +723,10 @@ static ssize_t store_emulate_tpws(struct se_dev_attrib *da, return count; } -static ssize_t store_pi_prot_type(struct se_dev_attrib *da, +static ssize_t pi_prot_type_store(struct config_item *item, const char *page, size_t count) { + struct se_dev_attrib *da = to_attrib(item); int old_prot = da->pi_prot_type, ret; struct se_device *dev = da->da_dev; u32 flag; @@ -787,9 +784,10 @@ static ssize_t store_pi_prot_type(struct se_dev_attrib *da, return count; } -static ssize_t store_pi_prot_format(struct se_dev_attrib *da, +static ssize_t pi_prot_format_store(struct config_item *item, const char *page, size_t count) { + struct se_dev_attrib *da = to_attrib(item); struct se_device *dev = da->da_dev; bool flag; int ret; @@ -824,9 +822,10 @@ static ssize_t store_pi_prot_format(struct se_dev_attrib *da, return count; } -static ssize_t store_force_pr_aptpl(struct se_dev_attrib *da, +static ssize_t force_pr_aptpl_store(struct config_item *item, const char *page, size_t count) { + struct se_dev_attrib *da = to_attrib(item); bool flag; int ret; @@ -845,9 +844,10 @@ static ssize_t store_force_pr_aptpl(struct se_dev_attrib *da, return count; } -static ssize_t store_emulate_rest_reord(struct se_dev_attrib *da, +static ssize_t emulate_rest_reord_store(struct config_item *item, const char *page, size_t count) { + struct se_dev_attrib *da = to_attrib(item); bool flag; int ret; @@ -869,9 +869,10 @@ static ssize_t store_emulate_rest_reord(struct se_dev_attrib *da, /* * Note, this can only be called on unexported SE Device Object. */ -static ssize_t store_queue_depth(struct se_dev_attrib *da, +static ssize_t queue_depth_store(struct config_item *item, const char *page, size_t count) { + struct se_dev_attrib *da = to_attrib(item); struct se_device *dev = da->da_dev; u32 val; int ret; @@ -905,9 +906,10 @@ static ssize_t store_queue_depth(struct se_dev_attrib *da, return count; } -static ssize_t store_optimal_sectors(struct se_dev_attrib *da, +static ssize_t optimal_sectors_store(struct config_item *item, const char *page, size_t count) { + struct se_dev_attrib *da = to_attrib(item); u32 val; int ret; @@ -934,9 +936,10 @@ static ssize_t store_optimal_sectors(struct se_dev_attrib *da, return count; } -static ssize_t store_block_size(struct se_dev_attrib *da, +static ssize_t block_size_store(struct config_item *item, const char *page, size_t count) { + struct se_dev_attrib *da = to_attrib(item); u32 val; int ret; @@ -967,50 +970,35 @@ static ssize_t store_block_size(struct se_dev_attrib *da, return count; } -CONFIGFS_EATTR_STRUCT(target_backend_dev_attrib, se_dev_attrib); -#define TB_DEV_ATTR(_backend, _name, _mode) \ -static struct target_backend_dev_attrib_attribute _backend##_dev_attrib_##_name = \ - __CONFIGFS_EATTR(_name, _mode, \ - show_##_name, \ - store_##_name); - -#define TB_DEV_ATTR_RO(_backend, _name) \ -static struct target_backend_dev_attrib_attribute _backend##_dev_attrib_##_name = \ - __CONFIGFS_EATTR_RO(_name, \ - show_##_name); - -TB_DEV_ATTR(target_core, emulate_model_alias, S_IRUGO | S_IWUSR); -TB_DEV_ATTR(target_core, emulate_dpo, S_IRUGO | S_IWUSR); -TB_DEV_ATTR(target_core, emulate_fua_write, S_IRUGO | S_IWUSR); -TB_DEV_ATTR(target_core, emulate_fua_read, S_IRUGO | S_IWUSR); -TB_DEV_ATTR(target_core, emulate_write_cache, S_IRUGO | S_IWUSR); -TB_DEV_ATTR(target_core, emulate_ua_intlck_ctrl, S_IRUGO | S_IWUSR); -TB_DEV_ATTR(target_core, emulate_tas, S_IRUGO | S_IWUSR); -TB_DEV_ATTR(target_core, emulate_tpu, S_IRUGO | S_IWUSR); -TB_DEV_ATTR(target_core, emulate_tpws, S_IRUGO | S_IWUSR); -TB_DEV_ATTR(target_core, emulate_caw, S_IRUGO | S_IWUSR); -TB_DEV_ATTR(target_core, emulate_3pc, S_IRUGO | S_IWUSR); -TB_DEV_ATTR(target_core, pi_prot_type, S_IRUGO | S_IWUSR); -TB_DEV_ATTR_RO(target_core, hw_pi_prot_type); -TB_DEV_ATTR(target_core, pi_prot_format, S_IRUGO | S_IWUSR); -TB_DEV_ATTR(target_core, enforce_pr_isids, S_IRUGO | S_IWUSR); -TB_DEV_ATTR(target_core, is_nonrot, S_IRUGO | S_IWUSR); -TB_DEV_ATTR(target_core, emulate_rest_reord, S_IRUGO | S_IWUSR); -TB_DEV_ATTR(target_core, force_pr_aptpl, S_IRUGO | S_IWUSR) -TB_DEV_ATTR_RO(target_core, hw_block_size); -TB_DEV_ATTR(target_core, block_size, S_IRUGO | S_IWUSR) -TB_DEV_ATTR_RO(target_core, hw_max_sectors); -TB_DEV_ATTR(target_core, optimal_sectors, S_IRUGO | S_IWUSR); -TB_DEV_ATTR_RO(target_core, hw_queue_depth); -TB_DEV_ATTR(target_core, queue_depth, S_IRUGO | S_IWUSR); -TB_DEV_ATTR(target_core, max_unmap_lba_count, S_IRUGO | S_IWUSR); -TB_DEV_ATTR(target_core, max_unmap_block_desc_count, S_IRUGO | S_IWUSR); -TB_DEV_ATTR(target_core, unmap_granularity, S_IRUGO | S_IWUSR); -TB_DEV_ATTR(target_core, unmap_granularity_alignment, S_IRUGO | S_IWUSR); -TB_DEV_ATTR(target_core, max_write_same_len, S_IRUGO | S_IWUSR); - -CONFIGFS_EATTR_STRUCT(target_core_dev_attrib, se_dev_attrib); -CONFIGFS_EATTR_OPS(target_core_dev_attrib, se_dev_attrib, da_group); +CONFIGFS_ATTR(, emulate_model_alias); +CONFIGFS_ATTR(, emulate_dpo); +CONFIGFS_ATTR(, emulate_fua_write); +CONFIGFS_ATTR(, emulate_fua_read); +CONFIGFS_ATTR(, emulate_write_cache); +CONFIGFS_ATTR(, emulate_ua_intlck_ctrl); +CONFIGFS_ATTR(, emulate_tas); +CONFIGFS_ATTR(, emulate_tpu); +CONFIGFS_ATTR(, emulate_tpws); +CONFIGFS_ATTR(, emulate_caw); +CONFIGFS_ATTR(, emulate_3pc); +CONFIGFS_ATTR(, pi_prot_type); +CONFIGFS_ATTR_RO(, hw_pi_prot_type); +CONFIGFS_ATTR(, pi_prot_format); +CONFIGFS_ATTR(, enforce_pr_isids); +CONFIGFS_ATTR(, is_nonrot); +CONFIGFS_ATTR(, emulate_rest_reord); +CONFIGFS_ATTR(, force_pr_aptpl); +CONFIGFS_ATTR_RO(, hw_block_size); +CONFIGFS_ATTR(, block_size); +CONFIGFS_ATTR_RO(, hw_max_sectors); +CONFIGFS_ATTR(, optimal_sectors); +CONFIGFS_ATTR_RO(, hw_queue_depth); +CONFIGFS_ATTR(, queue_depth); +CONFIGFS_ATTR(, max_unmap_lba_count); +CONFIGFS_ATTR(, max_unmap_block_desc_count); +CONFIGFS_ATTR(, unmap_granularity); +CONFIGFS_ATTR(, unmap_granularity_alignment); +CONFIGFS_ATTR(, max_write_same_len); /* * dev_attrib attributes for devices using the target core SBC/SPC @@ -1018,100 +1006,78 @@ CONFIGFS_EATTR_OPS(target_core_dev_attrib, se_dev_attrib, da_group); * these. */ struct configfs_attribute *sbc_attrib_attrs[] = { - &target_core_dev_attrib_emulate_model_alias.attr, - &target_core_dev_attrib_emulate_dpo.attr, - &target_core_dev_attrib_emulate_fua_write.attr, - &target_core_dev_attrib_emulate_fua_read.attr, - &target_core_dev_attrib_emulate_write_cache.attr, - &target_core_dev_attrib_emulate_ua_intlck_ctrl.attr, - &target_core_dev_attrib_emulate_tas.attr, - &target_core_dev_attrib_emulate_tpu.attr, - &target_core_dev_attrib_emulate_tpws.attr, - &target_core_dev_attrib_emulate_caw.attr, - &target_core_dev_attrib_emulate_3pc.attr, - &target_core_dev_attrib_pi_prot_type.attr, - &target_core_dev_attrib_hw_pi_prot_type.attr, - &target_core_dev_attrib_pi_prot_format.attr, - &target_core_dev_attrib_enforce_pr_isids.attr, - &target_core_dev_attrib_is_nonrot.attr, - &target_core_dev_attrib_emulate_rest_reord.attr, - &target_core_dev_attrib_force_pr_aptpl.attr, - &target_core_dev_attrib_hw_block_size.attr, - &target_core_dev_attrib_block_size.attr, - &target_core_dev_attrib_hw_max_sectors.attr, - &target_core_dev_attrib_optimal_sectors.attr, - &target_core_dev_attrib_hw_queue_depth.attr, - &target_core_dev_attrib_queue_depth.attr, - &target_core_dev_attrib_max_unmap_lba_count.attr, - &target_core_dev_attrib_max_unmap_block_desc_count.attr, - &target_core_dev_attrib_unmap_granularity.attr, - &target_core_dev_attrib_unmap_granularity_alignment.attr, - &target_core_dev_attrib_max_write_same_len.attr, + &attr_emulate_model_alias, + &attr_emulate_dpo, + &attr_emulate_fua_write, + &attr_emulate_fua_read, + &attr_emulate_write_cache, + &attr_emulate_ua_intlck_ctrl, + &attr_emulate_tas, + &attr_emulate_tpu, + &attr_emulate_tpws, + &attr_emulate_caw, + &attr_emulate_3pc, + &attr_pi_prot_type, + &attr_hw_pi_prot_type, + &attr_pi_prot_format, + &attr_enforce_pr_isids, + &attr_is_nonrot, + &attr_emulate_rest_reord, + &attr_force_pr_aptpl, + &attr_hw_block_size, + &attr_block_size, + &attr_hw_max_sectors, + &attr_optimal_sectors, + &attr_hw_queue_depth, + &attr_queue_depth, + &attr_max_unmap_lba_count, + &attr_max_unmap_block_desc_count, + &attr_unmap_granularity, + &attr_unmap_granularity_alignment, + &attr_max_write_same_len, NULL, }; EXPORT_SYMBOL(sbc_attrib_attrs); -TB_DEV_ATTR_RO(target_pt, hw_pi_prot_type); -TB_DEV_ATTR_RO(target_pt, hw_block_size); -TB_DEV_ATTR_RO(target_pt, hw_max_sectors); -TB_DEV_ATTR_RO(target_pt, hw_queue_depth); - /* * Minimal dev_attrib attributes for devices passing through CDBs. * In this case we only provide a few read-only attributes for * backwards compatibility. */ struct configfs_attribute *passthrough_attrib_attrs[] = { - &target_pt_dev_attrib_hw_pi_prot_type.attr, - &target_pt_dev_attrib_hw_block_size.attr, - &target_pt_dev_attrib_hw_max_sectors.attr, - &target_pt_dev_attrib_hw_queue_depth.attr, + &attr_hw_pi_prot_type, + &attr_hw_block_size, + &attr_hw_max_sectors, + &attr_hw_queue_depth, NULL, }; EXPORT_SYMBOL(passthrough_attrib_attrs); -static struct configfs_item_operations target_core_dev_attrib_ops = { - .show_attribute = target_core_dev_attrib_attr_show, - .store_attribute = target_core_dev_attrib_attr_store, -}; - -TB_CIT_SETUP_DRV(dev_attrib, &target_core_dev_attrib_ops, NULL); +TB_CIT_SETUP_DRV(dev_attrib, NULL, NULL); /* End functions for struct config_item_type tb_dev_attrib_cit */ /* Start functions for struct config_item_type tb_dev_wwn_cit */ -CONFIGFS_EATTR_STRUCT(target_core_dev_wwn, t10_wwn); -#define SE_DEV_WWN_ATTR(_name, _mode) \ -static struct target_core_dev_wwn_attribute target_core_dev_wwn_##_name = \ - __CONFIGFS_EATTR(_name, _mode, \ - target_core_dev_wwn_show_attr_##_name, \ - target_core_dev_wwn_store_attr_##_name); - -#define SE_DEV_WWN_ATTR_RO(_name); \ -do { \ - static struct target_core_dev_wwn_attribute \ - target_core_dev_wwn_##_name = \ - __CONFIGFS_EATTR_RO(_name, \ - target_core_dev_wwn_show_attr_##_name); \ -} while (0); +static struct t10_wwn *to_t10_wwn(struct config_item *item) +{ + return container_of(to_config_group(item), struct t10_wwn, t10_wwn_group); +} /* * VPD page 0x80 Unit serial */ -static ssize_t target_core_dev_wwn_show_attr_vpd_unit_serial( - struct t10_wwn *t10_wwn, - char *page) +static ssize_t target_wwn_vpd_unit_serial_show(struct config_item *item, + char *page) { return sprintf(page, "T10 VPD Unit Serial Number: %s\n", - &t10_wwn->unit_serial[0]); + &to_t10_wwn(item)->unit_serial[0]); } -static ssize_t target_core_dev_wwn_store_attr_vpd_unit_serial( - struct t10_wwn *t10_wwn, - const char *page, - size_t count) +static ssize_t target_wwn_vpd_unit_serial_store(struct config_item *item, + const char *page, size_t count) { + struct t10_wwn *t10_wwn = to_t10_wwn(item); struct se_device *dev = t10_wwn->t10_dev; unsigned char buf[INQUIRY_VPD_SERIAL_LEN]; @@ -1167,15 +1133,13 @@ static ssize_t target_core_dev_wwn_store_attr_vpd_unit_serial( return count; } -SE_DEV_WWN_ATTR(vpd_unit_serial, S_IRUGO | S_IWUSR); - /* * VPD page 0x83 Protocol Identifier */ -static ssize_t target_core_dev_wwn_show_attr_vpd_protocol_identifier( - struct t10_wwn *t10_wwn, - char *page) +static ssize_t target_wwn_vpd_protocol_identifier_show(struct config_item *item, + char *page) { + struct t10_wwn *t10_wwn = to_t10_wwn(item); struct t10_vpd *vpd; unsigned char buf[VPD_TMP_BUF_SIZE]; ssize_t len = 0; @@ -1199,25 +1163,15 @@ static ssize_t target_core_dev_wwn_show_attr_vpd_protocol_identifier( return len; } -static ssize_t target_core_dev_wwn_store_attr_vpd_protocol_identifier( - struct t10_wwn *t10_wwn, - const char *page, - size_t count) -{ - return -ENOSYS; -} - -SE_DEV_WWN_ATTR(vpd_protocol_identifier, S_IRUGO | S_IWUSR); - /* * Generic wrapper for dumping VPD identifiers by association. */ #define DEF_DEV_WWN_ASSOC_SHOW(_name, _assoc) \ -static ssize_t target_core_dev_wwn_show_attr_##_name( \ - struct t10_wwn *t10_wwn, \ - char *page) \ +static ssize_t target_wwn_##_name##_show(struct config_item *item, \ + char *page) \ { \ - struct t10_vpd *vpd; \ + struct t10_wwn *t10_wwn = to_t10_wwn(item); \ + struct t10_vpd *vpd; \ unsigned char buf[VPD_TMP_BUF_SIZE]; \ ssize_t len = 0; \ \ @@ -1249,84 +1203,39 @@ static ssize_t target_core_dev_wwn_show_attr_##_name( \ return len; \ } -/* - * VPD page 0x83 Association: Logical Unit - */ +/* VPD page 0x83 Association: Logical Unit */ DEF_DEV_WWN_ASSOC_SHOW(vpd_assoc_logical_unit, 0x00); - -static ssize_t target_core_dev_wwn_store_attr_vpd_assoc_logical_unit( - struct t10_wwn *t10_wwn, - const char *page, - size_t count) -{ - return -ENOSYS; -} - -SE_DEV_WWN_ATTR(vpd_assoc_logical_unit, S_IRUGO | S_IWUSR); - -/* - * VPD page 0x83 Association: Target Port - */ +/* VPD page 0x83 Association: Target Port */ DEF_DEV_WWN_ASSOC_SHOW(vpd_assoc_target_port, 0x10); - -static ssize_t target_core_dev_wwn_store_attr_vpd_assoc_target_port( - struct t10_wwn *t10_wwn, - const char *page, - size_t count) -{ - return -ENOSYS; -} - -SE_DEV_WWN_ATTR(vpd_assoc_target_port, S_IRUGO | S_IWUSR); - -/* - * VPD page 0x83 Association: SCSI Target Device - */ +/* VPD page 0x83 Association: SCSI Target Device */ DEF_DEV_WWN_ASSOC_SHOW(vpd_assoc_scsi_target_device, 0x20); -static ssize_t target_core_dev_wwn_store_attr_vpd_assoc_scsi_target_device( - struct t10_wwn *t10_wwn, - const char *page, - size_t count) -{ - return -ENOSYS; -} - -SE_DEV_WWN_ATTR(vpd_assoc_scsi_target_device, S_IRUGO | S_IWUSR); - -CONFIGFS_EATTR_OPS(target_core_dev_wwn, t10_wwn, t10_wwn_group); +CONFIGFS_ATTR(target_wwn_, vpd_unit_serial); +CONFIGFS_ATTR_RO(target_wwn_, vpd_protocol_identifier); +CONFIGFS_ATTR_RO(target_wwn_, vpd_assoc_logical_unit); +CONFIGFS_ATTR_RO(target_wwn_, vpd_assoc_target_port); +CONFIGFS_ATTR_RO(target_wwn_, vpd_assoc_scsi_target_device); static struct configfs_attribute *target_core_dev_wwn_attrs[] = { - &target_core_dev_wwn_vpd_unit_serial.attr, - &target_core_dev_wwn_vpd_protocol_identifier.attr, - &target_core_dev_wwn_vpd_assoc_logical_unit.attr, - &target_core_dev_wwn_vpd_assoc_target_port.attr, - &target_core_dev_wwn_vpd_assoc_scsi_target_device.attr, + &target_wwn_attr_vpd_unit_serial, + &target_wwn_attr_vpd_protocol_identifier, + &target_wwn_attr_vpd_assoc_logical_unit, + &target_wwn_attr_vpd_assoc_target_port, + &target_wwn_attr_vpd_assoc_scsi_target_device, NULL, }; -static struct configfs_item_operations target_core_dev_wwn_ops = { - .show_attribute = target_core_dev_wwn_attr_show, - .store_attribute = target_core_dev_wwn_attr_store, -}; - -TB_CIT_SETUP(dev_wwn, &target_core_dev_wwn_ops, NULL, target_core_dev_wwn_attrs); +TB_CIT_SETUP(dev_wwn, NULL, NULL, target_core_dev_wwn_attrs); /* End functions for struct config_item_type tb_dev_wwn_cit */ /* Start functions for struct config_item_type tb_dev_pr_cit */ -CONFIGFS_EATTR_STRUCT(target_core_dev_pr, se_device); -#define SE_DEV_PR_ATTR(_name, _mode) \ -static struct target_core_dev_pr_attribute target_core_dev_pr_##_name = \ - __CONFIGFS_EATTR(_name, _mode, \ - target_core_dev_pr_show_attr_##_name, \ - target_core_dev_pr_store_attr_##_name); - -#define SE_DEV_PR_ATTR_RO(_name); \ -static struct target_core_dev_pr_attribute target_core_dev_pr_##_name = \ - __CONFIGFS_EATTR_RO(_name, \ - target_core_dev_pr_show_attr_##_name); +static struct se_device *pr_to_dev(struct config_item *item) +{ + return container_of(to_config_group(item), struct se_device, + dev_pr_group); +} static ssize_t target_core_dev_pr_show_spc3_res(struct se_device *dev, char *page) @@ -1367,9 +1276,9 @@ static ssize_t target_core_dev_pr_show_spc2_res(struct se_device *dev, return len; } -static ssize_t target_core_dev_pr_show_attr_res_holder(struct se_device *dev, - char *page) +static ssize_t target_pr_res_holder_show(struct config_item *item, char *page) { + struct se_device *dev = pr_to_dev(item); int ret; if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH) @@ -1384,11 +1293,10 @@ static ssize_t target_core_dev_pr_show_attr_res_holder(struct se_device *dev, return ret; } -SE_DEV_PR_ATTR_RO(res_holder); - -static ssize_t target_core_dev_pr_show_attr_res_pr_all_tgt_pts( - struct se_device *dev, char *page) +static ssize_t target_pr_res_pr_all_tgt_pts_show(struct config_item *item, + char *page) { + struct se_device *dev = pr_to_dev(item); ssize_t len = 0; spin_lock(&dev->dev_reservation_lock); @@ -1406,22 +1314,17 @@ static ssize_t target_core_dev_pr_show_attr_res_pr_all_tgt_pts( return len; } -SE_DEV_PR_ATTR_RO(res_pr_all_tgt_pts); - -static ssize_t target_core_dev_pr_show_attr_res_pr_generation( - struct se_device *dev, char *page) +static ssize_t target_pr_res_pr_generation_show(struct config_item *item, + char *page) { - return sprintf(page, "0x%08x\n", dev->t10_pr.pr_generation); + return sprintf(page, "0x%08x\n", pr_to_dev(item)->t10_pr.pr_generation); } -SE_DEV_PR_ATTR_RO(res_pr_generation); -/* - * res_pr_holder_tg_port - */ -static ssize_t target_core_dev_pr_show_attr_res_pr_holder_tg_port( - struct se_device *dev, char *page) +static ssize_t target_pr_res_pr_holder_tg_port_show(struct config_item *item, + char *page) { + struct se_device *dev = pr_to_dev(item); struct se_node_acl *se_nacl; struct se_portal_group *se_tpg; struct t10_pr_registration *pr_reg; @@ -1453,11 +1356,11 @@ out_unlock: return len; } -SE_DEV_PR_ATTR_RO(res_pr_holder_tg_port); -static ssize_t target_core_dev_pr_show_attr_res_pr_registered_i_pts( - struct se_device *dev, char *page) +static ssize_t target_pr_res_pr_registered_i_pts_show(struct config_item *item, + char *page) { + struct se_device *dev = pr_to_dev(item); const struct target_core_fabric_ops *tfo; struct t10_pr_registration *pr_reg; unsigned char buf[384]; @@ -1495,11 +1398,9 @@ static ssize_t target_core_dev_pr_show_attr_res_pr_registered_i_pts( return len; } -SE_DEV_PR_ATTR_RO(res_pr_registered_i_pts); - -static ssize_t target_core_dev_pr_show_attr_res_pr_type( - struct se_device *dev, char *page) +static ssize_t target_pr_res_pr_type_show(struct config_item *item, char *page) { + struct se_device *dev = pr_to_dev(item); struct t10_pr_registration *pr_reg; ssize_t len = 0; @@ -1516,11 +1417,10 @@ static ssize_t target_core_dev_pr_show_attr_res_pr_type( return len; } -SE_DEV_PR_ATTR_RO(res_pr_type); - -static ssize_t target_core_dev_pr_show_attr_res_type( - struct se_device *dev, char *page) +static ssize_t target_pr_res_type_show(struct config_item *item, char *page) { + struct se_device *dev = pr_to_dev(item); + if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH) return sprintf(page, "SPC_PASSTHROUGH\n"); else if (dev->dev_reservation_flags & DRF_SPC2_RESERVATIONS) @@ -1529,11 +1429,11 @@ static ssize_t target_core_dev_pr_show_attr_res_type( return sprintf(page, "SPC3_PERSISTENT_RESERVATIONS\n"); } -SE_DEV_PR_ATTR_RO(res_type); - -static ssize_t target_core_dev_pr_show_attr_res_aptpl_active( - struct se_device *dev, char *page) +static ssize_t target_pr_res_aptpl_active_show(struct config_item *item, + char *page) { + struct se_device *dev = pr_to_dev(item); + if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH) return 0; @@ -1541,14 +1441,11 @@ static ssize_t target_core_dev_pr_show_attr_res_aptpl_active( (dev->t10_pr.pr_aptpl_active) ? "Activated" : "Disabled"); } -SE_DEV_PR_ATTR_RO(res_aptpl_active); - -/* - * res_aptpl_metadata - */ -static ssize_t target_core_dev_pr_show_attr_res_aptpl_metadata( - struct se_device *dev, char *page) +static ssize_t target_pr_res_aptpl_metadata_show(struct config_item *item, + char *page) { + struct se_device *dev = pr_to_dev(item); + if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH) return 0; @@ -1580,11 +1477,10 @@ static match_table_t tokens = { {Opt_err, NULL} }; -static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata( - struct se_device *dev, - const char *page, - size_t count) +static ssize_t target_pr_res_aptpl_metadata_store(struct config_item *item, + const char *page, size_t count) { + struct se_device *dev = pr_to_dev(item); unsigned char *i_fabric = NULL, *i_port = NULL, *isid = NULL; unsigned char *t_fabric = NULL, *t_port = NULL; char *orig, *ptr, *opts; @@ -1765,37 +1661,44 @@ out: return (ret == 0) ? count : ret; } -SE_DEV_PR_ATTR(res_aptpl_metadata, S_IRUGO | S_IWUSR); -CONFIGFS_EATTR_OPS(target_core_dev_pr, se_device, dev_pr_group); +CONFIGFS_ATTR_RO(target_pr_, res_holder); +CONFIGFS_ATTR_RO(target_pr_, res_pr_all_tgt_pts); +CONFIGFS_ATTR_RO(target_pr_, res_pr_generation); +CONFIGFS_ATTR_RO(target_pr_, res_pr_holder_tg_port); +CONFIGFS_ATTR_RO(target_pr_, res_pr_registered_i_pts); +CONFIGFS_ATTR_RO(target_pr_, res_pr_type); +CONFIGFS_ATTR_RO(target_pr_, res_type); +CONFIGFS_ATTR_RO(target_pr_, res_aptpl_active); +CONFIGFS_ATTR(target_pr_, res_aptpl_metadata); static struct configfs_attribute *target_core_dev_pr_attrs[] = { - &target_core_dev_pr_res_holder.attr, - &target_core_dev_pr_res_pr_all_tgt_pts.attr, - &target_core_dev_pr_res_pr_generation.attr, - &target_core_dev_pr_res_pr_holder_tg_port.attr, - &target_core_dev_pr_res_pr_registered_i_pts.attr, - &target_core_dev_pr_res_pr_type.attr, - &target_core_dev_pr_res_type.attr, - &target_core_dev_pr_res_aptpl_active.attr, - &target_core_dev_pr_res_aptpl_metadata.attr, + &target_pr_attr_res_holder, + &target_pr_attr_res_pr_all_tgt_pts, + &target_pr_attr_res_pr_generation, + &target_pr_attr_res_pr_holder_tg_port, + &target_pr_attr_res_pr_registered_i_pts, + &target_pr_attr_res_pr_type, + &target_pr_attr_res_type, + &target_pr_attr_res_aptpl_active, + &target_pr_attr_res_aptpl_metadata, NULL, }; -static struct configfs_item_operations target_core_dev_pr_ops = { - .show_attribute = target_core_dev_pr_attr_show, - .store_attribute = target_core_dev_pr_attr_store, -}; - -TB_CIT_SETUP(dev_pr, &target_core_dev_pr_ops, NULL, target_core_dev_pr_attrs); +TB_CIT_SETUP(dev_pr, NULL, NULL, target_core_dev_pr_attrs); /* End functions for struct config_item_type tb_dev_pr_cit */ /* Start functions for struct config_item_type tb_dev_cit */ -static ssize_t target_core_show_dev_info(void *p, char *page) +static inline struct se_device *to_device(struct config_item *item) +{ + return container_of(to_config_group(item), struct se_device, dev_group); +} + +static ssize_t target_dev_info_show(struct config_item *item, char *page) { - struct se_device *dev = p; + struct se_device *dev = to_device(item); int bl = 0; ssize_t read_bytes = 0; @@ -1806,35 +1709,17 @@ static ssize_t target_core_show_dev_info(void *p, char *page) return read_bytes; } -static struct target_core_configfs_attribute target_core_attr_dev_info = { - .attr = { .ca_owner = THIS_MODULE, - .ca_name = "info", - .ca_mode = S_IRUGO }, - .show = target_core_show_dev_info, - .store = NULL, -}; - -static ssize_t target_core_store_dev_control( - void *p, - const char *page, - size_t count) +static ssize_t target_dev_control_store(struct config_item *item, + const char *page, size_t count) { - struct se_device *dev = p; + struct se_device *dev = to_device(item); return dev->transport->set_configfs_dev_params(dev, page, count); } -static struct target_core_configfs_attribute target_core_attr_dev_control = { - .attr = { .ca_owner = THIS_MODULE, - .ca_name = "control", - .ca_mode = S_IWUSR }, - .show = NULL, - .store = target_core_store_dev_control, -}; - -static ssize_t target_core_show_dev_alias(void *p, char *page) +static ssize_t target_dev_alias_show(struct config_item *item, char *page) { - struct se_device *dev = p; + struct se_device *dev = to_device(item); if (!(dev->dev_flags & DF_USING_ALIAS)) return 0; @@ -1842,12 +1727,10 @@ static ssize_t target_core_show_dev_alias(void *p, char *page) return snprintf(page, PAGE_SIZE, "%s\n", dev->dev_alias); } -static ssize_t target_core_store_dev_alias( - void *p, - const char *page, - size_t count) +static ssize_t target_dev_alias_store(struct config_item *item, + const char *page, size_t count) { - struct se_device *dev = p; + struct se_device *dev = to_device(item); struct se_hba *hba = dev->se_hba; ssize_t read_bytes; @@ -1874,17 +1757,9 @@ static ssize_t target_core_store_dev_alias( return read_bytes; } -static struct target_core_configfs_attribute target_core_attr_dev_alias = { - .attr = { .ca_owner = THIS_MODULE, - .ca_name = "alias", - .ca_mode = S_IRUGO | S_IWUSR }, - .show = target_core_show_dev_alias, - .store = target_core_store_dev_alias, -}; - -static ssize_t target_core_show_dev_udev_path(void *p, char *page) +static ssize_t target_dev_udev_path_show(struct config_item *item, char *page) { - struct se_device *dev = p; + struct se_device *dev = to_device(item); if (!(dev->dev_flags & DF_USING_UDEV_PATH)) return 0; @@ -1892,12 +1767,10 @@ static ssize_t target_core_show_dev_udev_path(void *p, char *page) return snprintf(page, PAGE_SIZE, "%s\n", dev->udev_path); } -static ssize_t target_core_store_dev_udev_path( - void *p, - const char *page, - size_t count) +static ssize_t target_dev_udev_path_store(struct config_item *item, + const char *page, size_t count) { - struct se_device *dev = p; + struct se_device *dev = to_device(item); struct se_hba *hba = dev->se_hba; ssize_t read_bytes; @@ -1925,27 +1798,17 @@ static ssize_t target_core_store_dev_udev_path( return read_bytes; } -static struct target_core_configfs_attribute target_core_attr_dev_udev_path = { - .attr = { .ca_owner = THIS_MODULE, - .ca_name = "udev_path", - .ca_mode = S_IRUGO | S_IWUSR }, - .show = target_core_show_dev_udev_path, - .store = target_core_store_dev_udev_path, -}; - -static ssize_t target_core_show_dev_enable(void *p, char *page) +static ssize_t target_dev_enable_show(struct config_item *item, char *page) { - struct se_device *dev = p; + struct se_device *dev = to_device(item); return snprintf(page, PAGE_SIZE, "%d\n", !!(dev->dev_flags & DF_CONFIGURED)); } -static ssize_t target_core_store_dev_enable( - void *p, - const char *page, - size_t count) +static ssize_t target_dev_enable_store(struct config_item *item, + const char *page, size_t count) { - struct se_device *dev = p; + struct se_device *dev = to_device(item); char *ptr; int ret; @@ -1962,17 +1825,9 @@ static ssize_t target_core_store_dev_enable( return count; } -static struct target_core_configfs_attribute target_core_attr_dev_enable = { - .attr = { .ca_owner = THIS_MODULE, - .ca_name = "enable", - .ca_mode = S_IRUGO | S_IWUSR }, - .show = target_core_show_dev_enable, - .store = target_core_store_dev_enable, -}; - -static ssize_t target_core_show_alua_lu_gp(void *p, char *page) +static ssize_t target_dev_alua_lu_gp_show(struct config_item *item, char *page) { - struct se_device *dev = p; + struct se_device *dev = to_device(item); struct config_item *lu_ci; struct t10_alua_lu_gp *lu_gp; struct t10_alua_lu_gp_member *lu_gp_mem; @@ -1994,12 +1849,10 @@ static ssize_t target_core_show_alua_lu_gp(void *p, char *page) return len; } -static ssize_t target_core_store_alua_lu_gp( - void *p, - const char *page, - size_t count) +static ssize_t target_dev_alua_lu_gp_store(struct config_item *item, + const char *page, size_t count) { - struct se_device *dev = p; + struct se_device *dev = to_device(item); struct se_hba *hba = dev->se_hba; struct t10_alua_lu_gp *lu_gp = NULL, *lu_gp_new = NULL; struct t10_alua_lu_gp_member *lu_gp_mem; @@ -2076,17 +1929,9 @@ static ssize_t target_core_store_alua_lu_gp( return count; } -static struct target_core_configfs_attribute target_core_attr_dev_alua_lu_gp = { - .attr = { .ca_owner = THIS_MODULE, - .ca_name = "alua_lu_gp", - .ca_mode = S_IRUGO | S_IWUSR }, - .show = target_core_show_alua_lu_gp, - .store = target_core_store_alua_lu_gp, -}; - -static ssize_t target_core_show_dev_lba_map(void *p, char *page) +static ssize_t target_dev_lba_map_show(struct config_item *item, char *page) { - struct se_device *dev = p; + struct se_device *dev = to_device(item); struct t10_alua_lba_map *map; struct t10_alua_lba_map_member *mem; char *b = page; @@ -2129,12 +1974,10 @@ static ssize_t target_core_show_dev_lba_map(void *p, char *page) return bl; } -static ssize_t target_core_store_dev_lba_map( - void *p, - const char *page, - size_t count) +static ssize_t target_dev_lba_map_store(struct config_item *item, + const char *page, size_t count) { - struct se_device *dev = p; + struct se_device *dev = to_device(item); struct t10_alua_lba_map *lba_map = NULL; struct list_head lba_list; char *map_entries, *ptr; @@ -2246,22 +2089,22 @@ out: return count; } -static struct target_core_configfs_attribute target_core_attr_dev_lba_map = { - .attr = { .ca_owner = THIS_MODULE, - .ca_name = "lba_map", - .ca_mode = S_IRUGO | S_IWUSR }, - .show = target_core_show_dev_lba_map, - .store = target_core_store_dev_lba_map, -}; +CONFIGFS_ATTR_RO(target_dev_, info); +CONFIGFS_ATTR_WO(target_dev_, control); +CONFIGFS_ATTR(target_dev_, alias); +CONFIGFS_ATTR(target_dev_, udev_path); +CONFIGFS_ATTR(target_dev_, enable); +CONFIGFS_ATTR(target_dev_, alua_lu_gp); +CONFIGFS_ATTR(target_dev_, lba_map); static struct configfs_attribute *target_core_dev_attrs[] = { - &target_core_attr_dev_info.attr, - &target_core_attr_dev_control.attr, - &target_core_attr_dev_alias.attr, - &target_core_attr_dev_udev_path.attr, - &target_core_attr_dev_enable.attr, - &target_core_attr_dev_alua_lu_gp.attr, - &target_core_attr_dev_lba_map.attr, + &target_dev_attr_info, + &target_dev_attr_control, + &target_dev_attr_alias, + &target_dev_attr_udev_path, + &target_dev_attr_enable, + &target_dev_attr_alua_lu_gp, + &target_dev_attr_lba_map, NULL, }; @@ -2275,42 +2118,8 @@ static void target_core_dev_release(struct config_item *item) target_free_device(dev); } -static ssize_t target_core_dev_show(struct config_item *item, - struct configfs_attribute *attr, - char *page) -{ - struct config_group *dev_cg = to_config_group(item); - struct se_device *dev = - container_of(dev_cg, struct se_device, dev_group); - struct target_core_configfs_attribute *tc_attr = container_of( - attr, struct target_core_configfs_attribute, attr); - - if (!tc_attr->show) - return -EINVAL; - - return tc_attr->show(dev, page); -} - -static ssize_t target_core_dev_store(struct config_item *item, - struct configfs_attribute *attr, - const char *page, size_t count) -{ - struct config_group *dev_cg = to_config_group(item); - struct se_device *dev = - container_of(dev_cg, struct se_device, dev_group); - struct target_core_configfs_attribute *tc_attr = container_of( - attr, struct target_core_configfs_attribute, attr); - - if (!tc_attr->store) - return -EINVAL; - - return tc_attr->store(dev, page, count); -} - static struct configfs_item_operations target_core_dev_item_ops = { .release = target_core_dev_release, - .show_attribute = target_core_dev_show, - .store_attribute = target_core_dev_store, }; TB_CIT_SETUP(dev, &target_core_dev_item_ops, NULL, target_core_dev_attrs); @@ -2319,38 +2128,25 @@ TB_CIT_SETUP(dev, &target_core_dev_item_ops, NULL, target_core_dev_attrs); /* Start functions for struct config_item_type target_core_alua_lu_gp_cit */ -CONFIGFS_EATTR_STRUCT(target_core_alua_lu_gp, t10_alua_lu_gp); -#define SE_DEV_ALUA_LU_ATTR(_name, _mode) \ -static struct target_core_alua_lu_gp_attribute \ - target_core_alua_lu_gp_##_name = \ - __CONFIGFS_EATTR(_name, _mode, \ - target_core_alua_lu_gp_show_attr_##_name, \ - target_core_alua_lu_gp_store_attr_##_name); - -#define SE_DEV_ALUA_LU_ATTR_RO(_name) \ -static struct target_core_alua_lu_gp_attribute \ - target_core_alua_lu_gp_##_name = \ - __CONFIGFS_EATTR_RO(_name, \ - target_core_alua_lu_gp_show_attr_##_name); +static inline struct t10_alua_lu_gp *to_lu_gp(struct config_item *item) +{ + return container_of(to_config_group(item), struct t10_alua_lu_gp, + lu_gp_group); +} -/* - * lu_gp_id - */ -static ssize_t target_core_alua_lu_gp_show_attr_lu_gp_id( - struct t10_alua_lu_gp *lu_gp, - char *page) +static ssize_t target_lu_gp_lu_gp_id_show(struct config_item *item, char *page) { + struct t10_alua_lu_gp *lu_gp = to_lu_gp(item); + if (!lu_gp->lu_gp_valid_id) return 0; - return sprintf(page, "%hu\n", lu_gp->lu_gp_id); } -static ssize_t target_core_alua_lu_gp_store_attr_lu_gp_id( - struct t10_alua_lu_gp *lu_gp, - const char *page, - size_t count) +static ssize_t target_lu_gp_lu_gp_id_store(struct config_item *item, + const char *page, size_t count) { + struct t10_alua_lu_gp *lu_gp = to_lu_gp(item); struct config_group *alua_lu_gp_cg = &lu_gp->lu_gp_group; unsigned long lu_gp_id; int ret; @@ -2379,15 +2175,9 @@ static ssize_t target_core_alua_lu_gp_store_attr_lu_gp_id( return count; } -SE_DEV_ALUA_LU_ATTR(lu_gp_id, S_IRUGO | S_IWUSR); - -/* - * members - */ -static ssize_t target_core_alua_lu_gp_show_attr_members( - struct t10_alua_lu_gp *lu_gp, - char *page) +static ssize_t target_lu_gp_members_show(struct config_item *item, char *page) { + struct t10_alua_lu_gp *lu_gp = to_lu_gp(item); struct se_device *dev; struct se_hba *hba; struct t10_alua_lu_gp_member *lu_gp_mem; @@ -2419,13 +2209,12 @@ static ssize_t target_core_alua_lu_gp_show_attr_members( return len; } -SE_DEV_ALUA_LU_ATTR_RO(members); - -CONFIGFS_EATTR_OPS(target_core_alua_lu_gp, t10_alua_lu_gp, lu_gp_group); +CONFIGFS_ATTR(target_lu_gp_, lu_gp_id); +CONFIGFS_ATTR_RO(target_lu_gp_, members); static struct configfs_attribute *target_core_alua_lu_gp_attrs[] = { - &target_core_alua_lu_gp_lu_gp_id.attr, - &target_core_alua_lu_gp_members.attr, + &target_lu_gp_attr_lu_gp_id, + &target_lu_gp_attr_members, NULL, }; @@ -2439,8 +2228,6 @@ static void target_core_alua_lu_gp_release(struct config_item *item) static struct configfs_item_operations target_core_alua_lu_gp_ops = { .release = target_core_alua_lu_gp_release, - .show_attribute = target_core_alua_lu_gp_attr_show, - .store_attribute = target_core_alua_lu_gp_attr_store, }; static struct config_item_type target_core_alua_lu_gp_cit = { @@ -2511,36 +2298,23 @@ static struct config_item_type target_core_alua_lu_gps_cit = { /* Start functions for struct config_item_type target_core_alua_tg_pt_gp_cit */ -CONFIGFS_EATTR_STRUCT(target_core_alua_tg_pt_gp, t10_alua_tg_pt_gp); -#define SE_DEV_ALUA_TG_PT_ATTR(_name, _mode) \ -static struct target_core_alua_tg_pt_gp_attribute \ - target_core_alua_tg_pt_gp_##_name = \ - __CONFIGFS_EATTR(_name, _mode, \ - target_core_alua_tg_pt_gp_show_attr_##_name, \ - target_core_alua_tg_pt_gp_store_attr_##_name); - -#define SE_DEV_ALUA_TG_PT_ATTR_RO(_name) \ -static struct target_core_alua_tg_pt_gp_attribute \ - target_core_alua_tg_pt_gp_##_name = \ - __CONFIGFS_EATTR_RO(_name, \ - target_core_alua_tg_pt_gp_show_attr_##_name); +static inline struct t10_alua_tg_pt_gp *to_tg_pt_gp(struct config_item *item) +{ + return container_of(to_config_group(item), struct t10_alua_tg_pt_gp, + tg_pt_gp_group); +} -/* - * alua_access_state - */ -static ssize_t target_core_alua_tg_pt_gp_show_attr_alua_access_state( - struct t10_alua_tg_pt_gp *tg_pt_gp, - char *page) +static ssize_t target_tg_pt_gp_alua_access_state_show(struct config_item *item, + char *page) { return sprintf(page, "%d\n", - atomic_read(&tg_pt_gp->tg_pt_gp_alua_access_state)); + atomic_read(&to_tg_pt_gp(item)->tg_pt_gp_alua_access_state)); } -static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_access_state( - struct t10_alua_tg_pt_gp *tg_pt_gp, - const char *page, - size_t count) +static ssize_t target_tg_pt_gp_alua_access_state_store(struct config_item *item, + const char *page, size_t count) { + struct t10_alua_tg_pt_gp *tg_pt_gp = to_tg_pt_gp(item); struct se_device *dev = tg_pt_gp->tg_pt_gp_dev; unsigned long tmp; int new_state, ret; @@ -2582,24 +2356,18 @@ static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_access_state( return (!ret) ? count : -EINVAL; } -SE_DEV_ALUA_TG_PT_ATTR(alua_access_state, S_IRUGO | S_IWUSR); - -/* - * alua_access_status - */ -static ssize_t target_core_alua_tg_pt_gp_show_attr_alua_access_status( - struct t10_alua_tg_pt_gp *tg_pt_gp, - char *page) +static ssize_t target_tg_pt_gp_alua_access_status_show(struct config_item *item, + char *page) { + struct t10_alua_tg_pt_gp *tg_pt_gp = to_tg_pt_gp(item); return sprintf(page, "%s\n", core_alua_dump_status(tg_pt_gp->tg_pt_gp_alua_access_status)); } -static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_access_status( - struct t10_alua_tg_pt_gp *tg_pt_gp, - const char *page, - size_t count) +static ssize_t target_tg_pt_gp_alua_access_status_store( + struct config_item *item, const char *page, size_t count) { + struct t10_alua_tg_pt_gp *tg_pt_gp = to_tg_pt_gp(item); unsigned long tmp; int new_status, ret; @@ -2630,43 +2398,31 @@ static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_access_status( return count; } -SE_DEV_ALUA_TG_PT_ATTR(alua_access_status, S_IRUGO | S_IWUSR); - -/* - * alua_access_type - */ -static ssize_t target_core_alua_tg_pt_gp_show_attr_alua_access_type( - struct t10_alua_tg_pt_gp *tg_pt_gp, - char *page) +static ssize_t target_tg_pt_gp_alua_access_type_show(struct config_item *item, + char *page) { - return core_alua_show_access_type(tg_pt_gp, page); + return core_alua_show_access_type(to_tg_pt_gp(item), page); } -static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_access_type( - struct t10_alua_tg_pt_gp *tg_pt_gp, - const char *page, - size_t count) +static ssize_t target_tg_pt_gp_alua_access_type_store(struct config_item *item, + const char *page, size_t count) { - return core_alua_store_access_type(tg_pt_gp, page, count); + return core_alua_store_access_type(to_tg_pt_gp(item), page, count); } -SE_DEV_ALUA_TG_PT_ATTR(alua_access_type, S_IRUGO | S_IWUSR); - -/* - * alua_supported_states - */ - -#define SE_DEV_ALUA_SUPPORT_STATE_SHOW(_name, _var, _bit) \ -static ssize_t target_core_alua_tg_pt_gp_show_attr_alua_support_##_name( \ - struct t10_alua_tg_pt_gp *t, char *p) \ +#define ALUA_SUPPORTED_STATE_ATTR(_name, _bit) \ +static ssize_t target_tg_pt_gp_alua_support_##_name##_show( \ + struct config_item *item, char *p) \ { \ - return sprintf(p, "%d\n", !!(t->_var & _bit)); \ -} - -#define SE_DEV_ALUA_SUPPORT_STATE_STORE(_name, _var, _bit) \ -static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_support_##_name(\ - struct t10_alua_tg_pt_gp *t, const char *p, size_t c) \ + struct t10_alua_tg_pt_gp *t = to_tg_pt_gp(item); \ + return sprintf(p, "%d\n", \ + !!(t->tg_pt_gp_alua_supported_states & _bit)); \ +} \ + \ +static ssize_t target_tg_pt_gp_alua_support_##_name##_store( \ + struct config_item *item, const char *p, size_t c) \ { \ + struct t10_alua_tg_pt_gp *t = to_tg_pt_gp(item); \ unsigned long tmp; \ int ret; \ \ @@ -2687,70 +2443,32 @@ static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_support_##_name(\ return -EINVAL; \ } \ if (tmp) \ - t->_var |= _bit; \ + t->tg_pt_gp_alua_supported_states |= _bit; \ else \ - t->_var &= ~_bit; \ + t->tg_pt_gp_alua_supported_states &= ~_bit; \ \ return c; \ } -SE_DEV_ALUA_SUPPORT_STATE_SHOW(transitioning, - tg_pt_gp_alua_supported_states, ALUA_T_SUP); -SE_DEV_ALUA_SUPPORT_STATE_STORE(transitioning, - tg_pt_gp_alua_supported_states, ALUA_T_SUP); -SE_DEV_ALUA_TG_PT_ATTR(alua_support_transitioning, S_IRUGO | S_IWUSR); - -SE_DEV_ALUA_SUPPORT_STATE_SHOW(offline, - tg_pt_gp_alua_supported_states, ALUA_O_SUP); -SE_DEV_ALUA_SUPPORT_STATE_STORE(offline, - tg_pt_gp_alua_supported_states, ALUA_O_SUP); -SE_DEV_ALUA_TG_PT_ATTR(alua_support_offline, S_IRUGO | S_IWUSR); - -SE_DEV_ALUA_SUPPORT_STATE_SHOW(lba_dependent, - tg_pt_gp_alua_supported_states, ALUA_LBD_SUP); -SE_DEV_ALUA_SUPPORT_STATE_STORE(lba_dependent, - tg_pt_gp_alua_supported_states, ALUA_LBD_SUP); -SE_DEV_ALUA_TG_PT_ATTR(alua_support_lba_dependent, S_IRUGO); - -SE_DEV_ALUA_SUPPORT_STATE_SHOW(unavailable, - tg_pt_gp_alua_supported_states, ALUA_U_SUP); -SE_DEV_ALUA_SUPPORT_STATE_STORE(unavailable, - tg_pt_gp_alua_supported_states, ALUA_U_SUP); -SE_DEV_ALUA_TG_PT_ATTR(alua_support_unavailable, S_IRUGO | S_IWUSR); - -SE_DEV_ALUA_SUPPORT_STATE_SHOW(standby, - tg_pt_gp_alua_supported_states, ALUA_S_SUP); -SE_DEV_ALUA_SUPPORT_STATE_STORE(standby, - tg_pt_gp_alua_supported_states, ALUA_S_SUP); -SE_DEV_ALUA_TG_PT_ATTR(alua_support_standby, S_IRUGO | S_IWUSR); - -SE_DEV_ALUA_SUPPORT_STATE_SHOW(active_optimized, - tg_pt_gp_alua_supported_states, ALUA_AO_SUP); -SE_DEV_ALUA_SUPPORT_STATE_STORE(active_optimized, - tg_pt_gp_alua_supported_states, ALUA_AO_SUP); -SE_DEV_ALUA_TG_PT_ATTR(alua_support_active_optimized, S_IRUGO | S_IWUSR); - -SE_DEV_ALUA_SUPPORT_STATE_SHOW(active_nonoptimized, - tg_pt_gp_alua_supported_states, ALUA_AN_SUP); -SE_DEV_ALUA_SUPPORT_STATE_STORE(active_nonoptimized, - tg_pt_gp_alua_supported_states, ALUA_AN_SUP); -SE_DEV_ALUA_TG_PT_ATTR(alua_support_active_nonoptimized, S_IRUGO | S_IWUSR); +ALUA_SUPPORTED_STATE_ATTR(transitioning, ALUA_T_SUP); +ALUA_SUPPORTED_STATE_ATTR(offline, ALUA_O_SUP); +ALUA_SUPPORTED_STATE_ATTR(lba_dependent, ALUA_LBD_SUP); +ALUA_SUPPORTED_STATE_ATTR(unavailable, ALUA_U_SUP); +ALUA_SUPPORTED_STATE_ATTR(standby, ALUA_S_SUP); +ALUA_SUPPORTED_STATE_ATTR(active_optimized, ALUA_AO_SUP); +ALUA_SUPPORTED_STATE_ATTR(active_nonoptimized, ALUA_AN_SUP); -/* - * alua_write_metadata - */ -static ssize_t target_core_alua_tg_pt_gp_show_attr_alua_write_metadata( - struct t10_alua_tg_pt_gp *tg_pt_gp, - char *page) +static ssize_t target_tg_pt_gp_alua_write_metadata_show( + struct config_item *item, char *page) { - return sprintf(page, "%d\n", tg_pt_gp->tg_pt_gp_write_metadata); + return sprintf(page, "%d\n", + to_tg_pt_gp(item)->tg_pt_gp_write_metadata); } -static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_write_metadata( - struct t10_alua_tg_pt_gp *tg_pt_gp, - const char *page, - size_t count) +static ssize_t target_tg_pt_gp_alua_write_metadata_store( + struct config_item *item, const char *page, size_t count) { + struct t10_alua_tg_pt_gp *tg_pt_gp = to_tg_pt_gp(item); unsigned long tmp; int ret; @@ -2770,110 +2488,71 @@ static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_write_metadata( return count; } -SE_DEV_ALUA_TG_PT_ATTR(alua_write_metadata, S_IRUGO | S_IWUSR); - - - -/* - * nonop_delay_msecs - */ -static ssize_t target_core_alua_tg_pt_gp_show_attr_nonop_delay_msecs( - struct t10_alua_tg_pt_gp *tg_pt_gp, - char *page) +static ssize_t target_tg_pt_gp_nonop_delay_msecs_show(struct config_item *item, + char *page) { - return core_alua_show_nonop_delay_msecs(tg_pt_gp, page); - + return core_alua_show_nonop_delay_msecs(to_tg_pt_gp(item), page); } -static ssize_t target_core_alua_tg_pt_gp_store_attr_nonop_delay_msecs( - struct t10_alua_tg_pt_gp *tg_pt_gp, - const char *page, - size_t count) +static ssize_t target_tg_pt_gp_nonop_delay_msecs_store(struct config_item *item, + const char *page, size_t count) { - return core_alua_store_nonop_delay_msecs(tg_pt_gp, page, count); + return core_alua_store_nonop_delay_msecs(to_tg_pt_gp(item), page, + count); } -SE_DEV_ALUA_TG_PT_ATTR(nonop_delay_msecs, S_IRUGO | S_IWUSR); - -/* - * trans_delay_msecs - */ -static ssize_t target_core_alua_tg_pt_gp_show_attr_trans_delay_msecs( - struct t10_alua_tg_pt_gp *tg_pt_gp, - char *page) +static ssize_t target_tg_pt_gp_trans_delay_msecs_show(struct config_item *item, + char *page) { - return core_alua_show_trans_delay_msecs(tg_pt_gp, page); + return core_alua_show_trans_delay_msecs(to_tg_pt_gp(item), page); } -static ssize_t target_core_alua_tg_pt_gp_store_attr_trans_delay_msecs( - struct t10_alua_tg_pt_gp *tg_pt_gp, - const char *page, - size_t count) +static ssize_t target_tg_pt_gp_trans_delay_msecs_store(struct config_item *item, + const char *page, size_t count) { - return core_alua_store_trans_delay_msecs(tg_pt_gp, page, count); + return core_alua_store_trans_delay_msecs(to_tg_pt_gp(item), page, + count); } -SE_DEV_ALUA_TG_PT_ATTR(trans_delay_msecs, S_IRUGO | S_IWUSR); - -/* - * implicit_trans_secs - */ -static ssize_t target_core_alua_tg_pt_gp_show_attr_implicit_trans_secs( - struct t10_alua_tg_pt_gp *tg_pt_gp, - char *page) +static ssize_t target_tg_pt_gp_implicit_trans_secs_show( + struct config_item *item, char *page) { - return core_alua_show_implicit_trans_secs(tg_pt_gp, page); + return core_alua_show_implicit_trans_secs(to_tg_pt_gp(item), page); } -static ssize_t target_core_alua_tg_pt_gp_store_attr_implicit_trans_secs( - struct t10_alua_tg_pt_gp *tg_pt_gp, - const char *page, - size_t count) +static ssize_t target_tg_pt_gp_implicit_trans_secs_store( + struct config_item *item, const char *page, size_t count) { - return core_alua_store_implicit_trans_secs(tg_pt_gp, page, count); + return core_alua_store_implicit_trans_secs(to_tg_pt_gp(item), page, + count); } -SE_DEV_ALUA_TG_PT_ATTR(implicit_trans_secs, S_IRUGO | S_IWUSR); - -/* - * preferred - */ - -static ssize_t target_core_alua_tg_pt_gp_show_attr_preferred( - struct t10_alua_tg_pt_gp *tg_pt_gp, - char *page) +static ssize_t target_tg_pt_gp_preferred_show(struct config_item *item, + char *page) { - return core_alua_show_preferred_bit(tg_pt_gp, page); + return core_alua_show_preferred_bit(to_tg_pt_gp(item), page); } -static ssize_t target_core_alua_tg_pt_gp_store_attr_preferred( - struct t10_alua_tg_pt_gp *tg_pt_gp, - const char *page, - size_t count) +static ssize_t target_tg_pt_gp_preferred_store(struct config_item *item, + const char *page, size_t count) { - return core_alua_store_preferred_bit(tg_pt_gp, page, count); + return core_alua_store_preferred_bit(to_tg_pt_gp(item), page, count); } -SE_DEV_ALUA_TG_PT_ATTR(preferred, S_IRUGO | S_IWUSR); - -/* - * tg_pt_gp_id - */ -static ssize_t target_core_alua_tg_pt_gp_show_attr_tg_pt_gp_id( - struct t10_alua_tg_pt_gp *tg_pt_gp, - char *page) +static ssize_t target_tg_pt_gp_tg_pt_gp_id_show(struct config_item *item, + char *page) { + struct t10_alua_tg_pt_gp *tg_pt_gp = to_tg_pt_gp(item); + if (!tg_pt_gp->tg_pt_gp_valid_id) return 0; - return sprintf(page, "%hu\n", tg_pt_gp->tg_pt_gp_id); } -static ssize_t target_core_alua_tg_pt_gp_store_attr_tg_pt_gp_id( - struct t10_alua_tg_pt_gp *tg_pt_gp, - const char *page, - size_t count) +static ssize_t target_tg_pt_gp_tg_pt_gp_id_store(struct config_item *item, + const char *page, size_t count) { + struct t10_alua_tg_pt_gp *tg_pt_gp = to_tg_pt_gp(item); struct config_group *alua_tg_pt_gp_cg = &tg_pt_gp->tg_pt_gp_group; unsigned long tg_pt_gp_id; int ret; @@ -2902,15 +2581,10 @@ static ssize_t target_core_alua_tg_pt_gp_store_attr_tg_pt_gp_id( return count; } -SE_DEV_ALUA_TG_PT_ATTR(tg_pt_gp_id, S_IRUGO | S_IWUSR); - -/* - * members - */ -static ssize_t target_core_alua_tg_pt_gp_show_attr_members( - struct t10_alua_tg_pt_gp *tg_pt_gp, - char *page) +static ssize_t target_tg_pt_gp_members_show(struct config_item *item, + char *page) { + struct t10_alua_tg_pt_gp *tg_pt_gp = to_tg_pt_gp(item); struct se_lun *lun; ssize_t len = 0, cur_len; unsigned char buf[TG_PT_GROUP_NAME_BUF]; @@ -2942,29 +2616,42 @@ static ssize_t target_core_alua_tg_pt_gp_show_attr_members( return len; } -SE_DEV_ALUA_TG_PT_ATTR_RO(members); - -CONFIGFS_EATTR_OPS(target_core_alua_tg_pt_gp, t10_alua_tg_pt_gp, - tg_pt_gp_group); +CONFIGFS_ATTR(target_tg_pt_gp_, alua_access_state); +CONFIGFS_ATTR(target_tg_pt_gp_, alua_access_status); +CONFIGFS_ATTR(target_tg_pt_gp_, alua_access_type); +CONFIGFS_ATTR(target_tg_pt_gp_, alua_support_transitioning); +CONFIGFS_ATTR(target_tg_pt_gp_, alua_support_offline); +CONFIGFS_ATTR(target_tg_pt_gp_, alua_support_lba_dependent); +CONFIGFS_ATTR(target_tg_pt_gp_, alua_support_unavailable); +CONFIGFS_ATTR(target_tg_pt_gp_, alua_support_standby); +CONFIGFS_ATTR(target_tg_pt_gp_, alua_support_active_optimized); +CONFIGFS_ATTR(target_tg_pt_gp_, alua_support_active_nonoptimized); +CONFIGFS_ATTR(target_tg_pt_gp_, alua_write_metadata); +CONFIGFS_ATTR(target_tg_pt_gp_, nonop_delay_msecs); +CONFIGFS_ATTR(target_tg_pt_gp_, trans_delay_msecs); +CONFIGFS_ATTR(target_tg_pt_gp_, implicit_trans_secs); +CONFIGFS_ATTR(target_tg_pt_gp_, preferred); +CONFIGFS_ATTR(target_tg_pt_gp_, tg_pt_gp_id); +CONFIGFS_ATTR_RO(target_tg_pt_gp_, members); static struct configfs_attribute *target_core_alua_tg_pt_gp_attrs[] = { - &target_core_alua_tg_pt_gp_alua_access_state.attr, - &target_core_alua_tg_pt_gp_alua_access_status.attr, - &target_core_alua_tg_pt_gp_alua_access_type.attr, - &target_core_alua_tg_pt_gp_alua_support_transitioning.attr, - &target_core_alua_tg_pt_gp_alua_support_offline.attr, - &target_core_alua_tg_pt_gp_alua_support_lba_dependent.attr, - &target_core_alua_tg_pt_gp_alua_support_unavailable.attr, - &target_core_alua_tg_pt_gp_alua_support_standby.attr, - &target_core_alua_tg_pt_gp_alua_support_active_nonoptimized.attr, - &target_core_alua_tg_pt_gp_alua_support_active_optimized.attr, - &target_core_alua_tg_pt_gp_alua_write_metadata.attr, - &target_core_alua_tg_pt_gp_nonop_delay_msecs.attr, - &target_core_alua_tg_pt_gp_trans_delay_msecs.attr, - &target_core_alua_tg_pt_gp_implicit_trans_secs.attr, - &target_core_alua_tg_pt_gp_preferred.attr, - &target_core_alua_tg_pt_gp_tg_pt_gp_id.attr, - &target_core_alua_tg_pt_gp_members.attr, + &target_tg_pt_gp_attr_alua_access_state, + &target_tg_pt_gp_attr_alua_access_status, + &target_tg_pt_gp_attr_alua_access_type, + &target_tg_pt_gp_attr_alua_support_transitioning, + &target_tg_pt_gp_attr_alua_support_offline, + &target_tg_pt_gp_attr_alua_support_lba_dependent, + &target_tg_pt_gp_attr_alua_support_unavailable, + &target_tg_pt_gp_attr_alua_support_standby, + &target_tg_pt_gp_attr_alua_support_active_nonoptimized, + &target_tg_pt_gp_attr_alua_support_active_optimized, + &target_tg_pt_gp_attr_alua_write_metadata, + &target_tg_pt_gp_attr_nonop_delay_msecs, + &target_tg_pt_gp_attr_trans_delay_msecs, + &target_tg_pt_gp_attr_implicit_trans_secs, + &target_tg_pt_gp_attr_preferred, + &target_tg_pt_gp_attr_tg_pt_gp_id, + &target_tg_pt_gp_attr_members, NULL, }; @@ -2978,8 +2665,6 @@ static void target_core_alua_tg_pt_gp_release(struct config_item *item) static struct configfs_item_operations target_core_alua_tg_pt_gp_ops = { .release = target_core_alua_tg_pt_gp_release, - .show_attribute = target_core_alua_tg_pt_gp_attr_show, - .store_attribute = target_core_alua_tg_pt_gp_attr_store, }; static struct config_item_type target_core_alua_tg_pt_gp_cit = { @@ -3237,34 +2922,24 @@ static struct configfs_group_operations target_core_hba_group_ops = { .drop_item = target_core_drop_subdev, }; -CONFIGFS_EATTR_STRUCT(target_core_hba, se_hba); -#define SE_HBA_ATTR(_name, _mode) \ -static struct target_core_hba_attribute \ - target_core_hba_##_name = \ - __CONFIGFS_EATTR(_name, _mode, \ - target_core_hba_show_attr_##_name, \ - target_core_hba_store_attr_##_name); -#define SE_HBA_ATTR_RO(_name) \ -static struct target_core_hba_attribute \ - target_core_hba_##_name = \ - __CONFIGFS_EATTR_RO(_name, \ - target_core_hba_show_attr_##_name); +static inline struct se_hba *to_hba(struct config_item *item) +{ + return container_of(to_config_group(item), struct se_hba, hba_group); +} -static ssize_t target_core_hba_show_attr_hba_info( - struct se_hba *hba, - char *page) +static ssize_t target_hba_info_show(struct config_item *item, char *page) { + struct se_hba *hba = to_hba(item); + return sprintf(page, "HBA Index: %d plugin: %s version: %s\n", hba->hba_id, hba->backend->ops->name, TARGET_CORE_VERSION); } -SE_HBA_ATTR_RO(hba_info); - -static ssize_t target_core_hba_show_attr_hba_mode(struct se_hba *hba, - char *page) +static ssize_t target_hba_mode_show(struct config_item *item, char *page) { + struct se_hba *hba = to_hba(item); int hba_mode = 0; if (hba->hba_flags & HBA_FLAGS_PSCSI_MODE) @@ -3273,9 +2948,10 @@ static ssize_t target_core_hba_show_attr_hba_mode(struct se_hba *hba, return sprintf(page, "%d\n", hba_mode); } -static ssize_t target_core_hba_store_attr_hba_mode(struct se_hba *hba, - const char *page, size_t count) +static ssize_t target_hba_mode_store(struct config_item *item, + const char *page, size_t count) { + struct se_hba *hba = to_hba(item); unsigned long mode_flag; int ret; @@ -3304,9 +2980,8 @@ static ssize_t target_core_hba_store_attr_hba_mode(struct se_hba *hba, return count; } -SE_HBA_ATTR(hba_mode, S_IRUGO | S_IWUSR); - -CONFIGFS_EATTR_OPS(target_core_hba, se_hba, hba_group); +CONFIGFS_ATTR_RO(target_, hba_info); +CONFIGFS_ATTR(target_, hba_mode); static void target_core_hba_release(struct config_item *item) { @@ -3316,15 +2991,13 @@ static void target_core_hba_release(struct config_item *item) } static struct configfs_attribute *target_core_hba_attrs[] = { - &target_core_hba_hba_info.attr, - &target_core_hba_hba_mode.attr, + &target_attr_hba_info, + &target_attr_hba_mode, NULL, }; static struct configfs_item_operations target_core_hba_item_ops = { .release = target_core_hba_release, - .show_attribute = target_core_hba_attr_show, - .store_attribute = target_core_hba_attr_store, }; static struct config_item_type target_core_hba_cit = { diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index be42429468e2..f916d18ccb48 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c @@ -35,8 +35,6 @@ #include <target/target_core_base.h> #include <target/target_core_fabric.h> -#include <target/target_core_fabric_configfs.h> -#include <target/configfs_macros.h> #include "target_core_internal.h" #include "target_core_alua.h" @@ -152,17 +150,16 @@ static int target_fabric_mappedlun_unlink( return core_dev_del_initiator_node_lun_acl(lun, lacl); } -CONFIGFS_EATTR_STRUCT(target_fabric_mappedlun, se_lun_acl); -#define TCM_MAPPEDLUN_ATTR(_name, _mode) \ -static struct target_fabric_mappedlun_attribute target_fabric_mappedlun_##_name = \ - __CONFIGFS_EATTR(_name, _mode, \ - target_fabric_mappedlun_show_##_name, \ - target_fabric_mappedlun_store_##_name); +static struct se_lun_acl *item_to_lun_acl(struct config_item *item) +{ + return container_of(to_config_group(item), struct se_lun_acl, + se_lun_group); +} -static ssize_t target_fabric_mappedlun_show_write_protect( - struct se_lun_acl *lacl, - char *page) +static ssize_t target_fabric_mappedlun_write_protect_show( + struct config_item *item, char *page) { + struct se_lun_acl *lacl = item_to_lun_acl(item); struct se_node_acl *se_nacl = lacl->se_lun_nacl; struct se_dev_entry *deve; ssize_t len = 0; @@ -178,11 +175,10 @@ static ssize_t target_fabric_mappedlun_show_write_protect( return len; } -static ssize_t target_fabric_mappedlun_store_write_protect( - struct se_lun_acl *lacl, - const char *page, - size_t count) +static ssize_t target_fabric_mappedlun_write_protect_store( + struct config_item *item, const char *page, size_t count) { + struct se_lun_acl *lacl = item_to_lun_acl(item); struct se_node_acl *se_nacl = lacl->se_lun_nacl; struct se_portal_group *se_tpg = se_nacl->se_tpg; unsigned long op; @@ -209,9 +205,12 @@ static ssize_t target_fabric_mappedlun_store_write_protect( } -TCM_MAPPEDLUN_ATTR(write_protect, S_IRUGO | S_IWUSR); +CONFIGFS_ATTR(target_fabric_mappedlun_, write_protect); -CONFIGFS_EATTR_OPS(target_fabric_mappedlun, se_lun_acl, se_lun_group); +static struct configfs_attribute *target_fabric_mappedlun_attrs[] = { + &target_fabric_mappedlun_attr_write_protect, + NULL, +}; static void target_fabric_mappedlun_release(struct config_item *item) { @@ -222,15 +221,8 @@ static void target_fabric_mappedlun_release(struct config_item *item) core_dev_free_initiator_node_lun_acl(se_tpg, lacl); } -static struct configfs_attribute *target_fabric_mappedlun_attrs[] = { - &target_fabric_mappedlun_write_protect.attr, - NULL, -}; - static struct configfs_item_operations target_fabric_mappedlun_item_ops = { .release = target_fabric_mappedlun_release, - .show_attribute = target_fabric_mappedlun_attr_show, - .store_attribute = target_fabric_mappedlun_attr_store, .allow_link = target_fabric_mappedlun_link, .drop_link = target_fabric_mappedlun_unlink, }; @@ -266,49 +258,12 @@ TF_CIT_SETUP(tpg_mappedlun_stat, NULL, &target_fabric_mappedlun_stat_group_ops, /* End of tfc_tpg_mappedlun_port_cit */ -/* Start of tfc_tpg_nacl_attrib_cit */ - -CONFIGFS_EATTR_OPS(target_fabric_nacl_attrib, se_node_acl, acl_attrib_group); - -static struct configfs_item_operations target_fabric_nacl_attrib_item_ops = { - .show_attribute = target_fabric_nacl_attrib_attr_show, - .store_attribute = target_fabric_nacl_attrib_attr_store, -}; - -TF_CIT_SETUP_DRV(tpg_nacl_attrib, &target_fabric_nacl_attrib_item_ops, NULL); - -/* End of tfc_tpg_nacl_attrib_cit */ - -/* Start of tfc_tpg_nacl_auth_cit */ - -CONFIGFS_EATTR_OPS(target_fabric_nacl_auth, se_node_acl, acl_auth_group); - -static struct configfs_item_operations target_fabric_nacl_auth_item_ops = { - .show_attribute = target_fabric_nacl_auth_attr_show, - .store_attribute = target_fabric_nacl_auth_attr_store, -}; - -TF_CIT_SETUP_DRV(tpg_nacl_auth, &target_fabric_nacl_auth_item_ops, NULL); - -/* End of tfc_tpg_nacl_auth_cit */ - -/* Start of tfc_tpg_nacl_param_cit */ - -CONFIGFS_EATTR_OPS(target_fabric_nacl_param, se_node_acl, acl_param_group); - -static struct configfs_item_operations target_fabric_nacl_param_item_ops = { - .show_attribute = target_fabric_nacl_param_attr_show, - .store_attribute = target_fabric_nacl_param_attr_store, -}; - -TF_CIT_SETUP_DRV(tpg_nacl_param, &target_fabric_nacl_param_item_ops, NULL); - -/* End of tfc_tpg_nacl_param_cit */ +TF_CIT_SETUP_DRV(tpg_nacl_attrib, NULL, NULL); +TF_CIT_SETUP_DRV(tpg_nacl_auth, NULL, NULL); +TF_CIT_SETUP_DRV(tpg_nacl_param, NULL, NULL); /* Start of tfc_tpg_nacl_base_cit */ -CONFIGFS_EATTR_OPS(target_fabric_nacl_base, se_node_acl, acl_group); - static struct config_group *target_fabric_make_mappedlun( struct config_group *group, const char *name) @@ -438,8 +393,6 @@ static void target_fabric_nacl_base_release(struct config_item *item) static struct configfs_item_operations target_fabric_nacl_base_item_ops = { .release = target_fabric_nacl_base_release, - .show_attribute = target_fabric_nacl_base_attr_show, - .store_attribute = target_fabric_nacl_base_attr_store, }; static struct configfs_group_operations target_fabric_nacl_base_group_ops = { @@ -540,8 +493,6 @@ TF_CIT_SETUP(tpg_nacl, NULL, &target_fabric_nacl_group_ops, NULL); /* Start of tfc_tpg_np_base_cit */ -CONFIGFS_EATTR_OPS(target_fabric_np_base, se_tpg_np, tpg_np_group); - static void target_fabric_np_base_release(struct config_item *item) { struct se_tpg_np *se_tpg_np = container_of(to_config_group(item), @@ -554,8 +505,6 @@ static void target_fabric_np_base_release(struct config_item *item) static struct configfs_item_operations target_fabric_np_base_item_ops = { .release = target_fabric_np_base_release, - .show_attribute = target_fabric_np_base_attr_show, - .store_attribute = target_fabric_np_base_attr_store, }; TF_CIT_SETUP_DRV(tpg_np_base, &target_fabric_np_base_item_ops, NULL); @@ -610,132 +559,113 @@ TF_CIT_SETUP(tpg_np, NULL, &target_fabric_np_group_ops, NULL); /* Start of tfc_tpg_port_cit */ -CONFIGFS_EATTR_STRUCT(target_fabric_port, se_lun); -#define TCM_PORT_ATTR(_name, _mode) \ -static struct target_fabric_port_attribute target_fabric_port_##_name = \ - __CONFIGFS_EATTR(_name, _mode, \ - target_fabric_port_show_attr_##_name, \ - target_fabric_port_store_attr_##_name); - -#define TCM_PORT_ATTOR_RO(_name) \ - __CONFIGFS_EATTR_RO(_name, \ - target_fabric_port_show_attr_##_name); +static struct se_lun *item_to_lun(struct config_item *item) +{ + return container_of(to_config_group(item), struct se_lun, + lun_group); +} -/* - * alua_tg_pt_gp - */ -static ssize_t target_fabric_port_show_attr_alua_tg_pt_gp( - struct se_lun *lun, - char *page) +static ssize_t target_fabric_port_alua_tg_pt_gp_show(struct config_item *item, + char *page) { + struct se_lun *lun = item_to_lun(item); + if (!lun || !lun->lun_se_dev) return -ENODEV; return core_alua_show_tg_pt_gp_info(lun, page); } -static ssize_t target_fabric_port_store_attr_alua_tg_pt_gp( - struct se_lun *lun, - const char *page, - size_t count) +static ssize_t target_fabric_port_alua_tg_pt_gp_store(struct config_item *item, + const char *page, size_t count) { + struct se_lun *lun = item_to_lun(item); + if (!lun || !lun->lun_se_dev) return -ENODEV; return core_alua_store_tg_pt_gp_info(lun, page, count); } -TCM_PORT_ATTR(alua_tg_pt_gp, S_IRUGO | S_IWUSR); - -/* - * alua_tg_pt_offline - */ -static ssize_t target_fabric_port_show_attr_alua_tg_pt_offline( - struct se_lun *lun, - char *page) +static ssize_t target_fabric_port_alua_tg_pt_offline_show( + struct config_item *item, char *page) { + struct se_lun *lun = item_to_lun(item); + if (!lun || !lun->lun_se_dev) return -ENODEV; return core_alua_show_offline_bit(lun, page); } -static ssize_t target_fabric_port_store_attr_alua_tg_pt_offline( - struct se_lun *lun, - const char *page, - size_t count) +static ssize_t target_fabric_port_alua_tg_pt_offline_store( + struct config_item *item, const char *page, size_t count) { + struct se_lun *lun = item_to_lun(item); + if (!lun || !lun->lun_se_dev) return -ENODEV; return core_alua_store_offline_bit(lun, page, count); } -TCM_PORT_ATTR(alua_tg_pt_offline, S_IRUGO | S_IWUSR); - -/* - * alua_tg_pt_status - */ -static ssize_t target_fabric_port_show_attr_alua_tg_pt_status( - struct se_lun *lun, - char *page) +static ssize_t target_fabric_port_alua_tg_pt_status_show( + struct config_item *item, char *page) { + struct se_lun *lun = item_to_lun(item); + if (!lun || !lun->lun_se_dev) return -ENODEV; return core_alua_show_secondary_status(lun, page); } -static ssize_t target_fabric_port_store_attr_alua_tg_pt_status( - struct se_lun *lun, - const char *page, - size_t count) +static ssize_t target_fabric_port_alua_tg_pt_status_store( + struct config_item *item, const char *page, size_t count) { + struct se_lun *lun = item_to_lun(item); + if (!lun || !lun->lun_se_dev) return -ENODEV; return core_alua_store_secondary_status(lun, page, count); } -TCM_PORT_ATTR(alua_tg_pt_status, S_IRUGO | S_IWUSR); - -/* - * alua_tg_pt_write_md - */ -static ssize_t target_fabric_port_show_attr_alua_tg_pt_write_md( - struct se_lun *lun, - char *page) +static ssize_t target_fabric_port_alua_tg_pt_write_md_show( + struct config_item *item, char *page) { + struct se_lun *lun = item_to_lun(item); + if (!lun || !lun->lun_se_dev) return -ENODEV; return core_alua_show_secondary_write_metadata(lun, page); } -static ssize_t target_fabric_port_store_attr_alua_tg_pt_write_md( - struct se_lun *lun, - const char *page, - size_t count) +static ssize_t target_fabric_port_alua_tg_pt_write_md_store( + struct config_item *item, const char *page, size_t count) { + struct se_lun *lun = item_to_lun(item); + if (!lun || !lun->lun_se_dev) return -ENODEV; return core_alua_store_secondary_write_metadata(lun, page, count); } -TCM_PORT_ATTR(alua_tg_pt_write_md, S_IRUGO | S_IWUSR); - +CONFIGFS_ATTR(target_fabric_port_, alua_tg_pt_gp); +CONFIGFS_ATTR(target_fabric_port_, alua_tg_pt_offline); +CONFIGFS_ATTR(target_fabric_port_, alua_tg_pt_status); +CONFIGFS_ATTR(target_fabric_port_, alua_tg_pt_write_md); static struct configfs_attribute *target_fabric_port_attrs[] = { - &target_fabric_port_alua_tg_pt_gp.attr, - &target_fabric_port_alua_tg_pt_offline.attr, - &target_fabric_port_alua_tg_pt_status.attr, - &target_fabric_port_alua_tg_pt_write_md.attr, + &target_fabric_port_attr_alua_tg_pt_gp, + &target_fabric_port_attr_alua_tg_pt_offline, + &target_fabric_port_attr_alua_tg_pt_status, + &target_fabric_port_attr_alua_tg_pt_write_md, NULL, }; -CONFIGFS_EATTR_OPS(target_fabric_port, se_lun, lun_group); - static int target_fabric_port_link( struct config_item *lun_ci, struct config_item *se_dev_ci) @@ -821,8 +751,6 @@ static void target_fabric_port_release(struct config_item *item) } static struct configfs_item_operations target_fabric_port_item_ops = { - .show_attribute = target_fabric_port_attr_show, - .store_attribute = target_fabric_port_attr_store, .release = target_fabric_port_release, .allow_link = target_fabric_port_link, .drop_link = target_fabric_port_unlink, @@ -952,50 +880,11 @@ TF_CIT_SETUP(tpg_lun, NULL, &target_fabric_lun_group_ops, NULL); /* End of tfc_tpg_lun_cit */ -/* Start of tfc_tpg_attrib_cit */ - -CONFIGFS_EATTR_OPS(target_fabric_tpg_attrib, se_portal_group, tpg_attrib_group); - -static struct configfs_item_operations target_fabric_tpg_attrib_item_ops = { - .show_attribute = target_fabric_tpg_attrib_attr_show, - .store_attribute = target_fabric_tpg_attrib_attr_store, -}; - -TF_CIT_SETUP_DRV(tpg_attrib, &target_fabric_tpg_attrib_item_ops, NULL); - -/* End of tfc_tpg_attrib_cit */ - -/* Start of tfc_tpg_auth_cit */ - -CONFIGFS_EATTR_OPS(target_fabric_tpg_auth, se_portal_group, tpg_auth_group); - -static struct configfs_item_operations target_fabric_tpg_auth_item_ops = { - .show_attribute = target_fabric_tpg_auth_attr_show, - .store_attribute = target_fabric_tpg_auth_attr_store, -}; - -TF_CIT_SETUP_DRV(tpg_auth, &target_fabric_tpg_auth_item_ops, NULL); - -/* End of tfc_tpg_attrib_cit */ - -/* Start of tfc_tpg_param_cit */ - -CONFIGFS_EATTR_OPS(target_fabric_tpg_param, se_portal_group, tpg_param_group); - -static struct configfs_item_operations target_fabric_tpg_param_item_ops = { - .show_attribute = target_fabric_tpg_param_attr_show, - .store_attribute = target_fabric_tpg_param_attr_store, -}; - -TF_CIT_SETUP_DRV(tpg_param, &target_fabric_tpg_param_item_ops, NULL); - -/* End of tfc_tpg_param_cit */ +TF_CIT_SETUP_DRV(tpg_attrib, NULL, NULL); +TF_CIT_SETUP_DRV(tpg_auth, NULL, NULL); +TF_CIT_SETUP_DRV(tpg_param, NULL, NULL); /* Start of tfc_tpg_base_cit */ -/* - * For use with TF_TPG_ATTR() and TF_TPG_ATTR_RO() - */ -CONFIGFS_EATTR_OPS(target_fabric_tpg, se_portal_group, tpg_group); static void target_fabric_tpg_release(struct config_item *item) { @@ -1009,8 +898,6 @@ static void target_fabric_tpg_release(struct config_item *item) static struct configfs_item_operations target_fabric_tpg_base_item_ops = { .release = target_fabric_tpg_release, - .show_attribute = target_fabric_tpg_attr_show, - .store_attribute = target_fabric_tpg_attr_store, }; TF_CIT_SETUP_DRV(tpg_base, &target_fabric_tpg_base_item_ops, NULL); @@ -1176,33 +1063,9 @@ static struct configfs_group_operations target_fabric_wwn_group_ops = { .make_group = target_fabric_make_wwn, .drop_item = target_fabric_drop_wwn, }; -/* - * For use with TF_WWN_ATTR() and TF_WWN_ATTR_RO() - */ -CONFIGFS_EATTR_OPS(target_fabric_wwn, target_fabric_configfs, tf_group); - -static struct configfs_item_operations target_fabric_wwn_item_ops = { - .show_attribute = target_fabric_wwn_attr_show, - .store_attribute = target_fabric_wwn_attr_store, -}; - -TF_CIT_SETUP_DRV(wwn, &target_fabric_wwn_item_ops, &target_fabric_wwn_group_ops); - -/* End of tfc_wwn_cit */ - -/* Start of tfc_discovery_cit */ - -CONFIGFS_EATTR_OPS(target_fabric_discovery, target_fabric_configfs, - tf_disc_group); - -static struct configfs_item_operations target_fabric_discovery_item_ops = { - .show_attribute = target_fabric_discovery_attr_show, - .store_attribute = target_fabric_discovery_attr_store, -}; - -TF_CIT_SETUP_DRV(discovery, &target_fabric_discovery_item_ops, NULL); -/* End of tfc_discovery_cit */ +TF_CIT_SETUP_DRV(wwn, NULL, &target_fabric_wwn_group_ops); +TF_CIT_SETUP_DRV(discovery, NULL, NULL); int target_fabric_setup_cits(struct target_fabric_configfs *tf) { diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h index 99c24acfe676..dae0750c2032 100644 --- a/drivers/target/target_core_internal.h +++ b/drivers/target/target_core_internal.h @@ -87,6 +87,9 @@ void target_free_device(struct se_device *); /* target_core_configfs.c */ void target_setup_backend_cits(struct target_backend *); +/* target_core_fabric_configfs.c */ +int target_fabric_setup_cits(struct target_fabric_configfs *); + /* target_core_fabric_lib.c */ int target_get_pr_transport_id_len(struct se_node_acl *nacl, struct t10_pr_registration *pr_reg, int *format_code); diff --git a/drivers/target/target_core_stat.c b/drivers/target/target_core_stat.c index 20ed5d2e151a..273c72b2b83d 100644 --- a/drivers/target/target_core_stat.c +++ b/drivers/target/target_core_stat.c @@ -37,7 +37,6 @@ #include <target/target_core_base.h> #include <target/target_core_backend.h> #include <target/target_core_fabric.h> -#include <target/configfs_macros.h> #include "target_core_internal.h" @@ -55,75 +54,49 @@ * SCSI Device Table */ -CONFIGFS_EATTR_STRUCT(target_stat_scsi_dev, se_dev_stat_grps); -#define DEV_STAT_SCSI_DEV_ATTR(_name, _mode) \ -static struct target_stat_scsi_dev_attribute \ - target_stat_scsi_dev_##_name = \ - __CONFIGFS_EATTR(_name, _mode, \ - target_stat_scsi_dev_show_attr_##_name, \ - target_stat_scsi_dev_store_attr_##_name); - -#define DEV_STAT_SCSI_DEV_ATTR_RO(_name) \ -static struct target_stat_scsi_dev_attribute \ - target_stat_scsi_dev_##_name = \ - __CONFIGFS_EATTR_RO(_name, \ - target_stat_scsi_dev_show_attr_##_name); +static struct se_device *to_stat_dev(struct config_item *item) +{ + struct se_dev_stat_grps *sgrps = container_of(to_config_group(item), + struct se_dev_stat_grps, scsi_dev_group); + return container_of(sgrps, struct se_device, dev_stat_grps); +} -static ssize_t target_stat_scsi_dev_show_attr_inst( - struct se_dev_stat_grps *sgrps, char *page) +static ssize_t target_stat_inst_show(struct config_item *item, char *page) { - struct se_device *dev = - container_of(sgrps, struct se_device, dev_stat_grps); - struct se_hba *hba = dev->se_hba; + struct se_hba *hba = to_stat_dev(item)->se_hba; return snprintf(page, PAGE_SIZE, "%u\n", hba->hba_index); } -DEV_STAT_SCSI_DEV_ATTR_RO(inst); -static ssize_t target_stat_scsi_dev_show_attr_indx( - struct se_dev_stat_grps *sgrps, char *page) +static ssize_t target_stat_indx_show(struct config_item *item, char *page) { - struct se_device *dev = - container_of(sgrps, struct se_device, dev_stat_grps); - - return snprintf(page, PAGE_SIZE, "%u\n", dev->dev_index); + return snprintf(page, PAGE_SIZE, "%u\n", to_stat_dev(item)->dev_index); } -DEV_STAT_SCSI_DEV_ATTR_RO(indx); -static ssize_t target_stat_scsi_dev_show_attr_role( - struct se_dev_stat_grps *sgrps, char *page) +static ssize_t target_stat_role_show(struct config_item *item, char *page) { return snprintf(page, PAGE_SIZE, "Target\n"); } -DEV_STAT_SCSI_DEV_ATTR_RO(role); -static ssize_t target_stat_scsi_dev_show_attr_ports( - struct se_dev_stat_grps *sgrps, char *page) +static ssize_t target_stat_ports_show(struct config_item *item, char *page) { - struct se_device *dev = - container_of(sgrps, struct se_device, dev_stat_grps); - - return snprintf(page, PAGE_SIZE, "%u\n", dev->export_count); + return snprintf(page, PAGE_SIZE, "%u\n", to_stat_dev(item)->export_count); } -DEV_STAT_SCSI_DEV_ATTR_RO(ports); -CONFIGFS_EATTR_OPS(target_stat_scsi_dev, se_dev_stat_grps, scsi_dev_group); +CONFIGFS_ATTR_RO(target_stat_, inst); +CONFIGFS_ATTR_RO(target_stat_, indx); +CONFIGFS_ATTR_RO(target_stat_, role); +CONFIGFS_ATTR_RO(target_stat_, ports); static struct configfs_attribute *target_stat_scsi_dev_attrs[] = { - &target_stat_scsi_dev_inst.attr, - &target_stat_scsi_dev_indx.attr, - &target_stat_scsi_dev_role.attr, - &target_stat_scsi_dev_ports.attr, + &target_stat_attr_inst, + &target_stat_attr_indx, + &target_stat_attr_role, + &target_stat_attr_ports, NULL, }; -static struct configfs_item_operations target_stat_scsi_dev_attrib_ops = { - .show_attribute = target_stat_scsi_dev_attr_show, - .store_attribute = target_stat_scsi_dev_attr_store, -}; - static struct config_item_type target_stat_scsi_dev_cit = { - .ct_item_ops = &target_stat_scsi_dev_attrib_ops, .ct_attrs = target_stat_scsi_dev_attrs, .ct_owner = THIS_MODULE, }; @@ -131,109 +104,78 @@ static struct config_item_type target_stat_scsi_dev_cit = { /* * SCSI Target Device Table */ +static struct se_device *to_stat_tgt_dev(struct config_item *item) +{ + struct se_dev_stat_grps *sgrps = container_of(to_config_group(item), + struct se_dev_stat_grps, scsi_tgt_dev_group); + return container_of(sgrps, struct se_device, dev_stat_grps); +} -CONFIGFS_EATTR_STRUCT(target_stat_scsi_tgt_dev, se_dev_stat_grps); -#define DEV_STAT_SCSI_TGT_DEV_ATTR(_name, _mode) \ -static struct target_stat_scsi_tgt_dev_attribute \ - target_stat_scsi_tgt_dev_##_name = \ - __CONFIGFS_EATTR(_name, _mode, \ - target_stat_scsi_tgt_dev_show_attr_##_name, \ - target_stat_scsi_tgt_dev_store_attr_##_name); - -#define DEV_STAT_SCSI_TGT_DEV_ATTR_RO(_name) \ -static struct target_stat_scsi_tgt_dev_attribute \ - target_stat_scsi_tgt_dev_##_name = \ - __CONFIGFS_EATTR_RO(_name, \ - target_stat_scsi_tgt_dev_show_attr_##_name); - -static ssize_t target_stat_scsi_tgt_dev_show_attr_inst( - struct se_dev_stat_grps *sgrps, char *page) +static ssize_t target_stat_tgt_inst_show(struct config_item *item, char *page) { - struct se_device *dev = - container_of(sgrps, struct se_device, dev_stat_grps); - struct se_hba *hba = dev->se_hba; + struct se_hba *hba = to_stat_tgt_dev(item)->se_hba; return snprintf(page, PAGE_SIZE, "%u\n", hba->hba_index); } -DEV_STAT_SCSI_TGT_DEV_ATTR_RO(inst); -static ssize_t target_stat_scsi_tgt_dev_show_attr_indx( - struct se_dev_stat_grps *sgrps, char *page) +static ssize_t target_stat_tgt_indx_show(struct config_item *item, char *page) { - struct se_device *dev = - container_of(sgrps, struct se_device, dev_stat_grps); - - return snprintf(page, PAGE_SIZE, "%u\n", dev->dev_index); + return snprintf(page, PAGE_SIZE, "%u\n", to_stat_tgt_dev(item)->dev_index); } -DEV_STAT_SCSI_TGT_DEV_ATTR_RO(indx); -static ssize_t target_stat_scsi_tgt_dev_show_attr_num_lus( - struct se_dev_stat_grps *sgrps, char *page) +static ssize_t target_stat_tgt_num_lus_show(struct config_item *item, + char *page) { return snprintf(page, PAGE_SIZE, "%u\n", LU_COUNT); } -DEV_STAT_SCSI_TGT_DEV_ATTR_RO(num_lus); -static ssize_t target_stat_scsi_tgt_dev_show_attr_status( - struct se_dev_stat_grps *sgrps, char *page) +static ssize_t target_stat_tgt_status_show(struct config_item *item, + char *page) { - struct se_device *dev = - container_of(sgrps, struct se_device, dev_stat_grps); - - if (dev->export_count) + if (to_stat_tgt_dev(item)->export_count) return snprintf(page, PAGE_SIZE, "activated"); else return snprintf(page, PAGE_SIZE, "deactivated"); } -DEV_STAT_SCSI_TGT_DEV_ATTR_RO(status); -static ssize_t target_stat_scsi_tgt_dev_show_attr_non_access_lus( - struct se_dev_stat_grps *sgrps, char *page) +static ssize_t target_stat_tgt_non_access_lus_show(struct config_item *item, + char *page) { - struct se_device *dev = - container_of(sgrps, struct se_device, dev_stat_grps); int non_accessible_lus; - if (dev->export_count) + if (to_stat_tgt_dev(item)->export_count) non_accessible_lus = 0; else non_accessible_lus = 1; return snprintf(page, PAGE_SIZE, "%u\n", non_accessible_lus); } -DEV_STAT_SCSI_TGT_DEV_ATTR_RO(non_access_lus); -static ssize_t target_stat_scsi_tgt_dev_show_attr_resets( - struct se_dev_stat_grps *sgrps, char *page) +static ssize_t target_stat_tgt_resets_show(struct config_item *item, + char *page) { - struct se_device *dev = - container_of(sgrps, struct se_device, dev_stat_grps); - return snprintf(page, PAGE_SIZE, "%lu\n", - atomic_long_read(&dev->num_resets)); + atomic_long_read(&to_stat_tgt_dev(item)->num_resets)); } -DEV_STAT_SCSI_TGT_DEV_ATTR_RO(resets); - -CONFIGFS_EATTR_OPS(target_stat_scsi_tgt_dev, se_dev_stat_grps, scsi_tgt_dev_group); +CONFIGFS_ATTR_RO(target_stat_tgt_, inst); +CONFIGFS_ATTR_RO(target_stat_tgt_, indx); +CONFIGFS_ATTR_RO(target_stat_tgt_, num_lus); +CONFIGFS_ATTR_RO(target_stat_tgt_, status); +CONFIGFS_ATTR_RO(target_stat_tgt_, non_access_lus); +CONFIGFS_ATTR_RO(target_stat_tgt_, resets); static struct configfs_attribute *target_stat_scsi_tgt_dev_attrs[] = { - &target_stat_scsi_tgt_dev_inst.attr, - &target_stat_scsi_tgt_dev_indx.attr, - &target_stat_scsi_tgt_dev_num_lus.attr, - &target_stat_scsi_tgt_dev_status.attr, - &target_stat_scsi_tgt_dev_non_access_lus.attr, - &target_stat_scsi_tgt_dev_resets.attr, + &target_stat_tgt_attr_inst, + &target_stat_tgt_attr_indx, + &target_stat_tgt_attr_num_lus, + &target_stat_tgt_attr_status, + &target_stat_tgt_attr_non_access_lus, + &target_stat_tgt_attr_resets, NULL, }; -static struct configfs_item_operations target_stat_scsi_tgt_dev_attrib_ops = { - .show_attribute = target_stat_scsi_tgt_dev_attr_show, - .store_attribute = target_stat_scsi_tgt_dev_attr_store, -}; - static struct config_item_type target_stat_scsi_tgt_dev_cit = { - .ct_item_ops = &target_stat_scsi_tgt_dev_attrib_ops, .ct_attrs = target_stat_scsi_tgt_dev_attrs, .ct_owner = THIS_MODULE, }; @@ -242,72 +184,50 @@ static struct config_item_type target_stat_scsi_tgt_dev_cit = { * SCSI Logical Unit Table */ -CONFIGFS_EATTR_STRUCT(target_stat_scsi_lu, se_dev_stat_grps); -#define DEV_STAT_SCSI_LU_ATTR(_name, _mode) \ -static struct target_stat_scsi_lu_attribute target_stat_scsi_lu_##_name = \ - __CONFIGFS_EATTR(_name, _mode, \ - target_stat_scsi_lu_show_attr_##_name, \ - target_stat_scsi_lu_store_attr_##_name); - -#define DEV_STAT_SCSI_LU_ATTR_RO(_name) \ -static struct target_stat_scsi_lu_attribute target_stat_scsi_lu_##_name = \ - __CONFIGFS_EATTR_RO(_name, \ - target_stat_scsi_lu_show_attr_##_name); +static struct se_device *to_stat_lu_dev(struct config_item *item) +{ + struct se_dev_stat_grps *sgrps = container_of(to_config_group(item), + struct se_dev_stat_grps, scsi_lu_group); + return container_of(sgrps, struct se_device, dev_stat_grps); +} -static ssize_t target_stat_scsi_lu_show_attr_inst( - struct se_dev_stat_grps *sgrps, char *page) +static ssize_t target_stat_lu_inst_show(struct config_item *item, char *page) { - struct se_device *dev = - container_of(sgrps, struct se_device, dev_stat_grps); - struct se_hba *hba = dev->se_hba; + struct se_hba *hba = to_stat_lu_dev(item)->se_hba; return snprintf(page, PAGE_SIZE, "%u\n", hba->hba_index); } -DEV_STAT_SCSI_LU_ATTR_RO(inst); -static ssize_t target_stat_scsi_lu_show_attr_dev( - struct se_dev_stat_grps *sgrps, char *page) +static ssize_t target_stat_lu_dev_show(struct config_item *item, char *page) { - struct se_device *dev = - container_of(sgrps, struct se_device, dev_stat_grps); - - return snprintf(page, PAGE_SIZE, "%u\n", dev->dev_index); + return snprintf(page, PAGE_SIZE, "%u\n", + to_stat_lu_dev(item)->dev_index); } -DEV_STAT_SCSI_LU_ATTR_RO(dev); -static ssize_t target_stat_scsi_lu_show_attr_indx( - struct se_dev_stat_grps *sgrps, char *page) +static ssize_t target_stat_lu_indx_show(struct config_item *item, char *page) { return snprintf(page, PAGE_SIZE, "%u\n", SCSI_LU_INDEX); } -DEV_STAT_SCSI_LU_ATTR_RO(indx); -static ssize_t target_stat_scsi_lu_show_attr_lun( - struct se_dev_stat_grps *sgrps, char *page) +static ssize_t target_stat_lu_lun_show(struct config_item *item, char *page) { /* FIXME: scsiLuDefaultLun */ return snprintf(page, PAGE_SIZE, "%llu\n", (unsigned long long)0); } -DEV_STAT_SCSI_LU_ATTR_RO(lun); -static ssize_t target_stat_scsi_lu_show_attr_lu_name( - struct se_dev_stat_grps *sgrps, char *page) +static ssize_t target_stat_lu_lu_name_show(struct config_item *item, char *page) { - struct se_device *dev = - container_of(sgrps, struct se_device, dev_stat_grps); + struct se_device *dev = to_stat_lu_dev(item); /* scsiLuWwnName */ return snprintf(page, PAGE_SIZE, "%s\n", (strlen(dev->t10_wwn.unit_serial)) ? dev->t10_wwn.unit_serial : "None"); } -DEV_STAT_SCSI_LU_ATTR_RO(lu_name); -static ssize_t target_stat_scsi_lu_show_attr_vend( - struct se_dev_stat_grps *sgrps, char *page) +static ssize_t target_stat_lu_vend_show(struct config_item *item, char *page) { - struct se_device *dev = - container_of(sgrps, struct se_device, dev_stat_grps); + struct se_device *dev = to_stat_lu_dev(item); int i; char str[sizeof(dev->t10_wwn.vendor)+1]; @@ -318,13 +238,10 @@ static ssize_t target_stat_scsi_lu_show_attr_vend( str[i] = '\0'; return snprintf(page, PAGE_SIZE, "%s\n", str); } -DEV_STAT_SCSI_LU_ATTR_RO(vend); -static ssize_t target_stat_scsi_lu_show_attr_prod( - struct se_dev_stat_grps *sgrps, char *page) +static ssize_t target_stat_lu_prod_show(struct config_item *item, char *page) { - struct se_device *dev = - container_of(sgrps, struct se_device, dev_stat_grps); + struct se_device *dev = to_stat_lu_dev(item); int i; char str[sizeof(dev->t10_wwn.model)+1]; @@ -335,13 +252,10 @@ static ssize_t target_stat_scsi_lu_show_attr_prod( str[i] = '\0'; return snprintf(page, PAGE_SIZE, "%s\n", str); } -DEV_STAT_SCSI_LU_ATTR_RO(prod); -static ssize_t target_stat_scsi_lu_show_attr_rev( - struct se_dev_stat_grps *sgrps, char *page) +static ssize_t target_stat_lu_rev_show(struct config_item *item, char *page) { - struct se_device *dev = - container_of(sgrps, struct se_device, dev_stat_grps); + struct se_device *dev = to_stat_lu_dev(item); int i; char str[sizeof(dev->t10_wwn.revision)+1]; @@ -352,146 +266,137 @@ static ssize_t target_stat_scsi_lu_show_attr_rev( str[i] = '\0'; return snprintf(page, PAGE_SIZE, "%s\n", str); } -DEV_STAT_SCSI_LU_ATTR_RO(rev); -static ssize_t target_stat_scsi_lu_show_attr_dev_type( - struct se_dev_stat_grps *sgrps, char *page) +static ssize_t target_stat_lu_dev_type_show(struct config_item *item, char *page) { - struct se_device *dev = - container_of(sgrps, struct se_device, dev_stat_grps); + struct se_device *dev = to_stat_lu_dev(item); /* scsiLuPeripheralType */ return snprintf(page, PAGE_SIZE, "%u\n", dev->transport->get_device_type(dev)); } -DEV_STAT_SCSI_LU_ATTR_RO(dev_type); -static ssize_t target_stat_scsi_lu_show_attr_status( - struct se_dev_stat_grps *sgrps, char *page) +static ssize_t target_stat_lu_status_show(struct config_item *item, char *page) { - struct se_device *dev = - container_of(sgrps, struct se_device, dev_stat_grps); + struct se_device *dev = to_stat_lu_dev(item); /* scsiLuStatus */ return snprintf(page, PAGE_SIZE, "%s\n", (dev->export_count) ? "available" : "notavailable"); } -DEV_STAT_SCSI_LU_ATTR_RO(status); -static ssize_t target_stat_scsi_lu_show_attr_state_bit( - struct se_dev_stat_grps *sgrps, char *page) +static ssize_t target_stat_lu_state_bit_show(struct config_item *item, + char *page) { /* scsiLuState */ return snprintf(page, PAGE_SIZE, "exposed\n"); } -DEV_STAT_SCSI_LU_ATTR_RO(state_bit); -static ssize_t target_stat_scsi_lu_show_attr_num_cmds( - struct se_dev_stat_grps *sgrps, char *page) +static ssize_t target_stat_lu_num_cmds_show(struct config_item *item, + char *page) { - struct se_device *dev = - container_of(sgrps, struct se_device, dev_stat_grps); + struct se_device *dev = to_stat_lu_dev(item); /* scsiLuNumCommands */ return snprintf(page, PAGE_SIZE, "%lu\n", atomic_long_read(&dev->num_cmds)); } -DEV_STAT_SCSI_LU_ATTR_RO(num_cmds); -static ssize_t target_stat_scsi_lu_show_attr_read_mbytes( - struct se_dev_stat_grps *sgrps, char *page) +static ssize_t target_stat_lu_read_mbytes_show(struct config_item *item, + char *page) { - struct se_device *dev = - container_of(sgrps, struct se_device, dev_stat_grps); + struct se_device *dev = to_stat_lu_dev(item); /* scsiLuReadMegaBytes */ return snprintf(page, PAGE_SIZE, "%lu\n", atomic_long_read(&dev->read_bytes) >> 20); } -DEV_STAT_SCSI_LU_ATTR_RO(read_mbytes); -static ssize_t target_stat_scsi_lu_show_attr_write_mbytes( - struct se_dev_stat_grps *sgrps, char *page) +static ssize_t target_stat_lu_write_mbytes_show(struct config_item *item, + char *page) { - struct se_device *dev = - container_of(sgrps, struct se_device, dev_stat_grps); + struct se_device *dev = to_stat_lu_dev(item); /* scsiLuWrittenMegaBytes */ return snprintf(page, PAGE_SIZE, "%lu\n", atomic_long_read(&dev->write_bytes) >> 20); } -DEV_STAT_SCSI_LU_ATTR_RO(write_mbytes); -static ssize_t target_stat_scsi_lu_show_attr_resets( - struct se_dev_stat_grps *sgrps, char *page) +static ssize_t target_stat_lu_resets_show(struct config_item *item, char *page) { - struct se_device *dev = - container_of(sgrps, struct se_device, dev_stat_grps); + struct se_device *dev = to_stat_lu_dev(item); /* scsiLuInResets */ - return snprintf(page, PAGE_SIZE, "%lu\n", atomic_long_read(&dev->num_resets)); + return snprintf(page, PAGE_SIZE, "%lu\n", + atomic_long_read(&dev->num_resets)); } -DEV_STAT_SCSI_LU_ATTR_RO(resets); -static ssize_t target_stat_scsi_lu_show_attr_full_stat( - struct se_dev_stat_grps *sgrps, char *page) +static ssize_t target_stat_lu_full_stat_show(struct config_item *item, + char *page) { /* FIXME: scsiLuOutTaskSetFullStatus */ return snprintf(page, PAGE_SIZE, "%u\n", 0); } -DEV_STAT_SCSI_LU_ATTR_RO(full_stat); -static ssize_t target_stat_scsi_lu_show_attr_hs_num_cmds( - struct se_dev_stat_grps *sgrps, char *page) +static ssize_t target_stat_lu_hs_num_cmds_show(struct config_item *item, + char *page) { /* FIXME: scsiLuHSInCommands */ return snprintf(page, PAGE_SIZE, "%u\n", 0); } -DEV_STAT_SCSI_LU_ATTR_RO(hs_num_cmds); -static ssize_t target_stat_scsi_lu_show_attr_creation_time( - struct se_dev_stat_grps *sgrps, char *page) +static ssize_t target_stat_lu_creation_time_show(struct config_item *item, + char *page) { - struct se_device *dev = - container_of(sgrps, struct se_device, dev_stat_grps); + struct se_device *dev = to_stat_lu_dev(item); /* scsiLuCreationTime */ return snprintf(page, PAGE_SIZE, "%u\n", (u32)(((u32)dev->creation_time - INITIAL_JIFFIES) * 100 / HZ)); } -DEV_STAT_SCSI_LU_ATTR_RO(creation_time); -CONFIGFS_EATTR_OPS(target_stat_scsi_lu, se_dev_stat_grps, scsi_lu_group); +CONFIGFS_ATTR_RO(target_stat_lu_, inst); +CONFIGFS_ATTR_RO(target_stat_lu_, dev); +CONFIGFS_ATTR_RO(target_stat_lu_, indx); +CONFIGFS_ATTR_RO(target_stat_lu_, lun); +CONFIGFS_ATTR_RO(target_stat_lu_, lu_name); +CONFIGFS_ATTR_RO(target_stat_lu_, vend); +CONFIGFS_ATTR_RO(target_stat_lu_, prod); +CONFIGFS_ATTR_RO(target_stat_lu_, rev); +CONFIGFS_ATTR_RO(target_stat_lu_, dev_type); +CONFIGFS_ATTR_RO(target_stat_lu_, status); +CONFIGFS_ATTR_RO(target_stat_lu_, state_bit); +CONFIGFS_ATTR_RO(target_stat_lu_, num_cmds); +CONFIGFS_ATTR_RO(target_stat_lu_, read_mbytes); +CONFIGFS_ATTR_RO(target_stat_lu_, write_mbytes); +CONFIGFS_ATTR_RO(target_stat_lu_, resets); +CONFIGFS_ATTR_RO(target_stat_lu_, full_stat); +CONFIGFS_ATTR_RO(target_stat_lu_, hs_num_cmds); +CONFIGFS_ATTR_RO(target_stat_lu_, creation_time); static struct configfs_attribute *target_stat_scsi_lu_attrs[] = { - &target_stat_scsi_lu_inst.attr, - &target_stat_scsi_lu_dev.attr, - &target_stat_scsi_lu_indx.attr, - &target_stat_scsi_lu_lun.attr, - &target_stat_scsi_lu_lu_name.attr, - &target_stat_scsi_lu_vend.attr, - &target_stat_scsi_lu_prod.attr, - &target_stat_scsi_lu_rev.attr, - &target_stat_scsi_lu_dev_type.attr, - &target_stat_scsi_lu_status.attr, - &target_stat_scsi_lu_state_bit.attr, - &target_stat_scsi_lu_num_cmds.attr, - &target_stat_scsi_lu_read_mbytes.attr, - &target_stat_scsi_lu_write_mbytes.attr, - &target_stat_scsi_lu_resets.attr, - &target_stat_scsi_lu_full_stat.attr, - &target_stat_scsi_lu_hs_num_cmds.attr, - &target_stat_scsi_lu_creation_time.attr, + &target_stat_lu_attr_inst, + &target_stat_lu_attr_dev, + &target_stat_lu_attr_indx, + &target_stat_lu_attr_lun, + &target_stat_lu_attr_lu_name, + &target_stat_lu_attr_vend, + &target_stat_lu_attr_prod, + &target_stat_lu_attr_rev, + &target_stat_lu_attr_dev_type, + &target_stat_lu_attr_status, + &target_stat_lu_attr_state_bit, + &target_stat_lu_attr_num_cmds, + &target_stat_lu_attr_read_mbytes, + &target_stat_lu_attr_write_mbytes, + &target_stat_lu_attr_resets, + &target_stat_lu_attr_full_stat, + &target_stat_lu_attr_hs_num_cmds, + &target_stat_lu_attr_creation_time, NULL, }; -static struct configfs_item_operations target_stat_scsi_lu_attrib_ops = { - .show_attribute = target_stat_scsi_lu_attr_show, - .store_attribute = target_stat_scsi_lu_attr_store, -}; - static struct config_item_type target_stat_scsi_lu_cit = { - .ct_item_ops = &target_stat_scsi_lu_attrib_ops, .ct_attrs = target_stat_scsi_lu_attrs, .ct_owner = THIS_MODULE, }; @@ -521,24 +426,16 @@ void target_stat_setup_dev_default_groups(struct se_device *dev) * SCSI Port Table */ -CONFIGFS_EATTR_STRUCT(target_stat_scsi_port, se_port_stat_grps); -#define DEV_STAT_SCSI_PORT_ATTR(_name, _mode) \ -static struct target_stat_scsi_port_attribute \ - target_stat_scsi_port_##_name = \ - __CONFIGFS_EATTR(_name, _mode, \ - target_stat_scsi_port_show_attr_##_name, \ - target_stat_scsi_port_store_attr_##_name); - -#define DEV_STAT_SCSI_PORT_ATTR_RO(_name) \ -static struct target_stat_scsi_port_attribute \ - target_stat_scsi_port_##_name = \ - __CONFIGFS_EATTR_RO(_name, \ - target_stat_scsi_port_show_attr_##_name); +static struct se_lun *to_stat_port(struct config_item *item) +{ + struct se_port_stat_grps *pgrps = container_of(to_config_group(item), + struct se_port_stat_grps, scsi_port_group); + return container_of(pgrps, struct se_lun, port_stat_grps); +} -static ssize_t target_stat_scsi_port_show_attr_inst( - struct se_port_stat_grps *pgrps, char *page) +static ssize_t target_stat_port_inst_show(struct config_item *item, char *page) { - struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + struct se_lun *lun = to_stat_port(item); struct se_device *dev; ssize_t ret = -ENODEV; @@ -549,12 +446,10 @@ static ssize_t target_stat_scsi_port_show_attr_inst( rcu_read_unlock(); return ret; } -DEV_STAT_SCSI_PORT_ATTR_RO(inst); -static ssize_t target_stat_scsi_port_show_attr_dev( - struct se_port_stat_grps *pgrps, char *page) +static ssize_t target_stat_port_dev_show(struct config_item *item, char *page) { - struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + struct se_lun *lun = to_stat_port(item); struct se_device *dev; ssize_t ret = -ENODEV; @@ -565,12 +460,10 @@ static ssize_t target_stat_scsi_port_show_attr_dev( rcu_read_unlock(); return ret; } -DEV_STAT_SCSI_PORT_ATTR_RO(dev); -static ssize_t target_stat_scsi_port_show_attr_indx( - struct se_port_stat_grps *pgrps, char *page) +static ssize_t target_stat_port_indx_show(struct config_item *item, char *page) { - struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + struct se_lun *lun = to_stat_port(item); struct se_device *dev; ssize_t ret = -ENODEV; @@ -581,12 +474,10 @@ static ssize_t target_stat_scsi_port_show_attr_indx( rcu_read_unlock(); return ret; } -DEV_STAT_SCSI_PORT_ATTR_RO(indx); -static ssize_t target_stat_scsi_port_show_attr_role( - struct se_port_stat_grps *pgrps, char *page) +static ssize_t target_stat_port_role_show(struct config_item *item, char *page) { - struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + struct se_lun *lun = to_stat_port(item); struct se_device *dev; ssize_t ret = -ENODEV; @@ -597,12 +488,11 @@ static ssize_t target_stat_scsi_port_show_attr_role( rcu_read_unlock(); return ret; } -DEV_STAT_SCSI_PORT_ATTR_RO(role); -static ssize_t target_stat_scsi_port_show_attr_busy_count( - struct se_port_stat_grps *pgrps, char *page) +static ssize_t target_stat_port_busy_count_show(struct config_item *item, + char *page) { - struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + struct se_lun *lun = to_stat_port(item); struct se_device *dev; ssize_t ret = -ENODEV; @@ -615,26 +505,23 @@ static ssize_t target_stat_scsi_port_show_attr_busy_count( rcu_read_unlock(); return ret; } -DEV_STAT_SCSI_PORT_ATTR_RO(busy_count); -CONFIGFS_EATTR_OPS(target_stat_scsi_port, se_port_stat_grps, scsi_port_group); +CONFIGFS_ATTR_RO(target_stat_port_, inst); +CONFIGFS_ATTR_RO(target_stat_port_, dev); +CONFIGFS_ATTR_RO(target_stat_port_, indx); +CONFIGFS_ATTR_RO(target_stat_port_, role); +CONFIGFS_ATTR_RO(target_stat_port_, busy_count); static struct configfs_attribute *target_stat_scsi_port_attrs[] = { - &target_stat_scsi_port_inst.attr, - &target_stat_scsi_port_dev.attr, - &target_stat_scsi_port_indx.attr, - &target_stat_scsi_port_role.attr, - &target_stat_scsi_port_busy_count.attr, + &target_stat_port_attr_inst, + &target_stat_port_attr_dev, + &target_stat_port_attr_indx, + &target_stat_port_attr_role, + &target_stat_port_attr_busy_count, NULL, }; -static struct configfs_item_operations target_stat_scsi_port_attrib_ops = { - .show_attribute = target_stat_scsi_port_attr_show, - .store_attribute = target_stat_scsi_port_attr_store, -}; - static struct config_item_type target_stat_scsi_port_cit = { - .ct_item_ops = &target_stat_scsi_port_attrib_ops, .ct_attrs = target_stat_scsi_port_attrs, .ct_owner = THIS_MODULE, }; @@ -642,24 +529,17 @@ static struct config_item_type target_stat_scsi_port_cit = { /* * SCSI Target Port Table */ -CONFIGFS_EATTR_STRUCT(target_stat_scsi_tgt_port, se_port_stat_grps); -#define DEV_STAT_SCSI_TGT_PORT_ATTR(_name, _mode) \ -static struct target_stat_scsi_tgt_port_attribute \ - target_stat_scsi_tgt_port_##_name = \ - __CONFIGFS_EATTR(_name, _mode, \ - target_stat_scsi_tgt_port_show_attr_##_name, \ - target_stat_scsi_tgt_port_store_attr_##_name); - -#define DEV_STAT_SCSI_TGT_PORT_ATTR_RO(_name) \ -static struct target_stat_scsi_tgt_port_attribute \ - target_stat_scsi_tgt_port_##_name = \ - __CONFIGFS_EATTR_RO(_name, \ - target_stat_scsi_tgt_port_show_attr_##_name); - -static ssize_t target_stat_scsi_tgt_port_show_attr_inst( - struct se_port_stat_grps *pgrps, char *page) -{ - struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); +static struct se_lun *to_stat_tgt_port(struct config_item *item) +{ + struct se_port_stat_grps *pgrps = container_of(to_config_group(item), + struct se_port_stat_grps, scsi_tgt_port_group); + return container_of(pgrps, struct se_lun, port_stat_grps); +} + +static ssize_t target_stat_tgt_port_inst_show(struct config_item *item, + char *page) +{ + struct se_lun *lun = to_stat_tgt_port(item); struct se_device *dev; ssize_t ret = -ENODEV; @@ -670,12 +550,11 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_inst( rcu_read_unlock(); return ret; } -DEV_STAT_SCSI_TGT_PORT_ATTR_RO(inst); -static ssize_t target_stat_scsi_tgt_port_show_attr_dev( - struct se_port_stat_grps *pgrps, char *page) +static ssize_t target_stat_tgt_port_dev_show(struct config_item *item, + char *page) { - struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + struct se_lun *lun = to_stat_tgt_port(item); struct se_device *dev; ssize_t ret = -ENODEV; @@ -686,12 +565,11 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_dev( rcu_read_unlock(); return ret; } -DEV_STAT_SCSI_TGT_PORT_ATTR_RO(dev); -static ssize_t target_stat_scsi_tgt_port_show_attr_indx( - struct se_port_stat_grps *pgrps, char *page) +static ssize_t target_stat_tgt_port_indx_show(struct config_item *item, + char *page) { - struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + struct se_lun *lun = to_stat_tgt_port(item); struct se_device *dev; ssize_t ret = -ENODEV; @@ -702,12 +580,11 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_indx( rcu_read_unlock(); return ret; } -DEV_STAT_SCSI_TGT_PORT_ATTR_RO(indx); -static ssize_t target_stat_scsi_tgt_port_show_attr_name( - struct se_port_stat_grps *pgrps, char *page) +static ssize_t target_stat_tgt_port_name_show(struct config_item *item, + char *page) { - struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + struct se_lun *lun = to_stat_tgt_port(item); struct se_portal_group *tpg = lun->lun_tpg; struct se_device *dev; ssize_t ret = -ENODEV; @@ -721,12 +598,11 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_name( rcu_read_unlock(); return ret; } -DEV_STAT_SCSI_TGT_PORT_ATTR_RO(name); -static ssize_t target_stat_scsi_tgt_port_show_attr_port_index( - struct se_port_stat_grps *pgrps, char *page) +static ssize_t target_stat_tgt_port_port_index_show(struct config_item *item, + char *page) { - struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + struct se_lun *lun = to_stat_tgt_port(item); struct se_portal_group *tpg = lun->lun_tpg; struct se_device *dev; ssize_t ret = -ENODEV; @@ -740,12 +616,11 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_port_index( rcu_read_unlock(); return ret; } -DEV_STAT_SCSI_TGT_PORT_ATTR_RO(port_index); -static ssize_t target_stat_scsi_tgt_port_show_attr_in_cmds( - struct se_port_stat_grps *pgrps, char *page) +static ssize_t target_stat_tgt_port_in_cmds_show(struct config_item *item, + char *page) { - struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + struct se_lun *lun = to_stat_tgt_port(item); struct se_device *dev; ssize_t ret = -ENODEV; @@ -757,12 +632,11 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_in_cmds( rcu_read_unlock(); return ret; } -DEV_STAT_SCSI_TGT_PORT_ATTR_RO(in_cmds); -static ssize_t target_stat_scsi_tgt_port_show_attr_write_mbytes( - struct se_port_stat_grps *pgrps, char *page) +static ssize_t target_stat_tgt_port_write_mbytes_show(struct config_item *item, + char *page) { - struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + struct se_lun *lun = to_stat_tgt_port(item); struct se_device *dev; ssize_t ret = -ENODEV; @@ -774,12 +648,11 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_write_mbytes( rcu_read_unlock(); return ret; } -DEV_STAT_SCSI_TGT_PORT_ATTR_RO(write_mbytes); -static ssize_t target_stat_scsi_tgt_port_show_attr_read_mbytes( - struct se_port_stat_grps *pgrps, char *page) +static ssize_t target_stat_tgt_port_read_mbytes_show(struct config_item *item, + char *page) { - struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + struct se_lun *lun = to_stat_tgt_port(item); struct se_device *dev; ssize_t ret = -ENODEV; @@ -791,12 +664,11 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_read_mbytes( rcu_read_unlock(); return ret; } -DEV_STAT_SCSI_TGT_PORT_ATTR_RO(read_mbytes); -static ssize_t target_stat_scsi_tgt_port_show_attr_hs_in_cmds( - struct se_port_stat_grps *pgrps, char *page) +static ssize_t target_stat_tgt_port_hs_in_cmds_show(struct config_item *item, + char *page) { - struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + struct se_lun *lun = to_stat_tgt_port(item); struct se_device *dev; ssize_t ret = -ENODEV; @@ -809,57 +681,49 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_hs_in_cmds( rcu_read_unlock(); return ret; } -DEV_STAT_SCSI_TGT_PORT_ATTR_RO(hs_in_cmds); -CONFIGFS_EATTR_OPS(target_stat_scsi_tgt_port, se_port_stat_grps, - scsi_tgt_port_group); +CONFIGFS_ATTR_RO(target_stat_tgt_port_, inst); +CONFIGFS_ATTR_RO(target_stat_tgt_port_, dev); +CONFIGFS_ATTR_RO(target_stat_tgt_port_, indx); +CONFIGFS_ATTR_RO(target_stat_tgt_port_, name); +CONFIGFS_ATTR_RO(target_stat_tgt_port_, port_index); +CONFIGFS_ATTR_RO(target_stat_tgt_port_, in_cmds); +CONFIGFS_ATTR_RO(target_stat_tgt_port_, write_mbytes); +CONFIGFS_ATTR_RO(target_stat_tgt_port_, read_mbytes); +CONFIGFS_ATTR_RO(target_stat_tgt_port_, hs_in_cmds); static struct configfs_attribute *target_stat_scsi_tgt_port_attrs[] = { - &target_stat_scsi_tgt_port_inst.attr, - &target_stat_scsi_tgt_port_dev.attr, - &target_stat_scsi_tgt_port_indx.attr, - &target_stat_scsi_tgt_port_name.attr, - &target_stat_scsi_tgt_port_port_index.attr, - &target_stat_scsi_tgt_port_in_cmds.attr, - &target_stat_scsi_tgt_port_write_mbytes.attr, - &target_stat_scsi_tgt_port_read_mbytes.attr, - &target_stat_scsi_tgt_port_hs_in_cmds.attr, + &target_stat_tgt_port_attr_inst, + &target_stat_tgt_port_attr_dev, + &target_stat_tgt_port_attr_indx, + &target_stat_tgt_port_attr_name, + &target_stat_tgt_port_attr_port_index, + &target_stat_tgt_port_attr_in_cmds, + &target_stat_tgt_port_attr_write_mbytes, + &target_stat_tgt_port_attr_read_mbytes, + &target_stat_tgt_port_attr_hs_in_cmds, NULL, }; -static struct configfs_item_operations target_stat_scsi_tgt_port_attrib_ops = { - .show_attribute = target_stat_scsi_tgt_port_attr_show, - .store_attribute = target_stat_scsi_tgt_port_attr_store, -}; - static struct config_item_type target_stat_scsi_tgt_port_cit = { - .ct_item_ops = &target_stat_scsi_tgt_port_attrib_ops, .ct_attrs = target_stat_scsi_tgt_port_attrs, .ct_owner = THIS_MODULE, }; /* * SCSI Transport Table -o */ - -CONFIGFS_EATTR_STRUCT(target_stat_scsi_transport, se_port_stat_grps); -#define DEV_STAT_SCSI_TRANSPORT_ATTR(_name, _mode) \ -static struct target_stat_scsi_transport_attribute \ - target_stat_scsi_transport_##_name = \ - __CONFIGFS_EATTR(_name, _mode, \ - target_stat_scsi_transport_show_attr_##_name, \ - target_stat_scsi_transport_store_attr_##_name); - -#define DEV_STAT_SCSI_TRANSPORT_ATTR_RO(_name) \ -static struct target_stat_scsi_transport_attribute \ - target_stat_scsi_transport_##_name = \ - __CONFIGFS_EATTR_RO(_name, \ - target_stat_scsi_transport_show_attr_##_name); - -static ssize_t target_stat_scsi_transport_show_attr_inst( - struct se_port_stat_grps *pgrps, char *page) -{ - struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + */ +static struct se_lun *to_transport_stat(struct config_item *item) +{ + struct se_port_stat_grps *pgrps = container_of(to_config_group(item), + struct se_port_stat_grps, scsi_transport_group); + return container_of(pgrps, struct se_lun, port_stat_grps); +} + +static ssize_t target_stat_transport_inst_show(struct config_item *item, + char *page) +{ + struct se_lun *lun = to_transport_stat(item); struct se_device *dev; ssize_t ret = -ENODEV; @@ -870,12 +734,11 @@ static ssize_t target_stat_scsi_transport_show_attr_inst( rcu_read_unlock(); return ret; } -DEV_STAT_SCSI_TRANSPORT_ATTR_RO(inst); -static ssize_t target_stat_scsi_transport_show_attr_device( - struct se_port_stat_grps *pgrps, char *page) +static ssize_t target_stat_transport_device_show(struct config_item *item, + char *page) { - struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + struct se_lun *lun = to_transport_stat(item); struct se_device *dev; struct se_portal_group *tpg = lun->lun_tpg; ssize_t ret = -ENODEV; @@ -890,12 +753,11 @@ static ssize_t target_stat_scsi_transport_show_attr_device( rcu_read_unlock(); return ret; } -DEV_STAT_SCSI_TRANSPORT_ATTR_RO(device); -static ssize_t target_stat_scsi_transport_show_attr_indx( - struct se_port_stat_grps *pgrps, char *page) +static ssize_t target_stat_transport_indx_show(struct config_item *item, + char *page) { - struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + struct se_lun *lun = to_transport_stat(item); struct se_device *dev; struct se_portal_group *tpg = lun->lun_tpg; ssize_t ret = -ENODEV; @@ -908,12 +770,11 @@ static ssize_t target_stat_scsi_transport_show_attr_indx( rcu_read_unlock(); return ret; } -DEV_STAT_SCSI_TRANSPORT_ATTR_RO(indx); -static ssize_t target_stat_scsi_transport_show_attr_dev_name( - struct se_port_stat_grps *pgrps, char *page) +static ssize_t target_stat_transport_dev_name_show(struct config_item *item, + char *page) { - struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + struct se_lun *lun = to_transport_stat(item); struct se_device *dev; struct se_portal_group *tpg = lun->lun_tpg; struct t10_wwn *wwn; @@ -932,26 +793,21 @@ static ssize_t target_stat_scsi_transport_show_attr_dev_name( rcu_read_unlock(); return ret; } -DEV_STAT_SCSI_TRANSPORT_ATTR_RO(dev_name); -CONFIGFS_EATTR_OPS(target_stat_scsi_transport, se_port_stat_grps, - scsi_transport_group); +CONFIGFS_ATTR_RO(target_stat_transport_, inst); +CONFIGFS_ATTR_RO(target_stat_transport_, device); +CONFIGFS_ATTR_RO(target_stat_transport_, indx); +CONFIGFS_ATTR_RO(target_stat_transport_, dev_name); static struct configfs_attribute *target_stat_scsi_transport_attrs[] = { - &target_stat_scsi_transport_inst.attr, - &target_stat_scsi_transport_device.attr, - &target_stat_scsi_transport_indx.attr, - &target_stat_scsi_transport_dev_name.attr, + &target_stat_transport_attr_inst, + &target_stat_transport_attr_device, + &target_stat_transport_attr_indx, + &target_stat_transport_attr_dev_name, NULL, }; -static struct configfs_item_operations target_stat_scsi_transport_attrib_ops = { - .show_attribute = target_stat_scsi_transport_attr_show, - .store_attribute = target_stat_scsi_transport_attr_store, -}; - static struct config_item_type target_stat_scsi_transport_cit = { - .ct_item_ops = &target_stat_scsi_transport_attrib_ops, .ct_attrs = target_stat_scsi_transport_attrs, .ct_owner = THIS_MODULE, }; @@ -981,25 +837,17 @@ void target_stat_setup_port_default_groups(struct se_lun *lun) * SCSI Authorized Initiator Table */ -CONFIGFS_EATTR_STRUCT(target_stat_scsi_auth_intr, se_ml_stat_grps); -#define DEV_STAT_SCSI_AUTH_INTR_ATTR(_name, _mode) \ -static struct target_stat_scsi_auth_intr_attribute \ - target_stat_scsi_auth_intr_##_name = \ - __CONFIGFS_EATTR(_name, _mode, \ - target_stat_scsi_auth_intr_show_attr_##_name, \ - target_stat_scsi_auth_intr_store_attr_##_name); - -#define DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(_name) \ -static struct target_stat_scsi_auth_intr_attribute \ - target_stat_scsi_auth_intr_##_name = \ - __CONFIGFS_EATTR_RO(_name, \ - target_stat_scsi_auth_intr_show_attr_##_name); - -static ssize_t target_stat_scsi_auth_intr_show_attr_inst( - struct se_ml_stat_grps *lgrps, char *page) -{ - struct se_lun_acl *lacl = container_of(lgrps, - struct se_lun_acl, ml_stat_grps); +static struct se_lun_acl *auth_to_lacl(struct config_item *item) +{ + struct se_ml_stat_grps *lgrps = container_of(to_config_group(item), + struct se_ml_stat_grps, scsi_auth_intr_group); + return container_of(lgrps, struct se_lun_acl, ml_stat_grps); +} + +static ssize_t target_stat_auth_inst_show(struct config_item *item, + char *page) +{ + struct se_lun_acl *lacl = auth_to_lacl(item); struct se_node_acl *nacl = lacl->se_lun_nacl; struct se_dev_entry *deve; struct se_portal_group *tpg; @@ -1018,13 +866,11 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_inst( rcu_read_unlock(); return ret; } -DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(inst); -static ssize_t target_stat_scsi_auth_intr_show_attr_dev( - struct se_ml_stat_grps *lgrps, char *page) +static ssize_t target_stat_auth_dev_show(struct config_item *item, + char *page) { - struct se_lun_acl *lacl = container_of(lgrps, - struct se_lun_acl, ml_stat_grps); + struct se_lun_acl *lacl = auth_to_lacl(item); struct se_node_acl *nacl = lacl->se_lun_nacl; struct se_dev_entry *deve; struct se_lun *lun; @@ -1042,13 +888,11 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_dev( rcu_read_unlock(); return ret; } -DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(dev); -static ssize_t target_stat_scsi_auth_intr_show_attr_port( - struct se_ml_stat_grps *lgrps, char *page) +static ssize_t target_stat_auth_port_show(struct config_item *item, + char *page) { - struct se_lun_acl *lacl = container_of(lgrps, - struct se_lun_acl, ml_stat_grps); + struct se_lun_acl *lacl = auth_to_lacl(item); struct se_node_acl *nacl = lacl->se_lun_nacl; struct se_dev_entry *deve; struct se_portal_group *tpg; @@ -1066,13 +910,11 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_port( rcu_read_unlock(); return ret; } -DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(port); -static ssize_t target_stat_scsi_auth_intr_show_attr_indx( - struct se_ml_stat_grps *lgrps, char *page) +static ssize_t target_stat_auth_indx_show(struct config_item *item, + char *page) { - struct se_lun_acl *lacl = container_of(lgrps, - struct se_lun_acl, ml_stat_grps); + struct se_lun_acl *lacl = auth_to_lacl(item); struct se_node_acl *nacl = lacl->se_lun_nacl; struct se_dev_entry *deve; ssize_t ret; @@ -1088,13 +930,11 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_indx( rcu_read_unlock(); return ret; } -DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(indx); -static ssize_t target_stat_scsi_auth_intr_show_attr_dev_or_port( - struct se_ml_stat_grps *lgrps, char *page) +static ssize_t target_stat_auth_dev_or_port_show(struct config_item *item, + char *page) { - struct se_lun_acl *lacl = container_of(lgrps, - struct se_lun_acl, ml_stat_grps); + struct se_lun_acl *lacl = auth_to_lacl(item); struct se_node_acl *nacl = lacl->se_lun_nacl; struct se_dev_entry *deve; ssize_t ret; @@ -1110,13 +950,11 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_dev_or_port( rcu_read_unlock(); return ret; } -DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(dev_or_port); -static ssize_t target_stat_scsi_auth_intr_show_attr_intr_name( - struct se_ml_stat_grps *lgrps, char *page) +static ssize_t target_stat_auth_intr_name_show(struct config_item *item, + char *page) { - struct se_lun_acl *lacl = container_of(lgrps, - struct se_lun_acl, ml_stat_grps); + struct se_lun_acl *lacl = auth_to_lacl(item); struct se_node_acl *nacl = lacl->se_lun_nacl; struct se_dev_entry *deve; ssize_t ret; @@ -1132,13 +970,11 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_intr_name( rcu_read_unlock(); return ret; } -DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(intr_name); -static ssize_t target_stat_scsi_auth_intr_show_attr_map_indx( - struct se_ml_stat_grps *lgrps, char *page) +static ssize_t target_stat_auth_map_indx_show(struct config_item *item, + char *page) { - struct se_lun_acl *lacl = container_of(lgrps, - struct se_lun_acl, ml_stat_grps); + struct se_lun_acl *lacl = auth_to_lacl(item); struct se_node_acl *nacl = lacl->se_lun_nacl; struct se_dev_entry *deve; ssize_t ret; @@ -1154,13 +990,11 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_map_indx( rcu_read_unlock(); return ret; } -DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(map_indx); -static ssize_t target_stat_scsi_auth_intr_show_attr_att_count( - struct se_ml_stat_grps *lgrps, char *page) +static ssize_t target_stat_auth_att_count_show(struct config_item *item, + char *page) { - struct se_lun_acl *lacl = container_of(lgrps, - struct se_lun_acl, ml_stat_grps); + struct se_lun_acl *lacl = auth_to_lacl(item); struct se_node_acl *nacl = lacl->se_lun_nacl; struct se_dev_entry *deve; ssize_t ret; @@ -1176,13 +1010,11 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_att_count( rcu_read_unlock(); return ret; } -DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(att_count); -static ssize_t target_stat_scsi_auth_intr_show_attr_num_cmds( - struct se_ml_stat_grps *lgrps, char *page) +static ssize_t target_stat_auth_num_cmds_show(struct config_item *item, + char *page) { - struct se_lun_acl *lacl = container_of(lgrps, - struct se_lun_acl, ml_stat_grps); + struct se_lun_acl *lacl = auth_to_lacl(item); struct se_node_acl *nacl = lacl->se_lun_nacl; struct se_dev_entry *deve; ssize_t ret; @@ -1199,13 +1031,11 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_num_cmds( rcu_read_unlock(); return ret; } -DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(num_cmds); -static ssize_t target_stat_scsi_auth_intr_show_attr_read_mbytes( - struct se_ml_stat_grps *lgrps, char *page) +static ssize_t target_stat_auth_read_mbytes_show(struct config_item *item, + char *page) { - struct se_lun_acl *lacl = container_of(lgrps, - struct se_lun_acl, ml_stat_grps); + struct se_lun_acl *lacl = auth_to_lacl(item); struct se_node_acl *nacl = lacl->se_lun_nacl; struct se_dev_entry *deve; ssize_t ret; @@ -1222,13 +1052,11 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_read_mbytes( rcu_read_unlock(); return ret; } -DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(read_mbytes); -static ssize_t target_stat_scsi_auth_intr_show_attr_write_mbytes( - struct se_ml_stat_grps *lgrps, char *page) +static ssize_t target_stat_auth_write_mbytes_show(struct config_item *item, + char *page) { - struct se_lun_acl *lacl = container_of(lgrps, - struct se_lun_acl, ml_stat_grps); + struct se_lun_acl *lacl = auth_to_lacl(item); struct se_node_acl *nacl = lacl->se_lun_nacl; struct se_dev_entry *deve; ssize_t ret; @@ -1245,13 +1073,11 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_write_mbytes( rcu_read_unlock(); return ret; } -DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(write_mbytes); -static ssize_t target_stat_scsi_auth_intr_show_attr_hs_num_cmds( - struct se_ml_stat_grps *lgrps, char *page) +static ssize_t target_stat_auth_hs_num_cmds_show(struct config_item *item, + char *page) { - struct se_lun_acl *lacl = container_of(lgrps, - struct se_lun_acl, ml_stat_grps); + struct se_lun_acl *lacl = auth_to_lacl(item); struct se_node_acl *nacl = lacl->se_lun_nacl; struct se_dev_entry *deve; ssize_t ret; @@ -1267,13 +1093,11 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_hs_num_cmds( rcu_read_unlock(); return ret; } -DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(hs_num_cmds); -static ssize_t target_stat_scsi_auth_intr_show_attr_creation_time( - struct se_ml_stat_grps *lgrps, char *page) +static ssize_t target_stat_auth_creation_time_show(struct config_item *item, + char *page) { - struct se_lun_acl *lacl = container_of(lgrps, - struct se_lun_acl, ml_stat_grps); + struct se_lun_acl *lacl = auth_to_lacl(item); struct se_node_acl *nacl = lacl->se_lun_nacl; struct se_dev_entry *deve; ssize_t ret; @@ -1290,13 +1114,11 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_creation_time( rcu_read_unlock(); return ret; } -DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(creation_time); -static ssize_t target_stat_scsi_auth_intr_show_attr_row_status( - struct se_ml_stat_grps *lgrps, char *page) +static ssize_t target_stat_auth_row_status_show(struct config_item *item, + char *page) { - struct se_lun_acl *lacl = container_of(lgrps, - struct se_lun_acl, ml_stat_grps); + struct se_lun_acl *lacl = auth_to_lacl(item); struct se_node_acl *nacl = lacl->se_lun_nacl; struct se_dev_entry *deve; ssize_t ret; @@ -1312,36 +1134,41 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_row_status( rcu_read_unlock(); return ret; } -DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(row_status); -CONFIGFS_EATTR_OPS(target_stat_scsi_auth_intr, se_ml_stat_grps, - scsi_auth_intr_group); +CONFIGFS_ATTR_RO(target_stat_auth_, inst); +CONFIGFS_ATTR_RO(target_stat_auth_, dev); +CONFIGFS_ATTR_RO(target_stat_auth_, port); +CONFIGFS_ATTR_RO(target_stat_auth_, indx); +CONFIGFS_ATTR_RO(target_stat_auth_, dev_or_port); +CONFIGFS_ATTR_RO(target_stat_auth_, intr_name); +CONFIGFS_ATTR_RO(target_stat_auth_, map_indx); +CONFIGFS_ATTR_RO(target_stat_auth_, att_count); +CONFIGFS_ATTR_RO(target_stat_auth_, num_cmds); +CONFIGFS_ATTR_RO(target_stat_auth_, read_mbytes); +CONFIGFS_ATTR_RO(target_stat_auth_, write_mbytes); +CONFIGFS_ATTR_RO(target_stat_auth_, hs_num_cmds); +CONFIGFS_ATTR_RO(target_stat_auth_, creation_time); +CONFIGFS_ATTR_RO(target_stat_auth_, row_status); static struct configfs_attribute *target_stat_scsi_auth_intr_attrs[] = { - &target_stat_scsi_auth_intr_inst.attr, - &target_stat_scsi_auth_intr_dev.attr, - &target_stat_scsi_auth_intr_port.attr, - &target_stat_scsi_auth_intr_indx.attr, - &target_stat_scsi_auth_intr_dev_or_port.attr, - &target_stat_scsi_auth_intr_intr_name.attr, - &target_stat_scsi_auth_intr_map_indx.attr, - &target_stat_scsi_auth_intr_att_count.attr, - &target_stat_scsi_auth_intr_num_cmds.attr, - &target_stat_scsi_auth_intr_read_mbytes.attr, - &target_stat_scsi_auth_intr_write_mbytes.attr, - &target_stat_scsi_auth_intr_hs_num_cmds.attr, - &target_stat_scsi_auth_intr_creation_time.attr, - &target_stat_scsi_auth_intr_row_status.attr, + &target_stat_auth_attr_inst, + &target_stat_auth_attr_dev, + &target_stat_auth_attr_port, + &target_stat_auth_attr_indx, + &target_stat_auth_attr_dev_or_port, + &target_stat_auth_attr_intr_name, + &target_stat_auth_attr_map_indx, + &target_stat_auth_attr_att_count, + &target_stat_auth_attr_num_cmds, + &target_stat_auth_attr_read_mbytes, + &target_stat_auth_attr_write_mbytes, + &target_stat_auth_attr_hs_num_cmds, + &target_stat_auth_attr_creation_time, + &target_stat_auth_attr_row_status, NULL, }; -static struct configfs_item_operations target_stat_scsi_auth_intr_attrib_ops = { - .show_attribute = target_stat_scsi_auth_intr_attr_show, - .store_attribute = target_stat_scsi_auth_intr_attr_store, -}; - static struct config_item_type target_stat_scsi_auth_intr_cit = { - .ct_item_ops = &target_stat_scsi_auth_intr_attrib_ops, .ct_attrs = target_stat_scsi_auth_intr_attrs, .ct_owner = THIS_MODULE, }; @@ -1350,25 +1177,17 @@ static struct config_item_type target_stat_scsi_auth_intr_cit = { * SCSI Attached Initiator Port Table */ -CONFIGFS_EATTR_STRUCT(target_stat_scsi_att_intr_port, se_ml_stat_grps); -#define DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR(_name, _mode) \ -static struct target_stat_scsi_att_intr_port_attribute \ - target_stat_scsi_att_intr_port_##_name = \ - __CONFIGFS_EATTR(_name, _mode, \ - target_stat_scsi_att_intr_port_show_attr_##_name, \ - target_stat_scsi_att_intr_port_store_attr_##_name); - -#define DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR_RO(_name) \ -static struct target_stat_scsi_att_intr_port_attribute \ - target_stat_scsi_att_intr_port_##_name = \ - __CONFIGFS_EATTR_RO(_name, \ - target_stat_scsi_att_intr_port_show_attr_##_name); - -static ssize_t target_stat_scsi_att_intr_port_show_attr_inst( - struct se_ml_stat_grps *lgrps, char *page) -{ - struct se_lun_acl *lacl = container_of(lgrps, - struct se_lun_acl, ml_stat_grps); +static struct se_lun_acl *iport_to_lacl(struct config_item *item) +{ + struct se_ml_stat_grps *lgrps = container_of(to_config_group(item), + struct se_ml_stat_grps, scsi_att_intr_port_group); + return container_of(lgrps, struct se_lun_acl, ml_stat_grps); +} + +static ssize_t target_stat_iport_inst_show(struct config_item *item, + char *page) +{ + struct se_lun_acl *lacl = iport_to_lacl(item); struct se_node_acl *nacl = lacl->se_lun_nacl; struct se_dev_entry *deve; struct se_portal_group *tpg; @@ -1387,13 +1206,11 @@ static ssize_t target_stat_scsi_att_intr_port_show_attr_inst( rcu_read_unlock(); return ret; } -DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR_RO(inst); -static ssize_t target_stat_scsi_att_intr_port_show_attr_dev( - struct se_ml_stat_grps *lgrps, char *page) +static ssize_t target_stat_iport_dev_show(struct config_item *item, + char *page) { - struct se_lun_acl *lacl = container_of(lgrps, - struct se_lun_acl, ml_stat_grps); + struct se_lun_acl *lacl = iport_to_lacl(item); struct se_node_acl *nacl = lacl->se_lun_nacl; struct se_dev_entry *deve; struct se_lun *lun; @@ -1411,13 +1228,11 @@ static ssize_t target_stat_scsi_att_intr_port_show_attr_dev( rcu_read_unlock(); return ret; } -DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR_RO(dev); -static ssize_t target_stat_scsi_att_intr_port_show_attr_port( - struct se_ml_stat_grps *lgrps, char *page) +static ssize_t target_stat_iport_port_show(struct config_item *item, + char *page) { - struct se_lun_acl *lacl = container_of(lgrps, - struct se_lun_acl, ml_stat_grps); + struct se_lun_acl *lacl = iport_to_lacl(item); struct se_node_acl *nacl = lacl->se_lun_nacl; struct se_dev_entry *deve; struct se_portal_group *tpg; @@ -1435,13 +1250,11 @@ static ssize_t target_stat_scsi_att_intr_port_show_attr_port( rcu_read_unlock(); return ret; } -DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR_RO(port); -static ssize_t target_stat_scsi_att_intr_port_show_attr_indx( - struct se_ml_stat_grps *lgrps, char *page) +static ssize_t target_stat_iport_indx_show(struct config_item *item, + char *page) { - struct se_lun_acl *lacl = container_of(lgrps, - struct se_lun_acl, ml_stat_grps); + struct se_lun_acl *lacl = iport_to_lacl(item); struct se_node_acl *nacl = lacl->se_lun_nacl; struct se_session *se_sess; struct se_portal_group *tpg; @@ -1461,13 +1274,11 @@ static ssize_t target_stat_scsi_att_intr_port_show_attr_indx( spin_unlock_irq(&nacl->nacl_sess_lock); return ret; } -DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR_RO(indx); -static ssize_t target_stat_scsi_att_intr_port_show_attr_port_auth_indx( - struct se_ml_stat_grps *lgrps, char *page) +static ssize_t target_stat_iport_port_auth_indx_show(struct config_item *item, + char *page) { - struct se_lun_acl *lacl = container_of(lgrps, - struct se_lun_acl, ml_stat_grps); + struct se_lun_acl *lacl = iport_to_lacl(item); struct se_node_acl *nacl = lacl->se_lun_nacl; struct se_dev_entry *deve; ssize_t ret; @@ -1483,13 +1294,11 @@ static ssize_t target_stat_scsi_att_intr_port_show_attr_port_auth_indx( rcu_read_unlock(); return ret; } -DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR_RO(port_auth_indx); -static ssize_t target_stat_scsi_att_intr_port_show_attr_port_ident( - struct se_ml_stat_grps *lgrps, char *page) +static ssize_t target_stat_iport_port_ident_show(struct config_item *item, + char *page) { - struct se_lun_acl *lacl = container_of(lgrps, - struct se_lun_acl, ml_stat_grps); + struct se_lun_acl *lacl = iport_to_lacl(item); struct se_node_acl *nacl = lacl->se_lun_nacl; struct se_session *se_sess; struct se_portal_group *tpg; @@ -1513,28 +1322,25 @@ static ssize_t target_stat_scsi_att_intr_port_show_attr_port_ident( spin_unlock_irq(&nacl->nacl_sess_lock); return ret; } -DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR_RO(port_ident); -CONFIGFS_EATTR_OPS(target_stat_scsi_att_intr_port, se_ml_stat_grps, - scsi_att_intr_port_group); +CONFIGFS_ATTR_RO(target_stat_iport_, inst); +CONFIGFS_ATTR_RO(target_stat_iport_, dev); +CONFIGFS_ATTR_RO(target_stat_iport_, port); +CONFIGFS_ATTR_RO(target_stat_iport_, indx); +CONFIGFS_ATTR_RO(target_stat_iport_, port_auth_indx); +CONFIGFS_ATTR_RO(target_stat_iport_, port_ident); static struct configfs_attribute *target_stat_scsi_ath_intr_port_attrs[] = { - &target_stat_scsi_att_intr_port_inst.attr, - &target_stat_scsi_att_intr_port_dev.attr, - &target_stat_scsi_att_intr_port_port.attr, - &target_stat_scsi_att_intr_port_indx.attr, - &target_stat_scsi_att_intr_port_port_auth_indx.attr, - &target_stat_scsi_att_intr_port_port_ident.attr, + &target_stat_iport_attr_inst, + &target_stat_iport_attr_dev, + &target_stat_iport_attr_port, + &target_stat_iport_attr_indx, + &target_stat_iport_attr_port_auth_indx, + &target_stat_iport_attr_port_ident, NULL, }; -static struct configfs_item_operations target_stat_scsi_att_intr_port_attrib_ops = { - .show_attribute = target_stat_scsi_att_intr_port_attr_show, - .store_attribute = target_stat_scsi_att_intr_port_attr_store, -}; - static struct config_item_type target_stat_scsi_att_intr_port_cit = { - .ct_item_ops = &target_stat_scsi_att_intr_port_attrib_ops, .ct_attrs = target_stat_scsi_ath_intr_port_attrs, .ct_owner = THIS_MODULE, }; diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c index aa3caca8bace..064d6dfb5b6d 100644 --- a/drivers/target/tcm_fc/tfc_cmd.c +++ b/drivers/target/tcm_fc/tfc_cmd.c @@ -36,7 +36,6 @@ #include <target/target_core_base.h> #include <target/target_core_fabric.h> -#include <target/configfs_macros.h> #include "tcm_fc.h" diff --git a/drivers/target/tcm_fc/tfc_conf.c b/drivers/target/tcm_fc/tfc_conf.c index 16670933013b..85aeaa0ad303 100644 --- a/drivers/target/tcm_fc/tfc_conf.c +++ b/drivers/target/tcm_fc/tfc_conf.c @@ -38,8 +38,6 @@ #include <target/target_core_base.h> #include <target/target_core_fabric.h> -#include <target/target_core_fabric_configfs.h> -#include <target/configfs_macros.h> #include "tcm_fc.h" @@ -131,55 +129,51 @@ static ssize_t ft_wwn_store(void *arg, const char *buf, size_t len) * ACL auth ops. */ -static ssize_t ft_nacl_show_port_name( - struct se_node_acl *se_nacl, - char *page) +static ssize_t ft_nacl_port_name_show(struct config_item *item, char *page) { + struct se_node_acl *se_nacl = acl_to_nacl(item); struct ft_node_acl *acl = container_of(se_nacl, struct ft_node_acl, se_node_acl); return ft_wwn_show(&acl->node_auth.port_name, page); } -static ssize_t ft_nacl_store_port_name( - struct se_node_acl *se_nacl, - const char *page, - size_t count) +static ssize_t ft_nacl_port_name_store(struct config_item *item, + const char *page, size_t count) { + struct se_node_acl *se_nacl = acl_to_nacl(item); struct ft_node_acl *acl = container_of(se_nacl, struct ft_node_acl, se_node_acl); return ft_wwn_store(&acl->node_auth.port_name, page, count); } -TF_NACL_BASE_ATTR(ft, port_name, S_IRUGO | S_IWUSR); - -static ssize_t ft_nacl_show_node_name( - struct se_node_acl *se_nacl, - char *page) +static ssize_t ft_nacl_node_name_show(struct config_item *item, + char *page) { + struct se_node_acl *se_nacl = acl_to_nacl(item); struct ft_node_acl *acl = container_of(se_nacl, struct ft_node_acl, se_node_acl); return ft_wwn_show(&acl->node_auth.node_name, page); } -static ssize_t ft_nacl_store_node_name( - struct se_node_acl *se_nacl, - const char *page, - size_t count) +static ssize_t ft_nacl_node_name_store(struct config_item *item, + const char *page, size_t count) { + struct se_node_acl *se_nacl = acl_to_nacl(item); struct ft_node_acl *acl = container_of(se_nacl, struct ft_node_acl, se_node_acl); return ft_wwn_store(&acl->node_auth.node_name, page, count); } -TF_NACL_BASE_ATTR(ft, node_name, S_IRUGO | S_IWUSR); +CONFIGFS_ATTR(ft_nacl_, node_name); +CONFIGFS_ATTR(ft_nacl_, port_name); static struct configfs_attribute *ft_nacl_base_attrs[] = { - &ft_nacl_port_name.attr, - &ft_nacl_node_name.attr, + &ft_nacl_attr_port_name, + &ft_nacl_attr_node_name, NULL, }; @@ -386,18 +380,16 @@ static void ft_del_wwn(struct se_wwn *wwn) kfree(ft_wwn); } -static ssize_t ft_wwn_show_attr_version( - struct target_fabric_configfs *tf, - char *page) +static ssize_t ft_wwn_version_show(struct config_item *item, char *page) { return sprintf(page, "TCM FC " FT_VERSION " on %s/%s on " ""UTS_RELEASE"\n", utsname()->sysname, utsname()->machine); } -TF_WWN_ATTR_RO(ft, version); +CONFIGFS_ATTR_RO(ft_wwn_, version); static struct configfs_attribute *ft_wwn_attrs[] = { - &ft_wwn_version.attr, + &ft_wwn_attr_version, NULL, }; diff --git a/drivers/target/tcm_fc/tfc_io.c b/drivers/target/tcm_fc/tfc_io.c index 4b0fedd6bd4b..847c1aa6fbf4 100644 --- a/drivers/target/tcm_fc/tfc_io.c +++ b/drivers/target/tcm_fc/tfc_io.c @@ -44,7 +44,6 @@ #include <target/target_core_base.h> #include <target/target_core_fabric.h> -#include <target/configfs_macros.h> #include "tcm_fc.h" diff --git a/drivers/target/tcm_fc/tfc_sess.c b/drivers/target/tcm_fc/tfc_sess.c index 31a9e3fb98c5..7b934eac995d 100644 --- a/drivers/target/tcm_fc/tfc_sess.c +++ b/drivers/target/tcm_fc/tfc_sess.c @@ -36,7 +36,6 @@ #include <target/target_core_base.h> #include <target/target_core_fabric.h> -#include <target/configfs_macros.h> #include "tcm_fc.h" diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 5aabc4bc0d75..c463c89b90ef 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -147,6 +147,20 @@ config CLOCK_THERMAL device that is configured to use this cooling mechanism will be controlled to reduce clock frequency whenever temperature is high. +config DEVFREQ_THERMAL + bool "Generic device cooling support" + depends on PM_DEVFREQ + depends on PM_OPP + help + This implements the generic devfreq cooling mechanism through + frequency reduction for devices using devfreq. + + This will throttle the device by limiting the maximum allowed DVFS + frequency corresponding to the cooling level. + + In order to use the power extensions of the cooling device, + devfreq should use the simple_ondemand governor. + If you want this support, you should say Y here. config THERMAL_EMULATION @@ -275,6 +289,7 @@ config X86_PKG_TEMP_THERMAL tristate "X86 package temperature thermal driver" depends on X86_THERMAL_VECTOR select THERMAL_GOV_USER_SPACE + select THERMAL_WRITABLE_TRIPS default m help Enable this to register CPU digital sensor for package temperature as @@ -296,6 +311,7 @@ config INTEL_SOC_DTS_THERMAL tristate "Intel SoCs DTS thermal driver" depends on X86 select INTEL_SOC_DTS_IOSF_CORE + select THERMAL_WRITABLE_TRIPS help Enable this to register Intel SoCs (e.g. Bay Trail) platform digital temperature sensor (DTS). These SoCs have two additional DTSs in @@ -322,6 +338,7 @@ config INT340X_THERMAL select ACPI_THERMAL_REL select ACPI_FAN select INTEL_SOC_DTS_IOSF_CORE + select THERMAL_WRITABLE_TRIPS help Newer laptops and tablets that use ACPI may have thermal sensors and other devices with thermal control capabilities outside the core diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile index 26f160809959..cfae6a654793 100644 --- a/drivers/thermal/Makefile +++ b/drivers/thermal/Makefile @@ -22,6 +22,9 @@ thermal_sys-$(CONFIG_CPU_THERMAL) += cpu_cooling.o # clock cooling thermal_sys-$(CONFIG_CLOCK_THERMAL) += clock_cooling.o +# devfreq cooling +thermal_sys-$(CONFIG_DEVFREQ_THERMAL) += devfreq_cooling.o + # platform thermal drivers obj-$(CONFIG_QCOM_SPMI_TEMP_ALARM) += qcom-spmi-temp-alarm.o obj-$(CONFIG_SPEAR_THERMAL) += spear_thermal.o diff --git a/drivers/thermal/armada_thermal.c b/drivers/thermal/armada_thermal.c index 26b8d326546a..ae75328945f7 100644 --- a/drivers/thermal/armada_thermal.c +++ b/drivers/thermal/armada_thermal.c @@ -224,9 +224,9 @@ static const struct armada_thermal_data armada380_data = { .is_valid_shift = 10, .temp_shift = 0, .temp_mask = 0x3ff, - .coef_b = 2931108200UL, - .coef_m = 5000000UL, - .coef_div = 10502, + .coef_b = 1172499100UL, + .coef_m = 2000096UL, + .coef_div = 4201, .inverted = true, }; diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c index 42c6f71bdcc1..e3fbc5a5d88f 100644 --- a/drivers/thermal/cpu_cooling.c +++ b/drivers/thermal/cpu_cooling.c @@ -591,8 +591,7 @@ static int cpufreq_get_requested_power(struct thermal_cooling_device *cdev, if (trace_thermal_power_cpu_get_power_enabled()) { u32 ncpus = cpumask_weight(&cpufreq_device->allowed_cpus); - load_cpu = devm_kcalloc(&cdev->device, ncpus, sizeof(*load_cpu), - GFP_KERNEL); + load_cpu = kcalloc(ncpus, sizeof(*load_cpu), GFP_KERNEL); } for_each_cpu(cpu, &cpufreq_device->allowed_cpus) { @@ -615,8 +614,7 @@ static int cpufreq_get_requested_power(struct thermal_cooling_device *cdev, dynamic_power = get_dynamic_power(cpufreq_device, freq); ret = get_static_power(cpufreq_device, tz, freq, &static_power); if (ret) { - if (load_cpu) - devm_kfree(&cdev->device, load_cpu); + kfree(load_cpu); return ret; } @@ -625,7 +623,7 @@ static int cpufreq_get_requested_power(struct thermal_cooling_device *cdev, &cpufreq_device->allowed_cpus, freq, load_cpu, i, dynamic_power, static_power); - devm_kfree(&cdev->device, load_cpu); + kfree(load_cpu); } *power = static_power + dynamic_power; diff --git a/drivers/thermal/devfreq_cooling.c b/drivers/thermal/devfreq_cooling.c new file mode 100644 index 000000000000..01f0015f80dc --- /dev/null +++ b/drivers/thermal/devfreq_cooling.c @@ -0,0 +1,573 @@ +/* + * devfreq_cooling: Thermal cooling device implementation for devices using + * devfreq + * + * Copyright (C) 2014-2015 ARM Limited + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * TODO: + * - If OPPs are added or removed after devfreq cooling has + * registered, the devfreq cooling won't react to it. + */ + +#include <linux/devfreq.h> +#include <linux/devfreq_cooling.h> +#include <linux/export.h> +#include <linux/slab.h> +#include <linux/pm_opp.h> +#include <linux/thermal.h> + +#include <trace/events/thermal.h> + +static DEFINE_MUTEX(devfreq_lock); +static DEFINE_IDR(devfreq_idr); + +/** + * struct devfreq_cooling_device - Devfreq cooling device + * @id: unique integer value corresponding to each + * devfreq_cooling_device registered. + * @cdev: Pointer to associated thermal cooling device. + * @devfreq: Pointer to associated devfreq device. + * @cooling_state: Current cooling state. + * @power_table: Pointer to table with maximum power draw for each + * cooling state. State is the index into the table, and + * the power is in mW. + * @freq_table: Pointer to a table with the frequencies sorted in descending + * order. You can index the table by cooling device state + * @freq_table_size: Size of the @freq_table and @power_table + * @power_ops: Pointer to devfreq_cooling_power, used to generate the + * @power_table. + */ +struct devfreq_cooling_device { + int id; + struct thermal_cooling_device *cdev; + struct devfreq *devfreq; + unsigned long cooling_state; + u32 *power_table; + u32 *freq_table; + size_t freq_table_size; + struct devfreq_cooling_power *power_ops; +}; + +/** + * get_idr - function to get a unique id. + * @idr: struct idr * handle used to create a id. + * @id: int * value generated by this function. + * + * This function will populate @id with an unique + * id, using the idr API. + * + * Return: 0 on success, an error code on failure. + */ +static int get_idr(struct idr *idr, int *id) +{ + int ret; + + mutex_lock(&devfreq_lock); + ret = idr_alloc(idr, NULL, 0, 0, GFP_KERNEL); + mutex_unlock(&devfreq_lock); + if (unlikely(ret < 0)) + return ret; + *id = ret; + + return 0; +} + +/** + * release_idr - function to free the unique id. + * @idr: struct idr * handle used for creating the id. + * @id: int value representing the unique id. + */ +static void release_idr(struct idr *idr, int id) +{ + mutex_lock(&devfreq_lock); + idr_remove(idr, id); + mutex_unlock(&devfreq_lock); +} + +/** + * partition_enable_opps() - disable all opps above a given state + * @dfc: Pointer to devfreq we are operating on + * @cdev_state: cooling device state we're setting + * + * Go through the OPPs of the device, enabling all OPPs until + * @cdev_state and disabling those frequencies above it. + */ +static int partition_enable_opps(struct devfreq_cooling_device *dfc, + unsigned long cdev_state) +{ + int i; + struct device *dev = dfc->devfreq->dev.parent; + + for (i = 0; i < dfc->freq_table_size; i++) { + struct dev_pm_opp *opp; + int ret = 0; + unsigned int freq = dfc->freq_table[i]; + bool want_enable = i >= cdev_state ? true : false; + + rcu_read_lock(); + opp = dev_pm_opp_find_freq_exact(dev, freq, !want_enable); + rcu_read_unlock(); + + if (PTR_ERR(opp) == -ERANGE) + continue; + else if (IS_ERR(opp)) + return PTR_ERR(opp); + + if (want_enable) + ret = dev_pm_opp_enable(dev, freq); + else + ret = dev_pm_opp_disable(dev, freq); + + if (ret) + return ret; + } + + return 0; +} + +static int devfreq_cooling_get_max_state(struct thermal_cooling_device *cdev, + unsigned long *state) +{ + struct devfreq_cooling_device *dfc = cdev->devdata; + + *state = dfc->freq_table_size - 1; + + return 0; +} + +static int devfreq_cooling_get_cur_state(struct thermal_cooling_device *cdev, + unsigned long *state) +{ + struct devfreq_cooling_device *dfc = cdev->devdata; + + *state = dfc->cooling_state; + + return 0; +} + +static int devfreq_cooling_set_cur_state(struct thermal_cooling_device *cdev, + unsigned long state) +{ + struct devfreq_cooling_device *dfc = cdev->devdata; + struct devfreq *df = dfc->devfreq; + struct device *dev = df->dev.parent; + int ret; + + if (state == dfc->cooling_state) + return 0; + + dev_dbg(dev, "Setting cooling state %lu\n", state); + + if (state >= dfc->freq_table_size) + return -EINVAL; + + ret = partition_enable_opps(dfc, state); + if (ret) + return ret; + + dfc->cooling_state = state; + + return 0; +} + +/** + * freq_get_state() - get the cooling state corresponding to a frequency + * @dfc: Pointer to devfreq cooling device + * @freq: frequency in Hz + * + * Return: the cooling state associated with the @freq, or + * THERMAL_CSTATE_INVALID if it wasn't found. + */ +static unsigned long +freq_get_state(struct devfreq_cooling_device *dfc, unsigned long freq) +{ + int i; + + for (i = 0; i < dfc->freq_table_size; i++) { + if (dfc->freq_table[i] == freq) + return i; + } + + return THERMAL_CSTATE_INVALID; +} + +/** + * get_static_power() - calculate the static power + * @dfc: Pointer to devfreq cooling device + * @freq: Frequency in Hz + * + * Calculate the static power in milliwatts using the supplied + * get_static_power(). The current voltage is calculated using the + * OPP library. If no get_static_power() was supplied, assume the + * static power is negligible. + */ +static unsigned long +get_static_power(struct devfreq_cooling_device *dfc, unsigned long freq) +{ + struct devfreq *df = dfc->devfreq; + struct device *dev = df->dev.parent; + unsigned long voltage; + struct dev_pm_opp *opp; + + if (!dfc->power_ops->get_static_power) + return 0; + + rcu_read_lock(); + + opp = dev_pm_opp_find_freq_exact(dev, freq, true); + if (IS_ERR(opp) && (PTR_ERR(opp) == -ERANGE)) + opp = dev_pm_opp_find_freq_exact(dev, freq, false); + + voltage = dev_pm_opp_get_voltage(opp) / 1000; /* mV */ + + rcu_read_unlock(); + + if (voltage == 0) { + dev_warn_ratelimited(dev, + "Failed to get voltage for frequency %lu: %ld\n", + freq, IS_ERR(opp) ? PTR_ERR(opp) : 0); + return 0; + } + + return dfc->power_ops->get_static_power(voltage); +} + +/** + * get_dynamic_power - calculate the dynamic power + * @dfc: Pointer to devfreq cooling device + * @freq: Frequency in Hz + * @voltage: Voltage in millivolts + * + * Calculate the dynamic power in milliwatts consumed by the device at + * frequency @freq and voltage @voltage. If the get_dynamic_power() + * was supplied as part of the devfreq_cooling_power struct, then that + * function is used. Otherwise, a simple power model (Pdyn = Coeff * + * Voltage^2 * Frequency) is used. + */ +static unsigned long +get_dynamic_power(struct devfreq_cooling_device *dfc, unsigned long freq, + unsigned long voltage) +{ + u64 power; + u32 freq_mhz; + struct devfreq_cooling_power *dfc_power = dfc->power_ops; + + if (dfc_power->get_dynamic_power) + return dfc_power->get_dynamic_power(freq, voltage); + + freq_mhz = freq / 1000000; + power = (u64)dfc_power->dyn_power_coeff * freq_mhz * voltage * voltage; + do_div(power, 1000000000); + + return power; +} + +static int devfreq_cooling_get_requested_power(struct thermal_cooling_device *cdev, + struct thermal_zone_device *tz, + u32 *power) +{ + struct devfreq_cooling_device *dfc = cdev->devdata; + struct devfreq *df = dfc->devfreq; + struct devfreq_dev_status *status = &df->last_status; + unsigned long state; + unsigned long freq = status->current_frequency; + u32 dyn_power, static_power; + + /* Get dynamic power for state */ + state = freq_get_state(dfc, freq); + if (state == THERMAL_CSTATE_INVALID) + return -EAGAIN; + + dyn_power = dfc->power_table[state]; + + /* Scale dynamic power for utilization */ + dyn_power = (dyn_power * status->busy_time) / status->total_time; + + /* Get static power */ + static_power = get_static_power(dfc, freq); + + trace_thermal_power_devfreq_get_power(cdev, status, freq, dyn_power, + static_power); + + *power = dyn_power + static_power; + + return 0; +} + +static int devfreq_cooling_state2power(struct thermal_cooling_device *cdev, + struct thermal_zone_device *tz, + unsigned long state, + u32 *power) +{ + struct devfreq_cooling_device *dfc = cdev->devdata; + unsigned long freq; + u32 static_power; + + if (state < 0 || state >= dfc->freq_table_size) + return -EINVAL; + + freq = dfc->freq_table[state]; + static_power = get_static_power(dfc, freq); + + *power = dfc->power_table[state] + static_power; + return 0; +} + +static int devfreq_cooling_power2state(struct thermal_cooling_device *cdev, + struct thermal_zone_device *tz, + u32 power, unsigned long *state) +{ + struct devfreq_cooling_device *dfc = cdev->devdata; + struct devfreq *df = dfc->devfreq; + struct devfreq_dev_status *status = &df->last_status; + unsigned long freq = status->current_frequency; + unsigned long busy_time; + s32 dyn_power; + u32 static_power; + int i; + + static_power = get_static_power(dfc, freq); + + dyn_power = power - static_power; + dyn_power = dyn_power > 0 ? dyn_power : 0; + + /* Scale dynamic power for utilization */ + busy_time = status->busy_time ?: 1; + dyn_power = (dyn_power * status->total_time) / busy_time; + + /* + * Find the first cooling state that is within the power + * budget for dynamic power. + */ + for (i = 0; i < dfc->freq_table_size - 1; i++) + if (dyn_power >= dfc->power_table[i]) + break; + + *state = i; + trace_thermal_power_devfreq_limit(cdev, freq, *state, power); + return 0; +} + +static struct thermal_cooling_device_ops devfreq_cooling_ops = { + .get_max_state = devfreq_cooling_get_max_state, + .get_cur_state = devfreq_cooling_get_cur_state, + .set_cur_state = devfreq_cooling_set_cur_state, +}; + +/** + * devfreq_cooling_gen_tables() - Generate power and freq tables. + * @dfc: Pointer to devfreq cooling device. + * + * Generate power and frequency tables: the power table hold the + * device's maximum power usage at each cooling state (OPP). The + * static and dynamic power using the appropriate voltage and + * frequency for the state, is acquired from the struct + * devfreq_cooling_power, and summed to make the maximum power draw. + * + * The frequency table holds the frequencies in descending order. + * That way its indexed by cooling device state. + * + * The tables are malloced, and pointers put in dfc. They must be + * freed when unregistering the devfreq cooling device. + * + * Return: 0 on success, negative error code on failure. + */ +static int devfreq_cooling_gen_tables(struct devfreq_cooling_device *dfc) +{ + struct devfreq *df = dfc->devfreq; + struct device *dev = df->dev.parent; + int ret, num_opps; + unsigned long freq; + u32 *power_table = NULL; + u32 *freq_table; + int i; + + num_opps = dev_pm_opp_get_opp_count(dev); + + if (dfc->power_ops) { + power_table = kcalloc(num_opps, sizeof(*power_table), + GFP_KERNEL); + if (!power_table) + return -ENOMEM; + } + + freq_table = kcalloc(num_opps, sizeof(*freq_table), + GFP_KERNEL); + if (!freq_table) { + ret = -ENOMEM; + goto free_power_table; + } + + for (i = 0, freq = ULONG_MAX; i < num_opps; i++, freq--) { + unsigned long power_dyn, voltage; + struct dev_pm_opp *opp; + + rcu_read_lock(); + + opp = dev_pm_opp_find_freq_floor(dev, &freq); + if (IS_ERR(opp)) { + rcu_read_unlock(); + ret = PTR_ERR(opp); + goto free_tables; + } + + voltage = dev_pm_opp_get_voltage(opp) / 1000; /* mV */ + + rcu_read_unlock(); + + if (dfc->power_ops) { + power_dyn = get_dynamic_power(dfc, freq, voltage); + + dev_dbg(dev, "Dynamic power table: %lu MHz @ %lu mV: %lu = %lu mW\n", + freq / 1000000, voltage, power_dyn, power_dyn); + + power_table[i] = power_dyn; + } + + freq_table[i] = freq; + } + + if (dfc->power_ops) + dfc->power_table = power_table; + + dfc->freq_table = freq_table; + dfc->freq_table_size = num_opps; + + return 0; + +free_tables: + kfree(freq_table); +free_power_table: + kfree(power_table); + + return ret; +} + +/** + * of_devfreq_cooling_register_power() - Register devfreq cooling device, + * with OF and power information. + * @np: Pointer to OF device_node. + * @df: Pointer to devfreq device. + * @dfc_power: Pointer to devfreq_cooling_power. + * + * Register a devfreq cooling device. The available OPPs must be + * registered on the device. + * + * If @dfc_power is provided, the cooling device is registered with the + * power extensions. For the power extensions to work correctly, + * devfreq should use the simple_ondemand governor, other governors + * are not currently supported. + */ +struct thermal_cooling_device * +of_devfreq_cooling_register_power(struct device_node *np, struct devfreq *df, + struct devfreq_cooling_power *dfc_power) +{ + struct thermal_cooling_device *cdev; + struct devfreq_cooling_device *dfc; + char dev_name[THERMAL_NAME_LENGTH]; + int err; + + dfc = kzalloc(sizeof(*dfc), GFP_KERNEL); + if (!dfc) + return ERR_PTR(-ENOMEM); + + dfc->devfreq = df; + + if (dfc_power) { + dfc->power_ops = dfc_power; + + devfreq_cooling_ops.get_requested_power = + devfreq_cooling_get_requested_power; + devfreq_cooling_ops.state2power = devfreq_cooling_state2power; + devfreq_cooling_ops.power2state = devfreq_cooling_power2state; + } + + err = devfreq_cooling_gen_tables(dfc); + if (err) + goto free_dfc; + + err = get_idr(&devfreq_idr, &dfc->id); + if (err) + goto free_tables; + + snprintf(dev_name, sizeof(dev_name), "thermal-devfreq-%d", dfc->id); + + cdev = thermal_of_cooling_device_register(np, dev_name, dfc, + &devfreq_cooling_ops); + if (IS_ERR(cdev)) { + err = PTR_ERR(cdev); + dev_err(df->dev.parent, + "Failed to register devfreq cooling device (%d)\n", + err); + goto release_idr; + } + + dfc->cdev = cdev; + + return cdev; + +release_idr: + release_idr(&devfreq_idr, dfc->id); +free_tables: + kfree(dfc->power_table); + kfree(dfc->freq_table); +free_dfc: + kfree(dfc); + + return ERR_PTR(err); +} +EXPORT_SYMBOL_GPL(of_devfreq_cooling_register_power); + +/** + * of_devfreq_cooling_register() - Register devfreq cooling device, + * with OF information. + * @np: Pointer to OF device_node. + * @df: Pointer to devfreq device. + */ +struct thermal_cooling_device * +of_devfreq_cooling_register(struct device_node *np, struct devfreq *df) +{ + return of_devfreq_cooling_register_power(np, df, NULL); +} +EXPORT_SYMBOL_GPL(of_devfreq_cooling_register); + +/** + * devfreq_cooling_register() - Register devfreq cooling device. + * @df: Pointer to devfreq device. + */ +struct thermal_cooling_device *devfreq_cooling_register(struct devfreq *df) +{ + return of_devfreq_cooling_register(NULL, df); +} +EXPORT_SYMBOL_GPL(devfreq_cooling_register); + +/** + * devfreq_cooling_unregister() - Unregister devfreq cooling device. + * @dfc: Pointer to devfreq cooling device to unregister. + */ +void devfreq_cooling_unregister(struct thermal_cooling_device *cdev) +{ + struct devfreq_cooling_device *dfc; + + if (!cdev) + return; + + dfc = cdev->devdata; + + thermal_cooling_device_unregister(dfc->cdev); + release_idr(&devfreq_idr, dfc->id); + kfree(dfc->power_table); + kfree(dfc->freq_table); + + kfree(dfc); +} +EXPORT_SYMBOL_GPL(devfreq_cooling_unregister); diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c index 4bec1d3c3d27..c8fe3cac2e0e 100644 --- a/drivers/thermal/imx_thermal.c +++ b/drivers/thermal/imx_thermal.c @@ -288,7 +288,7 @@ static int imx_set_trip_temp(struct thermal_zone_device *tz, int trip, if (trip == IMX_TRIP_CRITICAL) return -EPERM; - if (temp > IMX_TEMP_PASSIVE) + if (temp < 0 || temp > IMX_TEMP_PASSIVE) return -EINVAL; data->temp_passive = temp; @@ -487,14 +487,6 @@ static int imx_thermal_probe(struct platform_device *pdev) if (data->irq < 0) return data->irq; - ret = devm_request_threaded_irq(&pdev->dev, data->irq, - imx_thermal_alarm_irq, imx_thermal_alarm_irq_thread, - 0, "imx_thermal", data); - if (ret < 0) { - dev_err(&pdev->dev, "failed to request alarm irq: %d\n", ret); - return ret; - } - platform_set_drvdata(pdev, data); ret = imx_get_sensor_data(pdev); @@ -571,6 +563,17 @@ static int imx_thermal_probe(struct platform_device *pdev) regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN); regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_MEASURE_TEMP); + ret = devm_request_threaded_irq(&pdev->dev, data->irq, + imx_thermal_alarm_irq, imx_thermal_alarm_irq_thread, + 0, "imx_thermal", data); + if (ret < 0) { + dev_err(&pdev->dev, "failed to request alarm irq: %d\n", ret); + clk_disable_unprepare(data->thermal_clk); + thermal_zone_device_unregister(data->tz); + cpufreq_cooling_unregister(data->cdev); + return ret; + } + data->irq_enabled = true; data->mode = THERMAL_DEVICE_ENABLED; diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c index c89ffb26a354..9787e8aa509f 100644 --- a/drivers/thermal/rockchip_thermal.c +++ b/drivers/thermal/rockchip_thermal.c @@ -22,6 +22,7 @@ #include <linux/platform_device.h> #include <linux/reset.h> #include <linux/thermal.h> +#include <linux/pinctrl/consumer.h> /** * If the temperature over a period of time High, @@ -106,16 +107,14 @@ struct rockchip_thermal_data { #define TSADCV2_AUTO_PERIOD_HT 0x6c #define TSADCV2_AUTO_EN BIT(0) -#define TSADCV2_AUTO_DISABLE ~BIT(0) #define TSADCV2_AUTO_SRC_EN(chn) BIT(4 + (chn)) #define TSADCV2_AUTO_TSHUT_POLARITY_HIGH BIT(8) -#define TSADCV2_AUTO_TSHUT_POLARITY_LOW ~BIT(8) #define TSADCV2_INT_SRC_EN(chn) BIT(chn) #define TSADCV2_SHUT_2GPIO_SRC_EN(chn) BIT(4 + (chn)) #define TSADCV2_SHUT_2CRU_SRC_EN(chn) BIT(8 + (chn)) -#define TSADCV2_INT_PD_CLEAR ~BIT(8) +#define TSADCV2_INT_PD_CLEAR_MASK ~BIT(8) #define TSADCV2_DATA_MASK 0xfff #define TSADCV2_HIGHT_INT_DEBOUNCE_COUNT 4 @@ -124,7 +123,7 @@ struct rockchip_thermal_data { #define TSADCV2_AUTO_PERIOD_HT_TIME 50 /* msec */ struct tsadc_table { - unsigned long code; + u32 code; long temp; }; @@ -164,7 +163,6 @@ static const struct tsadc_table v2_code_table[] = { {3452, 115000}, {3437, 120000}, {3421, 125000}, - {0, 125000}, }; static u32 rk_tsadcv2_temp_to_code(long temp) @@ -191,19 +189,21 @@ static u32 rk_tsadcv2_temp_to_code(long temp) return 0; } -static int rk_tsadcv2_code_to_temp(u32 code) +static int rk_tsadcv2_code_to_temp(u32 code, int *temp) { - unsigned int low = 0; + unsigned int low = 1; unsigned int high = ARRAY_SIZE(v2_code_table) - 1; unsigned int mid = (low + high) / 2; unsigned int num; unsigned long denom; - /* Invalid code, return -EAGAIN */ - if (code > TSADCV2_DATA_MASK) - return -EAGAIN; + BUILD_BUG_ON(ARRAY_SIZE(v2_code_table) < 2); - while (low <= high && mid) { + code &= TSADCV2_DATA_MASK; + if (code < v2_code_table[high].code) + return -EAGAIN; /* Incorrect reading */ + + while (low <= high) { if (code >= v2_code_table[mid].code && code < v2_code_table[mid - 1].code) break; @@ -223,7 +223,9 @@ static int rk_tsadcv2_code_to_temp(u32 code) num = v2_code_table[mid].temp - v2_code_table[mid - 1].temp; num *= v2_code_table[mid - 1].code - code; denom = v2_code_table[mid - 1].code - v2_code_table[mid].code; - return v2_code_table[mid - 1].temp + (num / denom); + *temp = v2_code_table[mid - 1].temp + (num / denom); + + return 0; } /** @@ -241,10 +243,10 @@ static void rk_tsadcv2_initialize(void __iomem *regs, enum tshut_polarity tshut_polarity) { if (tshut_polarity == TSHUT_HIGH_ACTIVE) - writel_relaxed(0 | (TSADCV2_AUTO_TSHUT_POLARITY_HIGH), + writel_relaxed(0U | TSADCV2_AUTO_TSHUT_POLARITY_HIGH, regs + TSADCV2_AUTO_CON); else - writel_relaxed(0 | (TSADCV2_AUTO_TSHUT_POLARITY_LOW), + writel_relaxed(0U & ~TSADCV2_AUTO_TSHUT_POLARITY_HIGH, regs + TSADCV2_AUTO_CON); writel_relaxed(TSADCV2_AUTO_PERIOD_TIME, regs + TSADCV2_AUTO_PERIOD); @@ -261,7 +263,7 @@ static void rk_tsadcv2_irq_ack(void __iomem *regs) u32 val; val = readl_relaxed(regs + TSADCV2_INT_PD); - writel_relaxed(val & TSADCV2_INT_PD_CLEAR, regs + TSADCV2_INT_PD); + writel_relaxed(val & TSADCV2_INT_PD_CLEAR_MASK, regs + TSADCV2_INT_PD); } static void rk_tsadcv2_control(void __iomem *regs, bool enable) @@ -281,14 +283,9 @@ static int rk_tsadcv2_get_temp(int chn, void __iomem *regs, int *temp) { u32 val; - /* the A/D value of the channel last conversion need some time */ val = readl_relaxed(regs + TSADCV2_DATA(chn)); - if (val == 0) - return -EAGAIN; - *temp = rk_tsadcv2_code_to_temp(val); - - return 0; + return rk_tsadcv2_code_to_temp(val, temp); } static void rk_tsadcv2_tshut_temp(int chn, void __iomem *regs, long temp) @@ -642,6 +639,8 @@ static int __maybe_unused rockchip_thermal_suspend(struct device *dev) clk_disable(thermal->pclk); clk_disable(thermal->clk); + pinctrl_pm_select_sleep_state(dev); + return 0; } @@ -678,6 +677,8 @@ static int __maybe_unused rockchip_thermal_resume(struct device *dev) for (i = 0; i < ARRAY_SIZE(thermal->sensors); i++) rockchip_thermal_toggle_sensor(&thermal->sensors[i], true); + pinctrl_pm_select_default_state(dev); + return 0; } diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c index ca920b0ecf8f..fa61eff88496 100644 --- a/drivers/thermal/samsung/exynos_tmu.c +++ b/drivers/thermal/samsung/exynos_tmu.c @@ -548,7 +548,7 @@ static int exynos5433_tmu_initialize(struct platform_device *pdev) default: pdata->cal_type = TYPE_ONE_POINT_TRIMMING; break; - }; + } dev_info(&pdev->dev, "Calibration type is %d-point calibration\n", cal_type ? 2 : 1); @@ -608,7 +608,7 @@ static int exynos5440_tmu_initialize(struct platform_device *pdev) { struct exynos_tmu_data *data = platform_get_drvdata(pdev); unsigned int trim_info = 0, con, rising_threshold; - int ret = 0, threshold_code; + int threshold_code; int crit_temp = 0; /* @@ -651,7 +651,8 @@ static int exynos5440_tmu_initialize(struct platform_device *pdev) /* Clear the PMIN in the common TMU register */ if (!data->id) writel(0, data->base_second + EXYNOS5440_TMU_PMIN); - return ret; + + return 0; } static int exynos7_tmu_initialize(struct platform_device *pdev) @@ -1168,27 +1169,10 @@ static int exynos_map_dt_data(struct platform_device *pdev) struct exynos_tmu_data *data = platform_get_drvdata(pdev); struct exynos_tmu_platform_data *pdata; struct resource res; - int ret; if (!data || !pdev->dev.of_node) return -ENODEV; - /* - * Try enabling the regulator if found - * TODO: Add regulator as an SOC feature, so that regulator enable - * is a compulsory call. - */ - data->regulator = devm_regulator_get(&pdev->dev, "vtmu"); - if (!IS_ERR(data->regulator)) { - ret = regulator_enable(data->regulator); - if (ret) { - dev_err(&pdev->dev, "failed to enable vtmu\n"); - return ret; - } - } else { - dev_info(&pdev->dev, "Regulator node (vtmu) not found\n"); - } - data->id = of_alias_get_id(pdev->dev.of_node, "tmuctrl"); if (data->id < 0) data->id = 0; @@ -1306,12 +1290,22 @@ static int exynos_tmu_probe(struct platform_device *pdev) platform_set_drvdata(pdev, data); mutex_init(&data->lock); - data->tzd = thermal_zone_of_sensor_register(&pdev->dev, 0, data, - &exynos_sensor_ops); - if (IS_ERR(data->tzd)) { - pr_err("thermal: tz: %p ERROR\n", data->tzd); - return PTR_ERR(data->tzd); + /* + * Try enabling the regulator if found + * TODO: Add regulator as an SOC feature, so that regulator enable + * is a compulsory call. + */ + data->regulator = devm_regulator_get(&pdev->dev, "vtmu"); + if (!IS_ERR(data->regulator)) { + ret = regulator_enable(data->regulator); + if (ret) { + dev_err(&pdev->dev, "failed to enable vtmu\n"); + return ret; + } + } else { + dev_info(&pdev->dev, "Regulator node (vtmu) not found\n"); } + ret = exynos_map_dt_data(pdev); if (ret) goto err_sensor; @@ -1363,23 +1357,38 @@ static int exynos_tmu_probe(struct platform_device *pdev) break; default: break; - }; + } + + /* + * data->tzd must be registered before calling exynos_tmu_initialize(), + * requesting irq and calling exynos_tmu_control(). + */ + data->tzd = thermal_zone_of_sensor_register(&pdev->dev, 0, data, + &exynos_sensor_ops); + if (IS_ERR(data->tzd)) { + ret = PTR_ERR(data->tzd); + dev_err(&pdev->dev, "Failed to register sensor: %d\n", ret); + goto err_sclk; + } ret = exynos_tmu_initialize(pdev); if (ret) { dev_err(&pdev->dev, "Failed to initialize TMU\n"); - goto err_sclk; + goto err_thermal; } ret = devm_request_irq(&pdev->dev, data->irq, exynos_tmu_irq, IRQF_TRIGGER_RISING | IRQF_SHARED, dev_name(&pdev->dev), data); if (ret) { dev_err(&pdev->dev, "Failed to request irq: %d\n", data->irq); - goto err_sclk; + goto err_thermal; } exynos_tmu_control(pdev, true); return 0; + +err_thermal: + thermal_zone_of_sensor_unregister(&pdev->dev, data->tzd); err_sclk: clk_disable_unprepare(data->sclk); err_clk: @@ -1388,9 +1397,8 @@ err_clk_sec: if (!IS_ERR(data->clk_sec)) clk_unprepare(data->clk_sec); err_sensor: - if (!IS_ERR_OR_NULL(data->regulator)) + if (!IS_ERR(data->regulator)) regulator_disable(data->regulator); - thermal_zone_of_sensor_unregister(&pdev->dev, data->tzd); return ret; } diff --git a/drivers/thermal/ti-soc-thermal/Kconfig b/drivers/thermal/ti-soc-thermal/Kconfig index cb6686ff09ae..ea8283f08aa6 100644 --- a/drivers/thermal/ti-soc-thermal/Kconfig +++ b/drivers/thermal/ti-soc-thermal/Kconfig @@ -19,6 +19,21 @@ config TI_THERMAL This includes trip points definitions, extrapolation rules and CPU cooling device bindings. +config OMAP3_THERMAL + bool "Texas Instruments OMAP3 thermal support" + depends on TI_SOC_THERMAL + depends on ARCH_OMAP3 || COMPILE_TEST + help + If you say yes here you get thermal support for the Texas Instruments + OMAP3 SoC family. The current chips supported are: + - OMAP3430 + + OMAP3 chips normally don't need thermal management, and sensors in + this generation are not accurate, nor they are very close to + the important hotspots. + + Say 'N' here. + config OMAP4_THERMAL bool "Texas Instruments OMAP4 thermal support" depends on TI_SOC_THERMAL diff --git a/drivers/thermal/ti-soc-thermal/Makefile b/drivers/thermal/ti-soc-thermal/Makefile index 1226b2484e55..0f89bdf03790 100644 --- a/drivers/thermal/ti-soc-thermal/Makefile +++ b/drivers/thermal/ti-soc-thermal/Makefile @@ -2,5 +2,6 @@ obj-$(CONFIG_TI_SOC_THERMAL) += ti-soc-thermal.o ti-soc-thermal-y := ti-bandgap.o ti-soc-thermal-$(CONFIG_TI_THERMAL) += ti-thermal-common.o ti-soc-thermal-$(CONFIG_DRA752_THERMAL) += dra752-thermal-data.o +ti-soc-thermal-$(CONFIG_OMAP3_THERMAL) += omap3-thermal-data.o ti-soc-thermal-$(CONFIG_OMAP4_THERMAL) += omap4-thermal-data.o ti-soc-thermal-$(CONFIG_OMAP5_THERMAL) += omap5-thermal-data.o diff --git a/drivers/thermal/ti-soc-thermal/omap3-thermal-data.c b/drivers/thermal/ti-soc-thermal/omap3-thermal-data.c new file mode 100644 index 000000000000..3ee34340edab --- /dev/null +++ b/drivers/thermal/ti-soc-thermal/omap3-thermal-data.c @@ -0,0 +1,176 @@ +/* + * OMAP3 thermal driver. + * + * Copyright (C) 2011-2012 Texas Instruments Inc. + * Copyright (C) 2014 Pavel Machek <pavel@ucw.cz> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + * Note + * http://www.ti.com/lit/er/sprz278f/sprz278f.pdf "Advisory + * 3.1.1.186 MMC OCP Clock Not Gated When Thermal Sensor Is Used" + * + * Also TI says: + * Just be careful when you try to make thermal policy like decisions + * based on this sensor. Placement of the sensor w.r.t the actual logic + * generating heat has to be a factor as well. If you are just looking + * for an approximation temperature (thermometerish kind), you might be + * ok with this. I am not sure we'd find any TI data around this.. just a + * heads up. + */ + +#include "ti-thermal.h" +#include "ti-bandgap.h" + +/* + * OMAP34XX has one instance of thermal sensor for MPU + * need to describe the individual bit fields + */ +static struct temp_sensor_registers +omap34xx_mpu_temp_sensor_registers = { + .temp_sensor_ctrl = 0, + .bgap_soc_mask = BIT(8), + .bgap_eocz_mask = BIT(7), + .bgap_dtemp_mask = 0x7f, + + .bgap_mode_ctrl = 0, + .mode_ctrl_mask = BIT(9), +}; + +/* Thresholds and limits for OMAP34XX MPU temperature sensor */ +static struct temp_sensor_data omap34xx_mpu_temp_sensor_data = { + .min_freq = 32768, + .max_freq = 32768, + .max_temp = 125000, + .min_temp = -40000, + .hyst_val = 5000, +}; + +/* + * Temperature values in milli degree celsius + */ +static const int +omap34xx_adc_to_temp[128] = { + -40000, -40000, -40000, -40000, -40000, -39000, -38000, -36000, + -34000, -32000, -31000, -29000, -28000, -26000, -25000, -24000, + -22000, -21000, -19000, -18000, -17000, -15000, -14000, -12000, + -11000, -9000, -8000, -7000, -5000, -4000, -2000, -1000, 0000, + 1000, 3000, 4000, 5000, 7000, 8000, 10000, 11000, 13000, 14000, + 15000, 17000, 18000, 20000, 21000, 22000, 24000, 25000, 27000, + 28000, 30000, 31000, 32000, 34000, 35000, 37000, 38000, 39000, + 41000, 42000, 44000, 45000, 47000, 48000, 49000, 51000, 52000, + 53000, 55000, 56000, 58000, 59000, 60000, 62000, 63000, 65000, + 66000, 67000, 69000, 70000, 72000, 73000, 74000, 76000, 77000, + 79000, 80000, 81000, 83000, 84000, 85000, 87000, 88000, 89000, + 91000, 92000, 94000, 95000, 96000, 98000, 99000, 100000, + 102000, 103000, 105000, 106000, 107000, 109000, 110000, 111000, + 113000, 114000, 116000, 117000, 118000, 120000, 121000, 122000, + 124000, 124000, 125000, 125000, 125000, 125000, 125000 +}; + +/* OMAP34XX data */ +const struct ti_bandgap_data omap34xx_data = { + .features = TI_BANDGAP_FEATURE_CLK_CTRL | TI_BANDGAP_FEATURE_UNRELIABLE, + .fclock_name = "ts_fck", + .div_ck_name = "ts_fck", + .conv_table = omap34xx_adc_to_temp, + .adc_start_val = 0, + .adc_end_val = 127, + .expose_sensor = ti_thermal_expose_sensor, + .remove_sensor = ti_thermal_remove_sensor, + + .sensors = { + { + .registers = &omap34xx_mpu_temp_sensor_registers, + .ts_data = &omap34xx_mpu_temp_sensor_data, + .domain = "cpu", + .slope = 0, + .constant = 20000, + .slope_pcb = 0, + .constant_pcb = 20000, + .register_cooling = NULL, + .unregister_cooling = NULL, + }, + }, + .sensor_count = 1, +}; + +/* + * OMAP36XX has one instance of thermal sensor for MPU + * need to describe the individual bit fields + */ +static struct temp_sensor_registers +omap36xx_mpu_temp_sensor_registers = { + .temp_sensor_ctrl = 0, + .bgap_soc_mask = BIT(9), + .bgap_eocz_mask = BIT(8), + .bgap_dtemp_mask = 0xFF, + + .bgap_mode_ctrl = 0, + .mode_ctrl_mask = BIT(10), +}; + +/* Thresholds and limits for OMAP36XX MPU temperature sensor */ +static struct temp_sensor_data omap36xx_mpu_temp_sensor_data = { + .min_freq = 32768, + .max_freq = 32768, + .max_temp = 125000, + .min_temp = -40000, + .hyst_val = 5000, +}; + +/* + * Temperature values in milli degree celsius + */ +static const int +omap36xx_adc_to_temp[128] = { + -40000, -40000, -40000, -40000, -40000, -40000, -40000, -40000, + -40000, -40000, -40000, -40000, -40000, -38000, -35000, -34000, + -32000, -30000, -28000, -26000, -24000, -22000, -20000, -18500, + -17000, -15000, -13500, -12000, -10000, -8000, -6500, -5000, -3500, + -1500, 0, 2000, 3500, 5000, 6500, 8500, 10000, 12000, 13500, + 15000, 17000, 19000, 21000, 23000, 25000, 27000, 28500, 30000, + 32000, 33500, 35000, 37000, 38500, 40000, 42000, 43500, 45000, + 47000, 48500, 50000, 52000, 53500, 55000, 57000, 58500, 60000, + 62000, 64000, 66000, 68000, 70000, 71500, 73500, 75000, 77000, + 78500, 80000, 82000, 83500, 85000, 87000, 88500, 90000, 92000, + 93500, 95000, 97000, 98500, 100000, 102000, 103500, 105000, 107000, + 109000, 111000, 113000, 115000, 117000, 118500, 120000, 122000, + 123500, 125000, 125000, 125000, 125000, 125000, 125000, 125000, + 125000, 125000, 125000, 125000, 125000, 125000, 125000, 125000, + 125000, 125000, 125000, 125000, 125000, 125000, 125000 +}; + +/* OMAP36XX data */ +const struct ti_bandgap_data omap36xx_data = { + .features = TI_BANDGAP_FEATURE_CLK_CTRL | TI_BANDGAP_FEATURE_UNRELIABLE, + .fclock_name = "ts_fck", + .div_ck_name = "ts_fck", + .conv_table = omap36xx_adc_to_temp, + .adc_start_val = 0, + .adc_end_val = 127, + .expose_sensor = ti_thermal_expose_sensor, + .remove_sensor = ti_thermal_remove_sensor, + + .sensors = { + { + .registers = &omap36xx_mpu_temp_sensor_registers, + .ts_data = &omap36xx_mpu_temp_sensor_data, + .domain = "cpu", + .slope = 0, + .constant = 20000, + .slope_pcb = 0, + .constant_pcb = 20000, + .register_cooling = NULL, + .unregister_cooling = NULL, + }, + }, + .sensor_count = 1, +}; diff --git a/drivers/thermal/ti-soc-thermal/ti-bandgap.c b/drivers/thermal/ti-soc-thermal/ti-bandgap.c index 10c47c048f7a..1e34a1efc554 100644 --- a/drivers/thermal/ti-soc-thermal/ti-bandgap.c +++ b/drivers/thermal/ti-soc-thermal/ti-bandgap.c @@ -1274,6 +1274,10 @@ int ti_bandgap_probe(struct platform_device *pdev) } bgp->dev = &pdev->dev; + if (TI_BANDGAP_HAS(bgp, UNRELIABLE)) + dev_warn(&pdev->dev, + "This OMAP thermal sensor is unreliable. You've been warned\n"); + if (TI_BANDGAP_HAS(bgp, TSHUT)) { ret = ti_bandgap_tshut_init(bgp, pdev); if (ret) { @@ -1579,6 +1583,16 @@ static SIMPLE_DEV_PM_OPS(ti_bandgap_dev_pm_ops, ti_bandgap_suspend, #endif static const struct of_device_id of_ti_bandgap_match[] = { +#ifdef CONFIG_OMAP3_THERMAL + { + .compatible = "ti,omap34xx-bandgap", + .data = (void *)&omap34xx_data, + }, + { + .compatible = "ti,omap36xx-bandgap", + .data = (void *)&omap36xx_data, + }, +#endif #ifdef CONFIG_OMAP4_THERMAL { .compatible = "ti,omap4430-bandgap", diff --git a/drivers/thermal/ti-soc-thermal/ti-bandgap.h b/drivers/thermal/ti-soc-thermal/ti-bandgap.h index 0c52f7afba00..fe0adb898764 100644 --- a/drivers/thermal/ti-soc-thermal/ti-bandgap.h +++ b/drivers/thermal/ti-soc-thermal/ti-bandgap.h @@ -322,6 +322,8 @@ struct ti_temp_sensor { * has Errata 814 * TI_BANDGAP_FEATURE_ERRATA_813 - used to workaorund when the bandgap device * has Errata 813 + * TI_BANDGAP_FEATURE_UNRELIABLE - used when the sensor readings are too + * inaccurate. * TI_BANDGAP_HAS(b, f) - macro to check if a bandgap device is capable of a * specific feature (above) or not. Return non-zero, if yes. */ @@ -337,6 +339,7 @@ struct ti_temp_sensor { #define TI_BANDGAP_FEATURE_HISTORY_BUFFER BIT(9) #define TI_BANDGAP_FEATURE_ERRATA_814 BIT(10) #define TI_BANDGAP_FEATURE_ERRATA_813 BIT(11) +#define TI_BANDGAP_FEATURE_UNRELIABLE BIT(12) #define TI_BANDGAP_HAS(b, f) \ ((b)->conf->features & TI_BANDGAP_FEATURE_ ## f) @@ -390,6 +393,14 @@ int ti_bandgap_set_sensor_data(struct ti_bandgap *bgp, int id, void *data); void *ti_bandgap_get_sensor_data(struct ti_bandgap *bgp, int id); int ti_bandgap_get_trend(struct ti_bandgap *bgp, int id, int *trend); +#ifdef CONFIG_OMAP3_THERMAL +extern const struct ti_bandgap_data omap34xx_data; +extern const struct ti_bandgap_data omap36xx_data; +#else +#define omap34xx_data NULL +#define omap36xx_data NULL +#endif + #ifdef CONFIG_OMAP4_THERMAL extern const struct ti_bandgap_data omap4430_data; extern const struct ti_bandgap_data omap4460_data; diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 13844261cd5f..ed776149261e 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -169,7 +169,7 @@ static inline int tty_copy_to_user(struct tty_struct *tty, { struct n_tty_data *ldata = tty->disc_data; - tty_audit_add_data(tty, to, n, ldata->icanon); + tty_audit_add_data(tty, from, n, ldata->icanon); return copy_to_user(to, from, n); } diff --git a/drivers/tty/serial/8250/8250_fsl.c b/drivers/tty/serial/8250/8250_fsl.c index c0533a57ec53..910bfee5a88b 100644 --- a/drivers/tty/serial/8250/8250_fsl.c +++ b/drivers/tty/serial/8250/8250_fsl.c @@ -60,3 +60,4 @@ int fsl8250_handle_irq(struct uart_port *port) spin_unlock_irqrestore(&up->port.lock, flags); return 1; } +EXPORT_SYMBOL_GPL(fsl8250_handle_irq); diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index e6f5e12a2d83..6412f1455beb 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -373,6 +373,7 @@ config SERIAL_8250_MID depends on SERIAL_8250 && PCI select HSU_DMA if SERIAL_8250_DMA select HSU_DMA_PCI if X86_INTEL_MID + select RATIONAL help Selecting this option will enable handling of the extra features present on the UART found on Intel Medfield SOC and various other diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 1aec4404062d..f38beb28e7ae 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1539,7 +1539,6 @@ config SERIAL_FSL_LPUART tristate "Freescale lpuart serial port support" depends on HAS_DMA select SERIAL_CORE - select SERIAL_EARLYCON help Support for the on-chip lpuart on some Freescale SOCs. @@ -1547,6 +1546,7 @@ config SERIAL_FSL_LPUART_CONSOLE bool "Console on Freescale lpuart serial port" depends on SERIAL_FSL_LPUART=y select SERIAL_CORE_CONSOLE + select SERIAL_EARLYCON help If you have enabled the lpuart serial port on the Freescale SoCs, you can make it the console by answering Y to this option. diff --git a/drivers/tty/serial/bcm63xx_uart.c b/drivers/tty/serial/bcm63xx_uart.c index 681e0f3d5e0e..a1c0a89d9c7f 100644 --- a/drivers/tty/serial/bcm63xx_uart.c +++ b/drivers/tty/serial/bcm63xx_uart.c @@ -474,7 +474,7 @@ static int bcm_uart_startup(struct uart_port *port) /* register irq and enable rx interrupts */ ret = request_irq(port->irq, bcm_uart_interrupt, 0, - bcm_uart_type(port), port); + dev_name(port->dev), port); if (ret) return ret; bcm_uart_writel(port, UART_RX_INT_MASK, UART_IR_REG); diff --git a/drivers/tty/serial/etraxfs-uart.c b/drivers/tty/serial/etraxfs-uart.c index 6813e316e9ff..2f80bc7e44fb 100644 --- a/drivers/tty/serial/etraxfs-uart.c +++ b/drivers/tty/serial/etraxfs-uart.c @@ -894,7 +894,7 @@ static int etraxfs_uart_probe(struct platform_device *pdev) up->regi_ser = of_iomap(np, 0); up->port.dev = &pdev->dev; - up->gpios = mctrl_gpio_init(&pdev->dev, 0); + up->gpios = mctrl_gpio_init_noauto(&pdev->dev, 0); if (IS_ERR(up->gpios)) return PTR_ERR(up->gpios); diff --git a/drivers/tty/tty_audit.c b/drivers/tty/tty_audit.c index 90ca082935f6..3d245cd3d8e6 100644 --- a/drivers/tty/tty_audit.c +++ b/drivers/tty/tty_audit.c @@ -265,7 +265,7 @@ static struct tty_audit_buf *tty_audit_buf_get(struct tty_struct *tty, * * Audit @data of @size from @tty, if necessary. */ -void tty_audit_add_data(struct tty_struct *tty, unsigned char *data, +void tty_audit_add_data(struct tty_struct *tty, const void *data, size_t size, unsigned icanon) { struct tty_audit_buf *buf; diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 0c41dbcb90b8..bcc8e1e8bb72 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -1282,18 +1282,22 @@ int tty_send_xchar(struct tty_struct *tty, char ch) int was_stopped = tty->stopped; if (tty->ops->send_xchar) { + down_read(&tty->termios_rwsem); tty->ops->send_xchar(tty, ch); + up_read(&tty->termios_rwsem); return 0; } if (tty_write_lock(tty, 0) < 0) return -ERESTARTSYS; + down_read(&tty->termios_rwsem); if (was_stopped) start_tty(tty); tty->ops->write(tty, &ch, 1); if (was_stopped) stop_tty(tty); + up_read(&tty->termios_rwsem); tty_write_unlock(tty); return 0; } diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c index 9c5aebfe7053..1445dd39aa62 100644 --- a/drivers/tty/tty_ioctl.c +++ b/drivers/tty/tty_ioctl.c @@ -1147,16 +1147,12 @@ int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file, spin_unlock_irq(&tty->flow_lock); break; case TCIOFF: - down_read(&tty->termios_rwsem); if (STOP_CHAR(tty) != __DISABLED_CHAR) retval = tty_send_xchar(tty, STOP_CHAR(tty)); - up_read(&tty->termios_rwsem); break; case TCION: - down_read(&tty->termios_rwsem); if (START_CHAR(tty) != __DISABLED_CHAR) retval = tty_send_xchar(tty, START_CHAR(tty)); - up_read(&tty->termios_rwsem); break; default: return -EINVAL; diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index 5af8f1874c1a..629e3c865072 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -592,7 +592,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) /* Restart the work queue in case no characters kick it off. Safe if already running */ - schedule_work(&tty->port->buf.work); + tty_buffer_restart_work(tty->port); tty_unlock(tty); return retval; diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index 6ccbf60cdd5c..5a048b7b92e8 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -84,6 +84,12 @@ struct ci_hdrc_imx_data { struct imx_usbmisc_data *usbmisc_data; bool supports_runtime_pm; bool in_lpm; + /* SoC before i.mx6 (except imx23/imx28) needs three clks */ + bool need_three_clks; + struct clk *clk_ipg; + struct clk *clk_ahb; + struct clk *clk_per; + /* --------------------------------- */ }; /* Common functions shared by usbmisc drivers */ @@ -135,6 +141,102 @@ static struct imx_usbmisc_data *usbmisc_get_init_data(struct device *dev) } /* End of common functions shared by usbmisc drivers*/ +static int imx_get_clks(struct device *dev) +{ + struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); + int ret = 0; + + data->clk_ipg = devm_clk_get(dev, "ipg"); + if (IS_ERR(data->clk_ipg)) { + /* If the platform only needs one clocks */ + data->clk = devm_clk_get(dev, NULL); + if (IS_ERR(data->clk)) { + ret = PTR_ERR(data->clk); + dev_err(dev, + "Failed to get clks, err=%ld,%ld\n", + PTR_ERR(data->clk), PTR_ERR(data->clk_ipg)); + return ret; + } + return ret; + } + + data->clk_ahb = devm_clk_get(dev, "ahb"); + if (IS_ERR(data->clk_ahb)) { + ret = PTR_ERR(data->clk_ahb); + dev_err(dev, + "Failed to get ahb clock, err=%d\n", ret); + return ret; + } + + data->clk_per = devm_clk_get(dev, "per"); + if (IS_ERR(data->clk_per)) { + ret = PTR_ERR(data->clk_per); + dev_err(dev, + "Failed to get per clock, err=%d\n", ret); + return ret; + } + + data->need_three_clks = true; + return ret; +} + +static int imx_prepare_enable_clks(struct device *dev) +{ + struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); + int ret = 0; + + if (data->need_three_clks) { + ret = clk_prepare_enable(data->clk_ipg); + if (ret) { + dev_err(dev, + "Failed to prepare/enable ipg clk, err=%d\n", + ret); + return ret; + } + + ret = clk_prepare_enable(data->clk_ahb); + if (ret) { + dev_err(dev, + "Failed to prepare/enable ahb clk, err=%d\n", + ret); + clk_disable_unprepare(data->clk_ipg); + return ret; + } + + ret = clk_prepare_enable(data->clk_per); + if (ret) { + dev_err(dev, + "Failed to prepare/enable per clk, err=%d\n", + ret); + clk_disable_unprepare(data->clk_ahb); + clk_disable_unprepare(data->clk_ipg); + return ret; + } + } else { + ret = clk_prepare_enable(data->clk); + if (ret) { + dev_err(dev, + "Failed to prepare/enable clk, err=%d\n", + ret); + return ret; + } + } + + return ret; +} + +static void imx_disable_unprepare_clks(struct device *dev) +{ + struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); + + if (data->need_three_clks) { + clk_disable_unprepare(data->clk_per); + clk_disable_unprepare(data->clk_ahb); + clk_disable_unprepare(data->clk_ipg); + } else { + clk_disable_unprepare(data->clk); + } +} static int ci_hdrc_imx_probe(struct platform_device *pdev) { @@ -145,31 +247,31 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) .flags = CI_HDRC_SET_NON_ZERO_TTHA, }; int ret; - const struct of_device_id *of_id = - of_match_device(ci_hdrc_imx_dt_ids, &pdev->dev); - const struct ci_hdrc_imx_platform_flag *imx_platform_flag = of_id->data; + const struct of_device_id *of_id; + const struct ci_hdrc_imx_platform_flag *imx_platform_flag; + + of_id = of_match_device(ci_hdrc_imx_dt_ids, &pdev->dev); + if (!of_id) + return -ENODEV; + + imx_platform_flag = of_id->data; data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; + platform_set_drvdata(pdev, data); data->usbmisc_data = usbmisc_get_init_data(&pdev->dev); if (IS_ERR(data->usbmisc_data)) return PTR_ERR(data->usbmisc_data); - data->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(data->clk)) { - dev_err(&pdev->dev, - "Failed to get clock, err=%ld\n", PTR_ERR(data->clk)); - return PTR_ERR(data->clk); - } + ret = imx_get_clks(&pdev->dev); + if (ret) + return ret; - ret = clk_prepare_enable(data->clk); - if (ret) { - dev_err(&pdev->dev, - "Failed to prepare or enable clock, err=%d\n", ret); + ret = imx_prepare_enable_clks(&pdev->dev); + if (ret) return ret; - } data->phy = devm_usb_get_phy_by_phandle(&pdev->dev, "fsl,usbphy", 0); if (IS_ERR(data->phy)) { @@ -212,8 +314,6 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) goto disable_device; } - platform_set_drvdata(pdev, data); - if (data->supports_runtime_pm) { pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); @@ -226,7 +326,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) disable_device: ci_hdrc_remove_device(data->ci_pdev); err_clk: - clk_disable_unprepare(data->clk); + imx_disable_unprepare_clks(&pdev->dev); return ret; } @@ -240,7 +340,7 @@ static int ci_hdrc_imx_remove(struct platform_device *pdev) pm_runtime_put_noidle(&pdev->dev); } ci_hdrc_remove_device(data->ci_pdev); - clk_disable_unprepare(data->clk); + imx_disable_unprepare_clks(&pdev->dev); return 0; } @@ -252,7 +352,7 @@ static int imx_controller_suspend(struct device *dev) dev_dbg(dev, "at %s\n", __func__); - clk_disable_unprepare(data->clk); + imx_disable_unprepare_clks(dev); data->in_lpm = true; return 0; @@ -270,7 +370,7 @@ static int imx_controller_resume(struct device *dev) return 0; } - ret = clk_prepare_enable(data->clk); + ret = imx_prepare_enable_clks(dev); if (ret) return ret; @@ -285,7 +385,7 @@ static int imx_controller_resume(struct device *dev) return 0; clk_disable: - clk_disable_unprepare(data->clk); + imx_disable_unprepare_clks(dev); return ret; } diff --git a/drivers/usb/chipidea/debug.c b/drivers/usb/chipidea/debug.c index 080b7be3daf0..58c8485a0715 100644 --- a/drivers/usb/chipidea/debug.c +++ b/drivers/usb/chipidea/debug.c @@ -322,8 +322,10 @@ static ssize_t ci_role_write(struct file *file, const char __user *ubuf, return -EINVAL; pm_runtime_get_sync(ci->dev); + disable_irq(ci->irq); ci_role_stop(ci); ret = ci_role_start(ci, role); + enable_irq(ci->irq); pm_runtime_put_sync(ci->dev); return ret ? ret : count; diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index 8223fe73ea85..391a1225b0ba 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -1751,6 +1751,22 @@ static int ci_udc_start(struct usb_gadget *gadget, return retval; } +static void ci_udc_stop_for_otg_fsm(struct ci_hdrc *ci) +{ + if (!ci_otg_is_fsm_mode(ci)) + return; + + mutex_lock(&ci->fsm.lock); + if (ci->fsm.otg->state == OTG_STATE_A_PERIPHERAL) { + ci->fsm.a_bidl_adis_tmout = 1; + ci_hdrc_otg_fsm_start(ci); + } else if (ci->fsm.otg->state == OTG_STATE_B_PERIPHERAL) { + ci->fsm.protocol = PROTO_UNDEF; + ci->fsm.otg->state = OTG_STATE_UNDEFINED; + } + mutex_unlock(&ci->fsm.lock); +} + /** * ci_udc_stop: unregister a gadget driver */ @@ -1775,6 +1791,7 @@ static int ci_udc_stop(struct usb_gadget *gadget) ci->driver = NULL; spin_unlock_irqrestore(&ci->lock, flags); + ci_udc_stop_for_otg_fsm(ci); return 0; } diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c index fcea4eb36eee..ab8b027e8cc8 100644 --- a/drivers/usb/chipidea/usbmisc_imx.c +++ b/drivers/usb/chipidea/usbmisc_imx.c @@ -500,7 +500,11 @@ static int usbmisc_imx_probe(struct platform_device *pdev) { struct resource *res; struct imx_usbmisc *data; - struct of_device_id *tmp_dev; + const struct of_device_id *of_id; + + of_id = of_match_device(usbmisc_imx_dt_ids, &pdev->dev); + if (!of_id) + return -ENODEV; data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); if (!data) @@ -513,9 +517,7 @@ static int usbmisc_imx_probe(struct platform_device *pdev) if (IS_ERR(data->base)) return PTR_ERR(data->base); - tmp_dev = (struct of_device_id *) - of_match_device(usbmisc_imx_dt_ids, &pdev->dev); - data->ops = (const struct usbmisc_ops *)tmp_dev->data; + data->ops = (const struct usbmisc_ops *)of_id->data; platform_set_drvdata(pdev, data); return 0; diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index 433bbc34a8a4..071964c7847f 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -884,11 +884,11 @@ static int usblp_wwait(struct usblp *usblp, int nonblock) add_wait_queue(&usblp->wwait, &waita); for (;;) { - set_current_state(TASK_INTERRUPTIBLE); if (mutex_lock_interruptible(&usblp->mut)) { rc = -EINTR; break; } + set_current_state(TASK_INTERRUPTIBLE); rc = usblp_wtest(usblp, nonblock); mutex_unlock(&usblp->mut); if (rc <= 0) diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig index a99c89e78126..dd280108758f 100644 --- a/drivers/usb/core/Kconfig +++ b/drivers/usb/core/Kconfig @@ -77,8 +77,7 @@ config USB_OTG_BLACKLIST_HUB config USB_OTG_FSM tristate "USB 2.0 OTG FSM implementation" - depends on USB - select USB_OTG + depends on USB && USB_OTG select USB_PHY help Implements OTG Finite State Machine as specified in On-The-Go diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index e79baf73c234..571c21727ff9 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -324,12 +324,13 @@ void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg) */ static void dwc2_hcd_rem_wakeup(struct dwc2_hsotg *hsotg) { - if (hsotg->lx_state == DWC2_L2) { + if (hsotg->bus_suspended) { hsotg->flags.b.port_suspend_change = 1; usb_hcd_resume_root_hub(hsotg->priv); - } else { - hsotg->flags.b.port_l1_change = 1; } + + if (hsotg->lx_state == DWC2_L1) + hsotg->flags.b.port_l1_change = 1; } /** @@ -1428,8 +1429,8 @@ static void dwc2_wakeup_detected(unsigned long data) dev_dbg(hsotg->dev, "Clear Resume: HPRT0=%0x\n", dwc2_readl(hsotg->regs + HPRT0)); - hsotg->bus_suspended = 0; dwc2_hcd_rem_wakeup(hsotg); + hsotg->bus_suspended = 0; /* Change to L0 state */ hsotg->lx_state = DWC2_L0; diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c index 5859b0fa19ee..e61d773cf65e 100644 --- a/drivers/usb/dwc2/platform.c +++ b/drivers/usb/dwc2/platform.c @@ -108,7 +108,8 @@ static const struct dwc2_core_params params_rk3066 = { .host_ls_low_power_phy_clk = -1, .ts_dline = -1, .reload_ctl = -1, - .ahbcfg = 0x7, /* INCR16 */ + .ahbcfg = GAHBCFG_HBSTLEN_INCR16 << + GAHBCFG_HBSTLEN_SHIFT, .uframe_sched = -1, .external_id_pin_ctl = -1, .hibernation = -1, diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index 77a622cb48ab..009d83048c8c 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -34,6 +34,8 @@ #define PCI_DEVICE_ID_INTEL_BSW 0x22b7 #define PCI_DEVICE_ID_INTEL_SPTLP 0x9d30 #define PCI_DEVICE_ID_INTEL_SPTH 0xa130 +#define PCI_DEVICE_ID_INTEL_BXT 0x0aaa +#define PCI_DEVICE_ID_INTEL_APL 0x5aaa static const struct acpi_gpio_params reset_gpios = { 0, 0, false }; static const struct acpi_gpio_params cs_gpios = { 1, 0, false }; @@ -210,6 +212,8 @@ static const struct pci_device_id dwc3_pci_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MRFLD), }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SPTLP), }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SPTH), }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BXT), }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_APL), }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_NL_USB), }, { } /* Terminating Entry */ }; diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 55ba447fdf8b..e24a01cc98df 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2744,12 +2744,34 @@ int dwc3_gadget_init(struct dwc3 *dwc) } dwc->gadget.ops = &dwc3_gadget_ops; - dwc->gadget.max_speed = USB_SPEED_SUPER; dwc->gadget.speed = USB_SPEED_UNKNOWN; dwc->gadget.sg_supported = true; dwc->gadget.name = "dwc3-gadget"; /* + * FIXME We might be setting max_speed to <SUPER, however versions + * <2.20a of dwc3 have an issue with metastability (documented + * elsewhere in this driver) which tells us we can't set max speed to + * anything lower than SUPER. + * + * Because gadget.max_speed is only used by composite.c and function + * drivers (i.e. it won't go into dwc3's registers) we are allowing this + * to happen so we avoid sending SuperSpeed Capability descriptor + * together with our BOS descriptor as that could confuse host into + * thinking we can handle super speed. + * + * Note that, in fact, we won't even support GetBOS requests when speed + * is less than super speed because we don't have means, yet, to tell + * composite.c that we are USB 2.0 + LPM ECN. + */ + if (dwc->revision < DWC3_REVISION_220A) + dwc3_trace(trace_dwc3_gadget, + "Changing max_speed on rev %08x\n", + dwc->revision); + + dwc->gadget.max_speed = dwc->maximum_speed; + + /* * Per databook, DWC3 needs buffer size to be aligned to MaxPacketSize * on ep out. */ diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index 294eb74fb078..163d305e1200 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -64,6 +64,11 @@ struct gadget_info { char qw_sign[OS_STRING_QW_SIGN_LEN]; }; +static inline struct gadget_info *to_gadget_info(struct config_item *item) +{ + return container_of(to_config_group(item), struct gadget_info, group); +} + struct config_usb_cfg { struct config_group group; struct config_group strings_group; @@ -74,6 +79,12 @@ struct config_usb_cfg { struct usb_gadget_strings *gstrings[MAX_USB_STRING_LANGS + 1]; }; +static inline struct config_usb_cfg *to_config_usb_cfg(struct config_item *item) +{ + return container_of(to_config_group(item), struct config_usb_cfg, + group); +} + struct gadget_strings { struct usb_gadget_strings stringtab_dev; struct usb_string strings[USB_GADGET_FIRST_AVAIL_IDX]; @@ -117,32 +128,25 @@ static int usb_string_copy(const char *s, char **s_copy) return 0; } -CONFIGFS_ATTR_STRUCT(gadget_info); -CONFIGFS_ATTR_STRUCT(config_usb_cfg); - -#define GI_DEVICE_DESC_ITEM_ATTR(name) \ - static struct gadget_info_attribute gadget_cdev_desc_##name = \ - __CONFIGFS_ATTR(name, S_IRUGO | S_IWUSR, \ - gadget_dev_desc_##name##_show, \ - gadget_dev_desc_##name##_store) - #define GI_DEVICE_DESC_SIMPLE_R_u8(__name) \ - static ssize_t gadget_dev_desc_##__name##_show(struct gadget_info *gi, \ +static ssize_t gadget_dev_desc_##__name##_show(struct config_item *item, \ char *page) \ { \ - return sprintf(page, "0x%02x\n", gi->cdev.desc.__name); \ + return sprintf(page, "0x%02x\n", \ + to_gadget_info(item)->cdev.desc.__name); \ } #define GI_DEVICE_DESC_SIMPLE_R_u16(__name) \ - static ssize_t gadget_dev_desc_##__name##_show(struct gadget_info *gi, \ +static ssize_t gadget_dev_desc_##__name##_show(struct config_item *item, \ char *page) \ { \ - return sprintf(page, "0x%04x\n", le16_to_cpup(&gi->cdev.desc.__name)); \ + return sprintf(page, "0x%04x\n", \ + le16_to_cpup(&to_gadget_info(item)->cdev.desc.__name)); \ } #define GI_DEVICE_DESC_SIMPLE_W_u8(_name) \ - static ssize_t gadget_dev_desc_##_name##_store(struct gadget_info *gi, \ +static ssize_t gadget_dev_desc_##_name##_store(struct config_item *item, \ const char *page, size_t len) \ { \ u8 val; \ @@ -150,12 +154,12 @@ CONFIGFS_ATTR_STRUCT(config_usb_cfg); ret = kstrtou8(page, 0, &val); \ if (ret) \ return ret; \ - gi->cdev.desc._name = val; \ + to_gadget_info(item)->cdev.desc._name = val; \ return len; \ } #define GI_DEVICE_DESC_SIMPLE_W_u16(_name) \ - static ssize_t gadget_dev_desc_##_name##_store(struct gadget_info *gi, \ +static ssize_t gadget_dev_desc_##_name##_store(struct config_item *item, \ const char *page, size_t len) \ { \ u16 val; \ @@ -163,7 +167,7 @@ CONFIGFS_ATTR_STRUCT(config_usb_cfg); ret = kstrtou16(page, 0, &val); \ if (ret) \ return ret; \ - gi->cdev.desc._name = cpu_to_le16p(&val); \ + to_gadget_info(item)->cdev.desc._name = cpu_to_le16p(&val); \ return len; \ } @@ -193,7 +197,7 @@ static ssize_t is_valid_bcd(u16 bcd_val) return 0; } -static ssize_t gadget_dev_desc_bcdDevice_store(struct gadget_info *gi, +static ssize_t gadget_dev_desc_bcdDevice_store(struct config_item *item, const char *page, size_t len) { u16 bcdDevice; @@ -206,11 +210,11 @@ static ssize_t gadget_dev_desc_bcdDevice_store(struct gadget_info *gi, if (ret) return ret; - gi->cdev.desc.bcdDevice = cpu_to_le16(bcdDevice); + to_gadget_info(item)->cdev.desc.bcdDevice = cpu_to_le16(bcdDevice); return len; } -static ssize_t gadget_dev_desc_bcdUSB_store(struct gadget_info *gi, +static ssize_t gadget_dev_desc_bcdUSB_store(struct config_item *item, const char *page, size_t len) { u16 bcdUSB; @@ -223,13 +227,13 @@ static ssize_t gadget_dev_desc_bcdUSB_store(struct gadget_info *gi, if (ret) return ret; - gi->cdev.desc.bcdUSB = cpu_to_le16(bcdUSB); + to_gadget_info(item)->cdev.desc.bcdUSB = cpu_to_le16(bcdUSB); return len; } -static ssize_t gadget_dev_desc_UDC_show(struct gadget_info *gi, char *page) +static ssize_t gadget_dev_desc_UDC_show(struct config_item *item, char *page) { - return sprintf(page, "%s\n", gi->udc_name ?: ""); + return sprintf(page, "%s\n", to_gadget_info(item)->udc_name ?: ""); } static int unregister_gadget(struct gadget_info *gi) @@ -247,9 +251,10 @@ static int unregister_gadget(struct gadget_info *gi) return 0; } -static ssize_t gadget_dev_desc_UDC_store(struct gadget_info *gi, +static ssize_t gadget_dev_desc_UDC_store(struct config_item *item, const char *page, size_t len) { + struct gadget_info *gi = to_gadget_info(item); char *name; int ret; @@ -283,34 +288,29 @@ err: return ret; } -GI_DEVICE_DESC_ITEM_ATTR(bDeviceClass); -GI_DEVICE_DESC_ITEM_ATTR(bDeviceSubClass); -GI_DEVICE_DESC_ITEM_ATTR(bDeviceProtocol); -GI_DEVICE_DESC_ITEM_ATTR(bMaxPacketSize0); -GI_DEVICE_DESC_ITEM_ATTR(idVendor); -GI_DEVICE_DESC_ITEM_ATTR(idProduct); -GI_DEVICE_DESC_ITEM_ATTR(bcdDevice); -GI_DEVICE_DESC_ITEM_ATTR(bcdUSB); -GI_DEVICE_DESC_ITEM_ATTR(UDC); +CONFIGFS_ATTR(gadget_dev_desc_, bDeviceClass); +CONFIGFS_ATTR(gadget_dev_desc_, bDeviceSubClass); +CONFIGFS_ATTR(gadget_dev_desc_, bDeviceProtocol); +CONFIGFS_ATTR(gadget_dev_desc_, bMaxPacketSize0); +CONFIGFS_ATTR(gadget_dev_desc_, idVendor); +CONFIGFS_ATTR(gadget_dev_desc_, idProduct); +CONFIGFS_ATTR(gadget_dev_desc_, bcdDevice); +CONFIGFS_ATTR(gadget_dev_desc_, bcdUSB); +CONFIGFS_ATTR(gadget_dev_desc_, UDC); static struct configfs_attribute *gadget_root_attrs[] = { - &gadget_cdev_desc_bDeviceClass.attr, - &gadget_cdev_desc_bDeviceSubClass.attr, - &gadget_cdev_desc_bDeviceProtocol.attr, - &gadget_cdev_desc_bMaxPacketSize0.attr, - &gadget_cdev_desc_idVendor.attr, - &gadget_cdev_desc_idProduct.attr, - &gadget_cdev_desc_bcdDevice.attr, - &gadget_cdev_desc_bcdUSB.attr, - &gadget_cdev_desc_UDC.attr, + &gadget_dev_desc_attr_bDeviceClass, + &gadget_dev_desc_attr_bDeviceSubClass, + &gadget_dev_desc_attr_bDeviceProtocol, + &gadget_dev_desc_attr_bMaxPacketSize0, + &gadget_dev_desc_attr_idVendor, + &gadget_dev_desc_attr_idProduct, + &gadget_dev_desc_attr_bcdDevice, + &gadget_dev_desc_attr_bcdUSB, + &gadget_dev_desc_attr_UDC, NULL, }; -static inline struct gadget_info *to_gadget_info(struct config_item *item) -{ - return container_of(to_config_group(item), struct gadget_info, group); -} - static inline struct gadget_strings *to_gadget_strings(struct config_item *item) { return container_of(to_config_group(item), struct gadget_strings, @@ -324,12 +324,6 @@ static inline struct gadget_config_name *to_gadget_config_name( group); } -static inline struct config_usb_cfg *to_config_usb_cfg(struct config_item *item) -{ - return container_of(to_config_group(item), struct config_usb_cfg, - group); -} - static inline struct usb_function_instance *to_usb_function_instance( struct config_item *item) { @@ -348,12 +342,8 @@ static void gadget_info_attr_release(struct config_item *item) kfree(gi); } -CONFIGFS_ATTR_OPS(gadget_info); - static struct configfs_item_operations gadget_root_item_ops = { .release = gadget_info_attr_release, - .show_attribute = gadget_info_attr_show, - .store_attribute = gadget_info_attr_store, }; static void gadget_config_attr_release(struct config_item *item) @@ -454,24 +444,20 @@ static int config_usb_cfg_unlink( return 0; } -CONFIGFS_ATTR_OPS(config_usb_cfg); - static struct configfs_item_operations gadget_config_item_ops = { .release = gadget_config_attr_release, - .show_attribute = config_usb_cfg_attr_show, - .store_attribute = config_usb_cfg_attr_store, .allow_link = config_usb_cfg_link, .drop_link = config_usb_cfg_unlink, }; -static ssize_t gadget_config_desc_MaxPower_show(struct config_usb_cfg *cfg, +static ssize_t gadget_config_desc_MaxPower_show(struct config_item *item, char *page) { - return sprintf(page, "%u\n", cfg->c.MaxPower); + return sprintf(page, "%u\n", to_config_usb_cfg(item)->c.MaxPower); } -static ssize_t gadget_config_desc_MaxPower_store(struct config_usb_cfg *cfg, +static ssize_t gadget_config_desc_MaxPower_store(struct config_item *item, const char *page, size_t len) { u16 val; @@ -481,17 +467,18 @@ static ssize_t gadget_config_desc_MaxPower_store(struct config_usb_cfg *cfg, return ret; if (DIV_ROUND_UP(val, 8) > 0xff) return -ERANGE; - cfg->c.MaxPower = val; + to_config_usb_cfg(item)->c.MaxPower = val; return len; } -static ssize_t gadget_config_desc_bmAttributes_show(struct config_usb_cfg *cfg, +static ssize_t gadget_config_desc_bmAttributes_show(struct config_item *item, char *page) { - return sprintf(page, "0x%02x\n", cfg->c.bmAttributes); + return sprintf(page, "0x%02x\n", + to_config_usb_cfg(item)->c.bmAttributes); } -static ssize_t gadget_config_desc_bmAttributes_store(struct config_usb_cfg *cfg, +static ssize_t gadget_config_desc_bmAttributes_store(struct config_item *item, const char *page, size_t len) { u8 val; @@ -504,22 +491,16 @@ static ssize_t gadget_config_desc_bmAttributes_store(struct config_usb_cfg *cfg, if (val & ~(USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER | USB_CONFIG_ATT_WAKEUP)) return -EINVAL; - cfg->c.bmAttributes = val; + to_config_usb_cfg(item)->c.bmAttributes = val; return len; } -#define CFG_CONFIG_DESC_ITEM_ATTR(name) \ - static struct config_usb_cfg_attribute gadget_usb_cfg_##name = \ - __CONFIGFS_ATTR(name, S_IRUGO | S_IWUSR, \ - gadget_config_desc_##name##_show, \ - gadget_config_desc_##name##_store) - -CFG_CONFIG_DESC_ITEM_ATTR(MaxPower); -CFG_CONFIG_DESC_ITEM_ATTR(bmAttributes); +CONFIGFS_ATTR(gadget_config_desc_, MaxPower); +CONFIGFS_ATTR(gadget_config_desc_, bmAttributes); static struct configfs_attribute *gadget_config_attrs[] = { - &gadget_usb_cfg_MaxPower.attr, - &gadget_usb_cfg_bmAttributes.attr, + &gadget_config_desc_attr_MaxPower, + &gadget_config_desc_attr_bmAttributes, NULL, }; @@ -616,11 +597,10 @@ static struct config_item_type functions_type = { .ct_owner = THIS_MODULE, }; -CONFIGFS_ATTR_STRUCT(gadget_config_name); GS_STRINGS_RW(gadget_config_name, configuration); static struct configfs_attribute *gadget_config_name_langid_attrs[] = { - &gadget_config_name_configuration.attr, + &gadget_config_name_attr_configuration, NULL, }; @@ -719,15 +699,14 @@ static struct config_item_type config_desc_type = { .ct_owner = THIS_MODULE, }; -CONFIGFS_ATTR_STRUCT(gadget_strings); GS_STRINGS_RW(gadget_strings, manufacturer); GS_STRINGS_RW(gadget_strings, product); GS_STRINGS_RW(gadget_strings, serialnumber); static struct configfs_attribute *gadget_strings_langid_attrs[] = { - &gadget_strings_manufacturer.attr, - &gadget_strings_product.attr, - &gadget_strings_serialnumber.attr, + &gadget_strings_attr_manufacturer, + &gadget_strings_attr_product, + &gadget_strings_attr_serialnumber, NULL, }; @@ -751,27 +730,25 @@ static inline struct os_desc *to_os_desc(struct config_item *item) return container_of(to_config_group(item), struct os_desc, group); } -CONFIGFS_ATTR_STRUCT(os_desc); -CONFIGFS_ATTR_OPS(os_desc); - -static ssize_t os_desc_use_show(struct os_desc *os_desc, char *page) +static inline struct gadget_info *os_desc_item_to_gadget_info( + struct config_item *item) { - struct gadget_info *gi; - - gi = to_gadget_info(os_desc->group.cg_item.ci_parent); + return to_gadget_info(to_os_desc(item)->group.cg_item.ci_parent); +} - return sprintf(page, "%d", gi->use_os_desc); +static ssize_t os_desc_use_show(struct config_item *item, char *page) +{ + return sprintf(page, "%d", + os_desc_item_to_gadget_info(item)->use_os_desc); } -static ssize_t os_desc_use_store(struct os_desc *os_desc, const char *page, +static ssize_t os_desc_use_store(struct config_item *item, const char *page, size_t len) { - struct gadget_info *gi; + struct gadget_info *gi = os_desc_item_to_gadget_info(item); int ret; bool use; - gi = to_gadget_info(os_desc->group.cg_item.ci_parent); - mutex_lock(&gi->lock); ret = strtobool(page, &use); if (!ret) { @@ -783,29 +760,19 @@ static ssize_t os_desc_use_store(struct os_desc *os_desc, const char *page, return ret; } -static struct os_desc_attribute os_desc_use = - __CONFIGFS_ATTR(use, S_IRUGO | S_IWUSR, - os_desc_use_show, - os_desc_use_store); - -static ssize_t os_desc_b_vendor_code_show(struct os_desc *os_desc, char *page) +static ssize_t os_desc_b_vendor_code_show(struct config_item *item, char *page) { - struct gadget_info *gi; - - gi = to_gadget_info(os_desc->group.cg_item.ci_parent); - - return sprintf(page, "%d", gi->b_vendor_code); + return sprintf(page, "%d", + os_desc_item_to_gadget_info(item)->b_vendor_code); } -static ssize_t os_desc_b_vendor_code_store(struct os_desc *os_desc, +static ssize_t os_desc_b_vendor_code_store(struct config_item *item, const char *page, size_t len) { - struct gadget_info *gi; + struct gadget_info *gi = os_desc_item_to_gadget_info(item); int ret; u8 b_vendor_code; - gi = to_gadget_info(os_desc->group.cg_item.ci_parent); - mutex_lock(&gi->lock); ret = kstrtou8(page, 0, &b_vendor_code); if (!ret) { @@ -817,29 +784,20 @@ static ssize_t os_desc_b_vendor_code_store(struct os_desc *os_desc, return ret; } -static struct os_desc_attribute os_desc_b_vendor_code = - __CONFIGFS_ATTR(b_vendor_code, S_IRUGO | S_IWUSR, - os_desc_b_vendor_code_show, - os_desc_b_vendor_code_store); - -static ssize_t os_desc_qw_sign_show(struct os_desc *os_desc, char *page) +static ssize_t os_desc_qw_sign_show(struct config_item *item, char *page) { - struct gadget_info *gi; - - gi = to_gadget_info(os_desc->group.cg_item.ci_parent); + struct gadget_info *gi = os_desc_item_to_gadget_info(item); memcpy(page, gi->qw_sign, OS_STRING_QW_SIGN_LEN); - return OS_STRING_QW_SIGN_LEN; } -static ssize_t os_desc_qw_sign_store(struct os_desc *os_desc, const char *page, +static ssize_t os_desc_qw_sign_store(struct config_item *item, const char *page, size_t len) { - struct gadget_info *gi; + struct gadget_info *gi = os_desc_item_to_gadget_info(item); int res, l; - gi = to_gadget_info(os_desc->group.cg_item.ci_parent); l = min((int)len, OS_STRING_QW_SIGN_LEN >> 1); if (page[l - 1] == '\n') --l; @@ -855,15 +813,14 @@ static ssize_t os_desc_qw_sign_store(struct os_desc *os_desc, const char *page, return res; } -static struct os_desc_attribute os_desc_qw_sign = - __CONFIGFS_ATTR(qw_sign, S_IRUGO | S_IWUSR, - os_desc_qw_sign_show, - os_desc_qw_sign_store); +CONFIGFS_ATTR(os_desc_, use); +CONFIGFS_ATTR(os_desc_, b_vendor_code); +CONFIGFS_ATTR(os_desc_, qw_sign); static struct configfs_attribute *os_desc_attrs[] = { - &os_desc_use.attr, - &os_desc_b_vendor_code.attr, - &os_desc_qw_sign.attr, + &os_desc_attr_use, + &os_desc_attr_b_vendor_code, + &os_desc_attr_qw_sign, NULL, }; @@ -926,8 +883,6 @@ static int os_desc_unlink(struct config_item *os_desc_ci, static struct configfs_item_operations os_desc_ops = { .release = os_desc_attr_release, - .show_attribute = os_desc_attr_show, - .store_attribute = os_desc_attr_store, .allow_link = os_desc_link, .drop_link = os_desc_unlink, }; @@ -938,28 +893,21 @@ static struct config_item_type os_desc_type = { .ct_owner = THIS_MODULE, }; -CONFIGFS_ATTR_STRUCT(usb_os_desc); -CONFIGFS_ATTR_OPS(usb_os_desc); - - static inline struct usb_os_desc_ext_prop *to_usb_os_desc_ext_prop(struct config_item *item) { return container_of(item, struct usb_os_desc_ext_prop, item); } -CONFIGFS_ATTR_STRUCT(usb_os_desc_ext_prop); -CONFIGFS_ATTR_OPS(usb_os_desc_ext_prop); - -static ssize_t ext_prop_type_show(struct usb_os_desc_ext_prop *ext_prop, - char *page) +static ssize_t ext_prop_type_show(struct config_item *item, char *page) { - return sprintf(page, "%d", ext_prop->type); + return sprintf(page, "%d", to_usb_os_desc_ext_prop(item)->type); } -static ssize_t ext_prop_type_store(struct usb_os_desc_ext_prop *ext_prop, +static ssize_t ext_prop_type_store(struct config_item *item, const char *page, size_t len) { + struct usb_os_desc_ext_prop *ext_prop = to_usb_os_desc_ext_prop(item); struct usb_os_desc *desc = to_usb_os_desc(ext_prop->item.ci_parent); u8 type; int ret; @@ -997,9 +945,9 @@ end: return ret; } -static ssize_t ext_prop_data_show(struct usb_os_desc_ext_prop *ext_prop, - char *page) +static ssize_t ext_prop_data_show(struct config_item *item, char *page) { + struct usb_os_desc_ext_prop *ext_prop = to_usb_os_desc_ext_prop(item); int len = ext_prop->data_len; if (ext_prop->type == USB_EXT_PROP_UNICODE || @@ -1011,9 +959,10 @@ static ssize_t ext_prop_data_show(struct usb_os_desc_ext_prop *ext_prop, return len; } -static ssize_t ext_prop_data_store(struct usb_os_desc_ext_prop *ext_prop, +static ssize_t ext_prop_data_store(struct config_item *item, const char *page, size_t len) { + struct usb_os_desc_ext_prop *ext_prop = to_usb_os_desc_ext_prop(item); struct usb_os_desc *desc = to_usb_os_desc(ext_prop->item.ci_parent); char *new_data; size_t ret_len = len; @@ -1044,17 +993,12 @@ static ssize_t ext_prop_data_store(struct usb_os_desc_ext_prop *ext_prop, return ret_len; } -static struct usb_os_desc_ext_prop_attribute ext_prop_type = - __CONFIGFS_ATTR(type, S_IRUGO | S_IWUSR, - ext_prop_type_show, ext_prop_type_store); - -static struct usb_os_desc_ext_prop_attribute ext_prop_data = - __CONFIGFS_ATTR(data, S_IRUGO | S_IWUSR, - ext_prop_data_show, ext_prop_data_store); +CONFIGFS_ATTR(ext_prop_, type); +CONFIGFS_ATTR(ext_prop_, data); static struct configfs_attribute *ext_prop_attrs[] = { - &ext_prop_type.attr, - &ext_prop_data.attr, + &ext_prop_attr_type, + &ext_prop_attr_data, NULL, }; @@ -1067,8 +1011,6 @@ static void usb_os_desc_ext_prop_release(struct config_item *item) static struct configfs_item_operations ext_prop_ops = { .release = usb_os_desc_ext_prop_release, - .show_attribute = usb_os_desc_ext_prop_attr_show, - .store_attribute = usb_os_desc_ext_prop_attr_store, }; static struct config_item *ext_prop_make( @@ -1137,21 +1079,17 @@ static struct configfs_group_operations interf_grp_ops = { .drop_item = &ext_prop_drop, }; -static struct configfs_item_operations interf_item_ops = { - .show_attribute = usb_os_desc_attr_show, - .store_attribute = usb_os_desc_attr_store, -}; - -static ssize_t interf_grp_compatible_id_show(struct usb_os_desc *desc, +static ssize_t interf_grp_compatible_id_show(struct config_item *item, char *page) { - memcpy(page, desc->ext_compat_id, 8); + memcpy(page, to_usb_os_desc(item)->ext_compat_id, 8); return 8; } -static ssize_t interf_grp_compatible_id_store(struct usb_os_desc *desc, +static ssize_t interf_grp_compatible_id_store(struct config_item *item, const char *page, size_t len) { + struct usb_os_desc *desc = to_usb_os_desc(item); int l; l = min_t(int, 8, len); @@ -1167,21 +1105,17 @@ static ssize_t interf_grp_compatible_id_store(struct usb_os_desc *desc, return len; } -static struct usb_os_desc_attribute interf_grp_attr_compatible_id = - __CONFIGFS_ATTR(compatible_id, S_IRUGO | S_IWUSR, - interf_grp_compatible_id_show, - interf_grp_compatible_id_store); - -static ssize_t interf_grp_sub_compatible_id_show(struct usb_os_desc *desc, +static ssize_t interf_grp_sub_compatible_id_show(struct config_item *item, char *page) { - memcpy(page, desc->ext_compat_id + 8, 8); + memcpy(page, to_usb_os_desc(item)->ext_compat_id + 8, 8); return 8; } -static ssize_t interf_grp_sub_compatible_id_store(struct usb_os_desc *desc, +static ssize_t interf_grp_sub_compatible_id_store(struct config_item *item, const char *page, size_t len) { + struct usb_os_desc *desc = to_usb_os_desc(item); int l; l = min_t(int, 8, len); @@ -1197,14 +1131,12 @@ static ssize_t interf_grp_sub_compatible_id_store(struct usb_os_desc *desc, return len; } -static struct usb_os_desc_attribute interf_grp_attr_sub_compatible_id = - __CONFIGFS_ATTR(sub_compatible_id, S_IRUGO | S_IWUSR, - interf_grp_sub_compatible_id_show, - interf_grp_sub_compatible_id_store); +CONFIGFS_ATTR(interf_grp_, compatible_id); +CONFIGFS_ATTR(interf_grp_, sub_compatible_id); static struct configfs_attribute *interf_grp_attrs[] = { - &interf_grp_attr_compatible_id.attr, - &interf_grp_attr_sub_compatible_id.attr, + &interf_grp_attr_compatible_id, + &interf_grp_attr_sub_compatible_id, NULL }; @@ -1242,7 +1174,6 @@ int usb_os_desc_prepare_interf_dir(struct config_group *parent, f_default_groups[0] = os_desc_group; os_desc_group->default_groups = interface_groups; - interface_type->ct_item_ops = &interf_item_ops; interface_type->ct_group_ops = &interf_grp_ops; interface_type->ct_attrs = interf_grp_attrs; interface_type->ct_owner = owner; diff --git a/drivers/usb/gadget/function/f_acm.c b/drivers/usb/gadget/function/f_acm.c index 22e723d12d36..2fa1e80a3ce7 100644 --- a/drivers/usb/gadget/function/f_acm.c +++ b/drivers/usb/gadget/function/f_acm.c @@ -761,21 +761,6 @@ static inline struct f_serial_opts *to_f_serial_opts(struct config_item *item) func_inst.group); } -CONFIGFS_ATTR_STRUCT(f_serial_opts); -static ssize_t f_acm_attr_show(struct config_item *item, - struct configfs_attribute *attr, - char *page) -{ - struct f_serial_opts *opts = to_f_serial_opts(item); - struct f_serial_opts_attribute *f_serial_opts_attr = - container_of(attr, struct f_serial_opts_attribute, attr); - ssize_t ret = 0; - - if (f_serial_opts_attr->show) - ret = f_serial_opts_attr->show(opts, page); - return ret; -} - static void acm_attr_release(struct config_item *item) { struct f_serial_opts *opts = to_f_serial_opts(item); @@ -785,20 +770,17 @@ static void acm_attr_release(struct config_item *item) static struct configfs_item_operations acm_item_ops = { .release = acm_attr_release, - .show_attribute = f_acm_attr_show, }; -static ssize_t f_acm_port_num_show(struct f_serial_opts *opts, char *page) +static ssize_t f_acm_port_num_show(struct config_item *item, char *page) { - return sprintf(page, "%u\n", opts->port_num); + return sprintf(page, "%u\n", to_f_serial_opts(item)->port_num); } -static struct f_serial_opts_attribute f_acm_port_num = - __CONFIGFS_ATTR_RO(port_num, f_acm_port_num_show); - +CONFIGFS_ATTR_RO(f_acm_port_, num); static struct configfs_attribute *acm_attrs[] = { - &f_acm_port_num.attr, + &f_acm_port_attr_num, NULL, }; diff --git a/drivers/usb/gadget/function/f_ecm.c b/drivers/usb/gadget/function/f_ecm.c index 4abca70cdaab..7ad60ee41914 100644 --- a/drivers/usb/gadget/function/f_ecm.c +++ b/drivers/usb/gadget/function/f_ecm.c @@ -838,10 +838,10 @@ USB_ETHERNET_CONFIGFS_ITEM_ATTR_QMULT(ecm); USB_ETHERNET_CONFIGFS_ITEM_ATTR_IFNAME(ecm); static struct configfs_attribute *ecm_attrs[] = { - &f_ecm_opts_dev_addr.attr, - &f_ecm_opts_host_addr.attr, - &f_ecm_opts_qmult.attr, - &f_ecm_opts_ifname.attr, + &ecm_opts_attr_dev_addr, + &ecm_opts_attr_host_addr, + &ecm_opts_attr_qmult, + &ecm_opts_attr_ifname, NULL, }; diff --git a/drivers/usb/gadget/function/f_eem.c b/drivers/usb/gadget/function/f_eem.c index 9a55757c729b..cad35a502d3f 100644 --- a/drivers/usb/gadget/function/f_eem.c +++ b/drivers/usb/gadget/function/f_eem.c @@ -545,10 +545,10 @@ USB_ETHERNET_CONFIGFS_ITEM_ATTR_QMULT(eem); USB_ETHERNET_CONFIGFS_ITEM_ATTR_IFNAME(eem); static struct configfs_attribute *eem_attrs[] = { - &f_eem_opts_dev_addr.attr, - &f_eem_opts_host_addr.attr, - &f_eem_opts_qmult.attr, - &f_eem_opts_ifname.attr, + &eem_opts_attr_dev_addr, + &eem_opts_attr_host_addr, + &eem_opts_attr_qmult, + &eem_opts_attr_ifname, NULL, }; diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c index 21fcf18f53a0..99285b416308 100644 --- a/drivers/usb/gadget/function/f_hid.c +++ b/drivers/usb/gadget/function/f_hid.c @@ -705,9 +705,6 @@ static inline struct f_hid_opts *to_f_hid_opts(struct config_item *item) func_inst.group); } -CONFIGFS_ATTR_STRUCT(f_hid_opts); -CONFIGFS_ATTR_OPS(f_hid_opts); - static void hid_attr_release(struct config_item *item) { struct f_hid_opts *opts = to_f_hid_opts(item); @@ -717,13 +714,12 @@ static void hid_attr_release(struct config_item *item) static struct configfs_item_operations hidg_item_ops = { .release = hid_attr_release, - .show_attribute = f_hid_opts_attr_show, - .store_attribute = f_hid_opts_attr_store, }; #define F_HID_OPT(name, prec, limit) \ -static ssize_t f_hid_opts_##name##_show(struct f_hid_opts *opts, char *page)\ +static ssize_t f_hid_opts_##name##_show(struct config_item *item, char *page)\ { \ + struct f_hid_opts *opts = to_f_hid_opts(item); \ int result; \ \ mutex_lock(&opts->lock); \ @@ -733,9 +729,10 @@ static ssize_t f_hid_opts_##name##_show(struct f_hid_opts *opts, char *page)\ return result; \ } \ \ -static ssize_t f_hid_opts_##name##_store(struct f_hid_opts *opts, \ +static ssize_t f_hid_opts_##name##_store(struct config_item *item, \ const char *page, size_t len) \ { \ + struct f_hid_opts *opts = to_f_hid_opts(item); \ int ret; \ u##prec num; \ \ @@ -761,16 +758,15 @@ end: \ return ret; \ } \ \ -static struct f_hid_opts_attribute f_hid_opts_##name = \ - __CONFIGFS_ATTR(name, S_IRUGO | S_IWUSR, f_hid_opts_##name##_show,\ - f_hid_opts_##name##_store) +CONFIGFS_ATTR(f_hid_opts_, name) F_HID_OPT(subclass, 8, 255); F_HID_OPT(protocol, 8, 255); F_HID_OPT(report_length, 16, 65535); -static ssize_t f_hid_opts_report_desc_show(struct f_hid_opts *opts, char *page) +static ssize_t f_hid_opts_report_desc_show(struct config_item *item, char *page) { + struct f_hid_opts *opts = to_f_hid_opts(item); int result; mutex_lock(&opts->lock); @@ -781,9 +777,10 @@ static ssize_t f_hid_opts_report_desc_show(struct f_hid_opts *opts, char *page) return result; } -static ssize_t f_hid_opts_report_desc_store(struct f_hid_opts *opts, +static ssize_t f_hid_opts_report_desc_store(struct config_item *item, const char *page, size_t len) { + struct f_hid_opts *opts = to_f_hid_opts(item); int ret = -EBUSY; char *d; @@ -810,16 +807,13 @@ end: return ret; } -static struct f_hid_opts_attribute f_hid_opts_report_desc = - __CONFIGFS_ATTR(report_desc, S_IRUGO | S_IWUSR, - f_hid_opts_report_desc_show, - f_hid_opts_report_desc_store); +CONFIGFS_ATTR(f_hid_opts_, report_desc); static struct configfs_attribute *hid_attrs[] = { - &f_hid_opts_subclass.attr, - &f_hid_opts_protocol.attr, - &f_hid_opts_report_length.attr, - &f_hid_opts_report_desc.attr, + &f_hid_opts_attr_subclass, + &f_hid_opts_attr_protocol, + &f_hid_opts_attr_report_length, + &f_hid_opts_attr_report_desc, NULL, }; diff --git a/drivers/usb/gadget/function/f_loopback.c b/drivers/usb/gadget/function/f_loopback.c index 6b2102bc0699..ddc3aad886b7 100644 --- a/drivers/usb/gadget/function/f_loopback.c +++ b/drivers/usb/gadget/function/f_loopback.c @@ -329,7 +329,7 @@ static int alloc_requests(struct usb_composite_dev *cdev, for (i = 0; i < loop->qlen && result == 0; i++) { result = -ENOMEM; - in_req = usb_ep_alloc_request(loop->in_ep, GFP_KERNEL); + in_req = usb_ep_alloc_request(loop->in_ep, GFP_ATOMIC); if (!in_req) goto fail; @@ -465,9 +465,6 @@ static inline struct f_lb_opts *to_f_lb_opts(struct config_item *item) func_inst.group); } -CONFIGFS_ATTR_STRUCT(f_lb_opts); -CONFIGFS_ATTR_OPS(f_lb_opts); - static void lb_attr_release(struct config_item *item) { struct f_lb_opts *lb_opts = to_f_lb_opts(item); @@ -477,12 +474,11 @@ static void lb_attr_release(struct config_item *item) static struct configfs_item_operations lb_item_ops = { .release = lb_attr_release, - .show_attribute = f_lb_opts_attr_show, - .store_attribute = f_lb_opts_attr_store, }; -static ssize_t f_lb_opts_qlen_show(struct f_lb_opts *opts, char *page) +static ssize_t f_lb_opts_qlen_show(struct config_item *item, char *page) { + struct f_lb_opts *opts = to_f_lb_opts(item); int result; mutex_lock(&opts->lock); @@ -492,9 +488,10 @@ static ssize_t f_lb_opts_qlen_show(struct f_lb_opts *opts, char *page) return result; } -static ssize_t f_lb_opts_qlen_store(struct f_lb_opts *opts, +static ssize_t f_lb_opts_qlen_store(struct config_item *item, const char *page, size_t len) { + struct f_lb_opts *opts = to_f_lb_opts(item); int ret; u32 num; @@ -515,13 +512,11 @@ end: return ret; } -static struct f_lb_opts_attribute f_lb_opts_qlen = - __CONFIGFS_ATTR(qlen, S_IRUGO | S_IWUSR, - f_lb_opts_qlen_show, - f_lb_opts_qlen_store); +CONFIGFS_ATTR(f_lb_opts_, qlen); -static ssize_t f_lb_opts_bulk_buflen_show(struct f_lb_opts *opts, char *page) +static ssize_t f_lb_opts_bulk_buflen_show(struct config_item *item, char *page) { + struct f_lb_opts *opts = to_f_lb_opts(item); int result; mutex_lock(&opts->lock); @@ -531,9 +526,10 @@ static ssize_t f_lb_opts_bulk_buflen_show(struct f_lb_opts *opts, char *page) return result; } -static ssize_t f_lb_opts_bulk_buflen_store(struct f_lb_opts *opts, +static ssize_t f_lb_opts_bulk_buflen_store(struct config_item *item, const char *page, size_t len) { + struct f_lb_opts *opts = to_f_lb_opts(item); int ret; u32 num; @@ -554,14 +550,11 @@ end: return ret; } -static struct f_lb_opts_attribute f_lb_opts_bulk_buflen = - __CONFIGFS_ATTR(buflen, S_IRUGO | S_IWUSR, - f_lb_opts_bulk_buflen_show, - f_lb_opts_bulk_buflen_store); +CONFIGFS_ATTR(f_lb_opts_, bulk_buflen); static struct configfs_attribute *lb_attrs[] = { - &f_lb_opts_qlen.attr, - &f_lb_opts_bulk_buflen.attr, + &f_lb_opts_attr_qlen, + &f_lb_opts_attr_bulk_buflen, NULL, }; diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index 5ec533826621..223ccf89d226 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -3140,9 +3140,6 @@ static inline struct fsg_opts *to_fsg_opts(struct config_item *item) func_inst.group); } -CONFIGFS_ATTR_STRUCT(fsg_lun_opts); -CONFIGFS_ATTR_OPS(fsg_lun_opts); - static void fsg_lun_attr_release(struct config_item *item) { struct fsg_lun_opts *lun_opts; @@ -3153,110 +3150,93 @@ static void fsg_lun_attr_release(struct config_item *item) static struct configfs_item_operations fsg_lun_item_ops = { .release = fsg_lun_attr_release, - .show_attribute = fsg_lun_opts_attr_show, - .store_attribute = fsg_lun_opts_attr_store, }; -static ssize_t fsg_lun_opts_file_show(struct fsg_lun_opts *opts, char *page) +static ssize_t fsg_lun_opts_file_show(struct config_item *item, char *page) { - struct fsg_opts *fsg_opts; - - fsg_opts = to_fsg_opts(opts->group.cg_item.ci_parent); + struct fsg_lun_opts *opts = to_fsg_lun_opts(item); + struct fsg_opts *fsg_opts = to_fsg_opts(opts->group.cg_item.ci_parent); return fsg_show_file(opts->lun, &fsg_opts->common->filesem, page); } -static ssize_t fsg_lun_opts_file_store(struct fsg_lun_opts *opts, +static ssize_t fsg_lun_opts_file_store(struct config_item *item, const char *page, size_t len) { - struct fsg_opts *fsg_opts; - - fsg_opts = to_fsg_opts(opts->group.cg_item.ci_parent); + struct fsg_lun_opts *opts = to_fsg_lun_opts(item); + struct fsg_opts *fsg_opts = to_fsg_opts(opts->group.cg_item.ci_parent); return fsg_store_file(opts->lun, &fsg_opts->common->filesem, page, len); } -static struct fsg_lun_opts_attribute fsg_lun_opts_file = - __CONFIGFS_ATTR(file, S_IRUGO | S_IWUSR, fsg_lun_opts_file_show, - fsg_lun_opts_file_store); +CONFIGFS_ATTR(fsg_lun_opts_, file); -static ssize_t fsg_lun_opts_ro_show(struct fsg_lun_opts *opts, char *page) +static ssize_t fsg_lun_opts_ro_show(struct config_item *item, char *page) { - return fsg_show_ro(opts->lun, page); + return fsg_show_ro(to_fsg_lun_opts(item)->lun, page); } -static ssize_t fsg_lun_opts_ro_store(struct fsg_lun_opts *opts, +static ssize_t fsg_lun_opts_ro_store(struct config_item *item, const char *page, size_t len) { - struct fsg_opts *fsg_opts; - - fsg_opts = to_fsg_opts(opts->group.cg_item.ci_parent); + struct fsg_lun_opts *opts = to_fsg_lun_opts(item); + struct fsg_opts *fsg_opts = to_fsg_opts(opts->group.cg_item.ci_parent); return fsg_store_ro(opts->lun, &fsg_opts->common->filesem, page, len); } -static struct fsg_lun_opts_attribute fsg_lun_opts_ro = - __CONFIGFS_ATTR(ro, S_IRUGO | S_IWUSR, fsg_lun_opts_ro_show, - fsg_lun_opts_ro_store); +CONFIGFS_ATTR(fsg_lun_opts_, ro); -static ssize_t fsg_lun_opts_removable_show(struct fsg_lun_opts *opts, +static ssize_t fsg_lun_opts_removable_show(struct config_item *item, char *page) { - return fsg_show_removable(opts->lun, page); + return fsg_show_removable(to_fsg_lun_opts(item)->lun, page); } -static ssize_t fsg_lun_opts_removable_store(struct fsg_lun_opts *opts, +static ssize_t fsg_lun_opts_removable_store(struct config_item *item, const char *page, size_t len) { - return fsg_store_removable(opts->lun, page, len); + return fsg_store_removable(to_fsg_lun_opts(item)->lun, page, len); } -static struct fsg_lun_opts_attribute fsg_lun_opts_removable = - __CONFIGFS_ATTR(removable, S_IRUGO | S_IWUSR, - fsg_lun_opts_removable_show, - fsg_lun_opts_removable_store); +CONFIGFS_ATTR(fsg_lun_opts_, removable); -static ssize_t fsg_lun_opts_cdrom_show(struct fsg_lun_opts *opts, char *page) +static ssize_t fsg_lun_opts_cdrom_show(struct config_item *item, char *page) { - return fsg_show_cdrom(opts->lun, page); + return fsg_show_cdrom(to_fsg_lun_opts(item)->lun, page); } -static ssize_t fsg_lun_opts_cdrom_store(struct fsg_lun_opts *opts, +static ssize_t fsg_lun_opts_cdrom_store(struct config_item *item, const char *page, size_t len) { - struct fsg_opts *fsg_opts; - - fsg_opts = to_fsg_opts(opts->group.cg_item.ci_parent); + struct fsg_lun_opts *opts = to_fsg_lun_opts(item); + struct fsg_opts *fsg_opts = to_fsg_opts(opts->group.cg_item.ci_parent); return fsg_store_cdrom(opts->lun, &fsg_opts->common->filesem, page, len); } -static struct fsg_lun_opts_attribute fsg_lun_opts_cdrom = - __CONFIGFS_ATTR(cdrom, S_IRUGO | S_IWUSR, fsg_lun_opts_cdrom_show, - fsg_lun_opts_cdrom_store); +CONFIGFS_ATTR(fsg_lun_opts_, cdrom); -static ssize_t fsg_lun_opts_nofua_show(struct fsg_lun_opts *opts, char *page) +static ssize_t fsg_lun_opts_nofua_show(struct config_item *item, char *page) { - return fsg_show_nofua(opts->lun, page); + return fsg_show_nofua(to_fsg_lun_opts(item)->lun, page); } -static ssize_t fsg_lun_opts_nofua_store(struct fsg_lun_opts *opts, +static ssize_t fsg_lun_opts_nofua_store(struct config_item *item, const char *page, size_t len) { - return fsg_store_nofua(opts->lun, page, len); + return fsg_store_nofua(to_fsg_lun_opts(item)->lun, page, len); } -static struct fsg_lun_opts_attribute fsg_lun_opts_nofua = - __CONFIGFS_ATTR(nofua, S_IRUGO | S_IWUSR, fsg_lun_opts_nofua_show, - fsg_lun_opts_nofua_store); +CONFIGFS_ATTR(fsg_lun_opts_, nofua); static struct configfs_attribute *fsg_lun_attrs[] = { - &fsg_lun_opts_file.attr, - &fsg_lun_opts_ro.attr, - &fsg_lun_opts_removable.attr, - &fsg_lun_opts_cdrom.attr, - &fsg_lun_opts_nofua.attr, + &fsg_lun_opts_attr_file, + &fsg_lun_opts_attr_ro, + &fsg_lun_opts_attr_removable, + &fsg_lun_opts_attr_cdrom, + &fsg_lun_opts_attr_nofua, NULL, }; @@ -3348,9 +3328,6 @@ static void fsg_lun_drop(struct config_group *group, struct config_item *item) config_item_put(item); } -CONFIGFS_ATTR_STRUCT(fsg_opts); -CONFIGFS_ATTR_OPS(fsg_opts); - static void fsg_attr_release(struct config_item *item) { struct fsg_opts *opts = to_fsg_opts(item); @@ -3360,12 +3337,11 @@ static void fsg_attr_release(struct config_item *item) static struct configfs_item_operations fsg_item_ops = { .release = fsg_attr_release, - .show_attribute = fsg_opts_attr_show, - .store_attribute = fsg_opts_attr_store, }; -static ssize_t fsg_opts_stall_show(struct fsg_opts *opts, char *page) +static ssize_t fsg_opts_stall_show(struct config_item *item, char *page) { + struct fsg_opts *opts = to_fsg_opts(item); int result; mutex_lock(&opts->lock); @@ -3375,9 +3351,10 @@ static ssize_t fsg_opts_stall_show(struct fsg_opts *opts, char *page) return result; } -static ssize_t fsg_opts_stall_store(struct fsg_opts *opts, const char *page, +static ssize_t fsg_opts_stall_store(struct config_item *item, const char *page, size_t len) { + struct fsg_opts *opts = to_fsg_opts(item); int ret; bool stall; @@ -3399,13 +3376,12 @@ static ssize_t fsg_opts_stall_store(struct fsg_opts *opts, const char *page, return ret; } -static struct fsg_opts_attribute fsg_opts_stall = - __CONFIGFS_ATTR(stall, S_IRUGO | S_IWUSR, fsg_opts_stall_show, - fsg_opts_stall_store); +CONFIGFS_ATTR(fsg_opts_, stall); #ifdef CONFIG_USB_GADGET_DEBUG_FILES -static ssize_t fsg_opts_num_buffers_show(struct fsg_opts *opts, char *page) +static ssize_t fsg_opts_num_buffers_show(struct config_item *item, char *page) { + struct fsg_opts *opts = to_fsg_opts(item); int result; mutex_lock(&opts->lock); @@ -3415,9 +3391,10 @@ static ssize_t fsg_opts_num_buffers_show(struct fsg_opts *opts, char *page) return result; } -static ssize_t fsg_opts_num_buffers_store(struct fsg_opts *opts, +static ssize_t fsg_opts_num_buffers_store(struct config_item *item, const char *page, size_t len) { + struct fsg_opts *opts = to_fsg_opts(item); int ret; u8 num; @@ -3442,17 +3419,13 @@ end: return ret; } -static struct fsg_opts_attribute fsg_opts_num_buffers = - __CONFIGFS_ATTR(num_buffers, S_IRUGO | S_IWUSR, - fsg_opts_num_buffers_show, - fsg_opts_num_buffers_store); - +CONFIGFS_ATTR(fsg_opts_, num_buffers); #endif static struct configfs_attribute *fsg_attrs[] = { - &fsg_opts_stall.attr, + &fsg_opts_attr_stall, #ifdef CONFIG_USB_GADGET_DEBUG_FILES - &fsg_opts_num_buffers.attr, + &fsg_opts_attr_num_buffers, #endif NULL, }; diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c index ce3c8a629266..42acb45e1ab4 100644 --- a/drivers/usb/gadget/function/f_midi.c +++ b/drivers/usb/gadget/function/f_midi.c @@ -902,9 +902,6 @@ static inline struct f_midi_opts *to_f_midi_opts(struct config_item *item) func_inst.group); } -CONFIGFS_ATTR_STRUCT(f_midi_opts); -CONFIGFS_ATTR_OPS(f_midi_opts); - static void midi_attr_release(struct config_item *item) { struct f_midi_opts *opts = to_f_midi_opts(item); @@ -914,13 +911,12 @@ static void midi_attr_release(struct config_item *item) static struct configfs_item_operations midi_item_ops = { .release = midi_attr_release, - .show_attribute = f_midi_opts_attr_show, - .store_attribute = f_midi_opts_attr_store, }; #define F_MIDI_OPT(name, test_limit, limit) \ -static ssize_t f_midi_opts_##name##_show(struct f_midi_opts *opts, char *page) \ +static ssize_t f_midi_opts_##name##_show(struct config_item *item, char *page) \ { \ + struct f_midi_opts *opts = to_f_midi_opts(item); \ int result; \ \ mutex_lock(&opts->lock); \ @@ -930,9 +926,10 @@ static ssize_t f_midi_opts_##name##_show(struct f_midi_opts *opts, char *page) \ return result; \ } \ \ -static ssize_t f_midi_opts_##name##_store(struct f_midi_opts *opts, \ +static ssize_t f_midi_opts_##name##_store(struct config_item *item, \ const char *page, size_t len) \ { \ + struct f_midi_opts *opts = to_f_midi_opts(item); \ int ret; \ u32 num; \ \ @@ -958,9 +955,7 @@ end: \ return ret; \ } \ \ -static struct f_midi_opts_attribute f_midi_opts_##name = \ - __CONFIGFS_ATTR(name, S_IRUGO | S_IWUSR, f_midi_opts_##name##_show, \ - f_midi_opts_##name##_store) +CONFIGFS_ATTR(f_midi_opts_, name); F_MIDI_OPT(index, true, SNDRV_CARDS); F_MIDI_OPT(buflen, false, 0); @@ -968,8 +963,9 @@ F_MIDI_OPT(qlen, false, 0); F_MIDI_OPT(in_ports, true, MAX_PORTS); F_MIDI_OPT(out_ports, true, MAX_PORTS); -static ssize_t f_midi_opts_id_show(struct f_midi_opts *opts, char *page) +static ssize_t f_midi_opts_id_show(struct config_item *item, char *page) { + struct f_midi_opts *opts = to_f_midi_opts(item); int result; mutex_lock(&opts->lock); @@ -985,9 +981,10 @@ static ssize_t f_midi_opts_id_show(struct f_midi_opts *opts, char *page) return result; } -static ssize_t f_midi_opts_id_store(struct f_midi_opts *opts, +static ssize_t f_midi_opts_id_store(struct config_item *item, const char *page, size_t len) { + struct f_midi_opts *opts = to_f_midi_opts(item); int ret; char *c; @@ -1012,17 +1009,15 @@ end: return ret; } -static struct f_midi_opts_attribute f_midi_opts_id = - __CONFIGFS_ATTR(id, S_IRUGO | S_IWUSR, f_midi_opts_id_show, - f_midi_opts_id_store); +CONFIGFS_ATTR(f_midi_opts_, id); static struct configfs_attribute *midi_attrs[] = { - &f_midi_opts_index.attr, - &f_midi_opts_buflen.attr, - &f_midi_opts_qlen.attr, - &f_midi_opts_in_ports.attr, - &f_midi_opts_out_ports.attr, - &f_midi_opts_id.attr, + &f_midi_opts_attr_index, + &f_midi_opts_attr_buflen, + &f_midi_opts_attr_qlen, + &f_midi_opts_attr_in_ports, + &f_midi_opts_attr_out_ports, + &f_midi_opts_attr_id, NULL, }; diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c index b6f7ed7d48a7..7ad798ace1e5 100644 --- a/drivers/usb/gadget/function/f_ncm.c +++ b/drivers/usb/gadget/function/f_ncm.c @@ -1488,10 +1488,10 @@ USB_ETHERNET_CONFIGFS_ITEM_ATTR_QMULT(ncm); USB_ETHERNET_CONFIGFS_ITEM_ATTR_IFNAME(ncm); static struct configfs_attribute *ncm_attrs[] = { - &f_ncm_opts_dev_addr.attr, - &f_ncm_opts_host_addr.attr, - &f_ncm_opts_qmult.attr, - &f_ncm_opts_ifname.attr, + &ncm_opts_attr_dev_addr, + &ncm_opts_attr_host_addr, + &ncm_opts_attr_qmult, + &ncm_opts_attr_ifname, NULL, }; diff --git a/drivers/usb/gadget/function/f_obex.c b/drivers/usb/gadget/function/f_obex.c index 1c3d30ad2f92..d6396e0909ee 100644 --- a/drivers/usb/gadget/function/f_obex.c +++ b/drivers/usb/gadget/function/f_obex.c @@ -387,22 +387,6 @@ static inline struct f_serial_opts *to_f_serial_opts(struct config_item *item) func_inst.group); } -CONFIGFS_ATTR_STRUCT(f_serial_opts); -static ssize_t f_obex_attr_show(struct config_item *item, - struct configfs_attribute *attr, - char *page) -{ - struct f_serial_opts *opts = to_f_serial_opts(item); - struct f_serial_opts_attribute *f_serial_opts_attr = - container_of(attr, struct f_serial_opts_attribute, attr); - ssize_t ret = 0; - - if (f_serial_opts_attr->show) - ret = f_serial_opts_attr->show(opts, page); - - return ret; -} - static void obex_attr_release(struct config_item *item) { struct f_serial_opts *opts = to_f_serial_opts(item); @@ -412,19 +396,17 @@ static void obex_attr_release(struct config_item *item) static struct configfs_item_operations obex_item_ops = { .release = obex_attr_release, - .show_attribute = f_obex_attr_show, }; -static ssize_t f_obex_port_num_show(struct f_serial_opts *opts, char *page) +static ssize_t f_obex_port_num_show(struct config_item *item, char *page) { - return sprintf(page, "%u\n", opts->port_num); + return sprintf(page, "%u\n", to_f_serial_opts(item)->port_num); } -static struct f_serial_opts_attribute f_obex_port_num = - __CONFIGFS_ATTR_RO(port_num, f_obex_port_num_show); +CONFIGFS_ATTR_RO(f_obex_, port_num); static struct configfs_attribute *acm_attrs[] = { - &f_obex_port_num.attr, + &f_obex_attr_port_num, NULL, }; diff --git a/drivers/usb/gadget/function/f_phonet.c b/drivers/usb/gadget/function/f_phonet.c index 62a198754029..157441dbfeba 100644 --- a/drivers/usb/gadget/function/f_phonet.c +++ b/drivers/usb/gadget/function/f_phonet.c @@ -583,21 +583,6 @@ static inline struct f_phonet_opts *to_f_phonet_opts(struct config_item *item) func_inst.group); } -CONFIGFS_ATTR_STRUCT(f_phonet_opts); -static ssize_t f_phonet_attr_show(struct config_item *item, - struct configfs_attribute *attr, - char *page) -{ - struct f_phonet_opts *opts = to_f_phonet_opts(item); - struct f_phonet_opts_attribute *f_phonet_opts_attr = - container_of(attr, struct f_phonet_opts_attribute, attr); - ssize_t ret = 0; - - if (f_phonet_opts_attr->show) - ret = f_phonet_opts_attr->show(opts, page); - return ret; -} - static void phonet_attr_release(struct config_item *item) { struct f_phonet_opts *opts = to_f_phonet_opts(item); @@ -607,19 +592,17 @@ static void phonet_attr_release(struct config_item *item) static struct configfs_item_operations phonet_item_ops = { .release = phonet_attr_release, - .show_attribute = f_phonet_attr_show, }; -static ssize_t f_phonet_ifname_show(struct f_phonet_opts *opts, char *page) +static ssize_t f_phonet_ifname_show(struct config_item *item, char *page) { - return gether_get_ifname(opts->net, page, PAGE_SIZE); + return gether_get_ifname(to_f_phonet_opts(item)->net, page, PAGE_SIZE); } -static struct f_phonet_opts_attribute f_phonet_ifname = - __CONFIGFS_ATTR_RO(ifname, f_phonet_ifname_show); +CONFIGFS_ATTR_RO(f_phonet_, ifname); static struct configfs_attribute *phonet_attrs[] = { - &f_phonet_ifname.attr, + &f_phonet_attr_ifname, NULL, }; diff --git a/drivers/usb/gadget/function/f_printer.c b/drivers/usb/gadget/function/f_printer.c index 7fb3209ed52c..0fbfb2b2aa08 100644 --- a/drivers/usb/gadget/function/f_printer.c +++ b/drivers/usb/gadget/function/f_printer.c @@ -1146,9 +1146,6 @@ static inline struct f_printer_opts func_inst.group); } -CONFIGFS_ATTR_STRUCT(f_printer_opts); -CONFIGFS_ATTR_OPS(f_printer_opts); - static void printer_attr_release(struct config_item *item) { struct f_printer_opts *opts = to_f_printer_opts(item); @@ -1158,13 +1155,12 @@ static void printer_attr_release(struct config_item *item) static struct configfs_item_operations printer_item_ops = { .release = printer_attr_release, - .show_attribute = f_printer_opts_attr_show, - .store_attribute = f_printer_opts_attr_store, }; -static ssize_t f_printer_opts_pnp_string_show(struct f_printer_opts *opts, +static ssize_t f_printer_opts_pnp_string_show(struct config_item *item, char *page) { + struct f_printer_opts *opts = to_f_printer_opts(item); int result; mutex_lock(&opts->lock); @@ -1174,9 +1170,10 @@ static ssize_t f_printer_opts_pnp_string_show(struct f_printer_opts *opts, return result; } -static ssize_t f_printer_opts_pnp_string_store(struct f_printer_opts *opts, +static ssize_t f_printer_opts_pnp_string_store(struct config_item *item, const char *page, size_t len) { + struct f_printer_opts *opts = to_f_printer_opts(item); int result, l; mutex_lock(&opts->lock); @@ -1189,14 +1186,12 @@ static ssize_t f_printer_opts_pnp_string_store(struct f_printer_opts *opts, return result; } -static struct f_printer_opts_attribute f_printer_opts_pnp_string = - __CONFIGFS_ATTR(pnp_string, S_IRUGO | S_IWUSR, - f_printer_opts_pnp_string_show, - f_printer_opts_pnp_string_store); +CONFIGFS_ATTR(f_printer_opts_, pnp_string); -static ssize_t f_printer_opts_q_len_show(struct f_printer_opts *opts, +static ssize_t f_printer_opts_q_len_show(struct config_item *item, char *page) { + struct f_printer_opts *opts = to_f_printer_opts(item); int result; mutex_lock(&opts->lock); @@ -1206,9 +1201,10 @@ static ssize_t f_printer_opts_q_len_show(struct f_printer_opts *opts, return result; } -static ssize_t f_printer_opts_q_len_store(struct f_printer_opts *opts, +static ssize_t f_printer_opts_q_len_store(struct config_item *item, const char *page, size_t len) { + struct f_printer_opts *opts = to_f_printer_opts(item); int ret; u16 num; @@ -1229,13 +1225,11 @@ end: return ret; } -static struct f_printer_opts_attribute f_printer_opts_q_len = - __CONFIGFS_ATTR(q_len, S_IRUGO | S_IWUSR, f_printer_opts_q_len_show, - f_printer_opts_q_len_store); +CONFIGFS_ATTR(f_printer_opts_, q_len); static struct configfs_attribute *printer_attrs[] = { - &f_printer_opts_pnp_string.attr, - &f_printer_opts_q_len.attr, + &f_printer_opts_attr_pnp_string, + &f_printer_opts_attr_q_len, NULL, }; diff --git a/drivers/usb/gadget/function/f_rndis.c b/drivers/usb/gadget/function/f_rndis.c index fd301ed9e294..e587767e374c 100644 --- a/drivers/usb/gadget/function/f_rndis.c +++ b/drivers/usb/gadget/function/f_rndis.c @@ -864,10 +864,10 @@ USB_ETHERNET_CONFIGFS_ITEM_ATTR_QMULT(rndis); USB_ETHERNET_CONFIGFS_ITEM_ATTR_IFNAME(rndis); static struct configfs_attribute *rndis_attrs[] = { - &f_rndis_opts_dev_addr.attr, - &f_rndis_opts_host_addr.attr, - &f_rndis_opts_qmult.attr, - &f_rndis_opts_ifname.attr, + &rndis_opts_attr_dev_addr, + &rndis_opts_attr_host_addr, + &rndis_opts_attr_qmult, + &rndis_opts_attr_ifname, NULL, }; diff --git a/drivers/usb/gadget/function/f_serial.c b/drivers/usb/gadget/function/f_serial.c index ba705e047d7e..6bb44d613bab 100644 --- a/drivers/usb/gadget/function/f_serial.c +++ b/drivers/usb/gadget/function/f_serial.c @@ -258,22 +258,6 @@ static inline struct f_serial_opts *to_f_serial_opts(struct config_item *item) func_inst.group); } -CONFIGFS_ATTR_STRUCT(f_serial_opts); -static ssize_t f_serial_attr_show(struct config_item *item, - struct configfs_attribute *attr, - char *page) -{ - struct f_serial_opts *opts = to_f_serial_opts(item); - struct f_serial_opts_attribute *f_serial_opts_attr = - container_of(attr, struct f_serial_opts_attribute, attr); - ssize_t ret = 0; - - if (f_serial_opts_attr->show) - ret = f_serial_opts_attr->show(opts, page); - - return ret; -} - static void serial_attr_release(struct config_item *item) { struct f_serial_opts *opts = to_f_serial_opts(item); @@ -283,19 +267,17 @@ static void serial_attr_release(struct config_item *item) static struct configfs_item_operations serial_item_ops = { .release = serial_attr_release, - .show_attribute = f_serial_attr_show, }; -static ssize_t f_serial_port_num_show(struct f_serial_opts *opts, char *page) +static ssize_t f_serial_port_num_show(struct config_item *item, char *page) { - return sprintf(page, "%u\n", opts->port_num); + return sprintf(page, "%u\n", to_f_serial_opts(item)->port_num); } -static struct f_serial_opts_attribute f_serial_port_num = - __CONFIGFS_ATTR_RO(port_num, f_serial_port_num_show); +CONFIGFS_ATTR_RO(f_serial_, port_num); static struct configfs_attribute *acm_attrs[] = { - &f_serial_port_num.attr, + &f_serial_attr_port_num, NULL, }; diff --git a/drivers/usb/gadget/function/f_sourcesink.c b/drivers/usb/gadget/function/f_sourcesink.c index d7646d3acd63..9f3ced62d916 100644 --- a/drivers/usb/gadget/function/f_sourcesink.c +++ b/drivers/usb/gadget/function/f_sourcesink.c @@ -889,9 +889,6 @@ static inline struct f_ss_opts *to_f_ss_opts(struct config_item *item) func_inst.group); } -CONFIGFS_ATTR_STRUCT(f_ss_opts); -CONFIGFS_ATTR_OPS(f_ss_opts); - static void ss_attr_release(struct config_item *item) { struct f_ss_opts *ss_opts = to_f_ss_opts(item); @@ -901,12 +898,11 @@ static void ss_attr_release(struct config_item *item) static struct configfs_item_operations ss_item_ops = { .release = ss_attr_release, - .show_attribute = f_ss_opts_attr_show, - .store_attribute = f_ss_opts_attr_store, }; -static ssize_t f_ss_opts_pattern_show(struct f_ss_opts *opts, char *page) +static ssize_t f_ss_opts_pattern_show(struct config_item *item, char *page) { + struct f_ss_opts *opts = to_f_ss_opts(item); int result; mutex_lock(&opts->lock); @@ -916,9 +912,10 @@ static ssize_t f_ss_opts_pattern_show(struct f_ss_opts *opts, char *page) return result; } -static ssize_t f_ss_opts_pattern_store(struct f_ss_opts *opts, +static ssize_t f_ss_opts_pattern_store(struct config_item *item, const char *page, size_t len) { + struct f_ss_opts *opts = to_f_ss_opts(item); int ret; u8 num; @@ -944,13 +941,11 @@ end: return ret; } -static struct f_ss_opts_attribute f_ss_opts_pattern = - __CONFIGFS_ATTR(pattern, S_IRUGO | S_IWUSR, - f_ss_opts_pattern_show, - f_ss_opts_pattern_store); +CONFIGFS_ATTR(f_ss_opts_, pattern); -static ssize_t f_ss_opts_isoc_interval_show(struct f_ss_opts *opts, char *page) +static ssize_t f_ss_opts_isoc_interval_show(struct config_item *item, char *page) { + struct f_ss_opts *opts = to_f_ss_opts(item); int result; mutex_lock(&opts->lock); @@ -960,9 +955,10 @@ static ssize_t f_ss_opts_isoc_interval_show(struct f_ss_opts *opts, char *page) return result; } -static ssize_t f_ss_opts_isoc_interval_store(struct f_ss_opts *opts, +static ssize_t f_ss_opts_isoc_interval_store(struct config_item *item, const char *page, size_t len) { + struct f_ss_opts *opts = to_f_ss_opts(item); int ret; u8 num; @@ -988,13 +984,11 @@ end: return ret; } -static struct f_ss_opts_attribute f_ss_opts_isoc_interval = - __CONFIGFS_ATTR(isoc_interval, S_IRUGO | S_IWUSR, - f_ss_opts_isoc_interval_show, - f_ss_opts_isoc_interval_store); +CONFIGFS_ATTR(f_ss_opts_, isoc_interval); -static ssize_t f_ss_opts_isoc_maxpacket_show(struct f_ss_opts *opts, char *page) +static ssize_t f_ss_opts_isoc_maxpacket_show(struct config_item *item, char *page) { + struct f_ss_opts *opts = to_f_ss_opts(item); int result; mutex_lock(&opts->lock); @@ -1004,9 +998,10 @@ static ssize_t f_ss_opts_isoc_maxpacket_show(struct f_ss_opts *opts, char *page) return result; } -static ssize_t f_ss_opts_isoc_maxpacket_store(struct f_ss_opts *opts, +static ssize_t f_ss_opts_isoc_maxpacket_store(struct config_item *item, const char *page, size_t len) { + struct f_ss_opts *opts = to_f_ss_opts(item); int ret; u16 num; @@ -1032,13 +1027,11 @@ end: return ret; } -static struct f_ss_opts_attribute f_ss_opts_isoc_maxpacket = - __CONFIGFS_ATTR(isoc_maxpacket, S_IRUGO | S_IWUSR, - f_ss_opts_isoc_maxpacket_show, - f_ss_opts_isoc_maxpacket_store); +CONFIGFS_ATTR(f_ss_opts_, isoc_maxpacket); -static ssize_t f_ss_opts_isoc_mult_show(struct f_ss_opts *opts, char *page) +static ssize_t f_ss_opts_isoc_mult_show(struct config_item *item, char *page) { + struct f_ss_opts *opts = to_f_ss_opts(item); int result; mutex_lock(&opts->lock); @@ -1048,9 +1041,10 @@ static ssize_t f_ss_opts_isoc_mult_show(struct f_ss_opts *opts, char *page) return result; } -static ssize_t f_ss_opts_isoc_mult_store(struct f_ss_opts *opts, +static ssize_t f_ss_opts_isoc_mult_store(struct config_item *item, const char *page, size_t len) { + struct f_ss_opts *opts = to_f_ss_opts(item); int ret; u8 num; @@ -1076,13 +1070,11 @@ end: return ret; } -static struct f_ss_opts_attribute f_ss_opts_isoc_mult = - __CONFIGFS_ATTR(isoc_mult, S_IRUGO | S_IWUSR, - f_ss_opts_isoc_mult_show, - f_ss_opts_isoc_mult_store); +CONFIGFS_ATTR(f_ss_opts_, isoc_mult); -static ssize_t f_ss_opts_isoc_maxburst_show(struct f_ss_opts *opts, char *page) +static ssize_t f_ss_opts_isoc_maxburst_show(struct config_item *item, char *page) { + struct f_ss_opts *opts = to_f_ss_opts(item); int result; mutex_lock(&opts->lock); @@ -1092,9 +1084,10 @@ static ssize_t f_ss_opts_isoc_maxburst_show(struct f_ss_opts *opts, char *page) return result; } -static ssize_t f_ss_opts_isoc_maxburst_store(struct f_ss_opts *opts, +static ssize_t f_ss_opts_isoc_maxburst_store(struct config_item *item, const char *page, size_t len) { + struct f_ss_opts *opts = to_f_ss_opts(item); int ret; u8 num; @@ -1120,13 +1113,11 @@ end: return ret; } -static struct f_ss_opts_attribute f_ss_opts_isoc_maxburst = - __CONFIGFS_ATTR(isoc_maxburst, S_IRUGO | S_IWUSR, - f_ss_opts_isoc_maxburst_show, - f_ss_opts_isoc_maxburst_store); +CONFIGFS_ATTR(f_ss_opts_, isoc_maxburst); -static ssize_t f_ss_opts_bulk_buflen_show(struct f_ss_opts *opts, char *page) +static ssize_t f_ss_opts_bulk_buflen_show(struct config_item *item, char *page) { + struct f_ss_opts *opts = to_f_ss_opts(item); int result; mutex_lock(&opts->lock); @@ -1136,9 +1127,10 @@ static ssize_t f_ss_opts_bulk_buflen_show(struct f_ss_opts *opts, char *page) return result; } -static ssize_t f_ss_opts_bulk_buflen_store(struct f_ss_opts *opts, +static ssize_t f_ss_opts_bulk_buflen_store(struct config_item *item, const char *page, size_t len) { + struct f_ss_opts *opts = to_f_ss_opts(item); int ret; u32 num; @@ -1159,18 +1151,15 @@ end: return ret; } -static struct f_ss_opts_attribute f_ss_opts_bulk_buflen = - __CONFIGFS_ATTR(buflen, S_IRUGO | S_IWUSR, - f_ss_opts_bulk_buflen_show, - f_ss_opts_bulk_buflen_store); +CONFIGFS_ATTR(f_ss_opts_, bulk_buflen); static struct configfs_attribute *ss_attrs[] = { - &f_ss_opts_pattern.attr, - &f_ss_opts_isoc_interval.attr, - &f_ss_opts_isoc_maxpacket.attr, - &f_ss_opts_isoc_mult.attr, - &f_ss_opts_isoc_maxburst.attr, - &f_ss_opts_bulk_buflen.attr, + &f_ss_opts_attr_pattern, + &f_ss_opts_attr_isoc_interval, + &f_ss_opts_attr_isoc_maxpacket, + &f_ss_opts_attr_isoc_mult, + &f_ss_opts_attr_isoc_maxburst, + &f_ss_opts_attr_bulk_buflen, NULL, }; diff --git a/drivers/usb/gadget/function/f_subset.c b/drivers/usb/gadget/function/f_subset.c index 2e66e624e6e1..829c78de9eba 100644 --- a/drivers/usb/gadget/function/f_subset.c +++ b/drivers/usb/gadget/function/f_subset.c @@ -405,10 +405,10 @@ USB_ETHERNET_CONFIGFS_ITEM_ATTR_QMULT(gether); USB_ETHERNET_CONFIGFS_ITEM_ATTR_IFNAME(gether); static struct configfs_attribute *gether_attrs[] = { - &f_gether_opts_dev_addr.attr, - &f_gether_opts_host_addr.attr, - &f_gether_opts_qmult.attr, - &f_gether_opts_ifname.attr, + &gether_opts_attr_dev_addr, + &gether_opts_attr_host_addr, + &gether_opts_attr_qmult, + &gether_opts_attr_ifname, NULL, }; diff --git a/drivers/usb/gadget/function/f_uac1.c b/drivers/usb/gadget/function/f_uac1.c index 8ee701924d29..6a2346b99f55 100644 --- a/drivers/usb/gadget/function/f_uac1.c +++ b/drivers/usb/gadget/function/f_uac1.c @@ -769,9 +769,6 @@ static inline struct f_uac1_opts *to_f_uac1_opts(struct config_item *item) func_inst.group); } -CONFIGFS_ATTR_STRUCT(f_uac1_opts); -CONFIGFS_ATTR_OPS(f_uac1_opts); - static void f_uac1_attr_release(struct config_item *item) { struct f_uac1_opts *opts = to_f_uac1_opts(item); @@ -781,14 +778,13 @@ static void f_uac1_attr_release(struct config_item *item) static struct configfs_item_operations f_uac1_item_ops = { .release = f_uac1_attr_release, - .show_attribute = f_uac1_opts_attr_show, - .store_attribute = f_uac1_opts_attr_store, }; #define UAC1_INT_ATTRIBUTE(name) \ -static ssize_t f_uac1_opts_##name##_show(struct f_uac1_opts *opts, \ +static ssize_t f_uac1_opts_##name##_show(struct config_item *item, \ char *page) \ { \ + struct f_uac1_opts *opts = to_f_uac1_opts(item); \ int result; \ \ mutex_lock(&opts->lock); \ @@ -798,9 +794,10 @@ static ssize_t f_uac1_opts_##name##_show(struct f_uac1_opts *opts, \ return result; \ } \ \ -static ssize_t f_uac1_opts_##name##_store(struct f_uac1_opts *opts, \ +static ssize_t f_uac1_opts_##name##_store(struct config_item *item, \ const char *page, size_t len) \ { \ + struct f_uac1_opts *opts = to_f_uac1_opts(item); \ int ret; \ u32 num; \ \ @@ -822,19 +819,17 @@ end: \ return ret; \ } \ \ -static struct f_uac1_opts_attribute f_uac1_opts_##name = \ - __CONFIGFS_ATTR(name, S_IRUGO | S_IWUSR, \ - f_uac1_opts_##name##_show, \ - f_uac1_opts_##name##_store) +CONFIGFS_ATTR(f_uac1_opts_, name) UAC1_INT_ATTRIBUTE(req_buf_size); UAC1_INT_ATTRIBUTE(req_count); UAC1_INT_ATTRIBUTE(audio_buf_size); #define UAC1_STR_ATTRIBUTE(name) \ -static ssize_t f_uac1_opts_##name##_show(struct f_uac1_opts *opts, \ +static ssize_t f_uac1_opts_##name##_show(struct config_item *item, \ char *page) \ { \ + struct f_uac1_opts *opts = to_f_uac1_opts(item); \ int result; \ \ mutex_lock(&opts->lock); \ @@ -844,9 +839,10 @@ static ssize_t f_uac1_opts_##name##_show(struct f_uac1_opts *opts, \ return result; \ } \ \ -static ssize_t f_uac1_opts_##name##_store(struct f_uac1_opts *opts, \ +static ssize_t f_uac1_opts_##name##_store(struct config_item *item, \ const char *page, size_t len) \ { \ + struct f_uac1_opts *opts = to_f_uac1_opts(item); \ int ret = -EBUSY; \ char *tmp; \ \ @@ -870,22 +866,19 @@ end: \ return ret; \ } \ \ -static struct f_uac1_opts_attribute f_uac1_opts_##name = \ - __CONFIGFS_ATTR(name, S_IRUGO | S_IWUSR, \ - f_uac1_opts_##name##_show, \ - f_uac1_opts_##name##_store) +CONFIGFS_ATTR(f_uac1_opts_, name) UAC1_STR_ATTRIBUTE(fn_play); UAC1_STR_ATTRIBUTE(fn_cap); UAC1_STR_ATTRIBUTE(fn_cntl); static struct configfs_attribute *f_uac1_attrs[] = { - &f_uac1_opts_req_buf_size.attr, - &f_uac1_opts_req_count.attr, - &f_uac1_opts_audio_buf_size.attr, - &f_uac1_opts_fn_play.attr, - &f_uac1_opts_fn_cap.attr, - &f_uac1_opts_fn_cntl.attr, + &f_uac1_opts_attr_req_buf_size, + &f_uac1_opts_attr_req_count, + &f_uac1_opts_attr_audio_buf_size, + &f_uac1_opts_attr_fn_play, + &f_uac1_opts_attr_fn_cap, + &f_uac1_opts_attr_fn_cntl, NULL, }; diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index 63336e269898..044ca79d3cb5 100644 --- a/drivers/usb/gadget/function/f_uac2.c +++ b/drivers/usb/gadget/function/f_uac2.c @@ -1439,9 +1439,6 @@ static inline struct f_uac2_opts *to_f_uac2_opts(struct config_item *item) func_inst.group); } -CONFIGFS_ATTR_STRUCT(f_uac2_opts); -CONFIGFS_ATTR_OPS(f_uac2_opts); - static void f_uac2_attr_release(struct config_item *item) { struct f_uac2_opts *opts = to_f_uac2_opts(item); @@ -1451,14 +1448,13 @@ static void f_uac2_attr_release(struct config_item *item) static struct configfs_item_operations f_uac2_item_ops = { .release = f_uac2_attr_release, - .show_attribute = f_uac2_opts_attr_show, - .store_attribute = f_uac2_opts_attr_store, }; #define UAC2_ATTRIBUTE(name) \ -static ssize_t f_uac2_opts_##name##_show(struct f_uac2_opts *opts, \ +static ssize_t f_uac2_opts_##name##_show(struct config_item *item, \ char *page) \ { \ + struct f_uac2_opts *opts = to_f_uac2_opts(item); \ int result; \ \ mutex_lock(&opts->lock); \ @@ -1468,9 +1464,10 @@ static ssize_t f_uac2_opts_##name##_show(struct f_uac2_opts *opts, \ return result; \ } \ \ -static ssize_t f_uac2_opts_##name##_store(struct f_uac2_opts *opts, \ +static ssize_t f_uac2_opts_##name##_store(struct config_item *item, \ const char *page, size_t len) \ { \ + struct f_uac2_opts *opts = to_f_uac2_opts(item); \ int ret; \ u32 num; \ \ @@ -1492,10 +1489,7 @@ end: \ return ret; \ } \ \ -static struct f_uac2_opts_attribute f_uac2_opts_##name = \ - __CONFIGFS_ATTR(name, S_IRUGO | S_IWUSR, \ - f_uac2_opts_##name##_show, \ - f_uac2_opts_##name##_store) +CONFIGFS_ATTR(f_uac2_opts_, name) UAC2_ATTRIBUTE(p_chmask); UAC2_ATTRIBUTE(p_srate); @@ -1505,12 +1499,12 @@ UAC2_ATTRIBUTE(c_srate); UAC2_ATTRIBUTE(c_ssize); static struct configfs_attribute *f_uac2_attrs[] = { - &f_uac2_opts_p_chmask.attr, - &f_uac2_opts_p_srate.attr, - &f_uac2_opts_p_ssize.attr, - &f_uac2_opts_c_chmask.attr, - &f_uac2_opts_c_srate.attr, - &f_uac2_opts_c_ssize.attr, + &f_uac2_opts_attr_p_chmask, + &f_uac2_opts_attr_p_srate, + &f_uac2_opts_attr_p_ssize, + &f_uac2_opts_attr_c_chmask, + &f_uac2_opts_attr_c_srate, + &f_uac2_opts_attr_c_ssize, NULL, }; diff --git a/drivers/usb/gadget/function/u_ether_configfs.h b/drivers/usb/gadget/function/u_ether_configfs.h index bcbd30146cfd..4f47289fcf7c 100644 --- a/drivers/usb/gadget/function/u_ether_configfs.h +++ b/drivers/usb/gadget/function/u_ether_configfs.h @@ -17,9 +17,6 @@ #define __U_ETHER_CONFIGFS_H #define USB_ETHERNET_CONFIGFS_ITEM(_f_) \ - CONFIGFS_ATTR_STRUCT(f_##_f_##_opts); \ - CONFIGFS_ATTR_OPS(f_##_f_##_opts); \ - \ static void _f_##_attr_release(struct config_item *item) \ { \ struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \ @@ -29,14 +26,13 @@ \ static struct configfs_item_operations _f_##_item_ops = { \ .release = _f_##_attr_release, \ - .show_attribute = f_##_f_##_opts_attr_show, \ - .store_attribute = f_##_f_##_opts_attr_store, \ } #define USB_ETHERNET_CONFIGFS_ITEM_ATTR_DEV_ADDR(_f_) \ - static ssize_t _f_##_opts_dev_addr_show(struct f_##_f_##_opts *opts, \ + static ssize_t _f_##_opts_dev_addr_show(struct config_item *item, \ char *page) \ { \ + struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \ int result; \ \ mutex_lock(&opts->lock); \ @@ -46,9 +42,10 @@ return result; \ } \ \ - static ssize_t _f_##_opts_dev_addr_store(struct f_##_f_##_opts *opts, \ + static ssize_t _f_##_opts_dev_addr_store(struct config_item *item, \ const char *page, size_t len)\ { \ + struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \ int ret; \ \ mutex_lock(&opts->lock); \ @@ -64,15 +61,13 @@ return ret; \ } \ \ - static struct f_##_f_##_opts_attribute f_##_f_##_opts_dev_addr = \ - __CONFIGFS_ATTR(dev_addr, S_IRUGO | S_IWUSR, \ - _f_##_opts_dev_addr_show, \ - _f_##_opts_dev_addr_store) + CONFIGFS_ATTR(_f_##_opts_, dev_addr) #define USB_ETHERNET_CONFIGFS_ITEM_ATTR_HOST_ADDR(_f_) \ - static ssize_t _f_##_opts_host_addr_show(struct f_##_f_##_opts *opts, \ + static ssize_t _f_##_opts_host_addr_show(struct config_item *item, \ char *page) \ { \ + struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \ int result; \ \ mutex_lock(&opts->lock); \ @@ -82,9 +77,10 @@ return result; \ } \ \ - static ssize_t _f_##_opts_host_addr_store(struct f_##_f_##_opts *opts, \ + static ssize_t _f_##_opts_host_addr_store(struct config_item *item, \ const char *page, size_t len)\ { \ + struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \ int ret; \ \ mutex_lock(&opts->lock); \ @@ -100,15 +96,13 @@ return ret; \ } \ \ - static struct f_##_f_##_opts_attribute f_##_f_##_opts_host_addr = \ - __CONFIGFS_ATTR(host_addr, S_IRUGO | S_IWUSR, \ - _f_##_opts_host_addr_show, \ - _f_##_opts_host_addr_store) + CONFIGFS_ATTR(_f_##_opts_, host_addr) #define USB_ETHERNET_CONFIGFS_ITEM_ATTR_QMULT(_f_) \ - static ssize_t _f_##_opts_qmult_show(struct f_##_f_##_opts *opts, \ + static ssize_t _f_##_opts_qmult_show(struct config_item *item, \ char *page) \ { \ + struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \ unsigned qmult; \ \ mutex_lock(&opts->lock); \ @@ -117,9 +111,10 @@ return sprintf(page, "%d", qmult); \ } \ \ - static ssize_t _f_##_opts_qmult_store(struct f_##_f_##_opts *opts, \ + static ssize_t _f_##_opts_qmult_store(struct config_item *item, \ const char *page, size_t len)\ { \ + struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \ u8 val; \ int ret; \ \ @@ -140,15 +135,13 @@ out: \ return ret; \ } \ \ - static struct f_##_f_##_opts_attribute f_##_f_##_opts_qmult = \ - __CONFIGFS_ATTR(qmult, S_IRUGO | S_IWUSR, \ - _f_##_opts_qmult_show, \ - _f_##_opts_qmult_store) + CONFIGFS_ATTR(_f_##_opts_, qmult) #define USB_ETHERNET_CONFIGFS_ITEM_ATTR_IFNAME(_f_) \ - static ssize_t _f_##_opts_ifname_show(struct f_##_f_##_opts *opts, \ + static ssize_t _f_##_opts_ifname_show(struct config_item *item, \ char *page) \ { \ + struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \ int ret; \ \ mutex_lock(&opts->lock); \ @@ -158,7 +151,6 @@ out: \ return ret; \ } \ \ - static struct f_##_f_##_opts_attribute f_##_f_##_opts_ifname = \ - __CONFIGFS_ATTR_RO(ifname, _f_##_opts_ifname_show) + CONFIGFS_ATTR_RO(_f_##_opts_, ifname) #endif /* __U_ETHER_CONFIGFS_H */ diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c index 3c0467bcb14f..289ebca316d3 100644 --- a/drivers/usb/gadget/function/uvc_configfs.c +++ b/drivers/usb/gadget/function/uvc_configfs.c @@ -17,19 +17,21 @@ #define UVCG_STREAMING_CONTROL_SIZE 1 -#define CONFIGFS_ATTR_OPS_RO(_item) \ -static ssize_t _item##_attr_show(struct config_item *item, \ - struct configfs_attribute *attr, \ - char *page) \ -{ \ - struct _item *_item = to_##_item(item); \ - struct _item##_attribute *_item##_attr = \ - container_of(attr, struct _item##_attribute, attr); \ - ssize_t ret = 0; \ - \ - if (_item##_attr->show) \ - ret = _item##_attr->show(_item, page); \ - return ret; \ +#define UVC_ATTR(prefix, cname, aname) \ +static struct configfs_attribute prefix##attr_##cname = { \ + .ca_name = __stringify(aname), \ + .ca_mode = S_IRUGO, \ + .ca_owner = THIS_MODULE, \ + .show = prefix##cname##_show, \ + .store = prefix##cname##_store, \ +} + +#define UVC_ATTR_RO(prefix, cname, aname) \ +static struct configfs_attribute prefix##attr_##cname = { \ + .ca_name = __stringify(aname), \ + .ca_mode = S_IRUGO, \ + .ca_owner = THIS_MODULE, \ + .show = prefix##cname##_show, \ } static inline struct f_uvc_opts *to_f_uvc_opts(struct config_item *item); @@ -48,18 +50,11 @@ static struct uvcg_control_header *to_uvcg_control_header(struct config_item *it return container_of(item, struct uvcg_control_header, item); } -CONFIGFS_ATTR_STRUCT(uvcg_control_header); -CONFIGFS_ATTR_OPS(uvcg_control_header); - -static struct configfs_item_operations uvcg_control_header_item_ops = { - .show_attribute = uvcg_control_header_attr_show, - .store_attribute = uvcg_control_header_attr_store, -}; - #define UVCG_CTRL_HDR_ATTR(cname, aname, conv, str2u, uxx, vnoc, limit) \ static ssize_t uvcg_control_header_##cname##_show( \ - struct uvcg_control_header *ch, char *page) \ + struct config_item *item, char *page) \ { \ + struct uvcg_control_header *ch = to_uvcg_control_header(item); \ struct f_uvc_opts *opts; \ struct config_item *opts_item; \ struct mutex *su_mutex = &ch->item.ci_group->cg_subsys->su_mutex;\ @@ -79,9 +74,10 @@ static ssize_t uvcg_control_header_##cname##_show( \ } \ \ static ssize_t \ -uvcg_control_header_##cname##_store(struct uvcg_control_header *ch, \ +uvcg_control_header_##cname##_store(struct config_item *item, \ const char *page, size_t len) \ { \ + struct uvcg_control_header *ch = to_uvcg_control_header(item); \ struct f_uvc_opts *opts; \ struct config_item *opts_item; \ struct mutex *su_mutex = &ch->item.ci_group->cg_subsys->su_mutex;\ @@ -115,11 +111,7 @@ end: \ return ret; \ } \ \ -static struct uvcg_control_header_attribute \ - uvcg_control_header_##cname = \ - __CONFIGFS_ATTR(aname, S_IRUGO | S_IWUSR, \ - uvcg_control_header_##cname##_show, \ - uvcg_control_header_##cname##_store) +UVC_ATTR(uvcg_control_header_, cname, aname) UVCG_CTRL_HDR_ATTR(bcd_uvc, bcdUVC, le16_to_cpu, kstrtou16, u16, cpu_to_le16, 0xffff); @@ -130,13 +122,12 @@ UVCG_CTRL_HDR_ATTR(dw_clock_frequency, dwClockFrequency, le32_to_cpu, kstrtou32, #undef UVCG_CTRL_HDR_ATTR static struct configfs_attribute *uvcg_control_header_attrs[] = { - &uvcg_control_header_bcd_uvc.attr, - &uvcg_control_header_dw_clock_frequency.attr, + &uvcg_control_header_attr_bcd_uvc, + &uvcg_control_header_attr_dw_clock_frequency, NULL, }; static struct config_item_type uvcg_control_header_type = { - .ct_item_ops = &uvcg_control_header_item_ops, .ct_attrs = uvcg_control_header_attrs, .ct_owner = THIS_MODULE, }; @@ -196,17 +187,11 @@ static inline struct uvcg_default_processing struct uvcg_default_processing, group); } -CONFIGFS_ATTR_STRUCT(uvcg_default_processing); -CONFIGFS_ATTR_OPS_RO(uvcg_default_processing); - -static struct configfs_item_operations uvcg_default_processing_item_ops = { - .show_attribute = uvcg_default_processing_attr_show, -}; - #define UVCG_DEFAULT_PROCESSING_ATTR(cname, aname, conv) \ static ssize_t uvcg_default_processing_##cname##_show( \ - struct uvcg_default_processing *dp, char *page) \ + struct config_item *item, char *page) \ { \ + struct uvcg_default_processing *dp = to_uvcg_default_processing(item); \ struct f_uvc_opts *opts; \ struct config_item *opts_item; \ struct mutex *su_mutex = &dp->group.cg_subsys->su_mutex; \ @@ -227,9 +212,7 @@ static ssize_t uvcg_default_processing_##cname##_show( \ return result; \ } \ \ -static struct uvcg_default_processing_attribute \ - uvcg_default_processing_##cname = \ - __CONFIGFS_ATTR_RO(aname, uvcg_default_processing_##cname##_show) +UVC_ATTR_RO(uvcg_default_processing_, cname, aname) #define identity_conv(x) (x) @@ -243,8 +226,9 @@ UVCG_DEFAULT_PROCESSING_ATTR(i_processing, iProcessing, identity_conv); #undef UVCG_DEFAULT_PROCESSING_ATTR static ssize_t uvcg_default_processing_bm_controls_show( - struct uvcg_default_processing *dp, char *page) + struct config_item *item, char *page) { + struct uvcg_default_processing *dp = to_uvcg_default_processing(item); struct f_uvc_opts *opts; struct config_item *opts_item; struct mutex *su_mutex = &dp->group.cg_subsys->su_mutex; @@ -270,22 +254,18 @@ static ssize_t uvcg_default_processing_bm_controls_show( return result; } -static struct uvcg_default_processing_attribute - uvcg_default_processing_bm_controls = - __CONFIGFS_ATTR_RO(bmControls, - uvcg_default_processing_bm_controls_show); +UVC_ATTR_RO(uvcg_default_processing_, bm_controls, bmControls); static struct configfs_attribute *uvcg_default_processing_attrs[] = { - &uvcg_default_processing_b_unit_id.attr, - &uvcg_default_processing_b_source_id.attr, - &uvcg_default_processing_w_max_multiplier.attr, - &uvcg_default_processing_bm_controls.attr, - &uvcg_default_processing_i_processing.attr, + &uvcg_default_processing_attr_b_unit_id, + &uvcg_default_processing_attr_b_source_id, + &uvcg_default_processing_attr_w_max_multiplier, + &uvcg_default_processing_attr_bm_controls, + &uvcg_default_processing_attr_i_processing, NULL, }; static struct config_item_type uvcg_default_processing_type = { - .ct_item_ops = &uvcg_default_processing_item_ops, .ct_attrs = uvcg_default_processing_attrs, .ct_owner = THIS_MODULE, }; @@ -318,17 +298,11 @@ static inline struct uvcg_default_camera struct uvcg_default_camera, group); } -CONFIGFS_ATTR_STRUCT(uvcg_default_camera); -CONFIGFS_ATTR_OPS_RO(uvcg_default_camera); - -static struct configfs_item_operations uvcg_default_camera_item_ops = { - .show_attribute = uvcg_default_camera_attr_show, -}; - #define UVCG_DEFAULT_CAMERA_ATTR(cname, aname, conv) \ static ssize_t uvcg_default_camera_##cname##_show( \ - struct uvcg_default_camera *dc, char *page) \ + struct config_item *item, char *page) \ { \ + struct uvcg_default_camera *dc = to_uvcg_default_camera(item); \ struct f_uvc_opts *opts; \ struct config_item *opts_item; \ struct mutex *su_mutex = &dc->group.cg_subsys->su_mutex; \ @@ -351,9 +325,7 @@ static ssize_t uvcg_default_camera_##cname##_show( \ return result; \ } \ \ -static struct uvcg_default_camera_attribute \ - uvcg_default_camera_##cname = \ - __CONFIGFS_ATTR_RO(aname, uvcg_default_camera_##cname##_show) +UVC_ATTR_RO(uvcg_default_camera_, cname, aname) #define identity_conv(x) (x) @@ -373,8 +345,9 @@ UVCG_DEFAULT_CAMERA_ATTR(w_ocular_focal_length, wOcularFocalLength, #undef UVCG_DEFAULT_CAMERA_ATTR static ssize_t uvcg_default_camera_bm_controls_show( - struct uvcg_default_camera *dc, char *page) + struct config_item *item, char *page) { + struct uvcg_default_camera *dc = to_uvcg_default_camera(item); struct f_uvc_opts *opts; struct config_item *opts_item; struct mutex *su_mutex = &dc->group.cg_subsys->su_mutex; @@ -400,24 +373,21 @@ static ssize_t uvcg_default_camera_bm_controls_show( return result; } -static struct uvcg_default_camera_attribute - uvcg_default_camera_bm_controls = - __CONFIGFS_ATTR_RO(bmControls, uvcg_default_camera_bm_controls_show); +UVC_ATTR_RO(uvcg_default_camera_, bm_controls, bmControls); static struct configfs_attribute *uvcg_default_camera_attrs[] = { - &uvcg_default_camera_b_terminal_id.attr, - &uvcg_default_camera_w_terminal_type.attr, - &uvcg_default_camera_b_assoc_terminal.attr, - &uvcg_default_camera_i_terminal.attr, - &uvcg_default_camera_w_objective_focal_length_min.attr, - &uvcg_default_camera_w_objective_focal_length_max.attr, - &uvcg_default_camera_w_ocular_focal_length.attr, - &uvcg_default_camera_bm_controls.attr, + &uvcg_default_camera_attr_b_terminal_id, + &uvcg_default_camera_attr_w_terminal_type, + &uvcg_default_camera_attr_b_assoc_terminal, + &uvcg_default_camera_attr_i_terminal, + &uvcg_default_camera_attr_w_objective_focal_length_min, + &uvcg_default_camera_attr_w_objective_focal_length_max, + &uvcg_default_camera_attr_w_ocular_focal_length, + &uvcg_default_camera_attr_bm_controls, NULL, }; static struct config_item_type uvcg_default_camera_type = { - .ct_item_ops = &uvcg_default_camera_item_ops, .ct_attrs = uvcg_default_camera_attrs, .ct_owner = THIS_MODULE, }; @@ -450,17 +420,11 @@ static inline struct uvcg_default_output struct uvcg_default_output, group); } -CONFIGFS_ATTR_STRUCT(uvcg_default_output); -CONFIGFS_ATTR_OPS_RO(uvcg_default_output); - -static struct configfs_item_operations uvcg_default_output_item_ops = { - .show_attribute = uvcg_default_output_attr_show, -}; - #define UVCG_DEFAULT_OUTPUT_ATTR(cname, aname, conv) \ static ssize_t uvcg_default_output_##cname##_show( \ - struct uvcg_default_output *dout, char *page) \ + struct config_item *item, char *page) \ { \ + struct uvcg_default_output *dout = to_uvcg_default_output(item); \ struct f_uvc_opts *opts; \ struct config_item *opts_item; \ struct mutex *su_mutex = &dout->group.cg_subsys->su_mutex; \ @@ -483,9 +447,7 @@ static ssize_t uvcg_default_output_##cname##_show( \ return result; \ } \ \ -static struct uvcg_default_output_attribute \ - uvcg_default_output_##cname = \ - __CONFIGFS_ATTR_RO(aname, uvcg_default_output_##cname##_show) +UVC_ATTR_RO(uvcg_default_output_, cname, aname) #define identity_conv(x) (x) @@ -500,16 +462,15 @@ UVCG_DEFAULT_OUTPUT_ATTR(i_terminal, iTerminal, identity_conv); #undef UVCG_DEFAULT_OUTPUT_ATTR static struct configfs_attribute *uvcg_default_output_attrs[] = { - &uvcg_default_output_b_terminal_id.attr, - &uvcg_default_output_w_terminal_type.attr, - &uvcg_default_output_b_assoc_terminal.attr, - &uvcg_default_output_b_source_id.attr, - &uvcg_default_output_i_terminal.attr, + &uvcg_default_output_attr_b_terminal_id, + &uvcg_default_output_attr_w_terminal_type, + &uvcg_default_output_attr_b_assoc_terminal, + &uvcg_default_output_attr_b_source_id, + &uvcg_default_output_attr_i_terminal, NULL, }; static struct config_item_type uvcg_default_output_type = { - .ct_item_ops = &uvcg_default_output_item_ops, .ct_attrs = uvcg_default_output_attrs, .ct_owner = THIS_MODULE, }; @@ -800,9 +761,6 @@ static struct uvcg_streaming_header *to_uvcg_streaming_header(struct config_item return container_of(item, struct uvcg_streaming_header, item); } -CONFIGFS_ATTR_STRUCT(uvcg_streaming_header); -CONFIGFS_ATTR_OPS(uvcg_streaming_header); - static int uvcg_streaming_header_allow_link(struct config_item *src, struct config_item *target) { @@ -893,16 +851,15 @@ out: } static struct configfs_item_operations uvcg_streaming_header_item_ops = { - .show_attribute = uvcg_streaming_header_attr_show, - .store_attribute = uvcg_streaming_header_attr_store, .allow_link = uvcg_streaming_header_allow_link, .drop_link = uvcg_streaming_header_drop_link, }; #define UVCG_STREAMING_HEADER_ATTR(cname, aname, conv) \ static ssize_t uvcg_streaming_header_##cname##_show( \ - struct uvcg_streaming_header *sh, char *page) \ + struct config_item *item, char *page) \ { \ + struct uvcg_streaming_header *sh = to_uvcg_streaming_header(item); \ struct f_uvc_opts *opts; \ struct config_item *opts_item; \ struct mutex *su_mutex = &sh->item.ci_group->cg_subsys->su_mutex;\ @@ -921,9 +878,7 @@ static ssize_t uvcg_streaming_header_##cname##_show( \ return result; \ } \ \ -static struct uvcg_streaming_header_attribute \ - uvcg_streaming_header_##cname = \ - __CONFIGFS_ATTR_RO(aname, uvcg_streaming_header_##cname##_show) +UVC_ATTR_RO(uvcg_streaming_header_, cname, aname) #define identity_conv(x) (x) @@ -939,11 +894,11 @@ UVCG_STREAMING_HEADER_ATTR(b_trigger_usage, bTriggerUsage, identity_conv); #undef UVCG_STREAMING_HEADER_ATTR static struct configfs_attribute *uvcg_streaming_header_attrs[] = { - &uvcg_streaming_header_bm_info.attr, - &uvcg_streaming_header_b_terminal_link.attr, - &uvcg_streaming_header_b_still_capture_method.attr, - &uvcg_streaming_header_b_trigger_support.attr, - &uvcg_streaming_header_b_trigger_usage.attr, + &uvcg_streaming_header_attr_bm_info, + &uvcg_streaming_header_attr_b_terminal_link, + &uvcg_streaming_header_attr_b_still_capture_method, + &uvcg_streaming_header_attr_b_trigger_support, + &uvcg_streaming_header_attr_b_trigger_usage, NULL, }; @@ -1022,17 +977,10 @@ static struct uvcg_frame *to_uvcg_frame(struct config_item *item) return container_of(item, struct uvcg_frame, item); } -CONFIGFS_ATTR_STRUCT(uvcg_frame); -CONFIGFS_ATTR_OPS(uvcg_frame); - -static struct configfs_item_operations uvcg_frame_item_ops = { - .show_attribute = uvcg_frame_attr_show, - .store_attribute = uvcg_frame_attr_store, -}; - #define UVCG_FRAME_ATTR(cname, aname, to_cpu_endian, to_little_endian, bits) \ -static ssize_t uvcg_frame_##cname##_show(struct uvcg_frame *f, char *page)\ +static ssize_t uvcg_frame_##cname##_show(struct config_item *item, char *page)\ { \ + struct uvcg_frame *f = to_uvcg_frame(item); \ struct f_uvc_opts *opts; \ struct config_item *opts_item; \ struct mutex *su_mutex = &f->item.ci_group->cg_subsys->su_mutex;\ @@ -1051,9 +999,10 @@ static ssize_t uvcg_frame_##cname##_show(struct uvcg_frame *f, char *page)\ return result; \ } \ \ -static ssize_t uvcg_frame_##cname##_store(struct uvcg_frame *f, \ +static ssize_t uvcg_frame_##cname##_store(struct config_item *item, \ const char *page, size_t len)\ { \ + struct uvcg_frame *f = to_uvcg_frame(item); \ struct f_uvc_opts *opts; \ struct config_item *opts_item; \ struct uvcg_format *fmt; \ @@ -1085,11 +1034,7 @@ end: \ return ret; \ } \ \ -static struct uvcg_frame_attribute \ - uvcg_frame_##cname = \ - __CONFIGFS_ATTR(aname, S_IRUGO | S_IWUSR, \ - uvcg_frame_##cname##_show, \ - uvcg_frame_##cname##_store) +UVC_ATTR(uvcg_frame_, cname, aname); #define noop_conversion(x) (x) @@ -1108,9 +1053,10 @@ UVCG_FRAME_ATTR(dw_default_frame_interval, dwDefaultFrameInterval, #undef UVCG_FRAME_ATTR -static ssize_t uvcg_frame_dw_frame_interval_show(struct uvcg_frame *frm, +static ssize_t uvcg_frame_dw_frame_interval_show(struct config_item *item, char *page) { + struct uvcg_frame *frm = to_uvcg_frame(item); struct f_uvc_opts *opts; struct config_item *opts_item; struct mutex *su_mutex = &frm->item.ci_group->cg_subsys->su_mutex; @@ -1185,9 +1131,10 @@ static int __uvcg_iter_frm_intrv(const char *page, size_t len, return 0; } -static ssize_t uvcg_frame_dw_frame_interval_store(struct uvcg_frame *ch, +static ssize_t uvcg_frame_dw_frame_interval_store(struct config_item *item, const char *page, size_t len) { + struct uvcg_frame *ch = to_uvcg_frame(item); struct f_uvc_opts *opts; struct config_item *opts_item; struct uvcg_format *fmt; @@ -1234,26 +1181,21 @@ end: return ret; } -static struct uvcg_frame_attribute - uvcg_frame_dw_frame_interval = - __CONFIGFS_ATTR(dwFrameInterval, S_IRUGO | S_IWUSR, - uvcg_frame_dw_frame_interval_show, - uvcg_frame_dw_frame_interval_store); +UVC_ATTR(uvcg_frame_, dw_frame_interval, dwFrameInterval); static struct configfs_attribute *uvcg_frame_attrs[] = { - &uvcg_frame_bm_capabilities.attr, - &uvcg_frame_w_width.attr, - &uvcg_frame_w_height.attr, - &uvcg_frame_dw_min_bit_rate.attr, - &uvcg_frame_dw_max_bit_rate.attr, - &uvcg_frame_dw_max_video_frame_buffer_size.attr, - &uvcg_frame_dw_default_frame_interval.attr, - &uvcg_frame_dw_frame_interval.attr, + &uvcg_frame_attr_bm_capabilities, + &uvcg_frame_attr_w_width, + &uvcg_frame_attr_w_height, + &uvcg_frame_attr_dw_min_bit_rate, + &uvcg_frame_attr_dw_max_bit_rate, + &uvcg_frame_attr_dw_max_video_frame_buffer_size, + &uvcg_frame_attr_dw_default_frame_interval, + &uvcg_frame_attr_dw_frame_interval, NULL, }; static struct config_item_type uvcg_frame_type = { - .ct_item_ops = &uvcg_frame_item_ops, .ct_attrs = uvcg_frame_attrs, .ct_owner = THIS_MODULE, }; @@ -1333,22 +1275,15 @@ static struct uvcg_uncompressed *to_uvcg_uncompressed(struct config_item *item) struct uvcg_uncompressed, fmt); } -CONFIGFS_ATTR_STRUCT(uvcg_uncompressed); -CONFIGFS_ATTR_OPS(uvcg_uncompressed); - -static struct configfs_item_operations uvcg_uncompressed_item_ops = { - .show_attribute = uvcg_uncompressed_attr_show, - .store_attribute = uvcg_uncompressed_attr_store, -}; - static struct configfs_group_operations uvcg_uncompressed_group_ops = { .make_item = uvcg_frame_make, .drop_item = uvcg_frame_drop, }; -static ssize_t uvcg_uncompressed_guid_format_show(struct uvcg_uncompressed *ch, +static ssize_t uvcg_uncompressed_guid_format_show(struct config_item *item, char *page) { + struct uvcg_uncompressed *ch = to_uvcg_uncompressed(item); struct f_uvc_opts *opts; struct config_item *opts_item; struct mutex *su_mutex = &ch->fmt.group.cg_subsys->su_mutex; @@ -1367,9 +1302,10 @@ static ssize_t uvcg_uncompressed_guid_format_show(struct uvcg_uncompressed *ch, return sizeof(ch->desc.guidFormat); } -static ssize_t uvcg_uncompressed_guid_format_store(struct uvcg_uncompressed *ch, +static ssize_t uvcg_uncompressed_guid_format_store(struct config_item *item, const char *page, size_t len) { + struct uvcg_uncompressed *ch = to_uvcg_uncompressed(item); struct f_uvc_opts *opts; struct config_item *opts_item; struct mutex *su_mutex = &ch->fmt.group.cg_subsys->su_mutex; @@ -1396,16 +1332,13 @@ end: return ret; } -static struct uvcg_uncompressed_attribute uvcg_uncompressed_guid_format = - __CONFIGFS_ATTR(guidFormat, S_IRUGO | S_IWUSR, - uvcg_uncompressed_guid_format_show, - uvcg_uncompressed_guid_format_store); - +UVC_ATTR(uvcg_uncompressed_, guid_format, guidFormat); #define UVCG_UNCOMPRESSED_ATTR_RO(cname, aname, conv) \ static ssize_t uvcg_uncompressed_##cname##_show( \ - struct uvcg_uncompressed *u, char *page) \ + struct config_item *item, char *page) \ { \ + struct uvcg_uncompressed *u = to_uvcg_uncompressed(item); \ struct f_uvc_opts *opts; \ struct config_item *opts_item; \ struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex; \ @@ -1424,14 +1357,13 @@ static ssize_t uvcg_uncompressed_##cname##_show( \ return result; \ } \ \ -static struct uvcg_uncompressed_attribute \ - uvcg_uncompressed_##cname = \ - __CONFIGFS_ATTR_RO(aname, uvcg_uncompressed_##cname##_show) +UVC_ATTR_RO(uvcg_uncompressed_, cname, aname); #define UVCG_UNCOMPRESSED_ATTR(cname, aname, conv) \ static ssize_t uvcg_uncompressed_##cname##_show( \ - struct uvcg_uncompressed *u, char *page) \ + struct config_item *item, char *page) \ { \ + struct uvcg_uncompressed *u = to_uvcg_uncompressed(item); \ struct f_uvc_opts *opts; \ struct config_item *opts_item; \ struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex; \ @@ -1451,9 +1383,10 @@ static ssize_t uvcg_uncompressed_##cname##_show( \ } \ \ static ssize_t \ -uvcg_uncompressed_##cname##_store(struct uvcg_uncompressed *u, \ +uvcg_uncompressed_##cname##_store(struct config_item *item, \ const char *page, size_t len) \ { \ + struct uvcg_uncompressed *u = to_uvcg_uncompressed(item); \ struct f_uvc_opts *opts; \ struct config_item *opts_item; \ struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex; \ @@ -1487,11 +1420,7 @@ end: \ return ret; \ } \ \ -static struct uvcg_uncompressed_attribute \ - uvcg_uncompressed_##cname = \ - __CONFIGFS_ATTR(aname, S_IRUGO | S_IWUSR, \ - uvcg_uncompressed_##cname##_show, \ - uvcg_uncompressed_##cname##_store) +UVC_ATTR(uvcg_uncompressed_, cname, aname); #define identity_conv(x) (x) @@ -1508,36 +1437,34 @@ UVCG_UNCOMPRESSED_ATTR_RO(bm_interface_flags, bmInterfaceFlags, identity_conv); #undef UVCG_UNCOMPRESSED_ATTR_RO static inline ssize_t -uvcg_uncompressed_bma_controls_show(struct uvcg_uncompressed *unc, char *page) +uvcg_uncompressed_bma_controls_show(struct config_item *item, char *page) { + struct uvcg_uncompressed *unc = to_uvcg_uncompressed(item); return uvcg_format_bma_controls_show(&unc->fmt, page); } static inline ssize_t -uvcg_uncompressed_bma_controls_store(struct uvcg_uncompressed *ch, +uvcg_uncompressed_bma_controls_store(struct config_item *item, const char *page, size_t len) { - return uvcg_format_bma_controls_store(&ch->fmt, page, len); + struct uvcg_uncompressed *unc = to_uvcg_uncompressed(item); + return uvcg_format_bma_controls_store(&unc->fmt, page, len); } -static struct uvcg_uncompressed_attribute uvcg_uncompressed_bma_controls = - __CONFIGFS_ATTR(bmaControls, S_IRUGO | S_IWUSR, - uvcg_uncompressed_bma_controls_show, - uvcg_uncompressed_bma_controls_store); +UVC_ATTR(uvcg_uncompressed_, bma_controls, bmaControls); static struct configfs_attribute *uvcg_uncompressed_attrs[] = { - &uvcg_uncompressed_guid_format.attr, - &uvcg_uncompressed_b_bits_per_pixel.attr, - &uvcg_uncompressed_b_default_frame_index.attr, - &uvcg_uncompressed_b_aspect_ratio_x.attr, - &uvcg_uncompressed_b_aspect_ratio_y.attr, - &uvcg_uncompressed_bm_interface_flags.attr, - &uvcg_uncompressed_bma_controls.attr, + &uvcg_uncompressed_attr_guid_format, + &uvcg_uncompressed_attr_b_bits_per_pixel, + &uvcg_uncompressed_attr_b_default_frame_index, + &uvcg_uncompressed_attr_b_aspect_ratio_x, + &uvcg_uncompressed_attr_b_aspect_ratio_y, + &uvcg_uncompressed_attr_bm_interface_flags, + &uvcg_uncompressed_attr_bma_controls, NULL, }; static struct config_item_type uvcg_uncompressed_type = { - .ct_item_ops = &uvcg_uncompressed_item_ops, .ct_group_ops = &uvcg_uncompressed_group_ops, .ct_attrs = uvcg_uncompressed_attrs, .ct_owner = THIS_MODULE, @@ -1605,22 +1532,15 @@ static struct uvcg_mjpeg *to_uvcg_mjpeg(struct config_item *item) struct uvcg_mjpeg, fmt); } -CONFIGFS_ATTR_STRUCT(uvcg_mjpeg); -CONFIGFS_ATTR_OPS(uvcg_mjpeg); - -static struct configfs_item_operations uvcg_mjpeg_item_ops = { - .show_attribute = uvcg_mjpeg_attr_show, - .store_attribute = uvcg_mjpeg_attr_store, -}; - static struct configfs_group_operations uvcg_mjpeg_group_ops = { .make_item = uvcg_frame_make, .drop_item = uvcg_frame_drop, }; #define UVCG_MJPEG_ATTR_RO(cname, aname, conv) \ -static ssize_t uvcg_mjpeg_##cname##_show(struct uvcg_mjpeg *u, char *page)\ +static ssize_t uvcg_mjpeg_##cname##_show(struct config_item *item, char *page)\ { \ + struct uvcg_mjpeg *u = to_uvcg_mjpeg(item); \ struct f_uvc_opts *opts; \ struct config_item *opts_item; \ struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex; \ @@ -1639,13 +1559,12 @@ static ssize_t uvcg_mjpeg_##cname##_show(struct uvcg_mjpeg *u, char *page)\ return result; \ } \ \ -static struct uvcg_mjpeg_attribute \ - uvcg_mjpeg_##cname = \ - __CONFIGFS_ATTR_RO(aname, uvcg_mjpeg_##cname##_show) +UVC_ATTR_RO(uvcg_mjpeg_, cname, aname) #define UVCG_MJPEG_ATTR(cname, aname, conv) \ -static ssize_t uvcg_mjpeg_##cname##_show(struct uvcg_mjpeg *u, char *page)\ +static ssize_t uvcg_mjpeg_##cname##_show(struct config_item *item, char *page)\ { \ + struct uvcg_mjpeg *u = to_uvcg_mjpeg(item); \ struct f_uvc_opts *opts; \ struct config_item *opts_item; \ struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex; \ @@ -1665,9 +1584,10 @@ static ssize_t uvcg_mjpeg_##cname##_show(struct uvcg_mjpeg *u, char *page)\ } \ \ static ssize_t \ -uvcg_mjpeg_##cname##_store(struct uvcg_mjpeg *u, \ +uvcg_mjpeg_##cname##_store(struct config_item *item, \ const char *page, size_t len) \ { \ + struct uvcg_mjpeg *u = to_uvcg_mjpeg(item); \ struct f_uvc_opts *opts; \ struct config_item *opts_item; \ struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex; \ @@ -1701,11 +1621,7 @@ end: \ return ret; \ } \ \ -static struct uvcg_mjpeg_attribute \ - uvcg_mjpeg_##cname = \ - __CONFIGFS_ATTR(aname, S_IRUGO | S_IWUSR, \ - uvcg_mjpeg_##cname##_show, \ - uvcg_mjpeg_##cname##_store) +UVC_ATTR(uvcg_mjpeg_, cname, aname) #define identity_conv(x) (x) @@ -1722,35 +1638,33 @@ UVCG_MJPEG_ATTR_RO(bm_interface_flags, bmInterfaceFlags, identity_conv); #undef UVCG_MJPEG_ATTR_RO static inline ssize_t -uvcg_mjpeg_bma_controls_show(struct uvcg_mjpeg *unc, char *page) +uvcg_mjpeg_bma_controls_show(struct config_item *item, char *page) { - return uvcg_format_bma_controls_show(&unc->fmt, page); + struct uvcg_mjpeg *u = to_uvcg_mjpeg(item); + return uvcg_format_bma_controls_show(&u->fmt, page); } static inline ssize_t -uvcg_mjpeg_bma_controls_store(struct uvcg_mjpeg *ch, +uvcg_mjpeg_bma_controls_store(struct config_item *item, const char *page, size_t len) { - return uvcg_format_bma_controls_store(&ch->fmt, page, len); + struct uvcg_mjpeg *u = to_uvcg_mjpeg(item); + return uvcg_format_bma_controls_store(&u->fmt, page, len); } -static struct uvcg_mjpeg_attribute uvcg_mjpeg_bma_controls = - __CONFIGFS_ATTR(bmaControls, S_IRUGO | S_IWUSR, - uvcg_mjpeg_bma_controls_show, - uvcg_mjpeg_bma_controls_store); +UVC_ATTR(uvcg_mjpeg_, bma_controls, bmaControls); static struct configfs_attribute *uvcg_mjpeg_attrs[] = { - &uvcg_mjpeg_b_default_frame_index.attr, - &uvcg_mjpeg_bm_flags.attr, - &uvcg_mjpeg_b_aspect_ratio_x.attr, - &uvcg_mjpeg_b_aspect_ratio_y.attr, - &uvcg_mjpeg_bm_interface_flags.attr, - &uvcg_mjpeg_bma_controls.attr, + &uvcg_mjpeg_attr_b_default_frame_index, + &uvcg_mjpeg_attr_bm_flags, + &uvcg_mjpeg_attr_b_aspect_ratio_x, + &uvcg_mjpeg_attr_b_aspect_ratio_y, + &uvcg_mjpeg_attr_bm_interface_flags, + &uvcg_mjpeg_attr_bma_controls, NULL, }; static struct config_item_type uvcg_mjpeg_type = { - .ct_item_ops = &uvcg_mjpeg_item_ops, .ct_group_ops = &uvcg_mjpeg_group_ops, .ct_attrs = uvcg_mjpeg_attrs, .ct_owner = THIS_MODULE, @@ -1811,17 +1725,12 @@ static inline struct uvcg_default_color_matching struct uvcg_default_color_matching, group); } -CONFIGFS_ATTR_STRUCT(uvcg_default_color_matching); -CONFIGFS_ATTR_OPS_RO(uvcg_default_color_matching); - -static struct configfs_item_operations uvcg_default_color_matching_item_ops = { - .show_attribute = uvcg_default_color_matching_attr_show, -}; - #define UVCG_DEFAULT_COLOR_MATCHING_ATTR(cname, aname, conv) \ static ssize_t uvcg_default_color_matching_##cname##_show( \ - struct uvcg_default_color_matching *dc, char *page) \ + struct config_item *item, char *page) \ { \ + struct uvcg_default_color_matching *dc = \ + to_uvcg_default_color_matching(item); \ struct f_uvc_opts *opts; \ struct config_item *opts_item; \ struct mutex *su_mutex = &dc->group.cg_subsys->su_mutex; \ @@ -1842,9 +1751,7 @@ static ssize_t uvcg_default_color_matching_##cname##_show( \ return result; \ } \ \ -static struct uvcg_default_color_matching_attribute \ - uvcg_default_color_matching_##cname = \ - __CONFIGFS_ATTR_RO(aname, uvcg_default_color_matching_##cname##_show) +UVC_ATTR_RO(uvcg_default_color_matching_, cname, aname) #define identity_conv(x) (x) @@ -1860,14 +1767,13 @@ UVCG_DEFAULT_COLOR_MATCHING_ATTR(b_matrix_coefficients, bMatrixCoefficients, #undef UVCG_DEFAULT_COLOR_MATCHING_ATTR static struct configfs_attribute *uvcg_default_color_matching_attrs[] = { - &uvcg_default_color_matching_b_color_primaries.attr, - &uvcg_default_color_matching_b_transfer_characteristics.attr, - &uvcg_default_color_matching_b_matrix_coefficients.attr, + &uvcg_default_color_matching_attr_b_color_primaries, + &uvcg_default_color_matching_attr_b_transfer_characteristics, + &uvcg_default_color_matching_attr_b_matrix_coefficients, NULL, }; static struct config_item_type uvcg_default_color_matching_type = { - .ct_item_ops = &uvcg_default_color_matching_item_ops, .ct_attrs = uvcg_default_color_matching_attrs, .ct_owner = THIS_MODULE, }; @@ -2285,9 +2191,6 @@ static inline struct f_uvc_opts *to_f_uvc_opts(struct config_item *item) func_inst.group); } -CONFIGFS_ATTR_STRUCT(f_uvc_opts); -CONFIGFS_ATTR_OPS(f_uvc_opts); - static void uvc_attr_release(struct config_item *item) { struct f_uvc_opts *opts = to_f_uvc_opts(item); @@ -2297,14 +2200,13 @@ static void uvc_attr_release(struct config_item *item) static struct configfs_item_operations uvc_item_ops = { .release = uvc_attr_release, - .show_attribute = f_uvc_opts_attr_show, - .store_attribute = f_uvc_opts_attr_store, }; #define UVCG_OPTS_ATTR(cname, conv, str2u, uxx, vnoc, limit) \ static ssize_t f_uvc_opts_##cname##_show( \ - struct f_uvc_opts *opts, char *page) \ + struct config_item *item, char *page) \ { \ + struct f_uvc_opts *opts = to_f_uvc_opts(item); \ int result; \ \ mutex_lock(&opts->lock); \ @@ -2315,9 +2217,10 @@ static ssize_t f_uvc_opts_##cname##_show( \ } \ \ static ssize_t \ -f_uvc_opts_##cname##_store(struct f_uvc_opts *opts, \ +f_uvc_opts_##cname##_store(struct config_item *item, \ const char *page, size_t len) \ { \ + struct f_uvc_opts *opts = to_f_uvc_opts(item); \ int ret; \ uxx num; \ \ @@ -2342,11 +2245,7 @@ end: \ return ret; \ } \ \ -static struct f_uvc_opts_attribute \ - f_uvc_opts_attribute_##cname = \ - __CONFIGFS_ATTR(cname, S_IRUGO | S_IWUSR, \ - f_uvc_opts_##cname##_show, \ - f_uvc_opts_##cname##_store) +UVC_ATTR(f_uvc_opts_, cname, aname) #define identity_conv(x) (x) @@ -2362,9 +2261,9 @@ UVCG_OPTS_ATTR(streaming_maxburst, identity_conv, kstrtou8, u8, identity_conv, #undef UVCG_OPTS_ATTR static struct configfs_attribute *uvc_attrs[] = { - &f_uvc_opts_attribute_streaming_interval.attr, - &f_uvc_opts_attribute_streaming_maxpacket.attr, - &f_uvc_opts_attribute_streaming_maxburst.attr, + &f_uvc_opts_attr_streaming_interval, + &f_uvc_opts_attr_streaming_maxpacket, + &f_uvc_opts_attr_streaming_maxburst, NULL, }; diff --git a/drivers/usb/gadget/legacy/tcm_usb_gadget.c b/drivers/usb/gadget/legacy/tcm_usb_gadget.c index 778e42abb3cb..22e56158d585 100644 --- a/drivers/usb/gadget/legacy/tcm_usb_gadget.c +++ b/drivers/usb/gadget/legacy/tcm_usb_gadget.c @@ -19,8 +19,6 @@ #include <scsi/scsi_tcq.h> #include <target/target_core_base.h> #include <target/target_core_fabric.h> -#include <target/target_core_fabric_configfs.h> -#include <target/configfs_macros.h> #include <asm/unaligned.h> #include "tcm_usb_gadget.h" @@ -1467,23 +1465,21 @@ static void usbg_drop_tport(struct se_wwn *wwn) /* * If somebody feels like dropping the version property, go ahead. */ -static ssize_t usbg_wwn_show_attr_version( - struct target_fabric_configfs *tf, - char *page) +static ssize_t usbg_wwn_version_show(struct config_item *item, char *page) { return sprintf(page, "usb-gadget fabric module\n"); } -TF_WWN_ATTR_RO(usbg, version); + +CONFIGFS_ATTR_RO(usbg_wwn_, version); static struct configfs_attribute *usbg_wwn_attrs[] = { - &usbg_wwn_version.attr, + &usbg_wwn_attr_version, NULL, }; -static ssize_t tcm_usbg_tpg_show_enable( - struct se_portal_group *se_tpg, - char *page) +static ssize_t tcm_usbg_tpg_enable_show(struct config_item *item, char *page) { + struct se_portal_group *se_tpg = to_tpg(item); struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg); return snprintf(page, PAGE_SIZE, "%u\n", tpg->gadget_connect); @@ -1492,11 +1488,10 @@ static ssize_t tcm_usbg_tpg_show_enable( static int usbg_attach(struct usbg_tpg *); static void usbg_detach(struct usbg_tpg *); -static ssize_t tcm_usbg_tpg_store_enable( - struct se_portal_group *se_tpg, - const char *page, - size_t count) +static ssize_t tcm_usbg_tpg_enable_store(struct config_item *item, + const char *page, size_t count) { + struct se_portal_group *se_tpg = to_tpg(item); struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg); unsigned long op; ssize_t ret; @@ -1523,12 +1518,10 @@ static ssize_t tcm_usbg_tpg_store_enable( out: return count; } -TF_TPG_BASE_ATTR(tcm_usbg, enable, S_IRUGO | S_IWUSR); -static ssize_t tcm_usbg_tpg_show_nexus( - struct se_portal_group *se_tpg, - char *page) +static ssize_t tcm_usbg_tpg_nexus_show(struct config_item *item, char *page) { + struct se_portal_group *se_tpg = to_tpg(item); struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg); struct tcm_usbg_nexus *tv_nexus; ssize_t ret; @@ -1636,11 +1629,10 @@ out: return ret; } -static ssize_t tcm_usbg_tpg_store_nexus( - struct se_portal_group *se_tpg, - const char *page, - size_t count) +static ssize_t tcm_usbg_tpg_nexus_store(struct config_item *item, + const char *page, size_t count) { + struct se_portal_group *se_tpg = to_tpg(item); struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg); unsigned char i_port[USBG_NAMELEN], *ptr; int ret; @@ -1670,11 +1662,13 @@ static ssize_t tcm_usbg_tpg_store_nexus( return ret; return count; } -TF_TPG_BASE_ATTR(tcm_usbg, nexus, S_IRUGO | S_IWUSR); + +CONFIGFS_ATTR(tcm_usbg_tpg_, enable); +CONFIGFS_ATTR(tcm_usbg_tpg_, nexus); static struct configfs_attribute *usbg_base_attrs[] = { - &tcm_usbg_tpg_enable.attr, - &tcm_usbg_tpg_nexus.attr, + &tcm_usbg_tpg_attr_enable, + &tcm_usbg_tpg_attr_nexus, NULL, }; diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c b/drivers/usb/gadget/udc/atmel_usba_udc.c index f0f2b066ac08..f92f5aff0dd5 100644 --- a/drivers/usb/gadget/udc/atmel_usba_udc.c +++ b/drivers/usb/gadget/udc/atmel_usba_udc.c @@ -1633,7 +1633,7 @@ static irqreturn_t usba_udc_irq(int irq, void *devid) spin_lock(&udc->lock); int_enb = usba_int_enb_get(udc); - status = usba_readl(udc, INT_STA) & int_enb; + status = usba_readl(udc, INT_STA) & (int_enb | USBA_HIGH_SPEED); DBG(DBG_INT, "irq, status=%#08x\n", status); if (status & USBA_DET_SUSPEND) { diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 5d2d7e954bd4..0230965fb78c 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -782,12 +782,15 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd, status |= USB_PORT_STAT_SUSPEND; } } - if ((raw_port_status & PORT_PLS_MASK) == XDEV_U0 - && (raw_port_status & PORT_POWER) - && (bus_state->suspended_ports & (1 << wIndex))) { - bus_state->suspended_ports &= ~(1 << wIndex); - if (hcd->speed < HCD_USB3) - bus_state->port_c_suspend |= 1 << wIndex; + if ((raw_port_status & PORT_PLS_MASK) == XDEV_U0 && + (raw_port_status & PORT_POWER)) { + if (bus_state->suspended_ports & (1 << wIndex)) { + bus_state->suspended_ports &= ~(1 << wIndex); + if (hcd->speed < HCD_USB3) + bus_state->port_c_suspend |= 1 << wIndex; + } + bus_state->resume_done[wIndex] = 0; + clear_bit(wIndex, &bus_state->resuming_ports); } if (raw_port_status & PORT_CONNECT) { status |= USB_PORT_STAT_CONNECTION; diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index fa836251ca21..6c5e8133cf87 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -3896,28 +3896,6 @@ cleanup: return ret; } -static int ep_ring_is_processing(struct xhci_hcd *xhci, - int slot_id, unsigned int ep_index) -{ - struct xhci_virt_device *xdev; - struct xhci_ring *ep_ring; - struct xhci_ep_ctx *ep_ctx; - struct xhci_virt_ep *xep; - dma_addr_t hw_deq; - - xdev = xhci->devs[slot_id]; - xep = &xhci->devs[slot_id]->eps[ep_index]; - ep_ring = xep->ring; - ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index); - - if ((le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK) != EP_STATE_RUNNING) - return 0; - - hw_deq = le64_to_cpu(ep_ctx->deq) & ~EP_CTX_CYCLE_MASK; - return (hw_deq != - xhci_trb_virt_to_dma(ep_ring->enq_seg, ep_ring->enqueue)); -} - /* * Check transfer ring to guarantee there is enough room for the urb. * Update ISO URB start_frame and interval. @@ -3983,10 +3961,12 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags, } /* Calculate the start frame and put it in urb->start_frame. */ - if (HCC_CFC(xhci->hcc_params) && - ep_ring_is_processing(xhci, slot_id, ep_index)) { - urb->start_frame = xep->next_frame_id; - goto skip_start_over; + if (HCC_CFC(xhci->hcc_params) && !list_empty(&ep_ring->td_list)) { + if ((le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK) == + EP_STATE_RUNNING) { + urb->start_frame = xep->next_frame_id; + goto skip_start_over; + } } start_frame = readl(&xhci->run_regs->microframe_index); diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 6e7dc6f93978..dfa44d3e8eee 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -175,6 +175,16 @@ int xhci_reset(struct xhci_hcd *xhci) command |= CMD_RESET; writel(command, &xhci->op_regs->command); + /* Existing Intel xHCI controllers require a delay of 1 mS, + * after setting the CMD_RESET bit, and before accessing any + * HC registers. This allows the HC to complete the + * reset operation and be ready for HC register access. + * Without this delay, the subsequent HC register access, + * may result in a system hang very rarely. + */ + if (xhci->quirks & XHCI_INTEL_HOST) + udelay(1000); + ret = xhci_handshake(&xhci->op_regs->command, CMD_RESET, 0, 10 * 1000 * 1000); if (ret) diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index ba13529cbd52..18cfc0a361cb 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -132,7 +132,7 @@ static inline struct musb *dev_to_musb(struct device *dev) /*-------------------------------------------------------------------------*/ #ifndef CONFIG_BLACKFIN -static int musb_ulpi_read(struct usb_phy *phy, u32 offset) +static int musb_ulpi_read(struct usb_phy *phy, u32 reg) { void __iomem *addr = phy->io_priv; int i = 0; @@ -151,7 +151,7 @@ static int musb_ulpi_read(struct usb_phy *phy, u32 offset) * ULPICarKitControlDisableUTMI after clearing POWER_SUSPENDM. */ - musb_writeb(addr, MUSB_ULPI_REG_ADDR, (u8)offset); + musb_writeb(addr, MUSB_ULPI_REG_ADDR, (u8)reg); musb_writeb(addr, MUSB_ULPI_REG_CONTROL, MUSB_ULPI_REG_REQ | MUSB_ULPI_RDN_WR); @@ -176,7 +176,7 @@ out: return ret; } -static int musb_ulpi_write(struct usb_phy *phy, u32 offset, u32 data) +static int musb_ulpi_write(struct usb_phy *phy, u32 val, u32 reg) { void __iomem *addr = phy->io_priv; int i = 0; @@ -191,8 +191,8 @@ static int musb_ulpi_write(struct usb_phy *phy, u32 offset, u32 data) power &= ~MUSB_POWER_SUSPENDM; musb_writeb(addr, MUSB_POWER, power); - musb_writeb(addr, MUSB_ULPI_REG_ADDR, (u8)offset); - musb_writeb(addr, MUSB_ULPI_REG_DATA, (u8)data); + musb_writeb(addr, MUSB_ULPI_REG_ADDR, (u8)reg); + musb_writeb(addr, MUSB_ULPI_REG_DATA, (u8)val); musb_writeb(addr, MUSB_ULPI_REG_CONTROL, MUSB_ULPI_REG_REQ); while (!(musb_readb(addr, MUSB_ULPI_REG_CONTROL) @@ -1668,7 +1668,7 @@ EXPORT_SYMBOL_GPL(musb_interrupt); static bool use_dma = 1; /* "modprobe ... use_dma=0" etc */ -module_param(use_dma, bool, 0); +module_param(use_dma, bool, 0644); MODULE_PARM_DESC(use_dma, "enable/disable use of DMA"); void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit) diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 26c65e66cc0f..795a45b1b25b 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -112,22 +112,32 @@ static void musb_h_tx_flush_fifo(struct musb_hw_ep *ep) struct musb *musb = ep->musb; void __iomem *epio = ep->regs; u16 csr; - u16 lastcsr = 0; int retries = 1000; csr = musb_readw(epio, MUSB_TXCSR); while (csr & MUSB_TXCSR_FIFONOTEMPTY) { - if (csr != lastcsr) - dev_dbg(musb->controller, "Host TX FIFONOTEMPTY csr: %02x\n", csr); - lastcsr = csr; csr |= MUSB_TXCSR_FLUSHFIFO | MUSB_TXCSR_TXPKTRDY; musb_writew(epio, MUSB_TXCSR, csr); csr = musb_readw(epio, MUSB_TXCSR); - if (WARN(retries-- < 1, + + /* + * FIXME: sometimes the tx fifo flush failed, it has been + * observed during device disconnect on AM335x. + * + * To reproduce the issue, ensure tx urb(s) are queued when + * unplug the usb device which is connected to AM335x usb + * host port. + * + * I found using a usb-ethernet device and running iperf + * (client on AM335x) has very high chance to trigger it. + * + * Better to turn on dev_dbg() in musb_cleanup_urb() with + * CPPI enabled to see the issue when aborting the tx channel. + */ + if (dev_WARN_ONCE(musb->controller, retries-- < 1, "Could not flush host TX%d fifo: csr: %04x\n", ep->epnum, csr)) return; - mdelay(1); } } diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig index 173132416170..22e8ecb6bfbd 100644 --- a/drivers/usb/phy/Kconfig +++ b/drivers/usb/phy/Kconfig @@ -21,7 +21,6 @@ config AB8500_USB config FSL_USB2_OTG bool "Freescale USB OTG Transceiver Driver" depends on USB_EHCI_FSL && USB_FSL_USB2 && USB_OTG_FSM && PM - select USB_OTG select USB_PHY help Enable this to support Freescale USB OTG transceiver. @@ -168,8 +167,7 @@ config USB_QCOM_8X16_PHY config USB_MV_OTG tristate "Marvell USB OTG support" - depends on USB_EHCI_MV && USB_MV_UDC && PM - select USB_OTG + depends on USB_EHCI_MV && USB_MV_UDC && PM && USB_OTG select USB_PHY help Say Y here if you want to build Marvell USB OTG transciever diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c index 4d863ebc117c..b7536af777ab 100644 --- a/drivers/usb/phy/phy-mxs-usb.c +++ b/drivers/usb/phy/phy-mxs-usb.c @@ -452,10 +452,13 @@ static int mxs_phy_probe(struct platform_device *pdev) struct clk *clk; struct mxs_phy *mxs_phy; int ret; - const struct of_device_id *of_id = - of_match_device(mxs_phy_dt_ids, &pdev->dev); + const struct of_device_id *of_id; struct device_node *np = pdev->dev.of_node; + of_id = of_match_device(mxs_phy_dt_ids, &pdev->dev); + if (!of_id) + return -ENODEV; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(base)) diff --git a/drivers/usb/phy/phy-omap-otg.c b/drivers/usb/phy/phy-omap-otg.c index 1270906ccb95..c4bf2de6d14e 100644 --- a/drivers/usb/phy/phy-omap-otg.c +++ b/drivers/usb/phy/phy-omap-otg.c @@ -105,7 +105,6 @@ static int omap_otg_probe(struct platform_device *pdev) extcon = extcon_get_extcon_dev(config->extcon); if (!extcon) return -EPROBE_DEFER; - otg_dev->extcon = extcon; otg_dev = devm_kzalloc(&pdev->dev, sizeof(*otg_dev), GFP_KERNEL); if (!otg_dev) @@ -115,6 +114,7 @@ static int omap_otg_probe(struct platform_device *pdev) if (IS_ERR(otg_dev->base)) return PTR_ERR(otg_dev->base); + otg_dev->extcon = extcon; otg_dev->id_nb.notifier_call = omap_otg_id_notifier; otg_dev->vbus_nb.notifier_call = omap_otg_vbus_notifier; diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 685fef71d3d1..f2280606b73c 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -161,6 +161,7 @@ static void option_instat_callback(struct urb *urb); #define NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_HIGHSPEED 0x9001 #define NOVATELWIRELESS_PRODUCT_E362 0x9010 #define NOVATELWIRELESS_PRODUCT_E371 0x9011 +#define NOVATELWIRELESS_PRODUCT_U620L 0x9022 #define NOVATELWIRELESS_PRODUCT_G2 0xA010 #define NOVATELWIRELESS_PRODUCT_MC551 0xB001 @@ -354,6 +355,7 @@ static void option_instat_callback(struct urb *urb); /* This is the 4G XS Stick W14 a.k.a. Mobilcom Debitel Surf-Stick * * It seems to contain a Qualcomm QSC6240/6290 chipset */ #define FOUR_G_SYSTEMS_PRODUCT_W14 0x9603 +#define FOUR_G_SYSTEMS_PRODUCT_W100 0x9b01 /* iBall 3.5G connect wireless modem */ #define IBALL_3_5G_CONNECT 0x9605 @@ -519,6 +521,11 @@ static const struct option_blacklist_info four_g_w14_blacklist = { .sendsetup = BIT(0) | BIT(1), }; +static const struct option_blacklist_info four_g_w100_blacklist = { + .sendsetup = BIT(1) | BIT(2), + .reserved = BIT(3), +}; + static const struct option_blacklist_info alcatel_x200_blacklist = { .sendsetup = BIT(0) | BIT(1), .reserved = BIT(4), @@ -1052,6 +1059,7 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC551, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_E362, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_E371, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_U620L, 0xff, 0x00, 0x00) }, { USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_H01) }, { USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_H01A) }, @@ -1641,6 +1649,9 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(LONGCHEER_VENDOR_ID, FOUR_G_SYSTEMS_PRODUCT_W14), .driver_info = (kernel_ulong_t)&four_g_w14_blacklist }, + { USB_DEVICE(LONGCHEER_VENDOR_ID, FOUR_G_SYSTEMS_PRODUCT_W100), + .driver_info = (kernel_ulong_t)&four_g_w100_blacklist + }, { USB_DEVICE_INTERFACE_CLASS(LONGCHEER_VENDOR_ID, SPEEDUP_PRODUCT_SU9800, 0xff) }, { USB_DEVICE(LONGCHEER_VENDOR_ID, ZOOM_PRODUCT_4597) }, { USB_DEVICE(LONGCHEER_VENDOR_ID, IBALL_3_5G_CONNECT) }, diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c index 5022fcfa0260..9919d2a9faf2 100644 --- a/drivers/usb/serial/qcserial.c +++ b/drivers/usb/serial/qcserial.c @@ -22,6 +22,8 @@ #define DRIVER_AUTHOR "Qualcomm Inc" #define DRIVER_DESC "Qualcomm USB Serial driver" +#define QUECTEL_EC20_PID 0x9215 + /* standard device layouts supported by this driver */ enum qcserial_layouts { QCSERIAL_G2K = 0, /* Gobi 2000 */ @@ -171,6 +173,38 @@ static const struct usb_device_id id_table[] = { }; MODULE_DEVICE_TABLE(usb, id_table); +static int handle_quectel_ec20(struct device *dev, int ifnum) +{ + int altsetting = 0; + + /* + * Quectel EC20 Mini PCIe LTE module layout: + * 0: DM/DIAG (use libqcdm from ModemManager for communication) + * 1: NMEA + * 2: AT-capable modem port + * 3: Modem interface + * 4: NDIS + */ + switch (ifnum) { + case 0: + dev_dbg(dev, "Quectel EC20 DM/DIAG interface found\n"); + break; + case 1: + dev_dbg(dev, "Quectel EC20 NMEA GPS interface found\n"); + break; + case 2: + case 3: + dev_dbg(dev, "Quectel EC20 Modem port found\n"); + break; + case 4: + /* Don't claim the QMI/net interface */ + altsetting = -1; + break; + } + + return altsetting; +} + static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id) { struct usb_host_interface *intf = serial->interface->cur_altsetting; @@ -181,6 +215,10 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id) int altsetting = -1; bool sendsetup = false; + /* we only support vendor specific functions */ + if (intf->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC) + goto done; + nintf = serial->dev->actconfig->desc.bNumInterfaces; dev_dbg(dev, "Num Interfaces = %d\n", nintf); ifnum = intf->desc.bInterfaceNumber; @@ -240,6 +278,12 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id) altsetting = -1; break; case QCSERIAL_G2K: + /* handle non-standard layouts */ + if (nintf == 5 && id->idProduct == QUECTEL_EC20_PID) { + altsetting = handle_quectel_ec20(dev, ifnum); + goto done; + } + /* * Gobi 2K+ USB layout: * 0: QMI/net @@ -301,29 +345,39 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id) break; case QCSERIAL_HWI: /* - * Huawei layout: - * 0: AT-capable modem port - * 1: DM/DIAG - * 2: AT-capable modem port - * 3: CCID-compatible PCSC interface - * 4: QMI/net - * 5: NMEA + * Huawei devices map functions by subclass + protocol + * instead of interface numbers. The protocol identify + * a specific function, while the subclass indicate a + * specific firmware source + * + * This is a blacklist of functions known to be + * non-serial. The rest are assumed to be serial and + * will be handled by this driver */ - switch (ifnum) { - case 0: - case 2: - dev_dbg(dev, "Modem port found\n"); - break; - case 1: - dev_dbg(dev, "DM/DIAG interface found\n"); - break; - case 5: - dev_dbg(dev, "NMEA GPS interface found\n"); - break; - default: - /* don't claim any unsupported interface */ + switch (intf->desc.bInterfaceProtocol) { + /* QMI combined (qmi_wwan) */ + case 0x07: + case 0x37: + case 0x67: + /* QMI data (qmi_wwan) */ + case 0x08: + case 0x38: + case 0x68: + /* QMI control (qmi_wwan) */ + case 0x09: + case 0x39: + case 0x69: + /* NCM like (huawei_cdc_ncm) */ + case 0x16: + case 0x46: + case 0x76: altsetting = -1; break; + default: + dev_dbg(dev, "Huawei type serial port found (%02x/%02x/%02x)\n", + intf->desc.bInterfaceClass, + intf->desc.bInterfaceSubClass, + intf->desc.bInterfaceProtocol); } break; default: diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index e9da41d9fe7f..2694df2f4559 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -159,6 +159,7 @@ static const struct usb_device_id ti_id_table_3410[] = { { USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_STEREO_PLUG_ID) }, { USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_STRIP_PORT_ID) }, { USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) }, + { USB_DEVICE(HONEYWELL_VENDOR_ID, HONEYWELL_HGI80_PRODUCT_ID) }, { } /* terminator */ }; @@ -191,6 +192,7 @@ static const struct usb_device_id ti_id_table_combined[] = { { USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_PRODUCT_ID) }, { USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_STRIP_PORT_ID) }, { USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) }, + { USB_DEVICE(HONEYWELL_VENDOR_ID, HONEYWELL_HGI80_PRODUCT_ID) }, { } /* terminator */ }; diff --git a/drivers/usb/serial/ti_usb_3410_5052.h b/drivers/usb/serial/ti_usb_3410_5052.h index 4a2423e84d55..98f35c656c02 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.h +++ b/drivers/usb/serial/ti_usb_3410_5052.h @@ -56,6 +56,10 @@ #define ABBOTT_PRODUCT_ID ABBOTT_STEREO_PLUG_ID #define ABBOTT_STRIP_PORT_ID 0x3420 +/* Honeywell vendor and product IDs */ +#define HONEYWELL_VENDOR_ID 0x10ac +#define HONEYWELL_HGI80_PRODUCT_ID 0x0102 /* Honeywell HGI80 */ + /* Commands */ #define TI_GET_VERSION 0x01 #define TI_GET_PORT_STATUS 0x02 diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c index 48ca9c204354..e69151664436 100644 --- a/drivers/usb/storage/uas.c +++ b/drivers/usb/storage/uas.c @@ -812,7 +812,6 @@ static struct scsi_host_template uas_host_template = { .this_id = -1, .sg_tablesize = SG_NONE, .skip_settle_delay = 1, - .use_blk_tags = 1, }; #define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \ @@ -929,10 +928,6 @@ static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id) if (result) goto set_alt0; - result = scsi_init_shared_tag_map(shost, devinfo->qdepth - 2); - if (result) - goto free_streams; - usb_set_intfdata(intf, shost); result = scsi_add_host(shost, &intf->dev); if (result) diff --git a/drivers/vfio/Kconfig b/drivers/vfio/Kconfig index 850d86ca685b..da6e2ce77495 100644 --- a/drivers/vfio/Kconfig +++ b/drivers/vfio/Kconfig @@ -31,6 +31,21 @@ menuconfig VFIO If you don't know what to do here, say N. +menuconfig VFIO_NOIOMMU + bool "VFIO No-IOMMU support" + depends on VFIO + help + VFIO is built on the ability to isolate devices using the IOMMU. + Only with an IOMMU can userspace access to DMA capable devices be + considered secure. VFIO No-IOMMU mode enables IOMMU groups for + devices without IOMMU backing for the purpose of re-using the VFIO + infrastructure in a non-secure mode. Use of this mode will result + in an unsupportable kernel and will therefore taint the kernel. + Device assignment to virtual machines is also not possible with + this mode since there is no IOMMU to provide DMA translation. + + If you don't know what to do here, say N. + source "drivers/vfio/pci/Kconfig" source "drivers/vfio/platform/Kconfig" source "virt/lib/Kconfig" diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c index 964ad572aaee..32b88bd2c82c 100644 --- a/drivers/vfio/pci/vfio_pci.c +++ b/drivers/vfio/pci/vfio_pci.c @@ -940,13 +940,13 @@ static int vfio_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (pdev->hdr_type != PCI_HEADER_TYPE_NORMAL) return -EINVAL; - group = iommu_group_get(&pdev->dev); + group = vfio_iommu_group_get(&pdev->dev); if (!group) return -EINVAL; vdev = kzalloc(sizeof(*vdev), GFP_KERNEL); if (!vdev) { - iommu_group_put(group); + vfio_iommu_group_put(group, &pdev->dev); return -ENOMEM; } @@ -957,7 +957,7 @@ static int vfio_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) ret = vfio_add_group_dev(&pdev->dev, &vfio_pci_ops, vdev); if (ret) { - iommu_group_put(group); + vfio_iommu_group_put(group, &pdev->dev); kfree(vdev); return ret; } @@ -993,7 +993,7 @@ static void vfio_pci_remove(struct pci_dev *pdev) if (!vdev) return; - iommu_group_put(pdev->dev.iommu_group); + vfio_iommu_group_put(pdev->dev.iommu_group, &pdev->dev); kfree(vdev); if (vfio_pci_is_vga(pdev)) { diff --git a/drivers/vfio/pci/vfio_pci_config.c b/drivers/vfio/pci/vfio_pci_config.c index ff75ca31a199..fe2b470d7ec6 100644 --- a/drivers/vfio/pci/vfio_pci_config.c +++ b/drivers/vfio/pci/vfio_pci_config.c @@ -46,7 +46,7 @@ * 0: Removed from the user visible capability list * FF: Variable length */ -static u8 pci_cap_length[] = { +static const u8 pci_cap_length[PCI_CAP_ID_MAX + 1] = { [PCI_CAP_ID_BASIC] = PCI_STD_HEADER_SIZEOF, /* pci config header */ [PCI_CAP_ID_PM] = PCI_PM_SIZEOF, [PCI_CAP_ID_AGP] = PCI_AGP_SIZEOF, @@ -74,7 +74,7 @@ static u8 pci_cap_length[] = { * 0: Removed or masked from the user visible capabilty list * FF: Variable length */ -static u16 pci_ext_cap_length[] = { +static const u16 pci_ext_cap_length[PCI_EXT_CAP_ID_MAX + 1] = { [PCI_EXT_CAP_ID_ERR] = PCI_ERR_ROOT_COMMAND, [PCI_EXT_CAP_ID_VC] = 0xFF, [PCI_EXT_CAP_ID_DSN] = PCI_EXT_CAP_DSN_SIZEOF, @@ -671,6 +671,73 @@ static int __init init_pci_cap_pm_perm(struct perm_bits *perm) return 0; } +static int vfio_vpd_config_write(struct vfio_pci_device *vdev, int pos, + int count, struct perm_bits *perm, + int offset, __le32 val) +{ + struct pci_dev *pdev = vdev->pdev; + __le16 *paddr = (__le16 *)(vdev->vconfig + pos - offset + PCI_VPD_ADDR); + __le32 *pdata = (__le32 *)(vdev->vconfig + pos - offset + PCI_VPD_DATA); + u16 addr; + u32 data; + + /* + * Write through to emulation. If the write includes the upper byte + * of PCI_VPD_ADDR, then the PCI_VPD_ADDR_F bit is written and we + * have work to do. + */ + count = vfio_default_config_write(vdev, pos, count, perm, offset, val); + if (count < 0 || offset > PCI_VPD_ADDR + 1 || + offset + count <= PCI_VPD_ADDR + 1) + return count; + + addr = le16_to_cpu(*paddr); + + if (addr & PCI_VPD_ADDR_F) { + data = le32_to_cpu(*pdata); + if (pci_write_vpd(pdev, addr & ~PCI_VPD_ADDR_F, 4, &data) != 4) + return count; + } else { + if (pci_read_vpd(pdev, addr, 4, &data) != 4) + return count; + *pdata = cpu_to_le32(data); + } + + /* + * Toggle PCI_VPD_ADDR_F in the emulated PCI_VPD_ADDR register to + * signal completion. If an error occurs above, we assume that not + * toggling this bit will induce a driver timeout. + */ + addr ^= PCI_VPD_ADDR_F; + *paddr = cpu_to_le16(addr); + + return count; +} + +/* Permissions for Vital Product Data capability */ +static int __init init_pci_cap_vpd_perm(struct perm_bits *perm) +{ + if (alloc_perm_bits(perm, pci_cap_length[PCI_CAP_ID_VPD])) + return -ENOMEM; + + perm->writefn = vfio_vpd_config_write; + + /* + * We always virtualize the next field so we can remove + * capabilities from the chain if we want to. + */ + p_setb(perm, PCI_CAP_LIST_NEXT, (u8)ALL_VIRT, NO_WRITE); + + /* + * Both the address and data registers are virtualized to + * enable access through the pci_vpd_read/write functions + */ + p_setw(perm, PCI_VPD_ADDR, (u16)ALL_VIRT, (u16)ALL_WRITE); + p_setd(perm, PCI_VPD_DATA, ALL_VIRT, ALL_WRITE); + + return 0; +} + /* Permissions for PCI-X capability */ static int __init init_pci_cap_pcix_perm(struct perm_bits *perm) { @@ -790,6 +857,7 @@ void vfio_pci_uninit_perm_bits(void) free_perm_bits(&cap_perms[PCI_CAP_ID_BASIC]); free_perm_bits(&cap_perms[PCI_CAP_ID_PM]); + free_perm_bits(&cap_perms[PCI_CAP_ID_VPD]); free_perm_bits(&cap_perms[PCI_CAP_ID_PCIX]); free_perm_bits(&cap_perms[PCI_CAP_ID_EXP]); free_perm_bits(&cap_perms[PCI_CAP_ID_AF]); @@ -807,7 +875,7 @@ int __init vfio_pci_init_perm_bits(void) /* Capabilities */ ret |= init_pci_cap_pm_perm(&cap_perms[PCI_CAP_ID_PM]); - cap_perms[PCI_CAP_ID_VPD].writefn = vfio_raw_config_write; + ret |= init_pci_cap_vpd_perm(&cap_perms[PCI_CAP_ID_VPD]); ret |= init_pci_cap_pcix_perm(&cap_perms[PCI_CAP_ID_PCIX]); cap_perms[PCI_CAP_ID_VNDR].writefn = vfio_raw_config_write; ret |= init_pci_cap_exp_perm(&cap_perms[PCI_CAP_ID_EXP]); diff --git a/drivers/vfio/platform/Makefile b/drivers/vfio/platform/Makefile index 9ce8afe28450..41a6224f5e6b 100644 --- a/drivers/vfio/platform/Makefile +++ b/drivers/vfio/platform/Makefile @@ -1,10 +1,12 @@ - -vfio-platform-y := vfio_platform.o vfio_platform_common.o vfio_platform_irq.o +vfio-platform-base-y := vfio_platform_common.o vfio_platform_irq.o +vfio-platform-y := vfio_platform.o obj-$(CONFIG_VFIO_PLATFORM) += vfio-platform.o +obj-$(CONFIG_VFIO_PLATFORM) += vfio-platform-base.o obj-$(CONFIG_VFIO_PLATFORM) += reset/ vfio-amba-y := vfio_amba.o obj-$(CONFIG_VFIO_AMBA) += vfio-amba.o +obj-$(CONFIG_VFIO_AMBA) += vfio-platform-base.o obj-$(CONFIG_VFIO_AMBA) += reset/ diff --git a/drivers/vfio/platform/reset/Kconfig b/drivers/vfio/platform/reset/Kconfig index 746b96b0003b..70cccc582bee 100644 --- a/drivers/vfio/platform/reset/Kconfig +++ b/drivers/vfio/platform/reset/Kconfig @@ -5,3 +5,11 @@ config VFIO_PLATFORM_CALXEDAXGMAC_RESET Enables the VFIO platform driver to handle reset for Calxeda xgmac If you don't know what to do here, say N. + +config VFIO_PLATFORM_AMDXGBE_RESET + tristate "VFIO support for AMD XGBE reset" + depends on VFIO_PLATFORM + help + Enables the VFIO platform driver to handle reset for AMD XGBE + + If you don't know what to do here, say N. diff --git a/drivers/vfio/platform/reset/Makefile b/drivers/vfio/platform/reset/Makefile index 2a486af9f8fa..93f4e232697b 100644 --- a/drivers/vfio/platform/reset/Makefile +++ b/drivers/vfio/platform/reset/Makefile @@ -1,5 +1,7 @@ vfio-platform-calxedaxgmac-y := vfio_platform_calxedaxgmac.o +vfio-platform-amdxgbe-y := vfio_platform_amdxgbe.o ccflags-y += -Idrivers/vfio/platform obj-$(CONFIG_VFIO_PLATFORM_CALXEDAXGMAC_RESET) += vfio-platform-calxedaxgmac.o +obj-$(CONFIG_VFIO_PLATFORM_AMDXGBE_RESET) += vfio-platform-amdxgbe.o diff --git a/drivers/vfio/platform/reset/vfio_platform_amdxgbe.c b/drivers/vfio/platform/reset/vfio_platform_amdxgbe.c new file mode 100644 index 000000000000..da5356f48d0b --- /dev/null +++ b/drivers/vfio/platform/reset/vfio_platform_amdxgbe.c @@ -0,0 +1,127 @@ +/* + * VFIO platform driver specialized for AMD xgbe reset + * reset code is inherited from AMD xgbe native driver + * + * Copyright (c) 2015 Linaro Ltd. + * www.linaro.org + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/io.h> +#include <uapi/linux/mdio.h> +#include <linux/delay.h> + +#include "vfio_platform_private.h" + +#define DMA_MR 0x3000 +#define MAC_VR 0x0110 +#define DMA_ISR 0x3008 +#define MAC_ISR 0x00b0 +#define PCS_MMD_SELECT 0xff +#define MDIO_AN_INT 0x8002 +#define MDIO_AN_INTMASK 0x8001 + +static unsigned int xmdio_read(void *ioaddr, unsigned int mmd, + unsigned int reg) +{ + unsigned int mmd_address, value; + + mmd_address = (mmd << 16) | ((reg) & 0xffff); + iowrite32(mmd_address >> 8, ioaddr + (PCS_MMD_SELECT << 2)); + value = ioread32(ioaddr + ((mmd_address & 0xff) << 2)); + return value; +} + +static void xmdio_write(void *ioaddr, unsigned int mmd, + unsigned int reg, unsigned int value) +{ + unsigned int mmd_address; + + mmd_address = (mmd << 16) | ((reg) & 0xffff); + iowrite32(mmd_address >> 8, ioaddr + (PCS_MMD_SELECT << 2)); + iowrite32(value, ioaddr + ((mmd_address & 0xff) << 2)); +} + +int vfio_platform_amdxgbe_reset(struct vfio_platform_device *vdev) +{ + struct vfio_platform_region *xgmac_regs = &vdev->regions[0]; + struct vfio_platform_region *xpcs_regs = &vdev->regions[1]; + u32 dma_mr_value, pcs_value, value; + unsigned int count; + + if (!xgmac_regs->ioaddr) { + xgmac_regs->ioaddr = + ioremap_nocache(xgmac_regs->addr, xgmac_regs->size); + if (!xgmac_regs->ioaddr) + return -ENOMEM; + } + if (!xpcs_regs->ioaddr) { + xpcs_regs->ioaddr = + ioremap_nocache(xpcs_regs->addr, xpcs_regs->size); + if (!xpcs_regs->ioaddr) + return -ENOMEM; + } + + /* reset the PHY through MDIO*/ + pcs_value = xmdio_read(xpcs_regs->ioaddr, MDIO_MMD_PCS, MDIO_CTRL1); + pcs_value |= MDIO_CTRL1_RESET; + xmdio_write(xpcs_regs->ioaddr, MDIO_MMD_PCS, MDIO_CTRL1, pcs_value); + + count = 50; + do { + msleep(20); + pcs_value = xmdio_read(xpcs_regs->ioaddr, MDIO_MMD_PCS, + MDIO_CTRL1); + } while ((pcs_value & MDIO_CTRL1_RESET) && --count); + + if (pcs_value & MDIO_CTRL1_RESET) + pr_warn("%s XGBE PHY reset timeout\n", __func__); + + /* disable auto-negotiation */ + value = xmdio_read(xpcs_regs->ioaddr, MDIO_MMD_AN, MDIO_CTRL1); + value &= ~MDIO_AN_CTRL1_ENABLE; + xmdio_write(xpcs_regs->ioaddr, MDIO_MMD_AN, MDIO_CTRL1, value); + + /* disable AN IRQ */ + xmdio_write(xpcs_regs->ioaddr, MDIO_MMD_AN, MDIO_AN_INTMASK, 0); + + /* clear AN IRQ */ + xmdio_write(xpcs_regs->ioaddr, MDIO_MMD_AN, MDIO_AN_INT, 0); + + /* MAC software reset */ + dma_mr_value = ioread32(xgmac_regs->ioaddr + DMA_MR); + dma_mr_value |= 0x1; + iowrite32(dma_mr_value, xgmac_regs->ioaddr + DMA_MR); + + usleep_range(10, 15); + + count = 2000; + while (count-- && (ioread32(xgmac_regs->ioaddr + DMA_MR) & 1)) + usleep_range(500, 600); + + if (!count) + pr_warn("%s MAC SW reset failed\n", __func__); + + return 0; +} + +module_vfio_reset_handler("amd,xgbe-seattle-v1a", vfio_platform_amdxgbe_reset); + +MODULE_VERSION("0.1"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Eric Auger <eric.auger@linaro.org>"); +MODULE_DESCRIPTION("Reset support for AMD xgbe vfio platform device"); diff --git a/drivers/vfio/platform/reset/vfio_platform_calxedaxgmac.c b/drivers/vfio/platform/reset/vfio_platform_calxedaxgmac.c index 619dc7d22082..e3d3d948e661 100644 --- a/drivers/vfio/platform/reset/vfio_platform_calxedaxgmac.c +++ b/drivers/vfio/platform/reset/vfio_platform_calxedaxgmac.c @@ -30,8 +30,6 @@ #define DRIVER_AUTHOR "Eric Auger <eric.auger@linaro.org>" #define DRIVER_DESC "Reset support for Calxeda xgmac vfio platform device" -#define CALXEDAXGMAC_COMPAT "calxeda,hb-xgmac" - /* XGMAC Register definitions */ #define XGMAC_CONTROL 0x00000000 /* MAC Configuration */ @@ -61,24 +59,25 @@ static inline void xgmac_mac_disable(void __iomem *ioaddr) int vfio_platform_calxedaxgmac_reset(struct vfio_platform_device *vdev) { - struct vfio_platform_region reg = vdev->regions[0]; + struct vfio_platform_region *reg = &vdev->regions[0]; - if (!reg.ioaddr) { - reg.ioaddr = - ioremap_nocache(reg.addr, reg.size); - if (!reg.ioaddr) + if (!reg->ioaddr) { + reg->ioaddr = + ioremap_nocache(reg->addr, reg->size); + if (!reg->ioaddr) return -ENOMEM; } /* disable IRQ */ - writel(0, reg.ioaddr + XGMAC_DMA_INTR_ENA); + writel(0, reg->ioaddr + XGMAC_DMA_INTR_ENA); /* Disable the MAC core */ - xgmac_mac_disable(reg.ioaddr); + xgmac_mac_disable(reg->ioaddr); return 0; } -EXPORT_SYMBOL_GPL(vfio_platform_calxedaxgmac_reset); + +module_vfio_reset_handler("calxeda,hb-xgmac", vfio_platform_calxedaxgmac_reset); MODULE_VERSION(DRIVER_VERSION); MODULE_LICENSE("GPL v2"); diff --git a/drivers/vfio/platform/vfio_amba.c b/drivers/vfio/platform/vfio_amba.c index ff0331f72526..a66479bd0edf 100644 --- a/drivers/vfio/platform/vfio_amba.c +++ b/drivers/vfio/platform/vfio_amba.c @@ -67,6 +67,7 @@ static int vfio_amba_probe(struct amba_device *adev, const struct amba_id *id) vdev->flags = VFIO_DEVICE_FLAGS_AMBA; vdev->get_resource = get_amba_resource; vdev->get_irq = get_amba_irq; + vdev->parent_module = THIS_MODULE; ret = vfio_platform_probe_common(vdev, &adev->dev); if (ret) { diff --git a/drivers/vfio/platform/vfio_platform.c b/drivers/vfio/platform/vfio_platform.c index cef645c83996..f1625dcfbb23 100644 --- a/drivers/vfio/platform/vfio_platform.c +++ b/drivers/vfio/platform/vfio_platform.c @@ -65,6 +65,7 @@ static int vfio_platform_probe(struct platform_device *pdev) vdev->flags = VFIO_DEVICE_FLAGS_PLATFORM; vdev->get_resource = get_platform_resource; vdev->get_irq = get_platform_irq; + vdev->parent_module = THIS_MODULE; ret = vfio_platform_probe_common(vdev, &pdev->dev); if (ret) diff --git a/drivers/vfio/platform/vfio_platform_common.c b/drivers/vfio/platform/vfio_platform_common.c index e43efb5e92bf..a1c50d630792 100644 --- a/drivers/vfio/platform/vfio_platform_common.c +++ b/drivers/vfio/platform/vfio_platform_common.c @@ -23,44 +23,50 @@ #include "vfio_platform_private.h" -static DEFINE_MUTEX(driver_lock); +#define DRIVER_VERSION "0.10" +#define DRIVER_AUTHOR "Antonios Motakis <a.motakis@virtualopensystems.com>" +#define DRIVER_DESC "VFIO platform base module" -static const struct vfio_platform_reset_combo reset_lookup_table[] = { - { - .compat = "calxeda,hb-xgmac", - .reset_function_name = "vfio_platform_calxedaxgmac_reset", - .module_name = "vfio-platform-calxedaxgmac", - }, -}; +static LIST_HEAD(reset_list); +static DEFINE_MUTEX(driver_lock); -static void vfio_platform_get_reset(struct vfio_platform_device *vdev, - struct device *dev) +static vfio_platform_reset_fn_t vfio_platform_lookup_reset(const char *compat, + struct module **module) { - const char *compat; - int (*reset)(struct vfio_platform_device *); - int ret, i; - - ret = device_property_read_string(dev, "compatible", &compat); - if (ret) - return; - - for (i = 0 ; i < ARRAY_SIZE(reset_lookup_table); i++) { - if (!strcmp(reset_lookup_table[i].compat, compat)) { - request_module(reset_lookup_table[i].module_name); - reset = __symbol_get( - reset_lookup_table[i].reset_function_name); - if (reset) { - vdev->reset = reset; - return; - } + struct vfio_platform_reset_node *iter; + vfio_platform_reset_fn_t reset_fn = NULL; + + mutex_lock(&driver_lock); + list_for_each_entry(iter, &reset_list, link) { + if (!strcmp(iter->compat, compat) && + try_module_get(iter->owner)) { + *module = iter->owner; + reset_fn = iter->reset; + break; } } + mutex_unlock(&driver_lock); + return reset_fn; +} + +static void vfio_platform_get_reset(struct vfio_platform_device *vdev) +{ + char modname[256]; + + vdev->reset = vfio_platform_lookup_reset(vdev->compat, + &vdev->reset_module); + if (!vdev->reset) { + snprintf(modname, 256, "vfio-reset:%s", vdev->compat); + request_module(modname); + vdev->reset = vfio_platform_lookup_reset(vdev->compat, + &vdev->reset_module); + } } static void vfio_platform_put_reset(struct vfio_platform_device *vdev) { if (vdev->reset) - symbol_put_addr(vdev->reset); + module_put(vdev->reset_module); } static int vfio_platform_regions_init(struct vfio_platform_device *vdev) @@ -138,15 +144,19 @@ static void vfio_platform_release(void *device_data) mutex_lock(&driver_lock); if (!(--vdev->refcnt)) { - if (vdev->reset) + if (vdev->reset) { + dev_info(vdev->device, "reset\n"); vdev->reset(vdev); + } else { + dev_warn(vdev->device, "no reset function found!\n"); + } vfio_platform_regions_cleanup(vdev); vfio_platform_irq_cleanup(vdev); } mutex_unlock(&driver_lock); - module_put(THIS_MODULE); + module_put(vdev->parent_module); } static int vfio_platform_open(void *device_data) @@ -154,7 +164,7 @@ static int vfio_platform_open(void *device_data) struct vfio_platform_device *vdev = device_data; int ret; - if (!try_module_get(THIS_MODULE)) + if (!try_module_get(vdev->parent_module)) return -ENODEV; mutex_lock(&driver_lock); @@ -168,8 +178,12 @@ static int vfio_platform_open(void *device_data) if (ret) goto err_irq; - if (vdev->reset) + if (vdev->reset) { + dev_info(vdev->device, "reset\n"); vdev->reset(vdev); + } else { + dev_warn(vdev->device, "no reset function found!\n"); + } } vdev->refcnt++; @@ -307,17 +321,17 @@ static long vfio_platform_ioctl(void *device_data, return -ENOTTY; } -static ssize_t vfio_platform_read_mmio(struct vfio_platform_region reg, +static ssize_t vfio_platform_read_mmio(struct vfio_platform_region *reg, char __user *buf, size_t count, loff_t off) { unsigned int done = 0; - if (!reg.ioaddr) { - reg.ioaddr = - ioremap_nocache(reg.addr, reg.size); + if (!reg->ioaddr) { + reg->ioaddr = + ioremap_nocache(reg->addr, reg->size); - if (!reg.ioaddr) + if (!reg->ioaddr) return -ENOMEM; } @@ -327,7 +341,7 @@ static ssize_t vfio_platform_read_mmio(struct vfio_platform_region reg, if (count >= 4 && !(off % 4)) { u32 val; - val = ioread32(reg.ioaddr + off); + val = ioread32(reg->ioaddr + off); if (copy_to_user(buf, &val, 4)) goto err; @@ -335,7 +349,7 @@ static ssize_t vfio_platform_read_mmio(struct vfio_platform_region reg, } else if (count >= 2 && !(off % 2)) { u16 val; - val = ioread16(reg.ioaddr + off); + val = ioread16(reg->ioaddr + off); if (copy_to_user(buf, &val, 2)) goto err; @@ -343,7 +357,7 @@ static ssize_t vfio_platform_read_mmio(struct vfio_platform_region reg, } else { u8 val; - val = ioread8(reg.ioaddr + off); + val = ioread8(reg->ioaddr + off); if (copy_to_user(buf, &val, 1)) goto err; @@ -376,7 +390,7 @@ static ssize_t vfio_platform_read(void *device_data, char __user *buf, return -EINVAL; if (vdev->regions[index].type & VFIO_PLATFORM_REGION_TYPE_MMIO) - return vfio_platform_read_mmio(vdev->regions[index], + return vfio_platform_read_mmio(&vdev->regions[index], buf, count, off); else if (vdev->regions[index].type & VFIO_PLATFORM_REGION_TYPE_PIO) return -EINVAL; /* not implemented */ @@ -384,17 +398,17 @@ static ssize_t vfio_platform_read(void *device_data, char __user *buf, return -EINVAL; } -static ssize_t vfio_platform_write_mmio(struct vfio_platform_region reg, +static ssize_t vfio_platform_write_mmio(struct vfio_platform_region *reg, const char __user *buf, size_t count, loff_t off) { unsigned int done = 0; - if (!reg.ioaddr) { - reg.ioaddr = - ioremap_nocache(reg.addr, reg.size); + if (!reg->ioaddr) { + reg->ioaddr = + ioremap_nocache(reg->addr, reg->size); - if (!reg.ioaddr) + if (!reg->ioaddr) return -ENOMEM; } @@ -406,7 +420,7 @@ static ssize_t vfio_platform_write_mmio(struct vfio_platform_region reg, if (copy_from_user(&val, buf, 4)) goto err; - iowrite32(val, reg.ioaddr + off); + iowrite32(val, reg->ioaddr + off); filled = 4; } else if (count >= 2 && !(off % 2)) { @@ -414,7 +428,7 @@ static ssize_t vfio_platform_write_mmio(struct vfio_platform_region reg, if (copy_from_user(&val, buf, 2)) goto err; - iowrite16(val, reg.ioaddr + off); + iowrite16(val, reg->ioaddr + off); filled = 2; } else { @@ -422,7 +436,7 @@ static ssize_t vfio_platform_write_mmio(struct vfio_platform_region reg, if (copy_from_user(&val, buf, 1)) goto err; - iowrite8(val, reg.ioaddr + off); + iowrite8(val, reg->ioaddr + off); filled = 1; } @@ -452,7 +466,7 @@ static ssize_t vfio_platform_write(void *device_data, const char __user *buf, return -EINVAL; if (vdev->regions[index].type & VFIO_PLATFORM_REGION_TYPE_MMIO) - return vfio_platform_write_mmio(vdev->regions[index], + return vfio_platform_write_mmio(&vdev->regions[index], buf, count, off); else if (vdev->regions[index].type & VFIO_PLATFORM_REGION_TYPE_PIO) return -EINVAL; /* not implemented */ @@ -539,6 +553,14 @@ int vfio_platform_probe_common(struct vfio_platform_device *vdev, if (!vdev) return -EINVAL; + ret = device_property_read_string(dev, "compatible", &vdev->compat); + if (ret) { + pr_err("VFIO: cannot retrieve compat for %s\n", vdev->name); + return -EINVAL; + } + + vdev->device = dev; + group = iommu_group_get(dev); if (!group) { pr_err("VFIO: No IOMMU group for device %s\n", vdev->name); @@ -551,7 +573,7 @@ int vfio_platform_probe_common(struct vfio_platform_device *vdev, return ret; } - vfio_platform_get_reset(vdev, dev); + vfio_platform_get_reset(vdev); mutex_init(&vdev->igate); @@ -573,3 +595,34 @@ struct vfio_platform_device *vfio_platform_remove_common(struct device *dev) return vdev; } EXPORT_SYMBOL_GPL(vfio_platform_remove_common); + +void __vfio_platform_register_reset(struct vfio_platform_reset_node *node) +{ + mutex_lock(&driver_lock); + list_add(&node->link, &reset_list); + mutex_unlock(&driver_lock); +} +EXPORT_SYMBOL_GPL(__vfio_platform_register_reset); + +void vfio_platform_unregister_reset(const char *compat, + vfio_platform_reset_fn_t fn) +{ + struct vfio_platform_reset_node *iter, *temp; + + mutex_lock(&driver_lock); + list_for_each_entry_safe(iter, temp, &reset_list, link) { + if (!strcmp(iter->compat, compat) && (iter->reset == fn)) { + list_del(&iter->link); + break; + } + } + + mutex_unlock(&driver_lock); + +} +EXPORT_SYMBOL_GPL(vfio_platform_unregister_reset); + +MODULE_VERSION(DRIVER_VERSION); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/drivers/vfio/platform/vfio_platform_irq.c b/drivers/vfio/platform/vfio_platform_irq.c index 88bba57b30a8..46d4750f43a8 100644 --- a/drivers/vfio/platform/vfio_platform_irq.c +++ b/drivers/vfio/platform/vfio_platform_irq.c @@ -185,6 +185,7 @@ static int vfio_set_trigger(struct vfio_platform_device *vdev, int index, int ret; if (irq->trigger) { + irq_clear_status_flags(irq->hwirq, IRQ_NOAUTOEN); free_irq(irq->hwirq, irq); kfree(irq->name); eventfd_ctx_put(irq->trigger); diff --git a/drivers/vfio/platform/vfio_platform_private.h b/drivers/vfio/platform/vfio_platform_private.h index 1c9b3d59543c..42816dd280cb 100644 --- a/drivers/vfio/platform/vfio_platform_private.h +++ b/drivers/vfio/platform/vfio_platform_private.h @@ -56,6 +56,10 @@ struct vfio_platform_device { u32 num_irqs; int refcnt; struct mutex igate; + struct module *parent_module; + const char *compat; + struct module *reset_module; + struct device *device; /* * These fields should be filled by the bus specific binder @@ -70,10 +74,13 @@ struct vfio_platform_device { int (*reset)(struct vfio_platform_device *vdev); }; -struct vfio_platform_reset_combo { - const char *compat; - const char *reset_function_name; - const char *module_name; +typedef int (*vfio_platform_reset_fn_t)(struct vfio_platform_device *vdev); + +struct vfio_platform_reset_node { + struct list_head link; + char *compat; + struct module *owner; + vfio_platform_reset_fn_t reset; }; extern int vfio_platform_probe_common(struct vfio_platform_device *vdev, @@ -89,4 +96,29 @@ extern int vfio_platform_set_irqs_ioctl(struct vfio_platform_device *vdev, unsigned start, unsigned count, void *data); +extern void __vfio_platform_register_reset(struct vfio_platform_reset_node *n); +extern void vfio_platform_unregister_reset(const char *compat, + vfio_platform_reset_fn_t fn); +#define vfio_platform_register_reset(__compat, __reset) \ +static struct vfio_platform_reset_node __reset ## _node = { \ + .owner = THIS_MODULE, \ + .compat = __compat, \ + .reset = __reset, \ +}; \ +__vfio_platform_register_reset(&__reset ## _node) + +#define module_vfio_reset_handler(compat, reset) \ +MODULE_ALIAS("vfio-reset:" compat); \ +static int __init reset ## _module_init(void) \ +{ \ + vfio_platform_register_reset(compat, reset); \ + return 0; \ +}; \ +static void __exit reset ## _module_exit(void) \ +{ \ + vfio_platform_unregister_reset(compat, reset); \ +}; \ +module_init(reset ## _module_init); \ +module_exit(reset ## _module_exit) + #endif /* VFIO_PLATFORM_PRIVATE_H */ diff --git a/drivers/vfio/vfio.c b/drivers/vfio/vfio.c index 563c510f285c..de632da2e22f 100644 --- a/drivers/vfio/vfio.c +++ b/drivers/vfio/vfio.c @@ -25,6 +25,7 @@ #include <linux/miscdevice.h> #include <linux/module.h> #include <linux/mutex.h> +#include <linux/pci.h> #include <linux/rwsem.h> #include <linux/sched.h> #include <linux/slab.h> @@ -61,6 +62,7 @@ struct vfio_container { struct rw_semaphore group_lock; struct vfio_iommu_driver *iommu_driver; void *iommu_data; + bool noiommu; }; struct vfio_unbound_dev { @@ -83,6 +85,7 @@ struct vfio_group { struct list_head unbound_list; struct mutex unbound_lock; atomic_t opened; + bool noiommu; }; struct vfio_device { @@ -94,6 +97,147 @@ struct vfio_device { void *device_data; }; +#ifdef CONFIG_VFIO_NOIOMMU +static bool noiommu __read_mostly; +module_param_named(enable_unsafe_noiommu_support, + noiommu, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(enable_unsafe_noiommu_mode, "Enable UNSAFE, no-IOMMU mode. This mode provides no device isolation, no DMA translation, no host kernel protection, cannot be used for device assignment to virtual machines, requires RAWIO permissions, and will taint the kernel. If you do not know what this is for, step away. (default: false)"); +#endif + +/* + * vfio_iommu_group_{get,put} are only intended for VFIO bus driver probe + * and remove functions, any use cases other than acquiring the first + * reference for the purpose of calling vfio_add_group_dev() or removing + * that symmetric reference after vfio_del_group_dev() should use the raw + * iommu_group_{get,put} functions. In particular, vfio_iommu_group_put() + * removes the device from the dummy group and cannot be nested. + */ +struct iommu_group *vfio_iommu_group_get(struct device *dev) +{ + struct iommu_group *group; + int __maybe_unused ret; + + group = iommu_group_get(dev); + +#ifdef CONFIG_VFIO_NOIOMMU + /* + * With noiommu enabled, an IOMMU group will be created for a device + * that doesn't already have one and doesn't have an iommu_ops on their + * bus. We use iommu_present() again in the main code to detect these + * fake groups. + */ + if (group || !noiommu || iommu_present(dev->bus)) + return group; + + group = iommu_group_alloc(); + if (IS_ERR(group)) + return NULL; + + iommu_group_set_name(group, "vfio-noiommu"); + ret = iommu_group_add_device(group, dev); + iommu_group_put(group); + if (ret) + return NULL; + + /* + * Where to taint? At this point we've added an IOMMU group for a + * device that is not backed by iommu_ops, therefore any iommu_ + * callback using iommu_ops can legitimately Oops. So, while we may + * be about to give a DMA capable device to a user without IOMMU + * protection, which is clearly taint-worthy, let's go ahead and do + * it here. + */ + add_taint(TAINT_USER, LOCKDEP_STILL_OK); + dev_warn(dev, "Adding kernel taint for vfio-noiommu group on device\n"); +#endif + + return group; +} +EXPORT_SYMBOL_GPL(vfio_iommu_group_get); + +void vfio_iommu_group_put(struct iommu_group *group, struct device *dev) +{ +#ifdef CONFIG_VFIO_NOIOMMU + if (!iommu_present(dev->bus)) + iommu_group_remove_device(dev); +#endif + + iommu_group_put(group); +} +EXPORT_SYMBOL_GPL(vfio_iommu_group_put); + +#ifdef CONFIG_VFIO_NOIOMMU +static void *vfio_noiommu_open(unsigned long arg) +{ + if (arg != VFIO_NOIOMMU_IOMMU) + return ERR_PTR(-EINVAL); + if (!capable(CAP_SYS_RAWIO)) + return ERR_PTR(-EPERM); + + return NULL; +} + +static void vfio_noiommu_release(void *iommu_data) +{ +} + +static long vfio_noiommu_ioctl(void *iommu_data, + unsigned int cmd, unsigned long arg) +{ + if (cmd == VFIO_CHECK_EXTENSION) + return arg == VFIO_NOIOMMU_IOMMU ? 1 : 0; + + return -ENOTTY; +} + +static int vfio_iommu_present(struct device *dev, void *unused) +{ + return iommu_present(dev->bus) ? 1 : 0; +} + +static int vfio_noiommu_attach_group(void *iommu_data, + struct iommu_group *iommu_group) +{ + return iommu_group_for_each_dev(iommu_group, NULL, + vfio_iommu_present) ? -EINVAL : 0; +} + +static void vfio_noiommu_detach_group(void *iommu_data, + struct iommu_group *iommu_group) +{ +} + +static struct vfio_iommu_driver_ops vfio_noiommu_ops = { + .name = "vfio-noiommu", + .owner = THIS_MODULE, + .open = vfio_noiommu_open, + .release = vfio_noiommu_release, + .ioctl = vfio_noiommu_ioctl, + .attach_group = vfio_noiommu_attach_group, + .detach_group = vfio_noiommu_detach_group, +}; + +static struct vfio_iommu_driver vfio_noiommu_driver = { + .ops = &vfio_noiommu_ops, +}; + +/* + * Wrap IOMMU drivers, the noiommu driver is the one and only driver for + * noiommu groups (and thus containers) and not available for normal groups. + */ +#define vfio_for_each_iommu_driver(con, pos) \ + for (pos = con->noiommu ? &vfio_noiommu_driver : \ + list_first_entry(&vfio.iommu_drivers_list, \ + struct vfio_iommu_driver, vfio_next); \ + (con->noiommu ? pos != NULL : \ + &pos->vfio_next != &vfio.iommu_drivers_list); \ + pos = con->noiommu ? NULL : list_next_entry(pos, vfio_next)) +#else +#define vfio_for_each_iommu_driver(con, pos) \ + list_for_each_entry(pos, &vfio.iommu_drivers_list, vfio_next) +#endif + + /** * IOMMU driver registration */ @@ -198,7 +342,8 @@ static void vfio_group_unlock_and_free(struct vfio_group *group) /** * Group objects - create, release, get, put, search */ -static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group) +static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group, + bool noiommu) { struct vfio_group *group, *tmp; struct device *dev; @@ -216,6 +361,7 @@ static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group) atomic_set(&group->container_users, 0); atomic_set(&group->opened, 0); group->iommu_group = iommu_group; + group->noiommu = noiommu; group->nb.notifier_call = vfio_iommu_group_notifier; @@ -251,7 +397,8 @@ static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group) dev = device_create(vfio.class, NULL, MKDEV(MAJOR(vfio.group_devt), minor), - group, "%d", iommu_group_id(iommu_group)); + group, "%s%d", noiommu ? "noiommu-" : "", + iommu_group_id(iommu_group)); if (IS_ERR(dev)) { vfio_free_group_minor(minor); vfio_group_unlock_and_free(group); @@ -438,16 +585,33 @@ static struct vfio_device *vfio_group_get_device(struct vfio_group *group, } /* - * Whitelist some drivers that we know are safe (no dma) or just sit on - * a device. It's not always practical to leave a device within a group - * driverless as it could get re-bound to something unsafe. + * Some drivers, like pci-stub, are only used to prevent other drivers from + * claiming a device and are therefore perfectly legitimate for a user owned + * group. The pci-stub driver has no dependencies on DMA or the IOVA mapping + * of the device, but it does prevent the user from having direct access to + * the device, which is useful in some circumstances. + * + * We also assume that we can include PCI interconnect devices, ie. bridges. + * IOMMU grouping on PCI necessitates that if we lack isolation on a bridge + * then all of the downstream devices will be part of the same IOMMU group as + * the bridge. Thus, if placing the bridge into the user owned IOVA space + * breaks anything, it only does so for user owned devices downstream. Note + * that error notification via MSI can be affected for platforms that handle + * MSI within the same IOVA space as DMA. */ -static const char * const vfio_driver_whitelist[] = { "pci-stub", "pcieport" }; +static const char * const vfio_driver_whitelist[] = { "pci-stub" }; -static bool vfio_whitelisted_driver(struct device_driver *drv) +static bool vfio_dev_whitelisted(struct device *dev, struct device_driver *drv) { int i; + if (dev_is_pci(dev)) { + struct pci_dev *pdev = to_pci_dev(dev); + + if (pdev->hdr_type != PCI_HEADER_TYPE_NORMAL) + return true; + } + for (i = 0; i < ARRAY_SIZE(vfio_driver_whitelist); i++) { if (!strcmp(drv->name, vfio_driver_whitelist[i])) return true; @@ -462,6 +626,7 @@ static bool vfio_whitelisted_driver(struct device_driver *drv) * - driver-less * - bound to a vfio driver * - bound to a whitelisted driver + * - a PCI interconnect device * * We use two methods to determine whether a device is bound to a vfio * driver. The first is to test whether the device exists in the vfio @@ -486,7 +651,7 @@ static int vfio_dev_viable(struct device *dev, void *data) } mutex_unlock(&group->unbound_lock); - if (!ret || !drv || vfio_whitelisted_driver(drv)) + if (!ret || !drv || vfio_dev_whitelisted(dev, drv)) return 0; device = vfio_group_get_device(group, dev); @@ -621,7 +786,8 @@ int vfio_add_group_dev(struct device *dev, group = vfio_group_get_from_iommu(iommu_group); if (!group) { - group = vfio_create_group(iommu_group); + group = vfio_create_group(iommu_group, + !iommu_present(dev->bus)); if (IS_ERR(group)) { iommu_group_put(iommu_group); return PTR_ERR(group); @@ -692,11 +858,12 @@ EXPORT_SYMBOL_GPL(vfio_device_get_from_dev); static struct vfio_device *vfio_device_get_from_name(struct vfio_group *group, char *buf) { - struct vfio_device *device; + struct vfio_device *it, *device = NULL; mutex_lock(&group->device_lock); - list_for_each_entry(device, &group->device_list, group_next) { - if (!strcmp(dev_name(device->dev), buf)) { + list_for_each_entry(it, &group->device_list, group_next) { + if (!strcmp(dev_name(it->dev), buf)) { + device = it; vfio_device_get(device); break; } @@ -832,8 +999,7 @@ static long vfio_ioctl_check_extension(struct vfio_container *container, */ if (!driver) { mutex_lock(&vfio.iommu_drivers_lock); - list_for_each_entry(driver, &vfio.iommu_drivers_list, - vfio_next) { + vfio_for_each_iommu_driver(container, driver) { if (!try_module_get(driver->ops->owner)) continue; @@ -902,7 +1068,7 @@ static long vfio_ioctl_set_iommu(struct vfio_container *container, } mutex_lock(&vfio.iommu_drivers_lock); - list_for_each_entry(driver, &vfio.iommu_drivers_list, vfio_next) { + vfio_for_each_iommu_driver(container, driver) { void *data; if (!try_module_get(driver->ops->owner)) @@ -1167,6 +1333,9 @@ static int vfio_group_set_container(struct vfio_group *group, int container_fd) if (atomic_read(&group->container_users)) return -EINVAL; + if (group->noiommu && !capable(CAP_SYS_RAWIO)) + return -EPERM; + f = fdget(container_fd); if (!f.file) return -EBADF; @@ -1182,6 +1351,13 @@ static int vfio_group_set_container(struct vfio_group *group, int container_fd) down_write(&container->group_lock); + /* Real groups and fake groups cannot mix */ + if (!list_empty(&container->group_list) && + container->noiommu != group->noiommu) { + ret = -EPERM; + goto unlock_out; + } + driver = container->iommu_driver; if (driver) { ret = driver->ops->attach_group(container->iommu_data, @@ -1191,6 +1367,7 @@ static int vfio_group_set_container(struct vfio_group *group, int container_fd) } group->container = container; + container->noiommu = group->noiommu; list_add(&group->container_next, &container->group_list); /* Get a reference on the container and mark a user within the group */ @@ -1221,6 +1398,9 @@ static int vfio_group_get_device_fd(struct vfio_group *group, char *buf) !group->container->iommu_driver || !vfio_group_viable(group)) return -EINVAL; + if (group->noiommu && !capable(CAP_SYS_RAWIO)) + return -EPERM; + device = vfio_device_get_from_name(group, buf); if (!device) return -ENODEV; @@ -1263,6 +1443,10 @@ static int vfio_group_get_device_fd(struct vfio_group *group, char *buf) fd_install(ret, filep); + if (group->noiommu) + dev_warn(device->dev, "vfio-noiommu device opened by user " + "(%s:%d)\n", current->comm, task_pid_nr(current)); + return ret; } @@ -1351,6 +1535,11 @@ static int vfio_group_fops_open(struct inode *inode, struct file *filep) if (!group) return -ENODEV; + if (group->noiommu && !capable(CAP_SYS_RAWIO)) { + vfio_group_put(group); + return -EPERM; + } + /* Do we need multiple instances of the group open? Seems not. */ opened = atomic_cmpxchg(&group->opened, 0, 1); if (opened) { @@ -1513,6 +1702,11 @@ struct vfio_group *vfio_group_get_external_user(struct file *filep) if (!atomic_inc_not_zero(&group->container_users)) return ERR_PTR(-EINVAL); + if (group->noiommu) { + atomic_dec(&group->container_users); + return ERR_PTR(-EPERM); + } + if (!group->container->iommu_driver || !vfio_group_viable(group)) { atomic_dec(&group->container_users); diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c index 57d8c37a002b..59d47cb638d5 100644 --- a/drivers/vfio/vfio_iommu_type1.c +++ b/drivers/vfio/vfio_iommu_type1.c @@ -403,13 +403,26 @@ static void vfio_remove_dma(struct vfio_iommu *iommu, struct vfio_dma *dma) static unsigned long vfio_pgsize_bitmap(struct vfio_iommu *iommu) { struct vfio_domain *domain; - unsigned long bitmap = PAGE_MASK; + unsigned long bitmap = ULONG_MAX; mutex_lock(&iommu->lock); list_for_each_entry(domain, &iommu->domain_list, next) bitmap &= domain->domain->ops->pgsize_bitmap; mutex_unlock(&iommu->lock); + /* + * In case the IOMMU supports page sizes smaller than PAGE_SIZE + * we pretend PAGE_SIZE is supported and hide sub-PAGE_SIZE sizes. + * That way the user will be able to map/unmap buffers whose size/ + * start address is aligned with PAGE_SIZE. Pinning code uses that + * granularity while iommu driver can use the sub-PAGE_SIZE size + * to map the buffer. + */ + if (bitmap & ~PAGE_MASK) { + bitmap &= PAGE_MASK; + bitmap |= PAGE_SIZE; + } + return bitmap; } diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index e25a23692822..29cfc57d496e 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -42,8 +42,6 @@ #include <scsi/scsi_proto.h> #include <target/target_core_base.h> #include <target/target_core_fabric.h> -#include <target/target_core_fabric_configfs.h> -#include <target/configfs_macros.h> #include <linux/vhost.h> #include <linux/virtio_scsi.h> #include <linux/llist.h> @@ -1684,11 +1682,10 @@ static void vhost_scsi_free_cmd_map_res(struct vhost_scsi_nexus *nexus, } } -static ssize_t vhost_scsi_tpg_attrib_store_fabric_prot_type( - struct se_portal_group *se_tpg, - const char *page, - size_t count) +static ssize_t vhost_scsi_tpg_attrib_fabric_prot_type_store( + struct config_item *item, const char *page, size_t count) { + struct se_portal_group *se_tpg = attrib_to_tpg(item); struct vhost_scsi_tpg *tpg = container_of(se_tpg, struct vhost_scsi_tpg, se_tpg); unsigned long val; @@ -1707,19 +1704,20 @@ static ssize_t vhost_scsi_tpg_attrib_store_fabric_prot_type( return count; } -static ssize_t vhost_scsi_tpg_attrib_show_fabric_prot_type( - struct se_portal_group *se_tpg, - char *page) +static ssize_t vhost_scsi_tpg_attrib_fabric_prot_type_show( + struct config_item *item, char *page) { + struct se_portal_group *se_tpg = attrib_to_tpg(item); struct vhost_scsi_tpg *tpg = container_of(se_tpg, struct vhost_scsi_tpg, se_tpg); return sprintf(page, "%d\n", tpg->tv_fabric_prot_type); } -TF_TPG_ATTRIB_ATTR(vhost_scsi, fabric_prot_type, S_IRUGO | S_IWUSR); + +CONFIGFS_ATTR(vhost_scsi_tpg_attrib_, fabric_prot_type); static struct configfs_attribute *vhost_scsi_tpg_attrib_attrs[] = { - &vhost_scsi_tpg_attrib_fabric_prot_type.attr, + &vhost_scsi_tpg_attrib_attr_fabric_prot_type, NULL, }; @@ -1867,9 +1865,9 @@ static int vhost_scsi_drop_nexus(struct vhost_scsi_tpg *tpg) return 0; } -static ssize_t vhost_scsi_tpg_show_nexus(struct se_portal_group *se_tpg, - char *page) +static ssize_t vhost_scsi_tpg_nexus_show(struct config_item *item, char *page) { + struct se_portal_group *se_tpg = to_tpg(item); struct vhost_scsi_tpg *tpg = container_of(se_tpg, struct vhost_scsi_tpg, se_tpg); struct vhost_scsi_nexus *tv_nexus; @@ -1888,10 +1886,10 @@ static ssize_t vhost_scsi_tpg_show_nexus(struct se_portal_group *se_tpg, return ret; } -static ssize_t vhost_scsi_tpg_store_nexus(struct se_portal_group *se_tpg, - const char *page, - size_t count) +static ssize_t vhost_scsi_tpg_nexus_store(struct config_item *item, + const char *page, size_t count) { + struct se_portal_group *se_tpg = to_tpg(item); struct vhost_scsi_tpg *tpg = container_of(se_tpg, struct vhost_scsi_tpg, se_tpg); struct vhost_scsi_tport *tport_wwn = tpg->tport; @@ -1966,10 +1964,10 @@ check_newline: return count; } -TF_TPG_BASE_ATTR(vhost_scsi, nexus, S_IRUGO | S_IWUSR); +CONFIGFS_ATTR(vhost_scsi_tpg_, nexus); static struct configfs_attribute *vhost_scsi_tpg_attrs[] = { - &vhost_scsi_tpg_nexus.attr, + &vhost_scsi_tpg_attr_nexus, NULL, }; @@ -2105,18 +2103,17 @@ static void vhost_scsi_drop_tport(struct se_wwn *wwn) } static ssize_t -vhost_scsi_wwn_show_attr_version(struct target_fabric_configfs *tf, - char *page) +vhost_scsi_wwn_version_show(struct config_item *item, char *page) { return sprintf(page, "TCM_VHOST fabric module %s on %s/%s" "on "UTS_RELEASE"\n", VHOST_SCSI_VERSION, utsname()->sysname, utsname()->machine); } -TF_WWN_ATTR_RO(vhost_scsi, version); +CONFIGFS_ATTR_RO(vhost_scsi_wwn_, version); static struct configfs_attribute *vhost_scsi_wwn_attrs[] = { - &vhost_scsi_wwn_version.attr, + &vhost_scsi_wwn_attr_version, NULL, }; diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c index 9eeefd7cad41..43bcae852546 100644 --- a/drivers/xen/xen-scsiback.c +++ b/drivers/xen/xen-scsiback.c @@ -53,7 +53,6 @@ #include <target/target_core_base.h> #include <target/target_core_fabric.h> -#include <target/target_core_fabric_configfs.h> #include <asm/hypervisor.h> @@ -1438,9 +1437,10 @@ static void scsiback_aborted_task(struct se_cmd *se_cmd) { } -static ssize_t scsiback_tpg_param_show_alias(struct se_portal_group *se_tpg, +static ssize_t scsiback_tpg_param_alias_show(struct config_item *item, char *page) { + struct se_portal_group *se_tpg = param_to_tpg(item); struct scsiback_tpg *tpg = container_of(se_tpg, struct scsiback_tpg, se_tpg); ssize_t rb; @@ -1452,9 +1452,10 @@ static ssize_t scsiback_tpg_param_show_alias(struct se_portal_group *se_tpg, return rb; } -static ssize_t scsiback_tpg_param_store_alias(struct se_portal_group *se_tpg, +static ssize_t scsiback_tpg_param_alias_store(struct config_item *item, const char *page, size_t count) { + struct se_portal_group *se_tpg = param_to_tpg(item); struct scsiback_tpg *tpg = container_of(se_tpg, struct scsiback_tpg, se_tpg); int len; @@ -1474,10 +1475,10 @@ static ssize_t scsiback_tpg_param_store_alias(struct se_portal_group *se_tpg, return count; } -TF_TPG_PARAM_ATTR(scsiback, alias, S_IRUGO | S_IWUSR); +CONFIGFS_ATTR(scsiback_tpg_param_, alias); static struct configfs_attribute *scsiback_param_attrs[] = { - &scsiback_tpg_param_alias.attr, + &scsiback_tpg_param_attr_alias, NULL, }; @@ -1585,9 +1586,9 @@ static int scsiback_drop_nexus(struct scsiback_tpg *tpg) return 0; } -static ssize_t scsiback_tpg_show_nexus(struct se_portal_group *se_tpg, - char *page) +static ssize_t scsiback_tpg_nexus_show(struct config_item *item, char *page) { + struct se_portal_group *se_tpg = to_tpg(item); struct scsiback_tpg *tpg = container_of(se_tpg, struct scsiback_tpg, se_tpg); struct scsiback_nexus *tv_nexus; @@ -1606,10 +1607,10 @@ static ssize_t scsiback_tpg_show_nexus(struct se_portal_group *se_tpg, return ret; } -static ssize_t scsiback_tpg_store_nexus(struct se_portal_group *se_tpg, - const char *page, - size_t count) +static ssize_t scsiback_tpg_nexus_store(struct config_item *item, + const char *page, size_t count) { + struct se_portal_group *se_tpg = to_tpg(item); struct scsiback_tpg *tpg = container_of(se_tpg, struct scsiback_tpg, se_tpg); struct scsiback_tport *tport_wwn = tpg->tport; @@ -1681,26 +1682,25 @@ check_newline: return count; } -TF_TPG_BASE_ATTR(scsiback, nexus, S_IRUGO | S_IWUSR); +CONFIGFS_ATTR(scsiback_tpg_, nexus); static struct configfs_attribute *scsiback_tpg_attrs[] = { - &scsiback_tpg_nexus.attr, + &scsiback_tpg_attr_nexus, NULL, }; static ssize_t -scsiback_wwn_show_attr_version(struct target_fabric_configfs *tf, - char *page) +scsiback_wwn_version_show(struct config_item *item, char *page) { return sprintf(page, "xen-pvscsi fabric module %s on %s/%s on " UTS_RELEASE"\n", VSCSI_VERSION, utsname()->sysname, utsname()->machine); } -TF_WWN_ATTR_RO(scsiback, version); +CONFIGFS_ATTR_RO(scsiback_wwn_, version); static struct configfs_attribute *scsiback_wwn_attrs[] = { - &scsiback_wwn_version.attr, + &scsiback_wwn_attr_version, NULL, }; |