- Convert ide-scsi to the new data accessors and cleanup
the !use_sg code paths.
In old code the MODE_SENSE or MODE_SELECT code paths still
assumed scsi_cmnd->request_buffer is a linear char pointer.
This means that this driver was broken since 2.6.17. Though
I admit this assumption is hidden behind a flag:
test_bit(PC_TRANSFORM, &pc->flags).
I have hacked these code paths to properly handle an sg_count==1,
which is true in todays implementation of MODE_SENSE or
MODE_SELECT.
Signed-off-by: Boaz Harrosh <[EMAIL PROTECTED]>
---
drivers/scsi/ide-scsi.c | 85 +++++++++++++++++++++++++++--------------------
1 files changed, 49 insertions(+), 36 deletions(-)
diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
index 1cc01ac..5c9a444 100644
--- a/drivers/scsi/ide-scsi.c
+++ b/drivers/scsi/ide-scsi.c
@@ -63,7 +63,7 @@
typedef struct idescsi_pc_s {
u8 c[12]; /* Actual packet bytes */
- int request_transfer; /* Bytes to transfer */
+ unsigned int request_transfer; /* Bytes to transfer */
int actually_transferred; /* Bytes actually transferred */
int buffer_size; /* Size of our data buffer */
struct request *rq; /* The corresponding request */
@@ -175,7 +175,8 @@ static void idescsi_input_buffers (ide_drive_t *drive,
idescsi_pc_t *pc, unsigne
char *buf;
while (bcount) {
- if (pc->sg - (struct scatterlist *)
pc->scsi_cmd->request_buffer > pc->scsi_cmd->use_sg) {
+ if (pc->sg - scsi_sglist(pc->scsi_cmd) >
+ scsi_sg_count(pc->scsi_cmd)) {
printk (KERN_ERR "ide-scsi: scatter gather table too
small, discarding data\n");
idescsi_discard_data (drive, bcount);
return;
@@ -210,7 +211,8 @@ static void idescsi_output_buffers (ide_drive_t *drive,
idescsi_pc_t *pc, unsign
char *buf;
while (bcount) {
- if (pc->sg - (struct scatterlist *)
pc->scsi_cmd->request_buffer > pc->scsi_cmd->use_sg) {
+ if (pc->sg - scsi_sglist(pc->scsi_cmd) >
+ scsi_sg_count(pc->scsi_cmd)) {
printk (KERN_ERR "ide-scsi: scatter gather table too
small, padding with zeros\n");
idescsi_output_zeros (drive, bcount);
return;
@@ -245,21 +247,21 @@ static void idescsi_output_buffers (ide_drive_t *drive,
idescsi_pc_t *pc, unsign
*/
static inline void idescsi_transform_pc1 (ide_drive_t *drive, idescsi_pc_t *pc)
{
- u8 *c = pc->c, *scsi_buf = pc->buffer, *sc = pc->scsi_cmd->cmnd;
- char *atapi_buf;
-
if (!test_bit(PC_TRANSFORM, &pc->flags))
return;
if (drive->media == ide_cdrom || drive->media == ide_optical) {
+ u8 *c = pc->c;
+
if (c[0] == READ_6 || c[0] == WRITE_6) {
c[8] = c[4]; c[5] = c[3]; c[4] =
c[2];
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) {
+ u8 *sc = pc->scsi_cmd->cmnd;
+ char *atapi_buf;
unsigned short new_len;
- if (!scsi_buf)
- return;
+
if ((atapi_buf = kmalloc(pc->buffer_size + 4,
GFP_ATOMIC)) == NULL)
return;
memset(atapi_buf, 0, pc->buffer_size + 4);
@@ -272,42 +274,62 @@ static inline void idescsi_transform_pc1 (ide_drive_t
*drive, idescsi_pc_t *pc)
c[7] = new_len >> 8;
c[9] = sc[5];
if (c[0] == MODE_SELECT_10) {
+ struct scatterlist *sg =
scsi_sglist(pc->scsi_cmd);
+ u8 *scsi_buf;
+
+ /* FIXME: Use proper copy_from_sg(...) */
+ BUG_ON(!sg || sg->length < 4);
+ if (pc->buffer_size > sg->length)
+ pc->buffer_size = sg->length;
+ scsi_buf = (u8 *)(kmap(sg->page) + sg->offset);
+
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);
+ kunmap(sg->page);
}
pc->buffer = atapi_buf;
- pc->request_transfer += 4;
pc->buffer_size += 4;
+ pc->request_transfer = pc->buffer_size;
}
}
}
static inline void idescsi_transform_pc2 (ide_drive_t *drive, idescsi_pc_t *pc)
{
- u8 *atapi_buf = pc->buffer;
- u8 *sc = pc->scsi_cmd->cmnd;
- u8 *scsi_buf = pc->scsi_cmd->request_buffer;
-
if (!test_bit(PC_TRANSFORM, &pc->flags))
return;
if (drive->media == ide_cdrom || drive->media == ide_optical) {
- if (pc->c[0] == MODE_SENSE_10 && sc[0] == MODE_SENSE) {
+ u8 *atapi_buf = pc->buffer;
+ u8 *sc = pc->scsi_cmd->cmnd;
+ u8 *scsi_buf;
+ int request_transfer;
+ struct scatterlist *sg = scsi_sglist(pc->scsi_cmd);
+
+ /* FIXME: Use proper copy_to_sg(...) */
+ BUG_ON(!sg || sg->length < 4);
+ request_transfer = min(sg->length - 4, pc->request_transfer -
8);
+ scsi_buf = (u8 *)(kmap(sg->page) + sg->offset);
+ if (atapi_buf &&
+ (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);
+ memcpy(scsi_buf + 4, atapi_buf + 8, request_transfer);
}
if (pc->c[0] == INQUIRY) {
scsi_buf[2] |= 2; /*
ansi_revision */
scsi_buf[3] = (scsi_buf[3] & 0xf0) | 2; /* response
data format */
}
+ kunmap(sg->page);
+ }
+ if (pc->buffer) {
+ kfree(pc->buffer);
+ pc->buffer = NULL;
}
- if (atapi_buf && atapi_buf != scsi_buf)
- kfree(atapi_buf);
}
static void hexdump(u8 *x, int len)
@@ -393,7 +415,6 @@ static int idescsi_end_request (ide_drive_t *drive, int
uptodate, int nrsecs)
idescsi_pc_t *pc = (idescsi_pc_t *) rq->special;
int log = test_bit(IDESCSI_LOG_CMD, &scsi->log);
struct Scsi_Host *host;
- u8 *scsi_buf;
int errors = rq->errors;
unsigned long flags;
@@ -435,6 +456,7 @@ static int idescsi_end_request (ide_drive_t *drive, int
uptodate, int nrsecs)
} else {
pc->scsi_cmd->result = DID_OK << 16;
idescsi_transform_pc2 (drive, pc);
+#if 0
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) {
@@ -443,6 +465,7 @@ static int idescsi_end_request (ide_drive_t *drive, int
uptodate, int nrsecs)
hexdump(scsi_buf, min_t(unsigned, 16,
pc->scsi_cmd->request_bufflen));
} else printk("\n");
}
+#endif
}
host = pc->scsi_cmd->device->host;
spin_lock_irqsave(host->host_lock, flags);
@@ -637,19 +660,14 @@ static int idescsi_map_sg(ide_drive_t *drive,
idescsi_pc_t *pc)
return 1;
sg = hwif->sg_table;
- scsi_sg = pc->scsi_cmd->request_buffer;
- segments = pc->scsi_cmd->use_sg;
+ scsi_sg = scsi_sglist(pc->scsi_cmd);
+ segments = scsi_sg_count(pc->scsi_cmd);
if (segments > hwif->sg_max_nents)
return 1;
- if (!segments) {
- hwif->sg_nents = 1;
- sg_init_one(sg, pc->scsi_cmd->request_buffer,
pc->request_transfer);
- } else {
- hwif->sg_nents = segments;
- memcpy(sg, scsi_sg, sizeof(*sg) * segments);
- }
+ hwif->sg_nents = segments;
+ memcpy(sg, scsi_sg, sizeof(*sg) * segments);
return 0;
}
@@ -667,7 +685,7 @@ static ide_startstop_t idescsi_issue_pc (ide_drive_t
*drive, idescsi_pc_t *pc)
scsi->pc=pc; /* Set
the current packet command */
pc->actually_transferred=0; /* We
haven't transferred any data yet */
pc->current_position=pc->buffer;
- bcount.all = min(pc->request_transfer, 63 * 1024); /*
Request to transfer the entire buffer at once */
+ bcount.all = min_t(unsigned, pc->request_transfer, 63 * 1024); /*
Request to transfer the entire buffer at once */
feature.all = 0;
if (drive->using_dma && !idescsi_map_sg(drive, pc)) {
@@ -905,15 +923,10 @@ static int idescsi_queue (struct scsi_cmnd *cmd,
pc->flags = 0;
pc->rq = rq;
memcpy (pc->c, cmd->cmnd, cmd->cmd_len);
- if (cmd->use_sg) {
- pc->buffer = NULL;
- pc->sg = cmd->request_buffer;
- } else {
- pc->buffer = cmd->request_buffer;
- pc->sg = NULL;
- }
+ pc->buffer = NULL;
+ pc->sg = scsi_sglist(cmd);
pc->b_count = 0;
- pc->request_transfer = pc->buffer_size = cmd->request_bufflen;
+ pc->request_transfer = pc->buffer_size = scsi_bufflen(cmd);
pc->scsi_cmd = cmd;
pc->done = done;
pc->timeout = jiffies + cmd->timeout_per_command;
--
1.5.3.1
-
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at http://vger.kernel.org/majordomo-info.html