Make the sense data available in the bio end_io path on request.
Signed-off-by: Lars Marowsky-Bree <lmb@suse.de>
Signed-off-by: Jens Axboe <axboe@suse.de>
--- diff/drivers/block/ll_rw_blk.c 2005-04-21 18:25:42.000000000 +0100
+++ source/drivers/block/ll_rw_blk.c 2005-04-21 18:25:39.000000000 +0100
@@ -3040,7 +3040,9 @@
int nr_bytes)
{
int total_bytes, bio_nbytes, error, next_idx = 0;
+ unsigned char *s = NULL;
struct bio *bio;
+ unsigned sense_key, asc, ascq;
/*
* extend uptodate bool to allow < 0 value to be direct io error
@@ -3049,6 +3051,21 @@
if (end_io_error(uptodate))
error = !uptodate ? -EIO : uptodate;
+ if (req->sense && req->sense_len) {
+ s = req->sense;
+ if ((s[0] & 0x7f) == 0x70) { /* current sense in fixed format */
+ sense_key = s[2] & 0x0f;
+ asc = s[12];
+ ascq = s[13];
+ } else if ((s[0] & 0x7f) == 0x72) { /* current sense in descriptor format */
+ sense_key = s[1] & 0x0f;
+ asc = s[2];
+ ascq = s[3];
+ } else {
+ s = NULL;
+ }
+ }
+
/*
* for a REQ_BLOCK_PC request, we want to carry any eventual
* sense key with us all the way through
@@ -3067,6 +3084,11 @@
while ((bio = req->bio) != NULL) {
int nbytes;
+ if (s)
+ bio_set_sense(bio, sense_key, asc, ascq);
+ else if (error < 0)
+ bio_set_errno(bio, -error);
+
if (nr_bytes >= bio->bi_size) {
req->bio = bio->bi_next;
nbytes = bio->bi_size;
--- diff/drivers/scsi/scsi_lib.c 2005-04-21 18:25:42.000000000 +0100
+++ source/drivers/scsi/scsi_lib.c 2005-04-21 18:25:39.000000000 +0100
@@ -535,9 +535,21 @@
{
request_queue_t *q = cmd->device->request_queue;
struct request *req = cmd->request;
+ int sense_override = 0;
unsigned long flags;
/*
+ * if room for sense wasn't supplied for this request, override with
+ * what we have stored for the duration of the end_io handling. this
+ * allows passing of sense to the block layer.
+ */
+ if (!req->sense && (cmd->sense_buffer[0] & 0x70)) {
+ req->sense = cmd->sense_buffer;
+ req->sense_len = 8 + cmd->sense_buffer[7];
+ sense_override = 1;
+ }
+
+ /*
* If there are blocks left over at the end, set up the command
* to queue the remainder of them.
*/
@@ -563,6 +575,9 @@
}
}
+ if (sense_override)
+ req->sense = NULL;
+
add_disk_randomness(req->rq_disk);
spin_lock_irqsave(q->queue_lock, flags);
--- diff/fs/bio.c 2005-04-04 17:38:35.000000000 +0100
+++ source/fs/bio.c 2005-04-21 18:25:39.000000000 +0100
@@ -123,6 +123,7 @@
bio->bi_next = NULL;
bio->bi_flags = 1 << BIO_UPTODATE;
bio->bi_rw = 0;
+ bio->bi_error = 0;
bio->bi_vcnt = 0;
bio->bi_idx = 0;
bio->bi_phys_segments = 0;
--- diff/include/linux/bio.h 2005-04-04 17:39:06.000000000 +0100
+++ source/include/linux/bio.h 2005-04-21 18:25:39.000000000 +0100
@@ -76,6 +76,7 @@
unsigned long bi_rw; /* bottom bits READ/WRITE,
* top bits priority
*/
+ unsigned int bi_error; /* -Exx or sense */
unsigned short bi_vcnt; /* how many bio_vec's */
unsigned short bi_idx; /* current index into bvl_vec */
@@ -238,6 +239,28 @@
*/
#define bio_get(bio) atomic_inc(&(bio)->bi_cnt)
+enum {
+ BIO_ERROR_ERRNO = 1,
+ BIO_ERROR_SENSE,
+};
+
+/*
+ * Extended error reporting. The upper 8 bits are flag values, the bottom
+ * 24 can be used for extended errors (such as sense).
+ */
+static inline void bio_set_sense(struct bio *bio, char key, char asc, char ascq)
+{
+ bio->bi_error = (BIO_ERROR_SENSE << 24) | (key << 16) | (asc << 8) | ascq;
+}
+
+static inline void bio_set_errno(struct bio *bio, int error)
+{
+ bio->bi_error = (BIO_ERROR_ERRNO << 24) | error;
+}
+
+#define bio_errno_valid(bio) ((bio)->bi_error & (BIO_ERROR_ERRNO << 24))
+#define bio_sense_valid(bio) ((bio)->bi_error & (BIO_ERROR_SENSE << 24))
+#define bio_sense_value(bio) ((bio)->bi_error & 0xffffff)
/*
* A bio_pair is used when we need to split a bio.