Merge branch 'upstream-linus' of git://github.com/jgarzik/libata-dev
* 'upstream-linus' of git://github.com/jgarzik/libata-dev: ahci: support the STA2X11 I/O Hub pata_bf54x: fix BMIDE status register emulation ata: add ata port hibernate callbacks ata: update ata port's runtime status during system resume [SCSI] runtime resume parent for child's system-resume ahci: platform support for suspend/resume libata-core: kill duplicate statement in ata_do_set_mode() pata_of_platform: remove direct dependency on OF_IRQ SATA/PATA: convert drivers/ata/* to use module_platform_driver() pata_cs5536: forward port changes from cs5536 libata-sff: use ATAPI_{COD|IO} ata: add ata port runtime PM callbacks ata: add ata port system PM callbacks [SCSI] sd: check runtime PM status in sd_shutdown [SCSI] check runtime PM status in system PM [SCSI] add flag to skip the runtime PM calls on the host ata: make ata port as parent device of scsi host ahci: start engine only during soft/hard resets
This commit is contained in:
commit
abce00f962
@ -820,7 +820,7 @@ config PATA_PLATFORM
|
|||||||
|
|
||||||
config PATA_OF_PLATFORM
|
config PATA_OF_PLATFORM
|
||||||
tristate "OpenFirmware platform device PATA support"
|
tristate "OpenFirmware platform device PATA support"
|
||||||
depends on PATA_PLATFORM && OF && OF_IRQ
|
depends on PATA_PLATFORM && OF
|
||||||
help
|
help
|
||||||
This option enables support for generic directly connected ATA
|
This option enables support for generic directly connected ATA
|
||||||
devices commonly found on embedded systems with OpenFirmware
|
devices commonly found on embedded systems with OpenFirmware
|
||||||
|
@ -52,7 +52,8 @@
|
|||||||
#define DRV_VERSION "3.0"
|
#define DRV_VERSION "3.0"
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
AHCI_PCI_BAR = 5,
|
AHCI_PCI_BAR_STA2X11 = 0,
|
||||||
|
AHCI_PCI_BAR_STANDARD = 5,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum board_ids {
|
enum board_ids {
|
||||||
@ -375,6 +376,9 @@ static const struct pci_device_id ahci_pci_tbl[] = {
|
|||||||
{ PCI_VDEVICE(SI, 0x1185), board_ahci }, /* SiS 968 */
|
{ PCI_VDEVICE(SI, 0x1185), board_ahci }, /* SiS 968 */
|
||||||
{ PCI_VDEVICE(SI, 0x0186), board_ahci }, /* SiS 968 */
|
{ PCI_VDEVICE(SI, 0x0186), board_ahci }, /* SiS 968 */
|
||||||
|
|
||||||
|
/* ST Microelectronics */
|
||||||
|
{ PCI_VDEVICE(STMICRO, 0xCC06), board_ahci }, /* ST ConneXt */
|
||||||
|
|
||||||
/* Marvell */
|
/* Marvell */
|
||||||
{ PCI_VDEVICE(MARVELL, 0x6145), board_ahci_mv }, /* 6145 */
|
{ PCI_VDEVICE(MARVELL, 0x6145), board_ahci_mv }, /* 6145 */
|
||||||
{ PCI_VDEVICE(MARVELL, 0x6121), board_ahci_mv }, /* 6121 */
|
{ PCI_VDEVICE(MARVELL, 0x6121), board_ahci_mv }, /* 6121 */
|
||||||
@ -622,6 +626,13 @@ static int ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac)
|
|||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the device fixup already set the dma_mask to some non-standard
|
||||||
|
* value, don't extend it here. This happens on STA2X11, for example.
|
||||||
|
*/
|
||||||
|
if (pdev->dma_mask && pdev->dma_mask < DMA_BIT_MASK(32))
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (using_dac &&
|
if (using_dac &&
|
||||||
!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
|
!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
|
||||||
rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
|
rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
|
||||||
@ -1026,6 +1037,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||||||
struct ahci_host_priv *hpriv;
|
struct ahci_host_priv *hpriv;
|
||||||
struct ata_host *host;
|
struct ata_host *host;
|
||||||
int n_ports, i, rc;
|
int n_ports, i, rc;
|
||||||
|
int ahci_pci_bar = AHCI_PCI_BAR_STANDARD;
|
||||||
|
|
||||||
VPRINTK("ENTER\n");
|
VPRINTK("ENTER\n");
|
||||||
|
|
||||||
@ -1057,6 +1069,10 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||||||
dev_info(&pdev->dev,
|
dev_info(&pdev->dev,
|
||||||
"PDC42819 can only drive SATA devices with this driver\n");
|
"PDC42819 can only drive SATA devices with this driver\n");
|
||||||
|
|
||||||
|
/* The Connext uses non-standard BAR */
|
||||||
|
if (pdev->vendor == PCI_VENDOR_ID_STMICRO && pdev->device == 0xCC06)
|
||||||
|
ahci_pci_bar = AHCI_PCI_BAR_STA2X11;
|
||||||
|
|
||||||
/* acquire resources */
|
/* acquire resources */
|
||||||
rc = pcim_enable_device(pdev);
|
rc = pcim_enable_device(pdev);
|
||||||
if (rc)
|
if (rc)
|
||||||
@ -1065,7 +1081,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||||||
/* AHCI controllers often implement SFF compatible interface.
|
/* AHCI controllers often implement SFF compatible interface.
|
||||||
* Grab all PCI BARs just in case.
|
* Grab all PCI BARs just in case.
|
||||||
*/
|
*/
|
||||||
rc = pcim_iomap_regions_request_all(pdev, 1 << AHCI_PCI_BAR, DRV_NAME);
|
rc = pcim_iomap_regions_request_all(pdev, 1 << ahci_pci_bar, DRV_NAME);
|
||||||
if (rc == -EBUSY)
|
if (rc == -EBUSY)
|
||||||
pcim_pin_device(pdev);
|
pcim_pin_device(pdev);
|
||||||
if (rc)
|
if (rc)
|
||||||
@ -1108,7 +1124,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||||||
if ((hpriv->flags & AHCI_HFLAG_NO_MSI) || pci_enable_msi(pdev))
|
if ((hpriv->flags & AHCI_HFLAG_NO_MSI) || pci_enable_msi(pdev))
|
||||||
pci_intx(pdev, 1);
|
pci_intx(pdev, 1);
|
||||||
|
|
||||||
hpriv->mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR];
|
hpriv->mmio = pcim_iomap_table(pdev)[ahci_pci_bar];
|
||||||
|
|
||||||
/* save initial config */
|
/* save initial config */
|
||||||
ahci_pci_save_initial_config(pdev, hpriv);
|
ahci_pci_save_initial_config(pdev, hpriv);
|
||||||
@ -1172,8 +1188,8 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||||||
for (i = 0; i < host->n_ports; i++) {
|
for (i = 0; i < host->n_ports; i++) {
|
||||||
struct ata_port *ap = host->ports[i];
|
struct ata_port *ap = host->ports[i];
|
||||||
|
|
||||||
ata_port_pbar_desc(ap, AHCI_PCI_BAR, -1, "abar");
|
ata_port_pbar_desc(ap, ahci_pci_bar, -1, "abar");
|
||||||
ata_port_pbar_desc(ap, AHCI_PCI_BAR,
|
ata_port_pbar_desc(ap, ahci_pci_bar,
|
||||||
0x100 + ap->port_no * 0x80, "port");
|
0x100 + ap->port_no * 0x80, "port");
|
||||||
|
|
||||||
/* set enclosure management message type */
|
/* set enclosure management message type */
|
||||||
|
@ -202,6 +202,71 @@ static int __devexit ahci_remove(struct platform_device *pdev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM
|
||||||
|
static int ahci_suspend(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;
|
||||||
|
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;
|
||||||
|
|
||||||
|
if (pdata && pdata->suspend)
|
||||||
|
return pdata->suspend(dev);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ahci_resume(struct device *dev)
|
||||||
|
{
|
||||||
|
struct ahci_platform_data *pdata = dev_get_platdata(dev);
|
||||||
|
struct ata_host *host = dev_get_drvdata(dev);
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (pdata && pdata->resume) {
|
||||||
|
rc = pdata->resume(dev);
|
||||||
|
if (rc)
|
||||||
|
return 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct dev_pm_ops ahci_pm_ops = {
|
||||||
|
.suspend = &ahci_suspend,
|
||||||
|
.resume = &ahci_resume,
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
static const struct of_device_id ahci_of_match[] = {
|
static const struct of_device_id ahci_of_match[] = {
|
||||||
{ .compatible = "calxeda,hb-ahci", },
|
{ .compatible = "calxeda,hb-ahci", },
|
||||||
{},
|
{},
|
||||||
@ -214,6 +279,9 @@ static struct platform_driver ahci_driver = {
|
|||||||
.name = "ahci",
|
.name = "ahci",
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.of_match_table = ahci_of_match,
|
.of_match_table = ahci_of_match,
|
||||||
|
#ifdef CONFIG_PM
|
||||||
|
.pm = &ahci_pm_ops,
|
||||||
|
#endif
|
||||||
},
|
},
|
||||||
.id_table = ahci_devtype,
|
.id_table = ahci_devtype,
|
||||||
};
|
};
|
||||||
|
@ -746,9 +746,6 @@ static void ahci_start_port(struct ata_port *ap)
|
|||||||
/* enable FIS reception */
|
/* enable FIS reception */
|
||||||
ahci_start_fis_rx(ap);
|
ahci_start_fis_rx(ap);
|
||||||
|
|
||||||
/* enable DMA */
|
|
||||||
ahci_start_engine(ap);
|
|
||||||
|
|
||||||
/* turn on LEDs */
|
/* turn on LEDs */
|
||||||
if (ap->flags & ATA_FLAG_EM) {
|
if (ap->flags & ATA_FLAG_EM) {
|
||||||
ata_for_each_link(link, ap, EDGE) {
|
ata_for_each_link(link, ap, EDGE) {
|
||||||
@ -2022,7 +2019,7 @@ static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
|
|||||||
ahci_power_down(ap);
|
ahci_power_down(ap);
|
||||||
else {
|
else {
|
||||||
ata_port_err(ap, "%s (%d)\n", emsg, rc);
|
ata_port_err(ap, "%s (%d)\n", emsg, rc);
|
||||||
ahci_start_port(ap);
|
ata_port_freeze(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -66,6 +66,7 @@
|
|||||||
#include <asm/byteorder.h>
|
#include <asm/byteorder.h>
|
||||||
#include <linux/cdrom.h>
|
#include <linux/cdrom.h>
|
||||||
#include <linux/ratelimit.h>
|
#include <linux/ratelimit.h>
|
||||||
|
#include <linux/pm_runtime.h>
|
||||||
|
|
||||||
#include "libata.h"
|
#include "libata.h"
|
||||||
#include "libata-transport.h"
|
#include "libata-transport.h"
|
||||||
@ -3248,10 +3249,10 @@ int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
|
|||||||
ata_force_xfermask(dev);
|
ata_force_xfermask(dev);
|
||||||
|
|
||||||
pio_mask = ata_pack_xfermask(dev->pio_mask, 0, 0);
|
pio_mask = ata_pack_xfermask(dev->pio_mask, 0, 0);
|
||||||
dma_mask = ata_pack_xfermask(0, dev->mwdma_mask, dev->udma_mask);
|
|
||||||
|
|
||||||
if (libata_dma_mask & mode_mask)
|
if (libata_dma_mask & mode_mask)
|
||||||
dma_mask = ata_pack_xfermask(0, dev->mwdma_mask, dev->udma_mask);
|
dma_mask = ata_pack_xfermask(0, dev->mwdma_mask,
|
||||||
|
dev->udma_mask);
|
||||||
else
|
else
|
||||||
dma_mask = 0;
|
dma_mask = 0;
|
||||||
|
|
||||||
@ -5234,73 +5235,55 @@ bool ata_link_offline(struct ata_link *link)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
static int ata_host_request_pm(struct ata_host *host, pm_message_t mesg,
|
static int ata_port_request_pm(struct ata_port *ap, pm_message_t mesg,
|
||||||
unsigned int action, unsigned int ehi_flags,
|
unsigned int action, unsigned int ehi_flags,
|
||||||
int wait)
|
int wait)
|
||||||
{
|
{
|
||||||
|
struct ata_link *link;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int i, rc;
|
int rc;
|
||||||
|
|
||||||
for (i = 0; i < host->n_ports; i++) {
|
/* Previous resume operation might still be in
|
||||||
struct ata_port *ap = host->ports[i];
|
* progress. Wait for PM_PENDING to clear.
|
||||||
struct ata_link *link;
|
*/
|
||||||
|
if (ap->pflags & ATA_PFLAG_PM_PENDING) {
|
||||||
/* Previous resume operation might still be in
|
ata_port_wait_eh(ap);
|
||||||
* progress. Wait for PM_PENDING to clear.
|
WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
|
||||||
*/
|
|
||||||
if (ap->pflags & ATA_PFLAG_PM_PENDING) {
|
|
||||||
ata_port_wait_eh(ap);
|
|
||||||
WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* request PM ops to EH */
|
|
||||||
spin_lock_irqsave(ap->lock, flags);
|
|
||||||
|
|
||||||
ap->pm_mesg = mesg;
|
|
||||||
if (wait) {
|
|
||||||
rc = 0;
|
|
||||||
ap->pm_result = &rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
ap->pflags |= ATA_PFLAG_PM_PENDING;
|
|
||||||
ata_for_each_link(link, ap, HOST_FIRST) {
|
|
||||||
link->eh_info.action |= action;
|
|
||||||
link->eh_info.flags |= ehi_flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
ata_port_schedule_eh(ap);
|
|
||||||
|
|
||||||
spin_unlock_irqrestore(ap->lock, flags);
|
|
||||||
|
|
||||||
/* wait and check result */
|
|
||||||
if (wait) {
|
|
||||||
ata_port_wait_eh(ap);
|
|
||||||
WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
|
|
||||||
if (rc)
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
/* request PM ops to EH */
|
||||||
|
spin_lock_irqsave(ap->lock, flags);
|
||||||
|
|
||||||
|
ap->pm_mesg = mesg;
|
||||||
|
if (wait) {
|
||||||
|
rc = 0;
|
||||||
|
ap->pm_result = &rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
ap->pflags |= ATA_PFLAG_PM_PENDING;
|
||||||
|
ata_for_each_link(link, ap, HOST_FIRST) {
|
||||||
|
link->eh_info.action |= action;
|
||||||
|
link->eh_info.flags |= ehi_flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
ata_port_schedule_eh(ap);
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(ap->lock, flags);
|
||||||
|
|
||||||
|
/* wait and check result */
|
||||||
|
if (wait) {
|
||||||
|
ata_port_wait_eh(ap);
|
||||||
|
WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
#define to_ata_port(d) container_of(d, struct ata_port, tdev)
|
||||||
* ata_host_suspend - suspend host
|
|
||||||
* @host: host to suspend
|
static int ata_port_suspend_common(struct device *dev, pm_message_t mesg)
|
||||||
* @mesg: PM message
|
|
||||||
*
|
|
||||||
* Suspend @host. Actual operation is performed by EH. This
|
|
||||||
* function requests EH to perform PM operations and waits for EH
|
|
||||||
* to finish.
|
|
||||||
*
|
|
||||||
* LOCKING:
|
|
||||||
* Kernel thread context (may sleep).
|
|
||||||
*
|
|
||||||
* RETURNS:
|
|
||||||
* 0 on success, -errno on failure.
|
|
||||||
*/
|
|
||||||
int ata_host_suspend(struct ata_host *host, pm_message_t mesg)
|
|
||||||
{
|
{
|
||||||
|
struct ata_port *ap = to_ata_port(dev);
|
||||||
unsigned int ehi_flags = ATA_EHI_QUIET;
|
unsigned int ehi_flags = ATA_EHI_QUIET;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
@ -5315,31 +5298,108 @@ int ata_host_suspend(struct ata_host *host, pm_message_t mesg)
|
|||||||
if (mesg.event == PM_EVENT_SUSPEND)
|
if (mesg.event == PM_EVENT_SUSPEND)
|
||||||
ehi_flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_NO_RECOVERY;
|
ehi_flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_NO_RECOVERY;
|
||||||
|
|
||||||
rc = ata_host_request_pm(host, mesg, 0, ehi_flags, 1);
|
rc = ata_port_request_pm(ap, mesg, 0, ehi_flags, 1);
|
||||||
if (rc == 0)
|
|
||||||
host->dev->power.power_state = mesg;
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ata_port_suspend(struct device *dev)
|
||||||
|
{
|
||||||
|
if (pm_runtime_suspended(dev))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return ata_port_suspend_common(dev, PMSG_SUSPEND);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ata_port_do_freeze(struct device *dev)
|
||||||
|
{
|
||||||
|
if (pm_runtime_suspended(dev))
|
||||||
|
pm_runtime_resume(dev);
|
||||||
|
|
||||||
|
return ata_port_suspend_common(dev, PMSG_FREEZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ata_port_poweroff(struct device *dev)
|
||||||
|
{
|
||||||
|
if (pm_runtime_suspended(dev))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return ata_port_suspend_common(dev, PMSG_HIBERNATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ata_port_resume_common(struct device *dev)
|
||||||
|
{
|
||||||
|
struct ata_port *ap = to_ata_port(dev);
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = ata_port_request_pm(ap, PMSG_ON, ATA_EH_RESET,
|
||||||
|
ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, 1);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ata_port_resume(struct device *dev)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = ata_port_resume_common(dev);
|
||||||
|
if (!rc) {
|
||||||
|
pm_runtime_disable(dev);
|
||||||
|
pm_runtime_set_active(dev);
|
||||||
|
pm_runtime_enable(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ata_port_runtime_idle(struct device *dev)
|
||||||
|
{
|
||||||
|
return pm_runtime_suspend(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct dev_pm_ops ata_port_pm_ops = {
|
||||||
|
.suspend = ata_port_suspend,
|
||||||
|
.resume = ata_port_resume,
|
||||||
|
.freeze = ata_port_do_freeze,
|
||||||
|
.thaw = ata_port_resume,
|
||||||
|
.poweroff = ata_port_poweroff,
|
||||||
|
.restore = ata_port_resume,
|
||||||
|
|
||||||
|
.runtime_suspend = ata_port_suspend,
|
||||||
|
.runtime_resume = ata_port_resume_common,
|
||||||
|
.runtime_idle = ata_port_runtime_idle,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ata_host_suspend - suspend host
|
||||||
|
* @host: host to suspend
|
||||||
|
* @mesg: PM message
|
||||||
|
*
|
||||||
|
* Suspend @host. Actual operation is performed by port suspend.
|
||||||
|
*/
|
||||||
|
int ata_host_suspend(struct ata_host *host, pm_message_t mesg)
|
||||||
|
{
|
||||||
|
host->dev->power.power_state = mesg;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ata_host_resume - resume host
|
* ata_host_resume - resume host
|
||||||
* @host: host to resume
|
* @host: host to resume
|
||||||
*
|
*
|
||||||
* Resume @host. Actual operation is performed by EH. This
|
* Resume @host. Actual operation is performed by port resume.
|
||||||
* function requests EH to perform PM operations and returns.
|
|
||||||
* Note that all resume operations are performed parallelly.
|
|
||||||
*
|
|
||||||
* LOCKING:
|
|
||||||
* Kernel thread context (may sleep).
|
|
||||||
*/
|
*/
|
||||||
void ata_host_resume(struct ata_host *host)
|
void ata_host_resume(struct ata_host *host)
|
||||||
{
|
{
|
||||||
ata_host_request_pm(host, PMSG_ON, ATA_EH_RESET,
|
|
||||||
ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, 0);
|
|
||||||
host->dev->power.power_state = PMSG_ON;
|
host->dev->power.power_state = PMSG_ON;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct device_type ata_port_type = {
|
||||||
|
.name = "ata_port",
|
||||||
|
#ifdef CONFIG_PM
|
||||||
|
.pm = &ata_port_pm_ops,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ata_dev_init - Initialize an ata_device structure
|
* ata_dev_init - Initialize an ata_device structure
|
||||||
* @dev: Device structure to initialize
|
* @dev: Device structure to initialize
|
||||||
|
@ -3381,6 +3381,7 @@ int ata_scsi_add_hosts(struct ata_host *host, struct scsi_host_template *sht)
|
|||||||
if (!shost)
|
if (!shost)
|
||||||
goto err_alloc;
|
goto err_alloc;
|
||||||
|
|
||||||
|
shost->eh_noresume = 1;
|
||||||
*(struct ata_port **)&shost->hostdata[0] = ap;
|
*(struct ata_port **)&shost->hostdata[0] = ap;
|
||||||
ap->scsi_host = shost;
|
ap->scsi_host = shost;
|
||||||
|
|
||||||
@ -3398,7 +3399,7 @@ int ata_scsi_add_hosts(struct ata_host *host, struct scsi_host_template *sht)
|
|||||||
*/
|
*/
|
||||||
shost->max_host_blocked = 1;
|
shost->max_host_blocked = 1;
|
||||||
|
|
||||||
rc = scsi_add_host(ap->scsi_host, ap->host->dev);
|
rc = scsi_add_host(ap->scsi_host, &ap->tdev);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto err_add;
|
goto err_add;
|
||||||
}
|
}
|
||||||
|
@ -929,11 +929,11 @@ static void atapi_pio_bytes(struct ata_queued_cmd *qc)
|
|||||||
bytes = (bc_hi << 8) | bc_lo;
|
bytes = (bc_hi << 8) | bc_lo;
|
||||||
|
|
||||||
/* shall be cleared to zero, indicating xfer of data */
|
/* shall be cleared to zero, indicating xfer of data */
|
||||||
if (unlikely(ireason & (1 << 0)))
|
if (unlikely(ireason & ATAPI_COD))
|
||||||
goto atapi_check;
|
goto atapi_check;
|
||||||
|
|
||||||
/* make sure transfer direction matches expected */
|
/* make sure transfer direction matches expected */
|
||||||
i_write = ((ireason & (1 << 1)) == 0) ? 1 : 0;
|
i_write = ((ireason & ATAPI_IO) == 0) ? 1 : 0;
|
||||||
if (unlikely(do_write != i_write))
|
if (unlikely(do_write != i_write))
|
||||||
goto atapi_check;
|
goto atapi_check;
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
#include <linux/libata.h>
|
#include <linux/libata.h>
|
||||||
#include <linux/hdreg.h>
|
#include <linux/hdreg.h>
|
||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
|
#include <linux/pm_runtime.h>
|
||||||
|
|
||||||
#include "libata.h"
|
#include "libata.h"
|
||||||
#include "libata-transport.h"
|
#include "libata-transport.h"
|
||||||
@ -279,6 +280,7 @@ int ata_tport_add(struct device *parent,
|
|||||||
struct device *dev = &ap->tdev;
|
struct device *dev = &ap->tdev;
|
||||||
|
|
||||||
device_initialize(dev);
|
device_initialize(dev);
|
||||||
|
dev->type = &ata_port_type;
|
||||||
|
|
||||||
dev->parent = get_device(parent);
|
dev->parent = get_device(parent);
|
||||||
dev->release = ata_tport_release;
|
dev->release = ata_tport_release;
|
||||||
@ -289,6 +291,9 @@ int ata_tport_add(struct device *parent,
|
|||||||
goto tport_err;
|
goto tport_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pm_runtime_set_active(dev);
|
||||||
|
pm_runtime_enable(dev);
|
||||||
|
|
||||||
transport_add_device(dev);
|
transport_add_device(dev);
|
||||||
transport_configure_device(dev);
|
transport_configure_device(dev);
|
||||||
|
|
||||||
|
@ -58,6 +58,7 @@ extern int atapi_passthru16;
|
|||||||
extern int libata_fua;
|
extern int libata_fua;
|
||||||
extern int libata_noacpi;
|
extern int libata_noacpi;
|
||||||
extern int libata_allow_tpm;
|
extern int libata_allow_tpm;
|
||||||
|
extern struct device_type ata_port_type;
|
||||||
extern struct ata_link *ata_dev_phys_link(struct ata_device *dev);
|
extern struct ata_link *ata_dev_phys_link(struct ata_device *dev);
|
||||||
extern void ata_force_cbl(struct ata_port *ap);
|
extern void ata_force_cbl(struct ata_port *ap);
|
||||||
extern u64 ata_tf_to_lba(const struct ata_taskfile *tf);
|
extern u64 ata_tf_to_lba(const struct ata_taskfile *tf);
|
||||||
|
@ -963,17 +963,7 @@ static struct platform_driver arasan_cf_driver = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init arasan_cf_init(void)
|
module_platform_driver(arasan_cf_driver);
|
||||||
{
|
|
||||||
return platform_driver_register(&arasan_cf_driver);
|
|
||||||
}
|
|
||||||
module_init(arasan_cf_init);
|
|
||||||
|
|
||||||
static void __exit arasan_cf_exit(void)
|
|
||||||
{
|
|
||||||
platform_driver_unregister(&arasan_cf_driver);
|
|
||||||
}
|
|
||||||
module_exit(arasan_cf_exit);
|
|
||||||
|
|
||||||
MODULE_AUTHOR("Viresh Kumar <viresh.kumar@st.com>");
|
MODULE_AUTHOR("Viresh Kumar <viresh.kumar@st.com>");
|
||||||
MODULE_DESCRIPTION("Arasan ATA Compact Flash driver");
|
MODULE_DESCRIPTION("Arasan ATA Compact Flash driver");
|
||||||
|
@ -454,20 +454,7 @@ static struct platform_driver pata_at91_driver = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init pata_at91_init(void)
|
module_platform_driver(pata_at91_driver);
|
||||||
{
|
|
||||||
return platform_driver_register(&pata_at91_driver);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __exit pata_at91_exit(void)
|
|
||||||
{
|
|
||||||
platform_driver_unregister(&pata_at91_driver);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
module_init(pata_at91_init);
|
|
||||||
module_exit(pata_at91_exit);
|
|
||||||
|
|
||||||
|
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
MODULE_DESCRIPTION("Driver for CF in True IDE mode on AT91SAM9260 SoC");
|
MODULE_DESCRIPTION("Driver for CF in True IDE mode on AT91SAM9260 SoC");
|
||||||
|
@ -418,14 +418,6 @@ static void bfin_set_dmamode(struct ata_port *ap, struct ata_device *adev)
|
|||||||
(tcyc_tdvs<<8 | tdvs));
|
(tcyc_tdvs<<8 | tdvs));
|
||||||
ATAPI_SET_ULTRA_TIM_2(base, (tmli<<8 | tss));
|
ATAPI_SET_ULTRA_TIM_2(base, (tmli<<8 | tss));
|
||||||
ATAPI_SET_ULTRA_TIM_3(base, (trp<<8 | tzah));
|
ATAPI_SET_ULTRA_TIM_3(base, (trp<<8 | tzah));
|
||||||
|
|
||||||
/* Enable host ATAPI Untra DMA interrupts */
|
|
||||||
ATAPI_SET_INT_MASK(base,
|
|
||||||
ATAPI_GET_INT_MASK(base)
|
|
||||||
| UDMAIN_DONE_MASK
|
|
||||||
| UDMAOUT_DONE_MASK
|
|
||||||
| UDMAIN_TERM_MASK
|
|
||||||
| UDMAOUT_TERM_MASK);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -470,10 +462,6 @@ static void bfin_set_dmamode(struct ata_port *ap, struct ata_device *adev)
|
|||||||
ATAPI_SET_MULTI_TIM_0(base, (tm<<8 | td));
|
ATAPI_SET_MULTI_TIM_0(base, (tm<<8 | td));
|
||||||
ATAPI_SET_MULTI_TIM_1(base, (tkr<<8 | tkw));
|
ATAPI_SET_MULTI_TIM_1(base, (tkr<<8 | tkw));
|
||||||
ATAPI_SET_MULTI_TIM_2(base, (teoc<<8 | th));
|
ATAPI_SET_MULTI_TIM_2(base, (teoc<<8 | th));
|
||||||
|
|
||||||
/* Enable host ATAPI Multi DMA interrupts */
|
|
||||||
ATAPI_SET_INT_MASK(base, ATAPI_GET_INT_MASK(base)
|
|
||||||
| MULTI_DONE_MASK | MULTI_TERM_MASK);
|
|
||||||
SSYNC();
|
SSYNC();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1153,15 +1141,11 @@ static unsigned char bfin_bmdma_status(struct ata_port *ap)
|
|||||||
{
|
{
|
||||||
unsigned char host_stat = 0;
|
unsigned char host_stat = 0;
|
||||||
void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
|
void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
|
||||||
unsigned short int_status = ATAPI_GET_INT_STATUS(base);
|
|
||||||
|
|
||||||
if (ATAPI_GET_STATUS(base) & (MULTI_XFER_ON|ULTRA_XFER_ON))
|
if (ATAPI_GET_STATUS(base) & (MULTI_XFER_ON | ULTRA_XFER_ON))
|
||||||
host_stat |= ATA_DMA_ACTIVE;
|
host_stat |= ATA_DMA_ACTIVE;
|
||||||
if (int_status & (MULTI_DONE_INT|UDMAIN_DONE_INT|UDMAOUT_DONE_INT|
|
if (ATAPI_GET_INT_STATUS(base) & ATAPI_DEV_INT)
|
||||||
ATAPI_DEV_INT))
|
|
||||||
host_stat |= ATA_DMA_INTR;
|
host_stat |= ATA_DMA_INTR;
|
||||||
if (int_status & (MULTI_TERM_INT|UDMAIN_TERM_INT|UDMAOUT_TERM_INT))
|
|
||||||
host_stat |= ATA_DMA_ERR|ATA_DMA_INTR;
|
|
||||||
|
|
||||||
dev_dbg(ap->dev, "ATAPI: host_stat=0x%x\n", host_stat);
|
dev_dbg(ap->dev, "ATAPI: host_stat=0x%x\n", host_stat);
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* pata_cs5536.c - CS5536 PATA for new ATA layer
|
* pata_cs5536.c - CS5536 PATA for new ATA layer
|
||||||
* (C) 2007 Martin K. Petersen <mkp@mkp.net>
|
* (C) 2007 Martin K. Petersen <mkp@mkp.net>
|
||||||
|
* (C) 2011 Bartlomiej Zolnierkiewicz
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
@ -55,24 +56,16 @@ MODULE_PARM_DESC(msr, "Force using MSR to configure IDE function (Default: 0)");
|
|||||||
#define DRV_VERSION "0.0.8"
|
#define DRV_VERSION "0.0.8"
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
CFG = 0,
|
MSR_IDE_CFG = 0x51300010,
|
||||||
DTC = 1,
|
|
||||||
CAST = 2,
|
|
||||||
ETC = 3,
|
|
||||||
|
|
||||||
MSR_IDE_BASE = 0x51300000,
|
|
||||||
MSR_IDE_CFG = (MSR_IDE_BASE + 0x10),
|
|
||||||
MSR_IDE_DTC = (MSR_IDE_BASE + 0x12),
|
|
||||||
MSR_IDE_CAST = (MSR_IDE_BASE + 0x13),
|
|
||||||
MSR_IDE_ETC = (MSR_IDE_BASE + 0x14),
|
|
||||||
|
|
||||||
PCI_IDE_CFG = 0x40,
|
PCI_IDE_CFG = 0x40,
|
||||||
PCI_IDE_DTC = 0x48,
|
|
||||||
PCI_IDE_CAST = 0x4c,
|
|
||||||
PCI_IDE_ETC = 0x50,
|
|
||||||
|
|
||||||
IDE_CFG_CHANEN = 0x2,
|
CFG = 0,
|
||||||
IDE_CFG_CABLE = 0x10000,
|
DTC = 2,
|
||||||
|
CAST = 3,
|
||||||
|
ETC = 4,
|
||||||
|
|
||||||
|
IDE_CFG_CHANEN = (1 << 1),
|
||||||
|
IDE_CFG_CABLE = (1 << 17) | (1 << 16),
|
||||||
|
|
||||||
IDE_D0_SHIFT = 24,
|
IDE_D0_SHIFT = 24,
|
||||||
IDE_D1_SHIFT = 16,
|
IDE_D1_SHIFT = 16,
|
||||||
@ -84,45 +77,50 @@ enum {
|
|||||||
IDE_CAST_CMD_MASK = 0xff,
|
IDE_CAST_CMD_MASK = 0xff,
|
||||||
IDE_CAST_CMD_SHIFT = 24,
|
IDE_CAST_CMD_SHIFT = 24,
|
||||||
|
|
||||||
IDE_ETC_NODMA = 0x03,
|
IDE_ETC_UDMA_MASK = 0xc0,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const u32 msr_reg[4] = {
|
static int cs5536_read(struct pci_dev *pdev, int reg, u32 *val)
|
||||||
MSR_IDE_CFG, MSR_IDE_DTC, MSR_IDE_CAST, MSR_IDE_ETC,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const u8 pci_reg[4] = {
|
|
||||||
PCI_IDE_CFG, PCI_IDE_DTC, PCI_IDE_CAST, PCI_IDE_ETC,
|
|
||||||
};
|
|
||||||
|
|
||||||
static inline int cs5536_read(struct pci_dev *pdev, int reg, u32 *val)
|
|
||||||
{
|
{
|
||||||
if (unlikely(use_msr)) {
|
if (unlikely(use_msr)) {
|
||||||
u32 dummy __maybe_unused;
|
u32 dummy __maybe_unused;
|
||||||
|
|
||||||
rdmsr(msr_reg[reg], *val, dummy);
|
rdmsr(MSR_IDE_CFG + reg, *val, dummy);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return pci_read_config_dword(pdev, pci_reg[reg], val);
|
return pci_read_config_dword(pdev, PCI_IDE_CFG + reg * 4, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int cs5536_write(struct pci_dev *pdev, int reg, int val)
|
static int cs5536_write(struct pci_dev *pdev, int reg, int val)
|
||||||
{
|
{
|
||||||
if (unlikely(use_msr)) {
|
if (unlikely(use_msr)) {
|
||||||
wrmsr(msr_reg[reg], val, 0);
|
wrmsr(MSR_IDE_CFG + reg, val, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return pci_write_config_dword(pdev, pci_reg[reg], val);
|
return pci_write_config_dword(pdev, PCI_IDE_CFG + reg * 4, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cs5536_program_dtc(struct ata_device *adev, u8 tim)
|
||||||
|
{
|
||||||
|
struct pci_dev *pdev = to_pci_dev(adev->link->ap->host->dev);
|
||||||
|
int dshift = adev->devno ? IDE_D1_SHIFT : IDE_D0_SHIFT;
|
||||||
|
u32 dtc;
|
||||||
|
|
||||||
|
cs5536_read(pdev, DTC, &dtc);
|
||||||
|
dtc &= ~(IDE_DRV_MASK << dshift);
|
||||||
|
dtc |= tim << dshift;
|
||||||
|
cs5536_write(pdev, DTC, dtc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* cs5536_cable_detect - detect cable type
|
* cs5536_cable_detect - detect cable type
|
||||||
* @ap: Port to detect on
|
* @ap: Port to detect on
|
||||||
*
|
*
|
||||||
* Perform cable detection for ATA66 capable cable. Return a libata
|
* Perform cable detection for ATA66 capable cable.
|
||||||
* cable type.
|
*
|
||||||
|
* Returns a cable type.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int cs5536_cable_detect(struct ata_port *ap)
|
static int cs5536_cable_detect(struct ata_port *ap)
|
||||||
@ -132,7 +130,7 @@ static int cs5536_cable_detect(struct ata_port *ap)
|
|||||||
|
|
||||||
cs5536_read(pdev, CFG, &cfg);
|
cs5536_read(pdev, CFG, &cfg);
|
||||||
|
|
||||||
if (cfg & (IDE_CFG_CABLE << ap->port_no))
|
if (cfg & IDE_CFG_CABLE)
|
||||||
return ATA_CBL_PATA80;
|
return ATA_CBL_PATA80;
|
||||||
else
|
else
|
||||||
return ATA_CBL_PATA40;
|
return ATA_CBL_PATA40;
|
||||||
@ -162,19 +160,15 @@ static void cs5536_set_piomode(struct ata_port *ap, struct ata_device *adev)
|
|||||||
struct ata_device *pair = ata_dev_pair(adev);
|
struct ata_device *pair = ata_dev_pair(adev);
|
||||||
int mode = adev->pio_mode - XFER_PIO_0;
|
int mode = adev->pio_mode - XFER_PIO_0;
|
||||||
int cmdmode = mode;
|
int cmdmode = mode;
|
||||||
int dshift = adev->devno ? IDE_D1_SHIFT : IDE_D0_SHIFT;
|
|
||||||
int cshift = adev->devno ? IDE_CAST_D1_SHIFT : IDE_CAST_D0_SHIFT;
|
int cshift = adev->devno ? IDE_CAST_D1_SHIFT : IDE_CAST_D0_SHIFT;
|
||||||
u32 dtc, cast, etc;
|
u32 cast;
|
||||||
|
|
||||||
if (pair)
|
if (pair)
|
||||||
cmdmode = min(mode, pair->pio_mode - XFER_PIO_0);
|
cmdmode = min(mode, pair->pio_mode - XFER_PIO_0);
|
||||||
|
|
||||||
cs5536_read(pdev, DTC, &dtc);
|
cs5536_program_dtc(adev, drv_timings[mode]);
|
||||||
cs5536_read(pdev, CAST, &cast);
|
|
||||||
cs5536_read(pdev, ETC, &etc);
|
|
||||||
|
|
||||||
dtc &= ~(IDE_DRV_MASK << dshift);
|
cs5536_read(pdev, CAST, &cast);
|
||||||
dtc |= drv_timings[mode] << dshift;
|
|
||||||
|
|
||||||
cast &= ~(IDE_CAST_DRV_MASK << cshift);
|
cast &= ~(IDE_CAST_DRV_MASK << cshift);
|
||||||
cast |= addr_timings[mode] << cshift;
|
cast |= addr_timings[mode] << cshift;
|
||||||
@ -182,12 +176,7 @@ static void cs5536_set_piomode(struct ata_port *ap, struct ata_device *adev)
|
|||||||
cast &= ~(IDE_CAST_CMD_MASK << IDE_CAST_CMD_SHIFT);
|
cast &= ~(IDE_CAST_CMD_MASK << IDE_CAST_CMD_SHIFT);
|
||||||
cast |= cmd_timings[cmdmode] << IDE_CAST_CMD_SHIFT;
|
cast |= cmd_timings[cmdmode] << IDE_CAST_CMD_SHIFT;
|
||||||
|
|
||||||
etc &= ~(IDE_DRV_MASK << dshift);
|
|
||||||
etc |= IDE_ETC_NODMA << dshift;
|
|
||||||
|
|
||||||
cs5536_write(pdev, DTC, dtc);
|
|
||||||
cs5536_write(pdev, CAST, cast);
|
cs5536_write(pdev, CAST, cast);
|
||||||
cs5536_write(pdev, ETC, etc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -208,25 +197,21 @@ static void cs5536_set_dmamode(struct ata_port *ap, struct ata_device *adev)
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
|
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
|
||||||
u32 dtc, etc;
|
u32 etc;
|
||||||
int mode = adev->dma_mode;
|
int mode = adev->dma_mode;
|
||||||
int dshift = adev->devno ? IDE_D1_SHIFT : IDE_D0_SHIFT;
|
int dshift = adev->devno ? IDE_D1_SHIFT : IDE_D0_SHIFT;
|
||||||
|
|
||||||
if (mode >= XFER_UDMA_0) {
|
cs5536_read(pdev, ETC, &etc);
|
||||||
cs5536_read(pdev, ETC, &etc);
|
|
||||||
|
|
||||||
|
if (mode >= XFER_UDMA_0) {
|
||||||
etc &= ~(IDE_DRV_MASK << dshift);
|
etc &= ~(IDE_DRV_MASK << dshift);
|
||||||
etc |= udma_timings[mode - XFER_UDMA_0] << dshift;
|
etc |= udma_timings[mode - XFER_UDMA_0] << dshift;
|
||||||
|
|
||||||
cs5536_write(pdev, ETC, etc);
|
|
||||||
} else { /* MWDMA */
|
} else { /* MWDMA */
|
||||||
cs5536_read(pdev, DTC, &dtc);
|
etc &= ~(IDE_ETC_UDMA_MASK << dshift);
|
||||||
|
cs5536_program_dtc(adev, mwdma_timings[mode - XFER_MW_DMA_0]);
|
||||||
dtc &= ~(IDE_DRV_MASK << dshift);
|
|
||||||
dtc |= mwdma_timings[mode - XFER_MW_DMA_0] << dshift;
|
|
||||||
|
|
||||||
cs5536_write(pdev, DTC, dtc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cs5536_write(pdev, ETC, etc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct scsi_host_template cs5536_sht = {
|
static struct scsi_host_template cs5536_sht = {
|
||||||
|
@ -235,17 +235,7 @@ static struct platform_driver pata_imx_driver = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init pata_imx_init(void)
|
module_platform_driver(pata_imx_driver);
|
||||||
{
|
|
||||||
return platform_driver_register(&pata_imx_driver);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __exit pata_imx_exit(void)
|
|
||||||
{
|
|
||||||
platform_driver_unregister(&pata_imx_driver);
|
|
||||||
}
|
|
||||||
module_init(pata_imx_init);
|
|
||||||
module_exit(pata_imx_exit);
|
|
||||||
|
|
||||||
MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
|
MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
|
||||||
MODULE_DESCRIPTION("low-level driver for iMX PATA");
|
MODULE_DESCRIPTION("low-level driver for iMX PATA");
|
||||||
|
@ -205,21 +205,10 @@ static struct platform_driver ixp4xx_pata_platform_driver = {
|
|||||||
.remove = __devexit_p(ixp4xx_pata_remove),
|
.remove = __devexit_p(ixp4xx_pata_remove),
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init ixp4xx_pata_init(void)
|
module_platform_driver(ixp4xx_pata_platform_driver);
|
||||||
{
|
|
||||||
return platform_driver_register(&ixp4xx_pata_platform_driver);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __exit ixp4xx_pata_exit(void)
|
|
||||||
{
|
|
||||||
platform_driver_unregister(&ixp4xx_pata_platform_driver);
|
|
||||||
}
|
|
||||||
|
|
||||||
MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
|
MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
|
||||||
MODULE_DESCRIPTION("low-level driver for ixp4xx Compact Flash PATA");
|
MODULE_DESCRIPTION("low-level driver for ixp4xx Compact Flash PATA");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
MODULE_VERSION(DRV_VERSION);
|
MODULE_VERSION(DRV_VERSION);
|
||||||
MODULE_ALIAS("platform:" DRV_NAME);
|
MODULE_ALIAS("platform:" DRV_NAME);
|
||||||
|
|
||||||
module_init(ixp4xx_pata_init);
|
|
||||||
module_exit(ixp4xx_pata_exit);
|
|
||||||
|
@ -897,26 +897,7 @@ static struct platform_driver mpc52xx_ata_of_platform_driver = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
module_platform_driver(mpc52xx_ata_of_platform_driver);
|
||||||
/* ======================================================================== */
|
|
||||||
/* Module */
|
|
||||||
/* ======================================================================== */
|
|
||||||
|
|
||||||
static int __init
|
|
||||||
mpc52xx_ata_init(void)
|
|
||||||
{
|
|
||||||
printk(KERN_INFO "ata: MPC52xx IDE/ATA libata driver\n");
|
|
||||||
return platform_driver_register(&mpc52xx_ata_of_platform_driver);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __exit
|
|
||||||
mpc52xx_ata_exit(void)
|
|
||||||
{
|
|
||||||
platform_driver_unregister(&mpc52xx_ata_of_platform_driver);
|
|
||||||
}
|
|
||||||
|
|
||||||
module_init(mpc52xx_ata_init);
|
|
||||||
module_exit(mpc52xx_ata_exit);
|
|
||||||
|
|
||||||
MODULE_AUTHOR("Sylvain Munaut <tnt@246tNt.com>");
|
MODULE_AUTHOR("Sylvain Munaut <tnt@246tNt.com>");
|
||||||
MODULE_DESCRIPTION("Freescale MPC52xx IDE/ATA libata driver");
|
MODULE_DESCRIPTION("Freescale MPC52xx IDE/ATA libata driver");
|
||||||
|
@ -12,8 +12,7 @@
|
|||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/of_address.h>
|
#include <linux/of_address.h>
|
||||||
#include <linux/of_irq.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/of_platform.h>
|
|
||||||
#include <linux/ata_platform.h>
|
#include <linux/ata_platform.h>
|
||||||
|
|
||||||
static int __devinit pata_of_platform_probe(struct platform_device *ofdev)
|
static int __devinit pata_of_platform_probe(struct platform_device *ofdev)
|
||||||
@ -22,7 +21,7 @@ static int __devinit pata_of_platform_probe(struct platform_device *ofdev)
|
|||||||
struct device_node *dn = ofdev->dev.of_node;
|
struct device_node *dn = ofdev->dev.of_node;
|
||||||
struct resource io_res;
|
struct resource io_res;
|
||||||
struct resource ctl_res;
|
struct resource ctl_res;
|
||||||
struct resource irq_res;
|
struct resource *irq_res;
|
||||||
unsigned int reg_shift = 0;
|
unsigned int reg_shift = 0;
|
||||||
int pio_mode = 0;
|
int pio_mode = 0;
|
||||||
int pio_mask;
|
int pio_mask;
|
||||||
@ -51,11 +50,9 @@ static int __devinit pata_of_platform_probe(struct platform_device *ofdev)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = of_irq_to_resource(dn, 0, &irq_res);
|
irq_res = platform_get_resource(ofdev, IORESOURCE_IRQ, 0);
|
||||||
if (!ret)
|
if (irq_res)
|
||||||
irq_res.start = irq_res.end = 0;
|
irq_res->flags = 0;
|
||||||
else
|
|
||||||
irq_res.flags = 0;
|
|
||||||
|
|
||||||
prop = of_get_property(dn, "reg-shift", NULL);
|
prop = of_get_property(dn, "reg-shift", NULL);
|
||||||
if (prop)
|
if (prop)
|
||||||
@ -75,7 +72,7 @@ static int __devinit pata_of_platform_probe(struct platform_device *ofdev)
|
|||||||
pio_mask = 1 << pio_mode;
|
pio_mask = 1 << pio_mode;
|
||||||
pio_mask |= (1 << pio_mode) - 1;
|
pio_mask |= (1 << pio_mode) - 1;
|
||||||
|
|
||||||
return __pata_platform_probe(&ofdev->dev, &io_res, &ctl_res, &irq_res,
|
return __pata_platform_probe(&ofdev->dev, &io_res, &ctl_res, irq_res,
|
||||||
reg_shift, pio_mask);
|
reg_shift, pio_mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,17 +98,7 @@ static struct platform_driver pata_of_platform_driver = {
|
|||||||
.remove = __devexit_p(pata_of_platform_remove),
|
.remove = __devexit_p(pata_of_platform_remove),
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init pata_of_platform_init(void)
|
module_platform_driver(pata_of_platform_driver);
|
||||||
{
|
|
||||||
return platform_driver_register(&pata_of_platform_driver);
|
|
||||||
}
|
|
||||||
module_init(pata_of_platform_init);
|
|
||||||
|
|
||||||
static void __exit pata_of_platform_exit(void)
|
|
||||||
{
|
|
||||||
platform_driver_unregister(&pata_of_platform_driver);
|
|
||||||
}
|
|
||||||
module_exit(pata_of_platform_exit);
|
|
||||||
|
|
||||||
MODULE_DESCRIPTION("OF-platform PATA driver");
|
MODULE_DESCRIPTION("OF-platform PATA driver");
|
||||||
MODULE_AUTHOR("Anton Vorontsov <avorontsov@ru.mvista.com>");
|
MODULE_AUTHOR("Anton Vorontsov <avorontsov@ru.mvista.com>");
|
||||||
|
@ -132,20 +132,9 @@ static struct platform_driver palmld_pata_platform_driver = {
|
|||||||
.remove = __devexit_p(palmld_pata_remove),
|
.remove = __devexit_p(palmld_pata_remove),
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init palmld_pata_init(void)
|
module_platform_driver(palmld_pata_platform_driver);
|
||||||
{
|
|
||||||
return platform_driver_register(&palmld_pata_platform_driver);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __exit palmld_pata_exit(void)
|
|
||||||
{
|
|
||||||
platform_driver_unregister(&palmld_pata_platform_driver);
|
|
||||||
}
|
|
||||||
|
|
||||||
MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
|
MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
|
||||||
MODULE_DESCRIPTION("PalmLD PATA driver");
|
MODULE_DESCRIPTION("PalmLD PATA driver");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
MODULE_ALIAS("platform:" DRV_NAME);
|
MODULE_ALIAS("platform:" DRV_NAME);
|
||||||
|
|
||||||
module_init(palmld_pata_init);
|
|
||||||
module_exit(palmld_pata_exit);
|
|
||||||
|
@ -256,17 +256,7 @@ static struct platform_driver pata_platform_driver = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init pata_platform_init(void)
|
module_platform_driver(pata_platform_driver);
|
||||||
{
|
|
||||||
return platform_driver_register(&pata_platform_driver);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __exit pata_platform_exit(void)
|
|
||||||
{
|
|
||||||
platform_driver_unregister(&pata_platform_driver);
|
|
||||||
}
|
|
||||||
module_init(pata_platform_init);
|
|
||||||
module_exit(pata_platform_exit);
|
|
||||||
|
|
||||||
module_param(pio_mask, int, 0);
|
module_param(pio_mask, int, 0);
|
||||||
|
|
||||||
|
@ -390,18 +390,7 @@ static struct platform_driver pxa_ata_driver = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init pxa_ata_init(void)
|
module_platform_driver(pxa_ata_driver);
|
||||||
{
|
|
||||||
return platform_driver_register(&pxa_ata_driver);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __exit pxa_ata_exit(void)
|
|
||||||
{
|
|
||||||
platform_driver_unregister(&pxa_ata_driver);
|
|
||||||
}
|
|
||||||
|
|
||||||
module_init(pxa_ata_init);
|
|
||||||
module_exit(pxa_ata_exit);
|
|
||||||
|
|
||||||
MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
|
MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
|
||||||
MODULE_DESCRIPTION("DMA-capable driver for PATA on PXA CPU");
|
MODULE_DESCRIPTION("DMA-capable driver for PATA on PXA CPU");
|
||||||
|
@ -188,9 +188,6 @@ static __devexit int rb532_pata_driver_remove(struct platform_device *pdev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* work with hotplug and coldplug */
|
|
||||||
MODULE_ALIAS("platform:" DRV_NAME);
|
|
||||||
|
|
||||||
static struct platform_driver rb532_pata_platform_driver = {
|
static struct platform_driver rb532_pata_platform_driver = {
|
||||||
.probe = rb532_pata_driver_probe,
|
.probe = rb532_pata_driver_probe,
|
||||||
.remove = __devexit_p(rb532_pata_driver_remove),
|
.remove = __devexit_p(rb532_pata_driver_remove),
|
||||||
@ -200,27 +197,13 @@ static struct platform_driver rb532_pata_platform_driver = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------ */
|
|
||||||
|
|
||||||
#define DRV_INFO DRV_DESC " version " DRV_VERSION
|
#define DRV_INFO DRV_DESC " version " DRV_VERSION
|
||||||
|
|
||||||
static int __init rb532_pata_module_init(void)
|
module_platform_driver(rb532_pata_platform_driver);
|
||||||
{
|
|
||||||
printk(KERN_INFO DRV_INFO "\n");
|
|
||||||
|
|
||||||
return platform_driver_register(&rb532_pata_platform_driver);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __exit rb532_pata_module_exit(void)
|
|
||||||
{
|
|
||||||
platform_driver_unregister(&rb532_pata_platform_driver);
|
|
||||||
}
|
|
||||||
|
|
||||||
MODULE_AUTHOR("Gabor Juhos <juhosg at openwrt.org>");
|
MODULE_AUTHOR("Gabor Juhos <juhosg at openwrt.org>");
|
||||||
MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");
|
MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");
|
||||||
MODULE_DESCRIPTION(DRV_DESC);
|
MODULE_DESCRIPTION(DRV_DESC);
|
||||||
MODULE_VERSION(DRV_VERSION);
|
MODULE_VERSION(DRV_VERSION);
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_ALIAS("platform:" DRV_NAME);
|
||||||
module_init(rb532_pata_module_init);
|
|
||||||
module_exit(rb532_pata_module_exit);
|
|
||||||
|
@ -1777,18 +1777,7 @@ static struct platform_driver sata_dwc_driver = {
|
|||||||
.remove = sata_dwc_remove,
|
.remove = sata_dwc_remove,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init sata_dwc_init(void)
|
module_platform_driver(sata_dwc_driver);
|
||||||
{
|
|
||||||
return platform_driver_register(&sata_dwc_driver);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __exit sata_dwc_exit(void)
|
|
||||||
{
|
|
||||||
platform_driver_unregister(&sata_dwc_driver);
|
|
||||||
}
|
|
||||||
|
|
||||||
module_init(sata_dwc_init);
|
|
||||||
module_exit(sata_dwc_exit);
|
|
||||||
|
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
MODULE_AUTHOR("Mark Miesfeld <mmiesfeld@amcc.com>");
|
MODULE_AUTHOR("Mark Miesfeld <mmiesfeld@amcc.com>");
|
||||||
|
@ -1452,21 +1452,9 @@ static struct platform_driver fsl_sata_driver = {
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init sata_fsl_init(void)
|
module_platform_driver(fsl_sata_driver);
|
||||||
{
|
|
||||||
platform_driver_register(&fsl_sata_driver);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __exit sata_fsl_exit(void)
|
|
||||||
{
|
|
||||||
platform_driver_unregister(&fsl_sata_driver);
|
|
||||||
}
|
|
||||||
|
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
MODULE_AUTHOR("Ashish Kalra, Freescale Semiconductor");
|
MODULE_AUTHOR("Ashish Kalra, Freescale Semiconductor");
|
||||||
MODULE_DESCRIPTION("Freescale 3.0Gbps SATA controller low level driver");
|
MODULE_DESCRIPTION("Freescale 3.0Gbps SATA controller low level driver");
|
||||||
MODULE_VERSION("1.10");
|
MODULE_VERSION("1.10");
|
||||||
|
|
||||||
module_init(sata_fsl_init);
|
|
||||||
module_exit(sata_fsl_exit);
|
|
||||||
|
@ -1812,7 +1812,7 @@ int scsi_error_handler(void *data)
|
|||||||
* what we need to do to get it up and online again (if we can).
|
* what we need to do to get it up and online again (if we can).
|
||||||
* If we fail, we end up taking the thing offline.
|
* If we fail, we end up taking the thing offline.
|
||||||
*/
|
*/
|
||||||
if (scsi_autopm_get_host(shost) != 0) {
|
if (!shost->eh_noresume && scsi_autopm_get_host(shost) != 0) {
|
||||||
SCSI_LOG_ERROR_RECOVERY(1,
|
SCSI_LOG_ERROR_RECOVERY(1,
|
||||||
printk(KERN_ERR "Error handler scsi_eh_%d "
|
printk(KERN_ERR "Error handler scsi_eh_%d "
|
||||||
"unable to autoresume\n",
|
"unable to autoresume\n",
|
||||||
@ -1833,7 +1833,8 @@ int scsi_error_handler(void *data)
|
|||||||
* which are still online.
|
* which are still online.
|
||||||
*/
|
*/
|
||||||
scsi_restart_operations(shost);
|
scsi_restart_operations(shost);
|
||||||
scsi_autopm_put_host(shost);
|
if (!shost->eh_noresume)
|
||||||
|
scsi_autopm_put_host(shost);
|
||||||
set_current_state(TASK_INTERRUPTIBLE);
|
set_current_state(TASK_INTERRUPTIBLE);
|
||||||
}
|
}
|
||||||
__set_current_state(TASK_RUNNING);
|
__set_current_state(TASK_RUNNING);
|
||||||
|
@ -49,8 +49,22 @@ static int scsi_bus_suspend_common(struct device *dev, pm_message_t msg)
|
|||||||
{
|
{
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
if (scsi_is_sdev_device(dev))
|
if (scsi_is_sdev_device(dev)) {
|
||||||
|
/*
|
||||||
|
* sd is the only high-level SCSI driver to implement runtime
|
||||||
|
* PM, and sd treats runtime suspend, system suspend, and
|
||||||
|
* system hibernate identically (but not system freeze).
|
||||||
|
*/
|
||||||
|
if (pm_runtime_suspended(dev)) {
|
||||||
|
if (msg.event == PM_EVENT_SUSPEND ||
|
||||||
|
msg.event == PM_EVENT_HIBERNATE)
|
||||||
|
return 0; /* already suspended */
|
||||||
|
|
||||||
|
/* wake up device so that FREEZE will succeed */
|
||||||
|
pm_runtime_resume(dev);
|
||||||
|
}
|
||||||
err = scsi_dev_type_suspend(dev, msg);
|
err = scsi_dev_type_suspend(dev, msg);
|
||||||
|
}
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,8 +72,17 @@ static int scsi_bus_resume_common(struct device *dev)
|
|||||||
{
|
{
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
if (scsi_is_sdev_device(dev))
|
if (scsi_is_sdev_device(dev)) {
|
||||||
|
/*
|
||||||
|
* Parent device may have runtime suspended as soon as
|
||||||
|
* it is woken up during the system resume.
|
||||||
|
*
|
||||||
|
* Resume it on behalf of child.
|
||||||
|
*/
|
||||||
|
pm_runtime_get_sync(dev->parent);
|
||||||
err = scsi_dev_type_resume(dev);
|
err = scsi_dev_type_resume(dev);
|
||||||
|
pm_runtime_put_sync(dev->parent);
|
||||||
|
}
|
||||||
|
|
||||||
if (err == 0) {
|
if (err == 0) {
|
||||||
pm_runtime_disable(dev);
|
pm_runtime_disable(dev);
|
||||||
|
@ -50,6 +50,7 @@
|
|||||||
#include <linux/string_helpers.h>
|
#include <linux/string_helpers.h>
|
||||||
#include <linux/async.h>
|
#include <linux/async.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
#include <linux/pm_runtime.h>
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
#include <asm/unaligned.h>
|
#include <asm/unaligned.h>
|
||||||
|
|
||||||
@ -2741,6 +2742,9 @@ static void sd_shutdown(struct device *dev)
|
|||||||
if (!sdkp)
|
if (!sdkp)
|
||||||
return; /* this can happen */
|
return; /* this can happen */
|
||||||
|
|
||||||
|
if (pm_runtime_suspended(dev))
|
||||||
|
goto exit;
|
||||||
|
|
||||||
if (sdkp->WCE) {
|
if (sdkp->WCE) {
|
||||||
sd_printk(KERN_NOTICE, sdkp, "Synchronizing SCSI cache\n");
|
sd_printk(KERN_NOTICE, sdkp, "Synchronizing SCSI cache\n");
|
||||||
sd_sync_cache(sdkp);
|
sd_sync_cache(sdkp);
|
||||||
@ -2751,6 +2755,7 @@ static void sd_shutdown(struct device *dev)
|
|||||||
sd_start_stop_device(sdkp, 0);
|
sd_start_stop_device(sdkp, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
scsi_disk_put(sdkp);
|
scsi_disk_put(sdkp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,6 +23,8 @@ struct ata_port_info;
|
|||||||
struct ahci_platform_data {
|
struct ahci_platform_data {
|
||||||
int (*init)(struct device *dev, void __iomem *addr);
|
int (*init)(struct device *dev, void __iomem *addr);
|
||||||
void (*exit)(struct device *dev);
|
void (*exit)(struct device *dev);
|
||||||
|
int (*suspend)(struct device *dev);
|
||||||
|
int (*resume)(struct device *dev);
|
||||||
const struct ata_port_info *ata_port_info;
|
const struct ata_port_info *ata_port_info;
|
||||||
unsigned int force_port_map;
|
unsigned int force_port_map;
|
||||||
unsigned int mask_port_map;
|
unsigned int mask_port_map;
|
||||||
|
@ -669,6 +669,9 @@ struct Scsi_Host {
|
|||||||
/* Asynchronous scan in progress */
|
/* Asynchronous scan in progress */
|
||||||
unsigned async_scan:1;
|
unsigned async_scan:1;
|
||||||
|
|
||||||
|
/* Don't resume host in EH */
|
||||||
|
unsigned eh_noresume:1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Optional work queue to be utilized by the transport
|
* Optional work queue to be utilized by the transport
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user