From: Lars Marowsky-Bree Make the sense data available in the bio end_io path on request. Signed-off-by: Lars Marowsky-Bree Signed-off-by: Jens Axboe --- block/ll_rw_blk.c | 22 ++++++++++++++++++++++ drivers/scsi/scsi_lib.c | 15 +++++++++++++++ fs/bio.c | 1 + include/linux/bio.h | 23 +++++++++++++++++++++++ 4 files changed, 61 insertions(+) Index: linux-2.6.22-rc1/block/ll_rw_blk.c =================================================================== --- linux-2.6.22-rc1.orig/block/ll_rw_blk.c 2007-05-13 02:45:56.000000000 +0100 +++ linux-2.6.22-rc1/block/ll_rw_blk.c 2007-05-14 18:13:39.000000000 +0100 @@ -3381,7 +3381,9 @@ static int __end_that_request_first(stru int nr_bytes) { int total_bytes, bio_nbytes, error, next_idx = 0; + unsigned char *s = NULL; struct bio *bio; + unsigned sense_key, asc, ascq; blk_add_trace_rq(req->q, req, BLK_TA_COMPLETE); @@ -3392,6 +3394,21 @@ static int __end_that_request_first(stru 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 @@ -3416,6 +3433,11 @@ static int __end_that_request_first(stru 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; Index: linux-2.6.22-rc1/drivers/scsi/scsi_lib.c =================================================================== --- linux-2.6.22-rc1.orig/drivers/scsi/scsi_lib.c 2007-05-13 02:45:56.000000000 +0100 +++ linux-2.6.22-rc1/drivers/scsi/scsi_lib.c 2007-05-14 18:13:39.000000000 +0100 @@ -656,9 +656,21 @@ static struct scsi_cmnd *scsi_end_reques { 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. */ @@ -685,6 +697,9 @@ static struct scsi_cmnd *scsi_end_reques } } + if (sense_override) + req->sense = NULL; + add_disk_randomness(req->rq_disk); spin_lock_irqsave(q->queue_lock, flags); Index: linux-2.6.22-rc1/fs/bio.c =================================================================== --- linux-2.6.22-rc1.orig/fs/bio.c 2007-05-14 18:13:21.000000000 +0100 +++ linux-2.6.22-rc1/fs/bio.c 2007-05-14 18:13:39.000000000 +0100 @@ -131,6 +131,7 @@ void bio_init(struct bio *bio) bio->bi_bdev = 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; Index: linux-2.6.22-rc1/include/linux/bio.h =================================================================== --- linux-2.6.22-rc1.orig/include/linux/bio.h 2007-05-13 02:45:56.000000000 +0100 +++ linux-2.6.22-rc1/include/linux/bio.h 2007-05-14 18:13:39.000000000 +0100 @@ -78,6 +78,7 @@ struct bio { 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 */ @@ -254,6 +255,28 @@ struct bio { */ #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.