diff options
author | Ondrej Zary <linux@zary.sk> | 2023-01-31 00:10:49 +0300 |
---|---|---|
committer | Damien Le Moal <damien.lemoal@opensource.wdc.com> | 2023-01-31 04:41:32 +0300 |
commit | 7750d8b51061467d9de8407a17c26cba9e15da10 (patch) | |
tree | 868b4d573937da3608b4ea4e35dc6d77ebfe7365 /drivers/block | |
parent | 246a1c4c6b7ffba88a2553d2b88f7b6280f253a2 (diff) | |
download | linux-7750d8b51061467d9de8407a17c26cba9e15da10.tar.xz |
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 <linux@zary.sk>
Acked-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Damien Le Moal <damien.lemoal@opensource.wdc.com>
Diffstat (limited to 'drivers/block')
28 files changed, 31 insertions, 5967 deletions
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 <grant@torque.net> - 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 <grant@torque.net> - 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 <grant@torque.net> - 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 <grant@torque.net> - 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 <grant@torque.net> - 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 <grant@torque.net> - 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 <grant@torque.net> - 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 <grant@torque.net> - 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) |