From 89f97ad1894ab518b05b798906085fb3d1b2d00f Mon Sep 17 00:00:00 2001 From: Mike Miller Date: Mon, 18 Dec 2006 10:59:39 +0100 Subject: [PATCH] cciss: set default raid level when reading geometry fails This patch sets a default raid level on a volume that either does not support reading the geometry or reports an invalid geometry for whatever reason. We were always setting some values for heads and sectors but never set a raid level. This caused lots of problems on some buggy firmware. Please consider this for inclusion. Thanks, mikem Signed-off-by: Mike Miller Signed-off-by: Jens Axboe --- drivers/block/cciss.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index d719a5d8f43..67a6d4a9343 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -1907,6 +1907,7 @@ static void cciss_geometry_inquiry(int ctlr, int logvol, "does not support reading geometry\n"); drv->heads = 255; drv->sectors = 32; // Sectors per track + drv->raid_level = RAID_UNKNOWN; } else { drv->heads = inq_buff->data_byte[6]; drv->sectors = inq_buff->data_byte[7]; -- cgit v1.2.3-70-g09d2 From a52de245ef0b6217a56fb2472ff65c3a196cafd5 Mon Sep 17 00:00:00 2001 From: Mike Miller Date: Mon, 18 Dec 2006 11:00:14 +0100 Subject: [PATCH] cciss: fix XFER_READ/XFER_WRITE in do_cciss_request This patch fixes a stupid bug. Sometime during the 2tb enhancement I ended up replacing the macros XFER_READ and XFER_WRITE with h->cciss_read and h->cciss_write respectively. It seemed to work somehow at least on x86_64 and ia64. I don't know how. But people started complaining about command timeouts on older controllers like the 64xx series and only on ia32. This resolves the issue reproduced in our lab. Please consider this for inclusion. Thanks, mikem Signed-off-by: Mike Miller Signed-off-by: Jens Axboe --- drivers/block/cciss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 67a6d4a9343..9d2ddb20934 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -2492,7 +2492,7 @@ static void do_cciss_request(request_queue_t *q) c->Request.Type.Type = TYPE_CMD; // It is a command. c->Request.Type.Attribute = ATTR_SIMPLE; c->Request.Type.Direction = - (rq_data_dir(creq) == READ) ? h->cciss_read : h->cciss_write; + (rq_data_dir(creq) == READ) ? XFER_READ : XFER_WRITE; c->Request.Timeout = 0; // Don't time out c->Request.CDB[0] = (rq_data_dir(creq) == READ) ? h->cciss_read : h->cciss_write; -- cgit v1.2.3-70-g09d2 From 2985259b0e3928d4cd0723ac5aad0d1190ab7717 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Tue, 19 Dec 2006 08:27:31 +0100 Subject: [PATCH] ->nr_sectors and ->hard_nr_sectors are not used for BLOCK_PC requests It's a file system thing, for block requests the only size used in the io paths is ->data_len as it is in bytes, not sectors. Signed-off-by: Jens Axboe --- block/ll_rw_blk.c | 6 ++---- drivers/scsi/scsi_lib.c | 2 -- 2 files changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index 79807dbc306..71a78a7e42f 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -2350,12 +2350,12 @@ static int __blk_rq_map_user(request_queue_t *q, struct request *rq, else bio = bio_copy_user(q, uaddr, len, reading); - if (IS_ERR(bio)) { + if (IS_ERR(bio)) return PTR_ERR(bio); - } orig_bio = bio; blk_queue_bounce(q, &bio); + /* * We link the bounce buffer in and could have to traverse it * later so we have to get a ref to prevent it from being freed @@ -2379,8 +2379,6 @@ static int __blk_rq_map_user(request_queue_t *q, struct request *rq, rq->biotail->bi_next = bio; rq->biotail = bio; - rq->nr_sectors += bio_sectors(bio); - rq->hard_nr_sectors = rq->nr_sectors; rq->data_len += bio->bi_size; } spin_unlock_irq(q->queue_lock); diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 1748e27501c..41a2ea32a30 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -270,8 +270,6 @@ static int scsi_merge_bio(struct request *rq, struct bio *bio) else { rq->biotail->bi_next = bio; rq->biotail = bio; - rq->hard_nr_sectors += bio_sectors(bio); - rq->nr_sectors = rq->hard_nr_sectors; } return 0; -- cgit v1.2.3-70-g09d2 From 1aa4f24fe96938cabe7a1e9da8bc3bfbd1dfe3fa Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Tue, 19 Dec 2006 08:33:11 +0100 Subject: [PATCH] Remove queue merging hooks We have full flexibility of merging parameters now, so we can remove the hooks that define back/front/request merge strategies. Nobody is using them anymore. Signed-off-by: Jens Axboe --- block/ll_rw_blk.c | 15 ++++++--------- drivers/scsi/scsi_lib.c | 2 +- include/linux/blkdev.h | 12 +++++------- 3 files changed, 12 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index 71a78a7e42f..433797934bd 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -1405,8 +1405,7 @@ static inline int ll_new_hw_segment(request_queue_t *q, return 1; } -static int ll_back_merge_fn(request_queue_t *q, struct request *req, - struct bio *bio) +int ll_back_merge_fn(request_queue_t *q, struct request *req, struct bio *bio) { unsigned short max_sectors; int len; @@ -1442,6 +1441,7 @@ static int ll_back_merge_fn(request_queue_t *q, struct request *req, return ll_new_hw_segment(q, req, bio); } +EXPORT_SYMBOL(ll_back_merge_fn); static int ll_front_merge_fn(request_queue_t *q, struct request *req, struct bio *bio) @@ -1912,9 +1912,6 @@ blk_init_queue_node(request_fn_proc *rfn, spinlock_t *lock, int node_id) } q->request_fn = rfn; - q->back_merge_fn = ll_back_merge_fn; - q->front_merge_fn = ll_front_merge_fn; - q->merge_requests_fn = ll_merge_requests_fn; q->prep_rq_fn = NULL; q->unplug_fn = generic_unplug_device; q->queue_flags = (1 << QUEUE_FLAG_CLUSTER); @@ -2371,7 +2368,7 @@ static int __blk_rq_map_user(request_queue_t *q, struct request *rq, spin_lock_irq(q->queue_lock); if (!rq->bio) blk_rq_bio_prep(q, rq, bio); - else if (!q->back_merge_fn(q, rq, bio)) { + else if (!ll_back_merge_fn(q, rq, bio)) { ret = -EINVAL; spin_unlock_irq(q->queue_lock); goto unmap_bio; @@ -2820,7 +2817,7 @@ static int attempt_merge(request_queue_t *q, struct request *req, * will have updated segment counts, update sector * counts here. */ - if (!q->merge_requests_fn(q, req, next)) + if (!ll_merge_requests_fn(q, req, next)) return 0; /* @@ -2937,7 +2934,7 @@ static int __make_request(request_queue_t *q, struct bio *bio) case ELEVATOR_BACK_MERGE: BUG_ON(!rq_mergeable(req)); - if (!q->back_merge_fn(q, req, bio)) + if (!ll_back_merge_fn(q, req, bio)) break; blk_add_trace_bio(q, bio, BLK_TA_BACKMERGE); @@ -2954,7 +2951,7 @@ static int __make_request(request_queue_t *q, struct bio *bio) case ELEVATOR_FRONT_MERGE: BUG_ON(!rq_mergeable(req)); - if (!q->front_merge_fn(q, req, bio)) + if (!ll_front_merge_fn(q, req, bio)) break; blk_add_trace_bio(q, bio, BLK_TA_FRONTMERGE); diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 41a2ea32a30..f02f48a882a 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -265,7 +265,7 @@ static int scsi_merge_bio(struct request *rq, struct bio *bio) if (!rq->bio) blk_rq_bio_prep(q, rq, bio); - else if (!q->back_merge_fn(q, rq, bio)) + else if (!ll_back_merge_fn(q, rq, bio)) return -EINVAL; else { rq->biotail->bi_next = bio; diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index ea330d7b46c..0fa33017ec0 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -331,10 +331,6 @@ struct request_pm_state #include -typedef int (merge_request_fn) (request_queue_t *, struct request *, - struct bio *); -typedef int (merge_requests_fn) (request_queue_t *, struct request *, - struct request *); typedef void (request_fn_proc) (request_queue_t *q); typedef int (make_request_fn) (request_queue_t *q, struct bio *bio); typedef int (prep_rq_fn) (request_queue_t *, struct request *); @@ -376,9 +372,6 @@ struct request_queue struct request_list rq; request_fn_proc *request_fn; - merge_request_fn *back_merge_fn; - merge_request_fn *front_merge_fn; - merge_requests_fn *merge_requests_fn; make_request_fn *make_request_fn; prep_rq_fn *prep_rq_fn; unplug_fn *unplug_fn; @@ -648,6 +641,11 @@ extern int scsi_cmd_ioctl(struct file *, struct gendisk *, unsigned int, void __ extern int sg_scsi_ioctl(struct file *, struct request_queue *, struct gendisk *, struct scsi_ioctl_command __user *); +/* + * Temporary export, until SCSI gets fixed up. + */ +extern int ll_back_merge_fn(request_queue_t *, struct request *, struct bio *); + /* * A queue has just exitted congestion. Note this in the global counter of * congested queues, and wake up anyone who was waiting for requests to be -- cgit v1.2.3-70-g09d2 From 8e5cfc45e7527eb5c8a9a22d56a7b9227e7c0913 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Tue, 19 Dec 2006 11:12:46 +0100 Subject: [PATCH] Fixup blk_rq_unmap_user() API The blk_rq_unmap_user() API is not very nice. It expects the caller to know that rq->bio has to be reset to the original bio, and it will silently do nothing if that is not done. Instead make it explicit that we need to pass in the first bio, by expecting a bio argument. Signed-off-by: Jens Axboe --- block/ll_rw_blk.c | 28 ++++++++++++++++------------ block/scsi_ioctl.c | 3 +-- drivers/cdrom/cdrom.c | 3 +-- include/linux/blkdev.h | 2 +- 4 files changed, 19 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index a66ec30855d..e07c079e07e 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -2405,6 +2405,7 @@ int blk_rq_map_user(request_queue_t *q, struct request *rq, void __user *ubuf, unsigned long len) { unsigned long bytes_read = 0; + struct bio *bio = NULL; int ret; if (len > (q->max_hw_sectors << 9)) @@ -2431,6 +2432,8 @@ int blk_rq_map_user(request_queue_t *q, struct request *rq, void __user *ubuf, ret = __blk_rq_map_user(q, rq, ubuf, map_len); if (ret < 0) goto unmap_rq; + if (!bio) + bio = rq->bio; bytes_read += ret; ubuf += ret; } @@ -2438,7 +2441,7 @@ int blk_rq_map_user(request_queue_t *q, struct request *rq, void __user *ubuf, rq->buffer = rq->data = NULL; return 0; unmap_rq: - blk_rq_unmap_user(rq); + blk_rq_unmap_user(bio); return ret; } @@ -2495,29 +2498,30 @@ EXPORT_SYMBOL(blk_rq_map_user_iov); /** * blk_rq_unmap_user - unmap a request with user data - * @rq: rq to be unmapped + * @bio: start of bio list * * Description: - * Unmap a rq previously mapped by blk_rq_map_user(). - * rq->bio must be set to the original head of the request. + * Unmap a rq previously mapped by blk_rq_map_user(). The caller must + * supply the original rq->bio from the blk_rq_map_user() return, since + * the io completion may have changed rq->bio. */ -int blk_rq_unmap_user(struct request *rq) +int blk_rq_unmap_user(struct bio *bio) { - struct bio *bio, *mapped_bio; + struct bio *mapped_bio; int ret = 0, ret2; - while ((bio = rq->bio)) { - if (bio_flagged(bio, BIO_BOUNCED)) + while (bio) { + mapped_bio = bio; + if (unlikely(bio_flagged(bio, BIO_BOUNCED))) mapped_bio = bio->bi_private; - else - mapped_bio = bio; ret2 = __blk_rq_unmap_user(mapped_bio); if (ret2 && !ret) ret = ret2; - rq->bio = bio->bi_next; - bio_put(bio); + mapped_bio = bio; + bio = bio->bi_next; + bio_put(mapped_bio); } return ret; diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c index f322b6a441d..2528a0c0dec 100644 --- a/block/scsi_ioctl.c +++ b/block/scsi_ioctl.c @@ -333,8 +333,7 @@ static int sg_io(struct file *file, request_queue_t *q, hdr->sb_len_wr = len; } - rq->bio = bio; - if (blk_rq_unmap_user(rq)) + if (blk_rq_unmap_user(bio)) ret = -EFAULT; /* may not have succeeded, but output values written to control diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index e4a2f8f3a1d..66d028d3043 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -2139,8 +2139,7 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf, cdi->last_sense = s->sense_key; } - rq->bio = bio; - if (blk_rq_unmap_user(rq)) + if (blk_rq_unmap_user(bio)) ret = -EFAULT; if (ret) diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 0fa33017ec0..36a6eacefe2 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -672,7 +672,7 @@ extern void __blk_stop_queue(request_queue_t *q); extern void blk_run_queue(request_queue_t *); extern void blk_start_queueing(request_queue_t *); extern int blk_rq_map_user(request_queue_t *, struct request *, void __user *, unsigned long); -extern int blk_rq_unmap_user(struct request *); +extern int blk_rq_unmap_user(struct bio *); extern int blk_rq_map_kern(request_queue_t *, struct request *, void *, unsigned int, gfp_t); extern int blk_rq_map_user_iov(request_queue_t *, struct request *, struct sg_iovec *, int, unsigned int); -- cgit v1.2.3-70-g09d2