Commit 8a32f81a authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'ata-5.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/dlemoal/libata

Pull ata updates from Damien Le Moal:
 "For this cycle, the libata.force kernel parameter changes stand out.
  Beside that, some small cleanups in various drivers. In more detail:

   - Changes to the pata_mpc52xx driver in preparation for powerpc's
     asm/prom.h cleanup, from Christophe.

   - Improved ATA command allocation, from John.

   - Various small cleanups to the pata_via, pata_sil680, pata_ftide010,
     sata_gemini, ahci_brcm drivers and to libata-core, from Sergey,
     Diego, Ruyi, Mighao and Jiabing.

   - Add support for the RZ/G2H SoC to the rcar-sata driver, from Lad.

   - AHCI RAID ID cleanup, from Dan.

   - Improvement to the libata.force kernel parameter to allow most
     horkage flags to be manually forced for debugging drive issues in
     the field without needing recompiling a kernel, from me"

* tag 'ata-5.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/dlemoal/libata:
  ata: pata_ftide010: Remove unneeded ERROR check before clk_disable_unprepare
  doc: admin-guide: Update libata kernel parameters
  ata: libata-core: Allow forcing most horkage flags
  ata: libata-core: Improve link flags forced settings
  ata: libata-core: Refactor force_tbl definition
  ata: libata-core: cleanup ata_device_blacklist
  ata: simplify the return expression of brcm_ahci_remove
  ata: Make use of the helper function devm_platform_ioremap_resource()
  ata: libata-core: replace "its" with "it is"
  ahci: Add a generic 'controller2' RAID id
  dt-bindings: ata: renesas,rcar-sata: Add r8a774e1 support
  ata: pata_via: fix sloppy typing in via_do_set_mode()
  ata: pata_sil680: fix result type of sil680_sel{dev|reg}()
  ata: libata-core: fix parameter type in ata_xfer_mode2shift()
  libata: Improve ATA queued command allocation
  ata: pata_mpc52xx: Prepare cleanup of powerpc's asm/prom.h
