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

Fix in the imm driver the same problem that was fixed in the ppa driver by
commit 68a4f84a17 ("scsi: ppa: Add a module parameter for the transfer
mode").

Tested and confirmed working with an Iomega Z250P zip drive and a StarTech
PEX1P2 AX99100 PCIe parallel port.

Signed-off-by: Alex Henrie <alexhenrie24@gmail.com>
Link: https://lore.kernel.org/r/20230831054620.515611-1-alexhenrie24@gmail.com
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
Alex Henrie 2023-08-30 23:23:48 -06:00 committed by Martin K. Petersen
parent 1345a7d909
commit b0597fd5a9
3 changed files with 37 additions and 52 deletions

View file

@ -834,21 +834,6 @@ config SCSI_IMM
To compile this driver as a module, choose M here: the
module will be called imm.
config SCSI_IZIP_EPP16
bool "ppa/imm option - Use slow (but safe) EPP-16"
depends on SCSI_IMM
help
EPP (Enhanced Parallel Port) is a standard for parallel ports which
allows them to act as expansion buses that can handle up to 64
peripheral devices.
Some parallel port chipsets are slower than their motherboard, and
so we have to control the state of the chipset's FIFO queue every
now and then to avoid data loss. This will be done if you say Y
here.
Generally, saying Y is the safe option and slows things down a bit.
config SCSI_IZIP_SLOW_CTR
bool "ppa/imm option - Assume slow parport control register"
depends on SCSI_PPA || SCSI_IMM

View file

@ -51,10 +51,15 @@ typedef struct {
} imm_struct;
static void imm_reset_pulse(unsigned int base);
static int device_check(imm_struct *dev);
static int device_check(imm_struct *dev, bool autodetect);
#include "imm.h"
static unsigned int mode = IMM_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 inline imm_struct *imm_dev(struct Scsi_Host *host)
{
return *(imm_struct **)&host->hostdata;
@ -366,13 +371,10 @@ static int imm_out(imm_struct *dev, char *buffer, int len)
case IMM_EPP_8:
epp_reset(ppb);
w_ctr(ppb, 0x4);
#ifdef CONFIG_SCSI_IZIP_EPP16
if (!(((long) buffer | len) & 0x01))
outsw(ppb + 4, buffer, len >> 1);
#else
if (!(((long) buffer | len) & 0x03))
if (dev->mode == IMM_EPP_32 && !(((long) buffer | len) & 0x03))
outsl(ppb + 4, buffer, len >> 2);
#endif
else if (dev->mode == IMM_EPP_16 && !(((long) buffer | len) & 0x01))
outsw(ppb + 4, buffer, len >> 1);
else
outsb(ppb + 4, buffer, len);
w_ctr(ppb, 0xc);
@ -426,13 +428,10 @@ static int imm_in(imm_struct *dev, char *buffer, int len)
case IMM_EPP_8:
epp_reset(ppb);
w_ctr(ppb, 0x24);
#ifdef CONFIG_SCSI_IZIP_EPP16
if (!(((long) buffer | len) & 0x01))
insw(ppb + 4, buffer, len >> 1);
#else
if (!(((long) buffer | len) & 0x03))
insl(ppb + 4, buffer, len >> 2);
#endif
if (dev->mode == IMM_EPP_32 && !(((long) buffer | len) & 0x03))
insw(ppb + 4, buffer, len >> 2);
else if (dev->mode == IMM_EPP_16 && !(((long) buffer | len) & 0x01))
insl(ppb + 4, buffer, len >> 1);
else
insb(ppb + 4, buffer, len);
w_ctr(ppb, 0x2c);
@ -589,13 +588,28 @@ static int imm_select(imm_struct *dev, int target)
static int imm_init(imm_struct *dev)
{
bool autodetect = dev->mode == IMM_AUTODETECT;
if (autodetect) {
int modes = dev->dev->port->modes;
/* Mode detection works up the chain of speed
* This avoids a nasty if-then-else-if-... tree
*/
dev->mode = IMM_NIBBLE;
if (modes & PARPORT_MODE_TRISTATE)
dev->mode = IMM_PS2;
}
if (imm_connect(dev, 0) != 1)
return -EIO;
imm_reset_pulse(dev->base);
mdelay(1); /* Delay to allow devices to settle */
imm_disconnect(dev);
mdelay(1); /* Another delay to allow devices to settle */
return device_check(dev);
return device_check(dev, autodetect);
}
static inline int imm_send_command(struct scsi_cmnd *cmd)
@ -1000,7 +1014,7 @@ static int imm_reset(struct scsi_cmnd *cmd)
return SUCCESS;
}
static int device_check(imm_struct *dev)
static int device_check(imm_struct *dev, bool autodetect)
{
/* 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. */
@ -1012,8 +1026,8 @@ static int device_check(imm_struct *dev)
old_mode = dev->mode;
for (loop = 0; loop < 8; loop++) {
/* Attempt to use EPP for Test Unit Ready */
if ((ppb & 0x0007) == 0x0000)
dev->mode = IMM_EPP_32;
if (autodetect && (ppb & 0x0007) == 0x0000)
dev->mode = IMM_EPP_8;
second_pass:
imm_connect(dev, CONNECT_EPP_MAYBE);
@ -1038,7 +1052,7 @@ static int device_check(imm_struct *dev)
udelay(1000);
imm_disconnect(dev);
udelay(1000);
if (dev->mode == IMM_EPP_32) {
if (dev->mode != old_mode) {
dev->mode = old_mode;
goto second_pass;
}
@ -1063,7 +1077,7 @@ static int device_check(imm_struct *dev)
udelay(1000);
imm_disconnect(dev);
udelay(1000);
if (dev->mode == IMM_EPP_32) {
if (dev->mode != old_mode) {
dev->mode = old_mode;
goto second_pass;
}
@ -1150,7 +1164,6 @@ static int __imm_attach(struct parport *pb)
DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waiting);
DEFINE_WAIT(wait);
int ports;
int modes, ppb;
int err = -ENOMEM;
struct pardev_cb imm_cb;
@ -1162,7 +1175,7 @@ static int __imm_attach(struct parport *pb)
dev->base = -1;
dev->mode = IMM_AUTODETECT;
dev->mode = mode < IMM_UNKNOWN ? mode : IMM_AUTODETECT;
INIT_LIST_HEAD(&dev->list);
temp = find_parent();
@ -1197,18 +1210,9 @@ static int __imm_attach(struct parport *pb)
}
dev->waiting = NULL;
finish_wait(&waiting, &wait);
ppb = dev->base = dev->dev->port->base;
dev->base = dev->dev->port->base;
dev->base_hi = dev->dev->port->base_hi;
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 = IMM_NIBBLE;
if (modes & PARPORT_MODE_TRISTATE)
dev->mode = IMM_PS2;
w_ctr(dev->base, 0x0c);
/* Done configuration */

View file

@ -100,11 +100,7 @@ static char *IMM_MODE_STRING[] =
[IMM_PS2] = "PS/2",
[IMM_EPP_8] = "EPP 8 bit",
[IMM_EPP_16] = "EPP 16 bit",
#ifdef CONFIG_SCSI_IZIP_EPP16
[IMM_EPP_32] = "EPP 16 bit",
#else
[IMM_EPP_32] = "EPP 32 bit",
#endif
[IMM_UNKNOWN] = "Unknown",
};