scsi: ppa: Add a module parameter for the transfer mode

I have an Iomega Z100P2 zip drive, but it does not work with my StarTech
PEX1P2 AX99100 PCIe parallel port, which evidently does not support 16-bit
or 32-bit EPP. Currently the only way to tell the PPA driver to use 8-bit
EPP is to write 'mode=3' to /proc/scsi/ppa/*, but the driver doesn't
actually distinguish between the three EPP modes and still tries to use
16-bit or 32-bit EPP. And even if writing to that file did make the driver
use 8-bit EPP, it still wouldn't do me any good because by the time that
file exists, the drive has already failed to initialize.

Add a new parameter /sys/module/ppa/mode to set the transfer mode before
initializing the drive. This parameter replaces the use of
CONFIG_SCSI_IZIP_EPP16 in the PPA driver.

At the same time, default to 8-bit EPP. 16-bit and 32-bit EPP are not
necessary for the drive to function, nor are they part of the IEEE 1284
standard, so the driver should not assume that they are available.

Signed-off-by: Alex Henrie <alexhenrie24@gmail.com>
Link: https://lore.kernel.org/r/20230807155856.362864-2-alexhenrie24@gmail.com
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
Alex Henrie 2023-08-07 09:52:58 -06:00 committed by Martin K. Petersen
parent b68442ebda
commit 68a4f84a17
3 changed files with 43 additions and 45 deletions

View File

@ -836,7 +836,7 @@ config SCSI_IMM
config SCSI_IZIP_EPP16 config SCSI_IZIP_EPP16
bool "ppa/imm option - Use slow (but safe) EPP-16" bool "ppa/imm option - Use slow (but safe) EPP-16"
depends on SCSI_PPA || SCSI_IMM depends on SCSI_IMM
help help
EPP (Enhanced Parallel Port) is a standard for parallel ports which EPP (Enhanced Parallel Port) is a standard for parallel ports which
allows them to act as expansion buses that can handle up to 64 allows them to act as expansion buses that can handle up to 64

View File

@ -45,6 +45,11 @@ typedef struct {
#include "ppa.h" #include "ppa.h"
static unsigned int mode = PPA_AUTODETECT;
module_param(mode, uint, 0644);
MODULE_PARM_DESC(mode, "Transfer mode (0 = Autodetect, 1 = SPP 4-bit, "
"2 = SPP 8-bit, 3 = EPP 8-bit, 4 = EPP 16-bit, 5 = EPP 32-bit");
static struct scsi_pointer *ppa_scsi_pointer(struct scsi_cmnd *cmd) static struct scsi_pointer *ppa_scsi_pointer(struct scsi_cmnd *cmd)
{ {
return scsi_cmd_priv(cmd); return scsi_cmd_priv(cmd);
@ -157,7 +162,7 @@ static int ppa_show_info(struct seq_file *m, struct Scsi_Host *host)
return 0; return 0;
} }
static int device_check(ppa_struct *dev); static int device_check(ppa_struct *dev, bool autodetect);
#if PPA_DEBUG > 0 #if PPA_DEBUG > 0
#define ppa_fail(x,y) printk("ppa: ppa_fail(%i) from %s at line %d\n",\ #define ppa_fail(x,y) printk("ppa: ppa_fail(%i) from %s at line %d\n",\
@ -302,13 +307,10 @@ static int ppa_out(ppa_struct *dev, char *buffer, int len)
case PPA_EPP_8: case PPA_EPP_8:
epp_reset(ppb); epp_reset(ppb);
w_ctr(ppb, 0x4); w_ctr(ppb, 0x4);
#ifdef CONFIG_SCSI_IZIP_EPP16 if (dev->mode == PPA_EPP_32 && !(((long) buffer | len) & 0x01))
if (!(((long) buffer | len) & 0x01))
outsw(ppb + 4, buffer, len >> 1);
#else
if (!(((long) buffer | len) & 0x03))
outsl(ppb + 4, buffer, len >> 2); outsl(ppb + 4, buffer, len >> 2);
#endif else if (dev->mode == PPA_EPP_16 && !(((long) buffer | len) & 0x03))
outsw(ppb + 4, buffer, len >> 1);
else else
outsb(ppb + 4, buffer, len); outsb(ppb + 4, buffer, len);
w_ctr(ppb, 0xc); w_ctr(ppb, 0xc);
@ -355,13 +357,10 @@ static int ppa_in(ppa_struct *dev, char *buffer, int len)
case PPA_EPP_8: case PPA_EPP_8:
epp_reset(ppb); epp_reset(ppb);
w_ctr(ppb, 0x24); w_ctr(ppb, 0x24);
#ifdef CONFIG_SCSI_IZIP_EPP16 if (dev->mode == PPA_EPP_32 && !(((long) buffer | len) & 0x03))
if (!(((long) buffer | len) & 0x01))
insw(ppb + 4, buffer, len >> 1);
#else
if (!(((long) buffer | len) & 0x03))
insl(ppb + 4, buffer, len >> 2); insl(ppb + 4, buffer, len >> 2);
#endif else if (dev->mode == PPA_EPP_16 && !(((long) buffer | len) & 0x01))
insw(ppb + 4, buffer, len >> 1);
else else
insb(ppb + 4, buffer, len); insb(ppb + 4, buffer, len);
w_ctr(ppb, 0x2c); w_ctr(ppb, 0x2c);
@ -469,6 +468,27 @@ static int ppa_init(ppa_struct *dev)
{ {
int retv; int retv;
unsigned short ppb = dev->base; unsigned short ppb = dev->base;
bool autodetect = dev->mode == PPA_AUTODETECT;
if (autodetect) {
int modes = dev->dev->port->modes;
int ppb_hi = dev->dev->port->base_hi;
/* Mode detection works up the chain of speed
* This avoids a nasty if-then-else-if-... tree
*/
dev->mode = PPA_NIBBLE;
if (modes & PARPORT_MODE_TRISTATE)
dev->mode = PPA_PS2;
if (modes & PARPORT_MODE_ECP) {
w_ecr(ppb_hi, 0x20);
dev->mode = PPA_PS2;
}
if ((modes & PARPORT_MODE_EPP) && (modes & PARPORT_MODE_ECP))
w_ecr(ppb_hi, 0x80);
}
ppa_disconnect(dev); ppa_disconnect(dev);
ppa_connect(dev, CONNECT_NORMAL); ppa_connect(dev, CONNECT_NORMAL);
@ -492,7 +512,7 @@ static int ppa_init(ppa_struct *dev)
if (retv) if (retv)
return -EIO; return -EIO;
return device_check(dev); return device_check(dev, autodetect);
} }
static inline int ppa_send_command(struct scsi_cmnd *cmd) static inline int ppa_send_command(struct scsi_cmnd *cmd)
@ -883,7 +903,7 @@ static int ppa_reset(struct scsi_cmnd *cmd)
return SUCCESS; return SUCCESS;
} }
static int device_check(ppa_struct *dev) static int device_check(ppa_struct *dev, bool autodetect)
{ {
/* This routine looks for a device and then attempts to use EPP /* This routine looks for a device and then attempts to use EPP
to send a command. If all goes as planned then EPP is available. */ to send a command. If all goes as planned then EPP is available. */
@ -895,8 +915,8 @@ static int device_check(ppa_struct *dev)
old_mode = dev->mode; old_mode = dev->mode;
for (loop = 0; loop < 8; loop++) { for (loop = 0; loop < 8; loop++) {
/* Attempt to use EPP for Test Unit Ready */ /* Attempt to use EPP for Test Unit Ready */
if ((ppb & 0x0007) == 0x0000) if (autodetect && (ppb & 0x0007) == 0x0000)
dev->mode = PPA_EPP_32; dev->mode = PPA_EPP_8;
second_pass: second_pass:
ppa_connect(dev, CONNECT_EPP_MAYBE); ppa_connect(dev, CONNECT_EPP_MAYBE);
@ -924,7 +944,7 @@ second_pass:
udelay(1000); udelay(1000);
ppa_disconnect(dev); ppa_disconnect(dev);
udelay(1000); udelay(1000);
if (dev->mode == PPA_EPP_32) { if (dev->mode != old_mode) {
dev->mode = old_mode; dev->mode = old_mode;
goto second_pass; goto second_pass;
} }
@ -947,7 +967,7 @@ second_pass:
udelay(1000); udelay(1000);
ppa_disconnect(dev); ppa_disconnect(dev);
udelay(1000); udelay(1000);
if (dev->mode == PPA_EPP_32) { if (dev->mode != old_mode) {
dev->mode = old_mode; dev->mode = old_mode;
goto second_pass; goto second_pass;
} }
@ -1026,7 +1046,6 @@ static int __ppa_attach(struct parport *pb)
DEFINE_WAIT(wait); DEFINE_WAIT(wait);
ppa_struct *dev, *temp; ppa_struct *dev, *temp;
int ports; int ports;
int modes, ppb, ppb_hi;
int err = -ENOMEM; int err = -ENOMEM;
struct pardev_cb ppa_cb; struct pardev_cb ppa_cb;
@ -1034,7 +1053,7 @@ static int __ppa_attach(struct parport *pb)
if (!dev) if (!dev)
return -ENOMEM; return -ENOMEM;
dev->base = -1; dev->base = -1;
dev->mode = PPA_AUTODETECT; dev->mode = mode < PPA_UNKNOWN ? mode : PPA_AUTODETECT;
dev->recon_tmo = PPA_RECON_TMO; dev->recon_tmo = PPA_RECON_TMO;
init_waitqueue_head(&waiting); init_waitqueue_head(&waiting);
temp = find_parent(); temp = find_parent();
@ -1069,25 +1088,8 @@ static int __ppa_attach(struct parport *pb)
} }
dev->waiting = NULL; dev->waiting = NULL;
finish_wait(&waiting, &wait); finish_wait(&waiting, &wait);
ppb = dev->base = dev->dev->port->base; dev->base = dev->dev->port->base;
ppb_hi = dev->dev->port->base_hi; w_ctr(dev->base, 0x0c);
w_ctr(ppb, 0x0c);
modes = dev->dev->port->modes;
/* Mode detection works up the chain of speed
* This avoids a nasty if-then-else-if-... tree
*/
dev->mode = PPA_NIBBLE;
if (modes & PARPORT_MODE_TRISTATE)
dev->mode = PPA_PS2;
if (modes & PARPORT_MODE_ECP) {
w_ecr(ppb_hi, 0x20);
dev->mode = PPA_PS2;
}
if ((modes & PARPORT_MODE_EPP) && (modes & PARPORT_MODE_ECP))
w_ecr(ppb_hi, 0x80);
/* Done configuration */ /* Done configuration */

View File

@ -107,11 +107,7 @@ static char *PPA_MODE_STRING[] =
"PS/2", "PS/2",
"EPP 8 bit", "EPP 8 bit",
"EPP 16 bit", "EPP 16 bit",
#ifdef CONFIG_SCSI_IZIP_EPP16
"EPP 16 bit",
#else
"EPP 32 bit", "EPP 32 bit",
#endif
"Unknown"}; "Unknown"};
/* other options */ /* other options */