mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 20:07:46 +09:00
Merge 985564eb3e ("Merge tag 'core-debugobjects-2022-05-23' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip") into android-mainline
Steps on the way to 5.19-rc1 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com> Change-Id: If0988ce99bc4e47e5d58ea208fb159f371cd73da
This commit is contained in:
@@ -2630,14 +2630,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
|
||||
@@ -2647,7 +2647,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.
|
||||
|
||||
@@ -2660,19 +2660,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.
|
||||
|
||||
* nohrst, nosrst, norst: suppress hard, soft
|
||||
and both resets.
|
||||
* [no]ncqati: Enable or disable NCQ trim on ATI chipset.
|
||||
|
||||
* rstonce: only attempt one reset during
|
||||
hot-unplug link recovery
|
||||
* [no]trim: Enable or disable (unqueued) TRIM.
|
||||
|
||||
* dump_id: dump IDENTIFY data.
|
||||
* trim_zero: Indicate that TRIM command zeroes data.
|
||||
|
||||
* atapi_dmadir: Enable ATAPI DMADIR bridge support
|
||||
* 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.
|
||||
|
||||
* max_sec_lba48: Set or clear transfer size limit to
|
||||
65535 sectors.
|
||||
|
||||
* [no]lpm: Enable or disable link power management.
|
||||
|
||||
* [no]setxfer: Indicate if transfer speed mode setting
|
||||
should be skipped.
|
||||
|
||||
* 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``
|
||||
|
||||
@@ -306,8 +306,15 @@ Further notes:
|
||||
Mount options
|
||||
-------------
|
||||
|
||||
zonefs define the "errors=<behavior>" mount option to allow the user to specify
|
||||
zonefs behavior in response to I/O errors, inode size inconsistencies or zone
|
||||
zonefs defines several mount options:
|
||||
* errors=<behavior>
|
||||
* explicit-open
|
||||
|
||||
"errors=<behavior>" option
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The "errors=<behavior>" option mount option allows the user to specify zonefs
|
||||
behavior in response to I/O errors, inode size inconsistencies or zone
|
||||
condition changes. The defined behaviors are as follow:
|
||||
|
||||
* remount-ro (default)
|
||||
@@ -326,6 +333,9 @@ discover the amount of data that has been written to the zone. In the case of a
|
||||
read-only zone discovered at run-time, as indicated in the previous section.
|
||||
The size of the zone file is left unchanged from its last updated value.
|
||||
|
||||
"explicit-open" option
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
A zoned block device (e.g. an NVMe Zoned Namespace device) may have limits on
|
||||
the number of zones that can be active, that is, zones that are in the
|
||||
implicit open, explicit open or closed conditions. This potential limitation
|
||||
@@ -341,6 +351,44 @@ guaranteed that write requests can be processed. Conversely, the
|
||||
to the device on the last close() of a zone file if the zone is not full nor
|
||||
empty.
|
||||
|
||||
Runtime sysfs attributes
|
||||
------------------------
|
||||
|
||||
zonefs defines several sysfs attributes for mounted devices. All attributes
|
||||
are user readable and can be found in the directory /sys/fs/zonefs/<dev>/,
|
||||
where <dev> is the name of the mounted zoned block device.
|
||||
|
||||
The attributes defined are as follows.
|
||||
|
||||
* **max_wro_seq_files**: This attribute reports the maximum number of
|
||||
sequential zone files that can be open for writing. This number corresponds
|
||||
to the maximum number of explicitly or implicitly open zones that the device
|
||||
supports. A value of 0 means that the device has no limit and that any zone
|
||||
(any file) can be open for writing and written at any time, regardless of the
|
||||
state of other zones. When the *explicit-open* mount option is used, zonefs
|
||||
will fail any open() system call requesting to open a sequential zone file for
|
||||
writing when the number of sequential zone files already open for writing has
|
||||
reached the *max_wro_seq_files* limit.
|
||||
* **nr_wro_seq_files**: This attribute reports the current number of sequential
|
||||
zone files open for writing. When the "explicit-open" mount option is used,
|
||||
this number can never exceed *max_wro_seq_files*. If the *explicit-open*
|
||||
mount option is not used, the reported number can be greater than
|
||||
*max_wro_seq_files*. In such case, it is the responsibility of the
|
||||
application to not write simultaneously more than *max_wro_seq_files*
|
||||
sequential zone files. Failure to do so can result in write errors.
|
||||
* **max_active_seq_files**: This attribute reports the maximum number of
|
||||
sequential zone files that are in an active state, that is, sequential zone
|
||||
files that are partially writen (not empty nor full) or that have a zone that
|
||||
is explicitly open (which happens only if the *explicit-open* mount option is
|
||||
used). This number is always equal to the maximum number of active zones that
|
||||
the device supports. A value of 0 means that the mounted device has no limit
|
||||
on the number of sequential zone files that can be active.
|
||||
* **nr_active_seq_files**: This attributes reports the current number of
|
||||
sequential zone files that are active. If *max_active_seq_files* is not 0,
|
||||
then the value of *nr_active_seq_files* can never exceed the value of
|
||||
*nr_active_seq_files*, regardless of the use of the *explicit-open* mount
|
||||
option.
|
||||
|
||||
Zonefs User Space Tools
|
||||
=======================
|
||||
|
||||
|
||||
@@ -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,24 +638,48 @@ 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;
|
||||
|
||||
qc = ata_qc_new_init(dev, scsi_cmd_to_rq(cmd)->tag);
|
||||
if (qc) {
|
||||
qc->scsicmd = cmd;
|
||||
qc->scsidone = scsi_done;
|
||||
if (unlikely(ap->pflags & ATA_PFLAG_FROZEN))
|
||||
goto fail;
|
||||
|
||||
qc->sg = scsi_sglist(cmd);
|
||||
qc->n_elem = scsi_sg_count(cmd);
|
||||
|
||||
if (scsi_cmd_to_rq(cmd)->rq_flags & RQF_QUIET)
|
||||
qc->flags |= ATA_QCFLAG_QUIET;
|
||||
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 {
|
||||
cmd->result = (DID_OK << 16) | SAM_STAT_TASK_SET_FULL;
|
||||
scsi_done(cmd);
|
||||
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->scsicmd = cmd;
|
||||
qc->scsidone = scsi_done;
|
||||
|
||||
qc->sg = scsi_sglist(cmd);
|
||||
qc->n_elem = scsi_sg_count(cmd);
|
||||
|
||||
if (scsi_cmd_to_rq(cmd)->rq_flags & RQF_QUIET)
|
||||
qc->flags |= ATA_QCFLAG_QUIET;
|
||||
|
||||
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);
|
||||
clk_disable_unprepare(ftide->pclk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -547,8 +547,7 @@ 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);
|
||||
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);
|
||||
|
||||
|
||||
@@ -3,4 +3,4 @@ ccflags-y += -I$(src)
|
||||
|
||||
obj-$(CONFIG_ZONEFS_FS) += zonefs.o
|
||||
|
||||
zonefs-y := super.o
|
||||
zonefs-y := super.o sysfs.o
|
||||
|
||||
@@ -27,6 +27,39 @@
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include "trace.h"
|
||||
|
||||
/*
|
||||
* Manage the active zone count. Called with zi->i_truncate_mutex held.
|
||||
*/
|
||||
static void zonefs_account_active(struct inode *inode)
|
||||
{
|
||||
struct zonefs_sb_info *sbi = ZONEFS_SB(inode->i_sb);
|
||||
struct zonefs_inode_info *zi = ZONEFS_I(inode);
|
||||
|
||||
lockdep_assert_held(&zi->i_truncate_mutex);
|
||||
|
||||
if (zi->i_ztype != ZONEFS_ZTYPE_SEQ)
|
||||
return;
|
||||
|
||||
/*
|
||||
* If the zone is active, that is, if it is explicitly open or
|
||||
* partially written, check if it was already accounted as active.
|
||||
*/
|
||||
if ((zi->i_flags & ZONEFS_ZONE_OPEN) ||
|
||||
(zi->i_wpoffset > 0 && zi->i_wpoffset < zi->i_max_size)) {
|
||||
if (!(zi->i_flags & ZONEFS_ZONE_ACTIVE)) {
|
||||
zi->i_flags |= ZONEFS_ZONE_ACTIVE;
|
||||
atomic_inc(&sbi->s_active_seq_files);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* The zone is not active. If it was, update the active count */
|
||||
if (zi->i_flags & ZONEFS_ZONE_ACTIVE) {
|
||||
zi->i_flags &= ~ZONEFS_ZONE_ACTIVE;
|
||||
atomic_dec(&sbi->s_active_seq_files);
|
||||
}
|
||||
}
|
||||
|
||||
static inline int zonefs_zone_mgmt(struct inode *inode,
|
||||
enum req_opf op)
|
||||
{
|
||||
@@ -68,8 +101,13 @@ static inline void zonefs_i_size_write(struct inode *inode, loff_t isize)
|
||||
* A full zone is no longer open/active and does not need
|
||||
* explicit closing.
|
||||
*/
|
||||
if (isize >= zi->i_max_size)
|
||||
zi->i_flags &= ~ZONEFS_ZONE_OPEN;
|
||||
if (isize >= zi->i_max_size) {
|
||||
struct zonefs_sb_info *sbi = ZONEFS_SB(inode->i_sb);
|
||||
|
||||
if (zi->i_flags & ZONEFS_ZONE_ACTIVE)
|
||||
atomic_dec(&sbi->s_active_seq_files);
|
||||
zi->i_flags &= ~(ZONEFS_ZONE_OPEN | ZONEFS_ZONE_ACTIVE);
|
||||
}
|
||||
}
|
||||
|
||||
static int zonefs_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
|
||||
@@ -397,6 +435,7 @@ static int zonefs_io_error_cb(struct blk_zone *zone, unsigned int idx,
|
||||
zonefs_update_stats(inode, data_size);
|
||||
zonefs_i_size_write(inode, data_size);
|
||||
zi->i_wpoffset = data_size;
|
||||
zonefs_account_active(inode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -508,6 +547,7 @@ static int zonefs_file_truncate(struct inode *inode, loff_t isize)
|
||||
zonefs_update_stats(inode, isize);
|
||||
truncate_setsize(inode, isize);
|
||||
zi->i_wpoffset = isize;
|
||||
zonefs_account_active(inode);
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&zi->i_truncate_mutex);
|
||||
@@ -865,8 +905,15 @@ static ssize_t zonefs_file_dio_write(struct kiocb *iocb, struct iov_iter *from)
|
||||
(ret > 0 || ret == -EIOCBQUEUED)) {
|
||||
if (ret > 0)
|
||||
count = ret;
|
||||
|
||||
/*
|
||||
* Update the zone write pointer offset assuming the write
|
||||
* operation succeeded. If it did not, the error recovery path
|
||||
* will correct it. Also do active seq file accounting.
|
||||
*/
|
||||
mutex_lock(&zi->i_truncate_mutex);
|
||||
zi->i_wpoffset += count;
|
||||
zonefs_account_active(inode);
|
||||
mutex_unlock(&zi->i_truncate_mutex);
|
||||
}
|
||||
|
||||
@@ -1008,13 +1055,13 @@ inode_unlock:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline bool zonefs_file_use_exp_open(struct inode *inode, struct file *file)
|
||||
/*
|
||||
* Write open accounting is done only for sequential files.
|
||||
*/
|
||||
static inline bool zonefs_seq_file_need_wro(struct inode *inode,
|
||||
struct file *file)
|
||||
{
|
||||
struct zonefs_inode_info *zi = ZONEFS_I(inode);
|
||||
struct zonefs_sb_info *sbi = ZONEFS_SB(inode->i_sb);
|
||||
|
||||
if (!(sbi->s_mount_opts & ZONEFS_MNTOPT_EXPLICIT_OPEN))
|
||||
return false;
|
||||
|
||||
if (zi->i_ztype != ZONEFS_ZTYPE_SEQ)
|
||||
return false;
|
||||
@@ -1025,28 +1072,34 @@ static inline bool zonefs_file_use_exp_open(struct inode *inode, struct file *fi
|
||||
return true;
|
||||
}
|
||||
|
||||
static int zonefs_open_zone(struct inode *inode)
|
||||
static int zonefs_seq_file_write_open(struct inode *inode)
|
||||
{
|
||||
struct zonefs_inode_info *zi = ZONEFS_I(inode);
|
||||
struct zonefs_sb_info *sbi = ZONEFS_SB(inode->i_sb);
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&zi->i_truncate_mutex);
|
||||
|
||||
if (!zi->i_wr_refcnt) {
|
||||
if (atomic_inc_return(&sbi->s_open_zones) > sbi->s_max_open_zones) {
|
||||
atomic_dec(&sbi->s_open_zones);
|
||||
ret = -EBUSY;
|
||||
goto unlock;
|
||||
}
|
||||
struct zonefs_sb_info *sbi = ZONEFS_SB(inode->i_sb);
|
||||
unsigned int wro = atomic_inc_return(&sbi->s_wro_seq_files);
|
||||
|
||||
if (i_size_read(inode) < zi->i_max_size) {
|
||||
ret = zonefs_zone_mgmt(inode, REQ_OP_ZONE_OPEN);
|
||||
if (ret) {
|
||||
atomic_dec(&sbi->s_open_zones);
|
||||
if (sbi->s_mount_opts & ZONEFS_MNTOPT_EXPLICIT_OPEN) {
|
||||
|
||||
if (wro > sbi->s_max_wro_seq_files) {
|
||||
atomic_dec(&sbi->s_wro_seq_files);
|
||||
ret = -EBUSY;
|
||||
goto unlock;
|
||||
}
|
||||
zi->i_flags |= ZONEFS_ZONE_OPEN;
|
||||
|
||||
if (i_size_read(inode) < zi->i_max_size) {
|
||||
ret = zonefs_zone_mgmt(inode, REQ_OP_ZONE_OPEN);
|
||||
if (ret) {
|
||||
atomic_dec(&sbi->s_wro_seq_files);
|
||||
goto unlock;
|
||||
}
|
||||
zi->i_flags |= ZONEFS_ZONE_OPEN;
|
||||
zonefs_account_active(inode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1066,30 +1119,31 @@ static int zonefs_file_open(struct inode *inode, struct file *file)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (zonefs_file_use_exp_open(inode, file))
|
||||
return zonefs_open_zone(inode);
|
||||
if (zonefs_seq_file_need_wro(inode, file))
|
||||
return zonefs_seq_file_write_open(inode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void zonefs_close_zone(struct inode *inode)
|
||||
static void zonefs_seq_file_write_close(struct inode *inode)
|
||||
{
|
||||
struct zonefs_inode_info *zi = ZONEFS_I(inode);
|
||||
struct super_block *sb = inode->i_sb;
|
||||
struct zonefs_sb_info *sbi = ZONEFS_SB(sb);
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&zi->i_truncate_mutex);
|
||||
|
||||
zi->i_wr_refcnt--;
|
||||
if (!zi->i_wr_refcnt) {
|
||||
struct zonefs_sb_info *sbi = ZONEFS_SB(inode->i_sb);
|
||||
struct super_block *sb = inode->i_sb;
|
||||
|
||||
/*
|
||||
* If the file zone is full, it is not open anymore and we only
|
||||
* need to decrement the open count.
|
||||
*/
|
||||
if (!(zi->i_flags & ZONEFS_ZONE_OPEN))
|
||||
goto dec;
|
||||
if (zi->i_wr_refcnt)
|
||||
goto unlock;
|
||||
|
||||
/*
|
||||
* The file zone may not be open anymore (e.g. the file was truncated to
|
||||
* its maximum size or it was fully written). For this case, we only
|
||||
* need to decrement the write open count.
|
||||
*/
|
||||
if (zi->i_flags & ZONEFS_ZONE_OPEN) {
|
||||
ret = zonefs_zone_mgmt(inode, REQ_OP_ZONE_CLOSE);
|
||||
if (ret) {
|
||||
__zonefs_io_error(inode, false);
|
||||
@@ -1101,14 +1155,23 @@ static void zonefs_close_zone(struct inode *inode)
|
||||
*/
|
||||
if (zi->i_flags & ZONEFS_ZONE_OPEN &&
|
||||
!(sb->s_flags & SB_RDONLY)) {
|
||||
zonefs_warn(sb, "closing zone failed, remounting filesystem read-only\n");
|
||||
zonefs_warn(sb,
|
||||
"closing zone at %llu failed %d\n",
|
||||
zi->i_zsector, ret);
|
||||
zonefs_warn(sb,
|
||||
"remounting filesystem read-only\n");
|
||||
sb->s_flags |= SB_RDONLY;
|
||||
}
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
zi->i_flags &= ~ZONEFS_ZONE_OPEN;
|
||||
dec:
|
||||
atomic_dec(&sbi->s_open_zones);
|
||||
zonefs_account_active(inode);
|
||||
}
|
||||
|
||||
atomic_dec(&sbi->s_wro_seq_files);
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&zi->i_truncate_mutex);
|
||||
}
|
||||
|
||||
@@ -1120,8 +1183,8 @@ static int zonefs_file_release(struct inode *inode, struct file *file)
|
||||
* the zone has gone offline or read-only). Make sure we don't fail the
|
||||
* close(2) for user-space.
|
||||
*/
|
||||
if (zonefs_file_use_exp_open(inode, file))
|
||||
zonefs_close_zone(inode);
|
||||
if (zonefs_seq_file_need_wro(inode, file))
|
||||
zonefs_seq_file_write_close(inode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1310,7 +1373,7 @@ static int zonefs_init_file_inode(struct inode *inode, struct blk_zone *zone,
|
||||
struct super_block *sb = inode->i_sb;
|
||||
struct zonefs_sb_info *sbi = ZONEFS_SB(sb);
|
||||
struct zonefs_inode_info *zi = ZONEFS_I(inode);
|
||||
int ret = 0;
|
||||
int ret;
|
||||
|
||||
inode->i_ino = zone->start >> sbi->s_zone_sectors_shift;
|
||||
inode->i_mode = S_IFREG | sbi->s_perm;
|
||||
@@ -1336,6 +1399,8 @@ static int zonefs_init_file_inode(struct inode *inode, struct blk_zone *zone,
|
||||
sbi->s_blocks += zi->i_max_size >> sb->s_blocksize_bits;
|
||||
sbi->s_used_blocks += zi->i_wpoffset >> sb->s_blocksize_bits;
|
||||
|
||||
mutex_lock(&zi->i_truncate_mutex);
|
||||
|
||||
/*
|
||||
* For sequential zones, make sure that any open zone is closed first
|
||||
* to ensure that the initial number of open zones is 0, in sync with
|
||||
@@ -1345,12 +1410,17 @@ static int zonefs_init_file_inode(struct inode *inode, struct blk_zone *zone,
|
||||
if (type == ZONEFS_ZTYPE_SEQ &&
|
||||
(zone->cond == BLK_ZONE_COND_IMP_OPEN ||
|
||||
zone->cond == BLK_ZONE_COND_EXP_OPEN)) {
|
||||
mutex_lock(&zi->i_truncate_mutex);
|
||||
ret = zonefs_zone_mgmt(inode, REQ_OP_ZONE_CLOSE);
|
||||
mutex_unlock(&zi->i_truncate_mutex);
|
||||
if (ret)
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
return ret;
|
||||
zonefs_account_active(inode);
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&zi->i_truncate_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dentry *zonefs_create_inode(struct dentry *parent,
|
||||
@@ -1687,14 +1757,18 @@ static int zonefs_fill_super(struct super_block *sb, void *data, int silent)
|
||||
sbi->s_gid = GLOBAL_ROOT_GID;
|
||||
sbi->s_perm = 0640;
|
||||
sbi->s_mount_opts = ZONEFS_MNTOPT_ERRORS_RO;
|
||||
sbi->s_max_open_zones = bdev_max_open_zones(sb->s_bdev);
|
||||
atomic_set(&sbi->s_open_zones, 0);
|
||||
if (!sbi->s_max_open_zones &&
|
||||
|
||||
atomic_set(&sbi->s_wro_seq_files, 0);
|
||||
sbi->s_max_wro_seq_files = bdev_max_open_zones(sb->s_bdev);
|
||||
if (!sbi->s_max_wro_seq_files &&
|
||||
sbi->s_mount_opts & ZONEFS_MNTOPT_EXPLICIT_OPEN) {
|
||||
zonefs_info(sb, "No open zones limit. Ignoring explicit_open mount option\n");
|
||||
sbi->s_mount_opts &= ~ZONEFS_MNTOPT_EXPLICIT_OPEN;
|
||||
}
|
||||
|
||||
atomic_set(&sbi->s_active_seq_files, 0);
|
||||
sbi->s_max_active_seq_files = bdev_max_active_zones(sb->s_bdev);
|
||||
|
||||
ret = zonefs_read_super(sb);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -1709,6 +1783,10 @@ static int zonefs_fill_super(struct super_block *sb, void *data, int silent)
|
||||
if (ret)
|
||||
goto cleanup;
|
||||
|
||||
ret = zonefs_sysfs_register(sb);
|
||||
if (ret)
|
||||
goto cleanup;
|
||||
|
||||
zonefs_info(sb, "Mounting %u zones",
|
||||
blkdev_nr_zones(sb->s_bdev->bd_disk));
|
||||
|
||||
@@ -1754,6 +1832,8 @@ static void zonefs_kill_super(struct super_block *sb)
|
||||
|
||||
if (sb->s_root)
|
||||
d_genocide(sb->s_root);
|
||||
|
||||
zonefs_sysfs_unregister(sb);
|
||||
kill_block_super(sb);
|
||||
kfree(sbi);
|
||||
}
|
||||
@@ -1801,16 +1881,26 @@ static int __init zonefs_init(void)
|
||||
return ret;
|
||||
|
||||
ret = register_filesystem(&zonefs_type);
|
||||
if (ret) {
|
||||
zonefs_destroy_inodecache();
|
||||
return ret;
|
||||
}
|
||||
if (ret)
|
||||
goto destroy_inodecache;
|
||||
|
||||
ret = zonefs_sysfs_init();
|
||||
if (ret)
|
||||
goto unregister_fs;
|
||||
|
||||
return 0;
|
||||
|
||||
unregister_fs:
|
||||
unregister_filesystem(&zonefs_type);
|
||||
destroy_inodecache:
|
||||
zonefs_destroy_inodecache();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit zonefs_exit(void)
|
||||
{
|
||||
zonefs_sysfs_exit();
|
||||
zonefs_destroy_inodecache();
|
||||
unregister_filesystem(&zonefs_type);
|
||||
}
|
||||
|
||||
139
fs/zonefs/sysfs.c
Normal file
139
fs/zonefs/sysfs.c
Normal file
@@ -0,0 +1,139 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Simple file system for zoned block devices exposing zones as files.
|
||||
*
|
||||
* Copyright (C) 2022 Western Digital Corporation or its affiliates.
|
||||
*/
|
||||
#include <linux/fs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/blkdev.h>
|
||||
|
||||
#include "zonefs.h"
|
||||
|
||||
struct zonefs_sysfs_attr {
|
||||
struct attribute attr;
|
||||
ssize_t (*show)(struct zonefs_sb_info *sbi, char *buf);
|
||||
};
|
||||
|
||||
static inline struct zonefs_sysfs_attr *to_attr(struct attribute *attr)
|
||||
{
|
||||
return container_of(attr, struct zonefs_sysfs_attr, attr);
|
||||
}
|
||||
|
||||
#define ZONEFS_SYSFS_ATTR_RO(name) \
|
||||
static struct zonefs_sysfs_attr zonefs_sysfs_attr_##name = __ATTR_RO(name)
|
||||
|
||||
#define ATTR_LIST(name) &zonefs_sysfs_attr_##name.attr
|
||||
|
||||
static ssize_t zonefs_sysfs_attr_show(struct kobject *kobj,
|
||||
struct attribute *attr, char *buf)
|
||||
{
|
||||
struct zonefs_sb_info *sbi =
|
||||
container_of(kobj, struct zonefs_sb_info, s_kobj);
|
||||
struct zonefs_sysfs_attr *zonefs_attr =
|
||||
container_of(attr, struct zonefs_sysfs_attr, attr);
|
||||
|
||||
if (!zonefs_attr->show)
|
||||
return 0;
|
||||
|
||||
return zonefs_attr->show(sbi, buf);
|
||||
}
|
||||
|
||||
static ssize_t max_wro_seq_files_show(struct zonefs_sb_info *sbi, char *buf)
|
||||
{
|
||||
return sysfs_emit(buf, "%u\n", sbi->s_max_wro_seq_files);
|
||||
}
|
||||
ZONEFS_SYSFS_ATTR_RO(max_wro_seq_files);
|
||||
|
||||
static ssize_t nr_wro_seq_files_show(struct zonefs_sb_info *sbi, char *buf)
|
||||
{
|
||||
return sysfs_emit(buf, "%d\n", atomic_read(&sbi->s_wro_seq_files));
|
||||
}
|
||||
ZONEFS_SYSFS_ATTR_RO(nr_wro_seq_files);
|
||||
|
||||
static ssize_t max_active_seq_files_show(struct zonefs_sb_info *sbi, char *buf)
|
||||
{
|
||||
return sysfs_emit(buf, "%u\n", sbi->s_max_active_seq_files);
|
||||
}
|
||||
ZONEFS_SYSFS_ATTR_RO(max_active_seq_files);
|
||||
|
||||
static ssize_t nr_active_seq_files_show(struct zonefs_sb_info *sbi, char *buf)
|
||||
{
|
||||
return sysfs_emit(buf, "%d\n", atomic_read(&sbi->s_active_seq_files));
|
||||
}
|
||||
ZONEFS_SYSFS_ATTR_RO(nr_active_seq_files);
|
||||
|
||||
static struct attribute *zonefs_sysfs_attrs[] = {
|
||||
ATTR_LIST(max_wro_seq_files),
|
||||
ATTR_LIST(nr_wro_seq_files),
|
||||
ATTR_LIST(max_active_seq_files),
|
||||
ATTR_LIST(nr_active_seq_files),
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(zonefs_sysfs);
|
||||
|
||||
static void zonefs_sysfs_sb_release(struct kobject *kobj)
|
||||
{
|
||||
struct zonefs_sb_info *sbi =
|
||||
container_of(kobj, struct zonefs_sb_info, s_kobj);
|
||||
|
||||
complete(&sbi->s_kobj_unregister);
|
||||
}
|
||||
|
||||
static const struct sysfs_ops zonefs_sysfs_attr_ops = {
|
||||
.show = zonefs_sysfs_attr_show,
|
||||
};
|
||||
|
||||
static struct kobj_type zonefs_sb_ktype = {
|
||||
.default_groups = zonefs_sysfs_groups,
|
||||
.sysfs_ops = &zonefs_sysfs_attr_ops,
|
||||
.release = zonefs_sysfs_sb_release,
|
||||
};
|
||||
|
||||
static struct kobject *zonefs_sysfs_root;
|
||||
|
||||
int zonefs_sysfs_register(struct super_block *sb)
|
||||
{
|
||||
struct zonefs_sb_info *sbi = ZONEFS_SB(sb);
|
||||
int ret;
|
||||
|
||||
init_completion(&sbi->s_kobj_unregister);
|
||||
ret = kobject_init_and_add(&sbi->s_kobj, &zonefs_sb_ktype,
|
||||
zonefs_sysfs_root, "%s", sb->s_id);
|
||||
if (ret) {
|
||||
kobject_put(&sbi->s_kobj);
|
||||
wait_for_completion(&sbi->s_kobj_unregister);
|
||||
return ret;
|
||||
}
|
||||
|
||||
sbi->s_sysfs_registered = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void zonefs_sysfs_unregister(struct super_block *sb)
|
||||
{
|
||||
struct zonefs_sb_info *sbi = ZONEFS_SB(sb);
|
||||
|
||||
if (!sbi || !sbi->s_sysfs_registered)
|
||||
return;
|
||||
|
||||
kobject_del(&sbi->s_kobj);
|
||||
kobject_put(&sbi->s_kobj);
|
||||
wait_for_completion(&sbi->s_kobj_unregister);
|
||||
}
|
||||
|
||||
int __init zonefs_sysfs_init(void)
|
||||
{
|
||||
zonefs_sysfs_root = kobject_create_and_add("zonefs", fs_kobj);
|
||||
if (!zonefs_sysfs_root)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void zonefs_sysfs_exit(void)
|
||||
{
|
||||
kobject_put(zonefs_sysfs_root);
|
||||
zonefs_sysfs_root = NULL;
|
||||
}
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <linux/uuid.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/rwsem.h>
|
||||
#include <linux/kobject.h>
|
||||
|
||||
/*
|
||||
* Maximum length of file names: this only needs to be large enough to fit
|
||||
@@ -39,6 +40,7 @@ static inline enum zonefs_ztype zonefs_zone_type(struct blk_zone *zone)
|
||||
}
|
||||
|
||||
#define ZONEFS_ZONE_OPEN (1 << 0)
|
||||
#define ZONEFS_ZONE_ACTIVE (1 << 1)
|
||||
|
||||
/*
|
||||
* In-memory inode data.
|
||||
@@ -182,8 +184,15 @@ struct zonefs_sb_info {
|
||||
loff_t s_blocks;
|
||||
loff_t s_used_blocks;
|
||||
|
||||
unsigned int s_max_open_zones;
|
||||
atomic_t s_open_zones;
|
||||
unsigned int s_max_wro_seq_files;
|
||||
atomic_t s_wro_seq_files;
|
||||
|
||||
unsigned int s_max_active_seq_files;
|
||||
atomic_t s_active_seq_files;
|
||||
|
||||
bool s_sysfs_registered;
|
||||
struct kobject s_kobj;
|
||||
struct completion s_kobj_unregister;
|
||||
};
|
||||
|
||||
static inline struct zonefs_sb_info *ZONEFS_SB(struct super_block *sb)
|
||||
@@ -198,4 +207,9 @@ static inline struct zonefs_sb_info *ZONEFS_SB(struct super_block *sb)
|
||||
#define zonefs_warn(sb, format, args...) \
|
||||
pr_warn("zonefs (%s) WARNING: " format, sb->s_id, ## args)
|
||||
|
||||
int zonefs_sysfs_register(struct super_block *sb);
|
||||
void zonefs_sysfs_unregister(struct super_block *sb);
|
||||
int zonefs_sysfs_init(void);
|
||||
void zonefs_sysfs_exit(void);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Generic infrastructure for lifetime debugging of objects.
|
||||
*
|
||||
* Started by Thomas Gleixner
|
||||
*
|
||||
* Copyright (C) 2008, Thomas Gleixner <tglx@linutronix.de>
|
||||
*
|
||||
* For licencing details see kernel-base/COPYING
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "ODEBUG: " fmt
|
||||
|
||||
@@ -188,14 +188,18 @@ EXPORT_SYMBOL(irq_poll_init);
|
||||
static int irq_poll_cpu_dead(unsigned int cpu)
|
||||
{
|
||||
/*
|
||||
* If a CPU goes away, splice its entries to the current CPU
|
||||
* and trigger a run of the softirq
|
||||
* If a CPU goes away, splice its entries to the current CPU and
|
||||
* set the POLL softirq bit. The local_bh_disable()/enable() pair
|
||||
* ensures that it is handled. Otherwise the current CPU could
|
||||
* reach idle with the POLL softirq pending.
|
||||
*/
|
||||
local_bh_disable();
|
||||
local_irq_disable();
|
||||
list_splice_init(&per_cpu(blk_cpu_iopoll, cpu),
|
||||
this_cpu_ptr(&blk_cpu_iopoll));
|
||||
__raise_softirq_irqoff(IRQ_POLL_SOFTIRQ);
|
||||
local_irq_enable();
|
||||
local_bh_enable();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user