Commit cb406274 authored by Kai Mäkisara's avatar Kai Mäkisara Committed by James Bottomley

[PATCH] SCSI tape descriptor based sense data support

The patch at the end of this message converts the SCSI tape driver to support
also descriptor based sense data. Test for deferred sense data have been added
in a couple of places and the EOM tests have been unified. Some tests have been
simplified but the patch is not meant to change the current behavior. The
patch is against 2.6.11-rc4 and has been tested to some extent.

The patch also includes the msleep_interruptible change from from kernel
janitors.

Thanks to Doug Gilbert for doing a first version of this sense data
conversion.
Signed-off-by: default avatarKai Makisara <kai.makisara@kolumbus.fi>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@SteelEye.com>
parent 178a856d
......@@ -9,7 +9,7 @@
Steve Hirsch, Andreas Koppenh"ofer, Michael Leodolter, Eyal Lebedinsky,
Michael Schaefer, J"org Weule, and Eric Youngdale.
Copyright 1992 - 2004 Kai Makisara
Copyright 1992 - 2005 Kai Makisara
email Kai.Makisara@kolumbus.fi
Some small formal changes - aeb, 950809
......@@ -17,7 +17,7 @@
Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
*/
static char *verstr = "20041025";
static char *verstr = "20050213";
#include <linux/module.h>
......@@ -144,7 +144,7 @@ static char *st_formats[] = {
#error "Buffer size should not exceed (2 << 24 - 1) bytes!"
#endif
DEB( static int debugging = DEBUG; )
static int debugging = DEBUG;
#define MAX_RETRIES 0
#define MAX_WRITE_RETRIES 0
......@@ -262,25 +262,57 @@ static inline char *tape_name(struct scsi_tape *tape)
return tape->disk->disk_name;
}
static void st_analyze_sense(struct scsi_request *SRpnt, struct st_cmdstatus *s)
{
const u8 *ucp;
const u8 *sense = SRpnt->sr_sense_buffer;
s->have_sense = scsi_request_normalize_sense(SRpnt, &s->sense_hdr);
if (s->have_sense) {
s->remainder_valid =
scsi_get_sense_info_fld(sense, SCSI_SENSE_BUFFERSIZE, &s->uremainder64);
switch (sense[0] & 0x7f) {
case 0x71:
s->deferred = 1;
case 0x70:
s->fixed_format = 1;
s->flags = sense[2] & 0xe0;
break;
case 0x73:
s->deferred = 1;
case 0x72:
s->fixed_format = 0;
ucp = scsi_sense_desc_find(sense, SCSI_SENSE_BUFFERSIZE, 4);
s->flags = ucp ? (ucp[3] & 0xe0) : 0;
break;
default:
s->flags = 0;
}
}
}
/* Convert the result to success code */
static int st_chk_result(struct scsi_tape *STp, struct scsi_request * SRpnt)
{
int result = SRpnt->sr_result;
unsigned char *sense = SRpnt->sr_sense_buffer, scode;
u8 scode;
DEB(const char *stp;)
char *name = tape_name(STp);
struct st_cmdstatus *cmdstatp;
if (!result) {
sense[0] = 0; /* We don't have sense data if this byte is zero */
if (!result)
return 0;
}
if ((driver_byte(result) & DRIVER_MASK) == DRIVER_SENSE)
scode = sense[2] & 0x0f;
else {
sense[0] = 0;
cmdstatp = &STp->buffer->cmdstat;
st_analyze_sense(STp->buffer->last_SRpnt, cmdstatp);
if (cmdstatp->have_sense)
scode = STp->buffer->cmdstat.sense_hdr.sense_key;
else
scode = 0;
}
DEB(
if (debugging) {
......@@ -289,29 +321,30 @@ static int st_chk_result(struct scsi_tape *STp, struct scsi_request * SRpnt)
SRpnt->sr_cmnd[0], SRpnt->sr_cmnd[1], SRpnt->sr_cmnd[2],
SRpnt->sr_cmnd[3], SRpnt->sr_cmnd[4], SRpnt->sr_cmnd[5],
SRpnt->sr_bufflen);
if (driver_byte(result) & DRIVER_SENSE)
if (cmdstatp->have_sense)
scsi_print_req_sense("st", SRpnt);
} else ) /* end DEB */
if (!(driver_byte(result) & DRIVER_SENSE) ||
((sense[0] & 0x70) == 0x70 &&
scode != NO_SENSE &&
scode != RECOVERED_ERROR &&
/* scode != UNIT_ATTENTION && */
scode != BLANK_CHECK &&
scode != VOLUME_OVERFLOW &&
SRpnt->sr_cmnd[0] != MODE_SENSE &&
SRpnt->sr_cmnd[0] != TEST_UNIT_READY)) { /* Abnormal conditions for tape */
if (driver_byte(result) & DRIVER_SENSE) {
printk(KERN_WARNING "%s: Error with sense data: ", name);
scsi_print_req_sense("st", SRpnt);
} else
} ) /* end DEB */
if (!debugging) { /* Abnormal conditions for tape */
if (!cmdstatp->have_sense)
printk(KERN_WARNING
"%s: Error %x (sugg. bt 0x%x, driver bt 0x%x, host bt 0x%x).\n",
name, result, suggestion(result),
driver_byte(result) & DRIVER_MASK, host_byte(result));
driver_byte(result) & DRIVER_MASK, host_byte(result));
else if (cmdstatp->have_sense &&
scode != NO_SENSE &&
scode != RECOVERED_ERROR &&
/* scode != UNIT_ATTENTION && */
scode != BLANK_CHECK &&
scode != VOLUME_OVERFLOW &&
SRpnt->sr_cmnd[0] != MODE_SENSE &&
SRpnt->sr_cmnd[0] != TEST_UNIT_READY) {
printk(KERN_WARNING "%s: Error with sense data: ", name);
scsi_print_req_sense("st", SRpnt);
}
}
if (STp->cln_mode >= EXTENDED_SENSE_START) {
if (cmdstatp->fixed_format &&
STp->cln_mode >= EXTENDED_SENSE_START) { /* Only fixed format sense */
if (STp->cln_sense_value)
STp->cleaning_req |= ((SRpnt->sr_sense_buffer[STp->cln_mode] &
STp->cln_sense_mask) == STp->cln_sense_value);
......@@ -319,12 +352,13 @@ static int st_chk_result(struct scsi_tape *STp, struct scsi_request * SRpnt)
STp->cleaning_req |= ((SRpnt->sr_sense_buffer[STp->cln_mode] &
STp->cln_sense_mask) != 0);
}
if (sense[12] == 0 && sense[13] == 0x17) /* ASC and ASCQ => cleaning requested */
STp->cleaning_req = 1;
if (cmdstatp->have_sense &&
cmdstatp->sense_hdr.asc == 0 && cmdstatp->sense_hdr.ascq == 0x17)
STp->cleaning_req = 1; /* ASC and ASCQ => cleaning requested */
STp->pos_unknown |= STp->device->was_reset;
if ((sense[0] & 0x70) == 0x70 &&
if (cmdstatp->have_sense &&
scode == RECOVERED_ERROR
#if ST_RECOVERED_WRITE_FATAL
&& SRpnt->sr_cmnd[0] != WRITE_6
......@@ -346,7 +380,7 @@ static int st_chk_result(struct scsi_tape *STp, struct scsi_request * SRpnt)
STp->recover_count);
} ) /* end DEB */
if ((sense[2] & 0xe0) == 0)
if (cmdstatp->flags == 0)
return 0;
}
return (-EIO);
......@@ -356,28 +390,10 @@ static int st_chk_result(struct scsi_tape *STp, struct scsi_request * SRpnt)
/* Wakeup from interrupt */
static void st_sleep_done(struct scsi_cmnd * SCpnt)
{
int remainder;
struct scsi_tape *STp = container_of(SCpnt->request->rq_disk->private_data,
struct scsi_tape, driver);
if ((STp->buffer)->writing &&
(SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
(SCpnt->sense_buffer[2] & 0x40)) {
/* EOM at write-behind, has all been written? */
if ((SCpnt->sense_buffer[0] & 0x80) != 0)
remainder = (SCpnt->sense_buffer[3] << 24) |
(SCpnt->sense_buffer[4] << 16) |
(SCpnt->sense_buffer[5] << 8) |
SCpnt->sense_buffer[6];
else
remainder = 0;
if ((SCpnt->sense_buffer[2] & 0x0f) == VOLUME_OVERFLOW ||
remainder > 0)
(STp->buffer)->midlevel_result = SCpnt->result; /* Error */
else
(STp->buffer)->midlevel_result = INT_MAX; /* OK */
} else
(STp->buffer)->midlevel_result = SCpnt->result;
(STp->buffer)->cmdstat.midlevel_result = SCpnt->result;
SCpnt->request->rq_status = RQ_SCSI_DONE;
(STp->buffer)->last_SRpnt = SCpnt->sc_request;
DEB( STp->write_pending = 0; )
......@@ -421,6 +437,7 @@ st_do_scsi(struct scsi_request * SRpnt, struct scsi_tape * STp, unsigned char *c
SRpnt->sr_request->waiting = &(STp->wait);
SRpnt->sr_request->rq_status = RQ_SCSI_BUSY;
SRpnt->sr_request->rq_disk = STp->disk;
STp->buffer->cmdstat.have_sense = 0;
scsi_do_req(SRpnt, (void *) cmd, bp, bytes,
st_sleep_done, timeout, retries);
......@@ -434,13 +451,20 @@ st_do_scsi(struct scsi_request * SRpnt, struct scsi_tape * STp, unsigned char *c
}
/* Handle the write-behind checking (downs the semaphore) */
static void write_behind_check(struct scsi_tape * STp)
/* Handle the write-behind checking (waits for completion). Returns -ENOSPC if
write has been correct but EOM early warning reached, -EIO if write ended in
error or zero if write successful. Asynchronous writes are used only in
variable block mode. */
static int write_behind_check(struct scsi_tape * STp)
{
int retval = 0;
struct st_buffer *STbuffer;
struct st_partstat *STps;
struct st_cmdstatus *cmdstatp;
STbuffer = STp->buffer;
if (!STbuffer->writing)
return 0;
DEB(
if (STp->write_pending)
......@@ -463,9 +487,29 @@ static void write_behind_check(struct scsi_tape * STp)
else
STps->drv_block += STbuffer->writing / STp->block_size;
}
cmdstatp = &STbuffer->cmdstat;
if (STbuffer->syscall_result) {
retval = -EIO;
if (cmdstatp->have_sense && !cmdstatp->deferred &&
(cmdstatp->flags & SENSE_EOM) &&
(cmdstatp->sense_hdr.sense_key == NO_SENSE ||
cmdstatp->sense_hdr.sense_key == RECOVERED_ERROR)) {
/* EOM at write-behind, has all data been written? */
if (!cmdstatp->remainder_valid ||
cmdstatp->uremainder64 == 0)
retval = -ENOSPC;
}
if (retval == -EIO)
STps->drv_block = -1;
}
STbuffer->writing = 0;
return;
DEB(if (debugging && retval)
printk(ST_DEB_MSG "%s: Async write error %x, return value %d.\n",
tape_name(STp), STbuffer->cmdstat.midlevel_result, retval);) /* end DEB */
return retval;
}
......@@ -496,7 +540,7 @@ static int cross_eof(struct scsi_tape * STp, int forward)
scsi_release_request(SRpnt);
SRpnt = NULL;
if ((STp->buffer)->midlevel_result != 0)
if ((STp->buffer)->cmdstat.midlevel_result != 0)
printk(KERN_ERR "%s: Stepping over filemark %s failed.\n",
tape_name(STp), forward ? "forward" : "backward");
......@@ -513,19 +557,9 @@ static int flush_write_buffer(struct scsi_tape * STp)
struct scsi_request *SRpnt;
struct st_partstat *STps;
if ((STp->buffer)->writing) {
write_behind_check(STp);
if ((STp->buffer)->syscall_result) {
DEBC(printk(ST_DEB_MSG
"%s: Async write error (flush) %x.\n",
tape_name(STp), (STp->buffer)->midlevel_result))
if ((STp->buffer)->midlevel_result == INT_MAX)
return (-ENOSPC);
return (-EIO);
}
}
if (STp->block_size == 0)
return 0;
result = write_behind_check(STp);
if (result)
return result;
result = 0;
if (STp->dirty == 1) {
......@@ -553,18 +587,25 @@ static int flush_write_buffer(struct scsi_tape * STp)
STps = &(STp->ps[STp->partition]);
if ((STp->buffer)->syscall_result != 0) {
if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
(SRpnt->sr_sense_buffer[2] & 0x40) &&
(SRpnt->sr_sense_buffer[2] & 0x0f) == NO_SENSE) {
struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat;
if (cmdstatp->have_sense && !cmdstatp->deferred &&
(cmdstatp->flags & SENSE_EOM) &&
(cmdstatp->sense_hdr.sense_key == NO_SENSE ||
cmdstatp->sense_hdr.sense_key == RECOVERED_ERROR) &&
(!cmdstatp->remainder_valid ||
cmdstatp->uremainder64 == 0)) { /* All written at EOM early warning */
STp->dirty = 0;
(STp->buffer)->buffer_bytes = 0;
if (STps->drv_block >= 0)
STps->drv_block += blks;
result = (-ENOSPC);
} else {
printk(KERN_ERR "%s: Error on flush.\n",
tape_name(STp));
STps->drv_block = (-1);
result = (-EIO);
}
STps->drv_block = (-1);
} else {
if (STps->drv_block >= 0)
STps->drv_block += blks;
......@@ -728,6 +769,7 @@ static int test_ready(struct scsi_tape *STp, int do_wait)
int retval = CHKRES_READY, new_session = 0;
unsigned char cmd[MAX_COMMAND_SIZE];
struct scsi_request *SRpnt = NULL;
struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat;
max_wait = do_wait ? ST_BLOCK_SECONDS : 0;
......@@ -742,9 +784,9 @@ static int test_ready(struct scsi_tape *STp, int do_wait)
break;
}
if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70) {
if (cmdstatp->have_sense) {
scode = (SRpnt->sr_sense_buffer[2] & 0x0f);
scode = cmdstatp->sense_hdr.sense_key;
if (scode == UNIT_ATTENTION) { /* New media? */
new_session = 1;
......@@ -760,9 +802,7 @@ static int test_ready(struct scsi_tape *STp, int do_wait)
if (scode == NOT_READY) {
if (waits < max_wait) {
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(HZ);
if (signal_pending(current)) {
if (msleep_interruptible(1000)) {
retval = (-EINTR);
break;
}
......@@ -771,7 +811,7 @@ static int test_ready(struct scsi_tape *STp, int do_wait)
}
else {
if ((STp->device)->scsi_level >= SCSI_2 &&
SRpnt->sr_sense_buffer[12] == 0x3a) /* Check ASC */
cmdstatp->sense_hdr.asc == 0x3a) /* Check ASC */
retval = CHKRES_NO_TAPE;
else
retval = CHKRES_NOT_READY;
......@@ -877,7 +917,7 @@ static int check_tape(struct scsi_tape *STp, struct file *filp)
goto err_out;
}
if (!SRpnt->sr_result && !SRpnt->sr_sense_buffer[0]) {
if (!SRpnt->sr_result && !STp->buffer->cmdstat.have_sense) {
STp->max_block = ((STp->buffer)->b_data[1] << 16) |
((STp->buffer)->b_data[2] << 8) | (STp->buffer)->b_data[3];
STp->min_block = ((STp->buffer)->b_data[4] << 8) |
......@@ -1108,6 +1148,7 @@ static int st_flush(struct file *filp)
name, STp->nbr_requests, STp->nbr_dio, STp->nbr_pages, STp->nbr_combinable));
if (STps->rw == ST_WRITING && !STp->pos_unknown) {
struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat;
DEBC(printk(ST_DEB_MSG "%s: File length %lld bytes.\n",
name, (long long)filp->f_pos);
......@@ -1126,20 +1167,13 @@ static int st_flush(struct file *filp)
goto out;
}
if ((STp->buffer)->syscall_result != 0 &&
((SRpnt->sr_sense_buffer[0] & 0x70) != 0x70 ||
(SRpnt->sr_sense_buffer[2] & 0x4f) != 0x40 ||
((SRpnt->sr_sense_buffer[0] & 0x80) != 0 &&
(SRpnt->sr_sense_buffer[3] | SRpnt->sr_sense_buffer[4] |
SRpnt->sr_sense_buffer[5] |
SRpnt->sr_sense_buffer[6]) != 0))) {
/* Filter out successful write at EOM */
scsi_release_request(SRpnt);
SRpnt = NULL;
printk(KERN_ERR "%s: Error on write filemark.\n", name);
if (result == 0)
result = (-EIO);
} else {
if (STp->buffer->syscall_result == 0 ||
(cmdstatp->have_sense && !cmdstatp->deferred &&
(cmdstatp->flags & SENSE_EOM) &&
(cmdstatp->sense_hdr.sense_key == NO_SENSE ||
cmdstatp->sense_hdr.sense_key == RECOVERED_ERROR) &&
(!cmdstatp->remainder_valid || cmdstatp->uremainder64 == 0))) {
/* Write successful at EOM */
scsi_release_request(SRpnt);
SRpnt = NULL;
if (STps->drv_file >= 0)
......@@ -1149,6 +1183,13 @@ static int st_flush(struct file *filp)
cross_eof(STp, 0);
STps->eof = ST_FM;
}
else { /* Write error */
scsi_release_request(SRpnt);
SRpnt = NULL;
printk(KERN_ERR "%s: Error on write filemark.\n", name);
if (result == 0)
result = (-EIO);
}
DEBC(printk(ST_DEB_MSG "%s: Buffer flushed, %d EOF(s) written\n",
name, cmd[4]));
......@@ -1410,16 +1451,12 @@ st_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
}
STbp = STp->buffer;
if (STbp->writing) {
write_behind_check(STp);
if (STbp->syscall_result) {
DEBC(printk(ST_DEB_MSG "%s: Async write error (write) %x.\n",
name, STbp->midlevel_result));
if (STbp->midlevel_result == INT_MAX)
STps->eof = ST_EOM_OK;
else
STps->eof = ST_EOM_ERROR;
}
i = write_behind_check(STp);
if (i) {
if (i == -ENOSPC)
STps->eof = ST_EOM_OK;
else
STps->eof = ST_EOM_ERROR;
}
if (STps->eof == ST_EOM_OK) {
......@@ -1523,15 +1560,13 @@ st_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
}
if (STbp->syscall_result != 0) {
struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat;
DEBC(printk(ST_DEB_MSG "%s: Error on write:\n", name));
if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
(SRpnt->sr_sense_buffer[2] & 0x40)) {
scode = SRpnt->sr_sense_buffer[2] & 0x0f;
if ((SRpnt->sr_sense_buffer[0] & 0x80) != 0)
undone = (SRpnt->sr_sense_buffer[3] << 24) |
(SRpnt->sr_sense_buffer[4] << 16) |
(SRpnt->sr_sense_buffer[5] << 8) |
SRpnt->sr_sense_buffer[6];
if (cmdstatp->have_sense && (cmdstatp->flags & SENSE_EOM)) {
scode = cmdstatp->sense_hdr.sense_key;
if (cmdstatp->remainder_valid)
undone = (int)cmdstatp->uremainder64;
else if (STp->block_size == 0 &&
scode == VOLUME_OVERFLOW)
undone = transfer;
......@@ -1556,11 +1591,11 @@ st_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
retval = (-ENOSPC); /* EOM within current request */
DEBC(printk(ST_DEB_MSG
"%s: EOM with %d bytes unwritten.\n",
name, count));
name, (int)count));
} else {
/* EOT within data buffered earlier (possible only
in fixed block mode without direct i/o) */
if (!retry_eot && (SRpnt->sr_sense_buffer[0] & 1) == 0 &&
if (!retry_eot && !cmdstatp->deferred &&
(scode == NO_SENSE || scode == RECOVERED_ERROR)) {
move_buffer_data(STp->buffer, transfer - undone);
retry_eot = 1;
......@@ -1690,6 +1725,8 @@ static long read_tape(struct scsi_tape *STp, long count,
/* Something to check */
if (STbp->syscall_result) {
struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat;
retval = 1;
DEBC(printk(ST_DEB_MSG "%s: Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n",
name,
......@@ -1697,25 +1734,22 @@ static long read_tape(struct scsi_tape *STp, long count,
SRpnt->sr_sense_buffer[2], SRpnt->sr_sense_buffer[3],
SRpnt->sr_sense_buffer[4], SRpnt->sr_sense_buffer[5],
SRpnt->sr_sense_buffer[6], SRpnt->sr_sense_buffer[7]));
if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70) { /* extended sense */
if (cmdstatp->have_sense) {
if ((SRpnt->sr_sense_buffer[2] & 0x0f) == BLANK_CHECK)
SRpnt->sr_sense_buffer[2] &= 0xcf; /* No need for EOM in this case */
if (cmdstatp->sense_hdr.sense_key == BLANK_CHECK)
cmdstatp->flags &= 0xcf; /* No need for EOM in this case */
if ((SRpnt->sr_sense_buffer[2] & 0xe0) != 0) { /* EOF, EOM, or ILI */
if (cmdstatp->flags != 0) { /* EOF, EOM, or ILI */
/* Compute the residual count */
if ((SRpnt->sr_sense_buffer[0] & 0x80) != 0)
transfer = (SRpnt->sr_sense_buffer[3] << 24) |
(SRpnt->sr_sense_buffer[4] << 16) |
(SRpnt->sr_sense_buffer[5] << 8) |
SRpnt->sr_sense_buffer[6];
if (cmdstatp->remainder_valid)
transfer = (int)cmdstatp->uremainder64;
else
transfer = 0;
if (STp->block_size == 0 &&
(SRpnt->sr_sense_buffer[2] & 0x0f) == MEDIUM_ERROR)
cmdstatp->sense_hdr.sense_key == MEDIUM_ERROR)
transfer = bytes;
if (SRpnt->sr_sense_buffer[2] & 0x20) { /* ILI */
if (cmdstatp->flags & SENSE_ILI) { /* ILI */
if (STp->block_size == 0) {
if (transfer <= 0) {
if (transfer < 0)
......@@ -1749,7 +1783,7 @@ static long read_tape(struct scsi_tape *STp, long count,
if (st_int_ioctl(STp, MTBSR, 1))
return (-EIO);
}
} else if (SRpnt->sr_sense_buffer[2] & 0x80) { /* FM overrides EOM */
} else if (cmdstatp->flags & SENSE_FMK) { /* FM overrides EOM */
if (STps->eof != ST_FM_HIT)
STps->eof = ST_FM_HIT;
else
......@@ -1762,7 +1796,7 @@ static long read_tape(struct scsi_tape *STp, long count,
DEBC(printk(ST_DEB_MSG
"%s: EOF detected (%d bytes read).\n",
name, STbp->buffer_bytes));
} else if (SRpnt->sr_sense_buffer[2] & 0x40) {
} else if (cmdstatp->flags & SENSE_EOM) {
if (STps->eof == ST_FM)
STps->eof = ST_EOD_1;
else
......@@ -1783,7 +1817,7 @@ static long read_tape(struct scsi_tape *STp, long count,
"%s: Tape error while reading.\n", name));
STps->drv_block = (-1);
if (STps->eof == ST_FM &&
(SRpnt->sr_sense_buffer[2] & 0x0f) == BLANK_CHECK) {
cmdstatp->sense_hdr.sense_key == BLANK_CHECK) {
DEBC(printk(ST_DEB_MSG
"%s: Zero returned for first BLANK CHECK after EOF.\n",
name));
......@@ -1907,7 +1941,7 @@ st_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos)
printk(ST_DEB_MSG
"%s: EOF up (%d). Left %d, needed %d.\n", name,
STps->eof, STbp->buffer_bytes,
count - total);
(int)(count - total));
) /* end DEB */
transfer = STbp->buffer_bytes < count - total ?
STbp->buffer_bytes : count - total;
......@@ -2695,23 +2729,26 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon
} else { /* SCSI command was not completely successful. Don't return
from this block without releasing the SCSI command block! */
struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat;
if (SRpnt->sr_sense_buffer[2] & 0x40) {
if (cmdstatp->flags & SENSE_EOM) {
if (cmd_in != MTBSF && cmd_in != MTBSFM &&
cmd_in != MTBSR && cmd_in != MTBSS)
STps->eof = ST_EOM_OK;
STps->drv_block = 0;
}
undone = ((SRpnt->sr_sense_buffer[3] << 24) +
(SRpnt->sr_sense_buffer[4] << 16) +
(SRpnt->sr_sense_buffer[5] << 8) +
SRpnt->sr_sense_buffer[6]);
if (cmdstatp->remainder_valid)
undone = (int)cmdstatp->uremainder64;
else
undone = 0;
if (cmd_in == MTWEOF &&
(SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
(SRpnt->sr_sense_buffer[2] & 0x4f) == 0x40 &&
((SRpnt->sr_sense_buffer[0] & 0x80) == 0 || undone == 0)) {
cmdstatp->have_sense &&
(cmdstatp->flags & SENSE_EOM) &&
(cmdstatp->sense_hdr.sense_key == NO_SENSE ||
cmdstatp->sense_hdr.sense_key == RECOVERED_ERROR) &&
undone == 0) {
ioctl_result = 0; /* EOF written succesfully at EOM */
if (fileno >= 0)
fileno++;
......@@ -2732,7 +2769,7 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon
STps->drv_block = 0;
STps->eof = ST_NOEOF;
} else if (cmd_in == MTFSR) {
if (SRpnt->sr_sense_buffer[2] & 0x80) { /* Hit filemark */
if (cmdstatp->flags & SENSE_FMK) { /* Hit filemark */
if (STps->drv_file >= 0)
STps->drv_file++;
STps->drv_block = 0;
......@@ -2745,7 +2782,7 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon
STps->eof = ST_NOEOF;
}
} else if (cmd_in == MTBSR) {
if (SRpnt->sr_sense_buffer[2] & 0x80) { /* Hit filemark */
if (cmdstatp->flags & SENSE_FMK) { /* Hit filemark */
STps->drv_file--;
STps->drv_block = (-1);
} else {
......@@ -2763,7 +2800,7 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon
cmd_in == MTSETDENSITY ||
cmd_in == MTSETDRVBUFFER ||
cmd_in == SET_DENS_AND_BLK) {
if ((SRpnt->sr_sense_buffer[2] & 0x0f) == ILLEGAL_REQUEST &&
if (cmdstatp->sense_hdr.sense_key == ILLEGAL_REQUEST &&
!(STp->use_pf & PF_TESTED)) {
/* Try the other possible state of Page Format if not
already tried */
......@@ -2775,7 +2812,7 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon
} else if (chg_eof)
STps->eof = ST_NOEOF;
if ((SRpnt->sr_sense_buffer[2] & 0x0f) == BLANK_CHECK)
if (cmdstatp->sense_hdr.sense_key == BLANK_CHECK)
STps->eof = ST_EOD;
scsi_release_request(SRpnt);
......
......@@ -5,6 +5,18 @@
#include <linux/completion.h>
/* Descriptor for analyzed sense data */
struct st_cmdstatus {
int midlevel_result;
struct scsi_sense_hdr sense_hdr;
int have_sense;
u64 uremainder64;
u8 flags;
u8 remainder_valid;
u8 fixed_format;
u8 deferred;
};
/* The tape buffer descriptor. */
struct st_buffer {
unsigned char in_use;
......@@ -15,9 +27,9 @@ struct st_buffer {
int buffer_bytes;
int read_pointer;
int writing;
int midlevel_result;
int syscall_result;
struct scsi_request *last_SRpnt;
struct st_cmdstatus cmdstat;
unsigned char *b_data;
unsigned short use_sg; /* zero or max number of s/g segments for this adapter */
unsigned short sg_segs; /* number of segments in s/g list */
......@@ -192,4 +204,9 @@ struct scsi_tape {
#define EXTENDED_SENSE_START 18
/* Masks for some conditions in the sense data */
#define SENSE_FMK 0x80
#define SENSE_EOM 0x40
#define SENSE_ILI 0x20
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment