patch-2.1.96 linux/drivers/scsi/ide-scsi.c
Next file: linux/drivers/scsi/ide-scsi.h
Previous file: linux/drivers/scsi/ibmmca.c
Back to the patch index
Back to the overall index
- Lines: 330
- Date:
Fri Apr 10 15:22:21 1998
- Orig file:
v2.1.95/linux/drivers/scsi/ide-scsi.c
- Orig date:
Sat Jan 10 10:42:55 1998
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/ide-scsi.c linux/drivers/scsi/ide-scsi.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/scsi/ide-scsi.c Version 0.5 Jan 2, 1998
+ * linux/drivers/scsi/ide-scsi.c Version 0.6 Jan 27, 1998
*
* Copyright (C) 1996 - 1998 Gadi Oxman <gadio@netvision.net.il>
*/
@@ -20,9 +20,12 @@
* Use variable timeout for each command.
* Ver 0.5 Jan 2 98 Fix previous PD/CD support.
* Allow disabling of SCSI-6 to SCSI-10 transformation.
+ * Ver 0.6 Jan 27 98 Allow disabling of SCSI command translation layer
+ * for access through /dev/sg.
+ * Fix MODE_SENSE_6/MODE_SELECT_6/INQUIRY translation.
*/
-#define IDESCSI_VERSION "0.5"
+#define IDESCSI_VERSION "0.6"
#include <linux/module.h>
#include <linux/types.h>
@@ -37,6 +40,7 @@
#include <asm/io.h>
#include <asm/bitops.h>
+#include <asm/uaccess.h>
#include "../block/ide.h"
@@ -44,6 +48,7 @@
#include "hosts.h"
#include "sd.h"
#include "ide-scsi.h"
+#include <scsi/sg.h>
#define IDESCSI_DEBUG_LOG 0
@@ -68,12 +73,25 @@
*/
#define PC_DMA_IN_PROGRESS 0 /* 1 while DMA in progress */
#define PC_WRITING 1 /* Data direction */
+#define PC_TRANSFORM 2 /* transform SCSI commands */
+
+/*
+ * SCSI command transformation layer
+ */
+#define IDESCSI_TRANSFORM 0 /* Enable/Disable transformation */
+#define IDESCSI_SG_TRANSFORM 1 /* /dev/sg transformation */
+
+/*
+ * Log flags
+ */
+#define IDESCSI_LOG_CMD 0 /* Log SCSI commands */
typedef struct {
ide_drive_t *drive;
idescsi_pc_t *pc; /* Current packet command */
unsigned int flags; /* Status/Action flags */
- int transform; /* Transform SCSI-6 commands */
+ int transform; /* SCSI cmd translation layer */
+ int log; /* log flags */
} idescsi_scsi_t;
/*
@@ -153,11 +171,10 @@
*/
static inline void idescsi_transform_pc1 (ide_drive_t *drive, idescsi_pc_t *pc)
{
- idescsi_scsi_t *scsi = drive->driver_data;
- u8 *c = pc->c, *buf = pc->buffer, *sc = pc->scsi_cmd->cmnd;
- int i;
+ u8 *c = pc->c, *scsi_buf = pc->buffer, *sc = pc->scsi_cmd->cmnd;
+ char *atapi_buf;
- if (!scsi->transform)
+ if (!test_bit(PC_TRANSFORM, &pc->flags))
return;
if (drive->media == ide_cdrom) {
if (c[0] == READ_6 || c[0] == WRITE_6) {
@@ -165,35 +182,54 @@
c[3] = c[1] & 0x1f; c[2] = 0; c[1] &= 0xe0;
c[0] += (READ_10 - READ_6);
}
- if (c[0] == MODE_SENSE || (c[0] == MODE_SELECT && buf[3] == 8)) {
- pc->request_transfer -= 4;
+ if (c[0] == MODE_SENSE || c[0] == MODE_SELECT) {
+ if (!scsi_buf)
+ return;
+ if ((atapi_buf = kmalloc(pc->buffer_size + 4, GFP_ATOMIC)) == NULL)
+ return;
+ memset(atapi_buf, 0, pc->buffer_size + 4);
memset (c, 0, 12);
- c[0] = sc[0] | 0x40; c[2] = sc[2]; c[8] = sc[4] - 4;
- if (c[0] == MODE_SENSE_10) return;
- for (i = 0; i <= 7; i++) buf[i] = 0;
- for (i = 8; i < pc->buffer_size - 4; i++) buf[i] = buf[i + 4];
+ c[0] = sc[0] | 0x40; c[1] = sc[1]; c[2] = sc[2];
+ c[8] = sc[4] + 4; c[9] = sc[5];
+ if (sc[4] + 4 > 255)
+ c[7] = sc[4] + 4 - 255;
+ if (c[0] == MODE_SELECT_10) {
+ atapi_buf[1] = scsi_buf[0]; /* Mode data length */
+ atapi_buf[2] = scsi_buf[1]; /* Medium type */
+ atapi_buf[3] = scsi_buf[2]; /* Device specific parameter */
+ atapi_buf[7] = scsi_buf[3]; /* Block descriptor length */
+ memcpy(atapi_buf + 8, scsi_buf + 4, pc->buffer_size - 4);
+ }
+ pc->buffer = atapi_buf;
+ pc->request_transfer += 4;
+ pc->buffer_size += 4;
}
}
}
static inline void idescsi_transform_pc2 (ide_drive_t *drive, idescsi_pc_t *pc)
{
- idescsi_scsi_t *scsi = drive->driver_data;
- u8 *buf = pc->buffer;
- int i;
+ u8 *atapi_buf = pc->buffer;
+ u8 *sc = pc->scsi_cmd->cmnd;
+ u8 *scsi_buf = pc->scsi_cmd->request_buffer;
- if (!scsi->transform)
+ if (!test_bit(PC_TRANSFORM, &pc->flags))
return;
if (drive->media == ide_cdrom) {
- if (pc->c[0] == MODE_SENSE_10 && pc->scsi_cmd->cmnd[0] == MODE_SENSE) {
- buf[0] = buf[1]; buf[1] = buf[2];
- buf[2] = 0; buf[3] = 8;
- for (i = pc->buffer_size - 1; i >= 12; i--) buf[i] = buf[i - 4];
- for (i = 11; i >= 4; i--) buf[i] = 0;
+ if (pc->c[0] == MODE_SENSE_10 && sc[0] == MODE_SENSE) {
+ scsi_buf[0] = atapi_buf[1]; /* Mode data length */
+ scsi_buf[1] = atapi_buf[2]; /* Medium type */
+ scsi_buf[2] = atapi_buf[3]; /* Device specific parameter */
+ scsi_buf[3] = atapi_buf[7]; /* Block descriptor length */
+ memcpy(scsi_buf + 4, atapi_buf + 8, pc->request_transfer - 8);
+ }
+ if (pc->c[0] == INQUIRY) {
+ scsi_buf[2] |= 2; /* ansi_revision */
+ scsi_buf[3] = (scsi_buf[3] & 0xf0) | 2; /* response data format */
}
- if (pc->c[0] == INQUIRY)
- buf[2] |= 2;
}
+ if (atapi_buf && atapi_buf != scsi_buf)
+ kfree(atapi_buf);
}
static inline void idescsi_free_bh (struct buffer_head *bh)
@@ -207,12 +243,24 @@
}
}
+static void hexdump(u8 *x, int len)
+{
+ int i;
+
+ printk("[ ");
+ for (i = 0; i < len; i++)
+ printk("%x ", x[i]);
+ printk("]\n");
+}
+
static void idescsi_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
{
ide_drive_t *drive = hwgroup->drive;
idescsi_scsi_t *scsi = drive->driver_data;
struct request *rq = hwgroup->rq;
idescsi_pc_t *pc = (idescsi_pc_t *) rq->buffer;
+ int log = test_bit(IDESCSI_LOG_CMD, &scsi->log);
+ u8 *scsi_buf = pc->scsi_cmd->request_buffer;
if (rq->cmd != IDESCSI_PC_RQ) {
ide_end_request (uptodate, hwgroup);
@@ -220,21 +268,23 @@
}
ide_end_drive_cmd (drive, 0, 0);
if (rq->errors >= ERROR_MAX) {
-#if IDESCSI_DEBUG_LOG
- printk ("ide-scsi: %s: I/O error for %lu\n", drive->name, pc->scsi_cmd->serial_number);
-#endif /* IDESCSI_DEBUG_LOG */
pc->scsi_cmd->result = DID_ERROR << 16;
+ if (log)
+ printk ("ide-scsi: %s: I/O error for %lu\n", drive->name, pc->scsi_cmd->serial_number);
} else if (rq->errors) {
-#if IDESCSI_DEBUG_LOG
- printk ("ide-scsi: %s: check condition for %lu\n", drive->name, pc->scsi_cmd->serial_number);
-#endif /* IDESCSI_DEBUG_LOG */
pc->scsi_cmd->result = (CHECK_CONDITION << 1) | (DID_OK << 16);
+ if (log)
+ printk ("ide-scsi: %s: check condition for %lu\n", drive->name, pc->scsi_cmd->serial_number);
} else {
-#if IDESCSI_DEBUG_LOG
- printk ("ide-scsi: %s: success for %lu\n", drive->name, pc->scsi_cmd->serial_number);
-#endif /* IDESCSI_DEBUG_LOG */
pc->scsi_cmd->result = DID_OK << 16;
idescsi_transform_pc2 (drive, pc);
+ if (log) {
+ printk ("ide-scsi: %s: suc %lu", drive->name, pc->scsi_cmd->serial_number);
+ if (!test_bit(PC_WRITING, &pc->flags) && pc->actually_transferred && pc->actually_transferred <= 1024 && pc->buffer) {
+ printk(", rst = ");
+ hexdump(scsi_buf, IDE_MIN(16, pc->scsi_cmd->request_bufflen));
+ } else printk("\n");
+ }
}
pc->done(pc->scsi_cmd);
idescsi_free_bh (rq->bh);
@@ -274,9 +324,8 @@
status = GET_STAT(); /* Clear the interrupt */
if ((status & DRQ_STAT) == 0) { /* No more interrupts */
-#if IDESCSI_DEBUG_LOG
- printk (KERN_INFO "Packet command completed, %d bytes transferred\n", pc->actually_transferred);
-#endif /* IDESCSI_DEBUG_LOG */
+ if (test_bit(IDESCSI_LOG_CMD, &scsi->log))
+ printk (KERN_INFO "Packet command completed, %d bytes transferred\n", pc->actually_transferred);
ide_sti();
if (status & ERR_STAT)
rq->errors++;
@@ -306,11 +355,13 @@
}
}
if (ireason & IDESCSI_IREASON_IO) {
+ clear_bit(PC_WRITING, &pc->flags);
if (pc->sg)
idescsi_input_buffers (drive, pc, bcount);
else
atapi_input_bytes (drive,pc->current_position,bcount);
} else {
+ set_bit(PC_WRITING, &pc->flags);
if (pc->sg)
idescsi_output_buffers (drive, pc, bcount);
else
@@ -421,7 +472,8 @@
ide_add_setting(drive, "bios_cyl", SETTING_RW, -1, -1, TYPE_SHORT, 0, 1023, 1, 1, &drive->bios_cyl, NULL);
ide_add_setting(drive, "bios_head", SETTING_RW, -1, -1, TYPE_BYTE, 0, 255, 1, 1, &drive->bios_head, NULL);
ide_add_setting(drive, "bios_sect", SETTING_RW, -1, -1, TYPE_BYTE, 0, 63, 1, 1, &drive->bios_sect, NULL);
- ide_add_setting(drive, "transform", SETTING_RW, -1, -1, TYPE_INT, 0, 1, 1, 1, &scsi->transform, NULL);
+ ide_add_setting(drive, "transform", SETTING_RW, -1, -1, TYPE_INT, 0, 3, 1, 1, &scsi->transform, NULL);
+ ide_add_setting(drive, "log", SETTING_RW, -1, -1, TYPE_INT, 0, 1, 1, 1, &scsi->log, NULL);
}
/*
@@ -437,7 +489,11 @@
scsi->drive = drive;
if (drive->id && (drive->id->config & 0x0060) == 0x20)
set_bit (IDESCSI_DRQ_INTERRUPT, &scsi->flags);
- scsi->transform = 1;
+ set_bit(IDESCSI_TRANSFORM, &scsi->transform);
+ clear_bit(IDESCSI_SG_TRANSFORM, &scsi->transform);
+#if IDESCSI_DEBUG_LOG
+ set_bit(IDESCSI_LOG_CMD, &scsi->log);
+#endif /* IDESCSI_DEBUG_LOG */
idescsi_add_settings(drive);
}
@@ -554,6 +610,19 @@
return "SCSI host adapter emulation for IDE ATAPI devices";
}
+int idescsi_ioctl (Scsi_Device *dev, int cmd, void *arg)
+{
+ ide_drive_t *drive = idescsi_drives[dev->id];
+ idescsi_scsi_t *scsi = drive->driver_data;
+
+ if (cmd == SG_SET_TRANSFORM) {
+ set_bit(IDESCSI_SG_TRANSFORM, &scsi->transform);
+ return 0;
+ } else if (cmd == SG_GET_TRANSFORM)
+ return put_user(test_bit(IDESCSI_SG_TRANSFORM, &scsi->transform), (int *) arg);
+ return -EINVAL;
+}
+
static inline struct buffer_head *idescsi_kmalloc_bh (int count)
{
struct buffer_head *bh, *bhp, *first_bh;
@@ -624,20 +693,27 @@
return first_bh;
}
+static inline int should_transform(ide_drive_t *drive, Scsi_Cmnd *cmd)
+{
+ idescsi_scsi_t *scsi = drive->driver_data;
+
+ if (MAJOR(cmd->request.rq_dev) == SCSI_GENERIC_MAJOR)
+ return test_bit(IDESCSI_SG_TRANSFORM, &scsi->transform);
+ return test_bit(IDESCSI_TRANSFORM, &scsi->transform);
+}
+
int idescsi_queue (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
{
ide_drive_t *drive = idescsi_drives[cmd->target];
+ idescsi_scsi_t *scsi;
struct request *rq = NULL;
idescsi_pc_t *pc = NULL;
-#if IDESCSI_DEBUG_LOG
- printk ("idescsi_queue called, serial = %lu, cmd[0] = %x, id = %d\n", cmd->serial_number, cmd->cmnd[0], cmd->target);
-#endif /* IDESCSI_DEBUG_LOG */
-
if (!drive) {
printk (KERN_ERR "ide-scsi: drive id %d not present\n", cmd->target);
goto abort;
}
+ scsi = drive->driver_data;
pc = kmalloc (sizeof (idescsi_pc_t), GFP_ATOMIC);
rq = kmalloc (sizeof (struct request), GFP_ATOMIC);
if (rq == NULL || pc == NULL) {
@@ -661,7 +737,19 @@
pc->scsi_cmd = cmd;
pc->done = done;
pc->timeout = jiffies + cmd->timeout_per_command;
+
+ if (should_transform(drive, cmd))
+ set_bit(PC_TRANSFORM, &pc->flags);
idescsi_transform_pc1 (drive, pc);
+
+ if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) {
+ printk ("ide-scsi: %s: que %lu, cmd = ", drive->name, cmd->serial_number);
+ hexdump(cmd->cmnd, cmd->cmd_len);
+ if (memcmp(pc->c, cmd->cmnd, cmd->cmd_len)) {
+ printk ("ide-scsi: %s: que %lu, tsl = ", drive->name, cmd->serial_number);
+ hexdump(pc->c, 12);
+ }
+ }
ide_init_drive_cmd (rq);
rq->buffer = (char *) pc;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov