2023-01-21 23:21:36

by Ondrej Zary

[permalink] [raw]
Subject: [PATCH v2] pata_parport: add driver (PARIDE replacement)

The pata_parport is a libata-based replacement of the old PARIDE
subsystem - driver for parallel port IDE devices.
It uses the original paride low-level protocol drivers but does not
need the high-level drivers (pd, pcd, pf, pt, pg). The IDE devices
behind parallel port adapters are handled by the ATA layer.

This will allow paride and its high-level drivers to be removed.

Unfortunately, libata drivers cannot sleep so pata_parport claims
parport before activating the ata host and keeps it claimed (and
protocol connected) until the ata host is removed. This means that
no devices can be chained (neither other pata_parport devices nor
a printer).

paride and pata_parport are mutually exclusive because the compiled
protocol drivers are incompatible.

Tested with:
- Imation SuperDisk LS-120 and HP C4381A (EPAT)
- Freecom Parallel CD (FRPW)
- Toshiba Mobile CD-RW 2793008 w/Freecom Parallel Cable rev.903 (FRIQ)
- Backpack CD-RW 222011 and CD-RW 19350 (BPCK6)

The following bugs in low-level protocol drivers were found and will
be fixed later:

Note: EPP-32 mode is buggy in EPAT - and also in all other protocol
drivers - they don't handle non-multiple-of-4 block transfers
correctly. This causes problems with LS-120 drive.
There is also another bug in EPAT: EPP modes don't work unless a 4-bit
or 8-bit mode is used first (probably some initialization missing?).
Once the device is initialized, EPP works until power cycle.

So after device power on, you have to:
echo "parport0 epat 0" >/sys/bus/pata_parport/new_device
echo pata_parport.0 >/sys/bus/pata_parport/delete_device
echo "parport0 epat 4" >/sys/bus/pata_parport/new_device
(autoprobe will initialize correctly as it tries the slowest modes
first but you'll get the broken EPP-32 mode)

Note: EPP modes are buggy in FRPW, only modes 0 and 1 work.
Signed-off-by: Ondrej Zary <[email protected]>
---

Changes in v2:
- keep device connected, remove disconnect timer

Documentation/admin-guide/blockdev/paride.rst | 52 ++
drivers/Makefile | 2 +-
drivers/ata/Kconfig | 14 +
drivers/ata/Makefile | 2 +
drivers/ata/pata_parport.c | 783 ++++++++++++++++++
drivers/block/paride/Kconfig | 32 +-
drivers/block/paride/paride.h | 13 +
include/linux/pata_parport.h | 106 +++
8 files changed, 987 insertions(+), 17 deletions(-)
create mode 100644 drivers/ata/pata_parport.c
create mode 100644 include/linux/pata_parport.h

diff --git a/Documentation/admin-guide/blockdev/paride.rst b/Documentation/admin-guide/blockdev/paride.rst
index e1ce90af602a..e431a1ef41eb 100644
--- a/Documentation/admin-guide/blockdev/paride.rst
+++ b/Documentation/admin-guide/blockdev/paride.rst
@@ -2,6 +2,9 @@
Linux and parallel port IDE devices
===================================

+Most of this document describes the old paride driver. For the new libata
+pata_parport drivrer, jump to the section 4 at the end.
+
PARIDE v1.03 (c) 1997-8 Grant Guenther <[email protected]>

1. Introduction
@@ -437,3 +440,52 @@ You might also find some useful information on the linux-parport
web pages (although they are not always up to date) at

http://web.archive.org/web/%2E/http://www.torque.net/parport/
+
+4. pata_parport driver
+======================
+pata_parport is a libata-based driver that uses the same low-level protocol
+drivers as PARIDE but there are no high-level drivers (pd, pcd, pf, pt, pg).
+The IDE devices behind parallel port adapters are handled by the ATA layer.
+
+The device creation is also changed - no protocol numbers or parport I/O
+addresses are used.
+
+All parports and all protocol drivers are probed automatically unless probe=0
+parameter is used. So just "modprobe epat" is enough for a Imation SuperDisk
+drive to work.
+
+Manual device creation::
+
+ # echo "port protocol mode unit delay" >/sys/bus/pata_parport/new_device
+
+where:
+
+ ======== ================================================
+ port parport name (or "auto" for all parports)
+ protocol protocol name (or "auto" for all protocols)
+ mode mode number (protocol-specific) or -1 for probe
+ unit unit number (see the paride documentation above)
+ delay I/O delay (see the paride documentation above)
+ ======== ================================================
+
+If you omit the parameters from the end, defaults will be used, e.g.:
+
+Probe all parports with all protocols::
+
+ # echo auto >/sys/bus/pata_parport/new_device
+
+Probe parport0 using protocol epat and mode 4 (EPP-16)::
+
+ # echo "parport0 epat 4" >/sys/bus/pata_parport/new_device
+
+Probe parport0 using all protocols::
+
+ # echo "parport0 auto" >/sys/bus/pata_parport/new_device
+
+Probe all parports using protoocol epat::
+
+ # echo "auto epat" >/sys/bus/pata_parport/new_device
+
+Deleting devices::
+
+ # echo pata_parport.0 >/sys/bus/pata_parport/delete_device
diff --git a/drivers/Makefile b/drivers/Makefile
index bdf1c66141c9..f1365608bc8c 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -98,7 +98,7 @@ obj-$(CONFIG_DIO) += dio/
obj-$(CONFIG_SBUS) += sbus/
obj-$(CONFIG_ZORRO) += zorro/
obj-$(CONFIG_ATA_OVER_ETH) += block/aoe/
-obj-$(CONFIG_PARIDE) += block/paride/
+obj-y += block/paride/
obj-$(CONFIG_TC) += tc/
obj-$(CONFIG_USB_PHY) += usb/
obj-$(CONFIG_USB) += usb/
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index eceaec33af65..fb646480635c 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -1162,6 +1162,20 @@ config PATA_WINBOND_VLB
Support for the Winbond W83759A controller on Vesa Local Bus
systems.

+config PATA_PARPORT
+ tristate "Parallel port IDE device support"
+ depends on PARPORT_PC && PARIDE=n
+ help
+ There are many external CD-ROM and disk devices that connect through
+ your computer's parallel port. Most of them are actually IDE devices
+ using a parallel port IDE adapter. This option enables the
+ PATA_PARPORT subsystem which contains drivers for many of these
+ external drives.
+ Read <file:Documentation/admin-guide/blockdev/paride.rst> for more
+ information.
+
+ Use the old PARIDE protocol modules.
+
comment "Generic fallback / legacy drivers"

config PATA_ACPI
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index d2e36d367274..23588738cff0 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -114,6 +114,8 @@ obj-$(CONFIG_PATA_SAMSUNG_CF) += pata_samsung_cf.o

obj-$(CONFIG_PATA_PXA) += pata_pxa.o

+obj-$(CONFIG_PATA_PARPORT) += pata_parport.o
+
# Should be last but two libata driver
obj-$(CONFIG_PATA_ACPI) += pata_acpi.o
# Should be last but one libata driver
diff --git a/drivers/ata/pata_parport.c b/drivers/ata/pata_parport.c
new file mode 100644
index 000000000000..1c583e54d083
--- /dev/null
+++ b/drivers/ata/pata_parport.c
@@ -0,0 +1,783 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright 2023 Ondrej Zary
+ * based on paride.c by Grant R. Guenther <[email protected]>
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/parport.h>
+#include <linux/pata_parport.h>
+
+#define DRV_NAME "pata_parport"
+
+static DEFINE_IDR(parport_list);
+static DEFINE_IDR(protocols);
+static DEFINE_IDA(pata_parport_bus_dev_ids);
+static DEFINE_MUTEX(pi_mutex);
+
+static bool probe = true;
+module_param(probe, bool, 0644);
+MODULE_PARM_DESC(probe, "Enable automatic device probing (0=off, 1=on [default])");
+
+static bool verbose;
+module_param(verbose, bool, 0644);
+MODULE_PARM_DESC(verbose, "Enable verbose messages (0=off [default], 1=on)");
+
+#define DISCONNECT_TIMEOUT (HZ / 10)
+
+/* libata drivers cannot sleep so this driver claims parport before activating
+ * the ata host and keeps it claimed (and protocol connected) until the ata
+ * host is removed. Unfortunately, this means that you cannot use any chained
+ * devices (neither other pata_parport devices nor a printer).
+ */
+static void pi_connect(struct pi_adapter *pi)
+{
+ parport_claim_or_block(pi->pardev);
+ pi->proto->connect(pi);
+}
+
+static void pi_disconnect(struct pi_adapter *pi)
+{
+ pi->proto->disconnect(pi);
+ parport_release(pi->pardev);
+}
+
+/* functions taken from libata-sff.c and converted from direct port I/O */
+static void pata_parport_dev_select(struct ata_port *ap, unsigned int device)
+{
+ struct pi_adapter *pi = ap->host->private_data;
+ u8 tmp;
+
+ if (device == 0)
+ tmp = ATA_DEVICE_OBS;
+ else
+ tmp = ATA_DEVICE_OBS | ATA_DEV1;
+
+ pi->proto->write_regr(pi, 0, ATA_REG_DEVICE, tmp);
+ ata_sff_pause(ap);
+}
+
+static bool pata_parport_devchk(struct ata_port *ap, unsigned int device)
+{
+ struct pi_adapter *pi = ap->host->private_data;
+ u8 nsect, lbal;
+
+ pata_parport_dev_select(ap, device);
+
+ pi->proto->write_regr(pi, 0, ATA_REG_NSECT, 0x55);
+ pi->proto->write_regr(pi, 0, ATA_REG_LBAL, 0xaa);
+
+ pi->proto->write_regr(pi, 0, ATA_REG_NSECT, 0xaa);
+ pi->proto->write_regr(pi, 0, ATA_REG_LBAL, 0x55);
+
+ pi->proto->write_regr(pi, 0, ATA_REG_NSECT, 055);
+ pi->proto->write_regr(pi, 0, ATA_REG_LBAL, 0xaa);
+
+ nsect = pi->proto->read_regr(pi, 0, ATA_REG_NSECT);
+ lbal = pi->proto->read_regr(pi, 0, ATA_REG_LBAL);
+
+ if ((nsect == 0x55) && (lbal == 0xaa))
+ return true; /* we found a device */
+
+ return false; /* nothing found */
+}
+
+static int pata_parport_bus_softreset(struct ata_port *ap, unsigned int devmask,
+ unsigned long deadline)
+{
+ struct pi_adapter *pi = ap->host->private_data;
+
+ /* software reset. causes dev0 to be selected */
+ pi->proto->write_regr(pi, 1, 6, ap->ctl);
+ udelay(20);
+ pi->proto->write_regr(pi, 1, 6, ap->ctl | ATA_SRST);
+ udelay(20);
+ pi->proto->write_regr(pi, 1, 6, ap->ctl);
+ ap->last_ctl = ap->ctl;
+
+ /* wait the port to become ready */
+ return ata_sff_wait_after_reset(&ap->link, devmask, deadline);
+}
+
+static int pata_parport_softreset(struct ata_link *link, unsigned int *classes,
+ unsigned long deadline)
+{
+ struct ata_port *ap = link->ap;
+ unsigned int devmask = 0;
+ int rc;
+ u8 err;
+
+ /* determine if device 0/1 are present */
+ if (pata_parport_devchk(ap, 0))
+ devmask |= (1 << 0);
+ if (pata_parport_devchk(ap, 1))
+ devmask |= (1 << 1);
+
+ /* select device 0 again */
+ pata_parport_dev_select(ap, 0);
+
+ /* issue bus reset */
+ rc = pata_parport_bus_softreset(ap, devmask, deadline);
+ if (rc && rc != -ENODEV) {
+ ata_link_err(link, "SRST failed (errno=%d)\n", rc);
+ return rc;
+ }
+
+ /* determine by signature whether we have ATA or ATAPI devices */
+ classes[0] = ata_sff_dev_classify(&link->device[0],
+ devmask & (1 << 0), &err);
+ if (err != 0x81)
+ classes[1] = ata_sff_dev_classify(&link->device[1],
+ devmask & (1 << 1), &err);
+
+ return 0;
+}
+
+static u8 pata_parport_check_status(struct ata_port *ap)
+{
+ u8 status;
+ struct pi_adapter *pi = ap->host->private_data;
+
+ status = pi->proto->read_regr(pi, 0, ATA_REG_STATUS);
+
+ return status;
+}
+
+static u8 pata_parport_check_altstatus(struct ata_port *ap)
+{
+ u8 altstatus;
+ struct pi_adapter *pi = ap->host->private_data;
+
+ altstatus = pi->proto->read_regr(pi, 1, 6);
+
+ return altstatus;
+}
+
+static void pata_parport_tf_load(struct ata_port *ap,
+ const struct ata_taskfile *tf)
+{
+ struct pi_adapter *pi = ap->host->private_data;
+
+ if (tf->ctl != ap->last_ctl) {
+ pi->proto->write_regr(pi, 1, 6, tf->ctl);
+ ap->last_ctl = tf->ctl;
+ ata_wait_idle(ap);
+ }
+
+ if (tf->flags & ATA_TFLAG_ISADDR) {
+ if (tf->flags & ATA_TFLAG_LBA48) {
+ pi->proto->write_regr(pi, 0, ATA_REG_FEATURE,
+ tf->hob_feature);
+ pi->proto->write_regr(pi, 0, ATA_REG_NSECT,
+ tf->hob_nsect);
+ pi->proto->write_regr(pi, 0, ATA_REG_LBAL,
+ tf->hob_lbal);
+ pi->proto->write_regr(pi, 0, ATA_REG_LBAM,
+ tf->hob_lbam);
+ pi->proto->write_regr(pi, 0, ATA_REG_LBAH,
+ tf->hob_lbah);
+ }
+ pi->proto->write_regr(pi, 0, ATA_REG_FEATURE, tf->feature);
+ pi->proto->write_regr(pi, 0, ATA_REG_NSECT, tf->nsect);
+ pi->proto->write_regr(pi, 0, ATA_REG_LBAL, tf->lbal);
+ pi->proto->write_regr(pi, 0, ATA_REG_LBAM, tf->lbam);
+ pi->proto->write_regr(pi, 0, ATA_REG_LBAH, tf->lbah);
+ }
+
+ if (tf->flags & ATA_TFLAG_DEVICE)
+ pi->proto->write_regr(pi, 0, ATA_REG_DEVICE, tf->device);
+
+ ata_wait_idle(ap);
+}
+
+static void pata_parport_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+ struct pi_adapter *pi = ap->host->private_data;
+
+ tf->status = pi->proto->read_regr(pi, 0, ATA_REG_STATUS);
+ tf->error = pi->proto->read_regr(pi, 0, ATA_REG_ERR);
+ tf->nsect = pi->proto->read_regr(pi, 0, ATA_REG_NSECT);
+ tf->lbal = pi->proto->read_regr(pi, 0, ATA_REG_LBAL);
+ tf->lbam = pi->proto->read_regr(pi, 0, ATA_REG_LBAM);
+ tf->lbah = pi->proto->read_regr(pi, 0, ATA_REG_LBAH);
+ tf->device = pi->proto->read_regr(pi, 0, ATA_REG_DEVICE);
+
+ if (tf->flags & ATA_TFLAG_LBA48) {
+ pi->proto->write_regr(pi, 1, 6, tf->ctl | ATA_HOB);
+ tf->hob_feature = pi->proto->read_regr(pi, 0, ATA_REG_ERR);
+ tf->hob_nsect = pi->proto->read_regr(pi, 0, ATA_REG_NSECT);
+ tf->hob_lbal = pi->proto->read_regr(pi, 0, ATA_REG_LBAL);
+ tf->hob_lbam = pi->proto->read_regr(pi, 0, ATA_REG_LBAM);
+ tf->hob_lbah = pi->proto->read_regr(pi, 0, ATA_REG_LBAH);
+ pi->proto->write_regr(pi, 1, 6, tf->ctl);
+ ap->last_ctl = tf->ctl;
+ }
+}
+
+static void pata_parport_exec_command(struct ata_port *ap,
+ const struct ata_taskfile *tf)
+{
+ struct pi_adapter *pi = ap->host->private_data;
+
+ pi->proto->write_regr(pi, 0, ATA_REG_CMD, tf->command);
+ ata_sff_pause(ap);
+}
+
+static unsigned int pata_parport_data_xfer(struct ata_queued_cmd *qc,
+ unsigned char *buf, unsigned int buflen, int rw)
+{
+ struct ata_port *ap = qc->dev->link->ap;
+ struct pi_adapter *pi = ap->host->private_data;
+
+ if (rw == READ)
+ pi->proto->read_block(pi, buf, buflen);
+ else
+ pi->proto->write_block(pi, buf, buflen);
+
+ return buflen;
+}
+
+static void pata_parport_drain_fifo(struct ata_queued_cmd *qc)
+{
+ int count;
+ struct ata_port *ap;
+ struct pi_adapter *pi;
+ char junk[2];
+
+ /* We only need to flush incoming data when a command was running */
+ if (qc == NULL || qc->dma_dir == DMA_TO_DEVICE)
+ return;
+
+ ap = qc->ap;
+ pi = ap->host->private_data;
+ /* Drain up to 64K of data before we give up this recovery method */
+ for (count = 0; (pata_parport_check_status(ap) & ATA_DRQ)
+ && count < 65536; count += 2) {
+ pi->proto->read_block(pi, junk, 2);
+ }
+
+ if (count)
+ ata_port_dbg(ap, "drained %d bytes to clear DRQ\n", count);
+}
+
+static struct ata_port_operations pata_parport_port_ops = {
+ .inherits = &ata_sff_port_ops,
+
+ .softreset = pata_parport_softreset,
+ .hardreset = NULL,
+
+ .sff_dev_select = pata_parport_dev_select,
+ .sff_check_status = pata_parport_check_status,
+ .sff_check_altstatus = pata_parport_check_altstatus,
+ .sff_tf_load = pata_parport_tf_load,
+ .sff_tf_read = pata_parport_tf_read,
+ .sff_exec_command = pata_parport_exec_command,
+ .sff_data_xfer = pata_parport_data_xfer,
+ .sff_drain_fifo = pata_parport_drain_fifo,
+};
+
+static const struct ata_port_info pata_parport_port_info = {
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_PIO_POLLING,
+ .pio_mask = ATA_PIO0,
+ /* No DMA */
+ .port_ops = &pata_parport_port_ops,
+};
+
+static void pi_release(struct pi_adapter *pi)
+{
+ parport_unregister_device(pi->pardev);
+ if (pi->proto->release_proto)
+ pi->proto->release_proto(pi);
+ module_put(pi->proto->owner);
+}
+
+static int default_test_proto(struct pi_adapter *pi, char *scratch)
+{
+ int j, k;
+ int e[2] = { 0, 0 };
+
+ pi->proto->connect(pi);
+
+ for (j = 0; j < 2; j++) {
+ pi->proto->write_regr(pi, 0, 6, 0xa0 + j * 0x10);
+ for (k = 0; k < 256; k++) {
+ pi->proto->write_regr(pi, 0, 2, k ^ 0xaa);
+ pi->proto->write_regr(pi, 0, 3, k ^ 0x55);
+ if (pi->proto->read_regr(pi, 0, 2) != (k ^ 0xaa))
+ e[j]++;
+ }
+ }
+ pi->proto->disconnect(pi);
+
+ if (verbose)
+ dev_info(&pi->dev, "%s: port 0x%x, mode %d, test=(%d,%d)\n",
+ pi->proto->name, pi->port,
+ pi->mode, e[0], e[1]);
+
+ return e[0] && e[1]; /* not here if both > 0 */
+}
+
+static int pi_test_proto(struct pi_adapter *pi, char *scratch)
+{
+ int res;
+
+ parport_claim_or_block(pi->pardev);
+ if (pi->proto->test_proto)
+ res = pi->proto->test_proto(pi, scratch, verbose);
+ else
+ res = default_test_proto(pi, scratch);
+ parport_release(pi->pardev);
+
+ return res;
+}
+
+static bool pi_probe_mode(struct pi_adapter *pi, int max, char *scratch)
+{
+ int best, range;
+
+ if (pi->mode != -1) {
+ if (pi->mode >= max)
+ return false;
+ range = 3;
+ if (pi->mode >= pi->proto->epp_first)
+ range = 8;
+ if (range == 8 && pi->port % 8)
+ return false;
+ return !pi_test_proto(pi, scratch);
+ }
+ best = -1;
+ for (pi->mode = 0; pi->mode < max; pi->mode++) {
+ range = 3;
+ if (pi->mode >= pi->proto->epp_first)
+ range = 8;
+ if (range == 8 && pi->port % 8)
+ break;
+ if (!pi_test_proto(pi, scratch))
+ best = pi->mode;
+ }
+ pi->mode = best;
+ return best > -1;
+}
+
+static bool pi_probe_unit(struct pi_adapter *pi, int unit, char *scratch)
+{
+ int max, s, e;
+
+ s = unit;
+ e = s + 1;
+
+ if (s == -1) {
+ s = 0;
+ e = pi->proto->max_units;
+ }
+
+ if (pi->proto->test_port) {
+ parport_claim_or_block(pi->pardev);
+ max = pi->proto->test_port(pi);
+ parport_release(pi->pardev);
+ } else {
+ max = pi->proto->max_mode;
+ }
+
+ if (pi->proto->probe_unit) {
+ parport_claim_or_block(pi->pardev);
+ for (pi->unit = s; pi->unit < e; pi->unit++) {
+ if (pi->proto->probe_unit(pi)) {
+ parport_release(pi->pardev);
+ return pi_probe_mode(pi, max, scratch);
+ }
+ }
+ parport_release(pi->pardev);
+ return false;
+ }
+
+ return pi_probe_mode(pi, max, scratch);
+}
+
+static void pata_parport_dev_release(struct device *dev)
+{
+ struct pi_adapter *pi = container_of(dev, struct pi_adapter, dev);
+
+ kfree(pi);
+}
+
+static void pata_parport_bus_release(struct device *dev)
+{
+ /* nothing to do here but required to avoid warning on device removal */
+}
+
+static struct bus_type pata_parport_bus_type = {
+ .name = DRV_NAME,
+};
+
+static struct device pata_parport_bus = {
+ .init_name = DRV_NAME,
+ .release = pata_parport_bus_release,
+};
+
+/* temporary for old paride protocol modules */
+static struct scsi_host_template pata_parport_sht = {
+ PATA_PARPORT_SHT("pata_parport")
+};
+
+struct pi_device_match {
+ struct parport *parport;
+ struct pi_protocol *proto;
+};
+
+static int pi_find_dev(struct device *dev, void *data)
+{
+ struct pi_adapter *pi = container_of(dev, struct pi_adapter, dev);
+ struct pi_device_match *match = data;
+
+ return pi->pardev->port == match->parport && pi->proto == match->proto;
+}
+
+static struct pi_adapter *pi_init_one(struct parport *parport,
+ struct pi_protocol *pr, int mode, int unit, int delay)
+{
+ struct pardev_cb par_cb = { };
+ char scratch[512];
+ const struct ata_port_info *ppi[] = { &pata_parport_port_info };
+ struct ata_host *host;
+ struct pi_adapter *pi;
+ struct pi_device_match match = { .parport = parport, .proto = pr };
+
+ /*
+ * Abort if there's a device already registered on the same parport
+ * using the same protocol.
+ */
+ if (bus_for_each_dev(&pata_parport_bus_type, NULL, &match, pi_find_dev))
+ return NULL;
+
+ pi = kzalloc(sizeof(struct pi_adapter), GFP_KERNEL);
+ if (!pi)
+ return NULL;
+
+ /* set up pi->dev before pi_probe_unit() so it can use dev_printk() */
+ pi->dev.parent = &pata_parport_bus;
+ pi->dev.bus = &pata_parport_bus_type;
+ pi->dev.driver = &pr->driver;
+ pi->dev.release = pata_parport_dev_release;
+ pi->dev.id = ida_alloc(&pata_parport_bus_dev_ids, GFP_KERNEL);
+ if (pi->dev.id < 0)
+ return NULL; /* pata_parport_dev_release will do kfree(pi) */
+ dev_set_name(&pi->dev, "pata_parport.%u", pi->dev.id);
+ if (device_register(&pi->dev)) {
+ put_device(&pi->dev);
+ goto out_ida_free;
+ }
+
+ pi->proto = pr;
+
+ if (!try_module_get(pi->proto->owner))
+ goto out_unreg_dev;
+ if (pi->proto->init_proto && pi->proto->init_proto(pi) < 0)
+ goto out_module_put;
+
+ pi->delay = (delay == -1) ? pi->proto->default_delay : delay;
+ pi->mode = mode;
+ pi->port = parport->base;
+
+ par_cb.private = pi;
+ pi->pardev = parport_register_dev_model(parport, DRV_NAME, &par_cb,
+ pi->dev.id);
+ if (!pi->pardev)
+ goto out_module_put;
+
+ if (!pi_probe_unit(pi, unit, scratch)) {
+ dev_info(&pi->dev, "Adapter not found\n");
+ goto out_unreg_parport;
+ }
+
+ pi->proto->log_adapter(pi, scratch, verbose);
+
+ host = ata_host_alloc_pinfo(&pi->pardev->dev, ppi, 1);
+ if (!host)
+ goto out_unreg_parport;
+ dev_set_drvdata(&pi->dev, host);
+ host->private_data = pi;
+
+ ata_port_desc(host->ports[0], "port %s", pi->pardev->port->name);
+ ata_port_desc(host->ports[0], "protocol %s", pi->proto->name);
+
+ pi_connect(pi);
+ if (ata_host_activate(host, 0, NULL, 0, &pata_parport_sht))
+ goto out_unreg_parport;
+
+ return pi;
+
+out_unreg_parport:
+ pi_disconnect(pi);
+ parport_unregister_device(pi->pardev);
+ if (pi->proto->release_proto)
+ pi->proto->release_proto(pi);
+out_module_put:
+ module_put(pi->proto->owner);
+out_unreg_dev:
+ device_unregister(&pi->dev);
+out_ida_free:
+ ida_free(&pata_parport_bus_dev_ids, pi->dev.id);
+ return NULL;
+}
+
+int pata_parport_register_driver(struct pi_protocol *pr)
+{
+ int error;
+ struct parport *parport;
+ int port_num;
+
+ pr->driver.bus = &pata_parport_bus_type;
+ pr->driver.name = pr->name;
+ error = driver_register(&pr->driver);
+ if (error)
+ return error;
+
+ mutex_lock(&pi_mutex);
+ error = idr_alloc(&protocols, pr, 0, 0, GFP_KERNEL);
+ if (error < 0) {
+ driver_unregister(&pr->driver);
+ mutex_unlock(&pi_mutex);
+ return error;
+ }
+
+ pr_info("pata_parport: protocol %s registered\n", pr->name);
+
+ if (probe) {
+ /* probe all parports using this protocol */
+ idr_for_each_entry(&parport_list, parport, port_num)
+ pi_init_one(parport, pr, -1, 0, -1);
+ }
+ mutex_unlock(&pi_mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL(pata_parport_register_driver);
+
+void pata_parport_unregister_driver(struct pi_protocol *pr)
+{
+ struct pi_protocol *pr_iter;
+ int id = -1;
+
+ mutex_lock(&pi_mutex);
+ idr_for_each_entry(&protocols, pr_iter, id) {
+ if (pr_iter == pr)
+ break;
+ }
+ idr_remove(&protocols, id);
+ mutex_unlock(&pi_mutex);
+ driver_unregister(&pr->driver);
+}
+EXPORT_SYMBOL(pata_parport_unregister_driver);
+
+static ssize_t new_device_store(struct bus_type *bus, const char *buf,
+ size_t count)
+{
+ char port[12] = "auto";
+ char protocol[8] = "auto";
+ int mode = -1, unit = -1, delay = -1;
+ struct pi_protocol *pr, *pr_wanted;
+ struct device_driver *drv;
+ struct parport *parport;
+ int port_num, port_wanted, pr_num;
+ bool ok = false;
+
+ if (sscanf(buf, "%11s %7s %d %d %d",
+ port, protocol, &mode, &unit, &delay) < 1)
+ return -EINVAL;
+
+ if (sscanf(port, "parport%u", &port_wanted) < 1) {
+ if (!strcmp(port, "auto")) {
+ port_wanted = -1;
+ } else {
+ pr_err("invalid port name %s\n", port);
+ return -EINVAL;
+ }
+ }
+
+ drv = driver_find(protocol, &pata_parport_bus_type);
+ if (!drv) {
+ if (!strcmp(protocol, "auto")) {
+ pr_wanted = NULL;
+ } else {
+ pr_err("protocol %s not found\n", protocol);
+ return -EINVAL;
+ }
+ } else {
+ pr_wanted = container_of(drv, struct pi_protocol, driver);
+ }
+
+ mutex_lock(&pi_mutex);
+ /* walk all parports */
+ idr_for_each_entry(&parport_list, parport, port_num) {
+ if (port_num == port_wanted || port_wanted == -1) {
+ parport = parport_find_number(port_num);
+ if (!parport) {
+ pr_err("no such port %s\n", port);
+ mutex_unlock(&pi_mutex);
+ return -ENODEV;
+ }
+ /* walk all protocols */
+ idr_for_each_entry(&protocols, pr, pr_num) {
+ if (pr == pr_wanted || !pr_wanted)
+ if (pi_init_one(parport, pr, mode, unit,
+ delay))
+ ok = true;
+ }
+ parport_put_port(parport);
+ }
+ }
+ mutex_unlock(&pi_mutex);
+ if (!ok)
+ return -ENODEV;
+
+ return count;
+}
+static BUS_ATTR_WO(new_device);
+
+static void pi_remove_one(struct device *dev)
+{
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct pi_adapter *pi = host->private_data;
+
+ ata_host_detach(host);
+ pi_disconnect(pi);
+ pi_release(pi);
+ device_unregister(dev);
+ ida_free(&pata_parport_bus_dev_ids, dev->id);
+ /* pata_parport_dev_release will do kfree(pi) */
+}
+
+static ssize_t delete_device_store(struct bus_type *bus, const char *buf,
+ size_t count)
+{
+ struct device *dev;
+ char device_name[32];
+
+ if (sscanf(buf, "%31s", device_name) < 1)
+ return -EINVAL;
+
+ mutex_lock(&pi_mutex);
+ dev = bus_find_device_by_name(bus, NULL, device_name);
+ if (!dev) {
+ mutex_unlock(&pi_mutex);
+ return -ENODEV;
+ }
+
+ pi_remove_one(dev);
+ mutex_unlock(&pi_mutex);
+
+ return count;
+}
+static BUS_ATTR_WO(delete_device);
+
+static void pata_parport_attach(struct parport *port)
+{
+ struct pi_protocol *pr;
+ int pr_num, id;
+
+ mutex_lock(&pi_mutex);
+ id = idr_alloc(&parport_list, port, port->number, port->number,
+ GFP_KERNEL);
+ if (id < 0) {
+ mutex_unlock(&pi_mutex);
+ return;
+ }
+
+ if (probe) {
+ /* probe this port using all protocols */
+ idr_for_each_entry(&protocols, pr, pr_num)
+ pi_init_one(port, pr, -1, 0, -1);
+ }
+ mutex_unlock(&pi_mutex);
+}
+
+static int pi_remove_port(struct device *dev, void *p)
+{
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct pi_adapter *pi = host->private_data;
+
+ if (pi->pardev->port == p)
+ pi_remove_one(dev);
+
+ return 0;
+}
+
+static void pata_parport_detach(struct parport *port)
+{
+ mutex_lock(&pi_mutex);
+ bus_for_each_dev(&pata_parport_bus_type, NULL, port, pi_remove_port);
+ idr_remove(&parport_list, port->number);
+ mutex_unlock(&pi_mutex);
+}
+
+static struct parport_driver pata_parport_driver = {
+ .name = DRV_NAME,
+ .match_port = pata_parport_attach,
+ .detach = pata_parport_detach,
+ .devmodel = true,
+};
+
+static __init int pata_parport_init(void)
+{
+ int error;
+
+ error = bus_register(&pata_parport_bus_type);
+ if (error) {
+ pr_err("failed to register pata_parport bus, error: %d\n", error);
+ return error;
+ }
+
+ error = device_register(&pata_parport_bus);
+ if (error) {
+ pr_err("failed to register pata_parport bus, error: %d\n", error);
+ goto out_unregister_bus;
+ }
+
+ error = bus_create_file(&pata_parport_bus_type, &bus_attr_new_device);
+ if (error) {
+ pr_err("unable to create sysfs file, error: %d\n", error);
+ goto out_unregister_dev;
+ }
+
+ error = bus_create_file(&pata_parport_bus_type, &bus_attr_delete_device);
+ if (error) {
+ pr_err("unable to create sysfs file, error: %d\n", error);
+ goto out_remove_new;
+ }
+
+ error = parport_register_driver(&pata_parport_driver);
+ if (error) {
+ pr_err("unable to register parport driver, error: %d\n", error);
+ goto out_remove_del;
+ }
+
+ return 0;
+
+out_remove_del:
+ bus_remove_file(&pata_parport_bus_type, &bus_attr_delete_device);
+out_remove_new:
+ bus_remove_file(&pata_parport_bus_type, &bus_attr_new_device);
+out_unregister_dev:
+ device_unregister(&pata_parport_bus);
+out_unregister_bus:
+ bus_unregister(&pata_parport_bus_type);
+ return error;
+}
+
+static __exit void pata_parport_exit(void)
+{
+ parport_unregister_driver(&pata_parport_driver);
+ bus_remove_file(&pata_parport_bus_type, &bus_attr_new_device);
+ bus_remove_file(&pata_parport_bus_type, &bus_attr_delete_device);
+ device_unregister(&pata_parport_bus);
+ bus_unregister(&pata_parport_bus_type);
+}
+
+MODULE_AUTHOR("Ondrej Zary");
+MODULE_DESCRIPTION("driver for parallel port ATA adapters");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("paride");
+
+module_init(pata_parport_init);
+module_exit(pata_parport_exit);
diff --git a/drivers/block/paride/Kconfig b/drivers/block/paride/Kconfig
index a295634597ba..01e4ef3655c1 100644
--- a/drivers/block/paride/Kconfig
+++ b/drivers/block/paride/Kconfig
@@ -92,11 +92,11 @@ config PARIDE_PG
later fully support this driver.

comment "Parallel IDE protocol modules"
- depends on PARIDE
+ depends on PARIDE || PATA_PARPORT

config PARIDE_ATEN
tristate "ATEN EH-100 protocol"
- depends on PARIDE
+ depends on PARIDE || PATA_PARPORT
help
This option enables support for the ATEN EH-100 parallel port IDE
protocol. This protocol is used in some inexpensive low performance
@@ -109,7 +109,7 @@ config PARIDE_ATEN

config PARIDE_BPCK
tristate "MicroSolutions backpack (Series 5) protocol"
- depends on PARIDE
+ depends on PARIDE || PATA_PARPORT
help
This option enables support for the Micro Solutions BACKPACK
parallel port Series 5 IDE protocol. (Most BACKPACK drives made
@@ -127,7 +127,7 @@ config PARIDE_BPCK

config PARIDE_BPCK6
tristate "MicroSolutions backpack (Series 6) protocol"
- depends on PARIDE && !64BIT
+ depends on (PARIDE || PATA_PARPORT) && !64BIT
help
This option enables support for the Micro Solutions BACKPACK
parallel port Series 6 IDE protocol. (Most BACKPACK drives made
@@ -146,7 +146,7 @@ config PARIDE_BPCK6

config PARIDE_COMM
tristate "DataStor Commuter protocol"
- depends on PARIDE
+ depends on PARIDE || PATA_PARPORT
help
This option enables support for the Commuter parallel port IDE
protocol from DataStor. If you chose to build PARIDE support
@@ -157,7 +157,7 @@ config PARIDE_COMM

config PARIDE_DSTR
tristate "DataStor EP-2000 protocol"
- depends on PARIDE
+ depends on PARIDE || PATA_PARPORT
help
This option enables support for the EP-2000 parallel port IDE
protocol from DataStor. If you chose to build PARIDE support
@@ -168,7 +168,7 @@ config PARIDE_DSTR

config PARIDE_FIT2
tristate "FIT TD-2000 protocol"
- depends on PARIDE
+ depends on PARIDE || PATA_PARPORT
help
This option enables support for the TD-2000 parallel port IDE
protocol from Fidelity International Technology. This is a simple
@@ -181,7 +181,7 @@ config PARIDE_FIT2

config PARIDE_FIT3
tristate "FIT TD-3000 protocol"
- depends on PARIDE
+ depends on PARIDE || PATA_PARPORT
help
This option enables support for the TD-3000 parallel port IDE
protocol from Fidelity International Technology. This protocol is
@@ -194,7 +194,7 @@ config PARIDE_FIT3

config PARIDE_EPAT
tristate "Shuttle EPAT/EPEZ protocol"
- depends on PARIDE
+ depends on PARIDE || PATA_PARPORT
help
This option enables support for the EPAT parallel port IDE protocol.
EPAT is a parallel port IDE adapter manufactured by Shuttle
@@ -216,7 +216,7 @@ config PARIDE_EPATC8

config PARIDE_EPIA
tristate "Shuttle EPIA protocol"
- depends on PARIDE
+ depends on PARIDE || PATA_PARPORT
help
This option enables support for the (obsolete) EPIA parallel port
IDE protocol from Shuttle Technology. This adapter can still be
@@ -228,7 +228,7 @@ config PARIDE_EPIA

config PARIDE_FRIQ
tristate "Freecom IQ ASIC-2 protocol"
- depends on PARIDE
+ depends on PARIDE || PATA_PARPORT
help
This option enables support for version 2 of the Freecom IQ parallel
port IDE adapter. This adapter is used by the Maxell Superdisk
@@ -240,7 +240,7 @@ config PARIDE_FRIQ

config PARIDE_FRPW
tristate "FreeCom power protocol"
- depends on PARIDE
+ depends on PARIDE || PATA_PARPORT
help
This option enables support for the Freecom power parallel port IDE
protocol. If you chose to build PARIDE support into your kernel, you
@@ -251,7 +251,7 @@ config PARIDE_FRPW

config PARIDE_KBIC
tristate "KingByte KBIC-951A/971A protocols"
- depends on PARIDE
+ depends on PARIDE || PATA_PARPORT
help
This option enables support for the KBIC-951A and KBIC-971A parallel
port IDE protocols from KingByte Information Corp. KingByte's
@@ -264,7 +264,7 @@ config PARIDE_KBIC

config PARIDE_KTTI
tristate "KT PHd protocol"
- depends on PARIDE
+ depends on PARIDE || PATA_PARPORT
help
This option enables support for the "PHd" parallel port IDE protocol
from KT Technology. This is a simple (low speed) adapter that is
@@ -277,7 +277,7 @@ config PARIDE_KTTI

config PARIDE_ON20
tristate "OnSpec 90c20 protocol"
- depends on PARIDE
+ depends on PARIDE || PATA_PARPORT
help
This option enables support for the (obsolete) 90c20 parallel port
IDE protocol from OnSpec (often marketed under the ValuStore brand
@@ -289,7 +289,7 @@ config PARIDE_ON20

config PARIDE_ON26
tristate "OnSpec 90c26 protocol"
- depends on PARIDE
+ depends on PARIDE || PATA_PARPORT
help
This option enables support for the 90c26 parallel port IDE protocol
from OnSpec Electronics (often marketed under the ValuStore brand
diff --git a/drivers/block/paride/paride.h b/drivers/block/paride/paride.h
index ddb9e589da7f..24dcfadb782d 100644
--- a/drivers/block/paride/paride.h
+++ b/drivers/block/paride/paride.h
@@ -1,3 +1,15 @@
+/*
+ * The low-level protocol modules are used by either paride or pata_parport.
+ * These two are mutually exclusive because the compiled low-level protocol
+ * modules are not compatible.
+ * When PATA_PARPORT is enabled, include pata_parport.h instead of the rest
+ * of this file.
+ */
+
+#if IS_ENABLED(CONFIG_PATA_PARPORT)
+#include <linux/pata_parport.h>
+
+#else
#ifndef __DRIVERS_PARIDE_H__
#define __DRIVERS_PARIDE_H__

@@ -170,3 +182,4 @@ void pi_unregister_driver(void *);

#endif /* __DRIVERS_PARIDE_H__ */
/* end of paride.h */
+#endif /* IS_ENABLED(CONFIG_PATA_PARPORT) */
diff --git a/include/linux/pata_parport.h b/include/linux/pata_parport.h
new file mode 100644
index 000000000000..913f49ff1fad
--- /dev/null
+++ b/include/linux/pata_parport.h
@@ -0,0 +1,106 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * pata_parport.h (c) 1997-8 Grant R. Guenther <[email protected]>
+ * Under the terms of the GPL.
+ *
+ * This file defines the interface for parallel port IDE adapter chip drivers.
+ */
+
+#include <linux/libata.h>
+
+#define PI_PCD 1 /* dummy for paride protocol modules */
+
+struct pi_adapter {
+ struct device dev;
+ struct pi_protocol *proto; /* adapter protocol */
+ int port; /* base address of parallel port */
+ int mode; /* transfer mode in use */
+ int delay; /* adapter delay setting */
+ int devtype; /* dummy for paride protocol modules */
+ char *device; /* dummy for paride protocol modules */
+ int unit; /* unit number for chained adapters */
+ int saved_r0; /* saved port state */
+ int saved_r2; /* saved port state */
+ unsigned long private; /* for protocol module */
+ struct pardevice *pardev; /* pointer to pardevice */
+};
+
+typedef struct pi_adapter PIA; /* for paride protocol modules */
+
+/* registers are addressed as (cont,regr)
+ * cont: 0 for command register file, 1 for control register(s)
+ * regr: 0-7 for register number.
+ */
+
+/* macros and functions exported to the protocol modules */
+#define delay_p (pi->delay ? udelay(pi->delay) : (void)0)
+#define out_p(offs, byte) do { outb(byte, pi->port + offs); delay_p; } while (0)
+#define in_p(offs) (delay_p, inb(pi->port + offs))
+
+#define w0(byte) out_p(0, byte)
+#define r0() in_p(0)
+#define w1(byte) out_p(1, byte)
+#define r1() in_p(1)
+#define w2(byte) out_p(2, byte)
+#define r2() in_p(2)
+#define w3(byte) out_p(3, byte)
+#define w4(byte) out_p(4, byte)
+#define r4() in_p(4)
+#define w4w(data) do { outw(data, pi->port + 4); delay_p; } while (0)
+#define w4l(data) do { outl(data, pi->port + 4); delay_p; } while (0)
+#define r4w() (delay_p, inw(pi->port + 4))
+#define r4l() (delay_p, inl(pi->port + 4))
+
+static inline u16 pi_swab16(char *b, int k)
+{
+ union { u16 u; char t[2]; } r;
+
+ r.t[0] = b[2 * k + 1]; r.t[1] = b[2 * k];
+ return r.u;
+}
+
+static inline u32 pi_swab32(char *b, int k)
+{
+ union { u32 u; char f[4]; } r;
+
+ r.f[0] = b[4 * k + 1]; r.f[1] = b[4 * k];
+ r.f[2] = b[4 * k + 3]; r.f[3] = b[4 * k + 2];
+ return r.u;
+}
+
+struct pi_protocol {
+ char name[8];
+
+ int max_mode;
+ int epp_first; /* modes >= this use 8 ports */
+
+ int default_delay;
+ int max_units; /* max chained units probed for */
+
+ void (*write_regr)(struct pi_adapter *pi, int cont, int regr, int val);
+ int (*read_regr)(struct pi_adapter *pi, int cont, int regr);
+ void (*write_block)(struct pi_adapter *pi, char *buf, int count);
+ void (*read_block)(struct pi_adapter *pi, char *buf, int count);
+
+ void (*connect)(struct pi_adapter *pi);
+ void (*disconnect)(struct pi_adapter *pi);
+
+ int (*test_port)(struct pi_adapter *pi);
+ int (*probe_unit)(struct pi_adapter *pi);
+ int (*test_proto)(struct pi_adapter *pi, char *scratch, int verbose);
+ void (*log_adapter)(struct pi_adapter *pi, char *scratch, int verbose);
+
+ int (*init_proto)(struct pi_adapter *pi);
+ void (*release_proto)(struct pi_adapter *pi);
+ struct module *owner;
+ struct device_driver driver;
+ struct scsi_host_template sht;
+};
+
+#define PATA_PARPORT_SHT ATA_PIO_SHT
+
+int pata_parport_register_driver(struct pi_protocol *pr);
+void pata_parport_unregister_driver(struct pi_protocol *pr);
+/* defines for old paride protocol modules */
+#define paride_register pata_parport_register_driver
+#define paride_unregister pata_parport_unregister_driver
--
Ondrej Zary


2023-01-22 08:35:33

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [PATCH v2] pata_parport: add driver (PARIDE replacement)

I suspect a comment in the Kconfig for the old PARIDE code to point
to this and maybe even a runtime warning when using the old paride
code would be great.

But except for that the code looks awesome, so let's get it merged ASAP:

Reviewed-by: Christoph Hellwig <[email protected]>

2023-01-22 18:14:27

by Ondrej Zary

[permalink] [raw]
Subject: [PATCH] paride: Mark PARIDE as deprecated, point to PATA_PARPORT

Add Kconfig and runtime deprecation warnings to PARIDE, pointing users
to PATA_PARPORT.

Signed-off-by: Ondrej Zary <[email protected]>
---
drivers/block/Kconfig | 4 +++-
drivers/block/paride/paride.c | 2 ++
2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index a2184b428493..3a2065c6a4d7 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -104,7 +104,7 @@ config GDROM
You can also build this as a module which will be called gdrom.

config PARIDE
- tristate "Parallel port IDE device support"
+ tristate "Parallel port IDE device support (DEPRECATED)"
depends on PARPORT_PC
help
There are many external CD-ROM and disk devices that connect through
@@ -130,6 +130,8 @@ config PARIDE
"MicroSolutions backpack protocol", "DataStor Commuter protocol"
etc.).

+ This driver is deprecated, replaced by libata-based PATA_PARPORT.
+
source "drivers/block/paride/Kconfig"

source "drivers/block/mtip32xx/Kconfig"
diff --git a/drivers/block/paride/paride.c b/drivers/block/paride/paride.c
index 0e287993b778..010daf605728 100644
--- a/drivers/block/paride/paride.c
+++ b/drivers/block/paride/paride.c
@@ -452,6 +452,8 @@ void *pi_register_driver(char *name)
struct parport_driver *parp_drv;
int ret;

+ printk(KERN_WARNING "PARIDE is deprecated. Use PATA_PARPORT instead.\n");
+
parp_drv = kzalloc(sizeof(*parp_drv), GFP_KERNEL);
if (!parp_drv)
return NULL;
--
Ondrej Zary


2023-01-22 18:24:40

by Jens Axboe

[permalink] [raw]
Subject: Re: [PATCH v2] pata_parport: add driver (PARIDE replacement)

On 1/22/23 12:57 AM, Christoph Hellwig wrote:
> I suspect a comment in the Kconfig for the old PARIDE code to point
> to this and maybe even a runtime warning when using the old paride
> code would be great.
>
> But except for that the code looks awesome, so let's get it merged ASAP:
>
> Reviewed-by: Christoph Hellwig <[email protected]>

Since Ondrej is probably one of the few (maybe the only) user of this
code, why don't we just kill off the paride code in a separate patch
right after?

--
Jens Axboe



2023-01-22 19:11:56

by Sergey Shtylyov

[permalink] [raw]
Subject: Re: [PATCH] paride: Mark PARIDE as deprecated, point to PATA_PARPORT

Hello!

On 1/22/23 9:14 PM, Ondrej Zary wrote:

> Add Kconfig and runtime deprecation warnings to PARIDE, pointing users
> to PATA_PARPORT.
>
> Signed-off-by: Ondrej Zary <[email protected]>
[...]
> diff --git a/drivers/block/paride/paride.c b/drivers/block/paride/paride.c
> index 0e287993b778..010daf605728 100644
> --- a/drivers/block/paride/paride.c
> +++ b/drivers/block/paride/paride.c
> @@ -452,6 +452,8 @@ void *pi_register_driver(char *name)
> struct parport_driver *parp_drv;
> int ret;
>
> + printk(KERN_WARNING "PARIDE is deprecated. Use PATA_PARPORT instead.\n");

Why not pr_warn()?

[...]

MBR, Sergey

2023-01-22 20:11:01

by Ondrej Zary

[permalink] [raw]
Subject: [PATCH v2] paride: Mark PARIDE as deprecated, point to PATA_PARPORT

Add Kconfig and runtime deprecation warnings to PARIDE, pointing users
to PATA_PARPORT.

Signed-off-by: Ondrej Zary <[email protected]>
---
drivers/block/Kconfig | 4 +++-
drivers/block/paride/paride.c | 2 ++
2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index a2184b428493..3a2065c6a4d7 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -104,7 +104,7 @@ config GDROM
You can also build this as a module which will be called gdrom.

config PARIDE
- tristate "Parallel port IDE device support"
+ tristate "Parallel port IDE device support (DEPRECATED)"
depends on PARPORT_PC
help
There are many external CD-ROM and disk devices that connect through
@@ -130,6 +130,8 @@ config PARIDE
"MicroSolutions backpack protocol", "DataStor Commuter protocol"
etc.).

+ This driver is deprecated, replaced by libata-based PATA_PARPORT.
+
source "drivers/block/paride/Kconfig"

source "drivers/block/mtip32xx/Kconfig"
diff --git a/drivers/block/paride/paride.c b/drivers/block/paride/paride.c
index 0e287993b778..a4a49da9d0d2 100644
--- a/drivers/block/paride/paride.c
+++ b/drivers/block/paride/paride.c
@@ -452,6 +452,8 @@ void *pi_register_driver(char *name)
struct parport_driver *parp_drv;
int ret;

+ pr_warn("PARIDE is deprecated. Use PATA_PARPORT instead.\n");
+
parp_drv = kzalloc(sizeof(*parp_drv), GFP_KERNEL);
if (!parp_drv)
return NULL;
--
Ondrej Zary


2023-01-23 01:03:27

by Damien Le Moal

[permalink] [raw]
Subject: Re: [PATCH v2] pata_parport: add driver (PARIDE replacement)

On 1/22/23 07:53, Ondrej Zary wrote:
> The pata_parport is a libata-based replacement of the old PARIDE
> subsystem - driver for parallel port IDE devices.
> It uses the original paride low-level protocol drivers but does not
> need the high-level drivers (pd, pcd, pf, pt, pg). The IDE devices
> behind parallel port adapters are handled by the ATA layer.
>
> This will allow paride and its high-level drivers to be removed.
>
> Unfortunately, libata drivers cannot sleep so pata_parport claims
> parport before activating the ata host and keeps it claimed (and
> protocol connected) until the ata host is removed. This means that
> no devices can be chained (neither other pata_parport devices nor
> a printer).
>
> paride and pata_parport are mutually exclusive because the compiled
> protocol drivers are incompatible.
>
> Tested with:
> - Imation SuperDisk LS-120 and HP C4381A (EPAT)
> - Freecom Parallel CD (FRPW)
> - Toshiba Mobile CD-RW 2793008 w/Freecom Parallel Cable rev.903 (FRIQ)
> - Backpack CD-RW 222011 and CD-RW 19350 (BPCK6)
>
> The following bugs in low-level protocol drivers were found and will
> be fixed later:
>
> Note: EPP-32 mode is buggy in EPAT - and also in all other protocol
> drivers - they don't handle non-multiple-of-4 block transfers
> correctly. This causes problems with LS-120 drive.
> There is also another bug in EPAT: EPP modes don't work unless a 4-bit
> or 8-bit mode is used first (probably some initialization missing?).
> Once the device is initialized, EPP works until power cycle.
>
> So after device power on, you have to:
> echo "parport0 epat 0" >/sys/bus/pata_parport/new_device
> echo pata_parport.0 >/sys/bus/pata_parport/delete_device
> echo "parport0 epat 4" >/sys/bus/pata_parport/new_device
> (autoprobe will initialize correctly as it tries the slowest modes
> first but you'll get the broken EPP-32 mode)
>
> Note: EPP modes are buggy in FRPW, only modes 0 and 1 work.
> Signed-off-by: Ondrej Zary <[email protected]>

Overall, look good to me. Several comments below about simple
cleanups/improvements.

> ---

[...]
> diff --git a/drivers/ata/pata_parport.c b/drivers/ata/pata_parport.c
> new file mode 100644
> index 000000000000..1c583e54d083
> --- /dev/null
> +++ b/drivers/ata/pata_parport.c
> @@ -0,0 +1,783 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright 2023 Ondrej Zary
> + * based on paride.c by Grant R. Guenther <[email protected]>
> + */
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/parport.h>
> +#include <linux/pata_parport.h>
> +
> +#define DRV_NAME "pata_parport"
> +
> +static DEFINE_IDR(parport_list);
> +static DEFINE_IDR(protocols);
> +static DEFINE_IDA(pata_parport_bus_dev_ids);
> +static DEFINE_MUTEX(pi_mutex);
> +
> +static bool probe = true;
> +module_param(probe, bool, 0644);
> +MODULE_PARM_DESC(probe, "Enable automatic device probing (0=off, 1=on [default])");
> +
> +static bool verbose;
> +module_param(verbose, bool, 0644);
> +MODULE_PARM_DESC(verbose, "Enable verbose messages (0=off [default], 1=on)");

This is not needed. Use dynamic pr_debug()/dev_dbg() instead.

> +
> +#define DISCONNECT_TIMEOUT (HZ / 10)
> +
> +/* libata drivers cannot sleep so this driver claims parport before activating
> + * the ata host and keeps it claimed (and protocol connected) until the ata
> + * host is removed. Unfortunately, this means that you cannot use any chained
> + * devices (neither other pata_parport devices nor a printer).
> + */

Incorrect comment format. This should start with a "/*" line.

> +static void pi_connect(struct pi_adapter *pi)
> +{
> + parport_claim_or_block(pi->pardev);
> + pi->proto->connect(pi);
> +}
> +
> +static void pi_disconnect(struct pi_adapter *pi)
> +{
> + pi->proto->disconnect(pi);
> + parport_release(pi->pardev);
> +}
> +
> +/* functions taken from libata-sff.c and converted from direct port I/O */

I do not see how this comment is useful. I think you can drop it.

> +static void pata_parport_dev_select(struct ata_port *ap, unsigned int device)
> +{
> + struct pi_adapter *pi = ap->host->private_data;
> + u8 tmp;
> +
> + if (device == 0)
> + tmp = ATA_DEVICE_OBS;
> + else
> + tmp = ATA_DEVICE_OBS | ATA_DEV1;
> +
> + pi->proto->write_regr(pi, 0, ATA_REG_DEVICE, tmp);
> + ata_sff_pause(ap);
> +}
> +
> +static bool pata_parport_devchk(struct ata_port *ap, unsigned int device)
> +{
> + struct pi_adapter *pi = ap->host->private_data;
> + u8 nsect, lbal;
> +
> + pata_parport_dev_select(ap, device);
> +
> + pi->proto->write_regr(pi, 0, ATA_REG_NSECT, 0x55);
> + pi->proto->write_regr(pi, 0, ATA_REG_LBAL, 0xaa);
> +
> + pi->proto->write_regr(pi, 0, ATA_REG_NSECT, 0xaa);
> + pi->proto->write_regr(pi, 0, ATA_REG_LBAL, 0x55);
> +
> + pi->proto->write_regr(pi, 0, ATA_REG_NSECT, 055);
> + pi->proto->write_regr(pi, 0, ATA_REG_LBAL, 0xaa);
> +
> + nsect = pi->proto->read_regr(pi, 0, ATA_REG_NSECT);
> + lbal = pi->proto->read_regr(pi, 0, ATA_REG_LBAL);
> +
> + if ((nsect == 0x55) && (lbal == 0xaa))
> + return true; /* we found a device */
> +
> + return false; /* nothing found */

Simplify:

return (nsect == 0x55) && (lbal == 0xaa);

[...]

> +static u8 pata_parport_check_status(struct ata_port *ap)
> +{
> + u8 status;
> + struct pi_adapter *pi = ap->host->private_data;
> +
> + status = pi->proto->read_regr(pi, 0, ATA_REG_STATUS);
> +
> + return status;

The status variable is not necessary. Simply do:

return pi->proto->read_regr(pi, 0, ATA_REG_STATUS);

> +}
> +
> +static u8 pata_parport_check_altstatus(struct ata_port *ap)
> +{
> + u8 altstatus;
> + struct pi_adapter *pi = ap->host->private_data;
> +
> + altstatus = pi->proto->read_regr(pi, 1, 6);
> +
> + return altstatus;

Same here for altstatus.

[...]

> +static int default_test_proto(struct pi_adapter *pi, char *scratch)
> +{
> + int j, k;
> + int e[2] = { 0, 0 };
> +
> + pi->proto->connect(pi);
> +
> + for (j = 0; j < 2; j++) {
> + pi->proto->write_regr(pi, 0, 6, 0xa0 + j * 0x10);
> + for (k = 0; k < 256; k++) {
> + pi->proto->write_regr(pi, 0, 2, k ^ 0xaa);
> + pi->proto->write_regr(pi, 0, 3, k ^ 0x55);
> + if (pi->proto->read_regr(pi, 0, 2) != (k ^ 0xaa))
> + e[j]++;
> + }
> + }
> + pi->proto->disconnect(pi);
> +
> + if (verbose)
> + dev_info(&pi->dev, "%s: port 0x%x, mode %d, test=(%d,%d)\n",
> + pi->proto->name, pi->port,
> + pi->mode, e[0], e[1]);

Please remove the "if (verbose)" and use dev_dbg().

[...]

> +static struct bus_type pata_parport_bus_type = {
> + .name = DRV_NAME,
> +};
> +
> +static struct device pata_parport_bus = {
> + .init_name = DRV_NAME,
> + .release = pata_parport_bus_release,
> +};
> +
> +/* temporary for old paride protocol modules */

s/temporary/necessary ?

[...]

> +int pata_parport_register_driver(struct pi_protocol *pr)
> +{
> + int error;
> + struct parport *parport;
> + int port_num;
> +
> + pr->driver.bus = &pata_parport_bus_type;
> + pr->driver.name = pr->name;
> + error = driver_register(&pr->driver);
> + if (error)
> + return error;
> +
> + mutex_lock(&pi_mutex);
> + error = idr_alloc(&protocols, pr, 0, 0, GFP_KERNEL);
> + if (error < 0) {
> + driver_unregister(&pr->driver);
> + mutex_unlock(&pi_mutex);
> + return error;
> + }
> +
> + pr_info("pata_parport: protocol %s registered\n", pr->name);
> +
> + if (probe) {
> + /* probe all parports using this protocol */
> + idr_for_each_entry(&parport_list, parport, port_num)
> + pi_init_one(parport, pr, -1, 0, -1);
> + }
> + mutex_unlock(&pi_mutex);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL(pata_parport_register_driver);

EXPORT_SYMBOL_GPL()

> +
> +void pata_parport_unregister_driver(struct pi_protocol *pr)
> +{
> + struct pi_protocol *pr_iter;
> + int id = -1;
> +
> + mutex_lock(&pi_mutex);
> + idr_for_each_entry(&protocols, pr_iter, id) {
> + if (pr_iter == pr)
> + break;
> + }
> + idr_remove(&protocols, id);
> + mutex_unlock(&pi_mutex);
> + driver_unregister(&pr->driver);
> +}
> +EXPORT_SYMBOL(pata_parport_unregister_driver);

Same here.

> +
> +static ssize_t new_device_store(struct bus_type *bus, const char *buf,
> + size_t count)
> +{
> + char port[12] = "auto";
> + char protocol[8] = "auto";
> + int mode = -1, unit = -1, delay = -1;
> + struct pi_protocol *pr, *pr_wanted;
> + struct device_driver *drv;
> + struct parport *parport;
> + int port_num, port_wanted, pr_num;
> + bool ok = false;
> +
> + if (sscanf(buf, "%11s %7s %d %d %d",
> + port, protocol, &mode, &unit, &delay) < 1)
> + return -EINVAL;
> +
> + if (sscanf(port, "parport%u", &port_wanted) < 1) {
> + if (!strcmp(port, "auto")) {
> + port_wanted = -1;
> + } else {
> + pr_err("invalid port name %s\n", port);
> + return -EINVAL;
> + }

It would be nicer to reverse the if condition to drop the else:

if (strcmp(port, "auto")) {
pr_err("invalid port name %s\n", port);
return -EINVAL;
}
port_wanted = -1;

> + }
> +
> + drv = driver_find(protocol, &pata_parport_bus_type);
> + if (!drv) {
> + if (!strcmp(protocol, "auto")) {
> + pr_wanted = NULL;
> + } else {
> + pr_err("protocol %s not found\n", protocol);
> + return -EINVAL;
> + }

Same here.

[...]

> +static ssize_t delete_device_store(struct bus_type *bus, const char *buf,
> + size_t count)
> +{
> + struct device *dev;
> + char device_name[32];
> +
> + if (sscanf(buf, "%31s", device_name) < 1)
> + return -EINVAL;

Why sscanf() ? You can strncpy from buf to device_name directly, no ?
And given how you use device_name below, I think that you do not even need
the device_name variable.

> +
> + mutex_lock(&pi_mutex);
> + dev = bus_find_device_by_name(bus, NULL, device_name);
> + if (!dev) {
> + mutex_unlock(&pi_mutex);
> + return -ENODEV;
> + }
> +
> + pi_remove_one(dev);
> + mutex_unlock(&pi_mutex);
> +
> + return count;
> +}
> +static BUS_ATTR_WO(delete_device);

[...]

> diff --git a/include/linux/pata_parport.h b/include/linux/pata_parport.h
> new file mode 100644
> index 000000000000..913f49ff1fad
> --- /dev/null
> +++ b/include/linux/pata_parport.h
> @@ -0,0 +1,106 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * pata_parport.h (c) 1997-8 Grant R. Guenther <[email protected]>
> + * Under the terms of the GPL.
> + *
> + * This file defines the interface for parallel port IDE adapter chip drivers.
> + */
> +

You are missing:

#ifndef LINUX_PATA_PARPORT_H
#define LINUX_PATA_PARPORT_H

> +#include <linux/libata.h>
> +
> +#define PI_PCD 1 /* dummy for paride protocol modules */
> +
> +struct pi_adapter {
> + struct device dev;
> + struct pi_protocol *proto; /* adapter protocol */
> + int port; /* base address of parallel port */
> + int mode; /* transfer mode in use */
> + int delay; /* adapter delay setting */
> + int devtype; /* dummy for paride protocol modules */
> + char *device; /* dummy for paride protocol modules */
> + int unit; /* unit number for chained adapters */
> + int saved_r0; /* saved port state */
> + int saved_r2; /* saved port state */
> + unsigned long private; /* for protocol module */
> + struct pardevice *pardev; /* pointer to pardevice */
> +};
> +
> +typedef struct pi_adapter PIA; /* for paride protocol modules */
> +
> +/* registers are addressed as (cont,regr)
> + * cont: 0 for command register file, 1 for control register(s)
> + * regr: 0-7 for register number.
> + */
> +
> +/* macros and functions exported to the protocol modules */
> +#define delay_p (pi->delay ? udelay(pi->delay) : (void)0)
> +#define out_p(offs, byte) do { outb(byte, pi->port + offs); delay_p; } while (0)
> +#define in_p(offs) (delay_p, inb(pi->port + offs))

It would be way nicer to have these as inline functions.

> +
> +#define w0(byte) out_p(0, byte)
> +#define r0() in_p(0)
> +#define w1(byte) out_p(1, byte)
> +#define r1() in_p(1)
> +#define w2(byte) out_p(2, byte)
> +#define r2() in_p(2)
> +#define w3(byte) out_p(3, byte)
> +#define w4(byte) out_p(4, byte)
> +#define r4() in_p(4)
> +#define w4w(data) do { outw(data, pi->port + 4); delay_p; } while (0)
> +#define w4l(data) do { outl(data, pi->port + 4); delay_p; } while (0)
> +#define r4w() (delay_p, inw(pi->port + 4))
> +#define r4l() (delay_p, inl(pi->port + 4))
> +
> +static inline u16 pi_swab16(char *b, int k)
> +{
> + union { u16 u; char t[2]; } r;
> +
> + r.t[0] = b[2 * k + 1]; r.t[1] = b[2 * k];
> + return r.u;
> +}
> +
> +static inline u32 pi_swab32(char *b, int k)
> +{
> + union { u32 u; char f[4]; } r;
> +
> + r.f[0] = b[4 * k + 1]; r.f[1] = b[4 * k];
> + r.f[2] = b[4 * k + 3]; r.f[3] = b[4 * k + 2];
> + return r.u;
> +}
> +
> +struct pi_protocol {
> + char name[8];
> +
> + int max_mode;
> + int epp_first; /* modes >= this use 8 ports */
> +
> + int default_delay;
> + int max_units; /* max chained units probed for */
> +
> + void (*write_regr)(struct pi_adapter *pi, int cont, int regr, int val);
> + int (*read_regr)(struct pi_adapter *pi, int cont, int regr);
> + void (*write_block)(struct pi_adapter *pi, char *buf, int count);
> + void (*read_block)(struct pi_adapter *pi, char *buf, int count);
> +
> + void (*connect)(struct pi_adapter *pi);
> + void (*disconnect)(struct pi_adapter *pi);
> +
> + int (*test_port)(struct pi_adapter *pi);
> + int (*probe_unit)(struct pi_adapter *pi);
> + int (*test_proto)(struct pi_adapter *pi, char *scratch, int verbose);
> + void (*log_adapter)(struct pi_adapter *pi, char *scratch, int verbose);
> +
> + int (*init_proto)(struct pi_adapter *pi);
> + void (*release_proto)(struct pi_adapter *pi);
> + struct module *owner;
> + struct device_driver driver;
> + struct scsi_host_template sht;
> +};
> +
> +#define PATA_PARPORT_SHT ATA_PIO_SHT
> +
> +int pata_parport_register_driver(struct pi_protocol *pr);
> +void pata_parport_unregister_driver(struct pi_protocol *pr);
> +/* defines for old paride protocol modules */
> +#define paride_register pata_parport_register_driver
> +#define paride_unregister pata_parport_unregister_driver

--
Damien Le Moal
Western Digital Research


2023-01-23 01:15:13

by Damien Le Moal

[permalink] [raw]
Subject: Re: [PATCH v2] pata_parport: add driver (PARIDE replacement)

On 1/23/23 03:24, Jens Axboe wrote:
> On 1/22/23 12:57 AM, Christoph Hellwig wrote:
>> I suspect a comment in the Kconfig for the old PARIDE code to point
>> to this and maybe even a runtime warning when using the old paride
>> code would be great.
>>
>> But except for that the code looks awesome, so let's get it merged ASAP:
>>
>> Reviewed-by: Christoph Hellwig <[email protected]>
>
> Since Ondrej is probably one of the few (maybe the only) user of this
> code, why don't we just kill off the paride code in a separate patch
> right after?

+1

I do not see the point of deprecating it first. Let's remove that code
directly.

--
Damien Le Moal
Western Digital Research


2023-01-23 06:52:16

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [PATCH v2] pata_parport: add driver (PARIDE replacement)

On Sun, Jan 22, 2023 at 11:24:32AM -0700, Jens Axboe wrote:
> Since Ondrej is probably one of the few (maybe the only) user of this
> code, why don't we just kill off the paride code in a separate patch
> right after?

That seems a little too fast too me. I'd give it at least another merge
window if not two.

2023-01-23 07:38:01

by Hannes Reinecke

[permalink] [raw]
Subject: Re: [PATCH v2] pata_parport: add driver (PARIDE replacement)

On 1/22/23 19:24, Jens Axboe wrote:
> On 1/22/23 12:57 AM, Christoph Hellwig wrote:
>> I suspect a comment in the Kconfig for the old PARIDE code to point
>> to this and maybe even a runtime warning when using the old paride
>> code would be great.
>>
>> But except for that the code looks awesome, so let's get it merged ASAP:
>>
>> Reviewed-by: Christoph Hellwig <[email protected]>
>
> Since Ondrej is probably one of the few (maybe the only) user of this
> code, why don't we just kill off the paride code in a separate patch
> right after?
>
Go for it.

Cheers,

Hannes
--
Dr. Hannes Reinecke Kernel Storage Architect
[email protected] +49 911 74053 688
SUSE Software Solutions GmbH, Maxfeldstr. 5, 90409 Nürnberg
HRB 36809 (AG Nürnberg), Geschäftsführer: Ivo Totev, Andrew
Myers, Andrew McDonald, Martje Boudien Moerman


2023-01-23 07:38:42

by Hannes Reinecke

[permalink] [raw]
Subject: Re: [PATCH] paride: Mark PARIDE as deprecated, point to PATA_PARPORT

On 1/22/23 19:14, Ondrej Zary wrote:
> Add Kconfig and runtime deprecation warnings to PARIDE, pointing users
> to PATA_PARPORT.
>
> Signed-off-by: Ondrej Zary <[email protected]>
> ---
> drivers/block/Kconfig | 4 +++-
> drivers/block/paride/paride.c | 2 ++
> 2 files changed, 5 insertions(+), 1 deletion(-)
>
Reviewed-by: Hannes Reinecke <[email protected]>

Cheers,

Hannes
--
Dr. Hannes Reinecke Kernel Storage Architect
[email protected] +49 911 74053 688
SUSE Software Solutions GmbH, Maxfeldstr. 5, 90409 Nürnberg
HRB 36809 (AG Nürnberg), Geschäftsführer: Ivo Totev, Andrew
Myers, Andrew McDonald, Martje Boudien Moerman


2023-01-23 14:05:16

by Jens Axboe

[permalink] [raw]
Subject: Re: [PATCH v2] pata_parport: add driver (PARIDE replacement)

On 1/22/23 11:52 PM, Christoph Hellwig wrote:
> On Sun, Jan 22, 2023 at 11:24:32AM -0700, Jens Axboe wrote:
>> Since Ondrej is probably one of the few (maybe the only) user of this
>> code, why don't we just kill off the paride code in a separate patch
>> right after?
>
> That seems a little too fast too me. I'd give it at least another merge
> window if not two.

It's not going to matter in this case. If we do it immediately or after
two releases, nobody else is going to have noticed that message and
decided "Oh, let me just switch over and test the other one". And since
it's stuff that hasn't been released since the 90s, let's just get it
done.

--
Jens Axboe



2023-01-23 19:10:10

by Ondrej Zary

[permalink] [raw]
Subject: [PATCH v3] pata_parport: add driver (PARIDE replacement)

The pata_parport is a libata-based replacement of the old PARIDE
subsystem - driver for parallel port IDE devices.
It uses the original paride low-level protocol drivers but does not
need the high-level drivers (pd, pcd, pf, pt, pg). The IDE devices
behind parallel port adapters are handled by the ATA layer.

This will allow paride and its high-level drivers to be removed.

Unfortunately, libata drivers cannot sleep so pata_parport claims
parport before activating the ata host and keeps it claimed (and
protocol connected) until the ata host is removed. This means that
no devices can be chained (neither other pata_parport devices nor
a printer).

paride and pata_parport are mutually exclusive because the compiled
protocol drivers are incompatible.

Tested with:
- Imation SuperDisk LS-120 and HP C4381A (EPAT)
- Freecom Parallel CD (FRPW)
- Toshiba Mobile CD-RW 2793008 w/Freecom Parallel Cable rev.903 (FRIQ)
- Backpack CD-RW 222011 and CD-RW 19350 (BPCK6)

The following bugs in low-level protocol drivers were found and will
be fixed later:

Note: EPP-32 mode is buggy in EPAT - and also in all other protocol
drivers - they don't handle non-multiple-of-4 block transfers
correctly. This causes problems with LS-120 drive.
There is also another bug in EPAT: EPP modes don't work unless a 4-bit
or 8-bit mode is used first (probably some initialization missing?).
Once the device is initialized, EPP works until power cycle.

So after device power on, you have to:
echo "parport0 epat 0" >/sys/bus/pata_parport/new_device
echo pata_parport.0 >/sys/bus/pata_parport/delete_device
echo "parport0 epat 4" >/sys/bus/pata_parport/new_device
(autoprobe will initialize correctly as it tries the slowest modes
first but you'll get the broken EPP-32 mode)

Note: EPP modes are buggy in FRPW, only modes 0 and 1 work.
Signed-off-by: Ondrej Zary <[email protected]>
---

Changes in v3:
- addressed Damien's comments

Changes in v2:
- keep device connected, remove disconnect timer

Documentation/admin-guide/blockdev/paride.rst | 52 ++
drivers/Makefile | 2 +-
drivers/ata/Kconfig | 14 +
drivers/ata/Makefile | 2 +
drivers/ata/pata_parport.c | 759 ++++++++++++++++++
drivers/block/paride/Kconfig | 32 +-
drivers/block/paride/paride.h | 13 +
include/linux/pata_parport.h | 111 +++
8 files changed, 968 insertions(+), 17 deletions(-)
create mode 100644 drivers/ata/pata_parport.c
create mode 100644 include/linux/pata_parport.h

diff --git a/Documentation/admin-guide/blockdev/paride.rst b/Documentation/admin-guide/blockdev/paride.rst
index e1ce90af602a..e431a1ef41eb 100644
--- a/Documentation/admin-guide/blockdev/paride.rst
+++ b/Documentation/admin-guide/blockdev/paride.rst
@@ -2,6 +2,9 @@
Linux and parallel port IDE devices
===================================

+Most of this document describes the old paride driver. For the new libata
+pata_parport drivrer, jump to the section 4 at the end.
+
PARIDE v1.03 (c) 1997-8 Grant Guenther <[email protected]>

1. Introduction
@@ -437,3 +440,52 @@ You might also find some useful information on the linux-parport
web pages (although they are not always up to date) at

http://web.archive.org/web/%2E/http://www.torque.net/parport/
+
+4. pata_parport driver
+======================
+pata_parport is a libata-based driver that uses the same low-level protocol
+drivers as PARIDE but there are no high-level drivers (pd, pcd, pf, pt, pg).
+The IDE devices behind parallel port adapters are handled by the ATA layer.
+
+The device creation is also changed - no protocol numbers or parport I/O
+addresses are used.
+
+All parports and all protocol drivers are probed automatically unless probe=0
+parameter is used. So just "modprobe epat" is enough for a Imation SuperDisk
+drive to work.
+
+Manual device creation::
+
+ # echo "port protocol mode unit delay" >/sys/bus/pata_parport/new_device
+
+where:
+
+ ======== ================================================
+ port parport name (or "auto" for all parports)
+ protocol protocol name (or "auto" for all protocols)
+ mode mode number (protocol-specific) or -1 for probe
+ unit unit number (see the paride documentation above)
+ delay I/O delay (see the paride documentation above)
+ ======== ================================================
+
+If you omit the parameters from the end, defaults will be used, e.g.:
+
+Probe all parports with all protocols::
+
+ # echo auto >/sys/bus/pata_parport/new_device
+
+Probe parport0 using protocol epat and mode 4 (EPP-16)::
+
+ # echo "parport0 epat 4" >/sys/bus/pata_parport/new_device
+
+Probe parport0 using all protocols::
+
+ # echo "parport0 auto" >/sys/bus/pata_parport/new_device
+
+Probe all parports using protoocol epat::
+
+ # echo "auto epat" >/sys/bus/pata_parport/new_device
+
+Deleting devices::
+
+ # echo pata_parport.0 >/sys/bus/pata_parport/delete_device
diff --git a/drivers/Makefile b/drivers/Makefile
index bdf1c66141c9..f1365608bc8c 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -98,7 +98,7 @@ obj-$(CONFIG_DIO) += dio/
obj-$(CONFIG_SBUS) += sbus/
obj-$(CONFIG_ZORRO) += zorro/
obj-$(CONFIG_ATA_OVER_ETH) += block/aoe/
-obj-$(CONFIG_PARIDE) += block/paride/
+obj-y += block/paride/
obj-$(CONFIG_TC) += tc/
obj-$(CONFIG_USB_PHY) += usb/
obj-$(CONFIG_USB) += usb/
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index eceaec33af65..fb646480635c 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -1162,6 +1162,20 @@ config PATA_WINBOND_VLB
Support for the Winbond W83759A controller on Vesa Local Bus
systems.

+config PATA_PARPORT
+ tristate "Parallel port IDE device support"
+ depends on PARPORT_PC && PARIDE=n
+ help
+ There are many external CD-ROM and disk devices that connect through
+ your computer's parallel port. Most of them are actually IDE devices
+ using a parallel port IDE adapter. This option enables the
+ PATA_PARPORT subsystem which contains drivers for many of these
+ external drives.
+ Read <file:Documentation/admin-guide/blockdev/paride.rst> for more
+ information.
+
+ Use the old PARIDE protocol modules.
+
comment "Generic fallback / legacy drivers"

config PATA_ACPI
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index d2e36d367274..23588738cff0 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -114,6 +114,8 @@ obj-$(CONFIG_PATA_SAMSUNG_CF) += pata_samsung_cf.o

obj-$(CONFIG_PATA_PXA) += pata_pxa.o

+obj-$(CONFIG_PATA_PARPORT) += pata_parport.o
+
# Should be last but two libata driver
obj-$(CONFIG_PATA_ACPI) += pata_acpi.o
# Should be last but one libata driver
diff --git a/drivers/ata/pata_parport.c b/drivers/ata/pata_parport.c
new file mode 100644
index 000000000000..9e8ad93d7e59
--- /dev/null
+++ b/drivers/ata/pata_parport.c
@@ -0,0 +1,759 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright 2023 Ondrej Zary
+ * based on paride.c by Grant R. Guenther <[email protected]>
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/parport.h>
+#include <linux/pata_parport.h>
+
+#define DRV_NAME "pata_parport"
+
+static DEFINE_IDR(parport_list);
+static DEFINE_IDR(protocols);
+static DEFINE_IDA(pata_parport_bus_dev_ids);
+static DEFINE_MUTEX(pi_mutex);
+
+static bool probe = true;
+module_param(probe, bool, 0644);
+MODULE_PARM_DESC(probe, "Enable automatic device probing (0=off, 1=on [default])");
+
+/*
+ * libata drivers cannot sleep so this driver claims parport before activating
+ * the ata host and keeps it claimed (and protocol connected) until the ata
+ * host is removed. Unfortunately, this means that you cannot use any chained
+ * devices (neither other pata_parport devices nor a printer).
+ */
+static void pi_connect(struct pi_adapter *pi)
+{
+ parport_claim_or_block(pi->pardev);
+ pi->proto->connect(pi);
+}
+
+static void pi_disconnect(struct pi_adapter *pi)
+{
+ pi->proto->disconnect(pi);
+ parport_release(pi->pardev);
+}
+
+static void pata_parport_dev_select(struct ata_port *ap, unsigned int device)
+{
+ struct pi_adapter *pi = ap->host->private_data;
+ u8 tmp;
+
+ if (device == 0)
+ tmp = ATA_DEVICE_OBS;
+ else
+ tmp = ATA_DEVICE_OBS | ATA_DEV1;
+
+ pi->proto->write_regr(pi, 0, ATA_REG_DEVICE, tmp);
+ ata_sff_pause(ap);
+}
+
+static bool pata_parport_devchk(struct ata_port *ap, unsigned int device)
+{
+ struct pi_adapter *pi = ap->host->private_data;
+ u8 nsect, lbal;
+
+ pata_parport_dev_select(ap, device);
+
+ pi->proto->write_regr(pi, 0, ATA_REG_NSECT, 0x55);
+ pi->proto->write_regr(pi, 0, ATA_REG_LBAL, 0xaa);
+
+ pi->proto->write_regr(pi, 0, ATA_REG_NSECT, 0xaa);
+ pi->proto->write_regr(pi, 0, ATA_REG_LBAL, 0x55);
+
+ pi->proto->write_regr(pi, 0, ATA_REG_NSECT, 055);
+ pi->proto->write_regr(pi, 0, ATA_REG_LBAL, 0xaa);
+
+ nsect = pi->proto->read_regr(pi, 0, ATA_REG_NSECT);
+ lbal = pi->proto->read_regr(pi, 0, ATA_REG_LBAL);
+
+ return (nsect == 0x55) && (lbal == 0xaa);
+}
+
+static int pata_parport_bus_softreset(struct ata_port *ap, unsigned int devmask,
+ unsigned long deadline)
+{
+ struct pi_adapter *pi = ap->host->private_data;
+
+ /* software reset. causes dev0 to be selected */
+ pi->proto->write_regr(pi, 1, 6, ap->ctl);
+ udelay(20);
+ pi->proto->write_regr(pi, 1, 6, ap->ctl | ATA_SRST);
+ udelay(20);
+ pi->proto->write_regr(pi, 1, 6, ap->ctl);
+ ap->last_ctl = ap->ctl;
+
+ /* wait the port to become ready */
+ return ata_sff_wait_after_reset(&ap->link, devmask, deadline);
+}
+
+static int pata_parport_softreset(struct ata_link *link, unsigned int *classes,
+ unsigned long deadline)
+{
+ struct ata_port *ap = link->ap;
+ unsigned int devmask = 0;
+ int rc;
+ u8 err;
+
+ /* determine if device 0/1 are present */
+ if (pata_parport_devchk(ap, 0))
+ devmask |= (1 << 0);
+ if (pata_parport_devchk(ap, 1))
+ devmask |= (1 << 1);
+
+ /* select device 0 again */
+ pata_parport_dev_select(ap, 0);
+
+ /* issue bus reset */
+ rc = pata_parport_bus_softreset(ap, devmask, deadline);
+ if (rc && rc != -ENODEV) {
+ ata_link_err(link, "SRST failed (errno=%d)\n", rc);
+ return rc;
+ }
+
+ /* determine by signature whether we have ATA or ATAPI devices */
+ classes[0] = ata_sff_dev_classify(&link->device[0],
+ devmask & (1 << 0), &err);
+ if (err != 0x81)
+ classes[1] = ata_sff_dev_classify(&link->device[1],
+ devmask & (1 << 1), &err);
+
+ return 0;
+}
+
+static u8 pata_parport_check_status(struct ata_port *ap)
+{
+ struct pi_adapter *pi = ap->host->private_data;
+
+ return pi->proto->read_regr(pi, 0, ATA_REG_STATUS);
+}
+
+static u8 pata_parport_check_altstatus(struct ata_port *ap)
+{
+ struct pi_adapter *pi = ap->host->private_data;
+
+ return pi->proto->read_regr(pi, 1, 6);
+}
+
+static void pata_parport_tf_load(struct ata_port *ap,
+ const struct ata_taskfile *tf)
+{
+ struct pi_adapter *pi = ap->host->private_data;
+
+ if (tf->ctl != ap->last_ctl) {
+ pi->proto->write_regr(pi, 1, 6, tf->ctl);
+ ap->last_ctl = tf->ctl;
+ ata_wait_idle(ap);
+ }
+
+ if (tf->flags & ATA_TFLAG_ISADDR) {
+ if (tf->flags & ATA_TFLAG_LBA48) {
+ pi->proto->write_regr(pi, 0, ATA_REG_FEATURE,
+ tf->hob_feature);
+ pi->proto->write_regr(pi, 0, ATA_REG_NSECT,
+ tf->hob_nsect);
+ pi->proto->write_regr(pi, 0, ATA_REG_LBAL,
+ tf->hob_lbal);
+ pi->proto->write_regr(pi, 0, ATA_REG_LBAM,
+ tf->hob_lbam);
+ pi->proto->write_regr(pi, 0, ATA_REG_LBAH,
+ tf->hob_lbah);
+ }
+ pi->proto->write_regr(pi, 0, ATA_REG_FEATURE, tf->feature);
+ pi->proto->write_regr(pi, 0, ATA_REG_NSECT, tf->nsect);
+ pi->proto->write_regr(pi, 0, ATA_REG_LBAL, tf->lbal);
+ pi->proto->write_regr(pi, 0, ATA_REG_LBAM, tf->lbam);
+ pi->proto->write_regr(pi, 0, ATA_REG_LBAH, tf->lbah);
+ }
+
+ if (tf->flags & ATA_TFLAG_DEVICE)
+ pi->proto->write_regr(pi, 0, ATA_REG_DEVICE, tf->device);
+
+ ata_wait_idle(ap);
+}
+
+static void pata_parport_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+ struct pi_adapter *pi = ap->host->private_data;
+
+ tf->status = pi->proto->read_regr(pi, 0, ATA_REG_STATUS);
+ tf->error = pi->proto->read_regr(pi, 0, ATA_REG_ERR);
+ tf->nsect = pi->proto->read_regr(pi, 0, ATA_REG_NSECT);
+ tf->lbal = pi->proto->read_regr(pi, 0, ATA_REG_LBAL);
+ tf->lbam = pi->proto->read_regr(pi, 0, ATA_REG_LBAM);
+ tf->lbah = pi->proto->read_regr(pi, 0, ATA_REG_LBAH);
+ tf->device = pi->proto->read_regr(pi, 0, ATA_REG_DEVICE);
+
+ if (tf->flags & ATA_TFLAG_LBA48) {
+ pi->proto->write_regr(pi, 1, 6, tf->ctl | ATA_HOB);
+ tf->hob_feature = pi->proto->read_regr(pi, 0, ATA_REG_ERR);
+ tf->hob_nsect = pi->proto->read_regr(pi, 0, ATA_REG_NSECT);
+ tf->hob_lbal = pi->proto->read_regr(pi, 0, ATA_REG_LBAL);
+ tf->hob_lbam = pi->proto->read_regr(pi, 0, ATA_REG_LBAM);
+ tf->hob_lbah = pi->proto->read_regr(pi, 0, ATA_REG_LBAH);
+ pi->proto->write_regr(pi, 1, 6, tf->ctl);
+ ap->last_ctl = tf->ctl;
+ }
+}
+
+static void pata_parport_exec_command(struct ata_port *ap,
+ const struct ata_taskfile *tf)
+{
+ struct pi_adapter *pi = ap->host->private_data;
+
+ pi->proto->write_regr(pi, 0, ATA_REG_CMD, tf->command);
+ ata_sff_pause(ap);
+}
+
+static unsigned int pata_parport_data_xfer(struct ata_queued_cmd *qc,
+ unsigned char *buf, unsigned int buflen, int rw)
+{
+ struct ata_port *ap = qc->dev->link->ap;
+ struct pi_adapter *pi = ap->host->private_data;
+
+ if (rw == READ)
+ pi->proto->read_block(pi, buf, buflen);
+ else
+ pi->proto->write_block(pi, buf, buflen);
+
+ return buflen;
+}
+
+static void pata_parport_drain_fifo(struct ata_queued_cmd *qc)
+{
+ int count;
+ struct ata_port *ap;
+ struct pi_adapter *pi;
+ char junk[2];
+
+ /* We only need to flush incoming data when a command was running */
+ if (qc == NULL || qc->dma_dir == DMA_TO_DEVICE)
+ return;
+
+ ap = qc->ap;
+ pi = ap->host->private_data;
+ /* Drain up to 64K of data before we give up this recovery method */
+ for (count = 0; (pata_parport_check_status(ap) & ATA_DRQ)
+ && count < 65536; count += 2) {
+ pi->proto->read_block(pi, junk, 2);
+ }
+
+ if (count)
+ ata_port_dbg(ap, "drained %d bytes to clear DRQ\n", count);
+}
+
+static struct ata_port_operations pata_parport_port_ops = {
+ .inherits = &ata_sff_port_ops,
+
+ .softreset = pata_parport_softreset,
+ .hardreset = NULL,
+
+ .sff_dev_select = pata_parport_dev_select,
+ .sff_check_status = pata_parport_check_status,
+ .sff_check_altstatus = pata_parport_check_altstatus,
+ .sff_tf_load = pata_parport_tf_load,
+ .sff_tf_read = pata_parport_tf_read,
+ .sff_exec_command = pata_parport_exec_command,
+ .sff_data_xfer = pata_parport_data_xfer,
+ .sff_drain_fifo = pata_parport_drain_fifo,
+};
+
+static const struct ata_port_info pata_parport_port_info = {
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_PIO_POLLING,
+ .pio_mask = ATA_PIO0,
+ /* No DMA */
+ .port_ops = &pata_parport_port_ops,
+};
+
+static void pi_release(struct pi_adapter *pi)
+{
+ parport_unregister_device(pi->pardev);
+ if (pi->proto->release_proto)
+ pi->proto->release_proto(pi);
+ module_put(pi->proto->owner);
+}
+
+static int default_test_proto(struct pi_adapter *pi, char *scratch)
+{
+ int j, k;
+ int e[2] = { 0, 0 };
+
+ pi->proto->connect(pi);
+
+ for (j = 0; j < 2; j++) {
+ pi->proto->write_regr(pi, 0, 6, 0xa0 + j * 0x10);
+ for (k = 0; k < 256; k++) {
+ pi->proto->write_regr(pi, 0, 2, k ^ 0xaa);
+ pi->proto->write_regr(pi, 0, 3, k ^ 0x55);
+ if (pi->proto->read_regr(pi, 0, 2) != (k ^ 0xaa))
+ e[j]++;
+ }
+ }
+ pi->proto->disconnect(pi);
+
+ dev_dbg(&pi->dev, "%s: port 0x%x, mode %d, test=(%d,%d)\n",
+ pi->proto->name, pi->port, pi->mode, e[0], e[1]);
+
+ return e[0] && e[1]; /* not here if both > 0 */
+}
+
+static int pi_test_proto(struct pi_adapter *pi, char *scratch)
+{
+ int res;
+
+ parport_claim_or_block(pi->pardev);
+ if (pi->proto->test_proto)
+ res = pi->proto->test_proto(pi, scratch, 1);
+ else
+ res = default_test_proto(pi, scratch);
+ parport_release(pi->pardev);
+
+ return res;
+}
+
+static bool pi_probe_mode(struct pi_adapter *pi, int max, char *scratch)
+{
+ int best, range;
+
+ if (pi->mode != -1) {
+ if (pi->mode >= max)
+ return false;
+ range = 3;
+ if (pi->mode >= pi->proto->epp_first)
+ range = 8;
+ if (range == 8 && pi->port % 8)
+ return false;
+ return !pi_test_proto(pi, scratch);
+ }
+ best = -1;
+ for (pi->mode = 0; pi->mode < max; pi->mode++) {
+ range = 3;
+ if (pi->mode >= pi->proto->epp_first)
+ range = 8;
+ if (range == 8 && pi->port % 8)
+ break;
+ if (!pi_test_proto(pi, scratch))
+ best = pi->mode;
+ }
+ pi->mode = best;
+ return best > -1;
+}
+
+static bool pi_probe_unit(struct pi_adapter *pi, int unit, char *scratch)
+{
+ int max, s, e;
+
+ s = unit;
+ e = s + 1;
+
+ if (s == -1) {
+ s = 0;
+ e = pi->proto->max_units;
+ }
+
+ if (pi->proto->test_port) {
+ parport_claim_or_block(pi->pardev);
+ max = pi->proto->test_port(pi);
+ parport_release(pi->pardev);
+ } else {
+ max = pi->proto->max_mode;
+ }
+
+ if (pi->proto->probe_unit) {
+ parport_claim_or_block(pi->pardev);
+ for (pi->unit = s; pi->unit < e; pi->unit++) {
+ if (pi->proto->probe_unit(pi)) {
+ parport_release(pi->pardev);
+ return pi_probe_mode(pi, max, scratch);
+ }
+ }
+ parport_release(pi->pardev);
+ return false;
+ }
+
+ return pi_probe_mode(pi, max, scratch);
+}
+
+static void pata_parport_dev_release(struct device *dev)
+{
+ struct pi_adapter *pi = container_of(dev, struct pi_adapter, dev);
+
+ kfree(pi);
+}
+
+static void pata_parport_bus_release(struct device *dev)
+{
+ /* nothing to do here but required to avoid warning on device removal */
+}
+
+static struct bus_type pata_parport_bus_type = {
+ .name = DRV_NAME,
+};
+
+static struct device pata_parport_bus = {
+ .init_name = DRV_NAME,
+ .release = pata_parport_bus_release,
+};
+
+static struct scsi_host_template pata_parport_sht = {
+ PATA_PARPORT_SHT("pata_parport")
+};
+
+struct pi_device_match {
+ struct parport *parport;
+ struct pi_protocol *proto;
+};
+
+static int pi_find_dev(struct device *dev, void *data)
+{
+ struct pi_adapter *pi = container_of(dev, struct pi_adapter, dev);
+ struct pi_device_match *match = data;
+
+ return pi->pardev->port == match->parport && pi->proto == match->proto;
+}
+
+static struct pi_adapter *pi_init_one(struct parport *parport,
+ struct pi_protocol *pr, int mode, int unit, int delay)
+{
+ struct pardev_cb par_cb = { };
+ char scratch[512];
+ const struct ata_port_info *ppi[] = { &pata_parport_port_info };
+ struct ata_host *host;
+ struct pi_adapter *pi;
+ struct pi_device_match match = { .parport = parport, .proto = pr };
+
+ /*
+ * Abort if there's a device already registered on the same parport
+ * using the same protocol.
+ */
+ if (bus_for_each_dev(&pata_parport_bus_type, NULL, &match, pi_find_dev))
+ return NULL;
+
+ pi = kzalloc(sizeof(struct pi_adapter), GFP_KERNEL);
+ if (!pi)
+ return NULL;
+
+ /* set up pi->dev before pi_probe_unit() so it can use dev_printk() */
+ pi->dev.parent = &pata_parport_bus;
+ pi->dev.bus = &pata_parport_bus_type;
+ pi->dev.driver = &pr->driver;
+ pi->dev.release = pata_parport_dev_release;
+ pi->dev.id = ida_alloc(&pata_parport_bus_dev_ids, GFP_KERNEL);
+ if (pi->dev.id < 0)
+ return NULL; /* pata_parport_dev_release will do kfree(pi) */
+ dev_set_name(&pi->dev, "pata_parport.%u", pi->dev.id);
+ if (device_register(&pi->dev)) {
+ put_device(&pi->dev);
+ goto out_ida_free;
+ }
+
+ pi->proto = pr;
+
+ if (!try_module_get(pi->proto->owner))
+ goto out_unreg_dev;
+ if (pi->proto->init_proto && pi->proto->init_proto(pi) < 0)
+ goto out_module_put;
+
+ pi->delay = (delay == -1) ? pi->proto->default_delay : delay;
+ pi->mode = mode;
+ pi->port = parport->base;
+
+ par_cb.private = pi;
+ pi->pardev = parport_register_dev_model(parport, DRV_NAME, &par_cb,
+ pi->dev.id);
+ if (!pi->pardev)
+ goto out_module_put;
+
+ if (!pi_probe_unit(pi, unit, scratch)) {
+ dev_info(&pi->dev, "Adapter not found\n");
+ goto out_unreg_parport;
+ }
+
+ pi->proto->log_adapter(pi, scratch, 1);
+
+ host = ata_host_alloc_pinfo(&pi->pardev->dev, ppi, 1);
+ if (!host)
+ goto out_unreg_parport;
+ dev_set_drvdata(&pi->dev, host);
+ host->private_data = pi;
+
+ ata_port_desc(host->ports[0], "port %s", pi->pardev->port->name);
+ ata_port_desc(host->ports[0], "protocol %s", pi->proto->name);
+
+ pi_connect(pi);
+ if (ata_host_activate(host, 0, NULL, 0, &pata_parport_sht))
+ goto out_unreg_parport;
+
+ return pi;
+
+out_unreg_parport:
+ pi_disconnect(pi);
+ parport_unregister_device(pi->pardev);
+ if (pi->proto->release_proto)
+ pi->proto->release_proto(pi);
+out_module_put:
+ module_put(pi->proto->owner);
+out_unreg_dev:
+ device_unregister(&pi->dev);
+out_ida_free:
+ ida_free(&pata_parport_bus_dev_ids, pi->dev.id);
+ return NULL;
+}
+
+int pata_parport_register_driver(struct pi_protocol *pr)
+{
+ int error;
+ struct parport *parport;
+ int port_num;
+
+ pr->driver.bus = &pata_parport_bus_type;
+ pr->driver.name = pr->name;
+ error = driver_register(&pr->driver);
+ if (error)
+ return error;
+
+ mutex_lock(&pi_mutex);
+ error = idr_alloc(&protocols, pr, 0, 0, GFP_KERNEL);
+ if (error < 0) {
+ driver_unregister(&pr->driver);
+ mutex_unlock(&pi_mutex);
+ return error;
+ }
+
+ pr_info("pata_parport: protocol %s registered\n", pr->name);
+
+ if (probe) {
+ /* probe all parports using this protocol */
+ idr_for_each_entry(&parport_list, parport, port_num)
+ pi_init_one(parport, pr, -1, 0, -1);
+ }
+ mutex_unlock(&pi_mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(pata_parport_register_driver);
+
+void pata_parport_unregister_driver(struct pi_protocol *pr)
+{
+ struct pi_protocol *pr_iter;
+ int id = -1;
+
+ mutex_lock(&pi_mutex);
+ idr_for_each_entry(&protocols, pr_iter, id) {
+ if (pr_iter == pr)
+ break;
+ }
+ idr_remove(&protocols, id);
+ mutex_unlock(&pi_mutex);
+ driver_unregister(&pr->driver);
+}
+EXPORT_SYMBOL_GPL(pata_parport_unregister_driver);
+
+static ssize_t new_device_store(struct bus_type *bus, const char *buf,
+ size_t count)
+{
+ char port[12] = "auto";
+ char protocol[8] = "auto";
+ int mode = -1, unit = -1, delay = -1;
+ struct pi_protocol *pr, *pr_wanted;
+ struct device_driver *drv;
+ struct parport *parport;
+ int port_num, port_wanted, pr_num;
+ bool ok = false;
+
+ if (sscanf(buf, "%11s %7s %d %d %d",
+ port, protocol, &mode, &unit, &delay) < 1)
+ return -EINVAL;
+
+ if (sscanf(port, "parport%u", &port_wanted) < 1) {
+ if (strcmp(port, "auto")) {
+ pr_err("invalid port name %s\n", port);
+ return -EINVAL;
+ }
+ port_wanted = -1;
+ }
+
+ drv = driver_find(protocol, &pata_parport_bus_type);
+ if (!drv) {
+ if (strcmp(protocol, "auto")) {
+ pr_err("protocol %s not found\n", protocol);
+ return -EINVAL;
+ }
+ pr_wanted = NULL;
+ } else {
+ pr_wanted = container_of(drv, struct pi_protocol, driver);
+ }
+
+ mutex_lock(&pi_mutex);
+ /* walk all parports */
+ idr_for_each_entry(&parport_list, parport, port_num) {
+ if (port_num == port_wanted || port_wanted == -1) {
+ parport = parport_find_number(port_num);
+ if (!parport) {
+ pr_err("no such port %s\n", port);
+ mutex_unlock(&pi_mutex);
+ return -ENODEV;
+ }
+ /* walk all protocols */
+ idr_for_each_entry(&protocols, pr, pr_num) {
+ if (pr == pr_wanted || !pr_wanted)
+ if (pi_init_one(parport, pr, mode, unit,
+ delay))
+ ok = true;
+ }
+ parport_put_port(parport);
+ }
+ }
+ mutex_unlock(&pi_mutex);
+ if (!ok)
+ return -ENODEV;
+
+ return count;
+}
+static BUS_ATTR_WO(new_device);
+
+static void pi_remove_one(struct device *dev)
+{
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct pi_adapter *pi = host->private_data;
+
+ ata_host_detach(host);
+ pi_disconnect(pi);
+ pi_release(pi);
+ device_unregister(dev);
+ ida_free(&pata_parport_bus_dev_ids, dev->id);
+ /* pata_parport_dev_release will do kfree(pi) */
+}
+
+static ssize_t delete_device_store(struct bus_type *bus, const char *buf,
+ size_t count)
+{
+ struct device *dev;
+
+ mutex_lock(&pi_mutex);
+ dev = bus_find_device_by_name(bus, NULL, buf);
+ if (!dev) {
+ mutex_unlock(&pi_mutex);
+ return -ENODEV;
+ }
+
+ pi_remove_one(dev);
+ mutex_unlock(&pi_mutex);
+
+ return count;
+}
+static BUS_ATTR_WO(delete_device);
+
+static void pata_parport_attach(struct parport *port)
+{
+ struct pi_protocol *pr;
+ int pr_num, id;
+
+ mutex_lock(&pi_mutex);
+ id = idr_alloc(&parport_list, port, port->number, port->number,
+ GFP_KERNEL);
+ if (id < 0) {
+ mutex_unlock(&pi_mutex);
+ return;
+ }
+
+ if (probe) {
+ /* probe this port using all protocols */
+ idr_for_each_entry(&protocols, pr, pr_num)
+ pi_init_one(port, pr, -1, 0, -1);
+ }
+ mutex_unlock(&pi_mutex);
+}
+
+static int pi_remove_port(struct device *dev, void *p)
+{
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct pi_adapter *pi = host->private_data;
+
+ if (pi->pardev->port == p)
+ pi_remove_one(dev);
+
+ return 0;
+}
+
+static void pata_parport_detach(struct parport *port)
+{
+ mutex_lock(&pi_mutex);
+ bus_for_each_dev(&pata_parport_bus_type, NULL, port, pi_remove_port);
+ idr_remove(&parport_list, port->number);
+ mutex_unlock(&pi_mutex);
+}
+
+static struct parport_driver pata_parport_driver = {
+ .name = DRV_NAME,
+ .match_port = pata_parport_attach,
+ .detach = pata_parport_detach,
+ .devmodel = true,
+};
+
+static __init int pata_parport_init(void)
+{
+ int error;
+
+ error = bus_register(&pata_parport_bus_type);
+ if (error) {
+ pr_err("failed to register pata_parport bus, error: %d\n", error);
+ return error;
+ }
+
+ error = device_register(&pata_parport_bus);
+ if (error) {
+ pr_err("failed to register pata_parport bus, error: %d\n", error);
+ goto out_unregister_bus;
+ }
+
+ error = bus_create_file(&pata_parport_bus_type, &bus_attr_new_device);
+ if (error) {
+ pr_err("unable to create sysfs file, error: %d\n", error);
+ goto out_unregister_dev;
+ }
+
+ error = bus_create_file(&pata_parport_bus_type, &bus_attr_delete_device);
+ if (error) {
+ pr_err("unable to create sysfs file, error: %d\n", error);
+ goto out_remove_new;
+ }
+
+ error = parport_register_driver(&pata_parport_driver);
+ if (error) {
+ pr_err("unable to register parport driver, error: %d\n", error);
+ goto out_remove_del;
+ }
+
+ return 0;
+
+out_remove_del:
+ bus_remove_file(&pata_parport_bus_type, &bus_attr_delete_device);
+out_remove_new:
+ bus_remove_file(&pata_parport_bus_type, &bus_attr_new_device);
+out_unregister_dev:
+ device_unregister(&pata_parport_bus);
+out_unregister_bus:
+ bus_unregister(&pata_parport_bus_type);
+ return error;
+}
+
+static __exit void pata_parport_exit(void)
+{
+ parport_unregister_driver(&pata_parport_driver);
+ bus_remove_file(&pata_parport_bus_type, &bus_attr_new_device);
+ bus_remove_file(&pata_parport_bus_type, &bus_attr_delete_device);
+ device_unregister(&pata_parport_bus);
+ bus_unregister(&pata_parport_bus_type);
+}
+
+MODULE_AUTHOR("Ondrej Zary");
+MODULE_DESCRIPTION("driver for parallel port ATA adapters");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("paride");
+
+module_init(pata_parport_init);
+module_exit(pata_parport_exit);
diff --git a/drivers/block/paride/Kconfig b/drivers/block/paride/Kconfig
index a295634597ba..01e4ef3655c1 100644
--- a/drivers/block/paride/Kconfig
+++ b/drivers/block/paride/Kconfig
@@ -92,11 +92,11 @@ config PARIDE_PG
later fully support this driver.

comment "Parallel IDE protocol modules"
- depends on PARIDE
+ depends on PARIDE || PATA_PARPORT

config PARIDE_ATEN
tristate "ATEN EH-100 protocol"
- depends on PARIDE
+ depends on PARIDE || PATA_PARPORT
help
This option enables support for the ATEN EH-100 parallel port IDE
protocol. This protocol is used in some inexpensive low performance
@@ -109,7 +109,7 @@ config PARIDE_ATEN

config PARIDE_BPCK
tristate "MicroSolutions backpack (Series 5) protocol"
- depends on PARIDE
+ depends on PARIDE || PATA_PARPORT
help
This option enables support for the Micro Solutions BACKPACK
parallel port Series 5 IDE protocol. (Most BACKPACK drives made
@@ -127,7 +127,7 @@ config PARIDE_BPCK

config PARIDE_BPCK6
tristate "MicroSolutions backpack (Series 6) protocol"
- depends on PARIDE && !64BIT
+ depends on (PARIDE || PATA_PARPORT) && !64BIT
help
This option enables support for the Micro Solutions BACKPACK
parallel port Series 6 IDE protocol. (Most BACKPACK drives made
@@ -146,7 +146,7 @@ config PARIDE_BPCK6

config PARIDE_COMM
tristate "DataStor Commuter protocol"
- depends on PARIDE
+ depends on PARIDE || PATA_PARPORT
help
This option enables support for the Commuter parallel port IDE
protocol from DataStor. If you chose to build PARIDE support
@@ -157,7 +157,7 @@ config PARIDE_COMM

config PARIDE_DSTR
tristate "DataStor EP-2000 protocol"
- depends on PARIDE
+ depends on PARIDE || PATA_PARPORT
help
This option enables support for the EP-2000 parallel port IDE
protocol from DataStor. If you chose to build PARIDE support
@@ -168,7 +168,7 @@ config PARIDE_DSTR

config PARIDE_FIT2
tristate "FIT TD-2000 protocol"
- depends on PARIDE
+ depends on PARIDE || PATA_PARPORT
help
This option enables support for the TD-2000 parallel port IDE
protocol from Fidelity International Technology. This is a simple
@@ -181,7 +181,7 @@ config PARIDE_FIT2

config PARIDE_FIT3
tristate "FIT TD-3000 protocol"
- depends on PARIDE
+ depends on PARIDE || PATA_PARPORT
help
This option enables support for the TD-3000 parallel port IDE
protocol from Fidelity International Technology. This protocol is
@@ -194,7 +194,7 @@ config PARIDE_FIT3

config PARIDE_EPAT
tristate "Shuttle EPAT/EPEZ protocol"
- depends on PARIDE
+ depends on PARIDE || PATA_PARPORT
help
This option enables support for the EPAT parallel port IDE protocol.
EPAT is a parallel port IDE adapter manufactured by Shuttle
@@ -216,7 +216,7 @@ config PARIDE_EPATC8

config PARIDE_EPIA
tristate "Shuttle EPIA protocol"
- depends on PARIDE
+ depends on PARIDE || PATA_PARPORT
help
This option enables support for the (obsolete) EPIA parallel port
IDE protocol from Shuttle Technology. This adapter can still be
@@ -228,7 +228,7 @@ config PARIDE_EPIA

config PARIDE_FRIQ
tristate "Freecom IQ ASIC-2 protocol"
- depends on PARIDE
+ depends on PARIDE || PATA_PARPORT
help
This option enables support for version 2 of the Freecom IQ parallel
port IDE adapter. This adapter is used by the Maxell Superdisk
@@ -240,7 +240,7 @@ config PARIDE_FRIQ

config PARIDE_FRPW
tristate "FreeCom power protocol"
- depends on PARIDE
+ depends on PARIDE || PATA_PARPORT
help
This option enables support for the Freecom power parallel port IDE
protocol. If you chose to build PARIDE support into your kernel, you
@@ -251,7 +251,7 @@ config PARIDE_FRPW

config PARIDE_KBIC
tristate "KingByte KBIC-951A/971A protocols"
- depends on PARIDE
+ depends on PARIDE || PATA_PARPORT
help
This option enables support for the KBIC-951A and KBIC-971A parallel
port IDE protocols from KingByte Information Corp. KingByte's
@@ -264,7 +264,7 @@ config PARIDE_KBIC

config PARIDE_KTTI
tristate "KT PHd protocol"
- depends on PARIDE
+ depends on PARIDE || PATA_PARPORT
help
This option enables support for the "PHd" parallel port IDE protocol
from KT Technology. This is a simple (low speed) adapter that is
@@ -277,7 +277,7 @@ config PARIDE_KTTI

config PARIDE_ON20
tristate "OnSpec 90c20 protocol"
- depends on PARIDE
+ depends on PARIDE || PATA_PARPORT
help
This option enables support for the (obsolete) 90c20 parallel port
IDE protocol from OnSpec (often marketed under the ValuStore brand
@@ -289,7 +289,7 @@ config PARIDE_ON20

config PARIDE_ON26
tristate "OnSpec 90c26 protocol"
- depends on PARIDE
+ depends on PARIDE || PATA_PARPORT
help
This option enables support for the 90c26 parallel port IDE protocol
from OnSpec Electronics (often marketed under the ValuStore brand
diff --git a/drivers/block/paride/paride.h b/drivers/block/paride/paride.h
index ddb9e589da7f..24dcfadb782d 100644
--- a/drivers/block/paride/paride.h
+++ b/drivers/block/paride/paride.h
@@ -1,3 +1,15 @@
+/*
+ * The low-level protocol modules are used by either paride or pata_parport.
+ * These two are mutually exclusive because the compiled low-level protocol
+ * modules are not compatible.
+ * When PATA_PARPORT is enabled, include pata_parport.h instead of the rest
+ * of this file.
+ */
+
+#if IS_ENABLED(CONFIG_PATA_PARPORT)
+#include <linux/pata_parport.h>
+
+#else
#ifndef __DRIVERS_PARIDE_H__
#define __DRIVERS_PARIDE_H__

@@ -170,3 +182,4 @@ void pi_unregister_driver(void *);

#endif /* __DRIVERS_PARIDE_H__ */
/* end of paride.h */
+#endif /* IS_ENABLED(CONFIG_PATA_PARPORT) */
diff --git a/include/linux/pata_parport.h b/include/linux/pata_parport.h
new file mode 100644
index 000000000000..58781846f282
--- /dev/null
+++ b/include/linux/pata_parport.h
@@ -0,0 +1,111 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * pata_parport.h (c) 1997-8 Grant R. Guenther <[email protected]>
+ * Under the terms of the GPL.
+ *
+ * This file defines the interface for parallel port IDE adapter chip drivers.
+ */
+
+#ifndef LINUX_PATA_PARPORT_H
+#define LINUX_PATA_PARPORT_H
+
+#include <linux/libata.h>
+
+#define PI_PCD 1 /* dummy for paride protocol modules */
+
+struct pi_adapter {
+ struct device dev;
+ struct pi_protocol *proto; /* adapter protocol */
+ int port; /* base address of parallel port */
+ int mode; /* transfer mode in use */
+ int delay; /* adapter delay setting */
+ int devtype; /* dummy for paride protocol modules */
+ char *device; /* dummy for paride protocol modules */
+ int unit; /* unit number for chained adapters */
+ int saved_r0; /* saved port state */
+ int saved_r2; /* saved port state */
+ unsigned long private; /* for protocol module */
+ struct pardevice *pardev; /* pointer to pardevice */
+};
+
+typedef struct pi_adapter PIA; /* for paride protocol modules */
+
+/* registers are addressed as (cont,regr)
+ * cont: 0 for command register file, 1 for control register(s)
+ * regr: 0-7 for register number.
+ */
+
+/* macros and functions exported to the protocol modules */
+#define delay_p (pi->delay ? udelay(pi->delay) : (void)0)
+#define out_p(offs, byte) do { outb(byte, pi->port + offs); delay_p; } while (0)
+#define in_p(offs) (delay_p, inb(pi->port + offs))
+
+#define w0(byte) out_p(0, byte)
+#define r0() in_p(0)
+#define w1(byte) out_p(1, byte)
+#define r1() in_p(1)
+#define w2(byte) out_p(2, byte)
+#define r2() in_p(2)
+#define w3(byte) out_p(3, byte)
+#define w4(byte) out_p(4, byte)
+#define r4() in_p(4)
+#define w4w(data) do { outw(data, pi->port + 4); delay_p; } while (0)
+#define w4l(data) do { outl(data, pi->port + 4); delay_p; } while (0)
+#define r4w() (delay_p, inw(pi->port + 4))
+#define r4l() (delay_p, inl(pi->port + 4))
+
+static inline u16 pi_swab16(char *b, int k)
+{
+ union { u16 u; char t[2]; } r;
+
+ r.t[0] = b[2 * k + 1]; r.t[1] = b[2 * k];
+ return r.u;
+}
+
+static inline u32 pi_swab32(char *b, int k)
+{
+ union { u32 u; char f[4]; } r;
+
+ r.f[0] = b[4 * k + 1]; r.f[1] = b[4 * k];
+ r.f[2] = b[4 * k + 3]; r.f[3] = b[4 * k + 2];
+ return r.u;
+}
+
+struct pi_protocol {
+ char name[8];
+
+ int max_mode;
+ int epp_first; /* modes >= this use 8 ports */
+
+ int default_delay;
+ int max_units; /* max chained units probed for */
+
+ void (*write_regr)(struct pi_adapter *pi, int cont, int regr, int val);
+ int (*read_regr)(struct pi_adapter *pi, int cont, int regr);
+ void (*write_block)(struct pi_adapter *pi, char *buf, int count);
+ void (*read_block)(struct pi_adapter *pi, char *buf, int count);
+
+ void (*connect)(struct pi_adapter *pi);
+ void (*disconnect)(struct pi_adapter *pi);
+
+ int (*test_port)(struct pi_adapter *pi);
+ int (*probe_unit)(struct pi_adapter *pi);
+ int (*test_proto)(struct pi_adapter *pi, char *scratch, int verbose);
+ void (*log_adapter)(struct pi_adapter *pi, char *scratch, int verbose);
+
+ int (*init_proto)(struct pi_adapter *pi);
+ void (*release_proto)(struct pi_adapter *pi);
+ struct module *owner;
+ struct device_driver driver;
+ struct scsi_host_template sht;
+};
+
+#define PATA_PARPORT_SHT ATA_PIO_SHT
+
+int pata_parport_register_driver(struct pi_protocol *pr);
+void pata_parport_unregister_driver(struct pi_protocol *pr);
+/* defines for old paride protocol modules */
+#define paride_register pata_parport_register_driver
+#define paride_unregister pata_parport_unregister_driver
+
+#endif /* LINUX_PATA_PARPORT_H */
--
Ondrej Zary


2023-01-23 19:13:57

by Ondrej Zary

[permalink] [raw]
Subject: Re: [PATCH v2] pata_parport: add driver (PARIDE replacement)

On Monday 23 January 2023 02:03:16 Damien Le Moal wrote:

[...]

> You are missing:
>
> #ifndef LINUX_PATA_PARPORT_H
> #define LINUX_PATA_PARPORT_H
>
> > +#include <linux/libata.h>
> > +
> > +#define PI_PCD 1 /* dummy for paride protocol modules */
> > +
> > +struct pi_adapter {
> > + struct device dev;
> > + struct pi_protocol *proto; /* adapter protocol */
> > + int port; /* base address of parallel port */
> > + int mode; /* transfer mode in use */
> > + int delay; /* adapter delay setting */
> > + int devtype; /* dummy for paride protocol modules */
> > + char *device; /* dummy for paride protocol modules */
> > + int unit; /* unit number for chained adapters */
> > + int saved_r0; /* saved port state */
> > + int saved_r2; /* saved port state */
> > + unsigned long private; /* for protocol module */
> > + struct pardevice *pardev; /* pointer to pardevice */
> > +};
> > +
> > +typedef struct pi_adapter PIA; /* for paride protocol modules */
> > +
> > +/* registers are addressed as (cont,regr)
> > + * cont: 0 for command register file, 1 for control register(s)
> > + * regr: 0-7 for register number.
> > + */
> > +
> > +/* macros and functions exported to the protocol modules */
> > +#define delay_p (pi->delay ? udelay(pi->delay) : (void)0)
> > +#define out_p(offs, byte) do { outb(byte, pi->port + offs); delay_p; } while (0)
> > +#define in_p(offs) (delay_p, inb(pi->port + offs))
>
> It would be way nicer to have these as inline functions.

This should go away (as well as the code below) so I'm not touching it now.

> > +
> > +#define w0(byte) out_p(0, byte)
> > +#define r0() in_p(0)
> > +#define w1(byte) out_p(1, byte)
> > +#define r1() in_p(1)
> > +#define w2(byte) out_p(2, byte)
> > +#define r2() in_p(2)
> > +#define w3(byte) out_p(3, byte)
> > +#define w4(byte) out_p(4, byte)
> > +#define r4() in_p(4)
> > +#define w4w(data) do { outw(data, pi->port + 4); delay_p; } while (0)
> > +#define w4l(data) do { outl(data, pi->port + 4); delay_p; } while (0)
> > +#define r4w() (delay_p, inw(pi->port + 4))
> > +#define r4l() (delay_p, inl(pi->port + 4))
> > +
> > +static inline u16 pi_swab16(char *b, int k)
> > +{
> > + union { u16 u; char t[2]; } r;
> > +
> > + r.t[0] = b[2 * k + 1]; r.t[1] = b[2 * k];
> > + return r.u;
> > +}
> > +
> > +static inline u32 pi_swab32(char *b, int k)
> > +{
> > + union { u32 u; char f[4]; } r;
> > +
> > + r.f[0] = b[4 * k + 1]; r.f[1] = b[4 * k];
> > + r.f[2] = b[4 * k + 3]; r.f[3] = b[4 * k + 2];
> > + return r.u;
> > +}

--
Ondrej Zary

2023-01-24 10:03:10

by Hannes Reinecke

[permalink] [raw]
Subject: Re: [PATCH v2] pata_parport: add driver (PARIDE replacement)

On 1/21/23 23:53, Ondrej Zary wrote:
> The pata_parport is a libata-based replacement of the old PARIDE
> subsystem - driver for parallel port IDE devices.
> It uses the original paride low-level protocol drivers but does not
> need the high-level drivers (pd, pcd, pf, pt, pg). The IDE devices
> behind parallel port adapters are handled by the ATA layer.
>
> This will allow paride and its high-level drivers to be removed.
>
> Unfortunately, libata drivers cannot sleep so pata_parport claims
> parport before activating the ata host and keeps it claimed (and
> protocol connected) until the ata host is removed. This means that
> no devices can be chained (neither other pata_parport devices nor
> a printer).
>
> paride and pata_parport are mutually exclusive because the compiled
> protocol drivers are incompatible.
>
> Tested with:
> - Imation SuperDisk LS-120 and HP C4381A (EPAT)
> - Freecom Parallel CD (FRPW)
> - Toshiba Mobile CD-RW 2793008 w/Freecom Parallel Cable rev.903 (FRIQ)
> - Backpack CD-RW 222011 and CD-RW 19350 (BPCK6)
>
> The following bugs in low-level protocol drivers were found and will
> be fixed later:
>
> Note: EPP-32 mode is buggy in EPAT - and also in all other protocol
> drivers - they don't handle non-multiple-of-4 block transfers
> correctly. This causes problems with LS-120 drive.
> There is also another bug in EPAT: EPP modes don't work unless a 4-bit
> or 8-bit mode is used first (probably some initialization missing?).
> Once the device is initialized, EPP works until power cycle.
>
> So after device power on, you have to:
> echo "parport0 epat 0" >/sys/bus/pata_parport/new_device
> echo pata_parport.0 >/sys/bus/pata_parport/delete_device
> echo "parport0 epat 4" >/sys/bus/pata_parport/new_device
> (autoprobe will initialize correctly as it tries the slowest modes
> first but you'll get the broken EPP-32 mode)
>
> Note: EPP modes are buggy in FRPW, only modes 0 and 1 work.
> Signed-off-by: Ondrej Zary <[email protected]>
> ---
>
> Changes in v2:
> - keep device connected, remove disconnect timer
>
> Documentation/admin-guide/blockdev/paride.rst | 52 ++
> drivers/Makefile | 2 +-
> drivers/ata/Kconfig | 14 +
> drivers/ata/Makefile | 2 +
> drivers/ata/pata_parport.c | 783 ++++++++++++++++++
> drivers/block/paride/Kconfig | 32 +-
> drivers/block/paride/paride.h | 13 +
> include/linux/pata_parport.h | 106 +++
> 8 files changed, 987 insertions(+), 17 deletions(-)
> create mode 100644 drivers/ata/pata_parport.c
> create mode 100644 include/linux/pata_parport.h
>
Reviewed-by: Hannes Reinecke <[email protected]>

Cheers,

Hannes
--
Dr. Hannes Reinecke Kernel Storage Architect
[email protected] +49 911 74053 688
SUSE Software Solutions Germany GmbH, Maxfeldstr. 5, 90409 Nürnberg
HRB 36809 (AG Nürnberg), GF: Felix Imendörffer


2023-01-30 03:31:13

by Damien Le Moal

[permalink] [raw]
Subject: Re: [PATCH v3] pata_parport: add driver (PARIDE replacement)

On 1/24/23 04:09, Ondrej Zary wrote:
> The pata_parport is a libata-based replacement of the old PARIDE
> subsystem - driver for parallel port IDE devices.
> It uses the original paride low-level protocol drivers but does not
> need the high-level drivers (pd, pcd, pf, pt, pg). The IDE devices
> behind parallel port adapters are handled by the ATA layer.
>
> This will allow paride and its high-level drivers to be removed.
>
> Unfortunately, libata drivers cannot sleep so pata_parport claims
> parport before activating the ata host and keeps it claimed (and
> protocol connected) until the ata host is removed. This means that
> no devices can be chained (neither other pata_parport devices nor
> a printer).
>
> paride and pata_parport are mutually exclusive because the compiled
> protocol drivers are incompatible.
>
> Tested with:
> - Imation SuperDisk LS-120 and HP C4381A (EPAT)
> - Freecom Parallel CD (FRPW)
> - Toshiba Mobile CD-RW 2793008 w/Freecom Parallel Cable rev.903 (FRIQ)
> - Backpack CD-RW 222011 and CD-RW 19350 (BPCK6)
>
> The following bugs in low-level protocol drivers were found and will
> be fixed later:
>
> Note: EPP-32 mode is buggy in EPAT - and also in all other protocol
> drivers - they don't handle non-multiple-of-4 block transfers
> correctly. This causes problems with LS-120 drive.
> There is also another bug in EPAT: EPP modes don't work unless a 4-bit
> or 8-bit mode is used first (probably some initialization missing?).
> Once the device is initialized, EPP works until power cycle.
>
> So after device power on, you have to:
> echo "parport0 epat 0" >/sys/bus/pata_parport/new_device
> echo pata_parport.0 >/sys/bus/pata_parport/delete_device
> echo "parport0 epat 4" >/sys/bus/pata_parport/new_device
> (autoprobe will initialize correctly as it tries the slowest modes
> first but you'll get the broken EPP-32 mode)
>
> Note: EPP modes are buggy in FRPW, only modes 0 and 1 work.
> Signed-off-by: Ondrej Zary <[email protected]>

Are you going to send a patch to remove the legacy parport code ?
If we want this queued for 6.3, it is now (this week, asap) or we will
have to delay to 6.4. Unless Jens prefers the deprecation first, which I
think he said "better delete now".

> ---
>
> Changes in v3:
> - addressed Damien's comments
>
> Changes in v2:
> - keep device connected, remove disconnect timer
>
> Documentation/admin-guide/blockdev/paride.rst | 52 ++
> drivers/Makefile | 2 +-
> drivers/ata/Kconfig | 14 +
> drivers/ata/Makefile | 2 +
> drivers/ata/pata_parport.c | 759 ++++++++++++++++++
> drivers/block/paride/Kconfig | 32 +-
> drivers/block/paride/paride.h | 13 +
> include/linux/pata_parport.h | 111 +++
> 8 files changed, 968 insertions(+), 17 deletions(-)
> create mode 100644 drivers/ata/pata_parport.c
> create mode 100644 include/linux/pata_parport.h
>
> diff --git a/Documentation/admin-guide/blockdev/paride.rst b/Documentation/admin-guide/blockdev/paride.rst
> index e1ce90af602a..e431a1ef41eb 100644
> --- a/Documentation/admin-guide/blockdev/paride.rst
> +++ b/Documentation/admin-guide/blockdev/paride.rst
> @@ -2,6 +2,9 @@
> Linux and parallel port IDE devices
> ===================================
>
> +Most of this document describes the old paride driver. For the new libata
> +pata_parport drivrer, jump to the section 4 at the end.
> +
> PARIDE v1.03 (c) 1997-8 Grant Guenther <[email protected]>
>
> 1. Introduction
> @@ -437,3 +440,52 @@ You might also find some useful information on the linux-parport
> web pages (although they are not always up to date) at
>
> http://web.archive.org/web/%2E/http://www.torque.net/parport/
> +
> +4. pata_parport driver
> +======================
> +pata_parport is a libata-based driver that uses the same low-level protocol
> +drivers as PARIDE but there are no high-level drivers (pd, pcd, pf, pt, pg).
> +The IDE devices behind parallel port adapters are handled by the ATA layer.
> +
> +The device creation is also changed - no protocol numbers or parport I/O
> +addresses are used.
> +
> +All parports and all protocol drivers are probed automatically unless probe=0
> +parameter is used. So just "modprobe epat" is enough for a Imation SuperDisk
> +drive to work.
> +
> +Manual device creation::
> +
> + # echo "port protocol mode unit delay" >/sys/bus/pata_parport/new_device
> +
> +where:
> +
> + ======== ================================================
> + port parport name (or "auto" for all parports)
> + protocol protocol name (or "auto" for all protocols)
> + mode mode number (protocol-specific) or -1 for probe
> + unit unit number (see the paride documentation above)
> + delay I/O delay (see the paride documentation above)
> + ======== ================================================
> +
> +If you omit the parameters from the end, defaults will be used, e.g.:
> +
> +Probe all parports with all protocols::
> +
> + # echo auto >/sys/bus/pata_parport/new_device
> +
> +Probe parport0 using protocol epat and mode 4 (EPP-16)::
> +
> + # echo "parport0 epat 4" >/sys/bus/pata_parport/new_device
> +
> +Probe parport0 using all protocols::
> +
> + # echo "parport0 auto" >/sys/bus/pata_parport/new_device
> +
> +Probe all parports using protoocol epat::
> +
> + # echo "auto epat" >/sys/bus/pata_parport/new_device
> +
> +Deleting devices::
> +
> + # echo pata_parport.0 >/sys/bus/pata_parport/delete_device
> diff --git a/drivers/Makefile b/drivers/Makefile
> index bdf1c66141c9..f1365608bc8c 100644
> --- a/drivers/Makefile
> +++ b/drivers/Makefile
> @@ -98,7 +98,7 @@ obj-$(CONFIG_DIO) += dio/
> obj-$(CONFIG_SBUS) += sbus/
> obj-$(CONFIG_ZORRO) += zorro/
> obj-$(CONFIG_ATA_OVER_ETH) += block/aoe/
> -obj-$(CONFIG_PARIDE) += block/paride/
> +obj-y += block/paride/
> obj-$(CONFIG_TC) += tc/
> obj-$(CONFIG_USB_PHY) += usb/
> obj-$(CONFIG_USB) += usb/
> diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
> index eceaec33af65..fb646480635c 100644
> --- a/drivers/ata/Kconfig
> +++ b/drivers/ata/Kconfig
> @@ -1162,6 +1162,20 @@ config PATA_WINBOND_VLB
> Support for the Winbond W83759A controller on Vesa Local Bus
> systems.
>
> +config PATA_PARPORT
> + tristate "Parallel port IDE device support"
> + depends on PARPORT_PC && PARIDE=n
> + help
> + There are many external CD-ROM and disk devices that connect through
> + your computer's parallel port. Most of them are actually IDE devices
> + using a parallel port IDE adapter. This option enables the
> + PATA_PARPORT subsystem which contains drivers for many of these
> + external drives.
> + Read <file:Documentation/admin-guide/blockdev/paride.rst> for more
> + information.
> +
> + Use the old PARIDE protocol modules.
> +
> comment "Generic fallback / legacy drivers"
>
> config PATA_ACPI
> diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
> index d2e36d367274..23588738cff0 100644
> --- a/drivers/ata/Makefile
> +++ b/drivers/ata/Makefile
> @@ -114,6 +114,8 @@ obj-$(CONFIG_PATA_SAMSUNG_CF) += pata_samsung_cf.o
>
> obj-$(CONFIG_PATA_PXA) += pata_pxa.o
>
> +obj-$(CONFIG_PATA_PARPORT) += pata_parport.o
> +
> # Should be last but two libata driver
> obj-$(CONFIG_PATA_ACPI) += pata_acpi.o
> # Should be last but one libata driver
> diff --git a/drivers/ata/pata_parport.c b/drivers/ata/pata_parport.c
> new file mode 100644
> index 000000000000..9e8ad93d7e59
> --- /dev/null
> +++ b/drivers/ata/pata_parport.c
> @@ -0,0 +1,759 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright 2023 Ondrej Zary
> + * based on paride.c by Grant R. Guenther <[email protected]>
> + */
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/parport.h>
> +#include <linux/pata_parport.h>
> +
> +#define DRV_NAME "pata_parport"
> +
> +static DEFINE_IDR(parport_list);
> +static DEFINE_IDR(protocols);
> +static DEFINE_IDA(pata_parport_bus_dev_ids);
> +static DEFINE_MUTEX(pi_mutex);
> +
> +static bool probe = true;
> +module_param(probe, bool, 0644);
> +MODULE_PARM_DESC(probe, "Enable automatic device probing (0=off, 1=on [default])");
> +
> +/*
> + * libata drivers cannot sleep so this driver claims parport before activating
> + * the ata host and keeps it claimed (and protocol connected) until the ata
> + * host is removed. Unfortunately, this means that you cannot use any chained
> + * devices (neither other pata_parport devices nor a printer).
> + */
> +static void pi_connect(struct pi_adapter *pi)
> +{
> + parport_claim_or_block(pi->pardev);
> + pi->proto->connect(pi);
> +}
> +
> +static void pi_disconnect(struct pi_adapter *pi)
> +{
> + pi->proto->disconnect(pi);
> + parport_release(pi->pardev);
> +}
> +
> +static void pata_parport_dev_select(struct ata_port *ap, unsigned int device)
> +{
> + struct pi_adapter *pi = ap->host->private_data;
> + u8 tmp;
> +
> + if (device == 0)
> + tmp = ATA_DEVICE_OBS;
> + else
> + tmp = ATA_DEVICE_OBS | ATA_DEV1;
> +
> + pi->proto->write_regr(pi, 0, ATA_REG_DEVICE, tmp);
> + ata_sff_pause(ap);
> +}
> +
> +static bool pata_parport_devchk(struct ata_port *ap, unsigned int device)
> +{
> + struct pi_adapter *pi = ap->host->private_data;
> + u8 nsect, lbal;
> +
> + pata_parport_dev_select(ap, device);
> +
> + pi->proto->write_regr(pi, 0, ATA_REG_NSECT, 0x55);
> + pi->proto->write_regr(pi, 0, ATA_REG_LBAL, 0xaa);
> +
> + pi->proto->write_regr(pi, 0, ATA_REG_NSECT, 0xaa);
> + pi->proto->write_regr(pi, 0, ATA_REG_LBAL, 0x55);
> +
> + pi->proto->write_regr(pi, 0, ATA_REG_NSECT, 055);
> + pi->proto->write_regr(pi, 0, ATA_REG_LBAL, 0xaa);
> +
> + nsect = pi->proto->read_regr(pi, 0, ATA_REG_NSECT);
> + lbal = pi->proto->read_regr(pi, 0, ATA_REG_LBAL);
> +
> + return (nsect == 0x55) && (lbal == 0xaa);
> +}
> +
> +static int pata_parport_bus_softreset(struct ata_port *ap, unsigned int devmask,
> + unsigned long deadline)
> +{
> + struct pi_adapter *pi = ap->host->private_data;
> +
> + /* software reset. causes dev0 to be selected */
> + pi->proto->write_regr(pi, 1, 6, ap->ctl);
> + udelay(20);
> + pi->proto->write_regr(pi, 1, 6, ap->ctl | ATA_SRST);
> + udelay(20);
> + pi->proto->write_regr(pi, 1, 6, ap->ctl);
> + ap->last_ctl = ap->ctl;
> +
> + /* wait the port to become ready */
> + return ata_sff_wait_after_reset(&ap->link, devmask, deadline);
> +}
> +
> +static int pata_parport_softreset(struct ata_link *link, unsigned int *classes,
> + unsigned long deadline)
> +{
> + struct ata_port *ap = link->ap;
> + unsigned int devmask = 0;
> + int rc;
> + u8 err;
> +
> + /* determine if device 0/1 are present */
> + if (pata_parport_devchk(ap, 0))
> + devmask |= (1 << 0);
> + if (pata_parport_devchk(ap, 1))
> + devmask |= (1 << 1);
> +
> + /* select device 0 again */
> + pata_parport_dev_select(ap, 0);
> +
> + /* issue bus reset */
> + rc = pata_parport_bus_softreset(ap, devmask, deadline);
> + if (rc && rc != -ENODEV) {
> + ata_link_err(link, "SRST failed (errno=%d)\n", rc);
> + return rc;
> + }
> +
> + /* determine by signature whether we have ATA or ATAPI devices */
> + classes[0] = ata_sff_dev_classify(&link->device[0],
> + devmask & (1 << 0), &err);
> + if (err != 0x81)
> + classes[1] = ata_sff_dev_classify(&link->device[1],
> + devmask & (1 << 1), &err);
> +
> + return 0;
> +}
> +
> +static u8 pata_parport_check_status(struct ata_port *ap)
> +{
> + struct pi_adapter *pi = ap->host->private_data;
> +
> + return pi->proto->read_regr(pi, 0, ATA_REG_STATUS);
> +}
> +
> +static u8 pata_parport_check_altstatus(struct ata_port *ap)
> +{
> + struct pi_adapter *pi = ap->host->private_data;
> +
> + return pi->proto->read_regr(pi, 1, 6);
> +}
> +
> +static void pata_parport_tf_load(struct ata_port *ap,
> + const struct ata_taskfile *tf)
> +{
> + struct pi_adapter *pi = ap->host->private_data;
> +
> + if (tf->ctl != ap->last_ctl) {
> + pi->proto->write_regr(pi, 1, 6, tf->ctl);
> + ap->last_ctl = tf->ctl;
> + ata_wait_idle(ap);
> + }
> +
> + if (tf->flags & ATA_TFLAG_ISADDR) {
> + if (tf->flags & ATA_TFLAG_LBA48) {
> + pi->proto->write_regr(pi, 0, ATA_REG_FEATURE,
> + tf->hob_feature);
> + pi->proto->write_regr(pi, 0, ATA_REG_NSECT,
> + tf->hob_nsect);
> + pi->proto->write_regr(pi, 0, ATA_REG_LBAL,
> + tf->hob_lbal);
> + pi->proto->write_regr(pi, 0, ATA_REG_LBAM,
> + tf->hob_lbam);
> + pi->proto->write_regr(pi, 0, ATA_REG_LBAH,
> + tf->hob_lbah);
> + }
> + pi->proto->write_regr(pi, 0, ATA_REG_FEATURE, tf->feature);
> + pi->proto->write_regr(pi, 0, ATA_REG_NSECT, tf->nsect);
> + pi->proto->write_regr(pi, 0, ATA_REG_LBAL, tf->lbal);
> + pi->proto->write_regr(pi, 0, ATA_REG_LBAM, tf->lbam);
> + pi->proto->write_regr(pi, 0, ATA_REG_LBAH, tf->lbah);
> + }
> +
> + if (tf->flags & ATA_TFLAG_DEVICE)
> + pi->proto->write_regr(pi, 0, ATA_REG_DEVICE, tf->device);
> +
> + ata_wait_idle(ap);
> +}
> +
> +static void pata_parport_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
> +{
> + struct pi_adapter *pi = ap->host->private_data;
> +
> + tf->status = pi->proto->read_regr(pi, 0, ATA_REG_STATUS);
> + tf->error = pi->proto->read_regr(pi, 0, ATA_REG_ERR);
> + tf->nsect = pi->proto->read_regr(pi, 0, ATA_REG_NSECT);
> + tf->lbal = pi->proto->read_regr(pi, 0, ATA_REG_LBAL);
> + tf->lbam = pi->proto->read_regr(pi, 0, ATA_REG_LBAM);
> + tf->lbah = pi->proto->read_regr(pi, 0, ATA_REG_LBAH);
> + tf->device = pi->proto->read_regr(pi, 0, ATA_REG_DEVICE);
> +
> + if (tf->flags & ATA_TFLAG_LBA48) {
> + pi->proto->write_regr(pi, 1, 6, tf->ctl | ATA_HOB);
> + tf->hob_feature = pi->proto->read_regr(pi, 0, ATA_REG_ERR);
> + tf->hob_nsect = pi->proto->read_regr(pi, 0, ATA_REG_NSECT);
> + tf->hob_lbal = pi->proto->read_regr(pi, 0, ATA_REG_LBAL);
> + tf->hob_lbam = pi->proto->read_regr(pi, 0, ATA_REG_LBAM);
> + tf->hob_lbah = pi->proto->read_regr(pi, 0, ATA_REG_LBAH);
> + pi->proto->write_regr(pi, 1, 6, tf->ctl);
> + ap->last_ctl = tf->ctl;
> + }
> +}
> +
> +static void pata_parport_exec_command(struct ata_port *ap,
> + const struct ata_taskfile *tf)
> +{
> + struct pi_adapter *pi = ap->host->private_data;
> +
> + pi->proto->write_regr(pi, 0, ATA_REG_CMD, tf->command);
> + ata_sff_pause(ap);
> +}
> +
> +static unsigned int pata_parport_data_xfer(struct ata_queued_cmd *qc,
> + unsigned char *buf, unsigned int buflen, int rw)
> +{
> + struct ata_port *ap = qc->dev->link->ap;
> + struct pi_adapter *pi = ap->host->private_data;
> +
> + if (rw == READ)
> + pi->proto->read_block(pi, buf, buflen);
> + else
> + pi->proto->write_block(pi, buf, buflen);
> +
> + return buflen;
> +}
> +
> +static void pata_parport_drain_fifo(struct ata_queued_cmd *qc)
> +{
> + int count;
> + struct ata_port *ap;
> + struct pi_adapter *pi;
> + char junk[2];
> +
> + /* We only need to flush incoming data when a command was running */
> + if (qc == NULL || qc->dma_dir == DMA_TO_DEVICE)
> + return;
> +
> + ap = qc->ap;
> + pi = ap->host->private_data;
> + /* Drain up to 64K of data before we give up this recovery method */
> + for (count = 0; (pata_parport_check_status(ap) & ATA_DRQ)
> + && count < 65536; count += 2) {
> + pi->proto->read_block(pi, junk, 2);
> + }
> +
> + if (count)
> + ata_port_dbg(ap, "drained %d bytes to clear DRQ\n", count);
> +}
> +
> +static struct ata_port_operations pata_parport_port_ops = {
> + .inherits = &ata_sff_port_ops,
> +
> + .softreset = pata_parport_softreset,
> + .hardreset = NULL,
> +
> + .sff_dev_select = pata_parport_dev_select,
> + .sff_check_status = pata_parport_check_status,
> + .sff_check_altstatus = pata_parport_check_altstatus,
> + .sff_tf_load = pata_parport_tf_load,
> + .sff_tf_read = pata_parport_tf_read,
> + .sff_exec_command = pata_parport_exec_command,
> + .sff_data_xfer = pata_parport_data_xfer,
> + .sff_drain_fifo = pata_parport_drain_fifo,
> +};
> +
> +static const struct ata_port_info pata_parport_port_info = {
> + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_PIO_POLLING,
> + .pio_mask = ATA_PIO0,
> + /* No DMA */
> + .port_ops = &pata_parport_port_ops,
> +};
> +
> +static void pi_release(struct pi_adapter *pi)
> +{
> + parport_unregister_device(pi->pardev);
> + if (pi->proto->release_proto)
> + pi->proto->release_proto(pi);
> + module_put(pi->proto->owner);
> +}
> +
> +static int default_test_proto(struct pi_adapter *pi, char *scratch)
> +{
> + int j, k;
> + int e[2] = { 0, 0 };
> +
> + pi->proto->connect(pi);
> +
> + for (j = 0; j < 2; j++) {
> + pi->proto->write_regr(pi, 0, 6, 0xa0 + j * 0x10);
> + for (k = 0; k < 256; k++) {
> + pi->proto->write_regr(pi, 0, 2, k ^ 0xaa);
> + pi->proto->write_regr(pi, 0, 3, k ^ 0x55);
> + if (pi->proto->read_regr(pi, 0, 2) != (k ^ 0xaa))
> + e[j]++;
> + }
> + }
> + pi->proto->disconnect(pi);
> +
> + dev_dbg(&pi->dev, "%s: port 0x%x, mode %d, test=(%d,%d)\n",
> + pi->proto->name, pi->port, pi->mode, e[0], e[1]);
> +
> + return e[0] && e[1]; /* not here if both > 0 */
> +}
> +
> +static int pi_test_proto(struct pi_adapter *pi, char *scratch)
> +{
> + int res;
> +
> + parport_claim_or_block(pi->pardev);
> + if (pi->proto->test_proto)
> + res = pi->proto->test_proto(pi, scratch, 1);
> + else
> + res = default_test_proto(pi, scratch);
> + parport_release(pi->pardev);
> +
> + return res;
> +}
> +
> +static bool pi_probe_mode(struct pi_adapter *pi, int max, char *scratch)
> +{
> + int best, range;
> +
> + if (pi->mode != -1) {
> + if (pi->mode >= max)
> + return false;
> + range = 3;
> + if (pi->mode >= pi->proto->epp_first)
> + range = 8;
> + if (range == 8 && pi->port % 8)
> + return false;
> + return !pi_test_proto(pi, scratch);
> + }
> + best = -1;
> + for (pi->mode = 0; pi->mode < max; pi->mode++) {
> + range = 3;
> + if (pi->mode >= pi->proto->epp_first)
> + range = 8;
> + if (range == 8 && pi->port % 8)
> + break;
> + if (!pi_test_proto(pi, scratch))
> + best = pi->mode;
> + }
> + pi->mode = best;
> + return best > -1;
> +}
> +
> +static bool pi_probe_unit(struct pi_adapter *pi, int unit, char *scratch)
> +{
> + int max, s, e;
> +
> + s = unit;
> + e = s + 1;
> +
> + if (s == -1) {
> + s = 0;
> + e = pi->proto->max_units;
> + }
> +
> + if (pi->proto->test_port) {
> + parport_claim_or_block(pi->pardev);
> + max = pi->proto->test_port(pi);
> + parport_release(pi->pardev);
> + } else {
> + max = pi->proto->max_mode;
> + }
> +
> + if (pi->proto->probe_unit) {
> + parport_claim_or_block(pi->pardev);
> + for (pi->unit = s; pi->unit < e; pi->unit++) {
> + if (pi->proto->probe_unit(pi)) {
> + parport_release(pi->pardev);
> + return pi_probe_mode(pi, max, scratch);
> + }
> + }
> + parport_release(pi->pardev);
> + return false;
> + }
> +
> + return pi_probe_mode(pi, max, scratch);
> +}
> +
> +static void pata_parport_dev_release(struct device *dev)
> +{
> + struct pi_adapter *pi = container_of(dev, struct pi_adapter, dev);
> +
> + kfree(pi);
> +}
> +
> +static void pata_parport_bus_release(struct device *dev)
> +{
> + /* nothing to do here but required to avoid warning on device removal */
> +}
> +
> +static struct bus_type pata_parport_bus_type = {
> + .name = DRV_NAME,
> +};
> +
> +static struct device pata_parport_bus = {
> + .init_name = DRV_NAME,
> + .release = pata_parport_bus_release,
> +};
> +
> +static struct scsi_host_template pata_parport_sht = {
> + PATA_PARPORT_SHT("pata_parport")
> +};
> +
> +struct pi_device_match {
> + struct parport *parport;
> + struct pi_protocol *proto;
> +};
> +
> +static int pi_find_dev(struct device *dev, void *data)
> +{
> + struct pi_adapter *pi = container_of(dev, struct pi_adapter, dev);
> + struct pi_device_match *match = data;
> +
> + return pi->pardev->port == match->parport && pi->proto == match->proto;
> +}
> +
> +static struct pi_adapter *pi_init_one(struct parport *parport,
> + struct pi_protocol *pr, int mode, int unit, int delay)
> +{
> + struct pardev_cb par_cb = { };
> + char scratch[512];
> + const struct ata_port_info *ppi[] = { &pata_parport_port_info };
> + struct ata_host *host;
> + struct pi_adapter *pi;
> + struct pi_device_match match = { .parport = parport, .proto = pr };
> +
> + /*
> + * Abort if there's a device already registered on the same parport
> + * using the same protocol.
> + */
> + if (bus_for_each_dev(&pata_parport_bus_type, NULL, &match, pi_find_dev))
> + return NULL;
> +
> + pi = kzalloc(sizeof(struct pi_adapter), GFP_KERNEL);
> + if (!pi)
> + return NULL;
> +
> + /* set up pi->dev before pi_probe_unit() so it can use dev_printk() */
> + pi->dev.parent = &pata_parport_bus;
> + pi->dev.bus = &pata_parport_bus_type;
> + pi->dev.driver = &pr->driver;
> + pi->dev.release = pata_parport_dev_release;
> + pi->dev.id = ida_alloc(&pata_parport_bus_dev_ids, GFP_KERNEL);
> + if (pi->dev.id < 0)
> + return NULL; /* pata_parport_dev_release will do kfree(pi) */
> + dev_set_name(&pi->dev, "pata_parport.%u", pi->dev.id);
> + if (device_register(&pi->dev)) {
> + put_device(&pi->dev);
> + goto out_ida_free;
> + }
> +
> + pi->proto = pr;
> +
> + if (!try_module_get(pi->proto->owner))
> + goto out_unreg_dev;
> + if (pi->proto->init_proto && pi->proto->init_proto(pi) < 0)
> + goto out_module_put;
> +
> + pi->delay = (delay == -1) ? pi->proto->default_delay : delay;
> + pi->mode = mode;
> + pi->port = parport->base;
> +
> + par_cb.private = pi;
> + pi->pardev = parport_register_dev_model(parport, DRV_NAME, &par_cb,
> + pi->dev.id);
> + if (!pi->pardev)
> + goto out_module_put;
> +
> + if (!pi_probe_unit(pi, unit, scratch)) {
> + dev_info(&pi->dev, "Adapter not found\n");
> + goto out_unreg_parport;
> + }
> +
> + pi->proto->log_adapter(pi, scratch, 1);
> +
> + host = ata_host_alloc_pinfo(&pi->pardev->dev, ppi, 1);
> + if (!host)
> + goto out_unreg_parport;
> + dev_set_drvdata(&pi->dev, host);
> + host->private_data = pi;
> +
> + ata_port_desc(host->ports[0], "port %s", pi->pardev->port->name);
> + ata_port_desc(host->ports[0], "protocol %s", pi->proto->name);
> +
> + pi_connect(pi);
> + if (ata_host_activate(host, 0, NULL, 0, &pata_parport_sht))
> + goto out_unreg_parport;
> +
> + return pi;
> +
> +out_unreg_parport:
> + pi_disconnect(pi);
> + parport_unregister_device(pi->pardev);
> + if (pi->proto->release_proto)
> + pi->proto->release_proto(pi);
> +out_module_put:
> + module_put(pi->proto->owner);
> +out_unreg_dev:
> + device_unregister(&pi->dev);
> +out_ida_free:
> + ida_free(&pata_parport_bus_dev_ids, pi->dev.id);
> + return NULL;
> +}
> +
> +int pata_parport_register_driver(struct pi_protocol *pr)
> +{
> + int error;
> + struct parport *parport;
> + int port_num;
> +
> + pr->driver.bus = &pata_parport_bus_type;
> + pr->driver.name = pr->name;
> + error = driver_register(&pr->driver);
> + if (error)
> + return error;
> +
> + mutex_lock(&pi_mutex);
> + error = idr_alloc(&protocols, pr, 0, 0, GFP_KERNEL);
> + if (error < 0) {
> + driver_unregister(&pr->driver);
> + mutex_unlock(&pi_mutex);
> + return error;
> + }
> +
> + pr_info("pata_parport: protocol %s registered\n", pr->name);
> +
> + if (probe) {
> + /* probe all parports using this protocol */
> + idr_for_each_entry(&parport_list, parport, port_num)
> + pi_init_one(parport, pr, -1, 0, -1);
> + }
> + mutex_unlock(&pi_mutex);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(pata_parport_register_driver);
> +
> +void pata_parport_unregister_driver(struct pi_protocol *pr)
> +{
> + struct pi_protocol *pr_iter;
> + int id = -1;
> +
> + mutex_lock(&pi_mutex);
> + idr_for_each_entry(&protocols, pr_iter, id) {
> + if (pr_iter == pr)
> + break;
> + }
> + idr_remove(&protocols, id);
> + mutex_unlock(&pi_mutex);
> + driver_unregister(&pr->driver);
> +}
> +EXPORT_SYMBOL_GPL(pata_parport_unregister_driver);
> +
> +static ssize_t new_device_store(struct bus_type *bus, const char *buf,
> + size_t count)
> +{
> + char port[12] = "auto";
> + char protocol[8] = "auto";
> + int mode = -1, unit = -1, delay = -1;
> + struct pi_protocol *pr, *pr_wanted;
> + struct device_driver *drv;
> + struct parport *parport;
> + int port_num, port_wanted, pr_num;
> + bool ok = false;
> +
> + if (sscanf(buf, "%11s %7s %d %d %d",
> + port, protocol, &mode, &unit, &delay) < 1)
> + return -EINVAL;
> +
> + if (sscanf(port, "parport%u", &port_wanted) < 1) {
> + if (strcmp(port, "auto")) {
> + pr_err("invalid port name %s\n", port);
> + return -EINVAL;
> + }
> + port_wanted = -1;
> + }
> +
> + drv = driver_find(protocol, &pata_parport_bus_type);
> + if (!drv) {
> + if (strcmp(protocol, "auto")) {
> + pr_err("protocol %s not found\n", protocol);
> + return -EINVAL;
> + }
> + pr_wanted = NULL;
> + } else {
> + pr_wanted = container_of(drv, struct pi_protocol, driver);
> + }
> +
> + mutex_lock(&pi_mutex);
> + /* walk all parports */
> + idr_for_each_entry(&parport_list, parport, port_num) {
> + if (port_num == port_wanted || port_wanted == -1) {
> + parport = parport_find_number(port_num);
> + if (!parport) {
> + pr_err("no such port %s\n", port);
> + mutex_unlock(&pi_mutex);
> + return -ENODEV;
> + }
> + /* walk all protocols */
> + idr_for_each_entry(&protocols, pr, pr_num) {
> + if (pr == pr_wanted || !pr_wanted)
> + if (pi_init_one(parport, pr, mode, unit,
> + delay))
> + ok = true;
> + }
> + parport_put_port(parport);
> + }
> + }
> + mutex_unlock(&pi_mutex);
> + if (!ok)
> + return -ENODEV;
> +
> + return count;
> +}
> +static BUS_ATTR_WO(new_device);
> +
> +static void pi_remove_one(struct device *dev)
> +{
> + struct ata_host *host = dev_get_drvdata(dev);
> + struct pi_adapter *pi = host->private_data;
> +
> + ata_host_detach(host);
> + pi_disconnect(pi);
> + pi_release(pi);
> + device_unregister(dev);
> + ida_free(&pata_parport_bus_dev_ids, dev->id);
> + /* pata_parport_dev_release will do kfree(pi) */
> +}
> +
> +static ssize_t delete_device_store(struct bus_type *bus, const char *buf,
> + size_t count)
> +{
> + struct device *dev;
> +
> + mutex_lock(&pi_mutex);
> + dev = bus_find_device_by_name(bus, NULL, buf);
> + if (!dev) {
> + mutex_unlock(&pi_mutex);
> + return -ENODEV;
> + }
> +
> + pi_remove_one(dev);
> + mutex_unlock(&pi_mutex);
> +
> + return count;
> +}
> +static BUS_ATTR_WO(delete_device);
> +
> +static void pata_parport_attach(struct parport *port)
> +{
> + struct pi_protocol *pr;
> + int pr_num, id;
> +
> + mutex_lock(&pi_mutex);
> + id = idr_alloc(&parport_list, port, port->number, port->number,
> + GFP_KERNEL);
> + if (id < 0) {
> + mutex_unlock(&pi_mutex);
> + return;
> + }
> +
> + if (probe) {
> + /* probe this port using all protocols */
> + idr_for_each_entry(&protocols, pr, pr_num)
> + pi_init_one(port, pr, -1, 0, -1);
> + }
> + mutex_unlock(&pi_mutex);
> +}
> +
> +static int pi_remove_port(struct device *dev, void *p)
> +{
> + struct ata_host *host = dev_get_drvdata(dev);
> + struct pi_adapter *pi = host->private_data;
> +
> + if (pi->pardev->port == p)
> + pi_remove_one(dev);
> +
> + return 0;
> +}
> +
> +static void pata_parport_detach(struct parport *port)
> +{
> + mutex_lock(&pi_mutex);
> + bus_for_each_dev(&pata_parport_bus_type, NULL, port, pi_remove_port);
> + idr_remove(&parport_list, port->number);
> + mutex_unlock(&pi_mutex);
> +}
> +
> +static struct parport_driver pata_parport_driver = {
> + .name = DRV_NAME,
> + .match_port = pata_parport_attach,
> + .detach = pata_parport_detach,
> + .devmodel = true,
> +};
> +
> +static __init int pata_parport_init(void)
> +{
> + int error;
> +
> + error = bus_register(&pata_parport_bus_type);
> + if (error) {
> + pr_err("failed to register pata_parport bus, error: %d\n", error);
> + return error;
> + }
> +
> + error = device_register(&pata_parport_bus);
> + if (error) {
> + pr_err("failed to register pata_parport bus, error: %d\n", error);
> + goto out_unregister_bus;
> + }
> +
> + error = bus_create_file(&pata_parport_bus_type, &bus_attr_new_device);
> + if (error) {
> + pr_err("unable to create sysfs file, error: %d\n", error);
> + goto out_unregister_dev;
> + }
> +
> + error = bus_create_file(&pata_parport_bus_type, &bus_attr_delete_device);
> + if (error) {
> + pr_err("unable to create sysfs file, error: %d\n", error);
> + goto out_remove_new;
> + }
> +
> + error = parport_register_driver(&pata_parport_driver);
> + if (error) {
> + pr_err("unable to register parport driver, error: %d\n", error);
> + goto out_remove_del;
> + }
> +
> + return 0;
> +
> +out_remove_del:
> + bus_remove_file(&pata_parport_bus_type, &bus_attr_delete_device);
> +out_remove_new:
> + bus_remove_file(&pata_parport_bus_type, &bus_attr_new_device);
> +out_unregister_dev:
> + device_unregister(&pata_parport_bus);
> +out_unregister_bus:
> + bus_unregister(&pata_parport_bus_type);
> + return error;
> +}
> +
> +static __exit void pata_parport_exit(void)
> +{
> + parport_unregister_driver(&pata_parport_driver);
> + bus_remove_file(&pata_parport_bus_type, &bus_attr_new_device);
> + bus_remove_file(&pata_parport_bus_type, &bus_attr_delete_device);
> + device_unregister(&pata_parport_bus);
> + bus_unregister(&pata_parport_bus_type);
> +}
> +
> +MODULE_AUTHOR("Ondrej Zary");
> +MODULE_DESCRIPTION("driver for parallel port ATA adapters");
> +MODULE_LICENSE("GPL");
> +MODULE_ALIAS("paride");
> +
> +module_init(pata_parport_init);
> +module_exit(pata_parport_exit);
> diff --git a/drivers/block/paride/Kconfig b/drivers/block/paride/Kconfig
> index a295634597ba..01e4ef3655c1 100644
> --- a/drivers/block/paride/Kconfig
> +++ b/drivers/block/paride/Kconfig
> @@ -92,11 +92,11 @@ config PARIDE_PG
> later fully support this driver.
>
> comment "Parallel IDE protocol modules"
> - depends on PARIDE
> + depends on PARIDE || PATA_PARPORT
>
> config PARIDE_ATEN
> tristate "ATEN EH-100 protocol"
> - depends on PARIDE
> + depends on PARIDE || PATA_PARPORT
> help
> This option enables support for the ATEN EH-100 parallel port IDE
> protocol. This protocol is used in some inexpensive low performance
> @@ -109,7 +109,7 @@ config PARIDE_ATEN
>
> config PARIDE_BPCK
> tristate "MicroSolutions backpack (Series 5) protocol"
> - depends on PARIDE
> + depends on PARIDE || PATA_PARPORT
> help
> This option enables support for the Micro Solutions BACKPACK
> parallel port Series 5 IDE protocol. (Most BACKPACK drives made
> @@ -127,7 +127,7 @@ config PARIDE_BPCK
>
> config PARIDE_BPCK6
> tristate "MicroSolutions backpack (Series 6) protocol"
> - depends on PARIDE && !64BIT
> + depends on (PARIDE || PATA_PARPORT) && !64BIT
> help
> This option enables support for the Micro Solutions BACKPACK
> parallel port Series 6 IDE protocol. (Most BACKPACK drives made
> @@ -146,7 +146,7 @@ config PARIDE_BPCK6
>
> config PARIDE_COMM
> tristate "DataStor Commuter protocol"
> - depends on PARIDE
> + depends on PARIDE || PATA_PARPORT
> help
> This option enables support for the Commuter parallel port IDE
> protocol from DataStor. If you chose to build PARIDE support
> @@ -157,7 +157,7 @@ config PARIDE_COMM
>
> config PARIDE_DSTR
> tristate "DataStor EP-2000 protocol"
> - depends on PARIDE
> + depends on PARIDE || PATA_PARPORT
> help
> This option enables support for the EP-2000 parallel port IDE
> protocol from DataStor. If you chose to build PARIDE support
> @@ -168,7 +168,7 @@ config PARIDE_DSTR
>
> config PARIDE_FIT2
> tristate "FIT TD-2000 protocol"
> - depends on PARIDE
> + depends on PARIDE || PATA_PARPORT
> help
> This option enables support for the TD-2000 parallel port IDE
> protocol from Fidelity International Technology. This is a simple
> @@ -181,7 +181,7 @@ config PARIDE_FIT2
>
> config PARIDE_FIT3
> tristate "FIT TD-3000 protocol"
> - depends on PARIDE
> + depends on PARIDE || PATA_PARPORT
> help
> This option enables support for the TD-3000 parallel port IDE
> protocol from Fidelity International Technology. This protocol is
> @@ -194,7 +194,7 @@ config PARIDE_FIT3
>
> config PARIDE_EPAT
> tristate "Shuttle EPAT/EPEZ protocol"
> - depends on PARIDE
> + depends on PARIDE || PATA_PARPORT
> help
> This option enables support for the EPAT parallel port IDE protocol.
> EPAT is a parallel port IDE adapter manufactured by Shuttle
> @@ -216,7 +216,7 @@ config PARIDE_EPATC8
>
> config PARIDE_EPIA
> tristate "Shuttle EPIA protocol"
> - depends on PARIDE
> + depends on PARIDE || PATA_PARPORT
> help
> This option enables support for the (obsolete) EPIA parallel port
> IDE protocol from Shuttle Technology. This adapter can still be
> @@ -228,7 +228,7 @@ config PARIDE_EPIA
>
> config PARIDE_FRIQ
> tristate "Freecom IQ ASIC-2 protocol"
> - depends on PARIDE
> + depends on PARIDE || PATA_PARPORT
> help
> This option enables support for version 2 of the Freecom IQ parallel
> port IDE adapter. This adapter is used by the Maxell Superdisk
> @@ -240,7 +240,7 @@ config PARIDE_FRIQ
>
> config PARIDE_FRPW
> tristate "FreeCom power protocol"
> - depends on PARIDE
> + depends on PARIDE || PATA_PARPORT
> help
> This option enables support for the Freecom power parallel port IDE
> protocol. If you chose to build PARIDE support into your kernel, you
> @@ -251,7 +251,7 @@ config PARIDE_FRPW
>
> config PARIDE_KBIC
> tristate "KingByte KBIC-951A/971A protocols"
> - depends on PARIDE
> + depends on PARIDE || PATA_PARPORT
> help
> This option enables support for the KBIC-951A and KBIC-971A parallel
> port IDE protocols from KingByte Information Corp. KingByte's
> @@ -264,7 +264,7 @@ config PARIDE_KBIC
>
> config PARIDE_KTTI
> tristate "KT PHd protocol"
> - depends on PARIDE
> + depends on PARIDE || PATA_PARPORT
> help
> This option enables support for the "PHd" parallel port IDE protocol
> from KT Technology. This is a simple (low speed) adapter that is
> @@ -277,7 +277,7 @@ config PARIDE_KTTI
>
> config PARIDE_ON20
> tristate "OnSpec 90c20 protocol"
> - depends on PARIDE
> + depends on PARIDE || PATA_PARPORT
> help
> This option enables support for the (obsolete) 90c20 parallel port
> IDE protocol from OnSpec (often marketed under the ValuStore brand
> @@ -289,7 +289,7 @@ config PARIDE_ON20
>
> config PARIDE_ON26
> tristate "OnSpec 90c26 protocol"
> - depends on PARIDE
> + depends on PARIDE || PATA_PARPORT
> help
> This option enables support for the 90c26 parallel port IDE protocol
> from OnSpec Electronics (often marketed under the ValuStore brand
> diff --git a/drivers/block/paride/paride.h b/drivers/block/paride/paride.h
> index ddb9e589da7f..24dcfadb782d 100644
> --- a/drivers/block/paride/paride.h
> +++ b/drivers/block/paride/paride.h
> @@ -1,3 +1,15 @@
> +/*
> + * The low-level protocol modules are used by either paride or pata_parport.
> + * These two are mutually exclusive because the compiled low-level protocol
> + * modules are not compatible.
> + * When PATA_PARPORT is enabled, include pata_parport.h instead of the rest
> + * of this file.
> + */
> +
> +#if IS_ENABLED(CONFIG_PATA_PARPORT)
> +#include <linux/pata_parport.h>
> +
> +#else
> #ifndef __DRIVERS_PARIDE_H__
> #define __DRIVERS_PARIDE_H__
>
> @@ -170,3 +182,4 @@ void pi_unregister_driver(void *);
>
> #endif /* __DRIVERS_PARIDE_H__ */
> /* end of paride.h */
> +#endif /* IS_ENABLED(CONFIG_PATA_PARPORT) */
> diff --git a/include/linux/pata_parport.h b/include/linux/pata_parport.h
> new file mode 100644
> index 000000000000..58781846f282
> --- /dev/null
> +++ b/include/linux/pata_parport.h
> @@ -0,0 +1,111 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * pata_parport.h (c) 1997-8 Grant R. Guenther <[email protected]>
> + * Under the terms of the GPL.
> + *
> + * This file defines the interface for parallel port IDE adapter chip drivers.
> + */
> +
> +#ifndef LINUX_PATA_PARPORT_H
> +#define LINUX_PATA_PARPORT_H
> +
> +#include <linux/libata.h>
> +
> +#define PI_PCD 1 /* dummy for paride protocol modules */
> +
> +struct pi_adapter {
> + struct device dev;
> + struct pi_protocol *proto; /* adapter protocol */
> + int port; /* base address of parallel port */
> + int mode; /* transfer mode in use */
> + int delay; /* adapter delay setting */
> + int devtype; /* dummy for paride protocol modules */
> + char *device; /* dummy for paride protocol modules */
> + int unit; /* unit number for chained adapters */
> + int saved_r0; /* saved port state */
> + int saved_r2; /* saved port state */
> + unsigned long private; /* for protocol module */
> + struct pardevice *pardev; /* pointer to pardevice */
> +};
> +
> +typedef struct pi_adapter PIA; /* for paride protocol modules */
> +
> +/* registers are addressed as (cont,regr)
> + * cont: 0 for command register file, 1 for control register(s)
> + * regr: 0-7 for register number.
> + */
> +
> +/* macros and functions exported to the protocol modules */
> +#define delay_p (pi->delay ? udelay(pi->delay) : (void)0)
> +#define out_p(offs, byte) do { outb(byte, pi->port + offs); delay_p; } while (0)
> +#define in_p(offs) (delay_p, inb(pi->port + offs))
> +
> +#define w0(byte) out_p(0, byte)
> +#define r0() in_p(0)
> +#define w1(byte) out_p(1, byte)
> +#define r1() in_p(1)
> +#define w2(byte) out_p(2, byte)
> +#define r2() in_p(2)
> +#define w3(byte) out_p(3, byte)
> +#define w4(byte) out_p(4, byte)
> +#define r4() in_p(4)
> +#define w4w(data) do { outw(data, pi->port + 4); delay_p; } while (0)
> +#define w4l(data) do { outl(data, pi->port + 4); delay_p; } while (0)
> +#define r4w() (delay_p, inw(pi->port + 4))
> +#define r4l() (delay_p, inl(pi->port + 4))
> +
> +static inline u16 pi_swab16(char *b, int k)
> +{
> + union { u16 u; char t[2]; } r;
> +
> + r.t[0] = b[2 * k + 1]; r.t[1] = b[2 * k];
> + return r.u;
> +}
> +
> +static inline u32 pi_swab32(char *b, int k)
> +{
> + union { u32 u; char f[4]; } r;
> +
> + r.f[0] = b[4 * k + 1]; r.f[1] = b[4 * k];
> + r.f[2] = b[4 * k + 3]; r.f[3] = b[4 * k + 2];
> + return r.u;
> +}
> +
> +struct pi_protocol {
> + char name[8];
> +
> + int max_mode;
> + int epp_first; /* modes >= this use 8 ports */
> +
> + int default_delay;
> + int max_units; /* max chained units probed for */
> +
> + void (*write_regr)(struct pi_adapter *pi, int cont, int regr, int val);
> + int (*read_regr)(struct pi_adapter *pi, int cont, int regr);
> + void (*write_block)(struct pi_adapter *pi, char *buf, int count);
> + void (*read_block)(struct pi_adapter *pi, char *buf, int count);
> +
> + void (*connect)(struct pi_adapter *pi);
> + void (*disconnect)(struct pi_adapter *pi);
> +
> + int (*test_port)(struct pi_adapter *pi);
> + int (*probe_unit)(struct pi_adapter *pi);
> + int (*test_proto)(struct pi_adapter *pi, char *scratch, int verbose);
> + void (*log_adapter)(struct pi_adapter *pi, char *scratch, int verbose);
> +
> + int (*init_proto)(struct pi_adapter *pi);
> + void (*release_proto)(struct pi_adapter *pi);
> + struct module *owner;
> + struct device_driver driver;
> + struct scsi_host_template sht;
> +};
> +
> +#define PATA_PARPORT_SHT ATA_PIO_SHT
> +
> +int pata_parport_register_driver(struct pi_protocol *pr);
> +void pata_parport_unregister_driver(struct pi_protocol *pr);
> +/* defines for old paride protocol modules */
> +#define paride_register pata_parport_register_driver
> +#define paride_unregister pata_parport_unregister_driver
> +
> +#endif /* LINUX_PATA_PARPORT_H */

--
Damien Le Moal
Western Digital Research



2023-01-30 03:44:14

by Jens Axboe

[permalink] [raw]
Subject: Re: [PATCH v3] pata_parport: add driver (PARIDE replacement)

On 1/29/23 8:30?PM, Damien Le Moal wrote:
> On 1/24/23 04:09, Ondrej Zary wrote:
>> The pata_parport is a libata-based replacement of the old PARIDE
>> subsystem - driver for parallel port IDE devices.
>> It uses the original paride low-level protocol drivers but does not
>> need the high-level drivers (pd, pcd, pf, pt, pg). The IDE devices
>> behind parallel port adapters are handled by the ATA layer.
>>
>> This will allow paride and its high-level drivers to be removed.
>>
>> Unfortunately, libata drivers cannot sleep so pata_parport claims
>> parport before activating the ata host and keeps it claimed (and
>> protocol connected) until the ata host is removed. This means that
>> no devices can be chained (neither other pata_parport devices nor
>> a printer).
>>
>> paride and pata_parport are mutually exclusive because the compiled
>> protocol drivers are incompatible.
>>
>> Tested with:
>> - Imation SuperDisk LS-120 and HP C4381A (EPAT)
>> - Freecom Parallel CD (FRPW)
>> - Toshiba Mobile CD-RW 2793008 w/Freecom Parallel Cable rev.903 (FRIQ)
>> - Backpack CD-RW 222011 and CD-RW 19350 (BPCK6)
>>
>> The following bugs in low-level protocol drivers were found and will
>> be fixed later:
>>
>> Note: EPP-32 mode is buggy in EPAT - and also in all other protocol
>> drivers - they don't handle non-multiple-of-4 block transfers
>> correctly. This causes problems with LS-120 drive.
>> There is also another bug in EPAT: EPP modes don't work unless a 4-bit
>> or 8-bit mode is used first (probably some initialization missing?).
>> Once the device is initialized, EPP works until power cycle.
>>
>> So after device power on, you have to:
>> echo "parport0 epat 0" >/sys/bus/pata_parport/new_device
>> echo pata_parport.0 >/sys/bus/pata_parport/delete_device
>> echo "parport0 epat 4" >/sys/bus/pata_parport/new_device
>> (autoprobe will initialize correctly as it tries the slowest modes
>> first but you'll get the broken EPP-32 mode)
>>
>> Note: EPP modes are buggy in FRPW, only modes 0 and 1 work.
>> Signed-off-by: Ondrej Zary <[email protected]>
>
> Are you going to send a patch to remove the legacy parport code ?
> If we want this queued for 6.3, it is now (this week, asap) or we will
> have to delay to 6.4. Unless Jens prefers the deprecation first, which I
> think he said "better delete now".

I would prefer if we just delete it after merging this one, in the same
release. I don't think there's any point in delaying, as we're not
removing any functionality.

You could just queue that up too when adding this patch.


--
Jens Axboe


2023-01-30 06:49:21

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [PATCH v3] pata_parport: add driver (PARIDE replacement)

On Sun, Jan 29, 2023 at 08:44:06PM -0700, Jens Axboe wrote:
> I would prefer if we just delete it after merging this one, in the same
> release. I don't think there's any point in delaying, as we're not
> removing any functionality.
>
> You could just queue that up too when adding this patch.

I'd prefer to just deprecate. But most importantly I want this patch
in ASAP in some form.

2023-01-30 07:10:59

by Damien Le Moal

[permalink] [raw]
Subject: Re: [PATCH v3] pata_parport: add driver (PARIDE replacement)

On 1/30/23 15:48, Christoph Hellwig wrote:
> On Sun, Jan 29, 2023 at 08:44:06PM -0700, Jens Axboe wrote:
>> I would prefer if we just delete it after merging this one, in the same
>> release. I don't think there's any point in delaying, as we're not
>> removing any functionality.
>>
>> You could just queue that up too when adding this patch.
>
> I'd prefer to just deprecate. But most importantly I want this patch
> in ASAP in some form.

I will queue it. But I think it needs a follow up to result in something
consistent with KConfig. So either deprecate or delete PARPORT. I can queue the
deprecate patch and delete in 6.4, even though I share Jen's opinion to simply
delete directly. I am still fine either way.

Jens,

If you are OK with that, can I get your ack for the deprecate patch ? Unless you
prefer taking it through the block tree. Either way is fine with me.

--
Damien Le Moal
Western Digital Research


2023-01-30 15:24:25

by Jens Axboe

[permalink] [raw]
Subject: Re: [PATCH v3] pata_parport: add driver (PARIDE replacement)

On 1/29/23 11:48 PM, Christoph Hellwig wrote:
> On Sun, Jan 29, 2023 at 08:44:06PM -0700, Jens Axboe wrote:
>> I would prefer if we just delete it after merging this one, in the same
>> release. I don't think there's any point in delaying, as we're not
>> removing any functionality.
>>
>> You could just queue that up too when adding this patch.
>
> I'd prefer to just deprecate. But most importantly I want this patch
> in ASAP in some form.

There's feature parity and probably the single user of this already
knows it... I think we're grossly overthinking this one, just kill
the old code.

--
Jens Axboe



2023-01-30 15:25:11

by Jens Axboe

[permalink] [raw]
Subject: Re: [PATCH v3] pata_parport: add driver (PARIDE replacement)

On 1/30/23 12:10 AM, Damien Le Moal wrote:
> On 1/30/23 15:48, Christoph Hellwig wrote:
>> On Sun, Jan 29, 2023 at 08:44:06PM -0700, Jens Axboe wrote:
>>> I would prefer if we just delete it after merging this one, in the same
>>> release. I don't think there's any point in delaying, as we're not
>>> removing any functionality.
>>>
>>> You could just queue that up too when adding this patch.
>>
>> I'd prefer to just deprecate. But most importantly I want this patch
>> in ASAP in some form.
>
> I will queue it. But I think it needs a follow up to result in something
> consistent with KConfig. So either deprecate or delete PARPORT. I can queue the
> deprecate patch and delete in 6.4, even though I share Jen's opinion to simply
> delete directly. I am still fine either way.
>
> Jens,
>
> If you are OK with that, can I get your ack for the deprecate patch ? Unless you
> prefer taking it through the block tree. Either way is fine with me.

Yeah I'd be happy to ack that, did you post it? You can add my ack to the
new driver, fine with that now.

--
Jens Axboe



2023-01-30 21:11:34

by Ondrej Zary

[permalink] [raw]
Subject: [PATCH 1/2] drivers/block: Remove PARIDE core and high-level protocols

Remove PARIDE core and high level protocols, taking care not to break
low-level drivers (used by pata_parport). Also update documentation.

Signed-off-by: Ondrej Zary <[email protected]>
---
Documentation/admin-guide/blockdev/paride.rst | 440 ++-----
.../admin-guide/kernel-parameters.rst | 1 -
.../admin-guide/kernel-parameters.txt | 16 -
MAINTAINERS | 7 -
drivers/ata/Kconfig | 2 +-
drivers/block/Kconfig | 27 -
drivers/block/paride/Kconfig | 121 +-
drivers/block/paride/Makefile | 6 -
drivers/block/paride/Transition-notes | 128 --
drivers/block/paride/aten.c | 2 +-
drivers/block/paride/bpck.c | 2 +-
drivers/block/paride/bpck6.c | 2 +-
drivers/block/paride/comm.c | 2 +-
drivers/block/paride/dstr.c | 2 +-
drivers/block/paride/epat.c | 2 +-
drivers/block/paride/epia.c | 2 +-
drivers/block/paride/fit2.c | 2 +-
drivers/block/paride/fit3.c | 2 +-
drivers/block/paride/friq.c | 2 +-
drivers/block/paride/frpw.c | 2 +-
drivers/block/paride/kbic.c | 2 +-
drivers/block/paride/ktti.c | 2 +-
drivers/block/paride/mkd | 31 -
drivers/block/paride/on20.c | 2 +-
drivers/block/paride/on26.c | 2 +-
drivers/block/paride/paride.c | 479 --------
drivers/block/paride/paride.h | 185 ---
drivers/block/paride/pcd.c | 1042 ----------------
drivers/block/paride/pd.c | 1032 ----------------
drivers/block/paride/pf.c | 1057 -----------------
drivers/block/paride/pg.c | 734 ------------
drivers/block/paride/pseudo.h | 102 --
drivers/block/paride/pt.c | 1024 ----------------
33 files changed, 110 insertions(+), 6354 deletions(-)
delete mode 100644 drivers/block/paride/Transition-notes
delete mode 100644 drivers/block/paride/mkd
delete mode 100644 drivers/block/paride/paride.c
delete mode 100644 drivers/block/paride/paride.h
delete mode 100644 drivers/block/paride/pcd.c
delete mode 100644 drivers/block/paride/pd.c
delete mode 100644 drivers/block/paride/pf.c
delete mode 100644 drivers/block/paride/pg.c
delete mode 100644 drivers/block/paride/pseudo.h
delete mode 100644 drivers/block/paride/pt.c

diff --git a/Documentation/admin-guide/blockdev/paride.rst b/Documentation/admin-guide/blockdev/paride.rst
index e431a1ef41eb..e85ad37cc0e5 100644
--- a/Documentation/admin-guide/blockdev/paride.rst
+++ b/Documentation/admin-guide/blockdev/paride.rst
@@ -2,10 +2,8 @@
Linux and parallel port IDE devices
===================================

-Most of this document describes the old paride driver. For the new libata
-pata_parport drivrer, jump to the section 4 at the end.
-
PARIDE v1.03 (c) 1997-8 Grant Guenther <[email protected]>
+PATA_PARPORT (c) 2023 Ondrej Zary

1. Introduction
===============
@@ -54,27 +52,15 @@ parallel port IDE subsystem, including:

as well as most of the clone and no-name products on the market.

-To support such a wide range of devices, PARIDE, the parallel port IDE
-subsystem, is actually structured in three parts. There is a base
-paride module which provides a registry and some common methods for
-accessing the parallel ports. The second component is a set of
-high-level drivers for each of the different types of supported devices:
-
- === =============
- pd IDE disk
- pcd ATAPI CD-ROM
- pf ATAPI disk
- pt ATAPI tape
- pg ATAPI generic
- === =============
-
-(Currently, the pg driver is only used with CD-R drives).
+To support such a wide range of devices, pata_parport is actually structured
+in two parts. There is a base pata_parport module which provides an interface
+to kernel libata subsystem, registry and some common methods for accessing
+the parallel ports.

-The high-level drivers function according to the relevant standards.
-The third component of PARIDE is a set of low-level protocol drivers
-for each of the parallel port IDE adapter chips. Thanks to the interest
-and encouragement of Linux users from many parts of the world,
-support is available for almost all known adapter protocols:
+The second component is a set of low-level protocol drivers for each of the
+parallel port IDE adapter chips. Thanks to the interest and encouragement of
+Linux users from many parts of the world, support is available for almost all
+known adapter protocols:

==== ====================================== ====
aten ATEN EH-100 (HK)
@@ -94,251 +80,87 @@ support is available for almost all known adapter protocols:
==== ====================================== ====


-2. Using the PARIDE subsystem
-=============================
+2. Using pata_parport subsystem
+===============================

While configuring the Linux kernel, you may choose either to build
-the PARIDE drivers into your kernel, or to build them as modules.
+the pata_parport drivers into your kernel, or to build them as modules.

In either case, you will need to select "Parallel port IDE device support"
-as well as at least one of the high-level drivers and at least one
-of the parallel port communication protocols. If you do not know
-what kind of parallel port adapter is used in your drive, you could
-begin by checking the file names and any text files on your DOS
+and at least one of the parallel port communication protocols.
+If you do not know what kind of parallel port adapter is used in your drive,
+you could begin by checking the file names and any text files on your DOS
installation floppy. Alternatively, you can look at the markings on
the adapter chip itself. That's usually sufficient to identify the
correct device.

-You can actually select all the protocol modules, and allow the PARIDE
+You can actually select all the protocol modules, and allow the pata_parport
subsystem to try them all for you.

For the "brand-name" products listed above, here are the protocol
and high-level drivers that you would use:

- ================ ============ ====== ========
- Manufacturer Model Driver Protocol
- ================ ============ ====== ========
- MicroSolutions CD-ROM pcd bpck
- MicroSolutions PD drive pf bpck
- MicroSolutions hard-drive pd bpck
- MicroSolutions 8000t tape pt bpck
- SyQuest EZ, SparQ pd epat
- Imation Superdisk pf epat
- Maxell Superdisk pf friq
- Avatar Shark pd epat
- FreeCom CD-ROM pcd frpw
- Hewlett-Packard 5GB Tape pt epat
- Hewlett-Packard 7200e (CD) pcd epat
- Hewlett-Packard 7200e (CD-R) pg epat
- ================ ============ ====== ========
-
-2.1 Configuring built-in drivers
----------------------------------
-
-We recommend that you get to know how the drivers work and how to
-configure them as loadable modules, before attempting to compile a
-kernel with the drivers built-in.
-
-If you built all of your PARIDE support directly into your kernel,
-and you have just a single parallel port IDE device, your kernel should
-locate it automatically for you. If you have more than one device,
-you may need to give some command line options to your bootloader
-(eg: LILO), how to do that is beyond the scope of this document.
-
-The high-level drivers accept a number of command line parameters, all
-of which are documented in the source files in linux/drivers/block/paride.
-By default, each driver will automatically try all parallel ports it
-can find, and all protocol types that have been installed, until it finds
-a parallel port IDE adapter. Once it finds one, the probe stops. So,
-if you have more than one device, you will need to tell the drivers
-how to identify them. This requires specifying the port address, the
-protocol identification number and, for some devices, the drive's
-chain ID. While your system is booting, a number of messages are
-displayed on the console. Like all such messages, they can be
-reviewed with the 'dmesg' command. Among those messages will be
-some lines like::
-
- paride: bpck registered as protocol 0
- paride: epat registered as protocol 1
-
-The numbers will always be the same until you build a new kernel with
-different protocol selections. You should note these numbers as you
-will need them to identify the devices.
+ ================ ============ ========
+ Manufacturer Model Protocol
+ ================ ============ ========
+ MicroSolutions CD-ROM bpck
+ MicroSolutions PD drive bpck
+ MicroSolutions hard-drive bpck
+ MicroSolutions 8000t tape bpck
+ SyQuest EZ, SparQ epat
+ Imation Superdisk epat
+ Maxell Superdisk friq
+ Avatar Shark epat
+ FreeCom CD-ROM frpw
+ Hewlett-Packard 5GB Tape epat
+ Hewlett-Packard 7200e (CD) epat
+ Hewlett-Packard 7200e (CD-R) epat
+ ================ ============ ========
+
+All parports and all protocol drivers are probed automatically unless probe=0
+parameter is used. So just "modprobe epat" is enough for a Imation SuperDisk
+drive to work.
+
+Manual device creation::
+
+ # echo "port protocol mode unit delay" >/sys/bus/pata_parport/new_device
+
+where:
+
+ ======== ================================================
+ port parport name (or "auto" for all parports)
+ protocol protocol name (or "auto" for all protocols)
+ mode mode number (protocol-specific) or -1 for probe
+ unit unit number (for backpack only, see below)
+ delay I/O delay (see troubleshooting section below)
+ ======== ================================================

If you happen to be using a MicroSolutions backpack device, you will
also need to know the unit ID number for each drive. This is usually
the last two digits of the drive's serial number (but read MicroSolutions'
documentation about this).

-As an example, let's assume that you have a MicroSolutions PD/CD drive
-with unit ID number 36 connected to the parallel port at 0x378, a SyQuest
-EZ-135 connected to the chained port on the PD/CD drive and also an
-Imation Superdisk connected to port 0x278. You could give the following
-options on your boot command::
-
- pd.drive0=0x378,1 pf.drive0=0x278,1 pf.drive1=0x378,0,36
-
-In the last option, pf.drive1 configures device /dev/pf1, the 0x378
-is the parallel port base address, the 0 is the protocol registration
-number and 36 is the chain ID.
-
-Please note: while PARIDE will work both with and without the
-PARPORT parallel port sharing system that is included by the
-"Parallel port support" option, PARPORT must be included and enabled
-if you want to use chains of devices on the same parallel port.
-
-2.2 Loading and configuring PARIDE as modules
-----------------------------------------------
-
-It is much faster and simpler to get to understand the PARIDE drivers
-if you use them as loadable kernel modules.
-
-Note 1:
- using these drivers with the "kerneld" automatic module loading
- system is not recommended for beginners, and is not documented here.
-
-Note 2:
- if you build PARPORT support as a loadable module, PARIDE must
- also be built as loadable modules, and PARPORT must be loaded before
- the PARIDE modules.
-
-To use PARIDE, you must begin by::
-
- insmod paride
-
-this loads a base module which provides a registry for the protocols,
-among other tasks.
-
-Then, load as many of the protocol modules as you think you might need.
-As you load each module, it will register the protocols that it supports,
-and print a log message to your kernel log file and your console. For
-example::
-
- # insmod epat
- paride: epat registered as protocol 0
- # insmod kbic
- paride: k951 registered as protocol 1
- paride: k971 registered as protocol 2
-
-Finally, you can load high-level drivers for each kind of device that
-you have connected. By default, each driver will autoprobe for a single
-device, but you can support up to four similar devices by giving their
-individual coordinates when you load the driver.
-
-For example, if you had two no-name CD-ROM drives both using the
-KingByte KBIC-951A adapter, one on port 0x378 and the other on 0x3bc
-you could give the following command::
-
- # insmod pcd drive0=0x378,1 drive1=0x3bc,1
-
-For most adapters, giving a port address and protocol number is sufficient,
-but check the source files in linux/drivers/block/paride for more
-information. (Hopefully someone will write some man pages one day !).
-
-As another example, here's what happens when PARPORT is installed, and
-a SyQuest EZ-135 is attached to port 0x378::
-
- # insmod paride
- paride: version 1.0 installed
- # insmod epat
- paride: epat registered as protocol 0
- # insmod pd
- pd: pd version 1.0, major 45, cluster 64, nice 0
- pda: Sharing parport1 at 0x378
- pda: epat 1.0, Shuttle EPAT chip c3 at 0x378, mode 5 (EPP-32), delay 1
- pda: SyQuest EZ135A, 262144 blocks [128M], (512/16/32), removable media
- pda: pda1
-
-Note that the last line is the output from the generic partition table
-scanner - in this case it reports that it has found a disk with one partition.
-
-2.3 Using a PARIDE device
---------------------------
-
-Once the drivers have been loaded, you can access PARIDE devices in the
-same way as their traditional counterparts. You will probably need to
-create the device "special files". Here is a simple script that you can
-cut to a file and execute::
-
- #!/bin/bash
- #
- # mkd -- a script to create the device special files for the PARIDE subsystem
- #
- function mkdev {
- mknod $1 $2 $3 $4 ; chmod 0660 $1 ; chown root:disk $1
- }
- #
- function pd {
- D=$( printf \\$( printf "x%03x" $[ $1 + 97 ] ) )
- mkdev pd$D b 45 $[ $1 * 16 ]
- for P in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
- do mkdev pd$D$P b 45 $[ $1 * 16 + $P ]
- done
- }
- #
- cd /dev
- #
- for u in 0 1 2 3 ; do pd $u ; done
- for u in 0 1 2 3 ; do mkdev pcd$u b 46 $u ; done
- for u in 0 1 2 3 ; do mkdev pf$u b 47 $u ; done
- for u in 0 1 2 3 ; do mkdev pt$u c 96 $u ; done
- for u in 0 1 2 3 ; do mkdev npt$u c 96 $[ $u + 128 ] ; done
- for u in 0 1 2 3 ; do mkdev pg$u c 97 $u ; done
- #
- # end of mkd
-
-With the device files and drivers in place, you can access PARIDE devices
-like any other Linux device. For example, to mount a CD-ROM in pcd0, use::
-
- mount /dev/pcd0 /cdrom
-
-If you have a fresh Avatar Shark cartridge, and the drive is pda, you
-might do something like::
-
- fdisk /dev/pda -- make a new partition table with
- partition 1 of type 83
-
- mke2fs /dev/pda1 -- to build the file system
-
- mkdir /shark -- make a place to mount the disk
-
- mount /dev/pda1 /shark
-
-Devices like the Imation superdisk work in the same way, except that
-they do not have a partition table. For example to make a 120MB
-floppy that you could share with a DOS system::
-
- mkdosfs /dev/pf0
- mount /dev/pf0 /mnt
-
-
-2.4 The pf driver
-------------------
-
-The pf driver is intended for use with parallel port ATAPI disk
-devices. The most common devices in this category are PD drives
-and LS-120 drives. Traditionally, media for these devices are not
-partitioned. Consequently, the pf driver does not support partitioned
-media. This may be changed in a future version of the driver.
-
-2.5 Using the pt driver
-------------------------
-
-The pt driver for parallel port ATAPI tape drives is a minimal driver.
-It does not yet support many of the standard tape ioctl operations.
-For best performance, a block size of 32KB should be used. You will
-probably want to set the parallel port delay to 0, if you can.
-
-2.6 Using the pg driver
-------------------------
-
-The pg driver can be used in conjunction with the cdrecord program
-to create CD-ROMs. Please get cdrecord version 1.6.1 or later
-from ftp://ftp.fokus.gmd.de/pub/unix/cdrecord/ . To record CD-R media
-your parallel port should ideally be set to EPP mode, and the "port delay"
-should be set to 0. With those settings it is possible to record at 2x
-speed without any buffer underruns. If you cannot get the driver to work
-in EPP mode, try to use "bidirectional" or "PS/2" mode and 1x speeds only.
+If you omit the parameters from the end, defaults will be used, e.g.:
+
+Probe all parports with all protocols::
+
+ # echo auto >/sys/bus/pata_parport/new_device
+
+Probe parport0 using protocol epat and mode 4 (EPP-16)::
+
+ # echo "parport0 epat 4" >/sys/bus/pata_parport/new_device
+
+Probe parport0 using all protocols::
+
+ # echo "parport0 auto" >/sys/bus/pata_parport/new_device
+
+Probe all parports using protoocol epat::
+
+ # echo "auto epat" >/sys/bus/pata_parport/new_device
+
+Deleting devices::
+
+ # echo pata_parport.0 >/sys/bus/pata_parport/delete_device


3. Troubleshooting
@@ -347,9 +169,9 @@ in EPP mode, try to use "bidirectional" or "PS/2" mode and 1x speeds only.
3.1 Use EPP mode if you can
----------------------------

-The most common problems that people report with the PARIDE drivers
+The most common problems that people report with the pata_parport drivers
concern the parallel port CMOS settings. At this time, none of the
-PARIDE protocol modules support ECP mode, or any ECP combination modes.
+protocol modules support ECP mode, or any ECP combination modes.
If you are able to do so, please set your parallel port into EPP mode
using your CMOS setup procedure.

@@ -357,17 +179,14 @@ using your CMOS setup procedure.
-------------------------

Some parallel ports cannot reliably transfer data at full speed. To
-offset the errors, the PARIDE protocol modules introduce a "port
+offset the errors, the protocol modules introduce a "port
delay" between each access to the i/o ports. Each protocol sets
a default value for this delay. In most cases, the user can override
the default and set it to 0 - resulting in somewhat higher transfer
rates. In some rare cases (especially with older 486 systems) the
default delays are not long enough. if you experience corrupt data
transfers, or unexpected failures, you may wish to increase the
-port delay. The delay can be programmed using the "driveN" parameters
-to each of the high-level drivers. Please see the notes above, or
-read the comments at the beginning of the driver source files in
-linux/drivers/block/paride.
+port delay.

3.3 Some drives need a printer reset
-------------------------------------
@@ -377,115 +196,12 @@ that do not always power up correctly. We have noticed this with some
drives based on OnSpec and older Freecom adapters. In these rare cases,
the adapter can often be reinitialised by issuing a "printer reset" on
the parallel port. As the reset operation is potentially disruptive in
-multiple device environments, the PARIDE drivers will not do it
+multiple device environments, the pata_parport drivers will not do it
automatically. You can however, force a printer reset by doing::

insmod lp reset=1
rmmod lp

If you have one of these marginal cases, you should probably build
-your paride drivers as modules, and arrange to do the printer reset
-before loading the PARIDE drivers.
-
-3.4 Use the verbose option and dmesg if you need help
-------------------------------------------------------
-
-While a lot of testing has gone into these drivers to make them work
-as smoothly as possible, problems will arise. If you do have problems,
-please check all the obvious things first: does the drive work in
-DOS with the manufacturer's drivers ? If that doesn't yield any useful
-clues, then please make sure that only one drive is hooked to your system,
-and that either (a) PARPORT is enabled or (b) no other device driver
-is using your parallel port (check in /proc/ioports). Then, load the
-appropriate drivers (you can load several protocol modules if you want)
-as in::
-
- # insmod paride
- # insmod epat
- # insmod bpck
- # insmod kbic
- ...
- # insmod pd verbose=1
-
-(using the correct driver for the type of device you have, of course).
-The verbose=1 parameter will cause the drivers to log a trace of their
-activity as they attempt to locate your drive.
-
-Use 'dmesg' to capture a log of all the PARIDE messages (any messages
-beginning with paride:, a protocol module's name or a driver's name) and
-include that with your bug report. You can submit a bug report in one
-of two ways. Either send it directly to the author of the PARIDE suite,
-by e-mail to [email protected], or join the linux-parport mailing list
-and post your report there.
-
-3.5 For more information or help
----------------------------------
-
-You can join the linux-parport mailing list by sending a mail message
-to:
-
- [email protected]
-
-with the single word::
-
- subscribe
-
-in the body of the mail message (not in the subject line). Please be
-sure that your mail program is correctly set up when you do this, as
-the list manager is a robot that will subscribe you using the reply
-address in your mail headers. REMOVE any anti-spam gimmicks you may
-have in your mail headers, when sending mail to the list server.
-
-You might also find some useful information on the linux-parport
-web pages (although they are not always up to date) at
-
- http://web.archive.org/web/%2E/http://www.torque.net/parport/
-
-4. pata_parport driver
-======================
-pata_parport is a libata-based driver that uses the same low-level protocol
-drivers as PARIDE but there are no high-level drivers (pd, pcd, pf, pt, pg).
-The IDE devices behind parallel port adapters are handled by the ATA layer.
-
-The device creation is also changed - no protocol numbers or parport I/O
-addresses are used.
-
-All parports and all protocol drivers are probed automatically unless probe=0
-parameter is used. So just "modprobe epat" is enough for a Imation SuperDisk
-drive to work.
-
-Manual device creation::
-
- # echo "port protocol mode unit delay" >/sys/bus/pata_parport/new_device
-
-where:
-
- ======== ================================================
- port parport name (or "auto" for all parports)
- protocol protocol name (or "auto" for all protocols)
- mode mode number (protocol-specific) or -1 for probe
- unit unit number (see the paride documentation above)
- delay I/O delay (see the paride documentation above)
- ======== ================================================
-
-If you omit the parameters from the end, defaults will be used, e.g.:
-
-Probe all parports with all protocols::
-
- # echo auto >/sys/bus/pata_parport/new_device
-
-Probe parport0 using protocol epat and mode 4 (EPP-16)::
-
- # echo "parport0 epat 4" >/sys/bus/pata_parport/new_device
-
-Probe parport0 using all protocols::
-
- # echo "parport0 auto" >/sys/bus/pata_parport/new_device
-
-Probe all parports using protoocol epat::
-
- # echo "auto epat" >/sys/bus/pata_parport/new_device
-
-Deleting devices::
-
- # echo pata_parport.0 >/sys/bus/pata_parport/delete_device
+your pata_parport drivers as modules, and arrange to do the printer reset
+before loading the pata_parport drivers.
diff --git a/Documentation/admin-guide/kernel-parameters.rst b/Documentation/admin-guide/kernel-parameters.rst
index 959f73a32712..19600c50277b 100644
--- a/Documentation/admin-guide/kernel-parameters.rst
+++ b/Documentation/admin-guide/kernel-parameters.rst
@@ -142,7 +142,6 @@ parameter is applicable::
NFS Appropriate NFS support is enabled.
OF Devicetree is enabled.
PV_OPS A paravirtualized kernel is enabled.
- PARIDE The ParIDE (parallel port IDE) subsystem is enabled.
PARISC The PA-RISC architecture is enabled.
PCI PCI bus support is enabled.
PCIE PCI Express support is enabled.
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 3d0f2de7dc03..ebd46bb2e137 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -4120,10 +4120,6 @@

pcbit= [HW,ISDN]

- pcd. [PARIDE]
- See header of drivers/block/paride/pcd.c.
- See also Documentation/admin-guide/blockdev/paride.rst.
-
pci=option[,option...] [PCI] various PCI subsystem options.

Some options herein operate on a specific device
@@ -4386,9 +4382,6 @@
for debug and development, but should not be
needed on a platform with proper driver support.

- pd. [PARIDE]
- See Documentation/admin-guide/blockdev/paride.rst.
-
pdcchassis= [PARISC,HW] Disable/Enable PDC Chassis Status codes at
boot time.
Format: { 0 | 1 }
@@ -4401,12 +4394,6 @@
allocator. This parameter is primarily for debugging
and performance comparison.

- pf. [PARIDE]
- See Documentation/admin-guide/blockdev/paride.rst.
-
- pg. [PARIDE]
- See Documentation/admin-guide/blockdev/paride.rst.
-
pirq= [SMP,APIC] Manual mp-table setup
See Documentation/x86/i386/IO-APIC.rst.

@@ -4568,9 +4555,6 @@

pstore.backend= Specify the name of the pstore backend to use

- pt. [PARIDE]
- See Documentation/admin-guide/blockdev/paride.rst.
-
pti= [X86-64] Control Page Table Isolation of user and
kernel address spaces. Disabling this feature
removes hardening, but improves performance of
diff --git a/MAINTAINERS b/MAINTAINERS
index 7f86d02cb427..d2f1546bf332 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -15844,13 +15844,6 @@ F: arch/*/include/asm/paravirt*.h
F: arch/*/kernel/paravirt*
F: include/linux/hypervisor.h

-PARIDE DRIVERS FOR PARALLEL PORT IDE DEVICES
-M: Tim Waugh <[email protected]>
-L: [email protected] (subscribers-only)
-S: Maintained
-F: Documentation/admin-guide/blockdev/paride.rst
-F: drivers/block/paride/
-
PARISC ARCHITECTURE
M: "James E.J. Bottomley" <[email protected]>
M: Helge Deller <[email protected]>
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index fb646480635c..a5a31ba34bd3 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -1164,7 +1164,7 @@ config PATA_WINBOND_VLB

config PATA_PARPORT
tristate "Parallel port IDE device support"
- depends on PARPORT_PC && PARIDE=n
+ depends on PARPORT_PC
help
There are many external CD-ROM and disk devices that connect through
your computer's parallel port. Most of them are actually IDE devices
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index a2184b428493..71c9c6e3c07a 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -103,33 +103,6 @@ config GDROM
Most users will want to say "Y" here.
You can also build this as a module which will be called gdrom.

-config PARIDE
- tristate "Parallel port IDE device support"
- depends on PARPORT_PC
- help
- There are many external CD-ROM and disk devices that connect through
- your computer's parallel port. Most of them are actually IDE devices
- using a parallel port IDE adapter. This option enables the PARIDE
- subsystem which contains drivers for many of these external drives.
- Read <file:Documentation/admin-guide/blockdev/paride.rst> for more information.
-
- If you have said Y to the "Parallel-port support" configuration
- option, you may share a single port between your printer and other
- parallel port devices. Answer Y to build PARIDE support into your
- kernel, or M if you would like to build it as a loadable module. If
- your parallel port support is in a loadable module, you must build
- PARIDE as a module. If you built PARIDE support into your kernel,
- you may still build the individual protocol modules and high-level
- drivers as loadable modules. If you build this support as a module,
- it will be called paride.
-
- To use the PARIDE support, you must say Y or M here and also to at
- least one high-level driver (e.g. "Parallel port IDE disks",
- "Parallel port ATAPI CD-ROMs", "Parallel port ATAPI disks" etc.) and
- to at least one protocol driver (e.g. "ATEN EH-100 protocol",
- "MicroSolutions backpack protocol", "DataStor Commuter protocol"
- etc.).
-
source "drivers/block/paride/Kconfig"

source "drivers/block/mtip32xx/Kconfig"
diff --git a/drivers/block/paride/Kconfig b/drivers/block/paride/Kconfig
index 01e4ef3655c1..19310be860b2 100644
--- a/drivers/block/paride/Kconfig
+++ b/drivers/block/paride/Kconfig
@@ -1,102 +1,13 @@
# SPDX-License-Identifier: GPL-2.0
#
# PARIDE configuration
-#
-# PARIDE doesn't need PARPORT, but if PARPORT is configured as a module,
-# PARIDE must also be a module.
-# PARIDE only supports PC style parports. Tough for USB or other parports...
-
-comment "Parallel IDE high-level drivers"
- depends on PARIDE
-
-config PARIDE_PD
- tristate "Parallel port IDE disks"
- depends on PARIDE
- help
- This option enables the high-level driver for IDE-type disk devices
- connected through a parallel port. If you chose to build PARIDE
- support into your kernel, you may answer Y here to build in the
- parallel port IDE driver, otherwise you should answer M to build
- it as a loadable module. The module will be called pd. You
- must also have at least one parallel port protocol driver in your
- system. Among the devices supported by this driver are the SyQuest
- EZ-135, EZ-230 and SparQ drives, the Avatar Shark and the backpack
- hard drives from MicroSolutions.
-
-config PARIDE_PCD
- tristate "Parallel port ATAPI CD-ROMs"
- depends on PARIDE
- select CDROM
- help
- This option enables the high-level driver for ATAPI CD-ROM devices
- connected through a parallel port. If you chose to build PARIDE
- support into your kernel, you may answer Y here to build in the
- parallel port ATAPI CD-ROM driver, otherwise you should answer M to
- build it as a loadable module. The module will be called pcd. You
- must also have at least one parallel port protocol driver in your
- system. Among the devices supported by this driver are the
- MicroSolutions backpack CD-ROM drives and the Freecom Power CD. If
- you have such a CD-ROM drive, you should also say Y or M to "ISO
- 9660 CD-ROM file system support" below, because that's the file
- system used on CD-ROMs.
-
-config PARIDE_PF
- tristate "Parallel port ATAPI disks"
- depends on PARIDE
- help
- This option enables the high-level driver for ATAPI disk devices
- connected through a parallel port. If you chose to build PARIDE
- support into your kernel, you may answer Y here to build in the
- parallel port ATAPI disk driver, otherwise you should answer M
- to build it as a loadable module. The module will be called pf.
- You must also have at least one parallel port protocol driver in
- your system. Among the devices supported by this driver are the
- MicroSolutions backpack PD/CD drive and the Imation Superdisk
- LS-120 drive.
-
-config PARIDE_PT
- tristate "Parallel port ATAPI tapes"
- depends on PARIDE
- help
- This option enables the high-level driver for ATAPI tape devices
- connected through a parallel port. If you chose to build PARIDE
- support into your kernel, you may answer Y here to build in the
- parallel port ATAPI disk driver, otherwise you should answer M
- to build it as a loadable module. The module will be called pt.
- You must also have at least one parallel port protocol driver in
- your system. Among the devices supported by this driver is the
- parallel port version of the HP 5GB drive.
-
-config PARIDE_PG
- tristate "Parallel port generic ATAPI devices"
- depends on PARIDE
- help
- This option enables a special high-level driver for generic ATAPI
- devices connected through a parallel port. The driver allows user
- programs, such as cdrtools, to send ATAPI commands directly to a
- device.
-
- If you chose to build PARIDE support into your kernel, you may
- answer Y here to build in the parallel port generic ATAPI driver,
- otherwise you should answer M to build it as a loadable module. The
- module will be called pg.
-
- You must also have at least one parallel port protocol driver in
- your system.
-
- This driver implements an API loosely related to the generic SCSI
- driver. See <file:include/linux/pg.h>. for details.
-
- You can obtain the most recent version of cdrtools from
- <ftp://ftp.berlios.de/pub/cdrecord/>. Versions 1.6.1a3 and
- later fully support this driver.

comment "Parallel IDE protocol modules"
- depends on PARIDE || PATA_PARPORT
+ depends on PATA_PARPORT

config PARIDE_ATEN
tristate "ATEN EH-100 protocol"
- depends on PARIDE || PATA_PARPORT
+ depends on PATA_PARPORT
help
This option enables support for the ATEN EH-100 parallel port IDE
protocol. This protocol is used in some inexpensive low performance
@@ -109,7 +20,7 @@ config PARIDE_ATEN

config PARIDE_BPCK
tristate "MicroSolutions backpack (Series 5) protocol"
- depends on PARIDE || PATA_PARPORT
+ depends on PATA_PARPORT
help
This option enables support for the Micro Solutions BACKPACK
parallel port Series 5 IDE protocol. (Most BACKPACK drives made
@@ -127,7 +38,7 @@ config PARIDE_BPCK

config PARIDE_BPCK6
tristate "MicroSolutions backpack (Series 6) protocol"
- depends on (PARIDE || PATA_PARPORT) && !64BIT
+ depends on (PATA_PARPORT) && !64BIT
help
This option enables support for the Micro Solutions BACKPACK
parallel port Series 6 IDE protocol. (Most BACKPACK drives made
@@ -146,7 +57,7 @@ config PARIDE_BPCK6

config PARIDE_COMM
tristate "DataStor Commuter protocol"
- depends on PARIDE || PATA_PARPORT
+ depends on PATA_PARPORT
help
This option enables support for the Commuter parallel port IDE
protocol from DataStor. If you chose to build PARIDE support
@@ -157,7 +68,7 @@ config PARIDE_COMM

config PARIDE_DSTR
tristate "DataStor EP-2000 protocol"
- depends on PARIDE || PATA_PARPORT
+ depends on PATA_PARPORT
help
This option enables support for the EP-2000 parallel port IDE
protocol from DataStor. If you chose to build PARIDE support
@@ -168,7 +79,7 @@ config PARIDE_DSTR

config PARIDE_FIT2
tristate "FIT TD-2000 protocol"
- depends on PARIDE || PATA_PARPORT
+ depends on PATA_PARPORT
help
This option enables support for the TD-2000 parallel port IDE
protocol from Fidelity International Technology. This is a simple
@@ -181,7 +92,7 @@ config PARIDE_FIT2

config PARIDE_FIT3
tristate "FIT TD-3000 protocol"
- depends on PARIDE || PATA_PARPORT
+ depends on PATA_PARPORT
help
This option enables support for the TD-3000 parallel port IDE
protocol from Fidelity International Technology. This protocol is
@@ -194,7 +105,7 @@ config PARIDE_FIT3

config PARIDE_EPAT
tristate "Shuttle EPAT/EPEZ protocol"
- depends on PARIDE || PATA_PARPORT
+ depends on PATA_PARPORT
help
This option enables support for the EPAT parallel port IDE protocol.
EPAT is a parallel port IDE adapter manufactured by Shuttle
@@ -216,7 +127,7 @@ config PARIDE_EPATC8

config PARIDE_EPIA
tristate "Shuttle EPIA protocol"
- depends on PARIDE || PATA_PARPORT
+ depends on PATA_PARPORT
help
This option enables support for the (obsolete) EPIA parallel port
IDE protocol from Shuttle Technology. This adapter can still be
@@ -228,7 +139,7 @@ config PARIDE_EPIA

config PARIDE_FRIQ
tristate "Freecom IQ ASIC-2 protocol"
- depends on PARIDE || PATA_PARPORT
+ depends on PATA_PARPORT
help
This option enables support for version 2 of the Freecom IQ parallel
port IDE adapter. This adapter is used by the Maxell Superdisk
@@ -240,7 +151,7 @@ config PARIDE_FRIQ

config PARIDE_FRPW
tristate "FreeCom power protocol"
- depends on PARIDE || PATA_PARPORT
+ depends on PATA_PARPORT
help
This option enables support for the Freecom power parallel port IDE
protocol. If you chose to build PARIDE support into your kernel, you
@@ -251,7 +162,7 @@ config PARIDE_FRPW

config PARIDE_KBIC
tristate "KingByte KBIC-951A/971A protocols"
- depends on PARIDE || PATA_PARPORT
+ depends on PATA_PARPORT
help
This option enables support for the KBIC-951A and KBIC-971A parallel
port IDE protocols from KingByte Information Corp. KingByte's
@@ -264,7 +175,7 @@ config PARIDE_KBIC

config PARIDE_KTTI
tristate "KT PHd protocol"
- depends on PARIDE || PATA_PARPORT
+ depends on PATA_PARPORT
help
This option enables support for the "PHd" parallel port IDE protocol
from KT Technology. This is a simple (low speed) adapter that is
@@ -277,7 +188,7 @@ config PARIDE_KTTI

config PARIDE_ON20
tristate "OnSpec 90c20 protocol"
- depends on PARIDE || PATA_PARPORT
+ depends on PATA_PARPORT
help
This option enables support for the (obsolete) 90c20 parallel port
IDE protocol from OnSpec (often marketed under the ValuStore brand
@@ -289,7 +200,7 @@ config PARIDE_ON20

config PARIDE_ON26
tristate "OnSpec 90c26 protocol"
- depends on PARIDE || PATA_PARPORT
+ depends on PATA_PARPORT
help
This option enables support for the 90c26 parallel port IDE protocol
from OnSpec Electronics (often marketed under the ValuStore brand
diff --git a/drivers/block/paride/Makefile b/drivers/block/paride/Makefile
index cf1742a8475e..cdf54a27b0e7 100644
--- a/drivers/block/paride/Makefile
+++ b/drivers/block/paride/Makefile
@@ -6,7 +6,6 @@
# Rewritten to use lists instead of if-statements.
#

-obj-$(CONFIG_PARIDE) += paride.o
obj-$(CONFIG_PARIDE_ATEN) += aten.o
obj-$(CONFIG_PARIDE_BPCK) += bpck.o
obj-$(CONFIG_PARIDE_COMM) += comm.o
@@ -22,8 +21,3 @@ obj-$(CONFIG_PARIDE_ON20) += on20.o
obj-$(CONFIG_PARIDE_ON26) += on26.o
obj-$(CONFIG_PARIDE_KTTI) += ktti.o
obj-$(CONFIG_PARIDE_BPCK6) += bpck6.o
-obj-$(CONFIG_PARIDE_PD) += pd.o
-obj-$(CONFIG_PARIDE_PCD) += pcd.o
-obj-$(CONFIG_PARIDE_PF) += pf.o
-obj-$(CONFIG_PARIDE_PT) += pt.o
-obj-$(CONFIG_PARIDE_PG) += pg.o
diff --git a/drivers/block/paride/Transition-notes b/drivers/block/paride/Transition-notes
deleted file mode 100644
index 70374907c020..000000000000
--- a/drivers/block/paride/Transition-notes
+++ /dev/null
@@ -1,128 +0,0 @@
-Lemma 1:
- If ps_tq is scheduled, ps_tq_active is 1. ps_tq_int() can be called
- only when ps_tq_active is 1.
-Proof: All assignments to ps_tq_active and all scheduling of ps_tq happen
- under ps_spinlock. There are three places where that can happen:
- one in ps_set_intr() (A) and two in ps_tq_int() (B and C).
- Consider the sequnce of these events. A can not be preceded by
- anything except B, since it is under if (!ps_tq_active) under
- ps_spinlock. C is always preceded by B, since we can't reach it
- other than through B and we don't drop ps_spinlock between them.
- IOW, the sequence is A?(BA|BC|B)*. OTOH, number of B can not exceed
- the sum of numbers of A and C, since each call of ps_tq_int() is
- the result of ps_tq execution. Therefore, the sequence starts with
- A and each B is preceded by either A or C. Moments when we enter
- ps_tq_int() are sandwiched between {A,C} and B in that sequence,
- since at any time number of B can not exceed the number of these
- moments which, in turn, can not exceed the number of A and C.
- In other words, the sequence of events is (A or C set ps_tq_active to
- 1 and schedule ps_tq, ps_tq is executed, ps_tq_int() is entered,
- B resets ps_tq_active)*.
-
-
-consider the following area:
- * in do_pd_request1(): to calls of pi_do_claimed() and return in
- case when pd_req is NULL.
- * in next_request(): to call of do_pd_request1()
- * in do_pd_read(): to call of ps_set_intr()
- * in do_pd_read_start(): to calls of pi_do_claimed(), next_request()
-and ps_set_intr()
- * in do_pd_read_drq(): to calls of pi_do_claimed() and next_request()
- * in do_pd_write(): to call of ps_set_intr()
- * in do_pd_write_start(): to calls of pi_do_claimed(), next_request()
-and ps_set_intr()
- * in do_pd_write_done(): to calls of pi_do_claimed() and next_request()
- * in ps_set_intr(): to check for ps_tq_active and to scheduling
- ps_tq if ps_tq_active was 0.
- * in ps_tq_int(): from the moment when we get ps_spinlock() to the
- return, call of con() or scheduling ps_tq.
- * in pi_schedule_claimed() when called from pi_do_claimed() called from
- pd.c, everything until returning 1 or setting or setting ->claim_cont
- on the path that returns 0
- * in pi_do_claimed() when called from pd.c, everything until the call
- of pi_do_claimed() plus the everything until the call of cont() if
- pi_do_claimed() has returned 1.
- * in pi_wake_up() called for PIA that belongs to pd.c, everything from
- the moment when pi_spinlock has been acquired.
-
-Lemma 2:
- 1) at any time at most one thread of execution can be in that area or
- be preempted there.
- 2) When there is such a thread, pd_busy is set or pd_lock is held by
- that thread.
- 3) When there is such a thread, ps_tq_active is 0 or ps_spinlock is
- held by that thread.
- 4) When there is such a thread, all PIA belonging to pd.c have NULL
- ->claim_cont or pi_spinlock is held by thread in question.
-
-Proof: consider the first moment when the above is not true.
-
-(1) can become not true if some thread enters that area while another is there.
- a) do_pd_request1() can be called from next_request() or do_pd_request()
- In the first case the thread was already in the area. In the second,
- the thread was holding pd_lock and found pd_busy not set, which would
- mean that (2) was already not true.
- b) ps_set_intr() and pi_schedule_claimed() can be called only from the
- area.
- c) pi_do_claimed() is called by pd.c only from the area.
- d) ps_tq_int() can enter the area only when the thread is holding
- ps_spinlock and ps_tq_active is 1 (due to Lemma 1). It means that
- (3) was already not true.
- e) do_pd_{read,write}* could be called only from the area. The only
- case that needs consideration is call from pi_wake_up() and there
- we would have to be called for the PIA that got ->claimed_cont
- from pd.c. That could happen only if pi_do_claimed() had been
- called from pd.c for that PIA, which happens only for PIA belonging
- to pd.c.
- f) pi_wake_up() can enter the area only when the thread is holding
- pi_spinlock and ->claimed_cont is non-NULL for PIA belonging to
- pd.c. It means that (4) was already not true.
-
-(2) can become not true only when pd_lock is released by the thread in question.
- Indeed, pd_busy is reset only in the area and thread that resets
- it is holding pd_lock. The only place within the area where we
- release pd_lock is in pd_next_buf() (called from within the area).
- But that code does not reset pd_busy, so pd_busy would have to be
- 0 when pd_next_buf() had acquired pd_lock. If it become 0 while
- we were acquiring the lock, (1) would be already false, since
- the thread that had reset it would be in the area simulateously.
- If it was 0 before we tried to acquire pd_lock, (2) would be
- already false.
-
-For similar reasons, (3) can become not true only when ps_spinlock is released
-by the thread in question. However, all such places within the area are right
-after resetting ps_tq_active to 0.
-
-(4) is done the same way - all places where we release pi_spinlock within
-the area are either after resetting ->claimed_cont to NULL while holding
-pi_spinlock, or after not tocuhing ->claimed_cont since acquiring pi_spinlock
-also in the area. The only place where ->claimed_cont is made non-NULL is
-in the area, under pi_spinlock and we do not release it until after leaving
-the area.
-
-QED.
-
-
-Corollary 1: ps_tq_active can be killed. Indeed, the only place where we
-check its value is in ps_set_intr() and if it had been non-zero at that
-point, we would have violated either (2.1) (if it was set while ps_set_intr()
-was acquiring ps_spinlock) or (2.3) (if it was set when we started to
-acquire ps_spinlock).
-
-Corollary 2: ps_spinlock can be killed. Indeed, Lemma 1 and Lemma 2 show
-that the only possible contention is between scheduling ps_tq followed by
-immediate release of spinlock and beginning of execution of ps_tq on
-another CPU.
-
-Corollary 3: assignment to pd_busy in do_pd_read_start() and do_pd_write_start()
-can be killed. Indeed, we are not holding pd_lock and thus pd_busy is already
-1 here.
-
-Corollary 4: in ps_tq_int() uses of con can be replaced with uses of
-ps_continuation, since the latter is changed only from the area.
-We don't need to reset it to NULL, since we are guaranteed that there
-will be a call of ps_set_intr() before we look at ps_continuation again.
-We can remove the check for ps_continuation being NULL for the same
-reason - the value is guaranteed to be set by the last ps_set_intr() and
-we never pass it NULL. Assignements in the beginning of ps_set_intr()
-can be taken to callers as long as they remain within the area.
diff --git a/drivers/block/paride/aten.c b/drivers/block/paride/aten.c
index 2695465568ad..b66508bedbd0 100644
--- a/drivers/block/paride/aten.c
+++ b/drivers/block/paride/aten.c
@@ -25,7 +25,7 @@
#include <linux/types.h>
#include <asm/io.h>

-#include "paride.h"
+#include <linux/pata_parport.h>

#define j44(a,b) ((((a>>4)&0x0f)|(b&0xf0))^0x88)

diff --git a/drivers/block/paride/bpck.c b/drivers/block/paride/bpck.c
index d880a9465e9b..5fb3cf9ba11d 100644
--- a/drivers/block/paride/bpck.c
+++ b/drivers/block/paride/bpck.c
@@ -24,7 +24,7 @@
#include <linux/wait.h>
#include <asm/io.h>

-#include "paride.h"
+#include <linux/pata_parport.h>

#undef r2
#undef w2
diff --git a/drivers/block/paride/bpck6.c b/drivers/block/paride/bpck6.c
index ec64e7f5d1ce..d897e2a28efe 100644
--- a/drivers/block/paride/bpck6.c
+++ b/drivers/block/paride/bpck6.c
@@ -31,7 +31,7 @@
#include <linux/parport.h>

#include "ppc6lnx.c"
-#include "paride.h"
+#include <linux/pata_parport.h>

/* PARAMETERS */
static bool verbose; /* set this to 1 to see debugging messages and whatnot */
diff --git a/drivers/block/paride/comm.c b/drivers/block/paride/comm.c
index 9bcd35495323..1775e7ed9336 100644
--- a/drivers/block/paride/comm.c
+++ b/drivers/block/paride/comm.c
@@ -24,7 +24,7 @@
#include <linux/wait.h>
#include <asm/io.h>

-#include "paride.h"
+#include <linux/pata_parport.h>

/* mode codes: 0 nybble reads, 8-bit writes
1 8-bit reads and writes
diff --git a/drivers/block/paride/dstr.c b/drivers/block/paride/dstr.c
index accc5c777cbb..edf414d186a6 100644
--- a/drivers/block/paride/dstr.c
+++ b/drivers/block/paride/dstr.c
@@ -23,7 +23,7 @@
#include <linux/wait.h>
#include <asm/io.h>

-#include "paride.h"
+#include <linux/pata_parport.h>

/* mode codes: 0 nybble reads, 8-bit writes
1 8-bit reads and writes
diff --git a/drivers/block/paride/epat.c b/drivers/block/paride/epat.c
index 1bcdff77322e..6ce2dee7657f 100644
--- a/drivers/block/paride/epat.c
+++ b/drivers/block/paride/epat.c
@@ -26,7 +26,7 @@
#include <linux/wait.h>
#include <asm/io.h>

-#include "paride.h"
+#include <linux/pata_parport.h>

#define j44(a,b) (((a>>4)&0x0f)+(b&0xf0))
#define j53(a,b) (((a>>3)&0x1f)+((b<<4)&0xe0))
diff --git a/drivers/block/paride/epia.c b/drivers/block/paride/epia.c
index fb0e782d055e..417d5a3c7f72 100644
--- a/drivers/block/paride/epia.c
+++ b/drivers/block/paride/epia.c
@@ -27,7 +27,7 @@
#include <linux/wait.h>
#include <asm/io.h>

-#include "paride.h"
+#include <linux/pata_parport.h>

/* mode codes: 0 nybble reads on port 1, 8-bit writes
1 5/3 reads on ports 1 & 2, 8-bit writes
diff --git a/drivers/block/paride/fit2.c b/drivers/block/paride/fit2.c
index 381283753ae4..3c7a1069b026 100644
--- a/drivers/block/paride/fit2.c
+++ b/drivers/block/paride/fit2.c
@@ -23,7 +23,7 @@
#include <linux/wait.h>
#include <asm/io.h>

-#include "paride.h"
+#include <linux/pata_parport.h>

#define j44(a,b) (((a>>4)&0x0f)|(b&0xf0))

diff --git a/drivers/block/paride/fit3.c b/drivers/block/paride/fit3.c
index 275d269458eb..cd95f4f0edc2 100644
--- a/drivers/block/paride/fit3.c
+++ b/drivers/block/paride/fit3.c
@@ -27,7 +27,7 @@
#include <linux/wait.h>
#include <asm/io.h>

-#include "paride.h"
+#include <linux/pata_parport.h>

#define j44(a,b) (((a>>3)&0x0f)|((b<<1)&0xf0))

diff --git a/drivers/block/paride/friq.c b/drivers/block/paride/friq.c
index 4f2ba244689b..da1d0cb016d6 100644
--- a/drivers/block/paride/friq.c
+++ b/drivers/block/paride/friq.c
@@ -35,7 +35,7 @@
#include <linux/wait.h>
#include <asm/io.h>

-#include "paride.h"
+#include <linux/pata_parport.h>

#define CMD(x) w2(4);w0(0xff);w0(0xff);w0(0x73);w0(0x73);\
w0(0xc9);w0(0xc9);w0(0x26);w0(0x26);w0(x);w0(x);
diff --git a/drivers/block/paride/frpw.c b/drivers/block/paride/frpw.c
index c3cde364603a..7bc8fa16d5d8 100644
--- a/drivers/block/paride/frpw.c
+++ b/drivers/block/paride/frpw.c
@@ -33,7 +33,7 @@
#include <linux/wait.h>
#include <asm/io.h>

-#include "paride.h"
+#include <linux/pata_parport.h>

#define cec4 w2(0xc);w2(0xe);w2(0xe);w2(0xc);w2(4);w2(4);w2(4);
#define j44(l,h) (((l>>4)&0x0f)|(h&0xf0))
diff --git a/drivers/block/paride/kbic.c b/drivers/block/paride/kbic.c
index 35999c415ee3..f0960eb68635 100644
--- a/drivers/block/paride/kbic.c
+++ b/drivers/block/paride/kbic.c
@@ -28,7 +28,7 @@
#include <linux/wait.h>
#include <asm/io.h>

-#include "paride.h"
+#include <linux/pata_parport.h>

#define r12w() (delay_p,inw(pi->port+1)&0xffff)

diff --git a/drivers/block/paride/ktti.c b/drivers/block/paride/ktti.c
index 117ab0e8ccf0..fc4f707fed1f 100644
--- a/drivers/block/paride/ktti.c
+++ b/drivers/block/paride/ktti.c
@@ -19,7 +19,7 @@
#include <linux/wait.h>
#include <asm/io.h>

-#include "paride.h"
+#include <linux/pata_parport.h>

#define j44(a,b) (((a>>4)&0x0f)|(b&0xf0))

diff --git a/drivers/block/paride/mkd b/drivers/block/paride/mkd
deleted file mode 100644
index 6d0d802479ea..000000000000
--- a/drivers/block/paride/mkd
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/bin/bash
-# SPDX-License-Identifier: GPL-2.0
-#
-# mkd -- a script to create the device special files for the PARIDE subsystem
-#
-# block devices: pd (45), pcd (46), pf (47)
-# character devices: pt (96), pg (97)
-#
-function mkdev {
- mknod $1 $2 $3 $4 ; chmod 0660 $1 ; chown root:disk $1
-}
-#
-function pd {
- D=$( printf \\$( printf "x%03x" $[ $1 + 97 ] ) )
- mkdev pd$D b 45 $[ $1 * 16 ]
- for P in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
- do mkdev pd$D$P b 45 $[ $1 * 16 + $P ]
- done
-}
-#
-cd /dev
-#
-for u in 0 1 2 3 ; do pd $u ; done
-for u in 0 1 2 3 ; do mkdev pcd$u b 46 $u ; done
-for u in 0 1 2 3 ; do mkdev pf$u b 47 $u ; done
-for u in 0 1 2 3 ; do mkdev pt$u c 96 $u ; done
-for u in 0 1 2 3 ; do mkdev npt$u c 96 $[ $u + 128 ] ; done
-for u in 0 1 2 3 ; do mkdev pg$u c 97 $u ; done
-#
-# end of mkd
-
diff --git a/drivers/block/paride/on20.c b/drivers/block/paride/on20.c
index 0173697a1a4d..995fc41e3122 100644
--- a/drivers/block/paride/on20.c
+++ b/drivers/block/paride/on20.c
@@ -22,7 +22,7 @@
#include <linux/wait.h>
#include <asm/io.h>

-#include "paride.h"
+#include <linux/pata_parport.h>

#define op(f) w2(4);w0(f);w2(5);w2(0xd);w2(5);w2(0xd);w2(5);w2(4);
#define vl(v) w2(4);w0(v);w2(5);w2(7);w2(5);w2(4);
diff --git a/drivers/block/paride/on26.c b/drivers/block/paride/on26.c
index 95ba256921f2..35f1c481a782 100644
--- a/drivers/block/paride/on26.c
+++ b/drivers/block/paride/on26.c
@@ -26,7 +26,7 @@
#include <linux/wait.h>
#include <asm/io.h>

-#include "paride.h"
+#include <linux/pata_parport.h>

/* mode codes: 0 nybble reads, 8-bit writes
1 8-bit reads and writes
diff --git a/drivers/block/paride/paride.c b/drivers/block/paride/paride.c
deleted file mode 100644
index 0e287993b778..000000000000
--- a/drivers/block/paride/paride.c
+++ /dev/null
@@ -1,479 +0,0 @@
-/*
- paride.c (c) 1997-8 Grant R. Guenther <[email protected]>
- Under the terms of the GNU General Public License.
-
- This is the base module for the family of device drivers
- that support parallel port IDE devices.
-
-*/
-
-/* Changes:
-
- 1.01 GRG 1998.05.03 Use spinlocks
- 1.02 GRG 1998.05.05 init_proto, release_proto, ktti
- 1.03 GRG 1998.08.15 eliminate compiler warning
- 1.04 GRG 1998.11.28 added support for FRIQ
- 1.05 TMW 2000.06.06 use parport_find_number instead of
- parport_enumerate
- 1.06 TMW 2001.03.26 more sane parport-or-not resource management
-*/
-
-#define PI_VERSION "1.06"
-
-#include <linux/module.h>
-#include <linux/kmod.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/string.h>
-#include <linux/spinlock.h>
-#include <linux/wait.h>
-#include <linux/sched.h> /* TASK_* */
-#include <linux/parport.h>
-#include <linux/slab.h>
-
-#include "paride.h"
-
-MODULE_LICENSE("GPL");
-
-#define MAX_PROTOS 32
-
-static struct pi_protocol *protocols[MAX_PROTOS];
-
-static DEFINE_SPINLOCK(pi_spinlock);
-
-void pi_write_regr(PIA * pi, int cont, int regr, int val)
-{
- pi->proto->write_regr(pi, cont, regr, val);
-}
-
-EXPORT_SYMBOL(pi_write_regr);
-
-int pi_read_regr(PIA * pi, int cont, int regr)
-{
- return pi->proto->read_regr(pi, cont, regr);
-}
-
-EXPORT_SYMBOL(pi_read_regr);
-
-void pi_write_block(PIA * pi, char *buf, int count)
-{
- pi->proto->write_block(pi, buf, count);
-}
-
-EXPORT_SYMBOL(pi_write_block);
-
-void pi_read_block(PIA * pi, char *buf, int count)
-{
- pi->proto->read_block(pi, buf, count);
-}
-
-EXPORT_SYMBOL(pi_read_block);
-
-static void pi_wake_up(void *p)
-{
- PIA *pi = (PIA *) p;
- unsigned long flags;
- void (*cont) (void) = NULL;
-
- spin_lock_irqsave(&pi_spinlock, flags);
-
- if (pi->claim_cont && !parport_claim(pi->pardev)) {
- cont = pi->claim_cont;
- pi->claim_cont = NULL;
- pi->claimed = 1;
- }
-
- spin_unlock_irqrestore(&pi_spinlock, flags);
-
- wake_up(&(pi->parq));
-
- if (cont)
- cont();
-}
-
-int pi_schedule_claimed(PIA * pi, void (*cont) (void))
-{
- unsigned long flags;
-
- spin_lock_irqsave(&pi_spinlock, flags);
- if (pi->pardev && parport_claim(pi->pardev)) {
- pi->claim_cont = cont;
- spin_unlock_irqrestore(&pi_spinlock, flags);
- return 0;
- }
- pi->claimed = 1;
- spin_unlock_irqrestore(&pi_spinlock, flags);
- return 1;
-}
-EXPORT_SYMBOL(pi_schedule_claimed);
-
-void pi_do_claimed(PIA * pi, void (*cont) (void))
-{
- if (pi_schedule_claimed(pi, cont))
- cont();
-}
-
-EXPORT_SYMBOL(pi_do_claimed);
-
-static void pi_claim(PIA * pi)
-{
- if (pi->claimed)
- return;
- pi->claimed = 1;
- if (pi->pardev)
- wait_event(pi->parq,
- !parport_claim((struct pardevice *) pi->pardev));
-}
-
-static void pi_unclaim(PIA * pi)
-{
- pi->claimed = 0;
- if (pi->pardev)
- parport_release((struct pardevice *) (pi->pardev));
-}
-
-void pi_connect(PIA * pi)
-{
- pi_claim(pi);
- pi->proto->connect(pi);
-}
-
-EXPORT_SYMBOL(pi_connect);
-
-void pi_disconnect(PIA * pi)
-{
- pi->proto->disconnect(pi);
- pi_unclaim(pi);
-}
-
-EXPORT_SYMBOL(pi_disconnect);
-
-static void pi_unregister_parport(PIA * pi)
-{
- if (pi->pardev) {
- parport_unregister_device((struct pardevice *) (pi->pardev));
- pi->pardev = NULL;
- }
-}
-
-void pi_release(PIA * pi)
-{
- pi_unregister_parport(pi);
- if (pi->proto->release_proto)
- pi->proto->release_proto(pi);
- module_put(pi->proto->owner);
-}
-
-EXPORT_SYMBOL(pi_release);
-
-static int default_test_proto(PIA * pi, char *scratch, int verbose)
-{
- int j, k;
- int e[2] = { 0, 0 };
-
- pi->proto->connect(pi);
-
- for (j = 0; j < 2; j++) {
- pi_write_regr(pi, 0, 6, 0xa0 + j * 0x10);
- for (k = 0; k < 256; k++) {
- pi_write_regr(pi, 0, 2, k ^ 0xaa);
- pi_write_regr(pi, 0, 3, k ^ 0x55);
- if (pi_read_regr(pi, 0, 2) != (k ^ 0xaa))
- e[j]++;
- }
- }
- pi->proto->disconnect(pi);
-
- if (verbose)
- printk("%s: %s: port 0x%x, mode %d, test=(%d,%d)\n",
- pi->device, pi->proto->name, pi->port,
- pi->mode, e[0], e[1]);
-
- return (e[0] && e[1]); /* not here if both > 0 */
-}
-
-static int pi_test_proto(PIA * pi, char *scratch, int verbose)
-{
- int res;
-
- pi_claim(pi);
- if (pi->proto->test_proto)
- res = pi->proto->test_proto(pi, scratch, verbose);
- else
- res = default_test_proto(pi, scratch, verbose);
- pi_unclaim(pi);
-
- return res;
-}
-
-int paride_register(PIP * pr)
-{
- int k;
-
- for (k = 0; k < MAX_PROTOS; k++)
- if (protocols[k] && !strcmp(pr->name, protocols[k]->name)) {
- printk("paride: %s protocol already registered\n",
- pr->name);
- return -1;
- }
- k = 0;
- while ((k < MAX_PROTOS) && (protocols[k]))
- k++;
- if (k == MAX_PROTOS) {
- printk("paride: protocol table full\n");
- return -1;
- }
- protocols[k] = pr;
- pr->index = k;
- printk("paride: %s registered as protocol %d\n", pr->name, k);
- return 0;
-}
-
-EXPORT_SYMBOL(paride_register);
-
-void paride_unregister(PIP * pr)
-{
- if (!pr)
- return;
- if (protocols[pr->index] != pr) {
- printk("paride: %s not registered\n", pr->name);
- return;
- }
- protocols[pr->index] = NULL;
-}
-
-EXPORT_SYMBOL(paride_unregister);
-
-static int pi_register_parport(PIA *pi, int verbose, int unit)
-{
- struct parport *port;
- struct pardev_cb par_cb;
-
- port = parport_find_base(pi->port);
- if (!port)
- return 0;
- memset(&par_cb, 0, sizeof(par_cb));
- par_cb.wakeup = pi_wake_up;
- par_cb.private = (void *)pi;
- pi->pardev = parport_register_dev_model(port, pi->device, &par_cb,
- unit);
- parport_put_port(port);
- if (!pi->pardev)
- return 0;
-
- init_waitqueue_head(&pi->parq);
-
- if (verbose)
- printk("%s: 0x%x is %s\n", pi->device, pi->port, port->name);
-
- pi->parname = (char *) port->name;
-
- return 1;
-}
-
-static int pi_probe_mode(PIA * pi, int max, char *scratch, int verbose)
-{
- int best, range;
-
- if (pi->mode != -1) {
- if (pi->mode >= max)
- return 0;
- range = 3;
- if (pi->mode >= pi->proto->epp_first)
- range = 8;
- if ((range == 8) && (pi->port % 8))
- return 0;
- pi->reserved = range;
- return (!pi_test_proto(pi, scratch, verbose));
- }
- best = -1;
- for (pi->mode = 0; pi->mode < max; pi->mode++) {
- range = 3;
- if (pi->mode >= pi->proto->epp_first)
- range = 8;
- if ((range == 8) && (pi->port % 8))
- break;
- pi->reserved = range;
- if (!pi_test_proto(pi, scratch, verbose))
- best = pi->mode;
- }
- pi->mode = best;
- return (best > -1);
-}
-
-static int pi_probe_unit(PIA * pi, int unit, char *scratch, int verbose)
-{
- int max, s, e;
-
- s = unit;
- e = s + 1;
-
- if (s == -1) {
- s = 0;
- e = pi->proto->max_units;
- }
-
- if (!pi_register_parport(pi, verbose, s))
- return 0;
-
- if (pi->proto->test_port) {
- pi_claim(pi);
- max = pi->proto->test_port(pi);
- pi_unclaim(pi);
- } else
- max = pi->proto->max_mode;
-
- if (pi->proto->probe_unit) {
- pi_claim(pi);
- for (pi->unit = s; pi->unit < e; pi->unit++)
- if (pi->proto->probe_unit(pi)) {
- pi_unclaim(pi);
- if (pi_probe_mode(pi, max, scratch, verbose))
- return 1;
- pi_unregister_parport(pi);
- return 0;
- }
- pi_unclaim(pi);
- pi_unregister_parport(pi);
- return 0;
- }
-
- if (!pi_probe_mode(pi, max, scratch, verbose)) {
- pi_unregister_parport(pi);
- return 0;
- }
- return 1;
-
-}
-
-int pi_init(PIA * pi, int autoprobe, int port, int mode,
- int unit, int protocol, int delay, char *scratch,
- int devtype, int verbose, char *device)
-{
- int p, k, s, e;
- int lpts[7] = { 0x3bc, 0x378, 0x278, 0x268, 0x27c, 0x26c, 0 };
-
- s = protocol;
- e = s + 1;
-
- if (!protocols[0])
- request_module("paride_protocol");
-
- if (autoprobe) {
- s = 0;
- e = MAX_PROTOS;
- } else if ((s < 0) || (s >= MAX_PROTOS) || (port <= 0) ||
- (!protocols[s]) || (unit < 0) ||
- (unit >= protocols[s]->max_units)) {
- printk("%s: Invalid parameters\n", device);
- return 0;
- }
-
- for (p = s; p < e; p++) {
- struct pi_protocol *proto = protocols[p];
- if (!proto)
- continue;
- /* still racy */
- if (!try_module_get(proto->owner))
- continue;
- pi->proto = proto;
- pi->private = 0;
- if (proto->init_proto && proto->init_proto(pi) < 0) {
- pi->proto = NULL;
- module_put(proto->owner);
- continue;
- }
- if (delay == -1)
- pi->delay = pi->proto->default_delay;
- else
- pi->delay = delay;
- pi->devtype = devtype;
- pi->device = device;
-
- pi->parname = NULL;
- pi->pardev = NULL;
- init_waitqueue_head(&pi->parq);
- pi->claimed = 0;
- pi->claim_cont = NULL;
-
- pi->mode = mode;
- if (port != -1) {
- pi->port = port;
- if (pi_probe_unit(pi, unit, scratch, verbose))
- break;
- pi->port = 0;
- } else {
- k = 0;
- while ((pi->port = lpts[k++]))
- if (pi_probe_unit
- (pi, unit, scratch, verbose))
- break;
- if (pi->port)
- break;
- }
- if (pi->proto->release_proto)
- pi->proto->release_proto(pi);
- module_put(proto->owner);
- }
-
- if (!pi->port) {
- if (autoprobe)
- printk("%s: Autoprobe failed\n", device);
- else
- printk("%s: Adapter not found\n", device);
- return 0;
- }
-
- if (pi->parname)
- printk("%s: Sharing %s at 0x%x\n", pi->device,
- pi->parname, pi->port);
-
- pi->proto->log_adapter(pi, scratch, verbose);
-
- return 1;
-}
-
-EXPORT_SYMBOL(pi_init);
-
-static int pi_probe(struct pardevice *par_dev)
-{
- struct device_driver *drv = par_dev->dev.driver;
- int len = strlen(drv->name);
-
- if (strncmp(par_dev->name, drv->name, len))
- return -ENODEV;
-
- return 0;
-}
-
-void *pi_register_driver(char *name)
-{
- struct parport_driver *parp_drv;
- int ret;
-
- parp_drv = kzalloc(sizeof(*parp_drv), GFP_KERNEL);
- if (!parp_drv)
- return NULL;
-
- parp_drv->name = name;
- parp_drv->probe = pi_probe;
- parp_drv->devmodel = true;
-
- ret = parport_register_driver(parp_drv);
- if (ret) {
- kfree(parp_drv);
- return NULL;
- }
- return (void *)parp_drv;
-}
-EXPORT_SYMBOL(pi_register_driver);
-
-void pi_unregister_driver(void *_drv)
-{
- struct parport_driver *drv = _drv;
-
- parport_unregister_driver(drv);
- kfree(drv);
-}
-EXPORT_SYMBOL(pi_unregister_driver);
diff --git a/drivers/block/paride/paride.h b/drivers/block/paride/paride.h
deleted file mode 100644
index 24dcfadb782d..000000000000
--- a/drivers/block/paride/paride.h
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * The low-level protocol modules are used by either paride or pata_parport.
- * These two are mutually exclusive because the compiled low-level protocol
- * modules are not compatible.
- * When PATA_PARPORT is enabled, include pata_parport.h instead of the rest
- * of this file.
- */
-
-#if IS_ENABLED(CONFIG_PATA_PARPORT)
-#include <linux/pata_parport.h>
-
-#else
-#ifndef __DRIVERS_PARIDE_H__
-#define __DRIVERS_PARIDE_H__
-
-/*
- paride.h (c) 1997-8 Grant R. Guenther <[email protected]>
- Under the terms of the GPL.
-
- This file defines the interface between the high-level parallel
- IDE device drivers (pd, pf, pcd, pt) and the adapter chips.
-
-*/
-
-/* Changes:
-
- 1.01 GRG 1998.05.05 init_proto, release_proto
-*/
-
-#define PARIDE_H_VERSION "1.01"
-
-/* Some adapters need to know what kind of device they are in
-
- Values for devtype:
-*/
-
-#define PI_PD 0 /* IDE disk */
-#define PI_PCD 1 /* ATAPI CDrom */
-#define PI_PF 2 /* ATAPI disk */
-#define PI_PT 3 /* ATAPI tape */
-#define PI_PG 4 /* ATAPI generic */
-
-/* The paride module contains no state, instead the drivers allocate
- a pi_adapter data structure and pass it to paride in every operation.
-
-*/
-
-struct pi_adapter {
-
- struct pi_protocol *proto; /* adapter protocol */
- int port; /* base address of parallel port */
- int mode; /* transfer mode in use */
- int delay; /* adapter delay setting */
- int devtype; /* device type: PI_PD etc. */
- char *device; /* name of driver */
- int unit; /* unit number for chained adapters */
- int saved_r0; /* saved port state */
- int saved_r2; /* saved port state */
- int reserved; /* number of ports reserved */
- unsigned long private; /* for protocol module */
-
- wait_queue_head_t parq; /* semaphore for parport sharing */
- void *pardev; /* pointer to pardevice */
- char *parname; /* parport name */
- int claimed; /* parport has already been claimed */
- void (*claim_cont)(void); /* continuation for parport wait */
-};
-
-typedef struct pi_adapter PIA;
-
-/* functions exported by paride to the high level drivers */
-
-extern int pi_init(PIA *pi,
- int autoprobe, /* 1 to autoprobe */
- int port, /* base port address */
- int mode, /* -1 for autoprobe */
- int unit, /* unit number, if supported */
- int protocol, /* protocol to use */
- int delay, /* -1 to use adapter specific default */
- char * scratch, /* address of 512 byte buffer */
- int devtype, /* device type: PI_PD, PI_PCD, etc ... */
- int verbose, /* log verbose data while probing */
- char *device /* name of the driver */
- ); /* returns 0 on failure, 1 on success */
-
-extern void pi_release(PIA *pi);
-
-/* registers are addressed as (cont,regr)
-
- cont: 0 for command register file, 1 for control register(s)
- regr: 0-7 for register number.
-
-*/
-
-extern void pi_write_regr(PIA *pi, int cont, int regr, int val);
-
-extern int pi_read_regr(PIA *pi, int cont, int regr);
-
-extern void pi_write_block(PIA *pi, char * buf, int count);
-
-extern void pi_read_block(PIA *pi, char * buf, int count);
-
-extern void pi_connect(PIA *pi);
-
-extern void pi_disconnect(PIA *pi);
-
-extern void pi_do_claimed(PIA *pi, void (*cont)(void));
-extern int pi_schedule_claimed(PIA *pi, void (*cont)(void));
-
-/* macros and functions exported to the protocol modules */
-
-#define delay_p (pi->delay?udelay(pi->delay):(void)0)
-#define out_p(offs,byte) outb(byte,pi->port+offs); delay_p;
-#define in_p(offs) (delay_p,inb(pi->port+offs))
-
-#define w0(byte) {out_p(0,byte);}
-#define r0() (in_p(0) & 0xff)
-#define w1(byte) {out_p(1,byte);}
-#define r1() (in_p(1) & 0xff)
-#define w2(byte) {out_p(2,byte);}
-#define r2() (in_p(2) & 0xff)
-#define w3(byte) {out_p(3,byte);}
-#define w4(byte) {out_p(4,byte);}
-#define r4() (in_p(4) & 0xff)
-#define w4w(data) {outw(data,pi->port+4); delay_p;}
-#define w4l(data) {outl(data,pi->port+4); delay_p;}
-#define r4w() (delay_p,inw(pi->port+4)&0xffff)
-#define r4l() (delay_p,inl(pi->port+4)&0xffffffff)
-
-static inline u16 pi_swab16( char *b, int k)
-
-{ union { u16 u; char t[2]; } r;
-
- r.t[0]=b[2*k+1]; r.t[1]=b[2*k];
- return r.u;
-}
-
-static inline u32 pi_swab32( char *b, int k)
-
-{ union { u32 u; char f[4]; } r;
-
- r.f[0]=b[4*k+1]; r.f[1]=b[4*k];
- r.f[2]=b[4*k+3]; r.f[3]=b[4*k+2];
- return r.u;
-}
-
-struct pi_protocol {
-
- char name[8]; /* name for this protocol */
- int index; /* index into protocol table */
-
- int max_mode; /* max mode number */
- int epp_first; /* modes >= this use 8 ports */
-
- int default_delay; /* delay parameter if not specified */
- int max_units; /* max chained units probed for */
-
- void (*write_regr)(PIA *,int,int,int);
- int (*read_regr)(PIA *,int,int);
- void (*write_block)(PIA *,char *,int);
- void (*read_block)(PIA *,char *,int);
-
- void (*connect)(PIA *);
- void (*disconnect)(PIA *);
-
- int (*test_port)(PIA *);
- int (*probe_unit)(PIA *);
- int (*test_proto)(PIA *,char *,int);
- void (*log_adapter)(PIA *,char *,int);
-
- int (*init_proto)(PIA *);
- void (*release_proto)(PIA *);
- struct module *owner;
-};
-
-typedef struct pi_protocol PIP;
-
-extern int paride_register( PIP * );
-extern void paride_unregister ( PIP * );
-void *pi_register_driver(char *);
-void pi_unregister_driver(void *);
-
-#endif /* __DRIVERS_PARIDE_H__ */
-/* end of paride.h */
-#endif /* IS_ENABLED(CONFIG_PATA_PARPORT) */
diff --git a/drivers/block/paride/pcd.c b/drivers/block/paride/pcd.c
deleted file mode 100644
index a5ab40784119..000000000000
--- a/drivers/block/paride/pcd.c
+++ /dev/null
@@ -1,1042 +0,0 @@
-/*
- pcd.c (c) 1997-8 Grant R. Guenther <[email protected]>
- Under the terms of the GNU General Public License.
-
- This is a high-level driver for parallel port ATAPI CD-ROM
- drives based on chips supported by the paride module.
-
- By default, the driver will autoprobe for a single parallel
- port ATAPI CD-ROM drive, but if their individual parameters are
- specified, the driver can handle up to 4 drives.
-
- The behaviour of the pcd driver can be altered by setting
- some parameters from the insmod command line. The following
- parameters are adjustable:
-
- drive0 These four arguments can be arrays of
- drive1 1-6 integers as follows:
- drive2
- drive3 <prt>,<pro>,<uni>,<mod>,<slv>,<dly>
-
- Where,
-
- <prt> is the base of the parallel port address for
- the corresponding drive. (required)
-
- <pro> is the protocol number for the adapter that
- supports this drive. These numbers are
- logged by 'paride' when the protocol modules
- are initialised. (0 if not given)
-
- <uni> for those adapters that support chained
- devices, this is the unit selector for the
- chain of devices on the given port. It should
- be zero for devices that don't support chaining.
- (0 if not given)
-
- <mod> this can be -1 to choose the best mode, or one
- of the mode numbers supported by the adapter.
- (-1 if not given)
-
- <slv> ATAPI CD-ROMs can be jumpered to master or slave.
- Set this to 0 to choose the master drive, 1 to
- choose the slave, -1 (the default) to choose the
- first drive found.
-
- <dly> some parallel ports require the driver to
- go more slowly. -1 sets a default value that
- should work with the chosen protocol. Otherwise,
- set this to a small integer, the larger it is
- the slower the port i/o. In some cases, setting
- this to zero will speed up the device. (default -1)
-
- major You may use this parameter to override the
- default major number (46) that this driver
- will use. Be sure to change the device
- name as well.
-
- name This parameter is a character string that
- contains the name the kernel will use for this
- device (in /proc output, for instance).
- (default "pcd")
-
- verbose This parameter controls the amount of logging
- that the driver will do. Set it to 0 for
- normal operation, 1 to see autoprobe progress
- messages, or 2 to see additional debugging
- output. (default 0)
-
- nice This parameter controls the driver's use of
- idle CPU time, at the expense of some speed.
-
- If this driver is built into the kernel, you can use the
- following kernel command line parameters, with the same values
- as the corresponding module parameters listed above:
-
- pcd.drive0
- pcd.drive1
- pcd.drive2
- pcd.drive3
- pcd.nice
-
- In addition, you can use the parameter pcd.disable to disable
- the driver entirely.
-
-*/
-
-/* Changes:
-
- 1.01 GRG 1998.01.24 Added test unit ready support
- 1.02 GRG 1998.05.06 Changes to pcd_completion, ready_wait,
- and loosen interpretation of ATAPI
- standard for clearing error status.
- Use spinlocks. Eliminate sti().
- 1.03 GRG 1998.06.16 Eliminated an Ugh
- 1.04 GRG 1998.08.15 Added extra debugging, improvements to
- pcd_completion, use HZ in loop timing
- 1.05 GRG 1998.08.16 Conformed to "Uniform CD-ROM" standard
- 1.06 GRG 1998.08.19 Added audio ioctl support
- 1.07 GRG 1998.09.24 Increased reset timeout, added jumbo support
-
-*/
-
-#define PCD_VERSION "1.07"
-#define PCD_MAJOR 46
-#define PCD_NAME "pcd"
-#define PCD_UNITS 4
-
-/* Here are things one can override from the insmod command.
- Most are autoprobed by paride unless set here. Verbose is off
- by default.
-
-*/
-
-static int verbose = 0;
-static int major = PCD_MAJOR;
-static char *name = PCD_NAME;
-static int nice = 0;
-static int disable = 0;
-
-static int drive0[6] = { 0, 0, 0, -1, -1, -1 };
-static int drive1[6] = { 0, 0, 0, -1, -1, -1 };
-static int drive2[6] = { 0, 0, 0, -1, -1, -1 };
-static int drive3[6] = { 0, 0, 0, -1, -1, -1 };
-
-static int (*drives[4])[6] = {&drive0, &drive1, &drive2, &drive3};
-static int pcd_drive_count;
-
-enum {D_PRT, D_PRO, D_UNI, D_MOD, D_SLV, D_DLY};
-
-/* end of parameters */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/cdrom.h>
-#include <linux/spinlock.h>
-#include <linux/blk-mq.h>
-#include <linux/mutex.h>
-#include <linux/uaccess.h>
-
-static DEFINE_MUTEX(pcd_mutex);
-static DEFINE_SPINLOCK(pcd_lock);
-
-module_param(verbose, int, 0644);
-module_param(major, int, 0);
-module_param(name, charp, 0);
-module_param(nice, int, 0);
-module_param_array(drive0, int, NULL, 0);
-module_param_array(drive1, int, NULL, 0);
-module_param_array(drive2, int, NULL, 0);
-module_param_array(drive3, int, NULL, 0);
-
-#include "paride.h"
-#include "pseudo.h"
-
-#define PCD_RETRIES 5
-#define PCD_TMO 800 /* timeout in jiffies */
-#define PCD_DELAY 50 /* spin delay in uS */
-#define PCD_READY_TMO 20 /* in seconds */
-#define PCD_RESET_TMO 100 /* in tenths of a second */
-
-#define PCD_SPIN (1000000*PCD_TMO)/(HZ*PCD_DELAY)
-
-#define IDE_ERR 0x01
-#define IDE_DRQ 0x08
-#define IDE_READY 0x40
-#define IDE_BUSY 0x80
-
-static int pcd_open(struct cdrom_device_info *cdi, int purpose);
-static void pcd_release(struct cdrom_device_info *cdi);
-static int pcd_drive_status(struct cdrom_device_info *cdi, int slot_nr);
-static unsigned int pcd_check_events(struct cdrom_device_info *cdi,
- unsigned int clearing, int slot_nr);
-static int pcd_tray_move(struct cdrom_device_info *cdi, int position);
-static int pcd_lock_door(struct cdrom_device_info *cdi, int lock);
-static int pcd_drive_reset(struct cdrom_device_info *cdi);
-static int pcd_get_mcn(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn);
-static int pcd_audio_ioctl(struct cdrom_device_info *cdi,
- unsigned int cmd, void *arg);
-static int pcd_packet(struct cdrom_device_info *cdi,
- struct packet_command *cgc);
-
-static void do_pcd_read_drq(void);
-static blk_status_t pcd_queue_rq(struct blk_mq_hw_ctx *hctx,
- const struct blk_mq_queue_data *bd);
-static void do_pcd_read(void);
-
-struct pcd_unit {
- struct pi_adapter pia; /* interface to paride layer */
- struct pi_adapter *pi;
- int drive; /* master/slave */
- int last_sense; /* result of last request sense */
- int changed; /* media change seen */
- int present; /* does this unit exist ? */
- char *name; /* pcd0, pcd1, etc */
- struct cdrom_device_info info; /* uniform cdrom interface */
- struct gendisk *disk;
- struct blk_mq_tag_set tag_set;
- struct list_head rq_list;
-};
-
-static struct pcd_unit pcd[PCD_UNITS];
-
-static char pcd_scratch[64];
-static char pcd_buffer[2048]; /* raw block buffer */
-static int pcd_bufblk = -1; /* block in buffer, in CD units,
- -1 for nothing there. See also
- pd_unit.
- */
-
-/* the variables below are used mainly in the I/O request engine, which
- processes only one request at a time.
-*/
-
-static struct pcd_unit *pcd_current; /* current request's drive */
-static struct request *pcd_req;
-static int pcd_retries; /* retries on current request */
-static int pcd_busy; /* request being processed ? */
-static int pcd_sector; /* address of next requested sector */
-static int pcd_count; /* number of blocks still to do */
-static char *pcd_buf; /* buffer for request in progress */
-static void *par_drv; /* reference of parport driver */
-
-/* kernel glue structures */
-
-static int pcd_block_open(struct block_device *bdev, fmode_t mode)
-{
- struct pcd_unit *cd = bdev->bd_disk->private_data;
- int ret;
-
- bdev_check_media_change(bdev);
-
- mutex_lock(&pcd_mutex);
- ret = cdrom_open(&cd->info, bdev, mode);
- mutex_unlock(&pcd_mutex);
-
- return ret;
-}
-
-static void pcd_block_release(struct gendisk *disk, fmode_t mode)
-{
- struct pcd_unit *cd = disk->private_data;
- mutex_lock(&pcd_mutex);
- cdrom_release(&cd->info, mode);
- mutex_unlock(&pcd_mutex);
-}
-
-static int pcd_block_ioctl(struct block_device *bdev, fmode_t mode,
- unsigned cmd, unsigned long arg)
-{
- struct pcd_unit *cd = bdev->bd_disk->private_data;
- int ret;
-
- mutex_lock(&pcd_mutex);
- ret = cdrom_ioctl(&cd->info, bdev, mode, cmd, arg);
- mutex_unlock(&pcd_mutex);
-
- return ret;
-}
-
-static unsigned int pcd_block_check_events(struct gendisk *disk,
- unsigned int clearing)
-{
- struct pcd_unit *cd = disk->private_data;
- return cdrom_check_events(&cd->info, clearing);
-}
-
-static const struct block_device_operations pcd_bdops = {
- .owner = THIS_MODULE,
- .open = pcd_block_open,
- .release = pcd_block_release,
- .ioctl = pcd_block_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = blkdev_compat_ptr_ioctl,
-#endif
- .check_events = pcd_block_check_events,
-};
-
-static const struct cdrom_device_ops pcd_dops = {
- .open = pcd_open,
- .release = pcd_release,
- .drive_status = pcd_drive_status,
- .check_events = pcd_check_events,
- .tray_move = pcd_tray_move,
- .lock_door = pcd_lock_door,
- .get_mcn = pcd_get_mcn,
- .reset = pcd_drive_reset,
- .audio_ioctl = pcd_audio_ioctl,
- .generic_packet = pcd_packet,
- .capability = CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK |
- CDC_MCN | CDC_MEDIA_CHANGED | CDC_RESET |
- CDC_PLAY_AUDIO | CDC_GENERIC_PACKET | CDC_CD_R |
- CDC_CD_RW,
-};
-
-static const struct blk_mq_ops pcd_mq_ops = {
- .queue_rq = pcd_queue_rq,
-};
-
-static int pcd_open(struct cdrom_device_info *cdi, int purpose)
-{
- struct pcd_unit *cd = cdi->handle;
- if (!cd->present)
- return -ENODEV;
- return 0;
-}
-
-static void pcd_release(struct cdrom_device_info *cdi)
-{
-}
-
-static inline int status_reg(struct pcd_unit *cd)
-{
- return pi_read_regr(cd->pi, 1, 6);
-}
-
-static inline int read_reg(struct pcd_unit *cd, int reg)
-{
- return pi_read_regr(cd->pi, 0, reg);
-}
-
-static inline void write_reg(struct pcd_unit *cd, int reg, int val)
-{
- pi_write_regr(cd->pi, 0, reg, val);
-}
-
-static int pcd_wait(struct pcd_unit *cd, int go, int stop, char *fun, char *msg)
-{
- int j, r, e, s, p;
-
- j = 0;
- while ((((r = status_reg(cd)) & go) || (stop && (!(r & stop))))
- && (j++ < PCD_SPIN))
- udelay(PCD_DELAY);
-
- if ((r & (IDE_ERR & stop)) || (j > PCD_SPIN)) {
- s = read_reg(cd, 7);
- e = read_reg(cd, 1);
- p = read_reg(cd, 2);
- if (j > PCD_SPIN)
- e |= 0x100;
- if (fun)
- printk("%s: %s %s: alt=0x%x stat=0x%x err=0x%x"
- " loop=%d phase=%d\n",
- cd->name, fun, msg, r, s, e, j, p);
- return (s << 8) + r;
- }
- return 0;
-}
-
-static int pcd_command(struct pcd_unit *cd, char *cmd, int dlen, char *fun)
-{
- pi_connect(cd->pi);
-
- write_reg(cd, 6, 0xa0 + 0x10 * cd->drive);
-
- if (pcd_wait(cd, IDE_BUSY | IDE_DRQ, 0, fun, "before command")) {
- pi_disconnect(cd->pi);
- return -1;
- }
-
- write_reg(cd, 4, dlen % 256);
- write_reg(cd, 5, dlen / 256);
- write_reg(cd, 7, 0xa0); /* ATAPI packet command */
-
- if (pcd_wait(cd, IDE_BUSY, IDE_DRQ, fun, "command DRQ")) {
- pi_disconnect(cd->pi);
- return -1;
- }
-
- if (read_reg(cd, 2) != 1) {
- printk("%s: %s: command phase error\n", cd->name, fun);
- pi_disconnect(cd->pi);
- return -1;
- }
-
- pi_write_block(cd->pi, cmd, 12);
-
- return 0;
-}
-
-static int pcd_completion(struct pcd_unit *cd, char *buf, char *fun)
-{
- int r, d, p, n, k, j;
-
- r = -1;
- k = 0;
- j = 0;
-
- if (!pcd_wait(cd, IDE_BUSY, IDE_DRQ | IDE_READY | IDE_ERR,
- fun, "completion")) {
- r = 0;
- while (read_reg(cd, 7) & IDE_DRQ) {
- d = read_reg(cd, 4) + 256 * read_reg(cd, 5);
- n = (d + 3) & 0xfffc;
- p = read_reg(cd, 2) & 3;
-
- if ((p == 2) && (n > 0) && (j == 0)) {
- pi_read_block(cd->pi, buf, n);
- if (verbose > 1)
- printk("%s: %s: Read %d bytes\n",
- cd->name, fun, n);
- r = 0;
- j++;
- } else {
- if (verbose > 1)
- printk
- ("%s: %s: Unexpected phase %d, d=%d, k=%d\n",
- cd->name, fun, p, d, k);
- if (verbose < 2)
- printk_once(
- "%s: WARNING: ATAPI phase errors\n",
- cd->name);
- mdelay(1);
- }
- if (k++ > PCD_TMO) {
- printk("%s: Stuck DRQ\n", cd->name);
- break;
- }
- if (pcd_wait
- (cd, IDE_BUSY, IDE_DRQ | IDE_READY | IDE_ERR, fun,
- "completion")) {
- r = -1;
- break;
- }
- }
- }
-
- pi_disconnect(cd->pi);
-
- return r;
-}
-
-static void pcd_req_sense(struct pcd_unit *cd, char *fun)
-{
- char rs_cmd[12] = { 0x03, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0 };
- char buf[16];
- int r, c;
-
- r = pcd_command(cd, rs_cmd, 16, "Request sense");
- mdelay(1);
- if (!r)
- pcd_completion(cd, buf, "Request sense");
-
- cd->last_sense = -1;
- c = 2;
- if (!r) {
- if (fun)
- printk("%s: %s: Sense key: %x, ASC: %x, ASQ: %x\n",
- cd->name, fun, buf[2] & 0xf, buf[12], buf[13]);
- c = buf[2] & 0xf;
- cd->last_sense =
- c | ((buf[12] & 0xff) << 8) | ((buf[13] & 0xff) << 16);
- }
- if ((c == 2) || (c == 6))
- cd->changed = 1;
-}
-
-static int pcd_atapi(struct pcd_unit *cd, char *cmd, int dlen, char *buf, char *fun)
-{
- int r;
-
- r = pcd_command(cd, cmd, dlen, fun);
- mdelay(1);
- if (!r)
- r = pcd_completion(cd, buf, fun);
- if (r)
- pcd_req_sense(cd, fun);
-
- return r;
-}
-
-static int pcd_packet(struct cdrom_device_info *cdi, struct packet_command *cgc)
-{
- return pcd_atapi(cdi->handle, cgc->cmd, cgc->buflen, cgc->buffer,
- "generic packet");
-}
-
-#define DBMSG(msg) ((verbose>1)?(msg):NULL)
-
-static unsigned int pcd_check_events(struct cdrom_device_info *cdi,
- unsigned int clearing, int slot_nr)
-{
- struct pcd_unit *cd = cdi->handle;
- int res = cd->changed;
- if (res)
- cd->changed = 0;
- return res ? DISK_EVENT_MEDIA_CHANGE : 0;
-}
-
-static int pcd_lock_door(struct cdrom_device_info *cdi, int lock)
-{
- char un_cmd[12] = { 0x1e, 0, 0, 0, lock, 0, 0, 0, 0, 0, 0, 0 };
-
- return pcd_atapi(cdi->handle, un_cmd, 0, pcd_scratch,
- lock ? "lock door" : "unlock door");
-}
-
-static int pcd_tray_move(struct cdrom_device_info *cdi, int position)
-{
- char ej_cmd[12] = { 0x1b, 0, 0, 0, 3 - position, 0, 0, 0, 0, 0, 0, 0 };
-
- return pcd_atapi(cdi->handle, ej_cmd, 0, pcd_scratch,
- position ? "eject" : "close tray");
-}
-
-static void pcd_sleep(int cs)
-{
- schedule_timeout_interruptible(cs);
-}
-
-static int pcd_reset(struct pcd_unit *cd)
-{
- int i, k, flg;
- int expect[5] = { 1, 1, 1, 0x14, 0xeb };
-
- pi_connect(cd->pi);
- write_reg(cd, 6, 0xa0 + 0x10 * cd->drive);
- write_reg(cd, 7, 8);
-
- pcd_sleep(20 * HZ / 1000); /* delay a bit */
-
- k = 0;
- while ((k++ < PCD_RESET_TMO) && (status_reg(cd) & IDE_BUSY))
- pcd_sleep(HZ / 10);
-
- flg = 1;
- for (i = 0; i < 5; i++)
- flg &= (read_reg(cd, i + 1) == expect[i]);
-
- if (verbose) {
- printk("%s: Reset (%d) signature = ", cd->name, k);
- for (i = 0; i < 5; i++)
- printk("%3x", read_reg(cd, i + 1));
- if (!flg)
- printk(" (incorrect)");
- printk("\n");
- }
-
- pi_disconnect(cd->pi);
- return flg - 1;
-}
-
-static int pcd_drive_reset(struct cdrom_device_info *cdi)
-{
- return pcd_reset(cdi->handle);
-}
-
-static int pcd_ready_wait(struct pcd_unit *cd, int tmo)
-{
- char tr_cmd[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
- int k, p;
-
- k = 0;
- while (k < tmo) {
- cd->last_sense = 0;
- pcd_atapi(cd, tr_cmd, 0, NULL, DBMSG("test unit ready"));
- p = cd->last_sense;
- if (!p)
- return 0;
- if (!(((p & 0xffff) == 0x0402) || ((p & 0xff) == 6)))
- return p;
- k++;
- pcd_sleep(HZ);
- }
- return 0x000020; /* timeout */
-}
-
-static int pcd_drive_status(struct cdrom_device_info *cdi, int slot_nr)
-{
- char rc_cmd[12] = { 0x25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
- struct pcd_unit *cd = cdi->handle;
-
- if (pcd_ready_wait(cd, PCD_READY_TMO))
- return CDS_DRIVE_NOT_READY;
- if (pcd_atapi(cd, rc_cmd, 8, pcd_scratch, DBMSG("check media")))
- return CDS_NO_DISC;
- return CDS_DISC_OK;
-}
-
-static int pcd_identify(struct pcd_unit *cd)
-{
- char id_cmd[12] = { 0x12, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0 };
- char id[18];
- int k, s;
-
- pcd_bufblk = -1;
-
- s = pcd_atapi(cd, id_cmd, 36, pcd_buffer, "identify");
-
- if (s)
- return -1;
- if ((pcd_buffer[0] & 0x1f) != 5) {
- if (verbose)
- printk("%s: %s is not a CD-ROM\n",
- cd->name, cd->drive ? "Slave" : "Master");
- return -1;
- }
- memcpy(id, pcd_buffer + 16, 16);
- id[16] = 0;
- k = 16;
- while ((k >= 0) && (id[k] <= 0x20)) {
- id[k] = 0;
- k--;
- }
-
- printk("%s: %s: %s\n", cd->name, cd->drive ? "Slave" : "Master", id);
-
- return 0;
-}
-
-/*
- * returns 0, with id set if drive is detected, otherwise an error code.
- */
-static int pcd_probe(struct pcd_unit *cd, int ms)
-{
- if (ms == -1) {
- for (cd->drive = 0; cd->drive <= 1; cd->drive++)
- if (!pcd_reset(cd) && !pcd_identify(cd))
- return 0;
- } else {
- cd->drive = ms;
- if (!pcd_reset(cd) && !pcd_identify(cd))
- return 0;
- }
- return -ENODEV;
-}
-
-static int pcd_probe_capabilities(struct pcd_unit *cd)
-{
- char cmd[12] = { 0x5a, 1 << 3, 0x2a, 0, 0, 0, 0, 18, 0, 0, 0, 0 };
- char buffer[32];
- int ret;
-
- ret = pcd_atapi(cd, cmd, 18, buffer, "mode sense capabilities");
- if (ret)
- return ret;
-
- /* we should now have the cap page */
- if ((buffer[11] & 1) == 0)
- cd->info.mask |= CDC_CD_R;
- if ((buffer[11] & 2) == 0)
- cd->info.mask |= CDC_CD_RW;
- if ((buffer[12] & 1) == 0)
- cd->info.mask |= CDC_PLAY_AUDIO;
- if ((buffer[14] & 1) == 0)
- cd->info.mask |= CDC_LOCK;
- if ((buffer[14] & 8) == 0)
- cd->info.mask |= CDC_OPEN_TRAY;
- if ((buffer[14] >> 6) == 0)
- cd->info.mask |= CDC_CLOSE_TRAY;
-
- return 0;
-}
-
-/* I/O request processing */
-static int pcd_queue;
-
-static int set_next_request(void)
-{
- struct pcd_unit *cd;
- int old_pos = pcd_queue;
-
- do {
- cd = &pcd[pcd_queue];
- if (++pcd_queue == PCD_UNITS)
- pcd_queue = 0;
- if (cd->present && !list_empty(&cd->rq_list)) {
- pcd_req = list_first_entry(&cd->rq_list, struct request,
- queuelist);
- list_del_init(&pcd_req->queuelist);
- blk_mq_start_request(pcd_req);
- break;
- }
- } while (pcd_queue != old_pos);
-
- return pcd_req != NULL;
-}
-
-static void pcd_request(void)
-{
- struct pcd_unit *cd;
-
- if (pcd_busy)
- return;
-
- if (!pcd_req && !set_next_request())
- return;
-
- cd = pcd_req->q->disk->private_data;
- if (cd != pcd_current)
- pcd_bufblk = -1;
- pcd_current = cd;
- pcd_sector = blk_rq_pos(pcd_req);
- pcd_count = blk_rq_cur_sectors(pcd_req);
- pcd_buf = bio_data(pcd_req->bio);
- pcd_busy = 1;
- ps_set_intr(do_pcd_read, NULL, 0, nice);
-}
-
-static blk_status_t pcd_queue_rq(struct blk_mq_hw_ctx *hctx,
- const struct blk_mq_queue_data *bd)
-{
- struct pcd_unit *cd = hctx->queue->queuedata;
-
- if (rq_data_dir(bd->rq) != READ) {
- blk_mq_start_request(bd->rq);
- return BLK_STS_IOERR;
- }
-
- spin_lock_irq(&pcd_lock);
- list_add_tail(&bd->rq->queuelist, &cd->rq_list);
- pcd_request();
- spin_unlock_irq(&pcd_lock);
-
- return BLK_STS_OK;
-}
-
-static inline void next_request(blk_status_t err)
-{
- unsigned long saved_flags;
-
- spin_lock_irqsave(&pcd_lock, saved_flags);
- if (!blk_update_request(pcd_req, err, blk_rq_cur_bytes(pcd_req))) {
- __blk_mq_end_request(pcd_req, err);
- pcd_req = NULL;
- }
- pcd_busy = 0;
- pcd_request();
- spin_unlock_irqrestore(&pcd_lock, saved_flags);
-}
-
-static int pcd_ready(void)
-{
- return (((status_reg(pcd_current) & (IDE_BUSY | IDE_DRQ)) == IDE_DRQ));
-}
-
-static void pcd_transfer(void)
-{
-
- while (pcd_count && (pcd_sector / 4 == pcd_bufblk)) {
- int o = (pcd_sector % 4) * 512;
- memcpy(pcd_buf, pcd_buffer + o, 512);
- pcd_count--;
- pcd_buf += 512;
- pcd_sector++;
- }
-}
-
-static void pcd_start(void)
-{
- int b, i;
- char rd_cmd[12] = { 0xa8, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 };
-
- pcd_bufblk = pcd_sector / 4;
- b = pcd_bufblk;
- for (i = 0; i < 4; i++) {
- rd_cmd[5 - i] = b & 0xff;
- b = b >> 8;
- }
-
- if (pcd_command(pcd_current, rd_cmd, 2048, "read block")) {
- pcd_bufblk = -1;
- next_request(BLK_STS_IOERR);
- return;
- }
-
- mdelay(1);
-
- ps_set_intr(do_pcd_read_drq, pcd_ready, PCD_TMO, nice);
-}
-
-static void do_pcd_read(void)
-{
- pcd_busy = 1;
- pcd_retries = 0;
- pcd_transfer();
- if (!pcd_count) {
- next_request(0);
- return;
- }
-
- pi_do_claimed(pcd_current->pi, pcd_start);
-}
-
-static void do_pcd_read_drq(void)
-{
- unsigned long saved_flags;
-
- if (pcd_completion(pcd_current, pcd_buffer, "read block")) {
- if (pcd_retries < PCD_RETRIES) {
- mdelay(1);
- pcd_retries++;
- pi_do_claimed(pcd_current->pi, pcd_start);
- return;
- }
- pcd_bufblk = -1;
- next_request(BLK_STS_IOERR);
- return;
- }
-
- do_pcd_read();
- spin_lock_irqsave(&pcd_lock, saved_flags);
- pcd_request();
- spin_unlock_irqrestore(&pcd_lock, saved_flags);
-}
-
-/* the audio_ioctl stuff is adapted from sr_ioctl.c */
-
-static int pcd_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void *arg)
-{
- struct pcd_unit *cd = cdi->handle;
-
- switch (cmd) {
-
- case CDROMREADTOCHDR:
-
- {
- char cmd[12] =
- { GPCMD_READ_TOC_PMA_ATIP, 0, 0, 0, 0, 0, 0, 0, 12,
- 0, 0, 0 };
- struct cdrom_tochdr *tochdr =
- (struct cdrom_tochdr *) arg;
- char buffer[32];
- int r;
-
- r = pcd_atapi(cd, cmd, 12, buffer, "read toc header");
-
- tochdr->cdth_trk0 = buffer[2];
- tochdr->cdth_trk1 = buffer[3];
-
- return r ? -EIO : 0;
- }
-
- case CDROMREADTOCENTRY:
-
- {
- char cmd[12] =
- { GPCMD_READ_TOC_PMA_ATIP, 0, 0, 0, 0, 0, 0, 0, 12,
- 0, 0, 0 };
-
- struct cdrom_tocentry *tocentry =
- (struct cdrom_tocentry *) arg;
- unsigned char buffer[32];
- int r;
-
- cmd[1] =
- (tocentry->cdte_format == CDROM_MSF ? 0x02 : 0);
- cmd[6] = tocentry->cdte_track;
-
- r = pcd_atapi(cd, cmd, 12, buffer, "read toc entry");
-
- tocentry->cdte_ctrl = buffer[5] & 0xf;
- tocentry->cdte_adr = buffer[5] >> 4;
- tocentry->cdte_datamode =
- (tocentry->cdte_ctrl & 0x04) ? 1 : 0;
- if (tocentry->cdte_format == CDROM_MSF) {
- tocentry->cdte_addr.msf.minute = buffer[9];
- tocentry->cdte_addr.msf.second = buffer[10];
- tocentry->cdte_addr.msf.frame = buffer[11];
- } else
- tocentry->cdte_addr.lba =
- (((((buffer[8] << 8) + buffer[9]) << 8)
- + buffer[10]) << 8) + buffer[11];
-
- return r ? -EIO : 0;
- }
-
- default:
-
- return -ENOSYS;
- }
-}
-
-static int pcd_get_mcn(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn)
-{
- char cmd[12] =
- { GPCMD_READ_SUBCHANNEL, 0, 0x40, 2, 0, 0, 0, 0, 24, 0, 0, 0 };
- char buffer[32];
-
- if (pcd_atapi(cdi->handle, cmd, 24, buffer, "get mcn"))
- return -EIO;
-
- memcpy(mcn->medium_catalog_number, buffer + 9, 13);
- mcn->medium_catalog_number[13] = 0;
-
- return 0;
-}
-
-static int pcd_init_unit(struct pcd_unit *cd, bool autoprobe, int port,
- int mode, int unit, int protocol, int delay, int ms)
-{
- struct gendisk *disk;
- int ret;
-
- ret = blk_mq_alloc_sq_tag_set(&cd->tag_set, &pcd_mq_ops, 1,
- BLK_MQ_F_SHOULD_MERGE);
- if (ret)
- return ret;
-
- disk = blk_mq_alloc_disk(&cd->tag_set, cd);
- if (IS_ERR(disk)) {
- ret = PTR_ERR(disk);
- goto out_free_tag_set;
- }
-
- INIT_LIST_HEAD(&cd->rq_list);
- blk_queue_bounce_limit(disk->queue, BLK_BOUNCE_HIGH);
- cd->disk = disk;
- cd->pi = &cd->pia;
- cd->present = 0;
- cd->last_sense = 0;
- cd->changed = 1;
- cd->drive = (*drives[cd - pcd])[D_SLV];
-
- cd->name = &cd->info.name[0];
- snprintf(cd->name, sizeof(cd->info.name), "%s%d", name, unit);
- cd->info.ops = &pcd_dops;
- cd->info.handle = cd;
- cd->info.speed = 0;
- cd->info.capacity = 1;
- cd->info.mask = 0;
- disk->major = major;
- disk->first_minor = unit;
- disk->minors = 1;
- strcpy(disk->disk_name, cd->name); /* umm... */
- disk->fops = &pcd_bdops;
- disk->flags |= GENHD_FL_NO_PART;
- disk->events = DISK_EVENT_MEDIA_CHANGE;
- disk->event_flags = DISK_EVENT_FLAG_BLOCK_ON_EXCL_WRITE;
-
- if (!pi_init(cd->pi, autoprobe, port, mode, unit, protocol, delay,
- pcd_buffer, PI_PCD, verbose, cd->name)) {
- ret = -ENODEV;
- goto out_free_disk;
- }
- ret = pcd_probe(cd, ms);
- if (ret)
- goto out_pi_release;
-
- cd->present = 1;
- pcd_probe_capabilities(cd);
- ret = register_cdrom(cd->disk, &cd->info);
- if (ret)
- goto out_pi_release;
- ret = add_disk(cd->disk);
- if (ret)
- goto out_unreg_cdrom;
- return 0;
-
-out_unreg_cdrom:
- unregister_cdrom(&cd->info);
-out_pi_release:
- pi_release(cd->pi);
-out_free_disk:
- put_disk(cd->disk);
-out_free_tag_set:
- blk_mq_free_tag_set(&cd->tag_set);
- return ret;
-}
-
-static int __init pcd_init(void)
-{
- int found = 0, unit;
-
- if (disable)
- return -EINVAL;
-
- if (register_blkdev(major, name))
- return -EBUSY;
-
- pr_info("%s: %s version %s, major %d, nice %d\n",
- name, name, PCD_VERSION, major, nice);
-
- par_drv = pi_register_driver(name);
- if (!par_drv) {
- pr_err("failed to register %s driver\n", name);
- goto out_unregister_blkdev;
- }
-
- for (unit = 0; unit < PCD_UNITS; unit++) {
- if ((*drives[unit])[D_PRT])
- pcd_drive_count++;
- }
-
- if (pcd_drive_count == 0) { /* nothing spec'd - so autoprobe for 1 */
- if (!pcd_init_unit(pcd, 1, -1, -1, -1, -1, -1, -1))
- found++;
- } else {
- for (unit = 0; unit < PCD_UNITS; unit++) {
- struct pcd_unit *cd = &pcd[unit];
- int *conf = *drives[unit];
-
- if (!conf[D_PRT])
- continue;
- if (!pcd_init_unit(cd, 0, conf[D_PRT], conf[D_MOD],
- conf[D_UNI], conf[D_PRO], conf[D_DLY],
- conf[D_SLV]))
- found++;
- }
- }
-
- if (!found) {
- pr_info("%s: No CD-ROM drive found\n", name);
- goto out_unregister_pi_driver;
- }
-
- return 0;
-
-out_unregister_pi_driver:
- pi_unregister_driver(par_drv);
-out_unregister_blkdev:
- unregister_blkdev(major, name);
- return -ENODEV;
-}
-
-static void __exit pcd_exit(void)
-{
- struct pcd_unit *cd;
- int unit;
-
- for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) {
- if (!cd->present)
- continue;
-
- unregister_cdrom(&cd->info);
- del_gendisk(cd->disk);
- pi_release(cd->pi);
- put_disk(cd->disk);
-
- blk_mq_free_tag_set(&cd->tag_set);
- }
- pi_unregister_driver(par_drv);
- unregister_blkdev(major, name);
-}
-
-MODULE_LICENSE("GPL");
-module_init(pcd_init)
-module_exit(pcd_exit)
diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c
deleted file mode 100644
index f8a75bc90f70..000000000000
--- a/drivers/block/paride/pd.c
+++ /dev/null
@@ -1,1032 +0,0 @@
-/*
- pd.c (c) 1997-8 Grant R. Guenther <[email protected]>
- Under the terms of the GNU General Public License.
-
- This is the high-level driver for parallel port IDE hard
- drives based on chips supported by the paride module.
-
- By default, the driver will autoprobe for a single parallel
- port IDE drive, but if their individual parameters are
- specified, the driver can handle up to 4 drives.
-
- The behaviour of the pd driver can be altered by setting
- some parameters from the insmod command line. The following
- parameters are adjustable:
-
- drive0 These four arguments can be arrays of
- drive1 1-8 integers as follows:
- drive2
- drive3 <prt>,<pro>,<uni>,<mod>,<geo>,<sby>,<dly>,<slv>
-
- Where,
-
- <prt> is the base of the parallel port address for
- the corresponding drive. (required)
-
- <pro> is the protocol number for the adapter that
- supports this drive. These numbers are
- logged by 'paride' when the protocol modules
- are initialised. (0 if not given)
-
- <uni> for those adapters that support chained
- devices, this is the unit selector for the
- chain of devices on the given port. It should
- be zero for devices that don't support chaining.
- (0 if not given)
-
- <mod> this can be -1 to choose the best mode, or one
- of the mode numbers supported by the adapter.
- (-1 if not given)
-
- <geo> this defaults to 0 to indicate that the driver
- should use the CHS geometry provided by the drive
- itself. If set to 1, the driver will provide
- a logical geometry with 64 heads and 32 sectors
- per track, to be consistent with most SCSI
- drivers. (0 if not given)
-
- <sby> set this to zero to disable the power saving
- standby mode, if needed. (1 if not given)
-
- <dly> some parallel ports require the driver to
- go more slowly. -1 sets a default value that
- should work with the chosen protocol. Otherwise,
- set this to a small integer, the larger it is
- the slower the port i/o. In some cases, setting
- this to zero will speed up the device. (default -1)
-
- <slv> IDE disks can be jumpered to master or slave.
- Set this to 0 to choose the master drive, 1 to
- choose the slave, -1 (the default) to choose the
- first drive found.
-
-
- major You may use this parameter to override the
- default major number (45) that this driver
- will use. Be sure to change the device
- name as well.
-
- name This parameter is a character string that
- contains the name the kernel will use for this
- device (in /proc output, for instance).
- (default "pd")
-
- cluster The driver will attempt to aggregate requests
- for adjacent blocks into larger multi-block
- clusters. The maximum cluster size (in 512
- byte sectors) is set with this parameter.
- (default 64)
-
- verbose This parameter controls the amount of logging
- that the driver will do. Set it to 0 for
- normal operation, 1 to see autoprobe progress
- messages, or 2 to see additional debugging
- output. (default 0)
-
- nice This parameter controls the driver's use of
- idle CPU time, at the expense of some speed.
-
- If this driver is built into the kernel, you can use kernel
- the following command line parameters, with the same values
- as the corresponding module parameters listed above:
-
- pd.drive0
- pd.drive1
- pd.drive2
- pd.drive3
- pd.cluster
- pd.nice
-
- In addition, you can use the parameter pd.disable to disable
- the driver entirely.
-
-*/
-
-/* Changes:
-
- 1.01 GRG 1997.01.24 Restored pd_reset()
- Added eject ioctl
- 1.02 GRG 1998.05.06 SMP spinlock changes,
- Added slave support
- 1.03 GRG 1998.06.16 Eliminate an Ugh.
- 1.04 GRG 1998.08.15 Extra debugging, use HZ in loop timing
- 1.05 GRG 1998.09.24 Added jumbo support
-
-*/
-
-#define PD_VERSION "1.05"
-#define PD_MAJOR 45
-#define PD_NAME "pd"
-#define PD_UNITS 4
-
-/* Here are things one can override from the insmod command.
- Most are autoprobed by paride unless set here. Verbose is off
- by default.
-
-*/
-#include <linux/types.h>
-
-static int verbose = 0;
-static int major = PD_MAJOR;
-static char *name = PD_NAME;
-static int cluster = 64;
-static int nice = 0;
-static int disable = 0;
-
-static int drive0[8] = { 0, 0, 0, -1, 0, 1, -1, -1 };
-static int drive1[8] = { 0, 0, 0, -1, 0, 1, -1, -1 };
-static int drive2[8] = { 0, 0, 0, -1, 0, 1, -1, -1 };
-static int drive3[8] = { 0, 0, 0, -1, 0, 1, -1, -1 };
-
-static int (*drives[4])[8] = {&drive0, &drive1, &drive2, &drive3};
-
-enum {D_PRT, D_PRO, D_UNI, D_MOD, D_GEO, D_SBY, D_DLY, D_SLV};
-
-/* end of parameters */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/gfp.h>
-#include <linux/fs.h>
-#include <linux/delay.h>
-#include <linux/hdreg.h>
-#include <linux/cdrom.h> /* for the eject ioctl */
-#include <linux/blk-mq.h>
-#include <linux/blkpg.h>
-#include <linux/kernel.h>
-#include <linux/mutex.h>
-#include <linux/uaccess.h>
-#include <linux/workqueue.h>
-
-static DEFINE_MUTEX(pd_mutex);
-static DEFINE_SPINLOCK(pd_lock);
-
-module_param(verbose, int, 0);
-module_param(major, int, 0);
-module_param(name, charp, 0);
-module_param(cluster, int, 0);
-module_param(nice, int, 0);
-module_param_array(drive0, int, NULL, 0);
-module_param_array(drive1, int, NULL, 0);
-module_param_array(drive2, int, NULL, 0);
-module_param_array(drive3, int, NULL, 0);
-
-#include "paride.h"
-
-#define PD_BITS 4
-
-/* numbers for "SCSI" geometry */
-
-#define PD_LOG_HEADS 64
-#define PD_LOG_SECTS 32
-
-#define PD_ID_OFF 54
-#define PD_ID_LEN 14
-
-#define PD_MAX_RETRIES 5
-#define PD_TMO 800 /* interrupt timeout in jiffies */
-#define PD_SPIN_DEL 50 /* spin delay in micro-seconds */
-
-#define PD_SPIN (1000000*PD_TMO)/(HZ*PD_SPIN_DEL)
-
-#define STAT_ERR 0x00001
-#define STAT_INDEX 0x00002
-#define STAT_ECC 0x00004
-#define STAT_DRQ 0x00008
-#define STAT_SEEK 0x00010
-#define STAT_WRERR 0x00020
-#define STAT_READY 0x00040
-#define STAT_BUSY 0x00080
-
-#define ERR_AMNF 0x00100
-#define ERR_TK0NF 0x00200
-#define ERR_ABRT 0x00400
-#define ERR_MCR 0x00800
-#define ERR_IDNF 0x01000
-#define ERR_MC 0x02000
-#define ERR_UNC 0x04000
-#define ERR_TMO 0x10000
-
-#define IDE_READ 0x20
-#define IDE_WRITE 0x30
-#define IDE_READ_VRFY 0x40
-#define IDE_INIT_DEV_PARMS 0x91
-#define IDE_STANDBY 0x96
-#define IDE_ACKCHANGE 0xdb
-#define IDE_DOORLOCK 0xde
-#define IDE_DOORUNLOCK 0xdf
-#define IDE_IDENTIFY 0xec
-#define IDE_EJECT 0xed
-
-#define PD_NAMELEN 8
-
-struct pd_unit {
- struct pi_adapter pia; /* interface to paride layer */
- struct pi_adapter *pi;
- int access; /* count of active opens ... */
- int capacity; /* Size of this volume in sectors */
- int heads; /* physical geometry */
- int sectors;
- int cylinders;
- int can_lba;
- int drive; /* master=0 slave=1 */
- int changed; /* Have we seen a disk change ? */
- int removable; /* removable media device ? */
- int standby;
- int alt_geom;
- char name[PD_NAMELEN]; /* pda, pdb, etc ... */
- struct gendisk *gd;
- struct blk_mq_tag_set tag_set;
- struct list_head rq_list;
-};
-
-static struct pd_unit pd[PD_UNITS];
-
-struct pd_req {
- /* for REQ_OP_DRV_IN: */
- enum action (*func)(struct pd_unit *disk);
-};
-
-static char pd_scratch[512]; /* scratch block buffer */
-
-static char *pd_errs[17] = { "ERR", "INDEX", "ECC", "DRQ", "SEEK", "WRERR",
- "READY", "BUSY", "AMNF", "TK0NF", "ABRT", "MCR",
- "IDNF", "MC", "UNC", "???", "TMO"
-};
-
-static void *par_drv; /* reference of parport driver */
-
-static inline int status_reg(struct pd_unit *disk)
-{
- return pi_read_regr(disk->pi, 1, 6);
-}
-
-static inline int read_reg(struct pd_unit *disk, int reg)
-{
- return pi_read_regr(disk->pi, 0, reg);
-}
-
-static inline void write_status(struct pd_unit *disk, int val)
-{
- pi_write_regr(disk->pi, 1, 6, val);
-}
-
-static inline void write_reg(struct pd_unit *disk, int reg, int val)
-{
- pi_write_regr(disk->pi, 0, reg, val);
-}
-
-static inline u8 DRIVE(struct pd_unit *disk)
-{
- return 0xa0+0x10*disk->drive;
-}
-
-/* ide command interface */
-
-static void pd_print_error(struct pd_unit *disk, char *msg, int status)
-{
- int i;
-
- printk("%s: %s: status = 0x%x =", disk->name, msg, status);
- for (i = 0; i < ARRAY_SIZE(pd_errs); i++)
- if (status & (1 << i))
- printk(" %s", pd_errs[i]);
- printk("\n");
-}
-
-static void pd_reset(struct pd_unit *disk)
-{ /* called only for MASTER drive */
- write_status(disk, 4);
- udelay(50);
- write_status(disk, 0);
- udelay(250);
-}
-
-#define DBMSG(msg) ((verbose>1)?(msg):NULL)
-
-static int pd_wait_for(struct pd_unit *disk, int w, char *msg)
-{ /* polled wait */
- int k, r, e;
-
- k = 0;
- while (k < PD_SPIN) {
- r = status_reg(disk);
- k++;
- if (((r & w) == w) && !(r & STAT_BUSY))
- break;
- udelay(PD_SPIN_DEL);
- }
- e = (read_reg(disk, 1) << 8) + read_reg(disk, 7);
- if (k >= PD_SPIN)
- e |= ERR_TMO;
- if ((e & (STAT_ERR | ERR_TMO)) && (msg != NULL))
- pd_print_error(disk, msg, e);
- return e;
-}
-
-static void pd_send_command(struct pd_unit *disk, int n, int s, int h, int c0, int c1, int func)
-{
- write_reg(disk, 6, DRIVE(disk) + h);
- write_reg(disk, 1, 0); /* the IDE task file */
- write_reg(disk, 2, n);
- write_reg(disk, 3, s);
- write_reg(disk, 4, c0);
- write_reg(disk, 5, c1);
- write_reg(disk, 7, func);
-
- udelay(1);
-}
-
-static void pd_ide_command(struct pd_unit *disk, int func, int block, int count)
-{
- int c1, c0, h, s;
-
- if (disk->can_lba) {
- s = block & 255;
- c0 = (block >>= 8) & 255;
- c1 = (block >>= 8) & 255;
- h = ((block >>= 8) & 15) + 0x40;
- } else {
- s = (block % disk->sectors) + 1;
- h = (block /= disk->sectors) % disk->heads;
- c0 = (block /= disk->heads) % 256;
- c1 = (block >>= 8);
- }
- pd_send_command(disk, count, s, h, c0, c1, func);
-}
-
-/* The i/o request engine */
-
-enum action {Fail = 0, Ok = 1, Hold, Wait};
-
-static struct request *pd_req; /* current request */
-static enum action (*phase)(void);
-
-static void run_fsm(void);
-
-static void ps_tq_int(struct work_struct *work);
-
-static DECLARE_DELAYED_WORK(fsm_tq, ps_tq_int);
-
-static void schedule_fsm(void)
-{
- if (!nice)
- schedule_delayed_work(&fsm_tq, 0);
- else
- schedule_delayed_work(&fsm_tq, nice-1);
-}
-
-static void ps_tq_int(struct work_struct *work)
-{
- run_fsm();
-}
-
-static enum action do_pd_io_start(void);
-static enum action pd_special(void);
-static enum action do_pd_read_start(void);
-static enum action do_pd_write_start(void);
-static enum action do_pd_read_drq(void);
-static enum action do_pd_write_done(void);
-
-static int pd_queue;
-static int pd_claimed;
-
-static struct pd_unit *pd_current; /* current request's drive */
-static PIA *pi_current; /* current request's PIA */
-
-static int set_next_request(void)
-{
- struct gendisk *disk;
- struct request_queue *q;
- int old_pos = pd_queue;
-
- do {
- disk = pd[pd_queue].gd;
- q = disk ? disk->queue : NULL;
- if (++pd_queue == PD_UNITS)
- pd_queue = 0;
- if (q) {
- struct pd_unit *disk = q->queuedata;
-
- if (list_empty(&disk->rq_list))
- continue;
-
- pd_req = list_first_entry(&disk->rq_list,
- struct request,
- queuelist);
- list_del_init(&pd_req->queuelist);
- blk_mq_start_request(pd_req);
- break;
- }
- } while (pd_queue != old_pos);
-
- return pd_req != NULL;
-}
-
-static void run_fsm(void)
-{
- while (1) {
- enum action res;
- int stop = 0;
-
- if (!phase) {
- pd_current = pd_req->q->disk->private_data;
- pi_current = pd_current->pi;
- phase = do_pd_io_start;
- }
-
- switch (pd_claimed) {
- case 0:
- pd_claimed = 1;
- if (!pi_schedule_claimed(pi_current, run_fsm))
- return;
- fallthrough;
- case 1:
- pd_claimed = 2;
- pi_current->proto->connect(pi_current);
- }
-
- switch(res = phase()) {
- case Ok: case Fail: {
- blk_status_t err;
-
- err = res == Ok ? 0 : BLK_STS_IOERR;
- pi_disconnect(pi_current);
- pd_claimed = 0;
- phase = NULL;
- spin_lock_irq(&pd_lock);
- if (!blk_update_request(pd_req, err,
- blk_rq_cur_bytes(pd_req))) {
- __blk_mq_end_request(pd_req, err);
- pd_req = NULL;
- stop = !set_next_request();
- }
- spin_unlock_irq(&pd_lock);
- if (stop)
- return;
- }
- fallthrough;
- case Hold:
- schedule_fsm();
- return;
- case Wait:
- pi_disconnect(pi_current);
- pd_claimed = 0;
- }
- }
-}
-
-static int pd_retries = 0; /* i/o error retry count */
-static int pd_block; /* address of next requested block */
-static int pd_count; /* number of blocks still to do */
-static int pd_run; /* sectors in current cluster */
-static char *pd_buf; /* buffer for request in progress */
-
-static enum action do_pd_io_start(void)
-{
- switch (req_op(pd_req)) {
- case REQ_OP_DRV_IN:
- phase = pd_special;
- return pd_special();
- case REQ_OP_READ:
- case REQ_OP_WRITE:
- pd_block = blk_rq_pos(pd_req);
- pd_count = blk_rq_cur_sectors(pd_req);
- if (pd_block + pd_count > get_capacity(pd_req->q->disk))
- return Fail;
- pd_run = blk_rq_sectors(pd_req);
- pd_buf = bio_data(pd_req->bio);
- pd_retries = 0;
- if (req_op(pd_req) == REQ_OP_READ)
- return do_pd_read_start();
- else
- return do_pd_write_start();
- default:
- break;
- }
- return Fail;
-}
-
-static enum action pd_special(void)
-{
- struct pd_req *req = blk_mq_rq_to_pdu(pd_req);
-
- return req->func(pd_current);
-}
-
-static int pd_next_buf(void)
-{
- unsigned long saved_flags;
-
- pd_count--;
- pd_run--;
- pd_buf += 512;
- pd_block++;
- if (!pd_run)
- return 1;
- if (pd_count)
- return 0;
- spin_lock_irqsave(&pd_lock, saved_flags);
- if (!blk_update_request(pd_req, 0, blk_rq_cur_bytes(pd_req))) {
- __blk_mq_end_request(pd_req, 0);
- pd_req = NULL;
- pd_count = 0;
- pd_buf = NULL;
- } else {
- pd_count = blk_rq_cur_sectors(pd_req);
- pd_buf = bio_data(pd_req->bio);
- }
- spin_unlock_irqrestore(&pd_lock, saved_flags);
- return !pd_count;
-}
-
-static unsigned long pd_timeout;
-
-static enum action do_pd_read_start(void)
-{
- if (pd_wait_for(pd_current, STAT_READY, "do_pd_read") & STAT_ERR) {
- if (pd_retries < PD_MAX_RETRIES) {
- pd_retries++;
- return Wait;
- }
- return Fail;
- }
- pd_ide_command(pd_current, IDE_READ, pd_block, pd_run);
- phase = do_pd_read_drq;
- pd_timeout = jiffies + PD_TMO;
- return Hold;
-}
-
-static enum action do_pd_write_start(void)
-{
- if (pd_wait_for(pd_current, STAT_READY, "do_pd_write") & STAT_ERR) {
- if (pd_retries < PD_MAX_RETRIES) {
- pd_retries++;
- return Wait;
- }
- return Fail;
- }
- pd_ide_command(pd_current, IDE_WRITE, pd_block, pd_run);
- while (1) {
- if (pd_wait_for(pd_current, STAT_DRQ, "do_pd_write_drq") & STAT_ERR) {
- if (pd_retries < PD_MAX_RETRIES) {
- pd_retries++;
- return Wait;
- }
- return Fail;
- }
- pi_write_block(pd_current->pi, pd_buf, 512);
- if (pd_next_buf())
- break;
- }
- phase = do_pd_write_done;
- pd_timeout = jiffies + PD_TMO;
- return Hold;
-}
-
-static inline int pd_ready(void)
-{
- return !(status_reg(pd_current) & STAT_BUSY);
-}
-
-static enum action do_pd_read_drq(void)
-{
- if (!pd_ready() && !time_after_eq(jiffies, pd_timeout))
- return Hold;
-
- while (1) {
- if (pd_wait_for(pd_current, STAT_DRQ, "do_pd_read_drq") & STAT_ERR) {
- if (pd_retries < PD_MAX_RETRIES) {
- pd_retries++;
- phase = do_pd_read_start;
- return Wait;
- }
- return Fail;
- }
- pi_read_block(pd_current->pi, pd_buf, 512);
- if (pd_next_buf())
- break;
- }
- return Ok;
-}
-
-static enum action do_pd_write_done(void)
-{
- if (!pd_ready() && !time_after_eq(jiffies, pd_timeout))
- return Hold;
-
- if (pd_wait_for(pd_current, STAT_READY, "do_pd_write_done") & STAT_ERR) {
- if (pd_retries < PD_MAX_RETRIES) {
- pd_retries++;
- phase = do_pd_write_start;
- return Wait;
- }
- return Fail;
- }
- return Ok;
-}
-
-/* special io requests */
-
-/* According to the ATA standard, the default CHS geometry should be
- available following a reset. Some Western Digital drives come up
- in a mode where only LBA addresses are accepted until the device
- parameters are initialised.
-*/
-
-static void pd_init_dev_parms(struct pd_unit *disk)
-{
- pd_wait_for(disk, 0, DBMSG("before init_dev_parms"));
- pd_send_command(disk, disk->sectors, 0, disk->heads - 1, 0, 0,
- IDE_INIT_DEV_PARMS);
- udelay(300);
- pd_wait_for(disk, 0, "Initialise device parameters");
-}
-
-static enum action pd_door_lock(struct pd_unit *disk)
-{
- if (!(pd_wait_for(disk, STAT_READY, "Lock") & STAT_ERR)) {
- pd_send_command(disk, 1, 0, 0, 0, 0, IDE_DOORLOCK);
- pd_wait_for(disk, STAT_READY, "Lock done");
- }
- return Ok;
-}
-
-static enum action pd_door_unlock(struct pd_unit *disk)
-{
- if (!(pd_wait_for(disk, STAT_READY, "Lock") & STAT_ERR)) {
- pd_send_command(disk, 1, 0, 0, 0, 0, IDE_DOORUNLOCK);
- pd_wait_for(disk, STAT_READY, "Lock done");
- }
- return Ok;
-}
-
-static enum action pd_eject(struct pd_unit *disk)
-{
- pd_wait_for(disk, 0, DBMSG("before unlock on eject"));
- pd_send_command(disk, 1, 0, 0, 0, 0, IDE_DOORUNLOCK);
- pd_wait_for(disk, 0, DBMSG("after unlock on eject"));
- pd_wait_for(disk, 0, DBMSG("before eject"));
- pd_send_command(disk, 0, 0, 0, 0, 0, IDE_EJECT);
- pd_wait_for(disk, 0, DBMSG("after eject"));
- return Ok;
-}
-
-static enum action pd_media_check(struct pd_unit *disk)
-{
- int r = pd_wait_for(disk, STAT_READY, DBMSG("before media_check"));
- if (!(r & STAT_ERR)) {
- pd_send_command(disk, 1, 1, 0, 0, 0, IDE_READ_VRFY);
- r = pd_wait_for(disk, STAT_READY, DBMSG("RDY after READ_VRFY"));
- } else
- disk->changed = 1; /* say changed if other error */
- if (r & ERR_MC) {
- disk->changed = 1;
- pd_send_command(disk, 1, 0, 0, 0, 0, IDE_ACKCHANGE);
- pd_wait_for(disk, STAT_READY, DBMSG("RDY after ACKCHANGE"));
- pd_send_command(disk, 1, 1, 0, 0, 0, IDE_READ_VRFY);
- r = pd_wait_for(disk, STAT_READY, DBMSG("RDY after VRFY"));
- }
- return Ok;
-}
-
-static void pd_standby_off(struct pd_unit *disk)
-{
- pd_wait_for(disk, 0, DBMSG("before STANDBY"));
- pd_send_command(disk, 0, 0, 0, 0, 0, IDE_STANDBY);
- pd_wait_for(disk, 0, DBMSG("after STANDBY"));
-}
-
-static enum action pd_identify(struct pd_unit *disk)
-{
- int j;
- char id[PD_ID_LEN + 1];
-
-/* WARNING: here there may be dragons. reset() applies to both drives,
- but we call it only on probing the MASTER. This should allow most
- common configurations to work, but be warned that a reset can clear
- settings on the SLAVE drive.
-*/
-
- if (disk->drive == 0)
- pd_reset(disk);
-
- write_reg(disk, 6, DRIVE(disk));
- pd_wait_for(disk, 0, DBMSG("before IDENT"));
- pd_send_command(disk, 1, 0, 0, 0, 0, IDE_IDENTIFY);
-
- if (pd_wait_for(disk, STAT_DRQ, DBMSG("IDENT DRQ")) & STAT_ERR)
- return Fail;
- pi_read_block(disk->pi, pd_scratch, 512);
- disk->can_lba = pd_scratch[99] & 2;
- disk->sectors = le16_to_cpu(*(__le16 *) (pd_scratch + 12));
- disk->heads = le16_to_cpu(*(__le16 *) (pd_scratch + 6));
- disk->cylinders = le16_to_cpu(*(__le16 *) (pd_scratch + 2));
- if (disk->can_lba)
- disk->capacity = le32_to_cpu(*(__le32 *) (pd_scratch + 120));
- else
- disk->capacity = disk->sectors * disk->heads * disk->cylinders;
-
- for (j = 0; j < PD_ID_LEN; j++)
- id[j ^ 1] = pd_scratch[j + PD_ID_OFF];
- j = PD_ID_LEN - 1;
- while ((j >= 0) && (id[j] <= 0x20))
- j--;
- j++;
- id[j] = 0;
-
- disk->removable = pd_scratch[0] & 0x80;
-
- printk("%s: %s, %s, %d blocks [%dM], (%d/%d/%d), %s media\n",
- disk->name, id,
- disk->drive ? "slave" : "master",
- disk->capacity, disk->capacity / 2048,
- disk->cylinders, disk->heads, disk->sectors,
- disk->removable ? "removable" : "fixed");
-
- if (disk->capacity)
- pd_init_dev_parms(disk);
- if (!disk->standby)
- pd_standby_off(disk);
-
- return Ok;
-}
-
-/* end of io request engine */
-
-static blk_status_t pd_queue_rq(struct blk_mq_hw_ctx *hctx,
- const struct blk_mq_queue_data *bd)
-{
- struct pd_unit *disk = hctx->queue->queuedata;
-
- spin_lock_irq(&pd_lock);
- if (!pd_req) {
- pd_req = bd->rq;
- blk_mq_start_request(pd_req);
- } else
- list_add_tail(&bd->rq->queuelist, &disk->rq_list);
- spin_unlock_irq(&pd_lock);
-
- run_fsm();
- return BLK_STS_OK;
-}
-
-static int pd_special_command(struct pd_unit *disk,
- enum action (*func)(struct pd_unit *disk))
-{
- struct request *rq;
- struct pd_req *req;
-
- rq = blk_mq_alloc_request(disk->gd->queue, REQ_OP_DRV_IN, 0);
- if (IS_ERR(rq))
- return PTR_ERR(rq);
- req = blk_mq_rq_to_pdu(rq);
-
- req->func = func;
- blk_execute_rq(rq, false);
- blk_mq_free_request(rq);
- return 0;
-}
-
-/* kernel glue structures */
-
-static int pd_open(struct block_device *bdev, fmode_t mode)
-{
- struct pd_unit *disk = bdev->bd_disk->private_data;
-
- mutex_lock(&pd_mutex);
- disk->access++;
-
- if (disk->removable) {
- pd_special_command(disk, pd_media_check);
- pd_special_command(disk, pd_door_lock);
- }
- mutex_unlock(&pd_mutex);
- return 0;
-}
-
-static int pd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
-{
- struct pd_unit *disk = bdev->bd_disk->private_data;
-
- if (disk->alt_geom) {
- geo->heads = PD_LOG_HEADS;
- geo->sectors = PD_LOG_SECTS;
- geo->cylinders = disk->capacity / (geo->heads * geo->sectors);
- } else {
- geo->heads = disk->heads;
- geo->sectors = disk->sectors;
- geo->cylinders = disk->cylinders;
- }
-
- return 0;
-}
-
-static int pd_ioctl(struct block_device *bdev, fmode_t mode,
- unsigned int cmd, unsigned long arg)
-{
- struct pd_unit *disk = bdev->bd_disk->private_data;
-
- switch (cmd) {
- case CDROMEJECT:
- mutex_lock(&pd_mutex);
- if (disk->access == 1)
- pd_special_command(disk, pd_eject);
- mutex_unlock(&pd_mutex);
- return 0;
- default:
- return -EINVAL;
- }
-}
-
-static void pd_release(struct gendisk *p, fmode_t mode)
-{
- struct pd_unit *disk = p->private_data;
-
- mutex_lock(&pd_mutex);
- if (!--disk->access && disk->removable)
- pd_special_command(disk, pd_door_unlock);
- mutex_unlock(&pd_mutex);
-}
-
-static unsigned int pd_check_events(struct gendisk *p, unsigned int clearing)
-{
- struct pd_unit *disk = p->private_data;
- int r;
- if (!disk->removable)
- return 0;
- pd_special_command(disk, pd_media_check);
- r = disk->changed;
- disk->changed = 0;
- return r ? DISK_EVENT_MEDIA_CHANGE : 0;
-}
-
-static const struct block_device_operations pd_fops = {
- .owner = THIS_MODULE,
- .open = pd_open,
- .release = pd_release,
- .ioctl = pd_ioctl,
- .compat_ioctl = pd_ioctl,
- .getgeo = pd_getgeo,
- .check_events = pd_check_events,
-};
-
-/* probing */
-
-static const struct blk_mq_ops pd_mq_ops = {
- .queue_rq = pd_queue_rq,
-};
-
-static int pd_probe_drive(struct pd_unit *disk, int autoprobe, int port,
- int mode, int unit, int protocol, int delay)
-{
- int index = disk - pd;
- int *parm = *drives[index];
- struct gendisk *p;
- int ret;
-
- disk->pi = &disk->pia;
- disk->access = 0;
- disk->changed = 1;
- disk->capacity = 0;
- disk->drive = parm[D_SLV];
- snprintf(disk->name, PD_NAMELEN, "%s%c", name, 'a' + index);
- disk->alt_geom = parm[D_GEO];
- disk->standby = parm[D_SBY];
- INIT_LIST_HEAD(&disk->rq_list);
-
- if (!pi_init(disk->pi, autoprobe, port, mode, unit, protocol, delay,
- pd_scratch, PI_PD, verbose, disk->name))
- return -ENXIO;
-
- memset(&disk->tag_set, 0, sizeof(disk->tag_set));
- disk->tag_set.ops = &pd_mq_ops;
- disk->tag_set.cmd_size = sizeof(struct pd_req);
- disk->tag_set.nr_hw_queues = 1;
- disk->tag_set.nr_maps = 1;
- disk->tag_set.queue_depth = 2;
- disk->tag_set.numa_node = NUMA_NO_NODE;
- disk->tag_set.flags = BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_BLOCKING;
- ret = blk_mq_alloc_tag_set(&disk->tag_set);
- if (ret)
- goto pi_release;
-
- p = blk_mq_alloc_disk(&disk->tag_set, disk);
- if (IS_ERR(p)) {
- ret = PTR_ERR(p);
- goto free_tag_set;
- }
- disk->gd = p;
-
- strcpy(p->disk_name, disk->name);
- p->fops = &pd_fops;
- p->major = major;
- p->first_minor = (disk - pd) << PD_BITS;
- p->minors = 1 << PD_BITS;
- p->events = DISK_EVENT_MEDIA_CHANGE;
- p->private_data = disk;
- blk_queue_max_hw_sectors(p->queue, cluster);
- blk_queue_bounce_limit(p->queue, BLK_BOUNCE_HIGH);
-
- if (disk->drive == -1) {
- for (disk->drive = 0; disk->drive <= 1; disk->drive++) {
- ret = pd_special_command(disk, pd_identify);
- if (ret == 0)
- break;
- }
- } else {
- ret = pd_special_command(disk, pd_identify);
- }
- if (ret)
- goto put_disk;
- set_capacity(disk->gd, disk->capacity);
- ret = add_disk(disk->gd);
- if (ret)
- goto cleanup_disk;
- return 0;
-cleanup_disk:
- put_disk(disk->gd);
-put_disk:
- put_disk(p);
- disk->gd = NULL;
-free_tag_set:
- blk_mq_free_tag_set(&disk->tag_set);
-pi_release:
- pi_release(disk->pi);
- return ret;
-}
-
-static int __init pd_init(void)
-{
- int found = 0, unit, pd_drive_count = 0;
- struct pd_unit *disk;
-
- if (disable)
- return -ENODEV;
-
- if (register_blkdev(major, name))
- return -ENODEV;
-
- printk("%s: %s version %s, major %d, cluster %d, nice %d\n",
- name, name, PD_VERSION, major, cluster, nice);
-
- par_drv = pi_register_driver(name);
- if (!par_drv) {
- pr_err("failed to register %s driver\n", name);
- goto out_unregister_blkdev;
- }
-
- for (unit = 0; unit < PD_UNITS; unit++) {
- int *parm = *drives[unit];
-
- if (parm[D_PRT])
- pd_drive_count++;
- }
-
- if (pd_drive_count == 0) { /* nothing spec'd - so autoprobe for 1 */
- if (!pd_probe_drive(pd, 1, -1, -1, -1, -1, -1))
- found++;
- } else {
- for (unit = 0, disk = pd; unit < PD_UNITS; unit++, disk++) {
- int *parm = *drives[unit];
- if (!parm[D_PRT])
- continue;
- if (!pd_probe_drive(disk, 0, parm[D_PRT], parm[D_MOD],
- parm[D_UNI], parm[D_PRO], parm[D_DLY]))
- found++;
- }
- }
- if (!found) {
- printk("%s: no valid drive found\n", name);
- goto out_pi_unregister_driver;
- }
-
- return 0;
-
-out_pi_unregister_driver:
- pi_unregister_driver(par_drv);
-out_unregister_blkdev:
- unregister_blkdev(major, name);
- return -ENODEV;
-}
-
-static void __exit pd_exit(void)
-{
- struct pd_unit *disk;
- int unit;
- unregister_blkdev(major, name);
- for (unit = 0, disk = pd; unit < PD_UNITS; unit++, disk++) {
- struct gendisk *p = disk->gd;
- if (p) {
- disk->gd = NULL;
- del_gendisk(p);
- put_disk(p);
- blk_mq_free_tag_set(&disk->tag_set);
- pi_release(disk->pi);
- }
- }
-}
-
-MODULE_LICENSE("GPL");
-module_init(pd_init)
-module_exit(pd_exit)
diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c
deleted file mode 100644
index eec1b9fde245..000000000000
--- a/drivers/block/paride/pf.c
+++ /dev/null
@@ -1,1057 +0,0 @@
-/*
- pf.c (c) 1997-8 Grant R. Guenther <[email protected]>
- Under the terms of the GNU General Public License.
-
- This is the high-level driver for parallel port ATAPI disk
- drives based on chips supported by the paride module.
-
- By default, the driver will autoprobe for a single parallel
- port ATAPI disk drive, but if their individual parameters are
- specified, the driver can handle up to 4 drives.
-
- The behaviour of the pf driver can be altered by setting
- some parameters from the insmod command line. The following
- parameters are adjustable:
-
- drive0 These four arguments can be arrays of
- drive1 1-7 integers as follows:
- drive2
- drive3 <prt>,<pro>,<uni>,<mod>,<slv>,<lun>,<dly>
-
- Where,
-
- <prt> is the base of the parallel port address for
- the corresponding drive. (required)
-
- <pro> is the protocol number for the adapter that
- supports this drive. These numbers are
- logged by 'paride' when the protocol modules
- are initialised. (0 if not given)
-
- <uni> for those adapters that support chained
- devices, this is the unit selector for the
- chain of devices on the given port. It should
- be zero for devices that don't support chaining.
- (0 if not given)
-
- <mod> this can be -1 to choose the best mode, or one
- of the mode numbers supported by the adapter.
- (-1 if not given)
-
- <slv> ATAPI CDroms can be jumpered to master or slave.
- Set this to 0 to choose the master drive, 1 to
- choose the slave, -1 (the default) to choose the
- first drive found.
-
- <lun> Some ATAPI devices support multiple LUNs.
- One example is the ATAPI PD/CD drive from
- Matshita/Panasonic. This device has a
- CD drive on LUN 0 and a PD drive on LUN 1.
- By default, the driver will search for the
- first LUN with a supported device. Set
- this parameter to force it to use a specific
- LUN. (default -1)
-
- <dly> some parallel ports require the driver to
- go more slowly. -1 sets a default value that
- should work with the chosen protocol. Otherwise,
- set this to a small integer, the larger it is
- the slower the port i/o. In some cases, setting
- this to zero will speed up the device. (default -1)
-
- major You may use this parameter to override the
- default major number (47) that this driver
- will use. Be sure to change the device
- name as well.
-
- name This parameter is a character string that
- contains the name the kernel will use for this
- device (in /proc output, for instance).
- (default "pf").
-
- cluster The driver will attempt to aggregate requests
- for adjacent blocks into larger multi-block
- clusters. The maximum cluster size (in 512
- byte sectors) is set with this parameter.
- (default 64)
-
- verbose This parameter controls the amount of logging
- that the driver will do. Set it to 0 for
- normal operation, 1 to see autoprobe progress
- messages, or 2 to see additional debugging
- output. (default 0)
-
- nice This parameter controls the driver's use of
- idle CPU time, at the expense of some speed.
-
- If this driver is built into the kernel, you can use the
- following command line parameters, with the same values
- as the corresponding module parameters listed above:
-
- pf.drive0
- pf.drive1
- pf.drive2
- pf.drive3
- pf.cluster
- pf.nice
-
- In addition, you can use the parameter pf.disable to disable
- the driver entirely.
-
-*/
-
-/* Changes:
-
- 1.01 GRG 1998.05.03 Changes for SMP. Eliminate sti().
- Fix for drives that don't clear STAT_ERR
- until after next CDB delivered.
- Small change in pf_completion to round
- up transfer size.
- 1.02 GRG 1998.06.16 Eliminated an Ugh
- 1.03 GRG 1998.08.16 Use HZ in loop timings, extra debugging
- 1.04 GRG 1998.09.24 Added jumbo support
-
-*/
-
-#define PF_VERSION "1.04"
-#define PF_MAJOR 47
-#define PF_NAME "pf"
-#define PF_UNITS 4
-
-#include <linux/types.h>
-
-/* Here are things one can override from the insmod command.
- Most are autoprobed by paride unless set here. Verbose is off
- by default.
-
-*/
-
-static bool verbose = 0;
-static int major = PF_MAJOR;
-static char *name = PF_NAME;
-static int cluster = 64;
-static int nice = 0;
-static int disable = 0;
-
-static int drive0[7] = { 0, 0, 0, -1, -1, -1, -1 };
-static int drive1[7] = { 0, 0, 0, -1, -1, -1, -1 };
-static int drive2[7] = { 0, 0, 0, -1, -1, -1, -1 };
-static int drive3[7] = { 0, 0, 0, -1, -1, -1, -1 };
-
-static int (*drives[4])[7] = {&drive0, &drive1, &drive2, &drive3};
-static int pf_drive_count;
-
-enum {D_PRT, D_PRO, D_UNI, D_MOD, D_SLV, D_LUN, D_DLY};
-
-/* end of parameters */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/fs.h>
-#include <linux/delay.h>
-#include <linux/hdreg.h>
-#include <linux/cdrom.h>
-#include <linux/spinlock.h>
-#include <linux/blk-mq.h>
-#include <linux/blkpg.h>
-#include <linux/mutex.h>
-#include <linux/uaccess.h>
-
-static DEFINE_MUTEX(pf_mutex);
-static DEFINE_SPINLOCK(pf_spin_lock);
-
-module_param(verbose, bool, 0644);
-module_param(major, int, 0);
-module_param(name, charp, 0);
-module_param(cluster, int, 0);
-module_param(nice, int, 0);
-module_param_array(drive0, int, NULL, 0);
-module_param_array(drive1, int, NULL, 0);
-module_param_array(drive2, int, NULL, 0);
-module_param_array(drive3, int, NULL, 0);
-
-#include "paride.h"
-#include "pseudo.h"
-
-/* constants for faking geometry numbers */
-
-#define PF_FD_MAX 8192 /* use FD geometry under this size */
-#define PF_FD_HDS 2
-#define PF_FD_SPT 18
-#define PF_HD_HDS 64
-#define PF_HD_SPT 32
-
-#define PF_MAX_RETRIES 5
-#define PF_TMO 800 /* interrupt timeout in jiffies */
-#define PF_SPIN_DEL 50 /* spin delay in micro-seconds */
-
-#define PF_SPIN (1000000*PF_TMO)/(HZ*PF_SPIN_DEL)
-
-#define STAT_ERR 0x00001
-#define STAT_INDEX 0x00002
-#define STAT_ECC 0x00004
-#define STAT_DRQ 0x00008
-#define STAT_SEEK 0x00010
-#define STAT_WRERR 0x00020
-#define STAT_READY 0x00040
-#define STAT_BUSY 0x00080
-
-#define ATAPI_REQ_SENSE 0x03
-#define ATAPI_LOCK 0x1e
-#define ATAPI_DOOR 0x1b
-#define ATAPI_MODE_SENSE 0x5a
-#define ATAPI_CAPACITY 0x25
-#define ATAPI_IDENTIFY 0x12
-#define ATAPI_READ_10 0x28
-#define ATAPI_WRITE_10 0x2a
-
-static int pf_open(struct block_device *bdev, fmode_t mode);
-static blk_status_t pf_queue_rq(struct blk_mq_hw_ctx *hctx,
- const struct blk_mq_queue_data *bd);
-static int pf_ioctl(struct block_device *bdev, fmode_t mode,
- unsigned int cmd, unsigned long arg);
-static int pf_getgeo(struct block_device *bdev, struct hd_geometry *geo);
-
-static void pf_release(struct gendisk *disk, fmode_t mode);
-
-static void do_pf_read(void);
-static void do_pf_read_start(void);
-static void do_pf_write(void);
-static void do_pf_write_start(void);
-static void do_pf_read_drq(void);
-static void do_pf_write_done(void);
-
-#define PF_NM 0
-#define PF_RO 1
-#define PF_RW 2
-
-#define PF_NAMELEN 8
-
-struct pf_unit {
- struct pi_adapter pia; /* interface to paride layer */
- struct pi_adapter *pi;
- int removable; /* removable media device ? */
- int media_status; /* media present ? WP ? */
- int drive; /* drive */
- int lun;
- int access; /* count of active opens ... */
- int present; /* device present ? */
- char name[PF_NAMELEN]; /* pf0, pf1, ... */
- struct gendisk *disk;
- struct blk_mq_tag_set tag_set;
- struct list_head rq_list;
-};
-
-static struct pf_unit units[PF_UNITS];
-
-static int pf_identify(struct pf_unit *pf);
-static void pf_lock(struct pf_unit *pf, int func);
-static void pf_eject(struct pf_unit *pf);
-static unsigned int pf_check_events(struct gendisk *disk,
- unsigned int clearing);
-
-static char pf_scratch[512]; /* scratch block buffer */
-
-/* the variables below are used mainly in the I/O request engine, which
- processes only one request at a time.
-*/
-
-static int pf_retries = 0; /* i/o error retry count */
-static int pf_busy = 0; /* request being processed ? */
-static struct request *pf_req; /* current request */
-static int pf_block; /* address of next requested block */
-static int pf_count; /* number of blocks still to do */
-static int pf_run; /* sectors in current cluster */
-static int pf_cmd; /* current command READ/WRITE */
-static struct pf_unit *pf_current;/* unit of current request */
-static int pf_mask; /* stopper for pseudo-int */
-static char *pf_buf; /* buffer for request in progress */
-static void *par_drv; /* reference of parport driver */
-
-/* kernel glue structures */
-
-static const struct block_device_operations pf_fops = {
- .owner = THIS_MODULE,
- .open = pf_open,
- .release = pf_release,
- .ioctl = pf_ioctl,
- .compat_ioctl = pf_ioctl,
- .getgeo = pf_getgeo,
- .check_events = pf_check_events,
-};
-
-static const struct blk_mq_ops pf_mq_ops = {
- .queue_rq = pf_queue_rq,
-};
-
-static int pf_open(struct block_device *bdev, fmode_t mode)
-{
- struct pf_unit *pf = bdev->bd_disk->private_data;
- int ret;
-
- mutex_lock(&pf_mutex);
- pf_identify(pf);
-
- ret = -ENODEV;
- if (pf->media_status == PF_NM)
- goto out;
-
- ret = -EROFS;
- if ((pf->media_status == PF_RO) && (mode & FMODE_WRITE))
- goto out;
-
- ret = 0;
- pf->access++;
- if (pf->removable)
- pf_lock(pf, 1);
-out:
- mutex_unlock(&pf_mutex);
- return ret;
-}
-
-static int pf_getgeo(struct block_device *bdev, struct hd_geometry *geo)
-{
- struct pf_unit *pf = bdev->bd_disk->private_data;
- sector_t capacity = get_capacity(pf->disk);
-
- if (capacity < PF_FD_MAX) {
- geo->cylinders = sector_div(capacity, PF_FD_HDS * PF_FD_SPT);
- geo->heads = PF_FD_HDS;
- geo->sectors = PF_FD_SPT;
- } else {
- geo->cylinders = sector_div(capacity, PF_HD_HDS * PF_HD_SPT);
- geo->heads = PF_HD_HDS;
- geo->sectors = PF_HD_SPT;
- }
-
- return 0;
-}
-
-static int pf_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg)
-{
- struct pf_unit *pf = bdev->bd_disk->private_data;
-
- if (cmd != CDROMEJECT)
- return -EINVAL;
-
- if (pf->access != 1)
- return -EBUSY;
- mutex_lock(&pf_mutex);
- pf_eject(pf);
- mutex_unlock(&pf_mutex);
-
- return 0;
-}
-
-static void pf_release(struct gendisk *disk, fmode_t mode)
-{
- struct pf_unit *pf = disk->private_data;
-
- mutex_lock(&pf_mutex);
- if (pf->access <= 0) {
- mutex_unlock(&pf_mutex);
- WARN_ON(1);
- return;
- }
-
- pf->access--;
-
- if (!pf->access && pf->removable)
- pf_lock(pf, 0);
-
- mutex_unlock(&pf_mutex);
-}
-
-static unsigned int pf_check_events(struct gendisk *disk, unsigned int clearing)
-{
- return DISK_EVENT_MEDIA_CHANGE;
-}
-
-static inline int status_reg(struct pf_unit *pf)
-{
- return pi_read_regr(pf->pi, 1, 6);
-}
-
-static inline int read_reg(struct pf_unit *pf, int reg)
-{
- return pi_read_regr(pf->pi, 0, reg);
-}
-
-static inline void write_reg(struct pf_unit *pf, int reg, int val)
-{
- pi_write_regr(pf->pi, 0, reg, val);
-}
-
-static int pf_wait(struct pf_unit *pf, int go, int stop, char *fun, char *msg)
-{
- int j, r, e, s, p;
-
- j = 0;
- while ((((r = status_reg(pf)) & go) || (stop && (!(r & stop))))
- && (j++ < PF_SPIN))
- udelay(PF_SPIN_DEL);
-
- if ((r & (STAT_ERR & stop)) || (j > PF_SPIN)) {
- s = read_reg(pf, 7);
- e = read_reg(pf, 1);
- p = read_reg(pf, 2);
- if (j > PF_SPIN)
- e |= 0x100;
- if (fun)
- printk("%s: %s %s: alt=0x%x stat=0x%x err=0x%x"
- " loop=%d phase=%d\n",
- pf->name, fun, msg, r, s, e, j, p);
- return (e << 8) + s;
- }
- return 0;
-}
-
-static int pf_command(struct pf_unit *pf, char *cmd, int dlen, char *fun)
-{
- pi_connect(pf->pi);
-
- write_reg(pf, 6, 0xa0+0x10*pf->drive);
-
- if (pf_wait(pf, STAT_BUSY | STAT_DRQ, 0, fun, "before command")) {
- pi_disconnect(pf->pi);
- return -1;
- }
-
- write_reg(pf, 4, dlen % 256);
- write_reg(pf, 5, dlen / 256);
- write_reg(pf, 7, 0xa0); /* ATAPI packet command */
-
- if (pf_wait(pf, STAT_BUSY, STAT_DRQ, fun, "command DRQ")) {
- pi_disconnect(pf->pi);
- return -1;
- }
-
- if (read_reg(pf, 2) != 1) {
- printk("%s: %s: command phase error\n", pf->name, fun);
- pi_disconnect(pf->pi);
- return -1;
- }
-
- pi_write_block(pf->pi, cmd, 12);
-
- return 0;
-}
-
-static int pf_completion(struct pf_unit *pf, char *buf, char *fun)
-{
- int r, s, n;
-
- r = pf_wait(pf, STAT_BUSY, STAT_DRQ | STAT_READY | STAT_ERR,
- fun, "completion");
-
- if ((read_reg(pf, 2) & 2) && (read_reg(pf, 7) & STAT_DRQ)) {
- n = (((read_reg(pf, 4) + 256 * read_reg(pf, 5)) +
- 3) & 0xfffc);
- pi_read_block(pf->pi, buf, n);
- }
-
- s = pf_wait(pf, STAT_BUSY, STAT_READY | STAT_ERR, fun, "data done");
-
- pi_disconnect(pf->pi);
-
- return (r ? r : s);
-}
-
-static void pf_req_sense(struct pf_unit *pf, int quiet)
-{
- char rs_cmd[12] =
- { ATAPI_REQ_SENSE, pf->lun << 5, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0 };
- char buf[16];
- int r;
-
- r = pf_command(pf, rs_cmd, 16, "Request sense");
- mdelay(1);
- if (!r)
- pf_completion(pf, buf, "Request sense");
-
- if ((!r) && (!quiet))
- printk("%s: Sense key: %x, ASC: %x, ASQ: %x\n",
- pf->name, buf[2] & 0xf, buf[12], buf[13]);
-}
-
-static int pf_atapi(struct pf_unit *pf, char *cmd, int dlen, char *buf, char *fun)
-{
- int r;
-
- r = pf_command(pf, cmd, dlen, fun);
- mdelay(1);
- if (!r)
- r = pf_completion(pf, buf, fun);
- if (r)
- pf_req_sense(pf, !fun);
-
- return r;
-}
-
-static void pf_lock(struct pf_unit *pf, int func)
-{
- char lo_cmd[12] = { ATAPI_LOCK, pf->lun << 5, 0, 0, func, 0, 0, 0, 0, 0, 0, 0 };
-
- pf_atapi(pf, lo_cmd, 0, pf_scratch, func ? "lock" : "unlock");
-}
-
-static void pf_eject(struct pf_unit *pf)
-{
- char ej_cmd[12] = { ATAPI_DOOR, pf->lun << 5, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0 };
-
- pf_lock(pf, 0);
- pf_atapi(pf, ej_cmd, 0, pf_scratch, "eject");
-}
-
-#define PF_RESET_TMO 30 /* in tenths of a second */
-
-static void pf_sleep(int cs)
-{
- schedule_timeout_interruptible(cs);
-}
-
-/* the ATAPI standard actually specifies the contents of all 7 registers
- after a reset, but the specification is ambiguous concerning the last
- two bytes, and different drives interpret the standard differently.
- */
-
-static int pf_reset(struct pf_unit *pf)
-{
- int i, k, flg;
- int expect[5] = { 1, 1, 1, 0x14, 0xeb };
-
- pi_connect(pf->pi);
- write_reg(pf, 6, 0xa0+0x10*pf->drive);
- write_reg(pf, 7, 8);
-
- pf_sleep(20 * HZ / 1000);
-
- k = 0;
- while ((k++ < PF_RESET_TMO) && (status_reg(pf) & STAT_BUSY))
- pf_sleep(HZ / 10);
-
- flg = 1;
- for (i = 0; i < 5; i++)
- flg &= (read_reg(pf, i + 1) == expect[i]);
-
- if (verbose) {
- printk("%s: Reset (%d) signature = ", pf->name, k);
- for (i = 0; i < 5; i++)
- printk("%3x", read_reg(pf, i + 1));
- if (!flg)
- printk(" (incorrect)");
- printk("\n");
- }
-
- pi_disconnect(pf->pi);
- return flg - 1;
-}
-
-static void pf_mode_sense(struct pf_unit *pf)
-{
- char ms_cmd[12] =
- { ATAPI_MODE_SENSE, pf->lun << 5, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0 };
- char buf[8];
-
- pf_atapi(pf, ms_cmd, 8, buf, "mode sense");
- pf->media_status = PF_RW;
- if (buf[3] & 0x80)
- pf->media_status = PF_RO;
-}
-
-static void xs(char *buf, char *targ, int offs, int len)
-{
- int j, k, l;
-
- j = 0;
- l = 0;
- for (k = 0; k < len; k++)
- if ((buf[k + offs] != 0x20) || (buf[k + offs] != l))
- l = targ[j++] = buf[k + offs];
- if (l == 0x20)
- j--;
- targ[j] = 0;
-}
-
-static int xl(char *buf, int offs)
-{
- int v, k;
-
- v = 0;
- for (k = 0; k < 4; k++)
- v = v * 256 + (buf[k + offs] & 0xff);
- return v;
-}
-
-static void pf_get_capacity(struct pf_unit *pf)
-{
- char rc_cmd[12] = { ATAPI_CAPACITY, pf->lun << 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
- char buf[8];
- int bs;
-
- if (pf_atapi(pf, rc_cmd, 8, buf, "get capacity")) {
- pf->media_status = PF_NM;
- return;
- }
- set_capacity(pf->disk, xl(buf, 0) + 1);
- bs = xl(buf, 4);
- if (bs != 512) {
- set_capacity(pf->disk, 0);
- if (verbose)
- printk("%s: Drive %d, LUN %d,"
- " unsupported block size %d\n",
- pf->name, pf->drive, pf->lun, bs);
- }
-}
-
-static int pf_identify(struct pf_unit *pf)
-{
- int dt, s;
- char *ms[2] = { "master", "slave" };
- char mf[10], id[18];
- char id_cmd[12] =
- { ATAPI_IDENTIFY, pf->lun << 5, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0 };
- char buf[36];
-
- s = pf_atapi(pf, id_cmd, 36, buf, "identify");
- if (s)
- return -1;
-
- dt = buf[0] & 0x1f;
- if ((dt != 0) && (dt != 7)) {
- if (verbose)
- printk("%s: Drive %d, LUN %d, unsupported type %d\n",
- pf->name, pf->drive, pf->lun, dt);
- return -1;
- }
-
- xs(buf, mf, 8, 8);
- xs(buf, id, 16, 16);
-
- pf->removable = (buf[1] & 0x80);
-
- pf_mode_sense(pf);
- pf_mode_sense(pf);
- pf_mode_sense(pf);
-
- pf_get_capacity(pf);
-
- printk("%s: %s %s, %s LUN %d, type %d",
- pf->name, mf, id, ms[pf->drive], pf->lun, dt);
- if (pf->removable)
- printk(", removable");
- if (pf->media_status == PF_NM)
- printk(", no media\n");
- else {
- if (pf->media_status == PF_RO)
- printk(", RO");
- printk(", %llu blocks\n",
- (unsigned long long)get_capacity(pf->disk));
- }
- return 0;
-}
-
-/*
- * returns 0, with id set if drive is detected, otherwise an error code.
- */
-static int pf_probe(struct pf_unit *pf)
-{
- if (pf->drive == -1) {
- for (pf->drive = 0; pf->drive <= 1; pf->drive++)
- if (!pf_reset(pf)) {
- if (pf->lun != -1)
- return pf_identify(pf);
- else
- for (pf->lun = 0; pf->lun < 8; pf->lun++)
- if (!pf_identify(pf))
- return 0;
- }
- } else {
- if (pf_reset(pf))
- return -1;
- if (pf->lun != -1)
- return pf_identify(pf);
- for (pf->lun = 0; pf->lun < 8; pf->lun++)
- if (!pf_identify(pf))
- return 0;
- }
- return -ENODEV;
-}
-
-/* The i/o request engine */
-
-static int pf_start(struct pf_unit *pf, int cmd, int b, int c)
-{
- int i;
- char io_cmd[12] = { cmd, pf->lun << 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
-
- for (i = 0; i < 4; i++) {
- io_cmd[5 - i] = b & 0xff;
- b = b >> 8;
- }
-
- io_cmd[8] = c & 0xff;
- io_cmd[7] = (c >> 8) & 0xff;
-
- i = pf_command(pf, io_cmd, c * 512, "start i/o");
-
- mdelay(1);
-
- return i;
-}
-
-static int pf_ready(void)
-{
- return (((status_reg(pf_current) & (STAT_BUSY | pf_mask)) == pf_mask));
-}
-
-static int pf_queue;
-
-static int set_next_request(void)
-{
- struct pf_unit *pf;
- int old_pos = pf_queue;
-
- do {
- pf = &units[pf_queue];
- if (++pf_queue == PF_UNITS)
- pf_queue = 0;
- if (pf->present && !list_empty(&pf->rq_list)) {
- pf_req = list_first_entry(&pf->rq_list, struct request,
- queuelist);
- list_del_init(&pf_req->queuelist);
- blk_mq_start_request(pf_req);
- break;
- }
- } while (pf_queue != old_pos);
-
- return pf_req != NULL;
-}
-
-static void pf_end_request(blk_status_t err)
-{
- if (!pf_req)
- return;
- if (!blk_update_request(pf_req, err, blk_rq_cur_bytes(pf_req))) {
- __blk_mq_end_request(pf_req, err);
- pf_req = NULL;
- }
-}
-
-static void pf_request(void)
-{
- if (pf_busy)
- return;
-repeat:
- if (!pf_req && !set_next_request())
- return;
-
- pf_current = pf_req->q->disk->private_data;
- pf_block = blk_rq_pos(pf_req);
- pf_run = blk_rq_sectors(pf_req);
- pf_count = blk_rq_cur_sectors(pf_req);
-
- if (pf_block + pf_count > get_capacity(pf_req->q->disk)) {
- pf_end_request(BLK_STS_IOERR);
- goto repeat;
- }
-
- pf_cmd = rq_data_dir(pf_req);
- pf_buf = bio_data(pf_req->bio);
- pf_retries = 0;
-
- pf_busy = 1;
- if (pf_cmd == READ)
- pi_do_claimed(pf_current->pi, do_pf_read);
- else if (pf_cmd == WRITE)
- pi_do_claimed(pf_current->pi, do_pf_write);
- else {
- pf_busy = 0;
- pf_end_request(BLK_STS_IOERR);
- goto repeat;
- }
-}
-
-static blk_status_t pf_queue_rq(struct blk_mq_hw_ctx *hctx,
- const struct blk_mq_queue_data *bd)
-{
- struct pf_unit *pf = hctx->queue->queuedata;
-
- spin_lock_irq(&pf_spin_lock);
- list_add_tail(&bd->rq->queuelist, &pf->rq_list);
- pf_request();
- spin_unlock_irq(&pf_spin_lock);
-
- return BLK_STS_OK;
-}
-
-static int pf_next_buf(void)
-{
- unsigned long saved_flags;
-
- pf_count--;
- pf_run--;
- pf_buf += 512;
- pf_block++;
- if (!pf_run)
- return 1;
- if (!pf_count) {
- spin_lock_irqsave(&pf_spin_lock, saved_flags);
- pf_end_request(0);
- spin_unlock_irqrestore(&pf_spin_lock, saved_flags);
- if (!pf_req)
- return 1;
- pf_count = blk_rq_cur_sectors(pf_req);
- pf_buf = bio_data(pf_req->bio);
- }
- return 0;
-}
-
-static inline void next_request(blk_status_t err)
-{
- unsigned long saved_flags;
-
- spin_lock_irqsave(&pf_spin_lock, saved_flags);
- pf_end_request(err);
- pf_busy = 0;
- pf_request();
- spin_unlock_irqrestore(&pf_spin_lock, saved_flags);
-}
-
-/* detach from the calling context - in case the spinlock is held */
-static void do_pf_read(void)
-{
- ps_set_intr(do_pf_read_start, NULL, 0, nice);
-}
-
-static void do_pf_read_start(void)
-{
- pf_busy = 1;
-
- if (pf_start(pf_current, ATAPI_READ_10, pf_block, pf_run)) {
- pi_disconnect(pf_current->pi);
- if (pf_retries < PF_MAX_RETRIES) {
- pf_retries++;
- pi_do_claimed(pf_current->pi, do_pf_read_start);
- return;
- }
- next_request(BLK_STS_IOERR);
- return;
- }
- pf_mask = STAT_DRQ;
- ps_set_intr(do_pf_read_drq, pf_ready, PF_TMO, nice);
-}
-
-static void do_pf_read_drq(void)
-{
- while (1) {
- if (pf_wait(pf_current, STAT_BUSY, STAT_DRQ | STAT_ERR,
- "read block", "completion") & STAT_ERR) {
- pi_disconnect(pf_current->pi);
- if (pf_retries < PF_MAX_RETRIES) {
- pf_req_sense(pf_current, 0);
- pf_retries++;
- pi_do_claimed(pf_current->pi, do_pf_read_start);
- return;
- }
- next_request(BLK_STS_IOERR);
- return;
- }
- pi_read_block(pf_current->pi, pf_buf, 512);
- if (pf_next_buf())
- break;
- }
- pi_disconnect(pf_current->pi);
- next_request(0);
-}
-
-static void do_pf_write(void)
-{
- ps_set_intr(do_pf_write_start, NULL, 0, nice);
-}
-
-static void do_pf_write_start(void)
-{
- pf_busy = 1;
-
- if (pf_start(pf_current, ATAPI_WRITE_10, pf_block, pf_run)) {
- pi_disconnect(pf_current->pi);
- if (pf_retries < PF_MAX_RETRIES) {
- pf_retries++;
- pi_do_claimed(pf_current->pi, do_pf_write_start);
- return;
- }
- next_request(BLK_STS_IOERR);
- return;
- }
-
- while (1) {
- if (pf_wait(pf_current, STAT_BUSY, STAT_DRQ | STAT_ERR,
- "write block", "data wait") & STAT_ERR) {
- pi_disconnect(pf_current->pi);
- if (pf_retries < PF_MAX_RETRIES) {
- pf_retries++;
- pi_do_claimed(pf_current->pi, do_pf_write_start);
- return;
- }
- next_request(BLK_STS_IOERR);
- return;
- }
- pi_write_block(pf_current->pi, pf_buf, 512);
- if (pf_next_buf())
- break;
- }
- pf_mask = 0;
- ps_set_intr(do_pf_write_done, pf_ready, PF_TMO, nice);
-}
-
-static void do_pf_write_done(void)
-{
- if (pf_wait(pf_current, STAT_BUSY, 0, "write block", "done") & STAT_ERR) {
- pi_disconnect(pf_current->pi);
- if (pf_retries < PF_MAX_RETRIES) {
- pf_retries++;
- pi_do_claimed(pf_current->pi, do_pf_write_start);
- return;
- }
- next_request(BLK_STS_IOERR);
- return;
- }
- pi_disconnect(pf_current->pi);
- next_request(0);
-}
-
-static int __init pf_init_unit(struct pf_unit *pf, bool autoprobe, int port,
- int mode, int unit, int protocol, int delay, int ms)
-{
- struct gendisk *disk;
- int ret;
-
- ret = blk_mq_alloc_sq_tag_set(&pf->tag_set, &pf_mq_ops, 1,
- BLK_MQ_F_SHOULD_MERGE);
- if (ret)
- return ret;
-
- disk = blk_mq_alloc_disk(&pf->tag_set, pf);
- if (IS_ERR(disk)) {
- ret = PTR_ERR(disk);
- goto out_free_tag_set;
- }
- disk->major = major;
- disk->first_minor = pf - units;
- disk->minors = 1;
- strcpy(disk->disk_name, pf->name);
- disk->fops = &pf_fops;
- disk->flags |= GENHD_FL_NO_PART;
- disk->events = DISK_EVENT_MEDIA_CHANGE;
- disk->private_data = pf;
-
- blk_queue_max_segments(disk->queue, cluster);
- blk_queue_bounce_limit(disk->queue, BLK_BOUNCE_HIGH);
-
- INIT_LIST_HEAD(&pf->rq_list);
- pf->disk = disk;
- pf->pi = &pf->pia;
- pf->media_status = PF_NM;
- pf->drive = (*drives[disk->first_minor])[D_SLV];
- pf->lun = (*drives[disk->first_minor])[D_LUN];
- snprintf(pf->name, PF_NAMELEN, "%s%d", name, disk->first_minor);
-
- if (!pi_init(pf->pi, autoprobe, port, mode, unit, protocol, delay,
- pf_scratch, PI_PF, verbose, pf->name)) {
- ret = -ENODEV;
- goto out_free_disk;
- }
- ret = pf_probe(pf);
- if (ret)
- goto out_pi_release;
-
- ret = add_disk(disk);
- if (ret)
- goto out_pi_release;
- pf->present = 1;
- return 0;
-
-out_pi_release:
- pi_release(pf->pi);
-out_free_disk:
- put_disk(pf->disk);
-out_free_tag_set:
- blk_mq_free_tag_set(&pf->tag_set);
- return ret;
-}
-
-static int __init pf_init(void)
-{ /* preliminary initialisation */
- struct pf_unit *pf;
- int found = 0, unit;
-
- if (disable)
- return -EINVAL;
-
- if (register_blkdev(major, name))
- return -EBUSY;
-
- printk("%s: %s version %s, major %d, cluster %d, nice %d\n",
- name, name, PF_VERSION, major, cluster, nice);
-
- par_drv = pi_register_driver(name);
- if (!par_drv) {
- pr_err("failed to register %s driver\n", name);
- goto out_unregister_blkdev;
- }
-
- for (unit = 0; unit < PF_UNITS; unit++) {
- if (!(*drives[unit])[D_PRT])
- pf_drive_count++;
- }
-
- pf = units;
- if (pf_drive_count == 0) {
- if (pf_init_unit(pf, 1, -1, -1, -1, -1, -1, verbose))
- found++;
- } else {
- for (unit = 0; unit < PF_UNITS; unit++, pf++) {
- int *conf = *drives[unit];
- if (!conf[D_PRT])
- continue;
- if (pf_init_unit(pf, 0, conf[D_PRT], conf[D_MOD],
- conf[D_UNI], conf[D_PRO], conf[D_DLY],
- verbose))
- found++;
- }
- }
- if (!found) {
- printk("%s: No ATAPI disk detected\n", name);
- goto out_unregister_pi_driver;
- }
- pf_busy = 0;
- return 0;
-
-out_unregister_pi_driver:
- pi_unregister_driver(par_drv);
-out_unregister_blkdev:
- unregister_blkdev(major, name);
- return -ENODEV;
-}
-
-static void __exit pf_exit(void)
-{
- struct pf_unit *pf;
- int unit;
-
- for (pf = units, unit = 0; unit < PF_UNITS; pf++, unit++) {
- if (!pf->present)
- continue;
- del_gendisk(pf->disk);
- put_disk(pf->disk);
- blk_mq_free_tag_set(&pf->tag_set);
- pi_release(pf->pi);
- }
-
- unregister_blkdev(major, name);
-}
-
-MODULE_LICENSE("GPL");
-module_init(pf_init)
-module_exit(pf_exit)
diff --git a/drivers/block/paride/pg.c b/drivers/block/paride/pg.c
deleted file mode 100644
index 3b5882bfb736..000000000000
--- a/drivers/block/paride/pg.c
+++ /dev/null
@@ -1,734 +0,0 @@
-/*
- pg.c (c) 1998 Grant R. Guenther <[email protected]>
- Under the terms of the GNU General Public License.
-
- The pg driver provides a simple character device interface for
- sending ATAPI commands to a device. With the exception of the
- ATAPI reset operation, all operations are performed by a pair
- of read and write operations to the appropriate /dev/pgN device.
- A write operation delivers a command and any outbound data in
- a single buffer. Normally, the write will succeed unless the
- device is offline or malfunctioning, or there is already another
- command pending. If the write succeeds, it should be followed
- immediately by a read operation, to obtain any returned data and
- status information. A read will fail if there is no operation
- in progress.
-
- As a special case, the device can be reset with a write operation,
- and in this case, no following read is expected, or permitted.
-
- There are no ioctl() operations. Any single operation
- may transfer at most PG_MAX_DATA bytes. Note that the driver must
- copy the data through an internal buffer. In keeping with all
- current ATAPI devices, command packets are assumed to be exactly
- 12 bytes in length.
-
- To permit future changes to this interface, the headers in the
- read and write buffers contain a single character "magic" flag.
- Currently this flag must be the character "P".
-
- By default, the driver will autoprobe for a single parallel
- port ATAPI device, but if their individual parameters are
- specified, the driver can handle up to 4 devices.
-
- To use this device, you must have the following device
- special files defined:
-
- /dev/pg0 c 97 0
- /dev/pg1 c 97 1
- /dev/pg2 c 97 2
- /dev/pg3 c 97 3
-
- (You'll need to change the 97 to something else if you use
- the 'major' parameter to install the driver on a different
- major number.)
-
- The behaviour of the pg driver can be altered by setting
- some parameters from the insmod command line. The following
- parameters are adjustable:
-
- drive0 These four arguments can be arrays of
- drive1 1-6 integers as follows:
- drive2
- drive3 <prt>,<pro>,<uni>,<mod>,<slv>,<dly>
-
- Where,
-
- <prt> is the base of the parallel port address for
- the corresponding drive. (required)
-
- <pro> is the protocol number for the adapter that
- supports this drive. These numbers are
- logged by 'paride' when the protocol modules
- are initialised. (0 if not given)
-
- <uni> for those adapters that support chained
- devices, this is the unit selector for the
- chain of devices on the given port. It should
- be zero for devices that don't support chaining.
- (0 if not given)
-
- <mod> this can be -1 to choose the best mode, or one
- of the mode numbers supported by the adapter.
- (-1 if not given)
-
- <slv> ATAPI devices can be jumpered to master or slave.
- Set this to 0 to choose the master drive, 1 to
- choose the slave, -1 (the default) to choose the
- first drive found.
-
- <dly> some parallel ports require the driver to
- go more slowly. -1 sets a default value that
- should work with the chosen protocol. Otherwise,
- set this to a small integer, the larger it is
- the slower the port i/o. In some cases, setting
- this to zero will speed up the device. (default -1)
-
- major You may use this parameter to override the
- default major number (97) that this driver
- will use. Be sure to change the device
- name as well.
-
- name This parameter is a character string that
- contains the name the kernel will use for this
- device (in /proc output, for instance).
- (default "pg").
-
- verbose This parameter controls the amount of logging
- that is done by the driver. Set it to 0 for
- quiet operation, to 1 to enable progress
- messages while the driver probes for devices,
- or to 2 for full debug logging. (default 0)
-
- If this driver is built into the kernel, you can use
- the following command line parameters, with the same values
- as the corresponding module parameters listed above:
-
- pg.drive0
- pg.drive1
- pg.drive2
- pg.drive3
-
- In addition, you can use the parameter pg.disable to disable
- the driver entirely.
-
-*/
-
-/* Changes:
-
- 1.01 GRG 1998.06.16 Bug fixes
- 1.02 GRG 1998.09.24 Added jumbo support
-
-*/
-
-#define PG_VERSION "1.02"
-#define PG_MAJOR 97
-#define PG_NAME "pg"
-#define PG_UNITS 4
-
-#ifndef PI_PG
-#define PI_PG 4
-#endif
-
-#include <linux/types.h>
-/* Here are things one can override from the insmod command.
- Most are autoprobed by paride unless set here. Verbose is 0
- by default.
-
-*/
-
-static int verbose;
-static int major = PG_MAJOR;
-static char *name = PG_NAME;
-static int disable = 0;
-
-static int drive0[6] = { 0, 0, 0, -1, -1, -1 };
-static int drive1[6] = { 0, 0, 0, -1, -1, -1 };
-static int drive2[6] = { 0, 0, 0, -1, -1, -1 };
-static int drive3[6] = { 0, 0, 0, -1, -1, -1 };
-
-static int (*drives[4])[6] = {&drive0, &drive1, &drive2, &drive3};
-static int pg_drive_count;
-
-enum {D_PRT, D_PRO, D_UNI, D_MOD, D_SLV, D_DLY};
-
-/* end of parameters */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/fs.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/mtio.h>
-#include <linux/pg.h>
-#include <linux/device.h>
-#include <linux/sched.h> /* current, TASK_* */
-#include <linux/mutex.h>
-#include <linux/jiffies.h>
-
-#include <linux/uaccess.h>
-
-module_param(verbose, int, 0644);
-module_param(major, int, 0);
-module_param(name, charp, 0);
-module_param_array(drive0, int, NULL, 0);
-module_param_array(drive1, int, NULL, 0);
-module_param_array(drive2, int, NULL, 0);
-module_param_array(drive3, int, NULL, 0);
-
-#include "paride.h"
-
-#define PG_SPIN_DEL 50 /* spin delay in micro-seconds */
-#define PG_SPIN 200
-#define PG_TMO HZ
-#define PG_RESET_TMO 10*HZ
-
-#define STAT_ERR 0x01
-#define STAT_INDEX 0x02
-#define STAT_ECC 0x04
-#define STAT_DRQ 0x08
-#define STAT_SEEK 0x10
-#define STAT_WRERR 0x20
-#define STAT_READY 0x40
-#define STAT_BUSY 0x80
-
-#define ATAPI_IDENTIFY 0x12
-
-static DEFINE_MUTEX(pg_mutex);
-static int pg_open(struct inode *inode, struct file *file);
-static int pg_release(struct inode *inode, struct file *file);
-static ssize_t pg_read(struct file *filp, char __user *buf,
- size_t count, loff_t * ppos);
-static ssize_t pg_write(struct file *filp, const char __user *buf,
- size_t count, loff_t * ppos);
-static int pg_detect(void);
-
-#define PG_NAMELEN 8
-
-struct pg {
- struct pi_adapter pia; /* interface to paride layer */
- struct pi_adapter *pi;
- int busy; /* write done, read expected */
- int start; /* jiffies at command start */
- int dlen; /* transfer size requested */
- unsigned long timeout; /* timeout requested */
- int status; /* last sense key */
- int drive; /* drive */
- unsigned long access; /* count of active opens ... */
- int present; /* device present ? */
- char *bufptr;
- char name[PG_NAMELEN]; /* pg0, pg1, ... */
-};
-
-static struct pg devices[PG_UNITS];
-
-static int pg_identify(struct pg *dev, int log);
-
-static char pg_scratch[512]; /* scratch block buffer */
-
-static struct class *pg_class;
-static void *par_drv; /* reference of parport driver */
-
-/* kernel glue structures */
-
-static const struct file_operations pg_fops = {
- .owner = THIS_MODULE,
- .read = pg_read,
- .write = pg_write,
- .open = pg_open,
- .release = pg_release,
- .llseek = noop_llseek,
-};
-
-static void pg_init_units(void)
-{
- int unit;
-
- pg_drive_count = 0;
- for (unit = 0; unit < PG_UNITS; unit++) {
- int *parm = *drives[unit];
- struct pg *dev = &devices[unit];
- dev->pi = &dev->pia;
- clear_bit(0, &dev->access);
- dev->busy = 0;
- dev->present = 0;
- dev->bufptr = NULL;
- dev->drive = parm[D_SLV];
- snprintf(dev->name, PG_NAMELEN, "%s%c", name, 'a'+unit);
- if (parm[D_PRT])
- pg_drive_count++;
- }
-}
-
-static inline int status_reg(struct pg *dev)
-{
- return pi_read_regr(dev->pi, 1, 6);
-}
-
-static inline int read_reg(struct pg *dev, int reg)
-{
- return pi_read_regr(dev->pi, 0, reg);
-}
-
-static inline void write_reg(struct pg *dev, int reg, int val)
-{
- pi_write_regr(dev->pi, 0, reg, val);
-}
-
-static inline u8 DRIVE(struct pg *dev)
-{
- return 0xa0+0x10*dev->drive;
-}
-
-static void pg_sleep(int cs)
-{
- schedule_timeout_interruptible(cs);
-}
-
-static int pg_wait(struct pg *dev, int go, int stop, unsigned long tmo, char *msg)
-{
- int j, r, e, s, p, to;
-
- dev->status = 0;
-
- j = 0;
- while ((((r = status_reg(dev)) & go) || (stop && (!(r & stop))))
- && time_before(jiffies, tmo)) {
- if (j++ < PG_SPIN)
- udelay(PG_SPIN_DEL);
- else
- pg_sleep(1);
- }
-
- to = time_after_eq(jiffies, tmo);
-
- if ((r & (STAT_ERR & stop)) || to) {
- s = read_reg(dev, 7);
- e = read_reg(dev, 1);
- p = read_reg(dev, 2);
- if (verbose > 1)
- printk("%s: %s: stat=0x%x err=0x%x phase=%d%s\n",
- dev->name, msg, s, e, p, to ? " timeout" : "");
- if (to)
- e |= 0x100;
- dev->status = (e >> 4) & 0xff;
- return -1;
- }
- return 0;
-}
-
-static int pg_command(struct pg *dev, char *cmd, int dlen, unsigned long tmo)
-{
- int k;
-
- pi_connect(dev->pi);
-
- write_reg(dev, 6, DRIVE(dev));
-
- if (pg_wait(dev, STAT_BUSY | STAT_DRQ, 0, tmo, "before command"))
- goto fail;
-
- write_reg(dev, 4, dlen % 256);
- write_reg(dev, 5, dlen / 256);
- write_reg(dev, 7, 0xa0); /* ATAPI packet command */
-
- if (pg_wait(dev, STAT_BUSY, STAT_DRQ, tmo, "command DRQ"))
- goto fail;
-
- if (read_reg(dev, 2) != 1) {
- printk("%s: command phase error\n", dev->name);
- goto fail;
- }
-
- pi_write_block(dev->pi, cmd, 12);
-
- if (verbose > 1) {
- printk("%s: Command sent, dlen=%d packet= ", dev->name, dlen);
- for (k = 0; k < 12; k++)
- printk("%02x ", cmd[k] & 0xff);
- printk("\n");
- }
- return 0;
-fail:
- pi_disconnect(dev->pi);
- return -1;
-}
-
-static int pg_completion(struct pg *dev, char *buf, unsigned long tmo)
-{
- int r, d, n, p;
-
- r = pg_wait(dev, STAT_BUSY, STAT_DRQ | STAT_READY | STAT_ERR,
- tmo, "completion");
-
- dev->dlen = 0;
-
- while (read_reg(dev, 7) & STAT_DRQ) {
- d = (read_reg(dev, 4) + 256 * read_reg(dev, 5));
- n = ((d + 3) & 0xfffc);
- p = read_reg(dev, 2) & 3;
- if (p == 0)
- pi_write_block(dev->pi, buf, n);
- if (p == 2)
- pi_read_block(dev->pi, buf, n);
- if (verbose > 1)
- printk("%s: %s %d bytes\n", dev->name,
- p ? "Read" : "Write", n);
- dev->dlen += (1 - p) * d;
- buf += d;
- r = pg_wait(dev, STAT_BUSY, STAT_DRQ | STAT_READY | STAT_ERR,
- tmo, "completion");
- }
-
- pi_disconnect(dev->pi);
-
- return r;
-}
-
-static int pg_reset(struct pg *dev)
-{
- int i, k, err;
- int expect[5] = { 1, 1, 1, 0x14, 0xeb };
- int got[5];
-
- pi_connect(dev->pi);
- write_reg(dev, 6, DRIVE(dev));
- write_reg(dev, 7, 8);
-
- pg_sleep(20 * HZ / 1000);
-
- k = 0;
- while ((k++ < PG_RESET_TMO) && (status_reg(dev) & STAT_BUSY))
- pg_sleep(1);
-
- for (i = 0; i < 5; i++)
- got[i] = read_reg(dev, i + 1);
-
- err = memcmp(expect, got, sizeof(got)) ? -1 : 0;
-
- if (verbose) {
- printk("%s: Reset (%d) signature = ", dev->name, k);
- for (i = 0; i < 5; i++)
- printk("%3x", got[i]);
- if (err)
- printk(" (incorrect)");
- printk("\n");
- }
-
- pi_disconnect(dev->pi);
- return err;
-}
-
-static void xs(char *buf, char *targ, int len)
-{
- char l = '\0';
- int k;
-
- for (k = 0; k < len; k++) {
- char c = *buf++;
- if (c != ' ' && c != l)
- l = *targ++ = c;
- }
- if (l == ' ')
- targ--;
- *targ = '\0';
-}
-
-static int pg_identify(struct pg *dev, int log)
-{
- int s;
- char *ms[2] = { "master", "slave" };
- char mf[10], id[18];
- char id_cmd[12] = { ATAPI_IDENTIFY, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0 };
- char buf[36];
-
- s = pg_command(dev, id_cmd, 36, jiffies + PG_TMO);
- if (s)
- return -1;
- s = pg_completion(dev, buf, jiffies + PG_TMO);
- if (s)
- return -1;
-
- if (log) {
- xs(buf + 8, mf, 8);
- xs(buf + 16, id, 16);
- printk("%s: %s %s, %s\n", dev->name, mf, id, ms[dev->drive]);
- }
-
- return 0;
-}
-
-/*
- * returns 0, with id set if drive is detected
- * -1, if drive detection failed
- */
-static int pg_probe(struct pg *dev)
-{
- if (dev->drive == -1) {
- for (dev->drive = 0; dev->drive <= 1; dev->drive++)
- if (!pg_reset(dev))
- return pg_identify(dev, 1);
- } else {
- if (!pg_reset(dev))
- return pg_identify(dev, 1);
- }
- return -1;
-}
-
-static int pg_detect(void)
-{
- struct pg *dev = &devices[0];
- int k, unit;
-
- printk("%s: %s version %s, major %d\n", name, name, PG_VERSION, major);
-
- par_drv = pi_register_driver(name);
- if (!par_drv) {
- pr_err("failed to register %s driver\n", name);
- return -1;
- }
-
- k = 0;
- if (pg_drive_count == 0) {
- if (pi_init(dev->pi, 1, -1, -1, -1, -1, -1, pg_scratch,
- PI_PG, verbose, dev->name)) {
- if (!pg_probe(dev)) {
- dev->present = 1;
- k++;
- } else
- pi_release(dev->pi);
- }
-
- } else
- for (unit = 0; unit < PG_UNITS; unit++, dev++) {
- int *parm = *drives[unit];
- if (!parm[D_PRT])
- continue;
- if (pi_init(dev->pi, 0, parm[D_PRT], parm[D_MOD],
- parm[D_UNI], parm[D_PRO], parm[D_DLY],
- pg_scratch, PI_PG, verbose, dev->name)) {
- if (!pg_probe(dev)) {
- dev->present = 1;
- k++;
- } else
- pi_release(dev->pi);
- }
- }
-
- if (k)
- return 0;
-
- pi_unregister_driver(par_drv);
- printk("%s: No ATAPI device detected\n", name);
- return -1;
-}
-
-static int pg_open(struct inode *inode, struct file *file)
-{
- int unit = iminor(inode) & 0x7f;
- struct pg *dev = &devices[unit];
- int ret = 0;
-
- mutex_lock(&pg_mutex);
- if ((unit >= PG_UNITS) || (!dev->present)) {
- ret = -ENODEV;
- goto out;
- }
-
- if (test_and_set_bit(0, &dev->access)) {
- ret = -EBUSY;
- goto out;
- }
-
- if (dev->busy) {
- pg_reset(dev);
- dev->busy = 0;
- }
-
- pg_identify(dev, (verbose > 1));
-
- dev->bufptr = kmalloc(PG_MAX_DATA, GFP_KERNEL);
- if (dev->bufptr == NULL) {
- clear_bit(0, &dev->access);
- printk("%s: buffer allocation failed\n", dev->name);
- ret = -ENOMEM;
- goto out;
- }
-
- file->private_data = dev;
-
-out:
- mutex_unlock(&pg_mutex);
- return ret;
-}
-
-static int pg_release(struct inode *inode, struct file *file)
-{
- struct pg *dev = file->private_data;
-
- kfree(dev->bufptr);
- dev->bufptr = NULL;
- clear_bit(0, &dev->access);
-
- return 0;
-}
-
-static ssize_t pg_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos)
-{
- struct pg *dev = filp->private_data;
- struct pg_write_hdr hdr;
- int hs = sizeof (hdr);
-
- if (dev->busy)
- return -EBUSY;
- if (count < hs)
- return -EINVAL;
-
- if (copy_from_user(&hdr, buf, hs))
- return -EFAULT;
-
- if (hdr.magic != PG_MAGIC)
- return -EINVAL;
- if (hdr.dlen < 0 || hdr.dlen > PG_MAX_DATA)
- return -EINVAL;
- if ((count - hs) > PG_MAX_DATA)
- return -EINVAL;
-
- if (hdr.func == PG_RESET) {
- if (count != hs)
- return -EINVAL;
- if (pg_reset(dev))
- return -EIO;
- return count;
- }
-
- if (hdr.func != PG_COMMAND)
- return -EINVAL;
-
- dev->start = jiffies;
- dev->timeout = hdr.timeout * HZ + HZ / 2 + jiffies;
-
- if (pg_command(dev, hdr.packet, hdr.dlen, jiffies + PG_TMO)) {
- if (dev->status & 0x10)
- return -ETIME;
- return -EIO;
- }
-
- dev->busy = 1;
-
- if (copy_from_user(dev->bufptr, buf + hs, count - hs))
- return -EFAULT;
- return count;
-}
-
-static ssize_t pg_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
-{
- struct pg *dev = filp->private_data;
- struct pg_read_hdr hdr;
- int hs = sizeof (hdr);
- int copy;
-
- if (!dev->busy)
- return -EINVAL;
- if (count < hs)
- return -EINVAL;
-
- dev->busy = 0;
-
- if (pg_completion(dev, dev->bufptr, dev->timeout))
- if (dev->status & 0x10)
- return -ETIME;
-
- memset(&hdr, 0, sizeof(hdr));
- hdr.magic = PG_MAGIC;
- hdr.dlen = dev->dlen;
- copy = 0;
-
- if (hdr.dlen < 0) {
- hdr.dlen = -1 * hdr.dlen;
- copy = hdr.dlen;
- if (copy > (count - hs))
- copy = count - hs;
- }
-
- hdr.duration = (jiffies - dev->start + HZ / 2) / HZ;
- hdr.scsi = dev->status & 0x0f;
-
- if (copy_to_user(buf, &hdr, hs))
- return -EFAULT;
- if (copy > 0)
- if (copy_to_user(buf + hs, dev->bufptr, copy))
- return -EFAULT;
- return copy + hs;
-}
-
-static int __init pg_init(void)
-{
- int unit;
- int err;
-
- if (disable){
- err = -EINVAL;
- goto out;
- }
-
- pg_init_units();
-
- if (pg_detect()) {
- err = -ENODEV;
- goto out;
- }
-
- err = register_chrdev(major, name, &pg_fops);
- if (err < 0) {
- printk("pg_init: unable to get major number %d\n", major);
- for (unit = 0; unit < PG_UNITS; unit++) {
- struct pg *dev = &devices[unit];
- if (dev->present)
- pi_release(dev->pi);
- }
- goto out;
- }
- major = err; /* In case the user specified `major=0' (dynamic) */
- pg_class = class_create(THIS_MODULE, "pg");
- if (IS_ERR(pg_class)) {
- err = PTR_ERR(pg_class);
- goto out_chrdev;
- }
- for (unit = 0; unit < PG_UNITS; unit++) {
- struct pg *dev = &devices[unit];
- if (dev->present)
- device_create(pg_class, NULL, MKDEV(major, unit), NULL,
- "pg%u", unit);
- }
- err = 0;
- goto out;
-
-out_chrdev:
- unregister_chrdev(major, "pg");
-out:
- return err;
-}
-
-static void __exit pg_exit(void)
-{
- int unit;
-
- for (unit = 0; unit < PG_UNITS; unit++) {
- struct pg *dev = &devices[unit];
- if (dev->present)
- device_destroy(pg_class, MKDEV(major, unit));
- }
- class_destroy(pg_class);
- unregister_chrdev(major, name);
-
- for (unit = 0; unit < PG_UNITS; unit++) {
- struct pg *dev = &devices[unit];
- if (dev->present)
- pi_release(dev->pi);
- }
-}
-
-MODULE_LICENSE("GPL");
-module_init(pg_init)
-module_exit(pg_exit)
diff --git a/drivers/block/paride/pseudo.h b/drivers/block/paride/pseudo.h
deleted file mode 100644
index bc3703294143..000000000000
--- a/drivers/block/paride/pseudo.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- pseudo.h (c) 1997-8 Grant R. Guenther <[email protected]>
- Under the terms of the GNU General Public License.
-
- This is the "pseudo-interrupt" logic for parallel port drivers.
-
- This module is #included into each driver. It makes one
- function available:
-
- ps_set_intr( void (*continuation)(void),
- int (*ready)(void),
- int timeout,
- int nice )
-
- Which will arrange for ready() to be evaluated frequently and
- when either it returns true, or timeout jiffies have passed,
- continuation() will be invoked.
-
- If nice is 1, the test will done approximately once a
- jiffy. If nice is 0, the test will also be done whenever
- the scheduler runs (by adding it to a task queue). If
- nice is greater than 1, the test will be done once every
- (nice-1) jiffies.
-
-*/
-
-/* Changes:
-
- 1.01 1998.05.03 Switched from cli()/sti() to spinlocks
- 1.02 1998.12.14 Added support for nice > 1
-*/
-
-#define PS_VERSION "1.02"
-
-#include <linux/sched.h>
-#include <linux/workqueue.h>
-
-static void ps_tq_int(struct work_struct *work);
-
-static void (* ps_continuation)(void);
-static int (* ps_ready)(void);
-static unsigned long ps_timeout;
-static int ps_tq_active = 0;
-static int ps_nice = 0;
-
-static DEFINE_SPINLOCK(ps_spinlock __attribute__((unused)));
-
-static DECLARE_DELAYED_WORK(ps_tq, ps_tq_int);
-
-static void ps_set_intr(void (*continuation)(void),
- int (*ready)(void),
- int timeout, int nice)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&ps_spinlock,flags);
-
- ps_continuation = continuation;
- ps_ready = ready;
- ps_timeout = jiffies + timeout;
- ps_nice = nice;
-
- if (!ps_tq_active) {
- ps_tq_active = 1;
- if (!ps_nice)
- schedule_delayed_work(&ps_tq, 0);
- else
- schedule_delayed_work(&ps_tq, ps_nice-1);
- }
- spin_unlock_irqrestore(&ps_spinlock,flags);
-}
-
-static void ps_tq_int(struct work_struct *work)
-{
- void (*con)(void);
- unsigned long flags;
-
- spin_lock_irqsave(&ps_spinlock,flags);
-
- con = ps_continuation;
- ps_tq_active = 0;
-
- if (!con) {
- spin_unlock_irqrestore(&ps_spinlock,flags);
- return;
- }
- if (!ps_ready || ps_ready() || time_after_eq(jiffies, ps_timeout)) {
- ps_continuation = NULL;
- spin_unlock_irqrestore(&ps_spinlock,flags);
- con();
- return;
- }
- ps_tq_active = 1;
- if (!ps_nice)
- schedule_delayed_work(&ps_tq, 0);
- else
- schedule_delayed_work(&ps_tq, ps_nice-1);
- spin_unlock_irqrestore(&ps_spinlock,flags);
-}
-
-/* end of pseudo.h */
-
diff --git a/drivers/block/paride/pt.c b/drivers/block/paride/pt.c
deleted file mode 100644
index e815312a00ad..000000000000
--- a/drivers/block/paride/pt.c
+++ /dev/null
@@ -1,1024 +0,0 @@
-/*
- pt.c (c) 1998 Grant R. Guenther <[email protected]>
- Under the terms of the GNU General Public License.
-
- This is the high-level driver for parallel port ATAPI tape
- drives based on chips supported by the paride module.
-
- The driver implements both rewinding and non-rewinding
- devices, filemarks, and the rewind ioctl. It allocates
- a small internal "bounce buffer" for each open device, but
- otherwise expects buffering and blocking to be done at the
- user level. As with most block-structured tapes, short
- writes are padded to full tape blocks, so reading back a file
- may return more data than was actually written.
-
- By default, the driver will autoprobe for a single parallel
- port ATAPI tape drive, but if their individual parameters are
- specified, the driver can handle up to 4 drives.
-
- The rewinding devices are named /dev/pt0, /dev/pt1, ...
- while the non-rewinding devices are /dev/npt0, /dev/npt1, etc.
-
- The behaviour of the pt driver can be altered by setting
- some parameters from the insmod command line. The following
- parameters are adjustable:
-
- drive0 These four arguments can be arrays of
- drive1 1-6 integers as follows:
- drive2
- drive3 <prt>,<pro>,<uni>,<mod>,<slv>,<dly>
-
- Where,
-
- <prt> is the base of the parallel port address for
- the corresponding drive. (required)
-
- <pro> is the protocol number for the adapter that
- supports this drive. These numbers are
- logged by 'paride' when the protocol modules
- are initialised. (0 if not given)
-
- <uni> for those adapters that support chained
- devices, this is the unit selector for the
- chain of devices on the given port. It should
- be zero for devices that don't support chaining.
- (0 if not given)
-
- <mod> this can be -1 to choose the best mode, or one
- of the mode numbers supported by the adapter.
- (-1 if not given)
-
- <slv> ATAPI devices can be jumpered to master or slave.
- Set this to 0 to choose the master drive, 1 to
- choose the slave, -1 (the default) to choose the
- first drive found.
-
- <dly> some parallel ports require the driver to
- go more slowly. -1 sets a default value that
- should work with the chosen protocol. Otherwise,
- set this to a small integer, the larger it is
- the slower the port i/o. In some cases, setting
- this to zero will speed up the device. (default -1)
-
- major You may use this parameter to override the
- default major number (96) that this driver
- will use. Be sure to change the device
- name as well.
-
- name This parameter is a character string that
- contains the name the kernel will use for this
- device (in /proc output, for instance).
- (default "pt").
-
- verbose This parameter controls the amount of logging
- that the driver will do. Set it to 0 for
- normal operation, 1 to see autoprobe progress
- messages, or 2 to see additional debugging
- output. (default 0)
-
- If this driver is built into the kernel, you can use
- the following command line parameters, with the same values
- as the corresponding module parameters listed above:
-
- pt.drive0
- pt.drive1
- pt.drive2
- pt.drive3
-
- In addition, you can use the parameter pt.disable to disable
- the driver entirely.
-
-*/
-
-/* Changes:
-
- 1.01 GRG 1998.05.06 Round up transfer size, fix ready_wait,
- loosed interpretation of ATAPI standard
- for clearing error status.
- Eliminate sti();
- 1.02 GRG 1998.06.16 Eliminate an Ugh.
- 1.03 GRG 1998.08.15 Adjusted PT_TMO, use HZ in loop timing,
- extra debugging
- 1.04 GRG 1998.09.24 Repair minor coding error, added jumbo support
-
-*/
-
-#define PT_VERSION "1.04"
-#define PT_MAJOR 96
-#define PT_NAME "pt"
-#define PT_UNITS 4
-
-#include <linux/types.h>
-
-/* Here are things one can override from the insmod command.
- Most are autoprobed by paride unless set here. Verbose is on
- by default.
-
-*/
-
-static int verbose = 0;
-static int major = PT_MAJOR;
-static char *name = PT_NAME;
-static int disable = 0;
-
-static int drive0[6] = { 0, 0, 0, -1, -1, -1 };
-static int drive1[6] = { 0, 0, 0, -1, -1, -1 };
-static int drive2[6] = { 0, 0, 0, -1, -1, -1 };
-static int drive3[6] = { 0, 0, 0, -1, -1, -1 };
-
-static int (*drives[4])[6] = {&drive0, &drive1, &drive2, &drive3};
-
-#define D_PRT 0
-#define D_PRO 1
-#define D_UNI 2
-#define D_MOD 3
-#define D_SLV 4
-#define D_DLY 5
-
-#define DU (*drives[unit])
-
-/* end of parameters */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/fs.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/mtio.h>
-#include <linux/device.h>
-#include <linux/sched.h> /* current, TASK_*, schedule_timeout() */
-#include <linux/mutex.h>
-
-#include <linux/uaccess.h>
-
-module_param(verbose, int, 0);
-module_param(major, int, 0);
-module_param(name, charp, 0);
-module_param_array(drive0, int, NULL, 0);
-module_param_array(drive1, int, NULL, 0);
-module_param_array(drive2, int, NULL, 0);
-module_param_array(drive3, int, NULL, 0);
-
-#include "paride.h"
-
-#define PT_MAX_RETRIES 5
-#define PT_TMO 3000 /* interrupt timeout in jiffies */
-#define PT_SPIN_DEL 50 /* spin delay in micro-seconds */
-#define PT_RESET_TMO 30 /* 30 seconds */
-#define PT_READY_TMO 60 /* 60 seconds */
-#define PT_REWIND_TMO 1200 /* 20 minutes */
-
-#define PT_SPIN ((1000000/(HZ*PT_SPIN_DEL))*PT_TMO)
-
-#define STAT_ERR 0x00001
-#define STAT_INDEX 0x00002
-#define STAT_ECC 0x00004
-#define STAT_DRQ 0x00008
-#define STAT_SEEK 0x00010
-#define STAT_WRERR 0x00020
-#define STAT_READY 0x00040
-#define STAT_BUSY 0x00080
-#define STAT_SENSE 0x1f000
-
-#define ATAPI_TEST_READY 0x00
-#define ATAPI_REWIND 0x01
-#define ATAPI_REQ_SENSE 0x03
-#define ATAPI_READ_6 0x08
-#define ATAPI_WRITE_6 0x0a
-#define ATAPI_WFM 0x10
-#define ATAPI_IDENTIFY 0x12
-#define ATAPI_MODE_SENSE 0x1a
-#define ATAPI_LOG_SENSE 0x4d
-
-static DEFINE_MUTEX(pt_mutex);
-static int pt_open(struct inode *inode, struct file *file);
-static long pt_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
-static int pt_release(struct inode *inode, struct file *file);
-static ssize_t pt_read(struct file *filp, char __user *buf,
- size_t count, loff_t * ppos);
-static ssize_t pt_write(struct file *filp, const char __user *buf,
- size_t count, loff_t * ppos);
-static int pt_detect(void);
-
-/* bits in tape->flags */
-
-#define PT_MEDIA 1
-#define PT_WRITE_OK 2
-#define PT_REWIND 4
-#define PT_WRITING 8
-#define PT_READING 16
-#define PT_EOF 32
-
-#define PT_NAMELEN 8
-#define PT_BUFSIZE 16384
-
-struct pt_unit {
- struct pi_adapter pia; /* interface to paride layer */
- struct pi_adapter *pi;
- int flags; /* various state flags */
- int last_sense; /* result of last request sense */
- int drive; /* drive */
- atomic_t available; /* 1 if access is available 0 otherwise */
- int bs; /* block size */
- int capacity; /* Size of tape in KB */
- int present; /* device present ? */
- char *bufptr;
- char name[PT_NAMELEN]; /* pf0, pf1, ... */
-};
-
-static int pt_identify(struct pt_unit *tape);
-
-static struct pt_unit pt[PT_UNITS];
-
-static char pt_scratch[512]; /* scratch block buffer */
-static void *par_drv; /* reference of parport driver */
-
-/* kernel glue structures */
-
-static const struct file_operations pt_fops = {
- .owner = THIS_MODULE,
- .read = pt_read,
- .write = pt_write,
- .unlocked_ioctl = pt_ioctl,
- .open = pt_open,
- .release = pt_release,
- .llseek = noop_llseek,
-};
-
-/* sysfs class support */
-static struct class *pt_class;
-
-static inline int status_reg(struct pi_adapter *pi)
-{
- return pi_read_regr(pi, 1, 6);
-}
-
-static inline int read_reg(struct pi_adapter *pi, int reg)
-{
- return pi_read_regr(pi, 0, reg);
-}
-
-static inline void write_reg(struct pi_adapter *pi, int reg, int val)
-{
- pi_write_regr(pi, 0, reg, val);
-}
-
-static inline u8 DRIVE(struct pt_unit *tape)
-{
- return 0xa0+0x10*tape->drive;
-}
-
-static int pt_wait(struct pt_unit *tape, int go, int stop, char *fun, char *msg)
-{
- int j, r, e, s, p;
- struct pi_adapter *pi = tape->pi;
-
- j = 0;
- while ((((r = status_reg(pi)) & go) || (stop && (!(r & stop))))
- && (j++ < PT_SPIN))
- udelay(PT_SPIN_DEL);
-
- if ((r & (STAT_ERR & stop)) || (j > PT_SPIN)) {
- s = read_reg(pi, 7);
- e = read_reg(pi, 1);
- p = read_reg(pi, 2);
- if (j > PT_SPIN)
- e |= 0x100;
- if (fun)
- printk("%s: %s %s: alt=0x%x stat=0x%x err=0x%x"
- " loop=%d phase=%d\n",
- tape->name, fun, msg, r, s, e, j, p);
- return (e << 8) + s;
- }
- return 0;
-}
-
-static int pt_command(struct pt_unit *tape, char *cmd, int dlen, char *fun)
-{
- struct pi_adapter *pi = tape->pi;
- pi_connect(pi);
-
- write_reg(pi, 6, DRIVE(tape));
-
- if (pt_wait(tape, STAT_BUSY | STAT_DRQ, 0, fun, "before command")) {
- pi_disconnect(pi);
- return -1;
- }
-
- write_reg(pi, 4, dlen % 256);
- write_reg(pi, 5, dlen / 256);
- write_reg(pi, 7, 0xa0); /* ATAPI packet command */
-
- if (pt_wait(tape, STAT_BUSY, STAT_DRQ, fun, "command DRQ")) {
- pi_disconnect(pi);
- return -1;
- }
-
- if (read_reg(pi, 2) != 1) {
- printk("%s: %s: command phase error\n", tape->name, fun);
- pi_disconnect(pi);
- return -1;
- }
-
- pi_write_block(pi, cmd, 12);
-
- return 0;
-}
-
-static int pt_completion(struct pt_unit *tape, char *buf, char *fun)
-{
- struct pi_adapter *pi = tape->pi;
- int r, s, n, p;
-
- r = pt_wait(tape, STAT_BUSY, STAT_DRQ | STAT_READY | STAT_ERR,
- fun, "completion");
-
- if (read_reg(pi, 7) & STAT_DRQ) {
- n = (((read_reg(pi, 4) + 256 * read_reg(pi, 5)) +
- 3) & 0xfffc);
- p = read_reg(pi, 2) & 3;
- if (p == 0)
- pi_write_block(pi, buf, n);
- if (p == 2)
- pi_read_block(pi, buf, n);
- }
-
- s = pt_wait(tape, STAT_BUSY, STAT_READY | STAT_ERR, fun, "data done");
-
- pi_disconnect(pi);
-
- return (r ? r : s);
-}
-
-static void pt_req_sense(struct pt_unit *tape, int quiet)
-{
- char rs_cmd[12] = { ATAPI_REQ_SENSE, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0 };
- char buf[16];
- int r;
-
- r = pt_command(tape, rs_cmd, 16, "Request sense");
- mdelay(1);
- if (!r)
- pt_completion(tape, buf, "Request sense");
-
- tape->last_sense = -1;
- if (!r) {
- if (!quiet)
- printk("%s: Sense key: %x, ASC: %x, ASQ: %x\n",
- tape->name, buf[2] & 0xf, buf[12], buf[13]);
- tape->last_sense = (buf[2] & 0xf) | ((buf[12] & 0xff) << 8)
- | ((buf[13] & 0xff) << 16);
- }
-}
-
-static int pt_atapi(struct pt_unit *tape, char *cmd, int dlen, char *buf, char *fun)
-{
- int r;
-
- r = pt_command(tape, cmd, dlen, fun);
- mdelay(1);
- if (!r)
- r = pt_completion(tape, buf, fun);
- if (r)
- pt_req_sense(tape, !fun);
-
- return r;
-}
-
-static void pt_sleep(int cs)
-{
- schedule_timeout_interruptible(cs);
-}
-
-static int pt_poll_dsc(struct pt_unit *tape, int pause, int tmo, char *msg)
-{
- struct pi_adapter *pi = tape->pi;
- int k, e, s;
-
- k = 0;
- e = 0;
- s = 0;
- while (k < tmo) {
- pt_sleep(pause);
- k++;
- pi_connect(pi);
- write_reg(pi, 6, DRIVE(tape));
- s = read_reg(pi, 7);
- e = read_reg(pi, 1);
- pi_disconnect(pi);
- if (s & (STAT_ERR | STAT_SEEK))
- break;
- }
- if ((k >= tmo) || (s & STAT_ERR)) {
- if (k >= tmo)
- printk("%s: %s DSC timeout\n", tape->name, msg);
- else
- printk("%s: %s stat=0x%x err=0x%x\n", tape->name, msg, s,
- e);
- pt_req_sense(tape, 0);
- return 0;
- }
- return 1;
-}
-
-static void pt_media_access_cmd(struct pt_unit *tape, int tmo, char *cmd, char *fun)
-{
- if (pt_command(tape, cmd, 0, fun)) {
- pt_req_sense(tape, 0);
- return;
- }
- pi_disconnect(tape->pi);
- pt_poll_dsc(tape, HZ, tmo, fun);
-}
-
-static void pt_rewind(struct pt_unit *tape)
-{
- char rw_cmd[12] = { ATAPI_REWIND, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
-
- pt_media_access_cmd(tape, PT_REWIND_TMO, rw_cmd, "rewind");
-}
-
-static void pt_write_fm(struct pt_unit *tape)
-{
- char wm_cmd[12] = { ATAPI_WFM, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 };
-
- pt_media_access_cmd(tape, PT_TMO, wm_cmd, "write filemark");
-}
-
-#define DBMSG(msg) ((verbose>1)?(msg):NULL)
-
-static int pt_reset(struct pt_unit *tape)
-{
- struct pi_adapter *pi = tape->pi;
- int i, k, flg;
- int expect[5] = { 1, 1, 1, 0x14, 0xeb };
-
- pi_connect(pi);
- write_reg(pi, 6, DRIVE(tape));
- write_reg(pi, 7, 8);
-
- pt_sleep(20 * HZ / 1000);
-
- k = 0;
- while ((k++ < PT_RESET_TMO) && (status_reg(pi) & STAT_BUSY))
- pt_sleep(HZ / 10);
-
- flg = 1;
- for (i = 0; i < 5; i++)
- flg &= (read_reg(pi, i + 1) == expect[i]);
-
- if (verbose) {
- printk("%s: Reset (%d) signature = ", tape->name, k);
- for (i = 0; i < 5; i++)
- printk("%3x", read_reg(pi, i + 1));
- if (!flg)
- printk(" (incorrect)");
- printk("\n");
- }
-
- pi_disconnect(pi);
- return flg - 1;
-}
-
-static int pt_ready_wait(struct pt_unit *tape, int tmo)
-{
- char tr_cmd[12] = { ATAPI_TEST_READY, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
- int k, p;
-
- k = 0;
- while (k < tmo) {
- tape->last_sense = 0;
- pt_atapi(tape, tr_cmd, 0, NULL, DBMSG("test unit ready"));
- p = tape->last_sense;
- if (!p)
- return 0;
- if (!(((p & 0xffff) == 0x0402) || ((p & 0xff) == 6)))
- return p;
- k++;
- pt_sleep(HZ);
- }
- return 0x000020; /* timeout */
-}
-
-static void xs(char *buf, char *targ, int offs, int len)
-{
- int j, k, l;
-
- j = 0;
- l = 0;
- for (k = 0; k < len; k++)
- if ((buf[k + offs] != 0x20) || (buf[k + offs] != l))
- l = targ[j++] = buf[k + offs];
- if (l == 0x20)
- j--;
- targ[j] = 0;
-}
-
-static int xn(char *buf, int offs, int size)
-{
- int v, k;
-
- v = 0;
- for (k = 0; k < size; k++)
- v = v * 256 + (buf[k + offs] & 0xff);
- return v;
-}
-
-static int pt_identify(struct pt_unit *tape)
-{
- int dt, s;
- char *ms[2] = { "master", "slave" };
- char mf[10], id[18];
- char id_cmd[12] = { ATAPI_IDENTIFY, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0 };
- char ms_cmd[12] =
- { ATAPI_MODE_SENSE, 0, 0x2a, 0, 36, 0, 0, 0, 0, 0, 0, 0 };
- char ls_cmd[12] =
- { ATAPI_LOG_SENSE, 0, 0x71, 0, 0, 0, 0, 0, 36, 0, 0, 0 };
- char buf[36];
-
- s = pt_atapi(tape, id_cmd, 36, buf, "identify");
- if (s)
- return -1;
-
- dt = buf[0] & 0x1f;
- if (dt != 1) {
- if (verbose)
- printk("%s: Drive %d, unsupported type %d\n",
- tape->name, tape->drive, dt);
- return -1;
- }
-
- xs(buf, mf, 8, 8);
- xs(buf, id, 16, 16);
-
- tape->flags = 0;
- tape->capacity = 0;
- tape->bs = 0;
-
- if (!pt_ready_wait(tape, PT_READY_TMO))
- tape->flags |= PT_MEDIA;
-
- if (!pt_atapi(tape, ms_cmd, 36, buf, "mode sense")) {
- if (!(buf[2] & 0x80))
- tape->flags |= PT_WRITE_OK;
- tape->bs = xn(buf, 10, 2);
- }
-
- if (!pt_atapi(tape, ls_cmd, 36, buf, "log sense"))
- tape->capacity = xn(buf, 24, 4);
-
- printk("%s: %s %s, %s", tape->name, mf, id, ms[tape->drive]);
- if (!(tape->flags & PT_MEDIA))
- printk(", no media\n");
- else {
- if (!(tape->flags & PT_WRITE_OK))
- printk(", RO");
- printk(", blocksize %d, %d MB\n", tape->bs, tape->capacity / 1024);
- }
-
- return 0;
-}
-
-
-/*
- * returns 0, with id set if drive is detected
- * -1, if drive detection failed
- */
-static int pt_probe(struct pt_unit *tape)
-{
- if (tape->drive == -1) {
- for (tape->drive = 0; tape->drive <= 1; tape->drive++)
- if (!pt_reset(tape))
- return pt_identify(tape);
- } else {
- if (!pt_reset(tape))
- return pt_identify(tape);
- }
- return -1;
-}
-
-static int pt_detect(void)
-{
- struct pt_unit *tape;
- int specified = 0, found = 0;
- int unit;
-
- printk("%s: %s version %s, major %d\n", name, name, PT_VERSION, major);
-
- par_drv = pi_register_driver(name);
- if (!par_drv) {
- pr_err("failed to register %s driver\n", name);
- return -1;
- }
-
- specified = 0;
- for (unit = 0; unit < PT_UNITS; unit++) {
- struct pt_unit *tape = &pt[unit];
- tape->pi = &tape->pia;
- atomic_set(&tape->available, 1);
- tape->flags = 0;
- tape->last_sense = 0;
- tape->present = 0;
- tape->bufptr = NULL;
- tape->drive = DU[D_SLV];
- snprintf(tape->name, PT_NAMELEN, "%s%d", name, unit);
- if (!DU[D_PRT])
- continue;
- specified++;
- if (pi_init(tape->pi, 0, DU[D_PRT], DU[D_MOD], DU[D_UNI],
- DU[D_PRO], DU[D_DLY], pt_scratch, PI_PT,
- verbose, tape->name)) {
- if (!pt_probe(tape)) {
- tape->present = 1;
- found++;
- } else
- pi_release(tape->pi);
- }
- }
- if (specified == 0) {
- tape = pt;
- if (pi_init(tape->pi, 1, -1, -1, -1, -1, -1, pt_scratch,
- PI_PT, verbose, tape->name)) {
- if (!pt_probe(tape)) {
- tape->present = 1;
- found++;
- } else
- pi_release(tape->pi);
- }
-
- }
- if (found)
- return 0;
-
- pi_unregister_driver(par_drv);
- printk("%s: No ATAPI tape drive detected\n", name);
- return -1;
-}
-
-static int pt_open(struct inode *inode, struct file *file)
-{
- int unit = iminor(inode) & 0x7F;
- struct pt_unit *tape = pt + unit;
- int err;
-
- mutex_lock(&pt_mutex);
- if (unit >= PT_UNITS || (!tape->present)) {
- mutex_unlock(&pt_mutex);
- return -ENODEV;
- }
-
- err = -EBUSY;
- if (!atomic_dec_and_test(&tape->available))
- goto out;
-
- pt_identify(tape);
-
- err = -ENODEV;
- if (!(tape->flags & PT_MEDIA))
- goto out;
-
- err = -EROFS;
- if ((!(tape->flags & PT_WRITE_OK)) && (file->f_mode & FMODE_WRITE))
- goto out;
-
- if (!(iminor(inode) & 128))
- tape->flags |= PT_REWIND;
-
- err = -ENOMEM;
- tape->bufptr = kmalloc(PT_BUFSIZE, GFP_KERNEL);
- if (tape->bufptr == NULL) {
- printk("%s: buffer allocation failed\n", tape->name);
- goto out;
- }
-
- file->private_data = tape;
- mutex_unlock(&pt_mutex);
- return 0;
-
-out:
- atomic_inc(&tape->available);
- mutex_unlock(&pt_mutex);
- return err;
-}
-
-static long pt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct pt_unit *tape = file->private_data;
- struct mtop __user *p = (void __user *)arg;
- struct mtop mtop;
-
- switch (cmd) {
- case MTIOCTOP:
- if (copy_from_user(&mtop, p, sizeof(struct mtop)))
- return -EFAULT;
-
- switch (mtop.mt_op) {
-
- case MTREW:
- mutex_lock(&pt_mutex);
- pt_rewind(tape);
- mutex_unlock(&pt_mutex);
- return 0;
-
- case MTWEOF:
- mutex_lock(&pt_mutex);
- pt_write_fm(tape);
- mutex_unlock(&pt_mutex);
- return 0;
-
- default:
- /* FIXME: rate limit ?? */
- printk(KERN_DEBUG "%s: Unimplemented mt_op %d\n", tape->name,
- mtop.mt_op);
- return -EINVAL;
- }
-
- default:
- return -ENOTTY;
- }
-}
-
-static int
-pt_release(struct inode *inode, struct file *file)
-{
- struct pt_unit *tape = file->private_data;
-
- if (atomic_read(&tape->available) > 1)
- return -EINVAL;
-
- if (tape->flags & PT_WRITING)
- pt_write_fm(tape);
-
- if (tape->flags & PT_REWIND)
- pt_rewind(tape);
-
- kfree(tape->bufptr);
- tape->bufptr = NULL;
-
- atomic_inc(&tape->available);
-
- return 0;
-
-}
-
-static ssize_t pt_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos)
-{
- struct pt_unit *tape = filp->private_data;
- struct pi_adapter *pi = tape->pi;
- char rd_cmd[12] = { ATAPI_READ_6, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
- int k, n, r, p, s, t, b;
-
- if (!(tape->flags & (PT_READING | PT_WRITING))) {
- tape->flags |= PT_READING;
- if (pt_atapi(tape, rd_cmd, 0, NULL, "start read-ahead"))
- return -EIO;
- } else if (tape->flags & PT_WRITING)
- return -EIO;
-
- if (tape->flags & PT_EOF)
- return 0;
-
- t = 0;
-
- while (count > 0) {
-
- if (!pt_poll_dsc(tape, HZ / 100, PT_TMO, "read"))
- return -EIO;
-
- n = count;
- if (n > 32768)
- n = 32768; /* max per command */
- b = (n - 1 + tape->bs) / tape->bs;
- n = b * tape->bs; /* rounded up to even block */
-
- rd_cmd[4] = b;
-
- r = pt_command(tape, rd_cmd, n, "read");
-
- mdelay(1);
-
- if (r) {
- pt_req_sense(tape, 0);
- return -EIO;
- }
-
- while (1) {
-
- r = pt_wait(tape, STAT_BUSY,
- STAT_DRQ | STAT_ERR | STAT_READY,
- DBMSG("read DRQ"), "");
-
- if (r & STAT_SENSE) {
- pi_disconnect(pi);
- pt_req_sense(tape, 0);
- return -EIO;
- }
-
- if (r)
- tape->flags |= PT_EOF;
-
- s = read_reg(pi, 7);
-
- if (!(s & STAT_DRQ))
- break;
-
- n = (read_reg(pi, 4) + 256 * read_reg(pi, 5));
- p = (read_reg(pi, 2) & 3);
- if (p != 2) {
- pi_disconnect(pi);
- printk("%s: Phase error on read: %d\n", tape->name,
- p);
- return -EIO;
- }
-
- while (n > 0) {
- k = n;
- if (k > PT_BUFSIZE)
- k = PT_BUFSIZE;
- pi_read_block(pi, tape->bufptr, k);
- n -= k;
- b = k;
- if (b > count)
- b = count;
- if (copy_to_user(buf + t, tape->bufptr, b)) {
- pi_disconnect(pi);
- return -EFAULT;
- }
- t += b;
- count -= b;
- }
-
- }
- pi_disconnect(pi);
- if (tape->flags & PT_EOF)
- break;
- }
-
- return t;
-
-}
-
-static ssize_t pt_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
-{
- struct pt_unit *tape = filp->private_data;
- struct pi_adapter *pi = tape->pi;
- char wr_cmd[12] = { ATAPI_WRITE_6, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
- int k, n, r, p, s, t, b;
-
- if (!(tape->flags & PT_WRITE_OK))
- return -EROFS;
-
- if (!(tape->flags & (PT_READING | PT_WRITING))) {
- tape->flags |= PT_WRITING;
- if (pt_atapi
- (tape, wr_cmd, 0, NULL, "start buffer-available mode"))
- return -EIO;
- } else if (tape->flags & PT_READING)
- return -EIO;
-
- if (tape->flags & PT_EOF)
- return -ENOSPC;
-
- t = 0;
-
- while (count > 0) {
-
- if (!pt_poll_dsc(tape, HZ / 100, PT_TMO, "write"))
- return -EIO;
-
- n = count;
- if (n > 32768)
- n = 32768; /* max per command */
- b = (n - 1 + tape->bs) / tape->bs;
- n = b * tape->bs; /* rounded up to even block */
-
- wr_cmd[4] = b;
-
- r = pt_command(tape, wr_cmd, n, "write");
-
- mdelay(1);
-
- if (r) { /* error delivering command only */
- pt_req_sense(tape, 0);
- return -EIO;
- }
-
- while (1) {
-
- r = pt_wait(tape, STAT_BUSY,
- STAT_DRQ | STAT_ERR | STAT_READY,
- DBMSG("write DRQ"), NULL);
-
- if (r & STAT_SENSE) {
- pi_disconnect(pi);
- pt_req_sense(tape, 0);
- return -EIO;
- }
-
- if (r)
- tape->flags |= PT_EOF;
-
- s = read_reg(pi, 7);
-
- if (!(s & STAT_DRQ))
- break;
-
- n = (read_reg(pi, 4) + 256 * read_reg(pi, 5));
- p = (read_reg(pi, 2) & 3);
- if (p != 0) {
- pi_disconnect(pi);
- printk("%s: Phase error on write: %d \n",
- tape->name, p);
- return -EIO;
- }
-
- while (n > 0) {
- k = n;
- if (k > PT_BUFSIZE)
- k = PT_BUFSIZE;
- b = k;
- if (b > count)
- b = count;
- if (copy_from_user(tape->bufptr, buf + t, b)) {
- pi_disconnect(pi);
- return -EFAULT;
- }
- pi_write_block(pi, tape->bufptr, k);
- t += b;
- count -= b;
- n -= k;
- }
-
- }
- pi_disconnect(pi);
- if (tape->flags & PT_EOF)
- break;
- }
-
- return t;
-}
-
-static int __init pt_init(void)
-{
- int unit;
- int err;
-
- if (disable) {
- err = -EINVAL;
- goto out;
- }
-
- if (pt_detect()) {
- err = -ENODEV;
- goto out;
- }
-
- err = register_chrdev(major, name, &pt_fops);
- if (err < 0) {
- printk("pt_init: unable to get major number %d\n", major);
- for (unit = 0; unit < PT_UNITS; unit++)
- if (pt[unit].present)
- pi_release(pt[unit].pi);
- goto out;
- }
- major = err;
- pt_class = class_create(THIS_MODULE, "pt");
- if (IS_ERR(pt_class)) {
- err = PTR_ERR(pt_class);
- goto out_chrdev;
- }
-
- for (unit = 0; unit < PT_UNITS; unit++)
- if (pt[unit].present) {
- device_create(pt_class, NULL, MKDEV(major, unit), NULL,
- "pt%d", unit);
- device_create(pt_class, NULL, MKDEV(major, unit + 128),
- NULL, "pt%dn", unit);
- }
- goto out;
-
-out_chrdev:
- unregister_chrdev(major, "pt");
-out:
- return err;
-}
-
-static void __exit pt_exit(void)
-{
- int unit;
- for (unit = 0; unit < PT_UNITS; unit++)
- if (pt[unit].present) {
- device_destroy(pt_class, MKDEV(major, unit));
- device_destroy(pt_class, MKDEV(major, unit + 128));
- }
- class_destroy(pt_class);
- unregister_chrdev(major, name);
- for (unit = 0; unit < PT_UNITS; unit++)
- if (pt[unit].present)
- pi_release(pt[unit].pi);
-}
-
-MODULE_LICENSE("GPL");
-module_init(pt_init)
-module_exit(pt_exit)
--
Ondrej Zary


2023-01-30 23:18:47

by Damien Le Moal

[permalink] [raw]
Subject: Re: [PATCH v3] pata_parport: add driver (PARIDE replacement)

On 1/31/23 00:25, Jens Axboe wrote:
> On 1/30/23 12:10 AM, Damien Le Moal wrote:
>> On 1/30/23 15:48, Christoph Hellwig wrote:
>>> On Sun, Jan 29, 2023 at 08:44:06PM -0700, Jens Axboe wrote:
>>>> I would prefer if we just delete it after merging this one, in the same
>>>> release. I don't think there's any point in delaying, as we're not
>>>> removing any functionality.
>>>>
>>>> You could just queue that up too when adding this patch.
>>>
>>> I'd prefer to just deprecate. But most importantly I want this patch
>>> in ASAP in some form.
>>
>> I will queue it. But I think it needs a follow up to result in something
>> consistent with KConfig. So either deprecate or delete PARPORT. I can queue the
>> deprecate patch and delete in 6.4, even though I share Jen's opinion to simply
>> delete directly. I am still fine either way.
>>
>> Jens,
>>
>> If you are OK with that, can I get your ack for the deprecate patch ? Unless you
>> prefer taking it through the block tree. Either way is fine with me.
>
> Yeah I'd be happy to ack that, did you post it? You can add my ack to the
> new driver, fine with that now.

Will do. But I did not want to queue the new driver without killing (or
deprecating) the old code too. Ondrej has now sent 2 patches to remove the old
code. Please ack that !

--
Damien Le Moal
Western Digital Research


2023-01-30 23:24:36

by Jens Axboe

[permalink] [raw]
Subject: Re: [PATCH 1/2] drivers/block: Remove PARIDE core and high-level protocols

On 1/30/23 2:10 PM, Ondrej Zary wrote:
> Remove PARIDE core and high level protocols, taking care not to break
> low-level drivers (used by pata_parport). Also update documentation.
>
> Signed-off-by: Ondrej Zary <[email protected]>

Acked-by: Jens Axboe <[email protected]>

--
Jens Axboe