summaryrefslogtreecommitdiff
path: root/drivers/scsi/imm.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/imm.c')
-rw-r--r--drivers/scsi/imm.c233
1 files changed, 106 insertions, 127 deletions
diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c
index cea7f502e8ca..5c602c057798 100644
--- a/drivers/scsi/imm.c
+++ b/drivers/scsi/imm.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* imm.c -- low level driver for the IOMEGA MatchMaker
* parallel port SCSI host adapter.
*
@@ -50,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;
@@ -65,7 +71,7 @@ static void got_it(imm_struct *dev)
{
dev->base = dev->dev->port->base;
if (dev->cur_cmd)
- dev->cur_cmd->SCp.phase = 1;
+ imm_scsi_pointer(dev->cur_cmd)->phase = 1;
else
wake_up(dev->waiting);
}
@@ -365,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);
@@ -425,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);
@@ -588,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)
@@ -617,13 +632,14 @@ static inline int imm_send_command(struct scsi_cmnd *cmd)
* The driver appears to remain stable if we speed up the parallel port
* i/o in this function, but not elsewhere.
*/
-static int imm_completion(struct scsi_cmnd *cmd)
+static int imm_completion(struct scsi_cmnd *const cmd)
{
/* Return codes:
* -1 Error
* 0 Told to schedule
* 1 Finished data transfer
*/
+ struct scsi_pointer *scsi_pointer = imm_scsi_pointer(cmd);
imm_struct *dev = imm_dev(cmd->device->host);
unsigned short ppb = dev->base;
unsigned long start_jiffies = jiffies;
@@ -659,44 +675,43 @@ static int imm_completion(struct scsi_cmnd *cmd)
* a) Drive status is screwy (!ready && !present)
* b) Drive is requesting/sending more data than expected
*/
- if (((r & 0x88) != 0x88) || (cmd->SCp.this_residual <= 0)) {
+ if ((r & 0x88) != 0x88 || scsi_pointer->this_residual <= 0) {
imm_fail(dev, DID_ERROR);
return -1; /* ERROR_RETURN */
}
/* determine if we should use burst I/O */
if (dev->rd == 0) {
- fast = (bulk
- && (cmd->SCp.this_residual >=
- IMM_BURST_SIZE)) ? IMM_BURST_SIZE : 2;
- status = imm_out(dev, cmd->SCp.ptr, fast);
+ fast = bulk && scsi_pointer->this_residual >=
+ IMM_BURST_SIZE ? IMM_BURST_SIZE : 2;
+ status = imm_out(dev, scsi_pointer->ptr, fast);
} else {
- fast = (bulk
- && (cmd->SCp.this_residual >=
- IMM_BURST_SIZE)) ? IMM_BURST_SIZE : 1;
- status = imm_in(dev, cmd->SCp.ptr, fast);
+ fast = bulk && scsi_pointer->this_residual >=
+ IMM_BURST_SIZE ? IMM_BURST_SIZE : 1;
+ status = imm_in(dev, scsi_pointer->ptr, fast);
}
- cmd->SCp.ptr += fast;
- cmd->SCp.this_residual -= fast;
+ scsi_pointer->ptr += fast;
+ scsi_pointer->this_residual -= fast;
if (!status) {
imm_fail(dev, DID_BUS_BUSY);
return -1; /* ERROR_RETURN */
}
- if (cmd->SCp.buffer && !cmd->SCp.this_residual) {
+ if (scsi_pointer->buffer && !scsi_pointer->this_residual) {
/* if scatter/gather, advance to the next segment */
- if (cmd->SCp.buffers_residual--) {
- cmd->SCp.buffer++;
- cmd->SCp.this_residual =
- cmd->SCp.buffer->length;
- cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
+ if (scsi_pointer->buffers_residual--) {
+ scsi_pointer->buffer =
+ sg_next(scsi_pointer->buffer);
+ scsi_pointer->this_residual =
+ scsi_pointer->buffer->length;
+ scsi_pointer->ptr = sg_virt(scsi_pointer->buffer);
/*
* Make sure that we transfer even number of bytes
* otherwise it makes imm_byte_out() messy.
*/
- if (cmd->SCp.this_residual & 0x01)
- cmd->SCp.this_residual++;
+ if (scsi_pointer->this_residual & 0x01)
+ scsi_pointer->this_residual++;
}
}
/* Now check to see if the drive is ready to comunicate */
@@ -761,20 +776,21 @@ static void imm_interrupt(struct work_struct *work)
}
#endif
- if (cmd->SCp.phase > 1)
+ if (imm_scsi_pointer(cmd)->phase > 1)
imm_disconnect(dev);
imm_pb_dismiss(dev);
spin_lock_irqsave(host->host_lock, flags);
dev->cur_cmd = NULL;
- cmd->scsi_done(cmd);
+ scsi_done(cmd);
spin_unlock_irqrestore(host->host_lock, flags);
return;
}
-static int imm_engine(imm_struct *dev, struct scsi_cmnd *cmd)
+static int imm_engine(imm_struct *dev, struct scsi_cmnd *const cmd)
{
+ struct scsi_pointer *scsi_pointer = imm_scsi_pointer(cmd);
unsigned short ppb = dev->base;
unsigned char l = 0, h = 0;
int retv, x;
@@ -785,7 +801,7 @@ static int imm_engine(imm_struct *dev, struct scsi_cmnd *cmd)
if (dev->failed)
return 0;
- switch (cmd->SCp.phase) {
+ switch (scsi_pointer->phase) {
case 0: /* Phase 0 - Waiting for parport */
if (time_after(jiffies, dev->jstart + HZ)) {
/*
@@ -796,46 +812,47 @@ static int imm_engine(imm_struct *dev, struct scsi_cmnd *cmd)
return 0;
}
return 1; /* wait until imm_wakeup claims parport */
- /* Phase 1 - Connected */
- case 1:
+
+ case 1: /* Phase 1 - Connected */
imm_connect(dev, CONNECT_EPP_MAYBE);
- cmd->SCp.phase++;
+ scsi_pointer->phase++;
+ fallthrough;
- /* Phase 2 - We are now talking to the scsi bus */
- case 2:
+ case 2: /* Phase 2 - We are now talking to the scsi bus */
if (!imm_select(dev, scmd_id(cmd))) {
imm_fail(dev, DID_NO_CONNECT);
return 0;
}
- cmd->SCp.phase++;
+ scsi_pointer->phase++;
+ fallthrough;
- /* Phase 3 - Ready to accept a command */
- case 3:
+ case 3: /* Phase 3 - Ready to accept a command */
w_ctr(ppb, 0x0c);
if (!(r_str(ppb) & 0x80))
return 1;
if (!imm_send_command(cmd))
return 0;
- cmd->SCp.phase++;
+ scsi_pointer->phase++;
+ fallthrough;
- /* Phase 4 - Setup scatter/gather buffers */
- case 4:
+ case 4: /* Phase 4 - Setup scatter/gather buffers */
if (scsi_bufflen(cmd)) {
- cmd->SCp.buffer = scsi_sglist(cmd);
- cmd->SCp.this_residual = cmd->SCp.buffer->length;
- cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
+ scsi_pointer->buffer = scsi_sglist(cmd);
+ scsi_pointer->this_residual = scsi_pointer->buffer->length;
+ scsi_pointer->ptr = sg_virt(scsi_pointer->buffer);
} else {
- cmd->SCp.buffer = NULL;
- cmd->SCp.this_residual = 0;
- cmd->SCp.ptr = NULL;
+ scsi_pointer->buffer = NULL;
+ scsi_pointer->this_residual = 0;
+ scsi_pointer->ptr = NULL;
}
- cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1;
- cmd->SCp.phase++;
- if (cmd->SCp.this_residual & 0x01)
- cmd->SCp.this_residual++;
- /* Phase 5 - Pre-Data transfer stage */
- case 5:
+ scsi_pointer->buffers_residual = scsi_sg_count(cmd) - 1;
+ scsi_pointer->phase++;
+ if (scsi_pointer->this_residual & 0x01)
+ scsi_pointer->this_residual++;
+ fallthrough;
+
+ case 5: /* Phase 5 - Pre-Data transfer stage */
/* Spin lock for BUSY */
w_ctr(ppb, 0x0c);
if (!(r_str(ppb) & 0x80))
@@ -849,10 +866,10 @@ static int imm_engine(imm_struct *dev, struct scsi_cmnd *cmd)
if ((dev->dp) && (dev->rd))
if (imm_negotiate(dev))
return 0;
- cmd->SCp.phase++;
+ scsi_pointer->phase++;
+ fallthrough;
- /* Phase 6 - Data transfer stage */
- case 6:
+ case 6: /* Phase 6 - Data transfer stage */
/* Spin lock for BUSY */
w_ctr(ppb, 0x0c);
if (!(r_str(ppb) & 0x80))
@@ -865,10 +882,10 @@ static int imm_engine(imm_struct *dev, struct scsi_cmnd *cmd)
if (retv == 0)
return 1;
}
- cmd->SCp.phase++;
+ scsi_pointer->phase++;
+ fallthrough;
- /* Phase 7 - Post data transfer stage */
- case 7:
+ case 7: /* Phase 7 - Post data transfer stage */
if ((dev->dp) && (dev->rd)) {
if ((dev->mode == IMM_NIBBLE) || (dev->mode == IMM_PS2)) {
w_ctr(ppb, 0x4);
@@ -877,10 +894,10 @@ static int imm_engine(imm_struct *dev, struct scsi_cmnd *cmd)
w_ctr(ppb, 0x4);
}
}
- cmd->SCp.phase++;
+ scsi_pointer->phase++;
+ fallthrough;
- /* Phase 8 - Read status/message */
- case 8:
+ case 8: /* Phase 8 - Read status/message */
/* Check for data overrun */
if (imm_wait(dev) != (unsigned char) 0xb8) {
imm_fail(dev, DID_ERROR);
@@ -901,7 +918,6 @@ static int imm_engine(imm_struct *dev, struct scsi_cmnd *cmd)
w_ctr(ppb, 0x4);
}
return 0; /* Finished */
- break;
default:
printk("imm: Invalid scsi phase\n");
@@ -909,8 +925,7 @@ static int imm_engine(imm_struct *dev, struct scsi_cmnd *cmd)
return 0;
}
-static int imm_queuecommand_lck(struct scsi_cmnd *cmd,
- void (*done)(struct scsi_cmnd *))
+static int imm_queuecommand_lck(struct scsi_cmnd *cmd)
{
imm_struct *dev = imm_dev(cmd->device->host);
@@ -921,9 +936,8 @@ static int imm_queuecommand_lck(struct scsi_cmnd *cmd,
dev->failed = 0;
dev->jstart = jiffies;
dev->cur_cmd = cmd;
- cmd->scsi_done = done;
cmd->result = DID_ERROR << 16; /* default return code */
- cmd->SCp.phase = 0; /* bus free */
+ imm_scsi_pointer(cmd)->phase = 0; /* bus free */
schedule_delayed_work(&dev->imm_tq, 0);
@@ -940,7 +954,7 @@ static DEF_SCSI_QCMD(imm_queuecommand)
* be done in sd.c. Even if it gets fixed there, this will still
* work.
*/
-static int imm_biosparam(struct scsi_device *sdev, struct block_device *dev,
+static int imm_biosparam(struct scsi_device *sdev, struct gendisk *unused,
sector_t capacity, int ip[])
{
ip[0] = 0x40;
@@ -962,15 +976,13 @@ static int imm_abort(struct scsi_cmnd *cmd)
* have tied the SCSI_MESSAGE line high in the interface
*/
- switch (cmd->SCp.phase) {
+ switch (imm_scsi_pointer(cmd)->phase) {
case 0: /* Do not have access to parport */
case 1: /* Have not connected to interface */
dev->cur_cmd = NULL; /* Forget the problem */
return SUCCESS;
- break;
default: /* SCSI command sent, can not abort */
return FAILED;
- break;
}
}
@@ -990,7 +1002,7 @@ static int imm_reset(struct scsi_cmnd *cmd)
{
imm_struct *dev = imm_dev(cmd->device->host);
- if (cmd->SCp.phase)
+ if (imm_scsi_pointer(cmd)->phase)
imm_disconnect(dev);
dev->cur_cmd = NULL; /* Forget the problem */
@@ -1002,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. */
@@ -1014,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);
@@ -1040,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;
}
@@ -1065,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;
}
@@ -1088,17 +1100,7 @@ static int device_check(imm_struct *dev)
return -ENODEV;
}
-/*
- * imm cannot deal with highmem, so this causes all IO pages for this host
- * to reside in low memory (hence mapped)
- */
-static int imm_adjust_queue(struct scsi_device *device)
-{
- blk_queue_bounce_limit(device->request_queue, BLK_BOUNCE_HIGH);
- return 0;
-}
-
-static struct scsi_host_template imm_template = {
+static const struct scsi_host_template imm_template = {
.module = THIS_MODULE,
.proc_name = "imm",
.show_info = imm_show_info,
@@ -1111,7 +1113,7 @@ static struct scsi_host_template imm_template = {
.this_id = 7,
.sg_tablesize = SG_ALL,
.can_queue = 1,
- .slave_alloc = imm_adjust_queue,
+ .cmd_size = sizeof(struct scsi_pointer),
};
/***************************************************************************
@@ -1151,7 +1153,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;
@@ -1163,7 +1164,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();
@@ -1198,18 +1199,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 */
@@ -1282,21 +1274,8 @@ static struct parport_driver imm_driver = {
.name = "imm",
.match_port = imm_attach,
.detach = imm_detach,
- .devmodel = true,
};
+module_parport_driver(imm_driver);
-static int __init imm_driver_init(void)
-{
- printk("imm: Version %s\n", IMM_VERSION);
- return parport_register_driver(&imm_driver);
-}
-
-static void __exit imm_driver_exit(void)
-{
- parport_unregister_driver(&imm_driver);
-}
-
-module_init(imm_driver_init);
-module_exit(imm_driver_exit);
-
+MODULE_DESCRIPTION("IOMEGA MatchMaker parallel port SCSI host adapter driver");
MODULE_LICENSE("GPL");