From 91895b786e631ab47b618c901231f22b5a44115b Mon Sep 17 00:00:00 2001 From: Zheng Liu Date: Tue, 8 May 2012 11:24:03 +0800 Subject: libata: enable SATA disk fua detection on default Currently, SATA disk fua detection is disabled on default because most of devices don't support this feature at that time. With the development of technology, more and more SATA disks support this feature. So now we can enable this detection on default. Although fua detection is defined as a kernel module parameter, it is too hard to set its value because it must be loaded and set before system starts up. That needs to modify initrd file. So it is inconvenient for administrator who needs to manage a huge number of servers. Signed-off-by: Zheng Liu Signed-off-by: Jeff Garzik diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 5eee1c1..c3fbdca0 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -135,9 +135,9 @@ int atapi_passthru16 = 1; module_param(atapi_passthru16, int, 0444); MODULE_PARM_DESC(atapi_passthru16, "Enable ATA_16 passthru for ATAPI devices (0=off, 1=on [default])"); -int libata_fua = 0; +int libata_fua = 1; module_param_named(fua, libata_fua, int, 0444); -MODULE_PARM_DESC(fua, "FUA support (0=off [default], 1=on)"); +MODULE_PARM_DESC(fua, "FUA support (0=off, 1=on [default])"); static int ata_ignore_hpa; module_param_named(ignore_hpa, ata_ignore_hpa, int, 0644); -- cgit v0.10.2 From 3e451a495d6a529d9a01c487f272bb2c4241158f Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Fri, 17 Aug 2012 14:04:50 -0400 Subject: [libata] scsi: Remove unlikely() from FUA check Some other unlikely() should probably be removed as well. A fresh look reveals an over-enthusiasm for unlikely() in libata-scsi.c. Signed-off-by: Jeff Garzik diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 8ec81ca..86c2663 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -1655,7 +1655,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc) if (unlikely(scmd->cmd_len < 10)) goto invalid_fld; scsi_10_lba_len(cdb, &block, &n_block); - if (unlikely(cdb[1] & (1 << 3))) + if (cdb[1] & (1 << 3)) tf_flags |= ATA_TFLAG_FUA; break; case READ_6: @@ -1675,7 +1675,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc) if (unlikely(scmd->cmd_len < 16)) goto invalid_fld; scsi_16_lba_len(cdb, &block, &n_block); - if (unlikely(cdb[1] & (1 << 3))) + if (cdb[1] & (1 << 3)) tf_flags |= ATA_TFLAG_FUA; break; default: -- cgit v0.10.2 From 6ca8e79466d34874c188906e775c8f1f8c89b67a Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 5 Jul 2012 14:18:20 +0200 Subject: [libata] scsi: support MODE SENSE request for changeable and default parameters Since the next patch will introduce support for MODE SELECT, it makes sense to start advertising which bits are actually changeable. For now, the answer is none. Default parameters can also be reported, they are simply the same as the current parameters. Signed-off-by: Paolo Bonzini Signed-off-by: Jeff Garzik diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 86c2663..67d23bd 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -2205,9 +2205,33 @@ static unsigned int ata_scsiop_noop(struct ata_scsi_args *args, u8 *rbuf) } /** + * modecpy - Prepare response for MODE SENSE + * @dest: output buffer + * @src: data being copied + * @n: length of mode page + * @changeable: whether changeable parameters are requested + * + * Generate a generic MODE SENSE page for either current or changeable + * parameters. + * + * LOCKING: + * None. + */ +static void modecpy(u8 *dest, const u8 *src, int n, bool changeable) +{ + if (changeable) { + memcpy(dest, src, 2); + memset(dest + 2, 0, n - 2); + } else { + memcpy(dest, src, n); + } +} + +/** * ata_msense_caching - Simulate MODE SENSE caching info page * @id: device IDENTIFY data * @buf: output buffer + * @changeable: whether changeable parameters are requested * * Generate a caching info page, which conditionally indicates * write caching to the SCSI layer, depending on device @@ -2216,12 +2240,12 @@ static unsigned int ata_scsiop_noop(struct ata_scsi_args *args, u8 *rbuf) * LOCKING: * None. */ -static unsigned int ata_msense_caching(u16 *id, u8 *buf) +static unsigned int ata_msense_caching(u16 *id, u8 *buf, bool changeable) { - memcpy(buf, def_cache_mpage, sizeof(def_cache_mpage)); - if (ata_id_wcache_enabled(id)) + modecpy(buf, def_cache_mpage, sizeof(def_cache_mpage), changeable); + if (!changeable && ata_id_wcache_enabled(id)) buf[2] |= (1 << 2); /* write cache enable */ - if (!ata_id_rahead_enabled(id)) + if (!changeable && !ata_id_rahead_enabled(id)) buf[12] |= (1 << 5); /* disable read ahead */ return sizeof(def_cache_mpage); } @@ -2229,30 +2253,33 @@ static unsigned int ata_msense_caching(u16 *id, u8 *buf) /** * ata_msense_ctl_mode - Simulate MODE SENSE control mode page * @buf: output buffer + * @changeable: whether changeable parameters are requested * * Generate a generic MODE SENSE control mode page. * * LOCKING: * None. */ -static unsigned int ata_msense_ctl_mode(u8 *buf) +static unsigned int ata_msense_ctl_mode(u8 *buf, bool changeable) { - memcpy(buf, def_control_mpage, sizeof(def_control_mpage)); + modecpy(buf, def_control_mpage, sizeof(def_control_mpage), changeable); return sizeof(def_control_mpage); } /** * ata_msense_rw_recovery - Simulate MODE SENSE r/w error recovery page * @buf: output buffer + * @changeable: whether changeable parameters are requested * * Generate a generic MODE SENSE r/w error recovery page. * * LOCKING: * None. */ -static unsigned int ata_msense_rw_recovery(u8 *buf) +static unsigned int ata_msense_rw_recovery(u8 *buf, bool changeable) { - memcpy(buf, def_rw_recovery_mpage, sizeof(def_rw_recovery_mpage)); + modecpy(buf, def_rw_recovery_mpage, sizeof(def_rw_recovery_mpage), + changeable); return sizeof(def_rw_recovery_mpage); } @@ -2316,11 +2343,11 @@ static unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf) page_control = scsicmd[2] >> 6; switch (page_control) { case 0: /* current */ + case 1: /* changeable */ + case 2: /* defaults */ break; /* supported */ case 3: /* saved */ goto saving_not_supp; - case 1: /* changeable */ - case 2: /* defaults */ default: goto invalid_fld; } @@ -2341,21 +2368,21 @@ static unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf) switch(pg) { case RW_RECOVERY_MPAGE: - p += ata_msense_rw_recovery(p); + p += ata_msense_rw_recovery(p, page_control == 1); break; case CACHE_MPAGE: - p += ata_msense_caching(args->id, p); + p += ata_msense_caching(args->id, p, page_control == 1); break; case CONTROL_MPAGE: - p += ata_msense_ctl_mode(p); + p += ata_msense_ctl_mode(p, page_control == 1); break; case ALL_MPAGES: - p += ata_msense_rw_recovery(p); - p += ata_msense_caching(args->id, p); - p += ata_msense_ctl_mode(p); + p += ata_msense_rw_recovery(p, page_control == 1); + p += ata_msense_caching(args->id, p, page_control == 1); + p += ata_msense_ctl_mode(p, page_control == 1); break; default: /* invalid page code */ -- cgit v0.10.2 From 1b26d29ccd592ea585c7cc291384184c5568da92 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 5 Jul 2012 14:18:21 +0200 Subject: [libata] scsi: implement MODE SELECT command The cache_type file in sysfs lets users configure the disk cache in write-through or write-back modes. However, ata disks do not support writing to the file because they do not implement the MODE SELECT command. This patch adds a translation from MODE SELECT (for the caching page only) to the ATA SET FEATURES command. The set of changeable parameters answered by MODE SENSE is also adjusted accordingly. Signed-off-by: Paolo Bonzini Signed-off-by: Jeff Garzik diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 67d23bd..e3bda07 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -2243,7 +2243,7 @@ static void modecpy(u8 *dest, const u8 *src, int n, bool changeable) static unsigned int ata_msense_caching(u16 *id, u8 *buf, bool changeable) { modecpy(buf, def_cache_mpage, sizeof(def_cache_mpage), changeable); - if (!changeable && ata_id_wcache_enabled(id)) + if (changeable || ata_id_wcache_enabled(id)) buf[2] |= (1 << 2); /* write cache enable */ if (!changeable && !ata_id_rahead_enabled(id)) buf[12] |= (1 << 5); /* disable read ahead */ @@ -3107,6 +3107,188 @@ static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc) } /** + * ata_mselect_caching - Simulate MODE SELECT for caching info page + * @qc: Storage for translated ATA taskfile + * @buf: input buffer + * @len: number of valid bytes in the input buffer + * + * Prepare a taskfile to modify caching information for the device. + * + * LOCKING: + * None. + */ +static int ata_mselect_caching(struct ata_queued_cmd *qc, + const u8 *buf, int len) +{ + struct ata_taskfile *tf = &qc->tf; + struct ata_device *dev = qc->dev; + char mpage[CACHE_MPAGE_LEN]; + u8 wce; + + /* + * The first two bytes of def_cache_mpage are a header, so offsets + * in mpage are off by 2 compared to buf. Same for len. + */ + + if (len != CACHE_MPAGE_LEN - 2) + return -EINVAL; + + wce = buf[0] & (1 << 2); + + /* + * Check that read-only bits are not modified. + */ + ata_msense_caching(dev->id, mpage, false); + mpage[2] &= ~(1 << 2); + mpage[2] |= wce; + if (memcmp(mpage + 2, buf, CACHE_MPAGE_LEN - 2) != 0) + return -EINVAL; + + tf->flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR; + tf->protocol = ATA_PROT_NODATA; + tf->nsect = 0; + tf->command = ATA_CMD_SET_FEATURES; + tf->feature = wce ? SETFEATURES_WC_ON : SETFEATURES_WC_OFF; + return 0; +} + +/** + * ata_scsiop_mode_select - Simulate MODE SELECT 6, 10 commands + * @qc: Storage for translated ATA taskfile + * + * Converts a MODE SELECT command to an ATA SET FEATURES taskfile. + * Assume this is invoked for direct access devices (e.g. disks) only. + * There should be no block descriptor for other device types. + * + * LOCKING: + * spin_lock_irqsave(host lock) + */ +static unsigned int ata_scsi_mode_select_xlat(struct ata_queued_cmd *qc) +{ + struct scsi_cmnd *scmd = qc->scsicmd; + const u8 *cdb = scmd->cmnd; + const u8 *p; + u8 pg, spg; + unsigned six_byte, pg_len, hdr_len, bd_len; + int len; + + VPRINTK("ENTER\n"); + + six_byte = (cdb[0] == MODE_SELECT); + if (six_byte) { + if (scmd->cmd_len < 5) + goto invalid_fld; + + len = cdb[4]; + hdr_len = 4; + } else { + if (scmd->cmd_len < 9) + goto invalid_fld; + + len = (cdb[7] << 8) + cdb[8]; + hdr_len = 8; + } + + /* We only support PF=1, SP=0. */ + if ((cdb[1] & 0x11) != 0x10) + goto invalid_fld; + + /* Test early for possible overrun. */ + if (!scsi_sg_count(scmd) || scsi_sglist(scmd)->length < len) + goto invalid_param_len; + + p = page_address(sg_page(scsi_sglist(scmd))); + + /* Move past header and block descriptors. */ + if (len < hdr_len) + goto invalid_param_len; + + if (six_byte) + bd_len = p[3]; + else + bd_len = (p[6] << 8) + p[7]; + + len -= hdr_len; + p += hdr_len; + if (len < bd_len) + goto invalid_param_len; + if (bd_len != 0 && bd_len != 8) + goto invalid_param; + + len -= bd_len; + p += bd_len; + if (len == 0) + goto skip; + + /* Parse both possible formats for the mode page headers. */ + pg = p[0] & 0x3f; + if (p[0] & 0x40) { + if (len < 4) + goto invalid_param_len; + + spg = p[1]; + pg_len = (p[2] << 8) | p[3]; + p += 4; + len -= 4; + } else { + if (len < 2) + goto invalid_param_len; + + spg = 0; + pg_len = p[1]; + p += 2; + len -= 2; + } + + /* + * No mode subpages supported (yet) but asking for _all_ + * subpages may be valid + */ + if (spg && (spg != ALL_SUB_MPAGES)) + goto invalid_param; + if (pg_len > len) + goto invalid_param_len; + + switch (pg) { + case CACHE_MPAGE: + if (ata_mselect_caching(qc, p, pg_len) < 0) + goto invalid_param; + break; + + default: /* invalid page code */ + goto invalid_param; + } + + /* + * Only one page has changeable data, so we only support setting one + * page at a time. + */ + if (len > pg_len) + goto invalid_param; + + return 0; + + invalid_fld: + /* "Invalid field in CDB" */ + ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x24, 0x0); + return 1; + + invalid_param: + /* "Invalid field in parameter list" */ + ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x26, 0x0); + return 1; + + invalid_param_len: + /* "Parameter list length error" */ + ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x1a, 0x0); + return 1; + + skip: + scmd->result = SAM_STAT_GOOD; + return 1; +} + +/** * ata_get_xlat_func - check if SCSI to ATA translation is possible * @dev: ATA device * @cmd: SCSI command opcode to consider @@ -3146,6 +3328,11 @@ static inline ata_xlat_func_t ata_get_xlat_func(struct ata_device *dev, u8 cmd) case ATA_16: return ata_scsi_pass_thru; + case MODE_SELECT: + case MODE_SELECT_10: + return ata_scsi_mode_select_xlat; + break; + case START_STOP: return ata_scsi_start_stop_xlat; } @@ -3338,11 +3525,6 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd) ata_scsi_rbuf_fill(&args, ata_scsiop_mode_sense); break; - case MODE_SELECT: /* unconditionally return */ - case MODE_SELECT_10: /* bad-field-in-cdb */ - ata_scsi_invalid_field(cmd); - break; - case READ_CAPACITY: ata_scsi_rbuf_fill(&args, ata_scsiop_read_cap); break; -- cgit v0.10.2 From 9973a1c306a01804c41ab34166f1320c9f209038 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Thu, 13 Sep 2012 00:14:21 -0400 Subject: Revert "libata: enable SATA disk fua detection on default" It caused several reported regressions. This reverts commit 91895b786e631ab47b618c901231f22b5a44115b. diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index c3fbdca0..5eee1c1 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -135,9 +135,9 @@ int atapi_passthru16 = 1; module_param(atapi_passthru16, int, 0444); MODULE_PARM_DESC(atapi_passthru16, "Enable ATA_16 passthru for ATAPI devices (0=off, 1=on [default])"); -int libata_fua = 1; +int libata_fua = 0; module_param_named(fua, libata_fua, int, 0444); -MODULE_PARM_DESC(fua, "FUA support (0=off, 1=on [default])"); +MODULE_PARM_DESC(fua, "FUA support (0=off [default], 1=on)"); static int ata_ignore_hpa; module_param_named(ignore_hpa, ata_ignore_hpa, int, 0644); -- cgit v0.10.2 From 583661a89ed2e484bd295e7b4606099340478c38 Mon Sep 17 00:00:00 2001 From: Shane Huang Date: Fri, 7 Sep 2012 22:38:20 +0800 Subject: ata: define enum constants for IDENTIFY DEVICE Define enumeration constants for IDENTIFY DEVICE words. Signed-off-by: Shane Huang Signed-off-by: Jeff Garzik diff --git a/include/linux/ata.h b/include/linux/ata.h index 5713d3a..47a9dbf 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -77,6 +77,9 @@ enum { ATA_ID_EIDE_PIO_IORDY = 68, ATA_ID_ADDITIONAL_SUPP = 69, ATA_ID_QUEUE_DEPTH = 75, + ATA_ID_SATA_CAPABILITY = 76, + ATA_ID_SATA_CAPABILITY_2 = 77, + ATA_ID_FEATURE_SUPP = 78, ATA_ID_MAJOR_VER = 80, ATA_ID_COMMAND_SET_1 = 82, ATA_ID_COMMAND_SET_2 = 83, @@ -558,15 +561,17 @@ static inline int ata_is_data(u8 prot) #define ata_id_is_ata(id) (((id)[ATA_ID_CONFIG] & (1 << 15)) == 0) #define ata_id_has_lba(id) ((id)[ATA_ID_CAPABILITY] & (1 << 9)) #define ata_id_has_dma(id) ((id)[ATA_ID_CAPABILITY] & (1 << 8)) -#define ata_id_has_ncq(id) ((id)[76] & (1 << 8)) +#define ata_id_has_ncq(id) ((id)[ATA_ID_SATA_CAPABILITY] & (1 << 8)) #define ata_id_queue_depth(id) (((id)[ATA_ID_QUEUE_DEPTH] & 0x1f) + 1) #define ata_id_removeable(id) ((id)[ATA_ID_CONFIG] & (1 << 7)) #define ata_id_has_atapi_AN(id) \ - ( (((id)[76] != 0x0000) && ((id)[76] != 0xffff)) && \ - ((id)[78] & (1 << 5)) ) + ((((id)[ATA_ID_SATA_CAPABILITY] != 0x0000) && \ + ((id)[ATA_ID_SATA_CAPABILITY] != 0xffff)) && \ + ((id)[ATA_ID_FEATURE_SUPP] & (1 << 5))) #define ata_id_has_fpdma_aa(id) \ - ( (((id)[76] != 0x0000) && ((id)[76] != 0xffff)) && \ - ((id)[78] & (1 << 2)) ) + ((((id)[ATA_ID_SATA_CAPABILITY] != 0x0000) && \ + ((id)[ATA_ID_SATA_CAPABILITY] != 0xffff)) && \ + ((id)[ATA_ID_FEATURE_SUPP] & (1 << 2))) #define ata_id_iordy_disable(id) ((id)[ATA_ID_CAPABILITY] & (1 << 10)) #define ata_id_has_iordy(id) ((id)[ATA_ID_CAPABILITY] & (1 << 11)) #define ata_id_u32(id,n) \ @@ -578,11 +583,11 @@ static inline int ata_is_data(u8 prot) ((u64) (id)[(n) + 0]) ) #define ata_id_cdb_intr(id) (((id)[ATA_ID_CONFIG] & 0x60) == 0x20) -#define ata_id_has_da(id) ((id)[77] & (1 << 4)) +#define ata_id_has_da(id) ((id)[ATA_ID_SATA_CAPABILITY_2] & (1 << 4)) static inline bool ata_id_has_hipm(const u16 *id) { - u16 val = id[76]; + u16 val = id[ATA_ID_SATA_CAPABILITY]; if (val == 0 || val == 0xffff) return false; @@ -592,7 +597,7 @@ static inline bool ata_id_has_hipm(const u16 *id) static inline bool ata_id_has_dipm(const u16 *id) { - u16 val = id[78]; + u16 val = id[ATA_ID_FEATURE_SUPP]; if (val == 0 || val == 0xffff) return false; -- cgit v0.10.2 From 65fe1f0f66a57380229a4ced844188103135f37b Mon Sep 17 00:00:00 2001 From: Shane Huang Date: Fri, 7 Sep 2012 22:40:01 +0800 Subject: ahci: implement aggressive SATA device sleep support Device Sleep is a feature as described in AHCI 1.3.1 Technical Proposal. This feature enables an HBA and SATA storage device to enter the DevSleep interface state, enabling lower power SATA-based systems. Aggressive Device Sleep enables the HBA to assert the DEVSLP signal as soon as there are no commands outstanding to the device and the port specific Device Sleep idle timer has expired. This enables autonomous entry into the DevSleep interface state without waiting for software in power sensitive systems. This patch enables Aggressive Device Sleep only if both host controller and device support it. Tested on AMD reference board together with Device Sleep supported device sample. Signed-off-by: Shane Huang Reviewed-by: Aaron Lu Signed-off-by: Jeff Garzik diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h index 57eb1c2..6441cbe 100644 --- a/drivers/ata/ahci.h +++ b/drivers/ata/ahci.h @@ -115,6 +115,9 @@ enum { HOST_CAP2_BOH = (1 << 0), /* BIOS/OS handoff supported */ HOST_CAP2_NVMHCI = (1 << 1), /* NVMHCI supported */ HOST_CAP2_APST = (1 << 2), /* Automatic partial to slumber */ + HOST_CAP2_SDS = (1 << 3), /* Support device sleep */ + HOST_CAP2_SADM = (1 << 4), /* Support aggressive DevSlp */ + HOST_CAP2_DESO = (1 << 5), /* DevSlp from slumber only */ /* registers for each SATA port */ PORT_LST_ADDR = 0x00, /* command list DMA addr */ @@ -133,6 +136,7 @@ enum { PORT_SCR_ACT = 0x34, /* SATA phy register: SActive */ PORT_SCR_NTF = 0x3c, /* SATA phy register: SNotification */ PORT_FBS = 0x40, /* FIS-based Switching */ + PORT_DEVSLP = 0x44, /* device sleep */ /* PORT_IRQ_{STAT,MASK} bits */ PORT_IRQ_COLD_PRES = (1 << 31), /* cold presence detect */ @@ -186,6 +190,7 @@ enum { PORT_CMD_ICC_PARTIAL = (0x2 << 28), /* Put i/f in partial state */ PORT_CMD_ICC_SLUMBER = (0x6 << 28), /* Put i/f in slumber state */ + /* PORT_FBS bits */ PORT_FBS_DWE_OFFSET = 16, /* FBS device with error offset */ PORT_FBS_ADO_OFFSET = 12, /* FBS active dev optimization offset */ PORT_FBS_DEV_OFFSET = 8, /* FBS device to issue offset */ @@ -194,6 +199,15 @@ enum { PORT_FBS_DEC = (1 << 1), /* FBS device error clear */ PORT_FBS_EN = (1 << 0), /* Enable FBS */ + /* PORT_DEVSLP bits */ + PORT_DEVSLP_DM_OFFSET = 25, /* DITO multiplier offset */ + PORT_DEVSLP_DM_MASK = (0xf << 25), /* DITO multiplier mask */ + PORT_DEVSLP_DITO_OFFSET = 15, /* DITO offset */ + PORT_DEVSLP_MDAT_OFFSET = 10, /* Minimum assertion time */ + PORT_DEVSLP_DETO_OFFSET = 2, /* DevSlp exit timeout */ + PORT_DEVSLP_DSP = (1 << 1), /* DevSlp present */ + PORT_DEVSLP_ADSE = (1 << 0), /* Aggressive DevSlp enable */ + /* hpriv->flags bits */ #define AHCI_HFLAGS(flags) .private_data = (void *)(flags) diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 555c07a..4201e53 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -45,6 +45,7 @@ #include #include #include "ahci.h" +#include "libata.h" static int ahci_skip_host_reset; int ahci_ignore_sss; @@ -76,6 +77,7 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc); static int ahci_pmp_qc_defer(struct ata_queued_cmd *qc); static void ahci_freeze(struct ata_port *ap); static void ahci_thaw(struct ata_port *ap); +static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep); static void ahci_enable_fbs(struct ata_port *ap); static void ahci_disable_fbs(struct ata_port *ap); static void ahci_pmp_attach(struct ata_port *ap); @@ -193,6 +195,10 @@ module_param(ahci_em_messages, int, 0444); MODULE_PARM_DESC(ahci_em_messages, "AHCI Enclosure Management Message control (0 = off, 1 = on)"); +int devslp_idle_timeout = 1000; /* device sleep idle timeout in ms */ +module_param(devslp_idle_timeout, int, 0644); +MODULE_PARM_DESC(devslp_idle_timeout, "device sleep idle timeout"); + static void ahci_enable_ahci(void __iomem *mmio) { int i; @@ -702,6 +708,16 @@ static int ahci_set_lpm(struct ata_link *link, enum ata_lpm_policy policy, } } + /* set aggressive device sleep */ + if ((hpriv->cap2 & HOST_CAP2_SDS) && + (hpriv->cap2 & HOST_CAP2_SADM) && + (link->device->flags & ATA_DFLAG_DEVSLP)) { + if (policy == ATA_LPM_MIN_POWER) + ahci_set_aggressive_devslp(ap, true); + else + ahci_set_aggressive_devslp(ap, false); + } + if (policy == ATA_LPM_MAX_POWER) { sata_link_scr_lpm(link, policy, false); @@ -1890,6 +1906,81 @@ static void ahci_post_internal_cmd(struct ata_queued_cmd *qc) ahci_kick_engine(ap); } +static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep) +{ + void __iomem *port_mmio = ahci_port_base(ap); + struct ata_device *dev = ap->link.device; + u32 devslp, dm, dito, mdat, deto; + int rc; + unsigned int err_mask; + + devslp = readl(port_mmio + PORT_DEVSLP); + if (!(devslp & PORT_DEVSLP_DSP)) { + dev_err(ap->host->dev, "port does not support device sleep\n"); + return; + } + + /* disable device sleep */ + if (!sleep) { + if (devslp & PORT_DEVSLP_ADSE) { + writel(devslp & ~PORT_DEVSLP_ADSE, + port_mmio + PORT_DEVSLP); + err_mask = ata_dev_set_feature(dev, + SETFEATURES_SATA_DISABLE, + SATA_DEVSLP); + if (err_mask && err_mask != AC_ERR_DEV) + ata_dev_warn(dev, "failed to disable DEVSLP\n"); + } + return; + } + + /* device sleep was already enabled */ + if (devslp & PORT_DEVSLP_ADSE) + return; + + /* set DITO, MDAT, DETO and enable DevSlp, need to stop engine first */ + rc = ahci_stop_engine(ap); + if (rc) + return; + + dm = (devslp & PORT_DEVSLP_DM_MASK) >> PORT_DEVSLP_DM_OFFSET; + dito = devslp_idle_timeout / (dm + 1); + if (dito > 0x3ff) + dito = 0x3ff; + + /* Use the nominal value 10 ms if the read MDAT is zero, + * the nominal value of DETO is 20 ms. + */ + if (dev->sata_settings[ATA_LOG_DEVSLP_VALID] & + ATA_LOG_DEVSLP_VALID_MASK) { + mdat = dev->sata_settings[ATA_LOG_DEVSLP_MDAT] & + ATA_LOG_DEVSLP_MDAT_MASK; + if (!mdat) + mdat = 10; + deto = dev->sata_settings[ATA_LOG_DEVSLP_DETO]; + if (!deto) + deto = 20; + } else { + mdat = 10; + deto = 20; + } + + devslp |= ((dito << PORT_DEVSLP_DITO_OFFSET) | + (mdat << PORT_DEVSLP_MDAT_OFFSET) | + (deto << PORT_DEVSLP_DETO_OFFSET) | + PORT_DEVSLP_ADSE); + writel(devslp, port_mmio + PORT_DEVSLP); + + ahci_start_engine(ap); + + /* enable device sleep feature for the drive */ + err_mask = ata_dev_set_feature(dev, + SETFEATURES_SATA_ENABLE, + SATA_DEVSLP); + if (err_mask && err_mask != AC_ERR_DEV) + ata_dev_warn(dev, "failed to enable DEVSLP\n"); +} + static void ahci_enable_fbs(struct ata_port *ap) { struct ahci_port_priv *pp = ap->private_data; @@ -2164,7 +2255,8 @@ void ahci_print_info(struct ata_host *host, const char *scc_s) "flags: " "%s%s%s%s%s%s%s" "%s%s%s%s%s%s%s" - "%s%s%s%s%s%s\n" + "%s%s%s%s%s%s%s" + "%s%s\n" , cap & HOST_CAP_64 ? "64bit " : "", @@ -2184,6 +2276,9 @@ void ahci_print_info(struct ata_host *host, const char *scc_s) cap & HOST_CAP_CCC ? "ccc " : "", cap & HOST_CAP_EMS ? "ems " : "", cap & HOST_CAP_SXS ? "sxs " : "", + cap2 & HOST_CAP2_DESO ? "deso " : "", + cap2 & HOST_CAP2_SADM ? "sadm " : "", + cap2 & HOST_CAP2_SDS ? "sds " : "", cap2 & HOST_CAP2_APST ? "apst " : "", cap2 & HOST_CAP2_NVMHCI ? "nvmp " : "", cap2 & HOST_CAP2_BOH ? "boh " : "" diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 5eee1c1..25daf39 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2155,6 +2155,7 @@ int ata_dev_configure(struct ata_device *dev) int print_info = ehc->i.flags & ATA_EHI_PRINTINFO; const u16 *id = dev->id; unsigned long xfer_mask; + unsigned int err_mask; char revbuf[7]; /* XYZ-99\0 */ char fwrevbuf[ATA_ID_FW_REV_LEN+1]; char modelbuf[ATA_ID_PROD_LEN+1]; @@ -2323,6 +2324,26 @@ int ata_dev_configure(struct ata_device *dev) } } + /* check and mark DevSlp capability */ + if (ata_id_has_devslp(dev->id)) + dev->flags |= ATA_DFLAG_DEVSLP; + + /* Obtain SATA Settings page from Identify Device Data Log, + * which contains DevSlp timing variables etc. + * Exclude old devices with ata_id_has_ncq() + */ + if (ata_id_has_ncq(dev->id)) { + err_mask = ata_read_log_page(dev, + ATA_LOG_SATA_ID_DEV_DATA, + ATA_LOG_SATA_SETTINGS, + dev->sata_settings, + 1); + if (err_mask) + ata_dev_dbg(dev, + "failed to get Identify Device Data, Emask 0x%x\n", + err_mask); + } + dev->cdb_len = 16; } @@ -2351,8 +2372,6 @@ int ata_dev_configure(struct ata_device *dev) (ap->flags & ATA_FLAG_AN) && ata_id_has_atapi_AN(id) && (!sata_pmp_attached(ap) || sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf) == 0)) { - unsigned int err_mask; - /* issue SET feature command to turn this on */ err_mask = ata_dev_set_feature(dev, SETFEATURES_SATA_ENABLE, SATA_AN); @@ -3598,7 +3617,7 @@ int sata_link_scr_lpm(struct ata_link *link, enum ata_lpm_policy policy, switch (policy) { case ATA_LPM_MAX_POWER: /* disable all LPM transitions */ - scontrol |= (0x3 << 8); + scontrol |= (0x7 << 8); /* initiate transition to active state */ if (spm_wakeup) { scontrol |= (0x4 << 12); @@ -3608,12 +3627,12 @@ int sata_link_scr_lpm(struct ata_link *link, enum ata_lpm_policy policy, case ATA_LPM_MED_POWER: /* allow LPM to PARTIAL */ scontrol &= ~(0x1 << 8); - scontrol |= (0x2 << 8); + scontrol |= (0x6 << 8); break; case ATA_LPM_MIN_POWER: if (ata_link_nr_enabled(link) > 0) /* no restrictions on LPM transitions */ - scontrol &= ~(0x3 << 8); + scontrol &= ~(0x7 << 8); else { /* empty port, power off */ scontrol &= ~0xf; diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 7d4535e..2659894 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1487,6 +1487,7 @@ static const char *ata_err_string(unsigned int err_mask) /** * ata_read_log_page - read a specific log page * @dev: target device + * @log: log to read * @page: page to read * @buf: buffer to store read page * @sectors: number of sectors to read @@ -1499,17 +1500,18 @@ static const char *ata_err_string(unsigned int err_mask) * RETURNS: * 0 on success, AC_ERR_* mask otherwise. */ -static unsigned int ata_read_log_page(struct ata_device *dev, - u8 page, void *buf, unsigned int sectors) +unsigned int ata_read_log_page(struct ata_device *dev, u8 log, + u8 page, void *buf, unsigned int sectors) { struct ata_taskfile tf; unsigned int err_mask; - DPRINTK("read log page - page %d\n", page); + DPRINTK("read log page - log 0x%x, page 0x%x\n", log, page); ata_tf_init(dev, &tf); tf.command = ATA_CMD_READ_LOG_EXT; - tf.lbal = page; + tf.lbal = log; + tf.lbam = page; tf.nsect = sectors; tf.hob_nsect = sectors >> 8; tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_LBA48 | ATA_TFLAG_DEVICE; @@ -1545,7 +1547,7 @@ static int ata_eh_read_log_10h(struct ata_device *dev, u8 csum; int i; - err_mask = ata_read_log_page(dev, ATA_LOG_SATA_NCQ, buf, 1); + err_mask = ata_read_log_page(dev, ATA_LOG_SATA_NCQ, 0, buf, 1); if (err_mask) return -EIO; diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 50e4dff..7148a58 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -165,6 +165,8 @@ extern void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev, unsigned int action); extern void ata_eh_done(struct ata_link *link, struct ata_device *dev, unsigned int action); +extern unsigned int ata_read_log_page(struct ata_device *dev, u8 log, + u8 page, void *buf, unsigned int sectors); extern void ata_eh_autopsy(struct ata_port *ap); const char *ata_get_cmd_descript(u8 command); extern void ata_eh_report(struct ata_port *ap); diff --git a/include/linux/ata.h b/include/linux/ata.h index 47a9dbf..408da95 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -295,6 +295,13 @@ enum { /* READ_LOG_EXT pages */ ATA_LOG_SATA_NCQ = 0x10, + ATA_LOG_SATA_ID_DEV_DATA = 0x30, + ATA_LOG_SATA_SETTINGS = 0x08, + ATA_LOG_DEVSLP_MDAT = 0x30, + ATA_LOG_DEVSLP_MDAT_MASK = 0x1F, + ATA_LOG_DEVSLP_DETO = 0x31, + ATA_LOG_DEVSLP_VALID = 0x37, + ATA_LOG_DEVSLP_VALID_MASK = 0x80, /* READ/WRITE LONG (obsolete) */ ATA_CMD_READ_LONG = 0x22, @@ -348,6 +355,7 @@ enum { SATA_FPDMA_IN_ORDER = 0x04, /* FPDMA in-order data delivery */ SATA_AN = 0x05, /* Asynchronous Notification */ SATA_SSP = 0x06, /* Software Settings Preservation */ + SATA_DEVSLP = 0x09, /* Device Sleep */ /* feature values for SET_MAX */ ATA_SET_MAX_ADDR = 0x00, @@ -584,6 +592,7 @@ static inline int ata_is_data(u8 prot) #define ata_id_cdb_intr(id) (((id)[ATA_ID_CONFIG] & 0x60) == 0x20) #define ata_id_has_da(id) ((id)[ATA_ID_SATA_CAPABILITY_2] & (1 << 4)) +#define ata_id_has_devslp(id) ((id)[ATA_ID_FEATURE_SUPP] & (1 << 8)) static inline bool ata_id_has_hipm(const u16 *id) { diff --git a/include/linux/libata.h b/include/linux/libata.h index 64f90e1..464e67c 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -162,6 +162,7 @@ enum { ATA_DFLAG_DETACHED = (1 << 25), ATA_DFLAG_DA = (1 << 26), /* device supports Device Attention */ + ATA_DFLAG_DEVSLP = (1 << 27), /* device supports Device Sleep */ ATA_DEV_UNKNOWN = 0, /* unknown device */ ATA_DEV_ATA = 1, /* ATA device */ @@ -649,6 +650,9 @@ struct ata_device { u32 gscr[SATA_PMP_GSCR_DWORDS]; /* PMP GSCR block */ }; + /* Identify Device Data Log (30h), SATA Settings (page 08h) */ + u8 sata_settings[ATA_SECT_SIZE]; + /* error history */ int spdn_cnt; /* ering is CLEAR_END, read comment above CLEAR_END */ -- cgit v0.10.2 From 100f586bd0959fe0e52b8a0b8cb49a3df1c6b044 Mon Sep 17 00:00:00 2001 From: Shaohui Xie Date: Tue, 11 Sep 2012 10:48:53 +0800 Subject: sata_fsl: add workaround for data length mismatch on freescale V2 controller The freescale V2 SATA controller checks if the received data length matches the programmed length 'ttl', if not, it assumes that this is an error. In ATAPI, the 'ttl' is based on max allocation length and not the actual data transfer length, controller will raise 'DLM' (Data length Mismatch) error bit in Hstatus register. Along with 'DLM', DE (Device error) and FE (fatal Error) bits are also set in Hstatus register, 'E' (Internal Error) bit is set in Serror register and CE (Command Error) and DE (Device error) registers have the corresponding bit set. In this condition, we need to clear errors in following way: in the service routine, based on 'DLM' flag, HCONTROL[27] operation clears Hstatus, CE and DE registers, clear Serror register. Signed-off-by: Shaohui Xie Signed-off-by: Anju Bhartiya Signed-off-by: Jeff Garzik diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c index d6577b9..124b2c1 100644 --- a/drivers/ata/sata_fsl.c +++ b/drivers/ata/sata_fsl.c @@ -123,6 +123,7 @@ enum { ONLINE = (1 << 31), GOING_OFFLINE = (1 << 30), BIST_ERR = (1 << 29), + CLEAR_ERROR = (1 << 27), FATAL_ERR_HC_MASTER_ERR = (1 << 18), FATAL_ERR_PARITY_ERR_TX = (1 << 17), @@ -143,6 +144,7 @@ enum { FATAL_ERR_CRC_ERR_RX | FATAL_ERR_FIFO_OVRFL_TX | FATAL_ERR_FIFO_OVRFL_RX, + INT_ON_DATA_LENGTH_MISMATCH = (1 << 12), INT_ON_FATAL_ERR = (1 << 5), INT_ON_PHYRDY_CHG = (1 << 4), @@ -1181,25 +1183,54 @@ static void sata_fsl_host_intr(struct ata_port *ap) u32 hstatus, done_mask = 0; struct ata_queued_cmd *qc; u32 SError; + u32 tag; + u32 status_mask = INT_ON_ERROR; hstatus = ioread32(hcr_base + HSTATUS); sata_fsl_scr_read(&ap->link, SCR_ERROR, &SError); + /* Read command completed register */ + done_mask = ioread32(hcr_base + CC); + + /* Workaround for data length mismatch errata */ + if (unlikely(hstatus & INT_ON_DATA_LENGTH_MISMATCH)) { + for (tag = 0; tag < ATA_MAX_QUEUE; tag++) { + qc = ata_qc_from_tag(ap, tag); + if (qc && ata_is_atapi(qc->tf.protocol)) { + u32 hcontrol; + /* Set HControl[27] to clear error registers */ + hcontrol = ioread32(hcr_base + HCONTROL); + iowrite32(hcontrol | CLEAR_ERROR, + hcr_base + HCONTROL); + + /* Clear HControl[27] */ + iowrite32(hcontrol & ~CLEAR_ERROR, + hcr_base + HCONTROL); + + /* Clear SError[E] bit */ + sata_fsl_scr_write(&ap->link, SCR_ERROR, + SError); + + /* Ignore fatal error and device error */ + status_mask &= ~(INT_ON_SINGL_DEVICE_ERR + | INT_ON_FATAL_ERR); + break; + } + } + } + if (unlikely(SError & 0xFFFF0000)) { DPRINTK("serror @host_intr : 0x%x\n", SError); sata_fsl_error_intr(ap); } - if (unlikely(hstatus & INT_ON_ERROR)) { + if (unlikely(hstatus & status_mask)) { DPRINTK("error interrupt!!\n"); sata_fsl_error_intr(ap); return; } - /* Read command completed register */ - done_mask = ioread32(hcr_base + CC); - VPRINTK("Status of all queues :\n"); VPRINTK("done_mask/CC = 0x%x, CA = 0x%x, CE=0x%x,CQ=0x%x,apqa=0x%x\n", done_mask, -- cgit v0.10.2 From 8996b89d6bc98ae2f6d6e6e624a42a3f89d06949 Mon Sep 17 00:00:00 2001 From: Mark Langsdorf Date: Thu, 6 Sep 2012 16:03:30 -0500 Subject: ata: add platform driver for Calxeda AHCI controller Calxeda highbank SATA phy has intermittent problems bringing up a link with Gen3 drives. Retrying the phy hard reset can work-around this issue, but each reset also disables spread spectrum support. The reset function also needs to reprogram the phy to enable spread spectrum support. Create a new driver based on ahci_platform to support the Calxeda Highbank SATA controller. Signed-off-by: Mark Langsdorf Signed-off-by: Rob Herring Signed-off-by: Jeff Garzik diff --git a/Documentation/devicetree/bindings/arm/calxeda/combophy.txt b/Documentation/devicetree/bindings/arm/calxeda/combophy.txt new file mode 100644 index 0000000..6622bdb --- /dev/null +++ b/Documentation/devicetree/bindings/arm/calxeda/combophy.txt @@ -0,0 +1,17 @@ +Calxeda Highbank Combination Phys for SATA + +Properties: +- compatible : Should be "calxeda,hb-combophy" +- #phy-cells: Should be 1. +- reg : Address and size for Combination Phy registers. +- phydev: device ID for programming the combophy. + +Example: + + combophy5: combo-phy@fff5d000 { + compatible = "calxeda,hb-combophy"; + #phy-cells = <1>; + reg = <0xfff5d000 0x1000>; + phydev = <31>; + }; + diff --git a/Documentation/devicetree/bindings/ata/ahci-platform.txt b/Documentation/devicetree/bindings/ata/ahci-platform.txt index 8bb8a76..147c1f6 100644 --- a/Documentation/devicetree/bindings/ata/ahci-platform.txt +++ b/Documentation/devicetree/bindings/ata/ahci-platform.txt @@ -8,9 +8,17 @@ Required properties: - interrupts : - reg : +Optional properties: +- calxeda,port-phys: phandle-combophy and lane assignment, which maps each + SATA port to a combophy and a lane within that + combophy + Example: sata@ffe08000 { compatible = "calxeda,hb-ahci"; reg = <0xffe08000 0x1000>; interrupts = <115>; + calxeda,port-phys = <&combophy5 0 &combophy0 0 &combophy0 1 + &combophy0 2 &combophy0 3>; + }; diff --git a/arch/arm/boot/dts/highbank.dts b/arch/arm/boot/dts/highbank.dts index 9fecf1a..5204cf7 100644 --- a/arch/arm/boot/dts/highbank.dts +++ b/arch/arm/boot/dts/highbank.dts @@ -121,6 +121,9 @@ compatible = "calxeda,hb-ahci"; reg = <0xffe08000 0x10000>; interrupts = <0 83 4>; + calxeda,port-phys = <&combophy5 0 &combophy0 0 + &combophy0 1 &combophy0 2 + &combophy0 3>; }; sdhci@ffe0e000 { @@ -306,5 +309,19 @@ reg = <0xfff51000 0x1000>; interrupts = <0 80 4 0 81 4 0 82 4>; }; + + combophy0: combo-phy@fff58000 { + compatible = "calxeda,hb-combophy"; + #phy-cells = <1>; + reg = <0xfff58000 0x1000>; + phydev = <5>; + }; + + combophy5: combo-phy@fff5d000 { + compatible = "calxeda,hb-combophy"; + #phy-cells = <1>; + reg = <0xfff5d000 0x1000>; + phydev = <31>; + }; }; }; diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 27cecd3..e08d322 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -214,6 +214,14 @@ config SATA_DWC_VDEBUG help This option enables the taskfile dumping and NCQ debugging. +config SATA_HIGHBANK + tristate "Calxeda Highbank SATA support" + help + This option enables support for the Calxeda Highbank SoC's + onboard SATA. + + If unsure, say N. + config SATA_MV tristate "Marvell SATA support" help diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index a454a13..8b384f1 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_SATA_FSL) += sata_fsl.o obj-$(CONFIG_SATA_INIC162X) += sata_inic162x.o obj-$(CONFIG_SATA_SIL24) += sata_sil24.o obj-$(CONFIG_SATA_DWC) += sata_dwc_460ex.o +obj-$(CONFIG_SATA_HIGHBANK) += sata_highbank.o # SFF w/ custom DMA obj-$(CONFIG_PDC_ADMA) += pdc_adma.o diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c index 09728e0..dc187c7 100644 --- a/drivers/ata/ahci_platform.c +++ b/drivers/ata/ahci_platform.c @@ -277,7 +277,6 @@ static int ahci_resume(struct device *dev) SIMPLE_DEV_PM_OPS(ahci_pm_ops, ahci_suspend, ahci_resume); static const struct of_device_id ahci_of_match[] = { - { .compatible = "calxeda,hb-ahci", }, { .compatible = "snps,spear-ahci", }, {}, }; diff --git a/drivers/ata/sata_highbank.c b/drivers/ata/sata_highbank.c new file mode 100644 index 0000000..0d7c4c2 --- /dev/null +++ b/drivers/ata/sata_highbank.c @@ -0,0 +1,450 @@ +/* + * Calxeda Highbank AHCI SATA platform driver + * Copyright 2012 Calxeda, Inc. + * + * based on the AHCI SATA platform driver by Jeff Garzik and Anton Vorontsov + * + * 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 . + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ahci.h" + +#define CPHY_MAP(dev, addr) ((((dev) & 0x1f) << 7) | (((addr) >> 9) & 0x7f)) +#define CPHY_ADDR(addr) (((addr) & 0x1ff) << 2) +#define SERDES_CR_CTL 0x80a0 +#define SERDES_CR_ADDR 0x80a1 +#define SERDES_CR_DATA 0x80a2 +#define CR_BUSY 0x0001 +#define CR_START 0x0001 +#define CR_WR_RDN 0x0002 +#define CPHY_RX_INPUT_STS 0x2002 +#define CPHY_SATA_OVERRIDE 0x4000 +#define CPHY_OVERRIDE 0x2005 +#define SPHY_LANE 0x100 +#define SPHY_HALF_RATE 0x0001 +#define CPHY_SATA_DPLL_MODE 0x0700 +#define CPHY_SATA_DPLL_SHIFT 8 +#define CPHY_SATA_DPLL_RESET (1 << 11) +#define CPHY_PHY_COUNT 6 +#define CPHY_LANE_COUNT 4 +#define CPHY_PORT_COUNT (CPHY_PHY_COUNT * CPHY_LANE_COUNT) + +static DEFINE_SPINLOCK(cphy_lock); +/* Each of the 6 phys can have up to 4 sata ports attached to i. Map 0-based + * sata ports to their phys and then to their lanes within the phys + */ +struct phy_lane_info { + void __iomem *phy_base; + u8 lane_mapping; + u8 phy_devs; +}; +static struct phy_lane_info port_data[CPHY_PORT_COUNT]; + +static u32 __combo_phy_reg_read(u8 sata_port, u32 addr) +{ + u32 data; + u8 dev = port_data[sata_port].phy_devs; + spin_lock(&cphy_lock); + writel(CPHY_MAP(dev, addr), port_data[sata_port].phy_base + 0x800); + data = readl(port_data[sata_port].phy_base + CPHY_ADDR(addr)); + spin_unlock(&cphy_lock); + return data; +} + +static void __combo_phy_reg_write(u8 sata_port, u32 addr, u32 data) +{ + u8 dev = port_data[sata_port].phy_devs; + spin_lock(&cphy_lock); + writel(CPHY_MAP(dev, addr), port_data[sata_port].phy_base + 0x800); + writel(data, port_data[sata_port].phy_base + CPHY_ADDR(addr)); + spin_unlock(&cphy_lock); +} + +static void combo_phy_wait_for_ready(u8 sata_port) +{ + while (__combo_phy_reg_read(sata_port, SERDES_CR_CTL) & CR_BUSY) + udelay(5); +} + +static u32 combo_phy_read(u8 sata_port, u32 addr) +{ + combo_phy_wait_for_ready(sata_port); + __combo_phy_reg_write(sata_port, SERDES_CR_ADDR, addr); + __combo_phy_reg_write(sata_port, SERDES_CR_CTL, CR_START); + combo_phy_wait_for_ready(sata_port); + return __combo_phy_reg_read(sata_port, SERDES_CR_DATA); +} + +static void combo_phy_write(u8 sata_port, u32 addr, u32 data) +{ + combo_phy_wait_for_ready(sata_port); + __combo_phy_reg_write(sata_port, SERDES_CR_ADDR, addr); + __combo_phy_reg_write(sata_port, SERDES_CR_DATA, data); + __combo_phy_reg_write(sata_port, SERDES_CR_CTL, CR_WR_RDN | CR_START); +} + +static void highbank_cphy_disable_overrides(u8 sata_port) +{ + u8 lane = port_data[sata_port].lane_mapping; + u32 tmp; + if (unlikely(port_data[sata_port].phy_base == NULL)) + return; + tmp = combo_phy_read(sata_port, CPHY_RX_INPUT_STS + lane * SPHY_LANE); + tmp &= ~CPHY_SATA_OVERRIDE; + combo_phy_write(sata_port, CPHY_OVERRIDE + lane * SPHY_LANE, tmp); +} + +static void cphy_override_rx_mode(u8 sata_port, u32 val) +{ + u8 lane = port_data[sata_port].lane_mapping; + u32 tmp; + tmp = combo_phy_read(sata_port, CPHY_RX_INPUT_STS + lane * SPHY_LANE); + tmp &= ~CPHY_SATA_OVERRIDE; + combo_phy_write(sata_port, CPHY_OVERRIDE + lane * SPHY_LANE, tmp); + + tmp |= CPHY_SATA_OVERRIDE; + combo_phy_write(sata_port, CPHY_OVERRIDE + lane * SPHY_LANE, tmp); + + tmp &= ~CPHY_SATA_DPLL_MODE; + tmp |= val << CPHY_SATA_DPLL_SHIFT; + combo_phy_write(sata_port, CPHY_OVERRIDE + lane * SPHY_LANE, tmp); + + tmp |= CPHY_SATA_DPLL_RESET; + combo_phy_write(sata_port, CPHY_OVERRIDE + lane * SPHY_LANE, tmp); + + tmp &= ~CPHY_SATA_DPLL_RESET; + combo_phy_write(sata_port, CPHY_OVERRIDE + lane * SPHY_LANE, tmp); + + msleep(15); +} + +static void highbank_cphy_override_lane(u8 sata_port) +{ + u8 lane = port_data[sata_port].lane_mapping; + u32 tmp, k = 0; + + if (unlikely(port_data[sata_port].phy_base == NULL)) + return; + do { + tmp = combo_phy_read(sata_port, CPHY_RX_INPUT_STS + + lane * SPHY_LANE); + } while ((tmp & SPHY_HALF_RATE) && (k++ < 1000)); + cphy_override_rx_mode(sata_port, 3); +} + +static int highbank_initialize_phys(struct device *dev, void __iomem *addr) +{ + struct device_node *sata_node = dev->of_node; + int phy_count = 0, phy, port = 0; + void __iomem *cphy_base[CPHY_PHY_COUNT]; + struct device_node *phy_nodes[CPHY_PHY_COUNT]; + memset(port_data, 0, sizeof(struct phy_lane_info) * CPHY_PORT_COUNT); + memset(phy_nodes, 0, sizeof(struct device_node*) * CPHY_PHY_COUNT); + + do { + u32 tmp; + struct of_phandle_args phy_data; + if (of_parse_phandle_with_args(sata_node, + "calxeda,port-phys", "#phy-cells", + port, &phy_data)) + break; + for (phy = 0; phy < phy_count; phy++) { + if (phy_nodes[phy] == phy_data.np) + break; + } + if (phy_nodes[phy] == NULL) { + phy_nodes[phy] = phy_data.np; + cphy_base[phy] = of_iomap(phy_nodes[phy], 0); + if (cphy_base[phy] == NULL) { + return 0; + } + phy_count += 1; + } + port_data[port].lane_mapping = phy_data.args[0]; + of_property_read_u32(phy_nodes[phy], "phydev", &tmp); + port_data[port].phy_devs = tmp; + port_data[port].phy_base = cphy_base[phy]; + of_node_put(phy_data.np); + port += 1; + } while (port < CPHY_PORT_COUNT); + return 0; +} + +static int ahci_highbank_hardreset(struct ata_link *link, unsigned int *class, + unsigned long deadline) +{ + const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context); + struct ata_port *ap = link->ap; + struct ahci_port_priv *pp = ap->private_data; + u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; + struct ata_taskfile tf; + bool online; + u32 sstatus; + int rc; + int retry = 10; + + ahci_stop_engine(ap); + + /* clear D2H reception area to properly wait for D2H FIS */ + ata_tf_init(link->device, &tf); + tf.command = 0x80; + ata_tf_to_fis(&tf, 0, 0, d2h_fis); + + do { + highbank_cphy_disable_overrides(link->ap->port_no); + rc = sata_link_hardreset(link, timing, deadline, &online, NULL); + highbank_cphy_override_lane(link->ap->port_no); + + /* If the status is 1, we are connected, but the link did not + * come up. So retry resetting the link again. + */ + if (sata_scr_read(link, SCR_STATUS, &sstatus)) + break; + if (!(sstatus & 0x3)) + break; + } while (!online && retry--); + + ahci_start_engine(ap); + + if (online) + *class = ahci_dev_classify(ap); + + return rc; +} + +static struct ata_port_operations ahci_highbank_ops = { + .inherits = &ahci_ops, + .hardreset = ahci_highbank_hardreset, +}; + +static const struct ata_port_info ahci_highbank_port_info = { + .flags = AHCI_FLAG_COMMON, + .pio_mask = ATA_PIO4, + .udma_mask = ATA_UDMA6, + .port_ops = &ahci_highbank_ops, +}; + +static struct scsi_host_template ahci_highbank_platform_sht = { + AHCI_SHT("highbank-ahci"), +}; + +static const struct of_device_id ahci_of_match[] = { + { .compatible = "calxeda,hb-ahci" }, + {}, +}; +MODULE_DEVICE_TABLE(of, ahci_of_match); + +static int __init ahci_highbank_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct ahci_host_priv *hpriv; + struct ata_host *host; + struct resource *mem; + int irq; + int n_ports; + int i; + int rc; + struct ata_port_info pi = ahci_highbank_port_info; + const struct ata_port_info *ppi[] = { &pi, NULL }; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) { + dev_err(dev, "no mmio space\n"); + return -EINVAL; + } + + irq = platform_get_irq(pdev, 0); + if (irq <= 0) { + dev_err(dev, "no irq\n"); + return -EINVAL; + } + + hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL); + if (!hpriv) { + dev_err(dev, "can't alloc ahci_host_priv\n"); + return -ENOMEM; + } + + hpriv->flags |= (unsigned long)pi.private_data; + + hpriv->mmio = devm_ioremap(dev, mem->start, resource_size(mem)); + if (!hpriv->mmio) { + dev_err(dev, "can't map %pR\n", mem); + return -ENOMEM; + } + + rc = highbank_initialize_phys(dev, hpriv->mmio); + if (rc) + return rc; + + + ahci_save_initial_config(dev, hpriv, 0, 0); + + /* prepare host */ + if (hpriv->cap & HOST_CAP_NCQ) + pi.flags |= ATA_FLAG_NCQ; + + if (hpriv->cap & HOST_CAP_PMP) + pi.flags |= ATA_FLAG_PMP; + + ahci_set_em_messages(hpriv, &pi); + + /* CAP.NP sometimes indicate the index of the last enabled + * port, at other times, that of the last possible port, so + * determining the maximum port number requires looking at + * both CAP.NP and port_map. + */ + n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map)); + + host = ata_host_alloc_pinfo(dev, ppi, n_ports); + if (!host) { + rc = -ENOMEM; + goto err0; + } + + host->private_data = hpriv; + + if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss) + host->flags |= ATA_HOST_PARALLEL_SCAN; + + if (pi.flags & ATA_FLAG_EM) + ahci_reset_em(host); + + for (i = 0; i < host->n_ports; i++) { + struct ata_port *ap = host->ports[i]; + + ata_port_desc(ap, "mmio %pR", mem); + ata_port_desc(ap, "port 0x%x", 0x100 + ap->port_no * 0x80); + + /* set enclosure management message type */ + if (ap->flags & ATA_FLAG_EM) + ap->em_message_type = hpriv->em_msg_type; + + /* disabled/not-implemented port */ + if (!(hpriv->port_map & (1 << i))) + ap->ops = &ata_dummy_port_ops; + } + + rc = ahci_reset_controller(host); + if (rc) + goto err0; + + ahci_init_controller(host); + ahci_print_info(host, "platform"); + + rc = ata_host_activate(host, irq, ahci_interrupt, 0, + &ahci_highbank_platform_sht); + if (rc) + goto err0; + + return 0; +err0: + return rc; +} + +static int __devexit ahci_highbank_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct ata_host *host = dev_get_drvdata(dev); + + ata_host_detach(host); + + return 0; +} + +#ifdef CONFIG_PM +static int ahci_highbank_suspend(struct device *dev) +{ + struct ata_host *host = dev_get_drvdata(dev); + struct ahci_host_priv *hpriv = host->private_data; + void __iomem *mmio = hpriv->mmio; + u32 ctl; + int rc; + + if (hpriv->flags & AHCI_HFLAG_NO_SUSPEND) { + dev_err(dev, "firmware update required for suspend/resume\n"); + return -EIO; + } + + /* + * AHCI spec rev1.1 section 8.3.3: + * Software must disable interrupts prior to requesting a + * transition of the HBA to D3 state. + */ + ctl = readl(mmio + HOST_CTL); + ctl &= ~HOST_IRQ_EN; + writel(ctl, mmio + HOST_CTL); + readl(mmio + HOST_CTL); /* flush */ + + rc = ata_host_suspend(host, PMSG_SUSPEND); + if (rc) + return rc; + + return 0; +} + +static int ahci_highbank_resume(struct device *dev) +{ + struct ata_host *host = dev_get_drvdata(dev); + int rc; + + if (dev->power.power_state.event == PM_EVENT_SUSPEND) { + rc = ahci_reset_controller(host); + if (rc) + return rc; + + ahci_init_controller(host); + } + + ata_host_resume(host); + + return 0; +} +#endif + +SIMPLE_DEV_PM_OPS(ahci_highbank_pm_ops, + ahci_highbank_suspend, ahci_highbank_resume); + +static struct platform_driver ahci_highbank_driver = { + .remove = __devexit_p(ahci_highbank_remove), + .driver = { + .name = "highbank-ahci", + .owner = THIS_MODULE, + .of_match_table = ahci_of_match, + .pm = &ahci_highbank_pm_ops, + }, + .probe = ahci_highbank_probe, +}; + +module_platform_driver(ahci_highbank_driver); + +MODULE_DESCRIPTION("Calxeda Highbank AHCI SATA platform driver"); +MODULE_AUTHOR("Mark Langsdorf "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("sata:highbank"); -- cgit v0.10.2 From 3f09e6c0d32398b777b00c21053a1ef5f840b1af Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 27 Aug 2012 10:37:17 +0530 Subject: pata_arasan: Add clk_{un}prepare() support clk_{un}prepare is mandatory for platforms using common clock framework. Since this driver is used by SPEAr platform, which supports common clock framework, add clk_{un}prepare() support for it. Signed-off-by: Viresh Kumar Signed-off-by: Jeff Garzik diff --git a/drivers/ata/pata_arasan_cf.c b/drivers/ata/pata_arasan_cf.c index bfaa5cb..d82c6dc 100644 --- a/drivers/ata/pata_arasan_cf.c +++ b/drivers/ata/pata_arasan_cf.c @@ -310,7 +310,7 @@ static int cf_init(struct arasan_cf_dev *acdev) unsigned long flags; int ret = 0; - ret = clk_enable(acdev->clk); + ret = clk_prepare_enable(acdev->clk); if (ret) { dev_dbg(acdev->host->dev, "clock enable failed"); return ret; @@ -340,7 +340,7 @@ static void cf_exit(struct arasan_cf_dev *acdev) writel(readl(acdev->vbase + OP_MODE) & ~CFHOST_ENB, acdev->vbase + OP_MODE); spin_unlock_irqrestore(&acdev->host->lock, flags); - clk_disable(acdev->clk); + clk_disable_unprepare(acdev->clk); } static void dma_callback(void *dev) -- cgit v0.10.2 From 26fdaa7453db49de80cc216cb696233b23d0b9d1 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 27 Aug 2012 10:37:18 +0530 Subject: pata_arasan: add Device Tree probing capability SPEAr platforms now support DT and so must convert all drivers to support DT. This patch adds DT probing support for Arasan Compact Flash controller and updates its documentation too. Signed-off-by: Viresh Kumar Signed-off-by: Jeff Garzik diff --git a/Documentation/devicetree/bindings/ata/pata-arasan.txt b/Documentation/devicetree/bindings/ata/pata-arasan.txt new file mode 100644 index 0000000..95ec7f8 --- /dev/null +++ b/Documentation/devicetree/bindings/ata/pata-arasan.txt @@ -0,0 +1,17 @@ +* ARASAN PATA COMPACT FLASH CONTROLLER + +Required properties: +- compatible: "arasan,cf-spear1340" +- reg: Address range of the CF registers +- interrupt-parent: Should be the phandle for the interrupt controller + that services interrupts for this device +- interrupt: Should contain the CF interrupt number + +Example: + + cf@fc000000 { + compatible = "arasan,cf-spear1340"; + reg = <0xfc000000 0x1000>; + interrupt-parent = <&vic1>; + interrupts = <12>; + }; diff --git a/drivers/ata/pata_arasan_cf.c b/drivers/ata/pata_arasan_cf.c index d82c6dc..26201eb 100644 --- a/drivers/ata/pata_arasan_cf.c +++ b/drivers/ata/pata_arasan_cf.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -935,6 +936,14 @@ static int arasan_cf_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(arasan_cf_pm_ops, arasan_cf_suspend, arasan_cf_resume); +#ifdef CONFIG_OF +static const struct of_device_id arasan_cf_id_table[] = { + { .compatible = "arasan,cf-spear1340" }, + {} +}; +MODULE_DEVICE_TABLE(of, arasan_cf_id_table); +#endif + static struct platform_driver arasan_cf_driver = { .probe = arasan_cf_probe, .remove = __devexit_p(arasan_cf_remove), @@ -942,6 +951,7 @@ static struct platform_driver arasan_cf_driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, .pm = &arasan_cf_pm_ops, + .of_match_table = of_match_ptr(arasan_cf_id_table), }, }; -- cgit v0.10.2 From f1e70c2c535923de253eea2021376a936eb8d478 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 27 Aug 2012 10:37:19 +0530 Subject: ata/ahci_platform: Add clock framework support On many architectures, drivers are supposed to prepare/unprepare & enable/disable functional clock of device. This patch adds clock support for ahci_platform. Signed-off-by: Viresh Kumar Signed-off-by: Jeff Garzik diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h index 6441cbe..9be4712 100644 --- a/drivers/ata/ahci.h +++ b/drivers/ata/ahci.h @@ -35,6 +35,7 @@ #ifndef _AHCI_H #define _AHCI_H +#include #include /* Enclosure Management Control */ @@ -316,6 +317,7 @@ struct ahci_host_priv { u32 em_loc; /* enclosure management location */ u32 em_buf_sz; /* EM buffer size in byte */ u32 em_msg_type; /* EM message type */ + struct clk *clk; /* Only for platforms supporting clk */ }; extern int ahci_ignore_sss; diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c index dc187c7..b1ae480 100644 --- a/drivers/ata/ahci_platform.c +++ b/drivers/ata/ahci_platform.c @@ -12,6 +12,7 @@ * any later version. */ +#include #include #include #include @@ -118,6 +119,17 @@ static int __init ahci_probe(struct platform_device *pdev) return -ENOMEM; } + hpriv->clk = clk_get(dev, NULL); + if (IS_ERR(hpriv->clk)) { + dev_err(dev, "can't get clock\n"); + } else { + rc = clk_prepare_enable(hpriv->clk); + if (rc) { + dev_err(dev, "clock prepare enable failed"); + goto free_clk; + } + } + /* * Some platforms might need to prepare for mmio region access, * which could be done in the following init call. So, the mmio @@ -127,7 +139,7 @@ static int __init ahci_probe(struct platform_device *pdev) if (pdata && pdata->init) { rc = pdata->init(dev, hpriv->mmio); if (rc) - return rc; + goto disable_unprepare_clk; } ahci_save_initial_config(dev, hpriv, @@ -153,7 +165,7 @@ static int __init ahci_probe(struct platform_device *pdev) host = ata_host_alloc_pinfo(dev, ppi, n_ports); if (!host) { rc = -ENOMEM; - goto err0; + goto pdata_exit; } host->private_data = hpriv; @@ -183,7 +195,7 @@ static int __init ahci_probe(struct platform_device *pdev) rc = ahci_reset_controller(host); if (rc) - goto err0; + goto pdata_exit; ahci_init_controller(host); ahci_print_info(host, "platform"); @@ -191,12 +203,18 @@ static int __init ahci_probe(struct platform_device *pdev) rc = ata_host_activate(host, irq, ahci_interrupt, IRQF_SHARED, &ahci_platform_sht); if (rc) - goto err0; + goto pdata_exit; return 0; -err0: +pdata_exit: if (pdata && pdata->exit) pdata->exit(dev); +disable_unprepare_clk: + if (!IS_ERR(hpriv->clk)) + clk_disable_unprepare(hpriv->clk); +free_clk: + if (!IS_ERR(hpriv->clk)) + clk_put(hpriv->clk); return rc; } @@ -205,12 +223,18 @@ static int __devexit ahci_remove(struct platform_device *pdev) struct device *dev = &pdev->dev; struct ahci_platform_data *pdata = dev_get_platdata(dev); struct ata_host *host = dev_get_drvdata(dev); + struct ahci_host_priv *hpriv = host->private_data; ata_host_detach(host); if (pdata && pdata->exit) pdata->exit(dev); + if (!IS_ERR(hpriv->clk)) { + clk_disable_unprepare(hpriv->clk); + clk_put(hpriv->clk); + } + return 0; } @@ -245,6 +269,10 @@ static int ahci_suspend(struct device *dev) if (pdata && pdata->suspend) return pdata->suspend(dev); + + if (!IS_ERR(hpriv->clk)) + clk_disable_unprepare(hpriv->clk); + return 0; } @@ -252,18 +280,27 @@ static int ahci_resume(struct device *dev) { struct ahci_platform_data *pdata = dev_get_platdata(dev); struct ata_host *host = dev_get_drvdata(dev); + struct ahci_host_priv *hpriv = host->private_data; int rc; + if (!IS_ERR(hpriv->clk)) { + rc = clk_prepare_enable(hpriv->clk); + if (rc) { + dev_err(dev, "clock prepare enable failed"); + return rc; + } + } + if (pdata && pdata->resume) { rc = pdata->resume(dev); if (rc) - return rc; + goto disable_unprepare_clk; } if (dev->power.power_state.event == PM_EVENT_SUSPEND) { rc = ahci_reset_controller(host); if (rc) - return rc; + goto disable_unprepare_clk; ahci_init_controller(host); } @@ -271,6 +308,12 @@ static int ahci_resume(struct device *dev) ata_host_resume(host); return 0; + +disable_unprepare_clk: + if (!IS_ERR(hpriv->clk)) + clk_disable_unprepare(hpriv->clk); + + return rc; } #endif -- cgit v0.10.2 From 9ca7cfa4d0645c995b82261e205107463c5a0fe0 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Tue, 21 Aug 2012 22:18:50 +0400 Subject: libata-core: use ATA_LBA in ata_build_rw_tf() Since READ/WRITE FPDMA QUEUED commands are 48-bit, bit 6 of the device register means LBA, the same as for READ/WRITE DMA EXT commands. So use ATA_LBA instead of the bare number in ata_build_rw_tf()'s branch dedicated to the NCQ commands. Signed-off-by: Sergei Shtylyov Signed-off-by: Jeff Garzik diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 25daf39..2c27016 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -774,7 +774,7 @@ int ata_build_rw_tf(struct ata_taskfile *tf, struct ata_device *dev, tf->lbam = (block >> 8) & 0xff; tf->lbal = block & 0xff; - tf->device = 1 << 6; + tf->device = ATA_LBA; if (tf->flags & ATA_TFLAG_FUA) tf->device |= 1 << 7; } else if (dev->flags & ATA_DFLAG_LBA) { -- cgit v0.10.2 From 633de4cc2c049949459dd0b73d78576cd23906b5 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Thu, 13 Sep 2012 01:12:29 -0400 Subject: [libata] export ata_dev_set_feature() Signed-off-by: Jeff Garzik diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 2c27016..611050d 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4491,6 +4491,7 @@ unsigned int ata_dev_set_feature(struct ata_device *dev, u8 enable, u8 feature) DPRINTK("EXIT, err_mask=%x\n", err_mask); return err_mask; } +EXPORT_SYMBOL_GPL(ata_dev_set_feature); /** * ata_dev_init_params - Issue INIT DEV PARAMS command -- cgit v0.10.2 From 40dad0af2d5c3122d883b2baed4bb39baf6561ec Mon Sep 17 00:00:00 2001 From: Mark Langsdorf Date: Fri, 28 Sep 2012 12:23:37 -0500 Subject: [libata] Makefile: Fix build error in sata_highbank Allow sata_highbank to build even if no other users of libahci.o are built. Signed-off-by: Mark Langsdorf Signed-off-by: Jeff Garzik diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index 8b384f1..9329daf 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -9,7 +9,7 @@ obj-$(CONFIG_SATA_FSL) += sata_fsl.o obj-$(CONFIG_SATA_INIC162X) += sata_inic162x.o obj-$(CONFIG_SATA_SIL24) += sata_sil24.o obj-$(CONFIG_SATA_DWC) += sata_dwc_460ex.o -obj-$(CONFIG_SATA_HIGHBANK) += sata_highbank.o +obj-$(CONFIG_SATA_HIGHBANK) += sata_highbank.o libahci.o # SFF w/ custom DMA obj-$(CONFIG_PDC_ADMA) += pdc_adma.o -- cgit v0.10.2 From 13b74085d92feda78bad1045516d332a1e9a3407 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Fri, 28 Sep 2012 17:04:10 +0200 Subject: sata_mv: Fix warnings when no PCI Dove can be configured without PCI. We then get a number of warnings: warning: 'msi' defined but not used warning: 'mv5_sht' defined but not used warning: 'mv_dump_pci_cfg' defined but not used. Move around variables and add #ifdef as necassary to fix the warnings. Signed-off-by: Andrew Lunn Signed-off-by: Jeff Garzik diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 311be18..68f4fb5 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -79,8 +79,8 @@ * module options */ -static int msi; #ifdef CONFIG_PCI +static int msi; module_param(msi, int, S_IRUGO); MODULE_PARM_DESC(msi, "Enable use of PCI MSI (0=off, 1=on)"); #endif @@ -652,12 +652,13 @@ static u8 mv_sff_check_status(struct ata_port *ap); * because we have to allow room for worst case splitting of * PRDs for 64K boundaries in mv_fill_sg(). */ +#ifdef CONFIG_PCI static struct scsi_host_template mv5_sht = { ATA_BASE_SHT(DRV_NAME), .sg_tablesize = MV_MAX_SG_CT / 2, .dma_boundary = MV_DMA_BOUNDARY, }; - +#endif static struct scsi_host_template mv6_sht = { ATA_NCQ_SHT(DRV_NAME), .can_queue = MV_MAX_Q_DEPTH - 1, @@ -1252,7 +1253,7 @@ static void mv_dump_mem(void __iomem *start, unsigned bytes) } } #endif - +#if defined(ATA_DEBUG) || defined(CONFIG_PCI) static void mv_dump_pci_cfg(struct pci_dev *pdev, unsigned bytes) { #ifdef ATA_DEBUG @@ -1269,6 +1270,7 @@ static void mv_dump_pci_cfg(struct pci_dev *pdev, unsigned bytes) } #endif } +#endif static void mv_dump_all_regs(void __iomem *mmio_base, int port, struct pci_dev *pdev) { -- cgit v0.10.2