parents 5dc92186 71abb4df
......@@ -2622,14 +2622,14 @@
when set.
Format: <int>
libata.force= [LIBATA] Force configurations. The format is comma-
separated list of "[ID:]VAL" where ID is
PORT[.DEVICE]. PORT and DEVICE are decimal numbers
matching port, link or device. Basically, it matches
the ATA ID string printed on console by libata. If
the whole ID part is omitted, the last PORT and DEVICE
values are used. If ID hasn't been specified yet, the
configuration applies to all ports, links and devices.
libata.force= [LIBATA] Force configurations. The format is a comma-
separated list of "[ID:]VAL" where ID is PORT[.DEVICE].
PORT and DEVICE are decimal numbers matching port, link
or device. Basically, it matches the ATA ID string
printed on console by libata. If the whole ID part is
omitted, the last PORT and DEVICE values are used. If
ID hasn't been specified yet, the configuration applies
to all ports, links and devices.
If only DEVICE is omitted, the parameter applies to
the port and all links and devices behind it. DEVICE
......@@ -2639,7 +2639,7 @@
host link and device attached to it.
The VAL specifies the configuration to force. As long
as there's no ambiguity shortcut notation is allowed.
as there is no ambiguity, shortcut notation is allowed.
For example, both 1.5 and 1.5G would work for 1.5Gbps.
The following configurations can be forced.
......@@ -2652,19 +2652,58 @@
udma[/][16,25,33,44,66,100,133] notation is also
allowed.
* nohrst, nosrst, norst: suppress hard, soft and both
resets.
* rstonce: only attempt one reset during hot-unplug
link recovery.
* [no]dbdelay: Enable or disable the extra 200ms delay
before debouncing a link PHY and device presence
detection.
* [no]ncq: Turn on or off NCQ.
* [no]ncqtrim: Turn off queued DSM TRIM.
* [no]ncqtrim: Enable or disable queued DSM TRIM.
* [no]ncqati: Enable or disable NCQ trim on ATI chipset.
* [no]trim: Enable or disable (unqueued) TRIM.
* trim_zero: Indicate that TRIM command zeroes data.
* max_trim_128m: Set 128M maximum trim size limit.
* [no]dma: Turn on or off DMA transfers.
* atapi_dmadir: Enable ATAPI DMADIR bridge support.
* atapi_mod16_dma: Enable the use of ATAPI DMA for
commands that are not a multiple of 16 bytes.
* [no]dmalog: Enable or disable the use of the
READ LOG DMA EXT command to access logs.
* [no]iddevlog: Enable or disable access to the
identify device data log.
* [no]logdir: Enable or disable access to the general
purpose log directory.
* max_sec_128: Set transfer size limit to 128 sectors.
* max_sec_1024: Set or clear transfer size limit to
1024 sectors.
* nohrst, nosrst, norst: suppress hard, soft
and both resets.
* max_sec_lba48: Set or clear transfer size limit to
65535 sectors.
* rstonce: only attempt one reset during
hot-unplug link recovery
* [no]lpm: Enable or disable link power management.
* dump_id: dump IDENTIFY data.
* [no]setxfer: Indicate if transfer speed mode setting
should be skipped.
* atapi_dmadir: Enable ATAPI DMADIR bridge support
* dump_id: Dump IDENTIFY data.
* disable: Disable this device.
......
......@@ -26,6 +26,7 @@ properties:
- items:
- enum:
- renesas,sata-r8a774b1 # RZ/G2N
- renesas,sata-r8a774e1 # RZ/G2H
- renesas,sata-r8a7795 # R-Car H3
- renesas,sata-r8a77965 # R-Car M3-N
- const: renesas,rcar-gen3-sata # generic R-Car Gen3 or RZ/G2
......
......@@ -424,12 +424,6 @@ How commands are issued
-----------------------
Internal commands
First, qc is allocated and initialized using :c:func:`ata_qc_new_init`.
Although :c:func:`ata_qc_new_init` doesn't implement any wait or retry
mechanism when qc is not available, internal commands are currently
issued only during initialization and error recovery, so no other
command is active and allocation is guaranteed to succeed.
Once allocated qc's taskfile is initialized for the command to be
executed. qc currently has two mechanisms to notify completion. One
is via ``qc->complete_fn()`` callback and the other is completion
......@@ -447,11 +441,6 @@ SCSI commands
translated. No qc is involved in processing a simulated scmd. The
result is computed right away and the scmd is completed.
For a translated scmd, :c:func:`ata_qc_new_init` is invoked to allocate a
qc and the scmd is translated into the qc. SCSI midlayer's
completion notification function pointer is stored into
``qc->scsidone``.
``qc->complete_fn()`` callback is used for completion notification. ATA
commands use :c:func:`ata_scsi_qc_complete` while ATAPI commands use
:c:func:`atapi_qc_complete`. Both functions end up calling ``qc->scsidone``
......
......@@ -324,7 +324,6 @@ static const struct pci_device_id ahci_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, 0x1d02), board_ahci }, /* PBG AHCI */
{ PCI_VDEVICE(INTEL, 0x1d04), board_ahci }, /* PBG RAID */
{ PCI_VDEVICE(INTEL, 0x1d06), board_ahci }, /* PBG RAID */
{ PCI_VDEVICE(INTEL, 0x2826), board_ahci }, /* PBG/Lewisburg RAID*/
{ PCI_VDEVICE(INTEL, 0x2323), board_ahci }, /* DH89xxCC AHCI */
{ PCI_VDEVICE(INTEL, 0x1e02), board_ahci }, /* Panther Point AHCI */
{ PCI_VDEVICE(INTEL, 0x1e03), board_ahci_low_power }, /* Panther M AHCI */
......@@ -367,7 +366,9 @@ static const struct pci_device_id ahci_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, 0x1f3e), board_ahci_avn }, /* Avoton RAID */
{ PCI_VDEVICE(INTEL, 0x1f3f), board_ahci_avn }, /* Avoton RAID */
{ PCI_VDEVICE(INTEL, 0x2823), board_ahci }, /* Wellsburg/Lewisburg AHCI*/
{ PCI_VDEVICE(INTEL, 0x2827), board_ahci }, /* Wellsburg/Lewisburg RAID*/
{ PCI_VDEVICE(INTEL, 0x2826), board_ahci }, /* *burg SATA0 'RAID' */
{ PCI_VDEVICE(INTEL, 0x2827), board_ahci }, /* *burg SATA1 'RAID' */
{ PCI_VDEVICE(INTEL, 0x282f), board_ahci }, /* *burg SATA2 'RAID' */
{ PCI_VDEVICE(INTEL, 0x43d4), board_ahci }, /* Rocket Lake PCH-H RAID */
{ PCI_VDEVICE(INTEL, 0x43d5), board_ahci }, /* Rocket Lake PCH-H RAID */
{ PCI_VDEVICE(INTEL, 0x43d6), board_ahci }, /* Rocket Lake PCH-H RAID */
......
......@@ -549,15 +549,10 @@ static int brcm_ahci_remove(struct platform_device *pdev)
struct ata_host *host = dev_get_drvdata(&pdev->dev);
struct ahci_host_priv *hpriv = host->private_data;
struct brcm_ahci_priv *priv = hpriv->plat_data;
int ret;
brcm_sata_phys_disable(priv);
ret = ata_platform_remove_one(pdev);
if (ret)
return ret;
return 0;
return ata_platform_remove_one(pdev);
}
static void brcm_ahci_shutdown(struct platform_device *pdev)
......
......@@ -96,7 +96,8 @@ struct ata_force_param {
unsigned long xfer_mask;
unsigned int horkage_on;
unsigned int horkage_off;
u16 lflags;
u16 lflags_on;
u16 lflags_off;
};
struct ata_force_ent {
......@@ -386,11 +387,17 @@ static void ata_force_link_limits(struct ata_link *link)
}
/* let lflags stack */
if (fe->param.lflags) {
link->flags |= fe->param.lflags;
if (fe->param.lflags_on) {
link->flags |= fe->param.lflags_on;
ata_link_notice(link,
"FORCE: link flag 0x%x forced -> 0x%x\n",
fe->param.lflags, link->flags);
fe->param.lflags_on, link->flags);
}
if (fe->param.lflags_off) {
link->flags &= ~fe->param.lflags_off;
ata_link_notice(link,
"FORCE: link flag 0x%x cleared -> 0x%x\n",
fe->param.lflags_off, link->flags);
}
}
}
......@@ -898,7 +905,7 @@ EXPORT_SYMBOL_GPL(ata_xfer_mode2mask);
* RETURNS:
* Matching xfer_shift, -1 if no match found.
*/
int ata_xfer_mode2shift(unsigned long xfer_mode)
int ata_xfer_mode2shift(u8 xfer_mode)
{
const struct ata_xfer_ent *ent;
......@@ -1398,7 +1405,7 @@ unsigned long ata_id_xfermask(const u16 *id)
/* But wait.. there's more. Design your standards by
* committee and you too can get a free iordy field to
* process. However its the speeds not the modes that
* process. However it is the speeds not the modes that
* are supported... Note drivers using the timing API
* will get this right anyway
*/
......@@ -3898,7 +3905,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
/* Devices where NCQ should be avoided */
/* NCQ is slow */
{ "WDC WD740ADFD-00", NULL, ATA_HORKAGE_NONCQ },
{ "WDC WD740ADFD-00NLR1", NULL, ATA_HORKAGE_NONCQ, },
{ "WDC WD740ADFD-00NLR1", NULL, ATA_HORKAGE_NONCQ },
/* http://thread.gmane.org/gmane.linux.ide/14907 */
{ "FUJITSU MHT2060BH", NULL, ATA_HORKAGE_NONCQ },
/* NCQ is broken */
......@@ -3924,23 +3931,23 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
/* drives which fail FPDMA_AA activation (some may freeze afterwards)
the ST disks also have LPM issues */
{ "ST1000LM024 HN-M101MBB", NULL, ATA_HORKAGE_BROKEN_FPDMA_AA |
ATA_HORKAGE_NOLPM, },
ATA_HORKAGE_NOLPM },
{ "VB0250EAVER", "HPG7", ATA_HORKAGE_BROKEN_FPDMA_AA },
/* Blacklist entries taken from Silicon Image 3124/3132
Windows driver .inf file - also several Linux problem reports */
{ "HTS541060G9SA00", "MB3OC60D", ATA_HORKAGE_NONCQ, },
{ "HTS541080G9SA00", "MB4OC60D", ATA_HORKAGE_NONCQ, },
{ "HTS541010G9SA00", "MBZOC60D", ATA_HORKAGE_NONCQ, },
{ "HTS541060G9SA00", "MB3OC60D", ATA_HORKAGE_NONCQ },
{ "HTS541080G9SA00", "MB4OC60D", ATA_HORKAGE_NONCQ },
{ "HTS541010G9SA00", "MBZOC60D", ATA_HORKAGE_NONCQ },
/* https://bugzilla.kernel.org/show_bug.cgi?id=15573 */
{ "C300-CTFDDAC128MAG", "0001", ATA_HORKAGE_NONCQ, },
{ "C300-CTFDDAC128MAG", "0001", ATA_HORKAGE_NONCQ },
/* Sandisk SD7/8/9s lock up hard on large trims */
{ "SanDisk SD[789]*", NULL, ATA_HORKAGE_MAX_TRIM_128M, },
{ "SanDisk SD[789]*", NULL, ATA_HORKAGE_MAX_TRIM_128M },
/* devices which puke on READ_NATIVE_MAX */
{ "HDS724040KLSA80", "KFAOA20N", ATA_HORKAGE_BROKEN_HPA, },
{ "HDS724040KLSA80", "KFAOA20N", ATA_HORKAGE_BROKEN_HPA },
{ "WDC WD3200JD-00KLB0", "WD-WCAMR1130137", ATA_HORKAGE_BROKEN_HPA },
{ "WDC WD2500JD-00HBB0", "WD-WMAL71490727", ATA_HORKAGE_BROKEN_HPA },
{ "MAXTOR 6L080L4", "A93.0500", ATA_HORKAGE_BROKEN_HPA },
......@@ -3949,22 +3956,22 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
{ "OCZ-VERTEX", "1.30", ATA_HORKAGE_BROKEN_HPA },
/* Devices which report 1 sector over size HPA */
{ "ST340823A", NULL, ATA_HORKAGE_HPA_SIZE, },
{ "ST320413A", NULL, ATA_HORKAGE_HPA_SIZE, },
{ "ST310211A", NULL, ATA_HORKAGE_HPA_SIZE, },
{ "ST340823A", NULL, ATA_HORKAGE_HPA_SIZE },
{ "ST320413A", NULL, ATA_HORKAGE_HPA_SIZE },
{ "ST310211A", NULL, ATA_HORKAGE_HPA_SIZE },
/* Devices which get the IVB wrong */
{ "QUANTUM FIREBALLlct10 05", "A03.0900", ATA_HORKAGE_IVB, },
{ "QUANTUM FIREBALLlct10 05", "A03.0900", ATA_HORKAGE_IVB },
/* Maybe we should just blacklist TSSTcorp... */
{ "TSSTcorp CDDVDW SH-S202[HJN]", "SB0[01]", ATA_HORKAGE_IVB, },
{ "TSSTcorp CDDVDW SH-S202[HJN]", "SB0[01]", ATA_HORKAGE_IVB },
/* Devices that do not need bridging limits applied */
{ "MTRON MSP-SATA*", NULL, ATA_HORKAGE_BRIDGE_OK, },
{ "BUFFALO HD-QSU2/R5", NULL, ATA_HORKAGE_BRIDGE_OK, },
{ "MTRON MSP-SATA*", NULL, ATA_HORKAGE_BRIDGE_OK },
{ "BUFFALO HD-QSU2/R5", NULL, ATA_HORKAGE_BRIDGE_OK },
/* Devices which aren't very happy with higher link speeds */
{ "WD My Book", NULL, ATA_HORKAGE_1_5_GBPS, },
{ "Seagate FreeAgent GoFlex", NULL, ATA_HORKAGE_1_5_GBPS, },
{ "WD My Book", NULL, ATA_HORKAGE_1_5_GBPS },
{ "Seagate FreeAgent GoFlex", NULL, ATA_HORKAGE_1_5_GBPS },
/*
* Devices which choke on SETXFER. Applies only if both the
......@@ -3982,57 +3989,57 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
/* 512GB MX100 with MU01 firmware has both queued TRIM and LPM issues */
{ "Crucial_CT512MX100*", "MU01", ATA_HORKAGE_NO_NCQ_TRIM |
ATA_HORKAGE_ZERO_AFTER_TRIM |
ATA_HORKAGE_NOLPM, },
ATA_HORKAGE_NOLPM },
/* 512GB MX100 with newer firmware has only LPM issues */
{ "Crucial_CT512MX100*", NULL, ATA_HORKAGE_ZERO_AFTER_TRIM |
ATA_HORKAGE_NOLPM, },
ATA_HORKAGE_NOLPM },
/* 480GB+ M500 SSDs have both queued TRIM and LPM issues */
{ "Crucial_CT480M500*", NULL, ATA_HORKAGE_NO_NCQ_TRIM |
ATA_HORKAGE_ZERO_AFTER_TRIM |
ATA_HORKAGE_NOLPM, },
ATA_HORKAGE_NOLPM },
{ "Crucial_CT960M500*", NULL, ATA_HORKAGE_NO_NCQ_TRIM |
ATA_HORKAGE_ZERO_AFTER_TRIM |
ATA_HORKAGE_NOLPM, },
ATA_HORKAGE_NOLPM },
/* These specific Samsung models/firmware-revs do not handle LPM well */
{ "SAMSUNG MZMPC128HBFU-000MV", "CXM14M1Q", ATA_HORKAGE_NOLPM, },
{ "SAMSUNG SSD PM830 mSATA *", "CXM13D1Q", ATA_HORKAGE_NOLPM, },
{ "SAMSUNG MZ7TD256HAFV-000L9", NULL, ATA_HORKAGE_NOLPM, },
{ "SAMSUNG MZ7TE512HMHP-000L1", "EXT06L0Q", ATA_HORKAGE_NOLPM, },
{ "SAMSUNG MZMPC128HBFU-000MV", "CXM14M1Q", ATA_HORKAGE_NOLPM },
{ "SAMSUNG SSD PM830 mSATA *", "CXM13D1Q", ATA_HORKAGE_NOLPM },
{ "SAMSUNG MZ7TD256HAFV-000L9", NULL, ATA_HORKAGE_NOLPM },
{ "SAMSUNG MZ7TE512HMHP-000L1", "EXT06L0Q", ATA_HORKAGE_NOLPM },
/* devices that don't properly handle queued TRIM commands */
{ "Micron_M500IT_*", "MU01", ATA_HORKAGE_NO_NCQ_TRIM |
ATA_HORKAGE_ZERO_AFTER_TRIM, },
ATA_HORKAGE_ZERO_AFTER_TRIM },
{ "Micron_M500_*", NULL, ATA_HORKAGE_NO_NCQ_TRIM |
ATA_HORKAGE_ZERO_AFTER_TRIM, },
ATA_HORKAGE_ZERO_AFTER_TRIM },
{ "Crucial_CT*M500*", NULL, ATA_HORKAGE_NO_NCQ_TRIM |
ATA_HORKAGE_ZERO_AFTER_TRIM, },
ATA_HORKAGE_ZERO_AFTER_TRIM },
{ "Micron_M5[15]0_*", "MU01", ATA_HORKAGE_NO_NCQ_TRIM |
ATA_HORKAGE_ZERO_AFTER_TRIM, },
ATA_HORKAGE_ZERO_AFTER_TRIM },
{ "Crucial_CT*M550*", "MU01", ATA_HORKAGE_NO_NCQ_TRIM |
ATA_HORKAGE_ZERO_AFTER_TRIM, },
ATA_HORKAGE_ZERO_AFTER_TRIM },
{ "Crucial_CT*MX100*", "MU01", ATA_HORKAGE_NO_NCQ_TRIM |
ATA_HORKAGE_ZERO_AFTER_TRIM, },
ATA_HORKAGE_ZERO_AFTER_TRIM },
{ "Samsung SSD 840 EVO*", NULL, ATA_HORKAGE_NO_NCQ_TRIM |
ATA_HORKAGE_NO_DMA_LOG |
ATA_HORKAGE_ZERO_AFTER_TRIM, },
ATA_HORKAGE_ZERO_AFTER_TRIM },
{ "Samsung SSD 840*", NULL, ATA_HORKAGE_NO_NCQ_TRIM |
ATA_HORKAGE_ZERO_AFTER_TRIM, },
ATA_HORKAGE_ZERO_AFTER_TRIM },
{ "Samsung SSD 850*", NULL, ATA_HORKAGE_NO_NCQ_TRIM |
ATA_HORKAGE_ZERO_AFTER_TRIM, },
ATA_HORKAGE_ZERO_AFTER_TRIM },
{ "Samsung SSD 860*", NULL, ATA_HORKAGE_NO_NCQ_TRIM |
ATA_HORKAGE_ZERO_AFTER_TRIM |
ATA_HORKAGE_NO_NCQ_ON_ATI, },
ATA_HORKAGE_NO_NCQ_ON_ATI },
{ "Samsung SSD 870*", NULL, ATA_HORKAGE_NO_NCQ_TRIM |
ATA_HORKAGE_ZERO_AFTER_TRIM |
ATA_HORKAGE_NO_NCQ_ON_ATI, },
ATA_HORKAGE_NO_NCQ_ON_ATI },
{ "FCCT*M500*", NULL, ATA_HORKAGE_NO_NCQ_TRIM |
ATA_HORKAGE_ZERO_AFTER_TRIM, },
ATA_HORKAGE_ZERO_AFTER_TRIM },
/* devices that don't properly handle TRIM commands */
{ "SuperSSpeed S238*", NULL, ATA_HORKAGE_NOTRIM, },
{ "M88V29*", NULL, ATA_HORKAGE_NOTRIM, },
{ "SuperSSpeed S238*", NULL, ATA_HORKAGE_NOTRIM },
{ "M88V29*", NULL, ATA_HORKAGE_NOTRIM },
/*
* As defined, the DRAT (Deterministic Read After Trim) and RZAT
......@@ -4050,16 +4057,16 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
* The intel 510 drive has buggy DRAT/RZAT. Explicitly exclude
* that model before whitelisting all other intel SSDs.
*/
{ "INTEL*SSDSC2MH*", NULL, 0, },
{ "INTEL*SSDSC2MH*", NULL, 0 },
{ "Micron*", NULL, ATA_HORKAGE_ZERO_AFTER_TRIM, },
{ "Crucial*", NULL, ATA_HORKAGE_ZERO_AFTER_TRIM, },
{ "INTEL*SSD*", NULL, ATA_HORKAGE_ZERO_AFTER_TRIM, },
{ "SSD*INTEL*", NULL, ATA_HORKAGE_ZERO_AFTER_TRIM, },
{ "Samsung*SSD*", NULL, ATA_HORKAGE_ZERO_AFTER_TRIM, },
{ "SAMSUNG*SSD*", NULL, ATA_HORKAGE_ZERO_AFTER_TRIM, },
{ "SAMSUNG*MZ7KM*", NULL, ATA_HORKAGE_ZERO_AFTER_TRIM, },
{ "ST[1248][0248]0[FH]*", NULL, ATA_HORKAGE_ZERO_AFTER_TRIM, },
{ "Micron*", NULL, ATA_HORKAGE_ZERO_AFTER_TRIM },
{ "Crucial*", NULL, ATA_HORKAGE_ZERO_AFTER_TRIM },
{ "INTEL*SSD*", NULL, ATA_HORKAGE_ZERO_AFTER_TRIM },
{ "SSD*INTEL*", NULL, ATA_HORKAGE_ZERO_AFTER_TRIM },
{ "Samsung*SSD*", NULL, ATA_HORKAGE_ZERO_AFTER_TRIM },
{ "SAMSUNG*SSD*", NULL, ATA_HORKAGE_ZERO_AFTER_TRIM },
{ "SAMSUNG*MZ7KM*", NULL, ATA_HORKAGE_ZERO_AFTER_TRIM },
{ "ST[1248][0248]0[FH]*", NULL, ATA_HORKAGE_ZERO_AFTER_TRIM },
/*
* Some WD SATA-I drives spin up and down erratically when the link
......@@ -4566,42 +4573,6 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words)
#endif /* __BIG_ENDIAN */
}
/**
* ata_qc_new_init - Request an available ATA command, and initialize it
* @dev: Device from whom we request an available command structure
* @tag: tag
*
* LOCKING:
* None.
*/
struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev, int tag)
{
struct ata_port *ap = dev->link->ap;
struct ata_queued_cmd *qc;
/* no command while frozen */
if (unlikely(ap->pflags & ATA_PFLAG_FROZEN))
return NULL;
/* libsas case */
if (ap->flags & ATA_FLAG_SAS_HOST) {
tag = ata_sas_allocate_tag(ap);
if (tag < 0)
return NULL;
}
qc = __ata_qc_from_tag(ap, tag);
qc->tag = qc->hw_tag = tag;
qc->scsicmd = NULL;
qc->ap = ap;
qc->dev = dev;
ata_qc_reinit(qc);
return qc;
}
/**
* ata_qc_free - free unused ata_queued_cmd
* @qc: Command to complete
......@@ -4614,19 +4585,9 @@ struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev, int tag)
*/
void ata_qc_free(struct ata_queued_cmd *qc)
{
struct ata_port *ap;
unsigned int tag;
WARN_ON_ONCE(qc == NULL); /* ata_qc_from_tag _might_ return NULL */
ap = qc->ap;
qc->flags = 0;
tag = qc->tag;
if (ata_tag_valid(tag)) {
if (ata_tag_valid(qc->tag))
qc->tag = ATA_TAG_POISON;
if (ap->flags & ATA_FLAG_SAS_HOST)
ata_sas_free_tag(tag, ap);
}
}
void __ata_qc_complete(struct ata_queued_cmd *qc)
......@@ -5605,7 +5566,7 @@ static void ata_finalize_port_ops(struct ata_port_operations *ops)
* Start and then freeze ports of @host. Started status is
* recorded in host->flags, so this function can be called
* multiple times. Ports are guaranteed to get started only
* once. If host->ops isn't initialized yet, its set to the
* once. If host->ops is not initialized yet, it is set to the
* first non-dummy port ops.
*
* LOCKING:
......@@ -6146,67 +6107,113 @@ int ata_platform_remove_one(struct platform_device *pdev)
EXPORT_SYMBOL_GPL(ata_platform_remove_one);
#ifdef CONFIG_ATA_FORCE
#define force_cbl(name, flag) \
{ #name, .cbl = (flag) }
#define force_spd_limit(spd, val) \
{ #spd, .spd_limit = (val) }
#define force_xfer(mode, shift) \
{ #mode, .xfer_mask = (1UL << (shift)) }
#define force_lflag_on(name, flags) \
{ #name, .lflags_on = (flags) }
#define force_lflag_onoff(name, flags) \
{ "no" #name, .lflags_on = (flags) }, \
{ #name, .lflags_off = (flags) }
#define force_horkage_on(name, flag) \
{ #name, .horkage_on = (flag) }
#define force_horkage_onoff(name, flag) \
{ "no" #name, .horkage_on = (flag) }, \
{ #name, .horkage_off = (flag) }
static const struct ata_force_param force_tbl[] __initconst = {
force_cbl(40c, ATA_CBL_PATA40),
force_cbl(80c, ATA_CBL_PATA80),
force_cbl(short40c, ATA_CBL_PATA40_SHORT),
force_cbl(unk, ATA_CBL_PATA_UNK),
force_cbl(ign, ATA_CBL_PATA_IGN),
force_cbl(sata, ATA_CBL_SATA),
force_spd_limit(1.5Gbps, 1),
force_spd_limit(3.0Gbps, 2),
force_xfer(pio0, ATA_SHIFT_PIO + 0),
force_xfer(pio1, ATA_SHIFT_PIO + 1),
force_xfer(pio2, ATA_SHIFT_PIO + 2),
force_xfer(pio3, ATA_SHIFT_PIO + 3),
force_xfer(pio4, ATA_SHIFT_PIO + 4),
force_xfer(pio5, ATA_SHIFT_PIO + 5),
force_xfer(pio6, ATA_SHIFT_PIO + 6),
force_xfer(mwdma0, ATA_SHIFT_MWDMA + 0),
force_xfer(mwdma1, ATA_SHIFT_MWDMA + 1),
force_xfer(mwdma2, ATA_SHIFT_MWDMA + 2),
force_xfer(mwdma3, ATA_SHIFT_MWDMA + 3),
force_xfer(mwdma4, ATA_SHIFT_MWDMA + 4),
force_xfer(udma0, ATA_SHIFT_UDMA + 0),
force_xfer(udma16, ATA_SHIFT_UDMA + 0),
force_xfer(udma/16, ATA_SHIFT_UDMA + 0),
force_xfer(udma1, ATA_SHIFT_UDMA + 1),
force_xfer(udma25, ATA_SHIFT_UDMA + 1),
force_xfer(udma/25, ATA_SHIFT_UDMA + 1),
force_xfer(udma2, ATA_SHIFT_UDMA + 2),
force_xfer(udma33, ATA_SHIFT_UDMA + 2),
force_xfer(udma/33, ATA_SHIFT_UDMA + 2),
force_xfer(udma3, ATA_SHIFT_UDMA + 3),
force_xfer(udma44, ATA_SHIFT_UDMA + 3),
force_xfer(udma/44, ATA_SHIFT_UDMA + 3),
force_xfer(udma4, ATA_SHIFT_UDMA + 4),
force_xfer(udma66, ATA_SHIFT_UDMA + 4),
force_xfer(udma/66, ATA_SHIFT_UDMA + 4),
force_xfer(udma5, ATA_SHIFT_UDMA + 5),
force_xfer(udma100, ATA_SHIFT_UDMA + 5),
force_xfer(udma/100, ATA_SHIFT_UDMA + 5),
force_xfer(udma6, ATA_SHIFT_UDMA + 6),
force_xfer(udma133, ATA_SHIFT_UDMA + 6),
force_xfer(udma/133, ATA_SHIFT_UDMA + 6),
force_xfer(udma7, ATA_SHIFT_UDMA + 7),
force_lflag_on(nohrst, ATA_LFLAG_NO_HRST),
force_lflag_on(nosrst, ATA_LFLAG_NO_SRST),
force_lflag_on(norst, ATA_LFLAG_NO_HRST | ATA_LFLAG_NO_SRST),
force_lflag_on(rstonce, ATA_LFLAG_RST_ONCE),
force_lflag_onoff(dbdelay, ATA_LFLAG_NO_DEBOUNCE_DELAY),
force_horkage_onoff(ncq, ATA_HORKAGE_NONCQ),
force_horkage_onoff(ncqtrim, ATA_HORKAGE_NO_NCQ_TRIM),
force_horkage_onoff(ncqati, ATA_HORKAGE_NO_NCQ_ON_ATI),
force_horkage_onoff(trim, ATA_HORKAGE_NOTRIM),
force_horkage_on(trim_zero, ATA_HORKAGE_ZERO_AFTER_TRIM),
force_horkage_on(max_trim_128m, ATA_HORKAGE_MAX_TRIM_128M),
force_horkage_onoff(dma, ATA_HORKAGE_NODMA),
force_horkage_on(atapi_dmadir, ATA_HORKAGE_ATAPI_DMADIR),
force_horkage_on(atapi_mod16_dma, ATA_HORKAGE_ATAPI_MOD16_DMA),
force_horkage_onoff(dmalog, ATA_HORKAGE_NO_DMA_LOG),
force_horkage_onoff(iddevlog, ATA_HORKAGE_NO_ID_DEV_LOG),
force_horkage_onoff(logdir, ATA_HORKAGE_NO_LOG_DIR),
force_horkage_on(max_sec_128, ATA_HORKAGE_MAX_SEC_128),
force_horkage_on(max_sec_1024, ATA_HORKAGE_MAX_SEC_1024),
force_horkage_on(max_sec_lba48, ATA_HORKAGE_MAX_SEC_LBA48),
force_horkage_onoff(lpm, ATA_HORKAGE_NOLPM),
force_horkage_onoff(setxfer, ATA_HORKAGE_NOSETXFER),
force_horkage_on(dump_id, ATA_HORKAGE_DUMP_ID),
force_horkage_on(disable, ATA_HORKAGE_DISABLE),
};
static int __init ata_parse_force_one(char **cur,
struct ata_force_ent *force_ent,
const char **reason)
{
static const struct ata_force_param force_tbl[] __initconst = {
{ "40c", .cbl = ATA_CBL_PATA40 },
{ "80c", .cbl = ATA_CBL_PATA80 },
{ "short40c", .cbl = ATA_CBL_PATA40_SHORT },
{ "unk", .cbl = ATA_CBL_PATA_UNK },
{ "ign", .cbl = ATA_CBL_PATA_IGN },
{ "sata", .cbl = ATA_CBL_SATA },
{ "1.5Gbps", .spd_limit = 1 },
{ "3.0Gbps", .spd_limit = 2 },
{ "noncq", .horkage_on = ATA_HORKAGE_NONCQ },
{ "ncq", .horkage_off = ATA_HORKAGE_NONCQ },
{ "noncqtrim", .horkage_on = ATA_HORKAGE_NO_NCQ_TRIM },
{ "ncqtrim", .horkage_off = ATA_HORKAGE_NO_NCQ_TRIM },
{ "noncqati", .horkage_on = ATA_HORKAGE_NO_NCQ_ON_ATI },
{ "ncqati", .horkage_off = ATA_HORKAGE_NO_NCQ_ON_ATI },
{ "dump_id", .horkage_on = ATA_HORKAGE_DUMP_ID },
{ "pio0", .xfer_mask = 1 << (ATA_SHIFT_PIO + 0) },
{ "pio1", .xfer_mask = 1 << (ATA_SHIFT_PIO + 1) },
{ "pio2", .xfer_mask = 1 << (ATA_SHIFT_PIO + 2) },
{ "pio3", .xfer_mask = 1 << (ATA_SHIFT_PIO + 3) },
{ "pio4", .xfer_mask = 1 << (ATA_SHIFT_PIO + 4) },
{ "pio5", .xfer_mask = 1 << (ATA_SHIFT_PIO + 5) },
{ "pio6", .xfer_mask = 1 << (ATA_SHIFT_PIO + 6) },
{ "mwdma0", .xfer_mask = 1 << (ATA_SHIFT_MWDMA + 0) },
{ "mwdma1", .xfer_mask = 1 << (ATA_SHIFT_MWDMA + 1) },
{ "mwdma2", .xfer_mask = 1 << (ATA_SHIFT_MWDMA + 2) },
{ "mwdma3", .xfer_mask = 1 << (ATA_SHIFT_MWDMA + 3) },
{ "mwdma4", .xfer_mask = 1 << (ATA_SHIFT_MWDMA + 4) },
{ "udma0", .xfer_mask = 1 << (ATA_SHIFT_UDMA + 0) },
{ "udma16", .xfer_mask = 1 << (ATA_SHIFT_UDMA + 0) },
{ "udma/16", .xfer_mask = 1 << (ATA_SHIFT_UDMA + 0) },
{ "udma1", .xfer_mask = 1 << (ATA_SHIFT_UDMA + 1) },
{ "udma25", .xfer_mask = 1 << (ATA_SHIFT_UDMA + 1) },
{ "udma/25", .xfer_mask = 1 << (ATA_SHIFT_UDMA + 1) },
{ "udma2", .xfer_mask = 1 << (ATA_SHIFT_UDMA + 2) },
{ "udma33", .xfer_mask = 1 << (ATA_SHIFT_UDMA + 2) },
{ "udma/33", .xfer_mask = 1 << (ATA_SHIFT_UDMA + 2) },
{ "udma3", .xfer_mask = 1 << (ATA_SHIFT_UDMA + 3) },
{ "udma44", .xfer_mask = 1 << (ATA_SHIFT_UDMA + 3) },
{ "udma/44", .xfer_mask = 1 << (ATA_SHIFT_UDMA + 3) },
{ "udma4", .xfer_mask = 1 << (ATA_SHIFT_UDMA + 4) },
{ "udma66", .xfer_mask = 1 << (ATA_SHIFT_UDMA + 4) },
{ "udma/66", .xfer_mask = 1 << (ATA_SHIFT_UDMA + 4) },
{ "udma5", .xfer_mask = 1 << (ATA_SHIFT_UDMA + 5) },
{ "udma100", .xfer_mask = 1 << (ATA_SHIFT_UDMA + 5) },
{ "udma/100", .xfer_mask = 1 << (ATA_SHIFT_UDMA + 5) },
{ "udma6", .xfer_mask = 1 << (ATA_SHIFT_UDMA + 6) },
{ "udma133", .xfer_mask = 1 << (ATA_SHIFT_UDMA + 6) },
{ "udma/133", .xfer_mask = 1 << (ATA_SHIFT_UDMA + 6) },
{ "udma7", .xfer_mask = 1 << (ATA_SHIFT_UDMA + 7) },
{ "nohrst", .lflags = ATA_LFLAG_NO_HRST },
{ "nosrst", .lflags = ATA_LFLAG_NO_SRST },
{ "norst", .lflags = ATA_LFLAG_NO_HRST | ATA_LFLAG_NO_SRST },
{ "rstonce", .lflags = ATA_LFLAG_RST_ONCE },
{ "atapi_dmadir", .horkage_on = ATA_HORKAGE_ATAPI_DMADIR },
{ "disable", .horkage_on = ATA_HORKAGE_DISABLE },
};
char *start = *cur, *p = *cur;
char *id, *val, *endp;
const struct ata_force_param *match_fp = NULL;
......@@ -6288,7 +6295,7 @@ static void __init ata_parse_force_param(void)
int last_port = -1, last_device = -1;
char *p, *cur, *next;
/* calculate maximum number of params and allocate force_tbl */
/* Calculate maximum number of params and allocate ata_force_tbl */
for (p = ata_force_param_buf; *p; p++)
if (*p == ',')
size++;
......
......@@ -1268,31 +1268,6 @@ int ata_sas_queuecmd(struct scsi_cmnd *cmd, struct ata_port *ap)
}
EXPORT_SYMBOL_GPL(ata_sas_queuecmd);
int ata_sas_allocate_tag(struct ata_port *ap)
{
unsigned int max_queue = ap->host->n_tags;
unsigned int i, tag;
for (i = 0, tag = ap->sas_last_tag + 1; i < max_queue; i++, tag++) {
tag = tag < max_queue ? tag : 0;
/* the last tag is reserved for internal command. */
if (ata_tag_internal(tag))
continue;
if (!test_and_set_bit(tag, &ap->sas_tag_allocated)) {
ap->sas_last_tag = tag;
return tag;
}
}
return -1;
}
void ata_sas_free_tag(unsigned int tag, struct ata_port *ap)
{
clear_bit(tag, &ap->sas_tag_allocated);
}
/**
* sata_async_notification - SATA async notification handler
* @ap: ATA port where async notification is received
......
......@@ -638,10 +638,32 @@ EXPORT_SYMBOL_GPL(ata_scsi_ioctl);
static struct ata_queued_cmd *ata_scsi_qc_new(struct ata_device *dev,
struct scsi_cmnd *cmd)
{
struct ata_port *ap = dev->link->ap;
struct ata_queued_cmd *qc;
int tag;
if (unlikely(ap->pflags & ATA_PFLAG_FROZEN))
goto fail;
if (ap->flags & ATA_FLAG_SAS_HOST) {
/*
* SAS hosts may queue > ATA_MAX_QUEUE commands so use
* unique per-device budget token as a tag.
*/
if (WARN_ON_ONCE(cmd->budget_token >= ATA_MAX_QUEUE))
goto fail;
tag = cmd->budget_token;
} else {
tag = scsi_cmd_to_rq(cmd)->tag;
}
qc = __ata_qc_from_tag(ap, tag);
qc->tag = qc->hw_tag = tag;
qc->ap = ap;
qc->dev = dev;
ata_qc_reinit(qc);
qc = ata_qc_new_init(dev, scsi_cmd_to_rq(cmd)->tag);
if (qc) {
qc->scsicmd = cmd;
qc->scsidone = scsi_done;
......@@ -650,12 +672,14 @@ static struct ata_queued_cmd *ata_scsi_qc_new(struct ata_device *dev,
if (scsi_cmd_to_rq(cmd)->rq_flags & RQF_QUIET)
qc->flags |= ATA_QCFLAG_QUIET;
} else {
cmd->result = (DID_OK << 16) | SAM_STAT_TASK_SET_FULL;
scsi_done(cmd);
}
return qc;
fail:
set_host_byte(cmd, DID_OK);
set_status_byte(cmd, SAM_STAT_TASK_SET_FULL);
scsi_done(cmd);
return NULL;
}
static void ata_qc_set_pc_nbytes(struct ata_queued_cmd *qc)
......
......@@ -44,7 +44,6 @@ static inline void ata_force_cbl(struct ata_port *ap) { }
#endif
extern u64 ata_tf_to_lba(const struct ata_taskfile *tf);
extern u64 ata_tf_to_lba48(const struct ata_taskfile *tf);
extern struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev, int tag);
extern int ata_build_rw_tf(struct ata_taskfile *tf, struct ata_device *dev,
u64 block, u32 n_block, unsigned int tf_flags,
unsigned int tag, int class);
......@@ -91,18 +90,6 @@ extern unsigned int ata_read_log_page(struct ata_device *dev, u8 log,
#define to_ata_port(d) container_of(d, struct ata_port, tdev)
/* libata-sata.c */
#ifdef CONFIG_SATA_HOST
int ata_sas_allocate_tag(struct ata_port *ap);
void ata_sas_free_tag(unsigned int tag, struct ata_port *ap);
#else
static inline int ata_sas_allocate_tag(struct ata_port *ap)
{
return -EOPNOTSUPP;
}
static inline void ata_sas_free_tag(unsigned int tag, struct ata_port *ap) { }
#endif
/* libata-acpi.c */
#ifdef CONFIG_ATA_ACPI
extern unsigned int ata_acpi_gtf_filter;
......
......@@ -536,8 +536,8 @@ static int pata_ftide010_probe(struct platform_device *pdev)
return 0;
err_dis_clk:
if (!IS_ERR(ftide->pclk))
clk_disable_unprepare(ftide->pclk);
return ret;
}
......@@ -547,7 +547,6 @@ static int pata_ftide010_remove(struct platform_device *pdev)
struct ftide010 *ftide = host->private_data;
ata_host_detach(ftide->host);
if (!IS_ERR(ftide->pclk))
clk_disable_unprepare(ftide->pclk);
return 0;
......
......@@ -19,11 +19,12 @@
#include <linux/gfp.h>
#include <linux/delay.h>
#include <linux/libata.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/types.h>
#include <asm/cacheflush.h>
#include <asm/prom.h>
#include <asm/mpc52xx.h>
#include <linux/fsl/bestcomm/bestcomm.h>
......
......@@ -47,11 +47,9 @@
* criticial.
*/
static unsigned long sil680_selreg(struct ata_port *ap, int r)
static int sil680_selreg(struct ata_port *ap, int r)
{
unsigned long base = 0xA0 + r;
base += (ap->port_no << 4);
return base;
return 0xA0 + (ap->port_no << 4) + r;
}
/**
......@@ -65,12 +63,9 @@ static unsigned long sil680_selreg(struct ata_port *ap, int r)
* the unit shift.
*/
static unsigned long sil680_seldev(struct ata_port *ap, struct ata_device *adev, int r)
static int sil680_seldev(struct ata_port *ap, struct ata_device *adev, int r)
{
unsigned long base = 0xA0 + r;
base += (ap->port_no << 4);
base |= adev->devno ? 2 : 0;
return base;
return 0xA0 + (ap->port_no << 4) + r + (adev->devno << 1);
}
......@@ -85,8 +80,9 @@ static unsigned long sil680_seldev(struct ata_port *ap, struct ata_device *adev,
static int sil680_cable_detect(struct ata_port *ap)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
unsigned long addr = sil680_selreg(ap, 0);
int addr = sil680_selreg(ap, 0);
u8 ata66;
pci_read_config_byte(pdev, addr, &ata66);
if (ata66 & 1)
return ATA_CBL_PATA80;
......@@ -113,9 +109,9 @@ static void sil680_set_piomode(struct ata_port *ap, struct ata_device *adev)
0x328A, 0x2283, 0x1281, 0x10C3, 0x10C1
};
unsigned long tfaddr = sil680_selreg(ap, 0x02);
unsigned long addr = sil680_seldev(ap, adev, 0x04);
unsigned long addr_mask = 0x80 + 4 * ap->port_no;
int tfaddr = sil680_selreg(ap, 0x02);
int addr = sil680_seldev(ap, adev, 0x04);
int addr_mask = 0x80 + 4 * ap->port_no;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
int pio = adev->pio_mode - XFER_PIO_0;
int lowest_pio = pio;
......@@ -165,9 +161,9 @@ static void sil680_set_dmamode(struct ata_port *ap, struct ata_device *adev)
static const u16 dma_table[3] = { 0x2208, 0x10C2, 0x10C1 };
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
unsigned long ma = sil680_seldev(ap, adev, 0x08);
unsigned long ua = sil680_seldev(ap, adev, 0x0C);
unsigned long addr_mask = 0x80 + 4 * ap->port_no;
int ma = sil680_seldev(ap, adev, 0x08);
int ua = sil680_seldev(ap, adev, 0x0C);
int addr_mask = 0x80 + 4 * ap->port_no;
int port_shift = adev->devno * 4;
u8 scsc, mode;
u16 multi, ultra;
......@@ -219,7 +215,7 @@ static void sil680_sff_exec_command(struct ata_port *ap,
static bool sil680_sff_irq_check(struct ata_port *ap)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
unsigned long addr = sil680_selreg(ap, 1);
int addr = sil680_selreg(ap, 1);
u8 val;
pci_read_config_byte(pdev, addr, &val);
......
......@@ -248,9 +248,9 @@ static void via_do_set_mode(struct ata_port *ap, struct ata_device *adev,
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
struct ata_device *peer = ata_dev_pair(adev);
struct ata_timing t, p;
static int via_clock = 33333; /* Bus clock in kHZ */
unsigned long T = 1000000000 / via_clock;
unsigned long UT = T;
const int via_clock = 33333; /* Bus clock in kHz */
const int T = 1000000000 / via_clock;
int UT = T;
int ut;
int offset = 3 - (2*ap->port_no) - adev->devno;
......
......@@ -318,7 +318,6 @@ static int gemini_sata_probe(struct platform_device *pdev)
struct device_node *np = dev->of_node;
struct sata_gemini *sg;
struct regmap *map;
struct resource *res;
enum gemini_muxmode muxmode;
u32 gmode;
u32 gmask;
......@@ -329,11 +328,7 @@ static int gemini_sata_probe(struct platform_device *pdev)
return -ENOMEM;
sg->dev = dev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
sg->base = devm_ioremap_resource(dev, res);
sg->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(sg->base))
return PTR_ERR(sg->base);
......
......@@ -820,7 +820,6 @@ struct ata_port {
unsigned int cbl; /* cable type; ATA_CBL_xxx */
struct ata_queued_cmd qcmd[ATA_MAX_QUEUE + 1];
unsigned long sas_tag_allocated; /* for sas tag allocation only */
u64 qc_active;
int nr_active_links; /* #links with active qcs */
unsigned int sas_last_tag; /* track next tag hw expects */
......@@ -1111,7 +1110,7 @@ extern void ata_unpack_xfermask(unsigned long xfer_mask,
unsigned long *udma_mask);
extern u8 ata_xfer_mask2mode(unsigned long xfer_mask);
extern unsigned long ata_xfer_mode2mask(u8 xfer_mode);
extern int ata_xfer_mode2shift(unsigned long xfer_mode);
extern int ata_xfer_mode2shift(u8 xfer_mode);
extern const char *ata_mode_string(unsigned long xfer_mask);
extern unsigned long ata_id_xfermask(const u16 *id);
extern int ata_std_qc_defer(struct ata_queued_cmd *qc);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment