Commit 95272556 authored by Douglas Gilbert's avatar Douglas Gilbert Committed by James Bottomley

SG_IO ioctl in block layer

The attachment modifies the SG_IO ioctl that is in
the block layer to:
   - convey the SCSI status value back via the sg_io_hdr
     structure
   - in the event of CHECK CONDITION, convey the sense
     buffer back via the sg_io_hdr structure
   - set "output" fields in sg_io_hdr structure to sane
     values
   - modify the errno behaviour to be more like the
     SCSI generic driver's SG_IO ioctl

This patch was presented around lk 2.5.51 but fell between
the cracks. The only modification is to take account of
the changes to scsi/scsi_lib.c since then.
parent 03a85f8e
...@@ -40,6 +40,11 @@ const unsigned char scsi_command_size[8] = ...@@ -40,6 +40,11 @@ const unsigned char scsi_command_size[8] =
#define BLK_DEFAULT_TIMEOUT (60 * HZ) #define BLK_DEFAULT_TIMEOUT (60 * HZ)
/* defined in ../scsi/scsi.h ... should it be included? */
#ifndef SCSI_SENSE_BUFFERSIZE
#define SCSI_SENSE_BUFFERSIZE 64
#endif
int blk_do_rq(request_queue_t *q, struct block_device *bdev, struct request *rq) int blk_do_rq(request_queue_t *q, struct block_device *bdev, struct request *rq)
{ {
DECLARE_COMPLETION(wait); DECLARE_COMPLETION(wait);
...@@ -126,11 +131,11 @@ static int sg_io(request_queue_t *q, struct block_device *bdev, ...@@ -126,11 +131,11 @@ static int sg_io(request_queue_t *q, struct block_device *bdev,
struct sg_io_hdr *uptr) struct sg_io_hdr *uptr)
{ {
unsigned long uaddr, start_time; unsigned long uaddr, start_time;
int err, reading, writing, nr_sectors; int reading, writing, nr_sectors;
struct sg_io_hdr hdr; struct sg_io_hdr hdr;
struct request *rq; struct request *rq;
struct bio *bio; struct bio *bio;
char sense[24]; char sense[SCSI_SENSE_BUFFERSIZE];
void *buffer; void *buffer;
if (!access_ok(VERIFY_WRITE, uptr, sizeof(*uptr))) if (!access_ok(VERIFY_WRITE, uptr, sizeof(*uptr)))
...@@ -265,26 +270,36 @@ static int sg_io(request_queue_t *q, struct block_device *bdev, ...@@ -265,26 +270,36 @@ static int sg_io(request_queue_t *q, struct block_device *bdev,
start_time = jiffies; start_time = jiffies;
/* /* ignore return value. All information is passed back to caller
* return -EIO if we didn't transfer all data, caller can look at * (if he doesn't check that is his problem).
* residual count to find out how much did succeed * N.B. a non-zero SCSI status is _not_ necessarily an error.
*/ */
err = blk_do_rq(q, bdev, rq); blk_do_rq(q, bdev, rq);
if (rq->data_len > 0)
err = -EIO;
if (bio) { if (bio) {
bio_unmap_user(bio, reading); bio_unmap_user(bio, reading);
bio_put(bio); bio_put(bio);
} }
/* write to all output members */
hdr.status = rq->errors; hdr.status = rq->errors;
hdr.masked_status = (hdr.status >> 1) & 0x1f;
hdr.msg_status = 0;
hdr.host_status = 0;
hdr.driver_status = 0;
hdr.info = 0;
if (hdr.masked_status || hdr.host_status || hdr.driver_status)
hdr.info |= SG_INFO_CHECK;
hdr.resid = rq->data_len; hdr.resid = rq->data_len;
hdr.duration = (jiffies - start_time) * (1000 / HZ); hdr.duration = (jiffies - start_time) * (1000 / HZ);
hdr.sb_len_wr = 0;
if (rq->sense_len && hdr.sbp) { if (rq->sense_len && hdr.sbp) {
if (!copy_to_user(hdr.sbp,rq->sense, rq->sense_len)) int len = (hdr.mx_sb_len < rq->sense_len) ?
hdr.sb_len_wr = rq->sense_len; hdr.mx_sb_len : rq->sense_len;
if (!copy_to_user(hdr.sbp, rq->sense, len))
hdr.sb_len_wr = len;
} }
blk_put_request(rq); blk_put_request(rq);
...@@ -297,8 +312,9 @@ static int sg_io(request_queue_t *q, struct block_device *bdev, ...@@ -297,8 +312,9 @@ static int sg_io(request_queue_t *q, struct block_device *bdev,
kfree(buffer); kfree(buffer);
} }
/* may not have succeeded, but output values written to control
return err; * structure (struct sg_io_hdr). */
return 0;
} }
#define FORMAT_UNIT_TIMEOUT (2 * 60 * 60 * HZ) #define FORMAT_UNIT_TIMEOUT (2 * 60 * 60 * HZ)
......
...@@ -495,6 +495,7 @@ void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors, ...@@ -495,6 +495,7 @@ void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors,
int this_count = SCpnt->bufflen >> 9; int this_count = SCpnt->bufflen >> 9;
request_queue_t *q = SCpnt->device->request_queue; request_queue_t *q = SCpnt->device->request_queue;
struct request *req = SCpnt->request; struct request *req = SCpnt->request;
int clear_errors = 1;
/* /*
* We must do one of several things here: * We must do one of several things here:
...@@ -528,10 +529,22 @@ void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors, ...@@ -528,10 +529,22 @@ void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors,
kfree(SCpnt->buffer); kfree(SCpnt->buffer);
} }
if (blk_pc_request(req)) { if (blk_pc_request(req)) { /* SG_IO ioctl from block level */
req->errors = result & 0xff; req->errors = (driver_byte(result) & DRIVER_SENSE) ?
(CHECK_CONDITION << 1) : (result & 0xff);
if (!result) if (!result)
req->data_len -= SCpnt->bufflen; req->data_len -= SCpnt->bufflen;
else {
clear_errors = 0;
if (SCpnt->sense_buffer[0] & 0x70) {
int len = 8 + SCpnt->sense_buffer[7];
if (len > SCSI_SENSE_BUFFERSIZE)
len = SCSI_SENSE_BUFFERSIZE;
memcpy(req->sense, SCpnt->sense_buffer, len);
req->sense_len = len;
}
}
} }
/* /*
...@@ -552,6 +565,7 @@ void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors, ...@@ -552,6 +565,7 @@ void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors,
req->nr_sectors, good_sectors)); req->nr_sectors, good_sectors));
SCSI_LOG_HLCOMPLETE(1, printk("use_sg is %d\n ", SCpnt->use_sg)); SCSI_LOG_HLCOMPLETE(1, printk("use_sg is %d\n ", SCpnt->use_sg));
if (clear_errors)
req->errors = 0; req->errors = 0;
/* /*
* If multiple sectors are requested in one buffer, then * If multiple sectors are requested in one buffer, then
......
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