From 303694eeee5eacad5b84105a15afd9e351e1891b Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 21 Jun 2012 23:41:51 -0700 Subject: [SCSI] libsas: suspend / resume support libsas power management routines to suspend and recover the sas domain based on a model where the lldd is allowed and expected to be "forgetful". sas_suspend_ha - disable event processing allowing the lldd to take down links without concern for causing hotplug events. Regardless of whether the lldd actually posts link down messages libsas notifies the lldd that all domain_devices are gone. sas_prep_resume_ha - on the way back up before the lldd starts link training clean out any spurious events that were generated on the way down, and re-enable event processing sas_resume_ha - after the lldd has started and decided that all phys have posted link-up events this routine is called to let libsas start it's own timeout of any phys that did not resume. After the timeout an lldd can cancel the phy teardown by posting a link-up event. Storage for ex_change_count (u16) and phy_change_count (u8) are changed to int so they can be set to -1 to indicate 'invalidated'. Signed-off-by: Dan Williams Reviewed-by: Jacek Danecki Tested-by: Maciej Patelczyk Acked-by: Alan Stern Signed-off-by: James Bottomley --- include/scsi/libsas.h | 20 +++++++++++++++----- include/scsi/sas_ata.h | 10 ++++++++++ 2 files changed, 25 insertions(+), 5 deletions(-) (limited to 'include/scsi') diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h index ae33706afeb0..ef937b56f9b5 100644 --- a/include/scsi/libsas.h +++ b/include/scsi/libsas.h @@ -79,7 +79,8 @@ enum phy_event { PHYE_OOB_DONE = 1, PHYE_OOB_ERROR = 2, PHYE_SPINUP_HOLD = 3, /* hot plug SATA, no COMWAKE sent */ - PHY_NUM_EVENTS = 4, + PHYE_RESUME_TIMEOUT = 4, + PHY_NUM_EVENTS = 5, }; enum discover_event { @@ -87,8 +88,10 @@ enum discover_event { DISCE_REVALIDATE_DOMAIN = 1, DISCE_PORT_GONE = 2, DISCE_PROBE = 3, - DISCE_DESTRUCT = 4, - DISC_NUM_EVENTS = 5, + DISCE_SUSPEND = 4, + DISCE_RESUME = 5, + DISCE_DESTRUCT = 6, + DISC_NUM_EVENTS = 7, }; /* ---------- Expander Devices ---------- */ @@ -128,7 +131,7 @@ struct ex_phy { u8 attached_sas_addr[SAS_ADDR_SIZE]; u8 attached_phy_id; - u8 phy_change_count; + int phy_change_count; enum routing_attribute routing_attr; u8 virtual:1; @@ -141,7 +144,7 @@ struct ex_phy { struct expander_device { struct list_head children; - u16 ex_change_count; + int ex_change_count; u16 max_route_indexes; u8 num_phys; @@ -169,6 +172,7 @@ struct sata_device { enum ata_command_set command_set; struct smp_resp rps_resp; /* report_phy_sata_resp */ u8 port_no; /* port number, if this is a PM (Port) */ + int pm_result; struct ata_port *ap; struct ata_host ata_host; @@ -182,6 +186,7 @@ struct ssp_device { enum { SAS_DEV_GONE, + SAS_DEV_FOUND, /* device notified to lldd */ SAS_DEV_DESTROY, SAS_DEV_EH_PENDING, SAS_DEV_LU_RESET, @@ -273,6 +278,7 @@ struct asd_sas_port { enum sas_linkrate linkrate; struct sas_work work; + int suspended; /* public: */ int id; @@ -321,6 +327,7 @@ struct asd_sas_phy { unsigned long phy_events_pending; int error; + int suspended; struct sas_phy *phy; @@ -687,6 +694,9 @@ struct sas_domain_function_template { extern int sas_register_ha(struct sas_ha_struct *); extern int sas_unregister_ha(struct sas_ha_struct *); +extern void sas_prep_resume_ha(struct sas_ha_struct *sas_ha); +extern void sas_resume_ha(struct sas_ha_struct *sas_ha); +extern void sas_suspend_ha(struct sas_ha_struct *sas_ha); int sas_set_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates); diff --git a/include/scsi/sas_ata.h b/include/scsi/sas_ata.h index 2dfbdaa0b34a..ff71a5654684 100644 --- a/include/scsi/sas_ata.h +++ b/include/scsi/sas_ata.h @@ -45,6 +45,8 @@ void sas_ata_eh(struct Scsi_Host *shost, struct list_head *work_q, void sas_ata_schedule_reset(struct domain_device *dev); void sas_ata_wait_eh(struct domain_device *dev); void sas_probe_sata(struct asd_sas_port *port); +void sas_suspend_sata(struct asd_sas_port *port); +void sas_resume_sata(struct asd_sas_port *port); void sas_ata_end_eh(struct ata_port *ap); #else @@ -82,6 +84,14 @@ static inline void sas_probe_sata(struct asd_sas_port *port) { } +static inline void sas_suspend_sata(struct asd_sas_port *port) +{ +} + +static inline void sas_resume_sata(struct asd_sas_port *port) +{ +} + static inline int sas_get_ata_info(struct domain_device *dev, struct ex_phy *phy) { return 0; -- cgit v1.2.3 From d974e4265dbd35db118c318176727ecb7f469de3 Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Tue, 28 Aug 2012 14:29:35 -0400 Subject: [SCSI] Disable DIF on Hitachi Ultrastar 15K300 Hitachi Ultrastar 15K300 is quirky. Disable T10 PI (DIF). Signed-off-by: Martin K. Petersen Signed-off-by: James Bottomley --- drivers/scsi/scsi_devinfo.c | 1 + drivers/scsi/scsi_scan.c | 3 +++ include/scsi/scsi_device.h | 4 ++++ include/scsi/scsi_devinfo.h | 1 + 4 files changed, 9 insertions(+) (limited to 'include/scsi') diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index cf8dfab9489f..43fca9170bf2 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -172,6 +172,7 @@ static struct { {"HITACHI", "DF400", "*", BLIST_REPORTLUN2}, {"HITACHI", "DF500", "*", BLIST_REPORTLUN2}, {"HITACHI", "DISK-SUBSYSTEM", "*", BLIST_REPORTLUN2}, + {"HITACHI", "HUS1530", "*", BLIST_NO_DIF}, {"HITACHI", "OPEN-", "*", BLIST_REPORTLUN2}, {"HITACHI", "OP-C-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, {"HITACHI", "3380-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 56a93794c470..0a224e29c3f1 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -911,6 +911,9 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result, if (*bflags & BLIST_RETRY_HWERROR) sdev->retry_hwerror = 1; + if (*bflags & BLIST_NO_DIF) + sdev->no_dif = 1; + transport_configure_device(&sdev->sdev_gendev); if (sdev->host->hostt->slave_configure) { diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index 9895f69294fc..88fae8d20154 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -156,6 +156,7 @@ struct scsi_device { unsigned is_visible:1; /* is the device visible in sysfs */ unsigned can_power_off:1; /* Device supports runtime power off */ unsigned wce_default_on:1; /* Cache is ON by default */ + unsigned no_dif:1; /* T10 PI (DIF) should be disabled */ DECLARE_BITMAP(supported_events, SDEV_EVT_MAXBITS); /* supported events */ struct list_head event_list; /* asserted events */ @@ -476,6 +477,9 @@ static inline int scsi_device_enclosure(struct scsi_device *sdev) static inline int scsi_device_protection(struct scsi_device *sdev) { + if (sdev->no_dif) + return 0; + return sdev->scsi_level > SCSI_2 && sdev->inquiry[5] & (1<<0); } diff --git a/include/scsi/scsi_devinfo.h b/include/scsi/scsi_devinfo.h index b4ddd3b18b4c..cc1f3e786ad7 100644 --- a/include/scsi/scsi_devinfo.h +++ b/include/scsi/scsi_devinfo.h @@ -30,4 +30,5 @@ #define BLIST_RETRY_HWERROR 0x400000 /* retry HARDWARE_ERROR */ #define BLIST_MAX_512 0x800000 /* maximum 512 sector cdb length */ #define BLIST_ATTACH_PQ3 0x1000000 /* Scan: Attach to PQ3 devices */ +#define BLIST_NO_DIF 0x2000000 /* Disable T10 PI (DIF) */ #endif -- cgit v1.2.3 From 2c8bd81010ed9377e761893487803a9b7408014d Mon Sep 17 00:00:00 2001 From: Robert Love Date: Wed, 5 Sep 2012 13:50:07 -0700 Subject: [SCSI] fc-transport: Remove unnecessary include This header file is included in user space applications that are doing "FC Passthrough." This include causes them to also include scsi/scsi.h. Since this header file doesn't actually need scsi/scsi.h, remove the include line. This patch was tested with 'make allyesconfig'. Signed-off-by: Robert Love Tested-by: Ross Brattain Signed-off-by: James Bottomley --- include/scsi/scsi_bsg_fc.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'include/scsi') diff --git a/include/scsi/scsi_bsg_fc.h b/include/scsi/scsi_bsg_fc.h index 91a4e4ff9a9b..3031b900b087 100644 --- a/include/scsi/scsi_bsg_fc.h +++ b/include/scsi/scsi_bsg_fc.h @@ -26,8 +26,6 @@ * This file intended to be included by both kernel and user space */ -#include - /* * FC Transport SGIO v4 BSG Message Support */ -- cgit v1.2.3 From fe542396da73b7e2b0848618c7e95855c1b75689 Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Fri, 21 Sep 2012 12:44:12 -0400 Subject: [SCSI] sd: Ensure we correctly disable devices with unknown protection type We set the capacity to zero when we discovered a device formatted with an unknown DIF protection type. However, the read_capacity code would override the capacity and cause the device to be enabled regardless. Make sd_read_protection_type() return an error if the protection type is unknown. Also prevent duplicate printk lines when the device is being revalidated. Reported-by: Hannes Reinecke Signed-off-by: Martin K. Petersen Signed-off-by: James Bottomley --- drivers/scsi/sd.c | 50 ++++++++++++++++++++++++++++++------------------ include/scsi/scsi_host.h | 6 ++++++ 2 files changed, 37 insertions(+), 19 deletions(-) (limited to 'include/scsi') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index e04c302fa4f7..12f6fdfc1147 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1693,34 +1693,42 @@ sd_spinup_disk(struct scsi_disk *sdkp) /* * Determine whether disk supports Data Integrity Field. */ -static void sd_read_protection_type(struct scsi_disk *sdkp, unsigned char *buffer) +static int sd_read_protection_type(struct scsi_disk *sdkp, unsigned char *buffer) { struct scsi_device *sdp = sdkp->device; u8 type; + int ret = 0; if (scsi_device_protection(sdp) == 0 || (buffer[12] & 1) == 0) - return; + return ret; type = ((buffer[12] >> 1) & 7) + 1; /* P_TYPE 0 = Type 1 */ - if (type == sdkp->protection_type || !sdkp->first_scan) - return; + if (type > SD_DIF_TYPE3_PROTECTION) + ret = -ENODEV; + else if (scsi_host_dif_capable(sdp->host, type)) + ret = 1; + + if (sdkp->first_scan || type != sdkp->protection_type) + switch (ret) { + case -ENODEV: + sd_printk(KERN_ERR, sdkp, "formatted with unsupported" \ + " protection type %u. Disabling disk!\n", + type); + break; + case 1: + sd_printk(KERN_NOTICE, sdkp, + "Enabling DIF Type %u protection\n", type); + break; + case 0: + sd_printk(KERN_NOTICE, sdkp, + "Disabling DIF Type %u protection\n", type); + break; + } sdkp->protection_type = type; - if (type > SD_DIF_TYPE3_PROTECTION) { - sd_printk(KERN_ERR, sdkp, "formatted with unsupported " \ - "protection type %u. Disabling disk!\n", type); - sdkp->capacity = 0; - return; - } - - if (scsi_host_dif_capable(sdp->host, type)) - sd_printk(KERN_NOTICE, sdkp, - "Enabling DIF Type %u protection\n", type); - else - sd_printk(KERN_NOTICE, sdkp, - "Disabling DIF Type %u protection\n", type); + return ret; } static void read_capacity_error(struct scsi_disk *sdkp, struct scsi_device *sdp, @@ -1816,7 +1824,10 @@ static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp, sector_size = get_unaligned_be32(&buffer[8]); lba = get_unaligned_be64(&buffer[0]); - sd_read_protection_type(sdkp, buffer); + if (sd_read_protection_type(sdkp, buffer) < 0) { + sdkp->capacity = 0; + return -ENODEV; + } if ((sizeof(sdkp->capacity) == 4) && (lba >= 0xffffffffULL)) { sd_printk(KERN_ERR, sdkp, "Too big for this kernel. Use a " @@ -2654,7 +2665,8 @@ static void sd_probe_async(void *data, async_cookie_t cookie) } add_disk(gd); - sd_dif_config_host(sdkp); + if (sdkp->capacity) + sd_dif_config_host(sdkp); sd_revalidate_disk(gd); diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index 5f7d5b3b1c6e..49084807eb6b 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -873,6 +873,9 @@ static inline unsigned int scsi_host_dif_capable(struct Scsi_Host *shost, unsign SHOST_DIF_TYPE2_PROTECTION, SHOST_DIF_TYPE3_PROTECTION }; + if (target_type > SHOST_DIF_TYPE3_PROTECTION) + return 0; + return shost->prot_capabilities & cap[target_type] ? target_type : 0; } @@ -884,6 +887,9 @@ static inline unsigned int scsi_host_dix_capable(struct Scsi_Host *shost, unsign SHOST_DIX_TYPE2_PROTECTION, SHOST_DIX_TYPE3_PROTECTION }; + if (target_type > SHOST_DIX_TYPE3_PROTECTION) + return 0; + return shost->prot_capabilities & cap[target_type]; #endif return 0; -- cgit v1.2.3